[gtk/wip/baedert/for-master: 22/23] gl renderer: Fix nested rounded clip rendering



commit b9ed957af38b19538d483c90af21676b0f6c329c
Author: Timm Bäder <mail baedert org>
Date:   Tue May 12 20:11:13 2020 +0200

    gl renderer: Fix nested rounded clip rendering
    
    If the inner clip intersects with the corners of the outer clip, we
    potentially need a texture. We should add more fine-grained checks for
    this in the future though.
    
    Test case included.

 gsk/gl/gskglrenderer.c                          |  61 +++++++++++++++++++++++-
 testsuite/gsk/compare/nested-rounded-clips.node |  35 ++++++++++++++
 testsuite/gsk/compare/nested-rounded-clips.png  | Bin 0 -> 469 bytes
 testsuite/gsk/meson.build                       |   1 +
 4 files changed, 95 insertions(+), 2 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index ac8680ba0f..f45c4d5709 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -1129,6 +1129,35 @@ render_linear_gradient_node (GskGLRenderer   *self,
   load_vertex_data (ops_draw (builder, NULL), node, builder);
 }
 
+static inline gboolean
+rounded_inner_rect_contains_rect (const GskRoundedRect  *rounded,
+                                  const graphene_rect_t *rect)
+{
+  const graphene_rect_t *rounded_bounds = &rounded->bounds;
+  graphene_rect_t inner;
+  float offset_x, offset_y;
+
+  /* TODO: This is pretty conservative and we could to further, more
+   *       fine-grained checks to avoid offscreen drawing. */
+
+  offset_x = MAX (rounded->corner[GSK_CORNER_TOP_LEFT].width,
+                  rounded->corner[GSK_CORNER_BOTTOM_LEFT].width);
+  offset_y = MAX (rounded->corner[GSK_CORNER_TOP_LEFT].height,
+                  rounded->corner[GSK_CORNER_TOP_RIGHT].height);
+
+
+  inner.origin.x = rounded_bounds->origin.x + offset_x;
+  inner.origin.y = rounded_bounds->origin.y + offset_y;
+  inner.size.width = rounded_bounds->size.width - offset_x -
+                     MAX (rounded->corner[GSK_CORNER_TOP_RIGHT].width,
+                          rounded->corner[GSK_CORNER_BOTTOM_RIGHT].width);
+  inner.size.height = rounded_bounds->size.height - offset_y -
+                      MAX (rounded->corner[GSK_CORNER_BOTTOM_LEFT].height,
+                           rounded->corner[GSK_CORNER_BOTTOM_RIGHT].height);
+
+  return graphene_rect_contains_rect (&inner, rect);
+}
+
 static inline void
 render_clipped_child (GskGLRenderer         *self,
                       RenderOpBuilder       *builder,
@@ -1141,6 +1170,34 @@ render_clipped_child (GskGLRenderer         *self,
 
   ops_transform_bounds_modelview (builder, clip, &transformed_clip);
 
+  /* Intersection might end up having rounded corners again */
+  if (!gsk_rounded_rect_is_rectilinear (builder->current_clip))
+    {
+      if (!rounded_inner_rect_contains_rect (builder->current_clip,
+                                             &transformed_clip))
+        {
+          /* well fuck */
+          gboolean is_offscreen;
+          TextureRegion region;
+
+          ops_push_clip (builder, &child_clip);
+          if (!add_offscreen_ops (self, builder, &child->bounds,
+                                  child,
+                                  &region, &is_offscreen,
+                                  RESET_OPACITY | RESET_CLIP))
+            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;
+        }
+    }
+
+  /* Simple case: */
   graphene_rect_intersection (&transformed_clip,
                               &builder->current_clip->bounds,
                               &intersection);
@@ -1182,8 +1239,8 @@ render_rounded_clip_node (GskGLRenderer       *self,
 
   if (!ops_has_clip (builder))
     need_offscreen = FALSE;
-  else if (graphene_rect_contains_rect (&builder->current_clip->bounds,
-                                        &transformed_clip.bounds))
+  else if (rounded_inner_rect_contains_rect (builder->current_clip,
+                                             &transformed_clip.bounds))
     need_offscreen = FALSE;
   else
     need_offscreen = TRUE;
diff --git a/testsuite/gsk/compare/nested-rounded-clips.node b/testsuite/gsk/compare/nested-rounded-clips.node
new file mode 100644
index 0000000000..98646b28f7
--- /dev/null
+++ b/testsuite/gsk/compare/nested-rounded-clips.node
@@ -0,0 +1,35 @@
+  transform  {
+    child: rounded-clip {
+      child: rounded-clip {
+        clip: 10 10 30 30 / 5;
+        child: color {
+          color: teal;
+          bounds: 12 12 26 26;
+        }
+      }
+      clip: 10 10 30 30 / 25 0 0 0;
+    }
+
+    transform: scale(5);
+  }
+
+color {
+  color: black;
+  bounds: 55 100 40 40;
+}
+
+color {
+  color: black;
+  bounds: 70 80 20 20;
+}
+
+color {
+  color: black;
+  bounds: 90 70 40 40;
+}
+
+color {
+  color: black;
+  bounds: 105 55 30 20;
+}
+
diff --git a/testsuite/gsk/compare/nested-rounded-clips.png b/testsuite/gsk/compare/nested-rounded-clips.png
new file mode 100644
index 0000000000..8b954e1467
Binary files /dev/null and b/testsuite/gsk/compare/nested-rounded-clips.png differ
diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build
index e9fdc661b7..225ce98261 100644
--- a/testsuite/gsk/meson.build
+++ b/testsuite/gsk/meson.build
@@ -66,6 +66,7 @@ compare_render_tests = [
   'blend-invisible-child',
   'transform-in-transform',
   'transform-in-transform-in-transform',
+  'nested-rounded-clips',
 ]
 
 # these are too sensitive to differences in the renderers


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]