home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 February / CMCD0205.ISO / Linux / gimp-2.2.0.tar.gz / gimp-2.2.0.tar / gimp-2.2.0 / libgimpwidgets / gimppreviewarea.c < prev    next >
C/C++ Source or Header  |  2004-11-02  |  54KB  |  1,812 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * This library is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU Lesser General Public
  6.  * License as published by the Free Software Foundation; either
  7.  * version 2 of the License, or (at your option) any later version.
  8.  *
  9.  * This library is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12.  * Lesser General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU Lesser General Public
  15.  * License along with this library; if not, write to the
  16.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  17.  * Boston, MA 02111-1307, USA.
  18.  */
  19.  
  20. #include "config.h"
  21.  
  22. #include <string.h>
  23.  
  24. #include <gtk/gtk.h>
  25.  
  26. #include "libgimpbase/gimpbase.h"
  27.  
  28. #include "gimpwidgetstypes.h"
  29.  
  30. #include "gimppreviewarea.h"
  31.  
  32. #include "libgimp/libgimp-intl.h"
  33.  
  34.  
  35. enum
  36. {
  37.   PROP_0,
  38.   PROP_CHECK_SIZE,
  39.   PROP_CHECK_TYPE
  40. };
  41.  
  42.  
  43. #define DEFAULT_CHECK_SIZE  GIMP_CHECK_SIZE_MEDIUM_CHECKS
  44. #define DEFAULT_CHECK_TYPE  GIMP_CHECK_TYPE_GRAY_CHECKS
  45.  
  46.  
  47. static void      gimp_preview_area_class_init       (GimpPreviewAreaClass *klass);
  48. static void      gimp_preview_area_init             (GimpPreviewArea *area);
  49.  
  50. static void      gimp_preview_area_finalize         (GObject         *object);
  51. static void      gimp_preview_area_set_property     (GObject         *object,
  52.                                                      guint            property_id,
  53.                                                      const GValue    *value,
  54.                                                      GParamSpec      *pspec);
  55. static void      gimp_preview_area_get_property     (GObject         *object,
  56.                                                      guint            property_id,
  57.                                                      GValue          *value,
  58.                                                      GParamSpec      *pspec);
  59.  
  60. static void      gimp_preview_area_size_allocate    (GtkWidget       *widget,
  61.                                                      GtkAllocation   *allocation);
  62. static gboolean  gimp_preview_area_expose           (GtkWidget       *widget,
  63.                                                      GdkEventExpose  *event);
  64.  
  65. static void      gimp_preview_area_queue_draw       (GimpPreviewArea *area,
  66.                                                      gint             x,
  67.                                                      gint             y,
  68.                                                      gint             width,
  69.                                                      gint             height);
  70. static gint      gimp_preview_area_image_type_bytes (GimpImageType    type);
  71.  
  72.  
  73. static GtkDrawingAreaClass *parent_class = NULL;
  74.  
  75.  
  76. #define CHECK_COLOR(area, row, col)        \
  77.   (((((area)->offset_y + (row)) & size) ^  \
  78.     (((area)->offset_x + (col)) & size)) ? dark : light)
  79.  
  80.  
  81. GType
  82. gimp_preview_area_get_type (void)
  83. {
  84.   static GType view_type = 0;
  85.  
  86.   if (! view_type)
  87.     {
  88.       static const GTypeInfo view_info =
  89.       {
  90.         sizeof (GimpPreviewAreaClass),
  91.         NULL,           /* base_init */
  92.         NULL,           /* base_finalize */
  93.         (GClassInitFunc) gimp_preview_area_class_init,
  94.         NULL,           /* class_finalize */
  95.         NULL,           /* class_data */
  96.         sizeof (GimpPreviewArea),
  97.         0,              /* n_preallocs */
  98.         (GInstanceInitFunc) gimp_preview_area_init,
  99.       };
  100.  
  101.       view_type = g_type_register_static (GTK_TYPE_DRAWING_AREA,
  102.                                           "GimpPreviewArea",
  103.                                           &view_info, 0);
  104.     }
  105.  
  106.   return view_type;
  107. }
  108.  
  109. static void
  110. gimp_preview_area_class_init (GimpPreviewAreaClass *klass)
  111. {
  112.   GObjectClass   *object_class = G_OBJECT_CLASS (klass);
  113.   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
  114.  
  115.   parent_class = g_type_class_peek_parent (klass);
  116.  
  117.   object_class->finalize      = gimp_preview_area_finalize;
  118.   object_class->set_property  = gimp_preview_area_set_property;
  119.   object_class->get_property  = gimp_preview_area_get_property;
  120.  
  121.   widget_class->size_allocate = gimp_preview_area_size_allocate;
  122.   widget_class->expose_event  = gimp_preview_area_expose;
  123.  
  124.   g_object_class_install_property (object_class, PROP_CHECK_SIZE,
  125.                                    g_param_spec_enum ("check-size",
  126.                                                       _("Check Size"), NULL,
  127.                                                       GIMP_TYPE_CHECK_SIZE,
  128.                                                       DEFAULT_CHECK_SIZE,
  129.                                                       G_PARAM_READWRITE));
  130.  
  131.   g_object_class_install_property (object_class, PROP_CHECK_TYPE,
  132.                                    g_param_spec_enum ("check-type",
  133.                                                       _("Check Style"), NULL,
  134.                                                       GIMP_TYPE_CHECK_TYPE,
  135.                                                       DEFAULT_CHECK_TYPE,
  136.                                                       G_PARAM_READWRITE));
  137. }
  138.  
  139. static void
  140. gimp_preview_area_init (GimpPreviewArea *area)
  141. {
  142.   area->check_size = DEFAULT_CHECK_SIZE;
  143.   area->check_type = DEFAULT_CHECK_TYPE;
  144.   area->buf        = NULL;
  145.   area->colormap   = NULL;
  146.   area->offset_x   = 0;
  147.   area->offset_y   = 0;
  148.   area->width      = 0;
  149.   area->height     = 0;
  150.   area->rowstride  = 0;
  151.   area->max_width  = -1;
  152.   area->max_height = -1;
  153. }
  154.  
  155. static void
  156. gimp_preview_area_finalize (GObject *object)
  157. {
  158.   GimpPreviewArea *area = GIMP_PREVIEW_AREA (object);
  159.  
  160.   if (area->buf)
  161.     {
  162.       g_free (area->buf);
  163.       area->buf = NULL;
  164.     }
  165.   if (area->colormap)
  166.     {
  167.       g_free (area->colormap);
  168.       area->colormap = NULL;
  169.     }
  170.  
  171.   G_OBJECT_CLASS (parent_class)->finalize (object);
  172. }
  173.  
  174. static void
  175. gimp_preview_area_set_property (GObject      *object,
  176.                                 guint         property_id,
  177.                                 const GValue *value,
  178.                                 GParamSpec   *pspec)
  179. {
  180.   GimpPreviewArea *area = GIMP_PREVIEW_AREA (object);
  181.  
  182.   switch (property_id)
  183.     {
  184.     case PROP_CHECK_SIZE:
  185.       area->check_size = g_value_get_enum (value);
  186.       break;
  187.     case PROP_CHECK_TYPE:
  188.       area->check_type = g_value_get_enum (value);
  189.       break;
  190.  
  191.     default:
  192.       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  193.       break;
  194.     }
  195. }
  196.  
  197. static void
  198. gimp_preview_area_get_property (GObject    *object,
  199.                                 guint       property_id,
  200.                                 GValue     *value,
  201.                                 GParamSpec *pspec)
  202. {
  203.   GimpPreviewArea *area = GIMP_PREVIEW_AREA (object);
  204.  
  205.   switch (property_id)
  206.     {
  207.     case PROP_CHECK_SIZE:
  208.       g_value_set_enum (value, area->check_size);
  209.       break;
  210.     case PROP_CHECK_TYPE:
  211.       g_value_set_enum (value, area->check_type);
  212.       break;
  213.  
  214.     default:
  215.       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  216.       break;
  217.     }
  218. }
  219.  
  220. static void
  221. gimp_preview_area_size_allocate (GtkWidget     *widget,
  222.                                  GtkAllocation *allocation)
  223. {
  224.   GimpPreviewArea *area = GIMP_PREVIEW_AREA (widget);
  225.   gint             width;
  226.   gint             height;
  227.  
  228.   if (GTK_WIDGET_CLASS (parent_class)->size_allocate)
  229.     GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
  230.  
  231.   width  = (area->max_width > 0 ?
  232.             MIN (allocation->width, area->max_width) : allocation->width);
  233.   height = (area->max_height > 0 ?
  234.             MIN (allocation->height, area->max_height) : allocation->height);
  235.  
  236.   if (width  != area->width || height != area->height)
  237.     {
  238.       if (area->buf)
  239.         {
  240.           g_free (area->buf);
  241.  
  242.           area->buf       = NULL;
  243.           area->rowstride = 0;
  244.         }
  245.  
  246.       area->width  = width;
  247.       area->height = height;
  248.     }
  249. }
  250.  
  251. static gboolean
  252. gimp_preview_area_expose (GtkWidget      *widget,
  253.                           GdkEventExpose *event)
  254. {
  255.   GimpPreviewArea *area;
  256.   GdkRectangle     rect;
  257.   GdkRectangle     render;
  258.  
  259.   g_return_val_if_fail (GIMP_IS_PREVIEW_AREA (widget), FALSE);
  260.  
  261.   area = GIMP_PREVIEW_AREA (widget);
  262.  
  263.   if (! area->buf)
  264.     return FALSE;
  265.  
  266.   rect.x      = (widget->allocation.width  - area->width)  / 2;
  267.   rect.y      = (widget->allocation.height - area->height) / 2;
  268.   rect.width  = area->width;
  269.   rect.height = area->height;
  270.  
  271.   if (gdk_rectangle_intersect (&rect, &event->area, &render))
  272.     {
  273.       gint    x   = render.x - rect.x;
  274.       gint    y   = render.y - rect.y;
  275.       guchar *buf = area->buf + x * 3 + y * area->rowstride;
  276.  
  277.       gdk_draw_rgb_image_dithalign (widget->window,
  278.                                     widget->style->fg_gc[widget->state],
  279.                                     render.x,
  280.                                     render.y,
  281.                                     render.width,
  282.                                     render.height,
  283.                                     GDK_RGB_DITHER_MAX,
  284.                                     buf,
  285.                                     area->rowstride,
  286.                                     area->offset_x - render.x,
  287.                                     area->offset_y - render.y);
  288.     }
  289.  
  290.   return FALSE;
  291. }
  292.  
  293. static void
  294. gimp_preview_area_queue_draw (GimpPreviewArea *area,
  295.                               gint             x,
  296.                               gint             y,
  297.                               gint             width,
  298.                               gint             height)
  299. {
  300.   GtkWidget *widget = GTK_WIDGET (area);
  301.  
  302.   x += (widget->allocation.width  - area->width)  / 2;
  303.   y += (widget->allocation.height - area->height) / 2;
  304.  
  305.   gtk_widget_queue_draw_area (widget, x, y, width, height);
  306. }
  307.  
  308. static gint
  309. gimp_preview_area_image_type_bytes (GimpImageType type)
  310. {
  311.   switch (type)
  312.     {
  313.     case GIMP_GRAY_IMAGE:
  314.     case GIMP_INDEXED_IMAGE:
  315.       return 1;
  316.  
  317.     case GIMP_GRAYA_IMAGE:
  318.     case GIMP_INDEXEDA_IMAGE:
  319.       return 2;
  320.  
  321.     case GIMP_RGB_IMAGE:
  322.       return 3;
  323.  
  324.     case GIMP_RGBA_IMAGE:
  325.       return 4;
  326.  
  327.     default:
  328.       g_return_val_if_reached (0);
  329.       break;
  330.     }
  331. }
  332.  
  333. /**
  334.  * gimp_preview_area_new:
  335.  *
  336.  * Return value: a new #GimpPreviewArea widget.
  337.  *
  338.  * Since GIMP 2.2
  339.  **/
  340. GtkWidget *
  341. gimp_preview_area_new (void)
  342. {
  343.   return g_object_new (GIMP_TYPE_PREVIEW_AREA, NULL);
  344. }
  345.  
  346. /**
  347.  * gimp_preview_area_draw:
  348.  * @area:      a #GimpPreviewArea widget.
  349.  * @x:         x offset in preview
  350.  * @y:         y offset in preview
  351.  * @width:     buffer width
  352.  * @height:    buffer height
  353.  * @type:      the #GimpImageType of @buf
  354.  * @buf:       a #guchar buffer that contains the preview pixel data.
  355.  * @rowstride: rowstride of @buf
  356.  *
  357.  * Draws @buf on @area and queues a redraw on the rectangle that
  358.  * changed.
  359.  *
  360.  * Since GIMP 2.2
  361.  **/
  362. void
  363. gimp_preview_area_draw (GimpPreviewArea *area,
  364.                         gint             x,
  365.                         gint             y,
  366.                         gint             width,
  367.                         gint             height,
  368.                         GimpImageType    type,
  369.                         const guchar    *buf,
  370.                         gint             rowstride)
  371. {
  372.   const guchar    *src;
  373.   guchar          *dest;
  374.   guint            size;
  375.   guchar           light;
  376.   guchar           dark;
  377.   gint             row;
  378.   gint             col;
  379.  
  380.   g_return_if_fail (GIMP_IS_PREVIEW_AREA (area));
  381.   g_return_if_fail (width > 0 && height > 0);
  382.   g_return_if_fail (buf != NULL);
  383.   g_return_if_fail (rowstride > 0);
  384.  
  385.   if (x + width < 0 || x >= area->width)
  386.     return;
  387.  
  388.   if (y + height < 0 || y >= area->height)
  389.     return;
  390.  
  391.   if (x < 0)
  392.     {
  393.       gint  bpp = gimp_preview_area_image_type_bytes (type);
  394.  
  395.       buf   -= x * bpp;
  396.       width -= x;
  397.  
  398.       x = 0;
  399.     }
  400.  
  401.   if (x + width > area->width)
  402.     width = area->width - x;
  403.  
  404.   if (y < 0)
  405.     {
  406.       buf    -= y * rowstride;
  407.       height -= y;
  408.  
  409.       y = 0;
  410.     }
  411.  
  412.   if (y + height > area->height)
  413.     height = area->height - y;
  414.  
  415.   if (! area->buf)
  416.     {
  417.       area->rowstride = ((area->width * 3) + 3) & ~3;
  418.       area->buf = g_new (guchar, area->rowstride * area->height);
  419.     }
  420.  
  421.   size = 1 << (2 + area->check_size);
  422.   gimp_checks_get_shades (area->check_type, &light, &dark);
  423.  
  424.   src  = buf;
  425.   dest = area->buf + x * 3 + y * area->rowstride;
  426.  
  427.   switch (type)
  428.     {
  429.     case GIMP_RGB_IMAGE:
  430.       for (row = 0; row < height; row++)
  431.         {
  432.           memcpy (dest, src, 3 * width);
  433.  
  434.           src  += rowstride;
  435.           dest += area->rowstride;
  436.         }
  437.       break;
  438.  
  439.     case GIMP_RGBA_IMAGE:
  440.        for (row = y; row < y + height; row++)
  441.         {
  442.           const guchar *s = src;
  443.           guchar       *d = dest;
  444.  
  445.           for (col = x; col < x + width; col++, s += 4, d+= 3)
  446.             {
  447.               switch (s[3])
  448.                 {
  449.                 case 0:
  450.                   d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  451.                   break;
  452.  
  453.                 case 255:
  454.                   d[0] = s[0];
  455.                   d[1] = s[1];
  456.                   d[2] = s[2];
  457.                   break;
  458.  
  459.                 default:
  460.                   {
  461.                     register guint alpha = s[3] + 1;
  462.                     register guint check = CHECK_COLOR (area, row, col);
  463.  
  464.                     d[0] = ((check << 8) + (s[0] - check) * alpha) >> 8;
  465.                     d[1] = ((check << 8) + (s[1] - check) * alpha) >> 8;
  466.                     d[2] = ((check << 8) + (s[2] - check) * alpha) >> 8;
  467.                   }
  468.                   break;
  469.                 }
  470.             }
  471.  
  472.           src  += rowstride;
  473.           dest += area->rowstride;
  474.         }
  475.        break;
  476.  
  477.     case GIMP_GRAY_IMAGE:
  478.       for (row = 0; row < height; row++)
  479.         {
  480.           const guchar *s = src;
  481.           guchar       *d = dest;
  482.  
  483.           for (col = 0; col < width; col++, s++, d += 3)
  484.             {
  485.               d[0] = d[1] = d[2] = s[0];
  486.             }
  487.  
  488.           src  += rowstride;
  489.           dest += area->rowstride;
  490.         }
  491.       break;
  492.  
  493.     case GIMP_GRAYA_IMAGE:
  494.       for (row = y; row < y + height; row++)
  495.         {
  496.           const guchar *s = src;
  497.           guchar       *d = dest;
  498.  
  499.           for (col = x; col < x + width; col++, s += 2, d+= 3)
  500.             {
  501.               switch (s[1])
  502.                 {
  503.                 case 0:
  504.                   d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  505.                   break;
  506.  
  507.                 case 255:
  508.                   d[0] = d[1] = d[2] = s[0];
  509.                   break;
  510.  
  511.                 default:
  512.                   {
  513.                     register guint alpha = s[1] + 1;
  514.                     register guint check = CHECK_COLOR (area, row, col);
  515.  
  516.                     d[0] = d[1] = d[2] =
  517.                       ((check << 8) + (s[0] - check) * alpha) >> 8;
  518.                   }
  519.                   break;
  520.                 }
  521.             }
  522.  
  523.           src  += rowstride;
  524.           dest += area->rowstride;
  525.         }
  526.       break;
  527.  
  528.     case GIMP_INDEXED_IMAGE:
  529.       g_return_if_fail (area->colormap != NULL);
  530.       for (row = 0; row < height; row++)
  531.         {
  532.           const guchar *s = src;
  533.           guchar       *d = dest;
  534.  
  535.           for (col = 0; col < width; col++, s++, d += 3)
  536.             {
  537.               const guchar *colormap = area->colormap + 3 * s[0];
  538.  
  539.               d[0] = colormap[0];
  540.               d[1] = colormap[1];
  541.               d[2] = colormap[2];
  542.             }
  543.  
  544.           src  += rowstride;
  545.           dest += area->rowstride;
  546.         }
  547.       break;
  548.  
  549.     case GIMP_INDEXEDA_IMAGE:
  550.       g_return_if_fail (area->colormap != NULL);
  551.       for (row = y; row < y + height; row++)
  552.         {
  553.           const guchar *s = src;
  554.           guchar       *d = dest;
  555.  
  556.           for (col = x; col < x + width; col++, s += 2, d += 3)
  557.             {
  558.               const guchar *colormap  = area->colormap + 3 * s[0];
  559.  
  560.               switch (s[1])
  561.                 {
  562.                 case 0:
  563.                   d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  564.                   break;
  565.  
  566.                 case 255:
  567.                   d[0] = colormap[0];
  568.                   d[1] = colormap[1];
  569.                   d[2] = colormap[2];
  570.                   break;
  571.  
  572.                 default:
  573.                   {
  574.                     register guint alpha = s[3] + 1;
  575.                     register guint check = CHECK_COLOR (area, row, col);
  576.  
  577.                     d[0] = ((check << 8) + (colormap[0] - check) * alpha) >> 8;
  578.                     d[1] = ((check << 8) + (colormap[1] - check) * alpha) >> 8;
  579.                     d[2] = ((check << 8) + (colormap[2] - check) * alpha) >> 8;
  580.                   }
  581.                   break;
  582.                 }
  583.             }
  584.  
  585.           src  += rowstride;
  586.           dest += area->rowstride;
  587.         }
  588.       break;
  589.     }
  590.  
  591.   gimp_preview_area_queue_draw (area, x, y, width, height);
  592. }
  593.  
  594. /**
  595.  * gimp_preview_area_blend:
  596.  * @area:       a #GimpPreviewArea widget.
  597.  * @x:          x offset in preview
  598.  * @y:          y offset in preview
  599.  * @width:      buffer width
  600.  * @height:     buffer height
  601.  * @type:       the #GimpImageType of @buf1 and @buf2
  602.  * @buf1:       a #guchar buffer that contains the pixel data for
  603.  *              the first (on bottom) layer
  604.  * @rowstride1: rowstride of @buf1
  605.  * @buf2:       a #guchar buffer that contains the pixel data for
  606.  *              the second (on top) layer
  607.  * @rowstride2: rowstride of @buf2
  608.  * @opacity:    The opacity of the first layer.
  609.  *
  610.  * Blend @buf1 on top of @buf2 with the given @opacity on the @area
  611.  * and queues a redraw on the rectangle that changed.
  612.  *
  613.  * Since GIMP 2.2
  614.  **/
  615. void
  616. gimp_preview_area_blend (GimpPreviewArea *area,
  617.                          gint             x,
  618.                          gint             y,
  619.                          gint             width,
  620.                          gint             height,
  621.                          GimpImageType    type,
  622.                          const guchar    *buf1,
  623.                          gint             rowstride1,
  624.                          const guchar    *buf2,
  625.                          gint             rowstride2,
  626.                          guchar           opacity)
  627. {
  628.   const guchar    *src1;
  629.   const guchar    *src2;
  630.   guchar          *dest;
  631.   guint            size;
  632.   guchar           light;
  633.   guchar           dark;
  634.   gint             row;
  635.   gint             col;
  636.   gint             i;
  637.  
  638.   g_return_if_fail (GIMP_IS_PREVIEW_AREA (area));
  639.   g_return_if_fail (width > 0 && height > 0);
  640.   g_return_if_fail (buf1 != NULL);
  641.   g_return_if_fail (buf2 != NULL);
  642.   g_return_if_fail (rowstride1 > 0);
  643.   g_return_if_fail (rowstride2 > 0);
  644.  
  645.   switch (opacity)
  646.     {
  647.     case 0:
  648.       gimp_preview_area_draw (area, x, y, width, height,
  649.                               type, buf1, rowstride1);
  650.       return;
  651.  
  652.     case 255:
  653.       gimp_preview_area_draw (area, x, y, width, height,
  654.                               type, buf2, rowstride2);
  655.       return;
  656.  
  657.     default:
  658.       break;
  659.     }
  660.  
  661.   if (x + width < 0 || x >= area->width)
  662.     return;
  663.  
  664.   if (y + height < 0 || y >= area->height)
  665.     return;
  666.  
  667.   if (x < 0)
  668.     {
  669.       gint  bpp = gimp_preview_area_image_type_bytes (type);
  670.  
  671.       buf1  -= x * bpp;
  672.       buf2  -= x * bpp;
  673.       width -= x;
  674.  
  675.       x = 0;
  676.     }
  677.  
  678.   if (x + width > area->width)
  679.     width = area->width - x;
  680.  
  681.   if (y < 0)
  682.     {
  683.       buf1   -= y * rowstride1;
  684.       buf2   -= y * rowstride2;
  685.       height -= y;
  686.  
  687.       y = 0;
  688.     }
  689.  
  690.   if (y + height > area->height)
  691.     height = area->height - y;
  692.  
  693.   if (! area->buf)
  694.     {
  695.       area->rowstride = ((area->width * 3) + 3) & ~3;
  696.       area->buf = g_new (guchar, area->rowstride * area->height);
  697.     }
  698.  
  699.   size = 1 << (2 + area->check_size);
  700.   gimp_checks_get_shades (area->check_type, &light, &dark);
  701.  
  702.   src1 = buf1;
  703.   src2 = buf2;
  704.   dest = area->buf + x * 3 + y * area->rowstride;
  705.  
  706.   switch (type)
  707.     {
  708.     case GIMP_RGB_IMAGE:
  709.       for (row = 0; row < height; row++)
  710.         {
  711.           const guchar *s1 = src1;
  712.           const guchar *s2 = src2;
  713.           guchar       *d  = dest;
  714.  
  715.           for (col = x; col < x + width; col++, s1 += 3, s2 += 3, d+= 3)
  716.             {
  717.               d[0] = ((s1[0] << 8) + (s2[0] - s1[0]) * opacity) >> 8;
  718.               d[1] = ((s1[1] << 8) + (s2[1] - s1[1]) * opacity) >> 8;
  719.               d[2] = ((s1[2] << 8) + (s2[2] - s1[2]) * opacity) >> 8;
  720.             }
  721.  
  722.           src1 += rowstride1;
  723.           src2 += rowstride2;
  724.           dest += area->rowstride;
  725.         }
  726.       break;
  727.  
  728.     case GIMP_RGBA_IMAGE:
  729.       for (row = y; row < y + height; row++)
  730.         {
  731.           const guchar *s1 = src1;
  732.           const guchar *s2 = src2;
  733.           guchar       *d  = dest;
  734.  
  735.           for (col = x; col < x + width; col++, s1 += 4, s2 += 4, d+= 3)
  736.             {
  737.               guchar inter[4];
  738.  
  739.               if (s1[3] == s2[3])
  740.                 {
  741.                   inter[0] = ((s1[0] << 8) + (s2[0] - s1[0]) * opacity) >> 8;
  742.                   inter[1] = ((s1[1] << 8) + (s2[1] - s1[1]) * opacity) >> 8;
  743.                   inter[2] = ((s1[2] << 8) + (s2[2] - s1[2]) * opacity) >> 8;
  744.                   inter[3] = s1[3];
  745.                 }
  746.               else
  747.                 {
  748.                   inter[3] = ((s1[3] << 8) + (s2[3] - s1[3]) * opacity) >> 8;
  749.  
  750.                   if (inter[3])
  751.                     {
  752.                       for (i = 0; i < 3; i++)
  753.                         {
  754.                           gushort a = s1[i] * s1[3];
  755.                           gushort b = s2[i] * s2[3];
  756.  
  757.                           inter[i] =
  758.                             (((a << 8) + (b  - a) * opacity) >> 8) / inter[3];
  759.                         }
  760.                     }
  761.  
  762.                   switch (inter[3])
  763.                     {
  764.                     case 0:
  765.                       d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  766.                       break;
  767.  
  768.                     case 255:
  769.                       d[0] = inter[0];
  770.                       d[1] = inter[1];
  771.                       d[2] = inter[2];
  772.                       break;
  773.  
  774.                     default:
  775.                       {
  776.                         register guint alpha = inter[3] + 1;
  777.                         register guint check = CHECK_COLOR (area, row, col);
  778.  
  779.                         d[0] = ((check << 8) + (inter[0] - check) * alpha) >> 8;
  780.                         d[1] = ((check << 8) + (inter[1] - check) * alpha) >> 8;
  781.                         d[2] = ((check << 8) + (inter[2] - check) * alpha) >> 8;
  782.                       }
  783.                       break;
  784.                     }
  785.                 }
  786.             }
  787.  
  788.           src1 += rowstride1;
  789.           src2 += rowstride2;
  790.           dest += area->rowstride;
  791.         }
  792.       break;
  793.  
  794.     case GIMP_GRAY_IMAGE:
  795.       for (row = 0; row < height; row++)
  796.         {
  797.           const guchar *s1 = src1;
  798.           const guchar *s2 = src2;
  799.           guchar       *d  = dest;
  800.  
  801.           for (col = 0; col < width; col++, s1++, s2++, d += 3)
  802.             {
  803.               d[0] = d[1] = d[2] =
  804.                 ((s1[0] << 8) + (s2[0] - s1[0]) * opacity) >> 8;
  805.             }
  806.  
  807.           src1 += rowstride1;
  808.           src2 += rowstride2;
  809.           dest += area->rowstride;
  810.         }
  811.       break;
  812.  
  813.     case GIMP_GRAYA_IMAGE:
  814.       for (row = y; row < y + height; row++)
  815.         {
  816.           const guchar *s1 = src1;
  817.           const guchar *s2 = src2;
  818.           guchar       *d  = dest;
  819.  
  820.           for (col = x; col < x + width; col++, s1 += 2, s2 += 2, d+= 3)
  821.             {
  822.               guchar inter[2];
  823.  
  824.               if (s1[1] == s2[1])
  825.                 {
  826.                   inter[0] = ((s1[0] << 8) + (s2[0] - s1[0]) * opacity) >> 8;
  827.                   inter[1] = s1[1];
  828.                 }
  829.               else
  830.                 {
  831.                   inter[1] = ((s1[1] << 8) + (s2[1] - s1[1]) * opacity) >> 8;
  832.  
  833.                   if (inter[1])
  834.                     {
  835.                       gushort a = s1[0] * s1[1];
  836.                       gushort b = s2[0] * s2[1];
  837.  
  838.                       inter[0] =
  839.                         (((a << 8) + (b  - a) * opacity) >> 8) / inter[1];
  840.                     }
  841.                 }
  842.  
  843.               switch (inter[1])
  844.                 {
  845.                 case 0:
  846.                   d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  847.                   break;
  848.  
  849.                 case 255:
  850.                   d[0] = d[1] = d[2] = inter[0];
  851.                   break;
  852.  
  853.                 default:
  854.                   {
  855.                     register guint alpha = inter[1] + 1;
  856.                     register guint check = CHECK_COLOR (area, row, col);
  857.  
  858.                     d[0] = d[1] = d[2] =
  859.                       ((check << 8) + (inter[0] - check) * alpha) >> 8;
  860.                   }
  861.                   break;
  862.                 }
  863.             }
  864.  
  865.           src1 += rowstride1;
  866.           src2 += rowstride2;
  867.           dest += area->rowstride;
  868.         }
  869.       break;
  870.  
  871.     case GIMP_INDEXED_IMAGE:
  872.       g_return_if_fail (area->colormap != NULL);
  873.       for (row = 0; row < height; row++)
  874.         {
  875.           const guchar *s1 = src1;
  876.           const guchar *s2 = src2;
  877.           guchar       *d  = dest;
  878.  
  879.           for (col = 0; col < width; col++, s1++, s2++, d += 3)
  880.             {
  881.               const guchar *cmap1 = area->colormap + 3 * s1[0];
  882.               const guchar *cmap2 = area->colormap + 3 * s2[0];
  883.  
  884.               d[0] = ((cmap1[0] << 8) + (cmap2[0] - cmap1[0]) * opacity) >> 8;
  885.               d[1] = ((cmap1[1] << 8) + (cmap2[1] - cmap1[1]) * opacity) >> 8;
  886.               d[2] = ((cmap1[2] << 8) + (cmap2[2] - cmap1[2]) * opacity) >> 8;
  887.             }
  888.  
  889.           src1 += rowstride1;
  890.           src2 += rowstride2;
  891.           dest += area->rowstride;
  892.         }
  893.       break;
  894.  
  895.     case GIMP_INDEXEDA_IMAGE:
  896.       g_return_if_fail (area->colormap != NULL);
  897.       for (row = y; row < y + height; row++)
  898.         {
  899.           const guchar *s1 = src1;
  900.           const guchar *s2 = src2;
  901.           guchar       *d  = dest;
  902.  
  903.           for (col = x; col < x + width; col++, s1 += 2, s2 += 2, d += 3)
  904.             {
  905.               const guchar *cmap1  = area->colormap + 3 * s1[0];
  906.               const guchar *cmap2  = area->colormap + 3 * s2[0];
  907.               guchar        inter[4];
  908.  
  909.               if (s1[1] == s2[1])
  910.                 {
  911.                   inter[0] = (((cmap1[0] << 8) +
  912.                                (cmap2[0] - cmap1[0]) * opacity) >> 8);
  913.                   inter[1] = (((cmap1[1] << 8) +
  914.                                (cmap2[1] - cmap1[1]) * opacity) >> 8);
  915.                   inter[2] = (((cmap1[2] << 8) +
  916.                                (cmap2[2] - cmap1[2]) * opacity) >> 8);
  917.                   inter[3] = s1[1];
  918.                 }
  919.               else
  920.                 {
  921.                   inter[3] = ((s1[1] << 8) + (s2[1] - s1[1]) * opacity) >> 8;
  922.  
  923.                   if (inter[3])
  924.                     {
  925.                       for (i = 0; i < 3; i++)
  926.                         {
  927.                           gushort a = cmap1[i] * s1[1];
  928.                           gushort b = cmap2[i] * s2[1];
  929.  
  930.                           inter[i] =
  931.                             (((a << 8) + (b  - a) * opacity) >> 8) / inter[3];
  932.                         }
  933.                     }
  934.                 }
  935.  
  936.               switch (inter[3])
  937.                 {
  938.                 case 0:
  939.                   d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  940.                   break;
  941.  
  942.                 case 255:
  943.                   d[0] = inter[0];
  944.                   d[1] = inter[1];
  945.                   d[2] = inter[2];
  946.                   break;
  947.  
  948.                 default:
  949.                   {
  950.                     register guint alpha = inter[3] + 1;
  951.                     register guint check = CHECK_COLOR (area, row, col);
  952.  
  953.                     d[0] = ((check << 8) + (inter[0] - check) * alpha) >> 8;
  954.                     d[1] = ((check << 8) + (inter[1] - check) * alpha) >> 8;
  955.                     d[2] = ((check << 8) + (inter[2] - check) * alpha) >> 8;
  956.                   }
  957.                   break;
  958.                 }
  959.             }
  960.  
  961.           src1 += rowstride1;
  962.           src2 += rowstride2;
  963.           dest += area->rowstride;
  964.         }
  965.       break;
  966.     }
  967.  
  968.   gimp_preview_area_queue_draw (area, x, y, width, height);
  969. }
  970.  
  971. /**
  972.  * gimp_preview_area_mask:
  973.  * @area:           a #GimpPreviewArea widget.
  974.  * @x:              x offset in preview
  975.  * @y:              y offset in preview
  976.  * @width:          buffer width
  977.  * @height:         buffer height
  978.  * @type:           the #GimpImageType of @buf1 and @buf2
  979.  * @buf1:           a #guchar buffer that contains the pixel data for
  980.  *                  the first (on bottom) layer
  981.  * @rowstride1:     rowstride of @buf1
  982.  * @buf2:           a #guchar buffer that contains the pixel data for
  983.  *                  the second (on top) layer
  984.  * @rowstride2:     rowstride of @buf2
  985.  * @mask:           a #guchar buffer representing the mask of the second
  986.  *                  layer.
  987.  * @rowstride_mask: rowstride for the mask.
  988.  *
  989.  * Blend @buf1 on top of @buf2 with the given @mask on the @area
  990.  * and queues a redraw on the rectangle that changed.
  991.  *
  992.  * Since GIMP 2.2
  993.  **/
  994. void
  995. gimp_preview_area_mask (GimpPreviewArea *area,
  996.                         gint             x,
  997.                         gint             y,
  998.                         gint             width,
  999.                         gint             height,
  1000.                         GimpImageType    type,
  1001.                         const guchar    *buf1,
  1002.                         gint             rowstride1,
  1003.                         const guchar    *buf2,
  1004.                         gint             rowstride2,
  1005.                         guchar          *mask,
  1006.                         gint             rowstride_mask)
  1007. {
  1008.   const guchar    *src1;
  1009.   const guchar    *src2;
  1010.   const guchar    *src_mask;
  1011.   guchar          *dest;
  1012.   guint            size;
  1013.   guchar           light;
  1014.   guchar           dark;
  1015.   gint             row;
  1016.   gint             col;
  1017.   gint             i;
  1018.  
  1019.   g_return_if_fail (GIMP_IS_PREVIEW_AREA (area));
  1020.   g_return_if_fail (width > 0 && height > 0);
  1021.   g_return_if_fail (buf1 != NULL);
  1022.   g_return_if_fail (buf2 != NULL);
  1023.   g_return_if_fail (mask != NULL);
  1024.   g_return_if_fail (rowstride1 > 0);
  1025.   g_return_if_fail (rowstride2 > 0);
  1026.   g_return_if_fail (rowstride_mask > 0);
  1027.  
  1028.   if (x + width < 0 || x >= area->width)
  1029.     return;
  1030.  
  1031.   if (y + height < 0 || y >= area->height)
  1032.     return;
  1033.  
  1034.   if (x < 0)
  1035.     {
  1036.       gint  bpp = gimp_preview_area_image_type_bytes (type);
  1037.  
  1038.       buf1  -= x * bpp;
  1039.       buf2  -= x * bpp;
  1040.       mask  -= x;
  1041.       width -= x;
  1042.  
  1043.       x = 0;
  1044.     }
  1045.  
  1046.   if (x + width > area->width)
  1047.     width = area->width - x;
  1048.  
  1049.   if (y < 0)
  1050.     {
  1051.       buf1   -= y * rowstride1;
  1052.       buf2   -= y * rowstride2;
  1053.       mask   -= y * rowstride_mask;
  1054.       height -= y;
  1055.  
  1056.       y = 0;
  1057.     }
  1058.  
  1059.   if (y + height > area->height)
  1060.     height = area->height - y;
  1061.  
  1062.   if (! area->buf)
  1063.     {
  1064.       area->rowstride = ((area->width * 3) + 3) & ~3;
  1065.       area->buf = g_new (guchar, area->rowstride * area->height);
  1066.     }
  1067.  
  1068.   size = 1 << (2 + area->check_size);
  1069.   gimp_checks_get_shades (area->check_type, &light, &dark);
  1070.  
  1071.   src1     = buf1;
  1072.   src2     = buf2;
  1073.   src_mask = mask;
  1074.   dest     = area->buf + x * 3 + y * area->rowstride;
  1075.  
  1076.   switch (type)
  1077.     {
  1078.     case GIMP_RGB_IMAGE:
  1079.       for (row = 0; row < height; row++)
  1080.         {
  1081.           const guchar *s1 = src1;
  1082.           const guchar *s2 = src2;
  1083.           const guchar *m  = src_mask;
  1084.           guchar       *d  = dest;
  1085.  
  1086.           for (col = x; col < x + width; col++, s1 += 3, s2 += 3, m++, d+= 3)
  1087.             {
  1088.                d[0] = ((s1[0] << 8) + (s2[0] - s1[0]) * m[0]) >> 8;
  1089.                d[1] = ((s1[1] << 8) + (s2[1] - s1[1]) * m[0]) >> 8;
  1090.                d[2] = ((s1[2] << 8) + (s2[2] - s1[2]) * m[0]) >> 8;
  1091.             }
  1092.           src1     += rowstride1;
  1093.           src2     += rowstride2;
  1094.           src_mask += rowstride_mask;
  1095.           dest     += area->rowstride;
  1096.         }
  1097.       break;
  1098.  
  1099.     case GIMP_RGBA_IMAGE:
  1100.        for (row = y; row < y + height; row++)
  1101.         {
  1102.           const guchar *s1 = src1;
  1103.           const guchar *s2 = src2;
  1104.           const guchar *m  = src_mask;
  1105.           guchar       *d  = dest;
  1106.  
  1107.           for (col = x; col < x + width; col++, s1 += 4, s2 += 4, m++, d+= 3)
  1108.             {
  1109.               switch (m[0])
  1110.                 {
  1111.                 case 0:
  1112.                   switch (s1[3])
  1113.                     {
  1114.                     case 0:
  1115.                       d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  1116.                       break;
  1117.  
  1118.                     case 255:
  1119.                       d[0] = s1[0];
  1120.                       d[1] = s1[1];
  1121.                       d[2] = s1[2];
  1122.                       break;
  1123.  
  1124.                     default:
  1125.                       {
  1126.                         register guint alpha = s1[3] + 1;
  1127.                         register guint check = CHECK_COLOR (area, row, col);
  1128.  
  1129.                         d[0] = ((check << 8) + (s1[0] - check) * alpha) >> 8;
  1130.                         d[1] = ((check << 8) + (s1[1] - check) * alpha) >> 8;
  1131.                         d[2] = ((check << 8) + (s1[2] - check) * alpha) >> 8;
  1132.                       }
  1133.                       break;
  1134.                     }
  1135.                   break;
  1136.  
  1137.                 case 255:
  1138.                   switch (s2[3])
  1139.                     {
  1140.                     case 0:
  1141.                       d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  1142.                       break;
  1143.  
  1144.                     case 255:
  1145.                       d[0] = s2[0];
  1146.                       d[1] = s2[1];
  1147.                       d[2] = s2[2];
  1148.                       break;
  1149.  
  1150.                     default:
  1151.                       {
  1152.                         register guint alpha = s2[3] + 1;
  1153.                         register guint check = CHECK_COLOR (area, row, col);
  1154.  
  1155.                         d[0] = ((check << 8) + (s2[0] - check) * alpha) >> 8;
  1156.                         d[1] = ((check << 8) + (s2[1] - check) * alpha) >> 8;
  1157.                         d[2] = ((check << 8) + (s2[2] - check) * alpha) >> 8;
  1158.                       }
  1159.                       break;
  1160.                     }
  1161.                   break;
  1162.  
  1163.                 default:
  1164.                   {
  1165.                     guchar inter[4];
  1166.  
  1167.                     if (s1[3] == s2[3])
  1168.                       {
  1169.                         inter[0] = ((s1[0] << 8) + (s2[0] - s1[0]) * m[0]) >> 8;
  1170.                         inter[1] = ((s1[1] << 8) + (s2[1] - s1[1]) * m[0]) >> 8;
  1171.                         inter[2] = ((s1[2] << 8) + (s2[2] - s1[2]) * m[0]) >> 8;
  1172.                         inter[3] = s1[3];
  1173.                      }
  1174.                     else
  1175.                       {
  1176.                         inter[3] = ((s1[3] << 8) + (s2[3] - s1[3]) * m[0]) >> 8;
  1177.  
  1178.                         if (inter[3])
  1179.                           {
  1180.                             for (i = 0; i < 3; i++)
  1181.                              {
  1182.                                gushort a = s1[i] * s1[3];
  1183.                                gushort b = s2[i] * s2[3];
  1184.  
  1185.                                inter[i] =
  1186.                                  (((a << 8) + (b  - a) * m[0]) >> 8) / inter[3];
  1187.                              }
  1188.                          }
  1189.                       }
  1190.  
  1191.                     switch (inter[3])
  1192.                       {
  1193.                       case 0:
  1194.                         d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  1195.                         break;
  1196.  
  1197.                       case 255:
  1198.                         d[0] = inter[0];
  1199.                         d[1] = inter[1];
  1200.                         d[2] = inter[2];
  1201.                         break;
  1202.  
  1203.                       default:
  1204.                         {
  1205.                           register guint alpha = inter[3] + 1;
  1206.                           register guint check = CHECK_COLOR (area, row, col);
  1207.  
  1208.                           d[0] = (((check << 8) +
  1209.                                    (inter[0] - check) * alpha) >> 8);
  1210.                           d[1] = (((check << 8) +
  1211.                                    (inter[1] - check) * alpha) >> 8);
  1212.                           d[2] = (((check << 8) +
  1213.                                    (inter[2] - check) * alpha) >> 8);
  1214.                         }
  1215.                         break;
  1216.                       }
  1217.                   }
  1218.                   break;
  1219.                 }
  1220.             }
  1221.  
  1222.           src1     += rowstride1;
  1223.           src2     += rowstride2;
  1224.           src_mask += rowstride_mask;
  1225.           dest     += area->rowstride;
  1226.         }
  1227.        break;
  1228.  
  1229.     case GIMP_GRAY_IMAGE:
  1230.       for (row = 0; row < height; row++)
  1231.         {
  1232.           const guchar *s1 = src1;
  1233.           const guchar *s2 = src2;
  1234.           const guchar *m  = src_mask;
  1235.           guchar       *d  = dest;
  1236.  
  1237.           for (col = 0; col < width; col++, s1++, s2++, m++, d += 3)
  1238.             {
  1239.               d[0] = d[1] = d[2] = ((s1[0] << 8) + (s2[0] - s1[0]) * m[0]) >> 8;
  1240.             }
  1241.  
  1242.           src1     += rowstride1;
  1243.           src2     += rowstride2;
  1244.           src_mask += rowstride_mask;
  1245.           dest     += area->rowstride;
  1246.         }
  1247.       break;
  1248.  
  1249.     case GIMP_GRAYA_IMAGE:
  1250.       for (row = y; row < y + height; row++)
  1251.         {
  1252.           const guchar *s1 = src1;
  1253.           const guchar *s2 = src2;
  1254.           const guchar *m  = src_mask;
  1255.           guchar       *d  = dest;
  1256.  
  1257.           for (col = x; col < x + width; col++, s1 += 2, s2 += 2, m++, d+= 3)
  1258.             {
  1259.               switch (m[0])
  1260.                 {
  1261.                 case 0:
  1262.                   switch (s1[1])
  1263.                     {
  1264.                     case 0:
  1265.                       d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  1266.                       break;
  1267.  
  1268.                     case 255:
  1269.                       d[0] = d[1] = d[2] = s1[0];
  1270.                       break;
  1271.  
  1272.                     default:
  1273.                       {
  1274.                         register guint alpha = s1[1] + 1;
  1275.                         register guint check = CHECK_COLOR (area, row, col);
  1276.  
  1277.                         d[0] = d[1] = d[2] =
  1278.                           ((check << 8) + (s1[0] - check) * alpha) >> 8;
  1279.                       }
  1280.                       break;
  1281.                     }
  1282.                   break;
  1283.  
  1284.                 case 255:
  1285.                   switch (s2[1])
  1286.                     {
  1287.                     case 0:
  1288.                       d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  1289.                       break;
  1290.  
  1291.                     case 255:
  1292.                       d[0] = d[1] = d[2] = s2[0];
  1293.                       break;
  1294.  
  1295.                     default:
  1296.                       {
  1297.                         register guint alpha = s2[1] + 1;
  1298.                         register guint check = CHECK_COLOR (area, row, col);
  1299.  
  1300.                         d[0] = d[1] = d[2] =
  1301.                           ((check << 8) + (s2[0] - check) * alpha) >> 8;
  1302.                       }
  1303.                       break;
  1304.                     }
  1305.                   break;
  1306.  
  1307.                 default:
  1308.                   {
  1309.                     guchar inter[2];
  1310.  
  1311.                     if (s1[1] == s2[1])
  1312.                       {
  1313.                         inter[0] = ((s1[0] << 8) + (s2[0] - s1[0]) * m[0]) >> 8;
  1314.                         inter[1] = s1[1];
  1315.                       }
  1316.                     else
  1317.                       {
  1318.                         inter[1] = ((s1[1] << 8) + (s2[1] - s1[1]) * m[0]) >> 8;
  1319.  
  1320.                         if (inter[1])
  1321.                           {
  1322.                             gushort a = s1[0] * s1[1];
  1323.                             gushort b = s2[0] * s2[1];
  1324.  
  1325.                             inter[0] =
  1326.                               (((a << 8) + (b  - a) * m[0]) >> 8) / inter[1];
  1327.                           }
  1328.                       }
  1329.  
  1330.                     switch (inter[1])
  1331.                       {
  1332.                       case 0:
  1333.                         d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  1334.                         break;
  1335.  
  1336.                       case 255:
  1337.                         d[0] = d[1] = d[2] = inter[0];
  1338.                         break;
  1339.  
  1340.                       default:
  1341.                         {
  1342.                           register guint alpha = inter[1] + 1;
  1343.                           register guint check = CHECK_COLOR (area, row, col);
  1344.  
  1345.                           d[0] = d[1] = d[2] =
  1346.                             ((check << 8) + (inter[0] - check) * alpha) >> 8;
  1347.                         }
  1348.                         break;
  1349.                       }
  1350.                   }
  1351.                   break;
  1352.                 }
  1353.             }
  1354.  
  1355.           src1     += rowstride1;
  1356.           src2     += rowstride2;
  1357.           src_mask += rowstride_mask;
  1358.           dest     += area->rowstride;
  1359.         }
  1360.       break;
  1361.  
  1362.     case GIMP_INDEXED_IMAGE:
  1363.       g_return_if_fail (area->colormap != NULL);
  1364.       for (row = 0; row < height; row++)
  1365.         {
  1366.           const guchar *s1 = src1;
  1367.           const guchar *s2 = src2;
  1368.           const guchar *m  = src_mask;
  1369.           guchar       *d  = dest;
  1370.  
  1371.           for (col = 0; col < width; col++, s1++, s2++, m++, d += 3)
  1372.             {
  1373.               const guchar *cmap1 = area->colormap + 3 * s1[0];
  1374.               const guchar *cmap2 = area->colormap + 3 * s2[0];
  1375.  
  1376.               d[0] = ((cmap1[0] << 8) + (cmap2[0] - cmap1[0]) * m[0]) >> 8;
  1377.               d[1] = ((cmap1[1] << 8) + (cmap2[1] - cmap1[1]) * m[0]) >> 8;
  1378.               d[2] = ((cmap1[2] << 8) + (cmap2[2] - cmap1[2]) * m[0]) >> 8;
  1379.             }
  1380.  
  1381.           src1     += rowstride1;
  1382.           src2     += rowstride2;
  1383.           src_mask += rowstride_mask;
  1384.           dest     += area->rowstride;
  1385.         }
  1386.       break;
  1387.  
  1388.     case GIMP_INDEXEDA_IMAGE:
  1389.       g_return_if_fail (area->colormap != NULL);
  1390.       for (row = y; row < y + height; row++)
  1391.         {
  1392.           const guchar *s1 = src1;
  1393.           const guchar *s2 = src2;
  1394.           const guchar *m  = src_mask;
  1395.           guchar       *d  = dest;
  1396.  
  1397.           for (col = x; col < x + width; col++, s1 += 2, s2 += 2, m++, d += 3)
  1398.             {
  1399.               const guchar *cmap1  = area->colormap + 3 * s1[0];
  1400.               const guchar *cmap2  = area->colormap + 3 * s2[0];
  1401.  
  1402.               switch (m[0])
  1403.                 {
  1404.                 case 0:
  1405.                   switch (s1[1])
  1406.                     {
  1407.                     case 0:
  1408.                       d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  1409.                       break;
  1410.  
  1411.                     case 255:
  1412.                       d[0] = cmap1[0];
  1413.                       d[1] = cmap1[1];
  1414.                       d[2] = cmap1[2];
  1415.                       break;
  1416.  
  1417.                     default:
  1418.                       {
  1419.                         register guint alpha = s1[1] + 1;
  1420.                         register guint check = CHECK_COLOR (area, row, col);
  1421.  
  1422.                         d[0] = ((check << 8) + (cmap1[0] - check) * alpha) >> 8;
  1423.                         d[1] = ((check << 8) + (cmap1[1] - check) * alpha) >> 8;
  1424.                         d[2] = ((check << 8) + (cmap1[2] - check) * alpha) >> 8;
  1425.                       }
  1426.                       break;
  1427.                     }
  1428.                   break;
  1429.  
  1430.                 case 255:
  1431.                   switch (s2[1])
  1432.                     {
  1433.                     case 0:
  1434.                       d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  1435.                       break;
  1436.  
  1437.                     case 255:
  1438.                       d[0] = cmap2[0];
  1439.                       d[1] = cmap2[1];
  1440.                       d[2] = cmap2[2];
  1441.                       break;
  1442.  
  1443.                     default:
  1444.                       {
  1445.                         register guint alpha = s2[1] + 1;
  1446.                         register guint check = CHECK_COLOR (area, row, col);
  1447.  
  1448.                         d[0] = ((check << 8) + (cmap2[0] - check) * alpha) >> 8;
  1449.                         d[1] = ((check << 8) + (cmap2[1] - check) * alpha) >> 8;
  1450.                         d[2] = ((check << 8) + (cmap2[2] - check) * alpha) >> 8;
  1451.                       }
  1452.                       break;
  1453.                     }
  1454.                   break;
  1455.  
  1456.                 default:
  1457.                   {
  1458.                     guchar inter[4];
  1459.  
  1460.                     if (s1[1] == s2[1])
  1461.                       {
  1462.                         inter[0] = (((cmap1[0] << 8) +
  1463.                                      (cmap2[0] - cmap1[0]) * m[0]) >> 8);
  1464.                         inter[1] = (((cmap1[1] << 8) +
  1465.                                      (cmap2[1] - cmap1[1]) * m[0]) >> 8);
  1466.                         inter[2] = (((cmap1[2] << 8) +
  1467.                                      (cmap2[2] - cmap1[2]) * m[0]) >> 8);
  1468.                         inter[3] = s1[1];
  1469.                       }
  1470.                     else
  1471.                       {
  1472.                         inter[3] = ((s1[1] << 8) + (s2[1] - s1[1]) * m[0]) >> 8;
  1473.  
  1474.                         if (inter[3])
  1475.                           {
  1476.                             for (i = 0 ; i < 3 ; i++)
  1477.                               {
  1478.                                 gushort a = cmap1[i] * s1[1];
  1479.                                 gushort b = cmap2[i] * s2[1];
  1480.  
  1481.                                 inter[i] =
  1482.                                   (((a << 8) + (b  - a) * m[0]) >> 8) / inter[3];
  1483.                               }
  1484.                           }
  1485.                       }
  1486.  
  1487.                     switch (inter[3])
  1488.                       {
  1489.                       case 0:
  1490.                         d[0] = d[1] = d[2] = CHECK_COLOR (area, row, col);
  1491.                         break;
  1492.  
  1493.                       case 255:
  1494.                         d[0] = inter[0];
  1495.                         d[1] = inter[1];
  1496.                         d[2] = inter[2];
  1497.                         break;
  1498.  
  1499.                       default:
  1500.                         {
  1501.                           register guint alpha = inter[3] + 1;
  1502.                           register guint check = CHECK_COLOR (area, row, col);
  1503.  
  1504.                           d[0] = ((check << 8) + (inter[0] - check) * alpha) >> 8;
  1505.                           d[1] = ((check << 8) + (inter[1] - check) * alpha) >> 8;
  1506.                           d[2] = ((check << 8) + (inter[2] - check) * alpha) >> 8;
  1507.                         }
  1508.                         break;
  1509.                       }
  1510.                   }
  1511.                   break;
  1512.                 }
  1513.             }
  1514.  
  1515.           src1     += rowstride1;
  1516.           src2     += rowstride2;
  1517.           src_mask += rowstride_mask;
  1518.           dest     += area->rowstride;
  1519.         }
  1520.       break;
  1521.     }
  1522.  
  1523.   gimp_preview_area_queue_draw (area, x, y, width, height);
  1524. }
  1525.  
  1526. /**
  1527.  * gimp_preview_area_fill:
  1528.  * @area:   a #GimpPreviewArea widget.
  1529.  * @x:      x offset in preview
  1530.  * @y:      y offset in preview
  1531.  * @width:  buffer width
  1532.  * @height: buffer height
  1533.  * @red:
  1534.  * @green:
  1535.  * @blue:
  1536.  *
  1537.  * Fills the @area in the given color.
  1538.  *
  1539.  * Since GIMP 2.2
  1540.  **/
  1541. void
  1542. gimp_preview_area_fill (GimpPreviewArea *area,
  1543.                         gint             x,
  1544.                         gint             y,
  1545.                         gint             width,
  1546.                         gint             height,
  1547.                         guchar           red,
  1548.                         guchar           green,
  1549.                         guchar           blue)
  1550. {
  1551.   guchar *dest;
  1552.   guchar *d;
  1553.   gint    row;
  1554.   gint    col;
  1555.  
  1556.   g_return_if_fail (GIMP_IS_PREVIEW_AREA (area));
  1557.   g_return_if_fail (width > 0 && height > 0);
  1558.  
  1559.   if (x + width < 0 || x >= area->width)
  1560.     return;
  1561.  
  1562.   if (y + height < 0 || y >= area->height)
  1563.     return;
  1564.  
  1565.   if (x < 0)
  1566.     {
  1567.       width -= x;
  1568.       x = 0;
  1569.     }
  1570.  
  1571.   if (x + width > area->width)
  1572.     width = area->width - x;
  1573.  
  1574.   if (y < 0)
  1575.     {
  1576.       height -= y;
  1577.       y = 0;
  1578.     }
  1579.  
  1580.   if (y + height > area->height)
  1581.     height = area->height - y;
  1582.  
  1583.   if (! area->buf)
  1584.     {
  1585.       area->rowstride = ((area->width * 3) + 3) & ~3;
  1586.       area->buf = g_new (guchar, area->rowstride * area->height);
  1587.     }
  1588.  
  1589.   dest = area->buf + x * 3 + y * area->rowstride;
  1590.  
  1591.   /*  colorize first row  */
  1592.   for (col = 0, d = dest; col < width; col++, d+= 3)
  1593.     {
  1594.       d[0] = red;
  1595.       d[1] = green;
  1596.       d[2] = blue;
  1597.     }
  1598.  
  1599.   /*  copy first row to remaining rows  */
  1600.   for (row = 1, d = dest; row < height; row++)
  1601.     {
  1602.       d += area->rowstride;
  1603.  
  1604.       memcpy (d, dest, width * 3);
  1605.     }
  1606.  
  1607.   gimp_preview_area_queue_draw (area, x, y, width, height);
  1608. }
  1609.  
  1610. /**
  1611.  * gimp_preview_area_set_offsets:
  1612.  * @area: a #GimpPreviewArea
  1613.  * @x:    horizontal offset
  1614.  * @y:    vertical offset
  1615.  *
  1616.  * Sets the offsets of the previewed area. This information is used
  1617.  * when drawing the checkerboard and to determine the dither offsets.
  1618.  *
  1619.  * Since: GIMP 2.2
  1620.  **/
  1621. void
  1622. gimp_preview_area_set_offsets (GimpPreviewArea *area,
  1623.                                gint             x,
  1624.                                gint             y)
  1625. {
  1626.   g_return_if_fail (GIMP_IS_PREVIEW_AREA (area));
  1627.  
  1628.   area->offset_x = x;
  1629.   area->offset_y = y;
  1630. }
  1631.  
  1632. /**
  1633.  * gimp_preview_area_set_colormap:
  1634.  * @area:       a #GimpPreviewArea
  1635.  * @colormap:   a #guchar buffer that contains the colormap
  1636.  * @num_colors: the number of colors in the colormap
  1637.  *
  1638.  * Sets the colormap for the #GimpPreviewArea widget. You need to
  1639.  * call this function before you use gimp_preview_area_draw() with
  1640.  * an image type of %GIMP_INDEXED_IMAGE or %GIMP_INDEXEDA_IMAGE.
  1641.  *
  1642.  * Since GIMP 2.2
  1643.  **/
  1644. void
  1645. gimp_preview_area_set_colormap (GimpPreviewArea *area,
  1646.                                 const guchar    *colormap,
  1647.                                 gint             num_colors)
  1648. {
  1649.   g_return_if_fail (GIMP_IS_PREVIEW_AREA (area));
  1650.   g_return_if_fail (colormap != NULL || num_colors == 0);
  1651.   g_return_if_fail (num_colors >= 0 && num_colors <= 256);
  1652.  
  1653.   if (num_colors > 0)
  1654.     {
  1655.       if (! area->colormap)
  1656.         area->colormap = g_new0 (guchar, 3 * 256);
  1657.  
  1658.       memcpy (area->colormap, colormap, 3 * num_colors);
  1659.     }
  1660.   else
  1661.     {
  1662.       g_free (area->colormap);
  1663.       area->colormap = NULL;
  1664.     }
  1665. }
  1666.  
  1667. /**
  1668.  * gimp_preview_area_set_max_size:
  1669.  * @area:   a #GimpPreviewArea widget
  1670.  * @width:  the maximum width in pixels or -1 to unset the limit
  1671.  * @height: the maximum height in pixels or -1 to unset the limit
  1672.  *
  1673.  * Usually a #GimpPreviewArea fills the size that it is
  1674.  * allocated. This funtion allows you to limit the preview area to a
  1675.  * maximum size. If a larger size is allocated for the widget, the
  1676.  * preview will draw itself centered into the allocated area.
  1677.  *
  1678.  * Since: GIMP 2.2
  1679.  **/
  1680. void
  1681. gimp_preview_area_set_max_size (GimpPreviewArea *area,
  1682.                                 gint             width,
  1683.                                 gint             height)
  1684. {
  1685.   g_return_if_fail (GIMP_IS_PREVIEW_AREA (area));
  1686.  
  1687.   area->max_width  = width;
  1688.   area->max_height = height;
  1689. }
  1690.  
  1691.  
  1692.  
  1693. /*  popup menu  */
  1694.  
  1695. static void
  1696. gimp_preview_area_menu_toggled (GtkWidget       *item,
  1697.                                 GimpPreviewArea *area)
  1698. {
  1699.   gboolean active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item));
  1700.  
  1701.   if (active)
  1702.     {
  1703.       const gchar *name;
  1704.       gint         value;
  1705.  
  1706.       name  = g_object_get_data (G_OBJECT (item),
  1707.                                  "gimp-preview-area-prop-name");
  1708.       value = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item),
  1709.                                                   "gimp-preview-area-prop-value"));
  1710.  
  1711.       if (name)
  1712.         g_object_set (area,
  1713.                       name, value,
  1714.                       NULL);
  1715.     }
  1716. }
  1717.  
  1718. static GtkWidget *
  1719. gimp_preview_area_menu_new (GimpPreviewArea *area,
  1720.                             const gchar     *property)
  1721. {
  1722.   GParamSpec *pspec;
  1723.   GEnumClass *enum_class;
  1724.   GEnumValue *enum_value;
  1725.   GtkWidget  *menu;
  1726.   GtkWidget  *item;
  1727.   GSList     *group = NULL;
  1728.   gint        value;
  1729.  
  1730.   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (area), property);
  1731.  
  1732.   g_return_val_if_fail (G_IS_PARAM_SPEC_ENUM (pspec), NULL);
  1733.  
  1734.   g_object_get (area,
  1735.                 property, &value,
  1736.                 NULL);
  1737.  
  1738.   enum_class = G_PARAM_SPEC_ENUM (pspec)->enum_class;
  1739.  
  1740.   menu = gtk_menu_new ();
  1741.  
  1742.   for (enum_value = enum_class->values; enum_value->value_name; enum_value++)
  1743.     {
  1744.       const gchar *name = gimp_enum_value_get_desc (enum_class, enum_value);
  1745.  
  1746.       item = gtk_radio_menu_item_new_with_label (group, name);
  1747.  
  1748.       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  1749.       gtk_widget_show (item);
  1750.  
  1751.       g_object_set_data (G_OBJECT (item),
  1752.                          "gimp-preview-area-prop-name",
  1753.                          (gpointer) property);
  1754.  
  1755.       g_object_set_data (G_OBJECT (item),
  1756.                          "gimp-preview-area-prop-value",
  1757.                          GINT_TO_POINTER (enum_value->value));
  1758.  
  1759.       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
  1760.                                       (enum_value->value == value));
  1761.  
  1762.       g_signal_connect (item, "toggled",
  1763.                         G_CALLBACK (gimp_preview_area_menu_toggled),
  1764.                         area);
  1765.  
  1766.       group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
  1767.     }
  1768.  
  1769.   item = gtk_menu_item_new_with_label (g_param_spec_get_nick (pspec));
  1770.  
  1771.   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
  1772.  
  1773.   gtk_widget_show (item);
  1774.  
  1775.   return item;
  1776. }
  1777.  
  1778. /**
  1779.  * gimp_preview_area_menu_popup:
  1780.  * @area:  a #GimpPreviewArea
  1781.  * @event: the button event that causes the menu to popup or %NULL
  1782.  *
  1783.  * Creates a popup menu that allows to configure the size and type of
  1784.  * the checkerboard pattern that the @area uses to visualize transparency.
  1785.  *
  1786.  * Since: GIMP 2.2
  1787.  **/
  1788. void
  1789. gimp_preview_area_menu_popup (GimpPreviewArea *area,
  1790.                               GdkEventButton  *event)
  1791. {
  1792.   GtkWidget *menu;
  1793.  
  1794.   g_return_if_fail (GIMP_IS_PREVIEW_AREA (area));
  1795.  
  1796.   menu = gtk_menu_new ();
  1797.   gtk_menu_set_screen (GTK_MENU (menu),
  1798.                        gtk_widget_get_screen (GTK_WIDGET (area)));
  1799.  
  1800.   gtk_menu_shell_append (GTK_MENU_SHELL (menu),
  1801.                          gimp_preview_area_menu_new (area, "check-type"));
  1802.   gtk_menu_shell_append (GTK_MENU_SHELL (menu),
  1803.                          gimp_preview_area_menu_new (area, "check-size"));
  1804.  
  1805.   if (event)
  1806.     gtk_menu_popup (GTK_MENU (menu),
  1807.                     NULL, NULL, NULL, NULL, event->button, event->time);
  1808.   else
  1809.     gtk_menu_popup (GTK_MENU (menu),
  1810.                     NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ());
  1811. }
  1812.