• 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             return false;
349         }
350         imageParameter.SetImageSource(src);
351         auto width = Dimension(0.0);
352         auto height = Dimension(0.0);
353         auto sizeValue = std::pair<Dimension, Dimension>(width, height);
354         ParsSize(sizeValue, sizeJsValue);
355         imageParameter.SetSize(sizeValue);
356         auto fit = ImageFit::COVER;
357         if (objectFitJsValue->IsNumber()) {
358             auto fitIntValue = objectFitJsValue->ToNumber<int32_t>();
359             if (fitIntValue >= static_cast<int32_t>(ImageFit::FILL) &&
360                 fitIntValue <= static_cast<int32_t>(ImageFit::SCALE_DOWN)) {
361                 fit = static_cast<ImageFit>(fitIntValue);
362             }
363         }
364         imageParameter.SetImageFit(fit);
365         NG::ParticleConfig particleConfig;
366         particleConfig.SetImageParticleParameter(imageParameter);
367         particle.SetConfig(particleConfig);
368     } else {
369         auto radiusJsValue = configJsObject->GetProperty("radius");
370         CalcDimension radius;
371         JSParticle::ParseJsDimensionVp(radiusJsValue, radius);
372         NG::PointParticleParameter pointParameter;
373         pointParameter.SetRadius(!radius.IsNonPositive() ? radius.ConvertToPx() : 0.0f);
374         NG::ParticleConfig particleConfig;
375         particleConfig.SetPointParticleParameter(pointParameter);
376         particle.SetConfig(particleConfig);
377     }
378 
379     auto count = 0;
380     auto countJsValue = particleJsObject->GetProperty("count");
381     if (countJsValue->IsNumber()) {
382         auto countIntValue = countJsValue->ToNumber<int32_t>();
383         if (countIntValue >= -1) {
384             count = countIntValue;
385         }
386     }
387     particle.SetCount(count);
388 
389     auto lifeTime = 1000;
390     auto lifeTimeJsValue = particleJsObject->GetProperty("lifetime");
391     if (lifeTimeJsValue->IsNumber()) {
392         auto lifeTimeIntValue = lifeTimeJsValue->ToNumber<int64_t>();
393         if (lifeTimeIntValue >= -1) {
394             lifeTime = lifeTimeIntValue;
395         }
396     }
397     particle.SetLifeTime(lifeTime);
398     return true;
399 }
400 
ParseEmitterOption(JSRef<JSObject> & emitterJsObject,OHOS::Ace::NG::EmitterOption & emitterOption)401 bool ParseEmitterOption(JSRef<JSObject>& emitterJsObject, OHOS::Ace::NG::EmitterOption& emitterOption)
402 {
403     auto particleJsValue = emitterJsObject->GetProperty("particle");
404     if (!particleJsValue->IsObject()) {
405         return false;
406     }
407     auto particleJsObject = JSRef<JSObject>::Cast(particleJsValue);
408     OHOS::Ace::NG::Particle particle;
409     if (!ParseParticleObject(particleJsObject, particle)) {
410         return false;
411     }
412     emitterOption.SetParticle(particle);
413     int32_t emitRate = PARTICLE_DEFAULT_EMITTER_RATE;
414     auto emitRateJsValue = emitterJsObject->GetProperty("emitRate");
415     if (emitRateJsValue->IsNumber()) {
416         emitRate = emitRateJsValue->ToNumber<int32_t>() >= 0 ? emitRateJsValue->ToNumber<int32_t>() : emitRate;
417     }
418     emitterOption.SetEmitterRate(emitRate);
419 
420     auto emitShape = OHOS::Ace::NG::ParticleEmitterShape::RECTANGLE;
421     auto emitShapeJsValue = emitterJsObject->GetProperty("shape");
422     if (emitShapeJsValue->IsNumber()) {
423         auto emitShapeInt = emitShapeJsValue->ToNumber<int32_t>();
424         if (emitShapeInt >= static_cast<int32_t>(OHOS::Ace::NG::ParticleEmitterShape::RECTANGLE) &&
425             emitShapeInt <= static_cast<int32_t>(OHOS::Ace::NG::ParticleEmitterShape::ELLIPSE)) {
426             emitShape = static_cast<OHOS::Ace::NG::ParticleEmitterShape>(emitShapeInt);
427         }
428     }
429     emitterOption.SetShape(emitShape);
430     auto positionJsValue = emitterJsObject->GetProperty("position");
431     CalcDimension xValue(0.0);
432     CalcDimension yValue(0.0);
433     if (positionJsValue->IsArray()) {
434         auto positionJsArray = JSRef<JSArray>::Cast(positionJsValue);
435         if (positionJsArray->Length() == ARRAY_SIZE) {
436             JSParticle::ParseJsDimensionVp(positionJsArray->GetValueAt(0), xValue);
437             JSParticle::ParseJsDimensionVp(positionJsArray->GetValueAt(1), yValue);
438         }
439     }
440     auto positionValue = std::pair<Dimension, Dimension>(xValue, yValue);
441     emitterOption.SetPosition(positionValue);
442 
443     auto width = Dimension(1.0, DimensionUnit::PERCENT);
444     auto height = Dimension(1.0, DimensionUnit::PERCENT);
445     auto sizeValue = std::pair<Dimension, Dimension>(width, height);
446     auto sizeJsValue = emitterJsObject->GetProperty("size");
447     ParsSize(sizeValue, sizeJsValue);
448     emitterOption.SetSize(sizeValue);
449     return true;
450 }
451 
ParseAnimationColorArray(JSRef<JSArray> & curveConfigJsArray,std::list<NG::ParticlePropertyAnimation<Color>> & particleAnimationColorArray)452 void ParseAnimationColorArray(
453     JSRef<JSArray>& curveConfigJsArray, std::list<NG::ParticlePropertyAnimation<Color>>& particleAnimationColorArray)
454 {
455     auto arraySize = static_cast<int32_t>(curveConfigJsArray->Length());
456     for (int i = 0; i < arraySize; i++) {
457         auto arrayItemJsValue = curveConfigJsArray->GetValueAt(i);
458         NG::ParticlePropertyAnimation<Color> colorPropertyAnimation;
459         if (!arrayItemJsValue->IsObject()) {
460             continue;
461         }
462         auto arrayItemJsObject = JSRef<JSObject>::Cast(arrayItemJsValue);
463         auto fromJsValue = arrayItemJsObject->GetProperty("from");
464         Color from(DEFAULT_COLOR);
465         JSParticle::ParseJsColor(fromJsValue, from);
466         colorPropertyAnimation.SetFrom(from);
467         auto toJsValue = arrayItemJsObject->GetProperty("to");
468         Color to(DEFAULT_COLOR);
469         JSParticle::ParseJsColor(toJsValue, to);
470         colorPropertyAnimation.SetTo(to);
471         auto startMillisJsValue = arrayItemJsObject->GetProperty("startMillis");
472         auto startMillis = static_cast<int32_t>(0);
473         if (!JSParticle::ParseJsInt32(startMillisJsValue, startMillis) || startMillis < 0) {
474             startMillis = 0;
475         }
476         colorPropertyAnimation.SetStartMills(startMillis);
477         auto endMillisJsValue = arrayItemJsObject->GetProperty("endMillis");
478         auto endMillis = static_cast<int32_t>(0);
479         if (!JSParticle::ParseJsInt32(endMillisJsValue, endMillis) || endMillis < 0) {
480             endMillis = 0;
481         }
482         colorPropertyAnimation.SetEndMills(endMillis);
483         auto curveJsValue = arrayItemJsObject->GetProperty("curve");
484         auto curve = ParseCurve(curveJsValue);
485         if (curve) {
486             colorPropertyAnimation.SetCurve(curve);
487         }
488         particleAnimationColorArray.emplace_back(colorPropertyAnimation);
489     }
490 }
491 
ParseColorRandomUpdater(JSRef<JSVal> configJsValue,OHOS::Ace::NG::ParticleColorPropertyUpdater & updater)492 void ParseColorRandomUpdater(JSRef<JSVal> configJsValue, OHOS::Ace::NG::ParticleColorPropertyUpdater& updater)
493 {
494     NG::ParticleColorPropertyUpdaterConfig randomUpdaterConfig;
495     NG::ColorParticleRandomUpdateConfig colorRandomConfig;
496     if (!configJsValue->IsObject()) {
497         auto defaultPair = std::pair<float, float>(0.0f, 0.0f);
498         colorRandomConfig.SetRedRandom(defaultPair);
499         colorRandomConfig.SetGreenRandom(defaultPair);
500         colorRandomConfig.SetBlueRandom(defaultPair);
501         colorRandomConfig.SetAlphaRandom(defaultPair);
502         randomUpdaterConfig.SetRandomConfig(colorRandomConfig);
503         updater.SetConfig(randomUpdaterConfig);
504         return;
505     }
506     auto randomConfigJsObject = JSRef<JSObject>::Cast(configJsValue);
507     auto rJsValue = randomConfigJsObject->GetProperty("r");
508     auto gJsValue = randomConfigJsObject->GetProperty("g");
509     auto bJsValue = randomConfigJsObject->GetProperty("b");
510     auto aJsValue = randomConfigJsObject->GetProperty("a");
511     std::pair<float, float> defaultPair(0.0f, 0.0f);
512     auto rRangeValue = ParseParticleRange(rJsValue, 0.0f);
513     auto gRangeValue = ParseParticleRange(gJsValue, 0.0f);
514     auto bRangeValue = ParseParticleRange(bJsValue, 0.0f);
515     auto aRangeValue = ParseParticleRange(aJsValue, 0.0f);
516     colorRandomConfig.SetRedRandom(rRangeValue.value_or(defaultPair));
517     colorRandomConfig.SetGreenRandom(gRangeValue.value_or(defaultPair));
518     colorRandomConfig.SetBlueRandom(bRangeValue.value_or(defaultPair));
519     colorRandomConfig.SetAlphaRandom(aRangeValue.value_or(defaultPair));
520     randomUpdaterConfig.SetRandomConfig(colorRandomConfig);
521     updater.SetConfig(randomUpdaterConfig);
522 }
523 
ParseColorCurveUpdater(JSRef<JSVal> configJsValue,OHOS::Ace::NG::ParticleColorPropertyUpdater & updater)524 void ParseColorCurveUpdater(JSRef<JSVal> configJsValue, OHOS::Ace::NG::ParticleColorPropertyUpdater& updater)
525 {
526     std::list<NG::ParticlePropertyAnimation<Color>> particleAnimationColorArray;
527     NG::ParticleColorPropertyUpdaterConfig randomUpdaterConfig;
528     if (!configJsValue->IsArray()) {
529         randomUpdaterConfig.SetAnimationArray(particleAnimationColorArray);
530         updater.SetConfig(randomUpdaterConfig);
531         return;
532     }
533     auto curveConfigJsArray = JSRef<JSArray>::Cast(configJsValue);
534     ParseAnimationColorArray(curveConfigJsArray, particleAnimationColorArray);
535     randomUpdaterConfig.SetAnimationArray(particleAnimationColorArray);
536     updater.SetConfig(randomUpdaterConfig);
537 }
538 
ParseColorUpdater(JSRef<JSObject> & updaterJsObject,OHOS::Ace::NG::ParticleColorPropertyUpdater & updater)539 bool ParseColorUpdater(JSRef<JSObject>& updaterJsObject, OHOS::Ace::NG::ParticleColorPropertyUpdater& updater)
540 {
541     auto typeJsValue = updaterJsObject->GetProperty("type");
542     if (typeJsValue->IsNumber()) {
543         auto typeIntValue = typeJsValue->ToNumber<int32_t>();
544         if (typeIntValue < NG::UpdaterType::NONE_UPDATER || typeIntValue > NG::UpdaterType::CURVE) {
545             typeIntValue = NG::UpdaterType::NONE_UPDATER;
546         }
547         auto type = static_cast<NG::UpdaterType>(typeIntValue);
548         updater.SetUpdateType(type);
549         auto configJsValue = updaterJsObject->GetProperty("config");
550         if (type == NG::UpdaterType::RANDOM) {
551             ParseColorRandomUpdater(configJsValue, updater);
552             return true;
553         } else if (type == NG::UpdaterType::CURVE) {
554             ParseColorCurveUpdater(configJsValue, updater);
555             return true;
556         }
557     }
558     return false;
559 }
560 
ParseColorInitRange(JSRef<JSVal> colorRangeJsValue,OHOS::Ace::NG::ParticleColorPropertyOption & colorOption)561 void ParseColorInitRange(JSRef<JSVal> colorRangeJsValue, OHOS::Ace::NG::ParticleColorPropertyOption& colorOption)
562 {
563     Color fromColor(DEFAULT_COLOR);
564     Color toColor(DEFAULT_COLOR);
565     auto defaultRange = std::pair<Color, Color>(fromColor, toColor);
566     if (!colorRangeJsValue->IsArray()) {
567         colorOption.SetRange(defaultRange);
568         return;
569     }
570     auto colorRangeJsArray = JSRef<JSArray>::Cast(colorRangeJsValue);
571     if (static_cast<int32_t>(colorRangeJsArray->Length()) != ARRAY_SIZE) {
572         colorOption.SetRange(defaultRange);
573         return;
574     }
575     JSParticle::ParseJsColor(colorRangeJsArray->GetValueAt(0), fromColor);
576     JSParticle::ParseJsColor(colorRangeJsArray->GetValueAt(1), toColor);
577     auto range = std::pair<Color, Color>(fromColor, toColor);
578     colorOption.SetRange(range);
579 }
580 
ParseColorOption(JSRef<JSObject> & colorJsObject,OHOS::Ace::NG::ParticleColorPropertyOption & colorOption)581 void ParseColorOption(JSRef<JSObject>& colorJsObject, OHOS::Ace::NG::ParticleColorPropertyOption& colorOption)
582 {
583     auto colorRangeJsValue = colorJsObject->GetProperty("range");
584     ParseColorInitRange(colorRangeJsValue, colorOption);
585     auto updaterJsValue = colorJsObject->GetProperty("updater");
586     NG::ParticleColorPropertyUpdater updater;
587     if (updaterJsValue->IsObject()) {
588         auto updaterJsObject = JSRef<JSObject>::Cast(updaterJsValue);
589         if (ParseColorUpdater(updaterJsObject, updater)) {
590             colorOption.SetUpdater(updater);
591             return;
592         }
593     }
594     updater.SetUpdateType(NG::UpdaterType::NONE_UPDATER);
595     NG::ParticleColorPropertyUpdaterConfig noneUpdaterConfig;
596     noneUpdaterConfig.SetInValid(0);
597     updater.SetConfig(noneUpdaterConfig);
598     colorOption.SetUpdater(updater);
599 }
600 
ParseParticleVelocity(JSRef<JSVal> jsValue,OHOS::Ace::NG::VelocityProperty & velocity)601 void ParseParticleVelocity(JSRef<JSVal> jsValue, OHOS::Ace::NG::VelocityProperty& velocity)
602 {
603     auto defaultPair = std::pair<float, float>(0.0f, 0.0f);
604     if (!jsValue->IsObject()) {
605         velocity.SetSpeedRange(defaultPair);
606         velocity.SetAngleRange(defaultPair);
607         return;
608     }
609     auto jsValueObj = JSRef<JSObject>::Cast(jsValue);
610     auto speedJsValue = jsValueObj->GetProperty("speed");
611     auto angleJsValue = jsValueObj->GetProperty("angle");
612     auto speedPair = ParseParticleRange(speedJsValue, 0.0f);
613     if (speedPair.has_value()) {
614         velocity.SetSpeedRange(speedPair.value());
615     } else {
616         velocity.SetSpeedRange(defaultPair);
617     }
618     auto anglePair = ParseParticleRange(angleJsValue, 0.0f);
619     if (anglePair.has_value()) {
620         velocity.SetAngleRange(anglePair.value());
621     } else {
622         velocity.SetAngleRange(defaultPair);
623     }
624 }
625 
ParseParticleAcceleration(JSRef<JSVal> jsValue,OHOS::Ace::NG::AccelerationProperty & acceleration)626 void ParseParticleAcceleration(JSRef<JSVal> jsValue, OHOS::Ace::NG::AccelerationProperty& acceleration)
627 {
628     if (!jsValue->IsObject()) {
629         return;
630     }
631     auto jsValueObj = JSRef<JSObject>::Cast(jsValue);
632     auto speedValue = jsValueObj->GetProperty("speed");
633     auto alphaValue = jsValueObj->GetProperty("angle");
634     OHOS::Ace::NG::ParticleFloatPropertyOption speedOption;
635     if (speedValue->IsObject()) {
636         auto speedObject = JSRef<JSObject>::Cast(speedValue);
637         ParseFloatOption(speedObject, speedOption, DEFAULT_SPEED, MIN_SPEED, MAX_SPEED);
638         acceleration.SetSpeed(speedOption);
639     }
640     OHOS::Ace::NG::ParticleFloatPropertyOption angleOption;
641     if (alphaValue->IsObject()) {
642         auto alphaObject = JSRef<JSObject>::Cast(alphaValue);
643         ParseFloatOption(alphaObject, angleOption, DEFAULT_ANGLE, MIN_ANGLE, MAX_ANGLE);
644         acceleration.SetAngle(angleOption);
645     }
646 }
647 
ParseParticleOption(JSRef<JSObject> & particleJsObj,OHOS::Ace::NG::ParticleOption & particleOption)648 bool ParseParticleOption(JSRef<JSObject>& particleJsObj, OHOS::Ace::NG::ParticleOption& particleOption)
649 {
650     auto emitterJsValue = particleJsObj->GetProperty("emitter");
651     if (!emitterJsValue->IsObject()) {
652         return false;
653     }
654 
655     auto emitterJsObj = JSRef<JSObject>::Cast(emitterJsValue);
656     OHOS::Ace::NG::EmitterOption emitterOption;
657     if (!ParseEmitterOption(emitterJsObj, emitterOption)) {
658         return false;
659     }
660 
661     particleOption.SetEmitterOption(emitterOption);
662     auto colorJsValue = particleJsObj->GetProperty("color");
663     if (colorJsValue->IsObject()) {
664         auto colorJsObj = JSRef<JSObject>::Cast(colorJsValue);
665         OHOS::Ace::NG::ParticleColorPropertyOption colorOption;
666         ParseColorOption(colorJsObj, colorOption);
667         particleOption.SetParticleColorOption(colorOption);
668     }
669 
670     auto opacityJsValue = particleJsObj->GetProperty("opacity");
671     if (opacityJsValue->IsObject()) {
672         auto opacityJsObj = JSRef<JSObject>::Cast(opacityJsValue);
673         OHOS::Ace::NG::ParticleFloatPropertyOption opacityOption;
674         ParseFloatOption(opacityJsObj, opacityOption, DEFAULT_OPACITY, MIN_OPACITY, MAX_OPACITY);
675         particleOption.SetParticleOpacityOption(opacityOption);
676     }
677 
678     auto scaleJsValue = particleJsObj->GetProperty("scale");
679     if (scaleJsValue->IsObject()) {
680         auto scaleJsObj = JSRef<JSObject>::Cast(scaleJsValue);
681         OHOS::Ace::NG::ParticleFloatPropertyOption scaleOption;
682         ParseFloatOption(scaleJsObj, scaleOption, DEFAULT_SCALE, MIN_SCALE, MAX_SCALE);
683         particleOption.SetParticleScaleOption(scaleOption);
684     }
685 
686     auto velocityJsValue = particleJsObj->GetProperty("velocity");
687     OHOS::Ace::NG::VelocityProperty velocity;
688     ParseParticleVelocity(velocityJsValue, velocity);
689     particleOption.SetParticleVelocityOption(velocity);
690 
691     auto accelerationJsValue = particleJsObj->GetProperty("acceleration");
692     OHOS::Ace::NG::AccelerationProperty acceleration;
693     ParseParticleAcceleration(accelerationJsValue, acceleration);
694     particleOption.SetParticleAccelerationOption(acceleration);
695 
696     auto spinJsValue = particleJsObj->GetProperty("spin");
697     if (spinJsValue->IsObject()) {
698         auto spinJsObj = JSRef<JSObject>::Cast(spinJsValue);
699         OHOS::Ace::NG::ParticleFloatPropertyOption spinOption;
700         ParseFloatOption(spinJsObj, spinOption, DEFAULT_SPIN, MIN_SPIN, MAX_SPIN);
701         particleOption.SetParticleSpinOption(spinOption);
702     }
703     return true;
704 }
705 
ParseParticleArray(JSRef<JSArray> & paramArray,std::list<OHOS::Ace::NG::ParticleOption> & arrayValue)706 void ParseParticleArray(JSRef<JSArray>& paramArray, std::list<OHOS::Ace::NG::ParticleOption>& arrayValue)
707 {
708     for (size_t i = 0; i < paramArray->Length(); i++) {
709         if (!paramArray->GetValueAt(i)->IsObject()) {
710             continue;
711         }
712         OHOS::Ace::NG::ParticleOption option;
713         auto particleJsObj = JSRef<JSObject>::Cast(paramArray->GetValueAt(i));
714         if (!ParseParticleOption(particleJsObj, option)) {
715             continue;
716         }
717         arrayValue.emplace_back(option);
718     }
719 }
720 } // namespace
Create(const JSCallbackInfo & args)721 void JSParticle::Create(const JSCallbackInfo& args)
722 {
723     if (args.Length() < 1) {
724         return;
725     }
726     std::list<OHOS::Ace::NG::ParticleOption> arrayValue;
727     if (args[0]->IsObject()) {
728         JSRef<JSObject> paramObj = JSRef<JSObject>::Cast(args[0]);
729         auto particlesJsArray = paramObj->GetProperty("particles");
730         if (particlesJsArray->IsArray()) {
731             auto paramArray = JSRef<JSArray>::Cast(particlesJsArray);
732             ParseParticleArray(paramArray, arrayValue);
733         }
734     }
735     ParticleModel::GetInstance()->Create(arrayValue);
736 }
737 
JSBind(BindingTarget globalObj)738 void JSParticle::JSBind(BindingTarget globalObj)
739 {
740     JSClass<JSParticle>::Declare("Particle");
741     JSClass<JSParticle>::StaticMethod("create", &JSParticle::Create);
742     JSClass<JSParticle>::InheritAndBind<JSViewAbstract>(globalObj);
743 }
744 } // namespace OHOS::Ace::Framework
745