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