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

0001 /*
0002  *  SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_clone_layer.h"
0008 
0009 #include <kis_debug.h>
0010 #include <klocalizedstring.h>
0011 
0012 #include <KoIcon.h>
0013 #include <kis_icon.h>
0014 
0015 #include <KoColorSpace.h>
0016 #include <KoCompositeOpRegistry.h>
0017 
0018 #include "kis_default_bounds.h"
0019 #include "kis_paint_device.h"
0020 #include "kis_image.h"
0021 #include "kis_painter.h"
0022 #include "kis_node_visitor.h"
0023 #include "kis_processing_visitor.h"
0024 #include "kis_paint_layer.h"
0025 
0026 #include <QStack>
0027 #include <kis_effect_mask.h>
0028 #include "kis_lod_capable_layer_offset.h"
0029 
0030 
0031 struct Q_DECL_HIDDEN KisCloneLayer::Private
0032 {
0033     Private(KisDefaultBoundsBaseSP defaultBounds)
0034         : offset(defaultBounds)
0035     {
0036     }
0037 
0038     KisPaintDeviceSP fallback;
0039     KisLodCapableLayerOffset offset;
0040 
0041     KisLayerSP copyFrom;
0042     KisNodeUuidInfo copyFromInfo;
0043     CopyLayerType type {COPY_PROJECTION};
0044 };
0045 
0046 KisCloneLayer::KisCloneLayer(KisLayerSP from, KisImageWSP image, const QString &name, quint8 opacity)
0047         : KisLayer(image, name, opacity)
0048         , m_d(new Private(new KisDefaultBounds(image)))
0049 {
0050     KisImageSP imageSP = image.toStrongRef();
0051     if (!imageSP) {
0052         return;
0053     }
0054     m_d->fallback = new KisPaintDevice(this,
0055                                        imageSP->colorSpace(),
0056                                        new KisDefaultBounds(imageSP));
0057     m_d->copyFrom = from;
0058     m_d->type = COPY_PROJECTION;
0059 
0060     // When loading the layer we copy from might not exist yet
0061     if (m_d->copyFrom) {
0062         m_d->copyFrom->registerClone(this);
0063     }
0064 }
0065 
0066 KisCloneLayer::KisCloneLayer(const KisCloneLayer& rhs)
0067         : KisLayer(rhs)
0068         , m_d(new Private(new KisDefaultBounds(rhs.image())))
0069 {
0070     m_d->fallback = new KisPaintDevice(this,
0071                                        rhs.m_d->fallback->colorSpace(),
0072                                        new KisDefaultBounds(rhs.image()));
0073     m_d->copyFrom = rhs.copyFrom();
0074     m_d->type = rhs.copyType();
0075     m_d->offset = rhs.m_d->offset;
0076 
0077     if (m_d->copyFrom) {
0078         m_d->copyFrom->registerClone(this);
0079     }
0080 }
0081 
0082 KisCloneLayer::~KisCloneLayer()
0083 {
0084     if (m_d->copyFrom) {
0085         m_d->copyFrom->unregisterClone(this);
0086     }
0087     delete m_d;
0088 }
0089 
0090 KisLayerSP KisCloneLayer::reincarnateAsPaintLayer() const
0091 {
0092     KisPaintDeviceSP newOriginal = new KisPaintDevice(*original());
0093     KisPaintLayerSP newLayer = new KisPaintLayer(image(), name(), opacity(), newOriginal);
0094     newLayer->setX(newLayer->x() + x());
0095     newLayer->setY(newLayer->y() + y());
0096     newLayer->setCompositeOpId(compositeOpId());
0097     newLayer->mergeNodeProperties(nodeProperties());
0098 
0099     return newLayer;
0100 }
0101 
0102 void KisCloneLayer::setImage(KisImageWSP image)
0103 {
0104     m_d->fallback->setDefaultBounds(new KisDefaultBounds(image));
0105     KisLayer::setImage(image);
0106 }
0107 
0108 bool KisCloneLayer::allowAsChild(KisNodeSP node) const
0109 {
0110     return node->inherits("KisMask");
0111 }
0112 
0113 KisPaintDeviceSP KisCloneLayer::paintDevice() const
0114 {
0115     return 0;
0116 }
0117 
0118 KisPaintDeviceSP KisCloneLayer::original() const
0119 {
0120     if (!m_d->copyFrom || !m_d->copyFrom->projection()) return m_d->fallback;
0121     KisPaintDeviceSP retval;
0122     switch (m_d->type) {
0123     case COPY_PROJECTION:
0124         retval = m_d->copyFrom->projection();
0125         break;
0126 
0127     case COPY_ORIGINAL:
0128     default:
0129         retval = m_d->copyFrom->original();
0130     }
0131 
0132     return retval;
0133 }
0134 
0135 bool KisCloneLayer::needProjection() const
0136 {
0137     return m_d->offset.x() || m_d->offset.y();
0138 }
0139 
0140 const KoColorSpace *KisCloneLayer::colorSpace() const
0141 {
0142     return m_d->copyFrom ? m_d->copyFrom->colorSpace() : m_d->fallback->colorSpace();
0143 }
0144 
0145 void KisCloneLayer::copyOriginalToProjection(const KisPaintDeviceSP original,
0146         KisPaintDeviceSP projection,
0147         const QRect& rect) const
0148 {
0149     QRect copyRect = rect;
0150     copyRect.translate(-m_d->offset.x(), -m_d->offset.y());
0151 
0152     KisPainter::copyAreaOptimized(rect.topLeft(), original, projection, copyRect);
0153 }
0154 
0155 void KisCloneLayer::setDirtyOriginal(const QRect &rect)
0156 {
0157     /**
0158      * The original will be updated when the clone becomes visible
0159      * again.
0160      */
0161     if (!visible(true)) return;
0162 
0163     /**
0164      *  HINT: this method is present for historical reasons only.
0165      *        Long time ago the updates were calculated in
0166      *        "copyOriginalToProjection" coordinate system. Now
0167      *        everything is done in "original()" space.
0168      */
0169     KisLayer::setDirty(rect);
0170 }
0171 
0172 void KisCloneLayer::notifyParentVisibilityChanged(bool value)
0173 {
0174     KisImageSP imageSP = image().toStrongRef();
0175     if (!imageSP) {
0176         return;
0177     }
0178     KisLayer::setDirty(imageSP->bounds());
0179     KisLayer::notifyParentVisibilityChanged(value);
0180 }
0181 
0182 QRect KisCloneLayer::needRectOnSourceForMasks(const QRect &rc) const
0183 {
0184     QStack<QRect> applyRects_unused;
0185     bool rectVariesFlag;
0186 
0187     QList<KisEffectMaskSP> effectMasks = this->effectMasks();
0188     if (effectMasks.isEmpty()) return QRect();
0189 
0190     QRect needRect = this->masksNeedRect(effectMasks,
0191                                          rc,
0192                                          applyRects_unused,
0193                                          rectVariesFlag);
0194 
0195     if (needRect.isEmpty() ||
0196         (!rectVariesFlag && needRect == rc)) {
0197 
0198         return QRect();
0199     }
0200 
0201     return needRect;
0202 }
0203 
0204 qint32 KisCloneLayer::x() const
0205 {
0206     return m_d->offset.x();
0207 }
0208 qint32 KisCloneLayer::y() const
0209 {
0210     return m_d->offset.y();
0211 }
0212 void KisCloneLayer::setX(qint32 x)
0213 {
0214     m_d->offset.setX(x);
0215 }
0216 void KisCloneLayer::setY(qint32 y)
0217 {
0218     m_d->offset.setY(y);
0219 }
0220 
0221 QRect KisCloneLayer::extent() const
0222 {
0223     QRect rect = original()->extent();
0224 
0225     // HINT: no offset now. See a comment in setDirtyOriginal()
0226     return rect | projection()->extent();
0227 }
0228 
0229 QRect KisCloneLayer::exactBounds() const
0230 {
0231     QRect rect = original()->exactBounds();
0232 
0233     // HINT: no offset now. See a comment in setDirtyOriginal()
0234     return rect | projection()->exactBounds();
0235 }
0236 
0237 QRect KisCloneLayer::accessRect(const QRect &rect, PositionToFilthy pos) const
0238 {
0239     QRect resultRect = rect;
0240 
0241     if(pos & (N_FILTHY_PROJECTION | N_FILTHY)) {
0242         if (m_d->offset.x() || m_d->offset.y()) {
0243             resultRect |= rect.translated(-m_d->offset.x(), -m_d->offset.y());
0244         }
0245 
0246         /**
0247          * KisUpdateOriginalVisitor will try to recalculate some area
0248          * on the clone's source, so this extra rectangle should also
0249          * be taken into account
0250          */
0251         resultRect |= needRectOnSourceForMasks(rect);
0252     }
0253 
0254     return resultRect;
0255 }
0256 
0257 QRect KisCloneLayer::outgoingChangeRect(const QRect &rect) const
0258 {
0259     return rect.translated(m_d->offset.x(), m_d->offset.y());
0260 }
0261 
0262 bool KisCloneLayer::accept(KisNodeVisitor & v)
0263 {
0264     return v.visit(this);
0265 }
0266 
0267 void KisCloneLayer::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter)
0268 {
0269     return visitor.visit(this, undoAdapter);
0270 }
0271 
0272 void KisCloneLayer::setCopyFrom(KisLayerSP fromLayer)
0273 {
0274     if (m_d->copyFrom) {
0275         m_d->copyFrom->unregisterClone(this);
0276     }
0277 
0278     m_d->copyFrom = fromLayer;
0279 
0280     if (m_d->copyFrom) {
0281         m_d->copyFrom->registerClone(this);
0282     }
0283 }
0284 
0285 KisLayerSP KisCloneLayer::copyFrom() const
0286 {
0287     return m_d->copyFrom;
0288 }
0289 
0290 void KisCloneLayer::setCopyType(CopyLayerType type)
0291 {
0292     m_d->type = type;
0293 }
0294 
0295 CopyLayerType KisCloneLayer::copyType() const
0296 {
0297     return m_d->type;
0298 }
0299 
0300 KisNodeUuidInfo KisCloneLayer::copyFromInfo() const
0301 {
0302     return m_d->copyFrom ? KisNodeUuidInfo(m_d->copyFrom) : m_d->copyFromInfo;
0303 }
0304 
0305 void KisCloneLayer::setCopyFromInfo(KisNodeUuidInfo info)
0306 {
0307     Q_ASSERT(!m_d->copyFrom);
0308     m_d->copyFromInfo = info;
0309 }
0310 
0311 QIcon KisCloneLayer::icon() const
0312 {
0313     return KisIconUtils::loadIcon("cloneLayer");
0314 }
0315 
0316 KisBaseNode::PropertyList KisCloneLayer::sectionModelProperties() const
0317 {
0318     KisBaseNode::PropertyList l = KisLayer::sectionModelProperties();
0319     if (m_d->copyFrom)
0320         l << KisBaseNode::Property(KoID("copy_from", i18n("Copy From")), m_d->copyFrom->name());
0321 
0322     return l;
0323 }
0324 
0325 void KisCloneLayer::syncLodCache()
0326 {
0327     KisLayer::syncLodCache();
0328     m_d->offset.syncLodOffset();
0329 }
0330