diff options
Diffstat (limited to 'gtk/gtkcssshadowvalue.c')
-rw-r--r-- | gtk/gtkcssshadowvalue.c | 398 |
1 files changed, 0 insertions, 398 deletions
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, |