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