Commit 946bf224 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implement initial KisProjectionLeaf interface

KisProjectionLeaf is a special interface of KisNode that provides a
separate image graph for rendering. This interface is use by all walkers
and by async merger. The rest of Krita uses the basic one.
parent 915aea6b
......@@ -179,6 +179,7 @@ set(kritaimage_LIB_SRCS
kis_abstract_projection_plane.cpp
kis_layer_projection_plane.cpp
kis_mask_projection_plane.cpp
kis_projection_leaf.cpp
kis_mask.cc
kis_base_mask_generator.cpp
kis_rect_mask_generator.cpp
......
......@@ -54,10 +54,10 @@
//#define DEBUG_MERGER
#ifdef DEBUG_MERGER
#define DEBUG_NODE_ACTION(message, type, node, rect) \
qDebug() << message << type << ":" << node->name() << rect
#define DEBUG_NODE_ACTION(message, type, leaf, rect) \
qDebug() << message << type << ":" << leaf->node()->name() << rect
#else
#define DEBUG_NODE_ACTION(message, type, node, rect)
#define DEBUG_NODE_ACTION(message, type, leaf, rect)
#endif
......@@ -196,70 +196,68 @@ private:
/* KisAsyncMerger */
/*********************************************************************/
/**
* FIXME: Check node<->layer transitions
*/
void KisAsyncMerger::startMerge(KisBaseRectsWalker &walker, bool notifyClones) {
KisMergeWalker::NodeStack &nodeStack = walker.nodeStack();
KisMergeWalker::LeafStack &leafStack = walker.leafStack();
const bool useTempProjections = walker.needRectVaries();
while(!nodeStack.isEmpty()) {
KisMergeWalker::JobItem item = nodeStack.pop();
if(isRootNode(item.m_node)) continue;
while(!leafStack.isEmpty()) {
KisMergeWalker::JobItem item = leafStack.pop();
KisProjectionLeafSP currentLeaf = item.m_leaf;
if(currentLeaf->isRoot()) continue;
KisLayerSP currentNode = dynamic_cast<KisLayer*>(item.m_node.data());
// All the masks should be filtered by the walkers
Q_ASSERT(currentNode);
Q_ASSERT(currentLeaf->isLayer());
QRect applyRect = item.m_applyRect;
if(item.m_position & KisMergeWalker::N_EXTRA) {
// The type of layers that will not go to projection.
DEBUG_NODE_ACTION("Updating", "N_EXTRA", currentNode, applyRect);
DEBUG_NODE_ACTION("Updating", "N_EXTRA", currentLeaf, applyRect);
KisUpdateOriginalVisitor originalVisitor(applyRect,
m_currentProjection,
walker.cropRect());
currentNode->accept(originalVisitor);
currentNode->projectionPlane()->recalculate(applyRect, currentNode);
currentLeaf->accept(originalVisitor);
currentLeaf->projectionPlane()->recalculate(applyRect, currentLeaf->node());
continue;
}
if(!m_currentProjection)
setupProjection(currentNode, applyRect, useTempProjections);
setupProjection(currentLeaf, applyRect, useTempProjections);
KisUpdateOriginalVisitor originalVisitor(applyRect,
m_currentProjection,
walker.cropRect());
if(item.m_position & KisMergeWalker::N_FILTHY) {
DEBUG_NODE_ACTION("Updating", "N_FILTHY", currentNode, applyRect);
currentNode->accept(originalVisitor);
currentNode->projectionPlane()->recalculate(applyRect, walker.startNode());
DEBUG_NODE_ACTION("Updating", "N_FILTHY", currentLeaf, applyRect);
currentLeaf->accept(originalVisitor);
currentLeaf->projectionPlane()->recalculate(applyRect, walker.startNode());
}
else if(item.m_position & KisMergeWalker::N_ABOVE_FILTHY) {
DEBUG_NODE_ACTION("Updating", "N_ABOVE_FILTHY", currentNode, applyRect);
if(dependOnLowerNodes(currentNode)) {
currentNode->accept(originalVisitor);
currentNode->projectionPlane()->recalculate(applyRect, currentNode);
DEBUG_NODE_ACTION("Updating", "N_ABOVE_FILTHY", currentLeaf, applyRect);
if(currentLeaf->dependsOnLowerNodes()) {
currentLeaf->accept(originalVisitor);
currentLeaf->projectionPlane()->recalculate(applyRect, currentLeaf->node());
}
}
else if(item.m_position & KisMergeWalker::N_FILTHY_PROJECTION) {
DEBUG_NODE_ACTION("Updating", "N_FILTHY_PROJECTION", currentNode, applyRect);
currentNode->projectionPlane()->recalculate(applyRect, walker.startNode());
DEBUG_NODE_ACTION("Updating", "N_FILTHY_PROJECTION", currentLeaf, applyRect);
currentLeaf->projectionPlane()->recalculate(applyRect, walker.startNode());
}
else /*if(item.m_position & KisMergeWalker::N_BELOW_FILTHY)*/ {
DEBUG_NODE_ACTION("Updating", "N_BELOW_FILTHY", currentNode, applyRect);
DEBUG_NODE_ACTION("Updating", "N_BELOW_FILTHY", currentLeaf, applyRect);
/* nothing to do */
}
compositeWithProjection(currentNode, applyRect);
compositeWithProjection(currentLeaf, applyRect);
if(item.m_position & KisMergeWalker::N_TOPMOST) {
writeProjection(currentNode, useTempProjections, applyRect);
writeProjection(currentLeaf, useTempProjections, applyRect);
resetProjection();
}
}
......@@ -278,23 +276,15 @@ void KisAsyncMerger::startMerge(KisBaseRectsWalker &walker, bool notifyClones) {
}
}
bool KisAsyncMerger::isRootNode(KisNodeSP node) {
return !node->parent();
}
bool KisAsyncMerger::dependOnLowerNodes(KisNodeSP node) {
return qobject_cast<KisAdjustmentLayer*>(node.data());
}
void KisAsyncMerger::resetProjection() {
m_currentProjection = 0;
m_finalProjection = 0;
}
void KisAsyncMerger::setupProjection(KisNodeSP currentNode, const QRect& rect, bool useTempProjection) {
KisPaintDeviceSP parentOriginal = currentNode->parent()->original();
void KisAsyncMerger::setupProjection(KisProjectionLeafSP currentLeaf, const QRect& rect, bool useTempProjection) {
KisPaintDeviceSP parentOriginal = currentLeaf->parent()->original();
if (parentOriginal != currentNode->projection()) {
if (parentOriginal != currentLeaf->projection()) {
if (useTempProjection) {
if(!m_cachedPaintDevice)
m_cachedPaintDevice = new KisPaintDevice(parentOriginal->colorSpace());
......@@ -319,26 +309,26 @@ void KisAsyncMerger::setupProjection(KisNodeSP currentNode, const QRect& rect, b
}
}
void KisAsyncMerger::writeProjection(KisNodeSP topmostNode, bool useTempProjection, QRect rect) {
void KisAsyncMerger::writeProjection(KisProjectionLeafSP topmostLeaf, bool useTempProjection, QRect rect) {
Q_UNUSED(useTempProjection);
Q_UNUSED(topmostNode);
Q_UNUSED(topmostLeaf);
if (!m_currentProjection) return;
if(m_currentProjection != m_finalProjection) {
KisPainter::copyAreaOptimized(rect.topLeft(), m_currentProjection, m_finalProjection, rect);
}
DEBUG_NODE_ACTION("Writing projection", "", topmostNode->parent(), rect);
DEBUG_NODE_ACTION("Writing projection", "", topmostLeaf->parent(), rect);
}
bool KisAsyncMerger::compositeWithProjection(KisLayerSP layer, const QRect &rect) {
bool KisAsyncMerger::compositeWithProjection(KisProjectionLeafSP leaf, const QRect &rect) {
if (!m_currentProjection) return true;
if (!layer->visible()) return true;
if (!leaf->visible()) return true;
KisPainter gc(m_currentProjection);
layer->projectionPlane()->apply(&gc, rect);
leaf->projectionPlane()->apply(&gc, rect);
DEBUG_NODE_ACTION("Compositing projection", "", layer, rect);
DEBUG_NODE_ACTION("Compositing projection", "", leaf, rect);
return true;
}
......
......@@ -32,13 +32,10 @@ public:
void startMerge(KisBaseRectsWalker &walker, bool notifyClones = true);
private:
static inline bool isRootNode(KisNodeSP node);
static inline bool dependOnLowerNodes(KisNodeSP node);
inline void resetProjection();
inline void setupProjection(KisNodeSP currentNode, const QRect& rect, bool useTempProjection);
inline void writeProjection(KisNodeSP topmostNode, bool useTempProjection, QRect rect);
inline bool compositeWithProjection(KisLayerSP layer, const QRect &rect);
inline void setupProjection(KisProjectionLeafSP currentLeaf, const QRect& rect, bool useTempProjection);
inline void writeProjection(KisProjectionLeafSP topmostLeaf, bool useTempProjection, QRect rect);
inline bool compositeWithProjection(KisProjectionLeafSP leaf, const QRect &rect);
inline void doNotifyClones(KisBaseRectsWalker &walker);
private:
......
This diff is collapsed.
......@@ -36,7 +36,7 @@ public:
return FULL_REFRESH;
}
void startTrip(KisNodeSP startWith) {
void startTrip(KisProjectionLeafSP startWith) {
if(m_firstRun) {
m_firstRun = false;
......@@ -58,9 +58,9 @@ public:
}
}
void registerChangeRect(KisNodeSP node, NodePosition position) {
void registerChangeRect(KisProjectionLeafSP leaf, NodePosition position) {
if(m_currentUpdateType == FULL_REFRESH) {
KisRefreshSubtreeWalker::registerChangeRect(node, position);
KisRefreshSubtreeWalker::registerChangeRect(leaf, position);
}
else {
/**
......@@ -73,23 +73,23 @@ public:
* changeRects of all its children here.
*/
if(node == startNode() && node->parent()) {
KisRefreshSubtreeWalker::calculateChangeRect(node, requestedRect());
if(isStartLeaf(leaf)&& !leaf->isRoot()) {
KisRefreshSubtreeWalker::calculateChangeRect(leaf, requestedRect());
}
else {
KisMergeWalker::registerChangeRect(node, position);
KisMergeWalker::registerChangeRect(leaf, position);
}
}
}
void registerNeedRect(KisNodeSP node, NodePosition position) {
void registerNeedRect(KisProjectionLeafSP leaf, NodePosition position) {
if(m_currentUpdateType == FULL_REFRESH) {
KisRefreshSubtreeWalker::registerNeedRect(node, position);
KisRefreshSubtreeWalker::registerNeedRect(leaf, position);
}
else {
KisMergeWalker::registerNeedRect(node, position);
KisMergeWalker::registerNeedRect(leaf, position);
}
}
void adjustMasksChangeRect(KisNodeSP firstMask) {
void adjustMasksChangeRect(KisProjectionLeafSP firstMask) {
if(m_currentUpdateType == FULL_REFRESH) {
KisRefreshSubtreeWalker::adjustMasksChangeRect(firstMask);
}
......
......@@ -17,6 +17,8 @@
*/
#include "kis_merge_walker.h"
#include "kis_projection_leaf.h"
KisMergeWalker::KisMergeWalker(QRect cropRect, Flags flags)
......@@ -34,33 +36,33 @@ KisBaseRectsWalker::UpdateType KisMergeWalker::type() const
return m_flags == DEFAULT ? KisBaseRectsWalker::UPDATE : KisBaseRectsWalker::UPDATE_NO_FILTHY;
}
void KisMergeWalker::startTrip(KisNodeSP startWith)
void KisMergeWalker::startTrip(KisProjectionLeafSP startLeaf)
{
if(isMask(startWith)) {
startTripWithMask(startWith);
if(startLeaf->isMask()) {
startTripWithMask(startLeaf);
return;
}
visitHigherNode(startWith,
visitHigherNode(startLeaf,
m_flags == DEFAULT ? N_FILTHY : N_ABOVE_FILTHY);
KisNodeSP prevNode = startWith->prevSibling();
if(prevNode)
visitLowerNode(prevNode);
KisProjectionLeafSP prevLeaf = startLeaf->prevSibling();
if(prevLeaf)
visitLowerNode(prevLeaf);
}
void KisMergeWalker::startTripWithMask(KisNodeSP filthyMask)
void KisMergeWalker::startTripWithMask(KisProjectionLeafSP filthyMask)
{
adjustMasksChangeRect(filthyMask);
KisNodeSP parentLayer = filthyMask->parent();
KisProjectionLeafSP parentLayer = filthyMask->parent();
Q_ASSERT(parentLayer);
KisNodeSP nextNode = parentLayer->nextSibling();
KisNodeSP prevNode = parentLayer->prevSibling();
KisProjectionLeafSP nextLeaf = parentLayer->nextSibling();
KisProjectionLeafSP prevLeaf = parentLayer->prevSibling();
if (nextNode)
visitHigherNode(nextNode, N_ABOVE_FILTHY);
if (nextLeaf)
visitHigherNode(nextLeaf, N_ABOVE_FILTHY);
else if (parentLayer->parent())
startTrip(parentLayer->parent());
......@@ -69,32 +71,32 @@ void KisMergeWalker::startTripWithMask(KisNodeSP filthyMask)
calculateNodePosition(parentLayer);
registerNeedRect(parentLayer, positionToFilthy);
if(prevNode)
visitLowerNode(prevNode);
if(prevLeaf)
visitLowerNode(prevLeaf);
}
void KisMergeWalker::visitHigherNode(KisNodeSP node, NodePosition positionToFilthy)
void KisMergeWalker::visitHigherNode(KisProjectionLeafSP leaf, NodePosition positionToFilthy)
{
positionToFilthy |= calculateNodePosition(node);
positionToFilthy |= calculateNodePosition(leaf);
registerChangeRect(node, positionToFilthy);
registerChangeRect(leaf, positionToFilthy);
KisNodeSP nextNode = node->nextSibling();
if (nextNode)
visitHigherNode(nextNode, N_ABOVE_FILTHY);
else if (node->parent())
startTrip(node->parent());
KisProjectionLeafSP nextLeaf = leaf->nextSibling();
if (nextLeaf)
visitHigherNode(nextLeaf, N_ABOVE_FILTHY);
else if (leaf->parent())
startTrip(leaf->parent());
registerNeedRect(node, positionToFilthy);
registerNeedRect(leaf, positionToFilthy);
}
void KisMergeWalker::visitLowerNode(KisNodeSP node)
void KisMergeWalker::visitLowerNode(KisProjectionLeafSP leaf)
{
NodePosition position =
N_BELOW_FILTHY | calculateNodePosition(node);
registerNeedRect(node, position);
N_BELOW_FILTHY | calculateNodePosition(leaf);
registerNeedRect(leaf, position);
KisNodeSP prevNode = node->prevSibling();
if (prevNode)
visitLowerNode(prevNode);
KisProjectionLeafSP prevLeaf = leaf->prevSibling();
if (prevLeaf)
visitLowerNode(prevLeaf);
}
......@@ -59,25 +59,27 @@ protected:
* Then it goes down to the bottom collecting needRects
* for every branch.
*/
void startTrip(KisNodeSP startWith);
void startTrip(KisProjectionLeafSP startWith);
void startTripWithMask(KisNodeSP filthyMask);
using KisBaseRectsWalker::startTrip;
void startTripWithMask(KisProjectionLeafSP filthyMask);
private:
/**
* Visits a node @node and goes on crowling
* Visits a node @leaf and goes on crowling
* towards the top of the graph, caling visitHigherNode() or
* startTrip() one more time. After the top is reached
* returns back to the @node.
* returns back to the @leaf.
*/
void visitHigherNode(KisNodeSP node, NodePosition positionToFilthy);
void visitHigherNode(KisProjectionLeafSP leaf, NodePosition positionToFilthy);
/**
* Visits a node @node and goes on crowling
* Visits a node @leaf and goes on crowling
* towards the bottom of the graph, caling visitLowerNode() or
* startTrip() one more time.
*/
void visitLowerNode(KisNodeSP node);
void visitLowerNode(KisProjectionLeafSP leaf);
private:
const Flags m_flags;
......
......@@ -39,6 +39,7 @@
typedef KisSafeReadList<KisNodeSP> KisSafeReadNodeList;
#include "kis_abstract_projection_plane.h"
#include "kis_projection_leaf.h"
/**
......@@ -77,9 +78,11 @@ static KisNodeSPStaticRegistrar __registrar;
struct KisNode::Private
{
public:
Private()
Private(KisNode *node)
: graphListener(0)
, nodeProgressProxy(0) {
, nodeProgressProxy(0)
, projectionLeaf(new KisProjectionLeaf(node))
{
}
KisNodeWSP parent;
......@@ -89,6 +92,8 @@ public:
QReadWriteLock nodeSubgraphLock;
KisProjectionLeafSP projectionLeaf;
const KisNode* findSymmetricClone(const KisNode *srcRoot,
const KisNode *dstRoot,
const KisNode *srcTarget);
......@@ -159,7 +164,7 @@ void KisNode::Private::processDuplicatedClones(const KisNode *srcDuplicationRoot
}
KisNode::KisNode()
: m_d(new Private())
: m_d(new Private(this))
{
m_d->parent = 0;
m_d->graphListener = 0;
......@@ -167,7 +172,7 @@ KisNode::KisNode()
KisNode::KisNode(const KisNode & rhs)
: KisBaseNode(rhs)
, m_d(new Private())
, m_d(new Private(this))
{
m_d->parent = 0;
m_d->graphListener = 0;
......@@ -220,12 +225,17 @@ QRect KisNode::accessRect(const QRect &rect, PositionToFilthy pos) const
KisAbstractProjectionPlaneSP KisNode::projectionPlane() const
{
KIS_ASSERT_RECOVER_NOOP(0 && "KisNode::projectionPlane() is not defined!");
static KisAbstractProjectionPlaneSP plane =
static KisAbstractProjectionPlaneSP plane =
toQShared(new KisDumbProjectionPlane());
return plane;
}
KisProjectionLeafSP KisNode::projectionLeaf() const
{
return m_d->projectionLeaf;
}
bool KisNode::accept(KisNodeVisitor &v)
{
return v.visit(this);
......
......@@ -36,6 +36,7 @@ class KisNodeVisitor;
class KisNodeGraphListener;
class KisNodeProgressProxy;
class KisAbstractProjectionPlane;
class KisProjectionLeaf;
/**
* A KisNode is a KisBaseNode that knows about its direct peers, parent
......@@ -139,6 +140,16 @@ public:
*/
virtual KisAbstractProjectionPlaneSP projectionPlane() const;
/**
* The rendering of the image may not always happen in the order
* of the main graph. Pass-through nodes ake some subgraphs
* linear, so it the order of rendering change. projectionLeaf()
* is a special interface of KisNode that represents "a graph for
* projection rendering". Therefore the nodes in projectionLeaf()
* graph may have a different order the main one.
*/
virtual KisProjectionLeafSP projectionLeaf() const;
protected:
/**
......
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* 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 "kis_layer.h"
#include "kis_mask.h"
#include "kis_group_layer.h"
#include "kis_adjustment_layer.h"
struct KisProjectionLeaf::Private
{
Private(KisNode *_node) : node(_node) {}
KisNode* node;
};
KisProjectionLeaf::KisProjectionLeaf(KisNode *node)
: m_d(new Private(node))
{
}
KisProjectionLeaf::~KisProjectionLeaf()
{
}
KisProjectionLeafSP KisProjectionLeaf::parent() const
{
KisNodeSP node = m_d->node->parent();
return node ? node->projectionLeaf() : KisProjectionLeafSP();
}
KisProjectionLeafSP KisProjectionLeaf::firstChild() const
{
KisNodeSP node = m_d->node->firstChild();
return node ? node->projectionLeaf() : KisProjectionLeafSP();
}
KisProjectionLeafSP KisProjectionLeaf::lastChild() const
{
KisNodeSP node = m_d->node->lastChild();
return node ? node->projectionLeaf() : KisProjectionLeafSP();
}
KisProjectionLeafSP KisProjectionLeaf::prevSibling() const
{
KisNodeSP node = m_d->node->prevSibling();
return node ? node->projectionLeaf() : KisProjectionLeafSP();
}
KisProjectionLeafSP KisProjectionLeaf::nextSibling() const
{
KisNodeSP node = m_d->node->nextSibling();
return node ? node->projectionLeaf() : KisProjectionLeafSP();
}
int KisProjectionLeaf::childCount() const
{
return m_d->node->childCount();
}
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<const KisLayer*>(m_d->node);
}
bool KisProjectionLeaf::isMask() const
{
return (bool)qobject_cast<const KisMask*>(m_d->node);
}
bool KisProjectionLeaf::canHaveChildLayers() const
{
return (bool)qobject_cast<const KisGroupLayer*>(m_d->node);
}
bool KisProjectionLeaf::dependsOnLowerNodes() const
{
return (bool)qobject_cast<const KisAdjustmentLayer*>(m_d->node);
}
bool KisProjectionLeaf::visible() const
{
// check opacity as well!
return m_d->node->visible();
}
bool KisProjectionLeaf::isStillInGraph() const
{
return (bool)m_d->node->graphListener();
}
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* 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