1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "mozilla/DebugOnly.h"
7 #include "mozilla/MathAlgorithms.h"
8 
9 #include "mozilla/Logging.h"
10 
11 #include "nsServiceManagerUtils.h"
12 #include "nsILanguageAtomService.h"
13 
14 #include "gfxFontEntry.h"
15 #include "gfxTextRun.h"
16 #include "gfxPlatform.h"
17 #include "nsGkAtoms.h"
18 
19 #include "gfxTypes.h"
20 #include "gfxContext.h"
21 #include "gfxFontConstants.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 "nsUnicodeRange.h"
29 #include "nsStyleConsts.h"
30 #include "mozilla/AppUnits.h"
31 #include "mozilla/FloatingPoint.h"
32 #include "mozilla/Likely.h"
33 #include "mozilla/MemoryReporting.h"
34 #include "mozilla/Preferences.h"
35 #include "mozilla/Services.h"
36 #include "mozilla/Telemetry.h"
37 #include "gfxSVGGlyphs.h"
38 #include "gfx2DGlue.h"
39 
40 #include "cairo.h"
41 
42 #include "harfbuzz/hb.h"
43 #include "harfbuzz/hb-ot.h"
44 #include "graphite2/Font.h"
45 
46 #include <algorithm>
47 
48 using namespace mozilla;
49 using namespace mozilla::gfx;
50 using namespace mozilla::unicode;
51 using mozilla::services::GetObserverService;
52 
53 void
NotifyReleased()54 gfxCharacterMap::NotifyReleased()
55 {
56     gfxPlatformFontList *fontlist = gfxPlatformFontList::PlatformFontList();
57     if (mShared) {
58         fontlist->RemoveCmap(this);
59     }
60     delete this;
61 }
62 
gfxFontEntry()63 gfxFontEntry::gfxFontEntry() :
64     mStyle(NS_FONT_STYLE_NORMAL), mFixedPitch(false),
65     mIsValid(true),
66     mIsBadUnderlineFont(false),
67     mIsUserFontContainer(false),
68     mIsDataUserFont(false),
69     mIsLocalUserFont(false),
70     mStandardFace(false),
71     mSymbolFont(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     mCheckedForGraphiteTables(false),
85     mHasCmapTable(false),
86     mGrFaceInitialized(false),
87     mCheckedForColorGlyph(false),
88     mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
89     mUVSOffset(0), mUVSData(nullptr),
90     mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
91     mCOLR(nullptr),
92     mCPAL(nullptr),
93     mUnitsPerEm(0),
94     mHBFace(nullptr),
95     mGrFace(nullptr),
96     mGrFaceRefCnt(0),
97     mComputedSizeOfUserFont(0)
98 {
99     memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
100     memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
101 }
102 
gfxFontEntry(const nsAString & aName,bool aIsStandardFace)103 gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
104     mName(aName), mStyle(NS_FONT_STYLE_NORMAL), mFixedPitch(false),
105     mIsValid(true),
106     mIsBadUnderlineFont(false),
107     mIsUserFontContainer(false),
108     mIsDataUserFont(false),
109     mIsLocalUserFont(false), mStandardFace(aIsStandardFace),
110     mSymbolFont(false),
111     mIgnoreGDEF(false),
112     mIgnoreGSUB(false),
113     mSVGInitialized(false),
114     mHasSpaceFeaturesInitialized(false),
115     mHasSpaceFeatures(false),
116     mHasSpaceFeaturesKerning(false),
117     mHasSpaceFeaturesNonKerning(false),
118     mSkipDefaultFeatureSpaceCheck(false),
119     mGraphiteSpaceContextualsInitialized(false),
120     mHasGraphiteSpaceContextuals(false),
121     mSpaceGlyphIsInvisible(false),
122     mSpaceGlyphIsInvisibleInitialized(false),
123     mCheckedForGraphiteTables(false),
124     mHasCmapTable(false),
125     mGrFaceInitialized(false),
126     mCheckedForColorGlyph(false),
127     mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
128     mUVSOffset(0), mUVSData(nullptr),
129     mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
130     mCOLR(nullptr),
131     mCPAL(nullptr),
132     mUnitsPerEm(0),
133     mHBFace(nullptr),
134     mGrFace(nullptr),
135     mGrFaceRefCnt(0),
136     mComputedSizeOfUserFont(0)
137 {
138     memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
139     memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
140 }
141 
~gfxFontEntry()142 gfxFontEntry::~gfxFontEntry()
143 {
144     if (mCOLR) {
145         hb_blob_destroy(mCOLR);
146     }
147 
148     if (mCPAL) {
149         hb_blob_destroy(mCPAL);
150     }
151 
152     // For downloaded fonts, we need to tell the user font cache that this
153     // entry is being deleted.
154     if (mIsDataUserFont) {
155         gfxUserFontSet::UserFontCache::ForgetFont(this);
156     }
157 
158     if (mFeatureInputs) {
159         for (auto iter = mFeatureInputs->Iter(); !iter.Done(); iter.Next()) {
160             hb_set_t*& set = iter.Data();
161             hb_set_destroy(set);
162         }
163     }
164 
165     // By the time the entry is destroyed, all font instances that were
166     // using it should already have been deleted, and so the HB and/or Gr
167     // face objects should have been released.
168     MOZ_ASSERT(!mHBFace);
169     MOZ_ASSERT(!mGrFaceInitialized);
170 }
171 
IsSymbolFont()172 bool gfxFontEntry::IsSymbolFont()
173 {
174     return mSymbolFont;
175 }
176 
TestCharacterMap(uint32_t aCh)177 bool gfxFontEntry::TestCharacterMap(uint32_t aCh)
178 {
179     if (!mCharacterMap) {
180         ReadCMAP();
181         NS_ASSERTION(mCharacterMap, "failed to initialize character map");
182     }
183     return mCharacterMap->test(aCh);
184 }
185 
InitializeUVSMap()186 nsresult gfxFontEntry::InitializeUVSMap()
187 {
188     // mUVSOffset will not be initialized
189     // until cmap is initialized.
190     if (!mCharacterMap) {
191         ReadCMAP();
192         NS_ASSERTION(mCharacterMap, "failed to initialize character map");
193     }
194 
195     if (!mUVSOffset) {
196         return NS_ERROR_FAILURE;
197     }
198 
199     if (!mUVSData) {
200         const uint32_t kCmapTag = TRUETYPE_TAG('c','m','a','p');
201         AutoTable cmapTable(this, kCmapTag);
202         if (!cmapTable) {
203             mUVSOffset = 0; // don't bother to read the table again
204             return NS_ERROR_FAILURE;
205         }
206 
207         UniquePtr<uint8_t[]> uvsData;
208         unsigned int cmapLen;
209         const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
210         nsresult rv = gfxFontUtils::ReadCMAPTableFormat14(
211                           (const uint8_t*)cmapData + mUVSOffset,
212                           cmapLen - mUVSOffset, uvsData);
213 
214         if (NS_FAILED(rv)) {
215             mUVSOffset = 0; // don't bother to read the table again
216             return rv;
217         }
218 
219         mUVSData = Move(uvsData);
220     }
221 
222     return NS_OK;
223 }
224 
GetUVSGlyph(uint32_t aCh,uint32_t aVS)225 uint16_t gfxFontEntry::GetUVSGlyph(uint32_t aCh, uint32_t aVS)
226 {
227     InitializeUVSMap();
228 
229     if (mUVSData) {
230         return gfxFontUtils::MapUVSToGlyphFormat14(mUVSData.get(), aCh, aVS);
231     }
232 
233     return 0;
234 }
235 
SupportsScriptInGSUB(const hb_tag_t * aScriptTags)236 bool gfxFontEntry::SupportsScriptInGSUB(const hb_tag_t* aScriptTags)
237 {
238     hb_face_t *face = GetHBFace();
239     if (!face) {
240         return false;
241     }
242 
243     unsigned int index;
244     hb_tag_t     chosenScript;
245     bool found =
246         hb_ot_layout_table_choose_script(face, TRUETYPE_TAG('G','S','U','B'),
247                                          aScriptTags, &index, &chosenScript);
248     hb_face_destroy(face);
249 
250     return found && chosenScript != TRUETYPE_TAG('D','F','L','T');
251 }
252 
ReadCMAP(FontInfoData * aFontInfoData)253 nsresult gfxFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
254 {
255     NS_ASSERTION(false, "using default no-op implementation of ReadCMAP");
256     mCharacterMap = new gfxCharacterMap();
257     return NS_OK;
258 }
259 
260 nsString
RealFaceName()261 gfxFontEntry::RealFaceName()
262 {
263     AutoTable nameTable(this, TRUETYPE_TAG('n','a','m','e'));
264     if (nameTable) {
265         nsAutoString name;
266         nsresult rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
267         if (NS_SUCCEEDED(rv)) {
268             return name;
269         }
270     }
271     return Name();
272 }
273 
274 already_AddRefed<gfxFont>
FindOrMakeFont(const gfxFontStyle * aStyle,bool aNeedsBold,gfxCharacterMap * aUnicodeRangeMap)275 gfxFontEntry::FindOrMakeFont(const gfxFontStyle *aStyle,
276                              bool aNeedsBold,
277                              gfxCharacterMap* aUnicodeRangeMap)
278 {
279     // the font entry name is the psname, not the family name
280     RefPtr<gfxFont> font =
281         gfxFontCache::GetCache()->Lookup(this, aStyle, aUnicodeRangeMap);
282 
283     if (!font) {
284         gfxFont *newFont = CreateFontInstance(aStyle, aNeedsBold);
285         if (!newFont)
286             return nullptr;
287         if (!newFont->Valid()) {
288             delete newFont;
289             return nullptr;
290         }
291         font = newFont;
292         font->SetUnicodeRangeMap(aUnicodeRangeMap);
293         gfxFontCache::GetCache()->AddNew(font);
294     }
295     return font.forget();
296 }
297 
298 uint16_t
UnitsPerEm()299 gfxFontEntry::UnitsPerEm()
300 {
301     if (!mUnitsPerEm) {
302         AutoTable headTable(this, TRUETYPE_TAG('h','e','a','d'));
303         if (headTable) {
304             uint32_t len;
305             const HeadTable* head =
306                 reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable,
307                                                                     &len));
308             if (len >= sizeof(HeadTable)) {
309                 mUnitsPerEm = head->unitsPerEm;
310             }
311         }
312 
313         // if we didn't find a usable 'head' table, or if the value was
314         // outside the valid range, record it as invalid
315         if (mUnitsPerEm < kMinUPEM || mUnitsPerEm > kMaxUPEM) {
316             mUnitsPerEm = kInvalidUPEM;
317         }
318     }
319     return mUnitsPerEm;
320 }
321 
322 bool
HasSVGGlyph(uint32_t aGlyphId)323 gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId)
324 {
325     NS_ASSERTION(mSVGInitialized, "SVG data has not yet been loaded. TryGetSVGData() first.");
326     return mSVGGlyphs->HasSVGGlyph(aGlyphId);
327 }
328 
329 bool
GetSVGGlyphExtents(DrawTarget * aDrawTarget,uint32_t aGlyphId,gfxRect * aResult)330 gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphId,
331                                  gfxRect *aResult)
332 {
333     MOZ_ASSERT(mSVGInitialized,
334                "SVG data has not yet been loaded. TryGetSVGData() first.");
335     MOZ_ASSERT(mUnitsPerEm >= kMinUPEM && mUnitsPerEm <= kMaxUPEM,
336                "font has invalid unitsPerEm");
337 
338     cairo_matrix_t fontMatrix;
339     cairo_get_font_matrix(gfxFont::RefCairo(aDrawTarget), &fontMatrix);
340 
341     gfxMatrix svgToAppSpace(fontMatrix.xx, fontMatrix.yx,
342                             fontMatrix.xy, fontMatrix.yy,
343                             fontMatrix.x0, fontMatrix.y0);
344     svgToAppSpace.Scale(1.0f / mUnitsPerEm, 1.0f / mUnitsPerEm);
345 
346     return mSVGGlyphs->GetGlyphExtents(aGlyphId, svgToAppSpace, aResult);
347 }
348 
349 bool
RenderSVGGlyph(gfxContext * aContext,uint32_t aGlyphId,SVGContextPaint * aContextPaint)350 gfxFontEntry::RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId,
351                              SVGContextPaint* aContextPaint)
352 {
353     NS_ASSERTION(mSVGInitialized, "SVG data has not yet been loaded. TryGetSVGData() first.");
354     return mSVGGlyphs->RenderGlyph(aContext, aGlyphId, aContextPaint);
355 }
356 
357 bool
TryGetSVGData(gfxFont * aFont)358 gfxFontEntry::TryGetSVGData(gfxFont* aFont)
359 {
360     if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
361         return false;
362     }
363 
364     if (!mSVGInitialized) {
365         mSVGInitialized = true;
366 
367         // If UnitsPerEm is not known/valid, we can't use SVG glyphs
368         if (UnitsPerEm() == kInvalidUPEM) {
369             return false;
370         }
371 
372         // We don't use AutoTable here because we'll pass ownership of this
373         // blob to the gfxSVGGlyphs, once we've confirmed the table exists
374         hb_blob_t *svgTable = GetFontTable(TRUETYPE_TAG('S','V','G',' '));
375         if (!svgTable) {
376             return false;
377         }
378 
379         // gfxSVGGlyphs will hb_blob_destroy() the table when it is finished
380         // with it.
381         mSVGGlyphs = MakeUnique<gfxSVGGlyphs>(svgTable, this);
382     }
383 
384     if (mSVGGlyphs && !mFontsUsingSVGGlyphs.Contains(aFont)) {
385         mFontsUsingSVGGlyphs.AppendElement(aFont);
386     }
387 
388     return !!mSVGGlyphs;
389 }
390 
391 void
NotifyFontDestroyed(gfxFont * aFont)392 gfxFontEntry::NotifyFontDestroyed(gfxFont* aFont)
393 {
394     mFontsUsingSVGGlyphs.RemoveElement(aFont);
395 }
396 
397 void
NotifyGlyphsChanged()398 gfxFontEntry::NotifyGlyphsChanged()
399 {
400     for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
401         gfxFont* font = mFontsUsingSVGGlyphs[i];
402         font->NotifyGlyphsChanged();
403     }
404 }
405 
406 bool
TryGetColorGlyphs()407 gfxFontEntry::TryGetColorGlyphs()
408 {
409     if (mCheckedForColorGlyph) {
410         return (mCOLR && mCPAL);
411     }
412 
413     mCheckedForColorGlyph = true;
414 
415     mCOLR = GetFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R'));
416     if (!mCOLR) {
417         return false;
418     }
419 
420     mCPAL = GetFontTable(TRUETYPE_TAG('C', 'P', 'A', 'L'));
421     if (!mCPAL) {
422         hb_blob_destroy(mCOLR);
423         mCOLR = nullptr;
424         return false;
425     }
426 
427     // validation COLR and CPAL table
428     if (gfxFontUtils::ValidateColorGlyphs(mCOLR, mCPAL)) {
429         return true;
430     }
431 
432     hb_blob_destroy(mCOLR);
433     hb_blob_destroy(mCPAL);
434     mCOLR = nullptr;
435     mCPAL = nullptr;
436     return false;
437 }
438 
439 /**
440  * FontTableBlobData
441  *
442  * See FontTableHashEntry for the general strategy.
443  */
444 
445 class gfxFontEntry::FontTableBlobData {
446 public:
FontTableBlobData(nsTArray<uint8_t> && aBuffer)447     explicit FontTableBlobData(nsTArray<uint8_t>&& aBuffer)
448         : mTableData(Move(aBuffer))
449         , mHashtable(nullptr)
450         , mHashKey(0)
451     {
452         MOZ_COUNT_CTOR(FontTableBlobData);
453     }
454 
~FontTableBlobData()455     ~FontTableBlobData() {
456         MOZ_COUNT_DTOR(FontTableBlobData);
457         if (mHashtable && mHashKey) {
458             mHashtable->RemoveEntry(mHashKey);
459         }
460     }
461 
462     // Useful for creating blobs
GetTable() const463     const char *GetTable() const
464     {
465         return reinterpret_cast<const char*>(mTableData.Elements());
466     }
GetTableLength() const467     uint32_t GetTableLength() const { return mTableData.Length(); }
468 
469     // Tell this FontTableBlobData to remove the HashEntry when this is
470     // destroyed.
ManageHashEntry(nsTHashtable<FontTableHashEntry> * aHashtable,uint32_t aHashKey)471     void ManageHashEntry(nsTHashtable<FontTableHashEntry> *aHashtable,
472                          uint32_t aHashKey)
473     {
474         mHashtable = aHashtable;
475         mHashKey = aHashKey;
476     }
477 
478     // Disconnect from the HashEntry (because the blob has already been
479     // removed from the hashtable).
ForgetHashEntry()480     void ForgetHashEntry()
481     {
482         mHashtable = nullptr;
483         mHashKey = 0;
484     }
485 
SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const486     size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
487         return mTableData.ShallowSizeOfExcludingThis(aMallocSizeOf);
488     }
SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const489     size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
490         return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
491     }
492 
493 private:
494     // The font table data block
495     nsTArray<uint8_t> mTableData;
496 
497     // The blob destroy function needs to know the owning hashtable
498     // and the hashtable key, so that it can remove the entry.
499     nsTHashtable<FontTableHashEntry> *mHashtable;
500     uint32_t                          mHashKey;
501 
502     // not implemented
503     FontTableBlobData(const FontTableBlobData&);
504 };
505 
506 hb_blob_t *
507 gfxFontEntry::FontTableHashEntry::
ShareTableAndGetBlob(nsTArray<uint8_t> && aTable,nsTHashtable<FontTableHashEntry> * aHashtable)508 ShareTableAndGetBlob(nsTArray<uint8_t>&& aTable,
509                      nsTHashtable<FontTableHashEntry> *aHashtable)
510 {
511     Clear();
512     // adopts elements of aTable
513     mSharedBlobData = new FontTableBlobData(Move(aTable));
514 
515     mBlob = hb_blob_create(mSharedBlobData->GetTable(),
516                            mSharedBlobData->GetTableLength(),
517                            HB_MEMORY_MODE_READONLY,
518                            mSharedBlobData, DeleteFontTableBlobData);
519     if (mBlob == hb_blob_get_empty() ) {
520         // The FontTableBlobData was destroyed during hb_blob_create().
521         // The (empty) blob is still be held in the hashtable with a strong
522         // reference.
523         return hb_blob_reference(mBlob);
524     }
525 
526     // Tell the FontTableBlobData to remove this hash entry when destroyed.
527     // The hashtable does not keep a strong reference.
528     mSharedBlobData->ManageHashEntry(aHashtable, GetKey());
529     return mBlob;
530 }
531 
532 void
Clear()533 gfxFontEntry::FontTableHashEntry::Clear()
534 {
535     // If the FontTableBlobData is managing the hash entry, then the blob is
536     // not owned by this HashEntry; otherwise there is strong reference to the
537     // blob that must be removed.
538     if (mSharedBlobData) {
539         mSharedBlobData->ForgetHashEntry();
540         mSharedBlobData = nullptr;
541     } else if (mBlob) {
542         hb_blob_destroy(mBlob);
543     }
544     mBlob = nullptr;
545 }
546 
547 // a hb_destroy_func for hb_blob_create
548 
549 /* static */ void
DeleteFontTableBlobData(void * aBlobData)550 gfxFontEntry::FontTableHashEntry::DeleteFontTableBlobData(void *aBlobData)
551 {
552     delete static_cast<FontTableBlobData*>(aBlobData);
553 }
554 
555 hb_blob_t *
GetBlob() const556 gfxFontEntry::FontTableHashEntry::GetBlob() const
557 {
558     return hb_blob_reference(mBlob);
559 }
560 
561 bool
GetExistingFontTable(uint32_t aTag,hb_blob_t ** aBlob)562 gfxFontEntry::GetExistingFontTable(uint32_t aTag, hb_blob_t **aBlob)
563 {
564     if (!mFontTableCache) {
565         // we do this here rather than on fontEntry construction
566         // because not all shapers will access the table cache at all
567         mFontTableCache = MakeUnique<nsTHashtable<FontTableHashEntry>>(8);
568     }
569 
570     FontTableHashEntry *entry = mFontTableCache->GetEntry(aTag);
571     if (!entry) {
572         return false;
573     }
574 
575     *aBlob = entry->GetBlob();
576     return true;
577 }
578 
579 hb_blob_t *
ShareFontTableAndGetBlob(uint32_t aTag,nsTArray<uint8_t> * aBuffer)580 gfxFontEntry::ShareFontTableAndGetBlob(uint32_t aTag,
581                                        nsTArray<uint8_t>* aBuffer)
582 {
583     if (MOZ_UNLIKELY(!mFontTableCache)) {
584         // we do this here rather than on fontEntry construction
585         // because not all shapers will access the table cache at all
586       mFontTableCache = MakeUnique<nsTHashtable<FontTableHashEntry>>(8);
587     }
588 
589     FontTableHashEntry *entry = mFontTableCache->PutEntry(aTag);
590     if (MOZ_UNLIKELY(!entry)) { // OOM
591         return nullptr;
592     }
593 
594     if (!aBuffer) {
595         // ensure the entry is null
596         entry->Clear();
597         return nullptr;
598     }
599 
600     return entry->ShareTableAndGetBlob(Move(*aBuffer), mFontTableCache.get());
601 }
602 
603 already_AddRefed<gfxCharacterMap>
GetCMAPFromFontInfo(FontInfoData * aFontInfoData,uint32_t & aUVSOffset,bool & aSymbolFont)604 gfxFontEntry::GetCMAPFromFontInfo(FontInfoData *aFontInfoData,
605                                   uint32_t& aUVSOffset,
606                                   bool& aSymbolFont)
607 {
608     if (!aFontInfoData || !aFontInfoData->mLoadCmaps) {
609         return nullptr;
610     }
611 
612     return aFontInfoData->GetCMAP(mName, aUVSOffset, aSymbolFont);
613 }
614 
615 hb_blob_t *
GetFontTable(uint32_t aTag)616 gfxFontEntry::GetFontTable(uint32_t aTag)
617 {
618     hb_blob_t *blob;
619     if (GetExistingFontTable(aTag, &blob)) {
620         return blob;
621     }
622 
623     nsTArray<uint8_t> buffer;
624     bool haveTable = NS_SUCCEEDED(CopyFontTable(aTag, buffer));
625 
626     return ShareFontTableAndGetBlob(aTag, haveTable ? &buffer : nullptr);
627 }
628 
629 // callback for HarfBuzz to get a font table (in hb_blob_t form)
630 // from the font entry (passed as aUserData)
631 /*static*/ hb_blob_t *
HBGetTable(hb_face_t * face,uint32_t aTag,void * aUserData)632 gfxFontEntry::HBGetTable(hb_face_t *face, uint32_t aTag, void *aUserData)
633 {
634     gfxFontEntry *fontEntry = static_cast<gfxFontEntry*>(aUserData);
635 
636     // bug 589682 - ignore the GDEF table in buggy fonts (applies to
637     // Italic and BoldItalic faces of Times New Roman)
638     if (aTag == TRUETYPE_TAG('G','D','E','F') &&
639         fontEntry->IgnoreGDEF()) {
640         return nullptr;
641     }
642 
643     // bug 721719 - ignore the GSUB table in buggy fonts (applies to Roboto,
644     // at least on some Android ICS devices; set in gfxFT2FontList.cpp)
645     if (aTag == TRUETYPE_TAG('G','S','U','B') &&
646         fontEntry->IgnoreGSUB()) {
647         return nullptr;
648     }
649 
650     return fontEntry->GetFontTable(aTag);
651 }
652 
653 /*static*/ void
HBFaceDeletedCallback(void * aUserData)654 gfxFontEntry::HBFaceDeletedCallback(void *aUserData)
655 {
656     gfxFontEntry *fe = static_cast<gfxFontEntry*>(aUserData);
657     fe->ForgetHBFace();
658 }
659 
660 void
ForgetHBFace()661 gfxFontEntry::ForgetHBFace()
662 {
663     mHBFace = nullptr;
664 }
665 
666 hb_face_t*
GetHBFace()667 gfxFontEntry::GetHBFace()
668 {
669     if (!mHBFace) {
670         mHBFace = hb_face_create_for_tables(HBGetTable, this,
671                                             HBFaceDeletedCallback);
672         return mHBFace;
673     }
674     return hb_face_reference(mHBFace);
675 }
676 
677 /*static*/ const void*
GrGetTable(const void * aAppFaceHandle,unsigned int aName,size_t * aLen)678 gfxFontEntry::GrGetTable(const void *aAppFaceHandle, unsigned int aName,
679                          size_t *aLen)
680 {
681     gfxFontEntry *fontEntry =
682         static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
683     hb_blob_t *blob = fontEntry->GetFontTable(aName);
684     if (blob) {
685         unsigned int blobLength;
686         const void *tableData = hb_blob_get_data(blob, &blobLength);
687         fontEntry->mGrTableMap->Put(tableData, blob);
688         *aLen = blobLength;
689         return tableData;
690     }
691     *aLen = 0;
692     return nullptr;
693 }
694 
695 /*static*/ void
GrReleaseTable(const void * aAppFaceHandle,const void * aTableBuffer)696 gfxFontEntry::GrReleaseTable(const void *aAppFaceHandle,
697                              const void *aTableBuffer)
698 {
699     gfxFontEntry *fontEntry =
700         static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
701     void *data;
702     if (fontEntry->mGrTableMap->Get(aTableBuffer, &data)) {
703         fontEntry->mGrTableMap->Remove(aTableBuffer);
704         hb_blob_destroy(static_cast<hb_blob_t*>(data));
705     }
706 }
707 
708 gr_face*
GetGrFace()709 gfxFontEntry::GetGrFace()
710 {
711     if (!mGrFaceInitialized) {
712         gr_face_ops faceOps = {
713             sizeof(gr_face_ops),
714             GrGetTable,
715             GrReleaseTable
716         };
717         mGrTableMap = new nsDataHashtable<nsPtrHashKey<const void>,void*>;
718         mGrFace = gr_make_face_with_ops(this, &faceOps, gr_face_default);
719         mGrFaceInitialized = true;
720     }
721     ++mGrFaceRefCnt;
722     return mGrFace;
723 }
724 
725 void
ReleaseGrFace(gr_face * aFace)726 gfxFontEntry::ReleaseGrFace(gr_face *aFace)
727 {
728     MOZ_ASSERT(aFace == mGrFace); // sanity-check
729     MOZ_ASSERT(mGrFaceRefCnt > 0);
730     if (--mGrFaceRefCnt == 0) {
731         gr_face_destroy(mGrFace);
732         mGrFace = nullptr;
733         mGrFaceInitialized = false;
734         delete mGrTableMap;
735         mGrTableMap = nullptr;
736     }
737 }
738 
739 void
DisconnectSVG()740 gfxFontEntry::DisconnectSVG()
741 {
742     if (mSVGInitialized && mSVGGlyphs) {
743         mSVGGlyphs = nullptr;
744         mSVGInitialized = false;
745     }
746 }
747 
748 bool
HasFontTable(uint32_t aTableTag)749 gfxFontEntry::HasFontTable(uint32_t aTableTag)
750 {
751     AutoTable table(this, aTableTag);
752     return table && hb_blob_get_length(table) > 0;
753 }
754 
755 void
CheckForGraphiteTables()756 gfxFontEntry::CheckForGraphiteTables()
757 {
758     mHasGraphiteTables = HasFontTable(TRUETYPE_TAG('S','i','l','f'));
759 }
760 
761 bool
HasGraphiteSpaceContextuals()762 gfxFontEntry::HasGraphiteSpaceContextuals()
763 {
764     if (!mGraphiteSpaceContextualsInitialized) {
765         gr_face* face = GetGrFace();
766         if (face) {
767             const gr_faceinfo* faceInfo = gr_face_info(face, 0);
768             mHasGraphiteSpaceContextuals =
769                 faceInfo->space_contextuals != gr_faceinfo::gr_space_none;
770         }
771         ReleaseGrFace(face); // always balance GetGrFace, even if face is null
772         mGraphiteSpaceContextualsInitialized = true;
773     }
774     return mHasGraphiteSpaceContextuals;
775 }
776 
777 #define FEATURE_SCRIPT_MASK 0x000000ff // script index replaces low byte of tag
778 
779 static_assert(int(Script::NUM_SCRIPT_CODES) <= FEATURE_SCRIPT_MASK, "Too many script codes");
780 
781 // high-order three bytes of tag with script in low-order byte
782 #define SCRIPT_FEATURE(s,tag) (((~FEATURE_SCRIPT_MASK) & (tag)) | \
783                                ((FEATURE_SCRIPT_MASK) & static_cast<uint32_t>(s)))
784 
785 bool
SupportsOpenTypeFeature(Script aScript,uint32_t aFeatureTag)786 gfxFontEntry::SupportsOpenTypeFeature(Script aScript, uint32_t aFeatureTag)
787 {
788     if (!mSupportedFeatures) {
789         mSupportedFeatures = MakeUnique<nsDataHashtable<nsUint32HashKey,bool>>();
790     }
791 
792     // note: high-order three bytes *must* be unique for each feature
793     // listed below (see SCRIPT_FEATURE macro def'n)
794     NS_ASSERTION(aFeatureTag == HB_TAG('s','m','c','p') ||
795                  aFeatureTag == HB_TAG('c','2','s','c') ||
796                  aFeatureTag == HB_TAG('p','c','a','p') ||
797                  aFeatureTag == HB_TAG('c','2','p','c') ||
798                  aFeatureTag == HB_TAG('s','u','p','s') ||
799                  aFeatureTag == HB_TAG('s','u','b','s') ||
800                  aFeatureTag == HB_TAG('v','e','r','t'),
801                  "use of unknown feature tag");
802 
803     // note: graphite feature support uses the last script index
804     NS_ASSERTION(int(aScript) < FEATURE_SCRIPT_MASK - 1,
805                  "need to bump the size of the feature shift");
806 
807     uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
808     bool result;
809     if (mSupportedFeatures->Get(scriptFeature, &result)) {
810         return result;
811     }
812 
813     result = false;
814 
815     hb_face_t *face = GetHBFace();
816 
817     if (hb_ot_layout_has_substitution(face)) {
818         hb_script_t hbScript =
819             gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
820 
821         // Get the OpenType tag(s) that match this script code
822         hb_tag_t scriptTags[4] = {
823             HB_TAG_NONE,
824             HB_TAG_NONE,
825             HB_TAG_NONE,
826             HB_TAG_NONE
827         };
828         hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]);
829 
830         // Replace the first remaining NONE with DEFAULT
831         hb_tag_t* scriptTag = &scriptTags[0];
832         while (*scriptTag != HB_TAG_NONE) {
833             ++scriptTag;
834         }
835         *scriptTag = HB_OT_TAG_DEFAULT_SCRIPT;
836 
837         // Now check for 'smcp' under the first of those scripts that is present
838         const hb_tag_t kGSUB = HB_TAG('G','S','U','B');
839         scriptTag = &scriptTags[0];
840         while (*scriptTag != HB_TAG_NONE) {
841             unsigned int scriptIndex;
842             if (hb_ot_layout_table_find_script(face, kGSUB, *scriptTag,
843                                                &scriptIndex)) {
844                 if (hb_ot_layout_language_find_feature(face, kGSUB,
845                                                        scriptIndex,
846                                            HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
847                                                        aFeatureTag, nullptr)) {
848                     result = true;
849                 }
850                 break;
851             }
852             ++scriptTag;
853         }
854     }
855 
856     hb_face_destroy(face);
857 
858     mSupportedFeatures->Put(scriptFeature, result);
859 
860     return result;
861 }
862 
863 const hb_set_t*
InputsForOpenTypeFeature(Script aScript,uint32_t aFeatureTag)864 gfxFontEntry::InputsForOpenTypeFeature(Script aScript, uint32_t aFeatureTag)
865 {
866     if (!mFeatureInputs) {
867         mFeatureInputs = MakeUnique<nsDataHashtable<nsUint32HashKey,hb_set_t*>>();
868     }
869 
870     NS_ASSERTION(aFeatureTag == HB_TAG('s','u','p','s') ||
871                  aFeatureTag == HB_TAG('s','u','b','s'),
872                  "use of unknown feature tag");
873 
874     uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
875     hb_set_t *inputGlyphs;
876     if (mFeatureInputs->Get(scriptFeature, &inputGlyphs)) {
877         return inputGlyphs;
878     }
879 
880     inputGlyphs = hb_set_create();
881 
882     hb_face_t *face = GetHBFace();
883 
884     if (hb_ot_layout_has_substitution(face)) {
885         hb_script_t hbScript =
886             gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
887 
888         // Get the OpenType tag(s) that match this script code
889         hb_tag_t scriptTags[4] = {
890             HB_TAG_NONE,
891             HB_TAG_NONE,
892             HB_TAG_NONE,
893             HB_TAG_NONE
894         };
895         hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]);
896 
897         // Replace the first remaining NONE with DEFAULT
898         hb_tag_t* scriptTag = &scriptTags[0];
899         while (*scriptTag != HB_TAG_NONE) {
900             ++scriptTag;
901         }
902         *scriptTag = HB_OT_TAG_DEFAULT_SCRIPT;
903 
904         const hb_tag_t kGSUB = HB_TAG('G','S','U','B');
905         hb_tag_t features[2] = { aFeatureTag, HB_TAG_NONE };
906         hb_set_t *featurelookups = hb_set_create();
907         hb_ot_layout_collect_lookups(face, kGSUB, scriptTags, nullptr,
908                                      features, featurelookups);
909         hb_codepoint_t index = -1;
910         while (hb_set_next(featurelookups, &index)) {
911             hb_ot_layout_lookup_collect_glyphs(face, kGSUB, index,
912                                                nullptr, inputGlyphs,
913                                                nullptr, nullptr);
914         }
915         hb_set_destroy(featurelookups);
916     }
917 
918     hb_face_destroy(face);
919 
920     mFeatureInputs->Put(scriptFeature, inputGlyphs);
921     return inputGlyphs;
922 }
923 
924 bool
SupportsGraphiteFeature(uint32_t aFeatureTag)925 gfxFontEntry::SupportsGraphiteFeature(uint32_t aFeatureTag)
926 {
927     if (!mSupportedFeatures) {
928         mSupportedFeatures = MakeUnique<nsDataHashtable<nsUint32HashKey,bool>>();
929     }
930 
931     // note: high-order three bytes *must* be unique for each feature
932     // listed below (see SCRIPT_FEATURE macro def'n)
933     NS_ASSERTION(aFeatureTag == HB_TAG('s','m','c','p') ||
934                  aFeatureTag == HB_TAG('c','2','s','c') ||
935                  aFeatureTag == HB_TAG('p','c','a','p') ||
936                  aFeatureTag == HB_TAG('c','2','p','c') ||
937                  aFeatureTag == HB_TAG('s','u','p','s') ||
938                  aFeatureTag == HB_TAG('s','u','b','s'),
939                  "use of unknown feature tag");
940 
941     // graphite feature check uses the last script slot
942     uint32_t scriptFeature = SCRIPT_FEATURE(FEATURE_SCRIPT_MASK, aFeatureTag);
943     bool result;
944     if (mSupportedFeatures->Get(scriptFeature, &result)) {
945         return result;
946     }
947 
948     gr_face* face = GetGrFace();
949     result = face ? gr_face_find_fref(face, aFeatureTag) != nullptr : false;
950     ReleaseGrFace(face);
951 
952     mSupportedFeatures->Put(scriptFeature, result);
953 
954     return result;
955 }
956 
957 bool
GetColorLayersInfo(uint32_t aGlyphId,const mozilla::gfx::Color & aDefaultColor,nsTArray<uint16_t> & aLayerGlyphs,nsTArray<mozilla::gfx::Color> & aLayerColors)958 gfxFontEntry::GetColorLayersInfo(uint32_t aGlyphId,
959                             const mozilla::gfx::Color& aDefaultColor,
960                             nsTArray<uint16_t>& aLayerGlyphs,
961                             nsTArray<mozilla::gfx::Color>& aLayerColors)
962 {
963     return gfxFontUtils::GetColorGlyphLayers(mCOLR,
964                                              mCPAL,
965                                              aGlyphId,
966                                              aDefaultColor,
967                                              aLayerGlyphs,
968                                              aLayerColors);
969 }
970 
971 size_t
SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const972 gfxFontEntry::FontTableHashEntry::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
973 {
974     size_t n = 0;
975     if (mBlob) {
976         n += aMallocSizeOf(mBlob);
977     }
978     if (mSharedBlobData) {
979         n += mSharedBlobData->SizeOfIncludingThis(aMallocSizeOf);
980     }
981     return n;
982 }
983 
984 void
AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,FontListSizes * aSizes) const985 gfxFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
986                                      FontListSizes* aSizes) const
987 {
988     aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
989 
990     // cmaps are shared so only non-shared cmaps are included here
991     if (mCharacterMap && mCharacterMap->mBuildOnTheFly) {
992         aSizes->mCharMapsSize +=
993             mCharacterMap->SizeOfIncludingThis(aMallocSizeOf);
994     }
995     if (mFontTableCache) {
996         aSizes->mFontTableCacheSize +=
997             mFontTableCache->SizeOfIncludingThis(aMallocSizeOf);
998     }
999 
1000     // If the font has UVS data, we count that as part of the character map.
1001     if (mUVSData) {
1002         aSizes->mCharMapsSize += aMallocSizeOf(mUVSData.get());
1003     }
1004 
1005     // The following, if present, are essentially cached forms of font table
1006     // data, so we'll accumulate them together with the basic table cache.
1007     if (mUserFontData) {
1008         aSizes->mFontTableCacheSize +=
1009             mUserFontData->SizeOfIncludingThis(aMallocSizeOf);
1010     }
1011     if (mSVGGlyphs) {
1012         aSizes->mFontTableCacheSize +=
1013             mSVGGlyphs->SizeOfIncludingThis(aMallocSizeOf);
1014     }
1015     if (mSupportedFeatures) {
1016         aSizes->mFontTableCacheSize +=
1017             mSupportedFeatures->ShallowSizeOfIncludingThis(aMallocSizeOf);
1018     }
1019     if (mFeatureInputs) {
1020         aSizes->mFontTableCacheSize +=
1021             mFeatureInputs->ShallowSizeOfIncludingThis(aMallocSizeOf);
1022         for (auto iter = mFeatureInputs->ConstIter(); !iter.Done();
1023              iter.Next()) {
1024             // There's no API to get the real size of an hb_set, so we'll use
1025             // an approximation based on knowledge of the implementation.
1026             aSizes->mFontTableCacheSize += 8192; // vector of 64K bits
1027         }
1028     }
1029     // We don't include the size of mCOLR/mCPAL here, because (depending on the
1030     // font backend implementation) they will either wrap blocks of data owned
1031     // by the system (and potentially shared), or tables that are in our font
1032     // table cache and therefore already counted.
1033 }
1034 
1035 void
AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,FontListSizes * aSizes) const1036 gfxFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
1037                                      FontListSizes* aSizes) const
1038 {
1039     aSizes->mFontListSize += aMallocSizeOf(this);
1040     AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
1041 }
1042 
1043 // This is used to report the size of an individual downloaded font in the
1044 // user font cache. (Fonts that are part of the platform font list accumulate
1045 // their sizes to the font list's reporter using the AddSizeOf... methods
1046 // above.)
1047 size_t
ComputedSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const1048 gfxFontEntry::ComputedSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
1049 {
1050     FontListSizes s = { 0 };
1051     AddSizeOfExcludingThis(aMallocSizeOf, &s);
1052 
1053     // When reporting memory used for the main platform font list,
1054     // where we're typically summing the totals for a few hundred font faces,
1055     // we report the fields of FontListSizes separately.
1056     // But for downloaded user fonts, the actual resource data (added below)
1057     // will dominate, and the minor overhead of these pieces isn't worth
1058     // splitting out for an individual font.
1059     size_t result = s.mFontListSize + s.mFontTableCacheSize + s.mCharMapsSize;
1060 
1061     if (mIsDataUserFont) {
1062         MOZ_ASSERT(mComputedSizeOfUserFont > 0, "user font with no data?");
1063         result += mComputedSizeOfUserFont;
1064     }
1065 
1066     return result;
1067 }
1068 
1069 //////////////////////////////////////////////////////////////////////////////
1070 //
1071 // class gfxFontFamily
1072 //
1073 //////////////////////////////////////////////////////////////////////////////
1074 
1075 // we consider faces with mStandardFace == true to be "less than" those with false,
1076 // because during style matching, earlier entries are tried first
1077 class FontEntryStandardFaceComparator {
1078   public:
Equals(const RefPtr<gfxFontEntry> & a,const RefPtr<gfxFontEntry> & b) const1079     bool Equals(const RefPtr<gfxFontEntry>& a, const RefPtr<gfxFontEntry>& b) const {
1080         return a->mStandardFace == b->mStandardFace;
1081     }
LessThan(const RefPtr<gfxFontEntry> & a,const RefPtr<gfxFontEntry> & b) const1082     bool LessThan(const RefPtr<gfxFontEntry>& a, const RefPtr<gfxFontEntry>& b) const {
1083         return (a->mStandardFace == true && b->mStandardFace == false);
1084     }
1085 };
1086 
1087 void
SortAvailableFonts()1088 gfxFontFamily::SortAvailableFonts()
1089 {
1090     mAvailableFonts.Sort(FontEntryStandardFaceComparator());
1091 }
1092 
1093 bool
HasOtherFamilyNames()1094 gfxFontFamily::HasOtherFamilyNames()
1095 {
1096     // need to read in other family names to determine this
1097     if (!mOtherFamilyNamesInitialized) {
1098         ReadOtherFamilyNames(gfxPlatformFontList::PlatformFontList());  // sets mHasOtherFamilyNames
1099     }
1100     return mHasOtherFamilyNames;
1101 }
1102 
1103 gfxFontEntry*
FindFontForStyle(const gfxFontStyle & aFontStyle,bool & aNeedsSyntheticBold)1104 gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle,
1105                                 bool& aNeedsSyntheticBold)
1106 {
1107     AutoTArray<gfxFontEntry*,4> matched;
1108     FindAllFontsForStyle(aFontStyle, matched, aNeedsSyntheticBold);
1109     if (!matched.IsEmpty()) {
1110         return matched[0];
1111     }
1112     return nullptr;
1113 }
1114 
1115 #define STYLE_SHIFT 2 // number of bits to contain style distance
1116 
1117 // style distance ==> [0,2]
1118 static inline uint32_t
StyleDistance(uint32_t aFontStyle,uint32_t aTargetStyle)1119 StyleDistance(uint32_t aFontStyle, uint32_t aTargetStyle)
1120 {
1121     if (aFontStyle == aTargetStyle) {
1122         return 0; // styles match exactly ==> 0
1123     }
1124     if (aFontStyle == NS_FONT_STYLE_NORMAL ||
1125         aTargetStyle == NS_FONT_STYLE_NORMAL) {
1126         return 2; // one is normal (but not the other) ==> 2
1127     }
1128     return 1; // neither is normal; must be italic vs oblique ==> 1
1129 }
1130 
1131 #define REVERSE_STRETCH_DISTANCE 5
1132 
1133 // stretch distance ==> [0,13]
1134 static inline uint32_t
StretchDistance(int16_t aFontStretch,int16_t aTargetStretch)1135 StretchDistance(int16_t aFontStretch, int16_t aTargetStretch)
1136 {
1137     int32_t distance = 0;
1138     if (aTargetStretch != aFontStretch) {
1139         // stretch values are in the range -4 .. +4
1140         // if aTargetStretch is positive, we prefer more-positive values;
1141         // if zero or negative, prefer more-negative
1142         if (aTargetStretch > 0) {
1143             distance = (aFontStretch - aTargetStretch);
1144         } else {
1145             distance = (aTargetStretch - aFontStretch);
1146         }
1147         // if the computed "distance" here is negative, it means that
1148         // aFontEntry lies in the "non-preferred" direction from aTargetStretch,
1149         // so we treat that as larger than any preferred-direction distance
1150         // (max possible is 4) by adding an extra 5 to the absolute value
1151         if (distance < 0) {
1152             distance = -distance + REVERSE_STRETCH_DISTANCE;
1153         }
1154     }
1155     return uint32_t(distance);
1156 }
1157 
1158 // CSS currently limits font weights to multiples of 100 but the weight
1159 // matching code below does not assume this.
1160 //
1161 // Calculate weight distance with values in the range (0..1000). In general,
1162 // heavier weights match towards even heavier weights while lighter weights
1163 // match towards even lighter weights. Target weight values in the range
1164 // [400..500] are special, since they will first match up to 500, then down
1165 // towards 0, then up again towards 999.
1166 //
1167 // Example: with target 600 and font weight 800, distance will be 200. With
1168 // target 300 and font weight 600, distance will be 900, since heavier
1169 // weights are farther away than lighter weights. If the target is 5 and the
1170 // font weight 995, the distance would be 1590 for the same reason.
1171 
1172 #define REVERSE_WEIGHT_DISTANCE 600
1173 #define WEIGHT_SHIFT             11 // number of bits to contain weight distance
1174 
1175 // weight distance ==> [0,1598]
1176 static inline uint32_t
WeightDistance(uint32_t aFontWeight,uint32_t aTargetWeight)1177 WeightDistance(uint32_t aFontWeight, uint32_t aTargetWeight)
1178 {
1179     // Compute a measure of the "distance" between the requested
1180     // weight and the given fontEntry
1181 
1182     int32_t distance = 0, addedDistance = 0;
1183     if (aTargetWeight != aFontWeight) {
1184         if (aTargetWeight > 500) {
1185             distance = aFontWeight - aTargetWeight;
1186         } else if (aTargetWeight < 400) {
1187             distance = aTargetWeight - aFontWeight;
1188         } else {
1189             // special case - target is between 400 and 500
1190 
1191             // font weights between 400 and 500 are close
1192             if (aFontWeight >= 400 && aFontWeight <= 500) {
1193                 if (aFontWeight < aTargetWeight) {
1194                     distance = 500 - aFontWeight;
1195                 } else {
1196                     distance = aFontWeight - aTargetWeight;
1197                 }
1198             } else {
1199                 // font weights outside use rule for target weights < 400 with
1200                 // added distance to separate from font weights in
1201                 // the [400..500] range
1202                 distance = aTargetWeight - aFontWeight;
1203                 addedDistance = 100;
1204             }
1205         }
1206         if (distance < 0) {
1207             distance = -distance + REVERSE_WEIGHT_DISTANCE;
1208         }
1209         distance += addedDistance;
1210     }
1211     return uint32_t(distance);
1212 }
1213 
1214 #define MAX_DISTANCE 0xffffffff
1215 
1216 static inline uint32_t
WeightStyleStretchDistance(gfxFontEntry * aFontEntry,const gfxFontStyle & aTargetStyle)1217 WeightStyleStretchDistance(gfxFontEntry* aFontEntry,
1218                            const gfxFontStyle& aTargetStyle)
1219 {
1220     // weight/style/stretch priority: stretch >> style >> weight
1221     uint32_t stretchDist =
1222         StretchDistance(aFontEntry->mStretch, aTargetStyle.stretch);
1223     uint32_t styleDist = StyleDistance(aFontEntry->mStyle, aTargetStyle.style);
1224     uint32_t weightDist =
1225         WeightDistance(aFontEntry->Weight(), aTargetStyle.weight);
1226 
1227     NS_ASSERTION(weightDist < (1 << WEIGHT_SHIFT), "weight value out of bounds");
1228     NS_ASSERTION(styleDist < (1 << STYLE_SHIFT), "slope value out of bounds");
1229 
1230     return (stretchDist << (STYLE_SHIFT + WEIGHT_SHIFT)) |
1231            (styleDist << WEIGHT_SHIFT) |
1232            weightDist;
1233 }
1234 
1235 void
FindAllFontsForStyle(const gfxFontStyle & aFontStyle,nsTArray<gfxFontEntry * > & aFontEntryList,bool & aNeedsSyntheticBold)1236 gfxFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
1237                                     nsTArray<gfxFontEntry*>& aFontEntryList,
1238                                     bool& aNeedsSyntheticBold)
1239 {
1240     if (!mHasStyles) {
1241         FindStyleVariations(); // collect faces for the family, if not already done
1242     }
1243 
1244     NS_ASSERTION(mAvailableFonts.Length() > 0, "font family with no faces!");
1245     NS_ASSERTION(aFontEntryList.IsEmpty(), "non-empty fontlist passed in");
1246 
1247     aNeedsSyntheticBold = false;
1248 
1249     int8_t baseWeight = aFontStyle.ComputeWeight();
1250     bool wantBold = baseWeight >= 6;
1251     gfxFontEntry *fe = nullptr;
1252 
1253     // If the family has only one face, we simply return it; no further
1254     // checking needed
1255     uint32_t count = mAvailableFonts.Length();
1256     if (count == 1) {
1257         fe = mAvailableFonts[0];
1258         aNeedsSyntheticBold =
1259             wantBold && !fe->IsBold() && aFontStyle.allowSyntheticWeight;
1260         aFontEntryList.AppendElement(fe);
1261         return;
1262     }
1263 
1264     // Most families are "simple", having just Regular/Bold/Italic/BoldItalic,
1265     // or some subset of these. In this case, we have exactly 4 entries in mAvailableFonts,
1266     // stored in the above order; note that some of the entries may be nullptr.
1267     // We can then pick the required entry based on whether the request is for
1268     // bold or non-bold, italic or non-italic, without running the more complex
1269     // matching algorithm used for larger families with many weights and/or widths.
1270 
1271     if (mIsSimpleFamily) {
1272         // Family has no more than the "standard" 4 faces, at fixed indexes;
1273         // calculate which one we want.
1274         // Note that we cannot simply return it as not all 4 faces are necessarily present.
1275         bool wantItalic = (aFontStyle.style != NS_FONT_STYLE_NORMAL);
1276         uint8_t faceIndex = (wantItalic ? kItalicMask : 0) |
1277                             (wantBold ? kBoldMask : 0);
1278 
1279         // if the desired style is available, return it directly
1280         fe = mAvailableFonts[faceIndex];
1281         if (fe) {
1282             // no need to set aNeedsSyntheticBold here as we matched the boldness request
1283             aFontEntryList.AppendElement(fe);
1284             return;
1285         }
1286 
1287         // order to check fallback faces in a simple family, depending on requested style
1288         static const uint8_t simpleFallbacks[4][3] = {
1289             { kBoldFaceIndex, kItalicFaceIndex, kBoldItalicFaceIndex },   // fallbacks for Regular
1290             { kRegularFaceIndex, kBoldItalicFaceIndex, kItalicFaceIndex },// Bold
1291             { kBoldItalicFaceIndex, kRegularFaceIndex, kBoldFaceIndex },  // Italic
1292             { kItalicFaceIndex, kBoldFaceIndex, kRegularFaceIndex }       // BoldItalic
1293         };
1294         const uint8_t *order = simpleFallbacks[faceIndex];
1295 
1296         for (uint8_t trial = 0; trial < 3; ++trial) {
1297             // check remaining faces in order of preference to find the first that actually exists
1298             fe = mAvailableFonts[order[trial]];
1299             if (fe) {
1300                 aNeedsSyntheticBold =
1301                     wantBold && !fe->IsBold() &&
1302                     aFontStyle.allowSyntheticWeight;
1303                 aFontEntryList.AppendElement(fe);
1304                 return;
1305             }
1306         }
1307 
1308         // this can't happen unless we have totally broken the font-list manager!
1309         NS_NOTREACHED("no face found in simple font family!");
1310     }
1311 
1312     // Pick the font(s) that are closest to the desired weight, style, and
1313     // stretch. Iterate over all fonts, measuring the weight/style distance.
1314     // Because of unicode-range values, there may be more than one font for a
1315     // given but the 99% use case is only a single font entry per
1316     // weight/style/stretch distance value. To optimize this, only add entries
1317     // to the matched font array when another entry already has the same
1318     // weight/style/stretch distance and add the last matched font entry. For
1319     // normal platform fonts with a single font entry for each
1320     // weight/style/stretch combination, only the last matched font entry will
1321     // be added.
1322 
1323     uint32_t minDistance = MAX_DISTANCE;
1324     gfxFontEntry* matched = nullptr;
1325     // iterate in forward order so that faces like 'Bold' are matched before
1326     // matching style distance faces such as 'Bold Outline' (see bug 1185812)
1327     for (uint32_t i = 0; i < count; i++) {
1328         fe = mAvailableFonts[i];
1329         // weight/style/stretch priority: stretch >> style >> weight
1330         uint32_t distance = WeightStyleStretchDistance(fe, aFontStyle);
1331         if (distance < minDistance) {
1332             matched = fe;
1333             if (!aFontEntryList.IsEmpty()) {
1334                 aFontEntryList.Clear();
1335             }
1336             minDistance = distance;
1337         } else if (distance == minDistance) {
1338             if (matched) {
1339                 aFontEntryList.AppendElement(matched);
1340             }
1341             matched = fe;
1342         }
1343     }
1344 
1345     NS_ASSERTION(matched, "didn't match a font within a family");
1346 
1347     if (matched) {
1348         aFontEntryList.AppendElement(matched);
1349         if (!matched->IsBold() && aFontStyle.weight >= 600 &&
1350             aFontStyle.allowSyntheticWeight) {
1351             aNeedsSyntheticBold = true;
1352         }
1353     }
1354 }
1355 
1356 void
CheckForSimpleFamily()1357 gfxFontFamily::CheckForSimpleFamily()
1358 {
1359     // already checked this family
1360     if (mIsSimpleFamily) {
1361         return;
1362     }
1363 
1364     uint32_t count = mAvailableFonts.Length();
1365     if (count > 4 || count == 0) {
1366         return; // can't be "simple" if there are >4 faces;
1367                 // if none then the family is unusable anyway
1368     }
1369 
1370     if (count == 1) {
1371         mIsSimpleFamily = true;
1372         return;
1373     }
1374 
1375     int16_t firstStretch = mAvailableFonts[0]->Stretch();
1376 
1377     gfxFontEntry *faces[4] = { 0 };
1378     for (uint8_t i = 0; i < count; ++i) {
1379         gfxFontEntry *fe = mAvailableFonts[i];
1380         if (fe->Stretch() != firstStretch || fe->IsOblique()) {
1381             // simple families don't have varying font-stretch or oblique
1382             return;
1383         }
1384         uint8_t faceIndex = (fe->IsItalic() ? kItalicMask : 0) |
1385                             (fe->Weight() >= 600 ? kBoldMask : 0);
1386         if (faces[faceIndex]) {
1387             return; // two faces resolve to the same slot; family isn't "simple"
1388         }
1389         faces[faceIndex] = fe;
1390     }
1391 
1392     // we have successfully slotted the available faces into the standard
1393     // 4-face framework
1394     mAvailableFonts.SetLength(4);
1395     for (uint8_t i = 0; i < 4; ++i) {
1396         if (mAvailableFonts[i].get() != faces[i]) {
1397             mAvailableFonts[i].swap(faces[i]);
1398         }
1399     }
1400 
1401     mIsSimpleFamily = true;
1402 }
1403 
1404 #ifdef DEBUG
1405 bool
ContainsFace(gfxFontEntry * aFontEntry)1406 gfxFontFamily::ContainsFace(gfxFontEntry* aFontEntry) {
1407     uint32_t i, numFonts = mAvailableFonts.Length();
1408     for (i = 0; i < numFonts; i++) {
1409         if (mAvailableFonts[i] == aFontEntry) {
1410             return true;
1411         }
1412         // userfonts contain the actual real font entry
1413         if (mAvailableFonts[i] && mAvailableFonts[i]->mIsUserFontContainer) {
1414             gfxUserFontEntry* ufe =
1415                 static_cast<gfxUserFontEntry*>(mAvailableFonts[i].get());
1416             if (ufe->GetPlatformFontEntry() == aFontEntry) {
1417                 return true;
1418             }
1419         }
1420     }
1421     return false;
1422 }
1423 #endif
1424 
LocalizedName(nsAString & aLocalizedName)1425 void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
1426 {
1427     // just return the primary name; subclasses should override
1428     aLocalizedName = mName;
1429 }
1430 
1431 // metric for how close a given font matches a style
1432 static int32_t
CalcStyleMatch(gfxFontEntry * aFontEntry,const gfxFontStyle * aStyle)1433 CalcStyleMatch(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle)
1434 {
1435     int32_t rank = 0;
1436     if (aStyle) {
1437          // italics
1438          bool wantUpright = (aStyle->style == NS_FONT_STYLE_NORMAL);
1439          if (aFontEntry->IsUpright() == wantUpright) {
1440              rank += 10;
1441          }
1442 
1443         // measure of closeness of weight to the desired value
1444         rank += 9 - DeprecatedAbs(aFontEntry->Weight() / 100 - aStyle->ComputeWeight());
1445     } else {
1446         // if no font to match, prefer non-bold, non-italic fonts
1447         if (aFontEntry->IsUpright()) {
1448             rank += 3;
1449         }
1450         if (!aFontEntry->IsBold()) {
1451             rank += 2;
1452         }
1453     }
1454 
1455     return rank;
1456 }
1457 
1458 #define RANK_MATCHED_CMAP   20
1459 
1460 void
FindFontForChar(GlobalFontMatch * aMatchData)1461 gfxFontFamily::FindFontForChar(GlobalFontMatch *aMatchData)
1462 {
1463     if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
1464         // none of the faces in the family support the required char,
1465         // so bail out immediately
1466         return;
1467     }
1468 
1469     bool needsBold;
1470     gfxFontEntry *fe =
1471         FindFontForStyle(aMatchData->mStyle ? *aMatchData->mStyle
1472                                             : gfxFontStyle(),
1473                          needsBold);
1474 
1475     if (fe && !fe->SkipDuringSystemFallback()) {
1476         int32_t rank = 0;
1477 
1478         if (fe->HasCharacter(aMatchData->mCh)) {
1479             rank += RANK_MATCHED_CMAP;
1480             aMatchData->mCount++;
1481 
1482             LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
1483 
1484             if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
1485                 uint32_t unicodeRange = FindCharUnicodeRange(aMatchData->mCh);
1486                 Script script = GetScriptCode(aMatchData->mCh);
1487                 MOZ_LOG(log, LogLevel::Debug,\
1488                        ("(textrun-systemfallback-fonts) char: u+%6.6x "
1489                         "unicode-range: %d script: %d match: [%s]\n",
1490                         aMatchData->mCh,
1491                         unicodeRange, int(script),
1492                         NS_ConvertUTF16toUTF8(fe->Name()).get()));
1493             }
1494         }
1495 
1496         aMatchData->mCmapsTested++;
1497         if (rank == 0) {
1498             return;
1499         }
1500 
1501          // omitting from original windows code -- family name, lang group, pitch
1502          // not available in current FontEntry implementation
1503         rank += CalcStyleMatch(fe, aMatchData->mStyle);
1504 
1505         // xxx - add whether AAT font with morphing info for specific lang groups
1506 
1507         if (rank > aMatchData->mMatchRank
1508             || (rank == aMatchData->mMatchRank &&
1509                 Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
1510         {
1511             aMatchData->mBestMatch = fe;
1512             aMatchData->mMatchedFamily = this;
1513             aMatchData->mMatchRank = rank;
1514         }
1515     }
1516 }
1517 
1518 void
SearchAllFontsForChar(GlobalFontMatch * aMatchData)1519 gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch *aMatchData)
1520 {
1521     uint32_t i, numFonts = mAvailableFonts.Length();
1522     for (i = 0; i < numFonts; i++) {
1523         gfxFontEntry *fe = mAvailableFonts[i];
1524         if (fe && fe->HasCharacter(aMatchData->mCh)) {
1525             int32_t rank = RANK_MATCHED_CMAP;
1526             rank += CalcStyleMatch(fe, aMatchData->mStyle);
1527             if (rank > aMatchData->mMatchRank
1528                 || (rank == aMatchData->mMatchRank &&
1529                     Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
1530             {
1531                 aMatchData->mBestMatch = fe;
1532                 aMatchData->mMatchedFamily = this;
1533                 aMatchData->mMatchRank = rank;
1534             }
1535         }
1536     }
1537 }
1538 
1539 /*static*/ void
ReadOtherFamilyNamesForFace(const nsAString & aFamilyName,const char * aNameData,uint32_t aDataLength,nsTArray<nsString> & aOtherFamilyNames,bool useFullName)1540 gfxFontFamily::ReadOtherFamilyNamesForFace(const nsAString& aFamilyName,
1541                                            const char *aNameData,
1542                                            uint32_t aDataLength,
1543                                            nsTArray<nsString>& aOtherFamilyNames,
1544                                            bool useFullName)
1545 {
1546     const gfxFontUtils::NameHeader *nameHeader =
1547         reinterpret_cast<const gfxFontUtils::NameHeader*>(aNameData);
1548 
1549     uint32_t nameCount = nameHeader->count;
1550     if (nameCount * sizeof(gfxFontUtils::NameRecord) > aDataLength) {
1551         NS_WARNING("invalid font (name records)");
1552         return;
1553     }
1554 
1555     const gfxFontUtils::NameRecord *nameRecord =
1556         reinterpret_cast<const gfxFontUtils::NameRecord*>(aNameData + sizeof(gfxFontUtils::NameHeader));
1557     uint32_t stringsBase = uint32_t(nameHeader->stringOffset);
1558 
1559     for (uint32_t i = 0; i < nameCount; i++, nameRecord++) {
1560         uint32_t nameLen = nameRecord->length;
1561         uint32_t nameOff = nameRecord->offset;  // offset from base of string storage
1562 
1563         if (stringsBase + nameOff + nameLen > aDataLength) {
1564             NS_WARNING("invalid font (name table strings)");
1565             return;
1566         }
1567 
1568         uint16_t nameID = nameRecord->nameID;
1569         if ((useFullName && nameID == gfxFontUtils::NAME_ID_FULL) ||
1570             (!useFullName && (nameID == gfxFontUtils::NAME_ID_FAMILY ||
1571                               nameID == gfxFontUtils::NAME_ID_PREFERRED_FAMILY))) {
1572             nsAutoString otherFamilyName;
1573             bool ok = gfxFontUtils::DecodeFontName(aNameData + stringsBase + nameOff,
1574                                                      nameLen,
1575                                                      uint32_t(nameRecord->platformID),
1576                                                      uint32_t(nameRecord->encodingID),
1577                                                      uint32_t(nameRecord->languageID),
1578                                                      otherFamilyName);
1579             // add if not same as canonical family name
1580             if (ok && otherFamilyName != aFamilyName) {
1581                 aOtherFamilyNames.AppendElement(otherFamilyName);
1582             }
1583         }
1584     }
1585 }
1586 
1587 // returns true if other names were found, false otherwise
1588 bool
ReadOtherFamilyNamesForFace(gfxPlatformFontList * aPlatformFontList,hb_blob_t * aNameTable,bool useFullName)1589 gfxFontFamily::ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
1590                                            hb_blob_t           *aNameTable,
1591                                            bool                 useFullName)
1592 {
1593     uint32_t dataLength;
1594     const char *nameData = hb_blob_get_data(aNameTable, &dataLength);
1595     AutoTArray<nsString,4> otherFamilyNames;
1596 
1597     ReadOtherFamilyNamesForFace(mName, nameData, dataLength,
1598                                 otherFamilyNames, useFullName);
1599 
1600     uint32_t n = otherFamilyNames.Length();
1601     for (uint32_t i = 0; i < n; i++) {
1602         aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
1603     }
1604 
1605     return n != 0;
1606 }
1607 
1608 void
ReadOtherFamilyNames(gfxPlatformFontList * aPlatformFontList)1609 gfxFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
1610 {
1611     if (mOtherFamilyNamesInitialized)
1612         return;
1613     mOtherFamilyNamesInitialized = true;
1614 
1615     FindStyleVariations();
1616 
1617     // read in other family names for the first face in the list
1618     uint32_t i, numFonts = mAvailableFonts.Length();
1619     const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
1620 
1621     for (i = 0; i < numFonts; ++i) {
1622         gfxFontEntry *fe = mAvailableFonts[i];
1623         if (!fe) {
1624             continue;
1625         }
1626         gfxFontEntry::AutoTable nameTable(fe, kNAME);
1627         if (!nameTable) {
1628             continue;
1629         }
1630         mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
1631                                                            nameTable);
1632         break;
1633     }
1634 
1635     // read in other names for the first face in the list with the assumption
1636     // that if extra names don't exist in that face then they don't exist in
1637     // other faces for the same font
1638     if (!mHasOtherFamilyNames)
1639         return;
1640 
1641     // read in names for all faces, needed to catch cases where fonts have
1642     // family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
1643     for ( ; i < numFonts; i++) {
1644         gfxFontEntry *fe = mAvailableFonts[i];
1645         if (!fe) {
1646             continue;
1647         }
1648         gfxFontEntry::AutoTable nameTable(fe, kNAME);
1649         if (!nameTable) {
1650             continue;
1651         }
1652         ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
1653     }
1654 }
1655 
1656 void
ReadFaceNames(gfxPlatformFontList * aPlatformFontList,bool aNeedFullnamePostscriptNames,FontInfoData * aFontInfoData)1657 gfxFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
1658                              bool aNeedFullnamePostscriptNames,
1659                              FontInfoData *aFontInfoData)
1660 {
1661     // if all needed names have already been read, skip
1662     if (mOtherFamilyNamesInitialized &&
1663         (mFaceNamesInitialized || !aNeedFullnamePostscriptNames))
1664         return;
1665 
1666     bool asyncFontLoaderDisabled = false;
1667 
1668     if (!mOtherFamilyNamesInitialized &&
1669         aFontInfoData &&
1670         aFontInfoData->mLoadOtherNames &&
1671         !asyncFontLoaderDisabled)
1672     {
1673         AutoTArray<nsString,4> otherFamilyNames;
1674         bool foundOtherNames =
1675             aFontInfoData->GetOtherFamilyNames(mName, otherFamilyNames);
1676         if (foundOtherNames) {
1677             uint32_t i, n = otherFamilyNames.Length();
1678             for (i = 0; i < n; i++) {
1679                 aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
1680             }
1681         }
1682         mOtherFamilyNamesInitialized = true;
1683     }
1684 
1685     // if all needed data has been initialized, return
1686     if (mOtherFamilyNamesInitialized &&
1687         (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
1688         return;
1689     }
1690 
1691     FindStyleVariations(aFontInfoData);
1692 
1693     // check again, as style enumeration code may have loaded names
1694     if (mOtherFamilyNamesInitialized &&
1695         (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
1696         return;
1697     }
1698 
1699     uint32_t i, numFonts = mAvailableFonts.Length();
1700     const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
1701 
1702     bool firstTime = true, readAllFaces = false;
1703     for (i = 0; i < numFonts; ++i) {
1704         gfxFontEntry *fe = mAvailableFonts[i];
1705         if (!fe) {
1706             continue;
1707         }
1708 
1709         nsAutoString fullname, psname;
1710         bool foundFaceNames = false;
1711         if (!mFaceNamesInitialized &&
1712             aNeedFullnamePostscriptNames &&
1713             aFontInfoData &&
1714             aFontInfoData->mLoadFaceNames) {
1715             aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
1716             if (!fullname.IsEmpty()) {
1717                 aPlatformFontList->AddFullname(fe, fullname);
1718             }
1719             if (!psname.IsEmpty()) {
1720                 aPlatformFontList->AddPostscriptName(fe, psname);
1721             }
1722             foundFaceNames = true;
1723 
1724             // found everything needed? skip to next font
1725             if (mOtherFamilyNamesInitialized) {
1726                 continue;
1727             }
1728         }
1729 
1730         // load directly from the name table
1731         gfxFontEntry::AutoTable nameTable(fe, kNAME);
1732         if (!nameTable) {
1733             continue;
1734         }
1735 
1736         if (aNeedFullnamePostscriptNames && !foundFaceNames) {
1737             if (gfxFontUtils::ReadCanonicalName(
1738                     nameTable, gfxFontUtils::NAME_ID_FULL, fullname) == NS_OK)
1739             {
1740                 aPlatformFontList->AddFullname(fe, fullname);
1741             }
1742 
1743             if (gfxFontUtils::ReadCanonicalName(
1744                     nameTable, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK)
1745             {
1746                 aPlatformFontList->AddPostscriptName(fe, psname);
1747             }
1748         }
1749 
1750         if (!mOtherFamilyNamesInitialized && (firstTime || readAllFaces)) {
1751             bool foundOtherName = ReadOtherFamilyNamesForFace(aPlatformFontList,
1752                                                               nameTable);
1753 
1754             // if the first face has a different name, scan all faces, otherwise
1755             // assume the family doesn't have other names
1756             if (firstTime && foundOtherName) {
1757                 mHasOtherFamilyNames = true;
1758                 readAllFaces = true;
1759             }
1760             firstTime = false;
1761         }
1762 
1763         // if not reading in any more names, skip other faces
1764         if (!readAllFaces && !aNeedFullnamePostscriptNames) {
1765             break;
1766         }
1767     }
1768 
1769     mFaceNamesInitialized = true;
1770     mOtherFamilyNamesInitialized = true;
1771 }
1772 
1773 
1774 gfxFontEntry*
FindFont(const nsAString & aPostscriptName)1775 gfxFontFamily::FindFont(const nsAString& aPostscriptName)
1776 {
1777     // find the font using a simple linear search
1778     uint32_t numFonts = mAvailableFonts.Length();
1779     for (uint32_t i = 0; i < numFonts; i++) {
1780         gfxFontEntry *fe = mAvailableFonts[i].get();
1781         if (fe && fe->Name() == aPostscriptName)
1782             return fe;
1783     }
1784     return nullptr;
1785 }
1786 
1787 void
ReadAllCMAPs(FontInfoData * aFontInfoData)1788 gfxFontFamily::ReadAllCMAPs(FontInfoData *aFontInfoData)
1789 {
1790     FindStyleVariations(aFontInfoData);
1791 
1792     uint32_t i, numFonts = mAvailableFonts.Length();
1793     for (i = 0; i < numFonts; i++) {
1794         gfxFontEntry *fe = mAvailableFonts[i];
1795         // don't try to load cmaps for downloadable fonts not yet loaded
1796         if (!fe || fe->mIsUserFontContainer) {
1797             continue;
1798         }
1799         fe->ReadCMAP(aFontInfoData);
1800         mFamilyCharacterMap.Union(*(fe->mCharacterMap));
1801     }
1802     mFamilyCharacterMap.Compact();
1803     mFamilyCharacterMapInitialized = true;
1804 }
1805 
1806 void
AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,FontListSizes * aSizes) const1807 gfxFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
1808                                       FontListSizes* aSizes) const
1809 {
1810     aSizes->mFontListSize +=
1811         mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1812     aSizes->mCharMapsSize +=
1813         mFamilyCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
1814 
1815     aSizes->mFontListSize +=
1816         mAvailableFonts.ShallowSizeOfExcludingThis(aMallocSizeOf);
1817     for (uint32_t i = 0; i < mAvailableFonts.Length(); ++i) {
1818         gfxFontEntry *fe = mAvailableFonts[i];
1819         if (fe) {
1820             fe->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
1821         }
1822     }
1823 }
1824 
1825 void
AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,FontListSizes * aSizes) const1826 gfxFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
1827                                       FontListSizes* aSizes) const
1828 {
1829     aSizes->mFontListSize += aMallocSizeOf(this);
1830     AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
1831 }
1832