Browse Source

ThorVG: Update to 0.14.2

+ Fixes SVG: Graphical objects stored in <defs> shouldn't be rendered directly.
Martin Capitanio 1 year ago
parent
commit
bf444545be

+ 1 - 1
thirdparty/README.md

@@ -882,7 +882,7 @@ instead of `miniz.h` as an external dependency.
 ## thorvg
 
 - Upstream: https://github.com/thorvg/thorvg
-- Version: 0.14.1 (70b2f2dad158316dd08166d613b425248b36fd27, 2024)
+- Version: 0.14.2 (f6c4d8a94e0b2194fe911d6e19a550683055dd50, 2024)
 - License: MIT
 
 Files extracted from upstream source:

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

@@ -15,5 +15,5 @@
 // For internal debugging:
 //#define THORVG_LOG_ENABLED
 
-#define THORVG_VERSION_STRING "0.14.1"
+#define THORVG_VERSION_STRING "0.14.2"
 #endif

+ 9 - 0
thirdparty/thorvg/inc/thorvg.h

@@ -281,6 +281,9 @@ public:
      * The rotational axis passes through the point on the object with zero coordinates.
      *
      * @param[in] degree The value of the angle in degrees.
+     *
+     * @retval Result::InsufficientCondition in case a custom transform is applied.
+     * @see Paint::transform()
      */
     Result rotate(float degree) noexcept;
 
@@ -288,6 +291,9 @@ public:
      * @brief Sets the scale value of the object.
      *
      * @param[in] factor The value of the scaling factor. The default value is 1.
+     *
+     * @retval Result::InsufficientCondition in case a custom transform is applied.
+     * @see Paint::transform()
      */
     Result scale(float factor) noexcept;
 
@@ -299,6 +305,9 @@ public:
      *
      * @param[in] x The value of the horizontal shift.
      * @param[in] y The value of the vertical shift.
+     *
+     * @retval Result::InsufficientCondition in case a custom transform is applied.
+     * @see Paint::transform()
      */
     Result translate(float x, float y) noexcept;
 

+ 1 - 1
thirdparty/thorvg/src/common/tvgLines.cpp

@@ -238,7 +238,7 @@ float bezAngleAt(const Bezier& bz, float t)
     pt.x *= 3;
     pt.y *= 3;
 
-    return mathRad2Deg(atan2(pt.x, pt.y));
+    return mathRad2Deg(mathAtan2(pt.y, pt.x));
 }
 
 

+ 8 - 3
thirdparty/thorvg/src/common/tvgLock.h

@@ -28,6 +28,7 @@
 #define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR
 
 #include <mutex>
