1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Japan code.
16 : *
17 : * The Initial Developer of the Original Code is Mozilla Japan.
18 : * Portions created by the Initial Developer are Copyright (C) 2007
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Masayuki Nakano <masayuki@d-toybox.com>
23 : * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #ifndef GFX_FONTCONFIG_UTILS_H
40 : #define GFX_FONTCONFIG_UTILS_H
41 :
42 : #include "gfxPlatform.h"
43 :
44 : #include "nsAutoRef.h"
45 : #include "nsTArray.h"
46 : #include "nsTHashtable.h"
47 : #include "nsISupportsImpl.h"
48 :
49 : #include <fontconfig/fontconfig.h>
50 :
51 :
52 : template <>
53 : class nsAutoRefTraits<FcPattern> : public nsPointerRefTraits<FcPattern>
54 429 : {
55 : public:
56 429 : static void Release(FcPattern *ptr) { FcPatternDestroy(ptr); }
57 429 : static void AddRef(FcPattern *ptr) { FcPatternReference(ptr); }
58 : };
59 :
60 : template <>
61 : class nsAutoRefTraits<FcFontSet> : public nsPointerRefTraits<FcFontSet>
62 0 : {
63 : public:
64 0 : static void Release(FcFontSet *ptr) { FcFontSetDestroy(ptr); }
65 : };
66 :
67 : template <>
68 : class nsAutoRefTraits<FcCharSet> : public nsPointerRefTraits<FcCharSet>
69 0 : {
70 : public:
71 0 : static void Release(FcCharSet *ptr) { FcCharSetDestroy(ptr); }
72 : };
73 :
74 : class gfxIgnoreCaseCStringComparator
75 : {
76 : public:
77 0 : bool Equals(const nsACString& a, const nsACString& b) const
78 : {
79 0 : return nsCString(a).Equals(b, nsCaseInsensitiveCStringComparator());
80 : }
81 :
82 : bool LessThan(const nsACString& a, const nsACString& b) const
83 : {
84 : return a < b;
85 : }
86 : };
87 :
88 : class gfxFontNameList : public nsTArray<nsString>
89 : {
90 : public:
91 : NS_INLINE_DECL_REFCOUNTING(gfxFontNameList)
92 : bool Exists(nsAString& aName);
93 : };
94 :
95 3 : class gfxFontconfigUtils {
96 : public:
97 : gfxFontconfigUtils();
98 :
99 3 : static gfxFontconfigUtils* GetFontconfigUtils() {
100 3 : if (!sUtils)
101 3 : sUtils = new gfxFontconfigUtils();
102 3 : return sUtils;
103 : }
104 :
105 : static void Shutdown();
106 :
107 : nsresult GetFontList(nsIAtom *aLangGroup,
108 : const nsACString& aGenericFamily,
109 : nsTArray<nsString>& aListOfFonts);
110 :
111 : nsresult UpdateFontList();
112 :
113 : nsresult ResolveFontName(const nsAString& aFontName,
114 : gfxPlatform::FontResolverCallback aCallback,
115 : void *aClosure, bool& aAborted);
116 :
117 : nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
118 :
119 : const nsTArray< nsCountedRef<FcPattern> >&
120 : GetFontsForFamily(const FcChar8 *aFamilyName);
121 :
122 : const nsTArray< nsCountedRef<FcPattern> >&
123 : GetFontsForFullname(const FcChar8 *aFullname);
124 :
125 : // Returns the best support that any font offers for |aLang|.
126 : FcLangResult GetBestLangSupport(const FcChar8 *aLang);
127 : // Returns the fonts offering this best level of support.
128 : const nsTArray< nsCountedRef<FcPattern> >&
129 : GetFontsForLang(const FcChar8 *aLang);
130 :
131 : // Retuns the language support for a fontconfig font pattern
132 : static FcLangResult GetLangSupport(FcPattern *aFont, const FcChar8 *aLang);
133 :
134 : // Conversions between FcChar8*, which is unsigned char*,
135 : // and (signed) char*, that check the type of the argument.
136 0 : static const FcChar8 *ToFcChar8(const char *aCharPtr)
137 : {
138 0 : return reinterpret_cast<const FcChar8*>(aCharPtr);
139 : }
140 0 : static const FcChar8 *ToFcChar8(const nsCString& aCString)
141 : {
142 0 : return ToFcChar8(aCString.get());
143 : }
144 0 : static const char *ToCString(const FcChar8 *aChar8Ptr)
145 : {
146 0 : return reinterpret_cast<const char*>(aChar8Ptr);
147 : }
148 :
149 : static PRUint8 FcSlantToThebesStyle(int aFcSlant);
150 : static PRUint8 GetThebesStyle(FcPattern *aPattern); // slant
151 : static PRUint16 GetThebesWeight(FcPattern *aPattern);
152 : static PRInt16 GetThebesStretch(FcPattern *aPattern);
153 :
154 : static int GetFcSlant(const gfxFontStyle& aFontStyle);
155 : // Returns a precise FC_WEIGHT from |aBaseWeight|,
156 : // which is a CSS absolute weight / 100.
157 : static int FcWeightForBaseWeight(PRInt8 aBaseWeight);
158 :
159 : static int FcWidthForThebesStretch(PRInt16 aStretch);
160 :
161 : static bool GetFullnameFromFamilyAndStyle(FcPattern *aFont,
162 : nsACString *aFullname);
163 :
164 : // This doesn't consider which faces exist, and so initializes the pattern
165 : // using a guessed weight, and doesn't consider sizeAdjust.
166 : static nsReturnRef<FcPattern>
167 : NewPattern(const nsTArray<nsString>& aFamilies,
168 : const gfxFontStyle& aFontStyle, const char *aLang);
169 :
170 : /**
171 : * @param aLangGroup [in] a Mozilla langGroup.
172 : * @param aFcLang [out] returns a language suitable for fontconfig
173 : * matching |aLangGroup| or an empty string if no match is found.
174 : */
175 : static void GetSampleLangForGroup(nsIAtom *aLangGroup,
176 : nsACString *aFcLang);
177 :
178 : protected:
179 : // Base class for hash table entries with case-insensitive FcChar8
180 : // string keys.
181 102 : class FcStrEntryBase : public PLDHashEntryHdr {
182 : public:
183 : typedef const FcChar8 *KeyType;
184 : typedef const FcChar8 *KeyTypePointer;
185 :
186 429 : static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
187 : // Case-insensitive hash.
188 : //
189 : // fontconfig always ignores case of ASCII characters in family
190 : // names and languages, but treatment of whitespace in families is
191 : // not consistent. FcFontSort and FcFontMatch ignore whitespace
192 : // except for whitespace in the first character, while FcFontList
193 : // and config subsitution tests require whitespace to match
194 : // exactly. CSS 2.1 implies that whitespace is important in the
195 : // font-family property. FcStrCmpIgnoreCase considers whitespace
196 : // important.
197 429 : static PLDHashNumber HashKey(const FcChar8 *aKey) {
198 429 : PRUint32 hash = 0;
199 6588 : for (const FcChar8 *c = aKey; *c != '\0'; ++c) {
200 6159 : hash = PR_ROTATE_LEFT32(hash, 3) ^ FcToLower(*c);
201 : }
202 429 : return hash;
203 : }
204 : enum { ALLOW_MEMMOVE = true };
205 : };
206 :
207 : public:
208 : // Hash entry with a dependent const FcChar8* pointer to an external
209 : // string for a key (and no data). The user must ensure that the string
210 : // associated with the pointer is not destroyed. This entry type is
211 : // useful for family name keys as the family name string is held in the
212 : // font pattern.
213 0 : class DepFcStrEntry : public FcStrEntryBase {
214 : public:
215 : // When constructing a new entry in the hashtable, the key is left
216 : // NULL. The caller of PutEntry() must fill in mKey when NULL. This
217 : // provides a mechanism for the caller of PutEntry() to determine
218 : // whether the entry has been initialized.
219 102 : DepFcStrEntry(KeyTypePointer aName)
220 102 : : mKey(NULL) { }
221 :
222 0 : DepFcStrEntry(const DepFcStrEntry& toCopy)
223 0 : : mKey(toCopy.mKey) { }
224 :
225 327 : bool KeyEquals(KeyTypePointer aKey) const {
226 327 : return FcStrCmpIgnoreCase(aKey, mKey) == 0;
227 : }
228 :
229 : const FcChar8 *mKey;
230 : };
231 :
232 : // Hash entry that uses a copy of an FcChar8 string to store the key.
233 : // This entry type is useful for language keys, as languages are usually
234 : // not stored as strings in font patterns.
235 0 : class CopiedFcStrEntry : public FcStrEntryBase {
236 : public:
237 : // When constructing a new entry in the hashtable, the key is void.
238 : // The caller of PutEntry() must call InitKey() when IsKeyInitialized()
239 : // returns false. This provides a mechanism for the caller of
240 : // PutEntry() to determine whether the entry has been initialized.
241 0 : CopiedFcStrEntry(KeyTypePointer aName) {
242 0 : mKey.SetIsVoid(true);
243 0 : }
244 :
245 : CopiedFcStrEntry(const CopiedFcStrEntry& toCopy)
246 : : mKey(toCopy.mKey) { }
247 :
248 0 : bool KeyEquals(KeyTypePointer aKey) const {
249 0 : return FcStrCmpIgnoreCase(aKey, ToFcChar8(mKey)) == 0;
250 : }
251 :
252 0 : bool IsKeyInitialized() { return !mKey.IsVoid(); }
253 0 : void InitKey(const FcChar8* aKey) { mKey.Assign(ToCString(aKey)); }
254 :
255 : private:
256 : nsCString mKey;
257 : };
258 :
259 : protected:
260 102 : class FontsByFcStrEntry : public DepFcStrEntry {
261 : public:
262 102 : FontsByFcStrEntry(KeyTypePointer aName)
263 102 : : DepFcStrEntry(aName) { }
264 :
265 : FontsByFcStrEntry(const FontsByFcStrEntry& toCopy)
266 : : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { }
267 :
268 429 : bool AddFont(FcPattern *aFont) {
269 429 : return mFonts.AppendElement(aFont) != nsnull;
270 : }
271 0 : const nsTArray< nsCountedRef<FcPattern> >& GetFonts() {
272 0 : return mFonts;
273 : }
274 : private:
275 : nsTArray< nsCountedRef<FcPattern> > mFonts;
276 : };
277 :
278 : // FontsByFullnameEntry is similar to FontsByFcStrEntry (used for
279 : // mFontsByFamily) except for two differences:
280 : //
281 : // * The font does not always contain a single string for the fullname, so
282 : // the key is sometimes a combination of family and style.
283 : //
284 : // * There is usually only one font.
285 0 : class FontsByFullnameEntry : public DepFcStrEntry {
286 : public:
287 : // When constructing a new entry in the hashtable, the key is left
288 : // NULL. The caller of PutEntry() is must fill in mKey when adding
289 : // the first font if the key is not derived from the family and style.
290 : // If the key is derived from family and style, a font must be added.
291 0 : FontsByFullnameEntry(KeyTypePointer aName)
292 0 : : DepFcStrEntry(aName) { }
293 :
294 0 : FontsByFullnameEntry(const FontsByFullnameEntry& toCopy)
295 0 : : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { }
296 :
297 : bool KeyEquals(KeyTypePointer aKey) const;
298 :
299 0 : bool AddFont(FcPattern *aFont) {
300 0 : return mFonts.AppendElement(aFont) != nsnull;
301 : }
302 0 : const nsTArray< nsCountedRef<FcPattern> >& GetFonts() {
303 0 : return mFonts;
304 : }
305 :
306 : // Don't memmove the nsAutoTArray.
307 : enum { ALLOW_MEMMOVE = false };
308 : private:
309 : // There is usually only one font, but sometimes more.
310 : nsAutoTArray<nsCountedRef<FcPattern>,1> mFonts;
311 : };
312 :
313 0 : class LangSupportEntry : public CopiedFcStrEntry {
314 : public:
315 0 : LangSupportEntry(KeyTypePointer aName)
316 0 : : CopiedFcStrEntry(aName) { }
317 :
318 : LangSupportEntry(const LangSupportEntry& toCopy)
319 : : CopiedFcStrEntry(toCopy), mSupport(toCopy.mSupport) { }
320 :
321 : FcLangResult mSupport;
322 : nsTArray< nsCountedRef<FcPattern> > mFonts;
323 : };
324 :
325 : static gfxFontconfigUtils* sUtils;
326 :
327 : bool IsExistingFamily(const nsCString& aFamilyName);
328 :
329 : nsresult GetFontListInternal(nsTArray<nsCString>& aListOfFonts,
330 : nsIAtom *aLangGroup);
331 : nsresult UpdateFontListInternal(bool aForce = false);
332 :
333 : void AddFullnameEntries();
334 :
335 : LangSupportEntry *GetLangSupportEntry(const FcChar8 *aLang,
336 : bool aWithFonts);
337 :
338 : // mFontsByFamily and mFontsByFullname contain entries only for families
339 : // and fullnames for which there are fonts.
340 : nsTHashtable<FontsByFcStrEntry> mFontsByFamily;
341 : nsTHashtable<FontsByFullnameEntry> mFontsByFullname;
342 : // mLangSupportTable contains an entry for each language that has been
343 : // looked up through GetLangSupportEntry, even when the language is not
344 : // supported.
345 : nsTHashtable<LangSupportEntry> mLangSupportTable;
346 : const nsTArray< nsCountedRef<FcPattern> > mEmptyPatternArray;
347 :
348 : nsTArray<nsCString> mAliasForMultiFonts;
349 :
350 : FcConfig *mLastConfig;
351 : };
352 :
353 : #endif /* GFX_FONTCONFIG_UTILS_H */
|