• 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/property/particle_property.h"
21 #include "core/components_ng/property/particle_property_animation.h"
22 #include "core/common/resource/resource_parse_utils.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 
ParseSize(std::pair<Dimension,Dimension> & size,JSRef<JSVal> & sizeJsValue)69 void ParseSize(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 
ParseSize(std::pair<Dimension,Dimension> & size,JSRef<JSVal> & sizeJsValue,NG::ImageParticleParameter & imageParticle)88 void ParseSize(std::pair<Dimension, Dimension>& size,
89     JSRef<JSVal>& sizeJsValue, NG::ImageParticleParameter& imageParticle)
90 {
91     if (!sizeJsValue->IsArray()) {
92         return;
93     }
94     auto sizeJsArray = JSRef<JSArray>::Cast(sizeJsValue);
95     if (static_cast<int32_t>(sizeJsArray->Length()) != ARRAY_SIZE) {
96         TAG_LOGE(AceLogTag::ACE_ANIMATION, "ImageParticle: invalid size.");
97         return;
98     }
99     CalcDimension xValue;
100     CalcDimension yValue;
101     RefPtr<ResourceObject> xValueResObj;
102     if (JSParticle::ParseJsDimensionVp(sizeJsArray->GetValueAt(0), xValue, xValueResObj) &&
103         GreatOrEqual(xValue.Value(), 0.0)) {
104         size.first = xValue;
105         if (xValueResObj) {
106             auto&& sizeUpdateFunc =
107                 [](const RefPtr<ResourceObject>& resobjX, NG::ImageParticleParameter& imageParticle) {
108                 CalcDimension xValue(0.0);
109                 ResourceParseUtils::ParseResDimensionVpNG(resobjX, xValue);
110                 imageParticle.SetSizeX(xValue);
111             };
112             imageParticle.AddResource("imageParticle.sizeX", xValueResObj, std::move(sizeUpdateFunc));
113         } else {
114             imageParticle.RemoveResource("imageParticle.sizeX");
115         }
116     }
117     RefPtr<ResourceObject> yValueResObj;
118     if (JSParticle::ParseJsDimensionVp(sizeJsArray->GetValueAt(1), yValue, yValueResObj) &&
119         GreatOrEqual(yValue.Value(), 0.0)) {
120         size.second = yValue;
121         if (yValueResObj) {
122             auto&& sizeUpdateFunc =
123                 [](const RefPtr<ResourceObject>& resobjY, NG::ImageParticleParameter& imageParticle) {
124                 CalcDimension yValue(0.0);
125                 ResourceParseUtils::ParseResDimensionVpNG(resobjY, yValue);
126                 imageParticle.SetSizeY(yValue);
127             };
128             imageParticle.AddResource("imageParticle.sizeY", yValueResObj, std::move(sizeUpdateFunc));
129         } else {
130             imageParticle.RemoveResource("imageParticle.sizeY");
131         }
132     }
133 }
134 
ParseSize(std::pair<Dimension,Dimension> & size,JSRef<JSVal> & sizeJsValue,OHOS::Ace::NG::EmitterOption & emitterOption)135 void ParseSize(std::pair<Dimension, Dimension>& size,
136     JSRef<JSVal>& sizeJsValue, OHOS::Ace::NG::EmitterOption& emitterOption)
137 {
138     if (!sizeJsValue->IsArray()) {
139         return;
140     }
141     auto sizeJsArray = JSRef<JSArray>::Cast(sizeJsValue);
142     if (static_cast<int32_t>(sizeJsArray->Length()) != ARRAY_SIZE) {
143         TAG_LOGE(AceLogTag::ACE_ANIMATION, "EmitterOption: invalid size.");
144         return;
145     }
146     CalcDimension xValue;
147     CalcDimension yValue;
148     RefPtr<ResourceObject> xValueResObj;
149     if (JSParticle::ParseJsDimensionVp(sizeJsArray->GetValueAt(0), xValue, xValueResObj) &&
150         GreatOrEqual(xValue.Value(), 0.0)) {
151         size.first = xValue;
152         if (xValueResObj) {
153             auto&& sizeUpdateFunc =
154                 [](const RefPtr<ResourceObject>& resobjX, OHOS::Ace::NG::EmitterOption& emitterOption) {
155                 CalcDimension xValue(0.0);
156                 ResourceParseUtils::ParseResDimensionVpNG(resobjX, xValue);
157                 emitterOption.SetSizeX(xValue);
158             };
159             emitterOption.AddResource("emitterOption.sizeX", xValueResObj, std::move(sizeUpdateFunc));
160         } else {
161             emitterOption.RemoveResource("emitterOption.sizeX");
162         }
163     }
164     RefPtr<ResourceObject> yValueResObj;
165     if (JSParticle::ParseJsDimensionVp(sizeJsArray->GetValueAt(1), yValue, yValueResObj) &&
166         GreatOrEqual(yValue.Value(), 0.0)) {
167         size.second = yValue;
168         if (yValueResObj) {
169             auto&& sizeUpdateFunc =
170                 [](const RefPtr<ResourceObject>& resobjY, OHOS::Ace::NG::EmitterOption& emitterOption) {
171                 CalcDimension yValue(0.0);
172                 ResourceParseUtils::ParseResDimensionVpNG(resobjY, yValue);
173                 emitterOption.SetSizeY(yValue);
174             };
175             emitterOption.AddResource("emitterOption.sizeY", yValueResObj, std::move(sizeUpdateFunc));
176         } else {
177             emitterOption.RemoveResource("emitterOption.sizeY");
178         }
179     }
180 }
181 
ParseParticleRange(JSRef<JSVal> & jsValue,float defaultValue)182 std::optional<std::pair<float, float>> ParseParticleRange(JSRef<JSVal>& jsValue, float defaultValue)
183 {
184     std::optional<std::pair<float, float>> rangeOpt;
185     auto defaultPair = std::pair<float, float>(defaultValue, defaultValue);
186     if (!jsValue->IsArray()) {
187         rangeOpt = defaultPair;
188         return rangeOpt;
189     }
190     auto jsArray = JSRef<JSArray>::Cast(jsValue);
191     if (jsArray->Length() != ARRAY_SIZE) {
192         rangeOpt = defaultPair;
193         return rangeOpt;
194     }
195     auto from = defaultValue;
196     if (jsArray->GetValueAt(0)->IsNumber()) {
197         from = jsArray->GetValueAt(0)->ToNumber<float>();
198     }
199     auto to = defaultValue;
200     if (jsArray->GetValueAt(1)->IsNumber()) {
201         to = jsArray->GetValueAt(1)->ToNumber<float>();
202     }
203     if (GreatNotEqual(from, to)) {
204         rangeOpt = defaultPair;
205         return rangeOpt;
206     }
207     rangeOpt = std::pair<float, float>(from, to);
208     return rangeOpt;
209 }
210 
ParseCurve(JSRef<JSVal> & curveJsValue)211 RefPtr<Curve> ParseCurve(JSRef<JSVal>& curveJsValue)
212 {
213     RefPtr<Curve> curve;
214     if (curveJsValue->IsString()) {
215         std::string src;
216         if (JSParticle::ParseJsString(curveJsValue, src)) {
217             curve = CreateCurve(src);
218         }
219     }
220     if (!curve) {
221         curve = AceType::MakeRefPtr<LinearCurve>();
222     }
223     return curve;
224 }
225 
ParseAnimationFloatArray(JSRef<JSArray> & curveConfigJsArray,std::list<NG::ParticlePropertyAnimation<float>> & particleAnimationFloatArray,float defaultValue,float minValue,float maxValue)226 void ParseAnimationFloatArray(JSRef<JSArray>& curveConfigJsArray,
227     std::list<NG::ParticlePropertyAnimation<float>>& particleAnimationFloatArray, float defaultValue, float minValue,
228     float maxValue)
229 {
230     auto arraySize = static_cast<int32_t>(curveConfigJsArray->Length());
231     for (int i = 0; i < arraySize; i++) {
232         auto arrayItemJsValue = curveConfigJsArray->GetValueAt(i);
233         NG::ParticlePropertyAnimation<float> floatPropertyAnimation;
234         if (!arrayItemJsValue->IsObject()) {
235             continue;
236         }
237         auto arrayItemJsObject = JSRef<JSObject>::Cast(arrayItemJsValue);
238         auto fromJsValue = arrayItemJsObject->GetProperty("from");
239         float from = defaultValue;
240         if (fromJsValue->IsNumber()) {
241             from = fromJsValue->ToNumber<float>();
242             if (GreatNotEqual(minValue, MIN_BOUNDARY) && LessNotEqual(from, minValue)) {
243                 from = defaultValue;
244             }
245             if (LessNotEqual(maxValue, MAX_BOUNDARY) && GreatNotEqual(from, maxValue)) {
246                 from = defaultValue;
247             }
248         }
249         floatPropertyAnimation.SetFrom(from);
250         auto toJsValue = arrayItemJsObject->GetProperty("to");
251         float to = defaultValue;
252         if (toJsValue->IsNumber()) {
253             to = toJsValue->ToNumber<float>();
254             if (GreatNotEqual(minValue, MIN_BOUNDARY) && LessNotEqual(to, minValue)) {
255                 to = defaultValue;
256             }
257             if (LessNotEqual(maxValue, MAX_BOUNDARY) && GreatNotEqual(to, maxValue)) {
258                 to = defaultValue;
259             }
260         }
261         floatPropertyAnimation.SetTo(to);
262         auto startMillisJsValue = arrayItemJsObject->GetProperty("startMillis");
263         auto startMillis = static_cast<int32_t>(0);
264         if (!JSParticle::ParseJsInt32(startMillisJsValue, startMillis) || startMillis < 0) {
265             startMillis = 0;
266         }
267         floatPropertyAnimation.SetStartMills(startMillis);
268         auto endMillisJsValue = arrayItemJsObject->GetProperty("endMillis");
269         auto endMillis = static_cast<int32_t>(0);
270         if (!JSParticle::ParseJsInt32(endMillisJsValue, endMillis) || endMillis < 0) {
271             endMillis = 0;
272         }
273         floatPropertyAnimation.SetEndMills(endMillis);
274         auto curveJsValue = arrayItemJsObject->GetProperty("curve");
275         auto curve = ParseCurve(curveJsValue);
276         if (curve) {
277             floatPropertyAnimation.SetCurve(curve);
278         }
279         particleAnimationFloatArray.emplace_back(floatPropertyAnimation);
280     }
281 }
282 
ParseFloatRandomConfig(JSRef<JSVal> & configJsValue,OHOS::Ace::NG::ParticleFloatPropertyUpdater & updater)283 bool ParseFloatRandomConfig(JSRef<JSVal>& configJsValue, OHOS::Ace::NG::ParticleFloatPropertyUpdater& updater)
284 {
285     if (!configJsValue->IsArray()) {
286         return false;
287     }
288     auto randomConfigJsArray = JSRef<JSArray>::Cast(configJsValue);
289     auto randomArraySize = static_cast<int32_t>(randomConfigJsArray->Length());
290     if (randomArraySize != ARRAY_SIZE) {
291         return false;
292     }
293     auto randomRangePair = ParseParticleRange(configJsValue, 0.0f);
294     if (!randomRangePair.has_value()) {
295         return false;
296     }
297     NG::ParticleFloatPropertyUpdaterConfig randomUpdaterConfig;
298     randomUpdaterConfig.SetRandomConfig(randomRangePair.value());
299     updater.SetConfig(randomUpdaterConfig);
300     return true;
301 }
302 
ParseFloatCurveConfig(JSRef<JSVal> & configJsValue,OHOS::Ace::NG::ParticleFloatPropertyUpdater & updater,float defaultValue,float minValue,float maxValue)303 bool ParseFloatCurveConfig(JSRef<JSVal>& configJsValue, OHOS::Ace::NG::ParticleFloatPropertyUpdater& updater,
304     float defaultValue, float minValue, float maxValue)
305 {
306     if (!configJsValue->IsArray()) {
307         return false;
308     }
309     auto curveConfigJsArray = JSRef<JSArray>::Cast(configJsValue);
310     std::list<NG::ParticlePropertyAnimation<float>> particleAnimationFloatArray;
311     ParseAnimationFloatArray(curveConfigJsArray, particleAnimationFloatArray, defaultValue, minValue, maxValue);
312     NG::ParticleFloatPropertyUpdaterConfig updateConfig;
313     updateConfig.SetAnimations(particleAnimationFloatArray);
314     updater.SetConfig(updateConfig);
315     return true;
316 }
317 
ParseFloatUpdater(JSRef<JSObject> & updaterJsObject,OHOS::Ace::NG::ParticleFloatPropertyUpdater & updater,float defaultValue,float minValue,float maxValue)318 bool ParseFloatUpdater(JSRef<JSObject>& updaterJsObject, OHOS::Ace::NG::ParticleFloatPropertyUpdater& updater,
319     float defaultValue, float minValue, float maxValue)
320 {
321     auto typeJsValue = updaterJsObject->GetProperty("type");
322     if (typeJsValue->IsNumber()) {
323         auto typeIntValue = typeJsValue->ToNumber<int32_t>();
324         if (typeIntValue < NG::UpdaterType::NONE_UPDATER || typeIntValue > NG::UpdaterType::CURVE) {
325             typeIntValue = NG::UpdaterType::NONE_UPDATER;
326         }
327         auto type = static_cast<NG::UpdaterType>(typeIntValue);
328         updater.SetUpdaterType(type);
329         auto configJsValue = updaterJsObject->GetProperty("config");
330         if (type == NG::UpdaterType::RANDOM) {
331             if (!ParseFloatRandomConfig(configJsValue, updater)) {
332                 auto randomRangePair = std::pair<float, float>(0.0f, 0.0f);
333                 NG::ParticleFloatPropertyUpdaterConfig randomUpdaterConfig;
334                 randomUpdaterConfig.SetRandomConfig(randomRangePair);
335                 updater.SetConfig(randomUpdaterConfig);
336             }
337             return true;
338         } else if (type == NG::UpdaterType::CURVE) {
339             if (!ParseFloatCurveConfig(configJsValue, updater, defaultValue, minValue, maxValue)) {
340                 std::list<NG::ParticlePropertyAnimation<float>> particleAnimationFloatArray;
341                 NG::ParticleFloatPropertyUpdaterConfig updateConfig;
342                 updateConfig.SetAnimations(particleAnimationFloatArray);
343                 updater.SetConfig(updateConfig);
344             }
345             return true;
346         }
347     }
348     return false;
349 }
350 
ParseFloatInitRange(JSRef<JSVal> & floatRangeJsValue,OHOS::Ace::NG::ParticleFloatPropertyOption & floatOption,float defaultValue,float minValue,float maxValue)351 void ParseFloatInitRange(JSRef<JSVal>& floatRangeJsValue, OHOS::Ace::NG::ParticleFloatPropertyOption& floatOption,
352     float defaultValue, float minValue, float maxValue)
353 {
354     auto defaultPair = std::pair<float, float>(defaultValue, defaultValue);
355     if (!floatRangeJsValue->IsArray()) {
356         floatOption.SetRange(defaultPair);
357         return;
358     }
359     auto floatRangeJsArray = JSRef<JSArray>::Cast(floatRangeJsValue);
360     if (floatRangeJsArray->Length() != ARRAY_SIZE) {
361         floatOption.SetRange(defaultPair);
362         return;
363     }
364     auto from = defaultValue;
365     auto fromJsValue = floatRangeJsArray->GetValueAt(0);
366     if (fromJsValue->IsNumber()) {
367         from = fromJsValue->ToNumber<float>();
368         if (GreatNotEqual(minValue, MIN_BOUNDARY) && LessNotEqual(from, minValue)) {
369             from = defaultValue;
370         }
371         if (LessNotEqual(maxValue, MAX_BOUNDARY) && GreatNotEqual(from, maxValue)) {
372             from = defaultValue;
373         }
374     }
375     auto to = defaultValue;
376     auto toJsValue = floatRangeJsArray->GetValueAt(1);
377     if (toJsValue->IsNumber()) {
378         to = toJsValue->ToNumber<float>();
379         if (GreatNotEqual(minValue, MIN_BOUNDARY) && LessNotEqual(to, minValue)) {
380             to = defaultValue;
381         }
382         if (LessNotEqual(maxValue, MAX_BOUNDARY) && GreatNotEqual(to, maxValue)) {
383             to = defaultValue;
384         }
385     }
386     if (GreatNotEqual(from, to)) {
387         from = defaultValue;
388         to = defaultValue;
389     }
390     auto range = std::pair<float, float>(from, to);
391     floatOption.SetRange(range);
392 }
SrcAddResIfNeed(JSRef<JSVal> & srcJsValue,std::string & src,NG::ImageParticleParameter & imageParameter)393 bool SrcAddResIfNeed(JSRef<JSVal>& srcJsValue,
394     std::string& src, NG::ImageParticleParameter& imageParameter)
395 {
396     if (SystemProperties::ConfigChangePerform()) {
397         RefPtr<ResourceObject> resObj;
398         if (srcJsValue->IsString()) {
399             src = srcJsValue->ToString();
400         } else if (!JSParticle::ParseJsMedia(srcJsValue, src, resObj)) {
401             return false;
402         }
403         if (resObj) {
404             auto&& srcUpdateFunc =
405                 [](const RefPtr<ResourceObject>& resObj, NG::ImageParticleParameter& imageParameter) {
406                 std::string src;
407                 ResourceParseUtils::ParseResMedia(resObj, src);
408                 imageParameter.SetImageSource(src);
409             };
410             imageParameter.AddResource("ImageParticleParameter.src", resObj, std::move(srcUpdateFunc));
411         } else {
412             imageParameter.RemoveResource("ImageParticleParameter.src");
413         }
414     } else {
415         if (srcJsValue->IsString()) {
416             src = srcJsValue->ToString();
417         } else if (!JSParticle::ParseJsMedia(srcJsValue, src)) {
418             return false;
419         }
420     }
421     return true;
422 }
423 
ParseImageParticleObject(JSRef<JSObject> & configJsObject,OHOS::Ace::NG::Particle & particle)424 bool ParseImageParticleObject(JSRef<JSObject>& configJsObject, OHOS::Ace::NG::Particle& particle)
425 {
426     auto srcJsValue = configJsObject->GetProperty("src");
427     auto sizeJsValue = configJsObject->GetProperty("size");
428     auto objectFitJsValue = configJsObject->GetProperty("objectFit");
429     NG::ImageParticleParameter imageParameter;
430     std::string src;
431     bool result = SrcAddResIfNeed(srcJsValue, src, imageParameter);
432     if (!result) {
433         return false;
434     }
435     imageParameter.SetImageSource(src);
436     auto width = Dimension(0.0);
437     auto height = Dimension(0.0);
438     auto sizeValue = std::pair<Dimension, Dimension>(width, height);
439     if (SystemProperties::ConfigChangePerform()) {
440         ParseSize(sizeValue, sizeJsValue, imageParameter);
441     } else {
442         ParseSize(sizeValue, sizeJsValue);
443     }
444     imageParameter.SetSize(sizeValue);
445     auto fit = ImageFit::COVER;
446     if (objectFitJsValue->IsNumber()) {
447         auto fitIntValue = objectFitJsValue->ToNumber<int32_t>();
448         if (fitIntValue >= static_cast<int32_t>(ImageFit::FILL) &&
449             fitIntValue <= static_cast<int32_t>(ImageFit::SCALE_DOWN)) {
450             fit = static_cast<ImageFit>(fitIntValue);
451         }
452     }
453     imageParameter.SetImageFit(fit);
454     NG::ParticleConfig particleConfig;
455     particleConfig.SetImageParticleParameter(imageParameter);
456     particle.SetConfig(particleConfig);
457     return true;
458 }
459 
ParseFloatOption(JSRef<JSObject> & floatJsObject,OHOS::Ace::NG::ParticleFloatPropertyOption & floatOption,float defaultValue,float minValue,float maxValue)460 void ParseFloatOption(JSRef<JSObject>& floatJsObject, OHOS::Ace::NG::ParticleFloatPropertyOption& floatOption,
461     float defaultValue, float minValue, float maxValue)
462 {
463     auto floatRangeJsValue = floatJsObject->GetProperty("range");
464     ParseFloatInitRange(floatRangeJsValue, floatOption, defaultValue, minValue, maxValue);
465     auto updaterJsValue = floatJsObject->GetProperty("updater");
466     NG::ParticleFloatPropertyUpdater updater;
467     if (updaterJsValue->IsObject()) {
468         auto updaterJsObject = JSRef<JSObject>::Cast(updaterJsValue);
469         if (ParseFloatUpdater(updaterJsObject, updater, defaultValue, minValue, maxValue)) {
470             floatOption.SetUpdater(updater);
471             return;
472         }
473     }
474     updater.SetUpdaterType(NG::UpdaterType::NONE_UPDATER);
475     NG::ParticleFloatPropertyUpdaterConfig updateConfig;
476     updateConfig.SetNullStr("");
477     updater.SetConfig(updateConfig);
478     floatOption.SetUpdater(updater);
479 }
480 
481 template<typename T>
AnnulusRegisterResourceObject(T & annulusRegionValue,const RefPtr<ResourceObject> & centerXResObj,const RefPtr<ResourceObject> & centerYResObj,const RefPtr<ResourceObject> & innerRadiusResObj,const RefPtr<ResourceObject> & outerRadiusResObj)482 void AnnulusRegisterResourceObject(T& annulusRegionValue,
483     const RefPtr<ResourceObject>& centerXResObj, const RefPtr<ResourceObject>& centerYResObj,
484     const RefPtr<ResourceObject>& innerRadiusResObj, const RefPtr<ResourceObject>& outerRadiusResObj)
485 {
486     if (centerXResObj) {
487         auto&& centerXUpdateFunc = [](const RefPtr<ResourceObject>& centerXResObj,
488             OHOS::Ace::NG::ParticleAnnulusRegion& annulusRegion) {
489             CalcDimension centerXValue;
490             ResourceParseUtils::ParseResDimensionVpNG(centerXResObj, centerXValue);
491             annulusRegion.SetCenterX(centerXValue);
492         };
493         annulusRegionValue.AddResource(
494             "annulusRegion.centerX", centerXResObj, std::move(centerXUpdateFunc));
495     } else {
496         annulusRegionValue.RemoveResource("annulusRegion.centerX");
497     }
498     if (centerYResObj) {
499         auto&& centerYUpdateFunc = [](const RefPtr<ResourceObject>& centerYResObj,
500             OHOS::Ace::NG::ParticleAnnulusRegion& annulusRegion) {
501             CalcDimension centerYValue;
502             ResourceParseUtils::ParseResDimensionVpNG(centerYResObj, centerYValue);
503             annulusRegion.SetCenterY(centerYValue);
504         };
505         annulusRegionValue.AddResource(
506             "annulusRegion.centerY", centerYResObj, std::move(centerYUpdateFunc));
507     } else {
508         annulusRegionValue.RemoveResource("annulusRegion.centerY");
509     }
510     if (innerRadiusResObj) {
511         auto&& innerRadiusUpdateFunc = [](const RefPtr<ResourceObject>& innerRadiusResObj,
512             OHOS::Ace::NG::ParticleAnnulusRegion& annulusRegion) {
513             CalcDimension innerRadiusValue;
514             ResourceParseUtils::ParseResDimensionVpNG(innerRadiusResObj, innerRadiusValue);
515             annulusRegion.SetInnerRadius(innerRadiusValue);
516         };
517         annulusRegionValue.AddResource(
518             "annulusRegion.innerRadius", innerRadiusResObj, std::move(innerRadiusUpdateFunc));
519     } else {
520         annulusRegionValue.RemoveResource("annulusRegion.innerRadius");
521     }
522     if (outerRadiusResObj) {
523         auto&& outerRadiusUpdateFunc = [](const RefPtr<ResourceObject>& outerRadiusResObj,
524             OHOS::Ace::NG::ParticleAnnulusRegion& annulusRegion) {
525             CalcDimension outerRadiusValue;
526             ResourceParseUtils::ParseResDimensionVpNG(outerRadiusResObj, outerRadiusValue);
527             annulusRegion.SetOuterRadius(outerRadiusValue);
528         };
529         annulusRegionValue.AddResource(
530             "annulusRegion.outerRadius", outerRadiusResObj, std::move(outerRadiusUpdateFunc));
531     } else {
532         annulusRegionValue.RemoveResource("annulusRegion.outerRadius");
533     }
534 }
535 
ParseAnnulusCenter(const JSRef<JSObject> & centerJson,std::pair<CalcDimension,CalcDimension> & center,RefPtr<ResourceObject> & centerXResObj,RefPtr<ResourceObject> & centerYResObj)536 void ParseAnnulusCenter(const JSRef<JSObject>& centerJson, std::pair<CalcDimension, CalcDimension>& center,
537     RefPtr<ResourceObject>& centerXResObj, RefPtr<ResourceObject>& centerYResObj)
538 {
539     CalcDimension centerXValue;
540     CalcDimension centerYValue;
541     if (SystemProperties::ConfigChangePerform()) {
542         if (JSViewAbstract::ParseLengthMetricsToDimension(centerJson->GetProperty("x"),
543             centerXValue, centerXResObj)) {
544             center.first = centerXValue;
545         }
546         if (JSViewAbstract::ParseLengthMetricsToDimension(centerJson->GetProperty("y"),
547             centerYValue, centerYResObj)) {
548             center.second = centerYValue;
549         }
550     } else {
551         if (JSViewAbstract::ParseLengthMetricsToDimension(centerJson->GetProperty("x"), centerXValue)) {
552             center.first = centerXValue;
553         }
554         if (JSViewAbstract::ParseLengthMetricsToDimension(centerJson->GetProperty("y"), centerYValue)) {
555             center.second = centerYValue;
556         }
557     }
558 }
559 
ParseEmitterPropertyAnnulus(const JSRef<JSObject> & paramObj,EmitterProperty & emitterProperty)560 void ParseEmitterPropertyAnnulus(const JSRef<JSObject>& paramObj, EmitterProperty& emitterProperty)
561 {
562     auto annulusRegionProperty = paramObj->GetProperty("annulusRegion");
563     if (annulusRegionProperty->IsObject()) {
564         auto annulusRegion = Framework::JSRef<Framework::JSObject>::Cast(annulusRegionProperty);
565         auto centerProperty = annulusRegion->GetProperty("center");
566         std::pair<CalcDimension, CalcDimension> center = {
567             DEFAULT_CENTER_VALUE, DEFAULT_CENTER_VALUE
568         };
569         if (centerProperty->IsObject()) {
570             auto centerJson = JSRef<JSObject>::Cast(centerProperty);
571             CalcDimension centerXValue;
572             CalcDimension centerYValue;
573             if (JSViewAbstract::ParseLengthMetricsToDimension(centerJson->GetProperty("x"), centerXValue)) {
574                 center.first = centerXValue;
575             }
576             if (JSViewAbstract::ParseLengthMetricsToDimension(centerJson->GetProperty("y"), centerYValue)) {
577                 center.second = centerYValue;
578             }
579         }
580         CalcDimension innerRadiusValue;
581         CalcDimension outerRadiusValue;
582         JSViewAbstract::ParseLengthMetricsToDimension(annulusRegion->GetProperty("innerRadius"), innerRadiusValue);
583         JSViewAbstract::ParseLengthMetricsToDimension(annulusRegion->GetProperty("outerRadius"), outerRadiusValue);
584         auto startAngle = annulusRegion->GetProperty("startAngle");
585         auto startAngleValue = startAngle->IsNumber() ? startAngle->ToNumber<float>() : DEFAULT_START_ANGLE_VALUE;
586         auto endAngle = annulusRegion->GetProperty("endAngle");
587         auto endAngleValue = endAngle->IsNumber() ? endAngle->ToNumber<float>() : DEFAULT_END_ANGLE_VALUE;
588         emitterProperty.annulusRegion = {
589             center, innerRadiusValue, outerRadiusValue, startAngleValue, endAngleValue
590         };
591     }
592 }
593 
ParseEmitterOptionAnnulus(JSRef<JSObject> & emitterJsObject,OHOS::Ace::NG::EmitterOption & emitterOption)594 void ParseEmitterOptionAnnulus(JSRef<JSObject>& emitterJsObject, OHOS::Ace::NG::EmitterOption& emitterOption)
595 {
596     auto annulusRegionProperty = emitterJsObject->GetProperty("annulusRegion");
597     if (annulusRegionProperty->IsObject() &&
598         emitterOption.GetShape() == OHOS::Ace::NG::ParticleEmitterShape::ANNULUS) {
599         auto annulusRegion = JSRef<JSObject>::Cast(annulusRegionProperty);
600         auto centerProperty = annulusRegion->GetProperty("center");
601         std::pair<CalcDimension, CalcDimension> center = {
602             DEFAULT_CENTER_VALUE, DEFAULT_CENTER_VALUE
603             };
604         RefPtr<ResourceObject> centerXResObj;
605         RefPtr<ResourceObject> centerYResObj;
606         if (centerProperty->IsObject()) {
607             auto centerJson = JSRef<JSObject>::Cast(centerProperty);
608             ParseAnnulusCenter(centerJson, center, centerXResObj, centerYResObj);
609         }
610         CalcDimension innerRadiusValue;
611         RefPtr<ResourceObject> innerRadiusResObj;
612         if (SystemProperties::ConfigChangePerform()) {
613             JSViewAbstract::ParseLengthMetricsToDimension(
614                 annulusRegion->GetProperty("innerRadius"), innerRadiusValue, innerRadiusResObj);
615         } else {
616             JSViewAbstract::ParseLengthMetricsToDimension(
617                 annulusRegion->GetProperty("innerRadius"), innerRadiusValue);
618         }
619         CalcDimension outerRadiusValue;
620         RefPtr<ResourceObject> outerRadiusResObj;
621         if (SystemProperties::ConfigChangePerform()) {
622             JSViewAbstract::ParseLengthMetricsToDimension(
623                 annulusRegion->GetProperty("outerRadius"), outerRadiusValue, outerRadiusResObj);
624         } else {
625             JSViewAbstract::ParseLengthMetricsToDimension(
626                 annulusRegion->GetProperty("outerRadius"), outerRadiusValue);
627         }
628         auto startAngle = annulusRegion->GetProperty("startAngle");
629         auto startAngleValue = startAngle->IsNumber() ? startAngle->ToNumber<float>() : DEFAULT_START_ANGLE_VALUE;
630         auto endAngle = annulusRegion->GetProperty("endAngle");
631         auto endAngleValue = endAngle->IsNumber() ? endAngle->ToNumber<float>() : DEFAULT_END_ANGLE_VALUE;
632         auto annulusRegionValue =
633             NG::ParticleAnnulusRegion(center, innerRadiusValue, outerRadiusValue, startAngleValue, endAngleValue);
634         if (SystemProperties::ConfigChangePerform()) {
635             AnnulusRegisterResourceObject(annulusRegionValue, centerXResObj,
636                 centerYResObj, innerRadiusResObj, outerRadiusResObj);
637         }
638         emitterOption.SetAnnulusRegion(annulusRegionValue);
639     }
640 }
641 
ParseParticleObject(JSRef<JSObject> & particleJsObject,OHOS::Ace::NG::Particle & particle)642 bool ParseParticleObject(JSRef<JSObject>& particleJsObject, OHOS::Ace::NG::Particle& particle)
643 {
644     auto typeJsValue = particleJsObject->GetProperty("type");
645     auto typeValue = NG::ParticleType::POINT;
646     if (typeJsValue->IsNumber()) {
647         auto typeIntValue = typeJsValue->ToNumber<int32_t>();
648         if (typeIntValue >= static_cast<int32_t>(NG::ParticleType::POINT) &&
649             typeIntValue <= static_cast<int32_t>(NG::ParticleType::IMAGE)) {
650             typeValue = static_cast<NG::ParticleType>(typeIntValue);
651         }
652     }
653     particle.SetParticleType(typeValue);
654 
655     auto configJsValue = particleJsObject->GetProperty("config");
656     if (!configJsValue->IsObject()) {
657         return false;
658     }
659     auto configJsObject = JSRef<JSObject>::Cast(configJsValue);
660     if (typeValue == NG::ParticleType::IMAGE) {
661         bool result = ParseImageParticleObject(configJsObject, particle);
662         if (!result) {
663             return false;
664         }
665     } else {
666         auto radiusJsValue = configJsObject->GetProperty("radius");
667         CalcDimension radius;
668         JSParticle::ParseJsDimensionVp(radiusJsValue, radius);
669         NG::PointParticleParameter pointParameter;
670         pointParameter.SetRadius(!radius.IsNonPositive() ? radius.ConvertToPx() : 0.0f);
671         NG::ParticleConfig particleConfig;
672         particleConfig.SetPointParticleParameter(pointParameter);
673         particle.SetConfig(particleConfig);
674     }
675 
676     auto count = 0;
677     auto countJsValue = particleJsObject->GetProperty("count");
678     if (countJsValue->IsNumber()) {
679         auto countIntValue = countJsValue->ToNumber<int32_t>();
680         if (countIntValue >= -1) {
681             count = countIntValue;
682         }
683     }
684     particle.SetCount(count);
685 
686     int64_t lifeTime = 1000;
687     auto lifeTimeJsValue = particleJsObject->GetProperty("lifetime");
688     if (lifeTimeJsValue->IsNumber()) {
689         auto lifeTimeIntValue = lifeTimeJsValue->ToNumber<int64_t>();
690         if (lifeTimeIntValue >= -1) {
691             lifeTime = lifeTimeIntValue;
692         }
693     }
694     particle.SetLifeTime(lifeTime);
695     int64_t lifeTimeRange = 0;
696     auto lifeTimeRangeJsValue = particleJsObject->GetProperty("lifetimeRange");
697     if (lifeTimeRangeJsValue->IsNumber()) {
698         auto lifeTimeRangeIntValue = lifeTimeRangeJsValue->ToNumber<int64_t>();
699         if (lifeTimeRangeIntValue >= 0) {
700             lifeTimeRange = lifeTimeRangeIntValue;
701         }
702     }
703     particle.SetLifeTimeRange(lifeTimeRange);
704     return true;
705 }
706 
PositionAddResIfNeed(CalcDimension & xValue,CalcDimension & yValue,JSRef<JSArray> & positionJsArray,OHOS::Ace::NG::EmitterOption & emitterOption)707 void PositionAddResIfNeed(CalcDimension& xValue, CalcDimension& yValue,
708     JSRef<JSArray>& positionJsArray, OHOS::Ace::NG::EmitterOption& emitterOption)
709 {
710     if (SystemProperties::ConfigChangePerform()) {
711         RefPtr<ResourceObject> positionXResObj;
712         RefPtr<ResourceObject> positionYResObj;
713         JSParticle::ParseJsDimensionVp(positionJsArray->GetValueAt(0), xValue, positionXResObj);
714         JSParticle::ParseJsDimensionVp(positionJsArray->GetValueAt(1), yValue, positionYResObj);
715         if (positionXResObj) {
716             auto&& positionXUpdateFunc =
717                 [](const RefPtr<ResourceObject>& resobjX, OHOS::Ace::NG::EmitterOption& emitterOption) {
718                 CalcDimension positionXValue(0.0);
719                 ResourceParseUtils::ParseResDimensionVpNG(resobjX, positionXValue);
720                 emitterOption.SetPositionX(positionXValue);
721             };
722             emitterOption.AddResource("emitterOption.positionX",
723                 positionXResObj, std::move(positionXUpdateFunc));
724         } else {
725             emitterOption.RemoveResource("emitterOption.positionX");
726         }
727         if (positionYResObj) {
728             auto&& positionYUpdateFunc =
729                 [](const RefPtr<ResourceObject>& resobjY, OHOS::Ace::NG::EmitterOption& emitterOption) {
730                 CalcDimension positionYValue(0.0);
731                 ResourceParseUtils::ParseResDimensionVpNG(resobjY, positionYValue);
732                 emitterOption.SetPositionY(positionYValue);
733             };
734             emitterOption.AddResource("emitterOption.positionY",
735                 positionYResObj, std::move(positionYUpdateFunc));
736         } else {
737             emitterOption.RemoveResource("emitterOption.positionY");
738         }
739     } else {
740         JSParticle::ParseJsDimensionVp(positionJsArray->GetValueAt(0), xValue);
741         JSParticle::ParseJsDimensionVp(positionJsArray->GetValueAt(1), yValue);
742     }
743 }
744 
ParseEmitterOptionPosition(JSRef<JSObject> & emitterJsObject,OHOS::Ace::NG::EmitterOption & emitterOption)745 void ParseEmitterOptionPosition(JSRef<JSObject>& emitterJsObject, OHOS::Ace::NG::EmitterOption& emitterOption)
746 {
747     auto positionJsValue = emitterJsObject->GetProperty("position");
748     CalcDimension xValue(0.0);
749     CalcDimension yValue(0.0);
750     if (positionJsValue->IsArray()) {
751         auto positionJsArray = JSRef<JSArray>::Cast(positionJsValue);
752         if (positionJsArray->Length() == ARRAY_SIZE) {
753             PositionAddResIfNeed(xValue, yValue, positionJsArray, emitterOption);
754         }
755     }
756     auto positionValue = std::pair<Dimension, Dimension>(xValue, yValue);
757     emitterOption.SetPosition(positionValue);
758 }
759 
ParseEmitterOption(JSRef<JSObject> & emitterJsObject,OHOS::Ace::NG::EmitterOption & emitterOption)760 bool ParseEmitterOption(JSRef<JSObject>& emitterJsObject, OHOS::Ace::NG::EmitterOption& emitterOption)
761 {
762     auto particleJsValue = emitterJsObject->GetProperty("particle");
763     if (!particleJsValue->IsObject()) {
764         return false;
765     }
766     auto particleJsObject = JSRef<JSObject>::Cast(particleJsValue);
767     OHOS::Ace::NG::Particle particle;
768     if (!ParseParticleObject(particleJsObject, particle)) {
769         return false;
770     }
771     emitterOption.SetParticle(particle);
772     int32_t emitRate = PARTICLE_DEFAULT_EMITTER_RATE;
773     auto emitRateJsValue = emitterJsObject->GetProperty("emitRate");
774     if (emitRateJsValue->IsNumber()) {
775         emitRate = emitRateJsValue->ToNumber<int32_t>() >= 0 ? emitRateJsValue->ToNumber<int32_t>() : emitRate;
776     }
777     emitterOption.SetEmitterRate(emitRate);
778 
779     auto emitShape = OHOS::Ace::NG::ParticleEmitterShape::RECTANGLE;
780     auto emitShapeJsValue = emitterJsObject->GetProperty("shape");
781     if (emitShapeJsValue->IsNumber()) {
782         auto emitShapeInt = emitShapeJsValue->ToNumber<int32_t>();
783         if (emitShapeInt >= static_cast<int32_t>(OHOS::Ace::NG::ParticleEmitterShape::RECTANGLE) &&
784             emitShapeInt <= static_cast<int32_t>(OHOS::Ace::NG::ParticleEmitterShape::ANNULUS)) {
785             emitShape = static_cast<OHOS::Ace::NG::ParticleEmitterShape>(emitShapeInt);
786         }
787     }
788     emitterOption.SetShape(emitShape);
789     ParseEmitterOptionPosition(emitterJsObject, emitterOption);
790     auto width = Dimension(1.0, DimensionUnit::PERCENT);
791     auto height = Dimension(1.0, DimensionUnit::PERCENT);
792     auto sizeValue = std::pair<Dimension, Dimension>(width, height);
793     auto sizeJsValue = emitterJsObject->GetProperty("size");
794     if (SystemProperties::ConfigChangePerform()) {
795         ParseSize(sizeValue, sizeJsValue, emitterOption);
796     } else {
797         ParseSize(sizeValue, sizeJsValue);
798     }
799     emitterOption.SetSize(sizeValue);
800     ParseEmitterOptionAnnulus(emitterJsObject, emitterOption);
801     return true;
802 }
803 
FromAddResIfNeed(Color & from,JSRef<JSVal> & fromJsValue,NG::ParticlePropertyAnimation<Color> & colorPropertyAnimation,int i)804 void FromAddResIfNeed(Color& from, JSRef<JSVal>& fromJsValue,
805     NG::ParticlePropertyAnimation<Color>& colorPropertyAnimation, int i)
806 {
807     if (SystemProperties::ConfigChangePerform()) {
808         RefPtr<ResourceObject> fromResObj;
809         JSParticle::ParseJsColor(fromJsValue, from, fromResObj);
810         std::string key = "ParticlePropertyAnimation.from." + std::to_string(i);
811         if (fromResObj) {
812             auto&& fromUpdateFunc = [](const RefPtr<ResourceObject>& fromResObj,
813                 NG::ParticlePropertyAnimation<Color>& colorPropertyAnimation) {
814                 Color colorFirstValue(DEFAULT_COLOR);
815                 ResourceParseUtils::ParseResColor(fromResObj, colorFirstValue);
816                 colorPropertyAnimation.SetFrom(colorFirstValue);
817             };
818             colorPropertyAnimation.AddResource(key, fromResObj, std::move(fromUpdateFunc));
819         } else {
820             colorPropertyAnimation.RemoveResource(key);
821         }
822     } else {
823         JSParticle::ParseJsColor(fromJsValue, from);
824     }
825 }
826 
ToAddResIfNeed(Color & to,JSRef<JSVal> & toJsValue,NG::ParticlePropertyAnimation<Color> & colorPropertyAnimation,int i)827 void ToAddResIfNeed(Color& to, JSRef<JSVal>& toJsValue,
828     NG::ParticlePropertyAnimation<Color>& colorPropertyAnimation, int i)
829 {
830     if (SystemProperties::ConfigChangePerform()) {
831         RefPtr<ResourceObject> toResObj;
832         JSParticle::ParseJsColor(toJsValue, to, toResObj);
833         std::string key = "ParticlePropertyAnimation.to." + std::to_string(i);
834         if (toResObj) {
835             auto&& toUpdateFunc = [](const RefPtr<ResourceObject>& toResObj,
836                 OHOS::Ace::NG::ParticlePropertyAnimation<Color>& colorPropertyAnimation) {
837                 Color colorSecondValue(DEFAULT_COLOR);
838                 ResourceParseUtils::ParseResColor(toResObj, colorSecondValue);
839                 colorPropertyAnimation.SetTo(colorSecondValue);
840             };
841             colorPropertyAnimation.AddResource(key, toResObj, std::move(toUpdateFunc));
842         } else {
843             colorPropertyAnimation.RemoveResource(key);
844         }
845     } else {
846         JSParticle::ParseJsColor(toJsValue, to);
847     }
848 }
849 
ParseAnimationColorArray(JSRef<JSArray> & curveConfigJsArray,std::list<NG::ParticlePropertyAnimation<Color>> & particleAnimationColorArray)850 void ParseAnimationColorArray(
851     JSRef<JSArray>& curveConfigJsArray, std::list<NG::ParticlePropertyAnimation<Color>>& particleAnimationColorArray)
852 {
853     auto arraySize = static_cast<int32_t>(curveConfigJsArray->Length());
854     for (int i = 0; i < arraySize; i++) {
855         auto arrayItemJsValue = curveConfigJsArray->GetValueAt(i);
856         NG::ParticlePropertyAnimation<Color> colorPropertyAnimation;
857         if (!arrayItemJsValue->IsObject()) {
858             continue;
859         }
860         auto arrayItemJsObject = JSRef<JSObject>::Cast(arrayItemJsValue);
861         auto fromJsValue = arrayItemJsObject->GetProperty("from");
862         Color from(DEFAULT_COLOR);
863         FromAddResIfNeed(from, fromJsValue, colorPropertyAnimation, i);
864         colorPropertyAnimation.SetFrom(from);
865         auto toJsValue = arrayItemJsObject->GetProperty("to");
866         Color to(DEFAULT_COLOR);
867         ToAddResIfNeed(to, toJsValue, colorPropertyAnimation, i);
868         colorPropertyAnimation.SetTo(to);
869         auto startMillisJsValue = arrayItemJsObject->GetProperty("startMillis");
870         auto startMillis = static_cast<int32_t>(0);
871         if (!JSParticle::ParseJsInt32(startMillisJsValue, startMillis) || startMillis < 0) {
872             startMillis = 0;
873         }
874         colorPropertyAnimation.SetStartMills(startMillis);
875         auto endMillisJsValue = arrayItemJsObject->GetProperty("endMillis");
876         auto endMillis = static_cast<int32_t>(0);
877         if (!JSParticle::ParseJsInt32(endMillisJsValue, endMillis) || endMillis < 0) {
878             endMillis = 0;
879         }
880         colorPropertyAnimation.SetEndMills(endMillis);
881         auto curveJsValue = arrayItemJsObject->GetProperty("curve");
882         auto curve = ParseCurve(curveJsValue);
883         if (curve) {
884             colorPropertyAnimation.SetCurve(curve);
885         }
886         particleAnimationColorArray.emplace_back(colorPropertyAnimation);
887     }
888 }
889 
ParseColorRandomUpdater(JSRef<JSVal> configJsValue,OHOS::Ace::NG::ParticleColorPropertyUpdater & updater)890 void ParseColorRandomUpdater(JSRef<JSVal> configJsValue, OHOS::Ace::NG::ParticleColorPropertyUpdater& updater)
891 {
892     NG::ParticleColorPropertyUpdaterConfig randomUpdaterConfig;
893     NG::ColorParticleRandomUpdateConfig colorRandomConfig;
894     if (!configJsValue->IsObject()) {
895         auto defaultPair = std::pair<float, float>(0.0f, 0.0f);
896         colorRandomConfig.SetRedRandom(defaultPair);
897         colorRandomConfig.SetGreenRandom(defaultPair);
898         colorRandomConfig.SetBlueRandom(defaultPair);
899         colorRandomConfig.SetAlphaRandom(defaultPair);
900         randomUpdaterConfig.SetRandomConfig(colorRandomConfig);
901         updater.SetConfig(randomUpdaterConfig);
902         return;
903     }
904     auto randomConfigJsObject = JSRef<JSObject>::Cast(configJsValue);
905     auto rJsValue = randomConfigJsObject->GetProperty("r");
906     auto gJsValue = randomConfigJsObject->GetProperty("g");
907     auto bJsValue = randomConfigJsObject->GetProperty("b");
908     auto aJsValue = randomConfigJsObject->GetProperty("a");
909     std::pair<float, float> defaultPair(0.0f, 0.0f);
910     auto rRangeValue = ParseParticleRange(rJsValue, 0.0f);
911     auto gRangeValue = ParseParticleRange(gJsValue, 0.0f);
912     auto bRangeValue = ParseParticleRange(bJsValue, 0.0f);
913     auto aRangeValue = ParseParticleRange(aJsValue, 0.0f);
914     colorRandomConfig.SetRedRandom(rRangeValue.value_or(defaultPair));
915     colorRandomConfig.SetGreenRandom(gRangeValue.value_or(defaultPair));
916     colorRandomConfig.SetBlueRandom(bRangeValue.value_or(defaultPair));
917     colorRandomConfig.SetAlphaRandom(aRangeValue.value_or(defaultPair));
918     randomUpdaterConfig.SetRandomConfig(colorRandomConfig);
919     updater.SetConfig(randomUpdaterConfig);
920 }
921 
ParseColorCurveUpdater(JSRef<JSVal> configJsValue,OHOS::Ace::NG::ParticleColorPropertyUpdater & updater)922 void ParseColorCurveUpdater(JSRef<JSVal> configJsValue, OHOS::Ace::NG::ParticleColorPropertyUpdater& updater)
923 {
924     std::list<NG::ParticlePropertyAnimation<Color>> particleAnimationColorArray;
925     NG::ParticleColorPropertyUpdaterConfig randomUpdaterConfig;
926     if (!configJsValue->IsArray()) {
927         randomUpdaterConfig.SetAnimationArray(particleAnimationColorArray);
928         updater.SetConfig(randomUpdaterConfig);
929         return;
930     }
931     auto curveConfigJsArray = JSRef<JSArray>::Cast(configJsValue);
932     ParseAnimationColorArray(curveConfigJsArray, particleAnimationColorArray);
933     randomUpdaterConfig.SetAnimationArray(particleAnimationColorArray);
934     updater.SetConfig(randomUpdaterConfig);
935 }
936 
ParseColorUpdater(JSRef<JSObject> & updaterJsObject,OHOS::Ace::NG::ParticleColorPropertyUpdater & updater)937 bool ParseColorUpdater(JSRef<JSObject>& updaterJsObject, OHOS::Ace::NG::ParticleColorPropertyUpdater& updater)
938 {
939     auto typeJsValue = updaterJsObject->GetProperty("type");
940     if (typeJsValue->IsNumber()) {
941         auto typeIntValue = typeJsValue->ToNumber<int32_t>();
942         if (typeIntValue < NG::UpdaterType::NONE_UPDATER || typeIntValue > NG::UpdaterType::CURVE) {
943             typeIntValue = NG::UpdaterType::NONE_UPDATER;
944         }
945         auto type = static_cast<NG::UpdaterType>(typeIntValue);
946         updater.SetUpdateType(type);
947         auto configJsValue = updaterJsObject->GetProperty("config");
948         if (type == NG::UpdaterType::RANDOM) {
949             ParseColorRandomUpdater(configJsValue, updater);
950             return true;
951         } else if (type == NG::UpdaterType::CURVE) {
952             ParseColorCurveUpdater(configJsValue, updater);
953             return true;
954         }
955     }
956     return false;
957 }
958 
ParseColorInitRange(JSRef<JSVal> colorRangeJsValue,OHOS::Ace::NG::ParticleColorPropertyOption & colorOption)959 void ParseColorInitRange(JSRef<JSVal> colorRangeJsValue, OHOS::Ace::NG::ParticleColorPropertyOption& colorOption)
960 {
961     Color fromColor(DEFAULT_COLOR);
962     Color toColor(DEFAULT_COLOR);
963     auto defaultRange = std::pair<Color, Color>(fromColor, toColor);
964     if (!colorRangeJsValue->IsArray()) {
965         colorOption.SetRange(defaultRange);
966         return;
967     }
968     auto colorRangeJsArray = JSRef<JSArray>::Cast(colorRangeJsValue);
969     if (static_cast<int32_t>(colorRangeJsArray->Length()) != ARRAY_SIZE) {
970         colorOption.SetRange(defaultRange);
971         return;
972     }
973     if (SystemProperties::ConfigChangePerform()) {
974         RefPtr<ResourceObject> fromColorResObj;
975         RefPtr<ResourceObject> toColorResObj;
976         JSParticle::ParseJsColor(colorRangeJsArray->GetValueAt(0), fromColor, fromColorResObj);
977         JSParticle::ParseJsColor(colorRangeJsArray->GetValueAt(1), toColor, toColorResObj);
978         if (fromColorResObj) {
979             auto&& fromColorUpdateFunc = [](const RefPtr<ResourceObject>& fromColorResObj,
980                 OHOS::Ace::NG::ParticleColorPropertyOption& colorOption) {
981                 Color colorFirstValue(DEFAULT_COLOR);
982                 ResourceParseUtils::ParseResColor(fromColorResObj, colorFirstValue);
983                 colorOption.SetRangeFirst(colorFirstValue);
984             };
985             colorOption.AddResource("range.fromColor", fromColorResObj, std::move(fromColorUpdateFunc));
986         } else {
987             colorOption.RemoveResource("range.fromColor");
988         }
989         if (toColorResObj) {
990             auto&& toColorUpdateFunc = [](const RefPtr<ResourceObject>& toColorResObj,
991                 OHOS::Ace::NG::ParticleColorPropertyOption& colorOption) {
992                 Color colorSecondValue(DEFAULT_COLOR);
993                 ResourceParseUtils::ParseResColor(toColorResObj, colorSecondValue);
994                 colorOption.SetRangeSecond(colorSecondValue);
995             };
996             colorOption.AddResource("range.toColor", toColorResObj, std::move(toColorUpdateFunc));
997         } else {
998             colorOption.RemoveResource("range.toColor");
999         }
1000     } else {
1001         JSParticle::ParseJsColor(colorRangeJsArray->GetValueAt(0), fromColor);
1002         JSParticle::ParseJsColor(colorRangeJsArray->GetValueAt(1), toColor);
1003     }
1004     auto range = std::pair<Color, Color>(fromColor, toColor);
1005     colorOption.SetRange(range);
1006 }
1007 
ParseColorOption(JSRef<JSObject> & colorJsObject,OHOS::Ace::NG::ParticleColorPropertyOption & colorOption)1008 void ParseColorOption(JSRef<JSObject>& colorJsObject, OHOS::Ace::NG::ParticleColorPropertyOption& colorOption)
1009 {
1010     auto colorRangeJsValue = colorJsObject->GetProperty("range");
1011     ParseColorInitRange(colorRangeJsValue, colorOption);
1012 
1013     auto colorDist = OHOS::Ace::NG::DistributionType::UNIFORM;
1014     auto colorDistJsValue = colorJsObject->GetProperty("distributionType");
1015     if (colorDistJsValue->IsNumber()) {
1016         auto colorDistInt = colorDistJsValue->ToNumber<int32_t>();
1017         if (colorDistInt >= static_cast<int32_t>(OHOS::Ace::NG::DistributionType::UNIFORM) &&
1018             colorDistInt <= static_cast<int32_t>(OHOS::Ace::NG::DistributionType::GAUSSIAN)) {
1019             colorDist = static_cast<OHOS::Ace::NG::DistributionType>(colorDistInt);
1020         }
1021     }
1022     colorOption.SetDistribution(colorDist);
1023 
1024     auto updaterJsValue = colorJsObject->GetProperty("updater");
1025     NG::ParticleColorPropertyUpdater updater;
1026     if (updaterJsValue->IsObject()) {
1027         auto updaterJsObject = JSRef<JSObject>::Cast(updaterJsValue);
1028         if (ParseColorUpdater(updaterJsObject, updater)) {
1029             colorOption.SetUpdater(updater);
1030             return;
1031         }
1032     }
1033     updater.SetUpdateType(NG::UpdaterType::NONE_UPDATER);
1034     NG::ParticleColorPropertyUpdaterConfig noneUpdaterConfig;
1035     noneUpdaterConfig.SetInValid(0);
1036     updater.SetConfig(noneUpdaterConfig);
1037     colorOption.SetUpdater(updater);
1038 }
1039 
ParseParticleVelocity(JSRef<JSVal> jsValue,OHOS::Ace::NG::VelocityProperty & velocity)1040 void ParseParticleVelocity(JSRef<JSVal> jsValue, OHOS::Ace::NG::VelocityProperty& velocity)
1041 {
1042     auto defaultPair = std::pair<float, float>(0.0f, 0.0f);
1043     if (!jsValue->IsObject()) {
1044         velocity.SetSpeedRange(defaultPair);
1045         velocity.SetAngleRange(defaultPair);
1046         return;
1047     }
1048     auto jsValueObj = JSRef<JSObject>::Cast(jsValue);
1049     auto speedJsValue = jsValueObj->GetProperty("speed");
1050     auto angleJsValue = jsValueObj->GetProperty("angle");
1051     auto speedPair = ParseParticleRange(speedJsValue, 0.0f);
1052     if (speedPair.has_value()) {
1053         velocity.SetSpeedRange(speedPair.value());
1054     } else {
1055         velocity.SetSpeedRange(defaultPair);
1056     }
1057     auto anglePair = ParseParticleRange(angleJsValue, 0.0f);
1058     if (anglePair.has_value()) {
1059         velocity.SetAngleRange(anglePair.value());
1060     } else {
1061         velocity.SetAngleRange(defaultPair);
1062     }
1063 }
1064 
ParseParticleAcceleration(JSRef<JSVal> jsValue,OHOS::Ace::NG::AccelerationProperty & acceleration)1065 void ParseParticleAcceleration(JSRef<JSVal> jsValue, OHOS::Ace::NG::AccelerationProperty& acceleration)
1066 {
1067     if (!jsValue->IsObject()) {
1068         return;
1069     }
1070     auto jsValueObj = JSRef<JSObject>::Cast(jsValue);
1071     auto speedValue = jsValueObj->GetProperty("speed");
1072     auto alphaValue = jsValueObj->GetProperty("angle");
1073     OHOS::Ace::NG::ParticleFloatPropertyOption speedOption;
1074     if (speedValue->IsObject()) {
1075         auto speedObject = JSRef<JSObject>::Cast(speedValue);
1076         ParseFloatOption(speedObject, speedOption, DEFAULT_SPEED, MIN_SPEED, MAX_SPEED);
1077         acceleration.SetSpeed(speedOption);
1078     }
1079     OHOS::Ace::NG::ParticleFloatPropertyOption angleOption;
1080     if (alphaValue->IsObject()) {
1081         auto alphaObject = JSRef<JSObject>::Cast(alphaValue);
1082         ParseFloatOption(alphaObject, angleOption, DEFAULT_ANGLE, MIN_ANGLE, MAX_ANGLE);
1083         acceleration.SetAngle(angleOption);
1084     }
1085 }
1086 
ParseParticleOption(JSRef<JSObject> & particleJsObj,OHOS::Ace::NG::ParticleOption & particleOption)1087 bool ParseParticleOption(JSRef<JSObject>& particleJsObj, OHOS::Ace::NG::ParticleOption& particleOption)
1088 {
1089     auto emitterJsValue = particleJsObj->GetProperty("emitter");
1090     if (!emitterJsValue->IsObject()) {
1091         return false;
1092     }
1093 
1094     auto emitterJsObj = JSRef<JSObject>::Cast(emitterJsValue);
1095     OHOS::Ace::NG::EmitterOption emitterOption;
1096     if (!ParseEmitterOption(emitterJsObj, emitterOption)) {
1097         return false;
1098     }
1099 
1100     particleOption.SetEmitterOption(emitterOption);
1101     auto colorJsValue = particleJsObj->GetProperty("color");
1102     if (colorJsValue->IsObject()) {
1103         auto colorJsObj = JSRef<JSObject>::Cast(colorJsValue);
1104         OHOS::Ace::NG::ParticleColorPropertyOption colorOption;
1105         ParseColorOption(colorJsObj, colorOption);
1106         particleOption.SetParticleColorOption(colorOption);
1107     }
1108 
1109     auto opacityJsValue = particleJsObj->GetProperty("opacity");
1110     if (opacityJsValue->IsObject()) {
1111         auto opacityJsObj = JSRef<JSObject>::Cast(opacityJsValue);
1112         OHOS::Ace::NG::ParticleFloatPropertyOption opacityOption;
1113         ParseFloatOption(opacityJsObj, opacityOption, DEFAULT_OPACITY, MIN_OPACITY, MAX_OPACITY);
1114         particleOption.SetParticleOpacityOption(opacityOption);
1115     }
1116 
1117     auto scaleJsValue = particleJsObj->GetProperty("scale");
1118     if (scaleJsValue->IsObject()) {
1119         auto scaleJsObj = JSRef<JSObject>::Cast(scaleJsValue);
1120         OHOS::Ace::NG::ParticleFloatPropertyOption scaleOption;
1121         ParseFloatOption(scaleJsObj, scaleOption, DEFAULT_SCALE, MIN_SCALE, MAX_SCALE);
1122         particleOption.SetParticleScaleOption(scaleOption);
1123     }
1124 
1125     auto velocityJsValue = particleJsObj->GetProperty("velocity");
1126     OHOS::Ace::NG::VelocityProperty velocity;
1127     ParseParticleVelocity(velocityJsValue, velocity);
1128     particleOption.SetParticleVelocityOption(velocity);
1129 
1130     auto accelerationJsValue = particleJsObj->GetProperty("acceleration");
1131     OHOS::Ace::NG::AccelerationProperty acceleration;
1132     ParseParticleAcceleration(accelerationJsValue, acceleration);
1133     particleOption.SetParticleAccelerationOption(acceleration);
1134 
1135     auto spinJsValue = particleJsObj->GetProperty("spin");
1136     if (spinJsValue->IsObject()) {
1137         auto spinJsObj = JSRef<JSObject>::Cast(spinJsValue);
1138         OHOS::Ace::NG::ParticleFloatPropertyOption spinOption;
1139         ParseFloatOption(spinJsObj, spinOption, DEFAULT_SPIN, MIN_SPIN, MAX_SPIN);
1140         particleOption.SetParticleSpinOption(spinOption);
1141     }
1142     return true;
1143 }
1144 
ParseParticleArray(JSRef<JSArray> & paramArray,std::list<OHOS::Ace::NG::ParticleOption> & arrayValue)1145 void ParseParticleArray(JSRef<JSArray>& paramArray, std::list<OHOS::Ace::NG::ParticleOption>& arrayValue)
1146 {
1147     for (size_t i = 0; i < paramArray->Length(); i++) {
1148         if (!paramArray->GetValueAt(i)->IsObject()) {
1149             continue;
1150         }
1151         OHOS::Ace::NG::ParticleOption option;
1152         auto particleJsObj = JSRef<JSObject>::Cast(paramArray->GetValueAt(i));
1153         if (!ParseParticleOption(particleJsObj, option)) {
1154             continue;
1155         }
1156         arrayValue.emplace_back(option);
1157     }
1158 }
1159 } // namespace
Create(const JSCallbackInfo & args)1160 void JSParticle::Create(const JSCallbackInfo& args)
1161 {
1162     if (args.Length() < 1) {
1163         return;
1164     }
1165     std::list<OHOS::Ace::NG::ParticleOption> arrayValue;
1166     if (args[0]->IsObject()) {
1167         JSRef<JSObject> paramObj = JSRef<JSObject>::Cast(args[0]);
1168         auto particlesJsArray = paramObj->GetProperty("particles");
1169         if (particlesJsArray->IsArray()) {
1170             auto paramArray = JSRef<JSArray>::Cast(particlesJsArray);
1171             ParseParticleArray(paramArray, arrayValue);
1172         }
1173     }
1174     ParticleModel::GetInstance()->Create(arrayValue);
1175 }
AddDisturbance(std::vector<OHOS::Ace::ParticleDisturbance> & dataArray,const JSRef<JSObject> & paramObj)1176 void JSParticle::AddDisturbance(std::vector<OHOS::Ace::ParticleDisturbance>& dataArray, const JSRef<JSObject>& paramObj)
1177 {
1178     float strength = paramObj->GetProperty("strength")->ToNumber<float>();
1179     int shape = paramObj->GetProperty("shape")->ToNumber<int>();
1180     int sizeXValue = 0;
1181     int sizeYValue = 0;
1182     int positionXValue = 0;
1183     int positionYValue = 0;
1184     GetSizeAndPositionValues(paramObj, sizeXValue, sizeYValue, positionXValue, positionYValue);
1185     int feather = paramObj->GetProperty("feather")->ToNumber<int>();
1186     feather = std::clamp(feather, 0, 100);
1187     float noiseScale = 1.0f;
1188     if (paramObj->GetProperty("noiseScale")->IsNumber()) {
1189         noiseScale = paramObj->GetProperty("noiseScale")->ToNumber<float>();
1190         if (noiseScale < 0.0f) {
1191             noiseScale = 1.0f;
1192         }
1193     }
1194     float noiseFrequency = 1.0f;
1195     if (paramObj->GetProperty("noiseFrequency")->IsNumber()) {
1196         noiseFrequency = paramObj->GetProperty("noiseFrequency")->ToNumber<float>();
1197         if (noiseFrequency < 0.0f) {
1198             noiseFrequency = 1.0f;
1199         }
1200     }
1201     float noiseAmplitude = 1.0f;
1202     if (paramObj->GetProperty("noiseAmplitude")->IsNumber()) {
1203         noiseAmplitude = paramObj->GetProperty("noiseAmplitude")->ToNumber<float>();
1204         if (noiseAmplitude < 0.0f) {
1205             noiseAmplitude = 1.0f;
1206         }
1207     }
1208     ParticleDisturbance disturbanceField;
1209     disturbanceField.strength = strength;
1210     disturbanceField.shape = static_cast<ParticleDisturbanceShapeType>(shape);
1211     disturbanceField.size[0] = sizeXValue;
1212     disturbanceField.size[1] = sizeYValue;
1213     disturbanceField.position[0] = positionXValue;
1214     disturbanceField.position[1] = positionYValue;
1215     disturbanceField.feather = feather;
1216     disturbanceField.noiseScale = noiseScale;
1217     disturbanceField.noiseFrequency = noiseFrequency;
1218     disturbanceField.noiseAmplitude = noiseAmplitude;
1219     dataArray.push_back(disturbanceField);
1220 }
1221 
GetSizeAndPositionValues(const JSRef<JSObject> & paramObj,int & sizeXValue,int & sizeYValue,int & positionXValue,int & positionYValue)1222 void JSParticle::GetSizeAndPositionValues(
1223     const JSRef<JSObject>& paramObj, int& sizeXValue, int& sizeYValue, int& positionXValue, int& positionYValue)
1224 {
1225     JSRef<JSVal> sizeJsValue = paramObj->GetProperty("size");
1226     if (sizeJsValue->IsObject()) {
1227         JSRef<JSObject> sizeJsObject = JSRef<JSObject>::Cast(sizeJsValue);
1228         sizeXValue = sizeJsObject->GetProperty("width")->ToNumber<int>();
1229         sizeYValue = sizeJsObject->GetProperty("height")->ToNumber<int>();
1230     }
1231 
1232     JSRef<JSVal> positionJsValue = paramObj->GetProperty("position");
1233     if (positionJsValue->IsObject()) {
1234         JSRef<JSObject> positionJsObject = JSRef<JSObject>::Cast(positionJsValue);
1235         positionXValue = positionJsObject->GetProperty("x")->ToNumber<int>();
1236         positionYValue = positionJsObject->GetProperty("y")->ToNumber<int>();
1237     }
1238 }
1239 
JsDisturbanceFields(const JSCallbackInfo & args)1240 void JSParticle::JsDisturbanceFields(const JSCallbackInfo& args)
1241 {
1242     if (args.Length() != 1 || !args[0]->IsArray()) {
1243         return;
1244     }
1245     std::vector<ParticleDisturbance> dataArray;
1246     JSRef<JSArray> dataJsArray = JSRef<JSArray>::Cast(args[0]);
1247     for (size_t i = 0; i < dataJsArray->Length(); i++) {
1248         if (dataJsArray->GetValueAt(i)->IsObject()) {
1249             auto jsObject = JSRef<JSObject>::Cast(dataJsArray->GetValueAt(i));
1250             AddDisturbance(dataArray, jsObject);
1251         }
1252     }
1253 
1254     ParticleModel::GetInstance()->DisturbanceField(dataArray);
1255 }
1256 
ParseEmitterProperty(std::vector<OHOS::Ace::EmitterProperty> & data,const JSRef<JSObject> & paramObj)1257 void JSParticle::ParseEmitterProperty(
1258     std::vector<OHOS::Ace::EmitterProperty>& data, const JSRef<JSObject>& paramObj)
1259 {
1260     EmitterProperty emitterProperty;
1261     uint32_t index = 0u;
1262     if (paramObj->GetProperty("index")->IsNumber()) {
1263         uint32_t indexJsValue = paramObj->GetProperty("index")->ToNumber<uint32_t>();
1264         index = indexJsValue > 0 ? indexJsValue : 0;
1265     }
1266     emitterProperty.index = index;
1267 
1268     auto emitRateProperty = paramObj->GetProperty("emitRate");
1269     if (emitRateProperty->IsNumber()) {
1270         auto emitRateValue = emitRateProperty->ToNumber<int32_t>();
1271         emitterProperty.emitRate = emitRateValue >= 0 ? emitRateValue : PARTICLE_DEFAULT_EMITTER_RATE;
1272     }
1273     auto positionProperty = paramObj->GetProperty("position");
1274     if (positionProperty->IsObject()) {
1275         auto positionValue = Framework::JSRef<Framework::JSObject>::Cast(positionProperty);
1276         if (positionValue->GetProperty("x")->IsNumber() && positionValue->GetProperty("y")->IsNumber()) {
1277             auto positionXValue = positionValue->GetProperty("x")->ToNumber<float>();
1278             auto positonYValue = positionValue->GetProperty("y")->ToNumber<float>();
1279             emitterProperty.position = { positionXValue, positonYValue };
1280         }
1281     }
1282     auto sizeProperty = paramObj->GetProperty("size");
1283     if (sizeProperty->IsObject()) {
1284         auto sizeValue = Framework::JSRef<Framework::JSObject>::Cast(sizeProperty);
1285         auto sizeXValue = sizeValue->GetProperty("width")->ToNumber<float>();
1286         auto sizeYValue = sizeValue->GetProperty("height")->ToNumber<float>();
1287         if (sizeXValue > 0 && sizeYValue > 0) {
1288             emitterProperty.size = { sizeXValue, sizeYValue };
1289         }
1290     }
1291 
1292     ParseEmitterPropertyAnnulus(paramObj, emitterProperty);
1293     data.push_back(emitterProperty);
1294 }
1295 
JsEmitter(const JSCallbackInfo & args)1296 void JSParticle::JsEmitter(const JSCallbackInfo& args)
1297 {
1298     if (args.Length() != 1 || !args[0]->IsArray()) {
1299         return;
1300     }
1301     std::vector<EmitterProperty> dataArray;
1302     JSRef<JSArray> dataJsArray = JSRef<JSArray>::Cast(args[0]);
1303     size_t length = dataJsArray->Length();
1304     for (size_t i = 0; i < length; i++) {
1305         if (dataJsArray->GetValueAt(i)->IsObject()) {
1306             auto jsObject = JSRef<JSObject>::Cast(dataJsArray->GetValueAt(i));
1307             ParseEmitterProperty(dataArray, jsObject);
1308         }
1309     }
1310     ParticleModel::GetInstance()->updateEmitter(dataArray);
1311 }
1312 
JSBind(BindingTarget globalObj)1313 void JSParticle::JSBind(BindingTarget globalObj)
1314 {
1315     JSClass<JSParticle>::Declare("Particle");
1316     JSClass<JSParticle>::StaticMethod("create", &JSParticle::Create);
1317     JSClass<JSParticle>::StaticMethod("disturbanceFields", &JSParticle::JsDisturbanceFields);
1318     JSClass<JSParticle>::StaticMethod("emitter", &JSParticle::JsEmitter);
1319     JSClass<JSParticle>::InheritAndBind<JSViewAbstract>(globalObj);
1320 }
1321 } // namespace OHOS::Ace::Framework
1322