home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / channel.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  43.0 KB  |  1,776 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program 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
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <stdlib.h>
  22. #include <string.h>
  23.  
  24. #include <gtk/gtk.h>
  25.  
  26. #include "apptypes.h"
  27.  
  28. #include "appenv.h"
  29. #include "channel.h"
  30. #include "drawable.h"
  31. #include "gdisplay.h"
  32. #include "gimage_mask.h"
  33. #include "layer.h"
  34. #include "paint_funcs.h"
  35. #include "parasitelist.h"
  36. #include "temp_buf.h"
  37. #include "undo.h"
  38. #include "gimpsignal.h"
  39. #include "gimppreviewcache.h"
  40.  
  41. #include "channel_pvt.h"
  42. #include "tile.h"
  43.  
  44. #include "gimplut.h"
  45. #include "lut_funcs.h"
  46.  
  47. #include "libgimp/gimpmath.h"
  48.  
  49. #include "libgimp/gimpintl.h"
  50.  
  51.  
  52. enum {
  53.   REMOVED,
  54.   LAST_SIGNAL
  55. };
  56.  
  57. static void gimp_channel_class_init (GimpChannelClass *klass);
  58. static void gimp_channel_init       (GimpChannel      *channel);
  59. static void gimp_channel_destroy    (GtkObject        *object);
  60.  
  61. static TempBuf * channel_preview_private (Channel *channel,
  62.                       gint     width,
  63.                       gint     height);
  64.  
  65. static guint channel_signals[LAST_SIGNAL] = { 0 };
  66.  
  67. static GimpDrawableClass *parent_class = NULL;
  68.  
  69. GtkType
  70. gimp_channel_get_type ()
  71. {
  72.   static GtkType channel_type = 0;
  73.  
  74.   if (!channel_type)
  75.     {
  76.       GtkTypeInfo channel_info =
  77.       {
  78.     "GimpChannel",
  79.     sizeof (GimpChannel),
  80.     sizeof (GimpChannelClass),
  81.     (GtkClassInitFunc) gimp_channel_class_init,
  82.     (GtkObjectInitFunc) gimp_channel_init,
  83.         /* reserved_1 */ NULL,
  84.     /* reserved_2 */ NULL,
  85.     (GtkClassInitFunc) NULL,
  86.       };
  87.  
  88.       channel_type = gtk_type_unique (gimp_drawable_get_type (), &channel_info);
  89.     }
  90.  
  91.   return channel_type;
  92. }
  93.  
  94. static void
  95. gimp_channel_class_init (GimpChannelClass *class)
  96. {
  97.   GtkObjectClass *object_class;
  98.  
  99.   object_class = (GtkObjectClass*) class;
  100.   parent_class = gtk_type_class (gimp_drawable_get_type ());
  101.  
  102.   channel_signals[REMOVED] =
  103.       gimp_signal_new ("removed",
  104.                0, object_class->type, 0, gimp_sigtype_void);
  105.  
  106.   gtk_object_class_add_signals (object_class, channel_signals, LAST_SIGNAL);
  107.  
  108.   object_class->destroy = gimp_channel_destroy;
  109. }
  110.  
  111. static void
  112. gimp_channel_init (GimpChannel *channel)
  113. {
  114. }
  115.  
  116. /**************************/
  117. /*  Function definitions  */
  118. /**************************/
  119.  
  120. static void
  121. channel_validate (TileManager *tm,
  122.           Tile        *tile)
  123. {
  124.   /*  Set the contents of the tile to empty  */
  125.   memset (tile_data_pointer (tile, 0, 0), 
  126.       TRANSPARENT_OPACITY, tile_size (tile));
  127. }
  128.  
  129. Channel *
  130. channel_new (GimpImage *gimage,
  131.          gint       width,
  132.          gint       height,
  133.          gchar     *name,
  134.          gint       opacity,
  135.          guchar    *col)
  136. {
  137.   Channel * channel;
  138.   gint i;
  139.  
  140.   channel = gtk_type_new (gimp_channel_get_type ());
  141.  
  142.   gimp_drawable_configure (GIMP_DRAWABLE (channel), 
  143.                gimage, width, height, GRAY_GIMAGE, name);
  144.  
  145.   /*  set the channel color and opacity  */
  146.   for (i = 0; i < 3; i++)
  147.     channel->col[i] = col[i];
  148.  
  149.   channel->opacity     = opacity;
  150.   channel->show_masked = TRUE;
  151.  
  152.   /*  selection mask variables  */
  153.   channel->empty          = TRUE;
  154.   channel->segs_in        = NULL;
  155.   channel->segs_out       = NULL;
  156.   channel->num_segs_in    = 0;
  157.   channel->num_segs_out   = 0;
  158.   channel->bounds_known   = TRUE;
  159.   channel->boundary_known = TRUE;
  160.   channel->x1             = 0;
  161.   channel->y1             = 0;
  162.   channel->x2             = width;
  163.   channel->y2             = height;
  164.  
  165.   return channel;
  166. }
  167.  
  168. Channel *
  169. channel_ref (Channel *channel)
  170. {
  171.   gtk_object_ref  (GTK_OBJECT (channel));
  172.   gtk_object_sink (GTK_OBJECT (channel));
  173.  
  174.   return channel;
  175. }
  176.  
  177. void
  178. channel_unref (Channel *channel)
  179. {
  180.   gtk_object_unref (GTK_OBJECT (channel));
  181. }
  182.  
  183. Channel *
  184. channel_copy (Channel *channel)
  185. {
  186.   gchar *channel_name;
  187.   Channel *new_channel;
  188.   PixelRegion srcPR, destPR;
  189.   gchar *ext;
  190.   gint number;
  191.   gchar *name;
  192.   gint len;
  193.  
  194.   /*  formulate the new channel name  */
  195.   name = channel_get_name (channel);
  196.   ext = strrchr (name, '#');
  197.   len = strlen (_("copy"));
  198.   if ((strlen (name) >= len &&
  199.        strcmp (&name[strlen (name) - len], _("copy")) == 0) ||
  200.       (ext && (number = atoi (ext + 1)) > 0 && 
  201.        ((int)(log10 (number) + 1)) == strlen (ext + 1)))
  202.     /* don't have redundant "copy"s */
  203.     channel_name = g_strdup (name);
  204.   else
  205.     channel_name = g_strdup_printf (_("%s copy"), name);
  206.  
  207.   /*  allocate a new channel object  */
  208.   new_channel = channel_new (GIMP_DRAWABLE (channel)->gimage, 
  209.                  GIMP_DRAWABLE (channel)->width, 
  210.                  GIMP_DRAWABLE (channel)->height, 
  211.                  channel_name, channel->opacity, channel->col);
  212.   GIMP_DRAWABLE (new_channel)->visible = GIMP_DRAWABLE (channel)->visible;
  213.   new_channel->show_masked = channel->show_masked;
  214.  
  215.   /*  copy the contents across channels  */
  216.   pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles, 0, 0, 
  217.              GIMP_DRAWABLE (channel)->width, 
  218.              GIMP_DRAWABLE (channel)->height, FALSE);
  219.   pixel_region_init (&destPR, GIMP_DRAWABLE (new_channel)->tiles,
  220.              0, 0,
  221.              GIMP_DRAWABLE (channel)->width,
  222.              GIMP_DRAWABLE (channel)->height, TRUE);
  223.   copy_region (&srcPR, &destPR);
  224.  
  225.   /* copy the parasites */
  226.   GIMP_DRAWABLE (new_channel)->parasites 
  227.     = parasite_list_copy (GIMP_DRAWABLE (channel)->parasites);
  228.  
  229.   /*  free up the channel_name memory  */
  230.   g_free (channel_name);
  231.  
  232.   return new_channel;
  233. }
  234.  
  235. void
  236. channel_set_name (Channel *channel,
  237.           gchar   *name)
  238. {
  239.   gimp_drawable_set_name (GIMP_DRAWABLE (channel), name);
  240. }
  241.  
  242. gchar *
  243. channel_get_name (Channel *channel)
  244. {
  245.   return gimp_drawable_get_name (GIMP_DRAWABLE (channel));
  246. }
  247.  
  248. void 
  249. channel_set_color (Channel *channel,
  250.            guchar  *color)
  251. {
  252.   gint i;
  253.  
  254.   if (color)
  255.     {  
  256.       for (i = 0; i < 3; i++)
  257.     channel->col[i] = color[i];
  258.     }
  259. }
  260.  
  261. guchar *
  262. channel_get_color (Channel *channel)
  263. {
  264.   return (GIMP_CHANNEL (channel)->col); 
  265. }
  266.  
  267. int
  268. channel_get_opacity (Channel *channel)
  269.   return channel->opacity;
  270. }
  271.  
  272. void 
  273. channel_set_opacity (Channel *channel,
  274.              gint     opacity)
  275. {
  276.   if (opacity >=0 && opacity <= 100)
  277.     channel->opacity = (gint) (opacity * 255) / 100;
  278. }
  279.  
  280. Channel *
  281. channel_get_ID (gint ID)
  282. {
  283.   GimpDrawable *drawable;
  284.  
  285.   drawable = drawable_get_ID (ID);
  286.   if (drawable && GIMP_IS_CHANNEL (drawable)) 
  287.     return GIMP_CHANNEL (drawable);
  288.   else
  289.     return NULL;
  290. }
  291.  
  292. void
  293. channel_delete (Channel *channel)
  294. {
  295.   gtk_object_unref (GTK_OBJECT (channel));
  296. }
  297.  
  298. static void
  299. gimp_channel_destroy (GtkObject *object)
  300. {
  301.   GimpChannel *channel;
  302.  
  303.   g_return_if_fail (object != NULL);
  304.   g_return_if_fail (GIMP_IS_CHANNEL (object));
  305.  
  306.   channel = GIMP_CHANNEL (object);
  307.  
  308.   /* free the segments?  */
  309.   if (channel->segs_in)
  310.     g_free (channel->segs_in);
  311.   if (channel->segs_out)
  312.     g_free (channel->segs_out);
  313.  
  314.   if (GTK_OBJECT_CLASS (parent_class)->destroy)
  315.     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
  316.   
  317. }
  318.  
  319. /* The removed signal is sent out when the channel is no longer
  320.  * associcated with an image.  It's needed because channels aren't
  321.  * destroyed immediately, but kept around for undo purposes.  Connect
  322.  * to the removed signal to update bits of UI that are tied to a
  323.  * particular layer. */
  324. void
  325. channel_removed (Channel  *channel,
  326.          gpointer  data)
  327. {
  328.   g_return_if_fail (channel != NULL);
  329.   g_return_if_fail (GIMP_IS_CHANNEL (channel));
  330.  
  331.   gtk_signal_emit (GTK_OBJECT (channel), channel_signals[REMOVED]);
  332. }
  333.  
  334.  
  335. void
  336. channel_scale (Channel *channel,
  337.            gint     new_width,
  338.            gint     new_height)
  339. {
  340.   PixelRegion srcPR, destPR;
  341.   TileManager *new_tiles;
  342.  
  343.   if (new_width == 0 || new_height == 0)
  344.     return;
  345.  
  346.   /*  Update the old channel position  */
  347.   drawable_update (GIMP_DRAWABLE (channel),
  348.            0, 0,
  349.            GIMP_DRAWABLE (channel)->width,
  350.            GIMP_DRAWABLE (channel)->height);
  351.  
  352.   /*  Configure the pixel regions  */
  353.   pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
  354.              0, 0,
  355.              GIMP_DRAWABLE (channel)->width,
  356.              GIMP_DRAWABLE (channel)->height, FALSE);
  357.  
  358.   /*  Allocate the new channel, configure dest region  */
  359.   new_tiles = tile_manager_new (new_width, new_height, 1);
  360.   pixel_region_init (&destPR, new_tiles, 0, 0, new_width, new_height, TRUE);
  361.  
  362.   /*  Add an alpha channel  */
  363.   scale_region (&srcPR, &destPR);
  364.  
  365.   /*  Push the channel on the undo stack  */
  366.   undo_push_channel_mod (GIMP_DRAWABLE (channel)->gimage, channel);
  367.  
  368.   /*  Configure the new channel  */
  369.   GIMP_DRAWABLE (channel)->tiles = new_tiles;
  370.   GIMP_DRAWABLE (channel)->width = new_width;
  371.   GIMP_DRAWABLE (channel)->height = new_height;
  372.  
  373.   /*  bounds are now unknown  */
  374.   channel->bounds_known = FALSE;
  375.  
  376.   /*  Update the new channel position  */
  377.   drawable_update (GIMP_DRAWABLE (channel),
  378.            0, 0,
  379.            GIMP_DRAWABLE (channel)->width,
  380.            GIMP_DRAWABLE (channel)->height);
  381. }
  382.  
  383. void
  384. channel_resize (Channel *channel,
  385.         gint     new_width,
  386.         gint     new_height,
  387.         gint     offx,
  388.         gint     offy)
  389. {
  390.   PixelRegion srcPR, destPR;
  391.   TileManager *new_tiles;
  392.   guchar bg = 0;
  393.   gint clear;
  394.   gint w, h;
  395.   gint x1, y1, x2, y2;
  396.  
  397.   if (!new_width || !new_height)
  398.     return;
  399.  
  400.   x1 = CLAMP (offx, 0, new_width);
  401.   y1 = CLAMP (offy, 0, new_height);
  402.   x2 = CLAMP ((offx + GIMP_DRAWABLE (channel)->width), 0, new_width);
  403.   y2 = CLAMP ((offy + GIMP_DRAWABLE (channel)->height), 0, new_height);
  404.   w = x2 - x1;
  405.   h = y2 - y1;
  406.  
  407.   if (offx > 0)
  408.     {
  409.       x1 = 0;
  410.       x2 = offx;
  411.     }
  412.   else
  413.     {
  414.       x1 = -offx;
  415.       x2 = 0;
  416.     }
  417.  
  418.   if (offy > 0)
  419.     {
  420.       y1 = 0;
  421.       y2 = offy;
  422.     }
  423.   else
  424.     {
  425.       y1 = -offy;
  426.       y2 = 0;
  427.     }
  428.  
  429.   /*  Update the old channel position  */
  430.   drawable_update (GIMP_DRAWABLE (channel),
  431.            0, 0,
  432.            GIMP_DRAWABLE (channel)->width,
  433.            GIMP_DRAWABLE (channel)->height);
  434.  
  435.   /*  Configure the pixel regions  */
  436.   pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
  437.              x1, y1, w, h, FALSE);
  438.  
  439.   /*  Determine whether the new channel needs to be initially cleared  */
  440.   if ((new_width  > GIMP_DRAWABLE (channel)->width) ||
  441.       (new_height > GIMP_DRAWABLE (channel)->height) ||
  442.       (x2 || y2))
  443.     clear = TRUE;
  444.   else
  445.     clear = FALSE;
  446.  
  447.   /*  Allocate the new channel, configure dest region  */
  448.   new_tiles = tile_manager_new (new_width, new_height, 1);
  449.  
  450.   /*  Set to black (empty--for selections)  */
  451.   if (clear)
  452.     {
  453.       pixel_region_init (&destPR, new_tiles, 0, 0, new_width, new_height, TRUE);
  454.       color_region (&destPR, &bg);
  455.     }
  456.  
  457.   /*  copy from the old to the new  */
  458.   pixel_region_init (&destPR, new_tiles, x2, y2, w, h, TRUE);
  459.   if (w && h)
  460.     copy_region (&srcPR, &destPR);
  461.  
  462.   /*  Push the channel on the undo stack  */
  463.   undo_push_channel_mod (GIMP_DRAWABLE (channel)->gimage, channel);
  464.  
  465.   /*  Configure the new channel  */
  466.   GIMP_DRAWABLE (channel)->tiles  = new_tiles;
  467.   GIMP_DRAWABLE (channel)->width  = new_width;
  468.   GIMP_DRAWABLE (channel)->height = new_height;
  469.  
  470.   /*  bounds are now unknown  */
  471.   channel->bounds_known = FALSE;
  472.  
  473.   /*  update the new channel area  */
  474.   drawable_update (GIMP_DRAWABLE (channel),
  475.            0, 0,
  476.            GIMP_DRAWABLE (channel)->width,
  477.            GIMP_DRAWABLE (channel)->height);
  478. }
  479.  
  480. void            
  481. channel_update (Channel *channel)
  482. {
  483.   drawable_update (GIMP_DRAWABLE (channel),
  484.            0, 0,
  485.            GIMP_DRAWABLE (channel)->width,
  486.            GIMP_DRAWABLE (channel)->height);
  487.   gdisplays_flush ();
  488. }
  489.  
  490. /**********************/
  491. /*  access functions  */
  492. /**********************/
  493.  
  494. gboolean
  495. channel_toggle_visibility (Channel *channel)
  496. {
  497.   GIMP_DRAWABLE (channel)->visible = !GIMP_DRAWABLE (channel)->visible;
  498.  
  499.   return GIMP_DRAWABLE (channel)->visible;
  500. }
  501.  
  502. TempBuf *
  503. channel_preview (Channel *channel,
  504.          gint     width,
  505.          gint     height)
  506. {
  507.   /* Ok prime the cache with a large preview if the cache is invalid */
  508.   if (! GIMP_DRAWABLE (channel)->preview_valid &&
  509.       width  <= PREVIEW_CACHE_PRIME_WIDTH    &&
  510.       height <= PREVIEW_CACHE_PRIME_HEIGHT   &&
  511.       GIMP_DRAWABLE (channel)->gimage          &&
  512.       GIMP_DRAWABLE (channel)->gimage->width  > PREVIEW_CACHE_PRIME_WIDTH   &&
  513.       GIMP_DRAWABLE (channel)->gimage->height > PREVIEW_CACHE_PRIME_HEIGHT)
  514.     {
  515.       TempBuf * tb = channel_preview_private (channel,
  516.                           PREVIEW_CACHE_PRIME_WIDTH,
  517.                           PREVIEW_CACHE_PRIME_HEIGHT);
  518.       
  519.       /* Save the 2nd call */
  520.       if (width  == PREVIEW_CACHE_PRIME_WIDTH &&
  521.       height == PREVIEW_CACHE_PRIME_HEIGHT)
  522.     return tb;
  523.     }
  524.  
  525.   /* Second call - should NOT visit the tile cache...*/
  526.   return channel_preview_private (channel, width, height);
  527. }
  528.  
  529. static TempBuf *
  530. channel_preview_private (Channel *channel,
  531.              gint     width,
  532.              gint     height)
  533. {
  534.   MaskBuf     *preview_buf;
  535.   PixelRegion  srcPR;
  536.   PixelRegion  destPR;
  537.   gint         subsample;
  538.   TempBuf     *ret_buf;
  539.  
  540.   g_return_val_if_fail (channel != NULL, NULL);
  541.   g_return_val_if_fail (GIMP_IS_CHANNEL (channel), NULL);
  542.   
  543.   /*  The easy way  */
  544.   if (GIMP_DRAWABLE (channel)->preview_valid &&
  545.       (ret_buf =
  546.        gimp_preview_cache_get (& (GIMP_DRAWABLE (channel)->preview_cache),
  547.                    width, height)))
  548.     return ret_buf;
  549.   /*  The hard way  */
  550.   else
  551.     {
  552.       /*  calculate 'acceptable' subsample  */
  553.       subsample = 1;
  554.       if (width < 1) width = 1;
  555.       if (height < 1) height = 1;
  556.       while ((width  * (subsample + 1) * 2 < GIMP_DRAWABLE (channel)->width) &&
  557.          (height * (subsample + 1) * 2 < GIMP_DRAWABLE (channel)->height))
  558.     subsample = subsample + 1;
  559.  
  560.       pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
  561.              0, 0,
  562.              GIMP_DRAWABLE (channel)->width,
  563.              GIMP_DRAWABLE (channel)->height, FALSE);
  564.  
  565.       preview_buf = mask_buf_new (width, height);
  566.       destPR.bytes     = 1;
  567.       destPR.x         = 0;
  568.       destPR.y         = 0;
  569.       destPR.w         = width;
  570.       destPR.h         = height;
  571.       destPR.rowstride = width;
  572.       destPR.data      = mask_buf_data (preview_buf);
  573.  
  574.       subsample_region (&srcPR, &destPR, subsample);
  575.  
  576.       if (!GIMP_DRAWABLE (channel)->preview_valid)
  577.     gimp_preview_cache_invalidate (&(GIMP_DRAWABLE(channel)->preview_cache));
  578.  
  579.       GIMP_DRAWABLE (channel)->preview_valid = TRUE;
  580.       gimp_preview_cache_add (&(GIMP_DRAWABLE (channel)->preview_cache),
  581.                   preview_buf);
  582.       return preview_buf;
  583.     }
  584. }
  585.  
  586. void
  587. channel_invalidate_previews (GimpImage* gimage)
  588. {
  589.   GSList * tmp;
  590.   Channel * channel;
  591.  
  592.   g_return_if_fail (gimage != NULL);
  593.  
  594.   tmp = gimage->channels;
  595.  
  596.   while (tmp)
  597.     {
  598.       channel = (Channel *) tmp->data;
  599.       gimp_drawable_invalidate_preview (GIMP_DRAWABLE (channel), TRUE);
  600.       tmp = g_slist_next (tmp);
  601.     }
  602. }
  603.  
  604. Tattoo
  605. channel_get_tattoo (const Channel *channel)
  606. {
  607.   return (gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)));
  608. }
  609.  
  610. void
  611. channel_set_tattoo (const Channel *channel, 
  612.             Tattoo         value)
  613. {
  614.   gimp_drawable_set_tattoo (GIMP_DRAWABLE (channel), value);
  615. }
  616.  
  617. /******************************/
  618. /*  selection mask functions  */
  619. /******************************/
  620.  
  621. Channel *
  622. channel_new_mask (GimpImage *gimage,
  623.           gint       width,
  624.           gint       height)
  625. {
  626.   guchar black[3] = {0, 0, 0};
  627.   Channel *new_channel;
  628.  
  629.   /*  Create the new channel  */
  630.   new_channel = channel_new (gimage, width, height,
  631.                  _("Selection Mask"), 127, black);
  632.  
  633.   /*  Set the validate procedure  */
  634.   tile_manager_set_validate_proc (GIMP_DRAWABLE (new_channel)->tiles,
  635.                   channel_validate);
  636.  
  637.   return new_channel;
  638. }
  639.  
  640. gboolean
  641. channel_boundary (Channel   *mask,
  642.           BoundSeg **segs_in,
  643.           BoundSeg **segs_out,
  644.           gint      *num_segs_in,
  645.           gint      *num_segs_out,
  646.           gint       x1,
  647.           gint       y1,
  648.           gint       x2,
  649.           gint       y2)
  650. {
  651.   gint x3, y3, x4, y4;
  652.   PixelRegion bPR;
  653.  
  654.   if (! mask->boundary_known)
  655.     {
  656.       /* free the out of date boundary segments */
  657.       if (mask->segs_in)
  658.     g_free (mask->segs_in);
  659.       if (mask->segs_out)
  660.     g_free (mask->segs_out);
  661.  
  662.       if (channel_bounds (mask, &x3, &y3, &x4, &y4))
  663.     {
  664.       pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles,
  665.                  x3, y3, (x4 - x3), (y4 - y3), FALSE);
  666.       mask->segs_out = find_mask_boundary (&bPR, &mask->num_segs_out,
  667.                            IgnoreBounds,
  668.                            x1, y1,
  669.                            x2, y2);
  670.       x1 = MAX (x1, x3);
  671.       y1 = MAX (y1, y3);
  672.       x2 = MIN (x2, x4);
  673.       y2 = MIN (y2, y4);
  674.  
  675.       if (x2 > x1 && y2 > y1)
  676.         {
  677.           pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles,
  678.                  0, 0,
  679.                  GIMP_DRAWABLE (mask)->width,
  680.                  GIMP_DRAWABLE (mask)->height, FALSE);
  681.           mask->segs_in =  find_mask_boundary (&bPR, &mask->num_segs_in,
  682.                            WithinBounds,
  683.                            x1, y1,
  684.                            x2, y2);
  685.         }
  686.       else
  687.         {
  688.           mask->segs_in     = NULL;
  689.           mask->num_segs_in = 0;
  690.         }
  691.     }
  692.       else
  693.     {
  694.       mask->segs_in      = NULL;
  695.       mask->segs_out     = NULL;
  696.       mask->num_segs_in  = 0;
  697.       mask->num_segs_out = 0;
  698.     }
  699.       mask->boundary_known = TRUE;
  700.     }
  701.  
  702.   *segs_in      = mask->segs_in;
  703.   *segs_out     = mask->segs_out;
  704.   *num_segs_in  = mask->num_segs_in;
  705.   *num_segs_out = mask->num_segs_out;
  706.  
  707.   return TRUE;
  708. }
  709.  
  710. gint
  711. channel_value (Channel *mask,
  712.            gint     x,
  713.            gint     y)
  714. {
  715.   Tile *tile;
  716.   gint val;
  717.  
  718.   /*  Some checks to cut back on unnecessary work  */
  719.   if (mask->bounds_known)
  720.     {
  721.       if (mask->empty)
  722.     return 0;
  723.       else if (x < mask->x1 || x >= mask->x2 || y < mask->y1 || y >= mask->y2)
  724.     return 0;
  725.     }
  726.   else
  727.     {
  728.       if (x < 0 || x >= GIMP_DRAWABLE (mask)->width ||
  729.       y < 0 || y >= GIMP_DRAWABLE (mask)->height)
  730.     return 0;
  731.     }
  732.  
  733.   tile = tile_manager_get_tile (GIMP_DRAWABLE (mask)->tiles, x, y, TRUE, FALSE);
  734.   val = *(guchar *) (tile_data_pointer (tile, x % TILE_WIDTH, y % TILE_HEIGHT));
  735.   tile_release (tile, FALSE);
  736.  
  737.   return val;
  738. }
  739.  
  740. gboolean
  741. channel_bounds (Channel *mask,
  742.         gint    *x1,
  743.         gint    *y1,
  744.         gint    *x2,
  745.         gint    *y2)
  746. {
  747.   PixelRegion maskPR;
  748.   guchar *data, *data1;
  749.   gint x, y;
  750.   gint ex, ey;
  751.   gint tx1, tx2, ty1, ty2;
  752.   gint minx, maxx;
  753.   gpointer pr;
  754.  
  755.   /*  if the mask's bounds have already been reliably calculated...  */
  756.   if (mask->bounds_known)
  757.     {
  758.       *x1 = mask->x1;
  759.       *y1 = mask->y1;
  760.       *x2 = mask->x2;
  761.       *y2 = mask->y2;
  762.  
  763.       return !mask->empty;
  764.     }
  765.  
  766.   /*  go through and calculate the bounds  */
  767.   tx1 = GIMP_DRAWABLE (mask)->width;
  768.   ty1 = GIMP_DRAWABLE (mask)->height;
  769.   tx2 = 0;
  770.   ty2 = 0;
  771.  
  772.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  773.              0, 0,
  774.              GIMP_DRAWABLE (mask)->width,
  775.              GIMP_DRAWABLE (mask)->height, FALSE);
  776.   for (pr = pixel_regions_register (1, &maskPR);
  777.        pr != NULL;
  778.        pr = pixel_regions_process (pr))
  779.     {
  780.       data1 = data = maskPR.data;
  781.       ex = maskPR.x + maskPR.w;
  782.       ey = maskPR.y + maskPR.h;
  783.       /* only check the pixels if this tile is not fully within the currently
  784.      computed bounds */
  785.       if (maskPR.x < tx1 || ex > tx2 ||
  786.       maskPR.y < ty1 || ey > ty2)
  787.         {
  788.       /* Check upper left and lower right corners to see if we can
  789.          avoid checking the rest of the pixels in this tile */
  790.       if (data[0] && data[maskPR.rowstride*(maskPR.h - 1) + maskPR.w - 1])
  791.       {
  792.         if (maskPR.x < tx1)
  793.           tx1 = maskPR.x;
  794.         if (ex > tx2)
  795.           tx2 = ex;
  796.         if (maskPR.y < ty1)
  797.           ty1 = maskPR.y;
  798.         if (ey > ty2)
  799.           ty2 = ey;
  800.       }
  801.       else
  802.         for (y = maskPR.y; y < ey; y++, data1 += maskPR.rowstride)
  803.         {
  804.           for (x = maskPR.x, data = data1; x < ex; x++, data++)
  805.         if (*data)
  806.         {
  807.           minx = x;
  808.           maxx = x;
  809.           for (; x < ex; x++, data++)
  810.             if (*data)
  811.               maxx = x;
  812.           if (minx < tx1)
  813.             tx1 = minx;
  814.           if (maxx > tx2)
  815.             tx2 = maxx;
  816.           if (y < ty1)
  817.             ty1 = y;
  818.           if (y > ty2)
  819.             ty2 = y;
  820.           }
  821.         }
  822.     }
  823.     }
  824.  
  825.   tx2 = CLAMP (tx2 + 1, 0, GIMP_DRAWABLE (mask)->width);
  826.   ty2 = CLAMP (ty2 + 1, 0, GIMP_DRAWABLE (mask)->height);
  827.  
  828.   if (tx1 == GIMP_DRAWABLE (mask)->width && ty1 == GIMP_DRAWABLE (mask)->height)
  829.     {
  830.       mask->empty = TRUE;
  831.       mask->x1    = 0;
  832.       mask->y1    = 0;
  833.       mask->x2    = GIMP_DRAWABLE (mask)->width;
  834.       mask->y2    = GIMP_DRAWABLE (mask)->height;
  835.     }
  836.   else
  837.     {
  838.       mask->empty = FALSE;
  839.       mask->x1    = tx1;
  840.       mask->y1    = ty1;
  841.       mask->x2    = tx2;
  842.       mask->y2    = ty2;
  843.     }
  844.   mask->bounds_known = TRUE;
  845.  
  846.   *x1 = tx1;
  847.   *x2 = tx2;
  848.   *y1 = ty1;
  849.   *y2 = ty2;
  850.  
  851.   return !mask->empty;
  852. }
  853.  
  854. gboolean
  855. channel_is_empty (Channel *mask)
  856. {
  857.   PixelRegion maskPR;
  858.   guchar * data;
  859.   gint x, y;
  860.   gpointer pr;
  861.  
  862.   if (mask->bounds_known)
  863.     return mask->empty;
  864.  
  865.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  866.              0, 0,
  867.              GIMP_DRAWABLE (mask)->width,
  868.              GIMP_DRAWABLE (mask)->height, FALSE);
  869.   for (pr = pixel_regions_register (1, &maskPR);
  870.        pr != NULL;
  871.        pr = pixel_regions_process (pr))
  872.     {
  873.       /*  check if any pixel in the mask is non-zero  */
  874.       data = maskPR.data;
  875.       for (y = 0; y < maskPR.h; y++)
  876.     for (x = 0; x < maskPR.w; x++)
  877.       if (*data++)
  878.         {
  879.           pixel_regions_process_stop (pr);
  880.           return FALSE;
  881.         }
  882.     }
  883.  
  884.   /*  The mask is empty, meaning we can set the bounds as known  */
  885.   if (mask->segs_in)
  886.     g_free (mask->segs_in);
  887.   if (mask->segs_out)
  888.     g_free (mask->segs_out);
  889.  
  890.   mask->empty          = TRUE;
  891.   mask->segs_in        = NULL;
  892.   mask->segs_out       = NULL;
  893.   mask->num_segs_in    = 0;
  894.   mask->num_segs_out   = 0;
  895.   mask->bounds_known   = TRUE;
  896.   mask->boundary_known = TRUE;
  897.   mask->x1             = 0;
  898.   mask->y1             = 0;
  899.   mask->x2             = GIMP_DRAWABLE (mask)->width;
  900.   mask->y2             = GIMP_DRAWABLE (mask)->height;
  901.  
  902.   return TRUE;
  903. }
  904.  
  905. void
  906. channel_add_segment (Channel *mask,
  907.              gint     x,
  908.              gint     y,
  909.              gint     width,
  910.              gint     value)
  911. {
  912.   PixelRegion maskPR;
  913.   guchar *data;
  914.   gint val;
  915.   gint x2;
  916.   gpointer pr;
  917.  
  918.   /*  check horizontal extents...  */
  919.   x2 = x + width;
  920.   if (x2 < 0) x2 = 0;
  921.   if (x2 > GIMP_DRAWABLE (mask)->width) x2 = GIMP_DRAWABLE (mask)->width;
  922.   if (x < 0) x = 0;
  923.   if (x > GIMP_DRAWABLE (mask)->width) x = GIMP_DRAWABLE (mask)->width;
  924.   width = x2 - x;
  925.   if (!width) return;
  926.  
  927.   if (y < 0 || y > GIMP_DRAWABLE (mask)->height)
  928.     return;
  929.  
  930.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  931.              x, y, width, 1, TRUE);
  932.   for (pr = pixel_regions_register (1, &maskPR);
  933.        pr != NULL;
  934.        pr = pixel_regions_process (pr))
  935.     {
  936.       data = maskPR.data;
  937.       width = maskPR.w;
  938.       while (width--)
  939.     {
  940.       val = *data + value;
  941.       if (val > 255)
  942.         val = 255;
  943.       *data++ = val;
  944.     }
  945.     }
  946. }
  947.  
  948. void
  949. channel_sub_segment (Channel *mask,
  950.              gint     x,
  951.              gint     y,
  952.              gint     width,
  953.              gint     value)
  954. {
  955.   PixelRegion maskPR;
  956.   guchar *data;
  957.   gint val;
  958.   gint x2;
  959.   gpointer pr;
  960.  
  961.   /*  check horizontal extents...  */
  962.   x2 = x + width;
  963.   if (x2 < 0) x2 = 0;
  964.   if (x2 > GIMP_DRAWABLE (mask)->width) x2 = GIMP_DRAWABLE (mask)->width;
  965.   if (x < 0) x = 0;
  966.   if (x > GIMP_DRAWABLE (mask)->width) x = GIMP_DRAWABLE (mask)->width;
  967.   width = x2 - x;
  968.   if (!width) return;
  969.  
  970.   if (y < 0 || y > GIMP_DRAWABLE (mask)->height)
  971.     return;
  972.  
  973.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles, x, y, width, 1, TRUE);
  974.   for (pr = pixel_regions_register (1, &maskPR);
  975.        pr != NULL;
  976.        pr = pixel_regions_process (pr))
  977.     {
  978.       data = maskPR.data;
  979.       width = maskPR.w;
  980.       while (width--)
  981.     {
  982.       val = *data - value;
  983.       if (val < 0)
  984.         val = 0;
  985.       *data++ = val;
  986.     }
  987.     }
  988. }
  989.  
  990. void
  991. channel_combine_rect (Channel    *mask,
  992.               ChannelOps  op,
  993.               gint        x,
  994.               gint        y,
  995.               gint        w,
  996.               gint        h)
  997. {
  998.   gint x2, y2;
  999.   PixelRegion maskPR;
  1000.   guchar color;
  1001.  
  1002.   y2 = y + h;
  1003.   x2 = x + w;
  1004.  
  1005.   x  = CLAMP (x,  0, GIMP_DRAWABLE (mask)->width);
  1006.   y  = CLAMP (y,  0, GIMP_DRAWABLE (mask)->height);
  1007.   x2 = CLAMP (x2, 0, GIMP_DRAWABLE (mask)->width);
  1008.   y2 = CLAMP (y2, 0, GIMP_DRAWABLE (mask)->height);
  1009.  
  1010.   if (x2 - x <= 0 || y2 - y <= 0)
  1011.     return;
  1012.  
  1013.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  1014.              x, y, x2 - x, y2 - y, TRUE);
  1015.   if (op == ADD  || op == REPLACE)
  1016.     color = 255;
  1017.   else
  1018.     color = 0;
  1019.   color_region (&maskPR, &color);
  1020.  
  1021.   /*  Determine new boundary  */
  1022.   if (mask->bounds_known && (op == ADD) && !mask->empty)
  1023.     {
  1024.       if (x < mask->x1)
  1025.     mask->x1 = x;
  1026.       if (y < mask->y1)
  1027.     mask->y1 = y;
  1028.       if ((x + w) > mask->x2)
  1029.     mask->x2 = (x + w);
  1030.       if ((y + h) > mask->y2)
  1031.     mask->y2 = (y + h);
  1032.     }
  1033.   else if (op == REPLACE || mask->empty)
  1034.     {
  1035.       mask->empty = FALSE;
  1036.       mask->x1 = x;
  1037.       mask->y1 = y;
  1038.       mask->x2 = x + w;
  1039.       mask->y2 = y + h;
  1040.     }
  1041.   else
  1042.     mask->bounds_known = FALSE;
  1043.  
  1044.   mask->x1 = CLAMP (mask->x1, 0, GIMP_DRAWABLE (mask)->width);
  1045.   mask->y1 = CLAMP (mask->y1, 0, GIMP_DRAWABLE (mask)->height);
  1046.   mask->x2 = CLAMP (mask->x2, 0, GIMP_DRAWABLE (mask)->width);
  1047.   mask->y2 = CLAMP (mask->y2, 0, GIMP_DRAWABLE (mask)->height);
  1048. }
  1049.  
  1050. void
  1051. channel_combine_ellipse (Channel    *mask,
  1052.              ChannelOps  op,
  1053.              gint        x,
  1054.              gint        y,
  1055.              gint        w,
  1056.              gint        h,
  1057.              gboolean    antialias)
  1058. {
  1059.   gint i, j;
  1060.   gint x0, x1, x2;
  1061.   gint val, last;
  1062.   gfloat a_sqr, b_sqr, aob_sqr;
  1063.   gfloat w_sqr, h_sqr;
  1064.   gfloat y_sqr;
  1065.   gfloat t0, t1;
  1066.   gfloat r;
  1067.   gfloat cx, cy;
  1068.   gfloat rad;
  1069.   gfloat dist;
  1070.  
  1071.   if (!w || !h)
  1072.     return;
  1073.  
  1074.   a_sqr = (w * w / 4.0);
  1075.   b_sqr = (h * h / 4.0);
  1076.   aob_sqr = a_sqr / b_sqr;
  1077.  
  1078.   cx = x + w / 2.0;
  1079.   cy = y + h / 2.0;
  1080.  
  1081.   for (i = y; i < (y + h); i++)
  1082.     {
  1083.       if (i >= 0 && i < GIMP_DRAWABLE (mask)->height)
  1084.     {
  1085.       /*  Non-antialiased code  */
  1086.       if (!antialias)
  1087.         {
  1088.           y_sqr = (i + 0.5 - cy) * (i + 0.5 - cy);
  1089.           rad = sqrt (a_sqr - a_sqr * y_sqr / (double) b_sqr);
  1090.           x1 = ROUND (cx - rad);
  1091.           x2 = ROUND (cx + rad);
  1092.  
  1093.           switch (op)
  1094.         {
  1095.         case ADD: case REPLACE:
  1096.           channel_add_segment (mask, x1, i, (x2 - x1), 255);
  1097.           break;
  1098.         case SUB :
  1099.           channel_sub_segment (mask, x1, i, (x2 - x1), 255);
  1100.           break;
  1101.         default:
  1102.           g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
  1103.           break;
  1104.         }
  1105.         }
  1106.       /*  antialiasing  */
  1107.       else
  1108.         {
  1109.           x0 = x;
  1110.           last = 0;
  1111.           h_sqr = (i + 0.5 - cy) * (i + 0.5 - cy);
  1112.           for (j = x; j < (x + w); j++)
  1113.         {
  1114.           w_sqr = (j + 0.5 - cx) * (j + 0.5 - cx);
  1115.  
  1116.           if (h_sqr != 0)
  1117.             {
  1118.               t0 = w_sqr / h_sqr;
  1119.               t1 = a_sqr / (t0 + aob_sqr);
  1120.               r = sqrt (t1 + t0 * t1);
  1121.               rad = sqrt (w_sqr + h_sqr);
  1122.               dist = rad - r;
  1123.             }
  1124.           else
  1125.             dist = -1.0;
  1126.  
  1127.           if (dist < -0.5)
  1128.             val = 255;
  1129.           else if (dist < 0.5)
  1130.             val = (int) (255 * (1 - (dist + 0.5)));
  1131.           else
  1132.             val = 0;
  1133.           
  1134.           if (last != val && last)
  1135.             {
  1136.               switch (op)
  1137.             {
  1138.             case ADD: case REPLACE:
  1139.               channel_add_segment (mask, x0, i, j - x0, last);
  1140.               break;
  1141.             case SUB:
  1142.               channel_sub_segment (mask, x0, i, j - x0, last);
  1143.               break;
  1144.             default:
  1145.               g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
  1146.               break;
  1147.             }
  1148.             }
  1149.  
  1150.           if (last != val)
  1151.             {
  1152.               x0 = j;
  1153.               last = val;
  1154.               /* because we are symetric accross the y axis we can
  1155.              skip ahead a bit if we are inside the ellipse*/
  1156.               if (val == 255 && j < cx)
  1157.             j = cx + (cx - j) - 1;
  1158.             }
  1159.         }
  1160.  
  1161.           if (last)
  1162.         {
  1163.           if (op == ADD || op == REPLACE)
  1164.             channel_add_segment (mask, x0, i, j - x0, last);
  1165.           else if (op == SUB)
  1166.             channel_sub_segment (mask, x0, i, j - x0, last);
  1167.           else
  1168.             g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
  1169.         }
  1170.         }
  1171.  
  1172.     }
  1173.     }
  1174.  
  1175.   /*  Determine new boundary  */
  1176.   if (mask->bounds_known && (op == ADD) && !mask->empty)
  1177.     {
  1178.       if (x < mask->x1)
  1179.     mask->x1 = x;
  1180.       if (y < mask->y1)
  1181.     mask->y1 = y;
  1182.       if ((x + w) > mask->x2)
  1183.     mask->x2 = (x + w);
  1184.       if ((y + h) > mask->y2)
  1185.     mask->y2 = (y + h);
  1186.     }
  1187.   else if (op == REPLACE || mask->empty)
  1188.     {
  1189.       mask->empty = FALSE;
  1190.       mask->x1 = x;
  1191.       mask->y1 = y;
  1192.       mask->x2 = x + w;
  1193.       mask->y2 = y + h;
  1194.     }
  1195.   else
  1196.     mask->bounds_known = FALSE;
  1197.  
  1198.   mask->x1 = CLAMP (mask->x1, 0, GIMP_DRAWABLE (mask)->width);
  1199.   mask->y1 = CLAMP (mask->y1, 0, GIMP_DRAWABLE (mask)->height);
  1200.   mask->x2 = CLAMP (mask->x2, 0, GIMP_DRAWABLE (mask)->width);
  1201.   mask->y2 = CLAMP (mask->y2, 0, GIMP_DRAWABLE (mask)->height);
  1202. }
  1203.  
  1204. static void
  1205. channel_combine_sub_region_add (void        *unused,
  1206.                 PixelRegion *srcPR,
  1207.                 PixelRegion *destPR)
  1208. {
  1209.   guchar *src, *dest;
  1210.   gint x, y, val;
  1211.  
  1212.   src  = srcPR->data;
  1213.   dest = destPR->data;
  1214.  
  1215.   for (y = 0; y < srcPR->h; y++)
  1216.     {
  1217.       for (x = 0; x < srcPR->w; x++)
  1218.     {
  1219.       val = dest[x] + src[x];
  1220.       if (val > 255)
  1221.         dest[x] = 255;
  1222.       else
  1223.         dest[x] = val;
  1224.     }
  1225.       src  += srcPR->rowstride;
  1226.       dest += destPR->rowstride;
  1227.     }
  1228. }
  1229.  
  1230. static void
  1231. channel_combine_sub_region_sub (void        *unused,
  1232.                 PixelRegion *srcPR,
  1233.                 PixelRegion *destPR)
  1234. {
  1235.   guchar *src, *dest;
  1236.   gint x, y;
  1237.  
  1238.   src  = srcPR->data;
  1239.   dest = destPR->data;
  1240.  
  1241.   for (y = 0; y < srcPR->h; y++)
  1242.     {
  1243.       for (x = 0; x < srcPR->w; x++)
  1244.     {
  1245.       if (src[x] > dest[x])
  1246.         dest[x] = 0;
  1247.       else
  1248.         dest[x]-= src[x];
  1249.     }
  1250.       src  += srcPR->rowstride;
  1251.       dest += destPR->rowstride;
  1252.     }
  1253. }
  1254.  
  1255. static void
  1256. channel_combine_sub_region_intersect (void        *unused,
  1257.                       PixelRegion *srcPR,
  1258.                       PixelRegion *destPR)
  1259. {
  1260.   guchar *src, *dest;
  1261.   gint x, y;
  1262.  
  1263.   src  = srcPR->data;
  1264.   dest = destPR->data;
  1265.  
  1266.   for (y = 0; y < srcPR->h; y++)
  1267.     {
  1268.       for (x = 0; x < srcPR->w; x++)
  1269.     {
  1270.       dest[x] = MIN (dest[x], src[x]);
  1271.     }
  1272.       src  += srcPR->rowstride;
  1273.       dest += destPR->rowstride;
  1274.   }
  1275. }
  1276.  
  1277. void
  1278. channel_combine_mask (Channel    *mask,
  1279.               Channel    *add_on,
  1280.               ChannelOps  op,
  1281.               gint        off_x,
  1282.               gint        off_y)
  1283. {
  1284.   PixelRegion srcPR, destPR;
  1285.   gint x1, y1, x2, y2;
  1286.   gint w, h;
  1287.  
  1288.   x1 = CLAMP (off_x, 0, GIMP_DRAWABLE (mask)->width);
  1289.   y1 = CLAMP (off_y, 0, GIMP_DRAWABLE (mask)->height);
  1290.   x2 = CLAMP (off_x + GIMP_DRAWABLE (add_on)->width, 0,
  1291.           GIMP_DRAWABLE (mask)->width);
  1292.   y2 = CLAMP (off_y + GIMP_DRAWABLE (add_on)->height, 0,
  1293.           GIMP_DRAWABLE (mask)->height);
  1294.  
  1295.   w = (x2 - x1);
  1296.   h = (y2 - y1);
  1297.  
  1298.   pixel_region_init (&srcPR, GIMP_DRAWABLE (add_on)->tiles,
  1299.              (x1 - off_x), (y1 - off_y), w, h, FALSE);
  1300.   pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles, x1, y1, w, h, TRUE);
  1301.  
  1302.   switch (op)
  1303.     {
  1304.     case ADD: case REPLACE:
  1305.       pixel_regions_process_parallel ((p_func) channel_combine_sub_region_add,
  1306.                       NULL, 2, &srcPR, &destPR);
  1307.       break;
  1308.     case SUB:
  1309.       pixel_regions_process_parallel ((p_func) channel_combine_sub_region_sub,
  1310.                       NULL, 2, &srcPR, &destPR);
  1311.       break;
  1312.     case INTERSECT:
  1313.       pixel_regions_process_parallel ((p_func)
  1314.                       channel_combine_sub_region_intersect,
  1315.                       NULL, 2, &srcPR, &destPR);
  1316.       break;
  1317.     default:
  1318.       g_message ("Error: unknown opperation type in channel_combine_mask\n");
  1319.       break;
  1320.     }
  1321.   mask->bounds_known = FALSE;
  1322. }
  1323.  
  1324. void
  1325. channel_feather (Channel    *input,
  1326.          Channel    *output,
  1327.          gdouble     radius_x,
  1328.          gdouble     radius_y,
  1329.          ChannelOps  op,
  1330.          gint        off_x,
  1331.          gint        off_y)
  1332. {
  1333.   gint x1, y1, x2, y2;
  1334.   PixelRegion srcPR;
  1335.  
  1336.   x1 = CLAMP (off_x, 0, GIMP_DRAWABLE (output)->width);
  1337.   y1 = CLAMP (off_y, 0, GIMP_DRAWABLE (output)->height);
  1338.   x2 = CLAMP (off_x + GIMP_DRAWABLE (input)->width, 0,
  1339.           GIMP_DRAWABLE (output)->width);
  1340.   y2 = CLAMP (off_y + GIMP_DRAWABLE (input)->height, 0,
  1341.           GIMP_DRAWABLE (output)->height);
  1342.  
  1343.   pixel_region_init (&srcPR, GIMP_DRAWABLE (input)->tiles,
  1344.              (x1 - off_x), (y1 - off_y), (x2 - x1), (y2 - y1), FALSE);
  1345.   gaussian_blur_region (&srcPR, radius_x, radius_y);
  1346.  
  1347.   if (input != output) 
  1348.     channel_combine_mask (output, input, op, 0, 0);
  1349.  
  1350.   output->bounds_known = FALSE;
  1351. }
  1352.  
  1353. void
  1354. channel_push_undo (Channel *mask)
  1355. {
  1356.   gint x1, y1, x2, y2;
  1357.   MaskUndo *mask_undo;
  1358.   TileManager *undo_tiles;
  1359.   PixelRegion srcPR, destPR;
  1360.   GImage *gimage;
  1361.  
  1362.   mask_undo = g_new (MaskUndo, 1);
  1363.   if (channel_bounds (mask, &x1, &y1, &x2, &y2))
  1364.     {
  1365.       undo_tiles = tile_manager_new ((x2 - x1), (y2 - y1), 1);
  1366.       pixel_region_init (&srcPR, GIMP_DRAWABLE (mask)->tiles,
  1367.              x1, y1, (x2 - x1), (y2 - y1), FALSE);
  1368.       pixel_region_init (&destPR, undo_tiles, 0, 0, (x2 - x1), (y2 - y1), TRUE);
  1369.       copy_region (&srcPR, &destPR);
  1370.     }
  1371.   else
  1372.     undo_tiles = NULL;
  1373.  
  1374.   mask_undo->tiles = undo_tiles;
  1375.   mask_undo->x     = x1;
  1376.   mask_undo->y     = y1;
  1377.  
  1378.   /* push the undo buffer onto the undo stack */
  1379.   gimage = GIMP_DRAWABLE (mask)->gimage;
  1380.   undo_push_mask (gimage, mask_undo);
  1381.   gimage_mask_invalidate (gimage);
  1382.  
  1383.   /*  invalidate the preview  */
  1384.   GIMP_DRAWABLE (mask)->preview_valid = FALSE;
  1385. }
  1386.  
  1387. void
  1388. channel_clear (Channel *mask)
  1389. {
  1390.   PixelRegion maskPR;
  1391.   guchar bg = 0;
  1392.  
  1393.   /*  push the current channel onto the undo stack  */
  1394.   channel_push_undo (mask);
  1395.  
  1396.   if (mask->bounds_known && !mask->empty)
  1397.     {
  1398.       pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  1399.              mask->x1, mask->y1,
  1400.              (mask->x2 - mask->x1), (mask->y2 - mask->y1), TRUE);
  1401.       color_region (&maskPR, &bg);
  1402.     }
  1403.   else
  1404.     {
  1405.       /*  clear the mask  */
  1406.       pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  1407.              0, 0,
  1408.              GIMP_DRAWABLE (mask)->width,
  1409.              GIMP_DRAWABLE (mask)->height, TRUE);
  1410.       color_region (&maskPR, &bg);
  1411.     }
  1412.  
  1413.   /*  we know the bounds  */
  1414.   mask->bounds_known = TRUE;
  1415.   mask->empty        = TRUE;
  1416.   mask->x1           = 0;
  1417.   mask->y1           = 0;
  1418.   mask->x2           = GIMP_DRAWABLE (mask)->width;
  1419.   mask->y2           = GIMP_DRAWABLE (mask)->height;
  1420. }
  1421.  
  1422. void
  1423. channel_invert (Channel *mask)
  1424. {
  1425.   PixelRegion maskPR;
  1426.   GimpLut *lut;
  1427.  
  1428.   /*  push the current channel onto the undo stack  */
  1429.   channel_push_undo (mask);
  1430.  
  1431.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  1432.              0, 0,
  1433.              GIMP_DRAWABLE (mask)->width,
  1434.              GIMP_DRAWABLE (mask)->height, TRUE);
  1435.   
  1436.   lut = invert_lut_new (1);
  1437.  
  1438.   pixel_regions_process_parallel ((p_func) gimp_lut_process_inline,
  1439.                   lut, 1, &maskPR);
  1440.   gimp_lut_free (lut);
  1441.   mask->bounds_known = FALSE;
  1442. }
  1443.  
  1444. void
  1445. channel_sharpen (Channel *mask)
  1446. {
  1447.   PixelRegion maskPR;
  1448.   GimpLut *lut;
  1449.  
  1450.   /*  push the current channel onto the undo stack  */
  1451.   channel_push_undo (mask);
  1452.  
  1453.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  1454.              0, 0,
  1455.              GIMP_DRAWABLE (mask)->width,
  1456.              GIMP_DRAWABLE (mask)->height, TRUE);
  1457.   lut = threshold_lut_new (0.5, 1);
  1458.  
  1459.   pixel_regions_process_parallel ((p_func) gimp_lut_process_inline,
  1460.                   lut, 1, &maskPR);
  1461.   gimp_lut_free (lut);
  1462. }
  1463.  
  1464. void
  1465. channel_all (Channel *mask)
  1466. {
  1467.   PixelRegion maskPR;
  1468.   guchar bg = 255;
  1469.  
  1470.   /*  push the current channel onto the undo stack  */
  1471.   channel_push_undo (mask);
  1472.  
  1473.   /*  clear the mask  */
  1474.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  1475.              0, 0,
  1476.              GIMP_DRAWABLE (mask)->width,
  1477.              GIMP_DRAWABLE (mask)->height, TRUE);
  1478.   color_region (&maskPR, &bg);
  1479.  
  1480.   /*  we know the bounds  */
  1481.   mask->bounds_known = TRUE;
  1482.   mask->empty        = FALSE;
  1483.   mask->x1           = 0;
  1484.   mask->y1           = 0;
  1485.   mask->x2           = GIMP_DRAWABLE (mask)->width;
  1486.   mask->y2           = GIMP_DRAWABLE (mask)->height;
  1487. }
  1488.  
  1489. void
  1490. channel_border (Channel *mask,
  1491.         gint     radius_x,
  1492.         gint     radius_y)
  1493. {
  1494.   PixelRegion bPR;
  1495.   gint x1, y1, x2, y2;
  1496.  
  1497.   if (radius_x < 0 || radius_y < 0)
  1498.     return;
  1499.  
  1500.   if (! channel_bounds (mask, &x1, &y1, &x2, &y2))
  1501.     return;
  1502.   if (channel_is_empty (mask))
  1503.     return;
  1504.  
  1505.   if (x1 - radius_x < 0)
  1506.     x1 = 0;
  1507.   else
  1508.     x1 -= radius_x;
  1509.   if (x2 + radius_x > GIMP_DRAWABLE (mask)->width)
  1510.     x2 = GIMP_DRAWABLE (mask)->width;
  1511.   else
  1512.     x2 += radius_x;
  1513.  
  1514.   if (y1 - radius_y < 0)
  1515.     y1 = 0;
  1516.   else
  1517.     y1 -= radius_y;
  1518.   if (y2 + radius_y > GIMP_DRAWABLE (mask)->height)
  1519.     y2 = GIMP_DRAWABLE (mask)->height;
  1520.   else
  1521.     y2 += radius_y;
  1522.   /*  push the current channel onto the undo stack  */
  1523.   channel_push_undo (mask);
  1524.  
  1525.   pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles, x1, y1,
  1526.              (x2-x1), (y2-y1), TRUE);
  1527.  
  1528.   border_region (&bPR, radius_x, radius_y);
  1529.  
  1530.   mask->bounds_known = FALSE;
  1531. }
  1532.  
  1533. void
  1534. channel_grow (Channel *mask,
  1535.           gint     radius_x,
  1536.           gint     radius_y)
  1537. {
  1538.   PixelRegion bPR;
  1539.   gint x1, y1, x2, y2;
  1540.  
  1541.   if (radius_x == 0 && radius_y == 0)
  1542.     return;
  1543.  
  1544.   if (radius_x <= 0 && radius_y <= 0)
  1545.     {
  1546.       channel_shrink (mask, -radius_x, -radius_y, FALSE);
  1547.       return;
  1548.     }
  1549.  
  1550.   if (radius_x < 0 || radius_y < 0)
  1551.     return;
  1552.   
  1553.   if (! channel_bounds (mask, &x1, &y1, &x2, &y2))
  1554.     return;
  1555.   if (channel_is_empty (mask))
  1556.     return;
  1557.  
  1558.   if (x1 - radius_x > 0)
  1559.     x1 = x1 - radius_x;
  1560.   else
  1561.     x1 = 0;
  1562.   if (y1 - radius_y > 0)
  1563.     y1 = y1 - radius_y;
  1564.   else
  1565.     y1 = 0;
  1566.   if (x2 + radius_x < GIMP_DRAWABLE (mask)->width)
  1567.     x2 = x2 + radius_x;
  1568.   else
  1569.     x2 = GIMP_DRAWABLE (mask)->width;
  1570.   if (y2 + radius_y < GIMP_DRAWABLE (mask)->height)
  1571.     y2 = y2 + radius_y;
  1572.   else
  1573.     y2 = GIMP_DRAWABLE (mask)->height;
  1574.  
  1575.   /*  push the current channel onto the undo stack  */
  1576.   channel_push_undo (mask);
  1577.  
  1578.   /*  need full extents for grow, not! */
  1579.   pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles, x1, y1, (x2 - x1),
  1580.              (y2 - y1), TRUE);
  1581.  
  1582.   fatten_region (&bPR, radius_x, radius_y);
  1583.  
  1584.   mask->bounds_known = FALSE;
  1585. }
  1586.  
  1587. void
  1588. channel_shrink (Channel  *mask,
  1589.         gint      radius_x,
  1590.         gint      radius_y,
  1591.         gboolean  edge_lock)
  1592. {
  1593.   PixelRegion bPR;
  1594.   gint x1, y1, x2, y2;
  1595.  
  1596.   if (radius_x == 0 && radius_y == 0)
  1597.     return;
  1598.  
  1599.   if (radius_x <= 0 && radius_y <= 0)
  1600.     {
  1601.       channel_grow (mask, -radius_x, -radius_y);
  1602.       return;
  1603.     }
  1604.  
  1605.   if (radius_x < 0 || radius_y < 0)
  1606.     return;
  1607.   
  1608.   if (! channel_bounds (mask, &x1, &y1, &x2, &y2))
  1609.     return;
  1610.   if (channel_is_empty (mask))
  1611.     return;
  1612.  
  1613.   if (x1 > 0)
  1614.     x1--;
  1615.   if (y1 > 0)
  1616.     y1--;
  1617.   if (x2 < GIMP_DRAWABLE (mask)->width)
  1618.     x2++;
  1619.   if (y2 < GIMP_DRAWABLE (mask)->height)
  1620.     y2++;
  1621.  
  1622.   /*  push the current channel onto the undo stack  */
  1623.   channel_push_undo (mask);
  1624.  
  1625.   pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles, x1, y1, (x2 - x1),
  1626.              (y2 - y1), TRUE);
  1627.  
  1628.   thin_region (&bPR, radius_x, radius_y, edge_lock);
  1629.  
  1630.   mask->bounds_known = FALSE;
  1631. }
  1632.  
  1633. void
  1634. channel_translate (Channel *mask,
  1635.            gint     off_x,
  1636.            gint     off_y)
  1637. {
  1638.   gint width, height;
  1639.   Channel *tmp_mask;
  1640.   PixelRegion srcPR, destPR;
  1641.   guchar empty = 0;
  1642.   gint   x1, y1, x2, y2;
  1643.  
  1644.   tmp_mask = NULL;
  1645.  
  1646.   /*  push the current channel onto the undo stack  */
  1647.   channel_push_undo (mask);
  1648.  
  1649.   channel_bounds (mask, &x1, &y1, &x2, &y2);
  1650.   x1 = CLAMP ((x1 + off_x), 0, GIMP_DRAWABLE (mask)->width);
  1651.   y1 = CLAMP ((y1 + off_y), 0, GIMP_DRAWABLE (mask)->height);
  1652.   x2 = CLAMP ((x2 + off_x), 0, GIMP_DRAWABLE (mask)->width);
  1653.   y2 = CLAMP ((y2 + off_y), 0, GIMP_DRAWABLE (mask)->height);
  1654.  
  1655.   width = x2 - x1;
  1656.   height = y2 - y1;
  1657.  
  1658.   /*  make sure width and height are non-zero  */
  1659.   if (width != 0 && height != 0)
  1660.     {
  1661.       /*  copy the portion of the mask we will keep to a
  1662.        *  temporary buffer
  1663.        */
  1664.       tmp_mask = channel_new_mask (GIMP_DRAWABLE (mask)->gimage, width, height);
  1665.  
  1666.       pixel_region_init (&srcPR, GIMP_DRAWABLE (mask)->tiles,
  1667.              x1 - off_x, y1 - off_y, width, height, FALSE);
  1668.       pixel_region_init (&destPR, GIMP_DRAWABLE (tmp_mask)->tiles,
  1669.              0, 0, width, height, TRUE);
  1670.       copy_region (&srcPR, &destPR);
  1671.     }
  1672.  
  1673.   /*  clear the mask  */
  1674.   pixel_region_init (&srcPR, GIMP_DRAWABLE (mask)->tiles,
  1675.              0, 0,
  1676.              GIMP_DRAWABLE (mask)->width,
  1677.              GIMP_DRAWABLE (mask)->height, TRUE);
  1678.   color_region (&srcPR, &empty);
  1679.  
  1680.   if (width != 0 && height != 0)
  1681.     {
  1682.       /*  copy the temp mask back to the mask  */
  1683.       pixel_region_init (&srcPR, GIMP_DRAWABLE (tmp_mask)->tiles,
  1684.              0, 0, width, height, FALSE);
  1685.       pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles,
  1686.              x1, y1, width, height, TRUE);
  1687.       copy_region (&srcPR, &destPR);
  1688.  
  1689.       /*  free the temporary mask  */
  1690.       channel_delete (tmp_mask);
  1691.     }
  1692.  
  1693.   /*  calculate new bounds  */
  1694.   if (width == 0 || height == 0)
  1695.     {
  1696.       mask->empty = TRUE;
  1697.       mask->x1 = 0; mask->y1 = 0;
  1698.       mask->x2 = GIMP_DRAWABLE (mask)->width;
  1699.       mask->y2 = GIMP_DRAWABLE (mask)->height;
  1700.     }
  1701.   else
  1702.     {
  1703.       mask->x1 = x1;
  1704.       mask->y1 = y1;
  1705.       mask->x2 = x2;
  1706.       mask->y2 = y2;
  1707.     }
  1708. }
  1709.  
  1710. void
  1711. channel_layer_alpha (Channel *mask,
  1712.              Layer   *layer)
  1713. {
  1714.   PixelRegion srcPR, destPR;
  1715.   guchar empty = 0;
  1716.   gint   x1, y1, x2, y2;
  1717.  
  1718.   /*  push the current mask onto the undo stack  */
  1719.   channel_push_undo (mask);
  1720.  
  1721.   /*  clear the mask  */
  1722.   pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles,
  1723.              0, 0,
  1724.              GIMP_DRAWABLE (mask)->width,
  1725.              GIMP_DRAWABLE (mask)->height, TRUE);
  1726.   color_region (&destPR, &empty);
  1727.  
  1728.   x1 = CLAMP (GIMP_DRAWABLE (layer)->offset_x, 0, GIMP_DRAWABLE (mask)->width);
  1729.   y1 = CLAMP (GIMP_DRAWABLE (layer)->offset_y, 0, GIMP_DRAWABLE (mask)->height);
  1730.   x2 = CLAMP (GIMP_DRAWABLE (layer)->offset_x + GIMP_DRAWABLE (layer)->width,
  1731.           0, GIMP_DRAWABLE (mask)->width);
  1732.   y2 = CLAMP (GIMP_DRAWABLE( layer)->offset_y + GIMP_DRAWABLE (layer)->height,
  1733.           0, GIMP_DRAWABLE (mask)->height);
  1734.  
  1735.   pixel_region_init (&srcPR, GIMP_DRAWABLE (layer)->tiles,
  1736.              (x1 - GIMP_DRAWABLE (layer)->offset_x),
  1737.              (y1 - GIMP_DRAWABLE (layer)->offset_y),
  1738.              (x2 - x1), (y2 - y1), FALSE);
  1739.   pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles,
  1740.              x1, y1, (x2 - x1), (y2 - y1), TRUE);
  1741.   extract_alpha_region (&srcPR, NULL, &destPR);
  1742.  
  1743.   mask->bounds_known = FALSE;
  1744. }
  1745.  
  1746. void
  1747. channel_load (Channel *mask,
  1748.           Channel *channel)
  1749. {
  1750.   PixelRegion srcPR, destPR;
  1751.  
  1752.   /*  push the current mask onto the undo stack  */
  1753.   channel_push_undo (mask);
  1754.  
  1755.   /*  copy the channel to the mask  */
  1756.   pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
  1757.              0, 0,
  1758.              GIMP_DRAWABLE (channel)->width,
  1759.              GIMP_DRAWABLE (channel)->height, FALSE);
  1760.   pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles,
  1761.              0, 0,
  1762.              GIMP_DRAWABLE (channel)->width,
  1763.              GIMP_DRAWABLE (channel)->height, TRUE);
  1764.   copy_region (&srcPR, &destPR);
  1765.  
  1766.   mask->bounds_known = FALSE;
  1767. }
  1768.  
  1769. void
  1770. channel_invalidate_bounds (Channel *channel)
  1771. {
  1772.   channel->bounds_known = FALSE;
  1773. }
  1774.  
  1775.