1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/render/adapter/moon_progress_modifier.h"
17 
18 #include "core/components_ng/render/drawing_prop_convertor.h"
19 #include "core/pipeline_ng/pipeline_context.h"
20 
21 namespace OHOS::Ace::NG {
22 namespace {
23 constexpr int32_t DIFFUSE_DURATION = 300;
24 constexpr float INITIAL_RATIO = 1.0f;
25 constexpr int32_t INT32_TWO = 2;
26 constexpr int32_t ANGLE_90 = 90;
27 constexpr int32_t ANGLE_180 = 180;
28 constexpr int32_t ANGLE_270 = 270;
29 constexpr float FLOAT_ZERO_FIVE = 0.5f;
30 constexpr float FLOAT_ZERO_SEVEN = 0.7f;
31 constexpr float FLOAT_ONE_ZERO = 1.0f;
32 constexpr float SPRING_MOTION_RESPONSE = 0.314f;
33 constexpr float SPRING_MOTION_DAMPING_FRACTION = 0.95f;
34 const float EPSLION = 1e-5;
35 const float DEFAULT_MAXVALUE = 100.0f;
36 const bool DEFAULT_ENABLE_BREATHE = true;
37 constexpr float INITIAL_OPACITY = 0.0f;
38 constexpr int32_t PICTURE_DURATION = 750;
39 } // namespace
40 
MoonProgressModifier(const WeakPtr<FrameNode> & maskNode)41 MoonProgressModifier::MoonProgressModifier(const WeakPtr<FrameNode>& maskNode)
42     : maskColor_(AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::TRANSPARENT))),
43       ratio_(AceType::MakeRefPtr<AnimatablePropertyFloat>(INITIAL_RATIO)),
44       value_(AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f)),
45       opacity_(AceType::MakeRefPtr<AnimatablePropertyFloat>(INITIAL_OPACITY)),
46       maxValue_(AceType::MakeRefPtr<PropertyFloat>(DEFAULT_MAXVALUE)),
47       enableBreathe_(AceType::MakeRefPtr<PropertyBool>(DEFAULT_ENABLE_BREATHE))
48 {
49     maskNode_ = maskNode;
50     AttachProperty(maskColor_);
51     AttachProperty(ratio_);
52     AttachProperty(value_);
53     AttachProperty(opacity_);
54     AttachProperty(maxValue_);
55     AttachProperty(enableBreathe_);
56 }
57 
onDraw(DrawingContext & context)58 void MoonProgressModifier::onDraw(DrawingContext& context)
59 {
60     auto node = maskNode_.Upgrade();
61     CHECK_NULL_VOID(node);
62     auto geometryNode = node->GetGeometryNode();
63     CHECK_NULL_VOID(geometryNode);
64     auto contentSize = geometryNode->GetFrameSize();
65     frameSize_.SetWidth(contentSize.Width());
66     frameSize_.SetHeight(contentSize.Height());
67     SetBigRadius();
68     if (GreatOrEqual(ratio_->Get(), bigRadius_ / smallRadius_)) {
69         hideMask_ = true;
70         return;
71     }
72     PaintSquareMoon(context.canvas);
73 }
74 
SetMaskColor(LinearColor color)75 void MoonProgressModifier::SetMaskColor(LinearColor color)
76 {
77     maskColor_->Set(color);
78 }
79 
SetValue(float value)80 void MoonProgressModifier::SetValue(float value)
81 {
82     auto finishCallback = [weak = AceType::WeakClaim(this), bigRadius = bigRadius_, smallRadius = smallRadius_,
83                               id = Container::CurrentId()]() {
84         ContainerScope scope(id);
85         auto pipeline = PipelineContext::GetCurrentContext();
86         CHECK_NULL_VOID(pipeline);
87         auto modifier = weak.Upgrade();
88         CHECK_NULL_VOID(modifier);
89         double angle = (modifier->value_->Get() / modifier->maxValue_->Get()) * 1;
90         if (GreatNotEqual(std::abs(angle - FLOAT_ONE_ZERO), EPSLION)) {
91             modifier->StopPictureAnimate();
92             return;
93         }
94         if (modifier->enableBreathe_->Get() && Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE)) {
95             modifier->StartPictureAnimate();
96         } else {
97             modifier->StopPictureAnimate();
98             modifier->SetMoonAnimate(bigRadius / smallRadius);
99         }
100         pipeline->RequestFrame();
101     };
102 
103     AnimationOption option;
104     auto motion = AceType::MakeRefPtr<ResponsiveSpringMotion>(SPRING_MOTION_RESPONSE, SPRING_MOTION_DAMPING_FRACTION);
105     option.SetCurve(motion);
106     AnimationUtils::Animate(
107         option,
108         [weak = AceType::WeakClaim(AceType::RawPtr(value_)), valueTo = value]() {
109             auto value = weak.Upgrade();
110             CHECK_NULL_VOID(value);
111             value->Set(valueTo);
112         },
113         finishCallback);
114 
115     CHECK_NULL_VOID(maxValue_);
116     if (value < maxValue_->Get() && std::abs(maxValue_->Get() - value) > EPSLION &&
117         std::abs(ratio_->Get() - INITIAL_RATIO) > EPSLION) {
118         InitRatio();
119     }
120 }
121 
SetMaxValue(float value)122 void MoonProgressModifier::SetMaxValue(float value)
123 {
124     maxValue_->Set(value);
125 }
126 
GetMaxValue()127 float MoonProgressModifier::GetMaxValue()
128 {
129     if (maxValue_) {
130         return maxValue_->Get();
131     } else {
132         return DEFAULT_MAXVALUE;
133     }
134 }
135 
SetEnableBreathe(bool enableBreathe)136 void MoonProgressModifier::SetEnableBreathe(bool enableBreathe)
137 {
138     enableBreathe_->Set(enableBreathe);
139 }
140 
InitRatio()141 void MoonProgressModifier::InitRatio()
142 {
143     ratio_->Set(INITIAL_RATIO);
144     animationEnd_ = false;
145     hideMask_ = false;
146     RemoveVisibleChange();
147 }
148 
SetMoonAnimate(float value)149 void MoonProgressModifier::SetMoonAnimate(float value)
150 {
151     if (ratio_) {
152         animationEnd_ = true;
153         AnimationOption option;
154         option.SetDuration(DIFFUSE_DURATION);
155         option.SetDelay(0);
156         option.SetCurve(Curves::SHARP);
157         AnimationUtils::Animate(option, [weak = AceType::WeakClaim(AceType::RawPtr(ratio_)), value]() {
158             auto ratio = weak.Upgrade();
159             CHECK_NULL_VOID(ratio);
160             ratio->Set(value);
161         });
162     }
163 }
164 
StartPictureAnimate() const165 void MoonProgressModifier::StartPictureAnimate() const
166 {
167     if (GreatOrEqual(value_->Get(), maxValue_->Get()) && !animationEnd_) {
168         AnimationOption option;
169         option.SetDuration(PICTURE_DURATION);
170         option.SetDelay(0);
171         option.SetCurve(Curves::SHARP);
172         option.SetIteration(-1);
173         option.SetAnimationDirection(AnimationDirection::ALTERNATE);
174         AnimationUtils::Animate(option, [weak = AceType::WeakClaim(AceType::RawPtr(opacity_))]() {
175             auto opacity = weak.Upgrade();
176             CHECK_NULL_VOID(opacity);
177             opacity->Set(1.0f);
178         });
179     }
180 }
181 
StopPictureAnimate() const182 void MoonProgressModifier::StopPictureAnimate() const
183 {
184     AnimationOption option;
185     option.SetDuration(0);
186     AnimationUtils::Animate(option, [&]() { opacity_->Set(0.0f); });
187 }
188 
SetBigRadius()189 void MoonProgressModifier::SetBigRadius()
190 {
191     bigRadius_ = std::sqrt(
192         std::pow(frameSize_.Width() / INT32_TWO, INT32_TWO) + std::pow(frameSize_.Height() / INT32_TWO, INT32_TWO));
193     double radius = (std::min(frameSize_.Width() / INT32_TWO, frameSize_.Height() / INT32_TWO));
194     smallRadius_ = radius * INITIAL_RATIO * FLOAT_ZERO_SEVEN;
195 }
CalculateSquareMoonPath(RSPath & path,const PointF & centerPt,const double & angle)196 void MoonProgressModifier::CalculateSquareMoonPath(RSPath& path, const PointF& centerPt, const double& angle)
197 {
198     path.AddArc({ centerPt.GetX() - smallRadius_, centerPt.GetY() - smallRadius_, centerPt.GetX() + smallRadius_,
199                     centerPt.GetY() + smallRadius_ },
200         ANGLE_90, ANGLE_180);
201     if (LessOrEqual(angle, FLOAT_ZERO_FIVE)) {
202         double progressOffset = smallRadius_ - smallRadius_ * angle / FLOAT_ZERO_FIVE;
203         path.MoveTo(centerPt.GetX(), centerPt.GetY() - smallRadius_);
204         // startAngle:270  sweepAngle:-180
205         path.AddArc({ centerPt.GetX() - progressOffset, centerPt.GetY() - smallRadius_,
206                         centerPt.GetX() + progressOffset, centerPt.GetY() + smallRadius_ },
207             ANGLE_270, -ANGLE_180);
208     } else {
209         double progressOffset = smallRadius_ * (angle - FLOAT_ZERO_FIVE) / FLOAT_ZERO_FIVE;
210         path.MoveTo(centerPt.GetX(), centerPt.GetY() - smallRadius_);
211         // startAngle:270  sweepAngle:180
212         path.AddArc({ centerPt.GetX() - progressOffset, centerPt.GetY() - smallRadius_,
213                         centerPt.GetX() + progressOffset, centerPt.GetY() + smallRadius_ },
214             ANGLE_270, ANGLE_180);
215     }
216 }
PaintSquareMoon(RSCanvas & canvas)217 void MoonProgressModifier::PaintSquareMoon(RSCanvas& canvas)
218 {
219     PointF centerPt = PointF(frameSize_.Width() / INT32_TWO, frameSize_.Height() / INT32_TWO);
220     RSBrush brush;
221     double angle = value_->Get() / maxValue_->Get();
222 #ifndef USE_ROSEN_DRAWING
223     RSPath path;
224     RSPath clipPath;
225 #else
226     RSRecordingPath path;
227     RSRecordingPath clipPath;
228 #endif
229     brush.SetAntiAlias(true);
230     brush.SetColor(ToRSColor((maskColor_->Get())));
231     canvas.AttachBrush(brush);
232     path.SetFillStyle(RSPathFillType::EVENTODD);
233     path.AddCircle(centerPt.GetX(), centerPt.GetY(), bigRadius_, RSPathDirection::CW_DIRECTION);
234     if (NearZero(std::abs(ratio_->Get() - INITIAL_RATIO), EPSLION)) {
235         if (NearZero(angle, EPSLION)) {
236             canvas.DrawPath(path);
237             canvas.DetachBrush();
238             canvas.Restore();
239             return;
240         }
241         if (LessOrEqual(angle, FLOAT_ONE_ZERO)) {
242             CalculateSquareMoonPath(path, centerPt, angle);
243         } else {
244             clipPath.AddCircle(centerPt.GetX(), centerPt.GetY(), smallRadius_, RSPathDirection::CW_DIRECTION);
245             canvas.ClipPath(clipPath, RSClipOp::DIFFERENCE, true);
246         }
247         canvas.DrawPath(path);
248     } else {
249         path.MoveTo(centerPt.GetX(), centerPt.GetY() - smallRadius_ * ratio_->Get());
250         path.AddCircle(centerPt.GetX(), centerPt.GetY(), smallRadius_ * ratio_->Get(), RSPathDirection::CW_DIRECTION);
251         canvas.DrawPath(path);
252     }
253     canvas.DetachBrush();
254     canvas.Restore();
255     if (GreatOrEqual(angle, 1.0f)) {
256         PaintSquareMoonShadow(canvas, brush);
257     }
258 }
259 
PaintSquareMoonShadow(RSCanvas & canvas,RSBrush & brush)260 void MoonProgressModifier::PaintSquareMoonShadow(RSCanvas& canvas, RSBrush& brush)
261 {
262     RegisterVisibleChange();
263     Color color = Color::WHITE.ChangeOpacity(opacity_->Get());
264     brush.SetColor(ToRSColor(color));
265     auto radius = (std::min(frameSize_.Width() / INT32_TWO, frameSize_.Height() / INT32_TWO));
266     RSFilter filter;
267 #ifndef USE_ROSEN_DRAWING
268     RSPath path;
269     filter.SetImageFilter(
270         RSImageFilter::CreateBlurImageFilter(radius - smallRadius_, radius - smallRadius_, RSTileMode::DECAL, nullptr));
271 #else
272     RSRecordingPath path;
273     filter.SetImageFilter(RSRecordingImageFilter::CreateBlurImageFilter(
274         radius - smallRadius_, radius - smallRadius_, RSTileMode::DECAL, nullptr));
275 #endif
276     brush.SetFilter(filter);
277     canvas.AttachBrush(brush);
278     PointF centerPt = PointF(frameSize_.Width() / INT32_TWO, frameSize_.Height() / INT32_TWO);
279     path.AddCircle(centerPt.GetX(), centerPt.GetY(), smallRadius_, RSPathDirection::CW_DIRECTION);
280     canvas.ClipPath(path, RSClipOp::DIFFERENCE, true);
281     canvas.DrawPath(path);
282     canvas.DetachBrush();
283     canvas.Restore();
284 }
285 
RegisterVisibleChange()286 void MoonProgressModifier::RegisterVisibleChange()
287 {
288     if (hasVisibleChangeRegister_) {
289         return;
290     }
291     auto pipeline = PipelineContext::GetCurrentContext();
292     CHECK_NULL_VOID(pipeline);
293     auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
294         auto modifier = weak.Upgrade();
295         CHECK_NULL_VOID(modifier);
296         if (visible) {
297             modifier->StartPictureAnimate();
298         } else {
299             modifier->StopPictureAnimate();
300         }
301     };
302     std::vector<double> ratioList = { 0.0 };
303     auto node = maskNode_.Upgrade();
304     CHECK_NULL_VOID(node);
305     pipeline->AddVisibleAreaChangeNode(node, ratioList, callback, false);
306     pipeline->AddWindowStateChangedCallback(node->GetId());
307     hasVisibleChangeRegister_ = true;
308 }
309 
RemoveVisibleChange()310 void MoonProgressModifier::RemoveVisibleChange()
311 {
312     auto pipeline = PipelineContext::GetCurrentContext();
313     CHECK_NULL_VOID(pipeline);
314     auto node = maskNode_.Upgrade();
315     CHECK_NULL_VOID(node);
316     pipeline->RemoveVisibleAreaChangeNode(node->GetId());
317     pipeline->RemoveWindowStateChangedCallback(node->GetId());
318     hasVisibleChangeRegister_ = false;
319 }
320 } // namespace OHOS::Ace::NG
321