summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>2012-07-09 15:52:13 +0200
committerQt by Nokia <qt-info@nokia.com>2012-07-10 03:24:53 +0200
commit69fb70f6b3c88d4d2bb5ca97dbb7f77f42c828c5 (patch)
tree2c8bbc3fe4d470fd102a722af19c841a02db9031 /src/plugins
parentfafc1c3dc3eed3c331f5213f5238480335a346ee (diff)
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>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase.cpp181
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase.h1
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.cpp66
-rw-r--r--src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h2
4 files changed, 162 insertions, 88 deletions
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
index a27386c2ad..25f6c4aa21 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
@@ -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)
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h
index 6441e79177..a6b96e3818 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase.h
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h
@@ -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());
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp
index d7f48e59c5..a78b6f1620 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp
@@ -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)
diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h
index f5f20d57ce..32444c7cb0 100644
--- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h
+++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h
@@ -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: