[gtk+/wip/simple-draw3] Split out offscreen surface from GtkViewport to GtkPixelCache



commit d0e34a0ac91b7196d58267aeb4741444db6512df
Author: Alexander Larsson <alexl redhat com>
Date:   Tue Apr 30 15:13:36 2013 +0200

    Split out offscreen surface from GtkViewport to GtkPixelCache
    
    This will make it easier to do similar scrolling in other widgets.

 gtk/Makefile.am            |    2 +
 gtk/gtkpixelcache.c        |  312 ++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkpixelcacheprivate.h |   48 +++++++
 gtk/gtkviewport.c          |  252 ++++++------------------------------
 4 files changed, 403 insertions(+), 211 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 6e7bbf1..09ca890 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -519,6 +519,7 @@ gtk_private_h_sources =             \
        gtkprintoperation-private.h \
        gtkprintutils.h         \
        gtkprivate.h            \
+       gtkpixelcacheprivate.h  \
        gtkquery.h              \
        gtkrbtree.h             \
        gtkrecentchooserdefault.h \
@@ -800,6 +801,7 @@ gtk_base_c_sources =                \
        gtkprivate.c            \
        gtkprivatetypebuiltins.c \
        gtkprogressbar.c        \
+       gtkpixelcache.c         \
        gtkradioaction.c        \
        gtkradiobutton.c        \
        gtkradiomenuitem.c      \
