forked from AuroraMiddleware/gtk
gl renderer: Improve clipping code
don't render a clip to a texture if the new clip does not intersect with any of the corners of the currently rounded clip. Fixes #2770
This commit is contained in:
parent
094788f1a3
commit
d5bf3c2cd1
@ -4,6 +4,36 @@
|
||||
#define SANITY_CHECKS 0
|
||||
|
||||
|
||||
|
||||
#define rounded_rect_top_left(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x, \
|
||||
r->bounds.origin.y, \
|
||||
r->corner[0].width, r->corner[0].height))
|
||||
|
||||
#define rounded_rect_top_right(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x + r->bounds.size.width - r->corner[1].width, \
|
||||
r->bounds.origin.y, \
|
||||
r->corner[1].width, r->corner[1].height))
|
||||
|
||||
#define rounded_rect_bottom_right(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x + r->bounds.size.width - r->corner[2].width, \
|
||||
r->bounds.origin.y + r->bounds.size.height - r->corner[2].height, \
|
||||
r->corner[2].width, r->corner[2].height))
|
||||
|
||||
#define rounded_rect_bottom_left(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x, \
|
||||
r->bounds.origin.y + r->bounds.size.height - r->corner[2].height, \
|
||||
r->corner[3].width, r->corner[3].height))
|
||||
|
||||
|
||||
#define rounded_rect_corner0(r) rounded_rect_top_left(r)
|
||||
#define rounded_rect_corner1(r) rounded_rect_top_right(r)
|
||||
#define rounded_rect_corner2(r) rounded_rect_bottom_right(r)
|
||||
#define rounded_rect_corner3(r) rounded_rect_bottom_left(r)
|
||||
|
||||
#define rounded_rect_corner(r, i) (rounded_rect_corner ##i(r))
|
||||
#define graphene_size_non_zero(s) (s->width > 0 && s->height > 0)
|
||||
#define rounded_rect_has_corner(r, i) (r->corner[i].width > 0 && r->corner[i].height > 0)
|
||||
|
||||
#define rect_contains_point(r, _x, _y) (_x >= (r)->origin.x && _x <= (r)->origin.x + (r)->size.width && \
|
||||
_y >= (r)->origin.y && _y <= (r)->origin.y + (r)->size.height)
|
||||
|
||||
enum {
|
||||
NINE_SLICE_TOP_LEFT = 0,
|
||||
NINE_SLICE_TOP_CENTER = 1,
|
||||
|
@ -1159,59 +1159,112 @@ render_clipped_child (GskGLRenderer *self,
|
||||
GskRenderNode *child)
|
||||
{
|
||||
graphene_rect_t transformed_clip;
|
||||
graphene_rect_t intersection;
|
||||
GskRoundedRect child_clip;
|
||||
|
||||
ops_transform_bounds_modelview (builder, clip, &transformed_clip);
|
||||
|
||||
if (builder->clip_is_rectilinear)
|
||||
goto trivial;
|
||||
|
||||
{
|
||||
const GskRoundedRect *cur_clip = builder->current_clip;
|
||||
int n_corners = 0;
|
||||
bool corners[4];
|
||||
|
||||
/* Intersects with top left corner? */
|
||||
n_corners += corners[0] = rounded_rect_has_corner (cur_clip, 0) &&
|
||||
graphene_rect_intersection (&transformed_clip,
|
||||
&rounded_rect_corner (cur_clip, 0), NULL);
|
||||
/* top right? */
|
||||
n_corners += corners[1] = rounded_rect_has_corner (cur_clip, 1) &&
|
||||
graphene_rect_intersection (&transformed_clip,
|
||||
&rounded_rect_corner (cur_clip, 1), NULL);
|
||||
/* bottom right? */
|
||||
n_corners += corners[2] = rounded_rect_has_corner (cur_clip, 2) &&
|
||||
graphene_rect_intersection (&transformed_clip,
|
||||
&rounded_rect_corner (cur_clip, 2), NULL);
|
||||
/* bottom left */
|
||||
n_corners += corners[3] = rounded_rect_has_corner (cur_clip, 3) &&
|
||||
graphene_rect_intersection (&transformed_clip,
|
||||
&rounded_rect_corner (cur_clip, 3), NULL);
|
||||
|
||||
if (n_corners == 0)
|
||||
goto trivial;
|
||||
|
||||
if (corners[0] && !graphene_rect_contains_rect (&transformed_clip, &rounded_rect_corner (cur_clip, 0)))
|
||||
goto rtt;
|
||||
if (corners[1] && !graphene_rect_contains_rect (&transformed_clip, &rounded_rect_corner (cur_clip, 1)))
|
||||
goto rtt;
|
||||
if (corners[2] && !graphene_rect_contains_rect (&transformed_clip, &rounded_rect_corner (cur_clip, 2)))
|
||||
goto rtt;
|
||||
if (corners[3] && !graphene_rect_contains_rect (&transformed_clip, &rounded_rect_corner (cur_clip, 3)))
|
||||
goto rtt;
|
||||
|
||||
/* We do intersect with at least one of the corners, but in such a way that the
|
||||
* intersection between the two clips can still be represented by a single rounded
|
||||
* rect in a trivial way. do that. */
|
||||
{
|
||||
/* Simple case: */
|
||||
graphene_rect_intersection (&transformed_clip,
|
||||
&builder->current_clip->bounds,
|
||||
&intersection);
|
||||
GskRoundedRect real_intersection;
|
||||
|
||||
gsk_rounded_rect_init_from_rect (&child_clip, &intersection, 0.0f);
|
||||
graphene_rect_intersection (&transformed_clip, &cur_clip->bounds, &real_intersection.bounds);
|
||||
|
||||
ops_push_clip (builder, &child_clip);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (corners[i])
|
||||
real_intersection.corner[i] = cur_clip->corner[i];
|
||||
else
|
||||
real_intersection.corner[i].width = real_intersection.corner[i].height = 0;
|
||||
}
|
||||
|
||||
/* Draw with that new clip */
|
||||
ops_push_clip (builder, &real_intersection);
|
||||
gsk_gl_renderer_add_render_ops (self, child, builder);
|
||||
ops_pop_clip (builder);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Intersection might end up having rounded corners again */
|
||||
if (!rounded_inner_rect_contains_rect (builder->current_clip,
|
||||
&transformed_clip))
|
||||
{
|
||||
/* well fuck */
|
||||
const float scale = ops_get_scale (builder);
|
||||
gboolean is_offscreen;
|
||||
TextureRegion region;
|
||||
GskRoundedRect scaled_clip;
|
||||
rtt:
|
||||
{
|
||||
/* well fuck */
|
||||
const float scale = ops_get_scale (builder);
|
||||
gboolean is_offscreen;
|
||||
TextureRegion region;
|
||||
GskRoundedRect scaled_clip;
|
||||
|
||||
memset (&scaled_clip, 0, sizeof (GskRoundedRect));
|
||||
memset (&scaled_clip, 0, sizeof (GskRoundedRect));
|
||||
|
||||
scaled_clip.bounds.origin.x = clip->origin.x * scale;
|
||||
scaled_clip.bounds.origin.y = clip->origin.y * scale;
|
||||
scaled_clip.bounds.size.width = clip->size.width * scale;
|
||||
scaled_clip.bounds.size.height = clip->size.height * scale;
|
||||
scaled_clip.bounds.origin.x = clip->origin.x * scale;
|
||||
scaled_clip.bounds.origin.y = clip->origin.y * scale;
|
||||
scaled_clip.bounds.size.width = clip->size.width * scale;
|
||||
scaled_clip.bounds.size.height = clip->size.height * scale;
|
||||
|
||||
ops_push_clip (builder, &scaled_clip);
|
||||
if (!add_offscreen_ops (self, builder, &child->bounds,
|
||||
child,
|
||||
®ion, &is_offscreen,
|
||||
RESET_OPACITY | FORCE_OFFSCREEN))
|
||||
g_assert_not_reached ();
|
||||
ops_pop_clip (builder);
|
||||
ops_push_clip (builder, &scaled_clip);
|
||||
if (!add_offscreen_ops (self, builder, &child->bounds,
|
||||
child,
|
||||
®ion, &is_offscreen,
|
||||
RESET_OPACITY | FORCE_OFFSCREEN))
|
||||
g_assert_not_reached ();
|
||||
ops_pop_clip (builder);
|
||||
|
||||
ops_set_program (builder, &self->programs->blit_program);
|
||||
ops_set_texture (builder, region.texture_id);
|
||||
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), child, builder);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ops_set_program (builder, &self->programs->blit_program);
|
||||
ops_set_texture (builder, region.texture_id);
|
||||
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), child, builder);
|
||||
return;
|
||||
}
|
||||
trivial:
|
||||
memset (&child_clip, 0, sizeof (GskRoundedRect));
|
||||
graphene_rect_intersection (&transformed_clip,
|
||||
&builder->current_clip->bounds,
|
||||
&child_clip.bounds);
|
||||
|
||||
ops_push_clip (builder, &child_clip);
|
||||
gsk_gl_renderer_add_render_ops (self, child, builder);
|
||||
ops_pop_clip (builder);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
11
testsuite/gsk/compare/clip-in-rounded-clip1.node
Normal file
11
testsuite/gsk/compare/clip-in-rounded-clip1.node
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
rounded-clip {
|
||||
clip: 0 0 200 100 / 8 8 20 12;
|
||||
child: clip {
|
||||
clip: 40 30 20 50;
|
||||
child: color {
|
||||
bounds: 0 0 200 500;
|
||||
color: teal;
|
||||
}
|
||||
}
|
||||
}
|
BIN
testsuite/gsk/compare/clip-in-rounded-clip1.png
Normal file
BIN
testsuite/gsk/compare/clip-in-rounded-clip1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 115 B |
36
testsuite/gsk/compare/clip-in-rounded-clip2.node
Normal file
36
testsuite/gsk/compare/clip-in-rounded-clip2.node
Normal file
@ -0,0 +1,36 @@
|
||||
rounded-clip {
|
||||
clip: 0 0 200 100 / 0 0 40 0;
|
||||
child: clip {
|
||||
clip: 40 0 200 300;
|
||||
child: color {
|
||||
bounds: 0 0 300 500;
|
||||
color: teal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
color {
|
||||
bounds: 160 95 20 5;
|
||||
color: black;
|
||||
}
|
||||
|
||||
color {
|
||||
bounds: 178 90 9 5;
|
||||
color: black;
|
||||
}
|
||||
|
||||
color {
|
||||
bounds: 183 85 9 5;
|
||||
color: black;
|
||||
}
|
||||
|
||||
color {
|
||||
bounds: 188 76 9 9;
|
||||
color: black;
|
||||
}
|
||||
|
||||
|
||||
color {
|
||||
bounds: 195 50 5 30;
|
||||
color: black;
|
||||
}
|
BIN
testsuite/gsk/compare/clip-in-rounded-clip2.png
Normal file
BIN
testsuite/gsk/compare/clip-in-rounded-clip2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 407 B |
40
testsuite/gsk/compare/clip-in-rounded-clip3.node
Normal file
40
testsuite/gsk/compare/clip-in-rounded-clip3.node
Normal file
@ -0,0 +1,40 @@
|
||||
/* Force offscreen drawing by creating a clip that
|
||||
cannot be expressed using a single rounded rect */
|
||||
rounded-clip {
|
||||
clip: 0 0 100 100 / 0 50 50 50;
|
||||
child: clip {
|
||||
clip: 0 0 80 50;
|
||||
child: color {
|
||||
bounds: 0 0 300 500;
|
||||
color: teal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
color {
|
||||
bounds: 75 6 5 5;
|
||||
color: black;
|
||||
}
|
||||
|
||||
|
||||
color {
|
||||
bounds: 70 4 5 5;
|
||||
color: black;
|
||||
}
|
||||
|
||||
color {
|
||||
bounds: 65 2 5 5;
|
||||
color: black;
|
||||
}
|
||||
|
||||
color {
|
||||
bounds: 55 0 10 5;
|
||||
color: black;
|
||||
}
|
||||
|
||||
|
||||
color {
|
||||
bounds: 40 0 15 2;
|
||||
color: black;
|
||||
}
|
BIN
testsuite/gsk/compare/clip-in-rounded-clip3.png
Normal file
BIN
testsuite/gsk/compare/clip-in-rounded-clip3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 259 B |
@ -69,6 +69,9 @@ compare_render_tests = [
|
||||
'transform-in-transform',
|
||||
'transform-in-transform-in-transform',
|
||||
'nested-rounded-clips',
|
||||
'clip-in-rounded-clip1',
|
||||
'clip-in-rounded-clip2',
|
||||
'clip-in-rounded-clip3',
|
||||
]
|
||||
|
||||
# these are too sensitive to differences in the renderers
|
||||
|
Loading…
Reference in New Issue
Block a user