gimplayer.c 42.8 KB
Newer Older
1 2
/* TODO: make sure has_alpha gets set */

Elliot Lee's avatar
Elliot Lee committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* 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
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
19
 */
20

21 22
#include "config.h"

23
#include <stdlib.h>
24
#include <string.h>
25

26 27
#include <glib-object.h>

28 29
#include "libgimpmath/gimpmath.h"

30
#include "core-types.h"
31

32 33 34 35 36
#include "base/boundary.h"
#include "base/pixel-region.h"
#include "base/tile-manager.h"
#include "base/tile.h"

37 38
#include "paint-funcs/paint-funcs.h"

39
#include "gimpdrawable-invert.h"
40
#include "gimpcontainer.h"
41
#include "gimpimage.h"
42
#include "gimpimage-convert.h"
43
#include "gimplayer.h"
44
#include "gimplayer-floating-sel.h"
45
#include "gimplayermask.h"
46
#include "gimpmarshal.h"
47 48
#include "gimpparasitelist.h"

Elliot Lee's avatar
Elliot Lee committed
49
#include "undo.h"
50

51 52 53
#include "libgimp/gimpintl.h"


54 55
enum
{
56 57 58
  OPACITY_CHANGED,
  MODE_CHANGED,
  PRESERVE_TRANS_CHANGED,
59
  LINKED_CHANGED,
60 61 62 63 64
  MASK_CHANGED,
  LAST_SIGNAL
};


65 66
static void    gimp_layer_class_init         (GimpLayerClass     *klass);
static void    gimp_layer_init               (GimpLayer          *layer);
67

68
static void    gimp_layer_finalize           (GObject            *object);
69

70
static gsize   gimp_layer_get_memsize        (GimpObject         *object);
71

72 73 74 75 76 77 78
static void    gimp_layer_invalidate_preview (GimpViewable       *viewable);

static void    gimp_layer_transform_color    (GimpImage          *gimage,
                                              PixelRegion        *layerPR,
                                              PixelRegion        *bufPR,
                                              GimpDrawable       *drawable,
                                              GimpImageBaseType   type);
79 80


81 82 83
static guint  layer_signals[LAST_SIGNAL] = { 0 };

static GimpDrawableClass *parent_class   = NULL;
84

85

86
GType
87
gimp_layer_get_type (void)
88
{
89
  static GType layer_type = 0;
90

91
  if (! layer_type)
92
    {
93
      static const GTypeInfo layer_info =
94
      {
95 96 97 98 99 100
        sizeof (GimpLayerClass),
	(GBaseInitFunc) NULL,
	(GBaseFinalizeFunc) NULL,
	(GClassInitFunc) gimp_layer_class_init,
	NULL,           /* class_finalize */
	NULL,           /* class_data     */
101
	sizeof (GimpLayer),
102 103
	0,              /* n_preallocs    */
	(GInstanceInitFunc) gimp_layer_init,
104 105
      };

106 107 108
      layer_type = g_type_register_static (GIMP_TYPE_DRAWABLE,
					   "GimpLayer",
					   &layer_info, 0);
109 110 111 112 113 114
    }

  return layer_type;
}

static void
115
gimp_layer_class_init (GimpLayerClass *klass)
116
{
117
  GObjectClass      *object_class;
118
  GimpObjectClass   *gimp_object_class;
119
  GimpViewableClass *viewable_class;
120

121 122 123
  object_class      = G_OBJECT_CLASS (klass);
  gimp_object_class = GIMP_OBJECT_CLASS (klass);
  viewable_class    = GIMP_VIEWABLE_CLASS (klass);
124

125
  parent_class = g_type_class_peek_parent (klass);
126

127
  layer_signals[OPACITY_CHANGED] =
128 129 130 131 132
    g_signal_new ("opacity_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpLayerClass, opacity_changed),
		  NULL, NULL,
133
		  gimp_marshal_VOID__VOID,
134
		  G_TYPE_NONE, 0);
135 136

  layer_signals[MODE_CHANGED] =
137 138 139 140 141
    g_signal_new ("mode_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpLayerClass, mode_changed),
		  NULL, NULL,
142
		  gimp_marshal_VOID__VOID,
143
		  G_TYPE_NONE, 0);
144 145

  layer_signals[PRESERVE_TRANS_CHANGED] =
146 147 148 149 150
    g_signal_new ("preserve_trans_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpLayerClass, preserve_trans_changed),
		  NULL, NULL,
151
		  gimp_marshal_VOID__VOID,
152
		  G_TYPE_NONE, 0);
153

154
  layer_signals[LINKED_CHANGED] =
155 156 157 158 159
    g_signal_new ("linked_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpLayerClass, linked_changed),
		  NULL, NULL,
160
		  gimp_marshal_VOID__VOID,
161
		  G_TYPE_NONE, 0);
162

163
  layer_signals[MASK_CHANGED] =
164 165 166 167 168
    g_signal_new ("mask_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpLayerClass, mask_changed),
		  NULL, NULL,
169
		  gimp_marshal_VOID__VOID,
170
		  G_TYPE_NONE, 0);
171

172
  object_class->finalize             = gimp_layer_finalize;
173

174 175
  gimp_object_class->get_memsize     = gimp_layer_get_memsize;

176
  viewable_class->invalidate_preview = gimp_layer_invalidate_preview;
177

178
  klass->mask_changed                = NULL;
179 180 181 182 183
}

static void
gimp_layer_init (GimpLayer *layer)
{
184 185
  layer->linked         = FALSE;
  layer->preserve_trans = FALSE;
186

187
  layer->mask           = NULL;
188

189
  layer->opacity        = GIMP_OPACITY_OPAQUE;
190
  layer->mode           = GIMP_NORMAL_MODE;
191

192 193 194 195 196 197 198
  /*  floating selection  */
  layer->fs.backing_store  = NULL;
  layer->fs.drawable       = NULL;
  layer->fs.initial        = TRUE;
  layer->fs.boundary_known = FALSE;
  layer->fs.segs           = NULL;
  layer->fs.num_segs       = 0;
199 200
}

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
static void
gimp_layer_finalize (GObject *object)
{
  GimpLayer *layer;

  g_return_if_fail (GIMP_IS_LAYER (object));

  layer = GIMP_LAYER (object);

  if (layer->mask)
    {
      g_object_unref (G_OBJECT (layer->mask));
      layer->mask = NULL;
    }

  if (layer->fs.segs)
    {
      g_free (layer->fs.segs);
      layer->fs.segs = NULL;
    }

  /*  free the floating selection if it exists  */
  if (layer->fs.backing_store)
    {
      tile_manager_destroy (layer->fs.backing_store);
      layer->fs.backing_store = NULL;
    }

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
static gsize
gimp_layer_get_memsize (GimpObject *object)
{
  GimpLayer *layer;
  gsize      memsize = 0;

  layer = GIMP_LAYER (object);

  if (layer->mask)
    memsize += gimp_object_get_memsize (GIMP_OBJECT (layer->mask));

  if (layer->fs.backing_store)
    memsize += tile_manager_get_memsize (layer->fs.backing_store);

  memsize += layer->fs.num_segs * sizeof (BoundSeg);

  return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object);
}

