mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +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)
|
* \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] 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.
|
* \return Tvg_Animation A new Tvg_LottieAnimation object.
|
||||||
* \retval TVG_RESULT_SUCCESS Succeed.
|
* \retval TVG_RESULT_SUCCESS Succeed.
|
||||||
|
|
|
@ -25,7 +25,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Override Lottie properties using slot data.
|
* @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::Success When succeed.
|
||||||
* @retval Result::InsufficientCondition In case the animation is not loaded.
|
* @retval Result::InsufficientCondition In case the animation is not loaded.
|
||||||
|
|
|
@ -302,8 +302,12 @@ Paint* LottieLoader::paint()
|
||||||
|
|
||||||
bool LottieLoader::override(const char* slot)
|
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?
|
//TODO: Crashed, does this necessary?
|
||||||
auto temp = strdup(slot);
|
auto temp = strdup(slot);
|
||||||
|
|
||||||
|
@ -311,19 +315,26 @@ bool LottieLoader::override(const char* slot)
|
||||||
LottieParser parser(temp, dirName);
|
LottieParser parser(temp, dirName);
|
||||||
|
|
||||||
auto idx = 0;
|
auto idx = 0;
|
||||||
auto success = true;
|
|
||||||
while (auto sid = parser.sid(idx == 0)) {
|
while (auto sid = parser.sid(idx == 0)) {
|
||||||
for (auto s = comp->slots.begin(); s < comp->slots.end(); ++s) {
|
for (auto s = comp->slots.begin(); s < comp->slots.end(); ++s) {
|
||||||
if (strcmp((*s)->sid, sid)) continue;
|
if (strcmp((*s)->sid, sid)) continue;
|
||||||
if (!parser.parse(*s)) success = false;
|
if (!parser.apply(*s)) success = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++idx;
|
++idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx < 1) success = false;
|
if (idx < 1) success = false;
|
||||||
|
|
||||||
free(temp);
|
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;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ public:
|
||||||
|
|
||||||
char* dirName = nullptr; //base resource directory
|
char* dirName = nullptr; //base resource directory
|
||||||
bool copy = false; //"content" is owned by this loader
|
bool copy = false; //"content" is owned by this loader
|
||||||
|
bool overriden = false; //overridden properties with slots.
|
||||||
|
|
||||||
LottieLoader();
|
LottieLoader();
|
||||||
~LottieLoader();
|
~LottieLoader();
|
||||||
|
|
|
@ -632,19 +632,89 @@ struct LottieLayer : LottieGroup
|
||||||
|
|
||||||
struct LottieSlot
|
struct LottieSlot
|
||||||
{
|
{
|
||||||
char* sid;
|
struct Pair {
|
||||||
Array<LottieObject*> objs;
|
LottieObject* obj;
|
||||||
LottieProperty::Type type;
|
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)
|
LottieSlot(char* sid, LottieObject* obj, LottieProperty::Type type) : sid(sid), type(type)
|
||||||
{
|
{
|
||||||
objs.push(obj);
|
pairs.push({obj});
|
||||||
}
|
}
|
||||||
|
|
||||||
~LottieSlot()
|
~LottieSlot()
|
||||||
{
|
{
|
||||||
free(sid);
|
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.
|
//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) {
|
||||||
if (strcmp((*slot)->sid, sid)) continue;
|
if (strcmp((*slot)->sid, sid)) continue;
|
||||||
(*slot)->objs.push(obj);
|
(*slot)->pairs.push({obj});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
comp->slots.push(new LottieSlot(sid, obj, type));
|
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();
|
enterObject();
|
||||||
|
|
||||||
|
//OPTIMIZE: we can create the property directly, without object
|
||||||
LottieObject* obj = nullptr; //slot object
|
LottieObject* obj = nullptr; //slot object
|
||||||
|
|
||||||
switch (slot->type) {
|
switch (slot->type) {
|
||||||
|
@ -1278,10 +1279,7 @@ bool LottieParser::parse(LottieSlot* slot)
|
||||||
|
|
||||||
if (!obj || Invalid()) return false;
|
if (!obj || Invalid()) return false;
|
||||||
|
|
||||||
//apply slot object to all targets
|
slot->assign(obj);
|
||||||
for (auto target = slot->objs.begin(); target < slot->objs.end(); ++target) {
|
|
||||||
(*target)->override(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(obj);
|
delete(obj);
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse();
|
bool parse();
|
||||||
bool parse(LottieSlot* slot);
|
bool apply(LottieSlot* slot);
|
||||||
const char* sid(bool first = false);
|
const char* sid(bool first = false);
|
||||||
|
|
||||||
LottieComposition* comp = nullptr;
|
LottieComposition* comp = nullptr;
|
||||||
|
|
|
@ -204,6 +204,7 @@ uint32_t bsearch(T* frames, float frameNo)
|
||||||
struct LottieProperty
|
struct LottieProperty
|
||||||
{
|
{
|
||||||
enum class Type : uint8_t { Point = 0, Float, Opacity, Color, PathSet, ColorStop, Position, TextDoc, Invalid };
|
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)
|
T& operator=(const T& other)
|
||||||
{
|
{
|
||||||
//shallow copy, used for slot overriding
|
//shallow copy, used for slot overriding
|
||||||
delete(frames);
|
|
||||||
if (other.frames) {
|
if (other.frames) {
|
||||||
frames = other.frames;
|
frames = other.frames;
|
||||||
const_cast<T&>(other).frames = nullptr;
|
const_cast<T&>(other).frames = nullptr;
|
||||||
|
@ -467,7 +467,6 @@ struct LottieColorStop : LottieProperty
|
||||||
LottieColorStop& operator=(const LottieColorStop& other)
|
LottieColorStop& operator=(const LottieColorStop& other)
|
||||||
{
|
{
|
||||||
//shallow copy, used for slot overriding
|
//shallow copy, used for slot overriding
|
||||||
release();
|
|
||||||
if (other.frames) {
|
if (other.frames) {
|
||||||
frames = other.frames;
|
frames = other.frames;
|
||||||
const_cast<LottieColorStop&>(other).frames = nullptr;
|
const_cast<LottieColorStop&>(other).frames = nullptr;
|
||||||
|
@ -613,7 +612,6 @@ struct LottieTextDoc : LottieProperty
|
||||||
LottieTextDoc& operator=(const LottieTextDoc& other)
|
LottieTextDoc& operator=(const LottieTextDoc& other)
|
||||||
{
|
{
|
||||||
//shallow copy, used for slot overriding
|
//shallow copy, used for slot overriding
|
||||||
release();
|
|
||||||
if (other.frames) {
|
if (other.frames) {
|
||||||
frames = other.frames;
|
frames = other.frames;
|
||||||
const_cast<LottieTextDoc&>(other).frames = nullptr;
|
const_cast<LottieTextDoc&>(other).frames = nullptr;
|
||||||
|
|
Loading…
Add table
Reference in a new issue