Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/thebes/gfxPlatformFontList.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 "mozilla/Logging.h"
7
#include "mozilla/intl/LocaleService.h"
8
#include "mozilla/intl/MozLocale.h"
9
#include "mozilla/intl/OSPreferences.h"
10
11
#include "gfxPlatformFontList.h"
12
#include "gfxTextRun.h"
13
#include "gfxUserFontSet.h"
14
15
#include "nsCRT.h"
16
#include "nsGkAtoms.h"
17
#include "nsServiceManagerUtils.h"
18
#include "nsUnicharUtils.h"
19
#include "nsUnicodeRange.h"
20
#include "nsUnicodeProperties.h"
21
#include "nsXULAppAPI.h"
22
23
#include "mozilla/Attributes.h"
24
#include "mozilla/Likely.h"
25
#include "mozilla/MemoryReporting.h"
26
#include "mozilla/Mutex.h"
27
#include "mozilla/Preferences.h"
28
#include "mozilla/Telemetry.h"
29
#include "mozilla/TimeStamp.h"
30
#include "mozilla/dom/ContentParent.h"
31
#include "mozilla/gfx/2D.h"
32
33
#include <locale.h>
34
35
using namespace mozilla;
36
using mozilla::intl::LocaleService;
37
using mozilla::intl::Locale;
38
using mozilla::intl::OSPreferences;
39
40
0
#define LOG_FONTLIST(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
41
0
                               LogLevel::Debug, args)
42
#define LOG_FONTLIST_ENABLED() MOZ_LOG_TEST( \
43
                                   gfxPlatform::GetLog(eGfxLog_fontlist), \
44
                                   LogLevel::Debug)
45
0
#define LOG_FONTINIT(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
46
0
                               LogLevel::Debug, args)
47
0
#define LOG_FONTINIT_ENABLED() MOZ_LOG_TEST( \
48
0
                                   gfxPlatform::GetLog(eGfxLog_fontinit), \
49
0
                                   LogLevel::Debug)