Elliot Lee's avatar
Elliot Lee committed
251
static void
252
gimp_layer_invalidate_preview (GimpViewable *viewable)
253 254 255
{
  GimpLayer *layer;

256 257 258
  if (GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview)
    GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable);

259
  layer = GIMP_LAYER (viewable);
260

261
  if (gimp_layer_is_floating_sel (layer))
262
    floating_sel_invalidate (layer);
263 264 265
}

static void
266 267 268 269 270
gimp_layer_transform_color (GimpImage         *gimage,
			    PixelRegion       *layerPR,
			    PixelRegion       *bufPR,
			    GimpDrawable      *drawable,
			    GimpImageBaseType  type)
Elliot Lee's avatar
Elliot Lee committed
271
{
272 273
  gint      i;
  gint      h;
274 275
  guchar   *src;
  guchar   *dest;
276
  gpointer  pr;
Elliot Lee's avatar
Elliot Lee committed
277

278 279
  for (pr = pixel_regions_register (2, layerPR, bufPR);
       pr != NULL;
280
       pr = pixel_regions_process (pr))
Elliot Lee's avatar
Elliot Lee committed
281
    {
282 283 284
      h    = layerPR->h;
      src  = bufPR->data;
      dest = layerPR->data;
Elliot Lee's avatar
Elliot Lee committed
285 286 287 288 289

      while (h--)
	{
	  for (i = 0; i < layerPR->w; i++)
	    {
290
	      gimp_image_transform_color (gimage, drawable,
291 292
					  src  + (i * bufPR->bytes),
					  dest + (i * layerPR->bytes), type);
Elliot Lee's avatar
Elliot Lee committed
293
	      /*  copy alpha channel  */
294
	      dest[(i + 1) * layerPR->bytes - 1] = src[(i + 1) * bufPR->bytes - 1];
Elliot Lee's avatar
Elliot Lee committed
295 296
	    }

297 298
	  src  += bufPR->rowstride;
	  dest += layerPR->rowstride;
Elliot Lee's avatar
Elliot Lee committed
299 300 301 302 303 304
	}
    }
}

/**************************/
/*  Function definitions  */
305
/**************************/
Elliot Lee's avatar
Elliot Lee committed
306

307
GimpLayer *
308 309 310 311 312
gimp_layer_new (GimpImage            *gimage,
		gint                  width,
		gint                  height,
		GimpImageType         type,
		const gchar          *name,
313
		gdouble               opacity,
314
		GimpLayerModeEffects  mode)
Elliot Lee's avatar
Elliot Lee committed
315
{
316
  GimpLayer *layer;
Elliot Lee's avatar
Elliot Lee committed
317

318 319 320
  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
  g_return_val_if_fail (width > 0, NULL);
  g_return_val_if_fail (height > 0, NULL);
Elliot Lee's avatar
Elliot Lee committed
321

Michael Natterer's avatar
Michael Natterer committed
322
  layer = g_object_new (GIMP_TYPE_LAYER, NULL);
Elliot Lee's avatar
Elliot Lee committed
323

324
  gimp_drawable_configure (GIMP_DRAWABLE (layer),
325 326 327 328
			   gimage,
                           width, height,
                           type,
                           name);
Elliot Lee's avatar
Elliot Lee committed
329

330 331
  opacity = CLAMP (opacity, GIMP_OPACITY_TRANSPARENT, GIMP_OPACITY_OPAQUE);

Elliot Lee's avatar
Elliot Lee committed
332
  layer->opacity = opacity;
333
  layer->mode    = mode;
Elliot Lee's avatar
Elliot Lee committed
334 335 336 337

  return layer;
}

338
GimpLayer *
339 340 341
gimp_layer_copy (const GimpLayer *layer,
                 GType            new_type,
		 gboolean         add_alpha)
Elliot Lee's avatar
Elliot Lee committed
342
{
343
  GimpLayer *new_layer;
Elliot Lee's avatar
Elliot Lee committed
344

345 346
  g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL);
  g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_LAYER), NULL);
347

348 349 350
  new_layer = GIMP_LAYER (gimp_drawable_copy (GIMP_DRAWABLE (layer),
                                              new_type,
                                              add_alpha));
351

352
  new_layer->linked         = layer->linked;
Elliot Lee's avatar
Elliot Lee committed
353 354
  new_layer->preserve_trans = layer->preserve_trans;

355 356
  new_layer->mode           = layer->mode;
  new_layer->opacity        = layer->opacity;
Elliot Lee's avatar
Elliot Lee committed
357 358 359 360

  /*  duplicate the layer mask if necessary  */
  if (layer->mask)
    {
361
      new_layer->mask = gimp_layer_mask_copy (layer->mask);
362 363

      gimp_layer_mask_set_layer (new_layer->mask, new_layer);
Elliot Lee's avatar
Elliot Lee committed
364 365 366 367 368
    }

  return new_layer;
}

369 370 371 372 373 374 375 376 377 378 379 380 381 382
/**
 * gimp_layer_new_from_tiles:
 * @tiles:       The buffer to make the new layer from.
 * @dest_gimage: The image the new layer will be added to.
 * @name:        The new layer's name.
 * @opacity:     The new layer's opacity.
 * @mode:        The new layer's mode.
 * 
 * Copies %tiles to a layer taking into consideration the
 * possibility of transforming the contents to meet the requirements
 * of the target image type
 * 
 * Return value: The new layer.
 **/
383
GimpLayer *
384 385
gimp_layer_new_from_tiles (TileManager          *tiles,
                           GimpImage            *dest_gimage,
386
			   const gchar          *name,
387
			   gdouble               opacity,
388
			   GimpLayerModeEffects  mode)