diff --git a/gtk/gtkpixelcache.c b/gtk/gtkpixelcache.c
new file mode 100644
index 0000000..7b0b345
--- /dev/null
+++ b/gtk/gtkpixelcache.c
@@ -0,0 +1,312 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gtkpixelcacheprivate.h"
+
+/* The extra size of the offscreen surface we allocate
+   to make scrolling more efficient */
+#define EXTRA_SIZE 64
+
+/* When resizing viewport to smaller we allow this extra
+   size to avoid constantly reallocating when resizing */
+#define ALLOW_LARGER_SIZE 32
+
+struct _GtkPixelCache {
+  cairo_surface_t *surface;
+
+  /* Valid if surface != NULL */
+  int surface_x;
+  int surface_y;
+  int surface_w;
+  int surface_h;
+
+  /* may be null if not dirty */
+  cairo_region_t *surface_dirty;
+};
+
+GtkPixelCache *
+_gtk_pixel_cache_new ()
+{
+  GtkPixelCache *cache;
+
+  cache = g_new0 (GtkPixelCache, 1);
+
+  return cache;
+}
+
+void
+_gtk_pixel_cache_free (GtkPixelCache *cache)
+{
+  if (cache == NULL)
+    return;
+
+  if (cache->surface != NULL)
+    cairo_surface_destroy (cache->surface);
+
+  if (cache->surface_dirty != NULL)
+    cairo_region_destroy (cache->surface_dirty);
+
+  g_free (cache);
+}
+
+/* Region is in canvas coordinates */
+void
+_gtk_pixel_cache_invalidate (GtkPixelCache *cache,
+                            cairo_region_t *region)
+{
+  cairo_rectangle_int_t r;
+
+  if (cache->surface == NULL || cairo_region_is_empty (region))
+    return;
+
+  if (cache->surface_dirty == NULL)
+    {
+      cache->surface_dirty = cairo_region_copy (region);
+      cairo_region_translate (cache->surface_dirty,
+                             -cache->surface_x,
+                             -cache->surface_y);
+    }
+  else
+    {
+      cairo_region_translate (region,
+                             -cache->surface_x,
+                             -cache->surface_y);
+      cairo_region_union (cache->surface_dirty, region);
+      cairo_region_translate (region,
+                             cache->surface_x,
+                             cache->surface_y);
+    }
+
+  r.x = 0;
+  r.y = 0;
+  r.width = cache->surface_w;
+  r.height = cache->surface_h;
+  cairo_region_intersect_rectangle (cache->surface_dirty, &r);
+}
+
+static void
+_gtk_pixel_cache_create_surface_if_needed (GtkPixelCache         *cache,
+                                          GdkWindow             *window,
+                                          cairo_rectangle_int_t *view_rect,
+                                          cairo_rectangle_int_t *canvas_rect)
+{
+  cairo_rectangle_int_t rect;
+  int surface_w, surface_h;
+
+  surface_w = view_rect->width;
+  if (canvas_rect->width > surface_w)
+    surface_w = MIN (surface_w + EXTRA_SIZE, canvas_rect->width);
+
+  surface_h = view_rect->height;
+  if (canvas_rect->height > surface_h)
+    surface_h = MIN (surface_h + EXTRA_SIZE, canvas_rect->height);
+
+  /* If current surface can't fit view_rect or is too large, kill it */
+  if (cache->surface != NULL &&
+      (cache->surface_w < view_rect->width ||
+       cache->surface_w > surface_w + ALLOW_LARGER_SIZE ||
+       cache->surface_h < view_rect->height ||
+       cache->surface_h > surface_h + ALLOW_LARGER_SIZE))
+    {
+      cairo_surface_destroy (cache->surface);
+      cache->surface = NULL;
+      if (cache->surface_dirty)
+       cairo_region_destroy (cache->surface_dirty);
+      cache->surface_dirty = NULL;
+    }
+
+  /* Don't allocate a surface if view >= canvas, as we won't
+     be scrolling then anyway */
+  if (cache->surface == NULL &&
+      (view_rect->width < canvas_rect->width ||
+       view_rect->height < canvas_rect->height))
+    {
+      cache->surface_x = -canvas_rect->x;
+      cache->surface_y = -canvas_rect->y;
+      cache->surface_w = surface_w;
+      cache->surface_h = surface_h;
+      cache->surface =
+       gdk_window_create_similar_surface (window,
+                                          CAIRO_CONTENT_COLOR_ALPHA,
+                                          surface_w, surface_h);
+      rect.x = 0;
+      rect.y = 0;
+      rect.width = surface_w;
+      rect.height = surface_h;
+      cache->surface_dirty =
+       cairo_region_create_rectangle (&rect);
+    }
+}
+
+void
+_gtk_pixel_cache_set_position (GtkPixelCache         *cache,
+                              cairo_rectangle_int_t *view_rect,
+                              cairo_rectangle_int_t *canvas_rect)
+{
+  cairo_rectangle_int_t r, view_pos;
+  cairo_region_t *copy_region;
+  int new_surf_x, new_surf_y;
+  cairo_t *backing_cr;
+
+  if (cache->surface == NULL)
+    return;
+
+  /* Position of view inside canvas */
+  view_pos.x = -canvas_rect->x;
+  view_pos.y = -canvas_rect->y;
+  view_pos.width = view_rect->width;
+  view_pos.height = view_rect->height;
+
+  /* Reposition so all is visible */
+  if (view_pos.x < cache->surface_x ||
+      view_pos.x + view_pos.width >
+      cache->surface_x + cache->surface_w ||
+      view_pos.y < cache->surface_y ||
+      view_pos.y + view_pos.height >
+      cache->surface_y + cache->surface_h)
+    {
+      new_surf_x = cache->surface_x;
+      if (view_pos.x < cache->surface_x)
+       new_surf_x = MAX (view_pos.x + view_pos.width - cache->surface_w, 0);
+      else if (view_pos.x + view_pos.width >
+              cache->surface_x + cache->surface_w)
+       new_surf_x = MIN (view_pos.x, canvas_rect->width - cache->surface_w);
+
+      new_surf_y = cache->surface_y;
+      if (view_pos.y < cache->surface_y)
+       new_surf_y = MAX (view_pos.y + view_pos.height - cache->surface_h, 0);
+      else if (view_pos.y + view_pos.height >
+              cache->surface_y + cache->surface_h)
+       new_surf_y = MIN (view_pos.y, canvas_rect->height - cache->surface_h);
+
+      r.x = 0;
+      r.y = 0;
+      r.width = cache->surface_w;
+      r.height = cache->surface_h;
+      copy_region = cairo_region_create_rectangle (&r);
+
+      if (cache->surface_dirty)
+       {
+         cairo_region_subtract (copy_region, cache->surface_dirty);
+         cairo_region_destroy (cache->surface_dirty);
+         cache->surface_dirty = NULL;
+       }
+
+      cairo_region_translate (copy_region,
+                             cache->surface_x - new_surf_x,
+                             cache->surface_y - new_surf_y);
+      cairo_region_intersect_rectangle (copy_region, &r);
+
+      backing_cr = cairo_create (cache->surface);
+      gdk_cairo_region (backing_cr, copy_region);
+      cairo_clip (backing_cr);
+      cairo_push_group (backing_cr);
+      cairo_set_source_surface (backing_cr, cache->surface,
+                               cache->surface_x - new_surf_x,
+                               cache->surface_y - new_surf_y);
+      cairo_paint (backing_cr);
+      cairo_pop_group_to_source (backing_cr);
+      cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE);
+      cairo_paint (backing_cr);
+      cairo_destroy (backing_cr);
+
+      cache->surface_x = new_surf_x;
+      cache->surface_y = new_surf_y;
+
+      cairo_region_xor_rectangle (copy_region, &r);
+      cache->surface_dirty = copy_region;
+    }
+}
+
+void
+_gtk_pixel_cache_repaint (GtkPixelCache *cache,
+                         GtkPixelCacheDrawFunc draw,
+                         cairo_rectangle_int_t *view_rect,
+                         cairo_rectangle_int_t *canvas_rect,
+                         gpointer user_data)
+{
+  cairo_t *backing_cr;
+
+  if (cache->surface &&
+      cache->surface_dirty &&
+      !cairo_region_is_empty (cache->surface_dirty))
+    {
+      backing_cr = cairo_create (cache->surface);
+      gdk_cairo_region (backing_cr, cache->surface_dirty);
+      cairo_clip (backing_cr);
+      cairo_translate (backing_cr,
+                      -cache->surface_x - canvas_rect->x - view_rect->x,
+                      -cache->surface_y - canvas_rect->y - view_rect->y);
+      cairo_set_source_rgba (backing_cr,
+                            0.0, 0, 0, 0.0);
+      cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE);
+      cairo_paint (backing_cr);
+
+      cairo_set_operator (backing_cr, CAIRO_OPERATOR_OVER);
+
+      draw (backing_cr, user_data);
+
+      cairo_destroy (backing_cr);
+    }
+
+  if (cache->surface_dirty)
+    {
+      cairo_region_destroy (cache->surface_dirty);
+      cache->surface_dirty = NULL;
+    }
+}
+
+void
+_gtk_pixel_cache_draw (GtkPixelCache *cache,
+                      cairo_t *cr,
+                      GdkWindow *window,
+                      /* View position in widget coords */
+                      cairo_rectangle_int_t *view_rect,
+                      /* Size and position of canvas in view coords */
+                      cairo_rectangle_int_t *canvas_rect,
+                      GtkPixelCacheDrawFunc draw,
+                      gpointer user_data)
+{
+  _gtk_pixel_cache_create_surface_if_needed (cache, window,
+                                            view_rect, canvas_rect);
+  _gtk_pixel_cache_set_position (cache, view_rect, canvas_rect);
+  _gtk_pixel_cache_repaint (cache, draw, view_rect, canvas_rect, user_data);
+
+  if (cache->surface &&
+      /* Don't use backing surface if rendering elsewhere */
+      cairo_surface_get_type (cache->surface) == cairo_surface_get_type (cairo_get_target (cr)))
+    {
+      cairo_save (cr);
+      cairo_set_source_surface (cr, cache->surface,
+                               cache->surface_x + view_rect->x + canvas_rect->x,
+                               cache->surface_y + view_rect->y + canvas_rect->y);
+      cairo_rectangle (cr, view_rect->x, view_rect->x,
+                      view_rect->width, view_rect->height);
+      cairo_fill (cr);
+      cairo_restore (cr);
+    }
+  else
+    {
+      cairo_rectangle (cr,
+                      view_rect->x, view_rect->x,
+                      view_rect->width, view_rect->height);
+      cairo_clip (cr);
+      draw (cr, user_data);
+    }
+}
diff --git a/gtk/gtkpixelcacheprivate.h b/gtk/gtkpixelcacheprivate.h
new file mode 100644
index 0000000..2b916d0
--- /dev/null
+++ b/gtk/gtkpixelcacheprivate.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2013 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Alexander Larsson <alexl gnome org>
+ */
+
+#ifndef __GTK_PIXEL_CACHE_PRIVATE_H__
+#define __GTK_PIXEL_CACHE_PRIVATE_H__
+
+#include <glib-object.h>
+#include <gtkwidget.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GtkPixelCache           GtkPixelCache;
+
+typedef void (*GtkPixelCacheDrawFunc) (cairo_t *cr,
+                                      gpointer user_data);
+
+GtkPixelCache *_gtk_pixel_cache_new        (void);
+void           _gtk_pixel_cache_free       (GtkPixelCache         *cache);
+void           _gtk_pixel_cache_invalidate (GtkPixelCache         *cache,
+                                           cairo_region_t        *region);
+void           _gtk_pixel_cache_draw       (GtkPixelCache         *cache,
+                                           cairo_t               *cr,
+                                           GdkWindow             *window,
+                                           cairo_rectangle_int_t *view_rect,
+                                           cairo_rectangle_int_t *canvas_rect,
+                                           GtkPixelCacheDrawFunc  draw,
+                                           gpointer               user_data);
+
+
+G_END_DECLS
+
+#endif /* __GTK_PIXEL_CACHE_PRIVATE_H__ */
diff --git a/gtk/gtkviewport.c b/gtk/gtkviewport.c
index 06f6643..c8d47b7 100644
--- a/gtk/gtkviewport.c
+++ b/gtk/gtkviewport.c
@@ -32,6 +32,7 @@
 #include "gtkprivate.h"
 #include "gtkscrollable.h"
 #include "gtktypebuiltins.h"
