summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--src/plugins/imageformats/svg/qsvgiohandler.cpp2
-rw-r--r--src/svg/qsvggenerator.cpp68
-rw-r--r--src/svg/qsvghandler.cpp74
-rw-r--r--src/svg/qsvghandler_p.h3
-rw-r--r--src/svg/qsvgtinydocument.cpp14
-rw-r--r--tests/auto/auto.pro1
-rw-r--r--tests/auto/qsvggenerator/referenceSvgs/radial_gradient.svg4
-rw-r--r--tests/auto/qsvggenerator/tst_qsvggenerator.cpp42
-rw-r--r--tests/auto/qsvgplugin/.gitignore1
-rw-r--r--tests/auto/qsvgplugin/qsvgplugin.pro8
-rw-r--r--tests/auto/qsvgplugin/resources.qrc16
-rw-r--r--tests/auto/qsvgplugin/square.svg5
-rw-r--r--tests/auto/qsvgplugin/square_size.svg5
-rw-r--r--tests/auto/qsvgplugin/square_size_viewbox.svg5
-rw-r--r--tests/auto/qsvgplugin/square_viewbox.svg5
-rw-r--r--tests/auto/qsvgplugin/tall.svg5
-rw-r--r--tests/auto/qsvgplugin/tall_size.svg5
-rw-r--r--tests/auto/qsvgplugin/tall_size_viewbox.svg5
-rw-r--r--tests/auto/qsvgplugin/tall_viewbox.svg5
-rw-r--r--tests/auto/qsvgplugin/tst_qsvgplugin.cpp108
-rw-r--r--tests/auto/qsvgplugin/wide.svg5
-rw-r--r--tests/auto/qsvgplugin/wide_size.svg5
-rw-r--r--tests/auto/qsvgplugin/wide_size_viewbox.svg5
-rw-r--r--tests/auto/qsvgplugin/wide_viewbox.svg5
25 files changed, 370 insertions, 33 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 13d7a60..d94a2e0 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.8.1
+MODULE_VERSION = 5.9.0
diff --git a/src/plugins/imageformats/svg/qsvgiohandler.cpp b/src/plugins/imageformats/svg/qsvgiohandler.cpp
index 88d37bc..0c26cb5 100644
--- a/src/plugins/imageformats/svg/qsvgiohandler.cpp
+++ b/src/plugins/imageformats/svg/qsvgiohandler.cpp
@@ -98,7 +98,7 @@ bool QSvgIOHandlerPrivate::load(QIODevice *device)
}
if (res) {
- defaultSize = QSize(r.viewBox().width(), r.viewBox().height());
+ defaultSize = r.defaultSize();
loaded = true;
}
diff --git a/src/svg/qsvggenerator.cpp b/src/svg/qsvggenerator.cpp
index 5829a1a..3f4e545 100644
--- a/src/svg/qsvggenerator.cpp
+++ b/src/svg/qsvggenerator.cpp
@@ -52,6 +52,7 @@
#include "qtextstream.h"
#include "qbuffer.h"
#include "qmath.h"
+#include "qbitmap.h"
#include "qdebug.h"
@@ -128,6 +129,9 @@ public:
QString currentGradientName;
int numGradients;
+ QStringList savedPatternBrushes;
+ QStringList savedPatternMasks;
+
struct _attributes {
QString document_title;
QString document_description;
@@ -145,12 +149,13 @@ static inline QPaintEngine::PaintEngineFeatures svgEngineFeatures()
{
return QPaintEngine::PaintEngineFeatures(
QPaintEngine::AllFeatures
- & ~QPaintEngine::PatternBrush
& ~QPaintEngine::PerspectiveTransform
& ~QPaintEngine::ConicalGradientFill
& ~QPaintEngine::PorterDuff);
}
+Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert);
+
class QSvgPaintEngine : public QPaintEngine
{
Q_DECLARE_PRIVATE(QSvgPaintEngine)
@@ -212,6 +217,41 @@ public:
Q_ASSERT(!isActive());
d_func()->resolution = resolution;
}
+
+ QString savePatternMask(Qt::BrushStyle style)
+ {
+ QString maskId = QString(QStringLiteral("patternmask%1")).arg(style);
+ if (!d_func()->savedPatternMasks.contains(maskId)) {
+ QImage img = qt_imageForBrush(style, true);
+ QRegion reg(QBitmap::fromData(img.size(), img.constBits()));
+ QString rct(QStringLiteral("<rect x=\"%1\" y=\"%2\" width=\"%3\" height=\"%4\" />"));
+ QTextStream str(&d_func()->defs, QIODevice::Append);
+ str << "<mask id=\"" << maskId << "\" x=\"0\" y=\"0\" width=\"8\" height=\"8\" "
+ << "stroke=\"none\" fill=\"#ffffff\" patternUnits=\"userSpaceOnUse\" >" << endl;
+ for (QRect r : reg.rects()) {
+ str << rct.arg(r.x()).arg(r.y()).arg(r.width()).arg(r.height()) << endl;
+ }
+ str << QStringLiteral("</mask>") << endl << endl;
+ d_func()->savedPatternMasks.append(maskId);
+ }
+ return maskId;
+ }
+
+ QString savePatternBrush(const QString &color, const QBrush &brush)
+ {
+ QString patternId = QString(QStringLiteral("fillpattern%1_")).arg(brush.style()) + color.midRef(1);
+ if (!d_func()->savedPatternBrushes.contains(patternId)) {
+ QString maskId = savePatternMask(brush.style());
+ QString geo(QStringLiteral("x=\"0\" y=\"0\" width=\"8\" height=\"8\""));
+ QTextStream str(&d_func()->defs, QIODevice::Append);
+ str << QString(QStringLiteral("<pattern id=\"%1\" %2 patternUnits=\"userSpaceOnUse\" >")).arg(patternId, geo) << endl;
+ str << QString(QStringLiteral("<rect %1 stroke=\"none\" fill=\"%2\" mask=\"url(#%3);\" />")).arg(geo, color, maskId) << endl;
+ str << QStringLiteral("</pattern>") << endl << endl;
+ d_func()->savedPatternBrushes.append(patternId);
+ }
+ return patternId;
+ }
+
void saveLinearGradientBrush(const QGradient *g)
{
QTextStream str(&d_func()->defs, QIODevice::Append);
@@ -242,7 +282,7 @@ public:
<< QLatin1String("fx=\"") <<grad->focalPoint().x() << QLatin1String("\" ")
<< QLatin1String("fy=\"") <<grad->focalPoint().y() << QLatin1String("\" ");
}
- str << QLatin1String("xml:id=\"") <<d_func()->generateGradientName()<< QLatin1String("\">\n");
+ str << QLatin1String("id=\"") <<d_func()->generateGradientName()<< QLatin1String("\">\n");
saveGradientStops(str, g);
str << QLatin1String("</radialGradient>") << endl;
}
@@ -421,6 +461,28 @@ public:
d_func()->attributes.fillOpacity = colorOpacity;
}
break;
+ case Qt::Dense1Pattern:
+ case Qt::Dense2Pattern:
+ case Qt::Dense3Pattern:
+ case Qt::Dense4Pattern:
+ case Qt::Dense5Pattern:
+ case Qt::Dense6Pattern:
+ case Qt::Dense7Pattern:
+ case Qt::HorPattern:
+ case Qt::VerPattern:
+ case Qt::CrossPattern:
+ case Qt::BDiagPattern:
+ case Qt::FDiagPattern:
+ case Qt::DiagCrossPattern: {
+ QString color, colorOpacity;
+ translate_color(sbrush.color(), &color, &colorOpacity);
+ QString patternId = savePatternBrush(color, sbrush);
+ QString patternRef = QString(QStringLiteral("url(#%1)")).arg(patternId);
+ stream() << "fill=\"" << patternRef << "\" fill-opacity=\"" << colorOpacity << "\" ";
+ d_func()->attributes.fill = patternRef;
+ d_func()->attributes.fillOpacity = colorOpacity;
+ break;
+ }
case Qt::LinearGradientPattern:
saveLinearGradientBrush(sbrush.gradient());
d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName);
@@ -1062,7 +1124,7 @@ void QSvgPaintEngine::drawRects(const QRectF *rects, int rectCount)
Q_D(QSvgPaintEngine);
for (int i=0; i < rectCount; ++i) {
- const QRectF &rect = rects[i];
+ const QRectF &rect = rects[i].normalized();
*d->stream << "<rect";
if (state->pen().isCosmetic())
*d->stream << " vector-effect=\"non-scaling-stroke\"";
diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp
index 3b1cbb8..df654e1 100644
--- a/src/svg/qsvghandler.cpp
+++ b/src/svg/qsvghandler.cpp
@@ -55,6 +55,7 @@
#include "qvector.h"
#include "qfileinfo.h"
#include "qfile.h"
+#include "qdir.h"
#include "qdebug.h"
#include "qmath.h"
#include "qnumeric.h"
@@ -65,9 +66,41 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcSvgHandler, "qt.svg")
+
static const char *qt_inherit_text = "inherit";
#define QT_INHERIT QLatin1String(qt_inherit_text)
+static QByteArray prefixMessage(const QByteArray &msg, const QXmlStreamReader *r)
+{
+ QByteArray result;
+ if (r) {
+ if (const QFile *file = qobject_cast<const QFile *>(r->device()))
+ result.append(QFile::encodeName(QDir::toNativeSeparators(file->fileName())));
+ else
+ result.append(QByteArrayLiteral("<input>"));
+ result.append(':');
+ result.append(QByteArray::number(r->lineNumber()));
+ if (const qint64 column = r->columnNumber()) {
+ result.append(':');
+ result.append(QByteArray::number(column));
+ }
+ result.append(QByteArrayLiteral(": "));
+ }
+ result.append(msg);
+ return result;
+}
+
+static inline QByteArray msgProblemParsing(const QString &localName, const QXmlStreamReader *r)
+{
+ return prefixMessage(QByteArrayLiteral("Problem parsing ") + localName.toLocal8Bit(), r);
+}
+
+static inline QByteArray msgCouldNotResolveProperty(const QString &id, const QXmlStreamReader *r)
+{
+ return prefixMessage(QByteArrayLiteral("Could not resolve property: ") + id.toLocal8Bit(), r);
+}
+
// ======== duplicated from qcolor_p
static inline int qsvg_h2i(char hex)
@@ -2692,11 +2725,11 @@ static QSvgNode *createImageNode(QSvgNode *parent,
filename = filename.trimmed();
if (filename.isEmpty()) {
- qWarning() << "QSvgHandler: Image filename is empty";
+ qCWarning(lcSvgHandler) << "QSvgHandler: Image filename is empty";
return 0;
}
if (nwidth <= 0 || nheight <= 0) {
- qWarning() << "QSvgHandler: Width or height for" << filename << "image was not greater than 0";
+ qCWarning(lcSvgHandler) << "QSvgHandler: Width or height for" << filename << "image was not greater than 0";
return 0;
}
@@ -2709,7 +2742,7 @@ static QSvgNode *createImageNode(QSvgNode *parent,
QByteArray data = QByteArray::fromBase64(dataStr.toLatin1());
image = QImage::fromData(data);
} else {
- qDebug()<<"QSvgHandler::createImageNode: Unrecognized inline image format!";
+ qCDebug(lcSvgHandler) << "QSvgHandler::createImageNode: Unrecognized inline image format!";
}
} else
image = QImage(filename);
@@ -3166,7 +3199,7 @@ static QSvgNode *createSvgNode(QSvgNode *parent,
QString baseProfile = attributes.value(QLatin1String("baseProfile")).toString();
#if 0
if (baseProfile.isEmpty() && baseProfile != QLatin1String("tiny")) {
- qWarning("Profile is %s while we only support tiny!",
+ qCWarning(lcSvgHandler, "Profile is %s while we only support tiny!",
qPrintable(baseProfile));
}
#endif
@@ -3332,7 +3365,7 @@ static QSvgNode *createUseNode(QSvgNode *parent,
}
}
- qWarning("link %s hasn't been detected!", qPrintable(linkId));
+ qCWarning(lcSvgHandler, "link %s hasn't been detected!", qPrintable(linkId));
return 0;
}
@@ -3619,8 +3652,10 @@ bool QSvgHandler::startElement(const QString &localName,
} else if (xmlSpace == QLatin1String("default")) {
m_whitespaceMode.push(QSvgText::Default);
} else {
- qWarning() << QString::fromLatin1("\"%1\" is an invalid value for attribute xml:space. "
- "Valid values are \"preserve\" and \"default\".").arg(xmlSpace.toString());
+ const QByteArray msg = '"' + xmlSpace.toString().toLocal8Bit()
+ + "\" is an invalid value for attribute xml:space. "
+ "Valid values are \"preserve\" and \"default\".";
+ qCWarning(lcSvgHandler, "%s", prefixMessage(msg, xml).constData());
m_whitespaceMode.push(QSvgText::Default);
}
@@ -3676,13 +3711,15 @@ bool QSvgHandler::startElement(const QString &localName,
if (node->type() == QSvgNode::TSPAN) {
static_cast<QSvgText *>(m_nodes.top())->addTspan(static_cast<QSvgTspan *>(node));
} else {
- qWarning("\'text\' or \'textArea\' element contains invalid element type.");
+ const QByteArray msg = QByteArrayLiteral("\'text\' or \'textArea\' element contains invalid element type.");
+ qCWarning(lcSvgHandler, "%s", prefixMessage(msg, xml).constData());
delete node;
node = 0;
}
break;
default:
- qWarning("Could not add child element to parent element because the types are incorrect.");
+ const QByteArray msg = QByteArrayLiteral("Could not add child element to parent element because the types are incorrect.");
+ qCWarning(lcSvgHandler, "%s", prefixMessage(msg, xml).constData());
delete node;
node = 0;
break;
@@ -3703,25 +3740,24 @@ bool QSvgHandler::startElement(const QString &localName,
}
} else if (ParseMethod method = findUtilFactory(localName)) {
Q_ASSERT(!m_nodes.isEmpty());
- if (!method(m_nodes.top(), attributes, this)) {
- qWarning("Problem parsing %s", qPrintable(localName));
- }
+ if (!method(m_nodes.top(), attributes, this))
+ qCWarning(lcSvgHandler, "%s", msgProblemParsing(localName, xml).constData());
} else if (StyleFactoryMethod method = findStyleFactoryMethod(localName)) {
QSvgStyleProperty *prop = method(m_nodes.top(), attributes, this);
if (prop) {
m_style = prop;
m_nodes.top()->appendStyleProperty(prop, someId(attributes));
} else {
- qWarning("Could not parse node: %s", qPrintable(localName));
+ const QByteArray msg = QByteArrayLiteral("Could not parse node: ") + localName.toLocal8Bit();
+ qCWarning(lcSvgHandler, "%s", prefixMessage(msg, xml).constData());
}
} else if (StyleParseMethod method = findStyleUtilFactoryMethod(localName)) {
if (m_style) {
- if (!method(m_style, attributes, this)) {
- qWarning("Problem parsing %s", qPrintable(localName));
- }
+ if (!method(m_style, attributes, this))
+ qCWarning(lcSvgHandler, "%s", msgProblemParsing(localName, xml).constData());
}
} else {
- //qWarning()<<"Skipping unknown element!"<<namespaceURI<<"::"<<localName;
+ //qCWarning(lcSvgHandler) <<"Skipping unknown element!"<<namespaceURI<<"::"<<localName;
m_skipNodes.push(Unknown);
return true;
}
@@ -3780,7 +3816,7 @@ void QSvgHandler::resolveGradients(QSvgNode *node)
if (style) {
fill->setFillStyle(style);
} else {
- qWarning("Could not resolve property : %s", qPrintable(id));
+ qCWarning(lcSvgHandler, "%s", msgCouldNotResolveProperty(id, xml).constData());
fill->setBrush(Qt::NoBrush);
}
}
@@ -3792,7 +3828,7 @@ void QSvgHandler::resolveGradients(QSvgNode *node)
if (style) {
stroke->setStyle(style);
} else {
- qWarning("Could not resolve property : %s", qPrintable(id));
+ qCWarning(lcSvgHandler, "%s", msgCouldNotResolveProperty(id, xml).constData());
stroke->setStroke(Qt::NoBrush);
}
}
diff --git a/src/svg/qsvghandler_p.h b/src/svg/qsvghandler_p.h
index 32dd059..2c06cb4 100644
--- a/src/svg/qsvghandler_p.h
+++ b/src/svg/qsvghandler_p.h
@@ -54,6 +54,7 @@
#include "QtCore/qxmlstream.h"
#include "QtCore/qhash.h"
#include "QtCore/qstack.h"
+#include <QtCore/QLoggingCategory>
#include "qsvgstyle_p.h"
#include "private/qcssparser_p.h"
#include "qsvggraphics_p.h"
@@ -186,6 +187,8 @@ private:
const bool m_ownsReader;
};
+Q_DECLARE_LOGGING_CATEGORY(lcSvgHandler)
+
QT_END_NAMESPACE
#endif // QSVGHANDLER_P_H
diff --git a/src/svg/qsvgtinydocument.cpp b/src/svg/qsvgtinydocument.cpp
index 7bb1f75..15351bd 100644
--- a/src/svg/qsvgtinydocument.cpp
+++ b/src/svg/qsvgtinydocument.cpp
@@ -104,7 +104,7 @@ QByteArray qt_inflateGZipDataFrom(QIODevice *device)
// Adding 16 to the window size gives us gzip decoding
if (inflateInit2(&zlibStream, MAX_WBITS + 16) != Z_OK) {
- qWarning("Cannot initialize zlib, because: %s",
+ qCWarning(lcSvgHandler, "Cannot initialize zlib, because: %s",
(zlibStream.msg != NULL ? zlibStream.msg : "Unknown error"));
return QByteArray();
}
@@ -137,7 +137,7 @@ QByteArray qt_inflateGZipDataFrom(QIODevice *device)
case Z_STREAM_ERROR:
case Z_MEM_ERROR: {
inflateEnd(&zlibStream);
- qWarning("Error while inflating gzip file: %s",
+ qCWarning(lcSvgHandler, "Error while inflating gzip file: %s",
(zlibStream.msg != NULL ? zlibStream.msg : "Unknown error"));
destination.chop(zlibStream.avail_out);
return destination;
@@ -167,8 +167,8 @@ QSvgTinyDocument * QSvgTinyDocument::load(const QString &fileName)
{
QFile file(fileName);
if (!file.open(QFile::ReadOnly)) {
- qWarning("Cannot open file '%s', because: %s",
- qPrintable(fileName), qPrintable(file.errorString()));
+ qCWarning(lcSvgHandler, "Cannot open file '%s', because: %s",
+ qPrintable(fileName), qPrintable(file.errorString()));
return 0;
}
@@ -185,7 +185,7 @@ QSvgTinyDocument * QSvgTinyDocument::load(const QString &fileName)
doc = handler.document();
doc->m_animationDuration = handler.animationDuration();
} else {
- qWarning("Cannot read file '%s', because: %s (line %d)",
+ qCWarning(lcSvgHandler, "Cannot read file '%s', because: %s (line %d)",
qPrintable(fileName), qPrintable(handler.errorString()), handler.lineNumber());
}
return doc;
@@ -261,7 +261,7 @@ void QSvgTinyDocument::draw(QPainter *p, const QString &id,
QSvgNode *node = scopeNode(id);
if (!node) {
- qDebug("Couldn't find node %s. Skipping rendering.", qPrintable(id));
+ qCDebug(lcSvgHandler, "Couldn't find node %s. Skipping rendering.", qPrintable(id));
return;
}
if (m_time.isNull()) {
@@ -443,7 +443,7 @@ QMatrix QSvgTinyDocument::matrixForElement(const QString &id) const
QSvgNode *node = scopeNode(id);
if (!node) {
- qDebug("Couldn't find node %s. Skipping rendering.", qPrintable(id));
+ qCDebug(lcSvgHandler, "Couldn't find node %s. Skipping rendering.", qPrintable(id));
return QMatrix();
}
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 43ff500..e2d84ec 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -4,6 +4,7 @@ qtHaveModule(widgets) {
qsvgdevice \
qsvggenerator \
qsvgrenderer \
+ qsvgplugin \
qicon_svg \
cmake \
installed_cmake
diff --git a/tests/auto/qsvggenerator/referenceSvgs/radial_gradient.svg b/tests/auto/qsvggenerator/referenceSvgs/radial_gradient.svg
index a56674c..13fc6f1 100644
--- a/tests/auto/qsvggenerator/referenceSvgs/radial_gradient.svg
+++ b/tests/auto/qsvggenerator/referenceSvgs/radial_gradient.svg
@@ -4,11 +4,11 @@
<title>Qt SVG Document</title>
<desc>Generated with Qt</desc>
<defs>
-<radialGradient gradientUnits="objectBoundingBox" cx="0.5" cy="0.5" r="0.5" fx="0.5" fy="0.5" xml:id="gradient1">
+<radialGradient gradientUnits="objectBoundingBox" cx="0.5" cy="0.5" r="0.5" fx="0.5" fy="0.5" id="gradient1">
<stop offset="0" stop-color="#ff0000" stop-opacity="1" />
<stop offset="1" stop-color="#0000ff" stop-opacity="1" />
</radialGradient>
-<radialGradient gradientUnits="userSpaceOnUse" cx="150" cy="50" r="50" fx="150" fy="50" xml:id="gradient2">
+<radialGradient gradientUnits="userSpaceOnUse" cx="150" cy="50" r="50" fx="150" fy="50" id="gradient2">
<stop offset="0" stop-color="#ff0000" stop-opacity="1" />
<stop offset="1" stop-color="#0000ff" stop-opacity="1" />
</radialGradient>
diff --git a/tests/auto/qsvggenerator/tst_qsvggenerator.cpp b/tests/auto/qsvggenerator/tst_qsvggenerator.cpp
index 4795b55..b55b687 100644
--- a/tests/auto/qsvggenerator/tst_qsvggenerator.cpp
+++ b/tests/auto/qsvggenerator/tst_qsvggenerator.cpp
@@ -58,6 +58,7 @@ private slots:
void fractionalFontSize();
void titleAndDescription();
void gradientInterpolation();
+ void patternBrush();
};
tst_QSvgGenerator::tst_QSvgGenerator()
@@ -423,5 +424,46 @@ void tst_QSvgGenerator::gradientInterpolation()
QVERIFY(sqrImageDiff(image, refImage) < 2); // pixel error < 1.41 (L2-norm)
}
+void tst_QSvgGenerator::patternBrush()
+{
+ { // Pattern brush should create mask and pattern used as fill
+ QSvgGenerator generator;
+ QByteArray byteArray;
+ QBuffer buffer(&byteArray);
+ generator.setOutputDevice(&buffer);
+ QPainter painter(&generator);
+ painter.setBrush(Qt::CrossPattern);
+ painter.drawRect(0, 0, 100, 100);
+ painter.end();
+
+ QVERIFY(byteArray.contains("<mask id=\"patternmask"));
+ QVERIFY(byteArray.contains("<pattern id=\"fillpattern"));
+ QVERIFY(byteArray.contains("<g fill=\"url(#fillpattern"));
+ }
+
+ { // Masks and patterns should be reused, not regenerated
+ QSvgGenerator generator;
+ QByteArray byteArray;
+ QBuffer buffer(&byteArray);
+ generator.setOutputDevice(&buffer);
+ QPainter painter(&generator);
+ painter.setBrush(QBrush(Qt::red, Qt::Dense3Pattern));
+ painter.drawRect(0, 0, 100, 100);
+ painter.drawEllipse(200, 50, 50, 50);
+ painter.setBrush(QBrush(Qt::green, Qt::Dense3Pattern));
+ painter.drawRoundedRect(0, 200, 100, 100, 10, 10);
+ painter.setBrush(QBrush(Qt::blue, Qt::Dense4Pattern));
+ painter.drawRect(200, 200, 100, 100);
+ painter.setBrush(QBrush(Qt::red, Qt::Dense3Pattern));
+ painter.drawRoundedRect(120, 120, 60, 60, 5, 5);
+ painter.end();
+
+ QCOMPARE(byteArray.count("<mask id=\"patternmask"), 2);
+ QCOMPARE(byteArray.count("<pattern id=\"fillpattern"), 3);
+ QVERIFY(byteArray.count("<g fill=\"url(#fillpattern") >= 4);
+ }
+
+}
+
QTEST_MAIN(tst_QSvgGenerator)
#include "tst_qsvggenerator.moc"
diff --git a/tests/auto/qsvgplugin/.gitignore b/tests/auto/qsvgplugin/.gitignore
new file mode 100644
index 0000000..c41c448
--- /dev/null
+++ b/tests/auto/qsvgplugin/.gitignore
@@ -0,0 +1 @@
+tst_qsvgplugin
diff --git a/tests/auto/qsvgplugin/qsvgplugin.pro b/tests/auto/qsvgplugin/qsvgplugin.pro
new file mode 100644
index 0000000..3fec52e
--- /dev/null
+++ b/tests/auto/qsvgplugin/qsvgplugin.pro
@@ -0,0 +1,8 @@
+TARGET = tst_qsvgplugin
+CONFIG += testcase
+QT += svg testlib widgets gui-private
+
+SOURCES += tst_qsvgplugin.cpp
+RESOURCES += resources.qrc
+
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
diff --git a/tests/auto/qsvgplugin/resources.qrc b/tests/auto/qsvgplugin/resources.qrc
new file mode 100644
index 0000000..fcb311a
--- /dev/null
+++ b/tests/auto/qsvgplugin/resources.qrc
@@ -0,0 +1,16 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>square.svg</file>
+ <file>square_size.svg</file>
+ <file>square_size_viewbox.svg</file>
+ <file>square_viewbox.svg</file>
+ <file>tall.svg</file>
+ <file>tall_size.svg</file>
+ <file>tall_size_viewbox.svg</file>
+ <file>tall_viewbox.svg</file>
+ <file>wide.svg</file>
+ <file>wide_size.svg</file>
+ <file>wide_size_viewbox.svg</file>
+ <file>wide_viewbox.svg</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/qsvgplugin/square.svg b/tests/auto/qsvgplugin/square.svg
new file mode 100644
index 0000000..f35fb87
--- /dev/null
+++ b/tests/auto/qsvgplugin/square.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">
+ <circle cx="50" cy="50" r="25" fill="#00ff00" />
+</svg>
diff --git a/tests/auto/qsvgplugin/square_size.svg b/tests/auto/qsvgplugin/square_size.svg
new file mode 100644
index 0000000..f4aeb67
--- /dev/null
+++ b/tests/auto/qsvgplugin/square_size.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" width="200px" height="200px">
+ <circle cx="50" cy="50" r="25" fill="#00ff00" />
+</svg>
diff --git a/tests/auto/qsvgplugin/square_size_viewbox.svg b/tests/auto/qsvgplugin/square_size_viewbox.svg
new file mode 100644
index 0000000..cf39bd7
--- /dev/null
+++ b/tests/auto/qsvgplugin/square_size_viewbox.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" width="200px" height="200px" viewBox="0 0 100 100">
+ <circle cx="50" cy="50" r="25" fill="#00ff00" />
+</svg>
diff --git a/tests/auto/qsvgplugin/square_viewbox.svg b/tests/auto/qsvgplugin/square_viewbox.svg
new file mode 100644
index 0000000..5811505
--- /dev/null
+++ b/tests/auto/qsvgplugin/square_viewbox.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/tall.svg b/tests/auto/qsvgplugin/tall.svg
new file mode 100644
index 0000000..b243b62
--- /dev/null
+++ b/tests/auto/qsvgplugin/tall.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">
+ <ellipse cx="25" cy="50" rx="12.5" ry="25" fill="#00ff00" />
+</svg>
diff --git a/tests/auto/qsvgplugin/tall_size.svg b/tests/auto/qsvgplugin/tall_size.svg
new file mode 100644
index 0000000..6121451
--- /dev/null
+++ b/tests/auto/qsvgplugin/tall_size.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" width="100px" height="200px">
+ <ellipse cx="25" cy="50" rx="12.5" ry="25" fill="#00ff00" />
+</svg>
diff --git a/tests/auto/qsvgplugin/tall_size_viewbox.svg b/tests/auto/qsvgplugin/tall_size_viewbox.svg
new file mode 100644
index 0000000..9d82492
--- /dev/null
+++ b/tests/auto/qsvgplugin/tall_size_viewbox.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" width="100px" height="200px" viewBox="0 0 50 100">
+ <ellipse cx="25" cy="50" rx="12.5" ry="25" fill="#00ff00" />
+</svg>
diff --git a/tests/auto/qsvgplugin/tall_viewbox.svg b/tests/auto/qsvgplugin/tall_viewbox.svg
new file mode 100644
index 0000000..8ed61a9
--- /dev/null
+++ b/tests/auto/qsvgplugin/tall_viewbox.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 50 100">
+ <ellipse cx="25" cy="50" rx="12.5" ry="25" fill="#00ff00" />
+</svg>
diff --git a/tests/auto/qsvgplugin/tst_qsvgplugin.cpp b/tests/auto/qsvgplugin/tst_qsvgplugin.cpp
new file mode 100644
index 0000000..4ec1737
--- /dev/null
+++ b/tests/auto/qsvgplugin/tst_qsvgplugin.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include "../../../src/plugins/imageformats/svg/qsvgiohandler.cpp"
+#include <QImage>
+#include <QStringList>
+#include <QVector>
+
+#ifndef SRCDIR
+#define SRCDIR
+#endif
+
+
+class tst_QSvgPlugin : public QObject
+{
+Q_OBJECT
+
+public:
+ tst_QSvgPlugin();
+ virtual ~tst_QSvgPlugin();
+
+private slots:
+ void checkSize_data();
+ void checkSize();
+};
+
+
+
+tst_QSvgPlugin::tst_QSvgPlugin()
+{
+}
+
+tst_QSvgPlugin::~tst_QSvgPlugin()
+{
+}
+
+void tst_QSvgPlugin::checkSize_data()
+{
+ QTest::addColumn<QString>("filename");
+ QTest::addColumn<int>("imageHeight");
+ QTest::addColumn<int>("imageWidth");
+
+ QTest::newRow("square") << SRCDIR "square.svg" << 50 << 50;
+ QTest::newRow("square_size") << SRCDIR "square_size.svg" << 200 << 200;
+ QTest::newRow("square_size_viewbox") << SRCDIR "square_size_viewbox.svg" << 200 << 200;
+ QTest::newRow("square_viewbox") << SRCDIR "square_viewbox.svg" << 100 << 100;
+ QTest::newRow("tall") << SRCDIR "tall.svg" << 50 << 25;
+ QTest::newRow("tall_size") << SRCDIR "tall_size.svg" << 200 << 100;
+ QTest::newRow("tall_size_viewbox") << SRCDIR "tall_size_viewbox.svg" << 200 << 100;
+ QTest::newRow("tall_viewbox") << SRCDIR "tall_viewbox.svg" << 100 << 50;
+ QTest::newRow("wide") << SRCDIR "wide.svg" << 25 << 50;
+ QTest::newRow("wide_size") << SRCDIR "wide_size.svg" << 100 << 200;
+ QTest::newRow("wide_size_viewbox") << SRCDIR "wide_size_viewbox.svg" << 100 << 200;
+ QTest::newRow("wide_viewbox") << SRCDIR "wide_viewbox.svg" << 50 << 100;
+}
+
+void tst_QSvgPlugin::checkSize()
+{
+ QFETCH(QString, filename);
+ QFETCH(int, imageHeight);
+ QFETCH(int, imageWidth);
+
+ QFile file(filename);
+ file.open(QIODevice::ReadOnly);
+
+ QSvgIOHandler plugin;
+ plugin.setDevice(&file);
+
+ QImage image;
+ plugin.read(&image);
+
+ file.close();
+
+ QCOMPARE(imageHeight, image.height());
+ QCOMPARE(imageWidth, image.width());
+}
+
+
+QTEST_MAIN(tst_QSvgPlugin)
+#include "tst_qsvgplugin.moc"
diff --git a/tests/auto/qsvgplugin/wide.svg b/tests/auto/qsvgplugin/wide.svg
new file mode 100644
index 0000000..9166606
--- /dev/null
+++ b/tests/auto/qsvgplugin/wide.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">
+ <ellipse cx="50" cy="25" rx="25" ry="12.5" fill="#00ff00" />
+</svg>
diff --git a/tests/auto/qsvgplugin/wide_size.svg b/tests/auto/qsvgplugin/wide_size.svg
new file mode 100644
index 0000000..e816154
--- /dev/null
+++ b/tests/auto/qsvgplugin/wide_size.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" width="200px" height="100px">
+ <ellipse cx="50" cy="25" rx="25" ry="12.5" fill="#00ff00" />
+</svg>
diff --git a/tests/auto/qsvgplugin/wide_size_viewbox.svg b/tests/auto/qsvgplugin/wide_size_viewbox.svg
new file mode 100644
index 0000000..3d9b044
--- /dev/null
+++ b/tests/auto/qsvgplugin/wide_size_viewbox.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" width="200px" height="100px" viewBox="0 0 100 50">
+ <ellipse cx="50" cy="25" rx="25" ry="12.5" fill="#00ff00" />
+</svg>
diff --git a/tests/auto/qsvgplugin/wide_viewbox.svg b/tests/auto/qsvgplugin/wide_viewbox.svg
new file mode 100644
index 0000000..aface45
--- /dev/null
+++ b/tests/auto/qsvgplugin/wide_viewbox.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 50">
+ <ellipse cx="50" cy="25" rx="25" ry="12.5" fill="#00ff00" />
+</svg>