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