50
51
gfxPlatformFontList *gfxPlatformFontList::sPlatformFontList = nullptr;
52
53
// Character ranges that require complex-script shaping support in the font,
54
// and so should be masked out by ReadCMAP if the necessary layout tables
55
// are not present.
56
// Currently used by the Mac and FT2 implementations only, but probably should
57
// be supported on Windows as well.
58
const gfxFontEntry::ScriptRange gfxPlatformFontList::sComplexScriptRanges[] = {
59
    // Actually, now that harfbuzz supports presentation-forms shaping for
60
    // Arabic, we can render it without layout tables. So maybe we don't
61
    // want to mask the basic Arabic block here?
62
    // This affects the arabic-fallback-*.html reftests, which rely on
63
    // loading a font that *doesn't* have any GSUB table.
64
    { 0x0600, 0x06FF, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
65
    { 0x0700, 0x074F, { TRUETYPE_TAG('s','y','r','c'), 0, 0 } },
66
    { 0x0750, 0x077F, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
67
    { 0x08A0, 0x08FF, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
68
    { 0x0900, 0x097F, { TRUETYPE_TAG('d','e','v','2'),
69
                        TRUETYPE_TAG('d','e','v','a'), 0 } },
70
    { 0x0980, 0x09FF, { TRUETYPE_TAG('b','n','g','2'),
71
                        TRUETYPE_TAG('b','e','n','g'), 0 } },
72
    { 0x0A00, 0x0A7F, { TRUETYPE_TAG('g','u','r','2'),
73
                        TRUETYPE_TAG('g','u','r','u'), 0 } },
74
    { 0x0A80, 0x0AFF, { TRUETYPE_TAG('g','j','r','2'),
75
                        TRUETYPE_TAG('g','u','j','r'), 0 } },
76
    { 0x0B00, 0x0B7F, { TRUETYPE_TAG('o','r','y','2'),
77
                        TRUETYPE_TAG('o','r','y','a'), 0 } },
78
    { 0x0B80, 0x0BFF, { TRUETYPE_TAG('t','m','l','2'),
79
                        TRUETYPE_TAG('t','a','m','l'), 0 } },
80
    { 0x0C00, 0x0C7F, { TRUETYPE_TAG('t','e','l','2'),
81
                        TRUETYPE_TAG('t','e','l','u'), 0 } },
82
    { 0x0C80, 0x0CFF, { TRUETYPE_TAG('k','n','d','2'),
83
                        TRUETYPE_TAG('k','n','d','a'), 0 } },
84
    { 0x0D00, 0x0D7F, { TRUETYPE_TAG('m','l','m','2'),
85
                        TRUETYPE_TAG('m','l','y','m'), 0 } },
86
    { 0x0D80, 0x0DFF, { TRUETYPE_TAG('s','i','n','h'), 0, 0 } },
87
    { 0x0E80, 0x0EFF, { TRUETYPE_TAG('l','a','o',' '), 0, 0 } },
88
    { 0x0F00, 0x0FFF, { TRUETYPE_TAG('t','i','b','t'), 0, 0 } },
89
    { 0x1000, 0x109f, { TRUETYPE_TAG('m','y','m','r'),
90
                        TRUETYPE_TAG('m','y','m','2'), 0 } },
91
    { 0x1780, 0x17ff, { TRUETYPE_TAG('k','h','m','r'), 0, 0 } },
92
    // Khmer Symbols (19e0..19ff) don't seem to need any special shaping
93
    { 0xaa60, 0xaa7f, { TRUETYPE_TAG('m','y','m','r'),
94
                        TRUETYPE_TAG('m','y','m','2'), 0 } },
95
    // Thai seems to be "renderable" without AAT morphing tables
96
    { 0, 0, { 0, 0, 0 } } // terminator
97
};
98
99
// prefs for the font info loader
100
0
#define FONT_LOADER_DELAY_PREF              "gfx.font_loader.delay"
101
0
#define FONT_LOADER_INTERVAL_PREF           "gfx.font_loader.interval"
102
103
static const char* kObservedPrefs[] = {
104
    "font.",
105
    "font.name-list.",
106
    "intl.accept_languages",  // hmmmm...
107
    nullptr
108
};
109
110
static const char kFontSystemWhitelistPref[] = "font.system.whitelist";
111
112
// xxx - this can probably be eliminated by reworking pref font handling code
113
static const char *gPrefLangNames[] = {
114
    #define FONT_PREF_LANG(enum_id_, str_, atom_id_) str_
115
    #include "gfxFontPrefLangList.h"
116
    #undef FONT_PREF_LANG
117
};
118
119
static_assert(MOZ_ARRAY_LENGTH(gPrefLangNames) == uint32_t(eFontPrefLang_Count),
120
              "size of pref lang name array doesn't match pref lang enum size");
121
122
class gfxFontListPrefObserver final : public nsIObserver {
123
0
    ~gfxFontListPrefObserver() {}
124
public:
125
    NS_DECL_ISUPPORTS
126
    NS_DECL_NSIOBSERVER
127
};
128
129
static void
130
FontListPrefChanged(const char* aPref, void* aData = nullptr)
131
0
{
132
0
    // XXX this could be made to only clear out the cache for the prefs that were changed
133
0
    // but it probably isn't that big a deal.
134
0
    gfxPlatformFontList::PlatformFontList()->ClearLangGroupPrefFonts();
135
0
    gfxFontCache::GetCache()->AgeAllGenerations();
136
0
}
137
138
static gfxFontListPrefObserver* gFontListPrefObserver = nullptr;
139
140
NS_IMPL_ISUPPORTS(gfxFontListPrefObserver, nsIObserver)
141
142
0
#define LOCALES_CHANGED_TOPIC "intl:system-locales-changed"
143
144
NS_IMETHODIMP
145
gfxFontListPrefObserver::Observe(nsISupports     *aSubject,
146
                                 const char      *aTopic,
147
                                 const char16_t *aData)
148
0
{
149
0
    NS_ASSERTION(!strcmp(aTopic, LOCALES_CHANGED_TOPIC), "invalid topic");
150
0
    FontListPrefChanged(nullptr);
151
0
152
0
    if (XRE_IsParentProcess()) {
153
0
        gfxPlatform::ForceGlobalReflow();
154
0
    }
155
0
    return NS_OK;
156
0
}
157
158
MOZ_DEFINE_MALLOC_SIZE_OF(FontListMallocSizeOf)
159
160
NS_IMPL_ISUPPORTS(gfxPlatformFontList::MemoryReporter, nsIMemoryReporter)
161
162
NS_IMETHODIMP
163
gfxPlatformFontList::MemoryReporter::CollectReports(
164
    nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
165
0
{
166
0
    FontListSizes sizes;
167
0
    sizes.mFontListSize = 0;
168
0
    sizes.mFontTableCacheSize = 0;
169
0
    sizes.mCharMapsSize = 0;
170
0
    sizes.mLoaderSize = 0;
171
0
172
0
    gfxPlatformFontList::PlatformFontList()->AddSizeOfIncludingThis(&FontListMallocSizeOf,
173
0
                                                                    &sizes);
174
0
175
0
    MOZ_COLLECT_REPORT(
176
0
        "explicit/gfx/font-list", KIND_HEAP, UNITS_BYTES,
177
0
        sizes.mFontListSize,
178
0
        "Memory used to manage the list of font families and faces.");
179
0
180
0
    MOZ_COLLECT_REPORT(
181
0
        "explicit/gfx/font-charmaps", KIND_HEAP, UNITS_BYTES,
182
0
        sizes.mCharMapsSize,
183
0
        "Memory used to record the character coverage of individual fonts.");
184
0
185
0
    if (sizes.mFontTableCacheSize) {
186
0
        MOZ_COLLECT_REPORT(
187
0
            "explicit/gfx/font-tables", KIND_HEAP, UNITS_BYTES,
188
0
            sizes.mFontTableCacheSize,
189
0
            "Memory used for cached font metrics and layout tables.");
190
0
    }
191
0
192
0
    if (sizes.mLoaderSize) {
193
0
        MOZ_COLLECT_REPORT(
194
0
            "explicit/gfx/font-loader", KIND_HEAP, UNITS_BYTES,
195
0
            sizes.mLoaderSize,
196
0
            "Memory used for (platform-specific) font loader.");
197
0
    }
198
0
199
0
    return NS_OK;
200
0
}
201
202
gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
203
    : mFontFamiliesMutex("gfxPlatformFontList::mFontFamiliesMutex"), mFontFamilies(64),
204
      mOtherFamilyNames(16), mBadUnderlineFamilyNames(8), mSharedCmaps(8),
205
      mStartIndex(0), mNumFamilies(0), mFontlistInitCount(0),
206
      mFontFamilyWhitelistActive(false)
207
0
{
208
0
    mOtherFamilyNamesInitialized = false;
209
0
210
0
    if (aNeedFullnamePostscriptNames) {
211
0
        mExtraNames = MakeUnique<ExtraNames>();
212
0
    }
213
0
    mFaceNameListsInitialized = false;
214
0
215
0
    mLangService = nsLanguageAtomService::GetService();
216
0
217
0
    LoadBadUnderlineList();
218
0
219
0
    // pref changes notification setup
220
0
    NS_ASSERTION(!gFontListPrefObserver,
221
0
                 "There has been font list pref observer already");
222
0
    gFontListPrefObserver = new gfxFontListPrefObserver();
223
0
    NS_ADDREF(gFontListPrefObserver);
224
0
225
0
    Preferences::RegisterPrefixCallbacks(FontListPrefChanged, kObservedPrefs);
226
0
227
0
    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
228
0
    if (obs) {
229
0
        obs->AddObserver(gFontListPrefObserver, LOCALES_CHANGED_TOPIC, false);
230
0
    }
231
0
232
0
    // Only the parent process listens for whitelist changes; it will then
233
0
    // notify its children to rebuild their font lists.
234
0
    if (XRE_IsParentProcess()) {
235
0
        Preferences::RegisterCallback(FontWhitelistPrefChanged,
236
0
                                      kFontSystemWhitelistPref);
237
0
    }
238
0
239
0
    RegisterStrongMemoryReporter(new MemoryReporter());
240
0
}
241
242
gfxPlatformFontList::~gfxPlatformFontList()
243
0
{
244
0
    mSharedCmaps.Clear();
245
0
    ClearLangGroupPrefFonts();
246
0
    NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
247
0
248
0
    Preferences::UnregisterPrefixCallbacks(FontListPrefChanged, kObservedPrefs);
249
0
250
0
    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
251
0
    if (obs) {
252
0
        obs->RemoveObserver(gFontListPrefObserver, LOCALES_CHANGED_TOPIC);
253
0
    }
254
0
255
0
    if (XRE_IsParentProcess()) {
256
0
        Preferences::UnregisterCallback(FontWhitelistPrefChanged,
257
0
                                        kFontSystemWhitelistPref);
258
0
    }
259
0
    NS_RELEASE(gFontListPrefObserver);
260
0
}
261
262
/* static */
263
void
264
gfxPlatformFontList::FontWhitelistPrefChanged(const char *aPref,
265
                                              void *aClosure)
266
0
{
267
0
    MOZ_ASSERT(XRE_IsParentProcess());
268
0
    gfxPlatformFontList::PlatformFontList()->UpdateFontList();
269
0
    mozilla::dom::ContentParent::NotifyUpdatedFonts();
270
0
}
271
272
// number of CSS generic font families
273
const uint32_t kNumGenerics = 5;
274
275
void
276
gfxPlatformFontList::ApplyWhitelist()
277
0
{
278
0
    nsTArray<nsCString> list;
279
0
    gfxFontUtils::GetPrefsFontList(kFontSystemWhitelistPref, list);
280
0
    uint32_t numFonts = list.Length();
281
0
    mFontFamilyWhitelistActive = (numFonts > 0);
282
0
    if (!mFontFamilyWhitelistActive) {
283
0
        return;
284
0
    }
285
0
    nsTHashtable<nsCStringHashKey> familyNamesWhitelist;
286
0
    for (uint32_t i = 0; i < numFonts; i++) {
287
0
        nsAutoCString key;
288
0
        ToLowerCase(list[i], key);
289
0
        familyNamesWhitelist.PutEntry(key);
290
0
    }
291
0
    for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
292
0
        // Don't continue if we only have one font left.
293
0
        if (mFontFamilies.Count() == 1) {
294
0
            break;
295
0
        }
296
0
        nsAutoCString fontFamilyName(iter.Key());
297
0
        ToLowerCase(fontFamilyName);
298
0
        if (!familyNamesWhitelist.Contains(fontFamilyName)) {
299
0
            iter.Remove();
300
0
        }
301
0
    }
302
0
}
303
304
bool
305
gfxPlatformFontList::AddWithLegacyFamilyName(const nsACString& aLegacyName,
306
                                             gfxFontEntry* aFontEntry)
307
0
{
308
0
    bool added = false;
309
0
    nsAutoCString key;
310
0
    ToLowerCase(aLegacyName, key);
311
0
    gfxFontFamily* family = mOtherFamilyNames.GetWeak(key);
312
0
    if (!family) {
313
0
        family = CreateFontFamily(aLegacyName);
314
0
        family->SetHasStyles(true); // we don't want the family to search for
315
0
                                    // faces, we're adding them directly here
316
0
        mOtherFamilyNames.Put(key, family);
317
0
        added = true;
318
0
    }
319
0
    family->AddFontEntry(aFontEntry->Clone());
320
0
    return added;
321
0
}
322
323
nsresult
324
gfxPlatformFontList::InitFontList()
325
0
{
326
0
    mFontlistInitCount++;
327
0
328
0
    if (LOG_FONTINIT_ENABLED()) {
329
0
        LOG_FONTINIT(("(fontinit) system fontlist initialization\n"));
330
0
    }
331
0
332
0
    // rebuilding fontlist so clear out font/word caches
333
0
    gfxFontCache *fontCache = gfxFontCache::GetCache();
334
0
    if (fontCache) {
335
0
        fontCache->AgeAllGenerations();
336
0
        fontCache->FlushShapedWordCaches();
337
0
    }
338
0
339
0
    gfxPlatform::PurgeSkiaFontCache();
340
0
341
0
    CancelInitOtherFamilyNamesTask();
342
0
    MutexAutoLock lock(mFontFamiliesMutex);
343
0
    mFontFamilies.Clear();
344
0
    mOtherFamilyNames.Clear();
345
0
    mOtherFamilyNamesInitialized = false;
346
0
347
0
    if (mExtraNames) {
348
0
        mExtraNames->mFullnames.Clear();
349
0
        mExtraNames->mPostscriptNames.Clear();
350
0
    }
351
0
    mFaceNameListsInitialized = false;
352
0
    ClearLangGroupPrefFonts();
353
0
    mReplacementCharFallbackFamily = nullptr;
354
0
    CancelLoader();
355
0
356
0
    // initialize ranges of characters for which system-wide font search should be skipped
357
0
    mCodepointsWithNoFonts.reset();
358
0
    mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
359
0
    mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
360
0
361
0
    sPlatformFontList = this;
362
0
363
0
    nsresult rv = InitFontListForPlatform();
364
0
    if (NS_FAILED(rv)) {
365
0
        return rv;
366
0
    }
367
0
368
0
    ApplyWhitelist();
369
0
    return NS_OK;
370
0
}
371
372
void
373
gfxPlatformFontList::GenerateFontListKey(const nsACString& aKeyName, nsACString& aResult)
374
0
{
375
0
    aResult = aKeyName;
376
0
    ToLowerCase(aResult);
377
0
}
378
379
0
#define OTHERNAMES_TIMEOUT 200
380
381
void
382
gfxPlatformFontList::InitOtherFamilyNames(bool aDeferOtherFamilyNamesLoading)
383
0
{
384
0
    if (mOtherFamilyNamesInitialized) {
385
0
        return;
386
0
    }
387
0
388
0
    // If the font loader delay has been set to zero, we don't defer loading
389
0
    // additional family names (regardless of the aDefer... parameter), as we
390
0
    // take this to mean availability of font info is to be prioritized over
391
0
    // potential startup perf or main-thread jank.
392
0
    // (This is used so we can reliably run reftests that depend on localized
393
0
    // font-family names being available.)
394
0
    if (aDeferOtherFamilyNamesLoading &&
395
0
        Preferences::GetUint(FONT_LOADER_DELAY_PREF) > 0) {
396
0
        if (!mPendingOtherFamilyNameTask) {
397
0
            RefPtr<mozilla::CancelableRunnable> task = new InitOtherFamilyNamesRunnable();
398
0
            mPendingOtherFamilyNameTask = task;
399
0
            NS_IdleDispatchToCurrentThread(task.forget());
400
0
        }
401
0
    } else {
402
0
        InitOtherFamilyNamesInternal(false);
403
0
    }
404
0
}
405
406
// time limit for loading facename lists (ms)
407
0
#define NAMELIST_TIMEOUT  200
408
409
gfxFontEntry*
410
gfxPlatformFontList::SearchFamiliesForFaceName(const nsACString& aFaceName)
411
0
{
412
0
    TimeStamp start = TimeStamp::Now();
413
0
    bool timedOut = false;
414
0
    // if mFirstChar is not 0, only load facenames for families
415
0
    // that start with this character
416
0
    char16_t firstChar = 0;
417
0
    gfxFontEntry *lookup = nullptr;
418
0
419
0
    // iterate over familes starting with the same letter
420
0
    firstChar = ToLowerCase(aFaceName.CharAt(0));
421
0
422
0
    for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
423
0
        nsCStringHashKey::KeyType key = iter.Key();
424
0
        RefPtr<gfxFontFamily>& family = iter.Data();
425
0
426
0
        // when filtering, skip names that don't start with the filter character
427
0
        if (firstChar && ToLowerCase(key.CharAt(0)) != firstChar) {
428
0
            continue;
429
0
        }
430
0
431
0
        family->ReadFaceNames(this, NeedFullnamePostscriptNames());
432
0
433
0
        TimeDuration elapsed = TimeStamp::Now() - start;
434
0
        if (elapsed.ToMilliseconds() > NAMELIST_TIMEOUT) {
435
0
            timedOut = true;
436
0
            break;
437
0
        }
438
0
    }
439
0
440
0
    lookup = FindFaceName(aFaceName);
441
0
442
0
    TimeStamp end = TimeStamp::Now();
443
0
    Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITFACENAMELISTS,
444
0
                                   start, end);
445
0
    if (LOG_FONTINIT_ENABLED()) {
446
0
        TimeDuration elapsed = end - start;
447
0
        LOG_FONTINIT(("(fontinit) SearchFamiliesForFaceName took %8.2f ms %s %s",
448
0
                      elapsed.ToMilliseconds(),
449
0
                      (lookup ? "found name" : ""),
450
0
                      (timedOut ? "timeout" : "")));
451
0
    }
452
0
453
0
    return lookup;
454
0
}
455
456
gfxFontEntry*
457
gfxPlatformFontList::FindFaceName(const nsACString& aFaceName)
458
0
{
459
0
    gfxFontEntry *lookup;
460
0
461
0
    // lookup in name lookup tables, return null if not found
462
0
    if (mExtraNames &&
463
0
        ((lookup = mExtraNames->mPostscriptNames.GetWeak(aFaceName)) ||
464
0
         (lookup = mExtraNames->mFullnames.GetWeak(aFaceName)))) {
465
0
        return lookup;
466
0
    }
467
0
468
0
    return nullptr;
469
0
}
470
471
gfxFontEntry*
472
gfxPlatformFontList::LookupInFaceNameLists(const nsACString& aFaceName)
473
0
{
474
0
    gfxFontEntry *lookup = nullptr;
475
0
476
0
    // initialize facename lookup tables if needed
477
0
    // note: this can terminate early or time out, in which case
478
0
    //       mFaceNameListsInitialized remains false
479
0
    if (!mFaceNameListsInitialized) {
480
0
        lookup = SearchFamiliesForFaceName(aFaceName);
481
0
        if (lookup) {
482
0
            return lookup;
483
0
        }
484
0
    }
485
0
486
0
    // lookup in name lookup tables, return null if not found
487
0
    if (!(lookup = FindFaceName(aFaceName))) {
488
0
        // names not completely initialized, so keep track of lookup misses
489
0
        if (!mFaceNameListsInitialized) {
490
0
            if (!mFaceNamesMissed) {
491
0
                mFaceNamesMissed = MakeUnique<nsTHashtable<nsCStringHashKey>>(2);
492
0
            }
493
0
            mFaceNamesMissed->PutEntry(aFaceName);
494
0
        }
495
0
    }
496
0
497
0
    return lookup;
498
0
}
499
500
void
501
gfxPlatformFontList::PreloadNamesList()
502
0
{
503
0
    AutoTArray<nsCString, 10> preloadFonts;
504
0
    gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts);
505
0
506
0
    uint32_t numFonts = preloadFonts.Length();
507
0
    for (uint32_t i = 0; i < numFonts; i++) {
508
0
        nsAutoCString key;
509
0
        GenerateFontListKey(preloadFonts[i], key);
510
0
511
0
        // only search canonical names!
512
0
        gfxFontFamily *familyEntry = mFontFamilies.GetWeak(key);
513
0
        if (familyEntry) {
514
0
            familyEntry->ReadOtherFamilyNames(this);
515
0
        }
516
0
    }
517
0
518
0
}
519
520
void
521
gfxPlatformFontList::LoadBadUnderlineList()
522
0
{
523
0
    AutoTArray<nsCString, 10> blacklist;
524
0
    gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
525
0
    uint32_t numFonts = blacklist.Length();
526
0
    for (uint32_t i = 0; i < numFonts; i++) {
527
0
        nsAutoCString key;
528
0
        GenerateFontListKey(blacklist[i], key);
529
0
        mBadUnderlineFamilyNames.PutEntry(key);
530
0
    }
531
0
}
532
533
void
534
gfxPlatformFontList::UpdateFontList()
535
0
{
536
0
    InitFontList();
537
0
    RebuildLocalFonts();
538
0
}
539
540
void
541
gfxPlatformFontList::GetFontList(nsAtom *aLangGroup,
542
                                 const nsACString& aGenericFamily,
543
                                 nsTArray<nsString>& aListOfFonts)
