From 71e3124469277d07f868460b162bce15303b8ec2 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 May 2024 00:07:14 +0900 Subject: [PATCH] lottie: optimize the internal data encode the object name with the hash value to save memory and enable fast data comparison. --- src/loaders/lottie/tvgLottieBuilder.cpp | 6 ++-- src/loaders/lottie/tvgLottieExpressions.cpp | 32 +++++++++------------ src/loaders/lottie/tvgLottieModel.cpp | 8 ++---- src/loaders/lottie/tvgLottieModel.h | 23 +++++++-------- src/loaders/lottie/tvgLottieParser.cpp | 23 ++++++++------- 5 files changed, 44 insertions(+), 48 deletions(-) diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index b41b6924..fb56919d 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -1264,7 +1264,7 @@ static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo, L static void _buildReference(LottieComposition* comp, LottieLayer* layer) { 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) { auto assetLayer = static_cast(*asset); if (_buildComposition(comp, assetLayer)) { @@ -1333,7 +1333,7 @@ static bool _buildComposition(LottieComposition* comp, LottieGroup* parent) auto child = static_cast(*c); //attach the precomp layer. - if (child->refId) _buildReference(comp, child); + if (child->rid) _buildReference(comp, child); if (child->matte.type != CompositeMethod::None) { //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 _bulidHierarchy(parent, child->matte.target); //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); diff --git a/src/loaders/lottie/tvgLottieExpressions.cpp b/src/loaders/lottie/tvgLottieExpressions.cpp index 89d19256..73c2eae1 100644 --- a/src/loaders/lottie/tvgLottieExpressions.cpp +++ b/src/loaders/lottie/tvgLottieExpressions.cpp @@ -22,6 +22,7 @@ #include "tvgMath.h" +#include "tvgCompressor.h" #include "tvgLottieModel.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) { 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) { - auto name = _name(args[0]); auto data = static_cast(jerry_object_get_native_ptr(info->function, &freeCb)); auto group = static_cast(data->obj); - auto target = group->content((char*)name); - free(name); + auto target = group->content(_idByName(args[0])); if (!target) return jerry_undefined(); //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 if (jerry_value_is_number(args[0])) { auto idx = (uint16_t)jerry_value_as_int32(args[0]); - layer = comp->layer(idx); + layer = comp->layerByIdx(idx); jerry_value_free(idx); //layer name } else { - auto name = _name(args[0]); - layer = comp->layer((char*)name); - free(name); + layer = comp->layerById(_idByName(args[0])); } 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) { auto comp = static_cast(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); + auto layer = comp->asset(_idByName(args[0])); if (!layer) return jerry_undefined(); diff --git a/src/loaders/lottie/tvgLottieModel.cpp b/src/loaders/lottie/tvgLottieModel.cpp index a1dd4e4c..abb77f33 100644 --- a/src/loaders/lottie/tvgLottieModel.cpp +++ b/src/loaders/lottie/tvgLottieModel.cpp @@ -344,11 +344,8 @@ void LottieGroup::prepare(LottieObject::Type type) LottieLayer::~LottieLayer() { - if (refId) { - //No need to free assets children because the Composition owns them. - children.clear(); - free(refId); - } + //No need to free assets children because the Composition owns them. + if (rid) children.clear(); for (auto m = masks.begin(); m < masks.end(); ++m) { delete(*m); @@ -356,6 +353,7 @@ LottieLayer::~LottieLayer() matte.target = nullptr; delete(transform); + free(name); } void LottieLayer::prepare() diff --git a/src/loaders/lottie/tvgLottieModel.h b/src/loaders/lottie/tvgLottieModel.h index df9a0715..a5c26821 100644 --- a/src/loaders/lottie/tvgLottieModel.h +++ b/src/loaders/lottie/tvgLottieModel.h @@ -110,7 +110,6 @@ struct LottieObject virtual ~LottieObject() { - free(name); } virtual void override(LottieProperty* prop) @@ -120,7 +119,7 @@ struct LottieObject virtual bool mergeable() { return false; } - char* name = nullptr; + unsigned long id = 0; Type type; bool hidden = false; //remove? }; @@ -500,16 +499,16 @@ struct LottieGroup : LottieObject void prepare(LottieObject::Type type = LottieObject::Group); 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. for (auto c = children.begin(); c < children.end(); ++c) { auto child = *c; if (child->type == LottieObject::Type::Group || child->type == LottieObject::Type::Layer) { if (auto ret = static_cast(child)->content(id)) return ret; - } else if (child->name && !strcmp(child->name, id)) return child; + } else if (child->id == id) return child; } return nullptr; } @@ -547,6 +546,7 @@ struct LottieLayer : LottieGroup LottieLayer* target = nullptr; } matte; + char* name = nullptr; BlendMethod blendMethod = BlendMethod::Normal; LottieLayer* parent = nullptr; LottieFloat timeRemap = 0.0f; @@ -560,12 +560,11 @@ struct LottieLayer : LottieGroup float inFrame = 0.0f; float outFrame = 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 pidx = -1; //index of the parent layer. int16_t idx = -1; //index of the current layer. - //cached data struct { float frameNo = -1.0f; Matrix matrix; @@ -635,16 +634,16 @@ struct LottieComposition return endFrame - startFrame; } - LottieLayer* layer(const char* name) + LottieLayer* layerById(unsigned long id) { for (auto child = root->children.begin(); child < root->children.end(); ++child) { auto layer = static_cast(*child); - if (layer->name && !strcmp(layer->name, name)) return layer; + if (layer->id == id) return layer; } return nullptr; } - LottieLayer* layer(int16_t idx) + LottieLayer* layerByIdx(int16_t idx) { for (auto child = root->children.begin(); child < root->children.end(); ++child) { auto layer = static_cast(*child); @@ -653,11 +652,11 @@ struct LottieComposition return nullptr; } - LottieLayer* asset(const char* name) + LottieLayer* asset(unsigned long id) { for (auto asset = assets.begin(); asset < assets.end(); ++asset) { auto layer = static_cast(*asset); - if (layer->name && !strcmp(layer->name, name)) return layer; + if (layer->id == id) return layer; } return nullptr; } diff --git a/src/loaders/lottie/tvgLottieParser.cpp b/src/loaders/lottie/tvgLottieParser.cpp index 1671109a..0b7eccb2 100644 --- a/src/loaders/lottie/tvgLottieParser.cpp +++ b/src/loaders/lottie/tvgLottieParser.cpp @@ -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]; 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) { if (KEY_AS("nm")) { - obj->name = getStringCopy(); + obj->id = djb2Encode(getString()); return true; } else if (KEY_AS("hd")) { obj->hidden = getBool(); @@ -921,7 +921,7 @@ LottieObject* LottieParser::parseAsset() enterObject(); LottieObject* obj = nullptr; - char *id = nullptr; + unsigned long id = 0; //Used for Image Asset const char* data = nullptr; @@ -932,7 +932,7 @@ LottieObject* LottieParser::parseAsset() if (KEY_AS("id")) { if (peekType() == kStringType) { - id = getStringCopy(); + id = djb2Encode(getString()); } else { id = _int2str(getInt()); } @@ -944,8 +944,7 @@ LottieObject* LottieParser::parseAsset() else skip(key); } if (data) obj = parseImage(data, subPath, embedded); - if (obj) obj->name = id; - else free(id); + if (obj) obj->id = id; return obj; } @@ -1192,10 +1191,14 @@ LottieLayer* LottieParser::parseLayer() enterObject(); 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("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("ks")) { @@ -1217,7 +1220,7 @@ LottieLayer* LottieParser::parseLayer() else if (KEY_AS("tp")) layer->mid = getInt(); else if (KEY_AS("masksProperties")) parseMasks(layer); 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("t")) parseText(layer->children); else if (KEY_AS("ef"))