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