From e94df6f5355dc89fa822c698cdf7aa8c4cc050c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Thu, 20 Jun 2024 09:43:02 +0200 Subject: [PATCH] thorvg: Update to 0.13.8 --- thirdparty/thorvg/inc/config.h | 2 +- .../thorvg/patches/pr2338-float_t.patch | 13 -- thirdparty/thorvg/src/common/tvgLock.h | 2 + .../thorvg/src/loaders/svg/tvgSvgLoader.cpp | 161 +++++++++++++----- .../src/loaders/svg/tvgSvgLoaderCommon.h | 20 ++- .../src/loaders/svg/tvgSvgSceneBuilder.cpp | 84 ++++++++- .../src/renderer/sw_engine/tvgSwCommon.h | 12 -- .../renderer/sw_engine/tvgSwRasterTexmap.h | 49 +++--- .../src/renderer/sw_engine/tvgSwRenderer.cpp | 2 +- .../src/renderer/sw_engine/tvgSwShape.cpp | 1 + thirdparty/thorvg/src/renderer/tvgCommon.h | 12 ++ thirdparty/thorvg/src/renderer/tvgPaint.cpp | 78 ++++++--- .../thorvg/src/renderer/tvgTaskScheduler.h | 2 + thirdparty/thorvg/update-thorvg.sh | 2 +- 14 files changed, 310 insertions(+), 130 deletions(-) delete mode 100644 thirdparty/thorvg/patches/pr2338-float_t.patch diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h index e2a61a9384a..fc7f3ac36dd 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.13.7" +#define THORVG_VERSION_STRING "0.13.8" #endif diff --git a/thirdparty/thorvg/patches/pr2338-float_t.patch b/thirdparty/thorvg/patches/pr2338-float_t.patch deleted file mode 100644 index 20b9050cbbe..00000000000 --- a/thirdparty/thorvg/patches/pr2338-float_t.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp -index f59994aae6..b2ce38852c 100644 ---- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp -+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp -@@ -709,7 +709,7 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char** - *ref = _idFromUrl((const char*)(str + 3)); - return true; - } else if (len >= 10 && (str[0] == 'h' || str[0] == 'H') && (str[1] == 's' || str[1] == 'S') && (str[2] == 'l' || str[2] == 'L') && str[3] == '(' && str[len - 1] == ')') { -- float_t th, ts, tb; -+ float th, ts, tb; - const char *content, *hue, *satuation, *brightness; - content = str + 4; - content = _skipSpace(content, nullptr); diff --git a/thirdparty/thorvg/src/common/tvgLock.h b/thirdparty/thorvg/src/common/tvgLock.h index 5dd3d5a6248..d8bf7269f6f 100644 --- a/thirdparty/thorvg/src/common/tvgLock.h +++ b/thirdparty/thorvg/src/common/tvgLock.h @@ -25,6 +25,8 @@ #ifdef THORVG_THREAD_SUPPORT +#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR + #include namespace tvg { diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp index b2ce38852c6..f29bc09b77e 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp @@ -175,14 +175,14 @@ static float _toFloat(const SvgParser* svgParse, const char* str, SvgParserLengt else if (strstr(str, "pc")) parsedValue *= PX_PER_PC; else if (strstr(str, "in")) parsedValue *= PX_PER_IN; else if (strstr(str, "%")) { - if (type == SvgParserLengthType::Vertical) parsedValue = (parsedValue / 100.0) * svgParse->global.h; - else if (type == SvgParserLengthType::Horizontal) parsedValue = (parsedValue / 100.0) * svgParse->global.w; - else //if other then it's radius + if (type == SvgParserLengthType::Vertical) parsedValue = (parsedValue / 100.0f) * svgParse->global.h; + else if (type == SvgParserLengthType::Horizontal) parsedValue = (parsedValue / 100.0f) * svgParse->global.w; + else //if other than it's radius { float max = svgParse->global.w; if (max < svgParse->global.h) max = svgParse->global.h; - parsedValue = (parsedValue / 100.0) * max; + parsedValue = (parsedValue / 100.0f) * max; } } //TODO: Implement 'em', 'ex' attributes @@ -580,7 +580,7 @@ static constexpr struct }; -static bool _hslToRgb(float hue, float satuation, float brightness, uint8_t* red, uint8_t* green, uint8_t* blue) +static bool _hslToRgb(float hue, float saturation, float brightness, uint8_t* red, uint8_t* green, uint8_t* blue) { if (!red || !green || !blue) return false; @@ -588,12 +588,12 @@ static bool _hslToRgb(float hue, float satuation, float brightness, uint8_t* red float _red = 0, _green = 0, _blue = 0; uint32_t i = 0; - if (mathZero(satuation)) _red = _green = _blue = brightness; + if (mathZero(saturation)) _red = _green = _blue = brightness; else { if (mathEqual(hue, 360.0)) hue = 0.0f; hue /= 60.0f; - v = (brightness <= 0.5f) ? (brightness * (1.0f + satuation)) : (brightness + satuation - (brightness * satuation)); + v = (brightness <= 0.5f) ? (brightness * (1.0f + saturation)) : (brightness + saturation - (brightness * saturation)); p = brightness + brightness - v; if (!mathZero(v)) sv = (v - p) / v; @@ -662,7 +662,7 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char** unsigned char tr, tg, tb; if (len == 4 && str[0] == '#') { - //Case for "#456" should be interprete as "#445566" + //Case for "#456" should be interpreted as "#445566" if (isxdigit(str[1]) && isxdigit(str[2]) && isxdigit(str[3])) { char tmp[3] = { '\0', '\0', '\0' }; tmp[0] = str[1]; @@ -710,7 +710,7 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char** return true; } else if (len >= 10 && (str[0] == 'h' || str[0] == 'H') && (str[1] == 's' || str[1] == 'S') && (str[2] == 'l' || str[2] == 'L') && str[3] == '(' && str[len - 1] == ')') { float th, ts, tb; - const char *content, *hue, *satuation, *brightness; + const char *content, *hue, *saturation, *brightness; content = str + 4; content = _skipSpace(content, nullptr); if (_parseNumber(&content, &hue, &th) && hue) { @@ -718,12 +718,12 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char** hue = _skipSpace(hue, nullptr); hue = (char*)_skipComma(hue); hue = _skipSpace(hue, nullptr); - if (_parseNumber(&hue, &satuation, &ts) && satuation && *satuation == '%') { + if (_parseNumber(&hue, &saturation, &ts) && saturation && *saturation == '%') { ts /= 100.0f; - satuation = _skipSpace(satuation + 1, nullptr); - satuation = (char*)_skipComma(satuation); - satuation = _skipSpace(satuation, nullptr); - if (_parseNumber(&satuation, &brightness, &tb) && brightness && *brightness == '%') { + saturation = _skipSpace(saturation + 1, nullptr); + saturation = (char*)_skipComma(saturation); + saturation = _skipSpace(saturation, nullptr); + if (_parseNumber(&saturation, &brightness, &tb) && brightness && *brightness == '%') { tb /= 100.0f; brightness = _skipSpace(brightness + 1, nullptr); if (brightness && brightness[0] == ')' && brightness[1] == '\0') { @@ -2119,7 +2119,72 @@ static SvgNode* _createUseNode(SvgLoaderData* loader, SvgNode* parent, const cha } -//TODO: Implement 'text' primitive +static constexpr struct +{ + const char* tag; + SvgParserLengthType type; + int sz; + size_t offset; +} textTags[] = { + {"x", SvgParserLengthType::Horizontal, sizeof("x"), offsetof(SvgTextNode, x)}, + {"y", SvgParserLengthType::Vertical, sizeof("y"), offsetof(SvgTextNode, y)}, + {"font-size", SvgParserLengthType::Vertical, sizeof("font-size"), offsetof(SvgTextNode, fontSize)} +}; + + +static bool _attrParseTextNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode* node = loader->svgParse->node; + SvgTextNode* text = &(node->node.text); + + unsigned char* array; + int sz = strlen(key); + + array = (unsigned char*)text; + for (unsigned int i = 0; i < sizeof(textTags) / sizeof(textTags[0]); i++) { + if (textTags[i].sz - 1 == sz && !strncmp(textTags[i].tag, key, sz)) { + *((float*)(array + textTags[i].offset)) = _toFloat(loader->svgParse, value, textTags[i].type); + return true; + } + } + + if (!strcmp(key, "font-family")) { + if (text->fontFamily && value) free(text->fontFamily); + text->fontFamily = strdup(value); + } else if (!strcmp(key, "style")) { + return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); + } else if (!strcmp(key, "clip-path")) { + _handleClipPathAttr(loader, node, value); + } else if (!strcmp(key, "mask")) { + _handleMaskAttr(loader, node, value); + } else if (!strcmp(key, "id")) { + if (node->id && value) free(node->id); + node->id = _copyId(value); + } else if (!strcmp(key, "class")) { + _handleCssClassAttr(loader, node, value); + } else { + return _parseStyleAttr(loader, key, value, false); + } + return true; +} + + +static SvgNode* _createTextNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::Text); + if (!loader->svgParse->node) return nullptr; + + //TODO: support the def font and size as used in a system? + loader->svgParse->node->node.text.fontSize = 10.0f; + loader->svgParse->node->node.text.fontFamily = nullptr; + + func(buf, bufLength, _attrParseTextNode, loader); + + return loader->svgParse->node; +} + + static constexpr struct { const char* tag; @@ -2134,7 +2199,8 @@ static constexpr struct {"rect", sizeof("rect"), _createRectNode}, {"polyline", sizeof("polyline"), _createPolylineNode}, {"line", sizeof("line"), _createLineNode}, - {"image", sizeof("image"), _createImageNode} + {"image", sizeof("image"), _createImageNode}, + {"text", sizeof("text"), _createTextNode} }; @@ -3122,6 +3188,20 @@ static void _copyAttr(SvgNode* to, const SvgNode* from) to->node.use.symbol = from->node.use.symbol; break; } + case SvgNodeType::Text: { + to->node.text.x = from->node.text.x; + to->node.text.y = from->node.text.y; + to->node.text.fontSize = from->node.text.fontSize; + if (from->node.text.text) { + if (to->node.text.text) free(to->node.text.text); + to->node.text.text = strdup(from->node.text.text); + } + if (from->node.text.fontFamily) { + if (to->node.text.fontFamily) free(to->node.text.fontFamily); + to->node.text.fontFamily = strdup(from->node.text.fontFamily); + } + break; + } default: { break; } @@ -3174,27 +3254,12 @@ static void _clonePostponedNodes(Array* cloneNodes, SvgNode* doc) } -static constexpr struct -{ - const char* tag; - size_t sz; -} popArray[] = { - {"g", sizeof("g")}, - {"svg", sizeof("svg")}, - {"defs", sizeof("defs")}, - {"mask", sizeof("mask")}, - {"clipPath", sizeof("clipPath")}, - {"style", sizeof("style")}, - {"symbol", sizeof("symbol")} -}; - - static void _svgLoaderParserXmlClose(SvgLoaderData* loader, const char* content) { content = _skipSpace(content, nullptr); - for (unsigned int i = 0; i < sizeof(popArray) / sizeof(popArray[0]); i++) { - if (!strncmp(content, popArray[i].tag, popArray[i].sz - 1)) { + for (unsigned int i = 0; i < sizeof(groupTags) / sizeof(groupTags[0]); i++) { + if (!strncmp(content, groupTags[i].tag, groupTags[i].sz - 1)) { loader->stack.pop(); break; } @@ -3259,7 +3324,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes); loader->cssStyle = node; loader->doc->node.doc.style = node; - loader->style = true; + loader->openedTag = OpenedTagType::Style; } } else { node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes); @@ -3275,9 +3340,12 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, else parent = loader->doc; node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes); if (node && !empty) { - auto defs = _createDefsNode(loader, nullptr, nullptr, 0, nullptr); - loader->stack.push(defs); - loader->currentGraphicsNode = node; + if (!strcmp(tagName, "text")) loader->openedTag = OpenedTagType::Text; + else { + auto defs = _createDefsNode(loader, nullptr, nullptr, 0, nullptr); + loader->stack.push(defs); + loader->currentGraphicsNode = node; + } } } else if ((gradientMethod = _findGradientFactory(tagName))) { SvgStyleGradient* gradient; @@ -3310,6 +3378,15 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, } +static void _svgLoaderParserText(SvgLoaderData* loader, const char* content, unsigned int length) +{ + auto text = &loader->svgParse->node->node.text; + if (text->text) free(text->text); + text->text = strDuplicate(content, length); + loader->openedTag = OpenedTagType::Other; +} + + static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* content, unsigned int length) { char* tag; @@ -3342,7 +3419,7 @@ static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* conte free(tag); free(name); } - loader->style = false; + loader->openedTag = OpenedTagType::Other; } @@ -3365,7 +3442,8 @@ static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content } case SimpleXMLType::Data: case SimpleXMLType::CData: { - if (loader->style) _svgLoaderParserXmlCssStyle(loader, content, length); + if (loader->openedTag == OpenedTagType::Style) _svgLoaderParserXmlCssStyle(loader, content, length); + else if (loader->openedTag == OpenedTagType::Text) _svgLoaderParserText(loader, content, length); break; } case SimpleXMLType::DoctypeChild: { @@ -3587,6 +3665,11 @@ static void _freeNode(SvgNode* node) free(node->node.image.href); break; } + case SvgNodeType::Text: { + free(node->node.text.text); + free(node->node.text.fontFamily); + break; + } default: { break; } diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h index 283f56561b2..5661c8ae82c 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h @@ -374,6 +374,14 @@ struct SvgCssStyleNode { }; +struct SvgTextNode +{ + char* text; + char* fontFamily; + float x, y; + float fontSize; +}; + struct SvgLinearGradient { float x1; @@ -518,6 +526,7 @@ struct SvgNode SvgClipNode clip; SvgCssStyleNode cssStyle; SvgSymbolNode symbol; + SvgTextNode text; } node; ~SvgNode(); }; @@ -545,11 +554,18 @@ struct SvgNodeIdPair char *id; }; +enum class OpenedTagType : uint8_t +{ + Other = 0, + Style, + Text +}; + struct SvgLoaderData { Array stack; SvgNode* doc = nullptr; - SvgNode* def = nullptr; + SvgNode* def = nullptr; //also used to store nested graphic nodes SvgNode* cssStyle = nullptr; Array gradients; SvgStyleGradient* latestGradient = nullptr; //For stops @@ -559,7 +575,7 @@ struct SvgLoaderData Array images; //embedded images int level = 0; bool result = false; - bool style = false; + OpenedTagType openedTag = OpenedTagType::Other; SvgNode* currentGraphicsNode = nullptr; }; diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp index 7e7efed3fc5..b048695a234 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -67,6 +67,14 @@ static Box _boundingBox(const Shape* shape) } +static Box _boundingBox(const Text* text) +{ + float x, y, w, h; + text->bounds(&x, &y, &w, &h, false); + return {x, y, w, h}; +} + + static void _transformMultiply(const Matrix* mBBox, Matrix* gradTransf) { gradTransf->e13 = gradTransf->e13 * mBBox->e11 + mBBox->e13; @@ -79,7 +87,7 @@ static void _transformMultiply(const Matrix* mBBox, Matrix* gradTransf) } -static unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, const Shape* vg, const Box& vBox, int opacity) +static unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, const Box& vBox, int opacity) { Fill::ColorStop* stops; int stopCount = 0; @@ -134,7 +142,7 @@ static unique_ptr _applyLinearGradientProperty(SvgStyleGradient* } -static unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, const Shape* vg, const Box& vBox, int opacity) +static unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, const Box& vBox, int opacity) { Fill::ColorStop *stops; int stopCount = 0; @@ -320,14 +328,15 @@ static void _applyProperty(SvgLoaderData& loaderData, SvgNode* node, Shape* vg, if (!style->fill.paint.gradient->userSpace) bBox = _boundingBox(vg); if (style->fill.paint.gradient->type == SvgGradientType::Linear) { - auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, vg, bBox, style->fill.opacity); - vg->fill(std::move(linear)); + auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, bBox, style->fill.opacity); + vg->fill(std::move(linear)); } else if (style->fill.paint.gradient->type == SvgGradientType::Radial) { - auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, vg, bBox, style->fill.opacity); - vg->fill(std::move(radial)); + auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, bBox, style->fill.opacity); + vg->fill(std::move(radial)); } } else if (style->fill.paint.url) { //TODO: Apply the color pointed by url + TVGLOG("SVG", "The fill's url not supported."); } else if (style->fill.paint.curColor) { //Apply the current style color vg->fill(style->color.r, style->color.g, style->color.b, style->fill.opacity); @@ -363,14 +372,15 @@ static void _applyProperty(SvgLoaderData& loaderData, SvgNode* node, Shape* vg, if (!style->stroke.paint.gradient->userSpace) bBox = _boundingBox(vg); if (style->stroke.paint.gradient->type == SvgGradientType::Linear) { - auto linear = _applyLinearGradientProperty(style->stroke.paint.gradient, vg, bBox, style->stroke.opacity); + auto linear = _applyLinearGradientProperty(style->stroke.paint.gradient, bBox, style->stroke.opacity); vg->stroke(std::move(linear)); } else if (style->stroke.paint.gradient->type == SvgGradientType::Radial) { - auto radial = _applyRadialGradientProperty(style->stroke.paint.gradient, vg, bBox, style->stroke.opacity); + auto radial = _applyRadialGradientProperty(style->stroke.paint.gradient, bBox, style->stroke.opacity); vg->stroke(std::move(radial)); } } else if (style->stroke.paint.url) { //TODO: Apply the color pointed by url + TVGLOG("SVG", "The stroke's url not supported."); } else if (style->stroke.paint.curColor) { //Apply the current style color vg->stroke(style->color.r, style->color.g, style->color.b, style->stroke.opacity); @@ -772,6 +782,61 @@ static unique_ptr _useBuildHelper(SvgLoaderData& loaderData, const SvgNod } +static void _applyTextFill(SvgStyleProperty* style, Text* text, const Box& vBox) +{ + //If fill property is nullptr then do nothing + if (style->fill.paint.none) { + //Do nothing + } else if (style->fill.paint.gradient) { + Box bBox = vBox; + if (!style->fill.paint.gradient->userSpace) bBox = _boundingBox(text); + + if (style->fill.paint.gradient->type == SvgGradientType::Linear) { + auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, bBox, style->fill.opacity); + text->fill(std::move(linear)); + } else if (style->fill.paint.gradient->type == SvgGradientType::Radial) { + auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, bBox, style->fill.opacity); + text->fill(std::move(radial)); + } + } else if (style->fill.paint.url) { + //TODO: Apply the color pointed by url + TVGLOG("SVG", "The fill's url not supported."); + } else if (style->fill.paint.curColor) { + //Apply the current style color + text->fill(style->color.r, style->color.g, style->color.b); + text->opacity(style->fill.opacity); + } else { + //Apply the fill color + text->fill(style->fill.paint.color.r, style->fill.paint.color.g, style->fill.paint.color.b); + text->opacity(style->fill.opacity); + } +} + + +static unique_ptr _textBuildHelper(SvgLoaderData& loaderData, const SvgNode* node, const Box& vBox, const string& svgPath) +{ + auto textNode = &node->node.text; + if (!textNode->text) return nullptr; + auto text = Text::gen(); + + Matrix textTransform = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + if (node->transform) textTransform = *node->transform; + mathTranslateR(&textTransform, node->node.text.x, node->node.text.y - textNode->fontSize); + text->transform(textTransform); + + //TODO: handle def values of font and size as used in a system? + const float ptPerPx = 0.75f; //1 pt = 1/72; 1 in = 96 px; -> 72/96 = 0.75 + auto fontSizePt = textNode->fontSize * ptPerPx; + if (textNode->fontFamily) text->font(textNode->fontFamily, fontSizePt); + text->text(textNode->text); + + _applyTextFill(node->style, text.get(), vBox); + _applyComposition(loaderData, text.get(), node, vBox, svgPath); + + return text; +} + + static unique_ptr _sceneBuildHelper(SvgLoaderData& loaderData, const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, int depth, bool* isMaskWhite) { /* Exception handling: Prevent invalid SVG data input. @@ -800,6 +865,9 @@ static unique_ptr _sceneBuildHelper(SvgLoaderData& loaderData, const SvgN scene->push(std::move(image)); if (isMaskWhite) *isMaskWhite = false; } + } else if ((*child)->type == SvgNodeType::Text) { + auto text = _textBuildHelper(loaderData, *child, vBox, svgPath); + if (text) scene->push(std::move(text)); } else if ((*child)->type != SvgNodeType::Mask) { auto shape = _shapeBuildHelper(loaderData, *child, vBox, svgPath); if (shape) { diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h index 3d73075a4a4..231410cdace 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h @@ -26,18 +26,6 @@ #include "tvgCommon.h" #include "tvgRender.h" -#include - -#if 0 -#include -static double timeStamp() -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (tv.tv_sec + tv.tv_usec / 1000000.0); -} -#endif - #define SW_CURVE_TYPE_POINT 0 #define SW_CURVE_TYPE_CUBIC 1 #define SW_ANGLE_PI (180L << 16) diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h index 8ec2bc0c47e..bab534bba29 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h @@ -34,14 +34,6 @@ struct AASpans int32_t yEnd; }; -static inline void _swap(float& a, float& b, float& tmp) -{ - tmp = a; - a = b; - b = tmp; -} - - //Careful! Shared resource, No support threading static float dudx, dvdx; static float dxdya, dxdyb, dudya, dvdya; @@ -85,7 +77,7 @@ static bool _rasterMaskedPolygonImageSegment(SwSurface* surface, const SwImage* int32_t sh = image->h; int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay; int32_t vv = 0, uu = 0; - int32_t minx = INT32_MAX, maxx = INT32_MIN; + int32_t minx = INT32_MAX, maxx = 0; float dx, u, v, iptr; SwSpan* span = nullptr; //used only when rle based. @@ -113,7 +105,7 @@ static bool _rasterMaskedPolygonImageSegment(SwSurface* surface, const SwImage* if (!region) { minx = INT32_MAX; - maxx = INT32_MIN; + maxx = 0; //one single row, could be consisted of multiple spans. while (span->y == y && spanIdx < image->rle->size) { if (minx > span->x) minx = span->x; @@ -278,7 +270,7 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage int32_t dw = surface->stride; int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay; int32_t vv = 0, uu = 0; - int32_t minx = INT32_MAX, maxx = INT32_MIN; + int32_t minx = INT32_MAX, maxx = 0; float dx, u, v, iptr; uint32_t* buf; SwSpan* span = nullptr; //used only when rle based. @@ -307,7 +299,7 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage if (!region) { minx = INT32_MAX; - maxx = INT32_MIN; + maxx = 0; //one single row, could be consisted of multiple spans. while (span->y == y && spanIdx < image->rle->size) { if (minx > span->x) minx = span->x; @@ -455,7 +447,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, int32_t dw = surface->stride; int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay; int32_t vv = 0, uu = 0; - int32_t minx = INT32_MAX, maxx = INT32_MIN; + int32_t minx = INT32_MAX, maxx = 0; float dx, u, v, iptr; uint32_t* buf; SwSpan* span = nullptr; //used only when rle based. @@ -489,7 +481,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, if (!region) { minx = INT32_MAX; - maxx = INT32_MIN; + maxx = 0; //one single row, could be consisted of multiple spans. while (span->y == y && spanIdx < image->rle->size) { if (minx > span->x) minx = span->x; @@ -650,28 +642,27 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const float off_y; float dxdy[3] = {0.0f, 0.0f, 0.0f}; - float tmp; auto upper = false; //Sort the vertices in ascending Y order if (y[0] > y[1]) { - _swap(x[0], x[1], tmp); - _swap(y[0], y[1], tmp); - _swap(u[0], u[1], tmp); - _swap(v[0], v[1], tmp); + std::swap(x[0], x[1]); + std::swap(y[0], y[1]); + std::swap(u[0], u[1]); + std::swap(v[0], v[1]); } if (y[0] > y[2]) { - _swap(x[0], x[2], tmp); - _swap(y[0], y[2], tmp); - _swap(u[0], u[2], tmp); - _swap(v[0], v[2], tmp); + std::swap(x[0], x[2]); + std::swap(y[0], y[2]); + std::swap(u[0], u[2]); + std::swap(v[0], v[2]); } if (y[1] > y[2]) { - _swap(x[1], x[2], tmp); - _swap(y[1], y[2], tmp); - _swap(u[1], u[2], tmp); - _swap(v[1], v[2], tmp); + std::swap(x[1], x[2]); + std::swap(y[1], y[2]); + std::swap(u[1], u[2]); + std::swap(v[1], v[2]); } //Y indexes @@ -837,7 +828,9 @@ static AASpans* _AASpans(float ymin, float ymax, const SwImage* image, const SwB for (int32_t i = 0; i < height; i++) { aaSpans->lines[i].x[0] = INT32_MAX; - aaSpans->lines[i].x[1] = INT32_MIN; + aaSpans->lines[i].x[1] = 0; + aaSpans->lines[i].length[0] = 0; + aaSpans->lines[i].length[1] = 0; } return aaSpans; } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp index f689179928a..78108af095c 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -86,7 +86,7 @@ struct SwShapeTask : SwTask Additionally, the stroke style should not be dashed. */ bool antialiasing(float strokeWidth) { - return strokeWidth < 2.0f || rshape->stroke->dashCnt > 0 || rshape->stroke->strokeFirst; + return strokeWidth < 2.0f || rshape->stroke->dashCnt > 0 || rshape->stroke->strokeFirst || rshape->strokeTrim(); } float validStrokeWidth() diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp index d8dd40d45b1..4f069ece975 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp @@ -420,6 +420,7 @@ static bool _axisAlignedRect(const SwOutline* outline) { //Fast Track: axis-aligned rectangle? if (outline->pts.count != 5) return false; + if (outline->types[2] == SW_CURVE_TYPE_CUBIC) return false; auto pt1 = outline->pts.data + 0; auto pt2 = outline->pts.data + 1; diff --git a/thirdparty/thorvg/src/renderer/tvgCommon.h b/thirdparty/thorvg/src/renderer/tvgCommon.h index d080ea19cf6..15a2cc4ef04 100644 --- a/thirdparty/thorvg/src/renderer/tvgCommon.h +++ b/thirdparty/thorvg/src/renderer/tvgCommon.h @@ -87,4 +87,16 @@ uint16_t THORVG_VERSION_NUMBER(); #define P(A) ((A)->pImpl) //Access to pimpl. #define PP(A) (((Paint*)(A))->pImpl) //Access to pimpl. + +//for debugging +#if 0 +#include +static inline double THORVG_TIMESTAMP() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec + tv.tv_usec / 1000000.0); +} +#endif + #endif //_TVG_COMMON_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.cpp b/thirdparty/thorvg/src/renderer/tvgPaint.cpp index fcb632e2b1a..ff0f75dc0fa 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.cpp +++ b/thirdparty/thorvg/src/renderer/tvgPaint.cpp @@ -41,8 +41,39 @@ } +static Result _clipRect(RenderMethod* renderer, const Point* pts, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& before) +{ + //sorting + Point tmp[4]; + Point min = {FLT_MAX, FLT_MAX}; + Point max = {0.0f, 0.0f}; -static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& viewport) + for (int i = 0; i < 4; ++i) { + tmp[i] = pts[i]; + if (rTransform) tmp[i] *= rTransform->m; + if (pTransform) tmp[i] *= pTransform->m; + if (tmp[i].x < min.x) min.x = tmp[i].x; + if (tmp[i].x > max.x) max.x = tmp[i].x; + if (tmp[i].y < min.y) min.y = tmp[i].y; + if (tmp[i].y > max.y) max.y = tmp[i].y; + } + + float region[4] = {float(before.x), float(before.x + before.w), float(before.y), float(before.y + before.h)}; + + //figure out if the clipper is a superset of the current viewport(before) region + if (min.x <= region[0] && max.x >= region[1] && min.y <= region[2] && max.y >= region[3]) { + //viewport region is same, nothing to do. + return Result::Success; + //figure out if the clipper is totally outside of the viewport + } else if (max.x <= region[0] || min.x >= region[1] || max.y <= region[2] || min.y >= region[3]) { + renderer->viewport({0, 0, 0, 0}); + return Result::Success; + } + return Result::InsufficientCondition; +} + + +static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& before) { /* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */ auto shape = static_cast(cmpTarget); @@ -58,9 +89,13 @@ static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform if (rTransform) rTransform->update(); - //No rotation and no skewing - if (pTransform && (!mathRightAngle(&pTransform->m) || mathSkewed(&pTransform->m))) return Result::InsufficientCondition; - if (rTransform && (!mathRightAngle(&rTransform->m) || mathSkewed(&rTransform->m))) return Result::InsufficientCondition; + //No rotation and no skewing, still can try out clipping the rect region. + auto tryClip = false; + + if (pTransform && (!mathRightAngle(&pTransform->m) || mathSkewed(&pTransform->m))) tryClip = true; + if (rTransform && (!mathRightAngle(&rTransform->m) || mathSkewed(&rTransform->m))) tryClip = true; + + if (tryClip) return _clipRect(renderer, pts, pTransform, rTransform, before); //Perpendicular Rectangle? auto pt1 = pts + 0; @@ -71,6 +106,8 @@ static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform if ((mathEqual(pt1->x, pt2->x) && mathEqual(pt2->y, pt3->y) && mathEqual(pt3->x, pt4->x) && mathEqual(pt1->y, pt4->y)) || (mathEqual(pt2->x, pt3->x) && mathEqual(pt1->y, pt2->y) && mathEqual(pt1->x, pt4->x) && mathEqual(pt3->y, pt4->y))) { + RenderRegion after; + auto v1 = *pt1; auto v2 = *pt3; @@ -85,25 +122,19 @@ static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform } //sorting - if (v1.x > v2.x) { - auto tmp = v2.x; - v2.x = v1.x; - v1.x = tmp; - } + if (v1.x > v2.x) std::swap(v1.x, v2.x); + if (v1.y > v2.y) std::swap(v1.y, v2.y); - if (v1.y > v2.y) { - auto tmp = v2.y; - v2.y = v1.y; - v1.y = tmp; - } + after.x = static_cast(v1.x); + after.y = static_cast(v1.y); + after.w = static_cast(ceil(v2.x - after.x)); + after.h = static_cast(ceil(v2.y - after.y)); - viewport.x = static_cast(v1.x); - viewport.y = static_cast(v1.y); - viewport.w = static_cast(ceil(v2.x - viewport.x)); - viewport.h = static_cast(ceil(v2.y - viewport.y)); + if (after.w < 0) after.w = 0; + if (after.h < 0) after.h = 0; - if (viewport.w < 0) viewport.w = 0; - if (viewport.h < 0) viewport.h = 0; + after.intersect(before); + renderer->viewport(after); return Result::Success; } @@ -264,11 +295,8 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT } } if (tryFastTrack) { - RenderRegion viewport2; - if ((compFastTrack = _compFastTrack(target, pTransform, target->pImpl->rTransform, viewport2)) == Result::Success) { - viewport = renderer->viewport(); - viewport2.intersect(viewport); - renderer->viewport(viewport2); + viewport = renderer->viewport(); + if ((compFastTrack = _compFastTrack(renderer, target, pTransform, target->pImpl->rTransform, viewport)) == Result::Success) { target->pImpl->ctxFlag |= ContextFlag::FastTrack; } } diff --git a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h index 58918e88f0e..93f8481707c 100644 --- a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h +++ b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h @@ -23,6 +23,8 @@ #ifndef _TVG_TASK_SCHEDULER_H_ #define _TVG_TASK_SCHEDULER_H_ +#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR + #include #include diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh index c0034ba888e..663d685d01f 100755 --- a/thirdparty/thorvg/update-thorvg.sh +++ b/thirdparty/thorvg/update-thorvg.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -VERSION=0.13.7 +VERSION=0.13.8 cd thirdparty/thorvg/ || true rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/