summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2020-02-13 13:43:59 +0000
committerMatthias Clasen <mclasen@redhat.com>2020-02-13 13:43:59 +0000
commit313c399122c61900e003fa24c026ff9055ae1aaa (patch)
tree181c4587a0a2b205e1433bc143ab6564bf160200
parentc313a71c3a0757d07bcf26a03236ea8cad624880 (diff)
parent052d0f6e6004b7c791cfbb891c70ab0bb316c228 (diff)
downloadgtk+-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.txt1
-rw-r--r--gdk/gdkcairo.c39
-rw-r--r--gdk/gdkcairo.h4
-rw-r--r--gsk/gskcairoblur.c29
-rw-r--r--gsk/gskrendernodeimpl.c94
-rw-r--r--gsk/gskroundedrect.c73
-rw-r--r--testsuite/gsk/meson.build1
-rw-r--r--testsuite/gsk/reftest-compare.c35
-rw-r--r--testsuite/gsk/rounded-rect.c100
-rw-r--r--testsuite/reftests/reftest-compare.c36
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;
}