svg_loader: postponed nodes properly cloned

In case when no defs tag was used, no child node was found.
Also the node attributes should not override those set in the ancestor.
This commit is contained in:
Mira Grudzinska 2022-01-05 16:49:43 +01:00 committed by Mira Grudzinska
parent f0141e63de
commit 6fb0984b49

View file

@ -1745,6 +1745,112 @@ error_grad_alloc:
}
static void _styleInherit(SvgStyleProperty* child, const SvgStyleProperty* parent)
{
if (parent == nullptr) return;
//Inherit the property of parent if not present in child.
if (!child->curColorSet) {
child->color = parent->color;
child->curColorSet = parent->curColorSet;
}
//Fill
if (!((int)child->fill.flags & (int)SvgFillFlags::Paint)) {
child->fill.paint.color = parent->fill.paint.color;
child->fill.paint.none = parent->fill.paint.none;
child->fill.paint.curColor = parent->fill.paint.curColor;
if (parent->fill.paint.url) child->fill.paint.url = _copyId(parent->fill.paint.url);
}
if (!((int)child->fill.flags & (int)SvgFillFlags::Opacity)) {
child->fill.opacity = parent->fill.opacity;
}
if (!((int)child->fill.flags & (int)SvgFillFlags::FillRule)) {
child->fill.fillRule = parent->fill.fillRule;
}
//Stroke
if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Paint)) {
child->stroke.paint.color = parent->stroke.paint.color;
child->stroke.paint.none = parent->stroke.paint.none;
child->stroke.paint.curColor = parent->stroke.paint.curColor;
child->stroke.paint.url = parent->stroke.paint.url ? _copyId(parent->stroke.paint.url) : nullptr;
}
if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Opacity)) {
child->stroke.opacity = parent->stroke.opacity;
}
if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Width)) {
child->stroke.width = parent->stroke.width;
}
if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Dash)) {
if (parent->stroke.dash.array.count > 0) {
child->stroke.dash.array.clear();
child->stroke.dash.array.reserve(parent->stroke.dash.array.count);
for (uint32_t i = 0; i < parent->stroke.dash.array.count; ++i) {
child->stroke.dash.array.push(parent->stroke.dash.array.data[i]);
}
}
}
if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Cap)) {
child->stroke.cap = parent->stroke.cap;
}
if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Join)) {
child->stroke.join = parent->stroke.join;
}
}
static void _styleCopy(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) {
to->color = from->color;
to->curColorSet = true;
}
//Fill
to->fill.flags = (SvgFillFlags)((int)to->fill.flags | (int)from->fill.flags);
if (((int)from->fill.flags & (int)SvgFillFlags::Paint)) {
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);
}
if (((int)from->fill.flags & (int)SvgFillFlags::Opacity)) {
to->fill.opacity = from->fill.opacity;
}
if (((int)from->fill.flags & (int)SvgFillFlags::FillRule)) {
to->fill.fillRule = from->fill.fillRule;
}
//Stroke
to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)from->stroke.flags);
if (((int)from->stroke.flags & (int)SvgStrokeFlags::Paint)) {
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;
}
if (((int)from->stroke.flags & (int)SvgStrokeFlags::Opacity)) {
to->stroke.opacity = from->stroke.opacity;
}
if (((int)from->stroke.flags & (int)SvgStrokeFlags::Width)) {
to->stroke.width = from->stroke.width;
}
if (((int)from->stroke.flags & (int)SvgStrokeFlags::Dash)) {
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]);
}
}
}
if (((int)from->stroke.flags & (int)SvgStrokeFlags::Cap)) {
to->stroke.cap = from->stroke.cap;
}
if (((int)from->stroke.flags & (int)SvgStrokeFlags::Join)) {
to->stroke.join = from->stroke.join;
}
}
static void _copyAttr(SvgNode* to, const SvgNode* from)
{
//Copy matrix attribute
@ -1753,7 +1859,8 @@ static void _copyAttr(SvgNode* to, const SvgNode* from)
if (to->transform) *to->transform = *from->transform;
}
//Copy style attribute
*to->style = *from->style;
_styleCopy(to->style, from->style);
to->style->flags = (SvgStyleFlags)((int)to->style->flags | (int)from->style->flags);
if (from->style->fill.paint.url) to->style->fill.paint.url = strdup(from->style->fill.paint.url);
if (from->style->stroke.paint.url) to->style->stroke.paint.url = strdup(from->style->stroke.paint.url);
if (from->style->clipPath.url) to->style->clipPath.url = strdup(from->style->clipPath.url);
@ -1829,9 +1936,9 @@ static void _cloneNode(SvgNode* from, SvgNode* parent)
if (!from || !parent) return;
newNode = _createNode(parent, from->type);
if (!newNode) return;
_styleInherit(newNode->style, parent->style);
_copyAttr(newNode, from);
auto child = from->child.data;
@ -1841,16 +1948,19 @@ static void _cloneNode(SvgNode* from, SvgNode* parent)
}
static void _postponeCloneNode(SvgLoaderData* loader, SvgNode *node, char* id) {
static void _postponeCloneNode(SvgLoaderData* loader, SvgNode *node, char* id)
{
loader->cloneNodes.push({node, id});
}
static void _clonePostponedNodes(Array<SvgNodeIdPair>* cloneNodes) {
static void _clonePostponedNodes(Array<SvgNodeIdPair>* cloneNodes, SvgNode* doc)
{
for (uint32_t i = 0; i < cloneNodes->count; ++i) {
auto nodeIdPair = cloneNodes->data[i];
auto defs = _getDefsNode(nodeIdPair.node);
auto nodeFrom = _findChildById(defs, nodeIdPair.id);
if (!nodeFrom) nodeFrom = _findChildById(doc, nodeIdPair.id);
_cloneNode(nodeFrom, nodeIdPair.node);
free(nodeIdPair.id);
}
@ -2508,59 +2618,8 @@ static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content
}
static void _styleInherit(SvgStyleProperty* child, const SvgStyleProperty* parent)
static void _inefficientNodeCheck(TVG_UNUSED SvgNode* node)
{
if (parent == nullptr) return;
//Inherit the property of parent if not present in child.
if (!child->curColorSet) {
child->color = parent->color;
child->curColorSet = parent->curColorSet;
}
//Fill
if (!((int)child->fill.flags & (int)SvgFillFlags::Paint)) {
child->fill.paint.color = parent->fill.paint.color;
child->fill.paint.none = parent->fill.paint.none;
child->fill.paint.curColor = parent->fill.paint.curColor;
if (parent->fill.paint.url) child->fill.paint.url = _copyId(parent->fill.paint.url);
}
if (!((int)child->fill.flags & (int)SvgFillFlags::Opacity)) {
child->fill.opacity = parent->fill.opacity;
}
if (!((int)child->fill.flags & (int)SvgFillFlags::FillRule)) {
child->fill.fillRule = parent->fill.fillRule;
}
//Stroke
if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Paint)) {
child->stroke.paint.color = parent->stroke.paint.color;
child->stroke.paint.none = parent->stroke.paint.none;
child->stroke.paint.curColor = parent->stroke.paint.curColor;
child->stroke.paint.url = parent->stroke.paint.url ? _copyId(parent->stroke.paint.url) : nullptr;
}
if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Opacity)) {
child->stroke.opacity = parent->stroke.opacity;
}
if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Width)) {
child->stroke.width = parent->stroke.width;
}
if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Dash)) {
if (parent->stroke.dash.array.count > 0) {
child->stroke.dash.array.clear();
child->stroke.dash.array.reserve(parent->stroke.dash.array.count);
for (uint32_t i = 0; i < parent->stroke.dash.array.count; ++i) {
child->stroke.dash.array.push(parent->stroke.dash.array.data[i]);
}
}
}
if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Cap)) {
child->stroke.cap = parent->stroke.cap;
}
if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Join)) {
child->stroke.join = parent->stroke.join;
}
}
static void _inefficientNodeCheck(TVG_UNUSED SvgNode* node){
#ifdef THORVG_LOG_ENABLED
auto type = simpleXmlNodeTypeToString(node->type);
@ -2857,7 +2916,7 @@ void SvgLoader::run(unsigned tid)
_updateComposite(loaderData.doc, loaderData.doc);
if (defs) _updateComposite(loaderData.doc, defs);
if (loaderData.cloneNodes.count > 0) _clonePostponedNodes(&loaderData.cloneNodes);
if (loaderData.cloneNodes.count > 0) _clonePostponedNodes(&loaderData.cloneNodes, loaderData.doc);
if (loaderData.gradients.count > 0) _updateGradient(loaderData.doc, &loaderData.gradients);
if (defs) _updateGradient(loaderData.doc, &defs->node.defs.gradients);