From 14408b7485ad29a5ce6c2cfa82660b4f53f89b9a Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 14 Jul 2018 21:53:29 +0200 Subject: render: Make gtk_render_background() use the snapshot API This removes a lot of duplicated code. --- gtk/gtkcssshadowsvalue.c | 17 -- gtk/gtkcssshadowsvalueprivate.h | 4 - gtk/gtkcssshadowvalue.c | 398 --------------------------------------- gtk/gtkcssshadowvalueprivate.h | 3 - gtk/gtkrender.c | 17 +- gtk/gtkrenderbackground.c | 321 ------------------------------- gtk/gtkrenderbackgroundprivate.h | 6 - 7 files changed, 14 insertions(+), 752 deletions(-) diff --git a/gtk/gtkcssshadowsvalue.c b/gtk/gtkcssshadowsvalue.c index 6aa4c50a93..76fc826ad9 100644 --- a/gtk/gtkcssshadowsvalue.c +++ b/gtk/gtkcssshadowsvalue.c @@ -301,23 +301,6 @@ _gtk_css_shadows_value_paint_icon (const GtkCssValue *shadows, } } -void -_gtk_css_shadows_value_paint_box (const GtkCssValue *shadows, - cairo_t *cr, - const GskRoundedRect*padding_box, - gboolean inset) -{ - guint i; - - g_return_if_fail (shadows->class == >K_CSS_VALUE_SHADOWS); - - for (i = 0; i < shadows->len; i++) - { - if (inset == _gtk_css_shadow_value_get_inset (shadows->values[i])) - _gtk_css_shadow_value_paint_box (shadows->values[i], cr, padding_box); - } -} - void gtk_css_shadows_value_snapshot_outset (const GtkCssValue *shadows, GtkSnapshot *snapshot, diff --git a/gtk/gtkcssshadowsvalueprivate.h b/gtk/gtkcssshadowsvalueprivate.h index 30eb4eebd9..f5a5151b42 100644 --- a/gtk/gtkcssshadowsvalueprivate.h +++ b/gtk/gtkcssshadowsvalueprivate.h @@ -44,10 +44,6 @@ void gtk_css_shadows_value_get_shadows (const GtkCssValue * void _gtk_css_shadows_value_paint_icon (const GtkCssValue *shadows, cairo_t *cr); -void _gtk_css_shadows_value_paint_box (const GtkCssValue *shadows, - cairo_t *cr, - const GskRoundedRect *padding_box, - gboolean inset); void gtk_css_shadows_value_snapshot_outset (const GtkCssValue *shadows, GtkSnapshot *snapshot, const GskRoundedRect *border_box); diff --git a/gtk/gtkcssshadowvalue.c b/gtk/gtkcssshadowvalue.c index b57d6aa9f0..0abcae13cf 100644 --- a/gtk/gtkcssshadowvalue.c +++ b/gtk/gtkcssshadowvalue.c @@ -495,404 +495,6 @@ gtk_css_shadow_value_get_shadow (const GtkCssValue *value, shadow->radius = _gtk_css_number_value_get (value->radius, 0); } -static gboolean -has_empty_clip (cairo_t *cr) -{ - double x1, y1, x2, y2; - - cairo_clip_extents (cr, &x1, &y1, &x2, &y2); - return x1 == x2 && y1 == y2; -} - -static void -draw_shadow (const GtkCssValue *shadow, - cairo_t *cr, - GskRoundedRect *box, - GskRoundedRect *clip_box, - GskBlurFlags blur_flags) -{ - cairo_t *shadow_cr; - gboolean do_blur; - - if (has_empty_clip (cr)) - return; - - gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color)); - do_blur = (blur_flags & (GSK_BLUR_X | GSK_BLUR_Y)) != 0; - if (do_blur) - shadow_cr = gtk_css_shadow_value_start_drawing (shadow, cr, blur_flags); - else - shadow_cr = cr; - - cairo_set_fill_rule (shadow_cr, CAIRO_FILL_RULE_EVEN_ODD); - gsk_rounded_rect_path (box, shadow_cr); - if (shadow->inset) - _gtk_rounded_box_clip_path (clip_box, shadow_cr); - - cairo_fill (shadow_cr); - - if (do_blur) - gtk_css_shadow_value_finish_drawing (shadow, shadow_cr, blur_flags); -} - -typedef struct { - double radius; - graphene_size_t corner; -} CornerMask; - -static guint -corner_mask_hash (CornerMask *mask) -{ - return ((guint)mask->radius << 24) ^ - ((guint)(mask->corner.width*4)) << 12 ^ - ((guint)(mask->corner.height*4)) << 0; -} - -static gboolean -corner_mask_equal (CornerMask *mask1, - CornerMask *mask2) -{ - return - mask1->radius == mask2->radius && - mask1->corner.width == mask2->corner.width && - mask1->corner.height == mask2->corner.height; -} - -static void -draw_shadow_corner (const GtkCssValue *shadow, - cairo_t *cr, - GskRoundedRect *box, - GskRoundedRect *clip_box, - GskCorner corner, - cairo_rectangle_int_t *drawn_rect) -{ - gdouble radius, clip_radius; - int x1, x2, x3, y1, y2, y3, x, y; - GskRoundedRect corner_box; - cairo_t *mask_cr; - cairo_surface_t *mask; - cairo_pattern_t *pattern; - cairo_matrix_t matrix; - double sx, sy; - static GHashTable *corner_mask_cache = NULL; - double max_other; - CornerMask key; - gboolean overlapped; - - radius = _gtk_css_number_value_get (shadow->radius, 0); - clip_radius = gsk_cairo_blur_compute_pixels (radius); - - overlapped = FALSE; - if (corner == GSK_CORNER_TOP_LEFT || corner == GSK_CORNER_BOTTOM_LEFT) - { - x1 = floor (box->bounds.origin.x - clip_radius); - x2 = ceil (box->bounds.origin.x + box->corner[corner].width + clip_radius); - x = x1; - sx = 1; - max_other = MAX(box->corner[GSK_CORNER_TOP_RIGHT].width, box->corner[GSK_CORNER_BOTTOM_RIGHT].width); - x3 = floor (box->bounds.origin.x + box->bounds.size.width - max_other - clip_radius); - if (x2 > x3) - overlapped = TRUE; - } - else - { - x1 = floor (box->bounds.origin.x + box->bounds.size.width - box->corner[corner].width - clip_radius); - x2 = ceil (box->bounds.origin.x + box->bounds.size.width + clip_radius); - x = x2; - sx = -1; - max_other = MAX(box->corner[GSK_CORNER_TOP_LEFT].width, box->corner[GSK_CORNER_BOTTOM_LEFT].width); - x3 = ceil (box->bounds.origin.x + max_other + clip_radius); - if (x3 > x1) - overlapped = TRUE; - } - - if (corner == GSK_CORNER_TOP_LEFT || corner == GSK_CORNER_TOP_RIGHT) - { - y1 = floor (box->bounds.origin.y - clip_radius); - y2 = ceil (box->bounds.origin.y + box->corner[corner].height + clip_radius); - y = y1; - sy = 1; - max_other = MAX(box->corner[GSK_CORNER_BOTTOM_LEFT].height, box->corner[GSK_CORNER_BOTTOM_RIGHT].height); - y3 = floor (box->bounds.origin.y + box->bounds.size.height - max_other - clip_radius); - if (y2 > y3) - overlapped = TRUE; - } - else - { - y1 = floor (box->bounds.origin.y + box->bounds.size.height - box->corner[corner].height - clip_radius); - y2 = ceil (box->bounds.origin.y + box->bounds.size.height + clip_radius); - y = y2; - sy = -1; - max_other = MAX(box->corner[GSK_CORNER_TOP_LEFT].height, box->corner[GSK_CORNER_TOP_RIGHT].height); - y3 = ceil (box->bounds.origin.y + max_other + clip_radius); - if (y3 > y1) - overlapped = TRUE; - } - - drawn_rect->x = x1; - drawn_rect->y = y1; - drawn_rect->width = x2 - x1; - drawn_rect->height = y2 - y1; - - cairo_rectangle (cr, x1, y1, x2 - x1, y2 - y1); - cairo_clip (cr); - - if (shadow->inset || overlapped) - { - /* Fall back to generic path if inset or if the corner radius - runs into each other */ - draw_shadow (shadow, cr, box, clip_box, GSK_BLUR_X | GSK_BLUR_Y); - return; - } - - if (has_empty_clip (cr)) - return; - - /* At this point we're drawing a blurred outset corner. The only - * things that affect the output of the blurred mask in this case - * is: - * - * What corner this is, which defines the orientation (sx,sy) - * and position (x,y) - * - * The blur radius (which also defines the clip_radius) - * - * The the horizontal and vertical corner radius - * - * We apply the first position and orientation when drawing the - * mask, so we cache rendered masks based on the blur radius and the - * corner radius. - */ - if (corner_mask_cache == NULL) - corner_mask_cache = g_hash_table_new_full ((GHashFunc)corner_mask_hash, - (GEqualFunc)corner_mask_equal, - g_free, (GDestroyNotify)cairo_surface_destroy); - - key.radius = radius; - key.corner = box->corner[corner]; - - mask = g_hash_table_lookup (corner_mask_cache, &key); - if (mask == NULL) - { - mask = cairo_surface_create_similar_image (cairo_get_target (cr), CAIRO_FORMAT_A8, - drawn_rect->width + clip_radius, - drawn_rect->height + clip_radius); - mask_cr = cairo_create (mask); - _gtk_rounded_box_init_rect (&corner_box, clip_radius, clip_radius, 2*drawn_rect->width, 2*drawn_rect->height); - corner_box.corner[0] = box->corner[corner]; - gsk_rounded_rect_path (&corner_box, mask_cr); - cairo_fill (mask_cr); - gsk_cairo_blur_surface (mask, radius, GSK_BLUR_X | GSK_BLUR_Y); - cairo_destroy (mask_cr); - g_hash_table_insert (corner_mask_cache, g_memdup (&key, sizeof (key)), mask); - } - - gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color)); - pattern = cairo_pattern_create_for_surface (mask); - cairo_matrix_init_identity (&matrix); - cairo_matrix_scale (&matrix, sx, sy); - cairo_matrix_translate (&matrix, -x, -y); - cairo_pattern_set_matrix (pattern, &matrix); - cairo_mask (cr, pattern); - cairo_pattern_destroy (pattern); -} - -static void -draw_shadow_side (const GtkCssValue *shadow, - cairo_t *cr, - GskRoundedRect *box, - GskRoundedRect *clip_box, - GtkCssSide side, - cairo_rectangle_int_t *drawn_rect) -{ - GskBlurFlags blur_flags = GSK_BLUR_REPEAT; - gdouble radius, clip_radius; - int x1, x2, y1, y2; - - radius = _gtk_css_number_value_get (shadow->radius, 0); - clip_radius = gsk_cairo_blur_compute_pixels (radius); - - if (side == GTK_CSS_TOP || side == GTK_CSS_BOTTOM) - { - blur_flags |= GSK_BLUR_Y; - x1 = floor (box->bounds.origin.x - clip_radius); - x2 = ceil (box->bounds.origin.x + box->bounds.size.width + clip_radius); - } - else if (side == GTK_CSS_LEFT) - { - x1 = floor (box->bounds.origin.x -clip_radius); - x2 = ceil (box->bounds.origin.x + clip_radius); - } - else - { - x1 = floor (box->bounds.origin.x + box->bounds.size.width -clip_radius); - x2 = ceil (box->bounds.origin.x + box->bounds.size.width + clip_radius); - } - - if (side == GTK_CSS_LEFT || side == GTK_CSS_RIGHT) - { - blur_flags |= GSK_BLUR_X; - y1 = floor (box->bounds.origin.y - clip_radius); - y2 = ceil (box->bounds.origin.y + box->bounds.size.height + clip_radius); - } - else if (side == GTK_CSS_TOP) - { - y1 = floor (box->bounds.origin.y -clip_radius); - y2 = ceil (box->bounds.origin.y + clip_radius); - } - else - { - y1 = floor (box->bounds.origin.y + box->bounds.size.height -clip_radius); - y2 = ceil (box->bounds.origin.y + box->bounds.size.height + clip_radius); - } - - drawn_rect->x = x1; - drawn_rect->y = y1; - drawn_rect->width = x2 - x1; - drawn_rect->height = y2 - y1; - - cairo_rectangle (cr, x1, y1, x2 - x1, y2 - y1); - cairo_clip (cr); - draw_shadow (shadow, cr, box, clip_box, blur_flags); -} - -void -_gtk_css_shadow_value_paint_box (const GtkCssValue *shadow, - cairo_t *cr, - const GskRoundedRect*padding_box) -{ - GskRoundedRect box, clip_box; - double spread, radius, clip_radius, x, y, outside; - double x1c, y1c, x2c, y2c; - - g_return_if_fail (shadow->class == >K_CSS_VALUE_SHADOW); - - /* We don't need to draw invisible shadows */ - if (gdk_rgba_is_clear (_gtk_css_rgba_value_get_rgba (shadow->color))) - return; - - cairo_clip_extents (cr, &x1c, &y1c, &x2c, &y2c); - if ((shadow->inset && !gsk_rounded_rect_intersects_rect (padding_box, &GRAPHENE_RECT_INIT (x1c, y1c, x2c - x1c, y2c - y1c))) || - (!shadow->inset && gsk_rounded_rect_contains_rect (padding_box, &GRAPHENE_RECT_INIT (x1c, y1c, x2c - x1c, y2c - y1c)))) - return; - - cairo_save (cr); - - spread = _gtk_css_number_value_get (shadow->spread, 0); - radius = _gtk_css_number_value_get (shadow->radius, 0); - clip_radius = gsk_cairo_blur_compute_pixels (radius); - x = _gtk_css_number_value_get (shadow->hoffset, 0); - y = _gtk_css_number_value_get (shadow->voffset, 0); - - if (shadow->inset) - { - gsk_rounded_rect_path (padding_box, cr); - cairo_clip (cr); - } - else - { - cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); - gsk_rounded_rect_path (padding_box, cr); - outside = spread + clip_radius + MAX (fabs (x), fabs (y)); - clip_box = *padding_box; - gsk_rounded_rect_shrink (&clip_box, -outside, -outside, -outside, -outside); - _gtk_rounded_box_clip_path (&clip_box, cr); - - cairo_clip (cr); - } - - box = *padding_box; - gsk_rounded_rect_offset (&box, x, y); - - if (shadow->inset) - gsk_rounded_rect_shrink (&box, spread, spread, spread, spread); - else /* Outset */ - gsk_rounded_rect_shrink (&box, -spread, -spread, -spread, -spread); - - clip_box = *padding_box; - gsk_rounded_rect_shrink (&clip_box, -clip_radius, -clip_radius, -clip_radius, -clip_radius); - - if (!needs_blur (shadow)) - draw_shadow (shadow, cr, &box, &clip_box, GSK_BLUR_NONE); - else - { - int i; - cairo_region_t *remaining; - cairo_rectangle_int_t r; - - /* For the blurred case we divide the rendering into 9 parts, - * 4 of the corners, 4 for the horizonat/vertical lines and - * one for the interior. We make the non-interior parts - * large enought to fit the full radius of the blur, so that - * the interior part can be drawn solidly. - */ - - if (shadow->inset) - { - /* In the inset case we want to paint the whole clip-box. - * We could remove the part of "box" where the blur doesn't - * reach, but computing that is a bit tricky since the - * rounded corners are on the "inside" of it. */ - r.x = floor (clip_box.bounds.origin.x); - r.y = floor (clip_box.bounds.origin.y); - r.width = ceil (clip_box.bounds.origin.x + clip_box.bounds.size.width) - r.x; - r.height = ceil (clip_box.bounds.origin.y + clip_box.bounds.size.height) - r.y; - remaining = cairo_region_create_rectangle (&r); - } - else - { - /* In the outset case we want to paint the entire box, plus as far - * as the radius reaches from it */ - r.x = floor (box.bounds.origin.x - clip_radius); - r.y = floor (box.bounds.origin.y - clip_radius); - r.width = ceil (box.bounds.origin.x + box.bounds.size.width + clip_radius) - r.x; - r.height = ceil (box.bounds.origin.y + box.bounds.size.height + clip_radius) - r.y; - - remaining = cairo_region_create_rectangle (&r); - } - - /* First do the corners of box */ - for (i = 0; i < 4; i++) - { - cairo_save (cr); - /* Always clip with remaining to ensure we never draw any area twice */ - gdk_cairo_region (cr, remaining); - cairo_clip (cr); - draw_shadow_corner (shadow, cr, &box, &clip_box, i, &r); - cairo_restore (cr); - - /* We drew the region, remove it from remaining */ - cairo_region_subtract_rectangle (remaining, &r); - } - - /* Then the sides */ - for (i = 0; i < 4; i++) - { - cairo_save (cr); - /* Always clip with remaining to ensure we never draw any area twice */ - gdk_cairo_region (cr, remaining); - cairo_clip (cr); - draw_shadow_side (shadow, cr, &box, &clip_box, i, &r); - cairo_restore (cr); - - /* We drew the region, remove it from remaining */ - cairo_region_subtract_rectangle (remaining, &r); - } - - /* Then the rest, which needs no blurring */ - - cairo_save (cr); - gdk_cairo_region (cr, remaining); - cairo_clip (cr); - draw_shadow (shadow, cr, &box, &clip_box, GSK_BLUR_NONE); - cairo_restore (cr); - - cairo_region_destroy (remaining); - } - - cairo_restore (cr); -} - void gtk_css_shadow_value_snapshot_outset (const GtkCssValue *shadow, GtkSnapshot *snapshot, diff --git a/gtk/gtkcssshadowvalueprivate.h b/gtk/gtkcssshadowvalueprivate.h index b04beea986..4633c8abed 100644 --- a/gtk/gtkcssshadowvalueprivate.h +++ b/gtk/gtkcssshadowvalueprivate.h @@ -44,9 +44,6 @@ void gtk_css_shadow_value_get_shadow (const GtkCssValue void _gtk_css_shadow_value_paint_icon (const GtkCssValue *shadow, cairo_t *cr); -void _gtk_css_shadow_value_paint_box (const GtkCssValue *shadow, - cairo_t *cr, - const GskRoundedRect *padding_box); void gtk_css_shadow_value_snapshot_outset (const GtkCssValue *shadow, GtkSnapshot *snapshot, diff --git a/gtk/gtkrender.c b/gtk/gtkrender.c index b42b402269..0481d67756 100644 --- a/gtk/gtkrender.c +++ b/gtk/gtkrender.c @@ -29,7 +29,6 @@ #include "gtkcssshadowsvalueprivate.h" #include "gtkcsstransformvalueprivate.h" #include "gtkhslaprivate.h" -#include "gtkrenderbackgroundprivate.h" #include "gtkrenderborderprivate.h" #include "gtkrendericonprivate.h" #include "gtkstylecontextprivate.h" @@ -238,14 +237,26 @@ gtk_render_background (GtkStyleContext *context, gdouble width, gdouble height) { + GtkSnapshot *snapshot; + GskRenderNode *node; + g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); if (width <= 0 || height <= 0) return; - gtk_css_style_render_background (gtk_style_context_lookup_style (context), - cr, x, y, width, height); + snapshot = gtk_snapshot_new (); + gtk_snapshot_render_background (snapshot, context, x, y, width, height); + node = gtk_snapshot_free_to_node (snapshot); + if (node == NULL) + return; + + cairo_save (cr); + gsk_render_node_draw (node, cr); + cairo_restore (cr); + + gsk_render_node_unref (node); } /** diff --git a/gtk/gtkrenderbackground.c b/gtk/gtkrenderbackground.c index e4143fedd8..0be739f679 100644 --- a/gtk/gtkrenderbackground.c +++ b/gtk/gtkrenderbackground.c @@ -57,23 +57,6 @@ struct _GtkThemingBackground { GskRoundedRect boxes[N_BOXES]; }; -static void -_gtk_theming_background_paint_color (GtkThemingBackground *bg, - cairo_t *cr, - const GdkRGBA *bg_color, - GtkCssValue *background_image) -{ - gint n_values = _gtk_css_array_value_get_n_values (background_image); - GtkCssArea clip = _gtk_css_area_value_get - (_gtk_css_array_value_get_nth - (gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_CLIP), - n_values - 1)); - - gsk_rounded_rect_path (&bg->boxes[clip], cr); - gdk_cairo_set_source_rgba (cr, bg_color); - cairo_fill (cr); -} - static void gtk_theming_background_snapshot_color (const GtkThemingBackground *bg, GtkSnapshot *snapshot, @@ -103,230 +86,6 @@ gtk_theming_background_snapshot_color (const GtkThemingBackground *bg, } } -static gboolean -_gtk_theming_background_needs_push_group (GtkCssStyle *style) -{ - GtkCssValue *blend_modes; - gint i; - - blend_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE); - - /* - * If we have any blend mode different than NORMAL, we'll need to - * push a group in order to correctly apply the blend modes. - */ - for (i = _gtk_css_array_value_get_n_values (blend_modes); i > 0; i--) - { - GskBlendMode blend_mode; - - blend_mode = _gtk_css_blend_mode_value_get (_gtk_css_array_value_get_nth (blend_modes, i - 1)); - - if (blend_mode != GSK_BLEND_MODE_DEFAULT) - return TRUE; - } - - return FALSE; -} - -static void -gtk_theming_background_paint_layer (GtkThemingBackground *bg, - guint idx, - cairo_t *cr) -{ - GtkCssRepeatStyle hrepeat, vrepeat; - const GtkCssValue *pos, *repeat; - GtkCssImage *image; - GskBlendMode blend_mode; - const GskRoundedRect *origin; - double image_width, image_height; - double width, height; - - pos = _gtk_css_array_value_get_nth (gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_POSITION), idx); - repeat = _gtk_css_array_value_get_nth (gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_REPEAT), idx); - hrepeat = _gtk_css_background_repeat_value_get_x (repeat); - vrepeat = _gtk_css_background_repeat_value_get_y (repeat); - image = _gtk_css_image_value_get_image ( - _gtk_css_array_value_get_nth ( - gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_IMAGE), - idx)); - blend_mode = _gtk_css_blend_mode_value_get ( - _gtk_css_array_value_get_nth ( - gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE), idx)); - - origin = &bg->boxes[ - _gtk_css_area_value_get ( - _gtk_css_array_value_get_nth ( - gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_ORIGIN), - idx))]; - width = origin->bounds.size.width; - height = origin->bounds.size.height; - - if (image == NULL || width <= 0 || height <= 0) - return; - - _gtk_css_bg_size_value_compute_size (_gtk_css_array_value_get_nth (gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_SIZE), idx), - image, - width, - height, - &image_width, - &image_height); - - if (image_width <= 0 || image_height <= 0) - return; - - /* optimization */ - if (image_width == width) - hrepeat = GTK_CSS_REPEAT_STYLE_NO_REPEAT; - if (image_height == height) - vrepeat = GTK_CSS_REPEAT_STYLE_NO_REPEAT; - - - cairo_save (cr); - - gsk_rounded_rect_path ( - &bg->boxes[ - _gtk_css_area_value_get ( - _gtk_css_array_value_get_nth ( - gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_CLIP), - idx))], - cr); - cairo_clip (cr); - - - cairo_translate (cr, origin->bounds.origin.x, origin->bounds.origin.y); - - /* - * Apply the blend mode, if any. - */ - if (G_UNLIKELY (_gtk_css_blend_mode_get_operator (blend_mode) != cairo_get_operator (cr))) - cairo_set_operator (cr, _gtk_css_blend_mode_get_operator (blend_mode)); - - - if (hrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT && vrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT) - { - cairo_translate (cr, - _gtk_css_position_value_get_x (pos, width - image_width), - _gtk_css_position_value_get_y (pos, height - image_height)); - /* shortcut for normal case */ - _gtk_css_image_draw (image, cr, image_width, image_height); - } - else - { - int surface_width, surface_height; - cairo_rectangle_t fill_rect; - cairo_surface_t *surface; - cairo_t *cr2; - - /* If ‘background-repeat’ is ‘round’ for one (or both) dimensions, - * there is a second step. The UA must scale the image in that - * dimension (or both dimensions) so that it fits a whole number of - * times in the background positioning area. In the case of the width - * (height is analogous): - * - * If X ≠ 0 is the width of the image after step one and W is the width - * of the background positioning area, then the rounded width - * X' = W / round(W / X) where round() is a function that returns the - * nearest natural number (integer greater than zero). - * - * If ‘background-repeat’ is ‘round’ for one dimension only and if - * ‘background-size’ is ‘auto’ for the other dimension, then there is - * a third step: that other dimension is scaled so that the original - * aspect ratio is restored. - */ - if (hrepeat == GTK_CSS_REPEAT_STYLE_ROUND) - { - double n = round (width / image_width); - - n = MAX (1, n); - - if (vrepeat != GTK_CSS_REPEAT_STYLE_ROUND - /* && vsize == auto (it is by default) */) - image_height *= width / (image_width * n); - image_width = width / n; - } - if (vrepeat == GTK_CSS_REPEAT_STYLE_ROUND) - { - double n = round (height / image_height); - - n = MAX (1, n); - - if (hrepeat != GTK_CSS_REPEAT_STYLE_ROUND - /* && hsize == auto (it is by default) */) - image_width *= height / (image_height * n); - image_height = height / n; - } - - /* if hrepeat or vrepeat is 'space', we create a somewhat larger surface - * to store the extra space. */ - if (hrepeat == GTK_CSS_REPEAT_STYLE_SPACE) - { - double n = floor (width / image_width); - surface_width = n ? round (width / n) : 0; - } - else - surface_width = round (image_width); - - if (vrepeat == GTK_CSS_REPEAT_STYLE_SPACE) - { - double n = floor (height / image_height); - surface_height = n ? round (height / n) : 0; - } - else - surface_height = round (image_height); - - surface = cairo_surface_create_similar (cairo_get_target (cr), - CAIRO_CONTENT_COLOR_ALPHA, - surface_width, surface_height); - cr2 = cairo_create (surface); - cairo_translate (cr2, - 0.5 * (surface_width - image_width), - 0.5 * (surface_height - image_height)); - _gtk_css_image_draw (image, cr2, image_width, image_height); - cairo_destroy (cr2); - - cairo_set_source_surface (cr, surface, - _gtk_css_position_value_get_x (pos, width - image_width), - _gtk_css_position_value_get_y (pos, height - image_height)); - cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); - cairo_surface_destroy (surface); - - if (hrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT) - { - fill_rect.x = _gtk_css_position_value_get_x (pos, width - image_width); - fill_rect.width = image_width; - } - else - { - fill_rect.x = 0; - fill_rect.width = width; - } - - if (vrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT) - { - fill_rect.y = _gtk_css_position_value_get_y (pos, height - image_height); - fill_rect.height = image_height; - } - else - { - fill_rect.y = 0; - fill_rect.height = height; - } - - cairo_rectangle (cr, fill_rect.x, fill_rect.y, - fill_rect.width, fill_rect.height); - cairo_fill (cr); - } - - /* - * Since this cairo_t can be shared with other widgets, - * we must reset the operator after all the backgrounds - * are properly rendered. - */ - cairo_set_operator (cr, CAIRO_OPERATOR_OVER); - - cairo_restore (cr); -} - static void gtk_theming_background_snapshot_layer (const GtkThemingBackground *bg, guint idx, @@ -530,86 +289,6 @@ gtk_theming_background_init (GtkThemingBackground *bg, 0, 0, width, height); } -void -gtk_css_style_render_background (GtkCssStyle *style, - cairo_t *cr, - gdouble x, - gdouble y, - gdouble width, - gdouble height) -{ - GtkThemingBackground bg; - gint idx; - GtkCssValue *background_image; - GtkCssValue *box_shadow; - const GdkRGBA *bg_color; - gboolean needs_push_group; - gint number_of_layers; - - background_image = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_IMAGE); - bg_color = _gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_COLOR)); - box_shadow = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BOX_SHADOW); - - /* This is the common default case of no background */ - if (gdk_rgba_is_clear (bg_color) && - _gtk_css_array_value_get_n_values (background_image) == 1 && - _gtk_css_image_value_get_image (_gtk_css_array_value_get_nth (background_image, 0)) == NULL && - _gtk_css_shadows_value_is_none (box_shadow)) - return; - - gtk_theming_background_init (&bg, style, width, height); - - cairo_save (cr); - cairo_translate (cr, x, y); - - /* Outset shadows */ - _gtk_css_shadows_value_paint_box (box_shadow, - cr, - &bg.boxes[GTK_CSS_AREA_BORDER_BOX], - FALSE); - - /* - * When we have a blend mode set for the background, we cannot blend the current - * widget's drawing with whatever the content that the Cairo context may have. - * Because of that, push the drawing to a new group before drawing the background - * layers, and paint the resulting image back after. - */ - needs_push_group = _gtk_theming_background_needs_push_group (style); - - if (needs_push_group) - { - cairo_save (cr); - cairo_rectangle (cr, 0, 0, width, height); - cairo_clip (cr); - cairo_push_group (cr); - } - - _gtk_theming_background_paint_color (&bg, cr, bg_color, background_image); - - number_of_layers = _gtk_css_array_value_get_n_values (background_image); - - for (idx = number_of_layers - 1; idx >= 0; idx--) - { - gtk_theming_background_paint_layer (&bg, idx, cr); - } - - /* Paint back the resulting surface */ - if (needs_push_group) - { - cairo_pop_group_to_source (cr); - cairo_paint (cr); - cairo_restore (cr); - } - - /* Inset shadows */ - _gtk_css_shadows_value_paint_box (box_shadow, - cr, - &bg.boxes[GTK_CSS_AREA_PADDING_BOX], - TRUE); - - cairo_restore (cr); -} - void gtk_css_style_snapshot_background (GtkCssStyle *style, GtkSnapshot *snapshot, diff --git a/gtk/gtkrenderbackgroundprivate.h b/gtk/gtkrenderbackgroundprivate.h index dd7f2f98dc..a812b3ef7a 100644 --- a/gtk/gtkrenderbackgroundprivate.h +++ b/gtk/gtkrenderbackgroundprivate.h @@ -28,12 +28,6 @@ G_BEGIN_DECLS -void gtk_css_style_render_background (GtkCssStyle *style, - cairo_t *cr, - gdouble x, - gdouble y, - gdouble width, - gdouble height); void gtk_css_style_snapshot_background (GtkCssStyle *style, GtkSnapshot *snapshot, gdouble width, -- cgit v1.2.1