mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
svg: clean & neat code++
no logical changes
This commit is contained in:
parent
468a1db1fa
commit
ad888019e9
3 changed files with 275 additions and 372 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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[] = {" ", """, " ", "'", "&", "<", ">", "#", "'"};
|
const char* const xmlEntity[] = {" ", """, " ", "'", "&", "<", ">", "#", "'"};
|
||||||
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_
|
||||||
|
|
Loading…
Add table
Reference in a new issue