+#include "gtkpixelcacheprivate.h"
 
 
 /**
@@ -66,12 +67,7 @@ struct _GtkViewportPrivate
   GdkWindow      *bin_window;
   GdkWindow      *view_window;
 
-  int backing_surface_x;
-  int backing_surface_y;
-  int backing_surface_w;
-  int backing_surface_h;
-  cairo_surface_t *backing_surface;
-  cairo_region_t *backing_surface_dirty;
+  GtkPixelCache *pixel_cache;
 
   /* GtkScrollablePolicy needs to be checked when
    * driving the scrollable adjustment values */
@@ -256,6 +252,8 @@ gtk_viewport_init (GtkViewport *viewport)
   priv->hadjustment = NULL;
   priv->vadjustment = NULL;
 
+  priv->pixel_cache = _gtk_pixel_cache_new ();
+
   viewport_set_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL, NULL);
   viewport_set_adjustment (viewport, GTK_ORIENTATION_VERTICAL, NULL);
 }
@@ -308,10 +306,15 @@ static void
 gtk_viewport_destroy (GtkWidget *widget)
 {
   GtkViewport *viewport = GTK_VIEWPORT (widget);
+  GtkViewportPrivate *priv = viewport->priv;
 
   viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL);
   viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_VERTICAL);
 
