StThemeDrawing: clip background to border
Previously, trying to use a background image and border on the same node resulted in the background drawing over the border. This commit adds support for background images to st_theme_node_render_background_with_border and changes the code to call that function when appropriate. https://bugzilla.gnome.org/show_bug.cgi?id=636976
This commit is contained in:
parent
03757c1fcb
commit
779d5462f2
@ -485,9 +485,233 @@ create_cairo_pattern_of_background_gradient (StThemeNode *node)
|
||||
return pattern;
|
||||
}
|
||||
|
||||
static cairo_pattern_t *
|
||||
create_cairo_pattern_of_background_image (StThemeNode *node,
|
||||
gboolean *needs_background_fill)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_pattern_t *pattern;
|
||||
cairo_content_t content;
|
||||
cairo_matrix_t matrix;
|
||||
const char *file;
|
||||
double height_ratio, width_ratio;
|
||||
int file_width;
|
||||
int file_height;
|
||||
|
||||
StTextureCache *texture_cache;
|
||||
|
||||
file = st_theme_node_get_background_image (node);
|
||||
|
||||
texture_cache = st_texture_cache_get_default ();
|
||||
|
||||
surface = st_texture_cache_load_file_to_cairo_surface (texture_cache, file);
|
||||
|
||||
if (surface == NULL)
|
||||
return NULL;
|
||||
|
||||
g_assert (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE);
|
||||
|
||||
content = cairo_surface_get_content (surface);
|
||||
pattern = cairo_pattern_create_for_surface (surface);
|
||||
|
||||
file_width = cairo_image_surface_get_width (surface);
|
||||
file_height = cairo_image_surface_get_height (surface);
|
||||
|
||||
height_ratio = file_height / node->alloc_height;
|
||||
width_ratio = file_width / node->alloc_width;
|
||||
|
||||
*needs_background_fill = TRUE;
|
||||
if ((file_width > node->alloc_width || file_height > node->alloc_height)
|
||||
&& !node->background_position_set)
|
||||
{
|
||||
double scale_factor;
|
||||
double x_offset, y_offset;
|
||||
|
||||
if (width_ratio > height_ratio)
|
||||
{
|
||||
double scaled_height;
|
||||
|
||||
/* center vertically */
|
||||
|
||||
scale_factor = width_ratio;
|
||||
scaled_height = file_height / scale_factor;
|
||||
|
||||
x_offset = 0.;
|
||||
y_offset = - (node->alloc_height / 2. - scaled_height / 2.);
|
||||
}
|
||||
else
|
||||
{
|
||||
double scaled_width;
|
||||
|
||||
/* center horizontally */
|
||||
|
||||
scale_factor = height_ratio;
|
||||
scaled_width = file_width / scale_factor;
|
||||
|
||||
y_offset = 0.;
|
||||
x_offset = - (node->alloc_width / 2. - scaled_width / 2.);
|
||||
}
|
||||
|
||||
cairo_matrix_init_translate (&matrix, x_offset, y_offset);
|
||||
cairo_matrix_scale (&matrix, scale_factor, scale_factor);
|
||||
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
|
||||
/* If it's opaque, and when scaled, fills up the entire allocated
|
||||
* area, then don't bother doing a background fill first
|
||||
*/
|
||||
if (content != CAIRO_CONTENT_COLOR_ALPHA && width_ratio == height_ratio)
|
||||
*needs_background_fill = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
double x_offset, y_offset;
|
||||
|
||||
if (node->background_position_set)
|
||||
{
|
||||
x_offset = -node->background_position_x;
|
||||
y_offset = -node->background_position_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node->alloc_width > file_width)
|
||||
x_offset = - (node->alloc_width / 2.0 - file_width / 2.0);
|
||||
else
|
||||
x_offset = - (file_width / 2.0 - node->alloc_width / 2.0);
|
||||
|
||||
if (node->alloc_height > file_height)
|
||||
y_offset = - (node->alloc_height / 2.0 - file_height / 2.0);
|
||||
else
|
||||
y_offset = - (file_height / 2.0 - node->alloc_height / 2.0);
|
||||
}
|
||||
|
||||
/* If it's opaque, and when translated, fills up the entire allocated
|
||||
* area, then don't bother doing a background fill first
|
||||
*/
|
||||
if (content != CAIRO_CONTENT_COLOR_ALPHA
|
||||
&& -x_offset <= 0
|
||||
&& -x_offset + file_width >= node->alloc_width
|
||||
&& -y_offset <= 0
|
||||
&& -y_offset + file_height >= node->alloc_height)
|
||||
*needs_background_fill = FALSE;
|
||||
|
||||
cairo_matrix_init_translate (&matrix, x_offset, y_offset);
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
static void
|
||||
paint_background_image_shadow_to_cairo_context (StThemeNode *node,
|
||||
StShadow *shadow_spec,
|
||||
cairo_pattern_t *pattern,
|
||||
cairo_t *cr,
|
||||
cairo_path_t *interior_path,
|
||||
cairo_path_t *outline_path,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
cairo_pattern_t *shadow_pattern;
|
||||
|
||||
g_assert (shadow_spec != NULL);
|
||||
g_assert (pattern != NULL);
|
||||
|
||||
if (outline_path != NULL)
|
||||
{
|
||||
cairo_surface_t *clipped_surface;
|
||||
cairo_pattern_t *clipped_pattern;
|
||||
cairo_t *temp_cr;
|
||||
|
||||
/* Prerender the pattern to a temporary surface,
|
||||
* so it's properly clipped before we create a shadow from it
|
||||
*/
|
||||
clipped_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
temp_cr = cairo_create (clipped_surface);
|
||||
|
||||
cairo_set_operator (temp_cr, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_paint (temp_cr);
|
||||
cairo_set_operator (temp_cr, CAIRO_OPERATOR_SOURCE);
|
||||
|
||||
if (interior_path != NULL)
|
||||
{
|
||||
cairo_append_path (temp_cr, interior_path);
|
||||
cairo_clip (temp_cr);
|
||||
}
|
||||
|
||||
cairo_append_path (temp_cr, outline_path);
|
||||
cairo_translate (temp_cr, x, y);
|
||||
cairo_set_source (temp_cr, pattern);
|
||||
cairo_clip (temp_cr);
|
||||
cairo_paint (temp_cr);
|
||||
cairo_destroy (temp_cr);
|
||||
|
||||
clipped_pattern = cairo_pattern_create_for_surface (clipped_surface);
|
||||
cairo_surface_destroy (clipped_surface);
|
||||
|
||||
shadow_pattern = _st_create_shadow_cairo_pattern (shadow_spec,
|
||||
clipped_pattern);
|
||||
cairo_pattern_destroy (clipped_pattern);
|
||||
}
|
||||
else
|
||||
{
|
||||
shadow_pattern = _st_create_shadow_cairo_pattern (shadow_spec,
|
||||
pattern);
|
||||
}
|
||||
|
||||
/* Stamp the shadow pattern out in the appropriate color
|
||||
* in a new layer
|
||||
*/
|
||||
cairo_push_group (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_source_rgba (cr,
|
||||
shadow_spec->color.red / 255.0,
|
||||
shadow_spec->color.green / 255.0,
|
||||
shadow_spec->color.blue / 255.0,
|
||||
shadow_spec->color.alpha / 255.0);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN);
|
||||
|
||||
cairo_set_source (cr, shadow_pattern);
|
||||
cairo_paint (cr);
|
||||
cairo_pattern_destroy (shadow_pattern);
|
||||
|
||||
cairo_pop_group_to_source (cr);
|
||||
|
||||
/* mask and merge the shadow
|
||||
*/
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_save (cr);
|
||||
if (interior_path != NULL)
|
||||
{
|
||||
/* If there are borders, clip the shadow to the interior
|
||||
* of the borders
|
||||
*/
|
||||
cairo_append_path (cr, interior_path);
|
||||
cairo_clip (cr);
|
||||
}
|
||||
else if (outline_path != NULL)
|
||||
{
|
||||
/* If there is a visible outline, clip the shadow to
|
||||
* that outline
|
||||
*/
|
||||
cairo_append_path (cr, outline_path);
|
||||
cairo_clip (cr);
|
||||
}
|
||||
|
||||
cairo_paint (cr);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
/* In order for borders to be smoothly blended with non-solid backgrounds,
|
||||
* we need to use cairo. This function is a slow fallback path for those
|
||||
* cases. It currently only supports gradients, however.
|
||||
* cases (gradients, background images, etc).
|
||||
*/
|
||||
static CoglHandle
|
||||
st_theme_node_render_background_with_border (StThemeNode *node)
|
||||
@ -497,21 +721,54 @@ st_theme_node_render_background_with_border (StThemeNode *node)
|
||||
int radius[4], i;
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *surface;
|
||||
StShadow *shadow_spec;
|
||||
cairo_pattern_t *pattern = NULL;
|
||||
gboolean draw_solid_background;
|
||||
cairo_path_t *outline_path = NULL;
|
||||
gboolean draw_solid_background = TRUE;
|
||||
gboolean draw_background_image_shadow = FALSE;
|
||||
gboolean has_visible_outline;
|
||||
ClutterColor border_color;
|
||||
int border_width[4];
|
||||
guint rowstride;
|
||||
guchar *data;
|
||||
ClutterActorBox actor_box;
|
||||
ClutterActorBox paint_box;
|
||||
cairo_path_t *interior_path = NULL;
|
||||
|
||||
border_image = st_theme_node_get_border_image (node);
|
||||
|
||||
rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, node->alloc_width);
|
||||
data = g_new0 (guchar, node->alloc_height * rowstride);
|
||||
shadow_spec = st_theme_node_get_background_image_shadow (node);
|
||||
|
||||
actor_box.x1 = 0;
|
||||
actor_box.x2 = node->alloc_width;
|
||||
actor_box.y1 = 0;
|
||||
actor_box.y2 = node->alloc_height;
|
||||
|
||||
/* If there's a background image shadow, we
|
||||
* may need to create an image bigger than the nodes
|
||||
* allocation
|
||||
*/
|
||||
st_theme_node_get_paint_box (node, &actor_box, &paint_box);
|
||||
|
||||
/* translate the boxes so the paint box is at 0,0
|
||||
*/
|
||||
actor_box.x1 += - paint_box.x1;
|
||||
actor_box.x2 += - paint_box.x1;
|
||||
actor_box.y1 += - paint_box.y1;
|
||||
actor_box.y2 += - paint_box.y1;
|
||||
|
||||
paint_box.x2 += - paint_box.x1;
|
||||
paint_box.x1 += - paint_box.x1;
|
||||
paint_box.y2 += - paint_box.y1;
|
||||
paint_box.y1 += - paint_box.y1;
|
||||
|
||||
rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
|
||||
paint_box.x2 - paint_box.x1);
|
||||
data = g_new0 (guchar, (paint_box.y2 - paint_box.y1) * rowstride);
|
||||
surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
node->alloc_width,
|
||||
node->alloc_height,
|
||||
paint_box.x2 - paint_box.x1,
|
||||
paint_box.y2 - paint_box.y1,
|
||||
rowstride);
|
||||
cr = cairo_create (surface);
|
||||
|
||||
@ -525,6 +782,9 @@ st_theme_node_render_background_with_border (StThemeNode *node)
|
||||
radius[i] = st_theme_node_get_border_radius (node, i);
|
||||
}
|
||||
|
||||
/* Note we don't support translucent background images on top
|
||||
* of gradients. It's strictly either/or.
|
||||
*/
|
||||
if (node->background_gradient_type != ST_GRADIENT_NONE)
|
||||
{
|
||||
pattern = create_cairo_pattern_of_background_gradient (node);
|
||||
@ -532,38 +792,54 @@ st_theme_node_render_background_with_border (StThemeNode *node)
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("st_theme_node_render_background_with_border called with non-gradient background (which isn't yet supported). Falling back to solid background color.");
|
||||
draw_solid_background = TRUE;
|
||||
const char *background_image;
|
||||
|
||||
background_image = st_theme_node_get_background_image (node);
|
||||
|
||||
if (background_image != NULL)
|
||||
{
|
||||
pattern = create_cairo_pattern_of_background_image (node,
|
||||
&draw_solid_background);
|
||||
if (shadow_spec && pattern != NULL)
|
||||
draw_background_image_shadow = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pattern == NULL)
|
||||
draw_solid_background = TRUE;
|
||||
|
||||
has_visible_outline = st_theme_node_has_visible_outline (node);
|
||||
|
||||
/* Create a path for the background's outline first */
|
||||
if (radius[ST_CORNER_TOPLEFT] > 0)
|
||||
cairo_arc (cr,
|
||||
radius[ST_CORNER_TOPLEFT],
|
||||
radius[ST_CORNER_TOPLEFT],
|
||||
actor_box.x1 + radius[ST_CORNER_TOPLEFT],
|
||||
actor_box.y1 + 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, node->alloc_width - radius[ST_CORNER_TOPRIGHT], 0);
|
||||
cairo_move_to (cr, actor_box.x1, actor_box.y1);
|
||||
cairo_line_to (cr, actor_box.x2 - radius[ST_CORNER_TOPRIGHT], actor_box.x1);
|
||||
if (radius[ST_CORNER_TOPRIGHT] > 0)
|
||||
cairo_arc (cr,
|
||||
node->alloc_width - radius[ST_CORNER_TOPRIGHT],
|
||||
radius[ST_CORNER_TOPRIGHT],
|
||||
actor_box.x2 - radius[ST_CORNER_TOPRIGHT],
|
||||
actor_box.x1 + radius[ST_CORNER_TOPRIGHT],
|
||||
radius[ST_CORNER_TOPRIGHT], 3 * M_PI / 2, 2 * M_PI);
|
||||
cairo_line_to (cr, node->alloc_width, node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT]);
|
||||
cairo_line_to (cr, actor_box.x2, actor_box.y2 - radius[ST_CORNER_BOTTOMRIGHT]);
|
||||
if (radius[ST_CORNER_BOTTOMRIGHT] > 0)
|
||||
cairo_arc (cr,
|
||||
node->alloc_width - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
actor_box.x2 - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
actor_box.y2 - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
radius[ST_CORNER_BOTTOMRIGHT], 0, M_PI / 2);
|
||||
cairo_line_to (cr, radius[ST_CORNER_BOTTOMLEFT], node->alloc_height);
|
||||
cairo_line_to (cr, actor_box.x1 + radius[ST_CORNER_BOTTOMLEFT], actor_box.y2);
|
||||
if (radius[ST_CORNER_BOTTOMLEFT] > 0)
|
||||
cairo_arc (cr,
|
||||
radius[ST_CORNER_BOTTOMLEFT],
|
||||
node->alloc_height - radius[ST_CORNER_BOTTOMLEFT],
|
||||
actor_box.x1 + radius[ST_CORNER_BOTTOMLEFT],
|
||||
actor_box.y2 - radius[ST_CORNER_BOTTOMLEFT],
|
||||
radius[ST_CORNER_BOTTOMLEFT], M_PI / 2, M_PI);
|
||||
cairo_close_path (cr);
|
||||
|
||||
outline_path = cairo_copy_path (cr);
|
||||
|
||||
/* If we have a solid border, we fill the outline shape with the border
|
||||
* color and create the inline shape for the background;
|
||||
* otherwise the outline shape is filled with the background
|
||||
@ -585,68 +861,80 @@ st_theme_node_render_background_with_border (StThemeNode *node)
|
||||
if (radius[ST_CORNER_TOPLEFT] > MAX(border_width[ST_SIDE_TOP],
|
||||
border_width[ST_SIDE_LEFT]))
|
||||
elliptical_arc (cr,
|
||||
radius[ST_CORNER_TOPLEFT],
|
||||
radius[ST_CORNER_TOPLEFT],
|
||||
actor_box.x1 + radius[ST_CORNER_TOPLEFT],
|
||||
actor_box.y1 + radius[ST_CORNER_TOPLEFT],
|
||||
radius[ST_CORNER_TOPLEFT] - border_width[ST_SIDE_LEFT],
|
||||
radius[ST_CORNER_TOPLEFT] - border_width[ST_SIDE_TOP],
|
||||
M_PI, 3 * M_PI / 2);
|
||||
else
|
||||
cairo_move_to (cr,
|
||||
border_width[ST_SIDE_LEFT],
|
||||
border_width[ST_SIDE_TOP]);
|
||||
actor_box.x1 + border_width[ST_SIDE_LEFT],
|
||||
actor_box.y1 + border_width[ST_SIDE_TOP]);
|
||||
|
||||
cairo_line_to (cr,
|
||||
node->alloc_width - MAX(radius[ST_CORNER_TOPRIGHT], border_width[ST_SIDE_RIGHT]),
|
||||
border_width[ST_SIDE_TOP]);
|
||||
actor_box.x2 - MAX(radius[ST_CORNER_TOPRIGHT], border_width[ST_SIDE_RIGHT]),
|
||||
actor_box.y1 + border_width[ST_SIDE_TOP]);
|
||||
|
||||
if (radius[ST_CORNER_TOPRIGHT] > MAX(border_width[ST_SIDE_TOP],
|
||||
border_width[ST_SIDE_RIGHT]))
|
||||
elliptical_arc (cr,
|
||||
node->alloc_width - radius[ST_CORNER_TOPRIGHT],
|
||||
radius[ST_CORNER_TOPRIGHT],
|
||||
actor_box.x2 - radius[ST_CORNER_TOPRIGHT],
|
||||
actor_box.y1 + radius[ST_CORNER_TOPRIGHT],
|
||||
radius[ST_CORNER_TOPRIGHT] - border_width[ST_SIDE_RIGHT],
|
||||
radius[ST_CORNER_TOPRIGHT] - border_width[ST_SIDE_TOP],
|
||||
3 * M_PI / 2, 2 * M_PI);
|
||||
else
|
||||
cairo_line_to (cr,
|
||||
node->alloc_width - border_width[ST_SIDE_RIGHT],
|
||||
border_width[ST_SIDE_TOP]);
|
||||
actor_box.x2 - border_width[ST_SIDE_RIGHT],
|
||||
actor_box.y1 + border_width[ST_SIDE_TOP]);
|
||||
|
||||
cairo_line_to (cr,
|
||||
node->alloc_width - border_width[ST_SIDE_RIGHT],
|
||||
node->alloc_height - MAX(radius[ST_CORNER_BOTTOMRIGHT], border_width[ST_SIDE_BOTTOM]));
|
||||
actor_box.x2 - border_width[ST_SIDE_RIGHT],
|
||||
actor_box.y2 - MAX(radius[ST_CORNER_BOTTOMRIGHT], border_width[ST_SIDE_BOTTOM]));
|
||||
|
||||
if (radius[ST_CORNER_BOTTOMRIGHT] > MAX(border_width[ST_SIDE_BOTTOM],
|
||||
border_width[ST_SIDE_RIGHT]))
|
||||
elliptical_arc (cr,
|
||||
node->alloc_width - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
actor_box.x2 - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
actor_box.y2 - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
radius[ST_CORNER_BOTTOMRIGHT] - border_width[ST_SIDE_RIGHT],
|
||||
radius[ST_CORNER_BOTTOMRIGHT] - border_width[ST_SIDE_BOTTOM],
|
||||
0, M_PI / 2);
|
||||
else
|
||||
cairo_line_to (cr,
|
||||
node->alloc_width - border_width[ST_SIDE_RIGHT],
|
||||
node->alloc_height - border_width[ST_SIDE_BOTTOM]);
|
||||
actor_box.x2 - border_width[ST_SIDE_RIGHT],
|
||||
actor_box.y2 - border_width[ST_SIDE_BOTTOM]);
|
||||
|
||||
cairo_line_to (cr,
|
||||
MAX(radius[ST_CORNER_BOTTOMLEFT], border_width[ST_SIDE_LEFT]),
|
||||
node->alloc_height - border_width[ST_SIDE_BOTTOM]);
|
||||
actor_box.y2 - border_width[ST_SIDE_BOTTOM]);
|
||||
|
||||
if (radius[ST_CORNER_BOTTOMLEFT] > MAX(border_width[ST_SIDE_BOTTOM],
|
||||
border_width[ST_SIDE_LEFT]))
|
||||
elliptical_arc (cr,
|
||||
radius[ST_CORNER_BOTTOMLEFT],
|
||||
node->alloc_height - radius[ST_CORNER_BOTTOMLEFT],
|
||||
actor_box.x1 + radius[ST_CORNER_BOTTOMLEFT],
|
||||
actor_box.y2 - radius[ST_CORNER_BOTTOMLEFT],
|
||||
radius[ST_CORNER_BOTTOMLEFT] - border_width[ST_SIDE_LEFT],
|
||||
radius[ST_CORNER_BOTTOMLEFT] - border_width[ST_SIDE_BOTTOM],
|
||||
M_PI / 2, M_PI);
|
||||
else
|
||||
cairo_line_to (cr,
|
||||
border_width[ST_SIDE_LEFT],
|
||||
node->alloc_height - border_width[ST_SIDE_BOTTOM]);
|
||||
actor_box.x1 + border_width[ST_SIDE_LEFT],
|
||||
actor_box.y2 - border_width[ST_SIDE_BOTTOM]);
|
||||
|
||||
cairo_close_path (cr);
|
||||
|
||||
interior_path = cairo_copy_path (cr);
|
||||
|
||||
/* clip drawing to the region inside of the borders
|
||||
*/
|
||||
cairo_clip (cr);
|
||||
|
||||
/* But fill the pattern as if it started at the edge of outline,
|
||||
* behind the borders. This is similar to
|
||||
* background-clip: border-box; semantics.
|
||||
*/
|
||||
cairo_append_path (cr, outline_path);
|
||||
}
|
||||
|
||||
if (draw_solid_background)
|
||||
@ -659,6 +947,23 @@ st_theme_node_render_background_with_border (StThemeNode *node)
|
||||
cairo_fill_preserve (cr);
|
||||
}
|
||||
|
||||
if (draw_background_image_shadow)
|
||||
{
|
||||
paint_background_image_shadow_to_cairo_context (node,
|
||||
shadow_spec,
|
||||
pattern,
|
||||
cr,
|
||||
interior_path,
|
||||
has_visible_outline? outline_path : NULL,
|
||||
actor_box.x1,
|
||||
actor_box.y1,
|
||||
paint_box.x2 - paint_box.x1,
|
||||
paint_box.y2 - paint_box.y1);
|
||||
cairo_append_path (cr, outline_path);
|
||||
}
|
||||
|
||||
cairo_translate (cr, actor_box.x1, actor_box.y1);
|
||||
|
||||
if (pattern != NULL)
|
||||
{
|
||||
cairo_set_source (cr, pattern);
|
||||
@ -666,7 +971,14 @@ st_theme_node_render_background_with_border (StThemeNode *node)
|
||||
cairo_pattern_destroy (pattern);
|
||||
}
|
||||
|
||||
texture = cogl_texture_new_from_data (node->alloc_width, node->alloc_height,
|
||||
if (outline_path != NULL)
|
||||
cairo_path_destroy (outline_path);
|
||||
|
||||
if (interior_path != NULL)
|
||||
cairo_path_destroy (interior_path);
|
||||
|
||||
texture = cogl_texture_new_from_data (paint_box.x2 - paint_box.x1,
|
||||
paint_box.y2 - paint_box.y1,
|
||||
COGL_TEXTURE_NONE,
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
COGL_PIXEL_FORMAT_BGRA_8888_PRE,
|
||||
@ -745,6 +1057,8 @@ st_theme_node_render_resources (StThemeNode *node,
|
||||
{
|
||||
StTextureCache *texture_cache;
|
||||
StBorderImage *border_image;
|
||||
gboolean has_border;
|
||||
gboolean has_border_radius;
|
||||
StShadow *box_shadow_spec;
|
||||
StShadow *background_image_shadow_spec;
|
||||
const char *background_image;
|
||||
@ -765,9 +1079,26 @@ st_theme_node_render_resources (StThemeNode *node,
|
||||
|
||||
box_shadow_spec = st_theme_node_get_box_shadow (node);
|
||||
|
||||
/* Load referenced images from disk and draw anything we need with cairo now */
|
||||
if (node->border_width[ST_SIDE_TOP] > 0 ||
|
||||
node->border_width[ST_SIDE_LEFT] > 0 ||
|
||||
node->border_width[ST_SIDE_RIGHT] > 0 ||
|
||||
node->border_width[ST_SIDE_BOTTOM] > 0)
|
||||
has_border = TRUE;
|
||||
else
|
||||
has_border = FALSE;
|
||||
|
||||
if (node->border_radius[ST_CORNER_TOPLEFT] > 0 ||
|
||||
node->border_radius[ST_CORNER_TOPRIGHT] > 0 ||
|
||||
node->border_radius[ST_CORNER_BOTTOMLEFT] > 0 ||
|
||||
node->border_radius[ST_CORNER_BOTTOMRIGHT] > 0)
|
||||
has_border_radius = TRUE;
|
||||
else
|
||||
has_border_radius = FALSE;
|
||||
|
||||
/* Load referenced images from disk and draw anything we need with cairo now */
|
||||
background_image = st_theme_node_get_background_image (node);
|
||||
border_image = st_theme_node_get_border_image (node);
|
||||
|
||||
if (border_image)
|
||||
{
|
||||
const char *filename;
|
||||
@ -777,14 +1108,23 @@ st_theme_node_render_resources (StThemeNode *node,
|
||||
node->border_slices_texture = st_texture_cache_load_file_to_cogl_texture (texture_cache, filename);
|
||||
}
|
||||
|
||||
if (node->background_gradient_type != ST_GRADIENT_NONE)
|
||||
node->prerendered_texture = st_theme_node_render_background_with_border (node);
|
||||
|
||||
if (node->border_slices_texture)
|
||||
node->border_slices_material = _st_create_texture_material (node->border_slices_texture);
|
||||
else
|
||||
node->border_slices_material = COGL_INVALID_HANDLE;
|
||||
|
||||
/* Use cairo to prerender the node if there is a gradient, or
|
||||
* background image with borders and/or rounded corners,
|
||||
* since we can't do those things easily with cogl.
|
||||
*
|
||||
* FIXME: if we could figure out ahead of time that a
|
||||
* background image won't overlap with the node borders,
|
||||
* then we could use cogl for that case.
|
||||
*/
|
||||
if ((node->background_gradient_type != ST_GRADIENT_NONE)
|
||||
|| (background_image && (has_border || has_border_radius)))
|
||||
node->prerendered_texture = st_theme_node_render_background_with_border (node);
|
||||
|
||||
if (node->prerendered_texture)
|
||||
node->prerendered_material = _st_create_texture_material (node->prerendered_texture);
|
||||
else
|
||||
@ -798,11 +1138,7 @@ st_theme_node_render_resources (StThemeNode *node,
|
||||
else if (node->prerendered_texture != COGL_INVALID_HANDLE)
|
||||
node->box_shadow_material = _st_create_shadow_material (box_shadow_spec,
|
||||
node->prerendered_texture);
|
||||
else if (node->background_color.alpha > 0 ||
|
||||
node->border_width[ST_SIDE_TOP] > 0 ||
|
||||
node->border_width[ST_SIDE_LEFT] > 0 ||
|
||||
node->border_width[ST_SIDE_RIGHT] > 0 ||
|
||||
node->border_width[ST_SIDE_BOTTOM] > 0)
|
||||
else if (node->background_color.alpha > 0 || has_border)
|
||||
{
|
||||
CoglHandle buffer, offscreen;
|
||||
|
||||
@ -829,10 +1165,8 @@ st_theme_node_render_resources (StThemeNode *node,
|
||||
}
|
||||
}
|
||||
|
||||
background_image = st_theme_node_get_background_image (node);
|
||||
background_image_shadow_spec = st_theme_node_get_background_image_shadow (node);
|
||||
|
||||
if (background_image != NULL)
|
||||
if (background_image != NULL && !has_border && !has_border_radius)
|
||||
{
|
||||
CoglHandle texture;
|
||||
|
||||
@ -1339,7 +1673,9 @@ st_theme_node_paint (StThemeNode *node,
|
||||
* not supported; the background color will be drawn with square
|
||||
* corners.
|
||||
* - The background image is drawn above the border color, not below it.
|
||||
* - We don't clip the background image to the (rounded) border area.
|
||||
* - We clip the background image to the inside edges of the border
|
||||
* instead of the outside edges of the border (but position the image
|
||||
* such that it's aligned to the outside edges)
|
||||
*/
|
||||
|
||||
if (node->box_shadow_material)
|
||||
@ -1352,7 +1688,15 @@ st_theme_node_paint (StThemeNode *node,
|
||||
node->border_slices_material != COGL_INVALID_HANDLE)
|
||||
{
|
||||
if (node->prerendered_material != COGL_INVALID_HANDLE)
|
||||
paint_material_with_opacity (node->prerendered_material, &allocation, paint_opacity);
|
||||
{
|
||||
ClutterActorBox paint_box;
|
||||
|
||||
st_theme_node_get_paint_box (node, &allocation, &paint_box);
|
||||
|
||||
paint_material_with_opacity (node->prerendered_material,
|
||||
&paint_box,
|
||||
paint_opacity);
|
||||
}
|
||||
|
||||
if (node->border_slices_material != COGL_INVALID_HANDLE)
|
||||
st_theme_node_paint_sliced_border_image (node, &allocation, paint_opacity);
|
||||
@ -1367,8 +1711,6 @@ st_theme_node_paint (StThemeNode *node,
|
||||
if (node->background_texture != COGL_INVALID_HANDLE)
|
||||
{
|
||||
ClutterActorBox background_box;
|
||||
|
||||
get_background_position (node, &allocation, &background_box);
|
||||
gboolean has_visible_outline;
|
||||
|
||||
/* If the background doesn't have a border or opaque background,
|
||||
@ -1377,6 +1719,8 @@ st_theme_node_paint (StThemeNode *node,
|
||||
*/
|
||||
has_visible_outline = st_theme_node_has_visible_outline (node);
|
||||
|
||||
get_background_position (node, &allocation, &background_box);
|
||||
|
||||
if (has_visible_outline)
|
||||
cogl_clip_push_rectangle (allocation.x1, allocation.y1, allocation.x2, allocation.y2);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user