Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/thebes/gfxFontFamilyList.h
Line
Count
Source (jump to first uncovered line)
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 "nsAtom.h"
10
#include "nsDebug.h"
11
#include "nsISupportsImpl.h"
12
#include "nsString.h"
13
#include "nsUnicharUtils.h"
14
#include "nsTArray.h"
15
#include "mozilla/MemoryReporting.h"
16
#include "mozilla/NotNull.h"
17
#include "mozilla/StaticPtr.h"
18
19
namespace mozilla {
20
21
/**
22
 * type of font family name, either a name (e.g. Helvetica) or a
23
 * generic (e.g. serif, sans-serif), with the ability to distinguish
24
 * between unquoted and quoted names for serializaiton
25
 */ 
26
27
enum FontFamilyType : uint8_t {
28
  eFamily_none = 0,  // used when finding generics
29
30
  // explicitly named font family (e.g. Helvetica)
31
  eFamily_named,
32
  eFamily_named_quoted,
33
34
  // generics
35
  eFamily_serif,         // pref font code relies on this ordering!!!
36
  eFamily_sans_serif,
37
  eFamily_monospace,
38
  eFamily_cursive,
39
  eFamily_fantasy,
40
41
  // special
42
  eFamily_moz_variable,
43
  eFamily_moz_fixed,
44
  eFamily_moz_emoji,
45
46
  eFamily_generic_first = eFamily_serif,
47
  eFamily_generic_last = eFamily_fantasy,
48
  eFamily_generic_count = (eFamily_fantasy - eFamily_serif + 1)
49
};
50
51
enum QuotedName { eQuotedName, eUnquotedName };
52
53
/**
54
 * font family name, an Atom for the name if not a generic and
55
 * a font type indicated named family or which generic family
56
 */
57
58
struct FontFamilyName final {
59
    FontFamilyName()
60
        : mType(eFamily_named)
61
    {}
62
63
    // named font family - e.g. Helvetica
64
    explicit FontFamilyName(nsAtom* aFamilyName,
65
                            QuotedName aQuoted = eUnquotedName) {
66
        mType = (aQuoted == eQuotedName) ? eFamily_named_quoted : eFamily_named;
67
        mName = aFamilyName;
68
    }
69
70
    explicit FontFamilyName(const nsACString& aFamilyName,
71
0
                            QuotedName aQuoted = eUnquotedName) {
72
0
        mType = (aQuoted == eQuotedName) ? eFamily_named_quoted : eFamily_named;
73
0
        mName = NS_Atomize(aFamilyName);
74
0
    }
75
76
    // generic font family - e.g. sans-serif
77
    explicit FontFamilyName(FontFamilyType aType) {
78
        NS_ASSERTION(aType != eFamily_named &&
79
                     aType != eFamily_named_quoted &&
80
                     aType != eFamily_none,
81
                     "expected a generic font type");
82
        mName = nullptr;
83
        mType = aType;
84
    }
85
86
    FontFamilyName(const FontFamilyName& aCopy) {
87
        mType = aCopy.mType;
88
        mName = aCopy.mName;
89
    }
90
91
0
    bool IsNamed() const {
92
0
        return mType == eFamily_named || mType == eFamily_named_quoted;
93
0
    }
94
95
0
    bool IsGeneric() const {
96
0
        return !IsNamed();
97
0
    }
98
99
    void AppendToString(nsACString& aFamilyList, bool aQuotes = true) const {
100
        switch (mType) {
101
            case eFamily_named:
102
                aFamilyList.Append(nsAtomCString(mName));
103
                break;
104
            case eFamily_named_quoted:
105
                if (aQuotes) {
106
                    aFamilyList.Append('"');
107
                }
108
                aFamilyList.Append(nsAtomCString(mName));
109
                if (aQuotes) {
110
                    aFamilyList.Append('"');
111
                }
112
                break;
113
            case eFamily_serif:
114
                aFamilyList.AppendLiteral("serif");
115
                break;
116
            case eFamily_sans_serif:
117
                aFamilyList.AppendLiteral("sans-serif");
118
                break;
119
            case eFamily_monospace:
120
                aFamilyList.AppendLiteral("monospace");
121
                break;
122
            case eFamily_cursive:
123
                aFamilyList.AppendLiteral("cursive");
124
                break;
125
            case eFamily_fantasy:
126
                aFamilyList.AppendLiteral("fantasy");
127
                break;
128
            case eFamily_moz_fixed:
129
                aFamilyList.AppendLiteral("-moz-fixed");
130
                break;
131
            default:
132
                break;
133
        }
134
    }
135
136
    // helper method that converts generic names to the right enum value
137
    static FontFamilyName
138
0
    Convert(const nsACString& aFamilyOrGenericName) {
139
0
        // should only be passed a single font - not entirely correct, a family
140
0
        // *could* have a comma in it but in practice never does so
141
0
        // for debug purposes this is fine
142
0
        NS_ASSERTION(aFamilyOrGenericName.FindChar(',') == -1,
143
0
                     "Convert method should only be passed a single family name");
144
0
145
0
        FontFamilyType genericType = eFamily_none;
146
0
        if (aFamilyOrGenericName.LowerCaseEqualsLiteral("serif")) {
147
0
            genericType = eFamily_serif;
148
0
        } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("sans-serif")) {
149
0
            genericType = eFamily_sans_serif;
150
0
        } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("monospace")) {
151
0
            genericType = eFamily_monospace;
152
0
        } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("cursive")) {
153
0
            genericType = eFamily_cursive;
154
0
        } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("fantasy")) {
155
0
            genericType = eFamily_fantasy;
156
0
        } else if (aFamilyOrGenericName.LowerCaseEqualsLiteral("-moz-fixed")) {
157
0
            genericType = eFamily_moz_fixed;
158
0
        } else {
159
0
            return FontFamilyName(aFamilyOrGenericName, eUnquotedName);
160
0
        }
