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

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     m_d->offset.setDefaultBounds(new KisDefaultBounds(image));
0106     KisLayer::setImage(image);
0107 }
0108 
0109 bool KisCloneLayer::allowAsChild(KisNodeSP node) const
0110 {
0111     return node->inherits("KisMask");
0112 }
0113 
0114 KisPaintDeviceSP KisCloneLayer::paintDevice() const
0115 {
0116     return 0;
0117 }
0118 
0119 KisPaintDeviceSP KisCloneLayer::original() const
0120 {
0121     if (!m_d->copyFrom || !m_d->copyFrom->projection()) return m_d->fallback;
0122     KisPaintDeviceSP retval;
0123     switch (m_d->type) {
0124     case COPY_PROJECTION:
0125         retval = m_d->copyFrom->projection();
0126         break;
0127 
0128     case COPY_ORIGINAL:
0129     default:
0130         retval = m_d->copyFrom->original();
0131     }
0132 
0133     return retval;
0134 }
0135 
0136 bool KisCloneLayer::needProjection() const
0137 {
0138     return m_d->offset->x() || m_d->offset->y();
0139 }
0140 
0141 const KoColorSpace *KisCloneLayer::colorSpace() const
0142 {
0143     return m_d->copyFrom ? m_d->copyFrom->colorSpace() : m_d->fallback->colorSpace();
0144 }
0145 
0146 void KisCloneLayer::copyOriginalToProjection(const KisPaintDeviceSP original,
0147         KisPaintDeviceSP projection,
0148         const QRect& rect) const
0149 {
0150     QRect copyRect = rect;
0151     copyRect.translate(-m_d->offset->x(), -m_d->offset->y());
0152 
0153     KisPainter::copyAreaOptimized(rect.topLeft(), original, projection, copyRect);
0154 }
0155 
0156 void KisCloneLayer::setDirtyOriginal(const QRect &rect)
0157 {
0158     /**
0159      * The original will be updated when the clone becomes visible
0160      * again.
0161      */
0162     if (!visible(true)) return;
0163 
0164     /**
0165      *  HINT: this method is present for historical reasons only.
0166      *        Long time ago the updates were calculated in
0167      *        "copyOriginalToProjection" coordinate system. Now
0168      *        everything is done in "original()" space.
0169      */
0170     KisLayer::setDirty(rect);
0171 }
0172 
0173 void KisCloneLayer::notifyParentVisibilityChanged(bool value)
0174 {
0175     KisImageSP imageSP = image().toStrongRef();
0176     if (!imageSP) {
0177         return;
0178     }
0179     KisLayer::setDirty(imageSP->bounds());
0180     KisLayer::notifyParentVisibilityChanged(value);
0181 }
0182 
0183 QRect KisCloneLayer::needRectOnSourceForMasks(const QRect &rc) const
0184 {
0185     QStack<QRect> applyRects_unused;
0186     bool rectVariesFlag;
0187 
0188     QList<KisEffectMaskSP> effectMasks = this->effectMasks();
0189     if (effectMasks.isEmpty()) return QRect();
0190 
0191     QRect needRect = this->masksNeedRect(effectMasks,
0192                                          rc,
0193                                          applyRects_unused,
0194                                          rectVariesFlag);
0195 
0196     if (needRect.isEmpty() ||
0197         (!rectVariesFlag && needRect == rc)) {
0198 
0199         return QRect();
0200     }
0201 
0202     return needRect;
0203 }
0204 
0205 qint32 KisCloneLayer::x() const
0206 {
0207     return m_d->offset->x();
0208 }
0209 qint32 KisCloneLayer::y() const
0210 {
0211     return m_d->offset->y();
0212 }
0213 void KisCloneLayer::setX(qint32 x)
0214 {
0215     m_d->offset->setX(x);
0216 }
0217 void KisCloneLayer::setY(qint32 y)
0218 {
0219     m_d->offset->setY(y);
0220 }
0221 
0222 QRect KisCloneLayer::extent() const
0223 {
0224     QRect rect = original()->extent();
0225 
0226     // HINT: no offset now. See a comment in setDirtyOriginal()
0227     return rect | projection()->extent();
0228 }
0229 
0230 QRect KisCloneLayer::exactBounds() const
0231 {
0232     QRect rect = original()->exactBounds();
0233 
0234     // HINT: no offset now. See a comment in setDirtyOriginal()
0235     return rect | projection()->exactBounds();
0236 }
0237 
0238 QRect KisCloneLayer::accessRect(const QRect &rect, PositionToFilthy pos) const
0239 {
0240     QRect resultRect = rect;
0241 
0242     if(pos & (N_FILTHY_PROJECTION | N_FILTHY)) {
0243         if (m_d->offset->x() || m_d->offset->y()) {
0244             resultRect |= rect.translated(-m_d->offset->x(), -m_d->offset->y());
0245         }
0246 
0247         /**
0248          * KisUpdateOriginalVisitor will try to recalculate some area
0249          * on the clone's source, so this extra rectangle should also
0250          * be taken into account
0251          */
0252         resultRect |= needRectOnSourceForMasks(rect);
0253     }
0254 
0255     return resultRect;
0256 }
0257 
0258 QRect KisCloneLayer::outgoingChangeRect(const QRect &rect) const
0259 {
0260     return rect.translated(m_d->offset->x(), m_d->offset->y());
0261 }
0262 
0263 bool KisCloneLayer::accept(KisNodeVisitor & v)
0264 {
0265     return v.visit(this);
0266 }
0267 
0268 void KisCloneLayer::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter)
0269 {
0270     return visitor.visit(this, undoAdapter);
0271 }
0272 
0273 void KisCloneLayer::setCopyFrom(KisLayerSP fromLayer)
0274 {
0275     if (m_d->copyFrom) {
0276         m_d->copyFrom->unregisterClone(this);
0277     }
0278 
0279     m_d->copyFrom = fromLayer;
0280 
0281     if (m_d->copyFrom) {
0282         m_d->copyFrom->registerClone(this);
0283     }
0284 }
0285 
0286 KisLayerSP KisCloneLayer::copyFrom() const
0287 {
0288     return m_d->copyFrom;
0289 }
0290 
0291 void KisCloneLayer::setCopyType(CopyLayerType type)
0292 {
0293     m_d->type = type;
0294 }
0295 
0296 CopyLayerType KisCloneLayer::copyType() const
0297 {
0298     return m_d->type;
0299 }
0300 
0301 KisNodeUuidInfo KisCloneLayer::copyFromInfo() const
0302 {
0303     return m_d->copyFrom ? KisNodeUuidInfo(m_d->copyFrom) : m_d->copyFromInfo;
0304 }
0305 
0306 void KisCloneLayer::setCopyFromInfo(KisNodeUuidInfo info)
0307 {
0308     Q_ASSERT(!m_d->copyFrom);
0309     m_d->copyFromInfo = info;
0310 }
0311 
0312 QIcon KisCloneLayer::icon() const
0313 {
0314     return KisIconUtils::loadIcon("cloneLayer");
0315 }
0316 
0317 KisBaseNode::PropertyList KisCloneLayer::sectionModelProperties() const
0318 {
0319     KisBaseNode::PropertyList l = KisLayer::sectionModelProperties();
0320     if (m_d->copyFrom)
0321         l << KisBaseNode::Property(KoID("copy_from", i18n("Copy From")), m_d->copyFrom->name());
0322 
0323     return l;
0324 }
0325 
0326 void KisCloneLayer::syncLodCache()
0327 {
0328     KisLayer::syncLodCache();
0329     m_d->offset.syncLodCache();
0330 }
0331