diff --git a/libqt5xdg-svg-render.patch b/libqt5xdg-svg-render.patch new file mode 100644 index 0000000..3f43d10 --- /dev/null +++ b/libqt5xdg-svg-render.patch @@ -0,0 +1,249 @@ +From 07bb4531fe90afed28785ae2ce1a5b3f8de1c022 Mon Sep 17 00:00:00 2001 +From: tsujan +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 + #include + #include ++#include + + #include + +@@ -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(mode) ++ % HexString(state) ++ % HexString(size.width()) ++ % HexString(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(mode) ++ % HexString(state) ++ % HexString(size.width()) ++ % HexString(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 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 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 > 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