1 /*
2  * Copyright (c) 2022-2023 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 #include "core/components_ng/pattern/rating/rating_pattern.h"
16 
17 #include <cstdint>
18 #include <iomanip>
19 #include <sstream>
20 
21 #include "base/memory/ace_type.h"
22 #include "base/utils/utils.h"
23 #include "core/common/recorder/event_recorder.h"
24 #include "core/common/recorder/node_data_cache.h"
25 #include "core/components/common/properties/color.h"
26 #include "core/components/theme/icon_theme.h"
27 #include "core/components_ng/base/inspector_filter.h"
28 #include "core/components_ng/pattern/rating/rating_model_ng.h"
29 #include "core/components_ng/pattern/rating/rating_paint_method.h"
30 #include "core/components_ng/property/property.h"
31 #include "core/components_ng/render/canvas_image.h"
32 #include "core/components_ng/render/drawing.h"
33 #include "core/image/image_source_info.h"
34 #include "core/pipeline_ng/pipeline_context.h"
35 
36 namespace OHOS::Ace::NG {
37 constexpr int32_t RATING_IMAGE_SUCCESS_CODE = 0b111;
38 constexpr int32_t DEFAULT_RATING_TOUCH_STAR_NUMBER = 0;
39 
OnAttachToFrameNode()40 void RatingPattern::OnAttachToFrameNode()
41 {
42     auto host = GetHost();
43     CHECK_NULL_VOID(host);
44     auto pipeline = GetContext();
45     CHECK_NULL_VOID(pipeline);
46     auto ratingTheme = pipeline->GetTheme<RatingTheme>();
47     CHECK_NULL_VOID(ratingTheme);
48     themeStarNum_ = ratingTheme->GetStarNum();
49     themeStepSize_ = ratingTheme->GetStepSize();
50     themeRatingScore_ = ratingTheme->GetRatingScore();
51     themeBorderWidth_ = ratingTheme->GetFocusBorderWidth();
52 }
53 
CheckImageInfoHasChangedOrNot(int32_t imageFlag,const ImageSourceInfo & sourceInfo,const std::string & lifeCycleTag)54 void RatingPattern::CheckImageInfoHasChangedOrNot(
55     int32_t imageFlag, const ImageSourceInfo& sourceInfo, const std::string& lifeCycleTag)
56 {
57     auto ratingLayoutProperty = GetLayoutProperty<RatingLayoutProperty>();
58     CHECK_NULL_VOID(ratingLayoutProperty);
59     auto currentSourceInfo = ImageSourceInfo("");
60     switch (imageFlag) {
61         case 0b001:
62             currentSourceInfo = ratingLayoutProperty->GetForegroundImageSourceInfo().value_or(ImageSourceInfo(""));
63             CHECK_NULL_VOID(currentSourceInfo == sourceInfo);
64             if (lifeCycleTag == "ImageDataFailed") {
65                 TAG_LOGW(AceLogTag::ACE_SELECT_COMPONENT,
66                     "Rating load foreground image failed, the sourceInfo is %{public}s", sourceInfo.ToString().c_str());
67             }
68             break;
69         case 0b010:
70             currentSourceInfo = ratingLayoutProperty->GetSecondaryImageSourceInfo().value_or(ImageSourceInfo(""));
71             CHECK_NULL_VOID(currentSourceInfo == sourceInfo);
72             if (lifeCycleTag == "ImageDataFailed") {
73                 TAG_LOGW(AceLogTag::ACE_SELECT_COMPONENT,
74                     "Rating load secondary image failed, the sourceInfo is %{public}s", sourceInfo.ToString().c_str());
75             }
76             break;
77         case 0b100:
78             currentSourceInfo = ratingLayoutProperty->GetBackgroundImageSourceInfo().value_or(ImageSourceInfo(""));
79             CHECK_NULL_VOID(currentSourceInfo == sourceInfo);
80             if (lifeCycleTag == "ImageDataFailed") {
81                 TAG_LOGW(AceLogTag::ACE_SELECT_COMPONENT,
82                     "Rating load background image failed, the sourceInfo is %{public}s", sourceInfo.ToString().c_str());
83             }
84             break;
85         default:
86             break;
87     }
88 }
89 
CreateLoadSuccessCallback(int32_t imageFlag)90 LoadSuccessNotifyTask RatingPattern::CreateLoadSuccessCallback(int32_t imageFlag)
91 {
92     auto task = [weak = WeakClaim(this), imageFlag](const ImageSourceInfo& sourceInfo) {
93         auto pattern = weak.Upgrade();
94         CHECK_NULL_VOID(pattern);
95         // check image info has changed or not
96         pattern->CheckImageInfoHasChangedOrNot(imageFlag, sourceInfo, "ImageDataSuccess");
97         pattern->OnImageLoadSuccess(imageFlag);
98     };
99     return task;
100 }
101 
CreateDataReadyCallback(int32_t imageFlag)102 DataReadyNotifyTask RatingPattern::CreateDataReadyCallback(int32_t imageFlag)
103 {
104     auto task = [weak = WeakClaim(this), imageFlag](const ImageSourceInfo& sourceInfo) {
105         auto pattern = weak.Upgrade();
106         CHECK_NULL_VOID(pattern);
107         // check image info has changed or not
108         pattern->CheckImageInfoHasChangedOrNot(imageFlag, sourceInfo, "ImageDataReady");
109         pattern->OnImageDataReady(imageFlag);
110     };
111     return task;
112 }
113 
CreateLoadFailCallback(int32_t imageFlag)114 LoadFailNotifyTask RatingPattern::CreateLoadFailCallback(int32_t imageFlag)
115 {
116     auto task = [weak = WeakClaim(this), imageFlag](const ImageSourceInfo& sourceInfo, const std::string& msg) {
117         auto pattern = weak.Upgrade();
118         CHECK_NULL_VOID(pattern);
119         // check image info has changed or not
120         pattern->CheckImageInfoHasChangedOrNot(imageFlag, sourceInfo, "ImageDataFailed");
121     };
122     return task;
123 }
124 
OnImageLoadSuccess(int32_t imageFlag)125 void RatingPattern::OnImageLoadSuccess(int32_t imageFlag)
126 {
127     if (imageFlag == 0b001) {
128         foregroundImageCanvas_ = foregroundImageLoadingCtx_->MoveCanvasImage();
129         foregroundConfig_.srcRect_ = foregroundImageLoadingCtx_->GetSrcRect();
130         foregroundConfig_.dstRect_ = foregroundImageLoadingCtx_->GetDstRect();
131         imageSuccessStateCode_ |= static_cast<uint32_t>(imageFlag);
132     }
133     if (imageFlag == 0b010) {
134         secondaryImageCanvas_ = secondaryImageLoadingCtx_->MoveCanvasImage();
135         secondaryConfig_.srcRect_ = secondaryImageLoadingCtx_->GetSrcRect();
136         secondaryConfig_.dstRect_ = secondaryImageLoadingCtx_->GetDstRect();
137         imageSuccessStateCode_ |= static_cast<uint32_t>(imageFlag);
138     }
139     if (imageFlag == 0b100) {
140         backgroundImageCanvas_ = backgroundImageLoadingCtx_->MoveCanvasImage();
141         backgroundConfig_.srcRect_ = backgroundImageLoadingCtx_->GetSrcRect();
142         backgroundConfig_.dstRect_ = backgroundImageLoadingCtx_->GetDstRect();
143         imageSuccessStateCode_ |= static_cast<uint32_t>(imageFlag);
144     }
145     // only when foreground, secondary and background image are all loaded successfully, mark dirty to update rendering.
146     if (imageSuccessStateCode_ == RATING_IMAGE_SUCCESS_CODE) {
147         MarkDirtyNode(PROPERTY_UPDATE_RENDER);
148     }
149 }
150 
OnImageDataReady(int32_t imageFlag)151 void RatingPattern::OnImageDataReady(int32_t imageFlag)
152 {
153     imageReadyStateCode_ |= static_cast<uint32_t>(imageFlag);
154 
155     // 3 images are ready, invoke to update layout to calculate single star size.
156     if (imageReadyStateCode_ == RATING_IMAGE_SUCCESS_CODE) {
157         MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
158     }
159 }
160 
UpdatePaintConfig()161 void RatingPattern::UpdatePaintConfig()
162 {
163     auto host = GetHost();
164     CHECK_NULL_VOID(host);
165     auto layoutProperty = GetLayoutProperty<RatingLayoutProperty>();
166     CHECK_NULL_VOID(layoutProperty);
167     auto starsNum = layoutProperty->GetStarsValue(themeStarNum_);
168     CHECK_EQUAL_VOID(starsNum, 0);
169     auto geometryNode = host->GetGeometryNode();
170     CHECK_NULL_VOID(geometryNode);
171     auto frameSize = geometryNode->GetFrameSize();
172     auto contentSize = geometryNode->GetContentSize();
173     foregroundConfig_.imageFit_ = ImageFit::FILL;
174     secondaryConfig_.imageFit_ = ImageFit::FILL;
175     backgroundConfig_.imageFit_ = ImageFit::FILL;
176     foregroundConfig_.scaleX_ = contentSize.Width() / frameSize.Width() / static_cast<float>(starsNum);
177     foregroundConfig_.scaleY_ = contentSize.Height() / frameSize.Height();
178     secondaryConfig_.scaleX_ = contentSize.Width() / frameSize.Width() / static_cast<float>(starsNum);
179     secondaryConfig_.scaleY_ = contentSize.Height() / frameSize.Height();
180     backgroundConfig_.scaleX_ = contentSize.Width() / frameSize.Width() / static_cast<float>(starsNum);
181     backgroundConfig_.scaleY_ = contentSize.Height() / frameSize.Height();
182 }
183 
CreateNodePaintMethod()184 RefPtr<NodePaintMethod> RatingPattern::CreateNodePaintMethod()
185 {
186     auto ratingLayoutProperty = GetLayoutProperty<RatingLayoutProperty>();
187     CHECK_NULL_RETURN(ratingLayoutProperty, nullptr);
188     if (!ratingModifier_) {
189         ratingModifier_ = AceType::MakeRefPtr<RatingModifier>();
190     }
191     auto starNum = ratingLayoutProperty->GetStarsValue(themeStarNum_);
192     auto defaultPaintMethod = MakeRefPtr<RatingPaintMethod>(ratingModifier_, starNum, state_, false);
193     CHECK_NULL_RETURN(ratingLayoutProperty, defaultPaintMethod);
194     CHECK_NULL_RETURN(foregroundImageCanvas_, defaultPaintMethod);
195     CHECK_NULL_RETURN(secondaryImageCanvas_, defaultPaintMethod);
196     CHECK_NULL_RETURN(backgroundImageCanvas_, defaultPaintMethod);
197     CHECK_NULL_RETURN(foregroundImageLoadingCtx_, defaultPaintMethod);
198     CHECK_NULL_RETURN(secondaryImageLoadingCtx_, defaultPaintMethod);
199     CHECK_NULL_RETURN(backgroundImageLoadingCtx_, defaultPaintMethod);
200     UpdatePaintConfig();
201     PrepareAnimation(foregroundImageCanvas_);
202     PrepareAnimation(secondaryImageCanvas_);
203     PrepareAnimation(backgroundImageCanvas_);
204     // when frameNode mark dirty to update rendering, only when 3 images are all loaded successfully and
205     // JudgeImageSourceInfo is true, pattern will update ratingModifier's CanvasImage.
206     if (ratingModifier_->JudgeImageSourceInfo(foregroundImageLoadingCtx_->GetSourceInfo(),
207             secondaryImageLoadingCtx_->GetSourceInfo(), backgroundImageLoadingCtx_->GetSourceInfo(),
208             foregroundConfig_) &&
209         imageSuccessStateCode_ == RATING_IMAGE_SUCCESS_CODE) {
210         ratingModifier_->UpdateImageSourceInfo(foregroundImageLoadingCtx_->GetSourceInfo(),
211             secondaryImageLoadingCtx_->GetSourceInfo(), backgroundImageLoadingCtx_->GetSourceInfo());
212         ratingModifier_->UpdateCanvasImage(foregroundImageCanvas_, secondaryImageCanvas_, backgroundImageCanvas_,
213             foregroundConfig_, secondaryConfig_, backgroundConfig_);
214     }
215     if (!(foregroundImageCanvas_->IsStatic() && secondaryImageCanvas_->IsStatic() &&
216             backgroundImageCanvas_->IsStatic())) {
217         ratingModifier_->SetNeedDraw(true);
218     }
219     ratingModifier_->SetUseContentModifier(UseContentModifier());
220     auto direction = ratingLayoutProperty->GetLayoutDirection();
221     auto reverse = direction == TextDirection::AUTO ? AceApplicationInfo::GetInstance().IsRightToLeft() :
222         direction == TextDirection::RTL;
223     auto paintMethod = MakeRefPtr<RatingPaintMethod>(ratingModifier_, starNum, state_, reverse);
224     paintMethod->UpdateFocusState(isfocus_, focusRatingScore_);
225     return paintMethod;
226 }
227 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)228 bool RatingPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
229 {
230     auto host = GetHost();
231     CHECK_NULL_RETURN(host, false);
232     std::optional<SizeF> contentSize = GetHostContentSize();
233     CHECK_NULL_RETURN(contentSize, false);
234     auto layoutProperty = GetLayoutProperty<RatingLayoutProperty>();
235     CHECK_NULL_RETURN(layoutProperty, false);
236     auto starsNum = layoutProperty->GetStarsValue(themeStarNum_);
237     singleStarWidth_ = contentSize->Width() / static_cast<float>(starsNum);
238     if (config.skipMeasure || dirty->SkipMeasureContent()) {
239         return false;
240     }
241     if (!foregroundImageCanvas_ || !secondaryImageCanvas_ || !backgroundImageCanvas_) {
242         return false;
243     }
244     return true;
245 }
246 
ConstrainsRatingScore(const RefPtr<RatingLayoutProperty> & layoutProperty)247 void RatingPattern::ConstrainsRatingScore(const RefPtr<RatingLayoutProperty>& layoutProperty)
248 {
249     auto ratingRenderProperty = GetPaintProperty<RatingRenderProperty>();
250 
251     // constrains ratingScore and StarNum.
252     // check if starNum is not positive, assign the value defined in theme.
253     if (layoutProperty->HasStars() && layoutProperty->GetStars().value() <= 0) {
254         layoutProperty->UpdateStars(themeStarNum_);
255     }
256 
257     // if ratingScore < 0, assign the value defined in theme.
258     if (ratingRenderProperty->HasRatingScore()) {
259         if (LessOrEqual(ratingRenderProperty->GetRatingScore().value(), 0.0)) {
260             UpdateRatingScore(themeRatingScore_);
261         }
262     }
263 
264     auto starNum = layoutProperty->GetStarsValue(themeStarNum_);
265     // steps max is stars, if steps > stars, assign the value defined in theme.
266     if (ratingRenderProperty->HasStepSize()) {
267         if (GreatNotEqual(ratingRenderProperty->GetStepSizeValue(themeStepSize_), starNum)) {
268             ratingRenderProperty->UpdateStepSize(themeStepSize_);
269         }
270     }
271 
272     // Calculate drewScore based on the stepSize, and it is cannot be greater than starNum.
273     const double ratingScore = ratingRenderProperty->GetRatingScore().value_or(themeRatingScore_);
274     const double stepSize = ratingRenderProperty->GetStepSize().value_or(themeStepSize_);
275     const double drawScore = fmin(Round(ratingScore / stepSize) * stepSize, static_cast<double>(starNum));
276     // do not fire onChange callback when rating is initialized for the first time.
277     if (hasInit_ && lastRatingScore_ != drawScore) {
278         FireChangeEvent();
279     }
280     if (!hasInit_) {
281         hasInit_ = true;
282     }
283     UpdateRatingScore(drawScore);
284     lastRatingScore_ = drawScore;
285 }
286 
RecalculatedRatingScoreBasedOnEventPoint(double eventPointX,bool isDrag)287 void RatingPattern::RecalculatedRatingScoreBasedOnEventPoint(double eventPointX, bool isDrag)
288 {
289     auto host = GetHost();
290     CHECK_NULL_VOID(host);
291     auto ratingLayoutProperty = GetLayoutProperty<RatingLayoutProperty>();
292     CHECK_NULL_VOID(ratingLayoutProperty);
293     auto ratingRenderProperty = GetPaintProperty<RatingRenderProperty>();
294     CHECK_NULL_VOID(ratingRenderProperty);
295     const auto& content = host->GetGeometryNode()->GetContent();
296     CHECK_NULL_VOID(content);
297     auto direction = ratingLayoutProperty->GetLayoutDirection();
298     auto reverse = direction == TextDirection::AUTO ? AceApplicationInfo::GetInstance().IsRightToLeft() :
299         direction == TextDirection::RTL;
300     auto touchLocationX =
301         reverse ? (content->GetRect().Right() - eventPointX) : (eventPointX - content->GetRect().Left());
302 
303     const int32_t starNum = ratingLayoutProperty->GetStarsValue(themeStarNum_);
304     // step1: calculate the number of star which the touch point falls on.
305     double wholeStarNum = 0.0;
306     wholeStarNum = floor(touchLocationX / singleStarWidth_);
307 
308     // step2: calculate relative position where the touch point falls on the wholeStarNum star.
309     double posInSingle = 0.0;
310     posInSingle = (touchLocationX - wholeStarNum * singleStarWidth_) / singleStarWidth_;
311     // step3: calculate the new ratingScore according to the touch point.
312     double ratingScore = wholeStarNum + posInSingle;
313     const double stepSize = ratingRenderProperty->GetStepSizeValue(themeStepSize_);
314     // step3.1: constrain ratingScore which cannot be greater than starNum and be less than 0.0.
315     ratingScore = ratingScore > starNum ? starNum : ratingScore;
316     ratingScore = (ratingScore < 0.0) ? 0.0 : ratingScore;
317     const double newDrawScore = fmin(ceil(ratingScore / stepSize) * stepSize, starNum);
318     // step3.2: Determine whether the old and new ratingScores are same or not.
319     const double oldRatingScore = ratingRenderProperty->GetRatingScoreValue();
320     const double oldDrawScore = fmin(Round(oldRatingScore / stepSize) * stepSize, static_cast<double>(starNum));
321 
322     CHECK_NULL_VOID(!NearEqual(newDrawScore, oldDrawScore));
323 
324     // step4: Update the ratingScore saved in renderProperty and update render.
325     UpdateRatingScore(newDrawScore);
326     std::ostringstream oldScore;
327     std::ostringstream newScore;
328     oldScore << std::fixed << std::setprecision(1) << oldDrawScore;
329     newScore << std::fixed << std::setprecision(1) << newDrawScore;
330     if (isDrag) {
331         host->OnAccessibilityEvent(AccessibilityEventType::TEXT_CHANGE, oldScore.str(), newScore.str());
332         ratingRenderProperty->UpdateTouchStar(
333             static_cast<int32_t>(reverse ? starNum - wholeStarNum - 1 : wholeStarNum));
334     }
335     MarkDirtyNode(PROPERTY_UPDATE_RENDER);
336 }
337 
IsIndicator()338 bool RatingPattern::IsIndicator()
339 {
340     auto ratingLayoutProperty = GetLayoutProperty<RatingLayoutProperty>();
341     CHECK_NULL_RETURN(ratingLayoutProperty, true);
342     // Do not handle event when rating is set as indicator or single star size is invalid.
343     return ratingLayoutProperty->GetIndicator().value_or(false) || !foregroundConfig_.dstRect_.IsValid();
344 }
345 
HandleDragUpdate(const GestureEvent & info)346 void RatingPattern::HandleDragUpdate(const GestureEvent& info)
347 {
348     CHECK_NULL_VOID(!IsIndicator());
349     RecalculatedRatingScoreBasedOnEventPoint(info.GetLocalLocation().GetX(), true);
350 }
351 
FireChangeEvent()352 void RatingPattern::FireChangeEvent()
353 {
354     auto ratingEventHub = GetEventHub<RatingEventHub>();
355     CHECK_NULL_VOID(ratingEventHub);
356     auto ratingRenderProperty = GetPaintProperty<RatingRenderProperty>();
357     CHECK_NULL_VOID(ratingRenderProperty);
358     std::stringstream ss;
359     ss << std::setprecision(2) << ratingRenderProperty->GetRatingScoreValue();
360     ratingEventHub->FireChangeEvent(ss.str());
361     lastRatingScore_ = ratingRenderProperty->GetRatingScoreValue();
362 
363     if (!Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
364         return;
365     }
366     auto host = GetHost();
367     CHECK_NULL_VOID(host);
368     auto inspectorId = host->GetInspectorId().value_or("");
369     Recorder::EventParamsBuilder builder;
370     auto score = ss.str();
371     builder.SetId(inspectorId).SetType(host->GetTag()).SetText(score).SetDescription(host->GetAutoEventParamValue(""));
372     Recorder::EventRecorder::Get().OnChange(std::move(builder));
373     if (inspectorId.empty()) {
374         return;
375     }
376     Recorder::NodeDataCache::Get().PutString(host, inspectorId, score);
377 }
378 
HandleDragEnd()379 void RatingPattern::HandleDragEnd()
380 {
381     CHECK_NULL_VOID(!IsIndicator());
382     FireChangeEvent();
383 }
384 
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)385 void RatingPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
386 {
387     CHECK_NULL_VOID(!panEvent_);
388     PanDirection panDirection;
389     panDirection.type = PanDirection::HORIZONTAL;
390 
391     panEvent_ = MakeRefPtr<PanEvent>([weak = WeakClaim(this)](const GestureEvent& info) {},
392         [weak = WeakClaim(this)](const GestureEvent& info) {
393             TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "rating handle drag update");
394             auto pattern = weak.Upgrade();
395             CHECK_NULL_VOID(pattern);
396             pattern->HandleDragUpdate(info);
397         },
398         [weak = WeakClaim(this)](const GestureEvent& /*info*/) {
399             TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "rating handle drag end");
400             auto pattern = weak.Upgrade();
401             CHECK_NULL_VOID(pattern);
402             // invoke onChange callback
403             pattern->HandleDragEnd();
404         },
405         [weak = WeakClaim(this)]() {});
406     gestureHub->AddPanEvent(panEvent_, panDirection, 1, DEFAULT_PAN_DISTANCE);
407 }
408 
InitTouchEvent(const RefPtr<GestureEventHub> & gestureHub)409 void RatingPattern::InitTouchEvent(const RefPtr<GestureEventHub>& gestureHub)
410 {
411     CHECK_NULL_VOID(!touchEvent_);
412     touchEvent_ = MakeRefPtr<TouchEventImpl>([weak = WeakClaim(this)](const TouchEventInfo& info) {
413         auto pattern = weak.Upgrade();
414         CHECK_NULL_VOID(pattern);
415         if (info.GetTouches().empty()) {
416             return;
417         }
418         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
419             auto localPosition = info.GetTouches().front().GetLocalLocation();
420             // handle touch down event and draw touch down effect.
421             pattern->HandleTouchDown(localPosition);
422             TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "rating handle touch down");
423         }
424         if (info.GetTouches().front().GetTouchType() == TouchType::UP) {
425             // handle touch up event and remove touch down effect.
426             pattern->HandleTouchUp();
427             TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "rating handle touch up");
428         }
429     });
430     gestureHub->AddTouchEvent(touchEvent_);
431 }
432 
HandleTouchUp()433 void RatingPattern::HandleTouchUp()
434 {
435     CHECK_NULL_VOID(!IsIndicator());
436     state_ = isHover_ ? RatingModifier::RatingAnimationType::PRESSTOHOVER : RatingModifier::RatingAnimationType::NONE;
437     MarkDirtyNode(PROPERTY_UPDATE_RENDER);
438 }
439 
HandleTouchDown(const Offset & localPosition)440 void RatingPattern::HandleTouchDown(const Offset& localPosition)
441 {
442     CHECK_NULL_VOID(!IsIndicator());
443 
444     auto ratingRenderProperty = GetPaintProperty<RatingRenderProperty>();
445     CHECK_NULL_VOID(ratingRenderProperty);
446     auto host = GetHost();
447     CHECK_NULL_VOID(host);
448     const auto& content = host->GetGeometryNode()->GetContent();
449     CHECK_NULL_VOID(content);
450     auto contentOffset = content->GetRect().GetOffset();
451     // calculate the number of star the touch point falls on and trigger render update.
452     const int32_t touchStar = floor((localPosition.GetX() - contentOffset.GetX()) / singleStarWidth_);
453     ratingRenderProperty->UpdateTouchStar(touchStar);
454     state_ = isHover_ ? RatingModifier::RatingAnimationType::HOVERTOPRESS : RatingModifier::RatingAnimationType::PRESS;
455     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
456 }
457 
HandleClick(const GestureEvent & info)458 void RatingPattern::HandleClick(const GestureEvent& info)
459 {
460     CHECK_NULL_VOID(!IsIndicator());
461     auto eventPointX = info.GetLocalLocation().GetX();
462     if (Negative(eventPointX)) {
463         return;
464     }
465     RecalculatedRatingScoreBasedOnEventPoint(eventPointX, false);
466     FireChangeEvent();
467 }
468 
InitClickEvent(const RefPtr<GestureEventHub> & gestureHub)469 void RatingPattern::InitClickEvent(const RefPtr<GestureEventHub>& gestureHub)
470 {
471     CHECK_NULL_VOID(!clickEvent_);
472     clickEvent_ = MakeRefPtr<ClickEvent>([weak = WeakClaim(this)](const GestureEvent& info) {
473         auto pattern = weak.Upgrade();
474         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "rating handle click");
475         pattern->HandleClick(info);
476     });
477     gestureHub->AddClickEvent(clickEvent_);
478 }
479 
GetInnerFocusPaintRect(RoundRect & paintRect)480 void RatingPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
481 {
482     auto host = GetHost();
483     CHECK_NULL_VOID(host);
484     const auto& content = host->GetGeometryNode()->GetContent();
485     CHECK_NULL_VOID(content);
486     auto singleStarHeight = content->GetRect().Height();
487     auto property = GetLayoutProperty<RatingLayoutProperty>();
488     CHECK_NULL_VOID(property);
489     auto offsetLeft = 0.0f;
490     auto offsetTop = 0.0f;
491     const auto& padding = property->GetPaddingProperty();
492     if (padding) {
493         offsetLeft += padding->left.value_or(CalcLength(0.0_vp)).GetDimension().ConvertToPx();
494         offsetTop += padding->top.value_or(CalcLength(0.0_vp)).GetDimension().ConvertToPx();
495     }
496     const auto& border = property->GetBorderWidthProperty();
497     if (border) {
498         offsetLeft += border->leftDimen.value_or(Dimension(0.0)).ConvertToPx();
499         offsetTop += border->topDimen.value_or(Dimension(0.0)).ConvertToPx();
500     }
501     auto ratingScore = focusRatingScore_;
502     auto wholeStarNum =
503         fmax((NearEqual(ratingScore, std::round(ratingScore)) ? ratingScore : ceil(ratingScore)) - 1, 0.0);
504     auto direction = property->GetLayoutDirection();
505     auto reverse = direction == TextDirection::AUTO ? AceApplicationInfo::GetInstance().IsRightToLeft() :
506         direction == TextDirection::RTL;
507     if (reverse) {
508         double starNum = property->GetStarsValue(themeStarNum_);
509         wholeStarNum = starNum - wholeStarNum - 1;
510     }
511     auto pipeline = PipelineBase::GetCurrentContext();
512     CHECK_NULL_VOID(pipeline);
513     auto ratingTheme = pipeline->GetTheme<RatingTheme>();
514     CHECK_NULL_VOID(ratingTheme);
515     auto radius = ratingTheme->GetFocusBorderRadius();
516 
517     paintRect.SetRect(RectF(static_cast<float>(wholeStarNum) * singleStarWidth_ + offsetLeft, offsetTop,
518         singleStarWidth_, singleStarHeight));
519     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, static_cast<RSScalar>(radius.ConvertToPx()),
520         static_cast<RSScalar>(radius.ConvertToPx()));
521     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, static_cast<RSScalar>(radius.ConvertToPx()),
522         static_cast<RSScalar>(radius.ConvertToPx()));
523     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, static_cast<RSScalar>(radius.ConvertToPx()),
524         static_cast<RSScalar>(radius.ConvertToPx()));
525     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, static_cast<RSScalar>(radius.ConvertToPx()),
526         static_cast<RSScalar>(radius.ConvertToPx()));
527 }
528 
PaintFocusState(double ratingScore)529 void RatingPattern::PaintFocusState(double ratingScore)
530 {
531     auto host = GetHost();
532     CHECK_NULL_VOID(host);
533     isfocus_ = true;
534     focusRatingScore_ = ratingScore;
535     RoundRect focusRect;
536     GetInnerFocusPaintRect(focusRect);
537 
538     auto focusHub = host->GetFocusHub();
539     CHECK_NULL_VOID(focusHub);
540     focusHub->PaintInnerFocusState(focusRect);
541 
542     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
543 }
544 
OnKeyEvent(const KeyEvent & event)545 bool RatingPattern::OnKeyEvent(const KeyEvent& event)
546 {
547     if (event.action != KeyAction::DOWN) {
548         return false;
549     }
550     auto ratingRenderProperty = GetPaintProperty<RatingRenderProperty>();
551     double ratingScore = focusRatingScore_;
552     auto ratingLayoutProperty = GetLayoutProperty<RatingLayoutProperty>();
553     double starNum = ratingLayoutProperty->GetStarsValue(themeStarNum_);
554     bool reverse = ratingLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
555     const double stepSize = ratingRenderProperty->GetStepSizeValue(themeStepSize_);
556     if (event.code == KeyCode::KEY_DPAD_LEFT) {
557         ratingScore = reverse ? fmin(ratingScore + stepSize, starNum) : fmax(ratingScore - stepSize, 0.0);
558         PaintFocusState(ratingScore);
559         return true;
560     }
561     if (event.code == KeyCode::KEY_DPAD_RIGHT) {
562         ratingScore = reverse ? fmax(ratingScore - stepSize, 0.0) : fmin(ratingScore + stepSize, starNum);
563         PaintFocusState(ratingScore);
564         return true;
565     }
566     if (event.code == KeyCode::KEY_MOVE_HOME) {
567         ratingScore = 1;
568         PaintFocusState(ratingScore);
569         return true;
570     }
571     if (event.code == KeyCode::KEY_MOVE_END) {
572         ratingScore = starNum;
573         PaintFocusState(ratingScore);
574         return true;
575     }
576     if (event.code == KeyCode::KEY_ENTER || event.code == KeyCode::KEY_SPACE) {
577         ratingRenderProperty->UpdateRatingScore(ratingScore);
578         FireChangeEvent();
579         return true;
580     }
581     return false;
582 }
583 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)584 void RatingPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
585 {
586     focusHub->SetFocusType(IsIndicator() ? FocusType::DISABLE : FocusType::NODE);
587     focusHub->SetOnKeyEventInternal([wp = WeakClaim(this)](const KeyEvent& event) -> bool {
588         auto pattern = wp.Upgrade();
589         CHECK_NULL_RETURN(pattern, false);
590         return pattern->OnKeyEvent(event);
591     });
592     focusHub->SetInnerFocusPaintRectCallback([wp = WeakClaim(this)](RoundRect& paintRect) {
593         auto pattern = wp.Upgrade();
594         if (pattern) {
595             pattern->GetInnerFocusPaintRect(paintRect);
596         }
597     });
598     focusHub->SetOnBlurInternal([wp = WeakClaim(this)]() {
599         auto pattern = wp.Upgrade();
600         CHECK_NULL_VOID(pattern);
601         pattern->OnBlurEvent();
602     });
603 }
604 
OnBlurEvent()605 void RatingPattern::OnBlurEvent()
606 {
607     isfocus_ = false;
608     auto ratingRenderProperty = GetPaintProperty<RatingRenderProperty>();
609     CHECK_NULL_VOID(ratingRenderProperty);
610     focusRatingScore_ = ratingRenderProperty->GetRatingScoreValue();
611     MarkDirtyNode(PROPERTY_UPDATE_RENDER);
612 }
613 
SetRatingScore(double ratingScore)614 void RatingPattern::SetRatingScore(double ratingScore)
615 {
616     auto host = GetHost();
617     CHECK_NULL_VOID(host);
618     auto eventHub = host->GetEventHub<EventHub>();
619     CHECK_NULL_VOID(eventHub);
620     auto enabled = eventHub->IsEnabled();
621     if (!enabled) {
622         return;
623     }
624     UpdateRatingScore(ratingScore);
625     OnModifyDone();
626 }
627 
UpdateRatingScore(double ratingScore)628 void RatingPattern::UpdateRatingScore(double ratingScore)
629 {
630     auto ratingRenderProperty = GetPaintProperty<RatingRenderProperty>();
631     CHECK_NULL_VOID(ratingRenderProperty);
632     ratingRenderProperty->UpdateRatingScore(ratingScore);
633     focusRatingScore_ = ratingScore;
634     FireBuilder();
635 }
636 
InitMouseEvent()637 void RatingPattern::InitMouseEvent()
638 {
639     CHECK_NULL_VOID(!(mouseEvent_ && hoverEvent_));
640     auto eventHub = GetHost()->GetEventHub<RatingEventHub>();
641     auto inputHub = eventHub->GetOrCreateInputEventHub();
642     mouseEvent_ = MakeRefPtr<InputEvent>([weak = WeakClaim(this)](MouseInfo& info) {
643         auto pattern = weak.Upgrade();
644         CHECK_NULL_VOID(pattern);
645         pattern->HandleMouseEvent(info);
646     });
647     hoverEvent_ = MakeRefPtr<InputEvent>([weak = WeakClaim(this)](bool isHover) {
648         auto pattern = weak.Upgrade();
649         CHECK_NULL_VOID(pattern);
650         pattern->HandleHoverEvent(isHover);
651     });
652     inputHub->AddOnHoverEvent(hoverEvent_);
653     inputHub->AddOnMouseEvent(mouseEvent_);
654 }
655 
HandleHoverEvent(bool isHover)656 void RatingPattern::HandleHoverEvent(bool isHover)
657 {
658     isHover_ = isHover;
659     state_ = isHover_ ? RatingModifier::RatingAnimationType::HOVER : RatingModifier::RatingAnimationType::NONE;
660     if (!isHover) {
661         UpdateRatingScore(lastRatingScore_);
662     }
663     MarkDirtyNode(PROPERTY_UPDATE_RENDER);
664 }
665 
HandleMouseEvent(MouseInfo & info)666 void RatingPattern::HandleMouseEvent(MouseInfo& info)
667 {
668     CHECK_NULL_VOID(!IsIndicator() && isHover_);
669     auto host = GetHost();
670     CHECK_NULL_VOID(host);
671     const auto& content = host->GetGeometryNode()->GetContent();
672     CHECK_NULL_VOID(content);
673     auto contentOffset = content->GetRect().GetOffset();
674     auto ratingRenderProperty = GetPaintProperty<RatingRenderProperty>();
675     CHECK_NULL_VOID(ratingRenderProperty);
676     auto ratingLayoutProperty = GetLayoutProperty<RatingLayoutProperty>();
677     CHECK_NULL_VOID(ratingLayoutProperty);
678     // calculate the number of star the mouse moved on and trigger render update.
679     auto touchStar =
680         static_cast<int32_t>(floor((info.GetLocalLocation().GetX() - contentOffset.GetX()) / singleStarWidth_));
681     touchStar =
682         std::clamp(touchStar, DEFAULT_RATING_TOUCH_STAR_NUMBER, ratingLayoutProperty->GetStarsValue(themeStarNum_) - 1);
683     ratingRenderProperty->UpdateTouchStar(touchStar);
684     RecalculatedRatingScoreBasedOnEventPoint(info.GetLocalLocation().GetX(), false);
685 }
686 
LoadForeground(const RefPtr<RatingLayoutProperty> & layoutProperty,const RefPtr<RatingTheme> & ratingTheme,const RefPtr<IconTheme> & iconTheme)687 void RatingPattern::LoadForeground(const RefPtr<RatingLayoutProperty>& layoutProperty,
688     const RefPtr<RatingTheme>& ratingTheme, const RefPtr<IconTheme>& iconTheme)
689 {
690     foregroundConfig_.isSvg_ = false;
691     /*
692      * tips : foregroundUri loaded the default star the first time, the ForegroundImageSourceInfo will not nullopt when
693      * rating create again. such as the ratingScore partical update.
694      * secondaryUri, backgroundUri is the same.
695      */
696     auto sourceInfo = ImageSourceInfo::CreateImageSourceInfoWithHost(GetHost());
697     if (!layoutProperty->HasForegroundImageSourceInfo()) {
698         isForegroundImageInfoFromTheme_ = true;
699         sourceInfo.SetResourceId(ratingTheme->GetForegroundResourceId());
700         layoutProperty->UpdateForegroundImageSourceInfo(sourceInfo);
701     } else {
702         sourceInfo = layoutProperty->GetForegroundImageSourceInfo().value();
703     }
704     auto iconPath = iconTheme->GetIconPath(sourceInfo.GetResourceId());
705     if (!iconPath.empty()) {
706         sourceInfo.SetSrc(iconPath, ratingTheme->GetStarColorActive());
707     }
708     if (sourceInfo.IsSvg()) {
709         foregroundConfig_.isSvg_ = true;
710     }
711     // Recreate ImageLoadingContext only when image source info has changed.
712     if (!foregroundImageLoadingCtx_ || (foregroundImageLoadingCtx_->GetSourceInfo() != sourceInfo)) {
713         // Construct the ImageLoadingContext and register the image life cycle callback.
714         LoadNotifier loadNotifierForegroundImage(
715             CreateDataReadyCallback(0b001), CreateLoadSuccessCallback(0b001), CreateLoadFailCallback(0b001));
716         foregroundImageLoadingCtx_ =
717             AceType::MakeRefPtr<ImageLoadingContext>(sourceInfo, std::move(loadNotifierForegroundImage));
718         foregroundImageLoadingCtx_->LoadImageData();
719     }
720 }
721 
LoadSecondary(const RefPtr<RatingLayoutProperty> & layoutProperty,const RefPtr<RatingTheme> & ratingTheme,const RefPtr<IconTheme> & iconTheme)722 void RatingPattern::LoadSecondary(const RefPtr<RatingLayoutProperty>& layoutProperty,
723     const RefPtr<RatingTheme>& ratingTheme, const RefPtr<IconTheme>& iconTheme)
724 {
725     secondaryConfig_.isSvg_ = false;
726     auto sourceInfo = ImageSourceInfo::CreateImageSourceInfoWithHost(GetHost());
727     if (!layoutProperty->HasSecondaryImageSourceInfo()) {
728         isSecondaryImageInfoFromTheme_ = true;
729         sourceInfo.SetResourceId(ratingTheme->GetSecondaryResourceId());
730         layoutProperty->UpdateSecondaryImageSourceInfo(sourceInfo);
731     } else {
732         sourceInfo = layoutProperty->GetSecondaryImageSourceInfo().value();
733     }
734     auto iconPath = iconTheme->GetIconPath(sourceInfo.GetResourceId());
735     if (!iconPath.empty()) {
736         sourceInfo.SetSrc(iconPath, ratingTheme->GetStarColorInactive());
737     }
738     if (sourceInfo.IsSvg()) {
739         secondaryConfig_.isSvg_ = true;
740     }
741     if (!secondaryImageLoadingCtx_ || secondaryImageLoadingCtx_->GetSourceInfo() != sourceInfo) {
742         LoadNotifier loadNotifierSecondaryImage(
743             CreateDataReadyCallback(0b010), CreateLoadSuccessCallback(0b010), CreateLoadFailCallback(0b010));
744         secondaryImageLoadingCtx_ =
745             AceType::MakeRefPtr<ImageLoadingContext>(sourceInfo, std::move(loadNotifierSecondaryImage));
746         secondaryImageLoadingCtx_->LoadImageData();
747     }
748 }
749 
LoadBackground(const RefPtr<RatingLayoutProperty> & layoutProperty,const RefPtr<RatingTheme> & ratingTheme,const RefPtr<IconTheme> & iconTheme)750 void RatingPattern::LoadBackground(const RefPtr<RatingLayoutProperty>& layoutProperty,
751     const RefPtr<RatingTheme>& ratingTheme, const RefPtr<IconTheme>& iconTheme)
752 {
753     backgroundConfig_.isSvg_ = false;
754     auto sourceInfo = ImageSourceInfo::CreateImageSourceInfoWithHost(GetHost());
755     if (!layoutProperty->HasBackgroundImageSourceInfo()) {
756         isBackgroundImageInfoFromTheme_ = true;
757         sourceInfo.SetResourceId(ratingTheme->GetBackgroundResourceId());
758         layoutProperty->UpdateBackgroundImageSourceInfo(sourceInfo);
759     } else {
760         sourceInfo = layoutProperty->GetBackgroundImageSourceInfo().value();
761     }
762     auto iconPath = iconTheme->GetIconPath(sourceInfo.GetResourceId());
763     if (!iconPath.empty()) {
764         sourceInfo.SetSrc(iconPath, ratingTheme->GetStarColorInactive());
765     }
766     if (sourceInfo.IsSvg()) {
767         backgroundConfig_.isSvg_ = true;
768     }
769     if (!backgroundImageLoadingCtx_ || backgroundImageLoadingCtx_->GetSourceInfo() != sourceInfo) {
770         LoadNotifier loadNotifierBackgroundImage(
771             CreateDataReadyCallback(0b100), CreateLoadSuccessCallback(0b100), CreateLoadFailCallback(0b100));
772         backgroundImageLoadingCtx_ =
773             AceType::MakeRefPtr<ImageLoadingContext>(sourceInfo, std::move(loadNotifierBackgroundImage));
774         backgroundImageLoadingCtx_->LoadImageData();
775     }
776 }
777 
OnModifyDone()778 void RatingPattern::OnModifyDone()
779 {
780     Pattern::OnModifyDone();
781     FireBuilder();
782     auto host = GetHost();
783     CHECK_NULL_VOID(host);
784     auto pipeline = PipelineBase::GetCurrentContext();
785     CHECK_NULL_VOID(pipeline);
786     auto ratingTheme = pipeline->GetTheme<RatingTheme>();
787     CHECK_NULL_VOID(ratingTheme);
788     auto iconTheme = pipeline->GetTheme<IconTheme>();
789     CHECK_NULL_VOID(iconTheme);
790     auto layoutProperty = host->GetLayoutProperty<RatingLayoutProperty>();
791     CHECK_NULL_VOID(layoutProperty);
792     // Reset image state code.
793     imageReadyStateCode_ = 0;
794     imageSuccessStateCode_ = 0;
795     // Constrains ratingScore and starNum in case of the illegal input.
796     ConstrainsRatingScore(layoutProperty);
797 
798     LoadForeground(layoutProperty, ratingTheme, iconTheme);
799     LoadSecondary(layoutProperty, ratingTheme, iconTheme);
800     LoadBackground(layoutProperty, ratingTheme, iconTheme);
801     auto hub = host->GetEventHub<EventHub>();
802     CHECK_NULL_VOID(hub);
803     auto gestureHub = hub->GetOrCreateGestureEventHub();
804     CHECK_NULL_VOID(gestureHub);
805     bool isIndicator = IsIndicator();
806     if (!isIndicator) {
807         InitTouchEvent(gestureHub);
808         InitPanEvent(gestureHub);
809         InitClickEvent(gestureHub);
810     }
811     InitMouseEvent();
812     // Init touch, pan, click and key event and register callback.
813     auto focusHub = host->GetFocusHub();
814     CHECK_NULL_VOID(focusHub);
815     InitOnKeyEvent(focusHub);
816 }
817 
818 // XTS inspector code
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const819 void RatingPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
820 {
821     /* no fixed attr below, just return */
822     if (filter.IsFastFilter()) {
823         return;
824     }
825     auto ratingLayoutProperty = GetLayoutProperty<RatingLayoutProperty>();
826     if (isForegroundImageInfoFromTheme_) {
827         json->PutExtAttr("foregroundImageSourceInfo", ImageSourceInfo("").ToString().c_str(), filter);
828     } else {
829         auto foregroundImageSourceInfo =
830             ratingLayoutProperty->GetForegroundImageSourceInfo().value_or(ImageSourceInfo(""));
831         json->PutExtAttr("foregroundImageSourceInfo", foregroundImageSourceInfo.ToString().c_str(), filter);
832     }
833     if (isSecondaryImageInfoFromTheme_) {
834         json->PutExtAttr("secondaryImageSourceInfo", ImageSourceInfo("").ToString().c_str(), filter);
835     } else {
836         auto secondaryImageSourceInfo =
837             ratingLayoutProperty->GetSecondaryImageSourceInfo().value_or(ImageSourceInfo(""));
838         json->PutExtAttr("secondaryImageSourceInfo", secondaryImageSourceInfo.ToString().c_str(), filter);
839     }
840     if (isBackgroundImageInfoFromTheme_) {
841         json->PutExtAttr("backgroundImageSourceInfo", ImageSourceInfo("").ToString().c_str(), filter);
842     } else {
843         auto backgroundImageSourceInfo =
844             ratingLayoutProperty->GetBackgroundImageSourceInfo().value_or(ImageSourceInfo(""));
845         json->PutExtAttr("backgroundImageSourceInfo", backgroundImageSourceInfo.ToString().c_str(), filter);
846     }
847 }
848 
MarkDirtyNode(const PropertyChangeFlag & flag)849 void RatingPattern::MarkDirtyNode(const PropertyChangeFlag& flag)
850 {
851     auto host = GetHost();
852     CHECK_NULL_VOID(host);
853     host->MarkDirtyNode(flag);
854 }
855 
PrepareAnimation(const RefPtr<CanvasImage> & image)856 void RatingPattern::PrepareAnimation(const RefPtr<CanvasImage>& image)
857 {
858     if (image->IsStatic()) {
859         return;
860     }
861     SetRedrawCallback(image);
862     // RegisterVisibleAreaChange
863     auto layoutProps = GetLayoutProperty<LayoutProperty>();
864     CHECK_NULL_VOID(layoutProps);
865     // pause animation if prop is initially set to invisible
866     if (layoutProps->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::VISIBLE) {
867         image->ControlAnimation(false);
868     } else {
869         image->ControlAnimation(true);
870     }
871 }
872 
SetRedrawCallback(const RefPtr<CanvasImage> & image)873 void RatingPattern::SetRedrawCallback(const RefPtr<CanvasImage>& image)
874 {
875     CHECK_NULL_VOID(image);
876     // set animation flush function for svg / gif
877     image->SetRedrawCallback([weak = WeakPtr(GetHost())] {
878         auto ratingNode = weak.Upgrade();
879         CHECK_NULL_VOID(ratingNode);
880         ratingNode->MarkNeedRenderOnly();
881     });
882 }
883 
FireBuilder()884 void RatingPattern::FireBuilder()
885 {
886     auto host = GetHost();
887     CHECK_NULL_VOID(host);
888     if (!makeFunc_.has_value()) {
889         host->RemoveChildAtIndex(0);
890         host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
891         return;
892     }
893     auto node = BuildContentModifierNode();
894     if (contentModifierNode_ == node) {
895         return;
896     }
897     host->RemoveChildAtIndex(0);
898     contentModifierNode_ = node;
899     CHECK_NULL_VOID(contentModifierNode_);
900     host->AddChild(contentModifierNode_, 0);
901     host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
902 }
903 
BuildContentModifierNode()904 RefPtr<FrameNode> RatingPattern::BuildContentModifierNode()
905 {
906     if (!makeFunc_.has_value()) {
907         return nullptr;
908     }
909     auto host = GetHost();
910     CHECK_NULL_RETURN(host, nullptr);
911     auto property = GetLayoutProperty<RatingLayoutProperty>();
912     CHECK_NULL_RETURN(property, nullptr);
913     auto renderProperty = GetPaintProperty<RatingRenderProperty>();
914     CHECK_NULL_RETURN(renderProperty, nullptr);
915     auto starNum = property->GetStarsValue(themeStarNum_);
916     auto isIndicator = IsIndicator();
917     auto ratingScore = renderProperty->GetRatingScoreValue(themeRatingScore_);
918     auto stepSize = renderProperty->GetStepSizeValue(themeStepSize_);
919     auto eventHub = host->GetEventHub<EventHub>();
920     CHECK_NULL_RETURN(eventHub, nullptr);
921     auto enabled = eventHub->IsEnabled();
922     RatingConfiguration ratingConfiguration(starNum, isIndicator, ratingScore, stepSize, enabled);
923     return (makeFunc_.value())(ratingConfiguration);
924 }
925 } // namespace OHOS::Ace::NG
926