Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package qt6-svg for openSUSE:Factory checked in at 2026-02-03 21:27:33 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/qt6-svg (Old) and /work/SRC/openSUSE:Factory/.qt6-svg.new.1995 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "qt6-svg" Tue Feb 3 21:27:33 2026 rev:43 rq:1330603 version:6.10.2 Changes: -------- --- /work/SRC/openSUSE:Factory/qt6-svg/qt6-svg.changes 2025-11-25 15:49:34.438201857 +0100 +++ /work/SRC/openSUSE:Factory/.qt6-svg.new.1995/qt6-svg.changes 2026-02-03 21:28:19.076619644 +0100 @@ -1,0 +2,6 @@ +Sat Jan 31 08:10:42 UTC 2026 - Christophe Marin <[email protected]> + +- Update to 6.10.2: + * https://www.qt.io/blog/qt-6.10.2-released + +------------------------------------------------------------------- Old: ---- qtsvg-everywhere-src-6.10.1.tar.xz New: ---- qtsvg-everywhere-src-6.10.2.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ qt6-svg.spec ++++++ --- /var/tmp/diff_new_pack.YaA7Sx/_old 2026-02-03 21:28:19.996658262 +0100 +++ /var/tmp/diff_new_pack.YaA7Sx/_new 2026-02-03 21:28:20.004658597 +0100 @@ -1,7 +1,7 @@ # # spec file for package qt6-svg # -# Copyright (c) 2025 SUSE LLC and contributors +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,7 +16,7 @@ # -%define real_version 6.10.1 +%define real_version 6.10.2 %define short_version 6.10 %define tar_name qtsvg-everywhere-src %define tar_suffix %{nil} @@ -27,10 +27,10 @@ %endif # Name: qt6-svg%{?pkg_suffix} -Version: 6.10.1 +Version: 6.10.2 Release: 0 Summary: Classes for rendering and displaying SVG drawings -License: LGPL-3.0-only OR (GPL-2.0-only OR GPL-3.0-or-later) +License: GPL-2.0-only OR GPL-3.0-or-later OR LGPL-3.0-only URL: https://www.qt.io Source0: https://download.qt.io/official_releases/qt/%{short_version}/%{real_version}%{tar_suffix}/submodules/%{tar_name}-%{real_version}%{tar_suffix}.tar.xz Source99: qt6-svg-rpmlintrc ++++++ qtsvg-everywhere-src-6.10.1.tar.xz -> qtsvg-everywhere-src-6.10.2.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtsvg-everywhere-src-6.10.1/.cmake.conf new/qtsvg-everywhere-src-6.10.2/.cmake.conf --- old/qtsvg-everywhere-src-6.10.1/.cmake.conf 2025-11-13 17:35:39.000000000 +0100 +++ new/qtsvg-everywhere-src-6.10.2/.cmake.conf 2026-01-20 05:15:33.000000000 +0100 @@ -1,5 +1,7 @@ -set(QT_REPO_MODULE_VERSION "6.10.1") +set(QT_REPO_MODULE_VERSION "6.10.2") set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1") -set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_AS_CONST=1") -list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_FOREACH=1") -list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_CONTEXTLESS_CONNECT=1") +set(QT_EXTRA_INTERNAL_TARGET_DEFINES + "QT_NO_CONTEXTLESS_CONNECT=1" + "QT_NO_FOREACH=1" + "QT_NO_QASCONST=1" +) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtsvg-everywhere-src-6.10.1/.tag new/qtsvg-everywhere-src-6.10.2/.tag --- old/qtsvg-everywhere-src-6.10.1/.tag 2025-11-13 17:35:39.000000000 +0100 +++ new/qtsvg-everywhere-src-6.10.2/.tag 2026-01-20 05:15:33.000000000 +0100 @@ -1 +1 @@ -4b1a183d3592f497bc3fd3a2c7130f228175b899 +b925029db51aff0b17a48f5939cb83c27932d0cb diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtsvg-everywhere-src-6.10.1/dependencies.yaml new/qtsvg-everywhere-src-6.10.2/dependencies.yaml --- old/qtsvg-everywhere-src-6.10.1/dependencies.yaml 2025-11-13 17:35:39.000000000 +0100 +++ new/qtsvg-everywhere-src-6.10.2/dependencies.yaml 2026-01-20 05:15:33.000000000 +0100 @@ -1,4 +1,4 @@ dependencies: ../qtbase: - ref: 90b845d15ffb97693dba527385db83510ebd121a + ref: 000d6c62f7880bb8d3054724e8da0b8ae244130e required: true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtsvg-everywhere-src-6.10.1/src/svg/qsvgfont.cpp new/qtsvg-everywhere-src-6.10.2/src/svg/qsvgfont.cpp --- old/qtsvg-everywhere-src-6.10.1/src/svg/qsvgfont.cpp 2025-11-13 17:35:39.000000000 +0100 +++ new/qtsvg-everywhere-src-6.10.2/src/svg/qsvgfont.cpp 2026-01-20 05:15:33.000000000 +0100 @@ -10,7 +10,7 @@ QT_BEGIN_NAMESPACE -QSvgGlyph::QSvgGlyph(QChar unicode, const QPainterPath &path, qreal horizAdvX) +QSvgGlyph::QSvgGlyph(const QString &unicode, const QPainterPath &path, qreal horizAdvX) : m_unicode(unicode), m_path(path), m_horizAdvX(horizAdvX) { @@ -29,10 +29,9 @@ } -void QSvgFont::addGlyph(QChar unicode, const QPainterPath &path, qreal horizAdvX ) +void QSvgFont::addGlyph(const QString &unicode, const QPainterPath &path, qreal horizAdvX) { - m_glyphs.insert(unicode, QSvgGlyph(unicode, path, - (horizAdvX==-1)?m_horizAdvX:horizAdvX)); + m_glyphs.emplaceBack(unicode, path, (horizAdvX == -1) ? m_horizAdvX : horizAdvX); } bool QSvgFont::addMissingGlyph(const QPainterPath &path, qreal horizAdvX) @@ -60,6 +59,38 @@ return bounds; } +// text must not be empty +char32_t firstUcs4(QStringView text) +{ + if (text.size() > 1 && text.at(0).isHighSurrogate() && text.at(1).isLowSurrogate()) + return QChar::surrogateToUcs4(text.at(0), text.at(1)); + + return text.first().unicode(); +} + +// returns a pointer to the first QSvgGlyph to be used in the text +// or nullptr if none can be found +const QSvgGlyph *QSvgFont::findFirstGlyphFor(QStringView text) const +{ + const auto possibleIndices = m_possibleGlyphIndicesForChar.value(firstUcs4(text)); + for (const qsizetype i : possibleIndices) { + const QSvgGlyph ¤tGlyph = m_glyphs.at(i); + if (text.startsWith(currentGlyph.m_unicode)) { + return ¤tGlyph; + } + } + + for (; m_firstUnscannedGlyphIdx < m_glyphs.size(); ++m_firstUnscannedGlyphIdx) { + const QSvgGlyph ¤tGlyph = m_glyphs.at(m_firstUnscannedGlyphIdx); + m_possibleGlyphIndicesForChar[firstUcs4(currentGlyph.m_unicode)].push_back(m_firstUnscannedGlyphIdx); + if (text.startsWith(currentGlyph.m_unicode)) { + ++m_firstUnscannedGlyphIdx; + return ¤tGlyph; + } + } + return nullptr; +} + void QSvgFont::draw_helper(QPainter *p, const QPointF &point, const QString &str, qreal pixelSize, Qt::Alignment alignment, QRectF *boundingRect) const { @@ -69,19 +100,30 @@ p->translate(point); p->scale(pixelSize / m_unitsPerEm, -pixelSize / m_unitsPerEm); - // Calculate the text width to be used for alignment - int textWidth = 0; - QString::const_iterator itr = str.constBegin(); - for ( ; itr != str.constEnd(); ++itr) { - QChar unicode = *itr; - if (!m_glyphs.contains(*itr)) { + QVarLengthArray<const QSvgGlyph *> glyphsToDraw; + QStringView substring = str; + while (substring.length()) { + const QSvgGlyph *foundGlyph = findFirstGlyphFor(substring); + if (foundGlyph) { + glyphsToDraw.append(foundGlyph); + substring.slice(foundGlyph->m_unicode.length()); + } else { if (m_missingGlyph) - textWidth += static_cast<int>(m_missingGlyph->m_horizAdvX); - continue; + glyphsToDraw.append(m_missingGlyph.get()); + if (substring.size() > 1 + && substring.at(0).isHighSurrogate() && substring.at(1).isLowSurrogate()) { + substring.slice(2); + } else { + substring.slice(1); + } } - textWidth += static_cast<int>(m_glyphs[unicode].m_horizAdvX); } + // Calculate the text width to be used for alignment + int textWidth = 0; + for (const auto *glyph : std::as_const(glyphsToDraw)) + textWidth += static_cast<int>(glyph->m_horizAdvX); + QPoint alignmentOffset(0, 0); if (alignment == Qt::AlignHCenter) { alignmentOffset.setX(-textWidth / 2); @@ -99,31 +141,20 @@ pen.setWidthF(penWidth); p->setPen(pen); - itr = str.constBegin(); - for ( ; itr != str.constEnd(); ++itr) { - QSvgGlyph foundGlyph; - QChar unicode = *itr; - if (m_glyphs.contains(*itr)) { - foundGlyph = m_glyphs[unicode]; - } else { - if (!m_missingGlyph) - continue; - foundGlyph = *m_missingGlyph; - } - + for (const auto *glyph : std::as_const(glyphsToDraw)) { if (isPainting) - p->drawPath(foundGlyph.m_path); + p->drawPath(glyph->m_path); if (boundingRect) { QPainterPathStroker stroker; stroker.setWidth(penWidth); stroker.setJoinStyle(p->pen().joinStyle()); stroker.setMiterLimit(p->pen().miterLimit()); - QPainterPath stroke = stroker.createStroke(foundGlyph.m_path); + QPainterPath stroke = stroker.createStroke(glyph->m_path); *boundingRect |= p->transform().map(stroke).boundingRect(); } - p->translate(foundGlyph.m_horizAdvX, 0); + p->translate(glyph->m_horizAdvX, 0); } p->restore(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtsvg-everywhere-src-6.10.1/src/svg/qsvgfont_p.h new/qtsvg-everywhere-src-6.10.2/src/svg/qsvgfont_p.h --- old/qtsvg-everywhere-src-6.10.1/src/svg/qsvgfont_p.h 2025-11-13 17:35:39.000000000 +0100 +++ new/qtsvg-everywhere-src-6.10.2/src/svg/qsvgfont_p.h 2026-01-20 05:15:33.000000000 +0100 @@ -16,7 +16,7 @@ // #include "qpainterpath.h" -#include "qhash.h" +#include "qlist.h" #include "qstring.h" #include "qsvgstyle_p.h" #include "qtsvgglobal_p.h" @@ -28,10 +28,10 @@ class Q_SVG_EXPORT QSvgGlyph { public: - QSvgGlyph(QChar unicode, const QPainterPath &path, qreal horizAdvX); - QSvgGlyph() : m_unicode(0), m_horizAdvX(0) {} + QSvgGlyph(const QString &unicode, const QPainterPath &path, qreal horizAdvX); + QSvgGlyph() : m_horizAdvX(0) {} - QChar m_unicode; + QString m_unicode; QPainterPath m_path; qreal m_horizAdvX; }; @@ -48,13 +48,14 @@ void setUnitsPerEm(qreal upem); - void addGlyph(QChar unicode, const QPainterPath &path, qreal horizAdvX = -1); + void addGlyph(const QString &unicode, const QPainterPath &path, qreal horizAdvX = -1); bool addMissingGlyph(const QPainterPath &path, qreal horizAdvX); void draw(QPainter *p, const QPointF &point, const QString &str, qreal pixelSize, Qt::Alignment alignment) const; QRectF boundingRect(QPainter *p, const QPointF &point, const QString &str, qreal pixelSize, Qt::Alignment alignment) const; + const QSvgGlyph *findFirstGlyphFor(QStringView text) const; public: QString m_familyName; @@ -62,9 +63,17 @@ qreal m_horizAdvX; // not about a missing <glyph> element, but the font's <missing-glyph> element: std::unique_ptr<const QSvgGlyph> m_missingGlyph; - QHash<QChar, QSvgGlyph> m_glyphs; + // The following needs to preserve the order of glyphs because + // "17.6 Glyph selection rules" in SVG Tiny 1.2 reads: + // "the 'font' element must be searched from its first + // 'glyph' element to its last in logical order" + QList<QSvgGlyph> m_glyphs; private: + // to speed up finding glyphs + mutable QHash<char32_t, QList<qsizetype>> m_possibleGlyphIndicesForChar; + mutable qsizetype m_firstUnscannedGlyphIdx = 0; + void draw_helper(QPainter *p, const QPointF &point, const QString &str, qreal pixelSize, Qt::Alignment alignment, QRectF *boundingRect = nullptr) const; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtsvg-everywhere-src-6.10.1/src/svg/qsvghandler.cpp new/qtsvg-everywhere-src-6.10.2/src/svg/qsvghandler.cpp --- old/qtsvg-everywhere-src-6.10.1/src/svg/qsvghandler.cpp 2025-11-13 17:35:39.000000000 +0100 +++ new/qtsvg-everywhere-src-6.10.2/src/svg/qsvghandler.cpp 2026-01-20 05:15:33.000000000 +0100 @@ -560,7 +560,7 @@ qWarning("glyph does not define a non-empty 'unicode' attribute and will be ignored"); return false; } - font->addGlyph(uncStr.at(0), path, havx); + font->addGlyph(uncStr.toString(), path, havx); return true; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtsvg-everywhere-src-6.10.1/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp new/qtsvg-everywhere-src-6.10.2/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp --- old/qtsvg-everywhere-src-6.10.1/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp 2025-11-13 17:35:39.000000000 +0100 +++ new/qtsvg-everywhere-src-6.10.2/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp 2026-01-20 05:15:33.000000000 +0100 @@ -86,6 +86,7 @@ void testMarker(); void testPatternElement(); void testMisplacedElement(); + void testCycles_data(); void testCycles(); void testFeFlood(); void testFeOffset(); @@ -94,7 +95,6 @@ void testFeComposite(); void testFeGaussian(); void testFeBlend(); - void testUseCycles(); void testOption_data(); void testOption(); @@ -130,6 +130,8 @@ QCOMPARE(20, obj1.framesPerSecond()); obj1.setFramesPerSecond(0); QCOMPARE(0, obj1.framesPerSecond()); + QTest::ignoreMessage(QtWarningMsg, + "QSvgRenderer::setFramesPerSecond: Cannot set negative value -2147483648"); obj1.setFramesPerSecond(INT_MIN); QCOMPARE(0, obj1.framesPerSecond()); // Can't have a negative framerate obj1.setFramesPerSecond(INT_MAX); @@ -169,7 +171,8 @@ void tst_QSvgRenderer::inexistentUrl() { - const char *src = "<svg><g><path d=\"\" style=\"stroke:url(#inexistent)\"/></g></svg>"; + const char *src = "<svg><g><path d=\"M0 0\" style=\"stroke:url(#inexistent)\"/></g></svg>"; + QTest::ignoreMessage(QtWarningMsg, "<input>:1:66: Could not resolve property: #inexistent"); QByteArray data(src); QSvgRenderer renderer(data); @@ -180,6 +183,7 @@ void tst_QSvgRenderer::emptyUrl() { const char *src = "<svg><text fill=\"url()\" /></svg>"; + QTest::ignoreMessage(QtWarningMsg, "<input>:1:32: Could not resolve property: "); QByteArray data(src); QSvgRenderer renderer(data); @@ -1755,6 +1759,7 @@ QByteArray data(svgs[i]); if (i == 0) QTest::ignoreMessage(QtWarningMsg, "QFont::setPointSizeF: Point size <= 0 (0.000000), must be greater than 0"); + QTest::ignoreMessage(QtWarningMsg, "QFont::setPixelSize: Pixel size <= 0 (0)"); QSvgRenderer renderer(data); images[i] = QImage(50, 50, QImage::Format_ARGB32_Premultiplied); images[i].fill(-1); @@ -2238,29 +2243,28 @@ QCOMPARE(image, refImage); } -void tst_QSvgRenderer::testCycles() +void tst_QSvgRenderer::testCycles_data() { - QByteArray svgDoc(R"(<svg viewBox="0 0 200 200"> - <pattern id="pattern" patternUnits="userSpaceOnUse" width="20" height="20"> - <rect x="0" y="0" width="10" height="10" fill="url(#pattern) "/> - </pattern> - </svg>)"); + QTest::addColumn<QByteArray>("svgDoc"); - QSvgRenderer renderer(svgDoc); - QVERIFY(!renderer.isValid()); + QTest::newRow("fill-pattern") << R"(<svg viewBox="0 0 200 200"> + <pattern id="pattern" patternUnits="userSpaceOnUse" width="20" height="20"> + <rect x="0" y="0" width="10" height="10" fill="url(#pattern) "/> + </pattern> + </svg>)"_ba; + + QTest::newRow("use") << R"(<svg viewBox="0 0 200 200"> + <g xml:id="group-1"><use xml:id="use-1" xlink:href="#group-2"/></g> + <g xml:id="group-2"><use xml:id="use-2" xlink:href="#group-1"/></g> + </svg>)"_ba; } -void tst_QSvgRenderer::testUseCycles() +void tst_QSvgRenderer::testCycles() { - QByteArray svgDoc(R"(<svg viewBox="0 0 200 200"> - <g xml:id="group-1"> - <use xml:id="use-1" xlink:href="#group-2" /> - </g> - <g xml:id="group-2"> - <use xml:id="use-2" xlink:href="#group-1" /> - </g> - </svg>)"); - + QFETCH(QByteArray, svgDoc); +#if QT_CONFIG(regularexpression) + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("Cycles detected in SVG")); +#endif QSvgRenderer renderer(svgDoc); QVERIFY(!renderer.isValid()); }