544
0
{
545
0
    MutexAutoLock lock(mFontFamiliesMutex);
546
0
    for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
547
0
        RefPtr<gfxFontFamily>& family = iter.Data();
548
0
        if (family->FilterForFontList(aLangGroup, aGenericFamily)) {
549
0
            nsAutoCString localizedFamilyName;
550
0
            family->LocalizedName(localizedFamilyName);
551
0
            aListOfFonts.AppendElement(NS_ConvertUTF8toUTF16(localizedFamilyName));
552
0
        }
553
0
    }
554
0
555
0
    aListOfFonts.Sort();
556
0
    aListOfFonts.Compact();
557
0
}
558
559
void
560
gfxPlatformFontList::GetFontFamilyList(nsTArray<RefPtr<gfxFontFamily> >& aFamilyArray)
561
0
{
562
0
    for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
563
0
        RefPtr<gfxFontFamily>& family = iter.Data();
564
0
        aFamilyArray.AppendElement(family);
565
0
    }
566
0
}
567
568
gfxFontEntry*
569
gfxPlatformFontList::SystemFindFontForChar(uint32_t aCh, uint32_t aNextCh,
570
                                           Script aRunScript,
571
                                           const gfxFontStyle* aStyle)
572
0
 {
573
0
    gfxFontEntry* fontEntry = nullptr;
574
0
575
0
    // is codepoint with no matching font? return null immediately
576
0
    if (mCodepointsWithNoFonts.test(aCh)) {
577
0
        return nullptr;
578
0
    }
579
0
580
0
    // Try to short-circuit font fallback for U+FFFD, used to represent
581
0
    // encoding errors: just use cached family from last time U+FFFD was seen.
582
0
    // This helps speed up pages with lots of encoding errors, binary-as-text,
583
0
    // etc.
584
0
    if (aCh == 0xFFFD && mReplacementCharFallbackFamily) {
585
0
        fontEntry =
586
0
            mReplacementCharFallbackFamily->FindFontForStyle(*aStyle);
587
0
588
0
        // this should never fail, as we must have found U+FFFD in order to set
589
0
        // mReplacementCharFallbackFamily at all, but better play it safe
590
0
        if (fontEntry && fontEntry->HasCharacter(aCh)) {
591
0
            return fontEntry;
592
0
        }
593
0
    }
594
0
595
0
    TimeStamp start = TimeStamp::Now();
596
0
597
0
    // search commonly available fonts
598
0
    bool common = true;
599
0
    gfxFontFamily *fallbackFamily = nullptr;
600
0
    fontEntry = CommonFontFallback(aCh, aNextCh, aRunScript, aStyle,
601
0
                                   &fallbackFamily);
602
0
 
603
0
    // if didn't find a font, do system-wide fallback (except for specials)
604
0
    uint32_t cmapCount = 0;
605
0
    if (!fontEntry) {
606
0
        common = false;
607
0
        fontEntry = GlobalFontFallback(aCh, aRunScript, aStyle, cmapCount,
608
0
                                       &fallbackFamily);
609
0
    }
610
0
    TimeDuration elapsed = TimeStamp::Now() - start;
611
0
612
0
    LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
613
0
614
0
    if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Warning))) {
615
0
        uint32_t unicodeRange = FindCharUnicodeRange(aCh);
616
0
        Script script = mozilla::unicode::GetScriptCode(aCh);
617
0
        MOZ_LOG(log, LogLevel::Warning,\
618
0
               ("(textrun-systemfallback-%s) char: u+%6.6x "
619
0
                 "unicode-range: %d script: %d match: [%s]"
620
0
                " time: %dus cmaps: %d\n",
621
0
                (common ? "common" : "global"), aCh,
622
0
                unicodeRange, static_cast<int>(script),
623
0
                (fontEntry ? fontEntry->Name().get() :
624
0
                    "<none>"),
625
0
                int32_t(elapsed.ToMicroseconds()),
626
0
                cmapCount));
627
0
    }
628
0
629
0
    // no match? add to set of non-matching codepoints
630
0
    if (!fontEntry) {
631
0
        mCodepointsWithNoFonts.set(aCh);
632
0
    } else if (aCh == 0xFFFD && fontEntry && fallbackFamily) {
633
0
        mReplacementCharFallbackFamily = fallbackFamily;
634
0
    }
635
0
 
636
0
    // track system fallback time
637
0
    static bool first = true;
638
0
    int32_t intElapsed = int32_t(first ? elapsed.ToMilliseconds() :
639
0
                                         elapsed.ToMicroseconds());
640
0
    Telemetry::Accumulate((first ? Telemetry::SYSTEM_FONT_FALLBACK_FIRST :
641
0
                                   Telemetry::SYSTEM_FONT_FALLBACK),
642
0
                          intElapsed);
643
0
    first = false;
644
0
645
0
    // track the script for which fallback occurred (incremented one make it
646
0
    // 1-based)
647
0
    Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT,
648
0
                          int(aRunScript) + 1);
649
0
650
0
    return fontEntry;
651
0
}
652
653
#define NUM_FALLBACK_FONTS        8
654
655
gfxFontEntry*
656
gfxPlatformFontList::CommonFontFallback(uint32_t aCh, uint32_t aNextCh,
657
                                        Script aRunScript,
658
                                        const gfxFontStyle* aMatchStyle,
659
                                        gfxFontFamily** aMatchedFamily)
660
0
{
661
0
    AutoTArray<const char*,NUM_FALLBACK_FONTS> defaultFallbacks;
662
0
    uint32_t i, numFallbacks;
663
0
664
0
    gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh, aNextCh,
665
0
                                                       aRunScript,
666
0
                                                       defaultFallbacks);
