From 9300de2d06a3cb9c1a406434d96f025a9861dd1f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 28 May 2024 17:02:52 +0900 Subject: [PATCH] lottie/builder: revise the layer build logic Promote the text/image updates to the layer level. --- src/loaders/lottie/tvgLottieBuilder.cpp | 244 ++++++++++++------------ 1 file changed, 118 insertions(+), 126 deletions(-) diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index abce6bec..3fdcd79c 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -592,85 +592,6 @@ static void _updatePath(LottieGroup* parent, LottieObject** child, float frameNo } -static void _updateText(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, TVG_UNUSED RenderContext* ctx, LottieExpressions* exps) -{ - auto text = static_cast(*child); - auto& doc = text->doc(frameNo); - auto p = doc.text; - - if (!p || !text->font) return; - - auto scale = doc.size * 0.01f; - float spacing = text->spacing(frameNo) / scale; - Point cursor = {0.0f, 0.0f}; - auto scene = Scene::gen(); - int line = 0; - - //text string - while (true) { - //TODO: remove nested scenes. - //end of text, new line of the cursor position - if (*p == 13 || *p == 3 || *p == '\0') { - //text layout position - auto ascent = text->font->ascent * scale; - if (ascent > doc.bbox.size.y) ascent = doc.bbox.size.y; - Point layout = {doc.bbox.pos.x, doc.bbox.pos.y + ascent - doc.shift}; - - //adjust the layout - if (doc.justify == 1) layout.x += doc.bbox.size.x - (cursor.x * scale); //right aligned - else if (doc.justify == 2) layout.x += (doc.bbox.size.x * 0.5f) - (cursor.x * 0.5f * scale); //center aligned - - scene->translate(layout.x, layout.y); - scene->scale(scale); - - parent->scene->push(std::move(scene)); - - if (*p == '\0') break; - ++p; - - //new text group, single scene for each line - scene = Scene::gen(); - cursor.x = 0.0f; - cursor.y = ++line * (doc.height / scale); - } - - //find the glyph - for (auto g = text->font->chars.begin(); g < text->font->chars.end(); ++g) { - auto glyph = *g; - //draw matched glyphs - if (!strncmp(glyph->code, p, glyph->len)) { - //TODO: caching? - auto shape = Shape::gen(); - for (auto g = glyph->children.begin(); g < glyph->children.end(); ++g) { - auto group = static_cast(*g); - for (auto p = group->children.begin(); p < group->children.end(); ++p) { - if (static_cast(*p)->pathset(frameNo, P(shape)->rs.path.cmds, P(shape)->rs.path.pts, nullptr, 0.0f, exps)) { - P(shape)->update(RenderUpdateFlag::Path); - } - } - } - shape->fill(doc.color.rgb[0], doc.color.rgb[1], doc.color.rgb[2]); - shape->translate(cursor.x, cursor.y); - - if (doc.stroke.render) { - shape->strokeJoin(StrokeJoin::Round); - shape->strokeWidth(doc.stroke.width / scale); - shape->strokeFill(doc.stroke.color.rgb[0], doc.stroke.color.rgb[1], doc.stroke.color.rgb[2]); - } - - scene->push(std::move(shape)); - - p += glyph->len; - - //advance the cursor position horizontally - cursor.x += glyph->width + spacing + doc.tracking; - break; - } - } - } -} - - static void _applyRoundedCorner(Shape* star, Shape* merging, float outerRoundness, float roundness, bool hasRoundness) { static constexpr auto ROUNDED_POLYSTAR_MAGIC_NUMBER = 0.47829f; @@ -949,45 +870,6 @@ static void _updatePolystar(LottieGroup* parent, LottieObject** child, float fra } -static void _updateImage(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, RenderContext* ctx) -{ - auto image = static_cast(*child); - auto picture = image->picture; - - if (!picture) { - picture = Picture::gen().release(); - - //force to load a picture on the same thread - TaskScheduler::async(false); - - if (image->size > 0) { - if (picture->load((const char*)image->b64Data, image->size, image->mimeType) != Result::Success) { - delete(picture); - return; - } - } else { - if (picture->load(image->path) != Result::Success) { - delete(picture); - return; - } - } - - TaskScheduler::async(true); - - image->picture = picture; - PP(picture)->ref(); - } - - if (ctx->propagator) { - if (auto matrix = PP(ctx->propagator)->transform()) { - picture->transform(*matrix); - } - picture->opacity(PP(ctx->propagator)->opacity); - } - parent->scene->push(cast(picture)); -} - - static void _updateRoundedCorner(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, RenderContext* ctx, LottieExpressions* exps) { auto roundedCorner= static_cast(*child); @@ -1088,18 +970,10 @@ static void _updateChildren(LottieGroup* parent, float frameNo, Inlist(layer->children.first()); + auto picture = image->picture; + + if (!picture) { + picture = Picture::gen().release(); + + //force to load a picture on the same thread + TaskScheduler::async(false); + + if (image->size > 0) { + if (picture->load((const char*)image->b64Data, image->size, image->mimeType) != Result::Success) { + delete(picture); + return; + } + } else { + if (picture->load(image->path) != Result::Success) { + delete(picture); + return; + } + } + + TaskScheduler::async(true); + + image->picture = picture; + PP(picture)->ref(); + } + layer->scene->push(cast(picture)); +} + + +static void _updateText(LottieLayer* layer, float frameNo) +{ + auto text = static_cast(layer->children.first()); + auto& doc = text->doc(frameNo); + auto p = doc.text; + + if (!p || !text->font) return; + + auto scale = doc.size * 0.01f; + float spacing = text->spacing(frameNo) / scale; + Point cursor = {0.0f, 0.0f}; + auto scene = Scene::gen(); + int line = 0; + + //text string + while (true) { + //TODO: remove nested scenes. + //end of text, new line of the cursor position + if (*p == 13 || *p == 3 || *p == '\0') { + //text layout position + auto ascent = text->font->ascent * scale; + if (ascent > doc.bbox.size.y) ascent = doc.bbox.size.y; + Point layout = {doc.bbox.pos.x, doc.bbox.pos.y + ascent - doc.shift}; + + //adjust the layout + if (doc.justify == 1) layout.x += doc.bbox.size.x - (cursor.x * scale); //right aligned + else if (doc.justify == 2) layout.x += (doc.bbox.size.x * 0.5f) - (cursor.x * 0.5f * scale); //center aligned + + scene->translate(layout.x, layout.y); + scene->scale(scale); + + layer->scene->push(std::move(scene)); + + if (*p == '\0') break; + ++p; + + //new text group, single scene for each line + scene = Scene::gen(); + cursor.x = 0.0f; + cursor.y = ++line * (doc.height / scale); + } + //find the glyph + for (auto g = text->font->chars.begin(); g < text->font->chars.end(); ++g) { + auto glyph = *g; + //draw matched glyphs + if (!strncmp(glyph->code, p, glyph->len)) { + //TODO: caching? + auto shape = Shape::gen(); + for (auto g = glyph->children.begin(); g < glyph->children.end(); ++g) { + auto group = static_cast(*g); + for (auto p = group->children.begin(); p < group->children.end(); ++p) { + if (static_cast(*p)->pathset(frameNo, P(shape)->rs.path.cmds, P(shape)->rs.path.pts, nullptr, 0.0f)) { + P(shape)->update(RenderUpdateFlag::Path); + } + } + } + shape->fill(doc.color.rgb[0], doc.color.rgb[1], doc.color.rgb[2]); + shape->translate(cursor.x, cursor.y); + + if (doc.stroke.render) { + shape->strokeJoin(StrokeJoin::Round); + shape->strokeWidth(doc.stroke.width / scale); + shape->strokeFill(doc.stroke.color.rgb[0], doc.stroke.color.rgb[1], doc.stroke.color.rgb[2]); + } + + scene->push(std::move(shape)); + + p += glyph->len; + + //advance the cursor position horizontally + cursor.x += glyph->width + spacing + doc.tracking; + break; + } + } + } +} + + static void _updateMaskings(LottieLayer* layer, float frameNo, LottieExpressions* exps) { if (layer->masks.count == 0) return; @@ -1243,6 +1227,14 @@ static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo, L _updateSolid(layer); break; } + case LottieLayer::Image: { + _updateImage(layer); + break; + } + case LottieLayer::Text: { + _updateText(layer, frameNo); + break; + } default: { if (!layer->children.empty()) { Inlist contexts;