[gimp] app/display: let cairo render the checkerboard



commit ccee0ec41a37727115e73d919e0c2a34ffae8f20
Author: Sven Neumann <sven gimp org>
Date:   Tue Sep 28 21:10:03 2010 +0200

    app/display: let cairo render the checkerboard
    
    Instead of blending the scaled image data onto the checkerboard and
    then painting this image to the screen, render the image data into
    an ARGB cairo image surface. Then paint a checkerboard on the canvas
    and the image on top of it.

 app/display/gimpdisplayshell-callbacks.c |    8 ++
 app/display/gimpdisplayshell-draw.c      |   46 +++++++++++
 app/display/gimpdisplayshell-draw.h      |    6 ++
 app/display/gimpdisplayshell-handlers.c  |    6 ++
 app/display/gimpdisplayshell-render.c    |  123 ++++-------------------------
 app/display/gimpdisplayshell.c           |    8 ++-
 app/display/gimpdisplayshell.h           |    1 +
 7 files changed, 91 insertions(+), 107 deletions(-)
---
diff --git a/app/display/gimpdisplayshell-callbacks.c b/app/display/gimpdisplayshell-callbacks.c
index dbd1dc3..6192689 100644
--- a/app/display/gimpdisplayshell-callbacks.c
+++ b/app/display/gimpdisplayshell-callbacks.c
@@ -2285,6 +2285,14 @@ gimp_display_shell_canvas_expose_image (GimpDisplayShell *shell,
 
   if (! gdk_region_empty (image_region))
     {
+      cairo_save (cr);
+      gimp_display_shell_draw_checkerboard (shell, cr,
+                                            image_rect.x,
+                                            image_rect.y,
+                                            image_rect.width,
+                                            image_rect.height);
+      cairo_restore (cr);
+
       gdk_region_get_rectangles (image_region, &rects, &n_rects);
 
       cairo_save (cr);
diff --git a/app/display/gimpdisplayshell-draw.c b/app/display/gimpdisplayshell-draw.c
index 5c67580..8131898 100644
--- a/app/display/gimpdisplayshell-draw.c
+++ b/app/display/gimpdisplayshell-draw.c
@@ -21,6 +21,7 @@
 #include <gtk/gtk.h>
 
 #include "libgimpbase/gimpbase.h"
+#include "libgimpcolor/gimpcolor.h"
 #include "libgimpmath/gimpmath.h"
 #include "libgimpwidgets/gimpwidgets.h"
 
@@ -750,3 +751,48 @@ gimp_display_shell_draw_area (GimpDisplayShell *shell,
         }
     }
 }
+
+static cairo_pattern_t *
+gimp_display_shell_create_checkerboard (GimpDisplayShell *shell,
+                                        cairo_t          *cr)
+{
+  GimpCheckSize  check_size;
+  GimpCheckType  check_type;
+  guchar         check_light;
+  guchar         check_dark;
+  GimpRGB        light;
+  GimpRGB        dark;
+
+  g_object_get (shell->display->config,
+                "transparency-size", &check_size,
+                "transparency-type", &check_type,
+                NULL);
+
+  gimp_checks_get_shades (check_type, &check_light, &check_dark);
+  gimp_rgb_set_uchar (&light, check_light, check_light, check_light);
+  gimp_rgb_set_uchar (&dark,  check_dark,  check_dark,  check_dark);
+
+  return gimp_cairo_checkerboard_create (cr,
+                                         1 << (check_size + 2), &light, &dark);
+}
+
+void
+gimp_display_shell_draw_checkerboard (GimpDisplayShell *shell,
+                                      cairo_t          *cr,
+                                      gint              x,
+                                      gint              y,
+                                      gint              w,
+                                      gint              h)
+{
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+  g_return_if_fail (cr != NULL);
+
+  if (G_UNLIKELY (! shell->checkerboard))
+    shell->checkerboard = gimp_display_shell_create_checkerboard (shell, cr);
+
+  cairo_rectangle (cr, x, y, w, h);
+  cairo_clip (cr);
+  cairo_translate (cr, - shell->offset_x, - shell->offset_y);
+  cairo_set_source (cr, shell->checkerboard);
+  cairo_paint (cr);
+}
diff --git a/app/display/gimpdisplayshell-draw.h b/app/display/gimpdisplayshell-draw.h
index 0baff69..8561458 100644
--- a/app/display/gimpdisplayshell-draw.h
+++ b/app/display/gimpdisplayshell-draw.h
@@ -71,6 +71,12 @@ void   gimp_display_shell_draw_area                  (GimpDisplayShell   *shell,
                                                       gint                y,
                                                       gint                w,
                                                       gint                h);
