[gnome-shell] StThemeDrawing: clip background to border
- From: Ray Strode <halfline src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] StThemeDrawing: clip background to border
- Date: Mon, 24 Jan 2011 17:24:56 +0000 (UTC)
commit 779d5462f272f809344d46baf2b152bf7ed7af47
Author: Ray Strode <rstrode redhat com>
Date: Fri Dec 10 17:15:39 2010 -0500
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
src/st/st-theme-node-drawing.c | 460 +++++++++++++++++++++++++++++++++++-----
1 files changed, 402 insertions(+), 58 deletions(-)
---
diff --git a/src/st/st-theme-node-drawing.c b/src/st/st-theme-node-drawing.c
index 59b3f84..52c737e 100644
--- a/src/st/st-theme-node-drawing.c
+++ b/src/st/st-theme-node-drawing.c
@@ -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);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]