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"
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
),
35 mScriptCache(nullptr) {
36 mNeedsSyntheticBold
= aFontStyle
->NeedsSyntheticBold(aFontEntry
);
41 mUnscaledFont
= aFontEntry
->LookupUnscaledFont(mFont
);
45 gfxGDIFont::~gfxGDIFont() {
47 ::DeleteObject(mFont
);
50 ScriptFreeCache(&mScriptCache
);
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
) {
66 NS_WARNING("invalid font! expect incorrect text rendering");
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
);
81 GetObject(GetHFONT(), sizeof(LOGFONT
), &lf
);
83 RefPtr
<ScaledFont
> newScaledFont
= Factory::CreateScaledFontForGDIFont(
84 &lf
, GetUnscaledFont(), GetAdjustedSize());
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
,
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);
123 void gfxGDIFont::Initialize() {
124 NS_ASSERTION(!mMetrics
, "re-creating metrics? this will leak");
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
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) {
145 switch (FontSizeAdjust::Tag(mStyle
.sizeAdjustBasis
)) {
147 MOZ_ASSERT_UNREACHABLE("unhandled sizeAdjustBasis?");
150 case FontSizeAdjust::Tag::ExHeight
:
151 aspect
= mMetrics
->xHeight
/ mMetrics
->emHeight
;
153 case FontSizeAdjust::Tag::CapHeight
:
154 aspect
= mMetrics
->capHeight
/ mMetrics
->emHeight
;
156 case FontSizeAdjust::Tag::ChWidth
: {
157 gfxFloat advance
= GetCharAdvance('0');
158 aspect
= advance
> 0.0 ? advance
/ mMetrics
->emHeight
: 0.5;
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;
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
);
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
));
205 NS_WARNING("Failed creating GDI font");
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}};
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
232 ROUND((double)metrics
.tmAscent
* DEFAULT_XHEIGHT_FACTOR
);
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
;
241 mMetrics
->capHeight
= gm
.gmptGlyphOrigin
.y
;
243 mMetrics
->emHeight
= metrics
.tmHeight
- metrics
.tmInternalLeading
;
244 gfxFloat typEmHeight
=
245 (double)oMetrics
.otmAscent
- (double)oMetrics
.otmDescent
;
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
);
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
);
260 NS_WARNING("Missing or corrupt font data, fasten your seatbelt");
262 memset(mMetrics
, 0, sizeof(*mMetrics
));
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'));
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
);
340 DWORD ret
= GetGlyphIndicesW(dc
.GetDC(), L
" ", 1, &glyph
,
341 GGI_MARK_NONEXISTING_GLYPHS
);
342 if (ret
!= GDI_ERROR
&& glyph
!= 0xFFFF) {
344 // Cache the width of a single space.
345 GetTextExtentPoint32W(dc
.GetDC(), L
" ", 1, &size
);
346 mMetrics
->spaceWidth
= ROUND(size
.cx
);
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
);
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
);
368 mMetrics
->ideographicWidth
= -1.0;
371 SanitizeMetrics(mMetrics
, GetFontEntry()->mIsBadUnderlineFont
);
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
;
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
);
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.
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)
415 // avoid GDI synthetic bold which occurs when weight
416 // specified is >= font data weight + 200
417 weight
= mNeedsSyntheticBold
? 700 : 200;
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
435 if (aUnicode
> 0xffff || aVarSelector
) {
440 mGlyphIDs
= MakeUnique
<nsTHashMap
<nsUint32HashKey
, uint32_t>>(64);
444 if (mGlyphIDs
->Get(aUnicode
, &gid
)) {
448 wchar_t ch
= aUnicode
;
450 HRESULT ret
= ScriptGetCMap(nullptr, &mScriptCache
, &ch
, 1, 0, &glyph
);
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
);
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) {
469 mGlyphIDs
->InsertOrUpdate(aUnicode
, glyph
);
473 int32_t gfxGDIFont::GetGlyphWidth(uint16_t aGID
) {
475 mGlyphWidths
= MakeUnique
<nsTHashMap
<nsUint32HashKey
, int32_t>>(128);
478 return mGlyphWidths
->WithEntryHandle(aGID
, [&](auto&& entry
) {
481 AutoSelectFont
fs(dc
, GetHFONT());
484 if (!GetCharWidthI(dc
, aGID
, 1, nullptr, &devWidth
)) {
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);
495 bool gfxGDIFont::GetGlyphBounds(uint16_t aGID
, gfxRect
* aBounds
, bool aTight
) {
497 AutoSelectFont
fs(dc
, GetHFONT());
501 if (!GetCharWidthI(dc
, aGID
, 1, nullptr, &devWidth
)) {
504 devWidth
= std::min(std::max(0, devWidth
), 0x7fff);
506 *aBounds
= gfxRect(0, -mMetrics
->maxAscent
, devWidth
,
507 mMetrics
->maxAscent
+ mMetrics
->maxDescent
);
511 const MAT2 kIdentityMatrix
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
513 if (GetGlyphOutlineW(dc
, aGID
, GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, nullptr,
514 &kIdentityMatrix
) == GDI_ERROR
) {
518 if (gm
.gmBlackBoxX
== 1 && gm
.gmBlackBoxY
== 1 &&
519 !GetGlyphOutlineW(dc
, aGID
, GGO_NATIVE
| GGO_GLYPH_INDEX
, &gm
, 0, nullptr,
521 // Workaround for GetGlyphOutline returning 1x1 bounding box
522 // for <space> glyph that is in fact empty.
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;
534 *aBounds
= gfxRect(gm
.gmptGlyphOrigin
.x
, -gm
.gmptGlyphOrigin
.y
,
535 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
539 void gfxGDIFont::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
,
540 FontCacheSizes
* aSizes
) const {
541 gfxFont::AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
542 aSizes
->mFontInstances
+= aMallocSizeOf(mMetrics
);
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
);