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/. */
5 
6 #include "gfxFontEntry.h"
7 
8 #include "mozilla/DebugOnly.h"
9 #include "mozilla/FontPropertyTypes.h"
10 #include "mozilla/MathAlgorithms.h"
11 
12 #include "mozilla/Logging.h"
13 
14 #include "gfxTextRun.h"
15 #include "gfxPlatform.h"
16 #include "nsGkAtoms.h"
17 
18 #include "gfxTypes.h"
19 #include "gfxContext.h"
20 #include "gfxFontConstants.h"
21 #include "gfxGraphiteShaper.h"
22 #include "gfxHarfBuzzShaper.h"
23 #include "gfxUserFontSet.h"
24 #include "gfxPlatformFontList.h"
25 #include "nsUnicodeProperties.h"
26 #include "nsMathUtils.h"
27 #include "nsBidiUtils.h"
28 #include "nsStyleConsts.h"
29 #include "mozilla/AppUnits.h"
30 #include "mozilla/FloatingPoint.h"
31 #ifdef MOZ_WASM_SANDBOXING_GRAPHITE
32 #  include "mozilla/ipc/LibrarySandboxPreload.h"
33 #endif
34 #include "mozilla/Likely.h"
35 #include "mozilla/MemoryReporting.h"
36 #include "mozilla/Preferences.h"
37 #include "mozilla/ScopeExit.h"
38 #include "mozilla/Services.h"
39 #include "mozilla/StaticPrefs_layout.h"
40 #include "mozilla/Telemetry.h"
41 #include "gfxSVGGlyphs.h"
42 #include "gfx2DGlue.h"
43 
44 #include "harfbuzz/hb.h"
45 #include "harfbuzz/hb-ot.h"
46 #include "graphite2/Font.h"
47 
48 #include "ThebesRLBox.h"
49 
50 #include <algorithm>
51 
52 using namespace mozilla;
53 using namespace mozilla::gfx;
54 using namespace mozilla::unicode;
55 using mozilla::services::GetObserverService;
56 
NotifyReleased()57 void gfxCharacterMap::NotifyReleased() {
58   gfxPlatformFontList* fontlist = gfxPlatformFontList::PlatformFontList();
59   if (mShared) {
60     fontlist->RemoveCmap(this);
61   }
62   delete this;
63 }
64 
gfxFontEntry()65 gfxFontEntry::gfxFontEntry()
66     : mFixedPitch(false),
67       mIsBadUnderlineFont(false),
68       mIsUserFontContainer(false),
69       mIsDataUserFont(false),
70       mIsLocalUserFont(false),
71       mStandardFace(false),
72       mIgnoreGDEF(false),
73       mIgnoreGSUB(false),
74       mSVGInitialized(false),
75       mHasSpaceFeaturesInitialized(false),
76       mHasSpaceFeatures(false),
77       mHasSpaceFeaturesKerning(false),
78       mHasSpaceFeaturesNonKerning(false),
79       mSkipDefaultFeatureSpaceCheck(false),
80       mGraphiteSpaceContextualsInitialized(false),
81       mHasGraphiteSpaceContextuals(false),
82       mSpaceGlyphIsInvisible(false),
83       mSpaceGlyphIsInvisibleInitialized(false),
84       mHasGraphiteTables(false),
85       mCheckedForGraphiteTables(false),
86       mHasCmapTable(false),
87       mGrFaceInitialized(false),
88       mCheckedForColorGlyph(false),
89       mCheckedForVariationAxes(false) {
90   memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
91   memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
92 }
93 
gfxFontEntry(const nsACString & aName,bool aIsStandardFace)94 gfxFontEntry::gfxFontEntry(const nsACString& aName, bool aIsStandardFace)
95     : mName(aName),
96       mFixedPitch(false),
97       mIsBadUnderlineFont(false),
98       mIsUserFontContainer(false),
99       mIsDataUserFont(false),
100       mIsLocalUserFont(false),
101       mStandardFace(aIsStandardFace),
102       mIgnoreGDEF(false),
103       mIgnoreGSUB(false),
104       mSVGInitialized(false),
105       mHasSpaceFeaturesInitialized(false),
106       mHasSpaceFeatures(false),
107       mHasSpaceFeaturesKerning(false),
108       mHasSpaceFeaturesNonKerning(false),
109       mSkipDefaultFeatureSpaceCheck(false),
110       mGraphiteSpaceContextualsInitialized(false),
111       mHasGraphiteSpaceContextuals(false),
112       mSpaceGlyphIsInvisible(false),
113       mSpaceGlyphIsInvisibleInitialized(false),
114       mHasGraphiteTables(false),
115       mCheckedForGraphiteTables(false),
116       mHasCmapTable(false),
117       mGrFaceInitialized(false),
118       mCheckedForColorGlyph(false),
119       mCheckedForVariationAxes(false) {
120   memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
121   memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
122 }
123 
~gfxFontEntry()124 gfxFontEntry::~gfxFontEntry() {
125   // Should not be dropped by stylo
126   MOZ_ASSERT(NS_IsMainThread());
127   hb_blob_destroy(mCOLR);
128   hb_blob_destroy(mCPAL);
129   if (TrakTableInitialized()) {
130     // Only if it was initialized, so that we don't try to call hb_blob_destroy
131     // on the kTrakTableUninitialized flag value!
132     hb_blob_destroy(mTrakTable);
133   }
134 
135   // For downloaded fonts, we need to tell the user font cache that this
136   // entry is being deleted.
137   if (mIsDataUserFont) {
138     gfxUserFontSet::UserFontCache::ForgetFont(this);
139   }
140 
141   if (mFeatureInputs) {
142     for (auto iter = mFeatureInputs->Iter(); !iter.Done(); iter.Next()) {
143       hb_set_t*& set = iter.Data();
144       hb_set_destroy(set);
145     }
146   }
147 
148   // By the time the entry is destroyed, all font instances that were
149   // using it should already have been deleted, and so the HB and/or Gr
150   // face objects should have been released.
151   MOZ_ASSERT(!mHBFace);
152   MOZ_ASSERT(!mGrFaceInitialized);
153 }
154 
TrySetShmemCharacterMap()155 bool gfxFontEntry::TrySetShmemCharacterMap() {
156   MOZ_ASSERT(mShmemFace);
157   auto list = gfxPlatformFontList::PlatformFontList()->SharedFontList();
158   mShmemCharacterMap =
159       static_cast<const SharedBitSet*>(mShmemFace->mCharacterMap.ToPtr(list));
160   return mShmemCharacterMap != nullptr;
161 }
162 
TestCharacterMap(uint32_t aCh)163 bool gfxFontEntry::TestCharacterMap(uint32_t aCh) {
164   if (!mCharacterMap && !mShmemCharacterMap) {
165     ReadCMAP();
166     MOZ_ASSERT(mCharacterMap || mShmemCharacterMap,
167                "failed to initialize character map");
168   }
169   return mShmemCharacterMap ? mShmemCharacterMap->test(aCh)
170                             : mCharacterMap->test(aCh);
171 }
172 
InitializeUVSMap()173 nsresult gfxFontEntry::InitializeUVSMap() {
174   // mUVSOffset will not be initialized
175   // until cmap is initialized.
176   if (!mCharacterMap && !mShmemCharacterMap) {
177     ReadCMAP();
178     NS_ASSERTION(mCharacterMap || mShmemCharacterMap,
179                  "failed to initialize character map");
180   }
181 
182   if (!mUVSOffset) {
183     return NS_ERROR_FAILURE;
184   }
185 
186   if (!mUVSData) {
187     const uint32_t kCmapTag = TRUETYPE_TAG('c', 'm', 'a', 'p');
188     AutoTable cmapTable(this, kCmapTag);
189     if (!cmapTable) {
190       mUVSOffset = 0;  // don't bother to read the table again
191       return NS_ERROR_FAILURE;
192     }
193 
194     UniquePtr<uint8_t[]> uvsData;
195     unsigned int cmapLen;
196     const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
197     nsresult rv = gfxFontUtils::ReadCMAPTableFormat14(
198         (const uint8_t*)cmapData + mUVSOffset, cmapLen - mUVSOffset, uvsData);
199 
200     if (NS_FAILED(rv)) {
201       mUVSOffset = 0;  // don't bother to read the table again
202       return rv;
203     }
204 
205     mUVSData = std::move(uvsData);
206   }
207 
208   return NS_OK;
209 }
210 
GetUVSGlyph(uint32_t aCh,uint32_t aVS)211 uint16_t gfxFontEntry::GetUVSGlyph(uint32_t aCh, uint32_t aVS) {
212   InitializeUVSMap();
213 
214   if (mUVSData) {
215     return gfxFontUtils::MapUVSToGlyphFormat14(mUVSData.get(), aCh, aVS);
216   }
217 
218   return 0;
219 }
220 
SupportsScriptInGSUB(const hb_tag_t * aScriptTags,uint32_t aNumTags)221 bool gfxFontEntry::SupportsScriptInGSUB(const hb_tag_t* aScriptTags,
222                                         uint32_t aNumTags) {
223   hb_face_t* face = GetHBFace();
224   if (!face) {
225     return false;
226   }
227 
228   unsigned int index;
229   hb_tag_t chosenScript;
230   bool found = hb_ot_layout_table_select_script(
231       face, TRUETYPE_TAG('G', 'S', 'U', 'B'), aNumTags, aScriptTags, &index,
232       &chosenScript);
233   hb_face_destroy(face);
234 
235   return found && chosenScript != TRUETYPE_TAG('D', 'F', 'L', 'T');
236 }
237 
ReadCMAP(FontInfoData * aFontInfoData)238 nsresult gfxFontEntry::ReadCMAP(FontInfoData* aFontInfoData) {
239   NS_ASSERTION(false, "using default no-op implementation of ReadCMAP");
240   mCharacterMap = new gfxCharacterMap();
241   return NS_OK;
242 }
243 
RealFaceName()244 nsCString gfxFontEntry::RealFaceName() {
245   AutoTable nameTable(this, TRUETYPE_TAG('n', 'a', 'm', 'e'));
246   if (nameTable) {
247     nsAutoCString name;
248     nsresult rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
249     if (NS_SUCCEEDED(rv)) {
250       return std::move(name);
251     }
252   }
253   return Name();
254 }
255 
FindOrMakeFont(const gfxFontStyle * aStyle,gfxCharacterMap * aUnicodeRangeMap)256 gfxFont* gfxFontEntry::FindOrMakeFont(const gfxFontStyle* aStyle,
257                                       gfxCharacterMap* aUnicodeRangeMap) {
258   // the font entry name is the psname, not the family name
259   gfxFont* font =
260       gfxFontCache::GetCache()->Lookup(this, aStyle, aUnicodeRangeMap);
261 
262   if (!font) {
263     gfxFont* newFont = CreateFontInstance(aStyle);
264     if (!newFont) {
265       return nullptr;
266     }
267     if (!newFont->Valid()) {
268       delete newFont;
269       return nullptr;
270     }
271     font = newFont;
272     font->SetUnicodeRangeMap(aUnicodeRangeMap);
273     gfxFontCache::GetCache()->AddNew(font);
274   }
275   return font;
276 }
277 
UnitsPerEm()278 uint16_t gfxFontEntry::UnitsPerEm() {
279   if (!mUnitsPerEm) {
280     AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd'));
281     if (headTable) {
282       uint32_t len;
283       const HeadTable* head =
284           reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable, &len));
285       if (len >= sizeof(HeadTable)) {
286         mUnitsPerEm = head->unitsPerEm;
287       }
288     }
289 
290     // if we didn't find a usable 'head' table, or if the value was
291     // outside the valid range, record it as invalid
292     if (mUnitsPerEm < kMinUPEM || mUnitsPerEm > kMaxUPEM) {
293       mUnitsPerEm = kInvalidUPEM;
294     }
295   }
296   return mUnitsPerEm;
297 }
298 
HasSVGGlyph(uint32_t aGlyphId)299 bool gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId) {
300   NS_ASSERTION(mSVGInitialized,
301                "SVG data has not yet been loaded. TryGetSVGData() first.");
302   return mSVGGlyphs->HasSVGGlyph(aGlyphId);
303 }
304 
GetSVGGlyphExtents(DrawTarget * aDrawTarget,uint32_t aGlyphId,gfxFloat aSize,gfxRect * aResult)305 bool gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget,
306                                       uint32_t aGlyphId, gfxFloat aSize,
307                                       gfxRect* aResult) {
308   MOZ_ASSERT(mSVGInitialized,
309              "SVG data has not yet been loaded. TryGetSVGData() first.");
310   MOZ_ASSERT(mUnitsPerEm >= kMinUPEM && mUnitsPerEm <= kMaxUPEM,
311              "font has invalid unitsPerEm");
312 
313   gfxMatrix svgToApp(aSize / mUnitsPerEm, 0, 0, aSize / mUnitsPerEm, 0, 0);
314   return mSVGGlyphs->GetGlyphExtents(aGlyphId, svgToApp, aResult);
315 }
316 
RenderSVGGlyph(gfxContext * aContext,uint32_t aGlyphId,SVGContextPaint * aContextPaint)317 void gfxFontEntry::RenderSVGGlyph(gfxContext* aContext, uint32_t aGlyphId,
318                                   SVGContextPaint* aContextPaint) {
319   NS_ASSERTION(mSVGInitialized,
320                "SVG data has not yet been loaded. TryGetSVGData() first.");
321   mSVGGlyphs->RenderGlyph(aContext, aGlyphId, aContextPaint);
322 }
323 
TryGetSVGData(gfxFont * aFont)324 bool gfxFontEntry::TryGetSVGData(gfxFont* aFont) {
325   if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
326     return false;
327   }
328 
329   if (!mSVGInitialized) {
330     mSVGInitialized = true;
331 
332     // If UnitsPerEm is not known/valid, we can't use SVG glyphs
333     if (UnitsPerEm() == kInvalidUPEM) {
334       return false;
335     }
336 
337     // We don't use AutoTable here because we'll pass ownership of this
338     // blob to the gfxSVGGlyphs, once we've confirmed the table exists
339     hb_blob_t* svgTable = GetFontTable(TRUETYPE_TAG('S', 'V', 'G', ' '));
340     if (!svgTable) {
341       return false;
342     }
343 
344     // gfxSVGGlyphs will hb_blob_destroy() the table when it is finished
345     // with it.
346     mSVGGlyphs = MakeUnique<gfxSVGGlyphs>(svgTable, this);
347   }
348 
349   if (mSVGGlyphs && !mFontsUsingSVGGlyphs.Contains(aFont)) {
350     mFontsUsingSVGGlyphs.AppendElement(aFont);
351   }
352 
353   return !!mSVGGlyphs;
354 }
355 
NotifyFontDestroyed(gfxFont * aFont)356 void gfxFontEntry::NotifyFontDestroyed(gfxFont* aFont) {
357   mFontsUsingSVGGlyphs.RemoveElement(aFont);
358 }
359 
NotifyGlyphsChanged()360 void gfxFontEntry::NotifyGlyphsChanged() {
361   for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
362     gfxFont* font = mFontsUsingSVGGlyphs[i];
363     font->NotifyGlyphsChanged();
364   }
365 }
366 
TryGetColorGlyphs()367 bool gfxFontEntry::TryGetColorGlyphs() {
368   if (mCheckedForColorGlyph) {
369     return (mCOLR && mCPAL);
370   }
371 
372   mCheckedForColorGlyph = true;
373 
374   mCOLR = GetFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R'));
375   if (!mCOLR) {
376     return false;
377   }
378 
379   mCPAL = GetFontTable(TRUETYPE_TAG('C', 'P', 'A', 'L'));
380   if (!mCPAL) {
381     hb_blob_destroy(mCOLR);
382     mCOLR = nullptr;
383     return false;
384   }
385 
386   // validation COLR and CPAL table
387   if (gfxFontUtils::ValidateColorGlyphs(mCOLR, mCPAL)) {
388     return true;
389   }
390 
391   hb_blob_destroy(mCOLR);
392   hb_blob_destroy(mCPAL);
393   mCOLR = nullptr;
394   mCPAL = nullptr;
395   return false;
396 }
397 
398 /**
399  * FontTableBlobData
400  *
401  * See FontTableHashEntry for the general strategy.
402  */
403 
404 class gfxFontEntry::FontTableBlobData {
405  public:
FontTableBlobData(nsTArray<uint8_t> && aBuffer)406   explicit FontTableBlobData(nsTArray<uint8_t>&& aBuffer)
407       : mTableData(std::move(aBuffer)), mHashtable(nullptr), mHashKey(0) {
408     MOZ_COUNT_CTOR(FontTableBlobData);
409   }
410 
~FontTableBlobData()411   ~FontTableBlobData() {
412     MOZ_COUNT_DTOR(FontTableBlobData);
413     if (mHashtable && mHashKey) {
414       mHashtable->RemoveEntry(mHashKey);
415     }
416   }
417 
418   // Useful for creating blobs
GetTable() const419   const char* GetTable() const {
420     return reinterpret_cast<const char*>(mTableData.Elements());
421   }
GetTableLength() const422   uint32_t GetTableLength() const { return mTableData.Length(); }
423 
424   // Tell this FontTableBlobData to remove the HashEntry when this is
425   // destroyed.
ManageHashEntry(nsTHashtable<FontTableHashEntry> * aHashtable,uint32_t aHashKey)426   void ManageHashEntry(nsTHashtable<FontTableHashEntry>* aHashtable,
427                        uint32_t aHashKey) {
428     mHashtable = aHashtable;
429     mHashKey = aHashKey;
430   }
431 
432   // Disconnect from the HashEntry (because the blob has already been
433   // removed from the hashtable).
ForgetHashEntry()434   void ForgetHashEntry() {
435     mHashtable = nullptr;
436     mHashKey = 0;
437   }
438 
SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const439   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
440     return mTableData.ShallowSizeOfExcludingThis(aMallocSizeOf);
441   }
SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const442   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
443     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
444   }
445 
446  private:
447   // The font table data block
448   nsTArray<uint8_t> mTableData;
449 
450   // The blob destroy function needs to know the owning hashtable
451   // and the hashtable key, so that it can remove the entry.
452   nsTHashtable<FontTableHashEntry>* mHashtable;
453   uint32_t mHashKey;
454 
455   // not implemented
456   FontTableBlobData(const FontTableBlobData&);
457 };
458 
ShareTableAndGetBlob(nsTArray<uint8_t> && aTable,nsTHashtable<FontTableHashEntry> * aHashtable)459 hb_blob_t* gfxFontEntry::FontTableHashEntry::ShareTableAndGetBlob(
460     nsTArray<uint8_t>&& aTable, nsTHashtable<FontTableHashEntry>* aHashtable) {
461   Clear();
462   // adopts elements of aTable
463   mSharedBlobData = new FontTableBlobData(std::move(aTable));
464 
465   mBlob = hb_blob_create(
466       mSharedBlobData->GetTable(), mSharedBlobData->GetTableLength(),
467       HB_MEMORY_MODE_READONLY, mSharedBlobData, DeleteFontTableBlobData);
468   if (mBlob == hb_blob_get_empty()) {
469     // The FontTableBlobData was destroyed during hb_blob_create().
470     // The (empty) blob is still be held in the hashtable with a strong
471     // reference.
472     return hb_blob_reference(mBlob);
473   }
474 
475   // Tell the FontTableBlobData to remove this hash entry when destroyed.
476   // The hashtable does not keep a strong reference.
477   mSharedBlobData->ManageHashEntry(aHashtable, GetKey());
478   return mBlob;
479 }
480 
Clear()481 void gfxFontEntry::FontTableHashEntry::Clear() {
482   // If the FontTableBlobData is managing the hash entry, then the blob is
483   // not owned by this HashEntry; otherwise there is strong reference to the
484   // blob that must be removed.
485   if (mSharedBlobData) {
486     mSharedBlobData->ForgetHashEntry();
487     mSharedBlobData = nullptr;
488   } else {
489     hb_blob_destroy(mBlob);
490   }
491   mBlob = nullptr;
492 }
493 
494 // a hb_destroy_func for hb_blob_create
495 
496 /* static */
DeleteFontTableBlobData(void * aBlobData)497 void gfxFontEntry::FontTableHashEntry::DeleteFontTableBlobData(
498     void* aBlobData) {
499   delete static_cast<FontTableBlobData*>(aBlobData);
500 }
501 
GetBlob() const502 hb_blob_t* gfxFontEntry::FontTableHashEntry::GetBlob() const {
503   return hb_blob_reference(mBlob);
504 }
505 
GetExistingFontTable(uint32_t aTag,hb_blob_t ** aBlob)506 bool gfxFontEntry::GetExistingFontTable(uint32_t aTag, hb_blob_t** aBlob) {
507   if (!mFontTableCache) {
508     // we do this here rather than on fontEntry construction
509     // because not all shapers will access the table cache at all
510     mFontTableCache = MakeUnique<nsTHashtable<FontTableHashEntry>>(8);
511   }
512 
513   FontTableHashEntry* entry = mFontTableCache->GetEntry(aTag);
514   if (!entry) {
515     return false;
516   }
517 
518   *aBlob = entry->GetBlob();
519   return true;
520 }
521 
ShareFontTableAndGetBlob(uint32_t aTag,nsTArray<uint8_t> * aBuffer)522 hb_blob_t* gfxFontEntry::ShareFontTableAndGetBlob(uint32_t aTag,
523                                                   nsTArray<uint8_t>* aBuffer) {
524   if (MOZ_UNLIKELY(!mFontTableCache)) {
525     // we do this here rather than on fontEntry construction
526     // because not all shapers will access the table cache at all
527     mFontTableCache = MakeUnique<nsTHashtable<FontTableHashEntry>>(8);
528   }
529 
530   FontTableHashEntry* entry = mFontTableCache->PutEntry(aTag);
531   if (MOZ_UNLIKELY(!entry)) {  // OOM
532     return nullptr;
533   }
534 
535   if (!aBuffer) {
536     // ensure the entry is null
537     entry->Clear();
538     return nullptr;
539   }
540 
541   return entry->ShareTableAndGetBlob(std::move(*aBuffer),
542                                      mFontTableCache.get());
543 }
544 
GetCMAPFromFontInfo(FontInfoData * aFontInfoData,uint32_t & aUVSOffset)545 already_AddRefed<gfxCharacterMap> gfxFontEntry::GetCMAPFromFontInfo(
546     FontInfoData* aFontInfoData, uint32_t& aUVSOffset) {
547   if (!aFontInfoData || !aFontInfoData->mLoadCmaps) {
548     return nullptr;
549   }
550 
551   return aFontInfoData->GetCMAP(mName, aUVSOffset);
552 }
553 
GetFontTable(uint32_t aTag)554 hb_blob_t* gfxFontEntry::GetFontTable(uint32_t aTag) {
555   hb_blob_t* blob;
556   if (GetExistingFontTable(aTag, &blob)) {
557     return blob;
558   }
559 
560   nsTArray<uint8_t> buffer;
561   bool haveTable = NS_SUCCEEDED(CopyFontTable(aTag, buffer));
562 
563   return ShareFontTableAndGetBlob(aTag, haveTable ? &buffer : nullptr);
564 }
565 
566 // callback for HarfBuzz to get a font table (in hb_blob_t form)
567 // from the font entry (passed as aUserData)
568 /*static*/
HBGetTable(hb_face_t * face,uint32_t aTag,void * aUserData)569 hb_blob_t* gfxFontEntry::HBGetTable(hb_face_t* face, uint32_t aTag,
570                                     void* aUserData) {
571   gfxFontEntry* fontEntry = static_cast<gfxFontEntry*>(aUserData);
572 
573   // bug 589682 - ignore the GDEF table in buggy fonts (applies to
574   // Italic and BoldItalic faces of Times New Roman)
575   if (aTag == TRUETYPE_TAG('G', 'D', 'E', 'F') && fontEntry->IgnoreGDEF()) {
576     return nullptr;
577   }
578 
579   // bug 721719 - ignore the GSUB table in buggy fonts (applies to Roboto,
580   // at least on some Android ICS devices; set in gfxFT2FontList.cpp)
581   if (aTag == TRUETYPE_TAG('G', 'S', 'U', 'B') && fontEntry->IgnoreGSUB()) {
582     return nullptr;
583   }
584 
585   return fontEntry->GetFontTable(aTag);
586 }
587 
588 /*static*/
HBFaceDeletedCallback(void * aUserData)589 void gfxFontEntry::HBFaceDeletedCallback(void* aUserData) {
590   gfxFontEntry* fe = static_cast<gfxFontEntry*>(aUserData);
591   fe->ForgetHBFace();
592 }
593 
ForgetHBFace()594 void gfxFontEntry::ForgetHBFace() { mHBFace = nullptr; }
595 
GetHBFace()596 hb_face_t* gfxFontEntry::GetHBFace() {
597   if (!mHBFace) {
598     mHBFace =
599         hb_face_create_for_tables(HBGetTable, this, HBFaceDeletedCallback);
600     return mHBFace;
601   }
602   return hb_face_reference(mHBFace);
603 }
604 
605 struct gfxFontEntry::GrSandboxData {
606   rlbox_sandbox_gr sandbox;
607   sandbox_callback_gr<const void* (*)(const void*, unsigned int, size_t*)>
608       grGetTableCallback;
609   sandbox_callback_gr<void (*)(const void*, const void*)>
610       grReleaseTableCallback;
611   // Text Shapers register a callback to get glyph advances
612   sandbox_callback_gr<float (*)(const void*, uint16_t)>
613       grGetGlyphAdvanceCallback;
614 
GrSandboxDatagfxFontEntry::GrSandboxData615   GrSandboxData() {
616 #ifdef MOZ_WASM_SANDBOXING_GRAPHITE
617     // Firefox preloads the library externally to ensure we won't be stopped by
618     // the content sandbox
619     const bool external_loads_exist = true;
620     // See Bug 1606981: In some environments allowing stdio in the wasm sandbox
621     // fails as the I/O redirection involves querying meta-data of file
622     // descriptors. This querying fails in some environments.
623     const bool allow_stdio = false;
624     sandbox.create_sandbox(mozilla::ipc::GetSandboxedGraphitePath().get(),
625                            external_loads_exist, allow_stdio);
626 #else
627     sandbox.create_sandbox();
628 #endif
629     grGetTableCallback = sandbox.register_callback(GrGetTable);
630     grReleaseTableCallback = sandbox.register_callback(GrReleaseTable);
631     grGetGlyphAdvanceCallback =
632         sandbox.register_callback(gfxGraphiteShaper::GrGetAdvance);
633   }
634 
~GrSandboxDatagfxFontEntry::GrSandboxData635   ~GrSandboxData() {
636     grGetTableCallback.unregister();
637     grReleaseTableCallback.unregister();
638     grGetGlyphAdvanceCallback.unregister();
639     sandbox.destroy_sandbox();
640   }
641 };
642 
643 static thread_local gfxFontEntry* tl_grGetFontTableCallbackData = nullptr;
644 
645 /*static*/
GrGetTable(rlbox_sandbox_gr & sandbox,tainted_opaque_gr<const void * >,tainted_opaque_gr<unsigned int> aName,tainted_opaque_gr<size_t * > aLen)646 tainted_opaque_gr<const void*> gfxFontEntry::GrGetTable(
647     rlbox_sandbox_gr& sandbox,
648     tainted_opaque_gr<const void*> /* aAppFaceHandle */,
649     tainted_opaque_gr<unsigned int> aName, tainted_opaque_gr<size_t*> aLen) {
650   gfxFontEntry* fontEntry = tl_grGetFontTableCallbackData;
651   tainted_gr<size_t*> t_aLen = rlbox::from_opaque(aLen);
652   *t_aLen = 0;
653   tainted_gr<const void*> ret = nullptr;
654 
655   if (fontEntry) {
656     unsigned int fontTableKey =
657         rlbox::from_opaque(aName).unverified_safe_because(
658             "This is only being used to index into a hashmap, which is robust "
659             "for any value. No checks needed.");
660     hb_blob_t* blob = fontEntry->GetFontTable(fontTableKey);
661 
662     if (blob) {
663       unsigned int blobLength;
664       const void* tableData = hb_blob_get_data(blob, &blobLength);
665       // tableData is read-only data shared with the sandbox.
666       // Making a copy in sandbox memory
667       tainted_gr<void*> t_tableData = rlbox::sandbox_reinterpret_cast<void*>(
668           sandbox.malloc_in_sandbox<char>(blobLength));
669       if (t_tableData) {
670         rlbox::memcpy(sandbox, t_tableData, tableData, blobLength);
671         *t_aLen = blobLength;
672         ret = rlbox::sandbox_const_cast<const void*>(t_tableData);
673       }
674       hb_blob_destroy(blob);
675     }
676   }
677 
678   return ret.to_opaque();
679 }
680 
681 /*static*/
GrReleaseTable(rlbox_sandbox_gr & sandbox,tainted_opaque_gr<const void * >,tainted_opaque_gr<const void * > aTableBuffer)682 void gfxFontEntry::GrReleaseTable(
683     rlbox_sandbox_gr& sandbox,
684     tainted_opaque_gr<const void*> /* aAppFaceHandle */,
685     tainted_opaque_gr<const void*> aTableBuffer) {
686   sandbox.free_in_sandbox(rlbox::from_opaque(aTableBuffer));
687 }
688 
GetGrSandbox()689 rlbox_sandbox_gr* gfxFontEntry::GetGrSandbox() {
690   MOZ_ASSERT(mSandboxData != nullptr);
691   return &mSandboxData->sandbox;
692 }
693 
694 sandbox_callback_gr<float (*)(const void*, uint16_t)>*
GetGrSandboxAdvanceCallbackHandle()695 gfxFontEntry::GetGrSandboxAdvanceCallbackHandle() {
696   MOZ_ASSERT(mSandboxData != nullptr);
697   return &mSandboxData->grGetGlyphAdvanceCallback;
698 }
699 
GetGrFace()700 tainted_opaque_gr<gr_face*> gfxFontEntry::GetGrFace() {
701   if (!mGrFaceInitialized) {
702     // When possible, the below code will use WASM as a sandboxing mechanism.
703     // At this time the wasm sandbox does not support threads.
704     // If Thebes is updated to make callst to the sandbox on multiple threaads,
705     // we need to make sure the underlying sandbox supports threading.
706     MOZ_ASSERT(NS_IsMainThread());
707 
708     mSandboxData = new GrSandboxData();
709 
710     auto p_faceOps = mSandboxData->sandbox.malloc_in_sandbox<gr_face_ops>();
711     if (!p_faceOps) {
712       MOZ_CRASH("Graphite sandbox memory allocation failed");
713     }
714     auto cleanup = MakeScopeExit(
715         [&] { mSandboxData->sandbox.free_in_sandbox(p_faceOps); });
716     p_faceOps->size = sizeof(*p_faceOps);
717     p_faceOps->get_table = mSandboxData->grGetTableCallback;
718     p_faceOps->release_table = mSandboxData->grReleaseTableCallback;
719 
720     tl_grGetFontTableCallbackData = this;
721     auto face = sandbox_invoke(
722         mSandboxData->sandbox, gr_make_face_with_ops,
723         // For security, we do not pass the callback data to this arg, and use
724         // a TLS var instead. However, gr_make_face_with_ops expects this to
725         // be a non null ptr. Therefore,  we should pass some dummy non null
726         // pointer which will be passed to callbacks, but never used. Let's just
727         // pass p_faceOps again, as this is a non-null tainted pointer.
728         p_faceOps /* appFaceHandle */, p_faceOps, gr_face_default);
729     tl_grGetFontTableCallbackData = nullptr;
730     mGrFace = face.to_opaque();
731     mGrFaceInitialized = true;
732   }
733   ++mGrFaceRefCnt;
734   return mGrFace;
735 }
736 
ReleaseGrFace(tainted_opaque_gr<gr_face * > aFace)737 void gfxFontEntry::ReleaseGrFace(tainted_opaque_gr<gr_face*> aFace) {
738   MOZ_ASSERT(
739       (rlbox::from_opaque(aFace) == rlbox::from_opaque(mGrFace))
740           .unverified_safe_because(
741               "This is safe as the only thing we are doing is comparing "
742               "addresses of two tainted pointers. Furthermore this is used "
743               "merely as a debugging aid in the debug builds. This function is "
744               "called only from the trusted Firefox code rather than the "
745               "untrusted libGraphite."));  // sanity-check
746   MOZ_ASSERT(mGrFaceRefCnt > 0);
747   if (--mGrFaceRefCnt == 0) {
748     auto t_mGrFace = rlbox::from_opaque(mGrFace);
749 
750     tl_grGetFontTableCallbackData = this;
751     sandbox_invoke(mSandboxData->sandbox, gr_face_destroy, t_mGrFace);
752     tl_grGetFontTableCallbackData = nullptr;
753 
754     t_mGrFace = nullptr;
755     mGrFace = t_mGrFace.to_opaque();
756 
757     delete mSandboxData;
758     mSandboxData = nullptr;
759 
760     mGrFaceInitialized = false;
761   }
762 }
763 
DisconnectSVG()764 void gfxFontEntry::DisconnectSVG() {
765   if (mSVGInitialized && mSVGGlyphs) {
766     mSVGGlyphs = nullptr;
767     mSVGInitialized = false;
768   }
769 }
770 
HasFontTable(uint32_t aTableTag)771 bool gfxFontEntry::HasFontTable(uint32_t aTableTag) {
772   AutoTable table(this, aTableTag);
773   return table && hb_blob_get_length(table) > 0;
774 }
775 
CheckForGraphiteTables()776 void gfxFontEntry::CheckForGraphiteTables() {
777   mHasGraphiteTables = HasFontTable(TRUETYPE_TAG('S', 'i', 'l', 'f'));
778 }
779 
HasGraphiteSpaceContextuals()780 tainted_boolean_hint gfxFontEntry::HasGraphiteSpaceContextuals() {
781   if (!mGraphiteSpaceContextualsInitialized) {
782     auto face = GetGrFace();
783     auto t_face = rlbox::from_opaque(face);
784     if (t_face) {
785       tainted_gr<const gr_faceinfo*> faceInfo =
786           sandbox_invoke(mSandboxData->sandbox, gr_face_info, t_face, 0);
787       // Comparison with a value in sandboxed memory returns a
788       // tainted_boolean_hint, i.e. a "hint", since the value could be changed
789       // maliciously at any moment.
790       tainted_boolean_hint is_not_none =
791           faceInfo->space_contextuals != gr_faceinfo::gr_space_none;
792       mHasGraphiteSpaceContextuals = is_not_none.unverified_safe_because(
793           "Note ideally mHasGraphiteSpaceContextuals would be "
794           "tainted_boolean_hint, but RLBox does not yet support bitfields, so "
795           "it is not wrapped. However, its value is only ever accessed through "
796           "this function which returns a tainted_boolean_hint, so unwrapping "
797           "temporarily is safe. We remove the wrapper now and re-add it "
798           "below.");
799     }
800     ReleaseGrFace(face);  // always balance GetGrFace, even if face is null
801     mGraphiteSpaceContextualsInitialized = true;
802   }
803 
804   bool ret = mHasGraphiteSpaceContextuals;
805   return tainted_boolean_hint(ret);
806 }
807 
808 #define FEATURE_SCRIPT_MASK 0x000000ff  // script index replaces low byte of tag
809 
810 static_assert(int(Script::NUM_SCRIPT_CODES) <= FEATURE_SCRIPT_MASK,
811               "Too many script codes");
812 
813 // high-order three bytes of tag with script in low-order byte
814 #define SCRIPT_FEATURE(s, tag)        \
815   (((~FEATURE_SCRIPT_MASK) & (tag)) | \
816    ((FEATURE_SCRIPT_MASK) & static_cast<uint32_t>(s)))
817 
SupportsOpenTypeFeature(Script aScript,uint32_t aFeatureTag)818 bool gfxFontEntry::SupportsOpenTypeFeature(Script aScript,
819                                            uint32_t aFeatureTag) {
820   if (!mSupportedFeatures) {
821     mSupportedFeatures = MakeUnique<nsDataHashtable<nsUint32HashKey, bool>>();
822   }
823 
824   // note: high-order three bytes *must* be unique for each feature
825   // listed below (see SCRIPT_FEATURE macro def'n)
826   NS_ASSERTION(aFeatureTag == HB_TAG('s', 'm', 'c', 'p') ||
827                    aFeatureTag == HB_TAG('c', '2', 's', 'c') ||
828                    aFeatureTag == HB_TAG('p', 'c', 'a', 'p') ||
829                    aFeatureTag == HB_TAG('c', '2', 'p', 'c') ||
830                    aFeatureTag == HB_TAG('s', 'u', 'p', 's') ||
831                    aFeatureTag == HB_TAG('s', 'u', 'b', 's') ||
832                    aFeatureTag == HB_TAG('v', 'e', 'r', 't'),
833                "use of unknown feature tag");
834 
835   // note: graphite feature support uses the last script index
836   NS_ASSERTION(int(aScript) < FEATURE_SCRIPT_MASK - 1,
837                "need to bump the size of the feature shift");
838 
839   uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
840   bool result;
841   if (mSupportedFeatures->Get(scriptFeature, &result)) {
842     return result;
843   }
844 
845   result = false;
846 
847   hb_face_t* face = GetHBFace();
848 
849   if (hb_ot_layout_has_substitution(face)) {
850     hb_script_t hbScript =
851         gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
852 
853     // Get the OpenType tag(s) that match this script code
854     unsigned int scriptCount = 4;
855     hb_tag_t scriptTags[4];
856     hb_ot_tags_from_script_and_language(hbScript, HB_LANGUAGE_INVALID,
857                                         &scriptCount, scriptTags, nullptr,
858                                         nullptr);
859 
860     // Append DEFAULT to the returned tags, if room
861     if (scriptCount < 4) {
862       scriptTags[scriptCount++] = HB_OT_TAG_DEFAULT_SCRIPT;
863     }
864 
865     // Now check for 'smcp' under the first of those scripts that is present
866     const hb_tag_t kGSUB = HB_TAG('G', 'S', 'U', 'B');
867     for (unsigned int i = 0; i < scriptCount; i++) {
868       unsigned int scriptIndex;
869       if (hb_ot_layout_table_find_script(face, kGSUB, scriptTags[i],
870                                          &scriptIndex)) {
871         if (hb_ot_layout_language_find_feature(
872                 face, kGSUB, scriptIndex, HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
873                 aFeatureTag, nullptr)) {
874           result = true;
875         }
876         break;
877       }
878     }
879   }
880 
881   hb_face_destroy(face);
882 
883   mSupportedFeatures->Put(scriptFeature, result);
884 
885   return result;
886 }
887 
InputsForOpenTypeFeature(Script aScript,uint32_t aFeatureTag)888 const hb_set_t* gfxFontEntry::InputsForOpenTypeFeature(Script aScript,
889                                                        uint32_t aFeatureTag) {
890   if (!mFeatureInputs) {
891     mFeatureInputs = MakeUnique<nsDataHashtable<nsUint32HashKey, hb_set_t*>>();
892   }
893 
894   NS_ASSERTION(aFeatureTag == HB_TAG('s', 'u', 'p', 's') ||
895                    aFeatureTag == HB_TAG('s', 'u', 'b', 's') ||
896                    aFeatureTag == HB_TAG('v', 'e', 'r', 't'),
897                "use of unknown feature tag");
898 
899   uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
900   hb_set_t* inputGlyphs;
901   if (mFeatureInputs->Get(scriptFeature, &inputGlyphs)) {
902     return inputGlyphs;
903   }
904 
905   inputGlyphs = hb_set_create();
906 
907   hb_face_t* face = GetHBFace();
908 
909   if (hb_ot_layout_has_substitution(face)) {
910     hb_script_t hbScript =
911         gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
912 
913     // Get the OpenType tag(s) that match this script code
914     unsigned int scriptCount = 4;
915     hb_tag_t scriptTags[5];  // space for null terminator
916     hb_ot_tags_from_script_and_language(hbScript, HB_LANGUAGE_INVALID,
917                                         &scriptCount, scriptTags, nullptr,
918                                         nullptr);
919 
920     // Append DEFAULT to the returned tags, if room
921     if (scriptCount < 4) {
922       scriptTags[scriptCount++] = HB_OT_TAG_DEFAULT_SCRIPT;
923     }
924     scriptTags[scriptCount++] = 0;
925 
926     const hb_tag_t kGSUB = HB_TAG('G', 'S', 'U', 'B');
927     hb_tag_t features[2] = {aFeatureTag, HB_TAG_NONE};
928     hb_set_t* featurelookups = hb_set_create();
929     hb_ot_layout_collect_lookups(face, kGSUB, scriptTags, nullptr, features,
930                                  featurelookups);
931     hb_codepoint_t index = -1;
932     while (hb_set_next(featurelookups, &index)) {
933       hb_ot_layout_lookup_collect_glyphs(face, kGSUB, index, nullptr,
934                                          inputGlyphs, nullptr, nullptr);
935     }
936     hb_set_destroy(featurelookups);
937   }
938 
939   hb_face_destroy(face);
940 
941   mFeatureInputs->Put(scriptFeature, inputGlyphs);
942   return inputGlyphs;
943 }
944 
SupportsGraphiteFeature(uint32_t aFeatureTag)945 bool gfxFontEntry::SupportsGraphiteFeature(uint32_t aFeatureTag) {
946   if (!mSupportedFeatures) {
947     mSupportedFeatures = MakeUnique<nsDataHashtable<nsUint32HashKey, bool>>();
948   }
949 
950   // note: high-order three bytes *must* be unique for each feature
951   // listed below (see SCRIPT_FEATURE macro def'n)
952   NS_ASSERTION(aFeatureTag == HB_TAG('s', 'm', 'c', 'p') ||
953                    aFeatureTag == HB_TAG('c', '2', 's', 'c') ||
954                    aFeatureTag == HB_TAG('p', 'c', 'a', 'p') ||
955                    aFeatureTag == HB_TAG('c', '2', 'p', 'c') ||
956                    aFeatureTag == HB_TAG('s', 'u', 'p', 's') ||
957                    aFeatureTag == HB_TAG('s', 'u', 'b', 's'),
958                "use of unknown feature tag");
959 
960   // graphite feature check uses the last script slot
961   uint32_t scriptFeature = SCRIPT_FEATURE(FEATURE_SCRIPT_MASK, aFeatureTag);
962   bool result;
963   if (mSupportedFeatures->Get(scriptFeature, &result)) {
964     return result;
965   }
966 
967   auto face = GetGrFace();
968   auto t_face = rlbox::from_opaque(face);
969   result = t_face ? sandbox_invoke(mSandboxData->sandbox, gr_face_find_fref,
970                                    t_face, aFeatureTag) != nullptr
971                   : false;
972   ReleaseGrFace(face);
973 
974   mSupportedFeatures->Put(scriptFeature, result);
975 
976   return result;
977 }
978 
GetFeatureInfo(nsTArray<gfxFontFeatureInfo> & aFeatureInfo)979 void gfxFontEntry::GetFeatureInfo(nsTArray<gfxFontFeatureInfo>& aFeatureInfo) {
980   // TODO: implement alternative code path for graphite fonts
981 
982   hb_face_t* face = GetHBFace();
983 
984   // Get the list of features for a specific <script,langSys> pair and
985   // append them to aFeatureInfo.
986   auto collectForLang = [=, &aFeatureInfo](
987                             hb_tag_t aTableTag, unsigned int aScript,
988                             hb_tag_t aScriptTag, unsigned int aLang,
989                             hb_tag_t aLangTag) {
990     unsigned int featCount = hb_ot_layout_language_get_feature_tags(
991         face, aTableTag, aScript, aLang, 0, nullptr, nullptr);
992     AutoTArray<hb_tag_t, 32> featTags;
993     featTags.SetLength(featCount);
994     hb_ot_layout_language_get_feature_tags(face, aTableTag, aScript, aLang, 0,
995                                            &featCount, featTags.Elements());
996     MOZ_ASSERT(featCount <= featTags.Length());
997     // Just in case HB didn't fill featTags (i.e. in case it returned fewer
998     // tags than it promised), we truncate at the length it says it filled:
999     featTags.SetLength(featCount);
1000     for (hb_tag_t t : featTags) {
1001       aFeatureInfo.AppendElement(gfxFontFeatureInfo{t, aScriptTag, aLangTag});
1002     }
1003   };
1004 
1005   // Iterate over the language systems supported by a given script,
1006   // and call collectForLang for each of them.
1007   auto collectForScript = [=](hb_tag_t aTableTag, unsigned int aScript,
1008                               hb_tag_t aScriptTag) {
1009     collectForLang(aTableTag, aScript, aScriptTag,
1010                    HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
1011                    HB_TAG('d', 'f', 'l', 't'));
1012     unsigned int langCount = hb_ot_layout_script_get_language_tags(
1013         face, aTableTag, aScript, 0, nullptr, nullptr);
1014     AutoTArray<hb_tag_t, 32> langTags;
1015     langTags.SetLength(langCount);
1016     hb_ot_layout_script_get_language_tags(face, aTableTag, aScript, 0,
1017                                           &langCount, langTags.Elements());
1018     MOZ_ASSERT(langCount <= langTags.Length());
1019     langTags.SetLength(langCount);
1020     for (unsigned int lang = 0; lang < langCount; ++lang) {
1021       collectForLang(aTableTag, aScript, aScriptTag, lang, langTags[lang]);
1022     }
1023   };
1024 
1025   // Iterate over the scripts supported by a table (GSUB or GPOS), and call
1026   // collectForScript for each of them.
1027   auto collectForTable = [=](hb_tag_t aTableTag) {
1028     unsigned int scriptCount = hb_ot_layout_table_get_script_tags(
1029         face, aTableTag, 0, nullptr, nullptr);
1030     AutoTArray<hb_tag_t, 32> scriptTags;
1031     scriptTags.SetLength(scriptCount);
1032     hb_ot_layout_table_get_script_tags(face, aTableTag, 0, &scriptCount,
1033                                        scriptTags.Elements());
1034     MOZ_ASSERT(scriptCount <= scriptTags.Length());
1035     scriptTags.SetLength(scriptCount);
1036     for (unsigned int script = 0; script < scriptCount; ++script) {
1037       collectForScript(aTableTag, script, scriptTags[script]);
1038     }
1039   };
1040 
1041   // Collect all OpenType Layout features, both substitution and positioning,
1042   // supported by the font resource.
1043   collectForTable(HB_TAG('G', 'S', 'U', 'B'));
1044   collectForTable(HB_TAG('G', 'P', 'O', 'S'));
1045 
1046   hb_face_destroy(face);
1047 }
1048 
GetColorLayersInfo(uint32_t aGlyphId,const mozilla::gfx::DeviceColor & aDefaultColor,nsTArray<uint16_t> & aLayerGlyphs,nsTArray<mozilla::gfx::DeviceColor> & aLayerColors)1049 bool gfxFontEntry::GetColorLayersInfo(
1050     uint32_t aGlyphId, const mozilla::gfx::DeviceColor& aDefaultColor,
1051     nsTArray<uint16_t>& aLayerGlyphs,
1052     nsTArray<mozilla::gfx::DeviceColor>& aLayerColors) {
1053   return gfxFontUtils::GetColorGlyphLayers(
1054       mCOLR, mCPAL, aGlyphId, aDefaultColor, aLayerGlyphs, aLayerColors);
1055 }
1056 
1057 typedef struct {
1058   AutoSwap_PRUint32 version;
1059   AutoSwap_PRUint16 format;
1060   AutoSwap_PRUint16 horizOffset;
1061   AutoSwap_PRUint16 vertOffset;
1062   AutoSwap_PRUint16 reserved;
1063   //  TrackData horizData;
1064   //  TrackData vertData;
1065 } TrakHeader;
1066 
1067 typedef struct {
1068   AutoSwap_PRUint16 nTracks;
1069   AutoSwap_PRUint16 nSizes;
1070   AutoSwap_PRUint32 sizeTableOffset;
1071   //  trackTableEntry trackTable[];
1072   //  fixed32 sizeTable[];
1073 } TrackData;
1074 
1075 typedef struct {
1076   AutoSwap_PRUint32 track;
1077   AutoSwap_PRUint16 nameIndex;
1078   AutoSwap_PRUint16 offset;
1079 } TrackTableEntry;
1080 
HasTrackingTable()1081 bool gfxFontEntry::HasTrackingTable() {
1082   if (!TrakTableInitialized()) {
1083     mTrakTable = GetFontTable(TRUETYPE_TAG('t', 'r', 'a', 'k'));
1084     if (mTrakTable) {
1085       if (!ParseTrakTable()) {
1086         hb_blob_destroy(mTrakTable);
1087         mTrakTable = nullptr;
1088       }
1089     }
1090   }
1091   return mTrakTable != nullptr;
1092 }
1093 
ParseTrakTable()1094 bool gfxFontEntry::ParseTrakTable() {
1095   // Check table validity and set up the subtable pointers we need;
1096   // if 'trak' table is invalid, or doesn't contain a 'normal' track,
1097   // return false to tell the caller not to try using it.
1098   unsigned int len;
1099   const char* data = hb_blob_get_data(mTrakTable, &len);
1100   if (len < sizeof(TrakHeader)) {
1101     return false;
1102   }
1103   auto trak = reinterpret_cast<const TrakHeader*>(data);
1104   uint16_t horizOffset = trak->horizOffset;
1105   if (trak->version != 0x00010000 || uint16_t(trak->format) != 0 ||
1106       horizOffset == 0 || uint16_t(trak->reserved) != 0) {
1107     return false;
1108   }
1109   // Find the horizontal trackData, and check it doesn't overrun the buffer.
1110   if (horizOffset > len - sizeof(TrackData)) {
1111     return false;
1112   }
1113   auto trackData = reinterpret_cast<const TrackData*>(data + horizOffset);
1114   uint16_t nTracks = trackData->nTracks;
1115   mNumTrakSizes = trackData->nSizes;
1116   if (nTracks == 0 || mNumTrakSizes < 2) {
1117     return false;
1118   }
1119   uint32_t sizeTableOffset = trackData->sizeTableOffset;
1120   // Find the trackTable, and check it doesn't overrun the buffer.
1121   if (horizOffset >
1122       len - (sizeof(TrackData) + nTracks * sizeof(TrackTableEntry))) {
1123     return false;
1124   }
1125   auto trackTable = reinterpret_cast<const TrackTableEntry*>(
1126       data + horizOffset + sizeof(TrackData));
1127   // Look for 'normal' tracking, bail out if no such track is present.
1128   unsigned trackIndex;
1129   for (trackIndex = 0; trackIndex < nTracks; ++trackIndex) {
1130     if (trackTable[trackIndex].track == 0x00000000) {
1131       break;
1132     }
1133   }
1134   if (trackIndex == nTracks) {
1135     return false;
1136   }
1137   // Find list of tracking values, and check they won't overrun.
1138   uint16_t offset = trackTable[trackIndex].offset;
1139   if (offset > len - mNumTrakSizes * sizeof(uint16_t)) {
1140     return false;
1141   }
1142   mTrakValues = reinterpret_cast<const AutoSwap_PRInt16*>(data + offset);
1143   // Find the size subtable, and check it doesn't overrun the buffer.
1144   mTrakSizeTable =
1145       reinterpret_cast<const AutoSwap_PRInt32*>(data + sizeTableOffset);
1146   if (mTrakSizeTable + mNumTrakSizes >
1147       reinterpret_cast<const AutoSwap_PRInt32*>(data + len)) {
1148     return false;
1149   }
1150   return true;
1151 }
1152 
TrackingForCSSPx(float aSize) const1153 float gfxFontEntry::TrackingForCSSPx(float aSize) const {
1154   MOZ_ASSERT(TrakTableInitialized() && mTrakTable && mTrakValues &&
1155              mTrakSizeTable);
1156 
1157   // Find index of first sizeTable entry that is >= the requested size.
1158   int32_t fixedSize = int32_t(aSize * 65536.0);  // float -> 16.16 fixed-point
1159   unsigned sizeIndex;
1160   for (sizeIndex = 0; sizeIndex < mNumTrakSizes; ++sizeIndex) {
1161     if (mTrakSizeTable[sizeIndex] >= fixedSize) {
1162       break;
1163     }
1164   }
1165   // Return the tracking value for the requested size, or an interpolated
1166   // value if the exact size isn't found.
1167   if (sizeIndex == mNumTrakSizes) {
1168     // Request is larger than last entry in the table, so just use that.
1169     // (We don't attempt to extrapolate more extreme tracking values than
1170     // the largest or smallest present in the table.)
1171     return int16_t(mTrakValues[mNumTrakSizes - 1]);
1172   }
1173   if (sizeIndex == 0 || mTrakSizeTable[sizeIndex] == fixedSize) {
1174     // Found an exact match, or size was smaller than the first entry.
1175     return int16_t(mTrakValues[sizeIndex]);
1176   }
1177   // Requested size falls between two entries: interpolate value.
1178   double s0 = mTrakSizeTable[sizeIndex - 1] / 65536.0;  // 16.16 -> float
1179   double s1 = mTrakSizeTable[sizeIndex] / 65536.0;
1180   double t = (aSize - s0) / (s1 - s0);
1181   return (1.0 - t) * int16_t(mTrakValues[sizeIndex - 1]) +
1182          t * int16_t(mTrakValues[sizeIndex]);
1183 }
1184 
SetupVariationRanges()1185 void gfxFontEntry::SetupVariationRanges() {
1186   if (!gfxPlatform::GetPlatform()->HasVariationFontSupport() ||
1187       !StaticPrefs::layout_css_font_variations_enabled() || !HasVariations() ||
1188       IsUserFont()) {
1189     return;
1190   }
1191   AutoTArray<gfxFontVariationAxis, 4> axes;
1192   GetVariationAxes(axes);
1193   for (const auto& axis : axes) {
1194     switch (axis.mTag) {
1195       case HB_TAG('w', 'g', 'h', 't'):
1196         // If the axis range looks like it doesn't fit the CSS font-weight
1197         // scale, we don't hook up the high-level property, and we mark
1198         // the face (in mRangeFlags) as having non-standard weight. This
1199         // means we won't map CSS font-weight to the axis. Setting 'wght'
1200         // with font-variation-settings will still work.
1201         // Strictly speaking, the min value should be checked against 1.0,
1202         // not 0.0, but we'll allow font makers that amount of leeway, as
1203         // in practice a number of fonts seem to use 0..1000.
1204         if (axis.mMinValue >= 0.0f && axis.mMaxValue <= 1000.0f &&
1205             // If axis.mMaxValue is less than the default weight we already
1206             // set up, assume the axis has a non-standard range (like Skia)
1207             // and don't try to map it.
1208             Weight().Min() <= FontWeight(axis.mMaxValue)) {
1209           if (FontWeight(axis.mDefaultValue) != Weight().Min()) {
1210             mStandardFace = false;
1211           }
1212           mWeightRange = WeightRange(FontWeight(std::max(1.0f, axis.mMinValue)),
1213                                      FontWeight(axis.mMaxValue));
1214         } else {
1215           mRangeFlags |= RangeFlags::eNonCSSWeight;
1216         }
1217         break;
1218 
1219       case HB_TAG('w', 'd', 't', 'h'):
1220         if (axis.mMinValue >= 0.0f && axis.mMaxValue <= 1000.0f &&
1221             Stretch().Min() <= FontStretch(axis.mMaxValue)) {
1222           if (FontStretch(axis.mDefaultValue) != Stretch().Min()) {
1223             mStandardFace = false;
1224           }
1225           mStretchRange = StretchRange(FontStretch(axis.mMinValue),
1226                                        FontStretch(axis.mMaxValue));
1227         } else {
1228           mRangeFlags |= RangeFlags::eNonCSSStretch;
1229         }
1230         break;
1231 
1232       case HB_TAG('s', 'l', 'n', 't'):
1233         if (axis.mMinValue >= -90.0f && axis.mMaxValue <= 90.0f) {
1234           if (FontSlantStyle::Oblique(axis.mDefaultValue) !=
1235               SlantStyle().Min()) {
1236             mStandardFace = false;
1237           }
1238           // OpenType and CSS measure angles in opposite directions, so we
1239           // have to flip signs and swap min/max when setting up the CSS
1240           // font-style range here.
1241           mStyleRange =
1242               SlantStyleRange(FontSlantStyle::Oblique(-axis.mMaxValue),
1243                               FontSlantStyle::Oblique(-axis.mMinValue));
1244         }
1245         break;
1246 
1247       case HB_TAG('i', 't', 'a', 'l'):
1248         if (axis.mMinValue <= 0.0f && axis.mMaxValue >= 1.0f) {
1249           if (axis.mDefaultValue != 0.0f) {
1250             mStandardFace = false;
1251           }
1252           mStyleRange = SlantStyleRange(FontSlantStyle::Normal(),
1253                                         FontSlantStyle::Italic());
1254         }
1255         break;
1256 
1257       default:
1258         continue;
1259     }
1260   }
1261 }
1262 
CheckForVariationAxes()1263 void gfxFontEntry::CheckForVariationAxes() {
1264   if (HasVariations()) {
1265     AutoTArray<gfxFontVariationAxis, 4> axes;
1266     GetVariationAxes(axes);
1267     for (const auto& axis : axes) {
1268       if (axis.mTag == HB_TAG('w', 'g', 'h', 't') && axis.mMaxValue >= 600.0f) {
1269         mRangeFlags |= RangeFlags::eBoldVariableWeight;
1270       } else if (axis.mTag == HB_TAG('i', 't', 'a', 'l') &&
1271                  axis.mMaxValue >= 1.0f) {
1272         mRangeFlags |= RangeFlags::eItalicVariation;
1273       }
1274     }
1275   }
1276   mCheckedForVariationAxes = true;
1277 }
1278 
HasBoldVariableWeight()1279 bool gfxFontEntry::HasBoldVariableWeight() {
1280   MOZ_ASSERT(!mIsUserFontContainer,
1281              "should not be called for user-font containers!");
1282 
1283   if (!gfxPlatform::GetPlatform()->HasVariationFontSupport()) {
1284     return false;
1285   }
1286 
1287   if (!mCheckedForVariationAxes) {
1288     CheckForVariationAxes();
1289   }
1290 
1291   return bool(mRangeFlags & RangeFlags::eBoldVariableWeight);
1292 }
1293 
HasItalicVariation()1294 bool gfxFontEntry::HasItalicVariation() {
1295   MOZ_ASSERT(!mIsUserFontContainer,
1296              "should not be called for user-font containers!");
1297 
1298   if (!gfxPlatform::GetPlatform()->HasVariationFontSupport()) {
1299     return false;
1300   }
1301 
1302   if (!mCheckedForVariationAxes) {
1303     CheckForVariationAxes();
1304   }
1305 
1306   return bool(mRangeFlags & RangeFlags::eItalicVariation);
1307 }
1308 
GetVariationsForStyle(nsTArray<gfxFontVariation> & aResult,const gfxFontStyle & aStyle)1309 void gfxFontEntry::GetVariationsForStyle(nsTArray<gfxFontVariation>& aResult,
1310                                          const gfxFontStyle& aStyle) {
1311   if (!gfxPlatform::GetPlatform()->HasVariationFontSupport() ||
1312       !StaticPrefs::layout_css_font_variations_enabled()) {
1313     return;
1314   }
1315 
1316   if (!HasVariations()) {
1317     return;
1318   }
1319 
1320   // Resolve high-level CSS properties from the requested style
1321   // (font-{style,weight,stretch}) to the appropriate variations.
1322   // The value used is clamped to the range available in the font face,
1323   // unless the face is a user font where no explicit descriptor was
1324   // given, indicated by the corresponding 'auto' range-flag.
1325 
1326   // We don't do these mappings if the font entry has weight and/or stretch
1327   // ranges that do not appear to use the CSS property scale. Some older
1328   // fonts created for QuickDrawGX/AAT may use "normalized" values where the
1329   // standard variation is 1.0 rather than 400.0 (weight) or 100.0 (stretch).
1330 
1331   if (!(mRangeFlags & RangeFlags::eNonCSSWeight)) {
1332     float weight = (IsUserFont() && (mRangeFlags & RangeFlags::eAutoWeight))
1333                        ? aStyle.weight.ToFloat()
1334                        : Weight().Clamp(aStyle.weight).ToFloat();
1335     aResult.AppendElement(gfxFontVariation{HB_TAG('w', 'g', 'h', 't'), weight});
1336   }
1337 
1338   if (!(mRangeFlags & RangeFlags::eNonCSSStretch)) {
1339     float stretch = (IsUserFont() && (mRangeFlags & RangeFlags::eAutoStretch))
1340                         ? aStyle.stretch.Percentage()
1341                         : Stretch().Clamp(aStyle.stretch).Percentage();
1342     aResult.AppendElement(
1343         gfxFontVariation{HB_TAG('w', 'd', 't', 'h'), stretch});
1344   }
1345 
1346   if (aStyle.style.IsItalic() && SupportsItalic()) {
1347     // The 'ital' axis is normally a binary toggle; intermediate values
1348     // can only be set using font-variation-settings.
1349     aResult.AppendElement(gfxFontVariation{HB_TAG('i', 't', 'a', 'l'), 1.0f});
1350   } else if (SlantStyle().Min().IsOblique()) {
1351     // Figure out what slant angle we should try to match from the
1352     // requested style.
1353     float angle = aStyle.style.IsNormal()
1354                       ? 0.0f
1355                       : aStyle.style.IsItalic()
1356                             ? FontSlantStyle::Oblique().ObliqueAngle()
1357                             : aStyle.style.ObliqueAngle();
1358     // Clamp to the available range, unless the face is a user font
1359     // with no explicit descriptor.
1360     if (!(IsUserFont() && (mRangeFlags & RangeFlags::eAutoSlantStyle))) {
1361       angle = SlantStyle().Clamp(FontSlantStyle::Oblique(angle)).ObliqueAngle();
1362     }
1363     // OpenType and CSS measure angles in opposite directions, so we have to
1364     // invert the sign of the CSS oblique value when setting OpenType 'slnt'.
1365     aResult.AppendElement(gfxFontVariation{HB_TAG('s', 'l', 'n', 't'), -angle});
1366   }
1367 
1368   auto replaceOrAppend = [&aResult](const gfxFontVariation& aSetting) {
1369     struct TagEquals {
1370       bool Equals(const gfxFontVariation& aIter, uint32_t aTag) const {
1371         return aIter.mTag == aTag;
1372       }
1373     };
1374     auto index = aResult.IndexOf(aSetting.mTag, 0, TagEquals());
1375     if (index == aResult.NoIndex) {
1376       aResult.AppendElement(aSetting);
1377     } else {
1378       aResult[index].mValue = aSetting.mValue;
1379     }
1380   };
1381 
1382   // The low-level font-variation-settings descriptor from @font-face,
1383   // if present, takes precedence over automatic variation settings
1384   // from high-level properties.
1385   for (const auto& v : mVariationSettings) {
1386     replaceOrAppend(v);
1387   }
1388 
1389   // And the low-level font-variation-settings property takes precedence
1390   // over the descriptor.
1391   for (const auto& v : aStyle.variationSettings) {
1392     replaceOrAppend(v);
1393   }
1394 }
1395 
SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const1396 size_t gfxFontEntry::FontTableHashEntry::SizeOfExcludingThis(
1397     mozilla::MallocSizeOf aMallocSizeOf) const {
1398   size_t n = 0;
1399   if (mBlob) {
1400     n += aMallocSizeOf(mBlob);
1401   }
1402   if (mSharedBlobData) {
1403     n += mSharedBlobData->SizeOfIncludingThis(aMallocSizeOf);
1404   }
1405   return n;
1406 }
1407 
AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,FontListSizes * aSizes) const1408 void gfxFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
1409                                           FontListSizes* aSizes) const {
1410   aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1411 
1412   // cmaps are shared so only non-shared cmaps are included here
1413   if (mCharacterMap && mCharacterMap->mBuildOnTheFly) {
1414     aSizes->mCharMapsSize += mCharacterMap->SizeOfIncludingThis(aMallocSizeOf);
1415   }
1416   if (mFontTableCache) {
1417     aSizes->mFontTableCacheSize +=
1418         mFontTableCache->SizeOfIncludingThis(aMallocSizeOf);
1419   }
1420 
1421   // If the font has UVS data, we count that as part of the character map.
1422   if (mUVSData) {
1423     aSizes->mCharMapsSize += aMallocSizeOf(mUVSData.get());
1424   }
1425 
1426   // The following, if present, are essentially cached forms of font table
1427   // data, so we'll accumulate them together with the basic table cache.
1428   if (mUserFontData) {
1429     aSizes->mFontTableCacheSize +=
1430         mUserFontData->SizeOfIncludingThis(aMallocSizeOf);
1431   }
1432   if (mSVGGlyphs) {
1433     aSizes->mFontTableCacheSize +=
1434         mSVGGlyphs->SizeOfIncludingThis(aMallocSizeOf);
1435   }
1436   if (mSupportedFeatures) {
1437     aSizes->mFontTableCacheSize +=
1438         mSupportedFeatures->ShallowSizeOfIncludingThis(aMallocSizeOf);
1439   }
1440   if (mFeatureInputs) {
1441     aSizes->mFontTableCacheSize +=
1442         mFeatureInputs->ShallowSizeOfIncludingThis(aMallocSizeOf);
1443     for (auto iter = mFeatureInputs->ConstIter(); !iter.Done(); iter.Next()) {
1444       // There's no API to get the real size of an hb_set, so we'll use
1445       // an approximation based on knowledge of the implementation.
1446       aSizes->mFontTableCacheSize += 8192;  // vector of 64K bits
1447     }
1448   }
1449   // We don't include the size of mCOLR/mCPAL here, because (depending on the
1450   // font backend implementation) they will either wrap blocks of data owned
1451   // by the system (and potentially shared), or tables that are in our font
1452   // table cache and therefore already counted.
1453 }
1454 
AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,FontListSizes * aSizes) const1455 void gfxFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
1456                                           FontListSizes* aSizes) const {
1457   aSizes->mFontListSize += aMallocSizeOf(this);
1458   AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
1459 }
1460 
1461 // This is used to report the size of an individual downloaded font in the
1462 // user font cache. (Fonts that are part of the platform font list accumulate
1463 // their sizes to the font list's reporter using the AddSizeOf... methods
1464 // above.)
ComputedSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const1465 size_t gfxFontEntry::ComputedSizeOfExcludingThis(
1466     MallocSizeOf aMallocSizeOf) const {
1467   FontListSizes s = {0};
1468   AddSizeOfExcludingThis(aMallocSizeOf, &s);
1469 
1470   // When reporting memory used for the main platform font list,
1471   // where we're typically summing the totals for a few hundred font faces,
1472   // we report the fields of FontListSizes separately.
1473   // But for downloaded user fonts, the actual resource data (added below)
1474   // will dominate, and the minor overhead of these pieces isn't worth
1475   // splitting out for an individual font.
1476   size_t result = s.mFontListSize + s.mFontTableCacheSize + s.mCharMapsSize;
1477 
1478   if (mIsDataUserFont) {
1479     MOZ_ASSERT(mComputedSizeOfUserFont > 0, "user font with no data?");
1480     result += mComputedSizeOfUserFont;
1481   }
1482 
1483   return result;
1484 }
1485 
1486 //////////////////////////////////////////////////////////////////////////////
1487 //
1488 // class gfxFontFamily
1489 //
1490 //////////////////////////////////////////////////////////////////////////////
1491 
1492 // we consider faces with mStandardFace == true to be "less than" those with
1493 // false, because during style matching, earlier entries are tried first
1494 class FontEntryStandardFaceComparator {
1495  public:
Equals(const RefPtr<gfxFontEntry> & a,const RefPtr<gfxFontEntry> & b) const1496   bool Equals(const RefPtr<gfxFontEntry>& a,
1497               const RefPtr<gfxFontEntry>& b) const {
1498     return a->mStandardFace == b->mStandardFace;
1499   }
LessThan(const RefPtr<gfxFontEntry> & a,const RefPtr<gfxFontEntry> & b) const1500   bool LessThan(const RefPtr<gfxFontEntry>& a,
1501                 const RefPtr<gfxFontEntry>& b) const {
1502     return (a->mStandardFace == true && b->mStandardFace == false);
1503   }
1504 };
1505 
SortAvailableFonts()1506 void gfxFontFamily::SortAvailableFonts() {
1507   mAvailableFonts.Sort(FontEntryStandardFaceComparator());
1508 }
1509 
HasOtherFamilyNames()1510 bool gfxFontFamily::HasOtherFamilyNames() {
1511   // need to read in other family names to determine this
1512   if (!mOtherFamilyNamesInitialized) {
1513     ReadOtherFamilyNames(
1514         gfxPlatformFontList::PlatformFontList());  // sets mHasOtherFamilyNames
1515   }
1516   return mHasOtherFamilyNames;
1517 }
1518 
FindFontForStyle(const gfxFontStyle & aFontStyle,bool aIgnoreSizeTolerance)1519 gfxFontEntry* gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle,
1520                                               bool aIgnoreSizeTolerance) {
1521   AutoTArray<gfxFontEntry*, 4> matched;
1522   FindAllFontsForStyle(aFontStyle, matched, aIgnoreSizeTolerance);
1523   if (!matched.IsEmpty()) {
1524     return matched[0];
1525   }
1526   return nullptr;
1527 }
1528 
WeightStyleStretchDistance(gfxFontEntry * aFontEntry,const gfxFontStyle & aTargetStyle)1529 static inline double WeightStyleStretchDistance(
1530     gfxFontEntry* aFontEntry, const gfxFontStyle& aTargetStyle) {
1531   double stretchDist =
1532       StretchDistance(aFontEntry->Stretch(), aTargetStyle.stretch);
1533   double styleDist =
1534       StyleDistance(aFontEntry->SlantStyle(), aTargetStyle.style);
1535   double weightDist = WeightDistance(aFontEntry->Weight(), aTargetStyle.weight);
1536 
1537   // Sanity-check that the distances are within the expected range
1538   // (update if implementation of the distance functions is changed).
1539   MOZ_ASSERT(stretchDist >= 0.0 && stretchDist <= 2000.0);
1540   MOZ_ASSERT(styleDist >= 0.0 && styleDist <= 500.0);
1541   MOZ_ASSERT(weightDist >= 0.0 && weightDist <= 1600.0);
1542 
1543   // weight/style/stretch priority: stretch >> style >> weight
1544   // so we multiply the stretch and style values to make them dominate
1545   // the result
1546   return stretchDist * 1.0e8 + styleDist * 1.0e4 + weightDist;
1547 }
1548 
FindAllFontsForStyle(const gfxFontStyle & aFontStyle,nsTArray<gfxFontEntry * > & aFontEntryList,bool aIgnoreSizeTolerance)1549 void gfxFontFamily::FindAllFontsForStyle(
1550     const gfxFontStyle& aFontStyle, nsTArray<gfxFontEntry*>& aFontEntryList,
1551     bool aIgnoreSizeTolerance) {
1552   if (!mHasStyles) {
1553     FindStyleVariations();  // collect faces for the family, if not already done
1554   }
1555 
1556   NS_ASSERTION(mAvailableFonts.Length() > 0, "font family with no faces!");
1557   NS_ASSERTION(aFontEntryList.IsEmpty(), "non-empty fontlist passed in");
1558 
1559   gfxFontEntry* fe = nullptr;
1560 
1561   // If the family has only one face, we simply return it; no further
1562   // checking needed
1563   uint32_t count = mAvailableFonts.Length();
1564   if (count == 1) {
1565     fe = mAvailableFonts[0];
1566     aFontEntryList.AppendElement(fe);
1567     return;
1568   }
1569 
1570   // Most families are "simple", having just Regular/Bold/Italic/BoldItalic,
1571   // or some subset of these. In this case, we have exactly 4 entries in
1572   // mAvailableFonts, stored in the above order; note that some of the entries
1573   // may be nullptr. We can then pick the required entry based on whether the
1574   // request is for bold or non-bold, italic or non-italic, without running the
1575   // more complex matching algorithm used for larger families with many weights
1576   // and/or widths.
1577 
1578   if (mIsSimpleFamily) {
1579     // Family has no more than the "standard" 4 faces, at fixed indexes;
1580     // calculate which one we want.
1581     // Note that we cannot simply return it as not all 4 faces are necessarily
1582     // present.
1583     bool wantBold = aFontStyle.weight >= FontWeight(600);
1584     bool wantItalic = !aFontStyle.style.IsNormal();
1585     uint8_t faceIndex =
1586         (wantItalic ? kItalicMask : 0) | (wantBold ? kBoldMask : 0);
1587 
1588     // if the desired style is available, return it directly
1589     fe = mAvailableFonts[faceIndex];
1590     if (fe) {
1591       aFontEntryList.AppendElement(fe);
1592       return;
1593     }
1594 
1595     // order to check fallback faces in a simple family, depending on requested
1596     // style
1597     static const uint8_t simpleFallbacks[4][3] = {
1598         {kBoldFaceIndex, kItalicFaceIndex,
1599          kBoldItalicFaceIndex},  // fallbacks for Regular
1600         {kRegularFaceIndex, kBoldItalicFaceIndex, kItalicFaceIndex},  // Bold
1601         {kBoldItalicFaceIndex, kRegularFaceIndex, kBoldFaceIndex},    // Italic
1602         {kItalicFaceIndex, kBoldFaceIndex, kRegularFaceIndex}  // BoldItalic
1603     };
1604     const uint8_t* order = simpleFallbacks[faceIndex];
1605 
1606     for (uint8_t trial = 0; trial < 3; ++trial) {
1607       // check remaining faces in order of preference to find the first that
1608       // actually exists
1609       fe = mAvailableFonts[order[trial]];
1610       if (fe) {
1611         aFontEntryList.AppendElement(fe);
1612         return;
1613       }
1614     }
1615 
1616     // this can't happen unless we have totally broken the font-list manager!
1617     MOZ_ASSERT_UNREACHABLE("no face found in simple font family!");
1618   }
1619 
1620   // Pick the font(s) that are closest to the desired weight, style, and
1621   // stretch. Iterate over all fonts, measuring the weight/style distance.
1622   // Because of unicode-range values, there may be more than one font for a
1623   // given but the 99% use case is only a single font entry per
1624   // weight/style/stretch distance value. To optimize this, only add entries
1625   // to the matched font array when another entry already has the same
1626   // weight/style/stretch distance and add the last matched font entry. For
1627   // normal platform fonts with a single font entry for each
1628   // weight/style/stretch combination, only the last matched font entry will
1629   // be added.
1630 
1631   double minDistance = INFINITY;
1632   gfxFontEntry* matched = nullptr;
1633   // iterate in forward order so that faces like 'Bold' are matched before
1634   // matching style distance faces such as 'Bold Outline' (see bug 1185812)
1635   for (uint32_t i = 0; i < count; i++) {
1636     fe = mAvailableFonts[i];
1637     // weight/style/stretch priority: stretch >> style >> weight
1638     double distance = WeightStyleStretchDistance(fe, aFontStyle);
1639     if (distance < minDistance) {
1640       matched = fe;
1641       if (!aFontEntryList.IsEmpty()) {
1642         aFontEntryList.Clear();
1643       }
1644       minDistance = distance;
1645     } else if (distance == minDistance) {
1646       if (matched) {
1647         aFontEntryList.AppendElement(matched);
1648       }
1649       matched = fe;
1650     }
1651   }
1652 
1653   NS_ASSERTION(matched, "didn't match a font within a family");
1654 
1655   if (matched) {
1656     aFontEntryList.AppendElement(matched);
1657   }
1658 }
1659 
CheckForSimpleFamily()1660 void gfxFontFamily::CheckForSimpleFamily() {
1661   // already checked this family
1662   if (mIsSimpleFamily) {
1663     return;
1664   }
1665 
1666   uint32_t count = mAvailableFonts.Length();
1667   if (count > 4 || count == 0) {
1668     return;  // can't be "simple" if there are >4 faces;
1669              // if none then the family is unusable anyway
1670   }
1671 
1672   if (count == 1) {
1673     mIsSimpleFamily = true;
1674     return;
1675   }
1676 
1677   StretchRange firstStretch = mAvailableFonts[0]->Stretch();
1678   if (!firstStretch.IsSingle()) {
1679     return;  // family with variation fonts is not considered "simple"
1680   }
1681 
1682   gfxFontEntry* faces[4] = {0};
1683   for (uint8_t i = 0; i < count; ++i) {
1684     gfxFontEntry* fe = mAvailableFonts[i];
1685     if (fe->Stretch() != firstStretch || fe->IsOblique()) {
1686       // simple families don't have varying font-stretch or oblique
1687       return;
1688     }
1689     if (!fe->Weight().IsSingle() || !fe->SlantStyle().IsSingle()) {
1690       return;  // family with variation fonts is not considered "simple"
1691     }
1692     uint8_t faceIndex = (fe->IsItalic() ? kItalicMask : 0) |
1693                         (fe->SupportsBold() ? kBoldMask : 0);
1694     if (faces[faceIndex]) {
1695       return;  // two faces resolve to the same slot; family isn't "simple"
1696     }
1697     faces[faceIndex] = fe;
1698   }
1699 
1700   // we have successfully slotted the available faces into the standard
1701   // 4-face framework
1702   mAvailableFonts.SetLength(4);
1703   for (uint8_t i = 0; i < 4; ++i) {
1704     if (mAvailableFonts[i].get() != faces[i]) {
1705       mAvailableFonts[i].swap(faces[i]);
1706     }
1707   }
1708 
1709   mIsSimpleFamily = true;
1710 }
1711 
1712 #ifdef DEBUG
ContainsFace(gfxFontEntry * aFontEntry)1713 bool gfxFontFamily::ContainsFace(gfxFontEntry* aFontEntry) {
1714   uint32_t i, numFonts = mAvailableFonts.Length();
1715   for (i = 0; i < numFonts; i++) {
1716     if (mAvailableFonts[i] == aFontEntry) {
1717       return true;
1718     }
1719     // userfonts contain the actual real font entry
1720     if (mAvailableFonts[i] && mAvailableFonts[i]->mIsUserFontContainer) {
1721       gfxUserFontEntry* ufe =
1722           static_cast<gfxUserFontEntry*>(mAvailableFonts[i].get());
1723       if (ufe->GetPlatformFontEntry() == aFontEntry) {
1724         return true;
1725       }
1726     }
1727   }
1728   return false;
1729 }
1730 #endif
1731 
LocalizedName(nsACString & aLocalizedName)1732 void gfxFontFamily::LocalizedName(nsACString& aLocalizedName) {
1733   // just return the primary name; subclasses should override
1734   aLocalizedName = mName;
1735 }
1736 
FindFontForChar(GlobalFontMatch * aMatchData)1737 void gfxFontFamily::FindFontForChar(GlobalFontMatch* aMatchData) {
1738   if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
1739     // none of the faces in the family support the required char,
1740     // so bail out immediately
1741     return;
1742   }
1743 
1744 #ifdef MOZ_GECKO_PROFILER
1745   nsCString charAndName;
1746   if (profiler_can_accept_markers()) {
1747     charAndName = nsPrintfCString("\\u%x %s", aMatchData->mCh, mName.get());
1748   }
1749   AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("gfxFontFamily::FindFontForChar",
1750                                         LAYOUT, charAndName);
1751 #endif
1752 
1753   AutoTArray<gfxFontEntry*, 4> entries;
1754   FindAllFontsForStyle(aMatchData->mStyle, entries,
1755                        /*aIgnoreSizeTolerance*/ true);
1756   if (entries.IsEmpty()) {
1757     return;
1758   }
1759 
1760   gfxFontEntry* fe = nullptr;
1761   float distance = INFINITY;
1762 
1763   for (auto e : entries) {
1764     if (e->SkipDuringSystemFallback()) {
1765       continue;
1766     }
1767 
1768     aMatchData->mCmapsTested++;
1769     if (e->HasCharacter(aMatchData->mCh)) {
1770       aMatchData->mCount++;
1771 
1772       LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
1773 
1774       if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
1775         Script script = GetScriptCode(aMatchData->mCh);
1776         MOZ_LOG(log, LogLevel::Debug,
1777                 ("(textrun-systemfallback-fonts) char: u+%6.6x "
1778                  "script: %d match: [%s]\n",
1779                  aMatchData->mCh, int(script), e->Name().get()));
1780       }
1781 
1782       fe = e;
1783       distance = WeightStyleStretchDistance(fe, aMatchData->mStyle);
1784       break;
1785     }
1786   }
1787 
1788   if (!fe && !aMatchData->mStyle.IsNormalStyle()) {
1789     // If style/weight/stretch was not Normal, see if we can
1790     // fall back to a next-best face (e.g. Arial Black -> Bold,
1791     // or Arial Narrow -> Regular).
1792     GlobalFontMatch data(aMatchData->mCh, aMatchData->mStyle);
1793     SearchAllFontsForChar(&data);
1794     if (!data.mBestMatch) {
1795       return;
1796     }
1797     fe = data.mBestMatch;
1798     distance = data.mMatchDistance;
1799   }
1800 
1801   if (!fe) {
1802     return;
1803   }
1804 
1805   if (distance < aMatchData->mMatchDistance ||
1806       (distance == aMatchData->mMatchDistance &&
1807        Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0)) {
1808     aMatchData->mBestMatch = fe;
1809     aMatchData->mMatchedFamily = this;
1810     aMatchData->mMatchDistance = distance;
1811   }
1812 }
1813 
SearchAllFontsForChar(GlobalFontMatch * aMatchData)1814 void gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch* aMatchData) {
1815   if (!mFamilyCharacterMapInitialized) {
1816     ReadAllCMAPs();
1817   }
1818   if (!mFamilyCharacterMap.test(aMatchData->mCh)) {
1819     return;
1820   }
1821   uint32_t i, numFonts = mAvailableFonts.Length();
1822   for (i = 0; i < numFonts; i++) {
1823     gfxFontEntry* fe = mAvailableFonts[i];
1824     if (fe && fe->HasCharacter(aMatchData->mCh)) {
1825       float distance = WeightStyleStretchDistance(fe, aMatchData->mStyle);
1826       if (distance < aMatchData->mMatchDistance ||
1827           (distance == aMatchData->mMatchDistance &&
1828            Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0)) {
1829         aMatchData->mBestMatch = fe;
1830         aMatchData->mMatchedFamily = this;
1831         aMatchData->mMatchDistance = distance;
1832       }
1833     }
1834   }
1835 }
1836 
1837 /*virtual*/
~gfxFontFamily()1838 gfxFontFamily::~gfxFontFamily() {
1839   // Should not be dropped by stylo
1840   MOZ_ASSERT(NS_IsMainThread());
1841 }
1842 
1843 // returns true if other names were found, false otherwise
ReadOtherFamilyNamesForFace(gfxPlatformFontList * aPlatformFontList,hb_blob_t * aNameTable,bool useFullName)1844 bool gfxFontFamily::ReadOtherFamilyNamesForFace(
1845     gfxPlatformFontList* aPlatformFontList, hb_blob_t* aNameTable,
1846     bool useFullName) {
1847   uint32_t dataLength;
1848   const char* nameData = hb_blob_get_data(aNameTable, &dataLength);
1849   AutoTArray<nsCString, 4> otherFamilyNames;
1850 
1851   gfxFontUtils::ReadOtherFamilyNamesForFace(mName, nameData, dataLength,
1852                                             otherFamilyNames, useFullName);
1853 
1854   uint32_t n = otherFamilyNames.Length();
1855   for (uint32_t i = 0; i < n; i++) {
1856     aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
1857   }
1858 
1859   return n != 0;
1860 }
1861 
ReadOtherFamilyNames(gfxPlatformFontList * aPlatformFontList)1862 void gfxFontFamily::ReadOtherFamilyNames(
1863     gfxPlatformFontList* aPlatformFontList) {
1864   if (mOtherFamilyNamesInitialized) return;
1865   mOtherFamilyNamesInitialized = true;
1866 
1867   FindStyleVariations();
1868 
1869   // read in other family names for the first face in the list
1870   uint32_t i, numFonts = mAvailableFonts.Length();
1871   const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
1872 
1873   for (i = 0; i < numFonts; ++i) {
1874     gfxFontEntry* fe = mAvailableFonts[i];
1875     if (!fe) {
1876       continue;
1877     }
1878     gfxFontEntry::AutoTable nameTable(fe, kNAME);
1879     if (!nameTable) {
1880       continue;
1881     }
1882     mHasOtherFamilyNames =
1883         ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
1884     break;
1885   }
1886 
1887   // read in other names for the first face in the list with the assumption
1888   // that if extra names don't exist in that face then they don't exist in
1889   // other faces for the same font
1890   if (!mHasOtherFamilyNames) return;
1891 
1892   // read in names for all faces, needed to catch cases where fonts have
1893   // family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
1894   for (; i < numFonts; i++) {
1895     gfxFontEntry* fe = mAvailableFonts[i];
1896     if (!fe) {
1897       continue;
1898     }
1899     gfxFontEntry::AutoTable nameTable(fe, kNAME);
1900     if (!nameTable) {
1901       continue;
1902     }
1903     ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
1904   }
1905 }
1906 
LookForLegacyFamilyName(const nsACString & aCanonicalName,const char * aNameData,uint32_t aDataLength,nsACString & aLegacyName)1907 static bool LookForLegacyFamilyName(const nsACString& aCanonicalName,
1908                                     const char* aNameData, uint32_t aDataLength,
1909                                     nsACString& aLegacyName /* outparam */) {
1910   const gfxFontUtils::NameHeader* nameHeader =
1911       reinterpret_cast<const gfxFontUtils::NameHeader*>(aNameData);
1912 
1913   uint32_t nameCount = nameHeader->count;
1914   if (nameCount * sizeof(gfxFontUtils::NameRecord) > aDataLength) {
1915     NS_WARNING("invalid font (name records)");
1916     return false;
1917   }
1918 
1919   const gfxFontUtils::NameRecord* nameRecord =
1920       reinterpret_cast<const gfxFontUtils::NameRecord*>(
1921           aNameData + sizeof(gfxFontUtils::NameHeader));
1922   uint32_t stringsBase = uint32_t(nameHeader->stringOffset);
1923 
1924   for (uint32_t i = 0; i < nameCount; i++, nameRecord++) {
1925     uint32_t nameLen = nameRecord->length;
1926     uint32_t nameOff = nameRecord->offset;
1927 
1928     if (stringsBase + nameOff + nameLen > aDataLength) {
1929       NS_WARNING("invalid font (name table strings)");
1930       return false;
1931     }
1932 
1933     if (uint16_t(nameRecord->nameID) == gfxFontUtils::NAME_ID_FAMILY) {
1934       bool ok = gfxFontUtils::DecodeFontName(
1935           aNameData + stringsBase + nameOff, nameLen,
1936           uint32_t(nameRecord->platformID), uint32_t(nameRecord->encodingID),
1937           uint32_t(nameRecord->languageID), aLegacyName);
1938       // it's only a legacy name if it differs from the canonical name
1939       if (ok && aLegacyName != aCanonicalName) {
1940         return true;
1941       }
1942     }
1943   }
1944   return false;
1945 }
1946 
CheckForLegacyFamilyNames(gfxPlatformFontList * aFontList)1947 bool gfxFontFamily::CheckForLegacyFamilyNames(gfxPlatformFontList* aFontList) {
1948   if (mCheckedForLegacyFamilyNames) {
1949     // we already did this, so there's nothing more to add
1950     return false;
1951   }
1952   mCheckedForLegacyFamilyNames = true;
1953   bool added = false;
1954   const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
1955   // Make a local copy of the array of font faces, in case of changes
1956   // during the iteration.
1957   for (auto& fe :
1958        CopyableAutoTArray<RefPtr<gfxFontEntry>, 8>(mAvailableFonts)) {
1959     if (!fe) {
1960       continue;
1961     }
1962     gfxFontEntry::AutoTable nameTable(fe, kNAME);
1963     if (!nameTable) {
1964       continue;
1965     }
1966     nsAutoCString legacyName;
1967     uint32_t dataLength;
1968     const char* nameData = hb_blob_get_data(nameTable, &dataLength);
1969     if (LookForLegacyFamilyName(Name(), nameData, dataLength, legacyName)) {
1970       if (aFontList->AddWithLegacyFamilyName(legacyName, fe, mVisibility)) {
1971         added = true;
1972       }
1973     }
1974   }
1975   return added;
1976 }
1977 
ReadFaceNames(gfxPlatformFontList * aPlatformFontList,bool aNeedFullnamePostscriptNames,FontInfoData * aFontInfoData)1978 void gfxFontFamily::ReadFaceNames(gfxPlatformFontList* aPlatformFontList,
1979                                   bool aNeedFullnamePostscriptNames,
1980                                   FontInfoData* aFontInfoData) {
1981   // if all needed names have already been read, skip
1982   if (mOtherFamilyNamesInitialized &&
1983       (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
1984     return;
1985   }
1986 
1987   bool asyncFontLoaderDisabled = false;
1988 
1989   if (!mOtherFamilyNamesInitialized && aFontInfoData &&
1990       aFontInfoData->mLoadOtherNames && !asyncFontLoaderDisabled) {
1991     const auto* otherFamilyNames = aFontInfoData->GetOtherFamilyNames(mName);
1992     if (otherFamilyNames) {
1993       uint32_t i, n = otherFamilyNames->Length();
1994       for (i = 0; i < n; i++) {
1995         aPlatformFontList->AddOtherFamilyName(this, (*otherFamilyNames)[i]);
1996       }
1997     }
1998     mOtherFamilyNamesInitialized = true;
1999   }
2000 
2001   // if all needed data has been initialized, return
2002   if (mOtherFamilyNamesInitialized &&
2003       (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
2004     return;
2005   }
2006 
2007   FindStyleVariations(aFontInfoData);
2008 
2009   // check again, as style enumeration code may have loaded names
2010   if (mOtherFamilyNamesInitialized &&
2011       (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
2012     return;
2013   }
2014 
2015   uint32_t i, numFonts = mAvailableFonts.Length();
2016   const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
2017 
2018   bool firstTime = true, readAllFaces = false;
2019   for (i = 0; i < numFonts; ++i) {
2020     gfxFontEntry* fe = mAvailableFonts[i];
2021     if (!fe) {
2022       continue;
2023     }
2024 
2025     nsAutoCString fullname, psname;
2026     bool foundFaceNames = false;
2027     if (!mFaceNamesInitialized && aNeedFullnamePostscriptNames &&
2028         aFontInfoData && aFontInfoData->mLoadFaceNames) {
2029       aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
2030       if (!fullname.IsEmpty()) {
2031         aPlatformFontList->AddFullname(fe, fullname);
2032       }
2033       if (!psname.IsEmpty()) {
2034         aPlatformFontList->AddPostscriptName(fe, psname);
2035       }
2036       foundFaceNames = true;
2037 
2038       // found everything needed? skip to next font
2039       if (mOtherFamilyNamesInitialized) {
2040         continue;
2041       }
2042     }
2043 
2044     // load directly from the name table
2045     gfxFontEntry::AutoTable nameTable(fe, kNAME);
2046     if (!nameTable) {
2047       continue;
2048     }
2049 
2050     if (aNeedFullnamePostscriptNames && !foundFaceNames) {
2051       if (gfxFontUtils::ReadCanonicalName(nameTable, gfxFontUtils::NAME_ID_FULL,
2052                                           fullname) == NS_OK) {
2053         aPlatformFontList->AddFullname(fe, fullname);
2054       }
2055 
2056       if (gfxFontUtils::ReadCanonicalName(
2057               nameTable, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK) {
2058         aPlatformFontList->AddPostscriptName(fe, psname);
2059       }
2060     }
2061 
2062     if (!mOtherFamilyNamesInitialized && (firstTime || readAllFaces)) {
2063       bool foundOtherName =
2064           ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
2065 
2066       // if the first face has a different name, scan all faces, otherwise
2067       // assume the family doesn't have other names
2068       if (firstTime && foundOtherName) {
2069         mHasOtherFamilyNames = true;
2070         readAllFaces = true;
2071       }
2072       firstTime = false;
2073     }
2074 
2075     // if not reading in any more names, skip other faces
2076     if (!readAllFaces && !aNeedFullnamePostscriptNames) {
2077       break;
2078     }
2079   }
2080 
2081   mFaceNamesInitialized = true;
2082   mOtherFamilyNamesInitialized = true;
2083 }
2084 
FindFont(const nsACString & aPostscriptName)2085 gfxFontEntry* gfxFontFamily::FindFont(const nsACString& aPostscriptName) {
2086   // find the font using a simple linear search
2087   uint32_t numFonts = mAvailableFonts.Length();
2088   for (uint32_t i = 0; i < numFonts; i++) {
2089     gfxFontEntry* fe = mAvailableFonts[i].get();
2090     if (fe && fe->Name() == aPostscriptName) return fe;
2091   }
2092   return nullptr;
2093 }
2094 
ReadAllCMAPs(FontInfoData * aFontInfoData)2095 void gfxFontFamily::ReadAllCMAPs(FontInfoData* aFontInfoData) {
2096   FindStyleVariations(aFontInfoData);
2097 
2098   uint32_t i, numFonts = mAvailableFonts.Length();
2099   for (i = 0; i < numFonts; i++) {
2100     gfxFontEntry* fe = mAvailableFonts[i];
2101     // don't try to load cmaps for downloadable fonts not yet loaded
2102     if (!fe || fe->mIsUserFontContainer) {
2103       continue;
2104     }
2105     fe->ReadCMAP(aFontInfoData);
2106     mFamilyCharacterMap.Union(*(fe->mCharacterMap));
2107   }
2108   mFamilyCharacterMap.Compact();
2109   mFamilyCharacterMapInitialized = true;
2110 }
2111 
AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,FontListSizes * aSizes) const2112 void gfxFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
2113                                            FontListSizes* aSizes) const {
2114   aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
2115   aSizes->mCharMapsSize +=
2116       mFamilyCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
2117 
2118   aSizes->mFontListSize +=
2119       mAvailableFonts.ShallowSizeOfExcludingThis(aMallocSizeOf);
2120   for (uint32_t i = 0; i < mAvailableFonts.Length(); ++i) {
2121     gfxFontEntry* fe = mAvailableFonts[i];
2122     if (fe) {
2123       fe->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
2124     }
2125   }
2126 }
2127 
AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,FontListSizes * aSizes) const2128 void gfxFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
2129                                            FontListSizes* aSizes) const {
2130   aSizes->mFontListSize += aMallocSizeOf(this);
2131   AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
2132 }
2133