Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libqt5xdg for openSUSE:Factory checked in at 2021-04-06 17:30:32 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libqt5xdg (Old) and /work/SRC/openSUSE:Factory/.libqt5xdg.new.2401 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libqt5xdg" Tue Apr 6 17:30:32 2021 rev:13 rq:882920 version:3.6.0 Changes: -------- --- /work/SRC/openSUSE:Factory/libqt5xdg/libqt5xdg.changes 2020-11-04 18:32:31.088130969 +0100 +++ /work/SRC/openSUSE:Factory/.libqt5xdg.new.2401/libqt5xdg.changes 2021-04-06 17:31:57.935271975 +0200 @@ -1,0 +2,6 @@ +Wed Mar 31 10:02:43 UTC 2021 - Michael Vetter <[email protected]> + +- bsc#1183834: Fix displaying of icons by using QSvgRenderer + * Add libqt5xdg-svg-render.patch + +------------------------------------------------------------------- New: ---- libqt5xdg-svg-render.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libqt5xdg.spec ++++++ --- /var/tmp/diff_new_pack.wUbwdl/_old 2021-04-06 17:31:58.467272576 +0200 +++ /var/tmp/diff_new_pack.wUbwdl/_new 2021-04-06 17:31:58.471272581 +0200 @@ -1,7 +1,7 @@ # # spec file for package libqt5xdg # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -27,6 +27,7 @@ Source: https://github.com/lxqt/libqtxdg/releases/download/%{version}/%{_name}-%{version}.tar.xz Source1: https://github.com/lxqt/libqtxdg/releases/download/%{version}/%{_name}-%{version}.tar.xz.asc Source2: %{name}.keyring +Patch0: libqt5xdg-svg-render.patch BuildRequires: cmake >= 3.1.0 BuildRequires: fdupes BuildRequires: gcc-c++ @@ -88,6 +89,7 @@ %prep %setup -q -n %{_name}-%{version} +%patch0 -p1 %build %cmake ++++++ libqt5xdg-svg-render.patch ++++++ >From 07bb4531fe90afed28785ae2ce1a5b3f8de1c022 Mon Sep 17 00:00:00 2001 From: tsujan <[email protected]> Date: Wed, 24 Mar 2021 14:24:55 +0430 Subject: [PATCH] Use QSvgRenderer for SVG icons (#247) * Use QSvgRenderer for SVG icons `QSvgRenderer` is used with a cache for both ordinary and colorized SVG icons. In this way, LXQt's icon handling cannot be broken by intruding icon engines, which register themselves for "svg" (see https://github.com/lxqt/libqtxdg/issues/246). Moreover, it does not depend on a specific code structure of `qtsvg` or any other icon engine. * Just removed a redundant computation * Used the same key structure for SVG cache --- src/xdgiconloader/xdgiconloader.cpp | 179 ++++++++++++++++------------ 1 file changed, 100 insertions(+), 79 deletions(-) diff --git a/src/xdgiconloader/xdgiconloader.cpp b/src/xdgiconloader/xdgiconloader.cpp index aeabda8..66d3dd8 100644 --- a/src/xdgiconloader/xdgiconloader.cpp +++ b/src/xdgiconloader/xdgiconloader.cpp @@ -53,6 +53,7 @@ #include <QImageReader> #include <QXmlStreamReader> #include <QFileSystemWatcher> +#include <QSvgRenderer> #include <private/qhexstring_p.h> @@ -787,121 +788,141 @@ QPixmap PixmapEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State st return cachedPixmap; } -// XXX: duplicated from qiconloader.cpp, because this symbol isn't exported :( +// NOTE: For SVG, QSvgRenderer is used to prevent our icon handling from +// being broken by icon engines that register themselves for SVG. QPixmap ScalableEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) { - if (svgIcon.isNull()) - svgIcon = QIcon(filename); + QPixmap pm; + if (size.isEmpty()) + return pm; - // Bypass QIcon API, as that will scale by device pixel ratio of the - // highest DPR screen since we're not passing on any QWindow. - if (QIconEngine *engine = svgIcon.data_ptr() ? svgIcon.data_ptr()->engine : nullptr) - return engine->pixmap(size, mode, state); + QString key = QLatin1String("lxqt_") + % filename + % HexString<int>(mode) + % HexString<int>(state) + % HexString<int>(size.width()) + % HexString<int>(size.height()); + if (!QPixmapCache::find(key, &pm)) + { + int icnSize = qMin(size.width(), size.height()); + pm = QPixmap(icnSize, icnSize); + pm.fill(Qt::transparent); - return QPixmap(); + QSvgRenderer renderer; + if (renderer.load(filename)) + { + QPainter p; + p.begin(&pm); + renderer.render(&p, QRect(0, 0, icnSize, icnSize)); + p.end(); + } + + svgIcon = QIcon(pm); + if (QIconEngine *engine = svgIcon.data_ptr() ? svgIcon.data_ptr()->engine : nullptr) + pm = engine->pixmap(size, mode, state); + QPixmapCache::insert(key, pm); + } + + return pm; } static const QString STYLE = QStringLiteral("\n.ColorScheme-Text, .ColorScheme-NeutralText {color:%1;}\ \n.ColorScheme-Background {color:%2;}\ \n.ColorScheme-Highlight {color:%3;}"); -// Note: Qt palette does not have any colors for positive/negative text +// NOTE: Qt palette does not have any colors for positive/negative text // .ColorScheme-PositiveText,ColorScheme-NegativeText {color:%4;} QPixmap ScalableFollowsColorEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) { QPixmap pm; - // see ScalableEntry::pixmap() for the reason - if (QIconEngine *engine = svgIcon.data_ptr() ? svgIcon.data_ptr()->engine : nullptr) - pm = engine->pixmap(size, mode, state); + if (size.isEmpty()) + return pm; - // Note: not checking the QIcon::isNull(), because in Qt5.10 the isNull() is not reliable - // for svg icons desierialized from stream (see https://codereview.qt-project.org/#/c/216086/) - if (pm.isNull()) + const QPalette pal = qApp->palette(); + QString txtCol, bgCol, hCol; + if (mode == QIcon::Disabled) + { + txtCol = pal.color(QPalette::Disabled, QPalette::WindowText).name(); + bgCol = pal.color(QPalette::Disabled, QPalette::Window).name(); + hCol = pal.color(QPalette::Disabled, QPalette::Highlight).name(); + } + else + { + if (mode == QIcon::Selected) + { + txtCol = pal.highlightedText().color().name(); + bgCol = pal.highlight().color().name(); + } + else // normal or active + { + txtCol = pal.windowText().color().name(); + bgCol = pal.window().color().name(); + } + hCol = pal.highlight().color().name(); + } + QString key = QLatin1String("lxqt_") + % filename + % HexString<int>(mode) + % HexString<int>(state) + % HexString<int>(size.width()) + % HexString<int>(size.height()) + % txtCol % bgCol % hCol; + if (!QPixmapCache::find(key, &pm)) { - // The following lines are adapted and updated from KDE's "kiconloader.cpp" -> - // KIconLoaderPrivate::processSvg() and KIconLoaderPrivate::createIconImage(). - // They read the SVG color scheme of SVG icons and give images based on the icon mode. - QHash<int, QByteArray> svg_buffers; + int icnSize = qMin(size.width(), size.height()); + pm = QPixmap(icnSize, icnSize); + pm.fill(Qt::transparent); + QFile device{filename}; if (device.open(QIODevice::ReadOnly)) { - const QPalette pal = qApp->palette(); - // Note: indexes are assembled as in qtsvg (QSvgIconEnginePrivate::hashKey()) - QMap<int, QString> style_sheets; - style_sheets[(QIcon::Normal<<4)|QIcon::Off] = STYLE.arg(pal.windowText().color().name(), pal.window().color().name(), pal.highlight().color().name()); - style_sheets[(QIcon::Selected<<4)|QIcon::Off] = STYLE.arg(pal.highlightedText().color().name(), pal.highlight().color().name(), pal.highlightedText().color().name()); - QMap<int, QSharedPointer<QXmlStreamWriter> > writers; - for (auto i = style_sheets.cbegin(); i != style_sheets.cend(); ++i) - { - writers[i.key()].reset(new QXmlStreamWriter{&svg_buffers[i.key()]}); - } - + QString styleSheet = STYLE.arg(txtCol, bgCol, hCol); + QByteArray svgBuffer; + QXmlStreamWriter writer(&svgBuffer); QXmlStreamReader xmlReader(&device); while (!xmlReader.atEnd()) { if (xmlReader.readNext() == QXmlStreamReader::StartElement - && xmlReader.qualifiedName() == QLatin1String("style") - && xmlReader.attributes().value(QLatin1String("id")) == QLatin1String("current-color-scheme")) + && xmlReader.qualifiedName() == QLatin1String("style") + && xmlReader.attributes().value(QLatin1String("id")) == QLatin1String("current-color-scheme")) { const auto attribs = xmlReader.attributes(); // store original data/text of the <style> element - QString original_data; + QString origData; while (xmlReader.tokenType() != QXmlStreamReader::EndElement) { if (xmlReader.tokenType() == QXmlStreamReader::Characters) - original_data += xmlReader.text(); + origData += xmlReader.text(); xmlReader.readNext(); } - for (auto i = style_sheets.cbegin(); i != style_sheets.cend(); ++i) - { - QXmlStreamWriter & writer = *writers[i.key()]; - writer.writeStartElement(QLatin1String("style")); - writer.writeAttributes(attribs); - // Note: We're writting the original style text to leave - // there "defaults" for unknown/unsupported classes. - // Then appending our "overrides" - writer.writeCharacters(original_data); - writer.writeCharacters(*i); - writer.writeEndElement(); - } - } else if (xmlReader.tokenType() != QXmlStreamReader::Invalid) - { - for (auto i = style_sheets.cbegin(); i != style_sheets.cend(); ++i) - { - writers[i.key()]->writeCurrentToken(xmlReader); - } + writer.writeStartElement(QLatin1String("style")); + writer.writeAttributes(attribs); + writer.writeCharacters(origData); + writer.writeCharacters(styleSheet); + writer.writeEndElement(); } + else if (xmlReader.tokenType() != QXmlStreamReader::Invalid) + writer.writeCurrentToken(xmlReader); + } + + if (!svgBuffer.isEmpty()) + { + QSvgRenderer renderer; + renderer.load(svgBuffer); + QPainter p; + p.begin(&pm); + renderer.render(&p, QRect(0, 0, icnSize, icnSize)); + p.end(); } - // duplicate the contets also for opposite state - svg_buffers[(QIcon::Normal<<4)|QIcon::On] = svg_buffers[(QIcon::Normal<<4)|QIcon::Off]; - svg_buffers[(QIcon::Selected<<4)|QIcon::On] = svg_buffers[(QIcon::Selected<<4)|QIcon::Off]; } - // use the QSvgIconEngine - // - assemble the content as it is done by the operator <<(QDataStream &s, const QIcon &icon) - // (the QSvgIconEngine::key() + QSvgIconEngine::write()) - // - create the QIcon from the content by usage of the QIcon::operator >>(QDataStream &s, const QIcon &icon) - // (icon with the (QSvgIconEngine) will be used) - QByteArray icon_arr; - QDataStream str{&icon_arr, QIODevice::WriteOnly}; - str.setVersion(QDataStream::Qt_4_4); - QHash<int, QString> filenames; - filenames[0] = filename; // Note: filenames are ignored in the QSvgIconEngine::read() - str << QStringLiteral("svg") << filenames << static_cast<int>(0)/*isCompressed*/ << svg_buffers << static_cast<int>(0)/*hasAddedPimaps*/; - - QDataStream str_read{&icon_arr, QIODevice::ReadOnly}; - str_read.setVersion(QDataStream::Qt_4_4); - - str_read >> svgIcon; + + // Do not use this pixmap directly but first get the icon + // for QIcon::pixmap() to handle states and modes, + // especially the disabled mode. + svgIcon = QIcon(pm); if (QIconEngine *engine = svgIcon.data_ptr() ? svgIcon.data_ptr()->engine : nullptr) pm = engine->pixmap(size, mode, state); - - // load the icon directly from file, if still null - if (pm.isNull()) - { - svgIcon = QIcon(filename); - if (QIconEngine *engine = svgIcon.data_ptr() ? svgIcon.data_ptr()->engine : nullptr) - pm = engine->pixmap(size, mode, state); - } + QPixmapCache::insert(key, pm); } return pm;
