[gtk/wip/chergert/quartz4u: 124/146] macos: avoid recreating views for opaque regions



commit a178aea9846a6143f5f46fbeab40908bd36abbfc
Author: Christian Hergert <chergert redhat com>
Date:   Wed Jun 3 17:44:09 2020 -0700

    macos: avoid recreating views for opaque regions

 gdk/macos/GdkMacosCairoView.c | 49 +++++++++++++++++++++++++++++++++++++++++--
 gdk/macos/GdkMacosCairoView.h |  1 +
 2 files changed, 48 insertions(+), 2 deletions(-)
---
diff --git a/gdk/macos/GdkMacosCairoView.c b/gdk/macos/GdkMacosCairoView.c
index 06f1db44a8..e6a31178b4 100644
--- a/gdk/macos/GdkMacosCairoView.c
+++ b/gdk/macos/GdkMacosCairoView.c
@@ -33,6 +33,14 @@
 
 @implementation GdkMacosCairoView
 
+-(void)dealloc
+{
+  g_clear_pointer (&self->opaque, g_ptr_array_unref);
+  self->transparent = NULL;
+
+  [super dealloc];
+}
+
 -(BOOL)isOpaque
 {
   if ([self window])
@@ -57,6 +65,9 @@
 {
   [[self->transparent subviews]
     makeObjectsPerformSelector:@selector(removeFromSuperview)];
+
+  if (self->opaque->len)
+    g_ptr_array_remove_range (self->opaque, 0, self->opaque->len);
 }
 
 -(void)setOpaqueRegion:(cairo_region_t *)region
@@ -64,13 +75,38 @@
   NSRect abs_bounds;
   guint n_rects;
 
-  [self removeOpaqueChildren];
-
   if (region == NULL)
     return;
 
   abs_bounds = [self convertRect:[self bounds] toView:nil];
   n_rects = cairo_region_num_rectangles (region);
+
+  /* The common case (at least for opaque windows and CSD) is that we will
+   * have either one or two opaque rectangles. If we detect that the same
+   * number of them are available as the previous, we can just resize the
+   * previous ones to avoid adding/removing views at a fast rate while
+   * resizing.
+   */
+  if (n_rects == self->opaque->len)
+    {
+      for (guint i = 0; i < n_rects; i++)
+        {
+          GdkMacosCairoSubview *child;
+          cairo_rectangle_int_t rect;
+
+          child = g_ptr_array_index (self->opaque, i);
+          cairo_region_get_rectangle (region, i, &rect);
+
+          [child setFrame:NSMakeRect (rect.x - abs_bounds.origin.x,
+                                      rect.y - abs_bounds.origin.y,
+                                      rect.width,
+                                      rect.height)];
+        }
+
+      return;
+    }
+
+  [self removeOpaqueChildren];
   for (guint i = 0; i < n_rects; i++)
     {
       GdkMacosCairoSubview *child;
@@ -87,6 +123,7 @@
       [child setOpaque:YES];
       [child setWantsLayer:YES];
       [self->transparent addSubview:child];
+      g_ptr_array_add (self->opaque, child);
     }
 }
 
@@ -94,6 +131,13 @@
 {
   if ((self = [super initWithFrame:frame]))
     {
+      /* An array to track all the opaque children placed into
+       * the child self->transparent. This allows us to reuse them
+       * when we receive a new opaque area instead of discarding
+       * them on each draw.
+       */
+      self->opaque = g_ptr_array_new ();
+
       /* Setup our primary subview which will render all content that is not
        * within an opaque region (such as shadows for CSD windows). For opaque
        * windows, this will all be obscurred by other views, so it doesn't
@@ -101,6 +145,7 @@
        */
       self->transparent = [[GdkMacosCairoSubview alloc] initWithFrame:frame];
       [self addSubview:self->transparent];
+
     }
 
   return self;
diff --git a/gdk/macos/GdkMacosCairoView.h b/gdk/macos/GdkMacosCairoView.h
index 913c24e399..1c28d83b39 100644
--- a/gdk/macos/GdkMacosCairoView.h
+++ b/gdk/macos/GdkMacosCairoView.h
@@ -28,6 +28,7 @@
 @interface GdkMacosCairoView : GdkMacosBaseView
 {
   NSView *transparent;
+  GPtrArray *opaque;
 }
 
 -(void)setCairoSurface:(cairo_surface_t *)cairoSurface


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