fix(gui): make SVG icon rasterization DPI-aware in loadPixmap (#189) #266

Merged
forbes merged 2 commits from fix/toolbar-icon-dpi-scaling into main 2026-02-18 18:57:15 +00:00
3 changed files with 96 additions and 1 deletions

View File

@@ -217,7 +217,9 @@ bool BitmapFactoryInst::loadPixmap(const QString& filename, QPixmap& icon) const
QFile svgFile(fi.filePath());
if (svgFile.open(QFile::ReadOnly | QFile::Text)) {
QByteArray content = svgFile.readAll();
icon = pixmapFromSvg(content, QSize(64, 64));
static qreal dpr = getMaximumDPR();
icon = pixmapFromSvg(content, QSize(64, 64) * dpr);
icon.setDevicePixelRatio(dpr);
}
}
else {

View File

@@ -0,0 +1,92 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
#include <gtest/gtest.h>
#include <QApplication>
#include <QDir>
#include <QFile>
#include <QTemporaryDir>
#include <Gui/BitmapFactory.h>
#include <src/App/InitApplication.h>
namespace
{
// Minimal valid SVG used as test icon
constexpr const char* kTestSvg =
R"(<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64")"
R"( viewBox="0 0 64 64"><rect width="64" height="64" fill="#ff0000"/></svg>)";
} // namespace
class BitmapFactoryTest : public ::testing::Test
{
protected:
static void SetUpTestSuite()
{
tests::initApplication();
// QPixmap and QSvgRenderer require a QGuiApplication.
// gtest_main does not create one, so we construct it here.
if (!QApplication::instance()) {
static int argc = 1;
static char arg0[] = "Gui_tests_run";
static char* argv[] = {arg0, nullptr};
static QApplication app(argc, argv);
}
}
};
// pixmapFromSvg(content, size) renders at the exact requested size
TEST_F(BitmapFactoryTest, PixmapFromSvgContentRendersAtRequestedSize)
{
QByteArray svg(kTestSvg);
QSize requested(48, 48);
QPixmap px = Gui::BitmapFactory().pixmapFromSvg(svg, requested);
ASSERT_FALSE(px.isNull());
EXPECT_EQ(px.width(), 48);
EXPECT_EQ(px.height(), 48);
}
// getMaximumDPR returns at least 1.0
TEST_F(BitmapFactoryTest, MaximumDPRIsAtLeastOne)
{
qreal dpr = Gui::BitmapFactoryInst::getMaximumDPR();
EXPECT_GE(dpr, 1.0);
}
// pixmap() loaded from an SVG file has correct devicePixelRatio and physical size
TEST_F(BitmapFactoryTest, PixmapFromSvgFileHasCorrectDPR)
{
// Write a test SVG to a temporary directory
QTemporaryDir tmpDir;
ASSERT_TRUE(tmpDir.isValid());
QString svgPath = tmpDir.path() + QDir::separator() + "test-dpi-icon.svg";
QFile file(svgPath);
ASSERT_TRUE(file.open(QFile::WriteOnly | QFile::Text));
file.write(kTestSvg);
file.close();
// Add the temp dir as a search path and load via pixmap()
Gui::BitmapFactory().addPath(tmpDir.path());
QPixmap px = Gui::BitmapFactory().pixmap("test-dpi-icon");
ASSERT_FALSE(px.isNull());
qreal expectedDpr = Gui::BitmapFactoryInst::getMaximumDPR();
EXPECT_DOUBLE_EQ(px.devicePixelRatio(), expectedDpr);
// Physical size should be 64 * dpr
int expectedPhysical = static_cast<int>(64 * expectedDpr);
EXPECT_EQ(px.width(), expectedPhysical);
EXPECT_EQ(px.height(), expectedPhysical);
Gui::BitmapFactory().removePath(tmpDir.path());
}

View File

@@ -3,6 +3,7 @@
# Standard C++ GTest tests
add_executable(Gui_tests_run
Assistant.cpp
BitmapFactory.cpp
Camera.cpp
StyleParameters/StyleParametersApplicationTest.cpp
StyleParameters/ParserTest.cpp