[gimp/goat-invasion: 476/608] app: port preview rendering to GEGL/cairo



commit 43499119761aaa3e8c56ea5ed8816bfc3b381a07
Author: Michael Natterer <mitch gimp org>
Date:   Tue Apr 10 14:08:44 2012 +0200

    app: port preview rendering to GEGL/cairo
    
    which gets rid of the render blend arrays in gimprender.[ch], and of
    image preview demultiplication.

 app/core/gimpimage-preview.c   |   48 +------
 app/widgets/gimprender.c       |  103 -------------
 app/widgets/gimprender.h       |   11 --
 app/widgets/gimpviewrenderer.c |  314 ++++++++++++++++++++--------------------
 4 files changed, 164 insertions(+), 312 deletions(-)
---
diff --git a/app/core/gimpimage-preview.c b/app/core/gimpimage-preview.c
index 12c02f6..f28e041 100644
--- a/app/core/gimpimage-preview.c
+++ b/app/core/gimpimage-preview.c
@@ -143,51 +143,15 @@ gimp_image_get_new_preview (GimpViewable *viewable,
 
   buf = tile_manager_get_preview (tiles, width, height);
 
-  /* FIXME: We could avoid this if the view renderer and all other
-   *        preview code would know how to deal with pre-multiply alpha.
-   */
   if (is_premult)
     {
-      guchar *data;
-      gint    pixels;
-
-      g_return_if_fail (buf != NULL);
-
-      switch (babl_format_get_bytes_per_pixel (buf->format))
+      if (buf->format == babl_format ("Y'A u8"))
+        {
+          buf->format = babl_format ("Y'aA u8");
+        }
+      else if (buf->format == babl_format ("R'G'B'A u8"))
         {
-        case 1:
-          break;
-
-        case 2:
-          data = gimp_temp_buf_get_data (buf);
-          pixels = buf->width * buf->height;
-          while (pixels--)
-            {
-              data[0] = (data[0] << 8) / (data[1] + 1);
-
-              data += 2;
-            }
-          break;
-
-        case 3:
-          break;
-
-        case 4:
-          data = gimp_temp_buf_get_data (buf);
-          pixels = buf->width * buf->height;
-          while (pixels--)
-            {
-              data[0] = (data[0] << 8) / (data[3] + 1);
-              data[1] = (data[1] << 8) / (data[3] + 1);
-              data[2] = (data[2] << 8) / (data[3] + 1);
-
-              data += 4;
-            }
-          break;
-
-        default:
-          g_warn_if_reached ();
-          break;
+          buf->format = babl_format ("R'aG'aB'aA u8");
         }
     }
 
diff --git a/app/widgets/gimprender.c b/app/widgets/gimprender.c
index 587c6a1..691a325 100644
--- a/app/widgets/gimprender.c
+++ b/app/widgets/gimprender.c
@@ -28,7 +28,6 @@
 #include "widgets-types.h"
 
 #include "core/gimp.h"
-#include "core/gimpviewable.h"
 
 #include "gimprender.h"
 
@@ -38,17 +37,6 @@ static void   gimp_render_setup_notify (gpointer    config,
                                         Gimp       *gimp);
 
 
-/*  accelerate blending on the checkerboard  */
-
-guchar *gimp_render_check_buf         = NULL;
-guchar *gimp_render_empty_buf         = NULL;
-guchar *gimp_render_white_buf         = NULL;
-
-guchar *gimp_render_blend_dark_check  = NULL;
-guchar *gimp_render_blend_light_check = NULL;
-guchar *gimp_render_blend_white       = NULL;
-
-
 static GimpRGB light;
 static GimpRGB dark;
 
@@ -73,42 +61,6 @@ gimp_render_exit (Gimp *gimp)
   g_signal_handlers_disconnect_by_func (gimp->config,
                                         gimp_render_setup_notify,
                                         gimp);
-
-  if (gimp_render_blend_dark_check)
-    {
-      g_free (gimp_render_blend_dark_check);
-      gimp_render_blend_dark_check = NULL;
-    }
-
-  if (gimp_render_blend_light_check)
-    {
-      g_free (gimp_render_blend_light_check);
-      gimp_render_blend_light_check = NULL;
-    }
-
-  if (gimp_render_blend_white)
-    {
-      g_free (gimp_render_blend_white);
-      gimp_render_blend_white = NULL;
-    }
-
-  if (gimp_render_check_buf)
-    {
-      g_free (gimp_render_check_buf);
-      gimp_render_check_buf = NULL;
-    }
-
-  if (gimp_render_empty_buf)
-    {
-      g_free (gimp_render_empty_buf);
-      gimp_render_empty_buf = NULL;
-    }
-
-  if (gimp_render_white_buf)
-    {
-      g_free (gimp_render_white_buf);
-      gimp_render_white_buf = NULL;
-    }
 }
 
 const GimpRGB *