+void   gimp_display_shell_draw_checkerboard          (GimpDisplayShell   *shell,
+                                                      cairo_t            *cr,
+                                                      gint                x,
+                                                      gint                y,
+                                                      gint                w,
+                                                      gint                h);
 
 
 #endif /* __GIMP_DISPLAY_SHELL_DRAW_H__ */
diff --git a/app/display/gimpdisplayshell-handlers.c b/app/display/gimpdisplayshell-handlers.c
index f080b74..ff65d8b 100644
--- a/app/display/gimpdisplayshell-handlers.c
+++ b/app/display/gimpdisplayshell-handlers.c
@@ -592,6 +592,12 @@ gimp_display_shell_check_notify_handler (GObject          *config,
   GimpCanvasPaddingMode padding_mode;
   GimpRGB               padding_color;
 
+  if (shell->checkerboard)
+    {
+      cairo_pattern_destroy (shell->checkerboard);
+      shell->checkerboard = NULL;
+    }
+
   gimp_display_shell_get_padding (shell, &padding_mode, &padding_color);
 
   switch (padding_mode)
diff --git a/app/display/gimpdisplayshell-render.c b/app/display/gimpdisplayshell-render.c
index b229ed0..26c8d66 100644
--- a/app/display/gimpdisplayshell-render.c
+++ b/app/display/gimpdisplayshell-render.c
@@ -74,7 +74,6 @@ struct _RenderInfo
   gdouble           scaley;
   gint              src_x;
   gint              src_y;
-  gint              dest_bpp;
   gint              dest_bpl;
 
   gint              zoom_quality;
@@ -102,17 +101,7 @@ static void  gimp_display_shell_render_info_scale   (RenderInfo       *info,
                                                      gint              level,
                                                      gboolean          is_premult);
 
-static void  gimp_display_shell_render_setup_notify (GObject          *config,
-                                                     GParamSpec       *param_spec,
-                                                     Gimp             *gimp);
-
-
-static guchar *tile_buf    = NULL;
-
-static guint   check_mod   = 0;
-static guint   check_shift = 0;
-static guchar  check_dark  = 0;
-static guchar  check_light = 0;
+static guchar *tile_buf = NULL;
 
 
 void
@@ -121,17 +110,8 @@ gimp_display_shell_render_init (Gimp *gimp)
   g_return_if_fail (GIMP_IS_GIMP (gimp));
   g_return_if_fail (tile_buf == NULL);
 
-  g_signal_connect (gimp->config, "notify::transparency-size",
-                    G_CALLBACK (gimp_display_shell_render_setup_notify),
-                    gimp);
-  g_signal_connect (gimp->config, "notify::transparency-type",
-                    G_CALLBACK (gimp_display_shell_render_setup_notify),
-                    gimp);
-
   /*  allocate a buffer for arranging information from a row of tiles  */
   tile_buf = g_new (guchar, GIMP_DISPLAY_RENDER_BUF_WIDTH * MAX_CHANNELS);
-
-  gimp_display_shell_render_setup_notify (G_OBJECT (gimp->config), NULL, gimp);
 }
 
 void
@@ -139,10 +119,6 @@ gimp_display_shell_render_exit (Gimp *gimp)
 {
   g_return_if_fail (GIMP_IS_GIMP (gimp));
 
-  g_signal_handlers_disconnect_by_func (gimp->config,
-                                        gimp_display_shell_render_setup_notify,
-                                        gimp);
-
   if (tile_buf)
     {
       g_free (tile_buf);
@@ -150,40 +126,6 @@ gimp_display_shell_render_exit (Gimp *gimp)
     }
 }
 
