gimpchannel.c 40.8 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

Sven Neumann's avatar
Sven Neumann committed
578
579
  g_return_if_fail (gimage != NULL);

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

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

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

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

603
604
605
/******************************/
/*  selection mask functions  */
/******************************/
Elliot Lee's avatar
Elliot Lee committed
606
607

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

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

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

  return new_channel;
}

626
627
628
629
630
631
632
633
634
635
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
636
{
637
  gint x3, y3, x4, y4;
Elliot Lee's avatar
Elliot Lee committed
638
639
640
641
642
643
644
645
646
647
648
649
  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))
	{
650
651
	  pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles,
			     x3, y3, (x4 - x3), (y4 - y3), FALSE);
Elliot Lee's avatar
Elliot Lee committed
652
653
654
655
	  mask->segs_out = find_mask_boundary (&bPR, &mask->num_segs_out,
					       IgnoreBounds,
					       x1, y1,
					       x2, y2);
656
657
658
659
	  x1 = MAX (x1, x3);
	  y1 = MAX (y1, y3);
	  x2 = MIN (x2, x4);
	  y2 = MIN (y2, y4);
Elliot Lee's avatar
Elliot Lee committed
660
661
662

	  if (x2 > x1 && y2 > y1)
	    {
663
664
665
666
	      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
667
668
669
670
671
672
673
	      mask->segs_in =  find_mask_boundary (&bPR, &mask->num_segs_in,
						   WithinBounds,
						   x1, y1,
						   x2, y2);
	    }
	  else
	    {
674
	      mask->segs_in     = NULL;
Elliot Lee's avatar
Elliot Lee committed
675
676
677
678
679
	      mask->num_segs_in = 0;
	    }
	}
      else
	{
680
681
682
	  mask->segs_in      = NULL;
	  mask->segs_out     = NULL;
	  mask->num_segs_in  = 0;
Elliot Lee's avatar
Elliot Lee committed
683
684
685
686
687
	  mask->num_segs_out = 0;
	}
      mask->boundary_known = TRUE;
    }

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

  return TRUE;
}

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

  /*  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
    {
714
715
      if (x < 0 || x >= GIMP_DRAWABLE (mask)->width ||
	  y < 0 || y >= GIMP_DRAWABLE (mask)->height)
Elliot Lee's avatar
Elliot Lee committed
716
717
718
	return 0;
    }

719
720
  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));
721
  tile_release (tile, FALSE);
Elliot Lee's avatar
Elliot Lee committed
722
723
724
725

  return val;
}

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

Elliot Lee's avatar
Elliot Lee committed
741
742
743
744
745
746
747
748
  /*  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;

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

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

758
759
760
761
762
763
764
  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
765
    {
766
      data1 = data = maskPR.data;
Elliot Lee's avatar
Elliot Lee committed
767
768
      ex = maskPR.x + maskPR.w;
      ey = maskPR.y + maskPR.h;
769
770
      /* only check the pixels if this tile is not fully within the currently
	 computed bounds */
771
772
      if (maskPR.x < tx1 || ex > tx2 ||
	  maskPR.y < ty1 || ey > ty2)
773
        {
774
775
776
777
778
779
780
781
782
783
784
785
786
787
	  /* 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
788
	    for (y = maskPR.y; y < ey; y++, data1 += maskPR.rowstride)
Elliot Lee's avatar
Elliot Lee committed
789
	    {
790
	      for (x = maskPR.x, data = data1; x < ex; x++, data++)
791
		if (*data)
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
		{
		  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
807
808
809
810
	    }
	}
    }

811
812
  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
813

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

832
833
834
835
836
  *x1 = tx1;
  *x2 = tx2;
  *y1 = ty1;
  *y2 = ty2;

837
  return !mask->empty;
Elliot Lee's avatar
Elliot Lee committed
838
839
}

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

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

851
852
853
854
855
856
857
  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
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
    {
      /*  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);

876
877
878
879
880
881
  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
882
  mask->boundary_known = TRUE;
883
884
885
886
  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
887
888
889
890
891

  return TRUE;
}

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

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

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

916
917
918
919
920
  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
921
922
923
924
925
926
927
928
929
930
931
932
933
934
    {
      data = maskPR.data;
      width = maskPR.w;
      while (width--)
	{
	  val = *data + value;
	  if (val > 255)
	    val = 255;
	  *data++ = val;
	}
    }
}

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

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

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

959
960
961
962
  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
963
964
965
966
967
968
969
970
971
972
973
974
975
976
    {
      data = maskPR.data;
      width = maskPR.w;
      while (width--)
	{
	  val = *data - value;
	  if (val < 0)
	    val = 0;
	  *data++ = val;
	}
    }
}

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

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

991
992
993
994
  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
995

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

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

  /*  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;

1030
1031
1032
1033
  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
1034
1035
1036
}

void
1037
1038
1039
1040
1041
1042
channel_combine_ellipse (Channel    *mask,
			 ChannelOps  op,
			 gint        x,
			 gint        y,
			 gint        w,
			 gint        h,
1043
			 gboolean    antialias)
Elliot Lee's avatar
Elliot Lee committed
1044
{
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
  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
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068

  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++)
    {
1069
      if (i >= 0 && i < GIMP_DRAWABLE (mask)->height)
Elliot Lee's avatar
Elliot Lee committed
1070
1071
	{
	  /*  Non-antialiased code  */
1072
	  if (!antialias)
Elliot Lee's avatar
Elliot Lee committed
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
	    {
	      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
1087
1088
1089
		default:
		  g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
		  break;
Elliot Lee's avatar
Elliot Lee committed
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
1117
1118
		}
	    }
	  /*  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;
1119
		  
Elliot Lee's avatar
Elliot Lee committed
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
		  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
1130
1131
1132
			default:
			  g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
			  break;
Elliot Lee's avatar
Elliot Lee committed
1133
1134
1135
1136
1137
1138
1139
			}
		    }

		  if (last != val)
		    {
		      x0 = j;
		      last = val;
1140
1141
1142
1143
		      /* 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
1144
1145
1146
1147
1148
1149
1150
1151
1152
		    }
		}

	      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
1153
1154
		  else
		    g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
Elliot Lee's avatar
Elliot Lee committed
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
1182
1183
		}
	    }

	}
    }

  /*  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;

1184
1185
1186
1187
  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
1188
1189
}

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

  src  = srcPR->data;
1199
  dest = destPR->data;
1200

1201
1202
  for (y = 0; y < srcPR->h; y++)
    {
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
      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;
1213
1214
1215
1216
    }
}

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

  src  = srcPR->data;
1225
  dest = destPR->data;
1226

1227
1228
  for (y = 0; y < srcPR->h; y++)
    {
1229
1230
1231
1232
1233
1234
1235
1236
1237
      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;
1238
1239
1240
1241
    }
}

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

  src  = srcPR->data;
1250
  dest = destPR->data;
1251

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

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

1274
1275
1276
1277
1278