1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfxFontconfigUtils.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,314 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef GFX_FONTCONFIG_UTILS_H 1.10 +#define GFX_FONTCONFIG_UTILS_H 1.11 + 1.12 +#include "gfxPlatform.h" 1.13 + 1.14 +#include "mozilla/MathAlgorithms.h" 1.15 +#include "nsAutoRef.h" 1.16 +#include "nsTArray.h" 1.17 +#include "nsTHashtable.h" 1.18 +#include "nsISupportsImpl.h" 1.19 + 1.20 +#include <fontconfig/fontconfig.h> 1.21 + 1.22 + 1.23 +template <> 1.24 +class nsAutoRefTraits<FcPattern> : public nsPointerRefTraits<FcPattern> 1.25 +{ 1.26 +public: 1.27 + static void Release(FcPattern *ptr) { FcPatternDestroy(ptr); } 1.28 + static void AddRef(FcPattern *ptr) { FcPatternReference(ptr); } 1.29 +}; 1.30 + 1.31 +template <> 1.32 +class nsAutoRefTraits<FcFontSet> : public nsPointerRefTraits<FcFontSet> 1.33 +{ 1.34 +public: 1.35 + static void Release(FcFontSet *ptr) { FcFontSetDestroy(ptr); } 1.36 +}; 1.37 + 1.38 +template <> 1.39 +class nsAutoRefTraits<FcCharSet> : public nsPointerRefTraits<FcCharSet> 1.40 +{ 1.41 +public: 1.42 + static void Release(FcCharSet *ptr) { FcCharSetDestroy(ptr); } 1.43 +}; 1.44 + 1.45 +class gfxIgnoreCaseCStringComparator 1.46 +{ 1.47 + public: 1.48 + bool Equals(const nsACString& a, const nsACString& b) const 1.49 + { 1.50 + return nsCString(a).Equals(b, nsCaseInsensitiveCStringComparator()); 1.51 + } 1.52 + 1.53 + bool LessThan(const nsACString& a, const nsACString& b) const 1.54 + { 1.55 + return a < b; 1.56 + } 1.57 +}; 1.58 + 1.59 +class gfxFontconfigUtils { 1.60 +public: 1.61 + gfxFontconfigUtils(); 1.62 + 1.63 + static gfxFontconfigUtils* GetFontconfigUtils() { 1.64 + if (!sUtils) 1.65 + sUtils = new gfxFontconfigUtils(); 1.66 + return sUtils; 1.67 + } 1.68 + 1.69 + static void Shutdown(); 1.70 + 1.71 + nsresult GetFontList(nsIAtom *aLangGroup, 1.72 + const nsACString& aGenericFamily, 1.73 + nsTArray<nsString>& aListOfFonts); 1.74 + 1.75 + nsresult UpdateFontList(); 1.76 + 1.77 + nsresult ResolveFontName(const nsAString& aFontName, 1.78 + gfxPlatform::FontResolverCallback aCallback, 1.79 + void *aClosure, bool& aAborted); 1.80 + 1.81 + nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName); 1.82 + 1.83 + const nsTArray< nsCountedRef<FcPattern> >& 1.84 + GetFontsForFamily(const FcChar8 *aFamilyName); 1.85 + 1.86 + const nsTArray< nsCountedRef<FcPattern> >& 1.87 + GetFontsForFullname(const FcChar8 *aFullname); 1.88 + 1.89 + // Returns the best support that any font offers for |aLang|. 1.90 + FcLangResult GetBestLangSupport(const FcChar8 *aLang); 1.91 + // Returns the fonts offering this best level of support. 1.92 + const nsTArray< nsCountedRef<FcPattern> >& 1.93 + GetFontsForLang(const FcChar8 *aLang); 1.94 + 1.95 + // Retuns the language support for a fontconfig font pattern 1.96 + static FcLangResult GetLangSupport(FcPattern *aFont, const FcChar8 *aLang); 1.97 + 1.98 + // Conversions between FcChar8*, which is unsigned char*, 1.99 + // and (signed) char*, that check the type of the argument. 1.100 + static const FcChar8 *ToFcChar8(const char *aCharPtr) 1.101 + { 1.102 + return reinterpret_cast<const FcChar8*>(aCharPtr); 1.103 + } 1.104 + static const FcChar8 *ToFcChar8(const nsCString& aCString) 1.105 + { 1.106 + return ToFcChar8(aCString.get()); 1.107 + } 1.108 + static const char *ToCString(const FcChar8 *aChar8Ptr) 1.109 + { 1.110 + return reinterpret_cast<const char*>(aChar8Ptr); 1.111 + } 1.112 + 1.113 + static uint8_t FcSlantToThebesStyle(int aFcSlant); 1.114 + static uint8_t GetThebesStyle(FcPattern *aPattern); // slant 1.115 + static uint16_t GetThebesWeight(FcPattern *aPattern); 1.116 + static int16_t GetThebesStretch(FcPattern *aPattern); 1.117 + 1.118 + static int GetFcSlant(const gfxFontStyle& aFontStyle); 1.119 + // Returns a precise FC_WEIGHT from |aBaseWeight|, 1.120 + // which is a CSS absolute weight / 100. 1.121 + static int FcWeightForBaseWeight(int8_t aBaseWeight); 1.122 + 1.123 + static int FcWidthForThebesStretch(int16_t aStretch); 1.124 + 1.125 + static bool GetFullnameFromFamilyAndStyle(FcPattern *aFont, 1.126 + nsACString *aFullname); 1.127 + 1.128 + // This doesn't consider which faces exist, and so initializes the pattern 1.129 + // using a guessed weight, and doesn't consider sizeAdjust. 1.130 + static nsReturnRef<FcPattern> 1.131 + NewPattern(const nsTArray<nsString>& aFamilies, 1.132 + const gfxFontStyle& aFontStyle, const char *aLang); 1.133 + 1.134 + /** 1.135 + * @param aLangGroup [in] a Mozilla langGroup. 1.136 + * @param aFcLang [out] returns a language suitable for fontconfig 1.137 + * matching |aLangGroup| or an empty string if no match is found. 1.138 + */ 1.139 + static void GetSampleLangForGroup(nsIAtom *aLangGroup, 1.140 + nsACString *aFcLang); 1.141 + 1.142 +protected: 1.143 + // Base class for hash table entries with case-insensitive FcChar8 1.144 + // string keys. 1.145 + class FcStrEntryBase : public PLDHashEntryHdr { 1.146 + public: 1.147 + typedef const FcChar8 *KeyType; 1.148 + typedef const FcChar8 *KeyTypePointer; 1.149 + 1.150 + static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } 1.151 + // Case-insensitive hash. 1.152 + // 1.153 + // fontconfig always ignores case of ASCII characters in family 1.154 + // names and languages, but treatment of whitespace in families is 1.155 + // not consistent. FcFontSort and FcFontMatch ignore whitespace 1.156 + // except for whitespace in the first character, while FcFontList 1.157 + // and config subsitution tests require whitespace to match 1.158 + // exactly. CSS 2.1 implies that whitespace is important in the 1.159 + // font-family property. FcStrCmpIgnoreCase considers whitespace 1.160 + // important. 1.161 + static PLDHashNumber HashKey(const FcChar8 *aKey) { 1.162 + uint32_t hash = 0; 1.163 + for (const FcChar8 *c = aKey; *c != '\0'; ++c) { 1.164 + hash = mozilla::RotateLeft(hash, 3) ^ FcToLower(*c); 1.165 + } 1.166 + return hash; 1.167 + } 1.168 + enum { ALLOW_MEMMOVE = true }; 1.169 + }; 1.170 + 1.171 +public: 1.172 + // Hash entry with a dependent const FcChar8* pointer to an external 1.173 + // string for a key (and no data). The user must ensure that the string 1.174 + // associated with the pointer is not destroyed. This entry type is 1.175 + // useful for family name keys as the family name string is held in the 1.176 + // font pattern. 1.177 + class DepFcStrEntry : public FcStrEntryBase { 1.178 + public: 1.179 + // When constructing a new entry in the hashtable, the key is left 1.180 + // nullptr. The caller of PutEntry() must fill in mKey when nullptr. 1.181 + // This provides a mechanism for the caller of PutEntry() to determine 1.182 + // whether the entry has been initialized. 1.183 + DepFcStrEntry(KeyTypePointer aName) 1.184 + : mKey(nullptr) { } 1.185 + 1.186 + DepFcStrEntry(const DepFcStrEntry& toCopy) 1.187 + : mKey(toCopy.mKey) { } 1.188 + 1.189 + bool KeyEquals(KeyTypePointer aKey) const { 1.190 + return FcStrCmpIgnoreCase(aKey, mKey) == 0; 1.191 + } 1.192 + 1.193 + const FcChar8 *mKey; 1.194 + }; 1.195 + 1.196 + // Hash entry that uses a copy of an FcChar8 string to store the key. 1.197 + // This entry type is useful for language keys, as languages are usually 1.198 + // not stored as strings in font patterns. 1.199 + class CopiedFcStrEntry : public FcStrEntryBase { 1.200 + public: 1.201 + // When constructing a new entry in the hashtable, the key is void. 1.202 + // The caller of PutEntry() must call InitKey() when IsKeyInitialized() 1.203 + // returns false. This provides a mechanism for the caller of 1.204 + // PutEntry() to determine whether the entry has been initialized. 1.205 + CopiedFcStrEntry(KeyTypePointer aName) { 1.206 + mKey.SetIsVoid(true); 1.207 + } 1.208 + 1.209 + CopiedFcStrEntry(const CopiedFcStrEntry& toCopy) 1.210 + : mKey(toCopy.mKey) { } 1.211 + 1.212 + bool KeyEquals(KeyTypePointer aKey) const { 1.213 + return FcStrCmpIgnoreCase(aKey, ToFcChar8(mKey)) == 0; 1.214 + } 1.215 + 1.216 + bool IsKeyInitialized() { return !mKey.IsVoid(); } 1.217 + void InitKey(const FcChar8* aKey) { mKey.Assign(ToCString(aKey)); } 1.218 + 1.219 + private: 1.220 + nsCString mKey; 1.221 + }; 1.222 + 1.223 +protected: 1.224 + class FontsByFcStrEntry : public DepFcStrEntry { 1.225 + public: 1.226 + FontsByFcStrEntry(KeyTypePointer aName) 1.227 + : DepFcStrEntry(aName) { } 1.228 + 1.229 + FontsByFcStrEntry(const FontsByFcStrEntry& toCopy) 1.230 + : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { } 1.231 + 1.232 + bool AddFont(FcPattern *aFont) { 1.233 + return mFonts.AppendElement(aFont) != nullptr; 1.234 + } 1.235 + const nsTArray< nsCountedRef<FcPattern> >& GetFonts() { 1.236 + return mFonts; 1.237 + } 1.238 + private: 1.239 + nsTArray< nsCountedRef<FcPattern> > mFonts; 1.240 + }; 1.241 + 1.242 + // FontsByFullnameEntry is similar to FontsByFcStrEntry (used for 1.243 + // mFontsByFamily) except for two differences: 1.244 + // 1.245 + // * The font does not always contain a single string for the fullname, so 1.246 + // the key is sometimes a combination of family and style. 1.247 + // 1.248 + // * There is usually only one font. 1.249 + class FontsByFullnameEntry : public DepFcStrEntry { 1.250 + public: 1.251 + // When constructing a new entry in the hashtable, the key is left 1.252 + // nullptr. The caller of PutEntry() is must fill in mKey when adding 1.253 + // the first font if the key is not derived from the family and style. 1.254 + // If the key is derived from family and style, a font must be added. 1.255 + FontsByFullnameEntry(KeyTypePointer aName) 1.256 + : DepFcStrEntry(aName) { } 1.257 + 1.258 + FontsByFullnameEntry(const FontsByFullnameEntry& toCopy) 1.259 + : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { } 1.260 + 1.261 + bool KeyEquals(KeyTypePointer aKey) const; 1.262 + 1.263 + bool AddFont(FcPattern *aFont) { 1.264 + return mFonts.AppendElement(aFont) != nullptr; 1.265 + } 1.266 + const nsTArray< nsCountedRef<FcPattern> >& GetFonts() { 1.267 + return mFonts; 1.268 + } 1.269 + 1.270 + // Don't memmove the nsAutoTArray. 1.271 + enum { ALLOW_MEMMOVE = false }; 1.272 + private: 1.273 + // There is usually only one font, but sometimes more. 1.274 + nsAutoTArray<nsCountedRef<FcPattern>,1> mFonts; 1.275 + }; 1.276 + 1.277 + class LangSupportEntry : public CopiedFcStrEntry { 1.278 + public: 1.279 + LangSupportEntry(KeyTypePointer aName) 1.280 + : CopiedFcStrEntry(aName) { } 1.281 + 1.282 + LangSupportEntry(const LangSupportEntry& toCopy) 1.283 + : CopiedFcStrEntry(toCopy), mSupport(toCopy.mSupport) { } 1.284 + 1.285 + FcLangResult mSupport; 1.286 + nsTArray< nsCountedRef<FcPattern> > mFonts; 1.287 + }; 1.288 + 1.289 + static gfxFontconfigUtils* sUtils; 1.290 + 1.291 + bool IsExistingFamily(const nsCString& aFamilyName); 1.292 + 1.293 + nsresult GetFontListInternal(nsTArray<nsCString>& aListOfFonts, 1.294 + nsIAtom *aLangGroup); 1.295 + nsresult UpdateFontListInternal(bool aForce = false); 1.296 + 1.297 + void AddFullnameEntries(); 1.298 + 1.299 + LangSupportEntry *GetLangSupportEntry(const FcChar8 *aLang, 1.300 + bool aWithFonts); 1.301 + 1.302 + // mFontsByFamily and mFontsByFullname contain entries only for families 1.303 + // and fullnames for which there are fonts. 1.304 + nsTHashtable<FontsByFcStrEntry> mFontsByFamily; 1.305 + nsTHashtable<FontsByFullnameEntry> mFontsByFullname; 1.306 + // mLangSupportTable contains an entry for each language that has been 1.307 + // looked up through GetLangSupportEntry, even when the language is not 1.308 + // supported. 1.309 + nsTHashtable<LangSupportEntry> mLangSupportTable; 1.310 + const nsTArray< nsCountedRef<FcPattern> > mEmptyPatternArray; 1.311 + 1.312 + nsTArray<nsCString> mAliasForMultiFonts; 1.313 + 1.314 + FcConfig *mLastConfig; 1.315 +}; 1.316 + 1.317 +#endif /* GFX_FONTCONFIG_UTILS_H */