gimpchannel.c 40.7 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
17
 */
18
19
#include "config.h"

Elliot Lee's avatar
Elliot Lee committed
20
21
#include <stdlib.h>
#include <string.h>
22

Elliot Lee's avatar
Elliot Lee committed
23
24
25
#include "appenv.h"
#include "channel.h"
#include "drawable.h"
26
#include "gdisplay.h"
Elliot Lee's avatar
Elliot Lee committed
27
28
29
#include "gimage_mask.h"
#include "layer.h"
#include "paint_funcs.h"
30
#include "parasitelist.h"
Elliot Lee's avatar
Elliot Lee committed
31
32
#include "temp_buf.h"
#include "undo.h"
33
#include "gimpsignal.h"
34
#include "gimppreviewcache.h"
Elliot Lee's avatar
Elliot Lee committed
35

36
#include "channel_pvt.h"
scott's avatar
scott committed
37
#include "tile.h"
38

39
40
41
#include "gimplut.h"
#include "lut_funcs.h"

42
43
44
45
46
#include "libgimp/gimpmath.h"

#include "libgimp/gimpintl.h"


47
enum {
48
  REMOVED,
49
50
51
52
53
54
55
  LAST_SIGNAL
};

static void gimp_channel_class_init (GimpChannelClass *klass);
static void gimp_channel_init       (GimpChannel      *channel);
static void gimp_channel_destroy    (GtkObject        *object);

56
static guint channel_signals[LAST_SIGNAL] = { 0 };
57
58
59

static GimpDrawableClass *parent_class = NULL;

60
GtkType
61
62
gimp_channel_get_type ()
{
63
  static GtkType channel_type = 0;
64
65
66
67
68
69
70
71
72
73

  if (!channel_type)
    {
      GtkTypeInfo channel_info =
      {
	"GimpChannel",
	sizeof (GimpChannel),
	sizeof (GimpChannelClass),
	(GtkClassInitFunc) gimp_channel_class_init,
	(GtkObjectInitFunc) gimp_channel_init,
74
75
        /* reserved_1 */ NULL,
	/* reserved_2 */ NULL,
76
	(GtkClassInitFunc) NULL,
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
      };

      channel_type = gtk_type_unique (gimp_drawable_get_type (), &channel_info);
    }

  return channel_type;
}

static void
gimp_channel_class_init (GimpChannelClass *class)
{
  GtkObjectClass *object_class;

  object_class = (GtkObjectClass*) class;
  parent_class = gtk_type_class (gimp_drawable_get_type ());

93
94
95
96
  channel_signals[REMOVED] =
	  gimp_signal_new ("removed",
			   0, object_class->type, 0, gimp_sigtype_void);

97
98
99
100
101
102
103
104
105
  gtk_object_class_add_signals (object_class, channel_signals, LAST_SIGNAL);

  object_class->destroy = gimp_channel_destroy;
}

static void
gimp_channel_init (GimpChannel *channel)
{
}
Elliot Lee's avatar
Elliot Lee committed
106
107
108

/**************************/
/*  Function definitions  */
109
/**************************/
Elliot Lee's avatar
Elliot Lee committed
110
111

static void
112
113
channel_validate (TileManager *tm,
		  Tile        *tile)
Elliot Lee's avatar
Elliot Lee committed
114
115
{
  /*  Set the contents of the tile to empty  */
scott's avatar
scott committed
116
  memset (tile_data_pointer (tile, 0, 0), 
117
	  TRANSPARENT_OPACITY, tile_size (tile));
Elliot Lee's avatar
Elliot Lee committed
118
119
120
}

Channel *
121
122
123
124
125
126
channel_new (GimpImage *gimage,
	     gint       width,
	     gint       height,
	     gchar     *name,
	     gint       opacity,
	     guchar    *col)
Elliot Lee's avatar
Elliot Lee committed
127
128
{
  Channel * channel;
129
  gint i;
Elliot Lee's avatar
Elliot Lee committed
130

131
  channel = gtk_type_new (gimp_channel_get_type ());
Elliot Lee's avatar
Elliot Lee committed
132

133
  gimp_drawable_configure (GIMP_DRAWABLE (channel), 
134
			   gimage, width, height, GRAY_GIMAGE, name);
Elliot Lee's avatar
Elliot Lee committed
135
136
137
138

  /*  set the channel color and opacity  */
  for (i = 0; i < 3; i++)
    channel->col[i] = col[i];
139
140
141

  channel->opacity     = opacity;
  channel->show_masked = TRUE;
Elliot Lee's avatar
Elliot Lee committed
142
143

  /*  selection mask variables  */
144
145
146
147
148
149
  channel->empty          = TRUE;
  channel->segs_in        = NULL;
  channel->segs_out       = NULL;
  channel->num_segs_in    = 0;
  channel->num_segs_out   = 0;
  channel->bounds_known   = TRUE;
Elliot Lee's avatar
Elliot Lee committed
150
  channel->boundary_known = TRUE;
151
152
153
154
  channel->x1             = 0;
  channel->y1             = 0;
  channel->x2             = width;
  channel->y2             = height;
Elliot Lee's avatar
Elliot Lee committed
155
156
157
158

  return channel;
}

scott's avatar
scott committed
159
160
161
162
163
Channel *
channel_ref (Channel *channel)
{
  gtk_object_ref  (GTK_OBJECT (channel));
  gtk_object_sink (GTK_OBJECT (channel));
164

scott's avatar
scott committed
165
166
167
168
169
170
171
172
173
  return channel;
}

void
channel_unref (Channel *channel)
{
  gtk_object_unref (GTK_OBJECT (channel));
}

