[gtk+/wip/simple-draw4: 4/20] gdkwindow: Simplify clip region handling



commit 6f32b6fadc4af87f00b0586097aedb52f3c4c249
Author: Alexander Larsson <alexl redhat com>
Date:   Wed Apr 17 16:36:52 2013 +0200

    gdkwindow: Simplify clip region handling
    
    Since we dropped the move region optimization there is really no need
    to try carefully keep track of opaque non-overlapped regions, as we
    don't use this information to trigger the optimization anymore.
    
    So, by assuming that all windows are non-opaque we can vastly simplify
    the clip region stuff. First of all, we don't need clip_region_with_children,
    as each window will need to draw under all children anyway. Secondly, we
    don't remove overlapping sibling areas from clip_region, as these are
    all non-opaque anyway and we need to draw under them
    
    Finally, we don't need to track the layered region anymore as its
    essentially unused. The few times something like it is needed we can
    compute it explicitly.
    
    For the case of native children of widgets we may cause a repaint
    under native windows that are guaranteed to be opaque, but these
    will be clipped by the native child anyway.

 gdk/gdkwindow.c |  275 +++++++++++++------------------------------------------
 1 files changed, 64 insertions(+), 211 deletions(-)
---
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index fd82e31..f1e8f75 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -123,9 +123,7 @@
  * All GdkWindows (native or not) track the position of the window in the parent
  * (x, y), the size of the window (width, height), the position of the window
  * with respect to the impl window (abs_x, abs_y). We also track the clip
- * region of the window wrt parent windows and siblings, in window-relative
- * coordinates with and without child windows included (clip_region,
- * clip_region_with_children).
+ * region of the window wrt parent windows, in window-relative coordinates (clip_region).
  *
  * All toplevel windows are native windows, but also child windows can be
  * native (although not children of offscreens). We always listen to
@@ -216,7 +214,6 @@ static void gdk_window_invalidate_rect_full (GdkWindow          *window,
                                             const GdkRectangle *rect,
                                             gboolean            invalidate_children,
                                             ClearBg             clear_bg);
-static void _gdk_window_propagate_has_alpha_background (GdkWindow *window);
 static cairo_surface_t *gdk_window_ref_impl_surface (GdkWindow *window);
 
 static void gdk_window_set_frame_clock (GdkWindow      *window,
@@ -565,9 +562,6 @@ gdk_window_finalize (GObject *object)
   if (window->devices_inside)
     g_list_free (window->devices_inside);
 
-  if (window->layered_region)
-      cairo_region_destroy (window->layered_region);
-
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -655,72 +649,76 @@ gdk_window_has_no_impl (GdkWindow *window)
   return window->impl_window != window;
 }
 
-static gboolean
-gdk_window_has_alpha (GdkWindow *window)
-{
-  return !gdk_window_has_impl (window) &&
-    (window->has_alpha_background || window->alpha != 255);
-}
-
 static void
-remove_layered_child_area (GdkWindow *window,
-                          cairo_region_t *region)
+remove_sibling_overlapped_area (GdkWindow *window,
+                               cairo_region_t *region)
 {
-  GdkWindow *child;
+  GdkWindow *parent;
+  GdkWindow *sibling;
   cairo_region_t *child_region;
   GdkRectangle r;
   GList *l;
+  cairo_region_t *shape;
 
-  for (l = window->children; l; l = l->next)
+  parent = window->parent;
+
+  if (parent == NULL)
+    return;
+
+  /* Convert from from window coords to parent coords */
+  cairo_region_translate (region, window->x, window->y);
+
+  for (l = parent->children; l; l = l->next)
     {
-      child = l->data;
+      sibling = l->data;
 
-      /* If region is empty already, no need to do
-        anything potentially costly */
-      if (cairo_region_is_empty (region))
+      if (sibling == window)
        break;
 
-      if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
+      if (!GDK_WINDOW_IS_MAPPED (sibling) || sibling->input_only || sibling->composited)
        continue;
 
       /* Ignore offscreen children, as they don't draw in their parent and
        * don't take part in the clipping */
-      if (gdk_window_is_offscreen (child))
-       continue;
-
-      /* Only non-impl children with alpha add to the layered region */
-      if (!gdk_window_has_alpha (child))
+      if (gdk_window_is_offscreen (sibling))
        continue;
 
-      r.x = child->x;
-      r.y = child->y;
-      r.width = child->width;
-      r.height = child->height;
-
-      /* Bail early if child totally outside region */
-      if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
-       continue;
+      r.x = sibling->x;
+      r.y = sibling->y;
+      r.width = sibling->width;
+      r.height = sibling->height;
 
       child_region = cairo_region_create_rectangle (&r);
-      if (child->shape)
+
+      if (sibling->shape)
        {
          /* Adjust shape region to parent window coords */
-         cairo_region_translate (child->shape, child->x, child->y);
-         cairo_region_intersect (child_region, child->shape);
-         cairo_region_translate (child->shape, -child->x, -child->y);
+         cairo_region_translate (sibling->shape, sibling->x, sibling->y);
+         cairo_region_intersect (child_region, sibling->shape);
+         cairo_region_translate (sibling->shape, -sibling->x, -sibling->y);
+       }
+      else if (window->window_type == GDK_WINDOW_FOREIGN)
+       {
+         shape = GDK_WINDOW_IMPL_GET_CLASS (sibling)->get_shape (sibling);
+         if (shape)
+           {
+             cairo_region_intersect (child_region, shape);
+             cairo_region_destroy (shape);
+           }
        }
 
       cairo_region_subtract (region, child_region);
       cairo_region_destroy (child_region);
     }
+
+  /* Convert back to window coords */
+  cairo_region_translate (region, -window->x, -window->y);
 }
 
 static void
 remove_child_area (GdkWindow *window,
-                  GdkWindow *until,
                   gboolean for_input,
-                  cairo_region_t *region,
-                  cairo_region_t *layered_region)
+                  cairo_region_t *region)
 {
   GdkWindow *child;
   cairo_region_t *child_region;
@@ -732,9 +730,6 @@ remove_child_area (GdkWindow *window,
     {
       child = l->data;
 
-      if (child == until)
-       break;
-
       /* If region is empty already, no need to do
         anything potentially costly */
       if (cairo_region_is_empty (region))
@@ -791,13 +786,7 @@ remove_child_area (GdkWindow *window,
            }
        }
 
-      if (gdk_window_has_alpha (child))
-       {
-         if (layered_region != NULL)
-           cairo_region_union (layered_region, child_region);
-       }
-      else
-       cairo_region_subtract (region, child_region);
+      cairo_region_subtract (region, child_region);
       cairo_region_destroy (child_region);
     }
 }
@@ -924,8 +913,7 @@ apply_clip_as_shape (GdkWindow *window)
   r.height = window->height;
 
   region = cairo_region_copy (window->clip_region);
