• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2025 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_ng/pattern/progress/progress_modifier.h"
17 
18 #include "core/components/progress/progress_theme.h"
19 #include "core/components_ng/render/drawing_prop_convertor.h"
20 
21 namespace OHOS::Ace::NG {
22 namespace {
23 constexpr int32_t INT32_TWO = 2;
24 constexpr int32_t ANGLE_45 = 45;
25 constexpr int32_t ANGLE_90 = 90;
26 constexpr int32_t ANGLE_180 = 180;
27 constexpr int32_t ANGLE_270 = 270;
28 constexpr int32_t ANGLE_360 = 360;
29 constexpr int32_t TIME_2000 = 2000; // 2000 ms
30 constexpr int32_t TIME_4000 = 4000; // 4000 ms
31 constexpr int32_t LOADING_ANIMATION_DURATION = 2000;
32 constexpr float DEFAULT_MAX_VALUE = 100.0f;
33 constexpr float DEFAULT_SCALE_WIDTH = 10.0f;
34 constexpr float DEFAULT_MIN_PROGRESS_WIDTH = 0.0f;
35 constexpr int32_t DEFAULT_SCALE_COUNT = 100;
36 constexpr double DEFAULT_CAPSULE_BORDER_WIDTH = 0.0;
37 constexpr float FLOAT_ZERO_FIVE = 0.5f;
38 constexpr float FLOAT_TWO_ZERO = 2.0f;
39 constexpr float SPRING_MOTION_RESPONSE = 0.314f;
40 constexpr float SPRING_MOTION_DAMPING_FRACTION = 0.95f;
41 constexpr Dimension SWEEP_WIDTH = 80.0_vp;
42 constexpr float RING_SHADOW_OFFSET_X = 5.0f;
43 constexpr float RING_SHADOW_OFFSET_Y = 5.0f;
44 constexpr float RING_SHADOW_BLUR_RADIUS_MIN = 5.0f;
45 constexpr float RING_SHADOW_VALID_RADIUS_MIN = 10.0f;
46 constexpr float RING_SHADOW_OPACITY = 0.4f;
47 constexpr Dimension LINEAR_SWEEPING_LEN = 80.0_vp;
48 } // namespace
ProgressModifier(const WeakPtr<FrameNode> & host,const ProgressAnimatableProperty & progressAnimatableProperty_)49 ProgressModifier::ProgressModifier(const WeakPtr<FrameNode>& host,
50     const ProgressAnimatableProperty& progressAnimatableProperty_)
51     : strokeWidth_(AceType::MakeRefPtr<AnimatablePropertyFloat>(progressAnimatableProperty_.strokeWidth)),
52       color_(AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(progressAnimatableProperty_.color))),
53       bgColor_(AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(progressAnimatableProperty_.bgColor))),
54       borderColor_(AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(progressAnimatableProperty_.borderColor))),
55       value_(AceType::MakeRefPtr<AnimatablePropertyFloat>(progressAnimatableProperty_.value)),
56       ringProgressColors_(AceType::MakeRefPtr<AnimatablePropertyVectorColor>(
57         GradientArithmetic(progressAnimatableProperty_.ringProgressColor))),
58       sweepingDate_(AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f)),
59       trailingHeadDate_(AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f)),
60       trailingTailDate_(AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f)),
61       strokeRadius_(AceType::MakeRefPtr<AnimatablePropertyFloat>(progressAnimatableProperty_.strokeRadius)),
62       offset_(AceType::MakeRefPtr<PropertyOffsetF>(OffsetF())),
63       contentSize_(AceType::MakeRefPtr<PropertySizeF>(SizeF())),
64       maxValue_(AceType::MakeRefPtr<PropertyFloat>(DEFAULT_MAX_VALUE)),
65       scaleWidth_(AceType::MakeRefPtr<PropertyFloat>(DEFAULT_SCALE_WIDTH)),
66       scaleCount_(AceType::MakeRefPtr<PropertyInt>(DEFAULT_SCALE_COUNT)),
67       progressType_(AceType::MakeRefPtr<PropertyInt>(static_cast<int32_t>(ProgressType::LINEAR))),
68       capsuleBorderWidth_(AceType::MakeRefPtr<PropertyFloat>(DEFAULT_CAPSULE_BORDER_WIDTH)),
69       sweepEffect_(AceType::MakeRefPtr<PropertyBool>(false)),
70       ringSweepEffect_(AceType::MakeRefPtr<PropertyBool>(false)),
71       linearSweepEffect_(AceType::MakeRefPtr<PropertyBool>(false)),
72       paintShadow_(AceType::MakeRefPtr<PropertyBool>(false)),
73       progressStatus_(AceType::MakeRefPtr<PropertyInt>(static_cast<int32_t>(ProgressStatus::PROGRESSING))),
74       isItalic_(AceType::MakeRefPtr<PropertyBool>(false)),
75       smoothEffect_(AceType::MakeRefPtr<PropertyBool>(true)),
76       useContentModifier_(AceType::MakeRefPtr<PropertyBool>(false)),
77       isRightToLeft_(AceType::MakeRefPtr<PropertyBool>(false)),
78       progressUpdate_(AceType::MakeRefPtr<PropertyBool>(false)),
79       capsuleBorderRadius_(AceType::MakeRefPtr<PropertyFloat>(0.0f)),
80       host_(host)
81 {
82     AttachProperty(strokeWidth_);
83     AttachProperty(color_);
84     AttachProperty(bgColor_);
85     AttachProperty(borderColor_);
86     AttachProperty(maxValue_);
87     AttachProperty(value_);
88     AttachProperty(scaleWidth_);
89     AttachProperty(scaleCount_);
90     AttachProperty(progressType_);
91     AttachProperty(capsuleBorderWidth_);
92     AttachProperty(sweepEffect_);
93     AttachProperty(trailingHeadDate_);
94     AttachProperty(trailingTailDate_);
95     AttachProperty(strokeRadius_);
96 
97     AttachProperty(ringProgressColors_);
98     AttachProperty(sweepingDate_);
99     AttachProperty(paintShadow_);
100     AttachProperty(progressStatus_);
101     AttachProperty(ringSweepEffect_);
102     AttachProperty(linearSweepEffect_);
103     AttachProperty(isItalic_);
104     AttachProperty(smoothEffect_);
105     AttachProperty(isRightToLeft_);
106     AttachProperty(progressUpdate_);
107     AttachProperty(capsuleBorderRadius_);
108 
109     auto pipeline = PipelineBase::GetCurrentContext();
110     CHECK_NULL_VOID(pipeline);
111     auto theme = pipeline->GetTheme<ProgressTheme>(GetThemeScopeId());
112     CHECK_NULL_VOID(theme);
113 
114     pressBlendColor_ = theme->GetClickEffect();
115     hoverBlendColor_ = theme->GetHoverBlendColor();
116 }
117 
onDraw(DrawingContext & context)118 void ProgressModifier::onDraw(DrawingContext& context)
119 {
120     if (useContentModifier_->Get()) {
121         return;
122     }
123     ContentDrawWithFunction(context);
124 }
125 
SetUseContentModifier(bool useContentModifier)126 void ProgressModifier::SetUseContentModifier(bool useContentModifier)
127 {
128     if (useContentModifier_) {
129         useContentModifier_->Set(useContentModifier);
130     }
131 }
132 
SetStrokeWidth(float width)133 void ProgressModifier::SetStrokeWidth(float width)
134 {
135     CHECK_NULL_VOID(strokeWidth_);
136     strokeWidth_->Set(width);
137 }
138 
SetColor(LinearColor color)139 void ProgressModifier::SetColor(LinearColor color)
140 {
141     CHECK_NULL_VOID(color_);
142     color_->Set(color);
143 }
144 
SetBackgroundColor(LinearColor color)145 void ProgressModifier::SetBackgroundColor(LinearColor color)
146 {
147     CHECK_NULL_VOID(bgColor_);
148     bgColor_->Set(color);
149 }
150 
SetBorderColor(LinearColor color)151 void ProgressModifier::SetBorderColor(LinearColor color)
152 {
153     CHECK_NULL_VOID(borderColor_);
154     borderColor_->Set(color);
155 }
156 
SetProgressType(ProgressType type)157 void ProgressModifier::SetProgressType(ProgressType type)
158 {
159     CHECK_NULL_VOID(progressType_);
160     progressType_->Set(static_cast<int32_t>(type));
161 }
162 
UpdateProgress()163 void ProgressModifier::UpdateProgress()
164 {
165     progressUpdate_->Set(!progressUpdate_->Get());
166 }
167 
ProcessSweepingAnimation(ProgressType type,float value)168 void ProgressModifier::ProcessSweepingAnimation(ProgressType type, float value)
169 {
170     if (!isVisible_) {
171         return;
172     }
173 
174     switch (type) {
175         case ProgressType::RING:
176             ProcessRingSweepingAnimation(value);
177             break;
178         case ProgressType::LINEAR:
179             ProcessLinearSweepingAnimation(value);
180             break;
181         case ProgressType::CAPSULE:
182             StartCapsuleSweepingAnimation(value);
183             break;
184         default:
185             break;
186     }
187 }
188 
StartCapsuleSweepingAnimation(float value)189 void ProgressModifier::StartCapsuleSweepingAnimation(float value)
190 {
191     auto contentSize = contentSize_->Get();
192     float barLength =
193         GreatOrEqual(contentSize.Width(), contentSize.Height()) ? contentSize.Width() : contentSize.Height();
194     float date = (value / maxValue_->Get()) * barLength + SWEEP_WIDTH.ConvertToPx();
195     float sweepSpeed = barLength / TIME_2000; // It takes 2 seconds to sweep the whole bar length.
196 
197     if (!isSweeping_ && sweepEffect_->Get() && isVisible_) {
198         StartCapsuleSweepingAnimationImpl(date, sweepSpeed);
199     } else if (!sweepEffect_->Get() || !isVisible_) {
200         StopSweepingAnimation();
201     } else {
202         dateUpdated_ = !NearEqual(sweepingDateBackup_, date);
203     }
204     sweepingDateBackup_ = date;
205 }
206 
StartCapsuleSweepingAnimationImpl(float value,float speed)207 void ProgressModifier::StartCapsuleSweepingAnimationImpl(float value, float speed)
208 {
209     if (!isVisible_ || !sweepEffect_) {
210         return;
211     }
212 
213     isSweeping_ = true;
214     sweepingDate_->Set(0.0f);
215     speed = NearZero(speed) ? 1.0f : speed;
216     int32_t time = value / speed;
217     AnimationOption option = AnimationOption();
218     auto motion = AceType::MakeRefPtr<LinearCurve>();
219     option.SetCurve(motion);
220     option.SetIteration(-1);
221     option.SetDuration(time);
222 
223     AnimationUtils::Animate(
224         option,
225         [value, id = Container::CurrentId(), weak = WeakClaim(this)]() {
226             ContainerScope scope(id);
227             auto modifier = weak.Upgrade();
228             CHECK_NULL_VOID(modifier);
229             modifier->sweepingDate_->Set(value);
230         },
231         nullptr,
232         [id = Container::CurrentId(), weak = WeakClaim(this), speed]() {
233             ContainerScope scope(id);
234             auto modifier = weak.Upgrade();
235             CHECK_NULL_VOID(modifier);
236             float currentDate = modifier->sweepingDate_->Get();
237             if (modifier->dateUpdated_) {
238                 modifier->dateUpdated_ = false;
239                 modifier->StopSweepingAnimation(currentDate);
240                 modifier->StartContinuousSweepingAnimation(currentDate, modifier->sweepingDateBackup_, speed);
241                 auto context = PipelineBase::GetCurrentContext();
242                 context->RequestFrame();
243             }
244         });
245 }
246 
SetRingProgressColor(const Gradient & color)247 void ProgressModifier::SetRingProgressColor(const Gradient& color)
248 {
249     CHECK_NULL_VOID(ringProgressColors_);
250     ringProgressColors_->Set(GradientArithmetic(color));
251 }
252 
SetPaintShadow(bool paintShadow)253 void ProgressModifier::SetPaintShadow(bool paintShadow)
254 {
255     CHECK_NULL_VOID(paintShadow_);
256     paintShadow_->Set(paintShadow);
257 }
258 
SetProgressStatus(ProgressStatus status)259 void ProgressModifier::SetProgressStatus(ProgressStatus status)
260 {
261     CHECK_NULL_VOID(progressStatus_);
262     progressStatus_->Set(static_cast<int32_t>(status));
263     if (status == ProgressStatus::LOADING) {
264         StartRingLoadingAnimation();
265     }
266 }
267 
SetIsItalic(bool isItalic)268 void ProgressModifier::SetIsItalic(bool isItalic)
269 {
270     CHECK_NULL_VOID(isItalic_);
271     isItalic_->Set(isItalic);
272 }
273 
SetVisible(bool isVisible)274 void ProgressModifier::SetVisible(bool isVisible)
275 {
276     CHECK_NULL_VOID(isVisible_ != isVisible);
277     isVisible_ = isVisible;
278 
279     if (!isVisible) {
280         if (isLoading_) {
281             StopRingLoadingHeadAnimation();
282             StopRingLoadingTailAnimation();
283         }
284 
285         if (isSweeping_) {
286             StopSweepingAnimation();
287         }
288     }
289 }
290 
SetSmoothEffect(bool value)291 void ProgressModifier::SetSmoothEffect(bool value)
292 {
293     CHECK_NULL_VOID(smoothEffect_);
294     smoothEffect_->Set(value);
295 }
296 
StartRingLoadingAnimation()297 void ProgressModifier::StartRingLoadingAnimation()
298 {
299     if (!isLoading_ && isVisible_) {
300         isLoading_ = true;
301         StartRingLoadingHeadAnimation();
302         StartRingLoadingTailAnimation();
303     }
304 }
305 
StartRingLoadingHeadAnimation()306 void ProgressModifier::StartRingLoadingHeadAnimation()
307 {
308     auto context = PipelineBase::GetCurrentContext();
309     CHECK_NULL_VOID(context);
310     bool isFormRender = context->IsFormRender() && !IsDynamicComponent();
311     AnimationOption optionHead = AnimationOption();
312     auto curveHead = AceType::MakeRefPtr<TailingHeadCurve>();
313     optionHead.SetDuration(LOADING_ANIMATION_DURATION);
314     optionHead.SetCurve(curveHead);
315     optionHead.SetIteration(isFormRender ? 1 : -1);
316     AnimationUtils::Animate(
317         optionHead, [&]() { trailingHeadDate_->Set(ANGLE_360); }, nullptr,
318         [weak = AceType::WeakClaim(this), id = Container::CurrentId()]() {
319             ContainerScope scope(id);
320             auto modifier = weak.Upgrade();
321             CHECK_NULL_VOID(modifier);
322             if (static_cast<ProgressStatus>(modifier->progressStatus_->Get()) == ProgressStatus::PROGRESSING) {
323                 modifier->StopRingLoadingHeadAnimation();
324             }
325         });
326 }
327 
StartRingLoadingTailAnimation()328 void ProgressModifier::StartRingLoadingTailAnimation()
329 {
330     auto context = PipelineBase::GetCurrentContext();
331     CHECK_NULL_VOID(context);
332     bool isFormRender = context->IsFormRender() && !IsDynamicComponent();
333     AnimationOption optionTail = AnimationOption();
334     auto curveTail = AceType::MakeRefPtr<CubicCurve>(0.33f, 0.00f, 0.66f, 0.10f);
335     optionTail.SetDuration(LOADING_ANIMATION_DURATION);
336     optionTail.SetCurve(curveTail);
337     optionTail.SetIteration(isFormRender ? 1 : -1);
338     AnimationUtils::Animate(
339         optionTail,
340         [&]() { trailingTailDate_->Set(ANGLE_360); },
341         nullptr,
342         [weak = AceType::WeakClaim(this), id = Container::CurrentId()]() {
343             ContainerScope scope(id);
344             auto modifier = weak.Upgrade();
345             CHECK_NULL_VOID(modifier);
346             if (static_cast<ProgressStatus>(modifier->progressStatus_->Get()) == ProgressStatus::PROGRESSING) {
347                 modifier->StopRingLoadingTailAnimation();
348                 if (GreatOrEqual(modifier->valueBackup_, 0.0f)) {
349                     modifier->SetValue(modifier->valueBackup_);
350                 }
351             }
352         });
353 }
354 
StopRingLoadingHeadAnimation()355 void ProgressModifier::StopRingLoadingHeadAnimation()
356 {
357     AnimationOption option = AnimationOption();
358     option.SetDuration(0);
359     AnimationUtils::Animate(option, [&]() { trailingHeadDate_->Set(0.0f); });
360 }
361 
StopRingLoadingTailAnimation()362 void ProgressModifier::StopRingLoadingTailAnimation()
363 {
364     AnimationOption option = AnimationOption();
365     option.SetDuration(0);
366     AnimationUtils::Animate(option, [&]() { trailingTailDate_->Set(0.0f); });
367     isLoading_ = false;
368 }
369 
ProcessRingSweepingAnimation(float value)370 void ProgressModifier::ProcessRingSweepingAnimation(float value)
371 {
372     if (NearZero(value) || NearEqual(value, maxValue_->Get())) {
373         StopSweepingAnimation();
374     } else {
375         StartRingSweepingAnimation(value);
376     }
377 }
378 
ProcessLinearSweepingAnimation(float value)379 void ProgressModifier::ProcessLinearSweepingAnimation(float value)
380 {
381     if (NearZero(value) || NearEqual(value, maxValue_->Get())) {
382         StopSweepingAnimation();
383     } else {
384         StartLinearSweepingAnimation(value);
385     }
386 }
387 
StartRingSweepingAnimation(float value)388 void ProgressModifier::StartRingSweepingAnimation(float value)
389 {
390     float maxValue = NearZero(maxValue_->Get()) ? 1.0f : maxValue_->Get();
391     float date = value / maxValue * ANGLE_360 + ANGLE_45;
392     float additionalAngle = CalcRingProgressAdditionalAngle();
393     date += additionalAngle * 2;
394     float sweepSpeed = float(ANGLE_360) / TIME_4000; // It takes 4 seconds to sweep a circle
395 
396     if (!isSweeping_ && ringSweepEffect_->Get()) {
397         StartRingSweepingAnimationImpl(date, sweepSpeed);
398     } else if (!ringSweepEffect_->Get() || NearEqual(valueBackup_, maxValue_->Get())) {
399         StopSweepingAnimation();
400     } else {
401         dateUpdated_ = !NearEqual(sweepingDateBackup_, date);
402     }
403 
404     sweepingDateBackup_ = date;
405 }
406 
StartRingSweepingAnimationImpl(float date,float speed)407 void ProgressModifier::StartRingSweepingAnimationImpl(float date, float speed)
408 {
409     if (!isVisible_ || !ringSweepEffect_) {
410         return;
411     }
412 
413     if (NearEqual(valueBackup_, maxValue_->Get())) {
414         return;
415     }
416 
417     auto context = PipelineBase::GetCurrentContext();
418     CHECK_NULL_VOID(context);
419     bool isFormRender = context->IsFormRender() && !IsDynamicComponent();
420     isSweeping_ = true;
421     AnimationOption option = AnimationOption();
422     speed = NearZero(speed) ? 1.0f : speed;
423     int32_t time = date / speed;
424     auto motion = AceType::MakeRefPtr<LinearCurve>();
425     option.SetCurve(motion);
426     option.SetIteration(isFormRender ? 1 : -1);
427     option.SetDuration(time);
428     AnimationUtils::Animate(
429         option,
430         [&]() { sweepingDate_->Set(date); },
431         nullptr,
432         [weak = WeakClaim(this), id = Container::CurrentId(), speed]() {
433             ContainerScope scope(id);
434             auto modifier = weak.Upgrade();
435             CHECK_NULL_VOID(modifier);
436             if (modifier->dateUpdated_) {
437                 modifier->dateUpdated_ = false;
438                 float currentDate = modifier->sweepingDate_->Get();
439                 modifier->StopSweepingAnimation(currentDate);
440                 modifier->StartContinuousSweepingAnimation(currentDate, modifier->sweepingDateBackup_, speed);
441                 auto context = PipelineBase::GetCurrentContext();
442                 context->RequestFrame();
443             }
444         });
445 }
446 
StartContinuousSweepingAnimation(float currentDate,float newDate,float speed)447 void ProgressModifier::StartContinuousSweepingAnimation(float currentDate, float newDate, float speed)
448 {
449     if (!isVisible_ || !IsSweepEffectOn()) {
450         return;
451     }
452 
453     if (NearEqual(valueBackup_, maxValue_->Get()) &&
454         (ProgressType(progressType_->Get()) == ProgressType::LINEAR ||
455         ProgressType(progressType_->Get()) == ProgressType::RING)) {
456         return;
457     }
458 
459     isSweeping_ = true;
460     speed = NearZero(speed) ? 1.0f : speed;
461     int32_t time = (newDate - currentDate) / speed;
462     AnimationOption option = AnimationOption();
463     auto motion = AceType::MakeRefPtr<LinearCurve>();
464     option.SetCurve(motion);
465     option.SetDuration(time);
466     AnimationUtils::Animate(
467         option,
468         [&]() { sweepingDate_->Set(newDate); },
469         [weak = WeakClaim(this), id = Container::CurrentId(), speed]() {
470             ContainerScope scope(id);
471             auto modifier = weak.Upgrade();
472             CHECK_NULL_VOID(modifier);
473             if (!modifier->dateUpdated_) {
474                 modifier->sweepingDate_->Set(0.0f);
475                 switch (ProgressType(modifier->progressType_->Get())) {
476                     case ProgressType::LINEAR:
477                         modifier->StartLinearSweepingAnimationImpl(modifier->sweepingDateBackup_, speed);
478                         break;
479                     case ProgressType::CAPSULE:
480                         modifier->StartCapsuleSweepingAnimationImpl(modifier->sweepingDateBackup_, speed);
481                         break;
482                     case ProgressType::RING:
483                         modifier->StartRingSweepingAnimationImpl(modifier->sweepingDateBackup_, speed);
484                         break;
485                     default:
486                         return;
487                 }
488                 auto context = PipelineBase::GetCurrentContext();
489                 context->RequestFrame();
490             } else {
491                 modifier->dateUpdated_ = false;
492                 float currentDate = modifier->sweepingDate_->Get();
493                 modifier->StartContinuousSweepingAnimation(currentDate, modifier->sweepingDateBackup_, speed);
494                 auto context = PipelineBase::GetCurrentContext();
495                 context->RequestFrame();
496             }
497         });
498 }
499 
IsSweepEffectOn()500 bool ProgressModifier::IsSweepEffectOn()
501 {
502     switch (ProgressType(progressType_->Get())) {
503         case ProgressType::LINEAR:
504             return linearSweepEffect_;
505         case ProgressType::CAPSULE:
506             return sweepEffect_;
507         case ProgressType::RING:
508             return ringSweepEffect_;
509         default:
510             return false;
511     }
512 }
513 
StopSweepingAnimation(float date)514 void ProgressModifier::StopSweepingAnimation(float date)
515 {
516     if (isSweeping_) {
517         isSweeping_ = false;
518         dateUpdated_ = false;
519         AnimationOption option = AnimationOption();
520         option.SetDuration(0);
521         AnimationUtils::Animate(option, [&]() { sweepingDate_->Set(date); });
522     }
523 }
524 
CalcRingProgressAdditionalAngle() const525 float ProgressModifier::CalcRingProgressAdditionalAngle() const
526 {
527     auto contentSize = contentSize_->Get();
528     auto strokeWidth = strokeWidth_->Get();
529     PointF centerPt = PointF(contentSize.Width() / 2, contentSize.Height() / 2);
530     float radius = std::min(contentSize.Width() / 2, contentSize.Height() / 2);
531     auto paintShadow = paintShadow_->Get() && GreatNotEqual(radius, RING_SHADOW_VALID_RADIUS_MIN);
532     auto shadowBlurOffset = paintShadow ? strokeWidth / 2 + std::max(RING_SHADOW_OFFSET_X, RING_SHADOW_OFFSET_Y) : 0.0f;
533     if (GreatOrEqual(strokeWidth + shadowBlurOffset, radius)) {
534         strokeWidth = radius / 2;
535         shadowBlurOffset = paintShadow ? strokeWidth / 2 + std::max(RING_SHADOW_OFFSET_X, RING_SHADOW_OFFSET_Y) : 0.0f;
536     }
537     return asinf((strokeWidth / 2) / (radius - strokeWidth / 2 - shadowBlurOffset)) * ANGLE_180 / PI_NUM;
538 }
539 
StartLinearSweepingAnimation(float value)540 void ProgressModifier::StartLinearSweepingAnimation(float value)
541 {
542     auto contentSize = contentSize_->Get();
543     float radius = strokeWidth_->Get() / 2;
544     float barLength = 0.0f;
545     float dateLength = 0.0f;
546 
547     if (GreatOrEqual(contentSize.Width(), contentSize.Height())) {
548         barLength = contentSize.Width() - radius * 2;
549     } else {
550         barLength = contentSize.Height() - radius * 2;
551     }
552 
553     if (NearEqual(barLength, 0.0f)) {
554         return;
555     }
556 
557     dateLength = barLength * value / maxValue_->Get();
558     if (NearEqual(dateLength, 0.0f)) {
559         return;
560     }
561 
562     float date = dateLength + strokeWidth_->Get() + LINEAR_SWEEPING_LEN.ConvertToPx();
563     float sweepSpeed = barLength / TIME_2000; // It takes 2 seconds to sweep the whole bar length
564     if (!isSweeping_ && linearSweepEffect_->Get()) {
565         StartLinearSweepingAnimationImpl(date, sweepSpeed);
566     } else if (!linearSweepEffect_->Get() || NearEqual(valueBackup_, maxValue_->Get())) {
567         StopSweepingAnimation();
568     } else {
569         dateUpdated_ = !NearEqual(sweepingDateBackup_, date);
570     }
571 
572     sweepingDateBackup_ = date;
573 }
574 
StartLinearSweepingAnimationImpl(float date,float speed)575 void ProgressModifier::StartLinearSweepingAnimationImpl(float date, float speed)
576 {
577     if (!isVisible_ || !linearSweepEffect_) {
578         return;
579     }
580 
581     if (NearEqual(valueBackup_, maxValue_->Get())) {
582         return;
583     }
584 
585     auto context = PipelineBase::GetCurrentContext();
586     CHECK_NULL_VOID(context);
587     bool isFormRender = context->IsFormRender() && !IsDynamicComponent();
588     isSweeping_ = true;
589     sweepingDate_->Set(0.0f);
590     speed = NearZero(speed) ? 1.0f : speed;
591     int32_t time = date / speed;
592     AnimationOption option = AnimationOption();
593     auto motion = AceType::MakeRefPtr<LinearCurve>();
594     option.SetCurve(motion);
595     option.SetIteration(isFormRender ? 1 : -1);
596     option.SetDuration(time);
597     AnimationUtils::Animate(
598         option,
599         [&]() { sweepingDate_->Set(date); },
600         nullptr,
601         [weak = WeakClaim(this), id = Container::CurrentId(), speed]() {
602             ContainerScope scope(id);
603             auto modifier = weak.Upgrade();
604             CHECK_NULL_VOID(modifier);
605             if (modifier->dateUpdated_) {
606                 modifier->dateUpdated_ = false;
607                 float currentDate = modifier->sweepingDate_->Get();
608                 modifier->StopSweepingAnimation(currentDate);
609                 modifier->StartContinuousSweepingAnimation(currentDate, modifier->sweepingDateBackup_, speed);
610                 auto context = PipelineBase::GetCurrentContext();
611                 context->RequestFrame();
612             }
613         });
614 }
615 
SetMaxValue(float value)616 void ProgressModifier::SetMaxValue(float value)
617 {
618     CHECK_NULL_VOID(maxValue_);
619     maxValue_->Set(value);
620 }
621 
SetValue(float value)622 void ProgressModifier::SetValue(float value)
623 {
624     valueBackup_ = value;
625 
626     if (isLoading_) {
627         return;
628     }
629 
630     CHECK_NULL_VOID(value_);
631     AnimationOption option = AnimationOption();
632     if (smoothEffect_->Get()) {
633         if (isVisible_) {
634             auto motion =
635                 AceType::MakeRefPtr<ResponsiveSpringMotion>(SPRING_MOTION_RESPONSE, SPRING_MOTION_DAMPING_FRACTION);
636             option.SetCurve(motion);
637         } else {
638             option.SetDuration(0);
639         }
640         AnimationUtils::Animate(option, [&]() { value_->Set(value); });
641     } else {
642         value_->Set(value);
643     }
644     ProcessSweepingAnimation(ProgressType(progressType_->Get()), value);
645 }
646 
SetScaleWidth(float value)647 void ProgressModifier::SetScaleWidth(float value)
648 {
649     CHECK_NULL_VOID(scaleWidth_);
650     scaleWidth_->Set(value);
651 }
652 
SetScaleCount(int32_t value)653 void ProgressModifier::SetScaleCount(int32_t value)
654 {
655     CHECK_NULL_VOID(scaleCount_);
656     scaleCount_->Set(value);
657 }
658 
SetContentOffset(const OffsetF & offset)659 void ProgressModifier::SetContentOffset(const OffsetF& offset)
660 {
661     CHECK_NULL_VOID(offset_);
662     offset_->Set(offset);
663 }
664 
SetContentSize(const SizeF & contentSize)665 void ProgressModifier::SetContentSize(const SizeF& contentSize)
666 {
667     CHECK_NULL_VOID(contentSize_);
668     contentSize_->Set(contentSize);
669 }
670 
SetBorderWidth(float width)671 void ProgressModifier::SetBorderWidth(float width)
672 {
673     capsuleBorderWidth_->Set(width);
674 }
675 
SetSweepEffect(bool value)676 void ProgressModifier::SetSweepEffect(bool value)
677 {
678     sweepEffect_->Set(value);
679 }
680 
SetRingSweepEffect(bool value)681 void ProgressModifier::SetRingSweepEffect(bool value)
682 {
683     ringSweepEffect_->Set(value);
684 }
685 
SetLinearSweepEffect(bool value)686 void ProgressModifier::SetLinearSweepEffect(bool value)
687 {
688     linearSweepEffect_->Set(value);
689 }
690 
SetCapsuleBorderRadius(float borderRadius)691 void ProgressModifier::SetCapsuleBorderRadius(float borderRadius)
692 {
693     CHECK_NULL_VOID(capsuleBorderRadius_);
694     capsuleBorderRadius_->Set(borderRadius);
695 }
696 
SetRingProgressLeftPadding(const Dimension & ringProgressLeftPadding)697 void ProgressModifier::SetRingProgressLeftPadding(const Dimension& ringProgressLeftPadding)
698 {
699     ringProgressLeftPadding_ = ringProgressLeftPadding;
700 }
701 
ContentDrawWithFunction(DrawingContext & context)702 void ProgressModifier::ContentDrawWithFunction(DrawingContext& context)
703 {
704     auto contentSize = contentSize_->Get();
705     auto& canvas = context.canvas;
706     if (progressType_->Get() == static_cast<int32_t>(ProgressType::LINEAR)) {
707         PaintLinear(canvas, offset_->Get(), contentSize);
708     } else if (progressType_->Get() == static_cast<int32_t>(ProgressType::RING)) {
709         PaintRing(canvas, offset_->Get(), contentSize);
710     } else if (progressType_->Get() == static_cast<int32_t>(ProgressType::SCALE)) {
711         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
712             PaintScaleRingForApiNine(canvas, offset_->Get(), contentSize);
713         } else {
714             PaintScaleRing(canvas, offset_->Get(), contentSize);
715         }
716     } else if (progressType_->Get() == static_cast<int32_t>(ProgressType::MOON)) {
717         PaintMoon(canvas, offset_->Get(), contentSize);
718     } else if (progressType_->Get() == static_cast<int32_t>(ProgressType::CAPSULE)) {
719         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
720             if (contentSize.Width() >= contentSize.Height()) {
721                 PaintCapsuleForApiNine(canvas, offset_->Get(), contentSize);
722             } else {
723                 PaintVerticalCapsuleForApiNine(canvas, offset_->Get(), contentSize);
724             }
725         } else if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
726             if (contentSize.Width() >= contentSize.Height()) {
727                 PaintCapsule(canvas, offset_->Get(), contentSize, contentSize.Height() / INT32_TWO);
728             } else {
729                 PaintVerticalCapsule(canvas, offset_->Get(), contentSize, contentSize.Width() / INT32_TWO);
730             }
731         } else {
732             if (contentSize.Width() >= contentSize.Height()) {
733                 PaintCapsule(canvas, offset_->Get(), contentSize, capsuleBorderRadius_->Get());
734             } else {
735                 PaintVerticalCapsule(canvas, offset_->Get(), contentSize, capsuleBorderRadius_->Get());
736             }
737         }
738     } else {
739         PaintLinear(canvas, offset_->Get(), contentSize);
740     }
741 }
742 
PaintLinear(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize) const743 void ProgressModifier::PaintLinear(RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize) const
744 {
745     RSBrush brush;
746     brush.SetAntiAlias(true);
747     brush.SetColor(ToRSColor(bgColor_->Get()));
748     double radius = strokeRadius_->Get();
749     if (contentSize.Width() >= contentSize.Height()) {
750         double barLength = contentSize.Width() - radius * INT32_TWO;
751         CHECK_NULL_VOID(Positive(barLength));
752         double dateLength = std::min(barLength * value_->Get() / maxValue_->Get(), barLength);
753         canvas.AttachBrush(brush);
754         canvas.DrawRoundRect(
755             { { offset.GetX(), offset.GetY(), contentSize.Width() + offset.GetX(),
756                                    strokeWidth_->Get() + offset.GetY() },
757             radius, radius });
758         canvas.DetachBrush();
759         // progress selected part
760         CHECK_NULL_VOID(Positive(value_->Get()));
761         brush.SetColor(ToRSColor((color_->Get())));
762         canvas.AttachBrush(brush);
763 #ifndef USE_ROSEN_DRAWING
764         RSPath path;
765 #else
766         RSRecordingPath path;
767 #endif
768         float leftTopX = !isRightToLeft_->Get()
769                              ? offset.GetX()
770                              : contentSize.Width() + offset.GetX() - (dateLength + radius * INT32_TWO);
771         float leftTopY = offset.GetY();
772         float rightBottomX = !isRightToLeft_->Get() ? dateLength + offset.GetX() + radius * INT32_TWO
773                                                     : contentSize.Width() + offset.GetX();
774         float rightBottomY = strokeWidth_->Get() + offset.GetY();
775         path.AddRoundRect({ leftTopX, leftTopY, rightBottomX, rightBottomY }, radius, radius);
776         canvas.DrawPath(path);
777         canvas.DetachBrush();
778         canvas.Restore();
779         PaintLinearSweeping(canvas, offset, path, true, contentSize);
780     } else {
781         double barLength = contentSize.Height() - radius * INT32_TWO;
782         CHECK_NULL_VOID(Positive(barLength));
783         double dateLength = std::min(barLength * value_->Get() / maxValue_->Get(), barLength);
784         canvas.AttachBrush(brush);
785         canvas.DrawRoundRect(
786             { { offset.GetX(), offset.GetY(), strokeWidth_->Get() + offset.GetX(),
787                                    contentSize.Height() + offset.GetY() },
788             radius, radius });
789         canvas.DetachBrush();
790         // progress selected part
791         CHECK_NULL_VOID(Positive(value_->Get()));
792         brush.SetColor(ToRSColor((color_->Get())));
793         canvas.AttachBrush(brush);
794 #ifndef USE_ROSEN_DRAWING
795         RSPath path;
796 #else
797         RSRecordingPath path;
798 #endif
799         path.AddRoundRect(
800             { offset.GetX(), offset.GetY(), strokeWidth_->Get() + offset.GetX(),
801               dateLength + offset.GetY() + radius * INT32_TWO },
802             radius, radius);
803         canvas.DrawPath(path);
804         canvas.DetachBrush();
805         canvas.Restore();
806         PaintLinearSweeping(canvas, offset, path, false, contentSize);
807     }
808 }
809 
PaintLinearSweeping(RSCanvas & canvas,const OffsetF & offset,const RSPath & path,bool isHorizontal,const SizeF & contentSize) const810 void ProgressModifier::PaintLinearSweeping(
811     RSCanvas& canvas, const OffsetF& offset, const RSPath& path, bool isHorizontal, const SizeF& contentSize) const
812 {
813     if (NearZero(value_->Get()) || NearZero(maxValue_->Get())) {
814         return;
815     }
816 
817     // If the progress reaches 100%, stop sweeping.
818     if (NearEqual(value_->Get(), maxValue_->Get())) {
819         return;
820     }
821 
822     std::vector<RSColorQuad> colors;
823     std::vector<float> pos;
824     GenerateLinearSweepingGradientInfo(colors, pos);
825 
826     RSBrush brush;
827     float leftTopX = 0.0f;
828     float leftTopY = 0.0f;
829     float rightBottomX = 0.0f;
830     float rightBottomY = 0.0f;
831     if (isHorizontal) {
832         leftTopX = !isRightToLeft_->Get() ? offset.GetX() + sweepingDate_->Get() - LINEAR_SWEEPING_LEN.ConvertToPx()
833                                           : contentSize.Width() + offset.GetX() - sweepingDate_->Get();
834         leftTopY = offset.GetY();
835         rightBottomX = !isRightToLeft_->Get() ? offset.GetX() + sweepingDate_->Get()
836                                               : contentSize.Width() + offset.GetX() - sweepingDate_->Get() +
837                                                     LINEAR_SWEEPING_LEN.ConvertToPx();
838         rightBottomY = offset.GetY() + strokeWidth_->Get();
839     } else {
840         leftTopX = offset.GetX();
841         leftTopY = offset.GetY() + sweepingDate_->Get() - LINEAR_SWEEPING_LEN.ConvertToPx();
842         rightBottomX = offset.GetX() + strokeWidth_->Get();
843         rightBottomY = offset.GetY() + sweepingDate_->Get();
844     }
845 
846     RSRect rect(leftTopX, leftTopY, rightBottomX, rightBottomY);
847 #ifndef USE_ROSEN_DRAWING
848     brush.SetShaderEffect(RSShaderEffect::CreateLinearGradient(
849         ToRSPoint(PointF(leftTopX, leftTopY)),
850         ToRSPoint(PointF(rightBottomX, rightBottomY)),
851         colors, pos, RSTileMode::CLAMP));
852 #else
853     brush.SetShaderEffect(RSRecordingShaderEffect::CreateLinearGradient(
854         ToRSPoint(PointF(leftTopX, leftTopY)),
855         ToRSPoint(PointF(rightBottomX, rightBottomY)),
856         colors, pos, RSTileMode::CLAMP));
857 #endif
858     canvas.Save();
859     canvas.ClipPath(path, RSClipOp::INTERSECT, true);
860     canvas.AttachBrush(brush);
861     canvas.DrawRect(rect);
862     canvas.DetachBrush();
863     canvas.Restore();
864 }
865 
GenerateLinearSweepingGradientInfo(std::vector<RSColorQuad> & colors,std::vector<float> & pos) const866 void ProgressModifier::GenerateLinearSweepingGradientInfo(
867     std::vector<RSColorQuad>& colors, std::vector<float>& pos) const
868 {
869     Gradient gradient;
870     Color sweepingColorBase = Color::WHITE;
871     Color sweepingColorEnd = sweepingColorBase.ChangeOpacity(0.0);
872     GradientColor gradientColorEnd;
873     gradientColorEnd.SetColor(sweepingColorEnd);
874     gradientColorEnd.SetDimension(Dimension(0.0, DimensionUnit::PERCENT));
875     gradient.AddColor(gradientColorEnd);
876 
877     // The sweep layer is a white gradient layer of length 80 vp with a opacity of 0.3 at 75 vp and 0.0 at both ends.
878     Dimension stageLen = 75.0_vp;
879     Color sweepingColorMiddle = sweepingColorBase.ChangeOpacity(0.3);
880     GradientColor gradientColorMiddle;
881     gradientColorMiddle.SetColor(sweepingColorMiddle);
882     gradientColorMiddle.SetDimension(
883         Dimension(!isRightToLeft_->Get() ? stageLen.ConvertToPx() / LINEAR_SWEEPING_LEN.ConvertToPx()
884                                          : 1 - stageLen.ConvertToPx() / LINEAR_SWEEPING_LEN.ConvertToPx(),
885             DimensionUnit::PERCENT));
886     gradient.AddColor(gradientColorMiddle);
887 
888     Color sweepingColorStart = sweepingColorBase.ChangeOpacity(0.0);
889     GradientColor gradientColorStart;
890     gradientColorStart.SetColor(sweepingColorStart);
891     gradientColorStart.SetDimension(Dimension(1.0, DimensionUnit::PERCENT));
892     gradient.AddColor(gradientColorStart);
893 
894     auto gradientColors = gradient.GetColors();
895     for (size_t i = 0; i < gradientColors.size(); i++) {
896         colors.emplace_back(gradientColors[i].GetColor().GetValue());
897         pos.emplace_back(gradientColors[i].GetDimension().Value());
898     }
899 }
900 
PaintRing(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize) const901 void ProgressModifier::PaintRing(RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize) const
902 {
903     auto centerPt = PointF(contentSize.Width() / 2, contentSize.Height() / 2) + offset;
904     auto radius = std::min(contentSize.Width() / 2, contentSize.Height() / 2);
905     auto angle = std::min((value_->Get() / maxValue_->Get()) * ANGLE_360, static_cast<float>(ANGLE_360));
906     auto thickness = strokeWidth_->Get();
907     // No shadow is drawn if radius is less or equal to 10, because it is no enough space to draw both ring and shadow.
908     auto paintShadow = paintShadow_->Get() && GreatNotEqual(radius, RING_SHADOW_VALID_RADIUS_MIN);
909     auto shadowBlurOffset = paintShadow ? thickness / 2 + std::max(RING_SHADOW_OFFSET_X, RING_SHADOW_OFFSET_Y) : 0.0f;
910     if (GreatOrEqual(thickness + shadowBlurOffset, radius)) {
911         thickness = radius / 2;
912         shadowBlurOffset = paintShadow ? thickness / 2 + std::max(RING_SHADOW_OFFSET_X, RING_SHADOW_OFFSET_Y) : 0.0f;
913     }
914     // The shadowBlurSigma is an empirical value. If it is greater than thickness / 5, the shadow will be cut by
915     // the canvas boundary.
916     auto shadowBlurSigma = std::max(thickness / 5, RING_SHADOW_BLUR_RADIUS_MIN);
917     radius = radius - thickness / 2 - shadowBlurOffset;
918 
919     RingProgressData ringData;
920     ringData.centerPt = centerPt;
921     ringData.radius = radius;
922     ringData.angle = angle;
923     ringData.thickness = thickness;
924     ringData.shadowBlurSigma = shadowBlurSigma;
925 
926     PaintRingBackground(canvas, ringData);
927     if (isRightToLeft_->Get()) {
928         canvas.Scale(-1, 1);
929         canvas.Translate(
930             -((radius + shadowBlurOffset + ringProgressLeftPadding_.ConvertToPx()) * INT32_TWO + thickness), 0);
931     }
932     if (isLoading_) {
933         PaintTrailing(canvas, ringData);
934         return;
935     }
936 
937     if (NearZero(angle)) {
938         return;
939     }
940 
941     if (paintShadow) {
942         ringData.centerPt = centerPt + OffsetF(RING_SHADOW_OFFSET_X, RING_SHADOW_OFFSET_Y);
943         PaintRingProgressOrShadow(canvas, ringData, true);
944     }
945     ringData.centerPt = centerPt;
946     PaintRingProgressOrShadow(canvas, ringData, false);
947     PaintRingSweeping(canvas, ringData);
948 }
949 
PaintRingBackground(RSCanvas & canvas,const RingProgressData & ringProgressData) const950 void ProgressModifier::PaintRingBackground(RSCanvas& canvas, const RingProgressData& ringProgressData) const
951 {
952     RSPen pen;
953     pen.SetAntiAlias(true);
954     pen.SetWidth(ringProgressData.thickness);
955     pen.SetCapStyle(ToRSCapStyle(LineCap::ROUND));
956     pen.SetColor(ToRSColor(bgColor_->Get()));
957 
958     canvas.Save();
959     canvas.AttachPen(pen);
960     canvas.DrawCircle(ToRSPoint(ringProgressData.centerPt), ringProgressData.radius);
961     canvas.DetachPen();
962     canvas.Restore();
963 }
964 
GetRingProgressGradientColors() const965 std::vector<GradientColor> ProgressModifier::GetRingProgressGradientColors() const
966 {
967     Gradient gradient = SortGradientColorsByOffset(ringProgressColors_->Get().GetGradient());
968     std::vector<GradientColor> gradientColors = gradient.GetColors();
969     // Fault protection processing, if gradientColors is empty, set to default colors.
970 
971     if (gradientColors.empty()) {
972         auto pipeline = PipelineBase::GetCurrentContext();
973         CHECK_NULL_RETURN(pipeline, gradientColors);
974         auto theme = pipeline->GetTheme<ProgressTheme>(GetThemeScopeId());
975         CHECK_NULL_RETURN(theme, gradientColors);
976         GradientColor endColor;
977         GradientColor beginColor;
978         endColor.SetLinearColor(LinearColor(theme->GetRingProgressEndSideColor()));
979         endColor.SetDimension(0.0);
980         beginColor.SetLinearColor(LinearColor(theme->GetRingProgressBeginSideColor()));
981         beginColor.SetDimension(1.0);
982         gradientColors.emplace_back(endColor);
983         gradientColors.emplace_back(beginColor);
984     }
985     return gradientColors;
986 }
987 
PaintRingProgressOrShadow(RSCanvas & canvas,const RingProgressData & ringProgressData,bool isShadow) const988 void ProgressModifier::PaintRingProgressOrShadow(
989     RSCanvas& canvas, const RingProgressData& ringProgressData, bool isShadow) const
990 {
991     auto angle = ringProgressData.angle;
992     float additionalAngle = CalcRingProgressAdditionalAngle();
993 
994     std::vector<GradientColor> gradientColors = GetRingProgressGradientColors();
995 
996     RSBrush brush;
997     brush.SetAntiAlias(true);
998 
999     if (isShadow) {
1000         for (size_t i = 0; i < gradientColors.size(); i++) {
1001             Color color = gradientColors[i].GetLinearColor().BlendOpacity(RING_SHADOW_OPACITY);
1002             gradientColors[i].SetLinearColor(LinearColor(color));
1003         }
1004         RSFilter filter;
1005 #ifndef USE_ROSEN_DRAWING
1006         filter.SetImageFilter(RSImageFilter::CreateBlurImageFilter(
1007             ringProgressData.shadowBlurSigma, ringProgressData.shadowBlurSigma, RSTileMode::DECAL, nullptr));
1008 #else
1009         filter.SetImageFilter(RSRecordingImageFilter::CreateBlurImageFilter(
1010             ringProgressData.shadowBlurSigma, ringProgressData.shadowBlurSigma, RSTileMode::DECAL, nullptr));
1011 #endif
1012         brush.SetFilter(filter);
1013     }
1014 
1015     if (LessOrEqual(angle + additionalAngle * INT32_TWO, ANGLE_360)) {
1016         PaintWhole(canvas, brush, ringProgressData, gradientColors);
1017     } else {
1018         PaintBeginHalf(canvas, brush, ringProgressData, gradientColors);
1019         PaintEndHalf(canvas, brush, ringProgressData, gradientColors);
1020     }
1021 }
1022 
PaintWhole(RSCanvas & canvas,RSBrush & brush,const RingProgressData & ringProgressData,std::vector<GradientColor> & gradientColors) const1023 void ProgressModifier::PaintWhole(RSCanvas& canvas, RSBrush& brush, const RingProgressData& ringProgressData,
1024     std::vector<GradientColor>& gradientColors) const
1025 {
1026     PointF centerPt = ringProgressData.centerPt;
1027     auto radius = ringProgressData.radius;
1028     auto angle = ringProgressData.angle;
1029     auto thickness = ringProgressData.thickness;
1030     double halfThickness = thickness / 2;
1031     float additionalAngle = CalcRingProgressAdditionalAngle();
1032     double radAngle = angle / ANGLE_180 * PI_NUM;
1033     double radAdditionalAngle = additionalAngle / ANGLE_180 * PI_NUM;
1034     double sinPointOutside = std::sin(radAngle + radAdditionalAngle) * (radius - halfThickness);
1035     double cosPointOutside = std::cos(radAngle + radAdditionalAngle) * (radius - halfThickness);
1036     double sinPointStart = std::sin(radAdditionalAngle) * radius;
1037     double cosPointStart = std::cos(radAdditionalAngle) * radius;
1038 
1039     std::vector<RSColorQuad> colors;
1040     std::vector<float> pos;
1041     for (size_t i = 0; i < gradientColors.size(); i++) {
1042         colors.emplace_back(gradientColors[i].GetLinearColor().GetValue());
1043         pos.emplace_back(gradientColors[i].GetDimension().Value());
1044     }
1045 
1046     RSPath path;
1047 #ifndef USE_ROSEN_DRAWING
1048     brush.SetShaderEffect(RSShaderEffect::CreateSweepGradient(ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())),
1049         colors, pos, RSTileMode::CLAMP, 0, angle + additionalAngle * INT32_TWO, nullptr));
1050 #else
1051     brush.SetShaderEffect(
1052         RSRecordingShaderEffect::CreateSweepGradient(ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos,
1053             RSTileMode::CLAMP, 0, angle + additionalAngle * INT32_TWO, nullptr));
1054 #endif
1055     path.ArcTo(centerPt.GetX() + cosPointStart - halfThickness, centerPt.GetY() + sinPointStart - halfThickness,
1056         centerPt.GetX() + cosPointStart + halfThickness, centerPt.GetY() + sinPointStart + halfThickness,
1057         ANGLE_180 + additionalAngle, ANGLE_180);
1058     path.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1059         centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness, additionalAngle, angle);
1060     path.ArcTo(halfThickness, halfThickness, 0.0f, RSPathDirection::CW_DIRECTION, centerPt.GetX() + cosPointOutside,
1061         centerPt.GetY() + sinPointOutside);
1062     path.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1063         centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness, additionalAngle + angle,
1064         -angle);
1065     path.Close();
1066     canvas.Save();
1067     canvas.Rotate(-ANGLE_90 - additionalAngle, centerPt.GetX(), centerPt.GetY());
1068     canvas.AttachBrush(brush);
1069     canvas.DrawPath(path);
1070     canvas.DetachBrush();
1071     canvas.Restore();
1072 }
1073 
PaintBeginHalf(RSCanvas & canvas,RSBrush & brush,const RingProgressData & ringProgressData,std::vector<GradientColor> & gradientColors) const1074 void ProgressModifier::PaintBeginHalf(RSCanvas& canvas, RSBrush& brush, const RingProgressData& ringProgressData,
1075     std::vector<GradientColor>& gradientColors) const
1076 {
1077     PointF centerPt = ringProgressData.centerPt;
1078     auto radius = ringProgressData.radius;
1079     auto angle = ringProgressData.angle;
1080     auto thickness = ringProgressData.thickness;
1081     double halfThickness = thickness / 2;
1082     float additionalAngle = CalcRingProgressAdditionalAngle();
1083 
1084     std::vector<RSColorQuad> colors;
1085     std::vector<float> pos;
1086     for (size_t i = 0; i < gradientColors.size(); i++) {
1087         colors.emplace_back(gradientColors[i].GetLinearColor().GetValue());
1088         pos.emplace_back(gradientColors[i].GetDimension().Value());
1089     }
1090     colors.emplace_back(gradientColors[0].GetLinearColor().GetValue());
1091     pos.emplace_back((ANGLE_360 - additionalAngle) / ANGLE_360);
1092 
1093     RSPath beginPath;
1094     RSPath path;
1095 #ifndef USE_ROSEN_DRAWING
1096     brush.SetShaderEffect(RSShaderEffect::CreateSweepGradient(ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())),
1097         colors, pos, RSTileMode::CLAMP, 0, angle, nullptr));
1098 #else
1099     brush.SetShaderEffect(RSRecordingShaderEffect::CreateSweepGradient(
1100         ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos, RSTileMode::CLAMP, 0, angle, nullptr));
1101 #endif
1102     float drawAngle = ANGLE_180 + FLOAT_ZERO_FIVE;
1103     beginPath.MoveTo(centerPt.GetX() + radius - halfThickness, centerPt.GetY());
1104     beginPath.ArcTo(centerPt.GetX() + radius - halfThickness, centerPt.GetY() - halfThickness,
1105         centerPt.GetX() + radius + halfThickness, centerPt.GetY() + halfThickness, ANGLE_180, ANGLE_180);
1106     beginPath.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1107         centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness, 0, drawAngle);
1108     beginPath.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1109         centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness, drawAngle, -drawAngle);
1110     beginPath.Close();
1111 
1112     canvas.Save();
1113     canvas.Rotate(-ANGLE_90, centerPt.GetX(), centerPt.GetY());
1114     canvas.AttachBrush(brush);
1115     canvas.DrawPath(beginPath);
1116     canvas.DetachBrush();
1117     canvas.Restore();
1118 }
1119 
PaintEndHalf(RSCanvas & canvas,RSBrush & brush,const RingProgressData & ringProgressData,std::vector<GradientColor> & gradientColors) const1120 void ProgressModifier::PaintEndHalf(RSCanvas& canvas, RSBrush& brush, const RingProgressData& ringProgressData,
1121     std::vector<GradientColor>& gradientColors) const
1122 {
1123     PointF centerPt = ringProgressData.centerPt;
1124     auto radius = ringProgressData.radius;
1125     auto angle = ringProgressData.angle;
1126     auto thickness = ringProgressData.thickness;
1127     double halfThickness = thickness / 2;
1128     float additionalAngle = CalcRingProgressAdditionalAngle();
1129     double radArc = (angle - ANGLE_180) / ANGLE_180 * PI_NUM;
1130     double sinPointOutside = std::sin(radArc) * (radius - halfThickness);
1131     double cosPointOutside = std::cos(radArc) * (radius - halfThickness);
1132 
1133     std::vector<RSColorQuad> colors;
1134     std::vector<float> pos;
1135     if (gradientColors.size() != 0) {
1136         colors.emplace_back(gradientColors[gradientColors.size() - 1].GetLinearColor().GetValue());
1137     }
1138     pos.emplace_back(additionalAngle / ANGLE_360);
1139     for (size_t i = 0; i < gradientColors.size(); i++) {
1140         colors.emplace_back(gradientColors[i].GetLinearColor().GetValue());
1141         pos.emplace_back(gradientColors[i].GetDimension().Value());
1142     }
1143 
1144     RSPath endPath;
1145 #ifndef USE_ROSEN_DRAWING
1146     brush.SetShaderEffect(RSShaderEffect::CreateSweepGradient(
1147         ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos, RSTileMode::CLAMP, 0, angle, nullptr));
1148 #else
1149     brush.SetShaderEffect(RSRecordingShaderEffect::CreateSweepGradient(
1150         ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos, RSTileMode::CLAMP, 0, angle, nullptr));
1151 #endif
1152     endPath.MoveTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY());
1153     endPath.LineTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY());
1154     endPath.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1155         centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness, ANGLE_180,
1156         angle - ANGLE_180);
1157     endPath.ArcTo(halfThickness, halfThickness, 0.0f, RSPathDirection::CW_DIRECTION, centerPt.GetX() - cosPointOutside,
1158         centerPt.GetY() - sinPointOutside);
1159     endPath.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1160         centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness, angle, ANGLE_180 - angle);
1161     endPath.Close();
1162     canvas.Save();
1163     canvas.Rotate(-ANGLE_90, centerPt.GetX(), centerPt.GetY());
1164     canvas.AttachBrush(brush);
1165     canvas.DrawPath(endPath);
1166     canvas.DetachBrush();
1167     canvas.Restore();
1168 }
1169 
SortGradientColorsByOffset(const Gradient & gradient) const1170 Gradient ProgressModifier::SortGradientColorsByOffset(const Gradient& gradient) const
1171 {
1172     auto srcGradientColors = gradient.GetColors();
1173     std::sort(
1174         srcGradientColors.begin(), srcGradientColors.end(), [](const GradientColor& left, const GradientColor& right) {
1175             return left.GetDimension().Value() < right.GetDimension().Value();
1176         });
1177 
1178     Gradient sortedGradient;
1179     for (const auto& item : srcGradientColors) {
1180         sortedGradient.AddColor(item);
1181     }
1182 
1183     return sortedGradient;
1184 }
1185 
PaintRingSweeping(RSCanvas & canvas,const RingProgressData & ringProgressData) const1186 void ProgressModifier::PaintRingSweeping(RSCanvas& canvas, const RingProgressData& ringProgressData) const
1187 {
1188     if (NearZero(value_->Get()) || NearZero(maxValue_->Get())) {
1189         return;
1190     }
1191 
1192     // If the progress reaches 100%, stop sweeping.
1193     if (NearEqual(value_->Get(), maxValue_->Get())) {
1194         return;
1195     }
1196 
1197     auto centerPt = ringProgressData.centerPt;
1198     auto radius = ringProgressData.radius;
1199     auto thickness = ringProgressData.thickness;
1200     double halfThickness = thickness / 2;
1201 
1202     RSPen pen;
1203     pen.SetAntiAlias(true);
1204     pen.SetWidth(thickness);
1205     pen.SetCapStyle(ToRSCapStyle(LineCap::ROUND));
1206 
1207     std::vector<RSColorQuad> colors;
1208     std::vector<float> pos;
1209     GenerateRingSweepingGradientInfo(colors, pos);
1210 
1211     float date = sweepingDate_->Get();
1212     float additionalAngle = CalcRingProgressAdditionalAngle();
1213     float startSweepAngle = date - ANGLE_45 - additionalAngle;
1214 #ifndef USE_ROSEN_DRAWING
1215     pen.SetShaderEffect(RSShaderEffect::CreateSweepGradient(
1216         ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos,
1217         RSTileMode::CLAMP, 0, ANGLE_45, nullptr));
1218 
1219     RSPath path;
1220 #else
1221     pen.SetShaderEffect(RSRecordingShaderEffect::CreateSweepGradient(
1222         ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos,
1223         RSTileMode::CLAMP, 0, ANGLE_45, nullptr));
1224 
1225     RSRecordingPath path;
1226 #endif
1227     double totalDegree = ANGLE_360;
1228     double angleArc = (value_->Get() / maxValue_->Get()) * totalDegree;
1229     double radArc = angleArc / totalDegree * 2 * PI_NUM;
1230     double sinPointInside = std::sin(radArc) * (radius - halfThickness);
1231     double cosPointInside = std::cos(radArc) * (radius - halfThickness);
1232     if (LessOrEqual(startSweepAngle, ANGLE_90)) {
1233         path.MoveTo(centerPt.GetX(), centerPt.GetY() - radius + halfThickness);
1234         path.ArcTo(centerPt.GetX() - halfThickness, centerPt.GetY() - radius - halfThickness,
1235             centerPt.GetX() + halfThickness, centerPt.GetY() - radius + halfThickness,
1236             ANGLE_90, ANGLE_180);
1237         if (GreatNotEqual(angleArc + additionalAngle * INT32_TWO, ANGLE_360)) {
1238             path.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1239                 centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness,
1240                 -ANGLE_90, ANGLE_180);
1241             path.LineTo(centerPt.GetX(), centerPt.GetY() + radius - halfThickness);
1242             path.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1243                 centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness,
1244                 ANGLE_90, -ANGLE_180);
1245 #ifndef USE_ROSEN_DRAWING
1246             RSPath path2;
1247             RSPath path3;
1248 #else
1249             RSRecordingPath path2;
1250             RSRecordingPath path3;
1251 #endif
1252             float x = centerPt.GetX() + sin(radArc) * radius;
1253             float y = centerPt.GetY() - cos(radArc) * radius;
1254             path2.AddCircle(x, y, halfThickness);
1255             path3.Op(path, path2, RSPathOp::INTERSECT);
1256             path.Op(path, path3, RSPathOp::DIFFERENCE);
1257         } else if (GreatNotEqual(angleArc, ANGLE_180)) {
1258             path.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1259                 centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness,
1260                 -ANGLE_90, ANGLE_180);
1261             path.LineTo(centerPt.GetX(), centerPt.GetY() + radius - halfThickness);
1262             path.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1263                 centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness,
1264                 ANGLE_90, -ANGLE_180);
1265         } else {
1266             path.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1267                 centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness,
1268                 -ANGLE_90, angleArc);
1269             path.ArcTo(halfThickness, halfThickness, 0.0f, RSPathDirection::CW_DIRECTION,
1270                 centerPt.GetX() + sinPointInside, centerPt.GetY() - cosPointInside);
1271             path.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1272                 centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness,
1273                 -ANGLE_90 + angleArc, -angleArc);
1274         }
1275     } else {
1276         path.MoveTo(centerPt.GetX() + radius - halfThickness, centerPt.GetY());
1277         path.LineTo(centerPt.GetX() + radius + halfThickness, centerPt.GetY());
1278         path.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1279             centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness,
1280             0, angleArc - ANGLE_90);
1281         path.ArcTo(halfThickness, halfThickness, 0.0f, RSPathDirection::CW_DIRECTION,
1282             centerPt.GetX() + sinPointInside, centerPt.GetY() - cosPointInside);
1283         path.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1284             centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness,
1285             angleArc - ANGLE_90, -angleArc + ANGLE_90);
1286     }
1287 
1288     canvas.Save();
1289     canvas.ClipPath(path, RSClipOp::INTERSECT, true);
1290 
1291     float rotateAngle = -ANGLE_90 + startSweepAngle;
1292     canvas.Rotate(rotateAngle, centerPt.GetX(), centerPt.GetY());
1293     canvas.AttachPen(pen);
1294     canvas.DrawArc(
1295         { centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius },
1296         0, ANGLE_45);
1297     canvas.DetachPen();
1298     canvas.Restore();
1299 }
1300 
GenerateRingSweepingGradientInfo(std::vector<RSColorQuad> & colors,std::vector<float> & pos) const1301 void ProgressModifier::GenerateRingSweepingGradientInfo(
1302     std::vector<RSColorQuad>& colors, std::vector<float>& pos) const
1303 {
1304     Gradient gradient;
1305     Color sweepingColorBase = Color::WHITE;
1306     Color sweepingColorEnd = sweepingColorBase.ChangeOpacity(0.0f);
1307     GradientColor gradientColorEnd;
1308     gradientColorEnd.SetColor(sweepingColorEnd);
1309     gradientColorEnd.SetDimension(Dimension(0.0, DimensionUnit::PERCENT));
1310     gradient.AddColor(gradientColorEnd);
1311 
1312     // The sweep layer is a 45-degree white gradient with an opacity of 0.4 at 35 degrees and 0 at both ends.
1313     Color sweepingColorMiddle = sweepingColorBase.ChangeOpacity(0.4f);
1314     GradientColor gradientColorMiddle;
1315     gradientColorMiddle.SetColor(sweepingColorMiddle);
1316     gradientColorMiddle.SetDimension(Dimension(35.0f / ANGLE_45, DimensionUnit::PERCENT));
1317     gradient.AddColor(gradientColorMiddle);
1318 
1319     Color sweepingColorStart = sweepingColorBase.ChangeOpacity(0.0f);
1320     GradientColor gradientColorStart;
1321     gradientColorStart.SetColor(sweepingColorStart);
1322     gradientColorStart.SetDimension(Dimension(1.0, DimensionUnit::PERCENT));
1323     gradient.AddColor(gradientColorStart);
1324 
1325     auto gradientColors = gradient.GetColors();
1326     for (size_t i = 0; i < gradientColors.size(); i++) {
1327         colors.emplace_back(gradientColors[i].GetColor().GetValue());
1328         pos.emplace_back(gradientColors[i].GetDimension().Value());
1329     }
1330 }
1331 
PaintTrailing(RSCanvas & canvas,const RingProgressData & ringProgressData) const1332 void ProgressModifier::PaintTrailing(RSCanvas& canvas, const RingProgressData& ringProgressData) const
1333 {
1334     PointF centerPt = ringProgressData.centerPt;
1335     double radius = ringProgressData.radius;
1336     double thickness = ringProgressData.thickness;
1337     float head = trailingHeadDate_->Get();
1338     float tail = trailingTailDate_->Get();
1339     float additionalAngle = CalcRingProgressAdditionalAngle();
1340     float rotateAngle = 0.0f;
1341     if (GreatOrEqual(head, ANGLE_360 - additionalAngle * FLOAT_TWO_ZERO)) {
1342         rotateAngle = -ANGLE_360 + head - tail + additionalAngle * FLOAT_TWO_ZERO;
1343     }
1344     head += (additionalAngle + rotateAngle);
1345     tail += (additionalAngle + rotateAngle);
1346 
1347     RSPen pen;
1348     pen.SetAntiAlias(true);
1349     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
1350     pen.SetWidth(thickness);
1351     canvas.Save();
1352 
1353     std::vector<GradientColor> gradientColors = GetRingProgressGradientColors();
1354     std::vector<RSColorQuad> colors;
1355     std::vector<float> pos;
1356 
1357     for (size_t i = 0; i < gradientColors.size(); i++) {
1358         double dimension = gradientColors[i].GetDimension().Value();
1359         Color color = gradientColors[i].GetLinearColor().BlendOpacity(dimension);
1360         colors.emplace_back(color.GetValue());
1361         pos.emplace_back(gradientColors[i].GetDimension().Value());
1362     }
1363 
1364     RSPath path;
1365 #ifndef USE_ROSEN_DRAWING
1366     pen.SetShaderEffect(RSShaderEffect::CreateSweepGradient(ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors,
1367         pos, RSTileMode::CLAMP, tail - additionalAngle, head + additionalAngle, nullptr));
1368 #else
1369     pen.SetShaderEffect(
1370         RSRecordingShaderEffect::CreateSweepGradient(ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos,
1371             RSTileMode::CLAMP, tail - additionalAngle, head + additionalAngle, nullptr));
1372 #endif
1373     RSRect rRect(
1374         centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius);
1375     path.AddArc(rRect, tail, head - tail);
1376     canvas.Rotate(-ANGLE_90 - rotateAngle - additionalAngle, centerPt.GetX(), centerPt.GetY());
1377     canvas.AttachPen(pen);
1378     canvas.DrawPath(path);
1379     canvas.DetachPen();
1380     canvas.Restore();
1381 }
1382 
PaintScaleRing(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize) const1383 void ProgressModifier::PaintScaleRing(RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize) const
1384 {
1385     PointF centerPt = PointF(contentSize.Width() / INT32_TWO, contentSize.Height() / INT32_TWO) + offset;
1386     double radius = std::min(contentSize.Width() / INT32_TWO, contentSize.Height() / INT32_TWO);
1387     double lengthOfScale = strokeWidth_->Get();
1388     double pathDistance = FLOAT_TWO_ZERO * M_PI * radius / scaleCount_->Get();
1389     if (scaleWidth_->Get() > pathDistance) {
1390         PaintRing(canvas, offset, contentSize);
1391         return;
1392     }
1393     double widthOfLine = scaleWidth_->Get();
1394     RSPen pen;
1395 #ifndef USE_ROSEN_DRAWING
1396     RSPath path;
1397 #else
1398     RSRecordingPath path;
1399 #endif
1400     pen.SetWidth(widthOfLine);
1401     path.AddRoundRect(
1402         { 0, 0, widthOfLine, lengthOfScale }, widthOfLine / INT32_TWO, widthOfLine / INT32_TWO,
1403         RSPathDirection::CW_DIRECTION);
1404     pen.SetAntiAlias(true);
1405     pen.SetCapStyle(ToRSCapStyle(LineCap::ROUND));
1406 #ifndef USE_ROSEN_DRAWING
1407     pen.SetPathEffect(RSPathEffect::CreatePathDashEffect(path, pathDistance, 0.0f, RSPathDashStyle::ROTATE));
1408 #else
1409     pen.SetPathEffect(RSRecordingPathEffect::CreatePathDashEffect(path, pathDistance, 0.0f, RSPathDashStyle::ROTATE));
1410 #endif
1411     pen.SetColor(ToRSColor(bgColor_->Get()));
1412     canvas.AttachPen(pen);
1413     if (isRightToLeft_->Get()) {
1414         canvas.Scale(-1, 1);
1415         canvas.Translate(-(radius + ringProgressLeftPadding_.ConvertToPx()) * INT32_TWO, 0);
1416     }
1417     canvas.DrawArc(
1418         { centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius },
1419         ANGLE_270, ANGLE_360);
1420     canvas.DetachPen();
1421     // start to draw cur value progress
1422     pen.SetColor(ToRSColor((color_->Get())));
1423     canvas.AttachPen(pen);
1424     double angle = std::min((value_->Get() / maxValue_->Get()) * ANGLE_360, static_cast<float>(ANGLE_360));
1425     canvas.DrawArc(
1426         { centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius },
1427         ANGLE_270, angle);
1428     canvas.DetachPen();
1429     canvas.Restore();
1430 }
1431 
PaintMoon(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize) const1432 void ProgressModifier::PaintMoon(RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize) const
1433 {
1434     static int32_t totalDegree = 1;
1435     PointF centerPt = PointF(contentSize.Width() / INT32_TWO, contentSize.Height() / INT32_TWO) + offset;
1436     double radius = std::min(contentSize.Width() / INT32_TWO, contentSize.Height() / INT32_TWO);
1437     RSBrush brush;
1438     brush.SetAntiAlias(true);
1439     brush.SetAlpha(true);
1440     brush.SetColor(ToRSColor(bgColor_->Get()));
1441     double angle = std::min((value_->Get() / maxValue_->Get()) * totalDegree, static_cast<float>(totalDegree));
1442 #ifndef USE_ROSEN_DRAWING
1443     RSPath path;
1444 #else
1445     RSRecordingPath path;
1446 #endif
1447     canvas.AttachBrush(brush);
1448     canvas.DrawCircle(ToRSPoint(centerPt), radius);
1449     canvas.DetachBrush();
1450     brush.SetColor(ToRSColor((color_->Get())));
1451     canvas.AttachBrush(brush);
1452     path.AddArc(
1453         { centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius },
1454         ANGLE_90, !isRightToLeft_->Get() ? ANGLE_180 : -ANGLE_180);
1455     if (angle <= FLOAT_ZERO_FIVE) {
1456         double progressOffset = radius - radius * angle / FLOAT_ZERO_FIVE;
1457         path.MoveTo(centerPt.GetX(), centerPt.GetY() - radius);
1458         // startAngle:270  sweepAngle:-180
1459         path.AddArc({ centerPt.GetX() - progressOffset, centerPt.GetY() - radius, centerPt.GetX() + progressOffset,
1460                         centerPt.GetY() + radius },
1461             ANGLE_270, !isRightToLeft_->Get() ? -ANGLE_180 : ANGLE_180);
1462         canvas.DrawPath(path);
1463     } else {
1464         double progressOffset = radius * (angle - FLOAT_ZERO_FIVE) / FLOAT_ZERO_FIVE;
1465         path.MoveTo(centerPt.GetX(), centerPt.GetY() - radius);
1466         // startAngle:270  sweepAngle:180
1467         path.AddArc({ centerPt.GetX() - progressOffset, centerPt.GetY() - radius, centerPt.GetX() + progressOffset,
1468                         centerPt.GetY() + radius },
1469             ANGLE_270, !isRightToLeft_->Get() ? ANGLE_180 : -ANGLE_180);
1470         canvas.DrawPath(path);
1471     }
1472     canvas.DetachBrush();
1473 }
1474 
PaintCapsule(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize,const float borderRadius) const1475 void ProgressModifier::PaintCapsule(
1476     RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize, const float borderRadius) const
1477 {
1478     auto borderWidth = capsuleBorderWidth_->Get();
1479     if (GreatNotEqual(2 * borderWidth, contentSize.Height())) {
1480         borderWidth = contentSize.Height() / 2;
1481     }
1482     float radiusBig = borderRadius - (borderWidth / INT32_TWO);
1483     float offsetXBig = offset.GetX() + borderWidth / INT32_TWO;
1484     float offsetYBig = offset.GetY() + borderWidth / INT32_TWO;
1485     float offsetX = offset.GetX();
1486     float offsetY = offset.GetY();
1487     RSBrush brush;
1488     brush.SetAntiAlias(true);
1489     RSPen pen;
1490     brush.SetAlpha(true);
1491     brush.SetColor(ToRSColor(bgColor_->Get()));
1492     pen.SetWidth(borderWidth);
1493     pen.SetAntiAlias(true);
1494     pen.SetColor(ToRSColor(borderColor_->Get()));
1495 #ifndef USE_ROSEN_DRAWING
1496     RSPath path;
1497 #else
1498     RSRecordingPath path;
1499 #endif
1500     canvas.AttachBrush(brush);
1501     canvas.DrawRoundRect({ { offsetX, offsetY, contentSize.Width() + offsetX, contentSize.Height() + offsetY },
1502         borderRadius, borderRadius });
1503     canvas.DetachBrush();
1504     canvas.AttachPen(pen);
1505     if (!NearZero(borderWidth)) {
1506         canvas.DrawRoundRect({ { offsetXBig, offsetYBig, contentSize.Width() - borderWidth + offsetXBig,
1507                                    contentSize.Height() - borderWidth + offsetYBig },
1508             radiusBig, radiusBig });
1509     }
1510     canvas.DetachPen();
1511     brush.SetColor(ToRSColor((color_->Get())));
1512     canvas.AttachBrush(brush);
1513     PaintCapsuleLeftBorder(path, offset, contentSize, borderRadius);
1514     PaintCapsuleRightBorder(path, offset, contentSize, borderRadius);
1515     canvas.DrawPath(path);
1516     canvas.DetachBrush();
1517     canvas.Restore();
1518 
1519     PaintCapsuleLightSweep(canvas, contentSize, offset, path, false);
1520 }
1521 
PaintCapsuleLeftBorder(RSPath & path,const OffsetF & offset,const SizeF & contentSize,const float borderRadius) const1522 void ProgressModifier::PaintCapsuleLeftBorder(
1523     RSPath& path, const OffsetF& offset, const SizeF& contentSize, const float borderRadius) const
1524 {
1525     float offsetX = offset.GetX();
1526     float offsetY = offset.GetY();
1527     bool isDefault = GreatOrEqual(borderRadius, contentSize.Height() / INT32_TWO);
1528     if (isDefault) {
1529         if (!isRightToLeft_->Get()) {
1530             path.AddArc({ offsetX, offsetY, INT32_TWO * borderRadius + offsetX, contentSize.Height() + offsetY },
1531                 ANGLE_90, ANGLE_180);
1532         } else {
1533             path.AddArc({ offsetX + contentSize.Width() - INT32_TWO * borderRadius, offsetY,
1534                             offsetX + contentSize.Width(), contentSize.Height() + offsetY },
1535                 ANGLE_270, ANGLE_180);
1536         }
1537     } else {
1538         RSRoundRect roundRect;
1539         if (!isRightToLeft_->Get()) {
1540             roundRect.SetRect({ offsetX, offsetY, borderRadius + offsetX, contentSize.Height() + offsetY });
1541             roundRect.SetCornerRadius(RSRoundRect::TOP_LEFT_POS, borderRadius, borderRadius);
1542             roundRect.SetCornerRadius(RSRoundRect::BOTTOM_LEFT_POS, borderRadius, borderRadius);
1543         } else {
1544             roundRect.SetRect({ offsetX + contentSize.Width() - borderRadius, offsetY, offsetX + contentSize.Width(),
1545                 contentSize.Height() + offsetY });
1546             roundRect.SetCornerRadius(RSRoundRect::TOP_RIGHT_POS, borderRadius, borderRadius);
1547             roundRect.SetCornerRadius(RSRoundRect::BOTTOM_RIGHT_POS, borderRadius, borderRadius);
1548         }
1549         path.AddRoundRect(roundRect);
1550     }
1551 }
1552 
PaintCapsuleRightBorder(RSPath & path,const OffsetF & offset,const SizeF & contentSize,const float borderRadius) const1553 void ProgressModifier::PaintCapsuleRightBorder(
1554     RSPath& path, const OffsetF& offset, const SizeF& contentSize, const float borderRadius) const
1555 {
1556     static int32_t totalDegree = 1;
1557     float offsetX = offset.GetX();
1558     float offsetY = offset.GetY();
1559     float progressWidth =
1560         std::min((value_->Get() / maxValue_->Get()) * totalDegree * contentSize.Width(), contentSize.Width());
1561     if (LessNotEqual(progressWidth, borderRadius)) {
1562         PaintCapsuleProgressLessRadiusScene(path, offset, contentSize, borderRadius);
1563     } else if (GreatNotEqual(progressWidth, contentSize.Width() - borderRadius)) {
1564         path.AddRect({ offsetX + borderRadius, offsetY, contentSize.Width() + offsetX - borderRadius,
1565             contentSize.Height() + offsetY });
1566         PaintCapsuleProgressGreaterRadiusScene(path, offset, contentSize, borderRadius);
1567     } else {
1568         if (!isRightToLeft_->Get()) {
1569             path.AddRect({ borderRadius + offsetX, offsetY, progressWidth + offsetX, contentSize.Height() + offsetY });
1570         } else {
1571             path.AddRect({ offsetX + contentSize.Width() - progressWidth, offsetY,
1572                 contentSize.Width() + offsetX - borderRadius, contentSize.Height() + offsetY });
1573         }
1574     }
1575 }
1576 
PaintCapsuleProgressLessRadiusScene(RSPath & path,const OffsetF & offset,const SizeF & contentSize,const float borderRadius) const1577 void ProgressModifier::PaintCapsuleProgressLessRadiusScene(
1578     RSPath& path, const OffsetF& offset, const SizeF& contentSize, const float borderRadius) const
1579 {
1580     static int32_t totalDegree = 1;
1581     float offsetX = offset.GetX();
1582     float offsetY = offset.GetY();
1583     float progressWidth =
1584         std::min((value_->Get() / maxValue_->Get()) * totalDegree * contentSize.Width(), contentSize.Width());
1585     progressWidth = std::max(progressWidth, DEFAULT_MIN_PROGRESS_WIDTH);
1586     bool isDefault = GreatOrEqual(borderRadius, contentSize.Height() / INT32_TWO);
1587     if (isDefault) {
1588         if (!isRightToLeft_->Get()) {
1589             // startAngle:270  sweepAngle:-180
1590             path.AddArc({ offsetX + progressWidth, offsetY, INT32_TWO * borderRadius - progressWidth + offsetX,
1591                             contentSize.Height() + offsetY },
1592                 ANGLE_270, -ANGLE_180);
1593         } else {
1594             path.AddArc({ offsetX + contentSize.Width() - INT32_TWO * borderRadius + progressWidth, offsetY,
1595                             offsetX + contentSize.Width() - progressWidth, contentSize.Height() + offsetY },
1596                 ANGLE_90, -ANGLE_180);
1597         }
1598     } else {
1599         float tmpRadius = borderRadius - progressWidth;
1600         RSRoundRect roundRect;
1601         if (!isRightToLeft_->Get()) {
1602             roundRect.SetRect(
1603                 { offsetX + progressWidth, offsetY, borderRadius + offsetX, contentSize.Height() + offsetY });
1604             roundRect.SetCornerRadius(RSRoundRect::TOP_LEFT_POS, tmpRadius, tmpRadius);
1605             roundRect.SetCornerRadius(RSRoundRect::BOTTOM_LEFT_POS, tmpRadius, tmpRadius);
1606         } else {
1607             roundRect.SetRect({ offsetX + contentSize.Width() - borderRadius, offsetY,
1608                 offsetX + contentSize.Width() - progressWidth, contentSize.Height() + offsetY });
1609             roundRect.SetCornerRadius(RSRoundRect::TOP_RIGHT_POS, tmpRadius, tmpRadius);
1610             roundRect.SetCornerRadius(RSRoundRect::BOTTOM_RIGHT_POS, tmpRadius, tmpRadius);
1611         }
1612         path.AddRoundRect(roundRect, RSPathDirection::CCW_DIRECTION);
1613     }
1614 }
1615 
PaintCapsuleProgressGreaterRadiusScene(RSPath & path,const OffsetF & offset,const SizeF & contentSize,const float borderRadius) const1616 void ProgressModifier::PaintCapsuleProgressGreaterRadiusScene(
1617     RSPath& path, const OffsetF& offset, const SizeF& contentSize, const float borderRadius) const
1618 {
1619     static int32_t totalDegree = 1;
1620     float offsetX = offset.GetX();
1621     float offsetY = offset.GetY();
1622     float progressWidth =
1623         std::min((value_->Get() / maxValue_->Get()) * totalDegree * contentSize.Width(), contentSize.Width());
1624     bool isDefault = GreatOrEqual(borderRadius, contentSize.Height() / INT32_TWO);
1625     if (isDefault) {
1626         if (!isRightToLeft_->Get()) {
1627             // startAngle:270  sweepAngle:180
1628             path.AddArc({ offsetX + (contentSize.Width() - borderRadius) * FLOAT_TWO_ZERO - progressWidth, offsetY,
1629                             offsetX + progressWidth, contentSize.Height() + offsetY },
1630                 ANGLE_270, ANGLE_180);
1631         } else {
1632             path.AddArc({ offsetX + contentSize.Width() - progressWidth, offsetY,
1633                             offsetX - contentSize.Width() + progressWidth + INT32_TWO * borderRadius,
1634                             contentSize.Height() + offsetY },
1635                 ANGLE_90, ANGLE_180);
1636         }
1637     } else {
1638         float tmpRadius = progressWidth - contentSize.Width() + borderRadius;
1639         RSRoundRect roundRect;
1640         if (!isRightToLeft_->Get()) {
1641             roundRect.SetRect({ contentSize.Width() + offsetX - borderRadius, offsetY, offsetX + progressWidth,
1642                 contentSize.Height() + offsetY });
1643             roundRect.SetCornerRadius(RSRoundRect::TOP_RIGHT_POS, tmpRadius, tmpRadius);
1644             roundRect.SetCornerRadius(RSRoundRect::BOTTOM_RIGHT_POS, tmpRadius, tmpRadius);
1645         } else {
1646             roundRect.SetRect({ contentSize.Width() - progressWidth + offsetX, offsetY, offsetX + borderRadius,
1647                 contentSize.Height() + offsetY });
1648             roundRect.SetCornerRadius(RSRoundRect::TOP_LEFT_POS, tmpRadius, tmpRadius);
1649             roundRect.SetCornerRadius(RSRoundRect::BOTTOM_LEFT_POS, tmpRadius, tmpRadius);
1650         }
1651         path.AddRoundRect(roundRect);
1652     }
1653 }
1654 
PaintVerticalCapsule(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize,const float borderRadius) const1655 void ProgressModifier::PaintVerticalCapsule(
1656     RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize, const float borderRadius) const
1657 {
1658     auto borderWidth = capsuleBorderWidth_->Get();
1659     if (GreatNotEqual(2 * borderWidth, contentSize.Width())) {
1660         borderWidth = contentSize.Width() / 2;
1661     }
1662     static int32_t totalDegree = 1;
1663     float radiusBig = borderRadius - (borderWidth / INT32_TWO);
1664     float offsetXBig = offset.GetX() + borderWidth / INT32_TWO;
1665     float offsetYBig = offset.GetY() + borderWidth / INT32_TWO;
1666     float offsetX = offset.GetX();
1667     float offsetY = offset.GetY();
1668     float progressWidth =
1669         std::min((value_->Get() / maxValue_->Get()) * totalDegree * contentSize.Height(), contentSize.Height());
1670     bool isDefault = GreatOrEqual(borderRadius, contentSize.Width() / INT32_TWO);
1671     RSBrush brush;
1672     brush.SetAntiAlias(true);
1673     RSPen pen;
1674     pen.SetWidth(borderWidth);
1675     pen.SetAntiAlias(true);
1676     pen.SetColor(ToRSColor(borderColor_->Get()));
1677     brush.SetAlpha(true);
1678     brush.SetColor(ToRSColor(bgColor_->Get()));
1679 #ifndef USE_ROSEN_DRAWING
1680     RSPath path;
1681 #else
1682     RSRecordingPath path;
1683 #endif
1684     canvas.AttachBrush(brush);
1685     canvas.DrawRoundRect({ { offsetX, offsetY, contentSize.Width() + offsetX, contentSize.Height() + offsetY },
1686         borderRadius, borderRadius });
1687     canvas.DetachBrush();
1688     canvas.AttachPen(pen);
1689     if (!NearZero(borderWidth)) {
1690         canvas.DrawRoundRect({ { offsetXBig, offsetYBig, contentSize.Width() - borderWidth + offsetXBig,
1691                                    contentSize.Height() - borderWidth + offsetYBig },
1692             radiusBig, radiusBig });
1693     }
1694     canvas.DetachPen();
1695     brush.SetColor(ToRSColor((color_->Get())));
1696     canvas.AttachBrush(brush);
1697     if (isDefault) {
1698         path.AddArc({ offsetX, offsetY, contentSize.Width() + offsetX, contentSize.Width() + offsetY }, 0, -ANGLE_180);
1699     } else {
1700         RSRoundRect roundRect;
1701         roundRect.SetRect({ offsetX, offsetY, contentSize.Width() + offsetX, offsetY + borderRadius });
1702         roundRect.SetCornerRadius(RSRoundRect::TOP_LEFT_POS, borderRadius, borderRadius);
1703         roundRect.SetCornerRadius(RSRoundRect::TOP_RIGHT_POS, borderRadius, borderRadius);
1704         path.AddRoundRect(roundRect);
1705     }
1706     if (LessNotEqual(progressWidth, borderRadius)) {
1707         if (isDefault) {
1708             // startAngle:180  sweepAngle:180
1709             path.AddArc({ offsetX, offsetY + progressWidth, contentSize.Width() + offsetX,
1710                             contentSize.Width() - progressWidth + offsetY },
1711                 ANGLE_180, ANGLE_180);
1712         } else {
1713             float tmpRadius = borderRadius - progressWidth;
1714             RSRoundRect roundRect;
1715             roundRect.SetRect(
1716                 { offsetX, offsetY + progressWidth, contentSize.Width() + offsetX, offsetY + borderRadius });
1717             roundRect.SetCornerRadius(RSRoundRect::TOP_LEFT_POS, tmpRadius, tmpRadius);
1718             roundRect.SetCornerRadius(RSRoundRect::TOP_RIGHT_POS, tmpRadius, tmpRadius);
1719             path.AddRoundRect(roundRect, RSPathDirection::CCW_DIRECTION);
1720         }
1721     } else if (GreatNotEqual(progressWidth, contentSize.Height() - borderRadius)) {
1722         path.AddRect({ offsetX, offsetY + borderRadius, contentSize.Width() + offsetX,
1723             contentSize.Height() - borderRadius + offsetY });
1724         if (isDefault) {
1725             // startAngle:180  sweepAngle:-180
1726             path.AddArc({ offsetX, offsetY + (contentSize.Height() - borderRadius) * FLOAT_TWO_ZERO - progressWidth,
1727                             contentSize.Width() + offsetX, progressWidth + offsetY },
1728                 ANGLE_180, -ANGLE_180);
1729         } else {
1730             float tmpRadius = progressWidth - contentSize.Height() + borderRadius;
1731             RSRoundRect roundRect;
1732             roundRect.SetRect({ offsetX, contentSize.Height() - borderRadius + offsetY, contentSize.Width() + offsetX,
1733                 progressWidth + offsetY });
1734             roundRect.SetCornerRadius(RSRoundRect::BOTTOM_LEFT_POS, tmpRadius, tmpRadius);
1735             roundRect.SetCornerRadius(RSRoundRect::BOTTOM_RIGHT_POS, tmpRadius, tmpRadius);
1736             path.AddRoundRect(roundRect);
1737         }
1738     } else {
1739         path.AddRect({ offsetX, borderRadius + offsetY, offsetX + contentSize.Width(), progressWidth + offsetY });
1740     }
1741     canvas.DrawPath(path);
1742     canvas.DetachBrush();
1743     canvas.Restore();
1744 
1745     PaintCapsuleLightSweep(canvas, contentSize, offset, path, true);
1746 }
1747 
PaintCapsuleLightSweep(RSCanvas & canvas,const SizeF & contentSize,const OffsetF & offset,const RSPath & path,bool isVertical) const1748 void ProgressModifier::PaintCapsuleLightSweep(
1749     RSCanvas& canvas, const SizeF& contentSize, const OffsetF& offset, const RSPath& path, bool isVertical) const
1750 {
1751     RSPen pen;
1752     pen.SetAntiAlias(true);
1753     pen.SetWidth(1);
1754     auto gradient = CreateCapsuleGradient();
1755     std::vector<RSColorQuad> colors;
1756     std::vector<float> pos;
1757     RSBrush brush;
1758     auto gradientColors = gradient.GetColors();
1759     for (size_t i = 0; i < gradientColors.size(); i++) {
1760         colors.emplace_back(gradientColors[i].GetColor().GetValue());
1761         pos.emplace_back(gradientColors[i].GetDimension().Value());
1762     }
1763 
1764     float endPos = sweepingDate_->Get();
1765 #ifndef USE_ROSEN_DRAWING
1766     if (isVertical) {
1767         brush.SetShaderEffect(RSShaderEffect::CreateLinearGradient(
1768             ToRSPoint(
1769                 PointF(offset.GetX() + contentSize.Width() / 2, offset.GetY() + endPos - SWEEP_WIDTH.ConvertToPx())),
1770             ToRSPoint(PointF(offset.GetX() + contentSize.Width() / 2, offset.GetY() + endPos)), colors, pos,
1771             RSTileMode::CLAMP));
1772     } else {
1773         brush.SetShaderEffect(RSShaderEffect::CreateLinearGradient(
1774             ToRSPoint(PointF(!isRightToLeft_->Get() ? offset.GetX() + endPos - SWEEP_WIDTH.ConvertToPx()
1775                                                     : offset.GetX() + contentSize.Width() - endPos,
1776                 offset.GetY() + contentSize.Height() / 2)),
1777             ToRSPoint(PointF(!isRightToLeft_->Get()
1778                                  ? offset.GetX() + endPos
1779                                  : offset.GetX() + contentSize.Width() - endPos + SWEEP_WIDTH.ConvertToPx(),
1780                 offset.GetY() + contentSize.Height() / 2)),
1781             colors, pos, RSTileMode::CLAMP));
1782     }
1783 #else
1784     if (isVertical) {
1785         brush.SetShaderEffect(RSRecordingShaderEffect::CreateLinearGradient(
1786             ToRSPoint(PointF(offset.GetX() + contentSize.Width() / 2,
1787                 offset.GetY() + endPos - SWEEP_WIDTH.ConvertToPx() + capsuleBorderWidth_->Get())),
1788             ToRSPoint(
1789                 PointF(offset.GetX() + contentSize.Width() / 2, offset.GetY() + endPos - capsuleBorderWidth_->Get())),
1790             colors, pos, RSTileMode::CLAMP));
1791     } else {
1792         brush.SetShaderEffect(RSRecordingShaderEffect::CreateLinearGradient(
1793             ToRSPoint(PointF(!isRightToLeft_->Get()
1794                                  ? offset.GetX() + endPos - SWEEP_WIDTH.ConvertToPx() + capsuleBorderWidth_->Get()
1795                                  : offset.GetX() + contentSize.Width() - endPos + capsuleBorderWidth_->Get(),
1796                 offset.GetY() + contentSize.Height() / 2)),
1797             ToRSPoint(PointF(!isRightToLeft_->Get() ? offset.GetX() + endPos - capsuleBorderWidth_->Get()
1798                                                     : offset.GetX() + contentSize.Width() - endPos +
1799                                                           SWEEP_WIDTH.ConvertToPx() - capsuleBorderWidth_->Get(),
1800                 offset.GetY() + contentSize.Height() / 2)),
1801             colors, pos, RSTileMode::CLAMP));
1802     }
1803 #endif
1804 
1805     auto offsetX = offset.GetX();
1806     auto offsetY = offset.GetY();
1807     canvas.Save();
1808     canvas.ClipPath(path, RSClipOp::INTERSECT, true);
1809     canvas.AttachBrush(brush);
1810     if (isVertical) {
1811         canvas.DrawRect(
1812             { offsetX, offsetY + endPos - SWEEP_WIDTH.ConvertToPx(),
1813             offsetX + contentSize.Width(), offsetY + endPos });
1814     } else {
1815         if (!isRightToLeft_->Get()) {
1816             canvas.DrawRect({ offsetX + endPos - SWEEP_WIDTH.ConvertToPx(), offsetY, offsetX + endPos,
1817                 offsetY + contentSize.Height() });
1818         } else {
1819             canvas.DrawRect({ offsetX + contentSize.Width() - endPos, offsetY,
1820                 offsetX + contentSize.Width() - endPos + SWEEP_WIDTH.ConvertToPx(), offsetY + contentSize.Height() });
1821         }
1822     }
1823     canvas.DetachBrush();
1824     canvas.Restore();
1825 }
1826 
CreateCapsuleGradient() const1827 Gradient ProgressModifier::CreateCapsuleGradient() const
1828 {
1829     Gradient gradient;
1830     Color lightSweepColorBase = Color::WHITE;
1831     Color lightSweepColorEnd = lightSweepColorBase.ChangeOpacity(0.0);
1832     Color lightSweepColorMiddle = lightSweepColorBase.ChangeOpacity(0.2);
1833     GradientColor gradientColorEnd;
1834     isRightToLeft_->Get() ? gradientColorEnd.SetColor(lightSweepColorMiddle)
1835                           : gradientColorEnd.SetColor(lightSweepColorEnd);
1836     gradientColorEnd.SetDimension(Dimension(0.0, DimensionUnit::VP));
1837     gradient.AddColor(gradientColorEnd);
1838 
1839     GradientColor gradientColorMiddle;
1840     isRightToLeft_->Get() ? gradientColorMiddle.SetColor(lightSweepColorEnd)
1841                           : gradientColorMiddle.SetColor(lightSweepColorMiddle);
1842     gradientColorMiddle.SetDimension(SWEEP_WIDTH);
1843     gradient.AddColor(gradientColorMiddle);
1844     return gradient;
1845 }
1846 
PostTask(const TaskExecutor::Task & task,const std::string & name)1847 bool ProgressModifier::PostTask(const TaskExecutor::Task& task, const std::string& name)
1848 {
1849     auto pipeline = PipelineBase::GetCurrentContext();
1850     CHECK_NULL_RETURN(pipeline, false);
1851     auto taskExecutor = pipeline->GetTaskExecutor();
1852     CHECK_NULL_RETURN(taskExecutor, false);
1853     return taskExecutor->PostTask(task, TaskExecutor::TaskType::UI, name);
1854 }
1855 
SetStrokeRadius(float strokeRaidus)1856 void ProgressModifier::SetStrokeRadius(float strokeRaidus)
1857 {
1858     strokeRadius_->Set(strokeRaidus);
1859 }
1860 
SetIsRightToLeft(bool value)1861 void ProgressModifier::SetIsRightToLeft(bool value)
1862 {
1863     if (isRightToLeft_->Get() == value) {
1864         return;
1865     }
1866     isRightToLeft_->Set(value);
1867 }
1868 
SetIsHovered(bool value)1869 void ProgressModifier::SetIsHovered(bool value)
1870 {
1871     isHover_ = value;
1872 }
1873 
SetIsPressed(bool value)1874 void ProgressModifier::SetIsPressed(bool value)
1875 {
1876     isPress_ = value;
1877 }
1878 
SetIsFocused(bool value)1879 void ProgressModifier::SetIsFocused(bool value)
1880 {
1881     isFocus_ = value;
1882 }
1883 
IsFocused() const1884 bool ProgressModifier::IsFocused() const
1885 {
1886     return isFocus_;
1887 }
1888 
CalculateHoverPressColor(const Color & color)1889 Color ProgressModifier::CalculateHoverPressColor(const Color& color)
1890 {
1891     if (progressType_->Get() != static_cast<int32_t>(ProgressType::CAPSULE)) {
1892         return color;
1893     }
1894 
1895     Color outColor = color;
1896     if (isHover_) {
1897         outColor = color.BlendColor(hoverBlendColor_);
1898     }
1899     if (isPress_) {
1900         outColor = color.BlendColor(pressBlendColor_);
1901     }
1902     return outColor;
1903 }
1904 
PaintScaleRingForApiNine(RSCanvas & canvas,const OffsetF & offset,const SizeF & frameSize) const1905 void ProgressModifier::PaintScaleRingForApiNine(RSCanvas& canvas, const OffsetF& offset, const SizeF& frameSize) const
1906 {
1907     auto scaleWidth = scaleWidth_->Get();
1908     PointF centerPt = PointF(frameSize.Width() / 2, frameSize.Height() / 2) + offset;
1909     double radius = std::min(frameSize.Width() / 2, frameSize.Height() / 2);
1910     double lengthOfScale = strokeWidth_->Get();
1911     if (lengthOfScale > radius) {
1912         lengthOfScale = radius / 2;
1913     }
1914     double pathDistance = 2.0 * M_PI * radius / scaleCount_->Get();
1915     if (scaleWidth > pathDistance) {
1916         PaintRing(canvas, offset, frameSize);
1917         return;
1918     }
1919     double widthOfLine = scaleWidth;
1920     RSPen pen;
1921     RSPath path;
1922     pen.SetWidth(widthOfLine);
1923     path.AddRoundRect({
1924         0, 0, widthOfLine, lengthOfScale }, widthOfLine / 2, widthOfLine / 2, RSPathDirection::CW_DIRECTION);
1925     pen.SetAntiAlias(true);
1926     pen.SetCapStyle(ToRSCapStyle(LineCap::ROUND));
1927     pen.SetPathEffect(RSPathEffect::CreatePathDashEffect(path, pathDistance, 0.0f, RSPathDashStyle::ROTATE));
1928     pen.SetColor(ToRSColor(bgColor_->Get()));
1929     canvas.AttachPen(pen);
1930     canvas.DrawArc({
1931         centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius },
1932         ANGLE_270, ANGLE_360);
1933     canvas.DetachPen();
1934     pen.SetColor(ToRSColor((color_->Get())));
1935     canvas.AttachPen(pen);
1936     double angle = (value_->Get() / maxValue_->Get()) * ANGLE_360;
1937     canvas.DrawArc({
1938         centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius },
1939         ANGLE_270, angle);
1940     canvas.DetachPen();
1941 }
1942 
PaintCapsuleForApiNine(RSCanvas & canvas,const OffsetF & offset,const SizeF & frameSize) const1943 void ProgressModifier::PaintCapsuleForApiNine(RSCanvas& canvas, const OffsetF& offset, const SizeF& frameSize) const
1944 {
1945     double radius = std::min(frameSize.Width() / 2, frameSize.Height() / 2);
1946     double offsetX = offset.GetX();
1947     double offsetY = offset.GetY();
1948     double progressWidth = (value_->Get() / maxValue_->Get()) * frameSize.Width();
1949     RSBrush brush;
1950     brush.SetAlpha(true);
1951     brush.SetColor(ToRSColor(bgColor_->Get()));
1952     RSPath path;
1953     canvas.AttachBrush(brush);
1954     canvas.DrawRoundRect({ { offsetX, offsetY, frameSize.Width() + offsetX, frameSize.Height() + offsetY },
1955         radius, radius });
1956     canvas.DetachBrush();
1957     brush.SetColor(ToRSColor(color_->Get()));
1958     canvas.AttachBrush(brush);
1959     path.AddArc({ offsetX, offsetY, 2 * radius + offsetX, frameSize.Height() + offsetY }, ANGLE_90, ANGLE_180);
1960     if (LessNotEqual(progressWidth, radius)) {
1961         // startAngle:270  sweepAngle:-180
1962         path.AddArc({
1963             offsetX + progressWidth, offsetY, 2 * radius - progressWidth + offsetX, frameSize.Height() + offsetY },
1964             ANGLE_270, -ANGLE_180);
1965     } else if (GreatNotEqual(progressWidth, frameSize.Width() - radius)) {
1966         path.AddRect({ offsetX + radius, offsetY, frameSize.Width() + offsetX - radius,
1967             frameSize.Height() + offsetY });
1968         // startAngle:270  sweepAngle:180
1969         path.AddArc({ offsetX + (frameSize.Width() - radius) * 2.0 - progressWidth, offsetY, offsetX + progressWidth,
1970             frameSize.Height() + offsetY }, ANGLE_270, ANGLE_180);
1971     } else {
1972         path.AddRect({ radius + offsetX, offsetY, progressWidth + offsetX, frameSize.Height() + offsetY });
1973     }
1974     canvas.DrawPath(path);
1975     canvas.DetachBrush();
1976 }
1977 
PaintVerticalCapsuleForApiNine(RSCanvas & canvas,const OffsetF & offset,const SizeF & frameSize) const1978 void ProgressModifier::PaintVerticalCapsuleForApiNine(
1979     RSCanvas& canvas, const OffsetF& offset, const SizeF& frameSize) const
1980 {
1981     double radius = std::min(frameSize.Width() / 2, frameSize.Height() / 2);
1982     double offsetX = offset.GetX();
1983     double offsetY = offset.GetY();
1984     double progressWidth = (value_->Get() / maxValue_->Get()) * frameSize.Height();
1985     RSBrush brush;
1986     brush.SetAlpha(true);
1987     brush.SetColor(ToRSColor(bgColor_->Get()));
1988     RSPath path;
1989     canvas.AttachBrush(brush);
1990     canvas.DrawRoundRect({ {
1991         offsetX, offsetY, frameSize.Width() + offsetX, frameSize.Height() + offsetY }, radius, radius });
1992     canvas.DetachBrush();
1993     brush.SetColor(ToRSColor((color_->Get())));
1994     canvas.AttachBrush(brush);
1995     path.AddArc({ offsetX, offsetY, frameSize.Width() + offsetX, frameSize.Width() + offsetY }, 0, -ANGLE_180);
1996     if (LessNotEqual(progressWidth, radius)) {
1997         // startAngle:180  sweepAngle:180
1998         path.AddArc({ offsetX, offsetY + progressWidth, frameSize.Width() + offsetX,
1999                         frameSize.Width() - progressWidth + offsetY },
2000             ANGLE_180, ANGLE_180);
2001     } else if (GreatNotEqual(progressWidth, frameSize.Height() - radius)) {
2002         path.AddRect({
2003             offsetX, offsetY + radius, frameSize.Width() + offsetX, frameSize.Height() - radius + offsetY });
2004         // startAngle:180  sweepAngle:-180
2005         path.AddArc({ offsetX, offsetY + (frameSize.Height() - radius) * 2.0 - progressWidth,
2006             frameSize.Width() + offsetX, progressWidth + offsetY }, ANGLE_180, -ANGLE_180);
2007     } else {
2008         path.AddRect({ offsetX, radius + offsetY, offsetX + frameSize.Width(), progressWidth + offsetY });
2009     }
2010     canvas.DrawPath(path);
2011     canvas.DetachBrush();
2012 }
2013 
GetThemeScopeId() const2014 uint32_t ProgressModifier::GetThemeScopeId() const
2015 {
2016     auto host = host_.Upgrade();
2017     return host ? host->GetThemeScopeId() : 0;
2018 }
2019 } // namespace OHOS::Ace::NG
2020