src/gui/text/qfontdatabase_win.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/text/qfontdatabase_win.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1171 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qt_windows.h"
+#include <private/qapplication_p.h>
+#include "qfont_p.h"
+#include "qfontengine_p.h"
+#include "qpaintdevice.h"
+#include "qlibrary.h"
+#include "qabstractfileengine.h"
+#include "qendian.h"
+
+#ifdef Q_OS_WINCE
+#   include <QTemporaryFile>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+extern HDC   shared_dc();                // common dc for all fonts
+
+#ifdef MAKE_TAG
+#undef MAKE_TAG
+#endif
+// GetFontData expects the tags in little endian ;(
+#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
+    (((quint32)(ch4)) << 24) | \
+    (((quint32)(ch3)) << 16) | \
+    (((quint32)(ch2)) << 8) | \
+    ((quint32)(ch1)) \
+   )
+
+static HFONT stock_sysfont  = 0;
+
+static bool localizedName(const QString &name)
+{
+    const QChar *c = name.unicode();
+    for(int i = 0; i < name.length(); ++i) {
+        if(c[i].unicode() >= 0x100)
+            return true;
+    }
+    return false;
+}
+
+static inline quint16 getUShort(const unsigned char *p)
+{
+    quint16 val;
+    val = *p++ << 8;
+    val |= *p;
+
+    return val;
+}
+
+static QString getEnglishName(const uchar *table, quint32 bytes)
+{
+    QString i18n_name;
+    enum {
+        NameRecordSize = 12,
+        FamilyId = 1,
+        MS_LangIdEnglish = 0x009
+    };
+
+    // get the name table
+    quint16 count;
+    quint16 string_offset;
+    const unsigned char *names;
+
+    int microsoft_id = -1;
+    int apple_id = -1;
+    int unicode_id = -1;
+
+    if(getUShort(table) != 0)
+        goto error;
+
+    count = getUShort(table+2);
+    string_offset = getUShort(table+4);
+    names = table + 6;
+
+    if(string_offset >= bytes || 6 + count*NameRecordSize > string_offset)
+        goto error;
+
+    for(int i = 0; i < count; ++i) {
+        // search for the correct name entry
+
+        quint16 platform_id = getUShort(names + i*NameRecordSize);
+        quint16 encoding_id = getUShort(names + 2 + i*NameRecordSize);
+        quint16 language_id = getUShort(names + 4 + i*NameRecordSize);
+        quint16 name_id = getUShort(names + 6 + i*NameRecordSize);
+
+        if(name_id != FamilyId)
+            continue;
+
+        enum {
+            PlatformId_Unicode = 0,
+            PlatformId_Apple = 1,
+            PlatformId_Microsoft = 3
+        };
+
+        quint16 length = getUShort(names + 8 + i*NameRecordSize);
+        quint16 offset = getUShort(names + 10 + i*NameRecordSize);
+        if(DWORD(string_offset + offset + length) >= bytes)
+            continue;
+
+        if ((platform_id == PlatformId_Microsoft
+            && (encoding_id == 0 || encoding_id == 1))
+            && (language_id & 0x3ff) == MS_LangIdEnglish
+            && microsoft_id == -1)
+            microsoft_id = i;
+            // not sure if encoding id 4 for Unicode is utf16 or ucs4...
+        else if(platform_id == PlatformId_Unicode && encoding_id < 4 && unicode_id == -1)
+            unicode_id = i;
+        else if(platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0)
+            apple_id = i;
+    }
+    {
+        bool unicode = false;
+        int id = -1;
+        if(microsoft_id != -1) {
+            id = microsoft_id;
+            unicode = true;
+        } else if(apple_id != -1) {
+            id = apple_id;
+            unicode = false;
+        } else if (unicode_id != -1) {
+            id = unicode_id;
+            unicode = true;
+        }
+        if(id != -1) {
+            quint16 length = getUShort(names + 8 + id*NameRecordSize);
+            quint16 offset = getUShort(names + 10 + id*NameRecordSize);
+            if(unicode) {
+                // utf16
+
+                length /= 2;
+                i18n_name.resize(length);
+                QChar *uc = (QChar *) i18n_name.unicode();
+                const unsigned char *string = table + string_offset + offset;
+                for(int i = 0; i < length; ++i)
+                    uc[i] = getUShort(string + 2*i);
+            } else {
+                // Apple Roman
+
+                i18n_name.resize(length);
+                QChar *uc = (QChar *) i18n_name.unicode();
+                const unsigned char *string = table + string_offset + offset;
+                for(int i = 0; i < length; ++i)
+                    uc[i] = QLatin1Char(string[i]);
+            }
+        }
+    }
+  error:
+    //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
+    return i18n_name;
+}
+
+static QString getEnglishName(const QString &familyName)
+{
+    QString i18n_name;
+
+    HDC hdc = GetDC( 0 );
+    LOGFONT lf;
+    memset(&lf, 0, sizeof(LOGFONT));
+    memcpy(lf.lfFaceName, familyName.utf16(), qMin(LF_FACESIZE, familyName.length()) * sizeof(wchar_t));
+    lf.lfCharSet = DEFAULT_CHARSET;
+    HFONT hfont = CreateFontIndirect(&lf);
+
+    if(!hfont) {
+        ReleaseDC(0, hdc);
+        return QString();
+    }
+
+    HGDIOBJ oldobj = SelectObject( hdc, hfont );
+
+    const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' );
+
+    // get the name table
+    unsigned char *table = 0;
+
+    DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 );
+    if ( bytes == GDI_ERROR ) {
+        // ### Unused variable
+        /* int err = GetLastError(); */
+        goto error;
+    }
+
+    table = new unsigned char[bytes];
+    GetFontData(hdc, name_tag, 0, table, bytes);
+    if ( bytes == GDI_ERROR )
+        goto error;
+
+    i18n_name = getEnglishName(table, bytes);
+error:
+    delete [] table;
+    SelectObject( hdc, oldobj );
+    DeleteObject( hfont );
+    ReleaseDC( 0, hdc );
+
+    //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
+    return i18n_name;
+}
+
+static
+void addFontToDatabase(QString familyName, const QString &scriptName,
+                       TEXTMETRIC *textmetric,
+                       const FONTSIGNATURE *signature,
+                       int type)
+{
+    const int script = -1;
+    const QString foundryName;
+    Q_UNUSED(script);
+
+    bool italic = false;
+    int weight;
+    bool fixed;
+    bool ttf;
+    bool scalable;
+    int size;
+
+//    QString escript = QString::fromWCharArray(f->elfScript);
+//    qDebug("script=%s", escript.latin1());
+
+    NEWTEXTMETRIC *tm = (NEWTEXTMETRIC *)textmetric;
+    fixed = !(tm->tmPitchAndFamily & TMPF_FIXED_PITCH);
+    ttf = (tm->tmPitchAndFamily & TMPF_TRUETYPE);
+    scalable = tm->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE);
+    size = scalable ? SMOOTH_SCALABLE : tm->tmHeight;
+    italic = tm->tmItalic;
+    weight = tm->tmWeight;
+
+    // the "@family" fonts are just the same as "family". Ignore them.
+    if (familyName[0] != QLatin1Char('@') && !familyName.startsWith(QLatin1String("WST_"))) {
+        QtFontStyle::Key styleKey;
+        styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
+        if (weight < 400)
+            styleKey.weight = QFont::Light;
+        else if (weight < 600)
+            styleKey.weight = QFont::Normal;
+        else if (weight < 700)
+            styleKey.weight = QFont::DemiBold;
+        else if (weight < 800)
+            styleKey.weight = QFont::Bold;
+        else
+            styleKey.weight = QFont::Black;
+
+        QtFontFamily *family = privateDb()->family(familyName, true);
+
+        if(ttf && localizedName(familyName) && family->english_name.isEmpty())
+            family->english_name = getEnglishName(familyName);
+
+        QtFontFoundry *foundry = family->foundry(foundryName, true);
+        QtFontStyle *style = foundry->style(styleKey, true);
+        style->smoothScalable = scalable;
+        style->pixelSize( size, TRUE);
+
+        // add fonts windows can generate for us:
+        if (styleKey.weight <= QFont::DemiBold) {
+            QtFontStyle::Key key(styleKey);
+            key.weight = QFont::Bold;
+            QtFontStyle *style = foundry->style(key, true);
+            style->smoothScalable = scalable;
+            style->pixelSize( size, TRUE);
+        }
+        if (styleKey.style != QFont::StyleItalic) {
+            QtFontStyle::Key key(styleKey);
+            key.style = QFont::StyleItalic;
+            QtFontStyle *style = foundry->style(key, true);
+            style->smoothScalable = scalable;
+            style->pixelSize( size, TRUE);
+        }
+        if (styleKey.weight <= QFont::DemiBold && styleKey.style != QFont::StyleItalic) {
+            QtFontStyle::Key key(styleKey);
+            key.weight = QFont::Bold;
+            key.style = QFont::StyleItalic;
+            QtFontStyle *style = foundry->style(key, true);
+            style->smoothScalable = scalable;
+            style->pixelSize( size, TRUE);
+        }
+
+        family->fixedPitch = fixed;
+
+        if (!family->writingSystemCheck && type & TRUETYPE_FONTTYPE) {
+            quint32 unicodeRange[4] = {
+                signature->fsUsb[0], signature->fsUsb[1],
+                signature->fsUsb[2], signature->fsUsb[3]
+            };
+#ifdef Q_WS_WINCE
+            if (signature->fsUsb[0] == 0) {
+                // If the unicode ranges bit mask is zero then
+                // EnumFontFamiliesEx failed to determine it properly.
+                // In this case we just pretend that the font supports all languages.
+                unicodeRange[0] = 0xbfffffff;   // second most significant bit must be zero
+                unicodeRange[1] = 0xffffffff;
+                unicodeRange[2] = 0xffffffff;
+                unicodeRange[3] = 0xffffffff;
+            }
+#endif
+            quint32 codePageRange[2] = {
+                signature->fsCsb[0], signature->fsCsb[1]
+            };
+            QList<QFontDatabase::WritingSystem> systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
+            for (int i = 0; i < systems.count(); ++i)
+                family->writingSystems[systems.at(i)] = QtFontFamily::Supported;
+        } else if (!family->writingSystemCheck) {
+            //qDebug("family='%s' script=%s", family->name.latin1(), script.latin1());
+            if (scriptName == QLatin1String("Western")
+                || scriptName == QLatin1String("Baltic")
+                || scriptName == QLatin1String("Central European")
+                || scriptName == QLatin1String("Turkish")
+                || scriptName == QLatin1String("Vietnamese"))
+                family->writingSystems[QFontDatabase::Latin] = QtFontFamily::Supported;
+            else if (scriptName == QLatin1String("Thai"))
+                family->writingSystems[QFontDatabase::Thai] = QtFontFamily::Supported;
+            else if (scriptName == QLatin1String("Symbol")
+                     || scriptName == QLatin1String("Other"))
+                family->writingSystems[QFontDatabase::Symbol] = QtFontFamily::Supported;
+            else if (scriptName == QLatin1String("OEM/Dos"))
+                family->writingSystems[QFontDatabase::Latin] = QtFontFamily::Supported;
+            else if (scriptName == QLatin1String("CHINESE_GB2312"))
+                family->writingSystems[QFontDatabase::SimplifiedChinese] = QtFontFamily::Supported;
+            else if (scriptName == QLatin1String("CHINESE_BIG5"))
+                family->writingSystems[QFontDatabase::TraditionalChinese] = QtFontFamily::Supported;
+            else if (scriptName == QLatin1String("Cyrillic"))
+                family->writingSystems[QFontDatabase::Cyrillic] = QtFontFamily::Supported;
+            else if (scriptName == QLatin1String("Hangul"))
+                family->writingSystems[QFontDatabase::Korean] = QtFontFamily::Supported;
+            else if (scriptName == QLatin1String("Hebrew"))
+                family->writingSystems[QFontDatabase::Hebrew] = QtFontFamily::Supported;
+            else if (scriptName == QLatin1String("Greek"))
+                family->writingSystems[QFontDatabase::Greek] = QtFontFamily::Supported;
+            else if (scriptName == QLatin1String("Japanese"))
+                family->writingSystems[QFontDatabase::Japanese] = QtFontFamily::Supported;
+            else if (scriptName == QLatin1String("Arabic"))
+                family->writingSystems[QFontDatabase::Arabic] = QtFontFamily::Supported;
+        }
+    }
+}
+
+static
+int CALLBACK
+storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric, int type, LPARAM /*p*/)
+{
+    QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName);
+    QString script = QString::fromWCharArray(f->elfScript);
+
+    FONTSIGNATURE signature = textmetric->ntmFontSig;
+
+    // NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is
+    // identical to a TEXTMETRIC except for the last four members, which we don't use
+    // anyway
+    addFontToDatabase(familyName, script, (TEXTMETRIC *)textmetric, &signature, type);
+    // keep on enumerating
+    return 1;
+}
+
+static
+void populate_database(const QString& fam)
+{
+    QFontDatabasePrivate *d = privateDb();
+    if (!d)
+        return;
+
+    QtFontFamily *family = 0;
+    if(!fam.isEmpty()) {
+        family = d->family(fam);
+        if(family && family->loaded)
+            return;
+    } else if (d->count) {
+        return;
+    }
+
+    HDC dummy = GetDC(0);
+
+    LOGFONT lf;
+    lf.lfCharSet = DEFAULT_CHARSET;
+    if (fam.isNull()) {
+        lf.lfFaceName[0] = 0;
+    } else {
+        memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32));  // 32 = Windows hard-coded
+    }
+    lf.lfPitchAndFamily = 0;
+
+    EnumFontFamiliesEx(dummy, &lf,
+        (FONTENUMPROC)storeFont, (LPARAM)privateDb(), 0);
+
+    ReleaseDC(0, dummy);
+
+    for (int i = 0; i < d->applicationFonts.count(); ++i) {
+        QFontDatabasePrivate::ApplicationFont fnt = d->applicationFonts.at(i);
+        if (!fnt.memoryFont)
+            continue;
+        for (int j = 0; j < fnt.families.count(); ++j) {
+            const QString familyName = fnt.families.at(j);
+            HDC hdc = GetDC(0);
+            LOGFONT lf;
+            memset(&lf, 0, sizeof(LOGFONT));
+            memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE, familyName.size()));
+            lf.lfCharSet = DEFAULT_CHARSET;
+            HFONT hfont = CreateFontIndirect(&lf);
+            HGDIOBJ oldobj = SelectObject(hdc, hfont);
+
+            TEXTMETRIC textMetrics;
+            GetTextMetrics(hdc, &textMetrics);
+
+            addFontToDatabase(familyName, QString(),
+                              &textMetrics,
+                              &fnt.signatures.at(j),
+                              TRUETYPE_FONTTYPE);
+
+            SelectObject(hdc, oldobj);
+            DeleteObject(hfont);
+            ReleaseDC(0, hdc);
+        }
+    }
+
+    if(!fam.isEmpty()) {
+        family = d->family(fam);
+        if(family) {
+            if(!family->writingSystemCheck) {
+            }
+            family->loaded = true;
+        }
+    }
+}
+
+static void initializeDb()
+{
+    QFontDatabasePrivate *db = privateDb();
+    if (!db || db->count)
+        return;
+
+    populate_database(QString());
+
+#ifdef QFONTDATABASE_DEBUG
+    // print the database
+    for (int f = 0; f < db->count; f++) {
+        QtFontFamily *family = db->families[f];
+        qDebug("    %s: %p", qPrintable(family->name), family);
+        populate_database(family->name);
+
+#if 0
+        qDebug("        scripts supported:");
+        for (int i = 0; i < QUnicodeTables::ScriptCount; i++)
+            if(family->writingSystems[i] & QtFontFamily::Supported)
+                qDebug("            %d", i);
+        for (int fd = 0; fd < family->count; fd++) {
+            QtFontFoundry *foundry = family->foundries[fd];
+            qDebug("        %s", foundry->name.latin1());
+            for (int s = 0; s < foundry->count; s++) {
+                QtFontStyle *style = foundry->styles[s];
+                qDebug("            style: style=%d weight=%d smooth=%d",  style->key.style,
+                       style->key.weight, style->smoothScalable );
+                if(!style->smoothScalable) {
+                    for(int i = 0; i < style->count; ++i) {
+                        qDebug("                %d", style->pixelSizes[i].pixelSize);
+                    }
+                }
+            }
+        }
+#endif
+    }
+#endif // QFONTDATABASE_DEBUG
+
+}
+
+static inline void load(const QString &family = QString(), int = -1)
+{
+    populate_database(family);
+}
+
+
+
+
+
+// --------------------------------------------------------------------------------------
+// font loader
+// --------------------------------------------------------------------------------------
+
+
+
+static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, const QFontPrivate *fp)
+{
+    fe->fontDef = request;                                // most settings are equal
+
+    HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fp->hdc) ? fp->hdc : shared_dc();
+    SelectObject(dc, fe->hfont);
+    wchar_t n[64];
+    GetTextFace(dc, 64, n);
+    fe->fontDef.family = QString::fromWCharArray(n);
+    fe->fontDef.fixedPitch = !(fe->tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
+    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.);
+    }
+}
+
+
+static const char *other_tryFonts[] = {
+    "Arial",
+    "MS UI Gothic",
+    "Gulim",
+    "SimSun",
+    "PMingLiU",
+    "Arial Unicode MS",
+    0
+};
+
+static const char *jp_tryFonts [] = {
+    "MS UI Gothic",
+    "Arial",
+    "Gulim",
+    "SimSun",
+    "PMingLiU",
+    "Arial Unicode MS",
+    0
+};
+
+static const char *ch_CN_tryFonts [] = {
+    "SimSun",
+    "Arial",
+    "PMingLiU",
+    "Gulim",
+    "MS UI Gothic",
+    "Arial Unicode MS",
+    0
+};
+
+static const char *ch_TW_tryFonts [] = {
+    "PMingLiU",
+    "Arial",
+    "SimSun",
+    "Gulim",
+    "MS UI Gothic",
+    "Arial Unicode MS",
+    0
+};
+
+static const char *kr_tryFonts[] = {
+    "Gulim",
+    "Arial",
+    "PMingLiU",
+    "SimSun",
+    "MS UI Gothic",
+    "Arial Unicode MS",
+    0
+};
+
+static const char **tryFonts = 0;
+
+
+static inline HFONT systemFont()
+{
+    if (stock_sysfont == 0)
+        stock_sysfont = (HFONT)GetStockObject(SYSTEM_FONT);
+    return stock_sysfont;
+}
+
+#if !defined(DEFAULT_GUI_FONT)
+#define DEFAULT_GUI_FONT 17
+#endif
+
+static
+QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &request, const QtFontDesc *desc,
+                        const QStringList &family_list)
+{
+    LOGFONT lf;
+    memset(&lf, 0, sizeof(LOGFONT));
+
+    bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fp->hdc;
+
+    HDC hdc = shared_dc();
+    QString font_name = desc->family->name;
+
+    if (useDevice) {
+        hdc = fp->hdc;
+        font_name = request.family;
+    }
+
+    bool stockFont = false;
+    bool preferClearTypeAA = false;
+
+    HFONT hfont = 0;
+
+    if (fp->rawMode) {                        // will choose a stock font
+        int f, deffnt = SYSTEM_FONT;
+        QString fam = desc->family->name.toLower();
+        if (fam == QLatin1String("default"))
+            f = deffnt;
+        else if (fam == QLatin1String("system"))
+            f = SYSTEM_FONT;
+#ifndef Q_WS_WINCE
+        else if (fam == QLatin1String("system_fixed"))
+            f = SYSTEM_FIXED_FONT;
+        else if (fam == QLatin1String("ansi_fixed"))
+            f = ANSI_FIXED_FONT;
+        else if (fam == QLatin1String("ansi_var"))
+            f = ANSI_VAR_FONT;
+        else if (fam == QLatin1String("device_default"))
+            f = DEVICE_DEFAULT_FONT;
+        else if (fam == QLatin1String("oem_fixed"))
+            f = OEM_FIXED_FONT;
+#endif
+        else if (fam[0] == QLatin1Char('#'))
+            f = fam.right(fam.length()-1).toInt();
+        else
+            f = deffnt;
+        hfont = (HFONT)GetStockObject(f);
+        if (!hfont) {
+            qErrnoWarning("QFontEngine::loadEngine: GetStockObject failed");
+            hfont = systemFont();
+        }
+        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 = -request.pixelSize;
+        lf.lfWidth                = 0;
+        lf.lfEscapement        = 0;
+        lf.lfOrientation        = 0;
+        if (desc->style->key.weight == 50)
+            lf.lfWeight = FW_DONTCARE;
+        else
+            lf.lfWeight = (desc->style->key.weight*900)/99;
+        lf.lfItalic                = (desc->style->key.style != QFont::StyleNormal);
+        lf.lfCharSet        = DEFAULT_CHARSET;
+
+        int strat = OUT_DEFAULT_PRECIS;
+        if (request.styleStrategy & QFont::PreferBitmap) {
+            strat = OUT_RASTER_PRECIS;
+#ifndef Q_WS_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_WS_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 = font_name;
+
+        if(fam.isEmpty())
+            fam = QLatin1String("MS Sans Serif");
+
+        if ((fam == QLatin1String("MS Sans Serif"))
+            && (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) {
+            fam = QLatin1String("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale
+        }
+        if (fam == QLatin1String("Courier") && !(request.styleStrategy & QFont::PreferBitmap))
+            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");
+
+        stockFont = (hfont == 0);
+        bool ttf = false;
+        int avWidth = 0;
+        BOOL res;
+        HGDIOBJ oldObj = SelectObject(hdc, hfont);
+
+        TEXTMETRIC tm;
+        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");
+        }
+
+#ifndef Q_WS_WINCE
+        if (hfont == 0) {
+            hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
+            stockFont = true;
+        }
+#else
+        if (hfont == 0) {
+            hfont = (HFONT)GetStockObject(SYSTEM_FONT);
+            stockFont = 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 = few;
+    initFontInfo(few, request, fp);
+    if(script == QUnicodeTables::Common
+       && !(request.styleStrategy & QFont::NoFontMerging)
+       && !(desc->family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) {
+        if(!tryFonts) {
+            LANGID lid = GetUserDefaultLangID();
+            switch( lid&0xff ) {
+            case LANG_CHINESE: // Chinese (Taiwan)
+                if ( lid == 0x0804 ) // Taiwan
+                    tryFonts = ch_TW_tryFonts;
+                else
+                    tryFonts = ch_CN_tryFonts;
+                break;
+            case LANG_JAPANESE:
+                tryFonts = jp_tryFonts;
+                break;
+            case LANG_KOREAN:
+                tryFonts = kr_tryFonts;
+                break;
+            default:
+                tryFonts = other_tryFonts;
+                break;
+            }
+        }
+        QStringList fm = QFontDatabase().families();
+        QStringList list = family_list;
+        const char **tf = tryFonts;
+        while(tf && *tf) {
+            if(fm.contains(QLatin1String(*tf)))
+                list << QLatin1String(*tf);
+            ++tf;
+        }
+        QFontEngine *mfe = new QFontEngineMultiWin(few, list);
+        mfe->fontDef = fe->fontDef;
+        fe = mfe;
+    }
+    return fe;
+}
+
+const char *styleHint(const QFontDef &request)
+{
+    const char *stylehint = 0;
+    switch (request.styleHint) {
+    case QFont::SansSerif:
+        stylehint = "Arial";
+        break;
+    case QFont::Serif:
+        stylehint = "Times New Roman";
+        break;
+    case QFont::TypeWriter:
+        stylehint = "Courier New";
+        break;
+    default:
+        if (request.fixedPitch)
+            stylehint = "Courier New";
+        break;
+    }
+    return stylehint;
+}
+
+static QFontEngine *loadWin(const QFontPrivate *d, int script, const QFontDef &req)
+{
+    // list of families to try
+    QStringList family_list = familyList(req);
+
+    const char *stylehint = styleHint(d->request);
+    if (stylehint)
+        family_list << QLatin1String(stylehint);
+
+    // append the default fallback font for the specified script
+    // family_list << ... ; ###########
+
+    // add the default family
+    QString defaultFamily = QApplication::font().family();
+    if (! family_list.contains(defaultFamily))
+        family_list << defaultFamily;
+
+    // add QFont::defaultFamily() to the list, for compatibility with
+    // previous versions
+    family_list << QApplication::font().defaultFamily();
+
+    // null family means find the first font matching the specified script
+    family_list << QString();
+
+    QtFontDesc desc;
+    QFontEngine *fe = 0;
+    QList<int> blacklistedFamilies;
+
+    while (!fe) {
+        for (int i = 0; i < family_list.size(); ++i) {
+            QString family, foundry;
+            parseFontName(family_list.at(i), foundry, family);
+            FM_DEBUG("loadWin: >>>>>>>>>>>>>>trying to match '%s'", family.toLatin1().data());
+            QT_PREPEND_NAMESPACE(match)(script, req, family, foundry, -1, &desc, blacklistedFamilies);
+            if (desc.family)
+                break;
+        }
+        if (!desc.family)
+            break;
+        fe = loadEngine(script, d, req, &desc, family_list);
+        if (!fe)
+            blacklistedFamilies.append(desc.familyIndex);
+    }
+    return fe;
+}
+
+
+void QFontDatabase::load(const QFontPrivate *d, int script)
+{
+    // sanity checks
+    if (!qApp)
+        qWarning("QFontDatabase::load: Must construct QApplication first");
+    Q_ASSERT(script >= 0 && script < QUnicodeTables::ScriptCount);
+
+    // normalize the request to get better caching
+    QFontDef req = d->request;
+    if (req.pixelSize <= 0)
+        req.pixelSize = qMax(1, qRound(req.pointSize * d->dpi / 72.));
+    req.pointSize = 0;
+    if (req.weight == 0)
+        req.weight = QFont::Normal;
+    if (req.stretch == 0)
+        req.stretch = 100;
+
+    QFontCache::Key key(req, d->rawMode ? QUnicodeTables::Common : script, d->screen);
+    if (!d->engineData)
+        getEngineData(d, key);
+
+    // the cached engineData could have already loaded the engine we want
+    if (d->engineData->engines[script])
+        return;
+
+    QFontEngine *fe = QFontCache::instance()->findEngine(key);
+
+    // set it to the actual pointsize, so QFontInfo will do the right thing
+    req.pointSize = req.pixelSize*72./d->dpi;
+
+    if (!fe) {
+        if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
+            fe = new QTestFontEngine(req.pixelSize);
+            fe->fontDef = req;
+        } else {
+            QMutexLocker locker(fontDatabaseMutex());
+            if (!privateDb()->count)
+                initializeDb();
+            fe = loadWin(d, script, req);
+        }
+        if (!fe) {
+            fe = new QFontEngineBox(req.pixelSize);
+            fe->fontDef = QFontDef();
+        }
+    }
+    d->engineData->engines[script] = fe;
+    fe->ref.ref();
+    QFontCache::instance()->insertEngine(key, fe);
+}
+
+#if !defined(FR_PRIVATE)
+#define FR_PRIVATE 0x10
+#endif
+
+typedef int (WINAPI *PtrAddFontResourceExW)(LPCWSTR, DWORD, PVOID);
+typedef HANDLE (WINAPI *PtrAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
+typedef BOOL (WINAPI *PtrRemoveFontResourceExW)(LPCWSTR, DWORD, PVOID);
+typedef BOOL (WINAPI *PtrRemoveFontMemResourceEx)(HANDLE);
+
+static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData)
+{
+    QList<quint32> offsets;
+    const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData);
+    if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) {
+        if (headerTag != MAKE_TAG(0, 1, 0, 0)
+            && headerTag != MAKE_TAG('O', 'T', 'T', 'O')
+            && headerTag != MAKE_TAG('t', 'r', 'u', 'e')
+            && headerTag != MAKE_TAG('t', 'y', 'p', '1'))
+            return offsets;
+        offsets << 0;
+        return offsets;
+    }
+    const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8);
+    for (uint i = 0; i < numFonts; ++i) {
+        offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
+    }
+    return offsets;
+}
+
+static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
+{
+    const quint16 numTables = qFromBigEndian<quint16>(data + 4);
+    for (uint i = 0; i < numTables; ++i) {
+        const quint32 offset = 12 + 16 * i;
+        if (*reinterpret_cast<const quint32 *>(data + offset) == tag) {
+            *table = fileBegin + qFromBigEndian<quint32>(data + offset + 8);
+            *length = qFromBigEndian<quint32>(data + offset + 12);
+            return;
+        }
+    }
+    *table = 0;
+    *length = 0;
+    return;
+}
+
+static void getFamiliesAndSignatures(const QByteArray &fontData, QFontDatabasePrivate::ApplicationFont *appFont)
+{
+    const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
+
+    QList<quint32> offsets = getTrueTypeFontOffsets(data);
+    if (offsets.isEmpty())
+        return;
+
+    for (int i = 0; i < offsets.count(); ++i) {
+        const uchar *font = data + offsets.at(i);
+        const uchar *table;
+        quint32 length;
+        getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
+        if (!table)
+            continue;
+        QString name = getEnglishName(table, length);
+        if (name.isEmpty())
+            continue;
+
+        appFont->families << name;
+        FONTSIGNATURE signature;
+        getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
+        if (table && length >= 86) {
+            // See also qfontdatabase_mac.cpp, offsets taken from OS/2 table in the TrueType spec
+            signature.fsUsb[0] = qFromBigEndian<quint32>(table + 42);
+            signature.fsUsb[1] = qFromBigEndian<quint32>(table + 46);
+            signature.fsUsb[2] = qFromBigEndian<quint32>(table + 50);
+            signature.fsUsb[3] = qFromBigEndian<quint32>(table + 54);
+
+            signature.fsCsb[0] = qFromBigEndian<quint32>(table + 78);
+            signature.fsCsb[1] = qFromBigEndian<quint32>(table + 82);
+        } else {
+            memset(&signature, 0, sizeof(signature));
+        }
+        appFont->signatures << signature;
+    }
+}
+
+static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
+{
+    if(!fnt->data.isEmpty()) {
+#ifndef Q_OS_WINCE
+        PtrAddFontMemResourceEx ptrAddFontMemResourceEx = (PtrAddFontMemResourceEx)QLibrary::resolve(QLatin1String("gdi32"),
+                                                                                                     "AddFontMemResourceEx");
+        if (!ptrAddFontMemResourceEx)
+            return;
+#endif
+        getFamiliesAndSignatures(fnt->data, fnt);
+        if (fnt->families.isEmpty())
+            return;
+
+#ifdef Q_OS_WINCE
+        HANDLE handle = 0;
+
+        {
+#ifdef QT_NO_TEMPORARYFILE
+           wchar_t lpBuffer[MAX_PATH];
+           GetTempPath(MAX_PATH, lpBuffer);
+           QString s = QString::fromWCharArray(lpBuffer);
+           QFile tempfile(s + QLatin1String("/font") + QString::number(GetTickCount()) + QLatin1String(".ttf"));
+           if (!tempfile.open(QIODevice::ReadWrite))
+#else
+            QTemporaryFile tempfile(QLatin1String("XXXXXXXX.ttf"));
+            if (!tempfile.open())
+#endif // QT_NO_TEMPORARYFILE
+                return;
+            if (tempfile.write(fnt->data) == -1)
+                return;
+
+#ifndef QT_NO_TEMPORARYFILE
+            tempfile.setAutoRemove(false);
+#endif
+            fnt->fileName = QFileInfo(tempfile.fileName()).absoluteFilePath();
+        }
+
+        if (AddFontResource((LPCWSTR)fnt->fileName.utf16()) == 0) {
+            QFile(fnt->fileName).remove();
+            return;
+        }
+#else
+        DWORD dummy = 0;
+        HANDLE handle = ptrAddFontMemResourceEx((void *)fnt->data.constData(), fnt->data.size(), 0,
+                                                &dummy);
+        if (handle == 0)
+            return;
+#endif // Q_OS_WINCE
+
+        fnt->handle = handle;
+        fnt->data = QByteArray();
+        fnt->memoryFont = true;
+    } else {
+        QFile f(fnt->fileName);
+        if (!f.open(QIODevice::ReadOnly))
+            return;
+        QByteArray data = f.readAll();
+        f.close();
+        getFamiliesAndSignatures(data, fnt);
+
+#ifdef Q_OS_WINCE
+        QFileInfo fileinfo(fnt->fileName);
+        fnt->fileName = fileinfo.absoluteFilePath();
+        if (AddFontResource((LPCWSTR)fnt->fileName.utf16()) == 0)
+            return;
+#else
+        // supported from 2000 on, so no need to deal with the *A variant
+        PtrAddFontResourceExW ptrAddFontResourceExW = (PtrAddFontResourceExW)QLibrary::resolve(QLatin1String("gdi32"),
+                                                                                               "AddFontResourceExW");
+        if (!ptrAddFontResourceExW
+            || ptrAddFontResourceExW((wchar_t*)fnt->fileName.utf16(), FR_PRIVATE, 0) == 0)
+            return;
+#endif // Q_OS_WINCE
+
+        fnt->memoryFont = false;
+    }
+}
+
+bool QFontDatabase::removeApplicationFont(int handle)
+{
+    QMutexLocker locker(fontDatabaseMutex());
+
+    QFontDatabasePrivate *db = privateDb();
+    if (handle < 0 || handle >= db->applicationFonts.count())
+        return false;
+
+    const QFontDatabasePrivate::ApplicationFont font = db->applicationFonts.at(handle);
+    db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
+    if (font.memoryFont) {
+#ifdef Q_OS_WINCE
+        bool removeSucceeded = RemoveFontResource((LPCWSTR)font.fileName.utf16());
+        QFile tempfile(font.fileName);
+        tempfile.remove();
+        if (!removeSucceeded)
+            return false;
+#else
+        PtrRemoveFontMemResourceEx ptrRemoveFontMemResourceEx = (PtrRemoveFontMemResourceEx)QLibrary::resolve(QLatin1String("gdi32"),
+                                                                                                              "RemoveFontMemResourceEx");
+        if (!ptrRemoveFontMemResourceEx
+            || !ptrRemoveFontMemResourceEx(font.handle))
+            return false;
+#endif // Q_OS_WINCE
+    } else {
+#ifdef Q_OS_WINCE
+        if (!RemoveFontResource((LPCWSTR)font.fileName.utf16()))
+            return false;
+#else
+        PtrRemoveFontResourceExW ptrRemoveFontResourceExW = (PtrRemoveFontResourceExW)QLibrary::resolve(QLatin1String("gdi32"),
+                                                                                                        "RemoveFontResourceExW");
+        if (!ptrRemoveFontResourceExW
+            || !ptrRemoveFontResourceExW((LPCWSTR)font.fileName.utf16(), FR_PRIVATE, 0))
+            return false;
+#endif // Q_OS_WINCE
+    }
+
+    db->invalidate();
+    return true;
+}
+
+bool QFontDatabase::removeAllApplicationFonts()
+{
+    QMutexLocker locker(fontDatabaseMutex());
+
+    QFontDatabasePrivate *db = privateDb();
+    for (int i = 0; i < db->applicationFonts.count(); ++i)
+        if (!removeApplicationFont(i))
+            return false;
+    return true;
+}
+
+bool QFontDatabase::supportsThreadedFontRendering()
+{
+    return true;
+}
+
+QT_END_NAMESPACE