[gimp/gimp-2-8] Bug 736411 - Ruler updates cause slowdown when painting



commit 597fae39b4911b6e6e201e711f6de86cb6548f10
Author: Michael Henning <drawoc darkrefraction com>
Date:   Tue Aug 11 16:20:59 2015 -0400

    Bug 736411 - Ruler updates cause slowdown when painting
    
    We now avoid drawing rulers in the position property setter and use
    gtk's region invalidation instead. Previously, we were basically
    redrawing the ruler inside the mouse event handler, which is pure evil.
    
    (cherry picked from commit 72617e42b426e6788c075539a20df7365d2cf102)

 libgimpwidgets/gimpruler.c |  176 ++++++++++++++++++++++++--------------------
 1 files changed, 96 insertions(+), 80 deletions(-)
---
diff --git a/libgimpwidgets/gimpruler.c b/libgimpwidgets/gimpruler.c
index 82ac41b..c412ebd 100644
--- a/libgimpwidgets/gimpruler.c
+++ b/libgimpwidgets/gimpruler.c
@@ -69,12 +69,10 @@ typedef struct
 
   GdkWindow       *input_window;
   cairo_surface_t *backing_store;
+  gboolean         backing_store_valid;
   PangoLayout     *layout;
   gdouble          font_scale;
 
-  gint             xsrc;
-  gint             ysrc;
-
   GList           *track_widgets;
 } GimpRulerPrivate;
 
@@ -119,6 +117,8 @@ static gboolean      gimp_ruler_expose        (GtkWidget      *widget,
                                                GdkEventExpose *event);
 
 static void          gimp_ruler_draw_ticks    (GimpRuler      *ruler);
+static GdkRectangle  gimp_ruler_get_pos_rect  (GimpRuler      *ruler,
+                                               gdouble         position);
 static void          gimp_ruler_draw_pos      (GimpRuler      *ruler,
                                                cairo_t        *cr);
 static void          gimp_ruler_make_pixmap   (GimpRuler      *ruler);
@@ -228,14 +228,15 @@ gimp_ruler_init (GimpRuler *ruler)
 
   gtk_widget_set_has_window (GTK_WIDGET (ruler), FALSE);
 
-  priv->orientation   = GTK_ORIENTATION_HORIZONTAL;
-  priv->unit          = GIMP_PIXELS;
-  priv->lower         = 0;
-  priv->upper         = 0;
-  priv->position      = 0;
-  priv->max_size      = 0;
-  priv->backing_store = NULL;
-  priv->font_scale    = DEFAULT_RULER_FONT_SCALE;
+  priv->orientation         = GTK_ORIENTATION_HORIZONTAL;
+  priv->unit                = GIMP_PIXELS;
+  priv->lower               = 0;
+  priv->upper               = 0;
+  priv->position            = 0;
+  priv->max_size            = 0;
+  priv->backing_store       = NULL;
+  priv->backing_store_valid = FALSE;
+  priv->font_scale          = DEFAULT_RULER_FONT_SCALE;
 }
 
 static void
@@ -573,6 +574,7 @@ gimp_ruler_set_unit (GimpRuler *ruler,
       priv->unit = unit;
       g_object_notify (G_OBJECT (ruler), "unit");
 
+      priv->backing_store_valid = FALSE;
       gtk_widget_queue_draw (GTK_WIDGET (ruler));
     }
 }
@@ -614,10 +616,28 @@ gimp_ruler_set_position (GimpRuler *ruler,
 
   if (priv->position != position)
     {
+      gdouble old_pos = priv->position;
+
       priv->position = position;
       g_object_notify (G_OBJECT (ruler), "position");
 
-      gimp_ruler_draw_pos (ruler, NULL);
+      {
+        GdkRectangle rect;
+
+        rect = gimp_ruler_get_pos_rect (ruler, old_pos);
+        gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
+                                    rect.x,
+                                    rect.y,
+                                    rect.width,
+                                    rect.height);
+
+        rect = gimp_ruler_get_pos_rect (ruler, position);
+        gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
+                                    rect.x,
+                                    rect.y,
+                                    rect.width,
+                                    rect.height);
+      }
     }
 }
 