+  if (priv->pixel_cache)
+    _gtk_pixel_cache_free (priv->pixel_cache);
+  priv->pixel_cache = NULL;
+
   GTK_WIDGET_CLASS (gtk_viewport_parent_class)->destroy (widget);
 }
 
@@ -663,28 +666,12 @@ gtk_viewport_bin_window_invalidate_handler (GdkWindow *window,
   gpointer widget;
   GtkViewport *viewport;
   GtkViewportPrivate *priv;
-  cairo_rectangle_int_t r;
 
   gdk_window_get_user_data (window, &widget);
   viewport = GTK_VIEWPORT (widget);
   priv = viewport->priv;
 
-  if (priv->backing_surface_dirty == NULL)
-    priv->backing_surface_dirty = cairo_region_create ();
-
-  cairo_region_translate (region,
-                         -priv->backing_surface_x,
-                         -priv->backing_surface_y);
-  cairo_region_union (priv->backing_surface_dirty, region);
-  cairo_region_translate (region,
-                         priv->backing_surface_x,
-                         priv->backing_surface_y);
-
-  r.x = 0;
-  r.y = 0;
-  r.width = priv->backing_surface_w;
-  r.height = priv->backing_surface_h;
-  cairo_region_intersect_rectangle (priv->backing_surface_dirty, &r);
+  _gtk_pixel_cache_invalidate (priv->pixel_cache, region);
 }
 
 static void
