From 3c98cb5828fa054e1062ffca87eb3400272abaf4 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 17 Jan 2024 14:37:58 +0900 Subject: [PATCH] lottie: Fixed the issue with gradient filling. Previously, multiple gradients within a single group couldn't be accounted for during rendering. This fix addresses the scenario by fragmenting the rendering context. --- src/loaders/lottie/tvgLottieBuilder.cpp | 26 ++++++++++++------------- src/loaders/lottie/tvgLottieModel.cpp | 10 ++++++++-- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index bdf0371c..f2c963d4 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -59,7 +59,7 @@ struct RenderContext LottieObject** begin = nullptr; //iteration entry point RenderRepeater* repeater = nullptr; float roundness = 0.0f; - bool stroking = false; //context has been separated by the stroking + bool fragmenting = false; //render context has been fragmented by filling bool reqFragment = false; //requirment to fragment the render context bool allowMerging = true; //individual trimpath doesn't allow merging shapes @@ -239,16 +239,18 @@ static void _updateStroke(LottieStroke* stroke, float frameNo, RenderContext* ct } -static bool _fragmentedStroking(LottieObject** child, Inlist& contexts, RenderContext* ctx) +static bool _fragmented(LottieObject** child, Inlist& contexts, RenderContext* ctx) { if (!ctx->reqFragment) return false; - if (ctx->stroking) return true; + if (ctx->fragmenting) return true; contexts.back(new RenderContext(*ctx)); auto fragment = contexts.tail; fragment->propagator->stroke(0.0f); fragment->begin = child - 1; - ctx->stroking = true; + ctx->fragmenting = true; + + TVGERR("LOTTIE", "Rendering is fragmented."); return false; } @@ -256,7 +258,7 @@ static bool _fragmentedStroking(LottieObject** child, Inlist& con static void _updateSolidStroke(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx) { - if (_fragmentedStroking(child, contexts, ctx)) return; + if (_fragmented(child, contexts, ctx)) return; auto stroke = static_cast(*child); @@ -269,7 +271,7 @@ static void _updateSolidStroke(TVG_UNUSED LottieGroup* parent, LottieObject** ch static void _updateGradientStroke(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx) { - if (_fragmentedStroking(child, contexts, ctx)) return; + if (_fragmented(child, contexts, ctx)) return; auto stroke = static_cast(*child); @@ -281,12 +283,11 @@ static void _updateGradientStroke(TVG_UNUSED LottieGroup* parent, LottieObject** static void _updateSolidFill(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, RenderContext* ctx) { - if (ctx->stroking) return; + if (_fragmented(child, contexts, ctx)) return; auto fill = static_cast(*child); ctx->merging = nullptr; - auto color = fill->color(frameNo); ctx->propagator->fill(color.rgb[0], color.rgb[1], color.rgb[2], fill->opacity(frameNo)); ctx->propagator->fill(fill->rule); @@ -297,12 +298,11 @@ static void _updateSolidFill(TVG_UNUSED LottieGroup* parent, LottieObject** chil static Shape* _updateGradientFill(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, RenderContext* ctx) { - if (ctx->stroking) return nullptr; + if (_fragmented(child, contexts, ctx)) return nullptr; auto fill = static_cast(*child); ctx->merging = nullptr; - //TODO: reuse the fill instance? ctx->propagator->fill(unique_ptr(fill->fill(frameNo))); ctx->propagator->fill(fill->rule); @@ -883,7 +883,7 @@ static void _updateChildren(LottieGroup* parent, float frameNo, Inlistchildren.count == 0) return; + if (precomp->children.empty()) return; frameNo = precomp->remap(frameNo); @@ -1000,9 +1000,7 @@ static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo) switch (layer->type) { case LottieLayer::Precomp: { - if (!layer->children.empty()) { - _updatePrecomp(layer, frameNo); - } + _updatePrecomp(layer, frameNo); break; } case LottieLayer::Solid: { diff --git a/src/loaders/lottie/tvgLottieModel.cpp b/src/loaders/lottie/tvgLottieModel.cpp index 404cb4ac..e82e9cc1 100644 --- a/src/loaders/lottie/tvgLottieModel.cpp +++ b/src/loaders/lottie/tvgLottieModel.cpp @@ -139,6 +139,7 @@ void LottieGroup::prepare(LottieObject::Type type) if (children.count == 0) return; size_t strokeCnt = 0; + size_t fillCnt = 0; for (auto c = children.end() - 1; c >= children.data; --c) { if (reqFragment && !statical) break; @@ -148,10 +149,15 @@ void LottieGroup::prepare(LottieObject::Type type) Multiple stroking or grouping with a stroking would occur this. This fragment resolves the overlapped stroke outlines. */ if (reqFragment) continue; - if (child->type == LottieObject::SolidStroke || child->type == LottieObject::GradientStroke) { + if (child->type == LottieObject::Group) { + if (strokeCnt > 0 || fillCnt > 0) reqFragment = true; + } else if (child->type == LottieObject::SolidStroke || child->type == LottieObject::GradientStroke) { if (strokeCnt > 0) reqFragment = true; else ++strokeCnt; - } else if (child->type == LottieObject::Group && strokeCnt > 0) reqFragment = true; + } else if (child->type == LottieObject::SolidFill || child->type == LottieObject::GradientFill) { + if (fillCnt > 0) reqFragment = true; + else ++fillCnt; + } } }