[gimp] app: port GimpDisplayShell selection drawing to cairo



commit 58db8a3ef0f87e83869604ec45c2f966b90f493e
Author: Michael Natterer <mitch gimp org>
Date:   Thu Aug 26 18:09:33 2010 +0200

    app: port GimpDisplayShell selection drawing to cairo
    
    but keep the old code around because it's much faster. The new code is
    enabled by defining the CAIRO_SELECTION environment variable.

 app/display/gimpdisplayshell-draw.c      |   63 +++++++++++++
 app/display/gimpdisplayshell-draw.h      |    9 ++
 app/display/gimpdisplayshell-selection.c |  150 ++++++++++++++++++++----------
 app/display/gimpdisplayshell-style.c     |   78 ++++++++++++++--
 app/display/gimpdisplayshell-style.h     |   43 +++++----
 5 files changed, 266 insertions(+), 77 deletions(-)
---
diff --git a/app/display/gimpdisplayshell-draw.c b/app/display/gimpdisplayshell-draw.c
index cfd9f88..df3d99c 100644
--- a/app/display/gimpdisplayshell-draw.c
+++ b/app/display/gimpdisplayshell-draw.c
@@ -566,6 +566,69 @@ gimp_display_shell_draw_layer_boundary (GimpDisplayShell *shell,
 }
 
 void
