summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEirik Aavitsland <eirik.aavitsland@qt.io>2018-08-10 13:25:11 +0200
committerEirik Aavitsland <eirik.aavitsland@qt.io>2018-08-20 13:59:12 +0000
commit907c2db46915eedac02f2a5a26291d2ce19282f9 (patch)
tree633734fcfacb6b48e626fdd0ee74baf20d2a221a /src
parentbb80aeee1fb19445889210ec913046d0ca385721 (diff)
downloadqtsvg-907c2db46915eedac02f2a5a26291d2ce19282f9.tar.gz
Fix parsing of forward referrals in use elements
SVG <use> elements may refer to a node that is defined later in the file. The parser would then fail to resolve the link. Implement delayed link resolution in the parser to handle such cases. Task-number: QTBUG-69694 Change-Id: I94ffb3511dbd0fac822bb56991415b2d99ccf90e Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/svg/qsvggraphics_p.h7
-rw-r--r--src/svg/qsvghandler.cpp62
-rw-r--r--src/svg/qsvghandler_p.h1
3 files changed, 55 insertions, 15 deletions
diff --git a/src/svg/qsvggraphics_p.h b/src/svg/qsvggraphics_p.h
index 33b5154..6e5b9d6 100644
--- a/src/svg/qsvggraphics_p.h
+++ b/src/svg/qsvggraphics_p.h
@@ -237,13 +237,20 @@ class QSvgUse : public QSvgNode
{
public:
QSvgUse(const QPointF &start, QSvgNode *parent, QSvgNode *link);
+ QSvgUse(const QPointF &start, QSvgNode *parent, const QString &linkId)
+ : QSvgUse(start, parent, nullptr)
+ { m_linkId = linkId; }
void draw(QPainter *p, QSvgExtraStates &states) override;
Type type() const override;
QRectF bounds(QPainter *p, QSvgExtraStates &states) const override;
+ bool isResolved() const { return m_link != nullptr; }
+ QString linkId() const { return m_linkId; }
+ void setLink(QSvgNode *link) { m_link = link; }
private:
QSvgNode *m_link;
QPointF m_start;
+ QString m_linkId;
};
class QSvgVideo : public QSvgNode
diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp
index b625d3f..5242ffe 100644
--- a/src/svg/qsvghandler.cpp
+++ b/src/svg/qsvghandler.cpp
@@ -3359,29 +3359,30 @@ static QSvgNode *createUseNode(QSvgNode *parent,
}
if (group) {
+ QPointF pt;
+ if (!xStr.isNull() || !yStr.isNull()) {
+ QSvgHandler::LengthType type;
+ qreal nx = parseLength(xStr, type, handler);
+ nx = convertToPixels(nx, true, type);
+
+ qreal ny = parseLength(yStr, type, handler);
+ ny = convertToPixels(ny, true, type);
+ pt = QPointF(nx, ny);
+ }
+
QSvgNode *link = group->scopeNode(linkId);
if (link) {
if (parent->isDescendantOf(link))
qCWarning(lcSvgHandler, "link #%s is recursive!", qPrintable(linkId));
- QPointF pt;
- if (!xStr.isNull() || !yStr.isNull()) {
- QSvgHandler::LengthType type;
- qreal nx = parseLength(xStr, type, handler);
- nx = convertToPixels(nx, true, type);
-
- qreal ny = parseLength(yStr, type, handler);
- ny = convertToPixels(ny, true, type);
- pt = QPointF(nx, ny);
- }
- //delay link resolving till the first draw call on
- //use nodes, link 2might have not been created yet
- QSvgUse *node = new QSvgUse(pt, parent, link);
- return node;
+ return new QSvgUse(pt, parent, link);
}
+
+ //delay link resolving, link might have not been created yet
+ return new QSvgUse(pt, parent, linkId);
}
- qCWarning(lcSvgHandler, "link %s hasn't been detected!", qPrintable(linkId));
+ qCWarning(lcSvgHandler, "<use> element %s in wrong context!", qPrintable(linkId));
return 0;
}
@@ -3647,6 +3648,7 @@ void QSvgHandler::parse()
}
}
resolveGradients(m_doc);
+ resolveNodes();
}
bool QSvgHandler::startElement(const QString &localName,
@@ -3751,6 +3753,9 @@ bool QSvgHandler::startElement(const QString &localName,
static_cast<QSvgText *>(node)->setWhitespaceMode(m_whitespaceMode.top());
} else if (node->type() == QSvgNode::TSPAN) {
static_cast<QSvgTspan *>(node)->setWhitespaceMode(m_whitespaceMode.top());
+ } else if (node->type() == QSvgNode::USE) {
+ if (!static_cast<QSvgUse *>(node)->isResolved())
+ m_resolveNodes.append(node);
}
}
}
@@ -3853,6 +3858,33 @@ void QSvgHandler::resolveGradients(QSvgNode *node)
}
}
+void QSvgHandler::resolveNodes()
+{
+ for (QSvgNode *node : qAsConst(m_resolveNodes)) {
+ if (!node || !node->parent() || node->type() != QSvgNode::USE)
+ continue;
+ QSvgUse *useNode = static_cast<QSvgUse *>(node);
+ if (useNode->isResolved())
+ continue;
+ QSvgNode::Type t = useNode->parent()->type();
+ if (!(t == QSvgNode::DOC || t == QSvgNode::DEFS || t == QSvgNode::G || t == QSvgNode::SWITCH))
+ continue;
+
+ QSvgStructureNode *group = static_cast<QSvgStructureNode *>(useNode->parent());
+ QSvgNode *link = group->scopeNode(useNode->linkId());
+ if (!link) {
+ qCWarning(lcSvgHandler, "link #%s is undefined!", qPrintable(useNode->linkId()));
+ continue;
+ }
+
+ if (useNode->parent()->isDescendantOf(link))
+ qCWarning(lcSvgHandler, "link #%s is recursive!", qPrintable(useNode->linkId()));
+
+ useNode->setLink(link);
+ }
+ m_resolveNodes.clear();
+}
+
bool QSvgHandler::characters(const QStringRef &str)
{
#ifndef QT_NO_CSSPARSER
diff --git a/src/svg/qsvghandler_p.h b/src/svg/qsvghandler_p.h
index 2c06cb4..5c13003 100644
--- a/src/svg/qsvghandler_p.h
+++ b/src/svg/qsvghandler_p.h
@@ -178,6 +178,7 @@ private:
#endif
void parse();
void resolveGradients(QSvgNode *node);
+ void resolveNodes();
QPen m_defaultPen;
/**