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();
90 double currentAngle = modifier->value_->GetStagingValue() / modifier->maxValue_->GetStagingValue();
91
92 // When first moon animation is interrupted by second,
93 // the second moon animation should use the staging value (the Latest updated value) for calculating.
94 if (GreatNotEqual(std::abs(angle - FLOAT_ONE_ZERO), EPSLION) ||
95 GreatNotEqual(std::abs(currentAngle - FLOAT_ONE_ZERO), EPSLION)) {
96 modifier->StopPictureAnimate();
97 return;
98 }
99 if (modifier->enableBreathe_->Get() && Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE)) {
100 modifier->StartPictureAnimate();
101 } else {
102 modifier->StopPictureAnimate();
103 modifier->SetMoonAnimate(bigRadius / smallRadius);
104 }
105 pipeline->RequestFrame();
106 };
107
108 AnimationOption option;
109 auto motion = AceType::MakeRefPtr<ResponsiveSpringMotion>(SPRING_MOTION_RESPONSE, SPRING_MOTION_DAMPING_FRACTION);
110 option.SetCurve(motion);
111 AnimationUtils::Animate(
112 option,
113 [weak = AceType::WeakClaim(AceType::RawPtr(value_)), valueTo = value]() {
114 auto value = weak.Upgrade();
115 CHECK_NULL_VOID(value);
116 value->Set(valueTo);
117 },
118 finishCallback);
119
120 CHECK_NULL_VOID(maxValue_);
121 if (value < maxValue_->Get() && std::abs(maxValue_->Get() - value) > EPSLION &&
122 std::abs(ratio_->Get() - INITIAL_RATIO) > EPSLION) {
123 InitRatio();
124 }
125 }
126
SetMaxValue(float value)127 void MoonProgressModifier::SetMaxValue(float value)
128 {
129 maxValue_->Set(value);
130 }
131
GetMaxValue()132 float MoonProgressModifier::GetMaxValue()
133 {
134 if (maxValue_) {
135 return maxValue_->Get();
136 } else {
137 return DEFAULT_MAXVALUE;
138 }
139 }
140
SetEnableBreathe(bool enableBreathe)141 void MoonProgressModifier::SetEnableBreathe(bool enableBreathe)
142 {
143 enableBreathe_->Set(enableBreathe);
144 }
145
InitRatio()146 void MoonProgressModifier::InitRatio()
147 {
148 ratio_->Set(INITIAL_RATIO);
149 animationEnd_ = false;
150 hideMask_ = false;
151 RemoveVisibleChange();
152 }
153
SetMoonAnimate(float value)154 void MoonProgressModifier::SetMoonAnimate(float value)
155 {
156 if (ratio_) {
157 animationEnd_ = true;
158 AnimationOption option;
159 option.SetDuration(DIFFUSE_DURATION);
160 option.SetDelay(0);
161 option.SetCurve(Curves::SHARP);
162 AnimationUtils::Animate(option, [weak = AceType::WeakClaim(AceType::RawPtr(ratio_)), value]() {
163 auto ratio = weak.Upgrade();
164 CHECK_NULL_VOID(ratio);
165 ratio->Set(value);
166 });
167 }
168 }
169
StartPictureAnimate() const170 void MoonProgressModifier::StartPictureAnimate() const
171 {
172 if (GreatOrEqual(value_->Get(), maxValue_->Get()) && !animationEnd_) {
173 AnimationOption option;
174 option.SetDuration(PICTURE_DURATION);
175 option.SetDelay(0);
176 option.SetCurve(Curves::SHARP);
177 option.SetIteration(-1);
178 option.SetAnimationDirection(AnimationDirection::ALTERNATE);
179 AnimationUtils::Animate(option, [weak = AceType::WeakClaim(AceType::RawPtr(opacity_))]() {
180 auto opacity = weak.Upgrade();
181 CHECK_NULL_VOID(opacity);
182 opacity->Set(1.0f);
183 });
184 }
185 }
186
StopPictureAnimate() const187 void MoonProgressModifier::StopPictureAnimate() const
188 {
189 AnimationOption option;
190 option.SetDuration(0);
191 AnimationUtils::Animate(option, [&]() { opacity_->Set(0.0f); });
192 }
193
SetBigRadius()194 void MoonProgressModifier::SetBigRadius()
195 {
196 bigRadius_ = std::sqrt(
197 std::pow(frameSize_.Width() / INT32_TWO, INT32_TWO) + std::pow(frameSize_.Height() / INT32_TWO, INT32_TWO));
198 double radius = (std::min(frameSize_.Width() / INT32_TWO, frameSize_.Height() / INT32_TWO));
199 smallRadius_ = radius * INITIAL_RATIO * FLOAT_ZERO_SEVEN;
200 }
CalculateSquareMoonPath(RSPath & path,const PointF & centerPt,const double & angle)201 void MoonProgressModifier::CalculateSquareMoonPath(RSPath& path, const PointF& centerPt, const double& angle)
202 {
203 path.AddArc({ centerPt.GetX() - smallRadius_, centerPt.GetY() - smallRadius_, centerPt.GetX() + smallRadius_,
204 centerPt.GetY() + smallRadius_ },
205 ANGLE_90, ANGLE_180);
206 if (LessOrEqual(angle, FLOAT_ZERO_FIVE)) {
207 double progressOffset = smallRadius_ - smallRadius_ * angle / FLOAT_ZERO_FIVE;
208 path.MoveTo(centerPt.GetX(), centerPt.GetY() - smallRadius_);
209 // startAngle:270 sweepAngle:-180
210 path.AddArc({ centerPt.GetX() - progressOffset, centerPt.GetY() - smallRadius_,
211 centerPt.GetX() + progressOffset, centerPt.GetY() + smallRadius_ },
212 ANGLE_270, -ANGLE_180);
213 } else {
214 double progressOffset = smallRadius_ * (angle - FLOAT_ZERO_FIVE) / FLOAT_ZERO_FIVE;
215 path.MoveTo(centerPt.GetX(), centerPt.GetY() - smallRadius_);
216 // startAngle:270 sweepAngle:180
217 path.AddArc({ centerPt.GetX() - progressOffset, centerPt.GetY() - smallRadius_,
218 centerPt.GetX() + progressOffset, centerPt.GetY() + smallRadius_ },
219 ANGLE_270, ANGLE_180);
220 }
221 }
PaintSquareMoon(RSCanvas & canvas)222 void MoonProgressModifier::PaintSquareMoon(RSCanvas& canvas)
223 {
224 PointF centerPt = PointF(frameSize_.Width() / INT32_TWO, frameSize_.Height() / INT32_TWO);
225 RSBrush brush;
226 double angle = value_->Get() / maxValue_->Get();
227 #ifndef USE_ROSEN_DRAWING
228 RSPath path;
229 RSPath clipPath;
230 #else
231 RSRecordingPath path;
232 RSRecordingPath clipPath;
233 #endif
234 brush.SetAntiAlias(true);
235 brush.SetColor(ToRSColor((maskColor_->Get())));
236 canvas.AttachBrush(brush);
237 path.SetFillStyle(RSPathFillType::EVENTODD);
238 path.AddCircle(centerPt.GetX(), centerPt.GetY(), bigRadius_, RSPathDirection::CW_DIRECTION);
239 if (NearZero(std::abs(ratio_->Get() - INITIAL_RATIO), EPSLION)) {
240 if (NearZero(angle, EPSLION)) {
241 canvas.DrawPath(path);
242 canvas.DetachBrush();
243 canvas.Restore();
244 return;
245 }
246 if (LessOrEqual(angle, FLOAT_ONE_ZERO)) {
247 CalculateSquareMoonPath(path, centerPt, angle);
248 } else {
249 clipPath.AddCircle(centerPt.GetX(), centerPt.GetY(), smallRadius_, RSPathDirection::CW_DIRECTION);
250 canvas.ClipPath(clipPath, RSClipOp::DIFFERENCE, true);
251 }
252 canvas.DrawPath(path);
253 } else {
254 path.MoveTo(centerPt.GetX(), centerPt.GetY() - smallRadius_ * ratio_->Get());
255 path.AddCircle(centerPt.GetX(), centerPt.GetY(), smallRadius_ * ratio_->Get(), RSPathDirection::CW_DIRECTION);
256 canvas.DrawPath(path);
257 }
258 canvas.DetachBrush();
259 canvas.Restore();
260 if (GreatOrEqual(angle, 1.0f)) {
261 PaintSquareMoonShadow(canvas, brush);
262 }
263 }
264
PaintSquareMoonShadow(RSCanvas & canvas,RSBrush & brush)265 void MoonProgressModifier::PaintSquareMoonShadow(RSCanvas& canvas, RSBrush& brush)
266 {
267 RegisterVisibleChange();
268 Color color = Color::WHITE.ChangeOpacity(opacity_->Get());
269 brush.SetColor(ToRSColor(color));
270 auto radius = (std::min(frameSize_.Width() / INT32_TWO, frameSize_.Height() / INT32_TWO));
271 RSFilter filter;
272 #ifndef USE_ROSEN_DRAWING
273 RSPath path;
274 filter.SetImageFilter(
275 RSImageFilter::CreateBlurImageFilter(radius - smallRadius_, radius - smallRadius_, RSTileMode::DECAL, nullptr));
276 #else
277 RSRecordingPath path;
278 filter.SetImageFilter(RSRecordingImageFilter::CreateBlurImageFilter(
279 radius - smallRadius_, radius - smallRadius_, RSTileMode::DECAL, nullptr));
280 #endif
281 brush.SetFilter(filter);
282 canvas.AttachBrush(brush);
283 PointF centerPt = PointF(frameSize_.Width() / INT32_TWO, frameSize_.Height() / INT32_TWO);
284 path.AddCircle(centerPt.GetX(), centerPt.GetY(), smallRadius_, RSPathDirection::CW_DIRECTION);
285 canvas.ClipPath(path, RSClipOp::DIFFERENCE, true);
286 canvas.DrawPath(path);
287 canvas.DetachBrush();
288 canvas.Restore();
289 }
290
RegisterVisibleChange()291 void MoonProgressModifier::RegisterVisibleChange()
292 {
293 if (hasVisibleChangeRegister_) {
294 return;
295 }
296 auto pipeline = PipelineContext::GetCurrentContext();
297 CHECK_NULL_VOID(pipeline);
298 auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
299 auto modifier = weak.Upgrade();
300 CHECK_NULL_VOID(modifier);
301 if (visible) {
302 modifier->StartPictureAnimate();
303 } else {
304 modifier->StopPictureAnimate();
305 }
306 };
307 std::vector<double> ratioList = { 0.0 };
308 auto node = maskNode_.Upgrade();
309 CHECK_NULL_VOID(node);
310 pipeline->AddVisibleAreaChangeNode(node, ratioList, callback, false);
311 pipeline->AddWindowStateChangedCallback(node->GetId());
312 hasVisibleChangeRegister_ = true;
313 }
314
RemoveVisibleChange()315 void MoonProgressModifier::RemoveVisibleChange()
316 {
317 auto pipeline = PipelineContext::GetCurrentContext();
318 CHECK_NULL_VOID(pipeline);
319 auto node = maskNode_.Upgrade();
320 CHECK_NULL_VOID(node);
321 pipeline->RemoveVisibleAreaChangeNode(node->GetId());
322 pipeline->RemoveWindowStateChangedCallback(node->GetId());
323 hasVisibleChangeRegister_ = false;
324 }
325 } // namespace OHOS::Ace::NG
326