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