summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/SharedFontList.h
blob: 6ef2a7744c7d27452c6ad5297a3d0717e3c844be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
/* 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 SharedFontList_h
#define SharedFontList_h

#include "gfxFontEntry.h"
#include <atomic>

class gfxCharacterMap;
struct gfxFontStyle;
struct GlobalFontMatch;

namespace mozilla {
namespace fontlist {

class FontList;  // See the separate SharedFontList-impl.h header

/**
 * A Pointer in the shared font list contains a packed index/offset pair,
 * with a 12-bit index into the array of shared-memory blocks, and a 20-bit
 * offset into the block.
 * The maximum size of each block is therefore 2^20 bytes (1 MB) if sub-parts
 * of the block are to be allocated; however, a larger block (up to 2^32 bytes)
 * can be created and used as a single allocation if necessary.
 */
struct Pointer {
 private:
  friend class FontList;
  static const uint32_t kIndexBits = 12u;
  static const uint32_t kBlockShift = 20u;
  static_assert(kIndexBits + kBlockShift == 32u, "bad Pointer bit count");

  static const uint32_t kNullValue = 0xffffffffu;
  static const uint32_t kOffsetMask = (1u << kBlockShift) - 1;

 public:
  static Pointer Null() { return Pointer(); }

  Pointer() : mBlockAndOffset(kNullValue) {}

  Pointer(uint32_t aBlock, uint32_t aOffset)
      : mBlockAndOffset((aBlock << kBlockShift) | aOffset) {
    MOZ_ASSERT(aBlock < (1u << kIndexBits) && aOffset < (1u << kBlockShift));
  }

  Pointer(const Pointer& aOther) {
    mBlockAndOffset.store(aOther.mBlockAndOffset);
  }

  Pointer(Pointer&& aOther) { mBlockAndOffset.store(aOther.mBlockAndOffset); }

  /**
   * Check if a Pointer has the null value.
   *
   * NOTE!
   * In a child process, it is possible that conversion to a "real" pointer
   * using ToPtr() will fail even when IsNull() is false, so calling code
   * that may run in child processes must be prepared to handle this.
   */
  bool IsNull() const { return mBlockAndOffset == kNullValue; }

  uint32_t Block() const { return mBlockAndOffset >> kBlockShift; }

  uint32_t Offset() const { return mBlockAndOffset & kOffsetMask; }

  /**
   * Convert a fontlist::Pointer to a standard C++ pointer. This requires the
   * FontList, which will know where the shared memory block is mapped in
   * the current process's address space.
   *
   * NOTE!
   * In child processes this may fail and return nullptr, even if IsNull() is
   * false, in cases where the font list is in the process of being rebuilt.
   */
  void* ToPtr(FontList* aFontList) const;

  Pointer& operator=(const Pointer& aOther) {
    mBlockAndOffset.store(aOther.mBlockAndOffset);
    return *this;
  }

  Pointer& operator=(Pointer&& aOther) {
    mBlockAndOffset.store(aOther.mBlockAndOffset);
    return *this;
  }

  // We store the block index and the offset within the block as a single
  // atomic 32-bit value so we can safely modify a Pointer without other
  // processes seeing a broken (partially-updated) value.
  std::atomic<uint32_t> mBlockAndOffset;
};

/**
 * Family and face names are stored as String records, which hold a length
 * (in utf-8 code units) and a Pointer to the string's UTF-8 characters.
 */
struct String {
  String() : mPointer(Pointer::Null()), mLength(0) {}

  String(FontList* aList, const nsACString& aString)
      : mPointer(Pointer::Null()) {
    Assign(aString, aList);
  }

  const nsCString AsString(FontList* aList) const {
    MOZ_ASSERT(!mPointer.IsNull());
    // It's tempting to use AssignLiteral here so that we get an nsCString that
    // simply wraps the character data in the shmem block without needing to
    // allocate or copy. But that's unsafe because in the event of font-list
    // reinitalization, that shared memory will be unmapped; then any copy of
    // the nsCString that may still be around will crash if accessed.
    return nsCString(static_cast<const char*>(mPointer.ToPtr(aList)), mLength);
  }

  void Assign(const nsACString& aString, FontList* aList);

  const char* BeginReading(FontList* aList) const {
    MOZ_ASSERT(!mPointer.IsNull());
    auto str = static_cast<const char*>(mPointer.ToPtr(aList));
    return str ? str : "";
  }

  uint32_t Length() const { return mLength; }

  /**
   * Return whether the String has been set to a value.
   *
   * NOTE!
   * In a child process, accessing the value could fail even if IsNull()
   * returned false. In this case, the nsCString constructor used by AsString()
   * will be passed a null pointer, and return an empty string despite the
   * non-zero Length() recorded here.
   */
  bool IsNull() const { return mPointer.IsNull(); }

 private:
  Pointer mPointer;
  uint32_t mLength;
};