Elliot Lee's avatar
Elliot Lee committed
174
175
176
Channel *
channel_copy (Channel *channel)
{
177
178
  gchar *channel_name;
  Channel *new_channel;
Elliot Lee's avatar
Elliot Lee committed
179
  PixelRegion srcPR, destPR;
180
181
182
183
  gchar *ext;
  gint number;
  gchar *name;
  gint len;
Elliot Lee's avatar
Elliot Lee committed
184
185

  /*  formulate the new channel name  */
186
187
  name = channel_get_name (channel);
  ext = strrchr (name, '#');
188
  len = strlen (_("copy"));
189
190
191
192
  if ((strlen (name) >= len &&
       strcmp (&name[strlen (name) - len], _("copy")) == 0) ||
      (ext && (number = atoi (ext + 1)) > 0 && 
       ((int)(log10 (number) + 1)) == strlen (ext + 1)))
193
194
    /* don't have redundant "copy"s */
    channel_name = g_strdup (name);
195
  else
196
    channel_name = g_strdup_printf (_("%s copy"), name);
Elliot Lee's avatar
Elliot Lee committed
197
198

  /*  allocate a new channel object  */
199
200
201
  new_channel = channel_new (GIMP_DRAWABLE (channel)->gimage, 
			     GIMP_DRAWABLE (channel)->width, 
			     GIMP_DRAWABLE (channel)->height, 
202
			     channel_name, channel->opacity, channel->col);
203
  GIMP_DRAWABLE (new_channel)->visible = GIMP_DRAWABLE (channel)->visible;
Elliot Lee's avatar
Elliot Lee committed
204
205
206
  new_channel->show_masked = channel->show_masked;

  /*  copy the contents across channels  */
207
208
209
210
211
212
213
  pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles, 0, 0, 
		     GIMP_DRAWABLE (channel)->width, 
		     GIMP_DRAWABLE (channel)->height, FALSE);
  pixel_region_init (&destPR, GIMP_DRAWABLE (new_channel)->tiles,
		     0, 0,
		     GIMP_DRAWABLE (channel)->width,
		     GIMP_DRAWABLE (channel)->height, TRUE);
Elliot Lee's avatar
Elliot Lee committed
214
215
  copy_region (&srcPR, &destPR);

216
  /* copy the parasites */
217
218
  GIMP_DRAWABLE (new_channel)->parasites 
    = parasite_list_copy (GIMP_DRAWABLE (channel)->parasites);
219

Elliot Lee's avatar
Elliot Lee committed
220
221
222
223
224
225
  /*  free up the channel_name memory  */
  g_free (channel_name);

  return new_channel;
}

226
void
227
228
channel_set_name (Channel *channel,
		  gchar   *name)
229
{
230
  gimp_drawable_set_name (GIMP_DRAWABLE (channel), name);
231
232
}

233
gchar *
234
235
channel_get_name (Channel *channel)
{
236
  return gimp_drawable_get_name (GIMP_DRAWABLE (channel));
237
238
}

239
void 
240
channel_set_color (Channel *channel,
241
		   guchar  *color)
242
{
243
244
  gint i;

245
246
  if (color)
    {  
247
248
      for (i = 0; i < 3; i++)
	channel->col[i] = color[i];
249
    }
250
}
251

Sven Neumann's avatar
Sven Neumann committed
252
guchar *
253
254
channel_get_color (Channel *channel)
{
255
  return (GIMP_CHANNEL (channel)->col); 
256
257
258
259
260
261
262
263
}
 
int
channel_get_opacity (Channel *channel)
{ 
  return channel->opacity;
}

264
void 
265
266
channel_set_opacity (Channel *channel,
		     gint     opacity)
267
268
{
  if (opacity >=0 && opacity <= 100)
269
    channel->opacity = (gint) (opacity * 255) / 100;
270
271
}

Elliot Lee's avatar
Elliot Lee committed
272
Channel *
273
channel_get_ID (gint ID)
Elliot Lee's avatar
Elliot Lee committed
274
{
275
  GimpDrawable *drawable;
276

277
278
279
280
281
  drawable = drawable_get_ID (ID);
  if (drawable && GIMP_IS_CHANNEL (drawable)) 
    return GIMP_CHANNEL (drawable);
  else
    return NULL;
Elliot Lee's avatar
Elliot Lee committed
282
283
284
285
286
}

void
channel_delete (Channel *channel)
{
scott's avatar
scott committed
287
  gtk_object_unref (GTK_OBJECT (channel));
288
289
290
291
292
293
294
295
296
297
298
299
}

static void
gimp_channel_destroy (GtkObject *object)
{
  GimpChannel *channel;

  g_return_if_fail (object != NULL);
  g_return_if_fail (GIMP_IS_CHANNEL (object));

  channel = GIMP_CHANNEL (object);

Elliot Lee's avatar
Elliot Lee committed
300
301
302
303
304
305
  /* free the segments?  */
  if (channel->segs_in)
    g_free (channel->segs_in);
  if (channel->segs_out)
    g_free (channel->segs_out);

306
  if (GTK_OBJECT_CLASS (parent_class)->destroy)
307
    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
308
  
Elliot Lee's avatar
Elliot Lee committed
309
310
}

311
312
313
314
315
316
317
/* The removed signal is sent out when the channel is no longer
 * associcated with an image.  It's needed because channels aren't
 * destroyed immediately, but kept around for undo purposes.  Connect
 * to the removed signal to update bits of UI that are tied to a
 * particular layer. */
void
channel_removed (Channel  *channel,
318
		 gpointer  data)
319
320
321
322
323
324
325
326
{
  g_return_if_fail (channel != NULL);
  g_return_if_fail (GIMP_IS_CHANNEL (channel));

  gtk_signal_emit (GTK_OBJECT (channel), channel_signals[REMOVED]);
}


Elliot Lee's avatar
Elliot Lee committed
327
void
328
329
330
channel_scale (Channel *channel,
	       gint     new_width,
	       gint     new_height)
Elliot Lee's avatar
Elliot Lee committed
331
332
333
334
335
336
337
338
{
  PixelRegion srcPR, destPR;
  TileManager *new_tiles;

  if (new_width == 0 || new_height == 0)
    return;

  /*  Update the old channel position  */
339
340
341
342
  drawable_update (GIMP_DRAWABLE (channel),
		   0, 0,
		   GIMP_DRAWABLE (channel)->width,
		   GIMP_DRAWABLE (channel)->height);
Elliot Lee's avatar
Elliot Lee committed
343
344

  /*  Configure the pixel regions  */
345
346
347
348
  pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
		     0, 0,
		     GIMP_DRAWABLE (channel)->width,
		     GIMP_DRAWABLE (channel)->height, FALSE);
