lottie: optimize the internal data

encode the object name with the hash value
to save memory and enable fast data comparison.
This commit is contained in:
Hermet Park 2024-05-30 00:07:14 +09:00
parent 53818b41f2
commit 71e3124469
5 changed files with 44 additions and 48 deletions

View file

@ -1264,7 +1264,7 @@ static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo, L
static void _buildReference(LottieComposition* comp, LottieLayer* layer) static void _buildReference(LottieComposition* comp, LottieLayer* layer)
{ {
for (auto asset = comp->assets.begin(); asset < comp->assets.end(); ++asset) { for (auto asset = comp->assets.begin(); asset < comp->assets.end(); ++asset) {
if (strcmp(layer->refId, (*asset)->name)) continue; if (layer->rid != (*asset)->id) continue;
if (layer->type == LottieLayer::Precomp) { if (layer->type == LottieLayer::Precomp) {
auto assetLayer = static_cast<LottieLayer*>(*asset); auto assetLayer = static_cast<LottieLayer*>(*asset);
if (_buildComposition(comp, assetLayer)) { if (_buildComposition(comp, assetLayer)) {
@ -1333,7 +1333,7 @@ static bool _buildComposition(LottieComposition* comp, LottieGroup* parent)
auto child = static_cast<LottieLayer*>(*c); auto child = static_cast<LottieLayer*>(*c);
//attach the precomp layer. //attach the precomp layer.
if (child->refId) _buildReference(comp, child); if (child->rid) _buildReference(comp, child);
if (child->matte.type != CompositeMethod::None) { if (child->matte.type != CompositeMethod::None) {
//no index of the matte layer is provided: the layer above is used as the matte source //no index of the matte layer is provided: the layer above is used as the matte source
@ -1353,7 +1353,7 @@ static bool _buildComposition(LottieComposition* comp, LottieGroup* parent)
//parenting //parenting
_bulidHierarchy(parent, child->matte.target); _bulidHierarchy(parent, child->matte.target);
//precomp referencing //precomp referencing
if (child->matte.target->refId) _buildReference(comp, child->matte.target); if (child->matte.target->rid) _buildReference(comp, child->matte.target);
} }
_bulidHierarchy(parent, child); _bulidHierarchy(parent, child);

View file

@ -22,6 +22,7 @@
#include "tvgMath.h" #include "tvgMath.h"
#include "tvgCompressor.h"
#include "tvgLottieModel.h" #include "tvgLottieModel.h"
#include "tvgLottieExpressions.h" #include "tvgLottieExpressions.h"
@ -76,6 +77,15 @@ static char* _name(jerry_value_t args)
} }
static unsigned long _idByName(jerry_value_t args)
{
auto name = _name(args);
auto id = djb2Encode(name);
free(name);
return id;
}
static jerry_value_t _toComp(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) 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!"); TVGERR("LOTTIE", "toComp is not supported in expressions!");
@ -537,11 +547,9 @@ static jerry_value_t _fromCompToSurface(const jerry_call_info_t* info, const jer
static jerry_value_t _content(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) 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 data = static_cast<ExpContent*>(jerry_object_get_native_ptr(info->function, &freeCb));
auto group = static_cast<LottieGroup*>(data->obj); auto group = static_cast<LottieGroup*>(data->obj);
auto target = group->content((char*)name); auto target = group->content(_idByName(args[0]));
free(name);
if (!target) return jerry_undefined(); if (!target) return jerry_undefined();
//find the a path property(sh) in the group layer? //find the a path property(sh) in the group layer?
@ -598,13 +606,11 @@ static jerry_value_t _layer(const jerry_call_info_t* info, const jerry_value_t a
//layer index //layer index
if (jerry_value_is_number(args[0])) { if (jerry_value_is_number(args[0])) {
auto idx = (uint16_t)jerry_value_as_int32(args[0]); auto idx = (uint16_t)jerry_value_as_int32(args[0]);
layer = comp->layer(idx); layer = comp->layerByIdx(idx);
jerry_value_free(idx); jerry_value_free(idx);
//layer name //layer name
} else { } else {
auto name = _name(args[0]); layer = comp->layerById(_idByName(args[0]));
layer = comp->layer((char*)name);
free(name);
} }
if (!layer) return jerry_undefined(); if (!layer) return jerry_undefined();
@ -998,17 +1004,7 @@ static void _buildProperty(float frameNo, jerry_value_t context, LottieExpressio
static jerry_value_t _comp(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) 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)); auto comp = static_cast<LottieComposition*>(jerry_object_get_native_ptr(info->function, nullptr));
LottieLayer* layer; auto layer = comp->asset(_idByName(args[0]));
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(); if (!layer) return jerry_undefined();

View file

@ -344,11 +344,8 @@ void LottieGroup::prepare(LottieObject::Type type)
LottieLayer::~LottieLayer() LottieLayer::~LottieLayer()
{ {
if (refId) { //No need to free assets children because the Composition owns them.
//No need to free assets children because the Composition owns them. if (rid) children.clear();
children.clear();
free(refId);
}
for (auto m = masks.begin(); m < masks.end(); ++m) { for (auto m = masks.begin(); m < masks.end(); ++m) {
delete(*m); delete(*m);
@ -356,6 +353,7 @@ LottieLayer::~LottieLayer()
matte.target = nullptr; matte.target = nullptr;
delete(transform); delete(transform);
free(name);
} }
void LottieLayer::prepare() void LottieLayer::prepare()

View file

@ -110,7 +110,6 @@ struct LottieObject
virtual ~LottieObject() virtual ~LottieObject()
{ {
free(name);
} }
virtual void override(LottieProperty* prop) virtual void override(LottieProperty* prop)
@ -120,7 +119,7 @@ struct LottieObject
virtual bool mergeable() { return false; } virtual bool mergeable() { return false; }
char* name = nullptr; unsigned long id = 0;
Type type; Type type;
bool hidden = false; //remove? bool hidden = false; //remove?
}; };
@ -500,16 +499,16 @@ struct LottieGroup : LottieObject
void prepare(LottieObject::Type type = LottieObject::Group); void prepare(LottieObject::Type type = LottieObject::Group);
bool mergeable() override { return allowMerge; } bool mergeable() override { return allowMerge; }
LottieObject* content(const char* id) LottieObject* content(unsigned long id)
{ {
if (name && !strcmp(name, id)) return this; if (this->id == id) return this;
//source has children, find recursively. //source has children, find recursively.
for (auto c = children.begin(); c < children.end(); ++c) { for (auto c = children.begin(); c < children.end(); ++c) {
auto child = *c; auto child = *c;
if (child->type == LottieObject::Type::Group || child->type == LottieObject::Type::Layer) { if (child->type == LottieObject::Type::Group || child->type == LottieObject::Type::Layer) {
if (auto ret = static_cast<LottieGroup*>(child)->content(id)) return ret; if (auto ret = static_cast<LottieGroup*>(child)->content(id)) return ret;
} else if (child->name && !strcmp(child->name, id)) return child; } else if (child->id == id) return child;
} }
return nullptr; return nullptr;
} }
@ -547,6 +546,7 @@ struct LottieLayer : LottieGroup
LottieLayer* target = nullptr; LottieLayer* target = nullptr;
} matte; } matte;
char* name = nullptr;
BlendMethod blendMethod = BlendMethod::Normal; BlendMethod blendMethod = BlendMethod::Normal;
LottieLayer* parent = nullptr; LottieLayer* parent = nullptr;
LottieFloat timeRemap = 0.0f; LottieFloat timeRemap = 0.0f;
@ -560,12 +560,11 @@ struct LottieLayer : LottieGroup
float inFrame = 0.0f; float inFrame = 0.0f;
float outFrame = 0.0f; float outFrame = 0.0f;
float startFrame = 0.0f; float startFrame = 0.0f;
char* refId = nullptr; //pre-composition reference. unsigned long rid = 0; //pre-composition reference id.
int16_t mid = -1; //id of the matte layer. int16_t mid = -1; //id of the matte layer.
int16_t pidx = -1; //index of the parent layer. int16_t pidx = -1; //index of the parent layer.
int16_t idx = -1; //index of the current layer. int16_t idx = -1; //index of the current layer.
//cached data
struct { struct {
float frameNo = -1.0f; float frameNo = -1.0f;
Matrix matrix; Matrix matrix;
@ -635,16 +634,16 @@ struct LottieComposition
return endFrame - startFrame; return endFrame - startFrame;
} }
LottieLayer* layer(const char* name) LottieLayer* layerById(unsigned long id)
{ {
for (auto child = root->children.begin(); child < root->children.end(); ++child) { for (auto child = root->children.begin(); child < root->children.end(); ++child) {
auto layer = static_cast<LottieLayer*>(*child); auto layer = static_cast<LottieLayer*>(*child);
if (layer->name && !strcmp(layer->name, name)) return layer; if (layer->id == id) return layer;
} }
return nullptr; return nullptr;
} }
LottieLayer* layer(int16_t idx) LottieLayer* layerByIdx(int16_t idx)
{ {
for (auto child = root->children.begin(); child < root->children.end(); ++child) { for (auto child = root->children.begin(); child < root->children.end(); ++child) {
auto layer = static_cast<LottieLayer*>(*child); auto layer = static_cast<LottieLayer*>(*child);
@ -653,11 +652,11 @@ struct LottieComposition
return nullptr; return nullptr;
} }
LottieLayer* asset(const char* name) LottieLayer* asset(unsigned long id)
{ {
for (auto asset = assets.begin(); asset < assets.end(); ++asset) { for (auto asset = assets.begin(); asset < assets.end(); ++asset) {
auto layer = static_cast<LottieLayer*>(*asset); auto layer = static_cast<LottieLayer*>(*asset);
if (layer->name && !strcmp(layer->name, name)) return layer; if (layer->id == id) return layer;
} }
return nullptr; return nullptr;
} }

View file

@ -51,11 +51,11 @@ static LottieExpression* _expression(char* code, LottieComposition* comp, Lottie
} }
static char* _int2str(int num) static unsigned long _int2str(int num)
{ {
char str[20]; char str[20];
snprintf(str, 20, "%d", num); snprintf(str, 20, "%d", num);
return strdup(str); return djb2Encode(str);
} }
@ -515,7 +515,7 @@ void LottieParser::parseProperty(T& prop, LottieObject* obj)
bool LottieParser::parseCommon(LottieObject* obj, const char* key) bool LottieParser::parseCommon(LottieObject* obj, const char* key)
{ {
if (KEY_AS("nm")) { if (KEY_AS("nm")) {
obj->name = getStringCopy(); obj->id = djb2Encode(getString());
return true; return true;
} else if (KEY_AS("hd")) { } else if (KEY_AS("hd")) {
obj->hidden = getBool(); obj->hidden = getBool();
@ -921,7 +921,7 @@ LottieObject* LottieParser::parseAsset()
enterObject(); enterObject();
LottieObject* obj = nullptr; LottieObject* obj = nullptr;
char *id = nullptr; unsigned long id = 0;
//Used for Image Asset //Used for Image Asset
const char* data = nullptr; const char* data = nullptr;
@ -932,7 +932,7 @@ LottieObject* LottieParser::parseAsset()
if (KEY_AS("id")) if (KEY_AS("id"))
{ {
if (peekType() == kStringType) { if (peekType() == kStringType) {
id = getStringCopy(); id = djb2Encode(getString());
} else { } else {
id = _int2str(getInt()); id = _int2str(getInt());
} }
@ -944,8 +944,7 @@ LottieObject* LottieParser::parseAsset()
else skip(key); else skip(key);
} }
if (data) obj = parseImage(data, subPath, embedded); if (data) obj = parseImage(data, subPath, embedded);
if (obj) obj->name = id; if (obj) obj->id = id;
else free(id);
return obj; return obj;
} }
@ -1192,10 +1191,14 @@ LottieLayer* LottieParser::parseLayer()
enterObject(); enterObject();
while (auto key = nextObjectKey()) { while (auto key = nextObjectKey()) {
if (KEY_AS("ddd")) ddd = getInt(); //3d layer if (KEY_AS("nm"))
{
layer->name = getStringCopy();
layer->id = djb2Encode(layer->name);
}
else if (KEY_AS("ddd")) ddd = getInt(); //3d layer
else if (KEY_AS("ind")) layer->idx = getInt(); else if (KEY_AS("ind")) layer->idx = getInt();
else if (KEY_AS("ty")) layer->type = (LottieLayer::Type) getInt(); else if (KEY_AS("ty")) layer->type = (LottieLayer::Type) getInt();
else if (KEY_AS("nm")) layer->name = getStringCopy();
else if (KEY_AS("sr")) layer->timeStretch = getFloat(); else if (KEY_AS("sr")) layer->timeStretch = getFloat();
else if (KEY_AS("ks")) else if (KEY_AS("ks"))
{ {
@ -1217,7 +1220,7 @@ LottieLayer* LottieParser::parseLayer()
else if (KEY_AS("tp")) layer->mid = getInt(); else if (KEY_AS("tp")) layer->mid = getInt();
else if (KEY_AS("masksProperties")) parseMasks(layer); else if (KEY_AS("masksProperties")) parseMasks(layer);
else if (KEY_AS("hd")) layer->hidden = getBool(); else if (KEY_AS("hd")) layer->hidden = getBool();
else if (KEY_AS("refId")) layer->refId = getStringCopy(); else if (KEY_AS("refId")) layer->rid = djb2Encode(getString());
else if (KEY_AS("td")) layer->matteSrc = getInt(); //used for matte layer else if (KEY_AS("td")) layer->matteSrc = getInt(); //used for matte layer
else if (KEY_AS("t")) parseText(layer->children); else if (KEY_AS("t")) parseText(layer->children);
else if (KEY_AS("ef")) else if (KEY_AS("ef"))