diff options
author | Matthias Clasen <mclasen@redhat.com> | 2020-02-13 13:43:59 +0000 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2020-02-13 13:43:59 +0000 |
commit | 313c399122c61900e003fa24c026ff9055ae1aaa (patch) | |
tree | 181c4587a0a2b205e1433bc143ab6564bf160200 | |
parent | c313a71c3a0757d07bcf26a03236ea8cad624880 (diff) | |
parent | 052d0f6e6004b7c791cfbb891c70ab0bb316c228 (diff) | |
download | gtk+-313c399122c61900e003fa24c026ff9055ae1aaa.tar.gz |
Merge branch 'wip/otte/no-clip-on-draw' into 'master'
Various fixes to rendernode drawing with Cairo
See merge request GNOME/gtk!1425
-rw-r--r-- | docs/reference/gdk/gdk4-sections.txt | 1 | ||||
-rw-r--r-- | gdk/gdkcairo.c | 39 | ||||
-rw-r--r-- | gdk/gdkcairo.h | 4 | ||||
-rw-r--r-- | gsk/gskcairoblur.c | 29 | ||||
-rw-r--r-- | gsk/gskrendernodeimpl.c | 94 | ||||
-rw-r--r-- | gsk/gskroundedrect.c | 73 | ||||
-rw-r--r-- | testsuite/gsk/meson.build | 1 | ||||
-rw-r--r-- | testsuite/gsk/reftest-compare.c | 35 | ||||
-rw-r--r-- | testsuite/gsk/rounded-rect.c | 100 | ||||
-rw-r--r-- | testsuite/reftests/reftest-compare.c | 36 |
10 files changed, 243 insertions, 169 deletions
diff --git a/docs/reference/gdk/gdk4-sections.txt b/docs/reference/gdk/gdk4-sections.txt index bb56a12c26..12cf24b475 100644 --- a/docs/reference/gdk/gdk4-sections.txt +++ b/docs/reference/gdk/gdk4-sections.txt @@ -366,7 +366,6 @@ gdk_pango_layout_line_get_clip_region <TITLE>Cairo Interaction</TITLE> <FILE>cairo_interaction</FILE> gdk_surface_create_similar_surface -gdk_cairo_get_clip_rectangle gdk_cairo_set_source_rgba gdk_cairo_set_source_pixbuf gdk_cairo_rectangle diff --git a/gdk/gdkcairo.c b/gdk/gdkcairo.c index c5917cfeb9..e9fcdff086 100644 --- a/gdk/gdkcairo.c +++ b/gdk/gdkcairo.c @@ -40,45 +40,6 @@ /** - * gdk_cairo_get_clip_rectangle: - * @cr: a cairo context - * @rect: (out) (allow-none): return location for the clip, or %NULL - * - * This is a convenience function around cairo_clip_extents(). - * It rounds the clip extents to integer coordinates and returns - * a boolean indicating if a clip area exists. - * - * Returns: %TRUE if a clip rectangle exists, %FALSE if all of @cr is - * clipped and all drawing can be skipped - */ -gboolean -gdk_cairo_get_clip_rectangle (cairo_t *cr, - GdkRectangle *rect) -{ - double x1, y1, x2, y2; - gboolean clip_exists; - - cairo_clip_extents (cr, &x1, &y1, &x2, &y2); - - clip_exists = x1 < x2 && y1 < y2; - - if (rect) - { - x1 = floor (x1); - y1 = floor (y1); - x2 = ceil (x2); - y2 = ceil (y2); - - rect->x = CLAMP (x1, G_MININT, G_MAXINT); - rect->y = CLAMP (y1, G_MININT, G_MAXINT); - rect->width = CLAMP (x2 - x1, G_MININT, G_MAXINT); - rect->height = CLAMP (y2 - y1, G_MININT, G_MAXINT); - } - - return clip_exists; -} - -/** * gdk_cairo_set_source_rgba: * @cr: a cairo context * @rgba: a #GdkRGBA diff --git a/gdk/gdkcairo.h b/gdk/gdkcairo.h index c4e2d3836c..49b4117eb0 100644 --- a/gdk/gdkcairo.h +++ b/gdk/gdkcairo.h @@ -30,10 +30,6 @@ G_BEGIN_DECLS GDK_AVAILABLE_IN_ALL -gboolean gdk_cairo_get_clip_rectangle (cairo_t *cr, - GdkRectangle *rect); - -GDK_AVAILABLE_IN_ALL void gdk_cairo_set_source_rgba (cairo_t *cr, const GdkRGBA *rgba); GDK_AVAILABLE_IN_ALL diff --git a/gsk/gskcairoblur.c b/gsk/gskcairoblur.c index 6b5a3d56df..6e9266c70d 100644 --- a/gsk/gskcairoblur.c +++ b/gsk/gskcairoblur.c @@ -281,8 +281,13 @@ gsk_cairo_blur_compute_pixels (double radius) } static gboolean -needs_blur (float radius) +needs_blur (float radius, + GskBlurFlags blur_flags) { + /* Neither blurring horizontal nor vertical means no blurring at all. */ + if ((blur_flags & (GSK_BLUR_X | GSK_BLUR_Y)) == 0) + return FALSE; + /* The code doesn't actually do any blurring for radius 1, as it * ends up with box filter size 1 */ if (radius <= 1.0) @@ -298,7 +303,7 @@ gsk_cairo_blur_start_drawing (cairo_t *cr, float radius, GskBlurFlags blur_flags) { - cairo_rectangle_int_t clip_rect; + double clip_x1, clip_x2, clip_y1, clip_y2, clip_width, clip_height; cairo_surface_t *surface; cairo_t *blur_cr; gdouble clip_radius; @@ -306,10 +311,12 @@ gsk_cairo_blur_start_drawing (cairo_t *cr, gboolean blur_x = (blur_flags & GSK_BLUR_X) != 0; gboolean blur_y = (blur_flags & GSK_BLUR_Y) != 0; - if (!needs_blur (radius)) + if (!needs_blur (radius, blur_flags)) return cr; - gdk_cairo_get_clip_rectangle (cr, &clip_rect); + cairo_clip_extents (cr, &clip_x1, &clip_y1, &clip_x2, &clip_y2); + clip_width = clip_x2 - clip_x1; + clip_height = clip_y2 - clip_y1; clip_radius = gsk_cairo_blur_compute_pixels (radius); @@ -319,20 +326,20 @@ gsk_cairo_blur_start_drawing (cairo_t *cr, if (blur_flags & GSK_BLUR_REPEAT) { if (!blur_x) - clip_rect.width = 1; + clip_width = 1; if (!blur_y) - clip_rect.height = 1; + clip_height = 1; } /* Create a larger surface to center the blur. */ surface = cairo_surface_create_similar_image (cairo_get_target (cr), CAIRO_FORMAT_A8, - x_scale * (clip_rect.width + (blur_x ? 2 * clip_radius : 0)), - y_scale * (clip_rect.height + (blur_y ? 2 * clip_radius : 0))); + x_scale * (clip_width + (blur_x ? 2 * clip_radius : 0)), + y_scale * (clip_height + (blur_y ? 2 * clip_radius : 0))); cairo_surface_set_device_scale (surface, x_scale, y_scale); cairo_surface_set_device_offset (surface, - x_scale * ((blur_x ? clip_radius : 0) - clip_rect.x), - y_scale * ((blur_y ? clip_radius : 0) - clip_rect.y)); + x_scale * ((blur_x ? clip_radius : 0) - clip_x1), + y_scale * ((blur_y ? clip_radius : 0) - clip_y1)); blur_cr = cairo_create (surface); cairo_set_user_data (blur_cr, &original_cr_key, cairo_reference (cr), (cairo_destroy_func_t) cairo_destroy); @@ -372,7 +379,7 @@ gsk_cairo_blur_finish_drawing (cairo_t *cr, cairo_surface_t *surface; gdouble x_scale; - if (!needs_blur (radius)) + if (!needs_blur (radius, blur_flags)) return cr; original_cr = cairo_get_user_data (cr, &original_cr_key); diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index a6957ff657..aad1fa59ef 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -30,6 +30,15 @@ #include "gdk/gdktextureprivate.h" #include <cairo-ft.h> +static inline void +gsk_cairo_rectangle (cairo_t *cr, + const graphene_rect_t *rect) +{ + cairo_rectangle (cr, + rect->origin.x, rect->origin.y, + rect->size.width, rect->size.height); +} + static void rectangle_init_from_graphene (cairo_rectangle_int_t *cairo, const graphene_rect_t *graphene) @@ -71,9 +80,7 @@ gsk_color_node_draw (GskRenderNode *node, gdk_cairo_set_source_rgba (cr, &self->color); - cairo_rectangle (cr, - node->bounds.origin.x, node->bounds.origin.y, - node->bounds.size.width, node->bounds.size.height); + gsk_cairo_rectangle (cr, &node->bounds); cairo_fill (cr); } @@ -184,9 +191,7 @@ gsk_linear_gradient_node_draw (GskRenderNode *node, cairo_set_source (cr, pattern); cairo_pattern_destroy (pattern); - cairo_rectangle (cr, - node->bounds.origin.x, node->bounds.origin.y, - node->bounds.size.width, node->bounds.size.height); + gsk_cairo_rectangle (cr, &node->bounds); cairo_fill (cr); } @@ -638,28 +643,26 @@ gsk_texture_node_draw (GskRenderNode *node, GskTextureNode *self = (GskTextureNode *) node; cairo_surface_t *surface; cairo_pattern_t *pattern; + cairo_matrix_t matrix; surface = gdk_texture_download_surface (self->texture); - - cairo_save (cr); - - cairo_translate (cr, node->bounds.origin.x, node->bounds.origin.y); - cairo_scale (cr, - node->bounds.size.width / gdk_texture_get_width (self->texture), - node->bounds.size.height / gdk_texture_get_height (self->texture)); - pattern = cairo_pattern_create_for_surface (surface); cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); - cairo_set_source (cr, pattern); - cairo_rectangle (cr, - 0, 0, - gdk_texture_get_width (self->texture), gdk_texture_get_height (self->texture)); - cairo_fill (cr); - cairo_restore (cr); + cairo_matrix_init_scale (&matrix, + gdk_texture_get_width (self->texture) / node->bounds.size.width, + gdk_texture_get_height (self->texture) / node->bounds.size.height); + cairo_matrix_translate (&matrix, + -node->bounds.origin.x, + -node->bounds.origin.y); + cairo_pattern_set_matrix (pattern, &matrix); + cairo_set_source (cr, pattern); cairo_pattern_destroy (pattern); cairo_surface_destroy (surface); + + gsk_cairo_rectangle (cr, &node->bounds); + cairo_fill (cr); } static void @@ -770,29 +773,21 @@ draw_shadow (cairo_t *cr, GskBlurFlags blur_flags) { cairo_t *shadow_cr; - gboolean do_blur; if (has_empty_clip (cr)) return; gdk_cairo_set_source_rgba (cr, color); - do_blur = (blur_flags & (GSK_BLUR_X | GSK_BLUR_Y)) != 0; - if (do_blur) - shadow_cr = gsk_cairo_blur_start_drawing (cr, radius, blur_flags); - else - shadow_cr = cr; + shadow_cr = gsk_cairo_blur_start_drawing (cr, radius, blur_flags); cairo_set_fill_rule (shadow_cr, CAIRO_FILL_RULE_EVEN_ODD); gsk_rounded_rect_path (box, shadow_cr); if (inset) - cairo_rectangle (shadow_cr, - clip_box->bounds.origin.x, clip_box->bounds.origin.y, - clip_box->bounds.size.width, clip_box->bounds.size.height); + gsk_cairo_rectangle (shadow_cr, &clip_box->bounds); cairo_fill (shadow_cr); - if (do_blur) - gsk_cairo_blur_finish_drawing (shadow_cr, radius, color, blur_flags); + gsk_cairo_blur_finish_drawing (shadow_cr, radius, color, blur_flags); } typedef struct { @@ -1329,9 +1324,7 @@ gsk_outset_shadow_node_draw (GskRenderNode *node, cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); gsk_rounded_rect_path (&self->outline, cr); - cairo_rectangle (cr, - clip_box.bounds.origin.x, clip_box.bounds.origin.y, - clip_box.bounds.size.width, clip_box.bounds.size.height); + gsk_cairo_rectangle (cr, &clip_box.bounds); cairo_clip (cr); @@ -1666,9 +1659,7 @@ gsk_cairo_node_get_draw_context (GskRenderNode *node) res = cairo_create (self->surface); } - cairo_rectangle (res, - node->bounds.origin.x, node->bounds.origin.y, - node->bounds.size.width, node->bounds.size.height); + gsk_cairo_rectangle (res, &node->bounds); cairo_clip (res); return res; @@ -1904,7 +1895,7 @@ gsk_transform_node_draw (GskRenderNode *node, if (gsk_transform_get_category (self->transform) < GSK_TRANSFORM_CATEGORY_2D) { cairo_set_source_rgb (cr, 255 / 255., 105 / 255., 180 / 255.); - cairo_rectangle (cr, node->bounds.origin.x, node->bounds.origin.y, node->bounds.size.width, node->bounds.size.height); + gsk_cairo_rectangle (cr, &node->bounds); cairo_fill (cr); return; } @@ -2220,8 +2211,7 @@ gsk_opacity_node_draw (GskRenderNode *node, cairo_save (cr); /* clip so the push_group() creates a smaller surface */ - cairo_rectangle (cr, node->bounds.origin.x, node->bounds.origin.y, - node->bounds.size.width, node->bounds.size.height); + gsk_cairo_rectangle (cr, &node->bounds); cairo_clip (cr); cairo_push_group (cr); @@ -2351,8 +2341,7 @@ gsk_color_matrix_node_draw (GskRenderNode *node, cairo_save (cr); /* clip so the push_group() creates a smaller surface */ - cairo_rectangle (cr, node->bounds.origin.x, node->bounds.origin.y, - node->bounds.size.width, node->bounds.size.height); + gsk_cairo_rectangle (cr, &node->bounds); cairo_clip (cr); cairo_push_group (cr); @@ -2550,15 +2539,12 @@ gsk_repeat_node_draw (GskRenderNode *node, .x0 = - self->child_bounds.origin.x, .y0 = - self->child_bounds.origin.y }); - cairo_set_source (cr, pattern); - cairo_rectangle (cr, - node->bounds.origin.x, node->bounds.origin.y, - node->bounds.size.width, node->bounds.size.height); - cairo_fill (cr); - cairo_pattern_destroy (pattern); cairo_surface_destroy (surface); + + gsk_cairo_rectangle (cr, &node->bounds); + cairo_fill (cr); } static const GskRenderNodeClass GSK_REPEAT_NODE_CLASS = { @@ -2653,9 +2639,7 @@ gsk_clip_node_draw (GskRenderNode *node, cairo_save (cr); - cairo_rectangle (cr, - self->clip.origin.x, self->clip.origin.y, - self->clip.size.width, self->clip.size.height); + gsk_cairo_rectangle (cr, &self->clip); cairo_clip (cr); gsk_render_node_draw (self->child, cr); @@ -2915,9 +2899,14 @@ gsk_shadow_node_draw (GskRenderNode *node, cairo_pattern_t *pattern; gsize i; + cairo_save (cr); + /* clip so the push_group() creates a small surface */ + gsk_cairo_rectangle (cr, &self->child->bounds); + cairo_clip (cr); cairo_push_group (cr); gsk_render_node_draw (self->child, cr); pattern = cairo_pop_group (cr); + cairo_restore (cr); for (i = 0; i < self->n_shadows; i++) { @@ -3811,8 +3800,7 @@ gsk_blur_node_draw (GskRenderNode *node, cairo_save (cr); /* clip so the push_group() creates a smaller surface */ - cairo_rectangle (cr, node->bounds.origin.x, node->bounds.origin.y, - node->bounds.size.width, node->bounds.size.height); + gsk_cairo_rectangle (cr, &node->bounds); cairo_clip (cr); cairo_push_group (cr); diff --git a/gsk/gskroundedrect.c b/gsk/gskroundedrect.c index bde6078b4e..4d95d52666 100644 --- a/gsk/gskroundedrect.c +++ b/gsk/gskroundedrect.c @@ -324,25 +324,25 @@ ellipsis_contains_point (const graphene_size_t *ellipsis, + (point->y * point->y) / (ellipsis->height * ellipsis->height) <= 1; } -/** - * gsk_rounded_rect_contains_point: - * @self: a #GskRoundedRect - * @point: the point to check - * - * Checks if the given @point is inside the rounded rectangle. This function - * returns %FALSE if the point is in the rounded corner areas. - * - * Returns: %TRUE if the @point is inside the rounded rectangle - **/ -gboolean -gsk_rounded_rect_contains_point (const GskRoundedRect *self, - const graphene_point_t *point) +typedef enum +{ + INSIDE, + OUTSIDE_TOP_LEFT, + OUTSIDE_TOP_RIGHT, + OUTSIDE_BOTTOM_LEFT, + OUTSIDE_BOTTOM_RIGHT, + OUTSIDE +} Location; + +static Location +gsk_rounded_rect_locate_point (const GskRoundedRect *self, + const graphene_point_t *point) { if (point->x < self->bounds.origin.x || point->y < self->bounds.origin.y || - point->x >= self->bounds.origin.x + self->bounds.size.width || - point->y >= self->bounds.origin.y + self->bounds.size.height) - return FALSE; + point->x > self->bounds.origin.x + self->bounds.size.width || + point->y > self->bounds.origin.y + self->bounds.size.height) + return OUTSIDE; if (self->bounds.origin.x + self->corner[GSK_CORNER_TOP_LEFT].width > point->x && self->bounds.origin.y + self->corner[GSK_CORNER_TOP_LEFT].height > point->y && @@ -351,7 +351,7 @@ gsk_rounded_rect_contains_point (const GskRoundedRect *self, self->bounds.origin.x + self->corner[GSK_CORNER_TOP_LEFT].width - point->x, self->bounds.origin.y + self->corner[GSK_CORNER_TOP_LEFT].height- point->y ))) - return FALSE; + return OUTSIDE_TOP_LEFT; if (self->bounds.origin.x + self->bounds.size.width - self->corner[GSK_CORNER_TOP_RIGHT].width < point->x && self->bounds.origin.y + self->corner[GSK_CORNER_TOP_RIGHT].height > point->y && @@ -360,7 +360,7 @@ gsk_rounded_rect_contains_point (const GskRoundedRect *self, self->bounds.origin.x + self->bounds.size.width - self->corner[GSK_CORNER_TOP_RIGHT].width - point->x, self->bounds.origin.y + self->corner[GSK_CORNER_TOP_RIGHT].height- point->y ))) - return FALSE; + return OUTSIDE_TOP_RIGHT; if (self->bounds.origin.x + self->corner[GSK_CORNER_BOTTOM_LEFT].width > point->x && self->bounds.origin.y + self->bounds.size.height - self->corner[GSK_CORNER_BOTTOM_LEFT].height < point->y && @@ -369,7 +369,7 @@ gsk_rounded_rect_contains_point (const GskRoundedRect *self, self->bounds.origin.x + self->corner[GSK_CORNER_BOTTOM_LEFT].width - point->x, self->bounds.origin.y + self->bounds.size.height - self->corner[GSK_CORNER_BOTTOM_LEFT].height- point->y ))) - return FALSE; + return OUTSIDE_BOTTOM_LEFT; if (self->bounds.origin.x + self->bounds.size.width - self->corner[GSK_CORNER_BOTTOM_RIGHT].width < point->x && self->bounds.origin.y + self->bounds.size.height - self->corner[GSK_CORNER_BOTTOM_RIGHT].height < point->y && @@ -378,9 +378,26 @@ gsk_rounded_rect_contains_point (const GskRoundedRect *self, self->bounds.origin.x + self->bounds.size.width - self->corner[GSK_CORNER_BOTTOM_RIGHT].width - point->x, self->bounds.origin.y + self->bounds.size.height - self->corner[GSK_CORNER_BOTTOM_RIGHT].height- point->y ))) - return FALSE; + return OUTSIDE_BOTTOM_RIGHT; - return TRUE; + return INSIDE; +} + +/** + * gsk_rounded_rect_contains_point: + * @self: a #GskRoundedRect + * @point: the point to check + * + * Checks if the given @point is inside the rounded rectangle. This function + * returns %FALSE if the point is in the rounded corner areas. + * + * Returns: %TRUE if the @point is inside the rounded rectangle + **/ +gboolean +gsk_rounded_rect_contains_point (const GskRoundedRect *self, + const graphene_point_t *point) +{ + return gsk_rounded_rect_locate_point (self, point) == INSIDE; } /** @@ -400,8 +417,8 @@ gsk_rounded_rect_contains_rect (const GskRoundedRect *self, { if (rect->origin.x < self->bounds.origin.x || rect->origin.y < self->bounds.origin.y || - rect->origin.x + rect->size.width >= self->bounds.origin.x + self->bounds.size.width || - rect->origin.y + rect->size.height >= self->bounds.origin.y + self->bounds.size.height) + rect->origin.x + rect->size.width > self->bounds.origin.x + self->bounds.size.width || + rect->origin.y + rect->size.height > self->bounds.origin.y + self->bounds.size.height) return FALSE; if (!gsk_rounded_rect_contains_point (self, &rect->origin) || @@ -431,10 +448,12 @@ gsk_rounded_rect_intersects_rect (const GskRoundedRect *self, if (!graphene_rect_intersection (&self->bounds, rect, NULL)) return FALSE; - if (!gsk_rounded_rect_contains_point (self, &rect->origin) && - !gsk_rounded_rect_contains_point (self, &GRAPHENE_POINT_INIT (rect->origin.x + rect->size.width, rect->origin.y)) && - !gsk_rounded_rect_contains_point (self, &GRAPHENE_POINT_INIT (rect->origin.x, rect->origin.y + rect->size.height)) && - !gsk_rounded_rect_contains_point (self, &GRAPHENE_POINT_INIT (rect->origin.x + rect->size.width, rect->origin.y + rect->size.height))) + /* If the bounding boxes intersect but the rectangles don't, one of the rect's corners + * must be in the opposite corner's outside region */ + if (gsk_rounded_rect_locate_point (self, &rect->origin) == OUTSIDE_BOTTOM_RIGHT || + gsk_rounded_rect_locate_point (self, &GRAPHENE_POINT_INIT (rect->origin.x + rect->size.width, rect->origin.y)) == OUTSIDE_BOTTOM_LEFT || + gsk_rounded_rect_locate_point (self, &GRAPHENE_POINT_INIT (rect->origin.x, rect->origin.y + rect->size.height)) == OUTSIDE_TOP_RIGHT || + gsk_rounded_rect_locate_point (self, &GRAPHENE_POINT_INIT (rect->origin.x + rect->size.width, rect->origin.y + rect->size.height)) == OUTSIDE_TOP_LEFT) return FALSE; return TRUE; diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build index f303dd5f79..2b53f219e5 100644 --- a/testsuite/gsk/meson.build +++ b/testsuite/gsk/meson.build @@ -184,6 +184,7 @@ foreach test : node_parser_tests endforeach tests = [ + ['rounded-rect'], ['transform'], ] diff --git a/testsuite/gsk/reftest-compare.c b/testsuite/gsk/reftest-compare.c index 84c560cabc..21f5962d9c 100644 --- a/testsuite/gsk/reftest-compare.c +++ b/testsuite/gsk/reftest-compare.c @@ -27,20 +27,19 @@ get_surface_size (cairo_surface_t *surface, int *width, int *height) { - GdkRectangle area; cairo_t *cr; + double x1, x2, y1, y2; cr = cairo_create (surface); - if (!gdk_cairo_get_clip_rectangle (cr, &area)) - { - g_assert_not_reached (); - } + cairo_clip_extents (cr, &x1, &y1, &x2, &y2); + cairo_destroy (cr); - g_assert (area.x == 0 && area.y == 0); - g_assert (area.width > 0 && area.height > 0); + g_assert (x1 == 0 && y1 == 0); + g_assert (x2 > 0 && y2 > 0); + g_assert ((int) x2 == x2 && (int) y2 == y2); - *width = area.width; - *height = area.height; + *width = x2; + *height = y2; } static cairo_surface_t * @@ -61,7 +60,6 @@ coerce_surface_for_comparison (cairo_surface_t *surface, cairo_paint (cr); cairo_destroy (cr); - cairo_surface_destroy (surface); g_assert (cairo_surface_status (coerced) == CAIRO_STATUS_SUCCESS); @@ -152,21 +150,24 @@ reftest_compare_surfaces (cairo_surface_t *surface1, cairo_surface_t *surface2) { int w1, h1, w2, h2, w, h; - cairo_surface_t *diff; + cairo_surface_t *coerced1, *coerced2, *diff; get_surface_size (surface1, &w1, &h1); get_surface_size (surface2, &w2, &h2); w = MAX (w1, w2); h = MAX (h1, h2); - surface1 = coerce_surface_for_comparison (surface1, w, h); - surface2 = coerce_surface_for_comparison (surface2, w, h); + coerced1 = coerce_surface_for_comparison (surface1, w, h); + coerced2 = coerce_surface_for_comparison (surface2, w, h); - diff = buffer_diff_core (cairo_image_surface_get_data (surface1), - cairo_image_surface_get_stride (surface1), - cairo_image_surface_get_data (surface2), - cairo_image_surface_get_stride (surface2), + diff = buffer_diff_core (cairo_image_surface_get_data (coerced1), + cairo_image_surface_get_stride (coerced1), + cairo_image_surface_get_data (coerced2), + cairo_image_surface_get_stride (coerced2), w, h); + cairo_surface_destroy (coerced1); + cairo_surface_destroy (coerced2); + return diff; } diff --git a/testsuite/gsk/rounded-rect.c b/testsuite/gsk/rounded-rect.c new file mode 100644 index 0000000000..ea969323a6 --- /dev/null +++ b/testsuite/gsk/rounded-rect.c @@ -0,0 +1,100 @@ +/* + * Copyright © 2020 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#include "config.h" + +#include <gtk/gtk.h> + +static void +test_contains_rect (void) +{ + static double points[] = { -5, 0, 5, 10, 15, 85, 90, 95, 100, 105 }; +#define LAST (G_N_ELEMENTS(points) - 1) + GskRoundedRect rounded; + guint x1, x2, y1, y2; + + gsk_rounded_rect_init_from_rect (&rounded, &GRAPHENE_RECT_INIT (0, 0, 100, 100), 10); + + for (x1 = 0; x1 < G_N_ELEMENTS (points); x1++) + for (x2 = x1 + 1; x2 < G_N_ELEMENTS (points); x2++) + for (y1 = 0; y1 < G_N_ELEMENTS (points); y1++) + for (y2 = y1 + 1; y2 < G_N_ELEMENTS (points); y2++) + { + graphene_rect_t rect; + gboolean inside; + + /* check all points are in the bounding box */ + inside = x1 > 0 && y1 > 0 && x2 < LAST && y2 < LAST; + /* now check all the corners */ + inside &= x1 > 2 || y1 > 2 || (x1 == 2 && y1 == 2); + inside &= x2 < LAST - 2 || y1 > 2 || (x2 == LAST - 2 && y1 == 2); + inside &= x2 < LAST - 2 || y2 < LAST - 2 || (x2 == LAST - 2 && y2 == LAST - 2); + inside &= x1 > 2 || y2 < LAST - 2 || (x1 == 2 && y2 == LAST - 2); + + graphene_rect_init (&rect, points[x1], points[y1], points[x2] - points[x1], points[y2] - points[y1]); + if (inside) + g_assert_true (gsk_rounded_rect_contains_rect (&rounded, &rect)); + else + g_assert_false (gsk_rounded_rect_contains_rect (&rounded, &rect)); + } +#undef LAST +} + +static void +test_intersects_rect (void) +{ + static double points[] = { -1, 0, 1, 99, 100, 101 }; +#define ALL_THE_POINTS (G_N_ELEMENTS(points)) +#define HALF_THE_POINTS (ALL_THE_POINTS / 2) + GskRoundedRect rounded; + guint x1, x2, y1, y2; + + gsk_rounded_rect_init_from_rect (&rounded, &GRAPHENE_RECT_INIT (0, 0, 100, 100), 10); + + for (x1 = 0; x1 < ALL_THE_POINTS; x1++) + for (x2 = x1 + 1; x2 < ALL_THE_POINTS; x2++) + for (y1 = 0; y1 < ALL_THE_POINTS; y1++) + for (y2 = y1 + 1; y2 < ALL_THE_POINTS; y2++) + { + graphene_rect_t rect; + gboolean should_contain_x, should_contain_y; + + graphene_rect_init (&rect, points[x1], points[y1], points[x2] - points[x1], points[y2] - points[y1]); + should_contain_x = x1 < HALF_THE_POINTS && x2 >= HALF_THE_POINTS && y2 > 1 && y1 < ALL_THE_POINTS - 2; + should_contain_y = y1 < HALF_THE_POINTS && y2 >= HALF_THE_POINTS && x2 > 1 && x1 < ALL_THE_POINTS - 2; + if (should_contain_x || should_contain_y) + g_assert_true (gsk_rounded_rect_intersects_rect (&rounded, &rect)); + else + g_assert_false (gsk_rounded_rect_intersects_rect (&rounded, &rect)); + } +#undef ALL_THE_POINTS +#undef HALF_THE_POINTS +} + +int +main (int argc, + char *argv[]) +{ + gtk_test_init (&argc, &argv, NULL); + + g_test_add_func ("/rounded-rect/contains-rect", test_contains_rect); + g_test_add_func ("/rounded-rect/intersects-rect", test_intersects_rect); + + return g_test_run (); +} diff --git a/testsuite/reftests/reftest-compare.c b/testsuite/reftests/reftest-compare.c index 84c560cabc..dc422089cd 100644 --- a/testsuite/reftests/reftest-compare.c +++ b/testsuite/reftests/reftest-compare.c @@ -27,22 +27,22 @@ get_surface_size (cairo_surface_t *surface, int *width, int *height) { - GdkRectangle area; cairo_t *cr; + double x1, x2, y1, y2; cr = cairo_create (surface); - if (!gdk_cairo_get_clip_rectangle (cr, &area)) - { - g_assert_not_reached (); - } + cairo_clip_extents (cr, &x1, &y1, &x2, &y2); + cairo_destroy (cr); - g_assert (area.x == 0 && area.y == 0); - g_assert (area.width > 0 && area.height > 0); + g_assert (x1 == 0 && y1 == 0); + g_assert (x2 > 0 && y2 > 0); + g_assert ((int) x2 == x2 && (int) y2 == y2); - *width = area.width; - *height = area.height; + *width = x2; + *height = y2; } + static cairo_surface_t * coerce_surface_for_comparison (cairo_surface_t *surface, int width, @@ -61,7 +61,6 @@ coerce_surface_for_comparison (cairo_surface_t *surface, cairo_paint (cr); cairo_destroy (cr); - cairo_surface_destroy (surface); g_assert (cairo_surface_status (coerced) == CAIRO_STATUS_SUCCESS); @@ -152,21 +151,24 @@ reftest_compare_surfaces (cairo_surface_t *surface1, cairo_surface_t *surface2) { int w1, h1, w2, h2, w, h; - cairo_surface_t *diff; + cairo_surface_t *coerced1, *coerced2, *diff; get_surface_size (surface1, &w1, &h1); get_surface_size (surface2, &w2, &h2); w = MAX (w1, w2); h = MAX (h1, h2); - surface1 = coerce_surface_for_comparison (surface1, w, h); - surface2 = coerce_surface_for_comparison (surface2, w, h); + coerced1 = coerce_surface_for_comparison (surface1, w, h); + coerced2 = coerce_surface_for_comparison (surface2, w, h); - diff = buffer_diff_core (cairo_image_surface_get_data (surface1), - cairo_image_surface_get_stride (surface1), - cairo_image_surface_get_data (surface2), - cairo_image_surface_get_stride (surface2), + diff = buffer_diff_core (cairo_image_surface_get_data (coerced1), + cairo_image_surface_get_stride (coerced1), + cairo_image_surface_get_data (coerced2), + cairo_image_surface_get_stride (coerced2), w, h); + cairo_surface_destroy (coerced1); + cairo_surface_destroy (coerced2); + return diff; } |