Elliot Lee's avatar
Elliot Lee committed
349
350
351
352
353
354
355
356
357

  /*  Allocate the new channel, configure dest region  */
  new_tiles = tile_manager_new (new_width, new_height, 1);
  pixel_region_init (&destPR, new_tiles, 0, 0, new_width, new_height, TRUE);

  /*  Add an alpha channel  */
  scale_region (&srcPR, &destPR);

  /*  Push the channel on the undo stack  */
358
  undo_push_channel_mod (GIMP_DRAWABLE (channel)->gimage, channel);
Elliot Lee's avatar
Elliot Lee committed
359
360

  /*  Configure the new channel  */
361
362
363
  GIMP_DRAWABLE (channel)->tiles = new_tiles;
  GIMP_DRAWABLE (channel)->width = new_width;
  GIMP_DRAWABLE (channel)->height = new_height;
Elliot Lee's avatar
Elliot Lee committed
364
365
366
367
368

  /*  bounds are now unknown  */
  channel->bounds_known = FALSE;

  /*  Update the new channel position  */
369
370
371
372
  drawable_update (GIMP_DRAWABLE (channel),
		   0, 0,
		   GIMP_DRAWABLE (channel)->width,
		   GIMP_DRAWABLE (channel)->height);
Elliot Lee's avatar
Elliot Lee committed
373
374
375
}

void
376
377
378
379
380
channel_resize (Channel *channel,
		gint     new_width,
		gint     new_height,
		gint     offx,
		gint     offy)
Elliot Lee's avatar
Elliot Lee committed
381
382
383
{
  PixelRegion srcPR, destPR;
  TileManager *new_tiles;
384
385
386
387
  guchar bg = 0;
  gint clear;
  gint w, h;
  gint x1, y1, x2, y2;
Elliot Lee's avatar
Elliot Lee committed
388
389
390
391

  if (!new_width || !new_height)
    return;

392
393
394
395
  x1 = CLAMP (offx, 0, new_width);
  y1 = CLAMP (offy, 0, new_height);
  x2 = CLAMP ((offx + GIMP_DRAWABLE (channel)->width), 0, new_width);
  y2 = CLAMP ((offy + GIMP_DRAWABLE (channel)->height), 0, new_height);
Elliot Lee's avatar
Elliot Lee committed
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
  w = x2 - x1;
  h = y2 - y1;

  if (offx > 0)
    {
      x1 = 0;
      x2 = offx;
    }
  else
    {
      x1 = -offx;
      x2 = 0;
    }

  if (offy > 0)
    {
      y1 = 0;
      y2 = offy;
    }
  else
    {
      y1 = -offy;
      y2 = 0;
    }

  /*  Update the old channel position  */
422
423
424
425
  drawable_update (GIMP_DRAWABLE (channel),
		   0, 0,
		   GIMP_DRAWABLE (channel)->width,
		   GIMP_DRAWABLE (channel)->height);
Elliot Lee's avatar
Elliot Lee committed
426
427

  /*  Configure the pixel regions  */
428
429
  pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
		     x1, y1, w, h, FALSE);
Elliot Lee's avatar
Elliot Lee committed
430
431

  /*  Determine whether the new channel needs to be initially cleared  */
432
433
  if ((new_width  > GIMP_DRAWABLE (channel)->width) ||
      (new_height > GIMP_DRAWABLE (channel)->height) ||
Elliot Lee's avatar
Elliot Lee committed
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
      (x2 || y2))
    clear = TRUE;
  else
    clear = FALSE;

  /*  Allocate the new channel, configure dest region  */
  new_tiles = tile_manager_new (new_width, new_height, 1);

  /*  Set to black (empty--for selections)  */
  if (clear)
    {
      pixel_region_init (&destPR, new_tiles, 0, 0, new_width, new_height, TRUE);
      color_region (&destPR, &bg);
    }

  /*  copy from the old to the new  */
  pixel_region_init (&destPR, new_tiles, x2, y2, w, h, TRUE);
  if (w && h)
    copy_region (&srcPR, &destPR);

  /*  Push the channel on the undo stack  */
455
  undo_push_channel_mod (GIMP_DRAWABLE (channel)->gimage, channel);
Elliot Lee's avatar
Elliot Lee committed
456
457

  /*  Configure the new channel  */
458
459
460
  GIMP_DRAWABLE (channel)->tiles  = new_tiles;
  GIMP_DRAWABLE (channel)->width  = new_width;
  GIMP_DRAWABLE (channel)->height = new_height;
Elliot Lee's avatar
Elliot Lee committed
461
462
463
464
465

  /*  bounds are now unknown  */
  channel->bounds_known = FALSE;

  /*  update the new channel area  */
466
467
468
469
  drawable_update (GIMP_DRAWABLE (channel),
		   0, 0,
		   GIMP_DRAWABLE (channel)->width,
		   GIMP_DRAWABLE (channel)->height);
Elliot Lee's avatar
Elliot Lee committed
470
471
}

472
473
474
void            
channel_update (Channel *channel)
{
475
476
477
478
479
  drawable_update (GIMP_DRAWABLE (channel),
		   0, 0,
		   GIMP_DRAWABLE (channel)->width,
		   GIMP_DRAWABLE (channel)->height);
  gdisplays_flush ();
480
481
}

482
483
484
/**********************/
/*  access functions  */
/**********************/
Elliot Lee's avatar
Elliot Lee committed
485

486
gboolean
Elliot Lee's avatar
Elliot Lee committed
487
488
channel_toggle_visibility (Channel *channel)
{
489
  GIMP_DRAWABLE (channel)->visible = !GIMP_DRAWABLE (channel)->visible;
Elliot Lee's avatar
Elliot Lee committed
490

491
  return GIMP_DRAWABLE (channel)->visible;
Elliot Lee's avatar
Elliot Lee committed
492
493
}

494
495
496
497
static TempBuf *
channel_preview_private (Channel *channel,
			 gint     width,
			 gint     height)
