1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "drawable/rs_drawable.h"
17 
18 #include <limits>
19 
20 #include "drawable/rs_misc_drawable.h"
21 #include "drawable/rs_property_drawable.h"
22 #include "drawable/rs_property_drawable_background.h"
23 #include "drawable/rs_property_drawable_foreground.h"
24 #include "pipeline/rs_render_node.h"
25 #include "pipeline/rs_surface_render_node.h"
26 
27 namespace OHOS::Rosen {
28 namespace {
29 using namespace DrawableV2;
30 
31 // NOTE: This LUT should always the same size and order as RSModifierType
32 // key = RSModifierType, value = RSDrawableSlot
33 constexpr int DIRTY_LUT_SIZE = static_cast<int>(RSModifierType::MAX_RS_MODIFIER_TYPE);
34 static constexpr std::array<RSDrawableSlot, DIRTY_LUT_SIZE> g_propertyToDrawableLut = {
35     RSDrawableSlot::INVALID,                       // INVALID
36     RSDrawableSlot::CLIP_TO_BOUNDS,                // BOUNDS
37     RSDrawableSlot::FRAME_OFFSET,                  // FRAME
38     RSDrawableSlot::INVALID,                       // POSITION_Z
39     RSDrawableSlot::INVALID,                       // POSITION_Z_APPLICABLE_CAMERA3D
40     RSDrawableSlot::INVALID,                       // PIVOT
41     RSDrawableSlot::INVALID,                       // PIVOT_Z
42     RSDrawableSlot::INVALID,                       // QUATERNION
43     RSDrawableSlot::INVALID,                       // ROTATION
44     RSDrawableSlot::INVALID,                       // ROTATION_X
45     RSDrawableSlot::INVALID,                       // ROTATION_Y
46     RSDrawableSlot::INVALID,                       // CAMERA_DISTANCE
47     RSDrawableSlot::INVALID,                       // SCALE
48     RSDrawableSlot::INVALID,                       // SKEW
49     RSDrawableSlot::INVALID,                       // PERSP
50     RSDrawableSlot::INVALID,                       // TRANSLATE
51     RSDrawableSlot::INVALID,                       // TRANSLATE_Z
52     RSDrawableSlot::INVALID,                       // SUBLAYER_TRANSFORM
53     RSDrawableSlot::CLIP_TO_BOUNDS,                // CORNER_RADIUS
54     RSDrawableSlot::INVALID,                       // ALPHA
55     RSDrawableSlot::INVALID,                       // ALPHA_OFFSCREEN
56     RSDrawableSlot::FOREGROUND_COLOR,              // FOREGROUND_COLOR
57     RSDrawableSlot::BACKGROUND_COLOR,              // BACKGROUND_COLOR
58     RSDrawableSlot::BACKGROUND_SHADER,             // BACKGROUND_SHADER
59     RSDrawableSlot::BACKGROUND_IMAGE,              // BG_IMAGE
60     RSDrawableSlot::BACKGROUND_IMAGE,              // BG_IMAGE_INNER_RECT
61     RSDrawableSlot::BACKGROUND_IMAGE,              // BG_IMAGE_WIDTH
62     RSDrawableSlot::BACKGROUND_IMAGE,              // BG_IMAGE_HEIGHT
63     RSDrawableSlot::BACKGROUND_IMAGE,              // BG_IMAGE_POSITION_X
64     RSDrawableSlot::BACKGROUND_IMAGE,              // BG_IMAGE_POSITION_Y
65     RSDrawableSlot::INVALID,                       // SURFACE_BG_COLOR
66     RSDrawableSlot::BORDER,                        // BORDER_COLOR
67     RSDrawableSlot::BORDER,                        // BORDER_WIDTH
68     RSDrawableSlot::BORDER,                        // BORDER_STYLE
69     RSDrawableSlot::BORDER,                        // BORDER_DASH_WIDTH
70     RSDrawableSlot::BORDER,                        // BORDER_DASH_GAP
71     RSDrawableSlot::COMPOSITING_FILTER,            // FILTER
72     RSDrawableSlot::BACKGROUND_FILTER,             // BACKGROUND_FILTER
73     RSDrawableSlot::COMPOSITING_FILTER,            // LINEAR_GRADIENT_BLUR_PARA
74     RSDrawableSlot::DYNAMIC_LIGHT_UP,              // DYNAMIC_LIGHT_UP_RATE
75     RSDrawableSlot::DYNAMIC_LIGHT_UP,              // DYNAMIC_LIGHT_UP_DEGREE
76     RSDrawableSlot::BLENDER,                       // FG_BRIGHTNESS_RATES
77     RSDrawableSlot::BLENDER,                       // FG_BRIGHTNESS_SATURATION
78     RSDrawableSlot::BLENDER,                       // FG_BRIGHTNESS_POSCOEFF
79     RSDrawableSlot::BLENDER,                       // FG_BRIGHTNESS_NEGCOEFF
80     RSDrawableSlot::BLENDER,                       // FG_BRIGHTNESS_FRACTION
81     RSDrawableSlot::BACKGROUND_COLOR,              // BG_BRIGHTNESS_RATES
82     RSDrawableSlot::BACKGROUND_COLOR,              // BG_BRIGHTNESS_SATURATION
83     RSDrawableSlot::BACKGROUND_COLOR,              // BG_BRIGHTNESS_POSCOEFF
84     RSDrawableSlot::BACKGROUND_COLOR,              // BG_BRIGHTNESS_NEGCOEFF
85     RSDrawableSlot::BACKGROUND_COLOR,              // BG_BRIGHTNESS_FRACTION
86     RSDrawableSlot::FRAME_OFFSET,                  // FRAME_GRAVITY
87     RSDrawableSlot::CLIP_TO_BOUNDS,                // CLIP_RRECT
88     RSDrawableSlot::CLIP_TO_BOUNDS,                // CLIP_BOUNDS
89     RSDrawableSlot::CLIP_TO_BOUNDS,                // CLIP_TO_BOUNDS
90     RSDrawableSlot::CLIP_TO_FRAME,                 // CLIP_TO_FRAME
91     RSDrawableSlot::INVALID,                       // VISIBLE
92     RSDrawableSlot::SHADOW,                        // SHADOW_COLOR
93     RSDrawableSlot::SHADOW,                        // SHADOW_OFFSET_X
94     RSDrawableSlot::SHADOW,                        // SHADOW_OFFSET_Y
95     RSDrawableSlot::SHADOW,                        // SHADOW_ALPHA
96     RSDrawableSlot::SHADOW,                        // SHADOW_ELEVATION
97     RSDrawableSlot::SHADOW,                        // SHADOW_RADIUS
98     RSDrawableSlot::SHADOW,                        // SHADOW_PATH
99     RSDrawableSlot::SHADOW,                        // SHADOW_MASK
100     RSDrawableSlot::SHADOW,                        // SHADOW_COLOR_STRATEGY
101     RSDrawableSlot::MASK,                          // MASK
102     RSDrawableSlot::FOREGROUND_FILTER,             // SPHERIZE
103     RSDrawableSlot::LIGHT_UP_EFFECT,               // LIGHT_UP_EFFECT
104     RSDrawableSlot::PIXEL_STRETCH,                 // PIXEL_STRETCH
105     RSDrawableSlot::PIXEL_STRETCH,                 // PIXEL_STRETCH_PERCENT
106     RSDrawableSlot::PIXEL_STRETCH,                 // PIXEL_STRETCH_TILE_MODE
107     RSDrawableSlot::USE_EFFECT,                    // USE_EFFECT
108     RSDrawableSlot::USE_EFFECT,                    // USE_EFFECT_TYPE
109     RSDrawableSlot::BLENDER,                       // COLOR_BLEND_MODE
110     RSDrawableSlot::BLENDER,                       // COLOR_BLEND_APPLY_TYPE
111     RSDrawableSlot::INVALID,                       // SANDBOX
112     RSDrawableSlot::COLOR_FILTER,                  // GRAY_SCALE
113     RSDrawableSlot::COLOR_FILTER,                  // BRIGHTNESS
114     RSDrawableSlot::COLOR_FILTER,                  // CONTRAST
115     RSDrawableSlot::COLOR_FILTER,                  // SATURATE
116     RSDrawableSlot::COLOR_FILTER,                  // SEPIA
117     RSDrawableSlot::COLOR_FILTER,                  // INVERT
118     RSDrawableSlot::BINARIZATION,                  // AIINVERT
119     RSDrawableSlot::BACKGROUND_FILTER,             // SYSTEMBAREFFECT
120     RSDrawableSlot::BACKGROUND_FILTER,             // WATER_RIPPLE_PROGRESS
121     RSDrawableSlot::BACKGROUND_FILTER,             // WATER_RIPPLE_EFFECT
122     RSDrawableSlot::COLOR_FILTER,                  // HUE_ROTATE
123     RSDrawableSlot::COLOR_FILTER,                  // COLOR_BLEND
124     RSDrawableSlot::PARTICLE_EFFECT,               // PARTICLE
125     RSDrawableSlot::SHADOW,                        // SHADOW_IS_FILLED
126     RSDrawableSlot::OUTLINE,                       // OUTLINE_COLOR
127     RSDrawableSlot::OUTLINE,                       // OUTLINE_WIDTH
128     RSDrawableSlot::OUTLINE,                       // OUTLINE_STYLE
129     RSDrawableSlot::OUTLINE,                       // OUTLINE_DASH_WIDTH
130     RSDrawableSlot::OUTLINE,                       // OUTLINE_DASH_GAP
131     RSDrawableSlot::OUTLINE,                       // OUTLINE_RADIUS
132     RSDrawableSlot::INVALID,                       // GREY_COEF
133     RSDrawableSlot::POINT_LIGHT,                   // LIGHT_INTENSITY
134     RSDrawableSlot::POINT_LIGHT,                   // LIGHT_COLOR
135     RSDrawableSlot::POINT_LIGHT,                   // LIGHT_POSITION
136     RSDrawableSlot::POINT_LIGHT,                   // ILLUMINATED_BORDER_WIDTH
137     RSDrawableSlot::POINT_LIGHT,                   // ILLUMINATED_TYPE
138     RSDrawableSlot::POINT_LIGHT,                   // BLOOM
139     RSDrawableSlot::FOREGROUND_FILTER,             // FOREGROUND_EFFECT_RADIUS
140     RSDrawableSlot::CHILDREN,                      // USE_SHADOW_BATCHING,
141     RSDrawableSlot::FOREGROUND_FILTER,             // MOTION_BLUR_PARA
142     RSDrawableSlot::PARTICLE_EFFECT,               // PARTICLE_EMITTER_UPDATER
143     RSDrawableSlot::PARTICLE_EFFECT,               // PARTICLE_NOISE_FIELD
144     RSDrawableSlot::FOREGROUND_FILTER,             // FLY_OUT_DEGREE
145     RSDrawableSlot::FOREGROUND_FILTER,             // FLY_OUT_PARAMS
146     RSDrawableSlot::FOREGROUND_FILTER,             // DISTORTION_K
147     RSDrawableSlot::DYNAMIC_DIM,                   // DYNAMIC_DIM_DEGREE,
148     RSDrawableSlot::BACKGROUND_FILTER,             // MAGNIFIER_PARA,
149     RSDrawableSlot::BACKGROUND_FILTER,             // BACKGROUND_BLUR_RADIUS,
150     RSDrawableSlot::BACKGROUND_FILTER,             // BACKGROUND_BLUR_SATURATION,
151     RSDrawableSlot::BACKGROUND_FILTER,             // BACKGROUND_BLUR_BRIGHTNESS,
152     RSDrawableSlot::BACKGROUND_FILTER,             // BACKGROUND_BLUR_MASK_COLOR,
153     RSDrawableSlot::BACKGROUND_FILTER,             // BACKGROUND_BLUR_COLOR_MODE,
154     RSDrawableSlot::BACKGROUND_FILTER,             // BACKGROUND_BLUR_RADIUS_X,
155     RSDrawableSlot::BACKGROUND_FILTER,             // BACKGROUND_BLUR_RADIUS_Y,
156     RSDrawableSlot::COMPOSITING_FILTER,            // FOREGROUND_BLUR_RADIUS,
157     RSDrawableSlot::COMPOSITING_FILTER,            // FOREGROUND_BLUR_SATURATION,
158     RSDrawableSlot::COMPOSITING_FILTER,            // FOREGROUND_BLUR_BRIGHTNESS,
159     RSDrawableSlot::COMPOSITING_FILTER,            // FOREGROUND_BLUR_MASK_COLOR,
160     RSDrawableSlot::COMPOSITING_FILTER,            // FOREGROUND_BLUR_COLOR_MODE,
161     RSDrawableSlot::COMPOSITING_FILTER,            // FOREGROUND_BLUR_RADIUS_X,
162     RSDrawableSlot::COMPOSITING_FILTER,            // FOREGROUND_BLUR_RADIUS_Y,
163     RSDrawableSlot::FOREGROUND_FILTER,             // ATTRACTION_FRACTION
164     RSDrawableSlot::FOREGROUND_FILTER,             // ATTRACTION_DSTPOINT
165     RSDrawableSlot::INVALID,                       // CUSTOM
166     RSDrawableSlot::INVALID,                       // EXTENDED
167     RSDrawableSlot::TRANSITION,                    // TRANSITION
168     RSDrawableSlot::BACKGROUND_STYLE,              // BACKGROUND_STYLE
169     RSDrawableSlot::CONTENT_STYLE,                 // CONTENT_STYLE
170     RSDrawableSlot::FOREGROUND_STYLE,              // FOREGROUND_STYLE
171     RSDrawableSlot::OVERLAY,                       // OVERLAY_STYLE
172     RSDrawableSlot::INVALID,                       // NODE_MODIFIER
173     RSDrawableSlot::ENV_FOREGROUND_COLOR,          // ENV_FOREGROUND_COLOR
174     RSDrawableSlot::ENV_FOREGROUND_COLOR_STRATEGY, // ENV_FOREGROUND_COLOR_STRATEGY
175     RSDrawableSlot::INVALID,                       // GEOMETRYTRANS
176     RSDrawableSlot::CUSTOM_CLIP_TO_FRAME,          // CUSTOM_CLIP_TO_FRAME,
177     RSDrawableSlot::BACKGROUND_FILTER,             // BEHIND_WINDOW_FILTER_RADIUS
178     RSDrawableSlot::BACKGROUND_FILTER,             // BEHIND_WINDOW_FILTER_SATURATION
179     RSDrawableSlot::BACKGROUND_FILTER,             // BEHIND_WINDOW_FILTER_BRIGHTNESS
180     RSDrawableSlot::BACKGROUND_FILTER,             // BEHIND_WINDOW_FILTER_MASK_COLOR
181     RSDrawableSlot::CHILDREN,                      // CHILDREN
182 };
183 
184 // Check if g_propertyToDrawableLut size match and is fully initialized (the last element should not be default value)
185 static_assert(g_propertyToDrawableLut.size() == static_cast<size_t>(RSModifierType::MAX_RS_MODIFIER_TYPE));
186 static_assert(g_propertyToDrawableLut.back() != RSDrawableSlot {});
187 
188 // Randomly check some LUT index and value
189 static_assert(g_propertyToDrawableLut[static_cast<size_t>(RSModifierType::USE_EFFECT)] == RSDrawableSlot::USE_EFFECT);
190 static_assert(
191     g_propertyToDrawableLut[static_cast<size_t>(RSModifierType::FOREGROUND_COLOR)] == RSDrawableSlot::FOREGROUND_COLOR);
192 static_assert(
193     g_propertyToDrawableLut[static_cast<size_t>(RSModifierType::CLIP_TO_FRAME)] == RSDrawableSlot::CLIP_TO_FRAME);
194 static_assert(
195     g_propertyToDrawableLut[static_cast<size_t>(RSModifierType::USE_SHADOW_BATCHING)] == RSDrawableSlot::CHILDREN);
196 static_assert(g_propertyToDrawableLut[static_cast<size_t>(RSModifierType::TRANSITION)] == RSDrawableSlot::TRANSITION);
197 static_assert(g_propertyToDrawableLut[static_cast<size_t>(RSModifierType::CHILDREN)] == RSDrawableSlot::CHILDREN);
198 
199 template<RSModifierType type>
ModifierGenerator(const RSRenderNode & node)200 static inline RSDrawable::Ptr ModifierGenerator(const RSRenderNode& node)
201 {
202     return RSCustomModifierDrawable::OnGenerate(node, type);
203 }
204 
205 // NOTE: This LUT should always the same size as RSDrawableSlot
206 // index = RSDrawableSlotType, value = DrawableGenerator
207 constexpr int GEN_LUT_SIZE = static_cast<int>(RSDrawableSlot::MAX);
208 static const std::array<RSDrawable::Generator, GEN_LUT_SIZE> g_drawableGeneratorLut = {
209     nullptr, // SAVE_ALL
210 
211     // Bounds Geometry
212     RSMaskDrawable::OnGenerate,                    // MASK,
213     ModifierGenerator<RSModifierType::TRANSITION>, // TRANSITION,
214     RSEnvFGColorDrawable::OnGenerate,              // ENV_FOREGROUND_COLOR,
215     RSShadowDrawable::OnGenerate,                  // SHADOW,
216     RSForegroundFilterDrawable::OnGenerate,        // FOREGROUND_FILTER
217     RSOutlineDrawable::OnGenerate,                 // OUTLINE,
218 
219     // BG properties in Bounds Clip
220     nullptr,                                             // BG_SAVE_BOUNDS,
221     nullptr,                                             // CLIP_TO_BOUNDS,
222     RSBeginBlenderDrawable::OnGenerate,                  // BLENDER,
223     RSBackgroundColorDrawable::OnGenerate,               // BACKGROUND_COLOR,
224     RSBackgroundShaderDrawable::OnGenerate,              // BACKGROUND_SHADER,
225     RSBackgroundImageDrawable::OnGenerate,               // BACKGROUND_IMAGE,
226     RSBackgroundFilterDrawable::OnGenerate,              // BACKGROUND_FILTER,
227     RSUseEffectDrawable::OnGenerate,                     // USE_EFFECT,
228     ModifierGenerator<RSModifierType::BACKGROUND_STYLE>, // BACKGROUND_STYLE,
229     RSDynamicLightUpDrawable::OnGenerate,                // DYNAMIC_LIGHT_UP,
230     RSEnvFGColorStrategyDrawable::OnGenerate,            // ENV_FOREGROUND_COLOR_STRATEGY,
231     nullptr,                                             // BG_RESTORE_BOUNDS,
232 
233     // Frame Geometry
234     nullptr,                                             // SAVE_FRAME,
235     RSFrameOffsetDrawable::OnGenerate,                   // FRAME_OFFSET,
236     RSClipToFrameDrawable::OnGenerate,                   // CLIP_TO_FRAME,
237     RSCustomClipToFrameDrawable::OnGenerate,             // CUSTOM_CLIP_TO_FRAME,
238     ModifierGenerator<RSModifierType::CONTENT_STYLE>,    // CONTENT_STYLE,
239     RSChildrenDrawable::OnGenerate,                      // CHILDREN,
240     ModifierGenerator<RSModifierType::FOREGROUND_STYLE>, // FOREGROUND_STYLE,
241     nullptr,                                             // RESTORE_FRAME,
242 
243     // FG properties in Bounds clip
244     nullptr,                                 // FG_SAVE_BOUNDS,
245     nullptr,                                 // FG_CLIP_TO_BOUNDS,
246     RSBinarizationDrawable::OnGenerate,      // BINARIZATION,
247     RSColorFilterDrawable::OnGenerate,       // COLOR_FILTER,
248     RSLightUpEffectDrawable::OnGenerate,     // LIGHT_UP_EFFECT,
249     RSDynamicDimDrawable::OnGenerate,        // DYNAMIC_DIM,
250     RSCompositingFilterDrawable::OnGenerate, // COMPOSITING_FILTER,
251     RSForegroundColorDrawable::OnGenerate,   // FOREGROUND_COLOR,
252     nullptr,                                 // FG_RESTORE_BOUNDS,
253 
254     // No clip (unless ClipToBounds is set)
255     RSPointLightDrawable::OnGenerate,                 // POINT_LIGHT,
256     RSBorderDrawable::OnGenerate,                     // BORDER,
257     ModifierGenerator<RSModifierType::OVERLAY_STYLE>, // OVERLAY,
258     RSParticleDrawable::OnGenerate,                   // PARTICLE_EFFECT,
259     RSPixelStretchDrawable::OnGenerate,               // PIXEL_STRETCH,
260 
261     // Restore state
262     RSEndBlenderDrawable::OnGenerate,               // RESTORE_BLEND_MODE,
263     RSForegroundFilterRestoreDrawable::OnGenerate,  // RESTORE_FOREGROUND_FILTER
264     nullptr,                                        // RESTORE_ALL,
265 };
266 
267 enum DrawableVecStatus : uint8_t {
268     CLIP_TO_BOUNDS     = 1 << 0,
269     BG_BOUNDS_PROPERTY = 1 << 1,
270     FG_BOUNDS_PROPERTY = 1 << 2,
271     ENV_CHANGED        = 1 << 3,
272     // Used by skip logic in RSRenderNode::UpdateDisplayList
273     FRAME_NOT_EMPTY    = 1 << 4,
274     NODE_NOT_EMPTY     = 1 << 5,
275 
276     // masks
277     BOUNDS_MASK  = CLIP_TO_BOUNDS | BG_BOUNDS_PROPERTY | FG_BOUNDS_PROPERTY,
278     FRAME_MASK   = FRAME_NOT_EMPTY,
279     OTHER_MASK   = ENV_CHANGED,
280 };
281 
HasPropertyDrawableInRange(const RSDrawable::Vec & drawableVec,RSDrawableSlot begin,RSDrawableSlot end)282 inline static bool HasPropertyDrawableInRange(
283     const RSDrawable::Vec& drawableVec, RSDrawableSlot begin, RSDrawableSlot end) noexcept
284 {
285     // Note: the loop range is [begin, end], both end is included.
286     auto beginIt = drawableVec.begin() + static_cast<size_t>(begin);
287     auto endIt = drawableVec.begin() + static_cast<size_t>(end) + 1;
288     return std::any_of(beginIt, endIt, [](const auto& Ptr) { return Ptr != nullptr; });
289 }
290 
CalculateDrawableVecStatus(RSRenderNode & node,const RSDrawable::Vec & drawableVec)291 static uint8_t CalculateDrawableVecStatus(RSRenderNode& node, const RSDrawable::Vec& drawableVec)
292 {
293     uint8_t result = 0;
294     bool nodeNotEmpty = false;
295     auto& properties = node.GetRenderProperties();
296 
297     // ClipToBounds if either 1. is surface node, 2. has explicit clip properties, 3. has blend mode or blender
298     bool shouldClipToBounds = node.IsInstanceOf<RSSurfaceRenderNode>() || properties.GetClipToBounds() ||
299                               properties.GetClipToRRect() || properties.GetClipBounds() != nullptr ||
300                               properties.GetColorBlendMode() != static_cast<int>(RSColorBlendMode::NONE) ||
301                               properties.IsFgBrightnessValid();
302     if (shouldClipToBounds) {
303         result |= DrawableVecStatus::CLIP_TO_BOUNDS;
304     }
305 
306     if (HasPropertyDrawableInRange(
307         drawableVec, RSDrawableSlot::CONTENT_BEGIN, RSDrawableSlot::CONTENT_END)) {
308         nodeNotEmpty = true;
309         result |= DrawableVecStatus::FRAME_NOT_EMPTY;
310     }
311 
312     if (HasPropertyDrawableInRange(
313         drawableVec, RSDrawableSlot::BG_PROPERTIES_BEGIN, RSDrawableSlot::BG_PROPERTIES_END)) {
314         result |= DrawableVecStatus::BG_BOUNDS_PROPERTY;
315         nodeNotEmpty = true;
316     }
317     if (HasPropertyDrawableInRange(
318         drawableVec, RSDrawableSlot::FG_PROPERTIES_BEGIN, RSDrawableSlot::FG_PROPERTIES_END)) {
319         result |= DrawableVecStatus::FG_BOUNDS_PROPERTY;
320         nodeNotEmpty = true;
321     }
322 
323     nodeNotEmpty = nodeNotEmpty ||
324         HasPropertyDrawableInRange(
325             drawableVec, RSDrawableSlot::TRANSITION_PROPERTIES_BEGIN, RSDrawableSlot::TRANSITION_PROPERTIES_END) ||
326         HasPropertyDrawableInRange(
327             drawableVec, RSDrawableSlot::EXTRA_PROPERTIES_BEGIN, RSDrawableSlot::EXTRA_PROPERTIES_END);
328     if (nodeNotEmpty) {
329         // Set NODE_NOT_EMPTY flag if any drawable (include frame/bg/fg/transition/extra) is set
330         result |= DrawableVecStatus::NODE_NOT_EMPTY;
331     }
332 
333     // Foreground color & Background Effect & Blend Mode should be processed here
334     if (drawableVec[static_cast<size_t>(RSDrawableSlot::ENV_FOREGROUND_COLOR)] ||
335         drawableVec[static_cast<size_t>(RSDrawableSlot::ENV_FOREGROUND_COLOR_STRATEGY)] ||
336         drawableVec[static_cast<size_t>(RSDrawableSlot::BLENDER)] ||
337         (node.GetType() == RSRenderNodeType::EFFECT_NODE &&
338             drawableVec[static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER)])) {
339         result |= DrawableVecStatus::ENV_CHANGED;
340     }
341 
342     return result;
343 }
344 
SaveRestoreHelper(RSDrawable::Vec & drawableVec,RSDrawableSlot slot1,RSDrawableSlot slot2,RSPaintFilterCanvas::SaveType type=RSPaintFilterCanvas::kCanvas)345 inline static void SaveRestoreHelper(RSDrawable::Vec& drawableVec, RSDrawableSlot slot1, RSDrawableSlot slot2,
346     RSPaintFilterCanvas::SaveType type = RSPaintFilterCanvas::kCanvas)
347 {
348     if (type == RSPaintFilterCanvas::kNone) {
349         return;
350     }
351     if (type == RSPaintFilterCanvas::kCanvas) {
352         auto count = std::make_shared<uint32_t>(std::numeric_limits<uint32_t>::max());
353         drawableVec[static_cast<size_t>(slot1)] = std::make_unique<RSSaveDrawable>(count);
354         drawableVec[static_cast<size_t>(slot2)] = std::make_unique<RSRestoreDrawable>(count);
355     } else {
356         auto status = std::make_shared<RSPaintFilterCanvas::SaveStatus>();
357         drawableVec[static_cast<size_t>(slot1)] = std::make_unique<RSCustomSaveDrawable>(status, type);
358         drawableVec[static_cast<size_t>(slot2)] = std::make_unique<RSCustomRestoreDrawable>(status);
359     }
360 }
361 
OptimizeBoundsSaveRestore(RSRenderNode & node,RSDrawable::Vec & drawableVec,uint8_t flags)362 static void OptimizeBoundsSaveRestore(RSRenderNode& node, RSDrawable::Vec& drawableVec, uint8_t flags)
363 {
364     // Erase existing save/clip/restore before re-generating
365     constexpr static std::array boundsSlotsToErase = {
366         RSDrawableSlot::BG_SAVE_BOUNDS,
367         RSDrawableSlot::CLIP_TO_BOUNDS,
368         RSDrawableSlot::BG_RESTORE_BOUNDS,
369         RSDrawableSlot::FG_SAVE_BOUNDS,
370         RSDrawableSlot::FG_CLIP_TO_BOUNDS,
371         RSDrawableSlot::FG_RESTORE_BOUNDS,
372     };
373     for (auto& slot : boundsSlotsToErase) {
374         drawableVec[static_cast<size_t>(slot)] = nullptr;
375     }
376 
377     if (flags & DrawableVecStatus::CLIP_TO_BOUNDS) {
378         // case 1: ClipToBounds set.
379         // add one clip, and reuse SAVE_ALL and RESTORE_ALL.
380         drawableVec[static_cast<size_t>(RSDrawableSlot::CLIP_TO_BOUNDS)] = RSClipToBoundsDrawable::OnGenerate(node);
381         return;
382     }
383 
384     if ((flags & DrawableVecStatus::BG_BOUNDS_PROPERTY) && (flags & DrawableVecStatus::FG_BOUNDS_PROPERTY)) {
385         // case 2: ClipToBounds not set and we have bounds properties both BG and FG.
386         // add two sets of save/clip/restore before & after content.
387 
388         // part 1: before children
389         SaveRestoreHelper(drawableVec, RSDrawableSlot::BG_SAVE_BOUNDS, RSDrawableSlot::BG_RESTORE_BOUNDS,
390             RSPaintFilterCanvas::kCanvas);
391         drawableVec[static_cast<size_t>(RSDrawableSlot::CLIP_TO_BOUNDS)] = RSClipToBoundsDrawable::OnGenerate(node);
392 
393         // part 2: after children, add aliases
394         drawableVec[static_cast<size_t>(RSDrawableSlot::FG_SAVE_BOUNDS)] =
395             drawableVec[static_cast<size_t>(RSDrawableSlot::BG_SAVE_BOUNDS)];
396         drawableVec[static_cast<size_t>(RSDrawableSlot::FG_CLIP_TO_BOUNDS)] =
397             drawableVec[static_cast<size_t>(RSDrawableSlot::CLIP_TO_BOUNDS)];
398         drawableVec[static_cast<size_t>(RSDrawableSlot::FG_RESTORE_BOUNDS)] =
399             drawableVec[static_cast<size_t>(RSDrawableSlot::BG_RESTORE_BOUNDS)];
400         return;
401     }
402 
403     if (flags & DrawableVecStatus::BG_BOUNDS_PROPERTY) {
404         // case 3: ClipToBounds not set and we have background bounds properties.
405         SaveRestoreHelper(drawableVec, RSDrawableSlot::BG_SAVE_BOUNDS, RSDrawableSlot::BG_RESTORE_BOUNDS,
406             RSPaintFilterCanvas::kCanvas);
407 
408         drawableVec[static_cast<size_t>(RSDrawableSlot::CLIP_TO_BOUNDS)] = RSClipToBoundsDrawable::OnGenerate(node);
409         return;
410     }
411 
412     if (flags & DrawableVecStatus::FG_BOUNDS_PROPERTY) {
413         // case 4: ClipToBounds not set and we have foreground bounds properties.
414         SaveRestoreHelper(drawableVec, RSDrawableSlot::FG_SAVE_BOUNDS, RSDrawableSlot::FG_RESTORE_BOUNDS,
415             RSPaintFilterCanvas::kCanvas);
416 
417         drawableVec[static_cast<size_t>(RSDrawableSlot::FG_CLIP_TO_BOUNDS)] = RSClipToBoundsDrawable::OnGenerate(node);
418         return;
419     }
420     // case 5: ClipToBounds not set and no bounds properties, no need to save/clip/restore.
421     // nothing to do
422 }
423 
OptimizeFrameSaveRestore(RSRenderNode & node,RSDrawable::Vec & drawableVec,uint8_t flags)424 static void OptimizeFrameSaveRestore(RSRenderNode& node, RSDrawable::Vec& drawableVec, uint8_t flags)
425 {
426     constexpr static std::array frameSlotsToErase = {
427         RSDrawableSlot::SAVE_FRAME,
428         RSDrawableSlot::RESTORE_FRAME,
429     };
430     // Erase existing save/clip/restore before re-generating
431     for (auto& slot : frameSlotsToErase) {
432         drawableVec[static_cast<size_t>(slot)] = nullptr;
433     }
434 
435     if (flags & DrawableVecStatus::FRAME_NOT_EMPTY) {
436         SaveRestoreHelper(
437             drawableVec, RSDrawableSlot::SAVE_FRAME, RSDrawableSlot::RESTORE_FRAME, RSPaintFilterCanvas::kCanvas);
438     }
439 }
440 
OptimizeGlobalSaveRestore(RSRenderNode & node,RSDrawable::Vec & drawableVec,uint8_t flags)441 static void OptimizeGlobalSaveRestore(RSRenderNode& node, RSDrawable::Vec& drawableVec, uint8_t flags)
442 {
443     constexpr static std::array globalSlotsToErase = {
444         RSDrawableSlot::SAVE_ALL,
445         RSDrawableSlot::RESTORE_ALL,
446     };
447     // Erase existing save/clip/restore before re-generating
448     for (auto& slot : globalSlotsToErase) {
449         drawableVec[static_cast<size_t>(slot)] = nullptr;
450     }
451 
452     // Parent will do canvas save/restore, we don't need to do it again
453     uint8_t saveType = RSPaintFilterCanvas::SaveType::kNone;
454     if (flags & DrawableVecStatus::ENV_CHANGED) {
455         // If we change env(fg color, effect, blendMode etc), we need to save env
456         saveType |= RSPaintFilterCanvas::SaveType::kEnv;
457     }
458 
459     if (saveType == RSPaintFilterCanvas::SaveType::kNone) {
460         return;
461     }
462     // add save/restore with needed type
463     SaveRestoreHelper(drawableVec, RSDrawableSlot::SAVE_ALL, RSDrawableSlot::RESTORE_ALL,
464         static_cast<RSPaintFilterCanvas::SaveType>(saveType));
465 }
466 
467 constexpr std::array boundsDirtyTypes = {
468     RSDrawableSlot::MASK,
469     RSDrawableSlot::SHADOW,
470     RSDrawableSlot::OUTLINE,
471     RSDrawableSlot::FOREGROUND_FILTER,
472     RSDrawableSlot::CLIP_TO_BOUNDS,
473     RSDrawableSlot::BACKGROUND_COLOR,
474     RSDrawableSlot::BACKGROUND_SHADER,
475     RSDrawableSlot::BACKGROUND_IMAGE,
476     RSDrawableSlot::ENV_FOREGROUND_COLOR_STRATEGY,
477     RSDrawableSlot::FRAME_OFFSET,
478     RSDrawableSlot::FG_CLIP_TO_BOUNDS,
479     RSDrawableSlot::FOREGROUND_COLOR,
480     RSDrawableSlot::POINT_LIGHT,
481     RSDrawableSlot::BORDER,
482     RSDrawableSlot::PIXEL_STRETCH,
483     RSDrawableSlot::RESTORE_FOREGROUND_FILTER,
484 };
485 constexpr std::array frameDirtyTypes = {
486     RSDrawableSlot::CLIP_TO_FRAME,
487     RSDrawableSlot::COMPOSITING_FILTER,
488 };
489 constexpr std::array borderDirtyTypes = {
490     RSDrawableSlot::BACKGROUND_COLOR,
491     RSDrawableSlot::BACKGROUND_SHADER,
492     RSDrawableSlot::BACKGROUND_IMAGE,
493 };
494 constexpr std::array bgfilterDirtyTypes = {
495     RSDrawableSlot::PIXEL_STRETCH,
496 };
497 constexpr std::array stretchDirtyTypes = {
498     RSDrawableSlot::BACKGROUND_FILTER,
499 };
500 const std::unordered_set<RSDrawableSlot> fuzeStretchBlurSafeList = {
501     RSDrawableSlot::BG_RESTORE_BOUNDS,
502     RSDrawableSlot::SAVE_FRAME,
503     RSDrawableSlot::RESTORE_FRAME,
504     RSDrawableSlot::FG_SAVE_BOUNDS,
505     RSDrawableSlot::FG_RESTORE_BOUNDS,
506 };
507 template<std::size_t SIZE>
MarkAffectedSlots(const std::array<RSDrawableSlot,SIZE> & affectedSlots,const RSDrawable::Vec & drawableVec,std::unordered_set<RSDrawableSlot> & dirtySlots)508 inline void MarkAffectedSlots(const std::array<RSDrawableSlot, SIZE>& affectedSlots, const RSDrawable::Vec& drawableVec,
509     std::unordered_set<RSDrawableSlot>& dirtySlots)
510 {
511     for (auto slot : affectedSlots) {
512         if (drawableVec[static_cast<size_t>(slot)]) {
513             dirtySlots.emplace(slot);
514         }
515     }
516 }
517 } // namespace
518 
CalculateDirtySlots(const ModifierDirtyTypes & dirtyTypes,const Vec & drawableVec)519 std::unordered_set<RSDrawableSlot> RSDrawable::CalculateDirtySlots(
520     const ModifierDirtyTypes& dirtyTypes, const Vec& drawableVec)
521 {
522     // Step 1.1: calculate dirty slots by looking up g_propertyToDrawableLut
523     std::unordered_set<RSDrawableSlot> dirtySlots;
524     for (size_t type = 0; type < static_cast<size_t>(RSModifierType::MAX_RS_MODIFIER_TYPE); type++) {
525         if (!dirtyTypes.test(type)) {
526             continue;
527         }
528         auto dirtySlot = g_propertyToDrawableLut[type];
529         if (dirtySlot != RSDrawableSlot::INVALID) {
530             dirtySlots.emplace(dirtySlot);
531         }
532     }
533 
534     // Step 1.2: expand dirty slots by rules
535     // if bounds or cornerRadius changed, mark affected drawables as dirty
536     if (dirtyTypes.test(static_cast<size_t>(RSModifierType::BOUNDS)) ||
537         dirtyTypes.test(static_cast<size_t>(RSModifierType::CORNER_RADIUS)) ||
538         dirtyTypes.test(static_cast<size_t>(RSModifierType::CLIP_BOUNDS))) {
539         MarkAffectedSlots(boundsDirtyTypes, drawableVec, dirtySlots);
540     }
541 
542     if (dirtyTypes.test(static_cast<size_t>(RSModifierType::SHADOW_MASK)) || dirtySlots.count(RSDrawableSlot::SHADOW)) {
543         dirtySlots.emplace(RSDrawableSlot::SHADOW);
544         dirtySlots.emplace(RSDrawableSlot::FOREGROUND_FILTER);
545     }
546 
547     if (dirtyTypes.test(static_cast<size_t>(RSModifierType::FRAME_GRAVITY))) {
548         dirtySlots.emplace(RSDrawableSlot::CONTENT_STYLE);
549         dirtySlots.emplace(RSDrawableSlot::FOREGROUND_STYLE);
550     }
551 
552     // if frame changed, mark affected drawables as dirty
553     if (dirtySlots.count(RSDrawableSlot::FRAME_OFFSET)) {
554         MarkAffectedSlots(frameDirtyTypes, drawableVec, dirtySlots);
555     }
556 
557     // if border changed, mark affected drawables as dirty
558     if (dirtySlots.count(RSDrawableSlot::BORDER)) {
559         MarkAffectedSlots(borderDirtyTypes, drawableVec, dirtySlots);
560     }
561 
562     // PLANNING: merge these restore operations with RESTORE_ALL drawable
563     if (dirtySlots.count(RSDrawableSlot::FOREGROUND_FILTER)) {
564         dirtySlots.emplace(RSDrawableSlot::RESTORE_FOREGROUND_FILTER);
565     }
566 
567     // if pixel-stretch changed, mark affected drawables as dirty
568     if (dirtySlots.count(RSDrawableSlot::PIXEL_STRETCH)) {
569         MarkAffectedSlots(stretchDirtyTypes, drawableVec, dirtySlots);
570     }
571     // if background filter changed, mark affected drawables as dirty
572     if (dirtySlots.count(RSDrawableSlot::BACKGROUND_FILTER)) {
573         MarkAffectedSlots(bgfilterDirtyTypes, drawableVec, dirtySlots);
574     }
575 
576     return dirtySlots;
577 }
578 
UpdateDirtySlots(const RSRenderNode & node,Vec & drawableVec,std::unordered_set<RSDrawableSlot> & dirtySlots)579 bool RSDrawable::UpdateDirtySlots(
580     const RSRenderNode& node, Vec& drawableVec, std::unordered_set<RSDrawableSlot>& dirtySlots)
581 {
582     // Step 2: Update or generate all dirty slots
583     bool drawableAddedOrRemoved = false;
584 
585     for (const auto& slot : dirtySlots) {
586         if (auto& drawable = drawableVec[static_cast<size_t>(slot)]) {
587             // If the slot is already created, call OnUpdate
588             if (!drawable->OnUpdate(node)) {
589                 // If the slot is no longer needed, destroy it
590                 drawable.reset();
591                 drawableAddedOrRemoved = true;
592             }
593         } else if (auto& generator = g_drawableGeneratorLut[static_cast<int>(slot)]) {
594             // If the slot is not created, call OnGenerate
595             if (auto drawable = generator(node)) {
596                 drawableVec[static_cast<size_t>(slot)] = std::move(drawable);
597                 drawableAddedOrRemoved = true;
598             }
599         }
600     }
601     // If at this point the child node happens to be null, and the scenario involves deleting the child node
602     // when the parent node is not on the tree, it is necessary to manually mark drawableAddedOrRemoved as true.
603     if (!drawableAddedOrRemoved && dirtySlots.count(RSDrawableSlot::CHILDREN) &&
604         drawableVec[static_cast<int8_t>(RSDrawableSlot::CHILDREN)] == nullptr) {
605         drawableAddedOrRemoved = true;
606     }
607 
608     return drawableAddedOrRemoved;
609 }
610 
FuzeDrawableSlots(const RSRenderNode & node,Vec & drawableVec)611 bool RSDrawable::FuzeDrawableSlots(const RSRenderNode& node, Vec& drawableVec)
612 {
613     // fuze the pixel stretch with MESA blur
614     if (!RSSystemProperties::GetMESABlurFuzedEnabled() ||
615         !drawableVec[static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER)] ||
616         !drawableVec[static_cast<size_t>(RSDrawableSlot::PIXEL_STRETCH)]) {
617         return false;
618     }
619 
620     auto &filterDrawable = drawableVec[static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER)];
621     auto bgFilterDrawable = std::static_pointer_cast<RSBackgroundFilterDrawable>(filterDrawable);
622     bgFilterDrawable->RemovePixelStretch();
623 
624     auto &stretchDrawable = drawableVec[static_cast<size_t>(RSDrawableSlot::PIXEL_STRETCH)];
625     auto pixelStretchDrawable = std::static_pointer_cast<RSPixelStretchDrawable>(stretchDrawable);
626     pixelStretchDrawable->OnUpdate(node);
627 
628     size_t start = static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER) + 1;
629     size_t end = static_cast<size_t>(RSDrawableSlot::PIXEL_STRETCH);
630     // We do not fuze if drawableSlots between BACKGROUND_FILTER and PIXEL_STRETCH exist
631     for (size_t ptr = start; ptr < end; ptr++) {
632         if (!fuzeStretchBlurSafeList.count(static_cast<RSDrawableSlot>(ptr)) && drawableVec[ptr]) {
633             return false;
634         }
635     }
636     if (bgFilterDrawable->FuzePixelStretch(node)) {
637         float INFTY = std::numeric_limits<float>::infinity();
638         pixelStretchDrawable->SetPixelStretch(Vector4f{ INFTY, INFTY, INFTY, INFTY });
639         return true;
640     }
641 
642     return false;
643 }
644 
UpdateSaveRestore(RSRenderNode & node,Vec & drawableVec,uint8_t & drawableVecStatus)645 void RSDrawable::UpdateSaveRestore(RSRenderNode& node, Vec& drawableVec, uint8_t& drawableVecStatus)
646 {
647     // ====================================================================
648     // Step 3: Universal save/clip/restore optimization
649 
650     // Step 3.1: calculate new drawable map status
651     auto drawableVecStatusNew = CalculateDrawableVecStatus(node, drawableVec);
652 
653     uint8_t changedBits = drawableVecStatus ^ drawableVecStatusNew;
654     if (changedBits == 0) {
655         // nothing to do
656         return;
657     }
658 
659     // Step 3.2: update save/clip/restore for changed types
660     if (changedBits & BOUNDS_MASK) {
661         // update bounds save/clip if need
662         OptimizeBoundsSaveRestore(node, drawableVec, drawableVecStatusNew);
663     }
664     if (changedBits & FRAME_MASK) {
665         // update frame save/clip if need
666         OptimizeFrameSaveRestore(node, drawableVec, drawableVecStatusNew);
667     }
668     if (changedBits & OTHER_MASK) {
669         // update global save/clip if need
670         OptimizeGlobalSaveRestore(node, drawableVec, drawableVecStatusNew);
671     }
672 
673     drawableVecStatus = drawableVecStatusNew;
674 }
675 } // namespace OHOS::Rosen
676