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