Elliot Lee's avatar
Elliot Lee committed
498
499
500
{
  MaskBuf * preview_buf;
  PixelRegion srcPR, destPR;
501
  gint subsample;
502
  TempBuf *ret_buf;
Elliot Lee's avatar
Elliot Lee committed
503
504

  /*  The easy way  */
505
506
507
508
  if (GIMP_DRAWABLE (channel)->preview_valid &&
      (ret_buf =
       gimp_preview_cache_get (& (GIMP_DRAWABLE (channel)->preview_cache),
			       width, height)))
509
    return ret_buf;
Elliot Lee's avatar
Elliot Lee committed
510
511
512
513
514
  /*  The hard way  */
  else
    {
      /*  calculate 'acceptable' subsample  */
      subsample = 1;
515
516
      if (width < 1) width = 1;
      if (height < 1) height = 1;
517
518
      while ((width  * (subsample + 1) * 2 < GIMP_DRAWABLE (channel)->width) &&
	     (height * (subsample + 1) * 2 < GIMP_DRAWABLE (channel)->height))
Elliot Lee's avatar
Elliot Lee committed
519
520
	subsample = subsample + 1;

521
522
523
524
      pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
			 0, 0,
			 GIMP_DRAWABLE (channel)->width,
			 GIMP_DRAWABLE (channel)->height, FALSE);
Elliot Lee's avatar
Elliot Lee committed
525
526

      preview_buf = mask_buf_new (width, height);
527
528
529
530
531
      destPR.bytes     = 1;
      destPR.x         = 0;
      destPR.y         = 0;
      destPR.w         = width;
      destPR.h         = height;
Elliot Lee's avatar
Elliot Lee committed
532
      destPR.rowstride = width;
533
      destPR.data      = mask_buf_data (preview_buf);
Elliot Lee's avatar
Elliot Lee committed
534
535
536

      subsample_region (&srcPR, &destPR, subsample);

537
538
539
540
541
542
      if (!GIMP_DRAWABLE (channel)->preview_valid)
	gimp_preview_cache_invalidate (&(GIMP_DRAWABLE(channel)->preview_cache));

      GIMP_DRAWABLE (channel)->preview_valid = TRUE;
      gimp_preview_cache_add (&(GIMP_DRAWABLE (channel)->preview_cache),
			      preview_buf);
543
      return preview_buf;
Elliot Lee's avatar
Elliot Lee committed
544
545
546
    }
}

547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
TempBuf *
channel_preview (Channel *channel,
		 gint     width,
		 gint     height)
{
  /* Ok prime the cache with a large preview if the cache is invalid */
  if(!GIMP_DRAWABLE(channel)->preview_valid && 
     width <= PREVIEW_CACHE_PRIME_WIDTH &&
     height <= PREVIEW_CACHE_PRIME_HEIGHT)
    {
      TempBuf * tb = channel_preview_private(channel,
					     PREVIEW_CACHE_PRIME_WIDTH,
					     PREVIEW_CACHE_PRIME_HEIGHT);
      
      /* Save the 2nd call */
      if(width == PREVIEW_CACHE_PRIME_WIDTH &&
	 height == PREVIEW_CACHE_PRIME_HEIGHT)
	return tb;
    }

  /* Second call - should NOT visit the tile cache...*/
  return channel_preview_private(channel,width,height);
}


Elliot Lee's avatar
Elliot Lee committed
572
void
573
channel_invalidate_previews (GimpImage* gimage)
Elliot Lee's avatar
Elliot Lee committed
574
{
575
  GSList * tmp;
Elliot Lee's avatar
Elliot Lee committed
576
  Channel * channel;
577
578

  tmp = gimage->channels;
Elliot Lee's avatar
Elliot Lee committed
579
580
581
582

  while (tmp)
    {
      channel = (Channel *) tmp->data;
583
      gimp_drawable_invalidate_preview (GIMP_DRAWABLE (channel), TRUE);
584
      tmp = g_slist_next (tmp);
Elliot Lee's avatar
Elliot Lee committed
585
586
587
    }
}

588
Tattoo
589
channel_get_tattoo (const Channel *channel)
590
{
591
  return (gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)));
592
593
}

594
void
595
596
channel_set_tattoo (const Channel *channel, 
		    Tattoo         value)
597
{
598
  gimp_drawable_set_tattoo (GIMP_DRAWABLE (channel), value);
599
600
}

601
602
603
/******************************/
/*  selection mask functions  */
/******************************/
Elliot Lee's avatar
Elliot Lee committed
604
605

Channel *
606
channel_new_mask (GimpImage *gimage,
607
608
		  gint       width,
		  gint       height)
Elliot Lee's avatar
Elliot Lee committed
609
{
610
  guchar black[3] = {0, 0, 0};
Elliot Lee's avatar
Elliot Lee committed
611
612
613
  Channel *new_channel;

  /*  Create the new channel  */
614
615
  new_channel = channel_new (gimage, width, height,
			     _("Selection Mask"), 127, black);
Elliot Lee's avatar
Elliot Lee committed
616
617

  /*  Set the validate procedure  */
618
619
  tile_manager_set_validate_proc (GIMP_DRAWABLE (new_channel)->tiles,
				  channel_validate);
Elliot Lee's avatar
Elliot Lee committed
620
621
622
623

  return new_channel;
}

624
625
626
627
628
629
630
631
632
633
gboolean
channel_boundary (Channel   *mask,
		  BoundSeg **segs_in,
		  BoundSeg **segs_out,
		  gint      *num_segs_in,
		  gint      *num_segs_out,
		  gint       x1,
		  gint       y1,
		  gint       x2,
		  gint       y2)
