macos: precalculate clip regions as CGRect
authorChristian Hergert <christian@hergert.me>
Fri, 4 Feb 2022 17:31:37 +0000 (09:31 -0800)
committerChristian Hergert <christian@hergert.me>
Fri, 4 Feb 2022 17:31:37 +0000 (09:31 -0800)
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
gdk/macos/GdkMacosCairoSubview.h

index af22e898870b89b0de7e23195cc6053be4bf1a2e..fddb0ed0c09b70953d321329f270e4f2ccfb9b01 100644 (file)
@@ -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];
 }
    * 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);
         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];
   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
index e6fda6ac43bf5d4eb4ddfe718690f478142b9573..e03b47727d6702f17feb8d8a7654d35d527fb076 100644 (file)
  */
 
 #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;