summaryrefslogtreecommitdiff
path: root/src/svg/qsvghandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/svg/qsvghandler.cpp')
-rw-r--r--src/svg/qsvghandler.cpp110
1 files changed, 78 insertions, 32 deletions
diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp
index fe07d0e..e935649 100644
--- a/src/svg/qsvghandler.cpp
+++ b/src/svg/qsvghandler.cpp
@@ -59,6 +59,7 @@
#include "qdebug.h"
#include "qmath.h"
#include "qnumeric.h"
+#include <qregularexpression.h>
#include "qvarlengtharray.h"
#include "private/qmath_p.h"
@@ -2738,7 +2739,7 @@ static QSvgNode *createImageNode(QSvgNode *parent,
const QStringRef y = attributes.value(QLatin1String("y"));
const QStringRef width = attributes.value(QLatin1String("width"));
const QStringRef height = attributes.value(QLatin1String("height"));
- QStringRef filename = attributes.value(QLatin1String("xlink:href"));
+ QString filename = attributes.value(QLatin1String("xlink:href")).toString();
qreal nx = toDouble(x);
qreal ny = toDouble(y);
QSvgHandler::LengthType type;
@@ -2763,17 +2764,26 @@ static QSvgNode *createImageNode(QSvgNode *parent,
int idx = filename.lastIndexOf(QLatin1String("base64,"));
if (idx != -1) {
idx += 7;
- QStringRef dataStr = filename.mid(idx);
+ const QString dataStr = filename.mid(idx);
QByteArray data = QByteArray::fromBase64(dataStr.toLatin1());
image = QImage::fromData(data);
} else {
qCDebug(lcSvgHandler) << "QSvgHandler::createImageNode: Unrecognized inline image format!";
}
- } else
- image = QImage(filename.toString());
+ } else {
+ const auto *file = qobject_cast<QFile *>(handler->device());
+ if (file) {
+ QUrl url(filename);
+ if (url.isRelative()) {
+ QFileInfo info(file->fileName());
+ filename = info.absoluteDir().absoluteFilePath(filename);
+ }
+ }
+ image = QImage(filename);
+ }
if (image.isNull()) {
- qDebug()<<"couldn't create image from "<<filename;
+ qCWarning(lcSvgHandler) << "Could not create image from" << filename;
return 0;
}
@@ -2865,7 +2875,7 @@ static void parseBaseGradient(QSvgNode *node,
}
if (units.isEmpty() || units == QLatin1String("objectBoundingBox")) {
- grad->setCoordinateMode(QGradient::ObjectBoundingMode);
+ grad->setCoordinateMode(QGradient::ObjectMode);
}
}
@@ -3358,29 +3368,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;
}
@@ -3646,6 +3657,7 @@ void QSvgHandler::parse()
}
}
resolveGradients(m_doc);
+ resolveNodes();
}
bool QSvgHandler::startElement(const QString &localName,
@@ -3750,6 +3762,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);
}
}
}
@@ -3852,6 +3867,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
@@ -3875,6 +3917,11 @@ bool QSvgHandler::characters(const QStringRef &str)
return true;
}
+QIODevice *QSvgHandler::device() const
+{
+ return xml->device();
+}
+
QSvgTinyDocument * QSvgHandler::document() const
{
return m_doc;
@@ -3948,24 +3995,23 @@ bool QSvgHandler::processingInstruction(const QString &target, const QString &da
Q_UNUSED(data)
#else
if (target == QLatin1String("xml-stylesheet")) {
- QRegExp rx(QLatin1String("type=\\\"(.+)\\\""));
- rx.setMinimal(true);
+ QRegularExpression rx(QLatin1String("type=\\\"(.+)\\\""),
+ QRegularExpression::InvertedGreedinessOption);
+ QRegularExpressionMatchIterator iter = rx.globalMatch(data);
bool isCss = false;
- int pos = 0;
- while ((pos = rx.indexIn(data, pos)) != -1) {
- QString type = rx.cap(1);
+ while (iter.hasNext()) {
+ QRegularExpressionMatch match = iter.next();
+ QString type = match.captured(1);
if (type.toLower() == QLatin1String("text/css")) {
isCss = true;
}
- pos += rx.matchedLength();
}
if (isCss) {
- QRegExp rx(QLatin1String("href=\\\"(.+)\\\""));
- rx.setMinimal(true);
- pos = 0;
- pos = rx.indexIn(data, pos);
- QString addr = rx.cap(1);
+ QRegularExpression rx(QLatin1String("href=\\\"(.+)\\\""),
+ QRegularExpression::InvertedGreedinessOption);
+ QRegularExpressionMatch match = rx.match(data);
+ QString addr = match.captured(1);
QFileInfo fi(addr);
//qDebug()<<"External CSS file "<<fi.absoluteFilePath()<<fi.exists();
if (fi.exists()) {