Line data Source code
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 "nsLanguageAtomService.h"
25 :
26 : class CharMapHashKey : public PLDHashEntryHdr
27 : {
28 : public:
29 : typedef gfxCharacterMap* KeyType;
30 : typedef const gfxCharacterMap* KeyTypePointer;
31 :
32 0 : explicit CharMapHashKey(const gfxCharacterMap *aCharMap) :
33 0 : mCharMap(const_cast<gfxCharacterMap*>(aCharMap))
34 : {
35 0 : MOZ_COUNT_CTOR(CharMapHashKey);
36 0 : }
37 : CharMapHashKey(const CharMapHashKey& toCopy) :
38 : mCharMap(toCopy.mCharMap)
39 : {
40 : MOZ_COUNT_CTOR(CharMapHashKey);
41 : }
42 0 : ~CharMapHashKey()
43 0 : {
44 0 : MOZ_COUNT_DTOR(CharMapHashKey);
45 0 : }
46 :
47 0 : gfxCharacterMap* GetKey() const { return mCharMap; }
48 :
49 0 : bool KeyEquals(const gfxCharacterMap *aCharMap) const {
50 0 : NS_ASSERTION(!aCharMap->mBuildOnTheFly && !mCharMap->mBuildOnTheFly,
51 : "custom cmap used in shared cmap hashtable");
52 : // cmaps built on the fly never match
53 0 : if (aCharMap->mHash != mCharMap->mHash)
54 : {
55 0 : return false;
56 : }
57 0 : return mCharMap->Equals(aCharMap);
58 : }
59 :
60 0 : static const gfxCharacterMap* KeyToPointer(gfxCharacterMap *aCharMap) {
61 0 : return aCharMap;
62 : }
63 0 : static PLDHashNumber HashKey(const gfxCharacterMap *aCharMap) {
64 0 : 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 :
96 10 : static gfxPlatformFontList* PlatformFontList() {
97 10 : return sPlatformFontList;
98 : }
99 :
100 3 : static nsresult Init() {
101 3 : NS_ASSERTION(!sPlatformFontList, "What's this doing here?");
102 3 : gfxPlatform::GetPlatform()->CreatePlatformFontList();
103 3 : if (!sPlatformFontList) {
104 0 : return NS_ERROR_OUT_OF_MEMORY;
105 : }
106 3 : return NS_OK;
107 : }
108 :
109 0 : static void Shutdown() {
110 0 : delete sPlatformFontList;
111 0 : sPlatformFontList = nullptr;
112 0 : }
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 :
153 0 : 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 : // get the default font name which is available on the system from
180 : // font.name-list.*. if there are no available fonts in the pref,
181 : // returns nullptr.
182 : gfxFontFamily* GetDefaultFontFamily(const nsACString& aLangGroup,
183 : const nsACString& aGenericFamily);
184 :
185 : virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
186 : FontListSizes* aSizes) const;
187 : virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
188 : FontListSizes* aSizes) const;
189 :
190 : // search for existing cmap that matches the input
191 : // return the input if no match is found
192 : gfxCharacterMap* FindCharMap(gfxCharacterMap *aCmap);
193 :
194 : // add a cmap to the shared cmap set
195 : gfxCharacterMap* AddCmap(const gfxCharacterMap *aCharMap);
196 :
197 : // remove the cmap from the shared cmap set
198 : void RemoveCmap(const gfxCharacterMap *aCharMap);
199 :
200 : // keep track of userfont sets to notify when global fontlist changes occur
201 0 : void AddUserFontSet(gfxUserFontSet *aUserFontSet) {
202 0 : mUserFontSetList.PutEntry(aUserFontSet);
203 0 : }
204 :
205 0 : void RemoveUserFontSet(gfxUserFontSet *aUserFontSet) {
206 0 : mUserFontSetList.RemoveEntry(aUserFontSet);
207 0 : }
208 :
209 : static const gfxFontEntry::ScriptRange sComplexScriptRanges[];
210 :
211 0 : void GetFontlistInitInfo(uint32_t& aNumInits, uint32_t& aLoaderState) {
212 0 : aNumInits = mFontlistInitCount;
213 0 : aLoaderState = (uint32_t) mState;
214 0 : }
215 :
216 : virtual void
217 : AddGenericFonts(mozilla::FontFamilyType aGenericType,
218 : nsIAtom* aLanguage,
219 : nsTArray<gfxFontFamily*>& aFamilyList);
220 :
221 : nsTArray<RefPtr<gfxFontFamily>>*
222 : GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType,
223 : eFontPrefLang aPrefLang);
224 :
225 : // in some situations, need to make decisions about ambiguous characters, may need to look at multiple pref langs
226 : void GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang);
227 :
228 : // convert a lang group to enum constant (i.e. "zh-TW" ==> eFontPrefLang_ChineseTW)
229 : static eFontPrefLang GetFontPrefLangFor(const char* aLang);
230 :
231 : // convert a lang group atom to enum constant
232 : static eFontPrefLang GetFontPrefLangFor(nsIAtom *aLang);
233 :
234 : // convert an enum constant to a lang group atom
235 : static nsIAtom* GetLangGroupForPrefLang(eFontPrefLang aLang);
236 :
237 : // convert a enum constant to lang group string (i.e. eFontPrefLang_ChineseTW ==> "zh-TW")
238 : static const char* GetPrefLangName(eFontPrefLang aLang);
239 :
240 : // map a Unicode range (based on char code) to a font language for Preferences
241 : static eFontPrefLang GetFontPrefLangFor(uint8_t aUnicodeRange);
242 :
243 : // returns true if a pref lang is CJK
244 : static bool IsLangCJK(eFontPrefLang aLang);
245 :
246 : // helper method to add a pref lang to an array, if not already in array
247 : static void AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang);
248 :
249 : // default serif/sans-serif choice based on font.default.xxx prefs
250 : mozilla::FontFamilyType
251 : GetDefaultGeneric(eFontPrefLang aLang);
252 :
253 : // map lang group ==> lang string
254 : void GetSampleLangForGroup(nsIAtom* aLanguage, nsACString& aLangStr,
255 : bool aCheckEnvironment = true);
256 :
257 : // Returns true if the font family whitelist is not empty.
258 : bool IsFontFamilyWhitelistActive();
259 :
260 0 : static void FontWhitelistPrefChanged(const char *aPref, void *aClosure) {
261 0 : gfxPlatformFontList::PlatformFontList()->UpdateFontList();
262 0 : }
263 :
264 : protected:
265 3 : class MemoryReporter final : public nsIMemoryReporter
266 : {
267 0 : ~MemoryReporter() {}
268 : public:
269 : NS_DECL_ISUPPORTS
270 : NS_DECL_NSIMEMORYREPORTER
271 : };
272 :
273 : template<bool ForNameList>
274 52 : class PrefNameMaker final : public nsAutoCString
275 : {
276 52 : void Init(const nsACString& aGeneric, const nsACString& aLangGroup)
277 : {
278 52 : Assign(ForNameList ? NS_LITERAL_CSTRING("font.name-list.")
279 : : NS_LITERAL_CSTRING("font.name."));
280 52 : Append(aGeneric);
281 52 : if (!aLangGroup.IsEmpty()) {
282 52 : Append('.');
283 52 : Append(aLangGroup);
284 : }
285 52 : }
286 :
287 : public:
288 42 : PrefNameMaker(const nsACString& aGeneric,
289 : const nsACString& aLangGroup)
290 42 : {
291 42 : Init(aGeneric, aLangGroup);
292 42 : }
293 :
294 0 : PrefNameMaker(const char* aGeneric,
295 : const char* aLangGroup)
296 0 : {
297 0 : Init(nsDependentCString(aGeneric), nsDependentCString(aLangGroup));
298 0 : }
299 :
300 10 : PrefNameMaker(const char* aGeneric,
301 : nsIAtom* aLangGroup)
302 10 : {
303 10 : if (aLangGroup) {
304 10 : Init(nsDependentCString(aGeneric), nsAtomCString(aLangGroup));
305 : } else {
306 0 : Init(nsDependentCString(aGeneric), nsAutoCString());
307 : }
308 10 : }
309 : };
310 :
311 : typedef PrefNameMaker<false> NamePref;
312 : typedef PrefNameMaker<true> NameListPref;
313 :
314 : explicit gfxPlatformFontList(bool aNeedFullnamePostscriptNames = true);
315 :
316 : static gfxPlatformFontList *sPlatformFontList;
317 :
318 : // Convenience method to return the first matching family (if any) as found
319 : // by FindAndAddFamilies().
320 : gfxFontFamily*
321 0 : FindFamily(const nsAString& aFamily, gfxFontStyle* aStyle = nullptr,
322 : gfxFloat aDevToCssSize = 1.0)
323 : {
324 0 : AutoTArray<gfxFontFamily*,1> families;
325 0 : return FindAndAddFamilies(aFamily, &families, aStyle, aDevToCssSize)
326 0 : ? families[0] : nullptr;
327 : }
328 :
329 : // Lookup family name in global family list without substitutions or
330 : // localized family name lookup. Used for common font fallback families.
331 0 : gfxFontFamily* FindFamilyByCanonicalName(const nsAString& aFamily) {
332 0 : nsAutoString key;
333 : gfxFontFamily *familyEntry;
334 0 : GenerateFontListKey(aFamily, key);
335 0 : if ((familyEntry = mFontFamilies.GetWeak(key))) {
336 0 : return CheckFamily(familyEntry);
337 : }
338 0 : return nullptr;
339 : }
340 :
341 : // returns default font for a given character, null otherwise
342 : gfxFontEntry* CommonFontFallback(uint32_t aCh, uint32_t aNextCh,
343 : Script aRunScript,
344 : const gfxFontStyle* aMatchStyle,
345 : gfxFontFamily** aMatchedFamily);
346 :
347 : // Search fonts system-wide for a given character, null if not found.
348 : gfxFontEntry* GlobalFontFallback(const uint32_t aCh,
349 : Script aRunScript,
350 : const gfxFontStyle* aMatchStyle,
351 : uint32_t& aCmapCount,
352 : gfxFontFamily** aMatchedFamily);
353 :
354 : // Platform-specific implementation of global font fallback, if any;
355 : // this may return nullptr in which case the default cmap-based fallback
356 : // will be performed.
357 : virtual gfxFontEntry*
358 0 : PlatformGlobalFontFallback(const uint32_t aCh,
359 : Script aRunScript,
360 : const gfxFontStyle* aMatchStyle,
361 : gfxFontFamily** aMatchedFamily)
362 : {
363 0 : return nullptr;
364 : }
365 :
366 : // whether system-based font fallback is used or not
367 : // if system fallback is used, no need to load all cmaps
368 0 : virtual bool UsesSystemFallback() { return false; }
369 :
370 : void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen,
371 : eFontPrefLang aCharLang, eFontPrefLang aPageLang);
372 :
373 : // verifies that a family contains a non-zero font count
374 : gfxFontFamily* CheckFamily(gfxFontFamily *aFamily);
375 :
376 : // initialize localized family names
377 : void InitOtherFamilyNames();
378 :
379 : // search through font families, looking for a given name, initializing
380 : // facename lists along the way. first checks all families with names
381 : // close to face name, then searchs all families if not found.
382 : gfxFontEntry* SearchFamiliesForFaceName(const nsAString& aFaceName);
383 :
384 : // helper method for finding fullname/postscript names in facename lists
385 : gfxFontEntry* FindFaceName(const nsAString& aFaceName);
386 :
387 : // look up a font by name, for cases where platform font list
388 : // maintains explicit mappings of fullname/psname ==> font
389 : virtual gfxFontEntry* LookupInFaceNameLists(const nsAString& aFontName);
390 :
391 : // commonly used fonts for which the name table should be loaded at startup
392 : virtual void PreloadNamesList();
393 :
394 : // load the bad underline blacklist from pref.
395 : void LoadBadUnderlineList();
396 :
397 : void GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult);
398 :
399 : virtual void GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames);
400 :
401 : // helper function to map lang to lang group
402 : nsIAtom* GetLangGroup(nsIAtom* aLanguage);
403 :
404 : // helper method for finding an appropriate lang string
405 : bool TryLangForGroup(const nsACString& aOSLang, nsIAtom* aLangGroup,
406 : nsACString& aLang);
407 :
408 : static const char* GetGenericName(mozilla::FontFamilyType aGenericType);
409 :
410 : // gfxFontInfoLoader overrides, used to load in font cmaps
411 : virtual void InitLoader();
412 : virtual bool LoadFontInfo();
413 : virtual void CleanupLoader();
414 :
415 : // read the loader initialization prefs, and start it
416 : void GetPrefsAndStartLoader();
417 :
418 : // for font list changes that affect all documents
419 : void ForceGlobalReflow();
420 :
421 : void RebuildLocalFonts();
422 :
423 : void
424 : ResolveGenericFontNames(mozilla::FontFamilyType aGenericType,
425 : eFontPrefLang aPrefLang,
426 : nsTArray<RefPtr<gfxFontFamily>>* aGenericFamilies);
427 :
428 : virtual nsresult InitFontListForPlatform() = 0;
429 :
430 : void ApplyWhitelist();
431 :
432 : typedef nsRefPtrHashtable<nsStringHashKey, gfxFontFamily> FontFamilyTable;
433 : typedef nsRefPtrHashtable<nsStringHashKey, gfxFontEntry> FontEntryTable;
434 :
435 : // used by memory reporter to accumulate sizes of family names in the table
436 : static size_t
437 : SizeOfFontFamilyTableExcludingThis(const FontFamilyTable& aTable,
438 : mozilla::MallocSizeOf aMallocSizeOf);
439 : static size_t
440 : SizeOfFontEntryTableExcludingThis(const FontEntryTable& aTable,
441 : mozilla::MallocSizeOf aMallocSizeOf);
442 :
443 : // Platform-specific helper for GetDefaultFont(...).
444 : virtual gfxFontFamily*
445 : GetDefaultFontForPlatform(const gfxFontStyle* aStyle) = 0;
446 :
447 : // canonical family name ==> family entry (unique, one name per family entry)
448 : FontFamilyTable mFontFamilies;
449 :
450 : // other family name ==> family entry (not unique, can have multiple names per
451 : // family entry, only names *other* than the canonical names are stored here)
452 : FontFamilyTable mOtherFamilyNames;
453 :
454 : // flag set after InitOtherFamilyNames is called upon first name lookup miss
455 : bool mOtherFamilyNamesInitialized;
456 :
457 : // flag set after fullname and Postcript name lists are populated
458 : bool mFaceNameListsInitialized;
459 :
460 0 : struct ExtraNames {
461 3 : ExtraNames() : mFullnames(64), mPostscriptNames(64) {}
462 :
463 : // fullname ==> font entry (unique, one name per font entry)
464 : FontEntryTable mFullnames;
465 : // Postscript name ==> font entry (unique, one name per font entry)
466 : FontEntryTable mPostscriptNames;
467 : };
468 : mozilla::UniquePtr<ExtraNames> mExtraNames;
469 :
470 : // face names missed when face name loading takes a long time
471 : mozilla::UniquePtr<nsTHashtable<nsStringHashKey> > mFaceNamesMissed;
472 :
473 : // localized family names missed when face name loading takes a long time
474 : mozilla::UniquePtr<nsTHashtable<nsStringHashKey> > mOtherNamesMissed;
475 :
476 : typedef nsTArray<RefPtr<gfxFontFamily>> PrefFontList;
477 : typedef mozilla::RangedArray<mozilla::UniquePtr<PrefFontList>,
478 : mozilla::eFamily_generic_first,
479 : mozilla::eFamily_generic_count> PrefFontsForLangGroup;
480 : mozilla::RangedArray<PrefFontsForLangGroup,
481 : eFontPrefLang_First,
482 : eFontPrefLang_Count> mLangGroupPrefFonts;
483 :
484 : // when system-wide font lookup fails for a character, cache it to skip future searches
485 : gfxSparseBitSet mCodepointsWithNoFonts;
486 :
487 : // the family to use for U+FFFD fallback, to avoid expensive search every time
488 : // on pages with lots of problems
489 : RefPtr<gfxFontFamily> mReplacementCharFallbackFamily;
490 :
491 : nsTHashtable<nsStringHashKey> mBadUnderlineFamilyNames;
492 :
493 : // character map data shared across families
494 : // contains weak ptrs to cmaps shared by font entry objects
495 : nsTHashtable<CharMapHashKey> mSharedCmaps;
496 :
497 : // data used as part of the font cmap loading process
498 : nsTArray<RefPtr<gfxFontFamily> > mFontFamiliesToLoad;
499 : uint32_t mStartIndex;
500 : uint32_t mIncrement;
501 : uint32_t mNumFamilies;
502 :
503 : // xxx - info for diagnosing no default font aborts
504 : // see bugs 636957, 1070983, 1189129
505 : uint32_t mFontlistInitCount; // num times InitFontList called
506 :
507 : nsTHashtable<nsPtrHashKey<gfxUserFontSet> > mUserFontSetList;
508 :
509 : nsLanguageAtomService* mLangService;
510 :
511 : nsTArray<uint32_t> mCJKPrefLangs;
512 : nsTArray<mozilla::FontFamilyType> mDefaultGenericsLangGroup;
513 :
514 : bool mFontFamilyWhitelistActive;
515 : };
516 :
517 : #endif /* GFXPLATFORMFONTLIST_H_ */
|