From: Subhransu Mohanty Date: Wed, 8 Jul 2020 08:17:30 +0000 (+0900) Subject: rlottie: refactor lottie model and renderer code. X-Git-Tag: submit/tizen/20200713.050659^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6945d99692a2a6cda8a6fe4271459e2e63df3de6;p=platform%2Fcore%2Fuifw%2Flottie-player.git rlottie: refactor lottie model and renderer code. - move all the internal code to rlottie::internal namespace - move model related code to rlottie::internal::model namespace - move rendering code to rlottie::internal::renderer namespace. - run clang-format - removed LOT class prefix. --- diff --git a/src/lottie/lottieanimation.cpp b/src/lottie/lottieanimation.cpp index 165f8ea..b7b66d8 100644 --- a/src/lottie/lottieanimation.cpp +++ b/src/lottie/lottieanimation.cpp @@ -17,17 +17,17 @@ */ #include "config.h" #include "lottieitem.h" -#include "lottieloader.h" #include "lottiemodel.h" #include "rlottie.h" #include using namespace rlottie; +using namespace rlottie::internal; LOT_EXPORT void rlottie::configureModelCacheSize(size_t cacheSize) { - LottieLoader::configureModelCacheSize(cacheSize); + internal::model::configureModelCacheSize(cacheSize); } struct RenderTask { @@ -43,15 +43,17 @@ using SharedRenderTask = std::shared_ptr; class AnimationImpl { public: - void init(const std::shared_ptr &model); + void init(std::shared_ptr composition); bool update(size_t frameNo, const VSize &size, bool keepAspectRatio); VSize size() const { return mModel->size(); } double duration() const { return mModel->duration(); } double frameRate() const { return mModel->frameRate(); } size_t totalFrame() const { return mModel->totalFrame(); } size_t frameAtPos(double pos) const { return mModel->frameAtPos(pos); } - Surface render(size_t frameNo, const Surface &surface, bool keepAspectRatio); - std::future renderAsync(size_t frameNo, Surface &&surface, bool keepAspectRatio); + Surface render(size_t frameNo, const Surface &surface, + bool keepAspectRatio); + std::future renderAsync(size_t frameNo, Surface &&surface, + bool keepAspectRatio); const LOTLayerNode * renderTree(size_t frameNo, const VSize &size); const LayerInfoList &layerInfoList() const @@ -61,37 +63,34 @@ public: } return mLayerList; } - const MarkerList &markers() const - { - return mModel->markers(); - } - void setValue(const std::string &keypath, LOTVariant &&value); - void removeFilter(const std::string &keypath, Property prop); + const MarkerList &markers() const { return mModel->markers(); } + void setValue(const std::string &keypath, LOTVariant &&value); + void removeFilter(const std::string &keypath, Property prop); private: - mutable LayerInfoList mLayerList; - std::string mFilePath; - std::shared_ptr mModel; - std::unique_ptr mCompItem; - SharedRenderTask mTask; - std::atomic mRenderInProgress; + mutable LayerInfoList mLayerList; + model::Composition * mModel; + SharedRenderTask mTask; + std::atomic mRenderInProgress; + std::unique_ptr mRenderer{nullptr}; }; void AnimationImpl::setValue(const std::string &keypath, LOTVariant &&value) { if (keypath.empty()) return; - mCompItem->setValue(keypath, value); + mRenderer->setValue(keypath, value); } const LOTLayerNode *AnimationImpl::renderTree(size_t frameNo, const VSize &size) { if (update(frameNo, size, true)) { - mCompItem->buildRenderTree(); + mRenderer->buildRenderTree(); } - return mCompItem->renderTree(); + return mRenderer->renderTree(); } -bool AnimationImpl::update(size_t frameNo, const VSize &size, bool keepAspectRatio) +bool AnimationImpl::update(size_t frameNo, const VSize &size, + bool keepAspectRatio) { frameNo += mModel->startFrame(); @@ -99,10 +98,11 @@ bool AnimationImpl::update(size_t frameNo, const VSize &size, bool keepAspectRat if (frameNo < mModel->startFrame()) frameNo = mModel->startFrame(); - return mCompItem->update(int(frameNo), size, keepAspectRatio); + return mRenderer->update(int(frameNo), size, keepAspectRatio); } -Surface AnimationImpl::render(size_t frameNo, const Surface &surface, bool keepAspectRatio) +Surface AnimationImpl::render(size_t frameNo, const Surface &surface, + bool keepAspectRatio) { bool renderInProgress = mRenderInProgress.load(); if (renderInProgress) { @@ -111,18 +111,20 @@ Surface AnimationImpl::render(size_t frameNo, const Surface &surface, bool keepA } mRenderInProgress.store(true); - update(frameNo, - VSize(int(surface.drawRegionWidth()), int(surface.drawRegionHeight())), keepAspectRatio); - mCompItem->render(surface); + update( + frameNo, + VSize(int(surface.drawRegionWidth()), int(surface.drawRegionHeight())), + keepAspectRatio); + mRenderer->render(surface); mRenderInProgress.store(false); return surface; } -void AnimationImpl::init(const std::shared_ptr &model) +void AnimationImpl::init(std::shared_ptr composition) { - mModel = model; - mCompItem = std::make_unique(mModel.get()); + mModel = composition.get(); + mRenderer = std::make_unique(composition); mRenderInProgress = false; } @@ -161,8 +163,8 @@ class RenderTaskScheduler { } if (!success && !_q[i].pop(task)) break; - auto result = - task->playerImpl->render(task->frameNo, task->surface, task->keepAspectRatio); + auto result = task->playerImpl->render(task->frameNo, task->surface, + task->keepAspectRatio); task->sender.set_value(result); } } @@ -216,7 +218,8 @@ public: std::future process(SharedRenderTask task) { - auto result = task->playerImpl->render(task->frameNo, task->surface, task->keepAspectRatio); + auto result = task->playerImpl->render(task->frameNo, task->surface, + task->keepAspectRatio); task->sender.set_value(result); return std::move(task->receiver); } @@ -225,7 +228,7 @@ public: std::future AnimationImpl::renderAsync(size_t frameNo, Surface &&surface, - bool keepAspectRatio) + bool keepAspectRatio) { if (!mTask) { mTask = std::make_shared(); @@ -255,43 +258,48 @@ std::unique_ptr Animation::loadFromData( return nullptr; } - LottieLoader loader; - if (loader.loadFromData(std::move(jsonData), key, resourcePath, cachePolicy)) { + auto composition = model::loadFromData(std::move(jsonData), key, + resourcePath, cachePolicy); + if (composition) { auto animation = std::unique_ptr(new Animation); - animation->d->init(loader.model()); + animation->d->init(std::move(composition)); return animation; } + return nullptr; } -std::unique_ptr Animation::loadFromData( std::string jsonData, std::string resourcePath, ColorFilter filter) +std::unique_ptr Animation::loadFromData(std::string jsonData, + std::string resourcePath, + ColorFilter filter) { if (jsonData.empty()) { vWarning << "jason data is empty"; return nullptr; } - LottieLoader loader; - if (loader.loadFromData(std::move(jsonData), std::move(resourcePath), std::move(filter))) { + auto composition = model::loadFromData( + std::move(jsonData), std::move(resourcePath), std::move(filter)); + if (composition) { auto animation = std::unique_ptr(new Animation); - animation->d->init(loader.model()); + animation->d->init(std::move(composition)); return animation; } return nullptr; } -std::unique_ptr -Animation::loadFromFile(const std::string &path, bool cachePolicy) +std::unique_ptr Animation::loadFromFile(const std::string &path, + bool cachePolicy) { if (path.empty()) { vWarning << "File path is empty"; return nullptr; } - LottieLoader loader; - if (loader.load(path, cachePolicy)) { + auto composition = model::loadFromFile(path, cachePolicy); + if (composition) { auto animation = std::unique_ptr(new Animation); - animation->d->init(loader.model()); + animation->d->init(std::move(composition)); return animation; } return nullptr; @@ -331,12 +339,14 @@ const LOTLayerNode *Animation::renderTree(size_t frameNo, size_t width, return d->renderTree(frameNo, VSize(int(width), int(height))); } -std::future Animation::render(size_t frameNo, Surface surface, bool keepAspectRatio) +std::future Animation::render(size_t frameNo, Surface surface, + bool keepAspectRatio) { return d->renderAsync(frameNo, std::move(surface), keepAspectRatio); } -void Animation::renderSync(size_t frameNo, Surface surface, bool keepAspectRatio) +void Animation::renderSync(size_t frameNo, Surface surface, + bool keepAspectRatio) { d->render(frameNo, surface, keepAspectRatio); } diff --git a/src/lottie/lottieitem.cpp b/src/lottie/lottieitem.cpp index a017e47..276fd71 100644 --- a/src/lottie/lottieitem.cpp +++ b/src/lottie/lottieitem.cpp @@ -68,24 +68,24 @@ static bool strokeProp(rlottie::Property prop) } } -static LOTLayerItem* -createLayerItem(LOTLayerData *layerData, VArenaAlloc *allocator) +static renderer::Layer *createLayerItem(model::Layer *layerData, + VArenaAlloc * allocator) { switch (layerData->mLayerType) { - case LayerType::Precomp: { - return allocator->make(layerData, allocator); + case model::Layer::Type::Precomp: { + return allocator->make(layerData, allocator); } - case LayerType::Solid: { - return allocator->make(layerData); + case model::Layer::Type::Solid: { + return allocator->make(layerData); } - case LayerType::Shape: { - return allocator->make(layerData, allocator); + case model::Layer::Type::Shape: { + return allocator->make(layerData, allocator); } - case LayerType::Null: { - return allocator->make(layerData); + case model::Layer::Type::Null: { + return allocator->make(layerData); } - case LayerType::Image: { - return allocator->make(layerData); + case model::Layer::Type::Image: { + return allocator->make(layerData); } default: return nullptr; @@ -93,27 +93,29 @@ createLayerItem(LOTLayerData *layerData, VArenaAlloc *allocator) } } -LOTCompItem::LOTCompItem(LOTModel *model) +renderer::Composition::Composition(std::shared_ptr model) : mCurFrameNo(-1) { - mCompData = model->mRoot.get(); - mRootLayer = createLayerItem(mCompData->mRootLayer, &mAllocator); + mModel = std::move(model); + mRootLayer = createLayerItem(mModel->mRootLayer, &mAllocator); mRootLayer->setComplexContent(false); - mViewSize = mCompData->size(); + mViewSize = mModel->size(); } -void LOTCompItem::setValue(const std::string &keypath, LOTVariant &value) +void renderer::Composition::setValue(const std::string &keypath, + LOTVariant & value) { LOTKeyPath key(keypath); mRootLayer->resolveKeyPath(key, 0, value); } -bool LOTCompItem::update(int frameNo, const VSize &size, bool keepAspectRatio) +bool renderer::Composition::update(int frameNo, const VSize &size, + bool keepAspectRatio) { // check if cached frame is same as requested frame. - if ((mViewSize == size) && - (mCurFrameNo == frameNo) && - (mKeepAspectRatio == keepAspectRatio)) return false; + if ((mViewSize == size) && (mCurFrameNo == frameNo) && + (mKeepAspectRatio == keepAspectRatio)) + return false; mViewSize = size; mCurFrameNo = frameNo; @@ -125,31 +127,33 @@ bool LOTCompItem::update(int frameNo, const VSize &size, bool keepAspectRatio) * viewbox to the viewport using AlignCenter rule. */ VMatrix m; - VSize viewPort = mViewSize; - VSize viewBox = mCompData->size(); - float sx = float(viewPort.width()) / viewBox.width(); - float sy = float(viewPort.height()) / viewBox.height(); + VSize viewPort = mViewSize; + VSize viewBox = mModel->size(); + float sx = float(viewPort.width()) / viewBox.width(); + float sy = float(viewPort.height()) / viewBox.height(); if (mKeepAspectRatio) { float scale = std::min(sx, sy); float tx = (viewPort.width() - viewBox.width() * scale) * 0.5f; float ty = (viewPort.height() - viewBox.height() * scale) * 0.5f; m.translate(tx, ty).scale(scale, scale); } else { - m.scale(sx, sy); + m.scale(sx, sy); } mRootLayer->update(frameNo, m, 1.0); return true; } -bool LOTCompItem::render(const rlottie::Surface &surface) +bool renderer::Composition::render(const rlottie::Surface &surface) { mSurface.reset(reinterpret_cast(surface.buffer()), - uint(surface.width()), uint(surface.height()), uint(surface.bytesPerLine()), + uint(surface.width()), uint(surface.height()), + uint(surface.bytesPerLine()), VBitmap::Format::ARGB32_Premultiplied); /* schedule all preprocess task for this frame at once. */ - VRect clip(0, 0, int(surface.drawRegionWidth()), int(surface.drawRegionHeight())); + VRect clip(0, 0, int(surface.drawRegionWidth()), + int(surface.drawRegionHeight())); mRootLayer->preprocess(clip); VPainter painter(&mSurface); @@ -162,8 +166,8 @@ bool LOTCompItem::render(const rlottie::Surface &surface) return true; } -void LOTMaskItem::update(int frameNo, const VMatrix & parentMatrix, - float /*parentAlpha*/, const DirtyFlag &flag) +void renderer::Mask::update(int frameNo, const VMatrix &parentMatrix, + float /*parentAlpha*/, const DirtyFlag &flag) { if (flag.testFlag(DirtyFlagBit::None) && mData->isStatic()) return; @@ -183,7 +187,7 @@ void LOTMaskItem::update(int frameNo, const VMatrix & parentMatrix, mRasterRequest = true; } -VRle LOTMaskItem::rle() +VRle renderer::Mask::rle() { if (mRasterRequest) { mRasterRequest = false; @@ -194,13 +198,14 @@ VRle LOTMaskItem::rle() return mRasterizer.rle(); } -void LOTMaskItem::preprocess(const VRect &clip) +void renderer::Mask::preprocess(const VRect &clip) { - if (mRasterRequest) mRasterizer.rasterize(mFinalPath, FillRule::Winding, clip); + if (mRasterRequest) + mRasterizer.rasterize(mFinalPath, FillRule::Winding, clip); } -void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask, - const VRle &matteRle, SurfaceCache& cache) +void renderer::Layer::render(VPainter *painter, const VRle &inheritMask, + const VRle &matteRle, SurfaceCache &cache) { auto renderlist = renderList(); @@ -232,7 +237,7 @@ void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask, if (!mask.empty()) rle = rle & mask; if (rle.empty()) continue; - if (matteType() == MatteType::AlphaInv) { + if (matteType() == model::MatteType::AlphaInv) { rle = rle - matteRle; painter->drawRle(VPoint(), rle); } else { @@ -243,15 +248,14 @@ void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask, } } -void LOTLayerMaskItem::preprocess(const VRect &clip) +void renderer::LayerMask::preprocess(const VRect &clip) { for (auto &i : mMasks) { i.preprocess(clip); } } - -LOTLayerMaskItem::LOTLayerMaskItem(LOTLayerData *layerData) +renderer::LayerMask::LayerMask(model::Layer *layerData) { if (!layerData->mExtra) return; @@ -263,8 +267,8 @@ LOTLayerMaskItem::LOTLayerMaskItem(LOTLayerData *layerData) } } -void LOTLayerMaskItem::update(int frameNo, const VMatrix &parentMatrix, - float parentAlpha, const DirtyFlag &flag) +void renderer::LayerMask::update(int frameNo, const VMatrix &parentMatrix, + float parentAlpha, const DirtyFlag &flag) { if (flag.testFlag(DirtyFlagBit::None) && isStatic()) return; @@ -274,28 +278,28 @@ void LOTLayerMaskItem::update(int frameNo, const VMatrix &parentMatrix, mDirty = true; } -VRle LOTLayerMaskItem::maskRle(const VRect &clipRect) +VRle renderer::LayerMask::maskRle(const VRect &clipRect) { if (!mDirty) return mRle; VRle rle; for (auto &i : mMasks) { switch (i.maskMode()) { - case LOTMaskData::Mode::Add: { + case model::Mask::Mode::Add: { rle = rle + i.rle(); break; } - case LOTMaskData::Mode::Substarct: { + case model::Mask::Mode::Substarct: { if (rle.empty() && !clipRect.empty()) rle = VRle::toRle(clipRect); rle = rle - i.rle(); break; } - case LOTMaskData::Mode::Intersect: { + case model::Mask::Mode::Intersect: { if (rle.empty() && !clipRect.empty()) rle = VRle::toRle(clipRect); rle = rle & i.rle(); break; } - case LOTMaskData::Mode::Difference: { + case model::Mask::Mode::Difference: { rle = rle ^ i.rle(); break; } @@ -313,14 +317,14 @@ VRle LOTLayerMaskItem::maskRle(const VRect &clipRect) return mRle; } -LOTLayerItem::LOTLayerItem(LOTLayerData *layerData) : mLayerData(layerData) +renderer::Layer::Layer(model::Layer *layerData) : mLayerData(layerData) { if (mLayerData->mHasMask) - mLayerMask = std::make_unique(mLayerData); + mLayerMask = std::make_unique(mLayerData); } -bool LOTLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, - LOTVariant &value) +bool renderer::Layer::resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) { if (!keyPath.matches(name(), depth)) { return false; @@ -335,10 +339,10 @@ bool LOTLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, return true; } -bool LOTShapeLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, - LOTVariant &value) +bool renderer::ShapeLayer::resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) { - if (LOTLayerItem::resolveKeyPath(keyPath, depth, value)) { + if (renderer::Layer::resolveKeyPath(keyPath, depth, value)) { if (keyPath.propagate(name(), depth)) { uint newDepth = keyPath.nextDepth(name(), depth); mRoot->resolveKeyPath(keyPath, newDepth, value); @@ -348,10 +352,10 @@ bool LOTShapeLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, return false; } -bool LOTCompLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, - LOTVariant &value) +bool renderer::CompLayer::resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) { - if (LOTLayerItem::resolveKeyPath(keyPath, depth, value)) { + if (renderer::Layer::resolveKeyPath(keyPath, depth, value)) { if (keyPath.propagate(name(), depth)) { uint newDepth = keyPath.nextDepth(name(), depth); for (const auto &layer : mLayers) { @@ -363,8 +367,8 @@ bool LOTCompLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, return false; } -void LOTLayerItem::update(int frameNumber, const VMatrix &parentMatrix, - float parentAlpha) +void renderer::Layer::update(int frameNumber, const VMatrix &parentMatrix, + float parentAlpha) { mFrameNo = frameNumber; // 1. check if the layer is part of the current frame @@ -409,20 +413,20 @@ void LOTLayerItem::update(int frameNumber, const VMatrix &parentMatrix, mDirtyFlag = DirtyFlagBit::None; } -VMatrix LOTLayerItem::matrix(int frameNo) const +VMatrix renderer::Layer::matrix(int frameNo) const { return mParentLayer ? (mLayerData->matrix(frameNo) * mParentLayer->matrix(frameNo)) : mLayerData->matrix(frameNo); } -bool LOTLayerItem::visible() const +bool renderer::Layer::visible() const { return (frameNo() >= mLayerData->inFrame() && frameNo() < mLayerData->outFrame()); } -void LOTLayerItem::preprocess(const VRect& clip) +void renderer::Layer::preprocess(const VRect &clip) { // layer dosen't contribute to the frame if (skipRendering()) return; @@ -433,8 +437,8 @@ void LOTLayerItem::preprocess(const VRect& clip) preprocessStage(clip); } -LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel, VArenaAlloc* allocator) - : LOTLayerItem(layerModel) +renderer::CompLayer::CompLayer(model::Layer *layerModel, VArenaAlloc *allocator) + : renderer::Layer(layerModel) { if (!mLayerData->mChildren.empty()) mLayers.reserve(mLayerData->mChildren.size()); @@ -442,8 +446,8 @@ LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel, VArenaAlloc* alloca // 1. keep the layer in back-to-front order. // as lottie model keeps the data in front-toback-order. for (auto it = mLayerData->mChildren.crbegin(); - it != mLayerData->mChildren.rend(); ++it ) { - auto model = static_cast(*it); + it != mLayerData->mChildren.rend(); ++it) { + auto model = static_cast(*it); auto item = createLayerItem(model, allocator); if (item) mLayers.push_back(item); } @@ -461,14 +465,14 @@ LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel, VArenaAlloc* alloca // 4. check if its a nested composition if (!layerModel->layerSize().empty()) { - mClipper = std::make_unique(layerModel->layerSize()); + mClipper = std::make_unique(layerModel->layerSize()); } if (mLayers.size() > 1) setComplexContent(true); } -void LOTCompLayerItem::render(VPainter *painter, const VRle &inheritMask, - const VRle &matteRle, SurfaceCache& cache) +void renderer::CompLayer::render(VPainter *painter, const VRle &inheritMask, + const VRle &matteRle, SurfaceCache &cache) { if (vIsZero(combinedAlpha())) return; @@ -478,11 +482,12 @@ void LOTCompLayerItem::render(VPainter *painter, const VRle &inheritMask, if (complexContent()) { VSize size = painter->clipBoundingRect().size(); VPainter srcPainter; - VBitmap srcBitmap = cache.make_surface(size.width(), size.height()); + VBitmap srcBitmap = cache.make_surface(size.width(), size.height()); srcPainter.begin(&srcBitmap); renderHelper(&srcPainter, inheritMask, matteRle, cache); srcPainter.end(); - painter->drawBitmap(VPoint(), srcBitmap, uchar(combinedAlpha() * 255.0f)); + painter->drawBitmap(VPoint(), srcBitmap, + uchar(combinedAlpha() * 255.0f)); cache.release_surface(srcBitmap); } else { renderHelper(painter, inheritMask, matteRle, cache); @@ -490,8 +495,10 @@ void LOTCompLayerItem::render(VPainter *painter, const VRle &inheritMask, } } -void LOTCompLayerItem::renderHelper(VPainter *painter, const VRle &inheritMask, - const VRle &matteRle, SurfaceCache& cache) +void renderer::CompLayer::renderHelper(VPainter * painter, + const VRle & inheritMask, + const VRle & matteRle, + SurfaceCache &cache) { VRle mask; if (mLayerMask) { @@ -508,7 +515,7 @@ void LOTCompLayerItem::renderHelper(VPainter *painter, const VRle &inheritMask, if (mask.empty()) return; } - LOTLayerItem *matte = nullptr; + renderer::Layer *matte = nullptr; for (const auto &layer : mLayers) { if (layer->hasMatte()) { matte = layer; @@ -516,8 +523,8 @@ void LOTCompLayerItem::renderHelper(VPainter *painter, const VRle &inheritMask, if (layer->visible()) { if (matte) { if (matte->visible()) - renderMatteLayer(painter, mask, matteRle, matte, - layer, cache); + renderMatteLayer(painter, mask, matteRle, matte, layer, + cache); } else { layer->render(painter, mask, matteRle, cache); } @@ -527,34 +534,36 @@ void LOTCompLayerItem::renderHelper(VPainter *painter, const VRle &inheritMask, } } -void LOTCompLayerItem::renderMatteLayer(VPainter *painter, const VRle &mask, - const VRle & matteRle, - LOTLayerItem *layer, LOTLayerItem *src, SurfaceCache& cache) +void renderer::CompLayer::renderMatteLayer(VPainter *painter, const VRle &mask, + const VRle & matteRle, + renderer::Layer *layer, + renderer::Layer *src, + SurfaceCache & cache) { VSize size = painter->clipBoundingRect().size(); // Decide if we can use fast matte. // 1. draw src layer to matte buffer VPainter srcPainter; - VBitmap srcBitmap = cache.make_surface(size.width(), size.height()); + VBitmap srcBitmap = cache.make_surface(size.width(), size.height()); srcPainter.begin(&srcBitmap); src->render(&srcPainter, mask, matteRle, cache); srcPainter.end(); // 2. draw layer to layer buffer VPainter layerPainter; - VBitmap layerBitmap = cache.make_surface(size.width(), size.height()); + VBitmap layerBitmap = cache.make_surface(size.width(), size.height()); layerPainter.begin(&layerBitmap); layer->render(&layerPainter, mask, matteRle, cache); // 2.1update composition mode switch (layer->matteType()) { - case MatteType::Alpha: - case MatteType::Luma: { + case model::MatteType::Alpha: + case model::MatteType::Luma: { layerPainter.setBlendMode(BlendMode::DestIn); break; } - case MatteType::AlphaInv: - case MatteType::LumaInv: { + case model::MatteType::AlphaInv: + case model::MatteType::LumaInv: { layerPainter.setBlendMode(BlendMode::DestOut); break; } @@ -563,8 +572,8 @@ void LOTCompLayerItem::renderMatteLayer(VPainter *painter, const VRle &mask, } // 2.2 update srcBuffer if the matte is luma type - if (layer->matteType() == MatteType::Luma || - layer->matteType() == MatteType::LumaInv) { + if (layer->matteType() == model::MatteType::Luma || + layer->matteType() == model::MatteType::LumaInv) { srcBitmap.updateLuma(); } @@ -578,7 +587,7 @@ void LOTCompLayerItem::renderMatteLayer(VPainter *painter, const VRle &mask, cache.release_surface(layerBitmap); } -void LOTClipperItem::update(const VMatrix &matrix) +void renderer::Clipper::update(const VMatrix &matrix) { mPath.reset(); mPath.addRect(VRectF(0, 0, mSize.width(), mSize.height())); @@ -586,25 +595,23 @@ void LOTClipperItem::update(const VMatrix &matrix) mRasterRequest = true; } -void LOTClipperItem::preprocess(const VRect &clip) +void renderer::Clipper::preprocess(const VRect &clip) { - if (mRasterRequest) - mRasterizer.rasterize(mPath, FillRule::Winding, clip); + if (mRasterRequest) mRasterizer.rasterize(mPath, FillRule::Winding, clip); mRasterRequest = false; } -VRle LOTClipperItem::rle(const VRle& mask) +VRle renderer::Clipper::rle(const VRle &mask) { - if (mask.empty()) - return mRasterizer.rle(); + if (mask.empty()) return mRasterizer.rle(); mMaskedRle.clone(mask); mMaskedRle &= mRasterizer.rle(); return mMaskedRle; } -void LOTCompLayerItem::updateContent() +void renderer::CompLayer::updateContent() { if (mClipper && flag().testFlag(DirtyFlagBit::Matrix)) { mClipper->update(combinedMatrix()); @@ -617,12 +624,12 @@ void LOTCompLayerItem::updateContent() } } -void LOTCompLayerItem::preprocessStage(const VRect &clip) +void renderer::CompLayer::preprocessStage(const VRect &clip) { // if layer has clipper if (mClipper) mClipper->preprocess(clip); - LOTLayerItem *matte = nullptr; + renderer::Layer *matte = nullptr; for (const auto &layer : mLayers) { if (layer->hasMatte()) { matte = layer; @@ -642,46 +649,44 @@ void LOTCompLayerItem::preprocessStage(const VRect &clip) } } -LOTSolidLayerItem::LOTSolidLayerItem(LOTLayerData *layerData) - : LOTLayerItem(layerData) +renderer::SolidLayer::SolidLayer(model::Layer *layerData) + : renderer::Layer(layerData) { mDrawableList = &mRenderNode; } -void LOTSolidLayerItem::updateContent() +void renderer::SolidLayer::updateContent() { if (flag() & DirtyFlagBit::Matrix) { VPath path; - path.addRect( - VRectF(0, 0, - mLayerData->layerSize().width(), - mLayerData->layerSize().height())); + path.addRect(VRectF(0, 0, mLayerData->layerSize().width(), + mLayerData->layerSize().height())); path.transform(combinedMatrix()); mRenderNode.mFlag |= VDrawable::DirtyState::Path; mRenderNode.mPath = path; } if (flag() & DirtyFlagBit::Alpha) { - LottieColor color = mLayerData->solidColor(); - VBrush brush(color.toColor(combinedAlpha())); + model::Color color = mLayerData->solidColor(); + VBrush brush(color.toColor(combinedAlpha())); mRenderNode.setBrush(brush); mRenderNode.mFlag |= VDrawable::DirtyState::Brush; } } -void LOTSolidLayerItem::preprocessStage(const VRect& clip) +void renderer::SolidLayer::preprocessStage(const VRect &clip) { mRenderNode.preprocess(clip); } -DrawableList LOTSolidLayerItem::renderList() +renderer::DrawableList renderer::SolidLayer::renderList() { if (skipRendering()) return {}; - return {&mDrawableList , 1}; + return {&mDrawableList, 1}; } -LOTImageLayerItem::LOTImageLayerItem(LOTLayerData *layerData) - : LOTLayerItem(layerData) +renderer::ImageLayer::ImageLayer(model::Layer *layerData) + : renderer::Layer(layerData) { mDrawableList = &mRenderNode; @@ -692,7 +697,7 @@ LOTImageLayerItem::LOTImageLayerItem(LOTLayerData *layerData) mRenderNode.setBrush(brush); } -void LOTImageLayerItem::updateContent() +void renderer::ImageLayer::updateContent() { if (!mLayerData->asset()) return; @@ -711,71 +716,71 @@ void LOTImageLayerItem::updateContent() } } -void LOTImageLayerItem::preprocessStage(const VRect& clip) +void renderer::ImageLayer::preprocessStage(const VRect &clip) { mRenderNode.preprocess(clip); } -DrawableList LOTImageLayerItem::renderList() +renderer::DrawableList renderer::ImageLayer::renderList() { if (skipRendering()) return {}; - return {&mDrawableList , 1}; + return {&mDrawableList, 1}; } -LOTNullLayerItem::LOTNullLayerItem(LOTLayerData *layerData) - : LOTLayerItem(layerData) +renderer::NullLayer::NullLayer(model::Layer *layerData) + : renderer::Layer(layerData) { } -void LOTNullLayerItem::updateContent() {} +void renderer::NullLayer::updateContent() {} -static LOTContentItem* -createContentItem(LOTData *contentData, VArenaAlloc* allocator) +static renderer::Object *createContentItem(model::Object *contentData, + VArenaAlloc * allocator) { switch (contentData->type()) { - case LOTData::Type::ShapeGroup: { - return allocator->make( - static_cast(contentData), allocator); + case model::Object::Type::Group: { + return allocator->make( + static_cast(contentData), allocator); } - case LOTData::Type::Rect: { - return allocator->make( - static_cast(contentData)); + case model::Object::Type::Rect: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::Ellipse: { - return allocator->make( - static_cast(contentData)); + case model::Object::Type::Ellipse: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::Shape: { - return allocator->make( - static_cast(contentData)); + case model::Object::Type::Path: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::Polystar: { - return allocator->make( - static_cast(contentData)); + case model::Object::Type::Polystar: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::Fill: { - return allocator->make( - static_cast(contentData)); + case model::Object::Type::Fill: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::GFill: { - return allocator->make( - static_cast(contentData)); + case model::Object::Type::GFill: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::Stroke: { - return allocator->make( - static_cast(contentData)); + case model::Object::Type::Stroke: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::GStroke: { - return allocator->make( - static_cast(contentData)); + case model::Object::Type::GStroke: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::Repeater: { - return allocator->make( - static_cast(contentData), allocator); + case model::Object::Type::Repeater: { + return allocator->make( + static_cast(contentData), allocator); } - case LOTData::Type::Trim: { - return allocator->make( - static_cast(contentData)); + case model::Object::Type::Trim: { + return allocator->make( + static_cast(contentData)); } default: return nullptr; @@ -783,13 +788,14 @@ createContentItem(LOTData *contentData, VArenaAlloc* allocator) } } -LOTShapeLayerItem::LOTShapeLayerItem(LOTLayerData *layerData, VArenaAlloc* allocator) - : LOTLayerItem(layerData), - mRoot(allocator->make(nullptr, allocator)) +renderer::ShapeLayer::ShapeLayer(model::Layer *layerData, + VArenaAlloc * allocator) + : renderer::Layer(layerData), + mRoot(allocator->make(nullptr, allocator)) { mRoot->addChildren(layerData, allocator); - std::vector list; + std::vector list; mRoot->processPaintItems(list); if (layerData->hasPathOperator()) { @@ -798,7 +804,7 @@ LOTShapeLayerItem::LOTShapeLayerItem(LOTLayerData *layerData, VArenaAlloc* alloc } } -void LOTShapeLayerItem::updateContent() +void renderer::ShapeLayer::updateContent() { mRoot->update(frameNo(), combinedMatrix(), combinedAlpha(), flag()); @@ -807,16 +813,15 @@ void LOTShapeLayerItem::updateContent() } } -void LOTShapeLayerItem::preprocessStage(const VRect& clip) +void renderer::ShapeLayer::preprocessStage(const VRect &clip) { mDrawableList.clear(); mRoot->renderList(mDrawableList); for (auto &drawable : mDrawableList) drawable->preprocess(clip); - } -DrawableList LOTShapeLayerItem::renderList() +renderer::DrawableList renderer::ShapeLayer::renderList() { if (skipRendering()) return {}; @@ -825,24 +830,24 @@ DrawableList LOTShapeLayerItem::renderList() if (mDrawableList.empty()) return {}; - return {mDrawableList.data() , mDrawableList.size()}; + return {mDrawableList.data(), mDrawableList.size()}; } -bool LOTContentGroupItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, - LOTVariant &value) +bool renderer::Group::resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) { - if (!keyPath.skip(name())) { + if (!keyPath.skip(name())) { if (!keyPath.matches(mModel.name(), depth)) { - return false; + return false; } if (!keyPath.skip(mModel.name())) { - if (keyPath.fullyResolvesTo(mModel.name(), depth) && - transformProp(value.property())) { - mModel.filter().addValue(value); - } + if (keyPath.fullyResolvesTo(mModel.name(), depth) && + transformProp(value.property())) { + mModel.filter().addValue(value); + } } - } + } if (keyPath.propagate(name(), depth)) { uint newDepth = keyPath.nextDepth(name(), depth); @@ -853,8 +858,8 @@ bool LOTContentGroupItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, return true; } -bool LOTFillItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, - LOTVariant &value) +bool renderer::Fill::resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) { if (!keyPath.matches(mModel.name(), depth)) { return false; @@ -868,8 +873,8 @@ bool LOTFillItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, return false; } -bool LOTStrokeItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, - LOTVariant &value) +bool renderer::Stroke::resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) { if (!keyPath.matches(mModel.name(), depth)) { return false; @@ -883,13 +888,13 @@ bool LOTStrokeItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, return false; } -LOTContentGroupItem::LOTContentGroupItem(LOTGroupData *data, VArenaAlloc* allocator) +renderer::Group::Group(model::Group *data, VArenaAlloc *allocator) : mModel(data) { addChildren(data, allocator); } -void LOTContentGroupItem::addChildren(LOTGroupData *data, VArenaAlloc* allocator) +void renderer::Group::addChildren(model::Group *data, VArenaAlloc *allocator) { if (!data) return; @@ -898,7 +903,7 @@ void LOTContentGroupItem::addChildren(LOTGroupData *data, VArenaAlloc* allocator // keep the content in back-to-front order. // as lottie model keeps it in front-to-back order. for (auto it = data->mChildren.crbegin(); it != data->mChildren.rend(); - ++it ) { + ++it) { auto content = createContentItem(*it, allocator); if (content) { mContents.push_back(content); @@ -906,11 +911,11 @@ void LOTContentGroupItem::addChildren(LOTGroupData *data, VArenaAlloc* allocator } } -void LOTContentGroupItem::update(int frameNo, const VMatrix &parentMatrix, - float parentAlpha, const DirtyFlag &flag) +void renderer::Group::update(int frameNo, const VMatrix &parentMatrix, + float parentAlpha, const DirtyFlag &flag) { DirtyFlag newFlag = flag; - float alpha; + float alpha; if (mModel.hasModel() && mModel.transform()) { VMatrix m = mModel.matrix(frameNo); @@ -937,17 +942,17 @@ void LOTContentGroupItem::update(int frameNo, const VMatrix &parentMatrix, } } -void LOTContentGroupItem::applyTrim() +void renderer::Group::applyTrim() { for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) { auto content = (*i); switch (content->type()) { - case ContentType::Trim: { - static_cast(content)->update(); + case renderer::Object::Type::Trim: { + static_cast(content)->update(); break; } - case ContentType::Group: { - static_cast(content)->applyTrim(); + case renderer::Object::Type::Group: { + static_cast(content)->applyTrim(); break; } default: @@ -956,34 +961,32 @@ void LOTContentGroupItem::applyTrim() } } -void LOTContentGroupItem::renderList(std::vector &list) +void renderer::Group::renderList(std::vector &list) { for (const auto &content : mContents) { content->renderList(list); } } -void LOTContentGroupItem::processPaintItems( - std::vector &list) +void renderer::Group::processPaintItems(std::vector &list) { size_t curOpCount = list.size(); for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) { auto content = (*i); switch (content->type()) { - case ContentType::Path: { - auto pathItem = static_cast(content); + case renderer::Object::Type::Shape: { + auto pathItem = static_cast(content); pathItem->setParent(this); list.push_back(pathItem); break; } - case ContentType::Paint: { - static_cast(content)->addPathItems(list, - curOpCount); + case renderer::Object::Type::Paint: { + static_cast(content)->addPathItems(list, + curOpCount); break; } - case ContentType::Group: { - static_cast(content)->processPaintItems( - list); + case renderer::Object::Type::Group: { + static_cast(content)->processPaintItems(list); break; } default: @@ -992,23 +995,24 @@ void LOTContentGroupItem::processPaintItems( } } -void LOTContentGroupItem::processTrimItems(std::vector &list) +void renderer::Group::processTrimItems(std::vector &list) { size_t curOpCount = list.size(); for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) { auto content = (*i); switch (content->type()) { - case ContentType::Path: { - list.push_back(static_cast(content)); + case renderer::Object::Type::Shape: { + list.push_back(static_cast(content)); break; } - case ContentType::Trim: { - static_cast(content)->addPathItems(list, curOpCount); + case renderer::Object::Type::Trim: { + static_cast(content)->addPathItems(list, + curOpCount); break; } - case ContentType::Group: { - static_cast(content)->processTrimItems(list); + case renderer::Object::Type::Group: { + static_cast(content)->processTrimItems(list); break; } default: @@ -1018,7 +1022,7 @@ void LOTContentGroupItem::processTrimItems(std::vector &list) } /* - * LOTPathDataItem uses 2 path objects for path object reuse. + * renderer::Shape uses 2 path objects for path object reuse. * mLocalPath - keeps track of the local path of the item before * applying path operation and transformation. * mTemp - keeps a referece to the mLocalPath and can be updated by the @@ -1034,7 +1038,7 @@ void LOTContentGroupItem::processTrimItems(std::vector &list) * carefull about the refcount so that we don't generate deep copy while * modifying the path objects. */ -void LOTPathDataItem::update(int frameNo, const VMatrix &, float, +void renderer::Shape::update(int frameNo, const VMatrix &, float, const DirtyFlag &flag) { mDirtyPath = false; @@ -1059,17 +1063,17 @@ void LOTPathDataItem::update(int frameNo, const VMatrix &, float, } } -void LOTPathDataItem::finalPath(VPath& result) +void renderer::Shape::finalPath(VPath &result) { - result.addPath(mTemp, static_cast(parent())->matrix()); + result.addPath(mTemp, static_cast(parent())->matrix()); } -LOTRectItem::LOTRectItem(LOTRectData *data) - : LOTPathDataItem(data->isStatic()), mData(data) +renderer::Rect::Rect(model::Rect *data) + : renderer::Shape(data->isStatic()), mData(data) { } -void LOTRectItem::updatePath(VPath &path, int frameNo) +void renderer::Rect::updatePath(VPath &path, int frameNo) { VPointF pos = mData->mPos.value(frameNo); VPointF size = mData->mSize.value(frameNo); @@ -1081,12 +1085,12 @@ void LOTRectItem::updatePath(VPath &path, int frameNo) path.addRoundRect(r, roundness, mData->direction()); } -LOTEllipseItem::LOTEllipseItem(LOTEllipseData *data) - : LOTPathDataItem(data->isStatic()), mData(data) +renderer::Ellipse::Ellipse(model::Ellipse *data) + : renderer::Shape(data->isStatic()), mData(data) { } -void LOTEllipseItem::updatePath(VPath &path, int frameNo) +void renderer::Ellipse::updatePath(VPath &path, int frameNo) { VPointF pos = mData->mPos.value(frameNo); VPointF size = mData->mSize.value(frameNo); @@ -1097,22 +1101,22 @@ void LOTEllipseItem::updatePath(VPath &path, int frameNo) path.addOval(r, mData->direction()); } -LOTShapeItem::LOTShapeItem(LOTShapeData *data) - : LOTPathDataItem(data->isStatic()), mData(data) +renderer::Path::Path(model::Path *data) + : renderer::Shape(data->isStatic()), mData(data) { } -void LOTShapeItem::updatePath(VPath &path, int frameNo) +void renderer::Path::updatePath(VPath &path, int frameNo) { mData->mShape.value(frameNo, path); } -LOTPolystarItem::LOTPolystarItem(LOTPolystarData *data) - : LOTPathDataItem(data->isStatic()), mData(data) +renderer::Polystar::Polystar(model::Polystar *data) + : renderer::Shape(data->isStatic()), mData(data) { } -void LOTPolystarItem::updatePath(VPath &path, int frameNo) +void renderer::Polystar::updatePath(VPath &path, int frameNo) { VPointF pos = mData->mPos.value(frameNo); float points = mData->mPointCount.value(frameNo); @@ -1125,7 +1129,7 @@ void LOTPolystarItem::updatePath(VPath &path, int frameNo) path.reset(); VMatrix m; - if (mData->mPolyType == LOTPolystarData::PolyType::Star) { + if (mData->mPolyType == model::Polystar::PolyType::Star) { path.addPolystar(points, innerRadius, outerRadius, innerRoundness, outerRoundness, 0.0, 0.0, 0.0, mData->direction()); } else { @@ -1142,19 +1146,16 @@ void LOTPolystarItem::updatePath(VPath &path, int frameNo) * PaintData Node handling * */ -LOTPaintDataItem::LOTPaintDataItem(bool staticContent) - : mStaticContent(staticContent) -{ -} +renderer::Paint::Paint(bool staticContent) : mStaticContent(staticContent) {} -void LOTPaintDataItem::update(int frameNo, const VMatrix & parentMatrix, - float parentAlpha, const DirtyFlag &/*flag*/) +void renderer::Paint::update(int frameNo, const VMatrix &parentMatrix, + float parentAlpha, const DirtyFlag & /*flag*/) { mRenderNodeUpdate = true; mContentToRender = updateContent(frameNo, parentMatrix, parentAlpha); } -void LOTPaintDataItem::updateRenderNode() +void renderer::Paint::updateRenderNode() { bool dirty = false; for (auto &i : mPathItems) { @@ -1176,7 +1177,7 @@ void LOTPaintDataItem::updateRenderNode() } } -void LOTPaintDataItem::renderList(std::vector &list) +void renderer::Paint::renderList(std::vector &list) { if (mRenderNodeUpdate) { updateRenderNode(); @@ -1194,20 +1195,20 @@ void LOTPaintDataItem::renderList(std::vector &list) if (mContentToRender) list.push_back(&mDrawable); } -void LOTPaintDataItem::addPathItems(std::vector &list, - size_t startOffset) +void renderer::Paint::addPathItems(std::vector &list, + size_t startOffset) { std::copy(list.begin() + startOffset, list.end(), back_inserter(mPathItems)); } -LOTFillItem::LOTFillItem(LOTFillData *data) - : LOTPaintDataItem(data->isStatic()), mModel(data) +renderer::Fill::Fill(model::Fill *data) + : renderer::Paint(data->isStatic()), mModel(data) { mDrawable.setName(mModel.name()); } -bool LOTFillItem::updateContent(int frameNo, const VMatrix &, float alpha) +bool renderer::Fill::updateContent(int frameNo, const VMatrix &, float alpha) { auto combinedAlpha = alpha * mModel.opacity(frameNo); auto color = mModel.color(frameNo).toColor(combinedAlpha); @@ -1219,13 +1220,14 @@ bool LOTFillItem::updateContent(int frameNo, const VMatrix &, float alpha) return !color.isTransparent(); } -LOTGFillItem::LOTGFillItem(LOTGFillData *data) - : LOTPaintDataItem(data->isStatic()), mData(data) +renderer::GradientFill::GradientFill(model::GradientFill *data) + : renderer::Paint(data->isStatic()), mData(data) { mDrawable.setName(mData->name()); } -bool LOTGFillItem::updateContent(int frameNo, const VMatrix &matrix, float alpha) +bool renderer::GradientFill::updateContent(int frameNo, const VMatrix &matrix, + float alpha) { float combinedAlpha = alpha * mData->opacity(frameNo); @@ -1238,8 +1240,8 @@ bool LOTGFillItem::updateContent(int frameNo, const VMatrix &matrix, float alpha return !vIsZero(combinedAlpha); } -LOTStrokeItem::LOTStrokeItem(LOTStrokeData *data) - : LOTPaintDataItem(data->isStatic()), mModel(data) +renderer::Stroke::Stroke(model::Stroke *data) + : renderer::Paint(data->isStatic()), mModel(data) { mDrawable.setName(mModel.name()); if (mModel.hasDashInfo()) { @@ -1251,7 +1253,8 @@ LOTStrokeItem::LOTStrokeItem(LOTStrokeData *data) static thread_local std::vector Dash_Vector; -bool LOTStrokeItem::updateContent(int frameNo, const VMatrix &matrix, float alpha) +bool renderer::Stroke::updateContent(int frameNo, const VMatrix &matrix, + float alpha) { auto combinedAlpha = alpha * mModel.opacity(frameNo); auto color = mModel.color(frameNo).toColor(combinedAlpha); @@ -1260,7 +1263,8 @@ bool LOTStrokeItem::updateContent(int frameNo, const VMatrix &matrix, float alph mDrawable.setBrush(brush); float scale = matrix.scale(); mDrawable.setStrokeInfo(mModel.capStyle(), mModel.joinStyle(), - mModel.miterLimit(), mModel.strokeWidth(frameNo) * scale); + mModel.miterLimit(), + mModel.strokeWidth(frameNo) * scale); if (mModel.hasDashInfo()) { Dash_Vector.clear(); @@ -1274,8 +1278,8 @@ bool LOTStrokeItem::updateContent(int frameNo, const VMatrix &matrix, float alph return !color.isTransparent(); } -LOTGStrokeItem::LOTGStrokeItem(LOTGStrokeData *data) - : LOTPaintDataItem(data->isStatic()), mData(data) +renderer::GradientStroke::GradientStroke(model::GradientStroke *data) + : renderer::Paint(data->isStatic()), mData(data) { mDrawable.setName(mData->name()); if (mData->hasDashInfo()) { @@ -1285,7 +1289,8 @@ LOTGStrokeItem::LOTGStrokeItem(LOTGStrokeData *data) } } -bool LOTGStrokeItem::updateContent(int frameNo, const VMatrix &matrix, float alpha) +bool renderer::GradientStroke::updateContent(int frameNo, const VMatrix &matrix, + float alpha) { float combinedAlpha = alpha * mData->opacity(frameNo); @@ -1294,7 +1299,7 @@ bool LOTGStrokeItem::updateContent(int frameNo, const VMatrix &matrix, float alp mGradient->mMatrix = matrix; auto scale = mGradient->mMatrix.scale(); mDrawable.setBrush(VBrush(mGradient.get())); - mDrawable.setStrokeInfo(mData->capStyle(), mData->joinStyle(), + mDrawable.setStrokeInfo(mData->capStyle(), mData->joinStyle(), mData->miterLimit(), mData->width(frameNo) * scale); if (mData->hasDashInfo()) { @@ -1309,19 +1314,14 @@ bool LOTGStrokeItem::updateContent(int frameNo, const VMatrix &matrix, float alp return !vIsZero(combinedAlpha); } -LOTTrimItem::LOTTrimItem(LOTTrimData *data) - : mData(data) -{ -} - -void LOTTrimItem::update(int frameNo, const VMatrix & /*parentMatrix*/, - float /*parentAlpha*/, const DirtyFlag & /*flag*/) +void renderer::Trim::update(int frameNo, const VMatrix & /*parentMatrix*/, + float /*parentAlpha*/, const DirtyFlag & /*flag*/) { mDirty = false; if (mCache.mFrameNo == frameNo) return; - LOTTrimData::Segment segment = mData->segment(frameNo); + model::Trim::Segment segment = mData->segment(frameNo); if (!(vCompare(mCache.mSegment.start, segment.start) && vCompare(mCache.mSegment.end, segment.end))) { @@ -1331,7 +1331,7 @@ void LOTTrimItem::update(int frameNo, const VMatrix & /*parentMatrix*/, mCache.mFrameNo = frameNo; } -void LOTTrimItem::update() +void renderer::Trim::update() { // when both path and trim are not dirty if (!(mDirty || pathDirty())) return; @@ -1350,12 +1350,12 @@ void LOTTrimItem::update() return; } - if (mData->type() == LOTTrimData::TrimType::Simultaneously) { + if (mData->type() == model::Trim::TrimType::Simultaneously) { for (auto &i : mPathItems) { mPathMesure.setRange(mCache.mSegment.start, mCache.mSegment.end); i->updatePath(mPathMesure.trim(i->localPath())); } - } else { // LOTTrimData::TrimType::Individually + } else { // model::Trim::TrimType::Individually float totalLength = 0.0; for (auto &i : mPathItems) { totalLength += i->localPath().length(); @@ -1396,29 +1396,30 @@ void LOTTrimItem::update() } } -void LOTTrimItem::addPathItems(std::vector &list, - size_t startOffset) +void renderer::Trim::addPathItems(std::vector &list, + size_t startOffset) { std::copy(list.begin() + startOffset, list.end(), back_inserter(mPathItems)); } -LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data, VArenaAlloc* allocator) : mRepeaterData(data) +renderer::Repeater::Repeater(model::Repeater *data, VArenaAlloc *allocator) + : mRepeaterData(data) { assert(mRepeaterData->content()); mCopies = mRepeaterData->maxCopies(); for (int i = 0; i < mCopies; i++) { - auto content = - allocator->make(mRepeaterData->content(), allocator); - //content->setParent(this); + auto content = allocator->make( + mRepeaterData->content(), allocator); + // content->setParent(this); mContents.push_back(content); } } -void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix, - float parentAlpha, const DirtyFlag &flag) +void renderer::Repeater::update(int frameNo, const VMatrix &parentMatrix, + float parentAlpha, const DirtyFlag &flag) { DirtyFlag newFlag = flag; @@ -1453,8 +1454,8 @@ void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix, } } -void LOTRepeaterItem::renderList(std::vector &list) +void renderer::Repeater::renderList(std::vector &list) { if (mHidden) return; - return LOTContentGroupItem::renderList(list); + return renderer::Group::renderList(list); } diff --git a/src/lottie/lottieitem.h b/src/lottie/lottieitem.h index 09bc5d5..03ca77d 100644 --- a/src/lottie/lottieitem.h +++ b/src/lottie/lottieitem.h @@ -13,571 +13,608 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LOTTIEITEM_H #define LOTTIEITEM_H -#include -#include - -#include"lottieproxymodel.h" -#include"vmatrix.h" -#include"vpath.h" -#include"vpoint.h" -#include"vpathmesure.h" -#include"rlottiecommon.h" -#include"rlottie.h" -#include"vpainter.h" -#include"vdrawable.h" -#include"lottiekeypath.h" -#include"varenaalloc.h" +#include +#include + +#include "lottiekeypath.h" +#include "lottieproxymodel.h" +#include "rlottie.h" +#include "rlottiecommon.h" +#include "varenaalloc.h" +#include "vdrawable.h" +#include "vmatrix.h" +#include "vpainter.h" +#include "vpath.h" +#include "vpathmesure.h" +#include "vpoint.h" V_USE_NAMESPACE -enum class DirtyFlagBit : uchar -{ - None = 0x00, - Matrix = 0x01, - Alpha = 0x02, - All = (Matrix | Alpha) -}; +namespace rlottie { -class LOTLayerItem; -class LOTMaskItem; -class VDrawable; +namespace internal { -class LOTDrawable : public VDrawable -{ -public: - void sync(); +template +class VSpan { public: - std::unique_ptr mCNode{nullptr}; + using reference = T &; + using pointer = T *; + using const_pointer = T const *; + using const_reference = T const &; + using index_type = size_t; - ~LOTDrawable() { - if (mCNode && mCNode->mGradient.stopPtr) - free(mCNode->mGradient.stopPtr); + 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; + +enum class DirtyFlagBit : uchar { + None = 0x00, + Matrix = 0x01, + Alpha = 0x02, + All = (Matrix | Alpha) }; +typedef vFlag DirtyFlag; -class SurfaceCache -{ -public: - SurfaceCache(){mCache.reserve(10);} +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}; + 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); + auto surface = mCache.back(); + surface.reset(width, height, format); - mCache.pop_back(); - return surface; - } + mCache.pop_back(); + return surface; + } - void release_surface(VBitmap& surface) - { - mCache.push_back(surface); - } + void release_surface(VBitmap &surface) { mCache.push_back(surface); } private: - std::vector mCache; + std::vector mCache; }; -class LOTCompItem -{ +class Drawable : public VDrawable { public: - explicit LOTCompItem(LOTModel *model); - 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; - LOTCompositionData *mCompData{nullptr}; - LOTLayerItem *mRootLayer{nullptr}; - VArenaAlloc mAllocator{2048}; - int mCurFrameNo; - bool mKeepAspectRatio{true}; + void sync(); + +public: + std::unique_ptr mCNode{nullptr}; + + ~Drawable() + { + if (mCNode && mCNode->mGradient.stopPtr) + free(mCNode->mGradient.stopPtr); + } }; -class LOTLayerMaskItem; +struct CApiData { + CApiData(); + LOTLayerNode mLayer; + std::vector mMasks; + std::vector mLayers; + std::vector mCNodeList; +}; -class LOTClipperItem -{ +class Clipper { public: - explicit LOTClipperItem(VSize size): mSize(size){} + explicit Clipper(VSize size) : mSize(size) {} void update(const VMatrix &matrix); void preprocess(const VRect &clip); - VRle rle(const VRle& mask); + VRle rle(const VRle &mask); + public: - VSize mSize; - VPath mPath; - VRle mMaskedRle; - VRasterizer mRasterizer; - bool mRasterRequest{false}; + VSize mSize; + VPath mPath; + VRle mMaskedRle; + VRasterizer mRasterizer; + bool mRasterRequest{false}; }; -typedef vFlag DirtyFlag; +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); -struct LOTCApiData -{ - LOTCApiData(); - LOTLayerNode mLayer; - std::vector mMasks; - std::vector mLayers; - std::vector mCNodeList; +public: + model::Mask *mData{nullptr}; + VPath mLocalPath; + VPath mFinalPath; + VRasterizer mRasterizer; + float mCombinedAlpha{0}; + bool mRasterRequest{false}; }; -template< class T> -class VSpan -{ +/* + * Handels mask property of a layer item + */ +class LayerMask { public: - using reference = T &; - using pointer = T *; - using const_pointer = T const *; - using const_reference = T const &; - using index_type = size_t; + 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); - using iterator = pointer; - using const_iterator = const_pointer; +public: + std::vector mMasks; + VRle mRle; + bool mStatic{true}; + bool mDirty{true}; +}; - VSpan() = default; - VSpan(pointer data, index_type size):_data(data), _size(size){} +class Layer; - 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 );} +class Composition { +public: + explicit Composition(std::shared_ptr 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: - pointer _data{nullptr}; - index_type _size{0}; + SurfaceCache mSurfaceCache; + VBitmap mSurface; + VMatrix mScaleMatrix; + VSize mViewSize; + std::shared_ptr mModel; + Layer * mRootLayer{nullptr}; + VArenaAlloc mAllocator{2048}; + int mCurFrameNo; + bool mKeepAspectRatio{true}; }; -using DrawableList = VSpan; - -class LOTLayerItem -{ +class Layer { public: - virtual ~LOTLayerItem() = default; - LOTLayerItem& operator=(LOTLayerItem&&) noexcept = delete; - LOTLayerItem(LOTLayerData *layerData); - int id() const {return mLayerData->id();} - int parentId() const {return mLayerData->parentId();} - void setParentLayer(LOTLayerItem *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 == MatteType::None) return false; return true; } - MatteType matteType() const { return mLayerData->mMatteType;} - bool visible() const; - virtual void buildLayerNode(); - LOTLayerNode& clayer() {return mCApiData->mLayer;} - std::vector& clayers() {return mCApiData->mLayers;} - std::vector& cmasks() {return mCApiData->mMasks;} - std::vector& cnodes() {return mCApiData->mCNodeList;} - const char* name() const {return mLayerData->name();} - virtual bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value); + 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 &clayers() { return mCApiData->mLayers; } + std::vector & cmasks() { return mCApiData->mMasks; } + std::vector & 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()));} + 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 mLayerMask; - LOTLayerData *mLayerData{nullptr}; - LOTLayerItem *mParentLayer{nullptr}; - VMatrix mCombinedMatrix; - float mCombinedAlpha{0.0}; - int mFrameNo{-1}; - DirtyFlag mDirtyFlag{DirtyFlagBit::All}; - bool mComplexContent{false}; - std::unique_ptr mCApiData; + std::unique_ptr 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 mCApiData; }; -class LOTCompLayerItem: public LOTLayerItem -{ +class CompLayer : public Layer { public: - explicit LOTCompLayerItem(LOTLayerData *layerData, VArenaAlloc* allocator); + 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; - 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; + 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, - LOTLayerItem *layer, LOTLayerItem *src, SurfaceCache& cache); + 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 mLayers; - std::unique_ptr mClipper; + std::vector mLayers; + std::unique_ptr mClipper; }; -class LOTSolidLayerItem: public LOTLayerItem -{ +class SolidLayer : public Layer { public: - explicit LOTSolidLayerItem(LOTLayerData *layerData); - void buildLayerNode() final; - DrawableList renderList() final; + explicit SolidLayer(model::Layer *layerData); + void buildLayerNode() final; + DrawableList renderList() final; + protected: - void preprocessStage(const VRect& clip) final; - void updateContent() final; + void preprocessStage(const VRect &clip) final; + void updateContent() final; + private: - LOTDrawable mRenderNode; - VDrawable *mDrawableList{nullptr}; //to work with the Span api + Drawable mRenderNode; + VDrawable *mDrawableList{nullptr}; // to work with the Span api }; -class LOTContentItem; -class LOTContentGroupItem; -class LOTShapeLayerItem: public LOTLayerItem -{ -public: - explicit LOTShapeLayerItem(LOTLayerData *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 mDrawableList; - LOTContentGroupItem *mRoot{nullptr}; -}; +class Group; -class LOTNullLayerItem: public LOTLayerItem -{ +class ShapeLayer : public Layer { public: - explicit LOTNullLayerItem(LOTLayerData *layerData); + 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&) final {} - void updateContent() final; + void preprocessStage(const VRect &clip) final; + void updateContent() final; + std::vector mDrawableList; + Group * mRoot{nullptr}; }; -class LOTImageLayerItem: public LOTLayerItem -{ +class NullLayer : public Layer { public: - explicit LOTImageLayerItem(LOTLayerData *layerData); - void buildLayerNode() final; - DrawableList renderList() final; + explicit NullLayer(model::Layer *layerData); + protected: - void preprocessStage(const VRect& clip) final; - void updateContent() final; -private: - LOTDrawable mRenderNode; - VTexture mTexture; - VDrawable *mDrawableList{nullptr}; //to work with the Span api + void preprocessStage(const VRect &) final {} + void updateContent() final; }; -class LOTMaskItem -{ +class ImageLayer : public Layer { public: - explicit LOTMaskItem(LOTMaskData *data): mData(data){} - void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag); - LOTMaskData::Mode maskMode() const { return mData->mMode;} - VRle rle(); - void preprocess(const VRect &clip); -public: - LOTMaskData *mData{nullptr}; - VPath mLocalPath; - VPath mFinalPath; - VRasterizer mRasterizer; - float mCombinedAlpha{0}; - bool mRasterRequest{false}; -}; + explicit ImageLayer(model::Layer *layerData); + void buildLayerNode() final; + DrawableList renderList() final; -/* - * Handels mask property of a layer item - */ -class LOTLayerMaskItem -{ -public: - explicit LOTLayerMaskItem(LOTLayerData *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 mMasks; - VRle mRle; - bool mStatic{true}; - bool mDirty{true}; -}; +protected: + void preprocessStage(const VRect &clip) final; + void updateContent() final; -class LOTPathDataItem; -class LOTPaintDataItem; -class LOTTrimItem; - -enum class ContentType : uchar -{ - Unknown, - Group, - Path, - Paint, - Trim +private: + Drawable mRenderNode; + VTexture mTexture; + VDrawable *mDrawableList{nullptr}; // to work with the Span api }; -class LOTContentGroupItem; -class LOTContentItem -{ +class Object { public: - virtual ~LOTContentItem() = default; - LOTContentItem& operator=(LOTContentItem&&) noexcept = delete; - virtual void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) = 0; virtual void renderList(std::vector &){} - virtual bool resolveKeyPath(LOTKeyPath &, uint, LOTVariant &) {return false;} - virtual ContentType type() const {return ContentType::Unknown;} + 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 &) {} + virtual bool resolveKeyPath(LOTKeyPath &, uint, LOTVariant &) + { + return false; + } + virtual Object::Type type() const { return Object::Type::Unknown; } }; -class LOTContentGroupItem: public LOTContentItem -{ +class Shape; +class Group : public Object { public: - LOTContentGroupItem() = default; - explicit LOTContentGroupItem(LOTGroupData *data, VArenaAlloc* allocator); - void addChildren(LOTGroupData *data, VArenaAlloc* allocator); - void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) override; - void applyTrim(); - void processTrimItems(std::vector &list); - void processPaintItems(std::vector &list); - void renderList(std::vector &list) override; - ContentType type() const final {return ContentType::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; + 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 &list); + void processPaintItems(std::vector &list); + void renderList(std::vector &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 mContents; - VMatrix mMatrix; + std::vector mContents; + VMatrix mMatrix; + private: - LOTProxyModel mModel; + LOTProxyModel mModel; }; -class LOTPathDataItem : public LOTContentItem -{ +class Shape : public Object { public: - LOTPathDataItem(bool staticPath): mStaticPath(staticPath){} - void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) final; - ContentType type() const final {return ContentType::Path;} - 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(LOTContentGroupItem *parent) {mParent = parent;} - LOTContentGroupItem *parent() const {return mParent;} + 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; + 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); - } - LOTContentGroupItem *mParent{nullptr}; - VPath mLocalPath; - VPath mTemp; - int mFrameNo{-1}; - bool mDirtyPath{true}; - bool mStaticPath; + 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 LOTRectItem: public LOTPathDataItem -{ +class Rect : public Shape { public: - explicit LOTRectItem(LOTRectData *data); + explicit Rect(model::Rect *data); + protected: - void updatePath(VPath& path, int frameNo) final; - LOTRectData *mData{nullptr}; - - bool hasChanged(int prevFrame, int curFrame) final { - return (mData->mPos.changed(prevFrame, curFrame) || - mData->mSize.changed(prevFrame, curFrame) || - mData->mRound.changed(prevFrame, curFrame)); - } + 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->mRound.changed(prevFrame, curFrame)); + } }; -class LOTEllipseItem: public LOTPathDataItem -{ +class Ellipse : public Shape { public: - explicit LOTEllipseItem(LOTEllipseData *data); + explicit Ellipse(model::Ellipse *data); + private: - void updatePath(VPath& path, int frameNo) final; - LOTEllipseData *mData{nullptr}; - bool hasChanged(int prevFrame, int curFrame) final { - return (mData->mPos.changed(prevFrame, curFrame) || - mData->mSize.changed(prevFrame, curFrame)); - } + 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 LOTShapeItem: public LOTPathDataItem -{ +class Path : public Shape { public: - explicit LOTShapeItem(LOTShapeData *data); + explicit Path(model::Path *data); + private: - void updatePath(VPath& path, int frameNo) final; - LOTShapeData *mData{nullptr}; - bool hasChanged(int prevFrame, int curFrame) final { - return mData->mShape.changed(prevFrame, curFrame); - } + 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 LOTPolystarItem: public LOTPathDataItem -{ +class Polystar : public Shape { public: - explicit LOTPolystarItem(LOTPolystarData *data); + explicit Polystar(model::Polystar *data); + private: - void updatePath(VPath& path, int frameNo) final; - LOTPolystarData *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)); - } + 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 LOTPaintDataItem : public LOTContentItem -{ +class Paint : public Object { public: - LOTPaintDataItem(bool staticContent); - void addPathItems(std::vector &list, size_t startOffset); - void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) override; - void renderList(std::vector &list) final; - ContentType type() const final {return ContentType::Paint;} + Paint(bool staticContent); + void addPathItems(std::vector &list, size_t startOffset); + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag) override; + void renderList(std::vector &list) final; + Object::Type type() const final { return Object::Type::Paint; } + protected: - virtual bool updateContent(int frameNo, const VMatrix &matrix, float alpha) = 0; + virtual bool updateContent(int frameNo, const VMatrix &matrix, + float alpha) = 0; + private: - void updateRenderNode(); + void updateRenderNode(); + protected: - std::vector mPathItems; - LOTDrawable mDrawable; - VPath mPath; - DirtyFlag mFlag; - bool mStaticContent; - bool mRenderNodeUpdate{true}; - bool mContentToRender{true}; + std::vector mPathItems; + Drawable mDrawable; + VPath mPath; + DirtyFlag mFlag; + bool mStaticContent; + bool mRenderNodeUpdate{true}; + bool mContentToRender{true}; }; -class LOTFillItem : public LOTPaintDataItem -{ +class Fill : public Paint { public: - explicit LOTFillItem(LOTFillData *data); + 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; + bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) final; + private: - LOTProxyModel mModel; + LOTProxyModel mModel; }; -class LOTGFillItem : public LOTPaintDataItem -{ +class GradientFill : public Paint { public: - explicit LOTGFillItem(LOTGFillData *data); + explicit GradientFill(model::GradientFill *data); + protected: - bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + private: - LOTGFillData *mData{nullptr}; - std::unique_ptr mGradient; + model::GradientFill * mData{nullptr}; + std::unique_ptr mGradient; }; -class LOTStrokeItem : public LOTPaintDataItem -{ +class Stroke : public Paint { public: - explicit LOTStrokeItem(LOTStrokeData *data); + 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; + bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) final; + private: - LOTProxyModel mModel; + LOTProxyModel mModel; }; -class LOTGStrokeItem : public LOTPaintDataItem -{ +class GradientStroke : public Paint { public: - explicit LOTGStrokeItem(LOTGStrokeData *data); + explicit GradientStroke(model::GradientStroke *data); + protected: - bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + private: - LOTGStrokeData *mData{nullptr}; - std::unique_ptr mGradient; + model::GradientStroke * mData{nullptr}; + std::unique_ptr mGradient; }; - -// Trim Item - -class LOTTrimItem : public LOTContentItem -{ +class Trim : public Object { public: - explicit LOTTrimItem(LOTTrimData *data); - void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) final; - ContentType type() const final {return ContentType::Trim;} - void update(); - void addPathItems(std::vector &list, size_t startOffset); + 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 &list, size_t startOffset); + private: - bool pathDirty() const { - for (auto &i : mPathItems) { - if (i->dirty()) - return true; - } - return false; - } - struct Cache { - int mFrameNo{-1}; - LOTTrimData::Segment mSegment{}; - }; - Cache mCache; - std::vector mPathItems; - LOTTrimData *mData{nullptr}; - VPathMesure mPathMesure; - bool mDirty{true}; + 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 mPathItems; + model::Trim * mData{nullptr}; + VPathMesure mPathMesure; + bool mDirty{true}; }; -class LOTRepeaterItem : public LOTContentGroupItem -{ +class Repeater : public Group { public: - explicit LOTRepeaterItem(LOTRepeaterData *data, VArenaAlloc* allocator); - void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) final; - void renderList(std::vector &list) final; + explicit Repeater(model::Repeater *data, VArenaAlloc *allocator); + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag) final; + void renderList(std::vector &list) final; + private: - LOTRepeaterData *mRepeaterData{nullptr}; - bool mHidden{false}; - int mCopies{0}; + model::Repeater *mRepeaterData{nullptr}; + bool mHidden{false}; + int mCopies{0}; }; +} // namespace renderer -#endif // LOTTIEITEM_H +} // namespace internal +} // namespace rlottie +#endif // LOTTIEITEM_H diff --git a/src/lottie/lottieitem_capi.cpp b/src/lottie/lottieitem_capi.cpp index 7d8ea9f..a4d8546 100644 --- a/src/lottie/lottieitem_capi.cpp +++ b/src/lottie/lottieitem_capi.cpp @@ -9,7 +9,9 @@ #include "lottieitem.h" #include "vdasher.h" -LOTCApiData::LOTCApiData() +using namespace rlottie::internal; + +renderer::CApiData::CApiData() { mLayer.mMaskList.ptr = nullptr; mLayer.mMaskList.size = 0; @@ -27,24 +29,24 @@ LOTCApiData::LOTCApiData() mLayer.keypath = nullptr; } -void LOTCompItem::buildRenderTree() +void renderer::Composition::buildRenderTree() { mRootLayer->buildLayerNode(); } -const LOTLayerNode *LOTCompItem::renderTree() const +const LOTLayerNode *renderer::Composition::renderTree() const { return &mRootLayer->clayer(); } -void LOTCompLayerItem::buildLayerNode() +void renderer::CompLayer::buildLayerNode() { - LOTLayerItem::buildLayerNode(); + renderer::Layer::buildLayerNode(); if (mClipper) { const auto &elm = mClipper->mPath.elements(); const auto &pts = mClipper->mPath.points(); - auto ptPtr = reinterpret_cast(pts.data()); - auto elmPtr = reinterpret_cast(elm.data()); + auto ptPtr = reinterpret_cast(pts.data()); + auto elmPtr = reinterpret_cast(elm.data()); clayer().mClipPath.ptPtr = ptPtr; clayer().mClipPath.elmPtr = elmPtr; clayer().mClipPath.ptCount = 2 * pts.size(); @@ -64,16 +66,15 @@ void LOTCompLayerItem::buildLayerNode() } } - -void LOTShapeLayerItem::buildLayerNode() +void renderer::ShapeLayer::buildLayerNode() { - LOTLayerItem::buildLayerNode(); + renderer::Layer::buildLayerNode(); auto renderlist = renderList(); cnodes().clear(); for (auto &i : renderlist) { - auto lotDrawable = static_cast(i); + auto lotDrawable = static_cast(i); lotDrawable->sync(); cnodes().push_back(lotDrawable->mCNode.get()); } @@ -81,10 +82,10 @@ void LOTShapeLayerItem::buildLayerNode() clayer().mNodeList.size = cnodes().size(); } -void LOTLayerItem::buildLayerNode() +void renderer::Layer::buildLayerNode() { if (!mCApiData) { - mCApiData = std::make_unique(); + mCApiData = std::make_unique(); clayer().keypath = name(); } if (complexContent()) clayer().mAlpha = uchar(combinedAlpha() * 255.f); @@ -92,16 +93,16 @@ void LOTLayerItem::buildLayerNode() // update matte if (hasMatte()) { switch (mLayerData->mMatteType) { - case MatteType::Alpha: + case model::MatteType::Alpha: clayer().mMatte = MatteAlpha; break; - case MatteType::AlphaInv: + case model::MatteType::AlphaInv: clayer().mMatte = MatteAlphaInv; break; - case MatteType::Luma: + case model::MatteType::Luma: clayer().mMatte = MatteLuma; break; - case MatteType::LumaInv: + case model::MatteType::LumaInv: clayer().mMatte = MatteLumaInv; break; default: @@ -114,27 +115,27 @@ void LOTLayerItem::buildLayerNode() cmasks().resize(mLayerMask->mMasks.size()); size_t i = 0; for (const auto &mask : mLayerMask->mMasks) { - auto &cNode = cmasks()[i++]; + auto & cNode = cmasks()[i++]; const auto &elm = mask.mFinalPath.elements(); const auto &pts = mask.mFinalPath.points(); - auto ptPtr = reinterpret_cast(pts.data()); - auto elmPtr = reinterpret_cast(elm.data()); + auto ptPtr = reinterpret_cast(pts.data()); + auto elmPtr = reinterpret_cast(elm.data()); cNode.mPath.ptPtr = ptPtr; cNode.mPath.ptCount = pts.size(); cNode.mPath.elmPtr = elmPtr; cNode.mPath.elmCount = elm.size(); cNode.mAlpha = uchar(mask.mCombinedAlpha * 255.0f); switch (mask.maskMode()) { - case LOTMaskData::Mode::Add: + case model::Mask::Mode::Add: cNode.mMode = MaskAdd; break; - case LOTMaskData::Mode::Substarct: + case model::Mask::Mode::Substarct: cNode.mMode = MaskSubstract; break; - case LOTMaskData::Mode::Intersect: + case model::Mask::Mode::Intersect: cNode.mMode = MaskIntersect; break; - case LOTMaskData::Mode::Difference: + case model::Mask::Mode::Difference: cNode.mMode = MaskDifference; break; default: @@ -147,15 +148,15 @@ void LOTLayerItem::buildLayerNode() } } -void LOTSolidLayerItem::buildLayerNode() +void renderer::SolidLayer::buildLayerNode() { - LOTLayerItem::buildLayerNode(); + renderer::Layer::buildLayerNode(); auto renderlist = renderList(); cnodes().clear(); for (auto &i : renderlist) { - auto lotDrawable = static_cast(i); + auto lotDrawable = static_cast(i); lotDrawable->sync(); cnodes().push_back(lotDrawable->mCNode.get()); } @@ -163,15 +164,15 @@ void LOTSolidLayerItem::buildLayerNode() clayer().mNodeList.size = cnodes().size(); } -void LOTImageLayerItem::buildLayerNode() +void renderer::ImageLayer::buildLayerNode() { - LOTLayerItem::buildLayerNode(); + renderer::Layer::buildLayerNode(); auto renderlist = renderList(); cnodes().clear(); for (auto &i : renderlist) { - auto lotDrawable = static_cast(i); + auto lotDrawable = static_cast(i); lotDrawable->sync(); lotDrawable->mCNode->mImageInfo.data = @@ -194,7 +195,8 @@ void LOTImageLayerItem::buildLayerNode() lotDrawable->mCNode->mImageInfo.mMatrix.m33 = combinedMatrix().m_33(); // Alpha calculation already combined. - lotDrawable->mCNode->mImageInfo.mAlpha = uchar(lotDrawable->mBrush.mTexture->mAlpha); + lotDrawable->mCNode->mImageInfo.mAlpha = + uchar(lotDrawable->mBrush.mTexture->mAlpha); cnodes().push_back(lotDrawable->mCNode.get()); } @@ -222,7 +224,7 @@ static void updateGStops(LOTNode *n, const VGradient *grad) } } -void LOTDrawable::sync() +void renderer::Drawable::sync() { if (!mCNode) { mCNode = std::make_unique(); @@ -335,4 +337,3 @@ void LOTDrawable::sync() break; } } - diff --git a/src/lottie/lottiekeypath.h b/src/lottie/lottiekeypath.h index 921bcad..c6ab63d 100644 --- a/src/lottie/lottiekeypath.h +++ b/src/lottie/lottiekeypath.h @@ -13,34 +13,37 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LOTTIEKEYPATH_H #define LOTTIEKEYPATH_H -#include "vglobal.h" #include #include +#include "vglobal.h" -class LOTKeyPath{ +class LOTKeyPath { public: LOTKeyPath(const std::string &keyPath); bool matches(const std::string &key, uint depth); uint nextDepth(const std::string key, uint depth); bool fullyResolvesTo(const std::string key, uint depth); - bool propagate(const std::string key, uint depth) { + bool propagate(const std::string key, uint depth) + { return skip(key) ? true : (depth < size()) || (mKeys[depth] == "**"); } - bool skip(const std::string &key) const { return key == "__";} + bool skip(const std::string &key) const { return key == "__"; } + private: - bool isGlobstar(uint depth) const {return mKeys[depth] == "**";} - bool isGlob(uint depth) const {return mKeys[depth] == "*";} - bool endsWithGlobstar() const { return mKeys.back() == "**"; } - size_t size() const {return mKeys.size() - 1;} + bool isGlobstar(uint depth) const { return mKeys[depth] == "**"; } + bool isGlob(uint depth) const { return mKeys[depth] == "*"; } + bool endsWithGlobstar() const { return mKeys.back() == "**"; } + size_t size() const { return mKeys.size() - 1; } + private: std::vector mKeys; }; -#endif //LOTTIEKEYPATH_H +#endif // LOTTIEKEYPATH_H diff --git a/src/lottie/lottieloader.cpp b/src/lottie/lottieloader.cpp index 1783b0e..329c2eb 100644 --- a/src/lottie/lottieloader.cpp +++ b/src/lottie/lottieloader.cpp @@ -16,26 +16,27 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "lottieloader.h" -#include "lottieparser.h" - #include #include #include +#include "lottiemodel.h" + #ifdef LOTTIE_CACHE_SUPPORT -#include #include +#include + +using namespace rlottie::internal; -class LottieModelCache { +class ModelCache { public: - static LottieModelCache &instance() + static ModelCache &instance() { - static LottieModelCache CACHE; - return CACHE; + static ModelCache singleton; + return singleton; } - std::shared_ptr find(const std::string &key) + std::shared_ptr find(const std::string &key) { std::lock_guard guard(mMutex); @@ -44,9 +45,8 @@ public: auto search = mHash.find(key); return (search != mHash.end()) ? search->second : nullptr; - } - void add(const std::string &key, std::shared_ptr value) + void add(const std::string &key, std::shared_ptr value) { std::lock_guard guard(mMutex); @@ -68,49 +68,53 @@ public: } private: - LottieModelCache() = default; + ModelCache() = default; - std::unordered_map> mHash; - std::mutex mMutex; - size_t mcacheSize{10}; + std::unordered_map> mHash; + std::mutex mMutex; + size_t mcacheSize{10}; }; #else -class LottieModelCache { +class ModelCache { public: - static LottieModelCache &instance() + static ModelCache &instance() + { + static ModelCache singleton; + return singleton; + } + std::shared_ptr find(const std::string &) { - static LottieModelCache CACHE; - return CACHE; + return nullptr; } - std::shared_ptr find(const std::string &) { return nullptr; } - void add(const std::string &, std::shared_ptr) {} + void add(const std::string &, std::shared_ptr) {} void configureCacheSize(size_t) {} }; #endif -void LottieLoader::configureModelCacheSize(size_t cacheSize) -{ - LottieModelCache::instance().configureCacheSize(cacheSize); -} - static std::string dirname(const std::string &path) { const char *ptr = strrchr(path.c_str(), '/'); #ifdef _WIN32 if (ptr) ptr = strrchr(ptr + 1, '\\'); #endif - int len = int(ptr + 1 - path.c_str()); // +1 to include '/' + int len = int(ptr + 1 - path.c_str()); // +1 to include '/' return std::string(path, 0, len); } -bool LottieLoader::load(const std::string &path, bool cachePolicy) +void model::configureModelCacheSize(size_t cacheSize) +{ + ModelCache::instance().configureCacheSize(cacheSize); +} + +std::shared_ptr model::loadFromFile(const std::string &path, + bool cachePolicy) { if (cachePolicy) { - mModel = LottieModelCache::instance().find(path); - if (mModel) return true; + auto obj = ModelCache::instance().find(path); + if (obj) return obj; } std::ifstream f; @@ -118,56 +122,44 @@ bool LottieLoader::load(const std::string &path, bool cachePolicy) if (!f.is_open()) { vCritical << "failed to open file = " << path.c_str(); - return false; + return {}; } else { std::string content; - std::getline(f, content, '\0') ; + std::getline(f, content, '\0'); f.close(); - if (content.empty()) return false; + if (content.empty()) return {}; - const char *str = content.c_str(); - LottieParser parser(const_cast(str), dirname(path)); - mModel = parser.model(); + auto obj = internal::model::parse(const_cast(content.c_str()), + dirname(path)); - if (!mModel) return false; + if (obj && cachePolicy) ModelCache::instance().add(path, obj); - if (cachePolicy) - LottieModelCache::instance().add(path, mModel); + return obj; } - - return true; } -bool LottieLoader::loadFromData(std::string jsonData, const std::string &key, - std::string resourcePath, bool cachePolicy) +std::shared_ptr model::loadFromData( + std::string jsonData, const std::string &key, std::string resourcePath, + bool cachePolicy) { if (cachePolicy) { - mModel = LottieModelCache::instance().find(key); - if (mModel) return true; + auto obj = ModelCache::instance().find(key); + if (obj) return obj; } - LottieParser parser(const_cast(jsonData.c_str()), std::move(resourcePath)); - mModel = parser.model(); + auto obj = internal::model::parse(const_cast(jsonData.c_str()), + std::move(resourcePath)); - if (!mModel) return false; - - if (cachePolicy) - LottieModelCache::instance().add(key, mModel); - - return true; -} - -bool LottieLoader::loadFromData(std::string jsonData, std::string resourcePath, ColorFilter filter) -{ - LottieParser parser(const_cast(jsonData.c_str()), std::move(resourcePath), std::move(filter)); - mModel = parser.model(); + if (obj && cachePolicy) ModelCache::instance().add(key, obj); - return mModel ? true : false; + return obj; } -std::shared_ptr LottieLoader::model() +std::shared_ptr model::loadFromData( + std::string jsonData, std::string resourcePath, model::ColorFilter filter) { - return mModel; + return internal::model::parse(const_cast(jsonData.c_str()), + std::move(resourcePath), std::move(filter)); } diff --git a/src/lottie/lottieloader.h b/src/lottie/lottieloader.h deleted file mode 100644 index 084bbea..0000000 --- a/src/lottie/lottieloader.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LOTTIELOADER_H -#define LOTTIELOADER_H - -#include -#include - -class LOTModel; -class LottieLoader -{ -public: - using ColorFilter = std::function; - static void configureModelCacheSize(size_t cacheSize); - bool load(const std::string &filePath, bool cachePolicy); - bool loadFromData(std::string jsonData, const std::string &key, - std::string resourcePath, bool cachePolicy); - bool loadFromData(std::string jsonData, std::string resourcePath, ColorFilter filter); - std::shared_ptr model(); -private: - std::shared_ptr mModel; -}; - -#endif // LOTTIELOADER_H - - diff --git a/src/lottie/lottiemodel.cpp b/src/lottie/lottiemodel.cpp index f3e42e6..1851228 100644 --- a/src/lottie/lottiemodel.cpp +++ b/src/lottie/lottiemodel.cpp @@ -23,6 +23,8 @@ #include "vimageloader.h" #include "vline.h" +using namespace rlottie::internal; + /* * We process the iterator objects in the children list * by iterating from back to front. when we find a repeater object @@ -36,14 +38,14 @@ */ class LottieRepeaterProcesser { public: - void visitChildren(LOTGroupData *obj) + void visitChildren(model::Group *obj) { for (auto i = obj->mChildren.rbegin(); i != obj->mChildren.rend(); ++i) { auto child = (*i); - if (child->type() == LOTData::Type::Repeater) { - LOTRepeaterData *repeater = - static_cast(child); + if (child->type() == model::Object::Type::Repeater) { + model::Repeater *repeater = + static_cast(child); // check if this repeater is already processed // can happen if the layer is an asset and referenced by // multiple layer. @@ -51,7 +53,7 @@ public: repeater->markProcessed(); - LOTShapeGroupData *content = repeater->content(); + auto content = repeater->content(); // 1. increment the reverse iterator to point to the // object before the repeater ++i; @@ -71,12 +73,12 @@ public: } } - void visit(LOTData *obj) + void visit(model::Object *obj) { switch (obj->type()) { - case LOTData::Type::ShapeGroup: - case LOTData::Type::Layer: { - visitChildren(static_cast(obj)); + case model::Object::Type::Group: + case model::Object::Type::Layer: { + visitChildren(static_cast(obj)); break; } default: @@ -86,31 +88,32 @@ public: }; class LottieUpdateStatVisitor { - LOTModelStat *stat; + model::Composition::Stats *stat; + public: - explicit LottieUpdateStatVisitor(LOTModelStat *s):stat(s){} - void visitChildren(LOTGroupData *obj) + explicit LottieUpdateStatVisitor(model::Composition::Stats *s) : stat(s) {} + void visitChildren(model::Group *obj) { for (const auto &child : obj->mChildren) { if (child) visit(child); } } - void visitLayer(LOTLayerData *layer) + void visitLayer(model::Layer *layer) { switch (layer->mLayerType) { - case LayerType::Precomp: + case model::Layer::Type::Precomp: stat->precompLayerCount++; break; - case LayerType::Null: + case model::Layer::Type::Null: stat->nullLayerCount++; break; - case LayerType::Shape: + case model::Layer::Type::Shape: stat->shapeLayerCount++; break; - case LayerType::Solid: + case model::Layer::Type::Solid: stat->solidLayerCount++; break; - case LayerType::Image: + case model::Layer::Type::Image: stat->imageLayerCount++; break; default: @@ -118,41 +121,40 @@ public: } visitChildren(layer); } - void visit(LOTData *obj) + void visit(model::Object *obj) { switch (obj->type()) { - case LOTData::Type::Layer: { - visitLayer(static_cast(obj)); + case model::Object::Type::Layer: { + visitLayer(static_cast(obj)); break; } - case LOTData::Type::Repeater: { - visitChildren(static_cast(obj)->content()); + case model::Object::Type::Repeater: { + visitChildren(static_cast(obj)->content()); break; } - case LOTData::Type::ShapeGroup: { - visitChildren(static_cast(obj)); + case model::Object::Type::Group: { + visitChildren(static_cast(obj)); break; } default: break; } } - }; -void LOTCompositionData::processRepeaterObjects() +void model::Composition::processRepeaterObjects() { LottieRepeaterProcesser visitor; visitor.visit(mRootLayer); } -void LOTCompositionData::updateStats() +void model::Composition::updateStats() { LottieUpdateStatVisitor visitor(&mStats); visitor.visit(mRootLayer); } -VMatrix LOTRepeaterTransform::matrix(int frameNo, float multiplier) const +VMatrix model::Repeater::Transform::matrix(int frameNo, float multiplier) const { VPointF scale = mScale.value(frameNo) / 100.f; scale.setX(std::pow(scale.x(), multiplier)); @@ -167,7 +169,7 @@ VMatrix LOTRepeaterTransform::matrix(int frameNo, float multiplier) const return m; } -VMatrix TransformData::matrix(int frameNo, bool autoOrient) const +VMatrix model::Transform::Data::matrix(int frameNo, bool autoOrient) const { VMatrix m; VPointF position; @@ -195,7 +197,7 @@ VMatrix TransformData::matrix(int frameNo, bool autoOrient) const return m; } -void LOTDashProperty::getDashInfo(int frameNo, std::vector& result) const +void model::Dash::getDashInfo(int frameNo, std::vector &result) const { result.clear(); @@ -203,8 +205,7 @@ void LOTDashProperty::getDashInfo(int frameNo, std::vector& result) const if (result.capacity() < mData.size()) result.reserve(mData.size() + 1); - for (const auto &elm : mData) - result.push_back(elm.value(frameNo)); + 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 @@ -212,10 +213,10 @@ void LOTDashProperty::getDashInfo(int frameNo, std::vector& result) const // 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. + // copy offset value to end. result.push_back(result.back()); // copy dash value to gap. - result[size-1] = result[size-2]; + result[size - 1] = result[size - 2]; } } @@ -239,22 +240,22 @@ void LOTDashProperty::getDashInfo(int frameNo, std::vector& result) const * ... * ] */ -void LOTGradient::populate(VGradientStops &stops, int frameNo) +void model::Gradient::populate(VGradientStops &stops, int frameNo) { - LottieGradient gradData = mGradient.value(frameNo); - auto size = gradData.mGradient.size(); - float * ptr = gradData.mGradient.data(); - int colorPoints = mColorPoints; + model::Gradient::Data gradData = mGradient.value(frameNo); + auto size = gradData.mGradient.size(); + float * ptr = gradData.mGradient.data(); + int colorPoints = mColorPoints; if (colorPoints == -1) { // for legacy bodymovin (ref: lottie-android) colorPoints = int(size / 4); } - auto opacityArraySize = size - colorPoints * 4; + auto opacityArraySize = size - colorPoints * 4; float *opacityPtr = ptr + (colorPoints * 4); stops.clear(); size_t j = 0; for (int i = 0; i < colorPoints; i++) { - float colorStop = ptr[0]; - LottieColor color = LottieColor(ptr[1], ptr[2], ptr[3]); + float colorStop = ptr[0]; + model::Color color = model::Color(ptr[1], ptr[2], ptr[3]); if (opacityArraySize) { if (j == opacityArraySize) { // already reached the end @@ -304,7 +305,7 @@ void LOTGradient::populate(VGradientStops &stops, int frameNo) } } -void LOTGradient::update(std::unique_ptr &grad, int frameNo) +void model::Gradient::update(std::unique_ptr &grad, int frameNo) { bool init = false; if (!grad) { @@ -344,8 +345,8 @@ void LOTGradient::update(std::unique_ptr &grad, int frameNo) */ float progress = mHighlightLength.value(frameNo) / 100.0f; if (vCompare(progress, 1.0f)) progress = 0.99f; - float startAngle = VLine(start, end).angle(); - float highlightAngle = mHighlightAngle.value(frameNo); + float startAngle = VLine(start, end).angle(); + float highlightAngle = mHighlightAngle.value(frameNo); static constexpr float K_PI = 3.1415926f; float angle = (startAngle + highlightAngle) * (K_PI / 180.0f); grad->radial.fx = @@ -357,18 +358,18 @@ void LOTGradient::update(std::unique_ptr &grad, int frameNo) } } -void LOTAsset::loadImageData(std::string data) +void model::Asset::loadImageData(std::string data) { if (!data.empty()) mBitmap = VImageLoader::instance().load(data.c_str(), data.length()); } -void LOTAsset::loadImagePath(std::string path) +void model::Asset::loadImagePath(std::string path) { if (!path.empty()) mBitmap = VImageLoader::instance().load(path.c_str()); } -std::vector LOTCompositionData::layerInfoList() const +std::vector model::Composition::layerInfoList() const { if (!mRootLayer || mRootLayer->mChildren.empty()) return {}; @@ -377,7 +378,7 @@ std::vector LOTCompositionData::layerInfoList() const result.reserve(mRootLayer->mChildren.size()); for (auto it : mRootLayer->mChildren) { - auto layer = static_cast(it); + auto layer = static_cast(it); result.emplace_back(layer->name(), layer->mInFrame, layer->mOutFrame); } diff --git a/src/lottie/lottiemodel.h b/src/lottie/lottiemodel.h index 55d94a1..7342344 100644 --- a/src/lottie/lottiemodel.h +++ b/src/lottie/lottiemodel.h @@ -13,115 +13,98 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LOTModel_H #define LOTModel_H -#include -#include -#include -#include +#include #include #include -#include"vpoint.h" -#include"vrect.h" -#include"vinterpolator.h" -#include"vmatrix.h" -#include"vbezier.h" -#include"vbrush.h" -#include"vpath.h" -#include"varenaalloc.h" +#include +#include +#include +#include +#include "varenaalloc.h" +#include "vbezier.h" +#include "vbrush.h" +#include "vinterpolator.h" +#include "vmatrix.h" +#include "vpath.h" +#include "vpoint.h" +#include "vrect.h" V_USE_NAMESPACE -class LOTCompositionData; -class LOTLayerData; -class LOTTransformData; -class LOTShapeGroupData; -class LOTShapeData; -class LOTRectData; -class LOTEllipseData; -class LOTTrimData; -class LOTRepeaterData; -class LOTFillData; -class LOTStrokeData; -class LOTGroupData; -class LOTGFillData; -class LOTGStrokeData; -class LottieShapeData; -class LOTPolystarData; -class LOTMaskData; - -struct LOTModelStat -{ - uint16_t precompLayerCount{0}; - uint16_t solidLayerCount{0}; - uint16_t shapeLayerCount{0}; - uint16_t imageLayerCount{0}; - uint16_t nullLayerCount{0}; +namespace rlottie { -}; +namespace internal { -enum class MatteType: uchar -{ - None = 0, - Alpha = 1, - AlphaInv, - Luma, - LumaInv -}; +using Marker = std::tuple; -enum class LayerType: uchar +using LayerInfo = Marker; + +template +inline T lerp(const T &start, const T &end, float t) { - Precomp = 0, - Solid = 1, - Image = 2, - Null = 3, - Shape = 4, - Text = 5 + return start + t * (end - start); +} + +namespace model { + +enum class MatteType : uchar { None = 0, Alpha = 1, AlphaInv, Luma, LumaInv }; + +enum class BlendMode : uchar { + Normal = 0, + Multiply = 1, + Screen = 2, + OverLay = 3 }; -class LottieColor -{ +class Color { public: - LottieColor() = default; - LottieColor(float red, float green , float blue):r(red), g(green),b(blue){} - VColor toColor(float a=1){ return VColor(uchar(255 * r), - uchar(255 * g), - uchar(255 * b), - uchar(255 * a));} - friend inline LottieColor operator+(const LottieColor &c1, const LottieColor &c2); - friend inline LottieColor operator-(const LottieColor &c1, const LottieColor &c2); + Color() = default; + Color(float red, float green, float blue) : r(red), g(green), b(blue) {} + VColor toColor(float a = 1) + { + return VColor(uchar(255 * r), uchar(255 * g), uchar(255 * b), + uchar(255 * a)); + } + friend inline Color operator+(const Color &c1, const Color &c2); + friend inline Color operator-(const Color &c1, const Color &c2); + public: float r{1}; float g{1}; float b{1}; }; -inline LottieColor operator-(const LottieColor &c1, const LottieColor &c2) +inline Color operator-(const Color &c1, const Color &c2) { - return LottieColor(c1.r - c2.r, c1.g - c2.g, c1.b - c2.b); + return Color(c1.r - c2.r, c1.g - c2.g, c1.b - c2.b); } -inline LottieColor operator+(const LottieColor &c1, const LottieColor &c2) +inline Color operator+(const Color &c1, const Color &c2) { - return LottieColor(c1.r + c2.r, c1.g + c2.g, c1.b + c2.b); + return Color(c1.r + c2.r, c1.g + c2.g, c1.b + c2.b); } -inline const LottieColor operator*(const LottieColor &c, float m) -{ return LottieColor(c.r*m, c.g*m, c.b*m); } - -inline const LottieColor operator*(float m, const LottieColor &c) -{ return LottieColor(c.r*m, c.g*m, c.b*m); } +inline const Color operator*(const Color &c, float m) +{ + return Color(c.r * m, c.g * m, c.b * m); +} -class LottieShapeData +inline const Color operator*(float m, const Color &c) { -public: - void reserve(size_t size) { - mPoints.reserve(mPoints.size() + size); - } - static void lerp(const LottieShapeData& start, const LottieShapeData& end, float t, VPath& result) + return Color(c.r * m, c.g * m, c.b * m); +} + +struct PathData { + std::vector mPoints; + bool mClosed = false; /* "c" */ + void reserve(size_t size) { mPoints.reserve(mPoints.size() + size); } + static void lerp(const PathData &start, const PathData &end, float t, + VPath &result) { result.reset(); auto size = std::min(start.mPoints.size(), end.mPoints.size()); @@ -129,16 +112,21 @@ public: * ptSize = size + 1(size + close) * elmSize = size/3 cubic + 1 move + 1 close */ - result.reserve(size + 1 , size/3 + 2); - result.moveTo(start.mPoints[0] + t * (end.mPoints[0] - start.mPoints[0])); - for (size_t i = 1 ; i < size; i+=3) { - result.cubicTo(start.mPoints[i] + t * (end.mPoints[i] - start.mPoints[i]), - start.mPoints[i+1] + t * (end.mPoints[i+1] - start.mPoints[i+1]), - start.mPoints[i+2] + t * (end.mPoints[i+2] - start.mPoints[i+2])); + result.reserve(size + 1, size / 3 + 2); + result.moveTo(start.mPoints[0] + + t * (end.mPoints[0] - start.mPoints[0])); + for (size_t i = 1; i < size; i += 3) { + result.cubicTo( + start.mPoints[i] + t * (end.mPoints[i] - start.mPoints[i]), + start.mPoints[i + 1] + + t * (end.mPoints[i + 1] - start.mPoints[i + 1]), + start.mPoints[i + 2] + + t * (end.mPoints[i + 2] - start.mPoints[i + 2])); } if (start.mClosed) result.close(); } - void toPath(VPath& path) const { + void toPath(VPath &path) const + { path.reset(); if (mPoints.empty()) return; @@ -149,161 +137,150 @@ public: * ptSize = size + 1(size + close) * elmSize = size/3 cubic + 1 move + 1 close */ - path.reserve(size + 1 , size/3 + 2); + path.reserve(size + 1, size / 3 + 2); path.moveTo(points[0]); - for (size_t i = 1 ; i < size; i+=3) { - path.cubicTo(points[i], points[i+1], points[i+2]); + for (size_t i = 1; i < size; i += 3) { + path.cubicTo(points[i], points[i + 1], points[i + 2]); } - if (mClosed) - path.close(); + if (mClosed) path.close(); } -public: - std::vector mPoints; - bool mClosed = false; /* "c" */ }; - - -template -inline T lerp(const T& start, const T& end, float t) -{ - return start + t * (end - start); -} - template -struct LOTKeyFrameValue -{ - T mStartValue; - T mEndValue; - T value(float t) const { - return lerp(mStartValue, mEndValue, t); - } - float angle(float ) const { return 0;} +struct Value { + T mStartValue; + T mEndValue; + T at(float t) const { return lerp(mStartValue, mEndValue, t); } + float angle(float) const { return 0; } }; template <> -struct LOTKeyFrameValue -{ +struct Value { VPointF mStartValue; VPointF mEndValue; VPointF mInTangent; VPointF mOutTangent; bool mPathKeyFrame = false; - VPointF value(float t) const { + VPointF at(float t) const + { if (mPathKeyFrame) { /* * position along the path calcualated * using bezier at progress length (t * bezlen) */ - VBezier b = VBezier::fromPoints(mStartValue, mStartValue + mOutTangent, - mEndValue + mInTangent, mEndValue); + VBezier b = + VBezier::fromPoints(mStartValue, mStartValue + mOutTangent, + mEndValue + mInTangent, mEndValue); return b.pointAt(b.tAtLength(t * b.length())); - } return lerp(mStartValue, mEndValue, t); } - float angle(float t) const { + float angle(float t) const + { if (mPathKeyFrame) { - VBezier b = VBezier::fromPoints(mStartValue, mStartValue + mOutTangent, - mEndValue + mInTangent, mEndValue); + VBezier b = + VBezier::fromPoints(mStartValue, mStartValue + mOutTangent, + mEndValue + mInTangent, mEndValue); return b.angleAt(b.tAtLength(t * b.length())); } return 0; } }; - -template -class LOTKeyFrame -{ +template +class KeyFrame { public: - float progress(int frameNo) const { - return mInterpolator ? mInterpolator->value((frameNo - mStartFrame) / (mEndFrame - mStartFrame)) : 0; - } - T value(int frameNo) const { - return mValue.value(progress(frameNo)); - } - float angle(int frameNo) const { - return mValue.angle(progress(frameNo)); + 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)); } public: - float mStartFrame{0}; - float mEndFrame{0}; - VInterpolator *mInterpolator{nullptr}; - LOTKeyFrameValue mValue; + float mStartFrame{0}; + float mEndFrame{0}; + VInterpolator *mInterpolator{nullptr}; + Value mValue; }; -template -class LOTAnimInfo -{ +template +class DynamicProperty { public: - T value(int frameNo) const { + T value(int frameNo) const + { if (mKeyFrames.front().mStartFrame >= frameNo) return mKeyFrames.front().mValue.mStartValue; - if(mKeyFrames.back().mEndFrame <= frameNo) + if (mKeyFrames.back().mEndFrame <= frameNo) return mKeyFrames.back().mValue.mEndValue; - for(const auto &keyFrame : mKeyFrames) { + for (const auto &keyFrame : mKeyFrames) { if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame) return keyFrame.value(frameNo); } return T(); } - float angle(int frameNo) const { + float angle(int frameNo) const + { if ((mKeyFrames.front().mStartFrame >= frameNo) || - (mKeyFrames.back().mEndFrame <= frameNo) ) + (mKeyFrames.back().mEndFrame <= frameNo)) return 0; - for(const auto &keyFrame : mKeyFrames) { + for (const auto &keyFrame : mKeyFrames) { if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame) return keyFrame.angle(frameNo); } return 0; } - bool changed(int prevFrame, int curFrame) const { + bool changed(int prevFrame, int curFrame) const + { auto first = mKeyFrames.front().mStartFrame; auto last = mKeyFrames.back().mEndFrame; - return !((first > prevFrame && first > curFrame) || - (last < prevFrame && last < curFrame)); + return !((first > prevFrame && first > curFrame) || + (last < prevFrame && last < curFrame)); } public: - std::vector> mKeyFrames; + std::vector> mKeyFrames; }; -template -class LOTAnimatable -{ +template +class Property { public: - LOTAnimatable() { construct(impl.mValue, {}); } - explicit LOTAnimatable(T value) { construct(impl.mValue, std::move(value)); } + Property() { construct(impl.mValue, {}); } + explicit Property(T value) { construct(impl.mValue, std::move(value)); } - const LOTAnimInfo& animation() const {return *(impl.mAnimInfo.get());} - const T& value() const {return impl.mValue;} + const DynamicProperty &animation() const + { + return *(impl.mAnimInfo.get()); + } + const T &value() const { return impl.mValue; } - LOTAnimInfo& animation() + DynamicProperty &animation() { if (mStatic) { destroy(); - construct(impl.mAnimInfo, std::make_unique>()); + construct(impl.mAnimInfo, std::make_unique>()); mStatic = false; } return *(impl.mAnimInfo.get()); } - T& value() + T &value() { assert(mStatic); return impl.mValue; } - LOTAnimatable(LOTAnimatable &&other) noexcept { + Property(Property &&other) noexcept + { if (!other.mStatic) { construct(impl.mAnimInfo, std::move(other.impl.mAnimInfo)); mStatic = false; @@ -313,21 +290,23 @@ public: } } // delete special member functions - LOTAnimatable(const LOTAnimatable &) = delete; - LOTAnimatable& operator=(const LOTAnimatable&) = delete; - LOTAnimatable& operator=(LOTAnimatable&&) = delete; + Property(const Property &) = delete; + Property &operator=(const Property &) = delete; + Property &operator=(Property &&) = delete; - ~LOTAnimatable() {destroy();} + ~Property() { destroy(); } - bool isStatic() const {return mStatic;} + bool isStatic() const { return mStatic; } - T value(int frameNo) const { + T value(int frameNo) const + { return isStatic() ? value() : animation().value(frameNo); } - // special function only for type T=LottieShapeData - template - auto value(int frameNo, VPath& path) const-> typename std::enable_if_t::value, void> + // special function only for type T=PathData + template + auto value(int frameNo, VPath &path) const -> + typename std::enable_if_t::value, void> { if (isStatic()) { value().toPath(path); @@ -335,71 +314,97 @@ public: const auto &vec = animation().mKeyFrames; if (vec.front().mStartFrame >= frameNo) return vec.front().mValue.mStartValue.toPath(path); - if(vec.back().mEndFrame <= frameNo) + if (vec.back().mEndFrame <= frameNo) return vec.back().mValue.mEndValue.toPath(path); - for(const auto &keyFrame : vec) { - if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame) { - LottieShapeData::lerp(keyFrame.mValue.mStartValue, - keyFrame.mValue.mEndValue, - keyFrame.progress(frameNo), - 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); } } } } - float angle(int frameNo) const { + float angle(int frameNo) const + { return isStatic() ? 0 : animation().angle(frameNo); } - bool changed(int prevFrame, int curFrame) const { + bool changed(int prevFrame, int curFrame) const + { return isStatic() ? false : animation().changed(prevFrame, curFrame); } + private: template - void construct(Tp& member, Tp&& val) + void construct(Tp &member, Tp &&val) { new (&member) Tp(std::move(val)); } - void destroy() { + void destroy() + { if (mStatic) { impl.mValue.~T(); } else { using std::unique_ptr; - impl.mAnimInfo.~unique_ptr>(); + impl.mAnimInfo.~unique_ptr>(); } } union details { - std::unique_ptr> mAnimInfo; - T mValue; + std::unique_ptr> mAnimInfo; + T mValue; details(){}; - details(const details&) = delete; - details(details&&) = delete; - details& operator=(details&&) = delete; - details& operator=(const details&) = delete; + details(const details &) = delete; + details(details &&) = delete; + details &operator=(details &&) = delete; + details &operator=(const details &) = delete; ~details(){}; - }impl; - bool mStatic{true}; + } impl; + bool mStatic{true}; }; -enum class LottieBlendMode: uchar -{ - Normal = 0, - Multiply = 1, - Screen = 2, - OverLay = 3 +class Path; +struct PathData; +struct Dash { + std::vector> 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 &result) const; }; -class LOTDataVisitor; -class LOTData -{ +class Mask { +public: + enum class Mode { None, Add, Substarct, Intersect, Difference }; + float opacity(int frameNo) const + { + return mOpacity.value(frameNo) / 100.0f; + } + bool isStatic() const { return mIsStatic; } + +public: + Property mShape; + Property mOpacity{100}; + bool mInv{false}; + bool mIsStatic{true}; + Mask::Mode mMode; +}; + +class Object { public: - enum class Type :unsigned char { + enum class Type : unsigned char { Composition = 1, Layer, - ShapeGroup, + Group, Transform, Fill, Stroke, @@ -407,54 +412,57 @@ public: GStroke, Rect, Ellipse, - Shape, + Path, Polystar, Trim, Repeater }; - explicit LOTData(LOTData::Type type):mPtr(nullptr) + explicit Object(Object::Type type) : mPtr(nullptr) { - mData._type = type; - mData._static = true; - mData._shortString = true; - mData._hidden = false; + mData._type = type; + mData._static = true; + mData._shortString = true; + mData._hidden = false; } - ~LOTData() { if (!shortString() && mPtr) free(mPtr); } - LOTData(const LOTData&) = delete; - LOTData& operator =(const LOTData&) = delete; - - void setStatic(bool value) { mData._static = value;} - bool isStatic() const {return mData._static;} - bool hidden() const {return mData._hidden;} - void setHidden(bool value) {mData._hidden = value;} - void setType(LOTData::Type type) {mData._type = type;} - LOTData::Type type() const { return mData._type;} - void setName(const char *name) + ~Object() + { + if (!shortString() && mPtr) free(mPtr); + } + Object(const Object &) = delete; + Object &operator=(const Object &) = delete; + + void setStatic(bool value) { mData._static = value; } + bool isStatic() const { return mData._static; } + bool hidden() const { return mData._hidden; } + void setHidden(bool value) { mData._hidden = value; } + void setType(Object::Type type) { mData._type = type; } + Object::Type type() const { return mData._type; } + void setName(const char *name) { if (name) { auto len = strlen(name); if (len < maxShortStringLength) { setShortString(true); - strncpy ( mData._buffer, name, len+1); + strncpy(mData._buffer, name, len + 1); } else { setShortString(false); mPtr = strdup(name); } - } } - const char* name() const {return shortString() ? mData._buffer : mPtr;} + const char *name() const { return shortString() ? mData._buffer : mPtr; } + private: static constexpr unsigned char maxShortStringLength = 14; - void setShortString(bool value) {mData._shortString = value;} - bool shortString() const {return mData._shortString;} - struct Data{ - char _buffer[maxShortStringLength]; - LOTData::Type _type; - bool _static : 1; - bool _hidden : 1; - bool _shortString : 1; + void setShortString(bool value) { mData._shortString = value; } + bool shortString() const { return mData._shortString; } + struct Data { + char _buffer[maxShortStringLength]; + Object::Type _type; + bool _static : 1; + bool _hidden : 1; + bool _shortString : 1; }; union { Data mData; @@ -462,80 +470,113 @@ private: }; }; -class LOTGroupData: public LOTData -{ -public: - explicit LOTGroupData(LOTData::Type type):LOTData(type){} -public: - std::vector mChildren; - LOTTransformData *mTransform{nullptr}; -}; - -class LOTShapeGroupData : public LOTGroupData -{ -public: - LOTShapeGroupData():LOTGroupData(LOTData::Type::ShapeGroup){} -}; - -class LOTLayerData; -struct LOTAsset -{ - enum class Type : unsigned char{ - Precomp, - Image, - Char - }; - bool isStatic() const {return mStatic;} - void setStatic(bool value) {mStatic = value;} - VBitmap bitmap() const {return mBitmap;} - void loadImageData(std::string data); - void loadImagePath(std::string Path); - Type mAssetType{Type::Precomp}; - bool mStatic{true}; - std::string mRefId; // ref id - std::vector mLayers; +struct Asset { + enum class Type : unsigned char { Precomp, Image, Char }; + bool isStatic() const { return mStatic; } + void setStatic(bool value) { mStatic = value; } + VBitmap bitmap() const { return mBitmap; } + void loadImageData(std::string data); + void loadImagePath(std::string Path); + Type mAssetType{Type::Precomp}; + bool mStatic{true}; + std::string mRefId; // ref id + std::vector mLayers; // image asset data - int mWidth{0}; - int mHeight{0}; - VBitmap mBitmap; + int mWidth{0}; + int mHeight{0}; + VBitmap mBitmap; }; -struct TransformDataExtra -{ - LOTAnimatable m3DRx{0}; - LOTAnimatable m3DRy{0}; - LOTAnimatable m3DRz{0}; - LOTAnimatable mSeparateX{0}; - LOTAnimatable mSeparateY{0}; - bool mSeparate{false}; - bool m3DData{false}; -}; +class Layer; -struct TransformData -{ - VMatrix matrix(int frameNo, bool autoOrient = false) const; - float opacity(int frameNo) const { return mOpacity.value(frameNo)/100.0f; } - void createExtraData() +class Composition : public Object { +public: + Composition() : Object(Object::Type::Composition) {} + std::vector layerInfoList() const; + const std::vector &markers() const { return mMarkers; } + double duration() const + { + return frameDuration() / frameRate(); // in second + } + size_t frameAtPos(double pos) const { - if (!mExtra) mExtra = std::make_unique(); + if (pos < 0) pos = 0; + if (pos > 1) pos = 1; + return size_t(round(pos * frameDuration())); } - LOTAnimatable mRotation{0}; /* "r" */ - LOTAnimatable mScale{{100, 100}}; /* "s" */ - LOTAnimatable mPosition; /* "p" */ - LOTAnimatable mAnchor; /* "a" */ - LOTAnimatable mOpacity{100}; /* "o" */ - std::unique_ptr mExtra; + long frameAtTime(double timeInSec) const + { + return long(frameAtPos(timeInSec / duration())); + } + size_t totalFrame() const { return mEndFrame - mStartFrame; } + long frameDuration() const { return mEndFrame - mStartFrame - 1; } + float frameRate() const { return mFrameRate; } + size_t startFrame() const { return mStartFrame; } + size_t endFrame() const { return mEndFrame; } + VSize size() const { return mSize; } + void processRepeaterObjects(); + void updateStats(); + +public: + struct Stats { + uint16_t precompLayerCount{0}; + uint16_t solidLayerCount{0}; + uint16_t shapeLayerCount{0}; + uint16_t imageLayerCount{0}; + uint16_t nullLayerCount{0}; + }; + +public: + std::string mVersion; + VSize mSize; + long mStartFrame{0}; + long mEndFrame{0}; + float mFrameRate{60}; + BlendMode mBlendMode{BlendMode::Normal}; + Layer * mRootLayer{nullptr}; + std::unordered_map mAssets; + + std::vector mMarkers; + VArenaAlloc mArenaAlloc{2048}; + Stats mStats; }; -class LOTTransformData : public LOTData -{ +class Transform : public Object { public: - LOTTransformData():LOTData(LOTData::Type::Transform){} - void set(TransformData* data, bool staticFlag) + struct Data { + struct Extra { + Property m3DRx{0}; + Property m3DRy{0}; + Property m3DRz{0}; + Property mSeparateX{0}; + Property mSeparateY{0}; + bool mSeparate{false}; + bool m3DData{false}; + }; + VMatrix matrix(int frameNo, bool autoOrient = false) const; + float opacity(int frameNo) const + { + return mOpacity.value(frameNo) / 100.0f; + } + void createExtraData() + { + 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; + }; + + Transform() : Object(Object::Type::Transform) {} + void set(Transform::Data *data, bool staticFlag) { setStatic(staticFlag); if (isStatic()) { - new (&impl.mStaticData) static_data(data->matrix(0), data->opacity(0)); + new (&impl.mStaticData) + StaticData(data->matrix(0), data->opacity(0)); } else { impl.mData = data; } @@ -550,153 +591,131 @@ public: if (isStatic()) return impl.mStaticData.mOpacity; return impl.mData->opacity(frameNo); } - LOTTransformData(const LOTTransformData&) = delete; - LOTTransformData(LOTTransformData&&) = delete; - LOTTransformData& operator=(LOTTransformData&) = delete; - LOTTransformData& operator=(LOTTransformData&&) = delete; - ~LOTTransformData() {destroy();} + Transform(const Transform &) = delete; + Transform(Transform &&) = delete; + Transform &operator=(Transform &) = delete; + Transform &operator=(Transform &&) = delete; + ~Transform() { destroy(); } private: - void destroy() { + void destroy() + { if (isStatic()) { - impl.mStaticData.~static_data(); + impl.mStaticData.~StaticData(); } } - struct static_data { - static_data(VMatrix &&m, float opacity): - mOpacity(opacity), mMatrix(std::move(m)){} - float mOpacity; - VMatrix mMatrix; + struct StaticData { + StaticData(VMatrix &&m, float opacity) + : mOpacity(opacity), mMatrix(std::move(m)) + { + } + float mOpacity; + VMatrix mMatrix; }; union details { - TransformData *mData{nullptr}; - static_data mStaticData; + Data * mData{nullptr}; + StaticData mStaticData; details(){}; - details(const details&) = delete; - details(details&&) = delete; - details& operator=(details&&) = delete; - details& operator=(const details&) = delete; + details(const details &) = delete; + details(details &&) = delete; + details &operator=(details &&) = delete; + details &operator=(const details &) = delete; ~details(){}; - }impl; + } impl; }; -struct ExtraLayerData -{ - LottieColor mSolidColor; - std::string mPreCompRefId; - LOTAnimatable mTimeRemap; /* "tm" */ - LOTCompositionData *mCompRef{nullptr}; - LOTAsset *mAsset{nullptr}; - std::vector mMasks; +class Group : public Object { +public: + Group() : Object(Object::Type::Group) {} + explicit Group(Object::Type type) : Object(type) {} + +public: + std::vector mChildren; + Transform * mTransform{nullptr}; }; -class LOTLayerData : public LOTGroupData -{ +class Layer : public Group { public: - LOTLayerData():LOTGroupData(LOTData::Type::Layer){} - bool hasPathOperator() const noexcept {return mHasPathOperator;} - bool hasGradient() const noexcept {return mHasGradient;} - bool hasMask() const noexcept {return mHasMask;} - bool hasRepeater() const noexcept {return mHasRepeater;} - int id() const noexcept{ return mId;} - int parentId() const noexcept{ return mParentId;} - bool hasParent() const noexcept {return mParentId != -1;} - int inFrame() const noexcept{return mInFrame;} - int outFrame() const noexcept{return mOutFrame;} - int startFrame() const noexcept{return mStartFrame;} - LottieColor solidColor() const noexcept{return mExtra->mSolidColor;} - bool autoOrient() const noexcept{return mAutoOrient;} - int timeRemap(int frameNo) const; - VSize layerSize() const {return mLayerSize;} - bool precompLayer() const {return mLayerType == LayerType::Precomp;} + enum class Type : uchar { + Precomp = 0, + Solid = 1, + Image = 2, + Null = 3, + Shape = 4, + Text = 5 + }; + Layer() : Group(Object::Type::Layer) {} + bool hasPathOperator() const noexcept { return mHasPathOperator; } + bool hasGradient() const noexcept { return mHasGradient; } + bool hasMask() const noexcept { return mHasMask; } + bool hasRepeater() const noexcept { return mHasRepeater; } + int id() const noexcept { return mId; } + int parentId() const noexcept { return mParentId; } + bool hasParent() const noexcept { return mParentId != -1; } + int inFrame() const noexcept { return mInFrame; } + int outFrame() const noexcept { return mOutFrame; } + int startFrame() const noexcept { return mStartFrame; } + Color solidColor() const noexcept { return mExtra->mSolidColor; } + bool autoOrient() const noexcept { return mAutoOrient; } + int timeRemap(int frameNo) const; + VSize layerSize() const { return mLayerSize; } + bool precompLayer() const { return mLayerType == Type::Precomp; } VMatrix matrix(int frameNo) const { - return mTransform ? mTransform->matrix(frameNo, autoOrient()) : VMatrix{}; + return mTransform ? mTransform->matrix(frameNo, autoOrient()) + : VMatrix{}; } float opacity(int frameNo) const { return mTransform ? mTransform->opacity(frameNo) : 1.0f; } - LOTAsset* asset() const + Asset *asset() const { return (mExtra && mExtra->mAsset) ? mExtra->mAsset : nullptr; } -public: - ExtraLayerData* extra() + struct Extra { + Color mSolidColor; + std::string mPreCompRefId; + Property mTimeRemap; /* "tm" */ + Composition * mCompRef{nullptr}; + Asset * mAsset{nullptr}; + std::vector mMasks; + }; + + Layer::Extra *extra() { - if (!mExtra) mExtra = std::make_unique(); + if (!mExtra) mExtra = std::make_unique(); return mExtra.get(); } - MatteType mMatteType{MatteType::None}; - LayerType mLayerType{LayerType::Null}; - LottieBlendMode mBlendMode{LottieBlendMode::Normal}; - bool mHasPathOperator{false}; - bool mHasMask{false}; - bool mHasRepeater{false}; - bool mHasGradient{false}; - bool mAutoOrient{false}; - VSize mLayerSize; - int mParentId{-1}; // Lottie the id of the parent in the composition - int mId{-1}; // Lottie the group id used for parenting. - float mTimeStreatch{1.0f}; - int mInFrame{0}; - int mOutFrame{0}; - int mStartFrame{0}; - std::unique_ptr mExtra{nullptr}; -}; - -using Marker = std::tuple; -using LayerInfo = Marker; -class LOTCompositionData : public LOTData -{ public: - LOTCompositionData():LOTData(LOTData::Type::Composition){} - std::vector layerInfoList() const; - const std::vector &markers() const { return mMarkers;} - double duration() const { - return frameDuration() / frameRate(); // in second - } - size_t frameAtPos(double pos) const { - if (pos < 0) pos = 0; - if (pos > 1) pos = 1; - return size_t(round(pos * frameDuration())); - } - long frameAtTime(double timeInSec) const { - return long(frameAtPos(timeInSec / duration())); - } - size_t totalFrame() const {return mEndFrame - mStartFrame;} - long frameDuration() const {return mEndFrame - mStartFrame -1;} - float frameRate() const {return mFrameRate;} - long startFrame() const {return mStartFrame;} - long endFrame() const {return mEndFrame;} - VSize size() const {return mSize;} - void processRepeaterObjects(); - void updateStats(); -public: - std::string mVersion; - VSize mSize; - long mStartFrame{0}; - long mEndFrame{0}; - float mFrameRate{60}; - LottieBlendMode mBlendMode{LottieBlendMode::Normal}; - LOTLayerData *mRootLayer{nullptr}; - std::unordered_map mAssets; - - std::vector mMarkers; - VArenaAlloc mArenaAlloc{2048}; - LOTModelStat mStats; + MatteType mMatteType{MatteType::None}; + Type mLayerType{Layer::Type::Null}; + BlendMode mBlendMode{BlendMode::Normal}; + bool mHasPathOperator{false}; + bool mHasMask{false}; + bool mHasRepeater{false}; + bool mHasGradient{false}; + bool mAutoOrient{false}; + VSize mLayerSize; + int mParentId{-1}; // Lottie the id of the parent in the composition + int mId{-1}; // Lottie the group id used for parenting. + float mTimeStreatch{1.0f}; + int mInFrame{0}; + int mOutFrame{0}; + int mStartFrame{0}; + std::unique_ptr mExtra{nullptr}; }; /** * TimeRemap has the value in time domain(in sec) - * To get the proper mapping first we get the mapped time at the current frame Number - * then we need to convert mapped time to frame number using the composition time line - * Ex: at frame 10 the mappend time is 0.5(500 ms) which will be convert to frame number - * 30 if the frame rate is 60. or will result to frame number 15 if the frame rate is 30. + * To get the proper mapping first we get the mapped time at the current frame + * Number then we need to convert mapped time to frame number using the + * composition time line Ex: at frame 10 the mappend time is 0.5(500 ms) which + * will be convert to frame number 30 if the frame rate is 60. or will result to + * frame number 15 if the frame rate is 30. */ -inline int LOTLayerData::timeRemap(int frameNo) const +inline int Layer::timeRemap(int frameNo) const { /* * only consider startFrame() when there is no timeRemap. @@ -706,277 +725,247 @@ inline int LOTLayerData::timeRemap(int frameNo) const if (!mExtra || mExtra->mTimeRemap.isStatic()) frameNo = frameNo - startFrame(); else - frameNo = mExtra->mCompRef->frameAtTime(mExtra->mTimeRemap.value(frameNo)); + frameNo = + mExtra->mCompRef->frameAtTime(mExtra->mTimeRemap.value(frameNo)); /* Apply time streatch if it has any. - * Time streatch is just a factor by which the animation will speedup or slow - * down with respect to the overal animation. - * Time streach factor is already applied to the layers inFrame and outFrame. - * @TODO need to find out if timestreatch also affects the in and out frame of the - * child layers or not. */ + * Time streatch is just a factor by which the animation will speedup or + * slow down with respect to the overal animation. Time streach factor is + * already applied to the layers inFrame and outFrame. + * @TODO need to find out if timestreatch also affects the in and out frame + * of the child layers or not. */ return int(frameNo / mTimeStreatch); } -class LOTFillData : public LOTData -{ +class Stroke : public Object { public: - LOTFillData():LOTData(LOTData::Type::Fill){} - LottieColor color(int frameNo) const {return mColor.value(frameNo);} - float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0f;} - FillRule fillRule() const {return mFillRule;} -public: - FillRule mFillRule{FillRule::Winding}; /* "r" */ - bool mEnabled{true}; /* "fillEnabled" */ - LOTAnimatable mColor; /* "c" */ - LOTAnimatable mOpacity{100}; /* "o" */ -}; - -struct LOTDashProperty -{ - std::vector> 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; + Stroke() : Object(Object::Type::Stroke) {} + Color color(int frameNo) const { return mColor.value(frameNo); } + float opacity(int frameNo) const + { + return mOpacity.value(frameNo) / 100.0f; } - void getDashInfo(int frameNo, std::vector& result) const; -}; - -class LOTStrokeData : public LOTData -{ -public: - LOTStrokeData():LOTData(LOTData::Type::Stroke){} - LottieColor color(int frameNo) const {return mColor.value(frameNo);} - float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0f;} - float strokeWidth(int frameNo) const {return mWidth.value(frameNo);} - CapStyle capStyle() const {return mCapStyle;} - JoinStyle joinStyle() const {return mJoinStyle;} - float miterLimit() const{return mMiterLimit;} - bool hasDashInfo() const {return !mDash.empty();} - void getDashInfo(int frameNo, std::vector& result) const + float strokeWidth(int frameNo) const { return mWidth.value(frameNo); } + CapStyle capStyle() const { return mCapStyle; } + JoinStyle joinStyle() const { return mJoinStyle; } + float miterLimit() const { return mMiterLimit; } + bool hasDashInfo() const { return !mDash.empty(); } + void getDashInfo(int frameNo, std::vector &result) const { return mDash.getDashInfo(frameNo, result); } -public: - LOTAnimatable mColor; /* "c" */ - LOTAnimatable mOpacity{100}; /* "o" */ - LOTAnimatable mWidth{0}; /* "w" */ - CapStyle mCapStyle{CapStyle::Flat}; /* "lc" */ - JoinStyle mJoinStyle{JoinStyle::Miter}; /* "lj" */ - float mMiterLimit{0}; /* "ml" */ - LOTDashProperty mDash; - bool mEnabled{true}; /* "fillEnabled" */ -}; -class LottieGradient -{ -public: - friend inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2); - friend inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2); - friend inline LottieGradient operator*(float m, const LottieGradient &g); public: - std::vector mGradient; + Property mColor; /* "c" */ + Property mOpacity{100}; /* "o" */ + Property mWidth{0}; /* "w" */ + CapStyle mCapStyle{CapStyle::Flat}; /* "lc" */ + JoinStyle mJoinStyle{JoinStyle::Miter}; /* "lj" */ + float mMiterLimit{0}; /* "ml" */ + Dash mDash; + bool mEnabled{true}; /* "fillEnabled" */ }; -inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2) -{ - if (g1.mGradient.size() != g2.mGradient.size()) - return g1; - - LottieGradient newG; - newG.mGradient = g1.mGradient; - - auto g2It = g2.mGradient.begin(); - for(auto &i : newG.mGradient) { - i = i + *g2It; - g2It++; - } - - return newG; -} - -inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2) -{ - if (g1.mGradient.size() != g2.mGradient.size()) - return g1; - LottieGradient newG; - newG.mGradient = g1.mGradient; - - auto g2It = g2.mGradient.begin(); - for(auto &i : newG.mGradient) { - i = i - *g2It; - g2It++; - } - - return newG; -} - -inline LottieGradient operator*(float m, const LottieGradient &g) -{ - LottieGradient newG; - newG.mGradient = g.mGradient; - - for(auto &i : newG.mGradient) { - i = i * m; +class Gradient : public Object { +public: + class Data { + public: + friend inline Gradient::Data operator+(const Gradient::Data &g1, + const Gradient::Data &g2); + friend inline Gradient::Data operator-(const Gradient::Data &g1, + const Gradient::Data &g2); + friend inline Gradient::Data operator*(float m, + const Gradient::Data &g); + + public: + std::vector mGradient; + }; + explicit Gradient(Object::Type type) : Object(type) {} + inline float opacity(int frameNo) const + { + return mOpacity.value(frameNo) / 100.0f; } - return newG; -} + void update(std::unique_ptr &grad, int frameNo); +private: + void populate(VGradientStops &stops, int frameNo); +public: + int mGradientType{1}; /* "t" Linear=1 , Radial = 2*/ + Property mStartPoint; /* "s" */ + Property mEndPoint; /* "e" */ + Property mHighlightLength{0}; /* "h" */ + Property mHighlightAngle{0}; /* "a" */ + Property mOpacity{100}; /* "o" */ + Property mGradient; /* "g" */ + int mColorPoints{-1}; + bool mEnabled{true}; /* "fillEnabled" */ +}; -class LOTGradient : public LOTData -{ +class GradientStroke : public Gradient { public: - explicit LOTGradient(LOTData::Type type):LOTData(type){} - inline float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0f;} - void update(std::unique_ptr &grad, int frameNo); + GradientStroke() : Gradient(Object::Type::GStroke) {} + float width(int frameNo) const { return mWidth.value(frameNo); } + CapStyle capStyle() const { return mCapStyle; } + JoinStyle joinStyle() const { return mJoinStyle; } + float miterLimit() const { return mMiterLimit; } + bool hasDashInfo() const { return !mDash.empty(); } + void getDashInfo(int frameNo, std::vector &result) const + { + return mDash.getDashInfo(frameNo, result); + } -private: - void populate(VGradientStops &stops, int frameNo); public: - int mGradientType{1}; /* "t" Linear=1 , Radial = 2*/ - LOTAnimatable mStartPoint; /* "s" */ - LOTAnimatable mEndPoint; /* "e" */ - LOTAnimatable mHighlightLength{0}; /* "h" */ - LOTAnimatable mHighlightAngle{0}; /* "a" */ - LOTAnimatable mOpacity{100}; /* "o" */ - LOTAnimatable mGradient; /* "g" */ - int mColorPoints{-1}; - bool mEnabled{true}; /* "fillEnabled" */ + Property mWidth; /* "w" */ + CapStyle mCapStyle{CapStyle::Flat}; /* "lc" */ + JoinStyle mJoinStyle{JoinStyle::Miter}; /* "lj" */ + float mMiterLimit{0}; /* "ml" */ + Dash mDash; }; -class LOTGFillData : public LOTGradient -{ +class GradientFill : public Gradient { public: - LOTGFillData():LOTGradient(LOTData::Type::GFill){} - FillRule fillRule() const {return mFillRule;} + GradientFill() : Gradient(Object::Type::GFill) {} + FillRule fillRule() const { return mFillRule; } + public: - FillRule mFillRule{FillRule::Winding}; /* "r" */ + FillRule mFillRule{FillRule::Winding}; /* "r" */ }; -class LOTGStrokeData : public LOTGradient -{ +class Fill : public Object { public: - LOTGStrokeData():LOTGradient(LOTData::Type::GStroke){} - float width(int frameNo) const {return mWidth.value(frameNo);} - CapStyle capStyle() const {return mCapStyle;} - JoinStyle joinStyle() const {return mJoinStyle;} - float miterLimit() const{return mMiterLimit;} - bool hasDashInfo() const {return !mDash.empty();} - void getDashInfo(int frameNo, std::vector& result) const + Fill() : Object(Object::Type::Fill) {} + Color color(int frameNo) const { return mColor.value(frameNo); } + float opacity(int frameNo) const { - return mDash.getDashInfo(frameNo, result); + return mOpacity.value(frameNo) / 100.0f; } + FillRule fillRule() const { return mFillRule; } + public: - LOTAnimatable mWidth; /* "w" */ - CapStyle mCapStyle{CapStyle::Flat}; /* "lc" */ - JoinStyle mJoinStyle{JoinStyle::Miter}; /* "lj" */ - float mMiterLimit{0}; /* "ml" */ - LOTDashProperty mDash; + FillRule mFillRule{FillRule::Winding}; /* "r" */ + bool mEnabled{true}; /* "fillEnabled" */ + Property mColor; /* "c" */ + Property mOpacity{100}; /* "o" */ }; -class LOTPath : public LOTData -{ +class Shape : public Object { public: - explicit LOTPath(LOTData::Type type):LOTData(type){} - VPath::Direction direction() { - return (mDirection == 3) ? - VPath::Direction::CCW : VPath::Direction::CW; + explicit Shape(Object::Type type) : Object(type) {} + VPath::Direction direction() + { + return (mDirection == 3) ? VPath::Direction::CCW : VPath::Direction::CW; } + public: - int mDirection{1}; + int mDirection{1}; }; -class LOTShapeData : public LOTPath -{ +class Path : public Shape { public: - LOTShapeData():LOTPath(LOTData::Type::Shape){} + Path() : Shape(Object::Type::Path) {} + public: - LOTAnimatable mShape; + Property mShape; }; -class LOTMaskData -{ +class Rect : public Shape { public: - enum class Mode { - None, - Add, - Substarct, - Intersect, - Difference - }; - float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0f;} - bool isStatic() const {return mIsStatic;} + Rect() : Shape(Object::Type::Rect) {} + public: - LOTAnimatable mShape; - LOTAnimatable mOpacity{100}; - bool mInv{false}; - bool mIsStatic{true}; - LOTMaskData::Mode mMode; + Property mPos; + Property mSize; + Property mRound{0}; }; -class LOTRectData : public LOTPath -{ +class Ellipse : public Shape { public: - LOTRectData():LOTPath(LOTData::Type::Rect){} + Ellipse() : Shape(Object::Type::Ellipse) {} + public: - LOTAnimatable mPos; - LOTAnimatable mSize; - LOTAnimatable mRound{0}; + Property mPos; + Property mSize; }; -class LOTEllipseData : public LOTPath -{ +class Polystar : public Shape { public: - LOTEllipseData():LOTPath(LOTData::Type::Ellipse){} + enum class PolyType { Star = 1, Polygon = 2 }; + Polystar() : Shape(Object::Type::Polystar) {} + public: - LOTAnimatable mPos; - LOTAnimatable mSize; + Polystar::PolyType mPolyType{PolyType::Polygon}; + Property mPos; + Property mPointCount{0}; + Property mInnerRadius{0}; + Property mOuterRadius{0}; + Property mInnerRoundness{0}; + Property mOuterRoundness{0}; + Property mRotation{0}; }; -class LOTPolystarData : public LOTPath -{ +class Repeater : public Object { public: - enum class PolyType { - Star = 1, - Polygon = 2 + struct Transform { + VMatrix matrix(int frameNo, float multiplier) const; + float startOpacity(int frameNo) const + { + return mStartOpacity.value(frameNo) / 100; + } + float endOpacity(int frameNo) const + { + return mEndOpacity.value(frameNo) / 100; + } + bool isStatic() const + { + return mRotation.isStatic() && mScale.isStatic() && + mPosition.isStatic() && mAnchor.isStatic() && + mStartOpacity.isStatic() && mEndOpacity.isStatic(); + } + Property mRotation{0}; /* "r" */ + Property mScale{{100, 100}}; /* "s" */ + Property mPosition; /* "p" */ + Property mAnchor; /* "a" */ + Property mStartOpacity{100}; /* "so" */ + Property mEndOpacity{100}; /* "eo" */ }; - LOTPolystarData():LOTPath(LOTData::Type::Polystar){} + Repeater() : Object(Object::Type::Repeater) {} + Group *content() const { return mContent ? mContent : nullptr; } + void setContent(Group *content) { mContent = content; } + int maxCopies() const { return int(mMaxCopies); } + float copies(int frameNo) const { return mCopies.value(frameNo); } + float offset(int frameNo) const { return mOffset.value(frameNo); } + bool processed() const { return mProcessed; } + void markProcessed() { mProcessed = true; } + public: - LOTPolystarData::PolyType mPolyType{PolyType::Polygon}; - LOTAnimatable mPos; - LOTAnimatable mPointCount{0}; - LOTAnimatable mInnerRadius{0}; - LOTAnimatable mOuterRadius{0}; - LOTAnimatable mInnerRoundness{0}; - LOTAnimatable mOuterRoundness{0}; - LOTAnimatable mRotation{0}; + Group * mContent{nullptr}; + Transform mTransform; + Property mCopies{0}; + Property mOffset{0}; + float mMaxCopies{0.0}; + bool mProcessed{false}; }; -class LOTTrimData : public LOTData -{ +class Trim : public Object { public: struct Segment { float start{0}; float end{0}; Segment() = default; - explicit Segment(float s, float e):start(s), end(e) {} - }; - enum class TrimType { - Simultaneously, - Individually + explicit Segment(float s, float e) : start(s), end(e) {} }; - LOTTrimData():LOTData(LOTData::Type::Trim){} + enum class TrimType { Simultaneously, Individually }; + Trim() : Object(Object::Type::Trim) {} /* * if start > end vector trims the path as a loop ( 2 segment) * if start < end vector trims the path without loop ( 1 segment). * if no offset then there is no loop. */ - Segment segment(int frameNo) const { - float start = mStart.value(frameNo)/100.0f; - float end = mEnd.value(frameNo)/100.0f; - float offset = std::fmod(mOffset.value(frameNo), 360.0f)/ 360.0f; + Segment segment(int frameNo) const + { + float start = mStart.value(frameNo) / 100.0f; + float end = mEnd.value(frameNo) / 100.0f; + float offset = std::fmod(mOffset.value(frameNo), 360.0f) / 360.0f; float diff = std::abs(start - end); if (vCompare(diff, 0.0f)) return Segment(0, 0); @@ -985,30 +974,32 @@ public: if (offset > 0) { start += offset; end += offset; - if (start <= 1 && end <=1) { + if (start <= 1 && end <= 1) { return noloop(start, end); } else if (start > 1 && end > 1) { return noloop(start - 1, end - 1); } else { - return (start > 1) ? - loop(start - 1 , end) : loop(start , end - 1); + return (start > 1) ? loop(start - 1, end) + : loop(start, end - 1); } } else { start += offset; - end += offset; + end += offset; if (start >= 0 && end >= 0) { return noloop(start, end); } else if (start < 0 && end < 0) { return noloop(1 + start, 1 + end); } else { - return (start < 0) ? - loop(1 + start, end) : loop(start , 1 + end); + return (start < 0) ? loop(1 + start, end) + : loop(start, 1 + end); } } } - LOTTrimData::TrimType type() const {return mTrimType;} + Trim::TrimType type() const { return mTrimType; } + private: - Segment noloop(float start, float end) const{ + Segment noloop(float start, float end) const + { assert(start >= 0); assert(end >= 0); Segment s; @@ -1016,7 +1007,8 @@ private: s.end = std::max(start, end); return s; } - Segment loop(float start, float end) const{ + Segment loop(float start, float end) const + { assert(start >= 0); assert(end >= 0); Segment s; @@ -1024,73 +1016,81 @@ private: s.end = std::min(start, end); return s; } + public: - LOTAnimatable mStart{0}; - LOTAnimatable mEnd{0}; - LOTAnimatable mOffset{0}; - LOTTrimData::TrimType mTrimType{TrimType::Simultaneously}; + Property mStart{0}; + Property mEnd{0}; + Property mOffset{0}; + Trim::TrimType mTrimType{TrimType::Simultaneously}; }; -class LOTRepeaterTransform +inline Gradient::Data operator+(const Gradient::Data &g1, + const Gradient::Data &g2) { -public: - VMatrix matrix(int frameNo, float multiplier) const; - float startOpacity(int frameNo) const { return mStartOpacity.value(frameNo)/100;} - float endOpacity(int frameNo) const { return mEndOpacity.value(frameNo)/100;} - bool isStatic() const - { - return mRotation.isStatic() && - mScale.isStatic() && - mPosition.isStatic() && - mAnchor.isStatic() && - mStartOpacity.isStatic() && - mEndOpacity.isStatic(); + if (g1.mGradient.size() != g2.mGradient.size()) return g1; + + Gradient::Data newG; + newG.mGradient = g1.mGradient; + + auto g2It = g2.mGradient.begin(); + for (auto &i : newG.mGradient) { + i = i + *g2It; + g2It++; } -public: - LOTAnimatable mRotation{0}; /* "r" */ - LOTAnimatable mScale{{100, 100}}; /* "s" */ - LOTAnimatable mPosition; /* "p" */ - LOTAnimatable mAnchor; /* "a" */ - LOTAnimatable mStartOpacity{100}; /* "so" */ - LOTAnimatable mEndOpacity{100}; /* "eo" */ -}; -class LOTRepeaterData : public LOTData + return newG; +} + +inline Gradient::Data operator-(const Gradient::Data &g1, + const Gradient::Data &g2) { -public: - LOTRepeaterData():LOTData(LOTData::Type::Repeater){} - LOTShapeGroupData *content() const { return mContent ? mContent : nullptr; } - void setContent(LOTShapeGroupData *content) {mContent = content;} - int maxCopies() const { return int(mMaxCopies);} - float copies(int frameNo) const {return mCopies.value(frameNo);} - float offset(int frameNo) const {return mOffset.value(frameNo);} - bool processed() const {return mProcessed;} - void markProcessed() {mProcessed = true;} -public: - LOTShapeGroupData* mContent{nullptr}; - LOTRepeaterTransform mTransform; - LOTAnimatable mCopies{0}; - LOTAnimatable mOffset{0}; - float mMaxCopies{0.0}; - bool mProcessed{false}; -}; + if (g1.mGradient.size() != g2.mGradient.size()) return g1; + Gradient::Data newG; + newG.mGradient = g1.mGradient; -class LOTModel + auto g2It = g2.mGradient.begin(); + for (auto &i : newG.mGradient) { + i = i - *g2It; + g2It++; + } + + return newG; +} + +inline Gradient::Data operator*(float m, const Gradient::Data &g) { -public: - bool isStatic() const {return mRoot->isStatic();} - VSize size() const {return mRoot->size();} - double duration() const {return mRoot->duration();} - size_t totalFrame() const {return mRoot->totalFrame();} - size_t frameDuration() const {return mRoot->frameDuration();} - double frameRate() const {return mRoot->frameRate();} - size_t startFrame() const {return mRoot->startFrame();} - size_t endFrame() const {return mRoot->endFrame();} - size_t frameAtPos(double pos) const {return mRoot->frameAtPos(pos);} - std::vector layerInfoList() const { return mRoot->layerInfoList();} - const std::vector &markers() const { return mRoot->markers();} -public: - std::shared_ptr mRoot; -}; + Gradient::Data newG; + newG.mGradient = g.mGradient; + + for (auto &i : newG.mGradient) { + i = i * m; + } + return newG; +} + +using ColorFilter = std::function; + +void configureModelCacheSize(size_t cacheSize); + +std::shared_ptr loadFromFile(const std::string &filePath, + bool cachePolicy); + +std::shared_ptr loadFromData(std::string jsonData, + const std::string &key, + std::string resourcePath, + bool cachePolicy); + +std::shared_ptr loadFromData(std::string jsonData, + std::string resourcePath, + ColorFilter filter); + +std::shared_ptr parse(char *str, std::string dir_path, + ColorFilter filter = {}); + +} // namespace model + +} // namespace internal + +} // namespace rlottie -#endif // LOTModel_H +#endif // LOTModel_H diff --git a/src/lottie/lottieparser.cpp b/src/lottie/lottieparser.cpp index 2e2720f..b3d6394 100644 --- a/src/lottie/lottieparser.cpp +++ b/src/lottie/lottieparser.cpp @@ -16,8 +16,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "lottieparser.h" - //#define DEBUG_PARSER // This parser implements JSON token-by-token parsing with an API that is @@ -63,6 +61,8 @@ RAPIDJSON_DIAG_OFF(effc++) using namespace rapidjson; +using namespace rlottie::internal; + class LookaheadParserHandler { public: bool Null() @@ -169,111 +169,116 @@ protected: class LottieParserImpl : public LookaheadParserHandler { public: - LottieParserImpl(char *str, std::string dir_path, ColorFilter filter) + LottieParserImpl(char *str, std::string dir_path, model::ColorFilter filter) : LookaheadParserHandler(str), mColorFilter(std::move(filter)), - mDirPath(std::move(dir_path)) {} + mDirPath(std::move(dir_path)) + { + } bool VerifyType(); bool ParseNext(); + public: - VArenaAlloc& allocator() {return compRef->mArenaAlloc;} - bool EnterObject(); - bool EnterArray(); - const char *NextObjectKey(); - bool NextArrayValue(); - int GetInt(); - double GetDouble(); - const char *GetString(); - bool GetBool(); - void GetNull(); + VArenaAlloc &allocator() { return compRef->mArenaAlloc; } + bool EnterObject(); + bool EnterArray(); + const char * NextObjectKey(); + bool NextArrayValue(); + int GetInt(); + double GetDouble(); + const char * GetString(); + bool GetBool(); + void GetNull(); void SkipObject(); void SkipArray(); void SkipValue(); Value *PeekValue(); - int PeekType() const; - bool IsValid() { return st_ != kError; } + int PeekType() const; + bool IsValid() { return st_ != kError; } void Skip(const char *key); - LottieBlendMode getBlendMode(); + model::BlendMode getBlendMode(); CapStyle getLineCap(); JoinStyle getLineJoin(); FillRule getFillRule(); - LOTTrimData::TrimType getTrimType(); - MatteType getMatteType(); - LayerType getLayerType(); + model::Trim::TrimType getTrimType(); + model::MatteType getMatteType(); + model::Layer::Type getLayerType(); - std::shared_ptr composition() const + std::shared_ptr composition() const { return mComposition; } - void parseComposition(); - void parseMarkers(); - void parseMarker(); - void parseAssets(LOTCompositionData *comp); - LOTAsset* parseAsset(); - void parseLayers(LOTCompositionData *comp); - LOTLayerData* parseLayer(); - void parseMaskProperty(LOTLayerData *layer); - void parseShapesAttr(LOTLayerData *layer); - void parseObject(LOTGroupData *parent); - LOTMaskData* parseMaskObject(); - LOTData* parseObjectTypeAttr(); - LOTData* parseGroupObject(); - LOTRectData* parseRectObject(); - LOTEllipseData* parseEllipseObject(); - LOTShapeData* parseShapeObject(); - LOTPolystarData* parsePolystarObject(); - - LOTTransformData* parseTransformObject(bool ddd = false); - LOTFillData* parseFillObject(); - LOTGFillData* parseGFillObject(); - LOTStrokeData* parseStrokeObject(); - LOTGStrokeData* parseGStrokeObject(); - LOTTrimData* parseTrimObject(); - LOTRepeaterData* parseReapeaterObject(); - - void parseGradientProperty(LOTGradient *gradient, const char *key); + void parseComposition(); + void parseMarkers(); + void parseMarker(); + void parseAssets(model::Composition *comp); + model::Asset * parseAsset(); + void parseLayers(model::Composition *comp); + model::Layer * parseLayer(); + void parseMaskProperty(model::Layer *layer); + void parseShapesAttr(model::Layer *layer); + void parseObject(model::Group *parent); + model::Mask * parseMaskObject(); + model::Object * parseObjectTypeAttr(); + model::Object * parseGroupObject(); + model::Rect * parseRectObject(); + model::Ellipse * parseEllipseObject(); + model::Path * parseShapeObject(); + model::Polystar *parsePolystarObject(); + + model::Transform * parseTransformObject(bool ddd = false); + model::Fill * parseFillObject(); + model::GradientFill * parseGFillObject(); + model::Stroke * parseStrokeObject(); + model::GradientStroke *parseGStrokeObject(); + model::Trim * parseTrimObject(); + model::Repeater * parseReapeaterObject(); + + void parseGradientProperty(model::Gradient *gradient, const char *key); VPointF parseInperpolatorPoint(); void getValue(VPointF &pt); void getValue(float &fval); - void getValue(LottieColor &color); + void getValue(model::Color &color); void getValue(int &ival); - void getValue(LottieShapeData &shape); - void getValue(LottieGradient &gradient); + void getValue(model::PathData &shape); + void getValue(model::Gradient::Data &gradient); void getValue(std::vector &v); - void getValue(LOTRepeaterTransform &); + void getValue(model::Repeater::Transform &); template - bool parseKeyFrameValue(const char *key, LOTKeyFrameValue &value); + bool parseKeyFrameValue(const char *key, model::Value &value); template - void parseKeyFrame(LOTAnimInfo &obj); + void parseKeyFrame(model::DynamicProperty &obj); template - void parseProperty(LOTAnimatable &obj); + void parseProperty(model::Property &obj); template - void parsePropertyHelper(LOTAnimatable &obj); + void parsePropertyHelper(model::Property &obj); - void parseShapeProperty(LOTAnimatable &obj); - void parseDashProperty(LOTDashProperty &dash); + void parseShapeProperty(model::Property &obj); + void parseDashProperty(model::Dash &dash); - VInterpolator* interpolator(VPointF, VPointF, std::string); + VInterpolator *interpolator(VPointF, VPointF, std::string); - LottieColor toColor(const char *str); + model::Color toColor(const char *str); void resolveLayerRefs(); void parsePathInfo(); + private: - ColorFilter mColorFilter; + model::ColorFilter mColorFilter; struct { - std::vector mInPoint; /* "i" */ - std::vector mOutPoint; /* "o" */ - std::vector mVertices; /* "v" */ - std::vector mResult; - bool mClosed{false}; - - void convert() { + std::vector mInPoint; /* "i" */ + std::vector mOutPoint; /* "o" */ + std::vector mVertices; /* "v" */ + std::vector mResult; + bool mClosed{false}; + + void convert() + { // shape data could be empty. if (mInPoint.empty() || mOutPoint.empty() || mVertices.empty()) { mResult.clear(); @@ -283,8 +288,8 @@ private: /* * Convert the AE shape format to * list of bazier curves - * The final structure will be Move +size*Cubic + Cubic (if the path is - * closed one) + * The final structure will be Move +size*Cubic + Cubic (if the path + * is closed one) */ if (mInPoint.size() != mOutPoint.size() || mInPoint.size() != mVertices.size()) { @@ -293,31 +298,34 @@ private: auto size = mVertices.size(); mResult.push_back(mVertices[0]); for (size_t i = 1; i < size; i++) { - mResult.push_back(mVertices[i - 1] + - mOutPoint[i - 1]); // CP1 = start + outTangent + mResult.push_back( + mVertices[i - 1] + + mOutPoint[i - 1]); // CP1 = start + outTangent mResult.push_back(mVertices[i] + - mInPoint[i]); // CP2 = end + inTangent + mInPoint[i]); // CP2 = end + inTangent mResult.push_back(mVertices[i]); // end point } if (mClosed) { - mResult.push_back(mVertices[size - 1] + - mOutPoint[size - 1]); // CP1 = start + outTangent + mResult.push_back( + mVertices[size - 1] + + mOutPoint[size - 1]); // CP1 = start + outTangent mResult.push_back(mVertices[0] + - mInPoint[0]); // CP2 = end + inTangent + mInPoint[0]); // CP2 = end + inTangent mResult.push_back(mVertices[0]); // end point } } } - void reset() { + void reset() + { mInPoint.clear(); mOutPoint.clear(); mVertices.clear(); mResult.clear(); mClosed = false; } - void updatePath(VPath &out) { - + void updatePath(VPath &out) + { if (mResult.empty()) return; auto size = mResult.size(); @@ -326,24 +334,23 @@ private: * ptSize = size + 1(size + close) * elmSize = size/3 cubic + 1 move + 1 close */ - out.reserve(size + 1 , size/3 + 2); + out.reserve(size + 1, size / 3 + 2); out.moveTo(points[0]); - for (size_t i = 1 ; i < size; i+=3) { - out.cubicTo(points[i], points[i+1], points[i+2]); + for (size_t i = 1; i < size; i += 3) { + out.cubicTo(points[i], points[i + 1], points[i + 2]); } - if (mClosed) - out.close(); - } - }mPathInfo; + if (mClosed) out.close(); + } + } mPathInfo; + protected: - std::unordered_map - mInterpolatorCache; - std::shared_ptr mComposition; - LOTCompositionData * compRef{nullptr}; - LOTLayerData * curLayerRef{nullptr}; - std::vector mLayersToUpdate; - std::string mDirPath; - void SkipOut(int depth); + std::unordered_map mInterpolatorCache; + std::shared_ptr mComposition; + model::Composition * compRef{nullptr}; + model::Layer * curLayerRef{nullptr}; + std::vector mLayersToUpdate; + std::string mDirPath; + void SkipOut(int depth); }; LookaheadParserHandler::LookaheadParserHandler(char *str) @@ -586,20 +593,20 @@ void LottieParserImpl::Skip(const char * /*key*/) } } -LottieBlendMode LottieParserImpl::getBlendMode() +model::BlendMode LottieParserImpl::getBlendMode() { RAPIDJSON_ASSERT(PeekType() == kNumberType); - LottieBlendMode mode = LottieBlendMode::Normal; + auto mode = model::BlendMode::Normal; switch (GetInt()) { case 1: - mode = LottieBlendMode::Multiply; + mode = model::BlendMode::Multiply; break; case 2: - mode = LottieBlendMode::Screen; + mode = model::BlendMode::Screen; break; case 3: - mode = LottieBlendMode::OverLay; + mode = model::BlendMode::OverLay; break; default: break; @@ -610,11 +617,11 @@ LottieBlendMode LottieParserImpl::getBlendMode() void LottieParserImpl::resolveLayerRefs() { for (const auto &layer : mLayersToUpdate) { - auto search = compRef->mAssets.find(layer->extra()->mPreCompRefId); + auto search = compRef->mAssets.find(layer->extra()->mPreCompRefId); if (search != compRef->mAssets.end()) { - if (layer->mLayerType == LayerType::Image) { + if (layer->mLayerType == model::Layer::Type::Image) { layer->extra()->mAsset = search->second; - } else if (layer->mLayerType == LayerType::Precomp) { + } else if (layer->mLayerType == model::Layer::Type::Precomp) { layer->mChildren = search->second->mLayers; layer->setStatic(layer->isStatic() && search->second->isStatic()); @@ -627,9 +634,9 @@ void LottieParserImpl::parseComposition() { RAPIDJSON_ASSERT(PeekType() == kObjectType); EnterObject(); - std::shared_ptr sharedComposition = - std::make_shared(); - LOTCompositionData *comp = sharedComposition.get(); + std::shared_ptr sharedComposition = + std::make_shared(); + model::Composition *comp = sharedComposition.get(); compRef = comp; while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "v")) { @@ -686,7 +693,7 @@ void LottieParserImpl::parseMarker() EnterObject(); std::string comment; int timeframe{0}; - int duration{0}; + int duration{0}; while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "cm")) { RAPIDJSON_ASSERT(PeekType() == kStringType); @@ -705,7 +712,8 @@ void LottieParserImpl::parseMarker() Skip(key); } } - compRef->mMarkers.emplace_back(std::move(comment), timeframe, timeframe + duration); + compRef->mMarkers.emplace_back(std::move(comment), timeframe, + timeframe + duration); } void LottieParserImpl::parseMarkers() @@ -718,7 +726,7 @@ void LottieParserImpl::parseMarkers() // update the precomp layers with the actual layer object } -void LottieParserImpl::parseAssets(LOTCompositionData *composition) +void LottieParserImpl::parseAssets(model::Composition *composition) { RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); @@ -740,10 +748,10 @@ static constexpr const unsigned char B64index[256] = { std::string b64decode(const char *data, const size_t len) { - auto p = reinterpret_cast(data); - int pad = len > 0 && (len % 4 || p[len - 1] == '='); - const size_t L = ((len + 3) / 4 - pad) * 4; - std::string str(L / 4 * 3 + pad, '\0'); + auto p = reinterpret_cast(data); + int pad = len > 0 && (len % 4 || p[len - 1] == '='); + const size_t L = ((len + 3) / 4 - pad) * 4; + std::string str(L / 4 * 3 + pad, '\0'); for (size_t i = 0, j = 0; i < L; i += 4) { int n = B64index[p[i]] << 18 | B64index[p[i + 1]] << 12 | @@ -782,8 +790,9 @@ static std::string convertFromBase64(const std::string &str) * so this is workaround for windows build */ #include -template -static std::string toString(const T &value) { +template +static std::string toString(const T &value) +{ std::ostringstream os; os << value; return os.str(); @@ -793,14 +802,14 @@ static std::string toString(const T &value) { * https://github.com/airbnb/lottie-web/blob/master/docs/json/layers/shape.json * */ -LOTAsset* LottieParserImpl::parseAsset() +model::Asset *LottieParserImpl::parseAsset() { RAPIDJSON_ASSERT(PeekType() == kObjectType); - auto asset = allocator().make(); - std::string filename; - std::string relativePath; - bool embededResource = false; + auto asset = allocator().make(); + std::string filename; + std::string relativePath; + bool embededResource = false; EnterObject(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "w")) { @@ -810,7 +819,7 @@ LOTAsset* LottieParserImpl::parseAsset() RAPIDJSON_ASSERT(PeekType() == kNumberType); asset->mHeight = GetInt(); } else if (0 == strcmp(key, "p")) { /* image name */ - asset->mAssetType = LOTAsset::Type::Image; + asset->mAssetType = model::Asset::Type::Image; RAPIDJSON_ASSERT(PeekType() == kStringType); filename = std::string(GetString()); } else if (0 == strcmp(key, "u")) { /* relative image path */ @@ -826,7 +835,7 @@ LOTAsset* LottieParserImpl::parseAsset() asset->mRefId = toString(GetInt()); } } else if (0 == strcmp(key, "layers")) { - asset->mAssetType = LOTAsset::Type::Precomp; + asset->mAssetType = model::Asset::Type::Precomp; RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); bool staticFlag = true; @@ -846,7 +855,7 @@ LOTAsset* LottieParserImpl::parseAsset() } } - if (asset->mAssetType == LOTAsset::Type::Image) { + if (asset->mAssetType == model::Asset::Type::Image) { if (embededResource) { // embeder resource should start with "data:" if (filename.compare(0, 5, "data:") == 0) { @@ -860,10 +869,10 @@ LOTAsset* LottieParserImpl::parseAsset() return asset; } -void LottieParserImpl::parseLayers(LOTCompositionData *comp) +void LottieParserImpl::parseLayers(model::Composition *comp) { - comp->mRootLayer = allocator().make(); - comp->mRootLayer->mLayerType = LayerType::Precomp; + comp->mRootLayer = allocator().make(); + comp->mRootLayer->mLayerType = model::Layer::Type::Precomp; comp->mRootLayer->setName("__"); bool staticFlag = true; RAPIDJSON_ASSERT(PeekType() == kArrayType); @@ -878,10 +887,10 @@ void LottieParserImpl::parseLayers(LOTCompositionData *comp) comp->mRootLayer->setStatic(staticFlag); } -LottieColor LottieParserImpl::toColor(const char *str) +model::Color LottieParserImpl::toColor(const char *str) { - LottieColor color; - auto len = strlen(str); + model::Color color; + auto len = strlen(str); // some resource has empty color string // return a default color for those cases. @@ -903,52 +912,52 @@ LottieColor LottieParserImpl::toColor(const char *str) return color; } -MatteType LottieParserImpl::getMatteType() +model::MatteType LottieParserImpl::getMatteType() { RAPIDJSON_ASSERT(PeekType() == kNumberType); switch (GetInt()) { case 1: - return MatteType::Alpha; + return model::MatteType::Alpha; break; case 2: - return MatteType::AlphaInv; + return model::MatteType::AlphaInv; break; case 3: - return MatteType::Luma; + return model::MatteType::Luma; break; case 4: - return MatteType::LumaInv; + return model::MatteType::LumaInv; break; default: - return MatteType::None; + return model::MatteType::None; break; } } -LayerType LottieParserImpl::getLayerType() +model::Layer::Type LottieParserImpl::getLayerType() { RAPIDJSON_ASSERT(PeekType() == kNumberType); switch (GetInt()) { case 0: - return LayerType::Precomp; + return model::Layer::Type::Precomp; break; case 1: - return LayerType::Solid; + return model::Layer::Type::Solid; break; case 2: - return LayerType::Image; + return model::Layer::Type::Image; break; case 3: - return LayerType::Null; + return model::Layer::Type::Null; break; case 4: - return LayerType::Shape; + return model::Layer::Type::Shape; break; case 5: - return LayerType::Text; + return model::Layer::Type::Text; break; default: - return LayerType::Null; + return model::Layer::Type::Null; break; } } @@ -957,10 +966,10 @@ LayerType LottieParserImpl::getLayerType() * https://github.com/airbnb/lottie-web/blob/master/docs/json/layers/shape.json * */ -LOTLayerData* LottieParserImpl::parseLayer() +model::Layer *LottieParserImpl::parseLayer() { RAPIDJSON_ASSERT(PeekType() == kObjectType); - LOTLayerData *layer = allocator().make(); + model::Layer *layer = allocator().make(); curLayerRef = layer; bool ddd = true; EnterObject(); @@ -1043,7 +1052,8 @@ LOTLayerData* LottieParserImpl::parseLayer() } // make sure layer data is not corrupted. - if (layer->hasParent() && (layer->id() == layer->parentId())) return nullptr; + if (layer->hasParent() && (layer->id() == layer->parentId())) + return nullptr; if (layer->mExtra) layer->mExtra->mCompRef = compRef; @@ -1052,7 +1062,7 @@ LOTLayerData* LottieParserImpl::parseLayer() // transform matrix(when it is a parent of some other layer) // so force it to be a Null Layer and release all resource. layer->setStatic(layer->mTransform->isStatic()); - layer->mLayerType = LayerType::Null; + layer->mLayerType = model::Layer::Type::Null; layer->mChildren = {}; return layer; } @@ -1074,7 +1084,7 @@ LOTLayerData* LottieParserImpl::parseLayer() return layer; } -void LottieParserImpl::parseMaskProperty(LOTLayerData *layer) +void LottieParserImpl::parseMaskProperty(model::Layer *layer) { RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); @@ -1083,9 +1093,9 @@ void LottieParserImpl::parseMaskProperty(LOTLayerData *layer) } } -LOTMaskData* LottieParserImpl::parseMaskObject() +model::Mask *LottieParserImpl::parseMaskObject() { - auto obj = allocator().make(); + auto obj = allocator().make(); RAPIDJSON_ASSERT(PeekType() == kObjectType); EnterObject(); @@ -1095,27 +1105,27 @@ LOTMaskData* LottieParserImpl::parseMaskObject() } else if (0 == strcmp(key, "mode")) { const char *str = GetString(); if (!str) { - obj->mMode = LOTMaskData::Mode::None; + obj->mMode = model::Mask::Mode::None; continue; } switch (str[0]) { case 'n': - obj->mMode = LOTMaskData::Mode::None; + obj->mMode = model::Mask::Mode::None; break; case 'a': - obj->mMode = LOTMaskData::Mode::Add; + obj->mMode = model::Mask::Mode::Add; break; case 's': - obj->mMode = LOTMaskData::Mode::Substarct; + obj->mMode = model::Mask::Mode::Substarct; break; case 'i': - obj->mMode = LOTMaskData::Mode::Intersect; + obj->mMode = model::Mask::Mode::Intersect; break; case 'f': - obj->mMode = LOTMaskData::Mode::Difference; + obj->mMode = model::Mask::Mode::Difference; break; default: - obj->mMode = LOTMaskData::Mode::None; + obj->mMode = model::Mask::Mode::None; break; } } else if (0 == strcmp(key, "pt")) { @@ -1130,7 +1140,7 @@ LOTMaskData* LottieParserImpl::parseMaskObject() return obj; } -void LottieParserImpl::parseShapesAttr(LOTLayerData *layer) +void LottieParserImpl::parseShapesAttr(model::Layer *layer) { RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); @@ -1139,7 +1149,7 @@ void LottieParserImpl::parseShapesAttr(LOTLayerData *layer) } } -LOTData* LottieParserImpl::parseObjectTypeAttr() +model::Object *LottieParserImpl::parseObjectTypeAttr() { RAPIDJSON_ASSERT(PeekType() == kStringType); const char *type = GetString(); @@ -1182,7 +1192,7 @@ LOTData* LottieParserImpl::parseObjectTypeAttr() } } -void LottieParserImpl::parseObject(LOTGroupData *parent) +void LottieParserImpl::parseObject(model::Group *parent) { RAPIDJSON_ASSERT(PeekType() == kObjectType); EnterObject(); @@ -1196,9 +1206,9 @@ void LottieParserImpl::parseObject(LOTGroupData *parent) } } -LOTData* LottieParserImpl::parseGroupObject() +model::Object *LottieParserImpl::parseGroupObject() { - auto group = allocator().make(); + auto group = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1210,8 +1220,10 @@ LOTData* LottieParserImpl::parseGroupObject() RAPIDJSON_ASSERT(PeekType() == kObjectType); parseObject(group); } - if (group->mChildren.back()->type() == LOTData::Type::Transform) { - group->mTransform = static_cast(group->mChildren.back()); + if (group->mChildren.back()->type() == + model::Object::Type::Transform) { + group->mTransform = + static_cast(group->mChildren.back()); group->mChildren.pop_back(); } } else { @@ -1233,9 +1245,9 @@ LOTData* LottieParserImpl::parseGroupObject() /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/rect.json */ -LOTRectData* LottieParserImpl::parseRectObject() +model::Rect *LottieParserImpl::parseRectObject() { - auto obj = allocator().make(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1262,9 +1274,9 @@ LOTRectData* LottieParserImpl::parseRectObject() /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/ellipse.json */ -LOTEllipseData* LottieParserImpl::parseEllipseObject() +model::Ellipse *LottieParserImpl::parseEllipseObject() { - auto obj = allocator().make(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1288,9 +1300,9 @@ LOTEllipseData* LottieParserImpl::parseEllipseObject() /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/shape.json */ -LOTShapeData* LottieParserImpl::parseShapeObject() +model::Path *LottieParserImpl::parseShapeObject() { - auto obj = allocator().make(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1316,9 +1328,9 @@ LOTShapeData* LottieParserImpl::parseShapeObject() /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/star.json */ -LOTPolystarData* LottieParserImpl::parsePolystarObject() +model::Polystar *LottieParserImpl::parsePolystarObject() { - auto obj = allocator().make(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1339,8 +1351,9 @@ LOTPolystarData* LottieParserImpl::parsePolystarObject() parseProperty(obj->mRotation); } else if (0 == strcmp(key, "sy")) { int starType = GetInt(); - if (starType == 1) obj->mPolyType = LOTPolystarData::PolyType::Star; - if (starType == 2) obj->mPolyType = LOTPolystarData::PolyType::Polygon; + if (starType == 1) obj->mPolyType = model::Polystar::PolyType::Star; + if (starType == 2) + obj->mPolyType = model::Polystar::PolyType::Polygon; } else if (0 == strcmp(key, "d")) { obj->mDirection = GetInt(); } else if (0 == strcmp(key, "hd")) { @@ -1361,19 +1374,19 @@ LOTPolystarData* LottieParserImpl::parsePolystarObject() return obj; } -LOTTrimData::TrimType LottieParserImpl::getTrimType() +model::Trim::TrimType LottieParserImpl::getTrimType() { RAPIDJSON_ASSERT(PeekType() == kNumberType); switch (GetInt()) { case 1: - return LOTTrimData::TrimType::Simultaneously; + return model::Trim::TrimType::Simultaneously; break; case 2: - return LOTTrimData::TrimType::Individually; + return model::Trim::TrimType::Individually; break; default: RAPIDJSON_ASSERT(0); - return LOTTrimData::TrimType::Simultaneously; + return model::Trim::TrimType::Simultaneously; break; } } @@ -1381,9 +1394,9 @@ LOTTrimData::TrimType LottieParserImpl::getTrimType() /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/trim.json */ -LOTTrimData* LottieParserImpl::parseTrimObject() +model::Trim *LottieParserImpl::parseTrimObject() { - auto obj = allocator().make(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1410,7 +1423,7 @@ LOTTrimData* LottieParserImpl::parseTrimObject() return obj; } -void LottieParserImpl::getValue(LOTRepeaterTransform &obj) +void LottieParserImpl::getValue(model::Repeater::Transform &obj) { EnterObject(); @@ -1433,11 +1446,11 @@ void LottieParserImpl::getValue(LOTRepeaterTransform &obj) } } -LOTRepeaterData* LottieParserImpl::parseReapeaterObject() +model::Repeater *LottieParserImpl::parseReapeaterObject() { - auto obj = allocator().make(); + auto obj = allocator().make(); - obj->setContent(allocator().make()); + obj->setContent(allocator().make()); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1478,15 +1491,14 @@ LOTRepeaterData* LottieParserImpl::parseReapeaterObject() /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/transform.json */ -LOTTransformData* LottieParserImpl::parseTransformObject( - bool ddd) +model::Transform *LottieParserImpl::parseTransformObject(bool ddd) { - auto objT = allocator().make(); + auto objT = allocator().make(); - std::shared_ptr sharedTransform = - std::make_shared(); + std::shared_ptr sharedTransform = + std::make_shared(); - auto obj = allocator().make(); + auto obj = allocator().make(); if (ddd) { obj->createExtraData(); obj->mExtra->m3DData = true; @@ -1537,8 +1549,7 @@ LOTTransformData* LottieParserImpl::parseTransformObject( obj->mRotation.isStatic() && obj->mScale.isStatic() && obj->mOpacity.isStatic(); if (obj->mExtra) { - isStatic = isStatic && - obj->mExtra->m3DRx.isStatic() && + isStatic = isStatic && obj->mExtra->m3DRx.isStatic() && obj->mExtra->m3DRy.isStatic() && obj->mExtra->m3DRz.isStatic() && obj->mExtra->mSeparateX.isStatic() && @@ -1553,9 +1564,9 @@ LOTTransformData* LottieParserImpl::parseTransformObject( /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/fill.json */ -LOTFillData* LottieParserImpl::parseFillObject() +model::Fill *LottieParserImpl::parseFillObject() { - auto obj = allocator().make(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1639,9 +1650,9 @@ JoinStyle LottieParserImpl::getLineJoin() /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/stroke.json */ -LOTStrokeData* LottieParserImpl::parseStrokeObject() +model::Stroke *LottieParserImpl::parseStrokeObject() { - auto obj = allocator().make(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1677,7 +1688,8 @@ LOTStrokeData* LottieParserImpl::parseStrokeObject() return obj; } -void LottieParserImpl::parseGradientProperty(LOTGradient *obj, const char *key) +void LottieParserImpl::parseGradientProperty(model::Gradient *obj, + const char * key) { if (0 == strcmp(key, "t")) { RAPIDJSON_ASSERT(PeekType() == kNumberType); @@ -1720,9 +1732,9 @@ void LottieParserImpl::parseGradientProperty(LOTGradient *obj, const char *key) /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/gfill.json */ -LOTGFillData* LottieParserImpl::parseGFillObject() +model::GradientFill *LottieParserImpl::parseGFillObject() { - auto obj = allocator().make(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1736,7 +1748,7 @@ LOTGFillData* LottieParserImpl::parseGFillObject() return obj; } -void LottieParserImpl::parseDashProperty(LOTDashProperty &dash) +void LottieParserImpl::parseDashProperty(model::Dash &dash) { RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); @@ -1757,9 +1769,9 @@ void LottieParserImpl::parseDashProperty(LOTDashProperty &dash) /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/gstroke.json */ -LOTGStrokeData* LottieParserImpl::parseGStrokeObject() +model::GradientStroke *LottieParserImpl::parseGStrokeObject() { - auto obj = allocator().make(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1831,7 +1843,7 @@ void LottieParserImpl::getValue(float &val) } } -void LottieParserImpl::getValue(LottieColor &color) +void LottieParserImpl::getValue(model::Color &color) { float val[4] = {0.f}; int i = 0; @@ -1844,14 +1856,14 @@ void LottieParserImpl::getValue(LottieColor &color) } } - if (mColorFilter) mColorFilter( val[0] , val[1], val[2]) ; + if (mColorFilter) mColorFilter(val[0], val[1], val[2]); color.r = val[0]; color.g = val[1]; color.b = val[2]; } -void LottieParserImpl::getValue(LottieGradient &grad) +void LottieParserImpl::getValue(model::Gradient::Data &grad) { if (PeekType() == kArrayType) EnterArray(); @@ -1907,7 +1919,7 @@ void LottieParserImpl::parsePathInfo() mPathInfo.convert(); } -void LottieParserImpl::getValue(LottieShapeData &obj) +void LottieParserImpl::getValue(model::PathData &obj) { parsePathInfo(); obj.mPoints = mPathInfo.mResult; @@ -1931,14 +1943,14 @@ VPointF LottieParserImpl::parseInperpolatorPoint() } template -bool LottieParserImpl::parseKeyFrameValue(const char *, LOTKeyFrameValue &) +bool LottieParserImpl::parseKeyFrameValue(const char *, model::Value &) { return false; } template <> -bool LottieParserImpl::parseKeyFrameValue(const char * key, - LOTKeyFrameValue &value) +bool LottieParserImpl::parseKeyFrameValue(const char * key, + model::Value &value) { if (0 == strcmp(key, "ti")) { value.mPathKeyFrame = true; @@ -1952,8 +1964,9 @@ bool LottieParserImpl::parseKeyFrameValue(const char * key, return true; } -VInterpolator* LottieParserImpl::interpolator( - VPointF inTangent, VPointF outTangent, std::string key) +VInterpolator *LottieParserImpl::interpolator(VPointF inTangent, + VPointF outTangent, + std::string key) { if (key.empty()) { std::array temp; @@ -1977,7 +1990,7 @@ VInterpolator* LottieParserImpl::interpolator( * https://github.com/airbnb/lottie-web/blob/master/docs/json/properties/multiDimensionalKeyframed.json */ template -void LottieParserImpl::parseKeyFrame(LOTAnimInfo &obj) +void LottieParserImpl::parseKeyFrame(model::DynamicProperty &obj) { struct ParsedField { std::string interpolatorKey; @@ -1988,10 +2001,10 @@ void LottieParserImpl::parseKeyFrame(LOTAnimInfo &obj) }; EnterObject(); - ParsedField parsed; - LOTKeyFrame keyframe; - VPointF inTangent; - VPointF outTangent; + ParsedField parsed; + model::KeyFrame keyframe; + VPointF inTangent; + VPointF outTangent; while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "i")) { @@ -2069,7 +2082,7 @@ void LottieParserImpl::parseKeyFrame(LOTAnimInfo &obj) /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/properties/shape.json */ -void LottieParserImpl::parseShapeProperty(LOTAnimatable &obj) +void LottieParserImpl::parseShapeProperty(model::Property &obj) { EnterObject(); while (const char *key = NextObjectKey()) { @@ -2098,7 +2111,7 @@ void LottieParserImpl::parseShapeProperty(LOTAnimatable &obj) } template -void LottieParserImpl::parsePropertyHelper(LOTAnimatable &obj) +void LottieParserImpl::parsePropertyHelper(model::Property &obj) { if (PeekType() == kNumberType) { if (!obj.isStatic()) { @@ -2141,7 +2154,7 @@ void LottieParserImpl::parsePropertyHelper(LOTAnimatable &obj) * https://github.com/airbnb/lottie-web/tree/master/docs/json/properties */ template -void LottieParserImpl::parseProperty(LOTAnimatable &obj) +void LottieParserImpl::parseProperty(model::Property &obj) { EnterObject(); while (const char *key = NextObjectKey()) { @@ -2155,9 +2168,9 @@ void LottieParserImpl::parseProperty(LOTAnimatable &obj) #ifdef LOTTIE_DUMP_TREE_SUPPORT -class LOTDataInspector { +class model::ObjectInspector { public: - void visit(LOTCompositionData *obj, std::string level) + void visit(model::Composition *obj, std::string level) { vDebug << " { " << level << "Composition:: a: " << !obj->isStatic() << ", v: " << obj->mVersion << ", stFm: " << obj->startFrame() @@ -2169,7 +2182,7 @@ public: level.erase(level.end() - 1, level.end()); vDebug << " } " << level << "Composition End\n"; } - void visit(LOTLayerData *obj, std::string level) + void visit(model::Layer *obj, std::string level) { vDebug << level << "{ " << layerType(obj->mLayerType) << ", name: " << obj->name() << ", id:" << obj->mId @@ -2181,7 +2194,7 @@ public: << ", W:" << obj->layerSize().width() << ", H:" << obj->layerSize().height(); - if (obj->mLayerType == LayerType::Image) + if (obj->mLayerType == model::Layer::Type::Image) vDebug << level << "\t{ " << "ImageInfo:" << " W :" << obj->extra()->mAsset->mWidth @@ -2190,22 +2203,22 @@ public: else { vDebug << level; } - visitChildren(static_cast(obj), level); + visitChildren(static_cast(obj), level); vDebug << level << "} " << layerType(obj->mLayerType).c_str() << ", id: " << obj->mId << "\n"; } - void visitChildren(LOTGroupData *obj, std::string level) + void visitChildren(model::Group *obj, std::string level) { level.append("\t"); for (const auto &child : obj->mChildren) visit(child, level); if (obj->mTransform) visit(obj->mTransform, level); } - void visit(LOTData *obj, std::string level) + void visit(model::Object *obj, std::string level) { switch (obj->type()) { - case LOTData::Type::Repeater: { - auto r = static_cast(obj); + case model::Object::Type::Repeater: { + auto r = static_cast(obj); vDebug << level << "{ Repeater: name: " << obj->name() << " , a:" << !obj->isStatic() << ", copies:" << r->maxCopies() @@ -2214,64 +2227,64 @@ public: vDebug << level << "} Repeater"; break; } - case LOTData::Type::ShapeGroup: { - vDebug << level << "{ ShapeGroup: name: " << obj->name() + case model::Object::Type::Group: { + vDebug << level << "{ Group: name: " << obj->name() << " , a:" << !obj->isStatic(); - visitChildren(static_cast(obj), level); - vDebug << level << "} ShapeGroup"; + visitChildren(static_cast(obj), level); + vDebug << level << "} Group"; break; } - case LOTData::Type::Layer: { - visit(static_cast(obj), level); + case model::Object::Type::Layer: { + visit(static_cast(obj), level); break; } - case LOTData::Type::Trim: { + case model::Object::Type::Trim: { vDebug << level << "{ Trim: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::Rect: { + case model::Object::Type::Rect: { vDebug << level << "{ Rect: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::Ellipse: { + case model::Object::Type::Ellipse: { vDebug << level << "{ Ellipse: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::Shape: { + case model::Object::Type::Path: { vDebug << level << "{ Shape: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::Polystar: { + case model::Object::Type::Polystar: { vDebug << level << "{ Polystar: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::Transform: { + case model::Object::Type::Transform: { vDebug << level << "{ Transform: name: " << obj->name() << " , a: " << !obj->isStatic() << " }"; break; } - case LOTData::Type::Stroke: { + case model::Object::Type::Stroke: { vDebug << level << "{ Stroke: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::GStroke: { + case model::Object::Type::GStroke: { vDebug << level << "{ GStroke: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::Fill: { + case model::Object::Type::Fill: { vDebug << level << "{ Fill: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::GFill: { - auto f = static_cast(obj); + case model::Object::Type::GFill: { + auto f = static_cast(obj); vDebug << level << "{ GFill: name: " << obj->name() << " , a:" << !f->isStatic() << ", ty:" << f->mGradientType << ", s:" << f->mStartPoint.value(0) @@ -2286,19 +2299,19 @@ public: std::string matteType(MatteType type) { switch (type) { - case MatteType::None: + case model::MatteType::None: return "Matte::None"; break; - case MatteType::Alpha: + case model::MatteType::Alpha: return "Matte::Alpha"; break; - case MatteType::AlphaInv: + case model::MatteType::AlphaInv: return "Matte::AlphaInv"; break; - case MatteType::Luma: + case model::MatteType::Luma: return "Matte::Luma"; break; - case MatteType::LumaInv: + case model::MatteType::LumaInv: return "Matte::LumaInv"; break; default: @@ -2309,22 +2322,22 @@ public: std::string layerType(LayerType type) { switch (type) { - case LayerType::Precomp: + case model::Layer::Type::Precomp: return "Layer::Precomp"; break; - case LayerType::Null: + case model::Layer::Type::Null: return "Layer::Null"; break; - case LayerType::Shape: + case model::Layer::Type::Shape: return "Layer::Shape"; break; - case LayerType::Solid: + case model::Layer::Type::Solid: return "Layer::Solid"; break; - case LayerType::Image: + case model::Layer::Type::Image: return "Layer::Image"; break; - case LayerType::Text: + case model::Layer::Type::Text: return "Layer::Text"; break; default: @@ -2336,32 +2349,30 @@ public: #endif -LottieParser::~LottieParser() = default; -LottieParser::LottieParser(char *str, std::string dir_path, ColorFilter filter) - : d(std::make_unique(str, std::move(dir_path), std::move(filter))) -{ - if (d->VerifyType()) - d->parseComposition(); - else - vWarning << "Input data is not Lottie format!"; -} - -std::shared_ptr LottieParser::model() +std::shared_ptr model::parse(char * str, + std::string dir_path, + model::ColorFilter filter) { - if (!d->composition()) return nullptr; - - std::shared_ptr model = std::make_shared(); - model->mRoot = d->composition(); - model->mRoot->processRepeaterObjects(); - model->mRoot->updateStats(); + LottieParserImpl obj(str, std::move(dir_path), std::move(filter)); + if (obj.VerifyType()) { + obj.parseComposition(); + auto composition = obj.composition(); + if (composition) { + composition->processRepeaterObjects(); + composition->updateStats(); #ifdef LOTTIE_DUMP_TREE_SUPPORT - LOTDataInspector inspector; - inspector.visit(model->mRoot.get(), ""); + model::ObjectInspector inspector; + inspector.visit(composition.get(), ""); #endif - return model; + return composition; + } + } + + vWarning << "Input data is not Lottie format!"; + return {}; } RAPIDJSON_DIAG_POP diff --git a/src/lottie/lottieparser.h b/src/lottie/lottieparser.h deleted file mode 100644 index 378719f..0000000 --- a/src/lottie/lottieparser.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LOTTIEPARSER_H -#define LOTTIEPARSER_H - -#include "lottiemodel.h" -#include -#include - -using ColorFilter = std::function; -class LottieParserImpl; -class LottieParser { -public: - ~LottieParser(); - LottieParser(char* str, std::string dir_path, ColorFilter filter = {}); - std::shared_ptr model(); -private: - std::unique_ptr d; -}; - -#endif // LOTTIEPARSER_H diff --git a/src/lottie/lottieproxymodel.h b/src/lottie/lottieproxymodel.h index 9a6a3f9..6075169 100644 --- a/src/lottie/lottieproxymodel.h +++ b/src/lottie/lottieproxymodel.h @@ -13,66 +13,74 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LOTTIEPROXYMODEL_H #define LOTTIEPROXYMODEL_H -#include -#include -#include +#include +#include +#include #include "lottiemodel.h" #include "rlottie.h" +using namespace rlottie::internal; // Naive way to implement std::variant // refactor it when we move to c++17 // users should make sure proper combination // of id and value are passed while creating the object. -class LOTVariant -{ +class LOTVariant { public: - using ValueFunc = std::function; - using ColorFunc = std::function; - using PointFunc = std::function; - using SizeFunc = std::function; + using ValueFunc = std::function; + using ColorFunc = std::function; + using PointFunc = std::function; + using SizeFunc = std::function; - LOTVariant(rlottie::Property prop, const ValueFunc &v):mPropery(prop), mTag(Value) + LOTVariant(rlottie::Property prop, const ValueFunc& v) + : mPropery(prop), mTag(Value) { construct(impl.valueFunc, v); } - LOTVariant(rlottie::Property prop, ValueFunc &&v):mPropery(prop), mTag(Value) + LOTVariant(rlottie::Property prop, ValueFunc&& v) + : mPropery(prop), mTag(Value) { moveConstruct(impl.valueFunc, std::move(v)); } - LOTVariant(rlottie::Property prop, const ColorFunc &v):mPropery(prop), mTag(Color) + LOTVariant(rlottie::Property prop, const ColorFunc& v) + : mPropery(prop), mTag(Color) { construct(impl.colorFunc, v); } - LOTVariant(rlottie::Property prop, ColorFunc &&v):mPropery(prop), mTag(Color) + LOTVariant(rlottie::Property prop, ColorFunc&& v) + : mPropery(prop), mTag(Color) { moveConstruct(impl.colorFunc, std::move(v)); } - LOTVariant(rlottie::Property prop, const PointFunc &v):mPropery(prop), mTag(Point) + LOTVariant(rlottie::Property prop, const PointFunc& v) + : mPropery(prop), mTag(Point) { construct(impl.pointFunc, v); } - LOTVariant(rlottie::Property prop, PointFunc &&v):mPropery(prop), mTag(Point) + LOTVariant(rlottie::Property prop, PointFunc&& v) + : mPropery(prop), mTag(Point) { moveConstruct(impl.pointFunc, std::move(v)); } - LOTVariant(rlottie::Property prop, const SizeFunc &v):mPropery(prop), mTag(Size) + LOTVariant(rlottie::Property prop, const SizeFunc& v) + : mPropery(prop), mTag(Size) { construct(impl.sizeFunc, v); } - LOTVariant(rlottie::Property prop, SizeFunc &&v):mPropery(prop), mTag(Size) + LOTVariant(rlottie::Property prop, SizeFunc&& v) + : mPropery(prop), mTag(Size) { moveConstruct(impl.sizeFunc, std::move(v)); } @@ -104,11 +112,22 @@ public: } LOTVariant() = default; - ~LOTVariant() noexcept {Destroy();} - LOTVariant(const LOTVariant& other) { Copy(other);} - LOTVariant(LOTVariant&& other) noexcept { Move(std::move(other));} - LOTVariant& operator=(LOTVariant&& other) { Destroy(); Move(std::move(other)); return *this;} - LOTVariant& operator=(const LOTVariant& other) { Destroy(); Copy(other); return *this;} + ~LOTVariant() noexcept { Destroy(); } + LOTVariant(const LOTVariant& other) { Copy(other); } + LOTVariant(LOTVariant&& other) noexcept { Move(std::move(other)); } + LOTVariant& operator=(LOTVariant&& other) + { + Destroy(); + Move(std::move(other)); + return *this; + } + LOTVariant& operator=(const LOTVariant& other) + { + Destroy(); + Copy(other); + return *this; + } + private: template void construct(T& member, const T& val) @@ -169,7 +188,7 @@ private: void Destroy() { - switch(mTag) { + switch (mTag) { case MonoState: { break; } @@ -192,29 +211,29 @@ private: } } - enum Type {MonoState, Value, Color, Point , Size}; + enum Type { MonoState, Value, Color, Point, Size }; rlottie::Property mPropery; Type mTag{MonoState}; - union details{ - ColorFunc colorFunc; - ValueFunc valueFunc; - PointFunc pointFunc; - SizeFunc sizeFunc; - details(){} - ~details(){} - }impl; + union details { + ColorFunc colorFunc; + ValueFunc valueFunc; + PointFunc pointFunc; + SizeFunc sizeFunc; + details() {} + ~details() {} + } impl; }; -class LOTFilter -{ +class LOTFilter { public: - void addValue(LOTVariant &value) + void addValue(LOTVariant& value) { uint index = static_cast(value.property()); if (mBitset.test(index)) { - std::replace_if(mFilters.begin(), - mFilters.end(), - [&value](const LOTVariant &e) {return e.property() == value.property();}, + std::replace_if(mFilters.begin(), mFilters.end(), + [&value](const LOTVariant& e) { + return e.property() == value.property(); + }, value); } else { mBitset.set(index); @@ -222,14 +241,16 @@ public: } } - void removeValue(LOTVariant &value) + void removeValue(LOTVariant& value) { uint index = static_cast(value.property()); if (mBitset.test(index)) { mBitset.reset(index); - mFilters.erase(std::remove_if(mFilters.begin(), - mFilters.end(), - [&value](const LOTVariant &e) {return e.property() == value.property();}), + mFilters.erase(std::remove_if(mFilters.begin(), mFilters.end(), + [&value](const LOTVariant& e) { + return e.property() == + value.property(); + }), mFilters.end()); } } @@ -237,55 +258,55 @@ public: { return mBitset.test(static_cast(prop)); } - LottieColor color(rlottie::Property prop, int frame) const + model::Color color(rlottie::Property prop, int frame) const { rlottie::FrameInfo info(frame); - rlottie::Color col = data(prop).color()(info); - return LottieColor(col.r(), col.g(), col.b()); + rlottie::Color col = data(prop).color()(info); + return model::Color(col.r(), col.g(), col.b()); } VPointF point(rlottie::Property prop, int frame) const { rlottie::FrameInfo info(frame); - rlottie::Point pt = data(prop).point()(info); + rlottie::Point pt = data(prop).point()(info); return VPointF(pt.x(), pt.y()); } VSize scale(rlottie::Property prop, int frame) const { rlottie::FrameInfo info(frame); - rlottie::Size sz = data(prop).size()(info); + rlottie::Size sz = data(prop).size()(info); return VSize(sz.w(), sz.h()); } float opacity(rlottie::Property prop, int frame) const { rlottie::FrameInfo info(frame); - float val = data(prop).value()(info); - return val/100; + float val = data(prop).value()(info); + return val / 100; } float value(rlottie::Property prop, int frame) const { rlottie::FrameInfo info(frame); return data(prop).value()(info); } + private: const LOTVariant& data(rlottie::Property prop) const { - auto result = std::find_if(mFilters.begin(), - mFilters.end(), - [prop](const LOTVariant &e){return e.property() == prop;}); + auto result = std::find_if( + mFilters.begin(), mFilters.end(), + [prop](const LOTVariant& e) { return e.property() == prop; }); return *result; } - std::bitset<32> mBitset{0}; - std::vector mFilters; + std::bitset<32> mBitset{0}; + std::vector mFilters; }; template -class LOTProxyModel -{ +class LOTProxyModel { public: - LOTProxyModel(T *model): _modelData(model) {} - LOTFilter& filter() {return mFilter;} - const char* name() const {return _modelData->name();} - LottieColor color(int frame) const + LOTProxyModel(T* model) : _modelData(model) {} + LOTFilter& filter() { return mFilter; } + const char* name() const { return _modelData->name(); } + model::Color color(int frame) const { if (mFilter.hasFilter(rlottie::Property::StrokeColor)) { return mFilter.color(rlottie::Property::StrokeColor, frame); @@ -306,27 +327,27 @@ public: } return _modelData->strokeWidth(frame); } - float miterLimit() const {return _modelData->miterLimit();} - CapStyle capStyle() const {return _modelData->capStyle();} - JoinStyle joinStyle() const {return _modelData->joinStyle();} - bool hasDashInfo() const { return _modelData->hasDashInfo();} - void getDashInfo(int frameNo, std::vector& result) const { + float miterLimit() const { return _modelData->miterLimit(); } + CapStyle capStyle() const { return _modelData->capStyle(); } + JoinStyle joinStyle() const { return _modelData->joinStyle(); } + bool hasDashInfo() const { return _modelData->hasDashInfo(); } + void getDashInfo(int frameNo, std::vector& result) const + { return _modelData->getDashInfo(frameNo, result); } private: - T *_modelData; - LOTFilter mFilter; + T* _modelData; + LOTFilter mFilter; }; template <> -class LOTProxyModel -{ +class LOTProxyModel { public: - LOTProxyModel(LOTFillData *model): _modelData(model) {} - LOTFilter& filter() {return mFilter;} - const char* name() const {return _modelData->name();} - LottieColor color(int frame) const + LOTProxyModel(model::Fill* model) : _modelData(model) {} + LOTFilter& filter() { return mFilter; } + const char* name() const { return _modelData->name(); } + model::Color color(int frame) const { if (mFilter.hasFilter(rlottie::Property::FillColor)) { return mFilter.color(rlottie::Property::FillColor, frame); @@ -340,22 +361,22 @@ public: } return _modelData->opacity(frame); } - FillRule fillRule() const {return _modelData->fillRule();} + FillRule fillRule() const { return _modelData->fillRule(); } + private: - LOTFillData *_modelData; - LOTFilter mFilter; + model::Fill* _modelData; + LOTFilter mFilter; }; template <> -class LOTProxyModel -{ +class LOTProxyModel { public: - LOTProxyModel(LOTGroupData *model = nullptr): _modelData(model) {} - bool hasModel() const { return _modelData ? true : false; } - LOTFilter& filter() {return mFilter;} - const char* name() const {return _modelData->name();} - LOTTransformData* transform() const { return _modelData->mTransform; } - VMatrix matrix(int frame) const + LOTProxyModel(model::Group* model = nullptr) : _modelData(model) {} + bool hasModel() const { return _modelData ? true : false; } + LOTFilter& filter() { return mFilter; } + const char* name() const { return _modelData->name(); } + model::Transform* transform() const { return _modelData->mTransform; } + VMatrix matrix(int frame) const { VMatrix mS, mR, mT; if (mFilter.hasFilter(rlottie::Property::TrScale)) { @@ -371,8 +392,9 @@ public: return _modelData->mTransform->matrix(frame) * mS * mR * mT; } + private: - LOTGroupData *_modelData; - LOTFilter mFilter; + model::Group* _modelData; + LOTFilter mFilter; }; -#endif // LOTTIEITEM_H +#endif // LOTTIEITEM_H