• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "bridge/declarative_frontend/jsview/js_particle.h"
16 
17 #include <array>
18 #include <utility>
19 
20 #include "core/components_ng/pattern/particle/particle_model_ng.h"
21 #include "core/components_ng/property/particle_property.h"
22 #include "core/components_ng/property/particle_property_animation.h"
23 namespace OHOS::Ace {
24 std::unique_ptr<ParticleModel> ParticleModel::instance_ = nullptr;
25 std::mutex ParticleModel::mutex_;
GetInstance()26 ParticleModel* ParticleModel::GetInstance()
27 {
28     if (!instance_) {
29         std::lock_guard<std::mutex> lock(mutex_);
30         if (!instance_) {
31 #ifdef NG_BUILD
32             instance_.reset(new NG::ParticleModelNG());
33 #else
34             if (Container::IsCurrentUseNewPipeline()) {
35                 instance_.reset(new NG::ParticleModelNG());
36             }
37 #endif
38         }
39     }
40     return instance_.get();
41 }
42 } // namespace OHOS::Ace
43 namespace OHOS::Ace::Framework {
44 namespace {
45 constexpr int32_t ARRAY_SIZE = 2;
46 constexpr int32_t PARTICLE_DEFAULT_EMITTER_RATE = 5;
47 constexpr float MIN_BOUNDARY = -100.0f;
48 constexpr float MIN_LIMIT = -10000.0f;
49 constexpr float MAX_BOUNDARY = 100.0f;
50 constexpr float MAX_LIMIT = 10000.0f;
51 constexpr float DEFAULT_OPACITY = 1.0f;
52 constexpr float DEFAULT_SCALE = 1.0f;
53 constexpr float DEFAULT_SPIN = 0.0f;
54 constexpr float DEFAULT_SPEED = 0.0f;
55 constexpr float DEFAULT_ANGLE = 0.0f;
56 constexpr float MIN_OPACITY = 0.0f;
57 constexpr float MIN_SCALE = 0.0f;
58 constexpr float MIN_SPIN = MIN_LIMIT;
59 constexpr float MIN_SPEED = 0.0f;
60 constexpr float MIN_ANGLE = MIN_LIMIT;
61 constexpr float MAX_OPACITY = 1.0f;
62 constexpr float MAX_SCALE = MAX_LIMIT;
63 constexpr float MAX_SPIN = MAX_LIMIT;
64 constexpr float MAX_SPEED = MAX_LIMIT;
65 constexpr float MAX_ANGLE = MAX_LIMIT;
66 
67 constexpr int DEFAULT_COLOR = 0xffffffff;
68 
ParsSize(std::pair<Dimension,Dimension> & size,JSRef<JSVal> & sizeJsValue)69 void ParsSize(std::pair<Dimension, Dimension>& size, JSRef<JSVal>& sizeJsValue)
70 {
71     if (sizeJsValue->IsArray()) {
72         auto sizeJsArray = JSRef<JSArray>::Cast(sizeJsValue);
73         if (static_cast<int32_t>(sizeJsArray->Length()) == ARRAY_SIZE) {
74             CalcDimension xValue;
75             CalcDimension yValue;
76             if (JSParticle::ParseJsDimensionVp(sizeJsArray->GetValueAt(0), xValue) &&
77                 GreatOrEqual(xValue.Value(), 0.0)) {
78                 size.first = xValue;
79             }
80             if (JSParticle::ParseJsDimensionVp(sizeJsArray->GetValueAt(1), yValue) &&
81                 GreatOrEqual(yValue.Value(), 0.0)) {
82                 size.second = yValue;
83             }
84         }
85     }
86 }
87 
ParseParticleRange(JSRef<JSVal> & jsValue,float defaultValue)88 std::optional<std::pair<float, float>> ParseParticleRange(JSRef<JSVal>& jsValue, float defaultValue)
89 {
90     std::optional<std::pair<float, float>> rangeOpt;
91     auto defaultPair = std::pair<float, float>(defaultValue, defaultValue);
92     if (!jsValue->IsArray()) {
93         rangeOpt = defaultPair;
94         return rangeOpt;
95     }
96     auto jsArray = JSRef<JSArray>::Cast(jsValue);
97     if (jsArray->Length() != ARRAY_SIZE) {
98         rangeOpt = defaultPair;
99         return rangeOpt;
100     }
101     auto from = defaultValue;
102     if (jsArray->GetValueAt(0)->IsNumber()) {
103         from = jsArray->GetValueAt(0)->ToNumber<float>();
104     }
105     auto to = defaultValue;
106     if (jsArray->GetValueAt(1)->IsNumber()) {
107         to = jsArray->GetValueAt(1)->ToNumber<float>();
108     }
109     if (GreatNotEqual(from, to)) {
110         rangeOpt = defaultPair;
111         return rangeOpt;
112     }
113     rangeOpt = std::pair<float, float>(from, to);
114     return rangeOpt;
115 }
116 
ParseCurve(JSRef<JSVal> & curveJsValue)117 RefPtr<Curve> ParseCurve(JSRef<JSVal>& curveJsValue)
118 {
119     RefPtr<Curve> curve;
120     if (curveJsValue->IsString()) {
121         std::string src;
122         if (JSParticle::ParseJsString(curveJsValue, src)) {
123             curve = CreateCurve(src);
124         }
125     }
126     if (!curve) {
127         curve = AceType::MakeRefPtr<LinearCurve>();
128     }
129     return curve;
130 }
131 
ParseAnimationFloatArray(JSRef<JSArray> & curveConfigJsArray,std::list<NG::ParticlePropertyAnimation<float>> & particleAnimationFloatArray,float defaultValue,float minValue,float maxValue)132 void ParseAnimationFloatArray(JSRef<JSArray>& curveConfigJsArray,
133     std::list<NG::ParticlePropertyAnimation<float>>& particleAnimationFloatArray, float defaultValue, float minValue,
134     float maxValue)
135 {
136     auto arraySize = static_cast<int32_t>(curveConfigJsArray->Length());
137     for (int i = 0; i < arraySize; i++) {
138         auto arrayItemJsValue = curveConfigJsArray->GetValueAt(i);
139         NG::ParticlePropertyAnimation<float> floatPropertyAnimation;
140         if (!arrayItemJsValue->IsObject()) {
141             continue;
142         }
143         auto arrayItemJsObject = JSRef<JSObject>::Cast(arrayItemJsValue);
144         auto fromJsValue = arrayItemJsObject->GetProperty("from");
145         float from = defaultValue;
146         if (fromJsValue->IsNumber()) {
147             from = fromJsValue->ToNumber<float>();
148             if (GreatNotEqual(minValue, MIN_BOUNDARY) && LessNotEqual(from, minValue)) {
149                 from = defaultValue;
150             }
151             if (LessNotEqual(maxValue, MAX_BOUNDARY) && GreatNotEqual(from, maxValue)) {
152                 from = defaultValue;
153             }
154         }
155         floatPropertyAnimation.SetFrom(from);
156         auto toJsValue = arrayItemJsObject->GetProperty("to");
157         float to = defaultValue;
158         if (toJsValue->IsNumber()) {
159             to = toJsValue->ToNumber<float>();
160             if (GreatNotEqual(minValue, MIN_BOUNDARY) && LessNotEqual(to, minValue)) {
161                 to = defaultValue;
162             }
163             if (LessNotEqual(maxValue, MAX_BOUNDARY) && GreatNotEqual(to, maxValue)) {
164                 to = defaultValue;
165             }
166         }
167         floatPropertyAnimation.SetTo(to);
168         auto startMillisJsValue = arrayItemJsObject->GetProperty("startMillis");
169         auto startMillis = static_cast<int32_t>(0);
170         if (!JSParticle::ParseJsInt32(startMillisJsValue, startMillis) || startMillis < 0) {
171             startMillis = 0;
172         }
173         floatPropertyAnimation.SetStartMills(startMillis);
174         auto endMillisJsValue = arrayItemJsObject->GetProperty("endMillis");
175         auto endMillis = static_cast<int32_t>(0);
176         if (!JSParticle::ParseJsInt32(endMillisJsValue, endMillis) || endMillis < 0) {
177             endMillis = 0;
178         }
179         floatPropertyAnimation.SetEndMills(endMillis);
180         auto curveJsValue = arrayItemJsObject->GetProperty("curve");
181         auto curve = ParseCurve(curveJsValue);
182         if (curve) {
183             floatPropertyAnimation.SetCurve(curve);
184         }
185         particleAnimationFloatArray.emplace_back(floatPropertyAnimation);
186     }
187 }
188 
ParseFloatRandomConfig(JSRef<JSVal> & configJsValue,OHOS::Ace::NG::ParticleFloatPropertyUpdater & updater)189 bool ParseFloatRandomConfig(JSRef<JSVal>& configJsValue, OHOS::Ace::NG::ParticleFloatPropertyUpdater& updater)
190 {
191     if (!configJsValue->IsArray()) {
192         return false;
193     }
194     auto randomConfigJsArray = JSRef<JSArray>::Cast(configJsValue);
195     auto randomArraySize = static_cast<int32_t>(randomConfigJsArray->Length());
196     if (randomArraySize != ARRAY_SIZE) {
197         return false;
198     }
199     auto randomRangePair = ParseParticleRange(configJsValue, 0.0f);
200     if (!randomRangePair.has_value()) {
201         return false;
202     }
203     NG::ParticleFloatPropertyUpdaterConfig randomUpdaterConfig;
204     randomUpdaterConfig.SetRandomConfig(randomRangePair.value());
205     updater.SetConfig(randomUpdaterConfig);
206     return true;
207 }
208 
ParseFloatCurveConfig(JSRef<JSVal> & configJsValue,OHOS::Ace::NG::ParticleFloatPropertyUpdater & updater,float defaultValue,float minValue,float maxValue)209 bool ParseFloatCurveConfig(JSRef<JSVal>& configJsValue, OHOS::Ace::NG::ParticleFloatPropertyUpdater& updater,
210     float defaultValue, float minValue, float maxValue)
211 {
212     if (!configJsValue->IsArray()) {
213         return false;
214     }
215     auto curveConfigJsArray = JSRef<JSArray>::Cast(configJsValue);
216     std::list<NG::ParticlePropertyAnimation<float>> particleAnimationFloatArray;
217     ParseAnimationFloatArray(curveConfigJsArray, particleAnimationFloatArray, defaultValue, minValue, maxValue);
218     NG::ParticleFloatPropertyUpdaterConfig updateConfig;
219     updateConfig.SetAnimations(particleAnimationFloatArray);
220     updater.SetConfig(updateConfig);
221     return true;
222 }
223 
ParseFloatUpdater(JSRef<JSObject> & updaterJsObject,OHOS::Ace::NG::ParticleFloatPropertyUpdater & updater,float defaultValue,float minValue,float maxValue)224 bool ParseFloatUpdater(JSRef<JSObject>& updaterJsObject, OHOS::Ace::NG::ParticleFloatPropertyUpdater& updater,
225     float defaultValue, float minValue, float maxValue)
226 {
227     auto typeJsValue = updaterJsObject->GetProperty("type");
228     if (typeJsValue->IsNumber()) {
229         auto typeIntValue = typeJsValue->ToNumber<int32_t>();
230         if (typeIntValue < NG::UpdaterType::NONE_UPDATER || typeIntValue > NG::UpdaterType::CURVE) {
231             typeIntValue = NG::UpdaterType::NONE_UPDATER;
232         }
233         auto type = static_cast<NG::UpdaterType>(typeIntValue);
234         updater.SetUpdaterType(type);
235         auto configJsValue = updaterJsObject->GetProperty("config");
236         if (type == NG::UpdaterType::RANDOM) {
237             if (!ParseFloatRandomConfig(configJsValue, updater)) {
238                 auto randomRangePair = std::pair<float, float>(0.0f, 0.0f);
239                 NG::ParticleFloatPropertyUpdaterConfig randomUpdaterConfig;
240                 randomUpdaterConfig.SetRandomConfig(randomRangePair);
241                 updater.SetConfig(randomUpdaterConfig);
242             }
243             return true;
244         } else if (type == NG::UpdaterType::CURVE) {
245             if (!ParseFloatCurveConfig(configJsValue, updater, defaultValue, minValue, maxValue)) {
246                 std::list<NG::ParticlePropertyAnimation<float>> particleAnimationFloatArray;
247                 NG::ParticleFloatPropertyUpdaterConfig updateConfig;
248                 updateConfig.SetAnimations(particleAnimationFloatArray);
249                 updater.SetConfig(updateConfig);
250             }
251             return true;
252         }
253     }
254     return false;
255 }
256 
ParseFloatInitRange(JSRef<JSVal> & floatRangeJsValue,OHOS::Ace::NG::ParticleFloatPropertyOption & floatOption,float defaultValue,float minValue,float maxValue)257 void ParseFloatInitRange(JSRef<JSVal>& floatRangeJsValue, OHOS::Ace::NG::ParticleFloatPropertyOption& floatOption,
258     float defaultValue, float minValue, float maxValue)
259 {
260     auto defaultPair = std::pair<float, float>(defaultValue, defaultValue);
261     if (!floatRangeJsValue->IsArray()) {
262         floatOption.SetRange(defaultPair);
263         return;
264     }
265     auto floatRangeJsArray = JSRef<JSArray>::Cast(floatRangeJsValue);
266     if (floatRangeJsArray->Length() != ARRAY_SIZE) {
267         floatOption.SetRange(defaultPair);
268         return;
269     }
270     auto from = defaultValue;
271     auto fromJsValue = floatRangeJsArray->GetValueAt(0);
272     if (fromJsValue->IsNumber()) {
273         from = fromJsValue->ToNumber<float>();
274         if (GreatNotEqual(minValue, MIN_BOUNDARY) && LessNotEqual(from, minValue)) {
275             from = defaultValue;
276         }
277         if (LessNotEqual(maxValue, MAX_BOUNDARY) && GreatNotEqual(from, maxValue)) {
278             from = defaultValue;
279         }
280     }
281     auto to = defaultValue;
282     auto toJsValue = floatRangeJsArray->GetValueAt(1);
283     if (toJsValue->IsNumber()) {
284         to = toJsValue->ToNumber<float>();
285         if (GreatNotEqual(minValue, MIN_BOUNDARY) && LessNotEqual(to, minValue)) {
286             to = defaultValue;
287         }
288         if (LessNotEqual(maxValue, MAX_BOUNDARY) && GreatNotEqual(to, maxValue)) {
289             to = defaultValue;
290         }
291     }
292     if (GreatNotEqual(from, to)) {
293         from = defaultValue;
294         to = defaultValue;
295     }
296     auto range = std::pair<float, float>(from, to);
297     floatOption.SetRange(range);
298 }
299 
ParseFloatOption(JSRef<JSObject> & floatJsObject,OHOS::Ace::NG::ParticleFloatPropertyOption & floatOption,float defaultValue,float minValue,float maxValue)300 void ParseFloatOption(JSRef<JSObject>& floatJsObject, OHOS::Ace::NG::ParticleFloatPropertyOption& floatOption,
301     float defaultValue, float minValue, float maxValue)
302 {
303     auto floatRangeJsValue = floatJsObject->GetProperty("range");
304     ParseFloatInitRange(floatRangeJsValue, floatOption, defaultValue, minValue, maxValue);
305     auto updaterJsValue = floatJsObject->GetProperty("updater");
306     NG::ParticleFloatPropertyUpdater updater;
307     if (updaterJsValue->IsObject()) {
308         auto updaterJsObject = JSRef<JSObject>::Cast(updaterJsValue);
309         if (ParseFloatUpdater(updaterJsObject, updater, defaultValue, minValue, maxValue)) {
310             floatOption.SetUpdater(updater);
311             return;
312         }
313     }
314     updater.SetUpdaterType(NG::UpdaterType::NONE_UPDATER);
315     NG::ParticleFloatPropertyUpdaterConfig updateConfig;
316     updateConfig.SetNullStr("");
317     updater.SetConfig(updateConfig);
318     floatOption.SetUpdater(updater);
319 }
320 
ParseParticleObject(JSRef<JSObject> & particleJsObject,OHOS::Ace::NG::Particle & particle)321 bool ParseParticleObject(JSRef<JSObject>& particleJsObject, OHOS::Ace::NG::Particle& particle)
322 {
323     auto typeJsValue = particleJsObject->GetProperty("type");
324     auto typeValue = NG::ParticleType::POINT;
325     if (typeJsValue->IsNumber()) {
326         auto typeIntValue = typeJsValue->ToNumber<int32_t>();
327         if (typeIntValue >= static_cast<int32_t>(NG::ParticleType::POINT) &&
328             typeIntValue <= static_cast<int32_t>(NG::ParticleType::IMAGE)) {
329             typeValue = static_cast<NG::ParticleType>(typeIntValue);
330         }
331     }
332     particle.SetParticleType(typeValue);
333 
334     auto configJsValue = particleJsObject->GetProperty("config");
335     if (!configJsValue->IsObject()) {
336         return false;
337     }
338     auto configJsObject = JSRef<JSObject>::Cast(configJsValue);
339     if (typeValue == NG::ParticleType::IMAGE) {
340         auto srcJsValue = configJsObject->GetProperty("src");
341         auto sizeJsValue = configJsObject->GetProperty("size");
342         auto objectFitJsValue = configJsObject->GetProperty("objectFit");
343         NG::ImageParticleParameter imageParameter;
344         std::string src;
345         if (srcJsValue->IsString()) {
346             src = srcJsValue->ToString();
347         } else if (!JSParticle::ParseJsMedia(srcJsValue, src)) {
348             LOGD("particle can not parse image src.");
349             return false;
350         }
351         imageParameter.SetImageSource(src);
352         auto width = Dimension(0.0);
353         auto height = Dimension(0.0);
354         auto sizeValue = std::pair<Dimension, Dimension>(width, height);
355         ParsSize(sizeValue, sizeJsValue);
356         imageParameter.SetSize(sizeValue);
357         auto fit = ImageFit::COVER;
358         if (objectFitJsValue->IsNumber()) {
359             auto fitIntValue = objectFitJsValue->ToNumber<int32_t>();
360             if (fitIntValue >= static_cast<int32_t>(ImageFit::FILL) &&
361                 fitIntValue <= static_cast<int32_t>(ImageFit::SCALE_DOWN)) {
362                 fit = static_cast<ImageFit>(fitIntValue);
363             }
364         }
365         imageParameter.SetImageFit(fit);
366         NG::ParticleConfig particleConfig;
367         particleConfig.SetImageParticleParameter(imageParameter);
368         particle.SetConfig(particleConfig);
369     } else {
370         auto radiusJsValue = configJsObject->GetProperty("radius");
371         CalcDimension radius;
372         JSParticle::ParseJsDimensionVp(radiusJsValue, radius);
373         NG::PointParticleParameter pointParameter;
374         pointParameter.SetRadius(!radius.IsNonPositive() ? radius.ConvertToPx() : 0.0f);
375         NG::ParticleConfig particleConfig;
376         particleConfig.SetPointParticleParameter(pointParameter);
377         particle.SetConfig(particleConfig);
378     }
379 
380     auto count = 0;
381     auto countJsValue = particleJsObject->GetProperty("count");
382     if (countJsValue->IsNumber()) {
383         auto countIntValue = countJsValue->ToNumber<int32_t>();
384         if (countIntValue >= -1) {
385             count = countIntValue;
386         }
387     }
388     particle.SetCount(count);
389 
390     auto lifeTime = 1000;
391     auto lifeTimeJsValue = particleJsObject->GetProperty("lifetime");
392     if (lifeTimeJsValue->IsNumber()) {
393         auto lifeTimeIntValue = lifeTimeJsValue->ToNumber<int64_t>();
394         if (lifeTimeIntValue >= -1) {
395             lifeTime = lifeTimeIntValue;
396         }
397     }
398     particle.SetLifeTime(lifeTime);
399     return true;
400 }
401 
ParseEmitterOption(JSRef<JSObject> & emitterJsObject,OHOS::Ace::NG::EmitterOption & emitterOption)402 bool ParseEmitterOption(JSRef<JSObject>& emitterJsObject, OHOS::Ace::NG::EmitterOption& emitterOption)
403 {
404     auto particleJsValue = emitterJsObject->GetProperty("particle");
405     if (!particleJsValue->IsObject()) {
406         return false;
407     }
408     auto particleJsObject = JSRef<JSObject>::Cast(particleJsValue);
409     OHOS::Ace::NG::Particle particle;
410     if (!ParseParticleObject(particleJsObject, particle)) {
411         return false;
412     }
413     emitterOption.SetParticle(particle);
414     int32_t emitRate = PARTICLE_DEFAULT_EMITTER_RATE;
415     auto emitRateJsValue = emitterJsObject->GetProperty("emitRate");
416     if (emitRateJsValue->IsNumber()) {
417         emitRate = emitRateJsValue->ToNumber<int32_t>() >= 0 ? emitRateJsValue->ToNumber<int32_t>() : emitRate;
418     }
419     emitterOption.SetEmitterRate(emitRate);
420 
421     auto emitShape = OHOS::Ace::NG::ParticleEmitterShape::RECTANGLE;
422     auto emitShapeJsValue = emitterJsObject->GetProperty("shape");
423     if (emitShapeJsValue->IsNumber()) {
424         auto emitShapeInt = emitShapeJsValue->ToNumber<int32_t>();
425         if (emitShapeInt >= static_cast<int32_t>(OHOS::Ace::NG::ParticleEmitterShape::RECTANGLE) &&
426             emitShapeInt <= static_cast<int32_t>(OHOS::Ace::NG::ParticleEmitterShape::ELLIPSE)) {
427             emitShape = static_cast<OHOS::Ace::NG::ParticleEmitterShape>(emitShapeInt);
428         }
429     }
430     emitterOption.SetShape(emitShape);
431     auto positionJsValue = emitterJsObject->GetProperty("position");
432     CalcDimension xValue(0.0);
433     CalcDimension yValue(0.0);
434     if (positionJsValue->IsArray()) {
435         auto positionJsArray = JSRef<JSArray>::Cast(positionJsValue);
436         if (positionJsArray->Length() == ARRAY_SIZE) {
437             JSParticle::ParseJsDimensionVp(positionJsArray->GetValueAt(0), xValue);
438             JSParticle::ParseJsDimensionVp(positionJsArray->GetValueAt(1), yValue);
439         }
440     }
441     auto positionValue = std::pair<Dimension, Dimension>(xValue, yValue);
442     emitterOption.SetPosition(positionValue);
443 
444     auto width = Dimension(1.0, DimensionUnit::PERCENT);
445     auto height = Dimension(1.0, DimensionUnit::PERCENT);
446     auto sizeValue = std::pair<Dimension, Dimension>(width, height);
447     auto sizeJsValue = emitterJsObject->GetProperty("size");
448     ParsSize(sizeValue, sizeJsValue);
449     emitterOption.SetSize(sizeValue);
450     return true;
451 }
452 
ParseAnimationColorArray(JSRef<JSArray> & curveConfigJsArray,std::list<NG::ParticlePropertyAnimation<Color>> & particleAnimationColorArray)453 void ParseAnimationColorArray(
454     JSRef<JSArray>& curveConfigJsArray, std::list<NG::ParticlePropertyAnimation<Color>>& particleAnimationColorArray)
455 {
456     auto arraySize = static_cast<int32_t>(curveConfigJsArray->Length());
457     for (int i = 0; i < arraySize; i++) {
458         auto arrayItemJsValue = curveConfigJsArray->GetValueAt(i);
459         NG::ParticlePropertyAnimation<Color> colorPropertyAnimation;
460         if (!arrayItemJsValue->IsObject()) {
461             continue;
462         }
463         auto arrayItemJsObject = JSRef<JSObject>::Cast(arrayItemJsValue);
464         auto fromJsValue = arrayItemJsObject->GetProperty("from");
465         Color from(DEFAULT_COLOR);
466         JSParticle::ParseJsColor(fromJsValue, from);
467         colorPropertyAnimation.SetFrom(from);
468         auto toJsValue = arrayItemJsObject->GetProperty("to");
469         Color to(DEFAULT_COLOR);
470         JSParticle::ParseJsColor(toJsValue, to);
471         colorPropertyAnimation.SetTo(to);
472         auto startMillisJsValue = arrayItemJsObject->GetProperty("startMillis");
473         auto startMillis = static_cast<int32_t>(0);
474         if (!JSParticle::ParseJsInt32(startMillisJsValue, startMillis) || startMillis < 0) {
475             startMillis = 0;
476         }
477         colorPropertyAnimation.SetStartMills(startMillis);
478         auto endMillisJsValue = arrayItemJsObject->GetProperty("endMillis");
479         auto endMillis = static_cast<int32_t>(0);
480         if (!JSParticle::ParseJsInt32(endMillisJsValue, endMillis) || endMillis < 0) {
481             endMillis = 0;
482         }
483         colorPropertyAnimation.SetEndMills(endMillis);
484         auto curveJsValue = arrayItemJsObject->GetProperty("curve");
485         auto curve = ParseCurve(curveJsValue);
486         if (curve) {
487             colorPropertyAnimation.SetCurve(curve);
488         }
489         particleAnimationColorArray.emplace_back(colorPropertyAnimation);
490     }
491 }
492 
ParseColorRandomUpdater(JSRef<JSVal> configJsValue,OHOS::Ace::NG::ParticleColorPropertyUpdater & updater)493 void ParseColorRandomUpdater(JSRef<JSVal> configJsValue, OHOS::Ace::NG::ParticleColorPropertyUpdater& updater)
494 {
495     NG::ParticleColorPropertyUpdaterConfig randomUpdaterConfig;
496     NG::ColorParticleRandomUpdateConfig colorRandomConfig;
497     if (!configJsValue->IsObject()) {
498         auto defaultPair = std::pair<float, float>(0.0f, 0.0f);
499         colorRandomConfig.SetRedRandom(defaultPair);
500         colorRandomConfig.SetGreenRandom(defaultPair);
501         colorRandomConfig.SetBlueRandom(defaultPair);
502         colorRandomConfig.SetAlphaRandom(defaultPair);
503         randomUpdaterConfig.SetRandomConfig(colorRandomConfig);
504         updater.SetConfig(randomUpdaterConfig);
505         return;
506     }
507     auto randomConfigJsObject = JSRef<JSObject>::Cast(configJsValue);
508     auto rJsValue = randomConfigJsObject->GetProperty("r");
509     auto gJsValue = randomConfigJsObject->GetProperty("g");
510     auto bJsValue = randomConfigJsObject->GetProperty("b");
511     auto aJsValue = randomConfigJsObject->GetProperty("a");
512     std::pair<float, float> defaultPair(0.0f, 0.0f);
513     auto rRangeValue = ParseParticleRange(rJsValue, 0.0f);
514     auto gRangeValue = ParseParticleRange(gJsValue, 0.0f);
515     auto bRangeValue = ParseParticleRange(bJsValue, 0.0f);
516     auto aRangeValue = ParseParticleRange(aJsValue, 0.0f);
517     colorRandomConfig.SetRedRandom(rRangeValue.value_or(defaultPair));
518     colorRandomConfig.SetGreenRandom(gRangeValue.value_or(defaultPair));
519     colorRandomConfig.SetBlueRandom(bRangeValue.value_or(defaultPair));
520     colorRandomConfig.SetAlphaRandom(aRangeValue.value_or(defaultPair));
521     randomUpdaterConfig.SetRandomConfig(colorRandomConfig);
522     updater.SetConfig(randomUpdaterConfig);
523 }
524 
ParseColorCurveUpdater(JSRef<JSVal> configJsValue,OHOS::Ace::NG::ParticleColorPropertyUpdater & updater)525 void ParseColorCurveUpdater(JSRef<JSVal> configJsValue, OHOS::Ace::NG::ParticleColorPropertyUpdater& updater)
526 {
527     std::list<NG::ParticlePropertyAnimation<Color>> particleAnimationColorArray;
528     NG::ParticleColorPropertyUpdaterConfig randomUpdaterConfig;
529     if (!configJsValue->IsArray()) {
530         randomUpdaterConfig.SetAnimationArray(particleAnimationColorArray);
531         updater.SetConfig(randomUpdaterConfig);
532         return;
533     }
534     auto curveConfigJsArray = JSRef<JSArray>::Cast(configJsValue);
535     ParseAnimationColorArray(curveConfigJsArray, particleAnimationColorArray);
536     randomUpdaterConfig.SetAnimationArray(particleAnimationColorArray);
537     updater.SetConfig(randomUpdaterConfig);
538 }
539 
ParseColorUpdater(JSRef<JSObject> & updaterJsObject,OHOS::Ace::NG::ParticleColorPropertyUpdater & updater)540 bool ParseColorUpdater(JSRef<JSObject>& updaterJsObject, OHOS::Ace::NG::ParticleColorPropertyUpdater& updater)
541 {
542     auto typeJsValue = updaterJsObject->GetProperty("type");
543     if (typeJsValue->IsNumber()) {
544         auto typeIntValue = typeJsValue->ToNumber<int32_t>();
545         if (typeIntValue < NG::UpdaterType::NONE_UPDATER || typeIntValue > NG::UpdaterType::CURVE) {
546             typeIntValue = NG::UpdaterType::NONE_UPDATER;
547         }
548         auto type = static_cast<NG::UpdaterType>(typeIntValue);
549         updater.SetUpdateType(type);
550         auto configJsValue = updaterJsObject->GetProperty("config");
551         if (type == NG::UpdaterType::RANDOM) {
552             ParseColorRandomUpdater(configJsValue, updater);
553             return true;
554         } else if (type == NG::UpdaterType::CURVE) {
555             ParseColorCurveUpdater(configJsValue, updater);
556             return true;
557         }
558     }
559     return false;
560 }
561 
ParseColorInitRange(JSRef<JSVal> colorRangeJsValue,OHOS::Ace::NG::ParticleColorPropertyOption & colorOption)562 void ParseColorInitRange(JSRef<JSVal> colorRangeJsValue, OHOS::Ace::NG::ParticleColorPropertyOption& colorOption)
563 {
564     Color fromColor(DEFAULT_COLOR);
565     Color toColor(DEFAULT_COLOR);
566     auto defaultRange = std::pair<Color, Color>(fromColor, toColor);
567     if (!colorRangeJsValue->IsArray()) {
568         colorOption.SetRange(defaultRange);
569         return;
570     }
571     auto colorRangeJsArray = JSRef<JSArray>::Cast(colorRangeJsValue);
572     if (static_cast<int32_t>(colorRangeJsArray->Length()) != ARRAY_SIZE) {
573         colorOption.SetRange(defaultRange);
574         return;
575     }
576     JSParticle::ParseJsColor(colorRangeJsArray->GetValueAt(0), fromColor);
577     JSParticle::ParseJsColor(colorRangeJsArray->GetValueAt(1), toColor);
578     auto range = std::pair<Color, Color>(fromColor, toColor);
579     colorOption.SetRange(range);
580 }
581 
ParseColorOption(JSRef<JSObject> & colorJsObject,OHOS::Ace::NG::ParticleColorPropertyOption & colorOption)582 void ParseColorOption(JSRef<JSObject>& colorJsObject, OHOS::Ace::NG::ParticleColorPropertyOption& colorOption)
583 {
584     auto colorRangeJsValue = colorJsObject->GetProperty("range");
585     ParseColorInitRange(colorRangeJsValue, colorOption);
586     auto updaterJsValue = colorJsObject->GetProperty("updater");
587     NG::ParticleColorPropertyUpdater updater;
588     if (updaterJsValue->IsObject()) {
589         auto updaterJsObject = JSRef<JSObject>::Cast(updaterJsValue);
590         if (ParseColorUpdater(updaterJsObject, updater)) {
591             colorOption.SetUpdater(updater);
592             return;
593         }
594     }
595     updater.SetUpdateType(NG::UpdaterType::NONE_UPDATER);
596     NG::ParticleColorPropertyUpdaterConfig noneUpdaterConfig;
597     noneUpdaterConfig.SetInValid(0);
598     updater.SetConfig(noneUpdaterConfig);
599     colorOption.SetUpdater(updater);
600 }
601 
ParseParticleVelocity(JSRef<JSVal> jsValue,OHOS::Ace::NG::VelocityProperty & velocity)602 void ParseParticleVelocity(JSRef<JSVal> jsValue, OHOS::Ace::NG::VelocityProperty& velocity)
603 {
604     auto defaultPair = std::pair<float, float>(0.0f, 0.0f);
605     if (!jsValue->IsObject()) {
606         velocity.SetSpeedRange(defaultPair);
607         velocity.SetAngleRange(defaultPair);
608         return;
609     }
610     auto jsValueObj = JSRef<JSObject>::Cast(jsValue);
611     auto speedJsValue = jsValueObj->GetProperty("speed");
612     auto angleJsValue = jsValueObj->GetProperty("angle");
613     auto speedPair = ParseParticleRange(speedJsValue, 0.0f);
614     if (speedPair.has_value()) {
615         velocity.SetSpeedRange(speedPair.value());
616     } else {
617         velocity.SetSpeedRange(defaultPair);
618     }
619     auto anglePair = ParseParticleRange(angleJsValue, 0.0f);
620     if (anglePair.has_value()) {
621         velocity.SetAngleRange(anglePair.value());
622     } else {
623         velocity.SetAngleRange(defaultPair);
624     }
625 }
626 
ParseParticleAcceleration(JSRef<JSVal> jsValue,OHOS::Ace::NG::AccelerationProperty & acceleration)627 void ParseParticleAcceleration(JSRef<JSVal> jsValue, OHOS::Ace::NG::AccelerationProperty& acceleration)
628 {
629     if (!jsValue->IsObject()) {
630         return;
631     }
632     auto jsValueObj = JSRef<JSObject>::Cast(jsValue);
633     auto speedValue = jsValueObj->GetProperty("speed");
634     auto alphaValue = jsValueObj->GetProperty("angle");
635     OHOS::Ace::NG::ParticleFloatPropertyOption speedOption;
636     if (speedValue->IsObject()) {
637         auto speedObject = JSRef<JSObject>::Cast(speedValue);
638         ParseFloatOption(speedObject, speedOption, DEFAULT_SPEED, MIN_SPEED, MAX_SPEED);
639         acceleration.SetSpeed(speedOption);
640     }
641     OHOS::Ace::NG::ParticleFloatPropertyOption angleOption;
642     if (alphaValue->IsObject()) {
643         auto alphaObject = JSRef<JSObject>::Cast(alphaValue);
644         ParseFloatOption(alphaObject, angleOption, DEFAULT_ANGLE, MIN_ANGLE, MAX_ANGLE);
645         acceleration.SetAngle(angleOption);
646     }
647 }
648 
ParseParticleOption(JSRef<JSObject> & particleJsObj,OHOS::Ace::NG::ParticleOption & particleOption)649 bool ParseParticleOption(JSRef<JSObject>& particleJsObj, OHOS::Ace::NG::ParticleOption& particleOption)
650 {
651     auto emitterJsValue = particleJsObj->GetProperty("emitter");
652     if (!emitterJsValue->IsObject()) {
653         return false;
654     }
655 
656     auto emitterJsObj = JSRef<JSObject>::Cast(emitterJsValue);
657     OHOS::Ace::NG::EmitterOption emitterOption;
658     if (!ParseEmitterOption(emitterJsObj, emitterOption)) {
659         return false;
660     }
661 
662     particleOption.SetEmitterOption(emitterOption);
663     auto colorJsValue = particleJsObj->GetProperty("color");
664     if (colorJsValue->IsObject()) {
665         auto colorJsObj = JSRef<JSObject>::Cast(colorJsValue);
666         OHOS::Ace::NG::ParticleColorPropertyOption colorOption;
667         ParseColorOption(colorJsObj, colorOption);
668         particleOption.SetParticleColorOption(colorOption);
669     }
670 
671     auto opacityJsValue = particleJsObj->GetProperty("opacity");
672     if (opacityJsValue->IsObject()) {
673         auto opacityJsObj = JSRef<JSObject>::Cast(opacityJsValue);
674         OHOS::Ace::NG::ParticleFloatPropertyOption opacityOption;
675         ParseFloatOption(opacityJsObj, opacityOption, DEFAULT_OPACITY, MIN_OPACITY, MAX_OPACITY);
676         particleOption.SetParticleOpacityOption(opacityOption);
677     }
678 
679     auto scaleJsValue = particleJsObj->GetProperty("scale");
680     if (scaleJsValue->IsObject()) {
681         auto scaleJsObj = JSRef<JSObject>::Cast(scaleJsValue);
682         OHOS::Ace::NG::ParticleFloatPropertyOption scaleOption;
683         ParseFloatOption(scaleJsObj, scaleOption, DEFAULT_SCALE, MIN_SCALE, MAX_SCALE);
684         particleOption.SetParticleScaleOption(scaleOption);
685     }
686 
687     auto velocityJsValue = particleJsObj->GetProperty("velocity");
688     OHOS::Ace::NG::VelocityProperty velocity;
689     ParseParticleVelocity(velocityJsValue, velocity);
690     particleOption.SetParticleVelocityOption(velocity);
691 
692     auto accelerationJsValue = particleJsObj->GetProperty("acceleration");
693     OHOS::Ace::NG::AccelerationProperty acceleration;
694     ParseParticleAcceleration(accelerationJsValue, acceleration);
695     particleOption.SetParticleAccelerationOption(acceleration);
696 
697     auto spinJsValue = particleJsObj->GetProperty("spin");
698     if (spinJsValue->IsObject()) {
699         auto spinJsObj = JSRef<JSObject>::Cast(spinJsValue);
700         OHOS::Ace::NG::ParticleFloatPropertyOption spinOption;
701         ParseFloatOption(spinJsObj, spinOption, DEFAULT_SPIN, MIN_SPIN, MAX_SPIN);
702         particleOption.SetParticleSpinOption(spinOption);
703     }
704     return true;
705 }
706 
ParseParticleArray(JSRef<JSArray> & paramArray,std::list<OHOS::Ace::NG::ParticleOption> & arrayValue)707 void ParseParticleArray(JSRef<JSArray>& paramArray, std::list<OHOS::Ace::NG::ParticleOption>& arrayValue)
708 {
709     for (size_t i = 0; i < paramArray->Length(); i++) {
710         if (!paramArray->GetValueAt(i)->IsObject()) {
711             continue;
712         }
713         OHOS::Ace::NG::ParticleOption option;
714         auto particleJsObj = JSRef<JSObject>::Cast(paramArray->GetValueAt(i));
715         if (!ParseParticleOption(particleJsObj, option)) {
716             continue;
717         }
718         arrayValue.emplace_back(option);
719     }
720 }
721 } // namespace
Create(const JSCallbackInfo & args)722 void JSParticle::Create(const JSCallbackInfo& args)
723 {
724     if (args.Length() < 1) {
725         return;
726     }
727     std::list<OHOS::Ace::NG::ParticleOption> arrayValue;
728     if (args[0]->IsObject()) {
729         JSRef<JSObject> paramObj = JSRef<JSObject>::Cast(args[0]);
730         auto particlesJsArray = paramObj->GetProperty("particles");
731         if (particlesJsArray->IsArray()) {
732             auto paramArray = JSRef<JSArray>::Cast(particlesJsArray);
733             ParseParticleArray(paramArray, arrayValue);
734         }
735     }
736     ParticleModel::GetInstance()->Create(arrayValue);
737 }
738 
JSBind(BindingTarget globalObj)739 void JSParticle::JSBind(BindingTarget globalObj)
740 {
741     JSClass<JSParticle>::Declare("Particle");
742     JSClass<JSParticle>::StaticMethod("create", &JSParticle::Create);
743     JSClass<JSParticle>::InheritAndBind<JSViewAbstract>(globalObj);
744 }
745 } // namespace OHOS::Ace::Framework
746