mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-19 22:41:52 +00:00

When the system fails to interpret the expression code, it forcibly disables the feature per property. This improvement enhances stability and performance by avoiding reckless attempts to interpret JavaScript code. When we confirm the full stability with expressions, we can revert this code.
1290 lines
42 KiB
C++
1290 lines
42 KiB
C++
/*
|
|
* Copyright (c) 2024 the ThorVG project. All rights reserved.
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
|
|
#include "tvgMath.h"
|
|
#include "tvgLottieModel.h"
|
|
#include "tvgLottieExpressions.h"
|
|
|
|
#ifdef THORVG_LOTTIE_EXPRESSIONS_SUPPORT
|
|
|
|
/************************************************************************/
|
|
/* Internal Class Implementation */
|
|
/************************************************************************/
|
|
|
|
struct ExpContent
|
|
{
|
|
LottieObject* obj;
|
|
float frameNo;
|
|
};
|
|
|
|
|
|
//reserved expressions speicifiers
|
|
static const char* EXP_NAME = "name";
|
|
static const char* EXP_CONTENT = "content";
|
|
static const char* EXP_WIDTH = "width";
|
|
static const char* EXP_HEIGHT = "height";
|
|
static const char* EXP_CYCLE = "cycle";
|
|
static const char* EXP_PINGPONG = "pingpong";
|
|
static const char* EXP_OFFSET = "offset";
|
|
static const char* EXP_CONTINUE = "continue";
|
|
static const char* EXP_TIME = "time";
|
|
static const char* EXP_VALUE = "value";
|
|
static const char* EXP_INDEX = "index";
|
|
static const char* EXP_EFFECT= "effect";
|
|
|
|
|
|
static void contentFree(void *native_p, struct jerry_object_native_info_t *info_p)
|
|
{
|
|
free(native_p);
|
|
}
|
|
|
|
static jerry_object_native_info_t freeCb {contentFree, 0, 0};
|
|
static uint32_t engineRefCnt = 0; //Expressions Engine reference count
|
|
|
|
|
|
static char* _name(jerry_value_t args)
|
|
{
|
|
auto arg0 = jerry_value_to_string(args);
|
|
auto len = jerry_string_length(arg0);
|
|
auto name = (jerry_char_t*)malloc(len * sizeof(jerry_char_t) + 1);
|
|
jerry_string_to_buffer(arg0, JERRY_ENCODING_UTF8, name, len);
|
|
name[len] = '\0';
|
|
jerry_value_free(arg0);
|
|
return (char*) name;
|
|
}
|
|
|
|
|
|
static jerry_value_t _toComp(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
TVGERR("LOTTIE", "toComp is not supported in expressions!");
|
|
|
|
return jerry_undefined();
|
|
}
|
|
|
|
|
|
static void _buildTransform(jerry_value_t context, LottieTransform* transform)
|
|
{
|
|
if (!transform) return;
|
|
|
|
auto obj = jerry_object();
|
|
jerry_object_set_sz(context, "transform", obj);
|
|
|
|
auto anchorPoint = jerry_object();
|
|
jerry_object_set_native_ptr(anchorPoint, nullptr, &transform->anchor);
|
|
jerry_object_set_sz(obj, "anchorPoint", anchorPoint);
|
|
jerry_value_free(anchorPoint);
|
|
|
|
auto position = jerry_object();
|
|
jerry_object_set_native_ptr(position, nullptr, &transform->position);
|
|
jerry_object_set_sz(obj, "position", position);
|
|
jerry_value_free(position);
|
|
|
|
auto scale = jerry_object();
|
|
jerry_object_set_native_ptr(scale, nullptr, &transform->scale);
|
|
jerry_object_set_sz(obj, "scale", scale);
|
|
jerry_value_free(scale);
|
|
|
|
auto rotation = jerry_object();
|
|
jerry_object_set_native_ptr(rotation, nullptr, &transform->rotation);
|
|
jerry_object_set_sz(obj, "rotation", rotation);
|
|
jerry_value_free(rotation);
|
|
|
|
auto opacity = jerry_object();
|
|
jerry_object_set_native_ptr(opacity, nullptr, &transform->opacity);
|
|
jerry_object_set_sz(obj, "opacity", opacity);
|
|
jerry_value_free(opacity);
|
|
|
|
jerry_value_free(obj);
|
|
}
|
|
|
|
|
|
static void _buildLayer(jerry_value_t context, LottieLayer* layer, LottieComposition* comp)
|
|
{
|
|
auto width = jerry_number(layer->w);
|
|
jerry_object_set_sz(context, EXP_WIDTH, width);
|
|
jerry_value_free(width);
|
|
|
|
auto height = jerry_number(layer->h);
|
|
jerry_object_set_sz(context, EXP_HEIGHT, height);
|
|
jerry_value_free(height);
|
|
|
|
auto index = jerry_number(layer->id);
|
|
jerry_object_set_sz(context, EXP_INDEX, index);
|
|
jerry_value_free(index);
|
|
|
|
auto parent = jerry_object();
|
|
jerry_object_set_native_ptr(parent, nullptr, layer->parent);
|
|
jerry_object_set_sz(context, "parent", parent);
|
|
jerry_value_free(parent);
|
|
|
|
auto hasParent = jerry_boolean(layer->parent ? true : false);
|
|
jerry_object_set_sz(context, "hasParent", hasParent);
|
|
jerry_value_free(hasParent);
|
|
|
|
auto inPoint = jerry_number(layer->inFrame);
|
|
jerry_object_set_sz(context, "inPoint", inPoint);
|
|
jerry_value_free(inPoint);
|
|
|
|
auto outPoint = jerry_number(layer->outFrame);
|
|
jerry_object_set_sz(context, "outPoint", outPoint);
|
|
jerry_value_free(outPoint);
|
|
|
|
auto startTime = jerry_number(comp->timeAtFrame(layer->startFrame));
|
|
jerry_object_set_sz(context, "startTime", startTime);
|
|
jerry_value_free(startTime);
|
|
|
|
auto hasVideo = jerry_boolean(false);
|
|
jerry_object_set_sz(context, "hasVideo", hasVideo);
|
|
jerry_value_free(hasVideo);
|
|
|
|
auto hasAudio = jerry_boolean(false);
|
|
jerry_object_set_sz(context, "hasAudio", hasAudio);
|
|
jerry_value_free(hasAudio);
|
|
|
|
//active, #current in the animation range?
|
|
|
|
auto enabled = jerry_boolean(!layer->hidden);
|
|
jerry_object_set_sz(context, "enabled", enabled);
|
|
jerry_value_free(enabled);
|
|
|
|
auto audioActive = jerry_boolean(false);
|
|
jerry_object_set_sz(context, "audioActive", audioActive);
|
|
jerry_value_free(audioActive);
|
|
|
|
//sampleImage(point, radius = [.5, .5], postEffect=true, t=time)
|
|
|
|
_buildTransform(context, layer->transform);
|
|
|
|
//audioLevels, #the value of the Audio Levels property of the layer in decibels
|
|
|
|
auto timeRemap = jerry_object();
|
|
jerry_object_set_native_ptr(timeRemap, nullptr, &layer->timeRemap);
|
|
jerry_object_set_sz(context, "timeRemap", timeRemap);
|
|
jerry_value_free(timeRemap);
|
|
|
|
//marker.key(index)
|
|
//marker.key(name)
|
|
//marker.nearestKey(t)
|
|
//marker.numKeys
|
|
|
|
auto name = jerry_string_sz(layer->name);
|
|
jerry_object_set_sz(context, EXP_NAME, name);
|
|
jerry_value_free(name);
|
|
|
|
auto toComp = jerry_function_external(_toComp);
|
|
jerry_object_set_sz(context, "toComp", toComp);
|
|
jerry_object_set_native_ptr(toComp, nullptr, comp);
|
|
jerry_value_free(toComp);
|
|
}
|
|
|
|
|
|
static jerry_value_t _value(float frameNo, LottieExpression* exp)
|
|
{
|
|
switch (exp->type) {
|
|
case LottieProperty::Type::Point: {
|
|
auto value = jerry_object();
|
|
auto pos = (*static_cast<LottiePoint*>(exp->property))(frameNo);
|
|
auto val1 = jerry_number(pos.x);
|
|
auto val2 = jerry_number(pos.y);
|
|
jerry_object_set_index(value, 0, val1);
|
|
jerry_object_set_index(value, 1, val2);
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
return value;
|
|
}
|
|
case LottieProperty::Type::Float: {
|
|
return jerry_number((*static_cast<LottieFloat*>(exp->property))(frameNo));
|
|
}
|
|
case LottieProperty::Type::Opacity: {
|
|
return jerry_number((*static_cast<LottieOpacity*>(exp->property))(frameNo));
|
|
}
|
|
case LottieProperty::Type::PathSet: {
|
|
auto value = jerry_object();
|
|
jerry_object_set_native_ptr(value, nullptr, exp->property);
|
|
return value;
|
|
}
|
|
case LottieProperty::Type::Position: {
|
|
auto value = jerry_object();
|
|
auto pos = (*static_cast<LottiePosition*>(exp->property))(frameNo);
|
|
auto val1 = jerry_number(pos.x);
|
|
auto val2 = jerry_number(pos.y);
|
|
jerry_object_set_index(value, 0, val1);
|
|
jerry_object_set_index(value, 1, val2);
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
return value;
|
|
}
|
|
default: {
|
|
TVGERR("LOTTIE", "Non supported type for value? = %d", (int) exp->type);
|
|
}
|
|
}
|
|
return jerry_undefined();
|
|
}
|
|
|
|
|
|
static jerry_value_t _addsub(const jerry_value_t args[], float addsub)
|
|
{
|
|
//1d
|
|
if (jerry_value_is_number(args[0])) return jerry_number(jerry_value_as_number(args[0]) + addsub * jerry_value_as_number(args[1]));
|
|
|
|
//2d
|
|
auto val1 = jerry_object_get_index(args[0], 0);
|
|
auto val2 = jerry_object_get_index(args[0], 1);
|
|
auto val3 = jerry_object_get_index(args[1], 0);
|
|
auto val4 = jerry_object_get_index(args[1], 1);
|
|
auto x = jerry_value_as_number(val1) + addsub * jerry_value_as_number(val3);
|
|
auto y = jerry_value_as_number(val2) + addsub * jerry_value_as_number(val4);
|
|
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
jerry_value_free(val3);
|
|
jerry_value_free(val4);
|
|
|
|
auto obj = jerry_object();
|
|
val1 = jerry_number(x);
|
|
val2 = jerry_number(y);
|
|
jerry_object_set_index(obj, 0, val1);
|
|
jerry_object_set_index(obj, 1, val2);
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
static jerry_value_t _muldiv(const jerry_value_t arg1, float arg2)
|
|
{
|
|
//1d
|
|
if (jerry_value_is_number(arg1)) return jerry_number(jerry_value_as_number(arg1) * arg2);
|
|
|
|
//2d
|
|
auto val1 = jerry_object_get_index(arg1, 0);
|
|
auto val2 = jerry_object_get_index(arg1, 1);
|
|
auto x = jerry_value_as_number(val1) * arg2;
|
|
auto y = jerry_value_as_number(val2) * arg2;
|
|
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
|
|
auto obj = jerry_object();
|
|
val1 = jerry_number(x);
|
|
val2 = jerry_number(y);
|
|
jerry_object_set_index(obj, 0, val1);
|
|
jerry_object_set_index(obj, 1, val2);
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
static jerry_value_t _add(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
return _addsub(args, 1.0f);
|
|
}
|
|
|
|
|
|
static jerry_value_t _sub(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
return _addsub(args, -1.0f);
|
|
}
|
|
|
|
|
|
static jerry_value_t _mul(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
return _muldiv(args[0], jerry_value_as_number(args[1]));
|
|
}
|
|
|
|
|
|
static jerry_value_t _div(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
return _muldiv(args[0], 1.0f / jerry_value_as_number(args[1]));
|
|
}
|
|
|
|
|
|
static jerry_value_t _interp(float t, const jerry_value_t args[], int argsCnt)
|
|
{
|
|
auto tMin = 0.0f;
|
|
auto tMax = 1.0f;
|
|
int idx = 0;
|
|
|
|
if (argsCnt > 3) {
|
|
tMin = jerry_value_as_number(args[1]);
|
|
tMax = jerry_value_as_number(args[2]);
|
|
idx += 2;
|
|
}
|
|
|
|
//2d
|
|
if (jerry_value_is_object(args[idx + 1]) && jerry_value_is_object(args[idx + 2])) {
|
|
auto val1 = jerry_object_get_index(args[0], 0);
|
|
auto val2 = jerry_object_get_index(args[0], 1);
|
|
auto val3 = jerry_object_get_index(args[1], 0);
|
|
auto val4 = jerry_object_get_index(args[1], 1);
|
|
|
|
Point pt1 = {(float)jerry_value_as_number(val1), (float)jerry_value_as_number(val2)};
|
|
Point pt2 = {(float)jerry_value_as_number(val3), (float)jerry_value_as_number(val4)};
|
|
Point ret;
|
|
if (t <= tMin) ret = pt1;
|
|
else if (t >= tMax) ret = pt2;
|
|
else ret = mathLerp(pt1, pt2, t);
|
|
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
jerry_value_free(val3);
|
|
jerry_value_free(val4);
|
|
|
|
auto obj = jerry_object();
|
|
val1 = jerry_number(ret.x);
|
|
val2 = jerry_number(ret.y);
|
|
jerry_object_set_index(obj, 0, val1);
|
|
jerry_object_set_index(obj, 1, val2);
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
|
|
return obj;
|
|
}
|
|
|
|
//1d
|
|
auto val1 = (float) jerry_value_as_number(args[idx + 1]);
|
|
if (t <= tMin) jerry_number(val1);
|
|
auto val2 = (float) jerry_value_as_number(args[idx + 2]);
|
|
if (t >= tMax) jerry_number(val2);
|
|
return jerry_number(mathLerp(val1, val2, t));
|
|
}
|
|
|
|
|
|
static jerry_value_t _linear(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto t = (float) jerry_value_as_number(args[0]);
|
|
return _interp(t, args, jerry_value_as_uint32(argsCnt));
|
|
}
|
|
|
|
|
|
static jerry_value_t _ease(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto t = (float) jerry_value_as_number(args[0]);
|
|
t = (t < 0.5) ? (4 * t * t * t) : (1.0f - pow(-2.0f * t + 2.0f, 3) * 0.5f);
|
|
return _interp(t, args, jerry_value_as_uint32(argsCnt));
|
|
}
|
|
|
|
|
|
|
|
static jerry_value_t _easeIn(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto t = (float) jerry_value_as_number(args[0]);
|
|
t = t * t * t;
|
|
return _interp(t, args, jerry_value_as_uint32(argsCnt));
|
|
}
|
|
|
|
|
|
static jerry_value_t _easeOut(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto t = (float) jerry_value_as_number(args[0]);
|
|
t = 1.0f - pow(1.0f - t, 3);
|
|
return _interp(t, args, jerry_value_as_uint32(argsCnt));
|
|
}
|
|
|
|
|
|
static jerry_value_t _clamp(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto num = jerry_value_as_number(args[0]);
|
|
auto limit1 = jerry_value_as_number(args[1]);
|
|
auto limit2 = jerry_value_as_number(args[2]);
|
|
|
|
//clamping
|
|
if (num < limit1) num = limit1;
|
|
if (num > limit2) num = limit2;
|
|
|
|
return jerry_number(num);
|
|
}
|
|
|
|
|
|
static jerry_value_t _dot(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto val1 = jerry_object_get_index(args[0], 0);
|
|
auto val2 = jerry_object_get_index(args[0], 1);
|
|
auto val3 = jerry_object_get_index(args[1], 0);
|
|
auto val4 = jerry_object_get_index(args[1], 1);
|
|
|
|
auto x = jerry_value_as_number(val1) * jerry_value_as_number(val3);
|
|
auto y = jerry_value_as_number(val2) * jerry_value_as_number(val4);
|
|
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
jerry_value_free(val3);
|
|
jerry_value_free(val4);
|
|
|
|
return jerry_number(x + y);
|
|
}
|
|
|
|
|
|
static jerry_value_t _cross(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto val1 = jerry_object_get_index(args[0], 0);
|
|
auto val2 = jerry_object_get_index(args[0], 1);
|
|
auto val3 = jerry_object_get_index(args[1], 0);
|
|
auto val4 = jerry_object_get_index(args[1], 1);
|
|
|
|
auto x = jerry_value_as_number(val1) * jerry_value_as_number(val4);
|
|
auto y = jerry_value_as_number(val2) * jerry_value_as_number(val3);
|
|
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
jerry_value_free(val3);
|
|
jerry_value_free(val4);
|
|
|
|
return jerry_number(x - y);
|
|
}
|
|
|
|
|
|
static jerry_value_t _normalize(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto val1 = jerry_object_get_index(args[0], 0);
|
|
auto val2 = jerry_object_get_index(args[0], 1);
|
|
auto x = jerry_value_as_number(val1);
|
|
auto y = jerry_value_as_number(val2);
|
|
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
|
|
auto length = sqrtf(x * x + y * y);
|
|
|
|
x /= length;
|
|
y /= length;
|
|
|
|
auto obj = jerry_object();
|
|
val1 = jerry_number(x);
|
|
val2 = jerry_number(y);
|
|
jerry_object_set_index(obj, 0, val1);
|
|
jerry_object_set_index(obj, 0, val2);
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
static jerry_value_t _length(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto val1 = jerry_object_get_index(args[0], 0);
|
|
auto val2 = jerry_object_get_index(args[0], 1);
|
|
auto x = jerry_value_as_number(val1);
|
|
auto y = jerry_value_as_number(val2);
|
|
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
|
|
return jerry_number(sqrtf(x * x + y * y));
|
|
}
|
|
|
|
|
|
static jerry_value_t _random(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto val = (float)(rand() % 10000001);
|
|
return jerry_number(val * 0.0000001f);
|
|
}
|
|
|
|
|
|
static jerry_value_t _deg2rad(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
return jerry_number(mathDeg2Rad((float)jerry_value_as_number(args[0])));
|
|
}
|
|
|
|
|
|
static jerry_value_t _rad2deg(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
return jerry_number(mathRad2Deg((float)jerry_value_as_number(args[0])));
|
|
}
|
|
|
|
|
|
static jerry_value_t _effect(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
TVGERR("LOTTIE", "effect is not supported in expressions!");
|
|
|
|
return jerry_undefined();
|
|
}
|
|
|
|
|
|
static jerry_value_t _fromCompToSurface(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
TVGERR("LOTTIE", "fromCompToSurface is not supported in expressions!");
|
|
|
|
return jerry_undefined();
|
|
}
|
|
|
|
|
|
static jerry_value_t _content(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto name = _name(args[0]);
|
|
auto data = static_cast<ExpContent*>(jerry_object_get_native_ptr(info->function, &freeCb));
|
|
auto group = static_cast<LottieGroup*>(data->obj);
|
|
auto target = group->content((char*)name);
|
|
free(name);
|
|
if (!target) return jerry_undefined();
|
|
|
|
//find the a path property(sh) in the group layer?
|
|
switch (target->type) {
|
|
case LottieObject::Group: {
|
|
auto group = static_cast<LottieGroup*>(target);
|
|
auto obj = jerry_function_external(_content);
|
|
|
|
//attach a transform
|
|
for (auto c = group->children.begin(); c < group->children.end(); ++c) {
|
|
if ((*c)->type == LottieObject::Type::Transform) {
|
|
_buildTransform(obj, static_cast<LottieTransform*>(*c));
|
|
break;
|
|
}
|
|
}
|
|
auto data2 = (ExpContent*)malloc(sizeof(ExpContent));
|
|
data2->obj = group;
|
|
data2->frameNo = data->frameNo;
|
|
jerry_object_set_native_ptr(obj, &freeCb, data2);
|
|
jerry_object_set_sz(obj, EXP_CONTENT, obj);
|
|
return obj;
|
|
}
|
|
case LottieObject::Path: {
|
|
jerry_value_t obj = jerry_object();
|
|
jerry_object_set_native_ptr(obj, nullptr, &static_cast<LottiePath*>(target)->pathset);
|
|
jerry_object_set_sz(obj, "path", obj);
|
|
return obj;
|
|
}
|
|
case LottieObject::Trimpath: {
|
|
auto trimpath = static_cast<LottieTrimpath*>(target);
|
|
jerry_value_t obj = jerry_object();
|
|
auto start = jerry_number(trimpath->start(data->frameNo));
|
|
jerry_object_set_sz(obj, "start", start);
|
|
jerry_value_free(start);
|
|
auto end = jerry_number(trimpath->end(data->frameNo));
|
|
jerry_object_set_sz(obj, "end", end);
|
|
jerry_value_free(end);
|
|
auto offset = jerry_number(trimpath->offset(data->frameNo));
|
|
jerry_object_set_sz(obj, "offset", end);
|
|
jerry_value_free(offset);
|
|
return obj;
|
|
}
|
|
default: break;
|
|
}
|
|
return jerry_undefined();
|
|
}
|
|
|
|
|
|
static jerry_value_t _layer(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto comp = static_cast<LottieComposition*>(jerry_object_get_native_ptr(info->function, nullptr));
|
|
LottieLayer* layer;
|
|
|
|
//layer index
|
|
if (jerry_value_is_number(args[0])) {
|
|
auto idx = (uint16_t)jerry_value_as_int32(args[0]);
|
|
layer = comp->layer(idx);
|
|
jerry_value_free(idx);
|
|
//layer name
|
|
} else {
|
|
auto name = _name(args[0]);
|
|
layer = comp->layer((char*)name);
|
|
free(name);
|
|
}
|
|
|
|
if (!layer) return jerry_undefined();
|
|
|
|
auto obj = jerry_object();
|
|
jerry_object_set_native_ptr(obj, nullptr, layer);
|
|
_buildLayer(obj, layer, comp);
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
static jerry_value_t _nearestKey(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
|
|
auto time = jerry_value_as_number(args[0]);
|
|
auto frameNo = exp->comp->frameAtTime(time);
|
|
auto index = jerry_number(exp->property->nearest(frameNo));
|
|
|
|
auto obj = jerry_object();
|
|
jerry_object_set_sz(obj, EXP_INDEX, index);
|
|
jerry_value_free(index);
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
static jerry_value_t _valueAtTime(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
|
|
auto time = jerry_value_as_number(args[0]);
|
|
auto frameNo = exp->comp->frameAtTime(time);
|
|
return _value(frameNo, exp);
|
|
}
|
|
|
|
|
|
static jerry_value_t _velocityAtTime(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
|
|
auto time = jerry_value_as_number(args[0]);
|
|
auto frameNo = exp->comp->frameAtTime(time);
|
|
auto key = exp->property->nearest(frameNo);
|
|
auto pframe = exp->property->frameNo(key - 1);
|
|
auto cframe = exp->property->frameNo(key);
|
|
auto elapsed = (cframe - pframe) / (exp->comp->frameRate);
|
|
|
|
Point cur, prv;
|
|
|
|
//compute the velocity
|
|
switch (exp->type) {
|
|
case LottieProperty::Type::Point: {
|
|
prv = (*static_cast<LottiePoint*>(exp->property))(pframe);
|
|
cur = (*static_cast<LottiePoint*>(exp->property))(cframe);
|
|
break;
|
|
}
|
|
case LottieProperty::Type::Position: {
|
|
prv = (*static_cast<LottiePosition*>(exp->property))(pframe);
|
|
cur = (*static_cast<LottiePosition*>(exp->property))(cframe);
|
|
break;
|
|
}
|
|
default: {
|
|
TVGERR("LOTTIE", "Non supported type for velocityAtTime?");
|
|
return jerry_undefined();
|
|
}
|
|
}
|
|
|
|
float velocity[] = {(cur.x - prv.x) / elapsed, (cur.y - prv.y) / elapsed};
|
|
|
|
auto obj = jerry_object();
|
|
auto val1 = jerry_number(velocity[0]);
|
|
auto val2 = jerry_number(velocity[1]);
|
|
jerry_object_set_index(obj, 0, val1);
|
|
jerry_object_set_index(obj, 1, val2);
|
|
jerry_value_free(val1);
|
|
jerry_value_free(val2);
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
static jerry_value_t _speedAtTime(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
|
|
auto time = jerry_value_as_number(args[0]);
|
|
auto frameNo = exp->comp->frameAtTime(time);
|
|
auto key = exp->property->nearest(frameNo);
|
|
auto pframe = exp->property->frameNo(key - 1);
|
|
auto cframe = exp->property->frameNo(key);
|
|
auto elapsed = (cframe - pframe) / (exp->comp->frameRate);
|
|
|
|
Point cur, prv;
|
|
|
|
//compute the velocity
|
|
switch (exp->type) {
|
|
case LottieProperty::Type::Point: {
|
|
prv = (*static_cast<LottiePoint*>(exp->property))(pframe);
|
|
cur = (*static_cast<LottiePoint*>(exp->property))(cframe);
|
|
break;
|
|
}
|
|
case LottieProperty::Type::Position: {
|
|
prv = (*static_cast<LottiePosition*>(exp->property))(pframe);
|
|
cur = (*static_cast<LottiePosition*>(exp->property))(cframe);
|
|
break;
|
|
}
|
|
default: {
|
|
TVGERR("LOTTIE", "Non supported type for speedAtTime?");
|
|
return jerry_undefined();
|
|
}
|
|
}
|
|
|
|
auto speed = sqrtf(pow(cur.x - prv.x, 2) + pow(cur.y - prv.y, 2)) / elapsed;
|
|
auto obj = jerry_number(speed);
|
|
return obj;
|
|
}
|
|
|
|
|
|
static bool _loopOutCommon(LottieExpression* exp, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
exp->loop.mode = LottieExpression::LoopMode::OutCycle;
|
|
|
|
if (argsCnt > 0) {
|
|
auto name = _name(args[0]);
|
|
if (!strcmp(name, EXP_CYCLE)) exp->loop.mode = LottieExpression::LoopMode::OutCycle;
|
|
else if (!strcmp(name, EXP_PINGPONG)) exp->loop.mode = LottieExpression::LoopMode::OutPingPong;
|
|
else if (!strcmp(name, EXP_OFFSET)) exp->loop.mode = LottieExpression::LoopMode::OutOffset;
|
|
else if (!strcmp(name, EXP_CONTINUE)) exp->loop.mode = LottieExpression::LoopMode::OutContinue;
|
|
free(name);
|
|
}
|
|
|
|
if (exp->loop.mode != LottieExpression::LoopMode::OutCycle) {
|
|
TVGERR("hermet", "Not supported loopOut type = %d", exp->loop.mode);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
static jerry_value_t _loopOut(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
|
|
|
|
if (!_loopOutCommon(exp, args, argsCnt)) return jerry_undefined();
|
|
|
|
if (argsCnt > 1) exp->loop.key = jerry_value_as_int32(args[1]);
|
|
|
|
auto obj = jerry_object();
|
|
jerry_object_set_native_ptr(obj, nullptr, exp->property);
|
|
return obj;
|
|
}
|
|
|
|
|
|
static jerry_value_t _loopOutDuration(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
|
|
|
|
if (!_loopOutCommon(exp, args, argsCnt)) return jerry_undefined();
|
|
|
|
if (argsCnt > 1) {
|
|
exp->loop.in = exp->comp->frameAtTime((float)jerry_value_as_int32(args[1]));
|
|
}
|
|
|
|
auto obj = jerry_object();
|
|
jerry_object_set_native_ptr(obj, nullptr, exp->property);
|
|
return obj;
|
|
}
|
|
|
|
|
|
static bool _loopInCommon(LottieExpression* exp, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
exp->loop.mode = LottieExpression::LoopMode::InCycle;
|
|
|
|
if (argsCnt > 0) {
|
|
auto name = _name(args[0]);
|
|
if (!strcmp(name, EXP_CYCLE)) exp->loop.mode = LottieExpression::LoopMode::InCycle;
|
|
else if (!strcmp(name, EXP_PINGPONG)) exp->loop.mode = LottieExpression::LoopMode::InPingPong;
|
|
else if (!strcmp(name, EXP_OFFSET)) exp->loop.mode = LottieExpression::LoopMode::InOffset;
|
|
else if (!strcmp(name, EXP_CONTINUE)) exp->loop.mode = LottieExpression::LoopMode::InContinue;
|
|
free(name);
|
|
}
|
|
|
|
if (exp->loop.mode != LottieExpression::LoopMode::InCycle) {
|
|
TVGERR("hermet", "Not supported loopOut type = %d", exp->loop.mode);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static jerry_value_t _loopIn(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
|
|
|
|
if (!_loopInCommon(exp, args, argsCnt)) return jerry_undefined();
|
|
|
|
if (argsCnt > 1) {
|
|
exp->loop.in = exp->comp->frameAtTime((float)jerry_value_as_int32(args[1]));
|
|
}
|
|
|
|
auto obj = jerry_object();
|
|
jerry_object_set_native_ptr(obj, nullptr, exp->property);
|
|
return obj;
|
|
}
|
|
|
|
|
|
static jerry_value_t _loopInDuration(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
|
|
|
|
if (argsCnt > 1) {
|
|
exp->loop.in = exp->comp->frameAtTime((float)jerry_value_as_int32(args[1]));
|
|
}
|
|
|
|
if (!_loopInCommon(exp, args, argsCnt)) return jerry_undefined();
|
|
|
|
auto obj = jerry_object();
|
|
jerry_object_set_native_ptr(obj, nullptr, exp->property);
|
|
return obj;
|
|
}
|
|
|
|
|
|
static jerry_value_t _key(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto exp = static_cast<LottieExpression*>(jerry_object_get_native_ptr(info->function, nullptr));
|
|
auto key = jerry_value_as_int32(args[0]);
|
|
auto frameNo = exp->property->frameNo(key);
|
|
auto time = jerry_number(exp->comp->timeAtFrame(frameNo));
|
|
auto value = _value(frameNo, exp);
|
|
|
|
auto obj = jerry_object();
|
|
jerry_object_set_sz(obj, EXP_TIME, time);
|
|
jerry_object_set_sz(obj, EXP_INDEX, args[0]);
|
|
jerry_object_set_sz(obj, EXP_VALUE, value);
|
|
|
|
jerry_value_free(time);
|
|
jerry_value_free(value);
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
|
|
static jerry_value_t _createPath(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
//TODO: arg1: points, arg2: inTagents, arg3: outTangents, arg4: isClosed
|
|
auto arg1 = jerry_value_to_object(args[0]);
|
|
auto pathset = jerry_object_get_native_ptr(arg1, nullptr);
|
|
if (!pathset) {
|
|
TVGERR("LOTTIE", "failed createPath()");
|
|
return jerry_undefined();
|
|
}
|
|
|
|
jerry_value_free(arg1);
|
|
|
|
auto obj = jerry_object();
|
|
jerry_object_set_native_ptr(obj, nullptr, pathset);
|
|
return obj;
|
|
}
|
|
|
|
|
|
static jerry_value_t _uniformPath(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto pathset = static_cast<LottiePathSet*>(jerry_object_get_native_ptr(info->function, nullptr));
|
|
|
|
/* TODO: ThorVG prebuilds the path data for performance.
|
|
It acutally need to constructs the Array<Point> for points, inTangents, outTangents and then return here... */
|
|
auto obj = jerry_object();
|
|
jerry_object_set_native_ptr(obj, nullptr, pathset);
|
|
return obj;
|
|
}
|
|
|
|
|
|
static jerry_value_t _isClosed(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
//TODO: Not used
|
|
return jerry_boolean(true);
|
|
}
|
|
|
|
|
|
static void _buildPath(jerry_value_t context, LottieExpression* exp)
|
|
{
|
|
//Trick for fast buliding path.
|
|
auto points = jerry_function_external(_uniformPath);
|
|
jerry_object_set_native_ptr(points, nullptr, exp->property);
|
|
jerry_object_set_sz(context, "points", points);
|
|
jerry_value_free(points);
|
|
|
|
auto inTangents = jerry_function_external(_uniformPath);
|
|
jerry_object_set_native_ptr(inTangents, nullptr, exp->property);
|
|
jerry_object_set_sz(context, "inTangents", inTangents);
|
|
jerry_value_free(inTangents);
|
|
|
|
auto outTangents = jerry_function_external(_uniformPath);
|
|
jerry_object_set_native_ptr(outTangents, nullptr, exp->property);
|
|
jerry_object_set_sz(context, "outTangents", outTangents);
|
|
jerry_value_free(outTangents);
|
|
|
|
auto isClosed = jerry_function_external(_isClosed);
|
|
jerry_object_set_native_ptr(isClosed, nullptr, exp->property);
|
|
jerry_object_set_sz(context, "isClosed", isClosed);
|
|
jerry_value_free(isClosed);
|
|
|
|
}
|
|
|
|
|
|
static void _buildProperty(float frameNo, jerry_value_t context, LottieExpression* exp)
|
|
{
|
|
auto value = _value(frameNo, exp);
|
|
jerry_object_set_sz(context, EXP_VALUE, value);
|
|
jerry_value_free(value);
|
|
|
|
auto valueAtTime = jerry_function_external(_valueAtTime);
|
|
jerry_object_set_sz(context, "valueAtTime", valueAtTime);
|
|
jerry_object_set_native_ptr(valueAtTime, nullptr, exp);
|
|
jerry_value_free(valueAtTime);
|
|
|
|
auto velocity = jerry_number(0.0f);
|
|
jerry_object_set_sz(context, "velocity", velocity);
|
|
jerry_value_free(velocity);
|
|
|
|
auto velocityAtTime = jerry_function_external(_velocityAtTime);
|
|
jerry_object_set_sz(context, "velocityAtTime", velocityAtTime);
|
|
jerry_object_set_native_ptr(velocityAtTime, nullptr, exp);
|
|
jerry_value_free(velocityAtTime);
|
|
|
|
auto speed = jerry_number(0.0f);
|
|
jerry_object_set_sz(context, "speed", speed);
|
|
jerry_value_free(speed);
|
|
|
|
auto speedAtTime = jerry_function_external(_speedAtTime);
|
|
jerry_object_set_sz(context, "speedAtTime", speedAtTime);
|
|
jerry_object_set_native_ptr(speedAtTime, nullptr, exp);
|
|
jerry_value_free(speedAtTime);
|
|
|
|
//wiggle(freq, amp, octaves=1, amp_mult=.5, t=time)
|
|
//temporalWiggle(freq, amp, octaves=1, amp_mult=.5, t=time)
|
|
//smooth(width=.2, samples=5, t=time)
|
|
|
|
auto loopIn = jerry_function_external(_loopIn);
|
|
jerry_object_set_sz(context, "loopIn", loopIn);
|
|
jerry_object_set_native_ptr(loopIn, nullptr, exp);
|
|
jerry_value_free(loopIn);
|
|
|
|
auto loopOut = jerry_function_external(_loopOut);
|
|
jerry_object_set_sz(context, "loopOut", loopOut);
|
|
jerry_object_set_native_ptr(loopOut, nullptr, exp);
|
|
jerry_value_free(loopOut);
|
|
|
|
auto loopInDuration = jerry_function_external(_loopInDuration);
|
|
jerry_object_set_sz(context, "loopInDuration", loopInDuration);
|
|
jerry_object_set_native_ptr(loopInDuration, nullptr, exp);
|
|
jerry_value_free(loopInDuration);
|
|
|
|
auto loopOutDuration = jerry_function_external(_loopOutDuration);
|
|
jerry_object_set_sz(context, "loopOutDuration", loopOutDuration);
|
|
jerry_object_set_native_ptr(loopOutDuration, nullptr, exp);
|
|
jerry_value_free(loopOutDuration);
|
|
|
|
auto key = jerry_function_external(_key);
|
|
jerry_object_set_sz(context, "key", key);
|
|
jerry_object_set_native_ptr(key, nullptr, exp);
|
|
jerry_value_free(key);
|
|
|
|
//key(markerName)
|
|
|
|
auto nearestKey = jerry_function_external(_nearestKey);
|
|
jerry_object_set_native_ptr(nearestKey, nullptr, exp);
|
|
jerry_object_set_sz(context, "nearestKey", nearestKey);
|
|
jerry_value_free(nearestKey);
|
|
|
|
auto numKeys = jerry_number(exp->property->frameCnt());
|
|
jerry_object_set_sz(context, "numKeys", numKeys);
|
|
jerry_value_free(numKeys);
|
|
|
|
//propertyGroup(countUp = 1)
|
|
//propertyIndex
|
|
//name
|
|
|
|
//content("name"), #look for the named property from a layer
|
|
auto data = (ExpContent*)malloc(sizeof(ExpContent));
|
|
data->obj = exp->layer;
|
|
data->frameNo = frameNo;
|
|
|
|
auto content = jerry_function_external(_content);
|
|
jerry_object_set_sz(context, EXP_CONTENT, content);
|
|
jerry_object_set_native_ptr(content, &freeCb, data);
|
|
jerry_value_free(content);
|
|
}
|
|
|
|
|
|
static jerry_value_t _comp(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
|
|
{
|
|
auto comp = static_cast<LottieComposition*>(jerry_object_get_native_ptr(info->function, nullptr));
|
|
LottieLayer* layer;
|
|
|
|
auto arg0 = jerry_value_to_string(args[0]);
|
|
auto len = jerry_string_length(arg0);
|
|
auto name = (jerry_char_t*)alloca(len * sizeof(jerry_char_t) + 1);
|
|
jerry_string_to_buffer(arg0, JERRY_ENCODING_UTF8, name, len);
|
|
name[len] = '\0';
|
|
|
|
jerry_value_free(arg0);
|
|
|
|
layer = comp->asset((char*)name);
|
|
|
|
if (!layer) return jerry_undefined();
|
|
|
|
auto obj = jerry_object();
|
|
jerry_object_set_native_ptr(obj, nullptr, layer);
|
|
_buildLayer(obj, layer, comp);
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
static void _buildMath(jerry_value_t context)
|
|
{
|
|
auto bm_mul = jerry_function_external(_mul);
|
|
jerry_object_set_sz(context, "$bm_mul", bm_mul);
|
|
jerry_value_free(bm_mul);
|
|
|
|
auto bm_sum = jerry_function_external(_add);
|
|
jerry_object_set_sz(context, "$bm_sum", bm_sum);
|
|
jerry_value_free(bm_sum);
|
|
|
|
auto bm_add = jerry_function_external(_add);
|
|
jerry_object_set_sz(context, "$bm_add", bm_add);
|
|
jerry_value_free(bm_add);
|
|
|
|
auto bm_sub = jerry_function_external(_sub);
|
|
jerry_object_set_sz(context, "$bm_sub", bm_sub);
|
|
jerry_value_free(bm_sub);
|
|
|
|
auto bm_div = jerry_function_external(_div);
|
|
jerry_object_set_sz(context, "$bm_div", bm_div);
|
|
jerry_value_free(bm_div);
|
|
|
|
auto mul = jerry_function_external(_mul);
|
|
jerry_object_set_sz(context, "mul", mul);
|
|
jerry_value_free(mul);
|
|
|
|
auto sum = jerry_function_external(_add);
|
|
jerry_object_set_sz(context, "sum", sum);
|
|
jerry_value_free(sum);
|
|
|
|
auto add = jerry_function_external(_add);
|
|
jerry_object_set_sz(context, "add", add);
|
|
jerry_value_free(add);
|
|
|
|
auto sub = jerry_function_external(_sub);
|
|
jerry_object_set_sz(context, "sub", sub);
|
|
jerry_value_free(sub);
|
|
|
|
auto div = jerry_function_external(_div);
|
|
jerry_object_set_sz(context, "div", div);
|
|
jerry_value_free(div);
|
|
|
|
auto clamp = jerry_function_external(_clamp);
|
|
jerry_object_set_sz(context, "clamp", clamp);
|
|
jerry_value_free(clamp);
|
|
|
|
auto dot = jerry_function_external(_dot);
|
|
jerry_object_set_sz(context, "dot", dot);
|
|
jerry_value_free(dot);
|
|
|
|
auto cross = jerry_function_external(_cross);
|
|
jerry_object_set_sz(context, "cross", cross);
|
|
jerry_value_free(cross);
|
|
|
|
auto normalize = jerry_function_external(_normalize);
|
|
jerry_object_set_sz(context, "normalize", normalize);
|
|
jerry_value_free(normalize);
|
|
|
|
auto length = jerry_function_external(_length);
|
|
jerry_object_set_sz(context, "length", length);
|
|
jerry_value_free(length);
|
|
|
|
auto random = jerry_function_external(_random);
|
|
jerry_object_set_sz(context, "random", random);
|
|
jerry_value_free(random);
|
|
|
|
auto deg2rad = jerry_function_external(_deg2rad);
|
|
jerry_object_set_sz(context, "degreesToRadians", deg2rad);
|
|
jerry_value_free(deg2rad);
|
|
|
|
auto rad2deg = jerry_function_external(_rad2deg);
|
|
jerry_object_set_sz(context, "radiansToDegrees", rad2deg);
|
|
jerry_value_free(rad2deg);
|
|
|
|
auto linear = jerry_function_external(_linear);
|
|
jerry_object_set_sz(context, "linear", linear);
|
|
jerry_value_free(linear);
|
|
|
|
auto ease = jerry_function_external(_ease);
|
|
jerry_object_set_sz(context, "ease", ease);
|
|
jerry_value_free(ease);
|
|
|
|
auto easeIn = jerry_function_external(_easeIn);
|
|
jerry_object_set_sz(context, "easeIn", easeIn);
|
|
jerry_value_free(easeIn);
|
|
|
|
auto easeOut = jerry_function_external(_easeOut);
|
|
jerry_object_set_sz(context, "easeOut", easeOut);
|
|
jerry_value_free(easeOut);
|
|
|
|
//lookAt
|
|
}
|
|
|
|
|
|
void LottieExpressions::buildComp(LottieComposition* comp)
|
|
{
|
|
jerry_object_set_native_ptr(this->comp, nullptr, comp);
|
|
jerry_object_set_native_ptr(thisComp, nullptr, comp);
|
|
jerry_object_set_native_ptr(layer, nullptr, comp);
|
|
|
|
//marker
|
|
//marker.key(index)
|
|
//marker.key(name)
|
|
//marker.nearestKey(t)
|
|
//marker.numKeys
|
|
|
|
auto numLayers = jerry_number(comp->root->children.count);
|
|
jerry_object_set_sz(thisComp, "numLayers", numLayers);
|
|
jerry_value_free(numLayers);
|
|
|
|
//activeCamera
|
|
|
|
auto width = jerry_number(comp->w);
|
|
jerry_object_set_sz(thisComp, EXP_WIDTH, width);
|
|
jerry_value_free(width);
|
|
|
|
auto height = jerry_number(comp->h);
|
|
jerry_object_set_sz(thisComp, EXP_HEIGHT, height);
|
|
jerry_value_free(height);
|
|
|
|
auto duration = jerry_number(comp->duration());
|
|
jerry_object_set_sz(thisComp, "duration", duration);
|
|
jerry_value_free(duration);
|
|
|
|
//ntscDropFrame
|
|
//displayStartTime
|
|
|
|
auto frameDuration = jerry_number(1.0f / comp->frameRate);
|
|
jerry_object_set_sz(thisComp, "frameDuration", frameDuration);
|
|
jerry_value_free(frameDuration);
|
|
|
|
//shutterAngle
|
|
//shutterPhase
|
|
//bgColor
|
|
//pixelAspect
|
|
|
|
auto name = jerry_string((jerry_char_t*)comp->name, strlen(comp->name), JERRY_ENCODING_UTF8);
|
|
jerry_object_set_sz(thisComp, EXP_NAME, name);
|
|
jerry_value_free(name);
|
|
}
|
|
|
|
|
|
jerry_value_t LottieExpressions::buildGlobal()
|
|
{
|
|
global = jerry_current_realm();
|
|
|
|
//comp(name)
|
|
comp = jerry_function_external(_comp);
|
|
jerry_object_set_sz(global, "comp", comp);
|
|
|
|
//footage(name)
|
|
|
|
thisComp = jerry_object();
|
|
jerry_object_set_sz(global, "thisComp", thisComp);
|
|
|
|
//layer(index) / layer(name) / layer(otherLayer, reIndex)
|
|
layer = jerry_function_external(_layer);
|
|
jerry_object_set_sz(thisComp, "layer", layer);
|
|
|
|
thisLayer = jerry_object();
|
|
jerry_object_set_sz(global, "thisLayer", thisLayer);
|
|
|
|
thisProperty = jerry_object();
|
|
jerry_object_set_sz(global, "thisProperty", thisProperty);
|
|
|
|
auto effect = jerry_function_external(_effect);
|
|
jerry_object_set_sz(global, EXP_EFFECT, effect);
|
|
jerry_value_free(effect);
|
|
|
|
auto fromCompToSurface = jerry_function_external(_fromCompToSurface);
|
|
jerry_object_set_sz(global, "fromCompToSurface", fromCompToSurface);
|
|
jerry_value_free(fromCompToSurface);
|
|
|
|
auto createPath = jerry_function_external(_createPath);
|
|
jerry_object_set_sz(global, "createPath", createPath);
|
|
jerry_value_free(createPath);
|
|
|
|
//posterizeTime(framesPerSecond)
|
|
//value
|
|
|
|
return global;
|
|
}
|
|
|
|
|
|
jerry_value_t LottieExpressions::evaluate(float frameNo, LottieExpression* exp)
|
|
{
|
|
buildComp(exp->comp);
|
|
|
|
//update global context values
|
|
jerry_object_set_native_ptr(thisLayer, nullptr, exp->layer);
|
|
_buildLayer(thisLayer, exp->layer, exp->comp);
|
|
|
|
jerry_object_set_native_ptr(thisProperty, nullptr, exp->property);
|
|
_buildProperty(frameNo, global, exp);
|
|
|
|
if (exp->type == LottieProperty::Type::PathSet) _buildPath(thisProperty, exp);
|
|
if (exp->object->type == LottieObject::Transform) _buildTransform(global, static_cast<LottieTransform*>(exp->object));
|
|
|
|
//evaluate the code
|
|
auto eval = jerry_eval((jerry_char_t *) exp->code, strlen(exp->code), JERRY_PARSE_NO_OPTS);
|
|
|
|
if (jerry_value_is_exception(eval)) {
|
|
exp->enabled = false; // The feature is experimental, it will be forcely turned off if it's incompatible.
|
|
return jerry_undefined();
|
|
}
|
|
|
|
jerry_value_free(eval);
|
|
|
|
return jerry_object_get_sz(global, "$bm_rt");
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* External Class Implementation */
|
|
/************************************************************************/
|
|
|
|
LottieExpressions::~LottieExpressions()
|
|
{
|
|
jerry_value_free(thisProperty);
|
|
jerry_value_free(thisLayer);
|
|
jerry_value_free(layer);
|
|
jerry_value_free(thisComp);
|
|
jerry_value_free(comp);
|
|
jerry_value_free(global);
|
|
jerry_cleanup();
|
|
}
|
|
|
|
|
|
LottieExpressions::LottieExpressions()
|
|
{
|
|
jerry_init(JERRY_INIT_EMPTY);
|
|
_buildMath(buildGlobal());
|
|
}
|
|
|
|
|
|
void LottieExpressions::update(float curTime)
|
|
{
|
|
//time, #current time in seconds
|
|
auto time = jerry_number(curTime);
|
|
jerry_object_set_sz(global, EXP_TIME, time);
|
|
jerry_value_free(time);
|
|
}
|
|
|
|
|
|
//FIXME: Threads support
|
|
#include "tvgTaskScheduler.h"
|
|
|
|
LottieExpressions* LottieExpressions::instance()
|
|
{
|
|
static LottieExpressions* exps = nullptr;
|
|
|
|
//FIXME: Threads support
|
|
if (TaskScheduler::threads() > 1) {
|
|
TVGLOG("LOTTIE", "Lottie Expressions are not supported with tvg threads");
|
|
return nullptr;
|
|
}
|
|
|
|
if (!exps) exps = new LottieExpressions;
|
|
++engineRefCnt;
|
|
return exps;
|
|
}
|
|
|
|
|
|
void LottieExpressions::retrieve(LottieExpressions* instance)
|
|
{
|
|
if (--engineRefCnt == 0) delete(instance);
|
|
}
|
|
|
|
|
|
#endif //THORVG_LOTTIE_EXPRESSIONS_SUPPORT
|