1/*
2    PPDocument_Layers.m
3
4    Copyright 2013-2018 Josh Freeman
5    http://www.twilightedge.com
6
7    This file is part of PikoPixel for Mac OS X and GNUstep.
8    PikoPixel is a graphical application for drawing & editing pixel-art images.
9
10    PikoPixel is free software: you can redistribute it and/or modify it under
11    the terms of the GNU Affero General Public License as published by the
12    Free Software Foundation, either version 3 of the License, or (at your
13    option) any later version approved for PikoPixel by its copyright holder (or
14    an authorized proxy).
15
16    PikoPixel is distributed in the hope that it will be useful, but WITHOUT ANY
17    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18    FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19    details.
20
21    You should have received a copy of the GNU Affero General Public License
22    along with this program. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#import "PPDocument.h"
26
27#import "PPDocument_Notifications.h"
28#import "PPDocumentLayer.h"
29#import "PPGeometry.h"
30#import "NSImage_PPUtilities.h"
31#import "NSBitmapImageRep_PPUtilities.h"
32#import "PPAppBootUtilities.h"
33
34
35static NSObject *gEmptyImageObject = nil;
36static NSBitmapImageRep *gEmptyBitmap = nil;
37
38
39@interface PPDocument (LayersPrivateMethods)
40
41- (bool) hasLayerAtIndex: (int) index;
42- (bool) isValidLayerInsertionIndex: (int) index;
43- (int) indexOfLayer: (PPDocumentLayer *) layer;
44
45- (bool) setupLayerForCurrentBlendingMode: (PPDocumentLayer *) layer;
46- (bool) setupAllLayersForCurrentBlendingMode;
47
48- (void) invalidateAllRelativeCachedLayerImagesForIndex: (int) index;
49- (void) invalidateCachedLayerImagesAtIndex: (int) index;
50- (void) invalidateImageObjectsInCache: (NSObject **) cachedImageObjectsArray
51            fromIndex: (int) startIndex
52            toIndex: (int) endIndex;
53- (void) removeAllCachedLayersImages;
54
55- (NSObject *) cachedOverlayersImageObjectForIndex: (int) index;
56- (NSObject *) cachedUnderlayersImageObjectForIndex: (int) index;
57
58- (NSObject *) mergedLayersImageObjectFromIndex: (int) firstIndex
59                toIndex: (int) lastIndex;
60
61- (NSBitmapImageRep *) mergedLayersBitmapFromIndex: (int) firstIndex
62                        toIndex: (int) lastIndex;
63
64- (void) updateMergedVisibleLayersBitmapInRect: (NSRect) rect
65            indexOfUpdatedLayer: (int) indexOfUpdatedLayer;
66
67- (NSString *) uniqueLayerNameWithRoot: (NSString *) rootName;
68- (NSString *) duplicateNameForLayerName: (NSString *) layerName;
69
70- (void) setupDrawingLayerWithLayerAtIndex: (int) newDrawingLayerIndex
71            andPostNotification: (bool) shouldPostNotification;
72
73- (void) setupDrawingLayerWithLayerAtIndex: (int) newDrawingLayerIndex;
74
75- (void) setupDrawingLayerMembers;
76
77- (void) mergeDrawingLayerWithNextLayerInDirection: (PPDirectionType) directionType;
78
79- (bool) handleUpdateToLayer: (PPDocumentLayer *) layer;
80- (void) handleUpdateToDrawingLayerInRect: (NSRect) updateRect;
81
82- (void) updateDissolvedDrawingLayerBitmapInRect: (NSRect) updateRect;
83
84- (void) insertArchivedLayer: (NSData *) archivedLayer
85            atIndex: (int) index
86            andSetAsDrawingLayer: (bool) shouldSetAsDrawingLayer;
87
88- (bool) setLayersWithArchivedLayersData: (NSData *) archivedLayersData;
89
90- (void) setName: (NSString *) name forLayerAtIndex: (int) index;
91- (void) setEnabledFlag: (bool) isEnabled forLayerAtIndex: (int) index;
92- (void) setOpacity: (float) opacity forLayerAtIndex: (int) index;
93
94- (void) copyTIFFData: (NSData *) tiffData
95            toLayerAtIndex: (int) index
96            atPoint: (NSPoint) origin;
97
98- (void) recacheMergedVisibleLayersThumbnailImageInBounds: (NSRect) bounds;
99- (void) recacheDissolvedDrawingLayerThumbnailImageInBounds: (NSRect) bounds;
100
101@end
102
103@implementation NSObject (PPDocument_Layers)
104
105+ (void) ppDocument_Layers_SetupGlobals
106{
107    gEmptyImageObject = [[NSNull null] retain];
108
109    gEmptyBitmap = [[NSBitmapImageRep ppMaskBitmapOfSize: NSMakeSize(1,1)] retain];
110}
111
112+ (void) load
113{
114    macroPerformNSObjectSelectorAfterAppLoads(ppDocument_Layers_SetupGlobals);
115}
116
117@end
118
119@implementation PPDocument (Layers)
120
121- (int) numLayers
122{
123    return _numLayers;
124}
125
126- (PPDocumentLayer *) layerAtIndex: (int) index
127{
128    if (![self hasLayerAtIndex: index])
129    {
130        return nil;
131    }
132
133    return (PPDocumentLayer *) [_layers objectAtIndex: index];
134}
135
136- (void) createNewLayer
137{
138    NSString *newLayerName;
139    PPDocumentLayer *newLayer;
140    int insertionIndex;
141
142    if (!_numLayers)
143    {
144        newLayerName = @"Main Layer";
145        insertionIndex = 0;
146    }
147    else
148    {
149        newLayerName = [self uniqueLayerNameWithRoot: @"New Layer"];
150        insertionIndex = _indexOfDrawingLayer + 1;
151    }
152
153    newLayer = [PPDocumentLayer layerWithSize: _canvasFrame.size andName: newLayerName];
154
155    if (!newLayer)
156        goto ERROR;
157
158    [self insertLayer: newLayer atIndex: insertionIndex andSetAsDrawingLayer: YES];
159
160    [[self undoManager] setActionName: @"Add Layer"];
161
162    return;
163
164ERROR:
165    return;
166}
167
168- (void) insertLayer: (PPDocumentLayer *) layer
169            atIndex: (int) index
170            andSetAsDrawingLayer: (bool) shouldSetAsDrawingLayer
171{
172    int oldDrawingLayerIndex;
173    NSUndoManager *undoManager;
174
175    if (!layer || ![self isValidLayerInsertionIndex: index])
176    {
177        return;
178    }
179
180    // manually invalidate relevant cached images that won't be invalidated later by
181    // invalidateAllRelativeCachedLayerImagesForIndex: (called by handleUpdateToLayerAtIndex:)
182
183    [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects
184            fromIndex: index
185            toIndex: _numLayers - 1];
186
187    [layer setDelegate: self];
188
189    [self setupLayerForCurrentBlendingMode: layer];
190
191    [_layers insertObject: layer atIndex: index];
192    _numLayers = [_layers count];
193
194    oldDrawingLayerIndex = _indexOfDrawingLayer;
195
196    if (shouldSetAsDrawingLayer)
197    {
198        [self setupDrawingLayerWithLayerAtIndex: index andPostNotification: NO];
199    }
200    else if (_indexOfDrawingLayer >= index)
201    {
202        _indexOfDrawingLayer++;
203    }
204
205    [self handleUpdateToLayerAtIndex: index inRect: _canvasFrame];
206
207    undoManager = [self undoManager];
208
209    if (shouldSetAsDrawingLayer)
210    {
211        [[undoManager prepareWithInvocationTarget: self]
212                                    setupDrawingLayerWithLayerAtIndex: oldDrawingLayerIndex];
213    }
214
215    [[undoManager prepareWithInvocationTarget: self] removeLayerAtIndex: index];
216
217    if (![undoManager isUndoing] && ![undoManager isRedoing])
218    {
219        [undoManager setActionName: @"Insert Layer"];
220    }
221
222    [self postNotification_ReorderedLayers];
223}
224
225- (void) removeLayerAtIndex: (int) index
226{
227    int topLayerIndex;
228    PPDocumentLayer *layer;
229    NSData *archivedLayer = nil;
230    bool needToSetDrawingLayer = NO;
231    NSUndoManager *undoManager;
232
233    if (![self hasLayerAtIndex: index])
234    {
235        return;
236    }
237
238    // manually invalidate relevant cached images that won't be invalidated later by
239    // invalidateAllRelativeCachedLayerImagesForIndex: (called by handleUpdateToLayerAtIndex:)
240
241    topLayerIndex = _numLayers - 1;
242    [self invalidateCachedLayerImagesAtIndex: topLayerIndex];
243    [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects
244            fromIndex: index
245            toIndex: topLayerIndex];
246
247    layer = [_layers objectAtIndex: index];
248    [layer setDelegate: nil];
249
250    archivedLayer = [NSKeyedArchiver archivedDataWithRootObject: layer];
251
252    [_layers removeObjectAtIndex: index];
253    _numLayers = [_layers count];
254
255    if (index == _indexOfDrawingLayer)
256    {
257        needToSetDrawingLayer = YES;
258    }
259
260    undoManager = [self undoManager];
261
262    // need to register insertArchivedLayer:... undo invocation before the call to
263    // createNewLayer, because createNewLayer registers an undo invocation for
264    // removeLayerAtIndex: (which might cause layer ordering & draw layer index issues on
265    // undo if the old removed layer is inserted before the newly-created layer is removed)
266
267    [[undoManager prepareWithInvocationTarget: self]
268                                                insertArchivedLayer: archivedLayer
269                                                atIndex: index
270                                                andSetAsDrawingLayer: needToSetDrawingLayer];
271
272    if (!_numLayers)
273    {
274        if (![undoManager isUndoing] && ![undoManager isRedoing])
275        {
276            [self createNewLayer];
277        }
278    }
279    else if (needToSetDrawingLayer)
280    {
281        index = _indexOfDrawingLayer;
282
283        if (index > 0)
284        {
285            index--;
286
287            [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects
288                    fromIndex: index
289                    toIndex: index];
290        }
291
292        [self setupDrawingLayerWithLayerAtIndex: index andPostNotification: NO];
293    }
294    else if (_indexOfDrawingLayer > index)
295    {
296        _indexOfDrawingLayer--;
297    }
298
299    if (index >= _numLayers)
300    {
301        index--;
302    }
303
304    [self handleUpdateToLayerAtIndex: index inRect: _canvasFrame];
305
306    if (![undoManager isUndoing] && ![undoManager isRedoing])
307    {
308        [undoManager setActionName: @"Delete Layer"];
309    }
310
311    [self postNotification_ReorderedLayers];
312}
313
314- (void) moveLayerAtIndex: (int) oldIndex
315            toIndex: (int) newIndex
316{
317    PPDocumentLayer *layer;
318    NSUndoManager *undoManager;
319
320    if (![self hasLayerAtIndex: oldIndex]
321        || ![self hasLayerAtIndex: newIndex]
322        || (oldIndex == newIndex))
323    {
324        return;
325    }
326
327    // manually invalidate relevant cached images that won't be invalidated later by
328    // invalidateAllRelativeCachedLayerImagesForIndex: (called by
329    // handleUpdateToLayerAtIndex: newIndex)
330
331    if (oldIndex < newIndex)
332    {
333        [self invalidateImageObjectsInCache: _cachedUnderlayersImageObjects
334                fromIndex: oldIndex + 1
335                toIndex: newIndex];
336    }
337    else
338    {
339        [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects
340                fromIndex: newIndex
341                toIndex: oldIndex - 1];
342    }
343
344    layer = [[[_layers objectAtIndex: oldIndex] retain] autorelease];
345
346    [_layers removeObjectAtIndex: oldIndex];
347    [_layers insertObject: layer atIndex: newIndex];
348
349    _indexOfDrawingLayer = [_layers indexOfObject: _drawingLayer];
350
351    undoManager = [self undoManager];
352    [[undoManager prepareWithInvocationTarget: self] moveLayerAtIndex: newIndex
353                                                                toIndex: oldIndex];
354
355    if (![undoManager isUndoing] && ![undoManager isRedoing])
356    {
357        [undoManager setActionName: @"Reorder Layers"];
358    }
359
360    [self handleUpdateToLayerAtIndex: newIndex inRect: _canvasFrame];
361
362    [self postNotification_ReorderedLayers];
363}
364
365- (void) duplicateLayerAtIndex: (int) index
366{
367    PPDocumentLayer *dupeLayer;
368    NSString *dupeLayerName;
369
370    if (![self hasLayerAtIndex: index])
371    {
372        return;
373    }
374
375    dupeLayer = [[[_layers objectAtIndex: index] copy] autorelease];
376
377    if (!dupeLayer)
378        goto ERROR;
379
380    dupeLayerName = [self duplicateNameForLayerName: [dupeLayer name]];
381
382    [dupeLayer setName: dupeLayerName];
383
384    [self insertLayer: dupeLayer atIndex: index + 1 andSetAsDrawingLayer: YES];
385
386    [[self undoManager] setActionName: @"Duplicate Layer"];
387
388    return;
389
390ERROR:
391    return;
392}
393
394- (void) removeAllLayers
395{
396    [self removeAllCachedLayersImages];
397
398    [_layers makeObjectsPerformSelector: @selector(setDelegate:) withObject: nil];
399    [_layers removeAllObjects];
400
401    _numLayers = 0;
402    _indexOfDrawingLayer = -1;
403
404    [self setupDrawingLayerMembers];
405}
406
407- (void) removeNontargetLayers
408{
409    NSMutableArray *targetLayers;
410    int i;
411    NSBitmapImageRep *selectionMask = nil;
412
413    targetLayers = [NSMutableArray array];
414
415    if (!targetLayers)
416        goto ERROR;
417
418    [self setupTargetLayerIndexesForOperationTarget: _layerOperationTarget];
419
420    // don't allow all layers to be removed (must be at least one target layer remaining)
421    if (!_numTargetLayerIndexes)
422        goto ERROR;
423
424    for (i=0; i<_numTargetLayerIndexes; i++)
425    {
426        [targetLayers addObject: [_layers objectAtIndex: _targetLayerIndexes[i]]];
427    }
428
429    if (_hasSelection)
430    {
431        selectionMask = [[_selectionMask copy] autorelease];
432    }
433
434    [self setLayers: targetLayers];
435
436    if (selectionMask)
437    {
438        [self setSelectionMask: selectionMask];
439    }
440
441    [[self undoManager] setActionName: @"Remove Nontarget Layers"];
442
443    return;
444
445ERROR:
446    return;
447}
448
449- (bool) setLayers: (NSArray *) newLayers
450{
451    NSData *archivedOldLayers;
452    unsigned oldIndexOfDrawingLayer, newIndexOfDrawingLayer;
453    NSUndoManager *undoManager;
454
455    if (!newLayers || ![newLayers count])
456    {
457        goto ERROR;
458    }
459
460    // use copies of the new layers, not the originals
461    newLayers = [[[NSArray alloc] initWithArray: newLayers copyItems: YES] autorelease];
462
463    if (!newLayers)
464        goto ERROR;
465
466    archivedOldLayers = [NSKeyedArchiver archivedDataWithRootObject: _layers];
467    oldIndexOfDrawingLayer = _indexOfDrawingLayer;
468
469    if (_hasSelection)
470    {
471        [self deselectAll]; // stores old selection in undo stack
472    }
473
474    [self removeAllLayers];
475
476    [_layers setArray: newLayers];
477
478    [_layers makeObjectsPerformSelector: @selector(setDelegate:) withObject: self];
479
480    _numLayers = [_layers count];
481
482    if (![self resizeCanvasForCurrentLayers])
483    {
484        goto ERROR;
485    }
486
487    [self setupAllLayersForCurrentBlendingMode];
488
489    newIndexOfDrawingLayer = oldIndexOfDrawingLayer;
490
491    if (![self hasLayerAtIndex: newIndexOfDrawingLayer])
492    {
493        newIndexOfDrawingLayer = 0;
494    }
495
496    [self setupDrawingLayerWithLayerAtIndex: newIndexOfDrawingLayer andPostNotification: NO];
497
498    [self handleUpdateToLayerAtIndex: _indexOfDrawingLayer inRect: _canvasFrame];
499
500    undoManager = [self undoManager];
501
502    [[undoManager prepareWithInvocationTarget: self]
503                                    setupDrawingLayerWithLayerAtIndex: oldIndexOfDrawingLayer];
504
505    [[undoManager prepareWithInvocationTarget: self]
506                                    setLayersWithArchivedLayersData: archivedOldLayers];
507
508    [self postNotification_ReloadedDocument];
509
510    return YES;
511
512ERROR:
513    return NO;
514}
515
516- (void) selectDrawingLayerAtIndex: (int) newDrawingLayerIndex
517{
518    int oldIndexOfDrawingLayer;
519    NSUndoManager *undoManager;
520
521    if (![self hasLayerAtIndex: newDrawingLayerIndex]
522        || (newDrawingLayerIndex == _indexOfDrawingLayer))
523    {
524        return;
525    }
526
527    oldIndexOfDrawingLayer = _indexOfDrawingLayer;
528
529    [self setupDrawingLayerWithLayerAtIndex: newDrawingLayerIndex];
530
531    undoManager = [self undoManager];
532    [[undoManager prepareWithInvocationTarget: self]
533                                            selectDrawingLayerAtIndex: oldIndexOfDrawingLayer];
534
535    if (![undoManager isUndoing] && ![undoManager isRedoing])
536    {
537        [undoManager setActionName: @"Switch Drawing Layer"];
538    }
539}
540
541- (int) indexOfDrawingLayer
542{
543    return _indexOfDrawingLayer;
544}
545
546- (PPDocumentLayer *) drawingLayer
547{
548    return _drawingLayer;
549}
550
551- (void) beginMultilayerOperation
552{
553    _disallowUpdatesToMergedBitmap = YES;
554
555    [[[self undoManager] prepareWithInvocationTarget: self] finishMultilayerOperation];
556}
557
558- (void) finishMultilayerOperation
559{
560    _disallowUpdatesToMergedBitmap = NO;
561
562    [self removeAllCachedLayersImages];
563    [self handleUpdateToLayerAtIndex: _indexOfDrawingLayer inRect: _canvasFrame];
564
565    [[[self undoManager] prepareWithInvocationTarget: self] beginMultilayerOperation];
566
567    [self postNotification_PerformedMultilayerOperation];
568}
569
570- (void) moveDrawingLayerUp
571{
572    if ((_indexOfDrawingLayer >= (_numLayers - 1)) || (_indexOfDrawingLayer < 0))
573    {
574        return;
575    }
576
577    [self moveLayerAtIndex: _indexOfDrawingLayer toIndex: _indexOfDrawingLayer+1];
578
579    [[self undoManager] setActionName: @"Move Layer Up"];
580}
581
582- (void) moveDrawingLayerDown
583{
584    if (_indexOfDrawingLayer < 1)
585    {
586        return;
587    }
588
589    [self moveLayerAtIndex: _indexOfDrawingLayer toIndex: _indexOfDrawingLayer-1];
590
591    [[self undoManager] setActionName: @"Move Layer Down"];
592}
593
594- (void) mergeDrawingLayerUp
595{
596    [self mergeDrawingLayerWithNextLayerInDirection: kPPDirectionType_Up];
597}
598
599- (void) mergeDrawingLayerDown
600{
601    [self mergeDrawingLayerWithNextLayerInDirection: kPPDirectionType_Down];
602}
603
604- (void) mergeAllLayers
605{
606    PPDocumentLayer *mergedLayer;
607    NSBitmapImageRep *selectionMask = nil;
608
609    mergedLayer = [[_drawingLayer copy] autorelease];
610
611    if (!mergedLayer)
612        goto ERROR;
613
614    [[mergedLayer bitmap] ppCopyFromBitmap: _mergedVisibleLayersBitmap
615                            toPoint: NSZeroPoint];
616
617    [mergedLayer handleUpdateToBitmapInRect: _canvasFrame];
618
619    [mergedLayer setOpacity: 1.0f];
620    [mergedLayer setEnabled: YES];
621
622    if (_hasSelection)
623    {
624        selectionMask = [[_selectionMask copy] autorelease];
625    }
626
627    [self setLayers: [NSArray arrayWithObject: mergedLayer]];
628
629    if (selectionMask)
630    {
631        [self setSelectionMask: selectionMask];
632    }
633
634    [[self undoManager] setActionName: @"Merge All Layers"];
635
636    return;
637
638ERROR:
639    return;
640}
641
642- (void) setEnabledFlagForAllLayers: (bool) isEnabled
643{
644    int i;
645
646    isEnabled = (isEnabled) ? YES : NO;
647
648    [self beginMultilayerOperation];
649
650    for (i=0; i<_numLayers; i++)
651    {
652        [(PPDocumentLayer *) [_layers objectAtIndex: i] setEnabled: isEnabled];
653    }
654
655    [self finishMultilayerOperation];
656
657    [[self undoManager]
658                setActionName: (isEnabled) ? @"Enable All Layers" : @"Disable All Layers"];
659}
660
661- (PPLayerBlendingMode) layerBlendingMode
662{
663    return _layerBlendingMode;
664}
665
666- (void) setLayerBlendingMode: (PPLayerBlendingMode) layerBlendingMode
667{
668    PPLayerBlendingMode oldLayerBlendingMode;
669    NSUndoManager *undoManager;
670
671    if (!PPLayerBlendingMode_IsValid(layerBlendingMode)
672        || (layerBlendingMode == _layerBlendingMode))
673    {
674        return;
675    }
676
677    [self removeAllCachedLayersImages];
678
679    oldLayerBlendingMode = _layerBlendingMode;
680
681    _layerBlendingMode = layerBlendingMode;
682
683    if (![self setupAllLayersForCurrentBlendingMode]
684        || ![self setupLayerBlendingBitmapOfSize: _canvasFrame.size])
685    {
686        // if setup fails (can only fail in Linear mode), recover by forcing to Standard mode
687
688        _layerBlendingMode = kPPLayerBlendingMode_Standard;
689
690        [self setupAllLayersForCurrentBlendingMode];
691        [self setupLayerBlendingBitmapOfSize: _canvasFrame.size];
692    }
693
694    [self updateMergedVisibleLayersBitmapInRect: _canvasFrame
695            indexOfUpdatedLayer: _indexOfDrawingLayer];
696
697    undoManager = [self undoManager];
698    [[undoManager prepareWithInvocationTarget: self] setLayerBlendingMode: oldLayerBlendingMode];
699
700    if (![undoManager isUndoing] && ![undoManager isRedoing])
701    {
702        [undoManager setActionName: @"Switch Layer Blending Mode"];
703    }
704
705    [self postNotification_SwitchedLayerBlendingMode];
706
707    [self postNotification_UpdatedMergedVisibleAreaInRect: _canvasFrame];
708
709    if (!_disallowThumbnailImageUpdateNotifications)
710    {
711        [self postNotification_UpdatedMergedVisibleThumbnailImage];
712    }
713}
714
715- (void) toggleLayerBlendingMode
716{
717    PPLayerBlendingMode newLayerBlendingMode = _layerBlendingMode + 1;
718
719    if (!PPLayerBlendingMode_IsValid(newLayerBlendingMode))
720    {
721        newLayerBlendingMode = 0;
722    }
723
724    [self setLayerBlendingMode: newLayerBlendingMode];
725}
726
727- (bool) setupLayerBlendingBitmapOfSize: (NSSize) bitmapSize
728{
729    if (PPGeometry_IsZeroSize(bitmapSize))
730    {
731        goto ERROR;
732    }
733
734    if (_layerBlendingMode == kPPLayerBlendingMode_Linear)
735    {
736        if (!_mergedVisibleLayersLinearBitmap
737            || !NSEqualSizes([_mergedVisibleLayersLinearBitmap ppSizeInPixels], bitmapSize))
738        {
739            NSBitmapImageRep *mergedVisibleLayersLinearBitmap =
740                                    [NSBitmapImageRep ppLinearRGB16BitmapOfSize: bitmapSize];
741
742            if (!mergedVisibleLayersLinearBitmap)
743                goto ERROR;
744
745            [_mergedVisibleLayersLinearBitmap release];
746            _mergedVisibleLayersLinearBitmap = [mergedVisibleLayersLinearBitmap retain];
747        }
748        else
749        {
750            [_mergedVisibleLayersLinearBitmap ppClearBitmap];
751        }
752    }
753    else    // kPPLayerBlendingMode_Standard: no linear bitmap needed
754    {
755        if (_mergedVisibleLayersLinearBitmap)
756        {
757            [_mergedVisibleLayersLinearBitmap release];
758            _mergedVisibleLayersLinearBitmap = nil;
759        }
760    }
761
762    return YES;
763
764ERROR:
765    return NO;
766}
767
768- (void) copyImageBitmap: (NSBitmapImageRep *) bitmap
769            toLayerAtIndex: (int) index
770            atPoint: (NSPoint) origin
771{
772    PPDocumentLayer *layer;
773    NSSize bitmapSize;
774    NSRect updateRect;
775    NSBitmapImageRep *layerBitmap;
776    NSData *undoBitmapTIFFData;
777
778    if (index == _indexOfDrawingLayer)
779    {
780        [self copyImageBitmapToDrawingLayer: bitmap atPoint: origin];
781        return;
782    }
783
784    if (![bitmap ppIsImageBitmap])
785    {
786        goto ERROR;
787    }
788
789    layer = [self layerAtIndex: index];
790
791    if (!layer)
792        goto ERROR;
793
794    origin = PPGeometry_PointClippedToIntegerValues(origin);
795    bitmapSize = [bitmap ppSizeInPixels];
796
797    updateRect.origin = origin;
798    updateRect.size = bitmapSize;
799
800    updateRect = NSIntersectionRect(updateRect, _canvasFrame);
801
802    if (NSIsEmptyRect(updateRect))
803    {
804        goto ERROR;
805    }
806
807    if (!NSEqualSizes(updateRect.size, bitmapSize))
808    {
809        NSRect croppingBounds;
810
811        croppingBounds.origin = NSMakePoint(updateRect.origin.x - origin.x,
812                                            updateRect.origin.y - origin.y);
813
814        croppingBounds.size = updateRect.size;
815
816        bitmap = [bitmap ppShallowDuplicateFromBounds: croppingBounds];
817
818        if (!bitmap)
819            goto ERROR;
820    }
821
822    layerBitmap = [layer bitmap];
823
824    undoBitmapTIFFData = [layerBitmap ppCompressedTIFFDataFromBounds: updateRect];
825
826    if (!undoBitmapTIFFData)
827        goto ERROR;
828
829    [layerBitmap ppCopyFromBitmap: bitmap toPoint: updateRect.origin];
830    [layer handleUpdateToBitmapInRect: updateRect];
831
832    [self handleUpdateToLayerAtIndex: index inRect: updateRect];
833
834    [[[self undoManager] prepareWithInvocationTarget: self] copyTIFFData: undoBitmapTIFFData
835                                                                toLayerAtIndex: index
836                                                                atPoint: updateRect.origin];
837
838    return;
839
840ERROR:
841    return;
842}
843
844- (void) handleUpdateToLayerAtIndex: (int) index inRect: (NSRect) updateRect
845{
846    if (![self hasLayerAtIndex: index] || _disallowUpdatesToMergedBitmap)
847    {
848        return;
849    }
850
851    updateRect = NSIntersectionRect(updateRect, _canvasFrame);
852
853    if (NSIsEmptyRect(updateRect))
854    {
855        return;
856    }
857
858    [self invalidateAllRelativeCachedLayerImagesForIndex: index];
859
860    [self updateMergedVisibleLayersBitmapInRect: updateRect
861            indexOfUpdatedLayer: index];
862
863    if (index == _indexOfDrawingLayer)
864    {
865        [self handleUpdateToDrawingLayerInRect: updateRect];
866    }
867
868    [self postNotification_UpdatedMergedVisibleAreaInRect: updateRect];
869
870    if (!_disallowThumbnailImageUpdateNotifications)
871    {
872        [self postNotification_UpdatedMergedVisibleThumbnailImage];
873    }
874}
875
876#pragma mark PPDocumentLayer delegate methods
877
878- (void) layer: (PPDocumentLayer *) layer
879            changedNameFromOldValue: (NSString *) oldName
880{
881    int layerIndex;
882    NSUndoManager *undoManager;
883
884    layerIndex = [self indexOfLayer: layer];
885
886    if (layerIndex < 0)
887    {
888        return;
889    }
890
891    undoManager = [self undoManager];
892    [[undoManager prepareWithInvocationTarget: self] setName: oldName
893                                                        forLayerAtIndex: layerIndex];
894
895    if (![undoManager isUndoing] && ![undoManager isRedoing])
896    {
897        [undoManager setActionName: @"Rename Layer"];
898    }
899
900    [self postNotification_ChangedAttributeOfLayerAtIndex: layerIndex];
901}
902
903- (void) layer: (PPDocumentLayer *) layer
904            changedEnabledFlagFromOldValue: (bool) oldEnabledFlag
905{
906    int layerIndex;
907    NSUndoManager *undoManager;
908
909    if (![self handleUpdateToLayer: layer])
910    {
911        return;
912    }
913
914    layerIndex = [self indexOfLayer: layer];
915
916    undoManager = [self undoManager];
917    [[undoManager prepareWithInvocationTarget: self] setEnabledFlag: oldEnabledFlag
918                                                        forLayerAtIndex: layerIndex];
919
920    if (![undoManager isUndoing] && ![undoManager isRedoing])
921    {
922        [undoManager setActionName: [layer isEnabled] ? @"Enable Layer" : @"Disable Layer"];
923    }
924
925    [self postNotification_ChangedAttributeOfLayerAtIndex: layerIndex];
926}
927
928- (void) layer: (PPDocumentLayer *) layer
929            changedOpacityFromOldValue: (float) oldOpacity
930            shouldRegisterUndo: (bool) shouldRegisterUndo
931{
932    int layerIndex;
933
934    if (![self handleUpdateToLayer: layer])
935    {
936        return;
937    }
938
939    layerIndex = [self indexOfLayer: layer];
940
941    if (shouldRegisterUndo)
942    {
943        NSUndoManager *undoManager = [self undoManager];
944
945        [[undoManager prepareWithInvocationTarget: self] setOpacity: oldOpacity
946                                                            forLayerAtIndex: layerIndex];
947
948        if (![undoManager isUndoing] && ![undoManager isRedoing])
949        {
950            NSString *actionName;
951
952            actionName = ([layer opacity] > oldOpacity) ? @"Increase" : @"Decrease";
953            actionName = [actionName stringByAppendingString: @" Layer Opacity"];
954
955            if (!actionName)
956            {
957                actionName = @"Change Layer Opacity";
958            }
959
960            [[self undoManager] setActionName: actionName];
961        }
962    }
963
964    [self postNotification_ChangedAttributeOfLayerAtIndex: layerIndex];
965}
966
967#pragma mark Private methods
968
969- (bool) hasLayerAtIndex: (int) index
970{
971    return ((index >= 0) && (index < _numLayers)) ? YES : NO;
972}
973
974- (bool) isValidLayerInsertionIndex: (int) index
975{
976    return ((index >= 0)
977            && (index <= _numLayers)
978            && (_numLayers < kMaxLayersPerDocument)) ? YES : NO;
979}
980
981- (int) indexOfLayer: (PPDocumentLayer *) layer
982{
983    NSUInteger indexOfLayer;
984
985    indexOfLayer = [_layers indexOfObject: layer];
986
987    if (indexOfLayer == NSNotFound)
988    {
989        return -1;
990    }
991
992    return (int) indexOfLayer;
993}
994
995- (bool) setupLayerForCurrentBlendingMode: (PPDocumentLayer *) layer
996{
997    bool shouldEnableLinearBitmap;
998
999    if (!layer)
1000        goto ERROR;
1001
1002    shouldEnableLinearBitmap = (_layerBlendingMode == kPPLayerBlendingMode_Linear) ? YES : NO;
1003
1004    if (![layer enableLinearBlendingBitmap: shouldEnableLinearBitmap])
1005    {
1006        goto ERROR;
1007    }
1008
1009    return YES;
1010
1011ERROR:
1012    return NO;
1013}
1014
1015- (bool) setupAllLayersForCurrentBlendingMode
1016{
1017    NSEnumerator *layerEnumerator;
1018    PPDocumentLayer *layer;
1019
1020    layerEnumerator = [_layers objectEnumerator];
1021
1022    while (layer = [layerEnumerator nextObject])
1023    {
1024        if (![self setupLayerForCurrentBlendingMode: layer])
1025        {
1026            goto ERROR;
1027        }
1028    }
1029
1030    return YES;
1031
1032ERROR:
1033    return NO;
1034}
1035
1036- (void) invalidateAllRelativeCachedLayerImagesForIndex: (int) index
1037{
1038    if (![self hasLayerAtIndex: index])
1039    {
1040        return;
1041    }
1042
1043    [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects
1044            fromIndex: 0
1045            toIndex: index - 1];
1046
1047    [self invalidateImageObjectsInCache: _cachedUnderlayersImageObjects
1048            fromIndex: index + 1
1049            toIndex: _numLayers - 1];
1050}
1051
1052- (void) invalidateCachedLayerImagesAtIndex: (int) index
1053{
1054    if (![self hasLayerAtIndex: index])
1055    {
1056        return;
1057    }
1058
1059    [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects
1060            fromIndex: index
1061            toIndex: index];
1062
1063    [self invalidateImageObjectsInCache: _cachedUnderlayersImageObjects
1064            fromIndex: index
1065            toIndex: index];
1066}
1067
1068- (void) invalidateImageObjectsInCache: (NSObject **) cachedImageObjectsArray
1069            fromIndex: (int) startIndex
1070            toIndex: (int) endIndex
1071{
1072    int i;
1073
1074    if (!cachedImageObjectsArray)
1075        goto ERROR;
1076
1077    if (startIndex < 0)
1078    {
1079        startIndex = 0;
1080    }
1081
1082    if (endIndex >= _numLayers)
1083    {
1084        endIndex = _numLayers - 1;
1085    }
1086
1087    if (startIndex > endIndex)
1088    {
1089        goto ERROR;
1090    }
1091
1092    for (i=startIndex; i<=endIndex; i++)
1093    {
1094        if (cachedImageObjectsArray[i])
1095        {
1096            [cachedImageObjectsArray[i] release];
1097            cachedImageObjectsArray[i] = nil;
1098        }
1099    }
1100
1101    return;
1102
1103ERROR:
1104    return;
1105}
1106
1107- (void) removeAllCachedLayersImages
1108{
1109    [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects
1110            fromIndex: 0
1111            toIndex: _numLayers - 1];
1112
1113    [self invalidateImageObjectsInCache: _cachedUnderlayersImageObjects
1114            fromIndex: 0
1115            toIndex: _numLayers - 1];
1116}
1117
1118- (NSObject *) cachedOverlayersImageObjectForIndex: (int) index
1119{
1120    if ((index >= (_numLayers - 1)) || ![self hasLayerAtIndex: index])
1121    {
1122        return nil;
1123    }
1124
1125    if (!_cachedOverlayersImageObjects[index])
1126    {
1127        _cachedOverlayersImageObjects[index] =
1128            [[self mergedLayersImageObjectFromIndex: index + 1 toIndex: _numLayers - 1] retain];
1129    }
1130
1131    return _cachedOverlayersImageObjects[index];
1132}
1133
1134- (NSObject *) cachedUnderlayersImageObjectForIndex: (int) index
1135{
1136    if ((index < 1) || ![self hasLayerAtIndex: index])
1137    {
1138        return nil;
1139    }
1140
1141    if (!_cachedUnderlayersImageObjects[index])
1142    {
1143        _cachedUnderlayersImageObjects[index] =
1144            [[self mergedLayersImageObjectFromIndex: 0 toIndex: index - 1] retain];
1145    }
1146
1147    return _cachedUnderlayersImageObjects[index];
1148}
1149
1150- (NSObject *) mergedLayersImageObjectFromIndex: (int) firstIndex
1151                toIndex: (int) lastIndex
1152{
1153    NSBitmapImageRep *mergedLayersBitmap;
1154    NSObject *imageObject = nil;
1155
1156    mergedLayersBitmap = [self mergedLayersBitmapFromIndex: firstIndex toIndex: lastIndex];
1157
1158    if (!mergedLayersBitmap)
1159        goto ERROR;
1160
1161    if (mergedLayersBitmap == gEmptyBitmap)
1162    {
1163        // Empty bitmap: return empty image-object
1164        imageObject = gEmptyImageObject;
1165    }
1166    else if (_layerBlendingMode == kPPLayerBlendingMode_Linear)
1167    {
1168        // Linear blending: image-objects are NSBitmapImageReps (LinearRGB16)
1169        imageObject = mergedLayersBitmap;
1170    }
1171    else
1172    {
1173        // Standard blending: image-objects are NSImages
1174        imageObject = [NSImage ppImageWithBitmap: mergedLayersBitmap];
1175    }
1176
1177    if (!imageObject)
1178        goto ERROR;
1179
1180    return imageObject;
1181
1182ERROR:
1183    return nil;
1184}
1185
1186- (NSBitmapImageRep *) mergedLayersBitmapFromIndex: (int) firstIndex
1187                        toIndex: (int) lastIndex
1188{
1189    NSBitmapImageRep *mergedLayersBitmap = nil;
1190    int index;
1191    PPDocumentLayer *layer;
1192    float layerOpacity;
1193
1194    if (firstIndex < 0)
1195    {
1196        firstIndex = 0;
1197    }
1198
1199    if (lastIndex >= [_layers count])
1200    {
1201        lastIndex = [_layers count] - 1;
1202    }
1203
1204    if (firstIndex > lastIndex)
1205    {
1206        goto ERROR;
1207    }
1208
1209    if (_layerBlendingMode == kPPLayerBlendingMode_Linear)
1210    {
1211        // Linear blending - generate LinearRGB16 bitmap, merge using PikoPixel's LinearRGB16
1212        // methods
1213
1214        for (index=lastIndex; index>=firstIndex; index--)
1215        {
1216            layer = [self layerAtIndex: index];
1217            layerOpacity = [layer opacity];
1218
1219            if ([layer isEnabled] && (layerOpacity > 0.0f))
1220            {
1221                if (!mergedLayersBitmap)
1222                {
1223                     mergedLayersBitmap =
1224                                [NSBitmapImageRep ppLinearRGB16BitmapOfSize: _canvasFrame.size];
1225
1226                    if (!mergedLayersBitmap)
1227                        goto ERROR;
1228
1229                    // merge the first layer using linear-copy (faster than linear-blend)
1230
1231                    [mergedLayersBitmap ppLinearCopyFromLinearBitmap:
1232                                                                [layer linearBlendingBitmap]
1233                                            opacity: layerOpacity
1234                                            inBounds: _canvasFrame];
1235                }
1236                else
1237                {
1238                    [mergedLayersBitmap ppLinearBlendFromLinearBitmapUnderneath:
1239                                                                [layer linearBlendingBitmap]
1240                                            sourceOpacity: layerOpacity
1241                                            inBounds: _canvasFrame];
1242                }
1243            }
1244        }
1245    }
1246    else
1247    {
1248        // Standard blending - generate standard Image bitmap (sRGB), merge using native Cocoa
1249        // methods
1250
1251        NSCompositingOperation compositingOperation;
1252
1253        for (index=firstIndex; index<=lastIndex; index++)
1254        {
1255            layer = [self layerAtIndex: index];
1256            layerOpacity = [layer opacity];
1257
1258            if ([layer isEnabled] && (layerOpacity > 0.0f))
1259            {
1260                if (!mergedLayersBitmap)
1261                {
1262                    mergedLayersBitmap =
1263                                    [NSBitmapImageRep ppImageBitmapOfSize: _canvasFrame.size];
1264
1265                    if (!mergedLayersBitmap)
1266                        goto ERROR;
1267
1268                    [mergedLayersBitmap ppSetAsCurrentGraphicsContext];
1269
1270                    // merge the first layer using NSCompositeCopy (faster than
1271                    // NSCompositeSourceOver)
1272
1273                    compositingOperation = NSCompositeCopy;
1274                }
1275                else
1276                {
1277                    compositingOperation = NSCompositeSourceOver;
1278                }
1279
1280                [[layer image] drawInRect: _canvasFrame
1281                                fromRect: _canvasFrame
1282                                operation: compositingOperation
1283                                fraction: layerOpacity];
1284            }
1285        }
1286
1287        if (mergedLayersBitmap)
1288        {
1289            [mergedLayersBitmap ppRestoreGraphicsContext];
1290        }
1291    }
1292
1293    if (!mergedLayersBitmap)
1294    {
1295        // No layers were merged - return empty bitmap (different from returning nil, which
1296        // signifies an error)
1297        return gEmptyBitmap;
1298    }
1299
1300    return mergedLayersBitmap;
1301
1302ERROR:
1303    return nil;
1304}
1305
1306- (void) updateMergedVisibleLayersBitmapInRect: (NSRect) rect
1307            indexOfUpdatedLayer: (int) indexOfUpdatedLayer
1308{
1309    NSObject *imageObject, *imageObjectsToMerge[3];
1310    int numImageObjectsToMerge = 0, imageIndexOfUpdatedLayer = -1, imageIndex;
1311    PPDocumentLayer *updatedLayer;
1312    float opacityOfUpdatedLayer, mergingOpacity;
1313    bool performedInitialMerge = NO;
1314
1315    if (NSIsEmptyRect(rect)
1316        || ![self hasLayerAtIndex: indexOfUpdatedLayer])
1317    {
1318        return;
1319    }
1320
1321    // Collect image-objects for merge:
1322
1323    // 1) Underlayers image (merged layers below updated layer)
1324
1325    imageObject = [self cachedUnderlayersImageObjectForIndex: indexOfUpdatedLayer];
1326
1327    if (imageObject && (imageObject != gEmptyImageObject))
1328    {
1329        imageObjectsToMerge[numImageObjectsToMerge++] = imageObject;
1330    }
1331
1332    // 2) Updated-layer image
1333
1334    updatedLayer = [_layers objectAtIndex: indexOfUpdatedLayer];
1335    opacityOfUpdatedLayer = [updatedLayer opacity];
1336
1337    if ([updatedLayer isEnabled] && (opacityOfUpdatedLayer > 0.0f))
1338    {
1339        // Linear blending: image-objects are NSBitmapImageReps (LinearRGB16)
1340        // Standard blending: image-objects are NSImages
1341
1342        imageObject =
1343            (_layerBlendingMode == kPPLayerBlendingMode_Linear) ?
1344                (NSObject *) [updatedLayer linearBlendingBitmap] :
1345                (NSObject *) [updatedLayer image];
1346
1347        // Don't need to check that (imageObject != gEmptyImageObject), since gEmptyImageObject
1348        // is local & won't be returned by PPDocumentLayer methods
1349
1350        if (imageObject)
1351        {
1352            imageIndexOfUpdatedLayer = numImageObjectsToMerge;
1353
1354            imageObjectsToMerge[numImageObjectsToMerge++] = imageObject;
1355        }
1356    }
1357
1358    // 3) Overlayers image (merged layers above updated layer)
1359
1360    imageObject = [self cachedOverlayersImageObjectForIndex: indexOfUpdatedLayer];
1361
1362    if (imageObject && (imageObject != gEmptyImageObject))
1363    {
1364        imageObjectsToMerge[numImageObjectsToMerge++] = imageObject;
1365    }
1366
1367    // Merge collected image-objects:
1368
1369    if (_layerBlendingMode == kPPLayerBlendingMode_Linear)
1370    {
1371        // Linear blending - image-objects are NSBitmapImageReps (LinearRGB16); merge using
1372        // PikoPixel's LinearRGB16 bitmap methods
1373
1374        NSBitmapImageRep *mergingBitmap;
1375
1376        for (imageIndex=numImageObjectsToMerge-1; imageIndex>=0; imageIndex--)
1377        {
1378            mergingBitmap = (NSBitmapImageRep *) imageObjectsToMerge[imageIndex];
1379
1380            mergingOpacity =
1381                (imageIndex == imageIndexOfUpdatedLayer) ? opacityOfUpdatedLayer : 1.0f;
1382
1383            if (!performedInitialMerge)
1384            {
1385                // merge the first bitmap using linear-copy (faster than linear-blend)
1386
1387                [_mergedVisibleLayersLinearBitmap ppLinearCopyFromLinearBitmap: mergingBitmap
1388                                                    opacity: mergingOpacity
1389                                                    inBounds: rect];
1390
1391                performedInitialMerge = YES;
1392            }
1393            else
1394            {
1395                [_mergedVisibleLayersLinearBitmap ppLinearBlendFromLinearBitmapUnderneath:
1396                                                                                mergingBitmap
1397                                                    sourceOpacity: mergingOpacity
1398                                                    inBounds: rect];
1399            }
1400        }
1401
1402        if (!performedInitialMerge)
1403        {
1404            // nothing was merged to the updated area, so clear it manually
1405            [_mergedVisibleLayersLinearBitmap ppClearBitmapInBounds: rect];
1406        }
1407
1408        [_mergedVisibleLayersLinearBitmap ppLinearCopyToImageBitmap: _mergedVisibleLayersBitmap
1409                                            inBounds: rect];
1410    }
1411    else
1412    {
1413        // Standard blending - image-objects are NSImages; merge using native Cocoa methods
1414
1415        NSImage *mergingImage;
1416        NSCompositingOperation compositingOperation;
1417
1418        for (imageIndex=0; imageIndex<numImageObjectsToMerge; imageIndex++)
1419        {
1420            mergingImage = (NSImage *) imageObjectsToMerge[imageIndex];
1421
1422            mergingOpacity =
1423                (imageIndex == imageIndexOfUpdatedLayer) ? opacityOfUpdatedLayer : 1.0f;
1424
1425            if (!performedInitialMerge)
1426            {
1427                [_mergedVisibleLayersBitmap ppSetAsCurrentGraphicsContext];
1428
1429                // merge the first image using NSCompositeCopy (faster than
1430                // NSCompositeSourceOver)
1431
1432                compositingOperation = NSCompositeCopy;
1433                performedInitialMerge = YES;
1434            }
1435            else
1436            {
1437                compositingOperation = NSCompositeSourceOver;
1438            }
1439
1440            [mergingImage drawInRect: rect
1441                            fromRect: rect
1442                            operation: compositingOperation
1443                            fraction: mergingOpacity];
1444        }
1445
1446        if (performedInitialMerge)
1447        {
1448            [_mergedVisibleLayersBitmap ppRestoreGraphicsContext];
1449        }
1450        else
1451        {
1452            // nothing was merged to the updated area, so clear it manually
1453            [_mergedVisibleLayersBitmap ppClearBitmapInBounds: rect];
1454        }
1455    }
1456
1457    _mergedVisibleBitmapHasEnabledLayer = (numImageObjectsToMerge > 0) ? YES : NO;
1458
1459    [self recacheMergedVisibleLayersThumbnailImageInBounds: rect];
1460}
1461
1462- (NSString *) uniqueLayerNameWithRoot: (NSString *) rootName
1463{
1464    int rootNameLength;
1465    NSMutableSet *prefixMatches;
1466    NSEnumerator *enumerator;
1467    PPDocumentLayer *layer;
1468    NSString *layerName, *testName;
1469    int suffixValue;
1470
1471    if (![rootName length])
1472    {
1473        rootName = @"";
1474    }
1475
1476    rootNameLength = [rootName length];
1477
1478    prefixMatches = [NSMutableSet set];
1479
1480    enumerator = [_layers objectEnumerator];
1481
1482    while (layer = [enumerator nextObject])
1483    {
1484        layerName = [layer name];
1485
1486        if (([layerName length] >= rootNameLength)
1487            && [layerName hasPrefix: rootName])
1488        {
1489            [prefixMatches addObject: layerName];
1490        }
1491    }
1492
1493    if (![prefixMatches count])
1494    {
1495        return rootName;
1496    }
1497
1498    suffixValue = 1;
1499    testName = [NSString stringWithFormat: @"%@ %02d", rootName, suffixValue];
1500
1501    while ([prefixMatches containsObject: testName])
1502    {
1503        suffixValue++;
1504        testName = [NSString stringWithFormat: @"%@ %02d", rootName, suffixValue];
1505    }
1506
1507    return testName;
1508}
1509
1510- (NSString *) duplicateNameForLayerName: (NSString *) layerName
1511{
1512    if (![layerName hasSuffix: @" copy"])
1513    {
1514        layerName = [layerName stringByAppendingString: @" copy"];
1515    }
1516
1517    return [self uniqueLayerNameWithRoot: layerName];
1518}
1519
1520- (void) setupDrawingLayerWithLayerAtIndex: (int) newDrawingLayerIndex
1521            andPostNotification: (bool) shouldPostNotification
1522{
1523    if (![self hasLayerAtIndex: newDrawingLayerIndex])
1524    {
1525        newDrawingLayerIndex = -1;
1526    }
1527
1528    _indexOfDrawingLayer = newDrawingLayerIndex;
1529
1530    [self setupDrawingLayerMembers];
1531
1532    [self handleUpdateToDrawingLayerInRect: _canvasFrame];
1533
1534    if (shouldPostNotification)
1535    {
1536        [self postNotification_SwitchedDrawingLayer];
1537    }
1538}
1539
1540- (void) setupDrawingLayerWithLayerAtIndex: (int) newDrawingLayerIndex
1541{
1542    [self setupDrawingLayerWithLayerAtIndex: newDrawingLayerIndex andPostNotification: YES];
1543}
1544
1545- (void) setupDrawingLayerMembers
1546{
1547    [_drawingLayerImage release];
1548    _drawingLayerImage = nil;
1549
1550    [_drawingLayerBitmap release];
1551    _drawingLayerBitmap = nil;
1552
1553    [_drawingLayer release];
1554    _drawingLayer = nil;
1555
1556    if ([self hasLayerAtIndex: _indexOfDrawingLayer])
1557    {
1558        _drawingLayer = [[_layers objectAtIndex: _indexOfDrawingLayer] retain];
1559        _drawingLayerBitmap = [[_drawingLayer bitmap] retain];
1560        _drawingLayerImage = [[_drawingLayer image] retain];
1561
1562        [_drawingUndoBitmap ppCopyFromBitmap: _drawingLayerBitmap toPoint: NSZeroPoint];
1563    }
1564    else
1565    {
1566        [_drawingUndoBitmap ppClearBitmap];
1567    }
1568}
1569
1570- (void) mergeDrawingLayerWithNextLayerInDirection: (PPDirectionType) directionType
1571{
1572    int indexOfMergingLayer;
1573    NSBitmapImageRep *mergedLayersBitmap;
1574    NSString *actionName;
1575    bool shouldEnableMergedDrawLayer = YES;
1576
1577    if (![self hasLayerAtIndex: _indexOfDrawingLayer])
1578    {
1579        goto ERROR;
1580    }
1581
1582    if (directionType == kPPDirectionType_Up)
1583    {
1584        indexOfMergingLayer = _indexOfDrawingLayer + 1;
1585
1586        if (![self hasLayerAtIndex: indexOfMergingLayer])
1587        {
1588            goto ERROR;
1589        }
1590
1591        mergedLayersBitmap = [self mergedLayersBitmapFromIndex: _indexOfDrawingLayer
1592                                    toIndex: indexOfMergingLayer];
1593
1594        actionName = @"Merge with Layer Above";
1595    }
1596    else if (directionType == kPPDirectionType_Down)
1597    {
1598        indexOfMergingLayer = _indexOfDrawingLayer - 1;
1599
1600        if (![self hasLayerAtIndex: indexOfMergingLayer])
1601        {
1602            goto ERROR;
1603        }
1604
1605        mergedLayersBitmap = [self mergedLayersBitmapFromIndex: indexOfMergingLayer
1606                                    toIndex: _indexOfDrawingLayer];
1607
1608        actionName = @"Merge with Layer Below";
1609    }
1610    else
1611    {
1612        // only allow up or down directions
1613        goto ERROR;
1614    }
1615
1616    if (mergedLayersBitmap == gEmptyBitmap)
1617    {
1618        mergedLayersBitmap = [NSBitmapImageRep ppImageBitmapOfSize: _canvasFrame.size];
1619        shouldEnableMergedDrawLayer = NO;
1620    }
1621    else if ([mergedLayersBitmap ppIsLinearRGB16Bitmap])
1622    {
1623        mergedLayersBitmap = [mergedLayersBitmap ppImageBitmapFromLinearRGB16Bitmap];
1624    }
1625
1626    if (!mergedLayersBitmap)
1627        goto ERROR;
1628
1629    [self copyImageBitmapToDrawingLayer: mergedLayersBitmap atPoint: NSZeroPoint];
1630
1631    [_drawingLayer setOpacity: 1.0f];
1632    [_drawingLayer setEnabled: shouldEnableMergedDrawLayer];
1633
1634    [self removeLayerAtIndex: indexOfMergingLayer];
1635
1636    [[self undoManager] setActionName: actionName];
1637
1638    return;
1639
1640ERROR:
1641    return;
1642}
1643
1644- (bool) handleUpdateToLayer: (PPDocumentLayer *) layer
1645{
1646    int indexOfChangedLayer;
1647
1648    indexOfChangedLayer = [_layers indexOfObject: layer];
1649
1650    if (![self hasLayerAtIndex: indexOfChangedLayer])
1651    {
1652        return NO;
1653    }
1654
1655    [self handleUpdateToLayerAtIndex: indexOfChangedLayer inRect: _canvasFrame];
1656
1657    return YES;
1658}
1659
1660- (void) handleUpdateToDrawingLayerInRect: (NSRect) updateRect
1661{
1662    [self updateDissolvedDrawingLayerBitmapInRect: updateRect];
1663
1664    [self postNotification_UpdatedDrawingLayerAreaInRect: updateRect];
1665
1666    if (!_disallowThumbnailImageUpdateNotifications)
1667    {
1668        [self postNotification_UpdatedDrawingLayerThumbnailImage];
1669    }
1670}
1671
1672- (void) updateDissolvedDrawingLayerBitmapInRect: (NSRect) updateRect
1673{
1674    float drawingLayerOpacity = [_drawingLayer opacity];
1675
1676    if ([_drawingLayer isEnabled] && (drawingLayerOpacity > 0))
1677    {
1678        [_dissolvedDrawingLayerBitmap ppSetAsCurrentGraphicsContext];
1679
1680        [_drawingLayerImage drawInRect: updateRect
1681                            fromRect: updateRect
1682                            operation: NSCompositeCopy
1683                            fraction: drawingLayerOpacity];
1684
1685        [_dissolvedDrawingLayerBitmap ppRestoreGraphicsContext];
1686    }
1687    else
1688    {
1689        [_dissolvedDrawingLayerBitmap ppClearBitmapInBounds: updateRect];
1690    }
1691
1692    [self recacheDissolvedDrawingLayerThumbnailImageInBounds: updateRect];
1693}
1694
1695- (void) insertArchivedLayer: (NSData *) archivedLayer
1696            atIndex: (int) index
1697            andSetAsDrawingLayer: (bool) shouldSetAsDrawingLayer
1698{
1699    PPDocumentLayer *layer;
1700
1701    if (!archivedLayer)
1702        goto ERROR;
1703
1704    layer = [NSKeyedUnarchiver unarchiveObjectWithData: archivedLayer];
1705
1706    if (!layer || ![layer isKindOfClass: [PPDocumentLayer class]])
1707    {
1708        goto ERROR;
1709    }
1710
1711    [self insertLayer: layer atIndex: index andSetAsDrawingLayer: shouldSetAsDrawingLayer];
1712
1713    return;
1714
1715ERROR:
1716    return;
1717}
1718
1719- (bool) setLayersWithArchivedLayersData: (NSData *) archivedLayersData
1720{
1721    NSArray *layers;
1722
1723    if (!archivedLayersData)
1724        goto ERROR;
1725
1726    layers = [NSKeyedUnarchiver unarchiveObjectWithData: archivedLayersData];
1727
1728    if (!layers || ![layers isKindOfClass: [NSArray class]])
1729    {
1730        goto ERROR;
1731    }
1732
1733    return [self setLayers: layers];
1734
1735ERROR:
1736    return NO;
1737}
1738
1739- (void) setName: (NSString *) name forLayerAtIndex: (int) index
1740{
1741    [[self layerAtIndex: index] setName: name];
1742}
1743
1744- (void) setEnabledFlag: (bool) isEnabled forLayerAtIndex: (int) index
1745{
1746    [[self layerAtIndex: index] setEnabled: isEnabled];
1747}
1748
1749- (void) setOpacity: (float) opacity forLayerAtIndex: (int) index
1750{
1751    [[self layerAtIndex: index] setOpacity: opacity];
1752}
1753
1754- (void) copyTIFFData: (NSData *) tiffData
1755            toLayerAtIndex: (int) index
1756            atPoint: (NSPoint) origin
1757{
1758    [self copyImageBitmap: [NSBitmapImageRep imageRepWithData: tiffData]
1759            toLayerAtIndex: index
1760            atPoint: origin];
1761}
1762
1763// recacheMergedVisibleLayersThumbnailImageInBounds:
1764// & recacheDissolvedDrawingLayerThumbnailImageInBounds: methods are patch targets on GNUstep
1765// (PPGNUstepGlue_ImageRecacheSpeedups)
1766
1767- (void) recacheMergedVisibleLayersThumbnailImageInBounds: (NSRect) bounds
1768{
1769    [_mergedVisibleLayersThumbnailImage recache];
1770}
1771
1772- (void) recacheDissolvedDrawingLayerThumbnailImageInBounds: (NSRect) bounds
1773{
1774    [_dissolvedDrawingLayerThumbnailImage recache];
1775}
1776
1777@end
1778