667
0
    numFallbacks = defaultFallbacks.Length();
668
0
    for (i = 0; i < numFallbacks; i++) {
669
0
        nsAutoCString familyName(defaultFallbacks[i]);
670
0
        gfxFontFamily *fallback = FindFamilyByCanonicalName(familyName);
671
0
        if (!fallback) {
672
0
            continue;
673
0
        }
674
0
675
0
        gfxFontEntry *fontEntry;
676
0
677
0
        // use first font in list that supports a given character
678
0
        fontEntry = fallback->FindFontForStyle(*aMatchStyle);
679
0
        if (fontEntry) {
680
0
            if (fontEntry->HasCharacter(aCh)) {
681
0
                *aMatchedFamily = fallback;
682
0
                return fontEntry;
683
0
            }
684
0
            // If we requested a styled font (bold and/or italic), and the char
685
0
            // was not available, check other faces of the family.
686
0
            if (!fontEntry->IsNormalStyle()) {
687
0
                // If style/weight/stretch was not Normal, see if we can
688
0
                // fall back to a next-best face (e.g. Arial Black -> Bold,
689
0
                // or Arial Narrow -> Regular).
690
0
                GlobalFontMatch data(aCh, *aMatchStyle);
691
0
                fallback->SearchAllFontsForChar(&data);
692
0
                if (data.mBestMatch) {
693
0
                    *aMatchedFamily = fallback;
694
0
                    return data.mBestMatch;
695
0
                }
696
0
            }
697
0
        }
698
0
    }
699
0
700
0
    return nullptr;
701
0
}
702
703
gfxFontEntry*
704
gfxPlatformFontList::GlobalFontFallback(const uint32_t aCh,
705
                                        Script aRunScript,
706
                                        const gfxFontStyle* aMatchStyle,
707
                                        uint32_t& aCmapCount,
708
                                        gfxFontFamily** aMatchedFamily)
709
0
{
710
0
    bool useCmaps = IsFontFamilyWhitelistActive() ||
711
0
                    gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
712
0
    if (!useCmaps) {
713
0
        // Allow platform-specific fallback code to try and find a usable font
714
0
        gfxFontEntry* fe =
715
0
            PlatformGlobalFontFallback(aCh, aRunScript, aMatchStyle,
716
0
                                       aMatchedFamily);
717
0
        if (fe) {
718
0
            return fe;
719
0
        }
720
0
    }
721
0
722
0
    // otherwise, try to find it among local fonts
723
0
    GlobalFontMatch data(aCh, *aMatchStyle);
724
0
725
0
    // iterate over all font families to find a font that support the character
726
0
    for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
727
0
      RefPtr<gfxFontFamily>& family = iter.Data();
728
0
      // evaluate all fonts in this family for a match
729
0
      family->FindFontForChar(&data);
730
0
    }
731
0
732
0
    aCmapCount = data.mCmapsTested;
733
0
    *aMatchedFamily = data.mMatchedFamily;
734
0
735
0
    return data.mBestMatch;
736
0
}
737
738
gfxFontFamily*
739
gfxPlatformFontList::CheckFamily(gfxFontFamily *aFamily)
740
0
{
741
0
    if (aFamily && !aFamily->HasStyles()) {
742
0
        aFamily->FindStyleVariations();
743
0
        aFamily->CheckForSimpleFamily();
744
0
    }
745
0
746
0
    if (aFamily && aFamily->GetFontList().Length() == 0) {
747
0
        // failed to load any faces for this family, so discard it
748
0
        nsAutoCString key;
749
0
        GenerateFontListKey(aFamily->Name(), key);
750
0
        mFontFamilies.Remove(key);
751
0
        return nullptr;
752
0
    }
753
0
754
0
    return aFamily;
755
0
}
756
757
bool
758
gfxPlatformFontList::FindAndAddFamilies(const nsACString& aFamily,
759
                                        nsTArray<FamilyAndGeneric>* aOutput,
760
                                        FindFamiliesFlags aFlags,
761
                                        gfxFontStyle* aStyle,
762
                                        gfxFloat aDevToCssSize)
763
0
{
764
0
    nsAutoCString key;
765
0
    GenerateFontListKey(aFamily, key);
766
0
767
0
    NS_ASSERTION(mFontFamilies.Count() != 0, "system font list was not initialized correctly");
768
0
769
0
    // lookup in canonical (i.e. English) family name list
770
0
    gfxFontFamily *familyEntry = mFontFamilies.GetWeak(key);
771
0
772
0
    // if not found, lookup in other family names list (mostly localized names)
773
0
    if (!familyEntry) {
774
0
        familyEntry = mOtherFamilyNames.GetWeak(key);
775
0
    }
776
0
777
0
    // if still not found and other family names not yet fully initialized,
778
0
    // initialize the rest of the list and try again.  this is done lazily
779
0
    // since reading name table entries is expensive.
780
0
    // although ASCII localized family names are possible they don't occur
781
0
    // in practice so avoid pulling in names at startup
782
0
    if (!familyEntry && !mOtherFamilyNamesInitialized && !IsASCII(aFamily)) {
783
0
        InitOtherFamilyNames(!(aFlags & FindFamiliesFlags::eForceOtherFamilyNamesLoading));
784
0
        familyEntry = mOtherFamilyNames.GetWeak(key);
785
0
        if (!familyEntry && !mOtherFamilyNamesInitialized &&
786
0
            !(aFlags & FindFamiliesFlags::eNoAddToNamesMissedWhenSearching)) {
787
0
            // localized family names load timed out, add name to list of
788
0
            // names to check after localized names are loaded
789
0
            if (!mOtherNamesMissed) {
790
0
                mOtherNamesMissed = MakeUnique<nsTHashtable<nsCStringHashKey>>(2);
791
0
            }
792
0
            mOtherNamesMissed->PutEntry(key);
793
0
        }
794
0
    }
795
0
796
0
    familyEntry = CheckFamily(familyEntry);
797
0
798
0
    // If we failed to find the requested family, check for a space in the
799
0
    // name; if found, and if the "base" name (up to the last space) exists
800
0
    // as a family, then this might be a legacy GDI-style family name for
801
0
    // an additional weight/width. Try searching the faces of the base family
802
0
    // and create any corresponding legacy families.
803
0
    if (!familyEntry && !(aFlags & FindFamiliesFlags::eNoSearchForLegacyFamilyNames)) {
804
0
        // We don't have nsAString::RFindChar, so look for a space manually
805
0
        const char* data = aFamily.BeginReading();
806
0
        int32_t index = aFamily.Length();
807
0
        while (--index > 0) {
808
0
            if (data[index] == ' ') {
809
0
                break;
810
0
            }
811
0
        }
812
0
        if (index > 0) {
813
0
            gfxFontFamily* base =
814
0
                FindFamily(Substring(aFamily, 0, index),
815
0
                           FindFamiliesFlags::eNoSearchForLegacyFamilyNames);
816
0
            // If we found the "base" family name, and if it has members with
817
0
            // legacy names, this will add corresponding font-family entries to
818
0
            // the mOtherFamilyNames list; then retry the legacy-family search.
819
0
            if (base && base->CheckForLegacyFamilyNames(this)) {
820
0
                familyEntry = mOtherFamilyNames.GetWeak(key);
821
0
            }
822
0
        }
823
0
    }
824
0
825
0
    if (familyEntry) {
826
0
        aOutput->AppendElement(FamilyAndGeneric(familyEntry));
827
0
        return true;
828
0
    }
829
0
830
0
    return false;
831
0
}
832
833
gfxFontEntry*
834
gfxPlatformFontList::FindFontForFamily(const nsACString& aFamily,
835
                                       const gfxFontStyle* aStyle)
836
0
{
837
0
    gfxFontFamily *familyEntry = FindFamily(aFamily);
838
0
839
0
    if (familyEntry)
840
0
        return familyEntry->FindFontForStyle(*aStyle);
841
0
842
0
    return nullptr;
843
0
}
844
845
void 
846
gfxPlatformFontList::AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsCString& aOtherFamilyName)
847
0
{
848
0
    nsAutoCString key;
849
0
    GenerateFontListKey(aOtherFamilyName, key);
850
0
851
0
    if (!mOtherFamilyNames.GetWeak(key)) {
852
0
        mOtherFamilyNames.Put(key, aFamilyEntry);
853
0
        LOG_FONTLIST(("(fontlist-otherfamily) canonical family: %s, "
854
0
                      "other family: %s\n",
855
0
                      aFamilyEntry->Name().get(),
856
0
                      aOtherFamilyName.get()));
857
0
        if (mBadUnderlineFamilyNames.Contains(key))
858
0
            aFamilyEntry->SetBadUnderlineFamily();
859
0
    }
860
0
}
861
862
void
863
gfxPlatformFontList::AddFullname(gfxFontEntry *aFontEntry, const nsCString& aFullname)
864
0
{
865
0
    if (!mExtraNames->mFullnames.GetWeak(aFullname)) {
866
0
        mExtraNames->mFullnames.Put(aFullname, aFontEntry);
867
0
        LOG_FONTLIST(("(fontlist-fullname) name: %s, fullname: %s\n",
868
0
                      aFontEntry->Name().get(),
869
0
                      aFullname.get()));
870
0
    }
871
0
}
872
873
void
874
gfxPlatformFontList::AddPostscriptName(gfxFontEntry *aFontEntry,
875
                                       const nsCString& aPostscriptName)
876
0
{
877
0
    if (!mExtraNames->mPostscriptNames.GetWeak(aPostscriptName)) {
878
0
        mExtraNames->mPostscriptNames.Put(aPostscriptName, aFontEntry);
879
0
        LOG_FONTLIST(("(fontlist-postscript) name: %s, psname: %s\n",
880
0
                      aFontEntry->Name().get(),
881
0
                      aPostscriptName.get()));
882
0
    }
883
0
}
884
885
bool
886
gfxPlatformFontList::GetStandardFamilyName(const nsCString& aFontName,
887
                                           nsACString& aFamilyName)
888
0
{
889
0
    aFamilyName.Truncate();
890
0
    gfxFontFamily *ff = FindFamily(aFontName);
891
0
    if (!ff) {
892
0
        return false;
893
0
    }
894
0
    aFamilyName = ff->Name();
895
0
    return true;
896
0
}
897
898
gfxFontFamily*
899
gfxPlatformFontList::GetDefaultFontFamily(const nsACString& aLangGroup,
900
                                          const nsACString& aGenericFamily)
901
0
{
902
0
    if (NS_WARN_IF(aLangGroup.IsEmpty()) ||
903
0
        NS_WARN_IF(aGenericFamily.IsEmpty())) {
904
0
        return nullptr;
905
0
    }
906
0
907
0
    AutoTArray<nsCString,4> names;
908
0
    gfxFontUtils::AppendPrefsFontList(
909
0
        NameListPref(aGenericFamily, aLangGroup).get(), names);
910
0
911
0
    for (const nsCString& name : names) {
912
0
        gfxFontFamily* fontFamily = FindFamily(name);
913
0
        if (fontFamily) {
914
0
            return fontFamily;
915
0
        }
916
0
    }
917
0
    return nullptr;
918
0
}
919
920
gfxCharacterMap*
921
gfxPlatformFontList::FindCharMap(gfxCharacterMap *aCmap)
922
0
{
923
0
    aCmap->CalcHash();
924
0
    gfxCharacterMap *cmap = AddCmap(aCmap);
925
0
    cmap->mShared = true;
926
0
    return cmap;
927
0
}
928
929
// add a cmap to the shared cmap set
930
gfxCharacterMap*
931
gfxPlatformFontList::AddCmap(const gfxCharacterMap* aCharMap)
932
0
{
933
0
    CharMapHashKey *found =
934
0
        mSharedCmaps.PutEntry(const_cast<gfxCharacterMap*>(aCharMap));
935
0
    return found->GetKey();
936
0
}
937
938
// remove the cmap from the shared cmap set
939
void
940
gfxPlatformFontList::RemoveCmap(const gfxCharacterMap* aCharMap)
941
0
{
942
0
    // skip lookups during teardown
943
0
    if (mSharedCmaps.Count() == 0) {
944
0
        return;
945
0
    }
946
0
947
0
    // cmap needs to match the entry *and* be the same ptr before removing
948
0
    CharMapHashKey *found =
949
0
        mSharedCmaps.GetEntry(const_cast<gfxCharacterMap*>(aCharMap));
950
0
    if (found && found->GetKey() == aCharMap) {
951
0
        mSharedCmaps.RemoveEntry(found);
952
0
    }
953
0
}
954
955
void
956
gfxPlatformFontList::ResolveGenericFontNames(
957
    FontFamilyType aGenericType,
958
    eFontPrefLang aPrefLang,
959
    nsTArray<RefPtr<gfxFontFamily>>* aGenericFamilies)
960
0
{
961
0
    const char* langGroupStr = GetPrefLangName(aPrefLang);
962
0
    const char* generic = GetGenericName(aGenericType);
963
0
964
0
    if (!generic) {
965
0
        return;
966
0
    }
967
0
968
0
    AutoTArray<nsCString,4> genericFamilies;
969
0
970
0
    // load family for "font.name.generic.lang"
971
0
    gfxFontUtils::AppendPrefsFontList(
972
0
        NamePref(generic, langGroupStr).get(), genericFamilies);
973
0
974
0
    // load fonts for "font.name-list.generic.lang"
975
0
    gfxFontUtils::AppendPrefsFontList(
976
0
        NameListPref(generic, langGroupStr).get(), genericFamilies);
977
0
978
0
    nsAtom* langGroup = GetLangGroupForPrefLang(aPrefLang);
979
0
    NS_ASSERTION(langGroup, "null lang group for pref lang");
980
0
981
0
    gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(genericFamilies,
982
0
                                                           langGroup,
983
0
                                                           aGenericFamilies);
984
0
985
#if 0  // dump out generic mappings
986
    printf("%s ===> ", prefFontName.get());
987
    for (uint32_t k = 0; k < aGenericFamilies->Length(); k++) {
988
        if (k > 0) printf(", ");
989
        printf("%s", aGenericFamilies[k]->Name().get());
990
    }
991
    printf("\n");
992
#endif
993
}
994
995
void
996
gfxPlatformFontList::ResolveEmojiFontNames(
997
    nsTArray<RefPtr<gfxFontFamily>>* aGenericFamilies)
998
0
{
999
0
    // emoji preference has no lang name
1000
0
    AutoTArray<nsCString,4> genericFamilies;
1001
0
1002
0
    nsAutoCString prefFontListName("font.name-list.emoji");
1003
0
    gfxFontUtils::AppendPrefsFontList(prefFontListName.get(), genericFamilies);
1004
0
1005
0
    gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(genericFamilies,
1006
0
                                                            nullptr,
1007
0
                                                            aGenericFamilies);
1008
0
}
1009
1010
void
1011
gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(
1012
    nsTArray<nsCString>& aGenericNameFamilies,
1013
    nsAtom* aLangGroup,
1014
    nsTArray<RefPtr<gfxFontFamily>>* aGenericFamilies)
1015
0
{
1016
0
    // lookup and add platform fonts uniquely
1017
0
    for (const nsCString& genericFamily : aGenericNameFamilies) {
1018
0
        gfxFontStyle style;
1019
0
        style.language = aLangGroup;
1020
0
        style.systemFont = false;
1021
0
        AutoTArray<FamilyAndGeneric,10> families;
1022
0
        FindAndAddFamilies(genericFamily,
1023
0
                           &families, FindFamiliesFlags(0),
1024
0
                           &style);
1025
0
        for (const FamilyAndGeneric& f : families) {
1026
0
            if (!aGenericFamilies->Contains(f.mFamily)) {
1027
0
                aGenericFamilies->AppendElement(f.mFamily);
1028
0
            }
1029
0
        }
1030
0
    }
1031
0
}
1032
1033
nsTArray<RefPtr<gfxFontFamily>>*
1034
gfxPlatformFontList::GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType,
1035
                                           eFontPrefLang aPrefLang)
1036
0
{
1037
0
    // treat -moz-fixed as monospace
1038
0
    if (aGenericType == eFamily_moz_fixed) {
1039
0
        aGenericType = eFamily_monospace;
1040
0
    }
1041
0
1042
0
    if (aGenericType == eFamily_moz_emoji) {
1043
0
        // Emoji font has no lang
1044
0
        PrefFontList* prefFonts = mEmojiPrefFont.get();
1045
0
        if (MOZ_UNLIKELY(!prefFonts)) {
1046
0
            prefFonts = new PrefFontList;
1047
0
            ResolveEmojiFontNames(prefFonts);
1048
0
            mEmojiPrefFont.reset(prefFonts);
1049
0
        }
1050
0
        return prefFonts;
1051
0
    }
1052
0
1053
0
    PrefFontList* prefFonts =
1054
0
        mLangGroupPrefFonts[aPrefLang][aGenericType].get();
1055
0
    if (MOZ_UNLIKELY(!prefFonts)) {
1056
0
        prefFonts = new PrefFontList;
1057
0
        ResolveGenericFontNames(aGenericType, aPrefLang, prefFonts);
1058
0
        mLangGroupPrefFonts[aPrefLang][aGenericType].reset(prefFonts);
1059
0
    }
1060
0
    return prefFonts;
1061
0
}
1062
1063
void
1064
gfxPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType,
1065
                                     nsAtom* aLanguage,
1066
                                     nsTArray<FamilyAndGeneric>& aFamilyList)
1067
0
{
1068
0
    // map lang ==> langGroup
1069
0
    nsAtom* langGroup = GetLangGroup(aLanguage);
1070
0
1071
0
    // langGroup ==> prefLang
1072
0
    eFontPrefLang prefLang = GetFontPrefLangFor(langGroup);
1073
0
1074
0
    // lookup pref fonts
1075
0
    nsTArray<RefPtr<gfxFontFamily>>* prefFonts =
1076
0
        GetPrefFontsLangGroup(aGenericType, prefLang);
1077
0
1078
0
    if (!prefFonts->IsEmpty()) {
1079
0
        aFamilyList.SetCapacity(aFamilyList.Length() + prefFonts->Length());
1080
0
        for (auto& f : *prefFonts) {
1081
0
            aFamilyList.AppendElement(FamilyAndGeneric(f.get(), aGenericType));
1082
0
        }
1083
0
    }
1084
0
}
1085
1086
static nsAtom* PrefLangToLangGroups(uint32_t aIndex)
1087
0
{
1088
0
    // static array here avoids static constructor
1089
0
    static nsAtom* gPrefLangToLangGroups[] = {
1090
0
        #define FONT_PREF_LANG(enum_id_, str_, atom_id_) nsGkAtoms::atom_id_
1091
0
        #include "gfxFontPrefLangList.h"
1092
0
        #undef FONT_PREF_LANG
1093
0
    };
1094
0
1095
0
    return aIndex < ArrayLength(gPrefLangToLangGroups)
1096
0
         ? gPrefLangToLangGroups[aIndex]
1097
0
         : nsGkAtoms::Unicode;
1098
0
}
1099
1100
eFontPrefLang
1101
gfxPlatformFontList::GetFontPrefLangFor(const char* aLang)
1102
0
{
1103
0
    if (!aLang || !aLang[0]) {
1104
0
        return eFontPrefLang_Others;
1105
0
    }
1106
0
    for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); ++i) {
1107
0
        if (!PL_strcasecmp(gPrefLangNames[i], aLang)) {
1108
0
            return eFontPrefLang(i);
1109
0
        }
1110
0
    }
1111
0
    return eFontPrefLang_Others;