Elliot Lee's avatar
Elliot Lee committed
389
{
390
  GimpLayer   *new_layer;
391 392
  PixelRegion  layerPR;
  PixelRegion  bufPR;
393
  gint         width, height;
Elliot Lee's avatar
Elliot Lee committed
394

395
  g_return_val_if_fail (tiles != NULL, NULL);
396
  g_return_val_if_fail (GIMP_IS_IMAGE (dest_gimage), NULL);
397
  g_return_val_if_fail (name != NULL, NULL);
Elliot Lee's avatar
Elliot Lee committed
398

399 400 401
  width  = tile_manager_width (tiles);
  height = tile_manager_height (tiles);

402
  new_layer = gimp_layer_new (dest_gimage,
403
                              width, height,
404
			      gimp_image_base_type_with_alpha (dest_gimage),
405 406 407
			      name,
			      opacity,
			      mode);
Elliot Lee's avatar
Elliot Lee committed
408

409
  if (! new_layer)
410
    {
411
      g_message ("gimp_layer_new_from_tiles: could not allocate new layer");
412 413
      return NULL;
    }
Elliot Lee's avatar
Elliot Lee committed
414 415

  /*  Configure the pixel regions  */
416 417
  pixel_region_init (&bufPR, tiles,
		     0, 0,
418
		     width, height,
419
		     FALSE);
420 421
  pixel_region_init (&layerPR, GIMP_DRAWABLE (new_layer)->tiles,
		     0, 0,
422
		     width, height,
423
		     TRUE);
Elliot Lee's avatar
Elliot Lee committed
424

425
  if ((tile_manager_bpp (tiles) == 4 &&
426
       GIMP_DRAWABLE (new_layer)->type == GIMP_RGBA_IMAGE) ||
427
      (tile_manager_bpp (tiles) == 2 &&
428
       GIMP_DRAWABLE (new_layer)->type == GIMP_GRAYA_IMAGE))
429 430 431 432
    {
      /*  If we want a layer the same type as the buffer  */
      copy_region (&bufPR, &layerPR);
    }
Elliot Lee's avatar
Elliot Lee committed
433
  else
434 435
    {
      /*  Transform the contents of the buf to the new_layer  */
436
      gimp_layer_transform_color (dest_gimage,
437 438 439 440 441 442
                                  &layerPR, &bufPR,
                                  GIMP_DRAWABLE (new_layer),
                                  ((tile_manager_bpp (tiles) == 4) ? 
                                   GIMP_RGB : GIMP_GRAY));
    }

Elliot Lee's avatar
Elliot Lee committed
443 444 445
  return new_layer;
}

446
GimpLayer *
447 448
gimp_layer_new_from_drawable (GimpDrawable *drawable,
                              GimpImage    *dest_image)
449 450 451 452 453 454 455
{
  GimpImage         *src_image;
  GimpImageBaseType  old_base_type;
  GimpDrawable      *new_drawable;
  GimpImageBaseType  new_base_type;

  g_return_val_if_fail (GIMP_DRAWABLE (drawable), NULL);
456
  g_return_val_if_fail (GIMP_IS_IMAGE (dest_image), NULL);
457

458
  src_image = gimp_item_get_image (GIMP_ITEM (drawable));
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535

  old_base_type = gimp_image_base_type (src_image);
  new_base_type = gimp_image_base_type (dest_image);

  if (GIMP_IS_LAYER (drawable))
    {
      new_drawable = GIMP_DRAWABLE (gimp_layer_copy (GIMP_LAYER (drawable),
                                                     G_TYPE_FROM_INSTANCE (drawable),
                                                     TRUE));
    }
  else
    {
      new_drawable = gimp_drawable_copy (drawable,
                                         GIMP_TYPE_LAYER,
                                         TRUE);
    }

  if (old_base_type != new_base_type)
    {
      TileManager   *new_tiles;
      GimpImageType  new_type;

      new_type = GIMP_IMAGE_TYPE_FROM_BASE_TYPE (new_base_type);

      if (gimp_drawable_has_alpha (new_drawable))
        new_type = GIMP_IMAGE_TYPE_WITH_ALPHA (new_type);

      new_tiles = tile_manager_new (gimp_drawable_width (new_drawable),
                                    gimp_drawable_height (new_drawable),
                                    GIMP_IMAGE_TYPE_BYTES (new_type));

      switch (new_base_type)
        {
        case GIMP_RGB:
          gimp_drawable_convert_rgb (new_drawable,
                                     new_tiles,
                                     old_base_type);
          break;

        case GIMP_GRAY:
          gimp_drawable_convert_grayscale (new_drawable,
                                           new_tiles,
                                           old_base_type);
          break;

        case GIMP_INDEXED:
          {
            PixelRegion layerPR;
            PixelRegion newPR;

            pixel_region_init (&layerPR, new_drawable->tiles,
                               0, 0,
                               gimp_drawable_width (new_drawable),
                               gimp_drawable_height (new_drawable),
                               FALSE);
            pixel_region_init (&newPR, new_tiles,
                               0, 0,
                               gimp_drawable_width (new_drawable),
                               gimp_drawable_height (new_drawable),
                               TRUE);

            gimp_layer_transform_color (dest_image,
                                        &newPR, &layerPR,
                                        NULL,
                                        old_base_type);
          }
          break;
        }

      tile_manager_destroy (new_drawable->tiles);

      new_drawable->tiles     = new_tiles;
      new_drawable->type      = new_type;
      new_drawable->bytes     = GIMP_IMAGE_TYPE_BYTES (new_type);
      new_drawable->has_alpha = GIMP_IMAGE_TYPE_HAS_ALPHA (new_type);
    }

536
  gimp_item_set_image (GIMP_ITEM (new_drawable), dest_image);
537 538 539 540

  return GIMP_LAYER (new_drawable);
}

541 542
GimpLayerMask *
gimp_layer_add_mask (GimpLayer     *layer,
543 544
		     GimpLayerMask *mask,
                     gboolean       push_undo)
Elliot Lee's avatar
Elliot Lee committed
545
{
Michael Natterer's avatar
Michael Natterer committed
546
  GimpImage *gimage;
547 548 549 550

  g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL);
  g_return_val_if_fail (GIMP_IS_LAYER_MASK (mask), NULL);

551
  gimage = gimp_item_get_image (GIMP_ITEM (layer));
552 553 554 555 556 557 558 559

  if (! gimage)
    {
      g_message (_("Cannot add layer mask to layer\n"
                   "which is not part of an image."));
      return NULL;
    }

Elliot Lee's avatar
Elliot Lee committed
560
  if (layer->mask)
