diff options
author | Timm Bäder <mail@baedert.org> | 2019-02-24 09:14:23 +0100 |
---|---|---|
committer | Timm Bäder <mail@baedert.org> | 2019-02-25 08:46:27 +0100 |
commit | 47fb1ec4c490fa22c0b01a749eefa016f609c19d (patch) | |
tree | 639294814357a99e5de875ee5c28ccc3dc3ad41a | |
parent | f0624266dc49c502dc664c8c65e642314664afb3 (diff) | |
download | gtk+-47fb1ec4c490fa22c0b01a749eefa016f609c19d.tar.gz |
gl renderer: Partially implement rounded rect intersection
Some rounded rect intersections can actually be done and even expressed
as a single rounded rectangle.
-rw-r--r-- | gsk/gl/gskglrenderer.c | 121 |
1 files changed, 108 insertions, 13 deletions
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 4033e42052..e0d2157d13 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -966,30 +966,125 @@ render_clip_node (GskGLRenderer *self, ops_pop_clip (builder); } +static inline void +get_inner_rect (const GskRoundedRect *rect, + graphene_rect_t *out) +{ + const float left = MAX (rect->corner[GSK_CORNER_TOP_LEFT].width, + rect->corner[GSK_CORNER_BOTTOM_LEFT].width); + const float top = MAX (rect->corner[GSK_CORNER_TOP_LEFT].height, + rect->corner[GSK_CORNER_TOP_RIGHT].height); + + out->origin.x = rect->bounds.origin.x + left; + out->origin.y = rect->bounds.origin.y + top; + + out->size.width = rect->bounds.size.width - left - + MAX (rect->corner[GSK_CORNER_TOP_RIGHT].width, + rect->corner[GSK_CORNER_BOTTOM_RIGHT].width); + + out->size.height = rect->bounds.size.height - top - + MAX (rect->corner[GSK_CORNER_BOTTOM_LEFT].height, + rect->corner[GSK_CORNER_BOTTOM_RIGHT].height); +} + +/* Best effort intersection of two rounded rectangles */ static gboolean -gsk_rounded_rect_intersection (const GskRoundedRect *self, - const GskRoundedRect *other, +gsk_rounded_rect_intersection (const GskRoundedRect *outer, + const GskRoundedRect *inner, GskRoundedRect *out_intersection) { - const graphene_rect_t *self_bounds = &self->bounds; - const graphene_rect_t *other_bounds = &other->bounds; + const graphene_rect_t *outer_bounds = &outer->bounds; + const graphene_rect_t *inner_bounds = &inner->bounds; + graphene_rect_t outer_inner; + graphene_rect_t inner_inner; + gboolean contained_x; + gboolean contained_y; - if (graphene_rect_contains_rect (self_bounds, other_bounds)) + if (graphene_rect_contains_rect (outer_bounds, inner_bounds)) { - *out_intersection = *other; + *out_intersection = *inner; return TRUE; } - /* TODO: There are a few cases here that we can express using a single - * rounded rectangle, which are even interesting in every day usage. - * For example, a partially scrolled-away rounded rectangle - * might just work. - */ + get_inner_rect (outer, &outer_inner); + get_inner_rect (inner, &inner_inner); - return FALSE; -} + contained_x = outer_inner.origin.x <= inner_inner.origin.x && + (outer_inner.origin.x + outer_inner.size.width) > (inner_inner.origin.x + + inner_inner.size.width); + contained_y = outer_inner.origin.y <= inner_inner.origin.y && + (outer_inner.origin.y + outer_inner.size.height) > (inner_inner.origin.y + + inner_inner.size.height); + if (contained_x && !contained_y) + { + /* The intersection is @inner, but cut-off and with the cut-off corners + * set to size 0 */ + *out_intersection = *inner; + + if (inner_bounds->origin.y < outer_bounds->origin.y) + { + /* Set top corners to 0 */ + graphene_rect_intersection (outer_bounds, inner_bounds, &out_intersection->bounds); + graphene_size_init (&out_intersection->corner[GSK_CORNER_TOP_LEFT], 0, 0); + graphene_size_init (&out_intersection->corner[GSK_CORNER_TOP_RIGHT], 0, 0); + graphene_size_init_from_size (&out_intersection->corner[GSK_CORNER_BOTTOM_LEFT], + &inner->corner[GSK_CORNER_BOTTOM_LEFT]); + graphene_size_init_from_size (&out_intersection->corner[GSK_CORNER_BOTTOM_RIGHT], + &inner->corner[GSK_CORNER_BOTTOM_RIGHT]); + return TRUE; + } + else if (inner_bounds->origin.y + inner_bounds->size.height > + outer_bounds->origin.y + outer_bounds->size.height) + { + /* Set bottom corners to 0 */ + graphene_rect_intersection (outer_bounds, inner_bounds, &out_intersection->bounds); + graphene_size_init (&out_intersection->corner[GSK_CORNER_BOTTOM_LEFT], 0, 0); + graphene_size_init (&out_intersection->corner[GSK_CORNER_BOTTOM_RIGHT], 0, 0); + graphene_size_init_from_size (&out_intersection->corner[GSK_CORNER_TOP_LEFT], + &inner->corner[GSK_CORNER_TOP_LEFT]); + graphene_size_init_from_size (&out_intersection->corner[GSK_CORNER_TOP_RIGHT], + &inner->corner[GSK_CORNER_TOP_RIGHT]); + return TRUE; + } + } + else if (!contained_x && contained_y) + { + /* The intersection is @inner, but cut-off and with the cut-off corners + * set to size 0 */ + *out_intersection = *inner; + + if (inner_bounds->origin.x < outer_bounds->origin.x) + { + /* Set left corners to 0 */ + graphene_rect_intersection (outer_bounds, inner_bounds, &out_intersection->bounds); + graphene_size_init (&out_intersection->corner[GSK_CORNER_TOP_LEFT], 0, 0); + graphene_size_init (&out_intersection->corner[GSK_CORNER_BOTTOM_LEFT], 0, 0); + graphene_size_init_from_size (&out_intersection->corner[GSK_CORNER_TOP_RIGHT], + &inner->corner[GSK_CORNER_TOP_RIGHT]); + graphene_size_init_from_size (&out_intersection->corner[GSK_CORNER_BOTTOM_RIGHT], + &inner->corner[GSK_CORNER_BOTTOM_RIGHT]); + return TRUE; + } + else if (inner_bounds->origin.x + inner_bounds->size.width > + outer_bounds->origin.x + outer_bounds->size.width) + { + /* Set right corners to 0 */ + graphene_rect_intersection (outer_bounds, inner_bounds, &out_intersection->bounds); + graphene_size_init (&out_intersection->corner[GSK_CORNER_TOP_RIGHT], 0, 0); + graphene_size_init (&out_intersection->corner[GSK_CORNER_BOTTOM_RIGHT], 0, 0); + graphene_size_init_from_size (&out_intersection->corner[GSK_CORNER_TOP_LEFT], + &inner->corner[GSK_CORNER_TOP_LEFT]); + graphene_size_init_from_size (&out_intersection->corner[GSK_CORNER_BOTTOM_LEFT], + &inner->corner[GSK_CORNER_BOTTOM_LEFT]); + return TRUE; + } + } + + /* Actually not possible or just too much work. */ + return FALSE; +} static inline void render_rounded_clip_node (GskGLRenderer *self, |