-static void
-gimp_display_shell_render_setup_notify (GObject    *config,
-                                        GParamSpec *param_spec,
-                                        Gimp       *gimp)
-{
-  GimpCheckSize check_size;
-  GimpCheckType check_type;
-
-  g_object_get (config,
-                "transparency-size", &check_size,
-                "transparency-type", &check_type,
-                NULL);
-
-  gimp_checks_get_shades (check_type, &check_light, &check_dark);
-
-  switch (check_size)
-    {
-    case GIMP_CHECK_SIZE_SMALL_CHECKS:
-      check_mod   = 0x3;
-      check_shift = 2;
-      break;
-
-    case GIMP_CHECK_SIZE_MEDIUM_CHECKS:
-      check_mod   = 0x7;
-      check_shift = 3;
-      break;
-
-    case GIMP_CHECK_SIZE_LARGE_CHECKS:
-      check_mod   = 0xf;
-      check_shift = 4;
-      break;
-    }
-}
-
 
 /*  Render Image functions  */
 
@@ -248,7 +190,6 @@ gimp_display_shell_render (GimpDisplayShell   *shell,
   info.w        = w;
   info.h        = h;
 
-  info.dest_bpp = 4;
   info.dest_bpl = cairo_image_surface_get_stride (shell->render_surface);
 
   switch (shell->display->config->zoom_quality)
@@ -303,6 +244,7 @@ gimp_display_shell_render (GimpDisplayShell   *shell,
                                       3 * GIMP_DISPLAY_RENDER_BUF_WIDTH);
 #endif
 
+#if 0
   /*  dim pixels outside the highlighted rectangle  */
   if (highlight)
     {
@@ -317,6 +259,7 @@ gimp_display_shell_render (GimpDisplayShell   *shell,
 
       gimp_display_shell_render_mask (shell, &info);
     }
+#endif
 
   cairo_surface_mark_dirty (shell->render_surface);
 
@@ -325,11 +268,11 @@ gimp_display_shell_render (GimpDisplayShell   *shell,
     gint disp_xoffset, disp_yoffset;
 
     gimp_display_shell_scroll_get_disp_offset (shell,
-					       &disp_xoffset, &disp_yoffset);
+                                               &disp_xoffset, &disp_yoffset);
 
+    cairo_rectangle (cr, x + disp_xoffset, y + disp_yoffset, w, h);
     cairo_set_source_surface (cr, shell->render_surface,
                               x + disp_xoffset, y + disp_yoffset);
-    cairo_rectangle (cr, x + disp_xoffset, y + disp_yoffset, w, h);
     cairo_fill (cr);
   }
 }