561 562 563 564 565 566 567 568 569 570 571 572 573
    {
      g_message(_("Unable to add a layer mask since\n"
                  "the layer already has one."));
      return NULL;
    }

  if (gimp_drawable_is_indexed (GIMP_DRAWABLE (layer)))
    {
      g_message(_("Unable to add a layer mask to a\n"
                  "layer in an indexed image."));
      return NULL;
    }

574
  if (! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
    {
      g_message (_("Cannot add layer mask to a layer\n"
                   "with no alpha channel."));
      return NULL;
    }

  if ((gimp_drawable_width (GIMP_DRAWABLE (layer)) !=
       gimp_drawable_width (GIMP_DRAWABLE (mask))) ||
      (gimp_drawable_height (GIMP_DRAWABLE (layer)) !=
       gimp_drawable_height (GIMP_DRAWABLE (mask))))
    {
      g_message(_("Cannot add layer mask of different\n"
                  "dimensions than specified layer."));
      return NULL;
    }
Elliot Lee's avatar
Elliot Lee committed
590

591 592 593
  layer->mask = mask;

  gimp_layer_mask_set_layer (mask, layer);
Elliot Lee's avatar
Elliot Lee committed
594

595 596 597 598
  gimp_drawable_update (GIMP_DRAWABLE (layer),
			0, 0,
			GIMP_DRAWABLE (layer)->width, 
			GIMP_DRAWABLE (layer)->height);
Elliot Lee's avatar
Elliot Lee committed
599

600
  if (push_undo)
Michael Natterer's avatar
Michael Natterer committed
601
    undo_push_layer_mask_add (gimage, layer, mask);
602

603
  g_signal_emit (G_OBJECT (layer), layer_signals[MASK_CHANGED], 0);
604

Elliot Lee's avatar
Elliot Lee committed
605 606 607
  return layer->mask;
}

608
GimpLayerMask *
609
gimp_layer_create_mask (const GimpLayer *layer,
610
			GimpAddMaskType  add_mask_type)
Elliot Lee's avatar
Elliot Lee committed
611
{
612 613
  PixelRegion    srcPR;
  PixelRegion    destPR;
614
  GimpLayerMask *mask;
615
  GimpImage     *gimage;
616
  gchar         *mask_name;
617
  GimpRGB        black = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE };
Elliot Lee's avatar
Elliot Lee committed
618

619
  gimage = gimp_item_get_image (GIMP_ITEM (layer));
620

621 622
  mask_name = g_strdup_printf (_("%s mask"),
			       gimp_object_get_name (GIMP_OBJECT (layer)));
Elliot Lee's avatar
Elliot Lee committed
623

624
  mask = gimp_layer_mask_new (gimp_item_get_image (GIMP_ITEM (layer)),
625 626 627
			      GIMP_DRAWABLE (layer)->width,
			      GIMP_DRAWABLE (layer)->height,
			      mask_name, &black);
628 629 630

  g_free (mask_name);

631 632
  GIMP_DRAWABLE (mask)->offset_x = GIMP_DRAWABLE (layer)->offset_x;
  GIMP_DRAWABLE (mask)->offset_y = GIMP_DRAWABLE (layer)->offset_y;
Elliot Lee's avatar
Elliot Lee committed
633

634
  pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles, 
635
		     0, 0, 
636 637
		     GIMP_DRAWABLE (mask)->width,
                     GIMP_DRAWABLE (mask)->height, 
638
		     TRUE);