Elliot Lee's avatar
Elliot Lee committed
634
{
635
  gint x3, y3, x4, y4;
Elliot Lee's avatar
Elliot Lee committed
636
637
638
639
640
641
642
643
644
645
646
647
  PixelRegion bPR;

  if (! mask->boundary_known)
    {
      /* free the out of date boundary segments */
      if (mask->segs_in)
	g_free (mask->segs_in);
      if (mask->segs_out)
	g_free (mask->segs_out);

      if (channel_bounds (mask, &x3, &y3, &x4, &y4))
	{
648
649
	  pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles,
			     x3, y3, (x4 - x3), (y4 - y3), FALSE);
Elliot Lee's avatar
Elliot Lee committed
650
651
652
653
	  mask->segs_out = find_mask_boundary (&bPR, &mask->num_segs_out,
					       IgnoreBounds,
					       x1, y1,
					       x2, y2);
654
655
656
657
	  x1 = MAX (x1, x3);
	  y1 = MAX (y1, y3);
	  x2 = MIN (x2, x4);
	  y2 = MIN (y2, y4);
Elliot Lee's avatar
Elliot Lee committed
658
659
660

	  if (x2 > x1 && y2 > y1)
	    {
661
662
663
664
	      pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles,
				 0, 0,
				 GIMP_DRAWABLE (mask)->width,
				 GIMP_DRAWABLE (mask)->height, FALSE);
Elliot Lee's avatar
Elliot Lee committed
665
666
667
668
669
670
671
	      mask->segs_in =  find_mask_boundary (&bPR, &mask->num_segs_in,
						   WithinBounds,
						   x1, y1,
						   x2, y2);
	    }
	  else
	    {
672
	      mask->segs_in     = NULL;
Elliot Lee's avatar
Elliot Lee committed
673
674
675
676
677
	      mask->num_segs_in = 0;
	    }
	}
      else
	{
678
679
680
	  mask->segs_in      = NULL;
	  mask->segs_out     = NULL;
	  mask->num_segs_in  = 0;
Elliot Lee's avatar
Elliot Lee committed
681
682
683
684
685
	  mask->num_segs_out = 0;
	}
      mask->boundary_known = TRUE;
    }

686
687
688
  *segs_in      = mask->segs_in;
  *segs_out     = mask->segs_out;
  *num_segs_in  = mask->num_segs_in;
Elliot Lee's avatar
Elliot Lee committed
689
690
691
692
693
  *num_segs_out = mask->num_segs_out;

  return TRUE;
}

694
695
696
697
gint
channel_value (Channel *mask,
	       gint     x,
	       gint     y)
Elliot Lee's avatar
Elliot Lee committed
698
699
{
  Tile *tile;
700
  gint val;
Elliot Lee's avatar
Elliot Lee committed
701
702
703
704
705
706
707
708
709
710
711

  /*  Some checks to cut back on unnecessary work  */
  if (mask->bounds_known)
    {
      if (mask->empty)
	return 0;
      else if (x < mask->x1 || x >= mask->x2 || y < mask->y1 || y >= mask->y2)
	return 0;
    }
  else
    {
712
713
      if (x < 0 || x >= GIMP_DRAWABLE (mask)->width ||
	  y < 0 || y >= GIMP_DRAWABLE (mask)->height)
Elliot Lee's avatar
Elliot Lee committed
714
715
716
	return 0;
    }

717
718
  tile = tile_manager_get_tile (GIMP_DRAWABLE (mask)->tiles, x, y, TRUE, FALSE);
  val = *(guchar *) (tile_data_pointer (tile, x % TILE_WIDTH, y % TILE_HEIGHT));
719
  tile_release (tile, FALSE);
Elliot Lee's avatar
Elliot Lee committed
720
721
722
723

  return val;
}

724
725
726
727
728
729
gboolean
channel_bounds (Channel *mask,
		gint    *x1,
		gint    *y1,
		gint    *x2,
		gint    *y2)
Elliot Lee's avatar
Elliot Lee committed
730
731
{
  PixelRegion maskPR;
732
733
734
735
736
  guchar *data, *data1;
  gint x, y;
  gint ex, ey;
  gint tx1, tx2, ty1, ty2;
  gint minx, maxx;
737
  gpointer pr;
738

Elliot Lee's avatar
Elliot Lee committed
739
740
741
742
743
744
745
746
  /*  if the mask's bounds have already been reliably calculated...  */
  if (mask->bounds_known)
    {
      *x1 = mask->x1;
      *y1 = mask->y1;
      *x2 = mask->x2;
      *y2 = mask->y2;

747
      return !mask->empty;
Elliot Lee's avatar
Elliot Lee committed
748
749
750
    }

  /*  go through and calculate the bounds  */
751
752
  tx1 = GIMP_DRAWABLE (mask)->width;
  ty1 = GIMP_DRAWABLE (mask)->height;
753
754
  tx2 = 0;
  ty2 = 0;
Elliot Lee's avatar
Elliot Lee committed
755

756
757
758
759
760
761
762
  pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
		     0, 0,
		     GIMP_DRAWABLE (mask)->width,
		     GIMP_DRAWABLE (mask)->height, FALSE);
  for (pr = pixel_regions_register (1, &maskPR);
       pr != NULL;
       pr = pixel_regions_process (pr))
Elliot Lee's avatar
Elliot Lee committed
763
    {
764
      data1 = data = maskPR.data;
Elliot Lee's avatar
Elliot Lee committed
765
766
      ex = maskPR.x + maskPR.w;
      ey = maskPR.y + maskPR.h;
767
768
      /* only check the pixels if this tile is not fully within the currently
	 computed bounds */
769
770
      if (maskPR.x < tx1 || ex > tx2 ||
	  maskPR.y < ty1 || ey > ty2)
771
        {
772
773
774
775
776
777
778
779
780
781
782
783
784
785
	  /* Check upper left and lower right corners to see if we can
	     avoid checking the rest of the pixels in this tile */
	  if (data[0] && data[maskPR.rowstride*(maskPR.h - 1) + maskPR.w - 1])
	  {
	    if (maskPR.x < tx1)
	      tx1 = maskPR.x;
	    if (ex > tx2)
	      tx2 = ex;
	    if (maskPR.y < ty1)
	      ty1 = maskPR.y;
	    if (ey > ty2)
	      ty2 = ey;
	  }
	  else
786
	    for (y = maskPR.y; y < ey; y++, data1 += maskPR.rowstride)
Elliot Lee's avatar
Elliot Lee committed
787
	    {
788
	      for (x = maskPR.x, data = data1; x < ex; x++, data++)
789
		if (*data)
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
		{
		  minx = x;
		  maxx = x;
		  for (; x < ex; x++, data++)
		    if (*data)
		      maxx = x;
		  if (minx < tx1)
		    tx1 = minx;
		  if (maxx > tx2)
		    tx2 = maxx;
		  if (y < ty1)
		    ty1 = y;
		  if (y > ty2)
		    ty2 = y;
	      }
Elliot Lee's avatar
Elliot Lee committed
805
806
807
808
	    }
	}
    }

