michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef GFX_FONTCONFIG_UTILS_H michael@0: #define GFX_FONTCONFIG_UTILS_H michael@0: michael@0: #include "gfxPlatform.h" michael@0: michael@0: #include "mozilla/MathAlgorithms.h" michael@0: #include "nsAutoRef.h" michael@0: #include "nsTArray.h" michael@0: #include "nsTHashtable.h" michael@0: #include "nsISupportsImpl.h" michael@0: michael@0: #include michael@0: michael@0: michael@0: template <> michael@0: class nsAutoRefTraits : public nsPointerRefTraits michael@0: { michael@0: public: michael@0: static void Release(FcPattern *ptr) { FcPatternDestroy(ptr); } michael@0: static void AddRef(FcPattern *ptr) { FcPatternReference(ptr); } michael@0: }; michael@0: michael@0: template <> michael@0: class nsAutoRefTraits : public nsPointerRefTraits michael@0: { michael@0: public: michael@0: static void Release(FcFontSet *ptr) { FcFontSetDestroy(ptr); } michael@0: }; michael@0: michael@0: template <> michael@0: class nsAutoRefTraits : public nsPointerRefTraits michael@0: { michael@0: public: michael@0: static void Release(FcCharSet *ptr) { FcCharSetDestroy(ptr); } michael@0: }; michael@0: michael@0: class gfxIgnoreCaseCStringComparator michael@0: { michael@0: public: michael@0: bool Equals(const nsACString& a, const nsACString& b) const michael@0: { michael@0: return nsCString(a).Equals(b, nsCaseInsensitiveCStringComparator()); michael@0: } michael@0: michael@0: bool LessThan(const nsACString& a, const nsACString& b) const michael@0: { michael@0: return a < b; michael@0: } michael@0: }; michael@0: michael@0: class gfxFontconfigUtils { michael@0: public: michael@0: gfxFontconfigUtils(); michael@0: michael@0: static gfxFontconfigUtils* GetFontconfigUtils() { michael@0: if (!sUtils) michael@0: sUtils = new gfxFontconfigUtils(); michael@0: return sUtils; michael@0: } michael@0: michael@0: static void Shutdown(); michael@0: michael@0: nsresult GetFontList(nsIAtom *aLangGroup, michael@0: const nsACString& aGenericFamily, michael@0: nsTArray& aListOfFonts); michael@0: michael@0: nsresult UpdateFontList(); michael@0: michael@0: nsresult ResolveFontName(const nsAString& aFontName, michael@0: gfxPlatform::FontResolverCallback aCallback, michael@0: void *aClosure, bool& aAborted); michael@0: michael@0: nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName); michael@0: michael@0: const nsTArray< nsCountedRef >& michael@0: GetFontsForFamily(const FcChar8 *aFamilyName); michael@0: michael@0: const nsTArray< nsCountedRef >& michael@0: GetFontsForFullname(const FcChar8 *aFullname); michael@0: michael@0: // Returns the best support that any font offers for |aLang|. michael@0: FcLangResult GetBestLangSupport(const FcChar8 *aLang); michael@0: // Returns the fonts offering this best level of support. michael@0: const nsTArray< nsCountedRef >& michael@0: GetFontsForLang(const FcChar8 *aLang); michael@0: michael@0: // Retuns the language support for a fontconfig font pattern michael@0: static FcLangResult GetLangSupport(FcPattern *aFont, const FcChar8 *aLang); michael@0: michael@0: // Conversions between FcChar8*, which is unsigned char*, michael@0: // and (signed) char*, that check the type of the argument. michael@0: static const FcChar8 *ToFcChar8(const char *aCharPtr) michael@0: { michael@0: return reinterpret_cast(aCharPtr); michael@0: } michael@0: static const FcChar8 *ToFcChar8(const nsCString& aCString) michael@0: { michael@0: return ToFcChar8(aCString.get()); michael@0: } michael@0: static const char *ToCString(const FcChar8 *aChar8Ptr) michael@0: { michael@0: return reinterpret_cast(aChar8Ptr); michael@0: } michael@0: michael@0: static uint8_t FcSlantToThebesStyle(int aFcSlant); michael@0: static uint8_t GetThebesStyle(FcPattern *aPattern); // slant michael@0: static uint16_t GetThebesWeight(FcPattern *aPattern); michael@0: static int16_t GetThebesStretch(FcPattern *aPattern); michael@0: michael@0: static int GetFcSlant(const gfxFontStyle& aFontStyle); michael@0: // Returns a precise FC_WEIGHT from |aBaseWeight|, michael@0: // which is a CSS absolute weight / 100. michael@0: static int FcWeightForBaseWeight(int8_t aBaseWeight); michael@0: michael@0: static int FcWidthForThebesStretch(int16_t aStretch); michael@0: michael@0: static bool GetFullnameFromFamilyAndStyle(FcPattern *aFont, michael@0: nsACString *aFullname); michael@0: michael@0: // This doesn't consider which faces exist, and so initializes the pattern michael@0: // using a guessed weight, and doesn't consider sizeAdjust. michael@0: static nsReturnRef michael@0: NewPattern(const nsTArray& aFamilies, michael@0: const gfxFontStyle& aFontStyle, const char *aLang); michael@0: michael@0: /** michael@0: * @param aLangGroup [in] a Mozilla langGroup. michael@0: * @param aFcLang [out] returns a language suitable for fontconfig michael@0: * matching |aLangGroup| or an empty string if no match is found. michael@0: */ michael@0: static void GetSampleLangForGroup(nsIAtom *aLangGroup, michael@0: nsACString *aFcLang); michael@0: michael@0: protected: michael@0: // Base class for hash table entries with case-insensitive FcChar8 michael@0: // string keys. michael@0: class FcStrEntryBase : public PLDHashEntryHdr { michael@0: public: michael@0: typedef const FcChar8 *KeyType; michael@0: typedef const FcChar8 *KeyTypePointer; michael@0: michael@0: static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } michael@0: // Case-insensitive hash. michael@0: // michael@0: // fontconfig always ignores case of ASCII characters in family michael@0: // names and languages, but treatment of whitespace in families is michael@0: // not consistent. FcFontSort and FcFontMatch ignore whitespace michael@0: // except for whitespace in the first character, while FcFontList michael@0: // and config subsitution tests require whitespace to match michael@0: // exactly. CSS 2.1 implies that whitespace is important in the michael@0: // font-family property. FcStrCmpIgnoreCase considers whitespace michael@0: // important. michael@0: static PLDHashNumber HashKey(const FcChar8 *aKey) { michael@0: uint32_t hash = 0; michael@0: for (const FcChar8 *c = aKey; *c != '\0'; ++c) { michael@0: hash = mozilla::RotateLeft(hash, 3) ^ FcToLower(*c); michael@0: } michael@0: return hash; michael@0: } michael@0: enum { ALLOW_MEMMOVE = true }; michael@0: }; michael@0: michael@0: public: michael@0: // Hash entry with a dependent const FcChar8* pointer to an external michael@0: // string for a key (and no data). The user must ensure that the string michael@0: // associated with the pointer is not destroyed. This entry type is michael@0: // useful for family name keys as the family name string is held in the michael@0: // font pattern. michael@0: class DepFcStrEntry : public FcStrEntryBase { michael@0: public: michael@0: // When constructing a new entry in the hashtable, the key is left michael@0: // nullptr. The caller of PutEntry() must fill in mKey when nullptr. michael@0: // This provides a mechanism for the caller of PutEntry() to determine michael@0: // whether the entry has been initialized. michael@0: DepFcStrEntry(KeyTypePointer aName) michael@0: : mKey(nullptr) { } michael@0: michael@0: DepFcStrEntry(const DepFcStrEntry& toCopy) michael@0: : mKey(toCopy.mKey) { } michael@0: michael@0: bool KeyEquals(KeyTypePointer aKey) const { michael@0: return FcStrCmpIgnoreCase(aKey, mKey) == 0; michael@0: } michael@0: michael@0: const FcChar8 *mKey; michael@0: }; michael@0: michael@0: // Hash entry that uses a copy of an FcChar8 string to store the key. michael@0: // This entry type is useful for language keys, as languages are usually michael@0: // not stored as strings in font patterns. michael@0: class CopiedFcStrEntry : public FcStrEntryBase { michael@0: public: michael@0: // When constructing a new entry in the hashtable, the key is void. michael@0: // The caller of PutEntry() must call InitKey() when IsKeyInitialized() michael@0: // returns false. This provides a mechanism for the caller of michael@0: // PutEntry() to determine whether the entry has been initialized. michael@0: CopiedFcStrEntry(KeyTypePointer aName) { michael@0: mKey.SetIsVoid(true); michael@0: } michael@0: michael@0: CopiedFcStrEntry(const CopiedFcStrEntry& toCopy) michael@0: : mKey(toCopy.mKey) { } michael@0: michael@0: bool KeyEquals(KeyTypePointer aKey) const { michael@0: return FcStrCmpIgnoreCase(aKey, ToFcChar8(mKey)) == 0; michael@0: } michael@0: michael@0: bool IsKeyInitialized() { return !mKey.IsVoid(); } michael@0: void InitKey(const FcChar8* aKey) { mKey.Assign(ToCString(aKey)); } michael@0: michael@0: private: michael@0: nsCString mKey; michael@0: }; michael@0: michael@0: protected: michael@0: class FontsByFcStrEntry : public DepFcStrEntry { michael@0: public: michael@0: FontsByFcStrEntry(KeyTypePointer aName) michael@0: : DepFcStrEntry(aName) { } michael@0: michael@0: FontsByFcStrEntry(const FontsByFcStrEntry& toCopy) michael@0: : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { } michael@0: michael@0: bool AddFont(FcPattern *aFont) { michael@0: return mFonts.AppendElement(aFont) != nullptr; michael@0: } michael@0: const nsTArray< nsCountedRef >& GetFonts() { michael@0: return mFonts; michael@0: } michael@0: private: michael@0: nsTArray< nsCountedRef > mFonts; michael@0: }; michael@0: michael@0: // FontsByFullnameEntry is similar to FontsByFcStrEntry (used for michael@0: // mFontsByFamily) except for two differences: michael@0: // michael@0: // * The font does not always contain a single string for the fullname, so michael@0: // the key is sometimes a combination of family and style. michael@0: // michael@0: // * There is usually only one font. michael@0: class FontsByFullnameEntry : public DepFcStrEntry { michael@0: public: michael@0: // When constructing a new entry in the hashtable, the key is left michael@0: // nullptr. The caller of PutEntry() is must fill in mKey when adding michael@0: // the first font if the key is not derived from the family and style. michael@0: // If the key is derived from family and style, a font must be added. michael@0: FontsByFullnameEntry(KeyTypePointer aName) michael@0: : DepFcStrEntry(aName) { } michael@0: michael@0: FontsByFullnameEntry(const FontsByFullnameEntry& toCopy) michael@0: : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { } michael@0: michael@0: bool KeyEquals(KeyTypePointer aKey) const; michael@0: michael@0: bool AddFont(FcPattern *aFont) { michael@0: return mFonts.AppendElement(aFont) != nullptr; michael@0: } michael@0: const nsTArray< nsCountedRef >& GetFonts() { michael@0: return mFonts; michael@0: } michael@0: michael@0: // Don't memmove the nsAutoTArray. michael@0: enum { ALLOW_MEMMOVE = false }; michael@0: private: michael@0: // There is usually only one font, but sometimes more. michael@0: nsAutoTArray,1> mFonts; michael@0: }; michael@0: michael@0: class LangSupportEntry : public CopiedFcStrEntry { michael@0: public: michael@0: LangSupportEntry(KeyTypePointer aName) michael@0: : CopiedFcStrEntry(aName) { } michael@0: michael@0: LangSupportEntry(const LangSupportEntry& toCopy) michael@0: : CopiedFcStrEntry(toCopy), mSupport(toCopy.mSupport) { } michael@0: michael@0: FcLangResult mSupport; michael@0: nsTArray< nsCountedRef > mFonts; michael@0: }; michael@0: michael@0: static gfxFontconfigUtils* sUtils; michael@0: michael@0: bool IsExistingFamily(const nsCString& aFamilyName); michael@0: michael@0: nsresult GetFontListInternal(nsTArray& aListOfFonts, michael@0: nsIAtom *aLangGroup); michael@0: nsresult UpdateFontListInternal(bool aForce = false); michael@0: michael@0: void AddFullnameEntries(); michael@0: michael@0: LangSupportEntry *GetLangSupportEntry(const FcChar8 *aLang, michael@0: bool aWithFonts); michael@0: michael@0: // mFontsByFamily and mFontsByFullname contain entries only for families michael@0: // and fullnames for which there are fonts. michael@0: nsTHashtable mFontsByFamily; michael@0: nsTHashtable mFontsByFullname; michael@0: // mLangSupportTable contains an entry for each language that has been michael@0: // looked up through GetLangSupportEntry, even when the language is not michael@0: // supported. michael@0: nsTHashtable mLangSupportTable; michael@0: const nsTArray< nsCountedRef > mEmptyPatternArray; michael@0: michael@0: nsTArray mAliasForMultiFonts; michael@0: michael@0: FcConfig *mLastConfig; michael@0: }; michael@0: michael@0: #endif /* GFX_FONTCONFIG_UTILS_H */