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