From dcf6ebcf18af7b3bef88e6a7b8501e833db46813 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Fri, 3 May 2024 02:21:01 +0200 Subject: [PATCH] svg_loader: move the display property to the style The display property, like any other node's style property, should be part of a node style. This ensures its correct copying and inheritance. For the 'symbol' node, which is not rendered unless it is used within a 'use' node, the display property can also be applied. Because of that it cannot be utilized during scene construction to determine whether the symbol is being defined or used within a 'use' context. --- src/loaders/svg/tvgSvgCssStyle.cpp | 8 ++++++++ src/loaders/svg/tvgSvgLoader.cpp | 16 +++++++++------- src/loaders/svg/tvgSvgLoaderCommon.h | 6 +++--- src/loaders/svg/tvgSvgSceneBuilder.cpp | 6 +++--- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/loaders/svg/tvgSvgCssStyle.cpp b/src/loaders/svg/tvgSvgCssStyle.cpp index 5cccce52..1b078c4f 100644 --- a/src/loaders/svg/tvgSvgCssStyle.cpp +++ b/src/loaders/svg/tvgSvgCssStyle.cpp @@ -57,6 +57,14 @@ static void _copyStyle(SvgStyleProperty* to, const SvgStyleProperty* from) to->flagsImportance = (to->flagsImportance | SvgStyleFlags::PaintOrder); } } + if (((from->flags & SvgStyleFlags::Display) && !(to->flags & SvgStyleFlags::Display)) || + _isImportanceApplicable(to->flagsImportance, from->flagsImportance, SvgStyleFlags::Display)) { + to->display = from->display; + to->flags = (to->flags | SvgStyleFlags::Display); + if (from->flagsImportance & SvgStyleFlags::Display) { + to->flagsImportance = (to->flagsImportance | SvgStyleFlags::Display); + } + } //Fill if (((from->fill.flags & SvgFillFlags::Paint) && !(to->flags & SvgStyleFlags::Fill)) || _isImportanceApplicable(to->flagsImportance, from->flagsImportance, SvgStyleFlags::Fill)) { diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 498c1108..ddda9152 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1156,8 +1156,9 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, // The default is "inline" which means visible and "none" means invisible. // Depending on the type of node, additional functionality may be required. // refer to https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/display - if (!strcmp(value, "none")) node->display = false; - else node->display = true; + node->style->flags = (node->style->flags | SvgStyleFlags::Display); + if (!strcmp(value, "none")) node->style->display = false; + else node->style->display = true; } @@ -1442,7 +1443,7 @@ static SvgNode* _createNode(SvgNode* parent, SvgNodeType type) node->style->paintOrder = _toPaintOrder("fill stroke"); //Default display is true("inline"). - node->display = true; + node->style->display = true; node->parent = parent; node->type = type; @@ -1518,7 +1519,7 @@ static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, cons loader->svgParse->node = _createNode(parent, SvgNodeType::ClipPath); if (!loader->svgParse->node) return nullptr; - loader->svgParse->node->display = false; + loader->svgParse->node->style->display = false; loader->svgParse->node->node.clip.userSpace = true; func(buf, bufLength, _attrParseClipPathNode, loader); @@ -1543,7 +1544,6 @@ static SvgNode* _createSymbolNode(SvgLoaderData* loader, SvgNode* parent, const loader->svgParse->node = _createNode(parent, SvgNodeType::Symbol); if (!loader->svgParse->node) return nullptr; - loader->svgParse->node->display = false; loader->svgParse->node->node.symbol.align = AspectRatioAlign::XMidYMid; loader->svgParse->node->node.symbol.meetOrSlice = AspectRatioMeetOrSlice::Meet; loader->svgParse->node->node.symbol.overflowVisible = false; @@ -2969,6 +2969,9 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) if (from->flags & SvgStyleFlags::PaintOrder) { to->paintOrder = from->paintOrder; } + if (from->flags & SvgStyleFlags::Display) { + to->display = from->display; + } //Fill to->fill.flags = (to->fill.flags | from->fill.flags); if (from->fill.flags & SvgFillFlags::Paint) { @@ -3029,7 +3032,6 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) static void _copyAttr(SvgNode* to, const SvgNode* from) { - to->display = from->display; //Copy matrix attribute if (from->transform) { to->transform = (Matrix*)malloc(sizeof(Matrix)); @@ -3373,7 +3375,7 @@ static void _inefficientNodeCheck(TVG_UNUSED SvgNode* node) #ifdef THORVG_LOG_ENABLED auto type = simpleXmlNodeTypeToString(node->type); - if (!node->display && node->type != SvgNodeType::ClipPath && node->type != SvgNodeType::Symbol) TVGLOG("SVG", "Inefficient elements used [Display is none][Node Type : %s]", type); + if (!node->style->display && node->type != SvgNodeType::ClipPath) TVGLOG("SVG", "Inefficient elements used [Display is none][Node Type : %s]", type); if (node->style->opacity == 0) TVGLOG("SVG", "Inefficient elements used [Opacity is zero][Node Type : %s]", type); if (node->style->fill.opacity == 0 && node->style->stroke.opacity == 0) TVGLOG("SVG", "Inefficient elements used [Fill opacity and stroke opacity are zero][Node Type : %s]", type); diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index 9d73dece..9f257734 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -485,11 +485,12 @@ struct SvgStyleProperty SvgComposite mask; int opacity; SvgColor color; - bool curColorSet; char* cssClass; - bool paintOrder; //true if default (fill, stroke), false otherwise SvgStyleFlags flags; SvgStyleFlags flagsImportance; //indicates the importance of the flag - if set, higher priority is applied (https://drafts.csswg.org/css-cascade-4/#importance) + bool curColorSet; + bool paintOrder; //true if default (fill, stroke), false otherwise + bool display; }; struct SvgNode @@ -518,7 +519,6 @@ struct SvgNode SvgCssStyleNode cssStyle; SvgSymbolNode symbol; } node; - bool display; ~SvgNode(); }; diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 7c4dc270..dab2161d 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -310,7 +310,7 @@ static void _applyProperty(SvgLoaderData& loaderData, SvgNode* node, Shape* vg, //Clip transformation is applied directly to the path in the _appendClipShape function if (node->transform && !clip) vg->transform(*node->transform); - if (node->type == SvgNodeType::Doc || !node->display) return; + if (node->type == SvgNodeType::Doc || !node->style->display) return; //If fill property is nullptr then do nothing if (style->fill.paint.none) { @@ -782,13 +782,13 @@ static unique_ptr _sceneBuildHelper(SvgLoaderData& loaderData, const SvgN // For a Symbol node, the viewBox transformation has to be applied first - see _useBuildHelper() if (!mask && node->transform && node->type != SvgNodeType::Symbol) scene->transform(*node->transform); - if (node->display && node->style->opacity != 0) { + if (node->style->display && node->style->opacity != 0) { auto child = node->child.data; for (uint32_t i = 0; i < node->child.count; ++i, ++child) { if (_isGroupType((*child)->type)) { if ((*child)->type == SvgNodeType::Use) scene->push(_useBuildHelper(loaderData, *child, vBox, svgPath, depth + 1, isMaskWhite)); - else + else if (!((*child)->type == SvgNodeType::Symbol && node->type != SvgNodeType::Use)) scene->push(_sceneBuildHelper(loaderData, *child, vBox, svgPath, false, depth + 1, isMaskWhite)); } else if ((*child)->type == SvgNodeType::Image) { auto image = _imageBuildHelper(loaderData, *child, vBox, svgPath);