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