@@ -437,12 +380,12 @@ gimp_display_shell_render_mask (GimpDisplayShell *shell,
   while (TRUE)
     {
       const guchar *src  = info->src;
-      guchar       *dest = info->dest;
+      guint32      *dest = (guint32 *) info->dest;
 
       switch (shell->mask_color)
         {
         case GIMP_RED_CHANNEL:
-          for (x = info->x; x < xe; x++, src++, dest += info->dest_bpp)
+          for (x = info->x; x < xe; x++, src++, dest += 4)
             {
               if (*src & 0x80)
                 continue;
@@ -453,7 +396,7 @@ gimp_display_shell_render_mask (GimpDisplayShell *shell,
           break;
 
         case GIMP_GREEN_CHANNEL:
-          for (x = info->x; x < xe; x++, src++, dest += info->dest_bpp)
+          for (x = info->x; x < xe; x++, src++, dest += 4)
             {
               if (*src & 0x80)
                 continue;
@@ -464,7 +407,7 @@ gimp_display_shell_render_mask (GimpDisplayShell *shell,
           break;
 
         case GIMP_BLUE_CHANNEL:
-          for (x = info->x; x < xe; x++, src++, dest += info->dest_bpp)
+          for (x = info->x; x < xe; x++, src++, dest += 4)
             {
               if (*src & 0x80)
                 continue;
@@ -512,24 +455,12 @@ render_image_gray_a (RenderInfo *info)
   while (TRUE)
     {
       const guchar *src  = info->src;
-      guchar       *dest = info->dest;
-      guint         dark_light;
+      guint32      *dest = (guint32 *) info->dest;
 
-      dark_light = (y >> check_shift) + (info->x >> check_shift);
-
-      for (x = info->x; x < xe; x++, src += 2, dest += info->dest_bpp)
+      for (x = info->x; x < xe; x++, src += 2, dest++)
         {
-          guint v;
-
-          if (dark_light & 0x1)
-            v = ((src[0] << 8) + check_dark  * (256 - src[1])) >> 8;
-          else
-            v = ((src[0] << 8) + check_light * (256 - src[1])) >> 8;
-
-          GIMP_CAIRO_RGB24_SET_PIXEL (dest, v, v, v);
-
-          if (((x + 1) & check_mod) == 0)
-            dark_light += 1;
+          /*  data in src is premultiplied already  */
+          *dest = (src[1] << 24) | (src[0] << 16) | (src[0] << 8) | src[0];
         }
 
       if (++y == ye)
@@ -561,32 +492,12 @@ render_image_rgb_a (RenderInfo *info)
   while (TRUE)
     {
       const guchar *src  = info->src;
-      guchar       *dest = info->dest;
-      guint         dark_light;
+      guint32      *dest = (guint32 *) info->dest;
 
-      dark_light = (y >> check_shift) + (info->x >> check_shift);
-
-      for (x = info->x; x < xe; x++, src += 4, dest += info->dest_bpp)
+      for (x = info->x; x < xe; x++, src += 4, dest++)
         {
-          guint r, g, b;
-
-          if (dark_light & 0x1)
-            {
-              r = ((src[0] << 8) + check_dark  * (256 - src[3])) >> 8;
-              g = ((src[1] << 8) + check_dark  * (256 - src[3])) >> 8;
-              b = ((src[2] << 8) + check_dark  * (256 - src[3])) >> 8;
-            }
-          else
-            {
-              r = ((src[0] << 8) + check_light * (256 - src[3])) >> 8;
-              g = ((src[1] << 8) + check_light * (256 - src[3])) >> 8;
-              b = ((src[2] << 8) + check_light * (256 - src[3])) >> 8;
-            }
-
-          GIMP_CAIRO_RGB24_SET_PIXEL (dest, r, g, b);
-
-          if (((x + 1) & check_mod) == 0)
-            dark_light += 1;
+          /*  data in src is premultiplied already  */
+          *dest = (src[3] << 24) | (src[0] << 16) | (src[1] << 8) | src[2];
         }
 
       if (++y == ye)
diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c
index 8b283dc..0ceeb7f 100644
--- a/app/display/gimpdisplayshell.c
+++ b/app/display/gimpdisplayshell.c
@@ -286,7 +286,7 @@ gimp_display_shell_init (GimpDisplayShell *shell)
   shell->x_src_dec   = 1;
   shell->y_src_dec   = 1;
 
-  shell->render_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+  shell->render_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                                       GIMP_DISPLAY_RENDER_BUF_WIDTH,
                                                       GIMP_DISPLAY_RENDER_BUF_HEIGHT);
 
@@ -769,6 +769,12 @@ gimp_display_shell_dispose (GObject *object)
       shell->render_surface = NULL;
     }
 
+  if (shell->checkerboard)
+    {
+      cairo_pattern_destroy (shell->checkerboard);
+      shell->checkerboard = NULL;
+    }
+
   if (shell->highlight)
     {
       g_slice_free (GdkRectangle, shell->highlight);
diff --git a/app/display/gimpdisplayshell.h b/app/display/gimpdisplayshell.h
index 3b3d313..e990352 100644
--- a/app/display/gimpdisplayshell.h
+++ b/app/display/gimpdisplayshell.h
@@ -132,6 +132,7 @@ struct _GimpDisplayShell
   GtkWidget         *statusbar;        /*  statusbar                          */
 
   cairo_surface_t   *render_surface;   /*  buffer for rendering the image     */
+  cairo_pattern_t   *checkerboard;     /*  checkerboard pattern               */
 
   guint              title_idle_id;    /*  title update idle ID               */
   gchar             *title;            /*  current title                      */



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