+gimp_display_shell_draw_selection_out (GimpDisplayShell *shell,
+                                       cairo_t          *cr,
+                                       GdkSegment       *segs,
+                                       gint              n_segs)
+{
+  gint i;
+
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+  g_return_if_fail (cr != NULL);
+  g_return_if_fail (segs != NULL && n_segs > 0);
+
+  gimp_display_shell_set_selection_out_style (shell, cr);
+
+  for (i = 0; i < n_segs; i++)
+    {
+      if (segs[i].x1 == segs[i].x2)
+        {
+          cairo_move_to (cr, segs[i].x1 + 0.5, segs[i].y1);
+          cairo_line_to (cr, segs[i].x2 + 0.5, segs[i].y2);
+        }
+      else
+        {
+          cairo_move_to (cr, segs[i].x1, segs[i].y1 + 0.5);
+          cairo_line_to (cr, segs[i].x2, segs[i].y2 + 0.5);
+        }
+    }
+
+  cairo_stroke (cr);
+}
+
+void
+gimp_display_shell_draw_selection_in (GimpDisplayShell *shell,
+                                      cairo_t          *cr,
+                                      GdkSegment       *segs,
+                                      gint              n_segs,
+                                      gint              index)
+{
+  gint i;
+
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+  g_return_if_fail (cr != NULL);
+  g_return_if_fail (segs != NULL && n_segs > 0);
+
+  gimp_display_shell_set_selection_in_style (shell, cr, index);
+
+  for (i = 0; i < n_segs; i++)
+    {
+      if (segs[i].x1 == segs[i].x2)
+        {
+          cairo_move_to (cr, segs[i].x1 + 0.5, segs[i].y1);
+          cairo_line_to (cr, segs[i].x2 + 0.5, segs[i].y2);
+        }
+      else
+        {
+          cairo_move_to (cr, segs[i].x1, segs[i].y1 + 0.5);
+          cairo_line_to (cr, segs[i].x2, segs[i].y2 + 0.5);
+        }
+    }
+
+  cairo_stroke (cr);
+}
+
+void
 gimp_display_shell_draw_vector (GimpDisplayShell *shell,
                                 GimpVectors      *vectors)
 {
diff --git a/app/display/gimpdisplayshell-draw.h b/app/display/gimpdisplayshell-draw.h
index d9d8199..8fed497 100644
--- a/app/display/gimpdisplayshell-draw.h
+++ b/app/display/gimpdisplayshell-draw.h
@@ -53,6 +53,15 @@ void   gimp_display_shell_draw_layer_boundary        (GimpDisplayShell   *shell,
                                                       GimpDrawable       *drawable,
                                                       GdkSegment         *segs,
                                                       gint                n_segs);
+void   gimp_display_shell_draw_selection_out         (GimpDisplayShell   *shell,
+                                                      cairo_t            *cr,
+                                                      GdkSegment         *segs,
+                                                      gint                n_segs);
+void   gimp_display_shell_draw_selection_in          (GimpDisplayShell   *shell,
+                                                      cairo_t            *cr,
+                                                      GdkSegment         *segs,
+                                                      gint                n_segs,
+                                                      gint                index);
 void   gimp_display_shell_draw_vector                (GimpDisplayShell   *shell,
                                                       GimpVectors        *vectors);
 void   gimp_display_shell_draw_vectors               (GimpDisplayShell   *shell);
diff --git a/app/display/gimpdisplayshell-selection.c b/app/display/gimpdisplayshell-selection.c
index 4741040..28b8cfd 100644
--- a/app/display/gimpdisplayshell-selection.c
+++ b/app/display/gimpdisplayshell-selection.c
@@ -51,6 +51,8 @@ struct _Selection
 {
   GimpDisplayShell *shell;            /*  shell that owns the selection     */
 
+  gboolean          use_cairo;        /*  temp hack                         */
+
   GdkSegment       *segs_in;          /*  gdk segments of area boundary     */
   gint              n_segs_in;        /*  number of segments in segs_in     */
 
@@ -122,6 +124,7 @@ gimp_display_shell_selection_init (GimpDisplayShell *shell)
   selection = g_slice_new0 (Selection);
 
   selection->shell        = shell;
+  selection->use_cairo    = g_getenv ("CAIRO_SELECTION") != NULL;
   selection->visible      = TRUE;
   selection->hidden       = ! gimp_display_shell_get_show_selection (shell);
   selection->layer_hidden = ! gimp_display_shell_get_show_layer (shell);
@@ -295,70 +298,105 @@ selection_resume (Selection *selection)
     selection_start (selection);
 }
 
+/* #define BENCHMARK 1 */
+
 static void
 selection_draw (Selection *selection)
 {
   GimpCanvas *canvas = GIMP_CANVAS (selection->shell->canvas);
+#ifdef BENCHMARK
+  GTimer     *timer  = g_timer_new ();
+  gint        test;
+
+  for (test = 0; test < 20; test++)
+    {
+#endif /* BENCHMARK */
+  if (selection->use_cairo)
+    {
+      if (selection->segs_in)
+        {
+          cairo_t *cr;
+
+          cr = gdk_cairo_create (gtk_widget_get_window (selection->shell->canvas));
+
+          gimp_display_shell_draw_selection_in (selection->shell, cr,
+                                                selection->segs_in,
+                                                selection->n_segs_in,
+                                                selection->index % 8);
 
+          cairo_destroy (cr);
+        }
+    }
+  else
+    {
 #ifdef USE_DRAWPOINTS
 
 #ifdef VERBOSE
-  {
-    gint j, sum;
+      {
+        gint j, sum;
 
-    sum = 0;
-    for (j = 0; j < 8; j++)
-      sum += selection->num_points_in[j];
+        sum = 0;
+        for (j = 0; j < 8; j++)
+          sum += selection->num_points_in[j];
 
-    g_print ("%d segments, %d points\n", selection->n_segs_in, sum);
-  }
+        g_print ("%d segments, %d points\n", selection->n_segs_in, sum);
+      }
 #endif
 
-  if (selection->segs_in)
-    {
-      gint i;
-
-      if (selection->index == 0)
+      if (selection->segs_in)
         {
-          for (i = 0; i < 4; i++)
-            if (selection->num_points_in[i])
-              gimp_canvas_draw_points (canvas, GIMP_CANVAS_STYLE_WHITE,
-                                       selection->points_in[i],
-                                       selection->num_points_in[i]);
-
-          for (i = 4; i < 8; i++)
-            if (selection->num_points_in[i])
-              gimp_canvas_draw_points (canvas, GIMP_CANVAS_STYLE_BLACK,
-                                       selection->points_in[i],
-                                       selection->num_points_in[i]);
-        }
-      else
-        {
-          i = ((selection->index + 3) & 7);
-          if (selection->num_points_in[i])
-            gimp_canvas_draw_points (canvas, GIMP_CANVAS_STYLE_WHITE,
-                                     selection->points_in[i],
-                                     selection->num_points_in[i]);
-
-          i = ((selection->index + 7) & 7);
-          if (selection->num_points_in[i])
-            gimp_canvas_draw_points (canvas, GIMP_CANVAS_STYLE_BLACK,
-                                     selection->points_in[i],
-                                     selection->num_points_in[i]);
+          gint i;
+
+          if (selection->index == 0)
+            {
+              for (i = 0; i < 4; i++)
+                if (selection->num_points_in[i])
+                  gimp_canvas_draw_points (canvas, GIMP_CANVAS_STYLE_WHITE,
+                                           selection->points_in[i],
+                                           selection->num_points_in[i]);
+
+              for (i = 4; i < 8; i++)
+                if (selection->num_points_in[i])
+                  gimp_canvas_draw_points (canvas, GIMP_CANVAS_STYLE_BLACK,
+                                           selection->points_in[i],
+                                           selection->num_points_in[i]);
+            }
+          else
+            {
+              i = ((selection->index + 3) & 7);
+              if (selection->num_points_in[i])
+                gimp_canvas_draw_points (canvas, GIMP_CANVAS_STYLE_WHITE,
+                                         selection->points_in[i],
+                                         selection->num_points_in[i]);
+
+              i = ((selection->index + 7) & 7);
+              if (selection->num_points_in[i])
+                gimp_canvas_draw_points (canvas, GIMP_CANVAS_STYLE_BLACK,
+                                         selection->points_in[i],
+                                         selection->num_points_in[i]);
+            }
         }
-    }
 
 #else  /*  ! USE_DRAWPOINTS  */
 
-  gimp_canvas_set_stipple_index (canvas,
-                                 GIMP_CANVAS_STYLE_SELECTION_IN,
-                                 selection->index);
-  if (selection->segs_in)
-    gimp_canvas_draw_segments (canvas, GIMP_CANVAS_STYLE_SELECTION_IN,
-                               selection->segs_in,
-                               selection->n_segs_in);
+      gimp_canvas_set_stipple_index (canvas,
+                                     GIMP_CANVAS_STYLE_SELECTION_IN,
+                                     selection->index);
+      if (selection->segs_in)
+        gimp_canvas_draw_segments (canvas, GIMP_CANVAS_STYLE_SELECTION_IN,
+                                   selection->segs_in,
+                                   selection->n_segs_in);
 
 #endif  /*  USE_DRAWPOINTS  */
+    }
+#ifdef BENCHMARK
+    }
+
+  g_printerr ("drawing 20 selections took %f seconds\n",
+              g_timer_elapsed (timer, NULL));
+
+  g_timer_destroy (timer);
+#endif /* BENCHMARK */
 }
 
 static void
@@ -739,10 +777,26 @@ selection_start_timeout (Selection *selection)
       selection_draw (selection);
 
       if (selection->segs_out)
-        gimp_canvas_draw_segments (canvas, GIMP_CANVAS_STYLE_SELECTION_OUT,
-                                   selection->segs_out,
-                                   selection->n_segs_out);
+        {
+          if (selection->use_cairo)
+            {
+              cairo_t *cr;
+
+              cr = gdk_cairo_create (gtk_widget_get_window (selection->shell->canvas));
 
+              gimp_display_shell_draw_selection_out (selection->shell, cr,
+                                                     selection->segs_out,
+                                                     selection->n_segs_out);
+
+              cairo_destroy (cr);
+            }
+          else
+            {
+              gimp_canvas_draw_segments (canvas, GIMP_CANVAS_STYLE_SELECTION_OUT,
+                                         selection->segs_out,
+                                         selection->n_segs_out);
+            }
+        }
 
       if (selection->segs_in && selection->visible)
         selection->timeout = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
diff --git a/app/display/gimpdisplayshell-style.c b/app/display/gimpdisplayshell-style.c
index 777f9b1..85366d1 100644
--- a/app/display/gimpdisplayshell-style.c
+++ b/app/display/gimpdisplayshell-style.c
@@ -20,6 +20,8 @@
 
 #include "config.h"
 
+#include <string.h>
+
 #include <gegl.h>
 #include <gtk/gtk.h>
 
@@ -53,12 +55,19 @@ static const GimpRGB layer_group_bg      = { 0.0, 1.0, 1.0, 1.0 };
 static const GimpRGB layer_mask_fg       = { 0.0, 0.0, 0.0, 1.0 };
 static const GimpRGB layer_mask_bg       = { 0.0, 1.0, 0.0, 1.0 };
 
+static const GimpRGB selection_out_fg    = { 1.0, 1.0, 1.0, 1.0 };
+static const GimpRGB selection_out_bg    = { 0.5, 0.5, 0.5, 1.0 };
+
+static const GimpRGB selection_in_fg     = { 0.0, 0.0, 0.0, 1.0 };
+static const GimpRGB selection_in_bg     = { 1.0, 1.0, 1.0, 1.0 };
+
 
 /*  local function prototypes  */
 
 static void   gimp_display_shell_set_stipple_style (cairo_t       *cr,
                                                     const GimpRGB *fg,
-                                                    const GimpRGB *bg);
+                                                    const GimpRGB *bg,
+                                                    gint           index);
 
 
 /*  public functions  */
