Accepting request 882920 from X11:LXQt

- bsc#1183834: Fix displaying of icons by using QSvgRenderer
  * Add libqt5xdg-svg-render.patch

OBS-URL: https://build.opensuse.org/request/show/882920
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/libqt5xdg?expand=0&rev=13
This commit is contained in:
Richard Brown 2021-04-06 15:30:32 +00:00 committed by Git OBS Bridge
commit 3df581eed4
3 changed files with 258 additions and 1 deletions

249
libqt5xdg-svg-render.patch Normal file
View File

@ -0,0 +1,249 @@
From 07bb4531fe90afed28785ae2ce1a5b3f8de1c022 Mon Sep 17 00:00:00 2001
From: tsujan <tsujan2000@gmail.com>
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;

View File

@ -1,3 +1,9 @@
-------------------------------------------------------------------
Wed Mar 31 10:02:43 UTC 2021 - Michael Vetter <mvetter@suse.com>
- bsc#1183834: Fix displaying of icons by using QSvgRenderer
* Add libqt5xdg-svg-render.patch
-------------------------------------------------------------------
Wed Nov 4 13:17:31 UTC 2020 - Michael Vetter <mvetter@suse.com>

View File

@ -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 @@ URL: https://lxqt.org
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 @@ Tools for QtXdg.
%prep
%setup -q -n %{_name}-%{version}
%patch0 -p1
%build
%cmake