Explorar o código

ThorVG: update from v0.12.3 to v0.12.4

https://github.com/thorvg/thorvg/releases/tag/v0.12.4

+ Full Changelog:
  https://github.com/thorvg/thorvg/compare/v0.12.3...v0.12.4

Godot-related SVG bug fixes:

+ loader/svg: Apply specification of out-of-range elliptical arc parameters,
  fix zero check of arc's rx and ry.
    thorvg/thorvg#1938

(cherry picked from commit da42124efe4f04fbb2749a255af09118b5be6156)
Martin Capitanio hai 1 ano
pai
achega
5970616be2

+ 1 - 1
thirdparty/README.md

@@ -825,7 +825,7 @@ instead of `miniz.h` as an external dependency.
 ## thorvg
 
 - Upstream: https://github.com/thorvg/thorvg
-- Version: 0.12.3 (9d79f0ccef632fd3b43b8ea02def529b6a8d2288, 2024)
+- Version: 0.12.4 (331839d49368e19ca15f35abee5ac541dbf23637, 2024)
 - License: MIT
 
 Files extracted from upstream source:

+ 1 - 1
thirdparty/thorvg/inc/config.h

@@ -10,5 +10,5 @@
 // For internal debugging:
 //#define THORVG_LOG_ENABLED
 
-#define THORVG_VERSION_STRING "0.12.3"
+#define THORVG_VERSION_STRING "0.12.4"
 #endif

+ 11 - 4
thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp

@@ -51,8 +51,8 @@
 #define _USE_MATH_DEFINES       //Math Constants are not defined in Standard C/C++.
 
 #include <cstring>
-#include <math.h>
 #include <ctype.h>
+#include "tvgMath.h"
 #include "tvgShape.h"
 #include "tvgSvgLoaderCommon.h"
 #include "tvgSvgPath.h"
@@ -471,9 +471,16 @@ static bool _processCommand(Array<PathCommand>* cmds, Array<Point>* pts, char cm
         }
         case 'a':
         case 'A': {
-            _pathAppendArcTo(cmds, pts, cur, curCtl, arr[5], arr[6], arr[0], arr[1], arr[2], arr[3], arr[4]);
-            *cur = *curCtl = {arr[5], arr[6]};
-            *isQuadratic = false;
+            if (mathZero(arr[0]) || mathZero(arr[1])) {
+                Point p = {arr[5], arr[6]};
+                cmds->push(PathCommand::LineTo);
+                pts->push(p);
+                *cur = {arr[5], arr[6]};
+            } else if (!mathEqual(cur->x, arr[5]) || !mathEqual(cur->y, arr[6])) {
+                _pathAppendArcTo(cmds, pts, cur, curCtl, arr[5], arr[6], fabsf(arr[0]), fabsf(arr[1]), arr[2], arr[3], arr[4]);
+                *cur = *curCtl = {arr[5], arr[6]};
+                *isQuadratic = false;
+            }
             break;
         }
         default: {

+ 6 - 11
thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp

@@ -63,7 +63,7 @@ struct SwTask : Task
         return region;
     }
 
-    virtual bool dispose() = 0;
+    virtual void dispose() = 0;
     virtual bool clip(SwRleData* target) = 0;
     virtual SwRleData* rle() = 0;
 
@@ -196,10 +196,9 @@ struct SwShapeTask : SwTask
         shapeDelOutline(&shape, mpool, tid);
     }
 
-    bool dispose() override
+    void dispose() override
     {
        shapeFree(&shape);
-       return true;
     }
 };
 
@@ -250,10 +249,9 @@ struct SwSceneTask : SwTask
         }
     }
 
-    bool dispose() override
+    void dispose() override
     {
         rleFree(sceneRle);
-        return true;
     }
 };
 
@@ -318,10 +316,9 @@ struct SwImageTask : SwTask
         imageDelOutline(&image, mpool, tid);
     }
 
-    bool dispose() override
+    void dispose() override
     {
        imageFree(&image);
-       return true;
     }
 };
 
