Load and use Segoe UI [Semibold] if no Open Sans.

Sometimes Open Sans Semibold fails to load properly on the latest
Windows Creators Update. In that case try to load Segoe UI instead.

An attempt to fix #3276.
This commit is contained in:
John Preston 2017-04-30 19:03:12 +03:00
parent 6418c9c718
commit 297856db32
7 changed files with 133 additions and 40 deletions

View File

@ -1043,7 +1043,7 @@ MainWindow::~MainWindow() {
PreLaunchWindow *PreLaunchWindowInstance = 0;
PreLaunchWindow::PreLaunchWindow(QString title) : TWidget(0) {
Fonts::start();
Fonts::Start();
QIcon icon(App::pixmapFromImageInPlace(QImage(cPlatform() == dbipMac ? qsl(":/gui/art/iconbig256.png") : qsl(":/gui/art/icon256.png"))));
if (cPlatform() == dbipLinux32 || cPlatform() == dbipLinux64) {
@ -1090,7 +1090,7 @@ PreLaunchWindow::~PreLaunchWindow() {
PreLaunchLabel::PreLaunchLabel(QWidget *parent) : QLabel(parent) {
QFont labelFont(font());
labelFont.setFamily(qsl("Open Sans Semibold"));
labelFont.setFamily(Fonts::GetOverride(qsl("Open Sans Semibold")));
labelFont.setPixelSize(static_cast<PreLaunchWindow*>(parent)->basicSize());
setFont(labelFont);
@ -1108,7 +1108,7 @@ void PreLaunchLabel::setText(const QString &text) {
PreLaunchInput::PreLaunchInput(QWidget *parent, bool password) : QLineEdit(parent) {
QFont logFont(font());
logFont.setFamily(qsl("Open Sans"));
logFont.setFamily(Fonts::GetOverride(qsl("Open Sans")));
logFont.setPixelSize(static_cast<PreLaunchWindow*>(parent)->basicSize());
setFont(logFont);
@ -1126,7 +1126,7 @@ PreLaunchInput::PreLaunchInput(QWidget *parent, bool password) : QLineEdit(paren
PreLaunchLog::PreLaunchLog(QWidget *parent) : QTextEdit(parent) {
QFont logFont(font());
logFont.setFamily(qsl("Open Sans"));
logFont.setFamily(Fonts::GetOverride(qsl("Open Sans")));
logFont.setPixelSize(static_cast<PreLaunchWindow*>(parent)->basicSize());
setFont(logFont);
@ -1148,7 +1148,7 @@ PreLaunchButton::PreLaunchButton(QWidget *parent, bool confirm) : QPushButton(pa
setObjectName(confirm ? "confirm" : "cancel");
QFont closeFont(font());
closeFont.setFamily(qsl("Open Sans Semibold"));
closeFont.setFamily(Fonts::GetOverride(qsl("Open Sans Semibold")));
closeFont.setPixelSize(static_cast<PreLaunchWindow*>(parent)->basicSize());
setFont(closeFont);
@ -1167,7 +1167,7 @@ PreLaunchCheckbox::PreLaunchCheckbox(QWidget *parent) : QCheckBox(parent) {
setCheckState(Qt::Checked);
QFont closeFont(font());
closeFont.setFamily(qsl("Open Sans Semibold"));
closeFont.setFamily(Fonts::GetOverride(qsl("Open Sans Semibold")));
closeFont.setPixelSize(static_cast<PreLaunchWindow*>(parent)->basicSize());
setFont(closeFont);

View File

@ -62,7 +62,7 @@ Messenger::Messenger() : QObject()
t_assert(SingleInstance == nullptr);
SingleInstance = this;
Fonts::start();
Fonts::Start();
ThirdParty::start();
Global::start();

View File

@ -56,7 +56,12 @@ int registerFontFamily(const QString &family) {
return result;
}
FontData::FontData(int size, uint32 flags, int family, Font *other) : f(fontFamilies[family]), m(f), _size(size), _flags(flags), _family(family) {
FontData::FontData(int size, uint32 flags, int family, Font *other)
: f(Fonts::GetOverride(fontFamilies[family]))
, m(f)
, _size(size)
, _flags(flags)
, _family(family) {
if (other) {
memcpy(modified, other, sizeof(modified));
} else {

View File

@ -567,7 +567,7 @@ public:
ch = emojiLookback = 0;
lastSkipped = false;
checkTilde = !cRetina() && _t->_st->font->size() == 13 && _t->_st->font->flags() == 0; // tilde Open Sans fix
checkTilde = !cRetina() && (_t->_st->font->size() == 13) && (_t->_st->font->flags() == 0) && (_t->_st->font->f.family() == qstr("Open Sans")); // tilde Open Sans fix
for (; ptr <= end; ++ptr) {
while (checkEntities() || (rich && checkCommand())) {
}

View File

@ -22,16 +22,96 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "mainwindow.h"
namespace Fonts {
namespace {
bool ValidateFont(const QString &familyName, int flags = 0) {
QFont checkFont(familyName);
checkFont.setPixelSize(13);
checkFont.setBold(flags & style::internal::FontBold);
checkFont.setItalic(flags & style::internal::FontItalic);
checkFont.setUnderline(flags & style::internal::FontUnderline);
checkFont.setStyleStrategy(QFont::PreferQuality);
auto realFamily = QFontInfo(checkFont).family();
if (realFamily.trimmed().compare(familyName, Qt::CaseInsensitive)) {
LOG(("Font Error: could not resolve '%1' font, got '%2' after feeding '%3'.").arg(familyName).arg(realFamily));
return false;
}
auto metrics = QFontMetrics(checkFont);
if (!metrics.height()) {
LOG(("Font Error: got a zero height in '%1'.").arg(familyName));
return false;
}
return true;
}
bool LoadCustomFont(const QString &filePath, const QString &familyName, int flags = 0) {
auto regularId = QFontDatabase::addApplicationFont(filePath);
if (regularId < 0) {
LOG(("Font Error: could not add '%1'.").arg(filePath));
return false;
}
auto found = [&familyName, regularId] {
for (auto &family : QFontDatabase::applicationFontFamilies(regularId)) {
if (!family.trimmed().compare(familyName, Qt::CaseInsensitive)) {
return true;
}
}
return false;
};
if (!found()) {
LOG(("Font Error: could not locate '%1' font in '%2'.").arg(familyName).arg(filePath));
return false;
}
return ValidateFont(familyName, flags);
}
bool Started = false;
void start() {
if (!Started) {
Started = true;
QString OpenSansOverride;
QString OpenSansSemiboldOverride;
QFontDatabase::addApplicationFont(qsl(":/gui/fonts/OpenSans-Regular.ttf"));
QFontDatabase::addApplicationFont(qsl(":/gui/fonts/OpenSans-Bold.ttf"));
QFontDatabase::addApplicationFont(qsl(":/gui/fonts/OpenSans-Semibold.ttf"));
} // namespace
void Start() {
if (Started) {
return;
}
Started = true;
auto regular = LoadCustomFont(qsl(":/gui/fonts/OpenSans-Regular.ttf"), qsl("Open Sans"));
auto bold = LoadCustomFont(qsl(":/gui/fonts/OpenSans-Bold.ttf"), qsl("Open Sans"), style::internal::FontBold);
auto semibold = LoadCustomFont(qsl(":/gui/fonts/OpenSans-Semibold.ttf"), qsl("Open Sans Semibold"));
#ifdef Q_OS_WIN
// Attempt to workaround a strange font bug with Open Sans Semibold not loading.
// See https://github.com/telegramdesktop/tdesktop/issues/3276 for details.
// 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").
if (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS10) {
if (!regular || !bold) {
if (ValidateFont(qsl("Segoe UI")) && ValidateFont(qsl("Segoe UI"), style::internal::FontBold)) {
OpenSansOverride = qsl("Segoe UI");
}
}
if (!semibold) {
if (ValidateFont(qsl("Segoe UI Semibold"))) {
OpenSansSemiboldOverride = qsl("Segoe UI Semibold");
}
}
}
#endif // Q_OS_WIN
}
QString GetOverride(const QString &familyName) {
if (familyName == qstr("Open Sans")) {
return OpenSansOverride.isEmpty() ? familyName : OpenSansOverride;
} else if (familyName == qstr("Open Sans Semibold")) {
return OpenSansSemiboldOverride.isEmpty() ? familyName : OpenSansSemiboldOverride;
}
return familyName;
}
} // Fonts

View File

@ -21,8 +21,11 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#pragma once
namespace Fonts {
void start();
}
void Start();
QString GetOverride(const QString &familyName);
} // namespace
class Painter : public QPainter {
public:

View File

@ -1079,9 +1079,10 @@ struct FormattingAction {
void FlatTextarea::processFormatting(int insertPosition, int insertEnd) {
// Tilde formatting.
auto regularFont = qsl("Open Sans"), semiboldFont = qsl("Open Sans Semibold");
bool tildeFormatting = !cRetina() && (font().pixelSize() == 13) && (font().family() == regularFont);
bool isTildeFragment = false;
auto tildeFormatting = !cRetina() && (font().pixelSize() == 13) && (font().family() == qstr("Open Sans"));
auto isTildeFragment = false;
auto tildeRegularFont = tildeFormatting ? qsl("Open Sans") : QString();
auto tildeFixedFont = tildeFormatting ? Fonts::GetOverride(qsl("Open Sans Semibold")) : QString();
// First tag handling (the one we inserted text to).
bool startTagFound = false;
@ -1118,7 +1119,7 @@ void FlatTextarea::processFormatting(int insertPosition, int insertEnd) {
auto charFormat = fragment.charFormat();
if (tildeFormatting) {
isTildeFragment = (charFormat.fontFamily() == semiboldFont);
isTildeFragment = (charFormat.fontFamily() == tildeFixedFont);
}
auto fragmentText = fragment.text();
@ -1202,7 +1203,7 @@ void FlatTextarea::processFormatting(int insertPosition, int insertEnd) {
c.mergeCharFormat(format);
} else if (action.type == ActionType::TildeFont) {
QTextCharFormat format;
format.setFontFamily(action.isTilde ? semiboldFont : regularFont);
format.setFontFamily(action.isTilde ? tildeFixedFont : tildeRegularFont);
c.mergeCharFormat(format);
insertPosition = action.intervalEnd;
}
@ -2126,9 +2127,11 @@ void InputArea::processDocumentContentsChange(int position, int charsAdded) {
int32 replacePosition = -1, replaceLen = 0;
EmojiPtr emoji = nullptr;
static QString regular = qsl("Open Sans"), semibold = qsl("Open Sans Semibold");
bool checkTilde = !cRetina() && (_inner->font().pixelSize() == 13) && (_inner->font().family() == regular);
bool wasTildeFragment = false;
// Tilde formatting.
auto tildeFormatting = !cRetina() && (font().pixelSize() == 13) && (font().family() == qstr("Open Sans"));
auto isTildeFragment = false;
auto tildeRegularFont = tildeFormatting ? qsl("Open Sans") : QString();
auto tildeFixedFont = tildeFormatting ? Fonts::GetOverride(qsl("Open Sans Semibold")) : QString();
QTextDocument *doc(_inner->document());
QTextCursor c(_inner->textCursor());
@ -2148,8 +2151,8 @@ void InputArea::processDocumentContentsChange(int position, int charsAdded) {
continue;
}
if (checkTilde) {
wasTildeFragment = (fragment.charFormat().fontFamily() == semibold);
if (tildeFormatting) {
isTildeFragment = (fragment.charFormat().fontFamily() == tildeFixedFont);
}
QString t(fragment.text());
@ -2167,9 +2170,9 @@ void InputArea::processDocumentContentsChange(int position, int charsAdded) {
break;
}
if (checkTilde && fp >= position) { // tilde fix in OpenSans
if (tildeFormatting && fp >= position) { // tilde fix in OpenSans
bool tilde = (ch->unicode() == '~');
if ((tilde && !wasTildeFragment) || (!tilde && wasTildeFragment)) {
if ((tilde && !isTildeFragment) || (!tilde && isTildeFragment)) {
if (replacePosition < 0) {
replacePosition = fp;
replaceLen = 1;
@ -2201,7 +2204,7 @@ void InputArea::processDocumentContentsChange(int position, int charsAdded) {
insertEmoji(emoji, c);
} else {
QTextCharFormat format;
format.setFontFamily(wasTildeFragment ? regular : semibold);
format.setFontFamily(isTildeFragment ? tildeRegularFont : tildeFixedFont);
c.mergeCharFormat(format);
}
charsAdded -= replacePosition + replaceLen - position;
@ -2857,9 +2860,11 @@ void InputField::processDocumentContentsChange(int position, int charsAdded) {
EmojiPtr emoji = nullptr;
bool newlineFound = false;
static QString regular = qsl("Open Sans"), semibold = qsl("Open Sans Semibold"), space(' ');
bool checkTilde = !cRetina() && (_inner->font().pixelSize() == 13) && (_inner->font().family() == regular);
bool wasTildeFragment = false;
// Tilde formatting.
auto tildeFormatting = !cRetina() && (font().pixelSize() == 13) && (font().family() == qstr("Open Sans"));
auto isTildeFragment = false;
auto tildeRegularFont = tildeFormatting ? qsl("Open Sans") : QString();
auto tildeFixedFont = tildeFormatting ? Fonts::GetOverride(qsl("Open Sans Semibold")) : QString();
QTextDocument *doc(_inner->document());
QTextCursor c(_inner->textCursor());
@ -2879,8 +2884,8 @@ void InputField::processDocumentContentsChange(int position, int charsAdded) {
continue;
}
if (checkTilde) {
wasTildeFragment = (fragment.charFormat().fontFamily() == semibold);
if (tildeFormatting) {
isTildeFragment = (fragment.charFormat().fontFamily() == tildeFixedFont);
}
QString t(fragment.text());
@ -2910,9 +2915,9 @@ void InputField::processDocumentContentsChange(int position, int charsAdded) {
break;
}
if (checkTilde && fp >= position) { // tilde fix in OpenSans
if (tildeFormatting && fp >= position) { // tilde fix in OpenSans
bool tilde = (ch->unicode() == '~');
if ((tilde && !wasTildeFragment) || (!tilde && wasTildeFragment)) {
if ((tilde && !isTildeFragment) || (!tilde && isTildeFragment)) {
if (replacePosition < 0) {
replacePosition = fp;
replaceLen = 1;
@ -2948,14 +2953,14 @@ void InputField::processDocumentContentsChange(int position, int charsAdded) {
c.setPosition(replacePosition + replaceLen, QTextCursor::KeepAnchor);
if (newlineFound) {
QTextCharFormat format;
format.setFontFamily(regular);
format.setFontFamily(font().family());
c.mergeCharFormat(format);
c.insertText(space);
c.insertText(" ");
} else if (emoji) {
insertEmoji(emoji, c);
} else {
QTextCharFormat format;
format.setFontFamily(wasTildeFragment ? regular : semibold);
format.setFontFamily(isTildeFragment ? tildeRegularFont : tildeFixedFont);
c.mergeCharFormat(format);
}
charsAdded -= replacePosition + replaceLen - position;