@@ -783,6 +770,25 @@ gtk_viewport_unrealize (GtkWidget *widget)
   GTK_WIDGET_CLASS (gtk_viewport_parent_class)->unrealize (widget);
 }
 
+static void
+draw_bin (cairo_t *cr,
+         gpointer user_data)
+{
+  GtkWidget *widget = GTK_WIDGET (user_data);
+  GtkViewport *viewport = GTK_VIEWPORT (widget);
+  GtkViewportPrivate *priv = viewport->priv;
+  GtkStyleContext *context;
+  int x, y;
+
+  context = gtk_widget_get_style_context (widget);
+
+  gdk_window_get_position (priv->bin_window, &x, &y);
+  gtk_render_background (context, cr, x, y,
+                        gdk_window_get_width (priv->bin_window),
+                        gdk_window_get_height (priv->bin_window));
+  GTK_WIDGET_CLASS (gtk_viewport_parent_class)->draw (widget, cr);
+}
+
 static gint
 gtk_viewport_draw (GtkWidget *widget,
                    cairo_t   *cr)
@@ -790,10 +796,6 @@ gtk_viewport_draw (GtkWidget *widget,
   GtkViewport *viewport = GTK_VIEWPORT (widget);
   GtkViewportPrivate *priv = viewport->priv;
   GtkStyleContext *context;
-  cairo_t *backing_cr;
-  GtkWidget *child;
-  int x, y, bin_x, bin_y, new_surf_x, new_surf_y;
-  cairo_rectangle_int_t view_pos;
 
   context = gtk_widget_get_style_context (widget);
 
@@ -810,150 +812,22 @@ gtk_viewport_draw (GtkWidget *widget,
       gtk_style_context_restore (context);
     }
 
-  if (priv->backing_surface &&
-      /* Don't use backing surface if rendering elsewhere */
-      cairo_surface_get_type (priv->backing_surface) == cairo_surface_get_type (cairo_get_target (cr)))
+  if (gtk_cairo_should_draw_window (cr, priv->bin_window))
     {
-      gdk_window_get_position (priv->bin_window, &bin_x, &bin_y);
-      view_pos.x = -bin_x;
-      view_pos.y = -bin_y;
-      view_pos.width = gdk_window_get_width (priv->view_window);
-      view_pos.height = gdk_window_get_height (priv->view_window);
-
-      /* Reposition so all is visible visible */
-      if (priv->backing_surface)
-       {
-         cairo_rectangle_int_t r;
-         cairo_region_t *copy_region;
-         if (view_pos.x < priv->backing_surface_x ||
-             view_pos.x + view_pos.width >
-             priv->backing_surface_x + priv->backing_surface_w ||
-             view_pos.y < priv->backing_surface_y ||
-             view_pos.y + view_pos.height >
-             priv->backing_surface_y + priv->backing_surface_h)
-           {
-             new_surf_x = priv->backing_surface_x;
-             if (view_pos.x < priv->backing_surface_x)
-               new_surf_x = view_pos.x - (priv->backing_surface_w - view_pos.width);
-             else if (view_pos.x + view_pos.width >
-                      priv->backing_surface_x + priv->backing_surface_w)
-               new_surf_x = view_pos.x;
-
-             new_surf_y = priv->backing_surface_y;
-             if (view_pos.y < priv->backing_surface_y)
-               new_surf_y = view_pos.y - (priv->backing_surface_h - view_pos.height);
-             else if (view_pos.y + view_pos.height >
-                      priv->backing_surface_y + priv->backing_surface_h)
-               new_surf_y = view_pos.y;
-
-             r.x = 0;
-             r.y = 0;
-             r.width = priv->backing_surface_w;
-             r.height = priv->backing_surface_h;
-             copy_region = cairo_region_create_rectangle (&r);
-
-             if (priv->backing_surface_dirty)
-               {
-                 cairo_region_subtract (copy_region, priv->backing_surface_dirty);
-                 cairo_region_destroy (priv->backing_surface_dirty);
-                 priv->backing_surface_dirty = NULL;
-               }
-
-             cairo_region_translate (copy_region,
-                                     priv->backing_surface_x - new_surf_x,
-                                     priv->backing_surface_y - new_surf_y);
-             cairo_region_intersect_rectangle (copy_region, &r);
-
-             backing_cr = cairo_create (priv->backing_surface);
-             gdk_cairo_region (backing_cr, copy_region);
-             cairo_clip (backing_cr);
-             cairo_push_group (backing_cr);
-             cairo_set_source_surface (backing_cr, priv->backing_surface,
-                                       priv->backing_surface_x - new_surf_x,
-                                       priv->backing_surface_y - new_surf_y);
-             cairo_paint (backing_cr);
-             cairo_pop_group_to_source (backing_cr);
-             cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE);
-             cairo_paint (backing_cr);
-             cairo_destroy (backing_cr);
-
-             priv->backing_surface_x = new_surf_x;
-             priv->backing_surface_y = new_surf_y;
-
-             cairo_region_xor_rectangle (copy_region, &r);
-             priv->backing_surface_dirty = copy_region;
-           }
-       }
+      cairo_rectangle_int_t view_rect;
+      cairo_rectangle_int_t canvas_rect;
 
-      if (priv->backing_surface_dirty &&
-         !cairo_region_is_empty (priv->backing_surface_dirty))
-       {
-         backing_cr = cairo_create (priv->backing_surface);
-         gdk_cairo_region (backing_cr, priv->backing_surface_dirty);
-         cairo_clip (backing_cr);
-         cairo_translate (backing_cr,
-                          -priv->backing_surface_x,
-                          -priv->backing_surface_y);
-         cairo_set_source_rgba (backing_cr,
-                                0, 0, 0, 0);
-         cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE);
-         cairo_paint (backing_cr);
-         cairo_set_operator (backing_cr, CAIRO_OPERATOR_OVER);
-         gtk_render_background (context, backing_cr,
-                                0,0,
-                                gdk_window_get_width (priv->bin_window),
-                                gdk_window_get_height (priv->bin_window));
-         child = gtk_bin_get_child (GTK_BIN (widget));
-         if (child && gtk_widget_get_visible (child)) {
-           if (!gtk_widget_get_has_window (child))
-             {
-               GtkAllocation child_allocation;
-               gtk_widget_get_allocation (child, &child_allocation);
-               cairo_translate (backing_cr,
-                                child_allocation.x,
-                                child_allocation.y);
-             }
-
-           gtk_widget_draw (child, backing_cr);
-         }
-
-         cairo_destroy (backing_cr);
-       }
+      gdk_window_get_position (priv->view_window, &view_rect.x, &view_rect.y);
+      view_rect.width = gdk_window_get_width (priv->view_window);
+      view_rect.height = gdk_window_get_height (priv->view_window);
 
-      if (priv->backing_surface_dirty)
-       {
-         cairo_region_destroy (priv->backing_surface_dirty);
-         priv->backing_surface_dirty = NULL;
-       }
+      gdk_window_get_position (priv->bin_window, &canvas_rect.x, &canvas_rect.y);
+      canvas_rect.width = gdk_window_get_width (priv->bin_window);
+      canvas_rect.height = gdk_window_get_height (priv->bin_window);
 
-      if (gtk_cairo_should_draw_window (cr, priv->bin_window))
-       {
-         gdk_window_get_position (priv->view_window, &x, &y);
-         cairo_set_source_surface (cr, priv->backing_surface,
-                                   priv->backing_surface_x + bin_x + x,
-                                   priv->backing_surface_y + bin_y + y);
-         cairo_rectangle (cr, x, y,
-                          gdk_window_get_width (priv->view_window),
-                          gdk_window_get_height (priv->view_window));
-         cairo_fill (cr);
-       }
-    }
-  else
-    {
-      /* Don't use backing_surface */
-      if (gtk_cairo_should_draw_window (cr, priv->bin_window))
-       {
-         gdk_window_get_position (priv->view_window, &x, &y);
-         cairo_rectangle (cr, x, y,
-                          gdk_window_get_width (priv->view_window),
-                          gdk_window_get_height (priv->view_window));
-         cairo_clip (cr);
-         gdk_window_get_position (priv->bin_window, &x, &y);
-         gtk_render_background (context, cr, x, y,
-                                gdk_window_get_width (priv->bin_window),
-                                gdk_window_get_height (priv->bin_window));
-         GTK_WIDGET_CLASS (gtk_viewport_parent_class)->draw (widget, cr);
-       }
+      _gtk_pixel_cache_draw (priv->pixel_cache, cr, priv->bin_window,
+                            &view_rect, &canvas_rect,
+                            draw_bin, widget);
     }
 
   return FALSE;