1112
0
}
1113
1114
eFontPrefLang
1115
gfxPlatformFontList::GetFontPrefLangFor(nsAtom *aLang)
1116
0
{
1117
0
    if (!aLang)
1118
0
        return eFontPrefLang_Others;
1119
0
    nsAutoCString lang;
1120
0
    aLang->ToUTF8String(lang);
1121
0
    return GetFontPrefLangFor(lang.get());
1122
0
}
1123
1124
nsAtom*
1125
gfxPlatformFontList::GetLangGroupForPrefLang(eFontPrefLang aLang)
1126
0
{
1127
0
    // the special CJK set pref lang should be resolved into separate
1128
0
    // calls to individual CJK pref langs before getting here
1129
0
    NS_ASSERTION(aLang != eFontPrefLang_CJKSet, "unresolved CJK set pref lang");
1130
0
1131
0
    return PrefLangToLangGroups(uint32_t(aLang));
1132
0
}
1133
1134
const char*
1135
gfxPlatformFontList::GetPrefLangName(eFontPrefLang aLang)
1136
0
{
1137
0
    if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) {
1138
0
        return gPrefLangNames[uint32_t(aLang)];
1139
0
    }
1140
0
    return nullptr;
1141
0
}
1142
1143
eFontPrefLang
1144
gfxPlatformFontList::GetFontPrefLangFor(uint8_t aUnicodeRange)
1145
{
1146
    switch (aUnicodeRange) {
1147
        case kRangeSetLatin:   return eFontPrefLang_Western;
1148
        case kRangeCyrillic:   return eFontPrefLang_Cyrillic;
1149
        case kRangeGreek:      return eFontPrefLang_Greek;
1150
        case kRangeHebrew:     return eFontPrefLang_Hebrew;
1151
        case kRangeArabic:     return eFontPrefLang_Arabic;
1152
        case kRangeThai:       return eFontPrefLang_Thai;
1153
        case kRangeKorean:     return eFontPrefLang_Korean;
1154
        case kRangeJapanese:   return eFontPrefLang_Japanese;
1155
        case kRangeSChinese:   return eFontPrefLang_ChineseCN;
1156
        case kRangeTChinese:   return eFontPrefLang_ChineseTW;
1157
        case kRangeDevanagari: return eFontPrefLang_Devanagari;
1158
        case kRangeTamil:      return eFontPrefLang_Tamil;
1159
        case kRangeArmenian:   return eFontPrefLang_Armenian;
1160
        case kRangeBengali:    return eFontPrefLang_Bengali;
1161
        case kRangeCanadian:   return eFontPrefLang_Canadian;
1162
        case kRangeEthiopic:   return eFontPrefLang_Ethiopic;
1163
        case kRangeGeorgian:   return eFontPrefLang_Georgian;
1164
        case kRangeGujarati:   return eFontPrefLang_Gujarati;
1165
        case kRangeGurmukhi:   return eFontPrefLang_Gurmukhi;
1166
        case kRangeKhmer:      return eFontPrefLang_Khmer;
1167
        case kRangeMalayalam:  return eFontPrefLang_Malayalam;
1168
        case kRangeOriya:      return eFontPrefLang_Oriya;
1169
        case kRangeTelugu:     return eFontPrefLang_Telugu;
1170
        case kRangeKannada:    return eFontPrefLang_Kannada;
1171
        case kRangeSinhala:    return eFontPrefLang_Sinhala;
1172
        case kRangeTibetan:    return eFontPrefLang_Tibetan;
1173
        case kRangeSetCJK:     return eFontPrefLang_CJKSet;
1174
        default:               return eFontPrefLang_Others;
1175
    }
1176
}
1177
1178
bool
1179
gfxPlatformFontList::IsLangCJK(eFontPrefLang aLang)
1180
{
1181
    switch (aLang) {
1182
        case eFontPrefLang_Japanese:
1183
        case eFontPrefLang_ChineseTW:
1184
        case eFontPrefLang_ChineseCN:
1185
        case eFontPrefLang_ChineseHK:
1186
        case eFontPrefLang_Korean:
1187
        case eFontPrefLang_CJKSet:
1188
            return true;
1189
        default:
1190
            return false;
1191
    }
1192
}
1193
1194
void
1195
gfxPlatformFontList::GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
1196
0
{
1197
0
    if (IsLangCJK(aCharLang)) {
1198
0
        AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang);
1199
0
    } else {
1200
0
        AppendPrefLang(aPrefLangs, aLen, aCharLang);
1201
0
    }
1202
0
1203
0
    AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others);
1204
0
}
1205
1206
void
1207
gfxPlatformFontList::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
1208
0
{
1209
0
    // prefer the lang specified by the page *if* CJK
1210
0
    if (IsLangCJK(aPageLang)) {
1211
0
        AppendPrefLang(aPrefLangs, aLen, aPageLang);
1212
0
    }
1213
0
1214
0
    // if not set up, set up the default CJK order, based on accept lang settings and locale
1215
0
    if (mCJKPrefLangs.Length() == 0) {
1216
0
1217
0
        // temp array
1218
0
        eFontPrefLang tempPrefLangs[kMaxLenPrefLangList];
1219
0
        uint32_t tempLen = 0;
1220
0
1221
0
        // Add the CJK pref fonts from accept languages, the order should be same order
1222
0
        nsAutoCString list;
1223
0
        Preferences::GetLocalizedCString("intl.accept_languages", list);
1224
0
        if (!list.IsEmpty()) {
1225
0
            const char kComma = ',';
1226
0
            const char *p, *p_end;
1227
0
            list.BeginReading(p);
1228
0
            list.EndReading(p_end);
1229
0
            while (p < p_end) {
1230
0
                while (nsCRT::IsAsciiSpace(*p)) {
1231
0
                    if (++p == p_end)
1232
0
                        break;
1233
0
                }
1234
0
                if (p == p_end)
1235
0
                    break;
1236
0
                const char *start = p;
1237
0
                while (++p != p_end && *p != kComma)
1238
0
                    /* nothing */ ;
1239
0
                nsAutoCString lang(Substring(start, p));
1240
0
                lang.CompressWhitespace(false, true);
1241
0
                eFontPrefLang fpl = gfxPlatformFontList::GetFontPrefLangFor(lang.get());
1242
0
                switch (fpl) {
1243
0
                    case eFontPrefLang_Japanese:
1244
0
                    case eFontPrefLang_Korean:
1245
0
                    case eFontPrefLang_ChineseCN:
1246
0
                    case eFontPrefLang_ChineseHK:
1247
0
                    case eFontPrefLang_ChineseTW:
1248
0
                        AppendPrefLang(tempPrefLangs, tempLen, fpl);
1249
0
                        break;
1250
0
                    default:
1251
0
                        break;
1252
0
                }
1253
0
                p++;
1254
0
            }
1255
0
        }
1256
0
1257
0
        // Try using app's locale
1258
0
        nsAutoCString localeStr;
1259
0
        LocaleService::GetInstance()->GetAppLocaleAsLangTag(localeStr);
1260
0
1261
0
        {
1262
0
          Locale locale(localeStr);
1263
0
          if (locale.GetLanguage().Equals("ja")) {
1264
0
              AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
1265
0
          } else if (locale.GetLanguage().Equals("zh")) {
1266
0
              if (locale.GetRegion().Equals("CN")) {
1267
0
                  AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
1268
0
              } else if (locale.GetRegion().Equals("TW")) {
1269
0
                  AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
1270
0
              } else if (locale.GetRegion().Equals("HK")) {
1271
0
                  AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
1272
0
              }
1273
0
          } else if (locale.GetLanguage().Equals("ko")) {
1274
0
              AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
1275
0
          }
1276
0
        }
1277
0
1278
0
        // Then add the known CJK prefs in order of system preferred locales
1279
0
        AutoTArray<nsCString,5> prefLocales;
1280
0
        prefLocales.AppendElement(NS_LITERAL_CSTRING("ja"));
1281
0
        prefLocales.AppendElement(NS_LITERAL_CSTRING("zh-CN"));
1282
0
        prefLocales.AppendElement(NS_LITERAL_CSTRING("zh-TW"));
1283
0
        prefLocales.AppendElement(NS_LITERAL_CSTRING("zh-HK"));
1284
0
        prefLocales.AppendElement(NS_LITERAL_CSTRING("ko"));
1285
0
1286
0
        AutoTArray<nsCString,16> sysLocales;
1287
0
        AutoTArray<nsCString,16> negLocales;
1288
0
        if (NS_SUCCEEDED(OSPreferences::GetInstance()->GetSystemLocales(sysLocales))) {
1289
0
            LocaleService::GetInstance()->NegotiateLanguages(
1290
0
                sysLocales, prefLocales, NS_LITERAL_CSTRING(""),
1291
0
                LocaleService::kLangNegStrategyFiltering, negLocales);
1292
0
            for (const auto& localeStr : negLocales) {
1293
0
                Locale locale(localeStr);
1294
0
1295
0
                if (locale.GetLanguage().Equals("ja")) {
1296
0
                    AppendPrefLang(tempPrefLangs, tempLen,
1297
0
                                   eFontPrefLang_Japanese);
1298
0
                } else if (locale.GetLanguage().Equals("zh")) {
1299
0
                    if (locale.GetRegion().Equals("CN")) {
1300
0
                        AppendPrefLang(tempPrefLangs, tempLen,
1301
0
                                       eFontPrefLang_ChineseCN);
1302
0
                    } else if (locale.GetRegion().Equals("TW")) {
1303
0
                        AppendPrefLang(tempPrefLangs, tempLen,
1304
0
                                       eFontPrefLang_ChineseTW);
1305
0
                    } else if (locale.GetRegion().Equals("HK")) {
1306
0
                        AppendPrefLang(tempPrefLangs, tempLen,
1307
0
                                       eFontPrefLang_ChineseHK);
1308
0
                    }
1309
0
                } else if (locale.GetLanguage().Equals("ko")) {
1310
0
                    AppendPrefLang(tempPrefLangs, tempLen,
1311
0
                                   eFontPrefLang_Korean);
1312
0
                }
1313
0
            }
1314
0
        }
1315
0
1316
0
        // last resort... (the order is same as old gfx.)
1317
0
        AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
1318
0
        AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
1319
0
        AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
1320
0
        AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
1321
0
        AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
1322
0
1323
0
        // copy into the cached array
1324
0
        uint32_t j;
1325
0
        for (j = 0; j < tempLen; j++) {
1326
0
            mCJKPrefLangs.AppendElement(tempPrefLangs[j]);
1327
0
        }
1328
0
    }
1329
0
1330
0
    // append in cached CJK langs
1331
0
    uint32_t  i, numCJKlangs = mCJKPrefLangs.Length();
1332
0
1333
0
    for (i = 0; i < numCJKlangs; i++) {
1334
0
        AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i]));
