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