1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef GFXPLATFORMFONTLIST_H_ 7 #define GFXPLATFORMFONTLIST_H_ 8 9 #include "nsDataHashtable.h" 10 #include "nsRefPtrHashtable.h" 11 #include "nsTHashtable.h" 12 13 #include "gfxFontUtils.h" 14 #include "gfxFontInfoLoader.h" 15 #include "gfxFont.h" 16 #include "gfxFontConstants.h" 17 #include "gfxPlatform.h" 18 #include "gfxFontFamilyList.h" 19 20 #include "nsIMemoryReporter.h" 21 #include "mozilla/Attributes.h" 22 #include "mozilla/MemoryReporting.h" 23 #include "mozilla/RangedArray.h" 24 #include "nsILanguageAtomService.h" 25 26 class CharMapHashKey : public PLDHashEntryHdr 27 { 28 public: 29 typedef gfxCharacterMap* KeyType; 30 typedef const gfxCharacterMap* KeyTypePointer; 31 CharMapHashKey(const gfxCharacterMap * aCharMap)32 explicit CharMapHashKey(const gfxCharacterMap *aCharMap) : 33 mCharMap(const_cast<gfxCharacterMap*>(aCharMap)) 34 { 35 MOZ_COUNT_CTOR(CharMapHashKey); 36 } CharMapHashKey(const CharMapHashKey & toCopy)37 CharMapHashKey(const CharMapHashKey& toCopy) : 38 mCharMap(toCopy.mCharMap) 39 { 40 MOZ_COUNT_CTOR(CharMapHashKey); 41 } ~CharMapHashKey()42 ~CharMapHashKey() 43 { 44 MOZ_COUNT_DTOR(CharMapHashKey); 45 } 46 GetKey()47 gfxCharacterMap* GetKey() const { return mCharMap; } 48 KeyEquals(const gfxCharacterMap * aCharMap)49 bool KeyEquals(const gfxCharacterMap *aCharMap) const { 50 NS_ASSERTION(!aCharMap->mBuildOnTheFly && !mCharMap->mBuildOnTheFly, 51 "custom cmap used in shared cmap hashtable"); 52 // cmaps built on the fly never match 53 if (aCharMap->mHash != mCharMap->mHash) 54 { 55 return false; 56 } 57 return mCharMap->Equals(aCharMap); 58 } 59 KeyToPointer(gfxCharacterMap * aCharMap)60 static const gfxCharacterMap* KeyToPointer(gfxCharacterMap *aCharMap) { 61 return aCharMap; 62 } HashKey(const gfxCharacterMap * aCharMap)63 static PLDHashNumber HashKey(const gfxCharacterMap *aCharMap) { 64 return aCharMap->mHash; 65 } 66 67 enum { ALLOW_MEMMOVE = true }; 68 69 protected: 70 gfxCharacterMap *mCharMap; 71 }; 72 73 // gfxPlatformFontList is an abstract class for the global font list on the system; 74 // concrete subclasses for each platform implement the actual interface to the system fonts. 75 // This class exists because we cannot rely on the platform font-finding APIs to behave 76 // in sensible/similar ways, particularly with rich, complex OpenType families, 77 // so we do our own font family/style management here instead. 78 79 // Much of this is based on the old gfxQuartzFontCache, but adapted for use on all platforms. 80 81 struct FontListSizes { 82 uint32_t mFontListSize; // size of the font list and dependent objects 83 // (font family and face names, etc), but NOT 84 // including the font table cache and the cmaps 85 uint32_t mFontTableCacheSize; // memory used for the gfxFontEntry table caches 86 uint32_t mCharMapsSize; // memory used for cmap coverage info 87 }; 88 89 class gfxUserFontSet; 90 91 class gfxPlatformFontList : public gfxFontInfoLoader 92 { 93 public: 94 typedef mozilla::unicode::Script Script; 95 PlatformFontList()96 static gfxPlatformFontList* PlatformFontList() { 97 return sPlatformFontList; 98 } 99 Init()100 static nsresult Init() { 101 NS_ASSERTION(!sPlatformFontList, "What's this doing here?"); 102 gfxPlatform::GetPlatform()->CreatePlatformFontList(); 103 if (!sPlatformFontList) { 104 return NS_ERROR_OUT_OF_MEMORY; 105 } 106 return NS_OK; 107 } 108 Shutdown()109 static void Shutdown() { 110 delete sPlatformFontList; 111 sPlatformFontList = nullptr; 112 } 113 114 virtual ~gfxPlatformFontList(); 115 116 // initialize font lists 117 nsresult InitFontList(); 118 119 virtual void GetFontList(nsIAtom *aLangGroup, 120 const nsACString& aGenericFamily, 121 nsTArray<nsString>& aListOfFonts); 122 123 void UpdateFontList(); 124 125 virtual void ClearLangGroupPrefFonts(); 126 127 virtual void GetFontFamilyList(nsTArray<RefPtr<gfxFontFamily> >& aFamilyArray); 128 129 gfxFontEntry* 130 SystemFindFontForChar(uint32_t aCh, uint32_t aNextCh, 131 Script aRunScript, 132 const gfxFontStyle* aStyle); 133 134 // Find family(ies) matching aFamily and append to the aOutput array 135 // (there may be multiple results in the case of fontconfig aliases, etc). 136 // Return true if any match was found and appended, false if none. 137 virtual bool 138 FindAndAddFamilies(const nsAString& aFamily, 139 nsTArray<gfxFontFamily*>* aOutput, 140 gfxFontStyle* aStyle = nullptr, 141 gfxFloat aDevToCssSize = 1.0); 142 143 gfxFontEntry* FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold); 144 145 // name lookup table methods 146 147 void AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName); 148 149 void AddFullname(gfxFontEntry *aFontEntry, nsAString& aFullname); 150 151 void AddPostscriptName(gfxFontEntry *aFontEntry, nsAString& aPostscriptName); 152 NeedFullnamePostscriptNames()153 bool NeedFullnamePostscriptNames() { return mExtraNames != nullptr; } 154 155 // pure virtual functions, to be provided by concrete subclasses 156 157 // get the system default font family 158 gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle); 159 160 // look up a font by name on the host platform 161 virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName, 162 uint16_t aWeight, 163 int16_t aStretch, 164 uint8_t aStyle) = 0; 165 166 // create a new platform font from downloaded data (@font-face) 167 // this method is responsible to ensure aFontData is free()'d 168 virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName, 169 uint16_t aWeight, 170 int16_t aStretch, 171 uint8_t aStyle, 172 const uint8_t* aFontData, 173 uint32_t aLength) = 0; 174 175 // get the standard family name on the platform for a given font name 176 // (platforms may override, eg Mac) 177 virtual bool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName); 178 179 virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, 180 FontListSizes* aSizes) const; 181 virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, 182 FontListSizes* aSizes) const; 183 184 // search for existing cmap that matches the input 185 // return the input if no match is found 186 gfxCharacterMap* FindCharMap(gfxCharacterMap *aCmap); 187 188 // add a cmap to the shared cmap set 189 gfxCharacterMap* AddCmap(const gfxCharacterMap *aCharMap); 190 191 // remove the cmap from the shared cmap set 192 void RemoveCmap(const gfxCharacterMap *aCharMap); 193 194 // keep track of userfont sets to notify when global fontlist changes occur AddUserFontSet(gfxUserFontSet * aUserFontSet)195 void AddUserFontSet(gfxUserFontSet *aUserFontSet) { 196 mUserFontSetList.PutEntry(aUserFontSet); 197 } 198 RemoveUserFontSet(gfxUserFontSet * aUserFontSet)199 void RemoveUserFontSet(gfxUserFontSet *aUserFontSet) { 200 mUserFontSetList.RemoveEntry(aUserFontSet); 201 } 202 203 static const gfxFontEntry::ScriptRange sComplexScriptRanges[]; 204 GetFontlistInitInfo(uint32_t & aNumInits,uint32_t & aLoaderState)205 void GetFontlistInitInfo(uint32_t& aNumInits, uint32_t& aLoaderState) { 206 aNumInits = mFontlistInitCount; 207 aLoaderState = (uint32_t) mState; 208 } 209 210 virtual void 211 AddGenericFonts(mozilla::FontFamilyType aGenericType, 212 nsIAtom* aLanguage, 213 nsTArray<gfxFontFamily*>& aFamilyList); 214 215 nsTArray<RefPtr<gfxFontFamily>>* 216 GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType, 217 eFontPrefLang aPrefLang); 218 219 // in some situations, need to make decisions about ambiguous characters, may need to look at multiple pref langs 220 void GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang); 221 222 // convert a lang group to enum constant (i.e. "zh-TW" ==> eFontPrefLang_ChineseTW) 223 static eFontPrefLang GetFontPrefLangFor(const char* aLang); 224 225 // convert a lang group atom to enum constant 226 static eFontPrefLang GetFontPrefLangFor(nsIAtom *aLang); 227 228 // convert an enum constant to a lang group atom 229 static nsIAtom* GetLangGroupForPrefLang(eFontPrefLang aLang); 230 231 // convert a enum constant to lang group string (i.e. eFontPrefLang_ChineseTW ==> "zh-TW") 232 static const char* GetPrefLangName(eFontPrefLang aLang); 233 234 // map a Unicode range (based on char code) to a font language for Preferences 235 static eFontPrefLang GetFontPrefLangFor(uint8_t aUnicodeRange); 236 237 // returns true if a pref lang is CJK 238 static bool IsLangCJK(eFontPrefLang aLang); 239 240 // helper method to add a pref lang to an array, if not already in array 241 static void AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang); 242 243 // default serif/sans-serif choice based on font.default.xxx prefs 244 mozilla::FontFamilyType 245 GetDefaultGeneric(eFontPrefLang aLang); 246 247 // map lang group ==> lang string 248 void GetSampleLangForGroup(nsIAtom* aLanguage, nsACString& aLangStr, 249 bool aCheckEnvironment = true); 250 251 // Returns true if the font family whitelist is not empty. 252 bool IsFontFamilyWhitelistActive(); 253 FontWhitelistPrefChanged(const char * aPref,void * aClosure)254 static void FontWhitelistPrefChanged(const char *aPref, void *aClosure) { 255 gfxPlatformFontList::PlatformFontList()->UpdateFontList(); 256 } 257 258 protected: 259 class MemoryReporter final : public nsIMemoryReporter 260 { ~MemoryReporter()261 ~MemoryReporter() {} 262 public: 263 NS_DECL_ISUPPORTS 264 NS_DECL_NSIMEMORYREPORTER 265 }; 266 267 explicit gfxPlatformFontList(bool aNeedFullnamePostscriptNames = true); 268 269 static gfxPlatformFontList *sPlatformFontList; 270 271 // Convenience method to return the first matching family (if any) as found 272 // by FindAndAddFamilies(). 273 gfxFontFamily* 274 FindFamily(const nsAString& aFamily, gfxFontStyle* aStyle = nullptr, 275 gfxFloat aDevToCssSize = 1.0) 276 { 277 AutoTArray<gfxFontFamily*,1> families; 278 return FindAndAddFamilies(aFamily, &families, aStyle, aDevToCssSize) 279 ? families[0] : nullptr; 280 } 281 282 // Lookup family name in global family list without substitutions or 283 // localized family name lookup. Used for common font fallback families. FindFamilyByCanonicalName(const nsAString & aFamily)284 gfxFontFamily* FindFamilyByCanonicalName(const nsAString& aFamily) { 285 nsAutoString key; 286 gfxFontFamily *familyEntry; 287 GenerateFontListKey(aFamily, key); 288 if ((familyEntry = mFontFamilies.GetWeak(key))) { 289 return CheckFamily(familyEntry); 290 } 291 return nullptr; 292 } 293 294 // returns default font for a given character, null otherwise 295 gfxFontEntry* CommonFontFallback(uint32_t aCh, uint32_t aNextCh, 296 Script aRunScript, 297 const gfxFontStyle* aMatchStyle, 298 gfxFontFamily** aMatchedFamily); 299 300 // Search fonts system-wide for a given character, null if not found. 301 gfxFontEntry* GlobalFontFallback(const uint32_t aCh, 302 Script aRunScript, 303 const gfxFontStyle* aMatchStyle, 304 uint32_t& aCmapCount, 305 gfxFontFamily** aMatchedFamily); 306 307 // Platform-specific implementation of global font fallback, if any; 308 // this may return nullptr in which case the default cmap-based fallback 309 // will be performed. 310 virtual gfxFontEntry* PlatformGlobalFontFallback(const uint32_t aCh,Script aRunScript,const gfxFontStyle * aMatchStyle,gfxFontFamily ** aMatchedFamily)311 PlatformGlobalFontFallback(const uint32_t aCh, 312 Script aRunScript, 313 const gfxFontStyle* aMatchStyle, 314 gfxFontFamily** aMatchedFamily) 315 { 316 return nullptr; 317 } 318 319 // whether system-based font fallback is used or not 320 // if system fallback is used, no need to load all cmaps UsesSystemFallback()321 virtual bool UsesSystemFallback() { return false; } 322 323 void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, 324 eFontPrefLang aCharLang, eFontPrefLang aPageLang); 325 326 // verifies that a family contains a non-zero font count 327 gfxFontFamily* CheckFamily(gfxFontFamily *aFamily); 328 329 // initialize localized family names 330 void InitOtherFamilyNames(); 331 332 // search through font families, looking for a given name, initializing 333 // facename lists along the way. first checks all families with names 334 // close to face name, then searchs all families if not found. 335 gfxFontEntry* SearchFamiliesForFaceName(const nsAString& aFaceName); 336 337 // helper method for finding fullname/postscript names in facename lists 338 gfxFontEntry* FindFaceName(const nsAString& aFaceName); 339 340 // look up a font by name, for cases where platform font list 341 // maintains explicit mappings of fullname/psname ==> font 342 virtual gfxFontEntry* LookupInFaceNameLists(const nsAString& aFontName); 343 344 // commonly used fonts for which the name table should be loaded at startup 345 virtual void PreloadNamesList(); 346 347 // load the bad underline blacklist from pref. 348 void LoadBadUnderlineList(); 349 350 void GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult); 351 352 virtual void GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames); 353 354 nsILanguageAtomService* GetLangService(); 355 356 // helper function to map lang to lang group 357 nsIAtom* GetLangGroup(nsIAtom* aLanguage); 358 359 // helper method for finding an appropriate lang string 360 bool TryLangForGroup(const nsACString& aOSLang, nsIAtom* aLangGroup, 361 nsACString& aLang); 362 363 static const char* GetGenericName(mozilla::FontFamilyType aGenericType); 364 365 // gfxFontInfoLoader overrides, used to load in font cmaps 366 virtual void InitLoader(); 367 virtual bool LoadFontInfo(); 368 virtual void CleanupLoader(); 369 370 // read the loader initialization prefs, and start it 371 void GetPrefsAndStartLoader(); 372 373 // for font list changes that affect all documents 374 void ForceGlobalReflow(); 375 376 void RebuildLocalFonts(); 377 378 void 379 ResolveGenericFontNames(mozilla::FontFamilyType aGenericType, 380 eFontPrefLang aPrefLang, 381 nsTArray<RefPtr<gfxFontFamily>>* aGenericFamilies); 382 383 virtual nsresult InitFontListForPlatform() = 0; 384 385 void ApplyWhitelist(); 386 387 typedef nsRefPtrHashtable<nsStringHashKey, gfxFontFamily> FontFamilyTable; 388 typedef nsRefPtrHashtable<nsStringHashKey, gfxFontEntry> FontEntryTable; 389 390 // used by memory reporter to accumulate sizes of family names in the table 391 static size_t 392 SizeOfFontFamilyTableExcludingThis(const FontFamilyTable& aTable, 393 mozilla::MallocSizeOf aMallocSizeOf); 394 static size_t 395 SizeOfFontEntryTableExcludingThis(const FontEntryTable& aTable, 396 mozilla::MallocSizeOf aMallocSizeOf); 397 398 // Platform-specific helper for GetDefaultFont(...). 399 virtual gfxFontFamily* 400 GetDefaultFontForPlatform(const gfxFontStyle* aStyle) = 0; 401 402 // canonical family name ==> family entry (unique, one name per family entry) 403 FontFamilyTable mFontFamilies; 404 405 // other family name ==> family entry (not unique, can have multiple names per 406 // family entry, only names *other* than the canonical names are stored here) 407 FontFamilyTable mOtherFamilyNames; 408 409 // flag set after InitOtherFamilyNames is called upon first name lookup miss 410 bool mOtherFamilyNamesInitialized; 411 412 // flag set after fullname and Postcript name lists are populated 413 bool mFaceNameListsInitialized; 414 415 struct ExtraNames { ExtraNamesExtraNames416 ExtraNames() : mFullnames(64), mPostscriptNames(64) {} 417 418 // fullname ==> font entry (unique, one name per font entry) 419 FontEntryTable mFullnames; 420 // Postscript name ==> font entry (unique, one name per font entry) 421 FontEntryTable mPostscriptNames; 422 }; 423 mozilla::UniquePtr<ExtraNames> mExtraNames; 424 425 // face names missed when face name loading takes a long time 426 mozilla::UniquePtr<nsTHashtable<nsStringHashKey> > mFaceNamesMissed; 427 428 // localized family names missed when face name loading takes a long time 429 mozilla::UniquePtr<nsTHashtable<nsStringHashKey> > mOtherNamesMissed; 430 431 typedef nsTArray<RefPtr<gfxFontFamily>> PrefFontList; 432 typedef mozilla::RangedArray<mozilla::UniquePtr<PrefFontList>, 433 mozilla::eFamily_generic_first, 434 mozilla::eFamily_generic_count> PrefFontsForLangGroup; 435 mozilla::RangedArray<PrefFontsForLangGroup, 436 eFontPrefLang_First, 437 eFontPrefLang_Count> mLangGroupPrefFonts; 438 439 // when system-wide font lookup fails for a character, cache it to skip future searches 440 gfxSparseBitSet mCodepointsWithNoFonts; 441 442 // the family to use for U+FFFD fallback, to avoid expensive search every time 443 // on pages with lots of problems 444 RefPtr<gfxFontFamily> mReplacementCharFallbackFamily; 445 446 nsTHashtable<nsStringHashKey> mBadUnderlineFamilyNames; 447 448 // character map data shared across families 449 // contains weak ptrs to cmaps shared by font entry objects 450 nsTHashtable<CharMapHashKey> mSharedCmaps; 451 452 // data used as part of the font cmap loading process 453 nsTArray<RefPtr<gfxFontFamily> > mFontFamiliesToLoad; 454 uint32_t mStartIndex; 455 uint32_t mIncrement; 456 uint32_t mNumFamilies; 457 458 // xxx - info for diagnosing no default font aborts 459 // see bugs 636957, 1070983, 1189129 460 uint32_t mFontlistInitCount; // num times InitFontList called 461 462 nsTHashtable<nsPtrHashKey<gfxUserFontSet> > mUserFontSetList; 463 464 nsCOMPtr<nsILanguageAtomService> mLangService; 465 nsTArray<uint32_t> mCJKPrefLangs; 466 nsTArray<mozilla::FontFamilyType> mDefaultGenericsLangGroup; 467 468 bool mFontFamilyWhitelistActive; 469 }; 470 471 #endif /* GFXPLATFORMFONTLIST_H_ */ 472