diff options
-rw-r--r-- | .qmake.conf | 2 | ||||
-rw-r--r-- | dist/changes-5.12.10 | 46 | ||||
-rw-r--r-- | dist/changes-5.15.2 | 42 | ||||
-rw-r--r-- | src/plugins/imageformats/svg/qsvgiohandler.cpp | 39 | ||||
-rw-r--r-- | src/svg/qsvghandler.cpp | 162 | ||||
-rw-r--r-- | src/svg/qsvgrenderer.cpp | 4 | ||||
-rw-r--r-- | src/svg/qsvgtinydocument.cpp | 4 | ||||
-rw-r--r-- | src/svg/qt_attribution.json | 5 | ||||
-rw-r--r-- | tests/auto/qsvgplugin/simple_Utf16BE.svg | bin | 0 -> 228 bytes | |||
-rw-r--r-- | tests/auto/qsvgplugin/simple_Utf16LE.svg | bin | 0 -> 228 bytes | |||
-rw-r--r-- | tests/auto/qsvgplugin/simple_Utf32BE.svg | bin | 0 -> 456 bytes | |||
-rw-r--r-- | tests/auto/qsvgplugin/simple_Utf32LE.svg | bin | 0 -> 456 bytes | |||
-rw-r--r-- | tests/auto/qsvgplugin/simple_Utf8.svg | 3 | ||||
-rw-r--r-- | tests/auto/qsvgplugin/tst_qsvgplugin.cpp | 32 | ||||
-rw-r--r-- | tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp | 14 |
15 files changed, 257 insertions, 96 deletions
diff --git a/.qmake.conf b/.qmake.conf index d9cffeb..bf083d6 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.15.1 +MODULE_VERSION = 5.15.9 diff --git a/dist/changes-5.12.10 b/dist/changes-5.12.10 new file mode 100644 index 0000000..b8f8f69 --- /dev/null +++ b/dist/changes-5.12.10 @@ -0,0 +1,46 @@ +Qt 5.12.10 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.9. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + https://doc.qt.io/qt-5.12/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. + +**************************************************************************** +* Library * +**************************************************************************** + + - This release fixes a number of cases where input fuzzing has + revealed that corrupt or pathological input could result in crashes + or undefined behavior: + oss-fuzz-23588 + oss-fuzz-23606 + oss-fuzz-23633 + oss-fuzz-23643 + oss-fuzz-23644 + oss-fuzz-23731 + oss-fuzz-24000 + oss-fuzz-24028 + oss-fuzz-24131 + oss-fuzz-24146 + oss-fuzz-24308 + oss-fuzz-24611 + oss-fuzz-24738 + +Third-Party Code +---------------- + + - XSVG license was re-classified to HPND-sell-variant, "Historical Permission + Notice and Disclaimer - sell variant" + diff --git a/dist/changes-5.15.2 b/dist/changes-5.15.2 new file mode 100644 index 0000000..1fdcd4a --- /dev/null +++ b/dist/changes-5.15.2 @@ -0,0 +1,42 @@ +Qt 5.15.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.15.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + https://doc.qt.io/qt-5.15/index.html + +The Qt version 5.15 series is binary compatible with the 5.14.x series. +Applications compiled for 5.14 will continue to run with 5.15. + +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. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + +**************************************************************************** +* Library * +**************************************************************************** + + - [QTBUG-87583] Allowed loading SVG files with a doctype declaration + - [oss-fuzz-24611] Implemented a basic format check for compressed svgs so + it will fail early if the file does not start with a svg or xml tag after + decompressing + - [oss-fuzz-24611] Avoids recursion when inflating compressed svgs and no + longer returns a partially extracted QByteArray + - [oss-fuzz-24347] Reduced memory consumption significantly for huge files. + - [oss-fuzz-24735] Reject corrupt svgs with invalid size + +Third-Party Code +---------------- + + - XSVG license was re-classified to HPND-sell-variant, "Historical Permission + Notice and Disclaimer - sell variant" + diff --git a/src/plugins/imageformats/svg/qsvgiohandler.cpp b/src/plugins/imageformats/svg/qsvgiohandler.cpp index 334c24b..561e77e 100644 --- a/src/plugins/imageformats/svg/qsvgiohandler.cpp +++ b/src/plugins/imageformats/svg/qsvgiohandler.cpp @@ -118,6 +118,24 @@ QSvgIOHandler::~QSvgIOHandler() delete d; } +static bool isPossiblySvg(QIODevice *device, bool *isCompressed = nullptr) +{ + constexpr int bufSize = 64; + char buf[bufSize]; + const qint64 readLen = device->peek(buf, bufSize); + if (readLen < 8) + return false; +# ifndef QT_NO_COMPRESS + if (quint8(buf[0]) == 0x1f && quint8(buf[1]) == 0x8b) { + if (isCompressed) + *isCompressed = true; + return true; + } +# endif + QTextStream str(QByteArray::fromRawData(buf, readLen)); + QByteArray ba = str.read(16).trimmed().toLatin1(); + return ba.startsWith("<?xml") || ba.startsWith("<svg") || ba.startsWith("<!--") || ba.startsWith("<!DOCTYPE svg"); +} bool QSvgIOHandler::canRead() const { @@ -126,15 +144,9 @@ bool QSvgIOHandler::canRead() const if (d->loaded && !d->readDone) return true; // Will happen if we have been asked for the size - QByteArray buf = device()->peek(8); -#ifndef QT_NO_COMPRESS - if (buf.startsWith("\x1f\x8b")) { - setFormat("svgz"); - return true; - } else -#endif - if (buf.contains("<?xml") || buf.contains("<svg") || buf.contains("<!--")) { - setFormat("svg"); + bool isCompressed = false; + if (isPossiblySvg(device(), &isCompressed)) { + setFormat(isCompressed ? "svgz" : "svg"); return true; } return false; @@ -170,6 +182,8 @@ bool QSvgIOHandler::read(QImage *image) bounds = t.mapRect(bounds); } if (image->size() != finalSize || !image->reinterpretAsFormat(QImage::Format_ARGB32_Premultiplied)) { + if (qMax(finalSize.width(), finalSize.height()) > 0xffff) + return false; // Assume corrupted file *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()); @@ -260,12 +274,7 @@ bool QSvgIOHandler::supportsOption(ImageOption option) const bool QSvgIOHandler::canRead(QIODevice *device) { - QByteArray buf = device->peek(8); - return -#ifndef QT_NO_COMPRESS - buf.startsWith("\x1f\x8b") || -#endif - buf.contains("<?xml") || buf.contains("<svg") || buf.contains("<!--"); + return isPossiblySvg(device); } QT_END_NAMESPACE diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp index c937254..b2227b6 100644 --- a/src/svg/qsvghandler.cpp +++ b/src/svg/qsvghandler.cpp @@ -65,6 +65,7 @@ #include "private/qmath_p.h" #include "float.h" +#include <cmath> QT_BEGIN_NAMESPACE @@ -672,6 +673,9 @@ static qreal toDouble(const QChar *&str) val = -val; } else { val = QByteArray::fromRawData(temp, pos).toDouble(); + // Do not tolerate values too wild to be represented normally by floats + if (qFpClassify(float(val)) != FP_NORMAL) + val = 0; } return val; @@ -724,15 +728,25 @@ static QVector<qreal> parseNumbersList(const QChar *&str) return points; } -static inline void parseNumbersArray(const QChar *&str, QVarLengthArray<qreal, 8> &points) +static inline void parseNumbersArray(const QChar *&str, QVarLengthArray<qreal, 8> &points, + const char *pattern = nullptr) { + const size_t patternLen = qstrlen(pattern); while (str->isSpace()) ++str; while (isDigit(str->unicode()) || *str == QLatin1Char('-') || *str == QLatin1Char('+') || *str == QLatin1Char('.')) { - points.append(toDouble(str)); + if (patternLen && pattern[points.size() % patternLen] == 'f') { + // flag expected, may only be 0 or 1 + if (*str != QLatin1Char('0') && *str != QLatin1Char('1')) + return; + points.append(*str == QLatin1Char('0') ? 0.0 : 1.0); + ++str; + } else { + points.append(toDouble(str)); + } while (str->isSpace()) ++str; @@ -1380,7 +1394,8 @@ static void parseFont(QSvgNode *node, break; case FontSizeValue: { QSvgHandler::LengthType dummy; // should always be pixel size - fontStyle->setSize(parseLength(attributes.fontSize, dummy, handler)); + fontStyle->setSize(qMin(parseLength(attributes.fontSize, dummy, handler), + qreal(0xffff))); } break; default: @@ -1611,6 +1626,7 @@ static void pathArc(QPainterPath &path, static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) { + const int maxElementCount = 0x7fff; // Assume file corruption if more path elements than this qreal x0 = 0, y0 = 0; // starting point qreal x = 0, y = 0; // current point char lastMode = 0; @@ -1618,28 +1634,31 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) const QChar *str = dataStr.constData(); const QChar *end = str + dataStr.size(); - while (str != end) { + bool ok = true; + while (ok && str != end) { while (str->isSpace() && (str + 1) != end) ++str; QChar pathElem = *str; ++str; QChar endc = *end; *const_cast<QChar *>(end) = 0; // parseNumbersArray requires 0-termination that QStringRef cannot guarantee + const char *pattern = nullptr; + if (pathElem == QLatin1Char('a') || pathElem == QLatin1Char('A')) + pattern = "rrrffrr"; QVarLengthArray<qreal, 8> arg; - parseNumbersArray(str, arg); + parseNumbersArray(str, arg, pattern); *const_cast<QChar *>(end) = endc; if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z')) arg.append(0);//dummy const qreal *num = arg.constData(); int count = arg.count(); - while (count > 0) { + while (ok && count > 0) { qreal offsetX = x; // correction offsets qreal offsetY = y; // for relative commands switch (pathElem.unicode()) { case 'm': { if (count < 2) { - num++; - count--; + ok = false; break; } x = x0 = num[0] + offsetX; @@ -1656,8 +1675,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) break; case 'M': { if (count < 2) { - num++; - count--; + ok = false; break; } x = x0 = num[0]; @@ -1683,8 +1701,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) break; case 'l': { if (count < 2) { - num++; - count--; + ok = false; break; } x = num[0] + offsetX; @@ -1697,8 +1714,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) break; case 'L': { if (count < 2) { - num++; - count--; + ok = false; break; } x = num[0]; @@ -1738,8 +1754,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) break; case 'c': { if (count < 6) { - num += count; - count = 0; + ok = false; break; } QPointF c1(num[0] + offsetX, num[1] + offsetY); @@ -1755,8 +1770,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) } case 'C': { if (count < 6) { - num += count; - count = 0; + ok = false; break; } QPointF c1(num[0], num[1]); @@ -1772,8 +1786,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) } case 's': { if (count < 4) { - num += count; - count = 0; + ok = false; break; } QPointF c1; @@ -1794,8 +1807,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) } case 'S': { if (count < 4) { - num += count; - count = 0; + ok = false; break; } QPointF c1; @@ -1816,8 +1828,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) } case 'q': { if (count < 4) { - num += count; - count = 0; + ok = false; break; } QPointF c(num[0] + offsetX, num[1] + offsetY); @@ -1832,8 +1843,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) } case 'Q': { if (count < 4) { - num += count; - count = 0; + ok = false; break; } QPointF c(num[0], num[1]); @@ -1848,8 +1858,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) } case 't': { if (count < 2) { - num += count; - count = 0; + ok = false; break; } QPointF e(num[0] + offsetX, num[1] + offsetY); @@ -1869,8 +1878,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) } case 'T': { if (count < 2) { - num += count; - count = 0; + ok = false; break; } QPointF e(num[0], num[1]); @@ -1890,8 +1898,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) } case 'a': { if (count < 7) { - num += count; - count = 0; + ok = false; break; } qreal rx = (*num++); @@ -1913,8 +1920,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) break; case 'A': { if (count < 7) { - num += count; - count = 0; + ok = false; break; } qreal rx = (*num++); @@ -1935,12 +1941,15 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) } break; default: - return false; + ok = false; + break; } lastMode = pathElem.toLatin1(); + if (path.elementCount() > maxElementCount) + ok = false; } } - return true; + return ok; } static bool parseStyle(QSvgNode *node, @@ -2354,6 +2363,28 @@ static bool parseAnimateNode(QSvgNode *parent, return true; } +static int parseClockValue(const QString &instr, bool *ok) +{ + QStringRef str(&instr); + int res = 0; + int ms = 1000; + str = str.trimmed(); + if (str.endsWith(QLatin1String("ms"))) { + str.chop(2); + ms = 1; + } else if (str.endsWith(QLatin1String("s"))) { + str.chop(1); + } + double val = ms * toDouble(str, ok); + if (ok) { + if (val > std::numeric_limits<int>::min() && val < std::numeric_limits<int>::max()) + res = static_cast<int>(val); + else + *ok = false; + } + return res; +} + static bool parseAnimateColorNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *handler) @@ -2387,23 +2418,13 @@ static bool parseAnimateColorNode(QSvgNode *parent, } } - int ms = 1000; - beginStr = beginStr.trimmed(); - if (beginStr.endsWith(QLatin1String("ms"))) { - beginStr.chop(2); - ms = 1; - } else if (beginStr.endsWith(QLatin1String("s"))) { - beginStr.chop(1); - } - durStr = durStr.trimmed(); - if (durStr.endsWith(QLatin1String("ms"))) { - durStr.chop(2); - ms = 1; - } else if (durStr.endsWith(QLatin1String("s"))) { - durStr.chop(1); - } - int begin = static_cast<int>(toDouble(beginStr) * ms); - int end = static_cast<int>((toDouble(durStr) + begin) * ms); + bool ok = true; + int begin = parseClockValue(beginStr, &ok); + if (!ok) + return false; + int end = begin + parseClockValue(durStr, &ok); + if (!ok || end <= begin) + return false; QSvgAnimateColor *anim = new QSvgAnimateColor(begin, end, 0); anim->setArgs((targetStr == QLatin1String("fill")), colors); @@ -2493,24 +2514,13 @@ static bool parseAnimateTransformNode(QSvgNode *parent, } } - int ms = 1000; - beginStr = beginStr.trimmed(); - if (beginStr.endsWith(QLatin1String("ms"))) { - beginStr.chop(2); - ms = 1; - } else if (beginStr.endsWith(QLatin1String("s"))) { - beginStr.chop(1); - } - int begin = static_cast<int>(toDouble(beginStr) * ms); - durStr = durStr.trimmed(); - if (durStr.endsWith(QLatin1String("ms"))) { - durStr.chop(2); - ms = 1; - } else if (durStr.endsWith(QLatin1String("s"))) { - durStr.chop(1); - ms = 1000; - } - int end = static_cast<int>(toDouble(durStr)*ms) + begin; + bool ok = true; + int begin = parseClockValue(beginStr, &ok); + if (!ok) + return false; + int end = begin + parseClockValue(durStr, &ok); + if (!ok || end <= begin) + return false; QSvgAnimateTransform::TransformType type = QSvgAnimateTransform::Empty; if (typeStr == QLatin1String("translate")) { @@ -2976,8 +2986,8 @@ static QSvgNode *createPathNode(QSvgNode *parent, QPainterPath qpath; qpath.setFillRule(Qt::WindingFill); - //XXX do error handling - parsePathDataFast(data, qpath); + if (!parsePathDataFast(data, qpath)) + qCWarning(lcSvgHandler, "Invalid path data; path truncated."); QSvgNode *path = new QSvgPath(parent, qpath); return path; @@ -3043,6 +3053,8 @@ static QSvgStyleProperty *createRadialGradientNode(QSvgNode *node, ncy = toDouble(cy); if (!r.isEmpty()) nr = toDouble(r); + if (nr < 0.5) + nr = 0.5; qreal nfx = ncx; if (!fx.isEmpty()) @@ -3679,9 +3691,7 @@ void QSvgHandler::parse() case QXmlStreamReader::EndElement: endElement(xml->name()); ++remainingUnfinishedElements; - // if we are using somebody else's qxmlstreamreader - // we should not read until the end of the stream - done = !m_ownsReader && (xml->name() == QLatin1String("svg")); + done = (xml->name() == QLatin1String("svg")); break; case QXmlStreamReader::Characters: characters(xml->text()); diff --git a/src/svg/qsvgrenderer.cpp b/src/svg/qsvgrenderer.cpp index 0097ec2..ff892d5 100644 --- a/src/svg/qsvgrenderer.cpp +++ b/src/svg/qsvgrenderer.cpp @@ -350,6 +350,10 @@ static bool loadDocument(QSvgRenderer *const q, { delete d->render; d->render = QSvgTinyDocument::load(in); + if (d->render && !d->render->size().isValid()) { + delete d->render; + d->render = nullptr; + } if (d->render && d->render->animated() && d->fps > 0) { if (!d->timer) d->timer = new QTimer(q); diff --git a/src/svg/qsvgtinydocument.cpp b/src/svg/qsvgtinydocument.cpp index 5956e35..63d0797 100644 --- a/src/svg/qsvgtinydocument.cpp +++ b/src/svg/qsvgtinydocument.cpp @@ -159,8 +159,8 @@ static QByteArray qt_inflateSvgzDataFrom(QIODevice *device, bool doCheckContent) if (doCheckContent) { // Quick format check, equivalent to QSvgIOHandler::canRead() - QByteArray buf = destination.left(8); - if (!buf.contains("<?xml") && !buf.contains("<svg") && !buf.contains("<!--")) { + QByteArray buf = destination.left(16); + if (!buf.contains("<?xml") && !buf.contains("<svg") && !buf.contains("<!--") && !buf.contains("<!DOCTYPE svg")) { inflateEnd(&zlibStream); qCWarning(lcSvgHandler, "Error while inflating gzip file: SVG format check failed"); return QByteArray(); diff --git a/src/svg/qt_attribution.json b/src/svg/qt_attribution.json index 515bb38..9b17698 100644 --- a/src/svg/qt_attribution.json +++ b/src/svg/qt_attribution.json @@ -6,7 +6,8 @@ "Files": "qtsvghandler.cpp", "Description": "Some code for arc handling is derived from code from the XSVG project.", - "License": "MIT \"Old Style\" License", + "License": "Historical Permission Notice and Disclaimer - sell variant", + "LicenseId": "HPND-sell-variant", "LicenseFile": "XSVG_LICENSE.txt", - "Copyright": "Copyright 2002 USC/Information Sciences Institute" + "Copyright": "Copyright 2002 USC/Information Sciences Institute" } diff --git a/tests/auto/qsvgplugin/simple_Utf16BE.svg b/tests/auto/qsvgplugin/simple_Utf16BE.svg Binary files differnew file mode 100644 index 0000000..c3312cb --- /dev/null +++ b/tests/auto/qsvgplugin/simple_Utf16BE.svg diff --git a/tests/auto/qsvgplugin/simple_Utf16LE.svg b/tests/auto/qsvgplugin/simple_Utf16LE.svg Binary files differnew file mode 100644 index 0000000..cdbeda9 --- /dev/null +++ b/tests/auto/qsvgplugin/simple_Utf16LE.svg diff --git a/tests/auto/qsvgplugin/simple_Utf32BE.svg b/tests/auto/qsvgplugin/simple_Utf32BE.svg Binary files differnew file mode 100644 index 0000000..0d5d02c --- /dev/null +++ b/tests/auto/qsvgplugin/simple_Utf32BE.svg diff --git a/tests/auto/qsvgplugin/simple_Utf32LE.svg b/tests/auto/qsvgplugin/simple_Utf32LE.svg Binary files differnew file mode 100644 index 0000000..58a7159 --- /dev/null +++ b/tests/auto/qsvgplugin/simple_Utf32LE.svg diff --git a/tests/auto/qsvgplugin/simple_Utf8.svg b/tests/auto/qsvgplugin/simple_Utf8.svg new file mode 100644 index 0000000..2052c48 --- /dev/null +++ b/tests/auto/qsvgplugin/simple_Utf8.svg @@ -0,0 +1,3 @@ +<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/tst_qsvgplugin.cpp b/tests/auto/qsvgplugin/tst_qsvgplugin.cpp index e1f84f3..73bbe8b 100644 --- a/tests/auto/qsvgplugin/tst_qsvgplugin.cpp +++ b/tests/auto/qsvgplugin/tst_qsvgplugin.cpp @@ -61,6 +61,8 @@ private slots: void checkSize_data(); void checkSize(); void checkImageInclude(); + void encodings_data(); + void encodings(); }; @@ -145,6 +147,36 @@ void tst_QSvgPlugin::checkImageInclude() logMessages.clear(); } +void tst_QSvgPlugin::encodings_data() +{ + QTest::addColumn<QString>("filename"); + + QTest::newRow("utf-8") << QFINDTESTDATA("simple_Utf8.svg"); + QTest::newRow("utf-16LE") << QFINDTESTDATA("simple_Utf16LE.svg"); + QTest::newRow("utf-16BE") << QFINDTESTDATA("simple_Utf16BE.svg"); + QTest::newRow("utf-32LE") << QFINDTESTDATA("simple_Utf32LE.svg"); + QTest::newRow("utf-32BE") << QFINDTESTDATA("simple_Utf32BE.svg"); +} + +void tst_QSvgPlugin::encodings() +{ + QFETCH(QString, filename); + + { + QFile file(filename); + file.open(QIODevice::ReadOnly); + QVERIFY(QSvgIOHandler::canRead(&file)); + } + + QFile file(filename); + file.open(QIODevice::ReadOnly); + QSvgIOHandler plugin; + plugin.setDevice(&file); + QVERIFY(plugin.canRead()); + QImage img; + QVERIFY(plugin.read(&img)); + QCOMPARE(img.size(), QSize(50, 50)); +} 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 8f1f03b..36c76ec 100644 --- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp +++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp @@ -74,6 +74,7 @@ private slots: void fillRule(); void opacity(); void paths(); + void paths2(); void displayMode(); void strokeInherit(); void testFillInheritance(); @@ -1047,6 +1048,19 @@ void tst_QSvgRenderer::paths() } } +void tst_QSvgRenderer::paths2() +{ + const char *svg = + "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\">" + "<path d=\"M 3 8 A 5 5 0 1013 8\" id=\"path1\"/>" + "</svg>"; + + QByteArray data(svg); + QSvgRenderer renderer(data); + QVERIFY(renderer.isValid()); + QCOMPARE(renderer.boundsOnElement(QLatin1String("path1")).toRect(), QRect(3, 8, 10, 5)); +} + void tst_QSvgRenderer::displayMode() { static const char *svgs[] = { |