svg: clean & neat code++

no logical changes
This commit is contained in:
Hermet Park 2025-03-17 17:35:34 +09:00
parent 468a1db1fa
commit ad888019e9
3 changed files with 275 additions and 372 deletions

View file

@ -45,9 +45,12 @@
#define STR_AS(A, B) !strcmp((A), (B)) #define STR_AS(A, B) !strcmp((A), (B))
typedef bool (*parseAttributes)(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data); typedef bool (*parseAttributes)(const char* buf, unsigned bufLength, xmlAttributeCb func, const void* data);
typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func); typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func);
typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength); typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength);
static bool _parseStyleAttr(void* data, const char* key, const char* value);
static bool _parseStyleAttr(void* data, const char* key, const char* value, bool style);
static char* _skipSpace(const char* str, const char* end) static char* _skipSpace(const char* str, const char* end)
{ {
@ -62,7 +65,6 @@ static char* _copyId(const char* str)
{ {
if (!str) return nullptr; if (!str) return nullptr;
if (strlen(str) == 0) return nullptr; if (strlen(str) == 0) return nullptr;
return duplicate(str); return duplicate(str);
} }
@ -77,7 +79,7 @@ static const char* _skipComma(const char* content)
static bool _parseNumber(const char** content, const char** end, float* number) static bool _parseNumber(const char** content, const char** end, float* number)
{ {
const char* _end = end ? *end : nullptr; auto _end = end ? *end : nullptr;
*number = toFloat(*content, (char**)&_end); *number = toFloat(*content, (char**)&_end);
//If the start of string is not number //If the start of string is not number
@ -166,7 +168,7 @@ static float _gradientToFloat(const SvgParser* svgParse, const char* str, bool&
{ {
char* end = nullptr; char* end = nullptr;
float parsedValue = toFloat(str, &end); auto parsedValue = toFloat(str, &end);
isPercentage = false; isPercentage = false;
if (strstr(str, "%")) { if (strstr(str, "%")) {
@ -189,7 +191,7 @@ static float _toOffset(const char* str)
char* end = nullptr; char* end = nullptr;
auto strEnd = str + strlen(str); auto strEnd = str + strlen(str);
float parsedValue = toFloat(str, &end); auto parsedValue = toFloat(str, &end);
end = _skipSpace(end, nullptr); end = _skipSpace(end, nullptr);
auto ptr = strstr(str, "%"); auto ptr = strstr(str, "%");
@ -206,7 +208,7 @@ static float _toOffset(const char* str)
static int _toOpacity(const char* str) static int _toOpacity(const char* str)
{ {
char* end = nullptr; char* end = nullptr;
float opacity = toFloat(str, &end); auto opacity = toFloat(str, &end);
if (end) { if (end) {
if (end[0] == '%' && end[1] == '\0') return lrint(opacity * 2.55f); if (end[0] == '%' && end[1] == '\0') return lrint(opacity * 2.55f);
@ -228,9 +230,9 @@ static SvgMaskType _toMaskType(const char* str)
//If any is omitted, will be rendered in its default order after the specified ones. //If any is omitted, will be rendered in its default order after the specified ones.
static bool _toPaintOrder(const char* str) static bool _toPaintOrder(const char* str)
{ {
uint8_t position = 1; auto position = 1;
uint8_t strokePosition = 0; auto strokePosition = 0;
uint8_t fillPosition = 0; auto fillPosition = 0;
while (*str != '\0') { while (*str != '\0') {
str = _skipSpace(str, nullptr); str = _skipSpace(str, nullptr);
@ -334,7 +336,7 @@ static void _parseDashArray(SvgLoaderData* loader, const char *str, SvgDash* das
while (*str) { while (*str) {
str = _skipComma(str); str = _skipComma(str);
float parsedValue = toFloat(str, &end); auto parsedValue = toFloat(str, &end);
if (str == end) break; if (str == end) break;
if (parsedValue <= 0.0f) break; if (parsedValue <= 0.0f) break;
if (*end == '%') { if (*end == '%') {
@ -398,9 +400,7 @@ static size_t _srcFromUrl(const char* url, char*& src)
static unsigned char _parseColor(const char* value, char** end) static unsigned char _parseColor(const char* value, char** end)
{ {
float r; auto r = toFloat(value, end);
r = toFloat(value, end);
*end = _skipSpace(*end, nullptr); *end = _skipSpace(*end, nullptr);
if (**end == '%') { if (**end == '%') {
r = 255 * r / 100; r = 255 * r / 100;
@ -574,79 +574,77 @@ static constexpr struct
static bool _hslToRgb(float hue, float saturation, 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; auto r = 0.0f, g = 0.0f, b = 0.0f;
auto i = 0;
float sv, vsf, f, p, q, t, v;
float _red = 0, _green = 0, _blue = 0;
uint32_t i = 0;
while (hue < 0) hue += 360.0f; while (hue < 0) hue += 360.0f;
hue = fmod(hue, 360.0f); hue = fmod(hue, 360.0f);
saturation = saturation > 0 ? std::min(saturation, 1.0f) : 0.0f; saturation = saturation > 0 ? std::min(saturation, 1.0f) : 0.0f;
brightness = brightness > 0 ? std::min(brightness, 1.0f) : 0.0f; brightness = brightness > 0 ? std::min(brightness, 1.0f) : 0.0f;
if (tvg::zero(saturation)) _red = _green = _blue = brightness; if (tvg::zero(saturation)) r = g = b = brightness;
else { else {
if (tvg::equal(hue, 360.0)) hue = 0.0f; if (tvg::equal(hue, 360.0)) hue = 0.0f;
hue /= 60.0f; hue /= 60.0f;
v = (brightness <= 0.5f) ? (brightness * (1.0f + saturation)) : (brightness + saturation - (brightness * saturation)); auto v = (brightness <= 0.5f) ? (brightness * (1.0f + saturation)) : (brightness + saturation - (brightness * saturation));
p = brightness + brightness - v; auto p = brightness + brightness - v;
float sv;
if (!tvg::zero(v)) sv = (v - p) / v; if (!tvg::zero(v)) sv = (v - p) / v;
else sv = 0; else sv = 0.0f;
i = static_cast<uint8_t>(hue); i = static_cast<uint8_t>(hue);
f = hue - i; auto f = hue - i;
vsf = v * sv * f; auto vsf = v * sv * f;
t = p + vsf; auto t = p + vsf;
q = v - vsf; auto q = v - vsf;
switch (i) { switch (i) {
case 0: { case 0: {
_red = v; r = v;
_green = t; g = t;
_blue = p; b = p;
break; break;
} }
case 1: { case 1: {
_red = q; r = q;
_green = v; g = v;
_blue = p; b = p;
break; break;
} }
case 2: { case 2: {
_red = p; r = p;
_green = v; g = v;
_blue = t; b = t;
break; break;
} }
case 3: { case 3: {
_red = p; r = p;
_green = q; g = q;
_blue = v; b = v;
break; break;
} }
case 4: { case 4: {
_red = t; r = t;
_green = p; g = p;
_blue = v; b = v;
break; break;
} }
case 5: { case 5: {
_red = v; r = v;
_green = p; g = p;
_blue = q; b = q;
break; break;
} }
} }
} }
*red = (uint8_t)nearbyint(_red * 255.0f); *red = (uint8_t)nearbyint(r * 255.0f);
*green = (uint8_t)nearbyint(_green * 255.0f); *green = (uint8_t)nearbyint(g * 255.0f);
*blue = (uint8_t)nearbyint(_blue * 255.0f); *blue = (uint8_t)nearbyint(b * 255.0f);
return true; return true;
} }
@ -654,9 +652,7 @@ static bool _hslToRgb(float hue, float saturation, float brightness, uint8_t* re
static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char** ref) static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char** ref)
{ {
unsigned int len = strlen(str); auto len = strlen(str);
char *red, *green, *blue;
unsigned char tr, tg, tb;
if (len == 4 && str[0] == '#') { if (len == 4 && str[0] == '#') {
//Case for "#456" should be interpreted as "#445566" //Case for "#456" should be interpreted as "#445566"
@ -688,11 +684,12 @@ 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] == 'r' || str[0] == 'R') && (str[1] == 'g' || str[1] == 'G') && (str[2] == 'b' || str[2] == 'B') && str[3] == '(' && str[len - 1] == ')') { } else if (len >= 10 && (str[0] == 'r' || str[0] == 'R') && (str[1] == 'g' || str[1] == 'G') && (str[2] == 'b' || str[2] == 'B') && str[3] == '(' && str[len - 1] == ')') {
tr = _parseColor(str + 4, &red); char *red, *green, *blue;
auto tr = _parseColor(str + 4, &red);
if (red && *red == ',') { if (red && *red == ',') {
tg = _parseColor(red + 1, &green); auto tg = _parseColor(red + 1, &green);
if (green && *green == ',') { if (green && *green == ',') {
tb = _parseColor(green + 1, &blue); auto tb = _parseColor(green + 1, &blue);
if (blue && blue[0] == ')' && blue[1] == '\0') { if (blue && blue[0] == ')' && blue[1] == '\0') {
*r = tr; *r = tr;
*g = tg; *g = tg;
@ -747,10 +744,10 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
static char* _parseNumbersArray(char* str, float* points, int* ptCount, int len) static char* _parseNumbersArray(char* str, float* points, int* ptCount, int len)
{ {
int count = 0; int count = 0;
char* end = nullptr;
str = _skipSpace(str, nullptr); str = _skipSpace(str, nullptr);
while ((count < len) && (isdigit(*str) || *str == '-' || *str == '+' || *str == '.')) { while ((count < len) && (isdigit(*str) || *str == '-' || *str == '+' || *str == '.')) {
char* end = nullptr;
points[count++] = toFloat(str, &end); points[count++] = toFloat(str, &end);
str = end; str = end;
str = _skipSpace(str, nullptr); str = _skipSpace(str, nullptr);
@ -807,8 +804,8 @@ static Matrix* _parseTransformationMatrix(const char* value)
float points[POINT_CNT]; float points[POINT_CNT];
int ptCount = 0; int ptCount = 0;
char* str = (char*)value; auto str = (char*)value;
char* end = str + strlen(str); auto end = str + strlen(str);
while (str < end) { while (str < end) {
auto state = MatrixState::Unknown; auto state = MatrixState::Unknown;
@ -902,10 +899,6 @@ static void _postpone(Array<SvgNodeIdPair>& nodes, SvgNode *node, char* id)
} }
static bool _parseStyleAttr(void* data, const char* key, const char* value);
static bool _parseStyleAttr(void* data, const char* key, const char* value, bool style);
static bool _attrParseSvgNode(void* data, const char* key, const char* value) static bool _attrParseSvgNode(void* data, const char* key, const char* value)
{ {
SvgLoaderData* loader = (SvgLoaderData*)data; SvgLoaderData* loader = (SvgLoaderData*)data;
@ -951,7 +944,7 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value)
} else if (STR_AS(key, "preserveAspectRatio")) { } else if (STR_AS(key, "preserveAspectRatio")) {
_parseAspectRatio(&value, &doc->align, &doc->meetOrSlice); _parseAspectRatio(&value, &doc->align, &doc->meetOrSlice);
} else if (STR_AS(key, "style")) { } else if (STR_AS(key, "style")) {
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); return xmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
#ifdef THORVG_LOG_ENABLED #ifdef THORVG_LOG_ENABLED
} else if ((STR_AS(key, "x") || STR_AS(key, "y")) && fabsf(toFloat(value, nullptr)) > FLOAT_EPSILON) { } else if ((STR_AS(key, "x") || STR_AS(key, "y")) && fabsf(toFloat(value, nullptr)) > FLOAT_EPSILON) {
TVGLOG("SVG", "Unsupported attributes used [Elements type: Svg][Attribute: %s][Value: %s]", key, value); TVGLOG("SVG", "Unsupported attributes used [Elements type: Svg][Attribute: %s][Value: %s]", key, value);
@ -1051,8 +1044,7 @@ static void _handleStrokeMiterlimitAttr(SvgLoaderData* loader, SvgNode* node, co
// https://www.w3.org/TR/SVG2/painting.html#LineJoin // https://www.w3.org/TR/SVG2/painting.html#LineJoin
// - A negative value for stroke-miterlimit must be treated as an illegal value. // - A negative value for stroke-miterlimit must be treated as an illegal value.
if (miterlimit < 0.0f) { if (miterlimit < 0.0f) {
TVGERR("SVG", "A stroke-miterlimit change (%f <- %f) with a negative value is omitted.", TVGERR("SVG", "A stroke-miterlimit change (%f <- %f) with a negative value is omitted.", node->style->stroke.miterlimit, miterlimit);
node->style->stroke.miterlimit, miterlimit);
return; return;
} }
@ -1261,7 +1253,7 @@ static bool _attrParseGNode(void* data, const char* key, const char* value)
SvgNode* node = loader->svgParse->node; SvgNode* node = loader->svgParse->node;
if (STR_AS(key, "style")) { if (STR_AS(key, "style")) {
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); return xmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (STR_AS(key, "transform")) { } else if (STR_AS(key, "transform")) {
node->transform = _parseTransformationMatrix(value); node->transform = _parseTransformationMatrix(value);
} else if (STR_AS(key, "id")) { } else if (STR_AS(key, "id")) {
@ -1292,7 +1284,7 @@ static bool _attrParseClipPathNode(void* data, const char* key, const char* valu
SvgClipNode* clip = &(node->node.clip); SvgClipNode* clip = &(node->node.clip);
if (STR_AS(key, "style")) { if (STR_AS(key, "style")) {
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); return xmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (STR_AS(key, "transform")) { } else if (STR_AS(key, "transform")) {
node->transform = _parseTransformationMatrix(value); node->transform = _parseTransformationMatrix(value);
} else if (STR_AS(key, "id")) { } else if (STR_AS(key, "id")) {
@ -1311,12 +1303,12 @@ static bool _attrParseClipPathNode(void* data, const char* key, const char* valu
static bool _attrParseMaskNode(void* data, const char* key, const char* value) static bool _attrParseMaskNode(void* data, const char* key, const char* value)
{ {
SvgLoaderData* loader = (SvgLoaderData*)data; auto loader = (SvgLoaderData*)data;
SvgNode* node = loader->svgParse->node; auto node = loader->svgParse->node;
SvgMaskNode* mask = &(node->node.mask); auto mask = &(node->node.mask);
if (STR_AS(key, "style")) { if (STR_AS(key, "style")) {
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); return xmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (STR_AS(key, "transform")) { } else if (STR_AS(key, "transform")) {
node->transform = _parseTransformationMatrix(value); node->transform = _parseTransformationMatrix(value);
} else if (STR_AS(key, "id")) { } else if (STR_AS(key, "id")) {
@ -1337,8 +1329,8 @@ static bool _attrParseMaskNode(void* data, const char* key, const char* value)
static bool _attrParseCssStyleNode(void* data, const char* key, const char* value) static bool _attrParseCssStyleNode(void* data, const char* key, const char* value)
{ {
SvgLoaderData* loader = (SvgLoaderData*)data; auto loader = (SvgLoaderData*)data;
SvgNode* node = loader->svgParse->node; auto node = loader->svgParse->node;
if (STR_AS(key, "id")) { if (STR_AS(key, "id")) {
if (value) tvg::free(node->id); if (value) tvg::free(node->id);
@ -1373,7 +1365,6 @@ static bool _attrParseSymbolNode(void* data, const char* key, const char* value)
} else { } else {
return _attrParseGNode(data, key, value); return _attrParseGNode(data, key, value);
} }
return true; return true;
} }
@ -1433,7 +1424,6 @@ static bool _attrParseFilterNode(void* data, const char* key, const char* value)
} else if (STR_AS(key, "filterUnits")) { } else if (STR_AS(key, "filterUnits")) {
if (STR_AS(value, "userSpaceOnUse")) filter->filterUserSpace = true; if (STR_AS(value, "userSpaceOnUse")) filter->filterUserSpace = true;
} }
return true; return true;
} }
@ -1484,22 +1474,13 @@ static SvgNode* _createNode(SvgNode* parent, SvgNodeType type)
{ {
SvgNode* node = tvg::calloc<SvgNode*>(1, sizeof(SvgNode)); SvgNode* node = tvg::calloc<SvgNode*>(1, sizeof(SvgNode));
if (!node) return nullptr;
//Default fill property //Default fill property
node->style = tvg::calloc<SvgStyleProperty*>(1, sizeof(SvgStyleProperty)); node->style = tvg::calloc<SvgStyleProperty*>(1, sizeof(SvgStyleProperty));
if (!node->style) {
tvg::free(node);
return nullptr;
}
//Set the default values other than 0/false: https://www.w3.org/TR/SVGTiny12/painting.html#SpecifyingPaint //Set the default values other than 0/false: https://www.w3.org/TR/SVGTiny12/painting.html#SpecifyingPaint
node->style->opacity = 255; node->style->opacity = 255;
node->style->fill.opacity = 255; node->style->fill.opacity = 255;
node->style->fill.fillRule = FillRule::NonZero; node->style->fill.fillRule = FillRule::NonZero;
node->style->stroke.paint.none = true; node->style->stroke.paint.none = true;
node->style->stroke.opacity = 255; node->style->stroke.opacity = 255;
node->style->stroke.width = 1; node->style->stroke.width = 1;
@ -1507,11 +1488,8 @@ static SvgNode* _createNode(SvgNode* parent, SvgNodeType type)
node->style->stroke.join = StrokeJoin::Miter; node->style->stroke.join = StrokeJoin::Miter;
node->style->stroke.miterlimit = 4.0f; node->style->stroke.miterlimit = 4.0f;
node->style->stroke.scale = 1.0; node->style->stroke.scale = 1.0;
node->style->paintOrder = _toPaintOrder("fill stroke"); node->style->paintOrder = _toPaintOrder("fill stroke");
node->style->display = true; node->style->display = true;
node->parent = parent; node->parent = parent;
node->type = type; node->type = type;
@ -1523,19 +1501,14 @@ static SvgNode* _createNode(SvgNode* parent, SvgNodeType type)
static SvgNode* _createDefsNode(TVG_UNUSED SvgLoaderData* loader, TVG_UNUSED SvgNode* parent, const char* buf, unsigned bufLength, TVG_UNUSED parseAttributes func) static SvgNode* _createDefsNode(TVG_UNUSED SvgLoaderData* loader, TVG_UNUSED SvgNode* parent, const char* buf, unsigned bufLength, TVG_UNUSED parseAttributes func)
{ {
if (loader->def && loader->doc->node.doc.defs) return loader->def; if (loader->def && loader->doc->node.doc.defs) return loader->def;
SvgNode* node = _createNode(nullptr, SvgNodeType::Defs); loader->def = loader->doc->node.doc.defs = _createNode(nullptr, SvgNodeType::Defs);
return loader->def;
loader->def = node;
loader->doc->node.doc.defs = node;
return node;
} }
static SvgNode* _createGNode(TVG_UNUSED SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) static SvgNode* _createGNode(TVG_UNUSED SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{ {
loader->svgParse->node = _createNode(parent, SvgNodeType::G); loader->svgParse->node = _createNode(parent, SvgNodeType::G);
if (!loader->svgParse->node) return nullptr;
func(buf, bufLength, _attrParseGNode, loader); func(buf, bufLength, _attrParseGNode, loader);
return loader->svgParse->node; return loader->svgParse->node;
} }
@ -1544,8 +1517,7 @@ static SvgNode* _createGNode(TVG_UNUSED SvgLoaderData* loader, SvgNode* parent,
static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{ {
loader->svgParse->node = _createNode(parent, SvgNodeType::Doc); loader->svgParse->node = _createNode(parent, SvgNodeType::Doc);
if (!loader->svgParse->node) return nullptr; auto doc = &(loader->svgParse->node->node.doc);
SvgDocNode* doc = &(loader->svgParse->node->node.doc);
loader->svgParse->global.w = 1.0f; loader->svgParse->global.w = 1.0f;
loader->svgParse->global.h = 1.0f; loader->svgParse->global.h = 1.0f;
@ -1663,7 +1635,7 @@ static bool _attrParsePathNode(void* data, const char* key, const char* value)
//Temporary: need to copy //Temporary: need to copy
path->path = _copyId(value); path->path = _copyId(value);
} else if (STR_AS(key, "style")) { } else if (STR_AS(key, "style")) {
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); return xmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (STR_AS(key, "clip-path")) { } else if (STR_AS(key, "clip-path")) {
_handleClipPathAttr(loader, node, value); _handleClipPathAttr(loader, node, value);
} else if (STR_AS(key, "mask")) { } else if (STR_AS(key, "mask")) {
@ -1727,7 +1699,7 @@ static bool _attrParseCircleNode(void* data, const char* key, const char* value)
} }
if (STR_AS(key, "style")) { if (STR_AS(key, "style")) {
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); return xmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (STR_AS(key, "clip-path")) { } else if (STR_AS(key, "clip-path")) {
_handleClipPathAttr(loader, node, value); _handleClipPathAttr(loader, node, value);
} else if (STR_AS(key, "mask")) { } else if (STR_AS(key, "mask")) {
@ -1796,7 +1768,7 @@ static bool _attrParseEllipseNode(void* data, const char* key, const char* value
} else if (STR_AS(key, "class")) { } else if (STR_AS(key, "class")) {
_handleCssClassAttr(loader, node, value); _handleCssClassAttr(loader, node, value);
} else if (STR_AS(key, "style")) { } else if (STR_AS(key, "style")) {
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); return xmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (STR_AS(key, "clip-path")) { } else if (STR_AS(key, "clip-path")) {
_handleClipPathAttr(loader, node, value); _handleClipPathAttr(loader, node, value);
} else if (STR_AS(key, "mask")) { } else if (STR_AS(key, "mask")) {
@ -1847,7 +1819,7 @@ static bool _attrParsePolygonNode(void* data, const char* key, const char* value
if (STR_AS(key, "points")) { if (STR_AS(key, "points")) {
return _attrParsePolygonPoints(value, polygon); return _attrParsePolygonPoints(value, polygon);
} else if (STR_AS(key, "style")) { } else if (STR_AS(key, "style")) {
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); return xmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (STR_AS(key, "clip-path")) { } else if (STR_AS(key, "clip-path")) {
_handleClipPathAttr(loader, node, value); _handleClipPathAttr(loader, node, value);
} else if (STR_AS(key, "mask")) { } else if (STR_AS(key, "mask")) {
@ -1936,7 +1908,7 @@ static bool _attrParseRectNode(void* data, const char* key, const char* value)
} else if (STR_AS(key, "class")) { } else if (STR_AS(key, "class")) {
_handleCssClassAttr(loader, node, value); _handleCssClassAttr(loader, node, value);
} else if (STR_AS(key, "style")) { } else if (STR_AS(key, "style")) {
ret = simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); ret = xmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (STR_AS(key, "clip-path")) { } else if (STR_AS(key, "clip-path")) {
_handleClipPathAttr(loader, node, value); _handleClipPathAttr(loader, node, value);
} else if (STR_AS(key, "mask")) { } else if (STR_AS(key, "mask")) {
@ -2001,7 +1973,7 @@ static bool _attrParseLineNode(void* data, const char* key, const char* value)
} else if (STR_AS(key, "class")) { } else if (STR_AS(key, "class")) {
_handleCssClassAttr(loader, node, value); _handleCssClassAttr(loader, node, value);
} else if (STR_AS(key, "style")) { } else if (STR_AS(key, "style")) {
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); return xmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (STR_AS(key, "clip-path")) { } else if (STR_AS(key, "clip-path")) {
_handleClipPathAttr(loader, node, value); _handleClipPathAttr(loader, node, value);
} else if (STR_AS(key, "mask")) { } else if (STR_AS(key, "mask")) {
@ -2076,7 +2048,7 @@ static bool _attrParseImageNode(void* data, const char* key, const char* value)
} else if (STR_AS(key, "class")) { } else if (STR_AS(key, "class")) {
_handleCssClassAttr(loader, node, value); _handleCssClassAttr(loader, node, value);
} else if (STR_AS(key, "style")) { } else if (STR_AS(key, "style")) {
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); return xmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (STR_AS(key, "clip-path")) { } else if (STR_AS(key, "clip-path")) {
_handleClipPathAttr(loader, node, value); _handleClipPathAttr(loader, node, value);
} else if (STR_AS(key, "mask")) { } else if (STR_AS(key, "mask")) {
@ -2143,7 +2115,7 @@ static SvgNode* _getDefsNode(SvgNode* node)
{ {
if (!node) return nullptr; if (!node) return nullptr;
while (node->parent != nullptr) { while (node->parent) {
node = node->parent; node = node->parent;
} }
@ -2158,16 +2130,14 @@ static SvgNode* _findNodeById(SvgNode *node, const char* id)
{ {
if (!node) return nullptr; if (!node) return nullptr;
SvgNode* result = nullptr;
if (node->id && STR_AS(node->id, id)) return node; if (node->id && STR_AS(node->id, id)) return node;
if (node->child.count > 0) { if (node->child.count > 0) {
ARRAY_FOREACH(p, node->child) { ARRAY_FOREACH(p, node->child) {
result = _findNodeById(*p, id); if (auto result = _findNodeById(*p, id)) return result;
if (result) break;
} }
} }
return result; return nullptr;
} }
@ -2291,7 +2261,7 @@ static bool _attrParseTextNode(void* data, const char* key, const char* value)
text->fontFamily = duplicate(value); text->fontFamily = duplicate(value);
} }
} else if (STR_AS(key, "style")) { } else if (STR_AS(key, "style")) {
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); return xmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (STR_AS(key, "clip-path")) { } else if (STR_AS(key, "clip-path")) {
_handleClipPathAttr(loader, node, value); _handleClipPathAttr(loader, node, value);
} else if (STR_AS(key, "mask")) { } else if (STR_AS(key, "mask")) {
@ -2677,7 +2647,7 @@ static SvgStyleGradient* _createRadialGradient(SvgLoaderData* loader, const char
loader->svgParse->gradient.parsedFx = false; loader->svgParse->gradient.parsedFx = false;
loader->svgParse->gradient.parsedFy = false; loader->svgParse->gradient.parsedFy = false;
simpleXmlParseAttributes(buf, bufLength, xmlParseAttributes(buf, bufLength,
_attrParseRadialGradientNode, loader); _attrParseRadialGradientNode, loader);
for (unsigned int i = 0; i < sizeof(radialTags) / sizeof(radialTags[0]); i++) { for (unsigned int i = 0; i < sizeof(radialTags) / sizeof(radialTags[0]); i++) {
@ -2748,7 +2718,7 @@ static bool _attrParseStops(void* data, const char* key, const char* value)
_toColor(value, &stop->r, &stop->g, &stop->b, nullptr); _toColor(value, &stop->r, &stop->g, &stop->b, nullptr);
} }
} else if (STR_AS(key, "style")) { } else if (STR_AS(key, "style")) {
simpleXmlParseW3CAttribute(value, strlen(value), _attrParseStopsStyle, data); xmlParseW3CAttribute(value, strlen(value), _attrParseStopsStyle, data);
} else { } else {
return false; return false;
} }
@ -2957,7 +2927,7 @@ static SvgStyleGradient* _createLinearGradient(SvgLoaderData* loader, const char
grad->linear->x2 = 1.0f; grad->linear->x2 = 1.0f;
grad->linear->isX2Percentage = true; grad->linear->isX2Percentage = true;
simpleXmlParseAttributes(buf, bufLength, _attrParseLinearGradientNode, loader); xmlParseAttributes(buf, bufLength, _attrParseLinearGradientNode, loader);
for (unsigned int i = 0; i < sizeof(linear_tags) / sizeof(linear_tags[0]); i++) { for (unsigned int i = 0; i < sizeof(linear_tags) / sizeof(linear_tags[0]); i++) {
linear_tags[i].tagRecalc(loader, grad->linear, grad->userSpace); linear_tags[i].tagRecalc(loader, grad->linear, grad->userSpace);
@ -3454,7 +3424,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
GradientFactoryMethod gradientMethod; GradientFactoryMethod gradientMethod;
SvgNode *node = nullptr, *parent = nullptr; SvgNode *node = nullptr, *parent = nullptr;
loader->level++; loader->level++;
attrs = simpleXmlFindAttributesTag(content, length); attrs = xmlFindAttributesTag(content, length);
if (!attrs) { if (!attrs) {
//Parse the empty tag //Parse the empty tag
@ -3478,7 +3448,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
if (empty) return; if (empty) return;
if (!loader->doc) { if (!loader->doc) {
if (!STR_AS(tagName, "svg")) return; //Not a valid svg document if (!STR_AS(tagName, "svg")) return; //Not a valid svg document
node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes); node = method(loader, nullptr, attrs, attrsLength, xmlParseAttributes);
loader->doc = node; loader->doc = node;
} else { } else {
if (STR_AS(tagName, "svg")) return; //Already loaded <svg>(SvgNodeType::Doc) tag if (STR_AS(tagName, "svg")) return; //Already loaded <svg>(SvgNodeType::Doc) tag
@ -3488,13 +3458,13 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
// TODO: For now only the first style node is saved. After the css id selector // TODO: For now only the first style node is saved. After the css id selector
// is introduced this if condition shouldn't be necessary any more // is introduced this if condition shouldn't be necessary any more
if (!loader->cssStyle) { if (!loader->cssStyle) {
node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes); node = method(loader, nullptr, attrs, attrsLength, xmlParseAttributes);
loader->cssStyle = node; loader->cssStyle = node;
loader->doc->node.doc.style = node; loader->doc->node.doc.style = node;
loader->openedTag = OpenedTagType::Style; loader->openedTag = OpenedTagType::Style;
} }
} else { } else {
node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes); node = method(loader, parent, attrs, attrsLength, xmlParseAttributes);
} }
} }
@ -3506,7 +3476,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
} else if ((method = _findGraphicsFactory(tagName))) { } else if ((method = _findGraphicsFactory(tagName))) {
if (loader->stack.count > 0) parent = loader->stack.last(); if (loader->stack.count > 0) parent = loader->stack.last();
else parent = loader->doc; else parent = loader->doc;
node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes); node = method(loader, parent, attrs, attrsLength, xmlParseAttributes);
if (node && !empty) { if (node && !empty) {
if (STR_AS(tagName, "text")) loader->openedTag = OpenedTagType::Text; if (STR_AS(tagName, "text")) loader->openedTag = OpenedTagType::Text;
auto defs = _createDefsNode(loader, nullptr, nullptr, 0, nullptr); auto defs = _createDefsNode(loader, nullptr, nullptr, 0, nullptr);
@ -3537,7 +3507,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
/* default value for opacity */ /* default value for opacity */
loader->svgParse->gradStop = {0.0f, 0, 0, 0, 255}; loader->svgParse->gradStop = {0.0f, 0, 0, 0, 255};
loader->svgParse->flags = SvgStopStyleFlags::StopDefault; loader->svgParse->flags = SvgStopStyleFlags::StopDefault;
simpleXmlParseAttributes(attrs, attrsLength, _attrParseStops, loader); xmlParseAttributes(attrs, attrsLength, _attrParseStops, loader);
loader->latestGradient->stops.push(loader->svgParse->gradStop); loader->latestGradient->stops.push(loader->svgParse->gradStop);
} else { } else {
loader->latestGradient = nullptr; loader->latestGradient = nullptr;
@ -3548,8 +3518,8 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
static void _svgLoaderParserText(SvgLoaderData* loader, const char* content, unsigned int length) static void _svgLoaderParserText(SvgLoaderData* loader, const char* content, unsigned int length)
{ {
auto text = &loader->svgParse->node->node.text; auto& text = loader->svgParse->node->node.text;
text->text = append(text->text, content, length); text.text = append(text.text, content, length);
} }
@ -3564,19 +3534,19 @@ static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* conte
GradientFactoryMethod gradientMethod; GradientFactoryMethod gradientMethod;
SvgNode *node = nullptr; SvgNode *node = nullptr;
while (auto next = simpleXmlParseCSSAttribute(content, length, &tag, &name, &attrs, &attrsLength)) { while (auto next = xmlParseCSSAttribute(content, length, &tag, &name, &attrs, &attrsLength)) {
if ((method = _findGroupFactory(tag))) { if ((method = _findGroupFactory(tag))) {
if ((node = method(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); if ((node = method(loader, loader->cssStyle, attrs, attrsLength, xmlParseW3CAttribute))) node->id = _copyId(name);
} else if ((method = _findGraphicsFactory(tag))) { } else if ((method = _findGraphicsFactory(tag))) {
if ((node = method(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); if ((node = method(loader, loader->cssStyle, attrs, attrsLength, xmlParseW3CAttribute))) node->id = _copyId(name);
} else if ((gradientMethod = _findGradientFactory(tag))) { } else if ((gradientMethod = _findGradientFactory(tag))) {
TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag); TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag);
} else if (STR_AS(tag, "stop")) { } else if (STR_AS(tag, "stop")) {
TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag); TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag);
} else if (STR_AS(tag, "all")) { } else if (STR_AS(tag, "all")) {
if ((node = _createCssStyleNode(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); if ((node = _createCssStyleNode(loader, loader->cssStyle, attrs, attrsLength, xmlParseW3CAttribute))) node->id = _copyId(name);
} else if (STR_AS(tag, "@font-face")) { //css at-rule specifying font } else if (STR_AS(tag, "@font-face")) { //css at-rule specifying font
_createFontFace(loader, attrs, attrsLength, simpleXmlParseW3CAttribute); _createFontFace(loader, attrs, attrsLength, xmlParseW3CAttribute);
} else if (!isIgnoreUnsupportedLogElements(tag)) { } else if (!isIgnoreUnsupportedLogElements(tag)) {
TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag); TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag);
} }
@ -3591,35 +3561,35 @@ static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* conte
} }
static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content, unsigned int length) static bool _svgLoaderParser(void* data, XMLType type, const char* content, unsigned int length)
{ {
SvgLoaderData* loader = (SvgLoaderData*)data; SvgLoaderData* loader = (SvgLoaderData*)data;
switch (type) { switch (type) {
case SimpleXMLType::Open: { case XMLType::Open: {
_svgLoaderParserXmlOpen(loader, content, length, false); _svgLoaderParserXmlOpen(loader, content, length, false);
break; break;
} }
case SimpleXMLType::OpenEmpty: { case XMLType::OpenEmpty: {
_svgLoaderParserXmlOpen(loader, content, length, true); _svgLoaderParserXmlOpen(loader, content, length, true);
break; break;
} }
case SimpleXMLType::Close: { case XMLType::Close: {
_svgLoaderParserXmlClose(loader, content, length); _svgLoaderParserXmlClose(loader, content, length);
break; break;
} }
case SimpleXMLType::Data: case XMLType::Data:
case SimpleXMLType::CData: { case XMLType::CData: {
if (loader->openedTag == OpenedTagType::Style) _svgLoaderParserXmlCssStyle(loader, content, length); if (loader->openedTag == OpenedTagType::Style) _svgLoaderParserXmlCssStyle(loader, content, length);
else if (loader->openedTag == OpenedTagType::Text) _svgLoaderParserText(loader, content, length); else if (loader->openedTag == OpenedTagType::Text) _svgLoaderParserText(loader, content, length);
break; break;
} }
case SimpleXMLType::DoctypeChild: { case XMLType::DoctypeChild: {
break; break;
} }
case SimpleXMLType::Ignored: case XMLType::Ignored:
case SimpleXMLType::Comment: case XMLType::Comment:
case SimpleXMLType::Doctype: { case XMLType::Doctype: {
break; break;
} }
default: { default: {
@ -3631,91 +3601,44 @@ static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content
} }
static void _inefficientNodeCheck(TVG_UNUSED SvgNode* node)
{
#ifdef THORVG_LOG_ENABLED
auto type = simpleXmlNodeTypeToString(node->type);
if (!node->style->display && node->type != SvgNodeType::ClipPath) TVGLOG("SVG", "Inefficient elements used [Display is none][Node Type : %s]", type);
if (node->style->opacity == 0) TVGLOG("SVG", "Inefficient elements used [Opacity is zero][Node Type : %s]", type);
if (node->style->fill.opacity == 0 && node->style->stroke.opacity == 0) TVGLOG("SVG", "Inefficient elements used [Fill opacity and stroke opacity are zero][Node Type : %s]", type);
switch (node->type) {
case SvgNodeType::Path: {
if (!node->node.path.path) TVGLOG("SVG", "Inefficient elements used [Empty path][Node Type : %s]", type);
break;
}
case SvgNodeType::Ellipse: {
if (node->node.ellipse.rx == 0 && node->node.ellipse.ry == 0) TVGLOG("SVG", "Inefficient elements used [Size is zero][Node Type : %s]", type);
break;
}
case SvgNodeType::Polygon:
case SvgNodeType::Polyline: {
if (node->node.polygon.pts.count < 2) TVGLOG("SVG", "Inefficient elements used [Invalid Polygon][Node Type : %s]", type);
break;
}
case SvgNodeType::Circle: {
if (node->node.circle.r == 0) TVGLOG("SVG", "Inefficient elements used [Size is zero][Node Type : %s]", type);
break;
}
case SvgNodeType::Rect: {
if (node->node.rect.w == 0 && node->node.rect.h) TVGLOG("SVG", "Inefficient elements used [Size is zero][Node Type : %s]", type);
break;
}
case SvgNodeType::Line: {
if (node->node.line.x1 == node->node.line.x2 && node->node.line.y1 == node->node.line.y2) TVGLOG("SVG", "Inefficient elements used [Size is zero][Node Type : %s]", type);
break;
}
default: break;
}
#endif
}
static void _updateStyle(SvgNode* node, SvgStyleProperty* parentStyle) static void _updateStyle(SvgNode* node, SvgStyleProperty* parentStyle)
{ {
_styleInherit(node->style, parentStyle); _styleInherit(node->style, parentStyle);
_inefficientNodeCheck(node);
ARRAY_FOREACH(p, node->child) { ARRAY_FOREACH(p, node->child) {
_updateStyle(*p, node->style); _updateStyle(*p, node->style);
} }
} }
static SvgStyleGradient* _gradientDup(SvgLoaderData* loader, Array<SvgStyleGradient*>* gradients, const char* id) static void _updateGradient(SvgLoaderData* loader, SvgNode* node, Array<SvgStyleGradient*>* gradients)
{ {
SvgStyleGradient* result = nullptr; auto duplicate = [&](SvgLoaderData* loader, Array<SvgStyleGradient*>* gradients, const char* id) -> SvgStyleGradient* {
SvgStyleGradient* result = nullptr;
ARRAY_FOREACH(p, *gradients) {
if ((*p)->id && STR_AS((*p)->id, id)) {
result = _cloneGradient(*p);
break;
}
}
if (result && result->ref) {
ARRAY_FOREACH(p, *gradients) { ARRAY_FOREACH(p, *gradients) {
if ((*p)->id && STR_AS((*p)->id, result->ref)) { if ((*p)->id && STR_AS((*p)->id, id)) {
_inheritGradient(loader, result, *p); result = _cloneGradient(*p);
break; break;
} }
} }
} if (result && result->ref) {
ARRAY_FOREACH(p, *gradients) {
if ((*p)->id && STR_AS((*p)->id, result->ref)) {
_inheritGradient(loader, result, *p);
break;
}
}
}
return result;
};
return result;
}
static void _updateGradient(SvgLoaderData* loader, SvgNode* node, Array<SvgStyleGradient*>* gradients)
{
if (node->child.count > 0) { if (node->child.count > 0) {
ARRAY_FOREACH(p, node->child) { ARRAY_FOREACH(p, node->child) {
_updateGradient(loader, *p, gradients); _updateGradient(loader, *p, gradients);
} }
} else { } else {
if (node->style->fill.paint.url) { if (node->style->fill.paint.url) {
auto newGrad = _gradientDup(loader, gradients, node->style->fill.paint.url); auto newGrad = duplicate(loader, gradients, node->style->fill.paint.url);
if (newGrad) { if (newGrad) {
if (node->style->fill.paint.gradient) { if (node->style->fill.paint.gradient) {
node->style->fill.paint.gradient->clear(); node->style->fill.paint.gradient->clear();
@ -3725,7 +3648,7 @@ static void _updateGradient(SvgLoaderData* loader, SvgNode* node, Array<SvgStyle
} }
} }
if (node->style->stroke.paint.url) { if (node->style->stroke.paint.url) {
auto newGrad = _gradientDup(loader, gradients, node->style->stroke.paint.url); auto newGrad = duplicate(loader, gradients, node->style->stroke.paint.url);
if (newGrad) { if (newGrad) {
if (node->style->stroke.paint.gradient) { if (node->style->stroke.paint.gradient) {
node->style->stroke.paint.gradient->clear(); node->style->stroke.paint.gradient->clear();
@ -3759,14 +3682,10 @@ static void _updateComposite(SvgNode* node, SvgNode* root)
static void _updateFilter(SvgNode* node, SvgNode* root) static void _updateFilter(SvgNode* node, SvgNode* root)
{ {
if (node->style->filter.url && !node->style->filter.node) { if (node->style->filter.url && !node->style->filter.node) {
SvgNode* findResult = _findNodeById(root, node->style->filter.url); node->style->filter.node = _findNodeById(root, node->style->filter.url);
if (findResult) node->style->filter.node = findResult;
} }
if (node->child.count > 0) { ARRAY_FOREACH(child, node->child) {
auto child = node->child.data; _updateFilter(*child, root);
for (uint32_t i = 0; i < node->child.count; ++i, ++child) {
_updateFilter(*child, root);
}
} }
} }
@ -3858,7 +3777,7 @@ static bool _svgLoaderParserForValidCheckXmlOpen(SvgLoaderData* loader, const ch
SvgNode *node = nullptr; SvgNode *node = nullptr;
int attrsLength = 0; int attrsLength = 0;
loader->level++; loader->level++;
attrs = simpleXmlFindAttributesTag(content, length); attrs = xmlFindAttributesTag(content, length);
if (!attrs) { if (!attrs) {
//Parse the empty tag //Parse the empty tag
@ -3878,7 +3797,7 @@ static bool _svgLoaderParserForValidCheckXmlOpen(SvgLoaderData* loader, const ch
if ((method = _findGroupFactory(tagName))) { if ((method = _findGroupFactory(tagName))) {
if (!loader->doc) { if (!loader->doc) {
if (!STR_AS(tagName, "svg")) return true; //Not a valid svg document if (!STR_AS(tagName, "svg")) return true; //Not a valid svg document
node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes); node = method(loader, nullptr, attrs, attrsLength, xmlParseAttributes);
loader->doc = node; loader->doc = node;
loader->stack.push(node); loader->stack.push(node);
return false; return false;
@ -3888,24 +3807,16 @@ static bool _svgLoaderParserForValidCheckXmlOpen(SvgLoaderData* loader, const ch
} }
static bool _svgLoaderParserForValidCheck(void* data, SimpleXMLType type, const char* content, unsigned int length) static bool _svgLoaderParserForValidCheck(void* data, XMLType type, const char* content, unsigned int length)
{ {
SvgLoaderData* loader = (SvgLoaderData*)data;
bool res = true;;
switch (type) { switch (type) {
case SimpleXMLType::Open: case XMLType::Open:
case SimpleXMLType::OpenEmpty: { case XMLType::OpenEmpty: {
//If 'res' is false, it means <svg> tag is found. //If 'res' is false, it means <svg> tag is found.
res = _svgLoaderParserForValidCheckXmlOpen(loader, content, length); return _svgLoaderParserForValidCheckXmlOpen(static_cast<SvgLoaderData*>(data), content, length);
break;
}
default: {
break;
} }
default: return true;
} }
return res;
} }
@ -3973,7 +3884,7 @@ void SvgLoader::run(unsigned tid)
return; return;
} }
if (!simpleXmlParse(content, size, true, _svgLoaderParser, &(loaderData))) return; if (!xmlParse(content, size, true, _svgLoaderParser, &(loaderData))) return;
if (loaderData.doc) { if (loaderData.doc) {
auto defs = loaderData.doc->node.doc.defs; auto defs = loaderData.doc->node.doc.defs;
@ -3994,16 +3905,17 @@ void SvgLoader::run(unsigned tid)
if (loaderData.gradients.count > 0) _updateGradient(&loaderData, loaderData.doc, &loaderData.gradients); if (loaderData.gradients.count > 0) _updateGradient(&loaderData, loaderData.doc, &loaderData.gradients);
if (defs) _updateGradient(&loaderData, loaderData.doc, &defs->node.defs.gradients); if (defs) _updateGradient(&loaderData, loaderData.doc, &defs->node.defs.gradients);
}
root = svgSceneBuild(loaderData, vbox, w, h, align, meetOrSlice, svgPath, viewFlag);
//In case no viewbox and width/height data is provided the completion of loading root = svgSceneBuild(loaderData, vbox, w, h, align, meetOrSlice, svgPath, viewFlag);
//has to be forced, in order to establish this data based on the whole picture.
if (!(viewFlag & SvgViewFlag::Viewbox)) { //In case no viewbox and width/height data is provided the completion of loading
//Override viewbox & size again after svg loading. //has to be forced, in order to establish this data based on the whole picture.
vbox = loaderData.doc->node.doc.vbox; if (!(viewFlag & SvgViewFlag::Viewbox)) {
w = loaderData.doc->node.doc.w; //Override viewbox & size again after svg loading.
h = loaderData.doc->node.doc.h; vbox = loaderData.doc->node.doc.vbox;
w = loaderData.doc->node.doc.w;
h = loaderData.doc->node.doc.h;
}
} }
clear(false); clear(false);
@ -4016,70 +3928,67 @@ bool SvgLoader::header()
//If the <svg> tag is found, the loaded file is valid and stores viewbox information. //If the <svg> tag is found, the loaded file is valid and stores viewbox information.
//After that, the remaining content data is parsed in order with async. //After that, the remaining content data is parsed in order with async.
loaderData.svgParse = tvg::malloc<SvgParser*>(sizeof(SvgParser)); loaderData.svgParse = tvg::malloc<SvgParser*>(sizeof(SvgParser));
if (!loaderData.svgParse) return false;
loaderData.svgParse->flags = SvgStopStyleFlags::StopDefault; loaderData.svgParse->flags = SvgStopStyleFlags::StopDefault;
viewFlag = SvgViewFlag::None; viewFlag = SvgViewFlag::None;
simpleXmlParse(content, size, true, _svgLoaderParserForValidCheck, &(loaderData)); xmlParse(content, size, true, _svgLoaderParserForValidCheck, &(loaderData));
if (loaderData.doc && loaderData.doc->type == SvgNodeType::Doc) { if (!loaderData.doc || loaderData.doc->type != SvgNodeType::Doc) {
viewFlag = loaderData.doc->node.doc.viewFlag; TVGLOG("SVG", "No SVG File. There is no <svg/>");
align = loaderData.doc->node.doc.align; return false;
meetOrSlice = loaderData.doc->node.doc.meetOrSlice;
if (viewFlag & SvgViewFlag::Viewbox) {
vbox = loaderData.doc->node.doc.vbox;
if (viewFlag & SvgViewFlag::Width) w = loaderData.doc->node.doc.w;
else {
w = loaderData.doc->node.doc.vbox.w;
if (viewFlag & SvgViewFlag::WidthInPercent) {
w *= loaderData.doc->node.doc.w;
viewFlag = (viewFlag ^ SvgViewFlag::WidthInPercent);
}
viewFlag = (viewFlag | SvgViewFlag::Width);
}
if (viewFlag & SvgViewFlag::Height) h = loaderData.doc->node.doc.h;
else {
h = loaderData.doc->node.doc.vbox.h;
if (viewFlag & SvgViewFlag::HeightInPercent) {
h *= loaderData.doc->node.doc.h;
viewFlag = (viewFlag ^ SvgViewFlag::HeightInPercent);
}
viewFlag = (viewFlag | SvgViewFlag::Height);
}
//In case no viewbox and width/height data is provided the completion of loading
//has to be forced, in order to establish this data based on the whole picture.
} else {
//Before loading, set default viewbox & size if they are empty
vbox.x = vbox.y = 0.0f;
if (viewFlag & SvgViewFlag::Width) {
vbox.w = w = loaderData.doc->node.doc.w;
} else {
vbox.w = 1.0f;
if (viewFlag & SvgViewFlag::WidthInPercent) {
w = loaderData.doc->node.doc.w;
} else w = 1.0f;
}
if (viewFlag & SvgViewFlag::Height) {
vbox.h = h = loaderData.doc->node.doc.h;
} else {
vbox.h = 1.0f;
if (viewFlag & SvgViewFlag::HeightInPercent) {
h = loaderData.doc->node.doc.h;
} else h = 1.0f;
}
run(0);
}
return true;
} }
TVGLOG("SVG", "No SVG File. There is no <svg/>"); viewFlag = loaderData.doc->node.doc.viewFlag;
return false; align = loaderData.doc->node.doc.align;
meetOrSlice = loaderData.doc->node.doc.meetOrSlice;
if (viewFlag & SvgViewFlag::Viewbox) {
vbox = loaderData.doc->node.doc.vbox;
if (viewFlag & SvgViewFlag::Width) w = loaderData.doc->node.doc.w;
else {
w = loaderData.doc->node.doc.vbox.w;
if (viewFlag & SvgViewFlag::WidthInPercent) {
w *= loaderData.doc->node.doc.w;
viewFlag = (viewFlag ^ SvgViewFlag::WidthInPercent);
}
viewFlag = (viewFlag | SvgViewFlag::Width);
}
if (viewFlag & SvgViewFlag::Height) h = loaderData.doc->node.doc.h;
else {
h = loaderData.doc->node.doc.vbox.h;
if (viewFlag & SvgViewFlag::HeightInPercent) {
h *= loaderData.doc->node.doc.h;
viewFlag = (viewFlag ^ SvgViewFlag::HeightInPercent);
}
viewFlag = (viewFlag | SvgViewFlag::Height);
}
//In case no viewbox and width/height data is provided the completion of loading
//has to be forced, in order to establish this data based on the whole picture.
} else {
//Before loading, set default viewbox & size if they are empty
vbox.x = vbox.y = 0.0f;
if (viewFlag & SvgViewFlag::Width) {
vbox.w = w = loaderData.doc->node.doc.w;
} else {
vbox.w = 1.0f;
if (viewFlag & SvgViewFlag::WidthInPercent) {
w = loaderData.doc->node.doc.w;
} else w = 1.0f;
}
if (viewFlag & SvgViewFlag::Height) {
vbox.h = h = loaderData.doc->node.doc.h;
} else {
vbox.h = 1.0f;
if (viewFlag & SvgViewFlag::HeightInPercent) {
h = loaderData.doc->node.doc.h;
} else h = 1.0f;
}
run(0);
}
return true;
} }

View file

@ -29,7 +29,7 @@
/* Internal Class Implementation */ /* Internal Class Implementation */
/************************************************************************/ /************************************************************************/
bool _isIgnoreUnsupportedLogAttributes(TVG_UNUSED const char* tagAttribute, TVG_UNUSED const char* tagValue) bool _unsupported(TVG_UNUSED const char* tagAttribute, TVG_UNUSED const char* tagValue)
{ {
#ifdef THORVG_LOG_ENABLED #ifdef THORVG_LOG_ENABLED
const auto attributesNum = 6; const auto attributesNum = 6;
@ -48,22 +48,18 @@ bool _isIgnoreUnsupportedLogAttributes(TVG_UNUSED const char* tagAttribute, TVG_
}; };
for (unsigned int i = 0; i < attributesNum; ++i) { for (unsigned int i = 0; i < attributesNum; ++i) {
if (!strncmp(tagAttribute, attributes[i].tag, attributes[i].tagWildcard ? strlen(attributes[i].tag) : strlen(tagAttribute))) { if (tvg::equal(tagAttribute, attributes[i].tag)) {
if (attributes[i].value && tagValue) { if (!attributes[i].value) return false;
if (!strncmp(tagValue, attributes[i].value, strlen(tagValue))) { if (tvg::equal(tagValue, attributes[i].value)) return false;
return true;
} else continue;
}
return true;
} }
} }
return false;
#endif
return true; return true;
#endif
return false;
} }
static const char* _simpleXmlFindWhiteSpace(const char* itr, const char* itrEnd) static const char* _xmlFindWhiteSpace(const char* itr, const char* itrEnd)
{ {
for (; itr < itrEnd; itr++) { for (; itr < itrEnd; itr++) {
if (isspace((unsigned char)*itr)) break; if (isspace((unsigned char)*itr)) break;
@ -72,7 +68,7 @@ static const char* _simpleXmlFindWhiteSpace(const char* itr, const char* itrEnd)
} }
static const char* _simpleXmlSkipWhiteSpace(const char* itr, const char* itrEnd) static const char* _xmlSkipWhiteSpace(const char* itr, const char* itrEnd)
{ {
for (; itr < itrEnd; itr++) { for (; itr < itrEnd; itr++) {
if (!isspace((unsigned char)*itr)) break; if (!isspace((unsigned char)*itr)) break;
@ -81,7 +77,7 @@ static const char* _simpleXmlSkipWhiteSpace(const char* itr, const char* itrEnd)
} }
static const char* _simpleXmlUnskipWhiteSpace(const char* itr, const char* itrStart) static const char* _xmlUnskipWhiteSpace(const char* itr, const char* itrStart)
{ {
for (itr--; itr > itrStart; itr--) { for (itr--; itr > itrStart; itr--) {
if (!isspace((unsigned char)*itr)) break; if (!isspace((unsigned char)*itr)) break;
@ -90,7 +86,7 @@ static const char* _simpleXmlUnskipWhiteSpace(const char* itr, const char* itrSt
} }
static const char* _simpleXmlSkipXmlEntities(const char* itr, const char* itrEnd) static const char* _xmlSkipXmlEntities(const char* itr, const char* itrEnd)
{ {
auto p = itr; auto p = itr;
while (itr < itrEnd && *itr == '&') { while (itr < itrEnd && *itr == '&') {
@ -107,7 +103,7 @@ static const char* _simpleXmlSkipXmlEntities(const char* itr, const char* itrEnd
} }
static const char* _simpleXmlUnskipXmlEntities(const char* itr, const char* itrStart) static const char* _xmlUnskipXmlEntities(const char* itr, const char* itrStart)
{ {
auto p = itr; auto p = itr;
while (itr > itrStart && *(itr - 1) == ';') { while (itr > itrStart && *(itr - 1) == ';') {
@ -127,12 +123,12 @@ static const char* _simpleXmlUnskipXmlEntities(const char* itr, const char* itrS
static const char* _skipWhiteSpacesAndXmlEntities(const char* itr, const char* itrEnd) static const char* _skipWhiteSpacesAndXmlEntities(const char* itr, const char* itrEnd)
{ {
itr = _simpleXmlSkipWhiteSpace(itr, itrEnd); itr = _xmlSkipWhiteSpace(itr, itrEnd);
auto p = itr; auto p = itr;
while (true) { while (true) {
if (p != (itr = _simpleXmlSkipXmlEntities(itr, itrEnd))) p = itr; if (p != (itr = _xmlSkipXmlEntities(itr, itrEnd))) p = itr;
else break; else break;
if (p != (itr = _simpleXmlSkipWhiteSpace(itr, itrEnd))) p = itr; if (p != (itr = _xmlSkipWhiteSpace(itr, itrEnd))) p = itr;
else break; else break;
} }
return itr; return itr;
@ -141,25 +137,25 @@ static const char* _skipWhiteSpacesAndXmlEntities(const char* itr, const char* i
static const char* _unskipWhiteSpacesAndXmlEntities(const char* itr, const char* itrStart) static const char* _unskipWhiteSpacesAndXmlEntities(const char* itr, const char* itrStart)
{ {
itr = _simpleXmlUnskipWhiteSpace(itr, itrStart); itr = _xmlUnskipWhiteSpace(itr, itrStart);
auto p = itr; auto p = itr;
while (true) { while (true) {
if (p != (itr = _simpleXmlUnskipXmlEntities(itr, itrStart))) p = itr; if (p != (itr = _xmlUnskipXmlEntities(itr, itrStart))) p = itr;
else break; else break;
if (p != (itr = _simpleXmlUnskipWhiteSpace(itr, itrStart))) p = itr; if (p != (itr = _xmlUnskipWhiteSpace(itr, itrStart))) p = itr;
else break; else break;
} }
return itr; return itr;
} }
static const char* _simpleXmlFindStartTag(const char* itr, const char* itrEnd) static const char* _xmlFindStartTag(const char* itr, const char* itrEnd)
{ {
return (const char*)memchr(itr, '<', itrEnd - itr); return (const char*)memchr(itr, '<', itrEnd - itr);
} }
static const char* _simpleXmlFindEndTag(const char* itr, const char* itrEnd) static const char* _xmlFindEndTag(const char* itr, const char* itrEnd)
{ {
bool insideQuote[2] = {false, false}; // 0: ", 1: ' bool insideQuote[2] = {false, false}; // 0: ", 1: '
for (; itr < itrEnd; itr++) { for (; itr < itrEnd; itr++) {
@ -174,7 +170,7 @@ static const char* _simpleXmlFindEndTag(const char* itr, const char* itrEnd)
} }
static const char* _simpleXmlFindEndCommentTag(const char* itr, const char* itrEnd) static const char* _xmlFindEndCommentTag(const char* itr, const char* itrEnd)
{ {
for (; itr < itrEnd; itr++) { for (; itr < itrEnd; itr++) {
if ((*itr == '-') && ((itr + 1 < itrEnd) && (*(itr + 1) == '-')) && ((itr + 2 < itrEnd) && (*(itr + 2) == '>'))) return itr + 2; if ((*itr == '-') && ((itr + 1 < itrEnd) && (*(itr + 1) == '-')) && ((itr + 2 < itrEnd) && (*(itr + 2) == '>'))) return itr + 2;
@ -183,7 +179,7 @@ static const char* _simpleXmlFindEndCommentTag(const char* itr, const char* itrE
} }
static const char* _simpleXmlFindEndCdataTag(const char* itr, const char* itrEnd) static const char* _xmlFindEndCdataTag(const char* itr, const char* itrEnd)
{ {
for (; itr < itrEnd; itr++) { for (; itr < itrEnd; itr++) {
if ((*itr == ']') && ((itr + 1 < itrEnd) && (*(itr + 1) == ']')) && ((itr + 2 < itrEnd) && (*(itr + 2) == '>'))) return itr + 2; if ((*itr == ']') && ((itr + 1 < itrEnd) && (*(itr + 1) == ']')) && ((itr + 2 < itrEnd) && (*(itr + 2) == '>'))) return itr + 2;
@ -192,7 +188,7 @@ static const char* _simpleXmlFindEndCdataTag(const char* itr, const char* itrEnd
} }
static const char* _simpleXmlFindDoctypeChildEndTag(const char* itr, const char* itrEnd) static const char* _xmlFindDoctypeChildEndTag(const char* itr, const char* itrEnd)
{ {
for (; itr < itrEnd; itr++) { for (; itr < itrEnd; itr++) {
if (*itr == '>') return itr; if (*itr == '>') return itr;
@ -201,32 +197,32 @@ static const char* _simpleXmlFindDoctypeChildEndTag(const char* itr, const char*
} }
static SimpleXMLType _getXMLType(const char* itr, const char* itrEnd, size_t &toff) static XMLType _getXMLType(const char* itr, const char* itrEnd, size_t &toff)
{ {
toff = 0; toff = 0;
if (itr[1] == '/') { if (itr[1] == '/') {
toff = 1; toff = 1;
return SimpleXMLType::Close; return XMLType::Close;
} else if (itr[1] == '?') { } else if (itr[1] == '?') {
toff = 1; toff = 1;
return SimpleXMLType::Processing; return XMLType::Processing;
} else if (itr[1] == '!') { } else if (itr[1] == '!') {
if ((itr + sizeof("<!DOCTYPE>") - 1 < itrEnd) && (!memcmp(itr + 2, "DOCTYPE", sizeof("DOCTYPE") - 1)) && ((itr[2 + sizeof("DOCTYPE") - 1] == '>') || (isspace((unsigned char)itr[2 + sizeof("DOCTYPE") - 1])))) { if ((itr + sizeof("<!DOCTYPE>") - 1 < itrEnd) && (!memcmp(itr + 2, "DOCTYPE", sizeof("DOCTYPE") - 1)) && ((itr[2 + sizeof("DOCTYPE") - 1] == '>') || (isspace((unsigned char)itr[2 + sizeof("DOCTYPE") - 1])))) {
toff = sizeof("!DOCTYPE") - 1; toff = sizeof("!DOCTYPE") - 1;
return SimpleXMLType::Doctype; return XMLType::Doctype;
} else if ((itr + sizeof("<![CDATA[]]>") - 1 < itrEnd) && (!memcmp(itr + 2, "[CDATA[", sizeof("[CDATA[") - 1))) { } else if ((itr + sizeof("<![CDATA[]]>") - 1 < itrEnd) && (!memcmp(itr + 2, "[CDATA[", sizeof("[CDATA[") - 1))) {
toff = sizeof("![CDATA[") - 1; toff = sizeof("![CDATA[") - 1;
return SimpleXMLType::CData; return XMLType::CData;
} else if ((itr + sizeof("<!---->") - 1 < itrEnd) && (!memcmp(itr + 2, "--", sizeof("--") - 1))) { } else if ((itr + sizeof("<!---->") - 1 < itrEnd) && (!memcmp(itr + 2, "--", sizeof("--") - 1))) {
toff = sizeof("!--") - 1; toff = sizeof("!--") - 1;
return SimpleXMLType::Comment; return XMLType::Comment;
} else if (itr + sizeof("<!>") - 1 < itrEnd) { } else if (itr + sizeof("<!>") - 1 < itrEnd) {
toff = sizeof("!") - 1; toff = sizeof("!") - 1;
return SimpleXMLType::DoctypeChild; return XMLType::DoctypeChild;
} }
return SimpleXMLType::Open; return XMLType::Open;
} }
return SimpleXMLType::Open; return XMLType::Open;
} }
@ -234,7 +230,7 @@ static SimpleXMLType _getXMLType(const char* itr, const char* itrEnd, size_t &to
/* External Class Implementation */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/
const char* simpleXmlNodeTypeToString(TVG_UNUSED SvgNodeType type) const char* xmlNodeTypeToString(TVG_UNUSED SvgNodeType type)
{ {
#ifdef THORVG_LOG_ENABLED #ifdef THORVG_LOG_ENABLED
static const char* TYPE_NAMES[] = { static const char* TYPE_NAMES[] = {
@ -285,7 +281,7 @@ bool isIgnoreUnsupportedLogElements(TVG_UNUSED const char* tagName)
} }
bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data) bool xmlParseAttributes(const char* buf, unsigned bufLength, xmlAttributeCb func, const void* data)
{ {
const char *itr = buf, *itrEnd = buf + bufLength; const char *itr = buf, *itrEnd = buf + bufLength;
char* tmpBuf = tvg::malloc<char*>(bufLength + 1); char* tmpBuf = tvg::malloc<char*>(bufLength + 1);
@ -315,7 +311,7 @@ bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttr
if (!value) goto error; if (!value) goto error;
value++; value++;
} }
keyEnd = _simpleXmlUnskipXmlEntities(keyEnd, key); keyEnd = _xmlUnskipXmlEntities(keyEnd, key);
value = _skipWhiteSpacesAndXmlEntities(value, itrEnd); value = _skipWhiteSpacesAndXmlEntities(value, itrEnd);
if (value == itrEnd) goto error; if (value == itrEnd) goto error;
@ -325,7 +321,7 @@ bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttr
if (!valueEnd) goto error; if (!valueEnd) goto error;
value++; value++;
} else { } else {
valueEnd = _simpleXmlFindWhiteSpace(value, itrEnd); valueEnd = _xmlFindWhiteSpace(value, itrEnd);
} }
itr = valueEnd + 1; itr = valueEnd + 1;
@ -339,15 +335,15 @@ bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttr
tval = tmpBuf + (keyEnd - key) + 1; tval = tmpBuf + (keyEnd - key) + 1;
int i = 0; int i = 0;
while (value < valueEnd) { while (value < valueEnd) {
value = _simpleXmlSkipXmlEntities(value, valueEnd); value = _xmlSkipXmlEntities(value, valueEnd);
tval[i++] = *value; tval[i++] = *value;
value++; value++;
} }
tval[i] = '\0'; tval[i] = '\0';
if (!func((void*)data, tmpBuf, tval)) { if (!func((void*)data, tmpBuf, tval)) {
if (!_isIgnoreUnsupportedLogAttributes(tmpBuf, tval)) { if (_unsupported(tmpBuf, tval)) {
TVGLOG("SVG", "Unsupported attributes used [Elements type: %s][Id : %s][Attribute: %s][Value: %s]", simpleXmlNodeTypeToString(((SvgLoaderData*)data)->svgParse->node->type), ((SvgLoaderData*)data)->svgParse->node->id ? ((SvgLoaderData*)data)->svgParse->node->id : "NO_ID", tmpBuf, tval ? tval : "NONE"); TVGLOG("SVG", "Unsupported attributes used [Elements type: %s][Id : %s][Attribute: %s][Value: %s]", xmlNodeTypeToString(((SvgLoaderData*)data)->svgParse->node->type), ((SvgLoaderData*)data)->svgParse->node->id ? ((SvgLoaderData*)data)->svgParse->node->id : "NO_ID", tmpBuf, tval ? tval : "NONE");
} }
} }
} }
@ -362,51 +358,49 @@ error:
} }
bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb func, const void* data) bool xmlParse(const char* buf, unsigned bufLength, bool strip, xmlCb func, const void* data)
{ {
const char *itr = buf, *itrEnd = buf + bufLength; const char *itr = buf, *itrEnd = buf + bufLength;
if (!buf || !func) return false;
while (itr < itrEnd) { while (itr < itrEnd) {
if (itr[0] == '<') { if (itr[0] == '<') {
//Invalid case //Invalid case
if (itr + 1 >= itrEnd) return false; if (itr + 1 >= itrEnd) return false;
size_t toff = 0; size_t toff = 0;
SimpleXMLType type = _getXMLType(itr, itrEnd, toff); XMLType type = _getXMLType(itr, itrEnd, toff);
const char* p; const char* p;
if (type == SimpleXMLType::CData) p = _simpleXmlFindEndCdataTag(itr + 1 + toff, itrEnd); if (type == XMLType::CData) p = _xmlFindEndCdataTag(itr + 1 + toff, itrEnd);
else if (type == SimpleXMLType::DoctypeChild) p = _simpleXmlFindDoctypeChildEndTag(itr + 1 + toff, itrEnd); else if (type == XMLType::DoctypeChild) p = _xmlFindDoctypeChildEndTag(itr + 1 + toff, itrEnd);
else if (type == SimpleXMLType::Comment) p = _simpleXmlFindEndCommentTag(itr + 1 + toff, itrEnd); else if (type == XMLType::Comment) p = _xmlFindEndCommentTag(itr + 1 + toff, itrEnd);
else p = _simpleXmlFindEndTag(itr + 1 + toff, itrEnd); else p = _xmlFindEndTag(itr + 1 + toff, itrEnd);
if (p) { if (p) {
//Invalid case: '<' nested //Invalid case: '<' nested
if (*p == '<' && type != SimpleXMLType::Doctype) return false; if (*p == '<' && type != XMLType::Doctype) return false;
const char *start, *end; const char *start, *end;
start = itr + 1 + toff; start = itr + 1 + toff;
end = p; end = p;
switch (type) { switch (type) {
case SimpleXMLType::Open: { case XMLType::Open: {
if (p[-1] == '/') { if (p[-1] == '/') {
type = SimpleXMLType::OpenEmpty; type = XMLType::OpenEmpty;
end--; end--;
} }
break; break;
} }
case SimpleXMLType::CData: { case XMLType::CData: {
if (!memcmp(p - 2, "]]", 2)) end -= 2; if (!memcmp(p - 2, "]]", 2)) end -= 2;
break; break;
} }
case SimpleXMLType::Processing: { case XMLType::Processing: {
if (p[-1] == '?') end--; if (p[-1] == '?') end--;
break; break;
} }
case SimpleXMLType::Comment: { case XMLType::Comment: {
if (!memcmp(p - 2, "--", 2)) end -= 2; if (!memcmp(p - 2, "--", 2)) end -= 2;
break; break;
} }
@ -415,7 +409,7 @@ bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb
} }
} }
if (strip && (type != SimpleXMLType::CData)) { if (strip && (type != XMLType::CData)) {
start = _skipWhiteSpacesAndXmlEntities(start, end); start = _skipWhiteSpacesAndXmlEntities(start, end);
end = _unskipWhiteSpacesAndXmlEntities(end, start); end = _unskipWhiteSpacesAndXmlEntities(end, start);
} }
@ -433,20 +427,20 @@ bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb
p = itr; p = itr;
p = _skipWhiteSpacesAndXmlEntities(p, itrEnd); p = _skipWhiteSpacesAndXmlEntities(p, itrEnd);
if (p) { if (p) {
if (!func((void*)data, SimpleXMLType::Ignored, itr, (unsigned int)(p - itr))) return false; if (!func((void*)data, XMLType::Ignored, itr, (unsigned int)(p - itr))) return false;
itr = p; itr = p;
} }
} }
p = _simpleXmlFindStartTag(itr, itrEnd); p = _xmlFindStartTag(itr, itrEnd);
if (!p) p = itrEnd; if (!p) p = itrEnd;
end = p; end = p;
if (strip) end = _unskipWhiteSpacesAndXmlEntities(end, itr); if (strip) end = _unskipWhiteSpacesAndXmlEntities(end, itr);
if (itr != end && !func((void*)data, SimpleXMLType::Data, itr, (unsigned int)(end - itr))) return false; if (itr != end && !func((void*)data, XMLType::Data, itr, (unsigned int)(end - itr))) return false;
if (strip && (end < p) && !func((void*)data, SimpleXMLType::Ignored, end, (unsigned int)(p - end))) return false; if (strip && (end < p) && !func((void*)data, XMLType::Ignored, end, (unsigned int)(p - end))) return false;
itr = p; itr = p;
} }
@ -455,7 +449,7 @@ bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb
} }
bool simpleXmlParseW3CAttribute(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data) bool xmlParseW3CAttribute(const char* buf, unsigned bufLength, xmlAttributeCb func, const void* data)
{ {
const char* end; const char* end;
char* key; char* key;
@ -508,14 +502,14 @@ bool simpleXmlParseW3CAttribute(const char* buf, unsigned bufLength, simpleXMLAt
} }
if (key[0]) { if (key[0]) {
key = const_cast<char*>(_simpleXmlSkipWhiteSpace(key, key + strlen(key))); key = const_cast<char*>(_xmlSkipWhiteSpace(key, key + strlen(key)));
key[_simpleXmlUnskipWhiteSpace(key + strlen(key) , key) - key] = '\0'; key[_xmlUnskipWhiteSpace(key + strlen(key) , key) - key] = '\0';
val = const_cast<char*>(_simpleXmlSkipWhiteSpace(val, val + strlen(val))); val = const_cast<char*>(_xmlSkipWhiteSpace(val, val + strlen(val)));
val[_simpleXmlUnskipWhiteSpace(val + strlen(val) , val) - val] = '\0'; val[_xmlUnskipWhiteSpace(val + strlen(val) , val) - val] = '\0';
if (!func((void*)data, key, val)) { if (!func((void*)data, key, val)) {
if (!_isIgnoreUnsupportedLogAttributes(key, val)) { if (!_unsupported(key, val)) {
TVGLOG("SVG", "Unsupported attributes used [Elements type: %s][Id : %s][Attribute: %s][Value: %s]", simpleXmlNodeTypeToString(((SvgLoaderData*)data)->svgParse->node->type), ((SvgLoaderData*)data)->svgParse->node->id ? ((SvgLoaderData*)data)->svgParse->node->id : "NO_ID", key, val ? val : "NONE"); TVGLOG("SVG", "Unsupported attributes used [Elements type: %s][Id : %s][Attribute: %s][Value: %s]", xmlNodeTypeToString(((SvgLoaderData*)data)->svgParse->node->type), ((SvgLoaderData*)data)->svgParse->node->id ? ((SvgLoaderData*)data)->svgParse->node->id : "NO_ID", key, val ? val : "NONE");
} }
} }
} }
@ -532,14 +526,14 @@ bool simpleXmlParseW3CAttribute(const char* buf, unsigned bufLength, simpleXMLAt
* Supported formats: * Supported formats:
* tag {}, .name {}, tag.name{} * tag {}, .name {}, tag.name{}
*/ */
const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength) const char* xmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength)
{ {
if (!buf) return nullptr; if (!buf) return nullptr;
*tag = *name = nullptr; *tag = *name = nullptr;
*attrsLength = 0; *attrsLength = 0;
auto itr = _simpleXmlSkipWhiteSpace(buf, buf + bufLength); auto itr = _xmlSkipWhiteSpace(buf, buf + bufLength);
auto itrEnd = (const char*)memchr(buf, '{', bufLength); auto itrEnd = (const char*)memchr(buf, '{', bufLength);
if (!itrEnd || itr == itrEnd) return nullptr; if (!itrEnd || itr == itrEnd) return nullptr;
@ -552,7 +546,7 @@ const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char
const char *p; const char *p;
itrEnd = _simpleXmlUnskipWhiteSpace(itrEnd, itr); itrEnd = _xmlUnskipWhiteSpace(itrEnd, itr);
if (*(itrEnd - 1) == '.') return nullptr; if (*(itrEnd - 1) == '.') return nullptr;
for (p = itr; p < itrEnd; p++) { for (p = itr; p < itrEnd; p++) {
@ -569,7 +563,7 @@ const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char
} }
const char* simpleXmlFindAttributesTag(const char* buf, unsigned bufLength) const char* xmlFindAttributesTag(const char* buf, unsigned bufLength)
{ {
const char *itr = buf, *itrEnd = buf + bufLength; const char *itr = buf, *itrEnd = buf + bufLength;
@ -578,7 +572,7 @@ const char* simpleXmlFindAttributesTag(const char* buf, unsigned bufLength)
//User skip tagname and already gave it the attributes. //User skip tagname and already gave it the attributes.
if (*itr == '=') return buf; if (*itr == '=') return buf;
} else { } else {
itr = _simpleXmlUnskipXmlEntities(itr, buf); itr = _xmlUnskipXmlEntities(itr, buf);
if (itr == itrEnd) return nullptr; if (itr == itrEnd) return nullptr;
return itr; return itr;
} }

View file

@ -20,8 +20,8 @@
* SOFTWARE. * SOFTWARE.
*/ */
#ifndef _TVG_SIMPLE_XML_PARSER_H_ #ifndef _TVG_XML_PARSER_H_
#define _TVG_SIMPLE_XML_PARSER_H_ #define _TVG_XML_PARSER_H_
#include "tvgSvgLoaderCommon.h" #include "tvgSvgLoaderCommon.h"
@ -29,7 +29,7 @@
const char* const xmlEntity[] = {"&#10;", "&quot;", "&nbsp;", "&apos;", "&amp;", "&lt;", "&gt;", "&#035;", "&#039;"}; const char* const xmlEntity[] = {"&#10;", "&quot;", "&nbsp;", "&apos;", "&amp;", "&lt;", "&gt;", "&#035;", "&#039;"};
const int xmlEntityLength[] = {5, 6, 6, 6, 5, 4, 4, 6, 6}; const int xmlEntityLength[] = {5, 6, 6, 6, 5, 4, 4, 6, 6};
enum class SimpleXMLType enum class XMLType
{ {
Open = 0, //!< \<tag attribute="value"\> Open = 0, //!< \<tag attribute="value"\>
OpenEmpty, //!< \<tag attribute="value" /\> OpenEmpty, //!< \<tag attribute="value" /\>
@ -44,15 +44,15 @@ enum class SimpleXMLType
DoctypeChild //!< \<!doctype_child DoctypeChild //!< \<!doctype_child
}; };
typedef bool (*simpleXMLCb)(void* data, SimpleXMLType type, const char* content, unsigned int length); typedef bool (*xmlCb)(void* data, XMLType type, const char* content, unsigned int length);
typedef bool (*simpleXMLAttributeCb)(void* data, const char* key, const char* value); typedef bool (*xmlAttributeCb)(void* data, const char* key, const char* value);
bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data); bool xmlParseAttributes(const char* buf, unsigned bufLength, xmlAttributeCb func, const void* data);
bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb func, const void* data); bool xmlParse(const char* buf, unsigned bufLength, bool strip, xmlCb func, const void* data);
bool simpleXmlParseW3CAttribute(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data); bool xmlParseW3CAttribute(const char* buf, unsigned bufLength, xmlAttributeCb func, const void* data);
const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength); const char* xmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength);
const char* simpleXmlFindAttributesTag(const char* buf, unsigned bufLength); const char* xmlFindAttributesTag(const char* buf, unsigned bufLength);
bool isIgnoreUnsupportedLogElements(const char* tagName); bool isIgnoreUnsupportedLogElements(const char* tagName);
const char* simpleXmlNodeTypeToString(SvgNodeType type); const char* xmlNodeTypeToString(SvgNodeType type);
#endif //_TVG_SIMPLE_XML_PARSER_H_ #endif //_TVG_XML_PARSER_H_