• 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_misc_drawable.h"
17 
18 #include "common/rs_common_def.h"
19 #include "common/rs_optional_trace.h"
20 #include "drawable/rs_property_drawable_utils.h"
21 #include "drawable/rs_render_node_drawable_adapter.h"
22 #include "pipeline/rs_canvas_drawing_render_node.h"
23 #include "pipeline/rs_render_node.h"
24 
25 #include "rs_profiler.h"
26 
27 namespace OHOS::Rosen {
28 namespace DrawableV2 {
29 constexpr int TRACE_LEVEL_TWO = 2;
30 // ==================== RSChildrenDrawable =====================
OnGenerate(const RSRenderNode & node)31 RSDrawable::Ptr RSChildrenDrawable::OnGenerate(const RSRenderNode& node)
32 {
33     if (auto ret = std::make_shared<RSChildrenDrawable>(); ret->OnUpdate(node)) {
34         return std::move(ret);
35     }
36     return nullptr;
37 }
38 
OnUpdate(const RSRenderNode & node)39 bool RSChildrenDrawable::OnUpdate(const RSRenderNode& node)
40 {
41     childrenHasSharedTransition_ = false;
42     auto children = node.GetSortedChildren();
43     // Regenerate children drawables
44     needSync_ = true;
45     stagingChildrenDrawableVec_.clear();
46 
47     if (LIKELY(!node.GetRenderProperties().GetUseShadowBatching())) {
48         // Non-ShadowBatching mode (default), draw all children in order
49         for (const auto& child : *children) {
50             if (UNLIKELY(child->GetSharedTransitionParam()) && OnSharedTransition(child)) {
51                 continue;
52             }
53             auto childDrawable = RSRenderNodeDrawableAdapter::OnGenerate(child);
54             if (!childDrawable) {
55                 continue;
56             }
57             if (childDrawable->GetSkipType() == SkipType::SKIP_SHADOW) {
58                 childDrawable->SetSkip(SkipType::NONE);
59             }
60             stagingChildrenDrawableVec_.push_back(std::move(childDrawable));
61         }
62     } else {
63         // ShadowBatching mode, draw all shadows, then draw all children
64         decltype(stagingChildrenDrawableVec_) pendingChildren;
65         for (const auto& child : *children) {
66             if (UNLIKELY(child->GetSharedTransitionParam()) && OnSharedTransition(child)) {
67                 continue;
68             }
69             auto childDrawable = RSRenderNodeDrawableAdapter::OnGenerate(child);
70             if (!childDrawable) {
71                 continue;
72             }
73             auto shadowDrawable = RSRenderNodeDrawableAdapter::OnGenerateShadowDrawable(child, childDrawable);
74             if (!shadowDrawable) {
75                 continue;
76             }
77             stagingChildrenDrawableVec_.push_back(std::move(shadowDrawable));
78             pendingChildren.push_back(std::move(childDrawable));
79         }
80         // merge two vectors, shadow drawables first, render node drawables second
81         stagingChildrenDrawableVec_.insert(
82             stagingChildrenDrawableVec_.end(), pendingChildren.begin(), pendingChildren.end());
83     }
84     const_cast<RSRenderNode&>(node).SetChildrenHasSharedTransition(childrenHasSharedTransition_);
85     return !stagingChildrenDrawableVec_.empty();
86 }
87 
OnSharedTransition(const RSRenderNode::SharedPtr & node)88 bool RSChildrenDrawable::OnSharedTransition(const RSRenderNode::SharedPtr& node)
89 {
90     auto nodeId = node->GetId();
91     const auto& sharedTransitionParam = node->GetSharedTransitionParam();
92 
93     auto pairedNode = sharedTransitionParam->GetPairedNode(nodeId);
94     if (!pairedNode || !pairedNode->IsOnTheTree()) {
95         sharedTransitionParam->paired_ = false;
96         return false;
97     }
98 
99     childrenHasSharedTransition_ = true;
100     // Skip if the shared transition is not paired (Note: this may cause the lower node to be drawn twice)
101     if (!sharedTransitionParam->paired_) {
102         return false;
103     }
104 
105     // Relation will be set in QuickPrepare
106     if (!sharedTransitionParam->HasRelation()) {
107         sharedTransitionParam->SetNeedGenerateDrawable(true);
108         return true;
109     }
110 
111     // Test if this node is lower in the hierarchy
112     bool isLower = sharedTransitionParam->IsLower(nodeId);
113     if (isLower) {
114         // for lower hierarchy node, we skip it here
115         return true;
116     } else {
117         // for higher hierarchy node, we add paired node (lower in hierarchy) first, then add it
118         if (auto childDrawable = RSRenderNodeDrawableAdapter::OnGenerate(pairedNode)) {
119             stagingChildrenDrawableVec_.push_back(std::move(childDrawable));
120         }
121         sharedTransitionParam->SetNeedGenerateDrawable(false);
122         return false;
123     }
124 }
125 
OnSync()126 void RSChildrenDrawable::OnSync()
127 {
128     if (!needSync_) {
129         return;
130     }
131     std::swap(stagingChildrenDrawableVec_, childrenDrawableVec_);
132     stagingChildrenDrawableVec_.clear();
133     needSync_ = false;
134 }
135 
CreateDrawFunc() const136 Drawing::RecordingCanvas::DrawFunc RSChildrenDrawable::CreateDrawFunc() const
137 {
138     auto ptr = std::static_pointer_cast<const RSChildrenDrawable>(shared_from_this());
139     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
140         for (size_t i = 0; i < ptr->childrenDrawableVec_.size(); i++) {
141 #ifdef RS_ENABLE_PREFETCH
142             size_t prefetchIndex = i + 2;
143             if (prefetchIndex < ptr->childrenDrawableVec_.size()) {
144                 __builtin_prefetch(&(ptr->childrenDrawableVec_[prefetchIndex]), 0, 1);
145             }
146 #endif
147             const auto& drawable = ptr->childrenDrawableVec_[i];
148             drawable->Draw(*canvas);
149         }
150     };
151 }
152 
153 // ==================== RSCustomModifierDrawable ===================
OnGenerate(const RSRenderNode & node,RSModifierType type)154 RSDrawable::Ptr RSCustomModifierDrawable::OnGenerate(const RSRenderNode& node, RSModifierType type)
155 {
156     if (auto ret = std::make_shared<RSCustomModifierDrawable>(type); ret->OnUpdate(node)) {
157         if (node.GetType() == RSRenderNodeType::CANVAS_DRAWING_NODE) {
158             ret->needClearOp_ = true;
159         }
160         return std::move(ret);
161     }
162     return nullptr;
163 }
164 
OnUpdate(const RSRenderNode & node)165 bool RSCustomModifierDrawable::OnUpdate(const RSRenderNode& node)
166 {
167     const auto& drawCmdModifiers = node.GetDrawCmdModifiers();
168     auto itr = drawCmdModifiers.find(type_);
169     if (itr == drawCmdModifiers.end() || itr->second.empty()) {
170         return false;
171     }
172 
173     stagingGravity_ = node.GetRenderProperties().GetFrameGravity();
174     stagingIsCanvasNode_ = node.IsInstanceOf<RSCanvasRenderNode>() && !node.IsInstanceOf<RSCanvasDrawingRenderNode>();
175     // regenerate stagingDrawCmdList_
176     needSync_ = true;
177     stagingDrawCmdListVec_.clear();
178     if (node.GetType() == RSRenderNodeType::CANVAS_DRAWING_NODE && type_ == RSModifierType::CONTENT_STYLE) {
179         auto& drawingNode = static_cast<const RSCanvasDrawingRenderNode&>(node);
180         auto& cmdLists = drawingNode.GetDrawCmdLists();
181         auto itr = cmdLists.find(type_);
182         if (itr == cmdLists.end() || itr->second.empty()) {
183             return false;
184         }
185         for (auto& cmd : itr->second) {
186             stagingDrawCmdListVec_.emplace_back(cmd);
187         }
188     } else {
189         for (const auto& modifier : itr->second) {
190             auto property = std::static_pointer_cast<RSRenderProperty<Drawing::DrawCmdListPtr>>(
191                 modifier->GetProperty());
192             if (const auto& drawCmdList = property->GetRef()) {
193                 if (drawCmdList->GetWidth() > 0 && drawCmdList->GetHeight() > 0) {
194                     stagingDrawCmdListVec_.push_back(drawCmdList);
195                 }
196             }
197         }
198     }
199     return !stagingDrawCmdListVec_.empty();
200 }
201 
OnSync()202 void RSCustomModifierDrawable::OnSync()
203 {
204     if (!needSync_) {
205         return;
206     }
207     gravity_ = stagingGravity_;
208     isCanvasNode_ = stagingIsCanvasNode_;
209     std::swap(stagingDrawCmdListVec_, drawCmdListVec_);
210     stagingDrawCmdListVec_.clear();
211     needSync_ = false;
212 }
213 
OnPurge()214 void RSCustomModifierDrawable::OnPurge()
215 {
216     for (auto &drawCmdList : drawCmdListVec_) {
217         if (drawCmdList) {
218             drawCmdList->Purge();
219         }
220     }
221 }
222 
CreateDrawFunc() const223 Drawing::RecordingCanvas::DrawFunc RSCustomModifierDrawable::CreateDrawFunc() const
224 {
225     auto ptr = std::static_pointer_cast<const RSCustomModifierDrawable>(shared_from_this());
226     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
227         for (size_t i = 0; i < ptr->drawCmdListVec_.size(); i++) {
228 #ifdef RS_ENABLE_PREFETCH
229             size_t prefetchIndex = i + 2;
230             if (prefetchIndex < ptr->drawCmdListVec_.size()) {
231                 __builtin_prefetch(&(ptr->drawCmdListVec_[prefetchIndex]), 0, 1);
232             }
233 #endif
234             const auto& drawCmdList = ptr->drawCmdListVec_[i];
235             Drawing::Matrix mat;
236             if (ptr->isCanvasNode_ &&
237                 RSPropertyDrawableUtils::GetGravityMatrix(ptr->gravity_, *rect, drawCmdList->GetWidth(),
238                     drawCmdList->GetHeight(), mat)) {
239                 canvas->ConcatMatrix(mat);
240             }
241             drawCmdList->Playback(*canvas, rect);
242             if (ptr->needClearOp_ && ptr->type_ == RSModifierType::CONTENT_STYLE) {
243                 RS_PROFILER_DRAWING_NODE_ADD_CLEAROP(drawCmdList);
244             }
245         }
246     };
247 }
248 
249 // ============================================================================
250 // Save and Restore
RSSaveDrawable(std::shared_ptr<uint32_t> content)251 RSSaveDrawable::RSSaveDrawable(std::shared_ptr<uint32_t> content) : content_(std::move(content)) {}
CreateDrawFunc() const252 Drawing::RecordingCanvas::DrawFunc RSSaveDrawable::CreateDrawFunc() const
253 {
254     return [content = content_](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
255         // Save and return save count
256         *content = canvas->Save();
257     };
258 }
259 
RSRestoreDrawable(std::shared_ptr<uint32_t> content)260 RSRestoreDrawable::RSRestoreDrawable(std::shared_ptr<uint32_t> content) : content_(std::move(content)) {}
CreateDrawFunc() const261 Drawing::RecordingCanvas::DrawFunc RSRestoreDrawable::CreateDrawFunc() const
262 {
263     return [content = content_](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
264         // return to previous save count
265         canvas->RestoreToCount(*content);
266     };
267 }
268 
RSCustomSaveDrawable(std::shared_ptr<RSPaintFilterCanvas::SaveStatus> content,RSPaintFilterCanvas::SaveType type)269 RSCustomSaveDrawable::RSCustomSaveDrawable(
270     std::shared_ptr<RSPaintFilterCanvas::SaveStatus> content, RSPaintFilterCanvas::SaveType type)
271     : content_(std::move(content)), type_(type)
272 {}
CreateDrawFunc() const273 Drawing::RecordingCanvas::DrawFunc RSCustomSaveDrawable::CreateDrawFunc() const
274 {
275     return [content = content_, type = type_](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
276         auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
277         // Save and return save count
278         *content = paintFilterCanvas->SaveAllStatus(type);
279     };
280 }
281 
RSCustomRestoreDrawable(std::shared_ptr<RSPaintFilterCanvas::SaveStatus> content)282 RSCustomRestoreDrawable::RSCustomRestoreDrawable(std::shared_ptr<RSPaintFilterCanvas::SaveStatus> content)
283     : content_(std::move(content))
284 {}
CreateDrawFunc() const285 Drawing::RecordingCanvas::DrawFunc RSCustomRestoreDrawable::CreateDrawFunc() const
286 {
287     return [content = content_](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
288         auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
289         // return to previous save count
290         paintFilterCanvas->RestoreStatus(*content);
291     };
292 }
293 
OnGenerate(const RSRenderNode & node)294 RSDrawable::Ptr RSBeginBlenderDrawable::OnGenerate(const RSRenderNode& node)
295 {
296     if (auto ret = std::make_shared<RSBeginBlenderDrawable>(); ret->OnUpdate(node)) {
297         return std::move(ret);
298     }
299     return nullptr;
300 }
301 
OnUpdate(const RSRenderNode & node)302 bool RSBeginBlenderDrawable::OnUpdate(const RSRenderNode& node)
303 {
304     // the order of blender and blendMode cannot be considered currently
305     const RSProperties& properties = node.GetRenderProperties();
306     auto blendMode = properties.GetColorBlendMode();
307     stagingBlendApplyType_ = properties.GetColorBlendApplyType();
308     // NOTE: stagingIsDangerous_ should be set true when adding a blender that may generate transparent pixels
309     if (properties.IsFgBrightnessValid()) {
310         if (Rosen::RSSystemProperties::GetDebugTraceLevel() >= TRACE_LEVEL_TWO) {
311             stagingPropertyDescription_ = properties.GetFgBrightnessDescription();
312         }
313         stagingBlender_ = RSPropertyDrawableUtils::MakeDynamicBrightnessBlender(
314             properties.GetFgBrightnessParams().value());
315         stagingIsDangerous_ = false;
316     } else if (blendMode && blendMode != static_cast<int>(RSColorBlendMode::NONE)) {
317         if (Rosen::RSSystemProperties::GetDebugTraceLevel() >= TRACE_LEVEL_TWO) {
318             stagingPropertyDescription_ = "BlendMode, blendMode: " + std::to_string(blendMode) +
319                 " blendApplyType: " + std::to_string(stagingBlendApplyType_);
320         }
321         // map blendMode to Drawing::BlendMode and convert to Blender
322         stagingBlender_ = Drawing::Blender::CreateWithBlendMode(static_cast<Drawing::BlendMode>(blendMode - 1));
323         stagingIsDangerous_ = RSPropertyDrawableUtils::IsDangerousBlendMode(blendMode - 1, stagingBlendApplyType_);
324     } else {
325         return false;
326     }
327 
328     needSync_ = true;
329 
330     return true;
331 }
332 
OnSync()333 void RSBeginBlenderDrawable::OnSync()
334 {
335     if (needSync_ == false) {
336         return;
337     }
338     blender_ = stagingBlender_;
339     blendApplyType_ = stagingBlendApplyType_;
340     propertyDescription_ = stagingPropertyDescription_;
341     stagingPropertyDescription_.clear();
342     needSync_ = false;
343 }
344 
CreateDrawFunc() const345 Drawing::RecordingCanvas::DrawFunc RSBeginBlenderDrawable::CreateDrawFunc() const
346 {
347     auto ptr = std::static_pointer_cast<const RSBeginBlenderDrawable>(shared_from_this());
348     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
349         auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
350         if (paintFilterCanvas == nullptr) {
351             return;
352         }
353         RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "RSBeginBlenderDrawable:: %s, bounds: %s",
354             ptr->propertyDescription_.c_str(), rect->ToString().c_str());
355         RSPropertyDrawableUtils::BeginBlender(*paintFilterCanvas, ptr->blender_, ptr->blendApplyType_,
356             ptr->isDangerous_);
357     };
358 }
359 
OnGenerate(const RSRenderNode & node)360 RSDrawable::Ptr RSEndBlenderDrawable::OnGenerate(const RSRenderNode& node)
361 {
362     if (auto ret = std::make_shared<RSEndBlenderDrawable>(); ret->OnUpdate(node)) {
363         return std::move(ret);
364     }
365     return nullptr;
366 };
367 
OnUpdate(const RSRenderNode & node)368 bool RSEndBlenderDrawable::OnUpdate(const RSRenderNode& node)
369 {
370     const RSProperties& properties = node.GetRenderProperties();
371     if (properties.GetColorBlendMode() == static_cast<int>(RSColorBlendMode::NONE) ||
372         properties.GetColorBlendApplyType() == static_cast<int>(RSColorBlendApplyType::FAST)) {
373         // no blend
374         return false;
375     }
376 
377     stagingBlendApplyType_ = properties.GetColorBlendApplyType();
378     needSync_ = true;
379 
380     return true;
381 }
382 
OnSync()383 void RSEndBlenderDrawable::OnSync()
384 {
385     if (needSync_ == false) {
386         return;
387     }
388     blendApplyType_ = stagingBlendApplyType_;
389     needSync_ = false;
390 }
391 
CreateDrawFunc() const392 Drawing::RecordingCanvas::DrawFunc RSEndBlenderDrawable::CreateDrawFunc() const
393 {
394     auto ptr = std::static_pointer_cast<const RSEndBlenderDrawable>(shared_from_this());
395     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
396         auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
397         RSPropertyDrawableUtils::EndBlender(*paintFilterCanvas, ptr->blendApplyType_);
398     };
399 }
400 
401 // ============================================================================
402 // EnvFGColor
OnGenerate(const RSRenderNode & node)403 RSDrawable::Ptr RSEnvFGColorDrawable::OnGenerate(const RSRenderNode& node)
404 {
405     if (auto ret = std::make_shared<RSEnvFGColorDrawable>(); ret->OnUpdate(node)) {
406         return std::move(ret);
407     }
408     return nullptr;
409 }
410 
OnUpdate(const RSRenderNode & node)411 bool RSEnvFGColorDrawable::OnUpdate(const RSRenderNode& node)
412 {
413     auto& drawCmdModifiers = const_cast<RSRenderContent::DrawCmdContainer&>(node.GetDrawCmdModifiers());
414     auto itr = drawCmdModifiers.find(RSModifierType::ENV_FOREGROUND_COLOR);
415     if (itr == drawCmdModifiers.end() || itr->second.empty()) {
416         return false;
417     }
418     const auto& modifier = itr->second.back();
419     auto renderProperty = std::static_pointer_cast<RSRenderAnimatableProperty<Color>>(modifier->GetProperty());
420     stagingEnvFGColor_ = renderProperty->Get();
421     needSync_ = true;
422     return true;
423 }
424 
OnSync()425 void RSEnvFGColorDrawable::OnSync()
426 {
427     if (!needSync_) {
428         return;
429     }
430     envFGColor_ = stagingEnvFGColor_;
431     needSync_ = false;
432 }
433 
CreateDrawFunc() const434 Drawing::RecordingCanvas::DrawFunc RSEnvFGColorDrawable::CreateDrawFunc() const
435 {
436     auto ptr = std::static_pointer_cast<const RSEnvFGColorDrawable>(shared_from_this());
437     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
438         auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
439         // planning: implement alpha offscreen
440         paintFilterCanvas->SetEnvForegroundColor(ptr->envFGColor_);
441     };
442 }
443 
444 // ============================================================================
445 // EnvFGColorStrategy
OnGenerate(const RSRenderNode & node)446 RSDrawable::Ptr RSEnvFGColorStrategyDrawable::OnGenerate(const RSRenderNode& node)
447 {
448     if (auto ret = std::make_shared<RSEnvFGColorStrategyDrawable>(); ret->OnUpdate(node)) {
449         return std::move(ret);
450     }
451     return nullptr;
452 }
453 
OnUpdate(const RSRenderNode & node)454 bool RSEnvFGColorStrategyDrawable::OnUpdate(const RSRenderNode& node)
455 {
456     auto& drawCmdModifiers = const_cast<RSRenderContent::DrawCmdContainer&>(node.GetDrawCmdModifiers());
457     auto itr = drawCmdModifiers.find(RSModifierType::ENV_FOREGROUND_COLOR_STRATEGY);
458     if (itr == drawCmdModifiers.end() || itr->second.empty()) {
459         return false;
460     }
461     const auto& modifier = itr->second.back();
462     auto property = std::static_pointer_cast<RSRenderProperty<ForegroundColorStrategyType>>(modifier->GetProperty());
463     stagingEnvFGColorStrategy_ = property->Get();
464     const auto& renderProperties = node.GetRenderProperties();
465     stagingBackgroundColor_ = renderProperties.GetBackgroundColor();
466     stagingNeedClipToBounds_ = renderProperties.GetClipToBounds();
467     stagingBoundsRect_ = renderProperties.GetBounds();
468     needSync_ = true;
469     return true;
470 }
471 
OnSync()472 void RSEnvFGColorStrategyDrawable::OnSync()
473 {
474     if (!needSync_) {
475         return;
476     }
477     envFGColorStrategy_ = stagingEnvFGColorStrategy_;
478     backgroundColor_ = stagingBackgroundColor_;
479     needClipToBounds_ = stagingNeedClipToBounds_;
480     boundsRect_ = stagingBoundsRect_;
481     needSync_ = false;
482 }
483 
CreateDrawFunc() const484 Drawing::RecordingCanvas::DrawFunc RSEnvFGColorStrategyDrawable::CreateDrawFunc() const
485 {
486     auto ptr = std::static_pointer_cast<const RSEnvFGColorStrategyDrawable>(shared_from_this());
487     return [this, ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
488         auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
489         switch (envFGColorStrategy_) {
490             case ForegroundColorStrategyType::INVERT_BACKGROUNDCOLOR: {
491                 // calculate the color by screebshot
492                 Color color = RSPropertyDrawableUtils::GetInvertBackgroundColor(*paintFilterCanvas, needClipToBounds_,
493                     boundsRect_, backgroundColor_);
494                 paintFilterCanvas->SetEnvForegroundColor(color);
495                 break;
496             }
497             default: {
498                 break;
499             }
500         }
501     };
502 }
503 
OnGenerate(const RSRenderNode & node)504 RSDrawable::Ptr RSCustomClipToFrameDrawable::OnGenerate(const RSRenderNode& node)
505 {
506     if (auto ret = std::make_shared<RSCustomClipToFrameDrawable>(); ret->OnUpdate(node)) {
507         return std::move(ret);
508     }
509     return nullptr;
510 }
511 
OnUpdate(const RSRenderNode & node)512 bool RSCustomClipToFrameDrawable::OnUpdate(const RSRenderNode& node)
513 {
514     auto& drawCmdModifiers = const_cast<RSRenderContent::DrawCmdContainer&>(node.GetDrawCmdModifiers());
515     auto itr = drawCmdModifiers.find(RSModifierType::CUSTOM_CLIP_TO_FRAME);
516     if (itr == drawCmdModifiers.end() || itr->second.empty()) {
517         return false;
518     }
519     const auto& modifier = itr->second.back();
520     auto renderProperty = std::static_pointer_cast<RSRenderAnimatableProperty<Vector4f>>(modifier->GetProperty());
521     const auto& clipRectV4f = renderProperty->Get();
522     stagingCustomClipRect_ = Drawing::Rect(clipRectV4f.x_, clipRectV4f.y_, clipRectV4f.z_, clipRectV4f.w_);
523     needSync_ = true;
524     return true;
525 }
526 
OnSync()527 void RSCustomClipToFrameDrawable::OnSync()
528 {
529     if (!needSync_) {
530         return;
531     }
532     customClipRect_ = stagingCustomClipRect_;
533     needSync_ = false;
534 }
535 
CreateDrawFunc() const536 Drawing::RecordingCanvas::DrawFunc RSCustomClipToFrameDrawable::CreateDrawFunc() const
537 {
538     auto ptr = std::static_pointer_cast<const RSCustomClipToFrameDrawable>(shared_from_this());
539     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
540         canvas->ClipRect(ptr->customClipRect_);
541     };
542 }
543 
544 } // namespace DrawableV2
545 } // namespace OHOS::Rosen
546