1335
0
    }
1336
0
1337
0
}
1338
1339
void
1340
gfxPlatformFontList::AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang)
1341
0
{
1342
0
    if (aLen >= kMaxLenPrefLangList) return;
1343
0
1344
0
    // make sure
1345
0
    uint32_t  i = 0;
1346
0
    while (i < aLen && aPrefLangs[i] != aAddLang) {
1347
0
        i++;
1348
0
    }
1349
0
1350
0
    if (i == aLen) {
1351
0
        aPrefLangs[aLen] = aAddLang;
1352
0
        aLen++;
1353
0
    }
1354
0
}
1355
1356
mozilla::FontFamilyType
1357
gfxPlatformFontList::GetDefaultGeneric(eFontPrefLang aLang)
1358
0
{
1359
0
    if (aLang == eFontPrefLang_Emoji) {
1360
0
      return eFamily_moz_emoji;
1361
0
    }
1362
0
1363
0
    // initialize lang group pref font defaults (i.e. serif/sans-serif)
1364
0
    if (MOZ_UNLIKELY(mDefaultGenericsLangGroup.IsEmpty())) {
1365
0
        mDefaultGenericsLangGroup.AppendElements(ArrayLength(gPrefLangNames));
1366
0
        for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); i++) {
1367
0
            nsAutoCString prefDefaultFontType("font.default.");
1368
0
            prefDefaultFontType.Append(GetPrefLangName(eFontPrefLang(i)));
1369
0
            nsAutoCString serifOrSans;
1370
0
            Preferences::GetCString(prefDefaultFontType.get(), serifOrSans);
1371
0
            if (serifOrSans.EqualsLiteral("sans-serif")) {
1372
0
                mDefaultGenericsLangGroup[i] = eFamily_sans_serif;
1373
0
            } else {
1374
0
                mDefaultGenericsLangGroup[i] = eFamily_serif;
1375
0
            }
1376
0
        }
1377
0
    }
1378
0
1379
0
    if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) {
1380
0
        return mDefaultGenericsLangGroup[uint32_t(aLang)];
1381
0
    }
1382
0
    return eFamily_serif;
1383
0
}
1384
1385
1386
gfxFontFamily*
1387
gfxPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle)
1388
0
{
1389
0
    gfxFontFamily* family = GetDefaultFontForPlatform(aStyle);
1390
0
    if (family) {
1391
0
        return family;
1392
0
    }
1393
0
    // Something has gone wrong and we were unable to retrieve a default font
1394
0
    // from the platform. (Likely the whitelist has blocked all potential
1395
0
    // default fonts.) As a last resort, we return the first font listed in
1396
0
    // mFontFamilies.
1397
0
    return mFontFamilies.Iter().Data();
1398
0
}
1399
1400
void
1401
gfxPlatformFontList::GetFontFamilyNames(nsTArray<nsCString>& aFontFamilyNames)
1402
0
{
1403
0
    for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
1404
0
        RefPtr<gfxFontFamily>& family = iter.Data();
1405
0
        aFontFamilyNames.AppendElement(family->Name());
1406
0
    }
1407
0
}
1408
1409
nsAtom*
1410
gfxPlatformFontList::GetLangGroup(nsAtom* aLanguage)
1411
0
{
1412
0
    // map lang ==> langGroup
1413
0
    nsAtom *langGroup = nullptr;
1414
0
    if (aLanguage) {
1415
0
        langGroup = mLangService->GetLanguageGroup(aLanguage);
1416
0
    }
1417
0
    if (!langGroup) {
1418
0
        langGroup = nsGkAtoms::Unicode;
1419
0
    }
1420
0
    return langGroup;
1421
0
}
1422
1423
/* static */ const char*
1424
gfxPlatformFontList::GetGenericName(FontFamilyType aGenericType)
1425
0
{
1426
0
    static const char kGeneric_serif[] = "serif";
1427
0
    static const char kGeneric_sans_serif[] = "sans-serif";
1428
0
    static const char kGeneric_monospace[] = "monospace";
1429
0
    static const char kGeneric_cursive[] = "cursive";
1430
0
    static const char kGeneric_fantasy[] = "fantasy";
1431
0
1432
0
    // type should be standard generic type at this point
1433
0
    NS_ASSERTION(aGenericType >= eFamily_serif &&
1434
0
                 aGenericType <= eFamily_fantasy,
1435
0
                 "standard generic font family type required");
1436
0
1437
0
    // map generic type to string
1438
0
    const char *generic = nullptr;
1439
0
    switch (aGenericType) {
1440
0
        case eFamily_serif:
1441
0
            generic = kGeneric_serif;
1442
0
            break;
1443
0
        case eFamily_sans_serif:
1444
0
            generic = kGeneric_sans_serif;
1445
0
            break;
1446
0
        case eFamily_monospace:
1447
0
            generic = kGeneric_monospace;
1448
0
            break;
1449
0
        case eFamily_cursive:
1450
0
            generic = kGeneric_cursive;
1451
0
            break;
1452
0
        case eFamily_fantasy:
1453
0
            generic = kGeneric_fantasy;
1454
0
            break;
1455
0
        default:
1456
0
            break;
1457
0
    }
1458
0
1459
0
    return generic;
1460
0
}
1461
1462
void
1463
gfxPlatformFontList::InitLoader()
1464
0
{
1465
0
    GetFontFamilyNames(mFontInfo->mFontFamiliesToLoad);
1466
0
    mStartIndex = 0;
1467
0
    mNumFamilies = mFontInfo->mFontFamiliesToLoad.Length();
1468
0
    memset(&(mFontInfo->mLoadStats), 0, sizeof(mFontInfo->mLoadStats));
1469
0
}
1470
1471
0
#define FONT_LOADER_MAX_TIMESLICE 100  // max time for one pass through RunLoader = 100ms
1472
1473
bool
1474
gfxPlatformFontList::LoadFontInfo()
1475
0
{
1476
0
    TimeStamp start = TimeStamp::Now();
1477
0
    uint32_t i, endIndex = mNumFamilies;
1478
0
    bool loadCmaps = !UsesSystemFallback() ||
1479
0
        gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
1480
0
1481
0
    // for each font family, load in various font info
1482
0
    for (i = mStartIndex; i < endIndex; i++) {
1483
0
        nsAutoCString key;
1484
0
        gfxFontFamily *familyEntry;
1485
0
        GenerateFontListKey(mFontInfo->mFontFamiliesToLoad[i], key);
1486
0
1487
0
        // lookup in canonical (i.e. English) family name list
1488
0
        if (!(familyEntry = mFontFamilies.GetWeak(key))) {
1489
0
            continue;
1490
0
        }
1491
0
1492
0
        // read in face names
1493
0
        familyEntry->ReadFaceNames(this, NeedFullnamePostscriptNames(), mFontInfo);
1494
0
1495
0
        // load the cmaps if needed
1496
0
        if (loadCmaps) {
1497
0
            familyEntry->ReadAllCMAPs(mFontInfo);
1498
0
        }
1499
0
1500
0
        // limit the time spent reading fonts in one pass
1501
0
        TimeDuration elapsed = TimeStamp::Now() - start;
1502
0
        if (elapsed.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE &&
1503
0
                i + 1 != endIndex) {
1504
0
            endIndex = i + 1;
1505
0
            break;
1506
0
        }
1507
0
    }
1508
0
1509
0
    mStartIndex = endIndex;
1510
0
    bool done = mStartIndex >= mNumFamilies;
1511
0
1512
0
    if (LOG_FONTINIT_ENABLED()) {
1513
0
        TimeDuration elapsed = TimeStamp::Now() - start;
1514
0
        LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
1515
0
                      elapsed.ToMilliseconds(), (done ? "true" : "false")));
1516
0
    }
1517
0
1518
0
    if (done) {
1519
0
        mOtherFamilyNamesInitialized = true;
1520
0
        CancelInitOtherFamilyNamesTask();
1521
0
        mFaceNameListsInitialized = true;
1522
0
    }
1523
0
1524
0
    return done;