@@ -76,11 +85,13 @@ gimp_display_shell_set_guide_style (GimpDisplayShell *shell,
   if (active)
     gimp_display_shell_set_stipple_style (cr,
                                           &guide_active_fg,
-                                          &guide_active_bg);
+                                          &guide_active_bg,
+                                          0);
   else
     gimp_display_shell_set_stipple_style (cr,
                                           &guide_normal_fg,
-                                          &guide_normal_bg);
+                                          &guide_normal_bg,
+                                          0);
 }
 
 void
@@ -124,7 +135,8 @@ gimp_display_shell_set_grid_style (GimpDisplayShell *shell,
         {
           gimp_display_shell_set_stipple_style (cr,
                                                 &grid->fgcolor,
-                                                &grid->bgcolor);
+                                                &grid->bgcolor,
+                                                0);
         }
       else
         {
@@ -132,7 +144,8 @@ gimp_display_shell_set_grid_style (GimpDisplayShell *shell,
 
           gimp_display_shell_set_stipple_style (cr,
                                                 &grid->fgcolor,
-                                                &bg);
+                                                &bg,
+                                                0);
         }
       break;
 
@@ -205,22 +218,56 @@ gimp_display_shell_set_layer_style (GimpDisplayShell *shell,
     {
       gimp_display_shell_set_stipple_style (cr,
                                             &layer_mask_fg,
-                                            &layer_mask_bg);
+                                            &layer_mask_bg,
+                                            0);
     }
   else if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
     {
       gimp_display_shell_set_stipple_style (cr,
                                             &layer_group_fg,
-                                            &layer_group_bg);
+                                            &layer_group_bg,
+                                            0);
     }
   else
     {
       gimp_display_shell_set_stipple_style (cr,
                                             &layer_fg,
-                                            &layer_bg);
+                                            &layer_bg,
+                                            0);
     }
 }
 
