const float getFontHeightToEmSizeFactor(Font& font, IDWriteFontCollection& dwFontCollection) { // To set the font size factor, we need to get the font metrics BOOL fontFound; uint32 fontIndex; // Search for the font in the font collection using the font name HRESULT hr = dwFontCollection.FindFamilyName (font.getTypefaceName().toWideCharPointer(), &fontIndex, &fontFound); if (! fontFound) fontIndex = 0; IDWriteFontFamily* dwFontFamily = nullptr; hr = dwFontCollection.GetFontFamily (fontIndex, &dwFontFamily); IDWriteFont* dwFont = nullptr; hr = dwFontFamily->GetFirstMatchingFont (DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &dwFont); IDWriteFontFace* dwFontFace = nullptr; hr = dwFont->CreateFontFace (&dwFontFace); // Font metrics are in font design units DWRITE_FONT_METRICS dwFontMetrics; dwFontFace->GetMetrics (&dwFontMetrics); const float totalHeight = std::abs ((float) dwFontMetrics.ascent) + std::abs ((float) dwFontMetrics.descent); const float fontHeightToEmSizeFactor = (float) dwFontMetrics.designUnitsPerEm / totalHeight; safeRelease (&dwFontFace); safeRelease (&dwFont); safeRelease (&dwFontFamily); return fontHeightToEmSizeFactor; }
//================================================================================================== static float getFontHeightToEmSizeFactor (IDWriteFont& dwFont) { ComSmartPtr<IDWriteFontFace> dwFontFace; dwFont.CreateFontFace (dwFontFace.resetAndGetPointerAddress()); if (dwFontFace == nullptr) return 1.0f; DWRITE_FONT_METRICS dwFontMetrics; dwFontFace->GetMetrics (&dwFontMetrics); const float totalHeight = (float) (std::abs (dwFontMetrics.ascent) + std::abs (dwFontMetrics.descent)); return dwFontMetrics.designUnitsPerEm / totalHeight; }
static QFontEngine *loadEngine(int script, const QFontDef &request, HDC fontHdc, int dpi, bool rawMode, const QtFontDesc *desc, const QStringList &family_list) { LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fontHdc; HDC hdc = shared_dc(); QString font_name = desc != 0 ? desc->family->name : request.family; if (useDevice) { hdc = fontHdc; font_name = request.family; } 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, deffnt = SYSTEM_FONT; QString fam = desc != 0 ? desc->family->name.toLower() : request.family.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 = -qRound(request.pixelSize); lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; if (desc == 0 || desc->style->key.weight == 50) lf.lfWeight = FW_DONTCARE; else lf.lfWeight = (desc->style->key.weight*900)/99; lf.lfItalic = (desc != 0 && 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 (!ttf || !useDirectWrite) { useDirectWrite = false; if (hfont && (!ttf || request.stretch != 100)) { DeleteObject(hfont); if (!res) qErrnoWarning("QFontEngine::loadEngine: GetTextMetrics failed"); lf.lfWidth = avWidth * request.stretch/100; hfont = CreateFontIndirect(&lf); if (!hfont) qErrnoWarning("QFontEngine::loadEngine: CreateFontIndirect with stretch failed"); } #ifndef Q_WS_WINCE if (hfont == 0) { hfont = (HFONT)GetStockObject(ANSI_VAR_FONT); stockFont = true; } #else if (hfont == 0) { hfont = (HFONT)GetStockObject(SYSTEM_FONT); stockFont = true; } #endif } #if !defined(QT_NO_DIRECTWRITE) else { // Default to false for DirectWrite (and re-enable once/if everything // turns out okay) useDirectWrite = false; QFontDatabasePrivate *db = privateDb(); if (db->directWriteFactory == 0) { HRESULT hr = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown **>(&db->directWriteFactory) ); if (FAILED(hr)) { qErrnoWarning("QFontEngine::loadEngine: DWriteCreateFactory failed"); } else { hr = db->directWriteFactory->GetGdiInterop(&db->directWriteGdiInterop); if (FAILED(hr)) qErrnoWarning("QFontEngine::loadEngine: GetGdiInterop failed"); } } if (db->directWriteGdiInterop != 0) { QString nameSubstitute = fontNameSubstitute(QString::fromWCharArray(lf.lfFaceName)); memcpy(lf.lfFaceName, nameSubstitute.utf16(), sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE)); HRESULT hr = db->directWriteGdiInterop->CreateFontFromLOGFONT( &lf, &directWriteFont); if (FAILED(hr)) { #ifndef QT_NO_DEBUG qErrnoWarning("QFontEngine::loadEngine: CreateFontFromLOGFONT failed " "for %ls (0x%lx)", lf.lfFaceName, hr); #endif } else { DeleteObject(hfont); useDirectWrite = true; } } } #endif } QFontEngine *fe = 0; if (!useDirectWrite) { QFontEngineWin *few = new QFontEngineWin(font_name, hfont, stockFont, lf); if (preferClearTypeAA) few->glyphFormat = QFontEngineGlyphCache::Raster_RGBMask; // Also check for OpenType tables when using complex scripts // ### TODO: This only works for scripts that require OpenType. More generally // for scripts that do not require OpenType we should just look at the list of // supported writing systems in the font's OS/2 table. if (scriptRequiresOpenType(script)) { HB_Face hbFace = few->harfbuzzFace(); if (!hbFace || !hbFace->supported_scripts[script]) { FM_DEBUG(" OpenType support missing for script\n"); delete few; return 0; } } initFontInfo(few, request, fontHdc, dpi); fe = few; } #if !defined(QT_NO_DIRECTWRITE) else { QFontDatabasePrivate *db = privateDb(); IDWriteFontFace *directWriteFontFace = NULL; HRESULT hr = directWriteFont->CreateFontFace(&directWriteFontFace); if (SUCCEEDED(hr)) { QFontEngineDirectWrite *fedw = new QFontEngineDirectWrite(db->directWriteFactory, directWriteFontFace, request.pixelSize); initFontInfo(fedw, request, dpi, directWriteFont); fe = fedw; } else { qErrnoWarning(hr, "QFontEngine::loadEngine: CreateFontFace failed"); } } if (directWriteFont != 0) directWriteFont->Release(); #endif if(script == QUnicodeTables::Common && !(request.styleStrategy & QFont::NoFontMerging) && desc != 0 && !(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(fe, list); mfe->fontDef = fe->fontDef; fe = mfe; } return fe; }
int main(void) { int argc; LPWSTR *argv; WCHAR *fontname, *string; int len; HDC dc; HFONT font, prevfont; IDWriteFontCollection *sysfc; UINT32 index; BOOL exists; IDWriteFontFamily *dwfamily; IDWriteFont *dwfont; IDWriteFontFace *dwface; featurePreparer *features; HRESULT hr; // TODO would using wmain() be adequate? argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (argv == NULL) dieLE("error getting command-line arguments"); if (argc != 3) { fprintf(stderr, "usage: %ws font string\n", argv[0]); return 1; } fontname = argv[1]; string = argv[2]; len = wcslen(string); // DirectWrite requires COM hr = CoInitialize(NULL); if (hr != S_OK) die("error initializing COM", hr); // Uniscribe requires a device context with the font to use dc = GetDC(NULL); if (dc == NULL) dieLE("error getting screen HDC for Uniscribe"); // TODO DEFAULT_CHARSET might affect the results we get font = CreateFontW(0, 0, 0, 0, 0, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontname); if (font == NULL) dieLE("error creating font for Uniscribe"); prevfont = (HFONT) SelectObject(dc, font); if (prevfont == NULL) dieLE("error selecting font into HDC for Uniscribe"); // and initialize DirectWrite hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory), (IUnknown **) (&dwfactory)); if (hr != S_OK) die("error initializing DirectWrite", hr); // and load the font *there* hr = dwfactory->GetSystemFontCollection(&sysfc, TRUE); if (hr != S_OK) die("error loading DirectWrite system font collection", hr); hr = sysfc->FindFamilyName(fontname, &index, &exists); if (hr != S_OK) die("error finding DirectWrite font family", hr); if (!exists) die("font not found in DirectWrite system font collection", E_FAIL); hr = sysfc->GetFontFamily(index, &dwfamily); if (hr != S_OK) die("error loading DirectWrite font family", hr); hr = dwfamily->GetFirstMatchingFont(DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &dwfont); if (hr != S_OK) die("error loading DirectWrite font object", hr); hr = dwfont->CreateFontFace(&dwface); if (hr != S_OK) die("error creating DirectWrite font face", hr); // first, uniscribe only; no features are used // uniscribeTest(dc, string, len, NULL, // doScriptItemize, doScriptShape, "Uniscribe"); // next, unprepared features (NULL values) features = new featurePreparer; //features->add('z','e','r','o',1); //features->add('f','r','a','c',1);features->prepare(len); // uniscribeTest(dc, string, len, features, // doScriptItemizeOpenType, doScriptShapeOpenType, "Uniscribe OpenType"); directwriteAnalyzerTest(dwface, string, len, features); delete features; dwface->Release(); dwfont->Release(); dwfamily->Release(); sysfc->Release(); dwfactory->Release(); SelectObject(dc, prevfont); DeleteObject(font); ReleaseDC(NULL, dc); CoUninitialize(); return 0; }