[Option][GUI] Font options

This commit is contained in:
Eric Kotato 2022-09-15 23:17:03 +03:00 committed by Eric Kotato
parent 0a4b33820c
commit ffa047754d
8 changed files with 163 additions and 47 deletions

View file

@ -6,6 +6,7 @@
// //
#include "ui/integration.h" #include "ui/integration.h"
#include "ui/style/style_core_custom_font.h"
#include "ui/gl/gl_detection.h" #include "ui/gl/gl_detection.h"
#include "ui/text/text_entity.h" #include "ui/text/text_entity.h"
#include "ui/text/text_block.h" #include "ui/text/text_block.h"
@ -43,6 +44,10 @@ void Integration::textActionsUpdated() {
void Integration::activationFromTopPanel() { void Integration::activationFromTopPanel() {
} }
style::CustomFontSettings Integration::fontSettings() {
return {};
}
bool Integration::screenIsLocked() { bool Integration::screenIsLocked() {
return false; return false;
} }

View file

@ -22,6 +22,10 @@ struct TextParseOptions;
class ClickHandler; class ClickHandler;
struct EntityLinkData; struct EntityLinkData;
namespace style {
struct CustomFontSettings;
} // namespace style
namespace Ui { namespace Ui {
namespace Emoji { namespace Emoji {
class One; class One;
@ -48,6 +52,8 @@ public:
virtual void textActionsUpdated(); virtual void textActionsUpdated();
virtual void activationFromTopPanel(); virtual void activationFromTopPanel();
virtual style::CustomFontSettings fontSettings();
[[nodiscard]] virtual bool screenIsLocked(); [[nodiscard]] virtual bool screenIsLocked();
[[nodiscard]] virtual std::shared_ptr<ClickHandler> createLinkHandler( [[nodiscard]] virtual std::shared_ptr<ClickHandler> createLinkHandler(

View file

@ -22,13 +22,15 @@ public:
void drawTextLeft(int x, int y, int outerw, const QString &text, int textWidth = -1) { void drawTextLeft(int x, int y, int outerw, const QString &text, int textWidth = -1) {
QFontMetrics m(fontMetrics()); QFontMetrics m(fontMetrics());
auto ascent = (_ascent == 0 ? m.ascent() : _ascent);
if (style::RightToLeft() && textWidth < 0) textWidth = m.horizontalAdvance(text); if (style::RightToLeft() && textWidth < 0) textWidth = m.horizontalAdvance(text);
drawText(style::RightToLeft() ? (outerw - x - textWidth) : x, y + m.ascent(), text); drawText(style::RightToLeft() ? (outerw - x - textWidth) : x, y + ascent, text);
} }
void drawTextRight(int x, int y, int outerw, const QString &text, int textWidth = -1) { void drawTextRight(int x, int y, int outerw, const QString &text, int textWidth = -1) {
QFontMetrics m(fontMetrics()); QFontMetrics m(fontMetrics());
auto ascent = (_ascent == 0 ? m.ascent() : _ascent);
if (!style::RightToLeft() && textWidth < 0) textWidth = m.horizontalAdvance(text); if (!style::RightToLeft() && textWidth < 0) textWidth = m.horizontalAdvance(text);
drawText(style::RightToLeft() ? x : (outerw - x - textWidth), y + m.ascent(), text); drawText(style::RightToLeft() ? x : (outerw - x - textWidth), y + ascent, text);
} }
void drawPixmapLeft(int x, int y, int outerw, const QPixmap &pix, const QRect &from) { void drawPixmapLeft(int x, int y, int outerw, const QPixmap &pix, const QRect &from) {
drawPixmap(QPoint(style::RightToLeft() ? (outerw - x - (from.width() / pix.devicePixelRatio())) : x, y), pix, from); drawPixmap(QPoint(style::RightToLeft() ? (outerw - x - (from.width() / pix.devicePixelRatio())) : x, y), pix, from);
@ -82,6 +84,10 @@ public:
[[nodiscard]] bool inactive() const { [[nodiscard]] bool inactive() const {
return _inactive; return _inactive;
} }
void setFont(const style::font &font) {
_ascent = font->ascent;
QPainter::setFont(font->f);
}
void setTextSpoilerMess(not_null<Ui::Text::SpoilerMess*> mess) { void setTextSpoilerMess(not_null<Ui::Text::SpoilerMess*> mess) {
_spoilerMess = mess; _spoilerMess = mess;
} }
@ -96,6 +102,7 @@ private:
const style::TextPalette *_textPalette = nullptr; const style::TextPalette *_textPalette = nullptr;
Ui::Text::SpoilerMess *_spoilerMess = nullptr; Ui::Text::SpoilerMess *_spoilerMess = nullptr;
bool _inactive = false; bool _inactive = false;
int _ascent = 0;
}; };

View file

@ -7,6 +7,8 @@
#include "ui/style/style_core_custom_font.h" #include "ui/style/style_core_custom_font.h"
#include "ui/style/style_core_font.h" #include "ui/style/style_core_font.h"
#include "ui/style/style_core_scale.h"
#include "ui/integration.h"
#include <QGuiApplication> #include <QGuiApplication>
#include <QFontDatabase> #include <QFontDatabase>
@ -29,6 +31,9 @@ void SetCustomFonts(const CustomFont &regular, const CustomFont &bold) {
QFont ResolveFont(const QString &familyOverride, uint32 flags, int size) { QFont ResolveFont(const QString &familyOverride, uint32 flags, int size) {
static auto Database = QFontDatabase(); static auto Database = QFontDatabase();
const auto fontSettings = Ui::Integration::Instance().fontSettings();
const auto overrideIsEmpty = GetPossibleEmptyOverride(flags).isEmpty();
const auto bold = ((flags & FontBold) || (flags & FontSemibold)); const auto bold = ((flags & FontBold) || (flags & FontSemibold));
const auto italic = (flags & FontItalic); const auto italic = (flags & FontItalic);
const auto &custom = bold ? BoldFont : RegularFont; const auto &custom = bold ? BoldFont : RegularFont;
@ -50,18 +55,29 @@ QFont ResolveFont(const QString &familyOverride, uint32 flags, int size) {
const auto point = good.isEmpty() ? size : good.front(); const auto point = good.isEmpty() ? size : good.front();
result = Database.font(custom.family, custom.style, point); result = Database.font(custom.family, custom.style, point);
} else { } else {
result.setFamily(GetFontOverride(flags)); if (!fontSettings.useSystemFont || !overrideIsEmpty) {
result.setFamily(GetFontOverride(flags));
}
if (bold) { if (bold) {
if (fontSettings.semiboldIsBold) {
result.setBold(true);
#ifdef DESKTOP_APP_USE_PACKAGED_FONTS #ifdef DESKTOP_APP_USE_PACKAGED_FONTS
result.setWeight(QFont::DemiBold);
#else // DESKTOP_APP_USE_PACKAGED_FONTS
result.setBold(true);
#endif // !DESKTOP_APP_USE_PACKAGED_FONTS
if (flags & FontItalic) {
result.setStyleName("Semibold Italic");
} else { } else {
result.setStyleName("Semibold"); result.setWeight(QFont::DemiBold);
#else // DESKTOP_APP_USE_PACKAGED_FONTS
} else if (fontSettings.useSystemFont) {
result.setWeight(QFont::DemiBold);
} else {
result.setBold(true);
#endif // !DESKTOP_APP_USE_PACKAGED_FONTS
}
if (!fontSettings.semiboldIsBold) {
if (flags & FontItalic) {
result.setStyleName("Semibold Italic");
} else {
result.setStyleName("Semibold");
}
} }
} }
} }
@ -71,7 +87,7 @@ QFont ResolveFont(const QString &familyOverride, uint32 flags, int size) {
result.setUnderline(flags & FontUnderline); result.setUnderline(flags & FontUnderline);
result.setStrikeOut(flags & FontStrikeOut); result.setStrikeOut(flags & FontStrikeOut);
result.setPixelSize(size); result.setPixelSize(size + ConvertScale(fontSettings.fontSize));
return result; return result;
} }

View file

@ -13,6 +13,16 @@ struct CustomFont {
QString style; QString style;
}; };
struct CustomFontSettings {
QString mainFont;
QString semiboldFont;
QString monospaceFont;
int fontSize = 0;
bool semiboldIsBold = false;
bool useSystemFont = false;
bool useOriginalMetrics = false;
};
inline bool operator==(const CustomFont &a, const CustomFont &b) { inline bool operator==(const CustomFont &a, const CustomFont &b) {
return (a.family == b.family) && (a.style == b.style); return (a.family == b.family) && (a.style == b.style);
} }

View file

@ -96,6 +96,11 @@ bool LoadCustomFont(const QString &filePath, const QString &familyName, int flag
return QFontDatabase::systemFont(type).family(); return QFontDatabase::systemFont(type).family();
} }
bool TryFont(const QString &attempt) {
const auto resolved = QFontInfo(QFont(attempt)).family();
return !resolved.trimmed().compare(attempt, Qt::CaseInsensitive);
}
[[nodiscard]] QString ManualMonospaceFont() { [[nodiscard]] QString ManualMonospaceFont() {
const auto kTryFirst = std::initializer_list<QString>{ const auto kTryFirst = std::initializer_list<QString>{
"Cascadia Mono", "Cascadia Mono",
@ -105,14 +110,23 @@ bool LoadCustomFont(const QString &filePath, const QString &familyName, int flag
"Courier" "Courier"
}; };
for (const auto &family : kTryFirst) { for (const auto &family : kTryFirst) {
const auto resolved = QFontInfo(QFont(family)).family(); if (TryFont(family)) {
if (!resolved.trimmed().compare(family, Qt::CaseInsensitive)) {
return family; return family;
} }
} }
return QString(); return QString();
} }
QFontMetrics GetFontMetrics(int size) {
#ifdef DESKTOP_APP_USE_PACKAGED_FONTS
QFont originalFont("Open Sans");
#else // !DESKTOP_APP_USE_PACKAGED_FONTS
QFont originalFont("DAOpenSansRegular");
#endif // !DESKTOP_APP_USE_PACKAGED_FONTS
originalFont.setPixelSize(size);
return QFontMetrics(originalFont);
}
enum { enum {
FontTypeRegular = 0, FontTypeRegular = 0,
FontTypeRegularItalic, FontTypeRegularItalic,
@ -179,52 +193,72 @@ void StartFonts() {
style_InitFontsResource(); style_InitFontsResource();
const auto fontSettings = Ui::Integration::Instance().fontSettings();
#ifndef DESKTOP_APP_USE_PACKAGED_FONTS #ifndef DESKTOP_APP_USE_PACKAGED_FONTS
[[maybe_unused]] bool areGood[FontTypesCount] = { false }; if (!fontSettings.useSystemFont) {
for (auto i = 0; i != FontTypesCount; ++i) { [[maybe_unused]] bool areGood[FontTypesCount] = { false };
const auto file = FontTypeFiles[i]; for (auto i = 0; i != FontTypesCount; ++i) {
const auto name = FontTypeNames[i]; const auto file = FontTypeFiles[i];
const auto flags = FontTypeFlags[i]; const auto name = FontTypeNames[i];
areGood[i] = LoadCustomFont(":/gui/fonts/" + file + ".ttf", name, flags); const auto flags = FontTypeFlags[i];
Overrides[i] = name; areGood[i] = LoadCustomFont(":/gui/fonts/" + file + ".ttf", name, flags);
Overrides[i] = name;
const auto persianFallbackFile = FontTypePersianFallbackFiles[i]; const auto persianFallbackFile = FontTypePersianFallbackFiles[i];
const auto persianFallback = FontTypePersianFallback[i]; const auto persianFallback = FontTypePersianFallback[i];
LoadCustomFont(":/gui/fonts/" + persianFallbackFile + ".ttf", persianFallback, flags); LoadCustomFont(":/gui/fonts/" + persianFallbackFile + ".ttf", persianFallback, flags);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
// Attempt to workaround a strange font bug with Open Sans Semibold not loading. // Attempt to workaround a strange font bug with Open Sans Semibold not loading.
// See https://github.com/telegramdesktop/tdesktop/issues/3276 for details. // See https://github.com/telegramdesktop/tdesktop/issues/3276 for details.
// Crash happens on "options.maxh / _t->_st->font->height" with "division by zero". // Crash happens on "options.maxh / _t->_st->font->height" with "division by zero".
// In that place "_t->_st->font" is "semiboldFont" is "font(13 "Open Sans Semibold"). // In that place "_t->_st->font" is "semiboldFont" is "font(13 "Open Sans Semibold").
const auto fallback = "Segoe UI"; const auto fallback = "Segoe UI";
if (!areGood[i]) { if (!areGood[i]) {
if (ValidateFont(fallback, flags)) { if (ValidateFont(fallback, flags)) {
Overrides[i] = fallback; Overrides[i] = fallback;
LOG(("Fonts Info: Using '%1' instead of '%2'.").arg(fallback).arg(name)); LOG(("Fonts Info: Using '%1' instead of '%2'.").arg(fallback).arg(name));
}
} }
} // Disable default fallbacks to Segoe UI, see:
// Disable default fallbacks to Segoe UI, see: // https://github.com/telegramdesktop/tdesktop/issues/5368
// https://github.com/telegramdesktop/tdesktop/issues/5368 //
// //QFont::insertSubstitution(name, fallback);
//QFont::insertSubstitution(name, fallback);
#endif // Q_OS_WIN #endif // Q_OS_WIN
QFont::insertSubstitution(name, persianFallback); QFont::insertSubstitution(name, persianFallback);
} }
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
auto list = QStringList(); auto list = QStringList();
list.append("STIXGeneral"); list.append("STIXGeneral");
list.append(".SF NS Text"); list.append(".SF NS Text");
list.append("Helvetica Neue"); list.append("Helvetica Neue");
list.append("Lucida Grande"); list.append("Lucida Grande");
for (const auto &name : FontTypeNames) { for (const auto &name : FontTypeNames) {
QFont::insertSubstitutions(name, list); QFont::insertSubstitutions(name, list);
} }
#endif // Q_OS_MAC #endif // Q_OS_MAC
}
#endif // !DESKTOP_APP_USE_PACKAGED_FONTS #endif // !DESKTOP_APP_USE_PACKAGED_FONTS
if (!fontSettings.mainFont.isEmpty() && ValidateFont(fontSettings.mainFont)) {
Overrides[FontTypeRegular] = fontSettings.mainFont;
Overrides[FontTypeRegularItalic] = fontSettings.mainFont;
}
if (!fontSettings.semiboldFont.isEmpty() && ValidateFont(fontSettings.semiboldFont)) {
Overrides[FontTypeBold] = fontSettings.semiboldFont;
Overrides[FontTypeBoldItalic] = fontSettings.semiboldFont;
Overrides[FontTypeSemibold] = fontSettings.semiboldFont;
Overrides[FontTypeSemiboldItalic] = fontSettings.semiboldFont;
} else if (!fontSettings.mainFont.isEmpty() && ValidateFont(fontSettings.mainFont)) {
Overrides[FontTypeBold] = fontSettings.mainFont;
Overrides[FontTypeBoldItalic] = fontSettings.mainFont;
Overrides[FontTypeSemibold] = fontSettings.mainFont;
Overrides[FontTypeSemiboldItalic] = fontSettings.mainFont;
}
auto appFont = QApplication::font(); auto appFont = QApplication::font();
appFont.setStyleStrategy(QFont::PreferQuality); appFont.setStyleStrategy(QFont::PreferQuality);
QApplication::setFont(appFont); QApplication::setFont(appFont);
@ -257,6 +291,12 @@ QString GetFontOverride(int32 flags) {
QString MonospaceFont() { QString MonospaceFont() {
static const auto family = [&]() -> QString { static const auto family = [&]() -> QString {
const auto fontSettings = Ui::Integration::Instance().fontSettings();
if (TryFont(fontSettings.monospaceFont)) {
return fontSettings.monospaceFont;
}
const auto manual = ManualMonospaceFont(); const auto manual = ManualMonospaceFont();
const auto system = SystemMonospaceFont(); const auto system = SystemMonospaceFont();
@ -269,7 +309,7 @@ QString MonospaceFont() {
const auto useSystem = manual.isEmpty() const auto useSystem = manual.isEmpty()
|| (metrics.horizontalAdvance(QChar('i')) == metrics.horizontalAdvance(QChar('W'))); || (metrics.horizontalAdvance(QChar('i')) == metrics.horizontalAdvance(QChar('W')));
#endif // Q_OS_WIN #endif // Q_OS_WIN
return useSystem ? system : manual; return (useSystem || fontSettings.useSystemFont) ? system : manual;
}(); }();
return family; return family;
@ -303,9 +343,19 @@ FontData::FontData(int size, uint32 flags, int family, Font *other)
} }
_modified[_flags] = Font(this); _modified[_flags] = Font(this);
height = int(base::SafeRound(_m.height())); const auto fontSettings = Ui::Integration::Instance().fontSettings();
ascent = int(base::SafeRound(_m.ascent())); if (fontSettings.useOriginalMetrics && !(_flags & FontMonospace)) {
descent = int(base::SafeRound(_m.descent())); const auto mOrig = GetFontMetrics(size);
height = int(base::SafeRound(mOrig.height()));
ascent = int(base::SafeRound(mOrig.ascent()));
descent = int(base::SafeRound(mOrig.descent()));
} else {
height = int(base::SafeRound(_m.height()));
ascent = int(base::SafeRound(_m.ascent()));
descent = int(base::SafeRound(_m.descent()));
}
spacew = width(QLatin1Char(' ')); spacew = width(QLatin1Char(' '));
elidew = width("..."); elidew = width("...");
} }

View file

@ -17,6 +17,7 @@ namespace style {
namespace internal { namespace internal {
void StartFonts(); void StartFonts();
[[nodiscard]] QString GetPossibleEmptyOverride(int32 flags = 0);
[[nodiscard]] QString GetFontOverride(int32 flags = 0); [[nodiscard]] QString GetFontOverride(int32 flags = 0);
[[nodiscard]] QString MonospaceFont(); [[nodiscard]] QString MonospaceFont();

View file

@ -11,6 +11,7 @@
#include "ui/emoji_config.h" #include "ui/emoji_config.h"
#include "ui/ui_utility.h" #include "ui/ui_utility.h"
#include "ui/painter.h" #include "ui/painter.h"
#include "ui/style/style_core_custom_font.h"
#include "base/invoke_queued.h" #include "base/invoke_queued.h"
#include "base/random.h" #include "base/random.h"
#include "base/platform/base_platform_info.h" #include "base/platform/base_platform_info.h"
@ -1233,6 +1234,14 @@ InputField::InputField(
_inner->viewport()->setAutoFillBackground(false); _inner->viewport()->setAutoFillBackground(false);
_inner->setContentsMargins(0, 0, 0, 0); _inner->setContentsMargins(0, 0, 0, 0);
const auto fontSettings = Integration::Instance().fontSettings();
if (fontSettings.useOriginalMetrics) {
const auto metrics = QFontMetricsF(_st.font->f);
const auto heightDelta = (_st.font->height - metrics.height());
const auto topMargin = (_st.font->ascent - metrics.ascent())
+ (heightDelta ? heightDelta / 2 : 0);
_inner->setViewportMargins(0, topMargin, 0, 0);
}
_inner->document()->setDocumentMargin(0); _inner->document()->setDocumentMargin(0);
setAttribute(Qt::WA_AcceptTouchEvents); setAttribute(Qt::WA_AcceptTouchEvents);
@ -1742,6 +1751,18 @@ void InputField::paintEvent(QPaintEvent *e) {
auto r = rect().marginsRemoved(_st.textMargins + _st.placeholderMargins); auto r = rect().marginsRemoved(_st.textMargins + _st.placeholderMargins);
r.moveLeft(r.left() + placeholderLeft); r.moveLeft(r.left() + placeholderLeft);
if (style::RightToLeft()) r.moveLeft(width() - r.left() - r.width()); if (style::RightToLeft()) r.moveLeft(width() - r.left() - r.width());
const auto fontSettings = Integration::Instance().fontSettings();
if (fontSettings.useOriginalMetrics) {
const auto metrics = QFontMetricsF(_st.placeholderFont->f);
if (_mode == Mode::SingleLine) {
const auto heightDelta = (_st.placeholderFont->height - metrics.height());
const auto topMargin = (_st.placeholderFont->ascent - metrics.ascent())
+ (heightDelta ? heightDelta / 2 : 0);
r.moveTop(r.top() + topMargin);
} else {
r.moveTop(r.top() + _st.placeholderFont->ascent - metrics.ascent());
}
}
p.drawText(r, _placeholder, _st.placeholderAlign); p.drawText(r, _placeholder, _st.placeholderAlign);
} }