mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-09 14:13:43 +00:00
lottie: Support the slot overriding feature
Internal model and parser modifications have been made to parse "sid" and retrieve their data into the LottieComposition. This will enable dynamic changes to the following Lottie objects: The slot feature will encompass these properties: - LottieSolidStroke - LottieSolidFill - LottieGradientStroke - LottieGradientFill - LottieTextDoc" Issue: https://github.com/thorvg/thorvg/issues/1808 Co-authored-by: Hermet Park <hermet@lottiefiles.com>
This commit is contained in:
parent
a361924887
commit
362e6faacb
7 changed files with 200 additions and 20 deletions
|
@ -300,6 +300,27 @@ Paint* LottieLoader::paint()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LottieLoader::override(const char* slot)
|
||||||
|
{
|
||||||
|
if (!slot) return false;
|
||||||
|
|
||||||
|
//parsing slot json
|
||||||
|
LottieParser parser(slot, dirName);
|
||||||
|
auto sid = parser.sid();
|
||||||
|
if (!sid) return false;
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
for (auto s = comp->slots.begin(); s < comp->slots.end(); ++s) {
|
||||||
|
if (!strcmp((*s)->sid, sid)) continue;
|
||||||
|
ret = parser.parse(*s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LottieLoader::frame(float no)
|
bool LottieLoader::frame(float no)
|
||||||
{
|
{
|
||||||
//no meaing to update if frame diff is less then 1ms
|
//no meaing to update if frame diff is less then 1ms
|
||||||
|
|
|
@ -53,6 +53,7 @@ public:
|
||||||
bool resize(Paint* paint, float w, float h) override;
|
bool resize(Paint* paint, float w, float h) override;
|
||||||
bool read() override;
|
bool read() override;
|
||||||
Paint* paint() override;
|
Paint* paint() override;
|
||||||
|
bool override(const char* slot);
|
||||||
|
|
||||||
//Frame Controls
|
//Frame Controls
|
||||||
bool frame(float no) override;
|
bool frame(float no) override;
|
||||||
|
|
|
@ -228,4 +228,9 @@ LottieComposition::~LottieComposition()
|
||||||
for (auto f = fonts.begin(); f < fonts.end(); ++f) {
|
for (auto f = fonts.begin(); f < fonts.end(); ++f) {
|
||||||
delete(*f);
|
delete(*f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//delete slots
|
||||||
|
for (auto s = slots.begin(); s < slots.end(); ++s) {
|
||||||
|
delete(*s);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -125,6 +125,11 @@ struct LottieObject
|
||||||
free(name);
|
free(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void override(LottieObject* prop)
|
||||||
|
{
|
||||||
|
TVGERR("LOTTIE", "Unsupported slot type");
|
||||||
|
}
|
||||||
|
|
||||||
char* name = nullptr;
|
char* name = nullptr;
|
||||||
Type type;
|
Type type;
|
||||||
bool statical = true; //no keyframes
|
bool statical = true; //no keyframes
|
||||||
|
@ -183,6 +188,12 @@ struct LottieText : LottieObject
|
||||||
LottieObject::type = LottieObject::Text;
|
LottieObject::type = LottieObject::Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void override(LottieObject* prop) override
|
||||||
|
{
|
||||||
|
this->doc = static_cast<LottieText*>(prop)->doc;
|
||||||
|
this->prepare();
|
||||||
|
}
|
||||||
|
|
||||||
LottieTextDoc doc;
|
LottieTextDoc doc;
|
||||||
LottieFont* font;
|
LottieFont* font;
|
||||||
LottieFloat spacing = 0.0f; //letter spacing
|
LottieFloat spacing = 0.0f; //letter spacing
|
||||||
|
@ -339,6 +350,12 @@ struct LottieSolidStroke : LottieSolid, LottieStroke
|
||||||
LottieObject::type = LottieObject::SolidStroke;
|
LottieObject::type = LottieObject::SolidStroke;
|
||||||
if (color.frames || opacity.frames || LottieStroke::dynamic()) statical = false;
|
if (color.frames || opacity.frames || LottieStroke::dynamic()) statical = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void override(LottieObject* prop) override
|
||||||
|
{
|
||||||
|
this->color = static_cast<LottieSolid*>(prop)->color;
|
||||||
|
this->prepare();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -350,6 +367,12 @@ struct LottieSolidFill : LottieSolid
|
||||||
if (color.frames || opacity.frames) statical = false;
|
if (color.frames || opacity.frames) statical = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void override(LottieObject* prop) override
|
||||||
|
{
|
||||||
|
this->color = static_cast<LottieSolid*>(prop)->color;
|
||||||
|
this->prepare();
|
||||||
|
}
|
||||||
|
|
||||||
FillRule rule = FillRule::Winding;
|
FillRule rule = FillRule::Winding;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -468,6 +491,12 @@ struct LottieGradientFill : LottieGradient
|
||||||
if (LottieGradient::prepare()) statical = false;
|
if (LottieGradient::prepare()) statical = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void override(LottieObject* prop) override
|
||||||
|
{
|
||||||
|
this->colorStops = static_cast<LottieGradient*>(prop)->colorStops;
|
||||||
|
this->prepare();
|
||||||
|
}
|
||||||
|
|
||||||
FillRule rule = FillRule::Winding;
|
FillRule rule = FillRule::Winding;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -479,6 +508,12 @@ struct LottieGradientStroke : LottieGradient, LottieStroke
|
||||||
LottieObject::type = LottieObject::GradientStroke;
|
LottieObject::type = LottieObject::GradientStroke;
|
||||||
if (LottieGradient::prepare() || LottieStroke::dynamic()) statical = false;
|
if (LottieGradient::prepare() || LottieStroke::dynamic()) statical = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void override(LottieObject* prop) override
|
||||||
|
{
|
||||||
|
this->colorStops = static_cast<LottieGradient*>(prop)->colorStops;
|
||||||
|
this->prepare();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -592,6 +627,24 @@ struct LottieLayer : LottieGroup
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieSlot
|
||||||
|
{
|
||||||
|
char* sid;
|
||||||
|
Array<LottieObject*> objs;
|
||||||
|
LottieProperty::Type type;
|
||||||
|
|
||||||
|
LottieSlot(char* sid, LottieObject* obj, LottieProperty::Type type) : sid(sid), type(type)
|
||||||
|
{
|
||||||
|
objs.push(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
~LottieSlot()
|
||||||
|
{
|
||||||
|
free(sid);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct LottieComposition
|
struct LottieComposition
|
||||||
{
|
{
|
||||||
~LottieComposition();
|
~LottieComposition();
|
||||||
|
@ -622,6 +675,7 @@ struct LottieComposition
|
||||||
Array<LottieObject*> assets;
|
Array<LottieObject*> assets;
|
||||||
Array<LottieInterpolator*> interpolators;
|
Array<LottieInterpolator*> interpolators;
|
||||||
Array<LottieFont*> fonts;
|
Array<LottieFont*> fonts;
|
||||||
|
Array<LottieSlot*> slots;
|
||||||
bool initiated = false;
|
bool initiated = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -334,6 +334,17 @@ void LottieParser::getInperpolatorPoint(Point& pt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void LottieParser::parseSlotProperty(T& prop)
|
||||||
|
{
|
||||||
|
while (auto key = nextObjectKey()) {
|
||||||
|
if (!strcmp(key, "p")) parseProperty(prop);
|
||||||
|
else skip(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool LottieParser::parseTangent(const char *key, LottieVectorFrame<T>& value)
|
bool LottieParser::parseTangent(const char *key, LottieVectorFrame<T>& value)
|
||||||
{
|
{
|
||||||
|
@ -456,13 +467,22 @@ void LottieParser::parsePropertyInternal(T& prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<LottieProperty::Type type, typename T>
|
||||||
void LottieParser::parseProperty(T& prop)
|
void LottieParser::parseProperty(T& prop, LottieObject* obj)
|
||||||
{
|
{
|
||||||
enterObject();
|
enterObject();
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (!strcmp(key, "k")) parsePropertyInternal(prop);
|
if (!strcmp(key, "k")) parsePropertyInternal(prop);
|
||||||
else skip(key);
|
else if (obj && !strcmp(key, "sid")) {
|
||||||
|
auto sid = getStringCopy();
|
||||||
|
//append object if the slot already exists.
|
||||||
|
for (auto slot = comp->slots.begin(); slot < comp->slots.end(); ++slot) {
|
||||||
|
if (strcmp((*slot)->sid, sid)) continue;
|
||||||
|
(*slot)->objs.push(obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
comp->slots.push(new LottieSlot(sid, obj, type));
|
||||||
|
} else skip(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,8 +572,8 @@ LottieSolidFill* LottieParser::parseSolidFill()
|
||||||
|
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (!strcmp(key, "nm")) fill->name = getStringCopy();
|
if (!strcmp(key, "nm")) fill->name = getStringCopy();
|
||||||
else if (!strcmp(key, "c")) parseProperty(fill->color);
|
else if (!strcmp(key, "c")) parseProperty<LottieProperty::Type::Color>(fill->color, fill);
|
||||||
else if (!strcmp(key, "o")) parseProperty(fill->opacity);
|
else if (!strcmp(key, "o")) parseProperty<LottieProperty::Type::Opacity>(fill->opacity, fill);
|
||||||
else if (!strcmp(key, "fillEnabled")) fill->hidden |= !getBool();
|
else if (!strcmp(key, "fillEnabled")) fill->hidden |= !getBool();
|
||||||
else if (!strcmp(key, "r")) fill->rule = getFillRule();
|
else if (!strcmp(key, "r")) fill->rule = getFillRule();
|
||||||
else if (!strcmp(key, "hd")) fill->hidden = getBool();
|
else if (!strcmp(key, "hd")) fill->hidden = getBool();
|
||||||
|
@ -590,9 +610,9 @@ LottieSolidStroke* LottieParser::parseSolidStroke()
|
||||||
if (!stroke) return nullptr;
|
if (!stroke) return nullptr;
|
||||||
|
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (!strcmp(key, "c")) parseProperty(stroke->color);
|
if (!strcmp(key, "c")) parseProperty<LottieProperty::Type::Color>(stroke->color, stroke);
|
||||||
else if (!strcmp(key, "o")) parseProperty(stroke->opacity);
|
else if (!strcmp(key, "o")) parseProperty<LottieProperty::Type::Opacity>(stroke->opacity, stroke);
|
||||||
else if (!strcmp(key, "w")) parseProperty(stroke->width);
|
else if (!strcmp(key, "w")) parseProperty<LottieProperty::Type::Float>(stroke->width, stroke);
|
||||||
else if (!strcmp(key, "lc")) stroke->cap = getStrokeCap();
|
else if (!strcmp(key, "lc")) stroke->cap = getStrokeCap();
|
||||||
else if (!strcmp(key, "lj")) stroke->join = getStrokeJoin();
|
else if (!strcmp(key, "lj")) stroke->join = getStrokeJoin();
|
||||||
else if (!strcmp(key, "ml")) stroke->miterLimit = getFloat();
|
else if (!strcmp(key, "ml")) stroke->miterLimit = getFloat();
|
||||||
|
@ -680,21 +700,23 @@ LottieRoundedCorner* LottieParser::parseRoundedCorner()
|
||||||
|
|
||||||
void LottieParser::parseGradient(LottieGradient* gradient, const char* key)
|
void LottieParser::parseGradient(LottieGradient* gradient, const char* key)
|
||||||
{
|
{
|
||||||
|
context->gradient = gradient;
|
||||||
|
|
||||||
if (!strcmp(key, "t")) gradient->id = getInt();
|
if (!strcmp(key, "t")) gradient->id = getInt();
|
||||||
else if (!strcmp(key, "o")) parseProperty(gradient->opacity);
|
else if (!strcmp(key, "o")) parseProperty<LottieProperty::Type::Opacity>(gradient->opacity, gradient);
|
||||||
else if (!strcmp(key, "g"))
|
else if (!strcmp(key, "g"))
|
||||||
{
|
{
|
||||||
enterObject();
|
enterObject();
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (!strcmp(key, "p")) gradient->colorStops.count = getInt();
|
if (!strcmp(key, "p")) gradient->colorStops.count = getInt();
|
||||||
else if (!strcmp(key, "k")) parseProperty(gradient->colorStops);
|
else if (!strcmp(key, "k")) parseProperty<LottieProperty::Type::ColorStop>(gradient->colorStops, gradient);
|
||||||
else skip(key);
|
else skip(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!strcmp(key, "s")) parseProperty(gradient->start);
|
else if (!strcmp(key, "s")) parseProperty<LottieProperty::Type::Point>(gradient->start, gradient);
|
||||||
else if (!strcmp(key, "e")) parseProperty(gradient->end);
|
else if (!strcmp(key, "e")) parseProperty<LottieProperty::Type::Point>(gradient->end, gradient);
|
||||||
else if (!strcmp(key, "h")) parseProperty(gradient->height);
|
else if (!strcmp(key, "h")) parseProperty<LottieProperty::Type::Float>(gradient->height, gradient);
|
||||||
else if (!strcmp(key, "a")) parseProperty(gradient->angle);
|
else if (!strcmp(key, "a")) parseProperty<LottieProperty::Type::Float>(gradient->angle, gradient);
|
||||||
else skip(key);
|
else skip(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -704,8 +726,6 @@ LottieGradientFill* LottieParser::parseGradientFill()
|
||||||
auto fill = new LottieGradientFill;
|
auto fill = new LottieGradientFill;
|
||||||
if (!fill) return nullptr;
|
if (!fill) return nullptr;
|
||||||
|
|
||||||
context->gradient = fill;
|
|
||||||
|
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (!strcmp(key, "nm")) fill->name = getStringCopy();
|
if (!strcmp(key, "nm")) fill->name = getStringCopy();
|
||||||
else if (!strcmp(key, "r")) fill->rule = getFillRule();
|
else if (!strcmp(key, "r")) fill->rule = getFillRule();
|
||||||
|
@ -724,8 +744,6 @@ LottieGradientStroke* LottieParser::parseGradientStroke()
|
||||||
auto stroke = new LottieGradientStroke;
|
auto stroke = new LottieGradientStroke;
|
||||||
if (!stroke) return nullptr;
|
if (!stroke) return nullptr;
|
||||||
|
|
||||||
context->gradient = stroke;
|
|
||||||
|
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (!strcmp(key, "nm")) stroke->name = getStringCopy();
|
if (!strcmp(key, "nm")) stroke->name = getStringCopy();
|
||||||
else if (!strcmp(key, "lc")) stroke->cap = getStrokeCap();
|
else if (!strcmp(key, "lc")) stroke->cap = getStrokeCap();
|
||||||
|
@ -1055,7 +1073,7 @@ void LottieParser::parseText(Array<LottieObject*>& parent)
|
||||||
auto text = new LottieText;
|
auto text = new LottieText;
|
||||||
|
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (!strcmp(key, "d")) parseProperty(text->doc);
|
if (!strcmp(key, "d")) parseProperty<LottieProperty::Type::TextDoc>(text->doc, text);
|
||||||
else if (!strcmp(key, "a")) parseTextRange(text);
|
else if (!strcmp(key, "a")) parseTextRange(text);
|
||||||
//else if (!strcmp(key, "p")) TVGLOG("LOTTIE", "Text Follow Path (p) is not supported");
|
//else if (!strcmp(key, "p")) TVGLOG("LOTTIE", "Text Follow Path (p) is not supported");
|
||||||
//else if (!strcmp(key, "m")) TVGLOG("LOTTIE", "Text Alignment Option (m) is not supported");
|
//else if (!strcmp(key, "m")) TVGLOG("LOTTIE", "Text Alignment Option (m) is not supported");
|
||||||
|
@ -1220,6 +1238,56 @@ void LottieParser::postProcess(Array<LottieGlyph*>& glyphes)
|
||||||
/* External Class Implementation */
|
/* External Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
|
const char* LottieParser::sid()
|
||||||
|
{
|
||||||
|
//verify json
|
||||||
|
if (!parseNext()) return nullptr;
|
||||||
|
enterObject();
|
||||||
|
return nextObjectKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LottieParser::parse(LottieSlot* slot)
|
||||||
|
{
|
||||||
|
enterObject();
|
||||||
|
|
||||||
|
LottieParser::Context context;
|
||||||
|
this->context = &context;
|
||||||
|
LottieObject* obj = nullptr; //slot object
|
||||||
|
|
||||||
|
switch (slot->type) {
|
||||||
|
case LottieProperty::Type::ColorStop: {
|
||||||
|
obj = new LottieGradient;
|
||||||
|
context.gradient = static_cast<LottieGradient*>(obj);
|
||||||
|
parseSlotProperty(static_cast<LottieGradient*>(obj)->colorStops);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LottieProperty::Type::Color: {
|
||||||
|
obj = new LottieSolid;
|
||||||
|
parseSlotProperty(static_cast<LottieSolid*>(obj)->color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LottieProperty::Type::TextDoc: {
|
||||||
|
obj = new LottieText;
|
||||||
|
parseSlotProperty(static_cast<LottieText*>(obj)->doc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!obj || Invalid()) return false;
|
||||||
|
|
||||||
|
//apply slot object to all targets
|
||||||
|
for (auto target = slot->objs.begin(); target < slot->objs.end(); ++target) {
|
||||||
|
(*target)->override(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(obj);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LottieParser::parse()
|
bool LottieParser::parse()
|
||||||
{
|
{
|
||||||
//verify json.
|
//verify json.
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include "tvgCommon.h"
|
#include "tvgCommon.h"
|
||||||
#include "tvgLottieParserHandler.h"
|
#include "tvgLottieParserHandler.h"
|
||||||
|
#include "tvgLottieProperty.h"
|
||||||
|
|
||||||
struct LottieParser : LookaheadParserHandler
|
struct LottieParser : LookaheadParserHandler
|
||||||
{
|
{
|
||||||
|
@ -35,6 +36,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse();
|
bool parse();
|
||||||
|
bool parse(LottieSlot* slot);
|
||||||
|
const char* sid();
|
||||||
|
|
||||||
LottieComposition* comp = nullptr;
|
LottieComposition* comp = nullptr;
|
||||||
const char* dirName = nullptr; //base resource directory
|
const char* dirName = nullptr; //base resource directory
|
||||||
|
@ -66,7 +69,8 @@ private:
|
||||||
template<typename T> bool parseTangent(const char *key, LottieScalarFrame<T>& value);
|
template<typename T> bool parseTangent(const char *key, LottieScalarFrame<T>& value);
|
||||||
template<typename T> void parseKeyFrame(T& prop);
|
template<typename T> void parseKeyFrame(T& prop);
|
||||||
template<typename T> void parsePropertyInternal(T& prop);
|
template<typename T> void parsePropertyInternal(T& prop);
|
||||||
template<typename T> void parseProperty(T& prop);
|
template<LottieProperty::Type type = LottieProperty::Type::Invalid, typename T> void parseProperty(T& prop, LottieObject* obj = nullptr);
|
||||||
|
template<typename T> void parseSlotProperty(T& prop);
|
||||||
|
|
||||||
LottieObject* parseObject();
|
LottieObject* parseObject();
|
||||||
LottieObject* parseAsset();
|
LottieObject* parseAsset();
|
||||||
|
|
|
@ -249,6 +249,15 @@ struct LottieGenericProperty : LottieProperty
|
||||||
return frame->interpolate(frame + 1, frameNo);
|
return frame->interpolate(frame + 1, frameNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
T& operator=(const T& other)
|
||||||
|
{
|
||||||
|
//shallow copy, used for slot overriding
|
||||||
|
delete(frames);
|
||||||
|
*this = other;
|
||||||
|
const_cast<T&>(other).frames = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
float angle(float frameNo) { return 0; }
|
float angle(float frameNo) { return 0; }
|
||||||
void prepare() {}
|
void prepare() {}
|
||||||
};
|
};
|
||||||
|
@ -433,6 +442,15 @@ struct LottieColorStop : LottieProperty
|
||||||
fill->colorStops(result.data, count);
|
fill->colorStops(result.data, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LottieColorStop& operator=(const LottieColorStop& other)
|
||||||
|
{
|
||||||
|
//shallow copy, used for slot overriding
|
||||||
|
delete(frames);
|
||||||
|
*this = other;
|
||||||
|
const_cast<LottieColorStop&>(other).frames = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void prepare() {}
|
void prepare() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -544,6 +562,15 @@ struct LottieTextDoc : LottieProperty
|
||||||
return frame->value;
|
return frame->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LottieTextDoc& operator=(const LottieTextDoc& other)
|
||||||
|
{
|
||||||
|
//shallow copy, used for slot overriding
|
||||||
|
delete(frames);
|
||||||
|
*this = other;
|
||||||
|
const_cast<LottieTextDoc&>(other).frames = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void prepare() {}
|
void prepare() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue