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