Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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 | } |