mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-07 10:33:24 -08:00
[Icons] Render authored theme SVG art without the SVG image plugin
`QPixmap("theme:file.svg")` needs Qt's SVG *image-format* plugin. Debian
builds that as the separate `qt6-svg-plugins` package, which is only a
Recommends of `qt6-svg-dev`, so a `--no-install-recommends` install (CI,
minimal user installs) does not have it. Authored theme art then loaded as
a null pixmap: the two authored-art render tests failed on Debian 13 and on
the Ubuntu sanitize leg while passing on a developer machine whose Qt
bundles the format.
Render authored SVG assets through QSvgRenderer instead, which is already
linked for the sentinel path and needs no plugin. Raster assets keep the
QPixmap loader. The test suite now hides the plugin directories, so the
dependency cannot come back unnoticed on platforms that ship the plugin.
This commit is contained in:
parent
876d66ffc9
commit
ceef749ac3
2 changed files with 71 additions and 3 deletions
|
|
@ -256,9 +256,21 @@ private:
|
|||
|
||||
QPixmap fromAsset(const QSize &pixelSize, QIcon::Mode mode) const
|
||||
{
|
||||
QPixmap pixmap(QStringLiteral("theme:") + resolvedPath);
|
||||
if (!pixelSize.isEmpty() && pixmap.size() != pixelSize) {
|
||||
pixmap = pixmap.scaled(pixelSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
QPixmap pixmap;
|
||||
if (resolvedAssetIsSvg) {
|
||||
// Render authored SVG art through QSvgRenderer rather than QPixmap.
|
||||
// Loading an `.svg` through QPixmap needs Qt's SVG *image-format*
|
||||
// plugin, which is a separate package on Linux distributions and is
|
||||
// absent from minimal installs and from CI (it is a Recommends of
|
||||
// qt6-svg-dev, so `--no-install-recommends` drops it). Art a theme
|
||||
// ships must not disappear because of a packaging choice, and the
|
||||
// renderer is already linked for the sentinel path.
|
||||
pixmap = renderSvg(resolvedSvg, pixelSize.isEmpty() ? intrinsicSize() : pixelSize, 1.0);
|
||||
} else {
|
||||
pixmap = QPixmap(QStringLiteral("theme:") + resolvedPath);
|
||||
if (!pixelSize.isEmpty() && pixmap.size() != pixelSize) {
|
||||
pixmap = pixmap.scaled(pixelSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
}
|
||||
if (mode == QIcon::Disabled && !pixmap.isNull()) {
|
||||
pixmap = QApplication::style()->generatedIconPixmap(QIcon::Disabled, pixmap, nullptr);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <QApplication>
|
||||
#include <QByteArray>
|
||||
#include <QColor>
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFont>
|
||||
|
|
@ -478,6 +479,61 @@ TEST_F(ThemeIconRenderTest, SentinelSvgBadgeMatchesTheEngine)
|
|||
EXPECT_GT(countOpaquePixels(pixmap, ThemeIconBadge::glyphColor(tone)), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Hides Qt's plugin directories while it lives, then restores them.
|
||||
*
|
||||
* Only the image-format plugins matter here: the platform plugin the fixture
|
||||
* needs is already loaded by the time a test runs.
|
||||
*/
|
||||
class ScopedPluginPathHiding
|
||||
{
|
||||
public:
|
||||
ScopedPluginPathHiding() : saved(QCoreApplication::libraryPaths())
|
||||
{
|
||||
QCoreApplication::setLibraryPaths({});
|
||||
}
|
||||
~ScopedPluginPathHiding()
|
||||
{
|
||||
QCoreApplication::setLibraryPaths(saved);
|
||||
}
|
||||
ScopedPluginPathHiding(const ScopedPluginPathHiding &) = delete;
|
||||
ScopedPluginPathHiding &operator=(const ScopedPluginPathHiding &) = delete;
|
||||
|
||||
private:
|
||||
QStringList saved;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Authored SVG art must not depend on Qt's SVG image-format plugin.
|
||||
*
|
||||
* Loading an `.svg` through QPixmap needs the separate `qsvg` image plugin.
|
||||
* Distributions that build Qt with the plugin split out (Debian, and therefore
|
||||
* CI) ship it in its own package, and a `--no-install-recommends` install does
|
||||
* not have it, so authored theme art rendered blank there while working on a
|
||||
* developer machine whose Qt bundles the format. Hiding the plugin directories
|
||||
* reproduces that install.
|
||||
*/
|
||||
TEST_F(ThemeIconRenderTest, AuthoredArtDoesNotNeedTheSvgImagePlugin)
|
||||
{
|
||||
QTemporaryDir themeDir;
|
||||
ASSERT_TRUE(themeDir.isValid());
|
||||
QFile file(QDir(themeDir.path()).absoluteFilePath(QStringLiteral("plain.svg")));
|
||||
ASSERT_TRUE(file.open(QIODevice::WriteOnly));
|
||||
file.write(svgWith("#336699"));
|
||||
file.close();
|
||||
QDir::addSearchPath(QStringLiteral("theme"), themeDir.path());
|
||||
|
||||
// The offscreen platform plugin is already loaded by the fixture, so an
|
||||
// empty library path only removes the image-format plugins.
|
||||
const ScopedPluginPathHiding hidePlugins;
|
||||
|
||||
const QIcon icon = loadThemedIcon(QStringLiteral("plain"));
|
||||
const QPixmap pixmap = icon.pixmap(QSize(32, 32));
|
||||
|
||||
ASSERT_FALSE(pixmap.isNull()) << "authored SVG art went through the QPixmap loader";
|
||||
EXPECT_GT(countOpaquePixels(pixmap, QColor(QStringLiteral("#336699"))), 0);
|
||||
}
|
||||
|
||||
/** @brief Badge never paints authored art: the asset keeps its own colors. */
|
||||
TEST_F(ThemeIconRenderTest, BadgeOnAuthoredArtUsesTheAssetPath)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue