From 589e93fa7489f2b6cebf88be34ebd3e6432949d8 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Fri, 14 Feb 2025 15:52:10 +0100 Subject: [PATCH] lottie: parsing embedded fonts data (#3220) Only parsing and font loading is added with a very basic text update while building the scene. @Issue: https://github.com/thorvg/thorvg/issues/3184 --- src/loaders/lottie/tvgLottieBuilder.cpp | 20 ++++++++++++++++++++ src/loaders/lottie/tvgLottieModel.cpp | 10 ++++++++++ src/loaders/lottie/tvgLottieModel.h | 9 +++++++++ src/loaders/lottie/tvgLottieParser.cpp | 16 ++++++++++++++++ src/loaders/lottie/tvgLottieParser.h | 1 + 5 files changed, 56 insertions(+) diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index 99aeacfc..39cec602 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -994,6 +994,21 @@ void LottieBuilder::updateImage(LottieGroup* layer) } +void _fontURLText(LottieText* text, Scene* main, float frameNo, LottieExpressions* exps) +{ + auto& doc = text->doc(frameNo); + if (!doc.text) return; + + const float ptPerPx = 0.75f; //1 pt = 1/72; 1 in = 96 px; -> 72/96 = 0.75 + auto txt = Text::gen(); + txt->font(doc.name, doc.size * 100.0f * ptPerPx); + txt->translate(0.0f, -doc.size * 100.0f); + txt->text(doc.text); + txt->fill(doc.color.rgb[0], doc.color.rgb[1], doc.color.rgb[2]); + main->push(std::move(txt)); +} + + void LottieBuilder::updateText(LottieLayer* layer, float frameNo) { auto text = static_cast(layer->children.first()); @@ -1003,6 +1018,11 @@ void LottieBuilder::updateText(LottieLayer* layer, float frameNo) if (!p || !text->font) return; + if (text->font->origin == LottieFont::Origin::FontURL) { + _fontURLText(text, layer->scene, frameNo, exps); + return; + } + auto scale = doc.size; Point cursor = {0.0f, 0.0f}; auto scene = Scene::gen(); diff --git a/src/loaders/lottie/tvgLottieModel.cpp b/src/loaders/lottie/tvgLottieModel.cpp index 08b202c7..a5a0e34d 100644 --- a/src/loaders/lottie/tvgLottieModel.cpp +++ b/src/loaders/lottie/tvgLottieModel.cpp @@ -197,6 +197,16 @@ float LottieTextRange::factor(float frameNo, float totalLen, float idx) } +void LottieFont::prepare() +{ + if (!data.b64src || !name) return; + + TaskScheduler::async(false); + Text::load(name, data.b64src, data.size, "ttf", false); + TaskScheduler::async(true); +} + + void LottieImage::prepare() { LottieObject::type = LottieObject::Image; diff --git a/src/loaders/lottie/tvgLottieModel.h b/src/loaders/lottie/tvgLottieModel.h index 4f4b63dc..b0f7907e 100644 --- a/src/loaders/lottie/tvgLottieModel.h +++ b/src/loaders/lottie/tvgLottieModel.h @@ -303,14 +303,23 @@ struct LottieFont free(style); free(family); free(name); + free(data.b64src); } + struct { + char* b64src = nullptr; + uint32_t size = 0; + } data; + Array chars; char* name = nullptr; char* family = nullptr; char* style = nullptr; + size_t dataSize = 0; float ascent = 0.0f; Origin origin = Embedded; + + void prepare(); }; struct LottieMarker diff --git a/src/loaders/lottie/tvgLottieParser.cpp b/src/loaders/lottie/tvgLottieParser.cpp index 73e63dd2..7b4f84bc 100644 --- a/src/loaders/lottie/tvgLottieParser.cpp +++ b/src/loaders/lottie/tvgLottieParser.cpp @@ -995,6 +995,19 @@ LottieObject* LottieParser::parseAsset() } +void LottieParser::parseFontData(LottieFont* font, const char* data) +{ + if (!data) return; + if (strncmp(data, "data:font/ttf;base64,", sizeof("data:font/ttf;base64,") - 1) != 0) { + TVGLOG("LOTTIE", "Unsupported embeded font data format"); + return; + } + + auto ttf = data + sizeof("data:font/ttf;base64,") - 1; + font->data.size = b64Decode(ttf, strlen(ttf), &font->data.b64src); +} + + LottieFont* LottieParser::parseFont() { enterObject(); @@ -1005,10 +1018,13 @@ LottieFont* LottieParser::parseFont() if (KEY_AS("fName")) font->name = getStringCopy(); else if (KEY_AS("fFamily")) font->family = getStringCopy(); else if (KEY_AS("fStyle")) font->style = getStringCopy(); + else if (KEY_AS("fPath")) parseFontData(font, getString()); else if (KEY_AS("ascent")) font->ascent = getFloat(); else if (KEY_AS("origin")) font->origin = (LottieFont::Origin) getInt(); else skip(key); } + + font->prepare(); return font; } diff --git a/src/loaders/lottie/tvgLottieParser.h b/src/loaders/lottie/tvgLottieParser.h index 29bc6eae..782eadd1 100644 --- a/src/loaders/lottie/tvgLottieParser.h +++ b/src/loaders/lottie/tvgLottieParser.h @@ -96,6 +96,7 @@ private: LottieRepeater* parseRepeater(); LottieOffsetPath* parseOffsetPath(); LottieFont* parseFont(); + void parseFontData(LottieFont* font, const char* data); LottieMarker* parseMarker(); void parseEffect(LottieEffect* effect, void(LottieParser::*func)(LottieEffect*, int));