161
0
162
0
        return FontFamilyName(genericType);
163
0
    }
164
165
    FontFamilyType mType;
166
    RefPtr<nsAtom> mName; // null if mType != eFamily_named
167
};
168
169
inline bool
170
operator==(const FontFamilyName& a, const FontFamilyName& b) {
171
    return a.mType == b.mType && a.mName == b.mName;
172
}
173
174
/**
175
 * A refcounted array of FontFamilyNames.  We use this to store the specified
176
 * value (in Servo) and the computed value (in both Gecko and Servo) of the
177
 * font-family property.
178
 */
179
class SharedFontList
180
{
181
public:
182
    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedFontList);
183
184
    SharedFontList()
185
    {
186
    }
187
188
    explicit SharedFontList(FontFamilyType aGenericType)
189
        : mNames { FontFamilyName(aGenericType) }
190
    {
191
    }
192
193
    SharedFontList(nsAtom* aFamilyName, QuotedName aQuoted)
194
        : mNames { FontFamilyName(aFamilyName, aQuoted) }
195
    {
196
    }
197
198
    SharedFontList(const nsACString& aFamilyName, QuotedName aQuoted)
199
        : mNames { FontFamilyName(aFamilyName, aQuoted) }
200
    {
201
    }
202
203
    explicit SharedFontList(const FontFamilyName& aName)
204
        : mNames { aName }
205
    {
206
    }
207
208
    explicit SharedFontList(nsTArray<FontFamilyName>&& aNames)
209
        : mNames(std::move(aNames))
210
    {
211
    }
212
213
    FontFamilyType FirstGeneric() const
214
    {
215
        for (const FontFamilyName& name : mNames) {
216
            if (name.IsGeneric()) {
217
                return name.mType;
218
            }
219
        }
220
        return eFamily_none;
221
    }
222
223
    bool HasGeneric() const
224
    {
225
        return FirstGeneric() != eFamily_none;
226
    }
227
228
    size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
229
    {
230
      size_t n = 0;
231
      n += aMallocSizeOf(this);
232
      n += mNames.ShallowSizeOfExcludingThis(aMallocSizeOf);
233
      return n;
234
    }
235
236
    size_t SizeOfIncludingThisIfUnshared(MallocSizeOf aMallocSizeOf) const
