From 6be45d2a71975a042450823272317a9cb16aa32a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Thu, 9 Jan 2025 15:03:57 +0100 Subject: [PATCH] thorvg: Update to 0.15.8 --- thirdparty/README.md | 2 +- thirdparty/thorvg/AUTHORS | 5 +- thirdparty/thorvg/inc/config.h | 2 +- thirdparty/thorvg/inc/thorvg.h | 9 +- .../src/loaders/external_png/tvgPngLoader.cpp | 4 + .../loaders/external_webp/tvgWebpLoader.cpp | 4 + .../thorvg/src/loaders/jpg/tvgJpgLoader.cpp | 4 + .../thorvg/src/loaders/svg/tvgSvgLoader.cpp | 4 + .../src/loaders/svg/tvgSvgSceneBuilder.cpp | 2 +- .../src/renderer/sw_engine/tvgSwCommon.h | 13 +- .../src/renderer/sw_engine/tvgSwFill.cpp | 1 + .../renderer/sw_engine/tvgSwPostEffect.cpp | 197 ++++++++++++++++-- .../src/renderer/sw_engine/tvgSwRaster.cpp | 29 +-- .../src/renderer/sw_engine/tvgSwRenderer.cpp | 82 +++++--- .../src/renderer/sw_engine/tvgSwRenderer.h | 6 +- .../src/renderer/sw_engine/tvgSwRle.cpp | 106 ++++++---- .../src/renderer/sw_engine/tvgSwStroke.cpp | 11 +- .../thorvg/src/renderer/tvgAccessor.cpp | 10 +- thirdparty/thorvg/src/renderer/tvgLoader.cpp | 4 + thirdparty/thorvg/src/renderer/tvgPaint.cpp | 4 +- thirdparty/thorvg/src/renderer/tvgPaint.h | 2 +- thirdparty/thorvg/src/renderer/tvgPicture.cpp | 21 +- thirdparty/thorvg/src/renderer/tvgPicture.h | 6 +- thirdparty/thorvg/src/renderer/tvgRender.h | 70 ++++++- thirdparty/thorvg/src/renderer/tvgScene.cpp | 12 ++ thirdparty/thorvg/src/renderer/tvgScene.h | 39 ++-- thirdparty/thorvg/src/renderer/tvgShape.cpp | 22 +- thirdparty/thorvg/src/renderer/tvgShape.h | 51 +++-- thirdparty/thorvg/src/renderer/tvgText.cpp | 11 +- thirdparty/thorvg/src/renderer/tvgText.h | 2 +- thirdparty/thorvg/update-thorvg.sh | 2 +- 31 files changed, 545 insertions(+), 192 deletions(-) diff --git a/thirdparty/README.md b/thirdparty/README.md index dc7eee4a0d6..d00f4af5c5a 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -934,7 +934,7 @@ instead of `miniz.h` as an external dependency. ## thorvg - Upstream: https://github.com/thorvg/thorvg -- Version: 0.15.5 (89ab573acb253567975b2494069c7ee9abc9267c, 2024) +- Version: 0.15.8 (bd8c2fca7663a22fba7a339937cb60f2f6247a2e, 2025) - License: MIT Files extracted from upstream source: diff --git a/thirdparty/thorvg/AUTHORS b/thirdparty/thorvg/AUTHORS index a15f3262a82..3a4cc7a11cf 100644 --- a/thirdparty/thorvg/AUTHORS +++ b/thirdparty/thorvg/AUTHORS @@ -22,7 +22,7 @@ Rafał Mikrut Martin Capitanio RuiwenTang YouJin Lee -SergeyLebedkin +Sergii Liebodkin Jinny You Nattu Adnan Gabor Kiss-Vamosi @@ -35,3 +35,6 @@ Thaddeus Crews Josh Soref Elliott Sales de Andrade Łukasz Pomietło +Kelly Loh +Dragoș Tiselice +Marcin Baszczewski diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h index 6df6f52d047..62ca775dab5 100644 --- a/thirdparty/thorvg/inc/config.h +++ b/thirdparty/thorvg/inc/config.h @@ -15,5 +15,5 @@ // For internal debugging: //#define THORVG_LOG_ENABLED -#define THORVG_VERSION_STRING "0.15.5" +#define THORVG_VERSION_STRING "0.15.8" #endif diff --git a/thirdparty/thorvg/inc/thorvg.h b/thirdparty/thorvg/inc/thorvg.h index 1ee898ca6ff..8e3ab4e6ce5 100644 --- a/thirdparty/thorvg/inc/thorvg.h +++ b/thirdparty/thorvg/inc/thorvg.h @@ -217,7 +217,10 @@ enum class SceneEffect : uint8_t { ClearAll = 0, ///< Reset all previously applied scene effects, restoring the scene to its original state. GaussianBlur, ///< Apply a blur effect with a Gaussian filter. Param(3) = {sigma(float)[> 0], direction(int)[both: 0 / horizontal: 1 / vertical: 2], border(int)[duplicate: 0 / wrap: 1], quality(int)[0 - 100]} - DropShadow ///< Apply a drop shadow effect with a Gaussian Blur filter. Param(8) = {color_R(int)[0 - 255], color_G(int)[0 - 255], color_B(int)[0 - 255], opacity(int)[0 - 255], angle(float)[0 - 360], distance(float), blur_sigma(float)[> 0], quality(int)[0 - 100]} + DropShadow, ///< Apply a drop shadow effect with a Gaussian Blur filter. Param(8) = {color_R(int)[0 - 255], color_G(int)[0 - 255], color_B(int)[0 - 255], opacity(int)[0 - 255], angle(float)[0 - 360], distance(float), blur_sigma(float)[> 0], quality(int)[0 - 100]} + Fill, ///< Override the scene content color with a given fill information (Experimental API). Param(5) = {color_R(int)[0 - 255], color_G(int)[0 - 255], color_B(int)[0 - 255], opacity(int)[0 - 255]} + Tint, ///< Tinting the current scene color with a given black, white color paramters (Experimental API). Param(7) = {black_R(int)[0 - 255], black_G(int)[0 - 255], black_B(int)[0 - 255], white_R(int)[0 - 255], white_G(int)[0 - 255], white_B(int)[0 - 255], intensity(float)[0 - 100]} + Tritone ///< Apply a tritone color effect to the scene using three color parameters for shadows, midtones, and highlights (Experimental API). Param(9) = {Shadow_R(int)[0 - 255], Shadow_G(int)[0 - 255], Shadow_B(int)[0 - 255], Midtone_R(int)[0 - 255], Midtone_G(int)[0 - 255], Midtone_B(int)[0 - 255], Highlight_R(int)[0 - 255], Highlight_G(int)[0 - 255], Highlight_B(int)[0 - 255]} }; @@ -2110,7 +2113,7 @@ public: /** * @brief Set the access function for traversing the Picture scene tree nodes. * - * @param[in] picture The picture node to traverse the internal scene-tree. + * @param[in] paint The paint node to traverse the internal scene-tree. * @param[in] func The callback function calling for every paint nodes of the Picture. * @param[in] data Data passed to the @p func as its argument. * @@ -2118,7 +2121,7 @@ public: * * @note Experimental API */ - Result set(const Picture* picture, std::function func, void* data) noexcept; + Result set(Paint* paint, std::function func, void* data) noexcept; /** * @brief Generate a unique ID (hash key) from a given name. diff --git a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp index 49c9f6e8aa2..71bf25a62b2 100644 --- a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp +++ b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp @@ -67,6 +67,7 @@ bool PngLoader::open(const string& path) bool PngLoader::open(const char* data, uint32_t size, bool copy) { +#ifdef THORVG_FILE_IO_SUPPORT image->opaque = NULL; if (!png_image_begin_read_from_memory(image, data, size)) return false; @@ -75,6 +76,9 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy) h = (float)image->height; return true; +#else + return false; +#endif } diff --git a/thirdparty/thorvg/src/loaders/external_webp/tvgWebpLoader.cpp b/thirdparty/thorvg/src/loaders/external_webp/tvgWebpLoader.cpp index 0db7d2d233f..6aa497c830d 100644 --- a/thirdparty/thorvg/src/loaders/external_webp/tvgWebpLoader.cpp +++ b/thirdparty/thorvg/src/loaders/external_webp/tvgWebpLoader.cpp @@ -68,6 +68,7 @@ WebpLoader::~WebpLoader() bool WebpLoader::open(const string& path) { +#ifdef THORVG_FILE_IO_SUPPORT auto webpFile = fopen(path.c_str(), "rb"); if (!webpFile) return false; @@ -96,6 +97,9 @@ bool WebpLoader::open(const string& path) finalize: fclose(webpFile); return ret; +#else + return false; +#endif } diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp index cb1306b71a3..b676bebfb99 100644 --- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp +++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp @@ -70,6 +70,7 @@ JpgLoader::~JpgLoader() bool JpgLoader::open(const string& path) { +#ifdef THORVG_FILE_IO_SUPPORT int width, height; decoder = jpgdHeader(path.c_str(), &width, &height); if (!decoder) return false; @@ -78,6 +79,9 @@ bool JpgLoader::open(const string& path) h = static_cast(height); return true; +#else + return false; +#endif } diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp index 1ab3043c24e..6ba433ba230 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp @@ -3973,6 +3973,7 @@ bool SvgLoader::open(const char* data, uint32_t size, bool copy) bool SvgLoader::open(const string& path) { +#ifdef THORVG_FILE_IO_SUPPORT clear(); ifstream f; @@ -3990,6 +3991,9 @@ bool SvgLoader::open(const string& path) size = filePath.size(); return header(); +#else + return false; +#endif } diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp index 00c7408a7e8..175739250a1 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -213,7 +213,7 @@ static bool _appendClipUseNode(SvgLoaderData& loaderData, SvgNode* node, Shape* Matrix m = {1, 0, node->node.use.x, 0, 1, node->node.use.y, 0, 0, 1}; finalTransform *= m; } - if (child->transform) finalTransform = *child->transform * finalTransform; + if (child->transform) finalTransform *= *child->transform; return _appendClipShape(loaderData, child, shape, vBox, svgPath, identity((const Matrix*)(&finalTransform)) ? nullptr : &finalTransform); } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h index 9371ae6c5ad..84fc4d9ea38 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h @@ -547,8 +547,8 @@ SwRle* rleRender(const SwBBox* bbox); void rleFree(SwRle* rle); void rleReset(SwRle* rle); void rleMerge(SwRle* rle, SwRle* clip1, SwRle* clip2); -void rleClip(SwRle* rle, const SwRle* clip); -void rleClip(SwRle* rle, const SwBBox* clip); +bool rleClip(SwRle* rle, const SwRle* clip); +bool rleClip(SwRle* rle, const SwBBox* clip); SwMpool* mpoolInit(uint32_t threads); bool mpoolTerm(SwMpool* mpool); @@ -575,10 +575,17 @@ void rasterXYFlip(uint32_t* src, uint32_t* dst, int32_t stride, int32_t w, int32 void rasterUnpremultiply(RenderSurface* surface); void rasterPremultiply(RenderSurface* surface); bool rasterConvertCS(RenderSurface* surface, ColorSpace to); +uint32_t rasterUnpremultiply(uint32_t data); bool effectGaussianBlur(SwCompositor* cmp, SwSurface* surface, const RenderEffectGaussianBlur* params); bool effectGaussianBlurPrepare(RenderEffectGaussianBlur* effect); -bool effectDropShadow(SwCompositor* cmp, SwSurface* surfaces[2], const RenderEffectDropShadow* params, uint8_t opacity, bool direct); +bool effectDropShadow(SwCompositor* cmp, SwSurface* surfaces[2], const RenderEffectDropShadow* params, bool direct); bool effectDropShadowPrepare(RenderEffectDropShadow* effect); +bool effectFillPrepare(RenderEffectFill* effect); +bool effectFill(SwCompositor* cmp, const RenderEffectFill* params, bool direct); +bool effectTintPrepare(RenderEffectTint* effect); +bool effectTint(SwCompositor* cmp, const RenderEffectTint* params, bool direct); +bool effectTritonePrepare(RenderEffectTritone* effect); +bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool direct); #endif /* _TVG_SW_COMMON_H_ */ diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp index f70ba7a13d6..e012465b708 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp @@ -487,6 +487,7 @@ void fillRadial(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32 auto src = MULTIPLY(A(_pixel(fill, sqrtf(det))), a); auto tmp = maskOp(src, *cmp, 0); *dst = tmp + MULTIPLY(*dst, ~tmp); + det += deltaDet; deltaDet += deltaDeltaDet; b += deltaB; } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwPostEffect.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwPostEffect.cpp index fd8e532e12a..3afbd660119 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwPostEffect.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwPostEffect.cpp @@ -150,7 +150,6 @@ bool effectGaussianBlurPrepare(RenderEffectGaussianBlur* params) //invalid if (extends == 0) { - params->invalid = true; free(rd); return false; } @@ -158,6 +157,7 @@ bool effectGaussianBlurPrepare(RenderEffectGaussianBlur* params) _gaussianExtendRegion(params->extend, extends, params->direction); params->rd = rd; + params->valid = true; return true; } @@ -165,11 +165,6 @@ bool effectGaussianBlurPrepare(RenderEffectGaussianBlur* params) bool effectGaussianBlur(SwCompositor* cmp, SwSurface* surface, const RenderEffectGaussianBlur* params) { - if (cmp->image.channelSize != sizeof(uint32_t)) { - TVGERR("SW_ENGINE", "Not supported grayscale Gaussian Blur!"); - return false; - } - auto& buffer = surface->compositor->image; auto data = static_cast(params->rd); auto& bbox = cmp->bbox; @@ -310,7 +305,6 @@ bool effectDropShadowPrepare(RenderEffectDropShadow* params) //invalid if (extends == 0 || params->color[3] == 0) { - params->invalid = true; free(rd); return false; } @@ -327,6 +321,7 @@ bool effectDropShadowPrepare(RenderEffectDropShadow* params) _dropShadowExtendRegion(params->extend, extends, rd->offset); params->rd = rd; + params->valid = true; return true; } @@ -335,13 +330,8 @@ bool effectDropShadowPrepare(RenderEffectDropShadow* params) //A quite same integration with effectGaussianBlur(). See it for detailed comments. //surface[0]: the original image, to overlay it into the filtered image. //surface[1]: temporary buffer for generating the filtered image. -bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffectDropShadow* params, uint8_t opacity, bool direct) +bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffectDropShadow* params, bool direct) { - if (cmp->image.channelSize != sizeof(uint32_t)) { - TVGERR("SW_ENGINE", "Not supported grayscale Drop Shadow!"); - return false; - } - //FIXME: if the body is partially visible due to clipping, the shadow also becomes partially visible. auto data = static_cast(params->rd); @@ -357,7 +347,8 @@ bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffe auto stride = cmp->image.stride; auto front = cmp->image.buf32; auto back = buffer[1]->buf32; - opacity = MULTIPLY(params->color[3], opacity); + + auto opacity = direct ? MULTIPLY(params->color[3], cmp->opacity) : params->color[3]; TVGLOG("SW_ENGINE", "DropShadow region(%ld, %ld, %ld, %ld) params(%f %f %f), level(%d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->angle, params->distance, params->sigma, data->level); @@ -408,3 +399,181 @@ bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffe return true; } + + +/************************************************************************/ +/* Fill Implementation */ +/************************************************************************/ + +bool effectFillPrepare(RenderEffectFill* params) +{ + params->valid = true; + return true; +} + + +bool effectFill(SwCompositor* cmp, const RenderEffectFill* params, bool direct) +{ + auto opacity = direct ? MULTIPLY(params->color[3], cmp->opacity) : params->color[3]; + + auto& bbox = cmp->bbox; + auto w = size_t(bbox.max.x - bbox.min.x); + auto h = size_t(bbox.max.y - bbox.min.y); + auto color = cmp->recoverSfc->join(params->color[0], params->color[1], params->color[2], 255); + + TVGLOG("SW_ENGINE", "Fill region(%ld, %ld, %ld, %ld), param(%d %d %d %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->color[0], params->color[1], params->color[2], params->color[3]); + + if (direct) { + auto dbuffer = cmp->recoverSfc->buf32 + (bbox.min.y * cmp->recoverSfc->stride + bbox.min.x); + auto sbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x); + for (size_t y = 0; y < h; ++y) { + auto dst = dbuffer; + auto src = sbuffer; + for (size_t x = 0; x < w; ++x, ++dst, ++src) { + auto a = MULTIPLY(opacity, A(*src)); + auto tmp = ALPHA_BLEND(color, a); + *dst = tmp + ALPHA_BLEND(*dst, 255 - a); + } + dbuffer += cmp->image.stride; + sbuffer += cmp->recoverSfc->stride; + } + cmp->valid = true; //no need the subsequent composition + } else { + auto dbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x); + for (size_t y = 0; y < h; ++y) { + auto dst = dbuffer; + for (size_t x = 0; x < w; ++x, ++dst) { + *dst = ALPHA_BLEND(color, MULTIPLY(opacity, A(*dst))); + } + dbuffer += cmp->image.stride; + } + } + return true; +} + + +/************************************************************************/ +/* Tint Implementation */ +/************************************************************************/ + +bool effectTintPrepare(RenderEffectTint* params) +{ + params->valid = true; + return true; +} + + +bool effectTint(SwCompositor* cmp, const RenderEffectTint* params, bool direct) +{ + auto& bbox = cmp->bbox; + auto w = size_t(bbox.max.x - bbox.min.x); + auto h = size_t(bbox.max.y - bbox.min.y); + auto black = cmp->recoverSfc->join(params->black[0], params->black[1], params->black[2], 255); + auto white = cmp->recoverSfc->join(params->white[0], params->white[1], params->white[2], 255); + auto opacity = cmp->opacity; + auto luma = cmp->recoverSfc->alphas[2]; //luma function + + TVGLOG("SW_ENGINE", "Tint region(%ld, %ld, %ld, %ld), param(%d %d %d, %d %d %d, %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->black[0], params->black[1], params->black[2], params->white[0], params->white[1], params->white[2], params->intensity); + + /* Tint Formula: (1 - L) * Black + L * White, where the L is Luminance. */ + + if (direct) { + auto dbuffer = cmp->recoverSfc->buf32 + (bbox.min.y * cmp->recoverSfc->stride + bbox.min.x); + auto sbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x); + for (size_t y = 0; y < h; ++y) { + auto dst = dbuffer; + auto src = sbuffer; + for (size_t x = 0; x < w; ++x, ++dst, ++src) { + auto tmp = rasterUnpremultiply(*src); + auto val = INTERPOLATE(INTERPOLATE(black, white, luma((uint8_t*)&tmp)), tmp, params->intensity); + *dst = INTERPOLATE(val, *dst, MULTIPLY(opacity, A(tmp))); + } + dbuffer += cmp->image.stride; + sbuffer += cmp->recoverSfc->stride; + } + cmp->valid = true; //no need the subsequent composition + } else { + auto dbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x); + for (size_t y = 0; y < h; ++y) { + auto dst = dbuffer; + for (size_t x = 0; x < w; ++x, ++dst) { + auto tmp = rasterUnpremultiply(*dst); + auto val = INTERPOLATE(INTERPOLATE(black, white, luma((uint8_t*)&tmp)), tmp, params->intensity); + *dst = ALPHA_BLEND(val, A(tmp)); + } + dbuffer += cmp->image.stride; + } + } + + return true; +} + + +/************************************************************************/ +/* Tritone Implementation */ +/************************************************************************/ + +static uint32_t _trintone(uint32_t s, uint32_t m, uint32_t h, int l) +{ + /* Tritone Formula: + if (L < 0.5) { (1 - 2L) * Shadow + 2L * Midtone } + else { (1 - 2(L - 0.5)) * Midtone + (2(L - 0.5)) * Highlight } + Where the L is Luminance. */ + + if (l < 128) { + auto a = std::min(l * 2, 255); + return ALPHA_BLEND(s, 255 - a) + ALPHA_BLEND(m, a); + } else { + auto a = 2 * std::max(0, l - 128); + return ALPHA_BLEND(m, 255 - a) + ALPHA_BLEND(h, a); + } +} + +bool effectTritonePrepare(RenderEffectTritone* params) +{ + params->valid = true; + return true; +} + + +bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool direct) +{ + auto& bbox = cmp->bbox; + auto w = size_t(bbox.max.x - bbox.min.x); + auto h = size_t(bbox.max.y - bbox.min.y); + auto shadow = cmp->recoverSfc->join(params->shadow[0], params->shadow[1], params->shadow[2], 255); + auto midtone = cmp->recoverSfc->join(params->midtone[0], params->midtone[1], params->midtone[2], 255); + auto highlight = cmp->recoverSfc->join(params->highlight[0], params->highlight[1], params->highlight[2], 255); + auto opacity = cmp->opacity; + auto luma = cmp->recoverSfc->alphas[2]; //luma function + + TVGLOG("SW_ENGINE", "Tritone region(%ld, %ld, %ld, %ld), param(%d %d %d, %d %d %d, %d %d %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->shadow[0], params->shadow[1], params->shadow[2], params->midtone[0], params->midtone[1], params->midtone[2], params->highlight[0], params->highlight[1], params->highlight[2]); + + if (direct) { + auto dbuffer = cmp->recoverSfc->buf32 + (bbox.min.y * cmp->recoverSfc->stride + bbox.min.x); + auto sbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x); + for (size_t y = 0; y < h; ++y) { + auto dst = dbuffer; + auto src = sbuffer; + for (size_t x = 0; x < w; ++x, ++dst, ++src) { + auto tmp = rasterUnpremultiply(*src); + *dst = INTERPOLATE(_trintone(shadow, midtone, highlight, luma((uint8_t*)&tmp)), *dst, MULTIPLY(opacity, A(tmp))); + } + dbuffer += cmp->image.stride; + sbuffer += cmp->recoverSfc->stride; + } + cmp->valid = true; //no need the subsequent composition + } else { + auto dbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x); + for (size_t y = 0; y < h; ++y) { + auto dst = dbuffer; + for (size_t x = 0; x < w; ++x, ++dst) { + auto tmp = rasterUnpremultiply(*dst); + *dst = ALPHA_BLEND(_trintone(shadow, midtone, highlight, luma((uint8_t*)&tmp)), A(tmp)); + } + dbuffer += cmp->image.stride; + } + } + + return true; +} diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp index 18ffc18e1e0..a404c124ad7 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp @@ -1667,6 +1667,20 @@ bool rasterClear(SwSurface* surface, uint32_t x, uint32_t y, uint32_t w, uint32_ } +uint32_t rasterUnpremultiply(uint32_t data) +{ + uint8_t a = data >> 24; + if (a == 255 || a == 0) return data; + uint16_t r = ((data >> 8) & 0xff00) / a; + uint16_t g = ((data) & 0xff00) / a; + uint16_t b = ((data << 8) & 0xff00) / a; + if (r > 0xff) r = 0xff; + if (g > 0xff) g = 0xff; + if (b > 0xff) b = 0xff; + return (a << 24) | (r << 16) | (g << 8) | (b); +} + + void rasterUnpremultiply(RenderSurface* surface) { if (surface->channelSize != sizeof(uint32_t)) return; @@ -1677,20 +1691,7 @@ void rasterUnpremultiply(RenderSurface* surface) for (uint32_t y = 0; y < surface->h; y++) { auto buffer = surface->buf32 + surface->stride * y; for (uint32_t x = 0; x < surface->w; ++x) { - uint8_t a = buffer[x] >> 24; - if (a == 255) { - continue; - } else if (a == 0) { - buffer[x] = 0x00ffffff; - } else { - uint16_t r = ((buffer[x] >> 8) & 0xff00) / a; - uint16_t g = ((buffer[x]) & 0xff00) / a; - uint16_t b = ((buffer[x] << 8) & 0xff00) / a; - if (r > 0xff) r = 0xff; - if (g > 0xff) g = 0xff; - if (b > 0xff) b = 0xff; - buffer[x] = (a << 24) | (r << 16) | (g << 8) | (b); - } + buffer[x] = rasterUnpremultiply(buffer[x]); } } surface->premultiplied = false; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp index 180f3cc37a2..4a709869203 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -103,11 +103,9 @@ struct SwShapeTask : SwTask bool clip(SwRle* target) override { - if (shape.fastTrack) rleClip(target, &bbox); - else if (shape.rle) rleClip(target, shape.rle); - else return false; - - return true; + if (shape.fastTrack) return rleClip(target, &bbox); + else if (shape.rle) return rleClip(target, shape.rle); + return false; } void run(unsigned tid) override @@ -177,10 +175,8 @@ struct SwShapeTask : SwTask //Clip Path for (auto clip = clips.begin(); clip < clips.end(); ++clip) { auto clipper = static_cast(*clip); - //Clip shape rle - if (shape.rle && !clipper->clip(shape.rle)) goto err; - //Clip stroke rle - if (shape.strokeRle && !clipper->clip(shape.strokeRle)) goto err; + if (shape.rle && !clipper->clip(shape.rle)) goto err; //Clip shape rle + if (shape.strokeRle && !clipper->clip(shape.strokeRle)) goto err; //Clip stroke rle } bbox = renderRegion; //sync @@ -546,15 +542,27 @@ const RenderSurface* SwRenderer::mainSurface() } -SwSurface* SwRenderer::request(int channelSize) +SwSurface* SwRenderer::request(int channelSize, bool square) { SwSurface* cmp = nullptr; + uint32_t w, h; + + if (square) { + //Same Dimensional Size is demanded for the Post Processing Fast Flipping + w = h = std::max(surface->w, surface->h); + } else { + w = surface->w; + h = surface->h; + } //Use cached data for (auto p = compositors.begin(); p < compositors.end(); ++p) { - if ((*p)->compositor->valid && (*p)->compositor->image.channelSize == channelSize) { - cmp = *p; - break; + auto cur = *p; + if (cur->compositor->valid && cur->compositor->image.channelSize == channelSize) { + if (w == cur->w && h == cur->h) { + cmp = *p; + break; + } } } @@ -563,15 +571,13 @@ SwSurface* SwRenderer::request(int channelSize) //Inherits attributes from main surface cmp = new SwSurface(surface); cmp->compositor = new SwCompositor; - cmp->compositor->image.data = (pixel_t*)malloc(channelSize * surface->stride * surface->h); - cmp->compositor->image.w = surface->w; - cmp->compositor->image.h = surface->h; - cmp->compositor->image.stride = surface->stride; + cmp->compositor->image.data = (pixel_t*)malloc(channelSize * w * h); + cmp->w = cmp->compositor->image.w = w; + cmp->h = cmp->compositor->image.h = h; + cmp->compositor->image.stride = w; cmp->compositor->image.direct = true; cmp->compositor->valid = true; cmp->channelSize = cmp->compositor->image.channelSize = channelSize; - cmp->w = cmp->compositor->image.w; - cmp->h = cmp->compositor->image.h; compositors.push(cmp); } @@ -583,7 +589,7 @@ SwSurface* SwRenderer::request(int channelSize) } -RenderCompositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs) +RenderCompositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs, CompositionFlag flags) { auto x = region.x; auto y = region.y; @@ -595,7 +601,7 @@ RenderCompositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs) //Out of boundary if (x >= sw || y >= sh || x + w < 0 || y + h < 0) return nullptr; - auto cmp = request(CHANNEL_SIZE(cs)); + auto cmp = request(CHANNEL_SIZE(cs), (flags & CompositionFlag::PostProcessing)); //Boundary Check if (x < 0) x = 0; @@ -630,12 +636,15 @@ bool SwRenderer::endComposite(RenderCompositor* cmp) if (!cmp) return false; auto p = static_cast(cmp); - p->valid = true; //Recover Context surface = p->recoverSfc; surface->compositor = p->recoverCmp; + //only invalid (currently used) surface can be composited + if (p->valid) return true; + p->valid = true; + //Default is alpha blending if (p->method == CompositeMethod::None) { Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1}; @@ -651,30 +660,47 @@ bool SwRenderer::prepare(RenderEffect* effect) switch (effect->type) { case SceneEffect::GaussianBlur: return effectGaussianBlurPrepare(static_cast(effect)); case SceneEffect::DropShadow: return effectDropShadowPrepare(static_cast(effect)); + case SceneEffect::Fill: return effectFillPrepare(static_cast(effect)); + case SceneEffect::Tint: return effectTintPrepare(static_cast(effect)); + case SceneEffect::Tritone: return effectTritonePrepare(static_cast(effect)); default: return false; } } -bool SwRenderer::effect(RenderCompositor* cmp, const RenderEffect* effect, uint8_t opacity, bool direct) +bool SwRenderer::effect(RenderCompositor* cmp, const RenderEffect* effect, bool direct) { - if (effect->invalid) return false; + if (!effect->valid) return false; auto p = static_cast(cmp); + if (p->image.channelSize != sizeof(uint32_t)) { + TVGERR("SW_ENGINE", "Not supported grayscale Gaussian Blur!"); + return false; + } + switch (effect->type) { case SceneEffect::GaussianBlur: { - return effectGaussianBlur(p, request(surface->channelSize), static_cast(effect)); + return effectGaussianBlur(p, request(surface->channelSize, true), static_cast(effect)); } case SceneEffect::DropShadow: { - auto cmp1 = request(surface->channelSize); + auto cmp1 = request(surface->channelSize, true); cmp1->compositor->valid = false; - auto cmp2 = request(surface->channelSize); + auto cmp2 = request(surface->channelSize, true); SwSurface* surfaces[] = {cmp1, cmp2}; - auto ret = effectDropShadow(p, surfaces, static_cast(effect), opacity, direct); + auto ret = effectDropShadow(p, surfaces, static_cast(effect), direct); cmp1->compositor->valid = true; return ret; } + case SceneEffect::Fill: { + return effectFill(p, static_cast(effect), direct); + } + case SceneEffect::Tint: { + return effectTint(p, static_cast(effect), direct); + } + case SceneEffect::Tritone: { + return effectTritone(p, static_cast(effect), direct); + } default: return false; } } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h index bd6beb8d85c..02fbe3b6b8b 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h @@ -55,13 +55,13 @@ public: bool target(pixel_t* data, uint32_t stride, uint32_t w, uint32_t h, ColorSpace cs); bool mempool(bool shared); - RenderCompositor* target(const RenderRegion& region, ColorSpace cs) override; + RenderCompositor* target(const RenderRegion& region, ColorSpace cs, CompositionFlag flags) override; bool beginComposite(RenderCompositor* cmp, CompositeMethod method, uint8_t opacity) override; bool endComposite(RenderCompositor* cmp) override; void clearCompositors(); bool prepare(RenderEffect* effect) override; - bool effect(RenderCompositor* cmp, const RenderEffect* effect, uint8_t opacity, bool direct) override; + bool effect(RenderCompositor* cmp, const RenderEffect* effect, bool direct) override; static SwRenderer* gen(); static bool init(uint32_t threads); @@ -79,7 +79,7 @@ private: SwRenderer(); ~SwRenderer(); - SwSurface* request(int channelSize); + SwSurface* request(int channelSize, bool square); RenderData prepareCommon(SwTask* task, const Matrix& transform, const Array& clips, uint8_t opacity, RenderUpdateFlag flags); }; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp index 3e4ad679a8a..cd9f40485ca 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp @@ -188,7 +188,6 @@ * http://www.freetype.org */ -#include #include #include #include "tvgSwCommon.h" @@ -243,8 +242,6 @@ struct RleWorker int bandSize; int bandShoot; - jmp_buf jmpBuf; - void* buffer; long bufferSize; @@ -359,7 +356,7 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor rle->spans = static_cast(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); @@ -418,7 +415,7 @@ static Cell* _findCell(RleWorker& rw) pcell = &cell->next; } - if (rw.cellsCnt >= rw.maxCells) longjmp(rw.jmpBuf, 1); + if (rw.cellsCnt >= rw.maxCells) return nullptr; auto cell = rw.cells + rw.cellsCnt++; cell->x = x; @@ -431,17 +428,22 @@ static Cell* _findCell(RleWorker& rw) } -static void _recordCell(RleWorker& rw) +static bool _recordCell(RleWorker& rw) { if (rw.area | rw.cover) { auto cell = _findCell(rw); + + if (cell == nullptr) return false; + cell->area += rw.area; cell->cover += rw.cover; } + + return true; } -static void _setCell(RleWorker& rw, SwPoint pos) +static bool _setCell(RleWorker& rw, SwPoint pos) { /* Move the cell pointer to a new position. We set the `invalid' */ /* flag to indicate that the cell isn't part of those we're interested */ @@ -458,22 +460,26 @@ static void _setCell(RleWorker& rw, SwPoint pos) pos.x -= rw.cellMin.x; pos.y -= rw.cellMin.y; - if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x; + //exceptions + if (pos.x < 0) pos.x = -1; + else if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x; //Are we moving to a different cell? if (pos != rw.cellPos) { //Record the current one if it is valid - if (!rw.invalid) _recordCell(rw); + if (!rw.invalid) { + if (!_recordCell(rw)) return false; + } + rw.area = rw.cover = 0; + rw.cellPos = pos; } - - rw.area = 0; - rw.cover = 0; - rw.cellPos = pos; rw.invalid = ((unsigned)pos.y >= (unsigned)rw.cellYCnt || pos.x >= rw.cellXCnt); + + return true; } -static void _startCell(RleWorker& rw, SwPoint pos) +static bool _startCell(RleWorker& rw, SwPoint pos) { if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x; if (pos.x < rw.cellMin.x) pos.x = rw.cellMin.x; @@ -483,23 +489,27 @@ static void _startCell(RleWorker& rw, SwPoint pos) rw.cellPos = pos - rw.cellMin; rw.invalid = false; - _setCell(rw, pos); + return _setCell(rw, pos); } -static void _moveTo(RleWorker& rw, const SwPoint& to) +static bool _moveTo(RleWorker& rw, const SwPoint& to) { //record current cell, if any */ - if (!rw.invalid) _recordCell(rw); + if (!rw.invalid) { + if (!_recordCell(rw)) return false; + } //start to a new position - _startCell(rw, TRUNC(to)); + if (!_startCell(rw, TRUNC(to))) return false; rw.pos = to; + + return true; } -static void _lineTo(RleWorker& rw, const SwPoint& to) +static bool _lineTo(RleWorker& rw, const SwPoint& to) { #define SW_UDIV(a, b) \ static_cast(((unsigned long)(a) * (unsigned long)(b)) >> \ @@ -511,7 +521,7 @@ static void _lineTo(RleWorker& rw, const SwPoint& to) //vertical clipping if ((e1.y >= rw.cellMax.y && e2.y >= rw.cellMax.y) || (e1.y < rw.cellMin.y && e2.y < rw.cellMin.y)) { rw.pos = to; - return; + return true; } auto line = rw.lineStack; @@ -539,7 +549,7 @@ static void _lineTo(RleWorker& rw, const SwPoint& to) //any horizontal line } else if (diff.y == 0) { e1.x = e2.x; - _setCell(rw, e1); + if (!_setCell(rw, e1)) return false; } else if (diff.x == 0) { //vertical line up if (diff.y > 0) { @@ -549,7 +559,7 @@ static void _lineTo(RleWorker& rw, const SwPoint& to) rw.area += (f2.y - f1.y) * f1.x * 2; f1.y = 0; ++e1.y; - _setCell(rw, e1); + if (!_setCell(rw, e1)) return false; } while(e1.y != e2.y); //vertical line down } else { @@ -559,7 +569,7 @@ static void _lineTo(RleWorker& rw, const SwPoint& to) rw.area += (f2.y - f1.y) * f1.x * 2; f1.y = ONE_PIXEL; --e1.y; - _setCell(rw, e1); + if (!_setCell(rw, e1)) return false; } while(e1.y != e2.y); } //any other line @@ -612,7 +622,7 @@ static void _lineTo(RleWorker& rw, const SwPoint& to) --e1.y; } - _setCell(rw, e1); + if (!_setCell(rw, e1)) return false; } while(e1 != e2); } @@ -622,12 +632,12 @@ static void _lineTo(RleWorker& rw, const SwPoint& to) rw.area += (f2.y - f1.y) * (f1.x + f2.x); rw.pos = line[0]; - if (line-- == rw.lineStack) return; + if (line-- == rw.lineStack) return true; } } -static void _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, const SwPoint& to) +static bool _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, const SwPoint& to) { auto arc = rw.bezStack; arc[0] = to; @@ -691,14 +701,14 @@ static void _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, continue; draw: - _lineTo(rw, arc[0]); - if (arc == rw.bezStack) return; + if (!_lineTo(rw, arc[0])) return false; + if (arc == rw.bezStack) return true; arc -= 3; } } -static void _decomposeOutline(RleWorker& rw) +static bool _decomposeOutline(RleWorker& rw) { auto outline = rw.outline; auto first = 0; //index of first point in contour @@ -711,38 +721,43 @@ static void _decomposeOutline(RleWorker& rw) auto types = outline->types.data + first; ++types; - _moveTo(rw, UPSCALE(outline->pts[first])); + if (!_moveTo(rw, UPSCALE(outline->pts[first]))) return false; while (pt < limit) { //emit a single line_to if (types[0] == SW_CURVE_TYPE_POINT) { ++pt; ++types; - _lineTo(rw, UPSCALE(*pt)); + if (!_lineTo(rw, UPSCALE(*pt))) return false; //types cubic } else { pt += 3; types += 3; - if (pt <= limit) _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(pt[0])); - else if (pt - 1 == limit) _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), start); + if (pt <= limit) { + if (!_cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(pt[0]))) return false; + } + else if (pt - 1 == limit) { + if (!_cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), start)) return false; + } else goto close; } } close: - _lineTo(rw, start); + if (!_lineTo(rw, start)) return false; first = last + 1; } + + return true; } static int _genRle(RleWorker& rw) { - if (setjmp(rw.jmpBuf) == 0) { - _decomposeOutline(rw); - if (!rw.invalid) _recordCell(rw); - return 0; + if (!_decomposeOutline(rw)) return -1; + if (!rw.invalid) { + if (!_recordCell(rw)) return -1; } - return -1; //lack of cell memory + return 0; } @@ -1005,9 +1020,9 @@ void rleFree(SwRle* rle) } -void rleClip(SwRle *rle, const SwRle *clip) +bool rleClip(SwRle *rle, const SwRle *clip) { - if (rle->size == 0 || clip->size == 0) return; + if (rle->size == 0 || clip->size == 0) return false; auto spanCnt = rle->size > clip->size ? rle->size : clip->size; auto spans = static_cast(malloc(sizeof(SwSpan) * (spanCnt))); auto spansEnd = _intersectSpansRegion(clip, rle, spans, spanCnt); @@ -1015,16 +1030,21 @@ void rleClip(SwRle *rle, const SwRle *clip) _replaceClipSpan(rle, spans, spansEnd - spans); TVGLOG("SW_ENGINE", "Using Path Clipping!"); + + return true; } -void rleClip(SwRle *rle, const SwBBox* clip) +bool rleClip(SwRle *rle, const SwBBox* clip) { - if (rle->size == 0) return; + if (rle->size == 0) return false; auto spans = static_cast(malloc(sizeof(SwSpan) * (rle->size))); auto spansEnd = _intersectSpansRect(clip, rle, spans, rle->size); _replaceClipSpan(rle, spans, spansEnd - spans); TVGLOG("SW_ENGINE", "Using Box Clipping!"); + + return true; } + diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp index e195f72adf2..fcc78b4bbb1 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp @@ -374,8 +374,12 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to) { auto delta = to - stroke.center; - //a zero-length lineto is a no-op; avoid creating a spurious corner - if (delta.zero()) return; + //a zero-length lineto is a no-op + if (delta.zero()) { + //round and square caps are expected to be drawn as a dot even for zero-length lines + if (stroke.firstPt && stroke.cap != StrokeCap::Butt) _firstSubPath(stroke, 0, 0); + return; + } /* The lineLength is used to determine the intersection of strokes outlines. The scale needs to be reverted since the stroke width has not been scaled. @@ -454,6 +458,9 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl //ignoreable size if (valid < 0 && arc == bezStack) { stroke.center = to; + + //round and square caps are expected to be drawn as a dot even for zero-length lines + if (stroke.firstPt && stroke.cap != StrokeCap::Butt) _firstSubPath(stroke, 0, 0); return; } diff --git a/thirdparty/thorvg/src/renderer/tvgAccessor.cpp b/thirdparty/thorvg/src/renderer/tvgAccessor.cpp index a1447268047..21caa2c2536 100644 --- a/thirdparty/thorvg/src/renderer/tvgAccessor.cpp +++ b/thirdparty/thorvg/src/renderer/tvgAccessor.cpp @@ -64,17 +64,17 @@ TVG_DEPRECATED unique_ptr Accessor::set(unique_ptr picture, fu } -Result Accessor::set(const Picture* picture, function func, void* data) noexcept +Result Accessor::set(Paint* paint, function func, void* data) noexcept { - if (!picture || !func) return Result::InvalidArguments; + if (!paint || !func) return Result::InvalidArguments; - //Use the Preorder Tree-Search + //Use the Preorder Tree-Searc //Root - if (!func(picture, data)) return Result::Success; + if (!func(paint, data)) return Result::Success; //Children - if (auto it = IteratorAccessor::iterator(picture)) { + if (auto it = IteratorAccessor::iterator(paint)) { accessChildren(it, func, data); delete(it); } diff --git a/thirdparty/thorvg/src/renderer/tvgLoader.cpp b/thirdparty/thorvg/src/renderer/tvgLoader.cpp index db51fc215a0..e69fb678a3a 100644 --- a/thirdparty/thorvg/src/renderer/tvgLoader.cpp +++ b/thirdparty/thorvg/src/renderer/tvgLoader.cpp @@ -172,6 +172,7 @@ static LoadModule* _find(FileType type) } +#ifdef THORVG_FILE_IO_SUPPORT static LoadModule* _findByPath(const string& path) { auto ext = path.substr(path.find_last_of(".") + 1); @@ -185,6 +186,7 @@ static LoadModule* _findByPath(const string& path) if (!ext.compare("otf") || !ext.compare("otc")) return _find(FileType::Ttf); return nullptr; } +#endif static FileType _convert(const string& mimeType) @@ -292,6 +294,7 @@ bool LoaderMgr::retrieve(LoadModule* loader) LoadModule* LoaderMgr::loader(const string& path, bool* invalid) { +#ifdef THORVG_FILE_IO_SUPPORT *invalid = false; //TODO: svg & lottie is not sharable. @@ -335,6 +338,7 @@ LoadModule* LoaderMgr::loader(const string& path, bool* invalid) } } *invalid = true; +#endif return nullptr; } diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.cpp b/thirdparty/thorvg/src/renderer/tvgPaint.cpp index 536e1878521..e00c2c1954e 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.cpp +++ b/thirdparty/thorvg/src/renderer/tvgPaint.cpp @@ -216,7 +216,7 @@ 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)); + cmp = renderer->target(region, COMPOSITE_TO_COLORSPACE(renderer, compData->method), CompositionFlag::Masking); if (renderer->beginComposite(cmp, CompositeMethod::None, 255)) { compData->target->pImpl->render(renderer); } @@ -374,7 +374,7 @@ void Paint::Impl::reset() blendMethod = BlendMethod::Normal; renderFlag = RenderUpdateFlag::None; - ctxFlag = ContextFlag::Invalid; + ctxFlag = ContextFlag::Default; opacity = 255; paint->id = 0; } diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.h b/thirdparty/thorvg/src/renderer/tvgPaint.h index d78e9bb3d1c..149dc0e0b51 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.h +++ b/thirdparty/thorvg/src/renderer/tvgPaint.h @@ -28,7 +28,7 @@ namespace tvg { - enum ContextFlag : uint8_t {Invalid = 0, FastTrack = 1}; + enum ContextFlag : uint8_t {Default = 0, FastTrack = 1}; struct Iterator { diff --git a/thirdparty/thorvg/src/renderer/tvgPicture.cpp b/thirdparty/thorvg/src/renderer/tvgPicture.cpp index d3e31d198a3..a268f0ed201 100644 --- a/thirdparty/thorvg/src/renderer/tvgPicture.cpp +++ b/thirdparty/thorvg/src/renderer/tvgPicture.cpp @@ -56,18 +56,20 @@ RenderUpdateFlag Picture::Impl::load() } -bool Picture::Impl::needComposition(uint8_t opacity) +void Picture::Impl::queryComposition(uint8_t opacity) { + cFlag = CompositionFlag::Invalid; + //In this case, paint(scene) would try composition itself. - if (opacity < 255) return false; + if (opacity < 255) return; //Composition test const Paint* target; auto method = picture->composite(&target); - if (!target || method == tvg::CompositeMethod::ClipPath) return false; - if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return false; + if (!target || method == tvg::CompositeMethod::ClipPath) return; + if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return; - return true; + cFlag = CompositionFlag::Opacity; } @@ -79,8 +81,8 @@ bool Picture::Impl::render(RenderMethod* renderer) if (surface) return renderer->renderImage(rd); else if (paint) { RenderCompositor* cmp = nullptr; - if (needComp) { - cmp = renderer->target(bounds(renderer), renderer->colorSpace()); + if (cFlag) { + cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast(cFlag)); renderer->beginComposite(cmp, CompositeMethod::None, 255); } ret = paint->pImpl->render(renderer); @@ -164,9 +166,14 @@ Type Picture::type() const noexcept Result Picture::load(const std::string& path) noexcept { +#ifdef THORVG_FILE_IO_SUPPORT if (path.empty()) return Result::InvalidArguments; return pImpl->load(path); +#else + TVGLOG("RENDERER", "FILE IO is disabled!"); + return Result::NonSupport; +#endif } diff --git a/thirdparty/thorvg/src/renderer/tvgPicture.h b/thirdparty/thorvg/src/renderer/tvgPicture.h index bbbc4391059..4b75b362497 100644 --- a/thirdparty/thorvg/src/renderer/tvgPicture.h +++ b/thirdparty/thorvg/src/renderer/tvgPicture.h @@ -64,10 +64,10 @@ struct Picture::Impl RenderData rd = nullptr; //engine data float w = 0, h = 0; Picture* picture = nullptr; + uint8_t cFlag = CompositionFlag::Invalid; bool resizing = false; - bool needComp = false; //need composition - bool needComposition(uint8_t opacity); + void queryComposition(uint8_t opacity); bool render(RenderMethod* renderer); bool size(float w, float h); RenderRegion bounds(RenderMethod* renderer); @@ -107,7 +107,7 @@ struct Picture::Impl loader->resize(paint, w, h); resizing = false; } - needComp = needComposition(opacity) ? true : false; + queryComposition(opacity); rd = paint->pImpl->update(renderer, transform, clips, opacity, flag, false); } return rd; diff --git a/thirdparty/thorvg/src/renderer/tvgRender.h b/thirdparty/thorvg/src/renderer/tvgRender.h index eae44a2e8ad..6558bd3ed05 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.h +++ b/thirdparty/thorvg/src/renderer/tvgRender.h @@ -36,6 +36,7 @@ using RenderData = void*; using pixel_t = uint32_t; enum RenderUpdateFlag : uint8_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, Blend = 128, All = 255}; +enum CompositionFlag : uint8_t {Invalid = 0, Opacity = 1, Blending = 2, Masking = 4, PostProcessing = 8}; //Composition Purpose //TODO: Move this in public header unifying with SwCanvas::Colorspace enum ColorSpace : uint8_t @@ -137,6 +138,7 @@ struct RenderStroke dashPattern = nullptr; } dashCnt = rhs.dashCnt; + dashOffset = rhs.dashOffset; miterlimit = rhs.miterlimit; cap = rhs.cap; join = rhs.join; @@ -268,7 +270,7 @@ struct RenderEffect RenderData rd = nullptr; RenderRegion extend = {0, 0, 0, 0}; SceneEffect type; - bool invalid = false; + bool valid = false; virtual ~RenderEffect() { @@ -309,7 +311,7 @@ struct RenderEffectDropShadow : RenderEffect inst->color[0] = va_arg(args, int); inst->color[1] = va_arg(args, int); inst->color[2] = va_arg(args, int); - inst->color[3] = std::min(va_arg(args, int), 255); + inst->color[3] = va_arg(args, int); inst->angle = (float) va_arg(args, double); inst->distance = (float) va_arg(args, double); inst->sigma = std::max((float) va_arg(args, double), 0.0f); @@ -319,6 +321,66 @@ struct RenderEffectDropShadow : RenderEffect } }; +struct RenderEffectFill : RenderEffect +{ + uint8_t color[4]; //rgba + + static RenderEffectFill* gen(va_list& args) + { + auto inst = new RenderEffectFill; + inst->color[0] = va_arg(args, int); + inst->color[1] = va_arg(args, int); + inst->color[2] = va_arg(args, int); + inst->color[3] = va_arg(args, int); + inst->type = SceneEffect::Fill; + return inst; + } +}; + +struct RenderEffectTint : RenderEffect +{ + uint8_t black[3]; //rgb + uint8_t white[3]; //rgb + uint8_t intensity; //0 - 255 + + static RenderEffectTint* gen(va_list& args) + { + auto inst = new RenderEffectTint; + inst->black[0] = va_arg(args, int); + inst->black[1] = va_arg(args, int); + inst->black[2] = va_arg(args, int); + inst->white[0] = va_arg(args, int); + inst->white[1] = va_arg(args, int); + inst->white[2] = va_arg(args, int); + inst->intensity = (uint8_t)(va_arg(args, double) * 2.55f); + inst->type = SceneEffect::Tint; + return inst; + } +}; + +struct RenderEffectTritone : RenderEffect +{ + uint8_t shadow[3]; //rgb + uint8_t midtone[3]; //rgb + uint8_t highlight[3]; //rgb + + static RenderEffectTritone* gen(va_list& args) + { + auto inst = new RenderEffectTritone; + inst->shadow[0] = va_arg(args, int); + inst->shadow[1] = va_arg(args, int); + inst->shadow[2] = va_arg(args, int); + inst->midtone[0] = va_arg(args, int); + inst->midtone[1] = va_arg(args, int); + inst->midtone[2] = va_arg(args, int); + inst->highlight[0] = va_arg(args, int); + inst->highlight[1] = va_arg(args, int); + inst->highlight[2] = va_arg(args, int); + inst->type = SceneEffect::Tritone; + return inst; + } +}; + class RenderMethod { private: @@ -347,12 +409,12 @@ public: virtual bool clear() = 0; virtual bool sync() = 0; - virtual RenderCompositor* target(const RenderRegion& region, ColorSpace cs) = 0; + virtual RenderCompositor* target(const RenderRegion& region, ColorSpace cs, CompositionFlag flags) = 0; virtual bool beginComposite(RenderCompositor* cmp, CompositeMethod method, uint8_t opacity) = 0; virtual bool endComposite(RenderCompositor* cmp) = 0; virtual bool prepare(RenderEffect* effect) = 0; - virtual bool effect(RenderCompositor* cmp, const RenderEffect* effect, uint8_t opacity, bool direct) = 0; + virtual bool effect(RenderCompositor* cmp, const RenderEffect* effect, bool direct) = 0; }; static inline bool MASK_REGION_MERGING(CompositeMethod method) diff --git a/thirdparty/thorvg/src/renderer/tvgScene.cpp b/thirdparty/thorvg/src/renderer/tvgScene.cpp index ce169d33ba6..9e9c3421e0d 100644 --- a/thirdparty/thorvg/src/renderer/tvgScene.cpp +++ b/thirdparty/thorvg/src/renderer/tvgScene.cpp @@ -128,6 +128,18 @@ Result Scene::push(SceneEffect effect, ...) noexcept re = RenderEffectDropShadow::gen(args); break; } + case SceneEffect::Fill: { + re = RenderEffectFill::gen(args); + break; + } + case SceneEffect::Tint: { + re = RenderEffectTint::gen(args); + break; + } + case SceneEffect::Tritone: { + re = RenderEffectTritone::gen(args); + break; + } default: break; } diff --git a/thirdparty/thorvg/src/renderer/tvgScene.h b/thirdparty/thorvg/src/renderer/tvgScene.h index 7972ae33fb1..bc789584ef5 100644 --- a/thirdparty/thorvg/src/renderer/tvgScene.h +++ b/thirdparty/thorvg/src/renderer/tvgScene.h @@ -62,8 +62,8 @@ struct Scene::Impl Scene* scene = nullptr; RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX}; Array* effects = nullptr; + uint8_t compFlag = CompositionFlag::Invalid; uint8_t opacity; //for composition - bool needComp = false; //composite or not Impl(Scene* s) : scene(s) { @@ -82,36 +82,36 @@ struct Scene::Impl } } - bool needComposition(uint8_t opacity) + uint8_t needComposition(uint8_t opacity) { - if (opacity == 0 || paints.empty()) return false; + compFlag = CompositionFlag::Invalid; - //post effects requires composition - if (effects) return true; + if (opacity == 0 || paints.empty()) return 0; - //Masking may require composition (even if opacity == 255) + //post effects, masking, blending may require composition + if (effects) compFlag |= CompositionFlag::PostProcessing; auto compMethod = scene->composite(nullptr); - if (compMethod != CompositeMethod::None && compMethod != CompositeMethod::ClipPath) return true; - - //Blending may require composition (even if opacity == 255) - if (PP(scene)->blendMethod != BlendMethod::Normal) return true; + if (compMethod != CompositeMethod::None && compMethod != CompositeMethod::ClipPath) compFlag |= CompositionFlag::Masking; + if (PP(scene)->blendMethod != BlendMethod::Normal) compFlag |= CompositionFlag::Blending; //Half translucent requires intermediate composition. - if (opacity == 255) return false; + if (opacity == 255) return compFlag; //If scene has several children or only scene, it may require composition. //OPTIMIZE: the bitmap type of the picture would not need the composition. //OPTIMIZE: a single paint of a scene would not need the composition. - if (paints.size() == 1 && paints.front()->type() == Type::Shape) return false; + if (paints.size() == 1 && paints.front()->type() == Type::Shape) return compFlag; - return true; + compFlag |= CompositionFlag::Opacity; + + return 1; } RenderData update(RenderMethod* renderer, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag flag, TVG_UNUSED bool clipper) { this->vport = renderer->viewport(); - if ((needComp = needComposition(opacity))) { + if (needComposition(opacity)) { /* Overriding opacity value. If this scene is half-translucent, It must do intermediate composition with that opacity value. */ this->opacity = opacity; @@ -131,8 +131,8 @@ struct Scene::Impl renderer->blend(PP(scene)->blendMethod); - if (needComp) { - cmp = renderer->target(bounds(renderer), renderer->colorSpace()); + if (compFlag) { + cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast(compFlag)); renderer->beginComposite(cmp, CompositeMethod::None, opacity); } @@ -143,9 +143,10 @@ struct Scene::Impl if (cmp) { //Apply post effects if any. if (effects) { - auto direct = effects->count == 1 ? true : false; + //Notify the possiblity of the direct composition of the effect result to the origin surface. + auto direct = (effects->count == 1) & (compFlag == CompositionFlag::PostProcessing); for (auto e = effects->begin(); e < effects->end(); ++e) { - renderer->effect(cmp, *e, opacity, direct); + renderer->effect(cmp, *e, direct); } } renderer->endComposite(cmp); @@ -178,7 +179,7 @@ struct Scene::Impl if (effects) { for (auto e = effects->begin(); e < effects->end(); ++e) { auto effect = *e; - if (effect->rd || renderer->prepare(effect)) { + if (effect->valid || renderer->prepare(effect)) { ex = std::min(ex, effect->extend.x); ey = std::min(ey, effect->extend.y); ew = std::max(ew, effect->extend.w); diff --git a/thirdparty/thorvg/src/renderer/tvgShape.cpp b/thirdparty/thorvg/src/renderer/tvgShape.cpp index 269d951f05a..f3091337aa5 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.cpp +++ b/thirdparty/thorvg/src/renderer/tvgShape.cpp @@ -66,7 +66,7 @@ Result Shape::reset() noexcept pImpl->rs.path.cmds.clear(); pImpl->rs.path.pts.clear(); - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->rFlag |= RenderUpdateFlag::Path; return Result::Success; } @@ -93,7 +93,7 @@ Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point* pImpl->grow(cmdCnt, ptsCnt); pImpl->append(cmds, cmdCnt, pts, ptsCnt); - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->rFlag |= RenderUpdateFlag::Path; return Result::Success; } @@ -111,7 +111,7 @@ Result Shape::lineTo(float x, float y) noexcept { pImpl->lineTo(x, y); - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->rFlag |= RenderUpdateFlag::Path; return Result::Success; } @@ -121,7 +121,7 @@ Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float { pImpl->cubicTo(cx1, cy1, cx2, cy2, x, y); - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->rFlag |= RenderUpdateFlag::Path; return Result::Success; } @@ -131,7 +131,7 @@ Result Shape::close() noexcept { pImpl->close(); - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->rFlag |= RenderUpdateFlag::Path; return Result::Success; } @@ -150,7 +150,7 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy); pImpl->close(); - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->rFlag |= RenderUpdateFlag::Path; return Result::Success; } @@ -212,7 +212,7 @@ TVG_DEPRECATED Result Shape::appendArc(float cx, float cy, float radius, float s if (pie) pImpl->close(); - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->rFlag |= RenderUpdateFlag::Path; return Result::Success; } @@ -252,7 +252,7 @@ Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry) pImpl->close(); } - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->rFlag |= RenderUpdateFlag::Path; return Result::Success; } @@ -263,7 +263,7 @@ Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept if (pImpl->rs.fill) { delete(pImpl->rs.fill); pImpl->rs.fill = nullptr; - pImpl->flag |= RenderUpdateFlag::Gradient; + pImpl->rFlag |= RenderUpdateFlag::Gradient; } if (r == pImpl->rs.color[0] && g == pImpl->rs.color[1] && b == pImpl->rs.color[2] && a == pImpl->rs.color[3]) return Result::Success; @@ -272,7 +272,7 @@ Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept pImpl->rs.color[1] = g; pImpl->rs.color[2] = b; pImpl->rs.color[3] = a; - pImpl->flag |= RenderUpdateFlag::Color; + pImpl->rFlag |= RenderUpdateFlag::Color; return Result::Success; } @@ -285,7 +285,7 @@ Result Shape::fill(unique_ptr f) noexcept if (pImpl->rs.fill && pImpl->rs.fill != p) delete(pImpl->rs.fill); pImpl->rs.fill = p; - pImpl->flag |= RenderUpdateFlag::Gradient; + pImpl->rFlag |= RenderUpdateFlag::Gradient; return Result::Success; } diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h index 42f81520606..a19b8d6ca62 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.h +++ b/thirdparty/thorvg/src/renderer/tvgShape.h @@ -33,10 +33,9 @@ struct Shape::Impl RenderShape rs; //shape data RenderData rd = nullptr; //engine data Shape* shape; - uint8_t flag = RenderUpdateFlag::None; - + uint8_t rFlag = RenderUpdateFlag::None; + uint8_t cFlag = CompositionFlag::Invalid; uint8_t opacity; //for composition - bool needComp = false; //composite or not Impl(Shape* s) : shape(s) { @@ -57,8 +56,8 @@ struct Shape::Impl renderer->blend(PP(shape)->blendMethod); - if (needComp) { - cmp = renderer->target(bounds(renderer), renderer->colorSpace()); + if (cFlag) { + cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast(cFlag)); renderer->beginComposite(cmp, CompositeMethod::None, opacity); } @@ -69,6 +68,8 @@ struct Shape::Impl bool needComposition(uint8_t opacity) { + cFlag = CompositionFlag::Invalid; + if (opacity == 0) return false; //Shape composition is only necessary when stroking & fill are valid. @@ -76,7 +77,10 @@ struct Shape::Impl if (!rs.fill && rs.color[3] == 0) return false; //translucent fill & stroke - if (opacity < 255) return true; + if (opacity < 255) { + cFlag = CompositionFlag::Opacity; + return true; + } //Composition test const Paint* target; @@ -97,22 +101,23 @@ struct Shape::Impl } } + cFlag = CompositionFlag::Masking; return true; } RenderData update(RenderMethod* renderer, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) { - if (static_cast(pFlag | flag) == RenderUpdateFlag::None) return rd; + if (static_cast(pFlag | rFlag) == RenderUpdateFlag::None) return rd; - if ((needComp = needComposition(opacity))) { + if (needComposition(opacity)) { /* Overriding opacity value. If this scene is half-translucent, It must do intermediate composition with that opacity value. */ this->opacity = opacity; opacity = 255; } - rd = renderer->prepare(rs, rd, transform, clips, opacity, static_cast(pFlag | flag), clipper); - flag = RenderUpdateFlag::None; + rd = renderer->prepare(rs, rd, transform, clips, opacity, static_cast(pFlag | rFlag), clipper); + rFlag = RenderUpdateFlag::None; return rd; } @@ -209,7 +214,7 @@ struct Shape::Impl { if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->width = width; - flag |= RenderUpdateFlag::Stroke; + rFlag |= RenderUpdateFlag::Stroke; } void strokeTrim(float begin, float end, bool simultaneous) @@ -225,7 +230,7 @@ struct Shape::Impl rs.stroke->trim.begin = begin; rs.stroke->trim.end = end; rs.stroke->trim.simultaneous = simultaneous; - flag |= RenderUpdateFlag::Stroke; + rFlag |= RenderUpdateFlag::Stroke; } bool strokeTrim(float* begin, float* end) @@ -245,21 +250,21 @@ struct Shape::Impl { if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->cap = cap; - flag |= RenderUpdateFlag::Stroke; + rFlag |= RenderUpdateFlag::Stroke; } void strokeJoin(StrokeJoin join) { if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->join = join; - flag |= RenderUpdateFlag::Stroke; + rFlag |= RenderUpdateFlag::Stroke; } void strokeMiterlimit(float miterlimit) { if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->miterlimit = miterlimit; - flag |= RenderUpdateFlag::Stroke; + rFlag |= RenderUpdateFlag::Stroke; } void strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) @@ -268,7 +273,7 @@ struct Shape::Impl if (rs.stroke->fill) { delete(rs.stroke->fill); rs.stroke->fill = nullptr; - flag |= RenderUpdateFlag::GradientStroke; + rFlag |= RenderUpdateFlag::GradientStroke; } rs.stroke->color[0] = r; @@ -276,7 +281,7 @@ struct Shape::Impl rs.stroke->color[2] = b; rs.stroke->color[3] = a; - flag |= RenderUpdateFlag::Stroke; + rFlag |= RenderUpdateFlag::Stroke; } Result strokeFill(unique_ptr f) @@ -289,8 +294,8 @@ struct Shape::Impl rs.stroke->fill = p; rs.stroke->color[3] = 0; - flag |= RenderUpdateFlag::Stroke; - flag |= RenderUpdateFlag::GradientStroke; + rFlag |= RenderUpdateFlag::Stroke; + rFlag |= RenderUpdateFlag::GradientStroke; return Result::Success; } @@ -325,7 +330,7 @@ struct Shape::Impl } rs.stroke->dashCnt = cnt; rs.stroke->dashOffset = offset; - flag |= RenderUpdateFlag::Stroke; + rFlag |= RenderUpdateFlag::Stroke; return Result::Success; } @@ -340,12 +345,12 @@ struct Shape::Impl { if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->strokeFirst = strokeFirst; - flag |= RenderUpdateFlag::Stroke; + rFlag |= RenderUpdateFlag::Stroke; } void update(RenderUpdateFlag flag) { - this->flag |= flag; + rFlag |= flag; } Paint* duplicate(Paint* ret) @@ -358,7 +363,7 @@ struct Shape::Impl delete(dup->rs.fill); //Default Properties - dup->flag = RenderUpdateFlag::All; + dup->rFlag = RenderUpdateFlag::All; dup->rs.rule = rs.rule; //Color diff --git a/thirdparty/thorvg/src/renderer/tvgText.cpp b/thirdparty/thorvg/src/renderer/tvgText.cpp index b324b95049e..a09bb302e57 100644 --- a/thirdparty/thorvg/src/renderer/tvgText.cpp +++ b/thirdparty/thorvg/src/renderer/tvgText.cpp @@ -60,13 +60,17 @@ Result Text::font(const char* name, float size, const char* style) noexcept Result Text::load(const std::string& path) noexcept { +#ifdef THORVG_FILE_IO_SUPPORT bool invalid; //invalid path if (!LoaderMgr::loader(path, &invalid)) { if (invalid) return Result::InvalidArguments; else return Result::NonSupport; } - return Result::Success; +#else + TVGLOG("RENDERER", "FILE IO is disabled!"); + return Result::NonSupport; +#endif } @@ -87,8 +91,13 @@ Result Text::load(const char* name, const char* data, uint32_t size, const strin Result Text::unload(const std::string& path) noexcept { +#ifdef THORVG_FILE_IO_SUPPORT if (LoaderMgr::retrieve(path)) return Result::Success; return Result::InsufficientCondition; +#else + TVGLOG("RENDERER", "FILE IO is disabled!"); + return Result::NonSupport; +#endif } diff --git a/thirdparty/thorvg/src/renderer/tvgText.h b/thirdparty/thorvg/src/renderer/tvgText.h index 11e01b58ce6..d92495ef714 100644 --- a/thirdparty/thorvg/src/renderer/tvgText.h +++ b/thirdparty/thorvg/src/renderer/tvgText.h @@ -113,7 +113,7 @@ struct Text::Impl //transform the gradient coordinates based on the final scaled font. auto fill = P(shape)->rs.fill; - if (fill && P(shape)->flag & RenderUpdateFlag::Gradient) { + if (fill && P(shape)->rFlag & RenderUpdateFlag::Gradient) { auto scale = 1.0f / loader->scale; if (fill->type() == Type::LinearGradient) { P(static_cast(fill))->x1 *= scale; diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh index f9953f2fc9e..5aeac089395 100755 --- a/thirdparty/thorvg/update-thorvg.sh +++ b/thirdparty/thorvg/update-thorvg.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -VERSION=0.15.5 +VERSION=0.15.8 # Uncomment and set a git hash to use specific commit instead of tag. #GIT_COMMIT=