809
810
  tx2 = CLAMP (tx2 + 1, 0, GIMP_DRAWABLE (mask)->width);
  ty2 = CLAMP (ty2 + 1, 0, GIMP_DRAWABLE (mask)->height);
Elliot Lee's avatar
Elliot Lee committed
811

812
  if (tx1 == GIMP_DRAWABLE (mask)->width && ty1 == GIMP_DRAWABLE (mask)->height)
Elliot Lee's avatar
Elliot Lee committed
813
814
    {
      mask->empty = TRUE;
815
816
817
818
      mask->x1    = 0;
      mask->y1    = 0;
      mask->x2    = GIMP_DRAWABLE (mask)->width;
      mask->y2    = GIMP_DRAWABLE (mask)->height;
Elliot Lee's avatar
Elliot Lee committed
819
820
821
822
    }
  else
    {
      mask->empty = FALSE;
823
824
825
826
      mask->x1    = tx1;
      mask->y1    = ty1;
      mask->x2    = tx2;
      mask->y2    = ty2;
Elliot Lee's avatar
Elliot Lee committed
827
828
829
    }
  mask->bounds_known = TRUE;

830
831
832
833
834
  *x1 = tx1;
  *x2 = tx2;
  *y1 = ty1;
  *y2 = ty2;

835
  return !mask->empty;
Elliot Lee's avatar
Elliot Lee committed
836
837
}

838
gboolean
Elliot Lee's avatar
Elliot Lee committed
839
840
841
channel_is_empty (Channel *mask)
{
  PixelRegion maskPR;
842
843
  guchar * data;
  gint x, y;
844
  gpointer pr;
Elliot Lee's avatar
Elliot Lee committed
845
846
847
848

  if (mask->bounds_known)
    return mask->empty;

849
850
851
852
853
854
855
  pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
		     0, 0,
		     GIMP_DRAWABLE (mask)->width,
		     GIMP_DRAWABLE (mask)->height, FALSE);
  for (pr = pixel_regions_register (1, &maskPR);
       pr != NULL;
       pr = pixel_regions_process (pr))
Elliot Lee's avatar
Elliot Lee committed
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
    {
      /*  check if any pixel in the mask is non-zero  */
      data = maskPR.data;
      for (y = 0; y < maskPR.h; y++)
	for (x = 0; x < maskPR.w; x++)
	  if (*data++)
	    {
	      pixel_regions_process_stop (pr);
	      return FALSE;
	    }
    }

  /*  The mask is empty, meaning we can set the bounds as known  */
  if (mask->segs_in)
    g_free (mask->segs_in);
  if (mask->segs_out)
    g_free (mask->segs_out);

874
875
876
877
878
879
  mask->empty          = TRUE;
  mask->segs_in        = NULL;
  mask->segs_out       = NULL;
  mask->num_segs_in    = 0;
  mask->num_segs_out   = 0;
  mask->bounds_known   = TRUE;
Elliot Lee's avatar
Elliot Lee committed
880
  mask->boundary_known = TRUE;
881
882
883
884
  mask->x1             = 0;
  mask->y1             = 0;
  mask->x2             = GIMP_DRAWABLE (mask)->width;
  mask->y2             = GIMP_DRAWABLE (mask)->height;
Elliot Lee's avatar
Elliot Lee committed
885
886
887
888
889

  return TRUE;
}

void
890
891
892
893
894
channel_add_segment (Channel *mask,
		     gint     x,
		     gint     y,
		     gint     width,
		     gint     value)
Elliot Lee's avatar
Elliot Lee committed
895
896
{
  PixelRegion maskPR;
897
898
899
  guchar *data;
  gint val;
  gint x2;
900
  gpointer pr;
Elliot Lee's avatar
Elliot Lee committed
901
902
903
904

  /*  check horizontal extents...  */
  x2 = x + width;
  if (x2 < 0) x2 = 0;
905
  if (x2 > GIMP_DRAWABLE (mask)->width) x2 = GIMP_DRAWABLE (mask)->width;
Elliot Lee's avatar
Elliot Lee committed
906
  if (x < 0) x = 0;
907
  if (x > GIMP_DRAWABLE (mask)->width) x = GIMP_DRAWABLE (mask)->width;
Elliot Lee's avatar
Elliot Lee committed
908
909
910
  width = x2 - x;
  if (!width) return;

911
  if (y < 0 || y > GIMP_DRAWABLE (mask)->height)
Elliot Lee's avatar
Elliot Lee committed
912
913
    return;

914
915
916
917
918
  pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
		     x, y, width, 1, TRUE);
  for (pr = pixel_regions_register (1, &maskPR);
       pr != NULL;
       pr = pixel_regions_process (pr))
Elliot Lee's avatar
Elliot Lee committed
919
920
921
922
923
924
925
926
927
928
929
930
931
932
    {
      data = maskPR.data;
      width = maskPR.w;
      while (width--)
	{
	  val = *data + value;
	  if (val > 255)
	    val = 255;
	  *data++ = val;
	}
    }
}

void
933
934
935
936
937
channel_sub_segment (Channel *mask,
		     gint     x,
		     gint     y,
		     gint     width,
		     gint     value)
