Line data Source code
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 392 : struct FontFamilyName final {
55 0 : FontFamilyName()
56 0 : : mType(eFamily_named)
57 0 : {}
58 :
59 : // named font family - e.g. Helvetica
60 10 : explicit FontFamilyName(const nsAString& aFamilyName,
61 10 : QuotedName aQuoted = eUnquotedName) {
62 10 : mType = (aQuoted == eQuotedName) ? eFamily_named_quoted : eFamily_named;
63 10 : mName = aFamilyName;
64 10 : }
65 :
66 : // generic font family - e.g. sans-serif
67 247 : explicit FontFamilyName(FontFamilyType aType) {
68 247 : NS_ASSERTION(aType != eFamily_named &&
69 : aType != eFamily_named_quoted &&
70 : aType != eFamily_none,
71 : "expected a generic font type");
72 247 : mName.Truncate();
73 247 : mType = aType;
74 247 : }
75 :
76 391 : FontFamilyName(const FontFamilyName& aCopy) {
77 391 : mType = aCopy.mType;
78 391 : mName = aCopy.mName;
79 391 : }
80 :
81 7 : bool IsNamed() const {
82 7 : return mType == eFamily_named || mType == eFamily_named_quoted;
83 : }
84 :
85 1 : bool IsGeneric() const {
86 1 : return !IsNamed();
87 : }
88 :
89 0 : void AppendToString(nsAString& aFamilyList, bool aQuotes = true) const {
90 0 : switch (mType) {
91 : case eFamily_named:
92 0 : aFamilyList.Append(mName);
93 0 : break;
94 : case eFamily_named_quoted:
95 0 : if (aQuotes) {
96 0 : aFamilyList.Append('"');
97 : }
98 0 : aFamilyList.Append(mName);
99 0 : if (aQuotes) {
100 0 : aFamilyList.Append('"');
101 : }
102 0 : break;
103 : case eFamily_serif:
104 0 : aFamilyList.AppendLiteral("serif");
105 0 : break;
106 : case eFamily_sans_serif:
107 0 : aFamilyList.AppendLiteral("sans-serif");
108 0 : break;
109 : case eFamily_monospace:
110 0 : aFamilyList.AppendLiteral("monospace");
111 0 : break;
112 : case eFamily_cursive:
113 0 : aFamilyList.AppendLiteral("cursive");
114 0 : break;
115 : case eFamily_fantasy:
116 0 : aFamilyList.AppendLiteral("fantasy");
117 0 : break;
118 : case eFamily_moz_fixed:
119 0 : aFamilyList.AppendLiteral("-moz-fixed");
120 0 : break;
121 : default:
122 0 : break;
123 : }
124 0 : }
125 :
126 : // helper method that converts generic names to the right enum value
127 : static FontFamilyName
128 8 : 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 8 : NS_ASSERTION(aFamilyOrGenericName.FindChar(',') == -1,
133 : "Convert method should only be passed a single family name");
134 :
135 8 : FontFamilyType genericType = eFamily_none;
136 8 : if (aFamilyOrGenericName.LowerCaseEqualsLiteral("serif")) {
137 7 : genericType = eFamily_serif;
138 1 : } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("sans-serif")) {
139 0 : genericType = eFamily_sans_serif;
140 1 : } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("monospace")) {
141 0 : genericType = eFamily_monospace;
142 1 : } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("cursive")) {
143 0 : genericType = eFamily_cursive;
144 1 : } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("fantasy")) {
145 0 : genericType = eFamily_fantasy;
146 1 : } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("-moz-fixed")) {
147 0 : genericType = eFamily_moz_fixed;
148 : } else {
149 1 : return FontFamilyName(aFamilyOrGenericName, eUnquotedName);
150 : }
151 :
152 7 : return FontFamilyName(genericType);
153 : }
154 :
155 : // memory reporting
156 0 : size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
157 0 : return mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
158 : }
159 :
160 : FontFamilyType mType;
161 : nsString mName; // empty if mType != eFamily_named
162 : };
163 :
164 : inline bool
165 445 : operator==(const FontFamilyName& a, const FontFamilyName& b) {
166 445 : 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 135 : class FontFamilyList {
176 : public:
177 16 : FontFamilyList()
178 16 : : mDefaultFontType(eFamily_none)
179 : {
180 16 : }
181 :
182 224 : explicit FontFamilyList(FontFamilyType aGenericType)
183 224 : : mDefaultFontType(eFamily_none)
184 : {
185 224 : Append(FontFamilyName(aGenericType));
186 224 : }
187 :
188 6 : FontFamilyList(const nsAString& aFamilyName,
189 : QuotedName aQuoted)
190 6 : : mDefaultFontType(eFamily_none)
191 : {
192 6 : Append(FontFamilyName(aFamilyName, aQuoted));
193 6 : }
194 :
195 117 : FontFamilyList(const FontFamilyList& aOther)
196 117 : : mFontlist(aOther.mFontlist)
197 117 : , mDefaultFontType(aOther.mDefaultFontType)
198 : {
199 117 : }
200 :
201 249 : void Append(const FontFamilyName& aFamilyName) {
202 249 : mFontlist.AppendElement(aFamilyName);
203 249 : }
204 :
205 0 : void Append(const nsTArray<nsString>& aFamilyNameList) {
206 0 : uint32_t len = aFamilyNameList.Length();
207 0 : for (uint32_t i = 0; i < len; i++) {
208 0 : mFontlist.AppendElement(FontFamilyName(aFamilyNameList[i],
209 0 : eUnquotedName));
210 : }
211 0 : }
212 :
213 0 : void Clear() {
214 0 : mFontlist.Clear();
215 0 : }
216 :
217 0 : uint32_t Length() const {
218 0 : return mFontlist.Length();
219 : }
220 :
221 16 : bool IsEmpty() const {
222 16 : return mFontlist.IsEmpty();
223 : }
224 :
225 6 : const nsTArray<FontFamilyName>& GetFontlist() const {
226 6 : return mFontlist;
227 : }
228 :
229 445 : bool Equals(const FontFamilyList& aFontlist) const {
230 890 : return mFontlist == aFontlist.mFontlist &&
231 890 : mDefaultFontType == aFontlist.mDefaultFontType;
232 : }
233 :
234 0 : FontFamilyType FirstGeneric() const {
235 0 : uint32_t len = mFontlist.Length();
236 0 : for (uint32_t i = 0; i < len; i++) {
237 0 : const FontFamilyName& name = mFontlist[i];
238 0 : if (name.IsGeneric()) {
239 0 : return name.mType;
240 : }
241 : }
242 0 : return eFamily_none;
243 : }
244 :
245 0 : bool HasGeneric() const {
246 0 : return FirstGeneric() != eFamily_none;
247 : }
248 :
249 0 : bool HasDefaultGeneric() const {
250 0 : uint32_t len = mFontlist.Length();
251 0 : for (uint32_t i = 0; i < len; i++) {
252 0 : const FontFamilyName& name = mFontlist[i];
253 0 : if (name.mType == mDefaultFontType) {
254 0 : return true;
255 : }
256 : }
257 0 : 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.
263 0 : bool PrioritizeFirstGeneric() {
264 0 : uint32_t len = mFontlist.Length();
265 0 : for (uint32_t i = 0; i < len; i++) {
266 0 : const FontFamilyName name = mFontlist[i];
267 0 : if (name.IsGeneric()) {
268 0 : if (name.mType == eFamily_cursive ||
269 0 : name.mType == eFamily_fantasy) {
270 0 : continue;
271 : }
272 0 : if (i > 0) {
273 0 : mFontlist.RemoveElementAt(i);
274 0 : mFontlist.InsertElementAt(0, name);
275 : }
276 0 : return true;
277 : }
278 : }
279 0 : return false;
280 : }
281 :
282 0 : void PrependGeneric(FontFamilyType aType) {
283 0 : mFontlist.InsertElementAt(0, FontFamilyName(aType));
284 0 : }
285 :
286 0 : void ToString(nsAString& aFamilyList,
287 : bool aQuotes = true,
288 : bool aIncludeDefault = false) const {
289 0 : aFamilyList.Truncate();
290 0 : uint32_t len = mFontlist.Length();
291 0 : for (uint32_t i = 0; i < len; i++) {
292 0 : if (i != 0) {
293 0 : aFamilyList.Append(',');
294 : }
295 0 : const FontFamilyName& name = mFontlist[i];
296 0 : name.AppendToString(aFamilyList, aQuotes);
297 : }
298 0 : if (aIncludeDefault && mDefaultFontType != eFamily_none) {
299 0 : if (!aFamilyList.IsEmpty()) {
300 0 : aFamilyList.Append(',');
301 : }
302 0 : if (mDefaultFontType == eFamily_serif) {
303 0 : aFamilyList.AppendLiteral("serif");
304 : } else {
305 0 : aFamilyList.AppendLiteral("sans-serif");
306 : }
307 : }
308 0 : }
309 :
310 : // searches for a specific non-generic name, lowercase comparison
311 0 : bool Contains(const nsAString& aFamilyName) const {
312 0 : uint32_t len = mFontlist.Length();
313 0 : nsAutoString fam(aFamilyName);
314 0 : ToLowerCase(fam);
315 0 : for (uint32_t i = 0; i < len; i++) {
316 0 : const FontFamilyName& name = mFontlist[i];
317 0 : if (name.mType != eFamily_named &&
318 0 : name.mType != eFamily_named_quoted) {
319 0 : continue;
320 : }
321 0 : nsAutoString listname(name.mName);
322 0 : ToLowerCase(listname);
323 0 : if (listname.Equals(fam)) {
324 0 : return true;
325 : }
326 : }
327 0 : return false;
328 : }
329 :
330 6 : FontFamilyType GetDefaultFontType() const { return mDefaultFontType; }
331 6 : void SetDefaultFontType(FontFamilyType aType) {
332 6 : 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 6 : mDefaultFontType = aType;
336 6 : }
337 :
338 : // memory reporting
339 0 : size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
340 0 : size_t n = 0;
341 0 : n += mFontlist.ShallowSizeOfExcludingThis(aMallocSizeOf);
342 0 : for (size_t i = 0; i < mFontlist.Length(); i++) {
343 0 : n += mFontlist[i].SizeOfExcludingThis(aMallocSizeOf);
344 : }
345 0 : return n;
346 : }
347 :
348 0 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
349 0 : 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 445 : operator==(const FontFamilyList& a, const FontFamilyList& b) {
359 445 : return a.Equals(b);
360 : }
361 :
362 : } // namespace mozilla
363 :
364 : #endif /* GFX_FONT_FAMILY_LIST_H */
|