@@ -679,6 +699,7 @@ gimp_ruler_set_range (GimpRuler *ruler,
     }
   g_object_thaw_notify (G_OBJECT (ruler));
 
+  priv->backing_store_valid = FALSE;
   gtk_widget_queue_draw (GTK_WIDGET (ruler));
 }
 
@@ -759,6 +780,8 @@ gimp_ruler_unrealize (GtkWidget *widget)
       priv->backing_store = NULL;
     }
 
+  priv->backing_store_valid = FALSE;
+
   if (priv->layout)
     {
       g_object_unref (priv->layout);
@@ -883,16 +906,16 @@ gimp_ruler_expose (GtkWidget      *widget,
       GtkAllocation     allocation;
       cairo_t          *cr;
 
-      gimp_ruler_draw_ticks (ruler);
+      if (! priv->backing_store_valid)
+        gimp_ruler_draw_ticks (ruler);
 
       cr = gdk_cairo_create (gtk_widget_get_window (widget));
       gdk_cairo_region (cr, event->region);
       cairo_clip (cr);
 
       gtk_widget_get_allocation (widget, &allocation);
-      cairo_translate (cr, allocation.x, allocation.y);
-
-      cairo_set_source_surface (cr, priv->backing_store, 0, 0);
+      cairo_set_source_surface (cr, priv->backing_store,
+                                allocation.x, allocation.y);
       cairo_paint (cr);
 
       gimp_ruler_draw_pos (ruler, cr);
@@ -1137,27 +1160,30 @@ gimp_ruler_draw_ticks (GimpRuler *ruler)
     }
 
   cairo_fill (cr);
+
+  priv->backing_store_valid = TRUE;
+
 out:
   cairo_destroy (cr);
 }
 
-static void
-gimp_ruler_draw_pos (GimpRuler *ruler,
-                     cairo_t   *cr)
+static GdkRectangle
+gimp_ruler_get_pos_rect (GimpRuler *ruler, gdouble position)
 {
+  GdkRectangle rect = {0, };
+
   GtkWidget        *widget = GTK_WIDGET (ruler);
   GtkStyle         *style  = gtk_widget_get_style (widget);
   GimpRulerPrivate *priv   = GIMP_RULER_GET_PRIVATE (ruler);
-  GtkStateType      state  = gtk_widget_get_state (widget);
   GtkAllocation     allocation;
-  gint              x, y;
   gint              width, height;
-  gint              bs_width, bs_height;
   gint              xthickness;
   gint              ythickness;
+  gdouble           upper, lower;
+  gdouble           increment;
 
   if (! gtk_widget_is_drawable (widget))
-    return;
+    return rect;
 
   gtk_widget_get_allocation (widget, &allocation);
 
@@ -1169,91 +1195,79 @@ gimp_ruler_draw_pos (GimpRuler *ruler,
       width  = allocation.width;
       height = allocation.height - ythickness * 2;
 
-      bs_width = height / 2 + 2;
-      bs_width |= 1;  /* make sure it's odd */
-      bs_height = bs_width / 2 + 1;
+      rect.width = height / 2 + 2;
+      rect.width |= 1;  /* make sure it's odd */
+      rect.height = rect.width / 2 + 1;
     }
   else
     {
       width  = allocation.width - xthickness * 2;
       height = allocation.height;
 
-      bs_height = width / 2 + 2;
-      bs_height |= 1;  /* make sure it's odd */
-      bs_width = bs_height / 2 + 1;
+      rect.height = width / 2 + 2;
+      rect.height |= 1;  /* make sure it's odd */
+      rect.width = rect.height / 2 + 1;
     }
 
-  if ((bs_width > 0) && (bs_height > 0))
-    {
-      gdouble  lower;
-      gdouble  upper;
-      gdouble  position;
-      gdouble  increment;
-
-      if (! cr)
-        {
-          cr = gdk_cairo_create (gtk_widget_get_window (widget));
+  gimp_ruler_get_range (ruler, &lower, &upper, NULL);
 
-          cairo_rectangle (cr,
-                           allocation.x, allocation.y,
-                           allocation.width, allocation.height);
-          cairo_clip (cr);
+  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      increment = (gdouble) width / (upper - lower);
 
-          cairo_translate (cr, allocation.x, allocation.y);
+      rect.x = ROUND ((position - lower) * increment) + (xthickness - rect.width) / 2 - 1;
+      rect.y = (height + rect.height) / 2 + ythickness;
+    }
+  else
+    {
+      increment = (gdouble) height / (upper - lower);
 
-          /*  If a backing store exists, restore the ruler  */
-          if (priv->backing_store)
-            {
-              cairo_set_source_surface (cr, priv->backing_store, 0, 0);
-              cairo_rectangle (cr, priv->xsrc, priv->ysrc, bs_width, bs_height);
-              cairo_fill (cr);
-            }
-        }
-      else
-        {
-          cairo_reference (cr);
-        }
+      rect.x = (width + rect.width) / 2 + xthickness;
+      rect.y = ROUND ((position - lower) * increment) + (ythickness - rect.height) / 2 - 1;
+    }
 
-      position = gimp_ruler_get_position (ruler);
+  rect.x += allocation.x;
+  rect.y += allocation.y;
 
-      gimp_ruler_get_range (ruler, &lower, &upper, NULL);
+  return rect;
+}
 