Elliot Lee's avatar
Elliot Lee committed
639 640 641

  switch (add_mask_type)
    {
642
    case GIMP_ADD_WHITE_MASK:
643 644 645 646 647
      {
        guchar white_mask = OPAQUE_OPACITY;

        color_region (&destPR, &white_mask);
      }
Elliot Lee's avatar
Elliot Lee committed
648
      break;
649

650
    case GIMP_ADD_BLACK_MASK:
651 652 653 654 655
      {
        guchar black_mask = TRANSPARENT_OPACITY;

        color_region (&destPR, &black_mask);
      }
Elliot Lee's avatar
Elliot Lee committed
656
      break;
657

658
    case GIMP_ADD_ALPHA_MASK:
659
      if (gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
Elliot Lee's avatar
Elliot Lee committed
660
	{
661
	  pixel_region_init (&srcPR, GIMP_DRAWABLE (layer)->tiles, 
662
			     0, 0, 
663 664
			     GIMP_DRAWABLE (layer)->width, 
			     GIMP_DRAWABLE (layer)->height, 
665
			     FALSE);
666
	  extract_alpha_region (&srcPR, NULL, &destPR);
Elliot Lee's avatar
Elliot Lee committed
667 668
	}
      break;
669

670 671
    case GIMP_ADD_SELECTION_MASK:
    case GIMP_ADD_INVERSE_SELECTION_MASK:
672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
      {
        GimpDrawable *selection;

        selection = GIMP_DRAWABLE (gimage->selection_mask);

        pixel_region_init (&srcPR, GIMP_DRAWABLE (selection)->tiles, 
                           GIMP_DRAWABLE (layer)->offset_x,
                           GIMP_DRAWABLE (layer)->offset_y, 
                           GIMP_DRAWABLE (layer)->width, 
                           GIMP_DRAWABLE (layer)->height, 
                           FALSE);
        copy_region (&srcPR, &destPR);
      }
      break;

687 688
    case GIMP_ADD_COPY_MASK:
    case GIMP_ADD_INVERSE_COPY_MASK:
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
      {
        TileManager   *copy_tiles;
        GimpImageType  layer_type;
        GimpImageType  copy_type;
        guchar         black_uchar[] = { 0, 0, 0, 0 };

        layer_type = GIMP_DRAWABLE (layer)->type;

        copy_type = (GIMP_IMAGE_TYPE_HAS_ALPHA (layer_type) ?
                     GIMP_GRAYA_IMAGE : GIMP_GRAY_IMAGE);

        copy_tiles = tile_manager_new (GIMP_DRAWABLE (layer)->width,
                                       GIMP_DRAWABLE (layer)->height,
                                       GIMP_IMAGE_TYPE_BYTES (copy_type));

        gimp_drawable_convert_grayscale (GIMP_DRAWABLE (layer),
                                         copy_tiles,
                                         GIMP_IMAGE_TYPE_BASE_TYPE (layer_type));

        pixel_region_init (&srcPR, copy_tiles,
                           0, 0,
                           GIMP_DRAWABLE (layer)->width, 
                           GIMP_DRAWABLE (layer)->height, 
                           FALSE);

        if (gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
          {
            flatten_region (&srcPR, &destPR, black_uchar);
          }
        else
          {
            copy_region (&srcPR, &destPR);
          }

        tile_manager_destroy (copy_tiles);
      }
Elliot Lee's avatar
Elliot Lee committed
725 726
    }

727 728
  switch (add_mask_type)
    {
729 730 731 732 733
    case GIMP_ADD_WHITE_MASK:
    case GIMP_ADD_BLACK_MASK:
    case GIMP_ADD_ALPHA_MASK:
    case GIMP_ADD_SELECTION_MASK:
    case GIMP_ADD_COPY_MASK:
734 735
      break;

736 737
    case GIMP_ADD_INVERSE_SELECTION_MASK:
    case GIMP_ADD_INVERSE_COPY_MASK:
738 739 740
      gimp_drawable_invert (GIMP_DRAWABLE (mask));
      break;
    }
741

Elliot Lee's avatar
Elliot Lee committed
742 743 744 745
  return mask;
}

void
746 747 748
gimp_layer_apply_mask (GimpLayer         *layer,
		       GimpMaskApplyMode  mode,
                       gboolean           push_undo)
Elliot Lee's avatar
Elliot Lee committed
749
{
Michael Natterer's avatar
Michael Natterer committed
750 751 752 753 754
  GimpImage   *gimage;
  gint         off_x;
  gint         off_y;
  PixelRegion  srcPR, maskPR;
  gboolean     view_changed = FALSE;
755 756

  g_return_if_fail (GIMP_IS_LAYER (layer));
Elliot Lee's avatar
Elliot Lee committed
757

758
  if (! layer->mask)
Elliot Lee's avatar
Elliot Lee committed
759 760 761
    return;

  /*  this operation can only be done to layers with an alpha channel  */
762
  if (! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
Elliot Lee's avatar
Elliot Lee committed
763 764
    return;

765
  gimage = gimp_item_get_image (GIMP_ITEM (layer));
766 767 768 769 770 771

  if (! gimage)
    return;

  if (push_undo)
    {
Michael Natterer's avatar
Michael Natterer committed
772
      undo_push_group_start (gimage, LAYER_APPLY_MASK_UNDO_GROUP);
773

Michael Natterer's avatar
Michael Natterer committed
774
      undo_push_layer_mask_remove (gimage, layer, layer->mask);
775 776 777
    }

  /*  check if applying the mask changes the projection  */
778 779 780 781 782
  if ((mode == GIMP_MASK_APPLY   && 
       (! layer->mask->apply_mask || layer->mask->show_mask))
      ||
      (mode == GIMP_MASK_DISCARD && 
       (  layer->mask->apply_mask || layer->mask->show_mask)))
783 784 785
    {
      view_changed = TRUE;
    }
Elliot Lee's avatar
Elliot Lee committed
786

787
  if (mode == GIMP_MASK_APPLY)
Elliot Lee's avatar
Elliot Lee committed
788
    {
789 790 791
      if (push_undo)
        {
          /*  Put this apply mask operation on the undo stack  */
792 793 794 795 796
          gimp_drawable_apply_image (GIMP_DRAWABLE (layer),
				     0, 0,
				     GIMP_DRAWABLE (layer)->width,
				     GIMP_DRAWABLE (layer)->height,
				     NULL, FALSE);
797
        }
Elliot Lee's avatar
Elliot Lee committed
798 799

      /*  Combine the current layer's alpha channel and the mask  */
800
      pixel_region_init (&srcPR, GIMP_DRAWABLE (layer)->tiles, 
801
			 0, 0, 
802
			 GIMP_DRAWABLE (layer)->width, 
803
			 GIMP_DRAWABLE (layer)->height, 
804
			 TRUE);
805 806 807
      pixel_region_init (&maskPR, GIMP_DRAWABLE (layer->mask)->tiles, 
			 0, 0, 
			 GIMP_DRAWABLE (layer)->width, 
808
			 GIMP_DRAWABLE (layer)->height, 
809
			 FALSE);
Elliot Lee's avatar
Elliot Lee committed
810

Manish Singh's avatar
Manish Singh committed
811
      apply_mask_to_region (&srcPR, &maskPR, OPAQUE_OPACITY);
812
      GIMP_DRAWABLE (layer)->preview_valid = FALSE;
813
    }
Elliot Lee's avatar
Elliot Lee committed
814

Michael Natterer's avatar
Michael Natterer committed
815
  g_object_unref (G_OBJECT (layer->mask));
816
  layer->mask = NULL;
817 818 819 820

  if (push_undo)
    {
      undo_push_group_end (gimage);
Elliot Lee's avatar
Elliot Lee committed
821
    }
822 823 824

  /*  If applying actually changed the view  */
  if (view_changed)
Elliot Lee's avatar
Elliot Lee committed
825
    {
826 827 828 829
      gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage));

      gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y);

830 831 832 833
      gimp_drawable_update (GIMP_DRAWABLE (layer),
			    0, 0,
			    gimp_drawable_width  (GIMP_DRAWABLE (layer)),
			    gimp_drawable_height (GIMP_DRAWABLE (layer)));
Elliot Lee's avatar
Elliot Lee committed
834
    }
835

836
  g_signal_emit (G_OBJECT (layer), layer_signals[MASK_CHANGED], 0);
Elliot Lee's avatar
Elliot Lee committed
837 838
}

839
void
840 841 842
gimp_layer_translate (GimpLayer *layer,
		      gint       off_x,
		      gint       off_y)
Elliot Lee's avatar
Elliot Lee committed
843
{
844
  /*  the undo call goes here  */
845
  undo_push_layer_displace (gimp_item_get_image (GIMP_ITEM (layer)), layer);
Elliot Lee's avatar
Elliot Lee committed
846 847

  /*  update the affected region  */
848 849 850 851
  gimp_drawable_update (GIMP_DRAWABLE (layer),
			0, 0, 
			GIMP_DRAWABLE (layer)->width, 
			GIMP_DRAWABLE (layer)->height);
Elliot Lee's avatar
Elliot Lee committed
852

853
  /*  invalidate the selection boundary because of a layer modification  */
854
  gimp_layer_invalidate_boundary (layer);
855
 
Elliot Lee's avatar
Elliot Lee committed
856
  /*  update the layer offsets  */
857 858
  GIMP_DRAWABLE (layer)->offset_x += off_x;
  GIMP_DRAWABLE (layer)->offset_y += off_y;
Elliot Lee's avatar
Elliot Lee committed
859 860

  /*  update the affected region  */
861 862 863 864
  gimp_drawable_update (GIMP_DRAWABLE (layer), 
			0, 0, 
			GIMP_DRAWABLE (layer)->width, 
			GIMP_DRAWABLE (layer)->height);
Elliot Lee's avatar
Elliot Lee committed
865

866 867
  if (layer->mask) 
    {
868 869
      GIMP_DRAWABLE (layer->mask)->offset_x += off_x;
      GIMP_DRAWABLE (layer->mask)->offset_y += off_y;
870

871
      /*  invalidate the mask preview  */
872
      gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer->mask));
