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