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