-  if (window->layered_region)
-    cairo_region_subtract (region, window->layered_region);
+  remove_sibling_overlapped_area (window, region);
 
   /* We only apply the clip region if would differ
      from the actual clip region implied by the size
@@ -948,7 +936,7 @@ recompute_visible_regions_internal (GdkWindow *private,
   GdkRectangle r;
   GList *l;
   GdkWindow *child;
-  cairo_region_t *new_clip, *new_layered;
+  cairo_region_t *new_clip;
   gboolean clip_region_changed;
   gboolean abs_pos_changed;
   int old_abs_x, old_abs_y;
@@ -975,13 +963,11 @@ recompute_visible_regions_internal (GdkWindow *private,
 
   /* Update clip region based on:
    * parent clip
-   * window size
-   * siblings in parents above window
+   * window size/position
    */
   clip_region_changed = FALSE;
   if (recalculate_clip)
     {
-      new_layered = cairo_region_create ();
       if (private->viewable)
        {
          /* Calculate visible region (sans children) in parent window coords */
@@ -992,17 +978,10 @@ recompute_visible_regions_internal (GdkWindow *private,
          new_clip = cairo_region_create_rectangle (&r);
 
          if (!gdk_window_is_toplevel (private))
-           {
-             cairo_region_intersect (new_clip, private->parent->clip_region);
-             cairo_region_union (new_layered, private->parent->layered_region);
-
-             /* Remove all overlapping children from parent. */
-             remove_child_area (private->parent, private, FALSE, new_clip, new_layered);
-           }
+           cairo_region_intersect (new_clip, private->parent->clip_region);
 
          /* Convert from parent coords to window coords */
          cairo_region_translate (new_clip, -private->x, -private->y);
-         cairo_region_translate (new_layered, -private->x, -private->y);
 
          if (private->shape)
            cairo_region_intersect (new_clip, private->shape);
@@ -1010,29 +989,13 @@ recompute_visible_regions_internal (GdkWindow *private,
       else
          new_clip = cairo_region_create ();
 
-      cairo_region_intersect (new_layered, new_clip);
-      
       if (private->clip_region == NULL ||
          !cairo_region_equal (private->clip_region, new_clip))
        clip_region_changed = TRUE;
 
-      if (private->layered_region == NULL ||
-         !cairo_region_equal (private->layered_region, new_layered))
-       clip_region_changed = TRUE;
-      
       if (private->clip_region)
        cairo_region_destroy (private->clip_region);
       private->clip_region = new_clip;
-
-      if (private->layered_region != NULL)
-       cairo_region_destroy (private->layered_region);
-      private->layered_region = new_layered;
-
-      if (private->clip_region_with_children)
-       cairo_region_destroy (private->clip_region_with_children);
-      private->clip_region_with_children = cairo_region_copy (private->clip_region);
-      if (private->window_type != GDK_WINDOW_ROOT)
-       remove_child_area (private, NULL, FALSE, private->clip_region_with_children, NULL);
     }
 
   if (clip_region_changed)
@@ -1446,7 +1409,6 @@ gdk_window_new (GdkWindow     *parent,
 
       /* XXX: Cache this somehow? */
       window->background = cairo_pattern_create_rgba (0, 0, 0, 0);
-      window->has_alpha_background = TRUE;
     }
   else
     {
@@ -1748,22 +1710,10 @@ gdk_window_reparent (GdkWindow *window,
 
   _gdk_window_update_viewable (window);
 
-  if (window->background == NULL)
-    {
-      /* parent relative background, update has_alpha_background */
-      if (window->parent == NULL ||
-         window->parent->window_type == GDK_WINDOW_ROOT)
-       window->has_alpha_background = FALSE;
-      else
-       window->has_alpha_background = window->parent->has_alpha_background;
-    }
-
   recompute_visible_regions (window, TRUE, FALSE);
   if (old_parent && GDK_WINDOW_TYPE (old_parent) != GDK_WINDOW_ROOT)
     recompute_visible_regions (old_parent, FALSE, TRUE);
 
-  _gdk_window_propagate_has_alpha_background (window);
-
   /* We used to apply the clip as the shape, but no more.
      Reset this to the real shape */
   if (gdk_window_has_impl (window) &&
@@ -1881,6 +1831,8 @@ gdk_window_ensure_native (GdkWindow *window)
   if (gdk_window_is_viewable (window))
     impl_class->show (window, FALSE);
 
+  gdk_window_invalidate_in_parent (window);
+
   return TRUE;
 }
 
@@ -2119,12 +2071,6 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
              cairo_region_destroy (window->clip_region);
              window->clip_region = NULL;
            }
-
-         if (window->clip_region_with_children)
-           {
-             cairo_region_destroy (window->clip_region_with_children);
-             window->clip_region_with_children = NULL;
-           }
        }
       break;
     }
@@ -2847,7 +2793,7 @@ gdk_window_flush_implicit_paint (GdkWindow *window)
 
   paint = l->data;
 
-  region = cairo_region_copy (window->clip_region_with_children);
+  region = cairo_region_copy (window->clip_region);
   cairo_region_translate (region, window->abs_x, window->abs_y);
 
   /* Anything in the whole flushed window that was drawn is now
@@ -3045,7 +2991,7 @@ gdk_window_begin_paint_region (GdkWindow       *window,
   paint = g_new (GdkWindowPaint, 1);
   paint->region = cairo_region_copy (region);
 
-  cairo_region_intersect (paint->region, window->clip_region_with_children);
+  cairo_region_intersect (paint->region, window->clip_region);
   cairo_region_get_extents (paint->region, &clip_box);
 
   cairo_region_translate (paint->region, window->abs_x, window->abs_y);
@@ -3080,9 +3026,8 @@ gdk_window_begin_paint_region (GdkWindow       *window,
      by being drawn in back to front order. However, if implicit paints are not used, for
      instance if it was flushed due to a non-double-buffered paint in the middle of the
      expose we need to copy in the existing data here. */
-  if (gdk_window_has_alpha (window) &&
-      (!implicit_paint ||
-       (implicit_paint && implicit_paint->flushed != NULL && !cairo_region_is_empty 
(implicit_paint->flushed))))
+  if (!implicit_paint ||
+      (implicit_paint && implicit_paint->flushed != NULL && !cairo_region_is_empty 
(implicit_paint->flushed)))
     {
       cairo_t *cr = cairo_create (paint->surface);
       /* We can't use gdk_cairo_set_source_window here, as that might
@@ -3186,7 +3131,7 @@ gdk_window_end_paint (GdkWindow *window)
     {
       cairo_t *cr;
 
-      full_clip = cairo_region_copy (window->clip_region_with_children);
+      full_clip = cairo_region_copy (window->clip_region);
       cairo_region_intersect (full_clip, paint->region);
 
       cr = gdk_cairo_create (window);
@@ -3535,7 +3480,7 @@ gdk_cairo_create (GdkWindow *window)
 
   if (!window->paint_stack)
     {
-      gdk_cairo_region (cr, window->clip_region_with_children);
+      gdk_cairo_region (cr, window->clip_region);
       cairo_clip (cr);
     }
   else
@@ -3715,10 +3660,9 @@ _gdk_window_process_updates_recurse (GdkWindow *window,
       end_implicit = gdk_window_begin_implicit_paint (window->impl_window, &clip_box, TRUE, window->alpha);
     }
 
-  /* Paint the window before the children, clipped to the window region
-     with visible child windows removed */
+  /* Paint the window before the children, clipped to the window region */
   clipped_expose_region = cairo_region_copy (expose_region);
-  cairo_region_intersect (clipped_expose_region, window->clip_region_with_children);
+  cairo_region_intersect (clipped_expose_region, window->clip_region);
 
   if (!cairo_region_is_empty (clipped_expose_region) &&
       !window->destroyed)
@@ -4416,7 +4360,7 @@ gdk_window_get_update_area (GdkWindow *window)
 
   if (impl_window->update_area)
     {
-      tmp_region = cairo_region_copy (window->clip_region_with_children);
+      tmp_region = cairo_region_copy (window->clip_region);
       /* Convert to impl coords */
       cairo_region_translate (tmp_region, window->abs_x, window->abs_y);
       cairo_region_intersect (tmp_region, impl_window->update_area);
@@ -4431,12 +4375,12 @@ gdk_window_get_update_area (GdkWindow *window)
          /* Convert from impl coords */
          cairo_region_translate (tmp_region, -window->abs_x, -window->abs_y);
 
-         /* Don't remove any update area that is overlapped by non-opaque windows
-            (children or siblings) with alpha, as these really need to be repainted
-            independently of this window. */
+         /* Don't remove any update area that is overlapped by sibling windows
+            or child windows as these really need to be repainted independently of this window. */
          to_remove = cairo_region_copy (tmp_region);
-         cairo_region_subtract (to_remove, window->parent->layered_region);
-         remove_layered_child_area (window, to_remove);
+
+         remove_child_area (window, FALSE, to_remove);
+         remove_sibling_overlapped_area (window, to_remove);
 
          /* Remove from update_area */
          cairo_region_translate (to_remove, window->abs_x, window->abs_y);
@@ -6068,28 +6012,6 @@ gdk_window_set_background_rgba (GdkWindow     *window,
 }
 
 
-/* Updates has_alpha_background recursively for all child windows
-   that have parent-relative alpha */
-static void
-_gdk_window_propagate_has_alpha_background (GdkWindow *window)
-{
-  GdkWindow *child;
-  GList *l;
-
-  for (l = window->children; l; l = l->next)
-    {
-      child = l->data;
-
-      if (child->background == NULL &&
-         child->has_alpha_background != window->has_alpha_background)
-       {
-         child->has_alpha_background = window->has_alpha_background;
-         recompute_visible_regions (child, TRUE, FALSE);
-         _gdk_window_propagate_has_alpha_background (child);
-       }
-    }
-}
-
 /**
  * gdk_window_set_background_pattern:
  * @window: a #GdkWindow
@@ -6107,9 +6029,6 @@ void
 gdk_window_set_background_pattern (GdkWindow *window,
                                    cairo_pattern_t *pattern)
 {
-  gboolean has_alpha;
-  cairo_pattern_type_t type;
-  
   g_return_if_fail (GDK_IS_WINDOW (window));
 
   if (window->input_only)
@@ -6121,69 +6040,6 @@ gdk_window_set_background_pattern (GdkWindow *window,
     cairo_pattern_destroy (window->background);
   window->background = pattern;
 
-  has_alpha = TRUE;
-
-  if (pattern == NULL)
-    {
-      /* parent-relative, copy has_alpha from parent */
-      if (window->parent == NULL ||
-         window->parent->window_type == GDK_WINDOW_ROOT)
-       has_alpha = FALSE;
-      else
-       has_alpha = window->parent->has_alpha_background;
-    }
-  else
-    {
-      type = cairo_pattern_get_type (pattern);
-
-      if (type == CAIRO_PATTERN_TYPE_SOLID)
-       {
-         double alpha;
-         cairo_pattern_get_rgba (pattern, NULL, NULL, NULL, &alpha);
-         if (alpha == 1.0)
-           has_alpha = FALSE;
-       }
-      else if (type == CAIRO_PATTERN_TYPE_LINEAR ||
-              type == CAIRO_PATTERN_TYPE_RADIAL)
-       {
-         int i, n;
-         double alpha;
-
-         n = 0;
-         cairo_pattern_get_color_stop_count (pattern, &n);
-         has_alpha = FALSE;
-         for (i = 0; i < n; i++)
-           {
-             cairo_pattern_get_color_stop_rgba (pattern, i, NULL,
-                                                NULL, NULL, NULL, &alpha);
-             if (alpha != 1.0)
-               {
-                 has_alpha = TRUE;
-                 break;
-               }
-           }
-       }
-      else if (type == CAIRO_PATTERN_TYPE_SURFACE)
-       {
-         cairo_surface_t *surface;
-         cairo_content_t content;
-
-         cairo_pattern_get_surface (pattern, &surface);
-         content = cairo_surface_get_content (surface);
-         has_alpha =
-           (content == CAIRO_CONTENT_ALPHA) ||
-           (content == CAIRO_CONTENT_COLOR_ALPHA);
-       }
-    }
-
-  if (has_alpha != window->has_alpha_background)
-    {
-      window->has_alpha_background = has_alpha;  
-      recompute_visible_regions (window, TRUE, FALSE);
-
-      _gdk_window_propagate_has_alpha_background (window);
-    }
-
   if (gdk_window_has_impl (window))
     {
       GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
@@ -6809,7 +6665,7 @@ do_child_shapes (GdkWindow *window,
   r.height = window->height;
 
   region = cairo_region_create_rectangle (&r);
-  remove_child_area (window, NULL, FALSE, region, NULL);
+  remove_child_area (window, FALSE, region);
 
   if (merge && window->shape)
     cairo_region_subtract (region, window->shape);
@@ -6928,7 +6784,7 @@ do_child_input_shapes (GdkWindow *window,
   r.height = window->height;
 
   region = cairo_region_create_rectangle (&r);
-  remove_child_area (window, NULL, TRUE, region, NULL);
+  remove_child_area (window, TRUE, region);
 
   if (merge && window->shape)
     cairo_region_subtract (region, window->shape);
@@ -9367,9 +9223,6 @@ gdk_window_print (GdkWindow *window,
     g_print (" alpha[%d]",
           window->alpha);
 
-  if (window->has_alpha_background)
-    g_print (" alpha_bg");
-
   s = print_region (window->clip_region);
   g_print (" clipbox[%s]", s);
 


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