@@ -987,7 +861,6 @@ gtk_viewport_size_allocate (GtkWidget     *widget,
   GtkAdjustment *vadjustment = priv->vadjustment;
   GtkAllocation child_allocation;
   GtkWidget *child;
-  int surface_w, surface_h;
 
   border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
 
@@ -1016,7 +889,6 @@ gtk_viewport_size_allocate (GtkWidget     *widget,
   if (gtk_widget_get_realized (widget))
     {
       GtkAllocation view_allocation;
-      cairo_rectangle_int_t rect;
 
       gdk_window_move_resize (gtk_widget_get_window (widget),
                              allocation->x + border_width,
@@ -1035,48 +907,6 @@ gtk_viewport_size_allocate (GtkWidget     *widget,
                               - gtk_adjustment_get_value (vadjustment),
                               child_allocation.width,
                               child_allocation.height);
-
-      surface_w = view_allocation.width;
-      if (child_allocation.width > view_allocation.width)
-       surface_w = MIN (surface_w + 64, child_allocation.width);
-
-      surface_h = view_allocation.height;
-      if (child_allocation.height > view_allocation.height)
-       surface_h = MIN (surface_h + 64, child_allocation.height);
-
-      if (priv->backing_surface != NULL &&
-         (priv->backing_surface_w < view_allocation.width ||
-          priv->backing_surface_w > surface_w + 32 ||
-          priv->backing_surface_h < view_allocation.height ||
-          priv->backing_surface_h > surface_h + 32))
-       {
-         cairo_surface_destroy (priv->backing_surface);
-         priv->backing_surface = NULL;
-         if (priv->backing_surface_dirty)
-           cairo_region_destroy (priv->backing_surface_dirty);
-         priv->backing_surface_dirty = NULL;
-       }
-
-      if (priv->backing_surface == NULL &&
-         (view_allocation.width < child_allocation.width ||
-          view_allocation.height < child_allocation.height))
-       {
-         priv->backing_surface_x = gtk_adjustment_get_value (hadjustment);
-         priv->backing_surface_y = gtk_adjustment_get_value (vadjustment);
-         priv->backing_surface_w = surface_w;
-         priv->backing_surface_h = surface_h;
-         priv->backing_surface_dirty = cairo_region_create ();
-         priv->backing_surface =
-           gdk_window_create_similar_surface (priv->bin_window,
-                                              CAIRO_CONTENT_COLOR_ALPHA,
-                                              surface_w, surface_h);
-         rect.x = 0;
-         rect.y = 0;
-         rect.width = surface_w;
-         rect.height = surface_h;
-         cairo_region_union_rectangle (priv->backing_surface_dirty,
-                                       &rect);
-       }
     }
 
   child = gtk_bin_get_child (bin);


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