summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dependencies.yaml2
-rw-r--r--dist/changes-5.15.242
-rw-r--r--dist/changes-6.0.017
-rw-r--r--src/svg/doc/src/qt6-changes.qdoc8
-rw-r--r--src/svg/doc/src/qtsvg-index.qdoc2
-rw-r--r--src/svg/qsvgfont.cpp4
-rw-r--r--src/svg/qsvggenerator.cpp9
-rw-r--r--src/svg/qsvghandler.cpp34
-rw-r--r--src/svg/qsvgstyle.cpp39
-rw-r--r--src/svg/qsvgstyle_p.h13
-rw-r--r--tests/auto/qsvggenerator/tst_qsvggenerator.cpp2
-rw-r--r--tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp65
12 files changed, 213 insertions, 24 deletions
diff --git a/dependencies.yaml b/dependencies.yaml
index 2671e63..d354a4e 100644
--- a/dependencies.yaml
+++ b/dependencies.yaml
@@ -1,4 +1,4 @@
dependencies:
../qtbase:
- ref: 66c94b83565d2db79307124b6cd797da33a5a7ef
+ ref: 420e27c9efc1ef1a6400dc287345e897036abc71
required: true
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/dist/changes-6.0.0 b/dist/changes-6.0.0
new file mode 100644
index 0000000..f1f569f
--- /dev/null
+++ b/dist/changes-6.0.0
@@ -0,0 +1,17 @@
+Qt 6.0.0 is a new major version release of Qt. It is not binary compatible with
+earlier Qt releases.
+
+The goal has been to retain as much source compatibility with Qt 5.15 as
+possible, but some changes were inevitable to make Qt a better framework.
+
+To make it easier to port to Qt 6.0, we have created a porting guide to
+summarize those changes and provide guidance to handle them. In the guide, you
+can find links to articles about changes that may affect your application and
+help you transition from Qt 5.15 to Qt 6.0:
+
+https://doc.qt.io/qt-6/portingguide.html
+
+For more details refer to the online documentation of Qt 6.0:
+
+https://doc.qt.io/qt-6/index.html
+
diff --git a/src/svg/doc/src/qt6-changes.qdoc b/src/svg/doc/src/qt6-changes.qdoc
index e549e5e..31a4639 100644
--- a/src/svg/doc/src/qt6-changes.qdoc
+++ b/src/svg/doc/src/qt6-changes.qdoc
@@ -27,8 +27,8 @@
/*!
\page qtsvg-changes-qt6.html
- \title Porting to Qt 6 - Qt SVG
- \ingroup porting-guides-5-to-6
+ \title Changes to Qt SVG
+ \ingroup changes-qt-5-to-6
\brief Migrate Qt SVG to Qt 6.
Qt 6 is a result of the conscious effort to make the framework more
@@ -41,6 +41,8 @@
In this topic we summarize those changes in Qt SVG, and provide
guidance to handle them.
- \section1 ADD STUFF HERE
+ \section1 Library split
+ The QtSvg module has been split into two libraries, with those classes
+ depending on QtWidgets living in a separate library, QtSvgWidgets.
*/
diff --git a/src/svg/doc/src/qtsvg-index.qdoc b/src/svg/doc/src/qtsvg-index.qdoc
index 4d58301..6e1d35a 100644
--- a/src/svg/doc/src/qtsvg-index.qdoc
+++ b/src/svg/doc/src/qtsvg-index.qdoc
@@ -48,7 +48,7 @@
\snippet doc_src_qtsvg.pro 1
\section1 Module Evolution
- \l{Porting to Qt 6 - Qt SVG} lists important changes in the module API
+ \l{Changes to Qt SVG} lists important changes in the module API
and functionality that were done for the Qt 6 series of Qt.
\section1 Licenses and Attributions
diff --git a/src/svg/qsvgfont.cpp b/src/svg/qsvgfont.cpp
index 6487de4..eb6c9cf 100644
--- a/src/svg/qsvgfont.cpp
+++ b/src/svg/qsvgfont.cpp
@@ -84,7 +84,7 @@ void QSvgFont::draw(QPainter *p, const QPointF &point, const QString &str, qreal
for ( ; itr != str.constEnd(); ++itr) {
QChar unicode = *itr;
if (!m_glyphs.contains(*itr)) {
- unicode = 0;
+ unicode = u'\0';
if (!m_glyphs.contains(unicode))
continue;
}
@@ -112,7 +112,7 @@ void QSvgFont::draw(QPainter *p, const QPointF &point, const QString &str, qreal
for ( ; itr != str.constEnd(); ++itr) {
QChar unicode = *itr;
if (!m_glyphs.contains(*itr)) {
- unicode = 0;
+ unicode = u'\0';
if (!m_glyphs.contains(unicode))
continue;
}
diff --git a/src/svg/qsvggenerator.cpp b/src/svg/qsvggenerator.cpp
index f69e420..7306551 100644
--- a/src/svg/qsvggenerator.cpp
+++ b/src/svg/qsvggenerator.cpp
@@ -951,12 +951,19 @@ void QSvgPaintEngine::drawImage(const QRectF &r, const QImage &image,
Q_UNUSED(sr);
Q_UNUSED(flags);
+ QString quality;
+ if (state->renderHints() & QPainter::SmoothPixmapTransform) {
+ quality = QLatin1String("optimizeQuality");
+ } else {
+ quality = QLatin1String("optimizeSpeed");
+ }
stream() << "<image ";
stream() << "x=\""<<r.x()<<"\" "
"y=\""<<r.y()<<"\" "
"width=\""<<r.width()<<"\" "
"height=\""<<r.height()<<"\" "
- "preserveAspectRatio=\"none\" ";
+ "preserveAspectRatio=\"none\" "
+ "image-rendering=\""<<quality<<"\" ";
QByteArray data;
QBuffer buffer(&data);
diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp
index 523efa6..2fd24bb 100644
--- a/src/svg/qsvghandler.cpp
+++ b/src/svg/qsvghandler.cpp
@@ -134,7 +134,7 @@ bool qsvg_get_hex_rgb(const char *name, QRgb *rgb)
if(name[0] != '#')
return false;
name++;
- int len = qstrlen(name);
+ const size_t len = qstrlen(name);
int r, g, b;
bool ok = true;
if (len == 12) {
@@ -221,6 +221,7 @@ struct QSvgAttributes
QStringView offset;
QStringView stopColor;
QStringView stopOpacity;
+ QStringView imageRendering;
#ifndef QT_NO_CSSPARSER
QList<QSvgCssAttribute> m_cssAttributes;
@@ -274,6 +275,10 @@ QSvgAttributes::QSvgAttributes(const QXmlStreamAttributes &xmlAttributes, QSvgHa
else if (name == QLatin1String("font-variant"))
fontVariant = value;
break;
+ case 'i':
+ if (name == QLatin1String("image-rendering"))
+ imageRendering = value;
+ break;
case 'o':
if (name == QLatin1String("opacity"))
@@ -376,6 +381,8 @@ QSvgAttributes::QSvgAttributes(const QXmlStreamAttributes &xmlAttributes, QSvgHa
case 'i':
if (name == QLatin1String("id"))
id = value.toString();
+ else if (name == QLatin1String("image-rendering"))
+ imageRendering = value;
break;
case 'o':
@@ -931,7 +938,7 @@ static bool createSvgGlyph(QSvgFont *font, const QXmlStreamAttributes &attribute
QStringView havStr = attributes.value(QLatin1String("horiz-adv-x"));
QStringView pathStr = attributes.value(QLatin1String("d"));
- QChar unicode = (uncStr.isEmpty()) ? 0 : uncStr.at(0);
+ QChar unicode = (uncStr.isEmpty()) ? u'\0' : uncStr.at(0);
qreal havx = (havStr.isEmpty()) ? -1 : toDouble(havStr);
QPainterPath path;
path.setFillRule(Qt::WindingFill);
@@ -1587,7 +1594,7 @@ static bool parsePathDataFast(QStringView dataStr, QPainterPath &path)
QChar pathElem = *str;
++str;
QChar endc = *end;
- *const_cast<QChar *>(end) = 0; // parseNumbersArray requires 0-termination that QStringView cannot guarantee
+ *const_cast<QChar *>(end) = u'\0'; // parseNumbersArray requires 0-termination that QStringView cannot guarantee
QVarLengthArray<qreal, 8> arg;
parseNumbersArray(str, arg);
*const_cast<QChar *>(end) = endc;
@@ -2251,6 +2258,25 @@ static void parseOthers(QSvgNode *node,
}
}
+static void parseRenderingHints(QSvgNode *node,
+ const QSvgAttributes &attributes,
+ QSvgHandler *)
+{
+ if (attributes.imageRendering.isEmpty())
+ return;
+
+ QString ir = attributes.imageRendering.toString().trimmed();
+ QSvgQualityStyle *p = new QSvgQualityStyle(0);
+ if (ir == QLatin1String("auto"))
+ p->setImageRendering(QSvgQualityStyle::ImageRenderingAuto);
+ else if (ir == QLatin1String("optimizeSpeed"))
+ p->setImageRendering(QSvgQualityStyle::ImageRenderingOptimizeSpeed);
+ else if (ir == QLatin1String("optimizeQuality"))
+ p->setImageRendering(QSvgQualityStyle::ImageRenderingOptimizeQuality);
+ node->appendStyleProperty(p, attributes.id);
+}
+
+
static bool parseStyle(QSvgNode *node,
const QSvgAttributes &attributes,
QSvgHandler *handler)
@@ -2263,7 +2289,9 @@ static bool parseStyle(QSvgNode *node,
parseVisibility(node, attributes, handler);
parseOpacity(node, attributes, handler);
parseCompOp(node, attributes, handler);
+ parseRenderingHints(node, attributes, handler);
parseOthers(node, attributes, handler);
+
#if 0
value = attributes.value("audio-level");
diff --git a/src/svg/qsvgstyle.cpp b/src/svg/qsvgstyle.cpp
index d425923..cf17944 100644
--- a/src/svg/qsvgstyle.cpp
+++ b/src/svg/qsvgstyle.cpp
@@ -61,7 +61,8 @@ QSvgExtraStates::QSvgExtraStates()
fontWeight(QFont::Normal),
fillRule(Qt::WindingFill),
strokeDashOffset(0),
- vectorEffect(false)
+ vectorEffect(false),
+ imageRendering(QSvgQualityStyle::ImageRenderingAuto)
{
}
@@ -81,16 +82,46 @@ void QSvgFillStyleProperty::revert(QPainter *, QSvgExtraStates &)
QSvgQualityStyle::QSvgQualityStyle(int color)
+ : m_imageRendering(QSvgQualityStyle::ImageRenderingAuto)
+ , m_oldImageRendering(QSvgQualityStyle::ImageRenderingAuto)
+ , m_imageRenderingSet(0)
{
Q_UNUSED(color);
}
-void QSvgQualityStyle::apply(QPainter *, const QSvgNode *, QSvgExtraStates &)
-{
+void QSvgQualityStyle::setImageRendering(ImageRendering hint) {
+ m_imageRendering = hint;
+ m_imageRenderingSet = 1;
}
-void QSvgQualityStyle::revert(QPainter *, QSvgExtraStates &)
+
+void QSvgQualityStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &states)
{
+ m_oldImageRendering = states.imageRendering;
+ if (m_imageRenderingSet) {
+ states.imageRendering = m_imageRendering;
+ }
+ if (m_imageRenderingSet) {
+ bool smooth = false;
+ if (m_imageRendering == ImageRenderingAuto)
+ // auto (the spec says to prefer quality)
+ smooth = true;
+ else
+ smooth = (m_imageRendering == ImageRenderingOptimizeQuality);
+ p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
+ }
+}
+void QSvgQualityStyle::revert(QPainter *p, QSvgExtraStates &states)
+{
+ if (m_imageRenderingSet) {
+ states.imageRendering = m_oldImageRendering;
+ bool smooth = false;
+ if (m_oldImageRendering == ImageRenderingAuto)
+ smooth = true;
+ else
+ smooth = (m_oldImageRendering == ImageRenderingOptimizeQuality);
+ p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
+ }
}
QSvgFillStyle::QSvgFillStyle()
diff --git a/src/svg/qsvgstyle_p.h b/src/svg/qsvgstyle_p.h
index 420dd67..8664f7a 100644
--- a/src/svg/qsvgstyle_p.h
+++ b/src/svg/qsvgstyle_p.h
@@ -148,6 +148,7 @@ struct Q_SVG_PRIVATE_EXPORT QSvgExtraStates
int nestedUseLevel = 0;
int nestedUseCount = 0;
bool vectorEffect; // true if pen is cosmetic
+ qint8 imageRendering; // QSvgQualityStyle::ImageRendering
};
class Q_SVG_PRIVATE_EXPORT QSvgStyleProperty : public QSvgRefCounted
@@ -186,10 +187,18 @@ public:
class Q_SVG_PRIVATE_EXPORT QSvgQualityStyle : public QSvgStyleProperty
{
public:
+ enum ImageRendering: qint8 {
+ ImageRenderingAuto = 0,
+ ImageRenderingOptimizeSpeed = 1,
+ ImageRenderingOptimizeQuality = 2,
+ };
+
QSvgQualityStyle(int color);
void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states) override;
void revert(QPainter *p, QSvgExtraStates &states) override;
Type type() const override;
+
+ void setImageRendering(ImageRendering);
private:
// color-render ing v v 'auto' | 'optimizeSpeed' |
// 'optimizeQuality' | 'inherit'
@@ -210,7 +219,9 @@ private:
// image-rendering v v 'auto' | 'optimizeSpeed' | 'optimizeQuality' |
// 'inherit'
- //QSvgImageRendering m_imageRendering;
+ qint32 m_imageRendering: 4;
+ qint32 m_oldImageRendering: 4;
+ qint32 m_imageRenderingSet: 1;
};
diff --git a/tests/auto/qsvggenerator/tst_qsvggenerator.cpp b/tests/auto/qsvggenerator/tst_qsvggenerator.cpp
index 4f626c3..22657f0 100644
--- a/tests/auto/qsvggenerator/tst_qsvggenerator.cpp
+++ b/tests/auto/qsvggenerator/tst_qsvggenerator.cpp
@@ -298,7 +298,7 @@ void tst_QSvgGenerator::fileEncoding()
generator.setOutputDevice(&buffer);
static const QChar unicode[] = { 'f', 'o', 'o',
- 0x00F8, 'b', 'a', 'r'};
+ u'\u00F8', 'b', 'a', 'r'};
int size = sizeof(unicode) / sizeof(QChar);
QString unicodeString = QString::fromRawData(unicode, size);
diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp
index ea23d2d..e27ee51 100644
--- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp
+++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp
@@ -85,6 +85,7 @@ private slots:
void oss_fuzz_23731();
void oss_fuzz_24131();
void oss_fuzz_24738();
+ void imageRendering();
#ifndef QT_NO_COMPRESS
void testGzLoading();
@@ -522,14 +523,17 @@ static qreal transformNorm(const QTransform &m)
+ m.m33() * m.m33());
}
-static bool diffIsSmallEnough(double diff, double norm)
+template<typename T>
+static inline bool diffIsSmallEnough(T diff, T norm)
{
- return diff <= 1e-12 * norm;
-}
-
-static inline bool diffIsSmallEnough(float diff, float norm)
-{
- return diff <= 1e-5 * norm;
+ static_assert(std::is_same_v<T, double> || std::is_same_v<T, float>);
+ T sigma = []{
+ if constexpr (std::is_same_v<T, double>)
+ return 1e-12;
+ else
+ return 1e-5;
+ }();
+ return diff <= sigma * norm;
}
static void compareTransforms(const QTransform &m1, const QTransform &m2)
@@ -1632,5 +1636,52 @@ void tst_QSvgRenderer::oss_fuzz_24738()
QSvgRenderer().load(QByteArray("<svg><path d=\"a 2 1e-212.....\">"));
}
+QByteArray image_data_url(QImage &image) {
+ QByteArray data;
+ QBuffer buffer(&data);
+ buffer.open(QBuffer::ReadWrite);
+ image.save(&buffer, "PNG");
+ buffer.close();
+ QByteArray url("data:image/png;base64,");
+ url.append(data.toBase64());
+ return url;
+}
+
+void tst_QSvgRenderer::imageRendering() {
+ QImage img(2, 2, QImage::Format_ARGB32_Premultiplied);
+ img.fill(Qt::green);
+ img.setPixel(0, 0, qRgb(255, 0, 0));
+ img.setPixel(1, 1, qRgb(255, 0, 0));
+ QByteArray imgurl(image_data_url(img));
+ QString svgtemplate(
+ "<svg><g transform='scale(2, 2)'>"
+ "<image image-rendering='%1' xlink:href='%2' width='2' height='2' />"
+ "</g></svg>"
+ );
+ const char *cases[] = {"optimizeQuality", "optimizeSpeed"};
+ for (auto ir: cases) {
+ QString svg = svgtemplate.arg(QLatin1String(ir)).arg(QLatin1String(imgurl));
+ QImage img1(4, 4, QImage::Format_ARGB32);
+ QPainter p1;
+ p1.begin(&img1);
+ QSvgRenderer renderer(svg.toLatin1());
+ Q_ASSERT(renderer.isValid());
+ renderer.render(&p1);
+ p1.end();
+
+ QImage img2(4, 4, QImage::Format_ARGB32);
+ QPainter p2(&img2);
+ p2.scale(2, 2);
+ if (QLatin1String(ir) == QLatin1String("optimizeSpeed"))
+ p2.setRenderHint(QPainter::SmoothPixmapTransform, false);
+ else if (QLatin1String(ir) == QLatin1String("optimizeQuality"))
+ p2.setRenderHint(QPainter::SmoothPixmapTransform, true);
+ p2.drawImage(0, 0, img);
+ p2.end();
+ QCOMPARE(img1, img2);
+ }
+}
+
+
QTEST_MAIN(tst_QSvgRenderer)
#include "tst_qsvgrenderer.moc"