Support fallback fonts in DirectWrite font engine

When selecting fallback fonts for a DirectWrite font, we would
cast the font engine to QWindowsFontEngine and get unpredictable
results and crashes. This change factors out getting the LOGFONT
data from the QFontDef struct and will use this to create a new
DirectWrite engine.

Task-number: QTBUG-22658

Change-Id: I743944d9a44d8742b47b1aa3354532493362cc4a
Reviewed-by: Jiang Jiang <jiang.jiang@nokia.com>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2012-07-09 15:52:13 +02:00 committed by Qt by Nokia
parent fafc1c3dc3
commit 69fb70f6b3
4 changed files with 162 additions and 88 deletions

View File

@ -1594,6 +1594,100 @@ static const char *kr_tryFonts[] = {
static const char **tryFonts = 0;
LOGFONT QWindowsFontDatabase::fontDefToLOGFONT(const QFontDef &request)
{
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
lf.lfHeight = -qRound(request.pixelSize);
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
if (request.weight == 50)
lf.lfWeight = FW_DONTCARE;
else
lf.lfWeight = (request.weight*900)/99;
lf.lfItalic = request.style != QFont::StyleNormal;
lf.lfCharSet = DEFAULT_CHARSET;
int strat = OUT_DEFAULT_PRECIS;
if (request.styleStrategy & QFont::PreferBitmap) {
strat = OUT_RASTER_PRECIS;
#ifndef Q_OS_WINCE
} else if (request.styleStrategy & QFont::PreferDevice) {
strat = OUT_DEVICE_PRECIS;
} else if (request.styleStrategy & QFont::PreferOutline) {
strat = OUT_OUTLINE_PRECIS;
} else if (request.styleStrategy & QFont::ForceOutline) {
strat = OUT_TT_ONLY_PRECIS;
#endif
}
lf.lfOutPrecision = strat;
int qual = DEFAULT_QUALITY;
if (request.styleStrategy & QFont::PreferMatch)
qual = DRAFT_QUALITY;
#ifndef Q_OS_WINCE
else if (request.styleStrategy & QFont::PreferQuality)
qual = PROOF_QUALITY;
#endif
if (request.styleStrategy & QFont::PreferAntialias) {
if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP) {
qual = CLEARTYPE_QUALITY;
} else {
qual = ANTIALIASED_QUALITY;
}
} else if (request.styleStrategy & QFont::NoAntialias) {
qual = NONANTIALIASED_QUALITY;
}
lf.lfQuality = qual;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
int hint = FF_DONTCARE;
switch (request.styleHint) {
case QFont::Helvetica:
hint = FF_SWISS;
break;
case QFont::Times:
hint = FF_ROMAN;
break;
case QFont::Courier:
hint = FF_MODERN;
break;
case QFont::OldEnglish:
hint = FF_DECORATIVE;
break;
case QFont::System:
hint = FF_MODERN;
break;
default:
break;
}
lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
QString fam = request.family;
if (fam.isEmpty())
fam = QStringLiteral("MS Sans Serif");
if ((fam == QStringLiteral("MS Sans Serif"))
&& (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) {
fam = QStringLiteral("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale
}
if (fam == QStringLiteral("Courier") && !(request.styleStrategy & QFont::PreferBitmap))
fam = QStringLiteral("Courier New");
memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
return lf;
}
QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &request,
HDC fontHdc, int dpi, bool rawMode,
const QStringList &family_list,
@ -1645,91 +1739,8 @@ QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &requ
}
stockFont = true;
} else {
int hint = FF_DONTCARE;
switch (request.styleHint) {
case QFont::Helvetica:
hint = FF_SWISS;
break;
case QFont::Times:
hint = FF_ROMAN;
break;
case QFont::Courier:
hint = FF_MODERN;
break;
case QFont::OldEnglish:
hint = FF_DECORATIVE;
break;
case QFont::System:
hint = FF_MODERN;
break;
default:
break;
}
lf.lfHeight = -qRound(request.pixelSize);
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
if (request.weight == 50)
lf.lfWeight = FW_DONTCARE;
else
lf.lfWeight = (request.weight*900)/99;
lf.lfItalic = request.style != QFont::StyleNormal;
lf.lfCharSet = DEFAULT_CHARSET;
int strat = OUT_DEFAULT_PRECIS;
if (request.styleStrategy & QFont::PreferBitmap) {
strat = OUT_RASTER_PRECIS;
#ifndef Q_OS_WINCE
} else if (request.styleStrategy & QFont::PreferDevice) {
strat = OUT_DEVICE_PRECIS;
} else if (request.styleStrategy & QFont::PreferOutline) {
strat = OUT_OUTLINE_PRECIS;
} else if (request.styleStrategy & QFont::ForceOutline) {
strat = OUT_TT_ONLY_PRECIS;
#endif
}
lf.lfOutPrecision = strat;
int qual = DEFAULT_QUALITY;
if (request.styleStrategy & QFont::PreferMatch)
qual = DRAFT_QUALITY;
#ifndef Q_OS_WINCE
else if (request.styleStrategy & QFont::PreferQuality)
qual = PROOF_QUALITY;
#endif
if (request.styleStrategy & QFont::PreferAntialias) {
if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP) {
qual = CLEARTYPE_QUALITY;
preferClearTypeAA = true;
} else {
qual = ANTIALIASED_QUALITY;
}
} else if (request.styleStrategy & QFont::NoAntialias) {
qual = NONANTIALIASED_QUALITY;
}
lf.lfQuality = qual;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
QString fam = request.family;
if(fam.isEmpty())
fam = QStringLiteral("MS Sans Serif");
if ((fam == QStringLiteral("MS Sans Serif"))
&& (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) {
fam = QStringLiteral("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale
}
if (fam == QStringLiteral("Courier") && !(request.styleStrategy & QFont::PreferBitmap))
fam = QStringLiteral("Courier New");
memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
lf = fontDefToLOGFONT(request);
preferClearTypeAA = lf.lfQuality == CLEARTYPE_QUALITY;
hfont = CreateFontIndirect(&lf);
if (!hfont)

View File

@ -101,6 +101,7 @@ public:
static QFont LOGFONT_to_QFont(const LOGFONT& lf, int verticalDPI = 0);
static qreal fontSmoothingGamma();
static LOGFONT fontDefToLOGFONT(const QFontDef &fontDef);
private:
void populate(const QString &family = QString());

View File

@ -50,6 +50,7 @@
#include "qwindowscontext.h"
#include "qwindowsfontdatabase.h"
#include "qtwindows_additional.h"
#include "qwindowsfontenginedirectwrite.h"
#include <QtGui/private/qtextengine_p.h> // glyph_metrics_t
#include <QtGui/private/qguiapplication_p.h>
@ -74,6 +75,10 @@
# include "qplatformfunctions_wince.h"
#endif
#if !defined(QT_NO_DIRECTWRITE)
# include <dwrite.h>
#endif
QT_BEGIN_NAMESPACE
//### mingw needed define
@ -1318,10 +1323,65 @@ void QWindowsMultiFontEngine::loadEngine(int at)
Q_ASSERT(at < engines.size());
Q_ASSERT(engines.at(at) == 0);
QFontEngine *fontEngine = engines.at(0);
QSharedPointer<QWindowsFontEngineData> data;
LOGFONT lf;
#ifndef QT_NO_DIRECTWRITE
if (fontEngine->type() == QFontEngine::DirectWrite) {
QWindowsFontEngineDirectWrite *fe = static_cast<QWindowsFontEngineDirectWrite *>(fontEngine);
lf = QWindowsFontDatabase::fontDefToLOGFONT(fe->fontDef);
data = fe->fontEngineData();
} else
#endif
{
QWindowsFontEngine *fe = static_cast<QWindowsFontEngine*>(fontEngine);
lf = fe->logFont();
data = fe->fontEngineData();
}
const QString fam = fallbacks.at(at-1);
QWindowsFontEngine *fe = static_cast<QWindowsFontEngine*>(engines.at(0));
LOGFONT lf = fe->logFont();
memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
#ifndef QT_NO_DIRECTWRITE
if (fontEngine->type() == QFontEngine::DirectWrite) {
const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(QString::fromWCharArray(lf.lfFaceName));
memcpy(lf.lfFaceName, nameSubstitute.utf16(),
sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE));
IDWriteFont *directWriteFont = 0;
HRESULT hr = data->directWriteGdiInterop->CreateFontFromLOGFONT(&lf, &directWriteFont);
if (FAILED(hr)) {
qErrnoWarning("%s: CreateFontFromLOGFONT failed", __FUNCTION__);
} else {
IDWriteFontFace *directWriteFontFace = NULL;
HRESULT hr = directWriteFont->CreateFontFace(&directWriteFontFace);
if (SUCCEEDED(hr)) {
QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace,
fontEngine->fontDef.pixelSize,
data);
fedw->setObjectName(QStringLiteral("QWindowsFontEngineDirectWrite_") + fontEngine->fontDef.family);
fedw->fontDef = fontDef;
fedw->ref.ref();
engines[at] = fedw;
if (QWindowsContext::verboseFonts)
qDebug("%s %d %s", __FUNCTION__, at, qPrintable(fam));
return;
} else {
qErrnoWarning("%s: CreateFontFace failed", __FUNCTION__);
}
}
}
#endif
// Get here if original font is not DirectWrite or DirectWrite creation failed for some
// reason
HFONT hfont = CreateFontIndirect(&lf);
bool stockFont = false;
@ -1329,7 +1389,7 @@ void QWindowsMultiFontEngine::loadEngine(int at)
hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
stockFont = true;
}
engines[at] = new QWindowsFontEngine(fam, hfont, stockFont, lf, fe->fontEngineData());
engines[at] = new QWindowsFontEngine(fam, hfont, stockFont, lf, data);
engines[at]->ref.ref();
engines[at]->fontDef = fontDef;
if (QWindowsContext::verboseFonts)

View File

@ -99,6 +99,8 @@ public:
bool canRender(const QChar *string, int len);
Type type() const;
const QSharedPointer<QWindowsFontEngineData> &fontEngineData() const { return m_fontEngineData; }
static QString fontNameSubstitute(const QString &familyName);
private: