summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/text/windows/qwindowsfontenginedirectwrite.cpp51
-rw-r--r--tests/manual/textrendering/fontenginecomparison/CMakeLists.txt21
-rw-r--r--tests/manual/textrendering/fontenginecomparison/main.cpp51
-rw-r--r--tests/manual/textrendering/fontenginecomparison/mainwindow.cpp86
-rw-r--r--tests/manual/textrendering/fontenginecomparison/mainwindow.h35
-rw-r--r--tests/manual/textrendering/fontenginecomparison/mainwindow.ui254
6 files changed, 479 insertions, 19 deletions
diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
index 2cf6aa92dd9..791e17f1d69 100644
--- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
@@ -163,27 +163,39 @@ static DWRITE_MEASURING_MODE renderModeToMeasureMode(DWRITE_RENDERING_MODE rende
}
}
+static QFont::HintingPreference determineHinting(const QFontDef &fontDef)
+{
+ QFont::HintingPreference hintingPreference = QFont::HintingPreference(fontDef.hintingPreference);
+ if (hintingPreference == QFont::PreferDefaultHinting) {
+ if (!qFuzzyCompare(qApp->devicePixelRatio(), 1.0)) {
+ // Microsoft documentation recommends using asymmetric rendering for small fonts
+ // at pixel size 16 and less, and symmetric for larger fonts.
+ hintingPreference = fontDef.pixelSize > 16.0
+ ? QFont::PreferNoHinting
+ : QFont::PreferVerticalHinting;
+ } else {
+ hintingPreference = QFont::PreferFullHinting;
+ }
+ }
+
+ return hintingPreference;
+}
+
DWRITE_RENDERING_MODE QWindowsFontEngineDirectWrite::hintingPreferenceToRenderingMode(const QFontDef &fontDef) const
{
if ((fontDef.styleStrategy & QFont::NoAntialias) && glyphFormat != QFontEngine::Format_ARGB)
return DWRITE_RENDERING_MODE_ALIASED;
- QFont::HintingPreference hintingPreference = QFont::HintingPreference(fontDef.hintingPreference);
- if (!qFuzzyCompare(qApp->devicePixelRatio(), 1.0) && hintingPreference == QFont::PreferDefaultHinting) {
- // Microsoft documentation recommends using asymmetric rendering for small fonts
- // at pixel size 16 and less, and symmetric for larger fonts.
- hintingPreference = fontDef.pixelSize > 16.0
- ? QFont::PreferNoHinting
- : QFont::PreferVerticalHinting;
- }
-
+ QFont::HintingPreference hintingPreference = determineHinting(fontDef);
switch (hintingPreference) {
case QFont::PreferNoHinting:
return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
case QFont::PreferVerticalHinting:
return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
default:
- return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
+ return fontDef.pixelSize > 16.0
+ ? DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
+ : DWRITE_RENDERING_MODE_GDI_CLASSIC;
}
}
@@ -558,15 +570,17 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn
QVarLengthArray<DWRITE_GLYPH_METRICS> glyphMetrics(glyphIndices.size());
HRESULT hr;
- DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef);
+ QFont::HintingPreference hint = determineHinting(fontDef);
bool needsDesignMetrics = shaperFlags & QFontEngine::DesignMetrics;
- if (!needsDesignMetrics && (renderMode == DWRITE_RENDERING_MODE_GDI_CLASSIC
- || renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL
- || renderMode == DWRITE_RENDERING_MODE_ALIASED)) {
+ if (!needsDesignMetrics && hint == QFont::PreferFullHinting) {
+ const DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef);
+ const bool needsNaturalMetrics = renderMode == DWRITE_RENDERING_MODE_NATURAL
+ || renderMode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
+
hr = m_directWriteFontFace->GetGdiCompatibleGlyphMetrics(float(fontDef.pixelSize),
1.0f,
NULL,
- renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL,
+ needsNaturalMetrics,
glyphIndices.data(),
glyphIndices.size(),
glyphMetrics.data());
@@ -763,11 +777,10 @@ QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph,
bool QWindowsFontEngineDirectWrite::supportsHorizontalSubPixelPositions() const
{
- DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef);
+ QFont::HintingPreference hinting = determineHinting(fontDef);
return (!isColorFont()
- && renderMode != DWRITE_RENDERING_MODE_GDI_CLASSIC
- && renderMode != DWRITE_RENDERING_MODE_GDI_NATURAL
- && renderMode != DWRITE_RENDERING_MODE_ALIASED);
+ && hinting != QFont::PreferFullHinting
+ && !(fontDef.styleStrategy & QFont::NoAntialias));
}
QFontEngine::Properties QWindowsFontEngineDirectWrite::properties() const
diff --git a/tests/manual/textrendering/fontenginecomparison/CMakeLists.txt b/tests/manual/textrendering/fontenginecomparison/CMakeLists.txt
new file mode 100644
index 00000000000..fc36718ad48
--- /dev/null
+++ b/tests/manual/textrendering/fontenginecomparison/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Copyright (C) 2025 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(vrs LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_manual_test(fontenginecomparison
+ GUI
+ SOURCES
+ main.cpp
+ mainwindow.cpp mainwindow.h mainwindow.ui
+ LIBRARIES
+ Qt::Gui
+ Qt::Widgets
+ ENABLE_AUTOGEN_TOOLS
+ uic
+
+)
diff --git a/tests/manual/textrendering/fontenginecomparison/main.cpp b/tests/manual/textrendering/fontenginecomparison/main.cpp
new file mode 100644
index 00000000000..c8fc4d84b38
--- /dev/null
+++ b/tests/manual/textrendering/fontenginecomparison/main.cpp
@@ -0,0 +1,51 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "mainwindow.h"
+
+#include <QtGui>
+#include <QApplication>
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+
+ if (a.arguments().size() > 5) {
+ QString fontFamily = a.arguments().at(1);
+ int fontSize = a.arguments().at(2).toInt();
+ QString example = a.arguments().at(3);
+ int weight = a.arguments().at(4).toInt();
+ bool isItalic = a.arguments().at(5).toInt();
+
+ QFont font(fontFamily);
+ font.setPixelSize(fontSize);
+ font.setWeight(QFont::Weight(weight));
+ font.setItalic(isItalic);
+
+ QTextLayout layout;
+ layout.setFont(font);
+ layout.setText(example);
+ layout.beginLayout();
+ layout.createLine();
+ layout.endLayout();
+
+ QRect brect = layout.boundingRect().toAlignedRect();
+
+ QImage image(brect.size(), QImage::Format_RGB32);
+ image.fill(Qt::white);
+ image.setDevicePixelRatio(1.0);
+
+ QPainter p;
+ p.begin(&image);
+ layout.draw(&p, -brect.topLeft());
+ p.end();
+
+ image.save(QStringLiteral("output.png"));
+
+ return 0;
+ } else {
+ MainWindow w;
+ w.show();
+ return a.exec();
+ }
+}
diff --git a/tests/manual/textrendering/fontenginecomparison/mainwindow.cpp b/tests/manual/textrendering/fontenginecomparison/mainwindow.cpp
new file mode 100644
index 00000000000..24123316851
--- /dev/null
+++ b/tests/manual/textrendering/fontenginecomparison/mainwindow.cpp
@@ -0,0 +1,86 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+
+#include <QProcess>
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+
+
+ ui->cbWeight->addItem(QStringLiteral("Thin"), QFont::Thin);
+ ui->cbWeight->addItem(QStringLiteral("ExtraLight"), QFont::ExtraLight);
+ ui->cbWeight->addItem(QStringLiteral("Light"), QFont::Light);
+ ui->cbWeight->addItem(QStringLiteral("Normal"), QFont::Normal);
+ ui->cbWeight->addItem(QStringLiteral("Medium"), QFont::Medium);
+ ui->cbWeight->addItem(QStringLiteral("DemiBold"), QFont::DemiBold);
+ ui->cbWeight->addItem(QStringLiteral("Bold"), QFont::Bold);
+ ui->cbWeight->addItem(QStringLiteral("ExtraBold"), QFont::ExtraBold);
+ ui->cbWeight->addItem(QStringLiteral("Black"), QFont::Black);
+ ui->cbWeight->setCurrentIndex(3);
+
+ updateFont();
+
+ connect(ui->sbPixelSize, &QSpinBox::valueChanged, this, &MainWindow::updateFont);
+ connect(ui->fontComboBox, &QFontComboBox::currentFontChanged, this, &MainWindow::updateFont);
+ connect(ui->rbDefault, &QRadioButton::toggled, this, &MainWindow::updateFont);
+ connect(ui->rbGdi, &QRadioButton::toggled, this, &MainWindow::updateFont);
+ connect(ui->rbFreetype, &QRadioButton::toggled, this, &MainWindow::updateFont);
+ connect(ui->leText, &QLineEdit::textChanged, this, &MainWindow::updateFont);
+ connect(ui->cbWeight, &QComboBox::currentIndexChanged, this, &MainWindow::updateFont);
+ connect(ui->cbItalic, &QCheckBox::toggled, this, &MainWindow::updateFont);
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
+
+void MainWindow::updateImage()
+{
+ if (m_process == nullptr)
+ return;
+
+ QImage img(QStringLiteral("output.png"));
+ if (!img.isNull())
+ ui->lImage->setPixmap(QPixmap::fromImage(img));
+}
+
+void MainWindow::updateFont()
+{
+ if (m_process == nullptr) {
+ m_process = new QProcess;
+ connect(m_process, &QProcess::finished, this, &MainWindow::updateImage);
+ }
+
+ if (m_process->isOpen())
+ m_process->close();
+
+ QString fontEngineName = QStringLiteral("directwrite");
+ if (ui->rbGdi->isChecked())
+ fontEngineName = QStringLiteral("gdi");
+ else if (ui->rbFreetype->isChecked())
+ fontEngineName = QStringLiteral("freetype");
+
+ QProcessEnvironment env;
+ env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("windows:fontengine=%1").arg(fontEngineName));
+ env.insert(QStringLiteral("windir"), qgetenv("windir"));
+ m_process->setProcessEnvironment(env);
+
+ QStringList args;
+ args.append(ui->fontComboBox->currentFont().family());
+ args.append(QString::number(ui->sbPixelSize->value()));
+ args.append(ui->leText->text().isEmpty()
+ ? QStringLiteral("The quick brown fox jumps over the lazy dog")
+ : ui->leText->text());
+ args.append(QString::number(ui->cbWeight->currentData().toInt()));
+ args.append(QString::number(int(ui->cbItalic->isChecked())));
+
+ m_process->start(qApp->arguments().first(), args);
+ m_process->waitForFinished();
+}
diff --git a/tests/manual/textrendering/fontenginecomparison/mainwindow.h b/tests/manual/textrendering/fontenginecomparison/mainwindow.h
new file mode 100644
index 00000000000..a7a4545ddbb
--- /dev/null
+++ b/tests/manual/textrendering/fontenginecomparison/mainwindow.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QProcess>
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class MainWindow;
+}
+QT_END_NAMESPACE
+
+class FontEngineRenderer;
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = nullptr);
+ ~MainWindow();
+
+public slots:
+ void updateFont();
+ void updateImage();
+
+private:
+ Ui::MainWindow *ui;
+ FontEngineRenderer *m_renderer = nullptr;
+ QProcess *m_process = nullptr;
+};
+#endif // MAINWINDOW_H
diff --git a/tests/manual/textrendering/fontenginecomparison/mainwindow.ui b/tests/manual/textrendering/fontenginecomparison/mainwindow.ui
new file mode 100644
index 00000000000..6393242740c
--- /dev/null
+++ b/tests/manual/textrendering/fontenginecomparison/mainwindow.ui
@@ -0,0 +1,254 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="gbExamples">
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="title">
+ <string>Examples</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QLabel" name="lImage">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Text settings</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLineEdit" name="leText">
+ <property name="text">
+ <string>The quick brown fox jumps over the lazy dog</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QFontComboBox" name="fontComboBox"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QComboBox" name="cbWeight"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="cbItalic">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Italic</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Pixel size:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="sbPixelSize">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>30</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Orientation::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Font engines</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QRadioButton" name="rbDefault">
+ <property name="text">
+ <string>Default</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="rbGdi">
+ <property name="text">
+ <string>GDI</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="rbFreetype">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Freetype</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>22</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>