Merge pull request #93378 from akien-mga/thorvg-0.13.8
thorvg: Update to 0.13.8
This commit is contained in:
commit
1f134f3865
|
@ -15,5 +15,5 @@
|
||||||
// For internal debugging:
|
// For internal debugging:
|
||||||
//#define THORVG_LOG_ENABLED
|
//#define THORVG_LOG_ENABLED
|
||||||
|
|
||||||
#define THORVG_VERSION_STRING "0.13.7"
|
#define THORVG_VERSION_STRING "0.13.8"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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);
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#ifdef THORVG_THREAD_SUPPORT
|
#ifdef THORVG_THREAD_SUPPORT
|
||||||
|
|
||||||
|
#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace tvg {
|
namespace tvg {
|
||||||
|
|
|
@ -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, "pc")) parsedValue *= PX_PER_PC;
|
||||||
else if (strstr(str, "in")) parsedValue *= PX_PER_IN;
|
else if (strstr(str, "in")) parsedValue *= PX_PER_IN;
|
||||||
else if (strstr(str, "%")) {
|
else if (strstr(str, "%")) {
|
||||||
if (type == SvgParserLengthType::Vertical) parsedValue = (parsedValue / 100.0) * svgParse->global.h;
|
if (type == SvgParserLengthType::Vertical) parsedValue = (parsedValue / 100.0f) * svgParse->global.h;
|
||||||
else if (type == SvgParserLengthType::Horizontal) parsedValue = (parsedValue / 100.0) * svgParse->global.w;
|
else if (type == SvgParserLengthType::Horizontal) parsedValue = (parsedValue / 100.0f) * svgParse->global.w;
|
||||||
else //if other then it's radius
|
else //if other than it's radius
|
||||||
{
|
{
|
||||||
float max = svgParse->global.w;
|
float max = svgParse->global.w;
|
||||||
if (max < svgParse->global.h)
|
if (max < svgParse->global.h)
|
||||||
max = svgParse->global.h;
|
max = svgParse->global.h;
|
||||||
parsedValue = (parsedValue / 100.0) * max;
|
parsedValue = (parsedValue / 100.0f) * max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: Implement 'em', 'ex' attributes
|
//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;
|
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;
|
float _red = 0, _green = 0, _blue = 0;
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
|
||||||
if (mathZero(satuation)) _red = _green = _blue = brightness;
|
if (mathZero(saturation)) _red = _green = _blue = brightness;
|
||||||
else {
|
else {
|
||||||
if (mathEqual(hue, 360.0)) hue = 0.0f;
|
if (mathEqual(hue, 360.0)) hue = 0.0f;
|
||||||
hue /= 60.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;
|
p = brightness + brightness - v;
|
||||||
|
|
||||||
if (!mathZero(v)) sv = (v - p) / 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;
|
unsigned char tr, tg, tb;
|
||||||
|
|
||||||
if (len == 4 && str[0] == '#') {
|
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])) {
|
if (isxdigit(str[1]) && isxdigit(str[2]) && isxdigit(str[3])) {
|
||||||
char tmp[3] = { '\0', '\0', '\0' };
|
char tmp[3] = { '\0', '\0', '\0' };
|
||||||
tmp[0] = str[1];
|
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;
|
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] == ')') {
|
} 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;
|
float th, ts, tb;
|
||||||
const char *content, *hue, *satuation, *brightness;
|
const char *content, *hue, *saturation, *brightness;
|
||||||
content = str + 4;
|
content = str + 4;
|
||||||
content = _skipSpace(content, nullptr);
|
content = _skipSpace(content, nullptr);
|
||||||
if (_parseNumber(&content, &hue, &th) && hue) {
|
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 = _skipSpace(hue, nullptr);
|
||||||
hue = (char*)_skipComma(hue);
|
hue = (char*)_skipComma(hue);
|
||||||
hue = _skipSpace(hue, nullptr);
|
hue = _skipSpace(hue, nullptr);
|
||||||
if (_parseNumber(&hue, &satuation, &ts) && satuation && *satuation == '%') {
|
if (_parseNumber(&hue, &saturation, &ts) && saturation && *saturation == '%') {
|
||||||
ts /= 100.0f;
|
ts /= 100.0f;
|
||||||
satuation = _skipSpace(satuation + 1, nullptr);
|
saturation = _skipSpace(saturation + 1, nullptr);
|
||||||
satuation = (char*)_skipComma(satuation);
|
saturation = (char*)_skipComma(saturation);
|
||||||
satuation = _skipSpace(satuation, nullptr);
|
saturation = _skipSpace(saturation, nullptr);
|
||||||
if (_parseNumber(&satuation, &brightness, &tb) && brightness && *brightness == '%') {
|
if (_parseNumber(&saturation, &brightness, &tb) && brightness && *brightness == '%') {
|
||||||
tb /= 100.0f;
|
tb /= 100.0f;
|
||||||
brightness = _skipSpace(brightness + 1, nullptr);
|
brightness = _skipSpace(brightness + 1, nullptr);
|
||||||
if (brightness && brightness[0] == ')' && brightness[1] == '\0') {
|
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
|
static constexpr struct
|
||||||
{
|
{
|
||||||
const char* tag;
|
const char* tag;
|
||||||
|
@ -2134,7 +2199,8 @@ static constexpr struct
|
||||||
{"rect", sizeof("rect"), _createRectNode},
|
{"rect", sizeof("rect"), _createRectNode},
|
||||||
{"polyline", sizeof("polyline"), _createPolylineNode},
|
{"polyline", sizeof("polyline"), _createPolylineNode},
|
||||||
{"line", sizeof("line"), _createLineNode},
|
{"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;
|
to->node.use.symbol = from->node.use.symbol;
|
||||||
break;
|
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: {
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3174,27 +3254,12 @@ static void _clonePostponedNodes(Array<SvgNodeIdPair>* 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)
|
static void _svgLoaderParserXmlClose(SvgLoaderData* loader, const char* content)
|
||||||
{
|
{
|
||||||
content = _skipSpace(content, nullptr);
|
content = _skipSpace(content, nullptr);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < sizeof(popArray) / sizeof(popArray[0]); i++) {
|
for (unsigned int i = 0; i < sizeof(groupTags) / sizeof(groupTags[0]); i++) {
|
||||||
if (!strncmp(content, popArray[i].tag, popArray[i].sz - 1)) {
|
if (!strncmp(content, groupTags[i].tag, groupTags[i].sz - 1)) {
|
||||||
loader->stack.pop();
|
loader->stack.pop();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3259,7 +3324,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
|
||||||
node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes);
|
node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes);
|
||||||
loader->cssStyle = node;
|
loader->cssStyle = node;
|
||||||
loader->doc->node.doc.style = node;
|
loader->doc->node.doc.style = node;
|
||||||
loader->style = true;
|
loader->openedTag = OpenedTagType::Style;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes);
|
node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes);
|
||||||
|
@ -3275,9 +3340,12 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
|
||||||
else parent = loader->doc;
|
else parent = loader->doc;
|
||||||
node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes);
|
node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes);
|
||||||
if (node && !empty) {
|
if (node && !empty) {
|
||||||
auto defs = _createDefsNode(loader, nullptr, nullptr, 0, nullptr);
|
if (!strcmp(tagName, "text")) loader->openedTag = OpenedTagType::Text;
|
||||||
loader->stack.push(defs);
|
else {
|
||||||
loader->currentGraphicsNode = node;
|
auto defs = _createDefsNode(loader, nullptr, nullptr, 0, nullptr);
|
||||||
|
loader->stack.push(defs);
|
||||||
|
loader->currentGraphicsNode = node;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if ((gradientMethod = _findGradientFactory(tagName))) {
|
} else if ((gradientMethod = _findGradientFactory(tagName))) {
|
||||||
SvgStyleGradient* gradient;
|
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)
|
static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* content, unsigned int length)
|
||||||
{
|
{
|
||||||
char* tag;
|
char* tag;
|
||||||
|
@ -3342,7 +3419,7 @@ static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* conte
|
||||||
free(tag);
|
free(tag);
|
||||||
free(name);
|
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::Data:
|
||||||
case SimpleXMLType::CData: {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case SimpleXMLType::DoctypeChild: {
|
case SimpleXMLType::DoctypeChild: {
|
||||||
|
@ -3587,6 +3665,11 @@ static void _freeNode(SvgNode* node)
|
||||||
free(node->node.image.href);
|
free(node->node.image.href);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SvgNodeType::Text: {
|
||||||
|
free(node->node.text.text);
|
||||||
|
free(node->node.text.fontFamily);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -374,6 +374,14 @@ struct SvgCssStyleNode
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SvgTextNode
|
||||||
|
{
|
||||||
|
char* text;
|
||||||
|
char* fontFamily;
|
||||||
|
float x, y;
|
||||||
|
float fontSize;
|
||||||
|
};
|
||||||
|
|
||||||
struct SvgLinearGradient
|
struct SvgLinearGradient
|
||||||
{
|
{
|
||||||
float x1;
|
float x1;
|
||||||
|
@ -518,6 +526,7 @@ struct SvgNode
|
||||||
SvgClipNode clip;
|
SvgClipNode clip;
|
||||||
SvgCssStyleNode cssStyle;
|
SvgCssStyleNode cssStyle;
|
||||||
SvgSymbolNode symbol;
|
SvgSymbolNode symbol;
|
||||||
|
SvgTextNode text;
|
||||||
} node;
|
} node;
|
||||||
~SvgNode();
|
~SvgNode();
|
||||||
};
|
};
|
||||||
|
@ -545,11 +554,18 @@ struct SvgNodeIdPair
|
||||||
char *id;
|
char *id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class OpenedTagType : uint8_t
|
||||||
|
{
|
||||||
|
Other = 0,
|
||||||
|
Style,
|
||||||
|
Text
|
||||||
|
};
|
||||||
|
|
||||||
struct SvgLoaderData
|
struct SvgLoaderData
|
||||||
{
|
{
|
||||||
Array<SvgNode*> stack;
|
Array<SvgNode*> stack;
|
||||||
SvgNode* doc = nullptr;
|
SvgNode* doc = nullptr;
|
||||||
SvgNode* def = nullptr;
|
SvgNode* def = nullptr; //also used to store nested graphic nodes
|
||||||
SvgNode* cssStyle = nullptr;
|
SvgNode* cssStyle = nullptr;
|
||||||
Array<SvgStyleGradient*> gradients;
|
Array<SvgStyleGradient*> gradients;
|
||||||
SvgStyleGradient* latestGradient = nullptr; //For stops
|
SvgStyleGradient* latestGradient = nullptr; //For stops
|
||||||
|
@ -559,7 +575,7 @@ struct SvgLoaderData
|
||||||
Array<char*> images; //embedded images
|
Array<char*> images; //embedded images
|
||||||
int level = 0;
|
int level = 0;
|
||||||
bool result = false;
|
bool result = false;
|
||||||
bool style = false;
|
OpenedTagType openedTag = OpenedTagType::Other;
|
||||||
SvgNode* currentGraphicsNode = nullptr;
|
SvgNode* currentGraphicsNode = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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)
|
static void _transformMultiply(const Matrix* mBBox, Matrix* gradTransf)
|
||||||
{
|
{
|
||||||
gradTransf->e13 = gradTransf->e13 * mBBox->e11 + mBBox->e13;
|
gradTransf->e13 = gradTransf->e13 * mBBox->e11 + mBBox->e13;
|
||||||
|
@ -79,7 +87,7 @@ static void _transformMultiply(const Matrix* mBBox, Matrix* gradTransf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static unique_ptr<LinearGradient> _applyLinearGradientProperty(SvgStyleGradient* g, const Shape* vg, const Box& vBox, int opacity)
|
static unique_ptr<LinearGradient> _applyLinearGradientProperty(SvgStyleGradient* g, const Box& vBox, int opacity)
|
||||||
{
|
{
|
||||||
Fill::ColorStop* stops;
|
Fill::ColorStop* stops;
|
||||||
int stopCount = 0;
|
int stopCount = 0;
|
||||||
|
@ -134,7 +142,7 @@ static unique_ptr<LinearGradient> _applyLinearGradientProperty(SvgStyleGradient*
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static unique_ptr<RadialGradient> _applyRadialGradientProperty(SvgStyleGradient* g, const Shape* vg, const Box& vBox, int opacity)
|
static unique_ptr<RadialGradient> _applyRadialGradientProperty(SvgStyleGradient* g, const Box& vBox, int opacity)
|
||||||
{
|
{
|
||||||
Fill::ColorStop *stops;
|
Fill::ColorStop *stops;
|
||||||
int stopCount = 0;
|
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->userSpace) bBox = _boundingBox(vg);
|
||||||
|
|
||||||
if (style->fill.paint.gradient->type == SvgGradientType::Linear) {
|
if (style->fill.paint.gradient->type == SvgGradientType::Linear) {
|
||||||
auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, vg, bBox, style->fill.opacity);
|
auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, bBox, style->fill.opacity);
|
||||||
vg->fill(std::move(linear));
|
vg->fill(std::move(linear));
|
||||||
} else if (style->fill.paint.gradient->type == SvgGradientType::Radial) {
|
} else if (style->fill.paint.gradient->type == SvgGradientType::Radial) {
|
||||||
auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, vg, bBox, style->fill.opacity);
|
auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, bBox, style->fill.opacity);
|
||||||
vg->fill(std::move(radial));
|
vg->fill(std::move(radial));
|
||||||
}
|
}
|
||||||
} else if (style->fill.paint.url) {
|
} else if (style->fill.paint.url) {
|
||||||
//TODO: Apply the color pointed by url
|
//TODO: Apply the color pointed by url
|
||||||
|
TVGLOG("SVG", "The fill's url not supported.");
|
||||||
} else if (style->fill.paint.curColor) {
|
} else if (style->fill.paint.curColor) {
|
||||||
//Apply the current style color
|
//Apply the current style color
|
||||||
vg->fill(style->color.r, style->color.g, style->color.b, style->fill.opacity);
|
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->userSpace) bBox = _boundingBox(vg);
|
||||||
|
|
||||||
if (style->stroke.paint.gradient->type == SvgGradientType::Linear) {
|
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));
|
vg->stroke(std::move(linear));
|
||||||
} else if (style->stroke.paint.gradient->type == SvgGradientType::Radial) {
|
} 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));
|
vg->stroke(std::move(radial));
|
||||||
}
|
}
|
||||||
} else if (style->stroke.paint.url) {
|
} else if (style->stroke.paint.url) {
|
||||||
//TODO: Apply the color pointed by url
|
//TODO: Apply the color pointed by url
|
||||||
|
TVGLOG("SVG", "The stroke's url not supported.");
|
||||||
} else if (style->stroke.paint.curColor) {
|
} else if (style->stroke.paint.curColor) {
|
||||||
//Apply the current style color
|
//Apply the current style color
|
||||||
vg->stroke(style->color.r, style->color.g, style->color.b, style->stroke.opacity);
|
vg->stroke(style->color.r, style->color.g, style->color.b, style->stroke.opacity);
|
||||||
|
@ -772,6 +782,61 @@ static unique_ptr<Scene> _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<Text> _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<Scene> _sceneBuildHelper(SvgLoaderData& loaderData, const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, int depth, bool* isMaskWhite)
|
static unique_ptr<Scene> _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.
|
/* Exception handling: Prevent invalid SVG data input.
|
||||||
|
@ -800,6 +865,9 @@ static unique_ptr<Scene> _sceneBuildHelper(SvgLoaderData& loaderData, const SvgN
|
||||||
scene->push(std::move(image));
|
scene->push(std::move(image));
|
||||||
if (isMaskWhite) *isMaskWhite = false;
|
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) {
|
} else if ((*child)->type != SvgNodeType::Mask) {
|
||||||
auto shape = _shapeBuildHelper(loaderData, *child, vBox, svgPath);
|
auto shape = _shapeBuildHelper(loaderData, *child, vBox, svgPath);
|
||||||
if (shape) {
|
if (shape) {
|
||||||
|
|
|
@ -26,18 +26,6 @@
|
||||||
#include "tvgCommon.h"
|
#include "tvgCommon.h"
|
||||||
#include "tvgRender.h"
|
#include "tvgRender.h"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
#include <sys/time.h>
|
|
||||||
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_POINT 0
|
||||||
#define SW_CURVE_TYPE_CUBIC 1
|
#define SW_CURVE_TYPE_CUBIC 1
|
||||||
#define SW_ANGLE_PI (180L << 16)
|
#define SW_ANGLE_PI (180L << 16)
|
||||||
|
|
|
@ -34,14 +34,6 @@ struct AASpans
|
||||||
int32_t yEnd;
|
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
|
//Careful! Shared resource, No support threading
|
||||||
static float dudx, dvdx;
|
static float dudx, dvdx;
|
||||||
static float dxdya, dxdyb, dudya, dvdya;
|
static float dxdya, dxdyb, dudya, dvdya;
|
||||||
|
@ -85,7 +77,7 @@ static bool _rasterMaskedPolygonImageSegment(SwSurface* surface, const SwImage*
|
||||||
int32_t sh = image->h;
|
int32_t sh = image->h;
|
||||||
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
|
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
|
||||||
int32_t vv = 0, uu = 0;
|
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;
|
float dx, u, v, iptr;
|
||||||
SwSpan* span = nullptr; //used only when rle based.
|
SwSpan* span = nullptr; //used only when rle based.
|
||||||
|
|
||||||
|
@ -113,7 +105,7 @@ static bool _rasterMaskedPolygonImageSegment(SwSurface* surface, const SwImage*
|
||||||
|
|
||||||
if (!region) {
|
if (!region) {
|
||||||
minx = INT32_MAX;
|
minx = INT32_MAX;
|
||||||
maxx = INT32_MIN;
|
maxx = 0;
|
||||||
//one single row, could be consisted of multiple spans.
|
//one single row, could be consisted of multiple spans.
|
||||||
while (span->y == y && spanIdx < image->rle->size) {
|
while (span->y == y && spanIdx < image->rle->size) {
|
||||||
if (minx > span->x) minx = span->x;
|
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 dw = surface->stride;
|
||||||
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
|
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
|
||||||
int32_t vv = 0, uu = 0;
|
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;
|
float dx, u, v, iptr;
|
||||||
uint32_t* buf;
|
uint32_t* buf;
|
||||||
SwSpan* span = nullptr; //used only when rle based.
|
SwSpan* span = nullptr; //used only when rle based.
|
||||||
|
@ -307,7 +299,7 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage
|
||||||
|
|
||||||
if (!region) {
|
if (!region) {
|
||||||
minx = INT32_MAX;
|
minx = INT32_MAX;
|
||||||
maxx = INT32_MIN;
|
maxx = 0;
|
||||||
//one single row, could be consisted of multiple spans.
|
//one single row, could be consisted of multiple spans.
|
||||||
while (span->y == y && spanIdx < image->rle->size) {
|
while (span->y == y && spanIdx < image->rle->size) {
|
||||||
if (minx > span->x) minx = span->x;
|
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 dw = surface->stride;
|
||||||
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
|
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
|
||||||
int32_t vv = 0, uu = 0;
|
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;
|
float dx, u, v, iptr;
|
||||||
uint32_t* buf;
|
uint32_t* buf;
|
||||||
SwSpan* span = nullptr; //used only when rle based.
|
SwSpan* span = nullptr; //used only when rle based.
|
||||||
|
@ -489,7 +481,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
|
||||||
|
|
||||||
if (!region) {
|
if (!region) {
|
||||||
minx = INT32_MAX;
|
minx = INT32_MAX;
|
||||||
maxx = INT32_MIN;
|
maxx = 0;
|
||||||
//one single row, could be consisted of multiple spans.
|
//one single row, could be consisted of multiple spans.
|
||||||
while (span->y == y && spanIdx < image->rle->size) {
|
while (span->y == y && spanIdx < image->rle->size) {
|
||||||
if (minx > span->x) minx = span->x;
|
if (minx > span->x) minx = span->x;
|
||||||
|
@ -650,28 +642,27 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const
|
||||||
|
|
||||||
float off_y;
|
float off_y;
|
||||||
float dxdy[3] = {0.0f, 0.0f, 0.0f};
|
float dxdy[3] = {0.0f, 0.0f, 0.0f};
|
||||||
float tmp;
|
|
||||||
|
|
||||||
auto upper = false;
|
auto upper = false;
|
||||||
|
|
||||||
//Sort the vertices in ascending Y order
|
//Sort the vertices in ascending Y order
|
||||||
if (y[0] > y[1]) {
|
if (y[0] > y[1]) {
|
||||||
_swap(x[0], x[1], tmp);
|
std::swap(x[0], x[1]);
|
||||||
_swap(y[0], y[1], tmp);
|
std::swap(y[0], y[1]);
|
||||||
_swap(u[0], u[1], tmp);
|
std::swap(u[0], u[1]);
|
||||||
_swap(v[0], v[1], tmp);
|
std::swap(v[0], v[1]);
|
||||||
}
|
}
|
||||||
if (y[0] > y[2]) {
|
if (y[0] > y[2]) {
|
||||||
_swap(x[0], x[2], tmp);
|
std::swap(x[0], x[2]);
|
||||||
_swap(y[0], y[2], tmp);
|
std::swap(y[0], y[2]);
|
||||||
_swap(u[0], u[2], tmp);
|
std::swap(u[0], u[2]);
|
||||||
_swap(v[0], v[2], tmp);
|
std::swap(v[0], v[2]);
|
||||||
}
|
}
|
||||||
if (y[1] > y[2]) {
|
if (y[1] > y[2]) {
|
||||||
_swap(x[1], x[2], tmp);
|
std::swap(x[1], x[2]);
|
||||||
_swap(y[1], y[2], tmp);
|
std::swap(y[1], y[2]);
|
||||||
_swap(u[1], u[2], tmp);
|
std::swap(u[1], u[2]);
|
||||||
_swap(v[1], v[2], tmp);
|
std::swap(v[1], v[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Y indexes
|
//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++) {
|
for (int32_t i = 0; i < height; i++) {
|
||||||
aaSpans->lines[i].x[0] = INT32_MAX;
|
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;
|
return aaSpans;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ struct SwShapeTask : SwTask
|
||||||
Additionally, the stroke style should not be dashed. */
|
Additionally, the stroke style should not be dashed. */
|
||||||
bool antialiasing(float strokeWidth)
|
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()
|
float validStrokeWidth()
|
||||||
|
|
|
@ -420,6 +420,7 @@ static bool _axisAlignedRect(const SwOutline* outline)
|
||||||
{
|
{
|
||||||
//Fast Track: axis-aligned rectangle?
|
//Fast Track: axis-aligned rectangle?
|
||||||
if (outline->pts.count != 5) return false;
|
if (outline->pts.count != 5) return false;
|
||||||
|
if (outline->types[2] == SW_CURVE_TYPE_CUBIC) return false;
|
||||||
|
|
||||||
auto pt1 = outline->pts.data + 0;
|
auto pt1 = outline->pts.data + 0;
|
||||||
auto pt2 = outline->pts.data + 1;
|
auto pt2 = outline->pts.data + 1;
|
||||||
|
|
|
@ -87,4 +87,16 @@ uint16_t THORVG_VERSION_NUMBER();
|
||||||
#define P(A) ((A)->pImpl) //Access to pimpl.
|
#define P(A) ((A)->pImpl) //Access to pimpl.
|
||||||
#define PP(A) (((Paint*)(A))->pImpl) //Access to pimpl.
|
#define PP(A) (((Paint*)(A))->pImpl) //Access to pimpl.
|
||||||
|
|
||||||
|
|
||||||
|
//for debugging
|
||||||
|
#if 0
|
||||||
|
#include <sys/time.h>
|
||||||
|
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_
|
#endif //_TVG_COMMON_H_
|
||||||
|
|
|
@ -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. */
|
/* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */
|
||||||
auto shape = static_cast<Shape*>(cmpTarget);
|
auto shape = static_cast<Shape*>(cmpTarget);
|
||||||
|
@ -58,9 +89,13 @@ static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform
|
||||||
|
|
||||||
if (rTransform) rTransform->update();
|
if (rTransform) rTransform->update();
|
||||||
|
|
||||||
//No rotation and no skewing
|
//No rotation and no skewing, still can try out clipping the rect region.
|
||||||
if (pTransform && (!mathRightAngle(&pTransform->m) || mathSkewed(&pTransform->m))) return Result::InsufficientCondition;
|
auto tryClip = false;
|
||||||
if (rTransform && (!mathRightAngle(&rTransform->m) || mathSkewed(&rTransform->m))) return Result::InsufficientCondition;
|
|
||||||
|
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?
|
//Perpendicular Rectangle?
|
||||||
auto pt1 = pts + 0;
|
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)) ||
|
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))) {
|
(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 v1 = *pt1;
|
||||||
auto v2 = *pt3;
|
auto v2 = *pt3;
|
||||||
|
|
||||||
|
@ -85,25 +122,19 @@ static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform
|
||||||
}
|
}
|
||||||
|
|
||||||
//sorting
|
//sorting
|
||||||
if (v1.x > v2.x) {
|
if (v1.x > v2.x) std::swap(v1.x, v2.x);
|
||||||
auto tmp = v2.x;
|
if (v1.y > v2.y) std::swap(v1.y, v2.y);
|
||||||
v2.x = v1.x;
|
|
||||||
v1.x = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v1.y > v2.y) {
|
after.x = static_cast<int32_t>(v1.x);
|
||||||
auto tmp = v2.y;
|
after.y = static_cast<int32_t>(v1.y);
|
||||||
v2.y = v1.y;
|
after.w = static_cast<int32_t>(ceil(v2.x - after.x));
|
||||||
v1.y = tmp;
|
after.h = static_cast<int32_t>(ceil(v2.y - after.y));
|
||||||
}
|
|
||||||
|
|
||||||
viewport.x = static_cast<int32_t>(v1.x);
|
if (after.w < 0) after.w = 0;
|
||||||
viewport.y = static_cast<int32_t>(v1.y);
|
if (after.h < 0) after.h = 0;
|
||||||
viewport.w = static_cast<int32_t>(ceil(v2.x - viewport.x));
|
|
||||||
viewport.h = static_cast<int32_t>(ceil(v2.y - viewport.y));
|
|
||||||
|
|
||||||
if (viewport.w < 0) viewport.w = 0;
|
after.intersect(before);
|
||||||
if (viewport.h < 0) viewport.h = 0;
|
renderer->viewport(after);
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
@ -264,11 +295,8 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tryFastTrack) {
|
if (tryFastTrack) {
|
||||||
RenderRegion viewport2;
|
viewport = renderer->viewport();
|
||||||
if ((compFastTrack = _compFastTrack(target, pTransform, target->pImpl->rTransform, viewport2)) == Result::Success) {
|
if ((compFastTrack = _compFastTrack(renderer, target, pTransform, target->pImpl->rTransform, viewport)) == Result::Success) {
|
||||||
viewport = renderer->viewport();
|
|
||||||
viewport2.intersect(viewport);
|
|
||||||
renderer->viewport(viewport2);
|
|
||||||
target->pImpl->ctxFlag |= ContextFlag::FastTrack;
|
target->pImpl->ctxFlag |= ContextFlag::FastTrack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
#ifndef _TVG_TASK_SCHEDULER_H_
|
#ifndef _TVG_TASK_SCHEDULER_H_
|
||||||
#define _TVG_TASK_SCHEDULER_H_
|
#define _TVG_TASK_SCHEDULER_H_
|
||||||
|
|
||||||
|
#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash -e
|
#!/bin/bash -e
|
||||||
|
|
||||||
VERSION=0.13.7
|
VERSION=0.13.8
|
||||||
|
|
||||||
cd thirdparty/thorvg/ || true
|
cd thirdparty/thorvg/ || true
|
||||||
rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/
|
rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/
|
||||||
|
|
Loading…
Reference in New Issue