From 27ddb3757e6b5423f4569a61001b4caad0b0dbd8 Mon Sep 17 00:00:00 2001 From: Reynaldo Aguilar Date: Tue, 15 Nov 2022 14:47:22 +1100 Subject: [PATCH] Include changes from original project (#4) * lottiemodel: Improve opacity calculation for gradient stop Basically, Graeidnt stop's color and opacity are provided as separate arrays. Stop position and opacity position do not match each other. Existing code is a sequential approach. It caused problems in various cases of positions. The improved logic repeats the loop, but no exceptions are raised. It's not complicated, it's simple. This code referenced the lottie-android library. https://github.com/airbnb/lottie-android/blob/master/lottie/src/main/java/com/airbnb/lottie/parser/GradientColorParser.java * replace uint ushort and uchar typedefs with uint32 uint16 and uint8 -- added format script to run clang format on latest commit. * replace unsigned int with uint32_t in Int() Signed-off-by: wangxuedong Change-Id: I4390c12fcf3aefccfe20290436b0dad96877008c * Add lottie_init() and lottie_shutdown() c api. To support dynamic loading and unloading of rlottie library safely we need to deallocate the resource cache as well as safely shutdown all the worker threads. current patch only stops the Render and Rle task schedulers when lottie_shutdown is called. Things yet to be implemented during shutdown phase - Unload image loader if loaded dynamically. - Check if we can release some cache resources. - Currently multiple load and unload of rlottie library will not work as we are not starting the scheduler again when lottie_init() called multiple time in the same process. * add formal parameter void to lottie_init() and lottie_shutdown() Signed-off-by: wangxuedong Change-Id: I40dbe4b07f9581e5042e468d3860e135622580c8 * Ignore animations with objects of unspecified type * Check border of color table while generating gradient * Delete accidentally committed Vim swap file * Fix one frame missing (#529) As mStartFrame and mEndFrame was counted from 0 and totalFrame() was calculated as a difference, there were always one frame missing and the animation rescaled. This patch adds one to the total frames count. issue: #527 * example: lottieviewer - fixed frame no (#528) There is a problem (issue #527) with totalFrame() in rlottie. As lottieviewer didn't showed the actual frame number, but calculated it from progress, it camouflaged the problem. Now the actual frame number and the total number of frames are displayed. Signed-off-by: wangxuedong Co-authored-by: JunsuChoi Co-authored-by: Subhransu Mohanty Co-authored-by: wangxuedong Co-authored-by: Nicholas Guriev Co-authored-by: Michal Maciola <71131832+mmaciola@users.noreply.github.com> --- example/lottieview.cpp | 1 - example/lottieviewer.cpp | 23 +++++----- format | 1 + inc/rlottie_capi.h | 30 +++++++++++++ src/binding/.lottieplayer.cpp.swp | Bin 12288 -> 0 bytes src/binding/c/lottieanimation_capi.cpp | 31 +++++++++++++ src/lottie/lottieanimation.cpp | 45 +++++++++++++++++-- src/lottie/lottiefiltermodel.h | 6 +-- src/lottie/lottieitem.cpp | 30 ++++++------- src/lottie/lottieitem.h | 20 ++++----- src/lottie/lottieitem_capi.cpp | 8 ++-- src/lottie/lottiekeypath.cpp | 6 +-- src/lottie/lottiekeypath.h | 12 ++--- src/lottie/lottiemodel.cpp | 59 +++++++------------------ src/lottie/lottiemodel.h | 15 ++++--- src/lottie/lottieparser.cpp | 8 +++- src/vector/vbitmap.cpp | 40 ++++++++--------- src/vector/vbitmap.h | 37 +++++++++------- src/vector/vbrush.cpp | 2 +- src/vector/vbrush.h | 2 +- src/vector/vdrawable.cpp | 2 +- src/vector/vdrawhelper.cpp | 20 ++++----- src/vector/vdrawhelper.h | 17 +++---- src/vector/vdrawhelper_common.cpp | 34 +++++++------- src/vector/vglobal.h | 57 +++++++++++++----------- src/vector/vpainter.cpp | 2 +- src/vector/vpath.h | 2 +- src/vector/vraster.cpp | 30 +++++++++++-- src/vector/vrle.cpp | 33 +++++++------- src/vector/vrle.h | 8 ++-- 30 files changed, 345 insertions(+), 236 deletions(-) create mode 100755 format delete mode 100644 src/binding/.lottieplayer.cpp.swp diff --git a/example/lottieview.cpp b/example/lottieview.cpp index d1fc9f26..7fdf903b 100644 --- a/example/lottieview.cpp +++ b/example/lottieview.cpp @@ -109,7 +109,6 @@ void LottieView::seek(float pos) { if (!mRenderDelegate) return; - mPos = mapProgress(pos); // check if the pos maps to the current frame diff --git a/example/lottieviewer.cpp b/example/lottieviewer.cpp index 8a09ea76..d3d86f35 100644 --- a/example/lottieviewer.cpp +++ b/example/lottieviewer.cpp @@ -62,12 +62,13 @@ _layout_del_cb(void *data, Evas *, Evas_Object *, void *) } static void -_update_frame_info(AppInfo *info, double pos) +_update_frame_info(AppInfo *info) { - int frameNo = pos * info->view->getTotalFrame(); - char buf[64]; + long currFrameNo = info->view->mCurFrame; + long totalFrameNo = info->view->getTotalFrame(); - sprintf(buf, "%d / %ld", frameNo, info->view->getTotalFrame()); + char buf[64]; + sprintf(buf, "%ld (total: %ld)", currFrameNo, totalFrameNo); elm_object_part_text_set(info->layout, "text", buf); } @@ -96,7 +97,7 @@ _animator_cb(void *data) if (info && info->autoPlaying && info->view) { float pos = info->view->getPos(); - _update_frame_info(info, pos); + _update_frame_info(info); elm_slider_value_set(info->slider, (double)pos); evas_object_image_pixels_dirty_set(info->view->getImage(), EINA_TRUE); if (pos >= 1.0) @@ -111,20 +112,20 @@ _slider_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) double val = elm_slider_value_get(obj); AppInfo *info = (AppInfo *)data; - _update_frame_info(info, val); - if (!info->autoPlaying) { info->view->seek(val); evas_object_image_pixels_dirty_set(info->view->getImage(), EINA_TRUE); } + + _update_frame_info(info); } static void _button_clicked_cb(void *data, Evas_Object */*obj*/, void */*event_info*/) { AppInfo *info = (AppInfo *)data; - + if (info->view->getPos() >= 1.0f) info->view->mPos = 0.0f; _toggle_start_button(info); } @@ -133,7 +134,6 @@ create_layout(Evas_Object *parent, const char *file) { Evas_Object *layout, *slider, *image, *button; Ecore_Animator *animator; - char buf[64]; AppInfo *info = (AppInfo *)calloc(sizeof(AppInfo), 1); //LAYOUT @@ -176,10 +176,9 @@ create_layout(Evas_Object *parent, const char *file) info->animator = animator; evas_object_event_callback_add(layout, EVAS_CALLBACK_DEL, _layout_del_cb, (void *)info); - sprintf(buf, "%d / %ld", 0, view->getTotalFrame()); - elm_object_part_text_set(layout, "text", buf); - view->seek(0.0); + _update_frame_info(info); + return layout; } diff --git a/format b/format new file mode 100755 index 00000000..c5630b48 --- /dev/null +++ b/format @@ -0,0 +1 @@ +git diff -U0 --no-color HEAD^ | clang-format-diff -i -p1 \ No newline at end of file diff --git a/inc/rlottie_capi.h b/inc/rlottie_capi.h index 7c883fac..80907ae6 100644 --- a/inc/rlottie_capi.h +++ b/inc/rlottie_capi.h @@ -46,6 +46,36 @@ typedef enum { typedef struct Lottie_Animation_S Lottie_Animation; +/** + * @brief Runs lottie initialization code when rlottie library is loaded + * dynamically. + * + * + * This api should be called before any other api when rlottie library + * is loaded using dlopen() or equivalent. + * + * @see lottie_shutdown() + * + * @ingroup Lottie_Animation + * @internal + */ +RLOTTIE_API void lottie_init(void); + +/** + * @brief Runs lottie teardown code when rlottie library is loaded + * dynamically. + * + * This api should be called before unloading the rlottie library for + * proper cleanup of the resource without doing so will result in undefined + * behaviour. + * + * @see lottie_init() + * + * @ingroup Lottie_Animation + * @internal + */ +RLOTTIE_API void lottie_shutdown(void); + /** * @brief Constructs an animation object from file path. * diff --git a/src/binding/.lottieplayer.cpp.swp b/src/binding/.lottieplayer.cpp.swp deleted file mode 100644 index e312a378e09c380c9279c04beb74d1bbdba214e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2OKcNI7{|ZR6VUJor(UW7gs_cYX;q2VG^c`u6i6gOgv7&gcE|BX&hB=1OrTN9 z<4kzoK_G5C!~p>p4jkcxs!AL|w5mWow8!?)s{ff;ZyYx^^w{=W>E~U0XTJHq-_BTx zJX7V#z5B$@VwrGkAbRoS_~Ds#XFoW%o~R+CS*i4m{)aCE-z$Vp|5ilb+JL3;D43Cs zic8A-M*8-(`dP7DY6ePqvJf_FCuLNMBd0Xw`L5?rCwJ_Pq7#Pi8jA0;0XEQSprz`C zorCo0C&Ol`Z{4z4Y#KV)*@Cax02^QfY=8~00XDz}*Z>>&j~h_o0G&dOtCBh=lk-5= zIeE(`Hoykh02^QfY=8~00XDz}*Z><~18m@5XrSg2eYBcraSf8k@Bi)p|KH;G|2NOW-0n1SUZR41tZ{ z_d%lHz|Y_<~18m@bX<(uAAR$B~RV(s^-RoHxiKOq!Xw-{UCJf^2Vb48rw1U64gjmoo zIFb(g4~~vj2=BeR$e@)N`Lb7#VvLQanQT_fn?Sn5W;Ks_M@&=|>`GZ{P3w zZaSdJLHAd>f10VyqMc2TVY{>@M*5_n$4`n`o`9B6b%K_!dZo}Iq(?ST)vx}-a6bX) z`+l{TZF$yDVZ=;=++1Gd8hzXshIQqhZzh55YP_4?J;u!ow9g5IHs?lH)!lhWbwJNY zH2dX4*x$Ys3USgHco+*Nsilwbcq@c@T2AMDjFC?g$gj=HIIKBR Zhs0)js|=C0dcM #include @@ -38,6 +41,34 @@ struct Lottie_Animation_S LOTMarkerList *mMarkerList; }; +static uint32_t _lottie_lib_ref_count = 0; + +RLOTTIE_API void lottie_init(void) +{ + if (_lottie_lib_ref_count > 0) { + _lottie_lib_ref_count++; + return; + } + lottie_init_impl(); + + _lottie_lib_ref_count = 1; +} + +RLOTTIE_API void lottie_shutdown(void) +{ + if (_lottie_lib_ref_count <= 0) { + // lottie_init() is not called before lottie_shutdown() + // or multiple shutdown is getting called. + return; + } + + _lottie_lib_ref_count--; + + if (_lottie_lib_ref_count == 0) { + lottie_shutdown_impl(); + } +} + RLOTTIE_API Lottie_Animation_S *lottie_animation_from_file(const char *path) { if (auto animation = Animation::loadFromFile(path) ) { diff --git a/src/lottie/lottieanimation.cpp b/src/lottie/lottieanimation.cpp index 601c065c..afcc400b 100644 --- a/src/lottie/lottieanimation.cpp +++ b/src/lottie/lottieanimation.cpp @@ -178,20 +178,29 @@ class RenderTaskScheduler { for (unsigned n = 0; n != _count; ++n) { _threads.emplace_back([&, n] { run(n); }); } + + IsRunning = true; } public: + static bool IsRunning; + static RenderTaskScheduler &instance() { static RenderTaskScheduler singleton; return singleton; } - ~RenderTaskScheduler() + ~RenderTaskScheduler() { stop(); } + + void stop() { - for (auto &e : _q) e.done(); + if (IsRunning) { + IsRunning = false; - for (auto &e : _threads) e.join(); + for (auto &e : _q) e.done(); + for (auto &e : _threads) e.join(); + } } std::future process(SharedRenderTask task) @@ -214,12 +223,16 @@ class RenderTaskScheduler { #else class RenderTaskScheduler { public: + static bool IsRunning; + static RenderTaskScheduler &instance() { static RenderTaskScheduler singleton; return singleton; } + void stop() {} + std::future process(SharedRenderTask task) { auto result = task->playerImpl->render(task->frameNo, task->surface, @@ -228,8 +241,11 @@ class RenderTaskScheduler { return std::move(task->receiver); } }; + #endif +bool RenderTaskScheduler::IsRunning{false}; + std::future AnimationImpl::renderAsync(size_t frameNo, Surface &&surface, bool keepAspectRatio) @@ -441,6 +457,29 @@ void Surface::setDrawRegion(size_t x, size_t y, size_t width, size_t height) mDrawArea.h = height; } +namespace { +void lottieShutdownRenderTaskScheduler() +{ + if (RenderTaskScheduler::IsRunning) { + RenderTaskScheduler::instance().stop(); + } +} +} // namespace + +// private apis exposed to c interface +void lottie_init_impl() +{ + // do nothing for now. +} + +extern void lottieShutdownRasterTaskScheduler(); + +void lottie_shutdown_impl() +{ + lottieShutdownRenderTaskScheduler(); + lottieShutdownRasterTaskScheduler(); +} + #ifdef LOTTIE_LOGGING_SUPPORT void initLogging() { diff --git a/src/lottie/lottiefiltermodel.h b/src/lottie/lottiefiltermodel.h index b2b98b19..4f78c11a 100644 --- a/src/lottie/lottiefiltermodel.h +++ b/src/lottie/lottiefiltermodel.h @@ -238,7 +238,7 @@ class FilterData { public: void addValue(LOTVariant& value) { - uint index = static_cast(value.property()); + uint32_t index = static_cast(value.property()); if (mBitset.test(index)) { std::replace_if(mFilters.begin(), mFilters.end(), [&value](const LOTVariant& e) { @@ -253,7 +253,7 @@ class FilterData { void removeValue(LOTVariant& value) { - uint index = static_cast(value.property()); + uint32_t index = static_cast(value.property()); if (mBitset.test(index)) { mBitset.reset(index); mFilters.erase(std::remove_if(mFilters.begin(), mFilters.end(), @@ -266,7 +266,7 @@ class FilterData { } bool hasFilter(rlottie::Property prop) const { - return mBitset.test(static_cast(prop)); + return mBitset.test(static_cast(prop)); } model::Color color(rlottie::Property prop, int frame) const { diff --git a/src/lottie/lottieitem.cpp b/src/lottie/lottieitem.cpp index 690e2c78..4cd22e4c 100644 --- a/src/lottie/lottieitem.cpp +++ b/src/lottie/lottieitem.cpp @@ -149,9 +149,9 @@ bool renderer::Composition::update(int frameNo, const VSize &size, bool renderer::Composition::render(const rlottie::Surface &surface) { - mSurface.reset(reinterpret_cast(surface.buffer()), - uint(surface.width()), uint(surface.height()), - uint(surface.bytesPerLine()), + mSurface.reset(reinterpret_cast(surface.buffer()), + uint32_t(surface.width()), uint32_t(surface.height()), + uint32_t(surface.bytesPerLine()), VBitmap::Format::ARGB32_Premultiplied); /* schedule all preprocess task for this frame at once. @@ -200,7 +200,7 @@ VRle renderer::Mask::rle() { if (!vCompare(mCombinedAlpha, 1.0f)) { VRle obj = mRasterizer.rle(); - obj *= uchar(mCombinedAlpha * 255); + obj *= uint8_t(mCombinedAlpha * 255); return obj; } else { return mRasterizer.rle(); @@ -343,7 +343,7 @@ renderer::Layer::Layer(model::Layer *layerData) : mLayerData(layerData) mLayerMask = std::make_unique(mLayerData); } -bool renderer::Layer::resolveKeyPath(LOTKeyPath &keyPath, uint depth, +bool renderer::Layer::resolveKeyPath(LOTKeyPath &keyPath, uint32_t depth, LOTVariant &value) { if (!keyPath.matches(name(), depth)) { @@ -359,12 +359,12 @@ bool renderer::Layer::resolveKeyPath(LOTKeyPath &keyPath, uint depth, return true; } -bool renderer::ShapeLayer::resolveKeyPath(LOTKeyPath &keyPath, uint depth, +bool renderer::ShapeLayer::resolveKeyPath(LOTKeyPath &keyPath, uint32_t depth, LOTVariant &value) { if (renderer::Layer::resolveKeyPath(keyPath, depth, value)) { if (keyPath.propagate(name(), depth)) { - uint newDepth = keyPath.nextDepth(name(), depth); + uint32_t newDepth = keyPath.nextDepth(name(), depth); mRoot->resolveKeyPath(keyPath, newDepth, value); } return true; @@ -372,12 +372,12 @@ bool renderer::ShapeLayer::resolveKeyPath(LOTKeyPath &keyPath, uint depth, return false; } -bool renderer::CompLayer::resolveKeyPath(LOTKeyPath &keyPath, uint depth, +bool renderer::CompLayer::resolveKeyPath(LOTKeyPath &keyPath, uint32_t depth, LOTVariant &value) { if (renderer::Layer::resolveKeyPath(keyPath, depth, value)) { if (keyPath.propagate(name(), depth)) { - uint newDepth = keyPath.nextDepth(name(), depth); + uint32_t newDepth = keyPath.nextDepth(name(), depth); for (const auto &layer : mLayers) { layer->resolveKeyPath(keyPath, newDepth, value); } @@ -443,7 +443,7 @@ VMatrix renderer::Layer::matrix(int frameNo) const bool renderer::Layer::visible() const { return (frameNo() >= mLayerData->inFrame() && - frameNo() < mLayerData->outFrame()); + frameNo() <= mLayerData->outFrame()); } void renderer::Layer::preprocess(const VRect &clip) @@ -507,7 +507,7 @@ void renderer::CompLayer::render(VPainter *painter, const VRle &inheritMask, renderHelper(&srcPainter, inheritMask, matteRle, cache); srcPainter.end(); painter->drawBitmap(VPoint(), srcBitmap, - uchar(combinedAlpha() * 255.0f)); + uint8_t(combinedAlpha() * 255.0f)); cache.release_surface(srcBitmap); } else { renderHelper(painter, inheritMask, matteRle, cache); @@ -863,7 +863,7 @@ renderer::DrawableList renderer::ShapeLayer::renderList() return {mDrawableList.data(), mDrawableList.size()}; } -bool renderer::Group::resolveKeyPath(LOTKeyPath &keyPath, uint depth, +bool renderer::Group::resolveKeyPath(LOTKeyPath &keyPath, uint32_t depth, LOTVariant &value) { if (!keyPath.skip(name())) { @@ -880,7 +880,7 @@ bool renderer::Group::resolveKeyPath(LOTKeyPath &keyPath, uint depth, } if (keyPath.propagate(name(), depth)) { - uint newDepth = keyPath.nextDepth(name(), depth); + uint32_t newDepth = keyPath.nextDepth(name(), depth); for (auto &child : mContents) { child->resolveKeyPath(keyPath, newDepth, value); } @@ -888,7 +888,7 @@ bool renderer::Group::resolveKeyPath(LOTKeyPath &keyPath, uint depth, return true; } -bool renderer::Fill::resolveKeyPath(LOTKeyPath &keyPath, uint depth, +bool renderer::Fill::resolveKeyPath(LOTKeyPath &keyPath, uint32_t depth, LOTVariant &value) { if (!keyPath.matches(mModel.name(), depth)) { @@ -903,7 +903,7 @@ bool renderer::Fill::resolveKeyPath(LOTKeyPath &keyPath, uint depth, return false; } -bool renderer::Stroke::resolveKeyPath(LOTKeyPath &keyPath, uint depth, +bool renderer::Stroke::resolveKeyPath(LOTKeyPath &keyPath, uint32_t depth, LOTVariant &value) { if (!keyPath.matches(mModel.name(), depth)) { diff --git a/src/lottie/lottieitem.h b/src/lottie/lottieitem.h index 6f602549..001ce667 100644 --- a/src/lottie/lottieitem.h +++ b/src/lottie/lottieitem.h @@ -80,7 +80,7 @@ namespace renderer { using DrawableList = VSpan; -enum class DirtyFlagBit : uchar { +enum class DirtyFlagBit : uint8_t { None = 0x00, Matrix = 0x01, Alpha = 0x02, @@ -239,8 +239,8 @@ class Layer { 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 bool resolveKeyPath(LOTKeyPath &keyPath, uint32_t depth, + LOTVariant &value); protected: virtual void preprocessStage(const VRect &clip) = 0; @@ -275,7 +275,7 @@ class CompLayer final : public Layer { void render(VPainter *painter, const VRle &mask, const VRle &matteRle, SurfaceCache &cache) final; void buildLayerNode() final; - bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + bool resolveKeyPath(LOTKeyPath &keyPath, uint32_t depth, LOTVariant &value) override; protected: @@ -317,7 +317,7 @@ class ShapeLayer final : public Layer { explicit ShapeLayer(model::Layer *layerData, VArenaAlloc *allocator); DrawableList renderList() final; void buildLayerNode() final; - bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + bool resolveKeyPath(LOTKeyPath &keyPath, uint32_t depth, LOTVariant &value) override; protected: @@ -355,13 +355,13 @@ class ImageLayer final : public Layer { class Object { public: - enum class Type : uchar { Unknown, Group, Shape, Paint, Trim }; + enum class Type : uint8_t { 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 &) + virtual bool resolveKeyPath(LOTKeyPath &, uint32_t, LOTVariant &) { return false; } @@ -387,7 +387,7 @@ class Group : public Object { static const char *TAG = "__"; return mModel.hasModel() ? mModel.name() : TAG; } - bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + bool resolveKeyPath(LOTKeyPath &keyPath, uint32_t depth, LOTVariant &value) override; protected: @@ -532,7 +532,7 @@ class Fill final : public Paint { protected: bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; - bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + bool resolveKeyPath(LOTKeyPath &keyPath, uint32_t depth, LOTVariant &value) final; private: @@ -557,7 +557,7 @@ class Stroke : public Paint { protected: bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; - bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + bool resolveKeyPath(LOTKeyPath &keyPath, uint32_t depth, LOTVariant &value) final; private: diff --git a/src/lottie/lottieitem_capi.cpp b/src/lottie/lottieitem_capi.cpp index 6f6fb950..31ca54a6 100644 --- a/src/lottie/lottieitem_capi.cpp +++ b/src/lottie/lottieitem_capi.cpp @@ -88,7 +88,7 @@ void renderer::Layer::buildLayerNode() mCApiData = std::make_unique(); clayer().keypath = name(); } - if (complexContent()) clayer().mAlpha = uchar(combinedAlpha() * 255.f); + if (complexContent()) clayer().mAlpha = uint8_t(combinedAlpha() * 255.f); clayer().mVisible = visible(); // update matte if (hasMatte()) { @@ -124,7 +124,7 @@ void renderer::Layer::buildLayerNode() cNode.mPath.ptCount = 2 * pts.size(); cNode.mPath.elmPtr = elmPtr; cNode.mPath.elmCount = elm.size(); - cNode.mAlpha = uchar(mask.mCombinedAlpha * 255.0f); + cNode.mAlpha = uint8_t(mask.mCombinedAlpha * 255.0f); switch (mask.maskMode()) { case model::Mask::Mode::Add: cNode.mMode = MaskAdd; @@ -196,7 +196,7 @@ void renderer::ImageLayer::buildLayerNode() // Alpha calculation already combined. lotDrawable->mCNode->mImageInfo.mAlpha = - uchar(lotDrawable->mBrush.mTexture->mAlpha); + uint8_t(lotDrawable->mBrush.mTexture->mAlpha); cnodes().push_back(lotDrawable->mCNode.get()); } @@ -216,7 +216,7 @@ static void updateGStops(LOTNode *n, const VGradient *grad) LOTGradientStop *ptr = n->mGradient.stopPtr; for (const auto &i : grad->mStops) { ptr->pos = i.first; - ptr->a = uchar(i.second.alpha() * grad->alpha()); + ptr->a = uint8_t(i.second.alpha() * grad->alpha()); ptr->r = i.second.red(); ptr->g = i.second.green(); ptr->b = i.second.blue(); diff --git a/src/lottie/lottiekeypath.cpp b/src/lottie/lottiekeypath.cpp index e8b6c6ae..21b01aac 100644 --- a/src/lottie/lottiekeypath.cpp +++ b/src/lottie/lottiekeypath.cpp @@ -12,7 +12,7 @@ LOTKeyPath::LOTKeyPath(const std::string &keyPath) } } -bool LOTKeyPath::matches(const std::string &key, uint depth) +bool LOTKeyPath::matches(const std::string &key, uint32_t depth) { if (skip(key)) { // This is an object we programatically create. @@ -28,7 +28,7 @@ bool LOTKeyPath::matches(const std::string &key, uint depth) return false; } -uint LOTKeyPath::nextDepth(const std::string key, uint depth) +uint32_t LOTKeyPath::nextDepth(const std::string key, uint32_t depth) { if (skip(key)) { // If it's a container then we added programatically and it isn't a part @@ -51,7 +51,7 @@ uint LOTKeyPath::nextDepth(const std::string key, uint depth) return depth; } -bool LOTKeyPath::fullyResolvesTo(const std::string key, uint depth) +bool LOTKeyPath::fullyResolvesTo(const std::string key, uint32_t depth) { if (depth > mKeys.size()) { return false; diff --git a/src/lottie/lottiekeypath.h b/src/lottie/lottiekeypath.h index 0b59b161..2c53287e 100644 --- a/src/lottie/lottiekeypath.h +++ b/src/lottie/lottiekeypath.h @@ -30,19 +30,19 @@ 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 matches(const std::string &key, uint32_t depth); + uint32_t nextDepth(const std::string key, uint32_t depth); + bool fullyResolvesTo(const std::string key, uint32_t depth); - bool propagate(const std::string key, uint depth) + bool propagate(const std::string key, uint32_t depth) { return skip(key) ? true : (depth < size()) || (mKeys[depth] == "**"); } 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 isGlobstar(uint32_t depth) const { return mKeys[depth] == "**"; } + bool isGlob(uint32_t depth) const { return mKeys[depth] == "*"; } bool endsWithGlobstar() const { return mKeys.back() == "**"; } size_t size() const { return mKeys.size() - 1; } diff --git a/src/lottie/lottiemodel.cpp b/src/lottie/lottiemodel.cpp index 9da82f70..1bca99d2 100644 --- a/src/lottie/lottiemodel.cpp +++ b/src/lottie/lottiemodel.cpp @@ -256,52 +256,12 @@ void model::Gradient::populate(VGradientStops &stops, int frameNo) 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]; model::Color color = model::Color(ptr[1], ptr[2], ptr[3]); if (opacityArraySize) { - if (j == opacityArraySize) { - // already reached the end - float stop1 = opacityPtr[j - 4]; - float op1 = opacityPtr[j - 3]; - float stop2 = opacityPtr[j - 2]; - float op2 = opacityPtr[j - 1]; - if (colorStop > stop2) { - stops.push_back( - std::make_pair(colorStop, color.toColor(op2))); - } else { - float progress = (colorStop - stop1) / (stop2 - stop1); - float opacity = op1 + progress * (op2 - op1); - stops.push_back( - std::make_pair(colorStop, color.toColor(opacity))); - } - continue; - } - for (; j < opacityArraySize; j += 2) { - float opacityStop = opacityPtr[j]; - if (opacityStop < colorStop) { - // add a color using opacity stop - stops.push_back(std::make_pair( - opacityStop, color.toColor(opacityPtr[j + 1]))); - continue; - } - // add a color using color stop - if (j == 0) { - stops.push_back(std::make_pair( - colorStop, color.toColor(opacityPtr[j + 1]))); - } else { - float progress = (colorStop - opacityPtr[j - 2]) / - (opacityPtr[j] - opacityPtr[j - 2]); - float opacity = - opacityPtr[j - 1] + - progress * (opacityPtr[j + 1] - opacityPtr[j - 1]); - stops.push_back( - std::make_pair(colorStop, color.toColor(opacity))); - } - j += 2; - break; - } + float opacity = getOpacityAtPosition(opacityPtr, opacityArraySize, colorStop); + stops.push_back(std::make_pair(colorStop, color.toColor(opacity))); } else { stops.push_back(std::make_pair(colorStop, color.toColor())); } @@ -309,6 +269,21 @@ void model::Gradient::populate(VGradientStops &stops, int frameNo) } } +float model::Gradient::getOpacityAtPosition(float *opacities, size_t opacityArraySize, float position) +{ + for (size_t i = 2; i < opacityArraySize; i += 2) + { + float lastPosition = opacities[i - 2]; + float thisPosition = opacities[i]; + if (opacities[i] >= position) { + float progress = (position - lastPosition) / (thisPosition - lastPosition); + progress = progress < 0.0f ? 0.0f : 1.0f < progress ? 1.0f : progress; //clamp(progress, 0, 1) + return opacities[i - 1] + progress * (opacities[i + 1] - opacities[i - 1]); + } + } + return 0.0f; +} + void model::Gradient::update(std::unique_ptr &grad, int frameNo) { bool init = false; diff --git a/src/lottie/lottiemodel.h b/src/lottie/lottiemodel.h index c6b8cf6d..745571e2 100644 --- a/src/lottie/lottiemodel.h +++ b/src/lottie/lottiemodel.h @@ -57,9 +57,9 @@ inline T lerp(const T &start, const T &end, float t) namespace model { -enum class MatteType : uchar { None = 0, Alpha = 1, AlphaInv, Luma, LumaInv }; +enum class MatteType : uint8_t { None = 0, Alpha = 1, AlphaInv, Luma, LumaInv }; -enum class BlendMode : uchar { +enum class BlendMode : uint8_t { Normal = 0, Multiply = 1, Screen = 2, @@ -72,8 +72,8 @@ class Color { 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)); + return VColor(uint8_t(255 * r), uint8_t(255 * g), uint8_t(255 * b), + uint8_t(255 * a)); } friend inline Color operator+(const Color &c1, const Color &c2); friend inline Color operator-(const Color &c1, const Color &c2); @@ -539,8 +539,8 @@ class Composition : public Object { { return long(frameAtPos(timeInSec / duration())); } - size_t totalFrame() const { return mEndFrame - mStartFrame; } - long frameDuration() const { return mEndFrame - mStartFrame - 1; } + size_t totalFrame() const { return mEndFrame - mStartFrame + 1; } + long frameDuration() const { return mEndFrame - mStartFrame; } float frameRate() const { return mFrameRate; } size_t startFrame() const { return mStartFrame; } size_t endFrame() const { return mEndFrame; } @@ -667,7 +667,7 @@ class Group : public Object { class Layer : public Group { public: - enum class Type : uchar { + enum class Type : uint8_t { Precomp = 0, Solid = 1, Image = 2, @@ -821,6 +821,7 @@ class Gradient : public Object { private: void populate(VGradientStops &stops, int frameNo); + float getOpacityAtPosition(float *opacities, size_t opacityArraySize, float position); public: int mGradientType{1}; /* "t" Linear=1 , Radial = 2*/ diff --git a/src/lottie/lottieparser.cpp b/src/lottie/lottieparser.cpp index ebaaf3e9..e14fd5c1 100644 --- a/src/lottie/lottieparser.cpp +++ b/src/lottie/lottieparser.cpp @@ -665,9 +665,9 @@ void LottieParserImpl::parseComposition() } else if (0 == strcmp(key, "h")) { comp->mSize.setHeight(GetInt()); } else if (0 == strcmp(key, "ip")) { - comp->mStartFrame = GetDouble(); + comp->mStartFrame = std::lround(GetDouble()); } else if (0 == strcmp(key, "op")) { - comp->mEndFrame = GetDouble(); + comp->mEndFrame = std::lround(GetDouble()); } else if (0 == strcmp(key, "fr")) { comp->mFrameRate = GetDouble(); } else if (0 == strcmp(key, "assets")) { @@ -1140,6 +1140,10 @@ void LottieParserImpl::parseShapesAttr(model::Layer *layer) model::Object *LottieParserImpl::parseObjectTypeAttr() { const char *type = GetString(); + if (!type) { + vWarning << "No object type specified"; + return nullptr; + } if (0 == strcmp(type, "gr")) { return parseGroupObject(); } else if (0 == strcmp(type, "rc")) { diff --git a/src/vector/vbitmap.cpp b/src/vector/vbitmap.cpp index 22cb2434..378db227 100644 --- a/src/vector/vbitmap.cpp +++ b/src/vector/vbitmap.cpp @@ -31,31 +31,31 @@ V_BEGIN_NAMESPACE void VBitmap::Impl::reset(size_t width, size_t height, VBitmap::Format format) { mRoData = nullptr; - mWidth = uint(width); - mHeight = uint(height); + mWidth = uint32_t(width); + mHeight = uint32_t(height); mFormat = format; mDepth = depth(format); mStride = ((mWidth * mDepth + 31) >> 5) << 2; // bytes per scanline (must be multiple of 4) - mOwnData = std::make_unique(mStride * mHeight); + mOwnData = std::make_unique(mStride * mHeight); } -void VBitmap::Impl::reset(uchar *data, size_t width, size_t height, size_t bytesPerLine, - VBitmap::Format format) +void VBitmap::Impl::reset(uint8_t *data, size_t width, size_t height, + size_t bytesPerLine, VBitmap::Format format) { mRoData = data; - mWidth = uint(width); - mHeight = uint(height); - mStride = uint(bytesPerLine); + mWidth = uint32_t(width); + mHeight = uint32_t(height); + mStride = uint32_t(bytesPerLine); mFormat = format; mDepth = depth(format); mOwnData = nullptr; } -uchar VBitmap::Impl::depth(VBitmap::Format format) +uint8_t VBitmap::Impl::depth(VBitmap::Format format) { - uchar depth = 1; + uint8_t depth = 1; switch (format) { case VBitmap::Format::Alpha8: depth = 8; @@ -70,7 +70,7 @@ uchar VBitmap::Impl::depth(VBitmap::Format format) return depth; } -void VBitmap::Impl::fill(uint /*pixel*/) +void VBitmap::Impl::fill(uint32_t /*pixel*/) { //@TODO } @@ -79,9 +79,9 @@ void VBitmap::Impl::updateLuma() { if (mFormat != VBitmap::Format::ARGB32_Premultiplied) return; auto dataPtr = data(); - for (uint col = 0; col < mHeight; col++) { - uint *pixel = (uint *)(dataPtr + mStride * col); - for (uint row = 0; row < mWidth; row++) { + for (uint32_t col = 0; col < mHeight; col++) { + uint32_t *pixel = (uint32_t *)(dataPtr + mStride * col); + for (uint32_t row = 0; row < mWidth; row++) { int alpha = vAlpha(*pixel); if (alpha == 0) { pixel++; @@ -112,8 +112,8 @@ VBitmap::VBitmap(size_t width, size_t height, VBitmap::Format format) mImpl = rc_ptr(width, height, format); } -VBitmap::VBitmap(uchar *data, size_t width, size_t height, size_t bytesPerLine, - VBitmap::Format format) +VBitmap::VBitmap(uint8_t *data, size_t width, size_t height, + size_t bytesPerLine, VBitmap::Format format) { if (!data || width <= 0 || height <= 0 || bytesPerLine <= 0 || format == Format::Invalid) @@ -122,7 +122,7 @@ VBitmap::VBitmap(uchar *data, size_t width, size_t height, size_t bytesPerLine, mImpl = rc_ptr(data, width, height, bytesPerLine, format); } -void VBitmap::reset(uchar *data, size_t w, size_t h, size_t bytesPerLine, +void VBitmap::reset(uint8_t *data, size_t w, size_t h, size_t bytesPerLine, VBitmap::Format format) { if (mImpl) { @@ -165,12 +165,12 @@ size_t VBitmap::depth() const return mImpl ? mImpl->mDepth : 0; } -uchar *VBitmap::data() +uint8_t *VBitmap::data() { return mImpl ? mImpl->data() : nullptr; } -uchar *VBitmap::data() const +uint8_t *VBitmap::data() const { return mImpl ? mImpl->data() : nullptr; } @@ -195,7 +195,7 @@ VBitmap::Format VBitmap::format() const return mImpl ? mImpl->format() : VBitmap::Format::Invalid; } -void VBitmap::fill(uint pixel) +void VBitmap::fill(uint32_t pixel) { if (mImpl) mImpl->fill(pixel); } diff --git a/src/vector/vbitmap.h b/src/vector/vbitmap.h index a068d744..bc5059a7 100644 --- a/src/vector/vbitmap.h +++ b/src/vector/vbitmap.h @@ -30,7 +30,7 @@ V_BEGIN_NAMESPACE class VBitmap { public: - enum class Format: uchar { + enum class Format : uint8_t { Invalid, Alpha8, ARGB32, @@ -39,8 +39,10 @@ class VBitmap { VBitmap() = default; VBitmap(size_t w, size_t h, VBitmap::Format format); - VBitmap(uchar *data, size_t w, size_t h, size_t bytesPerLine, VBitmap::Format format); - void reset(uchar *data, size_t w, size_t h, size_t stride, VBitmap::Format format); + VBitmap(uint8_t *data, size_t w, size_t h, size_t bytesPerLine, + VBitmap::Format format); + void reset(uint8_t *data, size_t w, size_t h, size_t stride, + VBitmap::Format format); void reset(size_t w, size_t h, VBitmap::Format format=Format::ARGB32_Premultiplied); size_t stride() const; size_t width() const; @@ -48,27 +50,28 @@ class VBitmap { size_t depth() const; VBitmap::Format format() const; bool valid() const; - uchar * data(); - uchar * data() const; + uint8_t * data(); + uint8_t * data() const; VRect rect() const; VSize size() const; - void fill(uint pixel); + void fill(uint32_t pixel); void updateLuma(); private: struct Impl { - std::unique_ptr mOwnData{nullptr}; - uchar * mRoData{nullptr}; - uint mWidth{0}; - uint mHeight{0}; - uint mStride{0}; - uchar mDepth{0}; + std::unique_ptr mOwnData{nullptr}; + uint8_t * mRoData{nullptr}; + uint32_t mWidth{0}; + uint32_t mHeight{0}; + uint32_t mStride{0}; + uint8_t mDepth{0}; VBitmap::Format mFormat{VBitmap::Format::Invalid}; explicit Impl(size_t width, size_t height, VBitmap::Format format) { reset(width, height, format); } - explicit Impl(uchar *data, size_t w, size_t h, size_t bytesPerLine, VBitmap::Format format) + explicit Impl(uint8_t *data, size_t w, size_t h, size_t bytesPerLine, + VBitmap::Format format) { reset(data, w, h, bytesPerLine, format); } @@ -77,12 +80,12 @@ class VBitmap { size_t stride() const { return mStride; } size_t width() const { return mWidth; } size_t height() const { return mHeight; } - uchar * data() { return mRoData ? mRoData : mOwnData.get(); } + uint8_t * data() { return mRoData ? mRoData : mOwnData.get(); } VBitmap::Format format() const { return mFormat; } - void reset(uchar *, size_t, size_t, size_t, VBitmap::Format); + void reset(uint8_t *, size_t, size_t, size_t, VBitmap::Format); void reset(size_t, size_t, VBitmap::Format); - static uchar depth(VBitmap::Format format); - void fill(uint); + static uint8_t depth(VBitmap::Format format); + void fill(uint32_t); void updateLuma(); }; diff --git a/src/vector/vbrush.cpp b/src/vector/vbrush.cpp index fc0902ba..f2ab3387 100644 --- a/src/vector/vbrush.cpp +++ b/src/vector/vbrush.cpp @@ -43,7 +43,7 @@ VBrush::VBrush(const VColor &color) : mType(VBrush::Type::Solid), mColor(color) { } -VBrush::VBrush(uchar r, uchar g, uchar b, uchar a) +VBrush::VBrush(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : mType(VBrush::Type::Solid), mColor(r, g, b, a) { diff --git a/src/vector/vbrush.h b/src/vector/vbrush.h index 74f8dcaf..a1abbd34 100644 --- a/src/vector/vbrush.h +++ b/src/vector/vbrush.h @@ -75,7 +75,7 @@ class VBrush { VBrush():mType(Type::NoBrush),mColor(){}; explicit VBrush(const VColor &color); explicit VBrush(const VGradient *gradient); - explicit VBrush(uchar r, uchar g, uchar b, uchar a); + explicit VBrush(uint8_t r, uint8_t g, uint8_t b, uint8_t a); explicit VBrush(const VTexture *texture); inline VBrush::Type type() const { return mType; } public: diff --git a/src/vector/vdrawable.cpp b/src/vector/vdrawable.cpp index c8ff02bc..55b1bc84 100644 --- a/src/vector/vdrawable.cpp +++ b/src/vector/vdrawable.cpp @@ -106,7 +106,7 @@ void VDrawable::setDashInfo(std::vector &dashInfo) bool hasChanged = false; if (obj->mDash.size() == dashInfo.size()) { - for (uint i = 0; i < dashInfo.size(); ++i) { + for (uint32_t i = 0; i < dashInfo.size(); ++i) { if (!vCompare(obj->mDash[i], dashInfo[i])) { hasChanged = true; break; diff --git a/src/vector/vdrawhelper.cpp b/src/vector/vdrawhelper.cpp index b14146d3..41593c86 100644 --- a/src/vector/vdrawhelper.cpp +++ b/src/vector/vdrawhelper.cpp @@ -56,7 +56,7 @@ class VGradientCache { VCacheKey hash_val = 0; VCacheData info; const VGradientStops &stops = gradient.mStops; - for (uint i = 0; i < stops.size() && i <= 2; i++) + for (uint32_t i = 0; i < stops.size() && i <= 2; i++) hash_val += VCacheKey(stops[i].second.premulARGB() * gradient.alpha()); @@ -100,11 +100,11 @@ class VGradientCache { } protected: - uint maxCacheSize() const { return 60; } + uint32_t maxCacheSize() const { return 60; } VCacheData addCacheElement(VCacheKey hash_val, const VGradient &gradient) { if (mCache.size() == maxCacheSize()) { - uint count = maxCacheSize() / 10; + uint32_t count = maxCacheSize() / 10; while (count--) { mCache.erase(mCache.begin()); } @@ -147,7 +147,7 @@ bool VGradientCache::generateGradientColorTable(const VGradientStops &stops, colorTable[pos++] = curColor; - while (fpos <= curr->first) { + while (fpos <= curr->first && pos < size) { colorTable[pos] = colorTable[pos - 1]; pos++; fpos += incr; @@ -519,7 +519,7 @@ static void blend_color(size_t size, const VRle::Span *array, void *userData) { VSpanData *data = (VSpanData *)(userData); Operator op = getOperator(data); - const uint color = data->mSolid; + const uint32_t color = data->mSolid; for (size_t i = 0 ; i < size; ++i) { const auto &span = array[i]; @@ -528,12 +528,12 @@ static void blend_color(size_t size, const VRle::Span *array, void *userData) } // Signature of Process Object -// void Pocess(uint* scratchBuffer, size_t x, size_t y, uchar cov) +// void Pocess(uint* scratchBuffer, size_t x, size_t y, uint8_t cov) template static inline void process_in_chunk(const VRle::Span *array, size_t size, Process process) { - std::array buf; + std::array buf; for (size_t i = 0; i < size; i++) { const auto &span = array[i]; size_t len = span.len; @@ -557,7 +557,7 @@ static void blend_gradient(size_t size, const VRle::Span *array, process_in_chunk( array, size, - [&](uint *scratch, size_t x, size_t y, size_t len, uchar cov) { + [&](uint32_t *scratch, size_t x, size_t y, size_t len, uint8_t cov) { op.srcFetch(scratch, &op, data, (int)y, (int)x, (int)len); op.func(data->buffer((int)x, (int)y), (int)len, scratch, cov); }); @@ -569,7 +569,7 @@ constexpr const T &clamp(const T &v, const T &lo, const T &hi) return v < lo ? lo : hi < v ? hi : v; } -static constexpr inline uchar alpha_mul(uchar a, uchar b) +static constexpr inline uint8_t alpha_mul(uint8_t a, uint8_t b) { return ((a * b) >> 8); } @@ -590,7 +590,7 @@ static void blend_image_xform(size_t size, const VRle::Span *array, process_in_chunk( array, size, - [&](uint *scratch, size_t x, size_t y, size_t len, uchar cov) { + [&](uint32_t *scratch, size_t x, size_t y, size_t len, uint8_t cov) { const auto coverage = (cov * src.alpha()) >> 8; const float xfactor = y * data->m21 + data->dx + data->m11; const float yfactor = y * data->m22 + data->dy + data->m12; diff --git a/src/vector/vdrawhelper.h b/src/vector/vdrawhelper.h index e654e93b..7d31e3f3 100644 --- a/src/vector/vdrawhelper.h +++ b/src/vector/vdrawhelper.h @@ -127,7 +127,7 @@ class VRasterBuffer { void resetBuffer(int val = 0); - inline uchar *scanLine(int y) + inline uint8_t *scanLine(int y) { assert(y >= 0); assert(size_t(y) < mHeight); @@ -150,7 +150,7 @@ class VRasterBuffer { size_t mHeight{0}; size_t mBytesPerLine{0}; size_t mBytesPerPixel{0}; - mutable uchar * mBuffer{nullptr}; + mutable uint8_t *mBuffer{nullptr}; }; struct VGradientData { @@ -171,8 +171,8 @@ struct VGradientData { struct VTextureData : public VRasterBuffer { uint32_t pixel(int x, int y) const { return *pixelRef(x, y); }; - uchar alpha() const { return mAlpha; } - void setAlpha(uchar alpha) { mAlpha = alpha; } + uint8_t alpha() const { return mAlpha; } + void setAlpha(uint8_t alpha) { mAlpha = alpha; } void setClip(const VRect &clip); // clip rect int left; @@ -180,7 +180,7 @@ struct VTextureData : public VRasterBuffer { int top; int bottom; bool hasAlpha; - uchar mAlpha; + uint8_t mAlpha; }; struct VColorTable { @@ -208,7 +208,7 @@ struct VSpanData { mDrawableSize = VSize(region.width(), region.height()); } - uint *buffer(int x, int y) const + uint32_t *buffer(int x, int y) const { return mRasterBuffer->pixelRef(x + mOffset.x(), y + mOffset.y()); } @@ -256,9 +256,10 @@ inline constexpr int vAlpha(uint32_t c) return c >> 24; } -static inline uint32_t interpolate_pixel(uint x, uint a, uint y, uint b) +static inline uint32_t interpolate_pixel(uint32_t x, uint32_t a, uint32_t y, + uint32_t b) { - uint t = (x & 0xff00ff) * a + (y & 0xff00ff) * b; + uint32_t t = (x & 0xff00ff) * a + (y & 0xff00ff) * b; t >>= 8; t &= 0xff00ff; x = ((x >> 8) & 0xff00ff) * a + ((y >> 8) & 0xff00ff) * b; diff --git a/src/vector/vdrawhelper_common.cpp b/src/vector/vdrawhelper_common.cpp index b2eb6db0..8a91b0f3 100644 --- a/src/vector/vdrawhelper_common.cpp +++ b/src/vector/vdrawhelper_common.cpp @@ -65,10 +65,10 @@ static void color_SourceOver(uint32_t *dest, int length, uint32_t color, dest = d * sa * ca + d * cia = d * (sa * ca + cia) */ -static void color_DestinationIn(uint *dest, int length, uint color, - uint alpha) +static void color_DestinationIn(uint32_t *dest, int length, uint32_t color, + uint32_t alpha) { - uint a = vAlpha(color); + uint32_t a = vAlpha(color); if (alpha != 255) { a = BYTE_MUL(a, alpha) + 255 - alpha; } @@ -82,10 +82,10 @@ static void color_DestinationIn(uint *dest, int length, uint color, dest = d * sia * ca + d * cia = d * (sia * ca + cia) */ -static void color_DestinationOut(uint *dest, int length, uint color, - uint alpha) +static void color_DestinationOut(uint32_t *dest, int length, uint32_t color, + uint32_t alpha) { - uint a = vAlpha(~color); + uint32_t a = vAlpha(~color); if (alpha != 255) a = BYTE_MUL(a, alpha) + 255 - alpha; for (int i = 0; i < length; ++i) { dest[i] = BYTE_MUL(dest[i], a); @@ -96,9 +96,9 @@ static void src_Source(uint32_t *dest, int length, const uint32_t *src, uint32_t alpha) { if (alpha == 255) { - memcpy(dest, src, size_t(length) * sizeof(uint)); + memcpy(dest, src, size_t(length) * sizeof(uint32_t)); } else { - uint ialpha = 255 - alpha; + uint32_t ialpha = 255 - alpha; for (int i = 0; i < length; ++i) { dest[i] = interpolate_pixel(src[i], alpha, dest[i], ialpha); @@ -112,7 +112,7 @@ static void src_Source(uint32_t *dest, int length, const uint32_t *src, static void src_SourceOver(uint32_t *dest, int length, const uint32_t *src, uint32_t alpha) { - uint s, sia; + uint32_t s, sia; if (alpha == 255) { for (int i = 0; i < length; ++i) { @@ -136,33 +136,33 @@ static void src_SourceOver(uint32_t *dest, int length, const uint32_t *src, } } -static void src_DestinationIn(uint *dest, int length, const uint *src, - uint alpha) +static void src_DestinationIn(uint32_t *dest, int length, const uint32_t *src, + uint32_t alpha) { if (alpha == 255) { for (int i = 0; i < length; ++i) { dest[i] = BYTE_MUL(dest[i], vAlpha(src[i])); } } else { - uint cia = 255 - alpha; + uint32_t cia = 255 - alpha; for (int i = 0; i < length; ++i) { - uint a = BYTE_MUL(vAlpha(src[i]), alpha) + cia; + uint32_t a = BYTE_MUL(vAlpha(src[i]), alpha) + cia; dest[i] = BYTE_MUL(dest[i], a); } } } -static void src_DestinationOut(uint *dest, int length, const uint *src, - uint alpha) +static void src_DestinationOut(uint32_t *dest, int length, const uint32_t *src, + uint32_t alpha) { if (alpha == 255) { for (int i = 0; i < length; ++i) { dest[i] = BYTE_MUL(dest[i], vAlpha(~src[i])); } } else { - uint cia = 255 - alpha; + uint32_t cia = 255 - alpha; for (int i = 0; i < length; ++i) { - uint sia = BYTE_MUL(vAlpha(~src[i]), alpha) + cia; + uint32_t sia = BYTE_MUL(vAlpha(~src[i]), alpha) + cia; dest[i] = BYTE_MUL(dest[i], sia); } } diff --git a/src/vector/vglobal.h b/src/vector/vglobal.h index 45e95e33..0aad7e8c 100644 --- a/src/vector/vglobal.h +++ b/src/vector/vglobal.h @@ -29,9 +29,6 @@ #include #include -using uint = uint32_t; -using ushort = uint16_t; -using uchar = uint8_t; #if !defined(V_NAMESPACE) @@ -122,10 +119,13 @@ class vFlagHelper { explicit constexpr inline vFlagHelper(int ai) noexcept : i(ai) {} constexpr inline operator int() const noexcept { return i; } - explicit constexpr inline vFlagHelper(uint ai) noexcept : i(int(ai)) {} + explicit constexpr inline vFlagHelper(uint32_t ai) noexcept : i(int(ai)) {} explicit constexpr inline vFlagHelper(short ai) noexcept : i(int(ai)) {} - explicit constexpr inline vFlagHelper(ushort ai) noexcept : i(int(uint(ai))) {} - constexpr inline operator uint() const noexcept { return uint(i); } + explicit constexpr inline vFlagHelper(uint16_t ai) noexcept + : i(int(uint32_t(ai))) + { + } + constexpr inline operator uint32_t() const noexcept { return uint32_t(i); } }; template @@ -139,7 +139,7 @@ class vFlag { using Int = typename std::conditional< std::is_unsigned::type>::value, - unsigned int, signed int>::type; + uint32_t, signed int>::type; using enum_type = Enum; // compiler-generated copy/move ctor/assignment operators are fine! @@ -153,7 +153,7 @@ class vFlag { i &= mask; return *this; } - inline vFlag &operator&=(uint mask) noexcept + inline vFlag &operator&=(uint32_t mask) noexcept { i &= mask; return *this; @@ -206,7 +206,7 @@ class vFlag { { return vFlag(vFlagHelper(i & mask)); } - constexpr inline vFlag operator&(uint mask) const noexcept + constexpr inline vFlag operator&(uint32_t mask) const noexcept { return vFlag(vFlagHelper(i & mask)); } @@ -236,44 +236,47 @@ class vFlag { class VColor { public: VColor() = default; - explicit VColor(uchar red, uchar green, uchar blue, uchar alpha = 255) noexcept - :a(alpha), r(red), g(green), b(blue){} - inline uchar red() const noexcept { return r; } - inline uchar green() const noexcept { return g; } - inline uchar blue() const noexcept { return b; } - inline uchar alpha() const noexcept { return a; } - inline void setRed(uchar red) noexcept { r = red; } - inline void setGreen(uchar green) noexcept { g = green; } - inline void setBlue(uchar blue) noexcept { b = blue; } - inline void setAlpha(uchar alpha) noexcept { a = alpha; } + explicit VColor(uint8_t red, uint8_t green, uint8_t blue, + uint8_t alpha = 255) noexcept + : a(alpha), r(red), g(green), b(blue) + { + } + inline uint8_t red() const noexcept { return r; } + inline uint8_t green() const noexcept { return g; } + inline uint8_t blue() const noexcept { return b; } + inline uint8_t alpha() const noexcept { return a; } + inline void setRed(uint8_t red) noexcept { r = red; } + inline void setGreen(uint8_t green) noexcept { g = green; } + inline void setBlue(uint8_t blue) noexcept { b = blue; } + inline void setAlpha(uint8_t alpha) noexcept { a = alpha; } inline bool isOpaque() const { return a == 255; } inline bool isTransparent() const { return a == 0; } inline bool operator==(const VColor &o) const { return ((a == o.a) && (r == o.r) && (g == o.g) && (b == o.b)); } - uint premulARGB() const + uint32_t premulARGB() const { int pr = (r * a) / 255; int pg = (g * a) / 255; int pb = (b * a) / 255; - return uint((a << 24) | (pr << 16) | (pg << 8) | (pb)); + return uint32_t((a << 24) | (pr << 16) | (pg << 8) | (pb)); } - uint premulARGB(float opacity) const + uint32_t premulARGB(float opacity) const { int alpha = int(a * opacity); int pr = (r * alpha) / 255; int pg = (g * alpha) / 255; int pb = (b * alpha) / 255; - return uint((alpha << 24) | (pr << 16) | (pg << 8) | (pb)); + return uint32_t((alpha << 24) | (pr << 16) | (pg << 8) | (pb)); } public: - uchar a{0}; - uchar r{0}; - uchar g{0}; - uchar b{0}; + uint8_t a{0}; + uint8_t r{0}; + uint8_t g{0}; + uint8_t b{0}; }; enum class FillRule: unsigned char { EvenOdd, Winding }; diff --git a/src/vector/vpainter.cpp b/src/vector/vpainter.cpp index 38a58e04..ab5492c7 100644 --- a/src/vector/vpainter.cpp +++ b/src/vector/vpainter.cpp @@ -66,7 +66,7 @@ static void fillRect(const VRect &r, VSpanData *data) int i = 0; while (i < n) { spans[i].x = short(x1); - spans[i].len = ushort(x2 - x1); + spans[i].len = uint16_t(x2 - x1); spans[i].y = short(y + i); spans[i].coverage = 255; ++i; diff --git a/src/vector/vpath.h b/src/vector/vpath.h index 90c2c3e5..9273cb61 100644 --- a/src/vector/vpath.h +++ b/src/vector/vpath.h @@ -35,7 +35,7 @@ class VPath { public: enum class Direction { CCW, CW }; - enum class Element : uchar { MoveTo, LineTo, CubicTo, Close }; + enum class Element : uint8_t { MoveTo, LineTo, CubicTo, Close }; bool empty() const; bool null() const; void moveTo(const VPointF &p); diff --git a/src/vector/vraster.cpp b/src/vector/vraster.cpp index 06243153..fdf66fb0 100644 --- a/src/vector/vraster.cpp +++ b/src/vector/vraster.cpp @@ -380,7 +380,7 @@ struct VRleTask { outRef.convert(mPath); outRef.convert(mCap, mJoin, mStrokeWidth, mMiterLimit); - uint points, contors; + uint32_t points, contors; SW_FT_Stroker_Set(stroker, outRef.ftWidth, outRef.ftCap, outRef.ftJoin, outRef.ftMiterLimit); @@ -461,20 +461,29 @@ class RleTaskScheduler { for (unsigned n = 0; n != _count; ++n) { _threads.emplace_back([&, n] { run(n); }); } + + IsRunning = true; } public: + static bool IsRunning; + static RleTaskScheduler &instance() { static RleTaskScheduler singleton; return singleton; } - ~RleTaskScheduler() + ~RleTaskScheduler() { stop(); } + + void stop() { - for (auto &e : _q) e.done(); + if (IsRunning) { + IsRunning = false; - for (auto &e : _threads) e.join(); + for (auto &e : _q) e.done(); + for (auto &e : _threads) e.join(); + } } void process(VTask task) @@ -499,12 +508,16 @@ class RleTaskScheduler { SW_FT_Stroker stroker; public: + static bool IsRunning; + static RleTaskScheduler &instance() { static RleTaskScheduler singleton; return singleton; } + void stop() {} + RleTaskScheduler() { SW_FT_Stroker_New(&stroker); } ~RleTaskScheduler() { SW_FT_Stroker_Done(stroker); } @@ -513,6 +526,8 @@ class RleTaskScheduler { }; #endif +bool RleTaskScheduler::IsRunning{false}; + struct VRasterizer::VRasterizerImpl { VRleTask mTask; @@ -560,4 +575,11 @@ void VRasterizer::rasterize(VPath path, CapStyle cap, JoinStyle join, updateRequest(); } +void lottieShutdownRasterTaskScheduler() +{ + if (RleTaskScheduler::IsRunning) { + RleTaskScheduler::instance().stop(); + } +} + V_END_NAMESPACE diff --git a/src/vector/vrle.cpp b/src/vector/vrle.cpp index 051560da..753db1a1 100644 --- a/src/vector/vrle.cpp +++ b/src/vector/vrle.cpp @@ -41,7 +41,7 @@ static size_t _opGeneric(rle_view &a, rle_view &b, Result &result, static size_t _opIntersect(const VRect &, rle_view &, Result &); static size_t _opIntersect(rle_view &, rle_view &, Result &); -static inline uchar divBy255(int x) +static inline uint8_t divBy255(int x) { return (x + (x >> 8) + 0x80) >> 8; } @@ -142,7 +142,7 @@ void VRle::Data::updateBbox() const } } -void VRle::Data::operator*=(uchar alpha) +void VRle::Data::operator*=(uint8_t alpha) { for (auto &i : mSpans) { i.coverage = divBy255(i.coverage * alpha); @@ -425,7 +425,7 @@ static size_t _opIntersect(const VRect &clip, rle_view &obj, Result &result) out->x = minx; } else { out->x = span.x; - out->len = std::min(span.len, ushort(maxx - span.x + 1)); + out->len = std::min(span.len, uint16_t(maxx - span.x + 1)); } if (out->len != 0) { out->y = span.y; @@ -442,12 +442,12 @@ static size_t _opIntersect(const VRect &clip, rle_view &obj, Result &result) return result.max_size() - available; } -static void blitXor(VRle::Span *spans, int count, uchar *buffer, int offsetX) +static void blitXor(VRle::Span *spans, int count, uint8_t *buffer, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; - uchar *ptr = buffer + x; + uint8_t *ptr = buffer + x; while (l--) { int da = *ptr; *ptr = divBy255((255 - spans->coverage) * (da) + @@ -458,13 +458,13 @@ static void blitXor(VRle::Span *spans, int count, uchar *buffer, int offsetX) } } -static void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, +static void blitDestinationOut(VRle::Span *spans, int count, uint8_t *buffer, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; - uchar *ptr = buffer + x; + uint8_t *ptr = buffer + x; while (l--) { *ptr = divBy255((255 - spans->coverage) * (*ptr)); ptr++; @@ -473,13 +473,13 @@ static void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, } } -static void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, +static void blitSrcOver(VRle::Span *spans, int count, uint8_t *buffer, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; - uchar *ptr = buffer + x; + uint8_t *ptr = buffer + x; while (l--) { *ptr = spans->coverage + divBy255((255 - spans->coverage) * (*ptr)); ptr++; @@ -488,12 +488,12 @@ static void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, } } -void blitSrc(VRle::Span *spans, int count, uchar *buffer, int offsetX) +void blitSrc(VRle::Span *spans, int count, uint8_t *buffer, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; - uchar *ptr = buffer + x; + uint8_t *ptr = buffer + x; while (l--) { *ptr = std::max(spans->coverage, *ptr); ptr++; @@ -502,15 +502,16 @@ void blitSrc(VRle::Span *spans, int count, uchar *buffer, int offsetX) } } -size_t bufferToRle(uchar *buffer, int size, int offsetX, int y, VRle::Span *out) +size_t bufferToRle(uint8_t *buffer, int size, int offsetX, int y, + VRle::Span *out) { size_t count = 0; - uchar value = buffer[0]; + uint8_t value = buffer[0]; int curIndex = 0; // size = offsetX < 0 ? size + offsetX : size; for (int i = 0; i < size; i++) { - uchar curValue = buffer[0]; + uint8_t curValue = buffer[0]; if (value != curValue) { if (value) { out->y = y; @@ -550,10 +551,10 @@ struct SpanMerger { break; } } - using blitter = void (*)(VRle::Span *, int, uchar *, int); + using blitter = void (*)(VRle::Span *, int, uint8_t *, int); blitter _blitter; std::array _result; - std::array _buffer; + std::array _buffer; VRle::Span * _aStart{nullptr}; VRle::Span * _bStart{nullptr}; diff --git a/src/vector/vrle.h b/src/vector/vrle.h index 761e5d1b..1bbb8365 100644 --- a/src/vector/vrle.h +++ b/src/vector/vrle.h @@ -36,8 +36,8 @@ class VRle { struct Span { short x{0}; short y{0}; - ushort len{0}; - uchar coverage{0}; + uint16_t len{0}; + uint8_t coverage{0}; }; using VRleSpanCb = void (*)(size_t count, const VRle::Span *spans, void *userData); @@ -52,7 +52,7 @@ class VRle { void reset() { d.write().reset(); } void translate(const VPoint &p) { d.write().translate(p); } - void operator*=(uchar alpha) { d.write() *= alpha; } + void operator*=(uint8_t alpha) { d.write() *= alpha; } void intersect(const VRect &r, VRleSpanCb cb, void *userData) const; void intersect(const VRle &rle, VRleSpanCb cb, void *userData) const; @@ -91,7 +91,7 @@ class VRle { void setBbox(const VRect &bbox) const; void reset(); void translate(const VPoint &p); - void operator*=(uchar alpha); + void operator*=(uint8_t alpha); void opGeneric(const VRle::Data &, const VRle::Data &, Op code); void opSubstract(const VRle::Data &, const VRle::Data &); void opIntersect(VRle::View a, VRle::View b);