gfx/thebes/gfxPlatformFontList.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifdef MOZ_LOGGING
michael@0 7 #define FORCE_PR_LOG /* Allow logging in the release build */
michael@0 8 #endif
michael@0 9 #include "prlog.h"
michael@0 10
michael@0 11 #include "gfxPlatformFontList.h"
michael@0 12 #include "gfxUserFontSet.h"
michael@0 13
michael@0 14 #include "nsUnicharUtils.h"
michael@0 15 #include "nsUnicodeRange.h"
michael@0 16 #include "nsUnicodeProperties.h"
michael@0 17
michael@0 18 #include "mozilla/Attributes.h"
michael@0 19 #include "mozilla/Likely.h"
michael@0 20 #include "mozilla/MemoryReporting.h"
michael@0 21 #include "mozilla/Preferences.h"
michael@0 22 #include "mozilla/Telemetry.h"
michael@0 23 #include "mozilla/TimeStamp.h"
michael@0 24 #include "mozilla/gfx/2D.h"
michael@0 25
michael@0 26 using namespace mozilla;
michael@0 27
michael@0 28 #ifdef PR_LOGGING
michael@0 29
michael@0 30 #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
michael@0 31 PR_LOG_DEBUG, args)
michael@0 32 #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
michael@0 33 gfxPlatform::GetLog(eGfxLog_fontlist), \
michael@0 34 PR_LOG_DEBUG)
michael@0 35 #define LOG_FONTINIT(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
michael@0 36 PR_LOG_DEBUG, args)
michael@0 37 #define LOG_FONTINIT_ENABLED() PR_LOG_TEST( \
michael@0 38 gfxPlatform::GetLog(eGfxLog_fontinit), \
michael@0 39 PR_LOG_DEBUG)
michael@0 40
michael@0 41 #endif // PR_LOGGING
michael@0 42
michael@0 43 gfxPlatformFontList *gfxPlatformFontList::sPlatformFontList = nullptr;
michael@0 44
michael@0 45 // Character ranges that require complex-script shaping support in the font,
michael@0 46 // and so should be masked out by ReadCMAP if the necessary layout tables
michael@0 47 // are not present.
michael@0 48 // Currently used by the Mac and FT2 implementations only, but probably should
michael@0 49 // be supported on Windows as well.
michael@0 50 const gfxFontEntry::ScriptRange gfxPlatformFontList::sComplexScriptRanges[] = {
michael@0 51 // Actually, now that harfbuzz supports presentation-forms shaping for
michael@0 52 // Arabic, we can render it without layout tables. So maybe we don't
michael@0 53 // want to mask the basic Arabic block here?
michael@0 54 // This affects the arabic-fallback-*.html reftests, which rely on
michael@0 55 // loading a font that *doesn't* have any GSUB table.
michael@0 56 { 0x0600, 0x06FF, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
michael@0 57 { 0x0700, 0x074F, { TRUETYPE_TAG('s','y','r','c'), 0, 0 } },
michael@0 58 { 0x0750, 0x077F, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
michael@0 59 { 0x08A0, 0x08FF, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } },
michael@0 60 { 0x0900, 0x097F, { TRUETYPE_TAG('d','e','v','2'),
michael@0 61 TRUETYPE_TAG('d','e','v','a'), 0 } },
michael@0 62 { 0x0980, 0x09FF, { TRUETYPE_TAG('b','n','g','2'),
michael@0 63 TRUETYPE_TAG('b','e','n','g'), 0 } },
michael@0 64 { 0x0A00, 0x0A7F, { TRUETYPE_TAG('g','u','r','2'),
michael@0 65 TRUETYPE_TAG('g','u','r','u'), 0 } },
michael@0 66 { 0x0A80, 0x0AFF, { TRUETYPE_TAG('g','j','r','2'),
michael@0 67 TRUETYPE_TAG('g','u','j','r'), 0 } },
michael@0 68 { 0x0B00, 0x0B7F, { TRUETYPE_TAG('o','r','y','2'),
michael@0 69 TRUETYPE_TAG('o','r','y','a'), 0 } },
michael@0 70 { 0x0B80, 0x0BFF, { TRUETYPE_TAG('t','m','l','2'),
michael@0 71 TRUETYPE_TAG('t','a','m','l'), 0 } },
michael@0 72 { 0x0C00, 0x0C7F, { TRUETYPE_TAG('t','e','l','2'),
michael@0 73 TRUETYPE_TAG('t','e','l','u'), 0 } },
michael@0 74 { 0x0C80, 0x0CFF, { TRUETYPE_TAG('k','n','d','2'),
michael@0 75 TRUETYPE_TAG('k','n','d','a'), 0 } },
michael@0 76 { 0x0D00, 0x0D7F, { TRUETYPE_TAG('m','l','m','2'),
michael@0 77 TRUETYPE_TAG('m','l','y','m'), 0 } },
michael@0 78 { 0x0D80, 0x0DFF, { TRUETYPE_TAG('s','i','n','h'), 0, 0 } },
michael@0 79 { 0x0E80, 0x0EFF, { TRUETYPE_TAG('l','a','o',' '), 0, 0 } },
michael@0 80 { 0x0F00, 0x0FFF, { TRUETYPE_TAG('t','i','b','t'), 0, 0 } },
michael@0 81 { 0x1000, 0x109f, { TRUETYPE_TAG('m','y','m','r'),
michael@0 82 TRUETYPE_TAG('m','y','m','2'), 0 } },
michael@0 83 { 0x1780, 0x17ff, { TRUETYPE_TAG('k','h','m','r'), 0, 0 } },
michael@0 84 // Khmer Symbols (19e0..19ff) don't seem to need any special shaping
michael@0 85 { 0xaa60, 0xaa7f, { TRUETYPE_TAG('m','y','m','r'),
michael@0 86 TRUETYPE_TAG('m','y','m','2'), 0 } },
michael@0 87 // Thai seems to be "renderable" without AAT morphing tables
michael@0 88 { 0, 0, { 0, 0, 0 } } // terminator
michael@0 89 };
michael@0 90
michael@0 91 // prefs for the font info loader
michael@0 92 #define FONT_LOADER_FAMILIES_PER_SLICE_PREF "gfx.font_loader.families_per_slice"
michael@0 93 #define FONT_LOADER_DELAY_PREF "gfx.font_loader.delay"
michael@0 94 #define FONT_LOADER_INTERVAL_PREF "gfx.font_loader.interval"
michael@0 95
michael@0 96 static const char* kObservedPrefs[] = {
michael@0 97 "font.",
michael@0 98 "font.name-list.",
michael@0 99 "intl.accept_languages", // hmmmm...
michael@0 100 nullptr
michael@0 101 };
michael@0 102
michael@0 103 class gfxFontListPrefObserver MOZ_FINAL : public nsIObserver {
michael@0 104 public:
michael@0 105 NS_DECL_ISUPPORTS
michael@0 106 NS_DECL_NSIOBSERVER
michael@0 107 };
michael@0 108
michael@0 109 static gfxFontListPrefObserver* gFontListPrefObserver = nullptr;
michael@0 110
michael@0 111 NS_IMPL_ISUPPORTS(gfxFontListPrefObserver, nsIObserver)
michael@0 112
michael@0 113 NS_IMETHODIMP
michael@0 114 gfxFontListPrefObserver::Observe(nsISupports *aSubject,
michael@0 115 const char *aTopic,
michael@0 116 const char16_t *aData)
michael@0 117 {
michael@0 118 NS_ASSERTION(!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID), "invalid topic");
michael@0 119 // XXX this could be made to only clear out the cache for the prefs that were changed
michael@0 120 // but it probably isn't that big a deal.
michael@0 121 gfxPlatformFontList::PlatformFontList()->ClearPrefFonts();
michael@0 122 gfxFontCache::GetCache()->AgeAllGenerations();
michael@0 123 return NS_OK;
michael@0 124 }
michael@0 125
michael@0 126 MOZ_DEFINE_MALLOC_SIZE_OF(FontListMallocSizeOf)
michael@0 127
michael@0 128 NS_IMPL_ISUPPORTS(gfxPlatformFontList::MemoryReporter, nsIMemoryReporter)
michael@0 129
michael@0 130 NS_IMETHODIMP
michael@0 131 gfxPlatformFontList::MemoryReporter::CollectReports
michael@0 132 (nsIMemoryReporterCallback* aCb,
michael@0 133 nsISupports* aClosure)
michael@0 134 {
michael@0 135 FontListSizes sizes;
michael@0 136 sizes.mFontListSize = 0;
michael@0 137 sizes.mFontTableCacheSize = 0;
michael@0 138 sizes.mCharMapsSize = 0;
michael@0 139
michael@0 140 gfxPlatformFontList::PlatformFontList()->AddSizeOfIncludingThis(&FontListMallocSizeOf,
michael@0 141 &sizes);
michael@0 142
michael@0 143 aCb->Callback(EmptyCString(),
michael@0 144 NS_LITERAL_CSTRING("explicit/gfx/font-list"),
michael@0 145 KIND_HEAP, UNITS_BYTES, sizes.mFontListSize,
michael@0 146 NS_LITERAL_CSTRING("Memory used to manage the list of font families and faces."),
michael@0 147 aClosure);
michael@0 148
michael@0 149 aCb->Callback(EmptyCString(),
michael@0 150 NS_LITERAL_CSTRING("explicit/gfx/font-charmaps"),
michael@0 151 KIND_HEAP, UNITS_BYTES, sizes.mCharMapsSize,
michael@0 152 NS_LITERAL_CSTRING("Memory used to record the character coverage of individual fonts."),
michael@0 153 aClosure);
michael@0 154
michael@0 155 if (sizes.mFontTableCacheSize) {
michael@0 156 aCb->Callback(EmptyCString(),
michael@0 157 NS_LITERAL_CSTRING("explicit/gfx/font-tables"),
michael@0 158 KIND_HEAP, UNITS_BYTES, sizes.mFontTableCacheSize,
michael@0 159 NS_LITERAL_CSTRING("Memory used for cached font metrics and layout tables."),
michael@0 160 aClosure);
michael@0 161 }
michael@0 162
michael@0 163 return NS_OK;
michael@0 164 }
michael@0 165
michael@0 166 gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
michael@0 167 : mFontFamilies(100), mOtherFamilyNames(30),
michael@0 168 mPrefFonts(10), mBadUnderlineFamilyNames(10), mSharedCmaps(16),
michael@0 169 mStartIndex(0), mIncrement(1), mNumFamilies(0)
michael@0 170 {
michael@0 171 mOtherFamilyNamesInitialized = false;
michael@0 172
michael@0 173 if (aNeedFullnamePostscriptNames) {
michael@0 174 mExtraNames = new ExtraNames();
michael@0 175 }
michael@0 176 mFaceNameListsInitialized = false;
michael@0 177
michael@0 178 LoadBadUnderlineList();
michael@0 179
michael@0 180 // pref changes notification setup
michael@0 181 NS_ASSERTION(!gFontListPrefObserver,
michael@0 182 "There has been font list pref observer already");
michael@0 183 gFontListPrefObserver = new gfxFontListPrefObserver();
michael@0 184 NS_ADDREF(gFontListPrefObserver);
michael@0 185 Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs);
michael@0 186
michael@0 187 RegisterStrongMemoryReporter(new MemoryReporter());
michael@0 188 }
michael@0 189
michael@0 190 gfxPlatformFontList::~gfxPlatformFontList()
michael@0 191 {
michael@0 192 mSharedCmaps.Clear();
michael@0 193 NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
michael@0 194 Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs);
michael@0 195 NS_RELEASE(gFontListPrefObserver);
michael@0 196 }
michael@0 197
michael@0 198 nsresult
michael@0 199 gfxPlatformFontList::InitFontList()
michael@0 200 {
michael@0 201 mFontFamilies.Clear();
michael@0 202 mOtherFamilyNames.Clear();
michael@0 203 mOtherFamilyNamesInitialized = false;
michael@0 204 if (mExtraNames) {
michael@0 205 mExtraNames->mFullnames.Clear();
michael@0 206 mExtraNames->mPostscriptNames.Clear();
michael@0 207 }
michael@0 208 mFaceNameListsInitialized = false;
michael@0 209 mPrefFonts.Clear();
michael@0 210 mReplacementCharFallbackFamily = nullptr;
michael@0 211 CancelLoader();
michael@0 212
michael@0 213 // initialize ranges of characters for which system-wide font search should be skipped
michael@0 214 mCodepointsWithNoFonts.reset();
michael@0 215 mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
michael@0 216 mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
michael@0 217
michael@0 218 sPlatformFontList = this;
michael@0 219
michael@0 220 return NS_OK;
michael@0 221 }
michael@0 222
michael@0 223 void
michael@0 224 gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
michael@0 225 {
michael@0 226 aResult = aKeyName;
michael@0 227 ToLowerCase(aResult);
michael@0 228 }
michael@0 229
michael@0 230 struct InitOtherNamesData {
michael@0 231 InitOtherNamesData(gfxPlatformFontList *aFontList,
michael@0 232 TimeStamp aStartTime)
michael@0 233 : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false)
michael@0 234 {}
michael@0 235
michael@0 236 gfxPlatformFontList *mFontList;
michael@0 237 TimeStamp mStartTime;
michael@0 238 bool mTimedOut;
michael@0 239 };
michael@0 240
michael@0 241 void
michael@0 242 gfxPlatformFontList::InitOtherFamilyNames()
michael@0 243 {
michael@0 244 if (mOtherFamilyNamesInitialized) {
michael@0 245 return;
michael@0 246 }
michael@0 247
michael@0 248 TimeStamp start = TimeStamp::Now();
michael@0 249
michael@0 250 // iterate over all font families and read in other family names
michael@0 251 InitOtherNamesData otherNamesData(this, start);
michael@0 252
michael@0 253 mFontFamilies.Enumerate(gfxPlatformFontList::InitOtherFamilyNamesProc,
michael@0 254 &otherNamesData);
michael@0 255
michael@0 256 if (!otherNamesData.mTimedOut) {
michael@0 257 mOtherFamilyNamesInitialized = true;
michael@0 258 }
michael@0 259 TimeStamp end = TimeStamp::Now();
michael@0 260 Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES,
michael@0 261 start, end);
michael@0 262
michael@0 263 #ifdef PR_LOGGING
michael@0 264 if (LOG_FONTINIT_ENABLED()) {
michael@0 265 TimeDuration elapsed = end - start;
michael@0 266 LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
michael@0 267 elapsed.ToMilliseconds(),
michael@0 268 (otherNamesData.mTimedOut ? "timeout" : "")));
michael@0 269 }
michael@0 270 #endif
michael@0 271 }
michael@0 272
michael@0 273 #define OTHERNAMES_TIMEOUT 200
michael@0 274
michael@0 275 PLDHashOperator
michael@0 276 gfxPlatformFontList::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
michael@0 277 nsRefPtr<gfxFontFamily>& aFamilyEntry,
michael@0 278 void* userArg)
michael@0 279 {
michael@0 280 InitOtherNamesData *data = static_cast<InitOtherNamesData*>(userArg);
michael@0 281
michael@0 282 aFamilyEntry->ReadOtherFamilyNames(data->mFontList);
michael@0 283 TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
michael@0 284 if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
michael@0 285 data->mTimedOut = true;
michael@0 286 return PL_DHASH_STOP;
michael@0 287 }
michael@0 288 return PL_DHASH_NEXT;
michael@0 289 }
michael@0 290
michael@0 291 struct ReadFaceNamesData {
michael@0 292 ReadFaceNamesData(gfxPlatformFontList *aFontList, TimeStamp aStartTime)
michael@0 293 : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false)
michael@0 294 {}
michael@0 295
michael@0 296 gfxPlatformFontList *mFontList;
michael@0 297 TimeStamp mStartTime;
michael@0 298 bool mTimedOut;
michael@0 299
michael@0 300 // if mFirstChar is not empty, only load facenames for families
michael@0 301 // that start with this character
michael@0 302 nsString mFirstChar;
michael@0 303 };
michael@0 304
michael@0 305 gfxFontEntry*
michael@0 306 gfxPlatformFontList::SearchFamiliesForFaceName(const nsAString& aFaceName)
michael@0 307 {
michael@0 308 TimeStamp start = TimeStamp::Now();
michael@0 309 gfxFontEntry *lookup = nullptr;
michael@0 310
michael@0 311 ReadFaceNamesData faceNameListsData(this, start);
michael@0 312
michael@0 313 // iterate over familes starting with the same letter
michael@0 314 faceNameListsData.mFirstChar.Assign(aFaceName.CharAt(0));
michael@0 315 ToLowerCase(faceNameListsData.mFirstChar);
michael@0 316 mFontFamilies.Enumerate(gfxPlatformFontList::ReadFaceNamesProc,
michael@0 317 &faceNameListsData);
michael@0 318 lookup = FindFaceName(aFaceName);
michael@0 319
michael@0 320 TimeStamp end = TimeStamp::Now();
michael@0 321 Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITFACENAMELISTS,
michael@0 322 start, end);
michael@0 323 #ifdef PR_LOGGING
michael@0 324 if (LOG_FONTINIT_ENABLED()) {
michael@0 325 TimeDuration elapsed = end - start;
michael@0 326 LOG_FONTINIT(("(fontinit) SearchFamiliesForFaceName took %8.2f ms %s %s",
michael@0 327 elapsed.ToMilliseconds(),
michael@0 328 (lookup ? "found name" : ""),
michael@0 329 (faceNameListsData.mTimedOut ? "timeout" : "")));
michael@0 330 }
michael@0 331 #endif
michael@0 332
michael@0 333 return lookup;
michael@0 334 }
michael@0 335
michael@0 336 // time limit for loading facename lists (ms)
michael@0 337 #define NAMELIST_TIMEOUT 200
michael@0 338
michael@0 339 PLDHashOperator
michael@0 340 gfxPlatformFontList::ReadFaceNamesProc(nsStringHashKey::KeyType aKey,
michael@0 341 nsRefPtr<gfxFontFamily>& aFamilyEntry,
michael@0 342 void* userArg)
michael@0 343 {
michael@0 344 ReadFaceNamesData *data = static_cast<ReadFaceNamesData*>(userArg);
michael@0 345 gfxPlatformFontList *fc = data->mFontList;
michael@0 346
michael@0 347 // when filtering, skip names that don't start with the filter character
michael@0 348 if (!(data->mFirstChar.IsEmpty())) {
michael@0 349 char16_t firstChar = aKey.CharAt(0);
michael@0 350 nsAutoString firstCharStr(&firstChar, 1);
michael@0 351 ToLowerCase(firstCharStr);
michael@0 352 if (!firstCharStr.Equals(data->mFirstChar)) {
michael@0 353 return PL_DHASH_NEXT;
michael@0 354 }
michael@0 355 }
michael@0 356 aFamilyEntry->ReadFaceNames(fc, fc->NeedFullnamePostscriptNames());
michael@0 357
michael@0 358 TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
michael@0 359 if (elapsed.ToMilliseconds() > NAMELIST_TIMEOUT) {
michael@0 360 data->mTimedOut = true;
michael@0 361 return PL_DHASH_STOP;
michael@0 362 }
michael@0 363 return PL_DHASH_NEXT;
michael@0 364 }
michael@0 365
michael@0 366 gfxFontEntry*
michael@0 367 gfxPlatformFontList::FindFaceName(const nsAString& aFaceName)
michael@0 368 {
michael@0 369 gfxFontEntry *lookup;
michael@0 370
michael@0 371 // lookup in name lookup tables, return null if not found
michael@0 372 if (mExtraNames &&
michael@0 373 ((lookup = mExtraNames->mPostscriptNames.GetWeak(aFaceName)) ||
michael@0 374 (lookup = mExtraNames->mFullnames.GetWeak(aFaceName)))) {
michael@0 375 return lookup;
michael@0 376 }
michael@0 377
michael@0 378 return nullptr;
michael@0 379 }
michael@0 380
michael@0 381 gfxFontEntry*
michael@0 382 gfxPlatformFontList::LookupInFaceNameLists(const nsAString& aFaceName)
michael@0 383 {
michael@0 384 gfxFontEntry *lookup = nullptr;
michael@0 385
michael@0 386 // initialize facename lookup tables if needed
michael@0 387 // note: this can terminate early or time out, in which case
michael@0 388 // mFaceNameListsInitialized remains false
michael@0 389 if (!mFaceNameListsInitialized) {
michael@0 390 lookup = SearchFamiliesForFaceName(aFaceName);
michael@0 391 if (lookup) {
michael@0 392 return lookup;
michael@0 393 }
michael@0 394 }
michael@0 395
michael@0 396 // lookup in name lookup tables, return null if not found
michael@0 397 if (!(lookup = FindFaceName(aFaceName))) {
michael@0 398 // names not completely initialized, so keep track of lookup misses
michael@0 399 if (!mFaceNameListsInitialized) {
michael@0 400 if (!mFaceNamesMissed) {
michael@0 401 mFaceNamesMissed = new nsTHashtable<nsStringHashKey>(4);
michael@0 402 }
michael@0 403 mFaceNamesMissed->PutEntry(aFaceName);
michael@0 404 }
michael@0 405 }
michael@0 406
michael@0 407 return lookup;
michael@0 408 }
michael@0 409
michael@0 410 void
michael@0 411 gfxPlatformFontList::PreloadNamesList()
michael@0 412 {
michael@0 413 nsAutoTArray<nsString, 10> preloadFonts;
michael@0 414 gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts);
michael@0 415
michael@0 416 uint32_t numFonts = preloadFonts.Length();
michael@0 417 for (uint32_t i = 0; i < numFonts; i++) {
michael@0 418 nsAutoString key;
michael@0 419 GenerateFontListKey(preloadFonts[i], key);
michael@0 420
michael@0 421 // only search canonical names!
michael@0 422 gfxFontFamily *familyEntry = mFontFamilies.GetWeak(key);
michael@0 423 if (familyEntry) {
michael@0 424 familyEntry->ReadOtherFamilyNames(this);
michael@0 425 }
michael@0 426 }
michael@0 427
michael@0 428 }
michael@0 429
michael@0 430 void
michael@0 431 gfxPlatformFontList::SetFixedPitch(const nsAString& aFamilyName)
michael@0 432 {
michael@0 433 gfxFontFamily *family = FindFamily(aFamilyName);
michael@0 434 if (!family) return;
michael@0 435
michael@0 436 family->FindStyleVariations();
michael@0 437 nsTArray<nsRefPtr<gfxFontEntry> >& fontlist = family->GetFontList();
michael@0 438
michael@0 439 uint32_t i, numFonts = fontlist.Length();
michael@0 440
michael@0 441 for (i = 0; i < numFonts; i++) {
michael@0 442 fontlist[i]->mFixedPitch = 1;
michael@0 443 }
michael@0 444 }
michael@0 445
michael@0 446 void
michael@0 447 gfxPlatformFontList::LoadBadUnderlineList()
michael@0 448 {
michael@0 449 nsAutoTArray<nsString, 10> blacklist;
michael@0 450 gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
michael@0 451 uint32_t numFonts = blacklist.Length();
michael@0 452 for (uint32_t i = 0; i < numFonts; i++) {
michael@0 453 nsAutoString key;
michael@0 454 GenerateFontListKey(blacklist[i], key);
michael@0 455 mBadUnderlineFamilyNames.PutEntry(key);
michael@0 456 }
michael@0 457 }
michael@0 458
michael@0 459 bool
michael@0 460 gfxPlatformFontList::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
michael@0 461 {
michael@0 462 gfxFontFamily *family = FindFamily(aFontName);
michael@0 463 if (family) {
michael@0 464 aResolvedFontName = family->Name();
michael@0 465 return true;
michael@0 466 }
michael@0 467 return false;
michael@0 468 }
michael@0 469
michael@0 470 static PLDHashOperator
michael@0 471 RebuildLocalFonts(nsPtrHashKey<gfxUserFontSet>* aKey,
michael@0 472 void* aClosure)
michael@0 473 {
michael@0 474 aKey->GetKey()->RebuildLocalRules();
michael@0 475 return PL_DHASH_NEXT;
michael@0 476 }
michael@0 477
michael@0 478 void
michael@0 479 gfxPlatformFontList::UpdateFontList()
michael@0 480 {
michael@0 481 InitFontList();
michael@0 482 mUserFontSetList.EnumerateEntries(RebuildLocalFonts, nullptr);
michael@0 483 }
michael@0 484
michael@0 485 struct FontListData {
michael@0 486 FontListData(nsIAtom *aLangGroup,
michael@0 487 const nsACString& aGenericFamily,
michael@0 488 nsTArray<nsString>& aListOfFonts) :
michael@0 489 mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
michael@0 490 mListOfFonts(aListOfFonts) {}
michael@0 491 nsIAtom *mLangGroup;
michael@0 492 const nsACString& mGenericFamily;
michael@0 493 nsTArray<nsString>& mListOfFonts;
michael@0 494 };
michael@0 495
michael@0 496 PLDHashOperator
michael@0 497 gfxPlatformFontList::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
michael@0 498 nsRefPtr<gfxFontFamily>& aFamilyEntry,
michael@0 499 void *aUserArg)
michael@0 500 {
michael@0 501 FontListData *data = static_cast<FontListData*>(aUserArg);
michael@0 502
michael@0 503 // use the first variation for now. This data should be the same
michael@0 504 // for all the variations and should probably be moved up to
michael@0 505 // the Family
michael@0 506 gfxFontStyle style;
michael@0 507 style.language = data->mLangGroup;
michael@0 508 bool needsBold;
michael@0 509 nsRefPtr<gfxFontEntry> aFontEntry = aFamilyEntry->FindFontForStyle(style, needsBold);
michael@0 510 NS_ASSERTION(aFontEntry, "couldn't find any font entry in family");
michael@0 511 if (!aFontEntry)
michael@0 512 return PL_DHASH_NEXT;
michael@0 513
michael@0 514 /* skip symbol fonts */
michael@0 515 if (aFontEntry->IsSymbolFont())
michael@0 516 return PL_DHASH_NEXT;
michael@0 517
michael@0 518 if (aFontEntry->SupportsLangGroup(data->mLangGroup) &&
michael@0 519 aFontEntry->MatchesGenericFamily(data->mGenericFamily)) {
michael@0 520 nsAutoString localizedFamilyName;
michael@0 521 aFamilyEntry->LocalizedName(localizedFamilyName);
michael@0 522 data->mListOfFonts.AppendElement(localizedFamilyName);
michael@0 523 }
michael@0 524
michael@0 525 return PL_DHASH_NEXT;
michael@0 526 }
michael@0 527
michael@0 528 void
michael@0 529 gfxPlatformFontList::GetFontList(nsIAtom *aLangGroup,
michael@0 530 const nsACString& aGenericFamily,
michael@0 531 nsTArray<nsString>& aListOfFonts)
michael@0 532 {
michael@0 533 FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
michael@0 534
michael@0 535 mFontFamilies.Enumerate(gfxPlatformFontList::HashEnumFuncForFamilies, &data);
michael@0 536
michael@0 537 aListOfFonts.Sort();
michael@0 538 aListOfFonts.Compact();
michael@0 539 }
michael@0 540
michael@0 541 struct FontFamilyListData {
michael@0 542 FontFamilyListData(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
michael@0 543 : mFamilyArray(aFamilyArray)
michael@0 544 {}
michael@0 545
michael@0 546 static PLDHashOperator AppendFamily(nsStringHashKey::KeyType aKey,
michael@0 547 nsRefPtr<gfxFontFamily>& aFamilyEntry,
michael@0 548 void *aUserArg)
michael@0 549 {
michael@0 550 FontFamilyListData *data = static_cast<FontFamilyListData*>(aUserArg);
michael@0 551 data->mFamilyArray.AppendElement(aFamilyEntry);
michael@0 552 return PL_DHASH_NEXT;
michael@0 553 }
michael@0 554
michael@0 555 nsTArray<nsRefPtr<gfxFontFamily> >& mFamilyArray;
michael@0 556 };
michael@0 557
michael@0 558 void
michael@0 559 gfxPlatformFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
michael@0 560 {
michael@0 561 FontFamilyListData data(aFamilyArray);
michael@0 562 mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
michael@0 563 }
michael@0 564
michael@0 565 gfxFontEntry*
michael@0 566 gfxPlatformFontList::SystemFindFontForChar(const uint32_t aCh,
michael@0 567 int32_t aRunScript,
michael@0 568 const gfxFontStyle* aStyle)
michael@0 569 {
michael@0 570 gfxFontEntry* fontEntry = nullptr;
michael@0 571
michael@0 572 // is codepoint with no matching font? return null immediately
michael@0 573 if (mCodepointsWithNoFonts.test(aCh)) {
michael@0 574 return nullptr;
michael@0 575 }
michael@0 576
michael@0 577 // Try to short-circuit font fallback for U+FFFD, used to represent
michael@0 578 // encoding errors: just use cached family from last time U+FFFD was seen.
michael@0 579 // This helps speed up pages with lots of encoding errors, binary-as-text,
michael@0 580 // etc.
michael@0 581 if (aCh == 0xFFFD && mReplacementCharFallbackFamily) {
michael@0 582 bool needsBold; // ignored in the system fallback case
michael@0 583
michael@0 584 fontEntry =
michael@0 585 mReplacementCharFallbackFamily->FindFontForStyle(*aStyle,
michael@0 586 needsBold);
michael@0 587
michael@0 588 // this should never fail, as we must have found U+FFFD in order to set
michael@0 589 // mReplacementCharFallbackFamily at all, but better play it safe
michael@0 590 if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
michael@0 591 return fontEntry;
michael@0 592 }
michael@0 593 }
michael@0 594
michael@0 595 TimeStamp start = TimeStamp::Now();
michael@0 596
michael@0 597 // search commonly available fonts
michael@0 598 bool common = true;
michael@0 599 gfxFontFamily *fallbackFamily = nullptr;
michael@0 600 fontEntry = CommonFontFallback(aCh, aRunScript, aStyle, &fallbackFamily);
michael@0 601
michael@0 602 // if didn't find a font, do system-wide fallback (except for specials)
michael@0 603 uint32_t cmapCount = 0;
michael@0 604 if (!fontEntry) {
michael@0 605 common = false;
michael@0 606 fontEntry = GlobalFontFallback(aCh, aRunScript, aStyle, cmapCount,
michael@0 607 &fallbackFamily);
michael@0 608 }
michael@0 609 TimeDuration elapsed = TimeStamp::Now() - start;
michael@0 610
michael@0 611 #ifdef PR_LOGGING
michael@0 612 PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textrun);
michael@0 613
michael@0 614 if (MOZ_UNLIKELY(PR_LOG_TEST(log, PR_LOG_WARNING))) {
michael@0 615 uint32_t unicodeRange = FindCharUnicodeRange(aCh);
michael@0 616 int32_t script = mozilla::unicode::GetScriptCode(aCh);
michael@0 617 PR_LOG(log, PR_LOG_WARNING,\
michael@0 618 ("(textrun-systemfallback-%s) char: u+%6.6x "
michael@0 619 "unicode-range: %d script: %d match: [%s]"
michael@0 620 " time: %dus cmaps: %d\n",
michael@0 621 (common ? "common" : "global"), aCh,
michael@0 622 unicodeRange, script,
michael@0 623 (fontEntry ? NS_ConvertUTF16toUTF8(fontEntry->Name()).get() :
michael@0 624 "<none>"),
michael@0 625 int32_t(elapsed.ToMicroseconds()),
michael@0 626 cmapCount));
michael@0 627 }
michael@0 628 #endif
michael@0 629
michael@0 630 // no match? add to set of non-matching codepoints
michael@0 631 if (!fontEntry) {
michael@0 632 mCodepointsWithNoFonts.set(aCh);
michael@0 633 } else if (aCh == 0xFFFD && fontEntry && fallbackFamily) {
michael@0 634 mReplacementCharFallbackFamily = fallbackFamily;
michael@0 635 }
michael@0 636
michael@0 637 // track system fallback time
michael@0 638 static bool first = true;
michael@0 639 int32_t intElapsed = int32_t(first ? elapsed.ToMilliseconds() :
michael@0 640 elapsed.ToMicroseconds());
michael@0 641 Telemetry::Accumulate((first ? Telemetry::SYSTEM_FONT_FALLBACK_FIRST :
michael@0 642 Telemetry::SYSTEM_FONT_FALLBACK),
michael@0 643 intElapsed);
michael@0 644 first = false;
michael@0 645
michael@0 646 // track the script for which fallback occurred (incremented one make it
michael@0 647 // 1-based)
michael@0 648 Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT, aRunScript + 1);
michael@0 649
michael@0 650 return fontEntry;
michael@0 651 }
michael@0 652
michael@0 653 PLDHashOperator
michael@0 654 gfxPlatformFontList::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<gfxFontFamily>& aFamilyEntry,
michael@0 655 void *userArg)
michael@0 656 {
michael@0 657 GlobalFontMatch *data = static_cast<GlobalFontMatch*>(userArg);
michael@0 658
michael@0 659 // evaluate all fonts in this family for a match
michael@0 660 aFamilyEntry->FindFontForChar(data);
michael@0 661
michael@0 662 return PL_DHASH_NEXT;
michael@0 663 }
michael@0 664
michael@0 665 #define NUM_FALLBACK_FONTS 8
michael@0 666
michael@0 667 gfxFontEntry*
michael@0 668 gfxPlatformFontList::CommonFontFallback(const uint32_t aCh,
michael@0 669 int32_t aRunScript,
michael@0 670 const gfxFontStyle* aMatchStyle,
michael@0 671 gfxFontFamily** aMatchedFamily)
michael@0 672 {
michael@0 673 nsAutoTArray<const char*,NUM_FALLBACK_FONTS> defaultFallbacks;
michael@0 674 uint32_t i, numFallbacks;
michael@0 675
michael@0 676 gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh, aRunScript,
michael@0 677 defaultFallbacks);
michael@0 678 numFallbacks = defaultFallbacks.Length();
michael@0 679 for (i = 0; i < numFallbacks; i++) {
michael@0 680 nsAutoString familyName;
michael@0 681 const char *fallbackFamily = defaultFallbacks[i];
michael@0 682
michael@0 683 familyName.AppendASCII(fallbackFamily);
michael@0 684 gfxFontFamily *fallback =
michael@0 685 gfxPlatformFontList::PlatformFontList()->FindFamily(familyName);
michael@0 686 if (!fallback)
michael@0 687 continue;
michael@0 688
michael@0 689 gfxFontEntry *fontEntry;
michael@0 690 bool needsBold; // ignored in the system fallback case
michael@0 691
michael@0 692 // use first font in list that supports a given character
michael@0 693 fontEntry = fallback->FindFontForStyle(*aMatchStyle, needsBold);
michael@0 694 if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
michael@0 695 *aMatchedFamily = fallback;
michael@0 696 return fontEntry;
michael@0 697 }
michael@0 698 }
michael@0 699
michael@0 700 return nullptr;
michael@0 701 }
michael@0 702
michael@0 703 gfxFontEntry*
michael@0 704 gfxPlatformFontList::GlobalFontFallback(const uint32_t aCh,
michael@0 705 int32_t aRunScript,
michael@0 706 const gfxFontStyle* aMatchStyle,
michael@0 707 uint32_t& aCmapCount,
michael@0 708 gfxFontFamily** aMatchedFamily)
michael@0 709 {
michael@0 710 // otherwise, try to find it among local fonts
michael@0 711 GlobalFontMatch data(aCh, aRunScript, aMatchStyle);
michael@0 712
michael@0 713 // iterate over all font families to find a font that support the character
michael@0 714 mFontFamilies.Enumerate(gfxPlatformFontList::FindFontForCharProc, &data);
michael@0 715
michael@0 716 aCmapCount = data.mCmapsTested;
michael@0 717 *aMatchedFamily = data.mMatchedFamily;
michael@0 718
michael@0 719 return data.mBestMatch;
michael@0 720 }
michael@0 721
michael@0 722 #ifdef XP_WIN
michael@0 723 #include <windows.h>
michael@0 724
michael@0 725 // crude hack for using when monitoring process
michael@0 726 static void LogRegistryEvent(const wchar_t *msg)
michael@0 727 {
michael@0 728 HKEY dummyKey;
michael@0 729 HRESULT hr;
michael@0 730 wchar_t buf[512];
michael@0 731
michael@0 732 wsprintfW(buf, L" log %s", msg);
michael@0 733 hr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
michael@0 734 if (SUCCEEDED(hr)) {
michael@0 735 RegCloseKey(dummyKey);
michael@0 736 }
michael@0 737 }
michael@0 738 #endif
michael@0 739
michael@0 740 gfxFontFamily*
michael@0 741 gfxPlatformFontList::CheckFamily(gfxFontFamily *aFamily)
michael@0 742 {
michael@0 743 if (aFamily && !aFamily->HasStyles()) {
michael@0 744 aFamily->FindStyleVariations();
michael@0 745 aFamily->CheckForSimpleFamily();
michael@0 746 }
michael@0 747
michael@0 748 if (aFamily && aFamily->GetFontList().Length() == 0) {
michael@0 749 // failed to load any faces for this family, so discard it
michael@0 750 nsAutoString key;
michael@0 751 GenerateFontListKey(aFamily->Name(), key);
michael@0 752 mFontFamilies.Remove(key);
michael@0 753 return nullptr;
michael@0 754 }
michael@0 755
michael@0 756 return aFamily;
michael@0 757 }
michael@0 758
michael@0 759 gfxFontFamily*
michael@0 760 gfxPlatformFontList::FindFamily(const nsAString& aFamily)
michael@0 761 {
michael@0 762 nsAutoString key;
michael@0 763 gfxFontFamily *familyEntry;
michael@0 764 GenerateFontListKey(aFamily, key);
michael@0 765
michael@0 766 NS_ASSERTION(mFontFamilies.Count() != 0, "system font list was not initialized correctly");
michael@0 767
michael@0 768 // lookup in canonical (i.e. English) family name list
michael@0 769 if ((familyEntry = mFontFamilies.GetWeak(key))) {
michael@0 770 return CheckFamily(familyEntry);
michael@0 771 }
michael@0 772
michael@0 773 // lookup in other family names list (mostly localized names)
michael@0 774 if ((familyEntry = mOtherFamilyNames.GetWeak(key)) != nullptr) {
michael@0 775 return CheckFamily(familyEntry);
michael@0 776 }
michael@0 777
michael@0 778 // name not found and other family names not yet fully initialized so
michael@0 779 // initialize the rest of the list and try again. this is done lazily
michael@0 780 // since reading name table entries is expensive.
michael@0 781 // although ASCII localized family names are possible they don't occur
michael@0 782 // in practice so avoid pulling in names at startup
michael@0 783 if (!mOtherFamilyNamesInitialized && !IsASCII(aFamily)) {
michael@0 784 InitOtherFamilyNames();
michael@0 785 if ((familyEntry = mOtherFamilyNames.GetWeak(key)) != nullptr) {
michael@0 786 return CheckFamily(familyEntry);
michael@0 787 } else if (!mOtherFamilyNamesInitialized) {
michael@0 788 // localized family names load timed out, add name to list of
michael@0 789 // names to check after localized names are loaded
michael@0 790 if (!mOtherNamesMissed) {
michael@0 791 mOtherNamesMissed = new nsTHashtable<nsStringHashKey>(4);
michael@0 792 }
michael@0 793 mOtherNamesMissed->PutEntry(key);
michael@0 794 }
michael@0 795 }
michael@0 796
michael@0 797 return nullptr;
michael@0 798 }
michael@0 799
michael@0 800 gfxFontEntry*
michael@0 801 gfxPlatformFontList::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold)
michael@0 802 {
michael@0 803 gfxFontFamily *familyEntry = FindFamily(aFamily);
michael@0 804
michael@0 805 aNeedsBold = false;
michael@0 806
michael@0 807 if (familyEntry)
michael@0 808 return familyEntry->FindFontForStyle(*aStyle, aNeedsBold);
michael@0 809
michael@0 810 return nullptr;
michael@0 811 }
michael@0 812
michael@0 813 bool
michael@0 814 gfxPlatformFontList::GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> > *array)
michael@0 815 {
michael@0 816 return mPrefFonts.Get(uint32_t(aLangGroup), array);
michael@0 817 }
michael@0 818
michael@0 819 void
michael@0 820 gfxPlatformFontList::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> >& array)
michael@0 821 {
michael@0 822 mPrefFonts.Put(uint32_t(aLangGroup), array);
michael@0 823 }
michael@0 824
michael@0 825 void
michael@0 826 gfxPlatformFontList::AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName)
michael@0 827 {
michael@0 828 nsAutoString key;
michael@0 829 GenerateFontListKey(aOtherFamilyName, key);
michael@0 830
michael@0 831 if (!mOtherFamilyNames.GetWeak(key)) {
michael@0 832 mOtherFamilyNames.Put(key, aFamilyEntry);
michael@0 833 #ifdef PR_LOGGING
michael@0 834 LOG_FONTLIST(("(fontlist-otherfamily) canonical family: %s, "
michael@0 835 "other family: %s\n",
michael@0 836 NS_ConvertUTF16toUTF8(aFamilyEntry->Name()).get(),
michael@0 837 NS_ConvertUTF16toUTF8(aOtherFamilyName).get()));
michael@0 838 #endif
michael@0 839 if (mBadUnderlineFamilyNames.Contains(key))
michael@0 840 aFamilyEntry->SetBadUnderlineFamily();
michael@0 841 }
michael@0 842 }
michael@0 843
michael@0 844 void
michael@0 845 gfxPlatformFontList::AddFullname(gfxFontEntry *aFontEntry, nsAString& aFullname)
michael@0 846 {
michael@0 847 if (!mExtraNames->mFullnames.GetWeak(aFullname)) {
michael@0 848 mExtraNames->mFullnames.Put(aFullname, aFontEntry);
michael@0 849 #ifdef PR_LOGGING
michael@0 850 LOG_FONTLIST(("(fontlist-fullname) name: %s, fullname: %s\n",
michael@0 851 NS_ConvertUTF16toUTF8(aFontEntry->Name()).get(),
michael@0 852 NS_ConvertUTF16toUTF8(aFullname).get()));
michael@0 853 #endif
michael@0 854 }
michael@0 855 }
michael@0 856
michael@0 857 void
michael@0 858 gfxPlatformFontList::AddPostscriptName(gfxFontEntry *aFontEntry, nsAString& aPostscriptName)
michael@0 859 {
michael@0 860 if (!mExtraNames->mPostscriptNames.GetWeak(aPostscriptName)) {
michael@0 861 mExtraNames->mPostscriptNames.Put(aPostscriptName, aFontEntry);
michael@0 862 #ifdef PR_LOGGING
michael@0 863 LOG_FONTLIST(("(fontlist-postscript) name: %s, psname: %s\n",
michael@0 864 NS_ConvertUTF16toUTF8(aFontEntry->Name()).get(),
michael@0 865 NS_ConvertUTF16toUTF8(aPostscriptName).get()));
michael@0 866 #endif
michael@0 867 }
michael@0 868 }
michael@0 869
michael@0 870 bool
michael@0 871 gfxPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
michael@0 872 {
michael@0 873 aFamilyName.Truncate();
michael@0 874 ResolveFontName(aFontName, aFamilyName);
michael@0 875 return !aFamilyName.IsEmpty();
michael@0 876 }
michael@0 877
michael@0 878 gfxCharacterMap*
michael@0 879 gfxPlatformFontList::FindCharMap(gfxCharacterMap *aCmap)
michael@0 880 {
michael@0 881 aCmap->CalcHash();
michael@0 882 gfxCharacterMap *cmap = AddCmap(aCmap);
michael@0 883 cmap->mShared = true;
michael@0 884 return cmap;
michael@0 885 }
michael@0 886
michael@0 887 // add a cmap to the shared cmap set
michael@0 888 gfxCharacterMap*
michael@0 889 gfxPlatformFontList::AddCmap(const gfxCharacterMap* aCharMap)
michael@0 890 {
michael@0 891 CharMapHashKey *found =
michael@0 892 mSharedCmaps.PutEntry(const_cast<gfxCharacterMap*>(aCharMap));
michael@0 893 return found->GetKey();
michael@0 894 }
michael@0 895
michael@0 896 // remove the cmap from the shared cmap set
michael@0 897 void
michael@0 898 gfxPlatformFontList::RemoveCmap(const gfxCharacterMap* aCharMap)
michael@0 899 {
michael@0 900 // skip lookups during teardown
michael@0 901 if (mSharedCmaps.Count() == 0) {
michael@0 902 return;
michael@0 903 }
michael@0 904
michael@0 905 // cmap needs to match the entry *and* be the same ptr before removing
michael@0 906 CharMapHashKey *found =
michael@0 907 mSharedCmaps.GetEntry(const_cast<gfxCharacterMap*>(aCharMap));
michael@0 908 if (found && found->GetKey() == aCharMap) {
michael@0 909 mSharedCmaps.RemoveEntry(const_cast<gfxCharacterMap*>(aCharMap));
michael@0 910 }
michael@0 911 }
michael@0 912
michael@0 913 static PLDHashOperator AppendFamilyToList(nsStringHashKey::KeyType aKey,
michael@0 914 nsRefPtr<gfxFontFamily>& aFamilyEntry,
michael@0 915 void *aUserArg)
michael@0 916 {
michael@0 917 nsTArray<nsString> *familyNames = static_cast<nsTArray<nsString> *>(aUserArg);
michael@0 918 familyNames->AppendElement(aFamilyEntry->Name());
michael@0 919 return PL_DHASH_NEXT;
michael@0 920 }
michael@0 921
michael@0 922 void
michael@0 923 gfxPlatformFontList::GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames)
michael@0 924 {
michael@0 925 mFontFamilies.Enumerate(AppendFamilyToList, &aFontFamilyNames);
michael@0 926 }
michael@0 927
michael@0 928 void
michael@0 929 gfxPlatformFontList::InitLoader()
michael@0 930 {
michael@0 931 GetFontFamilyNames(mFontInfo->mFontFamiliesToLoad);
michael@0 932 mStartIndex = 0;
michael@0 933 mNumFamilies = mFontInfo->mFontFamiliesToLoad.Length();
michael@0 934 memset(&(mFontInfo->mLoadStats), 0, sizeof(mFontInfo->mLoadStats));
michael@0 935 }
michael@0 936
michael@0 937 #define FONT_LOADER_MAX_TIMESLICE 100 // max time for one pass through RunLoader = 100ms
michael@0 938
michael@0 939 bool
michael@0 940 gfxPlatformFontList::LoadFontInfo()
michael@0 941 {
michael@0 942 TimeStamp start = TimeStamp::Now();
michael@0 943 uint32_t i, endIndex = mNumFamilies;
michael@0 944 bool loadCmaps = !UsesSystemFallback() ||
michael@0 945 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
michael@0 946
michael@0 947 // for each font family, load in various font info
michael@0 948 for (i = mStartIndex; i < endIndex; i++) {
michael@0 949 nsAutoString key;
michael@0 950 gfxFontFamily *familyEntry;
michael@0 951 GenerateFontListKey(mFontInfo->mFontFamiliesToLoad[i], key);
michael@0 952
michael@0 953 // lookup in canonical (i.e. English) family name list
michael@0 954 if (!(familyEntry = mFontFamilies.GetWeak(key))) {
michael@0 955 continue;
michael@0 956 }
michael@0 957
michael@0 958 // read in face names
michael@0 959 familyEntry->ReadFaceNames(this, NeedFullnamePostscriptNames(), mFontInfo);
michael@0 960
michael@0 961 // load the cmaps if needed
michael@0 962 if (loadCmaps) {
michael@0 963 familyEntry->ReadAllCMAPs(mFontInfo);
michael@0 964 }
michael@0 965
michael@0 966 // limit the time spent reading fonts in one pass
michael@0 967 TimeDuration elapsed = TimeStamp::Now() - start;
michael@0 968 if (elapsed.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE &&
michael@0 969 i + 1 != endIndex) {
michael@0 970 endIndex = i + 1;
michael@0 971 break;
michael@0 972 }
michael@0 973 }
michael@0 974
michael@0 975 mStartIndex = endIndex;
michael@0 976 bool done = mStartIndex >= mNumFamilies;
michael@0 977
michael@0 978 #ifdef PR_LOGGING
michael@0 979 if (LOG_FONTINIT_ENABLED()) {
michael@0 980 TimeDuration elapsed = TimeStamp::Now() - start;
michael@0 981 LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
michael@0 982 elapsed.ToMilliseconds(), (done ? "true" : "false")));
michael@0 983 }
michael@0 984 #endif
michael@0 985
michael@0 986 if (done) {
michael@0 987 mOtherFamilyNamesInitialized = true;
michael@0 988 mFaceNameListsInitialized = true;
michael@0 989 }
michael@0 990
michael@0 991 return done;
michael@0 992 }
michael@0 993
michael@0 994 struct LookupMissedFaceNamesData {
michael@0 995 LookupMissedFaceNamesData(gfxPlatformFontList *aFontList)
michael@0 996 : mFontList(aFontList), mFoundName(false) {}
michael@0 997
michael@0 998 gfxPlatformFontList *mFontList;
michael@0 999 bool mFoundName;
michael@0 1000 };
michael@0 1001
michael@0 1002 /*static*/ PLDHashOperator
michael@0 1003 gfxPlatformFontList::LookupMissedFaceNamesProc(nsStringHashKey *aKey,
michael@0 1004 void *aUserArg)
michael@0 1005 {
michael@0 1006 LookupMissedFaceNamesData *data =
michael@0 1007 reinterpret_cast<LookupMissedFaceNamesData*>(aUserArg);
michael@0 1008
michael@0 1009 if (data->mFontList->FindFaceName(aKey->GetKey())) {
michael@0 1010 data->mFoundName = true;
michael@0 1011 return PL_DHASH_STOP;
michael@0 1012 }
michael@0 1013 return PL_DHASH_NEXT;
michael@0 1014 }
michael@0 1015
michael@0 1016 struct LookupMissedOtherNamesData {
michael@0 1017 LookupMissedOtherNamesData(gfxPlatformFontList *aFontList)
michael@0 1018 : mFontList(aFontList), mFoundName(false) {}
michael@0 1019
michael@0 1020 gfxPlatformFontList *mFontList;
michael@0 1021 bool mFoundName;
michael@0 1022 };
michael@0 1023
michael@0 1024 /*static*/ PLDHashOperator
michael@0 1025 gfxPlatformFontList::LookupMissedOtherNamesProc(nsStringHashKey *aKey,
michael@0 1026 void *aUserArg)
michael@0 1027 {
michael@0 1028 LookupMissedOtherNamesData *data =
michael@0 1029 reinterpret_cast<LookupMissedOtherNamesData*>(aUserArg);
michael@0 1030
michael@0 1031 if (data->mFontList->FindFamily(aKey->GetKey())) {
michael@0 1032 data->mFoundName = true;
michael@0 1033 return PL_DHASH_STOP;
michael@0 1034 }
michael@0 1035 return PL_DHASH_NEXT;
michael@0 1036 }
michael@0 1037
michael@0 1038 void
michael@0 1039 gfxPlatformFontList::CleanupLoader()
michael@0 1040 {
michael@0 1041 mFontFamiliesToLoad.Clear();
michael@0 1042 mNumFamilies = 0;
michael@0 1043 bool rebuilt = false, forceReflow = false;
michael@0 1044
michael@0 1045 // if had missed face names that are now available, force reflow all
michael@0 1046 if (mFaceNamesMissed &&
michael@0 1047 mFaceNamesMissed->Count() != 0) {
michael@0 1048 LookupMissedFaceNamesData namedata(this);
michael@0 1049 mFaceNamesMissed->EnumerateEntries(LookupMissedFaceNamesProc, &namedata);
michael@0 1050 if (namedata.mFoundName) {
michael@0 1051 rebuilt = true;
michael@0 1052 mUserFontSetList.EnumerateEntries(RebuildLocalFonts, nullptr);
michael@0 1053 }
michael@0 1054 mFaceNamesMissed = nullptr;
michael@0 1055 }
michael@0 1056
michael@0 1057 if (mOtherNamesMissed) {
michael@0 1058 LookupMissedOtherNamesData othernamesdata(this);
michael@0 1059 mOtherNamesMissed->EnumerateEntries(LookupMissedOtherNamesProc,
michael@0 1060 &othernamesdata);
michael@0 1061 mOtherNamesMissed = nullptr;
michael@0 1062 if (othernamesdata.mFoundName) {
michael@0 1063 forceReflow = true;
michael@0 1064 ForceGlobalReflow();
michael@0 1065 }
michael@0 1066 }
michael@0 1067
michael@0 1068 #ifdef PR_LOGGING
michael@0 1069 if (LOG_FONTINIT_ENABLED() && mFontInfo) {
michael@0 1070 LOG_FONTINIT(("(fontinit) fontloader load thread took %8.2f ms "
michael@0 1071 "%d families %d fonts %d cmaps "
michael@0 1072 "%d facenames %d othernames %s %s",
michael@0 1073 mLoadTime.ToMilliseconds(),
michael@0 1074 mFontInfo->mLoadStats.families,
michael@0 1075 mFontInfo->mLoadStats.fonts,
michael@0 1076 mFontInfo->mLoadStats.cmaps,
michael@0 1077 mFontInfo->mLoadStats.facenames,
michael@0 1078 mFontInfo->mLoadStats.othernames,
michael@0 1079 (rebuilt ? "(userfont sets rebuilt)" : ""),
michael@0 1080 (forceReflow ? "(global reflow)" : "")));
michael@0 1081 }
michael@0 1082 #endif
michael@0 1083
michael@0 1084 gfxFontInfoLoader::CleanupLoader();
michael@0 1085 }
michael@0 1086
michael@0 1087 void
michael@0 1088 gfxPlatformFontList::GetPrefsAndStartLoader()
michael@0 1089 {
michael@0 1090 mIncrement =
michael@0 1091 std::max(1u, Preferences::GetUint(FONT_LOADER_FAMILIES_PER_SLICE_PREF));
michael@0 1092
michael@0 1093 uint32_t delay =
michael@0 1094 std::max(1u, Preferences::GetUint(FONT_LOADER_DELAY_PREF));
michael@0 1095 uint32_t interval =
michael@0 1096 std::max(1u, Preferences::GetUint(FONT_LOADER_INTERVAL_PREF));
michael@0 1097
michael@0 1098 StartLoader(delay, interval);
michael@0 1099 }
michael@0 1100
michael@0 1101 void
michael@0 1102 gfxPlatformFontList::ForceGlobalReflow()
michael@0 1103 {
michael@0 1104 // modify a preference that will trigger reflow everywhere
michael@0 1105 static const char kPrefName[] = "font.internaluseonly.changed";
michael@0 1106 bool fontInternalChange = Preferences::GetBool(kPrefName, false);
michael@0 1107 Preferences::SetBool(kPrefName, !fontInternalChange);
michael@0 1108 }
michael@0 1109
michael@0 1110 // Support for memory reporting
michael@0 1111
michael@0 1112 static size_t
michael@0 1113 SizeOfFamilyEntryExcludingThis(const nsAString& aKey,
michael@0 1114 const nsRefPtr<gfxFontFamily>& aFamily,
michael@0 1115 MallocSizeOf aMallocSizeOf,
michael@0 1116 void* aUserArg)
michael@0 1117 {
michael@0 1118 FontListSizes *sizes = static_cast<FontListSizes*>(aUserArg);
michael@0 1119 aFamily->AddSizeOfExcludingThis(aMallocSizeOf, sizes);
michael@0 1120
michael@0 1121 sizes->mFontListSize += aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
michael@0 1122
michael@0 1123 // we return zero here because the measurements have been added directly
michael@0 1124 // to the relevant fields of the FontListSizes record
michael@0 1125 return 0;
michael@0 1126 }
michael@0 1127
michael@0 1128 // this is also used by subclasses that hold additional hashes of family names
michael@0 1129 /*static*/ size_t
michael@0 1130 gfxPlatformFontList::SizeOfFamilyNameEntryExcludingThis
michael@0 1131 (const nsAString& aKey,
michael@0 1132 const nsRefPtr<gfxFontFamily>& aFamily,
michael@0 1133 MallocSizeOf aMallocSizeOf,
michael@0 1134 void* aUserArg)
michael@0 1135 {
michael@0 1136 // we don't count the size of the family here, because this is an *extra*
michael@0 1137 // reference to a family that will have already been counted in the main list
michael@0 1138 return aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
michael@0 1139 }
michael@0 1140
michael@0 1141 static size_t
michael@0 1142 SizeOfFontNameEntryExcludingThis(const nsAString& aKey,
michael@0 1143 const nsRefPtr<gfxFontEntry>& aFont,
michael@0 1144 MallocSizeOf aMallocSizeOf,
michael@0 1145 void* aUserArg)
michael@0 1146 {
michael@0 1147 // the font itself is counted by its owning family; here we only care about
michael@0 1148 // the name stored in the hashtable key
michael@0 1149 return aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
michael@0 1150 }
michael@0 1151
michael@0 1152 static size_t
michael@0 1153 SizeOfPrefFontEntryExcludingThis
michael@0 1154 (const uint32_t& aKey,
michael@0 1155 const nsTArray<nsRefPtr<gfxFontFamily> >& aList,
michael@0 1156 MallocSizeOf aMallocSizeOf,
michael@0 1157 void* aUserArg)
michael@0 1158 {
michael@0 1159 // again, we only care about the size of the array itself; we don't follow
michael@0 1160 // the refPtrs stored in it, because they point to entries already owned
michael@0 1161 // and accounted-for by the main font list
michael@0 1162 return aList.SizeOfExcludingThis(aMallocSizeOf);
michael@0 1163 }
michael@0 1164
michael@0 1165 static size_t
michael@0 1166 SizeOfStringEntryExcludingThis(nsStringHashKey* aHashEntry,
michael@0 1167 MallocSizeOf aMallocSizeOf,
michael@0 1168 void* aUserArg)
michael@0 1169 {
michael@0 1170 return aHashEntry->GetKey().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
michael@0 1171 }
michael@0 1172
michael@0 1173 static size_t
michael@0 1174 SizeOfSharedCmapExcludingThis(CharMapHashKey* aHashEntry,
michael@0 1175 MallocSizeOf aMallocSizeOf,
michael@0 1176 void* aUserArg)
michael@0 1177 {
michael@0 1178 FontListSizes *sizes = static_cast<FontListSizes*>(aUserArg);
michael@0 1179
michael@0 1180 uint32_t size = aHashEntry->GetKey()->SizeOfIncludingThis(aMallocSizeOf);
michael@0 1181 sizes->mCharMapsSize += size;
michael@0 1182
michael@0 1183 // we return zero here because the measurements have been added directly
michael@0 1184 // to the relevant fields of the FontListSizes record
michael@0 1185 return 0;
michael@0 1186 }
michael@0 1187
michael@0 1188 void
michael@0 1189 gfxPlatformFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
michael@0 1190 FontListSizes* aSizes) const
michael@0 1191 {
michael@0 1192 aSizes->mFontListSize +=
michael@0 1193 mFontFamilies.SizeOfExcludingThis(SizeOfFamilyEntryExcludingThis,
michael@0 1194 aMallocSizeOf, aSizes);
michael@0 1195
michael@0 1196 aSizes->mFontListSize +=
michael@0 1197 mOtherFamilyNames.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis,
michael@0 1198 aMallocSizeOf);
michael@0 1199
michael@0 1200 if (mExtraNames) {
michael@0 1201 aSizes->mFontListSize +=
michael@0 1202 mExtraNames->mFullnames.SizeOfExcludingThis(SizeOfFontNameEntryExcludingThis,
michael@0 1203 aMallocSizeOf);
michael@0 1204 aSizes->mFontListSize +=
michael@0 1205 mExtraNames->mPostscriptNames.SizeOfExcludingThis(SizeOfFontNameEntryExcludingThis,
michael@0 1206 aMallocSizeOf);
michael@0 1207 }
michael@0 1208
michael@0 1209 aSizes->mFontListSize +=
michael@0 1210 mCodepointsWithNoFonts.SizeOfExcludingThis(aMallocSizeOf);
michael@0 1211 aSizes->mFontListSize +=
michael@0 1212 mFontFamiliesToLoad.SizeOfExcludingThis(aMallocSizeOf);
michael@0 1213
michael@0 1214 aSizes->mFontListSize +=
michael@0 1215 mPrefFonts.SizeOfExcludingThis(SizeOfPrefFontEntryExcludingThis,
michael@0 1216 aMallocSizeOf);
michael@0 1217
michael@0 1218 aSizes->mFontListSize +=
michael@0 1219 mBadUnderlineFamilyNames.SizeOfExcludingThis(SizeOfStringEntryExcludingThis,
michael@0 1220 aMallocSizeOf);
michael@0 1221
michael@0 1222 aSizes->mFontListSize +=
michael@0 1223 mSharedCmaps.SizeOfExcludingThis(SizeOfSharedCmapExcludingThis,
michael@0 1224 aMallocSizeOf, aSizes);
michael@0 1225 }
michael@0 1226
michael@0 1227 void
michael@0 1228 gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
michael@0 1229 FontListSizes* aSizes) const
michael@0 1230 {
michael@0 1231 aSizes->mFontListSize += aMallocSizeOf(this);
michael@0 1232 AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
michael@0 1233 }

mercurial