diff options
Diffstat (limited to 'src/svg/qsvghandler.cpp')
-rw-r--r-- | src/svg/qsvghandler.cpp | 110 |
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()) { |