LCOV - code coverage report
Current view: top level - gfx/thebes - gfxPlatformFontList.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 155 757 20.5 %
Date: 2017-07-14 16:53:18 Functions: 23 72 31.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13