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