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_FONT_FAMILY_LIST_H 7 #define GFX_FONT_FAMILY_LIST_H 8 9 #include "nsDebug.h" 10 #include "nsISupportsImpl.h" 11 #include "nsString.h" 12 #include "nsUnicharUtils.h" 13 #include "nsTArray.h" 14 #include "mozilla/MemoryReporting.h" 15 16 namespace mozilla { 17 18 /** 19 * type of font family name, either a name (e.g. Helvetica) or a 20 * generic (e.g. serif, sans-serif), with the ability to distinguish 21 * between unquoted and quoted names for serializaiton 22 */ 23 24 enum FontFamilyType : uint32_t { 25 eFamily_none = 0, // used when finding generics 26 27 // explicitly named font family (e.g. Helvetica) 28 eFamily_named, 29 eFamily_named_quoted, 30 31 // generics 32 eFamily_serif, // pref font code relies on this ordering!!! 33 eFamily_sans_serif, 34 eFamily_monospace, 35 eFamily_cursive, 36 eFamily_fantasy, 37 38 // special 39 eFamily_moz_variable, 40 eFamily_moz_fixed, 41 42 eFamily_generic_first = eFamily_serif, 43 eFamily_generic_last = eFamily_fantasy, 44 eFamily_generic_count = (eFamily_fantasy - eFamily_serif + 1) 45 }; 46 47 enum QuotedName { eQuotedName, eUnquotedName }; 48 49 /** 50 * font family name, a string for the name if not a generic and 51 * a font type indicated named family or which generic family 52 */ 53 54 struct FontFamilyName final { FontFamilyNamefinal55 FontFamilyName() 56 : mType(eFamily_named) 57 {} 58 59 // named font family - e.g. Helvetica 60 explicit FontFamilyName(const nsAString& aFamilyName, 61 QuotedName aQuoted = eUnquotedName) { 62 mType = (aQuoted == eQuotedName) ? eFamily_named_quoted : eFamily_named; 63 mName = aFamilyName; 64 } 65 66 // generic font family - e.g. sans-serif FontFamilyNamefinal67 explicit FontFamilyName(FontFamilyType aType) { 68 NS_ASSERTION(aType != eFamily_named && 69 aType != eFamily_named_quoted && 70 aType != eFamily_none, 71 "expected a generic font type"); 72 mName.Truncate(); 73 mType = aType; 74 } 75 FontFamilyNamefinal76 FontFamilyName(const FontFamilyName& aCopy) { 77 mType = aCopy.mType; 78 mName = aCopy.mName; 79 } 80 IsNamedfinal81 bool IsNamed() const { 82 return mType == eFamily_named || mType == eFamily_named_quoted; 83 } 84 IsGenericfinal85 bool IsGeneric() const { 86 return !IsNamed(); 87 } 88 89 void AppendToString(nsAString& aFamilyList, bool aQuotes = true) const { 90 switch (mType) { 91 case eFamily_named: 92 aFamilyList.Append(mName); 93 break; 94 case eFamily_named_quoted: 95 if (aQuotes) { 96 aFamilyList.Append('"'); 97 } 98 aFamilyList.Append(mName); 99 if (aQuotes) { 100 aFamilyList.Append('"'); 101 } 102 break; 103 case eFamily_serif: 104 aFamilyList.AppendLiteral("serif"); 105 break; 106 case eFamily_sans_serif: 107 aFamilyList.AppendLiteral("sans-serif"); 108 break; 109 case eFamily_monospace: 110 aFamilyList.AppendLiteral("monospace"); 111 break; 112 case eFamily_cursive: 113 aFamilyList.AppendLiteral("cursive"); 114 break; 115 case eFamily_fantasy: 116 aFamilyList.AppendLiteral("fantasy"); 117 break; 118 case eFamily_moz_fixed: 119 aFamilyList.AppendLiteral("-moz-fixed"); 120 break; 121 default: 122 break; 123 } 124 } 125 126 // helper method that converts generic names to the right enum value 127 static FontFamilyName Convertfinal128 Convert(const nsAString& aFamilyOrGenericName) { 129 // should only be passed a single font - not entirely correct, a family 130 // *could* have a comma in it but in practice never does so 131 // for debug purposes this is fine 132 NS_ASSERTION(aFamilyOrGenericName.FindChar(',') == -1, 133 "Convert method should only be passed a single family name"); 134 135 FontFamilyType genericType = eFamily_none; 136 if (aFamilyOrGenericName.LowerCaseEqualsLiteral("serif")) { 137 genericType = eFamily_serif; 138 } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("sans-serif")) { 139 genericType = eFamily_sans_serif; 140 } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("monospace")) { 141 genericType = eFamily_monospace; 142 } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("cursive")) { 143 genericType = eFamily_cursive; 144 } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("fantasy")) { 145 genericType = eFamily_fantasy; 146 } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("-moz-fixed")) { 147 genericType = eFamily_moz_fixed; 148 } else { 149 return FontFamilyName(aFamilyOrGenericName, eUnquotedName); 150 } 151 152 return FontFamilyName(genericType); 153 } 154 155 // memory reporting SizeOfExcludingThisfinal156 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { 157 return mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf); 158 } 159 160 FontFamilyType mType; 161 nsString mName; // empty if mType != eFamily_named 162 }; 163 164 inline bool 165 operator==(const FontFamilyName& a, const FontFamilyName& b) { 166 return a.mType == b.mType && a.mName == b.mName; 167 } 168 169 /** 170 * font family list, array of font families and a default font type. 171 * font family names are either named strings or generics. the default 172 * font type is used to preserve the variable font fallback behavior 173 */ 174 175 class FontFamilyList { 176 public: FontFamilyList()177 FontFamilyList() 178 : mDefaultFontType(eFamily_none) 179 { 180 } 181 FontFamilyList(FontFamilyType aGenericType)182 explicit FontFamilyList(FontFamilyType aGenericType) 183 : mDefaultFontType(eFamily_none) 184 { 185 Append(FontFamilyName(aGenericType)); 186 } 187 FontFamilyList(const nsAString & aFamilyName,QuotedName aQuoted)188 FontFamilyList(const nsAString& aFamilyName, 189 QuotedName aQuoted) 190 : mDefaultFontType(eFamily_none) 191 { 192 Append(FontFamilyName(aFamilyName, aQuoted)); 193 } 194 FontFamilyList(const FontFamilyList & aOther)195 FontFamilyList(const FontFamilyList& aOther) 196 : mFontlist(aOther.mFontlist) 197 , mDefaultFontType(aOther.mDefaultFontType) 198 { 199 } 200 Append(const FontFamilyName & aFamilyName)201 void Append(const FontFamilyName& aFamilyName) { 202 mFontlist.AppendElement(aFamilyName); 203 } 204 Append(const nsTArray<nsString> & aFamilyNameList)205 void Append(const nsTArray<nsString>& aFamilyNameList) { 206 uint32_t len = aFamilyNameList.Length(); 207 for (uint32_t i = 0; i < len; i++) { 208 mFontlist.AppendElement(FontFamilyName(aFamilyNameList[i], 209 eUnquotedName)); 210 } 211 } 212 Clear()213 void Clear() { 214 mFontlist.Clear(); 215 } 216 Length()217 uint32_t Length() const { 218 return mFontlist.Length(); 219 } 220 IsEmpty()221 bool IsEmpty() const { 222 return mFontlist.IsEmpty(); 223 } 224 GetFontlist()225 const nsTArray<FontFamilyName>& GetFontlist() const { 226 return mFontlist; 227 } 228 Equals(const FontFamilyList & aFontlist)229 bool Equals(const FontFamilyList& aFontlist) const { 230 return mFontlist == aFontlist.mFontlist && 231 mDefaultFontType == aFontlist.mDefaultFontType; 232 } 233 FirstGeneric()234 FontFamilyType FirstGeneric() const { 235 uint32_t len = mFontlist.Length(); 236 for (uint32_t i = 0; i < len; i++) { 237 const FontFamilyName& name = mFontlist[i]; 238 if (name.IsGeneric()) { 239 return name.mType; 240 } 241 } 242 return eFamily_none; 243 } 244 HasGeneric()245 bool HasGeneric() const { 246 return FirstGeneric() != eFamily_none; 247 } 248 HasDefaultGeneric()249 bool HasDefaultGeneric() const { 250 uint32_t len = mFontlist.Length(); 251 for (uint32_t i = 0; i < len; i++) { 252 const FontFamilyName& name = mFontlist[i]; 253 if (name.mType == mDefaultFontType) { 254 return true; 255 } 256 } 257 return false; 258 } 259 260 // Find the first generic (but ignoring cursive and fantasy, as they are 261 // rarely configured in any useful way) in the list. 262 // If found, move it to the start and return true; else return false. PrioritizeFirstGeneric()263 bool PrioritizeFirstGeneric() { 264 uint32_t len = mFontlist.Length(); 265 for (uint32_t i = 0; i < len; i++) { 266 const FontFamilyName name = mFontlist[i]; 267 if (name.IsGeneric()) { 268 if (name.mType == eFamily_cursive || 269 name.mType == eFamily_fantasy) { 270 continue; 271 } 272 if (i > 0) { 273 mFontlist.RemoveElementAt(i); 274 mFontlist.InsertElementAt(0, name); 275 } 276 return true; 277 } 278 } 279 return false; 280 } 281 PrependGeneric(FontFamilyType aType)282 void PrependGeneric(FontFamilyType aType) { 283 mFontlist.InsertElementAt(0, FontFamilyName(aType)); 284 } 285 286 void ToString(nsAString& aFamilyList, 287 bool aQuotes = true, 288 bool aIncludeDefault = false) const { 289 aFamilyList.Truncate(); 290 uint32_t len = mFontlist.Length(); 291 for (uint32_t i = 0; i < len; i++) { 292 if (i != 0) { 293 aFamilyList.Append(','); 294 } 295 const FontFamilyName& name = mFontlist[i]; 296 name.AppendToString(aFamilyList, aQuotes); 297 } 298 if (aIncludeDefault && mDefaultFontType != eFamily_none) { 299 if (!aFamilyList.IsEmpty()) { 300 aFamilyList.Append(','); 301 } 302 if (mDefaultFontType == eFamily_serif) { 303 aFamilyList.AppendLiteral("serif"); 304 } else { 305 aFamilyList.AppendLiteral("sans-serif"); 306 } 307 } 308 } 309 310 // searches for a specific non-generic name, lowercase comparison Contains(const nsAString & aFamilyName)311 bool Contains(const nsAString& aFamilyName) const { 312 uint32_t len = mFontlist.Length(); 313 nsAutoString fam(aFamilyName); 314 ToLowerCase(fam); 315 for (uint32_t i = 0; i < len; i++) { 316 const FontFamilyName& name = mFontlist[i]; 317 if (name.mType != eFamily_named && 318 name.mType != eFamily_named_quoted) { 319 continue; 320 } 321 nsAutoString listname(name.mName); 322 ToLowerCase(listname); 323 if (listname.Equals(fam)) { 324 return true; 325 } 326 } 327 return false; 328 } 329 GetDefaultFontType()330 FontFamilyType GetDefaultFontType() const { return mDefaultFontType; } SetDefaultFontType(FontFamilyType aType)331 void SetDefaultFontType(FontFamilyType aType) { 332 NS_ASSERTION(aType == eFamily_none || aType == eFamily_serif || 333 aType == eFamily_sans_serif, 334 "default font type must be either serif or sans-serif"); 335 mDefaultFontType = aType; 336 } 337 338 // memory reporting SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)339 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { 340 size_t n = 0; 341 n += mFontlist.ShallowSizeOfExcludingThis(aMallocSizeOf); 342 for (size_t i = 0; i < mFontlist.Length(); i++) { 343 n += mFontlist[i].SizeOfExcludingThis(aMallocSizeOf); 344 } 345 return n; 346 } 347 SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)348 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { 349 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 350 } 351 352 private: 353 nsTArray<FontFamilyName> mFontlist; 354 FontFamilyType mDefaultFontType; // none, serif or sans-serif 355 }; 356 357 inline bool 358 operator==(const FontFamilyList& a, const FontFamilyList& b) { 359 return a.Equals(b); 360 } 361 362 } // namespace mozilla 363 364 #endif /* GFX_FONT_FAMILY_LIST_H */ 365