summaryrefslogtreecommitdiffstats
path: root/src/gui/text/qfontdatabase_win.cpp
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>2011-02-22 14:40:40 (GMT)
committerEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>2011-03-14 08:25:42 (GMT)
commitc0fed43b04dec8bd549043d3ea5e28908128082c (patch)
tree53b111aa672e80585c32e5874646a2c93b186a76 /src/gui/text/qfontdatabase_win.cpp
parent6f5553b95c4df489e0bf047399a90e9a564314e6 (diff)
downloadQt-c0fed43b04dec8bd549043d3ea5e28908128082c.zip
Qt-c0fed43b04dec8bd549043d3ea5e28908128082c.tar.gz
Qt-c0fed43b04dec8bd549043d3ea5e28908128082c.tar.bz2
Introduce QFontEngineDirectWrite
Make a font engine for subpixel positioned text on Windows Vista (with platform update) and Windows 7. If selected during configuration, the engine will be selected only when the hinting preference of a font is set to None or Vertical hinting. The font database uses most of the same logic but creates a direct write font based on the LOGFONT rather than a GDI handle. The engine is currently regarded as experimental, meaning that code using it should do substantial testing to make sure it covers their use cases. Task-number: QTBUG-12678 Reviewed-by: Jiang Jiang
Diffstat (limited to 'src/gui/text/qfontdatabase_win.cpp')
-rw-r--r--src/gui/text/qfontdatabase_win.cpp220
1 files changed, 185 insertions, 35 deletions
diff --git a/src/gui/text/qfontdatabase_win.cpp b/src/gui/text/qfontdatabase_win.cpp
index e2c5116..0bb1d8d 100644
--- a/src/gui/text/qfontdatabase_win.cpp
+++ b/src/gui/text/qfontdatabase_win.cpp
@@ -49,6 +49,11 @@
#include "qabstractfileengine.h"
#include "qendian.h"
+#if !defined(QT_NO_DIRECTWRITE)
+# include "qsettings.h"
+# include "qfontenginedirectwrite_p.h"
+#endif
+
#ifdef Q_OS_WINCE
# include <QTemporaryFile>
#endif
@@ -542,6 +547,65 @@ static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, const QFon
}
}
+#if !defined(QT_NO_DIRECTWRITE)
+static void initFontInfo(QFontEngineDirectWrite *fe, const QFontDef &request,
+ const QFontPrivate *fp, IDWriteFont *font)
+{
+ fe->fontDef = request;
+
+ IDWriteFontFamily *fontFamily = NULL;
+ HRESULT hr = font->GetFontFamily(&fontFamily);
+
+ IDWriteLocalizedStrings *familyNames = NULL;
+ if (SUCCEEDED(hr))
+ hr = fontFamily->GetFamilyNames(&familyNames);
+
+ UINT32 index = 0;
+ BOOL exists = false;
+
+ wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
+
+ if (SUCCEEDED(hr)) {
+ int defaultLocaleSuccess = GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH);
+
+ if (defaultLocaleSuccess)
+ hr = familyNames->FindLocaleName(localeName, &index, &exists);
+
+ if (SUCCEEDED(hr) && !exists)
+ hr = familyNames->FindLocaleName(L"en-us", &index, &exists);
+ }
+
+ if (!exists)
+ index = 0;
+
+ UINT32 length = 0;
+ if (SUCCEEDED(hr))
+ hr = familyNames->GetStringLength(index, &length);
+
+ wchar_t *name = new (std::nothrow) wchar_t[length+1];
+ if (name == NULL)
+ hr = E_OUTOFMEMORY;
+
+ // Get the family name.
+ if (SUCCEEDED(hr))
+ hr = familyNames->GetString(index, name, length + 1);
+
+ if (SUCCEEDED(hr))
+ fe->fontDef.family = QString::fromWCharArray(name);
+
+ delete[] name;
+ if (familyNames != NULL)
+ familyNames->Release();
+
+ if (FAILED(hr))
+ qErrnoWarning(hr, "initFontInfo: Failed to get family name");
+
+ if (fe->fontDef.pointSize < 0)
+ fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / fp->dpi;
+ else if (fe->fontDef.pixelSize == -1)
+ fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * fp->dpi / 72.);
+}
+#endif
static const char *other_tryFonts[] = {
"Arial",
@@ -595,6 +659,14 @@ static const char *kr_tryFonts[] = {
static const char **tryFonts = 0;
+#if !defined(QT_NO_DIRECTWRITE)
+static QString fontNameSubstitute(const QString &familyName)
+{
+ QLatin1String key("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\"
+ "FontSubstitutes");
+ return QSettings(key, QSettings::NativeFormat).value(familyName, familyName).toString();
+}
+#endif
static inline HFONT systemFont()
{
@@ -629,6 +701,15 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ
HFONT hfont = 0;
+
+#if !defined(QT_NO_DIRECTWRITE)
+ bool useDirectWrite = (request.hintingPreference & QFont::PreferNoHinting)
+ || (request.hintingPreference & QFont::PreferVerticalHinting);
+ IDWriteFont *directWriteFont = 0;
+#else
+ bool useDirectWrite = false;
+#endif
+
if (fp->rawMode) { // will choose a stock font
int f, deffnt = SYSTEM_FONT;
QString fam = desc->family->name.toLower();
@@ -745,6 +826,7 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ
fam = QLatin1String("Courier New");
memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
+
hfont = CreateFontIndirect(&lf);
if (!hfont)
qErrnoWarning("QFontEngine::loadEngine: CreateFontIndirect failed");
@@ -759,52 +841,120 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ
res = GetTextMetrics(hdc, &tm);
avWidth = tm.tmAveCharWidth;
ttf = tm.tmPitchAndFamily & TMPF_TRUETYPE;
-
SelectObject(hdc, oldObj);
- if (hfont && (!ttf || request.stretch != 100)) {
- DeleteObject(hfont);
- if (!res)
- qErrnoWarning("QFontEngine::loadEngine: GetTextMetrics failed");
- lf.lfWidth = avWidth * request.stretch/100;
- hfont = CreateFontIndirect(&lf);
- if (!hfont)
- qErrnoWarning("QFontEngine::loadEngine: CreateFontIndirect with stretch failed");
- }
+ if (!ttf || !useDirectWrite) {
+ useDirectWrite = false;
+
+ if (hfont && (!ttf || request.stretch != 100)) {
+ DeleteObject(hfont);
+ if (!res)
+ qErrnoWarning("QFontEngine::loadEngine: GetTextMetrics failed");
+ lf.lfWidth = avWidth * request.stretch/100;
+ hfont = CreateFontIndirect(&lf);
+ if (!hfont)
+ qErrnoWarning("QFontEngine::loadEngine: CreateFontIndirect with stretch failed");
+ }
#ifndef Q_WS_WINCE
- if (hfont == 0) {
- hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
- stockFont = true;
- }
+ if (hfont == 0) {
+ hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
+ stockFont = true;
+ }
#else
- if (hfont == 0) {
- hfont = (HFONT)GetStockObject(SYSTEM_FONT);
- stockFont = true;
+ if (hfont == 0) {
+ hfont = (HFONT)GetStockObject(SYSTEM_FONT);
+ stockFont = true;
+ }
+#endif
+
+ }
+
+#if !defined(QT_NO_DIRECTWRITE)
+ else {
+ // Default to false for DirectWrite (and re-enable once/if everything
+ // turns out okay)
+ useDirectWrite = false;
+
+ QFontDatabasePrivate *db = privateDb();
+ if (db->directWriteFactory == 0) {
+ HRESULT hr = DWriteCreateFactory(
+ DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown **>(&db->directWriteFactory)
+ );
+ if (FAILED(hr)) {
+ qErrnoWarning("QFontEngine::loadEngine: DWriteCreateFactory failed");
+ } else {
+ hr = db->directWriteFactory->GetGdiInterop(&db->directWriteGdiInterop);
+ if (FAILED(hr))
+ qErrnoWarning("QFontEngine::loadEngine: GetGdiInterop failed");
+ }
+ }
+
+ if (db->directWriteGdiInterop != 0) {
+ QString nameSubstitute = fontNameSubstitute(QString::fromWCharArray(lf.lfFaceName));
+ memcpy(lf.lfFaceName, nameSubstitute.utf16(),
+ sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE));
+
+ HRESULT hr = db->directWriteGdiInterop->CreateFontFromLOGFONT(
+ &lf,
+ &directWriteFont);
+ if (FAILED(hr)) {
+ qErrnoWarning("QFontEngine::loadEngine: CreateFontFromLOGFONT failed "
+ "for %ls (0x%lx)",
+ lf.lfFaceName, hr);
+ } else {
+ DeleteObject(hfont);
+ useDirectWrite = true;
+ }
+ }
}
#endif
}
- QFontEngineWin *few = new QFontEngineWin(font_name, hfont, stockFont, lf);
-
- if (preferClearTypeAA)
- few->glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
-
- // Also check for OpenType tables when using complex scripts
- // ### TODO: This only works for scripts that require OpenType. More generally
- // for scripts that do not require OpenType we should just look at the list of
- // supported writing systems in the font's OS/2 table.
- if (scriptRequiresOpenType(script)) {
- HB_Face hbFace = few->harfbuzzFace();
- if (!hbFace || !hbFace->supported_scripts[script]) {
- FM_DEBUG(" OpenType support missing for script\n");
- delete few;
- return 0;
+
+ QFontEngine *fe = 0;
+ if (!useDirectWrite) {
+ QFontEngineWin *few = new QFontEngineWin(font_name, hfont, stockFont, lf);
+ if (preferClearTypeAA)
+ few->glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
+
+ // Also check for OpenType tables when using complex scripts
+ // ### TODO: This only works for scripts that require OpenType. More generally
+ // for scripts that do not require OpenType we should just look at the list of
+ // supported writing systems in the font's OS/2 table.
+ if (scriptRequiresOpenType(script)) {
+ HB_Face hbFace = few->harfbuzzFace();
+ if (!hbFace || !hbFace->supported_scripts[script]) {
+ FM_DEBUG(" OpenType support missing for script\n");
+ delete few;
+ return 0;
+ }
}
+
+ initFontInfo(few, request, fp);
+ fe = few;
}
- QFontEngine *fe = few;
- initFontInfo(few, request, fp);
+#if !defined(QT_NO_DIRECTWRITE)
+ else {
+ QFontDatabasePrivate *db = privateDb();
+ QFontEngineDirectWrite *fedw = new QFontEngineDirectWrite(font_name,
+ db->directWriteFactory,
+ db->directWriteGdiInterop,
+ directWriteFont,
+ request.pixelSize);
+
+ initFontInfo(fedw, request, fp, directWriteFont);
+
+ fe = fedw;
+ }
+
+ if (directWriteFont != 0)
+ directWriteFont->Release();
+#endif
+
if(script == QUnicodeTables::Common
&& !(request.styleStrategy & QFont::NoFontMerging)
&& !(desc->family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) {
@@ -836,7 +986,7 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ
list << QLatin1String(*tf);
++tf;
}
- QFontEngine *mfe = new QFontEngineMultiWin(few, list);
+ QFontEngine *mfe = new QFontEngineMultiWin(fe, list);
mfe->fontDef = fe->fontDef;
fe = mfe;
}