michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "gfxGDIFont.h" michael@0: michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/WindowsVersion.h" michael@0: michael@0: #include "gfxGDIShaper.h" michael@0: #include "gfxUniscribeShaper.h" michael@0: #include "gfxHarfBuzzShaper.h" michael@0: #include michael@0: #include "gfxGraphiteShaper.h" michael@0: #include "gfxWindowsPlatform.h" michael@0: #include "gfxContext.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "nsUnicodeProperties.h" michael@0: #include "gfxFontConstants.h" michael@0: michael@0: #include "cairo-win32.h" michael@0: michael@0: #define ROUND(x) floor((x) + 0.5) michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::unicode; michael@0: michael@0: static inline cairo_antialias_t michael@0: GetCairoAntialiasOption(gfxFont::AntialiasOption anAntialiasOption) michael@0: { michael@0: switch (anAntialiasOption) { michael@0: default: michael@0: case gfxFont::kAntialiasDefault: michael@0: return CAIRO_ANTIALIAS_DEFAULT; michael@0: case gfxFont::kAntialiasNone: michael@0: return CAIRO_ANTIALIAS_NONE; michael@0: case gfxFont::kAntialiasGrayscale: michael@0: return CAIRO_ANTIALIAS_GRAY; michael@0: case gfxFont::kAntialiasSubpixel: michael@0: return CAIRO_ANTIALIAS_SUBPIXEL; michael@0: } michael@0: } michael@0: michael@0: gfxGDIFont::gfxGDIFont(GDIFontEntry *aFontEntry, michael@0: const gfxFontStyle *aFontStyle, michael@0: bool aNeedsBold, michael@0: AntialiasOption anAAOption) michael@0: : gfxFont(aFontEntry, aFontStyle, anAAOption), michael@0: mFont(nullptr), michael@0: mFontFace(nullptr), michael@0: mMetrics(nullptr), michael@0: mSpaceGlyph(0), michael@0: mNeedsBold(aNeedsBold) michael@0: { michael@0: if (FontCanSupportGraphite()) { michael@0: mGraphiteShaper = new gfxGraphiteShaper(this); michael@0: } michael@0: if (FontCanSupportHarfBuzz()) { michael@0: mHarfBuzzShaper = new gfxHarfBuzzShaper(this); michael@0: } michael@0: } michael@0: michael@0: gfxGDIFont::~gfxGDIFont() michael@0: { michael@0: if (mScaledFont) { michael@0: cairo_scaled_font_destroy(mScaledFont); michael@0: } michael@0: if (mFontFace) { michael@0: cairo_font_face_destroy(mFontFace); michael@0: } michael@0: if (mFont) { michael@0: ::DeleteObject(mFont); michael@0: } michael@0: delete mMetrics; michael@0: } michael@0: michael@0: void michael@0: gfxGDIFont::CreatePlatformShaper() michael@0: { michael@0: mPlatformShaper = new gfxGDIShaper(this); michael@0: } michael@0: michael@0: gfxFont* michael@0: gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption) michael@0: { michael@0: return new gfxGDIFont(static_cast(mFontEntry.get()), michael@0: &mStyle, mNeedsBold, anAAOption); michael@0: } michael@0: michael@0: static bool michael@0: UseUniscribe(gfxShapedText *aShapedText, michael@0: char16ptr_t aText, michael@0: uint32_t aLength) michael@0: { michael@0: uint32_t flags = aShapedText->Flags(); michael@0: bool useGDI; michael@0: michael@0: bool isXP = !IsVistaOrLater(); michael@0: michael@0: // bug 561304 - Uniscribe bug produces bad positioning at certain michael@0: // font sizes on XP, so default to GDI on XP using logic of 3.6 michael@0: michael@0: useGDI = isXP && michael@0: (flags & michael@0: (gfxTextRunFactory::TEXT_OPTIMIZE_SPEED | michael@0: gfxTextRunFactory::TEXT_IS_RTL) michael@0: ) == gfxTextRunFactory::TEXT_OPTIMIZE_SPEED; michael@0: michael@0: return !useGDI || michael@0: ScriptIsComplex(aText, aLength, SIC_COMPLEX) == S_OK; michael@0: } michael@0: michael@0: bool michael@0: gfxGDIFont::ShapeText(gfxContext *aContext, michael@0: const char16_t *aText, michael@0: uint32_t aOffset, michael@0: uint32_t aLength, michael@0: int32_t aScript, michael@0: gfxShapedText *aShapedText, michael@0: bool aPreferPlatformShaping) michael@0: { michael@0: if (!mMetrics) { michael@0: Initialize(); michael@0: } michael@0: if (!mIsValid) { michael@0: NS_WARNING("invalid font! expect incorrect text rendering"); michael@0: return false; michael@0: } michael@0: michael@0: bool ok = false; michael@0: michael@0: // Ensure the cairo font is set up, so there's no risk it'll fall back to michael@0: // creating a "toy" font internally (see bug 544617). michael@0: // We must check that this succeeded, otherwise we risk cairo creating the michael@0: // wrong kind of font internally as a fallback (bug 744480). michael@0: if (!SetupCairoFont(aContext)) { michael@0: return false; michael@0: } michael@0: michael@0: if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) { michael@0: ok = mGraphiteShaper->ShapeText(aContext, aText, michael@0: aOffset, aLength, michael@0: aScript, aShapedText); michael@0: } michael@0: michael@0: if (!ok && mHarfBuzzShaper) { michael@0: if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript) || michael@0: (!IsVistaOrLater() && michael@0: ScriptShapingType(aScript) == SHAPING_INDIC && michael@0: !Preferences::GetBool("gfx.font_rendering.winxp-indic-uniscribe", michael@0: false))) { michael@0: ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength, michael@0: aScript, aShapedText); michael@0: } michael@0: } michael@0: michael@0: if (!ok) { michael@0: GDIFontEntry *fe = static_cast(GetFontEntry()); michael@0: bool preferUniscribe = michael@0: (!fe->IsTrueType() || fe->IsSymbolFont()) && !fe->mForceGDI; michael@0: michael@0: if (preferUniscribe || UseUniscribe(aShapedText, aText, aLength)) { michael@0: // first try Uniscribe michael@0: if (!mUniscribeShaper) { michael@0: mUniscribeShaper = new gfxUniscribeShaper(this); michael@0: } michael@0: michael@0: ok = mUniscribeShaper->ShapeText(aContext, aText, aOffset, aLength, michael@0: aScript, aShapedText); michael@0: if (!ok) { michael@0: // fallback to GDI shaping michael@0: if (!mPlatformShaper) { michael@0: CreatePlatformShaper(); michael@0: } michael@0: michael@0: ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, michael@0: aLength, aScript, aShapedText); michael@0: } michael@0: } else { michael@0: // first use GDI michael@0: if (!mPlatformShaper) { michael@0: CreatePlatformShaper(); michael@0: } michael@0: michael@0: ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength, michael@0: aScript, aShapedText); michael@0: if (!ok) { michael@0: // try Uniscribe if GDI failed michael@0: if (!mUniscribeShaper) { michael@0: mUniscribeShaper = new gfxUniscribeShaper(this); michael@0: } michael@0: michael@0: // use Uniscribe shaping michael@0: ok = mUniscribeShaper->ShapeText(aContext, aText, michael@0: aOffset, aLength, michael@0: aScript, aShapedText); michael@0: } michael@0: } michael@0: michael@0: #if DEBUG michael@0: if (!ok) { michael@0: NS_ConvertUTF16toUTF8 name(GetName()); michael@0: char msg[256]; michael@0: michael@0: sprintf(msg, michael@0: "text shaping with both uniscribe and GDI failed for" michael@0: " font: %s", michael@0: name.get()); michael@0: NS_WARNING(msg); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText); michael@0: michael@0: return ok; michael@0: } michael@0: michael@0: const gfxFont::Metrics& michael@0: gfxGDIFont::GetMetrics() michael@0: { michael@0: if (!mMetrics) { michael@0: Initialize(); michael@0: } michael@0: return *mMetrics; michael@0: } michael@0: michael@0: uint32_t michael@0: gfxGDIFont::GetSpaceGlyph() michael@0: { michael@0: if (!mMetrics) { michael@0: Initialize(); michael@0: } michael@0: return mSpaceGlyph; michael@0: } michael@0: michael@0: bool michael@0: gfxGDIFont::SetupCairoFont(gfxContext *aContext) michael@0: { michael@0: if (!mMetrics) { michael@0: Initialize(); michael@0: } michael@0: if (!mScaledFont || michael@0: cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) { michael@0: // Don't cairo_set_scaled_font as that would propagate the error to michael@0: // the cairo_t, precluding any further drawing. michael@0: return false; michael@0: } michael@0: cairo_set_scaled_font(aContext->GetCairo(), mScaledFont); michael@0: return true; michael@0: } michael@0: michael@0: gfxFont::RunMetrics michael@0: gfxGDIFont::Measure(gfxTextRun *aTextRun, michael@0: uint32_t aStart, uint32_t aEnd, michael@0: BoundingBoxType aBoundingBoxType, michael@0: gfxContext *aRefContext, michael@0: Spacing *aSpacing) michael@0: { michael@0: gfxFont::RunMetrics metrics = michael@0: gfxFont::Measure(aTextRun, aStart, aEnd, michael@0: aBoundingBoxType, aRefContext, aSpacing); michael@0: michael@0: // if aBoundingBoxType is LOOSE_INK_EXTENTS michael@0: // and the underlying cairo font may be antialiased, michael@0: // we can't trust Windows to have considered all the pixels michael@0: // so we need to add "padding" to the bounds. michael@0: // (see bugs 475968, 439831, compare also bug 445087) michael@0: if (aBoundingBoxType == LOOSE_INK_EXTENTS && michael@0: mAntialiasOption != kAntialiasNone && michael@0: metrics.mBoundingBox.width > 0) { michael@0: metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit(); michael@0: metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 3; michael@0: } michael@0: michael@0: return metrics; michael@0: } michael@0: michael@0: #define OBLIQUE_SKEW_FACTOR 0.3 michael@0: michael@0: void michael@0: gfxGDIFont::Initialize() michael@0: { michael@0: NS_ASSERTION(!mMetrics, "re-creating metrics? this will leak"); michael@0: michael@0: LOGFONTW logFont; michael@0: michael@0: // Figure out if we want to do synthetic oblique styling. michael@0: GDIFontEntry* fe = static_cast(GetFontEntry()); michael@0: bool wantFakeItalic = michael@0: (mStyle.style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) && michael@0: !fe->IsItalic(); michael@0: michael@0: // If the font's family has an actual italic face (but font matching michael@0: // didn't choose it), we have to use a cairo transform instead of asking michael@0: // GDI to italicize, because that would use a different face and result michael@0: // in a possible glyph ID mismatch between shaping and rendering. michael@0: // michael@0: // We use the mFamilyHasItalicFace flag in the entry in case of user fonts, michael@0: // where the *CSS* family may not know about italic faces that are present michael@0: // in the *GDI* family, and which GDI would use if we asked it to perform michael@0: // the "italicization". michael@0: bool useCairoFakeItalic = wantFakeItalic && fe->mFamilyHasItalicFace; michael@0: michael@0: if (mAdjustedSize == 0.0) { michael@0: mAdjustedSize = mStyle.size; michael@0: if (mStyle.sizeAdjust != 0.0 && mAdjustedSize > 0.0) { michael@0: // to implement font-size-adjust, we first create the "unadjusted" font michael@0: FillLogFont(logFont, mAdjustedSize, michael@0: wantFakeItalic && !useCairoFakeItalic); michael@0: mFont = ::CreateFontIndirectW(&logFont); michael@0: michael@0: // initialize its metrics so we can calculate size adjustment michael@0: Initialize(); michael@0: michael@0: // calculate the properly adjusted size, and then proceed michael@0: // to recreate mFont and recalculate metrics michael@0: gfxFloat aspect = mMetrics->xHeight / mMetrics->emHeight; michael@0: mAdjustedSize = mStyle.GetAdjustedSize(aspect); michael@0: michael@0: // delete the temporary font and metrics michael@0: ::DeleteObject(mFont); michael@0: mFont = nullptr; michael@0: delete mMetrics; michael@0: mMetrics = nullptr; michael@0: } michael@0: } michael@0: michael@0: // (bug 724231) for local user fonts, we don't use GDI's synthetic bold, michael@0: // as it could lead to a different, incompatible face being used michael@0: // but instead do our own multi-striking michael@0: if (mNeedsBold && GetFontEntry()->IsLocalUserFont()) { michael@0: mApplySyntheticBold = true; michael@0: } michael@0: michael@0: // this may end up being zero michael@0: mAdjustedSize = ROUND(mAdjustedSize); michael@0: FillLogFont(logFont, mAdjustedSize, wantFakeItalic && !useCairoFakeItalic); michael@0: mFont = ::CreateFontIndirectW(&logFont); michael@0: michael@0: mMetrics = new gfxFont::Metrics; michael@0: ::memset(mMetrics, 0, sizeof(*mMetrics)); michael@0: michael@0: AutoDC dc; michael@0: SetGraphicsMode(dc.GetDC(), GM_ADVANCED); michael@0: AutoSelectFont selectFont(dc.GetDC(), mFont); michael@0: michael@0: // Get font metrics if size > 0 michael@0: if (mAdjustedSize > 0.0) { michael@0: michael@0: OUTLINETEXTMETRIC oMetrics; michael@0: TEXTMETRIC& metrics = oMetrics.otmTextMetrics; michael@0: michael@0: if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) { michael@0: mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y; michael@0: // Some fonts have wrong sign on their subscript offset, bug 410917. michael@0: mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y); michael@0: mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize; michael@0: mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition; michael@0: mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize; michael@0: mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition; michael@0: michael@0: const MAT2 kIdentityMatrix = { {0, 1}, {0, 0}, {0, 0}, {0, 1} }; michael@0: GLYPHMETRICS gm; michael@0: DWORD len = GetGlyphOutlineW(dc.GetDC(), char16_t('x'), GGO_METRICS, &gm, 0, nullptr, &kIdentityMatrix); michael@0: if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) { michael@0: // 56% of ascent, best guess for true type michael@0: mMetrics->xHeight = michael@0: ROUND((double)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); michael@0: } else { michael@0: mMetrics->xHeight = gm.gmptGlyphOrigin.y; michael@0: } michael@0: mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; michael@0: gfxFloat typEmHeight = (double)oMetrics.otmAscent - (double)oMetrics.otmDescent; michael@0: mMetrics->emAscent = ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight); michael@0: mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent; michael@0: if (oMetrics.otmEMSquare > 0) { michael@0: mFUnitsConvFactor = float(mAdjustedSize / oMetrics.otmEMSquare); michael@0: } michael@0: } else { michael@0: // Make a best-effort guess at extended metrics michael@0: // this is based on general typographic guidelines michael@0: michael@0: // GetTextMetrics can fail if the font file has been removed michael@0: // or corrupted recently. michael@0: BOOL result = GetTextMetrics(dc.GetDC(), &metrics); michael@0: if (!result) { michael@0: NS_WARNING("Missing or corrupt font data, fasten your seatbelt"); michael@0: mIsValid = false; michael@0: memset(mMetrics, 0, sizeof(*mMetrics)); michael@0: return; michael@0: } michael@0: michael@0: mMetrics->xHeight = michael@0: ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); michael@0: mMetrics->superscriptOffset = mMetrics->xHeight; michael@0: mMetrics->subscriptOffset = mMetrics->xHeight; michael@0: mMetrics->strikeoutSize = 1; michael@0: mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight michael@0: mMetrics->underlineSize = 1; michael@0: mMetrics->underlineOffset = -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent michael@0: mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; michael@0: mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading; michael@0: mMetrics->emDescent = metrics.tmDescent; michael@0: } michael@0: michael@0: mMetrics->internalLeading = metrics.tmInternalLeading; michael@0: mMetrics->externalLeading = metrics.tmExternalLeading; michael@0: mMetrics->maxHeight = metrics.tmHeight; michael@0: mMetrics->maxAscent = metrics.tmAscent; michael@0: mMetrics->maxDescent = metrics.tmDescent; michael@0: mMetrics->maxAdvance = metrics.tmMaxCharWidth; michael@0: mMetrics->aveCharWidth = std::max(1, metrics.tmAveCharWidth); michael@0: // The font is monospace when TMPF_FIXED_PITCH is *not* set! michael@0: // See http://msdn2.microsoft.com/en-us/library/ms534202(VS.85).aspx michael@0: if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { michael@0: mMetrics->maxAdvance = mMetrics->aveCharWidth; michael@0: } michael@0: michael@0: // Cache the width of a single space. michael@0: SIZE size; michael@0: GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size); michael@0: mMetrics->spaceWidth = ROUND(size.cx); michael@0: michael@0: // Cache the width of digit zero. michael@0: // XXX MSDN (http://msdn.microsoft.com/en-us/library/ms534223.aspx) michael@0: // does not say what the failure modes for GetTextExtentPoint32 are - michael@0: // is it safe to assume it will fail iff the font has no '0'? michael@0: if (GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size)) { michael@0: mMetrics->zeroOrAveCharWidth = ROUND(size.cx); michael@0: } else { michael@0: mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth; michael@0: } michael@0: michael@0: WORD glyph; michael@0: DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph, michael@0: GGI_MARK_NONEXISTING_GLYPHS); michael@0: if (ret != GDI_ERROR && glyph != 0xFFFF) { michael@0: mSpaceGlyph = glyph; michael@0: } michael@0: michael@0: SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont); michael@0: } michael@0: michael@0: if (IsSyntheticBold()) { michael@0: mMetrics->aveCharWidth += GetSyntheticBoldOffset(); michael@0: mMetrics->maxAdvance += GetSyntheticBoldOffset(); michael@0: } michael@0: michael@0: mFontFace = cairo_win32_font_face_create_for_logfontw_hfont(&logFont, michael@0: mFont); michael@0: michael@0: cairo_matrix_t sizeMatrix, ctm; michael@0: cairo_matrix_init_identity(&ctm); michael@0: cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize); michael@0: michael@0: if (useCairoFakeItalic) { michael@0: // Skew the matrix to do fake italic if it wasn't already applied michael@0: // via the LOGFONT michael@0: double skewfactor = OBLIQUE_SKEW_FACTOR; michael@0: cairo_matrix_t style; michael@0: cairo_matrix_init(&style, michael@0: 1, //xx michael@0: 0, //yx michael@0: -1 * skewfactor, //xy michael@0: 1, //yy michael@0: 0, //x0 michael@0: 0); //y0 michael@0: cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style); michael@0: } michael@0: michael@0: cairo_font_options_t *fontOptions = cairo_font_options_create(); michael@0: if (mAntialiasOption != kAntialiasDefault) { michael@0: cairo_font_options_set_antialias(fontOptions, michael@0: GetCairoAntialiasOption(mAntialiasOption)); michael@0: } michael@0: mScaledFont = cairo_scaled_font_create(mFontFace, &sizeMatrix, michael@0: &ctm, fontOptions); michael@0: cairo_font_options_destroy(fontOptions); michael@0: michael@0: if (!mScaledFont || michael@0: cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) { michael@0: #ifdef DEBUG michael@0: char warnBuf[1024]; michael@0: sprintf(warnBuf, "Failed to create scaled font: %s status: %d", michael@0: NS_ConvertUTF16toUTF8(mFontEntry->Name()).get(), michael@0: mScaledFont ? cairo_scaled_font_status(mScaledFont) : 0); michael@0: NS_WARNING(warnBuf); michael@0: #endif michael@0: mIsValid = false; michael@0: } else { michael@0: mIsValid = true; michael@0: } michael@0: michael@0: #if 0 michael@0: printf("Font: %p (%s) size: %f adjusted size: %f valid: %s\n", this, michael@0: NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size, mAdjustedSize, (mIsValid ? "yes" : "no")); michael@0: printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent); michael@0: printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance); michael@0: printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading); michael@0: printf(" spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->xHeight); michael@0: printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", michael@0: mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize, michael@0: mMetrics->superscriptOffset, mMetrics->subscriptOffset); michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize, michael@0: bool aUseGDIFakeItalic) michael@0: { michael@0: GDIFontEntry *fe = static_cast(GetFontEntry()); michael@0: michael@0: uint16_t weight; michael@0: if (fe->IsUserFont()) { michael@0: if (fe->IsLocalUserFont()) { michael@0: // for local user fonts, don't change the original weight michael@0: // in the entry's logfont, because that could alter the michael@0: // choice of actual face used (bug 724231) michael@0: weight = 0; michael@0: } else { michael@0: // avoid GDI synthetic bold which occurs when weight michael@0: // specified is >= font data weight + 200 michael@0: weight = mNeedsBold ? 700 : 200; michael@0: } michael@0: } else { michael@0: weight = mNeedsBold ? 700 : fe->Weight(); michael@0: } michael@0: michael@0: fe->FillLogFont(&aLogFont, weight, aSize, michael@0: (mAntialiasOption == kAntialiasSubpixel) ? true : false); michael@0: michael@0: // If GDI synthetic italic is wanted, force the lfItalic field to true michael@0: if (aUseGDIFakeItalic) { michael@0: aLogFont.lfItalic = 1; michael@0: } michael@0: } michael@0: michael@0: int32_t michael@0: gfxGDIFont::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID) michael@0: { michael@0: if (!mGlyphWidths) { michael@0: mGlyphWidths = new nsDataHashtable(200); michael@0: } michael@0: michael@0: int32_t width; michael@0: if (mGlyphWidths->Get(aGID, &width)) { michael@0: return width; michael@0: } michael@0: michael@0: DCFromContext dc(aCtx); michael@0: AutoSelectFont fs(dc, GetHFONT()); michael@0: michael@0: int devWidth; michael@0: if (GetCharWidthI(dc, aGID, 1, nullptr, &devWidth)) { michael@0: // ensure width is positive, 16.16 fixed-point value michael@0: width = (devWidth & 0x7fff) << 16; michael@0: mGlyphWidths->Put(aGID, width); michael@0: return width; michael@0: } michael@0: michael@0: return -1; michael@0: } michael@0: michael@0: void michael@0: gfxGDIFont::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, michael@0: FontCacheSizes* aSizes) const michael@0: { michael@0: gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); michael@0: aSizes->mFontInstances += aMallocSizeOf(mMetrics); michael@0: if (mGlyphWidths) { michael@0: aSizes->mFontInstances += michael@0: mGlyphWidths->SizeOfExcludingThis(nullptr, aMallocSizeOf); michael@0: } michael@0: } michael@0: michael@0: void michael@0: gfxGDIFont::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, michael@0: FontCacheSizes* aSizes) const michael@0: { michael@0: aSizes->mFontInstances += aMallocSizeOf(this); michael@0: AddSizeOfExcludingThis(aMallocSizeOf, aSizes); michael@0: }