237
    {
238
        size_t n = 0;
239
        if (mRefCnt.get() == 1) {
240
          n += SizeOfIncludingThis(aMallocSizeOf);
241
        }
242
        return n;
243
    }
244
245
    const nsTArray<FontFamilyName> mNames;
246
247
    static void Initialize();
248
    static void Shutdown();
249
    static StaticRefPtr<SharedFontList> sEmpty;
250
251
private:
252
    ~SharedFontList() = default;
253
};
254
255
/**
256
 * font family list, array of font families and a default font type.
257
 * font family names are either named strings or generics. the default
258
 * font type is used to preserve the variable font fallback behavior
259
 */
260
class FontFamilyList {
261
public:
262
    FontFamilyList()
263
        : mFontlist(WrapNotNull(SharedFontList::sEmpty.get()))
264
        , mDefaultFontType(eFamily_none)
265
    {
266
    }
267
268
    explicit FontFamilyList(FontFamilyType aGenericType)
269
        : mFontlist(MakeNotNull<SharedFontList*>(aGenericType))
270
        , mDefaultFontType(eFamily_none)
271
    {
272
    }
273
274
    FontFamilyList(nsAtom* aFamilyName,
275
                   QuotedName aQuoted)
276
        : mFontlist(MakeNotNull<SharedFontList*>(aFamilyName, aQuoted))
277
        , mDefaultFontType(eFamily_none)
278
    {
279
    }
280
281
    FontFamilyList(const nsACString& aFamilyName,
282
                   QuotedName aQuoted)
283
        : mFontlist(MakeNotNull<SharedFontList*>(aFamilyName, aQuoted))
284
        , mDefaultFontType(eFamily_none)
285
    {
286
    }
287
288
    explicit FontFamilyList(const FontFamilyName& aName)
289
        : mFontlist(MakeNotNull<SharedFontList*>(aName))
290
        , mDefaultFontType(eFamily_none)
291
    {
292
    }
293
294
    explicit FontFamilyList(nsTArray<FontFamilyName>&& aNames)
295
        : mFontlist(MakeNotNull<SharedFontList*>(std::move(aNames)))
296
        , mDefaultFontType(eFamily_none)
297
    {
298
    }
299
300
    FontFamilyList(const FontFamilyList& aOther)
301
        : mFontlist(aOther.mFontlist)
302
        , mDefaultFontType(aOther.mDefaultFontType)
303
    {
304
    }
305
306
    explicit FontFamilyList(NotNull<SharedFontList*> aFontList)
307
        : mFontlist(aFontList)
308
        , mDefaultFontType(eFamily_none)
309
    {
310
    }
311
312
    void SetFontlist(nsTArray<FontFamilyName>&& aNames)
313
    {
314
        mFontlist = MakeNotNull<SharedFontList*>(std::move(aNames));
315
    }
316
317
    void SetFontlist(NotNull<SharedFontList*> aFontlist)
318
    {
319
        mFontlist = aFontlist;
320
    }
321
322
    uint32_t Length() const {
323
        return mFontlist->mNames.Length();
324
    }
325
326
    bool IsEmpty() const {
327
        return mFontlist->mNames.IsEmpty();
328
    }
329
330
    NotNull<SharedFontList*> GetFontlist() const {
331
        return mFontlist;
332
    }
333
334
    bool Equals(const FontFamilyList& aFontlist) const {
335
        return (mFontlist == aFontlist.mFontlist ||
336
                mFontlist->mNames == aFontlist.mFontlist->mNames) &&
337
               mDefaultFontType == aFontlist.mDefaultFontType;
338
    }
339
340
    FontFamilyType FirstGeneric() const {
341
        return mFontlist->FirstGeneric();
342
    }
343
344
    bool HasGeneric() const
345
    {
346
        return mFontlist->HasGeneric();
347
    }
348
349
    bool HasDefaultGeneric() const {
350
        for (const FontFamilyName& name : mFontlist->mNames) {
351
            if (name.mType == mDefaultFontType) {
352
                return true;
353
            }
354
        }
355
        return false;
356
    }
357
358
    // Find the first generic (but ignoring cursive and fantasy, as they are
359
    // rarely configured in any useful way) in the list.
360
    // If found, move it to the start and return true; else return false.
361
    bool PrioritizeFirstGeneric() {
362
        uint32_t len = mFontlist->mNames.Length();
363
        for (uint32_t i = 0; i < len; i++) {
364
            const FontFamilyName name = mFontlist->mNames[i];
365
            if (name.IsGeneric()) {
366
                if (name.mType == eFamily_cursive ||
367
                    name.mType == eFamily_fantasy) {
368
                    continue;
369
                }
370
                if (i > 0) {
371
                    nsTArray<FontFamilyName> names;
372
                    names.AppendElements(mFontlist->mNames);
373
                    names.RemoveElementAt(i);
374
                    names.InsertElementAt(0, name);
375
                    SetFontlist(std::move(names));
376
                }
377
                return true;
378
            }
379
        }
380
        return false;
381
    }
382
383
    void PrependGeneric(FontFamilyType aType) {
384
        nsTArray<FontFamilyName> names;
385
        names.AppendElements(mFontlist->mNames);
386
        names.InsertElementAt(0, FontFamilyName(aType));
387
        SetFontlist(std::move(names));
388
    }
389
390
    void ToString(nsACString& aFamilyList,
391
                  bool aQuotes = true,
392
                  bool aIncludeDefault = false) const {
393
        const nsTArray<FontFamilyName>& names = mFontlist->mNames;
394
        aFamilyList.Truncate();
395
        uint32_t len = names.Length();
396
        for (uint32_t i = 0; i < len; i++) {
397
            if (i != 0) {
398
                aFamilyList.Append(',');
399
            }
400
            const FontFamilyName& name = names[i];
401
            name.AppendToString(aFamilyList, aQuotes);
402
        }
403
        if (aIncludeDefault && mDefaultFontType != eFamily_none) {
404
            if (!aFamilyList.IsEmpty()) {
405
                aFamilyList.Append(',');
406
            }
407
            if (mDefaultFontType == eFamily_serif) {
408
                aFamilyList.AppendLiteral("serif");
409
            } else {
410
                aFamilyList.AppendLiteral("sans-serif");
411
            }
412
        }
413
    }
414
415
    // searches for a specific non-generic name, lowercase comparison
416
    bool Contains(const nsACString& aFamilyName) const {
417
        NS_ConvertUTF8toUTF16 fam(aFamilyName);
418
        ToLowerCase(fam);
419
        for (const FontFamilyName& name : mFontlist->mNames) {
420
            if (!name.IsNamed()) {
421
                continue;
422
            }
423
            nsAtomString listname(name.mName);
424
            ToLowerCase(listname);
425
            if (listname.Equals(fam)) {
426
                return true;
427
            }
428
        }
429
        return false;
430
    }
431
432
    FontFamilyType GetDefaultFontType() const { return mDefaultFontType; }
433
    void SetDefaultFontType(FontFamilyType aType) {
434
        NS_ASSERTION(aType == eFamily_none || aType == eFamily_serif ||
435
                     aType == eFamily_sans_serif,
436
                     "default font type must be either serif or sans-serif");
437
        mDefaultFontType = aType;
438
    }
439
440
    // memory reporting
441
    size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
442
        size_t n = 0;
443
        n += mFontlist->SizeOfIncludingThisIfUnshared(aMallocSizeOf);
444
        return n;
445
    }
446
447
    size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
448
        return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
449
    }
450
451
protected:
452
    NotNull<RefPtr<SharedFontList>> mFontlist;
453
    FontFamilyType             mDefaultFontType; // none, serif or sans-serif
454
};
455
456
inline bool
457
operator==(const FontFamilyList& a, const FontFamilyList& b) {
458
    return a.Equals(b);
459
}
460
461
inline bool
462
operator!=(const FontFamilyList& a, const FontFamilyList& b) {
463
    return !a.Equals(b);
464
}
465
466
} // namespace mozilla
467
468
#endif /* GFX_FONT_FAMILY_LIST_H */