Better algorithm for font choosing

This commit is contained in:
ilya-fedin 2020-01-30 11:43:51 +04:00 committed by John Preston
parent 8d8d561127
commit 74889b8c21
8 changed files with 114 additions and 109 deletions

View file

@ -23,8 +23,6 @@ TextStyle {
lineHeight: pixels; lineHeight: pixels;
} }
semibold: "Open Sans Semibold";
fsize: 13px; fsize: 13px;
normalFont: font(fsize); normalFont: font(fsize);
semiboldFont: font(fsize semibold); semiboldFont: font(fsize semibold);

View file

@ -12,7 +12,6 @@
#include "styles/palette.h" #include "styles/palette.h"
#include <QtGui/QPainter> #include <QtGui/QPainter>
#include <QtGui/QFontDatabase>
#include <rpl/event_stream.h> #include <rpl/event_stream.h>
#include <rpl/variable.h> #include <rpl/variable.h>
@ -28,7 +27,6 @@ constexpr auto kContrastDeltaL = 64;
auto PaletteChanges = rpl::event_stream<>(); auto PaletteChanges = rpl::event_stream<>();
auto ShortAnimationRunning = rpl::variable<bool>(false); auto ShortAnimationRunning = rpl::variable<bool>(false);
auto RunningShortAnimations = 0; auto RunningShortAnimations = 0;
auto ResolvedMonospaceFont = style::font();
std::vector<internal::ModuleBase*> &StyleModules() { std::vector<internal::ModuleBase*> &StyleModules() {
static auto result = std::vector<internal::ModuleBase*>(); static auto result = std::vector<internal::ModuleBase*>();
@ -41,28 +39,6 @@ void startModules(int scale) {
} }
} }
void ResolveMonospaceFont() {
auto family = QString();
const auto tryFont = [&](const QString &attempt) {
if (family.isEmpty()
&& !QFontInfo(QFont(attempt)).family().trimmed().compare(
attempt,
Qt::CaseInsensitive)) {
family = attempt;
}
};
tryFont("Consolas");
tryFont("Liberation Mono");
tryFont("Menlo");
tryFont("Courier");
if (family.isEmpty()) {
const auto type = QFontDatabase::FixedFont;
family = QFontDatabase::systemFont(type).family();
}
const auto size = st::normalFont->f.pixelSize();
ResolvedMonospaceFont = style::font(size, 0, family);
}
} // namespace } // namespace
void registerModule(ModuleBase *module) { void registerModule(ModuleBase *module) {
@ -86,7 +62,6 @@ void StopShortAnimation() {
void startManager(int scale) { void startManager(int scale) {
internal::registerFontFamily("Open Sans"); internal::registerFontFamily("Open Sans");
internal::startModules(scale); internal::startModules(scale);
internal::ResolveMonospaceFont();
} }
void stopManager() { void stopManager() {
@ -106,10 +81,6 @@ rpl::producer<bool> ShortAnimationPlaying() {
return internal::ShortAnimationRunning.value(); return internal::ShortAnimationRunning.value();
} }
const style::font &MonospaceFont() {
return internal::ResolvedMonospaceFont;
}
void colorizeImage(const QImage &src, QColor c, QImage *outResult, QRect srcRect, QPoint dstPoint) { void colorizeImage(const QImage &src, QColor c, QImage *outResult, QRect srcRect, QPoint dstPoint) {
// In background_box ColorizePattern we use the fact that // In background_box ColorizePattern we use the fact that
// colorizeImage takes only first byte of the mask, so it // colorizeImage takes only first byte of the mask, so it

View file

@ -43,8 +43,6 @@ void NotifyPaletteChanged();
[[nodiscard]] rpl::producer<bool> ShortAnimationPlaying(); [[nodiscard]] rpl::producer<bool> ShortAnimationPlaying();
const style::font &MonospaceFont();
// *outResult must be r.width() x r.height(), ARGB32_Premultiplied. // *outResult must be r.width() x r.height(), ARGB32_Premultiplied.
// QRect(0, 0, src.width(), src.height()) must contain r. // QRect(0, 0, src.width(), src.height()) must contain r.
void colorizeImage(const QImage &src, QColor c, QImage *outResult, QRect srcRect = QRect(), QPoint dstPoint = QPoint(0, 0)); void colorizeImage(const QImage &src, QColor c, QImage *outResult, QRect srcRect = QRect(), QPoint dstPoint = QPoint(0, 0));

View file

@ -14,6 +14,7 @@
#include <QtCore/QVector> #include <QtCore/QVector>
#include <QtGui/QFontInfo> #include <QtGui/QFontInfo>
#include <QtGui/QFontDatabase> #include <QtGui/QFontDatabase>
#include <QtWidgets/QApplication>
void style_InitFontsResource() { void style_InitFontsResource() {
#ifndef DESKTOP_APP_USE_PACKAGED_FONTS #ifndef DESKTOP_APP_USE_PACKAGED_FONTS
@ -37,16 +38,14 @@ QVector<QString> fontFamilies;
QMap<uint32, FontData*> fontsMap; QMap<uint32, FontData*> fontsMap;
uint32 fontKey(int size, uint32 flags, int family) { uint32 fontKey(int size, uint32 flags, int family) {
return (((uint32(family) << 10) | uint32(size)) << 4) | flags; return (((uint32(family) << 12) | uint32(size)) << 6) | flags;
} }
bool ValidateFont(const QString &familyName, int flags = 0) { bool ValidateFont(const QString &familyName, int flags = 0) {
QFont checkFont(familyName); QFont checkFont(familyName);
checkFont.setPixelSize(13);
checkFont.setBold(flags & style::internal::FontBold); checkFont.setBold(flags & style::internal::FontBold);
checkFont.setItalic(flags & style::internal::FontItalic); checkFont.setItalic(flags & style::internal::FontItalic);
checkFont.setUnderline(flags & style::internal::FontUnderline); checkFont.setUnderline(flags & style::internal::FontUnderline);
checkFont.setStyleStrategy(QFont::PreferQuality);
auto realFamily = QFontInfo(checkFont).family(); auto realFamily = QFontInfo(checkFont).family();
if (realFamily.trimmed().compare(familyName, Qt::CaseInsensitive)) { if (realFamily.trimmed().compare(familyName, Qt::CaseInsensitive)) {
UI_LOG(("Font Error: could not resolve '%1' font, got '%2'.").arg(familyName).arg(realFamily)); UI_LOG(("Font Error: could not resolve '%1' font, got '%2'.").arg(familyName).arg(realFamily));
@ -86,6 +85,39 @@ bool LoadCustomFont(const QString &filePath, const QString &familyName, int flag
return ValidateFont(familyName, flags); return ValidateFont(familyName, flags);
} }
QString MonospaceFont() {
static const auto family = [&]() -> QString {
#ifdef Q_OS_WIN
const auto tryFont = [&](const QString &attempt) {
return !QFontInfo(QFont(attempt)).family().trimmed().compare(
attempt,
Qt::CaseInsensitive);
};
if (tryFont("Consolas")) {
return "Consolas";
}
if (tryFont("Liberation Mono")) {
return "Liberation Mono";
}
if (tryFont("Menlo")) {
return "Menlo";
}
if (tryFont("Courier")) {
return "Courier";
}
#endif // Q_OS_WIN
const auto type = QFontDatabase::FixedFont;
return QFontDatabase::systemFont(type).family();
}();
return family;
}
enum { enum {
FontTypeRegular = 0, FontTypeRegular = 0,
FontTypeRegularItalic, FontTypeRegularItalic,
@ -111,8 +143,8 @@ int32 FontTypeFlags[FontTypesCount] = {
FontItalic, FontItalic,
FontBold, FontBold,
FontBold | FontItalic, FontBold | FontItalic,
0, FontSemibold,
FontItalic, FontSemibold | FontItalic,
}; };
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QString FontTypeWindowsFallback[FontTypesCount] = { QString FontTypeWindowsFallback[FontTypesCount] = {
@ -168,7 +200,18 @@ void StartFonts() {
//QFont::insertSubstitution(name, fallback); //QFont::insertSubstitution(name, fallback);
#endif // Q_OS_WIN #endif // Q_OS_WIN
} }
#endif // !DESKTOP_APP_USE_PACKAGED_FONTS
#ifdef Q_OS_WIN
auto list = QStringList();
list.append("Microsoft YaHei");
list.append("Microsoft JhengHei UI");
list.append("Yu Gothic UI");
list.append("\xEB\xA7\x91\xEC\x9D\x80 \xEA\xB3\xA0\xEB\x94\x95");
for (const auto &name : FontTypeNames) {
QFont::insertSubstitutions(name, list);
}
#endif // Q_OS_WIN
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
auto list = QStringList(); auto list = QStringList();
list.append("STIXGeneral"); list.append("STIXGeneral");
@ -179,36 +222,44 @@ void StartFonts() {
QFont::insertSubstitutions(name, list); QFont::insertSubstitutions(name, list);
} }
#endif // Q_OS_MAC #endif // Q_OS_MAC
#endif // !DESKTOP_APP_USE_PACKAGED_FONTS
auto appFont = QFont(GetFontOverride());
appFont.setPixelSize(13);
appFont.setStyleStrategy(QFont::PreferQuality);
QApplication::setFont(appFont);
if (integrationExists) { if (integrationExists) {
Ui::Integration::Instance().startFontsEnd(); Ui::Integration::Instance().startFontsEnd();
} }
} }
QString GetPossibleEmptyOverride(const QString &familyName, int32 flags) { QString GetPossibleEmptyOverride(int32 flags) {
flags = flags & (FontBold | FontItalic); flags = flags & (FontBold | FontSemibold | FontItalic);
if (familyName == qstr("Open Sans")) { int32 flagsBold = flags & (FontBold | FontItalic);
if (flags == (FontBold | FontItalic)) { int32 flagsSemibold = flags & (FontSemibold | FontItalic);
return Overrides[FontTypeBoldItalic]; if (flagsSemibold == (FontSemibold | FontItalic)) {
} else if (flags == FontBold) { return Overrides[FontTypeSemiboldItalic];
return Overrides[FontTypeBold]; } else if (flagsSemibold == FontSemibold) {
} else if (flags == FontItalic) { return Overrides[FontTypeSemibold];
return Overrides[FontTypeRegularItalic]; } else if (flagsBold == (FontBold | FontItalic)) {
} else if (flags == 0) { return Overrides[FontTypeBoldItalic];
return Overrides[FontTypeRegular]; } else if (flagsBold == FontBold) {
} return Overrides[FontTypeBold];
} else if (familyName == qstr("Open Sans Semibold")) { } else if (flags == FontItalic) {
if (flags == FontItalic) { return Overrides[FontTypeRegularItalic];
return Overrides[FontTypeSemiboldItalic]; } else if (flags == 0) {
} else if (flags == 0) { return Overrides[FontTypeRegular];
return Overrides[FontTypeSemibold];
}
} }
return QString(); return QString();
} }
QString GetFontOverride(const QString &familyName, int32 flags) { QString GetFontOverride(int32 flags) {
const auto result = GetPossibleEmptyOverride(familyName, flags); const auto familyName = (flags & FontSemibold)
? "Open Sans Semibold"
: "Open Sans";
const auto result = GetPossibleEmptyOverride(flags);
return result.isEmpty() ? familyName : result; return result.isEmpty() ? familyName : result;
} }
@ -230,8 +281,7 @@ int registerFontFamily(const QString &family) {
} }
FontData::FontData(int size, uint32 flags, int family, Font *other) FontData::FontData(int size, uint32 flags, int family, Font *other)
: f(GetFontOverride(fontFamilies[family], flags)) : m(f)
, m(f)
, _size(size) , _size(size)
, _flags(flags) , _flags(flags)
, _family(family) { , _family(family) {
@ -242,18 +292,23 @@ FontData::FontData(int size, uint32 flags, int family, Font *other)
} }
modified[_flags] = Font(this); modified[_flags] = Font(this);
f.setPixelSize(size); if (_flags & FontMonospace) {
if (_flags & FontBold) { f.setFamily(MonospaceFont());
f.setBold(true); } else {
#ifdef DESKTOP_APP_USE_PACKAGED_FONTS f.setFamily(GetFontOverride(flags));
} else if (fontFamilies[family] == "Open Sans Semibold") {
f.setWeight(QFont::DemiBold);
#endif
} }
#ifdef DESKTOP_APP_USE_PACKAGED_FONTS
if (_flags & FontSemibold) {
f.setWeight(QFont::DemiBold);
}
#endif // DESKTOP_APP_USE_PACKAGED_FONTS
f.setPixelSize(size);
f.setBold(_flags & FontBold);
f.setItalic(_flags & FontItalic); f.setItalic(_flags & FontItalic);
f.setUnderline(_flags & FontUnderline); f.setUnderline(_flags & FontUnderline);
f.setStrikeOut(_flags & FontStrikeOut); f.setStrikeOut(_flags & FontStrikeOut);
f.setStyleStrategy(QFont::PreferQuality);
m = QFontMetrics(f); m = QFontMetrics(f);
height = m.height(); height = m.height();
@ -279,6 +334,14 @@ Font FontData::strikeout(bool set) const {
return otherFlagsFont(FontStrikeOut, set); return otherFlagsFont(FontStrikeOut, set);
} }
Font FontData::semibold(bool set) const {
return otherFlagsFont(FontSemibold, set);
}
Font FontData::monospace(bool set) const {
return otherFlagsFont(FontMonospace, set);
}
int FontData::size() const { int FontData::size() const {
return _size; return _size;
} }

View file

@ -15,7 +15,7 @@ namespace style {
namespace internal { namespace internal {
void StartFonts(); void StartFonts();
[[nodiscard]] QString GetFontOverride(const QString &familyName, int32 flags = 0); [[nodiscard]] QString GetFontOverride(int32 flags = 0);
void destroyFonts(); void destroyFonts();
int registerFontFamily(const QString &family); int registerFontFamily(const QString &family);
@ -59,8 +59,10 @@ enum FontFlags {
FontItalic = 0x02, FontItalic = 0x02,
FontUnderline = 0x04, FontUnderline = 0x04,
FontStrikeOut = 0x08, FontStrikeOut = 0x08,
FontSemibold = 0x10,
FontMonospace = 0x20,
FontDifferentFlags = 0x10, FontDifferentFlags = 0x40,
}; };
class FontData { class FontData {
@ -83,6 +85,8 @@ public:
Font italic(bool set = true) const; Font italic(bool set = true) const;
Font underline(bool set = true) const; Font underline(bool set = true) const;
Font strikeout(bool set = true) const; Font strikeout(bool set = true) const;
Font semibold(bool set = true) const;
Font monospace(bool set = true) const;
int size() const; int size() const;
uint32 flags() const; uint32 flags() const;

View file

@ -2014,24 +2014,18 @@ private:
} }
auto result = f; auto result = f;
if ((flags & TextBlockFPre) || (flags & TextBlockFCode)) { if ((flags & TextBlockFPre) || (flags & TextBlockFCode)) {
result = style::MonospaceFont(); result = result->monospace();
if (result->size() != f->size() || result->flags() != f->flags()) {
result = style::font(f->size(), f->flags(), result->family());
}
} else { } else {
if (flags & TextBlockFBold) { if (flags & TextBlockFBold) {
result = result->bold(); result = result->bold();
} else if (flags & TextBlockFSemibold) { } else if (flags & TextBlockFSemibold) {
result = st::semiboldFont; result = result->semibold();
if (result->size() != f->size() || result->flags() != f->flags()) {
result = style::font(f->size(), f->flags(), result->family());
}
} }
if (flags & TextBlockFItalic) result = result->italic(); if (flags & TextBlockFItalic) result = result->italic();
if (flags & TextBlockFUnderline) result = result->underline(); if (flags & TextBlockFUnderline) result = result->underline();
if (flags & TextBlockFStrikeOut) result = result->strikeout(); if (flags & TextBlockFStrikeOut) result = result->strikeout();
if (flags & TextBlockFTilde) { // tilde fix in OpenSans if (flags & TextBlockFTilde) { // tilde fix in OpenSans
result = st::semiboldFont; result = result->semibold();
} }
} }
return result; return result;

View file

@ -322,24 +322,18 @@ TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResi
} }
if ((flags & TextBlockFPre) || (flags & TextBlockFCode)) { if ((flags & TextBlockFPre) || (flags & TextBlockFCode)) {
blockFont = style::MonospaceFont(); blockFont = blockFont->monospace();
if (blockFont->size() != font->size() || blockFont->flags() != font->flags()) {
blockFont = style::font(font->size(), font->flags(), blockFont->family());
}
} else { } else {
if (flags & TextBlockFBold) { if (flags & TextBlockFBold) {
blockFont = blockFont->bold(); blockFont = blockFont->bold();
} else if (flags & TextBlockFSemibold) { } else if (flags & TextBlockFSemibold) {
blockFont = st::semiboldFont; blockFont = blockFont->semibold();
if (blockFont->size() != font->size() || blockFont->flags() != font->flags()) {
blockFont = style::font(font->size(), font->flags(), blockFont->family());
}
} }
if (flags & TextBlockFItalic) blockFont = blockFont->italic(); if (flags & TextBlockFItalic) blockFont = blockFont->italic();
if (flags & TextBlockFUnderline) blockFont = blockFont->underline(); if (flags & TextBlockFUnderline) blockFont = blockFont->underline();
if (flags & TextBlockFStrikeOut) blockFont = blockFont->strikeout(); if (flags & TextBlockFStrikeOut) blockFont = blockFont->strikeout();
if (flags & TextBlockFTilde) { // tilde fix in OpenSans if (flags & TextBlockFTilde) { // tilde fix in OpenSans
blockFont = st::semiboldFont; blockFont = blockFont->semibold();
} }
} }

View file

@ -651,15 +651,6 @@ void RemoveDocumentTags(
cursor.mergeCharFormat(format); cursor.mergeCharFormat(format);
} }
style::font AdjustFont(
const style::font &font,
const style::font &original) {
return (font->size() != original->size()
|| font->flags() != original->flags())
? style::font(original->size(), original->flags(), font->family())
: font;
}
bool IsValidMarkdownLink(const QString &link) { bool IsValidMarkdownLink(const QString &link) {
return (link.indexOf('.') >= 0) || (link.indexOf(':') >= 0); return (link.indexOf('.') >= 0) || (link.indexOf(':') >= 0);
} }
@ -672,16 +663,8 @@ QTextCharFormat PrepareTagFormat(
result.setForeground(st::defaultTextPalette.linkFg); result.setForeground(st::defaultTextPalette.linkFg);
result.setFont(st.font); result.setFont(st.font);
} else if (tag == kTagBold) { } else if (tag == kTagBold) {
auto semibold = st::semiboldFont;
if (semibold->size() != st.font->size()
|| semibold->flags() != st.font->flags()) {
semibold = style::font(
st.font->size(),
st.font->flags(),
semibold->family());
}
result.setForeground(st.textFg); result.setForeground(st.textFg);
result.setFont(AdjustFont(st::semiboldFont, st.font)); result.setFont(st.font->semibold());
} else if (tag == kTagItalic) { } else if (tag == kTagItalic) {
result.setForeground(st.textFg); result.setForeground(st.textFg);
result.setFont(st.font->italic()); result.setFont(st.font->italic());
@ -693,7 +676,7 @@ QTextCharFormat PrepareTagFormat(
result.setFont(st.font->strikeout()); result.setFont(st.font->strikeout());
} else if (tag == kTagCode || tag == kTagPre) { } else if (tag == kTagCode || tag == kTagPre) {
result.setForeground(st::defaultTextPalette.monoFg); result.setForeground(st::defaultTextPalette.monoFg);
result.setFont(AdjustFont(style::MonospaceFont(), st.font)); result.setFont(st.font->monospace());
} else { } else {
result.setForeground(st.textFg); result.setForeground(st.textFg);
result.setFont(st.font); result.setFont(st.font);
@ -1985,7 +1968,7 @@ void InputField::processFormatting(int insertPosition, int insertEnd) {
const auto tildeFormatting = (_st.font->f.pixelSize() * style::DevicePixelRatio() == 13) const auto tildeFormatting = (_st.font->f.pixelSize() * style::DevicePixelRatio() == 13)
&& (_st.font->f.family() == qstr("DAOpenSansRegular")); && (_st.font->f.family() == qstr("DAOpenSansRegular"));
auto isTildeFragment = false; auto isTildeFragment = false;
const auto tildeFixedFont = AdjustFont(st::semiboldFont, _st.font); const auto tildeFixedFont = _st.font->semibold();
// First tag handling (the one we inserted text to). // First tag handling (the one we inserted text to).
bool startTagFound = false; bool startTagFound = false;