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