diff options
Diffstat (limited to 'vendor/github.com/Benau/go_rlottie/lottie_lottieitem.h')
-rw-r--r-- | vendor/github.com/Benau/go_rlottie/lottie_lottieitem.h | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/vendor/github.com/Benau/go_rlottie/lottie_lottieitem.h b/vendor/github.com/Benau/go_rlottie/lottie_lottieitem.h new file mode 100644 index 00000000..e1276113 --- /dev/null +++ b/vendor/github.com/Benau/go_rlottie/lottie_lottieitem.h @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * 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 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef LOTTIEITEM_H +#define LOTTIEITEM_H + +#include <memory> +#include <sstream> + +#include "lottie_lottiekeypath.h" +#include "lottie_lottiefiltermodel.h" +#include "rlottie.h" +#include "rlottiecommon.h" +#include "vector_varenaalloc.h" +#include "vector_vdrawable.h" +#include "vector_vmatrix.h" +#include "vector_vpainter.h" +#include "vector_vpath.h" +#include "vector_vpathmesure.h" +#include "vector_vpoint.h" + +V_USE_NAMESPACE + +namespace rlottie { + +namespace internal { + +template <class T> +class VSpan { +public: + using reference = T &; + using pointer = T *; + using const_pointer = T const *; + using const_reference = T const &; + using index_type = size_t; + + using iterator = pointer; + using const_iterator = const_pointer; + + VSpan() = default; + VSpan(pointer data, index_type size) : _data(data), _size(size) {} + + constexpr pointer data() const noexcept { return _data; } + constexpr index_type size() const noexcept { return _size; } + constexpr bool empty() const noexcept { return size() == 0; } + constexpr iterator begin() const noexcept { return data(); } + constexpr iterator end() const noexcept { return data() + size(); } + constexpr const_iterator cbegin() const noexcept { return data(); } + constexpr const_iterator cend() const noexcept { return data() + size(); } + constexpr reference operator[](index_type idx) const + { + return *(data() + idx); + } + +private: + pointer _data{nullptr}; + index_type _size{0}; +}; + +namespace renderer { + +using DrawableList = VSpan<VDrawable *>; + +enum class DirtyFlagBit : uchar { + None = 0x00, + Matrix = 0x01, + Alpha = 0x02, + All = (Matrix | Alpha) +}; +typedef vFlag<DirtyFlagBit> DirtyFlag; + +class SurfaceCache { +public: + SurfaceCache() { mCache.reserve(10); } + + VBitmap make_surface( + size_t width, size_t height, + VBitmap::Format format = VBitmap::Format::ARGB32_Premultiplied) + { + if (mCache.empty()) return {width, height, format}; + + auto surface = mCache.back(); + surface.reset(width, height, format); + + mCache.pop_back(); + return surface; + } + + void release_surface(VBitmap &surface) { mCache.push_back(surface); } + +private: + std::vector<VBitmap> mCache; +}; + +class Drawable final : public VDrawable { +public: + void sync(); + +public: + std::unique_ptr<LOTNode> mCNode{nullptr}; + + ~Drawable() noexcept + { + if (mCNode && mCNode->mGradient.stopPtr) + free(mCNode->mGradient.stopPtr); + } +}; + +struct CApiData { + CApiData(); + LOTLayerNode mLayer; + std::vector<LOTMask> mMasks; + std::vector<LOTLayerNode *> mLayers; + std::vector<LOTNode *> mCNodeList; +}; + +class Clipper { +public: + explicit Clipper(VSize size) : mSize(size) {} + void update(const VMatrix &matrix); + void preprocess(const VRect &clip); + VRle rle(const VRle &mask); + +public: + VSize mSize; + VPath mPath; + VRle mMaskedRle; + VRasterizer mRasterizer; + bool mRasterRequest{false}; +}; + +class Mask { +public: + explicit Mask(model::Mask *data) : mData(data) {} + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag); + model::Mask::Mode maskMode() const { return mData->mMode; } + VRle rle(); + void preprocess(const VRect &clip); + bool inverted() const { return mData->mInv; } +public: + model::Mask *mData{nullptr}; + VPath mLocalPath; + VPath mFinalPath; + VRasterizer mRasterizer; + float mCombinedAlpha{0}; + bool mRasterRequest{false}; +}; + +/* + * Handels mask property of a layer item + */ +class LayerMask { +public: + explicit LayerMask(model::Layer *layerData); + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag); + bool isStatic() const { return mStatic; } + VRle maskRle(const VRect &clipRect); + void preprocess(const VRect &clip); + +public: + std::vector<Mask> mMasks; + VRle mRle; + bool mStatic{true}; + bool mDirty{true}; +}; + +class Layer; + +class Composition { +public: + explicit Composition(std::shared_ptr<model::Composition> composition); + bool update(int frameNo, const VSize &size, bool keepAspectRatio); + VSize size() const { return mViewSize; } + void buildRenderTree(); + const LOTLayerNode *renderTree() const; + bool render(const rlottie::Surface &surface); + void setValue(const std::string &keypath, LOTVariant &value); + +private: + SurfaceCache mSurfaceCache; + VBitmap mSurface; + VMatrix mScaleMatrix; + VSize mViewSize; + std::shared_ptr<model::Composition> mModel; + Layer * mRootLayer{nullptr}; + VArenaAlloc mAllocator{2048}; + int mCurFrameNo; + bool mKeepAspectRatio{true}; +}; + +class Layer { +public: + virtual ~Layer() = default; + Layer &operator=(Layer &&) noexcept = delete; + Layer(model::Layer *layerData); + int id() const { return mLayerData->id(); } + int parentId() const { return mLayerData->parentId(); } + void setParentLayer(Layer *parent) { mParentLayer = parent; } + void setComplexContent(bool value) { mComplexContent = value; } + bool complexContent() const { return mComplexContent; } + virtual void update(int frameNo, const VMatrix &parentMatrix, + float parentAlpha); + VMatrix matrix(int frameNo) const; + void preprocess(const VRect &clip); + virtual DrawableList renderList() { return {}; } + virtual void render(VPainter *painter, const VRle &mask, + const VRle &matteRle, SurfaceCache &cache); + bool hasMatte() + { + if (mLayerData->mMatteType == model::MatteType::None) return false; + return true; + } + model::MatteType matteType() const { return mLayerData->mMatteType; } + bool visible() const; + virtual void buildLayerNode(); + LOTLayerNode & clayer() { return mCApiData->mLayer; } + std::vector<LOTLayerNode *> &clayers() { return mCApiData->mLayers; } + std::vector<LOTMask> & cmasks() { return mCApiData->mMasks; } + std::vector<LOTNode *> & cnodes() { return mCApiData->mCNodeList; } + const char * name() const { return mLayerData->name(); } + virtual bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value); + +protected: + virtual void preprocessStage(const VRect &clip) = 0; + virtual void updateContent() = 0; + inline VMatrix combinedMatrix() const { return mCombinedMatrix; } + inline int frameNo() const { return mFrameNo; } + inline float combinedAlpha() const { return mCombinedAlpha; } + inline bool isStatic() const { return mLayerData->isStatic(); } + float opacity(int frameNo) const { return mLayerData->opacity(frameNo); } + inline DirtyFlag flag() const { return mDirtyFlag; } + bool skipRendering() const + { + return (!visible() || vIsZero(combinedAlpha())); + } + +protected: + std::unique_ptr<LayerMask> mLayerMask; + model::Layer * mLayerData{nullptr}; + Layer * mParentLayer{nullptr}; + VMatrix mCombinedMatrix; + float mCombinedAlpha{0.0}; + int mFrameNo{-1}; + DirtyFlag mDirtyFlag{DirtyFlagBit::All}; + bool mComplexContent{false}; + std::unique_ptr<CApiData> mCApiData; +}; + +class CompLayer final : public Layer { +public: + explicit CompLayer(model::Layer *layerData, VArenaAlloc *allocator); + + void render(VPainter *painter, const VRle &mask, const VRle &matteRle, + SurfaceCache &cache) final; + void buildLayerNode() final; + bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) override; + +protected: + void preprocessStage(const VRect &clip) final; + void updateContent() final; + +private: + void renderHelper(VPainter *painter, const VRle &mask, const VRle &matteRle, + SurfaceCache &cache); + void renderMatteLayer(VPainter *painter, const VRle &inheritMask, + const VRle &matteRle, Layer *layer, Layer *src, + SurfaceCache &cache); + +private: + std::vector<Layer *> mLayers; + std::unique_ptr<Clipper> mClipper; +}; + +class SolidLayer final : public Layer { +public: + explicit SolidLayer(model::Layer *layerData); + void buildLayerNode() final; + DrawableList renderList() final; + +protected: + void preprocessStage(const VRect &clip) final; + void updateContent() final; + +private: + Drawable mRenderNode; + VPath mPath; + VDrawable *mDrawableList{nullptr}; // to work with the Span api +}; + +class Group; + +class ShapeLayer final : public Layer { +public: + explicit ShapeLayer(model::Layer *layerData, VArenaAlloc *allocator); + DrawableList renderList() final; + void buildLayerNode() final; + bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) override; + +protected: + void preprocessStage(const VRect &clip) final; + void updateContent() final; + std::vector<VDrawable *> mDrawableList; + Group * mRoot{nullptr}; +}; + +class NullLayer final : public Layer { +public: + explicit NullLayer(model::Layer *layerData); + +protected: + void preprocessStage(const VRect &) final {} + void updateContent() final; +}; + +class ImageLayer final : public Layer { +public: + explicit ImageLayer(model::Layer *layerData); + void buildLayerNode() final; + DrawableList renderList() final; + +protected: + void preprocessStage(const VRect &clip) final; + void updateContent() final; + +private: + Drawable mRenderNode; + VTexture mTexture; + VPath mPath; + VDrawable *mDrawableList{nullptr}; // to work with the Span api +}; + +class Object { +public: + enum class Type : uchar { Unknown, Group, Shape, Paint, Trim }; + virtual ~Object() = default; + Object & operator=(Object &&) noexcept = delete; + virtual void update(int frameNo, const VMatrix &parentMatrix, + float parentAlpha, const DirtyFlag &flag) = 0; + virtual void renderList(std::vector<VDrawable *> &) {} + virtual bool resolveKeyPath(LOTKeyPath &, uint, LOTVariant &) + { + return false; + } + virtual Object::Type type() const { return Object::Type::Unknown; } +}; + +class Shape; +class Group : public Object { +public: + Group() = default; + explicit Group(model::Group *data, VArenaAlloc *allocator); + void addChildren(model::Group *data, VArenaAlloc *allocator); + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag) override; + void applyTrim(); + void processTrimItems(std::vector<Shape *> &list); + void processPaintItems(std::vector<Shape *> &list); + void renderList(std::vector<VDrawable *> &list) override; + Object::Type type() const final { return Object::Type::Group; } + const VMatrix &matrix() const { return mMatrix; } + const char * name() const + { + static const char *TAG = "__"; + return mModel.hasModel() ? mModel.name() : TAG; + } + bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) override; + +protected: + std::vector<Object *> mContents; + VMatrix mMatrix; + +private: + model::Filter<model::Group> mModel; +}; + +class Shape : public Object { +public: + Shape(bool staticPath) : mStaticPath(staticPath) {} + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag) final; + Object::Type type() const final { return Object::Type::Shape; } + bool dirty() const { return mDirtyPath; } + const VPath &localPath() const { return mTemp; } + void finalPath(VPath &result); + void updatePath(const VPath &path) + { + mTemp = path; + mDirtyPath = true; + } + bool staticPath() const { return mStaticPath; } + void setParent(Group *parent) { mParent = parent; } + Group *parent() const { return mParent; } + +protected: + virtual void updatePath(VPath &path, int frameNo) = 0; + virtual bool hasChanged(int prevFrame, int curFrame) = 0; + +private: + bool hasChanged(int frameNo) + { + int prevFrame = mFrameNo; + mFrameNo = frameNo; + if (prevFrame == -1) return true; + if (mStaticPath || (prevFrame == frameNo)) return false; + return hasChanged(prevFrame, frameNo); + } + Group *mParent{nullptr}; + VPath mLocalPath; + VPath mTemp; + int mFrameNo{-1}; + bool mDirtyPath{true}; + bool mStaticPath; +}; + +class Rect final : public Shape { +public: + explicit Rect(model::Rect *data); + +protected: + void updatePath(VPath &path, int frameNo) final; + model::Rect *mData{nullptr}; + + bool hasChanged(int prevFrame, int curFrame) final + { + return (mData->mPos.changed(prevFrame, curFrame) || + mData->mSize.changed(prevFrame, curFrame) || + mData->roundnessChanged(prevFrame, curFrame)); + } +}; + +class Ellipse final : public Shape { +public: + explicit Ellipse(model::Ellipse *data); + +private: + void updatePath(VPath &path, int frameNo) final; + model::Ellipse *mData{nullptr}; + bool hasChanged(int prevFrame, int curFrame) final + { + return (mData->mPos.changed(prevFrame, curFrame) || + mData->mSize.changed(prevFrame, curFrame)); + } +}; + +class Path final : public Shape { +public: + explicit Path(model::Path *data); + +private: + void updatePath(VPath &path, int frameNo) final; + model::Path *mData{nullptr}; + bool hasChanged(int prevFrame, int curFrame) final + { + return mData->mShape.changed(prevFrame, curFrame); + } +}; + +class Polystar final : public Shape { +public: + explicit Polystar(model::Polystar *data); + +private: + void updatePath(VPath &path, int frameNo) final; + model::Polystar *mData{nullptr}; + + bool hasChanged(int prevFrame, int curFrame) final + { + return (mData->mPos.changed(prevFrame, curFrame) || + mData->mPointCount.changed(prevFrame, curFrame) || + mData->mInnerRadius.changed(prevFrame, curFrame) || + mData->mOuterRadius.changed(prevFrame, curFrame) || + mData->mInnerRoundness.changed(prevFrame, curFrame) || + mData->mOuterRoundness.changed(prevFrame, curFrame) || + mData->mRotation.changed(prevFrame, curFrame)); + } +}; + +class Paint : public Object { +public: + Paint(bool staticContent); + void addPathItems(std::vector<Shape *> &list, size_t startOffset); + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag) override; + void renderList(std::vector<VDrawable *> &list) final; + Object::Type type() const final { return Object::Type::Paint; } + +protected: + virtual bool updateContent(int frameNo, const VMatrix &matrix, + float alpha) = 0; + +private: + void updateRenderNode(); + +protected: + std::vector<Shape *> mPathItems; + Drawable mDrawable; + VPath mPath; + DirtyFlag mFlag; + bool mStaticContent; + bool mRenderNodeUpdate{true}; + bool mContentToRender{true}; +}; + +class Fill final : public Paint { +public: + explicit Fill(model::Fill *data); + +protected: + bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) final; + +private: + model::Filter<model::Fill> mModel; +}; + +class GradientFill final : public Paint { +public: + explicit GradientFill(model::GradientFill *data); + +protected: + bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + +private: + model::GradientFill * mData{nullptr}; + std::unique_ptr<VGradient> mGradient; +}; + +class Stroke : public Paint { +public: + explicit Stroke(model::Stroke *data); + +protected: + bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) final; + +private: + model::Filter<model::Stroke> mModel; +}; + +class GradientStroke final : public Paint { +public: + explicit GradientStroke(model::GradientStroke *data); + +protected: + bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + +private: + model::GradientStroke * mData{nullptr}; + std::unique_ptr<VGradient> mGradient; +}; + +class Trim final : public Object { +public: + explicit Trim(model::Trim *data) : mData(data) {} + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag) final; + Object::Type type() const final { return Object::Type::Trim; } + void update(); + void addPathItems(std::vector<Shape *> &list, size_t startOffset); + +private: + bool pathDirty() const + { + for (auto &i : mPathItems) { + if (i->dirty()) return true; + } + return false; + } + struct Cache { + int mFrameNo{-1}; + model::Trim::Segment mSegment{}; + }; + Cache mCache; + std::vector<Shape *> mPathItems; + model::Trim * mData{nullptr}; + VPathMesure mPathMesure; + bool mDirty{true}; +}; + +class Repeater final : public Group { +public: + explicit Repeater(model::Repeater *data, VArenaAlloc *allocator); + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag) final; + void renderList(std::vector<VDrawable *> &list) final; + +private: + model::Repeater *mRepeaterData{nullptr}; + bool mHidden{false}; + int mCopies{0}; +}; + +} // namespace renderer + +} // namespace internal + +} // namespace rlottie + +#endif // LOTTIEITEM_H |