File indexing completed on 2024-05-19 04:26:19

0001 /*
0002  *  SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org>
0003  *  SPDX-FileCopyrightText: 2005 C. Boemann <cbo@boemann.dk>
0004  *  SPDX-FileCopyrightText: 2009 Dmitry Kazakov <dimula73@gmail.com>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include "kis_layer.h"
0010 
0011 
0012 #include <klocalizedstring.h>
0013 #include <QImage>
0014 #include <QBitArray>
0015 #include <QStack>
0016 #include <QMutex>
0017 #include <QMutexLocker>
0018 #include <QReadWriteLock>
0019 #include <QReadLocker>
0020 #include <QWriteLocker>
0021 
0022 #include <KoIcon.h>
0023 #include <kis_icon.h>
0024 #include <KoProperties.h>
0025 #include <KoCompositeOpRegistry.h>
0026 #include <KoColorSpace.h>
0027 
0028 #include "kis_debug.h"
0029 #include "kis_image.h"
0030 
0031 #include "kis_painter.h"
0032 #include "kis_mask.h"
0033 #include "kis_effect_mask.h"
0034 #include "kis_selection_mask.h"
0035 #include "kis_meta_data_store.h"
0036 #include "kis_selection.h"
0037 #include "kis_paint_layer.h"
0038 #include "kis_raster_keyframe_channel.h"
0039 
0040 #include "kis_clone_layer.h"
0041 
0042 #include "kis_psd_layer_style.h"
0043 #include "kis_layer_projection_plane.h"
0044 #include "layerstyles/kis_layer_style_projection_plane.h"
0045 
0046 #include "krita_utils.h"
0047 #include "kis_layer_properties_icons.h"
0048 #include "kis_layer_utils.h"
0049 #include "kis_projection_leaf.h"
0050 #include "KisSafeNodeProjectionStore.h"
0051 
0052 
0053 class KisCloneLayersList {
0054 public:
0055     void addClone(KisCloneLayerWSP cloneLayer) {
0056         m_clonesList.append(cloneLayer);
0057     }
0058 
0059     void removeClone(KisCloneLayerWSP cloneLayer) {
0060         m_clonesList.removeOne(cloneLayer);
0061     }
0062 
0063     void setDirty(const QRect &rect) {
0064         Q_FOREACH (KisCloneLayerSP clone, m_clonesList) {
0065             if (clone) {
0066                 clone->setDirtyOriginal(rect);
0067             }
0068         }
0069     }
0070 
0071     const QList<KisCloneLayerWSP> registeredClones() const {
0072         return m_clonesList;
0073     }
0074 
0075     bool hasClones() const {
0076         return !m_clonesList.isEmpty();
0077     }
0078 
0079 private:
0080     QList<KisCloneLayerWSP> m_clonesList;
0081 };
0082 
0083 class KisLayerMasksCache {
0084 public:
0085     KisLayerMasksCache(KisLayer *parent)
0086         : m_parent(parent)
0087     {
0088     }
0089 
0090     KisSelectionMaskSP selectionMask() {
0091         QReadLocker readLock(&m_lock);
0092 
0093         if (!m_isSelectionMaskValid) {
0094             readLock.unlock();
0095 
0096             QWriteLocker writeLock(&m_lock);
0097             if (!m_isSelectionMaskValid) {
0098                 KoProperties properties;
0099                 properties.setProperty("active", true);
0100                 properties.setProperty("visible", true);
0101                 QList<KisNodeSP> masks = m_parent->childNodes(QStringList("KisSelectionMask"), properties);
0102 
0103                 // return the first visible mask
0104                 Q_FOREACH (KisNodeSP mask, masks) {
0105                     if (mask) {
0106                         m_selectionMask = dynamic_cast<KisSelectionMask*>(mask.data());
0107                         break;
0108                     }
0109                 }
0110                 m_isSelectionMaskValid = true;
0111             }
0112 
0113             // return under write lock
0114             return m_selectionMask;
0115         }
0116 
0117         // return under read lock
0118         return m_selectionMask;
0119     }
0120 
0121     QList<KisEffectMaskSP> effectMasks() {
0122         QReadLocker readLock(&m_lock);
0123 
0124         if (!m_isEffectMasksValid) {
0125             readLock.unlock();
0126 
0127             QWriteLocker writeLock(&m_lock);
0128             if (!m_isEffectMasksValid) {
0129                 m_effectMasks = m_parent->searchEffectMasks(0);
0130                 m_isEffectMasksValid = true;
0131             }
0132 
0133             // return under write lock
0134             return m_effectMasks;
0135         }
0136 
0137         // return under read lock
0138         return m_effectMasks;
0139     }
0140 
0141     void setDirty()
0142     {
0143         QWriteLocker l(&m_lock);
0144         m_isSelectionMaskValid = false;
0145         m_isEffectMasksValid = false;
0146         m_selectionMask = 0;
0147         m_effectMasks.clear();
0148     }
0149 
0150 private:
0151     KisLayer *m_parent;
0152 
0153     QReadWriteLock m_lock;
0154 
0155     bool m_isSelectionMaskValid = false;
0156     bool m_isEffectMasksValid = false;
0157     KisSelectionMaskSP m_selectionMask;
0158     QList<KisEffectMaskSP> m_effectMasks;
0159 };
0160 
0161 struct Q_DECL_HIDDEN KisLayer::Private
0162 {
0163     Private(KisLayer *q)
0164         : masksCache(q)
0165     {
0166     }
0167 
0168     QBitArray channelFlags;
0169     KisMetaData::Store* metaDataStore {nullptr};
0170     KisCloneLayersList clonesList;
0171 
0172     KisPSDLayerStyleSP layerStyle;
0173     KisLayerStyleProjectionPlaneSP layerStyleProjectionPlane;
0174 
0175     KisLayerProjectionPlaneSP projectionPlane;
0176     KisSafeNodeProjectionStoreSP safeProjection;
0177 
0178     KisLayerMasksCache masksCache;
0179 };
0180 
0181 
0182 KisLayer::KisLayer(KisImageWSP image, const QString &name, quint8 opacity)
0183         : KisNode(image)
0184         , m_d(new Private(this))
0185 {
0186     setName(name);
0187     setOpacity(opacity);
0188     m_d->metaDataStore = new KisMetaData::Store();
0189     m_d->projectionPlane = toQShared(new KisLayerProjectionPlane(this));
0190     m_d->safeProjection = new KisSafeNodeProjectionStore();
0191     m_d->safeProjection->setImage(image);
0192 }
0193 
0194 KisLayer::KisLayer(const KisLayer& rhs)
0195         : KisNode(rhs)
0196         , m_d(new Private(this))
0197 {
0198     if (this != &rhs) {
0199         m_d->metaDataStore = new KisMetaData::Store(*rhs.m_d->metaDataStore);
0200         m_d->channelFlags = rhs.m_d->channelFlags;
0201 
0202         setName(rhs.name());
0203         m_d->projectionPlane = toQShared(new KisLayerProjectionPlane(this));
0204         m_d->safeProjection = new KisSafeNodeProjectionStore(*rhs.m_d->safeProjection);
0205         m_d->safeProjection->setImage(image());
0206 
0207         if (rhs.m_d->layerStyle) {
0208             m_d->layerStyle = rhs.m_d->layerStyle->clone().dynamicCast<KisPSDLayerStyle>();
0209 
0210             if (rhs.m_d->layerStyleProjectionPlane) {
0211                 m_d->layerStyleProjectionPlane = toQShared(
0212                     new KisLayerStyleProjectionPlane(*rhs.m_d->layerStyleProjectionPlane,
0213                                                      this,
0214                                                      m_d->layerStyle));
0215             }
0216         }
0217     }
0218 }
0219 
0220 KisLayer::~KisLayer()
0221 {
0222     delete m_d->metaDataStore;
0223     delete m_d;
0224 }
0225 
0226 const KoColorSpace * KisLayer::colorSpace() const
0227 {
0228     KisPaintDeviceSP dev = original();
0229     KIS_ASSERT_RECOVER_RETURN_VALUE(dev, KoColorSpaceRegistry::instance()->rgb8());
0230     return dev->colorSpace();
0231 }
0232 
0233 const KoCompositeOp * KisLayer::compositeOp() const
0234 {
0235     /**
0236      * FIXME: This function duplicates the same function from
0237      * KisMask. We can't move it to KisBaseNode as it doesn't
0238      * know anything about parent() method of KisNode
0239      * Please think it over...
0240      */
0241 
0242     KisNodeSP parentNode = parent();
0243     if (!parentNode) return 0;
0244 
0245     if (!parentNode->colorSpace()) return 0;
0246     const KoCompositeOp* op = parentNode->colorSpace()->compositeOp(compositeOpId());
0247     return op ? op : parentNode->colorSpace()->compositeOp(COMPOSITE_OVER);
0248 }
0249 
0250 KisPSDLayerStyleSP KisLayer::layerStyle() const
0251 {
0252     return m_d->layerStyle;
0253 }
0254 
0255 void KisLayer::setLayerStyle(KisPSDLayerStyleSP layerStyle)
0256 {
0257     if (layerStyle) {
0258         KIS_SAFE_ASSERT_RECOVER_NOOP(layerStyle->hasLocalResourcesSnapshot());
0259 
0260         m_d->layerStyle = layerStyle;
0261 
0262         KisLayerStyleProjectionPlaneSP plane = !layerStyle->isEmpty() ?
0263             KisLayerStyleProjectionPlaneSP(new KisLayerStyleProjectionPlane(this)) :
0264             KisLayerStyleProjectionPlaneSP(0);
0265 
0266         m_d->layerStyleProjectionPlane = plane;
0267     } else {
0268         m_d->layerStyleProjectionPlane.clear();
0269         m_d->layerStyle.clear();
0270     }
0271 }
0272 
0273 KisBaseNode::PropertyList KisLayer::sectionModelProperties() const
0274 {
0275     KisBaseNode::PropertyList l = KisBaseNode::sectionModelProperties();
0276     l << KisBaseNode::Property(KoID("opacity", i18n("Opacity")), i18n("%1%", percentOpacity()));
0277 
0278     const KoCompositeOp * compositeOp = this->compositeOp();
0279 
0280     if (compositeOp) {
0281         l << KisBaseNode::Property(KoID("compositeop", i18n("Blending Mode")), compositeOp->description());
0282     }
0283 
0284     if (m_d->layerStyle && !m_d->layerStyle->isEmpty()) {
0285         l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::layerStyle, m_d->layerStyle->isEnabled());
0286     }
0287 
0288     l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::inheritAlpha, alphaChannelDisabled());
0289 
0290     return l;
0291 }
0292 
0293 void KisLayer::setSectionModelProperties(const KisBaseNode::PropertyList &properties)
0294 {
0295     KisBaseNode::setSectionModelProperties(properties);
0296 
0297     Q_FOREACH (const KisBaseNode::Property &property, properties) {
0298         if (property.id == KisLayerPropertiesIcons::inheritAlpha.id()) {
0299             disableAlphaChannel(property.state.toBool());
0300         }
0301 
0302         if (property.id == KisLayerPropertiesIcons::layerStyle.id()) {
0303             if (m_d->layerStyle &&
0304                 m_d->layerStyle->isEnabled() != property.state.toBool()) {
0305 
0306                 m_d->layerStyle->setEnabled(property.state.toBool());
0307 
0308                 baseNodeChangedCallback();
0309                 baseNodeInvalidateAllFramesCallback();
0310             }
0311         }
0312     }
0313 }
0314 
0315 void KisLayer::disableAlphaChannel(bool disable)
0316 {
0317     QBitArray newChannelFlags = m_d->channelFlags;
0318 
0319     if(newChannelFlags.isEmpty())
0320         newChannelFlags = colorSpace()->channelFlags(true, true);
0321 
0322     if(disable)
0323         newChannelFlags &= colorSpace()->channelFlags(true, false);
0324     else
0325         newChannelFlags |= colorSpace()->channelFlags(false, true);
0326 
0327     setChannelFlags(newChannelFlags);
0328 }
0329 
0330 bool KisLayer::alphaChannelDisabled() const
0331 {
0332     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(colorSpace(), false);
0333     QBitArray flags = colorSpace()->channelFlags(false, true) & m_d->channelFlags;
0334     return flags.count(true) == 0 && !m_d->channelFlags.isEmpty();
0335 }
0336 
0337 
0338 void KisLayer::setChannelFlags(const QBitArray & channelFlags)
0339 {
0340     Q_ASSERT(channelFlags.isEmpty() ||((quint32)channelFlags.count() == colorSpace()->channelCount()));
0341 
0342     if (KritaUtils::compareChannelFlags(channelFlags,
0343                                         this->channelFlags())) {
0344         return;
0345     }
0346 
0347     if (!channelFlags.isEmpty() &&
0348         channelFlags == QBitArray(channelFlags.size(), true)) {
0349 
0350         m_d->channelFlags.clear();
0351     } else {
0352         m_d->channelFlags = channelFlags;
0353     }
0354 
0355     baseNodeChangedCallback();
0356     baseNodeInvalidateAllFramesCallback();
0357 }
0358 
0359 QBitArray & KisLayer::channelFlags() const
0360 {
0361     return m_d->channelFlags;
0362 }
0363 
0364 bool KisLayer::temporary() const
0365 {
0366     return nodeProperties().boolProperty("temporary", false);
0367 }
0368 
0369 void KisLayer::setTemporary(bool t)
0370 {
0371     setNodeProperty("temporary", t);
0372 }
0373 
0374 void KisLayer::setImage(KisImageWSP image)
0375 {
0376     // we own the projection device, so we should take care about it
0377     KisPaintDeviceSP projection = this->projection();
0378     if (projection && projection != original()) {
0379         projection->setDefaultBounds(new KisDefaultBounds(image));
0380     }
0381     m_d->safeProjection->setImage(image);
0382 
0383     KisNode::setImage(image);
0384 }
0385 
0386 bool KisLayer::canMergeAndKeepBlendOptions(KisLayerSP otherLayer)
0387 {
0388     return
0389         this->compositeOpId() == otherLayer->compositeOpId() &&
0390         this->opacity() == otherLayer->opacity() &&
0391         this->channelFlags() == otherLayer->channelFlags() &&
0392         !this->layerStyle() && !otherLayer->layerStyle() &&
0393         (this->colorSpace() == otherLayer->colorSpace() ||
0394          *this->colorSpace() == *otherLayer->colorSpace());
0395 }
0396 
0397 KisLayerSP KisLayer::createMergedLayerTemplate(KisLayerSP prevLayer)
0398 {
0399     const bool keepBlendingOptions = canMergeAndKeepBlendOptions(prevLayer);
0400 
0401     KisLayerSP newLayer = new KisPaintLayer(image(), prevLayer->name(), OPACITY_OPAQUE_U8);
0402 
0403     if (keepBlendingOptions) {
0404         newLayer->setCompositeOpId(compositeOpId());
0405         newLayer->setOpacity(opacity());
0406         newLayer->setChannelFlags(channelFlags());
0407     }
0408 
0409     return newLayer;
0410 }
0411 
0412 void KisLayer::fillMergedLayerTemplate(KisLayerSP dstLayer, KisLayerSP prevLayer, bool skipPaintingThisLayer)
0413 {
0414     const bool keepBlendingOptions = canMergeAndKeepBlendOptions(prevLayer);
0415 
0416     QRect layerProjectionExtent = this->projection()->extent();
0417     QRect prevLayerProjectionExtent = prevLayer->projection()->extent();
0418     bool alphaDisabled = this->alphaChannelDisabled();
0419     bool prevAlphaDisabled = prevLayer->alphaChannelDisabled();
0420 
0421     KisPaintDeviceSP mergedDevice = dstLayer->paintDevice();
0422 
0423     if (!keepBlendingOptions) {
0424         KisPainter gc(mergedDevice);
0425 
0426         KisImageSP imageSP = image().toStrongRef();
0427         if (!imageSP) {
0428             return;
0429         }
0430 
0431         //Copy the pixels of previous layer with their actual alpha value
0432         prevLayer->disableAlphaChannel(false);
0433 
0434         prevLayer->projectionPlane()->apply(&gc, prevLayerProjectionExtent | imageSP->bounds());
0435 
0436         //Restore the previous prevLayer disableAlpha status for correct undo/redo
0437         prevLayer->disableAlphaChannel(prevAlphaDisabled);
0438 
0439         if (!skipPaintingThisLayer) {
0440             //Paint the pixels of the current layer, using their actual alpha value
0441             if (alphaDisabled == prevAlphaDisabled) {
0442                 this->disableAlphaChannel(false);
0443             }
0444 
0445             this->projectionPlane()->apply(&gc, layerProjectionExtent | imageSP->bounds());
0446 
0447             //Restore the layer disableAlpha status for correct undo/redo
0448             this->disableAlphaChannel(alphaDisabled);
0449         }
0450     }
0451     else {
0452         //Copy prevLayer
0453         KisPaintDeviceSP srcDev = prevLayer->projection();
0454         mergedDevice->makeCloneFrom(srcDev, srcDev->extent());
0455 
0456         if (!skipPaintingThisLayer) {
0457             //Paint layer on the copy
0458             KisPainter gc(mergedDevice);
0459             gc.bitBlt(layerProjectionExtent.topLeft(), this->projection(), layerProjectionExtent);
0460         }
0461     }
0462 }
0463 
0464 void KisLayer::registerClone(KisCloneLayerWSP clone)
0465 {
0466     m_d->clonesList.addClone(clone);
0467 }
0468 
0469 void KisLayer::unregisterClone(KisCloneLayerWSP clone)
0470 {
0471     m_d->clonesList.removeClone(clone);
0472 }
0473 
0474 const QList<KisCloneLayerWSP> KisLayer::registeredClones() const
0475 {
0476     return m_d->clonesList.registeredClones();
0477 }
0478 
0479 bool KisLayer::hasClones() const
0480 {
0481     return m_d->clonesList.hasClones();
0482 }
0483 
0484 void KisLayer::updateClones(const QRect &rect)
0485 {
0486     m_d->clonesList.setDirty(rect);
0487 }
0488 
0489 void KisLayer::notifyChildMaskChanged()
0490 {
0491     m_d->masksCache.setDirty();
0492 }
0493 
0494 KisSelectionMaskSP KisLayer::selectionMask() const
0495 {
0496     return m_d->masksCache.selectionMask();
0497 }
0498 
0499 KisSelectionSP KisLayer::selection() const
0500 {
0501     KisSelectionMaskSP mask = selectionMask();
0502 
0503     if (mask) {
0504         return mask->selection();
0505     }
0506 
0507     KisImageSP image = this->image();
0508     if (image) {
0509         return image->globalSelection();
0510     }
0511     return KisSelectionSP();
0512 }
0513 
0514 ///////////////////////////////////////////////////////////////////////
0515 ///////////////////////////////////////////////////////////////////////
0516 
0517 QList<KisEffectMaskSP> KisLayer::effectMasks() const
0518 {
0519     return m_d->masksCache.effectMasks();
0520 }
0521 
0522 QList<KisEffectMaskSP> KisLayer::effectMasks(KisNodeSP lastNode) const
0523 {
0524     if (lastNode.isNull()) {
0525         return effectMasks();
0526     } else {
0527         // happens rarely.
0528         return searchEffectMasks(lastNode);
0529     }
0530 }
0531 
0532 QList<KisEffectMaskSP> KisLayer::searchEffectMasks(KisNodeSP lastNode) const
0533 {
0534     QList<KisEffectMaskSP> masks;
0535 
0536     KIS_SAFE_ASSERT_RECOVER_NOOP(projectionLeaf());
0537 
0538     KisProjectionLeafSP child = projectionLeaf()->firstChild();
0539     while (child) {
0540         if (child->node() == lastNode) break;
0541 
0542         KIS_SAFE_ASSERT_RECOVER_NOOP(child);
0543         KIS_SAFE_ASSERT_RECOVER_NOOP(child->node());
0544 
0545         if (child->visible()) {
0546             KisEffectMaskSP mask = dynamic_cast<KisEffectMask*>(const_cast<KisNode*>(child->node().data()));
0547             if (mask) {
0548                 masks.append(mask);
0549             }
0550         }
0551 
0552         child = child->nextSibling();
0553     }
0554 
0555     return masks;
0556 }
0557 
0558 bool KisLayer::hasEffectMasks() const
0559 {
0560     return  !m_d->masksCache.effectMasks().isEmpty();
0561 }
0562 
0563 QRect KisLayer::masksChangeRect(const QList<KisEffectMaskSP> &masks,
0564                                 const QRect &requestedRect,
0565                                 bool &rectVariesFlag) const
0566 {
0567     rectVariesFlag = false;
0568 
0569     QRect prevChangeRect = requestedRect;
0570 
0571     /**
0572      * We set default value of the change rect for the case
0573      * when there is no mask at all
0574      */
0575     QRect changeRect = requestedRect;
0576 
0577     Q_FOREACH (const KisEffectMaskSP& mask, masks) {
0578         changeRect = mask->changeRect(prevChangeRect);
0579 
0580         if (changeRect != prevChangeRect)
0581             rectVariesFlag = true;
0582 
0583         prevChangeRect = changeRect;
0584     }
0585 
0586     return changeRect;
0587 }
0588 
0589 QRect KisLayer::masksNeedRect(const QList<KisEffectMaskSP> &masks,
0590                               const QRect &changeRect,
0591                               QStack<QRect> &applyRects,
0592                               bool &rectVariesFlag) const
0593 {
0594     rectVariesFlag = false;
0595 
0596     QRect prevNeedRect = changeRect;
0597     QRect needRect;
0598     
0599     for (qint32 i = masks.size() - 1; i >= 0; i--) {
0600         applyRects.push(prevNeedRect);
0601 
0602         needRect = masks[i]->needRect(prevNeedRect);
0603 
0604         if (prevNeedRect != needRect)
0605             rectVariesFlag = true;
0606 
0607         prevNeedRect = needRect;
0608     }
0609 
0610     return needRect;
0611 }
0612 
0613 KisNode::PositionToFilthy calculatePositionToFilthy(KisNodeSP nodeInQuestion,
0614                                            KisNodeSP filthy,
0615                                            KisNodeSP parent)
0616 {
0617     if (parent == filthy || parent != filthy->parent()) {
0618         return KisNode::N_ABOVE_FILTHY;
0619     }
0620 
0621     if (nodeInQuestion == filthy) {
0622         return KisNode::N_FILTHY;
0623     }
0624 
0625     KisNodeSP node = nodeInQuestion->prevSibling();
0626     while (node) {
0627         if (node == filthy) {
0628             return KisNode::N_ABOVE_FILTHY;
0629         }
0630         node = node->prevSibling();
0631     }
0632 
0633     return KisNode::N_BELOW_FILTHY;
0634 }
0635 
0636 QRect KisLayer::applyMasks(const KisPaintDeviceSP source,
0637                            KisPaintDeviceSP destination,
0638                            const QRect &requestedRect,
0639                            KisNodeSP filthyNode,
0640                            KisNodeSP lastNode) const
0641 {
0642     Q_ASSERT(source);
0643     Q_ASSERT(destination);
0644 
0645     QList<KisEffectMaskSP> masks = effectMasks(lastNode);
0646     QRect changeRect;
0647     QRect needRect;
0648 
0649     if (masks.isEmpty()) {
0650         changeRect = requestedRect;
0651         if (source != destination) {
0652             copyOriginalToProjection(source, destination, requestedRect);
0653         }
0654     } else {
0655         QStack<QRect> applyRects;
0656         bool changeRectVaries;
0657         bool needRectVaries;
0658 
0659         /**
0660          * FIXME: Assume that varying of the changeRect has already
0661          * been taken into account while preparing walkers
0662          */
0663         changeRectVaries = false;
0664         changeRect = requestedRect;
0665         //changeRect = masksChangeRect(masks, requestedRect,
0666         //                             changeRectVaries);
0667 
0668         needRect = masksNeedRect(masks, changeRect,
0669                                  applyRects, needRectVaries);
0670 
0671         if (!changeRectVaries && !needRectVaries) {
0672             /**
0673              * A bit of optimization:
0674              * All filters will read/write exactly from/to the requested
0675              * rect so we needn't create temporary paint device,
0676              * just apply it onto destination
0677              */
0678             Q_ASSERT(needRect == requestedRect);
0679 
0680             if (source != destination) {
0681                 copyOriginalToProjection(source, destination, needRect);
0682             }
0683 
0684             Q_FOREACH (const KisEffectMaskSP& mask, masks) {
0685                 const QRect maskApplyRect = applyRects.pop();
0686                 const QRect maskNeedRect =
0687                     applyRects.isEmpty() ? needRect : applyRects.top();
0688                     
0689                 PositionToFilthy maskPosition = calculatePositionToFilthy(mask, filthyNode, const_cast<KisLayer*>(this));
0690                 mask->apply(destination, maskApplyRect, maskNeedRect, maskPosition);
0691             }
0692             Q_ASSERT(applyRects.isEmpty());
0693         } else {
0694             /**
0695              * We can't eliminate additional copy-op
0696              * as filters' behaviour may be quite insane here,
0697              * so let them work on their own paintDevice =)
0698              */
0699 
0700             KisPaintDeviceSP tempDevice = new KisPaintDevice(colorSpace());
0701             tempDevice->prepareClone(source);
0702             copyOriginalToProjection(source, tempDevice, needRect);
0703 
0704             QRect maskApplyRect = applyRects.pop();
0705             QRect maskNeedRect = needRect;
0706 
0707             Q_FOREACH (const KisEffectMaskSP& mask, masks) {
0708                 PositionToFilthy maskPosition = calculatePositionToFilthy(mask, filthyNode, const_cast<KisLayer*>(this));
0709                 mask->apply(tempDevice, maskApplyRect, maskNeedRect, maskPosition);
0710 
0711                 if (!applyRects.isEmpty()) {
0712                     maskNeedRect = maskApplyRect;
0713                     maskApplyRect = applyRects.pop();
0714                 }
0715             }
0716             Q_ASSERT(applyRects.isEmpty());
0717 
0718             KisPainter::copyAreaOptimized(changeRect.topLeft(), tempDevice, destination, changeRect);
0719         }
0720     }
0721 
0722     return changeRect;
0723 }
0724 
0725 QRect KisLayer::updateProjection(const QRect& rect, KisNodeSP filthyNode)
0726 {
0727     QRect updatedRect = rect;
0728     KisPaintDeviceSP originalDevice = original();
0729     if (!rect.isValid() ||
0730         (!visible() && !isIsolatedRoot() && !hasClones()) ||
0731         !originalDevice) return QRect();
0732 
0733     if (!needProjection() && !hasEffectMasks()) {
0734         m_d->safeProjection->releaseDevice();
0735     } else {
0736 
0737         if (!updatedRect.isEmpty()) {
0738             KisPaintDeviceSP projection = m_d->safeProjection->getDeviceLazy(originalDevice);
0739             updatedRect = applyMasks(originalDevice, projection,
0740                                      updatedRect, filthyNode, 0);
0741         }
0742     }
0743 
0744     return updatedRect;
0745 }
0746 
0747 QRect KisLayer::partialChangeRect(KisNodeSP lastNode, const QRect& rect)
0748 {
0749     bool changeRectVaries = false;
0750     QRect changeRect = outgoingChangeRect(rect);
0751     changeRect = masksChangeRect(effectMasks(lastNode), changeRect,
0752                                  changeRectVaries);
0753 
0754     return changeRect;
0755 }
0756 
0757 /**
0758  * \p rect is a dirty rect in layer's original() coordinates!
0759  */
0760 void KisLayer::buildProjectionUpToNode(KisPaintDeviceSP projection, KisNodeSP lastNode, const QRect& rect)
0761 {
0762     QRect changeRect = partialChangeRect(lastNode, rect);
0763 
0764     KisPaintDeviceSP originalDevice = original();
0765 
0766     KIS_SAFE_ASSERT_RECOVER_RETURN(needProjection() || hasEffectMasks());
0767 
0768     if (!changeRect.isEmpty()) {
0769         applyMasks(originalDevice, projection,
0770                    changeRect, this, lastNode);
0771     }
0772 }
0773 
0774 bool KisLayer::needProjection() const
0775 {
0776     return false;
0777 }
0778 
0779 void KisLayer::copyOriginalToProjection(const KisPaintDeviceSP original,
0780                                         KisPaintDeviceSP projection,
0781                                         const QRect& rect) const
0782 {
0783     KisPainter::copyAreaOptimized(rect.topLeft(), original, projection, rect);
0784 }
0785 
0786 KisAbstractProjectionPlaneSP KisLayer::projectionPlane() const
0787 {
0788     return m_d->layerStyleProjectionPlane ?
0789         KisAbstractProjectionPlaneSP(m_d->layerStyleProjectionPlane) :
0790         KisAbstractProjectionPlaneSP(m_d->projectionPlane);
0791 }
0792 
0793 KisLayerProjectionPlaneSP KisLayer::internalProjectionPlane() const
0794 {
0795     return m_d->projectionPlane;
0796 }
0797 
0798 KisPaintDeviceSP KisLayer::projection() const
0799 {
0800     KisPaintDeviceSP originalDevice = original();
0801 
0802     return needProjection() || hasEffectMasks() ?
0803         m_d->safeProjection->getDeviceLazy(originalDevice) : originalDevice;
0804 }
0805 
0806 QRect KisLayer::tightUserVisibleBounds() const
0807 {
0808     QRect changeRect = exactBounds();
0809 
0810     /// we do not use incomingChangeRect() here, because
0811     /// exactBounds() already takes it into account (it
0812     /// was used while preparing original())
0813 
0814     bool changeRectVaries;
0815     changeRect = outgoingChangeRect(changeRect);
0816     changeRect = masksChangeRect(effectMasks(), changeRect, changeRectVaries);
0817 
0818     return changeRect;
0819 }
0820 
0821 QRect KisLayer::amortizedProjectionRectForCleanupInChangePass() const
0822 {
0823     return projection()->exactBoundsAmortized();
0824 }
0825 
0826 QRect KisLayer::changeRect(const QRect &rect, PositionToFilthy pos) const
0827 {
0828     QRect changeRect = rect;
0829     changeRect = incomingChangeRect(changeRect);
0830 
0831     if(pos == KisNode::N_FILTHY) {
0832         QRect projectionToBeUpdated = amortizedProjectionRectForCleanupInChangePass() & changeRect;
0833 
0834         bool changeRectVaries;
0835         changeRect = outgoingChangeRect(changeRect);
0836         changeRect = masksChangeRect(effectMasks(), changeRect, changeRectVaries);
0837 
0838         /**
0839          * If the projection contains some dirty areas we should also
0840          * add them to the change rect, because they might have
0841          * changed. E.g. when a visibility of the mask has changed
0842          * while the parent layer was invincible.
0843          */
0844 
0845         if (!projectionToBeUpdated.isEmpty() &&
0846             !changeRect.contains(projectionToBeUpdated)) {
0847 
0848             changeRect |= projectionToBeUpdated;
0849         }
0850     }
0851 
0852     // TODO: string comparison: optimize!
0853     if (pos != KisNode::N_FILTHY &&
0854         pos != KisNode::N_FILTHY_PROJECTION &&
0855         compositeOpId() != COMPOSITE_COPY) {
0856 
0857         changeRect |= rect;
0858     }
0859 
0860     return changeRect;
0861 }
0862 
0863 void KisLayer::childNodeChanged(KisNodeSP changedChildNode)
0864 {
0865     if (dynamic_cast<KisMask*>(changedChildNode.data())) {
0866         notifyChildMaskChanged();
0867     }
0868 }
0869 
0870 QRect KisLayer::incomingChangeRect(const QRect &rect) const
0871 {
0872     return rect;
0873 }
0874 
0875 QRect KisLayer::outgoingChangeRect(const QRect &rect) const
0876 {
0877     return rect;
0878 }
0879 
0880 QRect KisLayer::needRectForOriginal(const QRect &rect) const
0881 {
0882     QRect needRect = rect;
0883 
0884     const QList<KisEffectMaskSP> masks = effectMasks();
0885 
0886     if (!masks.isEmpty()) {
0887         QStack<QRect> applyRects;
0888         bool needRectVaries;
0889 
0890         needRect = masksNeedRect(masks, rect,
0891                                  applyRects, needRectVaries);
0892     }
0893 
0894     return needRect;
0895 }
0896 
0897 QImage KisLayer::createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode)
0898 {
0899     if (w == 0 || h == 0) {
0900         return QImage();
0901     }
0902 
0903     KisPaintDeviceSP originalDevice = original();
0904 
0905     return originalDevice ?
0906            originalDevice->createThumbnail(w, h, aspectRatioMode, 1,
0907                                            KoColorConversionTransformation::internalRenderingIntent(),
0908                                            KoColorConversionTransformation::internalConversionFlags()) : QImage();
0909 }
0910 
0911 int KisLayer::thumbnailSeqNo() const
0912 {
0913     KisPaintDeviceSP originalDevice = original();
0914     return originalDevice ? originalDevice->sequenceNumber() : -1;
0915 }
0916 
0917 QImage KisLayer::createThumbnailForFrame(qint32 w, qint32 h, int time, Qt::AspectRatioMode aspectRatioMode)
0918 {
0919     if (w == 0 || h == 0) {
0920         return QImage();
0921     }
0922 
0923     KisPaintDeviceSP originalDevice = original();
0924     if (originalDevice ) {
0925         KisRasterKeyframeChannel *channel = originalDevice->keyframeChannel();
0926 
0927         if (channel) {
0928             KisPaintDeviceSP targetDevice = new KisPaintDevice(colorSpace());
0929             KisRasterKeyframeSP keyframe = channel->activeKeyframeAt<KisRasterKeyframe>(time);
0930             keyframe->writeFrameToDevice(targetDevice);
0931             return targetDevice->createThumbnail(w, h, aspectRatioMode, 1,
0932                                                  KoColorConversionTransformation::internalRenderingIntent(),
0933                                                  KoColorConversionTransformation::internalConversionFlags());
0934         }
0935     }
0936 
0937     return createThumbnail(w, h);
0938 }
0939 
0940 qint32 KisLayer::x() const
0941 {
0942     KisPaintDeviceSP originalDevice = original();
0943     return originalDevice ? originalDevice->x() : 0;
0944 }
0945 qint32 KisLayer::y() const
0946 {
0947     KisPaintDeviceSP originalDevice = original();
0948     return originalDevice ? originalDevice->y() : 0;
0949 }
0950 void KisLayer::setX(qint32 x)
0951 {
0952     KisPaintDeviceSP originalDevice = original();
0953     if (originalDevice)
0954         originalDevice->setX(x);
0955 }
0956 void KisLayer::setY(qint32 y)
0957 {
0958     KisPaintDeviceSP originalDevice = original();
0959     if (originalDevice)
0960         originalDevice->setY(y);
0961 }
0962 
0963 QRect KisLayer::layerExtentImpl(bool needExactBounds) const
0964 {
0965     QRect additionalMaskExtent = QRect();
0966     QList<KisEffectMaskSP> effectMasks = this->effectMasks();
0967 
0968     Q_FOREACH(KisEffectMaskSP mask, effectMasks) {
0969         additionalMaskExtent |= mask->nonDependentExtent();
0970     }
0971 
0972     KisPaintDeviceSP originalDevice = original();
0973     QRect layerExtent;
0974 
0975     if (originalDevice) {
0976         layerExtent = needExactBounds ?
0977             originalDevice->exactBounds() :
0978             originalDevice->extent();
0979     }
0980 
0981     QRect additionalCompositeOpExtent;
0982     if (compositeOpId() == COMPOSITE_COPY ||
0983         compositeOpId() == COMPOSITE_DESTINATION_IN ||
0984         compositeOpId() == COMPOSITE_DESTINATION_ATOP) {
0985 
0986         additionalCompositeOpExtent = originalDevice->defaultBounds()->bounds();
0987     }
0988 
0989     return layerExtent | additionalMaskExtent | additionalCompositeOpExtent;
0990 }
0991 
0992 QRect KisLayer::extent() const
0993 {
0994     return layerExtentImpl(false);
0995 }
0996 
0997 QRect KisLayer::exactBounds() const
0998 {
0999     return layerExtentImpl(true);
1000 }
1001 
1002 KisLayerSP KisLayer::parentLayer() const
1003 {
1004     return qobject_cast<KisLayer*>(parent().data());
1005 }
1006 
1007 KisMetaData::Store* KisLayer::metaData()
1008 {
1009     return m_d->metaDataStore;
1010 }
1011