From: Subhransu Mohanty Date: Wed, 12 Aug 2020 02:09:44 +0000 (+0900) Subject: optimization: refactor Property class for size optimization. X-Git-Tag: submit/tizen/20200817.223215~11 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e1d6fa0f7bda19929bdc595965905f497170dbcf;p=platform%2Fcore%2Fuifw%2Flottie-player.git optimization: refactor Property class for size optimization. As only Property in Transform object has the tangent info added a tag in Property to differentiate form other property. This will add tangent info to only property that require them. --- diff --git a/src/lottie/lottiemodel.h b/src/lottie/lottiemodel.h index 234d921..8513414 100644 --- a/src/lottie/lottiemodel.h +++ b/src/lottie/lottiemodel.h @@ -8,8 +8,8 @@ * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, @@ -150,165 +150,166 @@ struct PathData { } }; -template +template struct Value { - T mStartValue; - T mEndValue; - T at(float t) const { return lerp(mStartValue, mEndValue, t); } + T start_; + T end_; + T at(float t) const { return lerp(start_, end_, t); } float angle(float) const { return 0; } - void cache(){} + void cache() {} }; -template <> -struct Value { - VPointF mStartValue; - VPointF mEndValue; - VPointF mInTangent; - VPointF mOutTangent; - float mBezierLength{0}; - bool mPathKeyFrame{false}; - - void cache() { - if (mPathKeyFrame) { - mInTangent = mEndValue + mInTangent; - mOutTangent = mStartValue + mOutTangent; - mBezierLength = VBezier::fromPoints(mStartValue, mOutTangent, - mInTangent, mEndValue).length(); - if (vIsZero(mBezierLength)) { +struct Position; + +template +struct Value { + T start_; + T end_; + T inTangent_; + T outTangent_; + float length_{0}; + bool hasTangent_{false}; + + void cache() + { + if (hasTangent_) { + inTangent_ = end_ + inTangent_; + outTangent_ = start_ + outTangent_; + length_ = VBezier::fromPoints(start_, outTangent_, inTangent_, end_) + .length(); + if (vIsZero(length_)) { // this segment has zero length. // so disable expensive path computaion. - mPathKeyFrame = false; + hasTangent_ = false; } } } - VPointF at(float t) const + T at(float t) const { - if (mPathKeyFrame) { + if (hasTangent_) { /* * position along the path calcualated * using bezier at progress length (t * bezlen) */ VBezier b = - VBezier::fromPoints(mStartValue, mOutTangent, - mInTangent, mEndValue); - return b.pointAt(b.tAtLength(t * mBezierLength, mBezierLength)); + VBezier::fromPoints(start_, outTangent_, inTangent_, end_); + return b.pointAt(b.tAtLength(t * length_, length_)); } - return lerp(mStartValue, mEndValue, t); + return lerp(start_, end_, t); } float angle(float t) const { - if (mPathKeyFrame) { + if (hasTangent_) { VBezier b = - VBezier::fromPoints(mStartValue, mOutTangent, - mInTangent, mEndValue); - return b.angleAt(b.tAtLength(t * mBezierLength, mBezierLength)); + VBezier::fromPoints(start_, outTangent_, inTangent_, end_); + return b.angleAt(b.tAtLength(t * length_, length_)); } return 0; } }; -template -class KeyFrame { +template +class KeyFrames { public: - float progress(int frameNo) const - { - return mInterpolator ? mInterpolator->value((frameNo - mStartFrame) / - (mEndFrame - mStartFrame)) - : 0; - } - T value(int frameNo) const { return mValue.at(progress(frameNo)); } - float angle(int frameNo) const { return mValue.angle(progress(frameNo)); } + struct Frame { + float progress(int frameNo) const + { + return interpolator_ ? interpolator_->value((frameNo - start_) / + (end_ - start_)) + : 0; + } + T value(int frameNo) const { return value_.at(progress(frameNo)); } + float angle(int frameNo) const + { + return value_.angle(progress(frameNo)); + } -public: - float mStartFrame{0}; - float mEndFrame{0}; - VInterpolator *mInterpolator{nullptr}; - Value mValue; -}; + float start_{0}; + float end_{0}; + VInterpolator *interpolator_{nullptr}; + Value value_; + }; -template -class DynamicProperty { -public: T value(int frameNo) const { - if (mKeyFrames.front().mStartFrame >= frameNo) - return mKeyFrames.front().mValue.mStartValue; - if (mKeyFrames.back().mEndFrame <= frameNo) - return mKeyFrames.back().mValue.mEndValue; + if (frames_.front().start_ >= frameNo) + return frames_.front().value_.start_; + if (frames_.back().end_ <= frameNo) return frames_.back().value_.end_; - for (const auto &keyFrame : mKeyFrames) { - if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame) + for (const auto &keyFrame : frames_) { + if (frameNo >= keyFrame.start_ && frameNo < keyFrame.end_) return keyFrame.value(frameNo); } - return T(); + return {}; } float angle(int frameNo) const { - if ((mKeyFrames.front().mStartFrame >= frameNo) || - (mKeyFrames.back().mEndFrame <= frameNo)) + if ((frames_.front().start_ >= frameNo) || + (frames_.back().end_ <= frameNo)) return 0; - for (const auto &keyFrame : mKeyFrames) { - if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame) - return keyFrame.angle(frameNo); + for (const auto &frame : frames_) { + if (frameNo >= frame.start_ && frameNo < frame.end_) + return frame.angle(frameNo); } return 0; } bool changed(int prevFrame, int curFrame) const { - auto first = mKeyFrames.front().mStartFrame; - auto last = mKeyFrames.back().mEndFrame; + auto first = frames_.front().start_; + auto last = frames_.back().end_; return !((first > prevFrame && first > curFrame) || (last < prevFrame && last < curFrame)); } - - void cache() { for (auto &e : mKeyFrames) e.mValue.cache(); } + void cache() + { + for (auto &e : frames_) e.value_.cache(); + } public: - std::vector> mKeyFrames; + std::vector frames_; }; -template +template class Property { public: - Property() { construct(impl.mValue, {}); } - explicit Property(T value) { construct(impl.mValue, std::move(value)); } + using Animation = KeyFrames; - const DynamicProperty &animation() const - { - return *(impl.mAnimInfo.get()); - } - const T &value() const { return impl.mValue; } + Property() { construct(impl_.value_, {}); } + explicit Property(T value) { construct(impl_.value_, std::move(value)); } + + const Animation &animation() const { return *(impl_.animation_.get()); } + const T & value() const { return impl_.value_; } - DynamicProperty &animation() + Animation &animation() { - if (mStatic) { + if (isValue_) { destroy(); - construct(impl.mAnimInfo, std::make_unique>()); - mStatic = false; + construct(impl_.animation_, std::make_unique()); + isValue_ = false; } - return *(impl.mAnimInfo.get()); + return *(impl_.animation_.get()); } T &value() { - assert(mStatic); - return impl.mValue; + assert(isValue_); + return impl_.value_; } Property(Property &&other) noexcept { - if (!other.mStatic) { - construct(impl.mAnimInfo, std::move(other.impl.mAnimInfo)); - mStatic = false; + if (!other.isValue_) { + construct(impl_.animation_, std::move(other.impl_.animation_)); + isValue_ = false; } else { - construct(impl.mValue, std::move(other.impl.mValue)); - mStatic = true; + construct(impl_.value_, std::move(other.impl_.value_)); + isValue_ = true; } } // delete special member functions @@ -316,9 +317,9 @@ public: Property &operator=(const Property &) = delete; Property &operator=(Property &&) = delete; - ~Property() noexcept { destroy(); } + ~Property() { destroy(); } - bool isStatic() const { return mStatic; } + bool isStatic() const { return isValue_; } T value(int frameNo) const { @@ -326,25 +327,23 @@ public: } // special function only for type T=PathData - template + template auto value(int frameNo, VPath &path) const -> - typename std::enable_if_t::value, void> + typename std::enable_if_t::value, void> { if (isStatic()) { value().toPath(path); } else { - const auto &vec = animation().mKeyFrames; - if (vec.front().mStartFrame >= frameNo) - return vec.front().mValue.mStartValue.toPath(path); - if (vec.back().mEndFrame <= frameNo) - return vec.back().mValue.mEndValue.toPath(path); + const auto &vec = animation().frames_; + if (vec.front().start_ >= frameNo) + return vec.front().value_.start_.toPath(path); + if (vec.back().end_ <= frameNo) + return vec.back().value_.end_.toPath(path); for (const auto &keyFrame : vec) { - if (frameNo >= keyFrame.mStartFrame && - frameNo < keyFrame.mEndFrame) { - PathData::lerp(keyFrame.mValue.mStartValue, - keyFrame.mValue.mEndValue, - keyFrame.progress(frameNo), path); + if (frameNo >= keyFrame.start_ && frameNo < keyFrame.end_) { + T::lerp(keyFrame.value_.start_, keyFrame.value_.end_, + keyFrame.progress(frameNo), path); } } } @@ -359,8 +358,11 @@ public: { return isStatic() ? false : animation().changed(prevFrame, curFrame); } + void cache() + { + if (!isStatic()) animation().cache(); + } - void cache() { if (!isStatic()) animation().cache();} private: template void construct(Tp &member, Tp &&val) @@ -370,24 +372,24 @@ private: void destroy() { - if (mStatic) { - impl.mValue.~T(); + if (isValue_) { + impl_.value_.~T(); } else { using std::unique_ptr; - impl.mAnimInfo.~unique_ptr>(); + impl_.animation_.~unique_ptr(); } } union details { - std::unique_ptr> mAnimInfo; - T mValue; + std::unique_ptr animation_; + T value_; details(){}; details(const details &) = delete; details(details &&) = delete; details &operator=(details &&) = delete; details &operator=(const details &) = delete; ~details() noexcept {}; - } impl; - bool mStatic{true}; + } impl_; + bool isValue_{true}; }; class Path; @@ -585,12 +587,12 @@ public: { if (!mExtra) mExtra = std::make_unique(); } - Property mRotation{0}; /* "r" */ - Property mScale{{100, 100}}; /* "s" */ - Property mPosition; /* "p" */ - Property mAnchor; /* "a" */ - Property mOpacity{100}; /* "o" */ - std::unique_ptr mExtra; + Property mRotation{0}; /* "r" */ + Property mScale{{100, 100}}; /* "s" */ + Property mPosition; /* "p" */ + Property mAnchor; /* "a" */ + Property mOpacity{100}; /* "o" */ + std::unique_ptr mExtra; }; Transform() : Object(Object::Type::Transform) {} diff --git a/src/lottie/lottieparser.cpp b/src/lottie/lottieparser.cpp index c53d060..6a1a3cc 100644 --- a/src/lottie/lottieparser.cpp +++ b/src/lottie/lottieparser.cpp @@ -8,8 +8,8 @@ * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, @@ -253,14 +253,21 @@ public: void getValue(std::vector &v); void getValue(model::Repeater::Transform &); + template + bool parseKeyFrameValue(const char *key, model::Value &value) + { + return false; + } + template - bool parseKeyFrameValue(const char *key, model::Value &value); - template - void parseKeyFrame(model::DynamicProperty &obj); + bool parseKeyFrameValue(const char * key, + model::Value &value); + template + void parseKeyFrame(model::KeyFrames &obj); template void parseProperty(model::Property &obj); - template - void parsePropertyHelper(model::Property &obj); + template + void parsePropertyHelper(model::Property &obj); void parseShapeProperty(model::Property &obj); void parseDashProperty(model::Dash &dash); @@ -1463,11 +1470,11 @@ model::Repeater *LottieParserImpl::parseReapeaterObject() parseProperty(obj->mCopies); float maxCopy = 0.0; if (!obj->mCopies.isStatic()) { - for (auto &keyFrame : obj->mCopies.animation().mKeyFrames) { - if (maxCopy < keyFrame.mValue.mStartValue) - maxCopy = keyFrame.mValue.mStartValue; - if (maxCopy < keyFrame.mValue.mEndValue) - maxCopy = keyFrame.mValue.mEndValue; + for (auto &keyFrame : obj->mCopies.animation().frames_) { + if (maxCopy < keyFrame.value_.start_) + maxCopy = keyFrame.value_.start_; + if (maxCopy < keyFrame.value_.end_) + maxCopy = keyFrame.value_.end_; } } else { maxCopy = obj->mCopies.value(); @@ -1947,21 +1954,15 @@ VPointF LottieParserImpl::parseInperpolatorPoint() } template -bool LottieParserImpl::parseKeyFrameValue(const char *, model::Value &) -{ - return false; -} - -template <> -bool LottieParserImpl::parseKeyFrameValue(const char * key, - model::Value &value) +bool LottieParserImpl::parseKeyFrameValue( + const char *key, model::Value &value) { if (0 == strcmp(key, "ti")) { - value.mPathKeyFrame = true; - getValue(value.mInTangent); + value.hasTangent_ = true; + getValue(value.inTangent_); } else if (0 == strcmp(key, "to")) { - value.mPathKeyFrame = true; - getValue(value.mOutTangent); + value.hasTangent_ = true; + getValue(value.outTangent_); } else { return false; } @@ -1993,8 +1994,8 @@ VInterpolator *LottieParserImpl::interpolator(VPointF inTangent, /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/properties/multiDimensionalKeyframed.json */ -template -void LottieParserImpl::parseKeyFrame(model::DynamicProperty &obj) +template +void LottieParserImpl::parseKeyFrame(model::KeyFrames &obj) { struct ParsedField { std::string interpolatorKey; @@ -2005,10 +2006,10 @@ void LottieParserImpl::parseKeyFrame(model::DynamicProperty &obj) }; EnterObject(); - ParsedField parsed; - model::KeyFrame keyframe; - VPointF inTangent; - VPointF outTangent; + ParsedField parsed; + typename model::KeyFrames::Frame keyframe; + VPointF inTangent; + VPointF outTangent; while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "i")) { @@ -2017,14 +2018,14 @@ void LottieParserImpl::parseKeyFrame(model::DynamicProperty &obj) } else if (0 == strcmp(key, "o")) { outTangent = parseInperpolatorPoint(); } else if (0 == strcmp(key, "t")) { - keyframe.mStartFrame = GetDouble(); + keyframe.start_ = GetDouble(); } else if (0 == strcmp(key, "s")) { parsed.value = true; - getValue(keyframe.mValue.mStartValue); + getValue(keyframe.value_.start_); continue; } else if (0 == strcmp(key, "e")) { parsed.noEndValue = false; - getValue(keyframe.mValue.mEndValue); + getValue(keyframe.value_.end_); continue; } else if (0 == strcmp(key, "n")) { if (PeekType() == kStringType) { @@ -2043,7 +2044,7 @@ void LottieParserImpl::parseKeyFrame(model::DynamicProperty &obj) } } continue; - } else if (parseKeyFrameValue(key, keyframe.mValue)) { + } else if (parseKeyFrameValue(key, keyframe.value_)) { continue; } else if (0 == strcmp(key, "h")) { parsed.hold = GetInt(); @@ -2056,29 +2057,26 @@ void LottieParserImpl::parseKeyFrame(model::DynamicProperty &obj) } } - - auto &list = obj.mKeyFrames; - + auto &list = obj.frames_; if (!list.empty()) { // update the endFrame value of current keyframe - list.back().mEndFrame = keyframe.mStartFrame; + list.back().end_ = keyframe.start_; // if no end value provided, copy start value to previous frame if (parsed.value && parsed.noEndValue) { - list.back().mValue.mEndValue = - keyframe.mValue.mStartValue; + list.back().value_.end_ = keyframe.value_.start_; } } if (parsed.hold) { - keyframe.mValue.mEndValue = keyframe.mValue.mStartValue; - keyframe.mEndFrame = keyframe.mStartFrame; + keyframe.value_.end_ = keyframe.value_.start_; + keyframe.end_ = keyframe.start_; list.push_back(std::move(keyframe)); } else if (parsed.interpolator) { - keyframe.mInterpolator = interpolator( + keyframe.interpolator_ = interpolator( inTangent, outTangent, std::move(parsed.interpolatorKey)); list.push_back(std::move(keyframe)); } else { - // Last frame ignore + // its the last frame discard. } } @@ -2118,8 +2116,8 @@ void LottieParserImpl::parseShapeProperty(model::Property &obj) obj.cache(); } -template -void LottieParserImpl::parsePropertyHelper(model::Property &obj) +template +void LottieParserImpl::parsePropertyHelper(model::Property &obj) { if (PeekType() == kNumberType) { if (!obj.isStatic()) {