@@ -703,17 +700,15 @@ ColorSpace SwRenderer::colorSpace()
 }
 
 
-bool SwRenderer::dispose(RenderData data)
+void SwRenderer::dispose(RenderData data)
 {
     auto task = static_cast<SwTask*>(data);
-    if (!task) return true;
+    if (!task) return;
     task->done();
     task->dispose();
 
     if (task->pushed) task->disposed = true;
     else delete(task);
-
-    return true;
 }
 
 

+ 1 - 1
thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h

@@ -43,7 +43,7 @@ public:
     bool renderShape(RenderData data) override;
     bool renderImage(RenderData data) override;
     bool postRender() override;
-    bool dispose(RenderData data) override;
+    void dispose(RenderData data) override;
     RenderRegion region(RenderData data) override;
     RenderRegion viewport() override;
     bool viewport(const RenderRegion& vp) override;

+ 6 - 2
thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp

@@ -122,7 +122,9 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* trans
     Line cur = {dash.ptCur, *to};
     auto len = _lineLength(cur.pt1, cur.pt2);
 
-    if (len < dash.curLen) {
+    if (mathZero(len)) {
+        _outlineMoveTo(*dash.outline, &dash.ptCur, transform);
+    } else if (len < dash.curLen) {
         dash.curLen -= len;
         if (!dash.curOpGap) {
             if (dash.move) {
@@ -179,7 +181,9 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
     Bezier cur = {dash.ptCur, *ctrl1, *ctrl2, *to};
     auto len = bezLength(cur);
 
-    if (len < dash.curLen) {
+    if (mathZero(len)) {
+        _outlineMoveTo(*dash.outline, &dash.ptCur, transform);
+    } else if (len < dash.curLen) {
         dash.curLen -= len;
         if (!dash.curOpGap) {
             if (dash.move) {

+ 24 - 15
thirdparty/thorvg/src/renderer/tvgCanvas.h

@@ -33,14 +33,30 @@ struct Canvas::Impl
     bool refresh = false;   //if all paints should be updated by force.
     bool drawing = false;   //on drawing condition?
 
-    Impl(RenderMethod* pRenderer):renderer(pRenderer)
+    Impl(RenderMethod* pRenderer) : renderer(pRenderer)
     {
+        renderer->ref();
     }
 
     ~Impl()
     {
-        clear(true);
-        delete(renderer);
+        //make it sure any deffered jobs
+        if (renderer) {
+            renderer->sync();
+            renderer->clear();
+        }
+
+        clearPaints();
+
+        if (renderer && (renderer->unref() == 0)) delete(renderer);
+    }
+
+    void clearPaints()
+    {
+        for (auto paint : paints) {
+            if (P(paint)->unref() == 0) delete(paint);
+        }
+        paints.clear();
     }
 
     Result push(unique_ptr<Paint> paint)
@@ -62,15 +78,8 @@ struct Canvas::Impl
         if (!renderer || !renderer->clear()) return Result::InsufficientCondition;
 
         //Free paints
-        if (free) {
-            for (auto paint : paints) {
-                P(paint)->unref();
-                if (paint->pImpl->dispose(*renderer) && P(paint)->refCnt == 0) {
-                    delete(paint);
-                }
-            }
-            paints.clear();
-        }
+        if (free) clearPaints();
+
         drawing = false;
 
         return Result::Success;
@@ -94,7 +103,7 @@ struct Canvas::Impl
             //Optimize Me: Can we skip the searching?
             for (auto paint2 : paints) {
                 if (paint2 == paint) {
-                    paint->pImpl->update(*renderer, nullptr, clips, 255, flag);
+                    paint->pImpl->update(renderer, nullptr, clips, 255, flag);
                     return Result::Success;
                 }
             }
@@ -102,7 +111,7 @@ struct Canvas::Impl
         //Update all retained paint nodes
         } else {
             for (auto paint : paints) {
-                paint->pImpl->update(*renderer, nullptr, clips, 255, flag);
+                paint->pImpl->update(renderer, nullptr, clips, 255, flag);
             }
         }
 
@@ -117,7 +126,7 @@ struct Canvas::Impl
 
         bool rendered = false;
         for (auto paint : paints) {
-            if (paint->pImpl->render(*renderer)) rendered = true;
+            if (paint->pImpl->render(renderer)) rendered = true;
         }
 
         if (!rendered || !renderer->postRender()) return Result::InsufficientCondition;

+ 17 - 21
thirdparty/thorvg/src/renderer/tvgPaint.cpp

@@ -106,7 +106,7 @@ static bool _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform,
 }
 
 
-RenderRegion Paint::Impl::bounds(RenderMethod& renderer) const
+RenderRegion Paint::Impl::bounds(RenderMethod* renderer) const
 {
     RenderRegion ret;
     PAINT_METHOD(ret, bounds(renderer));
@@ -114,16 +114,6 @@ RenderRegion Paint::Impl::bounds(RenderMethod& renderer) const
 }
 
 
-bool Paint::Impl::dispose(RenderMethod& renderer)
-{
-    if (compData) compData->target->pImpl->dispose(renderer);
-
-    bool ret;
-    PAINT_METHOD(ret, dispose(renderer));
-    return ret;
-}
-
-
 Iterator* Paint::Impl::iterator()
 {
     Iterator* ret;
@@ -198,7 +188,7 @@ bool Paint::Impl::translate(float x, float y)
 }
 
 
-bool Paint::Impl::render(RenderMethod& renderer)
+bool Paint::Impl::render(RenderMethod* renderer)
 {
     Compositor* cmp = nullptr;
 
@@ -210,27 +200,33 @@ bool Paint::Impl::render(RenderMethod& renderer)
 
         if (MASK_REGION_MERGING(compData->method)) region.add(P(compData->target)->bounds(renderer));
         if (region.w == 0 || region.h == 0) return true;
-        cmp = renderer.target(region, COMPOSITE_TO_COLORSPACE(renderer, compData->method));
-        if (renderer.beginComposite(cmp, CompositeMethod::None, 255)) {
+        cmp = renderer->target(region, COMPOSITE_TO_COLORSPACE(renderer, compData->method));
+        if (renderer->beginComposite(cmp, CompositeMethod::None, 255)) {
             compData->target->pImpl->render(renderer);
         }
     }
 
-    if (cmp) renderer.beginComposite(cmp, compData->method, compData->target->pImpl->opacity);
+    if (cmp) renderer->beginComposite(cmp, compData->method, compData->target->pImpl->opacity);
 
-    renderer.blend(blendMethod);
+    renderer->blend(blendMethod);
 
     bool ret;
     PAINT_METHOD(ret, render(renderer));
 
-    if (cmp) renderer.endComposite(cmp);
+    if (cmp) renderer->endComposite(cmp);
 
     return ret;
 }
 
 
-RenderData Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
+RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pTransform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
 {
+    if (this->renderer != renderer) {
+        if (this->renderer) TVGERR("RENDERER", "paint's renderer has been changed!");
+        renderer->ref();
+        this->renderer = renderer;
+    }
+
     if (renderFlag & RenderUpdateFlag::Transform) {
         if (!rTransform) return nullptr;
         rTransform->update();
@@ -265,9 +261,9 @@ RenderData Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pT
             if (tryFastTrack) {
                 RenderRegion viewport2;
                 if ((compFastTrack = _compFastTrack(target, pTransform, target->pImpl->rTransform, viewport2))) {
-                    viewport = renderer.viewport();
+                    viewport = renderer->viewport();
                     viewport2.intersect(viewport);
-                    renderer.viewport(viewport2);
+                    renderer->viewport(viewport2);
                     target->pImpl->ctxFlag |= ContextFlag::FastTrack;
                 }
             }
@@ -289,7 +285,7 @@ RenderData Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pT
     PAINT_METHOD(rd, update(renderer, &outTransform, clips, opacity, newFlag, clipper));
 
     /* 3. Composition Post Processing */
-    if (compFastTrack) renderer.viewport(viewport);
+    if (compFastTrack) renderer->viewport(viewport);
     else if (childClipper) clips.pop();
 
     return rd;

+ 10 - 11
thirdparty/thorvg/src/renderer/tvgPaint.h

@@ -50,16 +50,15 @@ namespace tvg
         Paint* paint = nullptr;
         RenderTransform* rTransform = nullptr;
         Composite* compData = nullptr;
-        BlendMethod blendMethod = BlendMethod::Normal;              //uint8_t
+        RenderMethod* renderer = nullptr;
+        BlendMethod blendMethod = BlendMethod::Normal;   //uint8_t
         uint8_t renderFlag = RenderUpdateFlag::None;
         uint8_t ctxFlag = ContextFlag::Invalid;
         uint8_t id;
         uint8_t opacity = 255;
-        uint8_t refCnt = 0;
+        uint8_t refCnt = 0;                              //reference count
 
-        Impl(Paint* pnt) : paint(pnt)
-        {
-        }
+        Impl(Paint* pnt) : paint(pnt) {}
 
         ~Impl()
         {
@@ -68,18 +67,19 @@ namespace tvg
                 free(compData);
             }
             delete(rTransform);
+            if (renderer && (renderer->unref() == 0)) delete(renderer);
         }
 
         uint8_t ref()
         {
             if (refCnt == 255) TVGERR("RENDERER", "Corrupted reference count!");
-            return (++refCnt);
+            return ++refCnt;
         }
 
         uint8_t unref()
         {
             if (refCnt == 0) TVGERR("RENDERER", "Corrupted reference count!");
-            return (--refCnt);
+            return --refCnt;
         }
 
         bool transform(const Matrix& m)
@@ -131,15 +131,14 @@ namespace tvg
             return true;
         }
 
-        RenderRegion bounds(RenderMethod& renderer) const;
-        bool dispose(RenderMethod& renderer);
+        RenderRegion bounds(RenderMethod* renderer) const;
         Iterator* iterator();
         bool rotate(float degree);
         bool scale(float factor);
         bool translate(float x, float y);
         bool bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking);
-        RenderData update(RenderMethod& renderer, const RenderTransform* pTransform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper = false);
-        bool render(RenderMethod& renderer);
+        RenderData update(RenderMethod* renderer, const RenderTransform* pTransform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper = false);
+        bool render(RenderMethod* renderer);
         Paint* duplicate();
     };
 }

+ 7 - 7
thirdparty/thorvg/src/renderer/tvgPicture.cpp

@@ -69,18 +69,18 @@ bool Picture::Impl::needComposition(uint8_t opacity)
 }
 
 
-bool Picture::Impl::render(RenderMethod &renderer)
+bool Picture::Impl::render(RenderMethod* renderer)
 {
     bool ret = false;
-    if (surface) return renderer.renderImage(rd);
+    if (surface) return renderer->renderImage(rd);
     else if (paint) {
         Compositor* cmp = nullptr;
         if (needComp) {
-            cmp = renderer.target(bounds(renderer), renderer.colorSpace());
-            renderer.beginComposite(cmp, CompositeMethod::None, 255);
+            cmp = renderer->target(bounds(renderer), renderer->colorSpace());
+            renderer->beginComposite(cmp, CompositeMethod::None, 255);
         }
         ret = paint->pImpl->render(renderer);
-        if (cmp) renderer.endComposite(cmp);
+        if (cmp) renderer->endComposite(cmp);
     }
     return ret;
 }
@@ -95,9 +95,9 @@ bool Picture::Impl::size(float w, float h)
 }
 
 
-RenderRegion Picture::Impl::bounds(RenderMethod& renderer)
+RenderRegion Picture::Impl::bounds(RenderMethod* renderer)
 {
-    if (rd) return renderer.region(rd);
+    if (rd) return renderer->region(rd);
     if (paint) return paint->pImpl->bounds(renderer);
     return {0, 0, 0, 0};
 }

+ 9 - 12
thirdparty/thorvg/src/renderer/tvgPicture.h

@@ -70,9 +70,9 @@ struct Picture::Impl
 
     RenderTransform resizeTransform(const RenderTransform* pTransform);
     bool needComposition(uint8_t opacity);
-    bool render(RenderMethod &renderer);
+    bool render(RenderMethod* renderer);
     bool size(float w, float h);
-    RenderRegion bounds(RenderMethod& renderer);
+    RenderRegion bounds(RenderMethod* renderer);
     Result load(ImageLoader* ploader);
 
     Impl(Picture* p) : picture(p)
@@ -82,24 +82,21 @@ struct Picture::Impl
     ~Impl()
     {
         LoaderMgr::retrieve(loader);
+        if (surface) {
+            if (auto renderer = PP(picture)->renderer) {
+                renderer->dispose(rd);
+            }
+        }
         delete(paint);
     }
 
-    bool dispose(RenderMethod& renderer)
-    {
-        if (paint) paint->pImpl->dispose(renderer);
-        else if (surface) renderer.dispose(rd);
-        rd = nullptr;
-        return true;
-    }
-
-    RenderData update(RenderMethod &renderer, const RenderTransform* pTransform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
+    RenderData update(RenderMethod* renderer, const RenderTransform* pTransform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
     {
         auto flag = load();
 
         if (surface) {
             auto transform = resizeTransform(pTransform);
-            rd = renderer.prepare(surface, &rm, rd, &transform, clips, opacity, static_cast<RenderUpdateFlag>(pFlag | flag));
+            rd = renderer->prepare(surface, &rm, rd, &transform, clips, opacity, static_cast<RenderUpdateFlag>(pFlag | flag));
         } else if (paint) {
             if (resizing) {
                 loader->resize(paint, w, h);

+ 19 - 3
thirdparty/thorvg/src/renderer/tvgRender.h

@@ -261,7 +261,23 @@ struct RenderShape
 
 class RenderMethod
 {
+private:
+    uint32_t refCnt = 0;        //reference count
+    Key key;
+
 public:
+    uint32_t ref()
+    {
+        ScopedLock lock(key);
+        return (++refCnt);
+    }
+
+    uint32_t unref()
+    {
+        ScopedLock lock(key);
+        return (--refCnt);
+    }
+
     virtual ~RenderMethod() {}
     virtual RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) = 0;
     virtual RenderData prepare(const Array<RenderData>& scene, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags) = 0;
@@ -270,7 +286,7 @@ public:
     virtual bool renderShape(RenderData data) = 0;
     virtual bool renderImage(RenderData data) = 0;
     virtual bool postRender() = 0;
-    virtual bool dispose(RenderData data) = 0;
+    virtual void dispose(RenderData data) = 0;
     virtual RenderRegion region(RenderData data) = 0;
     virtual RenderRegion viewport() = 0;
     virtual bool viewport(const RenderRegion& vp) = 0;
@@ -322,7 +338,7 @@ static inline uint8_t CHANNEL_SIZE(ColorSpace cs)
     }
 }
 
-static inline ColorSpace COMPOSITE_TO_COLORSPACE(RenderMethod& renderer, CompositeMethod method)
+static inline ColorSpace COMPOSITE_TO_COLORSPACE(RenderMethod* renderer, CompositeMethod method)
 {
     switch(method) {
         case CompositeMethod::AlphaMask:
@@ -335,7 +351,7 @@ static inline ColorSpace COMPOSITE_TO_COLORSPACE(RenderMethod& renderer, Composi
         //TODO: Optimize Luma/InvLuma colorspace to Grayscale8
         case CompositeMethod::LumaMask:
         case CompositeMethod::InvLumaMask:
-            return renderer.colorSpace();
+            return renderer->colorSpace();
         default:
             TVGERR("RENDERER", "Unsupported Composite Size! = %d", (int)method);
             return ColorSpace::Unsupported;

+ 9 - 25
thirdparty/thorvg/src/renderer/tvgScene.h

@@ -59,7 +59,6 @@ struct SceneIterator : Iterator
 struct Scene::Impl
 {
     list<Paint*> paints;
-    RenderMethod* renderer = nullptr;    //keep it for explicit clear
     RenderData rd = nullptr;
     Scene* scene = nullptr;
     uint8_t opacity;                     //for composition
@@ -74,19 +73,10 @@ struct Scene::Impl
         for (auto paint : paints) {
             if (P(paint)->unref() == 0) delete(paint);
         }
-    }
 
-    bool dispose(RenderMethod& renderer)
-    {
-        for (auto paint : paints) {
-            paint->pImpl->dispose(renderer);
+        if (auto renderer = PP(scene)->renderer) {
+            renderer->dispose(rd);
         }
-
-        renderer.dispose(rd);
-        this->renderer = nullptr;
-        this->rd = nullptr;
-
-        return true;
     }
 
     bool needComposition(uint8_t opacity)
@@ -111,7 +101,7 @@ struct Scene::Impl
         return true;
     }
 
-    RenderData update(RenderMethod &renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flag, bool clipper)
+    RenderData update(RenderMethod* renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flag, bool clipper)
     {
         if ((needComp = needComposition(opacity))) {
             /* Overriding opacity value. If this scene is half-translucent,
@@ -120,14 +110,12 @@ struct Scene::Impl
             opacity = 255;
         }
 
-        this->renderer = &renderer;
-
         if (clipper) {
             Array<RenderData> rds(paints.size());
             for (auto paint : paints) {
                 rds.push(paint->pImpl->update(renderer, transform, clips, opacity, flag, true));
             }
-            rd = renderer.prepare(rds, rd, transform, clips, opacity, flag);
+            rd = renderer->prepare(rds, rd, transform, clips, opacity, flag);
             return rd;
         } else {
             for (auto paint : paints) {
@@ -137,13 +125,13 @@ struct Scene::Impl
         }
     }
 
-    bool render(RenderMethod& renderer)
+    bool render(RenderMethod* renderer)
     {
         Compositor* cmp = nullptr;
 
         if (needComp) {
-            cmp = renderer.target(bounds(renderer), renderer.colorSpace());
-            renderer.beginComposite(cmp, CompositeMethod::None, opacity);
+            cmp = renderer->target(bounds(renderer), renderer->colorSpace());
+            renderer->beginComposite(cmp, CompositeMethod::None, opacity);
             needComp = false;
         }
 
@@ -151,12 +139,12 @@ struct Scene::Impl
             if (!paint->pImpl->render(renderer)) return false;
         }
 
-        if (cmp) renderer.endComposite(cmp);
+        if (cmp) renderer->endComposite(cmp);
 
         return true;
     }
 
-    RenderRegion bounds(RenderMethod& renderer) const
+    RenderRegion bounds(RenderMethod* renderer) const
     {
         if (paints.empty()) return {0, 0, 0, 0};
 
@@ -226,14 +214,10 @@ struct Scene::Impl
 
     void clear(bool free)
     {
-        auto dispose = renderer ? true : false;
-
         for (auto paint : paints) {
-            if (dispose) free &= P(paint)->dispose(*renderer);
             if (P(paint)->unref() == 0 && free) delete(paint);
         }
         paints.clear();
-        renderer = nullptr;
     }
 
     Iterator* iterator()

+ 13 - 13
thirdparty/thorvg/src/renderer/tvgShape.h

@@ -41,25 +41,25 @@ struct Shape::Impl
     {
     }
 
-    bool dispose(RenderMethod& renderer)
+    ~Impl()
     {
-        renderer.dispose(rd);
-        rd = nullptr;
-        return true;
+        if (auto renderer = PP(shape)->renderer) {
+            renderer->dispose(rd);
+        }
     }
 
-    bool render(RenderMethod& renderer)
+    bool render(RenderMethod* renderer)
     {
         Compositor* cmp = nullptr;
         bool ret;
 
         if (needComp) {
-            cmp = renderer.target(bounds(renderer), renderer.colorSpace());
-            renderer.beginComposite(cmp, CompositeMethod::None, opacity);
+            cmp = renderer->target(bounds(renderer), renderer->colorSpace());
+            renderer->beginComposite(cmp, CompositeMethod::None, opacity);
             needComp = false;
         }
-        ret = renderer.renderShape(rd);
-        if (cmp) renderer.endComposite(cmp);
+        ret = renderer->renderShape(rd);
+        if (cmp) renderer->endComposite(cmp);
         return ret;
     }
 
@@ -83,7 +83,7 @@ struct Shape::Impl
         return true;
     }
 
-    RenderData update(RenderMethod& renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
+    RenderData update(RenderMethod* renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
     {     
         if ((needComp = needComposition(opacity))) {
             /* Overriding opacity value. If this scene is half-translucent,
@@ -92,14 +92,14 @@ struct Shape::Impl
             opacity = 255;
         }
 
-        rd = renderer.prepare(rs, rd, transform, clips, opacity, static_cast<RenderUpdateFlag>(pFlag | flag), clipper);
+        rd = renderer->prepare(rs, rd, transform, clips, opacity, static_cast<RenderUpdateFlag>(pFlag | flag), clipper);
         flag = RenderUpdateFlag::None;
         return rd;
     }
 
-    RenderRegion bounds(RenderMethod& renderer)
+    RenderRegion bounds(RenderMethod* renderer)
     {
-        return renderer.region(rd);
+        return renderer->region(rd);
     }
 
     bool bounds(float* x, float* y, float* w, float* h, bool stroking)

+ 6 - 14
thirdparty/thorvg/src/renderer/tvgText.h

@@ -35,7 +35,6 @@
 
 struct Text::Impl
 {
-    RenderData rd = nullptr;
     FontLoader* loader = nullptr;
     Shape* paint = nullptr;
     char* utf8 = nullptr;
@@ -92,12 +91,13 @@ struct Text::Impl
         return Result::Success;
     }
 
-    RenderRegion bounds(RenderMethod& renderer)
+    RenderRegion bounds(RenderMethod* renderer)
     {
-        return renderer.region(rd);
+        if (paint) return P(paint)->bounds(renderer);
+        else return {0, 0, 0, 0};
     }
 
-    bool render(RenderMethod& renderer)
+    bool render(RenderMethod* renderer)
     {
         if (paint) return PP(paint)->render(renderer);
         return false;
@@ -120,7 +120,7 @@ struct Text::Impl
         return false;
     }
 
-    RenderData update(RenderMethod& renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
+    RenderData update(RenderMethod* renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
     {
         if (!load()) return nullptr;
 
@@ -142,8 +142,7 @@ struct Text::Impl
                 P(static_cast<RadialGradient*>(fill))->fr *= scale;
             }
         }
-        rd = PP(paint)->update(renderer, transform, clips, opacity, pFlag, clipper);
-        return rd;
+        return PP(paint)->update(renderer, transform, clips, opacity, pFlag, clipper);
     }
 
     bool bounds(float* x, float* y, float* w, float* h, TVG_UNUSED bool stroking)
@@ -153,13 +152,6 @@ struct Text::Impl
         return true;
     }
 
-    bool dispose(RenderMethod& renderer)
-    {
-        renderer.dispose(rd);
-        this->rd = nullptr;
-        return true;
-    }
-
     Paint* duplicate()
     {
         load();

+ 1 - 1
thirdparty/thorvg/update-thorvg.sh

@@ -1,6 +1,6 @@
 #!/bin/bash -e
 
-VERSION=0.12.3
+VERSION=0.12.4
 
 cd thirdparty/thorvg/ || true
 rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/