1 /*
2 * Copyright (c) 2024 the ThorVG project. All rights reserved.
3
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #include "../../lv_conf_internal.h"
24 #if LV_USE_THORVG_INTERNAL
25
26
27 #include "tvgMath.h"
28 #include "tvgCompressor.h"
29 #include "tvgLottieModel.h"
30 #include "tvgLottieExpressions.h"
31
32 #ifdef THORVG_LOTTIE_EXPRESSIONS_SUPPORT
33
34 /************************************************************************/
35 /* Internal Class Implementation */
36 /************************************************************************/
37
38 struct ExpContent
39 {
40 LottieExpression* exp;
41 LottieObject* obj;
42 float frameNo;
43 };
44
45 static jerry_value_t _content(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt);
46
47 //reserved expressions specifiers
48 static const char* EXP_NAME = "name";
49 static const char* EXP_CONTENT = "content";
50 static const char* EXP_WIDTH = "width";
51 static const char* EXP_HEIGHT = "height";
52 static const char* EXP_CYCLE = "cycle";
53 static const char* EXP_PINGPONG = "pingpong";
54 static const char* EXP_OFFSET = "offset";
55 static const char* EXP_CONTINUE = "continue";
56 static const char* EXP_TIME = "time";
57 static const char* EXP_VALUE = "value";
58 static const char* EXP_INDEX = "index";
59 static const char* EXP_EFFECT= "effect";
60
61 static LottieExpressions* exps = nullptr; //singleton instance engine
62
63
_expcontent(LottieExpression * exp,float frameNo,LottieObject * obj)64 static ExpContent* _expcontent(LottieExpression* exp, float frameNo, LottieObject* obj)
65 {
66 auto data = (ExpContent*)malloc(sizeof(ExpContent));
67 data->exp = exp;
68 data->frameNo = frameNo;
69 data->obj = obj;
70 return data;
71 }
72
73
contentFree(void * native_p,struct jerry_object_native_info_t * info_p)74 static void contentFree(void *native_p, struct jerry_object_native_info_t *info_p)
75 {
76 free(native_p);
77 }
78
79 static jerry_object_native_info_t freeCb {contentFree, 0, 0};
80 static uint32_t engineRefCnt = 0; //Expressions Engine reference count
81
82
_name(jerry_value_t args)83 static char* _name(jerry_value_t args)
84 {
85 auto arg0 = jerry_value_to_string(args);
86 auto len = jerry_string_length(arg0);
87 auto name = (jerry_char_t*)malloc(len * sizeof(jerry_char_t) + 1);
88 jerry_string_to_buffer(arg0, JERRY_ENCODING_UTF8, name, len);
89 name[len] = '\0';
90 jerry_value_free(arg0);
91 return (char*) name;
92 }
93
94
_idByName(jerry_value_t args)95 static unsigned long _idByName(jerry_value_t args)
96 {
97 auto name = _name(args);
98 auto id = djb2Encode(name);
99 free(name);
100 return id;
101 }
102
103
_toComp(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)104 static jerry_value_t _toComp(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
105 {
106 TVGLOG("LOTTIE", "toComp is not supported in expressions!");
107
108 return jerry_undefined();
109 }
110
111
_value(float frameNo,LottieProperty * property)112 static jerry_value_t _value(float frameNo, LottieProperty* property)
113 {
114 switch (property->type) {
115 case LottieProperty::Type::Point: {
116 auto value = jerry_object();
117 auto pos = (*static_cast<LottiePoint*>(property))(frameNo);
118 auto val1 = jerry_number(pos.x);
119 auto val2 = jerry_number(pos.y);
120 jerry_object_set_index(value, 0, val1);
121 jerry_object_set_index(value, 1, val2);
122 jerry_value_free(val1);
123 jerry_value_free(val2);
124 return value;
125 }
126 case LottieProperty::Type::Float: {
127 return jerry_number((*static_cast<LottieFloat*>(property))(frameNo));
128 }
129 case LottieProperty::Type::Opacity: {
130 return jerry_number((*static_cast<LottieOpacity*>(property))(frameNo));
131 }
132 case LottieProperty::Type::PathSet: {
133 auto value = jerry_object();
134 jerry_object_set_native_ptr(value, nullptr, property);
135 return value;
136 }
137 case LottieProperty::Type::Position: {
138 auto value = jerry_object();
139 auto pos = (*static_cast<LottiePosition*>(property))(frameNo);
140 auto val1 = jerry_number(pos.x);
141 auto val2 = jerry_number(pos.y);
142 jerry_object_set_index(value, 0, val1);
143 jerry_object_set_index(value, 1, val2);
144 jerry_value_free(val1);
145 jerry_value_free(val2);
146 return value;
147 }
148 default: {
149 TVGERR("LOTTIE", "Non supported type for value? = %d", (int) property->type);
150 }
151 }
152 return jerry_undefined();
153 }
154
155
_buildTransform(jerry_value_t context,float frameNo,LottieTransform * transform)156 static void _buildTransform(jerry_value_t context, float frameNo, LottieTransform* transform)
157 {
158 if (!transform) return;
159
160 auto obj = jerry_object();
161 jerry_object_set_sz(context, "transform", obj);
162
163 auto anchorPoint = _value(frameNo, &transform->anchor);
164 jerry_object_set_sz(obj, "anchorPoint", anchorPoint);
165 jerry_value_free(anchorPoint);
166
167 auto position = _value(frameNo, &transform->position);
168 jerry_object_set_sz(obj, "position", position);
169 jerry_value_free(position);
170
171 auto scale = _value(frameNo, &transform->scale);
172 jerry_object_set_sz(obj, "scale", scale);
173 jerry_value_free(scale);
174
175 auto rotation = _value(frameNo, &transform->rotation);
176 jerry_object_set_sz(obj, "rotation", rotation);
177 jerry_value_free(rotation);
178
179 auto opacity = _value(frameNo, &transform->opacity);
180 jerry_object_set_sz(obj, "opacity", opacity);
181 jerry_value_free(opacity);
182
183 jerry_value_free(obj);
184 }
185
186
_buildGroup(LottieGroup * group,float frameNo)187 static jerry_value_t _buildGroup(LottieGroup* group, float frameNo)
188 {
189 auto obj = jerry_function_external(_content);
190
191 //attach a transform
192 for (auto c = group->children.begin(); c < group->children.end(); ++c) {
193 if ((*c)->type == LottieObject::Type::Transform) {
194 _buildTransform(obj, frameNo, static_cast<LottieTransform*>(*c));
195 break;
196 }
197 }
198 jerry_object_set_native_ptr(obj, &freeCb, _expcontent(nullptr, frameNo, group));
199 jerry_object_set_sz(obj, EXP_CONTENT, obj);
200 return obj;
201 }
202
203
_buildPolystar(LottiePolyStar * polystar,float frameNo)204 static jerry_value_t _buildPolystar(LottiePolyStar* polystar, float frameNo)
205 {
206 auto obj = jerry_object();
207 auto position = jerry_object();
208 jerry_object_set_native_ptr(position, nullptr, &polystar->position);
209 jerry_object_set_sz(obj, "position", position);
210 jerry_value_free(position);
211 auto innerRadius = jerry_number(polystar->innerRadius(frameNo));
212 jerry_object_set_sz(obj, "innerRadius", innerRadius);
213 jerry_value_free(innerRadius);
214 auto outerRadius = jerry_number(polystar->outerRadius(frameNo));
215 jerry_object_set_sz(obj, "outerRadius", outerRadius);
216 jerry_value_free(outerRadius);
217 auto innerRoundness = jerry_number(polystar->innerRoundness(frameNo));
218 jerry_object_set_sz(obj, "innerRoundness", innerRoundness);
219 jerry_value_free(innerRoundness);
220 auto outerRoundness = jerry_number(polystar->outerRoundness(frameNo));
221 jerry_object_set_sz(obj, "outerRoundness", outerRoundness);
222 jerry_value_free(outerRoundness);
223 auto rotation = jerry_number(polystar->rotation(frameNo));
224 jerry_object_set_sz(obj, "rotation", rotation);
225 jerry_value_free(rotation);
226 auto ptsCnt = jerry_number(polystar->ptsCnt(frameNo));
227 jerry_object_set_sz(obj, "points", ptsCnt);
228 jerry_value_free(ptsCnt);
229
230 return obj;
231 }
232
233
_buildTrimpath(LottieTrimpath * trimpath,float frameNo)234 static jerry_value_t _buildTrimpath(LottieTrimpath* trimpath, float frameNo)
235 {
236 jerry_value_t obj = jerry_object();
237 auto start = jerry_number(trimpath->start(frameNo));
238 jerry_object_set_sz(obj, "start", start);
239 jerry_value_free(start);
240 auto end = jerry_number(trimpath->end(frameNo));
241 jerry_object_set_sz(obj, "end", end);
242 jerry_value_free(end);
243 auto offset = jerry_number(trimpath->offset(frameNo));
244 jerry_object_set_sz(obj, "offset", end);
245 jerry_value_free(offset);
246
247 return obj;
248 }
249
250
_buildLayer(jerry_value_t context,float frameNo,LottieLayer * layer,LottieLayer * comp,LottieExpression * exp)251 static void _buildLayer(jerry_value_t context, float frameNo, LottieLayer* layer, LottieLayer* comp, LottieExpression* exp)
252 {
253 auto width = jerry_number(layer->w);
254 jerry_object_set_sz(context, EXP_WIDTH, width);
255 jerry_value_free(width);
256
257 auto height = jerry_number(layer->h);
258 jerry_object_set_sz(context, EXP_HEIGHT, height);
259 jerry_value_free(height);
260
261 auto index = jerry_number(layer->idx);
262 jerry_object_set_sz(context, EXP_INDEX, index);
263 jerry_value_free(index);
264
265 auto parent = jerry_object();
266 jerry_object_set_native_ptr(parent, nullptr, layer->parent);
267 jerry_object_set_sz(context, "parent", parent);
268 jerry_value_free(parent);
269
270 auto hasParent = jerry_boolean(layer->parent ? true : false);
271 jerry_object_set_sz(context, "hasParent", hasParent);
272 jerry_value_free(hasParent);
273
274 auto inPoint = jerry_number(layer->inFrame);
275 jerry_object_set_sz(context, "inPoint", inPoint);
276 jerry_value_free(inPoint);
277
278 auto outPoint = jerry_number(layer->outFrame);
279 jerry_object_set_sz(context, "outPoint", outPoint);
280 jerry_value_free(outPoint);
281
282 //TODO: Confirm exp->layer->comp->timeAtFrame() ?
283 auto startTime = jerry_number(exp->comp->timeAtFrame(layer->startFrame));
284 jerry_object_set_sz(context, "startTime", startTime);
285 jerry_value_free(startTime);
286
287 auto hasVideo = jerry_boolean(false);
288 jerry_object_set_sz(context, "hasVideo", hasVideo);
289 jerry_value_free(hasVideo);
290
291 auto hasAudio = jerry_boolean(false);
292 jerry_object_set_sz(context, "hasAudio", hasAudio);
293 jerry_value_free(hasAudio);
294
295 //active, #current in the animation range?
296
297 auto enabled = jerry_boolean(!layer->hidden);
298 jerry_object_set_sz(context, "enabled", enabled);
299 jerry_value_free(enabled);
300
301 auto audioActive = jerry_boolean(false);
302 jerry_object_set_sz(context, "audioActive", audioActive);
303 jerry_value_free(audioActive);
304
305 //sampleImage(point, radius = [.5, .5], postEffect=true, t=time)
306
307 _buildTransform(context, frameNo, layer->transform);
308
309 //audioLevels, #the value of the Audio Levels property of the layer in decibels
310
311 auto timeRemap = jerry_object();
312 jerry_object_set_native_ptr(timeRemap, nullptr, &layer->timeRemap);
313 jerry_object_set_sz(context, "timeRemap", timeRemap);
314 jerry_value_free(timeRemap);
315
316 //marker.key(index)
317 //marker.key(name)
318 //marker.nearestKey(t)
319 //marker.numKeys
320
321 auto name = jerry_string_sz(layer->name);
322 jerry_object_set_sz(context, EXP_NAME, name);
323 jerry_value_free(name);
324
325 auto toComp = jerry_function_external(_toComp);
326 jerry_object_set_sz(context, "toComp", toComp);
327 jerry_object_set_native_ptr(toComp, nullptr, comp);
328 jerry_value_free(toComp);
329
330 //content("name"), #look for the named property from a layer
331 auto content = jerry_function_external(_content);
332 jerry_object_set_sz(context, EXP_CONTENT, content);
333 jerry_object_set_native_ptr(content, &freeCb, _expcontent(exp, frameNo, layer));
334 jerry_value_free(content);
335 }
336
337
_addsub(const jerry_value_t args[],float addsub)338 static jerry_value_t _addsub(const jerry_value_t args[], float addsub)
339 {
340 auto n1 = jerry_value_is_number(args[0]);
341 auto n2 = jerry_value_is_number(args[1]);
342
343 //1d + 1d
344 if (n1 && n2) return jerry_number(jerry_value_as_number(args[0]) + addsub * jerry_value_as_number(args[1]));
345
346 auto val1 = jerry_object_get_index(args[n1 ? 1 : 0], 0);
347 auto val2 = jerry_object_get_index(args[n1 ? 1 : 0], 1);
348 auto x = jerry_value_as_number(val1);
349 auto y = jerry_value_as_number(val2);
350 jerry_value_free(val1);
351 jerry_value_free(val2);
352
353 //2d + 1d
354 if (n1 || n2) {
355 auto secondary = n1 ? 0 : 1;
356 auto val3 = jerry_value_as_number(args[secondary]);
357 if (secondary == 0) x = (x * addsub) + val3;
358 else x += (addsub * val3);
359 //2d + 2d
360 } else {
361 auto val3 = jerry_object_get_index(args[1], 0);
362 auto val4 = jerry_object_get_index(args[1], 1);
363 x += (addsub * jerry_value_as_number(val3));
364 y += (addsub * jerry_value_as_number(val4));
365 jerry_value_free(val3);
366 jerry_value_free(val4);
367 }
368
369 auto obj = jerry_object();
370 val1 = jerry_number(x);
371 val2 = jerry_number(y);
372 jerry_object_set_index(obj, 0, val1);
373 jerry_object_set_index(obj, 1, val2);
374 jerry_value_free(val1);
375 jerry_value_free(val2);
376
377 return obj;
378 }
379
380
_muldiv(const jerry_value_t arg1,float arg2)381 static jerry_value_t _muldiv(const jerry_value_t arg1, float arg2)
382 {
383 //1d
384 if (jerry_value_is_number(arg1)) return jerry_number(jerry_value_as_number(arg1) * arg2);
385
386 //2d
387 auto val1 = jerry_object_get_index(arg1, 0);
388 auto val2 = jerry_object_get_index(arg1, 1);
389 auto x = jerry_value_as_number(val1) * arg2;
390 auto y = jerry_value_as_number(val2) * arg2;
391
392 jerry_value_free(val1);
393 jerry_value_free(val2);
394
395 auto obj = jerry_object();
396 val1 = jerry_number(x);
397 val2 = jerry_number(y);
398 jerry_object_set_index(obj, 0, val1);
399 jerry_object_set_index(obj, 1, val2);
400 jerry_value_free(val1);
401 jerry_value_free(val2);
402
403 return obj;
404 }
405
406
_add(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)407 static jerry_value_t _add(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
408 {
409 return _addsub(args, 1.0f);
410 }
411
412
_sub(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)413 static jerry_value_t _sub(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
414 {
415 return _addsub(args, -1.0f);
416 }
417
418
_mul(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)419 static jerry_value_t _mul(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
420 {
421 return _muldiv(args[0], jerry_value_as_number(args[1]));
422 }
423
424
_div(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)425 static jerry_value_t _div(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
426 {
427 return _muldiv(args[0], 1.0f / jerry_value_as_number(args[1]));
428 }
429
430
_interp(float t,const jerry_value_t args[],int argsCnt)431 static jerry_value_t _interp(float t, const jerry_value_t args[], int argsCnt)
432 {
433 auto tMin = 0.0f;
434 auto tMax = 1.0f;
435 int idx = 0;
436
437 tMin = jerry_value_as_number(args[1]);
438 tMax = jerry_value_as_number(args[2]);
439 idx += 2;
440
441 t = (t - tMin) / (tMax - tMin);
442 if (t < 0) t = 0.0f;
443 else if (t > 1) t = 1.0f;
444
445 //2d
446 if (jerry_value_is_object(args[idx + 1]) && jerry_value_is_object(args[idx + 2])) {
447 auto val1 = jerry_object_get_index(args[idx + 1], 0);
448 auto val2 = jerry_object_get_index(args[idx + 1], 1);
449 auto val3 = jerry_object_get_index(args[idx + 2], 0);
450 auto val4 = jerry_object_get_index(args[idx + 2], 1);
451
452 Point pt1 = {(float)jerry_value_as_number(val1), (float)jerry_value_as_number(val2)};
453 Point pt2 = {(float)jerry_value_as_number(val3), (float)jerry_value_as_number(val4)};
454 Point ret;
455 ret = lerp(pt1, pt2, t);
456
457 jerry_value_free(val1);
458 jerry_value_free(val2);
459 jerry_value_free(val3);
460 jerry_value_free(val4);
461
462 auto obj = jerry_object();
463 val1 = jerry_number(ret.x);
464 val2 = jerry_number(ret.y);
465 jerry_object_set_index(obj, 0, val1);
466 jerry_object_set_index(obj, 1, val2);
467 jerry_value_free(val1);
468 jerry_value_free(val2);
469
470 return obj;
471 }
472
473 //1d
474 auto val1 = (float) jerry_value_as_number(args[idx + 1]);
475 auto val2 = (float) jerry_value_as_number(args[idx + 2]);
476 return jerry_number(lerp(val1, val2, t));
477 }
478
479
_linear(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)480 static jerry_value_t _linear(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
481 {
482 auto t = (float) jerry_value_as_number(args[0]);
483 return _interp(t, args, jerry_value_as_uint32(argsCnt));
484 }
485
486
_ease(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)487 static jerry_value_t _ease(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
488 {
489 auto t = (float) jerry_value_as_number(args[0]);
490 t = (t < 0.5) ? (4 * t * t * t) : (1.0f - pow(-2.0f * t + 2.0f, 3) * 0.5f);
491 return _interp(t, args, jerry_value_as_uint32(argsCnt));
492 }
493
494
495
_easeIn(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)496 static jerry_value_t _easeIn(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
497 {
498 auto t = (float) jerry_value_as_number(args[0]);
499 t = t * t * t;
500 return _interp(t, args, jerry_value_as_uint32(argsCnt));
501 }
502
503
_easeOut(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)504 static jerry_value_t _easeOut(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
505 {
506 auto t = (float) jerry_value_as_number(args[0]);
507 t = 1.0f - pow(1.0f - t, 3);
508 return _interp(t, args, jerry_value_as_uint32(argsCnt));
509 }
510
511
_clamp(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)512 static jerry_value_t _clamp(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
513 {
514 auto num = jerry_value_as_number(args[0]);
515 auto limit1 = jerry_value_as_number(args[1]);
516 auto limit2 = jerry_value_as_number(args[2]);
517
518 //clamping
519 if (num < limit1) num = limit1;
520 if (num > limit2) num = limit2;
521
522 return jerry_number(num);
523 }
524
525
_dot(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)526 static jerry_value_t _dot(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
527 {
528 auto val1 = jerry_object_get_index(args[0], 0);
529 auto val2 = jerry_object_get_index(args[0], 1);
530 auto val3 = jerry_object_get_index(args[1], 0);
531 auto val4 = jerry_object_get_index(args[1], 1);
532
533 auto x = jerry_value_as_number(val1) * jerry_value_as_number(val3);
534 auto y = jerry_value_as_number(val2) * jerry_value_as_number(val4);
535
536 jerry_value_free(val1);
537 jerry_value_free(val2);
538 jerry_value_free(val3);
539 jerry_value_free(val4);
540
541 return jerry_number(x + y);
542 }
543
544
_cross(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)545 static jerry_value_t _cross(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
546 {
547 auto val1 = jerry_object_get_index(args[0], 0);
548 auto val2 = jerry_object_get_index(args[0], 1);
549 auto val3 = jerry_object_get_index(args[1], 0);
550 auto val4 = jerry_object_get_index(args[1], 1);
551
552 auto x = jerry_value_as_number(val1) * jerry_value_as_number(val4);
553 auto y = jerry_value_as_number(val2) * jerry_value_as_number(val3);
554
555 jerry_value_free(val1);
556 jerry_value_free(val2);
557 jerry_value_free(val3);
558 jerry_value_free(val4);
559
560 return jerry_number(x - y);
561 }
562
563
_normalize(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)564 static jerry_value_t _normalize(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
565 {
566 auto val1 = jerry_object_get_index(args[0], 0);
567 auto val2 = jerry_object_get_index(args[0], 1);
568 auto x = jerry_value_as_number(val1);
569 auto y = jerry_value_as_number(val2);
570
571 jerry_value_free(val1);
572 jerry_value_free(val2);
573
574 auto length = sqrtf(x * x + y * y);
575
576 x /= length;
577 y /= length;
578
579 auto obj = jerry_object();
580 val1 = jerry_number(x);
581 val2 = jerry_number(y);
582 jerry_object_set_index(obj, 0, val1);
583 jerry_object_set_index(obj, 0, val2);
584 jerry_value_free(val1);
585 jerry_value_free(val2);
586
587 return obj;
588 }
589
590
_length(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)591 static jerry_value_t _length(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
592 {
593 auto val1 = jerry_object_get_index(args[0], 0);
594 auto val2 = jerry_object_get_index(args[0], 1);
595 auto x = jerry_value_as_number(val1);
596 auto y = jerry_value_as_number(val2);
597
598 jerry_value_free(val1);
599 jerry_value_free(val2);
600
601 return jerry_number(sqrtf(x * x + y * y));
602 }
603
604
_random(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)605 static jerry_value_t _random(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
606 {
607 auto val = (float)(rand() % 10000001);
608 return jerry_number(val * 0.0000001f);
609 }
610
611
_deg2rad(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)612 static jerry_value_t _deg2rad(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
613 {
614 return jerry_number(deg2rad((float)jerry_value_as_number(args[0])));
615 }
616
617
_rad2deg(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)618 static jerry_value_t _rad2deg(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
619 {
620 return jerry_number(rad2deg((float)jerry_value_as_number(args[0])));
621 }
622
623
_effect(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)624 static jerry_value_t _effect(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
625 {
626 TVGLOG("LOTTIE", "effect is not supported in expressions!");
627
628 return jerry_undefined();
629 }
630
631
_fromCompToSurface(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)632 static jerry_value_t _fromCompToSurface(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
633 {
634 TVGLOG("LOTTIE", "fromCompToSurface is not supported in expressions!");
635
636 return jerry_undefined();
637 }
638
639
_content(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)640 static jerry_value_t _content(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
641 {
642 auto data = static_cast<ExpContent*>(jerry_object_get_native_ptr(info->function, &freeCb));
643 auto group = static_cast<LottieGroup*>(data->obj);
644 auto target = group->content(_idByName(args[0]));
645 if (!target) return jerry_undefined();
646
647 //find the a path property(sh) in the group layer?
648 switch (target->type) {
649 case LottieObject::Group: return _buildGroup(static_cast<LottieGroup*>(target), data->frameNo);
650 case LottieObject::Path: {
651 jerry_value_t obj = jerry_object();
652 jerry_object_set_native_ptr(obj, nullptr, &static_cast<LottiePath*>(target)->pathset);
653 jerry_object_set_sz(obj, "path", obj);
654 return obj;
655 }
656 case LottieObject::Polystar: return _buildPolystar(static_cast<LottiePolyStar*>(target), data->frameNo);
657 case LottieObject::Trimpath: return _buildTrimpath(static_cast<LottieTrimpath*>(target), data->frameNo);
658 default: break;
659 }
660 return jerry_undefined();
661 }
662
663
_layer(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)664 static jerry_value_t _layer(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
665 {
666 auto data = static_cast<ExpContent*>(jerry_object_get_native_ptr(info->function, &freeCb));
667 auto comp = static_cast<LottieLayer*>(data->obj);
668 LottieLayer* layer;
669
670 //layer index
671 if (jerry_value_is_number(args[0])) {
672 auto idx = (uint16_t)jerry_value_as_int32(args[0]);
673 layer = comp->layerByIdx(idx);
674 jerry_value_free(idx);
675 //layer name
676 } else {
677 layer = comp->layerById(_idByName(args[0]));
678 }
679
680 if (!layer) return jerry_undefined();
681
682 auto obj = jerry_object();
683 jerry_object_set_native_ptr(obj, nullptr, layer);
684 _buildLayer(obj, data->frameNo, layer, comp, data->exp);
685
686 return obj;
687 }
688
689
_nearestKey(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)690 static jerry_value_t _nearestKey(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
691 {
692 auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
693 auto time = jerry_value_as_number(args[0]);
694 auto frameNo = exp->comp->frameAtTime(time);
695 auto index = jerry_number(exp->property->nearest(frameNo));
696
697 auto obj = jerry_object();
698 jerry_object_set_sz(obj, EXP_INDEX, index);
699 jerry_value_free(index);
700
701 return obj;
702 }
703
_property(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)704 static jerry_value_t _property(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
705 {
706 auto data = static_cast<ExpContent*>(jerry_object_get_native_ptr(info->function, &freeCb));
707 auto property = data->obj->property(jerry_value_as_int32(args[0]));
708 if (!property) return jerry_undefined();
709 return _value(data->frameNo, property);
710 }
711
712
_propertyGroup(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)713 static jerry_value_t _propertyGroup(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
714 {
715 auto data = static_cast<ExpContent*>(jerry_object_get_native_ptr(info->function, &freeCb));
716 auto level = jerry_value_as_int32(args[0]);
717
718 //intermediate group
719 if (level == 1) {
720 auto group = jerry_function_external(_property);
721 jerry_object_set_native_ptr(group, &freeCb, _expcontent(data->exp, data->frameNo, data->obj));
722 jerry_object_set_sz(group, "", group);
723 return group;
724 }
725
726 TVGLOG("LOTTIE", "propertyGroup(%d)?", level);
727
728 return jerry_undefined();
729 }
730
731
_valueAtTime(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)732 static jerry_value_t _valueAtTime(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
733 {
734 auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
735 auto time = jerry_value_as_number(args[0]);
736 auto frameNo = exp->comp->frameAtTime(time);
737 return _value(frameNo, exp->property);
738 }
739
740
_velocity(float px,float cx,float py,float cy,float elapsed)741 static jerry_value_t _velocity(float px, float cx, float py, float cy, float elapsed)
742 {
743 float velocity[] = {(cx - px) / elapsed, (cy - py) / elapsed};
744 auto obj = jerry_object();
745 auto val1 = jerry_number(velocity[0]);
746 auto val2 = jerry_number(velocity[1]);
747 jerry_object_set_index(obj, 0, val1);
748 jerry_object_set_index(obj, 1, val2);
749 jerry_value_free(val1);
750 jerry_value_free(val2);
751 return obj;
752 }
753
754
_velocityAtTime(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)755 static jerry_value_t _velocityAtTime(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
756 {
757 auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
758 auto time = jerry_value_as_number(args[0]);
759 auto frameNo = exp->comp->frameAtTime(time);
760 auto key = exp->property->nearest(frameNo);
761 auto pframe = exp->property->frameNo(key - 1);
762 auto cframe = exp->property->frameNo(key);
763 auto elapsed = (cframe - pframe) / (exp->comp->frameRate);
764
765 //compute the velocity
766 switch (exp->property->type) {
767 case LottieProperty::Type::Point: {
768 auto prv = (*static_cast<LottiePoint*>(exp->property))(pframe);
769 auto cur = (*static_cast<LottiePoint*>(exp->property))(cframe);
770 return _velocity(prv.x, cur.x, prv.y, cur.y, elapsed);
771 }
772 case LottieProperty::Type::Position: {
773 auto prv = (*static_cast<LottiePosition*>(exp->property))(pframe);
774 auto cur = (*static_cast<LottiePosition*>(exp->property))(cframe);
775 return _velocity(prv.x, cur.x, prv.y, cur.y, elapsed);
776 }
777 case LottieProperty::Type::Float: {
778 auto prv = (*static_cast<LottieFloat*>(exp->property))(pframe);
779 auto cur = (*static_cast<LottieFloat*>(exp->property))(cframe);
780 auto velocity = (cur - prv) / elapsed;
781 return jerry_number(velocity);
782 }
783 default: TVGLOG("LOTTIE", "Non supported type for velocityAtTime?");
784 }
785 return jerry_undefined();
786 }
787
788
_speedAtTime(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)789 static jerry_value_t _speedAtTime(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
790 {
791 auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
792 auto time = jerry_value_as_number(args[0]);
793 auto frameNo = exp->comp->frameAtTime(time);
794 auto key = exp->property->nearest(frameNo);
795 auto pframe = exp->property->frameNo(key - 1);
796 auto cframe = exp->property->frameNo(key);
797 auto elapsed = (cframe - pframe) / (exp->comp->frameRate);
798
799 Point cur, prv;
800
801 //compute the velocity
802 switch (exp->property->type) {
803 case LottieProperty::Type::Point: {
804 prv = (*static_cast<LottiePoint*>(exp->property))(pframe);
805 cur = (*static_cast<LottiePoint*>(exp->property))(cframe);
806 break;
807 }
808 case LottieProperty::Type::Position: {
809 prv = (*static_cast<LottiePosition*>(exp->property))(pframe);
810 cur = (*static_cast<LottiePosition*>(exp->property))(cframe);
811 break;
812 }
813 default: {
814 TVGLOG("LOTTIE", "Non supported type for speedAtTime?");
815 return jerry_undefined();
816 }
817 }
818
819 auto speed = sqrtf(pow(cur.x - prv.x, 2) + pow(cur.y - prv.y, 2)) / elapsed;
820 auto obj = jerry_number(speed);
821 return obj;
822 }
823
824
_loopOutCommon(LottieExpression * exp,const jerry_value_t args[],const jerry_length_t argsCnt)825 static bool _loopOutCommon(LottieExpression* exp, const jerry_value_t args[], const jerry_length_t argsCnt)
826 {
827 exp->loop.mode = LottieExpression::LoopMode::OutCycle;
828
829 if (argsCnt > 0) {
830 auto name = _name(args[0]);
831 if (!strcmp(name, EXP_CYCLE)) exp->loop.mode = LottieExpression::LoopMode::OutCycle;
832 else if (!strcmp(name, EXP_PINGPONG)) exp->loop.mode = LottieExpression::LoopMode::OutPingPong;
833 else if (!strcmp(name, EXP_OFFSET)) exp->loop.mode = LottieExpression::LoopMode::OutOffset;
834 else if (!strcmp(name, EXP_CONTINUE)) exp->loop.mode = LottieExpression::LoopMode::OutContinue;
835 free(name);
836 }
837
838 if (exp->loop.mode != LottieExpression::LoopMode::OutCycle && exp->loop.mode != LottieExpression::LoopMode::OutPingPong) {
839 TVGLOG("LOTTIE", "Not supported loopOut type = %d", exp->loop.mode);
840 return false;
841 }
842
843 return true;
844 }
845
846
_loopOut(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)847 static jerry_value_t _loopOut(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
848 {
849 auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
850
851 if (!_loopOutCommon(exp, args, argsCnt)) return jerry_undefined();
852
853 if (argsCnt > 1) exp->loop.key = jerry_value_as_int32(args[1]);
854
855 auto obj = jerry_object();
856 jerry_object_set_native_ptr(obj, nullptr, exp->property);
857 return obj;
858 }
859
860
_loopOutDuration(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)861 static jerry_value_t _loopOutDuration(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
862 {
863 auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
864
865 if (!_loopOutCommon(exp, args, argsCnt)) return jerry_undefined();
866
867 if (argsCnt > 1) {
868 exp->loop.in = exp->comp->frameAtTime((float)jerry_value_as_int32(args[1]));
869 }
870
871 auto obj = jerry_object();
872 jerry_object_set_native_ptr(obj, nullptr, exp->property);
873 return obj;
874 }
875
876
_loopInCommon(LottieExpression * exp,const jerry_value_t args[],const jerry_length_t argsCnt)877 static bool _loopInCommon(LottieExpression* exp, const jerry_value_t args[], const jerry_length_t argsCnt)
878 {
879 exp->loop.mode = LottieExpression::LoopMode::InCycle;
880
881 if (argsCnt > 0) {
882 auto name = _name(args[0]);
883 if (!strcmp(name, EXP_CYCLE)) exp->loop.mode = LottieExpression::LoopMode::InCycle;
884 else if (!strcmp(name, EXP_PINGPONG)) exp->loop.mode = LottieExpression::LoopMode::InPingPong;
885 else if (!strcmp(name, EXP_OFFSET)) exp->loop.mode = LottieExpression::LoopMode::InOffset;
886 else if (!strcmp(name, EXP_CONTINUE)) exp->loop.mode = LottieExpression::LoopMode::InContinue;
887 free(name);
888 }
889
890 if (exp->loop.mode != LottieExpression::LoopMode::InCycle && exp->loop.mode != LottieExpression::LoopMode::InPingPong) {
891 TVGLOG("LOTTIE", "Not supported loopIn type = %d", exp->loop.mode);
892 return false;
893 }
894
895 return true;
896 }
897
_loopIn(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)898 static jerry_value_t _loopIn(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
899 {
900 auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
901
902 if (!_loopInCommon(exp, args, argsCnt)) return jerry_undefined();
903
904 if (argsCnt > 1) exp->loop.key = jerry_value_as_int32(args[1]);
905
906 auto obj = jerry_object();
907 jerry_object_set_native_ptr(obj, nullptr, exp->property);
908 return obj;
909 }
910
911
_loopInDuration(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)912 static jerry_value_t _loopInDuration(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
913 {
914 auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
915
916 if (argsCnt > 1) {
917 exp->loop.in = exp->comp->frameAtTime((float)jerry_value_as_int32(args[1]));
918 }
919
920 if (!_loopInCommon(exp, args, argsCnt)) return jerry_undefined();
921
922 auto obj = jerry_object();
923 jerry_object_set_native_ptr(obj, nullptr, exp->property);
924 return obj;
925 }
926
927
_key(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)928 static jerry_value_t _key(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
929 {
930 auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
931 auto key = jerry_value_as_int32(args[0]);
932 auto frameNo = exp->property->frameNo(key);
933 auto time = jerry_number(exp->comp->timeAtFrame(frameNo));
934 auto value = _value(frameNo, exp->property);
935
936 auto obj = jerry_object();
937 jerry_object_set_sz(obj, EXP_TIME, time);
938 jerry_object_set_sz(obj, EXP_INDEX, args[0]);
939 jerry_object_set_sz(obj, EXP_VALUE, value);
940
941 //direct access, key[0], key[1]
942 if (exp->property->type == LottieProperty::Type::Float) {
943 jerry_object_set_index(obj, 0, value);
944 } else if (exp->property->type == LottieProperty::Type::Point || exp->property->type == LottieProperty::Type::Position) {
945 jerry_object_set_index(obj, 0, jerry_object_get_index(value, 0));
946 jerry_object_set_index(obj, 1, jerry_object_get_index(value, 1));
947 }
948
949 jerry_value_free(time);
950 jerry_value_free(value);
951
952 return obj;
953 }
954
955
_createPath(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)956 static jerry_value_t _createPath(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
957 {
958 //TODO: arg1: points, arg2: inTangents, arg3: outTangents, arg4: isClosed
959 auto arg1 = jerry_value_to_object(args[0]);
960 auto pathset = jerry_object_get_native_ptr(arg1, nullptr);
961 if (!pathset) {
962 TVGERR("LOTTIE", "failed createPath()");
963 return jerry_undefined();
964 }
965
966 jerry_value_free(arg1);
967
968 auto obj = jerry_object();
969 jerry_object_set_native_ptr(obj, nullptr, pathset);
970 return obj;
971 }
972
973
_uniformPath(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)974 static jerry_value_t _uniformPath(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
975 {
976 auto pathset = static_cast<LottiePathSet*>(jerry_object_get_native_ptr(info->function, nullptr));
977
978 /* TODO: ThorVG prebuilds the path data for performance.
979 It actually need to constructs the Array<Point> for points, inTangents, outTangents and then return here... */
980 auto obj = jerry_object();
981 jerry_object_set_native_ptr(obj, nullptr, pathset);
982 return obj;
983 }
984
985
_isClosed(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)986 static jerry_value_t _isClosed(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
987 {
988 //TODO: Not used
989 return jerry_boolean(true);
990 }
991
992
_buildPath(jerry_value_t context,LottieExpression * exp)993 static void _buildPath(jerry_value_t context, LottieExpression* exp)
994 {
995 //Trick for fast building path.
996 auto points = jerry_function_external(_uniformPath);
997 jerry_object_set_native_ptr(points, nullptr, exp->property);
998 jerry_object_set_sz(context, "points", points);
999 jerry_value_free(points);
1000
1001 auto inTangents = jerry_function_external(_uniformPath);
1002 jerry_object_set_native_ptr(inTangents, nullptr, exp->property);
1003 jerry_object_set_sz(context, "inTangents", inTangents);
1004 jerry_value_free(inTangents);
1005
1006 auto outTangents = jerry_function_external(_uniformPath);
1007 jerry_object_set_native_ptr(outTangents, nullptr, exp->property);
1008 jerry_object_set_sz(context, "outTangents", outTangents);
1009 jerry_value_free(outTangents);
1010
1011 auto isClosed = jerry_function_external(_isClosed);
1012 jerry_object_set_native_ptr(isClosed, nullptr, exp->property);
1013 jerry_object_set_sz(context, "isClosed", isClosed);
1014 jerry_value_free(isClosed);
1015
1016 }
1017
1018
_buildProperty(float frameNo,jerry_value_t context,LottieExpression * exp)1019 static void _buildProperty(float frameNo, jerry_value_t context, LottieExpression* exp)
1020 {
1021 auto value = _value(frameNo, exp->property);
1022 jerry_object_set_sz(context, EXP_VALUE, value);
1023 jerry_value_free(value);
1024
1025 auto valueAtTime = jerry_function_external(_valueAtTime);
1026 jerry_object_set_sz(context, "valueAtTime", valueAtTime);
1027 jerry_object_set_native_ptr(valueAtTime, nullptr, exp);
1028 jerry_value_free(valueAtTime);
1029
1030 auto velocity = jerry_number(0.0f);
1031 jerry_object_set_sz(context, "velocity", velocity);
1032 jerry_value_free(velocity);
1033
1034 auto velocityAtTime = jerry_function_external(_velocityAtTime);
1035 jerry_object_set_sz(context, "velocityAtTime", velocityAtTime);
1036 jerry_object_set_native_ptr(velocityAtTime, nullptr, exp);
1037 jerry_value_free(velocityAtTime);
1038
1039 auto speed = jerry_number(0.0f);
1040 jerry_object_set_sz(context, "speed", speed);
1041 jerry_value_free(speed);
1042
1043 auto speedAtTime = jerry_function_external(_speedAtTime);
1044 jerry_object_set_sz(context, "speedAtTime", speedAtTime);
1045 jerry_object_set_native_ptr(speedAtTime, nullptr, exp);
1046 jerry_value_free(speedAtTime);
1047
1048 //wiggle(freq, amp, octaves=1, amp_mult=.5, t=time)
1049 //temporalWiggle(freq, amp, octaves=1, amp_mult=.5, t=time)
1050 //smooth(width=.2, samples=5, t=time)
1051
1052 auto loopIn = jerry_function_external(_loopIn);
1053 jerry_object_set_sz(context, "loopIn", loopIn);
1054 jerry_object_set_native_ptr(loopIn, nullptr, exp);
1055 jerry_value_free(loopIn);
1056
1057 auto loopOut = jerry_function_external(_loopOut);
1058 jerry_object_set_sz(context, "loopOut", loopOut);
1059 jerry_object_set_native_ptr(loopOut, nullptr, exp);
1060 jerry_value_free(loopOut);
1061
1062 auto loopInDuration = jerry_function_external(_loopInDuration);
1063 jerry_object_set_sz(context, "loopInDuration", loopInDuration);
1064 jerry_object_set_native_ptr(loopInDuration, nullptr, exp);
1065 jerry_value_free(loopInDuration);
1066
1067 auto loopOutDuration = jerry_function_external(_loopOutDuration);
1068 jerry_object_set_sz(context, "loopOutDuration", loopOutDuration);
1069 jerry_object_set_native_ptr(loopOutDuration, nullptr, exp);
1070 jerry_value_free(loopOutDuration);
1071
1072 auto key = jerry_function_external(_key);
1073 jerry_object_set_sz(context, "key", key);
1074 jerry_object_set_native_ptr(key, nullptr, exp);
1075 jerry_value_free(key);
1076
1077 //key(markerName)
1078
1079 auto nearestKey = jerry_function_external(_nearestKey);
1080 jerry_object_set_native_ptr(nearestKey, nullptr, exp);
1081 jerry_object_set_sz(context, "nearestKey", nearestKey);
1082 jerry_value_free(nearestKey);
1083
1084 auto numKeys = jerry_number(exp->property->frameCnt());
1085 jerry_object_set_sz(context, "numKeys", numKeys);
1086 jerry_value_free(numKeys);
1087
1088 auto propertyGroup = jerry_function_external(_propertyGroup);
1089 jerry_object_set_native_ptr(propertyGroup, &freeCb, _expcontent(exp, frameNo, exp->object));
1090 jerry_object_set_sz(context, "propertyGroup", propertyGroup);
1091 jerry_value_free(propertyGroup);
1092
1093 //propertyIndex
1094
1095 //name
1096
1097 //content("name"), #look for the named property from a layer
1098 auto content = jerry_function_external(_content);
1099 jerry_object_set_sz(context, EXP_CONTENT, content);
1100 jerry_object_set_native_ptr(content, &freeCb, _expcontent(exp, frameNo, exp->layer));
1101 jerry_value_free(content);
1102
1103 //expansions per types
1104 if (exp->property->type == LottieProperty::Type::PathSet) _buildPath(context, exp);
1105 }
1106
1107
_comp(const jerry_call_info_t * info,const jerry_value_t args[],const jerry_length_t argsCnt)1108 static jerry_value_t _comp(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
1109 {
1110 auto data = static_cast<ExpContent*>(jerry_object_get_native_ptr(info->function, &freeCb));
1111 auto comp = static_cast<LottieLayer*>(data->obj);
1112 auto layer = comp->layerById(_idByName(args[0]));
1113
1114 if (!layer) return jerry_undefined();
1115
1116 auto obj = jerry_object();
1117 jerry_object_set_native_ptr(obj, nullptr, layer);
1118 _buildLayer(obj, data->frameNo, layer, comp, data->exp);
1119
1120 return obj;
1121 }
1122
1123
_buildMath(jerry_value_t context)1124 static void _buildMath(jerry_value_t context)
1125 {
1126 auto bm_mul = jerry_function_external(_mul);
1127 jerry_object_set_sz(context, "$bm_mul", bm_mul);
1128 jerry_value_free(bm_mul);
1129
1130 auto bm_sum = jerry_function_external(_add);
1131 jerry_object_set_sz(context, "$bm_sum", bm_sum);
1132 jerry_value_free(bm_sum);
1133
1134 auto bm_add = jerry_function_external(_add);
1135 jerry_object_set_sz(context, "$bm_add", bm_add);
1136 jerry_value_free(bm_add);
1137
1138 auto bm_sub = jerry_function_external(_sub);
1139 jerry_object_set_sz(context, "$bm_sub", bm_sub);
1140 jerry_value_free(bm_sub);
1141
1142 auto bm_div = jerry_function_external(_div);
1143 jerry_object_set_sz(context, "$bm_div", bm_div);
1144 jerry_value_free(bm_div);
1145
1146 auto mul = jerry_function_external(_mul);
1147 jerry_object_set_sz(context, "mul", mul);
1148 jerry_value_free(mul);
1149
1150 auto sum = jerry_function_external(_add);
1151 jerry_object_set_sz(context, "sum", sum);
1152 jerry_value_free(sum);
1153
1154 auto add = jerry_function_external(_add);
1155 jerry_object_set_sz(context, "add", add);
1156 jerry_value_free(add);
1157
1158 auto sub = jerry_function_external(_sub);
1159 jerry_object_set_sz(context, "sub", sub);
1160 jerry_value_free(sub);
1161
1162 auto div = jerry_function_external(_div);
1163 jerry_object_set_sz(context, "div", div);
1164 jerry_value_free(div);
1165
1166 auto clamp = jerry_function_external(_clamp);
1167 jerry_object_set_sz(context, "clamp", clamp);
1168 jerry_value_free(clamp);
1169
1170 auto dot = jerry_function_external(_dot);
1171 jerry_object_set_sz(context, "dot", dot);
1172 jerry_value_free(dot);
1173
1174 auto cross = jerry_function_external(_cross);
1175 jerry_object_set_sz(context, "cross", cross);
1176 jerry_value_free(cross);
1177
1178 auto normalize = jerry_function_external(_normalize);
1179 jerry_object_set_sz(context, "normalize", normalize);
1180 jerry_value_free(normalize);
1181
1182 auto length = jerry_function_external(_length);
1183 jerry_object_set_sz(context, "length", length);
1184 jerry_value_free(length);
1185
1186 auto random = jerry_function_external(_random);
1187 jerry_object_set_sz(context, "random", random);
1188 jerry_value_free(random);
1189
1190 auto deg2rad = jerry_function_external(_deg2rad);
1191 jerry_object_set_sz(context, "degreesToRadians", deg2rad);
1192 jerry_value_free(deg2rad);
1193
1194 auto rad2deg = jerry_function_external(_rad2deg);
1195 jerry_object_set_sz(context, "radiansToDegrees", rad2deg);
1196 jerry_value_free(rad2deg);
1197
1198 auto linear = jerry_function_external(_linear);
1199 jerry_object_set_sz(context, "linear", linear);
1200 jerry_value_free(linear);
1201
1202 auto ease = jerry_function_external(_ease);
1203 jerry_object_set_sz(context, "ease", ease);
1204 jerry_value_free(ease);
1205
1206 auto easeIn = jerry_function_external(_easeIn);
1207 jerry_object_set_sz(context, "easeIn", easeIn);
1208 jerry_value_free(easeIn);
1209
1210 auto easeOut = jerry_function_external(_easeOut);
1211 jerry_object_set_sz(context, "easeOut", easeOut);
1212 jerry_value_free(easeOut);
1213
1214 //lookAt
1215 }
1216
1217
buildGlobal(LottieExpression * exp)1218 void LottieExpressions::buildGlobal(LottieExpression* exp)
1219 {
1220 auto index = jerry_number(exp->layer->idx);
1221 jerry_object_set_sz(global, EXP_INDEX, index);
1222 jerry_value_free(index);
1223 }
1224
1225
buildComp(jerry_value_t context,float frameNo,LottieLayer * comp,LottieExpression * exp)1226 void LottieExpressions::buildComp(jerry_value_t context, float frameNo, LottieLayer* comp, LottieExpression* exp)
1227 {
1228 auto data = static_cast<ExpContent*>(jerry_object_get_native_ptr(context, &freeCb));
1229 data->exp = exp;
1230 data->frameNo = frameNo;
1231 data->obj = comp;
1232
1233 //layer(index) / layer(name) / layer(otherLayer, reIndex)
1234 auto layer = jerry_function_external(_layer);
1235 jerry_object_set_sz(context, "layer", layer);
1236
1237 jerry_object_set_native_ptr(layer, &freeCb, _expcontent(exp, frameNo, comp));
1238 jerry_value_free(layer);
1239
1240 auto numLayers = jerry_number(comp->children.count);
1241 jerry_object_set_sz(context, "numLayers", numLayers);
1242 jerry_value_free(numLayers);
1243 }
1244
1245
buildComp(LottieComposition * comp,float frameNo,LottieExpression * exp)1246 void LottieExpressions::buildComp(LottieComposition* comp, float frameNo, LottieExpression* exp)
1247 {
1248 buildComp(this->comp, frameNo, comp->root, exp);
1249
1250 //marker
1251 //marker.key(index)
1252 //marker.key(name)
1253 //marker.nearestKey(t)
1254 //marker.numKeys
1255
1256 //activeCamera
1257
1258 auto width = jerry_number(comp->w);
1259 jerry_object_set_sz(thisComp, EXP_WIDTH, width);
1260 jerry_value_free(width);
1261
1262 auto height = jerry_number(comp->h);
1263 jerry_object_set_sz(thisComp, EXP_HEIGHT, height);
1264 jerry_value_free(height);
1265
1266 auto duration = jerry_number(comp->duration());
1267 jerry_object_set_sz(thisComp, "duration", duration);
1268 jerry_value_free(duration);
1269
1270 //ntscDropFrame
1271 //displayStartTime
1272
1273 auto frameDuration = jerry_number(1.0f / comp->frameRate);
1274 jerry_object_set_sz(thisComp, "frameDuration", frameDuration);
1275 jerry_value_free(frameDuration);
1276
1277 //shutterAngle
1278 //shutterPhase
1279 //bgColor
1280 //pixelAspect
1281
1282 auto name = jerry_string((jerry_char_t*)comp->name, strlen(comp->name), JERRY_ENCODING_UTF8);
1283 jerry_object_set_sz(thisComp, EXP_NAME, name);
1284 jerry_value_free(name);
1285 }
1286
1287
buildGlobal()1288 jerry_value_t LottieExpressions::buildGlobal()
1289 {
1290 global = jerry_current_realm();
1291
1292 //comp(name)
1293 comp = jerry_function_external(_comp);
1294 jerry_object_set_native_ptr(comp, &freeCb, _expcontent(nullptr, 0.0f, nullptr));
1295 jerry_object_set_sz(global, "comp", comp);
1296
1297 //footage(name)
1298
1299 thisComp = jerry_object();
1300 jerry_object_set_native_ptr(thisComp, &freeCb, _expcontent(nullptr, 0.0f, nullptr));
1301 jerry_object_set_sz(global, "thisComp", thisComp);
1302
1303 thisLayer = jerry_object();
1304 jerry_object_set_sz(global, "thisLayer", thisLayer);
1305
1306 thisProperty = jerry_object();
1307 jerry_object_set_sz(global, "thisProperty", thisProperty);
1308
1309 auto effect = jerry_function_external(_effect);
1310 jerry_object_set_sz(global, EXP_EFFECT, effect);
1311 jerry_value_free(effect);
1312
1313 auto fromCompToSurface = jerry_function_external(_fromCompToSurface);
1314 jerry_object_set_sz(global, "fromCompToSurface", fromCompToSurface);
1315 jerry_value_free(fromCompToSurface);
1316
1317 auto createPath = jerry_function_external(_createPath);
1318 jerry_object_set_sz(global, "createPath", createPath);
1319 jerry_value_free(createPath);
1320
1321 //posterizeTime(framesPerSecond)
1322 //value
1323
1324 return global;
1325 }
1326
1327
evaluate(float frameNo,LottieExpression * exp)1328 jerry_value_t LottieExpressions::evaluate(float frameNo, LottieExpression* exp)
1329 {
1330 if (exp->disabled) return jerry_undefined();
1331
1332 buildGlobal(exp);
1333
1334 //main composition
1335 buildComp(exp->comp, frameNo, exp);
1336
1337 //this composition
1338 buildComp(thisComp, frameNo, exp->layer->comp, exp);
1339
1340 //update global context values
1341 _buildProperty(frameNo, global, exp);
1342
1343 //this layer
1344 jerry_object_set_native_ptr(thisLayer, nullptr, exp->layer);
1345 _buildLayer(thisLayer, frameNo, exp->layer, exp->comp->root, exp);
1346
1347 //this property
1348 jerry_object_set_native_ptr(thisProperty, nullptr, exp->property);
1349 _buildProperty(frameNo, thisProperty, exp);
1350
1351 //expansions per object type
1352 if (exp->object->type == LottieObject::Transform) _buildTransform(global, frameNo, static_cast<LottieTransform*>(exp->object));
1353
1354 //evaluate the code
1355 auto eval = jerry_eval((jerry_char_t *) exp->code, strlen(exp->code), JERRY_PARSE_NO_OPTS);
1356
1357 if (jerry_value_is_exception(eval) || jerry_value_is_undefined(eval)) {
1358 TVGERR("LOTTIE", "Failed to dispatch the expressions!");
1359 exp->disabled = true;
1360 return jerry_undefined();
1361 }
1362
1363 jerry_value_free(eval);
1364
1365 return jerry_object_get_sz(global, "$bm_rt");
1366 }
1367
1368
1369 /************************************************************************/
1370 /* External Class Implementation */
1371 /************************************************************************/
1372
~LottieExpressions()1373 LottieExpressions::~LottieExpressions()
1374 {
1375 jerry_value_free(thisProperty);
1376 jerry_value_free(thisLayer);
1377 jerry_value_free(thisComp);
1378 jerry_value_free(comp);
1379 jerry_value_free(global);
1380 jerry_cleanup();
1381 }
1382
1383
LottieExpressions()1384 LottieExpressions::LottieExpressions()
1385 {
1386 jerry_init(JERRY_INIT_EMPTY);
1387 _buildMath(buildGlobal());
1388 }
1389
1390
update(float curTime)1391 void LottieExpressions::update(float curTime)
1392 {
1393 //time, #current time in seconds
1394 auto time = jerry_number(curTime);
1395 jerry_object_set_sz(global, EXP_TIME, time);
1396 jerry_value_free(time);
1397 }
1398
1399
1400 //FIXME: Threads support
1401 #include "tvgTaskScheduler.h"
1402
instance()1403 LottieExpressions* LottieExpressions::instance()
1404 {
1405 //FIXME: Threads support
1406 if (TaskScheduler::threads() > 1) {
1407 TVGLOG("LOTTIE", "Lottie Expressions are not supported with tvg threads");
1408 return nullptr;
1409 }
1410
1411 if (!exps) exps = new LottieExpressions;
1412 ++engineRefCnt;
1413 return exps;
1414 }
1415
1416
retrieve(LottieExpressions * instance)1417 void LottieExpressions::retrieve(LottieExpressions* instance)
1418 {
1419 if (--engineRefCnt == 0) {
1420 delete(instance);
1421 exps = nullptr;
1422 }
1423 }
1424
1425
1426 #endif //THORVG_LOTTIE_EXPRESSIONS_SUPPORT
1427
1428 #endif /* LV_USE_THORVG_INTERNAL */
1429
1430