1 /*
2 * Copyright (c) 2021-2022 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 "core/components/list/render_list_item.h"
17
18 #include "base/log/dump_log.h"
19 #include "core/common/vibrator/vibrator_proxy.h"
20 #include "core/components/flex/render_flex.h"
21 #include "core/components/list/render_list_item_group.h"
22 #include "core/components/list/tv_interactive_effect.h"
23 #ifdef WEARABLE_PRODUCT
24 #include "core/components/list/watch_interactive_effect.h"
25 #endif
26
27 namespace OHOS::Ace {
28 namespace {
29
30 const double HALF_SIZE = 0.5;
31 const double ITEM_DISTANCE_BASE = 76.0;
32 const double ITEM_DEFAULT_SCALE = 1.0;
33 const double ITEM_ZERO = 0.0;
34 const double ITEM_SCALE_BASE = 1.12;
35 const double ITEM_OPACITY_BASE = 1.0;
36 const double ITEM_RATIO = -0.34; // 0.78 - 1.12 // 0.66 - 1.0
37 const double DISTANCE_EPSILON = 1.0;
38 constexpr int32_t MIN_COMPATITABLE_VERSION = 5;
39 const double WATCH_SIZE = 466.0;
40
41 #ifdef WEARABLE_PRODUCT
42 const std::string& VIBRATOR_TYPE_WATCH_CROWN_STRENGTH1 = "watchhaptic.crown.strength1";
43 #endif
44
45 } // namespace
46
RenderListItem()47 RenderListItem::RenderListItem()
48 {
49 Initialize();
50 }
51
Initialize()52 void RenderListItem::Initialize()
53 {
54 clickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
55 clickRecognizer_->SetOnClick([weakItem = AceType::WeakClaim(this)](const ClickInfo&) {
56 auto item = weakItem.Upgrade();
57 if (item) {
58 item->HandleClicked();
59 }
60 });
61 touchRecognizer_ = AceType::MakeRefPtr<RawRecognizer>();
62 touchRecognizer_->SetOnTouchDown([weakItem = AceType::WeakClaim(this)](const TouchEventInfo&) {
63 auto item = weakItem.Upgrade();
64 if (item && item->GetSupportClick()) {
65 item->PlayPressDownAnimation();
66 }
67 });
68 touchRecognizer_->SetOnTouchUp([weakItem = AceType::WeakClaim(this)](const TouchEventInfo&) {
69 auto item = weakItem.Upgrade();
70 if (item && item->GetSupportClick()) {
71 item->PlayPressUpAnimation();
72 }
73 });
74 touchRecognizer_->SetOnTouchCancel([weakItem = AceType::WeakClaim(this)](const TouchEventInfo&) {
75 auto item = weakItem.Upgrade();
76 if (item && item->GetSupportClick()) {
77 item->PlayPressUpAnimation();
78 }
79 });
80 }
81
PerformLayout()82 void RenderListItem::PerformLayout()
83 {
84 if (!GetChildren().empty()) {
85 auto child = GetChildren().front();
86 auto context = context_.Upgrade();
87 if (NeedDivider() && context && context->GetIsDeclarative()) {
88 auto layoutParam = GetLayoutParam();
89 auto maxSize = layoutParam.GetMaxSize();
90 auto dividerSize = IsListVertical() ? Size(0.0, NormalizeToPx(dividerHeight_))
91 : Size(NormalizeToPx(dividerHeight_), 0.0);
92 maxSize = maxSize - dividerSize;
93 layoutParam.SetMaxSize(maxSize);
94 child->Layout(layoutParam);
95 } else {
96 child->Layout(GetLayoutParam());
97 }
98 child->SetPosition(Offset::Zero());
99 if (NeedDivider()) {
100 auto dividerSize = IsListVertical() ? Size(0.0, NormalizeToPx(dividerHeight_))
101 : Size(NormalizeToPx(dividerHeight_), 0.0);
102 SetLayoutSize(dividerSize + child->GetLayoutSize());
103 } else {
104 SetLayoutSize(child->GetLayoutSize());
105 }
106 // update focus animation size
107 focusAnimationRRect_.SetRect(Rect(Offset(0, 0), GetPaintSize() * TV_ITEM_SCALE));
108
109 if (SystemProperties::GetDeviceType() == DeviceType::WATCH) {
110 CalculateScaleFactorOnWatch();
111 }
112 }
113 }
114
CalculateScaleFactorOnWatch()115 void RenderListItem::CalculateScaleFactorOnWatch()
116 {
117 if (isTitle_) {
118 return;
119 }
120
121 auto context = GetContext().Upgrade();
122 const static int32_t PLATFORM_VERSION_FIVE = 5;
123 if (context && context->GetMinPlatformVersion() <= PLATFORM_VERSION_FIVE) {
124 Offset itemCenter = GetGlobalOffset() + GetLayoutSize() * HALF_SIZE;
125 double scale = ITEM_DEFAULT_SCALE;
126 double viewScale = ITEM_DEFAULT_SCALE;
127 auto pipelineContext = context_.Upgrade();
128 if (pipelineContext) {
129 scale = pipelineContext->GetDipScale();
130 viewScale = pipelineContext->GetViewScale();
131 }
132 if (NearZero(scale) || NearZero(viewScale)) {
133 LOGE("pipeline parameter is invalid");
134 return;
135 }
136 auto distance = std::abs(itemCenter.GetY() - WATCH_SIZE / viewScale * HALF_SIZE);
137 auto ratio = std::pow(distance, SQUARE) * ITEM_RATIO / std::pow(ITEM_DISTANCE_BASE * scale, SQUARE);
138 scaleFactor_ = std::max(ITEM_ZERO, ratio + ITEM_SCALE_BASE);
139 opacityFactor_ = std::max(ITEM_ZERO, ratio + ITEM_OPACITY_BASE);
140 } else {
141 auto renderList = GetRenderList();
142 if (!renderList) {
143 LOGE("Can not find parent render list");
144 return;
145 }
146
147 double itemSize = renderList->IsVertical() ? GetLayoutSize().Height() : GetLayoutSize().Width();
148 double itemCenter = GetPositionInList() + renderList->GetListPosition() + itemSize * HALF_SIZE;
149 double scale = ITEM_DEFAULT_SCALE;
150 auto pipelineContext = context_.Upgrade();
151 if (pipelineContext) {
152 scale = pipelineContext->GetDipScale();
153 }
154 if (NearZero(scale)) {
155 LOGE("Pipeline parameter is invalid");
156 return;
157 }
158 double viewPort = renderList->IsVertical() ? viewPort_.Height() : viewPort_.Width();
159 auto distance = std::abs(itemCenter - viewPort * HALF_SIZE);
160 if (NearZero(distance, DISTANCE_EPSILON)) {
161 distance = 0.0;
162 }
163 auto ratio = std::pow(distance, SQUARE) * ITEM_RATIO / std::pow(ITEM_DISTANCE_BASE * scale, SQUARE);
164 scaleFactor_ = std::max(ITEM_ZERO, ratio + ITEM_SCALE_BASE);
165 opacityFactor_ = std::max(ITEM_ZERO, ratio + ITEM_OPACITY_BASE);
166 }
167 }
168
Update(const RefPtr<Component> & component)169 void RenderListItem::Update(const RefPtr<Component>& component)
170 {
171 itemComponent_ = component;
172 auto item = AceType::DynamicCast<ListItemComponent>(component);
173 if (item) {
174 type_ = item->GetType();
175 index_ = item->GetIndex();
176 columnSpan_ = item->GetColumnSpan();
177 op_ = item->GetOperation();
178 flags_ = item->GetFlags();
179 // update focus animation color
180 focusAnimationColor_ = item->GetFocusAnimationColor();
181 // update focus animation corner radius
182 focusAnimationRRect_.SetCorner({ item->GetTopLeftRadius(), item->GetTopRightRadius(),
183 item->GetBottomRightRadius(), item->GetBottomLeftRadius() });
184
185 needVibrate_ = item->NeedVibrate();
186 auto context = context_.Upgrade();
187 if (needVibrate_ && !vibrator_ && context) {
188 vibrator_ = VibratorProxy::GetInstance().GetVibrator(context->GetTaskExecutor());
189 }
190
191 rotationVibrate_ = item->IsRotationVibrate();
192 if (rotationVibrate_ && !vibrator_ && context) {
193 vibrator_ = VibratorProxy::GetInstance().GetVibrator(context->GetTaskExecutor());
194 }
195
196 supportScale_ = item->GetSupportScale();
197 supportOpacity_ = item->GetSupportOpacity();
198 supportClick_ = item->GetSupportClick();
199 isTitle_ = item->IsTitle();
200 sticky_ = item->GetSticky();
201 stickyMode_ = item->GetStickyMode();
202 clickColor_ = item->GetClickColor();
203 selfAlign_ = item->GetAlignSelf();
204 Dimension radius = item->GetStickyRadius();
205 if (radius.IsValid()) {
206 stickyRadius_ = context ? context->NormalizeToPx(radius) : stickyRadius_;
207 }
208
209 if (!primary_ && item->GetPrimary()) {
210 NotifyGroupPrimaryChange();
211 }
212 SetPrimary(item->GetPrimary());
213
214 // list divider
215 needDivider_ = item->NeedDivider();
216 isActive_ = item->IsActive();
217 dividerLength_ = item->GetDividerLength();
218 dividerHeight_ = item->GetDividerHeight();
219 dividerOrigin_ = item->GetDividerOrigin();
220 dividerColor_ = item->GetDividerColor();
221 auto onClickId = item->GetClickEventId();
222 clickEvent_ = AceAsyncEvent<void()>::Create(onClickId, GetContext());
223 clickRecognizer_->SetUseCatchMode(true);
224 if (!onClickId.GetCatchMode()) {
225 static const int32_t bubbleModeVersion = 6;
226 auto pipeline = context_.Upgrade();
227 if (pipeline && pipeline->GetMinPlatformVersion() >= bubbleModeVersion) {
228 clickRecognizer_->SetUseCatchMode(false);
229 return;
230 }
231 }
232 stickyEvent_ = AceAsyncEvent<void(const std::string&)>::Create(item->GetStickyEventId(), GetContext());
233 transitionEffect_ = item->GetTransitionEffect();
234 UpdateAccessibilityAttr();
235 MarkNeedLayout();
236 }
237 }
238
NotifyGroupPrimaryChange()239 void RenderListItem::NotifyGroupPrimaryChange()
240 {
241 auto parent = GetParent().Upgrade();
242 while (parent) {
243 auto group = AceType::DynamicCast<RenderListItemGroup>(parent);
244 if (group) {
245 group->ItemPrimaryChange(GetIndex());
246 break;
247 }
248 parent = parent->GetParent().Upgrade();
249 }
250 }
251
GetPositionInList() const252 double RenderListItem::GetPositionInList() const
253 {
254 RefPtr<RenderNode> parentNode = GetParent().Upgrade();
255 while (parentNode) {
256 RefPtr<RenderList> listNode = AceType::DynamicCast<RenderList>(parentNode);
257 if (listNode) {
258 return listNode->GetItemPosition(index_);
259 }
260 parentNode = parentNode->GetParent().Upgrade();
261 }
262 return 0.0;
263 }
264
IsItemCenter(bool isVertical,Size viewport)265 bool RenderListItem::IsItemCenter(bool isVertical, Size viewport)
266 {
267 auto parent = GetParent().Upgrade();
268 if (!parent) {
269 return false;
270 }
271 Size itemSize = GetLayoutSize();
272 Offset itemPosition = parent->GetPosition();
273 double size = isVertical ? itemSize.Height() : itemSize.Width();
274 double position = isVertical ? itemPosition.GetY() : itemPosition.GetX();
275 double center = (isVertical ? viewport.Height() : viewport.Width()) / 2.0;
276 return center > position && center < (position + size);
277 }
278
ResetFocusEffect()279 void RenderListItem::ResetFocusEffect()
280 {
281 #ifdef WEARABLE_PRODUCT
282 if (SystemProperties::GetDeviceType() == DeviceType::WATCH) {
283 focusController_ = AceType::MakeRefPtr<WatchInteractiveEffect>(GetContext());
284 #else
285 if (SystemProperties::GetDeviceType() == DeviceType::TV) {
286 focusController_ = AceType::MakeRefPtr<TVInteractiveEffect>(GetContext());
287 #endif
288 } else {
289 focusController_ = AceType::MakeRefPtr<InteractiveEffect>(GetContext());
290 }
291 focusController_->Initialize(GetThemeManager());
292 focusController_->SetItemNode(AceType::WeakClaim(this));
293 auto listNode = GetRenderList();
294 if (listNode) {
295 auto weakList = WeakPtr<RenderList>(listNode);
296 focusController_->SetListNode(weakList);
297 }
298 }
299
300 void RenderListItem::HandleItemEffect(bool isFromRotate)
301 {
302 if (!focusController_) {
303 ResetFocusEffect();
304 }
305
306 if (currentState_ != lastState_) {
307 #ifdef WEARABLE_PRODUCT
308 if (needVibrate_ && lastState_ == ItemState::NEARBY && currentState_ == ItemState::FOCUS && vibrator_) {
309 vibrator_->Vibrate(VIBRATOR_TYPE_WATCH_CROWN_STRENGTH1);
310 }
311 if (rotationVibrate_ && isFromRotate && vibrator_) {
312 vibrator_->Vibrate(VIBRATOR_TYPE_WATCH_CROWN_STRENGTH1);
313 }
314 #endif
315 lastState_ = currentState_;
316 if (currentState_ != ItemState::NONE && currentState_ != ItemState::CLICK) {
317 focusController_->ShowAnimation(currentState_);
318 } else {
319 // invalid focus
320 }
321 }
322 MarkNeedRender();
323 }
324
325 void RenderListItem::HandleClicked()
326 {
327 if (clickEvent_) {
328 clickEvent_();
329 }
330
331 if (primary_ && clicked_) {
332 clicked_();
333 }
334 }
335
336 void RenderListItem::PlayPressDownAnimation()
337 {
338 if (!focusController_) {
339 ResetFocusEffect();
340 }
341 pressAnimation_ = true;
342 focusController_->TouchDownAnimation();
343 }
344
345 void RenderListItem::PlayPressUpAnimation()
346 {
347 if (!focusController_) {
348 ResetFocusEffect();
349 }
350 pressAnimation_ = false;
351 focusController_->TouchUpAnimation();
352 }
353
354 void RenderListItem::OnCancelPressAnimation()
355 {
356 if (!pressAnimation_) {
357 return;
358 }
359 if (!focusController_) {
360 ResetFocusEffect();
361 }
362 focusController_->CancelTouchAnimation();
363 }
364
365 void RenderListItem::HandleStickyEvent(bool sticky)
366 {
367 std::string state = sticky ? "true" : "false";
368 std::string param = std::string(R"("sticky",{"state":)").append(state).append("},null");
369 if (stickyEvent_) {
370 stickyEvent_(param);
371 }
372 }
373
374 void RenderListItem::OnTouchTestHit(
375 const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
376 {
377 if (!GetVisible() && !GetClonedBySticky()) {
378 return;
379 }
380 // supportClick means show click effect
381 bool supportClick = supportClick_;
382 auto pipeline = context_.Upgrade();
383 if (pipeline && pipeline->GetMinPlatformVersion() > MIN_COMPATITABLE_VERSION) {
384 supportClick = true;
385 }
386 if ((!touchRecognizer_) || (!clickRecognizer_) || (!supportClick)) {
387 return;
388 }
389 touchRecognizer_->SetCoordinateOffset(coordinateOffset);
390 clickRecognizer_->SetCoordinateOffset(coordinateOffset);
391 result.emplace_back(touchRecognizer_);
392 result.emplace_back(clickRecognizer_);
393 }
394
395 void RenderListItem::UpdateItemFocusRect(double scale)
396 {
397 focusAnimationRRect_.SetRect(Rect(Offset(0.0, 0.0), GetPaintSize() * scale));
398 }
399
400 void RenderListItem::HandleFocusEvent(bool focus, bool isInGroup)
401 {
402 if (SystemProperties::GetDeviceType() == DeviceType::WATCH) {
403 return;
404 }
405 focused_ = focus;
406
407 ShowFocusAnimation(focus, Rect(0.0, 0.0, 0.0, 0.0));
408
409 if (focus) {
410 ChangeStatus(RenderStatus::FOCUS);
411 currentState_ = ItemState::FOCUS;
412 if (isInGroup) {
413 HandleItemEffect();
414 return;
415 }
416 RefPtr<RenderNode> parentNode = GetParent().Upgrade();
417 while (parentNode) {
418 RefPtr<RenderList> listNode = AceType::DynamicCast<RenderList>(parentNode);
419 if (listNode) {
420 listNode->ListItemFocused(index_);
421 break;
422 }
423 parentNode = parentNode->GetParent().Upgrade();
424 }
425 } else {
426 ChangeStatus(RenderStatus::BLUR);
427 currentState_ = ItemState::BLUR;
428 }
429 HandleItemEffect();
430 }
431
432 Offset RenderListItem::GetPaintOffset() const
433 {
434 auto globalOffset = GetGlobalOffset();
435 auto layoutSize = GetLayoutSize(); // size include margin
436 auto paintSize = GetPaintSize(); // size exclude margin
437 auto margin = GetMarginInPx();
438 if (layoutSize > paintSize) {
439 globalOffset.SetX(globalOffset.GetX() + margin.LeftPx());
440 globalOffset.SetY(globalOffset.GetY() + margin.TopPx());
441 }
442 return globalOffset;
443 }
444
445 EdgePx RenderListItem::GetMarginInPx() const
446 {
447 EdgePx marginInPx;
448 auto children = GetChildren();
449 if (children.empty()) {
450 return marginInPx;
451 }
452
453 auto child = children.front();
454 while (child) {
455 auto box = AceType::DynamicCast<RenderBoxBase>(child);
456 if (box) {
457 auto boxChildren = box->GetChildren();
458 if (boxChildren.empty()) {
459 break;
460 }
461 auto boxChild = boxChildren.front();
462 if (boxChild && AceType::DynamicCast<RenderFlex>(boxChild)) {
463 marginInPx = box->GetMargin();
464 break;
465 }
466 }
467 children = child->GetChildren();
468 if (children.empty()) {
469 break;
470 }
471 child = children.front();
472 }
473 return marginInPx;
474 }
475
476 Size RenderListItem::GetPaintSize() const
477 {
478 Size size = GetLayoutSize();
479 auto margin = GetMarginInPx();
480 return size - margin.GetLayoutSize();
481 }
482
483 Border RenderListItem::GetFocusBorder() const
484 {
485 Border border;
486 border.SetTopRightRadius(focusAnimationRRect_.GetCorner().topRightRadius);
487 border.SetTopLeftRadius(focusAnimationRRect_.GetCorner().topLeftRadius);
488 border.SetBottomLeftRadius(focusAnimationRRect_.GetCorner().bottomLeftRadius);
489 border.SetBottomRightRadius(focusAnimationRRect_.GetCorner().bottomRightRadius);
490 return border;
491 }
492
493 void RenderListItem::ShowFocusAnimation(bool focus, const Rect& listRect, double scale)
494 {
495 // paint focus animation
496 auto context = context_.Upgrade();
497 if (!context) {
498 LOGE("[Focus]Pipeline context is nullptr");
499 return;
500 }
501
502 if (focus) {
503 Size size = GetPaintSize();
504 auto globalOffset = GetPaintOffset() + (size * (DEFAULT_SCALE - scale) * HALF_SIZE);
505 if (listRect.IsValid()) {
506 context->ShowFocusAnimation(focusAnimationRRect_, focusAnimationColor_, globalOffset, listRect);
507 context->ShowShadow(focusAnimationRRect_, globalOffset);
508 } else {
509 context->ShowFocusAnimation(focusAnimationRRect_, focusAnimationColor_, globalOffset);
510 context->ShowShadow(focusAnimationRRect_, globalOffset);
511 }
512 } else {
513 context->CancelFocusAnimation();
514 context->CancelShadow();
515 }
516 }
517
518 void RenderListItem::UpdateAccessibilityAttr()
519 {
520 auto refPtr = accessibilityNode_.Upgrade();
521 if (!refPtr) {
522 return;
523 }
524
525 refPtr->SetClickableState(true);
526 refPtr->SetActionClickImpl([weakItem = AceType::WeakClaim(this)]() {
527 auto item = weakItem.Upgrade();
528 if (item) {
529 LOGI("Trigger ActionClick by Accessibility(%{public}d).", item->index_);
530 item->HandleClicked();
531 item->OnGroupClicked();
532 }
533 });
534
535 refPtr->SetFocusableState(true);
536 refPtr->SetActionFocusImpl([weakItem = AceType::WeakClaim(this)]() {
537 auto item = weakItem.Upgrade();
538 if (item) {
539 LOGI("Trigger ActionFocus by Accessibility(%{public}d).", item->index_);
540 item->MoveToViewPort();
541 }
542 });
543 refPtr->AddSupportAction(AceAction::ACTION_ACCESSIBILITY_FOCUS);
544 }
545
546 void RenderListItem::OnGroupClicked()
547 {
548 if (!primary_ || !curPrimary_) {
549 return; // Only trigger group click when current item is primary.
550 }
551 RefPtr<RenderNode> parent = GetParent().Upgrade();
552 while (parent) {
553 RefPtr<RenderListItemGroup> group = AceType::DynamicCast<RenderListItemGroup>(parent);
554 if (group) {
555 return group->HandleClicked();
556 }
557 parent = parent->GetParent().Upgrade();
558 }
559 }
560
561 void RenderListItem::MoveToViewPort()
562 {
563 RefPtr<RenderNode> parentNode = GetParent().Upgrade();
564 while (parentNode) {
565 RefPtr<RenderList> listNode = AceType::DynamicCast<RenderList>(parentNode);
566 if (listNode) {
567 return listNode->MoveItemToViewPort(GetPositionInList());
568 }
569 parentNode = parentNode->GetParent().Upgrade();
570 }
571 }
572
573 RefPtr<RenderList> RenderListItem::GetRenderList() const
574 {
575 auto parent = GetParent().Upgrade();
576 while (parent) {
577 auto parentNode = AceType::DynamicCast<RenderList>(parent);
578 if (parentNode) {
579 return parentNode;
580 }
581 parent = parent->GetParent().Upgrade();
582 }
583 return nullptr;
584 }
585
586 bool RenderListItem::NeedDivider()
587 {
588 return needDivider_ && !IsLastItem();
589 }
590
591 bool RenderListItem::IsLastItem()
592 {
593 auto renderList = GetRenderList();
594 if (renderList) {
595 int32_t maxCount = renderList->GetMaxCount();
596 if (GetIndex() == maxCount - 1) {
597 return true;
598 }
599 }
600 return false;
601 }
602
603 bool RenderListItem::IsListVertical()
604 {
605 auto renderList = GetRenderList();
606 if (renderList) {
607 FlexDirection listDirection = renderList->GetDirection();
608 return listDirection == FlexDirection::COLUMN || listDirection == FlexDirection::COLUMN_REVERSE;
609 }
610 return true;
611 }
612
613 void RenderListItem::Dump()
614 {
615 DumpLog::GetInstance().AddDesc(std::string("index: ").append(std::to_string(GetIndex())));
616 }
617
618 void RenderListItem::RunCardTransitionAnimation(double shiftHeight)
619 {
620 auto renderList = GetRenderList();
621 if (!renderList) {
622 LOGE("list render is null");
623 return;
624 }
625 makeCardTransition_ = true;
626 renderList->SetMakeCardTransition(makeCardTransition_);
627 if (transitionEffect_ == TransitionEffect::UNFOLD) {
628 renderList->SetShiftHeight(shiftHeight);
629 } else {
630 renderList->SetShiftHeight(0.0);
631 }
632 renderList->MarkNeedRender();
633 }
634
635 void RenderListItem::StopCardTransitionAnimation()
636 {
637 makeCardTransition_ = false;
638 auto renderList = GetRenderList();
639 if (renderList) {
640 renderList->SetMakeCardTransition(makeCardTransition_);
641 renderList->SetShiftHeight(0.0);
642 renderList->MarkNeedRender();
643 }
644 }
645
646 RRect RenderListItem::GetRRect() const
647 {
648 auto child = GetFirstChild();
649 while (child) {
650 auto childNode = AceType::DynamicCast<RenderBox>(child);
651 if (childNode) {
652 auto margin = childNode->GetMargin();
653 auto rrect = RRect(Rect(childNode->GetGlobalOffset() + margin.GetOffset(),
654 childNode->GetLayoutSize() - margin.GetLayoutSize()));
655 if (childNode->GetBackDecoration()) {
656 auto border = childNode->GetBackDecoration()->GetBorder();
657 rrect.SetCorner({ border.TopLeftRadius(), border.TopRightRadius(),
658 border.BottomLeftRadius(), border.BottomRightRadius() });
659 }
660 return rrect;
661 }
662 child = child->GetFirstChild();
663 }
664 return RRect();
665 }
666
667 } // namespace OHOS::Ace
668