Coverage Report

Created: 2018-09-25 14:53

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