Elliot Lee's avatar
Elliot Lee committed
938
939
{
  PixelRegion maskPR;
940
941
942
  guchar *data;
  gint val;
  gint x2;
943
  gpointer pr;
Elliot Lee's avatar
Elliot Lee committed
944
945
946
947

  /*  check horizontal extents...  */
  x2 = x + width;
  if (x2 < 0) x2 = 0;
948
  if (x2 > GIMP_DRAWABLE (mask)->width) x2 = GIMP_DRAWABLE (mask)->width;
Elliot Lee's avatar
Elliot Lee committed
949
  if (x < 0) x = 0;
950
  if (x > GIMP_DRAWABLE (mask)->width) x = GIMP_DRAWABLE (mask)->width;
Elliot Lee's avatar
Elliot Lee committed
951
952
953
  width = x2 - x;
  if (!width) return;

954
  if (y < 0 || y > GIMP_DRAWABLE (mask)->height)
Elliot Lee's avatar
Elliot Lee committed
955
956
    return;

957
958
959
960
  pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles, x, y, width, 1, TRUE);
  for (pr = pixel_regions_register (1, &maskPR);
       pr != NULL;
       pr = pixel_regions_process (pr))
Elliot Lee's avatar
Elliot Lee committed
961
962
963
964
965
966
967
968
969
970
971
972
973
974
    {
      data = maskPR.data;
      width = maskPR.w;
      while (width--)
	{
	  val = *data - value;
	  if (val < 0)
	    val = 0;
	  *data++ = val;
	}
    }
}

void
975
976
977
978
979
980
channel_combine_rect (Channel    *mask,
		      ChannelOps  op,
		      gint        x,
		      gint        y,
		      gint        w,
		      gint        h)
Elliot Lee's avatar
Elliot Lee committed
981
{
982
  gint x2, y2;
Elliot Lee's avatar
Elliot Lee committed
983
  PixelRegion maskPR;
984
985
  guchar color;

986
987
  y2 = y + h;
  x2 = x + w;
Elliot Lee's avatar
Elliot Lee committed
988

989
990
991
992
  x  = CLAMP (x,  0, GIMP_DRAWABLE (mask)->width);
  y  = CLAMP (y,  0, GIMP_DRAWABLE (mask)->height);
  x2 = CLAMP (x2, 0, GIMP_DRAWABLE (mask)->width);
  y2 = CLAMP (y2, 0, GIMP_DRAWABLE (mask)->height);
Elliot Lee's avatar
Elliot Lee committed
993

994
  if (x2 - x <= 0 || y2 - y <= 0)
Elliot Lee's avatar
Elliot Lee committed
995
996
    return;

997
998
  pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
		     x, y, x2 - x, y2 - y, TRUE);
999
1000
1001
1002
  if (op == ADD  || op == REPLACE)
    color = 255;
  else
    color = 0;
1003
  color_region (&maskPR, &color);
Elliot Lee's avatar
Elliot Lee committed
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027

  /*  Determine new boundary  */
  if (mask->bounds_known && (op == ADD) && !mask->empty)
    {
      if (x < mask->x1)
	mask->x1 = x;
      if (y < mask->y1)
	mask->y1 = y;
      if ((x + w) > mask->x2)
	mask->x2 = (x + w);
      if ((y + h) > mask->y2)
	mask->y2 = (y + h);
    }
  else if (op == REPLACE || mask->empty)
    {
      mask->empty = FALSE;
      mask->x1 = x;
      mask->y1 = y;
      mask->x2 = x + w;
      mask->y2 = y + h;
    }
  else
    mask->bounds_known = FALSE;

1028
1029
1030
1031
  mask->x1 = CLAMP (mask->x1, 0, GIMP_DRAWABLE (mask)->width);
  mask->y1 = CLAMP (mask->y1, 0, GIMP_DRAWABLE (mask)->height);
  mask->x2 = CLAMP (mask->x2, 0, GIMP_DRAWABLE (mask)->width);
  mask->y2 = CLAMP (mask->y2, 0, GIMP_DRAWABLE (mask)->height);
Elliot Lee's avatar
Elliot Lee committed
1032
1033
1034
}

void
1035
1036
1037
1038
1039
1040
channel_combine_ellipse (Channel    *mask,
			 ChannelOps  op,
			 gint        x,
			 gint        y,
			 gint        w,
			 gint        h,
1041
			 gboolean    antialias)