@@ -131,7 +83,6 @@ gimp_render_setup_notify (gpointer    config,
   GimpCheckType check_type;
   guchar        dark_check;
   guchar        light_check;
-  gint          i, j;
 
   g_object_get (config,
                 "transparency-type", &check_type,
@@ -141,58 +92,4 @@ gimp_render_setup_notify (gpointer    config,
 
   gimp_rgba_set_uchar (&light, light_check, light_check, light_check, 255);
   gimp_rgba_set_uchar (&dark,  dark_check,  dark_check,  dark_check,  255);
-
-  if (! gimp_render_blend_dark_check)
-    gimp_render_blend_dark_check = g_new (guchar, 65536);
-
-  if (! gimp_render_blend_light_check)
-    gimp_render_blend_light_check = g_new (guchar, 65536);
-
-  if (! gimp_render_blend_white)
-    gimp_render_blend_white = g_new (guchar, 65536);
-
-  for (i = 0; i < 256; i++)
-    for (j = 0; j < 256; j++)
-      {
-        gimp_render_blend_dark_check [(i << 8) + j] =
-          (guchar) ((j * i + dark_check * (255 - i)) / 255);
-
-        gimp_render_blend_light_check [(i << 8) + j] =
-          (guchar) ((j * i + light_check * (255 - i)) / 255);
-
-        gimp_render_blend_white [(i << 8) + j] =
-          (guchar) ((j * i + 255 * (255 - i)) / 255);
-      }
-
-  g_free (gimp_render_check_buf);
-  g_free (gimp_render_empty_buf);
-  g_free (gimp_render_white_buf);
-
-#define BUF_SIZE (GIMP_VIEWABLE_MAX_PREVIEW_SIZE + 4)
-
-  gimp_render_check_buf = g_new  (guchar, BUF_SIZE * 3);
-  gimp_render_empty_buf = g_new0 (guchar, BUF_SIZE * 3);
-  gimp_render_white_buf = g_new  (guchar, BUF_SIZE * 3);
-
-  /*  calculate check buffer for previews  */
-
-  memset (gimp_render_white_buf, 255, BUF_SIZE * 3);
-
-  for (i = 0; i < BUF_SIZE; i++)
-    {
-      if (i & 0x4)
-        {
-          gimp_render_check_buf[i * 3 + 0] = dark_check;
-          gimp_render_check_buf[i * 3 + 1] = dark_check;
-          gimp_render_check_buf[i * 3 + 2] = dark_check;
-        }
-      else
-        {
-          gimp_render_check_buf[i * 3 + 0] = light_check;
-          gimp_render_check_buf[i * 3 + 1] = light_check;
-          gimp_render_check_buf[i * 3 + 2] = light_check;
-        }
-    }
-
-#undef BUF_SIZE
 }
diff --git a/app/widgets/gimprender.h b/app/widgets/gimprender.h
index 22ae0af..bbf8226 100644
--- a/app/widgets/gimprender.h
+++ b/app/widgets/gimprender.h
@@ -19,17 +19,6 @@
 #define __GIMP_RENDER_H__
 
 
-/* buffers that contain pre-rendered patterns/colors */
-extern guchar *gimp_render_check_buf;
-extern guchar *gimp_render_empty_buf;
-extern guchar *gimp_render_white_buf;
-
-/* lookup tables for blending over a checkerboard */
-extern guchar *gimp_render_blend_dark_check;
-extern guchar *gimp_render_blend_light_check;
-extern guchar *gimp_render_blend_white;
-
-
 void            gimp_render_init              (Gimp *gimp);
 void            gimp_render_exit              (Gimp *gimp);
 
diff --git a/app/widgets/gimpviewrenderer.c b/app/widgets/gimpviewrenderer.c
index eaae393..f989bc4 100644
--- a/app/widgets/gimpviewrenderer.c
+++ b/app/widgets/gimpviewrenderer.c
@@ -33,6 +33,7 @@
 
 #include "widgets-types.h"
 
+#include "core/gimp-cairo.h"
 #include "core/gimpcontext.h"
 #include "core/gimpmarshal.h"
 #include "core/gimptempbuf.h"
@@ -73,7 +74,8 @@ static cairo_pattern_t *
                  gimp_view_renderer_create_background (GimpViewRenderer   *renderer,
                                                        GtkWidget          *widget);
 
-static void      gimp_view_render_temp_buf_to_surface (GimpTempBuf        *temp_buf,
+static void      gimp_view_render_temp_buf_to_surface (GimpViewRenderer   *renderer,
+                                                       GimpTempBuf        *temp_buf,
                                                        gint                channel,
                                                        GimpViewBG          inside_bg,
                                                        GimpViewBG          outside_bg,
@@ -695,8 +697,10 @@ gimp_view_renderer_real_draw (GimpViewRenderer *renderer,
       if (renderer->bg_stock_id)
         {
           if (! renderer->pattern)
-            renderer->pattern = gimp_view_renderer_create_background (renderer,
-                                                                      widget);
+            {
+              renderer->pattern = gimp_view_renderer_create_background (renderer,
+                                                                        widget);
+            }
 
           cairo_set_source (cr, renderer->pattern);
           cairo_paint (cr);
@@ -724,12 +728,10 @@ gimp_view_renderer_real_draw (GimpViewRenderer *renderer,
       if (content == CAIRO_CONTENT_COLOR_ALPHA)
         {
           if (! renderer->pattern)
-            {
-              renderer->pattern =
-                gimp_cairo_checkerboard_create (cr, GIMP_CHECK_SIZE_SM,
-                                                gimp_render_light_check_color (),
-                                                gimp_render_dark_check_color ());
-            }
+            renderer->pattern =
+              gimp_cairo_checkerboard_create (cr, GIMP_CHECK_SIZE_SM,
+                                              gimp_render_light_check_color (),
+                                              gimp_render_dark_check_color ());
 
           cairo_set_source (cr, renderer->pattern);
           cairo_fill_preserve (cr);
@@ -824,7 +826,8 @@ gimp_view_renderer_render_temp_buf (GimpViewRenderer *renderer,
                                                     renderer->width,
                                                     renderer->height);
 
-  gimp_view_render_temp_buf_to_surface (temp_buf,
+  gimp_view_render_temp_buf_to_surface (renderer,
+                                        temp_buf,
                                         channel,
                                         inside_bg,
                                         outside_bg,
@@ -916,47 +919,22 @@ gimp_view_renderer_render_stock (GimpViewRenderer *renderer,
 }
 
 static void
-gimp_view_render_temp_buf_to_surface (GimpTempBuf     *temp_buf,
-                                      gint             channel,
-                                      GimpViewBG       inside_bg,
-                                      GimpViewBG       outside_bg,
-                                      cairo_surface_t *surface,
-                                      gint             dest_width,
-                                      gint             dest_height)
+gimp_view_render_temp_buf_to_surface (GimpViewRenderer *renderer,
+                                      GimpTempBuf      *temp_buf,
+                                      gint              channel,
+                                      GimpViewBG        inside_bg,
+                                      GimpViewBG        outside_bg,
+                                      cairo_surface_t  *surface,
+                                      gint              surface_width,
+                                      gint              surface_height)
 {
-  const guchar *src;
-  const guchar *pad_buf;
-  guchar       *dest;
-  gint          i, j;
-  gint          x1, y1;
-  gint          x2, y2;
-  gint          bytes;
-  gint          rowstride;
-  gint          dest_stride;
-  gboolean      color;
-  gboolean      has_alpha;
-  gboolean      render_composite;
-  gint          red_component;
-  gint          green_component;
-  gint          blue_component;
-  gint          alpha_component;
+  cairo_t *cr;
+  gint     x, y;
+  gint     width, height;
 
   g_return_if_fail (temp_buf != NULL);
   g_return_if_fail (surface != NULL);
 
-  /* In rare cases we can get here while GIMP is exiting, handle that
-   * by checking for availability of the buffers
-   */
-  if (! gimp_render_check_buf ||
-      ! gimp_render_empty_buf ||
-      ! gimp_render_white_buf)
-    return;
-
-  cairo_surface_flush (surface);
-
-  dest        = cairo_image_surface_get_data (surface);
-  dest_stride = cairo_image_surface_get_stride (surface);
-
   /*  Here are the different cases this functions handles correctly:
    *  1)  Offset temp_buf which does not necessarily cover full image area
    *  2)  Color conversion of temp_buf if it is gray and image is color
@@ -969,146 +947,170 @@ gimp_view_render_temp_buf_to_surface (GimpTempBuf     *temp_buf,
    *  3)  If image is gray, then temp_buf should have bytes == {1, 2}
    */
 
-  bytes            = babl_format_get_bytes_per_pixel (temp_buf->format);
-  color            = (bytes == 3 || bytes == 4);
-  has_alpha        = babl_format_has_alpha (temp_buf->format);
-  render_composite = (channel == -1);
-  rowstride        = temp_buf->width * bytes;
+  cr = cairo_create (surface);
 
-  /*  render the checkerboard only if the temp_buf has alpha *and*
-   *  we render a composite view
-   */
-  if (has_alpha && render_composite && outside_bg == GIMP_VIEW_BG_CHECKS)
-    pad_buf = gimp_render_check_buf;
-  else if (outside_bg == GIMP_VIEW_BG_WHITE)
-    pad_buf = gimp_render_white_buf;
-  else
-    pad_buf = gimp_render_empty_buf;
+  if (outside_bg == GIMP_VIEW_BG_CHECKS ||
+      inside_bg  == GIMP_VIEW_BG_CHECKS)
+    {
+      if (! renderer->pattern)
+        renderer->pattern =
+          gimp_cairo_checkerboard_create (cr, GIMP_CHECK_SIZE_SM,
+                                          gimp_render_light_check_color (),
+                                          gimp_render_dark_check_color ());
+    }
 
-  if (render_composite)
+  switch (outside_bg)
     {
-      if (color)
-        {
-          red_component   = RED;
-          green_component = GREEN;
-          blue_component  = BLUE;
-          alpha_component = ALPHA;
-        }
-      else
+    case GIMP_VIEW_BG_CHECKS:
+      cairo_set_source (cr, renderer->pattern);
+      break;
+
+    case GIMP_VIEW_BG_WHITE:
+      cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+      break;
+    }
+
+  cairo_paint (cr);
+
+  if (! gimp_rectangle_intersect (0, 0,
+                                  surface_width, surface_height,
+                                  temp_buf->x, temp_buf->y,
+                                  temp_buf->width, temp_buf->height,
+                                  &x, &y,
+                                  &width, &height))
+    {
+      cairo_destroy (cr);
+      return;
+    }
+
+  if (inside_bg != outside_bg &&
+      babl_format_has_alpha (temp_buf->format) && channel == -1)
+    {
+      cairo_rectangle (cr, x, y, width, height);
+
+      switch (inside_bg)
         {
-          red_component   = GRAY;
-          green_component = GRAY;
-          blue_component  = GRAY;
-          alpha_component = ALPHA_G;
+        case GIMP_VIEW_BG_CHECKS:
+          cairo_set_source (cr, renderer->pattern);
+          break;
+
+        case GIMP_VIEW_BG_WHITE:
+          cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+          break;
         }
+
+      cairo_fill (cr);
     }
-  else
+
+  if (babl_format_has_alpha (temp_buf->format) && channel == -1)
     {
-      red_component   = channel;
-      green_component = channel;
-      blue_component  = channel;
-      alpha_component = 0;
+      GeglBuffer      *src_buffer;
+      GeglBuffer      *dest_buffer;
+      cairo_surface_t *alpha_surface;
+
+      alpha_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+                                                  width, height);
+
+      src_buffer  = gimp_temp_buf_create_buffer (temp_buf);
+      dest_buffer = gimp_cairo_image_surface_create_buffer (alpha_surface);
+
+      gegl_buffer_copy (src_buffer,
+                        GEGL_RECTANGLE (x - temp_buf->x,
+                                        y - temp_buf->y,
+                                        width, height),
+                        dest_buffer,
+                        GEGL_RECTANGLE (0, 0, 0, 0));
+
+      g_object_unref (src_buffer);
+      g_object_unref (dest_buffer);
+
+      cairo_surface_mark_dirty (alpha_surface);
+
+      cairo_translate (cr, x, y);
+      cairo_rectangle (cr, 0, 0, width, height);
+      cairo_set_source_surface (cr, alpha_surface, 0, 0);
+      cairo_fill (cr);
+
+      cairo_surface_destroy (alpha_surface);
     }
+  else if (channel == -1)
+    {
+      GeglBuffer *src_buffer;
+      GeglBuffer *dest_buffer;
 
-  x1 = CLAMP (temp_buf->x, 0, dest_width);
-  y1 = CLAMP (temp_buf->y, 0, dest_height);
-  x2 = CLAMP (temp_buf->x + temp_buf->width,  0, dest_width);
-  y2 = CLAMP (temp_buf->y + temp_buf->height, 0, dest_height);
+      cairo_surface_flush (surface);
 
-  src = gimp_temp_buf_get_data (temp_buf) + ((y1 - temp_buf->y) * rowstride +
-                                             (x1 - temp_buf->x) * bytes);
+      src_buffer  = gimp_temp_buf_create_buffer (temp_buf);
+      dest_buffer = gimp_cairo_image_surface_create_buffer (surface);
 
-  for (i = 0; i < dest_height; i++)
+      gegl_buffer_copy (src_buffer,
+                        GEGL_RECTANGLE (x - temp_buf->x,
+                                        y - temp_buf->y,
+                                        width, height),
+                        dest_buffer,
+                        GEGL_RECTANGLE (x, y, 0, 0));
+
+      g_object_unref (src_buffer);
+      g_object_unref (dest_buffer);
+
+      cairo_surface_mark_dirty (surface);
+    }
+  else
     {
-      guchar       *d = dest;
-      const guchar *cb;
-      gint          offset;
+      const Babl   *fish;
+      const guchar *src;
+      guchar       *dest;
+      gint          dest_stride;
+      gint          bytes;
+      gint          rowstride;
+      gint          i;
 
-      if (i & 0x4)
-        {
-          offset = 4;
-          cb = pad_buf + offset * 3;
-        }
-      else
-        {
-          offset = 0;
-          cb = pad_buf;
-        }
+      cairo_surface_flush (surface);
 
-      /*  The interesting stuff between leading & trailing
-       *  vertical transparency
-       */
-      if (i >= y1 && i < y2)
+      bytes     = babl_format_get_bytes_per_pixel (temp_buf->format);
+      rowstride = temp_buf->width * bytes;
+
+      src = gimp_temp_buf_get_data (temp_buf) + ((y - temp_buf->y) * rowstride +
+                                                 (x - temp_buf->x) * bytes);
+
+      dest        = cairo_image_surface_get_data (surface);
+      dest_stride = cairo_image_surface_get_stride (surface);
+
+      dest += y * dest_stride + x * 4;
+
+      fish = babl_fish (temp_buf->format,
+                        babl_format ("cairo-RGB24"));
+
+      for (i = y; i < (y + height); i++)
         {
           const guchar *s = src;
+          guchar       *d = dest;
+          gint          j;
 
-          /*  Handle the leading transparency  */
-          for (j = 0; j < x1; j++, d += 4, cb += 3)
+          for (j = x; j < (x + width); j++, d += 4, s += bytes)
             {
-              GIMP_CAIRO_RGB24_SET_PIXEL (d, cb[0], cb[1], cb[2]);
-            }
-
-          /*  The stuff in the middle  */
-          for (j = x1; j < x2; j++, d += 4, s += bytes)
-            {
-              if (has_alpha && render_composite)
+              if (bytes > 2)
                 {
-                  const guint a = s[alpha_component] << 8;
-
-                  if (inside_bg == GIMP_VIEW_BG_CHECKS)
-                    {
-                      if ((j + offset) & 0x4)
-                        {
-                          GIMP_CAIRO_RGB24_SET_PIXEL (d,
-                                                      gimp_render_blend_dark_check [a | s[red_component]],
-                                                      gimp_render_blend_dark_check [a | s[green_component]],
-                                                      gimp_render_blend_dark_check [a | s[blue_component]]);
-                        }
-                      else
-                        {
-                          GIMP_CAIRO_RGB24_SET_PIXEL (d,
-                                                      gimp_render_blend_light_check [a | s[red_component]],
-                                                      gimp_render_blend_light_check [a | s[green_component]],
-                                                      gimp_render_blend_light_check [a | s[blue_component]]);
-                        }
-                    }
-                  else /* GIMP_VIEW_BG_WHITE */
-                    {
-                      GIMP_CAIRO_RGB24_SET_PIXEL (d,
-                                                  gimp_render_blend_white [a | s[red_component]],
-                                                  gimp_render_blend_white [a | s[green_component]],
-                                                  gimp_render_blend_white [a | s[blue_component]]);
-                    }
+                  guchar pixel[4] = { s[channel], s[channel], s[channel], 255 };
+
+                  babl_process (fish, pixel, d, 1);
                 }
               else
                 {
-                  GIMP_CAIRO_RGB24_SET_PIXEL (d,
-                                              s[red_component],
-                                              s[green_component],
-                                              s[blue_component]);
-                }
-            }
+                  guchar pixel[2] = { s[channel], 255 };
 
-          /*  Handle the trailing transparency  */
-          for (j = x2; j < dest_width; j++, d+= 4, cb += 3)
-            {
-              GIMP_CAIRO_RGB24_SET_PIXEL (d, cb[0], cb[1], cb[2]);
+                  babl_process (fish, pixel, d, 1);
+                }
             }
 
           src += rowstride;
-        }
-      else
-        {
-          for (j = 0; j < dest_width; j++, d+= 4, cb += 3)
-            {
-              GIMP_CAIRO_RGB24_SET_PIXEL (d, cb[0], cb[1], cb[2]);
-            }
+          dest += dest_stride;
         }
 
-      dest += dest_stride;
+      cairo_surface_mark_dirty (surface);
     }
 
-  cairo_surface_mark_dirty (surface);
+  cairo_destroy (cr);
 }
 
 /* This function creates a background pattern from a stock icon



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