diff --git a/inc/thorvg.h b/inc/thorvg.h index fb61db94..552e8a20 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -447,6 +447,53 @@ public: */ MaskMethod mask(const Paint** target) const noexcept; + /** + * @brief Increment the reference count for the Paint instance. + * + * This method increases the reference count of the Paint object, allowing shared ownership and control over its lifetime. + * + * @return The updated reference count after the increment by 1. + * + * @warning Please ensure that each call to ref() is paired with a corresponding call to unref() to prevent a dangling instance. + * + * @see Paint::unref() + * @see Paint::refCnt() + * + * @since 1.0 + */ + uint8_t ref() noexcept; + + /** + * @brief Decrement the reference count for the Paint instance. + * + * This method decreases the reference count of the Paint object by 1. + * If the reference count reaches zero and the @p free flag is set to true, the Paint instance is automatically deleted. + * + * @param[in] free Flag indicating whether to delete the Paint instance when the reference count reaches zero. + * + * @return The updated reference count after the decrement. + * + * @see Paint::ref() + * @see Paint::refCnt() + * + * @since 1.0 + */ + uint8_t unref(bool free = true) noexcept; + + /** + * @brief Retrieve the current reference count of the Paint instance. + * + * This method provides the current reference count, allowing the user to check the shared ownership state of the Paint object. + * + * @return The current reference count of the Paint instance. + * + * @see Paint::ref() + * @see Paint::unref() + * + * @since 1.0 + */ + uint8_t refCnt() const noexcept; + /** * @brief Returns the ID value of this class. * diff --git a/src/loaders/lottie/tvgLottieBuilder.h b/src/loaders/lottie/tvgLottieBuilder.h index cb628e86..17278c22 100644 --- a/src/loaders/lottie/tvgLottieBuilder.h +++ b/src/loaders/lottie/tvgLottieBuilder.h @@ -25,7 +25,6 @@ #include "tvgCommon.h" #include "tvgInlist.h" -#include "tvgPaint.h" #include "tvgShape.h" #include "tvgLottieExpressions.h" #include "tvgLottieModifier.h" @@ -64,13 +63,13 @@ struct RenderContext RenderContext(Shape* propagator) { P(propagator)->reset(); - PP(propagator)->ref(); + propagator->ref(); this->propagator = propagator; } ~RenderContext() { - PP(propagator)->unref(); + propagator->unref(false); free(transform); delete(roundness); delete(offsetPath); @@ -79,7 +78,7 @@ struct RenderContext RenderContext(const RenderContext& rhs, Shape* propagator, bool mergeable = false) { if (mergeable) merging = rhs.merging; - PP(propagator)->ref(); + propagator->ref(); this->propagator = propagator; this->repeaters = rhs.repeaters; if (rhs.roundness) this->roundness = new LottieRoundnessModifier(rhs.roundness->r); diff --git a/src/loaders/lottie/tvgLottieModel.cpp b/src/loaders/lottie/tvgLottieModel.cpp index 54f889c5..4057b746 100644 --- a/src/loaders/lottie/tvgLottieModel.cpp +++ b/src/loaders/lottie/tvgLottieModel.cpp @@ -21,8 +21,6 @@ */ #include "tvgMath.h" -#include "tvgPaint.h" -#include "tvgFill.h" #include "tvgTaskScheduler.h" #include "tvgLottieModel.h" @@ -170,7 +168,7 @@ void LottieImage::prepare() TaskScheduler::async(true); picture->size(data.width, data.height); - PP(picture)->ref(); + picture->ref(); pooler.push(picture); } @@ -472,14 +470,14 @@ void LottieLayer::prepare(RGB24* color) if (type == LottieLayer::Precomp) { auto clipper = Shape::gen(); clipper->appendRect(0.0f, 0.0f, w, h); - PP(clipper)->ref(); + clipper->ref(); statical.pooler.push(clipper); //prepare solid fill in advance if it is a layer type. } else if (color && type == LottieLayer::Solid) { auto solidFill = Shape::gen(); solidFill->appendRect(0, 0, static_cast(w), static_cast(h)); solidFill->fill(color->rgb[0], color->rgb[1], color->rgb[2]); - PP(solidFill)->ref(); + solidFill->ref(); statical.pooler.push(solidFill); } diff --git a/src/loaders/lottie/tvgLottieRenderPooler.h b/src/loaders/lottie/tvgLottieRenderPooler.h index a41a720f..036631e1 100644 --- a/src/loaders/lottie/tvgLottieRenderPooler.h +++ b/src/loaders/lottie/tvgLottieRenderPooler.h @@ -36,7 +36,7 @@ struct LottieRenderPooler ~LottieRenderPooler() { for (auto p = pooler.begin(); p < pooler.end(); ++p) { - if (PP(*p)->unref() == 0) delete(*p); + (*p)->unref(); } } @@ -44,12 +44,12 @@ struct LottieRenderPooler { //return available one. for (auto p = pooler.begin(); p < pooler.end(); ++p) { - if (PP(*p)->refCnt == 1) return *p; + if ((*p)->refCnt() == 1) return *p; } //no empty, generate a new one. auto p = copy ? static_cast(pooler[0]->duplicate()) : T::gen(); - PP(p)->ref(); + p->ref(); pooler.push(p); return p; } diff --git a/src/renderer/tvgAnimation.h b/src/renderer/tvgAnimation.h index ce05d7c2..6eb5d495 100644 --- a/src/renderer/tvgAnimation.h +++ b/src/renderer/tvgAnimation.h @@ -24,7 +24,6 @@ #define _TVG_ANIMATION_H_ #include "tvgCommon.h" -#include "tvgPaint.h" #include "tvgPicture.h" struct Animation::Impl @@ -34,14 +33,12 @@ struct Animation::Impl Impl() { picture = Picture::gen(); - PP(picture)->ref(); + picture->ref(); } ~Impl() { - if (PP(picture)->unref() == 0) { - delete(picture); - } + picture->unref(); } }; diff --git a/src/renderer/tvgCanvas.h b/src/renderer/tvgCanvas.h index 927ea976..b68fa447 100644 --- a/src/renderer/tvgCanvas.h +++ b/src/renderer/tvgCanvas.h @@ -53,7 +53,7 @@ struct Canvas::Impl void clearPaints() { for (auto paint : paints) { - if (P(paint)->unref() == 0) delete(paint); + paint->unref(); } paints.clear(); } @@ -64,7 +64,7 @@ struct Canvas::Impl if (status == Status::Drawing) return Result::InsufficientCondition; if (!paint) return Result::MemoryCorruption; - PP(paint)->ref(); + paint->ref(); paints.push_back(paint); return update(paint, true); @@ -72,16 +72,18 @@ struct Canvas::Impl Result clear(bool paints, bool buffer) { + auto ret = Result::Success; + if (status == Status::Drawing) return Result::InsufficientCondition; //Clear render target - if (buffer) { - if (!renderer->clear()) return Result::InsufficientCondition; + if (buffer && !renderer->clear()) { + ret = Result::InsufficientCondition; } if (paints) clearPaints(); - return Result::Success; + return ret; } Result update(Paint* paint, bool force) diff --git a/src/renderer/tvgPaint.cpp b/src/renderer/tvgPaint.cpp index 84cbc0b1..463930d9 100644 --- a/src/renderer/tvgPaint.cpp +++ b/src/renderer/tvgPaint.cpp @@ -362,7 +362,7 @@ void Paint::Impl::reset() } if (maskData) { - if (P(maskData->target)->unref() == 0) delete(maskData->target); + maskData->target->unref(); free(maskData); maskData = nullptr; } @@ -502,4 +502,34 @@ Result Paint::blend(BlendMethod method) noexcept } return Result::Success; +} + + +uint8_t Paint::ref() noexcept +{ + if (pImpl->refCnt == UINT8_MAX) TVGERR("RENDERER", "Reference Count Overflow!"); + else ++pImpl->refCnt; + + return pImpl->refCnt; +} + + +uint8_t Paint::unref(bool free) noexcept +{ + if (pImpl->refCnt > 0) --pImpl->refCnt; + else TVGERR("RENDERER", "Corrupted Reference Count!"); + + if (free && pImpl->refCnt == 0) { + //TODO: use the global dismiss function? + delete(this); + return 0; + } + + return pImpl->refCnt; +} + + +uint8_t Paint::refCnt() const noexcept +{ + return pImpl->refCnt; } \ No newline at end of file diff --git a/src/renderer/tvgPaint.h b/src/renderer/tvgPaint.h index 95124fb9..221e3dad 100644 --- a/src/renderer/tvgPaint.h +++ b/src/renderer/tvgPaint.h @@ -76,7 +76,7 @@ namespace tvg uint8_t renderFlag; uint8_t ctxFlag; uint8_t opacity; - uint8_t refCnt = 0; //reference count + uint8_t refCnt = 0; //reference count Impl(Paint* pnt) : paint(pnt) { @@ -86,25 +86,13 @@ namespace tvg ~Impl() { if (maskData) { - if (P(maskData->target)->unref() == 0) delete(maskData->target); + maskData->target->unref(); free(maskData); } - if (clipper && P(clipper)->unref() == 0) delete(clipper); + if (clipper) clipper->unref(); if (renderer && (renderer->unref() == 0)) delete(renderer); } - uint8_t ref() - { - if (refCnt == 255) TVGERR("RENDERER", "Corrupted reference count!"); - return ++refCnt; - } - - uint8_t unref() - { - if (refCnt == 0) TVGERR("RENDERER", "Corrupted reference count!"); - return --refCnt; - } - bool transform(const Matrix& m) { if (&tr.m != &m) tr.m = m; @@ -124,16 +112,11 @@ namespace tvg void clip(Paint* clp) { - if (this->clipper) { - P(this->clipper)->unref(); - if (this->clipper != clp && P(this->clipper)->refCnt == 0) { - delete(this->clipper); - } - } - this->clipper = clp; + if (clipper) clipper->unref(clipper != clp); + clipper = clp; if (!clp) return; - P(clipper)->ref(); + clipper->ref(); } bool mask(Paint* source, Paint* target, MaskMethod method) @@ -142,10 +125,7 @@ namespace tvg if ((!target && method != MaskMethod::None) || (target && method == MaskMethod::None)) return false; if (maskData) { - P(maskData->target)->unref(); - if ((maskData->target != target) && P(maskData->target)->refCnt == 0) { - delete(maskData->target); - } + maskData->target->unref(maskData->target != target); //Reset scenario if (!target && method == MaskMethod::None) { free(maskData); @@ -156,7 +136,7 @@ namespace tvg if (!target && method == MaskMethod::None) return true; maskData = static_cast(malloc(sizeof(Mask))); } - P(target)->ref(); + target->ref(); maskData->target = target; maskData->source = source; maskData->method = method; diff --git a/src/renderer/tvgSaver.cpp b/src/renderer/tvgSaver.cpp index 75975db0..5100c75f 100644 --- a/src/renderer/tvgSaver.cpp +++ b/src/renderer/tvgSaver.cpp @@ -23,7 +23,6 @@ #include "tvgCommon.h" #include "tvgStr.h" #include "tvgSaveModule.h" -#include "tvgPaint.h" #ifdef THORVG_GIF_SAVER_SUPPORT #include "tvgGifSaver.h" @@ -107,7 +106,7 @@ Result Saver::save(Paint* paint, const char* filename, uint32_t quality) noexcep //Already on saving another resource. if (pImpl->saveModule) { - if (P(paint)->refCnt == 0) delete(paint); + if (paint->refCnt() == 0) delete(paint); return Result::InsufficientCondition; } @@ -116,12 +115,12 @@ Result Saver::save(Paint* paint, const char* filename, uint32_t quality) noexcep pImpl->saveModule = saveModule; return Result::Success; } else { - if (P(paint)->refCnt == 0) delete(paint); + if (paint->refCnt() == 0) delete(paint); delete(saveModule); return Result::Unknown; } } - if (P(paint)->refCnt == 0) delete(paint); + if (paint->refCnt() == 0) delete(paint); return Result::NonSupport; } @@ -140,7 +139,7 @@ Result Saver::save(Animation* animation, const char* filename, uint32_t quality, if (!animation) return Result::MemoryCorruption; //animation holds the picture, it must be 1 at the bottom. - auto remove = PP(animation->picture())->refCnt <= 1 ? true : false; + auto remove = animation->picture()->refCnt() <= 1 ? true : false; if (tvg::zero(animation->totalFrame())) { if (remove) delete(animation); diff --git a/src/renderer/tvgScene.cpp b/src/renderer/tvgScene.cpp index e363bb88..3bd7b3d2 100644 --- a/src/renderer/tvgScene.cpp +++ b/src/renderer/tvgScene.cpp @@ -70,7 +70,7 @@ Type Scene::type() const noexcept Result Scene::push(Paint* paint) noexcept { if (!paint) return Result::MemoryCorruption; - PP(paint)->ref(); + paint->ref(); pImpl->paints.push_back(paint); return Result::Success; diff --git a/src/renderer/tvgScene.h b/src/renderer/tvgScene.h index df0077b5..371c807c 100644 --- a/src/renderer/tvgScene.h +++ b/src/renderer/tvgScene.h @@ -74,7 +74,7 @@ struct Scene::Impl resetEffects(); for (auto paint : paints) { - if (P(paint)->unref() == 0) delete(paint); + paint->unref(); } if (auto renderer = PP(scene)->renderer) { @@ -230,7 +230,7 @@ struct Scene::Impl for (auto paint : paints) { auto cdup = paint->duplicate(); - P(cdup)->ref(); + cdup->ref(); dup->paints.push_back(cdup); } @@ -242,7 +242,7 @@ struct Scene::Impl void clear(bool free) { for (auto paint : paints) { - if (P(paint)->unref() == 0 && free) delete(paint); + paint->unref(free); } paints.clear(); } diff --git a/src/savers/gif/tvgGifSaver.cpp b/src/savers/gif/tvgGifSaver.cpp index 1befdfad..4f01b447 100644 --- a/src/savers/gif/tvgGifSaver.cpp +++ b/src/savers/gif/tvgGifSaver.cpp @@ -100,7 +100,7 @@ bool GifSaver::close() bg = nullptr; //animation holds the picture, it must be 1 at the bottom. - if (animation && PP(animation->picture())->refCnt <= 1) delete(animation); + if (animation && animation->picture()->refCnt() <= 1) delete(animation); animation = nullptr; free(path);