mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
lottie: Support the slot reverting feature
Implemented the ability to revert Lottie slots by calling override with nullptr. This functionality allows for the complete reversal of applied slots. usage: - `animation->override(nullptr)` Co-Authored-By: Hermet Park <hermet@lottiefiles.com>
This commit is contained in:
parent
48f58637e1
commit
b3f09cab6b
8 changed files with 112 additions and 34 deletions
|
@ -2357,7 +2357,7 @@ TVG_API Tvg_Animation* tvg_lottie_animation_new();
|
|||
* \brief Override the lottie properties through the slot data. (Experimental API)
|
||||
*
|
||||
* \param[in] animation The Tvg_Animation object to override the property with the slot.
|
||||
* \param[in] slot The lottie slot data in json.
|
||||
* \param[in] slot The Lottie slot data in json, or @c nullptr to reset.
|
||||
*
|
||||
* \return Tvg_Animation A new Tvg_LottieAnimation object.
|
||||
* \retval TVG_RESULT_SUCCESS Succeed.
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
/**
|
||||
* @brief Override Lottie properties using slot data.
|
||||
*
|
||||
* @param[in] slot The Lottie slot data in JSON format.
|
||||
* @param[in] slot The Lottie slot data in JSON format to override, or @c nullptr to reset.
|
||||
*
|
||||
* @retval Result::Success When succeed.
|
||||
* @retval Result::InsufficientCondition In case the animation is not loaded.
|
||||
|
|
|
@ -302,8 +302,12 @@ Paint* LottieLoader::paint()
|
|||
|
||||
bool LottieLoader::override(const char* slot)
|
||||
{
|
||||
if (!slot || !comp || comp->slots.count == 0) return false;
|
||||
if (!comp || comp->slots.count == 0) return false;
|
||||
|
||||
auto success = true;
|
||||
|
||||
//override slots
|
||||
if (slot) {
|
||||
//TODO: Crashed, does this necessary?
|
||||
auto temp = strdup(slot);
|
||||
|
||||
|
@ -311,19 +315,26 @@ bool LottieLoader::override(const char* slot)
|
|||
LottieParser parser(temp, dirName);
|
||||
|
||||
auto idx = 0;
|
||||
auto success = true;
|
||||
while (auto sid = parser.sid(idx == 0)) {
|
||||
for (auto s = comp->slots.begin(); s < comp->slots.end(); ++s) {
|
||||
if (strcmp((*s)->sid, sid)) continue;
|
||||
if (!parser.parse(*s)) success = false;
|
||||
if (!parser.apply(*s)) success = false;
|
||||
break;
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
|
||||
if (idx < 1) success = false;
|
||||
|
||||
free(temp);
|
||||
overriden = success;
|
||||
|
||||
//reset slots
|
||||
} else if (overriden) {
|
||||
for (auto s = comp->slots.begin(); s < comp->slots.end(); ++s) {
|
||||
(*s)->reset();
|
||||
}
|
||||
overriden = false;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ public:
|
|||
|
||||
char* dirName = nullptr; //base resource directory
|
||||
bool copy = false; //"content" is owned by this loader
|
||||
bool overriden = false; //overridden properties with slots.
|
||||
|
||||
LottieLoader();
|
||||
~LottieLoader();
|
||||
|
|
|
@ -632,19 +632,89 @@ struct LottieLayer : LottieGroup
|
|||
|
||||
struct LottieSlot
|
||||
{
|
||||
char* sid;
|
||||
Array<LottieObject*> objs;
|
||||
LottieProperty::Type type;
|
||||
struct Pair {
|
||||
LottieObject* obj;
|
||||
LottieProperty* prop;
|
||||
};
|
||||
|
||||
void assign(LottieObject* target)
|
||||
{
|
||||
//apply slot object to all targets
|
||||
for (auto pair = pairs.begin(); pair < pairs.end(); ++pair) {
|
||||
//backup the original properties before overwriting
|
||||
if (!overriden) {
|
||||
switch (type) {
|
||||
case LottieProperty::Type::ColorStop: {
|
||||
pair->prop = new LottieColorStop;
|
||||
*static_cast<LottieColorStop*>(pair->prop) = static_cast<LottieGradient*>(pair->obj)->colorStops;
|
||||
break;
|
||||
}
|
||||
case LottieProperty::Type::Color: {
|
||||
pair->prop = new LottieColor;
|
||||
*static_cast<LottieColor*>(pair->prop) = static_cast<LottieSolid*>(pair->obj)->color;
|
||||
break;
|
||||
}
|
||||
case LottieProperty::Type::TextDoc: {
|
||||
pair->prop = new LottieTextDoc;
|
||||
*static_cast<LottieTextDoc*>(pair->prop) = static_cast<LottieText*>(pair->obj)->doc;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
//FIXME: it overrides the object's whole properties, but it acutally needs a single property of it.
|
||||
pair->obj->override(target);
|
||||
}
|
||||
overriden = true;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
if (!overriden) return;
|
||||
|
||||
for (auto pair = pairs.begin(); pair < pairs.end(); ++pair) {
|
||||
switch (type) {
|
||||
case LottieProperty::Type::ColorStop: {
|
||||
static_cast<LottieGradient*>(pair->obj)->colorStops.release();
|
||||
static_cast<LottieGradient*>(pair->obj)->colorStops = *static_cast<LottieColorStop*>(pair->prop);
|
||||
break;
|
||||
}
|
||||
case LottieProperty::Type::Color: {
|
||||
static_cast<LottieSolid*>(pair->obj)->color.release();
|
||||
static_cast<LottieSolid*>(pair->obj)->color = *static_cast<LottieColor*>(pair->prop);
|
||||
break;
|
||||
}
|
||||
case LottieProperty::Type::TextDoc: {
|
||||
static_cast<LottieText*>(pair->obj)->doc.release();
|
||||
static_cast<LottieText*>(pair->obj)->doc = *static_cast<LottieTextDoc*>(pair->prop);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
delete(pair->prop);
|
||||
pair->prop = nullptr;
|
||||
}
|
||||
overriden = false;
|
||||
}
|
||||
|
||||
LottieSlot(char* sid, LottieObject* obj, LottieProperty::Type type) : sid(sid), type(type)
|
||||
{
|
||||
objs.push(obj);
|
||||
pairs.push({obj});
|
||||
}
|
||||
|
||||
~LottieSlot()
|
||||
{
|
||||
free(sid);
|
||||
if (!overriden) return;
|
||||
for (auto pair = pairs.begin(); pair < pairs.end(); ++pair) {
|
||||
delete(pair->prop);
|
||||
}
|
||||
}
|
||||
|
||||
char* sid;
|
||||
Array<Pair> pairs;
|
||||
LottieProperty::Type type;
|
||||
bool overriden = false;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -478,7 +478,7 @@ void LottieParser::parseProperty(T& prop, LottieObject* obj)
|
|||
//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);
|
||||
(*slot)->pairs.push({obj});
|
||||
return;
|
||||
}
|
||||
comp->slots.push(new LottieSlot(sid, obj, type));
|
||||
|
@ -1250,10 +1250,11 @@ const char* LottieParser::sid(bool first)
|
|||
}
|
||||
|
||||
|
||||
bool LottieParser::parse(LottieSlot* slot)
|
||||
bool LottieParser::apply(LottieSlot* slot)
|
||||
{
|
||||
enterObject();
|
||||
|
||||
//OPTIMIZE: we can create the property directly, without object
|
||||
LottieObject* obj = nullptr; //slot object
|
||||
|
||||
switch (slot->type) {
|
||||
|
@ -1278,10 +1279,7 @@ bool LottieParser::parse(LottieSlot* slot)
|
|||
|
||||
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);
|
||||
}
|
||||
slot->assign(obj);
|
||||
|
||||
delete(obj);
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
}
|
||||
|
||||
bool parse();
|
||||
bool parse(LottieSlot* slot);
|
||||
bool apply(LottieSlot* slot);
|
||||
const char* sid(bool first = false);
|
||||
|
||||
LottieComposition* comp = nullptr;
|
||||
|
|
|
@ -204,6 +204,7 @@ uint32_t bsearch(T* frames, float frameNo)
|
|||
struct LottieProperty
|
||||
{
|
||||
enum class Type : uint8_t { Point = 0, Float, Opacity, Color, PathSet, ColorStop, Position, TextDoc, Invalid };
|
||||
virtual ~LottieProperty() {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -258,7 +259,6 @@ struct LottieGenericProperty : LottieProperty
|
|||
T& operator=(const T& other)
|
||||
{
|
||||
//shallow copy, used for slot overriding
|
||||
delete(frames);
|
||||
if (other.frames) {
|
||||
frames = other.frames;
|
||||
const_cast<T&>(other).frames = nullptr;
|
||||
|
@ -467,7 +467,6 @@ struct LottieColorStop : LottieProperty
|
|||
LottieColorStop& operator=(const LottieColorStop& other)
|
||||
{
|
||||
//shallow copy, used for slot overriding
|
||||
release();
|
||||
if (other.frames) {
|
||||
frames = other.frames;
|
||||
const_cast<LottieColorStop&>(other).frames = nullptr;
|
||||
|
@ -613,7 +612,6 @@ struct LottieTextDoc : LottieProperty
|
|||
LottieTextDoc& operator=(const LottieTextDoc& other)
|
||||
{
|
||||
//shallow copy, used for slot overriding
|
||||
release();
|
||||
if (other.frames) {
|
||||
frames = other.frames;
|
||||
const_cast<LottieTextDoc&>(other).frames = nullptr;
|
||||
|
|
Loading…
Add table
Reference in a new issue