Change handling of gradients
Some changes to the way we handle CSS gradients: * draw without padding, thus interpreting gradients as part of the background rather than as content * clip to (rounded) border area * draw the border along the gradient instead of trying to align the gradient layer with the background/border layer * use the border_image actor instead of the background_image one https://bugzilla.gnome.org/show_bug.cgi?id=606257
This commit is contained in:
parent
3f750a5637
commit
7486c09fbb
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include <clutter/clutter.h>
|
#include <clutter/clutter.h>
|
||||||
|
|
||||||
@ -61,6 +62,9 @@ struct _StWidgetPrivate
|
|||||||
ClutterActor *background_image_shadow;
|
ClutterActor *background_image_shadow;
|
||||||
ClutterColor bg_color;
|
ClutterColor bg_color;
|
||||||
|
|
||||||
|
guint border_width;
|
||||||
|
ClutterColor border_color;
|
||||||
|
|
||||||
StGradientType bg_gradient_type;
|
StGradientType bg_gradient_type;
|
||||||
ClutterColor bg_gradient_end;
|
ClutterColor bg_gradient_end;
|
||||||
|
|
||||||
@ -302,7 +306,7 @@ st_widget_allocate (ClutterActor *actor,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (priv->border_image)
|
if (priv->border_image && priv->bg_gradient_type == ST_GRADIENT_NONE)
|
||||||
{
|
{
|
||||||
ClutterActorBox frame_box = {
|
ClutterActorBox frame_box = {
|
||||||
0,
|
0,
|
||||||
@ -315,8 +319,27 @@ st_widget_allocate (ClutterActor *actor,
|
|||||||
&frame_box,
|
&frame_box,
|
||||||
flags);
|
flags);
|
||||||
}
|
}
|
||||||
|
else if (priv->bg_gradient_type != ST_GRADIENT_NONE)
|
||||||
|
{
|
||||||
|
float width, height;
|
||||||
|
ClutterActorBox frame_box;
|
||||||
|
|
||||||
if (priv->background_image && priv->bg_gradient_type == ST_GRADIENT_NONE)
|
width = box->x2 - box->x1;
|
||||||
|
height = box->y2 - box->y1;
|
||||||
|
frame_box.x1 = frame_box.y1 = 0;
|
||||||
|
frame_box.x2 = width;
|
||||||
|
frame_box.y2 = height;
|
||||||
|
|
||||||
|
if (width > 0 && height > 0)
|
||||||
|
clutter_cairo_texture_set_surface_size (CLUTTER_CAIRO_TEXTURE (priv->border_image),
|
||||||
|
width, height);
|
||||||
|
st_widget_redraw_gradient ((StWidget*) actor);
|
||||||
|
clutter_actor_allocate (CLUTTER_ACTOR (priv->border_image),
|
||||||
|
&frame_box,
|
||||||
|
flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->background_image)
|
||||||
{
|
{
|
||||||
ClutterActorBox frame_box = {
|
ClutterActorBox frame_box = {
|
||||||
0, 0, box->x2 - box->x1, box->y2 - box->y1
|
0, 0, box->x2 - box->x1, box->y2 - box->y1
|
||||||
@ -393,27 +416,6 @@ st_widget_allocate (ClutterActor *actor,
|
|||||||
&frame_box,
|
&frame_box,
|
||||||
flags);
|
flags);
|
||||||
}
|
}
|
||||||
else if (priv->bg_gradient_type != ST_GRADIENT_NONE)
|
|
||||||
{
|
|
||||||
float width, height;
|
|
||||||
ClutterActorBox frame_box, content_box;
|
|
||||||
|
|
||||||
width = box->x2 - box->x1;
|
|
||||||
height = box->y2 - box->y1;
|
|
||||||
frame_box.x1 = frame_box.y1 = 0;
|
|
||||||
frame_box.x2 = width;
|
|
||||||
frame_box.y2 = height;
|
|
||||||
|
|
||||||
st_theme_node_get_content_box (theme_node, &frame_box, &content_box);
|
|
||||||
|
|
||||||
if (width > 0 && height > 0)
|
|
||||||
clutter_cairo_texture_set_surface_size (CLUTTER_CAIRO_TEXTURE (priv->background_image),
|
|
||||||
width, height);
|
|
||||||
st_widget_redraw_gradient ((StWidget*) actor);
|
|
||||||
clutter_actor_allocate (CLUTTER_ACTOR (priv->background_image),
|
|
||||||
&content_box,
|
|
||||||
flags);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -597,82 +599,115 @@ st_widget_unmap (ClutterActor *actor)
|
|||||||
clutter_actor_unmap ((ClutterActor *) priv->tooltip);
|
clutter_actor_unmap ((ClutterActor *) priv->tooltip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
draw_vertical_gradient (ClutterCairoTexture *texture,
|
|
||||||
ClutterColor *start,
|
|
||||||
ClutterColor *end)
|
|
||||||
{
|
|
||||||
guint width, height;
|
|
||||||
cairo_t *cr;
|
|
||||||
cairo_pattern_t *pattern;
|
|
||||||
|
|
||||||
clutter_cairo_texture_get_surface_size (texture, &width, &height);
|
|
||||||
clutter_cairo_texture_clear (texture);
|
|
||||||
cr = clutter_cairo_texture_create (texture);
|
|
||||||
|
|
||||||
pattern = cairo_pattern_create_linear (0, 0, 0, height);
|
|
||||||
cairo_pattern_add_color_stop_rgba (pattern, 0,
|
|
||||||
start->red / 255.,
|
|
||||||
start->green / 255.,
|
|
||||||
start->blue / 255.,
|
|
||||||
start->alpha / 255.);
|
|
||||||
cairo_pattern_add_color_stop_rgba (pattern, 1,
|
|
||||||
end->red / 255.,
|
|
||||||
end->green / 255.,
|
|
||||||
end->blue / 255.,
|
|
||||||
end->alpha / 255.);
|
|
||||||
|
|
||||||
cairo_rectangle (cr, 0, 0, width, height);
|
|
||||||
cairo_set_source (cr, pattern);
|
|
||||||
cairo_fill (cr);
|
|
||||||
|
|
||||||
cairo_pattern_destroy (pattern);
|
|
||||||
cairo_destroy (cr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
draw_horizontal_gradient (ClutterCairoTexture *texture,
|
|
||||||
ClutterColor *start,
|
|
||||||
ClutterColor *end)
|
|
||||||
{
|
|
||||||
guint width, height;
|
|
||||||
cairo_t *cr;
|
|
||||||
cairo_pattern_t *pattern;
|
|
||||||
|
|
||||||
clutter_cairo_texture_get_surface_size (texture, &width, &height);
|
|
||||||
clutter_cairo_texture_clear (texture);
|
|
||||||
cr = clutter_cairo_texture_create (texture);
|
|
||||||
|
|
||||||
pattern = cairo_pattern_create_linear (0, 0, width, 0);
|
|
||||||
cairo_pattern_add_color_stop_rgba (pattern, 0,
|
|
||||||
start->red / 255.,
|
|
||||||
start->green / 255.,
|
|
||||||
start->blue / 255.,
|
|
||||||
start->alpha / 255.);
|
|
||||||
cairo_pattern_add_color_stop_rgba (pattern, 1,
|
|
||||||
end->red / 255.,
|
|
||||||
end->green / 255.,
|
|
||||||
end->blue / 255.,
|
|
||||||
end->alpha / 255.);
|
|
||||||
cairo_rectangle (cr, 0, 0, width, height);
|
|
||||||
cairo_set_source (cr, pattern);
|
|
||||||
cairo_fill (cr);
|
|
||||||
|
|
||||||
cairo_pattern_destroy (pattern);
|
|
||||||
cairo_destroy (cr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
st_widget_redraw_gradient (StWidget *widget)
|
st_widget_redraw_gradient (StWidget *widget)
|
||||||
{
|
{
|
||||||
if (widget->priv->bg_gradient_type == ST_GRADIENT_VERTICAL)
|
ClutterCairoTexture *texture;
|
||||||
draw_vertical_gradient ((ClutterCairoTexture*) widget->priv->background_image,
|
ClutterColor *start, *end;
|
||||||
&widget->priv->bg_color,
|
StWidgetPrivate *priv;
|
||||||
&widget->priv->bg_gradient_end);
|
guint width, height;
|
||||||
else if (widget->priv->bg_gradient_type == ST_GRADIENT_HORIZONTAL)
|
guint radius[4], i;
|
||||||
draw_horizontal_gradient ((ClutterCairoTexture*) widget->priv->background_image,
|
cairo_t *cr;
|
||||||
&widget->priv->bg_color,
|
cairo_pattern_t *pattern;
|
||||||
&widget->priv->bg_gradient_end);
|
gboolean round_border = FALSE;
|
||||||
|
|
||||||
|
if (widget->priv->bg_gradient_type == ST_GRADIENT_NONE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
texture = CLUTTER_CAIRO_TEXTURE (widget->priv->border_image);
|
||||||
|
priv = widget->priv;
|
||||||
|
start = &widget->priv->bg_color;
|
||||||
|
end = &widget->priv->bg_gradient_end;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
radius[i] = st_theme_node_get_border_radius (priv->theme_node, i);
|
||||||
|
if (radius[i] > 0)
|
||||||
|
round_border = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
clutter_cairo_texture_get_surface_size (texture, &width, &height);
|
||||||
|
clutter_cairo_texture_clear (texture);
|
||||||
|
cr = clutter_cairo_texture_create (texture);
|
||||||
|
|
||||||
|
if (priv->bg_gradient_type == ST_GRADIENT_VERTICAL)
|
||||||
|
pattern = cairo_pattern_create_linear (0, 0, 0, height);
|
||||||
|
else
|
||||||
|
pattern = cairo_pattern_create_linear (0, 0, width, 0);
|
||||||
|
|
||||||
|
cairo_pattern_add_color_stop_rgba (pattern, 0,
|
||||||
|
start->red / 255.,
|
||||||
|
start->green / 255.,
|
||||||
|
start->blue / 255.,
|
||||||
|
start->alpha / 255.);
|
||||||
|
cairo_pattern_add_color_stop_rgba (pattern, 1,
|
||||||
|
end->red / 255.,
|
||||||
|
end->green / 255.,
|
||||||
|
end->blue / 255.,
|
||||||
|
end->alpha / 255.);
|
||||||
|
|
||||||
|
if (round_border)
|
||||||
|
{
|
||||||
|
if (radius[ST_CORNER_TOPLEFT] > 0)
|
||||||
|
cairo_arc (cr,
|
||||||
|
radius[ST_CORNER_TOPLEFT],
|
||||||
|
radius[ST_CORNER_TOPLEFT],
|
||||||
|
radius[ST_CORNER_TOPLEFT], M_PI, 3 * M_PI / 2);
|
||||||
|
else
|
||||||
|
cairo_move_to (cr, 0, 0);
|
||||||
|
cairo_line_to (cr, width - radius[ST_CORNER_TOPRIGHT], 0);
|
||||||
|
if (radius[ST_CORNER_TOPRIGHT] > 0)
|
||||||
|
cairo_arc (cr,
|
||||||
|
width - radius[ST_CORNER_TOPRIGHT],
|
||||||
|
radius[ST_CORNER_TOPRIGHT],
|
||||||
|
radius[ST_CORNER_TOPRIGHT], 3 * M_PI / 2, 2 * M_PI);
|
||||||
|
cairo_line_to (cr, width, height - radius[ST_CORNER_BOTTOMRIGHT]);
|
||||||
|
if (radius[ST_CORNER_BOTTOMRIGHT])
|
||||||
|
cairo_arc (cr,
|
||||||
|
width - radius[ST_CORNER_BOTTOMRIGHT],
|
||||||
|
height - radius[ST_CORNER_BOTTOMRIGHT],
|
||||||
|
radius[ST_CORNER_BOTTOMRIGHT], 0, M_PI / 2);
|
||||||
|
cairo_line_to (cr, radius[ST_CORNER_BOTTOMLEFT], height);
|
||||||
|
if (radius[ST_CORNER_BOTTOMLEFT])
|
||||||
|
cairo_arc (cr,
|
||||||
|
radius[ST_CORNER_BOTTOMLEFT],
|
||||||
|
height - radius[ST_CORNER_BOTTOMLEFT],
|
||||||
|
radius[ST_CORNER_BOTTOMLEFT], M_PI / 2, M_PI);
|
||||||
|
cairo_close_path (cr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cairo_rectangle (cr, 0, 0, width, height);
|
||||||
|
|
||||||
|
if (priv->border_width > 0)
|
||||||
|
{
|
||||||
|
guint8 opacity;
|
||||||
|
gdouble effective_alpha;
|
||||||
|
cairo_path_t *path;
|
||||||
|
|
||||||
|
path = cairo_copy_path (cr);
|
||||||
|
opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (widget));
|
||||||
|
effective_alpha = priv->border_color.alpha * opacity / (255. * 255.);
|
||||||
|
|
||||||
|
cairo_set_source_rgba (cr,
|
||||||
|
priv->border_color.red / 255.,
|
||||||
|
priv->border_color.green / 255.,
|
||||||
|
priv->border_color.blue / 255.,
|
||||||
|
effective_alpha);
|
||||||
|
cairo_fill (cr);
|
||||||
|
|
||||||
|
cairo_translate (cr, priv->border_width, priv->border_width);
|
||||||
|
cairo_scale (cr,
|
||||||
|
(gdouble)(width - 2 * priv->border_width) / width,
|
||||||
|
(gdouble)(height - 2 * priv->border_width) / height);
|
||||||
|
cairo_append_path (cr, path);
|
||||||
|
cairo_path_destroy (path);
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_set_source (cr, pattern);
|
||||||
|
cairo_fill (cr);
|
||||||
|
|
||||||
|
cairo_pattern_destroy (pattern);
|
||||||
|
cairo_destroy (cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void notify_children_of_style_change (ClutterContainer *container);
|
static void notify_children_of_style_change (ClutterContainer *container);
|
||||||
@ -709,9 +744,7 @@ st_widget_real_style_changed (StWidget *self)
|
|||||||
gboolean relayout_needed = FALSE;
|
gboolean relayout_needed = FALSE;
|
||||||
gboolean has_changed = FALSE;
|
gboolean has_changed = FALSE;
|
||||||
ClutterColor color;
|
ClutterColor color;
|
||||||
guint border_width = 0;
|
|
||||||
guint border_radius = 0;
|
guint border_radius = 0;
|
||||||
ClutterColor border_color = { 0, };
|
|
||||||
StGradientType gradient;
|
StGradientType gradient;
|
||||||
ClutterColor gradient_end;
|
ClutterColor gradient_end;
|
||||||
StSide side;
|
StSide side;
|
||||||
@ -779,9 +812,9 @@ st_widget_real_style_changed (StWidget *self)
|
|||||||
* Background image
|
* Background image
|
||||||
* Border color or border image
|
* Border color or border image
|
||||||
* Content
|
* Content
|
||||||
* - The background color and image extend to and are clipped by the
|
* - The background color, gradient and image extend to and are clipped by
|
||||||
* edge of the border area, so will be rounded if the border is rounded.
|
* the edge of the border area, so will be rounded if the border is
|
||||||
* (CSS3 background-clip property modifies this)
|
* rounded. (CSS3 background-clip property modifies this)
|
||||||
* - The border image replaces what would normally be drawn by the border
|
* - The border image replaces what would normally be drawn by the border
|
||||||
* - The border image is not clipped by a rounded border-radius
|
* - The border image is not clipped by a rounded border-radius
|
||||||
* - The border radius rounds the background even if the border is
|
* - The border radius rounds the background even if the border is
|
||||||
@ -793,21 +826,24 @@ st_widget_real_style_changed (StWidget *self)
|
|||||||
* - The combination of border image and a non-zero border radius is
|
* - The combination of border image and a non-zero border radius is
|
||||||
* not supported; the background color will be drawn with square
|
* not supported; the background color will be drawn with square
|
||||||
* corners.
|
* corners.
|
||||||
|
* - The combination of border image and a background gradient is not
|
||||||
|
* supported; the background will be drawn as a solid color
|
||||||
* - The background image is drawn above the border color or image,
|
* - The background image is drawn above the border color or image,
|
||||||
* not below it.
|
* not below it.
|
||||||
* - We don't clip the background image to the (rounded) border area.
|
* - We don't clip the background image to the (rounded) border area.
|
||||||
*
|
*
|
||||||
* The first two allow us always draw with no more than single border_image
|
* The first three allow us to always draw with no more than a single
|
||||||
* and a single background image above it.
|
* border_image and a single background image above it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Check whether all border widths are the same. Also, acquire the
|
/* Check whether all border widths are the same. Also, acquire the
|
||||||
* first nonzero border width as well as the border color.
|
* first nonzero border width as well as the border color.
|
||||||
*/
|
*/
|
||||||
uniform_border_width = TRUE;
|
uniform_border_width = TRUE;
|
||||||
border_width = st_theme_node_get_border_width (theme_node, ST_SIDE_TOP);
|
priv->border_width = st_theme_node_get_border_width (theme_node,
|
||||||
if (border_width > 0.5)
|
ST_SIDE_TOP);
|
||||||
border_width = (int)(0.5 + border_width);
|
if (priv->border_width > 0.5)
|
||||||
|
priv->border_width = (int)(0.5 + priv->border_width);
|
||||||
for (side = 0; side < 4; side++)
|
for (side = 0; side < 4; side++)
|
||||||
{
|
{
|
||||||
double width = st_theme_node_get_border_width (theme_node, side);
|
double width = st_theme_node_get_border_width (theme_node, side);
|
||||||
@ -815,10 +851,11 @@ st_widget_real_style_changed (StWidget *self)
|
|||||||
width = (int)(0.5 + width);
|
width = (int)(0.5 + width);
|
||||||
if (width > 0)
|
if (width > 0)
|
||||||
{
|
{
|
||||||
border_width = width;
|
priv->border_width = width;
|
||||||
st_theme_node_get_border_color (theme_node, side, &border_color);
|
st_theme_node_get_border_color (theme_node,
|
||||||
|
side, &priv->border_color);
|
||||||
}
|
}
|
||||||
if ((int)width != border_width)
|
if ((int)width != priv->border_width)
|
||||||
{
|
{
|
||||||
uniform_border_width = FALSE;
|
uniform_border_width = FALSE;
|
||||||
break;
|
break;
|
||||||
@ -867,6 +904,17 @@ st_widget_real_style_changed (StWidget *self)
|
|||||||
border_left);
|
border_left);
|
||||||
clutter_actor_set_parent (priv->border_image, CLUTTER_ACTOR (self));
|
clutter_actor_set_parent (priv->border_image, CLUTTER_ACTOR (self));
|
||||||
|
|
||||||
|
has_changed = TRUE;
|
||||||
|
relayout_needed = TRUE;
|
||||||
|
}
|
||||||
|
else if (priv->bg_gradient_type != ST_GRADIENT_NONE)
|
||||||
|
{
|
||||||
|
priv->draw_border_internal = FALSE;
|
||||||
|
priv->draw_bg_color = FALSE;
|
||||||
|
texture = g_object_new (CLUTTER_TYPE_CAIRO_TEXTURE, NULL);
|
||||||
|
priv->border_image = CLUTTER_ACTOR (texture);
|
||||||
|
clutter_actor_set_parent (priv->border_image, CLUTTER_ACTOR (self));
|
||||||
|
|
||||||
has_changed = TRUE;
|
has_changed = TRUE;
|
||||||
relayout_needed = TRUE;
|
relayout_needed = TRUE;
|
||||||
}
|
}
|
||||||
@ -876,8 +924,8 @@ st_widget_real_style_changed (StWidget *self)
|
|||||||
priv->draw_bg_color = FALSE;
|
priv->draw_bg_color = FALSE;
|
||||||
priv->border_image = g_object_new (BIG_TYPE_RECTANGLE,
|
priv->border_image = g_object_new (BIG_TYPE_RECTANGLE,
|
||||||
"color", &priv->bg_color,
|
"color", &priv->bg_color,
|
||||||
"border-width", border_width,
|
"border-width", priv->border_width,
|
||||||
"border-color", &border_color,
|
"border-color", &priv->border_color,
|
||||||
"corner-radius", border_radius,
|
"corner-radius", border_radius,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@ -886,7 +934,7 @@ st_widget_real_style_changed (StWidget *self)
|
|||||||
has_changed = TRUE;
|
has_changed = TRUE;
|
||||||
relayout_needed = TRUE;
|
relayout_needed = TRUE;
|
||||||
}
|
}
|
||||||
else if (border_width > 0 && border_color.alpha != 0)
|
else if (priv->border_width > 0 && priv->border_color.alpha != 0)
|
||||||
{
|
{
|
||||||
priv->draw_bg_color = TRUE;
|
priv->draw_bg_color = TRUE;
|
||||||
priv->draw_border_internal = TRUE;
|
priv->draw_border_internal = TRUE;
|
||||||
@ -917,15 +965,6 @@ st_widget_real_style_changed (StWidget *self)
|
|||||||
has_changed = TRUE;
|
has_changed = TRUE;
|
||||||
relayout_needed = TRUE;
|
relayout_needed = TRUE;
|
||||||
}
|
}
|
||||||
else if (priv->bg_gradient_type != ST_GRADIENT_NONE)
|
|
||||||
{
|
|
||||||
texture = g_object_new (CLUTTER_TYPE_CAIRO_TEXTURE, NULL);
|
|
||||||
priv->background_image = CLUTTER_ACTOR (texture);
|
|
||||||
clutter_actor_set_parent (priv->background_image,
|
|
||||||
CLUTTER_ACTOR (self));
|
|
||||||
has_changed = TRUE;
|
|
||||||
relayout_needed = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CSS based drop shadows
|
/* CSS based drop shadows
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user