diff --git a/src/loaders/lottie/tvgLottieLoader.cpp b/src/loaders/lottie/tvgLottieLoader.cpp index a067ff3b..b8919f92 100644 --- a/src/loaders/lottie/tvgLottieLoader.cpp +++ b/src/loaders/lottie/tvgLottieLoader.cpp @@ -61,8 +61,6 @@ void LottieLoader::release() free((char*)content); content = nullptr; } - free(dirName); - dirName = nullptr; } @@ -85,6 +83,8 @@ LottieLoader::~LottieLoader() //TODO: correct position? delete(comp); delete(builder); + + free(dirName); } diff --git a/src/loaders/lottie/tvgLottieModel.cpp b/src/loaders/lottie/tvgLottieModel.cpp index 90dd7f9d..31fdfd60 100644 --- a/src/loaders/lottie/tvgLottieModel.cpp +++ b/src/loaders/lottie/tvgLottieModel.cpp @@ -61,6 +61,14 @@ void LottieSlot::reset() static_cast(pair->prop)->frames = nullptr; break; } + case LottieProperty::Type::Image: { + static_cast(pair->obj)->data.release(); + static_cast(pair->obj)->data = *static_cast(pair->prop); + static_cast(pair->prop)->b64Data = nullptr; + static_cast(pair->prop)->mimeType = nullptr; + static_cast(pair->obj)->prepare(); + break; + } default: break; } delete(pair->prop); @@ -108,6 +116,14 @@ void LottieSlot::assign(LottieObject* target) pair->obj->override(&static_cast(target)->doc); break; } + case LottieProperty::Type::Image: { + if (!overridden) { + pair->prop = new LottieBitmap; + *static_cast(pair->prop) = static_cast(pair->obj)->data; + } + pair->obj->override(&static_cast(target)->data); + break; + } default: break; } } @@ -152,13 +168,6 @@ float LottieTextRange::factor(float frameNo, float totalLen, float idx) } -LottieImage::~LottieImage() -{ - free(b64Data); - free(mimeType); -} - - void LottieImage::prepare() { LottieObject::type = LottieObject::Image; @@ -168,14 +177,15 @@ void LottieImage::prepare() //force to load a picture on the same thread TaskScheduler::async(false); - if (size > 0) picture->load((const char*)b64Data, size, mimeType, false); - else picture->load(path); + if (data.size > 0) picture->load((const char*)data.b64Data, data.size, data.mimeType, false); + else picture->load(data.path); TaskScheduler::async(true); - picture->size(width, height); + picture->size(data.width, data.height); PP(picture)->ref(); + pooler.reset(); pooler.push(picture); } diff --git a/src/loaders/lottie/tvgLottieModel.h b/src/loaders/lottie/tvgLottieModel.h index 4144fda3..e148ca93 100644 --- a/src/loaders/lottie/tvgLottieModel.h +++ b/src/loaders/lottie/tvgLottieModel.h @@ -649,16 +649,14 @@ struct LottieGradientStroke : LottieGradient, LottieStroke struct LottieImage : LottieObject, LottieRenderPooler { - union { - char* b64Data = nullptr; - char* path; - }; - char* mimeType = nullptr; - uint32_t size = 0; - float width = 0.0f; - float height = 0.0f; + LottieBitmap data; + + void override(LottieProperty* prop) override + { + this->data = *static_cast(prop); + this->prepare(); + } - ~LottieImage(); void prepare(); }; diff --git a/src/loaders/lottie/tvgLottieParser.cpp b/src/loaders/lottie/tvgLottieParser.cpp index f17cebcb..73466a16 100644 --- a/src/loaders/lottie/tvgLottieParser.cpp +++ b/src/loaders/lottie/tvgLottieParser.cpp @@ -486,10 +486,8 @@ void LottieParser::parsePropertyInternal(T& prop) template -void LottieParser::registerSlot(LottieObject* obj) +void LottieParser::registerSlot(LottieObject* obj, char* sid) { - auto sid = getStringCopy(); - //append object if the slot already exists. for (auto slot = comp->slots.begin(); slot < comp->slots.end(); ++slot) { if (strcmp((*slot)->sid, sid)) continue; @@ -506,7 +504,7 @@ void LottieParser::parseProperty(T& prop, LottieObject* obj) enterObject(); while (auto key = nextObjectKey()) { if (KEY_AS("k")) parsePropertyInternal(prop); - else if (obj && KEY_AS("sid")) registerSlot(obj); + else if (obj && KEY_AS("sid")) registerSlot(obj, getStringCopy()); else if (KEY_AS("x")) prop.exp = _expression(getStringCopy(), comp, context.layer, context.parent, &prop); else if (KEY_AS("ix")) prop.ix = getInt(); else skip(key); @@ -761,7 +759,7 @@ void LottieParser::parseColorStop(LottieGradient* gradient) while (auto key = nextObjectKey()) { if (KEY_AS("p")) gradient->colorStops.count = getInt(); else if (KEY_AS("k")) parseProperty(gradient->colorStops, gradient); - else if (KEY_AS("sid")) registerSlot(gradient); + else if (KEY_AS("sid")) registerSlot(gradient, getStringCopy()); else skip(key); } } @@ -931,45 +929,39 @@ void LottieParser::parseObject(Array& parent) } -LottieImage* LottieParser::parseImage(const char* data, const char* subPath, bool embedded, float width, float height) +void LottieParser::parseImage(LottieImage* image, const char* data, const char* subPath, bool embedded, float width, float height) { - //Used for Image Asset - auto image = new LottieImage; - //embedded image resource. should start with "data:" //header look like "data:image/png;base64," so need to skip till ','. if (embedded && !strncmp(data, "data:", 5)) { //figure out the mimetype auto mimeType = data + 11; auto needle = strstr(mimeType, ";"); - image->mimeType = strDuplicate(mimeType, needle - mimeType); + image->data.mimeType = strDuplicate(mimeType, needle - mimeType); //b64 data auto b64Data = strstr(data, ",") + 1; size_t length = strlen(data) - (b64Data - data); - image->size = b64Decode(b64Data, length, &image->b64Data); + image->data.size = b64Decode(b64Data, length, &image->data.b64Data); //external image resource } else { auto len = strlen(dirName) + strlen(subPath) + strlen(data) + 1; - image->path = static_cast(malloc(len)); - snprintf(image->path, len, "%s%s%s", dirName, subPath, data); + image->data.path = static_cast(malloc(len)); + snprintf(image->data.path, len, "%s%s%s", dirName, subPath, data); } - image->width = width; - image->height = height; + image->data.width = width; + image->data.height = height; image->prepare(); - - return image; } LottieObject* LottieParser::parseAsset() { - enterObject(); - LottieObject* obj = nullptr; unsigned long id = 0; //Used for Image Asset + char* sid = nullptr; const char* data = nullptr; const char* subPath = nullptr; float width = 0.0f; @@ -991,9 +983,14 @@ LottieObject* LottieParser::parseAsset() else if (KEY_AS("w")) width = getFloat(); else if (KEY_AS("h")) height = getFloat(); else if (KEY_AS("e")) embedded = getInt(); + else if (KEY_AS("sid")) sid = getStringCopy(); else skip(key); } - if (data) obj = parseImage(data, subPath, embedded, width, height); + if (data) { + obj = new LottieImage; + parseImage(static_cast(obj), data, subPath, embedded, width, height); + if (sid) registerSlot(obj, sid); + } if (obj) obj->id = id; return obj; } @@ -1021,6 +1018,7 @@ void LottieParser::parseAssets() { enterArray(); while (nextArrayValue()) { + enterObject(); auto asset = parseAsset(); if (asset) comp->assets.push(asset); else TVGERR("LOTTIE", "Invalid Asset!"); @@ -1478,6 +1476,11 @@ bool LottieParser::apply(LottieSlot* slot) parseSlotProperty(static_cast(obj)->doc); break; } + case LottieProperty::Type::Image: { + obj = parseAsset(); + context.parent = obj; + break; + } default: break; } diff --git a/src/loaders/lottie/tvgLottieParser.h b/src/loaders/lottie/tvgLottieParser.h index 0a1746a5..484d795e 100644 --- a/src/loaders/lottie/tvgLottieParser.h +++ b/src/loaders/lottie/tvgLottieParser.h @@ -39,7 +39,7 @@ public: bool apply(LottieSlot* slot); const char* sid(bool first = false); void captureSlots(const char* key); - template void registerSlot(LottieObject* obj); + template void registerSlot(LottieObject* obj, char* sid); LottieComposition* comp = nullptr; const char* dirName = nullptr; //base resource directory @@ -77,7 +77,7 @@ private: LottieObject* parseObject(); LottieObject* parseAsset(); - LottieImage* parseImage(const char* data, const char* subPath, bool embedded, float width, float height); + void parseImage(LottieImage* image, const char* data, const char* subPath, bool embedded, float width, float height); LottieLayer* parseLayer(LottieLayer* precomp); LottieObject* parseGroup(); LottieRect* parseRect(); diff --git a/src/loaders/lottie/tvgLottieProperty.h b/src/loaders/lottie/tvgLottieProperty.h index 8190326b..84c52ef7 100644 --- a/src/loaders/lottie/tvgLottieProperty.h +++ b/src/loaders/lottie/tvgLottieProperty.h @@ -112,7 +112,7 @@ struct LottieVectorFrame //Property would have an either keyframes or single value. struct LottieProperty { - enum class Type : uint8_t { Point = 0, Float, Opacity, Color, PathSet, ColorStop, Position, TextDoc, Invalid }; + enum class Type : uint8_t { Point = 0, Float, Opacity, Color, PathSet, ColorStop, Position, TextDoc, Image, Invalid }; LottieExpression* exp = nullptr; Type type; @@ -828,6 +828,52 @@ struct LottieTextDoc : LottieProperty }; +struct LottieBitmap : LottieProperty +{ + union { + char* b64Data = nullptr; + char* path; + }; + char* mimeType = nullptr; + uint32_t size = 0; + float width = 0.0f; + float height = 0.0f; + + ~LottieBitmap() + { + release(); + } + + void release() + { + free(b64Data); + free(mimeType); + + b64Data = nullptr; + mimeType = nullptr; + } + + uint32_t frameCnt() override { return 0; } + uint32_t nearest(float time) override { return 0; } + float frameNo(int32_t key) override { return 0; } + + LottieBitmap& operator=(const LottieBitmap& other) + { + //shallow copy, used for slot overriding + if (other.mimeType) b64Data = other.b64Data; + else path = other.path; + mimeType = other.mimeType; + size = other.size; + width = other.width; + height = other.height; + + const_cast(other).b64Data = nullptr; + const_cast(other).mimeType = nullptr; + return *this; + } +}; + + using LottiePoint = LottieGenericProperty; using LottieFloat = LottieGenericProperty; using LottieOpacity = LottieGenericProperty;