From 0b8d0804219b7e2e6179112d663b989d5b749d17 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 17 Aug 2011 15:58:39 +0200 Subject: Add Windows to the Lighthouse. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an initial Lighthouse plugin for the Windows operating system. Change-Id: I6934562266e1aa0ac270bf6107df05a9e56ef82c Reviewed-on: http://codereview.qt.nokia.com/3107 Reviewed-by: Oliver Wolff Reviewed-by: Samuel Rødal --- .../platforms/windows/qwindowsfontdatabase.cpp | 950 +++++++++++++++++++++ 1 file changed, 950 insertions(+) create mode 100644 src/plugins/platforms/windows/qwindowsfontdatabase.cpp (limited to 'src/plugins/platforms/windows/qwindowsfontdatabase.cpp') diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp new file mode 100644 index 0000000000..ea35ab5f9f --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -0,0 +1,950 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsfontdatabase.h" +#include "qwindowscontext.h" +#include "qwindowsfontengine.h" +#include "qwindowsfontenginedirectwrite.h" +#include "qtwindows_additional.h" + +#include +#include + +#include +#include + +#if !defined(QT_NO_DIRECTWRITE) +# include +# include +#endif + +QT_BEGIN_NAMESPACE + +/*! + \struct QWindowsFontEngineData + \brief Static constant data shared by the font engines. + \ingroup qt-lighthouse-win +*/ + +QWindowsFontEngineData::QWindowsFontEngineData() +#if !defined(QT_NO_DIRECTWRITE) + : directWriteFactory(0) + , directWriteGdiInterop(0) +#endif +{ + // from qapplication_win.cpp + UINT result = 0; + if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0)) + clearTypeEnabled = (result == FE_FONTSMOOTHINGCLEARTYPE); + + int winSmooth; + if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0)) { + fontSmoothingGamma = winSmooth / qreal(1000.0); + } else { + fontSmoothingGamma = 1.0; + } + + // Safeguard ourselves against corrupt registry values... + if (fontSmoothingGamma > 5 || fontSmoothingGamma < 1) + fontSmoothingGamma = qreal(1.4); + + const qreal gray_gamma = 2.31; + for (int i=0; i<256; ++i) + pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047)); + + HDC displayDC = GetDC(0); + hdc = CreateCompatibleDC(displayDC); + ReleaseDC(0, displayDC); +} + +QWindowsFontEngineData::~QWindowsFontEngineData() +{ + if (hdc) + ReleaseDC(0, hdc); +#if !defined(QT_NO_DIRECTWRITE) + if (directWriteGdiInterop) + directWriteGdiInterop->Release(); + if (directWriteFactory) + directWriteFactory->Release(); +#endif +} + +#if !defined(QT_NO_DIRECTWRITE) +static inline bool initDirectWrite(QWindowsFontEngineData *d) +{ + if (!d->directWriteFactory) { + const HRESULT hr = DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast(&d->directWriteFactory) + ); + if (FAILED(hr)) { + qErrnoWarning("%s: DWriteCreateFactory failed", __FUNCTION__); + return false; + } + } + if (!d->directWriteGdiInterop) { + const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop); + if (FAILED(hr)) { + qErrnoWarning("%s: GetGdiInterop failed", __FUNCTION__); + return false; + } + } + return true; +} + +#endif // !defined(QT_NO_DIRECTWRITE) + +/*! + \class QWindowsFontDatabase + \brief Font database for Windows + + \note The Qt 4.8 WIndows font database employed a mechanism of + delayed population of the database again passing a font name + to EnumFontFamiliesEx(), working around the fact that + EnumFontFamiliesEx() does not list all fonts by default. + This should be introduced to Lighthouse as well? + + \ingroup qt-lighthouse-win +*/ + +QDebug operator<<(QDebug d, const QFontDef &def) +{ + d.nospace() << "Family=" << def.family << " Stylename=" << def.styleName + << " pointsize=" << def.pointSize << " pixelsize=" << def.pixelSize + << " styleHint=" << def.styleHint << " weight=" << def.weight + << " stretch=" << def.stretch << " hintingPreference=" + << def.hintingPreference << ' '; + return d; +} + +/* From QFontDatabase.cpp, qt_determine_writing_systems_from_truetype_bits(). + * Fixme: Make public? */ + +// see the Unicode subset bitfields in the MSDN docs +static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { + // Any, + { 127, 127 }, + // Latin, + { 0, 127 }, + // Greek, + { 7, 127 }, + // Cyrillic, + { 9, 127 }, + // Armenian, + { 10, 127 }, + // Hebrew, + { 11, 127 }, + // Arabic, + { 13, 127 }, + // Syriac, + { 71, 127 }, + //Thaana, + { 72, 127 }, + //Devanagari, + { 15, 127 }, + //Bengali, + { 16, 127 }, + //Gurmukhi, + { 17, 127 }, + //Gujarati, + { 18, 127 }, + //Oriya, + { 19, 127 }, + //Tamil, + { 20, 127 }, + //Telugu, + { 21, 127 }, + //Kannada, + { 22, 127 }, + //Malayalam, + { 23, 127 }, + //Sinhala, + { 73, 127 }, + //Thai, + { 24, 127 }, + //Lao, + { 25, 127 }, + //Tibetan, + { 70, 127 }, + //Myanmar, + { 74, 127 }, + // Georgian, + { 26, 127 }, + // Khmer, + { 80, 127 }, + // SimplifiedChinese, + { 126, 127 }, + // TraditionalChinese, + { 126, 127 }, + // Japanese, + { 126, 127 }, + // Korean, + { 56, 127 }, + // Vietnamese, + { 0, 127 }, // same as latin1 + // Other, + { 126, 127 }, + // Ogham, + { 78, 127 }, + // Runic, + { 79, 127 }, + // Nko, + { 14, 127 }, +}; + +enum +{ + SimplifiedChineseCsbBit = 18, + TraditionalChineseCsbBit = 20, + JapaneseCsbBit = 17, + KoreanCsbBit = 21 +}; + +static inline void writingSystemsFromTrueTypeBits(quint32 unicodeRange[4], + quint32 codePageRange[2], + QSupportedWritingSystems *ws) +{ + bool hasScript = false; + for(int i = 0; i < QFontDatabase::WritingSystemsCount; i++) { + int bit = requiredUnicodeBits[i][0]; + int index = bit/32; + int flag = 1 << (bit&31); + if (bit != 126 && unicodeRange[index] & flag) { + bit = requiredUnicodeBits[i][1]; + index = bit/32; + + flag = 1 << (bit&31); + if (bit == 127 || unicodeRange[index] & flag) { + ws->setSupported(QFontDatabase::WritingSystem(i), true); + hasScript = true; + } + } + } + if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) { + ws->setSupported(QFontDatabase::SimplifiedChinese, true); + hasScript = true; + } + if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) { + ws->setSupported(QFontDatabase::TraditionalChinese, true); + hasScript = true; + } + if(codePageRange[0] & (1 << JapaneseCsbBit)) { + ws->setSupported(QFontDatabase::Japanese, true); + hasScript = true; + //qDebug("font %s supports Japanese", familyName.latin1()); + } + if(codePageRange[0] & (1 << KoreanCsbBit)) { + ws->setSupported(QFontDatabase::Korean, true); + hasScript = true; + } + if (!hasScript) + ws->setSupported(QFontDatabase::Symbol, true); +} + +// convert 0 ~ 1000 integer to QFont::Weight +static inline QFont::Weight weightFromInteger(long weight) +{ + if (weight < 400) + return QFont::Light; + if (weight < 600) + return QFont::Normal; + if (weight < 700) + return QFont::DemiBold; + if (weight < 800) + return QFont::Bold; + return QFont::Black; +} + +static inline QFontDatabase::WritingSystem writingSystemFromScript(const QString &scriptName) +{ + if (scriptName == QStringLiteral("Western") + || scriptName == QStringLiteral("Baltic") + || scriptName == QStringLiteral("Central European") + || scriptName == QStringLiteral("Turkish") + || scriptName == QStringLiteral("Vietnamese") + || scriptName == QStringLiteral("OEM/Dos")) + return QFontDatabase::Latin; + if (scriptName == QStringLiteral("Thai")) + return QFontDatabase::Thai; + if (scriptName == QStringLiteral("Symbol") + || scriptName == QStringLiteral("Other")) + return QFontDatabase::Symbol; + if (scriptName == QStringLiteral("CHINESE_GB2312")) + return QFontDatabase::SimplifiedChinese; + if (scriptName == QStringLiteral("CHINESE_BIG5")) + return QFontDatabase::TraditionalChinese; + if (scriptName == QStringLiteral("Cyrillic")) + return QFontDatabase::Cyrillic; + if (scriptName == QStringLiteral("Hangul")) + return QFontDatabase::Korean; + if (scriptName == QStringLiteral("Hebrew")) + return QFontDatabase::Hebrew; + if (scriptName == QStringLiteral("Greek")) + return QFontDatabase::Greek; + if (scriptName == QStringLiteral("Japanese")) + return QFontDatabase::Japanese; + if (scriptName == QStringLiteral("Arabic")) + return QFontDatabase::Arabic; + return QFontDatabase::Any; +} + +static bool addFontToDatabase(QString familyName, const QString &scriptName, + const TEXTMETRIC *textmetric, + const FONTSIGNATURE *signature, + int type) +{ + // the "@family" fonts are just the same as "family". Ignore them. + if (familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QStringLiteral("WST_"))) + return false; + + static const int SMOOTH_SCALABLE = 0xffff; + const QString foundryName; // No such concept. + const NEWTEXTMETRIC *tm = (NEWTEXTMETRIC *)textmetric; + const bool fixed = !(tm->tmPitchAndFamily & TMPF_FIXED_PITCH); + const bool ttf = (tm->tmPitchAndFamily & TMPF_TRUETYPE); + const bool scalable = tm->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE); + const int size = scalable ? SMOOTH_SCALABLE : tm->tmHeight; + const QFont::Style style = tm->tmItalic ? QFont::StyleItalic : QFont::StyleNormal; + const bool antialias = false; + const QFont::Weight weight = weightFromInteger(tm->tmWeight); + const QFont::Stretch stretch = QFont::Unstretched; + + Q_UNUSED(fixed) + + if (QWindowsContext::verboseFonts > 2) { + QDebug nospace = qDebug().nospace(); + nospace << __FUNCTION__ << familyName << scriptName + << "TTF=" << ttf; + if (type & DEVICE_FONTTYPE) + nospace << " DEVICE"; + if (type & RASTER_FONTTYPE) + nospace << " RASTER"; + if (type & TRUETYPE_FONTTYPE) + nospace << " TRUETYPE"; + nospace << " scalable=" << scalable << " Size=" << size + << " Style=" << style << " Weight=" << weight + << " stretch=" << stretch; + } + +/* Fixme: omitted for the moment + if(ttf && localizedName(familyName) && family->english_name.isEmpty()) + family->english_name = getEnglishName(familyName); +*/ + QSupportedWritingSystems writingSystems; + if (type & TRUETYPE_FONTTYPE) { + quint32 unicodeRange[4] = { + signature->fsUsb[0], signature->fsUsb[1], + signature->fsUsb[2], signature->fsUsb[3] + }; + quint32 codePageRange[2] = { + signature->fsCsb[0], signature->fsCsb[1] + }; + writingSystemsFromTrueTypeBits(unicodeRange, codePageRange, &writingSystems); + // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains + // the symbol for Baht, and Windows thus reports that it supports the Thai script. + // Since it's the default UI font on this platform, most widgets will be unable to + // display Thai text by default. As a temporary work around, we special case Segoe UI + // and remove the Thai script from its list of supported writing systems. + if (writingSystems.supported(QFontDatabase::Thai) && + familyName == QStringLiteral("Segoe UI")) + writingSystems.setSupported(QFontDatabase::Thai, false); + } else { + const QFontDatabase::WritingSystem ws = writingSystemFromScript(scriptName); + if (ws != QFontDatabase::Any) + writingSystems.setSupported(ws); + } + + QPlatformFontDatabase::registerFont(familyName, foundryName, weight, + style, stretch, antialias, scalable, size, writingSystems, 0); + // add fonts windows can generate for us: + if (weight <= QFont::DemiBold) + QPlatformFontDatabase::registerFont(familyName, foundryName, QFont::Bold, + style, stretch, antialias, scalable, size, writingSystems, 0); + if (style != QFont::StyleItalic) + QPlatformFontDatabase::registerFont(familyName, foundryName, weight, + QFont::StyleItalic, stretch, antialias, scalable, size, writingSystems, 0); + if (weight <= QFont::DemiBold && style != QFont::StyleItalic) + QPlatformFontDatabase::registerFont(familyName, foundryName, QFont::Bold, + QFont::StyleItalic, stretch, antialias, scalable, size, writingSystems, 0); + return true; +} + +static int CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric, + int type, LPARAM namesSetIn) +{ + typedef QSet StringSet; + const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName); + const QString script = QString::fromWCharArray(f->elfScript); + + const 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 + if (addFontToDatabase(familyName, script, (TEXTMETRIC *)textmetric, &signature, type)) + reinterpret_cast(namesSetIn)->insert(familyName); + + // keep on enumerating + return 1; +} + +void QWindowsFontDatabase::populateFontDatabase() +{ + if (m_families.isEmpty()) { + QPlatformFontDatabase::populateFontDatabase(); + populate(); // Called multiple times. + // Work around EnumFontFamiliesEx() not listing the system font, see below. + const QString sysFontFamily = QGuiApplication::font().family(); + if (!m_families.contains(sysFontFamily)) + populate(sysFontFamily); + } +} + +/*! + \brief Populate font database using EnumFontFamiliesEx(). + + Normally, leaving the name empty should enumerate + all fonts, however, system fonts like "MS Shell Dlg 2" + are only found when specifying the name explicitly. +*/ + +void QWindowsFontDatabase::populate(const QString &family) + { + + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << m_families.size() << family; + + HDC dummy = GetDC(0); + LOGFONT lf; + lf.lfCharSet = DEFAULT_CHARSET; + if (family.size() >= LF_FACESIZE) { + qWarning("%s: Unable to enumerate family '%s'.", + __FUNCTION__, qPrintable(family)); + return; + } + wmemcpy(lf.lfFaceName, reinterpret_cast(family.utf16()), + family.size() + 1); + lf.lfPitchAndFamily = 0; + EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)storeFont, + (LPARAM)&m_families, 0); + ReleaseDC(0, dummy); +} + +QWindowsFontDatabase::QWindowsFontDatabase() : + m_fontEngineData(new QWindowsFontEngineData) +{ + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << "Clear type: " + << m_fontEngineData->clearTypeEnabled << "gamma: " + << m_fontEngineData->fontSmoothingGamma; +} + +QWindowsFontDatabase::~QWindowsFontDatabase() +{ +} + +QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, + QUnicodeTables::Script script, + void *handle) +{ + QFontEngine *fe = QWindowsFontDatabase::createEngine(script, fontDef, + 0, QWindowsContext::instance()->defaultDPI(), false, + QStringList(), m_fontEngineData); + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << "FONTDEF" << fontDef << script << fe << handle; + return fe; +} + +QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) +{ + QFontEngine *fe = QPlatformFontDatabase::fontEngine(fontData, pixelSize, hintingPreference); + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fe; + return fe; +} + +QStringList QWindowsFontDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const +{ + QStringList result = QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script); + if (!result.isEmpty()) + return result; + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << family << style << styleHint + << script << result << m_families.size(); + return result; +} + +QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) +{ + const QStringList result = QPlatformFontDatabase::addApplicationFont(fontData, fileName); + Q_UNIMPLEMENTED(); + return result; +} + +void QWindowsFontDatabase::releaseHandle(void *handle) +{ + if (handle && QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << handle; +} + +QString QWindowsFontDatabase::fontDir() const +{ + const QString result = QPlatformFontDatabase::fontDir(); + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << result; + return result; +} + +HFONT QWindowsFontDatabase::systemFont() +{ + static const HFONT stock_sysfont = (HFONT)GetStockObject(SYSTEM_FONT); + return stock_sysfont; +} + +// Creation functions + +static inline bool scriptRequiresOpenType(int script) +{ + return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala) + || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko); +} + +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; + +QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &request, + HDC fontHdc, int dpi, bool rawMode, + const QStringList &family_list, + const QSharedPointer &data) +{ + LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); + + const bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fontHdc; + + const HDC hdc = useDevice ? fontHdc : data->hdc; + + bool stockFont = false; + bool preferClearTypeAA = false; + + 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 (rawMode) { // will choose a stock font + int f = SYSTEM_FONT; + const QString fam = request.family.toLower(); + if (fam == QStringLiteral("default") || fam == QStringLiteral("system")) + f = SYSTEM_FONT; + else if (fam == QStringLiteral("system_fixed")) + f = SYSTEM_FIXED_FONT; + else if (fam == QStringLiteral("ansi_fixed")) + f = ANSI_FIXED_FONT; + else if (fam == QStringLiteral("ansi_var")) + f = ANSI_VAR_FONT; + else if (fam == QStringLiteral("device_default")) + f = DEVICE_DEFAULT_FONT; + else if (fam == QStringLiteral("oem_fixed")) + f = OEM_FIXED_FONT; + else if (fam.at(0) == QLatin1Char('#')) + f = fam.right(fam.length()-1).toInt(); + hfont = (HFONT)GetStockObject(f); + if (!hfont) { + qErrnoWarning("%s: GetStockObject failed", __FUNCTION__); + hfont = QWindowsFontDatabase::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 = -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; + } 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; + } + + lf.lfOutPrecision = strat; + + int qual = DEFAULT_QUALITY; + + if (request.styleStrategy & QFont::PreferMatch) + qual = DRAFT_QUALITY; + else if (request.styleStrategy & QFont::PreferQuality) + qual = PROOF_QUALITY; + + 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 + + hfont = CreateFontIndirect(&lf); + if (!hfont) + qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__); + + 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 (!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("%s: CreateFontIndirect with stretch failed", __FUNCTION__); + } + + if (hfont == 0) { + hfont = (HFONT)GetStockObject(ANSI_VAR_FONT); + stockFont = true; + } + } + +#if !defined(QT_NO_DIRECTWRITE) + else { + // Default to false for DirectWrite (and re-enable once/if everything + // turns out okay) + useDirectWrite = false; + if (initDirectWrite(data.data())) { + const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(QString::fromWCharArray(lf.lfFaceName)); + memcpy(lf.lfFaceName, nameSubstitute.utf16(), + sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE)); + + HRESULT hr = data->directWriteGdiInterop->CreateFontFromLOGFONT( + &lf, + &directWriteFont); + if (FAILED(hr)) { + qErrnoWarning("%s: CreateFontFromLOGFONT failed", __FUNCTION__); + } else { + DeleteObject(hfont); + useDirectWrite = true; + } + } + } +#endif + } + + QFontEngine *fe = 0; + if (!useDirectWrite) { + QWindowsFontEngine *few = new QWindowsFontEngine(request.family, hfont, stockFont, lf, data); + few->setObjectName(QStringLiteral("QWindowsFontEngine_") + request.family); + 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]) { + qWarning(" OpenType support missing for script\n"); + delete few; + return 0; + } + } + + few->initFontInfo(request, fontHdc, dpi); + fe = few; + } + +#if !defined(QT_NO_DIRECTWRITE) + else { + IDWriteFontFace *directWriteFontFace = NULL; + HRESULT hr = directWriteFont->CreateFontFace(&directWriteFontFace); + if (SUCCEEDED(hr)) { + QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace, + request.pixelSize, + data); + fedw->initFontInfo(request, dpi, directWriteFont); + fedw->setObjectName(QStringLiteral("QWindowsFontEngineDirectWrite_") + request.family); + fe = fedw; + } else { + qErrnoWarning("%s: CreateFontFace failed", __FUNCTION__); + } + } + + if (directWriteFont != 0) + directWriteFont->Release(); +#endif + + if(script == QUnicodeTables::Common + && !(request.styleStrategy & QFont::NoFontMerging)) { + QFontDatabase db; + if (!db.writingSystems(request.family).contains(QFontDatabase::Symbol)) { + 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 QWindowsMultiFontEngine(fe, list); + mfe->setObjectName(QStringLiteral("QWindowsMultiFontEngine_") + request.family); + mfe->fontDef = fe->fontDef; + fe = mfe; + } + } + return fe; +} + +static inline int verticalDPI() +{ + return GetDeviceCaps(QWindowsContext::instance()->displayContext(), LOGPIXELSY); +} + +QFont QWindowsFontDatabase::defaultFont() const +{ + LOGFONT lf; + GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf); + QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(lf); + // "MS Shell Dlg 2" is the correct system font >= Win2k + if (systemFont.family() == QStringLiteral("MS Shell Dlg")) + systemFont.setFamily(QStringLiteral("MS Shell Dlg 2")); + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << systemFont; + return systemFont; +} + +QHash QWindowsFontDatabase::defaultFonts() const +{ + QHash result; + NONCLIENTMETRICS ncm; + ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT); + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0); + + const int verticalRes = verticalDPI(); + + const QFont menuFont = LOGFONT_to_QFont(ncm.lfMenuFont, verticalRes); + const QFont messageFont = LOGFONT_to_QFont(ncm.lfMessageFont, verticalRes); + const QFont statusFont = LOGFONT_to_QFont(ncm.lfStatusFont, verticalRes); + const QFont titleFont = LOGFONT_to_QFont(ncm.lfCaptionFont, verticalRes); + + LOGFONT lfIconTitleFont; + SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); + const QFont iconTitleFont = LOGFONT_to_QFont(lfIconTitleFont, verticalRes); + + result.insert(QByteArray("QMenu"), menuFont); + result.insert(QByteArray("QMenuBar"), menuFont); + result.insert(QByteArray("QMessageBox"), messageFont); + result.insert(QByteArray("QTipLabel"), statusFont); + result.insert(QByteArray("QStatusBar"), statusFont); + result.insert(QByteArray("Q3TitleBar"), titleFont); + result.insert(QByteArray("QWorkspaceTitleBar"), titleFont); + result.insert(QByteArray("QAbstractItemView"), iconTitleFont); + result.insert(QByteArray("QDockWidgetTitle"), iconTitleFont); + if (QWindowsContext::verboseFonts) { + typedef QHash::const_iterator CIT; + QDebug nsp = qDebug().nospace(); + nsp << __FUNCTION__ << " DPI=" << verticalRes << "\n"; + const CIT cend = result.constEnd(); + for (CIT it = result.constBegin(); it != cend; ++it) + nsp << it.key() << ' ' << it.value() << '\n'; + } + return result; +} + +QFont QWindowsFontDatabase::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In) +{ + if (verticalDPI_In <= 0) + verticalDPI_In = verticalDPI(); + QFont qFont(QString::fromWCharArray(logFont.lfFaceName)); + qFont.setItalic(logFont.lfItalic); + if (logFont.lfWeight != FW_DONTCARE) + qFont.setWeight(weightFromInteger(logFont.lfWeight)); + const qreal logFontHeight = qAbs(logFont.lfHeight); + qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In)); + qFont.setUnderline(false); + qFont.setOverline(false); + qFont.setStrikeOut(false); + return qFont; +} + +QT_END_NAMESPACE -- cgit v1.2.3