File indexing completed on 2024-05-12 15:58:39
0001 /* 0002 * SPDX-FileCopyrightText: 2010 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef __KIS_REFRESH_SUBTREE_WALKER_H 0008 #define __KIS_REFRESH_SUBTREE_WALKER_H 0009 0010 #include "kis_types.h" 0011 #include "kis_base_rects_walker.h" 0012 0013 0014 class KRITAIMAGE_EXPORT KisRefreshSubtreeWalker : public virtual KisBaseRectsWalker 0015 { 0016 public: 0017 enum Flag { 0018 None = 0x0, 0019 SkipNonRenderableNodes = 0x1, 0020 NoFilthyMode = 0x2 0021 }; 0022 0023 Q_DECLARE_FLAGS(Flags, Flag); 0024 0025 public: 0026 KisRefreshSubtreeWalker(QRect cropRect, Flags flags = None) 0027 : m_flags(flags) 0028 { 0029 setCropRect(cropRect); 0030 } 0031 0032 UpdateType type() const override { 0033 return UNSUPPORTED; 0034 } 0035 0036 ~KisRefreshSubtreeWalker() override 0037 { 0038 } 0039 0040 Flags flags() const { 0041 return m_flags; 0042 } 0043 0044 protected: 0045 KisRefreshSubtreeWalker() {} 0046 0047 0048 QRect calculateChangeRect(KisProjectionLeafSP startWith, 0049 const QRect &requestedRect) { 0050 0051 if(!startWith->isLayer()) 0052 return requestedRect; 0053 0054 QRect childrenRect; 0055 QRect tempRect = requestedRect; 0056 bool changeRectVaries = false; 0057 0058 KisProjectionLeafSP currentLeaf = startWith->firstChild(); 0059 KisProjectionLeafSP prevLeaf; 0060 KisProjectionLeafSP nextLeaf; 0061 0062 while(currentLeaf) { 0063 nextLeaf = currentLeaf->nextSibling(); 0064 0065 if(currentLeaf->isLayer() && currentLeaf->shouldBeRendered()) { 0066 tempRect |= calculateChangeRect(currentLeaf, requestedRect); 0067 0068 if(!changeRectVaries) 0069 changeRectVaries = tempRect != requestedRect; 0070 0071 childrenRect = tempRect; 0072 prevLeaf = currentLeaf; 0073 } 0074 0075 currentLeaf = nextLeaf; 0076 } 0077 0078 tempRect |= startWith->projectionPlane()->changeRect(requestedRect | childrenRect); 0079 0080 if(!changeRectVaries) 0081 changeRectVaries = tempRect != requestedRect; 0082 0083 setExplicitChangeRect(tempRect, changeRectVaries); 0084 0085 return tempRect; 0086 } 0087 0088 void startTrip(KisProjectionLeafSP startWith) override { 0089 setExplicitChangeRect(requestedRect(), false); 0090 0091 if (isStartLeaf(startWith)) { 0092 KisProjectionLeafSP extraUpdateLeaf = startWith; 0093 0094 if (startWith->isMask()) { 0095 /** 0096 * When the mask is the root of the update, update 0097 * its parent projection using N_EXTRA method. 0098 * 0099 * This special update is necessary because the following 0100 * wolker will work in N_ABOVE_FILTHY mode only 0101 */ 0102 0103 extraUpdateLeaf = startWith->parent(); 0104 } 0105 0106 /** 0107 * Sometimes it may happen that the mask is placed outside layers hierarchy 0108 * (e.g. inactive selection mask), then the projection leafs will not point 0109 * to anywhere 0110 */ 0111 if (extraUpdateLeaf) { 0112 NodePosition pos = N_EXTRA | calculateNodePosition(extraUpdateLeaf); 0113 registerNeedRect(extraUpdateLeaf, pos); 0114 0115 /** 0116 * In normal walkers we register notifications 0117 * in the change-rect pass to avoid regeneration 0118 * of the nodes that are below filthy. In the subtree 0119 * walker there is no change-rect pass and all the 0120 * nodes are considered as filthy, so we should do 0121 * that explicitly. 0122 */ 0123 registerCloneNotification(extraUpdateLeaf->node(), pos); 0124 } 0125 } 0126 0127 /** 0128 * If the node is not renderable and we don't care about hidden groups, 0129 * e.g. when generating animation frames, then just skip the entire group. 0130 */ 0131 if (m_flags & SkipNonRenderableNodes && !startWith->shouldBeRendered()) return; 0132 0133 0134 KisProjectionLeafSP currentLeaf = startWith->lastChild(); 0135 while(currentLeaf) { 0136 NodePosition pos = (m_flags & NoFilthyMode ? N_ABOVE_FILTHY : N_FILTHY) | 0137 calculateNodePosition(currentLeaf); 0138 registerNeedRect(currentLeaf, pos); 0139 0140 // see a comment above 0141 registerCloneNotification(currentLeaf->node(), pos); 0142 currentLeaf = currentLeaf->prevSibling(); 0143 } 0144 0145 /** 0146 * In no-filthy mode we just recompose the root layer 0147 * without entering any subgroups 0148 */ 0149 if (m_flags & NoFilthyMode) return; 0150 0151 currentLeaf = startWith->lastChild(); 0152 while(currentLeaf) { 0153 if(currentLeaf->canHaveChildLayers()) { 0154 startTrip(currentLeaf); 0155 } 0156 currentLeaf = currentLeaf->prevSibling(); 0157 } 0158 } 0159 0160 private: 0161 Flags m_flags = None; 0162 }; 0163 0164 Q_DECLARE_OPERATORS_FOR_FLAGS(KisRefreshSubtreeWalker::Flags); 0165 0166 #endif /* __KIS_REFRESH_SUBTREE_WALKER_H */ 0167