-      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
-        {
-          increment = (gdouble) width / (upper - lower);
+static void
+gimp_ruler_draw_pos (GimpRuler *ruler, cairo_t *cr)
+{
+  GtkWidget        *widget = GTK_WIDGET (ruler);
+  GtkStyle         *style  = gtk_widget_get_style (widget);
+  GimpRulerPrivate *priv   = GIMP_RULER_GET_PRIVATE (ruler);
+  GtkStateType      state  = gtk_widget_get_state (widget);
+  GdkRectangle      pos_rect;
 
-          x = ROUND ((position - lower) * increment) + (xthickness - bs_width) / 2 - 1;
-          y = (height + bs_height) / 2 + ythickness;
-        }
-      else
-        {
-          increment = (gdouble) height / (upper - lower);
+  if (! gtk_widget_is_drawable (widget))
+    return;
 
-          x = (width + bs_width) / 2 + xthickness;
-          y = ROUND ((position - lower) * increment) + (ythickness - bs_height) / 2 - 1;
-        }
+  pos_rect = gimp_ruler_get_pos_rect (ruler, gimp_ruler_get_position (ruler));
 
+  if ((pos_rect.width > 0) && (pos_rect.height > 0))
+    {
       gdk_cairo_set_source_color (cr, &style->fg[state]);
 
-      cairo_move_to (cr, x, y);
+      cairo_move_to (cr, pos_rect.x, pos_rect.y);
 
       if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
         {
-          cairo_line_to (cr, x + bs_width / 2.0, y + bs_height);
-          cairo_line_to (cr, x + bs_width,       y);
+          cairo_line_to (cr, pos_rect.x + pos_rect.width / 2.0,
+                             pos_rect.y + pos_rect.height);
+          cairo_line_to (cr, pos_rect.x + pos_rect.width,
+                             pos_rect.y);
         }
       else
         {
-          cairo_line_to (cr, x + bs_width, y + bs_height / 2.0);
-          cairo_line_to (cr, x,            y + bs_height);
+          cairo_line_to (cr, pos_rect.x + pos_rect.width,
+                             pos_rect.y + pos_rect.height / 2.0);
+          cairo_line_to (cr, pos_rect.x,
+                             pos_rect.y + pos_rect.height);
         }
 
       cairo_fill (cr);
-
-      cairo_destroy (cr);
-
-      priv->xsrc = x;
-      priv->ysrc = y;
     }
 }
 
@@ -1274,6 +1288,8 @@ gimp_ruler_make_pixmap (GimpRuler *ruler)
                                        CAIRO_CONTENT_COLOR,
                                        allocation.width,
                                        allocation.height);
+
+  priv->backing_store_valid = FALSE;
 }
 
 


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