lottie/builder: ++size optimization

Replaced std::queue with inlist for optimizing binary size (-1.3kb).
This commit is contained in:
Hermet Park 2023-11-22 12:42:34 +09:00
parent 49137b3851
commit 815eb23856

View file

@ -20,11 +20,10 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include <queue>
#include "tvgCommon.h" #include "tvgCommon.h"
#include "tvgPaint.h" #include "tvgPaint.h"
#include "tvgShape.h" #include "tvgShape.h"
#include "tvgInlist.h"
#include "tvgLottieModel.h" #include "tvgLottieModel.h"
#include "tvgLottieBuilder.h" #include "tvgLottieBuilder.h"
#include "tvgTaskScheduler.h" #include "tvgTaskScheduler.h"
@ -51,6 +50,8 @@ struct RenderRepeater
struct RenderContext struct RenderContext
{ {
INLIST_ITEM(RenderContext);
Shape* propagator = nullptr; Shape* propagator = nullptr;
Shape* merging = nullptr; //merging shapes if possible (if shapes have same properties) Shape* merging = nullptr; //merging shapes if possible (if shapes have same properties)
LottieObject** begin = nullptr; //iteration entry point LottieObject** begin = nullptr; //iteration entry point
@ -83,7 +84,7 @@ struct RenderContext
}; };
static void _updateChildren(LottieGroup* parent, float frameNo, queue<RenderContext>& contexts); static void _updateChildren(LottieGroup* parent, float frameNo, Inlist<RenderContext>& contexts);
static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo); static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo);
static bool _buildComposition(LottieComposition* comp, LottieGroup* parent); static bool _buildComposition(LottieComposition* comp, LottieGroup* parent);
@ -177,30 +178,30 @@ static void _updateTransform(LottieLayer* layer, float frameNo)
} }
static void _updateTransform(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED queue<RenderContext>& contexts, RenderContext& ctx) static void _updateTransform(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
auto transform = static_cast<LottieTransform*>(*child); auto transform = static_cast<LottieTransform*>(*child);
if (!transform) return; if (!transform) return;
ctx.merging = nullptr; ctx->merging = nullptr;
Matrix matrix; Matrix matrix;
uint8_t opacity; uint8_t opacity;
if (!_updateTransform(transform, frameNo, false, matrix, opacity)) return; if (!_updateTransform(transform, frameNo, false, matrix, opacity)) return;
auto pmatrix = PP(ctx.propagator)->transform(); auto pmatrix = PP(ctx->propagator)->transform();
ctx.propagator->transform(pmatrix ? mathMultiply(pmatrix, &matrix) : matrix); ctx->propagator->transform(pmatrix ? mathMultiply(pmatrix, &matrix) : matrix);
ctx.propagator->opacity(MULTIPLY(opacity, PP(ctx.propagator)->opacity)); ctx->propagator->opacity(MULTIPLY(opacity, PP(ctx->propagator)->opacity));
//FIXME: preserve the stroke width. too workaround, need a better design. //FIXME: preserve the stroke width. too workaround, need a better design.
if (P(ctx.propagator)->rs.strokeWidth() > 0.0f) { if (P(ctx->propagator)->rs.strokeWidth() > 0.0f) {
auto denominator = sqrtf(matrix.e11 * matrix.e11 + matrix.e12 * matrix.e12); auto denominator = sqrtf(matrix.e11 * matrix.e11 + matrix.e12 * matrix.e12);
if (denominator > 1.0f) ctx.propagator->stroke(ctx.propagator->strokeWidth() / denominator); if (denominator > 1.0f) ctx->propagator->stroke(ctx->propagator->strokeWidth() / denominator);
} }
} }
static void _updateGroup(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED queue<RenderContext>& pcontexts, RenderContext& ctx) static void _updateGroup(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& pcontexts, RenderContext* ctx)
{ {
auto group = static_cast<LottieGroup*>(*child); auto group = static_cast<LottieGroup*>(*child);
@ -209,124 +210,124 @@ static void _updateGroup(LottieGroup* parent, LottieObject** child, float frameN
//Prepare render data //Prepare render data
group->scene = parent->scene; group->scene = parent->scene;
queue<RenderContext> contexts; Inlist<RenderContext> contexts;
contexts.push(ctx); contexts.back(new RenderContext(*ctx));
_updateChildren(group, frameNo, contexts); _updateChildren(group, frameNo, contexts);
contexts.free();
} }
static void _updateStroke(LottieStroke* stroke, float frameNo, RenderContext& ctx) static void _updateStroke(LottieStroke* stroke, float frameNo, RenderContext* ctx)
{ {
ctx.propagator->stroke(stroke->width(frameNo)); ctx->propagator->stroke(stroke->width(frameNo));
ctx.propagator->stroke(stroke->cap); ctx->propagator->stroke(stroke->cap);
ctx.propagator->stroke(stroke->join); ctx->propagator->stroke(stroke->join);
ctx.propagator->strokeMiterlimit(stroke->miterLimit); ctx->propagator->strokeMiterlimit(stroke->miterLimit);
if (stroke->dashattr) { if (stroke->dashattr) {
float dashes[2]; float dashes[2];
dashes[0] = stroke->dashSize(frameNo); dashes[0] = stroke->dashSize(frameNo);
dashes[1] = dashes[0] + stroke->dashGap(frameNo); dashes[1] = dashes[0] + stroke->dashGap(frameNo);
P(ctx.propagator)->strokeDash(dashes, 2, stroke->dashOffset(frameNo)); P(ctx->propagator)->strokeDash(dashes, 2, stroke->dashOffset(frameNo));
} else { } else {
ctx.propagator->stroke(nullptr, 0); ctx->propagator->stroke(nullptr, 0);
} }
} }
static bool _fragmentedStroking(LottieObject** child, queue<RenderContext>& contexts, RenderContext& ctx) static bool _fragmentedStroking(LottieObject** child, Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
if (!ctx.reqFragment) return false; if (!ctx->reqFragment) return false;
if (ctx.stroking) return true; if (ctx->stroking) return true;
contexts.push(ctx); contexts.back(new RenderContext(*ctx));
auto& fragment = contexts.back(); auto fragment = contexts.tail;
fragment.propagator->stroke(0.0f); fragment->propagator->stroke(0.0f);
fragment.begin = child - 1; fragment->begin = child - 1;
ctx.stroking = true; ctx->stroking = true;
return false; return false;
} }
static void _updateSolidStroke(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, queue<RenderContext>& contexts, RenderContext& ctx) static void _updateSolidStroke(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
if (_fragmentedStroking(child, contexts, ctx)) return; if (_fragmentedStroking(child, contexts, ctx)) return;
auto stroke = static_cast<LottieSolidStroke*>(*child); auto stroke = static_cast<LottieSolidStroke*>(*child);
ctx.merging = nullptr; ctx->merging = nullptr;
auto color = stroke->color(frameNo); auto color = stroke->color(frameNo);
ctx.propagator->stroke(color.rgb[0], color.rgb[1], color.rgb[2], stroke->opacity(frameNo)); ctx->propagator->stroke(color.rgb[0], color.rgb[1], color.rgb[2], stroke->opacity(frameNo));
_updateStroke(static_cast<LottieStroke*>(stroke), frameNo, ctx); _updateStroke(static_cast<LottieStroke*>(stroke), frameNo, ctx);
} }
static void _updateGradientStroke(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, queue<RenderContext>& contexts, RenderContext& ctx) static void _updateGradientStroke(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
if (_fragmentedStroking(child, contexts, ctx)) return; if (_fragmentedStroking(child, contexts, ctx)) return;
auto stroke = static_cast<LottieGradientStroke*>(*child); auto stroke = static_cast<LottieGradientStroke*>(*child);
ctx.merging = nullptr; ctx->merging = nullptr;
ctx.propagator->stroke(unique_ptr<Fill>(stroke->fill(frameNo))); ctx->propagator->stroke(unique_ptr<Fill>(stroke->fill(frameNo)));
_updateStroke(static_cast<LottieStroke*>(stroke), frameNo, ctx); _updateStroke(static_cast<LottieStroke*>(stroke), frameNo, ctx);
} }
static void _updateSolidFill(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED queue<RenderContext>& contexts, RenderContext& ctx) static void _updateSolidFill(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
if (ctx.stroking) return; if (ctx->stroking) return;
auto fill = static_cast<LottieSolidFill*>(*child); auto fill = static_cast<LottieSolidFill*>(*child);
ctx.merging = nullptr; ctx->merging = nullptr;
auto color = fill->color(frameNo); auto color = fill->color(frameNo);
ctx.propagator->fill(color.rgb[0], color.rgb[1], color.rgb[2], fill->opacity(frameNo)); ctx->propagator->fill(color.rgb[0], color.rgb[1], color.rgb[2], fill->opacity(frameNo));
ctx.propagator->fill(fill->rule); ctx->propagator->fill(fill->rule);
if (ctx.propagator->strokeWidth() > 0) ctx.propagator->order(true); if (ctx->propagator->strokeWidth() > 0) ctx->propagator->order(true);
} }
static Shape* _updateGradientFill(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED queue<RenderContext>& contexts, RenderContext& ctx) static Shape* _updateGradientFill(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
if (ctx.stroking) return nullptr; if (ctx->stroking) return nullptr;
auto fill = static_cast<LottieGradientFill*>(*child); auto fill = static_cast<LottieGradientFill*>(*child);
ctx.merging = nullptr; ctx->merging = nullptr;
//TODO: reuse the fill instance? //TODO: reuse the fill instance?
ctx.propagator->fill(unique_ptr<Fill>(fill->fill(frameNo))); ctx->propagator->fill(unique_ptr<Fill>(fill->fill(frameNo)));
ctx.propagator->fill(fill->rule); ctx->propagator->fill(fill->rule);
ctx.propagator->opacity(MULTIPLY(fill->opacity(frameNo), PP(ctx.propagator)->opacity)); ctx->propagator->opacity(MULTIPLY(fill->opacity(frameNo), PP(ctx->propagator)->opacity));
if (ctx.propagator->strokeWidth() > 0) ctx.propagator->order(true); if (ctx->propagator->strokeWidth() > 0) ctx->propagator->order(true);
return nullptr; return nullptr;
} }
static Shape* _draw(LottieGroup* parent, RenderContext& ctx) static Shape* _draw(LottieGroup* parent, RenderContext* ctx)
{ {
if (ctx.allowMerging && ctx.merging) return ctx.merging; if (ctx->allowMerging && ctx->merging) return ctx->merging;
auto shape = cast<Shape>(ctx.propagator->duplicate()); auto shape = cast<Shape>(ctx->propagator->duplicate());
ctx.merging = shape.get(); ctx->merging = shape.get();
parent->scene->push(std::move(shape)); parent->scene->push(std::move(shape));
return ctx.merging; return ctx->merging;
} }
//OPTIMIZE: path? //OPTIMIZE: path?
static void _repeat(LottieGroup* parent, unique_ptr<Shape> path, RenderContext& ctx) static void _repeat(LottieGroup* parent, unique_ptr<Shape> path, RenderContext* ctx)
{ {
auto repeater = ctx.repeater; auto repeater = ctx->repeater;
Array<Shape*> shapes; Array<Shape*> shapes;
shapes.reserve(repeater->cnt); shapes.reserve(repeater->cnt);
@ -334,7 +335,7 @@ static void _repeat(LottieGroup* parent, unique_ptr<Shape> path, RenderContext&
for (int i = 0; i < repeater->cnt; ++i) { for (int i = 0; i < repeater->cnt; ++i) {
auto multiplier = repeater->offset + static_cast<float>(i); auto multiplier = repeater->offset + static_cast<float>(i);
auto shape = static_cast<Shape*>(ctx.propagator->duplicate()); auto shape = static_cast<Shape*>(ctx->propagator->duplicate());
P(shape)->rs.path = P(path.get())->rs.path; P(shape)->rs.path = P(path.get())->rs.path;
auto opacity = repeater->interpOpacity ? mathLerp<uint8_t>(repeater->startOpacity, repeater->endOpacity, static_cast<float>(i + 1) / repeater->cnt) : repeater->startOpacity; auto opacity = repeater->interpOpacity ? mathLerp<uint8_t>(repeater->startOpacity, repeater->endOpacity, static_cast<float>(i + 1) / repeater->cnt) : repeater->startOpacity;
@ -350,7 +351,7 @@ static void _repeat(LottieGroup* parent, unique_ptr<Shape> path, RenderContext&
auto pm = PP(shape)->transform(); auto pm = PP(shape)->transform();
shape->transform(pm ? mathMultiply(&m, pm) : m); shape->transform(pm ? mathMultiply(&m, pm) : m);
if (ctx.roundness > 1.0f && P(shape)->rs.stroke) { if (ctx->roundness > 1.0f && P(shape)->rs.stroke) {
TVGERR("LOTTIE", "FIXME: Path roundesss should be applied properly!"); TVGERR("LOTTIE", "FIXME: Path roundesss should be applied properly!");
P(shape)->rs.stroke->join = StrokeJoin::Round; P(shape)->rs.stroke->join = StrokeJoin::Round;
} }
@ -371,21 +372,21 @@ static void _repeat(LottieGroup* parent, unique_ptr<Shape> path, RenderContext&
} }
static void _updateRect(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED queue<RenderContext>& contexts, RenderContext& ctx) static void _updateRect(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
auto rect= static_cast<LottieRect*>(*child); auto rect= static_cast<LottieRect*>(*child);
auto position = rect->position(frameNo); auto position = rect->position(frameNo);
auto size = rect->size(frameNo); auto size = rect->size(frameNo);
auto roundness = rect->radius(frameNo); auto roundness = rect->radius(frameNo);
if (ctx.roundness > roundness) roundness = ctx.roundness; if (ctx->roundness > roundness) roundness = ctx->roundness;
if (roundness > 0.0f) { if (roundness > 0.0f) {
if (roundness > size.x * 0.5f) roundness = size.x * 0.5f; if (roundness > size.x * 0.5f) roundness = size.x * 0.5f;
if (roundness > size.y * 0.5f) roundness = size.y * 0.5f; if (roundness > size.y * 0.5f) roundness = size.y * 0.5f;
} }
if (ctx.repeater) { if (ctx->repeater) {
auto path = Shape::gen(); auto path = Shape::gen();
path->appendRect(position.x - size.x * 0.5f, position.y - size.y * 0.5f, size.x, size.y, roundness, roundness); path->appendRect(position.x - size.x * 0.5f, position.y - size.y * 0.5f, size.x, size.y, roundness, roundness);
_repeat(parent, std::move(path), ctx); _repeat(parent, std::move(path), ctx);
@ -396,14 +397,14 @@ static void _updateRect(LottieGroup* parent, LottieObject** child, float frameNo
} }
static void _updateEllipse(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED queue<RenderContext>& contexts, RenderContext& ctx) static void _updateEllipse(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
auto ellipse= static_cast<LottieEllipse*>(*child); auto ellipse= static_cast<LottieEllipse*>(*child);
auto position = ellipse->position(frameNo); auto position = ellipse->position(frameNo);
auto size = ellipse->size(frameNo); auto size = ellipse->size(frameNo);
if (ctx.repeater) { if (ctx->repeater) {
auto path = Shape::gen(); auto path = Shape::gen();
path->appendCircle(position.x, position.y, size.x * 0.5f, size.y * 0.5f); path->appendCircle(position.x, position.y, size.x * 0.5f, size.y * 0.5f);
_repeat(parent, std::move(path), ctx); _repeat(parent, std::move(path), ctx);
@ -414,11 +415,11 @@ static void _updateEllipse(LottieGroup* parent, LottieObject** child, float fram
} }
static void _updatePath(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED queue<RenderContext>& contexts, RenderContext& ctx) static void _updatePath(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
auto path= static_cast<LottiePath*>(*child); auto path= static_cast<LottiePath*>(*child);
if (ctx.repeater) { if (ctx->repeater) {
auto p = Shape::gen(); auto p = Shape::gen();
path->pathset(frameNo, P(p)->rs.path.cmds, P(p)->rs.path.pts); path->pathset(frameNo, P(p)->rs.path.cmds, P(p)->rs.path.pts);
_repeat(parent, std::move(p), ctx); _repeat(parent, std::move(p), ctx);
@ -429,7 +430,7 @@ static void _updatePath(LottieGroup* parent, LottieObject** child, float frameNo
P(merging)->update(RenderUpdateFlag::Path); P(merging)->update(RenderUpdateFlag::Path);
} }
if (ctx.roundness > 1.0f && P(merging)->rs.stroke) { if (ctx->roundness > 1.0f && P(merging)->rs.stroke) {
TVGERR("LOTTIE", "FIXME: Path roundesss should be applied properly!"); TVGERR("LOTTIE", "FIXME: Path roundesss should be applied properly!");
P(merging)->rs.stroke->join = StrokeJoin::Round; P(merging)->rs.stroke->join = StrokeJoin::Round;
} }
@ -615,7 +616,7 @@ static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* tr
} }
static void _updatePolystar(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED queue<RenderContext>& contexts, RenderContext& ctx) static void _updatePolystar(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
auto star= static_cast<LottiePolyStar*>(*child); auto star= static_cast<LottiePolyStar*>(*child);
@ -628,7 +629,7 @@ static void _updatePolystar(LottieGroup* parent, LottieObject** child, float fra
auto identity = mathIdentity((const Matrix*)&matrix); auto identity = mathIdentity((const Matrix*)&matrix);
if (ctx.repeater) { if (ctx->repeater) {
auto p = Shape::gen(); auto p = Shape::gen();
if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, frameNo, p.get()); if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, frameNo, p.get());
else _updatePolygon(parent, star, identity ? nullptr : &matrix, frameNo, p.get()); else _updatePolygon(parent, star, identity ? nullptr : &matrix, frameNo, p.get());
@ -642,7 +643,7 @@ static void _updatePolystar(LottieGroup* parent, LottieObject** child, float fra
} }
static void _updateImage(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED queue<RenderContext>& contexts, RenderContext& ctx) static void _updateImage(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
auto image = static_cast<LottieImage*>(*child); auto image = static_cast<LottieImage*>(*child);
auto picture = image->picture; auto picture = image->picture;
@ -671,74 +672,74 @@ static void _updateImage(LottieGroup* parent, LottieObject** child, float frameN
PP(picture)->ref(); PP(picture)->ref();
} }
if (ctx.propagator) { if (ctx->propagator) {
if (auto matrix = PP(ctx.propagator)->transform()) { if (auto matrix = PP(ctx->propagator)->transform()) {
picture->transform(*matrix); picture->transform(*matrix);
} }
picture->opacity(PP(ctx.propagator)->opacity); picture->opacity(PP(ctx->propagator)->opacity);
} }
parent->scene->push(cast<Picture>(picture)); parent->scene->push(cast<Picture>(picture));
} }
static void _updateRoundedCorner(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED queue<RenderContext>& contexts, RenderContext& ctx) static void _updateRoundedCorner(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
auto roundedCorner= static_cast<LottieRoundedCorner*>(*child); auto roundedCorner= static_cast<LottieRoundedCorner*>(*child);
auto roundness = roundedCorner->radius(frameNo); auto roundness = roundedCorner->radius(frameNo);
if (ctx.roundness < roundness) ctx.roundness = roundness; if (ctx->roundness < roundness) ctx->roundness = roundness;
} }
static void _updateRepeater(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED queue<RenderContext>& contexts, RenderContext& ctx) static void _updateRepeater(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
auto repeater= static_cast<LottieRepeater*>(*child); auto repeater= static_cast<LottieRepeater*>(*child);
if (!ctx.repeater) ctx.repeater = new RenderRepeater(); if (!ctx->repeater) ctx->repeater = new RenderRepeater();
ctx.repeater->cnt = static_cast<int>(repeater->copies(frameNo)); ctx->repeater->cnt = static_cast<int>(repeater->copies(frameNo));
ctx.repeater->offset = repeater->offset(frameNo); ctx->repeater->offset = repeater->offset(frameNo);
ctx.repeater->position = repeater->position(frameNo); ctx->repeater->position = repeater->position(frameNo);
ctx.repeater->anchor = repeater->anchor(frameNo); ctx->repeater->anchor = repeater->anchor(frameNo);
ctx.repeater->scale = repeater->scale(frameNo); ctx->repeater->scale = repeater->scale(frameNo);
ctx.repeater->rotation = repeater->rotation(frameNo); ctx->repeater->rotation = repeater->rotation(frameNo);
ctx.repeater->startOpacity = repeater->startOpacity(frameNo); ctx->repeater->startOpacity = repeater->startOpacity(frameNo);
ctx.repeater->endOpacity = repeater->endOpacity(frameNo); ctx->repeater->endOpacity = repeater->endOpacity(frameNo);
ctx.repeater->inorder = repeater->inorder; ctx->repeater->inorder = repeater->inorder;
ctx.repeater->interpOpacity = (ctx.repeater->startOpacity == ctx.repeater->endOpacity) ? false : true; ctx->repeater->interpOpacity = (ctx->repeater->startOpacity == ctx->repeater->endOpacity) ? false : true;
ctx.merging = nullptr; ctx->merging = nullptr;
} }
static void _updateTrimpath(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED queue<RenderContext>& contexts, RenderContext& ctx) static void _updateTrimpath(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& contexts, RenderContext* ctx)
{ {
auto trimpath= static_cast<LottieTrimpath*>(*child); auto trimpath= static_cast<LottieTrimpath*>(*child);
float begin, end; float begin, end;
trimpath->segment(frameNo, begin, end); trimpath->segment(frameNo, begin, end);
if (P(ctx.propagator)->rs.stroke) { if (P(ctx->propagator)->rs.stroke) {
auto pbegin = P(ctx.propagator)->rs.stroke->trim.begin; auto pbegin = P(ctx->propagator)->rs.stroke->trim.begin;
auto pend = P(ctx.propagator)->rs.stroke->trim.end; auto pend = P(ctx->propagator)->rs.stroke->trim.end;
auto length = fabsf(pend - pbegin); auto length = fabsf(pend - pbegin);
begin = (length * begin) + pbegin; begin = (length * begin) + pbegin;
end = (length * end) + pbegin; end = (length * end) + pbegin;
} }
P(ctx.propagator)->strokeTrim(begin, end); P(ctx->propagator)->strokeTrim(begin, end);
if (trimpath->type == LottieTrimpath::Individual) ctx.allowMerging = false; if (trimpath->type == LottieTrimpath::Individual) ctx->allowMerging = false;
} }
static void _updateChildren(LottieGroup* parent, float frameNo, queue<RenderContext>& contexts) static void _updateChildren(LottieGroup* parent, float frameNo, Inlist<RenderContext>& contexts)
{ {
contexts.front().begin = parent->children.end() - 1; contexts.head->begin = parent->children.end() - 1;
while (contexts.size() > 0) { while (!contexts.empty()) {
auto& ctx = contexts.front(); auto ctx = contexts.front();
ctx.reqFragment = parent->reqFragment; ctx->reqFragment = parent->reqFragment;
for (auto child = ctx.begin; child >= parent->children.data; --child) { for (auto child = ctx->begin; child >= parent->children.data; --child) {
switch ((*child)->type) { switch ((*child)->type) {
case LottieObject::Group: { case LottieObject::Group: {
_updateGroup(parent, child, frameNo, contexts, ctx); _updateGroup(parent, child, frameNo, contexts, ctx);
@ -799,7 +800,7 @@ static void _updateChildren(LottieGroup* parent, float frameNo, queue<RenderCont
default: break; default: break;
} }
} }
contexts.pop(); delete(ctx);
} }
} }
@ -938,9 +939,10 @@ static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo)
} }
default: { default: {
if (!layer->children.empty()) { if (!layer->children.empty()) {
queue<RenderContext> contexts; Inlist<RenderContext> contexts;
contexts.emplace(); contexts.back(new RenderContext);
_updateChildren(layer, frameNo, contexts); _updateChildren(layer, frameNo, contexts);
contexts.free();
} }
break; break;
} }