summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--LGPL_EXCEPTION.txt22
-rw-r--r--dist/changes-5.12.028
-rw-r--r--examples/svg/network/bearercloud/bearercloud.cpp2
-rw-r--r--examples/svg/network/bearercloud/cloud.cpp2
-rw-r--r--examples/svg/network/bearercloud/cloud.h2
-rw-r--r--examples/svg/richtext/textobject/textobject.pro5
-rw-r--r--src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp95
-rw-r--r--src/plugins/imageformats/svg/qsvgiohandler.cpp7
-rw-r--r--src/svg/qsvggenerator.cpp2
-rw-r--r--src/svg/qsvggraphics_p.h7
-rw-r--r--src/svg/qsvghandler.cpp110
-rw-r--r--src/svg/qsvghandler_p.h2
-rw-r--r--tests/auto/qsvgplugin/imageInclude.svg18
-rw-r--r--tests/auto/qsvgplugin/imageIncludeA.svg5
-rw-r--r--tests/auto/qsvgplugin/resources.qrc2
-rw-r--r--tests/auto/qsvgplugin/tst_qsvgplugin.cpp41
-rw-r--r--tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp45
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]);
}
}
}