[gtk/wip/chergert/macos-fixes] macos: precalculate clip regions as CGRect



commit 8ea0a4fc5096907df8dc3be9a9216891a5cda6a4
Author: Christian Hergert <christian hergert me>
Date:   Fri Feb 4 09:31:37 2022 -0800

    macos: precalculate clip regions as CGRect
    
    We can make our drawRect do less work if we precalculate the clip
    and damage regions upfront by intersecting them with the bounds.

 gdk/macos/GdkMacosCairoSubview.c | 87 ++++++++++++++++++++++------------------
 gdk/macos/GdkMacosCairoSubview.h |  9 +++--
 2 files changed, 53 insertions(+), 43 deletions(-)
---
diff --git a/gdk/macos/GdkMacosCairoSubview.c b/gdk/macos/GdkMacosCairoSubview.c
index af22e89887..fddb0ed0c0 100644
--- a/gdk/macos/GdkMacosCairoSubview.c
+++ b/gdk/macos/GdkMacosCairoSubview.c
@@ -32,7 +32,8 @@
 
 -(void)dealloc
 {
-  g_clear_pointer (&self->clip, cairo_region_destroy);
+  g_clear_pointer (&self->clip, g_array_unref);
+  g_clear_pointer (&self->damage, g_array_unref);
   g_clear_pointer (&self->image, CGImageRelease);
   [super dealloc];
 }
@@ -75,21 +76,18 @@
    * to the self->clip region. This is usually just on the views
    * for the shadow areas.
    */
+  CGContextAddRect (cgContext, [self bounds]);
   if (self->clip != NULL)
     {
-      guint n_rects = cairo_region_num_rectangles (self->clip);
-
-      for (guint i = 0; i < n_rects; i++)
-        {
-          cairo_rectangle_int_t area;
-
-          cairo_region_get_rectangle (self->clip, i, &area);
-          CGContextAddRect (cgContext,
-                            CGRectMake (area.x, area.y, area.width, area.height));
-        }
-
-      CGContextClip (cgContext);
+      for (guint i = 0; i < self->clip->len; i++)
+        CGContextAddRect (cgContext, g_array_index (self->clip, CGRect, i));
     }
+  if (self->damage != NULL)
+    {
+      for (guint i = 0; i < self->damage->len; i++)
+        CGContextAddRect (cgContext, g_array_index (self->damage, CGRect, i));
+    }
+  CGContextClip (cgContext);
 
   /* Scale/Translate so that the CGImageRef draws in proper format/placement */
   scale = CGSizeMake (1.0, 1.0);
@@ -115,28 +113,7 @@
         image = CGImageRetain (theImage);
     }
 
-  if (region != NULL)
-    {
-      NSView *root_view = [[self window] contentView];
-      NSRect abs_bounds = [self convertRect:[self bounds] toView:root_view];
-      guint n_rects = cairo_region_num_rectangles (region);
-
-      for (guint i = 0; i < n_rects; i++)
-        {
-          cairo_rectangle_int_t rect;
-          NSRect nsrect;
-
-          cairo_region_get_rectangle (region, i, &rect);
-          nsrect = NSMakeRect (rect.x, rect.y, rect.width, rect.height);
-
-          if (NSIntersectsRect (abs_bounds, nsrect))
-            {
-              nsrect.origin.x -= abs_bounds.origin.x;
-              nsrect.origin.y -= abs_bounds.origin.y;
-              [self setNeedsDisplayInRect:nsrect];
-            }
-        }
-    }
+  [self convertRegion:region toArray:&self->damage andDisplay:YES];
 
   for (id view in [self subviews])
     [(GdkMacosCairoSubview *)view setImage:theImage withDamage:region];
@@ -147,14 +124,44 @@
   self->_isOpaque = opaque;
 }
 
--(void)setClip:(cairo_region_t*)region
+-(void)convertRegion:(const cairo_region_t *)region
+             toArray:(GArray **)array
+          andDisplay:(BOOL)display
 {
-  if (region != self->clip)
+  NSView *root_view;
+  CGRect abs_bounds;
+  guint n_rects;
+
+  if (*array == NULL)
+    *array = g_array_new (FALSE, FALSE, sizeof (CGRect));
+  else
+    g_array_set_size (*array, 0);
+
+  root_view = [[self window] contentView];
+  abs_bounds = [self convertRect:[self bounds] toView:root_view];
+  n_rects = cairo_region_num_rectangles (region);
+
+  for (guint i = 0; i < n_rects; i++)
     {
-      g_clear_pointer (&self->clip, cairo_region_destroy);
-      if (region != NULL)
-        self->clip = cairo_region_reference (region);
+      cairo_rectangle_int_t rect;
+      CGRect nsrect;
+
+      cairo_region_get_rectangle (region, i, &rect);
+      nsrect = CGRectIntersection (abs_bounds, CGRectMake (rect.x, rect.y, rect.width, rect.height));
+
+      if (!CGRectIsNull (nsrect))
+        g_array_append_val (*array, nsrect);
+
+      if (display)
+        [self setNeedsDisplayInRect:CGRectMake (rect.x - abs_bounds.origin.x,
+                                                rect.y - abs_bounds.origin.y,
+                                                rect.width, rect.height)];
     }
 }
 
+-(void)setClip:(cairo_region_t*)region
+{
+  [self convertRegion:region toArray:&self->clip andDisplay:NO];
+}
+
 @end
diff --git a/gdk/macos/GdkMacosCairoSubview.h b/gdk/macos/GdkMacosCairoSubview.h
index e6fda6ac43..e03b47727d 100644
--- a/gdk/macos/GdkMacosCairoSubview.h
+++ b/gdk/macos/GdkMacosCairoSubview.h
@@ -19,14 +19,17 @@
  */
 
 #include <AppKit/AppKit.h>
+#include <cairo.h>
+#include <glib.h>
 
 #define GDK_IS_MACOS_CAIRO_SUBVIEW(obj) ((obj) && [obj isKindOfClass:[GdkMacosCairoSubview class]])
 
 @interface GdkMacosCairoSubview : NSView
 {
-  BOOL             _isOpaque;
-  cairo_region_t  *clip;
-  CGImageRef       image;
+  BOOL        _isOpaque;
+  GArray     *clip;
+  GArray     *damage;
+  CGImageRef  image;
 }
 
 -(void)setOpaque:(BOOL)opaque;


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