/**
 * A Face record represents an individual font resource; it has the style
 * properties needed for font matching, as well as a pointer to a character
 * map that records the supported character set. This may be Null if we have
 * not yet loaded the data.
 * The mDescriptor and mIndex fields provide the information needed to
 * instantiate a (platform-specific) font reference that can be used with
 * platform font APIs; their content depends on the requirements of the
 * platform APIs (e.g. font PostScript name, file pathname, serialized
 * fontconfig pattern, etc).
 */
struct Face {
  // Data required to initialize a Face
  struct InitData {
    nsCString mDescriptor;  // descriptor that can be used to instantiate a
                            // platform font reference
    uint16_t mIndex;        // an index used with descriptor (on some platforms)
    bool mFixedPitch;       // is the face fixed-pitch (monospaced)?
    mozilla::WeightRange mWeight;      // CSS font-weight value
    mozilla::StretchRange mStretch;    // CSS font-stretch value
    mozilla::SlantStyleRange mStyle;   // CSS font-style value
    RefPtr<gfxCharacterMap> mCharMap;  // character map, or null if not loaded
  };

  // Note that mCharacterMap is not set from the InitData by this constructor;
  // the caller must use SetCharacterMap to handle that separately if required.
  Face(FontList* aList, const InitData& aData)
      : mDescriptor(aList, aData.mDescriptor),
        mIndex(aData.mIndex),
        mFixedPitch(aData.mFixedPitch),
        mWeight(aData.mWeight),
        mStretch(aData.mStretch),
        mStyle(aData.mStyle),
        mCharacterMap(Pointer::Null()) {}

  bool HasValidDescriptor() const {
    return !mDescriptor.IsNull() && mIndex != uint16_t(-1);
  }

  void SetCharacterMap(FontList* aList, gfxCharacterMap* aCharMap);

  String mDescriptor;
  uint16_t mIndex;
  bool mFixedPitch;
  mozilla::WeightRange mWeight;
  mozilla::StretchRange mStretch;
  mozilla::SlantStyleRange mStyle;
  Pointer mCharacterMap;
};

/**
 * A Family record represents an available (installed) font family; it has
 * a name (for display purposes) and a key (lowercased, for case-insensitive
 * lookups), as well as a pointer to an array of Faces. Depending on the
 * platform, the array of faces may be lazily initialized the first time we
 * want to use the family.
 */
struct Family {
  static constexpr uint32_t kNoIndex = uint32_t(-1);

  // Data required to initialize a Family
  struct InitData {
    InitData(const nsACString& aKey,      // lookup key (lowercased)
             const nsACString& aName,     // display name
             uint32_t aIndex = kNoIndex,  // [win] system collection index
             FontVisibility aVisibility = FontVisibility::Unknown,
             bool aBundled = false,       // [win] font was bundled with the app
                                          // rather than system-installed
             bool aBadUnderline = false,  // underline-position in font is bad
             bool aForceClassic = false,  // [win] use "GDI classic" rendering
             bool aAltLocale = false      // font is alternate localized family
             )
        : mKey(aKey),
          mName(aName),
          mIndex(aIndex),
          mVisibility(aVisibility),
          mBundled(aBundled),
          mBadUnderline(aBadUnderline),
          mForceClassic(aForceClassic),
          mAltLocale(aAltLocale) {}
    bool operator<(const InitData& aRHS) const { return mKey < aRHS.mKey; }
    bool operator==(const InitData& aRHS) const {
      return mKey == aRHS.mKey && mName == aRHS.mName &&
             mVisibility == aRHS.mVisibility && mBundled == aRHS.mBundled &&
             mBadUnderline == aRHS.mBadUnderline;
    }
    const nsCString mKey;
    const nsCString mName;
    uint32_t mIndex;
    FontVisibility mVisibility;
    bool mBundled;
    bool mBadUnderline;
    bool mForceClassic;
    bool mAltLocale;
  };

  /**
   * Font families are considered "simple" if they contain only 4 faces with
   * style attributes corresponding to Regular, Bold, Italic, and BoldItalic
   * respectively, or a subset of these (e.g. only Regular and Bold). In this
   * case, the faces are stored at predefined positions in the mFaces array,
   * and a simplified (faster) style-matching algorithm can be used.
   */
  enum {
    // Indexes into mFaces for families where mIsSimple is true
    kRegularFaceIndex = 0,
    kBoldFaceIndex = 1,
    kItalicFaceIndex = 2,
    kBoldItalicFaceIndex = 3,
    // mask values for selecting face with bold and/or italic attributes
    kBoldMask = 0x01,
    kItalicMask = 0x02
  };

  Family(FontList* aList, const InitData& aData);

  void AddFaces(FontList* aList, const nsTArray<Face::InitData>& aFaces);

  void SetFacePtrs(FontList* aList, nsTArray<Pointer>& aFaces);

  const String& Key() const { return mKey; }

  const String& DisplayName() const { return mName; }

