File indexing completed on 2024-05-12 15:58:32
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 "kis_onion_skin_cache.h" 0036 0037 struct Q_DECL_HIDDEN KisPaintLayer::Private 0038 { 0039 public: 0040 Private() : contentChannel(0) {} 0041 0042 KisPaintDeviceSP paintDevice; 0043 QBitArray paintChannelFlags; 0044 0045 // the real pointer is owned by the paint device 0046 KisRasterKeyframeChannel *contentChannel; 0047 0048 KisSignalAutoConnectionsStore onionSkinConnection; 0049 KisOnionSkinCache onionSkinCache; 0050 0051 bool onionSkinVisibleOverride = true; 0052 }; 0053 0054 KisPaintLayer::KisPaintLayer(KisImageWSP image, const QString& name, quint8 opacity, KisPaintDeviceSP dev) 0055 : KisLayer(image, name, opacity) 0056 , m_d(new Private()) 0057 { 0058 Q_ASSERT(dev); 0059 0060 init(dev); 0061 m_d->paintDevice->setDefaultBounds(new KisDefaultBounds(image)); 0062 } 0063 0064 0065 KisPaintLayer::KisPaintLayer(KisImageWSP image, const QString& name, quint8 opacity) 0066 : KisLayer(image, name, opacity) 0067 , m_d(new Private()) 0068 { 0069 Q_ASSERT(image); 0070 0071 init(new KisPaintDevice(this, image->colorSpace(), new KisDefaultBounds(image))); 0072 } 0073 0074 KisPaintLayer::KisPaintLayer(KisImageWSP image, const QString& name, quint8 opacity, const KoColorSpace * colorSpace) 0075 : KisLayer(image, name, opacity) 0076 , m_d(new Private()) 0077 { 0078 if (!colorSpace) { 0079 Q_ASSERT(image); 0080 colorSpace = image->colorSpace(); 0081 } 0082 Q_ASSERT(colorSpace); 0083 init(new KisPaintDevice(this, colorSpace, new KisDefaultBounds(image))); 0084 } 0085 0086 KisPaintLayer::KisPaintLayer(const KisPaintLayer& rhs) 0087 : KisLayer(rhs) 0088 , KisIndirectPaintingSupport() 0089 , m_d(new Private) 0090 { 0091 const bool copyFrames = (rhs.m_d->contentChannel != 0); 0092 if (!copyFrames) { 0093 init(new KisPaintDevice(*rhs.m_d->paintDevice.data()), rhs.m_d->paintChannelFlags); 0094 } else { 0095 init(new KisPaintDevice(*rhs.m_d->paintDevice.data(), KritaUtils::CopyAllFrames), rhs.m_d->paintChannelFlags); 0096 0097 m_d->contentChannel = m_d->paintDevice->keyframeChannel(); 0098 addKeyframeChannel(m_d->contentChannel); 0099 0100 m_d->contentChannel->setOnionSkinsEnabled(rhs.onionSkinEnabled()); 0101 0102 KisLayer::enableAnimation(); 0103 } 0104 } 0105 0106 void KisPaintLayer::init(KisPaintDeviceSP paintDevice, const QBitArray &paintChannelFlags) 0107 { 0108 m_d->paintDevice = paintDevice; 0109 m_d->paintDevice->setParentNode(this); 0110 0111 m_d->paintChannelFlags = paintChannelFlags; 0112 } 0113 0114 KisPaintLayer::~KisPaintLayer() 0115 { 0116 delete m_d; 0117 } 0118 0119 bool KisPaintLayer::allowAsChild(KisNodeSP node) const 0120 { 0121 return node->inherits("KisMask"); 0122 } 0123 0124 KisPaintDeviceSP KisPaintLayer::original() const 0125 { 0126 return m_d->paintDevice; 0127 } 0128 0129 KisPaintDeviceSP KisPaintLayer::paintDevice() const 0130 { 0131 return m_d->paintDevice; 0132 } 0133 0134 bool KisPaintLayer::needProjection() const 0135 { 0136 return hasTemporaryTarget() || (isAnimated() && onionSkinEnabled()); 0137 } 0138 0139 void KisPaintLayer::copyOriginalToProjection(const KisPaintDeviceSP original, 0140 KisPaintDeviceSP projection, 0141 const QRect& rect) const 0142 { 0143 KisIndirectPaintingSupport::ReadLocker l(this); 0144 0145 KisPainter::copyAreaOptimized(rect.topLeft(), original, projection, rect); 0146 0147 if (hasTemporaryTarget()) { 0148 KisPainter gc(projection); 0149 setupTemporaryPainter(&gc); 0150 gc.bitBlt(rect.topLeft(), temporaryTarget(), rect); 0151 } 0152 0153 if (m_d->contentChannel && 0154 m_d->contentChannel->keyframeCount() > 1 && 0155 onionSkinEnabled() && 0156 m_d->onionSkinVisibleOverride && 0157 !m_d->paintDevice->defaultBounds()->externalFrameActive()) { 0158 0159 KisPaintDeviceSP skins = m_d->onionSkinCache.projection(m_d->paintDevice); 0160 0161 KisPainter gcDest(projection); 0162 gcDest.setCompositeOpId(COMPOSITE_BEHIND); 0163 gcDest.bitBlt(rect.topLeft(), skins, rect); 0164 gcDest.end(); 0165 } 0166 0167 if (!m_d->contentChannel || 0168 (m_d->contentChannel->keyframeCount() <= 1) || !onionSkinEnabled()) { 0169 m_d->onionSkinCache.reset(); 0170 } 0171 } 0172 0173 QIcon KisPaintLayer::icon() const 0174 { 0175 return KisIconUtils::loadIcon("paintLayer"); 0176 } 0177 0178 void KisPaintLayer::setImage(KisImageWSP image) 0179 { 0180 m_d->paintDevice->setDefaultBounds(new KisDefaultBounds(image)); 0181 KisLayer::setImage(image); 0182 } 0183 0184 KisBaseNode::PropertyList KisPaintLayer::sectionModelProperties() const 0185 { 0186 KisBaseNode::PropertyList l = KisLayer::sectionModelProperties(); 0187 0188 l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::alphaLocked, alphaLocked()); 0189 0190 if (isAnimated()) { 0191 l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::onionSkins, onionSkinEnabled()); 0192 } 0193 0194 return l; 0195 } 0196 0197 void KisPaintLayer::setSectionModelProperties(const KisBaseNode::PropertyList &properties) 0198 { 0199 Q_FOREACH (const KisBaseNode::Property &property, properties) { 0200 if (property.name == i18n("Alpha Locked")) { 0201 setAlphaLocked(property.state.toBool()); 0202 } 0203 else if (property.name == i18n("Onion Skins")) { 0204 setOnionSkinEnabled(property.state.toBool()); 0205 } 0206 } 0207 0208 KisLayer::setSectionModelProperties(properties); 0209 } 0210 0211 bool KisPaintLayer::accept(KisNodeVisitor &v) 0212 { 0213 return v.visit(this); 0214 } 0215 0216 void KisPaintLayer::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) 0217 { 0218 return visitor.visit(this, undoAdapter); 0219 } 0220 0221 void KisPaintLayer::setChannelLockFlags(const QBitArray& channelFlags) 0222 { 0223 Q_ASSERT(((quint32)channelFlags.count() == colorSpace()->channelCount() || channelFlags.isEmpty())); 0224 m_d->paintChannelFlags = channelFlags; 0225 } 0226 0227 const QBitArray& KisPaintLayer::channelLockFlags() const 0228 { 0229 return m_d->paintChannelFlags; 0230 } 0231 0232 QRect KisPaintLayer::extent() const 0233 { 0234 KisPaintDeviceSP t = temporaryTarget(); 0235 QRect rect = t ? t->extent() : QRect(); 0236 if (onionSkinEnabled() && m_d->onionSkinVisibleOverride) rect |= KisOnionSkinCompositor::instance()->calculateExtent(m_d->paintDevice); 0237 return rect | KisLayer::extent(); 0238 } 0239 0240 QRect KisPaintLayer::exactBounds() const 0241 { 0242 KisPaintDeviceSP t = temporaryTarget(); 0243 QRect rect = t ? t->extent() : QRect(); 0244 if (onionSkinEnabled() && m_d->onionSkinVisibleOverride) rect |= KisOnionSkinCompositor::instance()->calculateExtent(m_d->paintDevice); 0245 return rect | KisLayer::exactBounds(); 0246 } 0247 0248 bool KisPaintLayer::alphaLocked() const 0249 { 0250 QBitArray flags = colorSpace()->channelFlags(false, true) & m_d->paintChannelFlags; 0251 return flags.count(true) == 0 && !m_d->paintChannelFlags.isEmpty(); 0252 } 0253 0254 void KisPaintLayer::setAlphaLocked(bool lock) 0255 { 0256 if(m_d->paintChannelFlags.isEmpty()) 0257 m_d->paintChannelFlags = colorSpace()->channelFlags(true, true); 0258 0259 if(lock) 0260 m_d->paintChannelFlags &= colorSpace()->channelFlags(true, false); 0261 else 0262 m_d->paintChannelFlags |= colorSpace()->channelFlags(false, true); 0263 0264 baseNodeChangedCallback(); 0265 } 0266 0267 bool KisPaintLayer::onionSkinEnabled() const 0268 { 0269 return nodeProperties().boolProperty("onionskin", false); 0270 } 0271 0272 void KisPaintLayer::setOnionSkinEnabled(bool state) 0273 { 0274 const auto oldState = onionSkinEnabled(); 0275 if (oldState == state) return; 0276 0277 if (!state && oldState) { 0278 // FIXME: change ordering! race condition possible! 0279 0280 // Turning off onionskins shrinks our extent. Let's clean up the onion skins first 0281 setDirty(KisOnionSkinCompositor::instance()->calculateExtent(m_d->paintDevice)); 0282 } 0283 0284 if (state) { 0285 m_d->onionSkinConnection.addConnection(KisOnionSkinCompositor::instance(), 0286 SIGNAL(sigOnionSkinChanged()), 0287 this, 0288 SLOT(slotExternalUpdateOnionSkins())); 0289 } else { 0290 m_d->onionSkinConnection.clear(); 0291 } 0292 0293 if (m_d->contentChannel) { 0294 m_d->contentChannel->setOnionSkinsEnabled(state); 0295 } 0296 0297 setNodeProperty("onionskin", state); 0298 } 0299 0300 void KisPaintLayer::flushOnionSkinCache() { 0301 m_d->onionSkinCache.reset(); 0302 } 0303 0304 void KisPaintLayer::slotExternalUpdateOnionSkins() 0305 { 0306 if (!onionSkinEnabled()) return; 0307 0308 const QRect dirtyRect = 0309 KisOnionSkinCompositor::instance()->calculateFullExtent(m_d->paintDevice); 0310 0311 setDirty(dirtyRect); 0312 } 0313 0314 KisKeyframeChannel *KisPaintLayer::requestKeyframeChannel(const QString &id) 0315 { 0316 if (id == KisKeyframeChannel::Raster.id()) { 0317 m_d->contentChannel = m_d->paintDevice->createKeyframeChannel(KisKeyframeChannel::Raster); 0318 m_d->contentChannel->setOnionSkinsEnabled(onionSkinEnabled()); 0319 enableAnimation(); 0320 return m_d->contentChannel; 0321 } 0322 0323 return KisLayer::requestKeyframeChannel(id); 0324 } 0325 0326 bool KisPaintLayer::supportsKeyframeChannel(const QString &id) 0327 { 0328 if (id == KisKeyframeChannel::Raster.id()) { 0329 return true; 0330 } 0331 0332 return KisLayer::supportsKeyframeChannel(id); 0333 } 0334 0335 KisPaintDeviceList KisPaintLayer::getLodCapableDevices() const 0336 { 0337 KisPaintDeviceList list = KisLayer::getLodCapableDevices(); 0338 0339 KisPaintDeviceSP onionSkinsDevice = m_d->onionSkinCache.lodCapableDevice(); 0340 if (onionSkinsDevice) { 0341 list << onionSkinsDevice; 0342 } 0343 0344 return list; 0345 } 0346 0347 bool KisPaintLayer::decorationsVisible() const 0348 { 0349 return m_d->onionSkinVisibleOverride; 0350 } 0351 0352 void KisPaintLayer::setDecorationsVisible(bool value, bool update) 0353 { 0354 if (value == decorationsVisible()) return; 0355 0356 const QRect oldExtent = extent(); 0357 0358 m_d->onionSkinVisibleOverride = value; 0359 0360 if (update && onionSkinEnabled()) { 0361 setDirty(oldExtent | extent()); 0362 } 0363 }