File indexing completed on 2024-05-19 04:26:26
0001 /* 0002 * SPDX-FileCopyrightText: 2005 C. Boemann <cbo@boemann.dk> 0003 * SPDX-FileCopyrightText: 2006 Bart Coppens <kde@bartcoppens.be> 0004 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org> 0005 * SPDX-FileCopyrightText: 2009 Dmitry Kazakov <dimula73@gmail.com> 0006 * 0007 * SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "kis_paint_layer.h" 0011 0012 #include <kis_debug.h> 0013 #include <klocalizedstring.h> 0014 0015 #include <KoIcon.h> 0016 #include <kis_icon.h> 0017 #include <KoColorSpace.h> 0018 #include <KoColorProfile.h> 0019 #include <KoCompositeOpRegistry.h> 0020 #include <KoProperties.h> 0021 0022 #include "kis_image.h" 0023 #include "kis_painter.h" 0024 #include "kis_paint_device.h" 0025 #include "kis_node_visitor.h" 0026 #include "kis_processing_visitor.h" 0027 #include "kis_default_bounds.h" 0028 0029 #include "kis_onion_skin_compositor.h" 0030 #include "kis_raster_keyframe_channel.h" 0031 0032 #include "kis_signal_auto_connection.h" 0033 #include "kis_layer_properties_icons.h" 0034 0035 #include "KisFrameChangeUpdateRecipe.h" 0036 #include "kis_onion_skin_cache.h" 0037 #include "kis_time_span.h" 0038 0039 0040 struct Q_DECL_HIDDEN KisPaintLayer::Private 0041 { 0042 public: 0043 Private(KisPaintLayer *_q) : q(_q), contentChannel(0) {} 0044 0045 KisPaintLayer *q; 0046 0047 KisPaintDeviceSP paintDevice; 0048 QBitArray paintChannelFlags; 0049 0050 // the real pointer is owned by the paint device 0051 KisRasterKeyframeChannel *contentChannel; 0052 0053 KisSignalAutoConnectionsStore onionSkinConnection; 0054 KisOnionSkinCache onionSkinCache; 0055 0056 bool onionSkinVisibleOverride = true; 0057 0058 [[nodiscard]] 0059 KisFrameChangeUpdateRecipe 0060 handleRasterKeyframeChannelUpdateImpl(const KisKeyframeChannel *channel, int time); 0061 }; 0062 0063 KisPaintLayer::KisPaintLayer(KisImageWSP image, const QString& name, quint8 opacity, KisPaintDeviceSP dev) 0064 : KisLayer(image, name, opacity) 0065 , m_d(new Private(this)) 0066 { 0067 Q_ASSERT(dev); 0068 0069 m_d->paintDevice = dev; 0070 m_d->paintDevice->setDefaultBounds(new KisDefaultBounds(image)); 0071 m_d->paintDevice->setSupportsWraparoundMode(true); 0072 m_d->paintDevice->setParentNode(this); 0073 } 0074 0075 0076 KisPaintLayer::KisPaintLayer(KisImageWSP image, const QString& name, quint8 opacity) 0077 : KisLayer(image, name, opacity) 0078 , m_d(new Private(this)) 0079 { 0080 Q_ASSERT(image); 0081 0082 m_d->paintDevice = new KisPaintDevice(this, image->colorSpace(), new KisDefaultBounds(image)); 0083 m_d->paintDevice->setSupportsWraparoundMode(true); 0084 } 0085 0086 KisPaintLayer::KisPaintLayer(KisImageWSP image, const QString& name, quint8 opacity, const KoColorSpace * colorSpace) 0087 : KisLayer(image, name, opacity) 0088 , m_d(new Private(this)) 0089 { 0090 if (!colorSpace) { 0091 Q_ASSERT(image); 0092 colorSpace = image->colorSpace(); 0093 } 0094 Q_ASSERT(colorSpace); 0095 m_d->paintDevice = new KisPaintDevice(this, colorSpace, new KisDefaultBounds(image)); 0096 m_d->paintDevice->setSupportsWraparoundMode(true); 0097 } 0098 0099 KisPaintLayer::KisPaintLayer(const KisPaintLayer& rhs) 0100 : KisLayer(rhs) 0101 , KisIndirectPaintingSupport() 0102 , m_d(new Private(this)) 0103 { 0104 const bool copyFrames = (rhs.m_d->contentChannel != 0); 0105 if (!copyFrames) { 0106 m_d->paintDevice = new KisPaintDevice(*rhs.m_d->paintDevice.data(), KritaUtils::CopySnapshot, this); 0107 m_d->paintDevice->setSupportsWraparoundMode(true); 0108 m_d->paintChannelFlags = rhs.m_d->paintChannelFlags; 0109 } else { 0110 m_d->paintDevice = new KisPaintDevice(*rhs.m_d->paintDevice.data(), KritaUtils::CopyAllFrames, this); 0111 m_d->paintDevice->setSupportsWraparoundMode(true); 0112 m_d->paintChannelFlags = rhs.m_d->paintChannelFlags; 0113 0114 m_d->contentChannel = m_d->paintDevice->keyframeChannel(); 0115 addKeyframeChannel(m_d->contentChannel); 0116 0117 m_d->contentChannel->setOnionSkinsEnabled(rhs.onionSkinEnabled()); 0118 0119 KisLayer::enableAnimation(); 0120 } 0121 } 0122 0123 KisPaintLayer::~KisPaintLayer() 0124 { 0125 delete m_d; 0126 } 0127 0128 bool KisPaintLayer::allowAsChild(KisNodeSP node) const 0129 { 0130 return node->inherits("KisMask"); 0131 } 0132 0133 KisPaintDeviceSP KisPaintLayer::original() const 0134 { 0135 return m_d->paintDevice; 0136 } 0137 0138 KisPaintDeviceSP KisPaintLayer::paintDevice() const 0139 { 0140 return m_d->paintDevice; 0141 } 0142 0143 bool KisPaintLayer::needProjection() const 0144 { 0145 return hasTemporaryTarget() || (isAnimated() && onionSkinEnabled()); 0146 } 0147 0148 void KisPaintLayer::copyOriginalToProjection(const KisPaintDeviceSP original, 0149 KisPaintDeviceSP projection, 0150 const QRect& rect) const 0151 { 0152 KisIndirectPaintingSupport::ReadLocker l(this); 0153 0154 KisPainter::copyAreaOptimized(rect.topLeft(), original, projection, rect); 0155 0156 if (hasTemporaryTarget()) { 0157 KisPainter gc(projection); 0158 setupTemporaryPainter(&gc); 0159 gc.bitBlt(rect.topLeft(), temporaryTarget(), rect); 0160 } 0161 0162 if (m_d->contentChannel && 0163 m_d->contentChannel->keyframeCount() > 1 && 0164 onionSkinEnabled() && 0165 m_d->onionSkinVisibleOverride && 0166 !m_d->paintDevice->defaultBounds()->externalFrameActive()) { 0167 0168 KisPaintDeviceSP skins = m_d->onionSkinCache.projection(m_d->paintDevice); 0169 0170 KisPainter gcDest(projection); 0171 gcDest.setCompositeOpId(COMPOSITE_BEHIND); 0172 gcDest.bitBlt(rect.topLeft(), skins, rect); 0173 gcDest.end(); 0174 } 0175 0176 if (!m_d->contentChannel || 0177 (m_d->contentChannel->keyframeCount() <= 1) || !onionSkinEnabled()) { 0178 m_d->onionSkinCache.reset(); 0179 } 0180 } 0181 0182 QIcon KisPaintLayer::icon() const 0183 { 0184 return KisIconUtils::loadIcon("paintLayer"); 0185 } 0186 0187 void KisPaintLayer::setImage(KisImageWSP image) 0188 { 0189 m_d->paintDevice->setDefaultBounds(new KisDefaultBounds(image)); 0190 KisLayer::setImage(image); 0191 } 0192 0193 KisBaseNode::PropertyList KisPaintLayer::sectionModelProperties() const 0194 { 0195 KisBaseNode::PropertyList l = KisLayer::sectionModelProperties(); 0196 0197 l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::alphaLocked, alphaLocked()); 0198 0199 if (isAnimated()) { 0200 l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::onionSkins, onionSkinEnabled()); 0201 } 0202 0203 return l; 0204 } 0205 0206 void KisPaintLayer::setSectionModelProperties(const KisBaseNode::PropertyList &properties) 0207 { 0208 Q_FOREACH (const KisBaseNode::Property &property, properties) { 0209 if (property.name == i18n("Alpha Locked")) { 0210 setAlphaLocked(property.state.toBool()); 0211 } 0212 else if (property.name == i18n("Onion Skins")) { 0213 setOnionSkinEnabled(property.state.toBool()); 0214 } 0215 } 0216 0217 KisLayer::setSectionModelProperties(properties); 0218 } 0219 0220 bool KisPaintLayer::accept(KisNodeVisitor &v) 0221 { 0222 return v.visit(this); 0223 } 0224 0225 void KisPaintLayer::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) 0226 { 0227 return visitor.visit(this, undoAdapter); 0228 } 0229 0230 void KisPaintLayer::setChannelLockFlags(const QBitArray& channelFlags) 0231 { 0232 Q_ASSERT(((quint32)channelFlags.count() == colorSpace()->channelCount() || channelFlags.isEmpty())); 0233 m_d->paintChannelFlags = channelFlags; 0234 } 0235 0236 const QBitArray& KisPaintLayer::channelLockFlags() const 0237 { 0238 return m_d->paintChannelFlags; 0239 } 0240 0241 QRect KisPaintLayer::extent() const 0242 { 0243 KisPaintDeviceSP t = temporaryTarget(); 0244 QRect rect = t ? t->extent() : QRect(); 0245 if (onionSkinEnabled() && m_d->onionSkinVisibleOverride) rect |= KisOnionSkinCompositor::instance()->calculateExtent(m_d->paintDevice); 0246 return rect | KisLayer::extent(); 0247 } 0248 0249 QRect KisPaintLayer::exactBounds() const 0250 { 0251 KisPaintDeviceSP t = temporaryTarget(); 0252 QRect rect = t ? t->extent() : QRect(); 0253 if (onionSkinEnabled() && m_d->onionSkinVisibleOverride) rect |= KisOnionSkinCompositor::instance()->calculateExtent(m_d->paintDevice); 0254 return rect | KisLayer::exactBounds(); 0255 } 0256 0257 bool KisPaintLayer::alphaLocked() const 0258 { 0259 QBitArray flags = colorSpace()->channelFlags(false, true) & m_d->paintChannelFlags; 0260 return flags.count(true) == 0 && !m_d->paintChannelFlags.isEmpty(); 0261 } 0262 0263 void KisPaintLayer::setAlphaLocked(bool lock) 0264 { 0265 if(m_d->paintChannelFlags.isEmpty()) 0266 m_d->paintChannelFlags = colorSpace()->channelFlags(true, true); 0267 0268 if(lock) 0269 m_d->paintChannelFlags &= colorSpace()->channelFlags(true, false); 0270 else 0271 m_d->paintChannelFlags |= colorSpace()->channelFlags(false, true); 0272 0273 baseNodeChangedCallback(); 0274 } 0275 0276 bool KisPaintLayer::onionSkinEnabled() const 0277 { 0278 return nodeProperties().boolProperty("onionskin", false); 0279 } 0280 0281 void KisPaintLayer::setOnionSkinEnabled(bool state) 0282 { 0283 const auto oldState = onionSkinEnabled(); 0284 if (oldState == state) return; 0285 0286 if (!state && oldState) { 0287 // FIXME: change ordering! race condition possible! 0288 0289 // Turning off onionskins shrinks our extent. Let's clean up the onion skins first 0290 setDirty(KisOnionSkinCompositor::instance()->calculateExtent(m_d->paintDevice)); 0291 } 0292 0293 if (state) { 0294 m_d->onionSkinConnection.addConnection(KisOnionSkinCompositor::instance(), 0295 SIGNAL(sigOnionSkinChanged()), 0296 this, 0297 SLOT(slotExternalUpdateOnionSkins())); 0298 } else { 0299 m_d->onionSkinConnection.clear(); 0300 } 0301 0302 if (m_d->contentChannel) { 0303 m_d->contentChannel->setOnionSkinsEnabled(state); 0304 } 0305 0306 setNodeProperty("onionskin", state); 0307 } 0308 0309 void KisPaintLayer::flushOnionSkinCache() { 0310 m_d->onionSkinCache.reset(); 0311 } 0312 0313 void KisPaintLayer::slotExternalUpdateOnionSkins() 0314 { 0315 if (!onionSkinEnabled()) return; 0316 0317 const QRect dirtyRect = 0318 KisOnionSkinCompositor::instance()->calculateFullExtent(m_d->paintDevice); 0319 0320 setDirty(dirtyRect); 0321 } 0322 0323 KisKeyframeChannel *KisPaintLayer::requestKeyframeChannel(const QString &id) 0324 { 0325 if (id == KisKeyframeChannel::Raster.id()) { 0326 m_d->contentChannel = m_d->paintDevice->createKeyframeChannel(KisKeyframeChannel::Raster); 0327 m_d->contentChannel->setOnionSkinsEnabled(onionSkinEnabled()); 0328 0329 enableAnimation(); 0330 return m_d->contentChannel; 0331 } 0332 0333 return KisLayer::requestKeyframeChannel(id); 0334 } 0335 0336 KisFrameChangeUpdateRecipe KisPaintLayer::Private::handleRasterKeyframeChannelUpdateImpl(const KisKeyframeChannel *channel, int time) 0337 { 0338 KisFrameChangeUpdateRecipe recipe; 0339 0340 recipe.affectedRange = channel->affectedFrames(time); 0341 recipe.affectedRect = channel->affectedRect(time); 0342 0343 KisImageWSP image = q->image(); 0344 if (image) { 0345 KisDefaultBoundsSP bounds(new KisDefaultBounds(image)); 0346 if (recipe.affectedRange.contains(bounds->currentTime())) { 0347 recipe.totalDirtyRect = recipe.affectedRect; 0348 } 0349 } 0350 0351 if (contentChannel->onionSkinsEnabled()) { 0352 recipe.totalDirtyRect |= KisOnionSkinCompositor::instance()->updateExtentOnAddition(paintDevice, time); 0353 } 0354 0355 return recipe; 0356 } 0357 0358 void KisPaintLayer::handleKeyframeChannelFrameChange(const KisKeyframeChannel *channel, int time) 0359 { 0360 if (channel->id() == KisKeyframeChannel::Raster.id()) { 0361 KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "raster channel is not supposed to emit sigKeyframeChanged"); 0362 } else { 0363 KisLayer::handleKeyframeChannelFrameChange(channel, time); 0364 } 0365 } 0366 0367 void KisPaintLayer::handleKeyframeChannelFrameAdded(const KisKeyframeChannel *channel, int time) 0368 { 0369 if (channel->id() == KisKeyframeChannel::Raster.id()) { 0370 m_d->handleRasterKeyframeChannelUpdateImpl(channel, time).notify(this); 0371 } else { 0372 KisLayer::handleKeyframeChannelFrameAdded(channel, time); 0373 } 0374 } 0375 0376 KisFrameChangeUpdateRecipe KisPaintLayer::handleKeyframeChannelFrameAboutToBeRemovedImpl(const KisKeyframeChannel *channel, int time) 0377 { 0378 if (channel->id() == KisKeyframeChannel::Raster.id()) { 0379 return m_d->handleRasterKeyframeChannelUpdateImpl(channel, time); 0380 } else { 0381 return KisLayer::handleKeyframeChannelFrameAboutToBeRemovedImpl(channel, time); 0382 } 0383 } 0384 0385 bool KisPaintLayer::supportsKeyframeChannel(const QString &id) 0386 { 0387 if (id == KisKeyframeChannel::Raster.id()) { 0388 return true; 0389 } 0390 0391 return KisLayer::supportsKeyframeChannel(id); 0392 } 0393 0394 KisPaintDeviceList KisPaintLayer::getLodCapableDevices() const 0395 { 0396 KisPaintDeviceList list = KisLayer::getLodCapableDevices(); 0397 0398 KisPaintDeviceSP onionSkinsDevice = m_d->onionSkinCache.lodCapableDevice(); 0399 if (onionSkinsDevice) { 0400 list << onionSkinsDevice; 0401 } 0402 0403 return list; 0404 } 0405 0406 bool KisPaintLayer::decorationsVisible() const 0407 { 0408 return m_d->onionSkinVisibleOverride; 0409 } 0410 0411 void KisPaintLayer::setDecorationsVisible(bool value, bool update) 0412 { 0413 if (value == decorationsVisible()) return; 0414 0415 const QRect oldExtent = extent(); 0416 0417 m_d->onionSkinVisibleOverride = value; 0418 0419 if (update && onionSkinEnabled()) { 0420 setDirty(oldExtent | extent()); 0421 } 0422 }