- reduce Stroke and GStroke model object size by keeping a vector instead of fixed array property.
- keep a vector instead of fixed size array in model.
- keep a vector instead of fix size array in shadow tree.
- refactor getDashInfo() to DashProperty class and reuse by both Stroke and GradientStroke model object.
- enable move constructor in LOTAnimatable class to support creation vector of objects.
}
LOTStrokeItem::LOTStrokeItem(LOTStrokeData *data)
- : LOTPaintDataItem(data->isStatic()), mModel(data)
-{
- mDashArraySize = 0;
-}
+ : LOTPaintDataItem(data->isStatic()), mModel(data){}
void LOTStrokeItem::updateContent(int frameNo)
{
mColor = mModel.color(frameNo).toColor(mModel.opacity(frameNo));
mWidth = mModel.strokeWidth(frameNo);
- if (mModel.hasDashInfo()) {
- mDashArraySize = mModel.getDashInfo(frameNo, mDashArray);
- }
+ if (mModel.hasDashInfo()) mModel.getDashInfo(frameNo, mDashInfo);
}
static float getScale(const VMatrix &matrix)
getScale(static_cast<LOTContentGroupItem *>(parent())->matrix());
mDrawable.setStrokeInfo(mModel.capStyle(), mModel.joinStyle(),
mModel.meterLimit(), mWidth * scale);
- if (mDashArraySize) {
- for (int i = 0; i < mDashArraySize; i++) mDashArray[i] *= scale;
-
- /* AE draw the dash even if dash value is 0 */
- if (vCompare(mDashArray[0], 0.0f)) mDashArray[0] = 0.1f;
- mDrawable.setDashInfo(mDashArray, mDashArraySize);
+ if (!mDashInfo.empty()) {
+ for (auto &elm : mDashInfo) elm *= scale;
+ mDrawable.setDashInfo(mDashInfo);
}
}
LOTGStrokeItem::LOTGStrokeItem(LOTGStrokeData *data)
- : LOTPaintDataItem(data->isStatic()), mData(data)
-{
- mDashArraySize = 0;
-}
+ : LOTPaintDataItem(data->isStatic()), mData(data){}
void LOTGStrokeItem::updateContent(int frameNo)
{
mJoin = mData->joinStyle();
mMiterLimit = mData->meterLimit();
mWidth = mData->width(frameNo);
- if (mData->hasDashInfo()) {
- mDashArraySize = mData->getDashInfo(frameNo, mDashArray);
- }
+
+ if (mData->hasDashInfo()) mData->getDashInfo(frameNo, mDashInfo);
}
void LOTGStrokeItem::updateRenderNode()
mGradient->setAlpha(mAlpha * parentAlpha());
mDrawable.setBrush(VBrush(mGradient.get()));
mDrawable.setStrokeInfo(mCap, mJoin, mMiterLimit, mWidth * scale);
- if (mDashArraySize) {
- for (int i = 0; i < mDashArraySize; i++) mDashArray[i] *= scale;
- mDrawable.setDashInfo(mDashArray, mDashArraySize);
+
+ if (!mDashInfo.empty()) {
+ for (auto &elm : mDashInfo) elm *= scale;
+ mDrawable.setDashInfo(mDashInfo);
}
}
if (mFlag & DirtyState::None) return;
if (mFlag & DirtyState::Path) {
- if (mStroke.mDash.size()) {
+ if (!mStroke.mDash.empty()) {
VDasher dasher(mStroke.mDash.data(), mStroke.mDash.size());
mPath = dasher.dashed(mPath);
}
LOTProxyModel<LOTStrokeData> mModel;
VColor mColor;
float mWidth{0};
- float mDashArray[6];
- int mDashArraySize{0};
+ std::vector<float> mDashInfo;
};
class LOTGStrokeItem : public LOTPaintDataItem
VColor mColor;
float mAlpha{1.0};
float mWidth{0};
- float mDashArray[6];
- int mDashArraySize{0};
+ std::vector<float> mDashInfo;
};
return m;
}
-int LOTStrokeData::getDashInfo(int frameNo, float *array) const
+void LOTDashProperty::getDashInfo(int frameNo, std::vector<float>& result) const
{
- if (!mDash.mDashCount) return 0;
- // odd case
- if (mDash.mDashCount % 2) {
- for (int i = 0; i < mDash.mDashCount; i++) {
- array[i] = mDash.mDashArray[i].value(frameNo);
- }
- return mDash.mDashCount;
- } else { // even case when last gap info is not provided.
- int i;
- for (i = 0; i < mDash.mDashCount - 1; i++) {
- array[i] = mDash.mDashArray[i].value(frameNo);
- }
- array[i] = array[i - 1];
- array[i + 1] = mDash.mDashArray[i].value(frameNo);
- return mDash.mDashCount + 1;
- }
-}
+ result.clear();
-int LOTGStrokeData::getDashInfo(int frameNo, float *array) const
-{
- if (!mDash.mDashCount) return 0;
- // odd case
- if (mDash.mDashCount % 2) {
- for (int i = 0; i < mDash.mDashCount; i++) {
- array[i] = mDash.mDashArray[i].value(frameNo);
- }
- return mDash.mDashCount;
- } else { // even case when last gap info is not provided.
- int i;
- for (i = 0; i < mDash.mDashCount - 1; i++) {
- array[i] = mDash.mDashArray[i].value(frameNo);
- }
- array[i] = array[i - 1];
- array[i + 1] = mDash.mDashArray[i].value(frameNo);
- return mDash.mDashCount + 1;
+ if (mData.empty()) return;
+
+ if (result.capacity() < mData.size()) result.reserve(mData.size() + 1);
+
+ for (const auto &elm : mData)
+ result.push_back(elm.value(frameNo));
+
+ // if the size is even then we are missing last
+ // gap information which is same as the last dash value
+ // copy it from the last dash value.
+ // NOTE: last value is the offset and last-1 is the last dash value.
+ auto size = result.size();
+ if ((size % 2) == 0) {
+ //copy offset value to end.
+ result.push_back(result.back());
+ // copy dash value to gap.
+ result[size-1] = result[size-2];
}
}
return impl.mValue;
}
+ LOTAnimatable(LOTAnimatable &&other) noexcept {
+ if (!other.mStatic) {
+ construct(impl.mAnimInfo, std::move(other.impl.mAnimInfo));
+ mStatic = false;
+ } else {
+ construct(impl.mValue, std::move(other.impl.mValue));
+ mStatic = true;
+ }
+ }
// delete special member functions
LOTAnimatable(const LOTAnimatable &) = delete;
- LOTAnimatable(LOTAnimatable &&) = delete;
LOTAnimatable& operator=(const LOTAnimatable&) = delete;
LOTAnimatable& operator=(LOTAnimatable&&) = delete;
struct LOTDashProperty
{
- LOTAnimatable<float> mDashArray[5]; /* "d" "g" "o"*/
- int mDashCount{0};
- bool mStatic{true};
+ std::vector<LOTAnimatable<float>> mData;
+ bool empty() const {return mData.empty();}
+ size_t size() const {return mData.size();}
+ bool isStatic() const {
+ for(const auto &elm : mData)
+ if (!elm.isStatic()) return false;
+ return true;
+ }
+ void getDashInfo(int frameNo, std::vector<float>& result) const;
};
class LOTStrokeData : public LOTData
CapStyle capStyle() const {return mCapStyle;}
JoinStyle joinStyle() const {return mJoinStyle;}
float meterLimit() const{return mMeterLimit;}
- bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
- int getDashInfo(int frameNo, float *array) const;
+ bool hasDashInfo() const {return !mDash.empty();}
+ void getDashInfo(int frameNo, std::vector<float>& result) const
+ {
+ return mDash.getDashInfo(frameNo, result);
+ }
public:
LOTAnimatable<LottieColor> mColor; /* "c" */
LOTAnimatable<float> mOpacity{100}; /* "o" */
CapStyle capStyle() const {return mCapStyle;}
JoinStyle joinStyle() const {return mJoinStyle;}
float meterLimit() const{return mMeterLimit;}
- bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
- int getDashInfo(int frameNo, float *array) const;
+ bool hasDashInfo() const {return !mDash.empty();}
+ void getDashInfo(int frameNo, std::vector<float>& result) const
+ {
+ return mDash.getDashInfo(frameNo, result);
+ }
public:
LOTAnimatable<float> mWidth; /* "w" */
CapStyle mCapStyle{CapStyle::Flat}; /* "lc" */
}
}
obj->setStatic(obj->mColor.isStatic() && obj->mOpacity.isStatic() &&
- obj->mWidth.isStatic() && obj->mDash.mStatic);
+ obj->mWidth.isStatic() && obj->mDash.isStatic());
return sharedStroke;
}
void LottieParserImpl::parseDashProperty(LOTDashProperty &dash)
{
- dash.mDashCount = 0;
- dash.mStatic = true;
RAPIDJSON_ASSERT(PeekType() == kArrayType);
EnterArray();
while (NextArrayValue()) {
EnterObject();
while (const char *key = NextObjectKey()) {
if (0 == strcmp(key, "v")) {
- parseProperty(dash.mDashArray[dash.mDashCount++]);
+ dash.mData.emplace_back();
+ parseProperty(dash.mData.back());
} else {
Skip(key);
}
}
}
-
- // update the staic proprty
- for (int i = 0; i < dash.mDashCount; i++) {
- if (!dash.mDashArray[i].isStatic()) {
- dash.mStatic = false;
- break;
- }
- }
}
/*
}
obj->setStatic(obj->isStatic() && obj->mWidth.isStatic() &&
- obj->mDash.mStatic);
+ obj->mDash.isStatic());
return sharedGStroke;
}
CapStyle capStyle() const {return _modelData->capStyle();}
JoinStyle joinStyle() const {return _modelData->joinStyle();}
bool hasDashInfo() const { return _modelData->hasDashInfo();}
- int getDashInfo(int frameNo, float *array) const {return _modelData->getDashInfo(frameNo, array);}
+ void getDashInfo(int frameNo, std::vector<float>& result) const {
+ return _modelData->getDashInfo(frameNo, result);
+ }
private:
T *_modelData;
VPath VDasher::dashed(const VPath &path)
{
+ if (mNoLength && mNoGap) return path;
+
if (path.empty() || mNoLength) return VPath();
+
if (mNoGap) return path;
mResult = {};
mFlag |= DirtyState::Path;
}
-void VDrawable::setDashInfo(float *array, uint size)
+void VDrawable::setDashInfo(std::vector<float> &dashInfo)
{
bool hasChanged = false;
- if (mStroke.mDash.size() == size) {
- for (uint i = 0; i < size; i++) {
- if (!vCompare(mStroke.mDash[i], array[i])) {
+ if (mStroke.mDash.size() == dashInfo.size()) {
+ for (uint i = 0; i < dashInfo.size(); i++) {
+ if (!vCompare(mStroke.mDash[i], dashInfo[i])) {
hasChanged = true;
break;
}
if (!hasChanged) return;
- mStroke.mDash.clear();
+ mStroke.mDash = dashInfo;
- for (uint i = 0; i < size; i++) {
- mStroke.mDash.push_back(array[i]);
- }
mFlag |= DirtyState::Path;
}
void setBrush(const VBrush &brush) { mBrush = brush; }
void setStrokeInfo(CapStyle cap, JoinStyle join, float meterLimit,
float strokeWidth);
- void setDashInfo(float *array, uint size);
+ void setDashInfo(std::vector<float> &dashInfo);
void preprocess(const VRect &clip);
VRle rle();