873
    }
Elliot Lee's avatar
Elliot Lee committed
874 875 876
}

void
877
gimp_layer_add_alpha (GimpLayer *layer)
Elliot Lee's avatar
Elliot Lee committed
878
{
879 880 881
  PixelRegion    srcPR, destPR;
  TileManager   *new_tiles;
  GimpImageType  type;
882
  GimpImage     *gimage;
Elliot Lee's avatar
Elliot Lee committed
883

884 885 886 887
  if (gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
    return;

  type = gimp_drawable_type_with_alpha (GIMP_DRAWABLE (layer));
Elliot Lee's avatar
Elliot Lee committed
888 889

  /*  Configure the pixel regions  */
890
  pixel_region_init (&srcPR, GIMP_DRAWABLE (layer)->tiles, 
891
		     0, 0, 
892 893
		     GIMP_DRAWABLE (layer)->width, 
		     GIMP_DRAWABLE (layer)->height, 
894
		     FALSE);
Elliot Lee's avatar
Elliot Lee committed
895 896

  /*  Allocate the new layer, configure dest region  */
897 898
  new_tiles = tile_manager_new (GIMP_DRAWABLE (layer)->width, 
				GIMP_DRAWABLE (layer)->height, 
899
				gimp_drawable_bytes_with_alpha (GIMP_DRAWABLE (layer)));
900 901
  pixel_region_init (&destPR, new_tiles, 
		     0, 0, 
902 903
		     GIMP_DRAWABLE (layer)->width, 
		     GIMP_DRAWABLE (layer)->height, 
904
		     TRUE);
Elliot Lee's avatar
Elliot Lee committed
905 906 907 908 909

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

  /*  Push the layer on the undo stack  */
910
  undo_push_layer_mod (gimp_item_get_image (GIMP_ITEM (layer)), layer);
Elliot Lee's avatar
Elliot Lee committed
911 912

  /*  Configure the new layer  */
913 914
  GIMP_DRAWABLE (layer)->tiles         = new_tiles;
  GIMP_DRAWABLE (layer)->type          = type;
915
  GIMP_DRAWABLE (layer)->bytes         = GIMP_DRAWABLE (layer)->bytes + 1;
916 917
  GIMP_DRAWABLE (layer)->has_alpha     = GIMP_IMAGE_TYPE_HAS_ALPHA (type);
  GIMP_DRAWABLE (layer)->preview_valid = FALSE;
Elliot Lee's avatar
Elliot Lee committed
918

919
  gimage = gimp_item_get_image (GIMP_ITEM (layer));
920 921 922 923 924

  if (gimage->layers->num_children == 1)
    {
      gimp_image_alpha_changed (gimage);
    }
Elliot Lee's avatar
Elliot Lee committed
925 926
}

927
static void
928 929 930 931 932 933
gimp_layer_scale_lowlevel (GimpLayer             *layer,
			   gint                   new_width,
			   gint                   new_height,
			   gint                   new_offset_x,
			   gint                   new_offset_y,
                           GimpInterpolationType  interpolation_type)
Elliot Lee's avatar
Elliot Lee committed
934
{
935
  PixelRegion  srcPR, destPR;
Elliot Lee's avatar
Elliot Lee committed
936 937 938
  TileManager *new_tiles;

  /*  Update the old layer position  */
939 940 941 942
  gimp_drawable_update (GIMP_DRAWABLE (layer),
			0, 0,
			GIMP_DRAWABLE (layer)->width, 
			GIMP_DRAWABLE (layer)->height);
Elliot Lee's avatar
Elliot Lee committed
943 944

  /*  Configure the pixel regions  */
945 946
  pixel_region_init (&srcPR, GIMP_DRAWABLE(layer)->tiles, 
		     0, 0, 
947 948
		     GIMP_DRAWABLE (layer)->width, 
		     GIMP_DRAWABLE (layer)->height, 
949
		     FALSE);
Elliot Lee's avatar
Elliot Lee committed
950 951

  /*  Allocate the new layer, configure dest region  */
952
  new_tiles = tile_manager_new (new_width, new_height, 
953
				GIMP_DRAWABLE (layer)->bytes);
954 955 956 957
  pixel_region_init (&destPR, new_tiles, 
		     0, 0, 
		     new_width, new_height, 
		     TRUE);
Elliot Lee's avatar
Elliot Lee committed
958 959 960 961 962 963

  /*  Scale the layer -
   *   If the layer is of type INDEXED, then we don't use pixel-value
   *   resampling because that doesn't necessarily make sense for INDEXED
   *   images.
   */
964 965
  if (GIMP_IMAGE_TYPE_IS_INDEXED (GIMP_DRAWABLE (layer)->type))
    {
966
      scale_region (&srcPR, &destPR, GIMP_INTERPOLATION_NONE);
967
    }
Elliot Lee's avatar
Elliot Lee committed
968
  else
969 970 971
    {
      scale_region (&srcPR, &destPR, interpolation_type);
    }
Elliot Lee's avatar
Elliot Lee committed
972 973

  /*  Push the layer on the undo stack  */
974
  undo_push_layer_mod (gimp_item_get_image (GIMP_ITEM (layer)), layer);
Elliot Lee's avatar
Elliot Lee committed
975 976 977

  /*  Configure the new layer  */

978 979 980 981 982
  GIMP_DRAWABLE (layer)->offset_x = new_offset_x;
  GIMP_DRAWABLE (layer)->offset_y = new_offset_y;
  GIMP_DRAWABLE (layer)->tiles    = new_tiles;
  GIMP_DRAWABLE (layer)->width    = new_width;
  GIMP_DRAWABLE (layer)->height   = new_height;
Elliot Lee's avatar
Elliot Lee committed
983

984 985 986
  /*  If there is a layer mask, make sure it gets scaled also  */
  if (layer->mask) 
    {
987 988
      GIMP_DRAWABLE (layer->mask)->offset_x = GIMP_DRAWABLE (layer)->offset_x;
      GIMP_DRAWABLE (layer->mask)->offset_y = GIMP_DRAWABLE (layer)->offset_y;
989 990 991

      gimp_channel_scale (GIMP_CHANNEL (layer->mask), new_width, new_height,
                          interpolation_type);
992
    }
993 994

  /*  Make sure we're not caching any old selection info  */
995 996
  gimp_layer_invalidate_boundary (layer);

Elliot Lee's avatar
Elliot Lee committed
997
  /*  Update the new layer position  */
998 999 1000 1001
  gimp_drawable_update (GIMP_DRAWABLE (layer),
			0, 0,
			GIMP_DRAWABLE (layer)->width, 
			GIMP_DRAWABLE (layer)->height);
Elliot Lee's avatar
Elliot Lee committed
1002 1003
}

1004
/**
1005
 * gimp_layer_check_scaling:
1006
 * @layer:      Layer to check
1007 1008
 * @new_width:  proposed width of layer's image, in pixels
 * @new_height: proposed height of layer's image, in pixels
1009
 *
1010
 * Scales layer dimensions, then snaps them to pixel centers
1011
 *
1012 1013 1014
 * Returns: #FALSE if any dimension reduces to zero as a result 
 *          of this; otherwise, returns #TRUE.
 **/
1015
gboolean
1016 1017 1018
gimp_layer_check_scaling (const GimpLayer *layer,
			  gint             new_width,
			  gint             new_height)
1019
{
1020 1021 1022 1023 1024 1025
  GimpImage *gimage;
  gdouble    img_scale_w;
  gdouble    img_scale_h;
  gint       new_layer_width;
  gint       new_layer_height;

1026
  gimage           = gimp_item_get_image (GIMP_ITEM (layer));
1027 1028 1029 1030 1031 1032 1033 1034
  img_scale_w      = (gdouble) new_width  / (gdouble) gimage->width;
  img_scale_h      = (gdouble) new_height / (gdouble) gimage->height;
  new_layer_width  = ROUND (img_scale_w *
			    (gdouble) GIMP_DRAWABLE (layer)->width);
  new_layer_height = ROUND (img_scale_h *
			    (gdouble) GIMP_DRAWABLE (layer)->height);

  return (new_layer_width != 0 && new_layer_height != 0);  
1035 1036 1037
}

/**
1038
 * gimp_layer_scale_by_factors:
1039
 * @layer:    Layer to be transformed by explicit width and height factors.
1040 1041 1042 1043 1044
 * @w_factor: scale factor to apply to width and horizontal offset
 * @h_factor: scale factor to apply to height and vertical offset
 * 
 * Scales layer dimensions and offsets by uniform width and
 * height factors.
1045
 *
1046
 * Use gimp_layer_scale_by_factors() in circumstances when the
1047 1048 1049 1050 1051 1052 1053
 * same width and height scaling factors are to be uniformly
 * applied to a set of layers. In this context, the layer's
 * dimensions and offsets from the sides of the containing
 * image all change by these predetermined factors. By fiat,
 * the fixed point of the transform is the upper left hand
 * corner of the image. Returns gboolean FALSE if a requested
 * scale factor is zero or if a scaling zero's out a layer
1054
 * dimension; returns #TRUE otherwise.
1055
 *
1056
 * Use gimp_layer_scale() in circumstances where new layer width
1057 1058
 * and height dimensions are predetermined instead.
 *
1059 1060
 * Side effects: Undo set created for layer. Old layer imagery 
 *               scaled & painted to new layer tiles. 
1061
 *
1062 1063 1064
 * Returns: #TRUE, if the scaled layer has positive dimensions
 *          #FALSE if the scaled layer has at least one zero dimension
 **/
1065
gboolean
1066 1067 1068 1069
gimp_layer_scale_by_factors (GimpLayer             *layer,
			     gdouble                w_factor,
			     gdouble                h_factor,
                             GimpInterpolationType  interpolation_type)
1070
{
1071 1072
  gint new_width, new_height;
  gint new_offset_x, new_offset_y;
1073

1074 1075
  if (w_factor == 0.0 || h_factor == 0.0)
    {
1076
      g_message ("gimp_layer_scale_by_factors: Error. Requested width or height scale equals zero.");
1077 1078 1079
      return FALSE;
    }

1080 1081 1082 1083
  new_offset_x = ROUND (w_factor * (gdouble) GIMP_DRAWABLE (layer)->offset_x);
  new_offset_y = ROUND (h_factor * (gdouble) GIMP_DRAWABLE (layer)->offset_y);
  new_width    = ROUND (w_factor * (gdouble) GIMP_DRAWABLE (layer)->width);
  new_height   = ROUND (h_factor * (gdouble) GIMP_DRAWABLE (layer)->height);
1084

1085
  if (new_width != 0 && new_height != 0)
1086
    {
1087 1088
      gimp_layer_scale_lowlevel (layer,
				 new_width, new_height,
1089 1090
				 new_offset_x, new_offset_y,
                                 interpolation_type);
1091 1092
      return TRUE;
    }
1093 1094

  return FALSE;
1095 1096 1097
}

/**
1098
 * gimp_layer_scale:
1099
 * @layer:        The layer to be transformed by width & height scale factors
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
 * @new_width:    The width that layer will acquire
 * @new_height:   The height that the layer will acquire
 * @local_origin: sets fixed point of the scaling transform. See below.
 *
 * Sets layer dimensions to new_width and
 * new_height. Derives vertical and horizontal scaling
 * transforms from new width and height. If local_origin is
 * TRUE, the fixed point of the scaling transform coincides
 * with the layer's center point.  Otherwise, the fixed
 * point is taken to be [-GIMP_DRAWABLE(layer)->offset_x,
 * -GIMP_DRAWABLE(layer)->offset_y].
 *
 * Since this function derives scale factors from new and
 * current layer dimensions, these factors will vary from
 * layer to layer because of aliasing artifacts; factor
 * variations among layers can be quite large where layer
 * dimensions approach pixel dimensions. Use 
1117
 * gimp_layer_scale_by_factors() where constant scales are to
1118 1119 1120 1121 1122
 * be uniformly applied to a number of layers.
 *
 * Side effects: undo set created for layer.
 *               Old layer imagery scaled 
 *               & painted to new layer tiles 
1123
 **/
1124
void
1125 1126 1127 1128 1129
gimp_layer_scale (GimpLayer             *layer,
		  gint                   new_width,
		  gint                   new_height,
                  GimpInterpolationType  interpolation_type,
		  gboolean               local_origin)
1130 1131 1132 1133 1134
{
  gint new_offset_x, new_offset_y;

  if (new_width == 0 || new_height == 0)
    {
1135
      g_message ("gimp_layer_scale: Error. Requested width or height equals zero.");
1136 1137
      return;
    }
1138

1139 1140
  if (local_origin)
    {
1141 1142 1143 1144 1145
      new_offset_x = GIMP_DRAWABLE (layer)->offset_x + 
	((GIMP_DRAWABLE (layer)->width  - new_width) / 2.0);

      new_offset_y = GIMP_DRAWABLE (layer)->offset_y + 
	((GIMP_DRAWABLE (layer)->height - new_height) / 2.0);
1146 1147 1148
    }
  else
    {
1149 1150 1151 1152 1153 1154 1155
      new_offset_x = (gint) (((gdouble) new_width * 
			      GIMP_DRAWABLE (layer)->offset_x / 
			      (gdouble) GIMP_DRAWABLE (layer)->width));

      new_offset_y = (gint) (((gdouble) new_height * 
			      GIMP_DRAWABLE (layer)->offset_y / 
			      (gdouble) GIMP_DRAWABLE (layer)->height));
1156
    }
1157 1158 1159

  gimp_layer_scale_lowlevel (layer, 
			     new_width, new_height, 
1160 1161
			     new_offset_x, new_offset_y,
                             interpolation_type);
1162 1163
}

Elliot Lee's avatar
Elliot Lee committed
1164
void
1165 1166 1167 1168 1169
gimp_layer_resize (GimpLayer *layer,
		   gint       new_width,
		   gint       new_height,
		   gint       offx,
		   gint       offy)
Elliot Lee's avatar
Elliot Lee committed
1170
{
1171
  PixelRegion  srcPR, destPR;
Elliot Lee's avatar
Elliot Lee committed
1172
  TileManager *new_tiles;
1173 1174
  gint         w, h;
  gint         x1, y1, x2, y2;
Elliot Lee's avatar
Elliot Lee committed
1175

1176
  if (new_width < 1 || new_height < 1)
Elliot Lee's avatar
Elliot Lee committed
1177 1178
    return;

1179 1180
  x1 = CLAMP (offx, 0, new_width);
  y1 = CLAMP (offy, 0, new_height);
1181
  x2 = CLAMP ((offx + GIMP_DRAWABLE(layer)->width),  0, new_width);
1182
  y2 = CLAMP ((offy + GIMP_DRAWABLE(layer)->height), 0, new_height);
Elliot Lee's avatar
Elliot Lee committed
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
  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 layer position  */
1209 1210 1211 1212
  gimp_drawable_update (GIMP_DRAWABLE( layer),
			0, 0,
			GIMP_DRAWABLE (layer)->width,
			GIMP_DRAWABLE (layer)->height);
Elliot Lee's avatar
Elliot Lee committed
1213 1214

  /*  Configure the pixel regions  */
1215
  pixel_region_init (&srcPR, GIMP_DRAWABLE (layer)->tiles, 
1216 1217 1218
		     x1, y1, 
		     w, h, 
		     FALSE);
Elliot Lee's avatar
Elliot Lee committed
1219 1220

  /*  Allocate the new layer, configure dest region  */
1221
  new_tiles = tile_manager_new (new_width, new_height, 
1222
				GIMP_DRAWABLE (layer)->bytes);
1223 1224 1225 1226
  pixel_region_init (&destPR, new_tiles, 
		     0, 0, 
		     new_width, new_height, 
		     TRUE);
Elliot Lee's avatar
Elliot Lee committed
1227 1228

  /*  fill with the fill color  */
1229
  if (gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
Elliot Lee's avatar
Elliot Lee committed
1230 1231
    {
      /*  Set to transparent and black  */
1232 1233
      guchar bg[4] = {0, 0, 0, 0};

Elliot Lee's avatar
Elliot Lee committed
1234 1235 1236 1237
      color_region (&destPR, bg);
    }
  else
    {
1238 1239
      guchar bg[3];

1240
      gimp_image_get_background (gimp_item_get_image (GIMP_ITEM (layer)),
1241
				 GIMP_DRAWABLE (layer), bg);
Elliot Lee's avatar
Elliot Lee committed
1242 1243
      color_region (&destPR, bg);
    }
1244

1245 1246 1247 1248
  pixel_region_init (&destPR, new_tiles, 
		     x2, y2, 
		     w, h, 
		     TRUE);
Elliot Lee's avatar
Elliot Lee committed
1249 1250 1251 1252 1253 1254

  /*  copy from the old to the new  */
  if (w && h)
    copy_region (&srcPR, &destPR);

  /*  Push the layer on the undo stack  */
1255
  undo_push_layer_mod (gimp_item_get_image (GIMP_ITEM (layer)), layer);
Elliot Lee's avatar
Elliot Lee committed
1256 1257

  /*  Configure the new layer  */
1258 1259 1260 1261 1262
  GIMP_DRAWABLE (layer)->tiles = new_tiles;
  GIMP_DRAWABLE (layer)->offset_x = x1 + GIMP_DRAWABLE (layer)->offset_x - x2;
  GIMP_DRAWABLE (layer)->offset_y = y1 + GIMP_DRAWABLE (layer)->offset_y - y2;
  GIMP_DRAWABLE (layer)->width = new_width;
  GIMP_DRAWABLE (layer)->height = new_height;
1263 1264

  /*  If there is a layer mask, make sure it gets resized also  */
1265 1266
  if (layer->mask)
    {
1267 1268
      GIMP_DRAWABLE (layer->mask)->offset_x = GIMP_DRAWABLE (layer)->offset_x;
      GIMP_DRAWABLE (layer->mask)->offset_y = GIMP_DRAWABLE (layer)->offset_y;
1269 1270
      gimp_channel_resize (GIMP_CHANNEL (layer->mask),
			   new_width, new_height, offx, offy);
1271
    }
Elliot Lee's avatar
Elliot Lee committed
1272

1273
  /*  Make sure we're not caching any old selection info  */
1274
  gimp_layer_invalidate_boundary (layer);
1275

Elliot Lee's avatar
Elliot Lee committed
1276
  /*  update the new layer area  */
1277 1278 1279 1280
  gimp_drawable_update (GIMP_DRAWABLE (layer),
			0, 0,
			GIMP_DRAWABLE (layer)->width,
			GIMP_DRAWABLE (layer)->height