1 /*
2  *  Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include "kis_projection_leaf.h"
20 
21 #include <KoColorSpace.h>
22 
23 #include "kis_layer.h"
24 #include "kis_image.h"
25 #include "kis_mask.h"
26 #include "kis_group_layer.h"
27 #include "kis_selection_mask.h"
28 #include "kis_adjustment_layer.h"
29 
30 #include "krita_utils.h"
31 
32 #include "kis_refresh_subtree_walker.h"
33 #include "kis_async_merger.h"
34 #include "kis_node_graph_listener.h"
35 #include "kis_clone_layer.h"
36 
37 
38 struct Q_DECL_HIDDEN KisProjectionLeaf::Private
39 {
PrivateKisProjectionLeaf::Private40     Private(KisNode *_node) : node(_node) {}
41 
42     KisNodeWSP node;
43     bool isTemporaryHidden = false;
44 
checkPassThroughKisProjectionLeaf::Private45     static bool checkPassThrough(const KisNode *node) {
46         const KisGroupLayer *group = qobject_cast<const KisGroupLayer*>(node);
47         return group && group->passThroughMode();
48     }
49 
isSelectionMaskKisProjectionLeaf::Private50     static bool isSelectionMask(const KisNode *node) {
51         return qobject_cast<const KisSelectionMask*>(node);
52     }
53 
skipSelectionMasksForwardKisProjectionLeaf::Private54     static KisNodeSP skipSelectionMasksForward(KisNodeSP node) {
55         while (node && isSelectionMask(node)) {
56             node = node->nextSibling();
57         }
58         return node;
59     }
60 
skipSelectionMasksBackwardKisProjectionLeaf::Private61     static KisNodeSP skipSelectionMasksBackward(KisNodeSP node) {
62         while (node && isSelectionMask(node)) {
63             node = node->prevSibling();
64         }
65         return node;
66     }
67 
checkParentPassThroughKisProjectionLeaf::Private68     bool checkParentPassThrough() {
69         return node->parent() && checkPassThrough(node->parent());
70     }
71 
checkThisPassThroughKisProjectionLeaf::Private72     bool checkThisPassThrough() {
73         return checkPassThrough(node);
74     }
75 
overlayProjectionLeafKisProjectionLeaf::Private76     KisProjectionLeafSP overlayProjectionLeaf() const {
77         return node && node->graphListener() && node->graphListener()->graphOverlayNode() ?
78             node->graphListener()->graphOverlayNode()->projectionLeaf() : 0;
79     }
80 
isTopmostNodeKisProjectionLeaf::Private81     bool isTopmostNode() const {
82         return !skipSelectionMasksForward(node->nextSibling()) &&
83             node->parent() &&
84             !node->parent()->parent();
85     }
86 
findRootKisProjectionLeaf::Private87     KisNodeSP findRoot() const {
88         KisNodeSP root = node;
89 
90         while (root->parent()) {
91             root = root->parent();
92         }
93 
94         return root;
95     }
96 
temporarySetPassThroughKisProjectionLeaf::Private97     void temporarySetPassThrough(bool value) {
98         KisGroupLayer *group = qobject_cast<KisGroupLayer*>(node.data());
99         if (!group) return;
100 
101         group->setPassThroughMode(value);
102     }
103 };
104 
KisProjectionLeaf(KisNode * node)105 KisProjectionLeaf::KisProjectionLeaf(KisNode *node)
106     : m_d(new Private(node))
107 {
108 }
109 
~KisProjectionLeaf()110 KisProjectionLeaf::~KisProjectionLeaf()
111 {
112 }
113 
parent() const114 KisProjectionLeafSP KisProjectionLeaf::parent() const
115 {
116     KisNodeSP node;
117 
118     if (Private::isSelectionMask(m_d->node)) {
119         if (m_d->overlayProjectionLeaf() == this) {
120             node = m_d->findRoot();
121         }
122     } else {
123         node = m_d->node->parent();
124     }
125 
126     while (node && Private::checkPassThrough(node)) {
127         node = node->parent();
128     }
129 
130     return node ? node->projectionLeaf() : KisProjectionLeafSP();
131 }
132 
133 
firstChild() const134 KisProjectionLeafSP KisProjectionLeaf::firstChild() const
135 {
136     KisNodeSP node;
137 
138     if (!m_d->checkThisPassThrough()) {
139         node = m_d->node->firstChild();
140         node = Private::skipSelectionMasksForward(node);
141     }
142 
143     if (!node && isRoot()) {
144         KisProjectionLeafSP overlayLeaf = m_d->overlayProjectionLeaf();
145         if (overlayLeaf) {
146             return overlayLeaf;
147         }
148     }
149 
150     return node ? node->projectionLeaf() : KisProjectionLeafSP();
151 }
152 
lastChild() const153 KisProjectionLeafSP KisProjectionLeaf::lastChild() const
154 {
155     KisNodeSP node;
156 
157     if (isRoot()) {
158         KisProjectionLeafSP overlayLeaf = m_d->overlayProjectionLeaf();
159         if (overlayLeaf) {
160             return overlayLeaf;
161         }
162     }
163 
164     if (!m_d->checkThisPassThrough()) {
165         node = m_d->node->lastChild();
166         node = Private::skipSelectionMasksBackward(node);
167     }
168 
169     return node ? node->projectionLeaf() : KisProjectionLeafSP();
170 }
171 
prevSibling() const172 KisProjectionLeafSP KisProjectionLeaf::prevSibling() const
173 {
174     if (Private::isSelectionMask(m_d->node)) {
175         KisProjectionLeafSP leaf;
176 
177         if (m_d->overlayProjectionLeaf() == this) {
178             KisNodeSP node = m_d->findRoot()->lastChild();
179             node = Private::skipSelectionMasksBackward(node);
180             leaf = node->projectionLeaf();
181         }
182 
183         return leaf;
184     }
185 
186     KisNodeSP node;
187 
188     if (m_d->checkThisPassThrough()) {
189         node = m_d->node->lastChild();
190         node = Private::skipSelectionMasksBackward(node);
191     }
192 
193     if (!node) {
194         node = m_d->node->prevSibling();
195         node = Private::skipSelectionMasksBackward(node);
196     }
197 
198     const KisProjectionLeaf *leaf = this;
199     while (!node && leaf->m_d->checkParentPassThrough()) {
200         leaf = leaf->node()->parent()->projectionLeaf().data();
201         node = leaf->node()->prevSibling();
202         node = Private::skipSelectionMasksBackward(node);
203     }
204 
205     return node ? node->projectionLeaf() : KisProjectionLeafSP();
206 }
207 
nextSibling() const208 KisProjectionLeafSP KisProjectionLeaf::nextSibling() const
209 {
210     if (Private::isSelectionMask(m_d->node)) {
211         return KisProjectionLeafSP();
212     }
213 
214     KisProjectionLeafSP overlayLeaf = m_d->overlayProjectionLeaf();
215     if (overlayLeaf && m_d->isTopmostNode()) {
216         return overlayLeaf;
217     }
218 
219     KisNodeSP node = m_d->node->nextSibling();
220     node = Private::skipSelectionMasksForward(node);
221 
222     while (node && Private::checkPassThrough(node) && node->firstChild()) {
223         node = node->firstChild();
224         node = Private::skipSelectionMasksForward(node);
225     }
226 
227     if (!node && m_d->checkParentPassThrough()) {
228         node = m_d->node->parent();
229         node = Private::skipSelectionMasksForward(node);
230     }
231 
232     return node ? node->projectionLeaf() : KisProjectionLeafSP();
233 }
234 
node() const235 KisNodeSP KisProjectionLeaf::node() const
236 {
237     return m_d->node;
238 }
239 
projectionPlane() const240 KisAbstractProjectionPlaneSP KisProjectionLeaf::projectionPlane() const
241 {
242     return m_d->node->projectionPlane();
243 }
244 
accept(KisNodeVisitor & visitor)245 bool KisProjectionLeaf::accept(KisNodeVisitor &visitor)
246 {
247     return m_d->node->accept(visitor);
248 }
249 
original()250 KisPaintDeviceSP KisProjectionLeaf::original()
251 {
252     return m_d->node->original();
253 }
254 
projection()255 KisPaintDeviceSP KisProjectionLeaf::projection()
256 {
257     return m_d->node->projection();
258 }
259 
isRoot() const260 bool KisProjectionLeaf::isRoot() const
261 {
262     return (bool)!m_d->node->parent();
263 }
264 
isLayer() const265 bool KisProjectionLeaf::isLayer() const
266 {
267     return (bool)qobject_cast<const KisLayer*>(m_d->node.data()) &&
268         !m_d->node->isFakeNode();
269 }
270 
isMask() const271 bool KisProjectionLeaf::isMask() const
272 {
273     return (bool)qobject_cast<const KisMask*>(m_d->node.data()) &&
274         !m_d->node->isFakeNode();
275 }
276 
canHaveChildLayers() const277 bool KisProjectionLeaf::canHaveChildLayers() const
278 {
279     return (bool)qobject_cast<const KisGroupLayer*>(m_d->node.data());
280 }
281 
dependsOnLowerNodes() const282 bool KisProjectionLeaf::dependsOnLowerNodes() const
283 {
284     return (bool)qobject_cast<const KisAdjustmentLayer*>(m_d->node.data());
285 }
286 
visible() const287 bool KisProjectionLeaf::visible() const
288 {
289     if (m_d->isTemporaryHidden || isDroppedNode()) return false;
290 
291     // TODO: check opacity as well!
292 
293     bool hiddenByParentPassThrough = false;
294 
295     KisNodeSP node = m_d->node->parent();
296     while (node && node->projectionLeaf()->m_d->checkThisPassThrough()) {
297         hiddenByParentPassThrough |= !node->visible();
298         node = node->parent();
299     }
300 
301     return (m_d->node->visible(false) || m_d->node->isIsolatedRoot()) &&
302         !m_d->checkThisPassThrough() &&
303         !hiddenByParentPassThrough;
304 }
305 
opacity() const306 quint8 KisProjectionLeaf::opacity() const
307 {
308     quint8 resultOpacity = m_d->node->opacity();
309 
310     if (m_d->checkParentPassThrough()) {
311         quint8 parentOpacity = m_d->node->parent()->projectionLeaf()->opacity();
312 
313         resultOpacity = KritaUtils::mergeOpacity(resultOpacity, parentOpacity);
314     }
315 
316     return resultOpacity;
317 }
318 
channelFlags() const319 QBitArray KisProjectionLeaf::channelFlags() const
320 {
321     QBitArray channelFlags;
322 
323     KisLayer *layer = qobject_cast<KisLayer*>(m_d->node.data());
324     if (!layer) return channelFlags;
325 
326     channelFlags = layer->channelFlags();
327 
328     if (m_d->checkParentPassThrough()) {
329         QBitArray parentChannelFlags;
330 
331         if (*m_d->node->colorSpace() ==
332             *m_d->node->parent()->colorSpace()) {
333 
334             KisLayer *parentLayer = qobject_cast<KisLayer*>(m_d->node->parent().data());
335             parentChannelFlags = parentLayer->channelFlags();
336         }
337 
338         channelFlags = KritaUtils::mergeChannelFlags(channelFlags, parentChannelFlags);
339     }
340 
341     return channelFlags;
342 }
343 
isStillInGraph() const344 bool KisProjectionLeaf::isStillInGraph() const
345 {
346     return (bool)m_d->node->graphListener();
347 }
348 
hasClones() const349 bool KisProjectionLeaf::hasClones() const
350 {
351     KisLayer *layer = qobject_cast<KisLayer*>(m_d->node.data());
352     return layer ? layer->hasClones() : false;
353 }
354 
isDroppedNode() const355 bool KisProjectionLeaf::isDroppedNode() const
356 {
357     return dropReason() != NodeAvailable;
358 }
359 
dropReason() const360 KisProjectionLeaf::NodeDropReason KisProjectionLeaf::dropReason() const
361 {
362     if (qobject_cast<KisMask*>(m_d->node.data()) &&
363             m_d->checkParentPassThrough()) {
364 
365         return DropPassThroughMask;
366     }
367 
368     KisCloneLayer *cloneLayer = qobject_cast<KisCloneLayer*>(m_d->node.data());
369     if (cloneLayer && cloneLayer->copyFrom()) {
370         KisProjectionLeafSP leaf = cloneLayer->copyFrom()->projectionLeaf();
371 
372         if (leaf->m_d->checkThisPassThrough()) {
373             return DropPassThroughClone;
374         }
375     }
376 
377     return NodeAvailable;
378 }
379 
isOverlayProjectionLeaf() const380 bool KisProjectionLeaf::isOverlayProjectionLeaf() const
381 {
382     return this == m_d->overlayProjectionLeaf();
383 }
384 
setTemporaryHiddenFromRendering(bool value)385 void KisProjectionLeaf::setTemporaryHiddenFromRendering(bool value)
386 {
387     m_d->isTemporaryHidden = value;
388 }
389 
isTemporaryHiddenFromRendering() const390 bool KisProjectionLeaf::isTemporaryHiddenFromRendering() const
391 {
392     return m_d->isTemporaryHidden;
393 }
394 
395 /**
396  * This method is rather slow and dangerous. It should be executes in
397  * exclusive environment only.
398  */
explicitlyRegeneratePassThroughProjection()399 void KisProjectionLeaf::explicitlyRegeneratePassThroughProjection()
400 {
401     if (!m_d->checkThisPassThrough()) return;
402 
403     m_d->temporarySetPassThrough(false);
404 
405     const QRect updateRect = projection()->defaultBounds()->bounds();
406 
407     KisRefreshSubtreeWalker walker(updateRect);
408     walker.collectRects(m_d->node, updateRect);
409 
410     KisAsyncMerger merger;
411     merger.startMerge(walker);
412 
413     m_d->temporarySetPassThrough(true);
414 }
415