summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--examples/svg/embedded/desktopservices/contenttab.cpp1
-rw-r--r--examples/svg/embedded/fluidlauncher/pictureflow.cpp6
-rw-r--r--examples/svg/embedded/weatherinfo/weatherinfo.cpp4
-rw-r--r--examples/svg/network/bearercloud/cloud.cpp2
-rw-r--r--examples/svg/opengl/framebufferobject/glwidget.cpp2
-rw-r--r--examples/svg/svgviewer/mainwindow.cpp14
-rw-r--r--examples/svg/svgviewer/mainwindow.h2
-rw-r--r--examples/svg/svgviewer/svgview.cpp10
-rw-r--r--examples/svg/svgviewer/svgview.h2
-rw-r--r--src/svg/qsvggenerator.cpp2
-rw-r--r--src/svg/qsvghandler.cpp2
-rw-r--r--src/svg/qsvghandler_p.h2
-rw-r--r--src/svg/qsvgnode.cpp2
-rw-r--r--src/svg/qsvgstyle.cpp2
-rw-r--r--src/svg/qsvgtinydocument.cpp57
-rw-r--r--src/svg/qsvgtinydocument_p.h9
-rw-r--r--tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp10
-rw-r--r--tests/libfuzzer/svg/qsvgrenderer/render/main.cpp42
-rw-r--r--tests/libfuzzer/svg/qsvgrenderer/render/render.pro3
-rw-r--r--tests/manual/rendertestsuite/.gitignore2
-rw-r--r--tests/manual/rendertestsuite/README32
-rw-r--r--tests/manual/rendertestsuite/main.cpp139
-rw-r--r--tests/manual/rendertestsuite/rendertestsuite.pro3
24 files changed, 296 insertions, 56 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 988629e..c6f1702 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.13.2
+MODULE_VERSION = 5.14.0
diff --git a/examples/svg/embedded/desktopservices/contenttab.cpp b/examples/svg/embedded/desktopservices/contenttab.cpp
index 8d467df..2dac351 100644
--- a/examples/svg/embedded/desktopservices/contenttab.cpp
+++ b/examples/svg/embedded/desktopservices/contenttab.cpp
@@ -124,6 +124,7 @@ void ContentTab::keyPressEvent(QKeyEvent *event)
switch (event->key()) {
case Qt::Key_Select:
openItem(currentItem());
+ Q_FALLTHROUGH();
default:
QListWidget::keyPressEvent(event);
break;
diff --git a/examples/svg/embedded/fluidlauncher/pictureflow.cpp b/examples/svg/embedded/fluidlauncher/pictureflow.cpp
index 191ff2e..b0657a2 100644
--- a/examples/svg/embedded/fluidlauncher/pictureflow.cpp
+++ b/examples/svg/embedded/fluidlauncher/pictureflow.cpp
@@ -85,7 +85,7 @@
#include <QTimer>
#include <QVector>
#include <QWidget>
-#include <QTime>
+#include <QElapsedTimer>
#include <QDebug>
@@ -376,7 +376,7 @@ public:
int singlePressThreshold;
QPoint firstPress;
QPoint previousPos;
- QTime previousPosTimestamp;
+ QElapsedTimer previousPosTimestamp;
int pixelDistanceMoved;
int pixelsToMovePerSlide;
@@ -1397,7 +1397,7 @@ void PictureFlow::timerEvent(QTimerEvent* event)
{
if(event->timerId() == d->animateTimer.timerId())
{
-// QTime now = QTime::currentTime();
+// QElapsedTimer now; now.start();
d->updateAnimation();
// d->animateTimer.start(qMax(0, 30-now.elapsed() ), this);
}
diff --git a/examples/svg/embedded/weatherinfo/weatherinfo.cpp b/examples/svg/embedded/weatherinfo/weatherinfo.cpp
index b64d8ca..21aa986 100644
--- a/examples/svg/embedded/weatherinfo/weatherinfo.cpp
+++ b/examples/svg/embedded/weatherinfo/weatherinfo.cpp
@@ -147,17 +147,13 @@ private slots:
void animate(int frame) {
qreal progress = static_cast<qreal>(frame) / 100;
-#if QT_VERSION >= 0x040500
m_iconItem->setOpacity(progress);
-#endif
qreal hw = width() / 2.0;
m_statusItem->setPos(-hw + hw * progress, 0);
for (int i = 0; i < m_forecastItems.count(); ++i) {
qreal ofs = i * 0.5 / m_forecastItems.count();
qreal alpha = qBound(qreal(0), 2 * (progress - ofs), qreal(1));
-#if QT_VERSION >= 0x040500
m_conditionItems[i]->setOpacity(alpha);
-#endif
QPointF pos = m_forecastItems[i]->pos();
if (width() > height()) {
qreal fx = width() - width() * 0.4 * alpha;
diff --git a/examples/svg/network/bearercloud/cloud.cpp b/examples/svg/network/bearercloud/cloud.cpp
index 4e0313a..1117c94 100644
--- a/examples/svg/network/bearercloud/cloud.cpp
+++ b/examples/svg/network/bearercloud/cloud.cpp
@@ -76,9 +76,7 @@ Cloud::Cloud(const QNetworkConfiguration &config, QGraphicsItem *parent)
this, SLOT(stateChanged(QNetworkSession::State)));
setFlag(ItemIsMovable);
-#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
setFlag(ItemSendsGeometryChanges);
-#endif
setZValue(1);
icon = new QGraphicsSvgItem(this);
diff --git a/examples/svg/opengl/framebufferobject/glwidget.cpp b/examples/svg/opengl/framebufferobject/glwidget.cpp
index 38ee5db..03eed6c 100644
--- a/examples/svg/opengl/framebufferobject/glwidget.cpp
+++ b/examples/svg/opengl/framebufferobject/glwidget.cpp
@@ -253,7 +253,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *e)
void GLWidget::wheelEvent(QWheelEvent *e)
{
- e->delta() > 0 ? scale += scale*0.1f : scale -= scale*0.1f;
+ e->angleDelta().y() > 0 ? scale += scale*0.1f : scale -= scale*0.1f;
draw();
}
diff --git a/examples/svg/svgviewer/mainwindow.cpp b/examples/svg/svgviewer/mainwindow.cpp
index 7dd240a..d095416 100644
--- a/examples/svg/svgviewer/mainwindow.cpp
+++ b/examples/svg/svgviewer/mainwindow.cpp
@@ -118,14 +118,10 @@ MainWindow::MainWindow()
m_imageAction->setData(int(SvgView::Image));
rendererMenu->addSeparator();
- m_highQualityAntialiasingAction = rendererMenu->addAction(tr("&High Quality Antialiasing"));
- m_highQualityAntialiasingAction->setEnabled(false);
- m_highQualityAntialiasingAction->setCheckable(true);
- m_highQualityAntialiasingAction->setChecked(false);
- connect(m_highQualityAntialiasingAction, &QAction::toggled, m_view, &SvgView::setHighQualityAntialiasing);
-#ifdef QT_NO_OPENGL
- m_highQualityAntialiasingAction->setVisible(false);
-#endif
+ m_antialiasingAction = rendererMenu->addAction(tr("&Antialiasing"));
+ m_antialiasingAction->setCheckable(true);
+ m_antialiasingAction->setChecked(false);
+ connect(m_antialiasingAction, &QAction::toggled, m_view, &SvgView::setAntialiasing);
QActionGroup *rendererGroup = new QActionGroup(this);
rendererGroup->addAction(m_nativeAction);
@@ -191,8 +187,6 @@ bool MainWindow::loadFile(const QString &fileName)
void MainWindow::setRenderer(int renderMode)
{
-
- m_highQualityAntialiasingAction->setEnabled(renderMode == SvgView::OpenGL);
m_view->setRenderer(static_cast<SvgView::RendererType>(renderMode));
}
diff --git a/examples/svg/svgviewer/mainwindow.h b/examples/svg/svgviewer/mainwindow.h
index 6c2af7e..a102eaa 100644
--- a/examples/svg/svgviewer/mainwindow.h
+++ b/examples/svg/svgviewer/mainwindow.h
@@ -85,7 +85,7 @@ private:
QAction *m_nativeAction;
QAction *m_glAction;
QAction *m_imageAction;
- QAction *m_highQualityAntialiasingAction;
+ QAction *m_antialiasingAction;
QAction *m_backgroundAction;
QAction *m_outlineAction;
diff --git a/examples/svg/svgviewer/svgview.cpp b/examples/svg/svgviewer/svgview.cpp
index ecc8409..e87d0ea 100644
--- a/examples/svg/svgviewer/svgview.cpp
+++ b/examples/svg/svgviewer/svgview.cpp
@@ -153,13 +153,9 @@ void SvgView::setRenderer(RendererType type)
}
}
-void SvgView::setHighQualityAntialiasing(bool highQualityAntialiasing)
+void SvgView::setAntialiasing(bool antialiasing)
{
-#ifndef QT_NO_OPENGL
- setRenderHint(QPainter::HighQualityAntialiasing, highQualityAntialiasing);
-#else
- Q_UNUSED(highQualityAntialiasing);
-#endif
+ setRenderHint(QPainter::Antialiasing, antialiasing);
}
void SvgView::setViewBackground(bool enable)
@@ -222,7 +218,7 @@ void SvgView::paintEvent(QPaintEvent *event)
void SvgView::wheelEvent(QWheelEvent *event)
{
- zoomBy(qPow(1.2, event->delta() / 240.0));
+ zoomBy(qPow(1.2, event->angleDelta().y() / 240.0));
}
void SvgView::zoomBy(qreal factor)
diff --git a/examples/svg/svgviewer/svgview.h b/examples/svg/svgviewer/svgview.h
index 1b6b33e..7d5f7d1 100644
--- a/examples/svg/svgviewer/svgview.h
+++ b/examples/svg/svgviewer/svgview.h
@@ -79,7 +79,7 @@ public:
qreal zoomFactor() const;
public slots:
- void setHighQualityAntialiasing(bool highQualityAntialiasing);
+ void setAntialiasing(bool antialiasing);
void setViewBackground(bool enable);
void setViewOutline(bool enable);
void zoomIn();
diff --git a/src/svg/qsvggenerator.cpp b/src/svg/qsvggenerator.cpp
index 07f8d74..b671c44 100644
--- a/src/svg/qsvggenerator.cpp
+++ b/src/svg/qsvggenerator.cpp
@@ -1009,7 +1009,7 @@ void QSvgPaintEngine::updateState(const QPaintEngineState &state)
}
if (flags & QPaintEngine::DirtyTransform) {
- d->matrix = state.matrix();
+ d->matrix = state.transform().toAffine();
*d->stream << "transform=\"matrix(" << d->matrix.m11() << ','
<< d->matrix.m12() << ','
<< d->matrix.m21() << ',' << d->matrix.m22() << ','
diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp
index fe79977..86ca77e 100644
--- a/src/svg/qsvghandler.cpp
+++ b/src/svg/qsvghandler.cpp
@@ -1986,7 +1986,7 @@ static void parseCSStoXMLAttrs(const QVector<QCss::Declaration> &declarations,
}
}
-void QSvgHandler::parseCSStoXMLAttrs(QString css, QVector<QSvgCssAttribute> *attributes)
+void QSvgHandler::parseCSStoXMLAttrs(const QString &css, QVector<QSvgCssAttribute> *attributes)
{
// preprocess (for unicode escapes), tokenize and remove comments
m_cssParser.init(css);
diff --git a/src/svg/qsvghandler_p.h b/src/svg/qsvghandler_p.h
index 8eb061b..d76e56c 100644
--- a/src/svg/qsvghandler_p.h
+++ b/src/svg/qsvghandler_p.h
@@ -128,7 +128,7 @@ public:
int animationDuration() const;
#ifndef QT_NO_CSSPARSER
- void parseCSStoXMLAttrs(QString css, QVector<QSvgCssAttribute> *attributes);
+ void parseCSStoXMLAttrs(const QString &css, QVector<QSvgCssAttribute> *attributes);
#endif
inline QPen defaultPen() const
diff --git a/src/svg/qsvgnode.cpp b/src/svg/qsvgnode.cpp
index 14aaea4..29fd4e5 100644
--- a/src/svg/qsvgnode.cpp
+++ b/src/svg/qsvgnode.cpp
@@ -341,7 +341,7 @@ QSvgNode::DisplayMode QSvgNode::displayMode() const
qreal QSvgNode::strokeWidth(QPainter *p)
{
- QPen pen = p->pen();
+ const QPen &pen = p->pen();
if (pen.style() == Qt::NoPen || pen.brush().style() == Qt::NoBrush || pen.isCosmetic())
return 0;
return pen.widthF();
diff --git a/src/svg/qsvgstyle.cpp b/src/svg/qsvgstyle.cpp
index b934f94..c4edd25 100644
--- a/src/svg/qsvgstyle.cpp
+++ b/src/svg/qsvgstyle.cpp
@@ -126,7 +126,7 @@ void QSvgFillStyle::setFillStyle(QSvgFillStyleProperty* style)
void QSvgFillStyle::setBrush(QBrush brush)
{
- m_fill = brush;
+ m_fill = std::move(brush);
m_style = 0;
m_fillSet = 1;
}
diff --git a/src/svg/qsvgtinydocument.cpp b/src/svg/qsvgtinydocument.cpp
index da464cc..3143ad2 100644
--- a/src/svg/qsvgtinydocument.cpp
+++ b/src/svg/qsvgtinydocument.cpp
@@ -60,6 +60,7 @@ QSvgTinyDocument::QSvgTinyDocument()
: QSvgStructureNode(0)
, m_widthPercent(false)
, m_heightPercent(false)
+ , m_time(0)
, m_animated(false)
, m_animationDuration(0)
, m_fps(30)
@@ -230,9 +231,8 @@ QSvgTinyDocument * QSvgTinyDocument::load(QXmlStreamReader *contents)
void QSvgTinyDocument::draw(QPainter *p, const QRectF &bounds)
{
- if (m_time.isNull()) {
- m_time.start();
- }
+ if (m_time == 0)
+ m_time = QDateTime::currentMSecsSinceEpoch();
if (displayMode() == QSvgNode::NoneMode)
return;
@@ -269,9 +269,8 @@ void QSvgTinyDocument::draw(QPainter *p, const QString &id,
qCDebug(lcSvgHandler, "Couldn't find node %s. Skipping rendering.", qPrintable(id));
return;
}
- if (m_time.isNull()) {
- m_time.start();
- }
+ if (m_time == 0)
+ m_time = QDateTime::currentMSecsSinceEpoch();
if (node->displayMode() == QSvgNode::NoneMode)
return;
@@ -339,6 +338,7 @@ void QSvgTinyDocument::setHeight(int len, bool percent)
void QSvgTinyDocument::setViewBox(const QRectF &rect)
{
m_viewBox = rect;
+ m_implicitViewBox = false;
}
void QSvgTinyDocument::addSvgFont(QSvgFont *font)
@@ -376,7 +376,7 @@ QSvgFillStyleProperty *QSvgTinyDocument::namedStyle(const QString &id) const
void QSvgTinyDocument::restartAnimation()
{
- m_time.restart();
+ m_time = QDateTime::currentMSecsSinceEpoch();
}
bool QSvgTinyDocument::animated() const
@@ -420,14 +420,35 @@ void QSvgTinyDocument::mapSourceToTarget(QPainter *p, const QRectF &targetRect,
source = viewBox();
if (source != target && !source.isNull()) {
- QTransform transform;
- transform.scale(target.width() / source.width(),
- target.height() / source.height());
- QRectF c2 = transform.mapRect(source);
- p->translate(target.x() - c2.x(),
- target.y() - c2.y());
- p->scale(target.width() / source.width(),
- target.height() / source.height());
+ if (m_implicitViewBox) {
+ QTransform transform;
+ transform.scale(target.width() / source.width(),
+ target.height() / source.height());
+ QRectF c2 = transform.mapRect(source);
+ p->translate(target.x() - c2.x(),
+ target.y() - c2.y());
+ p->scale(target.width() / source.width(),
+ target.height() / source.height());
+ } else {
+ // Code path used when a view box is specified and we're not rendering a specific element by id
+ // but the entire document. This attempts to emulate the default values of the <preserveAspectRatio>
+ // tag that's implicitly defined when <viewbox> is used.
+
+ // Apply the view box translation if specified.
+ p->translate(target.x() - source.x(),
+ target.y() - source.y());
+
+ // Scale the view box into the view port (target) by preserve the aspect ratio.
+ QSizeF viewBoxSize = source.size();
+ viewBoxSize.scale(target.width(), target.height(), Qt::KeepAspectRatio);
+
+ // Center the view box in the view port
+ p->translate((target.width() - viewBoxSize.width()) / 2,
+ (target.height() - viewBoxSize.height()) / 2);
+
+ p->scale(viewBoxSize.width() / source.width(),
+ viewBoxSize.height() / source.height());
+ }
}
}
@@ -469,7 +490,7 @@ QMatrix QSvgTinyDocument::matrixForElement(const QString &id) const
int QSvgTinyDocument::currentFrame() const
{
- double runningPercentage = qMin(m_time.elapsed()/double(m_animationDuration), 1.);
+ double runningPercentage = qMin(currentElapsed() / double(m_animationDuration), 1.);
int totalFrames = m_fps * m_animationDuration;
@@ -482,8 +503,8 @@ void QSvgTinyDocument::setCurrentFrame(int frame)
double framePercentage = frame/double(totalFrames);
double timeForFrame = m_animationDuration * framePercentage; //in S
timeForFrame *= 1000; //in ms
- int timeToAdd = int(timeForFrame - m_time.elapsed());
- m_time = m_time.addMSecs(timeToAdd);
+ int timeToAdd = int(timeForFrame - currentElapsed());
+ m_time += timeToAdd;
}
void QSvgTinyDocument::setFramesPerSecond(int num)
diff --git a/src/svg/qsvgtinydocument_p.h b/src/svg/qsvgtinydocument_p.h
index aa51751..404587d 100644
--- a/src/svg/qsvgtinydocument_p.h
+++ b/src/svg/qsvgtinydocument_p.h
@@ -125,13 +125,14 @@ private:
bool m_widthPercent;
bool m_heightPercent;
+ mutable bool m_implicitViewBox = true;
mutable QRectF m_viewBox;
QHash<QString, QSvgRefCounter<QSvgFont> > m_fonts;
QHash<QString, QSvgNode *> m_namedNodes;
QHash<QString, QSvgRefCounter<QSvgFillStyleProperty> > m_namedStyles;
- QTime m_time;
+ qint64 m_time;
bool m_animated;
int m_animationDuration;
int m_fps;
@@ -173,8 +174,10 @@ inline bool QSvgTinyDocument::heightPercent() const
inline QRectF QSvgTinyDocument::viewBox() const
{
- if (m_viewBox.isNull())
+ if (m_viewBox.isNull()) {
m_viewBox = transformedBounds();
+ m_implicitViewBox = true;
+ }
return m_viewBox;
}
@@ -186,7 +189,7 @@ inline bool QSvgTinyDocument::preserveAspectRatio() const
inline int QSvgTinyDocument::currentElapsed() const
{
- return m_time.elapsed();
+ return QDateTime::currentMSecsSinceEpoch() - m_time;
}
inline int QSvgTinyDocument::animationDuration() const
diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp
index e0646f2..cf19213 100644
--- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp
+++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp
@@ -268,6 +268,16 @@ void tst_QSvgRenderer::testMapViewBoxToTarget()
QCOMPARE(picture.boundingRect(), QRect(125, 125, 250, 250));
}
+ { // Viewport and viewBox specified -> scale 500x500 square to 1000x750 while preserving aspect ratio gives 750x750
+ // however the box is centered at 375, 250
+ data = "<svg width=\"1000\" height=\"750\" viewBox=\"-250 -250 500 500\"><g><rect x=\"0\" y=\"0\" width=\"500\" height=\"500\" /></g></svg>";
+ QPicture picture;
+ QPainter painter(&picture);
+ QSvgRenderer rend(data);
+ rend.render(&painter);
+ painter.end();
+ QCOMPARE(picture.boundingRect(), QRect(375, 250, 750, 750));
+ }
}
void tst_QSvgRenderer::testRenderElement()
diff --git a/tests/libfuzzer/svg/qsvgrenderer/render/main.cpp b/tests/libfuzzer/svg/qsvgrenderer/render/main.cpp
new file mode 100644
index 0000000..0197115
--- /dev/null
+++ b/tests/libfuzzer/svg/qsvgrenderer/render/main.cpp
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 <QApplication>
+#include <QImage>
+#include <QPainter>
+#include <QSvgRenderer>
+
+extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size) {
+ static int c = 0;
+ static QApplication a(c, nullptr);
+ static QImage image(377, 233, QImage::Format_RGB32);
+ static QPainter painter(&image);
+ QSvgRenderer renderer(QByteArray(Data, Size));
+ renderer.render(&painter);
+ return 0;
+}
diff --git a/tests/libfuzzer/svg/qsvgrenderer/render/render.pro b/tests/libfuzzer/svg/qsvgrenderer/render/render.pro
new file mode 100644
index 0000000..be94755
--- /dev/null
+++ b/tests/libfuzzer/svg/qsvgrenderer/render/render.pro
@@ -0,0 +1,3 @@
+QT += svg
+SOURCES += main.cpp
+LIBS += -fsanitize=fuzzer
diff --git a/tests/manual/rendertestsuite/.gitignore b/tests/manual/rendertestsuite/.gitignore
new file mode 100644
index 0000000..54f7094
--- /dev/null
+++ b/tests/manual/rendertestsuite/.gitignore
@@ -0,0 +1,2 @@
+baseline
+difference
diff --git a/tests/manual/rendertestsuite/README b/tests/manual/rendertestsuite/README
new file mode 100644
index 0000000..0609d4f
--- /dev/null
+++ b/tests/manual/rendertestsuite/README
@@ -0,0 +1,32 @@
+This little helper program can be used together with the SVG Tiny 1.2 test
+suite to determine the visual impact of changes to the renderer on the basis of
+the test suite.
+
+Suppose you have the test suite installed in ~/tests, then you can create a
+base line of renderings of all the SVG images by running
+
+ mkdir baseline
+ ./rendertestsuite create-baseline ~/tests
+
+and the output will be stored in the 'baseline/' sub-directory.
+
+After making changes to the renderer, you can create a new set of images by running
+
+ mkdir difference
+ ./rendertestsuite diff ~/tests
+
+and side-by-side images of the old and the new images in case they differ will
+be stored in the sub-directory 'difference/'.
+
+An easy way to inspect the output is by using KDE's gwenview:
+
+ gwenview difference/
+
+
+Note that due to rounding errors there will always be subtle differences, even
+when not doing any changes to the renderer.
+
+
+You can find the test suite at
+
+ https://www.w3.org/Graphics/SVG/WG/wiki/Test_Suite_Overview#SVG_1.2_Tiny_Test_Suite:_12_September_2008
diff --git a/tests/manual/rendertestsuite/main.cpp b/tests/manual/rendertestsuite/main.cpp
new file mode 100644
index 0000000..dfdf88c
--- /dev/null
+++ b/tests/manual/rendertestsuite/main.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt SVG module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include <QtSvg>
+#include <QtGui>
+#include <stdlib.h>
+
+static QImage render(const QString &filePath)
+{
+ fprintf(stdout, "Rendering %s\n", qPrintable(filePath));
+ QSvgRenderer renderer(filePath);
+ if (!renderer.isValid()) {
+ fprintf(stderr, "Could not load SVG file %s\n", qPrintable(filePath));
+ return QImage();
+ }
+ QImage image(480, 360, QImage::Format_ARGB32);
+ image.fill(Qt::transparent);
+ {
+ QPainter p(&image);
+ renderer.render(&p);
+ }
+ return image;
+}
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ QCommandLineParser parser;
+ parser.addHelpOption();
+ parser.addPositionalArgument(QLatin1String("command"), QLatin1String("[create-baseline,diff]"));
+ parser.addPositionalArgument(QLatin1String("path-to-svg-testsuite"), QLatin1String("Path to the svg/ sub-directory of the test suite"));
+
+ parser.process(app);
+
+ const auto args = parser.positionalArguments();
+
+ if (args.count() != 2) {
+ parser.showHelp(EXIT_FAILURE);
+ return EXIT_FAILURE; // never reached
+ }
+
+ const QString commandAsString = args.at(0);
+ const QString sourcePath = args.at(1);
+
+ QDirIterator sourceFileIterator(sourcePath, QStringList(QLatin1String("*.svg")), QDir::Files);
+ const QString baselinePath = "baseline";
+
+ const auto referenceFilePath = [baselinePath](const QFileInfo &testCaseFileInfo) -> QString {
+ return baselinePath + QLatin1Char('/') + testCaseFileInfo.baseName() + QLatin1String(".png");
+ };
+
+ if (commandAsString == "create-baseline") {
+ while (sourceFileIterator.hasNext()) {
+ sourceFileIterator.next();
+
+ QImage image = render(sourceFileIterator.filePath());
+ if (image.isNull())
+ return EXIT_FAILURE;
+ QString outputFileName = referenceFilePath(sourceFileIterator.fileInfo());
+ if (!image.save(outputFileName)) {
+ fprintf(stderr, "Could not save PNG file %s\n", qPrintable(outputFileName));
+ return EXIT_FAILURE;
+ }
+ }
+ } else if (commandAsString == "diff") {
+ while (sourceFileIterator.hasNext()) {
+ sourceFileIterator.next();
+
+ QImage actual = render(sourceFileIterator.filePath());
+ const QString referencePath = referenceFilePath(sourceFileIterator.fileInfo());
+ QImage reference;
+ if (!reference.load(referencePath)) {
+ fprintf(stderr, "Could not load reference file %s\n", qPrintable(referencePath));
+ return EXIT_FAILURE;
+ }
+
+ if (actual == reference)
+ continue;
+
+ QImage sideBySideImage(actual.width() * 2, actual.height(), QImage::Format_ARGB32);
+ sideBySideImage.fill(Qt::transparent);
+ {
+ QPainter p(&sideBySideImage);
+ p.drawImage(0, 0, actual);
+ p.drawImage(actual.width(), 0, reference);
+ }
+
+ const QString sideBySideFileName = "difference/" + sourceFileIterator.fileInfo().baseName() + QLatin1String(".png");
+ if (!sideBySideImage.save(sideBySideFileName)) {
+ fprintf(stderr, "Could not save side-by-side image at %s\n", qPrintable(sideBySideFileName));
+ return EXIT_FAILURE;
+ }
+ }
+ } else {
+ fprintf(stderr, "Unknown command %s\n", qPrintable(commandAsString));
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/tests/manual/rendertestsuite/rendertestsuite.pro b/tests/manual/rendertestsuite/rendertestsuite.pro
new file mode 100644
index 0000000..855d3fc
--- /dev/null
+++ b/tests/manual/rendertestsuite/rendertestsuite.pro
@@ -0,0 +1,3 @@
+TEMPLATE = app
+QT = core gui svg
+SOURCES = main.cpp