+#include "tvgTaskScheduler.h"
 
 namespace tvg {
 
@@ -42,13 +43,17 @@ namespace tvg {
 
         ScopedLock(Key& k)
         {
-            k.mtx.lock();
-            key = &k;
+            if (TaskScheduler::threads() > 0) {
+                k.mtx.lock();
+                key = &k;
+            }
         }
 
         ~ScopedLock()
         {
-            key->mtx.unlock();
+            if (TaskScheduler::threads() > 0) {
+                key->mtx.unlock();
+            }
         }
     };
 

+ 14 - 0
thirdparty/thorvg/src/common/tvgMath.cpp

@@ -22,6 +22,20 @@
 
 #include "tvgMath.h"
 
+//see: https://en.wikipedia.org/wiki/Remez_algorithm
+float mathAtan2(float y, float x)
+{
+    if (y == 0.0f && x == 0.0f) return 0.0f;
+
+    auto a = std::min(fabsf(x), fabsf(y)) / std::max(fabsf(x), fabsf(y));
+    auto s = a * a;
+    auto r = ((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a;
+    if (fabsf(y) > fabsf(x)) r = 1.57079637f - r;
+    if (x < 0) r = 3.14159274f - r;
+    if (y < 0) return -r;
+    return r;
+}
+
 
 bool mathInverse(const Matrix* m, Matrix* out)
 {

+ 2 - 1
thirdparty/thorvg/src/common/tvgMath.h

@@ -42,6 +42,7 @@
 /* General functions                                                    */
 /************************************************************************/
 
+float mathAtan2(float y, float x);
 
 static inline float mathDeg2Rad(float degree)
 {
@@ -79,7 +80,7 @@ bool operator==(const Matrix& lhs, const Matrix& rhs);
 
 static inline bool mathRightAngle(const Matrix* m)
 {
-   auto radian = fabsf(atan2f(m->e21, m->e11));
+   auto radian = fabsf(mathAtan2(m->e21, m->e11));
    if (radian < FLOAT_EPSILON || mathEqual(radian, MATH_PI2) || mathEqual(radian, MATH_PI)) return true;
    return false;
 }

+ 22 - 7
thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp

@@ -647,9 +647,9 @@ static bool _hslToRgb(float hue, float saturation, float brightness, uint8_t* re
         }
     }
 
-    *red = static_cast<uint8_t>(ceil(_red * 255.0f));
-    *green = static_cast<uint8_t>(ceil(_green * 255.0f));
-    *blue = static_cast<uint8_t>(ceil(_blue * 255.0f));
+    *red = (uint8_t)nearbyint(_red * 255.0f);
+    *green = (uint8_t)nearbyint(_green * 255.0f);
+    *blue = (uint8_t)nearbyint(_blue * 255.0f);
 
     return true;
 }
@@ -3254,19 +3254,34 @@ static void _clonePostponedNodes(Array<SvgNodeIdPair>* cloneNodes, SvgNode* doc)
 }
 
 
-static void _svgLoaderParserXmlClose(SvgLoaderData* loader, const char* content)
+static void _svgLoaderParserXmlClose(SvgLoaderData* loader, const char* content, unsigned int length)
 {
+    const char* itr = nullptr;
+    int sz = length;
+    char tagName[20] = "";
+
     content = _skipSpace(content, nullptr);
+    itr = content;
+    while ((itr != nullptr) && *itr != '>') itr++;
+
+    if (itr) {
+        sz = itr - content;
+        while ((sz > 0) && (isspace(content[sz - 1]))) sz--;
+        if ((unsigned int)sz >= sizeof(tagName)) sz = sizeof(tagName) - 1;
+        strncpy(tagName, content, sz);
+        tagName[sz] = '\0';
+    }
+    else return;
 
     for (unsigned int i = 0; i < sizeof(groupTags) / sizeof(groupTags[0]); i++) {
-        if (!strncmp(content, groupTags[i].tag, groupTags[i].sz - 1)) {
+        if (!strncmp(tagName, groupTags[i].tag, sz)) {
             loader->stack.pop();
             break;
         }
     }
 
     for (unsigned int i = 0; i < sizeof(graphicsTags) / sizeof(graphicsTags[0]); i++) {
-        if (!strncmp(content, graphicsTags[i].tag, graphicsTags[i].sz - 1)) {
+        if (!strncmp(tagName, graphicsTags[i].tag, sz)) {
             loader->currentGraphicsNode = nullptr;
             loader->stack.pop();
             break;
@@ -3437,7 +3452,7 @@ static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content
             break;
         }
         case SimpleXMLType::Close: {
-            _svgLoaderParserXmlClose(loader, content);
+            _svgLoaderParserXmlClose(loader, content, length);
             break;
         }
         case SimpleXMLType::Data:

+ 2 - 2
thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp

@@ -194,10 +194,10 @@ void _pathAppendArcTo(Array<PathCommand>* cmds, Array<Point>* pts, Point* cur, P
     //We dont' use arccos (as per w3c doc), see
     //http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
     //Note: atan2 (0.0, 1.0) == 0.0
-    at = atan2(((y1p - cyp) / ry), ((x1p - cxp) / rx));
+    at = mathAtan2(((y1p - cyp) / ry), ((x1p - cxp) / rx));
     theta1 = (at < 0.0f) ? 2.0f * MATH_PI + at : at;
 
-    nat = atan2(((-y1p - cyp) / ry), ((-x1p - cxp) / rx));
+    nat = mathAtan2(((-y1p - cyp) / ry), ((-x1p - cxp) / rx));
     deltaTheta = (nat < at) ? 2.0f * MATH_PI - at + nat : nat - at;
 
     if (sweep) {

+ 2 - 2
thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp

@@ -114,8 +114,8 @@ bool imagePrepare(SwImage* image, const RenderMesh* mesh, const Matrix* transfor
 
     //Fast track: Non-transformed image but just shifted.
     if (image->direct) {
-        image->ox = -static_cast<int32_t>(round(transform->e13));
-        image->oy = -static_cast<int32_t>(round(transform->e23));
+        image->ox = -static_cast<int32_t>(nearbyint(transform->e13));
+        image->oy = -static_cast<int32_t>(nearbyint(transform->e23));
     //Figure out the scale factor by transform matrix
     } else {
         auto scaleX = sqrtf((transform->e11 * transform->e11) + (transform->e21 * transform->e21));

+ 7 - 7
thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp

@@ -164,8 +164,8 @@ void mathRotate(SwPoint& pt, SwFixed angle)
     auto cosv = cosf(radian);
     auto sinv = sinf(radian);
 
-    pt.x = SwCoord(roundf((v.x * cosv - v.y * sinv) * 64.0f));
-    pt.y = SwCoord(roundf((v.x * sinv + v.y * cosv) * 64.0f));
+    pt.x = SwCoord(nearbyint((v.x * cosv - v.y * sinv) * 64.0f));
+    pt.y = SwCoord(nearbyint((v.x * sinv + v.y * cosv) * 64.0f));
 }
 
 
@@ -179,7 +179,7 @@ SwFixed mathTan(SwFixed angle)
 SwFixed mathAtan(const SwPoint& pt)
 {
     if (pt.zero()) return 0;
-    return SwFixed(atan2f(TO_FLOAT(pt.y), TO_FLOAT(pt.x)) * (180.0f / MATH_PI) * 65536.0f);
+    return SwFixed(mathAtan2(TO_FLOAT(pt.y), TO_FLOAT(pt.x)) * (180.0f / MATH_PI) * 65536.0f);
 }
 
 
@@ -309,10 +309,10 @@ bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, S
     //the rasterization region has to be rearranged.
     //https://github.com/Samsung/thorvg/issues/916
     if (fastTrack) {
-        renderRegion.min.x = static_cast<SwCoord>(round(xMin / 64.0f));
-        renderRegion.max.x = static_cast<SwCoord>(round(xMax / 64.0f));
-        renderRegion.min.y = static_cast<SwCoord>(round(yMin / 64.0f));
-        renderRegion.max.y = static_cast<SwCoord>(round(yMax / 64.0f));
+        renderRegion.min.x = static_cast<SwCoord>(nearbyint(xMin / 64.0f));
+        renderRegion.max.x = static_cast<SwCoord>(nearbyint(xMax / 64.0f));
+        renderRegion.min.y = static_cast<SwCoord>(nearbyint(yMin / 64.0f));
+        renderRegion.max.y = static_cast<SwCoord>(nearbyint(yMax / 64.0f));
     } else {
         renderRegion.min.x = xMin >> 6;
         renderRegion.max.x = (xMax + 63) >> 6;

+ 3 - 2
thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp

@@ -383,7 +383,8 @@ static bool _rasterMattedRect(SwSurface* surface, const SwBBox& region, uint8_t
             auto dst = &buffer[y * surface->stride];
             auto cmp = &cbuffer[y * surface->compositor->image.stride * csize];
             for (uint32_t x = 0; x < w; ++x, ++dst, cmp += csize) {
-                *dst = INTERPOLATE(color, *dst, alpha(cmp));
+                auto tmp = ALPHA_BLEND(color, alpha(cmp));
+                *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
             }
         }
     //8bits grayscale
@@ -674,7 +675,7 @@ static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint8_t r, uint8_t g,
     auto sy = (y) * itransform->e22 + itransform->e23 - 0.49f; \
     if (sy <= -0.5f || (uint32_t)(sy + 0.5f) >= image->h) continue; \
     if (scaleMethod == _interpDownScaler) { \
-        auto my = (int32_t)round(sy); \
+        auto my = (int32_t)nearbyint(sy); \
         miny = my - (int32_t)sampleSize; \
         if (miny < 0) miny = 0; \
         maxy = my + (int32_t)sampleSize; \

+ 36 - 67
thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp

@@ -197,7 +197,6 @@
 /* Internal Class Implementation                                        */
 /************************************************************************/
 
-constexpr auto MAX_SPANS = 256;
 constexpr auto PIXEL_BITS = 8;   //must be at least 6 bits!
 constexpr auto ONE_PIXEL = (1L << PIXEL_BITS);
 
@@ -240,10 +239,6 @@ struct RleWorker
 
     SwOutline* outline;
 
-    SwSpan spans[MAX_SPANS];
-    int spansCnt;
-    int ySpan;
-
     int bandSize;
     int bandShoot;
 
@@ -301,26 +296,6 @@ static inline SwCoord HYPOT(SwPoint pt)
     return ((pt.x > pt.y) ? (pt.x + (3 * pt.y >> 3)) : (pt.y + (3 * pt.x >> 3)));
 }
 
-static void _genSpan(SwRleData* rle, const SwSpan* spans, uint32_t count)
-{
-    auto newSize = rle->size + count;
-
-    /* allocate enough memory for new spans */
-    /* alloc is required to prevent free and reallocation */
-    /* when the rle needs to be regenerated because of attribute change. */
-    if (rle->alloc < newSize) {
-        rle->alloc = (newSize * 2);
-        //OPTIMIZE: use mempool!
-        rle->spans = static_cast<SwSpan*>(realloc(rle->spans, rle->alloc * sizeof(SwSpan)));
-    }
-
-    //copy the new spans to the allocated memory
-    SwSpan* lastSpan = rle->spans + rle->size;
-    memcpy(lastSpan, spans, count * sizeof(SwSpan));
-
-    rle->size = newSize;
-}
-
 
 static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount)
 {
@@ -344,25 +319,26 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor
         if (coverage > 255) coverage = 255;
     }
 
+    if (coverage == 0) return;
+
     //span has ushort coordinates. check limit overflow
     if (x >= SHRT_MAX) {
-        TVGERR("SW_ENGINE", "X-coordiante overflow!");
-        x = SHRT_MAX;
+        TVGERR("SW_ENGINE", "X-coordinate overflow!");
+        return;
     }
     if (y >= SHRT_MAX) {
-        TVGERR("SW_ENGINE", "Y Coordiante overflow!");
-        y = SHRT_MAX;
+        TVGERR("SW_ENGINE", "Y-coordinate overflow!");
+        return;
     }
 
-    if (coverage > 0) {
-        if (!rw.antiAlias) coverage = 255;
-        auto count = rw.spansCnt;
-        auto span = rw.spans + count - 1;
+    auto rle = rw.rle;
 
-        //see whether we can add this span to the current list
-        if ((count > 0) && (rw.ySpan == y) &&
-            (span->x + span->len == x) && (span->coverage == coverage)) {
+    if (!rw.antiAlias) coverage = 255;
 
+    //see whether we can add this span to the current list
+    if (rle->size > 0) {
+        auto span = rle->spans + rle->size - 1;
+        if ((span->coverage == coverage) && (span->y == y) && (span->x + span->len == x)) {
             //Clip x range
             SwCoord xOver = 0;
             if (x + acount >= rw.cellMax.x) xOver -= (x + acount - rw.cellMax.x);
@@ -372,35 +348,35 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor
             span->len += (acount + xOver);
             return;
         }
+    }
 
-        if (count >= MAX_SPANS) {
-            _genSpan(rw.rle, rw.spans, count);
-            rw.spansCnt = 0;
-            rw.ySpan = 0;
-            span = rw.spans;
-        } else {
-            ++span;
+    //span pool is full, grow it.
+    if (rle->size >= rle->alloc) {
+        auto newSize = (rle->size > 0) ? (rle->size * 2) : 256;
+        if (rle->alloc < newSize) {
+            rle->alloc = newSize;
+            rle->spans = static_cast<SwSpan*>(realloc(rle->spans, rle->alloc * sizeof(SwSpan)));
         }
+    }
 
-        //Clip x range
-        SwCoord xOver = 0;
-        if (x + acount >= rw.cellMax.x) xOver -= (x + acount - rw.cellMax.x);
-        if (x < rw.cellMin.x) {
-            xOver -= (rw.cellMin.x - x);
-            x = rw.cellMin.x;
-        }
+    //Clip x range
+    SwCoord xOver = 0;
+    if (x + acount >= rw.cellMax.x) xOver -= (x + acount - rw.cellMax.x);
+    if (x < rw.cellMin.x) {
+        xOver -= (rw.cellMin.x - x);
+        x = rw.cellMin.x;
+    }
 
-        //Nothing to draw
-        if (acount + xOver <= 0) return;
+    //Nothing to draw
+    if (acount + xOver <= 0) return;
 
-        //add a span to the current list
-        span->x = x;
-        span->y = y;
-        span->len = (acount + xOver);
-        span->coverage = coverage;
-        ++rw.spansCnt;
-        rw.ySpan = y;
-    }
+    //add a span to the current list
+    auto span = rle->spans + rle->size;
+    span->x = x;
+    span->y = y;
+    span->len = (acount + xOver);
+    span->coverage = coverage;
+    rle->size++;
 }
 
 
@@ -408,9 +384,6 @@ static void _sweep(RleWorker& rw)
 {
     if (rw.cellsCnt == 0) return;
 
-    rw.spansCnt = 0;
-    rw.ySpan = 0;
-
     for (int y = 0; y < rw.yCnt; ++y) {
         auto cover = 0;
         auto x = 0;
@@ -427,8 +400,6 @@ static void _sweep(RleWorker& rw)
 
         if (cover != 0) _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x);
     }
-
-    if (rw.spansCnt > 0) _genSpan(rw.rle, rw.spans, rw.spansCnt);
 }
 
 
@@ -926,7 +897,6 @@ SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& ren
     rw.cellMax = renderRegion.max;
     rw.cellXCnt = rw.cellMax.x - rw.cellMin.x;
     rw.cellYCnt = rw.cellMax.y - rw.cellMin.y;
-    rw.ySpan = 0;
     rw.outline = const_cast<SwOutline*>(outline);
     rw.bandSize = rw.bufferSize / (sizeof(Cell) * 2);  //bandSize: 256
     rw.bandShoot = 0;
@@ -1019,7 +989,6 @@ SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& ren
 
 error:
     free(rw.rle);
-    rw.rle = nullptr;
     return nullptr;
 }
 

+ 15 - 15
thirdparty/thorvg/src/renderer/tvgPaint.cpp

@@ -87,7 +87,7 @@ static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const Ren
 
     if (ptsCnt != 4) return Result::InsufficientCondition;
 
-    if (rTransform) rTransform->update();
+    if (rTransform && (cmpTarget->pImpl->renderFlag & RenderUpdateFlag::Transform)) rTransform->update();
 
     //No rotation and no skewing, still can try out clipping the rect region.
     auto tryClip = false;
@@ -181,13 +181,14 @@ Paint* Paint::Impl::duplicate()
 bool Paint::Impl::rotate(float degree)
 {
     if (rTransform) {
+        if (rTransform->overriding) return false;
         if (mathEqual(degree, rTransform->degree)) return true;
     } else {
         if (mathZero(degree)) return true;
         rTransform = new RenderTransform();
     }
     rTransform->degree = degree;
-    if (!rTransform->overriding) renderFlag |= RenderUpdateFlag::Transform;
+    renderFlag |= RenderUpdateFlag::Transform;
 
     return true;
 }
@@ -196,13 +197,14 @@ bool Paint::Impl::rotate(float degree)
 bool Paint::Impl::scale(float factor)
 {
     if (rTransform) {
+        if (rTransform->overriding) return false;
         if (mathEqual(factor, rTransform->scale)) return true;
     } else {
         if (mathEqual(factor, 1.0f)) return true;
         rTransform = new RenderTransform();
     }
     rTransform->scale = factor;
-    if (!rTransform->overriding) renderFlag |= RenderUpdateFlag::Transform;
+    renderFlag |= RenderUpdateFlag::Transform;
 
     return true;
 }
@@ -211,14 +213,15 @@ bool Paint::Impl::scale(float factor)
 bool Paint::Impl::translate(float x, float y)
 {
     if (rTransform) {
-        if (mathEqual(x, rTransform->x) && mathEqual(y, rTransform->y)) return true;
+        if (rTransform->overriding) return false;
+        if (mathEqual(x, rTransform->m.e13) && mathEqual(y, rTransform->m.e23)) return true;
     } else {
         if (mathZero(x) && mathZero(y)) return true;
         rTransform = new RenderTransform();
     }
-    rTransform->x = x;
-    rTransform->y = y;
-    if (!rTransform->overriding) renderFlag |= RenderUpdateFlag::Transform;
+    rTransform->m.e13 = x;
+    rTransform->m.e23 = y;
+    renderFlag |= RenderUpdateFlag::Transform;
 
     return true;
 }
@@ -263,10 +266,7 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT
         this->renderer = renderer;
     }
 
-    if (renderFlag & RenderUpdateFlag::Transform) {
-        if (!rTransform) return nullptr;
-        rTransform->update();
-    }
+    if (renderFlag & RenderUpdateFlag::Transform) rTransform->update();
 
     /* 1. Composition Pre Processing */
     RenderData trd = nullptr;                 //composite target render data
@@ -390,28 +390,28 @@ Paint :: ~Paint()
 Result Paint::rotate(float degree) noexcept
 {
     if (pImpl->rotate(degree)) return Result::Success;
-    return Result::FailedAllocation;
+    return Result::InsufficientCondition;
 }
 
 
 Result Paint::scale(float factor) noexcept
 {
     if (pImpl->scale(factor)) return Result::Success;
-    return Result::FailedAllocation;
+    return Result::InsufficientCondition;
 }
 
 
 Result Paint::translate(float x, float y) noexcept
 {
     if (pImpl->translate(x, y)) return Result::Success;
-    return Result::FailedAllocation;
+    return Result::InsufficientCondition;
 }
 
 
 Result Paint::transform(const Matrix& m) noexcept
 {
     if (pImpl->transform(m)) return Result::Success;
-    return Result::FailedAllocation;
+    return Result::InsufficientCondition;
 }
 
 

+ 1 - 2
thirdparty/thorvg/src/renderer/tvgPaint.h

@@ -87,7 +87,6 @@ namespace tvg
             if (!rTransform) {
                 if (mathIdentity(&m)) return true;
                 rTransform = new RenderTransform();
-                if (!rTransform) return false;
             }
             rTransform->override(m);
             renderFlag |= RenderUpdateFlag::Transform;
@@ -98,7 +97,7 @@ namespace tvg
         Matrix* transform()
         {
             if (rTransform) {
-                rTransform->update();
+                if (renderFlag & RenderUpdateFlag::Transform) rTransform->update();
                 return &rTransform->m;
             }
             return nullptr;

+ 5 - 3
thirdparty/thorvg/src/renderer/tvgPicture.h

@@ -92,18 +92,19 @@ struct Picture::Impl
 
     RenderData update(RenderMethod* renderer, const RenderTransform* pTransform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
     {
-        auto flag = load();
+        auto flag = static_cast<RenderUpdateFlag>(pFlag | load());
 
         if (surface) {
+            if (flag == RenderUpdateFlag::None) return rd;
             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, flag);
         } else if (paint) {
             if (resizing) {
                 loader->resize(paint, w, h);
                 resizing = false;
             }
             needComp = needComposition(opacity) ? true : false;
-            rd = paint->pImpl->update(renderer, pTransform, clips, opacity, static_cast<RenderUpdateFlag>(pFlag | flag), clipper);
+            rd = paint->pImpl->update(renderer, pTransform, clips, opacity, flag, clipper);
         }
         return rd;
     }
@@ -200,6 +201,7 @@ struct Picture::Impl
         if (loader) {
             dup->loader = loader;
             ++dup->loader->sharing;
+            PP(ret)->renderFlag |= RenderUpdateFlag::Image;
         }
 
         dup->surface = surface;

+ 23 - 4
thirdparty/thorvg/src/renderer/tvgRender.cpp

@@ -32,6 +32,20 @@
 /* External Class Implementation                                        */
 /************************************************************************/
 
+uint32_t RenderMethod::ref()
+{
+    ScopedLock lock(key);
+    return (++refCnt);
+}
+
+
+uint32_t RenderMethod::unref()
+{
+    ScopedLock lock(key);
+    return (--refCnt);
+}
+
+
 void RenderTransform::override(const Matrix& m)
 {
     this->m = m;
@@ -43,13 +57,18 @@ void RenderTransform::update()
 {
     if (overriding) return;
 
-    mathIdentity(&m);
+    m.e11 = 1.0f;
+    m.e12 = 0.0f;
 
-    mathScale(&m, scale, scale);
+    m.e21 = 0.0f;
+    m.e22 = 1.0f;
 
-    mathRotate(&m, degree);
+    m.e31 = 0.0f;
+    m.e32 = 0.0f;
+    m.e33 = 1.0f;
 
-    mathTranslate(&m, x, y);
+    mathScale(&m, scale, scale);
+    mathRotate(&m, degree);
 }
 
 

+ 8 - 15
thirdparty/thorvg/src/renderer/tvgRender.h

@@ -112,9 +112,7 @@ struct RenderRegion
 
 struct RenderTransform
 {
-    Matrix m;             //3x3 Matrix Elements
-    float x = 0.0f;
-    float y = 0.0f;
+    Matrix m;
     float degree = 0.0f;  //rotation degree
     float scale = 1.0f;   //scale factor
     bool overriding = false;  //user transform?
@@ -122,7 +120,11 @@ struct RenderTransform
     void update();
     void override(const Matrix& m);
 
-    RenderTransform() {}
+    RenderTransform()
+    {
+        m.e13 = m.e23 = 0.0f;
+    }
+
     RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs);
 };
 
@@ -246,17 +248,8 @@ private:
     Key key;
 
 public:
-    uint32_t ref()
-    {
-        ScopedLock lock(key);
-        return (++refCnt);
-    }
-
-    uint32_t unref()
-    {
-        ScopedLock lock(key);
-        return (--refCnt);
-    }
+    uint32_t ref();
+    uint32_t unref();
 
     virtual ~RenderMethod() {}
     virtual RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) = 0;

+ 3 - 1
thirdparty/thorvg/src/renderer/tvgShape.h

@@ -96,7 +96,9 @@ struct Shape::Impl
     }
 
     RenderData update(RenderMethod* renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
-    {     
+    {
+        if (static_cast<RenderUpdateFlag>(pFlag | flag) == RenderUpdateFlag::None) return rd;
+
         if ((needComp = needComposition(opacity))) {
             /* Overriding opacity value. If this scene is half-translucent,
                It must do intermeidate composition with that opacity value. */ 

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

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