|
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 GFX_FONTCONFIG_UTILS_H |
|
7 #define GFX_FONTCONFIG_UTILS_H |
|
8 |
|
9 #include "gfxPlatform.h" |
|
10 |
|
11 #include "mozilla/MathAlgorithms.h" |
|
12 #include "nsAutoRef.h" |
|
13 #include "nsTArray.h" |
|
14 #include "nsTHashtable.h" |
|
15 #include "nsISupportsImpl.h" |
|
16 |
|
17 #include <fontconfig/fontconfig.h> |
|
18 |
|
19 |
|
20 template <> |
|
21 class nsAutoRefTraits<FcPattern> : public nsPointerRefTraits<FcPattern> |
|
22 { |
|
23 public: |
|
24 static void Release(FcPattern *ptr) { FcPatternDestroy(ptr); } |
|
25 static void AddRef(FcPattern *ptr) { FcPatternReference(ptr); } |
|
26 }; |
|
27 |
|
28 template <> |
|
29 class nsAutoRefTraits<FcFontSet> : public nsPointerRefTraits<FcFontSet> |
|
30 { |
|
31 public: |
|
32 static void Release(FcFontSet *ptr) { FcFontSetDestroy(ptr); } |
|
33 }; |
|
34 |
|
35 template <> |
|
36 class nsAutoRefTraits<FcCharSet> : public nsPointerRefTraits<FcCharSet> |
|
37 { |
|
38 public: |
|
39 static void Release(FcCharSet *ptr) { FcCharSetDestroy(ptr); } |
|
40 }; |
|
41 |
|
42 class gfxIgnoreCaseCStringComparator |
|
43 { |
|
44 public: |
|
45 bool Equals(const nsACString& a, const nsACString& b) const |
|
46 { |
|
47 return nsCString(a).Equals(b, nsCaseInsensitiveCStringComparator()); |
|
48 } |
|
49 |
|
50 bool LessThan(const nsACString& a, const nsACString& b) const |
|
51 { |
|
52 return a < b; |
|
53 } |
|
54 }; |
|
55 |
|
56 class gfxFontconfigUtils { |
|
57 public: |
|
58 gfxFontconfigUtils(); |
|
59 |
|
60 static gfxFontconfigUtils* GetFontconfigUtils() { |
|
61 if (!sUtils) |
|
62 sUtils = new gfxFontconfigUtils(); |
|
63 return sUtils; |
|
64 } |
|
65 |
|
66 static void Shutdown(); |
|
67 |
|
68 nsresult GetFontList(nsIAtom *aLangGroup, |
|
69 const nsACString& aGenericFamily, |
|
70 nsTArray<nsString>& aListOfFonts); |
|
71 |
|
72 nsresult UpdateFontList(); |
|
73 |
|
74 nsresult ResolveFontName(const nsAString& aFontName, |
|
75 gfxPlatform::FontResolverCallback aCallback, |
|
76 void *aClosure, bool& aAborted); |
|
77 |
|
78 nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName); |
|
79 |
|
80 const nsTArray< nsCountedRef<FcPattern> >& |
|
81 GetFontsForFamily(const FcChar8 *aFamilyName); |
|
82 |
|
83 const nsTArray< nsCountedRef<FcPattern> >& |
|
84 GetFontsForFullname(const FcChar8 *aFullname); |
|
85 |
|
86 // Returns the best support that any font offers for |aLang|. |
|
87 FcLangResult GetBestLangSupport(const FcChar8 *aLang); |
|
88 // Returns the fonts offering this best level of support. |
|
89 const nsTArray< nsCountedRef<FcPattern> >& |
|
90 GetFontsForLang(const FcChar8 *aLang); |
|
91 |
|
92 // Retuns the language support for a fontconfig font pattern |
|
93 static FcLangResult GetLangSupport(FcPattern *aFont, const FcChar8 *aLang); |
|
94 |
|
95 // Conversions between FcChar8*, which is unsigned char*, |
|
96 // and (signed) char*, that check the type of the argument. |
|
97 static const FcChar8 *ToFcChar8(const char *aCharPtr) |
|
98 { |
|
99 return reinterpret_cast<const FcChar8*>(aCharPtr); |
|
100 } |
|
101 static const FcChar8 *ToFcChar8(const nsCString& aCString) |
|
102 { |
|
103 return ToFcChar8(aCString.get()); |
|
104 } |
|
105 static const char *ToCString(const FcChar8 *aChar8Ptr) |
|
106 { |
|
107 return reinterpret_cast<const char*>(aChar8Ptr); |
|
108 } |
|
109 |
|
110 static uint8_t FcSlantToThebesStyle(int aFcSlant); |
|
111 static uint8_t GetThebesStyle(FcPattern *aPattern); // slant |
|
112 static uint16_t GetThebesWeight(FcPattern *aPattern); |
|
113 static int16_t GetThebesStretch(FcPattern *aPattern); |
|
114 |
|
115 static int GetFcSlant(const gfxFontStyle& aFontStyle); |
|
116 // Returns a precise FC_WEIGHT from |aBaseWeight|, |
|
117 // which is a CSS absolute weight / 100. |
|
118 static int FcWeightForBaseWeight(int8_t aBaseWeight); |
|
119 |
|
120 static int FcWidthForThebesStretch(int16_t aStretch); |
|
121 |
|
122 static bool GetFullnameFromFamilyAndStyle(FcPattern *aFont, |
|
123 nsACString *aFullname); |
|
124 |
|
125 // This doesn't consider which faces exist, and so initializes the pattern |
|
126 // using a guessed weight, and doesn't consider sizeAdjust. |
|
127 static nsReturnRef<FcPattern> |
|
128 NewPattern(const nsTArray<nsString>& aFamilies, |
|
129 const gfxFontStyle& aFontStyle, const char *aLang); |
|
130 |
|
131 /** |
|
132 * @param aLangGroup [in] a Mozilla langGroup. |
|
133 * @param aFcLang [out] returns a language suitable for fontconfig |
|
134 * matching |aLangGroup| or an empty string if no match is found. |
|
135 */ |
|
136 static void GetSampleLangForGroup(nsIAtom *aLangGroup, |
|
137 nsACString *aFcLang); |
|
138 |
|
139 protected: |
|
140 // Base class for hash table entries with case-insensitive FcChar8 |
|
141 // string keys. |
|
142 class FcStrEntryBase : public PLDHashEntryHdr { |
|
143 public: |
|
144 typedef const FcChar8 *KeyType; |
|
145 typedef const FcChar8 *KeyTypePointer; |
|
146 |
|
147 static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } |
|
148 // Case-insensitive hash. |
|
149 // |
|
150 // fontconfig always ignores case of ASCII characters in family |
|
151 // names and languages, but treatment of whitespace in families is |
|
152 // not consistent. FcFontSort and FcFontMatch ignore whitespace |
|
153 // except for whitespace in the first character, while FcFontList |
|
154 // and config subsitution tests require whitespace to match |
|
155 // exactly. CSS 2.1 implies that whitespace is important in the |
|
156 // font-family property. FcStrCmpIgnoreCase considers whitespace |
|
157 // important. |
|
158 static PLDHashNumber HashKey(const FcChar8 *aKey) { |
|
159 uint32_t hash = 0; |
|
160 for (const FcChar8 *c = aKey; *c != '\0'; ++c) { |
|
161 hash = mozilla::RotateLeft(hash, 3) ^ FcToLower(*c); |
|
162 } |
|
163 return hash; |
|
164 } |
|
165 enum { ALLOW_MEMMOVE = true }; |
|
166 }; |
|
167 |
|
168 public: |
|
169 // Hash entry with a dependent const FcChar8* pointer to an external |
|
170 // string for a key (and no data). The user must ensure that the string |
|
171 // associated with the pointer is not destroyed. This entry type is |
|
172 // useful for family name keys as the family name string is held in the |
|
173 // font pattern. |
|
174 class DepFcStrEntry : public FcStrEntryBase { |
|
175 public: |
|
176 // When constructing a new entry in the hashtable, the key is left |
|
177 // nullptr. The caller of PutEntry() must fill in mKey when nullptr. |
|
178 // This provides a mechanism for the caller of PutEntry() to determine |
|
179 // whether the entry has been initialized. |
|
180 DepFcStrEntry(KeyTypePointer aName) |
|
181 : mKey(nullptr) { } |
|
182 |
|
183 DepFcStrEntry(const DepFcStrEntry& toCopy) |
|
184 : mKey(toCopy.mKey) { } |
|
185 |
|
186 bool KeyEquals(KeyTypePointer aKey) const { |
|
187 return FcStrCmpIgnoreCase(aKey, mKey) == 0; |
|
188 } |
|
189 |
|
190 const FcChar8 *mKey; |
|
191 }; |
|
192 |
|
193 // Hash entry that uses a copy of an FcChar8 string to store the key. |
|
194 // This entry type is useful for language keys, as languages are usually |
|
195 // not stored as strings in font patterns. |
|
196 class CopiedFcStrEntry : public FcStrEntryBase { |
|
197 public: |
|
198 // When constructing a new entry in the hashtable, the key is void. |
|
199 // The caller of PutEntry() must call InitKey() when IsKeyInitialized() |
|
200 // returns false. This provides a mechanism for the caller of |
|
201 // PutEntry() to determine whether the entry has been initialized. |
|
202 CopiedFcStrEntry(KeyTypePointer aName) { |
|
203 mKey.SetIsVoid(true); |
|
204 } |
|
205 |
|
206 CopiedFcStrEntry(const CopiedFcStrEntry& toCopy) |
|
207 : mKey(toCopy.mKey) { } |
|
208 |
|
209 bool KeyEquals(KeyTypePointer aKey) const { |
|
210 return FcStrCmpIgnoreCase(aKey, ToFcChar8(mKey)) == 0; |
|
211 } |
|
212 |
|
213 bool IsKeyInitialized() { return !mKey.IsVoid(); } |
|
214 void InitKey(const FcChar8* aKey) { mKey.Assign(ToCString(aKey)); } |
|
215 |
|
216 private: |
|
217 nsCString mKey; |
|
218 }; |
|
219 |
|
220 protected: |
|
221 class FontsByFcStrEntry : public DepFcStrEntry { |
|
222 public: |
|
223 FontsByFcStrEntry(KeyTypePointer aName) |
|
224 : DepFcStrEntry(aName) { } |
|
225 |
|
226 FontsByFcStrEntry(const FontsByFcStrEntry& toCopy) |
|
227 : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { } |
|
228 |
|
229 bool AddFont(FcPattern *aFont) { |
|
230 return mFonts.AppendElement(aFont) != nullptr; |
|
231 } |
|
232 const nsTArray< nsCountedRef<FcPattern> >& GetFonts() { |
|
233 return mFonts; |
|
234 } |
|
235 private: |
|
236 nsTArray< nsCountedRef<FcPattern> > mFonts; |
|
237 }; |
|
238 |
|
239 // FontsByFullnameEntry is similar to FontsByFcStrEntry (used for |
|
240 // mFontsByFamily) except for two differences: |
|
241 // |
|
242 // * The font does not always contain a single string for the fullname, so |
|
243 // the key is sometimes a combination of family and style. |
|
244 // |
|
245 // * There is usually only one font. |
|
246 class FontsByFullnameEntry : public DepFcStrEntry { |
|
247 public: |
|
248 // When constructing a new entry in the hashtable, the key is left |
|
249 // nullptr. The caller of PutEntry() is must fill in mKey when adding |
|
250 // the first font if the key is not derived from the family and style. |
|
251 // If the key is derived from family and style, a font must be added. |
|
252 FontsByFullnameEntry(KeyTypePointer aName) |
|
253 : DepFcStrEntry(aName) { } |
|
254 |
|
255 FontsByFullnameEntry(const FontsByFullnameEntry& toCopy) |
|
256 : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { } |
|
257 |
|
258 bool KeyEquals(KeyTypePointer aKey) const; |
|
259 |
|
260 bool AddFont(FcPattern *aFont) { |
|
261 return mFonts.AppendElement(aFont) != nullptr; |
|
262 } |
|
263 const nsTArray< nsCountedRef<FcPattern> >& GetFonts() { |
|
264 return mFonts; |
|
265 } |
|
266 |
|
267 // Don't memmove the nsAutoTArray. |
|
268 enum { ALLOW_MEMMOVE = false }; |
|
269 private: |
|
270 // There is usually only one font, but sometimes more. |
|
271 nsAutoTArray<nsCountedRef<FcPattern>,1> mFonts; |
|
272 }; |
|
273 |
|
274 class LangSupportEntry : public CopiedFcStrEntry { |
|
275 public: |
|
276 LangSupportEntry(KeyTypePointer aName) |
|
277 : CopiedFcStrEntry(aName) { } |
|
278 |
|
279 LangSupportEntry(const LangSupportEntry& toCopy) |
|
280 : CopiedFcStrEntry(toCopy), mSupport(toCopy.mSupport) { } |
|
281 |
|
282 FcLangResult mSupport; |
|
283 nsTArray< nsCountedRef<FcPattern> > mFonts; |
|
284 }; |
|
285 |
|
286 static gfxFontconfigUtils* sUtils; |
|
287 |
|
288 bool IsExistingFamily(const nsCString& aFamilyName); |
|
289 |
|
290 nsresult GetFontListInternal(nsTArray<nsCString>& aListOfFonts, |
|
291 nsIAtom *aLangGroup); |
|
292 nsresult UpdateFontListInternal(bool aForce = false); |
|
293 |
|
294 void AddFullnameEntries(); |
|
295 |
|
296 LangSupportEntry *GetLangSupportEntry(const FcChar8 *aLang, |
|
297 bool aWithFonts); |
|
298 |
|
299 // mFontsByFamily and mFontsByFullname contain entries only for families |
|
300 // and fullnames for which there are fonts. |
|
301 nsTHashtable<FontsByFcStrEntry> mFontsByFamily; |
|
302 nsTHashtable<FontsByFullnameEntry> mFontsByFullname; |
|
303 // mLangSupportTable contains an entry for each language that has been |
|
304 // looked up through GetLangSupportEntry, even when the language is not |
|
305 // supported. |
|
306 nsTHashtable<LangSupportEntry> mLangSupportTable; |
|
307 const nsTArray< nsCountedRef<FcPattern> > mEmptyPatternArray; |
|
308 |
|
309 nsTArray<nsCString> mAliasForMultiFonts; |
|
310 |
|
311 FcConfig *mLastConfig; |
|
312 }; |
|
313 |
|
314 #endif /* GFX_FONTCONFIG_UTILS_H */ |