gfx/thebes/gfxPlatformFontList.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/thebes/gfxPlatformFontList.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1233 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifdef MOZ_LOGGING
    1.10 +#define FORCE_PR_LOG /* Allow logging in the release build */
    1.11 +#endif
    1.12 +#include "prlog.h"
    1.13 +
    1.14 +#include "gfxPlatformFontList.h"
    1.15 +#include "gfxUserFontSet.h"
    1.16 +
    1.17 +#include "nsUnicharUtils.h"
    1.18 +#include "nsUnicodeRange.h"
    1.19 +#include "nsUnicodeProperties.h"
    1.20 +
    1.21 +#include "mozilla/Attributes.h"
    1.22 +#include "mozilla/Likely.h"
    1.23 +#include "mozilla/MemoryReporting.h"
    1.24 +#include "mozilla/Preferences.h"
    1.25 +#include "mozilla/Telemetry.h"
    1.26 +#include "mozilla/TimeStamp.h"
    1.27 +#include "mozilla/gfx/2D.h"
    1.28 +
    1.29 +using namespace mozilla;
    1.30 +
    1.31 +#ifdef PR_LOGGING
    1.32 +
    1.33 +#define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
    1.34 +                               PR_LOG_DEBUG, args)
    1.35 +#define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
    1.36 +                                   gfxPlatform::GetLog(eGfxLog_fontlist), \
    1.37 +                                   PR_LOG_DEBUG)
    1.38 +#define LOG_FONTINIT(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
    1.39 +                               PR_LOG_DEBUG, args)
    1.40 +#define LOG_FONTINIT_ENABLED() PR_LOG_TEST( \
    1.41 +                                   gfxPlatform::GetLog(eGfxLog_fontinit), \
    1.42 +                                   PR_LOG_DEBUG)
    1.43 +
    1.44 +#endif // PR_LOGGING
    1.45 +
    1.46 +gfxPlatformFontList *gfxPlatformFontList::sPlatformFontList = nullptr;
    1.47 +
    1.48 +// Character ranges that require complex-script shaping support in the font,
    1.49 +// and so should be masked out by ReadCMAP if the necessary layout tables
    1.50 +// are not present.
    1.51 +// Currently used by the Mac and FT2 implementations only, but probably should
    1.52 +// be supported on Windows as well.
    1.53 +const gfxFontEntry::ScriptRange gfxPlatformFontList::sComplexScriptRanges[] = {
    1.54 +    // Actually, now that harfbuzz supports presentation-forms shaping for
    1.55 +    // Arabic, we can render it without layout tables. So maybe we don't
    1.56 +    // want to mask the basic Arabic block here?
    1.57 +    // This affects the arabic-fallback-*.html reftests, which rely on
    1.58 +    // loading a font that *doesn't* have any GSUB table.
    1.59 +    { 0x0600, 0x06FF, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
    1.60 +    { 0x0700, 0x074F, { TRUETYPE_TAG('s','y','r','c'), 0, 0 } },
    1.61 +    { 0x0750, 0x077F, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
    1.62 +    { 0x08A0, 0x08FF, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
    1.63 +    { 0x0900, 0x097F, { TRUETYPE_TAG('d','e','v','2'),
    1.64 +                        TRUETYPE_TAG('d','e','v','a'), 0 } },
    1.65 +    { 0x0980, 0x09FF, { TRUETYPE_TAG('b','n','g','2'),
    1.66 +                        TRUETYPE_TAG('b','e','n','g'), 0 } },
    1.67 +    { 0x0A00, 0x0A7F, { TRUETYPE_TAG('g','u','r','2'),
    1.68 +                        TRUETYPE_TAG('g','u','r','u'), 0 } },
    1.69 +    { 0x0A80, 0x0AFF, { TRUETYPE_TAG('g','j','r','2'),
    1.70 +                        TRUETYPE_TAG('g','u','j','r'), 0 } },
    1.71 +    { 0x0B00, 0x0B7F, { TRUETYPE_TAG('o','r','y','2'),
    1.72 +                        TRUETYPE_TAG('o','r','y','a'), 0 } },
    1.73 +    { 0x0B80, 0x0BFF, { TRUETYPE_TAG('t','m','l','2'),
    1.74 +                        TRUETYPE_TAG('t','a','m','l'), 0 } },
    1.75 +    { 0x0C00, 0x0C7F, { TRUETYPE_TAG('t','e','l','2'),
    1.76 +                        TRUETYPE_TAG('t','e','l','u'), 0 } },
    1.77 +    { 0x0C80, 0x0CFF, { TRUETYPE_TAG('k','n','d','2'),
    1.78 +                        TRUETYPE_TAG('k','n','d','a'), 0 } },
    1.79 +    { 0x0D00, 0x0D7F, { TRUETYPE_TAG('m','l','m','2'),
    1.80 +                        TRUETYPE_TAG('m','l','y','m'), 0 } },
    1.81 +    { 0x0D80, 0x0DFF, { TRUETYPE_TAG('s','i','n','h'), 0, 0 } },
    1.82 +    { 0x0E80, 0x0EFF, { TRUETYPE_TAG('l','a','o',' '), 0, 0 } },
    1.83 +    { 0x0F00, 0x0FFF, { TRUETYPE_TAG('t','i','b','t'), 0, 0 } },
    1.84 +    { 0x1000, 0x109f, { TRUETYPE_TAG('m','y','m','r'),
    1.85 +                        TRUETYPE_TAG('m','y','m','2'), 0 } },
    1.86 +    { 0x1780, 0x17ff, { TRUETYPE_TAG('k','h','m','r'), 0, 0 } },
    1.87 +    // Khmer Symbols (19e0..19ff) don't seem to need any special shaping
    1.88 +    { 0xaa60, 0xaa7f, { TRUETYPE_TAG('m','y','m','r'),
    1.89 +                        TRUETYPE_TAG('m','y','m','2'), 0 } },
    1.90 +    // Thai seems to be "renderable" without AAT morphing tables
    1.91 +    { 0, 0, { 0, 0, 0 } } // terminator
    1.92 +};
    1.93 +
    1.94 +// prefs for the font info loader
    1.95 +#define FONT_LOADER_FAMILIES_PER_SLICE_PREF "gfx.font_loader.families_per_slice"
    1.96 +#define FONT_LOADER_DELAY_PREF              "gfx.font_loader.delay"
    1.97 +#define FONT_LOADER_INTERVAL_PREF           "gfx.font_loader.interval"
    1.98 +
    1.99 +static const char* kObservedPrefs[] = {
   1.100 +    "font.",
   1.101 +    "font.name-list.",
   1.102 +    "intl.accept_languages",  // hmmmm...
   1.103 +    nullptr
   1.104 +};
   1.105 +
   1.106 +class gfxFontListPrefObserver MOZ_FINAL : public nsIObserver {
   1.107 +public:
   1.108 +    NS_DECL_ISUPPORTS
   1.109 +    NS_DECL_NSIOBSERVER
   1.110 +};
   1.111 +
   1.112 +static gfxFontListPrefObserver* gFontListPrefObserver = nullptr;
   1.113 +
   1.114 +NS_IMPL_ISUPPORTS(gfxFontListPrefObserver, nsIObserver)
   1.115 +
   1.116 +NS_IMETHODIMP
   1.117 +gfxFontListPrefObserver::Observe(nsISupports     *aSubject,
   1.118 +                                 const char      *aTopic,
   1.119 +                                 const char16_t *aData)
   1.120 +{
   1.121 +    NS_ASSERTION(!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID), "invalid topic");
   1.122 +    // XXX this could be made to only clear out the cache for the prefs that were changed
   1.123 +    // but it probably isn't that big a deal.
   1.124 +    gfxPlatformFontList::PlatformFontList()->ClearPrefFonts();
   1.125 +    gfxFontCache::GetCache()->AgeAllGenerations();
   1.126 +    return NS_OK;
   1.127 +}
   1.128 +
   1.129 +MOZ_DEFINE_MALLOC_SIZE_OF(FontListMallocSizeOf)
   1.130 +
   1.131 +NS_IMPL_ISUPPORTS(gfxPlatformFontList::MemoryReporter, nsIMemoryReporter)
   1.132 +
   1.133 +NS_IMETHODIMP
   1.134 +gfxPlatformFontList::MemoryReporter::CollectReports
   1.135 +    (nsIMemoryReporterCallback* aCb,
   1.136 +     nsISupports* aClosure)
   1.137 +{
   1.138 +    FontListSizes sizes;
   1.139 +    sizes.mFontListSize = 0;
   1.140 +    sizes.mFontTableCacheSize = 0;
   1.141 +    sizes.mCharMapsSize = 0;
   1.142 +
   1.143 +    gfxPlatformFontList::PlatformFontList()->AddSizeOfIncludingThis(&FontListMallocSizeOf,
   1.144 +                                                                    &sizes);
   1.145 +
   1.146 +    aCb->Callback(EmptyCString(),
   1.147 +                  NS_LITERAL_CSTRING("explicit/gfx/font-list"),
   1.148 +                  KIND_HEAP, UNITS_BYTES, sizes.mFontListSize,
   1.149 +                  NS_LITERAL_CSTRING("Memory used to manage the list of font families and faces."),
   1.150 +                  aClosure);
   1.151 +
   1.152 +    aCb->Callback(EmptyCString(),
   1.153 +                  NS_LITERAL_CSTRING("explicit/gfx/font-charmaps"),
   1.154 +                  KIND_HEAP, UNITS_BYTES, sizes.mCharMapsSize,
   1.155 +                  NS_LITERAL_CSTRING("Memory used to record the character coverage of individual fonts."),
   1.156 +                  aClosure);
   1.157 +
   1.158 +    if (sizes.mFontTableCacheSize) {
   1.159 +        aCb->Callback(EmptyCString(),
   1.160 +                      NS_LITERAL_CSTRING("explicit/gfx/font-tables"),
   1.161 +                      KIND_HEAP, UNITS_BYTES, sizes.mFontTableCacheSize,
   1.162 +                      NS_LITERAL_CSTRING("Memory used for cached font metrics and layout tables."),
   1.163 +                      aClosure);
   1.164 +    }
   1.165 +
   1.166 +    return NS_OK;
   1.167 +}
   1.168 +
   1.169 +gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
   1.170 +    : mFontFamilies(100), mOtherFamilyNames(30),
   1.171 +      mPrefFonts(10), mBadUnderlineFamilyNames(10), mSharedCmaps(16),
   1.172 +      mStartIndex(0), mIncrement(1), mNumFamilies(0)
   1.173 +{
   1.174 +    mOtherFamilyNamesInitialized = false;
   1.175 +
   1.176 +    if (aNeedFullnamePostscriptNames) {
   1.177 +        mExtraNames = new ExtraNames();
   1.178 +    }
   1.179 +    mFaceNameListsInitialized = false;
   1.180 +
   1.181 +    LoadBadUnderlineList();
   1.182 +
   1.183 +    // pref changes notification setup
   1.184 +    NS_ASSERTION(!gFontListPrefObserver,
   1.185 +                 "There has been font list pref observer already");
   1.186 +    gFontListPrefObserver = new gfxFontListPrefObserver();
   1.187 +    NS_ADDREF(gFontListPrefObserver);
   1.188 +    Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs);
   1.189 +
   1.190 +    RegisterStrongMemoryReporter(new MemoryReporter());
   1.191 +}
   1.192 +
   1.193 +gfxPlatformFontList::~gfxPlatformFontList()
   1.194 +{
   1.195 +    mSharedCmaps.Clear();
   1.196 +    NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
   1.197 +    Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs);
   1.198 +    NS_RELEASE(gFontListPrefObserver);
   1.199 +}
   1.200 +
   1.201 +nsresult
   1.202 +gfxPlatformFontList::InitFontList()
   1.203 +{
   1.204 +    mFontFamilies.Clear();
   1.205 +    mOtherFamilyNames.Clear();
   1.206 +    mOtherFamilyNamesInitialized = false;
   1.207 +    if (mExtraNames) {
   1.208 +        mExtraNames->mFullnames.Clear();
   1.209 +        mExtraNames->mPostscriptNames.Clear();
   1.210 +    }
   1.211 +    mFaceNameListsInitialized = false;
   1.212 +    mPrefFonts.Clear();
   1.213 +    mReplacementCharFallbackFamily = nullptr;
   1.214 +    CancelLoader();
   1.215 +
   1.216 +    // initialize ranges of characters for which system-wide font search should be skipped
   1.217 +    mCodepointsWithNoFonts.reset();
   1.218 +    mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
   1.219 +    mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
   1.220 +
   1.221 +    sPlatformFontList = this;
   1.222 +
   1.223 +    return NS_OK;
   1.224 +}
   1.225 +
   1.226 +void
   1.227 +gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
   1.228 +{
   1.229 +    aResult = aKeyName;
   1.230 +    ToLowerCase(aResult);
   1.231 +}
   1.232 +
   1.233 +struct InitOtherNamesData {
   1.234 +    InitOtherNamesData(gfxPlatformFontList *aFontList,
   1.235 +                       TimeStamp aStartTime)
   1.236 +        : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false)
   1.237 +    {}
   1.238 +
   1.239 +    gfxPlatformFontList *mFontList;
   1.240 +    TimeStamp mStartTime;
   1.241 +    bool mTimedOut;
   1.242 +};
   1.243 +
   1.244 +void 
   1.245 +gfxPlatformFontList::InitOtherFamilyNames()
   1.246 +{
   1.247 +    if (mOtherFamilyNamesInitialized) {
   1.248 +        return;
   1.249 +    }
   1.250 +
   1.251 +    TimeStamp start = TimeStamp::Now();
   1.252 +
   1.253 +    // iterate over all font families and read in other family names
   1.254 +    InitOtherNamesData otherNamesData(this, start);
   1.255 +
   1.256 +    mFontFamilies.Enumerate(gfxPlatformFontList::InitOtherFamilyNamesProc,
   1.257 +                            &otherNamesData);
   1.258 +
   1.259 +    if (!otherNamesData.mTimedOut) {
   1.260 +        mOtherFamilyNamesInitialized = true;
   1.261 +    }
   1.262 +    TimeStamp end = TimeStamp::Now();
   1.263 +    Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES,
   1.264 +                                   start, end);
   1.265 +
   1.266 +#ifdef PR_LOGGING
   1.267 +    if (LOG_FONTINIT_ENABLED()) {
   1.268 +        TimeDuration elapsed = end - start;
   1.269 +        LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
   1.270 +                      elapsed.ToMilliseconds(),
   1.271 +                      (otherNamesData.mTimedOut ? "timeout" : "")));
   1.272 +    }
   1.273 +#endif
   1.274 +}
   1.275 +
   1.276 +#define OTHERNAMES_TIMEOUT 200
   1.277 +
   1.278 +PLDHashOperator
   1.279 +gfxPlatformFontList::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
   1.280 +                                              nsRefPtr<gfxFontFamily>& aFamilyEntry,
   1.281 +                                              void* userArg)
   1.282 +{
   1.283 +    InitOtherNamesData *data = static_cast<InitOtherNamesData*>(userArg);
   1.284 +
   1.285 +    aFamilyEntry->ReadOtherFamilyNames(data->mFontList);
   1.286 +    TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
   1.287 +    if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
   1.288 +        data->mTimedOut = true;
   1.289 +        return PL_DHASH_STOP;
   1.290 +    }
   1.291 +    return PL_DHASH_NEXT;
   1.292 +}
   1.293 + 
   1.294 +struct ReadFaceNamesData {
   1.295 +    ReadFaceNamesData(gfxPlatformFontList *aFontList, TimeStamp aStartTime)
   1.296 +        : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false)
   1.297 +    {}
   1.298 +
   1.299 +    gfxPlatformFontList *mFontList;
   1.300 +    TimeStamp mStartTime;
   1.301 +    bool mTimedOut;
   1.302 +
   1.303 +    // if mFirstChar is not empty, only load facenames for families
   1.304 +    // that start with this character
   1.305 +    nsString mFirstChar;
   1.306 +};
   1.307 +
   1.308 +gfxFontEntry*
   1.309 +gfxPlatformFontList::SearchFamiliesForFaceName(const nsAString& aFaceName)
   1.310 +{
   1.311 +    TimeStamp start = TimeStamp::Now();
   1.312 +    gfxFontEntry *lookup = nullptr;
   1.313 +
   1.314 +    ReadFaceNamesData faceNameListsData(this, start);
   1.315 +
   1.316 +    // iterate over familes starting with the same letter
   1.317 +    faceNameListsData.mFirstChar.Assign(aFaceName.CharAt(0));
   1.318 +    ToLowerCase(faceNameListsData.mFirstChar);
   1.319 +    mFontFamilies.Enumerate(gfxPlatformFontList::ReadFaceNamesProc,
   1.320 +                            &faceNameListsData);
   1.321 +    lookup = FindFaceName(aFaceName);
   1.322 +
   1.323 +    TimeStamp end = TimeStamp::Now();
   1.324 +    Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITFACENAMELISTS,
   1.325 +                                   start, end);
   1.326 +#ifdef PR_LOGGING
   1.327 +    if (LOG_FONTINIT_ENABLED()) {
   1.328 +        TimeDuration elapsed = end - start;
   1.329 +        LOG_FONTINIT(("(fontinit) SearchFamiliesForFaceName took %8.2f ms %s %s",
   1.330 +                      elapsed.ToMilliseconds(),
   1.331 +                      (lookup ? "found name" : ""),
   1.332 +                      (faceNameListsData.mTimedOut ? "timeout" : "")));
   1.333 +    }
   1.334 +#endif
   1.335 +
   1.336 +    return lookup;
   1.337 +}
   1.338 +
   1.339 +// time limit for loading facename lists (ms)
   1.340 +#define NAMELIST_TIMEOUT  200
   1.341 +
   1.342 +PLDHashOperator
   1.343 +gfxPlatformFontList::ReadFaceNamesProc(nsStringHashKey::KeyType aKey,
   1.344 +                                       nsRefPtr<gfxFontFamily>& aFamilyEntry,
   1.345 +                                       void* userArg)
   1.346 +{
   1.347 +    ReadFaceNamesData *data = static_cast<ReadFaceNamesData*>(userArg);
   1.348 +    gfxPlatformFontList *fc = data->mFontList;
   1.349 +
   1.350 +    // when filtering, skip names that don't start with the filter character
   1.351 +    if (!(data->mFirstChar.IsEmpty())) {
   1.352 +        char16_t firstChar = aKey.CharAt(0);
   1.353 +        nsAutoString firstCharStr(&firstChar, 1);
   1.354 +        ToLowerCase(firstCharStr);
   1.355 +        if (!firstCharStr.Equals(data->mFirstChar)) {
   1.356 +            return PL_DHASH_NEXT;
   1.357 +        }
   1.358 +    }
   1.359 +    aFamilyEntry->ReadFaceNames(fc, fc->NeedFullnamePostscriptNames());
   1.360 +
   1.361 +    TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
   1.362 +    if (elapsed.ToMilliseconds() > NAMELIST_TIMEOUT) {
   1.363 +        data->mTimedOut = true;
   1.364 +        return PL_DHASH_STOP;
   1.365 +    }
   1.366 +    return PL_DHASH_NEXT;
   1.367 +}
   1.368 +
   1.369 +gfxFontEntry*
   1.370 +gfxPlatformFontList::FindFaceName(const nsAString& aFaceName)
   1.371 +{
   1.372 +    gfxFontEntry *lookup;
   1.373 +
   1.374 +    // lookup in name lookup tables, return null if not found
   1.375 +    if (mExtraNames &&
   1.376 +        ((lookup = mExtraNames->mPostscriptNames.GetWeak(aFaceName)) ||
   1.377 +         (lookup = mExtraNames->mFullnames.GetWeak(aFaceName)))) {
   1.378 +        return lookup;
   1.379 +    }
   1.380 +
   1.381 +    return nullptr;
   1.382 +}
   1.383 +
   1.384 +gfxFontEntry*
   1.385 +gfxPlatformFontList::LookupInFaceNameLists(const nsAString& aFaceName)
   1.386 +{
   1.387 +    gfxFontEntry *lookup = nullptr;
   1.388 +
   1.389 +    // initialize facename lookup tables if needed
   1.390 +    // note: this can terminate early or time out, in which case
   1.391 +    //       mFaceNameListsInitialized remains false
   1.392 +    if (!mFaceNameListsInitialized) {
   1.393 +        lookup = SearchFamiliesForFaceName(aFaceName);
   1.394 +        if (lookup) {
   1.395 +            return lookup;
   1.396 +        }
   1.397 +    }
   1.398 +
   1.399 +    // lookup in name lookup tables, return null if not found
   1.400 +    if (!(lookup = FindFaceName(aFaceName))) {
   1.401 +        // names not completely initialized, so keep track of lookup misses
   1.402 +        if (!mFaceNameListsInitialized) {
   1.403 +            if (!mFaceNamesMissed) {
   1.404 +                mFaceNamesMissed = new nsTHashtable<nsStringHashKey>(4);
   1.405 +            }
   1.406 +            mFaceNamesMissed->PutEntry(aFaceName);
   1.407 +        }
   1.408 +    }
   1.409 +
   1.410 +    return lookup;
   1.411 +}
   1.412 +
   1.413 +void
   1.414 +gfxPlatformFontList::PreloadNamesList()
   1.415 +{
   1.416 +    nsAutoTArray<nsString, 10> preloadFonts;
   1.417 +    gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts);
   1.418 +
   1.419 +    uint32_t numFonts = preloadFonts.Length();
   1.420 +    for (uint32_t i = 0; i < numFonts; i++) {
   1.421 +        nsAutoString key;
   1.422 +        GenerateFontListKey(preloadFonts[i], key);
   1.423 +        
   1.424 +        // only search canonical names!
   1.425 +        gfxFontFamily *familyEntry = mFontFamilies.GetWeak(key);
   1.426 +        if (familyEntry) {
   1.427 +            familyEntry->ReadOtherFamilyNames(this);
   1.428 +        }
   1.429 +    }
   1.430 +
   1.431 +}
   1.432 +
   1.433 +void 
   1.434 +gfxPlatformFontList::SetFixedPitch(const nsAString& aFamilyName)
   1.435 +{
   1.436 +    gfxFontFamily *family = FindFamily(aFamilyName);
   1.437 +    if (!family) return;
   1.438 +
   1.439 +    family->FindStyleVariations();
   1.440 +    nsTArray<nsRefPtr<gfxFontEntry> >& fontlist = family->GetFontList();
   1.441 +
   1.442 +    uint32_t i, numFonts = fontlist.Length();
   1.443 +
   1.444 +    for (i = 0; i < numFonts; i++) {
   1.445 +        fontlist[i]->mFixedPitch = 1;
   1.446 +    }
   1.447 +}
   1.448 +
   1.449 +void
   1.450 +gfxPlatformFontList::LoadBadUnderlineList()
   1.451 +{
   1.452 +    nsAutoTArray<nsString, 10> blacklist;
   1.453 +    gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
   1.454 +    uint32_t numFonts = blacklist.Length();
   1.455 +    for (uint32_t i = 0; i < numFonts; i++) {
   1.456 +        nsAutoString key;
   1.457 +        GenerateFontListKey(blacklist[i], key);
   1.458 +        mBadUnderlineFamilyNames.PutEntry(key);
   1.459 +    }
   1.460 +}
   1.461 +
   1.462 +bool 
   1.463 +gfxPlatformFontList::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
   1.464 +{
   1.465 +    gfxFontFamily *family = FindFamily(aFontName);
   1.466 +    if (family) {
   1.467 +        aResolvedFontName = family->Name();
   1.468 +        return true;
   1.469 +    }
   1.470 +    return false;
   1.471 +}
   1.472 +
   1.473 +static PLDHashOperator
   1.474 +RebuildLocalFonts(nsPtrHashKey<gfxUserFontSet>* aKey,
   1.475 +                  void* aClosure)
   1.476 +{
   1.477 +    aKey->GetKey()->RebuildLocalRules();
   1.478 +    return PL_DHASH_NEXT;
   1.479 +}
   1.480 +
   1.481 +void
   1.482 +gfxPlatformFontList::UpdateFontList()
   1.483 +{
   1.484 +    InitFontList();
   1.485 +    mUserFontSetList.EnumerateEntries(RebuildLocalFonts, nullptr);
   1.486 +}
   1.487 +
   1.488 +struct FontListData {
   1.489 +    FontListData(nsIAtom *aLangGroup,
   1.490 +                 const nsACString& aGenericFamily,
   1.491 +                 nsTArray<nsString>& aListOfFonts) :
   1.492 +        mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
   1.493 +        mListOfFonts(aListOfFonts) {}
   1.494 +    nsIAtom *mLangGroup;
   1.495 +    const nsACString& mGenericFamily;
   1.496 +    nsTArray<nsString>& mListOfFonts;
   1.497 +};
   1.498 +
   1.499 +PLDHashOperator
   1.500 +gfxPlatformFontList::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
   1.501 +                                             nsRefPtr<gfxFontFamily>& aFamilyEntry,
   1.502 +                                             void *aUserArg)
   1.503 +{
   1.504 +    FontListData *data = static_cast<FontListData*>(aUserArg);
   1.505 +
   1.506 +    // use the first variation for now.  This data should be the same
   1.507 +    // for all the variations and should probably be moved up to
   1.508 +    // the Family
   1.509 +    gfxFontStyle style;
   1.510 +    style.language = data->mLangGroup;
   1.511 +    bool needsBold;
   1.512 +    nsRefPtr<gfxFontEntry> aFontEntry = aFamilyEntry->FindFontForStyle(style, needsBold);
   1.513 +    NS_ASSERTION(aFontEntry, "couldn't find any font entry in family");
   1.514 +    if (!aFontEntry)
   1.515 +        return PL_DHASH_NEXT;
   1.516 +
   1.517 +    /* skip symbol fonts */
   1.518 +    if (aFontEntry->IsSymbolFont())
   1.519 +        return PL_DHASH_NEXT;
   1.520 +
   1.521 +    if (aFontEntry->SupportsLangGroup(data->mLangGroup) &&
   1.522 +        aFontEntry->MatchesGenericFamily(data->mGenericFamily)) {
   1.523 +        nsAutoString localizedFamilyName;
   1.524 +        aFamilyEntry->LocalizedName(localizedFamilyName);
   1.525 +        data->mListOfFonts.AppendElement(localizedFamilyName);
   1.526 +    }
   1.527 +
   1.528 +    return PL_DHASH_NEXT;
   1.529 +}
   1.530 +
   1.531 +void
   1.532 +gfxPlatformFontList::GetFontList(nsIAtom *aLangGroup,
   1.533 +                                 const nsACString& aGenericFamily,
   1.534 +                                 nsTArray<nsString>& aListOfFonts)
   1.535 +{
   1.536 +    FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
   1.537 +
   1.538 +    mFontFamilies.Enumerate(gfxPlatformFontList::HashEnumFuncForFamilies, &data);
   1.539 +
   1.540 +    aListOfFonts.Sort();
   1.541 +    aListOfFonts.Compact();
   1.542 +}
   1.543 +
   1.544 +struct FontFamilyListData {
   1.545 +    FontFamilyListData(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray) 
   1.546 +        : mFamilyArray(aFamilyArray)
   1.547 +    {}
   1.548 +
   1.549 +    static PLDHashOperator AppendFamily(nsStringHashKey::KeyType aKey,
   1.550 +                                        nsRefPtr<gfxFontFamily>& aFamilyEntry,
   1.551 +                                        void *aUserArg)
   1.552 +    {
   1.553 +        FontFamilyListData *data = static_cast<FontFamilyListData*>(aUserArg);
   1.554 +        data->mFamilyArray.AppendElement(aFamilyEntry);
   1.555 +        return PL_DHASH_NEXT;
   1.556 +    }
   1.557 +
   1.558 +    nsTArray<nsRefPtr<gfxFontFamily> >& mFamilyArray;
   1.559 +};
   1.560 +
   1.561 +void
   1.562 +gfxPlatformFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
   1.563 +{
   1.564 +    FontFamilyListData data(aFamilyArray);
   1.565 +    mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
   1.566 +}
   1.567 +
   1.568 +gfxFontEntry*
   1.569 +gfxPlatformFontList::SystemFindFontForChar(const uint32_t aCh,
   1.570 +                                           int32_t aRunScript,
   1.571 +                                           const gfxFontStyle* aStyle)
   1.572 + {
   1.573 +    gfxFontEntry* fontEntry = nullptr;
   1.574 +
   1.575 +    // is codepoint with no matching font? return null immediately
   1.576 +    if (mCodepointsWithNoFonts.test(aCh)) {
   1.577 +        return nullptr;
   1.578 +    }
   1.579 +
   1.580 +    // Try to short-circuit font fallback for U+FFFD, used to represent
   1.581 +    // encoding errors: just use cached family from last time U+FFFD was seen.
   1.582 +    // This helps speed up pages with lots of encoding errors, binary-as-text,
   1.583 +    // etc.
   1.584 +    if (aCh == 0xFFFD && mReplacementCharFallbackFamily) {
   1.585 +        bool needsBold;  // ignored in the system fallback case
   1.586 +
   1.587 +        fontEntry =
   1.588 +            mReplacementCharFallbackFamily->FindFontForStyle(*aStyle,
   1.589 +                                                             needsBold);
   1.590 +
   1.591 +        // this should never fail, as we must have found U+FFFD in order to set
   1.592 +        // mReplacementCharFallbackFamily at all, but better play it safe
   1.593 +        if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
   1.594 +            return fontEntry;
   1.595 +        }
   1.596 +    }
   1.597 +
   1.598 +    TimeStamp start = TimeStamp::Now();
   1.599 +
   1.600 +    // search commonly available fonts
   1.601 +    bool common = true;
   1.602 +    gfxFontFamily *fallbackFamily = nullptr;
   1.603 +    fontEntry = CommonFontFallback(aCh, aRunScript, aStyle, &fallbackFamily);
   1.604 + 
   1.605 +    // if didn't find a font, do system-wide fallback (except for specials)
   1.606 +    uint32_t cmapCount = 0;
   1.607 +    if (!fontEntry) {
   1.608 +        common = false;
   1.609 +        fontEntry = GlobalFontFallback(aCh, aRunScript, aStyle, cmapCount,
   1.610 +                                       &fallbackFamily);
   1.611 +    }
   1.612 +    TimeDuration elapsed = TimeStamp::Now() - start;
   1.613 +
   1.614 +#ifdef PR_LOGGING
   1.615 +    PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textrun);
   1.616 +
   1.617 +    if (MOZ_UNLIKELY(PR_LOG_TEST(log, PR_LOG_WARNING))) {
   1.618 +        uint32_t unicodeRange = FindCharUnicodeRange(aCh);
   1.619 +        int32_t script = mozilla::unicode::GetScriptCode(aCh);
   1.620 +        PR_LOG(log, PR_LOG_WARNING,\
   1.621 +               ("(textrun-systemfallback-%s) char: u+%6.6x "
   1.622 +                 "unicode-range: %d script: %d match: [%s]"
   1.623 +                " time: %dus cmaps: %d\n",
   1.624 +                (common ? "common" : "global"), aCh,
   1.625 +                 unicodeRange, script,
   1.626 +                (fontEntry ? NS_ConvertUTF16toUTF8(fontEntry->Name()).get() :
   1.627 +                    "<none>"),
   1.628 +                int32_t(elapsed.ToMicroseconds()),
   1.629 +                cmapCount));
   1.630 +    }
   1.631 +#endif
   1.632 +
   1.633 +    // no match? add to set of non-matching codepoints
   1.634 +    if (!fontEntry) {
   1.635 +        mCodepointsWithNoFonts.set(aCh);
   1.636 +    } else if (aCh == 0xFFFD && fontEntry && fallbackFamily) {
   1.637 +        mReplacementCharFallbackFamily = fallbackFamily;
   1.638 +    }
   1.639 + 
   1.640 +    // track system fallback time
   1.641 +    static bool first = true;
   1.642 +    int32_t intElapsed = int32_t(first ? elapsed.ToMilliseconds() :
   1.643 +                                         elapsed.ToMicroseconds());
   1.644 +    Telemetry::Accumulate((first ? Telemetry::SYSTEM_FONT_FALLBACK_FIRST :
   1.645 +                                   Telemetry::SYSTEM_FONT_FALLBACK),
   1.646 +                          intElapsed);
   1.647 +    first = false;
   1.648 +
   1.649 +    // track the script for which fallback occurred (incremented one make it
   1.650 +    // 1-based)
   1.651 +    Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT, aRunScript + 1);
   1.652 +
   1.653 +    return fontEntry;
   1.654 +}
   1.655 +
   1.656 +PLDHashOperator 
   1.657 +gfxPlatformFontList::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<gfxFontFamily>& aFamilyEntry,
   1.658 +     void *userArg)
   1.659 +{
   1.660 +    GlobalFontMatch *data = static_cast<GlobalFontMatch*>(userArg);
   1.661 +
   1.662 +    // evaluate all fonts in this family for a match
   1.663 +    aFamilyEntry->FindFontForChar(data);
   1.664 +
   1.665 +    return PL_DHASH_NEXT;
   1.666 +}
   1.667 +
   1.668 +#define NUM_FALLBACK_FONTS        8
   1.669 +
   1.670 +gfxFontEntry*
   1.671 +gfxPlatformFontList::CommonFontFallback(const uint32_t aCh,
   1.672 +                                        int32_t aRunScript,
   1.673 +                                        const gfxFontStyle* aMatchStyle,
   1.674 +                                        gfxFontFamily** aMatchedFamily)
   1.675 +{
   1.676 +    nsAutoTArray<const char*,NUM_FALLBACK_FONTS> defaultFallbacks;
   1.677 +    uint32_t i, numFallbacks;
   1.678 +
   1.679 +    gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh, aRunScript,
   1.680 +                                                       defaultFallbacks);
   1.681 +    numFallbacks = defaultFallbacks.Length();
   1.682 +    for (i = 0; i < numFallbacks; i++) {
   1.683 +        nsAutoString familyName;
   1.684 +        const char *fallbackFamily = defaultFallbacks[i];
   1.685 +
   1.686 +        familyName.AppendASCII(fallbackFamily);
   1.687 +        gfxFontFamily *fallback =
   1.688 +                gfxPlatformFontList::PlatformFontList()->FindFamily(familyName);
   1.689 +        if (!fallback)
   1.690 +            continue;
   1.691 +
   1.692 +        gfxFontEntry *fontEntry;
   1.693 +        bool needsBold;  // ignored in the system fallback case
   1.694 +
   1.695 +        // use first font in list that supports a given character
   1.696 +        fontEntry = fallback->FindFontForStyle(*aMatchStyle, needsBold);
   1.697 +        if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
   1.698 +            *aMatchedFamily = fallback;
   1.699 +            return fontEntry;
   1.700 +        }
   1.701 +    }
   1.702 +
   1.703 +    return nullptr;
   1.704 +}
   1.705 +
   1.706 +gfxFontEntry*
   1.707 +gfxPlatformFontList::GlobalFontFallback(const uint32_t aCh,
   1.708 +                                        int32_t aRunScript,
   1.709 +                                        const gfxFontStyle* aMatchStyle,
   1.710 +                                        uint32_t& aCmapCount,
   1.711 +                                        gfxFontFamily** aMatchedFamily)
   1.712 +{
   1.713 +    // otherwise, try to find it among local fonts
   1.714 +    GlobalFontMatch data(aCh, aRunScript, aMatchStyle);
   1.715 +
   1.716 +    // iterate over all font families to find a font that support the character
   1.717 +    mFontFamilies.Enumerate(gfxPlatformFontList::FindFontForCharProc, &data);
   1.718 +
   1.719 +    aCmapCount = data.mCmapsTested;
   1.720 +    *aMatchedFamily = data.mMatchedFamily;
   1.721 +
   1.722 +    return data.mBestMatch;
   1.723 +}
   1.724 +
   1.725 +#ifdef XP_WIN
   1.726 +#include <windows.h>
   1.727 +
   1.728 +// crude hack for using when monitoring process
   1.729 +static void LogRegistryEvent(const wchar_t *msg)
   1.730 +{
   1.731 +  HKEY dummyKey;
   1.732 +  HRESULT hr;
   1.733 +  wchar_t buf[512];
   1.734 +
   1.735 +  wsprintfW(buf, L" log %s", msg);
   1.736 +  hr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
   1.737 +  if (SUCCEEDED(hr)) {
   1.738 +    RegCloseKey(dummyKey);
   1.739 +  }
   1.740 +}
   1.741 +#endif
   1.742 +
   1.743 +gfxFontFamily*
   1.744 +gfxPlatformFontList::CheckFamily(gfxFontFamily *aFamily)
   1.745 +{
   1.746 +    if (aFamily && !aFamily->HasStyles()) {
   1.747 +        aFamily->FindStyleVariations();
   1.748 +        aFamily->CheckForSimpleFamily();
   1.749 +    }
   1.750 +
   1.751 +    if (aFamily && aFamily->GetFontList().Length() == 0) {
   1.752 +        // failed to load any faces for this family, so discard it
   1.753 +        nsAutoString key;
   1.754 +        GenerateFontListKey(aFamily->Name(), key);
   1.755 +        mFontFamilies.Remove(key);
   1.756 +        return nullptr;
   1.757 +    }
   1.758 +
   1.759 +    return aFamily;
   1.760 +}
   1.761 +
   1.762 +gfxFontFamily* 
   1.763 +gfxPlatformFontList::FindFamily(const nsAString& aFamily)
   1.764 +{
   1.765 +    nsAutoString key;
   1.766 +    gfxFontFamily *familyEntry;
   1.767 +    GenerateFontListKey(aFamily, key);
   1.768 +
   1.769 +    NS_ASSERTION(mFontFamilies.Count() != 0, "system font list was not initialized correctly");
   1.770 +
   1.771 +    // lookup in canonical (i.e. English) family name list
   1.772 +    if ((familyEntry = mFontFamilies.GetWeak(key))) {
   1.773 +        return CheckFamily(familyEntry);
   1.774 +    }
   1.775 +
   1.776 +    // lookup in other family names list (mostly localized names)
   1.777 +    if ((familyEntry = mOtherFamilyNames.GetWeak(key)) != nullptr) {
   1.778 +        return CheckFamily(familyEntry);
   1.779 +    }
   1.780 +
   1.781 +    // name not found and other family names not yet fully initialized so
   1.782 +    // initialize the rest of the list and try again.  this is done lazily
   1.783 +    // since reading name table entries is expensive.
   1.784 +    // although ASCII localized family names are possible they don't occur
   1.785 +    // in practice so avoid pulling in names at startup
   1.786 +    if (!mOtherFamilyNamesInitialized && !IsASCII(aFamily)) {
   1.787 +        InitOtherFamilyNames();
   1.788 +        if ((familyEntry = mOtherFamilyNames.GetWeak(key)) != nullptr) {
   1.789 +            return CheckFamily(familyEntry);
   1.790 +        } else if (!mOtherFamilyNamesInitialized) {
   1.791 +            // localized family names load timed out, add name to list of
   1.792 +            // names to check after localized names are loaded
   1.793 +            if (!mOtherNamesMissed) {
   1.794 +                mOtherNamesMissed = new nsTHashtable<nsStringHashKey>(4);
   1.795 +            }
   1.796 +            mOtherNamesMissed->PutEntry(key);
   1.797 +        }
   1.798 +    }
   1.799 +
   1.800 +    return nullptr;
   1.801 +}
   1.802 +
   1.803 +gfxFontEntry*
   1.804 +gfxPlatformFontList::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold)
   1.805 +{
   1.806 +    gfxFontFamily *familyEntry = FindFamily(aFamily);
   1.807 +
   1.808 +    aNeedsBold = false;
   1.809 +
   1.810 +    if (familyEntry)
   1.811 +        return familyEntry->FindFontForStyle(*aStyle, aNeedsBold);
   1.812 +
   1.813 +    return nullptr;
   1.814 +}
   1.815 +
   1.816 +bool
   1.817 +gfxPlatformFontList::GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> > *array)
   1.818 +{
   1.819 +    return mPrefFonts.Get(uint32_t(aLangGroup), array);
   1.820 +}
   1.821 +
   1.822 +void
   1.823 +gfxPlatformFontList::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> >& array)
   1.824 +{
   1.825 +    mPrefFonts.Put(uint32_t(aLangGroup), array);
   1.826 +}
   1.827 +
   1.828 +void 
   1.829 +gfxPlatformFontList::AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName)
   1.830 +{
   1.831 +    nsAutoString key;
   1.832 +    GenerateFontListKey(aOtherFamilyName, key);
   1.833 +
   1.834 +    if (!mOtherFamilyNames.GetWeak(key)) {
   1.835 +        mOtherFamilyNames.Put(key, aFamilyEntry);
   1.836 +#ifdef PR_LOGGING
   1.837 +        LOG_FONTLIST(("(fontlist-otherfamily) canonical family: %s, "
   1.838 +                      "other family: %s\n",
   1.839 +                      NS_ConvertUTF16toUTF8(aFamilyEntry->Name()).get(),
   1.840 +                      NS_ConvertUTF16toUTF8(aOtherFamilyName).get()));
   1.841 +#endif
   1.842 +        if (mBadUnderlineFamilyNames.Contains(key))
   1.843 +            aFamilyEntry->SetBadUnderlineFamily();
   1.844 +    }
   1.845 +}
   1.846 +
   1.847 +void
   1.848 +gfxPlatformFontList::AddFullname(gfxFontEntry *aFontEntry, nsAString& aFullname)
   1.849 +{
   1.850 +    if (!mExtraNames->mFullnames.GetWeak(aFullname)) {
   1.851 +        mExtraNames->mFullnames.Put(aFullname, aFontEntry);
   1.852 +#ifdef PR_LOGGING
   1.853 +        LOG_FONTLIST(("(fontlist-fullname) name: %s, fullname: %s\n",
   1.854 +                      NS_ConvertUTF16toUTF8(aFontEntry->Name()).get(),
   1.855 +                      NS_ConvertUTF16toUTF8(aFullname).get()));
   1.856 +#endif
   1.857 +    }
   1.858 +}
   1.859 +
   1.860 +void
   1.861 +gfxPlatformFontList::AddPostscriptName(gfxFontEntry *aFontEntry, nsAString& aPostscriptName)
   1.862 +{
   1.863 +    if (!mExtraNames->mPostscriptNames.GetWeak(aPostscriptName)) {
   1.864 +        mExtraNames->mPostscriptNames.Put(aPostscriptName, aFontEntry);
   1.865 +#ifdef PR_LOGGING
   1.866 +        LOG_FONTLIST(("(fontlist-postscript) name: %s, psname: %s\n",
   1.867 +                      NS_ConvertUTF16toUTF8(aFontEntry->Name()).get(),
   1.868 +                      NS_ConvertUTF16toUTF8(aPostscriptName).get()));
   1.869 +#endif
   1.870 +    }
   1.871 +}
   1.872 +
   1.873 +bool
   1.874 +gfxPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
   1.875 +{
   1.876 +    aFamilyName.Truncate();
   1.877 +    ResolveFontName(aFontName, aFamilyName);
   1.878 +    return !aFamilyName.IsEmpty();
   1.879 +}
   1.880 +
   1.881 +gfxCharacterMap*
   1.882 +gfxPlatformFontList::FindCharMap(gfxCharacterMap *aCmap)
   1.883 +{
   1.884 +    aCmap->CalcHash();
   1.885 +    gfxCharacterMap *cmap = AddCmap(aCmap);
   1.886 +    cmap->mShared = true;
   1.887 +    return cmap;
   1.888 +}
   1.889 +
   1.890 +// add a cmap to the shared cmap set
   1.891 +gfxCharacterMap*
   1.892 +gfxPlatformFontList::AddCmap(const gfxCharacterMap* aCharMap)
   1.893 +{
   1.894 +    CharMapHashKey *found =
   1.895 +        mSharedCmaps.PutEntry(const_cast<gfxCharacterMap*>(aCharMap));
   1.896 +    return found->GetKey();
   1.897 +}
   1.898 +
   1.899 +// remove the cmap from the shared cmap set
   1.900 +void
   1.901 +gfxPlatformFontList::RemoveCmap(const gfxCharacterMap* aCharMap)
   1.902 +{
   1.903 +    // skip lookups during teardown
   1.904 +    if (mSharedCmaps.Count() == 0) {
   1.905 +        return;
   1.906 +    }
   1.907 +
   1.908 +    // cmap needs to match the entry *and* be the same ptr before removing
   1.909 +    CharMapHashKey *found =
   1.910 +        mSharedCmaps.GetEntry(const_cast<gfxCharacterMap*>(aCharMap));
   1.911 +    if (found && found->GetKey() == aCharMap) {
   1.912 +        mSharedCmaps.RemoveEntry(const_cast<gfxCharacterMap*>(aCharMap));
   1.913 +    }
   1.914 +}
   1.915 +
   1.916 +static PLDHashOperator AppendFamilyToList(nsStringHashKey::KeyType aKey,
   1.917 +                                          nsRefPtr<gfxFontFamily>& aFamilyEntry,
   1.918 +                                          void *aUserArg)
   1.919 +{
   1.920 +    nsTArray<nsString> *familyNames = static_cast<nsTArray<nsString> *>(aUserArg);
   1.921 +    familyNames->AppendElement(aFamilyEntry->Name());
   1.922 +    return PL_DHASH_NEXT;
   1.923 +}
   1.924 +
   1.925 +void
   1.926 +gfxPlatformFontList::GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames)
   1.927 +{
   1.928 +    mFontFamilies.Enumerate(AppendFamilyToList, &aFontFamilyNames);
   1.929 +}
   1.930 +
   1.931 +void 
   1.932 +gfxPlatformFontList::InitLoader()
   1.933 +{
   1.934 +    GetFontFamilyNames(mFontInfo->mFontFamiliesToLoad);
   1.935 +    mStartIndex = 0;
   1.936 +    mNumFamilies = mFontInfo->mFontFamiliesToLoad.Length();
   1.937 +    memset(&(mFontInfo->mLoadStats), 0, sizeof(mFontInfo->mLoadStats));
   1.938 +}
   1.939 +
   1.940 +#define FONT_LOADER_MAX_TIMESLICE 100  // max time for one pass through RunLoader = 100ms
   1.941 +
   1.942 +bool
   1.943 +gfxPlatformFontList::LoadFontInfo()
   1.944 +{
   1.945 +    TimeStamp start = TimeStamp::Now();
   1.946 +    uint32_t i, endIndex = mNumFamilies;
   1.947 +    bool loadCmaps = !UsesSystemFallback() ||
   1.948 +        gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
   1.949 +
   1.950 +    // for each font family, load in various font info
   1.951 +    for (i = mStartIndex; i < endIndex; i++) {
   1.952 +        nsAutoString key;
   1.953 +        gfxFontFamily *familyEntry;
   1.954 +        GenerateFontListKey(mFontInfo->mFontFamiliesToLoad[i], key);
   1.955 +
   1.956 +        // lookup in canonical (i.e. English) family name list
   1.957 +        if (!(familyEntry = mFontFamilies.GetWeak(key))) {
   1.958 +            continue;
   1.959 +        }
   1.960 +
   1.961 +        // read in face names
   1.962 +        familyEntry->ReadFaceNames(this, NeedFullnamePostscriptNames(), mFontInfo);
   1.963 +
   1.964 +        // load the cmaps if needed
   1.965 +        if (loadCmaps) {
   1.966 +            familyEntry->ReadAllCMAPs(mFontInfo);
   1.967 +        }
   1.968 +
   1.969 +        // limit the time spent reading fonts in one pass
   1.970 +        TimeDuration elapsed = TimeStamp::Now() - start;
   1.971 +        if (elapsed.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE &&
   1.972 +                i + 1 != endIndex) {
   1.973 +            endIndex = i + 1;
   1.974 +            break;
   1.975 +        }
   1.976 +    }
   1.977 +
   1.978 +    mStartIndex = endIndex;
   1.979 +    bool done = mStartIndex >= mNumFamilies;
   1.980 +
   1.981 +#ifdef PR_LOGGING
   1.982 +    if (LOG_FONTINIT_ENABLED()) {
   1.983 +        TimeDuration elapsed = TimeStamp::Now() - start;
   1.984 +        LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
   1.985 +                      elapsed.ToMilliseconds(), (done ? "true" : "false")));
   1.986 +    }
   1.987 +#endif
   1.988 +
   1.989 +    if (done) {
   1.990 +        mOtherFamilyNamesInitialized = true;
   1.991 +        mFaceNameListsInitialized = true;
   1.992 +    }
   1.993 +
   1.994 +    return done;
   1.995 +}
   1.996 +
   1.997 +struct LookupMissedFaceNamesData {
   1.998 +    LookupMissedFaceNamesData(gfxPlatformFontList *aFontList)
   1.999 +        : mFontList(aFontList), mFoundName(false) {}
  1.1000 +
  1.1001 +    gfxPlatformFontList *mFontList;
  1.1002 +    bool mFoundName;
  1.1003 +};
  1.1004 +
  1.1005 +/*static*/ PLDHashOperator
  1.1006 +gfxPlatformFontList::LookupMissedFaceNamesProc(nsStringHashKey *aKey,
  1.1007 +                                               void *aUserArg)
  1.1008 +{
  1.1009 +    LookupMissedFaceNamesData *data =
  1.1010 +        reinterpret_cast<LookupMissedFaceNamesData*>(aUserArg);
  1.1011 +
  1.1012 +    if (data->mFontList->FindFaceName(aKey->GetKey())) {
  1.1013 +        data->mFoundName = true;
  1.1014 +        return PL_DHASH_STOP;
  1.1015 +    }
  1.1016 +    return PL_DHASH_NEXT;
  1.1017 +}
  1.1018 +
  1.1019 +struct LookupMissedOtherNamesData {
  1.1020 +    LookupMissedOtherNamesData(gfxPlatformFontList *aFontList)
  1.1021 +        : mFontList(aFontList), mFoundName(false) {}
  1.1022 +
  1.1023 +    gfxPlatformFontList *mFontList;
  1.1024 +    bool mFoundName;
  1.1025 +};
  1.1026 +
  1.1027 +/*static*/ PLDHashOperator
  1.1028 +gfxPlatformFontList::LookupMissedOtherNamesProc(nsStringHashKey *aKey,
  1.1029 +                                                void *aUserArg)
  1.1030 +{
  1.1031 +    LookupMissedOtherNamesData *data =
  1.1032 +        reinterpret_cast<LookupMissedOtherNamesData*>(aUserArg);
  1.1033 +
  1.1034 +    if (data->mFontList->FindFamily(aKey->GetKey())) {
  1.1035 +        data->mFoundName = true;
  1.1036 +        return PL_DHASH_STOP;
  1.1037 +    }
  1.1038 +    return PL_DHASH_NEXT;
  1.1039 +}
  1.1040 +
  1.1041 +void 
  1.1042 +gfxPlatformFontList::CleanupLoader()
  1.1043 +{
  1.1044 +    mFontFamiliesToLoad.Clear();
  1.1045 +    mNumFamilies = 0;
  1.1046 +    bool rebuilt = false, forceReflow = false;
  1.1047 +
  1.1048 +    // if had missed face names that are now available, force reflow all
  1.1049 +    if (mFaceNamesMissed &&
  1.1050 +        mFaceNamesMissed->Count() != 0) {
  1.1051 +        LookupMissedFaceNamesData namedata(this);
  1.1052 +        mFaceNamesMissed->EnumerateEntries(LookupMissedFaceNamesProc, &namedata);
  1.1053 +        if (namedata.mFoundName) {
  1.1054 +            rebuilt = true;
  1.1055 +            mUserFontSetList.EnumerateEntries(RebuildLocalFonts, nullptr);
  1.1056 +        }
  1.1057 +        mFaceNamesMissed = nullptr;
  1.1058 +    }
  1.1059 +
  1.1060 +    if (mOtherNamesMissed) {
  1.1061 +        LookupMissedOtherNamesData othernamesdata(this);
  1.1062 +        mOtherNamesMissed->EnumerateEntries(LookupMissedOtherNamesProc,
  1.1063 +                                            &othernamesdata);
  1.1064 +        mOtherNamesMissed = nullptr;
  1.1065 +        if (othernamesdata.mFoundName) {
  1.1066 +            forceReflow = true;
  1.1067 +            ForceGlobalReflow();
  1.1068 +        }
  1.1069 +    }
  1.1070 +
  1.1071 +#ifdef PR_LOGGING
  1.1072 +    if (LOG_FONTINIT_ENABLED() && mFontInfo) {
  1.1073 +        LOG_FONTINIT(("(fontinit) fontloader load thread took %8.2f ms "
  1.1074 +                      "%d families %d fonts %d cmaps "
  1.1075 +                      "%d facenames %d othernames %s %s",
  1.1076 +                      mLoadTime.ToMilliseconds(),
  1.1077 +                      mFontInfo->mLoadStats.families,
  1.1078 +                      mFontInfo->mLoadStats.fonts,
  1.1079 +                      mFontInfo->mLoadStats.cmaps,
  1.1080 +                      mFontInfo->mLoadStats.facenames,
  1.1081 +                      mFontInfo->mLoadStats.othernames,
  1.1082 +                      (rebuilt ? "(userfont sets rebuilt)" : ""),
  1.1083 +                      (forceReflow ? "(global reflow)" : "")));
  1.1084 +    }
  1.1085 +#endif
  1.1086 +
  1.1087 +    gfxFontInfoLoader::CleanupLoader();
  1.1088 +}
  1.1089 +
  1.1090 +void
  1.1091 +gfxPlatformFontList::GetPrefsAndStartLoader()
  1.1092 +{
  1.1093 +    mIncrement =
  1.1094 +        std::max(1u, Preferences::GetUint(FONT_LOADER_FAMILIES_PER_SLICE_PREF));
  1.1095 +
  1.1096 +    uint32_t delay =
  1.1097 +        std::max(1u, Preferences::GetUint(FONT_LOADER_DELAY_PREF));
  1.1098 +    uint32_t interval =
  1.1099 +        std::max(1u, Preferences::GetUint(FONT_LOADER_INTERVAL_PREF));
  1.1100 +
  1.1101 +    StartLoader(delay, interval);
  1.1102 +}
  1.1103 +
  1.1104 +void
  1.1105 +gfxPlatformFontList::ForceGlobalReflow()
  1.1106 +{
  1.1107 +    // modify a preference that will trigger reflow everywhere
  1.1108 +    static const char kPrefName[] = "font.internaluseonly.changed";
  1.1109 +    bool fontInternalChange = Preferences::GetBool(kPrefName, false);
  1.1110 +    Preferences::SetBool(kPrefName, !fontInternalChange);
  1.1111 +}
  1.1112 +
  1.1113 +// Support for memory reporting
  1.1114 +
  1.1115 +static size_t
  1.1116 +SizeOfFamilyEntryExcludingThis(const nsAString&               aKey,
  1.1117 +                               const nsRefPtr<gfxFontFamily>& aFamily,
  1.1118 +                               MallocSizeOf                   aMallocSizeOf,
  1.1119 +                               void*                          aUserArg)
  1.1120 +{
  1.1121 +    FontListSizes *sizes = static_cast<FontListSizes*>(aUserArg);
  1.1122 +    aFamily->AddSizeOfExcludingThis(aMallocSizeOf, sizes);
  1.1123 +
  1.1124 +    sizes->mFontListSize += aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
  1.1125 +
  1.1126 +    // we return zero here because the measurements have been added directly
  1.1127 +    // to the relevant fields of the FontListSizes record
  1.1128 +    return 0;
  1.1129 +}
  1.1130 +
  1.1131 +// this is also used by subclasses that hold additional hashes of family names
  1.1132 +/*static*/ size_t
  1.1133 +gfxPlatformFontList::SizeOfFamilyNameEntryExcludingThis
  1.1134 +    (const nsAString&               aKey,
  1.1135 +     const nsRefPtr<gfxFontFamily>& aFamily,
  1.1136 +     MallocSizeOf                   aMallocSizeOf,
  1.1137 +     void*                          aUserArg)
  1.1138 +{
  1.1139 +    // we don't count the size of the family here, because this is an *extra*
  1.1140 +    // reference to a family that will have already been counted in the main list
  1.1141 +    return aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
  1.1142 +}
  1.1143 +
  1.1144 +static size_t
  1.1145 +SizeOfFontNameEntryExcludingThis(const nsAString&              aKey,
  1.1146 +                                 const nsRefPtr<gfxFontEntry>& aFont,
  1.1147 +                                 MallocSizeOf                  aMallocSizeOf,
  1.1148 +                                 void*                         aUserArg)
  1.1149 +{
  1.1150 +    // the font itself is counted by its owning family; here we only care about
  1.1151 +    // the name stored in the hashtable key
  1.1152 +    return aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
  1.1153 +}
  1.1154 +
  1.1155 +static size_t
  1.1156 +SizeOfPrefFontEntryExcludingThis
  1.1157 +    (const uint32_t&                           aKey,
  1.1158 +     const nsTArray<nsRefPtr<gfxFontFamily> >& aList,
  1.1159 +     MallocSizeOf                              aMallocSizeOf,
  1.1160 +     void*                                     aUserArg)
  1.1161 +{
  1.1162 +    // again, we only care about the size of the array itself; we don't follow
  1.1163 +    // the refPtrs stored in it, because they point to entries already owned
  1.1164 +    // and accounted-for by the main font list
  1.1165 +    return aList.SizeOfExcludingThis(aMallocSizeOf);
  1.1166 +}
  1.1167 +
  1.1168 +static size_t
  1.1169 +SizeOfStringEntryExcludingThis(nsStringHashKey*  aHashEntry,
  1.1170 +                               MallocSizeOf      aMallocSizeOf,
  1.1171 +                               void*             aUserArg)
  1.1172 +{
  1.1173 +    return aHashEntry->GetKey().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
  1.1174 +}
  1.1175 +
  1.1176 +static size_t
  1.1177 +SizeOfSharedCmapExcludingThis(CharMapHashKey*   aHashEntry,
  1.1178 +                              MallocSizeOf      aMallocSizeOf,
  1.1179 +                              void*             aUserArg)
  1.1180 +{
  1.1181 +    FontListSizes *sizes = static_cast<FontListSizes*>(aUserArg);
  1.1182 +
  1.1183 +    uint32_t size = aHashEntry->GetKey()->SizeOfIncludingThis(aMallocSizeOf);
  1.1184 +    sizes->mCharMapsSize += size;
  1.1185 +
  1.1186 +    // we return zero here because the measurements have been added directly
  1.1187 +    // to the relevant fields of the FontListSizes record
  1.1188 +    return 0;
  1.1189 +}
  1.1190 +
  1.1191 +void
  1.1192 +gfxPlatformFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
  1.1193 +                                            FontListSizes* aSizes) const
  1.1194 +{
  1.1195 +    aSizes->mFontListSize +=
  1.1196 +        mFontFamilies.SizeOfExcludingThis(SizeOfFamilyEntryExcludingThis,
  1.1197 +                                          aMallocSizeOf, aSizes);
  1.1198 +
  1.1199 +    aSizes->mFontListSize +=
  1.1200 +        mOtherFamilyNames.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis,
  1.1201 +                                              aMallocSizeOf);
  1.1202 +
  1.1203 +    if (mExtraNames) {
  1.1204 +        aSizes->mFontListSize +=
  1.1205 +            mExtraNames->mFullnames.SizeOfExcludingThis(SizeOfFontNameEntryExcludingThis,
  1.1206 +                                                        aMallocSizeOf);
  1.1207 +        aSizes->mFontListSize +=
  1.1208 +            mExtraNames->mPostscriptNames.SizeOfExcludingThis(SizeOfFontNameEntryExcludingThis,
  1.1209 +                                                              aMallocSizeOf);
  1.1210 +    }
  1.1211 +
  1.1212 +    aSizes->mFontListSize +=
  1.1213 +        mCodepointsWithNoFonts.SizeOfExcludingThis(aMallocSizeOf);
  1.1214 +    aSizes->mFontListSize +=
  1.1215 +        mFontFamiliesToLoad.SizeOfExcludingThis(aMallocSizeOf);
  1.1216 +
  1.1217 +    aSizes->mFontListSize +=
  1.1218 +        mPrefFonts.SizeOfExcludingThis(SizeOfPrefFontEntryExcludingThis,
  1.1219 +                                       aMallocSizeOf);
  1.1220 +
  1.1221 +    aSizes->mFontListSize +=
  1.1222 +        mBadUnderlineFamilyNames.SizeOfExcludingThis(SizeOfStringEntryExcludingThis,
  1.1223 +                                                     aMallocSizeOf);
  1.1224 +
  1.1225 +    aSizes->mFontListSize +=
  1.1226 +        mSharedCmaps.SizeOfExcludingThis(SizeOfSharedCmapExcludingThis,
  1.1227 +                                         aMallocSizeOf, aSizes);
  1.1228 +}
  1.1229 +
  1.1230 +void
  1.1231 +gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
  1.1232 +                                            FontListSizes* aSizes) const
  1.1233 +{
  1.1234 +    aSizes->mFontListSize += aMallocSizeOf(this);
  1.1235 +    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
  1.1236 +}

mercurial