diff --git a/krita/image/kis_projection_leaf.cpp b/krita/image/kis_projection_leaf.cpp index c13fdc9a7e..370662e787 100644 --- a/krita/image/kis_projection_leaf.cpp +++ b/krita/image/kis_projection_leaf.cpp @@ -1,242 +1,244 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_projection_leaf.h" #include #include "kis_layer.h" #include "kis_mask.h" #include "kis_group_layer.h" #include "kis_adjustment_layer.h" #include "krita_utils.h" struct KisProjectionLeaf::Private { Private(KisNode *_node) : node(_node) {} KisNode* node; static bool checkPassThrough(const KisNode *node) { const KisGroupLayer *group = qobject_cast(node); return group && group->passThroughMode(); } bool checkParentPassThrough() { return node->parent() && checkPassThrough(node->parent()); } bool checkThisPassThrough() { return checkPassThrough(node); } }; KisProjectionLeaf::KisProjectionLeaf(KisNode *node) : m_d(new Private(node)) { } KisProjectionLeaf::~KisProjectionLeaf() { } KisProjectionLeafSP KisProjectionLeaf::parent() const { KisNodeSP node = m_d->node->parent(); - if (node && Private::checkPassThrough(node)) { + while (node && Private::checkPassThrough(node)) { node = node->parent(); } return node ? node->projectionLeaf() : KisProjectionLeafSP(); } KisProjectionLeafSP KisProjectionLeaf::firstChild() const { KisNodeSP node; if (!m_d->checkThisPassThrough()) { node = m_d->node->firstChild(); } return node ? node->projectionLeaf() : KisProjectionLeafSP(); } KisProjectionLeafSP KisProjectionLeaf::lastChild() const { KisNodeSP node; if (!m_d->checkThisPassThrough()) { node = m_d->node->lastChild(); } return node ? node->projectionLeaf() : KisProjectionLeafSP(); } KisProjectionLeafSP KisProjectionLeaf::prevSibling() const { KisNodeSP node; if (m_d->checkThisPassThrough()) { node = m_d->node->lastChild(); } if (!node) { node = m_d->node->prevSibling(); } - if (!node && m_d->checkParentPassThrough()) { - node = m_d->node->parent()->prevSibling(); + const KisProjectionLeaf *leaf = this; + while (!node && leaf->m_d->checkParentPassThrough()) { + leaf = leaf->node()->parent()->projectionLeaf().data(); + node = leaf->node()->prevSibling(); } return node ? node->projectionLeaf() : KisProjectionLeafSP(); } KisProjectionLeafSP KisProjectionLeaf::nextSibling() const { KisNodeSP node = m_d->node->nextSibling(); - if (node && Private::checkPassThrough(node) && node->firstChild()) { + while (node && Private::checkPassThrough(node) && node->firstChild()) { node = node->firstChild(); } if (!node && m_d->checkParentPassThrough()) { node = m_d->node->parent(); } return node ? node->projectionLeaf() : KisProjectionLeafSP(); } bool KisProjectionLeaf::hasChildren() const { return m_d->node->firstChild(); } KisNodeSP KisProjectionLeaf::node() const { return m_d->node; } KisAbstractProjectionPlaneSP KisProjectionLeaf::projectionPlane() const { return m_d->node->projectionPlane(); } bool KisProjectionLeaf::accept(KisNodeVisitor &visitor) { return m_d->node->accept(visitor); } KisPaintDeviceSP KisProjectionLeaf::original() { return m_d->node->original(); } KisPaintDeviceSP KisProjectionLeaf::projection() { return m_d->node->projection(); } bool KisProjectionLeaf::isRoot() const { return (bool)!m_d->node->parent(); } bool KisProjectionLeaf::isLayer() const { return (bool)qobject_cast(m_d->node); } bool KisProjectionLeaf::isMask() const { return (bool)qobject_cast(m_d->node); } bool KisProjectionLeaf::canHaveChildLayers() const { return (bool)qobject_cast(m_d->node); } bool KisProjectionLeaf::dependsOnLowerNodes() const { return (bool)qobject_cast(m_d->node); } bool KisProjectionLeaf::visible() const { // TODO: check opacity as well! bool hiddenByParentPassThrough = m_d->checkParentPassThrough() && !m_d->node->parent()->visible(); return m_d->node->visible(false) && !m_d->checkThisPassThrough() && !hiddenByParentPassThrough; } quint8 KisProjectionLeaf::opacity() const { quint8 resultOpacity = m_d->node->opacity(); if (m_d->checkParentPassThrough()) { quint8 parentOpacity = m_d->node->parent()->projectionLeaf()->opacity(); resultOpacity = KritaUtils::mergeOpacity(resultOpacity, parentOpacity); } return resultOpacity; } QBitArray KisProjectionLeaf::channelFlags() const { QBitArray channelFlags; KisLayer *layer = qobject_cast(m_d->node); if (!layer) return channelFlags; channelFlags = layer->channelFlags(); if (m_d->checkParentPassThrough()) { QBitArray parentChannelFlags; if (*m_d->node->colorSpace() == *m_d->node->parent()->colorSpace()) { KisLayer *parentLayer = qobject_cast(m_d->node->parent().data()); parentChannelFlags = parentLayer->channelFlags(); } channelFlags = KritaUtils::mergeChannelFlags(channelFlags, parentChannelFlags); } return channelFlags; } bool KisProjectionLeaf::isStillInGraph() const { return (bool)m_d->node->graphListener(); } bool KisProjectionLeaf::isDroppedMask() const { return qobject_cast(m_d->node) && m_d->checkParentPassThrough(); } diff --git a/krita/image/tests/kis_projection_leaf_test.cpp b/krita/image/tests/kis_projection_leaf_test.cpp index b5df21d819..5ce6f843b4 100644 --- a/krita/image/tests/kis_projection_leaf_test.cpp +++ b/krita/image/tests/kis_projection_leaf_test.cpp @@ -1,163 +1,290 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_projection_leaf_test.h" #include #include "qimage_based_test.h" #include "kis_projection_leaf.h" #include "kis_group_layer.h" struct TestImage : TestUtil::QImageBasedTest { TestImage() : TestUtil::QImageBasedTest("") { undoStore = new KisSurrogateUndoStore(); image = createImage(undoStore); addGlobalSelection(image); } KisSurrogateUndoStore *undoStore; KisImageSP image; KisNodeSP findBlur1() { return findNode(image->root(), "blur1"); } KisNodeSP findClone1() { return findNode(image->root(), "clone1"); } KisNodeSP findPaint1() { return findNode(image->root(), "paint1"); } }; bool safeCompare(KisProjectionLeafSP leaf, KisNodeSP node) { return (!leaf && !node) || (leaf->node() == node); } void checkNode(KisNodeSP node, const QString &prefix) { qDebug() << prefix << node->name(); safeCompare(node->projectionLeaf()->parent(), node->parent()); safeCompare(node->projectionLeaf()->firstChild(), node->firstChild()); safeCompare(node->projectionLeaf()->lastChild(), node->lastChild()); safeCompare(node->projectionLeaf()->prevSibling(), node->prevSibling()); safeCompare(node->projectionLeaf()->nextSibling(), node->nextSibling()); QCOMPARE(node->projectionLeaf()->node(), node); KisNodeSP prevNode = node->lastChild(); while(prevNode) { checkNode(prevNode, QString("\"\"%1").arg(prefix)); prevNode = prevNode->prevSibling(); } } void printNodes(KisNodeSP node, const QString &prefix = "") { qDebug() << prefix << node->name(); KisNodeSP prevNode = node->lastChild(); while(prevNode) { printNodes(prevNode, QString("\"\"%1").arg(prefix)); prevNode = prevNode->prevSibling(); } } -void printLeafsBackward(KisProjectionLeafSP leaf, const QString &prefix = "") +void printLeafsBackward(KisProjectionLeafSP leaf, QList &refNodes, const QString &prefix = "") { qDebug() << prefix << leaf->node()->name(); + QCOMPARE(leaf->node()->name(), refNodes.takeFirst()); KisProjectionLeafSP prevLeaf = leaf->lastChild(); while(prevLeaf) { - printLeafsBackward(prevLeaf, QString("\"\"%1").arg(prefix)); + printLeafsBackward(prevLeaf, refNodes, QString("\"\"%1").arg(prefix)); prevLeaf = prevLeaf->prevSibling(); } + + if (prefix == "") { + QVERIFY(refNodes.isEmpty()); + } } -void printLeafsForward(KisProjectionLeafSP leaf, const QString &prefix = "") +void printLeafsForward(KisProjectionLeafSP leaf, QList &refNodes, const QString &prefix = "") { qDebug() << prefix << leaf->node()->name(); + QCOMPARE(leaf->node()->name(), refNodes.takeFirst()); KisProjectionLeafSP prevLeaf = leaf->firstChild(); while(prevLeaf) { - printLeafsForward(prevLeaf, QString("\"\"%1").arg(prefix)); + printLeafsForward(prevLeaf, refNodes, QString("\"\"%1").arg(prefix)); prevLeaf = prevLeaf->nextSibling(); } } -void printParents(KisProjectionLeafSP leaf, const QString &prefix = "") +void printParents(KisProjectionLeafSP leaf, QList &refNodes, const QString &prefix = "") { qDebug() << prefix << leaf->node()->name(); - + QCOMPARE(leaf->node()->name(), refNodes.takeFirst()); leaf = leaf->parent(); if (leaf) { - printParents(leaf, QString("\"\"%1").arg(prefix)); + printParents(leaf, refNodes, QString("\"\"%1").arg(prefix)); } } void KisProjectionLeafTest::test() { TestImage t; checkNode(t.image->root(), ""); } void KisProjectionLeafTest::testPassThrough() { TestImage t; KisGroupLayerSP group1 = new KisGroupLayer(t.image, "group1", OPACITY_OPAQUE_U8); KisPaintLayerSP paint2 = new KisPaintLayer(t.image, "paint2", OPACITY_OPAQUE_U8); KisPaintLayerSP paint3 = new KisPaintLayer(t.image, "paint3", OPACITY_OPAQUE_U8); KisPaintLayerSP paint4 = new KisPaintLayer(t.image, "paint4", OPACITY_OPAQUE_U8); group1->setPassThroughMode(true); t.image->addNode(group1, t.image->root(), t.findBlur1()); t.image->addNode(paint2, group1); t.image->addNode(paint3, group1); t.image->addNode(paint4, group1); //checkNode(t.image->root(), ""); qDebug() << "== Nodes"; printNodes(t.image->root()); - qDebug() << "== Leafs backward"; - printLeafsBackward(t.image->root()->projectionLeaf()); - qDebug() << "== Leafs forward"; - printLeafsForward(t.image->root()->projectionLeaf()); - qDebug() << "== Parents for paint4"; - printParents(paint4->projectionLeaf()); + { + qDebug() << "== Leafs backward"; + + QList refNodes; + refNodes << "root" + << "selection" + << "paint1" + << "tmask1" + << "group1" << "paint4" << "paint3" << "paint2" + << "blur1" + << "clone1"; + + printLeafsBackward(t.image->root()->projectionLeaf(), refNodes); + } + + { + qDebug() << "== Leafs forward"; + + QList refNodes; + refNodes << "root" + << "clone1" + << "blur1" + << "paint2" << "paint3" << "paint4" << "group1" + << "paint1" + << "tmask1" + << "selection"; + + printLeafsForward(t.image->root()->projectionLeaf(), refNodes); + } + + { + qDebug() << "== Parents for paint4"; + QList refNodes; + refNodes << "paint4" << "root"; + printParents(paint4->projectionLeaf(), refNodes); + } + + { + qDebug() << "== Parents for paint3"; + QList refNodes; + refNodes << "paint3" << "root"; + printParents(paint3->projectionLeaf(), refNodes); + } + + { + qDebug() << "== Parents for group1"; + QList refNodes; + refNodes << "group1" << "root"; + printParents(group1->projectionLeaf(), refNodes); + } +} + +void KisProjectionLeafTest::testNestedPassThrough() +{ + TestImage t; + + KisGroupLayerSP group1 = new KisGroupLayer(t.image, "group1", OPACITY_OPAQUE_U8); + KisGroupLayerSP group2 = new KisGroupLayer(t.image, "group2", OPACITY_OPAQUE_U8); + KisGroupLayerSP group3 = new KisGroupLayer(t.image, "group3", OPACITY_OPAQUE_U8); + + KisPaintLayerSP paint4 = new KisPaintLayer(t.image, "paint4", OPACITY_OPAQUE_U8); + KisPaintLayerSP paint5 = new KisPaintLayer(t.image, "paint5", OPACITY_OPAQUE_U8); + + group1->setPassThroughMode(true); + group2->setPassThroughMode(true); + group3->setPassThroughMode(true); + + t.image->addNode(group1, t.image->root(), t.findBlur1()); + t.image->addNode(group2, group1); + t.image->addNode(paint4, group2); + + t.image->addNode(group3, t.image->root(), t.findBlur1()); + t.image->addNode(paint5, group3); + + //checkNode(t.image->root(), ""); + + qDebug() << "== Nodes"; + printNodes(t.image->root()); + + { + qDebug() << "== Leafs backward"; + + QList refNodes; + refNodes << "root" + << "selection" + << "paint1" + << "tmask1" + << "group1" << "group2" <<"paint4" + << "group3" << "paint5" + << "blur1" + << "clone1"; + + printLeafsBackward(t.image->root()->projectionLeaf(), refNodes); + } + + { + qDebug() << "== Leafs forward"; + + QList refNodes; + refNodes << "root" + << "clone1" + << "blur1" - qDebug() << "== Parents for paint3"; - printParents(paint3->projectionLeaf()); + << "paint5" << "group3" + << "paint4" << "group2" << "group1" - qDebug() << "== Parents for group1"; - printParents(group1->projectionLeaf()); + << "paint1" + << "tmask1" + << "selection"; + + printLeafsForward(t.image->root()->projectionLeaf(), refNodes); + } + + { + qDebug() << "== Parents for paint4"; + QList refNodes; + refNodes << "paint4" << "root"; + printParents(paint4->projectionLeaf(), refNodes); + } + + { + qDebug() << "== Parents for paint5"; + QList refNodes; + refNodes << "paint5" << "root"; + printParents(paint5->projectionLeaf(), refNodes); + } + + { + qDebug() << "== Parents for group1"; + QList refNodes; + refNodes << "group1" << "root"; + printParents(group1->projectionLeaf(), refNodes); + } } QTEST_KDEMAIN(KisProjectionLeafTest, GUI) diff --git a/krita/image/tests/kis_projection_leaf_test.h b/krita/image/tests/kis_projection_leaf_test.h index 2244fd412a..173ac9585d 100644 --- a/krita/image/tests/kis_projection_leaf_test.h +++ b/krita/image/tests/kis_projection_leaf_test.h @@ -1,32 +1,33 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_PROJECTION_LEAF_TEST_H #define __KIS_PROJECTION_LEAF_TEST_H #include class KisProjectionLeafTest : public QObject { Q_OBJECT private slots: void test(); void testPassThrough(); + void testNestedPassThrough(); }; #endif /* __KIS_PROJECTION_LEAF_TEST_H */