diff options
-rw-r--r-- | .qmake.conf | 2 | ||||
-rw-r--r-- | LGPL_EXCEPTION.txt | 22 | ||||
-rw-r--r-- | dist/changes-5.12.0 | 28 | ||||
-rw-r--r-- | examples/svg/network/bearercloud/bearercloud.cpp | 2 | ||||
-rw-r--r-- | examples/svg/network/bearercloud/cloud.cpp | 2 | ||||
-rw-r--r-- | examples/svg/network/bearercloud/cloud.h | 2 | ||||
-rw-r--r-- | examples/svg/richtext/textobject/textobject.pro | 5 | ||||
-rw-r--r-- | src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp | 95 | ||||
-rw-r--r-- | src/plugins/imageformats/svg/qsvgiohandler.cpp | 7 | ||||
-rw-r--r-- | src/svg/qsvggenerator.cpp | 2 | ||||
-rw-r--r-- | src/svg/qsvggraphics_p.h | 7 | ||||
-rw-r--r-- | src/svg/qsvghandler.cpp | 110 | ||||
-rw-r--r-- | src/svg/qsvghandler_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qsvgplugin/imageInclude.svg | 18 | ||||
-rw-r--r-- | tests/auto/qsvgplugin/imageIncludeA.svg | 5 | ||||
-rw-r--r-- | tests/auto/qsvgplugin/resources.qrc | 2 | ||||
-rw-r--r-- | tests/auto/qsvgplugin/tst_qsvgplugin.cpp | 41 | ||||
-rw-r--r-- | tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp | 45 |
18 files changed, 302 insertions, 95 deletions
diff --git a/.qmake.conf b/.qmake.conf index b952473..bc074d5 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -3,4 +3,4 @@ load(qt_build_config) CONFIG += warning_clean DEFINES += QT_NO_FOREACH -MODULE_VERSION = 5.11.3 +MODULE_VERSION = 5.12.0 diff --git a/LGPL_EXCEPTION.txt b/LGPL_EXCEPTION.txt deleted file mode 100644 index 5cdacb9..0000000 --- a/LGPL_EXCEPTION.txt +++ /dev/null @@ -1,22 +0,0 @@ -The Qt Company Qt LGPL Exception version 1.1 - -As an additional permission to the GNU Lesser General Public License version -2.1, the object code form of a "work that uses the Library" may incorporate -material from a header file that is part of the Library. You may distribute -such object code under terms of your choice, provided that: - (i) the header files of the Library have not been modified; and - (ii) the incorporated material is limited to numerical parameters, data - structure layouts, accessors, macros, inline functions and - templates; and - (iii) you comply with the terms of Section 6 of the GNU Lesser General - Public License version 2.1. - -Moreover, you may apply this exception to a modified version of the Library, -provided that such modification does not involve copying material from the -Library into the modified Library's header files unless such material is -limited to (i) numerical parameters; (ii) data structure layouts; -(iii) accessors; and (iv) small macros, templates and inline functions of -five lines or less in length. - -Furthermore, you are not required to apply this additional permission to a -modified version of the Library. diff --git a/dist/changes-5.12.0 b/dist/changes-5.12.0 new file mode 100644 index 0000000..63038d6 --- /dev/null +++ b/dist/changes-5.12.0 @@ -0,0 +1,28 @@ +Qt 5.12 introduces many new features and improvements as well as bugfixes +over the 5.11.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* General * +**************************************************************************** + + - SVG Reading/Rendering: + * [QTBUG-59978][QTBUG-67995] Fix objectBoundingBox transformed gradients + * [QTBUG-69694] Fix parsing of forward referrals in <use> elements + + - QIcon/QSvgIconEngine: + * [QTBUG-67452] Made SVG icons behave like pixmap icons: An + explicitly-set disabled icon is no longer additionally grayed out. diff --git a/examples/svg/network/bearercloud/bearercloud.cpp b/examples/svg/network/bearercloud/bearercloud.cpp index 610764a..0f08aec 100644 --- a/examples/svg/network/bearercloud/bearercloud.cpp +++ b/examples/svg/network/bearercloud/bearercloud.cpp @@ -131,7 +131,7 @@ void BearerCloud::timerEvent(QTimerEvent *) bool cloudsMoved = false; for (Cloud *cloud : clouds) - cloudsMoved |= cloud->advance(); + cloudsMoved |= cloud->advanceAnimation(); if (!cloudsMoved) { killTimer(timerId); diff --git a/examples/svg/network/bearercloud/cloud.cpp b/examples/svg/network/bearercloud/cloud.cpp index 43f6379..4e0313a 100644 --- a/examples/svg/network/bearercloud/cloud.cpp +++ b/examples/svg/network/bearercloud/cloud.cpp @@ -170,7 +170,7 @@ void Cloud::calculateForces() newPos.setY(qMin(qMax(newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10)); } -bool Cloud::advance() +bool Cloud::advanceAnimation() { static const qreal scaleDelta = 0.01; diff --git a/examples/svg/network/bearercloud/cloud.h b/examples/svg/network/bearercloud/cloud.h index 2a728d1..a91b994 100644 --- a/examples/svg/network/bearercloud/cloud.h +++ b/examples/svg/network/bearercloud/cloud.h @@ -76,7 +76,7 @@ public: void calculateForces(); - bool advance(); + bool advanceAnimation(); QRectF boundingRect() const override; void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override; diff --git a/examples/svg/richtext/textobject/textobject.pro b/examples/svg/richtext/textobject/textobject.pro index 8892ae7..a19d2b2 100644 --- a/examples/svg/richtext/textobject/textobject.pro +++ b/examples/svg/richtext/textobject/textobject.pro @@ -12,8 +12,3 @@ RESOURCES = resources.qrc target.path = $$[QT_INSTALL_EXAMPLES]/svg/richtext/textobject INSTALLS += target -wince*{ - filesToDeploy.files = files/*.svg - filesToDeploy.path = files - DEPLOYMENT += filesToDeploy -} diff --git a/src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp b/src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp index 0c54e0e..e23dd9a 100644 --- a/src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp +++ b/src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp @@ -74,7 +74,8 @@ public: void stepSerialNum() { serialNum = lastSerialNum.fetchAndAddRelaxed(1); } - void loadDataForModeAndState(QSvgRenderer *renderer, QIcon::Mode mode, QIcon::State state); + bool tryLoad(QSvgRenderer *renderer, QIcon::Mode mode, QIcon::State state); + QIcon::Mode loadDataForModeAndState(QSvgRenderer *renderer, QIcon::Mode mode, QIcon::State state); QHash<int, QString> svgFiles; QHash<int, QByteArray> *svgBuffers; @@ -121,31 +122,73 @@ QSize QSvgIconEngine::actualSize(const QSize &size, QIcon::Mode mode, return pm.size(); } -void QSvgIconEnginePrivate::loadDataForModeAndState(QSvgRenderer *renderer, QIcon::Mode mode, QIcon::State state) +static QByteArray maybeUncompress(const QByteArray &ba) { - QByteArray buf; - const QIcon::State oppositeState = state == QIcon::Off ? QIcon::On : QIcon::Off; - if (svgBuffers) { - buf = svgBuffers->value(hashKey(mode, state)); - if (buf.isEmpty()) - buf = svgBuffers->value(hashKey(QIcon::Normal, state)); - if (buf.isEmpty()) - buf = svgBuffers->value(hashKey(QIcon::Normal, oppositeState)); - } - if (!buf.isEmpty()) { #ifndef QT_NO_COMPRESS - buf = qUncompress(buf); + return qUncompress(ba); +#else + return ba; #endif - renderer->load(buf); +} + +bool QSvgIconEnginePrivate::tryLoad(QSvgRenderer *renderer, QIcon::Mode mode, QIcon::State state) +{ + if (svgBuffers) { + QByteArray buf = svgBuffers->value(hashKey(mode, state)); + if (!buf.isEmpty()) { + buf = maybeUncompress(buf); + renderer->load(buf); + return true; + } + } + QString svgFile = svgFiles.value(hashKey(mode, state)); + if (!svgFile.isEmpty()) { + renderer->load(svgFile); + return true; + } + return false; +} + +QIcon::Mode QSvgIconEnginePrivate::loadDataForModeAndState(QSvgRenderer *renderer, QIcon::Mode mode, QIcon::State state) +{ + if (tryLoad(renderer, mode, state)) + return mode; + + const QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off : QIcon::On; + if (mode == QIcon::Disabled || mode == QIcon::Selected) { + const QIcon::Mode oppositeMode = (mode == QIcon::Disabled) ? QIcon::Selected : QIcon::Disabled; + if (tryLoad(renderer, QIcon::Normal, state)) + return QIcon::Normal; + if (tryLoad(renderer, QIcon::Active, state)) + return QIcon::Active; + if (tryLoad(renderer, mode, oppositeState)) + return mode; + if (tryLoad(renderer, QIcon::Normal, oppositeState)) + return QIcon::Normal; + if (tryLoad(renderer, QIcon::Active, oppositeState)) + return QIcon::Active; + if (tryLoad(renderer, oppositeMode, state)) + return oppositeMode; + if (tryLoad(renderer, oppositeMode, oppositeState)) + return oppositeMode; } else { - QString svgFile = svgFiles.value(hashKey(mode, state)); - if (svgFile.isEmpty()) - svgFile = svgFiles.value(hashKey(QIcon::Normal, state)); - if (svgFile.isEmpty()) - svgFile = svgFiles.value(hashKey(QIcon::Normal, oppositeState)); - if (!svgFile.isEmpty()) - renderer->load(svgFile); + const QIcon::Mode oppositeMode = (mode == QIcon::Normal) ? QIcon::Active : QIcon::Normal; + if (tryLoad(renderer, oppositeMode, state)) + return oppositeMode; + if (tryLoad(renderer, mode, oppositeState)) + return mode; + if (tryLoad(renderer, oppositeMode, oppositeState)) + return oppositeMode; + if (tryLoad(renderer, QIcon::Disabled, state)) + return QIcon::Disabled; + if (tryLoad(renderer, QIcon::Selected, state)) + return QIcon::Selected; + if (tryLoad(renderer, QIcon::Disabled, oppositeState)) + return QIcon::Disabled; + if (tryLoad(renderer, QIcon::Selected, oppositeState)) + return QIcon::Selected; } + return QIcon::Normal; } QPixmap QSvgIconEngine::pixmap(const QSize &size, QIcon::Mode mode, @@ -164,7 +207,7 @@ QPixmap QSvgIconEngine::pixmap(const QSize &size, QIcon::Mode mode, } QSvgRenderer renderer; - d->loadDataForModeAndState(&renderer, mode, state); + const QIcon::Mode loadmode = d->loadDataForModeAndState(&renderer, mode, state); if (!renderer.isValid()) return pm; @@ -182,9 +225,11 @@ QPixmap QSvgIconEngine::pixmap(const QSize &size, QIcon::Mode mode, p.end(); pm = QPixmap::fromImage(img); if (qobject_cast<QGuiApplication *>(QCoreApplication::instance())) { - const QPixmap generated = QGuiApplicationPrivate::instance()->applyQIconStyleHelper(mode, pm); - if (!generated.isNull()) - pm = generated; + if (loadmode != mode && mode != QIcon::Normal) { + const QPixmap generated = QGuiApplicationPrivate::instance()->applyQIconStyleHelper(mode, pm); + if (!generated.isNull()) + pm = generated; + } } if (!pm.isNull()) diff --git a/src/plugins/imageformats/svg/qsvgiohandler.cpp b/src/plugins/imageformats/svg/qsvgiohandler.cpp index 457c79e..a999d47 100644 --- a/src/plugins/imageformats/svg/qsvgiohandler.cpp +++ b/src/plugins/imageformats/svg/qsvgiohandler.cpp @@ -176,8 +176,13 @@ bool QSvgIOHandler::read(QImage *image) t.translate(tr1.x(), tr1.y()); bounds = t.mapRect(bounds); } - if (image->size() != finalSize || !image->reinterpretAsFormat(QImage::Format_ARGB32_Premultiplied)) + if (image->size() != finalSize || !image->reinterpretAsFormat(QImage::Format_ARGB32_Premultiplied)) { *image = QImage(finalSize, QImage::Format_ARGB32_Premultiplied); + if (!finalSize.isEmpty() && image->isNull()) { + qWarning("QSvgIOHandler: QImage allocation failed (size %i x %i)", finalSize.width(), finalSize.height()); + return false; + } + } if (!finalSize.isEmpty()) { image->fill(d->backColor.rgba()); QPainter p(image); diff --git a/src/svg/qsvggenerator.cpp b/src/svg/qsvggenerator.cpp index 424cc76..07f8d74 100644 --- a/src/svg/qsvggenerator.cpp +++ b/src/svg/qsvggenerator.cpp @@ -334,7 +334,7 @@ public: void saveGradientUnits(QTextStream &str, const QGradient *gradient) { str << QLatin1String("gradientUnits=\""); - if (gradient && gradient->coordinateMode() == QGradient::ObjectBoundingMode) + if (gradient && (gradient->coordinateMode() == QGradient::ObjectBoundingMode || gradient->coordinateMode() == QGradient::ObjectMode)) str << QLatin1String("objectBoundingBox"); else str << QLatin1String("userSpaceOnUse"); 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 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()) { diff --git a/src/svg/qsvghandler_p.h b/src/svg/qsvghandler_p.h index 2c06cb4..8eb061b 100644 --- a/src/svg/qsvghandler_p.h +++ b/src/svg/qsvghandler_p.h @@ -99,6 +99,7 @@ public: QSvgHandler(QXmlStreamReader *const data); ~QSvgHandler(); + QIODevice *device() const; QSvgTinyDocument *document() const; inline bool ok() const { @@ -178,6 +179,7 @@ private: #endif void parse(); void resolveGradients(QSvgNode *node); + void resolveNodes(); QPen m_defaultPen; /** diff --git a/tests/auto/qsvgplugin/imageInclude.svg b/tests/auto/qsvgplugin/imageInclude.svg new file mode 100644 index 0000000..c78d3fa --- /dev/null +++ b/tests/auto/qsvgplugin/imageInclude.svg @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<svg version="1.0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100"> + <circle cx="50" cy="50" r="25" fill="#00ff00" /> + + <image x="0" y="0" width="100" height="100" xlink:href="imageIncludeA.svg" /> + <image x="0" y="0" width="100" height="100" xlink:href="./imageIncludeA.svg" /> + <image x="0" y="0" width="100" height="100" xlink:href=":/imageIncludeA.svg" /> + + <image x="0" y="0" width="100" height="100" xlink:href="notExisting.svg" /> + <image x="0" y="0" width="100" height="100" xlink:href="./notExisting.svg" /> + <image x="0" y="0" width="100" height="100" xlink:href="../notExisting.svg" /> + <image x="0" y="0" width="100" height="100" xlink:href="/notExisting.svg" /> + <image x="0" y="0" width="100" height="100" xlink:href=":/notExisting.svg" /> + <image x="0" y="0" width="100" height="100" xlink:href="qrc:///notExisting.svg" /> + <image x="0" y="0" width="100" height="100" xlink:href="file:///notExisting.svg" /> + <image x="0" y="0" width="100" height="100" xlink:href="http://qt.io/notExisting.svg" /> +</svg> diff --git a/tests/auto/qsvgplugin/imageIncludeA.svg b/tests/auto/qsvgplugin/imageIncludeA.svg new file mode 100644 index 0000000..5811505 --- /dev/null +++ b/tests/auto/qsvgplugin/imageIncludeA.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"> + <circle cx="50" cy="50" r="25" fill="#00ff00" /> +</svg> diff --git a/tests/auto/qsvgplugin/resources.qrc b/tests/auto/qsvgplugin/resources.qrc index fcb311a..fd83b80 100644 --- a/tests/auto/qsvgplugin/resources.qrc +++ b/tests/auto/qsvgplugin/resources.qrc @@ -1,5 +1,7 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource> + <file>imageInclude.svg</file> + <file>imageIncludeA.svg</file> <file>square.svg</file> <file>square_size.svg</file> <file>square_size_viewbox.svg</file> diff --git a/tests/auto/qsvgplugin/tst_qsvgplugin.cpp b/tests/auto/qsvgplugin/tst_qsvgplugin.cpp index 4ec1737..da49b75 100644 --- a/tests/auto/qsvgplugin/tst_qsvgplugin.cpp +++ b/tests/auto/qsvgplugin/tst_qsvgplugin.cpp @@ -39,6 +39,16 @@ #endif +QStringList logMessages; + +static void messageHandler(QtMsgType pType, const QMessageLogContext& pContext, const QString& pMsg) +{ + Q_UNUSED(pType); + Q_UNUSED(pContext); + logMessages.append(pMsg); +} + + class tst_QSvgPlugin : public QObject { Q_OBJECT @@ -50,6 +60,7 @@ public: private slots: void checkSize_data(); void checkSize(); + void checkImageInclude(); }; @@ -103,6 +114,36 @@ void tst_QSvgPlugin::checkSize() QCOMPARE(imageWidth, image.width()); } +void tst_QSvgPlugin::checkImageInclude() +{ + const QString filename(SRCDIR "imageInclude.svg"); + + QFile file(filename); + file.open(QIODevice::ReadOnly); + + QSvgIOHandler plugin; + plugin.setDevice(&file); + + QImage image; + qInstallMessageHandler(messageHandler); + plugin.read(&image); + qInstallMessageHandler(nullptr); + + file.close(); + + QCOMPARE(logMessages.size(), 8); + QCOMPARE(logMessages.at(0), QString("Could not create image from \"%1notExisting.svg\"").arg(SRCDIR)); + QCOMPARE(logMessages.at(1), QString("Could not create image from \"%1./notExisting.svg\"").arg(SRCDIR)); + QCOMPARE(logMessages.at(2), QString("Could not create image from \"%1../notExisting.svg\"").arg(SRCDIR)); + QCOMPARE(logMessages.at(3), QString("Could not create image from \"%1notExisting.svg\"").arg(QDir::rootPath())); + QCOMPARE(logMessages.at(4), QLatin1String("Could not create image from \":/notExisting.svg\"")); + QCOMPARE(logMessages.at(5), QLatin1String("Could not create image from \"qrc:///notExisting.svg\"")); + QCOMPARE(logMessages.at(6), QLatin1String("Could not create image from \"file:///notExisting.svg\"")); + QCOMPARE(logMessages.at(7), QLatin1String("Could not create image from \"http://qt.io/notExisting.svg\"")); + + logMessages.clear(); +} + QTEST_MAIN(tst_QSvgPlugin) #include "tst_qsvgplugin.moc" diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp index a8fc9de..5e13bee 100644 --- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp +++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp @@ -1261,32 +1261,36 @@ void tst_QSvgRenderer::testStopOffsetOpacity() void tst_QSvgRenderer::testUseElement() { static const char *svgs[] = { - //Use referring to non group node (1) + // 0 - Use referring to non group node (1) "<svg viewBox = \"0 0 200 200\">" " <polygon points=\"20,20 50,120 100,10 40,80 50,80\"/>" " <polygon points=\"20,80 50,180 100,70 40,140 50,140\" fill= \"red\" stroke = \"blue\" fill-opacity = \"0.7\" fill-rule = \"evenodd\" stroke-width = \"3\"/>" "</svg>", + // 1 "<svg viewBox = \"0 0 200 200\">" " <polygon id = \"usedPolyline\" points=\"20,20 50,120 100,10 40,80 50,80\"/>" " <use y = \"60\" xlink:href = \"#usedPolyline\" fill= \"red\" stroke = \"blue\" fill-opacity = \"0.7\" fill-rule = \"evenodd\" stroke-width = \"3\"/>" "</svg>", + // 2 "<svg viewBox = \"0 0 200 200\">" " <polygon id = \"usedPolyline\" points=\"20,20 50,120 100,10 40,80 50,80\"/>" " <g fill = \" red\" fill-opacity =\"0.2\">" "<use y = \"60\" xlink:href = \"#usedPolyline\" stroke = \"blue\" fill-opacity = \"0.7\" fill-rule = \"evenodd\" stroke-width = \"3\"/>" "</g>" "</svg>", + // 3 "<svg viewBox = \"0 0 200 200\">" " <polygon id = \"usedPolyline\" points=\"20,20 50,120 100,10 40,80 50,80\"/>" " <g stroke-width = \"3\" stroke = \"yellow\">" " <use y = \"60\" xlink:href = \"#usedPolyline\" fill = \" red\" stroke = \"blue\" fill-opacity = \"0.7\" fill-rule = \"evenodd\"/>" " </g>" "</svg>", - //Use referring to non group node (2) + // 4 - Use referring to non group node (2) "<svg viewBox = \"0 0 200 200\">" " <polygon points=\"20,20 50,120 100,10 40,80 50,80\" fill = \"green\" fill-rule = \"nonzero\" stroke = \"purple\" stroke-width = \"4\" stroke-dasharray = \"1,1,3,1\" stroke-offset = \"3\" stroke-miterlimit = \"6\" stroke-linecap = \"butt\" stroke-linejoin = \"round\"/>" " <polygon points=\"20,80 50,180 100,70 40,140 50,140\" fill= \"red\" stroke = \"blue\" fill-opacity = \"0.7\" fill-rule = \"evenodd\" stroke-width = \"3\" stroke-dasharray = \"1,1,1,1\" stroke-offset = \"5\" stroke-miterlimit = \"3\" stroke-linecap = \"butt\" stroke-linejoin = \"square\"/>" "</svg>", + // 5 "<svg viewBox = \"0 0 200 200\">" " <g fill = \"green\" fill-rule = \"nonzero\" stroke = \"purple\" stroke-width = \"4\" stroke-dasharray = \"1,1,3,1\" stroke-offset = \"3\" stroke-miterlimit = \"6\" stroke-linecap = \"butt\" stroke-linejoin = \"round\">" " <polygon id = \"usedPolyline\" points=\"20,20 50,120 100,10 40,80 50,80\" />" @@ -1295,6 +1299,7 @@ void tst_QSvgRenderer::testUseElement() " <use y = \"60\" xlink:href = \"#usedPolyline\" fill-opacity = \"0.7\" fill= \"red\" stroke = \"blue\" fill-rule = \"evenodd\"/>" " </g>" "</svg>", + // 6 "<svg viewBox = \"0 0 200 200\">" " <g fill = \"green\" fill-rule = \"nonzero\" stroke = \"purple\" stroke-width = \"4\" stroke-dasharray = \"1,1,3,1\" stroke-offset = \"3\" stroke-miterlimit = \"6\" stroke-linecap = \"butt\" stroke-linejoin = \"round\">" " <polygon id = \"usedPolyline\" points=\"20,20 50,120 100,10 40,80 50,80\" />" @@ -1303,7 +1308,7 @@ void tst_QSvgRenderer::testUseElement() " <use y = \"60\" xlink:href = \"#usedPolyline\" fill= \"red\" stroke = \"blue\" fill-opacity = \"0.7\" fill-rule = \"evenodd\" />" " </g>" "</svg>", - //Use referring to group node + // 7 - Use referring to group node "<svg viewBox = \"0 0 200 200\">" " <g>" " <circle cx=\"0\" cy=\"0\" r=\"100\" fill = \"red\" fill-opacity = \"0.6\"/>" @@ -1311,6 +1316,7 @@ void tst_QSvgRenderer::testUseElement() " <circle fill=\"#a6ce39\" cx=\"0\" cy=\"0\" r=\"33\" fill-opacity = \"0.5\"/>" " </g>" "</svg>", + // 8 "<svg viewBox = \"0 0 200 200\">" " <defs>" " <g id=\"usedG\">" @@ -1321,6 +1327,7 @@ void tst_QSvgRenderer::testUseElement() " </defs>" " <use xlink:href =\"#usedG\" fill = \"red\" fill-opacity =\"0.5\"/>" "</svg>", + // 9 "<svg viewBox = \"0 0 200 200\">" " <defs>" " <g fill = \"blue\" fill-opacity = \"0.3\">" @@ -1335,16 +1342,40 @@ void tst_QSvgRenderer::testUseElement() " <use xlink:href =\"#usedG\" />" " </g>" "</svg>", - // Self referral, should be ignored + // 10 - Self referral, should be ignored "<svg><g id=\"0\"><use xlink:href=\"#0\" /></g></svg>", + // 11 "<svg width=\"200\" height=\"200\">" " <rect width=\"100\" height=\"50\"/>" "</svg>", + // 12 "<svg width=\"200\" height=\"200\">" " <g id=\"0\"><use xlink:href=\"#0\" /><rect width=\"100\" height=\"50\"/></g>" "</svg>", + // 13 "<svg width=\"200\" height=\"200\">" " <g id=\"0\"><g><use xlink:href=\"#0\" /><rect width=\"100\" height=\"50\"/></g></g>" + "</svg>", + // 14 (undefined) + "<svg width=\"200\" height=\"200\">" + " <rect width=\"100\" height=\"50\"/>" + " <use x=\"100\" y=\"100\" opacity=\"0.5\" xlink:href=\"#nosuch\" />" + "</svg>", + // 15 - Forward references + "<svg viewBox = \"0 0 200 200\">" + " <use y = \"60\" xlink:href = \"#usedPolyline\" fill= \"red\" stroke = \"blue\" fill-opacity = \"0.7\" fill-rule = \"evenodd\" stroke-width = \"3\"/>" + " <polygon id = \"usedPolyline\" points=\"20,20 50,120 100,10 40,80 50,80\"/>" + "</svg>", + // 16 + "<svg viewBox = \"0 0 200 200\">" + " <use xlink:href =\"#usedG\" fill = \"red\" fill-opacity =\"0.5\"/>" + " <defs>" + " <g id=\"usedG\">" + " <circle cx=\"0\" cy=\"0\" r=\"100\" fill-opacity = \"0.6\"/>" + " <rect x = \"10\" y = \"10\" width = \"30\" height = \"30\"/>" + " <circle fill=\"#a6ce39\" cx=\"0\" cy=\"0\" r=\"33\" />" + " </g>" + " </defs>" "</svg>" }; @@ -1373,8 +1404,12 @@ void tst_QSvgRenderer::testUseElement() } } else if (i > 7 && i < 10) { QCOMPARE(images[8], images[i]); - } else if (i > 11) { + } else if (i > 11 && i < 15) { QCOMPARE(images[11], images[i]); + } else if (i == 15) { + QCOMPARE(images[0], images[i]); + } else if (i == 16) { + QCOMPARE(images[8], images[i]); } } } |