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

View File

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

View File

@ -56,7 +56,12 @@ int registerFontFamily(const QString &family) {
return result; 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) { if (other) {
memcpy(modified, other, sizeof(modified)); memcpy(modified, other, sizeof(modified));
} else { } else {

View File

@ -567,7 +567,7 @@ public:
ch = emojiLookback = 0; ch = emojiLookback = 0;
lastSkipped = false; 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) { for (; ptr <= end; ++ptr) {
while (checkEntities() || (rich && checkCommand())) { while (checkEntities() || (rich && checkCommand())) {
} }

View File

@ -22,16 +22,96 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "mainwindow.h" #include "mainwindow.h"
namespace Fonts { 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; bool Started = false;
void start() { QString OpenSansOverride;
if (!Started) { QString OpenSansSemiboldOverride;
Started = true;
QFontDatabase::addApplicationFont(qsl(":/gui/fonts/OpenSans-Regular.ttf")); } // namespace
QFontDatabase::addApplicationFont(qsl(":/gui/fonts/OpenSans-Bold.ttf"));
QFontDatabase::addApplicationFont(qsl(":/gui/fonts/OpenSans-Semibold.ttf")); 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 } // Fonts

View File

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

View File

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