Elliot Lee's avatar
Elliot Lee committed
1042
{
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
  gint i, j;
  gint x0, x1, x2;
  gint val, last;
  gfloat a_sqr, b_sqr, aob_sqr;
  gfloat w_sqr, h_sqr;
  gfloat y_sqr;
  gfloat t0, t1;
  gfloat r;
  gfloat cx, cy;
  gfloat rad;
  gfloat dist;
Elliot Lee's avatar
Elliot Lee committed
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066

  if (!w || !h)
    return;

  a_sqr = (w * w / 4.0);
  b_sqr = (h * h / 4.0);
  aob_sqr = a_sqr / b_sqr;

  cx = x + w / 2.0;
  cy = y + h / 2.0;

  for (i = y; i < (y + h); i++)
    {
1067
      if (i >= 0 && i < GIMP_DRAWABLE (mask)->height)
Elliot Lee's avatar
Elliot Lee committed
1068
1069
	{
	  /*  Non-antialiased code  */
1070
	  if (!antialias)
Elliot Lee's avatar
Elliot Lee committed
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
	    {
	      y_sqr = (i + 0.5 - cy) * (i + 0.5 - cy);
	      rad = sqrt (a_sqr - a_sqr * y_sqr / (double) b_sqr);
	      x1 = ROUND (cx - rad);
	      x2 = ROUND (cx + rad);

	      switch (op)
		{
		case ADD: case REPLACE:
		  channel_add_segment (mask, x1, i, (x2 - x1), 255);
		  break;
		case SUB :
		  channel_sub_segment (mask, x1, i, (x2 - x1), 255);
		  break;
Sven Neumann's avatar
Sven Neumann committed
1085
1086
1087
		default:
		  g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
		  break;
Elliot Lee's avatar
Elliot Lee committed
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
		}
	    }
	  /*  antialiasing  */
	  else
	    {
	      x0 = x;
	      last = 0;
	      h_sqr = (i + 0.5 - cy) * (i + 0.5 - cy);
	      for (j = x; j < (x + w); j++)
		{
		  w_sqr = (j + 0.5 - cx) * (j + 0.5 - cx);

		  if (h_sqr != 0)
		    {
		      t0 = w_sqr / h_sqr;
		      t1 = a_sqr / (t0 + aob_sqr);
		      r = sqrt (t1 + t0 * t1);
		      rad = sqrt (w_sqr + h_sqr);
		      dist = rad - r;
		    }
		  else
		    dist = -1.0;

		  if (dist < -0.5)
		    val = 255;
		  else if (dist < 0.5)
		    val = (int) (255 * (1 - (dist + 0.5)));
		  else
		    val = 0;
1117
		  
Elliot Lee's avatar
Elliot Lee committed
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
		  if (last != val && last)
		    {
		      switch (op)
			{
			case ADD: case REPLACE:
			  channel_add_segment (mask, x0, i, j - x0, last);
			  break;
			case SUB:
			  channel_sub_segment (mask, x0, i, j - x0, last);
			  break;
Sven Neumann's avatar
Sven Neumann committed
1128
1129
1130
			default:
			  g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
			  break;
Elliot Lee's avatar
Elliot Lee committed
1131
1132
1133
1134
1135
1136
1137
			}
		    }

		  if (last != val)
		    {
		      x0 = j;
		      last = val;
1138
1139
1140
1141
		      /* because we are symetric accross the y axis we can
			 skip ahead a bit if we are inside the ellipse*/
		      if (val == 255 && j < cx)
			j = cx + (cx - j) - 1;
Elliot Lee's avatar
Elliot Lee committed
1142
1143
1144
1145
1146
1147
1148
1149
1150
		    }
		}

	      if (last)
		{
		  if (op == ADD || op == REPLACE)
		    channel_add_segment (mask, x0, i, j - x0, last);
		  else if (op == SUB)
		    channel_sub_segment (mask, x0, i, j - x0, last);
Sven Neumann's avatar
Sven Neumann committed
1151
1152
		  else
		    g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
Elliot Lee's avatar
Elliot Lee committed
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
		}
	    }

	}
    }

  /*  Determine new boundary  */
  if (mask->bounds_known && (op == ADD) && !mask->empty)
    {
      if (x < mask->x1)
	mask->x1 = x;
      if (y < mask->y1)
	mask->y1 = y;
      if ((x + w) > mask->x2)
	mask->x2 = (x + w);
      if ((y + h) > mask->y2)
	mask->y2 = (y + h);
    }
  else if (op == REPLACE || mask->empty)
    {
      mask->empty = FALSE;
      mask->x1 = x;
      mask->y1 = y;
      mask->x2 = x + w;
      mask->y2 = y + h;
    }
  else
    mask->bounds_known = FALSE;

1182
1183
1184
1185
  mask->x1 = CLAMP (mask->x1, 0, GIMP_DRAWABLE (mask)->width);
  mask->y1 = CLAMP (mask->y1, 0, GIMP_DRAWABLE (mask)->height);
  mask->x2 = CLAMP (mask->x2, 0, GIMP_DRAWABLE (mask)->width);
  mask->y2 = CLAMP (mask->y2, 0, GIMP_DRAWABLE (mask)->height);
Elliot Lee's avatar
Elliot Lee committed
1186
1187
}

1188
static void
1189
channel_combine_sub_region_add (void        *unused,
1190
1191
1192
				PixelRegion *srcPR,
				PixelRegion *destPR)
{
1193
1194
1195
1196
  guchar *src, *dest;
  gint x, y, val;

  src  = srcPR->data;
1197
  dest = destPR->data;
1198

1199
1200
  for (y = 0; y < srcPR->h; y++)
    {
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
      for (x = 0; x < srcPR->w; x++)
	{
	  val = dest[x] + src[x];
	  if (val > 255)
	    dest[x] = 255;
	  else
	    dest[x] = val;
	}
      src  += srcPR->rowstride;
      dest += destPR->rowstride;
1211
1212
1213
1214
    }
}

static void
1215
channel_combine_sub_region_sub (void        *unused,
1216
1217
1218
				PixelRegion *srcPR,
				PixelRegion *destPR)
{
1219
1220
1221
1222
  guchar *src, *dest;
  gint x, y;

  src  = srcPR->data;
1223
  dest = destPR->data;
1224

1225
1226
  for (y = 0; y < srcPR->h; y++)
    {
1227
1228
1229
1230
1231
1232
1233
1234
1235
      for (x = 0; x < srcPR->w; x++)
	{
	  if (src[x] > dest[x])
	    dest[x] = 0;
	  else
	    dest[x]-= src[x];
	}
      src  += srcPR->rowstride;
      dest += destPR->rowstride;
1236
1237
1238
1239
    }
}

static void
1240
channel_combine_sub_region_intersect (void        *unused,
1241
1242
1243
				      PixelRegion *srcPR,
				      PixelRegion *destPR)
{
1244
1245
1246
1247
  guchar *src, *dest;
  gint x, y;

  src  = srcPR->data;
1248
  dest = destPR->data;
1249

1250
1251
  for (y = 0; y < srcPR->h; y++)
    {
1252
1253
      for (x = 0; x < srcPR->w; x++)
	{
1254
	  dest[x] = MIN (dest[x], src[x]);
1255
1256
1257
	}
      src  += srcPR->rowstride;
      dest += destPR->rowstride;
1258
1259
1260
  }
}

Elliot Lee's avatar
Elliot Lee committed
1261
void
1262
1263
1264
1265
1266
channel_combine_mask (Channel    *mask,
		      Channel    *add_on,
		      ChannelOps  op,
		      gint        off_x,
		      gint        off_y)
Elliot Lee's avatar
Elliot Lee committed
1267
1268
{
  PixelRegion srcPR, destPR;
1269
1270
  gint x1, y1, x2, y2;
  gint w, h;
Elliot Lee's avatar
Elliot Lee committed
1271

1272
1273
1274
1275
1276
1277
  x1 = CLAMP (off_x, 0, GIMP_DRAWABLE (mask)->width);
  y1 = CLAMP (off_y, 0, GIMP_DRAWABLE (mask)->height);
  x2 = CLAMP (off_x + GIMP_DRAWABLE (add_on)->width, 0,
	      GIMP_DRAWABLE (mask)->width);
  y2 = CLAMP (off_y + GIMP_DRAWABLE (add_on)->height, 0,
	      GIMP_DRAWABLE (mask)->height);