From 3685015cebf508480befb8c230b36ea61203b29f Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Mon, 17 Jan 2022 23:11:24 +0100 Subject: [PATCH 01/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 02/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 03/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 04/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 05/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 06/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 07/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 08/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 09/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 10/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 11/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 From 662fb7a5112737396269c793c93813b580c4562c Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sat, 29 Jan 2022 00:40:09 +0100 Subject: [PATCH 12/16] svg_loader: css style functions moved to a separate file Change-Id: I6ea53062f358e0128a3b8eafba4e6217b7b9666e --- src/loaders/svg/meson.build | 2 + src/loaders/svg/tvgSvgCssStyle.cpp | 189 +++++++++++++++++++++++++++++++++++++ src/loaders/svg/tvgSvgCssStyle.h | 34 +++++++ src/loaders/svg/tvgSvgLoader.cpp | 170 ++------------------------------- 4 files changed, 232 insertions(+), 163 deletions(-) create mode 100644 src/loaders/svg/tvgSvgCssStyle.cpp create mode 100644 src/loaders/svg/tvgSvgCssStyle.h diff --git a/src/loaders/svg/meson.build b/src/loaders/svg/meson.build index d6d8cec..8048dd1 100644 --- a/src/loaders/svg/meson.build +++ b/src/loaders/svg/meson.build @@ -1,10 +1,12 @@ source_file = [ + 'tvgSvgCssStyle.h', 'tvgSvgLoader.h', 'tvgSvgLoaderCommon.h', 'tvgSvgPath.h', 'tvgSvgSceneBuilder.h', 'tvgSvgUtil.h', 'tvgXmlParser.h', + 'tvgSvgCssStyle.cpp', 'tvgSvgLoader.cpp', 'tvgSvgPath.cpp', 'tvgSvgSceneBuilder.cpp', diff --git a/src/loaders/svg/tvgSvgCssStyle.cpp b/src/loaders/svg/tvgSvgCssStyle.cpp new file mode 100644 index 0000000..60edf92 --- /dev/null +++ b/src/loaders/svg/tvgSvgCssStyle.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "tvgSvgCssStyle.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +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 = strdup(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->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 + 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; + if (from->stroke.paint.url) to->stroke.paint.url = strdup(from->stroke.paint.url); + 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->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)) { + 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->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 + //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 +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +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); +} + + +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)->type == type) { + if ((!title && !(*child)->id) || (title && (*child)->id && !strcmp((*child)->id, title))) return (*child); + } + } + return nullptr; +} + + +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; +} + + +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); + } + } +} + + +void stylePostponedNodes(Array* nodesToStyle, SvgNode* cssStyle) +{ + 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)) { + copyCssStyleAttr(nodeIdPair.node, cssNode); + } + if (auto cssNode = findCssStyleNode(cssStyle, nodeIdPair.id)) { + copyCssStyleAttr(nodeIdPair.node, cssNode); + } + } +} + diff --git a/src/loaders/svg/tvgSvgCssStyle.h b/src/loaders/svg/tvgSvgCssStyle.h new file mode 100644 index 0000000..90fbcbf --- /dev/null +++ b/src/loaders/svg/tvgSvgCssStyle.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _TVG_SVG_CSS_STYLE_H_ +#define _TVG_SVG_CSS_STYLE_H_ + +#include "tvgSvgLoaderCommon.h" + +void copyCssStyleAttr(SvgNode* to, const SvgNode* from); +SvgNode* findCssStyleNode(const SvgNode* cssStyle, const char* title, SvgNodeType type); +SvgNode* findCssStyleNode(const SvgNode* cssStyle, const char* title); +void updateCssStyle(SvgNode* doc, SvgNode* cssStyle); +void stylePostponedNodes(Array* nodesToStyle, SvgNode* cssStyle); + +#endif //_TVG_SVG_CSS_STYLE_H_ diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index e68b776..196de4d 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -60,6 +60,7 @@ #include "tvgSvgLoader.h" #include "tvgSvgSceneBuilder.h" #include "tvgSvgUtil.h" +#include "tvgSvgCssStyle.h" /************************************************************************/ /* Internal Class Implementation */ @@ -949,130 +950,6 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, } -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)->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; -} - - -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->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 - 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->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)) { - 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->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 - //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); -} - - static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char* value) { auto cssClass = &node->style->cssClass; @@ -1083,13 +960,13 @@ static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char bool cssClassFound = false; //css styling: tag.name has higher priority than .name - if (auto cssNode = _findCssStyleNode(loader->cssStyle, *cssClass, node->type)) { + if (auto cssNode = findCssStyleNode(loader->cssStyle, *cssClass, node->type)) { cssClassFound = true; - _copyCssStyleAttr(node, cssNode); + copyCssStyleAttr(node, cssNode); } - if (auto cssNode = _findCssStyleNode(loader->cssStyle, *cssClass)) { + if (auto cssNode = findCssStyleNode(loader->cssStyle, *cssClass)) { cssClassFound = true; - _copyCssStyleAttr(node, cssNode); + copyCssStyleAttr(node, cssNode); } if (!cssClassFound) _postponeCloneNode(&loader->nodesToStyle, node, *cssClass); @@ -3001,39 +2878,6 @@ 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 _stylePostponedNodes(Array* nodesToStyle, SvgNode* cssStyle) -{ - 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)) { - _copyCssStyleAttr(nodeIdPair.node, cssNode); - } - if (auto cssNode = _findCssStyleNode(cssStyle, nodeIdPair.id)) { - _copyCssStyleAttr(nodeIdPair.node, cssNode); - } - } -} - - static void _freeNodeStyle(SvgStyleProperty* style) { if (!style) return; @@ -3210,8 +3054,8 @@ 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.nodesToStyle.count > 0) _stylePostponedNodes(&loaderData.nodesToStyle, loaderData.cssStyle); - if (loaderData.cssStyle) _updateCssStyle(loaderData.doc, loaderData.cssStyle); + if (loaderData.nodesToStyle.count > 0) stylePostponedNodes(&loaderData.nodesToStyle, loaderData.cssStyle); + if (loaderData.cssStyle) updateCssStyle(loaderData.doc, loaderData.cssStyle); } root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, preserveAspect, svgPath); } -- 2.7.4 From 3f2d3b2d57b943b2de2e53e05f0625b3a43bbd15 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sat, 29 Jan 2022 23:08:53 +0100 Subject: [PATCH 13/16] svg_loader: fixing css style for group selectors, clips/masks The css styling has to be applied as the first step of the node updates. Whereas the updateStyle function should be called as the last step, after all other node updates are made. Change-Id: I59d11f6d372ff4f32c22b067edff90b552900ef8 --- src/loaders/svg/tvgSvgCssStyle.cpp | 3 +-- src/loaders/svg/tvgSvgLoader.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/loaders/svg/tvgSvgCssStyle.cpp b/src/loaders/svg/tvgSvgCssStyle.cpp index 60edf92..67fb39c 100644 --- a/src/loaders/svg/tvgSvgCssStyle.cpp +++ b/src/loaders/svg/tvgSvgCssStyle.cpp @@ -101,7 +101,6 @@ static void _cssStyleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) to->opacity = from->opacity; to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Opacity); } - //TODO: support clip-path, mask, mask-type, display } @@ -121,7 +120,7 @@ void copyCssStyleAttr(SvgNode* to, const SvgNode* from) } //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); } diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 196de4d..0fdd883 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2688,7 +2688,7 @@ static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* conte while (auto next = simpleXmlParseCSSAttribute(content, length, &tag, &name, &attrs, &attrsLength)) { if ((method = _findGroupFactory(tag))) { - TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag); + 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, simpleXmlParseW3CAttribute))) node->id = _copyId(name); } else if ((gradientMethod = _findGradientFactory(tag))) { @@ -3043,9 +3043,11 @@ void SvgLoader::run(unsigned tid) if (!simpleXmlParse(content, size, true, _svgLoaderParser, &(loaderData))) return; if (loaderData.doc) { - _updateStyle(loaderData.doc, nullptr); auto defs = loaderData.doc->node.doc.defs; + if (loaderData.nodesToStyle.count > 0) stylePostponedNodes(&loaderData.nodesToStyle, loaderData.cssStyle); + if (loaderData.cssStyle) updateCssStyle(loaderData.doc, loaderData.cssStyle); + _updateComposite(loaderData.doc, loaderData.doc); if (defs) _updateComposite(loaderData.doc, defs); @@ -3054,8 +3056,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.nodesToStyle.count > 0) stylePostponedNodes(&loaderData.nodesToStyle, loaderData.cssStyle); - if (loaderData.cssStyle) updateCssStyle(loaderData.doc, loaderData.cssStyle); + _updateStyle(loaderData.doc, nullptr); } root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, preserveAspect, svgPath); } -- 2.7.4 From fc155c8096b701a26c031a9ba52d8a4d46da7f8c Mon Sep 17 00:00:00 2001 From: jykeon Date: Mon, 27 Feb 2023 19:12:37 +0900 Subject: [PATCH 14/16] Bump up 0.7.8 Change-Id: Ib9bd24a04afecb67ba77e560119dddc7b0b2219a 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 1519072..2f5fab7 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.7.7 +Version: 0.7.8 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From 742aac04b5d27ada809aed95768f9005cf22bcac Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 25 Jan 2022 12:38:49 +0100 Subject: [PATCH 15/16] example: cssStyle.svg add For now it's a simple file used to check the styling precedence and overall correctness. After the css stylling will be fully introduced a more complex file can be used, Change-Id: I10fe2b7d4c201e29893ab6a919d132a2e2a47e24 --- src/examples/images/cssStyle.svg | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/examples/images/cssStyle.svg diff --git a/src/examples/images/cssStyle.svg b/src/examples/images/cssStyle.svg new file mode 100644 index 0000000..53d071f --- /dev/null +++ b/src/examples/images/cssStyle.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + -- 2.7.4 From 68f20ef932abde4a057d7634dc030de177cebd4e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 8 Feb 2022 18:02:20 +0900 Subject: [PATCH 16/16] example: just renamed the svg file. Change-Id: Ib880280971d5d2d93cab3b59938e94e230b7a4f5 --- src/examples/images/{cssStyle.svg => css-style.svg} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/examples/images/{cssStyle.svg => css-style.svg} (100%) diff --git a/src/examples/images/cssStyle.svg b/src/examples/images/css-style.svg similarity index 100% rename from src/examples/images/cssStyle.svg rename to src/examples/images/css-style.svg -- 2.7.4