no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / gfx / thebes / gfxGDIFont.cpp
blob2053b337271c2e7d9b43e7c0be28ac5314e5deb1
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "gfxGDIFont.h"
8 #include "mozilla/MemoryReporting.h"
9 #include "mozilla/Sprintf.h"
10 #include "mozilla/WindowsVersion.h"
12 #include <algorithm>
13 #include "gfxWindowsPlatform.h"
14 #include "gfxContext.h"
15 #include "mozilla/Preferences.h"
16 #include "nsUnicodeProperties.h"
17 #include "gfxFontConstants.h"
18 #include "gfxHarfBuzzShaper.h"
19 #include "gfxTextRun.h"
21 #include "cairo-win32.h"
23 #define ROUND(x) floor((x) + 0.5)
25 using namespace mozilla;
26 using namespace mozilla::gfx;
27 using namespace mozilla::unicode;
29 gfxGDIFont::gfxGDIFont(GDIFontEntry* aFontEntry, const gfxFontStyle* aFontStyle,
30 AntialiasOption anAAOption)
31 : gfxFont(nullptr, aFontEntry, aFontStyle, anAAOption),
32 mFont(nullptr),
33 mMetrics(nullptr),
34 mIsBitmap(false),
35 mScriptCache(nullptr) {
36 mNeedsSyntheticBold = aFontStyle->NeedsSyntheticBold(aFontEntry);
38 Initialize();
40 if (mFont) {
41 mUnscaledFont = aFontEntry->LookupUnscaledFont(mFont);
45 gfxGDIFont::~gfxGDIFont() {
46 if (mFont) {
47 ::DeleteObject(mFont);
49 if (mScriptCache) {
50 ScriptFreeCache(&mScriptCache);
52 delete mMetrics;
55 gfxFont* gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption) const {
56 auto entry = static_cast<GDIFontEntry*>(mFontEntry.get());
57 return new gfxGDIFont(entry, &mStyle, anAAOption);
60 bool gfxGDIFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
61 uint32_t aOffset, uint32_t aLength, Script aScript,
62 nsAtom* aLanguage, bool aVertical,
63 RoundingFlags aRounding,
64 gfxShapedText* aShapedText) {
65 if (!mIsValid) {
66 NS_WARNING("invalid font! expect incorrect text rendering");
67 return false;
70 return gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript,
71 aLanguage, aVertical, aRounding, aShapedText);
74 already_AddRefed<ScaledFont> gfxGDIFont::GetScaledFont(
75 const TextRunDrawParams& aRunParams) {
76 if (ScaledFont* scaledFont = mAzureScaledFont) {
77 return do_AddRef(scaledFont);
80 LOGFONT lf;
81 GetObject(GetHFONT(), sizeof(LOGFONT), &lf);
83 RefPtr<ScaledFont> newScaledFont = Factory::CreateScaledFontForGDIFont(
84 &lf, GetUnscaledFont(), GetAdjustedSize());
85 if (!newScaledFont) {
86 return nullptr;
89 InitializeScaledFont(newScaledFont);
91 if (mAzureScaledFont.compareExchange(nullptr, newScaledFont.get())) {
92 Unused << newScaledFont.forget();
94 ScaledFont* scaledFont = mAzureScaledFont;
95 return do_AddRef(scaledFont);
98 gfxFont::RunMetrics gfxGDIFont::Measure(const gfxTextRun* aTextRun,
99 uint32_t aStart, uint32_t aEnd,
100 BoundingBoxType aBoundingBoxType,
101 DrawTarget* aRefDrawTarget,
102 Spacing* aSpacing,
103 gfx::ShapedTextFlags aOrientation) {
104 gfxFont::RunMetrics metrics =
105 gfxFont::Measure(aTextRun, aStart, aEnd, aBoundingBoxType, aRefDrawTarget,
106 aSpacing, aOrientation);
108 // if aBoundingBoxType is LOOSE_INK_EXTENTS
109 // and the underlying cairo font may be antialiased,
110 // we can't trust Windows to have considered all the pixels
111 // so we need to add "padding" to the bounds.
112 // (see bugs 475968, 439831, compare also bug 445087)
113 if (aBoundingBoxType == LOOSE_INK_EXTENTS &&
114 mAntialiasOption != kAntialiasNone && metrics.mBoundingBox.Width() > 0) {
115 metrics.mBoundingBox.MoveByX(-aTextRun->GetAppUnitsPerDevUnit());
116 metrics.mBoundingBox.SetWidth(metrics.mBoundingBox.Width() +
117 aTextRun->GetAppUnitsPerDevUnit() * 3);
120 return metrics;
123 void gfxGDIFont::Initialize() {
124 NS_ASSERTION(!mMetrics, "re-creating metrics? this will leak");
126 LOGFONTW logFont;
128 if (mAdjustedSize == 0.0) {
129 mAdjustedSize = GetAdjustedSize();
130 if (FontSizeAdjust::Tag(mStyle.sizeAdjustBasis) !=
131 FontSizeAdjust::Tag::None) {
132 if (mStyle.sizeAdjust > 0.0 && mAdjustedSize > 0.0) {
133 // to implement font-size-adjust, we first create the "unadjusted" font
134 FillLogFont(logFont, mAdjustedSize);
135 mFont = ::CreateFontIndirectW(&logFont);
137 // initialize its metrics so we can calculate size adjustment
138 Initialize();
140 // Unless the font was so small that GDI metrics rounded to zero,
141 // calculate the properly adjusted size, and then proceed
142 // to recreate mFont and recalculate metrics
143 if (mMetrics->emHeight > 0.0) {
144 gfxFloat aspect;
145 switch (FontSizeAdjust::Tag(mStyle.sizeAdjustBasis)) {
146 default:
147 MOZ_ASSERT_UNREACHABLE("unhandled sizeAdjustBasis?");
148 aspect = 0.0;
149 break;
150 case FontSizeAdjust::Tag::ExHeight:
151 aspect = mMetrics->xHeight / mMetrics->emHeight;
152 break;
153 case FontSizeAdjust::Tag::CapHeight:
154 aspect = mMetrics->capHeight / mMetrics->emHeight;
155 break;
156 case FontSizeAdjust::Tag::ChWidth: {
157 gfxFloat advance = GetCharAdvance('0');
158 aspect = advance > 0.0 ? advance / mMetrics->emHeight : 0.5;
159 break;
161 case FontSizeAdjust::Tag::IcWidth:
162 case FontSizeAdjust::Tag::IcHeight: {
163 bool vertical = FontSizeAdjust::Tag(mStyle.sizeAdjustBasis) ==
164 FontSizeAdjust::Tag::IcHeight;
165 gfxFloat advance = GetCharAdvance(kWaterIdeograph, vertical);
166 aspect = advance > 0.0 ? advance / mMetrics->emHeight : 1.0;
167 break;
170 if (aspect > 0.0) {
171 // If we created a shaper above (to measure glyphs), discard it so
172 // we get a new one for the adjusted scaling.
173 delete mHarfBuzzShaper.exchange(nullptr);
174 mAdjustedSize = mStyle.GetAdjustedSize(aspect);
178 // delete the temporary font and metrics
179 ::DeleteObject(mFont);
180 mFont = nullptr;
181 delete mMetrics;
182 mMetrics = nullptr;
183 } else {
184 mAdjustedSize = 0.0;
189 // (bug 724231) for local user fonts, we don't use GDI's synthetic bold,
190 // as it could lead to a different, incompatible face being used
191 // but instead do our own multi-striking
192 if (mNeedsSyntheticBold && GetFontEntry()->IsLocalUserFont()) {
193 mApplySyntheticBold = true;
196 // this may end up being zero
197 mAdjustedSize = ROUND(mAdjustedSize);
198 FillLogFont(logFont, mAdjustedSize);
199 mFont = ::CreateFontIndirectW(&logFont);
201 mMetrics = new gfxFont::Metrics;
202 ::memset(mMetrics, 0, sizeof(*mMetrics));
204 if (!mFont) {
205 NS_WARNING("Failed creating GDI font");
206 mIsValid = false;
207 return;
210 AutoDC dc;
211 SetGraphicsMode(dc.GetDC(), GM_ADVANCED);
212 AutoSelectFont selectFont(dc.GetDC(), mFont);
214 // Get font metrics if size > 0
215 if (mAdjustedSize > 0.0) {
216 OUTLINETEXTMETRIC oMetrics;
217 TEXTMETRIC& metrics = oMetrics.otmTextMetrics;
219 if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) {
220 mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize;
221 mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition;
222 mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize;
223 mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition;
225 const MAT2 kIdentityMatrix = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
226 GLYPHMETRICS gm;
227 DWORD len = GetGlyphOutlineW(dc.GetDC(), char16_t('x'), GGO_METRICS, &gm,
228 0, nullptr, &kIdentityMatrix);
229 if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) {
230 // 56% of ascent, best guess for true type
231 mMetrics->xHeight =
232 ROUND((double)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR);
233 } else {
234 mMetrics->xHeight = gm.gmptGlyphOrigin.y;
236 len = GetGlyphOutlineW(dc.GetDC(), char16_t('H'), GGO_METRICS, &gm, 0,
237 nullptr, &kIdentityMatrix);
238 if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) {
239 mMetrics->capHeight = metrics.tmAscent - metrics.tmInternalLeading;
240 } else {
241 mMetrics->capHeight = gm.gmptGlyphOrigin.y;
243 mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading;
244 gfxFloat typEmHeight =
245 (double)oMetrics.otmAscent - (double)oMetrics.otmDescent;
246 mMetrics->emAscent =
247 ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight);
248 mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent;
249 if (oMetrics.otmEMSquare > 0) {
250 mFUnitsConvFactor = float(mAdjustedSize / oMetrics.otmEMSquare);
252 } else {
253 // Make a best-effort guess at extended metrics
254 // this is based on general typographic guidelines
256 // GetTextMetrics can fail if the font file has been removed
257 // or corrupted recently.
258 BOOL result = GetTextMetrics(dc.GetDC(), &metrics);
259 if (!result) {
260 NS_WARNING("Missing or corrupt font data, fasten your seatbelt");
261 mIsValid = false;
262 memset(mMetrics, 0, sizeof(*mMetrics));
263 return;
266 mMetrics->xHeight =
267 ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR);
268 mMetrics->strikeoutSize = 1;
269 mMetrics->strikeoutOffset =
270 ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight
271 mMetrics->underlineSize = 1;
272 mMetrics->underlineOffset =
273 -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent
274 mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading;
275 mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading;
276 mMetrics->emDescent = metrics.tmDescent;
277 mMetrics->capHeight = mMetrics->emAscent;
280 mMetrics->internalLeading = metrics.tmInternalLeading;
281 mMetrics->externalLeading = metrics.tmExternalLeading;
282 mMetrics->maxHeight = metrics.tmHeight;
283 mMetrics->maxAscent = metrics.tmAscent;
284 mMetrics->maxDescent = metrics.tmDescent;
285 mMetrics->maxAdvance = metrics.tmMaxCharWidth;
286 mMetrics->aveCharWidth = std::max<gfxFloat>(1, metrics.tmAveCharWidth);
287 // The font is monospace when TMPF_FIXED_PITCH is *not* set!
288 // See http://msdn2.microsoft.com/en-us/library/ms534202(VS.85).aspx
289 if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
290 mMetrics->maxAdvance = mMetrics->aveCharWidth;
293 mIsBitmap = !(metrics.tmPitchAndFamily & TMPF_VECTOR);
295 // For fonts with USE_TYPO_METRICS set in the fsSelection field,
296 // let the OS/2 sTypo* metrics override the previous values.
297 // (see http://www.microsoft.com/typography/otspec/os2.htm#fss)
298 // Using the equivalent values from oMetrics provides inconsistent
299 // results with CFF fonts, so we instead rely on OS2Table.
300 gfxFontEntry::AutoTable os2Table(mFontEntry,
301 TRUETYPE_TAG('O', 'S', '/', '2'));
302 if (os2Table) {
303 uint32_t len;
304 const OS2Table* os2 =
305 reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len));
306 if (len >= offsetof(OS2Table, sTypoLineGap) + sizeof(int16_t)) {
307 const uint16_t kUseTypoMetricsMask = 1 << 7;
308 if ((uint16_t(os2->fsSelection) & kUseTypoMetricsMask)) {
309 double ascent = int16_t(os2->sTypoAscender);
310 double descent = int16_t(os2->sTypoDescender);
311 double lineGap = int16_t(os2->sTypoLineGap);
312 mMetrics->maxAscent = ROUND(ascent * mFUnitsConvFactor);
313 mMetrics->maxDescent = -ROUND(descent * mFUnitsConvFactor);
314 mMetrics->maxHeight = mMetrics->maxAscent + mMetrics->maxDescent;
315 mMetrics->internalLeading = mMetrics->maxHeight - mMetrics->emHeight;
316 gfxFloat lineHeight =
317 ROUND((ascent - descent + lineGap) * mFUnitsConvFactor);
318 lineHeight = std::max(lineHeight, mMetrics->maxHeight);
319 mMetrics->externalLeading = lineHeight - mMetrics->maxHeight;
322 // although sxHeight and sCapHeight are signed fields, we consider
323 // negative values to be erroneous and just ignore them
324 if (uint16_t(os2->version) >= 2) {
325 // version 2 and later includes the x-height and cap-height fields
326 if (len >= offsetof(OS2Table, sxHeight) + sizeof(int16_t) &&
327 int16_t(os2->sxHeight) > 0) {
328 mMetrics->xHeight = ROUND(int16_t(os2->sxHeight) * mFUnitsConvFactor);
330 if (len >= offsetof(OS2Table, sCapHeight) + sizeof(int16_t) &&
331 int16_t(os2->sCapHeight) > 0) {
332 mMetrics->capHeight =
333 ROUND(int16_t(os2->sCapHeight) * mFUnitsConvFactor);
338 WORD glyph;
339 SIZE size;
340 DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph,
341 GGI_MARK_NONEXISTING_GLYPHS);
342 if (ret != GDI_ERROR && glyph != 0xFFFF) {
343 mSpaceGlyph = glyph;
344 // Cache the width of a single space.
345 GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size);
346 mMetrics->spaceWidth = ROUND(size.cx);
347 } else {
348 mMetrics->spaceWidth = mMetrics->aveCharWidth;
351 // Cache the width of digit zero, if available.
352 ret = GetGlyphIndicesW(dc.GetDC(), L"0", 1, &glyph,
353 GGI_MARK_NONEXISTING_GLYPHS);
354 if (ret != GDI_ERROR && glyph != 0xFFFF) {
355 GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size);
356 mMetrics->zeroWidth = ROUND(size.cx);
357 } else {
358 mMetrics->zeroWidth = -1.0; // indicates not found
361 wchar_t ch = kWaterIdeograph;
362 ret = GetGlyphIndicesW(dc.GetDC(), &ch, 1, &glyph,
363 GGI_MARK_NONEXISTING_GLYPHS);
364 if (ret != GDI_ERROR && glyph != 0xFFFF) {
365 GetTextExtentPoint32W(dc.GetDC(), &ch, 1, &size);
366 mMetrics->ideographicWidth = ROUND(size.cx);
367 } else {
368 mMetrics->ideographicWidth = -1.0;
371 SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
372 } else {
373 mFUnitsConvFactor = 0.0; // zero-sized font: all values scale to zero
376 if (ApplySyntheticBold()) {
377 auto delta = GetSyntheticBoldOffset();
378 mMetrics->spaceWidth += delta;
379 mMetrics->aveCharWidth += delta;
380 mMetrics->maxAdvance += delta;
381 if (mMetrics->zeroWidth > 0) {
382 mMetrics->zeroWidth += delta;
384 if (mMetrics->ideographicWidth > 0) {
385 mMetrics->ideographicWidth += delta;
389 #if 0
390 printf("Font: %p (%s) size: %f adjusted size: %f valid: %s\n", this,
391 GetName().get(), mStyle.size, mAdjustedSize, (mIsValid ? "yes" : "no"));
392 printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent);
393 printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance);
394 printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading);
395 printf(" spaceWidth: %f aveCharWidth: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth);
396 printf(" xHeight: %f capHeight: %f\n", mMetrics->xHeight, mMetrics->capHeight);
397 printf(" uOff: %f uSize: %f stOff: %f stSize: %f\n",
398 mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize);
399 #endif
402 void gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize) {
403 GDIFontEntry* fe = static_cast<GDIFontEntry*>(GetFontEntry());
405 // Figure out the lfWeight value to use for GDI font selection,
406 // or zero to use the entry's current LOGFONT value.
407 LONG weight;
408 if (fe->IsUserFont()) {
409 if (fe->IsLocalUserFont()) {
410 // for local user fonts, don't change the original weight
411 // in the entry's logfont, because that could alter the
412 // choice of actual face used (bug 724231)
413 weight = 0;
414 } else {
415 // avoid GDI synthetic bold which occurs when weight
416 // specified is >= font data weight + 200
417 weight = mNeedsSyntheticBold ? 700 : 200;
419 } else {
420 // GDI doesn't support variation fonts, so for system fonts we know
421 // that the entry has only a single weight, not a range.
422 MOZ_ASSERT(fe->Weight().IsSingle());
423 weight = mNeedsSyntheticBold ? 700 : fe->Weight().Min().ToIntRounded();
426 fe->FillLogFont(&aLogFont, weight, aSize);
429 uint32_t gfxGDIFont::GetGlyph(uint32_t aUnicode, uint32_t aVarSelector) {
430 // Callback used only for fonts that lack a 'cmap' table.
432 // We don't support variation selector sequences or non-BMP characters
433 // in the legacy bitmap, vector or postscript fonts that might use
434 // this code path.
435 if (aUnicode > 0xffff || aVarSelector) {
436 return 0;
439 if (!mGlyphIDs) {
440 mGlyphIDs = MakeUnique<nsTHashMap<nsUint32HashKey, uint32_t>>(64);
443 uint32_t gid;
444 if (mGlyphIDs->Get(aUnicode, &gid)) {
445 return gid;
448 wchar_t ch = aUnicode;
449 WORD glyph;
450 HRESULT ret = ScriptGetCMap(nullptr, &mScriptCache, &ch, 1, 0, &glyph);
451 if (ret != S_OK) {
452 AutoDC dc;
453 AutoSelectFont fs(dc.GetDC(), GetHFONT());
454 if (ret == E_PENDING) {
455 // Try ScriptGetCMap again now that we've set up the font.
456 ret = ScriptGetCMap(dc.GetDC(), &mScriptCache, &ch, 1, 0, &glyph);
458 if (ret != S_OK) {
459 // If ScriptGetCMap still failed, fall back to GetGlyphIndicesW
460 // (see bug 1105807).
461 DWORD ret = GetGlyphIndicesW(dc.GetDC(), &ch, 1, &glyph,
462 GGI_MARK_NONEXISTING_GLYPHS);
463 if (ret == GDI_ERROR || glyph == 0xFFFF) {
464 glyph = 0;
469 mGlyphIDs->InsertOrUpdate(aUnicode, glyph);
470 return glyph;
473 int32_t gfxGDIFont::GetGlyphWidth(uint16_t aGID) {
474 if (!mGlyphWidths) {
475 mGlyphWidths = MakeUnique<nsTHashMap<nsUint32HashKey, int32_t>>(128);
478 return mGlyphWidths->WithEntryHandle(aGID, [&](auto&& entry) {
479 if (!entry) {
480 DCForMetrics dc;
481 AutoSelectFont fs(dc, GetHFONT());
483 int devWidth;
484 if (!GetCharWidthI(dc, aGID, 1, nullptr, &devWidth)) {
485 return -1;
487 // clamp value to range [0..0x7fff], and convert to 16.16 fixed-point
488 devWidth = std::min(std::max(0, devWidth), 0x7fff);
489 entry.Insert(devWidth << 16);
491 return *entry;
495 bool gfxGDIFont::GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) {
496 DCForMetrics dc;
497 AutoSelectFont fs(dc, GetHFONT());
499 if (mIsBitmap) {
500 int devWidth;
501 if (!GetCharWidthI(dc, aGID, 1, nullptr, &devWidth)) {
502 return false;
504 devWidth = std::min(std::max(0, devWidth), 0x7fff);
506 *aBounds = gfxRect(0, -mMetrics->maxAscent, devWidth,
507 mMetrics->maxAscent + mMetrics->maxDescent);
508 return true;
511 const MAT2 kIdentityMatrix = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
512 GLYPHMETRICS gm;
513 if (GetGlyphOutlineW(dc, aGID, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr,
514 &kIdentityMatrix) == GDI_ERROR) {
515 return false;
518 if (gm.gmBlackBoxX == 1 && gm.gmBlackBoxY == 1 &&
519 !GetGlyphOutlineW(dc, aGID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, nullptr,
520 &kIdentityMatrix)) {
521 // Workaround for GetGlyphOutline returning 1x1 bounding box
522 // for <space> glyph that is in fact empty.
523 gm.gmBlackBoxX = 0;
524 gm.gmBlackBoxY = 0;
525 } else if (gm.gmBlackBoxX > 0 && !aTight) {
526 // The bounding box reported by Windows supposedly contains the glyph's
527 // "black" area; however, antialiasing (especially with ClearType) means
528 // that the actual image that needs to be rendered may "bleed" into the
529 // adjacent pixels, mainly on the right side.
530 gm.gmptGlyphOrigin.x -= 1;
531 gm.gmBlackBoxX += 3;
534 *aBounds = gfxRect(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
535 gm.gmBlackBoxX, gm.gmBlackBoxY);
536 return true;
539 void gfxGDIFont::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
540 FontCacheSizes* aSizes) const {
541 gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
542 aSizes->mFontInstances += aMallocSizeOf(mMetrics);
543 if (mGlyphWidths) {
544 aSizes->mFontInstances +=
545 mGlyphWidths->ShallowSizeOfIncludingThis(aMallocSizeOf);
549 void gfxGDIFont::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
550 FontCacheSizes* aSizes) const {
551 aSizes->mFontInstances += aMallocSizeOf(this);
552 AddSizeOfExcludingThis(aMallocSizeOf, aSizes);