From fee0c9f5f34d8a4ee7ab3777b69074aa63b94d0d Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sun, 9 Jan 2022 21:31:24 +0100 Subject: [PATCH 01/16] svg_loader: css style node introduced For now it is assumed that only one style element is defined in an svg file, although it can be easily changed if needed. The style node will be used to define the style applied to a node of a given type or in a case when a class attrib was used. Change-Id: I53e95dadfbf8a1a48903bc9f07bd2cbec82a4eda --- src/loaders/svg/tvgSvgLoader.cpp | 33 +++++++++++++++++++++++++++++++-- src/loaders/svg/tvgSvgLoaderCommon.h | 7 +++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 7def62d..2a9cba5 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1102,6 +1102,21 @@ static bool _attrParseMaskNode(void* data, const char* key, const char* value) } +static bool _attrParseCssStyleNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode* node = loader->svgParse->node; + + if (!strcmp(key, "id")) { + if (node->id && value) free(node->id); + node->id = _copyId(value); + } else { + return _parseStyleAttr(loader, key, value, false); + } + return true; +} + + static SvgNode* _createNode(SvgNode* parent, SvgNodeType type) { SvgNode* node = (SvgNode*)calloc(1, sizeof(SvgNode)); @@ -1226,6 +1241,17 @@ static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, cons return loader->svgParse->node; } + +static SvgNode* _createCssStyleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::CssStyle); + if (!loader->svgParse->node) return nullptr; + + simpleXmlParseAttributes(buf, bufLength, _attrParseCssStyleNode, loader); + return loader->svgParse->node; +} + + static bool _attrParsePathNode(void* data, const char* key, const char* value) { SvgLoaderData* loader = (SvgLoaderData*)data; @@ -2096,7 +2122,8 @@ static constexpr struct {"g", sizeof("g"), _createGNode}, {"svg", sizeof("svg"), _createSvgNode}, {"mask", sizeof("mask"), _createMaskNode}, - {"clipPath", sizeof("clipPath"), _createClipPathNode} + {"clipPath", sizeof("clipPath"), _createClipPathNode}, + {"style", sizeof("style"), _createCssStyleNode} }; @@ -2526,7 +2553,8 @@ static constexpr struct {"svg", sizeof("svg")}, {"defs", sizeof("defs")}, {"mask", sizeof("mask")}, - {"clipPath", sizeof("clipPath")} + {"clipPath", sizeof("clipPath")}, + {"style", sizeof("style")} }; @@ -2585,6 +2613,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, if (loader->stack.count > 0) parent = loader->stack.data[loader->stack.count - 1]; else parent = loader->doc; node = method(loader, parent, attrs, attrsLength); + if (!strcmp(tagName, "style")) loader->cssStyle = node; } if (!node) return; diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index 04f5b34..41c4184 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -51,6 +51,7 @@ enum class SvgNodeType Video, ClipPath, Mask, + CssStyle, Unknown }; @@ -233,6 +234,10 @@ struct SvgMaskNode bool userSpace; }; +struct SvgCssStyleNode +{ +}; + struct SvgLinearGradient { float x1; @@ -368,6 +373,7 @@ struct SvgNode SvgImageNode image; SvgMaskNode mask; SvgClipNode clip; + SvgCssStyleNode cssStyle; } node; bool display; ~SvgNode(); @@ -402,6 +408,7 @@ struct SvgLoaderData Array stack = {nullptr, 0, 0}; SvgNode* doc = nullptr; SvgNode* def = nullptr; + SvgNode* cssStyle = nullptr; Array gradients; SvgStyleGradient* latestGradient = nullptr; //For stops SvgParser* svgParse = nullptr; -- 2.7.4 From 36f52d998c92c6c982d9bc7208e4cb0fda7459eb Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 12 Jan 2022 16:23:22 +0100 Subject: [PATCH 02/16] svg_loader: intro to the implementation of the css internal style sheets parsing Function simpleXmlParseCSSAttribute() used to parse the data inside the style tag. For now the supported formats are: tag {}, .name {}, tag.name{} _svgLoaderParserXmlStyle() used to deal with the results of the above - to create the proper nodes. Will work after create...Node() are changed. Note: The geometric attributes are not copied from the node defining the style to the node using it. The SVG2 standard has to be checked to decide whether it should be supported. Change-Id: I0b910bbb88d1142909f997219621c9011ed4e39c --- src/loaders/svg/tvgSvgLoader.cpp | 189 ++++++++++++++++++++++++----------- src/loaders/svg/tvgSvgLoaderCommon.h | 1 + src/loaders/svg/tvgXmlParser.cpp | 41 ++++++++ src/loaders/svg/tvgXmlParser.h | 7 +- 4 files changed, 176 insertions(+), 62 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 2a9cba5..274b198 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -80,6 +80,9 @@ typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength); +static void _copyAttr(SvgNode* to, const SvgNode* from, bool copyGeomAttrib = true); + + static char* _skipSpace(const char* str, const char* end) { while (((end && str < end) || (!end && *str != '\0')) && isspace(*str)) { @@ -947,12 +950,32 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, } -static void _handleCssClassAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) +static SvgNode* _findCssStyleNode(const SvgNode* cssStyle, const char* title) +{ + if (!cssStyle) return nullptr; + + auto child = cssStyle->child.data; + for (uint32_t i = 0; i < cssStyle->child.count; ++i, ++child) { + if (((*child)->id) && !strcmp((*child)->id, title)) return (*child); + } + return nullptr; + + +} + + +static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char* value) { auto cssClass = &node->style->cssClass; if (*cssClass && value) free(*cssClass); *cssClass = _copyId(value); + + //TODO: works only if style was defined before it is used + if (auto cssNode = _findCssStyleNode(loader->cssStyle, *cssClass)) { + //TODO: check SVG2 stndard - should the geometric properties be copied? + _copyAttr(node, cssNode, false); + } } @@ -1908,7 +1931,7 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) } -static void _copyAttr(SvgNode* to, const SvgNode* from) +static void _copyAttr(SvgNode* to, const SvgNode* from, bool copyGeomAttrib) { //Copy matrix attribute if (from->transform) { @@ -1923,67 +1946,67 @@ static void _copyAttr(SvgNode* to, const SvgNode* from) if (from->style->clipPath.url) to->style->clipPath.url = strdup(from->style->clipPath.url); if (from->style->mask.url) to->style->mask.url = strdup(from->style->mask.url); - //Copy node attribute - switch (from->type) { - case SvgNodeType::Circle: { - to->node.circle.cx = from->node.circle.cx; - to->node.circle.cy = from->node.circle.cy; - to->node.circle.r = from->node.circle.r; - break; - } - case SvgNodeType::Ellipse: { - to->node.ellipse.cx = from->node.ellipse.cx; - to->node.ellipse.cy = from->node.ellipse.cy; - to->node.ellipse.rx = from->node.ellipse.rx; - to->node.ellipse.ry = from->node.ellipse.ry; - break; - } - case SvgNodeType::Rect: { - to->node.rect.x = from->node.rect.x; - to->node.rect.y = from->node.rect.y; - to->node.rect.w = from->node.rect.w; - to->node.rect.h = from->node.rect.h; - to->node.rect.rx = from->node.rect.rx; - to->node.rect.ry = from->node.rect.ry; - to->node.rect.hasRx = from->node.rect.hasRx; - to->node.rect.hasRy = from->node.rect.hasRy; - break; - } - case SvgNodeType::Line: { - to->node.line.x1 = from->node.line.x1; - to->node.line.y1 = from->node.line.y1; - to->node.line.x2 = from->node.line.x2; - to->node.line.y2 = from->node.line.y2; - break; - } - case SvgNodeType::Path: { - if (from->node.path.path) to->node.path.path = strdup(from->node.path.path); - break; - } - case SvgNodeType::Polygon: { - if ((to->node.polygon.pointsCount = from->node.polygon.pointsCount)) { + if (copyGeomAttrib) { + //Copy node attribute + switch (from->type) { + case SvgNodeType::Circle: { + to->node.circle.cx = from->node.circle.cx; + to->node.circle.cy = from->node.circle.cy; + to->node.circle.r = from->node.circle.r; + break; + } + case SvgNodeType::Ellipse: { + to->node.ellipse.cx = from->node.ellipse.cx; + to->node.ellipse.cy = from->node.ellipse.cy; + to->node.ellipse.rx = from->node.ellipse.rx; + to->node.ellipse.ry = from->node.ellipse.ry; + break; + } + case SvgNodeType::Rect: { + to->node.rect.x = from->node.rect.x; + to->node.rect.y = from->node.rect.y; + to->node.rect.w = from->node.rect.w; + to->node.rect.h = from->node.rect.h; + to->node.rect.rx = from->node.rect.rx; + to->node.rect.ry = from->node.rect.ry; + to->node.rect.hasRx = from->node.rect.hasRx; + to->node.rect.hasRy = from->node.rect.hasRy; + break; + } + case SvgNodeType::Line: { + to->node.line.x1 = from->node.line.x1; + to->node.line.y1 = from->node.line.y1; + to->node.line.x2 = from->node.line.x2; + to->node.line.y2 = from->node.line.y2; + break; + } + case SvgNodeType::Path: { + if (from->node.path.path) to->node.path.path = strdup(from->node.path.path); + break; + } + case SvgNodeType::Polygon: { + to->node.polygon.pointsCount = from->node.polygon.pointsCount; to->node.polygon.points = (float*)malloc(to->node.polygon.pointsCount * sizeof(float)); memcpy(to->node.polygon.points, from->node.polygon.points, to->node.polygon.pointsCount * sizeof(float)); + break; } - break; - } - case SvgNodeType::Polyline: { - if ((to->node.polyline.pointsCount = from->node.polyline.pointsCount)) { + case SvgNodeType::Polyline: { + to->node.polyline.pointsCount = from->node.polyline.pointsCount; to->node.polyline.points = (float*)malloc(to->node.polyline.pointsCount * sizeof(float)); memcpy(to->node.polyline.points, from->node.polyline.points, to->node.polyline.pointsCount * sizeof(float)); + break; + } + case SvgNodeType::Image: { + to->node.image.x = from->node.image.x; + to->node.image.y = from->node.image.y; + to->node.image.w = from->node.image.w; + to->node.image.h = from->node.image.h; + if (from->node.image.href) to->node.image.href = strdup(from->node.image.href); + break; + } + default: { + break; } - break; - } - case SvgNodeType::Image: { - to->node.image.x = from->node.image.x; - to->node.image.y = from->node.image.y; - to->node.image.w = from->node.image.w; - to->node.image.h = from->node.image.h; - if (from->node.image.href) to->node.image.href = strdup(from->node.image.href); - break; - } - default: { - break; } } } @@ -2093,6 +2116,7 @@ static SvgNode* _createUseNode(SvgLoaderData* loader, SvgNode* parent, const cha return loader->svgParse->node; } + //TODO: Implement 'text' primitive static constexpr struct { @@ -2583,6 +2607,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, GradientFactoryMethod gradientMethod; SvgNode *node = nullptr, *parent = nullptr; loader->level++; + loader->style = false; attrs = simpleXmlFindAttributesTag(content, length); if (!attrs) { @@ -2613,7 +2638,10 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, if (loader->stack.count > 0) parent = loader->stack.data[loader->stack.count - 1]; else parent = loader->doc; node = method(loader, parent, attrs, attrsLength); - if (!strcmp(tagName, "style")) loader->cssStyle = node; + if (!strcmp(tagName, "style")) { + loader->cssStyle = node; + loader->style = true; + } } if (!node) return; @@ -2654,6 +2682,46 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, } +static void _svgLoaderParserXmlStyle(SvgLoaderData* loader, const char* content, unsigned int length) +{ + char* tag; + char* name; + const char* attrs = nullptr; + unsigned int attrsLength = 0; + + FactoryMethod method; + GradientFactoryMethod gradientMethod; + SvgNode *node = nullptr; + + const char *buf = content; + unsigned buflen = length; + + + while (auto next = simpleXmlParseCSSAttribute(buf, buflen, &tag, &name, &attrs, &attrsLength)) { + if ((method = _findGroupFactory(tag))) { + //TODO - node->id ??? add additional var for svgnode? + if ((node = method(loader, loader->cssStyle, attrs, attrsLength))) node->id = _copyId(name); + } else if ((method = _findGraphicsFactory(tag))) { + if ((node = method(loader, loader->cssStyle, attrs, attrsLength))) node->id = _copyId(name); + //TODO - implement + } else if ((gradientMethod = _findGradientFactory(tag))) { + //TODO - implement + //SvgStyleGradient* gradient = gradientMethod(loader, attrs, attrsLength); + } else if (!strcmp(tag, "stop")) { + //TODO - implement + } else if (!isIgnoreUnsupportedLogElements(tag)) { + TVGLOG("SVG", "Unsupported elements used [Elements: %s]", tag); + } + + buflen -= next - buf; + buf = next; + + free(tag); + free(name); + } +} + + static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content, unsigned int length) { SvgLoaderData* loader = (SvgLoaderData*)data; @@ -2672,7 +2740,10 @@ static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content break; } case SimpleXMLType::Data: - case SimpleXMLType::CData: + case SimpleXMLType::CData: { + if (loader->style) _svgLoaderParserXmlStyle(loader, content, length); + break; + } case SimpleXMLType::DoctypeChild: { break; } diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index 41c4184..9669660 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -415,6 +415,7 @@ struct SvgLoaderData Array cloneNodes; int level = 0; bool result = false; + bool style = false; //TODO: find a better sollution? }; /* diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index d182bc2..8381ade 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -509,6 +509,47 @@ bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, cons } +/* + * Supported formats: + * tag {}, .name {}, tag.name{} + */ +const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength) +{ + if (!buf) return nullptr; + + *tag = *name = nullptr; + *attrsLength = 0; + + auto itr = _simpleXmlSkipWhiteSpace(buf, buf + bufLength); + auto itrEnd = (const char*)memchr(buf, '{', bufLength); + + if (!itrEnd || itr == itrEnd) return nullptr; + + auto nextElement = (const char*)memchr(itrEnd, '}', bufLength - (itrEnd - buf)); + if (!nextElement) return nullptr; + + *attrs = itrEnd + 1; + *attrsLength = nextElement - *attrs; + + const char *p; + + itrEnd = _simpleXmlUnskipWhiteSpace(itrEnd, itr); + if (*(itrEnd - 1) == '.') return nullptr; + + for (p = itr; p < itrEnd; p++) { + if (*p == '.') break; + } + + if (p == itr) *tag = strdup("all"); + else *tag = strndup(itr, p - itr); + + if (p == itrEnd) *name = nullptr; + else *name = strndup(p + 1, itrEnd - p - 1); + + return (nextElement ? nextElement + 1 : nullptr); +} + + const char* simpleXmlFindAttributesTag(const char* buf, unsigned bufLength) { const char *itr = buf, *itrEnd = buf + bufLength; diff --git a/src/loaders/svg/tvgXmlParser.h b/src/loaders/svg/tvgXmlParser.h index aa00668..3f703bf 100644 --- a/src/loaders/svg/tvgXmlParser.h +++ b/src/loaders/svg/tvgXmlParser.h @@ -32,7 +32,7 @@ const int xmlEntityLength[] = {6, 6, 6, 5, 4, 4, 6, 6}; enum class SimpleXMLType { Open = 0, //!< \ - OpenEmpty, //!< \ + OpenEmpty, //!< \ Close, //!< \ Data, //!< tag text data CData, //!< \ @@ -41,7 +41,7 @@ enum class SimpleXMLType Doctype, //!< \ Ignored, //!< whatever is ignored by parser, like whitespace - DoctypeChild //!< \ Date: Mon, 17 Jan 2022 19:35:05 +0100 Subject: [PATCH 03/16] svg_loader: additional arg added into create...Node() functions A function pointer added as an additional arg in order to make it possible to use these functions to create a normal nodes and also nodes defined inside a style tag. These two cases need to be parsed using different functions: simpleXmlParseAttributes() and simpleXmlParseW3CAttribute(). Change-Id: Ic039b5b21172326bea15060195b2cb14153036a4 --- src/loaders/svg/tvgSvgLoader.cpp | 97 ++++++++++++++++++++-------------------- src/loaders/svg/tvgXmlParser.cpp | 2 +- src/loaders/svg/tvgXmlParser.h | 2 +- 3 files changed, 51 insertions(+), 50 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 274b198..e074f20 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -76,7 +76,8 @@ #define PX_PER_CM 37.79528f //1 in = 2.54 cm -> PX_PER_IN/2.54 -typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength); +typedef bool (*parseAttributes)(const char*, unsigned, simpleXMLAttributeCb, const void*); +typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func); typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength); @@ -797,7 +798,7 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "preserveAspectRatio")) { if (!strcmp(value, "none")) doc->preserveAspect = false; } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } #ifdef THORVG_LOG_ENABLED else if ((!strcmp(key, "x") || !strcmp(key, "y")) && fabsf(svgUtilStrtof(value, nullptr)) > FLT_EPSILON) { @@ -1053,7 +1054,7 @@ static bool _attrParseGNode(void* data, const char* key, const char* value) SvgNode* node = loader->svgParse->node; if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "transform")) { node->transform = _parseTransformationMatrix(value); } else if (!strcmp(key, "id")) { @@ -1082,7 +1083,7 @@ static bool _attrParseClipPathNode(void* data, const char* key, const char* valu SvgClipNode* clip = &(node->node.clip); if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "transform")) { node->transform = _parseTransformationMatrix(value); } else if (!strcmp(key, "id")) { @@ -1106,7 +1107,7 @@ static bool _attrParseMaskNode(void* data, const char* key, const char* value) SvgMaskNode* mask = &(node->node.mask); if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "transform")) { node->transform = _parseTransformationMatrix(value); } else if (!strcmp(key, "id")) { @@ -1191,7 +1192,7 @@ static SvgNode* _createNode(SvgNode* parent, SvgNodeType type) } -static SvgNode* _createDefsNode(TVG_UNUSED SvgLoaderData* loader, TVG_UNUSED SvgNode* parent, const char* buf, unsigned bufLength) +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; SvgNode* node = _createNode(nullptr, SvgNodeType::Defs); @@ -1202,17 +1203,17 @@ static SvgNode* _createDefsNode(TVG_UNUSED SvgLoaderData* loader, TVG_UNUSED Svg } -static SvgNode* _createGNode(TVG_UNUSED SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createGNode(TVG_UNUSED SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::G); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseGNode, loader); + func(buf, bufLength, _attrParseGNode, loader); return loader->svgParse->node; } -static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Doc); if (!loader->svgParse->node) return nullptr; @@ -1222,7 +1223,7 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha loader->svgParse->global.h = 0; doc->preserveAspect = true; - simpleXmlParseAttributes(buf, bufLength, _attrParseSvgNode, loader); + func(buf, bufLength, _attrParseSvgNode, loader); if (loader->svgParse->global.w == 0) { if (doc->w < FLT_EPSILON) loader->svgParse->global.w = 1; @@ -1237,7 +1238,7 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha } -static SvgNode* _createMaskNode(SvgLoaderData* loader, SvgNode* parent, TVG_UNUSED const char* buf, TVG_UNUSED unsigned bufLength) +static SvgNode* _createMaskNode(SvgLoaderData* loader, SvgNode* parent, TVG_UNUSED const char* buf, TVG_UNUSED unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Mask); if (!loader->svgParse->node) return nullptr; @@ -1245,13 +1246,13 @@ static SvgNode* _createMaskNode(SvgLoaderData* loader, SvgNode* parent, TVG_UNUS loader->svgParse->node->node.mask.userSpace = true; loader->svgParse->node->node.mask.type = SvgMaskType::Luminance; - simpleXmlParseAttributes(buf, bufLength, _attrParseMaskNode, loader); + func(buf, bufLength, _attrParseMaskNode, loader); return loader->svgParse->node; } -static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::ClipPath); if (!loader->svgParse->node) return nullptr; @@ -1259,18 +1260,18 @@ static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, cons loader->svgParse->node->display = false; loader->svgParse->node->node.clip.userSpace = true; - simpleXmlParseAttributes(buf, bufLength, _attrParseClipPathNode, loader); + func(buf, bufLength, _attrParseClipPathNode, loader); return loader->svgParse->node; } -static SvgNode* _createCssStyleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createCssStyleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::CssStyle); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseCssStyleNode, loader); + func(buf, bufLength, _attrParseCssStyleNode, loader); return loader->svgParse->node; } @@ -1285,7 +1286,7 @@ static bool _attrParsePathNode(void* data, const char* key, const char* value) //Temporary: need to copy path->path = _copyId(value); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1302,13 +1303,13 @@ static bool _attrParsePathNode(void* data, const char* key, const char* value) } -static SvgNode* _createPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Path); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParsePathNode, loader); + func(buf, bufLength, _attrParsePathNode, loader); return loader->svgParse->node; } @@ -1347,7 +1348,7 @@ static bool _attrParseCircleNode(void* data, const char* key, const char* value) } if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1364,13 +1365,13 @@ static bool _attrParseCircleNode(void* data, const char* key, const char* value) } -static SvgNode* _createCircleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createCircleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Circle); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseCircleNode, loader); + func(buf, bufLength, _attrParseCircleNode, loader); return loader->svgParse->node; } @@ -1414,7 +1415,7 @@ static bool _attrParseEllipseNode(void* data, const char* key, const char* value } else if (!strcmp(key, "class")) { _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1426,13 +1427,13 @@ static bool _attrParseEllipseNode(void* data, const char* key, const char* value } -static SvgNode* _createEllipseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createEllipseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Ellipse); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseEllipseNode, loader); + func(buf, bufLength, _attrParseEllipseNode, loader); return loader->svgParse->node; } @@ -1488,7 +1489,7 @@ static bool _attrParsePolygonNode(void* data, const char* key, const char* value if (!strcmp(key, "points")) { return _attrParsePolygonPoints(value, &polygon->points, &polygon->pointsCount); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1505,24 +1506,24 @@ static bool _attrParsePolygonNode(void* data, const char* key, const char* value } -static SvgNode* _createPolygonNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createPolygonNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Polygon); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParsePolygonNode, loader); + func(buf, bufLength, _attrParsePolygonNode, loader); return loader->svgParse->node; } -static SvgNode* _createPolylineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createPolylineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Polyline); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParsePolygonNode, loader); + func(buf, bufLength, _attrParsePolygonNode, loader); return loader->svgParse->node; } @@ -1575,7 +1576,7 @@ static bool _attrParseRectNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "class")) { _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { - ret = simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + ret = simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1588,7 +1589,7 @@ static bool _attrParseRectNode(void* data, const char* key, const char* value) } -static SvgNode* _createRectNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createRectNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Rect); @@ -1596,7 +1597,7 @@ static SvgNode* _createRectNode(SvgLoaderData* loader, SvgNode* parent, const ch loader->svgParse->node->node.rect.hasRx = loader->svgParse->node->node.rect.hasRy = false; - simpleXmlParseAttributes(buf, bufLength, _attrParseRectNode, loader); + func(buf, bufLength, _attrParseRectNode, loader); return loader->svgParse->node; } @@ -1640,7 +1641,7 @@ static bool _attrParseLineNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "class")) { _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1652,13 +1653,13 @@ static bool _attrParseLineNode(void* data, const char* key, const char* value) } -static SvgNode* _createLineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createLineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Line); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseLineNode, loader); + func(buf, bufLength, _attrParseLineNode, loader); return loader->svgParse->node; } @@ -1713,7 +1714,7 @@ static bool _attrParseImageNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "class")) { _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1725,13 +1726,13 @@ static bool _attrParseImageNode(void* data, const char* key, const char* value) } -static SvgNode* _createImageNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createImageNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Image); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseImageNode, loader); + func(buf, bufLength, _attrParseImageNode, loader); return loader->svgParse->node; } @@ -2106,13 +2107,13 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value) } -static SvgNode* _createUseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createUseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Use); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseUseNode, loader); + func(buf, bufLength, _attrParseUseNode, loader); return loader->svgParse->node; } @@ -2389,7 +2390,7 @@ static bool _attrParseStops(void* data, const char* key, const char* value) _toColor(value, &stop->r, &stop->g, &stop->b, nullptr); } } else if (!strcmp(key, "style")) { - simpleXmlParseW3CAttribute(value, _attrParseStopsStyle, data); + simpleXmlParseW3CAttribute(value, 0, _attrParseStopsStyle, data); } else { return false; } @@ -2631,13 +2632,13 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, if (empty) return; if (!loader->doc) { if (strcmp(tagName, "svg")) return; //Not a valid svg document - node = method(loader, nullptr, attrs, attrsLength); + node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes); loader->doc = node; } else { if (!strcmp(tagName, "svg")) return; //Already loaded (SvgNodeType::Doc) tag if (loader->stack.count > 0) parent = loader->stack.data[loader->stack.count - 1]; else parent = loader->doc; - node = method(loader, parent, attrs, attrsLength); + node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes); if (!strcmp(tagName, "style")) { loader->cssStyle = node; loader->style = true; @@ -2651,7 +2652,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, } else if ((method = _findGraphicsFactory(tagName))) { if (loader->stack.count > 0) parent = loader->stack.data[loader->stack.count - 1]; else parent = loader->doc; - node = method(loader, parent, attrs, attrsLength); + node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes); } else if ((gradientMethod = _findGradientFactory(tagName))) { SvgStyleGradient* gradient; gradient = gradientMethod(loader, attrs, attrsLength); @@ -2700,9 +2701,9 @@ static void _svgLoaderParserXmlStyle(SvgLoaderData* loader, const char* content, while (auto next = simpleXmlParseCSSAttribute(buf, buflen, &tag, &name, &attrs, &attrsLength)) { if ((method = _findGroupFactory(tag))) { //TODO - node->id ??? add additional var for svgnode? - if ((node = method(loader, loader->cssStyle, attrs, attrsLength))) node->id = _copyId(name); + if ((node = method(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); } else if ((method = _findGraphicsFactory(tag))) { - if ((node = method(loader, loader->cssStyle, attrs, attrsLength))) node->id = _copyId(name); + if ((node = method(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); //TODO - implement } else if ((gradientMethod = _findGradientFactory(tag))) { //TODO - implement @@ -2994,7 +2995,7 @@ static bool _svgLoaderParserForValidCheckXmlOpen(SvgLoaderData* loader, const ch if ((method = _findGroupFactory(tagName))) { if (!loader->doc) { if (strcmp(tagName, "svg")) return true; //Not a valid svg document - node = method(loader, nullptr, attrs, attrsLength); + node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes); loader->doc = node; loader->stack.push(node); return false; diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index 8381ade..4b54e06 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -450,7 +450,7 @@ bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb } -bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, const void* data) +bool simpleXmlParseW3CAttribute(const char* buf, TVG_UNUSED unsigned buflen, simpleXMLAttributeCb func, const void* data) { const char* end; char* key; diff --git a/src/loaders/svg/tvgXmlParser.h b/src/loaders/svg/tvgXmlParser.h index 3f703bf..832fb18 100644 --- a/src/loaders/svg/tvgXmlParser.h +++ b/src/loaders/svg/tvgXmlParser.h @@ -49,7 +49,7 @@ typedef bool (*simpleXMLAttributeCb)(void* data, const char* key, const char* va bool simpleXmlParseAttributes(const char* buf, unsigned buflen, simpleXMLAttributeCb func, const void* data); bool simpleXmlParse(const char* buf, unsigned buflen, bool strip, simpleXMLCb func, const void* data); -bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, const void* data); +bool simpleXmlParseW3CAttribute(const char* buf, TVG_UNUSED unsigned buflen, simpleXMLAttributeCb func, const void* data); const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength); const char* simpleXmlFindAttributesTag(const char* buf, unsigned buflen); bool isIgnoreUnsupportedLogElements(const char* tagName); -- 2.7.4 From bf89e88b07936b623901dc9bc41c781ec38fbb90 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Mon, 17 Jan 2022 22:32:19 +0100 Subject: [PATCH 04/16] svg_loader: additional check while style parsing This check is needed so the function can be used to parse not only the inline styles, but also the css internal style sheet. Change-Id: I6e325d81781326deaccdad8170f11f1acf5f43f2 --- src/loaders/svg/tvgXmlParser.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index 4b54e06..20fd85c 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -468,6 +468,13 @@ bool simpleXmlParseW3CAttribute(const char* buf, TVG_UNUSED unsigned buflen, sim do { char* sep = (char*)strchr(buf, ':'); next = (char*)strchr(buf, ';'); + if (sep >= end) + { + next = nullptr; + sep = nullptr; + } + if (next >= end) next = nullptr; + key[0] = '\0'; val[0] = '\0'; -- 2.7.4 From a134be4f28bf1d3521f00b0aeee6fb7d3a289755 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Mon, 17 Jan 2022 22:55:02 +0100 Subject: [PATCH 05/16] svg_loader: buflen arg used in the simpleXmlParseW3CAttribute() While parsing the css internal style sheets the buflen has to be passed. Change-Id: Iad755186b4ed2e73a93b8d4ed82fb9098a75bbeb --- src/loaders/svg/tvgSvgLoader.cpp | 33 +++++++++++++++++---------------- src/loaders/svg/tvgXmlParser.cpp | 5 ++--- src/loaders/svg/tvgXmlParser.h | 2 +- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index e074f20..38af850 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -798,7 +798,7 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "preserveAspectRatio")) { if (!strcmp(value, "none")) doc->preserveAspect = false; } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); } #ifdef THORVG_LOG_ENABLED else if ((!strcmp(key, "x") || !strcmp(key, "y")) && fabsf(svgUtilStrtof(value, nullptr)) > FLT_EPSILON) { @@ -951,13 +951,13 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, } -static SvgNode* _findCssStyleNode(const SvgNode* cssStyle, const char* title) +static SvgNode* _findCssStyleNode(const SvgNode* cssStyle, const char* title, SvgNodeType type) { if (!cssStyle) return nullptr; auto child = cssStyle->child.data; for (uint32_t i = 0; i < cssStyle->child.count; ++i, ++child) { - if (((*child)->id) && !strcmp((*child)->id, title)) return (*child); + if ((*child)->type == type && ((*child)->id) && !strcmp((*child)->id, title)) return (*child); } return nullptr; @@ -973,8 +973,8 @@ static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char *cssClass = _copyId(value); //TODO: works only if style was defined before it is used - if (auto cssNode = _findCssStyleNode(loader->cssStyle, *cssClass)) { - //TODO: check SVG2 stndard - should the geometric properties be copied? + if (auto cssNode = _findCssStyleNode(loader->cssStyle, *cssClass, node->type)) { + //TODO: check SVG2 standard - should the geometric properties be copied? _copyAttr(node, cssNode, false); } } @@ -1054,7 +1054,7 @@ static bool _attrParseGNode(void* data, const char* key, const char* value) SvgNode* node = loader->svgParse->node; if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); } else if (!strcmp(key, "transform")) { node->transform = _parseTransformationMatrix(value); } else if (!strcmp(key, "id")) { @@ -1083,7 +1083,7 @@ static bool _attrParseClipPathNode(void* data, const char* key, const char* valu SvgClipNode* clip = &(node->node.clip); if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); } else if (!strcmp(key, "transform")) { node->transform = _parseTransformationMatrix(value); } else if (!strcmp(key, "id")) { @@ -1107,7 +1107,7 @@ static bool _attrParseMaskNode(void* data, const char* key, const char* value) SvgMaskNode* mask = &(node->node.mask); if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); } else if (!strcmp(key, "transform")) { node->transform = _parseTransformationMatrix(value); } else if (!strcmp(key, "id")) { @@ -1286,7 +1286,7 @@ static bool _attrParsePathNode(void* data, const char* key, const char* value) //Temporary: need to copy path->path = _copyId(value); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1348,7 +1348,7 @@ static bool _attrParseCircleNode(void* data, const char* key, const char* value) } if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1415,7 +1415,7 @@ static bool _attrParseEllipseNode(void* data, const char* key, const char* value } else if (!strcmp(key, "class")) { _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1489,7 +1489,7 @@ static bool _attrParsePolygonNode(void* data, const char* key, const char* value if (!strcmp(key, "points")) { return _attrParsePolygonPoints(value, &polygon->points, &polygon->pointsCount); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1576,7 +1576,7 @@ static bool _attrParseRectNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "class")) { _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { - ret = simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); + ret = simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1641,7 +1641,7 @@ static bool _attrParseLineNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "class")) { _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1714,7 +1714,7 @@ static bool _attrParseImageNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "class")) { _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -2390,7 +2390,7 @@ static bool _attrParseStops(void* data, const char* key, const char* value) _toColor(value, &stop->r, &stop->g, &stop->b, nullptr); } } else if (!strcmp(key, "style")) { - simpleXmlParseW3CAttribute(value, 0, _attrParseStopsStyle, data); + simpleXmlParseW3CAttribute(value, strlen(value), _attrParseStopsStyle, data); } else { return false; } @@ -2717,6 +2717,7 @@ static void _svgLoaderParserXmlStyle(SvgLoaderData* loader, const char* content, buflen -= next - buf; buf = next; + free(tag); free(name); } diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index 20fd85c..e3e42b0 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -450,7 +450,7 @@ bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb } -bool simpleXmlParseW3CAttribute(const char* buf, TVG_UNUSED unsigned buflen, simpleXMLAttributeCb func, const void* data) +bool simpleXmlParseW3CAttribute(const char* buf, unsigned buflen, simpleXMLAttributeCb func, const void* data) { const char* end; char* key; @@ -459,7 +459,7 @@ bool simpleXmlParseW3CAttribute(const char* buf, TVG_UNUSED unsigned buflen, sim if (!buf) return false; - end = buf + strlen(buf); + end = buf + buflen; key = (char*)alloca(end - buf + 1); val = (char*)alloca(end - buf + 1); @@ -475,7 +475,6 @@ bool simpleXmlParseW3CAttribute(const char* buf, TVG_UNUSED unsigned buflen, sim } if (next >= end) next = nullptr; - key[0] = '\0'; val[0] = '\0'; diff --git a/src/loaders/svg/tvgXmlParser.h b/src/loaders/svg/tvgXmlParser.h index 832fb18..2ce7179 100644 --- a/src/loaders/svg/tvgXmlParser.h +++ b/src/loaders/svg/tvgXmlParser.h @@ -49,7 +49,7 @@ typedef bool (*simpleXMLAttributeCb)(void* data, const char* key, const char* va bool simpleXmlParseAttributes(const char* buf, unsigned buflen, simpleXMLAttributeCb func, const void* data); bool simpleXmlParse(const char* buf, unsigned buflen, bool strip, simpleXMLCb func, const void* data); -bool simpleXmlParseW3CAttribute(const char* buf, TVG_UNUSED unsigned buflen, simpleXMLAttributeCb func, const void* data); +bool simpleXmlParseW3CAttribute(const char* buf, unsigned buflen, simpleXMLAttributeCb func, const void* data); const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength); const char* simpleXmlFindAttributesTag(const char* buf, unsigned buflen); bool isIgnoreUnsupportedLogElements(const char* tagName); -- 2.7.4 From 3685015cebf508480befb8c230b36ea61203b29f Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Mon, 17 Jan 2022 23:11:24 +0100 Subject: [PATCH 06/16] svg_loader: remove unnecessary variables Change-Id: If5f1418c3aab366c977db0f5ac4078cc915cb46e --- src/loaders/svg/tvgSvgLoader.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 38af850..88637d6 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2694,11 +2694,7 @@ static void _svgLoaderParserXmlStyle(SvgLoaderData* loader, const char* content, GradientFactoryMethod gradientMethod; SvgNode *node = nullptr; - const char *buf = content; - unsigned buflen = length; - - - while (auto next = simpleXmlParseCSSAttribute(buf, buflen, &tag, &name, &attrs, &attrsLength)) { + while (auto next = simpleXmlParseCSSAttribute(content, length, &tag, &name, &attrs, &attrsLength)) { if ((method = _findGroupFactory(tag))) { //TODO - node->id ??? add additional var for svgnode? if ((node = method(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); @@ -2714,9 +2710,8 @@ static void _svgLoaderParserXmlStyle(SvgLoaderData* loader, const char* content, TVGLOG("SVG", "Unsupported elements used [Elements: %s]", tag); } - buflen -= next - buf; - buf = next; - + length -= next - content; + content = next; free(tag); free(name); -- 2.7.4 From 3c14a2cc49adb491f96c722d452c1cd909ca92a6 Mon Sep 17 00:00:00 2001 From: jykeon Date: Mon, 27 Feb 2023 18:07:26 +0900 Subject: [PATCH 07/16] Bump up 0.7.7 Change-Id: I7a248987ab997c664910bc3d16e4cb9bef775048 Signed-off-by: jykeon --- packaging/thorvg.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index 295f2a1..1519072 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.7.6 +Version: 0.7.7 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From 6932709d535b23dbaaab67ce300adf96c8e9332c Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 18 Jan 2022 00:06:21 +0100 Subject: [PATCH 08/16] svg_loader: proper precedence of a styling The attribute values should be copied from a style node only if they were set in the destination node using the attributes (in opocity to a style attribute). A proper copyCssStyleAttr() function is introduced. Change-Id: Iaaa0c2b561c2bea276617bfd87dc26ed80bb4bbd --- src/loaders/svg/tvgSvgLoader.cpp | 218 +++++++++++++++++++++++++++------------ 1 file changed, 150 insertions(+), 68 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 88637d6..c13ef0d 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -81,9 +81,6 @@ typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength); -static void _copyAttr(SvgNode* to, const SvgNode* from, bool copyGeomAttrib = true); - - static char* _skipSpace(const char* str, const char* end) { while (((end && str < end) || (!end && *str != '\0')) && isspace(*str)) { @@ -960,8 +957,95 @@ static SvgNode* _findCssStyleNode(const SvgNode* cssStyle, const char* title, Sv if ((*child)->type == type && ((*child)->id) && !strcmp((*child)->id, title)) return (*child); } return nullptr; +} +static void _cssStyleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) +{ + if (from == nullptr) return; + //Copy the properties of 'from' only if they were explicitly set (not the default ones). + if (from->curColorSet && !((int)to->flags & (int)SvgStyleFlags::Color)) { + to->color = from->color; + to->curColorSet = true; + to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Color); + } + //Fill + if (((int)from->fill.flags & (int)SvgFillFlags::Paint) && !((int)to->flags & (int)SvgStyleFlags::Fill)) { + to->fill.paint.color = from->fill.paint.color; + to->fill.paint.none = from->fill.paint.none; + to->fill.paint.curColor = from->fill.paint.curColor; + if (from->fill.paint.url) to->fill.paint.url = _copyId(from->fill.paint.url); + to->fill.flags = (SvgFillFlags)((int)to->fill.flags | (int)SvgFillFlags::Paint); + to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Fill); + } + if (((int)from->fill.flags & (int)SvgFillFlags::Opacity) && !((int)to->flags & (int)SvgStyleFlags::FillOpacity)) { + to->fill.opacity = from->fill.opacity; + to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::FillOpacity); + } + if (((int)from->fill.flags & (int)SvgFillFlags::FillRule) && !((int)to->flags & (int)SvgStyleFlags::FillRule)) { + to->fill.fillRule = from->fill.fillRule; + to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::FillRule); + } + //Stroke + if (((int)from->stroke.flags & (int)SvgStrokeFlags::Paint) && !((int)to->flags & (int)SvgStyleFlags::Stroke)) { + to->stroke.paint.color = from->stroke.paint.color; + to->stroke.paint.none = from->stroke.paint.none; + to->stroke.paint.curColor = from->stroke.paint.curColor; + to->stroke.paint.url = from->stroke.paint.url ? _copyId(from->stroke.paint.url) : nullptr; + to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Paint); + to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Stroke); + } + if (((int)from->stroke.flags & (int)SvgStrokeFlags::Opacity) && !((int)to->flags & (int)SvgStyleFlags::StrokeOpacity)) { + to->stroke.opacity = from->stroke.opacity; + to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeOpacity); + } + if (((int)from->stroke.flags & (int)SvgStrokeFlags::Width) && !((int)to->flags & (int)SvgStyleFlags::StrokeWidth)) { + to->stroke.width = from->stroke.width; + to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeWidth); + } + if (((int)from->stroke.flags & (int)SvgStrokeFlags::Dash) && !((int)to->flags & (int)SvgStyleFlags::StrokeDashArray)) { + if (from->stroke.dash.array.count > 0) { + to->stroke.dash.array.clear(); + to->stroke.dash.array.reserve(from->stroke.dash.array.count); + for (uint32_t i = 0; i < from->stroke.dash.array.count; ++i) { + to->stroke.dash.array.push(from->stroke.dash.array.data[i]); + } + to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeDashArray); + } + } + if (((int)from->stroke.flags & (int)SvgStrokeFlags::Cap) && !((int)to->flags & (int)SvgStyleFlags::StrokeLineCap)) { + to->stroke.cap = from->stroke.cap; + to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeLineCap); + } + if (((int)from->stroke.flags & (int)SvgStrokeFlags::Join) && !((int)to->flags & (int)SvgStyleFlags::StrokeLineJoin)) { + to->stroke.join = from->stroke.join; + to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeLineJoin); + } + //Opacity + //TODO: it can be set to be 255 and shouldn't be changed by attribute 'opacity' + if (from->opacity < 255 && !((int)to->flags & (int)SvgStyleFlags::Opacity)) { + to->opacity = from->opacity; + to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Opacity); + } + //TODO: support clip-path, mask, mask-type, display +} + + +static void _copyCssStyleAttr(SvgNode* to, const SvgNode* from) +{ + //Copy matrix attribute + if (from->transform && !((int)to->style->flags & (int)SvgStyleFlags::Transform)) { + to->transform = (Matrix*)malloc(sizeof(Matrix)); + if (to->transform) { + *to->transform = *from->transform; + to->style->flags = (SvgStyleFlags)((int)to->style->flags | (int)SvgStyleFlags::Transform); + } + } + //Copy style attribute + _cssStyleCopy(to->style, from->style); + //TODO: clips and masks are not supported yet in css style + if (from->style->clipPath.url) to->style->clipPath.url = strdup(from->style->clipPath.url); + if (from->style->mask.url) to->style->mask.url = strdup(from->style->mask.url); } @@ -975,7 +1059,7 @@ static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char //TODO: works only if style was defined before it is used if (auto cssNode = _findCssStyleNode(loader->cssStyle, *cssClass, node->type)) { //TODO: check SVG2 standard - should the geometric properties be copied? - _copyAttr(node, cssNode, false); + _copyCssStyleAttr(node, cssNode); } } @@ -1932,7 +2016,7 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) } -static void _copyAttr(SvgNode* to, const SvgNode* from, bool copyGeomAttrib) +static void _copyAttr(SvgNode* to, const SvgNode* from) { //Copy matrix attribute if (from->transform) { @@ -1947,67 +2031,65 @@ static void _copyAttr(SvgNode* to, const SvgNode* from, bool copyGeomAttrib) if (from->style->clipPath.url) to->style->clipPath.url = strdup(from->style->clipPath.url); if (from->style->mask.url) to->style->mask.url = strdup(from->style->mask.url); - if (copyGeomAttrib) { - //Copy node attribute - switch (from->type) { - case SvgNodeType::Circle: { - to->node.circle.cx = from->node.circle.cx; - to->node.circle.cy = from->node.circle.cy; - to->node.circle.r = from->node.circle.r; - break; - } - case SvgNodeType::Ellipse: { - to->node.ellipse.cx = from->node.ellipse.cx; - to->node.ellipse.cy = from->node.ellipse.cy; - to->node.ellipse.rx = from->node.ellipse.rx; - to->node.ellipse.ry = from->node.ellipse.ry; - break; - } - case SvgNodeType::Rect: { - to->node.rect.x = from->node.rect.x; - to->node.rect.y = from->node.rect.y; - to->node.rect.w = from->node.rect.w; - to->node.rect.h = from->node.rect.h; - to->node.rect.rx = from->node.rect.rx; - to->node.rect.ry = from->node.rect.ry; - to->node.rect.hasRx = from->node.rect.hasRx; - to->node.rect.hasRy = from->node.rect.hasRy; - break; - } - case SvgNodeType::Line: { - to->node.line.x1 = from->node.line.x1; - to->node.line.y1 = from->node.line.y1; - to->node.line.x2 = from->node.line.x2; - to->node.line.y2 = from->node.line.y2; - break; - } - case SvgNodeType::Path: { - if (from->node.path.path) to->node.path.path = strdup(from->node.path.path); - break; - } - case SvgNodeType::Polygon: { - to->node.polygon.pointsCount = from->node.polygon.pointsCount; - to->node.polygon.points = (float*)malloc(to->node.polygon.pointsCount * sizeof(float)); - memcpy(to->node.polygon.points, from->node.polygon.points, to->node.polygon.pointsCount * sizeof(float)); - break; - } - case SvgNodeType::Polyline: { - to->node.polyline.pointsCount = from->node.polyline.pointsCount; - to->node.polyline.points = (float*)malloc(to->node.polyline.pointsCount * sizeof(float)); - memcpy(to->node.polyline.points, from->node.polyline.points, to->node.polyline.pointsCount * sizeof(float)); - break; - } - case SvgNodeType::Image: { - to->node.image.x = from->node.image.x; - to->node.image.y = from->node.image.y; - to->node.image.w = from->node.image.w; - to->node.image.h = from->node.image.h; - if (from->node.image.href) to->node.image.href = strdup(from->node.image.href); - break; - } - default: { - break; - } + //Copy node attribute + switch (from->type) { + case SvgNodeType::Circle: { + to->node.circle.cx = from->node.circle.cx; + to->node.circle.cy = from->node.circle.cy; + to->node.circle.r = from->node.circle.r; + break; + } + case SvgNodeType::Ellipse: { + to->node.ellipse.cx = from->node.ellipse.cx; + to->node.ellipse.cy = from->node.ellipse.cy; + to->node.ellipse.rx = from->node.ellipse.rx; + to->node.ellipse.ry = from->node.ellipse.ry; + break; + } + case SvgNodeType::Rect: { + to->node.rect.x = from->node.rect.x; + to->node.rect.y = from->node.rect.y; + to->node.rect.w = from->node.rect.w; + to->node.rect.h = from->node.rect.h; + to->node.rect.rx = from->node.rect.rx; + to->node.rect.ry = from->node.rect.ry; + to->node.rect.hasRx = from->node.rect.hasRx; + to->node.rect.hasRy = from->node.rect.hasRy; + break; + } + case SvgNodeType::Line: { + to->node.line.x1 = from->node.line.x1; + to->node.line.y1 = from->node.line.y1; + to->node.line.x2 = from->node.line.x2; + to->node.line.y2 = from->node.line.y2; + break; + } + case SvgNodeType::Path: { + if (from->node.path.path) to->node.path.path = strdup(from->node.path.path); + break; + } + case SvgNodeType::Polygon: { + to->node.polygon.pointsCount = from->node.polygon.pointsCount; + to->node.polygon.points = (float*)malloc(to->node.polygon.pointsCount * sizeof(float)); + memcpy(to->node.polygon.points, from->node.polygon.points, to->node.polygon.pointsCount * sizeof(float)); + break; + } + case SvgNodeType::Polyline: { + to->node.polyline.pointsCount = from->node.polyline.pointsCount; + to->node.polyline.points = (float*)malloc(to->node.polyline.pointsCount * sizeof(float)); + memcpy(to->node.polyline.points, from->node.polyline.points, to->node.polyline.pointsCount * sizeof(float)); + break; + } + case SvgNodeType::Image: { + to->node.image.x = from->node.image.x; + to->node.image.y = from->node.image.y; + to->node.image.w = from->node.image.w; + to->node.image.h = from->node.image.h; + if (from->node.image.href) to->node.image.href = strdup(from->node.image.href); + break; + } + default: { + break; } } } @@ -2683,7 +2765,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, } -static void _svgLoaderParserXmlStyle(SvgLoaderData* loader, const char* content, unsigned int length) +static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* content, unsigned int length) { char* tag; char* name; @@ -2738,7 +2820,7 @@ static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content } case SimpleXMLType::Data: case SimpleXMLType::CData: { - if (loader->style) _svgLoaderParserXmlStyle(loader, content, length); + if (loader->style) _svgLoaderParserXmlCssStyle(loader, content, length); break; } case SimpleXMLType::DoctypeChild: { -- 2.7.4 From ffef3d952c4c5ee133594931bb4b647156859864 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 18 Jan 2022 02:36:26 +0100 Subject: [PATCH 09/16] svg_loader: supporting different target formats in css Css styling supports now targets defined only by tag or only by name (tag.name was already supported before). Also proper precedence of a styling is fixed - flags were not set. Change-Id: I757fa8ac54ccd38603f250691add141d0bacad21 --- src/loaders/svg/tvgSvgLoader.cpp | 50 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index c13ef0d..9b0097d 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -954,7 +954,23 @@ static SvgNode* _findCssStyleNode(const SvgNode* cssStyle, const char* title, Sv auto child = cssStyle->child.data; for (uint32_t i = 0; i < cssStyle->child.count; ++i, ++child) { - if ((*child)->type == type && ((*child)->id) && !strcmp((*child)->id, title)) return (*child); + if ((*child)->type == type) { + if ((!title && !(*child)->id) || (title && (*child)->id && !strcmp((*child)->id, title))) return (*child); + } + } + return nullptr; +} + + +static SvgNode* _findCssStyleNode(const SvgNode* cssStyle, const char* title) +{ + if (!cssStyle) return nullptr; + + auto child = cssStyle->child.data; + for (uint32_t i = 0; i < cssStyle->child.count; ++i, ++child) { + if ((*child)->type == SvgNodeType::CssStyle) { + if ((title && (*child)->id && !strcmp((*child)->id, title))) return (*child); + } } return nullptr; } @@ -980,10 +996,12 @@ static void _cssStyleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) } if (((int)from->fill.flags & (int)SvgFillFlags::Opacity) && !((int)to->flags & (int)SvgStyleFlags::FillOpacity)) { to->fill.opacity = from->fill.opacity; + to->fill.flags = (SvgFillFlags)((int)to->fill.flags | (int)SvgFillFlags::Opacity); to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::FillOpacity); } if (((int)from->fill.flags & (int)SvgFillFlags::FillRule) && !((int)to->flags & (int)SvgStyleFlags::FillRule)) { to->fill.fillRule = from->fill.fillRule; + to->fill.flags = (SvgFillFlags)((int)to->fill.flags | (int)SvgFillFlags::FillRule); to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::FillRule); } //Stroke @@ -997,10 +1015,12 @@ static void _cssStyleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) } if (((int)from->stroke.flags & (int)SvgStrokeFlags::Opacity) && !((int)to->flags & (int)SvgStyleFlags::StrokeOpacity)) { to->stroke.opacity = from->stroke.opacity; + to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Opacity); to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeOpacity); } if (((int)from->stroke.flags & (int)SvgStrokeFlags::Width) && !((int)to->flags & (int)SvgStyleFlags::StrokeWidth)) { to->stroke.width = from->stroke.width; + to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Width); to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeWidth); } if (((int)from->stroke.flags & (int)SvgStrokeFlags::Dash) && !((int)to->flags & (int)SvgStyleFlags::StrokeDashArray)) { @@ -1010,15 +1030,18 @@ static void _cssStyleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) for (uint32_t i = 0; i < from->stroke.dash.array.count; ++i) { to->stroke.dash.array.push(from->stroke.dash.array.data[i]); } + to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Dash); to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeDashArray); } } if (((int)from->stroke.flags & (int)SvgStrokeFlags::Cap) && !((int)to->flags & (int)SvgStyleFlags::StrokeLineCap)) { to->stroke.cap = from->stroke.cap; + to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Cap); to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeLineCap); } if (((int)from->stroke.flags & (int)SvgStrokeFlags::Join) && !((int)to->flags & (int)SvgStyleFlags::StrokeLineJoin)) { to->stroke.join = from->stroke.join; + to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Join); to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeLineJoin); } //Opacity @@ -1061,6 +1084,9 @@ static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char //TODO: check SVG2 standard - should the geometric properties be copied? _copyCssStyleAttr(node, cssNode); } + if (auto cssNode = _findCssStyleNode(loader->cssStyle, *cssClass)) { + _copyCssStyleAttr(node, cssNode); + } } @@ -2788,6 +2814,8 @@ static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* conte //SvgStyleGradient* gradient = gradientMethod(loader, attrs, attrsLength); } else if (!strcmp(tag, "stop")) { //TODO - implement + } else if (!strcmp(tag, "all")) { + if ((node = _createCssStyleNode(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); } else if (!isIgnoreUnsupportedLogElements(tag)) { TVGLOG("SVG", "Unsupported elements used [Elements: %s]", tag); } @@ -2968,6 +2996,23 @@ static void _updateComposite(SvgNode* node, SvgNode* root) } +static void _updateCssStyle(SvgNode* doc, SvgNode* cssStyle) +{ + if (doc->child.count > 0) { + auto child = doc->child.data; + for (uint32_t i = 0; i < doc->child.count; ++i, ++child) { + if (auto cssNode = _findCssStyleNode(cssStyle, nullptr, (*child)->type)) { + _copyCssStyleAttr(*child, cssNode); + } + if (auto cssNode = _findCssStyleNode(cssStyle, nullptr)) { + _copyCssStyleAttr(*child, cssNode); + } + _updateCssStyle(*child, cssStyle); + } + } +} + + static void _freeNodeStyle(SvgStyleProperty* style) { if (!style) return; @@ -3143,6 +3188,9 @@ void SvgLoader::run(unsigned tid) if (loaderData.gradients.count > 0) _updateGradient(loaderData.doc, &loaderData.gradients); if (defs) _updateGradient(loaderData.doc, &defs->node.defs.gradients); + + //TODO: defs should be updated as well? + if (loaderData.cssStyle) _updateCssStyle(loaderData.doc, loaderData.cssStyle); } root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, preserveAspect, svgPath); } -- 2.7.4 From 08c3d45c5244ac413d711f1c65aa84f82d667ce0 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 18 Jan 2022 14:33:55 +0100 Subject: [PATCH 10/16] svg_loader: css styling supported also when defs were postponed Defs can be defined at the end of the file. In such a case each node with a defined class attribute has to be marked and checked at the final stage of processing - the proper style node has to be found and its style has to be applied. Change-Id: If464fa8970e13c71820553b04caecc5c3512edc9 --- src/loaders/svg/tvgSvgLoader.cpp | 34 +++++++++++++++++++++++++++++----- src/loaders/svg/tvgSvgLoaderCommon.h | 1 + 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 9b0097d..6ebd882 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -80,6 +80,7 @@ typedef bool (*parseAttributes)(const char*, unsigned, simpleXMLAttributeCb, con typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func); typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength); +static void _postponeCloneNode(Array* nodes, SvgNode *node, char* id); static char* _skipSpace(const char* str, const char* end) { @@ -1054,6 +1055,7 @@ static void _cssStyleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) } +//TODO: check SVG2 standard - should the geometric properties be copied? static void _copyCssStyleAttr(SvgNode* to, const SvgNode* from) { //Copy matrix attribute @@ -1079,14 +1081,19 @@ static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char if (*cssClass && value) free(*cssClass); *cssClass = _copyId(value); - //TODO: works only if style was defined before it is used + bool cssClassFound = false; + + //css styling: tag.name has higher priority than .name if (auto cssNode = _findCssStyleNode(loader->cssStyle, *cssClass, node->type)) { - //TODO: check SVG2 standard - should the geometric properties be copied? + cssClassFound = true; _copyCssStyleAttr(node, cssNode); } if (auto cssNode = _findCssStyleNode(loader->cssStyle, *cssClass)) { + cssClassFound = true; _copyCssStyleAttr(node, cssNode); } + + if (!cssClassFound) _postponeCloneNode(&loader->cloneCssStyleNodes, node, *cssClass); } @@ -2146,9 +2153,9 @@ static void _cloneNode(SvgNode* from, SvgNode* parent, int depth) } -static void _postponeCloneNode(SvgLoaderData* loader, SvgNode *node, char* id) +static void _postponeCloneNode(Array* nodes, SvgNode *node, char* id) { - loader->cloneNodes.push({node, id}); + nodes->push({node, id}); } @@ -2206,7 +2213,7 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value) //some svg export software include element at the end of the file //if so the 'from' element won't be found now and we have to repeat finding //after the whole file is parsed - _postponeCloneNode(loader, node, id); + _postponeCloneNode(&loader->cloneNodes, node, id); } } else { return _attrParseGNode(data, key, value); @@ -3013,6 +3020,22 @@ static void _updateCssStyle(SvgNode* doc, SvgNode* cssStyle) } +static void _clonePostponedCssStyleNodes(Array* cloneCssStyleNodes, SvgNode* cssStyle) +{ + for (uint32_t i = 0; i < cloneCssStyleNodes->count; ++i) { + auto nodeIdPair = cloneCssStyleNodes->data[i]; + + //css styling: tag.name has higher priority than .name + if (auto cssNode = _findCssStyleNode(cssStyle, nodeIdPair.id, nodeIdPair.node->type)) { + _copyCssStyleAttr(nodeIdPair.node, cssNode); + } + if (auto cssNode = _findCssStyleNode(cssStyle, nodeIdPair.id)) { + _copyCssStyleAttr(nodeIdPair.node, cssNode); + } + } +} + + static void _freeNodeStyle(SvgStyleProperty* style) { if (!style) return; @@ -3189,6 +3212,7 @@ void SvgLoader::run(unsigned tid) if (loaderData.gradients.count > 0) _updateGradient(loaderData.doc, &loaderData.gradients); if (defs) _updateGradient(loaderData.doc, &defs->node.defs.gradients); + if (loaderData.cloneCssStyleNodes.count > 0) _clonePostponedCssStyleNodes(&loaderData.cloneCssStyleNodes, loaderData.cssStyle); //TODO: defs should be updated as well? if (loaderData.cssStyle) _updateCssStyle(loaderData.doc, loaderData.cssStyle); } diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index 9669660..ad88897 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -413,6 +413,7 @@ struct SvgLoaderData SvgStyleGradient* latestGradient = nullptr; //For stops SvgParser* svgParse = nullptr; Array cloneNodes; + Array cloneCssStyleNodes; int level = 0; bool result = false; bool style = false; //TODO: find a better sollution? -- 2.7.4 From 6ec669ec7145fbe90b3b6a926eedf0daac136100 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 19 Jan 2022 02:30:01 +0100 Subject: [PATCH 11/16] svg_loader: restoring changes from ed3b17b2281df03f2df67ebc34cafa12b2aea737 (preventing memcpy from a nullptr) Change-Id: If5e0628815d375d93334003f4d4e71da1c9f7b51 --- src/loaders/svg/tvgSvgLoader.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 6ebd882..c0d547e 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2102,15 +2102,17 @@ static void _copyAttr(SvgNode* to, const SvgNode* from) break; } case SvgNodeType::Polygon: { - to->node.polygon.pointsCount = from->node.polygon.pointsCount; - to->node.polygon.points = (float*)malloc(to->node.polygon.pointsCount * sizeof(float)); - memcpy(to->node.polygon.points, from->node.polygon.points, to->node.polygon.pointsCount * sizeof(float)); + if ((to->node.polygon.pointsCount = from->node.polygon.pointsCount)) { + to->node.polygon.points = (float*)malloc(to->node.polygon.pointsCount * sizeof(float)); + memcpy(to->node.polygon.points, from->node.polygon.points, to->node.polygon.pointsCount * sizeof(float)); + } break; } case SvgNodeType::Polyline: { - to->node.polyline.pointsCount = from->node.polyline.pointsCount; - to->node.polyline.points = (float*)malloc(to->node.polyline.pointsCount * sizeof(float)); - memcpy(to->node.polyline.points, from->node.polyline.points, to->node.polyline.pointsCount * sizeof(float)); + if ((to->node.polyline.pointsCount = from->node.polyline.pointsCount)) { + to->node.polyline.points = (float*)malloc(to->node.polyline.pointsCount * sizeof(float)); + memcpy(to->node.polyline.points, from->node.polyline.points, to->node.polyline.pointsCount * sizeof(float)); + } break; } case SvgNodeType::Image: { -- 2.7.4 From c57338e42d449f58fda0274b62b932ed13712864 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 19 Jan 2022 02:34:39 +0100 Subject: [PATCH 12/16] svg_loader: some names changed, no logical changes Change-Id: I4101cac14d2792f9b2fb85529e3908267362eac6 --- src/loaders/svg/tvgSvgLoader.cpp | 10 +++++----- src/loaders/svg/tvgSvgLoaderCommon.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index c0d547e..23628fd 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1093,7 +1093,7 @@ static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char _copyCssStyleAttr(node, cssNode); } - if (!cssClassFound) _postponeCloneNode(&loader->cloneCssStyleNodes, node, *cssClass); + if (!cssClassFound) _postponeCloneNode(&loader->nodesToStyle, node, *cssClass); } @@ -3022,10 +3022,10 @@ static void _updateCssStyle(SvgNode* doc, SvgNode* cssStyle) } -static void _clonePostponedCssStyleNodes(Array* cloneCssStyleNodes, SvgNode* cssStyle) +static void _stylePostponedNodes(Array* nodesToStyle, SvgNode* cssStyle) { - for (uint32_t i = 0; i < cloneCssStyleNodes->count; ++i) { - auto nodeIdPair = cloneCssStyleNodes->data[i]; + for (uint32_t i = 0; i < nodesToStyle->count; ++i) { + auto nodeIdPair = nodesToStyle->data[i]; //css styling: tag.name has higher priority than .name if (auto cssNode = _findCssStyleNode(cssStyle, nodeIdPair.id, nodeIdPair.node->type)) { @@ -3214,7 +3214,7 @@ void SvgLoader::run(unsigned tid) if (loaderData.gradients.count > 0) _updateGradient(loaderData.doc, &loaderData.gradients); if (defs) _updateGradient(loaderData.doc, &defs->node.defs.gradients); - if (loaderData.cloneCssStyleNodes.count > 0) _clonePostponedCssStyleNodes(&loaderData.cloneCssStyleNodes, loaderData.cssStyle); + if (loaderData.nodesToStyle.count > 0) _stylePostponedNodes(&loaderData.nodesToStyle, loaderData.cssStyle); //TODO: defs should be updated as well? if (loaderData.cssStyle) _updateCssStyle(loaderData.doc, loaderData.cssStyle); } diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index ad88897..1453b6d 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -413,7 +413,7 @@ struct SvgLoaderData SvgStyleGradient* latestGradient = nullptr; //For stops SvgParser* svgParse = nullptr; Array cloneNodes; - Array cloneCssStyleNodes; + Array nodesToStyle; int level = 0; bool result = false; bool style = false; //TODO: find a better sollution? -- 2.7.4 From 98884dc8e5a9454e5b57912a98aac66378eebf02 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Thu, 20 Jan 2022 02:07:30 +0100 Subject: [PATCH 13/16] svg_loader: custom _strndup added For the compatibility reasons a custom version of strndup is introduced. Change-Id: I8c1d0581eed8e708d7d3d5af121a7933b33ab77c --- src/loaders/svg/tvgXmlParser.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index e3e42b0..7c3bb56 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -236,6 +236,14 @@ static SimpleXMLType _getXMLType(const char* itr, const char* itrEnd, size_t &to } +static char* _strndup(const char* src, unsigned len) +{ + auto ret = (char*)malloc(len + 1); + if (!ret) return nullptr; + ret[len] = '\0'; + return (char*)memcpy(ret, src, len); +} + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -547,10 +555,10 @@ const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char } if (p == itr) *tag = strdup("all"); - else *tag = strndup(itr, p - itr); + else *tag = _strndup(itr, p - itr); if (p == itrEnd) *name = nullptr; - else *name = strndup(p + 1, itrEnd - p - 1); + else *name = _strndup(p + 1, itrEnd - p - 1); return (nextElement ? nextElement + 1 : nullptr); } -- 2.7.4 From 84d1bacc48b1e09f168654260339bb3941279daa Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 25 Jan 2022 12:20:22 +0100 Subject: [PATCH 14/16] svg_loader: tvg styling applied to the code Change-Id: I836926e52873e836c7dfdd64eae8ab56f0e4fe5d --- src/loaders/svg/tvgXmlParser.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index 7c3bb56..7e8fdae 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -476,8 +476,7 @@ bool simpleXmlParseW3CAttribute(const char* buf, unsigned buflen, simpleXMLAttri do { char* sep = (char*)strchr(buf, ':'); next = (char*)strchr(buf, ';'); - if (sep >= end) - { + if (sep >= end) { next = nullptr; sep = nullptr; } -- 2.7.4 From 84a5f7e3982d373134113700edf8140f8db4faf5 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Thu, 27 Jan 2022 22:58:52 +0100 Subject: [PATCH 15/16] svg_loader: fixing cdata block reading The CData block is read if it's inside the style tag. In a case when the CData block was just after the style block, the data was still read, although it shouldn't be. Fixed. Change-Id: I3cd242d0738475c0cc986f6dc8a375e3b9d5b7a5 --- src/loaders/svg/tvgSvgLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 23628fd..351d872 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2725,7 +2725,6 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, GradientFactoryMethod gradientMethod; SvgNode *node = nullptr, *parent = nullptr; loader->level++; - loader->style = false; attrs = simpleXmlFindAttributesTag(content, length); if (!attrs) { @@ -2835,6 +2834,7 @@ static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* conte free(tag); free(name); } + loader->style = false; } -- 2.7.4 From 8db4c1dbe42008458f767f737fab29ba0e8f07f2 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Fri, 28 Jan 2022 01:42:02 +0100 Subject: [PATCH 16/16] svg_loader: styling++ (no logical changes) Change-Id: I8cde1a51aaf567aa65b9cb838bd39242a8e4d61f --- src/loaders/svg/tvgSvgLoader.cpp | 17 ++++++----------- src/loaders/svg/tvgSvgLoaderCommon.h | 2 +- src/loaders/svg/tvgXmlParser.cpp | 4 ++-- src/loaders/svg/tvgXmlParser.h | 8 ++++---- 4 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 351d872..e68b776 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -75,13 +75,13 @@ #define PX_PER_MM 3.779528f //1 in = 25.4 mm -> PX_PER_IN/25.4 #define PX_PER_CM 37.79528f //1 in = 2.54 cm -> PX_PER_IN/2.54 - -typedef bool (*parseAttributes)(const char*, unsigned, simpleXMLAttributeCb, const void*); +typedef bool (*parseAttributes)(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data); typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func); typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength); static void _postponeCloneNode(Array* nodes, SvgNode *node, char* id); + static char* _skipSpace(const char* str, const char* end) { while (((end && str < end) || (!end && *str != '\0')) && isspace(*str)) { @@ -1055,7 +1055,6 @@ static void _cssStyleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) } -//TODO: check SVG2 standard - should the geometric properties be copied? static void _copyCssStyleAttr(SvgNode* to, const SvgNode* from) { //Copy matrix attribute @@ -2812,20 +2811,17 @@ static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* conte while (auto next = simpleXmlParseCSSAttribute(content, length, &tag, &name, &attrs, &attrsLength)) { if ((method = _findGroupFactory(tag))) { - //TODO - node->id ??? add additional var for svgnode? - if ((node = method(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); + TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag); } else if ((method = _findGraphicsFactory(tag))) { if ((node = method(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); - //TODO - implement } else if ((gradientMethod = _findGradientFactory(tag))) { - //TODO - implement - //SvgStyleGradient* gradient = gradientMethod(loader, attrs, attrsLength); + TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag); } else if (!strcmp(tag, "stop")) { - //TODO - implement + TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag); } else if (!strcmp(tag, "all")) { if ((node = _createCssStyleNode(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); } else if (!isIgnoreUnsupportedLogElements(tag)) { - TVGLOG("SVG", "Unsupported elements used [Elements: %s]", tag); + TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag); } length -= next - content; @@ -3215,7 +3211,6 @@ void SvgLoader::run(unsigned tid) if (defs) _updateGradient(loaderData.doc, &defs->node.defs.gradients); if (loaderData.nodesToStyle.count > 0) _stylePostponedNodes(&loaderData.nodesToStyle, loaderData.cssStyle); - //TODO: defs should be updated as well? if (loaderData.cssStyle) _updateCssStyle(loaderData.doc, loaderData.cssStyle); } root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, preserveAspect, svgPath); diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index 1453b6d..364ec15 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -416,7 +416,7 @@ struct SvgLoaderData Array nodesToStyle; int level = 0; bool result = false; - bool style = false; //TODO: find a better sollution? + bool style = false; }; /* diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index 7e8fdae..aa93870 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -458,7 +458,7 @@ bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb } -bool simpleXmlParseW3CAttribute(const char* buf, unsigned buflen, simpleXMLAttributeCb func, const void* data) +bool simpleXmlParseW3CAttribute(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data) { const char* end; char* key; @@ -467,7 +467,7 @@ bool simpleXmlParseW3CAttribute(const char* buf, unsigned buflen, simpleXMLAttri if (!buf) return false; - end = buf + buflen; + end = buf + bufLength; key = (char*)alloca(end - buf + 1); val = (char*)alloca(end - buf + 1); diff --git a/src/loaders/svg/tvgXmlParser.h b/src/loaders/svg/tvgXmlParser.h index 2ce7179..e2761ca 100644 --- a/src/loaders/svg/tvgXmlParser.h +++ b/src/loaders/svg/tvgXmlParser.h @@ -47,11 +47,11 @@ enum class SimpleXMLType typedef bool (*simpleXMLCb)(void* data, SimpleXMLType type, const char* content, unsigned int length); typedef bool (*simpleXMLAttributeCb)(void* data, const char* key, const char* value); -bool simpleXmlParseAttributes(const char* buf, unsigned buflen, simpleXMLAttributeCb func, const void* data); -bool simpleXmlParse(const char* buf, unsigned buflen, bool strip, simpleXMLCb func, const void* data); -bool simpleXmlParseW3CAttribute(const char* buf, unsigned buflen, simpleXMLAttributeCb func, const void* data); +bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data); +bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb func, const void* data); +bool simpleXmlParseW3CAttribute(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data); const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength); -const char* simpleXmlFindAttributesTag(const char* buf, unsigned buflen); +const char* simpleXmlFindAttributesTag(const char* buf, unsigned bufLength); bool isIgnoreUnsupportedLogElements(const char* tagName); const char* simpleXmlNodeTypeToString(SvgNodeType type); -- 2.7.4