1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qt_windows.h"
44 #include <private/qapplication_p.h>
46 #include "qfontengine_p.h"
47 #include "qpaintdevice.h"
48 #include <private/qsystemlibrary_p.h>
49 #include "qabstractfileengine.h"
52 #if !defined(QT_NO_DIRECTWRITE)
53 # include "qsettings.h"
54 # include "qfontenginedirectwrite_p.h"
58 # include <QTemporaryFile>
63 extern HDC shared_dc(); // common dc for all fonts
68 // GetFontData expects the tags in little endian ;(
69 #define MAKE_TAG(ch1, ch2, ch3, ch4) (\
70 (((quint32)(ch4)) << 24) | \
71 (((quint32)(ch3)) << 16) | \
72 (((quint32)(ch2)) << 8) | \
76 static HFONT stock_sysfont = 0;
78 static bool localizedName(const QString &name)
80 const QChar *c = name.unicode();
81 for(int i = 0; i < name.length(); ++i) {
82 if(c[i].unicode() >= 0x100)
88 static inline quint16 getUShort(const unsigned char *p)
97 static QString getEnglishName(const uchar *table, quint32 bytes)
103 MS_LangIdEnglish = 0x009
106 // get the name table
108 quint16 string_offset;
109 const unsigned char *names;
111 int microsoft_id = -1;
115 if(getUShort(table) != 0)
118 count = getUShort(table+2);
119 string_offset = getUShort(table+4);
122 if(string_offset >= bytes || 6 + count*NameRecordSize > string_offset)
125 for(int i = 0; i < count; ++i) {
126 // search for the correct name entry
128 quint16 platform_id = getUShort(names + i*NameRecordSize);
129 quint16 encoding_id = getUShort(names + 2 + i*NameRecordSize);
130 quint16 language_id = getUShort(names + 4 + i*NameRecordSize);
131 quint16 name_id = getUShort(names + 6 + i*NameRecordSize);
133 if(name_id != FamilyId)
137 PlatformId_Unicode = 0,
138 PlatformId_Apple = 1,
139 PlatformId_Microsoft = 3
142 quint16 length = getUShort(names + 8 + i*NameRecordSize);
143 quint16 offset = getUShort(names + 10 + i*NameRecordSize);
144 if(DWORD(string_offset + offset + length) >= bytes)
147 if ((platform_id == PlatformId_Microsoft
148 && (encoding_id == 0 || encoding_id == 1))
149 && (language_id & 0x3ff) == MS_LangIdEnglish
150 && microsoft_id == -1)
152 // not sure if encoding id 4 for Unicode is utf16 or ucs4...
153 else if(platform_id == PlatformId_Unicode && encoding_id < 4 && unicode_id == -1)
155 else if(platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0)
159 bool unicode = false;
161 if(microsoft_id != -1) {
164 } else if(apple_id != -1) {
167 } else if (unicode_id != -1) {
172 quint16 length = getUShort(names + 8 + id*NameRecordSize);
173 quint16 offset = getUShort(names + 10 + id*NameRecordSize);
178 i18n_name.resize(length);
179 QChar *uc = (QChar *) i18n_name.unicode();
180 const unsigned char *string = table + string_offset + offset;
181 for(int i = 0; i < length; ++i)
182 uc[i] = getUShort(string + 2*i);
186 i18n_name.resize(length);
187 QChar *uc = (QChar *) i18n_name.unicode();
188 const unsigned char *string = table + string_offset + offset;
189 for(int i = 0; i < length; ++i)
190 uc[i] = QLatin1Char(string[i]);
195 //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
199 static QString getEnglishName(const QString &familyName)
203 HDC hdc = GetDC( 0 );
205 memset(&lf, 0, sizeof(LOGFONT));
206 memcpy(lf.lfFaceName, familyName.utf16(), qMin(LF_FACESIZE, familyName.length()) * sizeof(wchar_t));
207 lf.lfCharSet = DEFAULT_CHARSET;
208 HFONT hfont = CreateFontIndirect(&lf);
215 HGDIOBJ oldobj = SelectObject( hdc, hfont );
217 const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' );
219 // get the name table
220 unsigned char *table = 0;
222 DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 );
223 if ( bytes == GDI_ERROR ) {
224 // ### Unused variable
225 /* int err = GetLastError(); */
229 table = new unsigned char[bytes];
230 GetFontData(hdc, name_tag, 0, table, bytes);
231 if ( bytes == GDI_ERROR )
234 i18n_name = getEnglishName(table, bytes);
237 SelectObject( hdc, oldobj );
238 DeleteObject( hfont );
241 //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
245 extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp
248 void addFontToDatabase(QString familyName, const QString &scriptName,
249 TEXTMETRIC *textmetric,
250 const FONTSIGNATURE *signature,
253 const int script = -1;
254 const QString foundryName;
264 // QString escript = QString::fromWCharArray(f->elfScript);
265 // qDebug("script=%s", escript.latin1());
267 NEWTEXTMETRIC *tm = (NEWTEXTMETRIC *)textmetric;
268 fixed = !(tm->tmPitchAndFamily & TMPF_FIXED_PITCH);
269 ttf = (tm->tmPitchAndFamily & TMPF_TRUETYPE);
270 scalable = tm->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE);
271 size = scalable ? SMOOTH_SCALABLE : tm->tmHeight;
272 italic = tm->tmItalic;
273 weight = tm->tmWeight;
275 // the "@family" fonts are just the same as "family". Ignore them.
276 if (familyName[0] != QLatin1Char('@') && !familyName.startsWith(QLatin1String("WST_"))) {
277 QtFontStyle::Key styleKey;
278 styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
279 styleKey.weight = weightFromInteger(weight);
281 QtFontFamily *family = privateDb()->family(familyName, true);
283 if(ttf && localizedName(familyName) && family->english_name.isEmpty())
284 family->english_name = getEnglishName(familyName);
286 QtFontFoundry *foundry = family->foundry(foundryName, true);
287 QtFontStyle *style = foundry->style(styleKey, QString(), true);
288 style->smoothScalable = scalable;
289 style->pixelSize( size, TRUE);
291 // add fonts windows can generate for us:
292 if (styleKey.weight <= QFont::DemiBold) {
293 QtFontStyle::Key key(styleKey);
294 key.weight = QFont::Bold;
295 QtFontStyle *style = foundry->style(key, QString(), true);
296 style->smoothScalable = scalable;
297 style->pixelSize( size, TRUE);
299 if (styleKey.style != QFont::StyleItalic) {
300 QtFontStyle::Key key(styleKey);
301 key.style = QFont::StyleItalic;
302 QtFontStyle *style = foundry->style(key, QString(), true);
303 style->smoothScalable = scalable;
304 style->pixelSize( size, TRUE);
306 if (styleKey.weight <= QFont::DemiBold && styleKey.style != QFont::StyleItalic) {
307 QtFontStyle::Key key(styleKey);
308 key.weight = QFont::Bold;
309 key.style = QFont::StyleItalic;
310 QtFontStyle *style = foundry->style(key, QString(), true);
311 style->smoothScalable = scalable;
312 style->pixelSize( size, TRUE);
315 family->fixedPitch = fixed;
317 if (!family->writingSystemCheck && type & TRUETYPE_FONTTYPE) {
318 quint32 unicodeRange[4] = {
319 signature->fsUsb[0], signature->fsUsb[1],
320 signature->fsUsb[2], signature->fsUsb[3]
323 if (signature->fsUsb[0] == 0) {
324 // If the unicode ranges bit mask is zero then
325 // EnumFontFamiliesEx failed to determine it properly.
326 // In this case we just pretend that the font supports all languages.
327 unicodeRange[0] = 0xbfffffff; // second most significant bit must be zero
328 unicodeRange[1] = 0xffffffff;
329 unicodeRange[2] = 0xffffffff;
330 unicodeRange[3] = 0xffffffff;
333 quint32 codePageRange[2] = {
334 signature->fsCsb[0], signature->fsCsb[1]
336 QList<QFontDatabase::WritingSystem> systems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange);
338 for (int i = 0; i < systems.count(); ++i) {
339 QFontDatabase::WritingSystem writingSystem = systems.at(i);
341 // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains
342 // the symbol for Baht, and Windows thus reports that it supports the Thai script.
343 // Since it's the default UI font on this platform, most widgets will be unable to
344 // display Thai text by default. As a temporary work around, we special case Segoe UI
345 // and remove the Thai script from its list of supported writing systems.
346 if (writingSystem != QFontDatabase::Thai || familyName != QLatin1String("Segoe UI"))
347 family->writingSystems[writingSystem] = QtFontFamily::Supported;
349 } else if (!family->writingSystemCheck) {
350 //qDebug("family='%s' script=%s", family->name.latin1(), script.latin1());
351 if (scriptName == QLatin1String("Western")
352 || scriptName == QLatin1String("Baltic")
353 || scriptName == QLatin1String("Central European")
354 || scriptName == QLatin1String("Turkish")
355 || scriptName == QLatin1String("Vietnamese"))
356 family->writingSystems[QFontDatabase::Latin] = QtFontFamily::Supported;
357 else if (scriptName == QLatin1String("Thai"))
358 family->writingSystems[QFontDatabase::Thai] = QtFontFamily::Supported;
359 else if (scriptName == QLatin1String("Symbol")
360 || scriptName == QLatin1String("Other"))
361 family->writingSystems[QFontDatabase::Symbol] = QtFontFamily::Supported;
362 else if (scriptName == QLatin1String("OEM/Dos"))
363 family->writingSystems[QFontDatabase::Latin] = QtFontFamily::Supported;
364 else if (scriptName == QLatin1String("CHINESE_GB2312"))
365 family->writingSystems[QFontDatabase::SimplifiedChinese] = QtFontFamily::Supported;
366 else if (scriptName == QLatin1String("CHINESE_BIG5"))
367 family->writingSystems[QFontDatabase::TraditionalChinese] = QtFontFamily::Supported;
368 else if (scriptName == QLatin1String("Cyrillic"))
369 family->writingSystems[QFontDatabase::Cyrillic] = QtFontFamily::Supported;
370 else if (scriptName == QLatin1String("Hangul"))
371 family->writingSystems[QFontDatabase::Korean] = QtFontFamily::Supported;
372 else if (scriptName == QLatin1String("Hebrew"))
373 family->writingSystems[QFontDatabase::Hebrew] = QtFontFamily::Supported;
374 else if (scriptName == QLatin1String("Greek"))
375 family->writingSystems[QFontDatabase::Greek] = QtFontFamily::Supported;
376 else if (scriptName == QLatin1String("Japanese"))
377 family->writingSystems[QFontDatabase::Japanese] = QtFontFamily::Supported;
378 else if (scriptName == QLatin1String("Arabic"))
379 family->writingSystems[QFontDatabase::Arabic] = QtFontFamily::Supported;
386 storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric, int type, LPARAM /*p*/)
388 QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName);
389 QString script = QString::fromWCharArray(f->elfScript);
391 FONTSIGNATURE signature = textmetric->ntmFontSig;
393 // NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is
394 // identical to a TEXTMETRIC except for the last four members, which we don't use
396 addFontToDatabase(familyName, script, (TEXTMETRIC *)textmetric, &signature, type);
397 // keep on enumerating
402 void populate_database(const QString& fam)
404 QFontDatabasePrivate *d = privateDb();
408 QtFontFamily *family = 0;
410 family = d->family(fam);
411 if(family && family->loaded)
413 } else if (d->count) {
417 HDC dummy = GetDC(0);
420 lf.lfCharSet = DEFAULT_CHARSET;
422 lf.lfFaceName[0] = 0;
424 memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
426 lf.lfPitchAndFamily = 0;
428 EnumFontFamiliesEx(dummy, &lf,
429 (FONTENUMPROC)storeFont, (LPARAM)privateDb(), 0);
433 for (int i = 0; i < d->applicationFonts.count(); ++i) {
434 QFontDatabasePrivate::ApplicationFont fnt = d->applicationFonts.at(i);
437 for (int j = 0; j < fnt.families.count(); ++j) {
438 const QString familyName = fnt.families.at(j);
441 memset(&lf, 0, sizeof(LOGFONT));
442 memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE, familyName.size()));
443 lf.lfCharSet = DEFAULT_CHARSET;
444 HFONT hfont = CreateFontIndirect(&lf);
445 HGDIOBJ oldobj = SelectObject(hdc, hfont);
447 TEXTMETRIC textMetrics;
448 GetTextMetrics(hdc, &textMetrics);
450 addFontToDatabase(familyName, QString(),
452 &fnt.signatures.at(j),
455 SelectObject(hdc, oldobj);
462 family = d->family(fam);
464 if(!family->writingSystemCheck) {
466 family->loaded = true;
471 static void initializeDb()
473 QFontDatabasePrivate *db = privateDb();
474 if (!db || db->count)
477 populate_database(QString());
479 #ifdef QFONTDATABASE_DEBUG
480 // print the database
481 for (int f = 0; f < db->count; f++) {
482 QtFontFamily *family = db->families[f];
483 qDebug(" %s: %p", qPrintable(family->name), family);
484 populate_database(family->name);
487 qDebug(" scripts supported:");
488 for (int i = 0; i < QUnicodeTables::ScriptCount; i++)
489 if(family->writingSystems[i] & QtFontFamily::Supported)
491 for (int fd = 0; fd < family->count; fd++) {
492 QtFontFoundry *foundry = family->foundries[fd];
493 qDebug(" %s", foundry->name.latin1());
494 for (int s = 0; s < foundry->count; s++) {
495 QtFontStyle *style = foundry->styles[s];
496 qDebug(" style: style=%d weight=%d smooth=%d", style->key.style,
497 style->key.weight, style->smoothScalable );
498 if(!style->smoothScalable) {
499 for(int i = 0; i < style->count; ++i) {
500 qDebug(" %d", style->pixelSizes[i].pixelSize);
507 #endif // QFONTDATABASE_DEBUG
511 static inline void load(const QString &family = QString(), int = -1)
513 populate_database(family);
520 // --------------------------------------------------------------------------------------
522 // --------------------------------------------------------------------------------------
526 static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, HDC fontHdc, int dpi)
528 fe->fontDef = request; // most settings are equal
530 HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fontHdc) ? fontHdc : shared_dc();
531 SelectObject(dc, fe->hfont);
533 GetTextFace(dc, 64, n);
534 fe->fontDef.family = QString::fromWCharArray(n);
535 fe->fontDef.fixedPitch = !(fe->tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
536 if (fe->fontDef.pointSize < 0) {
537 fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / dpi;
538 } else if (fe->fontDef.pixelSize == -1) {
539 fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * dpi / 72.);
543 #if !defined(QT_NO_DIRECTWRITE)
544 static void initFontInfo(QFontEngineDirectWrite *fe, const QFontDef &request,
545 int dpi, IDWriteFont *font)
547 fe->fontDef = request;
549 IDWriteFontFamily *fontFamily = NULL;
550 HRESULT hr = font->GetFontFamily(&fontFamily);
552 IDWriteLocalizedStrings *familyNames = NULL;
554 hr = fontFamily->GetFamilyNames(&familyNames);
559 wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
562 int defaultLocaleSuccess = GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH);
564 if (defaultLocaleSuccess)
565 hr = familyNames->FindLocaleName(localeName, &index, &exists);
567 if (SUCCEEDED(hr) && !exists)
568 hr = familyNames->FindLocaleName(L"en-us", &index, &exists);
576 hr = familyNames->GetStringLength(index, &length);
578 wchar_t *name = new (std::nothrow) wchar_t[length+1];
582 // Get the family name.
584 hr = familyNames->GetString(index, name, length + 1);
587 fe->fontDef.family = QString::fromWCharArray(name);
590 if (familyNames != NULL)
591 familyNames->Release();
594 qErrnoWarning(hr, "initFontInfo: Failed to get family name");
596 if (fe->fontDef.pointSize < 0)
597 fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / dpi;
598 else if (fe->fontDef.pixelSize == -1)
599 fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * dpi / 72.);
603 static const char *other_tryFonts[] = {
613 static const char *jp_tryFonts [] = {
623 static const char *ch_CN_tryFonts [] = {
633 static const char *ch_TW_tryFonts [] = {
643 static const char *kr_tryFonts[] = {
653 static const char **tryFonts = 0;
655 #if !defined(QT_NO_DIRECTWRITE)
656 static QString fontNameSubstitute(const QString &familyName)
658 QLatin1String key("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\"
660 return QSettings(key, QSettings::NativeFormat).value(familyName, familyName).toString();
664 static inline HFONT systemFont()
666 if (stock_sysfont == 0)
667 stock_sysfont = (HFONT)GetStockObject(SYSTEM_FONT);
668 return stock_sysfont;
671 #if !defined(DEFAULT_GUI_FONT)
672 #define DEFAULT_GUI_FONT 17
675 static QFontEngine *loadEngine(int script, const QFontDef &request,
676 HDC fontHdc, int dpi, bool rawMode,
677 const QtFontDesc *desc,
678 const QStringList &family_list)
681 memset(&lf, 0, sizeof(LOGFONT));
683 bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fontHdc;
685 HDC hdc = shared_dc();
686 QString font_name = desc != 0 ? desc->family->name : request.family;
690 font_name = request.family;
693 bool stockFont = false;
694 bool preferClearTypeAA = false;
699 #if !defined(QT_NO_DIRECTWRITE)
700 bool useDirectWrite = (request.hintingPreference == QFont::PreferNoHinting)
701 || (request.hintingPreference == QFont::PreferVerticalHinting);
702 IDWriteFont *directWriteFont = 0;
704 bool useDirectWrite = false;
707 if (rawMode) { // will choose a stock font
708 int f, deffnt = SYSTEM_FONT;
709 QString fam = desc != 0 ? desc->family->name.toLower() : request.family.toLower();
710 if (fam == QLatin1String("default"))
712 else if (fam == QLatin1String("system"))
715 else if (fam == QLatin1String("system_fixed"))
716 f = SYSTEM_FIXED_FONT;
717 else if (fam == QLatin1String("ansi_fixed"))
719 else if (fam == QLatin1String("ansi_var"))
721 else if (fam == QLatin1String("device_default"))
722 f = DEVICE_DEFAULT_FONT;
723 else if (fam == QLatin1String("oem_fixed"))
726 else if (fam[0] == QLatin1Char('#'))
727 f = fam.right(fam.length()-1).toInt();
730 hfont = (HFONT)GetStockObject(f);
732 qErrnoWarning("QFontEngine::loadEngine: GetStockObject failed");
733 hfont = systemFont();
738 int hint = FF_DONTCARE;
739 switch (request.styleHint) {
740 case QFont::Helvetica:
749 case QFont::OldEnglish:
750 hint = FF_DECORATIVE;
759 lf.lfHeight = -qRound(request.pixelSize);
762 lf.lfOrientation = 0;
763 if (desc == 0 || desc->style->key.weight == 50)
764 lf.lfWeight = FW_DONTCARE;
766 lf.lfWeight = (desc->style->key.weight*900)/99;
767 lf.lfItalic = (desc != 0 && desc->style->key.style != QFont::StyleNormal);
768 lf.lfCharSet = DEFAULT_CHARSET;
770 int strat = OUT_DEFAULT_PRECIS;
771 if (request.styleStrategy & QFont::PreferBitmap) {
772 strat = OUT_RASTER_PRECIS;
774 } else if (request.styleStrategy & QFont::PreferDevice) {
775 strat = OUT_DEVICE_PRECIS;
776 } else if (request.styleStrategy & QFont::PreferOutline) {
777 strat = OUT_OUTLINE_PRECIS;
778 } else if (request.styleStrategy & QFont::ForceOutline) {
779 strat = OUT_TT_ONLY_PRECIS;
783 lf.lfOutPrecision = strat;
785 int qual = DEFAULT_QUALITY;
787 if (request.styleStrategy & QFont::PreferMatch)
788 qual = DRAFT_QUALITY;
790 else if (request.styleStrategy & QFont::PreferQuality)
791 qual = PROOF_QUALITY;
794 if (request.styleStrategy & QFont::PreferAntialias) {
795 if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP) {
796 qual = CLEARTYPE_QUALITY;
797 preferClearTypeAA = true;
799 qual = ANTIALIASED_QUALITY;
801 } else if (request.styleStrategy & QFont::NoAntialias) {
802 qual = NONANTIALIASED_QUALITY;
807 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
808 lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
810 QString fam = font_name;
813 fam = QLatin1String("MS Sans Serif");
815 if ((fam == QLatin1String("MS Sans Serif"))
816 && (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) {
817 fam = QLatin1String("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale
819 if (fam == QLatin1String("Courier") && !(request.styleStrategy & QFont::PreferBitmap))
820 fam = QLatin1String("Courier New");
822 memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
824 hfont = CreateFontIndirect(&lf);
826 qErrnoWarning("QFontEngine::loadEngine: CreateFontIndirect failed");
828 stockFont = (hfont == 0);
832 HGDIOBJ oldObj = SelectObject(hdc, hfont);
835 res = GetTextMetrics(hdc, &tm);
836 avWidth = tm.tmAveCharWidth;
837 ttf = tm.tmPitchAndFamily & TMPF_TRUETYPE;
838 SelectObject(hdc, oldObj);
840 if (!ttf || !useDirectWrite) {
841 useDirectWrite = false;
843 if (hfont && (!ttf || request.stretch != 100)) {
846 qErrnoWarning("QFontEngine::loadEngine: GetTextMetrics failed");
847 lf.lfWidth = avWidth * request.stretch/100;
848 hfont = CreateFontIndirect(&lf);
850 qErrnoWarning("QFontEngine::loadEngine: CreateFontIndirect with stretch failed");
855 hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
860 hfont = (HFONT)GetStockObject(SYSTEM_FONT);
867 #if !defined(QT_NO_DIRECTWRITE)
869 // Default to false for DirectWrite (and re-enable once/if everything
871 useDirectWrite = false;
873 QFontDatabasePrivate *db = privateDb();
874 if (db->directWriteFactory == 0) {
875 HRESULT hr = DWriteCreateFactory(
876 DWRITE_FACTORY_TYPE_SHARED,
877 __uuidof(IDWriteFactory),
878 reinterpret_cast<IUnknown **>(&db->directWriteFactory)
881 qErrnoWarning("QFontEngine::loadEngine: DWriteCreateFactory failed");
883 hr = db->directWriteFactory->GetGdiInterop(&db->directWriteGdiInterop);
885 qErrnoWarning("QFontEngine::loadEngine: GetGdiInterop failed");
889 if (db->directWriteGdiInterop != 0) {
890 QString nameSubstitute = fontNameSubstitute(QString::fromWCharArray(lf.lfFaceName));
891 memcpy(lf.lfFaceName, nameSubstitute.utf16(),
892 sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE));
894 HRESULT hr = db->directWriteGdiInterop->CreateFontFromLOGFONT(
899 qErrnoWarning("QFontEngine::loadEngine: CreateFontFromLOGFONT failed "
905 useDirectWrite = true;
914 if (!useDirectWrite) {
915 QFontEngineWin *few = new QFontEngineWin(font_name, hfont, stockFont, lf);
916 if (preferClearTypeAA)
917 few->glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
919 // Also check for OpenType tables when using complex scripts
920 // ### TODO: This only works for scripts that require OpenType. More generally
921 // for scripts that do not require OpenType we should just look at the list of
922 // supported writing systems in the font's OS/2 table.
923 if (scriptRequiresOpenType(script)) {
924 HB_Face hbFace = few->harfbuzzFace();
925 if (!hbFace || !hbFace->supported_scripts[script]) {
926 FM_DEBUG(" OpenType support missing for script\n");
932 initFontInfo(few, request, fontHdc, dpi);
936 #if !defined(QT_NO_DIRECTWRITE)
938 QFontDatabasePrivate *db = privateDb();
940 IDWriteFontFace *directWriteFontFace = NULL;
941 HRESULT hr = directWriteFont->CreateFontFace(&directWriteFontFace);
943 QFontEngineDirectWrite *fedw = new QFontEngineDirectWrite(db->directWriteFactory,
947 initFontInfo(fedw, request, dpi, directWriteFont);
951 qErrnoWarning(hr, "QFontEngine::loadEngine: CreateFontFace failed");
955 if (directWriteFont != 0)
956 directWriteFont->Release();
959 if(script == QUnicodeTables::Common
960 && !(request.styleStrategy & QFont::NoFontMerging)
962 && !(desc->family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) {
964 LANGID lid = GetUserDefaultLangID();
966 case LANG_CHINESE: // Chinese (Taiwan)
967 if ( lid == 0x0804 ) // Taiwan
968 tryFonts = ch_TW_tryFonts;
970 tryFonts = ch_CN_tryFonts;
973 tryFonts = jp_tryFonts;
976 tryFonts = kr_tryFonts;
979 tryFonts = other_tryFonts;
983 QStringList fm = QFontDatabase().families();
984 QStringList list = family_list;
985 const char **tf = tryFonts;
987 if(fm.contains(QLatin1String(*tf)))
988 list << QLatin1String(*tf);
991 QFontEngine *mfe = new QFontEngineMultiWin(fe, list);
992 mfe->fontDef = fe->fontDef;
998 QFontEngine *qt_load_font_engine_win(const QFontDef &request)
1001 extern int qt_defaultDpi();
1003 QFontCache::Key key(request, QUnicodeTables::Common);
1004 QFontEngine *fe = QFontCache::instance()->findEngine(key);
1008 return loadEngine(QUnicodeTables::Common, request, 0, qt_defaultDpi(), false, 0,
1012 const char *styleHint(const QFontDef &request)
1014 const char *stylehint = 0;
1015 switch (request.styleHint) {
1016 case QFont::SansSerif:
1017 stylehint = "Arial";
1020 stylehint = "Times New Roman";
1022 case QFont::TypeWriter:
1023 stylehint = "Courier New";
1026 if (request.fixedPitch)
1027 stylehint = "Courier New";
1033 static QFontEngine *loadWin(const QFontPrivate *d, int script, const QFontDef &req)
1035 // list of families to try
1036 QStringList family_list = familyList(req);
1038 const char *stylehint = styleHint(d->request);
1040 family_list << QLatin1String(stylehint);
1042 // append the default fallback font for the specified script
1043 // family_list << ... ; ###########
1045 // add the default family
1046 QString defaultFamily = QApplication::font().family();
1047 if (! family_list.contains(defaultFamily))
1048 family_list << defaultFamily;
1050 // add QFont::defaultFamily() to the list, for compatibility with
1051 // previous versions
1052 family_list << QApplication::font().defaultFamily();
1054 // null family means find the first font matching the specified script
1055 family_list << QString();
1058 QFontEngine *fe = 0;
1059 QList<int> blacklistedFamilies;
1062 for (int i = 0; i < family_list.size(); ++i) {
1063 QString family, foundry;
1064 parseFontName(family_list.at(i), foundry, family);
1065 FM_DEBUG("loadWin: >>>>>>>>>>>>>>trying to match '%s'", family.toLatin1().data());
1066 QT_PREPEND_NAMESPACE(match)(script, req, family, foundry, -1, &desc, blacklistedFamilies);
1072 fe = loadEngine(script, req, d->hdc, d->dpi, d->rawMode, &desc, family_list);
1074 blacklistedFamilies.append(desc.familyIndex);
1079 void QFontDatabase::load(const QFontPrivate *d, int script)
1083 qWarning("QFontDatabase::load: Must construct QApplication first");
1084 Q_ASSERT(script >= 0 && script < QUnicodeTables::ScriptCount);
1086 // normalize the request to get better caching
1087 QFontDef req = d->request;
1088 if (req.pixelSize <= 0)
1089 req.pixelSize = floor((100.0 * req.pointSize * d->dpi) / 72. + 0.5) / 100;
1090 if (req.pixelSize < 1)
1092 if (req.weight == 0)
1093 req.weight = QFont::Normal;
1094 if (req.stretch == 0)
1097 QFontCache::Key key(req, d->rawMode ? QUnicodeTables::Common : script, d->screen);
1099 getEngineData(d, key);
1101 // the cached engineData could have already loaded the engine we want
1102 if (d->engineData->engines[script])
1105 QFontEngine *fe = QFontCache::instance()->findEngine(key);
1107 // set it to the actual pointsize, so QFontInfo will do the right thing
1108 if (req.pointSize < 0)
1109 req.pointSize = req.pixelSize*72./d->dpi;
1112 if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
1113 fe = new QTestFontEngine(req.pixelSize);
1116 QMutexLocker locker(fontDatabaseMutex());
1117 if (!privateDb()->count)
1119 fe = loadWin(d, script, req);
1122 fe = new QFontEngineBox(req.pixelSize);
1123 fe->fontDef = QFontDef();
1126 d->engineData->engines[script] = fe;
1128 QFontCache::instance()->insertEngine(key, fe);
1131 #if !defined(FR_PRIVATE)
1132 #define FR_PRIVATE 0x10
1135 typedef int (WINAPI *PtrAddFontResourceExW)(LPCWSTR, DWORD, PVOID);
1136 typedef HANDLE (WINAPI *PtrAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
1137 typedef BOOL (WINAPI *PtrRemoveFontResourceExW)(LPCWSTR, DWORD, PVOID);
1138 typedef BOOL (WINAPI *PtrRemoveFontMemResourceEx)(HANDLE);
1140 static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData)
1142 QList<quint32> offsets;
1143 const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData);
1144 if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) {
1145 if (headerTag != MAKE_TAG(0, 1, 0, 0)
1146 && headerTag != MAKE_TAG('O', 'T', 'T', 'O')
1147 && headerTag != MAKE_TAG('t', 'r', 'u', 'e')
1148 && headerTag != MAKE_TAG('t', 'y', 'p', '1'))
1153 const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8);
1154 for (uint i = 0; i < numFonts; ++i) {
1155 offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
1160 static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
1162 const quint16 numTables = qFromBigEndian<quint16>(data + 4);
1163 for (uint i = 0; i < numTables; ++i) {
1164 const quint32 offset = 12 + 16 * i;
1165 if (*reinterpret_cast<const quint32 *>(data + offset) == tag) {
1166 *table = fileBegin + qFromBigEndian<quint32>(data + offset + 8);
1167 *length = qFromBigEndian<quint32>(data + offset + 12);
1176 static void getFamiliesAndSignatures(const QByteArray &fontData, QFontDatabasePrivate::ApplicationFont *appFont)
1178 const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
1180 QList<quint32> offsets = getTrueTypeFontOffsets(data);
1181 if (offsets.isEmpty())
1184 for (int i = 0; i < offsets.count(); ++i) {
1185 const uchar *font = data + offsets.at(i);
1188 getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
1191 QString name = getEnglishName(table, length);
1195 appFont->families << name;
1196 FONTSIGNATURE signature;
1197 getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
1198 if (table && length >= 86) {
1199 // See also qfontdatabase_mac.cpp, offsets taken from OS/2 table in the TrueType spec
1200 signature.fsUsb[0] = qFromBigEndian<quint32>(table + 42);
1201 signature.fsUsb[1] = qFromBigEndian<quint32>(table + 46);
1202 signature.fsUsb[2] = qFromBigEndian<quint32>(table + 50);
1203 signature.fsUsb[3] = qFromBigEndian<quint32>(table + 54);
1205 signature.fsCsb[0] = qFromBigEndian<quint32>(table + 78);
1206 signature.fsCsb[1] = qFromBigEndian<quint32>(table + 82);
1208 memset(&signature, 0, sizeof(signature));
1210 appFont->signatures << signature;
1214 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
1216 if(!fnt->data.isEmpty()) {
1218 PtrAddFontMemResourceEx ptrAddFontMemResourceEx = (PtrAddFontMemResourceEx)QSystemLibrary::resolve(QLatin1String("gdi32"),
1219 "AddFontMemResourceEx");
1220 if (!ptrAddFontMemResourceEx)
1223 getFamiliesAndSignatures(fnt->data, fnt);
1224 if (fnt->families.isEmpty())
1231 #ifdef QT_NO_TEMPORARYFILE
1232 wchar_t lpBuffer[MAX_PATH];
1233 GetTempPath(MAX_PATH, lpBuffer);
1234 QString s = QString::fromWCharArray(lpBuffer);
1235 QFile tempfile(s + QLatin1String("/font") + QString::number(GetTickCount()) + QLatin1String(".ttf"));
1236 if (!tempfile.open(QIODevice::ReadWrite))
1238 QTemporaryFile tempfile(QLatin1String("XXXXXXXX.ttf"));
1239 if (!tempfile.open())
1240 #endif // QT_NO_TEMPORARYFILE
1242 if (tempfile.write(fnt->data) == -1)
1245 #ifndef QT_NO_TEMPORARYFILE
1246 tempfile.setAutoRemove(false);
1248 fnt->fileName = QFileInfo(tempfile.fileName()).absoluteFilePath();
1251 if (AddFontResource((LPCWSTR)fnt->fileName.utf16()) == 0) {
1252 QFile(fnt->fileName).remove();
1257 HANDLE handle = ptrAddFontMemResourceEx((void *)fnt->data.constData(), fnt->data.size(), 0,
1261 #endif // Q_OS_WINCE
1263 fnt->handle = handle;
1264 fnt->data = QByteArray();
1265 fnt->memoryFont = true;
1267 QFile f(fnt->fileName);
1268 if (!f.open(QIODevice::ReadOnly))
1270 QByteArray data = f.readAll();
1272 getFamiliesAndSignatures(data, fnt);
1275 QFileInfo fileinfo(fnt->fileName);
1276 fnt->fileName = fileinfo.absoluteFilePath();
1277 if (AddFontResource((LPCWSTR)fnt->fileName.utf16()) == 0)
1280 PtrAddFontResourceExW ptrAddFontResourceExW = (PtrAddFontResourceExW)QSystemLibrary::resolve(QLatin1String("gdi32"),
1281 "AddFontResourceExW");
1282 if (!ptrAddFontResourceExW
1283 || ptrAddFontResourceExW((wchar_t*)fnt->fileName.utf16(), FR_PRIVATE, 0) == 0)
1285 #endif // Q_OS_WINCE
1287 fnt->memoryFont = false;
1291 bool QFontDatabase::removeApplicationFont(int handle)
1293 QMutexLocker locker(fontDatabaseMutex());
1295 QFontDatabasePrivate *db = privateDb();
1296 if (handle < 0 || handle >= db->applicationFonts.count())
1299 const QFontDatabasePrivate::ApplicationFont font = db->applicationFonts.at(handle);
1300 db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
1301 if (font.memoryFont) {
1303 bool removeSucceeded = RemoveFontResource((LPCWSTR)font.fileName.utf16());
1304 QFile tempfile(font.fileName);
1306 if (!removeSucceeded)
1309 PtrRemoveFontMemResourceEx ptrRemoveFontMemResourceEx = (PtrRemoveFontMemResourceEx)QSystemLibrary::resolve(QLatin1String("gdi32"),
1310 "RemoveFontMemResourceEx");
1311 if (!ptrRemoveFontMemResourceEx
1312 || !ptrRemoveFontMemResourceEx(font.handle))
1314 #endif // Q_OS_WINCE
1317 if (!RemoveFontResource((LPCWSTR)font.fileName.utf16()))
1320 PtrRemoveFontResourceExW ptrRemoveFontResourceExW = (PtrRemoveFontResourceExW)QSystemLibrary::resolve(QLatin1String("gdi32"),
1321 "RemoveFontResourceExW");
1322 if (!ptrRemoveFontResourceExW
1323 || !ptrRemoveFontResourceExW((LPCWSTR)font.fileName.utf16(), FR_PRIVATE, 0))
1325 #endif // Q_OS_WINCE
1332 bool QFontDatabase::removeAllApplicationFonts()
1334 QMutexLocker locker(fontDatabaseMutex());
1336 QFontDatabasePrivate *db = privateDb();
1337 for (int i = 0; i < db->applicationFonts.count(); ++i)
1338 if (!removeApplicationFont(i))
1343 bool QFontDatabase::supportsThreadedFontRendering()