void QFontEngineWin::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const { HGDIOBJ oldFont = 0; HDC hdc = shared_dc(); if (ttf && (flags & QTextEngine::DesignMetrics)) { for(int i = 0; i < glyphs->numGlyphs; i++) { unsigned int glyph = glyphs->glyphs[i]; if(int(glyph) >= designAdvancesSize) { int newSize = (glyph + 256) >> 8 << 8; designAdvances = q_check_ptr((QFixed *)realloc(designAdvances, newSize*sizeof(QFixed))); for(int i = designAdvancesSize; i < newSize; ++i) designAdvances[i] = -1000000; designAdvancesSize = newSize; } if (designAdvances[glyph] < -999999) { if (!oldFont) oldFont = selectDesignFont(); int width = 0; calculateTTFGlyphWidth(hdc, glyph, width); designAdvances[glyph] = QFixed(width) / designToDevice; } glyphs->advances_x[i] = designAdvances[glyph]; glyphs->advances_y[i] = 0; } if(oldFont) DeleteObject(SelectObject(hdc, oldFont)); } else {
void QFontEngineWin::getCMap() { ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE); HDC hdc = shared_dc(); SelectObject(hdc, hfont); bool symb = false; if (ttf) { cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p'))); int size = 0; cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()), cmapTable.size(), &symb, &size); } if (!cmap) { ttf = false; symb = false; } symbol = symb; designToDevice = 1; _faceId.index = 0; if(cmap) { OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc); designToDevice = QFixed((int)otm->otmEMSquare)/int(otm->otmTextMetrics.tmHeight); unitsPerEm = otm->otmEMSquare; x_height = (int)otm->otmsXHeight; loadKerningPairs(designToDevice); _faceId.filename = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFullName)).toLatin1(); lineWidth = otm->otmsUnderscoreSize; fsType = otm->otmfsType; free(otm); } else { unitsPerEm = tm.tmHeight; } }
HGDIOBJ QFontEngineWin::selectDesignFont() const { LOGFONT f = logfont; f.lfHeight = unitsPerEm; HFONT designFont = CreateFontIndirect(&f); return SelectObject(shared_dc(), designFont); }
// ### maybe move to qapplication_win QFont qt_LOGFONTtoQFont(LOGFONT& lf, bool /*scale*/) { QString family = QT_WA_INLINE(QString::fromUtf16((ushort*)lf.lfFaceName), QString::fromLocal8Bit((char*)lf.lfFaceName)); QFont qf(family); qf.setItalic(lf.lfItalic); if (lf.lfWeight != FW_DONTCARE) { int weight; if (lf.lfWeight < 400) weight = QFont::Light; else if (lf.lfWeight < 600) weight = QFont::Normal; else if (lf.lfWeight < 700) weight = QFont::DemiBold; else if (lf.lfWeight < 800) weight = QFont::Bold; else weight = QFont::Black; qf.setWeight(weight); } int lfh = qAbs(lf.lfHeight); qf.setPointSizeF(lfh * 72.0 / GetDeviceCaps(shared_dc(),LOGPIXELSY)); qf.setUnderline(false); qf.setOverline(false); qf.setStrikeOut(false); return qf; }
// ### maybe move to qapplication_win QFont qt_LOGFONTtoQFont(LOGFONT& lf, bool /*scale*/) { QString family = QString::fromWCharArray(lf.lfFaceName); QFont qf(family); qf.setItalic(lf.lfItalic); if (lf.lfWeight != FW_DONTCARE) qf.setWeight(weightFromInteger(lf.lfWeight)); int lfh = qAbs(lf.lfHeight); qf.setPointSizeF(lfh * 72.0 / GetDeviceCaps(shared_dc(),LOGPIXELSY)); qf.setUnderline(false); qf.setOverline(false); qf.setStrikeOut(false); return qf; }
static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, HDC fontHdc, int dpi) { fe->fontDef = request; // most settings are equal HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fontHdc) ? fontHdc : 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. / dpi; } else if (fe->fontDef.pixelSize == -1) { fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * dpi / 72.); } }
QFontEngineWin::~QFontEngineWin() { if (designAdvances) free(designAdvances); if (widthCache) free(widthCache); // make sure we aren't by accident still selected SelectObject(shared_dc(), (HFONT)GetStockObject(SYSTEM_FONT)); if (!stockFont) { if (!DeleteObject(hfont)) qErrnoWarning("QFontEngineWin: failed to delete non-stock font..."); } }
// ### maybe move to qapplication_win QFont qt_LOGFONTtoQFont(LOGFONT& lf, bool /*scale*/) { QString family = QString::fromWCharArray(lf.lfFaceName); #ifdef QT_ENABLE_FREETYPE_FOR_WIN // Substitute font by myself. // Windows return font family name which should be substituted from SystemParametersInfo(). // If we use GDI's font engine, Windows substitute font family. // If we use FreeType, FreeType don't do that, and we need to substitute font by myself. //std::cout << "family: " << family.toUtf8().data() << std::endl; { HKEY key; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes"), 0, KEY_READ, &key) == ERROR_SUCCESS) { int i = 0; TCHAR buff[MAX_PATH]; DWORD size = sizeof(buff) / sizeof(buff[0]); BYTE data[1024*4]; DWORD dataSize = sizeof(data)/sizeof(data[0]); DWORD type; while (RegEnumValue(key, i++, buff, &size, NULL, &type, data, &dataSize) == ERROR_SUCCESS) { QString subFamily = QString::fromWCharArray(buff); if (family.compare(subFamily) == 0) { if (type == REG_SZ) family = QString::fromWCharArray((WCHAR *)data); break; } size = sizeof(buff) / sizeof(buff[0]); dataSize = sizeof(data)/sizeof(data[0]); } } } //std::cout << "use family: " << family.toUtf8().data() << std::endl; #endif QFont qf(family); qf.setItalic(lf.lfItalic); if (lf.lfWeight != FW_DONTCARE) qf.setWeight(weightFromInteger(lf.lfWeight)); int lfh = qAbs(lf.lfHeight); qf.setPointSizeF(lfh * 72.0 / GetDeviceCaps(shared_dc(),LOGPIXELSY)); qf.setUnderline(false); qf.setOverline(false); qf.setStrikeOut(false); return qf; }
QFontEngineWin::QFontEngineWin(const QString &name, HFONT _hfont, bool stockFont, LOGFONT lf) { //qDebug("regular windows font engine created: font='%s', size=%d", name, lf.lfHeight); _name = name; cmap = 0; hfont = _hfont; logfont = lf; HDC hdc = shared_dc(); SelectObject(hdc, hfont); this->stockFont = stockFont; fontDef.pixelSize = -lf.lfHeight; lbearing = SHRT_MIN; rbearing = SHRT_MIN; synthesized_flags = -1; lineWidth = -1; x_height = -1; BOOL res = GetTextMetrics(hdc, &tm); fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH); if (!res) { qErrnoWarning("QFontEngineWin: GetTextMetrics failed"); ZeroMemory(&tm, sizeof(TEXTMETRIC)); } cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000; getCMap(); widthCache = 0; widthCacheSize = 0; designAdvances = 0; designAdvancesSize = 0; if (!resolvedGetCharWidthI) resolveGetCharWidthI(); }
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 size; size = GetOutlineTextMetricsA(hdc, 0, 0); OUTLINETEXTMETRICA *otm = (OUTLINETEXTMETRICA *)malloc(size); GetOutlineTextMetricsA(hdc, size, otm); return otm; } #endif void QFontEngineWin::getCMap() { QT_WA({ ttf = (bool)(tm.w.tmPitchAndFamily & TMPF_TRUETYPE); } , { ttf = (bool)(tm.a.tmPitchAndFamily & TMPF_TRUETYPE); }); HDC hdc = shared_dc(); SelectObject(hdc, hfont); bool symb = false; if (ttf) { cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p'))); int size = 0; cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()), cmapTable.size(), &symb, &size); } if (!cmap) { ttf = false; symb = false; } symbol = symb; designToDevice = 1; _faceId.index = 0;
int QFontEngineWin::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, bool mirrored) const { int i = 0; int glyph_pos = 0; if (mirrored) { #if defined(Q_WS_WINCE) { #else if (symbol) { for (; i < numChars; ++i, ++glyph_pos) { unsigned int uc = getChar(str, i, numChars); glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); if (!glyphs->glyphs[glyph_pos] && uc < 0x100) glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000); } } else if (ttf) { for (; i < numChars; ++i, ++glyph_pos) { unsigned int uc = getChar(str, i, numChars); glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, QChar::mirroredChar(uc)); } } else { #endif wchar_t first = tm.tmFirstChar; wchar_t last = tm.tmLastChar; for (; i < numChars; ++i, ++glyph_pos) { uint ucs = QChar::mirroredChar(getChar(str, i, numChars)); if ( #ifdef Q_WS_WINCE tm.tmFirstChar > 60000 || // see line 375 #endif ucs >= first && ucs <= last) glyphs->glyphs[glyph_pos] = ucs; else glyphs->glyphs[glyph_pos] = 0; } } } else { #if defined(Q_WS_WINCE) { #else if (symbol) { for (; i < numChars; ++i, ++glyph_pos) { unsigned int uc = getChar(str, i, numChars); glyphs->glyphs[i] = getTrueTypeGlyphIndex(cmap, uc); if(!glyphs->glyphs[glyph_pos] && uc < 0x100) glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000); } } else if (ttf) { for (; i < numChars; ++i, ++glyph_pos) { unsigned int uc = getChar(str, i, numChars); glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); } } else { #endif wchar_t first = tm.tmFirstChar; wchar_t last = tm.tmLastChar; for (; i < numChars; ++i, ++glyph_pos) { uint uc = getChar(str, i, numChars); if ( #ifdef Q_WS_WINCE tm.tmFirstChar > 60000 || // see comment in QFontEngineWin #endif uc >= first && uc <= last) glyphs->glyphs[glyph_pos] = uc; else glyphs->glyphs[glyph_pos] = 0; } } } glyphs->numGlyphs = glyph_pos; return glyph_pos; } QFontEngineWin::QFontEngineWin(const QString &name, HFONT _hfont, bool stockFont, LOGFONT lf) { //qDebug("regular windows font engine created: font='%s', size=%d", name, lf.lfHeight); _name = name; cmap = 0; hfont = _hfont; logfont = lf; HDC hdc = shared_dc(); SelectObject(hdc, hfont); this->stockFont = stockFont; fontDef.pixelSize = -lf.lfHeight; lbearing = SHRT_MIN; rbearing = SHRT_MIN; synthesized_flags = -1; lineWidth = -1; x_height = -1; BOOL res = GetTextMetrics(hdc, &tm); fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH); if (!res) { qErrnoWarning("QFontEngineWin: GetTextMetrics failed"); ZeroMemory(&tm, sizeof(TEXTMETRIC)); } cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000; getCMap(); widthCache = 0; widthCacheSize = 0; designAdvances = 0; designAdvancesSize = 0; #ifndef Q_WS_WINCE if (!resolvedGetCharWidthI) resolveGetCharWidthI(); #endif }
bool QFontEngineWin::hasCMapTable() const { HDC hdc = shared_dc(); SelectObject(hdc, hfont); return GetFontData(hdc, MAKE_TAG('c', 'm', 'a', 'p'), 0, 0, 0) != GDI_ERROR; }