File indexing completed on 2024-05-12 15:58:24

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)
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         //Paint the pixels of the current layer, using their actual alpha value
0440         if (alphaDisabled == prevAlphaDisabled) {
0441             this->disableAlphaChannel(false);
0442         }
0443 
0444         this->projectionPlane()->apply(&gc, layerProjectionExtent | imageSP->bounds());
0445 
0446         //Restore the layer disableAlpha status for correct undo/redo
0447         this->disableAlphaChannel(alphaDisabled);
0448     }
0449     else {
0450         //Copy prevLayer
0451         KisPaintDeviceSP srcDev = prevLayer->projection();
0452         mergedDevice->makeCloneFrom(srcDev, srcDev->extent());
0453 
0454         //Paint layer on the copy
0455         KisPainter gc(mergedDevice);
0456         gc.bitBlt(layerProjectionExtent.topLeft(), this->projection(), layerProjectionExtent);
0457     }
0458 }
0459 
0460 void KisLayer::registerClone(KisCloneLayerWSP clone)
0461 {
0462     m_d->clonesList.addClone(clone);
0463 }
0464 
0465 void KisLayer::unregisterClone(KisCloneLayerWSP clone)
0466 {
0467     m_d->clonesList.removeClone(clone);
0468 }
0469 
0470 const QList<KisCloneLayerWSP> KisLayer::registeredClones() const
0471 {
0472     return m_d->clonesList.registeredClones();
0473 }
0474 
0475 bool KisLayer::hasClones() const
0476 {
0477     return m_d->clonesList.hasClones();
0478 }
0479 
0480 void KisLayer::updateClones(const QRect &rect)
0481 {
0482     m_d->clonesList.setDirty(rect);
0483 }
0484 
0485 void KisLayer::notifyChildMaskChanged()
0486 {
0487     m_d->masksCache.setDirty();
0488 }
0489 
0490 KisSelectionMaskSP KisLayer::selectionMask() const
0491 {
0492     return m_d->masksCache.selectionMask();
0493 }
0494 
0495 KisSelectionSP KisLayer::selection() const
0496 {
0497     KisSelectionMaskSP mask = selectionMask();
0498 
0499     if (mask) {
0500         return mask->selection();
0501     }
0502 
0503     KisImageSP image = this->image();
0504     if (image) {
0505         return image->globalSelection();
0506     }
0507     return KisSelectionSP();
0508 }
0509 
0510 ///////////////////////////////////////////////////////////////////////
0511 ///////////////////////////////////////////////////////////////////////
0512 
0513 QList<KisEffectMaskSP> KisLayer::effectMasks() const
0514 {
0515     return m_d->masksCache.effectMasks();
0516 }
0517 
0518 QList<KisEffectMaskSP> KisLayer::effectMasks(KisNodeSP lastNode) const
0519 {
0520     if (lastNode.isNull()) {
0521         return effectMasks();
0522     } else {
0523         // happens rarely.
0524         return searchEffectMasks(lastNode);
0525     }
0526 }
0527 
0528 QList<KisEffectMaskSP> KisLayer::searchEffectMasks(KisNodeSP lastNode) const
0529 {
0530     QList<KisEffectMaskSP> masks;
0531 
0532     KIS_SAFE_ASSERT_RECOVER_NOOP(projectionLeaf());
0533 
0534     KisProjectionLeafSP child = projectionLeaf()->firstChild();
0535     while (child) {
0536         if (child->node() == lastNode) break;
0537 
0538         KIS_SAFE_ASSERT_RECOVER_NOOP(child);
0539         KIS_SAFE_ASSERT_RECOVER_NOOP(child->node());
0540 
0541         if (child->visible()) {
0542             KisEffectMaskSP mask = dynamic_cast<KisEffectMask*>(const_cast<KisNode*>(child->node().data()));
0543             if (mask) {
0544                 masks.append(mask);
0545             }
0546         }
0547 
0548         child = child->nextSibling();
0549     }
0550 
0551     return masks;
0552 }
0553 
0554 bool KisLayer::hasEffectMasks() const
0555 {
0556     return  !m_d->masksCache.effectMasks().isEmpty();
0557 }
0558 
0559 QRect KisLayer::masksChangeRect(const QList<KisEffectMaskSP> &masks,
0560                                 const QRect &requestedRect,
0561                                 bool &rectVariesFlag) const
0562 {
0563     rectVariesFlag = false;
0564 
0565     QRect prevChangeRect = requestedRect;
0566 
0567     /**
0568      * We set default value of the change rect for the case
0569      * when there is no mask at all
0570      */
0571     QRect changeRect = requestedRect;
0572 
0573     Q_FOREACH (const KisEffectMaskSP& mask, masks) {
0574         changeRect = mask->changeRect(prevChangeRect);
0575 
0576         if (changeRect != prevChangeRect)
0577             rectVariesFlag = true;
0578 
0579         prevChangeRect = changeRect;
0580     }
0581 
0582     return changeRect;
0583 }
0584 
0585 QRect KisLayer::masksNeedRect(const QList<KisEffectMaskSP> &masks,
0586                               const QRect &changeRect,
0587                               QStack<QRect> &applyRects,
0588                               bool &rectVariesFlag) const
0589 {
0590     rectVariesFlag = false;
0591 
0592     QRect prevNeedRect = changeRect;
0593     QRect needRect;
0594     
0595     for (qint32 i = masks.size() - 1; i >= 0; i--) {
0596         applyRects.push(prevNeedRect);
0597 
0598         needRect = masks[i]->needRect(prevNeedRect);
0599 
0600         if (prevNeedRect != needRect)
0601             rectVariesFlag = true;
0602 
0603         prevNeedRect = needRect;
0604     }
0605 
0606     return needRect;
0607 }
0608 
0609 KisNode::PositionToFilthy calculatePositionToFilthy(KisNodeSP nodeInQuestion,
0610                                            KisNodeSP filthy,
0611                                            KisNodeSP parent)
0612 {
0613     if (parent == filthy || parent != filthy->parent()) {
0614         return KisNode::N_ABOVE_FILTHY;
0615     }
0616 
0617     if (nodeInQuestion == filthy) {
0618         return KisNode::N_FILTHY;
0619     }
0620 
0621     KisNodeSP node = nodeInQuestion->prevSibling();
0622     while (node) {
0623         if (node == filthy) {
0624             return KisNode::N_ABOVE_FILTHY;
0625         }
0626         node = node->prevSibling();
0627     }
0628 
0629     return KisNode::N_BELOW_FILTHY;
0630 }
0631 
0632 QRect KisLayer::applyMasks(const KisPaintDeviceSP source,
0633                            KisPaintDeviceSP destination,
0634                            const QRect &requestedRect,
0635                            KisNodeSP filthyNode,
0636                            KisNodeSP lastNode) const
0637 {
0638     Q_ASSERT(source);
0639     Q_ASSERT(destination);
0640 
0641     QList<KisEffectMaskSP> masks = effectMasks(lastNode);
0642     QRect changeRect;
0643     QRect needRect;
0644 
0645     if (masks.isEmpty()) {
0646         changeRect = requestedRect;
0647         if (source != destination) {
0648             copyOriginalToProjection(source, destination, requestedRect);
0649         }
0650     } else {
0651         QStack<QRect> applyRects;
0652         bool changeRectVaries;
0653         bool needRectVaries;
0654 
0655         /**
0656          * FIXME: Assume that varying of the changeRect has already
0657          * been taken into account while preparing walkers
0658          */
0659         changeRectVaries = false;
0660         changeRect = requestedRect;
0661         //changeRect = masksChangeRect(masks, requestedRect,
0662         //                             changeRectVaries);
0663 
0664         needRect = masksNeedRect(masks, changeRect,
0665                                  applyRects, needRectVaries);
0666 
0667         if (!changeRectVaries && !needRectVaries) {
0668             /**
0669              * A bit of optimization:
0670              * All filters will read/write exactly from/to the requested
0671              * rect so we needn't create temporary paint device,
0672              * just apply it onto destination
0673              */
0674             Q_ASSERT(needRect == requestedRect);
0675 
0676             if (source != destination) {
0677                 copyOriginalToProjection(source, destination, needRect);
0678             }
0679 
0680             Q_FOREACH (const KisEffectMaskSP& mask, masks) {
0681                 const QRect maskApplyRect = applyRects.pop();
0682                 const QRect maskNeedRect =
0683                     applyRects.isEmpty() ? needRect : applyRects.top();
0684                     
0685                 PositionToFilthy maskPosition = calculatePositionToFilthy(mask, filthyNode, const_cast<KisLayer*>(this));
0686                 mask->apply(destination, maskApplyRect, maskNeedRect, maskPosition);
0687             }
0688             Q_ASSERT(applyRects.isEmpty());
0689         } else {
0690             /**
0691              * We can't eliminate additional copy-op
0692              * as filters' behaviour may be quite insane here,
0693              * so let them work on their own paintDevice =)
0694              */
0695 
0696             KisPaintDeviceSP tempDevice = new KisPaintDevice(colorSpace());
0697             tempDevice->prepareClone(source);
0698             copyOriginalToProjection(source, tempDevice, needRect);
0699 
0700             QRect maskApplyRect = applyRects.pop();
0701             QRect maskNeedRect = needRect;
0702 
0703             Q_FOREACH (const KisEffectMaskSP& mask, masks) {
0704                 PositionToFilthy maskPosition = calculatePositionToFilthy(mask, filthyNode, const_cast<KisLayer*>(this));
0705                 mask->apply(tempDevice, maskApplyRect, maskNeedRect, maskPosition);
0706 
0707                 if (!applyRects.isEmpty()) {
0708                     maskNeedRect = maskApplyRect;
0709                     maskApplyRect = applyRects.pop();
0710                 }
0711             }
0712             Q_ASSERT(applyRects.isEmpty());
0713 
0714             KisPainter::copyAreaOptimized(changeRect.topLeft(), tempDevice, destination, changeRect);
0715         }
0716     }
0717 
0718     return changeRect;
0719 }
0720 
0721 QRect KisLayer::updateProjection(const QRect& rect, KisNodeSP filthyNode)
0722 {
0723     QRect updatedRect = rect;
0724     KisPaintDeviceSP originalDevice = original();
0725     if (!rect.isValid() ||
0726         (!visible() && !isIsolatedRoot() && !hasClones()) ||
0727         !originalDevice) return QRect();
0728 
0729     if (!needProjection() && !hasEffectMasks()) {
0730         m_d->safeProjection->releaseDevice();
0731     } else {
0732 
0733         if (!updatedRect.isEmpty()) {
0734             KisPaintDeviceSP projection = m_d->safeProjection->getDeviceLazy(originalDevice);
0735             updatedRect = applyMasks(originalDevice, projection,
0736                                      updatedRect, filthyNode, 0);
0737         }
0738     }
0739 
0740     return updatedRect;
0741 }
0742 
0743 QRect KisLayer::partialChangeRect(KisNodeSP lastNode, const QRect& rect)
0744 {
0745     bool changeRectVaries = false;
0746     QRect changeRect = outgoingChangeRect(rect);
0747     changeRect = masksChangeRect(effectMasks(lastNode), changeRect,
0748                                  changeRectVaries);
0749 
0750     return changeRect;
0751 }
0752 
0753 /**
0754  * \p rect is a dirty rect in layer's original() coordinates!
0755  */
0756 void KisLayer::buildProjectionUpToNode(KisPaintDeviceSP projection, KisNodeSP lastNode, const QRect& rect)
0757 {
0758     QRect changeRect = partialChangeRect(lastNode, rect);
0759 
0760     KisPaintDeviceSP originalDevice = original();
0761 
0762     KIS_SAFE_ASSERT_RECOVER_RETURN(needProjection() || hasEffectMasks());
0763 
0764     if (!changeRect.isEmpty()) {
0765         applyMasks(originalDevice, projection,
0766                    changeRect, this, lastNode);
0767     }
0768 }
0769 
0770 bool KisLayer::needProjection() const
0771 {
0772     return false;
0773 }
0774 
0775 void KisLayer::copyOriginalToProjection(const KisPaintDeviceSP original,
0776                                         KisPaintDeviceSP projection,
0777                                         const QRect& rect) const
0778 {
0779     KisPainter::copyAreaOptimized(rect.topLeft(), original, projection, rect);
0780 }
0781 
0782 KisAbstractProjectionPlaneSP KisLayer::projectionPlane() const
0783 {
0784     return m_d->layerStyleProjectionPlane ?
0785         KisAbstractProjectionPlaneSP(m_d->layerStyleProjectionPlane) :
0786         KisAbstractProjectionPlaneSP(m_d->projectionPlane);
0787 }
0788 
0789 KisLayerProjectionPlaneSP KisLayer::internalProjectionPlane() const
0790 {
0791     return m_d->projectionPlane;
0792 }
0793 
0794 KisPaintDeviceSP KisLayer::projection() const
0795 {
0796     KisPaintDeviceSP originalDevice = original();
0797 
0798     return needProjection() || hasEffectMasks() ?
0799         m_d->safeProjection->getDeviceLazy(originalDevice) : originalDevice;
0800 }
0801 
0802 QRect KisLayer::tightUserVisibleBounds() const
0803 {
0804     QRect changeRect = exactBounds();
0805 
0806     /// we do not use incomingChangeRect() here, because
0807     /// exactBounds() already takes it into account (it
0808     /// was used while preparing original())
0809 
0810     bool changeRectVaries;
0811     changeRect = outgoingChangeRect(changeRect);
0812     changeRect = masksChangeRect(effectMasks(), changeRect, changeRectVaries);
0813 
0814     return changeRect;
0815 }
0816 
0817 QRect KisLayer::amortizedProjectionRectForCleanupInChangePass() const
0818 {
0819     return projection()->exactBoundsAmortized();
0820 }
0821 
0822 QRect KisLayer::changeRect(const QRect &rect, PositionToFilthy pos) const
0823 {
0824     QRect changeRect = rect;
0825     changeRect = incomingChangeRect(changeRect);
0826 
0827     if(pos == KisNode::N_FILTHY) {
0828         QRect projectionToBeUpdated = amortizedProjectionRectForCleanupInChangePass() & changeRect;
0829 
0830         bool changeRectVaries;
0831         changeRect = outgoingChangeRect(changeRect);
0832         changeRect = masksChangeRect(effectMasks(), changeRect, changeRectVaries);
0833 
0834         /**
0835          * If the projection contains some dirty areas we should also
0836          * add them to the change rect, because they might have
0837          * changed. E.g. when a visibility of the mask has chnaged
0838          * while the parent layer was invinisble.
0839          */
0840 
0841         if (!projectionToBeUpdated.isEmpty() &&
0842             !changeRect.contains(projectionToBeUpdated)) {
0843 
0844             changeRect |= projectionToBeUpdated;
0845         }
0846     }
0847 
0848     // TODO: string comparison: optimize!
0849     if (pos != KisNode::N_FILTHY &&
0850         pos != KisNode::N_FILTHY_PROJECTION &&
0851         compositeOpId() != COMPOSITE_COPY) {
0852 
0853         changeRect |= rect;
0854     }
0855 
0856     return changeRect;
0857 }
0858 
0859 void KisLayer::childNodeChanged(KisNodeSP changedChildNode)
0860 {
0861     if (dynamic_cast<KisMask*>(changedChildNode.data())) {
0862         notifyChildMaskChanged();
0863     }
0864 }
0865 
0866 QRect KisLayer::incomingChangeRect(const QRect &rect) const
0867 {
0868     return rect;
0869 }
0870 
0871 QRect KisLayer::outgoingChangeRect(const QRect &rect) const
0872 {
0873     return rect;
0874 }
0875 
0876 QRect KisLayer::needRectForOriginal(const QRect &rect) const
0877 {
0878     QRect needRect = rect;
0879 
0880     const QList<KisEffectMaskSP> masks = effectMasks();
0881 
0882     if (!masks.isEmpty()) {
0883         QStack<QRect> applyRects;
0884         bool needRectVaries;
0885 
0886         needRect = masksNeedRect(masks, rect,
0887                                  applyRects, needRectVaries);
0888     }
0889 
0890     return needRect;
0891 }
0892 
0893 QImage KisLayer::createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode)
0894 {
0895     if (w == 0 || h == 0) {
0896         return QImage();
0897     }
0898 
0899     KisPaintDeviceSP originalDevice = original();
0900 
0901     return originalDevice ?
0902            originalDevice->createThumbnail(w, h, aspectRatioMode, 1,
0903                                            KoColorConversionTransformation::internalRenderingIntent(),
0904                                            KoColorConversionTransformation::internalConversionFlags()) : QImage();
0905 }
0906 
0907 QImage KisLayer::createThumbnailForFrame(qint32 w, qint32 h, int time, Qt::AspectRatioMode aspectRatioMode)
0908 {
0909     if (w == 0 || h == 0) {
0910         return QImage();
0911     }
0912 
0913     KisPaintDeviceSP originalDevice = original();
0914     if (originalDevice ) {
0915         KisRasterKeyframeChannel *channel = originalDevice->keyframeChannel();
0916 
0917         if (channel) {
0918             KisPaintDeviceSP targetDevice = new KisPaintDevice(colorSpace());
0919             KisRasterKeyframeSP keyframe = channel->activeKeyframeAt<KisRasterKeyframe>(time);
0920             keyframe->writeFrameToDevice(targetDevice);
0921             return targetDevice->createThumbnail(w, h, aspectRatioMode, 1,
0922                                                  KoColorConversionTransformation::internalRenderingIntent(),
0923                                                  KoColorConversionTransformation::internalConversionFlags());
0924         }
0925     }
0926 
0927     return createThumbnail(w, h);
0928 }
0929 
0930 qint32 KisLayer::x() const
0931 {
0932     KisPaintDeviceSP originalDevice = original();
0933     return originalDevice ? originalDevice->x() : 0;
0934 }
0935 qint32 KisLayer::y() const
0936 {
0937     KisPaintDeviceSP originalDevice = original();
0938     return originalDevice ? originalDevice->y() : 0;
0939 }
0940 void KisLayer::setX(qint32 x)
0941 {
0942     KisPaintDeviceSP originalDevice = original();
0943     if (originalDevice)
0944         originalDevice->setX(x);
0945 }
0946 void KisLayer::setY(qint32 y)
0947 {
0948     KisPaintDeviceSP originalDevice = original();
0949     if (originalDevice)
0950         originalDevice->setY(y);
0951 }
0952 
0953 QRect KisLayer::layerExtentImpl(bool needExactBounds) const
0954 {
0955     QRect additionalMaskExtent = QRect();
0956     QList<KisEffectMaskSP> effectMasks = this->effectMasks();
0957 
0958     Q_FOREACH(KisEffectMaskSP mask, effectMasks) {
0959         additionalMaskExtent |= mask->nonDependentExtent();
0960     }
0961 
0962     KisPaintDeviceSP originalDevice = original();
0963     QRect layerExtent;
0964 
0965     if (originalDevice) {
0966         layerExtent = needExactBounds ?
0967             originalDevice->exactBounds() :
0968             originalDevice->extent();
0969     }
0970 
0971     QRect additionalCompositeOpExtent;
0972     if (compositeOpId() == COMPOSITE_COPY ||
0973         compositeOpId() == COMPOSITE_DESTINATION_IN ||
0974         compositeOpId() == COMPOSITE_DESTINATION_ATOP) {
0975 
0976         additionalCompositeOpExtent = originalDevice->defaultBounds()->bounds();
0977     }
0978 
0979     return layerExtent | additionalMaskExtent | additionalCompositeOpExtent;
0980 }
0981 
0982 QRect KisLayer::extent() const
0983 {
0984     return layerExtentImpl(false);
0985 }
0986 
0987 QRect KisLayer::exactBounds() const
0988 {
0989     return layerExtentImpl(true);
0990 }
0991 
0992 KisLayerSP KisLayer::parentLayer() const
0993 {
0994     return qobject_cast<KisLayer*>(parent().data());
0995 }
0996 
0997 KisMetaData::Store* KisLayer::metaData()
0998 {
0999     return m_d->metaDataStore;
1000 }
1001