  uint32_t Index() const { return mIndex; }
  bool IsBundled() const { return mIsBundled; }

  uint32_t NumFaces() const {
    MOZ_ASSERT(IsInitialized());
    return mFaceCount;
  }

  Pointer* Faces(FontList* aList) const {
    MOZ_ASSERT(IsInitialized());
    return static_cast<Pointer*>(mFaces.ToPtr(aList));
  }

  FontVisibility Visibility() const { return mVisibility; }
  bool IsHidden() const { return Visibility() == FontVisibility::Hidden; }

  bool IsBadUnderlineFamily() const { return mIsBadUnderlineFamily; }
  bool IsForceClassic() const { return mIsForceClassic; }
  bool IsSimple() const { return mIsSimple; }
  bool IsAltLocaleFamily() const { return mIsAltLocale; }

  // IsInitialized indicates whether the family has been populated with faces,
  // and is therefore ready to use.
  // It is possible that character maps have not yet been loaded.
  bool IsInitialized() const { return !mFaces.IsNull(); }

  // IsFullyInitialized indicates that not only faces but also character maps
  // have been set up, so the family can be searched without the possibility
  // that IPC messaging will be triggered.
  bool IsFullyInitialized() const {
    return IsInitialized() && !mCharacterMap.IsNull();
  }

  void FindAllFacesForStyle(FontList* aList, const gfxFontStyle& aStyle,
                            nsTArray<Face*>& aFaceList,
                            bool aIgnoreSizeTolerance = false) const;

  Face* FindFaceForStyle(FontList* aList, const gfxFontStyle& aStyle,
                         bool aIgnoreSizeTolerance = false) const;

  void SearchAllFontsForChar(FontList* aList, GlobalFontMatch* aMatchData);

  void SetupFamilyCharMap(FontList* aList);

 private:
  std::atomic<uint32_t> mFaceCount;
  String mKey;
  String mName;
  Pointer mCharacterMap;  // If non-null, union of character coverage of all
                          // faces in the family
  Pointer mFaces;         // Pointer to array of |mFaceCount| face pointers
  uint32_t mIndex;        // [win] Top bit set indicates app-bundled font family
  FontVisibility mVisibility;
  bool mIsSimple;  // family allows simplified style matching: mFaces contains
                   // exactly 4 entries [Regular, Bold, Italic, BoldItalic].
  bool mIsBundled : 1;
  bool mIsBadUnderlineFamily : 1;
  bool mIsForceClassic : 1;
  bool mIsAltLocale : 1;
};

/**
 * For platforms where we build an index of local font face names (PS-name
 * and fullname of the font) to support @font-face{src:local(...)}, we map
 * each face name to an index into the family list, and an index into the
 * family's list of faces.
 */
struct LocalFaceRec {
  /**
   * The InitData struct needs to record the family name rather than index,
   * as we may be collecting these records at the same time as building the
   * family list, so we don't yet know the final family index.
   * Likewise, in some cases we don't know the final face index because the
   * faces may be re-sorted to fit into predefined positions in a "simple"
   * family (if we're reading names before the family has been fully set up).
   * In that case, we'll store uint32_t(-1) as mFaceIndex, and record the
   * string descriptor instead.
   * When actually recorded in the FontList's mLocalFaces array, the family
   * will be stored as a simple index into the mFamilies array, and the face
   * as an index into the family's mFaces.
   */
  struct InitData {
    nsCString mFamilyName;
    nsCString mFaceDescriptor;
    uint32_t mFaceIndex = uint32_t(-1);
    InitData(const nsACString& aFamily, const nsACString& aFace)
        : mFamilyName(aFamily), mFaceDescriptor(aFace) {}
    InitData(const nsACString& aFamily, uint32_t aFaceIndex)
        : mFamilyName(aFamily), mFaceIndex(aFaceIndex) {}
    InitData() = default;
  };
  String mKey;
  uint32_t mFamilyIndex;  // Index into the font list's Families array
  uint32_t mFaceIndex;    // Index into the family's Faces array
};

}  // namespace fontlist
}  // namespace mozilla

#include "ipc/IPCMessageUtils.h"

namespace IPC {

template <>
struct ParamTraits<mozilla::fontlist::Pointer> {
  typedef mozilla::fontlist::Pointer paramType;
  static void Write(Message* aMsg, const paramType& aParam) {
    uint32_t v = aParam.mBlockAndOffset;
    WriteParam(aMsg, v);
  }
  static bool Read(const Message* aMsg, PickleIterator* aIter,
                   paramType* aResult) {
    uint32_t v;
    if (ReadParam(aMsg, aIter, &v)) {
      aResult->mBlockAndOffset.store(v);
      return true;
    }
    return false;
  }
};

}  // namespace IPC

#undef ERROR  // This is defined via Windows.h, but conflicts with some bindings
              // code when this gets included in the same compilation unit.

#endif /* SharedFontList_h */