1525
0
}
1526
1527
void
1528
gfxPlatformFontList::CleanupLoader()
1529
0
{
1530
0
    mFontFamiliesToLoad.Clear();
1531
0
    mNumFamilies = 0;
1532
0
    bool rebuilt = false, forceReflow = false;
1533
0
1534
0
    // if had missed face names that are now available, force reflow all
1535
0
    if (mFaceNamesMissed) {
1536
0
        for (auto it = mFaceNamesMissed->Iter(); !it.Done(); it.Next()) {
1537
0
            if (FindFaceName(it.Get()->GetKey())) {
1538
0
                rebuilt = true;
1539
0
                RebuildLocalFonts();
1540
0
                break;
1541
0
            }
1542
0
        }
1543
0
        mFaceNamesMissed = nullptr;
1544
0
    }
1545
0
1546
0
    if (mOtherNamesMissed) {
1547
0
        for (auto it = mOtherNamesMissed->Iter(); !it.Done(); it.Next()) {
1548
0
            if (FindFamily(it.Get()->GetKey(),
1549
0
                           (FindFamiliesFlags::eForceOtherFamilyNamesLoading |
1550
0
                            FindFamiliesFlags::eNoAddToNamesMissedWhenSearching))) {
1551
0
                forceReflow = true;
1552
0
                ForceGlobalReflow();
1553
0
                break;
1554
0
            }
1555
0
        }
1556
0
        mOtherNamesMissed = nullptr;
1557
0
    }
1558
0
1559
0
    if (LOG_FONTINIT_ENABLED() && mFontInfo) {
1560
0
        LOG_FONTINIT(("(fontinit) fontloader load thread took %8.2f ms "
1561
0
                      "%d families %d fonts %d cmaps "
1562
0
                      "%d facenames %d othernames %s %s",
1563
0
                      mLoadTime.ToMilliseconds(),
1564
0
                      mFontInfo->mLoadStats.families,
1565
0
                      mFontInfo->mLoadStats.fonts,
1566
0
                      mFontInfo->mLoadStats.cmaps,
1567
0
                      mFontInfo->mLoadStats.facenames,
1568
0
                      mFontInfo->mLoadStats.othernames,
1569
0
                      (rebuilt ? "(userfont sets rebuilt)" : ""),
1570
0
                      (forceReflow ? "(global reflow)" : "")));
1571
0
    }
1572
0
1573
0
    gfxFontInfoLoader::CleanupLoader();
1574
0
}
1575
1576
void
1577
gfxPlatformFontList::GetPrefsAndStartLoader()
1578
0
{
1579
0
    uint32_t delay =
1580
0
        std::max(1u, Preferences::GetUint(FONT_LOADER_DELAY_PREF));
1581
0
    uint32_t interval =
1582
0
        std::max(1u, Preferences::GetUint(FONT_LOADER_INTERVAL_PREF));
1583
0
1584
0
    StartLoader(delay, interval);
1585
0
}
1586
1587
void
1588
gfxPlatformFontList::RebuildLocalFonts()
1589
0
{
1590
0
    for (auto it = mUserFontSetList.Iter(); !it.Done(); it.Next()) {
1591
0
        it.Get()->GetKey()->RebuildLocalRules();
1592
0
    }
1593
0
}
1594
1595
void
1596
gfxPlatformFontList::ClearLangGroupPrefFonts()
1597
0
{
1598
0
    for (uint32_t i = eFontPrefLang_First;
1599
0
         i < eFontPrefLang_First + eFontPrefLang_Count; i++) {
1600
0
        auto& prefFontsLangGroup = mLangGroupPrefFonts[i];
1601
0
        for (uint32_t j = eFamily_generic_first;
1602
0
             j < eFamily_generic_first + eFamily_generic_count; j++) {
1603
0
            prefFontsLangGroup[j] = nullptr;
1604
0
        }
1605
0
    }
1606
0
    mCJKPrefLangs.Clear();
1607
0
    mEmojiPrefFont = nullptr;
1608
0
}
1609
1610
// Support for memory reporting
1611
1612
// this is also used by subclasses that hold additional font tables
1613
/*static*/ size_t
1614
gfxPlatformFontList::SizeOfFontFamilyTableExcludingThis(
1615
    const FontFamilyTable& aTable,
1616
    MallocSizeOf aMallocSizeOf)
1617
0
{
1618
0
    size_t n = aTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
1619
0
    for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
1620
0
        // We don't count the size of the family here, because this is an
1621
0
        // *extra* reference to a family that will have already been counted in
1622
0
        // the main list.
1623
0
        n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1624
0
    }
1625
0
    return n;
1626
0
}
1627
1628
/*static*/ size_t
1629
gfxPlatformFontList::SizeOfFontEntryTableExcludingThis(
1630
    const FontEntryTable& aTable,
1631
    MallocSizeOf aMallocSizeOf)
1632
0
{
1633
0
    size_t n = aTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
1634
0
    for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
1635
0
        // The font itself is counted by its owning family; here we only care
1636
0
        // about the names stored in the hashtable keys.
1637
0
        n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1638
0
    }
1639
0
    return n;
1640
0
}
1641
1642
void
1643
gfxPlatformFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
1644
                                            FontListSizes* aSizes) const
1645
0
{
1646
0
    aSizes->mFontListSize +=
1647
0
        mFontFamilies.ShallowSizeOfExcludingThis(aMallocSizeOf);
1648
0
    for (auto iter = mFontFamilies.ConstIter(); !iter.Done(); iter.Next()) {
1649
0
        aSizes->mFontListSize +=
1650
0
            iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1651
0
        iter.Data()->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
1652
0
    }
1653
0
1654
0
    aSizes->mFontListSize +=
1655
0
        SizeOfFontFamilyTableExcludingThis(mOtherFamilyNames, aMallocSizeOf);
1656
0
1657
0
    if (mExtraNames) {
1658
0
        aSizes->mFontListSize +=
1659
0
            SizeOfFontEntryTableExcludingThis(mExtraNames->mFullnames,
1660
0
                                              aMallocSizeOf);
1661
0
        aSizes->mFontListSize +=
1662
0
            SizeOfFontEntryTableExcludingThis(mExtraNames->mPostscriptNames,
1663
0
                                              aMallocSizeOf);
1664
0
    }
1665
0
1666
0
    for (uint32_t i = eFontPrefLang_First;
1667
0
         i < eFontPrefLang_First + eFontPrefLang_Count; i++) {
1668
0
        auto& prefFontsLangGroup = mLangGroupPrefFonts[i];
1669
0
        for (uint32_t j = eFamily_generic_first;
1670
0
             j < eFamily_generic_first + eFamily_generic_count; j++) {
1671
0
            PrefFontList* pf = prefFontsLangGroup[j].get();
1672
0
            if (pf) {
1673
0
                aSizes->mFontListSize +=
1674
0
                    pf->ShallowSizeOfExcludingThis(aMallocSizeOf);
1675
0
            }
1676
0
        }
1677
0
    }
1678
0
1679
0
    aSizes->mFontListSize +=
1680
0
        mCodepointsWithNoFonts.SizeOfExcludingThis(aMallocSizeOf);
1681
0
    aSizes->mFontListSize +=
1682
0
        mFontFamiliesToLoad.ShallowSizeOfExcludingThis(aMallocSizeOf);
1683
0
1684
0
    aSizes->mFontListSize +=
1685
0
        mBadUnderlineFamilyNames.SizeOfExcludingThis(aMallocSizeOf);
1686
0
1687
0
    aSizes->mFontListSize +=
1688
0
        mSharedCmaps.ShallowSizeOfExcludingThis(aMallocSizeOf);
1689
0
    for (auto iter = mSharedCmaps.ConstIter(); !iter.Done(); iter.Next()) {
1690
0
        aSizes->mCharMapsSize +=
1691
0
            iter.Get()->GetKey()->SizeOfIncludingThis(aMallocSizeOf);
1692
0
    }
1693
0
}
1694
1695
void
1696
gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
1697
                                            FontListSizes* aSizes) const
1698
0
{
1699
0
    aSizes->mFontListSize += aMallocSizeOf(this);
1700
0
    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
1701
0
}
1702
1703
bool
1704
gfxPlatformFontList::IsFontFamilyWhitelistActive()
1705
0
{
1706
0
    return mFontFamilyWhitelistActive;
1707
0
}
1708
1709
void
1710
gfxPlatformFontList::InitOtherFamilyNamesInternal(bool aDeferOtherFamilyNamesLoading)
1711
0
{
1712
0
    if (mOtherFamilyNamesInitialized) {
1713
0
        return;
1714
0
    }
1715
0
1716
0
    if (aDeferOtherFamilyNamesLoading) {
1717
0
        TimeStamp start = TimeStamp::Now();
1718
0
        bool timedOut = false;
1719
0
1720
0
        for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
1721
0
            RefPtr<gfxFontFamily>& family = iter.Data();
1722
0
            family->ReadOtherFamilyNames(this);
1723
0
            TimeDuration elapsed = TimeStamp::Now() - start;
1724
0
            if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
1725
0
                timedOut = true;
1726
0
                break;
1727
0
            }
1728
0
        }
1729
0
1730
0
        if (!timedOut) {
1731
0
            mOtherFamilyNamesInitialized = true;
1732
0
            CancelInitOtherFamilyNamesTask();
1733
0
        }
1734
0
        TimeStamp end = TimeStamp::Now();
1735
0
        Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES,
1736
0
                                       start, end);
1737
0
1738
0
        if (LOG_FONTINIT_ENABLED()) {
1739
0
            TimeDuration elapsed = end - start;
1740
0
            LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
1741
0
                          elapsed.ToMilliseconds(),
1742
0
                          (timedOut ? "timeout" : "")));
1743
0
        }
1744
0
    } else {
1745
0
        TimeStamp start = TimeStamp::Now();
1746
0
1747
0
        for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
1748
0
            RefPtr<gfxFontFamily>& family = iter.Data();
1749
0
            family->ReadOtherFamilyNames(this);
1750
0
        }
1751
0
1752
0
        mOtherFamilyNamesInitialized = true;
1753
0
        CancelInitOtherFamilyNamesTask();
1754
0
1755
0
        TimeStamp end = TimeStamp::Now();
1756
0
        Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES_NO_DEFERRING,
1757
0
                                       start, end);
1758
0
1759
0
        if (LOG_FONTINIT_ENABLED()) {
1760
0
            TimeDuration elapsed = end - start;
1761
0
            LOG_FONTINIT(("(fontinit) InitOtherFamilyNames without deferring took %8.2f ms",
1762
0
                          elapsed.ToMilliseconds()));
1763
0
        }
1764
0
    }
1765
0
}
1766
1767
void
1768
gfxPlatformFontList::CancelInitOtherFamilyNamesTask()
1769
0
{
1770
0
    if (mPendingOtherFamilyNameTask) {
1771
0
        mPendingOtherFamilyNameTask->Cancel();
1772
0
        mPendingOtherFamilyNameTask = nullptr;
1773
0
    }
1774
0
}
1775
1776
#undef LOG
1777
#undef LOG_ENABLED