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.
This commit is contained in:
Mira Grudzinska 2024-05-03 02:21:01 +02:00 committed by Hermet Park
parent c614efec3d
commit dcf6ebcf18
4 changed files with 23 additions and 13 deletions

View file

@ -57,6 +57,14 @@ static void _copyStyle(SvgStyleProperty* to, const SvgStyleProperty* from)
to->flagsImportance = (to->flagsImportance | SvgStyleFlags::PaintOrder); 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 //Fill
if (((from->fill.flags & SvgFillFlags::Paint) && !(to->flags & SvgStyleFlags::Fill)) || if (((from->fill.flags & SvgFillFlags::Paint) && !(to->flags & SvgStyleFlags::Fill)) ||
_isImportanceApplicable(to->flagsImportance, from->flagsImportance, SvgStyleFlags::Fill)) { _isImportanceApplicable(to->flagsImportance, from->flagsImportance, SvgStyleFlags::Fill)) {

View file

@ -1156,8 +1156,9 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node,
// The default is "inline" which means visible and "none" means invisible. // The default is "inline" which means visible and "none" means invisible.
// Depending on the type of node, additional functionality may be required. // Depending on the type of node, additional functionality may be required.
// refer to https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/display // refer to https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/display
if (!strcmp(value, "none")) node->display = false; node->style->flags = (node->style->flags | SvgStyleFlags::Display);
else node->display = true; 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"); node->style->paintOrder = _toPaintOrder("fill stroke");
//Default display is true("inline"). //Default display is true("inline").
node->display = true; node->style->display = true;
node->parent = parent; node->parent = parent;
node->type = type; node->type = type;
@ -1518,7 +1519,7 @@ static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, cons
loader->svgParse->node = _createNode(parent, SvgNodeType::ClipPath); loader->svgParse->node = _createNode(parent, SvgNodeType::ClipPath);
if (!loader->svgParse->node) return nullptr; if (!loader->svgParse->node) return nullptr;
loader->svgParse->node->display = false; loader->svgParse->node->style->display = false;
loader->svgParse->node->node.clip.userSpace = true; loader->svgParse->node->node.clip.userSpace = true;
func(buf, bufLength, _attrParseClipPathNode, loader); func(buf, bufLength, _attrParseClipPathNode, loader);
@ -1543,7 +1544,6 @@ static SvgNode* _createSymbolNode(SvgLoaderData* loader, SvgNode* parent, const
loader->svgParse->node = _createNode(parent, SvgNodeType::Symbol); loader->svgParse->node = _createNode(parent, SvgNodeType::Symbol);
if (!loader->svgParse->node) return nullptr; if (!loader->svgParse->node) return nullptr;
loader->svgParse->node->display = false;
loader->svgParse->node->node.symbol.align = AspectRatioAlign::XMidYMid; loader->svgParse->node->node.symbol.align = AspectRatioAlign::XMidYMid;
loader->svgParse->node->node.symbol.meetOrSlice = AspectRatioMeetOrSlice::Meet; loader->svgParse->node->node.symbol.meetOrSlice = AspectRatioMeetOrSlice::Meet;
loader->svgParse->node->node.symbol.overflowVisible = false; loader->svgParse->node->node.symbol.overflowVisible = false;
@ -2969,6 +2969,9 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from)
if (from->flags & SvgStyleFlags::PaintOrder) { if (from->flags & SvgStyleFlags::PaintOrder) {
to->paintOrder = from->paintOrder; to->paintOrder = from->paintOrder;
} }
if (from->flags & SvgStyleFlags::Display) {
to->display = from->display;
}
//Fill //Fill
to->fill.flags = (to->fill.flags | from->fill.flags); to->fill.flags = (to->fill.flags | from->fill.flags);
if (from->fill.flags & SvgFillFlags::Paint) { 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) static void _copyAttr(SvgNode* to, const SvgNode* from)
{ {
to->display = from->display;
//Copy matrix attribute //Copy matrix attribute
if (from->transform) { if (from->transform) {
to->transform = (Matrix*)malloc(sizeof(Matrix)); to->transform = (Matrix*)malloc(sizeof(Matrix));
@ -3373,7 +3375,7 @@ static void _inefficientNodeCheck(TVG_UNUSED SvgNode* node)
#ifdef THORVG_LOG_ENABLED #ifdef THORVG_LOG_ENABLED
auto type = simpleXmlNodeTypeToString(node->type); 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->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); 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);

View file

@ -485,11 +485,12 @@ struct SvgStyleProperty
SvgComposite mask; SvgComposite mask;
int opacity; int opacity;
SvgColor color; SvgColor color;
bool curColorSet;
char* cssClass; char* cssClass;
bool paintOrder; //true if default (fill, stroke), false otherwise
SvgStyleFlags flags; SvgStyleFlags flags;
SvgStyleFlags flagsImportance; //indicates the importance of the flag - if set, higher priority is applied (https://drafts.csswg.org/css-cascade-4/#importance) 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 struct SvgNode
@ -518,7 +519,6 @@ struct SvgNode
SvgCssStyleNode cssStyle; SvgCssStyleNode cssStyle;
SvgSymbolNode symbol; SvgSymbolNode symbol;
} node; } node;
bool display;
~SvgNode(); ~SvgNode();
}; };

View file

@ -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 //Clip transformation is applied directly to the path in the _appendClipShape function
if (node->transform && !clip) vg->transform(*node->transform); 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 fill property is nullptr then do nothing
if (style->fill.paint.none) { if (style->fill.paint.none) {
@ -782,13 +782,13 @@ static unique_ptr<Scene> _sceneBuildHelper(SvgLoaderData& loaderData, const SvgN
// For a Symbol node, the viewBox transformation has to be applied first - see _useBuildHelper() // 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 (!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; auto child = node->child.data;
for (uint32_t i = 0; i < node->child.count; ++i, ++child) { for (uint32_t i = 0; i < node->child.count; ++i, ++child) {
if (_isGroupType((*child)->type)) { if (_isGroupType((*child)->type)) {
if ((*child)->type == SvgNodeType::Use) if ((*child)->type == SvgNodeType::Use)
scene->push(_useBuildHelper(loaderData, *child, vBox, svgPath, depth + 1, isMaskWhite)); 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)); scene->push(_sceneBuildHelper(loaderData, *child, vBox, svgPath, false, depth + 1, isMaskWhite));
} else if ((*child)->type == SvgNodeType::Image) { } else if ((*child)->type == SvgNodeType::Image) {
auto image = _imageBuildHelper(loaderData, *child, vBox, svgPath); auto image = _imageBuildHelper(loaderData, *child, vBox, svgPath);