File indexing completed on 2024-05-12 15:58:37
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_projection_leaf.h" 0008 0009 #include <KoColorSpace.h> 0010 0011 #include "kis_layer.h" 0012 #include "kis_image.h" 0013 #include "kis_mask.h" 0014 #include "kis_group_layer.h" 0015 #include "kis_selection_mask.h" 0016 #include "kis_adjustment_layer.h" 0017 0018 #include "krita_utils.h" 0019 0020 #include "kis_refresh_subtree_walker.h" 0021 #include "kis_async_merger.h" 0022 #include "kis_node_graph_listener.h" 0023 #include "kis_clone_layer.h" 0024 0025 0026 struct Q_DECL_HIDDEN KisProjectionLeaf::Private 0027 { 0028 Private(KisNode *_node) : node(_node) {} 0029 0030 KisNodeWSP node; 0031 bool isTemporaryHidden = false; 0032 0033 static bool checkPassThrough(const KisNode *node) { 0034 const KisGroupLayer *group = qobject_cast<const KisGroupLayer*>(node); 0035 return group && group->passThroughMode(); 0036 } 0037 0038 static bool isSelectionMask(const KisNode *node) { 0039 return qobject_cast<const KisSelectionMask*>(node); 0040 } 0041 0042 static KisNodeSP skipSelectionMasksForward(KisNodeSP node) { 0043 while (node && isSelectionMask(node)) { 0044 node = node->nextSibling(); 0045 } 0046 return node; 0047 } 0048 0049 static KisNodeSP skipSelectionMasksBackward(KisNodeSP node) { 0050 while (node && isSelectionMask(node)) { 0051 node = node->prevSibling(); 0052 } 0053 return node; 0054 } 0055 0056 bool checkParentPassThrough() { 0057 return node->parent() && checkPassThrough(node->parent()); 0058 } 0059 0060 bool checkThisPassThrough() { 0061 return checkPassThrough(node); 0062 } 0063 0064 KisProjectionLeafSP overlayProjectionLeaf() const { 0065 return node && node->graphListener() && node->graphListener()->graphOverlayNode() ? 0066 node->graphListener()->graphOverlayNode()->projectionLeaf() : 0; 0067 } 0068 0069 bool isTopmostNode() const { 0070 return !skipSelectionMasksForward(node->nextSibling()) && 0071 node->parent() && 0072 !node->parent()->parent(); 0073 } 0074 0075 KisNodeSP findRoot() const { 0076 KisNodeSP root = node; 0077 0078 while (root->parent()) { 0079 root = root->parent(); 0080 } 0081 0082 return root; 0083 } 0084 0085 void temporarySetPassThrough(bool value) { 0086 KisGroupLayer *group = qobject_cast<KisGroupLayer*>(node.data()); 0087 if (!group) return; 0088 0089 group->setPassThroughMode(value); 0090 } 0091 }; 0092 0093 KisProjectionLeaf::KisProjectionLeaf(KisNode *node) 0094 : m_d(new Private(node)) 0095 { 0096 } 0097 0098 KisProjectionLeaf::~KisProjectionLeaf() 0099 { 0100 } 0101 0102 KisProjectionLeafSP KisProjectionLeaf::parent() const 0103 { 0104 KisNodeSP node; 0105 0106 if (Private::isSelectionMask(m_d->node)) { 0107 if (m_d->overlayProjectionLeaf() == this) { 0108 node = m_d->findRoot(); 0109 } 0110 } else { 0111 node = m_d->node->parent(); 0112 } 0113 0114 while (node && Private::checkPassThrough(node)) { 0115 node = node->parent(); 0116 } 0117 0118 return node ? node->projectionLeaf() : KisProjectionLeafSP(); 0119 } 0120 0121 0122 KisProjectionLeafSP KisProjectionLeaf::firstChild() const 0123 { 0124 KisNodeSP node; 0125 0126 if (!m_d->checkThisPassThrough()) { 0127 node = m_d->node->firstChild(); 0128 node = Private::skipSelectionMasksForward(node); 0129 } 0130 0131 if (!node && isRoot()) { 0132 KisProjectionLeafSP overlayLeaf = m_d->overlayProjectionLeaf(); 0133 if (overlayLeaf) { 0134 return overlayLeaf; 0135 } 0136 } 0137 0138 return node ? node->projectionLeaf() : KisProjectionLeafSP(); 0139 } 0140 0141 KisProjectionLeafSP KisProjectionLeaf::lastChild() const 0142 { 0143 KisNodeSP node; 0144 0145 if (isRoot()) { 0146 KisProjectionLeafSP overlayLeaf = m_d->overlayProjectionLeaf(); 0147 if (overlayLeaf) { 0148 return overlayLeaf; 0149 } 0150 } 0151 0152 if (!m_d->checkThisPassThrough()) { 0153 node = m_d->node->lastChild(); 0154 node = Private::skipSelectionMasksBackward(node); 0155 } 0156 0157 return node ? node->projectionLeaf() : KisProjectionLeafSP(); 0158 } 0159 0160 KisProjectionLeafSP KisProjectionLeaf::prevSibling() const 0161 { 0162 if (Private::isSelectionMask(m_d->node)) { 0163 KisProjectionLeafSP leaf; 0164 0165 if (m_d->overlayProjectionLeaf() == this) { 0166 KisNodeSP node = m_d->findRoot()->lastChild(); 0167 node = Private::skipSelectionMasksBackward(node); 0168 leaf = node->projectionLeaf(); 0169 } 0170 0171 return leaf; 0172 } 0173 0174 KisNodeSP node; 0175 0176 if (m_d->checkThisPassThrough()) { 0177 node = m_d->node->lastChild(); 0178 node = Private::skipSelectionMasksBackward(node); 0179 } 0180 0181 if (!node) { 0182 node = m_d->node->prevSibling(); 0183 node = Private::skipSelectionMasksBackward(node); 0184 } 0185 0186 const KisProjectionLeaf *leaf = this; 0187 while (!node && leaf->m_d->checkParentPassThrough()) { 0188 leaf = leaf->node()->parent()->projectionLeaf().data(); 0189 node = leaf->node()->prevSibling(); 0190 node = Private::skipSelectionMasksBackward(node); 0191 } 0192 0193 return node ? node->projectionLeaf() : KisProjectionLeafSP(); 0194 } 0195 0196 KisProjectionLeafSP KisProjectionLeaf::nextSibling() const 0197 { 0198 if (Private::isSelectionMask(m_d->node)) { 0199 return KisProjectionLeafSP(); 0200 } 0201 0202 KisProjectionLeafSP overlayLeaf = m_d->overlayProjectionLeaf(); 0203 if (overlayLeaf && m_d->isTopmostNode()) { 0204 return overlayLeaf; 0205 } 0206 0207 KisNodeSP node = m_d->node->nextSibling(); 0208 node = Private::skipSelectionMasksForward(node); 0209 0210 while (node && Private::checkPassThrough(node) && node->firstChild()) { 0211 node = node->firstChild(); 0212 node = Private::skipSelectionMasksForward(node); 0213 } 0214 0215 if (!node && m_d->checkParentPassThrough()) { 0216 node = m_d->node->parent(); 0217 node = Private::skipSelectionMasksForward(node); 0218 } 0219 0220 return node ? node->projectionLeaf() : KisProjectionLeafSP(); 0221 } 0222 0223 KisNodeSP KisProjectionLeaf::node() const 0224 { 0225 return m_d->node; 0226 } 0227 0228 KisAbstractProjectionPlaneSP KisProjectionLeaf::projectionPlane() const 0229 { 0230 return m_d->node->projectionPlane(); 0231 } 0232 0233 bool KisProjectionLeaf::accept(KisNodeVisitor &visitor) 0234 { 0235 return m_d->node->accept(visitor); 0236 } 0237 0238 KisPaintDeviceSP KisProjectionLeaf::original() 0239 { 0240 return m_d->node->original(); 0241 } 0242 0243 KisPaintDeviceSP KisProjectionLeaf::projection() 0244 { 0245 return m_d->node->projection(); 0246 } 0247 0248 KisPaintDeviceSP KisProjectionLeaf::lazyDestinationForSubtreeComposition() 0249 { 0250 const KisGroupLayer *group = qobject_cast<const KisGroupLayer*>(m_d->node.data()); 0251 return group ? group->lazyDestinationForSubtreeComposition() : nullptr; 0252 } 0253 0254 bool KisProjectionLeaf::isRoot() const 0255 { 0256 return (bool)!m_d->node->parent(); 0257 } 0258 0259 bool KisProjectionLeaf::isLayer() const 0260 { 0261 return (bool)qobject_cast<const KisLayer*>(m_d->node.data()) && 0262 !m_d->node->isFakeNode(); 0263 } 0264 0265 bool KisProjectionLeaf::isMask() const 0266 { 0267 return (bool)qobject_cast<const KisMask*>(m_d->node.data()) && 0268 !m_d->node->isFakeNode(); 0269 } 0270 0271 bool KisProjectionLeaf::canHaveChildLayers() const 0272 { 0273 return (bool)qobject_cast<const KisGroupLayer*>(m_d->node.data()); 0274 } 0275 0276 bool KisProjectionLeaf::dependsOnLowerNodes() const 0277 { 0278 return (bool)qobject_cast<const KisAdjustmentLayer*>(m_d->node.data()); 0279 } 0280 0281 bool KisProjectionLeaf::visible() const 0282 { 0283 if (m_d->isTemporaryHidden || isDroppedNode()) return false; 0284 0285 // TODO: check opacity as well! 0286 0287 bool hiddenByParentPassThrough = false; 0288 0289 KisNodeSP node = m_d->node->parent(); 0290 while (node && node->projectionLeaf()->m_d->checkThisPassThrough()) { 0291 hiddenByParentPassThrough |= !node->visible(); 0292 node = node->parent(); 0293 } 0294 0295 return (m_d->node->visible(false) || m_d->node->isIsolatedRoot()) && 0296 !m_d->checkThisPassThrough() && 0297 !hiddenByParentPassThrough; 0298 } 0299 0300 quint8 KisProjectionLeaf::opacity() const 0301 { 0302 quint8 resultOpacity = m_d->node->opacity(); 0303 0304 if (m_d->checkParentPassThrough()) { 0305 quint8 parentOpacity = m_d->node->parent()->projectionLeaf()->opacity(); 0306 0307 resultOpacity = KritaUtils::mergeOpacity(resultOpacity, parentOpacity); 0308 } 0309 0310 return resultOpacity; 0311 } 0312 0313 QBitArray KisProjectionLeaf::channelFlags() const 0314 { 0315 QBitArray channelFlags; 0316 0317 KisLayer *layer = qobject_cast<KisLayer*>(m_d->node.data()); 0318 if (!layer) return channelFlags; 0319 0320 channelFlags = layer->channelFlags(); 0321 0322 if (m_d->checkParentPassThrough()) { 0323 QBitArray parentChannelFlags; 0324 0325 if (*m_d->node->colorSpace() == 0326 *m_d->node->parent()->colorSpace()) { 0327 0328 KisLayer *parentLayer = qobject_cast<KisLayer*>(m_d->node->parent().data()); 0329 parentChannelFlags = parentLayer->channelFlags(); 0330 } 0331 0332 channelFlags = KritaUtils::mergeChannelFlags(channelFlags, parentChannelFlags); 0333 } 0334 0335 return channelFlags; 0336 } 0337 0338 bool KisProjectionLeaf::isStillInGraph() const 0339 { 0340 return (bool)m_d->node->graphListener(); 0341 } 0342 0343 bool KisProjectionLeaf::hasClones() const 0344 { 0345 KisLayer *layer = qobject_cast<KisLayer*>(m_d->node.data()); 0346 return layer ? layer->hasClones() : false; 0347 } 0348 0349 bool KisProjectionLeaf::isDroppedNode() const 0350 { 0351 return dropReason() != NodeAvailable; 0352 } 0353 0354 bool KisProjectionLeaf::shouldBeRendered() const 0355 { 0356 return visible() || hasClones(); 0357 } 0358 0359 KisProjectionLeaf::NodeDropReason KisProjectionLeaf::dropReason() const 0360 { 0361 if (qobject_cast<KisMask*>(m_d->node.data()) && 0362 m_d->checkParentPassThrough()) { 0363 0364 return DropPassThroughMask; 0365 } 0366 0367 KisCloneLayer *cloneLayer = qobject_cast<KisCloneLayer*>(m_d->node.data()); 0368 if (cloneLayer && cloneLayer->copyFrom()) { 0369 KisProjectionLeafSP leaf = cloneLayer->copyFrom()->projectionLeaf(); 0370 0371 if (leaf->m_d->checkThisPassThrough()) { 0372 return DropPassThroughClone; 0373 } 0374 } 0375 0376 return NodeAvailable; 0377 } 0378 0379 bool KisProjectionLeaf::isOverlayProjectionLeaf() const 0380 { 0381 return this == m_d->overlayProjectionLeaf(); 0382 } 0383 0384 void KisProjectionLeaf::setTemporaryHiddenFromRendering(bool value) 0385 { 0386 m_d->isTemporaryHidden = value; 0387 } 0388 0389 bool KisProjectionLeaf::isTemporaryHiddenFromRendering() const 0390 { 0391 return m_d->isTemporaryHidden; 0392 } 0393 0394 /** 0395 * This method is rather slow and dangerous. It should be executes in 0396 * exclusive environment only. 0397 */ 0398 void KisProjectionLeaf::explicitlyRegeneratePassThroughProjection() 0399 { 0400 if (!m_d->checkThisPassThrough()) return; 0401 0402 m_d->temporarySetPassThrough(false); 0403 0404 const QRect updateRect = projection()->defaultBounds()->bounds(); 0405 0406 KisRefreshSubtreeWalker walker(updateRect); 0407 walker.collectRects(m_d->node, updateRect); 0408 0409 KisAsyncMerger merger; 0410 merger.startMerge(walker); 0411 0412 m_d->temporarySetPassThrough(true); 0413 }