{
// 1. create layer item
for (auto &i : mLayerData->mChildren) {
- LOTLayerData *layerModel = dynamic_cast<LOTLayerData *>(i.get());
- if (layerModel) {
- auto layerItem = LOTCompItem::createLayerItem(layerModel);
- if (layerItem) mLayers.push_back(std::move(layerItem));
- }
+ LOTLayerData *layerModel = static_cast<LOTLayerData *>(i.get());
+ auto layerItem = LOTCompItem::createLayerItem(layerModel);
+ if (layerItem) mLayers.push_back(std::move(layerItem));
}
// 2. update parent layer
#include <cassert>
#include <stack>
-class LottieRepeaterProcesser : public LOTDataVisitor {
+class LottieRepeaterProcesser {
public:
- void visit(LOTCompositionData *) override {}
- void visit(LOTLayerData *) override {}
- void visit(LOTTransformData *) override {}
- void visit(LOTShapeGroupData *) override {}
- void visit(LOTShapeData *) override {}
- void visit(LOTRectData *) override {}
- void visit(LOTEllipseData *) override {}
- void visit(LOTTrimData *) override {}
- void visit(LOTRepeaterData *) override { mRepeaterFound = true; }
- void visit(LOTFillData *) override {}
- void visit(LOTStrokeData *) override {}
- void visit(LOTPolystarData *) override {}
- void visitChildren(LOTGroupData *obj) override
+ void visitChildren(LOTGroupData *obj)
{
for (const auto& child : obj->mChildren) {
- child.get()->accept(this);
- if (mRepeaterFound) {
+ if (child->mType == LOTData::Type::Repeater) {
LOTRepeaterData *repeater =
static_cast<LOTRepeaterData *>(child.get());
std::shared_ptr<LOTShapeGroupData> sharedShapeGroup =
// the repeater object.
for (const auto& cpChild : obj->mChildren) {
if (cpChild == child) break;
- // there shouldn't be any trim object left in the child list
- if (cpChild.get()->type() == LOTData::Type::Trim) {
- assert(0);
- }
shapeGroup->mChildren.push_back(cpChild);
}
- mRepeaterFound = false;
}
}
}
-public:
- bool mRepeaterFound{false};
+ void visit(LOTData *obj) {
+ switch (obj->mType) {
+ case LOTData::Type::Repeater:
+ case LOTData::Type::ShapeGroup:
+ case LOTData::Type::Layer:{
+ visitChildren(static_cast<LOTGroupData *>(obj));
+ break;
+ }
+ default:
+ break;
+ }
+ }
};
void LOTCompositionData::processRepeaterObjects()
{
LottieRepeaterProcesser visitor;
- accept(&visitor);
+ visitor.visit(mRootLayer.get());
}
VMatrix LOTTransformData::matrix(int frameNo) const
class LOTPolystarData;
class LOTMaskData;
-class LOTDataVisitor
-{
-public:
- virtual ~LOTDataVisitor() = default;
- virtual void visit(LOTCompositionData *) = 0;
- virtual void visit(LOTLayerData *) = 0;
- virtual void visit(LOTTransformData *) = 0;
- virtual void visit(LOTShapeGroupData *) = 0;
- virtual void visit(LOTShapeData *) = 0;
- virtual void visit(LOTRectData *) = 0;
- virtual void visit(LOTEllipseData *) = 0;
- virtual void visit(LOTPolystarData *) {};
- virtual void visit(LOTTrimData *) = 0;
- virtual void visit(LOTRepeaterData *) = 0;
- virtual void visit(LOTFillData *) = 0;
- virtual void visit(LOTStrokeData *) = 0;
- virtual void visit(LOTGFillData *){};
- virtual void visit(LOTGStrokeData *){};
- virtual void visitChildren(LOTGroupData *) = 0;
-};
-
enum class MatteType
{
None = 0,
Repeater
};
LOTData(LOTData::Type type): mType(type){}
- virtual ~LOTData()= default;
inline LOTData::Type type() const {return mType;}
- virtual void accept(LOTDataVisitor *){}
bool isStatic() const{return mStatic;}
void setStatic(bool value) {mStatic = value;}
public:
bool mStatic{true};
- LOTData::Type mType;
+ LOTData::Type mType;
};
class LOTGroupData: public LOTData
{
public:
LOTShapeGroupData():LOTGroupData(LOTData::Type::ShapeGroup){}
- void accept(LOTDataVisitor *visitor) override
- {visitor->visit(this); visitor->visitChildren(this);}
};
class LOTLayerData;
int solidWidth() const noexcept{return mSolidLayer.mWidth;}
int solidHeight() const noexcept{return mSolidLayer.mHeight;}
LottieColor solidColor() const noexcept{return mSolidLayer.mColor;}
- void accept(LOTDataVisitor *visitor) override
- {visitor->visit(this); visitor->visitChildren(this);}
public:
struct SolidLayer {
int mWidth{0};
long endFrame() const {return mEndFrame;}
VSize size() const {return mSize;}
void processRepeaterObjects();
- void accept(LOTDataVisitor *visitor) override
- {visitor->visit(this); mRootLayer->accept(visitor);}
public:
std::string mVersion;
VSize mSize;
float opacity(int frameNo) const;
void cacheMatrix();
bool staticMatrix() const {return mStaticMatrix;}
- void accept(LOTDataVisitor *visitor) final
- {visitor->visit(this);}
private:
VMatrix computeMatrix(int frameNo) const;
public:
LOTFillData():LOTData(LOTData::Type::Fill){}
float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
FillRule fillRule() const {return mFillRule;}
- void accept(LOTDataVisitor *visitor) final
- {visitor->visit(this);}
public:
FillRule mFillRule{FillRule::Winding}; /* "r" */
LOTAnimatable<LottieColor> mColor; /* "c" */
float meterLimit() const{return mMeterLimit;}
bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
int getDashInfo(int frameNo, float *array) const;
- void accept(LOTDataVisitor *visitor) final
- {visitor->visit(this);}
public:
LOTAnimatable<LottieColor> mColor; /* "c" */
LOTAnimatable<int> mOpacity{100}; /* "o" */
public:
LOTGFillData():LOTGradient(LOTData::Type::GFill){}
FillRule fillRule() const {return mFillRule;}
- void accept(LOTDataVisitor *visitor) final
- {visitor->visit(this);}
public:
FillRule mFillRule{FillRule::Winding}; /* "r" */
};
float meterLimit() const{return mMeterLimit;}
bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
int getDashInfo(int frameNo, float *array) const;
- void accept(LOTDataVisitor *visitor) final
- {visitor->visit(this);}
public:
LOTAnimatable<float> mWidth; /* "w" */
CapStyle mCapStyle; /* "lc" */
public:
LOTShapeData():LOTPath(LOTData::Type::Shape){}
void process();
- void accept(LOTDataVisitor *visitor) final
- {visitor->visit(this);}
public:
LOTAnimatable<LottieShapeData> mShape;
};
{
public:
LOTRectData():LOTPath(LOTData::Type::Rect){}
- void accept(LOTDataVisitor *visitor) final
- {visitor->visit(this);}
public:
LOTAnimatable<VPointF> mPos;
LOTAnimatable<VPointF> mSize;
class LOTEllipseData : public LOTPath
{
public:
- void accept(LOTDataVisitor *visitor) final
- {visitor->visit(this);}
LOTEllipseData():LOTPath(LOTData::Type::Ellipse){}
public:
LOTAnimatable<VPointF> mPos;
Polygon = 2
};
LOTPolystarData():LOTPath(LOTData::Type::Polystar){}
- void accept(LOTDataVisitor *visitor) final
- {visitor->visit(this);}
public:
LOTPolystarData::PolyType mType{PolyType::Polygon};
LOTAnimatable<VPointF> mPos;
Individually
};
LOTTrimData():LOTData(LOTData::Type::Trim){}
- void accept(LOTDataVisitor *visitor) final
- {visitor->visit(this);}
float start(int frameNo) const {return mStart.value(frameNo)/100.0f;}
float end(int frameNo) const {return mEnd.value(frameNo)/100.0f;}
float offset(int frameNo) const {return fmod(mOffset.value(frameNo), 360.0f)/ 360.0f;}
{
public:
LOTRepeaterData():LOTGroupData(LOTData::Type::Repeater){}
- void accept(LOTDataVisitor *visitor) final
- {visitor->visit(this); visitor->visitChildren(this);}
public:
LOTAnimatable<float> mCopies{0};
LOTAnimatable<float> mOffset{0};
RAPIDJSON_ASSERT(PeekType() == kObjectType);
parseObject(group);
}
- group->mTransform = std::dynamic_pointer_cast<LOTTransformData>(
- group->mChildren.back());
- group->mChildren.pop_back();
+ if (group->mChildren.back()->mType == LOTData::Type::Transform) {
+ group->mTransform = std::static_pointer_cast<LOTTransformData>(
+ group->mChildren.back());
+ group->mChildren.pop_back();
+ }
} else {
Skip(key);
}
}
}
-class LOTDataInspector : public LOTDataVisitor {
+#ifdef DEBUG_PARSER
+
+class LOTDataInspector {
public:
- void visit(LOTCompositionData *obj) override
+ void visit(LOTCompositionData *obj)
{
vDebug << "[COMP_START:: static:" << obj->isStatic()
<< " v:" << obj->mVersion << " [{ stFm endFm fmRate } { "
<< obj->mStartFrame << " " << obj->mEndFrame << " }]\n";
+ visit(obj->mRootLayer.get());
+ vDebug << "[COMP End ]\n";
}
- void visit(LOTLayerData *obj) override
+ void visit(LOTLayerData *obj)
{
vDebug << "[LAYER_START:: type:" << layerType(obj->mLayerType)
<< " id:" << obj->mId << " Pid:" << obj->mParentId
<< "[{ stFm endFm stTm tmStrch } { " << obj->mInFrame << " "
<< obj->mOutFrame << " " << obj->mStartFrame << " "
<< obj->mTimeStreatch << " }]";
+
+ visitChildren(static_cast<LOTGroupData *>(obj));
+
+ vDebug << "[LAYER_END:: type:"
+ << layerType(obj->mLayerType).c_str()
+ << " id:" << obj->mId << "\n";
}
- void visit(LOTTransformData *t) override
- {
- vDebug << "[TRANSFORM: static: " << t->isStatic() << " ]";
- }
- void visit(LOTShapeGroupData *o) override
- {
- vDebug << "[GROUP_START:: static:" << o->isStatic() << "]";
- }
- void visit(LOTShapeData *s) override
- {
- vDebug << "[SHAPE: static:" << s->isStatic() << "]";
- }
- void visit(LOTRectData *r) override
- {
- vDebug << "[RECT: static:" << r->isStatic() << "]";
- }
- void visit(LOTEllipseData *e) override
- {
- vDebug << "[ELLIPSE: static:" << e->isStatic() << "]";
- }
- void visit(LOTPolystarData *e) override
- {
- vDebug << "[POLYSTAR: static:" << e->isStatic() << "]";
- }
- void visit(LOTTrimData *t) override
- {
- vDebug << "[TRIM: static: " << t->isStatic() << " ]";
- }
- void visit(LOTRepeaterData *r) override
- {
- vDebug << "[REPEATER: static:" << r->isStatic() << "]";
- }
- void visit(LOTFillData *f) override
- {
- vDebug << "[FILL: static:" << f->isStatic() << "]";
- }
- void visit(LOTGFillData *f) override
- {
- vDebug << "[GFILL: static:" << f->isStatic()
- << " ty:" << f->mGradientType << " s:" << f->mStartPoint.value(0)
- << " e:" << f->mEndPoint.value(0) << "]";
- }
- void visit(LOTGStrokeData *f) override
- {
- vDebug << "[GSTROKE: static:" << f->isStatic() << "]";
- }
- void visit(LOTStrokeData *s) override
+ void visitChildren(LOTGroupData *obj)
{
- vDebug << "[STROKE: static:" << s->isStatic() << "]";
+ for (const auto& child : obj->mChildren) visit(child.get());
}
- void visitChildren(LOTGroupData *obj) override
- {
- for (const auto& child : obj->mChildren) child.get()->accept(this);
- switch (obj->type()) {
- case LOTData::Type::Layer: {
- LOTLayerData *layer = static_cast<LOTLayerData *>(obj);
- vDebug << "[LAYER_END:: type:"
- << layerType(layer->mLayerType).c_str()
- << " id:" << layer->mId << "\n";
+
+ void visit(LOTData *obj) {
+ switch (obj->mType) {
+ case LOTData::Type::Repeater: {
+ vDebug << "[REPEATER_START]";
+ visitChildren(static_cast<LOTGroupData *>(obj));
+ vDebug << "[REPEATER_END]";
break;
}
- case LOTData::Type::ShapeGroup:
+ case LOTData::Type::ShapeGroup: {
+ vDebug << "[GROUP_START:: static:" << obj->isStatic() << "]";
+ visitChildren(static_cast<LOTGroupData *>(obj));
vDebug << "[GROUP_END]";
break;
- case LOTData::Type::Composition:
- vDebug << "[COMP End ]\n";
+ }
+ case LOTData::Type::Layer:{
+ visit(static_cast<LOTLayerData *>(obj));
+ break;
+ }
+ case LOTData::Type::Trim:{
+ vDebug << "[TRIM: static: " << obj->isStatic() << " ]";
+ break;
+ }
+ case LOTData::Type::Rect:{
+ vDebug << "[RECT: static:" << obj->isStatic() << "]";
+ break;
+ }
+ case LOTData::Type::Ellipse:{
+ vDebug << "[RECT: static:" << obj->isStatic() << "]";
+ break;
+ }
+ case LOTData::Type::Shape:{
+ vDebug << "[SHAPE: static:" << obj->isStatic() << "]";
+ break;
+ }
+ case LOTData::Type::Polystar:{
+ vDebug << "[POLYSTAR: static:" << obj->isStatic() << "]";
+ break;
+ }
+ case LOTData::Type::Transform:{
+ vDebug << "[TRANSFORM: static: " << obj->isStatic() << " ]";
+ break;
+ }
+ case LOTData::Type::Stroke:{
+ vDebug << "[SHAPE: static:" << obj->isStatic() << "]";
break;
- case LOTData::Type::Repeater:
- vDebug << "[REPEATER End ]";
+ }
+ case LOTData::Type::GStroke:{
+ vDebug << "[TRANSFORM: static: " << obj->isStatic() << " ]";
+ break;
+ }
+ case LOTData::Type::Fill:{
+ vDebug << "[FILL: static:" << obj->isStatic() << "]";
break;
+ }
+ case LOTData::Type::GFill:{
+ auto f = static_cast<LOTGFillData *>(obj);
+ vDebug << "[GFILL: static:" << f->isStatic()
+ << " ty:" << f->mGradientType << " s:" << f->mStartPoint.value(0)
+ << " e:" << f->mEndPoint.value(0) << "]";
+ break;
+ }
default:
break;
}
}
+
std::string layerType(LayerType type)
{
switch (type) {
}
};
+#endif
+
LottieParser::~LottieParser()
{
delete d;
#ifdef DEBUG_PARSER
LOTDataInspector inspector;
- model->mRoot->accept(&inspector);
+ inspector.visit(model->mRoot.get());
#endif
return model;