diff options
Diffstat (limited to 'gfx/thebes/gfxFontFamilyList.h')
-rw-r--r-- | gfx/thebes/gfxFontFamilyList.h | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/gfx/thebes/gfxFontFamilyList.h b/gfx/thebes/gfxFontFamilyList.h new file mode 100644 index 000000000..e240102e0 --- /dev/null +++ b/gfx/thebes/gfxFontFamilyList.h @@ -0,0 +1,364 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GFX_FONT_FAMILY_LIST_H +#define GFX_FONT_FAMILY_LIST_H + +#include "nsDebug.h" +#include "nsISupportsImpl.h" +#include "nsString.h" +#include "nsUnicharUtils.h" +#include "nsTArray.h" +#include "mozilla/MemoryReporting.h" + +namespace mozilla { + +/** + * type of font family name, either a name (e.g. Helvetica) or a + * generic (e.g. serif, sans-serif), with the ability to distinguish + * between unquoted and quoted names for serializaiton + */ + +enum FontFamilyType : uint32_t { + eFamily_none = 0, // used when finding generics + + // explicitly named font family (e.g. Helvetica) + eFamily_named, + eFamily_named_quoted, + + // generics + eFamily_serif, // pref font code relies on this ordering!!! + eFamily_sans_serif, + eFamily_monospace, + eFamily_cursive, + eFamily_fantasy, + + // special + eFamily_moz_variable, + eFamily_moz_fixed, + + eFamily_generic_first = eFamily_serif, + eFamily_generic_last = eFamily_fantasy, + eFamily_generic_count = (eFamily_fantasy - eFamily_serif + 1) +}; + +enum QuotedName { eQuotedName, eUnquotedName }; + +/** + * font family name, a string for the name if not a generic and + * a font type indicated named family or which generic family + */ + +struct FontFamilyName final { + FontFamilyName() + : mType(eFamily_named) + {} + + // named font family - e.g. Helvetica + explicit FontFamilyName(const nsAString& aFamilyName, + QuotedName aQuoted = eUnquotedName) { + mType = (aQuoted == eQuotedName) ? eFamily_named_quoted : eFamily_named; + mName = aFamilyName; + } + + // generic font family - e.g. sans-serif + explicit FontFamilyName(FontFamilyType aType) { + NS_ASSERTION(aType != eFamily_named && + aType != eFamily_named_quoted && + aType != eFamily_none, + "expected a generic font type"); + mName.Truncate(); + mType = aType; + } + + FontFamilyName(const FontFamilyName& aCopy) { + mType = aCopy.mType; + mName = aCopy.mName; + } + + bool IsNamed() const { + return mType == eFamily_named || mType == eFamily_named_quoted; + } + + bool IsGeneric() const { + return !IsNamed(); + } + + void AppendToString(nsAString& aFamilyList, bool aQuotes = true) const { + switch (mType) { + case eFamily_named: + aFamilyList.Append(mName); + break; + case eFamily_named_quoted: + if (aQuotes) { + aFamilyList.Append('"'); + } + aFamilyList.Append(mName); + if (aQuotes) { + aFamilyList.Append('"'); + } + break; + case eFamily_serif: + aFamilyList.AppendLiteral("serif"); + break; + case eFamily_sans_serif: + aFamilyList.AppendLiteral("sans-serif"); + break; + case eFamily_monospace: + aFamilyList.AppendLiteral("monospace"); + break; + case eFamily_cursive: + aFamilyList.AppendLiteral("cursive"); + break; + case eFamily_fantasy: + aFamilyList.AppendLiteral("fantasy"); + break; + case eFamily_moz_fixed: + aFamilyList.AppendLiteral("-moz-fixed"); + break; + default: + break; + } + } + + // helper method that converts generic names to the right enum value + static FontFamilyName + Convert(const nsAString& aFamilyOrGenericName) { + // should only be passed a single font - not entirely correct, a family + // *could* have a comma in it but in practice never does so + // for debug purposes this is fine + NS_ASSERTION(aFamilyOrGenericName.FindChar(',') == -1, + "Convert method should only be passed a single family name"); + + FontFamilyType genericType = eFamily_none; + if (aFamilyOrGenericName.LowerCaseEqualsLiteral("serif")) { + genericType = eFamily_serif; + } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("sans-serif")) { + genericType = eFamily_sans_serif; + } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("monospace")) { + genericType = eFamily_monospace; + } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("cursive")) { + genericType = eFamily_cursive; + } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("fantasy")) { + genericType = eFamily_fantasy; + } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("-moz-fixed")) { + genericType = eFamily_moz_fixed; + } else { + return FontFamilyName(aFamilyOrGenericName, eUnquotedName); + } + + return FontFamilyName(genericType); + } + + // memory reporting + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { + return mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf); + } + + FontFamilyType mType; + nsString mName; // empty if mType != eFamily_named +}; + +inline bool +operator==(const FontFamilyName& a, const FontFamilyName& b) { + return a.mType == b.mType && a.mName == b.mName; +} + +/** + * font family list, array of font families and a default font type. + * font family names are either named strings or generics. the default + * font type is used to preserve the variable font fallback behavior + */ + +class FontFamilyList { +public: + FontFamilyList() + : mDefaultFontType(eFamily_none) + { + } + + explicit FontFamilyList(FontFamilyType aGenericType) + : mDefaultFontType(eFamily_none) + { + Append(FontFamilyName(aGenericType)); + } + + FontFamilyList(const nsAString& aFamilyName, + QuotedName aQuoted) + : mDefaultFontType(eFamily_none) + { + Append(FontFamilyName(aFamilyName, aQuoted)); + } + + FontFamilyList(const FontFamilyList& aOther) + : mFontlist(aOther.mFontlist) + , mDefaultFontType(aOther.mDefaultFontType) + { + } + + void Append(const FontFamilyName& aFamilyName) { + mFontlist.AppendElement(aFamilyName); + } + + void Append(const nsTArray<nsString>& aFamilyNameList) { + uint32_t len = aFamilyNameList.Length(); + for (uint32_t i = 0; i < len; i++) { + mFontlist.AppendElement(FontFamilyName(aFamilyNameList[i], + eUnquotedName)); + } + } + + void Clear() { + mFontlist.Clear(); + } + + uint32_t Length() const { + return mFontlist.Length(); + } + + bool IsEmpty() const { + return mFontlist.IsEmpty(); + } + + const nsTArray<FontFamilyName>& GetFontlist() const { + return mFontlist; + } + + bool Equals(const FontFamilyList& aFontlist) const { + return mFontlist == aFontlist.mFontlist && + mDefaultFontType == aFontlist.mDefaultFontType; + } + + FontFamilyType FirstGeneric() const { + uint32_t len = mFontlist.Length(); + for (uint32_t i = 0; i < len; i++) { + const FontFamilyName& name = mFontlist[i]; + if (name.IsGeneric()) { + return name.mType; + } + } + return eFamily_none; + } + + bool HasGeneric() const { + return FirstGeneric() != eFamily_none; + } + + bool HasDefaultGeneric() const { + uint32_t len = mFontlist.Length(); + for (uint32_t i = 0; i < len; i++) { + const FontFamilyName& name = mFontlist[i]; + if (name.mType == mDefaultFontType) { + return true; + } + } + return false; + } + + // Find the first generic (but ignoring cursive and fantasy, as they are + // rarely configured in any useful way) in the list. + // If found, move it to the start and return true; else return false. + bool PrioritizeFirstGeneric() { + uint32_t len = mFontlist.Length(); + for (uint32_t i = 0; i < len; i++) { + const FontFamilyName name = mFontlist[i]; + if (name.IsGeneric()) { + if (name.mType == eFamily_cursive || + name.mType == eFamily_fantasy) { + continue; + } + if (i > 0) { + mFontlist.RemoveElementAt(i); + mFontlist.InsertElementAt(0, name); + } + return true; + } + } + return false; + } + + void PrependGeneric(FontFamilyType aType) { + mFontlist.InsertElementAt(0, FontFamilyName(aType)); + } + + void ToString(nsAString& aFamilyList, + bool aQuotes = true, + bool aIncludeDefault = false) const { + aFamilyList.Truncate(); + uint32_t len = mFontlist.Length(); + for (uint32_t i = 0; i < len; i++) { + if (i != 0) { + aFamilyList.Append(','); + } + const FontFamilyName& name = mFontlist[i]; + name.AppendToString(aFamilyList, aQuotes); + } + if (aIncludeDefault && mDefaultFontType != eFamily_none) { + if (!aFamilyList.IsEmpty()) { + aFamilyList.Append(','); + } + if (mDefaultFontType == eFamily_serif) { + aFamilyList.AppendLiteral("serif"); + } else { + aFamilyList.AppendLiteral("sans-serif"); + } + } + } + + // searches for a specific non-generic name, lowercase comparison + bool Contains(const nsAString& aFamilyName) const { + uint32_t len = mFontlist.Length(); + nsAutoString fam(aFamilyName); + ToLowerCase(fam); + for (uint32_t i = 0; i < len; i++) { + const FontFamilyName& name = mFontlist[i]; + if (name.mType != eFamily_named && + name.mType != eFamily_named_quoted) { + continue; + } + nsAutoString listname(name.mName); + ToLowerCase(listname); + if (listname.Equals(fam)) { + return true; + } + } + return false; + } + + FontFamilyType GetDefaultFontType() const { return mDefaultFontType; } + void SetDefaultFontType(FontFamilyType aType) { + NS_ASSERTION(aType == eFamily_none || aType == eFamily_serif || + aType == eFamily_sans_serif, + "default font type must be either serif or sans-serif"); + mDefaultFontType = aType; + } + + // memory reporting + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { + size_t n = 0; + n += mFontlist.ShallowSizeOfExcludingThis(aMallocSizeOf); + for (size_t i = 0; i < mFontlist.Length(); i++) { + n += mFontlist[i].SizeOfExcludingThis(aMallocSizeOf); + } + return n; + } + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); + } + +private: + nsTArray<FontFamilyName> mFontlist; + FontFamilyType mDefaultFontType; // none, serif or sans-serif +}; + +inline bool +operator==(const FontFamilyList& a, const FontFamilyList& b) { + return a.Equals(b); +} + +} // namespace mozilla + +#endif /* GFX_FONT_FAMILY_LIST_H */ |