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