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