FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) { LOGFONT winfont = {0}; FillLogFont(fontDescription, &winfont); // Windows will always give us a valid pointer here, even if the face name // is non-existent. We have to double-check and see if the family name was // really used. String winName; HFONT hfont = createFontIndirectAndGetWinName(family, &winfont, &winName); if (!hfont) return 0; // FIXME: Do we need to use predefined fonts "guaranteed" to exist // when we're running in layout-test mode? if (!equalIgnoringCase(family, winName)) { // For CJK fonts with both English and native names, // GetTextFace returns a native name under the font's "locale" // and an English name under other locales regardless of // lfFaceName field of LOGFONT. As a result, we need to check // if a font has an alternate name. If there is, we need to // compare it with what's requested in the first place. String altName; if (!LookupAltName(family, altName) || !equalIgnoringCase(altName, winName)) { DeleteObject(hfont); return 0; } } return new FontPlatformData(hfont, fontDescription.computedPixelSize()); }
ASSISTANT::Text::Text(double _x, double _y, double _width, double _height, int _zPosition, LPCTSTR _color, LPCTSTR _textString, LPCTSTR _family, LPCTSTR _size, LPCTSTR _weight, LPCTSTR _slant, LPCTSTR _position, int _textStyle, UINT _id, LPCTSTR _hyperlink, LPCTSTR _currentDirectory, LPCTSTR _linkedObjects, LPCTSTR linkColor) : ColoredObject(_x, _y, _width, _height, _zPosition, _color, _T("none"), 0, _T("none"), _id, _hyperlink, _currentDirectory, _linkedObjects) { fontFamily = _family; fontSize = _size; fontWeight = _weight; fontSlant = _slant; textPosition = _position; textStyle = _textStyle; offY = 0; drawSize = _ttoi(_size); text.Empty(); if (_textString) { text = _textString; } actPos = EndPos(); if (text.IsEmpty()) firstPos = true; else firstPos = false; m_bHasSupportedFont = true; m_bTextWidthIsStatic = true; // Compute dimension FillLogFont(m_logFont, fontFamily, drawSize, fontWeight, fontSlant); fAscent = GetTextAscent(&m_logFont); fDescent = GetTextDescent(&m_logFont); if (m_dWidth == 0) { m_bTextWidthIsStatic = false; if (text.GetLength() > 0) m_dWidth = GetTextWidth(text, text.GetLength(), &m_logFont); } m_dHeight = fAscent + fDescent; if (_hyperlink) hyperlink_ = _hyperlink; else hyperlink_.Empty(); if (linkColor) activatedLinkColor = linkColor; else activatedLinkColor.Empty(); linkWasActivated = false; m_bHasReturnAtEnd = false; }
void ASSISTANT::Text::SetFontUnsupported() { m_bHasSupportedFont = false; // Arial is default font FillLogFont(m_logFont, _T("Arial"), drawSize, fontWeight, fontSlant); fAscent = GetTextAscent(&m_logFont); fDescent = GetTextDescent(&m_logFont); if (!m_bTextWidthIsStatic) if (text.GetLength() > 0) m_dWidth = GetTextWidth(text, text.GetLength(), &m_logFont); else m_dWidth = 0; m_dHeight = fAscent+fDescent; }
void gfxGDIFont::Initialize() { NS_ASSERTION(!mMetrics, "re-creating metrics? this will leak"); LOGFONTW logFont; // Figure out if we want to do synthetic oblique styling. GDIFontEntry* fe = static_cast<GDIFontEntry*>(GetFontEntry()); bool wantFakeItalic = (mStyle.style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) && !fe->IsItalic(); // If the font's family has an actual italic face (but font matching // didn't choose it), we have to use a cairo transform instead of asking // GDI to italicize, because that would use a different face and result // in a possible glyph ID mismatch between shaping and rendering. // // We use the mFamilyHasItalicFace flag in the entry in case of user fonts, // where the *CSS* family may not know about italic faces that are present // in the *GDI* family, and which GDI would use if we asked it to perform // the "italicization". bool useCairoFakeItalic = wantFakeItalic && fe->mFamilyHasItalicFace; if (mAdjustedSize == 0.0) { mAdjustedSize = mStyle.size; if (mStyle.sizeAdjust != 0.0 && mAdjustedSize > 0.0) { // to implement font-size-adjust, we first create the "unadjusted" font FillLogFont(logFont, mAdjustedSize, wantFakeItalic && !useCairoFakeItalic); mFont = ::CreateFontIndirectW(&logFont); // initialize its metrics so we can calculate size adjustment Initialize(); // calculate the properly adjusted size, and then proceed // to recreate mFont and recalculate metrics gfxFloat aspect = mMetrics->xHeight / mMetrics->emHeight; mAdjustedSize = mStyle.GetAdjustedSize(aspect); // delete the temporary font and metrics ::DeleteObject(mFont); mFont = nullptr; delete mMetrics; mMetrics = nullptr; } } // (bug 724231) for local user fonts, we don't use GDI's synthetic bold, // as it could lead to a different, incompatible face being used // but instead do our own multi-striking if (mNeedsBold && GetFontEntry()->IsLocalUserFont()) { mApplySyntheticBold = true; } // this may end up being zero mAdjustedSize = ROUND(mAdjustedSize); FillLogFont(logFont, mAdjustedSize, wantFakeItalic && !useCairoFakeItalic); mFont = ::CreateFontIndirectW(&logFont); mMetrics = new gfxFont::Metrics; ::memset(mMetrics, 0, sizeof(*mMetrics)); AutoDC dc; SetGraphicsMode(dc.GetDC(), GM_ADVANCED); AutoSelectFont selectFont(dc.GetDC(), mFont); // Get font metrics if size > 0 if (mAdjustedSize > 0.0) { OUTLINETEXTMETRIC oMetrics; TEXTMETRIC& metrics = oMetrics.otmTextMetrics; if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) { mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y; // Some fonts have wrong sign on their subscript offset, bug 410917. mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y); mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize; mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition; mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize; mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition; const MAT2 kIdentityMatrix = { {0, 1}, {0, 0}, {0, 0}, {0, 1} }; GLYPHMETRICS gm; DWORD len = GetGlyphOutlineW(dc.GetDC(), PRUnichar('x'), GGO_METRICS, &gm, 0, nullptr, &kIdentityMatrix); if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) { // 56% of ascent, best guess for true type mMetrics->xHeight = ROUND((double)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); } else { mMetrics->xHeight = gm.gmptGlyphOrigin.y; } mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; gfxFloat typEmHeight = (double)oMetrics.otmAscent - (double)oMetrics.otmDescent; mMetrics->emAscent = ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight); mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent; if (oMetrics.otmEMSquare > 0) { mFUnitsConvFactor = float(mAdjustedSize / oMetrics.otmEMSquare); } } else { // Make a best-effort guess at extended metrics // this is based on general typographic guidelines // GetTextMetrics can fail if the font file has been removed // or corrupted recently. BOOL result = GetTextMetrics(dc.GetDC(), &metrics); if (!result) { NS_WARNING("Missing or corrupt font data, fasten your seatbelt"); mIsValid = false; memset(mMetrics, 0, sizeof(*mMetrics)); return; } mMetrics->xHeight = ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); mMetrics->superscriptOffset = mMetrics->xHeight; mMetrics->subscriptOffset = mMetrics->xHeight; mMetrics->strikeoutSize = 1; mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight mMetrics->underlineSize = 1; mMetrics->underlineOffset = -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading; mMetrics->emDescent = metrics.tmDescent; } mMetrics->internalLeading = metrics.tmInternalLeading; mMetrics->externalLeading = metrics.tmExternalLeading; mMetrics->maxHeight = metrics.tmHeight; mMetrics->maxAscent = metrics.tmAscent; mMetrics->maxDescent = metrics.tmDescent; mMetrics->maxAdvance = metrics.tmMaxCharWidth; mMetrics->aveCharWidth = NS_MAX<gfxFloat>(1, metrics.tmAveCharWidth); // The font is monospace when TMPF_FIXED_PITCH is *not* set! // See http://msdn2.microsoft.com/en-us/library/ms534202(VS.85).aspx if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { mMetrics->maxAdvance = mMetrics->aveCharWidth; } // Cache the width of a single space. SIZE size; GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size); mMetrics->spaceWidth = ROUND(size.cx); // Cache the width of digit zero. // XXX MSDN (http://msdn.microsoft.com/en-us/library/ms534223.aspx) // does not say what the failure modes for GetTextExtentPoint32 are - // is it safe to assume it will fail iff the font has no '0'? if (GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size)) { mMetrics->zeroOrAveCharWidth = ROUND(size.cx); } else { mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth; } mSpaceGlyph = 0; if (metrics.tmPitchAndFamily & TMPF_TRUETYPE) { WORD glyph; DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS); if (ret != GDI_ERROR && glyph != 0xFFFF) { mSpaceGlyph = glyph; } } SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont); } if (IsSyntheticBold()) { mMetrics->aveCharWidth += GetSyntheticBoldOffset(); mMetrics->maxAdvance += GetSyntheticBoldOffset(); } mFontFace = cairo_win32_font_face_create_for_logfontw_hfont(&logFont, mFont); cairo_matrix_t sizeMatrix, ctm; cairo_matrix_init_identity(&ctm); cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize); if (useCairoFakeItalic) { // Skew the matrix to do fake italic if it wasn't already applied // via the LOGFONT double skewfactor = OBLIQUE_SKEW_FACTOR; cairo_matrix_t style; cairo_matrix_init(&style, 1, //xx 0, //yx -1 * skewfactor, //xy 1, //yy 0, //x0 0); //y0 cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style); } cairo_font_options_t *fontOptions = cairo_font_options_create(); if (mAntialiasOption != kAntialiasDefault) { cairo_font_options_set_antialias(fontOptions, GetCairoAntialiasOption(mAntialiasOption)); } mScaledFont = cairo_scaled_font_create(mFontFace, &sizeMatrix, &ctm, fontOptions); cairo_font_options_destroy(fontOptions); if (!mScaledFont || cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) { #ifdef DEBUG char warnBuf[1024]; sprintf(warnBuf, "Failed to create scaled font: %s status: %d", NS_ConvertUTF16toUTF8(mFontEntry->Name()).get(), mScaledFont ? cairo_scaled_font_status(mScaledFont) : 0); NS_WARNING(warnBuf); #endif mIsValid = false; } else { mIsValid = true; } #if 0 printf("Font: %p (%s) size: %f adjusted size: %f valid: %s\n", this, NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size, mAdjustedSize, (mIsValid ? "yes" : "no")); printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent); printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance); printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading); printf(" spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->xHeight); printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize, mMetrics->superscriptOffset, mMetrics->subscriptOffset); #endif }
void gfxGDIFont::Initialize() { NS_ASSERTION(!mMetrics, "re-creating metrics? this will leak"); LOGFONTW logFont; if (mAdjustedSize == 0.0) { mAdjustedSize = mStyle.size; if (mStyle.sizeAdjust != 0.0 && mAdjustedSize > 0.0) { // to implement font-size-adjust, we first create the "unadjusted" font FillLogFont(logFont, mAdjustedSize); mFont = ::CreateFontIndirectW(&logFont); // initialize its metrics so we can calculate size adjustment Initialize(); // calculate the properly adjusted size, and then proceed // to recreate mFont and recalculate metrics gfxFloat aspect = mMetrics->xHeight / mMetrics->emHeight; mAdjustedSize = mStyle.GetAdjustedSize(aspect); // delete the temporary font and metrics ::DeleteObject(mFont); mFont = nsnull; delete mMetrics; mMetrics = nsnull; } } FillLogFont(logFont, mAdjustedSize); mFont = ::CreateFontIndirectW(&logFont); mMetrics = new gfxFont::Metrics; ::memset(mMetrics, 0, sizeof(*mMetrics)); AutoDC dc; SetGraphicsMode(dc.GetDC(), GM_ADVANCED); AutoSelectFont selectFont(dc.GetDC(), mFont); // Get font metrics OUTLINETEXTMETRIC oMetrics; TEXTMETRIC& metrics = oMetrics.otmTextMetrics; if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) { mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y; // Some fonts have wrong sign on their subscript offset, bug 410917. mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y); mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize; mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition; mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize; mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition; const MAT2 kIdentityMatrix = { {0, 1}, {0, 0}, {0, 0}, {0, 1} }; GLYPHMETRICS gm; DWORD len = GetGlyphOutlineW(dc.GetDC(), PRUnichar('x'), GGO_METRICS, &gm, 0, nsnull, &kIdentityMatrix); if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) { // 56% of ascent, best guess for true type mMetrics->xHeight = ROUND((double)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); } else { mMetrics->xHeight = gm.gmptGlyphOrigin.y; } mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; gfxFloat typEmHeight = (double)oMetrics.otmAscent - (double)oMetrics.otmDescent; mMetrics->emAscent = ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight); mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent; if (oMetrics.otmEMSquare > 0) { mFUnitsConvFactor = float(GetAdjustedSize() / oMetrics.otmEMSquare); } } else { // Make a best-effort guess at extended metrics // this is based on general typographic guidelines // GetTextMetrics can fail if the font file has been removed // or corrupted recently. BOOL result = GetTextMetrics(dc.GetDC(), &metrics); if (!result) { NS_WARNING("Missing or corrupt font data, fasten your seatbelt"); mIsValid = PR_FALSE; memset(mMetrics, 0, sizeof(*mMetrics)); return; } mMetrics->xHeight = ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); mMetrics->superscriptOffset = mMetrics->xHeight; mMetrics->subscriptOffset = mMetrics->xHeight; mMetrics->strikeoutSize = 1; mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight mMetrics->underlineSize = 1; mMetrics->underlineOffset = -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading; mMetrics->emDescent = metrics.tmDescent; } mMetrics->internalLeading = metrics.tmInternalLeading; mMetrics->externalLeading = metrics.tmExternalLeading; mMetrics->maxHeight = metrics.tmHeight; mMetrics->maxAscent = metrics.tmAscent; mMetrics->maxDescent = metrics.tmDescent; mMetrics->maxAdvance = metrics.tmMaxCharWidth; mMetrics->aveCharWidth = PR_MAX(1, metrics.tmAveCharWidth); // The font is monospace when TMPF_FIXED_PITCH is *not* set! // See http://msdn2.microsoft.com/en-us/library/ms534202(VS.85).aspx if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { mMetrics->maxAdvance = mMetrics->aveCharWidth; } // Cache the width of a single space. SIZE size; GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size); mMetrics->spaceWidth = ROUND(size.cx); // Cache the width of digit zero. // XXX MSDN (http://msdn.microsoft.com/en-us/library/ms534223.aspx) // does not say what the failure modes for GetTextExtentPoint32 are - // is it safe to assume it will fail iff the font has no '0'? if (GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size)) { mMetrics->zeroOrAveCharWidth = ROUND(size.cx); } else { mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth; } mSpaceGlyph = 0; if (metrics.tmPitchAndFamily & TMPF_TRUETYPE) { WORD glyph; DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS); if (ret != GDI_ERROR && glyph != 0xFFFF) { mSpaceGlyph = glyph; } } SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont); mFontFace = cairo_win32_font_face_create_for_logfontw_hfont(&logFont, mFont); cairo_matrix_t sizeMatrix, ctm; cairo_matrix_init_identity(&ctm); cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize); cairo_font_options_t *fontOptions = cairo_font_options_create(); if (mAntialiasOption != kAntialiasDefault) { cairo_font_options_set_antialias(fontOptions, GetCairoAntialiasOption(mAntialiasOption)); } mScaledFont = cairo_scaled_font_create(mFontFace, &sizeMatrix, &ctm, fontOptions); cairo_font_options_destroy(fontOptions); if (!mScaledFont || cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) { #ifdef DEBUG char warnBuf[1024]; sprintf(warnBuf, "Failed to create scaled font: %s status: %d", NS_ConvertUTF16toUTF8(mFontEntry->Name()).get(), mScaledFont ? cairo_scaled_font_status(mScaledFont) : 0); NS_WARNING(warnBuf); #endif } mIsValid = PR_TRUE; #if 0 printf("Font: %p (%s) size: %f\n", this, NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size); printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent); printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance); printf(" internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading); printf(" spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight); printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset); #endif }