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