lottie: ++slot overriding

- fixed the ommiting the duplicate keyframe data overriding
- code refactoring

issue: https://github.com/thorvg/thorvg/issues/2988
This commit is contained in:
Hermet Park 2024-11-25 21:44:48 +09:00 committed by Hermet Park
parent b453bd4f40
commit e811a513f2
5 changed files with 78 additions and 83 deletions

View file

@ -39,36 +39,10 @@ void LottieSlot::reset()
{ {
if (!overridden) return; if (!overridden) return;
auto shallow = pairs.count == 1 ? true : false;
for (auto pair = pairs.begin(); pair < pairs.end(); ++pair) { for (auto pair = pairs.begin(); pair < pairs.end(); ++pair) {
switch (type) { pair->obj->override(pair->prop, shallow, true);
case LottieProperty::Type::ColorStop: {
static_cast<LottieGradient*>(pair->obj)->colorStops.release();
static_cast<LottieGradient*>(pair->obj)->colorStops = *static_cast<LottieColorStop*>(pair->prop);
static_cast<LottieColorStop*>(pair->prop)->frames = nullptr;
break;
}
case LottieProperty::Type::Color: {
static_cast<LottieSolid*>(pair->obj)->color.release();
static_cast<LottieSolid*>(pair->obj)->color = *static_cast<LottieColor*>(pair->prop);
static_cast<LottieColor*>(pair->prop)->frames = nullptr;
break;
}
case LottieProperty::Type::TextDoc: {
static_cast<LottieText*>(pair->obj)->doc.release();
static_cast<LottieText*>(pair->obj)->doc = *static_cast<LottieTextDoc*>(pair->prop);
static_cast<LottieTextDoc*>(pair->prop)->frames = nullptr;
break;
}
case LottieProperty::Type::Image: {
static_cast<LottieImage*>(pair->obj)->data.release();
static_cast<LottieImage*>(pair->obj)->data = *static_cast<LottieBitmap*>(pair->prop);
static_cast<LottieBitmap*>(pair->prop)->b64Data = nullptr;
static_cast<LottieBitmap*>(pair->prop)->mimeType = nullptr;
static_cast<LottieImage*>(pair->obj)->prepare();
break;
}
default: break;
}
delete(pair->prop); delete(pair->prop);
pair->prop = nullptr; pair->prop = nullptr;
} }
@ -79,6 +53,7 @@ void LottieSlot::reset()
void LottieSlot::assign(LottieObject* target, bool byDefault) void LottieSlot::assign(LottieObject* target, bool byDefault)
{ {
auto copy = !overridden && !byDefault; auto copy = !overridden && !byDefault;
auto shallow = pairs.count == 1 ? true : false;
//apply slot object to all targets //apply slot object to all targets
for (auto pair = pairs.begin(); pair < pairs.end(); ++pair) { for (auto pair = pairs.begin(); pair < pairs.end(); ++pair) {
@ -86,27 +61,27 @@ void LottieSlot::assign(LottieObject* target, bool byDefault)
switch (type) { switch (type) {
case LottieProperty::Type::Opacity: { case LottieProperty::Type::Opacity: {
if (copy) pair->prop = new LottieOpacity(static_cast<LottieSolid*>(pair->obj)->opacity); if (copy) pair->prop = new LottieOpacity(static_cast<LottieSolid*>(pair->obj)->opacity);
pair->obj->override(&static_cast<LottieSolid*>(target)->opacity, byDefault); pair->obj->override(&static_cast<LottieSolid*>(target)->opacity, shallow, byDefault);
break; break;
} }
case LottieProperty::Type::Color: { case LottieProperty::Type::Color: {
if (copy) pair->prop = new LottieColor(static_cast<LottieSolid*>(pair->obj)->color); if (copy) pair->prop = new LottieColor(static_cast<LottieSolid*>(pair->obj)->color);
pair->obj->override(&static_cast<LottieSolid*>(target)->color, byDefault); pair->obj->override(&static_cast<LottieSolid*>(target)->color, shallow, byDefault);
break; break;
} }
case LottieProperty::Type::ColorStop: { case LottieProperty::Type::ColorStop: {
if (copy) pair->prop = new LottieColorStop(static_cast<LottieGradient*>(pair->obj)->colorStops); if (copy) pair->prop = new LottieColorStop(static_cast<LottieGradient*>(pair->obj)->colorStops);
pair->obj->override(&static_cast<LottieGradient*>(target)->colorStops, byDefault); pair->obj->override(&static_cast<LottieGradient*>(target)->colorStops, shallow, byDefault);
break; break;
} }
case LottieProperty::Type::TextDoc: { case LottieProperty::Type::TextDoc: {
if (copy) pair->prop = new LottieTextDoc(static_cast<LottieText*>(pair->obj)->doc); if (copy) pair->prop = new LottieTextDoc(static_cast<LottieText*>(pair->obj)->doc);
pair->obj->override(&static_cast<LottieText*>(target)->doc, byDefault); pair->obj->override(&static_cast<LottieText*>(target)->doc, shallow, byDefault);
break; break;
} }
case LottieProperty::Type::Image: { case LottieProperty::Type::Image: {
if (copy) pair->prop = new LottieBitmap(static_cast<LottieImage*>(pair->obj)->data); if (copy) pair->prop = new LottieBitmap(static_cast<LottieImage*>(pair->obj)->data);
pair->obj->override(&static_cast<LottieImage*>(target)->data, byDefault); pair->obj->override(&static_cast<LottieImage*>(target)->data, shallow, byDefault);
break; break;
} }
default: break; default: break;

View file

@ -158,7 +158,7 @@ struct LottieObject
{ {
} }
virtual void override(LottieProperty* prop, bool byDefault = false) virtual void override(LottieProperty* prop, bool shallow, bool byDefault)
{ {
TVGERR("LOTTIE", "Unsupported slot type"); TVGERR("LOTTIE", "Unsupported slot type");
} }
@ -284,10 +284,10 @@ struct LottieText : LottieObject, LottieRenderPooler<tvg::Shape>
LottieObject::type = LottieObject::Text; LottieObject::type = LottieObject::Text;
} }
void override(LottieProperty* prop, bool byDefault = false) override void override(LottieProperty* prop, bool shallow, bool byDefault = false) override
{ {
if (byDefault) doc.release(); if (byDefault) doc.release();
doc = *static_cast<LottieTextDoc*>(prop); doc.copy(*static_cast<LottieTextDoc*>(prop), shallow);
prepare(); prepare();
} }
@ -556,10 +556,10 @@ struct LottieSolidStroke : LottieSolid, LottieStroke
return LottieSolid::property(ix); return LottieSolid::property(ix);
} }
void override(LottieProperty* prop, bool byDefault) override void override(LottieProperty* prop, bool shallow, bool byDefault) override
{ {
if (byDefault) color.release(); if (byDefault) color.release();
color = *static_cast<LottieColor*>(prop); color.copy(*static_cast<LottieColor*>(prop), shallow);
prepare(); prepare();
} }
}; };
@ -572,14 +572,14 @@ struct LottieSolidFill : LottieSolid
LottieObject::type = LottieObject::SolidFill; LottieObject::type = LottieObject::SolidFill;
} }
void override(LottieProperty* prop, bool byDefault) override void override(LottieProperty* prop, bool shallow, bool byDefault) override
{ {
if (prop->type == LottieProperty::Type::Opacity) { if (prop->type == LottieProperty::Type::Opacity) {
if (byDefault) opacity.release(); if (byDefault) opacity.release();
opacity = *static_cast<LottieOpacity*>(prop); opacity.copy(*static_cast<LottieOpacity*>(prop), shallow);
} else if (prop->type == LottieProperty::Type::Color) { } else if (prop->type == LottieProperty::Type::Color) {
if (byDefault) color.release(); if (byDefault) color.release();
color = *static_cast<LottieColor*>(prop); color.copy(*static_cast<LottieColor*>(prop), shallow);
} }
prepare(); prepare();
} }
@ -618,6 +618,12 @@ struct LottieGradient : LottieObject
return nullptr; return nullptr;
} }
void override(LottieProperty* prop, bool shallow, bool byDefault = false) override
{
if (byDefault) colorStops.release();
colorStops.copy(*static_cast<LottieColorStop*>(prop), shallow);
}
uint32_t populate(ColorStop& color, size_t count); uint32_t populate(ColorStop& color, size_t count);
Fill* fill(float frameNo, LottieExpressions* exps); Fill* fill(float frameNo, LottieExpressions* exps);
@ -639,10 +645,9 @@ struct LottieGradientFill : LottieGradient
LottieGradient::prepare(); LottieGradient::prepare();
} }
void override(LottieProperty* prop, bool byDefault) override void override(LottieProperty* prop, bool shallow, bool byDefault) override
{ {
if (byDefault) colorStops.release(); LottieGradient::override(prop, shallow, byDefault);
colorStops = *static_cast<LottieColorStop*>(prop);
prepare(); prepare();
} }
@ -669,10 +674,9 @@ struct LottieGradientStroke : LottieGradient, LottieStroke
return LottieGradient::property(ix); return LottieGradient::property(ix);
} }
void override(LottieProperty* prop, bool byDefault = false) override void override(LottieProperty* prop, bool shallow, bool byDefault = false) override
{ {
if (byDefault) colorStops.release(); LottieGradient::override(prop, shallow, byDefault);
colorStops = *static_cast<LottieColorStop*>(prop);
prepare(); prepare();
} }
}; };
@ -682,10 +686,10 @@ struct LottieImage : LottieObject, LottieRenderPooler<tvg::Picture>
{ {
LottieBitmap data; LottieBitmap data;
void override(LottieProperty* prop, bool byDefault = false) override void override(LottieProperty* prop, bool shallow, bool byDefault = false) override
{ {
if (byDefault) data.release(); if (byDefault) data.release();
data = *static_cast<LottieBitmap*>(prop); data.copy(*static_cast<LottieBitmap*>(prop), shallow);
update(); update();
} }

View file

@ -487,7 +487,7 @@ void LottieParser::parsePropertyInternal(T& prop)
template<LottieProperty::Type type> template<LottieProperty::Type type>
void LottieParser::registerSlot(LottieObject* obj, char* sid) void LottieParser::registerSlot(LottieObject* obj, const char* sid)
{ {
//append object if the slot already exists. //append object if the slot already exists.
for (auto slot = comp->slots.begin(); slot < comp->slots.end(); ++slot) { for (auto slot = comp->slots.begin(); slot < comp->slots.end(); ++slot) {
@ -495,7 +495,7 @@ void LottieParser::registerSlot(LottieObject* obj, char* sid)
(*slot)->pairs.push({obj}); (*slot)->pairs.push({obj});
return; return;
} }
comp->slots.push(new LottieSlot(sid, obj, type)); comp->slots.push(new LottieSlot(strdup(sid), obj, type));
} }
@ -505,7 +505,7 @@ void LottieParser::parseProperty(T& prop, LottieObject* obj)
enterObject(); enterObject();
while (auto key = nextObjectKey()) { while (auto key = nextObjectKey()) {
if (KEY_AS("k")) parsePropertyInternal(prop); if (KEY_AS("k")) parsePropertyInternal(prop);
else if (obj && KEY_AS("sid")) registerSlot<type>(obj, getStringCopy()); else if (obj && KEY_AS("sid")) registerSlot<type>(obj, getString());
else if (KEY_AS("x")) prop.exp = _expression(getStringCopy(), comp, context.layer, context.parent, &prop); else if (KEY_AS("x")) prop.exp = _expression(getStringCopy(), comp, context.layer, context.parent, &prop);
else if (KEY_AS("ix")) prop.ix = getInt(); else if (KEY_AS("ix")) prop.ix = getInt();
else skip(key); else skip(key);
@ -760,7 +760,7 @@ void LottieParser::parseColorStop(LottieGradient* gradient)
while (auto key = nextObjectKey()) { while (auto key = nextObjectKey()) {
if (KEY_AS("p")) gradient->colorStops.count = getInt(); if (KEY_AS("p")) gradient->colorStops.count = getInt();
else if (KEY_AS("k")) parseProperty<LottieProperty::Type::ColorStop>(gradient->colorStops, gradient); else if (KEY_AS("k")) parseProperty<LottieProperty::Type::ColorStop>(gradient->colorStops, gradient);
else if (KEY_AS("sid")) registerSlot<LottieProperty::Type::ColorStop>(gradient, getStringCopy()); else if (KEY_AS("sid")) registerSlot<LottieProperty::Type::ColorStop>(gradient, getString());
else skip(key); else skip(key);
} }
} }
@ -964,7 +964,7 @@ LottieObject* LottieParser::parseAsset()
unsigned long id = 0; unsigned long id = 0;
//Used for Image Asset //Used for Image Asset
char* sid = nullptr; const char* sid = nullptr;
const char* data = nullptr; const char* data = nullptr;
const char* subPath = nullptr; const char* subPath = nullptr;
float width = 0.0f; float width = 0.0f;
@ -986,7 +986,7 @@ LottieObject* LottieParser::parseAsset()
else if (KEY_AS("w")) width = getFloat(); else if (KEY_AS("w")) width = getFloat();
else if (KEY_AS("h")) height = getFloat(); else if (KEY_AS("h")) height = getFloat();
else if (KEY_AS("e")) embedded = getInt(); else if (KEY_AS("e")) embedded = getInt();
else if (KEY_AS("sid")) sid = getStringCopy(); else if (KEY_AS("sid")) sid = getString();
else skip(key); else skip(key);
} }
if (data) { if (data) {

View file

@ -39,7 +39,7 @@ public:
bool apply(LottieSlot* slot, bool byDefault); bool apply(LottieSlot* slot, bool byDefault);
const char* sid(bool first = false); const char* sid(bool first = false);
void captureSlots(const char* key); void captureSlots(const char* key);
template<LottieProperty::Type type = LottieProperty::Type::Invalid> void registerSlot(LottieObject* obj, char* sid); template<LottieProperty::Type type = LottieProperty::Type::Invalid> void registerSlot(LottieObject* obj, const char* sid);
LottieComposition* comp = nullptr; LottieComposition* comp = nullptr;
const char* dirName = nullptr; //base resource directory const char* dirName = nullptr; //base resource directory

View file

@ -263,7 +263,8 @@ struct LottieGenericProperty : LottieProperty
LottieGenericProperty(const LottieGenericProperty<T>& rhs) LottieGenericProperty(const LottieGenericProperty<T>& rhs)
{ {
*this = rhs; copy(rhs);
type = rhs.type;
} }
~LottieGenericProperty() ~LottieGenericProperty()
@ -334,14 +335,17 @@ struct LottieGenericProperty : LottieProperty
return operator()(frameNo); return operator()(frameNo);
} }
LottieGenericProperty<T>& operator=(const LottieGenericProperty<T>& rhs) void copy(const LottieGenericProperty<T>& rhs, bool shallow = true)
{ {
//shallow copy, used for slot overriding
if (rhs.frames) { if (rhs.frames) {
if (shallow) {
frames = rhs.frames; frames = rhs.frames;
const_cast<LottieGenericProperty<T>&>(rhs).frames = nullptr; const_cast<LottieGenericProperty<T>&>(rhs).frames = nullptr;
} else {
frames = new Array<LottieScalarFrame<T>>;
*frames = *rhs.frames;
}
} else value = rhs.value; } else value = rhs.value;
return *this;
} }
float angle(float frameNo) { return 0; } float angle(float frameNo) { return 0; }
@ -513,7 +517,8 @@ struct LottieColorStop : LottieProperty
LottieColorStop(const LottieColorStop& rhs) LottieColorStop(const LottieColorStop& rhs)
{ {
*this = rhs; copy(rhs);
type = rhs.type;
} }
~LottieColorStop() ~LottieColorStop()
@ -620,20 +625,22 @@ struct LottieColorStop : LottieProperty
return fill->colorStops(result.data, count); return fill->colorStops(result.data, count);
} }
LottieColorStop& operator=(const LottieColorStop& rhs) void copy(const LottieColorStop& rhs, bool shallow = true)
{ {
//shallow copy, used for slot overriding
if (rhs.frames) { if (rhs.frames) {
if (shallow) {
frames = rhs.frames; frames = rhs.frames;
const_cast<LottieColorStop&>(rhs).frames = nullptr; const_cast<LottieColorStop&>(rhs).frames = nullptr;
} else {
frames = new Array<LottieScalarFrame<ColorStop>>;
*frames = *rhs.frames;
}
} else { } else {
value = rhs.value; value = rhs.value;
const_cast<LottieColorStop&>(rhs).value = ColorStop(); const_cast<LottieColorStop&>(rhs).value = ColorStop();
} }
populated = rhs.populated; populated = rhs.populated;
count = rhs.count; count = rhs.count;
return *this;
} }
void prepare() {} void prepare() {}
@ -751,7 +758,8 @@ struct LottieTextDoc : LottieProperty
LottieTextDoc(const LottieTextDoc& rhs) LottieTextDoc(const LottieTextDoc& rhs)
{ {
*this = rhs; copy(rhs);
type = rhs.type;
} }
~LottieTextDoc() ~LottieTextDoc()
@ -827,18 +835,21 @@ struct LottieTextDoc : LottieProperty
return frame->value; return frame->value;
} }
LottieTextDoc& operator=(const LottieTextDoc& rhs) void copy(const LottieTextDoc& rhs, bool shallow = true)
{ {
//shallow copy, used for slot overriding
if (rhs.frames) { if (rhs.frames) {
if (shallow) {
frames = rhs.frames; frames = rhs.frames;
const_cast<LottieTextDoc&>(rhs).frames = nullptr; const_cast<LottieTextDoc&>(rhs).frames = nullptr;
} else {
frames = new Array<LottieScalarFrame<TextDocument>>;
*frames = *rhs.frames;
}
} else { } else {
value = rhs.value; value = rhs.value;
const_cast<LottieTextDoc&>(rhs).value.text = nullptr; const_cast<LottieTextDoc&>(rhs).value.text = nullptr;
const_cast<LottieTextDoc&>(rhs).value.name = nullptr; const_cast<LottieTextDoc&>(rhs).value.name = nullptr;
} }
return *this;
} }
void prepare() {} void prepare() {}
@ -860,7 +871,8 @@ struct LottieBitmap : LottieProperty
LottieBitmap(const LottieBitmap& rhs) LottieBitmap(const LottieBitmap& rhs)
{ {
*this = rhs; copy(rhs);
type = rhs.type;
} }
~LottieBitmap() ~LottieBitmap()
@ -881,19 +893,23 @@ struct LottieBitmap : LottieProperty
uint32_t nearest(float time) override { return 0; } uint32_t nearest(float time) override { return 0; }
float frameNo(int32_t key) override { return 0; } float frameNo(int32_t key) override { return 0; }
LottieBitmap& operator=(const LottieBitmap& rhs) void copy(const LottieBitmap& rhs, bool shallow = true)
{ {
//shallow copy, used for slot overriding if (shallow) {
if (rhs.mimeType) b64Data = rhs.b64Data; b64Data = rhs.b64Data;
else path = rhs.path;
mimeType = rhs.mimeType; mimeType = rhs.mimeType;
} else {
//TODO: optimize here by avoiding data copy
TVGLOG("LOTTIE", "Shallow copy of the image data!");
b64Data = strdup(rhs.b64Data);
mimeType = strdup(rhs.mimeType);
}
size = rhs.size; size = rhs.size;
width = rhs.width; width = rhs.width;
height = rhs.height; height = rhs.height;
const_cast<LottieBitmap&>(rhs).b64Data = nullptr; const_cast<LottieBitmap&>(rhs).b64Data = nullptr;
const_cast<LottieBitmap&>(rhs).mimeType = nullptr; const_cast<LottieBitmap&>(rhs).mimeType = nullptr;
return *this;
} }
}; };