File indexing completed on 2024-05-12 15:58:28

0001 /*
0002  *  SPDX-FileCopyrightText: 2009 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_merge_walker.h"
0008 #include "kis_projection_leaf.h"
0009 
0010 
0011 
0012 KisMergeWalker::KisMergeWalker(QRect cropRect,  Flags flags)
0013     : m_flags(flags)
0014 {
0015     setCropRect(cropRect);
0016 }
0017 
0018 KisMergeWalker::~KisMergeWalker()
0019 {
0020 }
0021 
0022 KisBaseRectsWalker::UpdateType KisMergeWalker::type() const
0023 {
0024     return m_flags == DEFAULT ? KisBaseRectsWalker::UPDATE : KisBaseRectsWalker::UPDATE_NO_FILTHY;
0025 }
0026 
0027 void KisMergeWalker::startTripImpl(KisProjectionLeafSP startLeaf, KisMergeWalker::Flags flags)
0028 {
0029     if(startLeaf->isMask()) {
0030         startTripWithMask(startLeaf, flags);
0031         return;
0032     }
0033 
0034     visitHigherNode(startLeaf,
0035                     flags == DEFAULT ? N_FILTHY : N_ABOVE_FILTHY);
0036 
0037     KisProjectionLeafSP prevLeaf = startLeaf->prevSibling();
0038     if(prevLeaf)
0039         visitLowerNode(prevLeaf);
0040 }
0041 
0042 
0043 void KisMergeWalker::startTrip(KisProjectionLeafSP startLeaf)
0044 {
0045     startTripImpl(startLeaf, m_flags);
0046 }
0047 
0048 void KisMergeWalker::startTripWithMask(KisProjectionLeafSP filthyMask, KisMergeWalker::Flags flags)
0049 {
0050     /**
0051      * Under very rare circumstances it may happen that the update
0052      * queue will contain a job pointing to a node that has
0053      * already been deleted from the image (directly or by undo
0054      * command). If it happens to a layer then the walker will
0055      * handle it as usual by building a trivial graph pointing to
0056      * nowhere, but when it happens to a mask... not. Because the
0057      * mask is always expected to have a parent layer to process.
0058      *
0059      * So just handle it here separately.
0060      */
0061     KisProjectionLeafSP parentLayer = filthyMask->parent();
0062     if (!parentLayer) {
0063         return;
0064     }
0065 
0066     adjustMasksChangeRect(filthyMask);
0067 
0068     KisProjectionLeafSP nextLeaf = parentLayer->nextSibling();
0069     KisProjectionLeafSP prevLeaf = parentLayer->prevSibling();
0070 
0071     if (nextLeaf)
0072         visitHigherNode(nextLeaf, N_ABOVE_FILTHY);
0073     else if (parentLayer->parent())
0074         startTripImpl(parentLayer->parent(), DEFAULT);
0075 
0076     NodePosition positionToFilthy =
0077         (flags == DEFAULT ? N_FILTHY_PROJECTION : N_ABOVE_FILTHY) |
0078         calculateNodePosition(parentLayer);
0079     registerNeedRect(parentLayer, positionToFilthy);
0080 
0081     if(prevLeaf)
0082         visitLowerNode(prevLeaf);
0083 }
0084 
0085 void KisMergeWalker::visitHigherNode(KisProjectionLeafSP leaf, NodePosition positionToFilthy)
0086 {
0087     positionToFilthy |= calculateNodePosition(leaf);
0088 
0089     registerChangeRect(leaf, positionToFilthy);
0090 
0091     KisProjectionLeafSP nextLeaf = leaf->nextSibling();
0092     if (nextLeaf)
0093         visitHigherNode(nextLeaf, N_ABOVE_FILTHY);
0094     else if (leaf->parent())
0095         startTripImpl(leaf->parent(), DEFAULT);
0096 
0097     registerNeedRect(leaf, positionToFilthy);
0098 }
0099 
0100 void KisMergeWalker::visitLowerNode(KisProjectionLeafSP leaf)
0101 {
0102     NodePosition position =
0103         N_BELOW_FILTHY | calculateNodePosition(leaf);
0104     registerNeedRect(leaf, position);
0105 
0106     KisProjectionLeafSP prevLeaf = leaf->prevSibling();
0107     if (prevLeaf)
0108         visitLowerNode(prevLeaf);
0109 }