File indexing completed on 2024-05-12 15:58:18
0001 /* 0002 * SPDX-FileCopyrightText: 2005 C. Boemann <cbo@boemann.dk> 0003 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org> 0004 * SPDX-FileCopyrightText: 2009 Dmitry Kazakov <dimula73@gmail.com> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "kis_group_layer.h" 0010 0011 #include <KoIcon.h> 0012 #include <kis_icon.h> 0013 #include <KoCompositeOpRegistry.h> 0014 #include <KoColorSpace.h> 0015 #include <KoColor.h> 0016 0017 0018 #include "kis_node_visitor.h" 0019 #include "kis_processing_visitor.h" 0020 #include "kis_debug.h" 0021 #include "kis_image.h" 0022 #include "kis_paint_device.h" 0023 #include "kis_default_bounds.h" 0024 #include "kis_clone_layer.h" 0025 #include "kis_selection_mask.h" 0026 #include "kis_psd_layer_style.h" 0027 #include "kis_layer_properties_icons.h" 0028 0029 0030 struct Q_DECL_HIDDEN KisGroupLayer::Private 0031 { 0032 public: 0033 Private() 0034 : paintDevice(0) 0035 , x(0) 0036 , y(0) 0037 , passThroughMode(false) 0038 { 0039 } 0040 0041 KisPaintDeviceSP paintDevice; 0042 qint32 x; 0043 qint32 y; 0044 bool passThroughMode; 0045 0046 std::tuple<KisPaintDeviceSP, bool> originalImpl() const; 0047 }; 0048 0049 KisGroupLayer::KisGroupLayer(KisImageWSP image, const QString &name, quint8 opacity) : 0050 KisLayer(image, name, opacity), 0051 m_d(new Private()) 0052 { 0053 resetCache(); 0054 } 0055 0056 KisGroupLayer::KisGroupLayer(const KisGroupLayer &rhs) : 0057 KisLayer(rhs), 0058 m_d(new Private()) 0059 { 0060 m_d->paintDevice = new KisPaintDevice(*rhs.m_d->paintDevice.data()); 0061 m_d->x = rhs.m_d->x; 0062 m_d->y = rhs.m_d->y; 0063 m_d->paintDevice->setDefaultPixel(const_cast<KisGroupLayer*>(&rhs)->m_d->paintDevice->defaultPixel()); 0064 m_d->paintDevice->setProjectionDevice(true); 0065 m_d->passThroughMode = rhs.passThroughMode(); 0066 } 0067 0068 KisGroupLayer::~KisGroupLayer() 0069 { 0070 delete m_d; 0071 } 0072 0073 bool KisGroupLayer::checkCloneLayer(KisCloneLayerSP clone) const 0074 { 0075 KisNodeSP source = clone->copyFrom(); 0076 if (source) { 0077 if(!allowAsChild(source)) return false; 0078 0079 if (source->inherits("KisGroupLayer")) { 0080 KisNodeSP newParent = const_cast<KisGroupLayer*>(this); 0081 while (newParent) { 0082 if (newParent == source) { 0083 return false; 0084 } 0085 newParent = newParent->parent(); 0086 } 0087 } 0088 } 0089 0090 return true; 0091 } 0092 0093 bool KisGroupLayer::checkNodeRecursively(KisNodeSP node) const 0094 { 0095 KisCloneLayerSP cloneLayer = dynamic_cast<KisCloneLayer*>(node.data()); 0096 if(cloneLayer) { 0097 return checkCloneLayer(cloneLayer); 0098 } 0099 else if (node->inherits("KisGroupLayer")) { 0100 KisNodeSP child = node->firstChild(); 0101 while (child) { 0102 if (!checkNodeRecursively(child)) { 0103 return false; 0104 } 0105 child = child->nextSibling(); 0106 } 0107 } 0108 0109 return true; 0110 } 0111 0112 bool KisGroupLayer::allowAsChild(KisNodeSP node) const 0113 { 0114 if (!checkNodeRecursively(node)) return false; 0115 0116 if (!parent()) { 0117 // We are the root layer, so we need to check 0118 // whether the node that's going to be added is 0119 // a selection mask; that is only allowed if 0120 // there isn't a global selection. See 0121 // BUG:294905 0122 0123 if (node->inherits("KisSelectionMask")) { 0124 return !qobject_cast<KisSelectionMask*>(node.data())->active() || !selectionMask(); 0125 } 0126 0127 KisImageSP image = this->image(); 0128 0129 if (!image || !image->allowMasksOnRootNode()) { 0130 if (node->inherits("KisMask")) { 0131 return false; 0132 } 0133 } 0134 } 0135 0136 return checkNodeRecursively(node); 0137 0138 } 0139 0140 const KoColorSpace * KisGroupLayer::colorSpace() const 0141 { 0142 return m_d->paintDevice->colorSpace(); 0143 } 0144 0145 QIcon KisGroupLayer::icon() const 0146 { 0147 return KisIconUtils::loadIcon("groupLayer"); 0148 } 0149 0150 void KisGroupLayer::setImage(KisImageWSP image) 0151 { 0152 m_d->paintDevice->setDefaultBounds(new KisDefaultBounds(image)); 0153 KisLayer::setImage(image); 0154 } 0155 0156 KisLayerSP KisGroupLayer::createMergedLayerTemplate(KisLayerSP prevLayer) 0157 { 0158 KisGroupLayer *prevGroup = dynamic_cast<KisGroupLayer*>(prevLayer.data()); 0159 0160 if (prevGroup && canMergeAndKeepBlendOptions(prevLayer)) { 0161 KisSharedPtr<KisGroupLayer> merged(new KisGroupLayer(*prevGroup)); 0162 0163 KisNodeSP child, cloned; 0164 0165 for (child = firstChild(); child; child = child->nextSibling()) { 0166 cloned = child->clone(); 0167 image()->addNode(cloned, merged); 0168 } 0169 0170 if (!merged->passThroughMode()) { 0171 image()->refreshGraphAsync(merged); 0172 } 0173 0174 return merged; 0175 } else 0176 return KisLayer::createMergedLayerTemplate(prevLayer); 0177 } 0178 0179 void KisGroupLayer::fillMergedLayerTemplate(KisLayerSP dstLayer, KisLayerSP prevLayer) 0180 { 0181 if (!dynamic_cast<KisGroupLayer*>(dstLayer.data())) { 0182 KisLayer::fillMergedLayerTemplate(dstLayer, prevLayer); 0183 } 0184 } 0185 0186 void KisGroupLayer::resetCache(const KoColorSpace *colorSpace) 0187 { 0188 if (!colorSpace) 0189 colorSpace = image()->colorSpace(); 0190 0191 Q_ASSERT(colorSpace); 0192 0193 if (!m_d->paintDevice) { 0194 0195 KisPaintDeviceSP dev = new KisPaintDevice(this, colorSpace, new KisDefaultBounds(image())); 0196 dev->setX(this->x()); 0197 dev->setY(this->y()); 0198 m_d->paintDevice = dev; 0199 m_d->paintDevice->setProjectionDevice(true); 0200 } 0201 else if(*m_d->paintDevice->colorSpace() != *colorSpace) { 0202 0203 m_d->paintDevice->clear(); 0204 m_d->paintDevice->convertTo(colorSpace); 0205 0206 } else { 0207 0208 m_d->paintDevice->clear(); 0209 } 0210 } 0211 0212 KisLayer* KisGroupLayer::onlyMeaningfulChild() const 0213 { 0214 KisNode *child = firstChild().data(); 0215 KisLayer *onlyLayer = 0; 0216 0217 while (child) { 0218 KisLayer *layer = qobject_cast<KisLayer*>(child); 0219 if (layer && !layer->isFakeNode()) { 0220 if (onlyLayer) return 0; 0221 onlyLayer = layer; 0222 } 0223 child = child->nextSibling().data(); 0224 } 0225 0226 return onlyLayer; 0227 } 0228 0229 KisPaintDeviceSP KisGroupLayer::tryObligeChild() const 0230 { 0231 KisLayer *child = onlyMeaningfulChild(); 0232 0233 if (child) { 0234 KisPaintDeviceSP projection = child->projection(); 0235 if (child->channelFlags().isEmpty() && 0236 projection && 0237 child->visible() && 0238 (child->compositeOpId() == COMPOSITE_OVER || 0239 child->compositeOpId() == COMPOSITE_ALPHA_DARKEN || 0240 child->compositeOpId() == COMPOSITE_COPY) && 0241 child->opacity() == OPACITY_OPAQUE_U8 && 0242 *projection->colorSpace() == *colorSpace() && 0243 !child->layerStyle()) { 0244 0245 quint8 defaultOpacity = 0246 m_d->paintDevice->defaultPixel().opacityU8(); 0247 0248 if(defaultOpacity == OPACITY_TRANSPARENT_U8) { 0249 return projection; 0250 } 0251 } 0252 } 0253 0254 return 0; 0255 } 0256 0257 std::tuple<KisPaintDeviceSP, bool> KisGroupLayer::originalImpl() const 0258 { 0259 /** 0260 * We are too lazy! Let's our children work for us. 0261 * Try to use children's paintDevice if it's the only 0262 * one in stack and meets some conditions 0263 */ 0264 KisPaintDeviceSP realOriginal = tryObligeChild(); 0265 bool ownsOriginal = false; 0266 0267 if (!realOriginal) { 0268 if (!childCount() && !m_d->paintDevice->extent().isEmpty()) { 0269 m_d->paintDevice->clear(); 0270 } 0271 realOriginal = m_d->paintDevice; 0272 ownsOriginal = true; 0273 } 0274 0275 return std::make_tuple(realOriginal, ownsOriginal); 0276 } 0277 0278 KisPaintDeviceSP KisGroupLayer::original() const 0279 { 0280 return std::get<0>(originalImpl()); 0281 } 0282 0283 KisPaintDeviceSP KisGroupLayer::lazyDestinationForSubtreeComposition() const 0284 { 0285 KisPaintDeviceSP originalDev; 0286 bool ownsOriginal = false; 0287 std::tie(originalDev, ownsOriginal) = originalImpl(); 0288 0289 return ownsOriginal ? originalDev : nullptr; 0290 } 0291 0292 QRect KisGroupLayer::amortizedProjectionRectForCleanupInChangePass() const 0293 { 0294 return hasEffectMasks() ? projection()->exactBoundsAmortized() : m_d->paintDevice->exactBoundsAmortized(); 0295 } 0296 0297 KisPaintDeviceSP KisGroupLayer::paintDevice() const 0298 { 0299 return 0; 0300 } 0301 0302 bool KisGroupLayer::projectionIsValid() const 0303 { 0304 return !tryObligeChild(); 0305 } 0306 0307 void KisGroupLayer::setDefaultProjectionColor(KoColor color) 0308 { 0309 m_d->paintDevice->setDefaultPixel(color); 0310 } 0311 0312 KoColor KisGroupLayer::defaultProjectionColor() const 0313 { 0314 KoColor color(m_d->paintDevice->defaultPixel(), m_d->paintDevice->colorSpace()); 0315 return color; 0316 } 0317 0318 bool KisGroupLayer::passThroughMode() const 0319 { 0320 return m_d->passThroughMode; 0321 } 0322 0323 void KisGroupLayer::setPassThroughMode(bool value) 0324 { 0325 if (m_d->passThroughMode == value) return; 0326 0327 m_d->passThroughMode = value; 0328 if (m_d->passThroughMode) { 0329 resetCache(colorSpace()); 0330 } 0331 baseNodeChangedCallback(); 0332 baseNodeInvalidateAllFramesCallback(); 0333 notifyChildMaskChanged(); 0334 } 0335 0336 KisBaseNode::PropertyList KisGroupLayer::sectionModelProperties() const 0337 { 0338 KisBaseNode::PropertyList l = KisLayer::sectionModelProperties(); 0339 0340 l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::passThrough, passThroughMode()); 0341 0342 return l; 0343 } 0344 0345 void KisGroupLayer::setSectionModelProperties(const KisBaseNode::PropertyList &properties) 0346 { 0347 Q_FOREACH (const KisBaseNode::Property &property, properties) { 0348 if (property.name == i18n("Pass Through")) { 0349 setPassThroughMode(property.state.toBool()); 0350 } 0351 } 0352 0353 KisLayer::setSectionModelProperties(properties); 0354 } 0355 0356 bool KisGroupLayer::accept(KisNodeVisitor &v) 0357 { 0358 return v.visit(this); 0359 } 0360 0361 void KisGroupLayer::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) 0362 { 0363 return visitor.visit(this, undoAdapter); 0364 } 0365 0366 qint32 KisGroupLayer::x() const 0367 { 0368 return m_d->paintDevice ? m_d->paintDevice->x() : m_d->x; 0369 } 0370 0371 qint32 KisGroupLayer::y() const 0372 { 0373 return m_d->paintDevice ? m_d->paintDevice->y() : m_d->y; 0374 } 0375 0376 void KisGroupLayer::setX(qint32 x) 0377 { 0378 m_d->x = x; 0379 if(m_d->paintDevice) { 0380 m_d->paintDevice->setX(x); 0381 } 0382 } 0383 0384 void KisGroupLayer::setY(qint32 y) 0385 { 0386 m_d->y = y; 0387 if(m_d->paintDevice) { 0388 m_d->paintDevice->setY(y); 0389 } 0390 } 0391 0392 struct ExtentPolicy 0393 { 0394 inline QRect operator() (const KisNode *node) { 0395 return node->extent(); 0396 } 0397 }; 0398 0399 struct ExactBoundsPolicy 0400 { 0401 inline QRect operator() (const KisNode *node) { 0402 return node->exactBounds(); 0403 } 0404 }; 0405 0406 template <class MetricPolicy> 0407 QRect collectRects(const KisNode *node, MetricPolicy policy) 0408 { 0409 QRect accumulator; 0410 0411 const KisNode *child = node->firstChild(); 0412 while (child) { 0413 if (!qobject_cast<const KisMask*>(child)) { 0414 accumulator |= policy(child); 0415 } 0416 child = child->nextSibling(); 0417 } 0418 0419 return accumulator; 0420 } 0421 0422 QRect KisGroupLayer::extent() const 0423 { 0424 return m_d->passThroughMode ? 0425 collectRects(this, ExtentPolicy()) : 0426 KisLayer::extent(); 0427 } 0428 0429 QRect KisGroupLayer::exactBounds() const 0430 { 0431 return m_d->passThroughMode ? 0432 collectRects(this, ExactBoundsPolicy()) : 0433 KisLayer::exactBounds(); 0434 }