+void
+gimp_display_shell_set_selection_out_style (GimpDisplayShell *shell,
+                                            cairo_t          *cr)
+{
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+  g_return_if_fail (cr != NULL);
+
+  cairo_set_line_width (cr, 1.0);
+
+  gimp_display_shell_set_stipple_style (cr,
+                                        &selection_out_fg,
+                                        &selection_out_bg,
+                                        0);
+}
+
+void
+gimp_display_shell_set_selection_in_style (GimpDisplayShell *shell,
+                                           cairo_t          *cr,
+                                           gint              index)
+{
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+  g_return_if_fail (cr != NULL);
+
+  cairo_set_line_width (cr, 1.0);
+
+  gimp_display_shell_set_stipple_style (cr,
+                                        &selection_in_fg,
+                                        &selection_in_bg,
+                                        index);
+}
+
 
 /*  private functions  */
 
@@ -229,7 +276,8 @@ static cairo_user_data_key_t surface_data_key = { 0, };
 static void
 gimp_display_shell_set_stipple_style (cairo_t       *cr,
                                       const GimpRGB *fg,
-                                      const GimpRGB *bg)
+                                      const GimpRGB *bg,
+                                      gint           index)
 {
   cairo_surface_t *surface;
   guchar          *data = g_malloc0 (8 * 8 * 4);
@@ -247,7 +295,7 @@ gimp_display_shell_set_stipple_style (cairo_t       *cr,
     {
       for (x = 0; x < 8; x++)
         {
-          if ((y < 4 && x < 4) || (y >= 4 && x >= 4))
+          if ((x + y + index) % 8 >= 4)
             GIMP_CAIRO_ARGB32_SET_PIXEL (d, fg_r, fg_g, fg_b, fg_a);
           else
             GIMP_CAIRO_ARGB32_SET_PIXEL (d, bg_r, bg_g, bg_b, bg_a);
@@ -256,6 +304,16 @@ gimp_display_shell_set_stipple_style (cairo_t       *cr,
         }
     }
 
+  if (FALSE)//index > 0)
+    {
+      gint    move = index * 4;
+      guchar *buf  = g_alloca (8 * 8 * 4);
+
+      memcpy (buf, data, 8 * 8 * 4);
+      memcpy (data, buf + 8 * 8 * 4 - move, move);
+      memcpy (data + move, buf, 8 * 8 * 4 - move);
+    }
+
   surface = cairo_image_surface_create_for_data (data,
                                                  CAIRO_FORMAT_ARGB32,
                                                  8, 8, 8 * 4);
diff --git a/app/display/gimpdisplayshell-style.h b/app/display/gimpdisplayshell-style.h
index 2717da4..8be7eea 100644
--- a/app/display/gimpdisplayshell-style.h
+++ b/app/display/gimpdisplayshell-style.h
@@ -22,25 +22,30 @@
 #define __GIMP_DISPLAY_SHELL_STYLE_H__
 
 
-void   gimp_display_shell_set_guide_style        (GimpDisplayShell *shell,
-                                                  cairo_t          *cr,
-                                                  gboolean          active);
-void   gimp_display_shell_set_sample_point_style (GimpDisplayShell *shell,
-                                                  cairo_t          *cr,
-                                                  gboolean          active);
-void   gimp_display_shell_set_grid_style         (GimpDisplayShell *shell,
-                                                  cairo_t          *cr,
-                                                  GimpGrid         *grid);
-void   gimp_display_shell_set_cursor_style       (GimpDisplayShell *shell,
-                                                  cairo_t          *cr);
-void   gimp_display_shell_set_pen_style          (GimpDisplayShell *shell,
-                                                  cairo_t          *cr,
-                                                  GimpContext      *context,
-                                                  GimpActiveColor   active,
-                                                  gint              width);
-void   gimp_display_shell_set_layer_style        (GimpDisplayShell *shell,
-                                                  cairo_t          *cr,
-                                                  GimpDrawable     *drawable);
+void   gimp_display_shell_set_guide_style         (GimpDisplayShell *shell,
+                                                   cairo_t          *cr,
+                                                   gboolean          active);
+void   gimp_display_shell_set_sample_point_style  (GimpDisplayShell *shell,
+                                                   cairo_t          *cr,
+                                                   gboolean          active);
+void   gimp_display_shell_set_grid_style          (GimpDisplayShell *shell,
+                                                   cairo_t          *cr,
+                                                   GimpGrid         *grid);
+void   gimp_display_shell_set_cursor_style        (GimpDisplayShell *shell,
+                                                   cairo_t          *cr);
+void   gimp_display_shell_set_pen_style           (GimpDisplayShell *shell,
+                                                   cairo_t          *cr,
+                                                   GimpContext      *context,
+                                                   GimpActiveColor   active,
+                                                   gint              width);
+void   gimp_display_shell_set_layer_style         (GimpDisplayShell *shell,
+                                                   cairo_t          *cr,
+                                                   GimpDrawable     *drawable);
+void   gimp_display_shell_set_selection_out_style (GimpDisplayShell *shell,
+                                                   cairo_t          *cr);
+void   gimp_display_shell_set_selection_in_style  (GimpDisplayShell *shell,
+                                                   cairo_t          *cr,
+                                                   gint              index);
 
 
 #endif /* __GIMP_DISPLAY_SHELL_STYLE_H__ */



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