Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kf6-ksvg for openSUSE:Factory checked in at 2026-09-11 18:00:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kf6-ksvg (Old) and /work/SRC/openSUSE:Factory/.kf6-ksvg.new.1265 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kf6-ksvg" Fri Sep 11 18:00:28 2026 rev:33 rq:1376719 version:6.30.0 Changes: -------- --- /work/SRC/openSUSE:Factory/kf6-ksvg/kf6-ksvg.changes 2026-08-17 17:00:32.409312345 +0200 +++ /work/SRC/openSUSE:Factory/.kf6-ksvg.new.1265/kf6-ksvg.changes 2026-09-11 18:02:58.056936691 +0200 @@ -1,0 +2,13 @@ +Tue Sep 8 09:22:31 UTC 2026 - Christophe Marin <[email protected]> + +- Update to 6.30.0 + * New feature release + * For more details please see: + * https://kde.org/announcements/frameworks/6/6.30.0 +- Changes since 6.29.0: + * Update dependency version to 6.30.0 + * Add missing EXCLUDE_DEPRECATED_BEFORE_AND_AT default variable declaration + * SvgItem: hold one texture for one picture, like FrameSvgItem does + * Update version to 6.30.0 + +------------------------------------------------------------------- Old: ---- ksvg-6.29.0.tar.xz ksvg-6.29.0.tar.xz.sig New: ---- ksvg-6.30.0.tar.xz ksvg-6.30.0.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kf6-ksvg.spec ++++++ --- /var/tmp/diff_new_pack.P4nITa/_old 2026-09-11 18:03:00.050020040 +0200 +++ /var/tmp/diff_new_pack.P4nITa/_new 2026-09-11 18:03:00.052020124 +0200 @@ -19,11 +19,11 @@ %define qt6_version 6.9.0 %define rname ksvg -# Full KF6 version (e.g. 6.29.0) +# Full KF6 version (e.g. 6.30.0) %{!?_kf6_version: %global _kf6_version %{version}} %bcond_without released Name: kf6-ksvg -Version: 6.29.0 +Version: 6.30.0 Release: 0 Summary: Components for handling SVGs License: GPL-2.0-or-later ++++++ 0001-Revert-Support-for-fractional-scaling.patch ++++++ --- /var/tmp/diff_new_pack.P4nITa/_old 2026-09-11 18:03:00.076021128 +0200 +++ /var/tmp/diff_new_pack.P4nITa/_new 2026-09-11 18:03:00.080021295 +0200 @@ -14,11 +14,11 @@ src/ksvg/svg.cpp | 27 ++++--- 7 files changed, 115 insertions(+), 120 deletions(-) -Index: ksvg-6.11.0git.20251028T204230~9eebb9d6/src/declarativeimports/framesvgitem.cpp +Index: ksvg-6.24.0git.20260817T171546~c35038c1/src/declarativeimports/framesvgitem.cpp =================================================================== ---- ksvg-6.11.0git.20251028T204230~9eebb9d6.orig/src/declarativeimports/framesvgitem.cpp 2025-10-28 19:42:30.000000000 +0100 -+++ ksvg-6.11.0git.20251028T204230~9eebb9d6/src/declarativeimports/framesvgitem.cpp 2025-10-29 05:53:35.434927031 +0100 -@@ -123,7 +123,7 @@ +--- ksvg-6.24.0git.20260817T171546~c35038c1.orig/src/declarativeimports/framesvgitem.cpp 2026-08-17 19:15:46.000000000 +0200 ++++ ksvg-6.24.0git.20260817T171546~c35038c1/src/declarativeimports/framesvgitem.cpp 2026-08-19 07:38:23.616648064 +0200 +@@ -122,7 +122,7 @@ void reposition(const QRect &frameGeometry, QSize &fullSize) { @@ -27,7 +27,7 @@ // ensure we're not passing a weird rectangle to updateTexturedRectGeometry if (!nodeRect.isValid() || nodeRect.isEmpty()) { -@@ -153,7 +153,7 @@ +@@ -152,7 +152,7 @@ QString elementId = prefix + FrameSvgHelpers::borderToElementId(m_border); // re-render the SVG at new size @@ -36,7 +36,7 @@ textureRect = texture()->normalizedTextureSubRect(); } else if (texture()) { // for fast stretch. textureRect = texture()->normalizedTextureSubRect(); -@@ -731,7 +731,10 @@ +@@ -730,7 +730,10 @@ void FrameSvgItem::updateDevicePixelRatio() { @@ -48,19 +48,19 @@ if (newDevicePixelRatio != m_frameSvg->devicePixelRatio()) { m_frameSvg->setDevicePixelRatio(newDevicePixelRatio); m_textureChanged = true; -Index: ksvg-6.11.0git.20251028T204230~9eebb9d6/src/declarativeimports/svgitem.cpp +Index: ksvg-6.24.0git.20260817T171546~c35038c1/src/declarativeimports/svgitem.cpp =================================================================== ---- ksvg-6.11.0git.20251028T204230~9eebb9d6.orig/src/declarativeimports/svgitem.cpp 2025-10-28 19:42:30.000000000 +0100 -+++ ksvg-6.11.0git.20251028T204230~9eebb9d6/src/declarativeimports/svgitem.cpp 2025-10-29 05:55:58.826843180 +0100 -@@ -15,6 +15,7 @@ - #include "ksvg/svg.h" +--- ksvg-6.24.0git.20260817T171546~c35038c1.orig/src/declarativeimports/svgitem.cpp 2026-08-17 19:15:46.000000000 +0200 ++++ ksvg-6.24.0git.20260817T171546~c35038c1/src/declarativeimports/svgitem.cpp 2026-08-19 07:38:23.616793086 +0200 +@@ -16,6 +16,7 @@ + #include "imagetexturescache.h" #include "managedtexturenode.h" +#include <cmath> //floor() #include <KColorScheme> #include <KColorUtils> -@@ -273,7 +274,10 @@ +@@ -277,7 +278,10 @@ void SvgItem::updateDevicePixelRatio() { @@ -72,10 +72,10 @@ if (newDevicePixelRatio != m_svg->devicePixelRatio()) { m_svg->setDevicePixelRatio(newDevicePixelRatio); m_textureChanged = true; -Index: ksvg-6.11.0git.20251028T204230~9eebb9d6/src/ksvg/framesvg.cpp +Index: ksvg-6.24.0git.20260817T171546~c35038c1/src/ksvg/framesvg.cpp =================================================================== ---- ksvg-6.11.0git.20251028T204230~9eebb9d6.orig/src/ksvg/framesvg.cpp 2025-10-28 19:42:30.000000000 +0100 -+++ ksvg-6.11.0git.20251028T204230~9eebb9d6/src/ksvg/framesvg.cpp 2025-10-29 05:53:35.435166833 +0100 +--- ksvg-6.24.0git.20260817T171546~c35038c1.orig/src/ksvg/framesvg.cpp 2026-08-17 19:15:46.000000000 +0200 ++++ ksvg-6.24.0git.20260817T171546~c35038c1/src/ksvg/framesvg.cpp 2026-08-19 07:38:23.616864927 +0200 @@ -15,7 +15,7 @@ #include <QCryptographicHash> #include <QPainter> @@ -94,7 +94,7 @@ } else { return d->frameSize(d->frame.data()); } -@@ -490,6 +490,9 @@ +@@ -517,6 +517,9 @@ if (maskFrame->cachedBackground.isNull()) { generateBackground(maskFrame); @@ -104,7 +104,7 @@ } return maskFrame->cachedBackground; -@@ -554,8 +557,8 @@ +@@ -581,8 +584,8 @@ } // Overlays @@ -115,7 +115,7 @@ if (overlayAvailable && !overlayCached) { overlaySize = q->elementSize(frame->prefix % QLatin1String("overlay")).toSize(); -@@ -582,7 +585,7 @@ +@@ -609,7 +612,7 @@ if (q->hasElement(QLatin1String("mask-") % prefix % QLatin1String("center"))) { overlay = alphaMask(); } else { @@ -124,7 +124,7 @@ overlay.fill(Qt::white); } QPainter overlayPainter(&overlay); -@@ -590,13 +593,13 @@ +@@ -617,13 +620,13 @@ // Tiling? if (q->hasElement(frame->prefix % QLatin1String("hint-overlay-tile-horizontal")) || q->hasElement(frame->prefix % QLatin1String("hint-overlay-tile-vertical"))) { @@ -141,7 +141,7 @@ } overlayPainter.end(); -@@ -609,14 +612,14 @@ +@@ -636,14 +639,14 @@ if (!overlay.isNull()) { QPainter p(&frame->cachedBackground); p.setCompositionMode(QPainter::CompositionMode_SourceOver); @@ -158,7 +158,7 @@ if (!size.isValid()) { #ifndef NDEBUG -@@ -629,14 +632,13 @@ +@@ -656,14 +659,13 @@ return; } @@ -175,7 +175,7 @@ paintCenter(p, frame, contentRect, size); paintCorner(p, frame, FrameSvg::LeftBorder | FrameSvg::TopBorder, contentRect); -@@ -645,26 +647,25 @@ +@@ -672,26 +674,25 @@ paintCorner(p, frame, FrameSvg::RightBorder | FrameSvg::BottomBorder, contentRect); // Sides @@ -214,7 +214,7 @@ if (frame->enabledBorders & FrameSvg::LeftBorder && q->hasElement(frame->prefix % QLatin1String("left"))) { contentRect.translate(frame->leftWidth * q->devicePixelRatio(), 0); } -@@ -686,7 +687,7 @@ +@@ -713,7 +714,7 @@ const QString oldPath = fd->imagePath; const FrameSvg::EnabledBorders oldBorders = fd->enabledBorders; @@ -223,7 +223,7 @@ const int oldColorSet = fd->colorSet; const auto oldColors = fd->colorOverrides; -@@ -751,28 +752,27 @@ +@@ -778,28 +779,27 @@ } } @@ -258,7 +258,7 @@ } else { q->paint(&p, FrameSvgHelpers::sectionRect(FrameSvg::NoBorder, contentRect, fullSize * q->devicePixelRatio()), centerElementId); } -@@ -781,7 +781,7 @@ +@@ -808,7 +808,7 @@ if (frame->composeOverBorder) { p.setCompositionMode(QPainter::CompositionMode_DestinationIn); @@ -267,7 +267,7 @@ p.setCompositionMode(QPainter::CompositionMode_SourceOver); } } -@@ -789,51 +789,35 @@ +@@ -816,51 +816,35 @@ void FrameSvgPrivate::paintBorder(QPainter &p, const QSharedPointer<FrameData> &frame, const FrameSvg::EnabledBorders borders, @@ -326,7 +326,7 @@ } } -@@ -891,7 +875,7 @@ +@@ -918,7 +902,7 @@ // qCDebug(LOG_KSVG) << "!!!!!!!!!!!!!!!!!!!!!! updating sizes" << prefix; Q_ASSERT(frame); @@ -335,10 +335,10 @@ q->resize(); if (!frame->cachedBackground.isNull()) { frame->cachedBackground = QPixmap(); -Index: ksvg-6.11.0git.20251028T204230~9eebb9d6/src/ksvg/private/framesvg_helpers.h +Index: ksvg-6.24.0git.20260817T171546~c35038c1/src/ksvg/private/framesvg_helpers.h =================================================================== ---- ksvg-6.11.0git.20251028T204230~9eebb9d6.orig/src/ksvg/private/framesvg_helpers.h 2025-10-28 19:42:30.000000000 +0100 -+++ ksvg-6.11.0git.20251028T204230~9eebb9d6/src/ksvg/private/framesvg_helpers.h 2025-10-29 05:53:35.435298165 +0100 +--- ksvg-6.24.0git.20260817T171546~c35038c1.orig/src/ksvg/private/framesvg_helpers.h 2026-08-17 19:15:46.000000000 +0200 ++++ ksvg-6.24.0git.20260817T171546~c35038c1/src/ksvg/private/framesvg_helpers.h 2026-08-19 07:38:23.616990868 +0200 @@ -45,7 +45,7 @@ /* * Returns the suggested geometry for the borders given a fullSize frame size and a contentRect @@ -385,10 +385,10 @@ } } -Index: ksvg-6.11.0git.20251028T204230~9eebb9d6/src/ksvg/private/framesvg_p.h +Index: ksvg-6.24.0git.20260817T171546~c35038c1/src/ksvg/private/framesvg_p.h =================================================================== ---- ksvg-6.11.0git.20251028T204230~9eebb9d6.orig/src/ksvg/private/framesvg_p.h 2025-10-28 19:42:30.000000000 +0100 -+++ ksvg-6.11.0git.20251028T204230~9eebb9d6/src/ksvg/private/framesvg_p.h 2025-10-29 05:53:35.435356265 +0100 +--- ksvg-6.24.0git.20260817T171546~c35038c1.orig/src/ksvg/private/framesvg_p.h 2026-08-17 19:15:46.000000000 +0200 ++++ ksvg-6.24.0git.20260817T171546~c35038c1/src/ksvg/private/framesvg_p.h 2026-08-19 07:38:23.617039319 +0200 @@ -80,39 +80,38 @@ static const int MAX_CACHED_MASKS = 10; uint lastModified = 0; @@ -493,10 +493,10 @@ static QHash<ImageSetPrivate *, QHash<uint, QWeakPointer<FrameData>>> s_sharedFrames; -Index: ksvg-6.11.0git.20251028T204230~9eebb9d6/src/ksvg/private/svg_p.h +Index: ksvg-6.24.0git.20260817T171546~c35038c1/src/ksvg/private/svg_p.h =================================================================== ---- ksvg-6.11.0git.20251028T204230~9eebb9d6.orig/src/ksvg/private/svg_p.h 2025-10-28 19:42:30.000000000 +0100 -+++ ksvg-6.11.0git.20251028T204230~9eebb9d6/src/ksvg/private/svg_p.h 2025-10-29 05:53:35.435391006 +0100 +--- ksvg-6.24.0git.20260817T171546~c35038c1.orig/src/ksvg/private/svg_p.h 2026-08-17 19:15:46.000000000 +0200 ++++ ksvg-6.24.0git.20260817T171546~c35038c1/src/ksvg/private/svg_p.h 2026-08-19 07:38:23.617072599 +0200 @@ -141,8 +141,8 @@ void setNaturalSize(const QString &path, const QSizeF &size); QSizeF naturalSize(const QString &path); @@ -517,11 +517,11 @@ QHash<QString, unsigned int> m_lastModifiedTimes; }; } -Index: ksvg-6.11.0git.20251028T204230~9eebb9d6/src/ksvg/svg.cpp +Index: ksvg-6.24.0git.20260817T171546~c35038c1/src/ksvg/svg.cpp =================================================================== ---- ksvg-6.11.0git.20251028T204230~9eebb9d6.orig/src/ksvg/svg.cpp 2025-10-28 19:42:30.000000000 +0100 -+++ ksvg-6.11.0git.20251028T204230~9eebb9d6/src/ksvg/svg.cpp 2025-10-29 05:53:35.435444116 +0100 -@@ -273,7 +273,7 @@ +--- ksvg-6.24.0git.20260817T171546~c35038c1.orig/src/ksvg/svg.cpp 2026-08-17 19:15:46.000000000 +0200 ++++ ksvg-6.24.0git.20260817T171546~c35038c1/src/ksvg/svg.cpp 2026-08-19 07:38:23.617125489 +0200 +@@ -278,7 +278,7 @@ QMetaObject::invokeMethod(m_configSyncTimer, qOverload<>(&QTimer::start)); } @@ -530,7 +530,7 @@ { const QString pathId = path % id; -@@ -281,7 +281,7 @@ +@@ -286,7 +286,7 @@ if (it == m_sizeHintsForId.constEnd()) { KConfigGroup imageGroup(m_svgElementsCache, path); const QStringList &encoded = imageGroup.readEntry(id, QStringList()); @@ -539,7 +539,7 @@ for (const auto &token : encoded) { const auto &parts = token.split(QLatin1Char('x')); if (parts.size() != 2) { -@@ -299,10 +299,10 @@ +@@ -304,10 +304,10 @@ return *it; } @@ -552,7 +552,7 @@ QString ret; for (const auto &s : list) { ret += QString::number(s.width()) % QLatin1Char('x') % QString::number(s.height()) % QLatin1Char(','); -@@ -563,7 +563,7 @@ +@@ -568,7 +568,7 @@ // Look at the size hinted elements and try to find the smallest one with an // identical aspect ratio. if (s.isValid() && !elementId.isEmpty()) { @@ -561,7 +561,7 @@ if (!elementSizeHints.isEmpty()) { QSizeF bestFit(-1, -1); -@@ -890,11 +890,18 @@ +@@ -898,11 +898,18 @@ void Svg::setDevicePixelRatio(qreal ratio) { @@ -581,7 +581,7 @@ Q_EMIT repaintNeeded(); } -@@ -922,7 +929,7 @@ +@@ -930,7 +937,7 @@ void Svg::paint(QPainter *painter, const QPointF &point, const QString &elementID) { Q_ASSERT(painter->device()); @@ -590,7 +590,7 @@ QPixmap pix((elementID.isNull() || d->multipleImages) ? d->findInCache(elementID, ratio, size()) : d->findInCache(elementID, ratio)); if (pix.isNull()) { -@@ -940,16 +947,16 @@ +@@ -948,16 +955,16 @@ void Svg::paint(QPainter *painter, const QRectF &rect, const QString &elementID) { Q_ASSERT(painter->device()); ++++++ ksvg-6.29.0.tar.xz -> ksvg-6.30.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksvg-6.29.0/CMakeLists.txt new/ksvg-6.30.0/CMakeLists.txt --- old/ksvg-6.29.0/CMakeLists.txt 2026-08-07 22:42:48.000000000 +0200 +++ new/ksvg-6.30.0/CMakeLists.txt 2026-09-04 13:40:55.000000000 +0200 @@ -1,12 +1,12 @@ cmake_minimum_required(VERSION 3.29) -set(KF_VERSION "6.29.0") # handled by release scripts -set(KF_DEP_VERSION "6.29.0") # handled by release scripts +set(KF_VERSION "6.30.0") # handled by release scripts +set(KF_DEP_VERSION "6.30.0") # handled by release scripts project(KSvg VERSION ${KF_VERSION}) # ECM setup include(FeatureSummary) -find_package(ECM 6.29.0 NO_MODULE) +find_package(ECM 6.30.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) @@ -28,6 +28,8 @@ include(ECMQmlModule) include(ECMGenerateQDoc) +set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].") + ecm_setup_version(PROJECT VARIABLE_PREFIX KSVG VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/ksvg_version.h" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksvg-6.29.0/autotests/svgtest.cpp new/ksvg-6.30.0/autotests/svgtest.cpp --- old/ksvg-6.29.0/autotests/svgtest.cpp 2026-08-07 22:42:48.000000000 +0200 +++ new/ksvg-6.30.0/autotests/svgtest.cpp 2026-09-04 13:40:55.000000000 +0200 @@ -32,6 +32,7 @@ void testElements(); void testColors(); void testStylesheetOverrideColorChange(); + void theSameImageIsHandedBackForTheSameRequest(); private: KSvg::Svg *m_svg; @@ -99,6 +100,35 @@ QCOMPARE(m_svg->size(), QSizeF(148, 148)); } +void SvgTest::theSameImageIsHandedBackForTheSameRequest() +{ + // The texture cache the QML items share keys on QImage::cacheKey(), so two items drawing one element + // at one size hold a single texture between them only as long as the same image comes back for it. + // Sixty list rows showing one arrow are sixty uploads and sixty atlas entries if this stops holding. + const QSize size(25, 25); + + // Two items are two Svg objects, so the question is asked of two of them rather than of m_svg, which + // the cases before this one leave carrying color overrides. + KSvg::Svg one; + one.setImagePath(QFINDTESTDATA("data/background.svgz")); + QVERIFY(one.isValid()); + const QImage once = one.image(size, QString()); + QVERIFY(!once.isNull()); + QCOMPARE(one.image(size, QString()).cacheKey(), once.cacheKey()); + + KSvg::Svg other; + other.setImagePath(QFINDTESTDATA("data/background.svgz")); + QVERIFY(other.isValid()); + QCOMPARE(other.image(size, QString()).cacheKey(), once.cacheKey()); + + // A different size is a different picture, and has to be a different image. + QVERIFY(one.image(QSize(26, 26), QString()).cacheKey() != once.cacheKey()); + + // A color override is a different picture too, so it must not be served the same image. + other.setColor(KSvg::Svg::StyleSheetColor::Text, Qt::magenta); + QVERIFY(other.image(size, QString()).cacheKey() != once.cacheKey()); +} + void SvgTest::testElements() { QVERIFY(m_svg->hasElement("center")); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksvg-6.29.0/src/declarativeimports/framesvgitem.cpp new/ksvg-6.30.0/src/declarativeimports/framesvgitem.cpp --- old/ksvg-6.29.0/src/declarativeimports/framesvgitem.cpp 2026-08-07 22:42:48.000000000 +0200 +++ new/ksvg-6.30.0/src/declarativeimports/framesvgitem.cpp 2026-09-04 13:40:55.000000000 +0200 @@ -28,7 +28,6 @@ namespace KSvg { -Q_GLOBAL_STATIC(ImageTexturesCache, s_cache) class FrameNode : public QSGNode { @@ -118,7 +117,7 @@ if (m_fitMode != Tile) { options = QQuickWindow::TextureCanUseAtlas; } - setTexture(s_cache->loadTexture(m_frameSvg->window(), m_frameSvg->frameSvg()->image(size, elementId), options)); + setTexture(ImageTexturesCache::instance()->loadTexture(m_frameSvg->window(), m_frameSvg->frameSvg()->image(size, elementId), options)); } void reposition(const QRect &frameGeometry, QSize &fullSize) @@ -664,7 +663,7 @@ if ((m_textureChanged || m_sizeChanged) || textureNode->texture()->textureSize() != m_frameSvg->size()) { QImage image = m_frameSvg->framePixmap().toImage(); - textureNode->setTexture(s_cache->loadTexture(window(), image)); + textureNode->setTexture(ImageTexturesCache::instance()->loadTexture(window(), image)); textureNode->setRect(0, 0, width(), height()); m_textureChanged = false; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksvg-6.29.0/src/declarativeimports/imagetexturescache.cpp new/ksvg-6.30.0/src/declarativeimports/imagetexturescache.cpp --- old/ksvg-6.29.0/src/declarativeimports/imagetexturescache.cpp 2026-08-07 22:42:48.000000000 +0200 +++ new/ksvg-6.30.0/src/declarativeimports/imagetexturescache.cpp 2026-09-04 13:40:55.000000000 +0200 @@ -5,6 +5,8 @@ */ #include "imagetexturescache.h" +#include <QMutex> +#include <QMutexLocker> #include <QSGTexture> typedef QHash<qint64, QHash<QWindow *, QWeakPointer<QSGTexture>>> TexturesCache; @@ -13,6 +15,9 @@ { public: TexturesCache cache; + // Items ask for their textures from the render thread of the window they are in, and a window has its + // own, so the cache is reached from several threads at once. + QMutex lock; }; ImageTexturesCache::ImageTexturesCache() @@ -24,13 +29,21 @@ { } +ImageTexturesCache *ImageTexturesCache::instance() +{ + static ImageTexturesCache cache; + return &cache; +} + QSharedPointer<QSGTexture> ImageTexturesCache::loadTexture(QQuickWindow *window, const QImage &image, QQuickWindow::CreateTextureOptions options) { qint64 id = image.cacheKey(); + QMutexLocker locked(&d->lock); QSharedPointer<QSGTexture> texture = d->cache.value(id).value(window).toStrongRef(); if (!texture) { auto cleanAndDelete = [this, window, id](QSGTexture *texture) { + QMutexLocker locked(&d->lock); QHash<QWindow *, QWeakPointer<QSGTexture>> &textures = (d->cache)[id]; textures.remove(window); if (textures.isEmpty()) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksvg-6.29.0/src/declarativeimports/imagetexturescache.h new/ksvg-6.30.0/src/declarativeimports/imagetexturescache.h --- old/ksvg-6.29.0/src/declarativeimports/imagetexturescache.h 2026-08-07 22:42:48.000000000 +0200 +++ new/ksvg-6.30.0/src/declarativeimports/imagetexturescache.h 2026-09-04 13:40:55.000000000 +0200 @@ -30,6 +30,14 @@ ~ImageTexturesCache(); /*! + * Returns the cache every item shares. + * + * Two items drawing the same picture should hold one texture between them, which only works if they + * ask the same cache for it. + */ + static ImageTexturesCache *instance(); + + /*! * Returns the texture for a given window and image. * * If image id is the same as one already provided before, we will not diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksvg-6.29.0/src/declarativeimports/svgitem.cpp new/ksvg-6.30.0/src/declarativeimports/svgitem.cpp --- old/ksvg-6.29.0/src/declarativeimports/svgitem.cpp 2026-08-07 22:42:48.000000000 +0200 +++ new/ksvg-6.30.0/src/declarativeimports/svgitem.cpp 2026-09-04 13:40:55.000000000 +0200 @@ -14,6 +14,7 @@ #include "ksvg/svg.h" +#include "imagetexturescache.h" #include "managedtexturenode.h" #include <KColorScheme> @@ -222,8 +223,10 @@ return nullptr; } - QSharedPointer<QSGTexture> texture(window()->createTextureFromImage(m_image, QQuickWindow::TextureCanUseAtlas)); - textureNode->setTexture(texture); + // The same element at the same size is one picture however many items draw it, and KSvg hands back + // the same image for it, so one texture is enough: an arrow in sixty list rows was sixty uploads + // and sixty atlas entries before this. + textureNode->setTexture(ImageTexturesCache::instance()->loadTexture(window(), m_image, QQuickWindow::TextureCanUseAtlas)); m_textureChanged = false; textureNode->setRect(0, 0, width(), height());
