File indexing completed on 2024-05-19 04:29:20

0001 /*
0002  * SPDX-FileCopyrightText: 2016 The Qt Company Ltd.
0003  * SPDX-FileCopyrightText: 2020 Halla Rempt <halla@valdyas.org>
0004  * SPDX-FileCopyrightText: 2021 Alvin Wong <alvin@alvinhc.com>
0005  *
0006  * SPDX-License-Identifier: GPL-3.0-or-later
0007  *
0008  *
0009  * This file contains code that was borrowed and modified from the Qt Project,
0010  * originally licensed under LGPL-3.0-or-later or GPL-2.0-or-later.
0011  */
0012 
0013 #include "KisUiFont.h"
0014 
0015 #include <kis_config.h>
0016 
0017 #include <boost/optional.hpp>
0018 
0019 #include <QtGlobal>
0020 #include <QFontDatabase>
0021 
0022 #if defined(Q_OS_WIN) && QT_VERSION < 0x060000
0023 # include <qt_windows.h>
0024 #endif
0025 
0026 namespace KisUiFont
0027 {
0028 
0029 static const QString useCustomSystemFontCfgName = QStringLiteral("use_custom_system_font");
0030 static const QString customSystemFontCfgName = QStringLiteral("custom_system_font");
0031 static const QString customFontSizeCfgName = QStringLiteral("custom_font_size");
0032 
0033 /**
0034  * @brief Gets the system default UI font.
0035  * @return the system default UI font.
0036  */
0037 static QFont systemDefaultUiFont();
0038 
0039 /**
0040  * @brief Returns the font the user has configured.
0041  * @return the user font if it has been set, otherwise `boost::none`.
0042  */
0043 static boost::optional<QFont> userCfgUiFont();
0044 
0045 #if defined(Q_OS_WIN) && QT_VERSION < 0x060000
0046 static QFont windowsSystemUiFont();
0047 #endif
0048 
0049 QFont systemDefaultUiFont()
0050 {
0051 #if defined(Q_OS_WIN) && QT_VERSION < 0x060000
0052     return windowsSystemUiFont();
0053 #else
0054     return QFontDatabase::systemFont(QFontDatabase::GeneralFont);
0055 #endif
0056 }
0057 
0058 boost::optional<QFont> userCfgUiFont()
0059 {
0060     KisConfig cfg(true);
0061     if (cfg.readEntry<bool>(useCustomSystemFontCfgName, false)) {
0062         QString fontName = cfg.readEntry<QString>(customSystemFontCfgName, QString());
0063         if (fontName.isEmpty()) {
0064             return boost::none;
0065         }
0066         int fontSize = cfg.readEntry<int>(customFontSizeCfgName, -1);
0067         if (fontSize <= 6) {
0068             fontSize = systemDefaultUiFont().pointSize();
0069         }
0070         return QFont(fontName, fontSize);
0071     } else {
0072         return boost::none;
0073     }
0074 }
0075 
0076 QFont normalFont()
0077 {
0078     QFont font;
0079     if (boost::optional<QFont> userFont = userCfgUiFont()) {
0080         font = *userFont;
0081     } else {
0082         font = systemDefaultUiFont();
0083     }
0084 #ifdef Q_OS_WIN
0085     // XXX: Forces Qt to use full hinting for UI text, otherwise the default
0086     //      will cause Qt to do vertical hinting only when High-DPI is active,
0087     //      which makes some UI text extremely blurry on CJK systems.
0088     font.setHintingPreference(QFont::PreferFullHinting);
0089 #endif
0090     return font;
0091 }
0092 
0093 QFont dockFont()
0094 {
0095     QFont font = normalFont();
0096     font.setPointSizeF(font.pointSizeF() * 0.9);
0097     return font;
0098 }
0099 
0100 #if defined(Q_OS_WIN) && QT_VERSION < 0x060000
0101 
0102 // From qtbase/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
0103 static int defaultVerticalDPI()
0104 {
0105     static int vDPI = -1;
0106     if (vDPI == -1) {
0107         if (HDC defaultDC = GetDC(0)) {
0108             vDPI = GetDeviceCaps(defaultDC, LOGPIXELSY);
0109             ReleaseDC(0, defaultDC);
0110         } else {
0111             // FIXME: Resolve now or return 96 and keep unresolved?
0112             vDPI = 96;
0113         }
0114     }
0115     return vDPI;
0116 }
0117 
0118 // From qtbase/src/gui/text/qplatformfontdatabase.cpp
0119 QFont::Weight weightFromInteger(int weight)
0120 {
0121     if (weight < 150) {
0122         return QFont::Thin;
0123     }
0124     if (weight < 250) {
0125         return QFont::ExtraLight;
0126     }
0127     if (weight < 350) {
0128         return QFont::Light;
0129     }
0130     if (weight < 450) {
0131         return QFont::Normal;
0132     }
0133     if (weight < 550) {
0134         return QFont::Medium;
0135     }
0136     if (weight < 650) {
0137         return QFont::DemiBold;
0138     }
0139     if (weight < 750) {
0140         return QFont::Bold;
0141     }
0142     if (weight < 850) {
0143         return QFont::ExtraBold;
0144     }
0145     return QFont::Black;
0146 }
0147 
0148 // From qtbase/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
0149 static QFont LOGFONT_to_QFont(const LOGFONTW& logFont)
0150 {
0151     const int verticalDPI_In = defaultVerticalDPI();
0152     QFont qFont(QString::fromWCharArray(logFont.lfFaceName));
0153     qFont.setItalic(logFont.lfItalic);
0154     if (logFont.lfWeight != FW_DONTCARE) {
0155         qFont.setWeight(weightFromInteger(logFont.lfWeight));
0156     }
0157     const qreal logFontHeight = qAbs(logFont.lfHeight);
0158     qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In));
0159     qFont.setUnderline(logFont.lfUnderline);
0160     qFont.setOverline(false);
0161     qFont.setStrikeOut(logFont.lfStrikeOut);
0162     return qFont;
0163 }
0164 
0165 // From qtbase/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
0166 static QFont windowsSystemUiFont()
0167 {
0168     // Qt 6: Obtain default GUI font (typically "Segoe UI, 9pt", see QTBUG-58610)
0169     NONCLIENTMETRICSW ncm;
0170     ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICSW, lfMessageFont) + sizeof(LOGFONTW);
0171     SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0);
0172     const QFont systemFont = LOGFONT_to_QFont(ncm.lfMessageFont);
0173     return systemFont;
0174 }
0175 #endif
0176 
0177 } // namespace KisUiFont