Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/style/FontFaceSet.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef mozilla_dom_FontFaceSet_h
8
#define mozilla_dom_FontFaceSet_h
9
10
#include "mozilla/dom/FontFace.h"
11
#include "mozilla/dom/FontFaceSetBinding.h"
12
#include "mozilla/DOMEventTargetHelper.h"
13
#include "mozilla/FontPropertyTypes.h"
14
#include "gfxUserFontSet.h"
15
#include "nsICSSLoaderObserver.h"
16
17
struct gfxFontFaceSrc;
18
class gfxFontSrcPrincipal;
19
class gfxUserFontEntry;
20
class nsFontFaceLoader;
21
class nsIPrincipal;
22
class nsPIDOMWindowInner;
23
struct RawServoFontFaceRule;
24
25
namespace mozilla {
26
class PostTraversalTask;
27
class SharedFontList;
28
namespace dom {
29
class FontFace;
30
class Promise;
31
} // namespace dom
32
} // namespace mozilla
33
34
namespace mozilla {
35
namespace dom {
36
37
class FontFaceSet final : public DOMEventTargetHelper
38
                        , public nsIDOMEventListener
39
                        , public nsICSSLoaderObserver
40
{
41
  friend class mozilla::PostTraversalTask;
42
  friend class UserFontSet;
43
44
public:
45
  /**
46
   * A gfxUserFontSet that integrates with the layout and style systems to
47
   * manage @font-face rules and handle network requests for font loading.
48
   *
49
   * We would combine this class and FontFaceSet into the one class if it were
50
   * possible; it's not because FontFaceSet is cycle collected and
51
   * gfxUserFontSet isn't (and can't be, as gfx classes don't use the cycle
52
   * collector).  So UserFontSet exists just to override the needed virtual
53
   * methods from gfxUserFontSet and to forward them on FontFaceSet.
54
   */
55
  class UserFontSet final : public gfxUserFontSet
56
  {
57
    friend class FontFaceSet;
58
59
  public:
60
    explicit UserFontSet(FontFaceSet* aFontFaceSet)
61
      : mFontFaceSet(aFontFaceSet)
62
0
    {
63
0
    }
64
65
    FontFaceSet* GetFontFaceSet() { return mFontFaceSet; }
66
67
    gfxFontSrcPrincipal* GetStandardFontLoadPrincipal() const final
68
0
    {
69
0
      return mFontFaceSet ? mFontFaceSet->mStandardFontLoadPrincipal.get() : nullptr;
70
0
    }
71
72
    bool IsFontLoadAllowed(const gfxFontFaceSrc&) final;
73
74
    void DispatchFontLoadViolations(
75
      nsTArray<nsCOMPtr<nsIRunnable>>& aViolations) override;
76
77
    virtual nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
78
                               const gfxFontFaceSrc* aFontFaceSrc) override;
79
80
    void RecordFontLoadDone(uint32_t aFontSize,
81
                            mozilla::TimeStamp aDoneTime) override;
82
83
    bool BypassCache() final
84
0
    {
85
0
      return mFontFaceSet && mFontFaceSet->mBypassCache;
86
0
    }
87
88
  protected:
89
    virtual bool GetPrivateBrowsing() override;
90
    virtual nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
91
                                      const gfxFontFaceSrc* aFontFaceSrc,
92
                                      uint8_t*& aBuffer,
93
                                      uint32_t& aBufferLength) override;
94
    virtual nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
95
                                const char* aMessage,
96
                                uint32_t aFlags = nsIScriptError::errorFlag,
97
                                nsresult aStatus = NS_OK) override;
98
    virtual void DoRebuildUserFontSet() override;
99
    already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
100
                                   const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
101
                                   WeightRange aWeight,
102
                                   StretchRange aStretch,
103
                                   SlantStyleRange aStyle,
104
                                   const nsTArray<gfxFontFeature>& aFeatureSettings,
105
                                   const nsTArray<gfxFontVariation>& aVariationSettings,
106
                                   uint32_t aLanguageOverride,
107
                                   gfxCharacterMap* aUnicodeRanges,
108
                                   uint8_t aFontDisplay,
109
                                   RangeFlags aRangeFlags) override;
110
111
  private:
112
    RefPtr<FontFaceSet> mFontFaceSet;
113
  };
114
115
  NS_DECL_ISUPPORTS_INHERITED
116
  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FontFaceSet, DOMEventTargetHelper)
117
  NS_DECL_NSIDOMEVENTLISTENER
118
119
  FontFaceSet(nsPIDOMWindowInner* aWindow, nsIDocument* aDocument);
120
121
  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
122
123
  UserFontSet* GetUserFontSet() { return mUserFontSet; }
124
125
  // Called by nsFontFaceLoader when the loader has completed normally.
126
  // It's removed from the mLoaders set.
127
  void RemoveLoader(nsFontFaceLoader* aLoader);
128
129
  bool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules);
130
131
  nsPresContext* GetPresContext();
132
133
  // search for @font-face rule that matches a platform font entry
134
  RawServoFontFaceRule* FindRuleForEntry(gfxFontEntry* aFontEntry);
135
136
  void IncrementGeneration(bool aIsRebuild = false);
137
138
  /**
139
   * Finds an existing entry in the user font cache or creates a new user
140
   * font entry for the given FontFace object.
141
   */
142
  static already_AddRefed<gfxUserFontEntry>
143
    FindOrCreateUserFontEntryFromFontFace(FontFace* aFontFace);
144
145
  /**
146
   * Notification method called by a FontFace to indicate that its loading
147
   * status has changed.
148
   */
149
  void OnFontFaceStatusChanged(FontFace* aFontFace);
150
151
  /**
152
   * Notification method called by the nsPresContext to indicate that the
153
   * refresh driver ticked and flushed style and layout.
154
   * were just flushed.
155
   */
156
  void DidRefresh();
157
158
  /**
159
   * Returns whether the "layout.css.font-loading-api.enabled" pref is true.
160
   */
161
  static bool PrefEnabled();
162
163
  // nsICSSLoaderObserver
164
  NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet,
165
                              bool aWasAlternate,
166
                              nsresult aStatus) override;
167
168
  FontFace* GetFontFaceAt(uint32_t aIndex);
169
170
  void FlushUserFontSet();
171
172
  static nsPresContext* GetPresContextFor(gfxUserFontSet* aUserFontSet)
173
0
  {
174
0
    FontFaceSet* set = static_cast<UserFontSet*>(aUserFontSet)->mFontFaceSet;
175
0
    return set ? set->GetPresContext() : nullptr;
176
0
  }
177
178
  void RefreshStandardFontLoadPrincipal();
179
180
  void CopyNonRuleFacesTo(FontFaceSet* aFontFaceSet) const;
181
182
0
  nsIDocument* Document() const { return mDocument; }
183
184
  // -- Web IDL --------------------------------------------------------------
185
186
  IMPL_EVENT_HANDLER(loading)
187
  IMPL_EVENT_HANDLER(loadingdone)
188
  IMPL_EVENT_HANDLER(loadingerror)
189
  already_AddRefed<mozilla::dom::Promise> Load(JSContext* aCx,
190
                                               const nsAString& aFont,
191
                                               const nsAString& aText,
192
                                               mozilla::ErrorResult& aRv);
193
  bool Check(const nsAString& aFont,
194
             const nsAString& aText,
195
             mozilla::ErrorResult& aRv);
196
  mozilla::dom::Promise* GetReady(mozilla::ErrorResult& aRv);
197
  mozilla::dom::FontFaceSetLoadStatus Status();
198
199
  void Add(FontFace& aFontFace, mozilla::ErrorResult& aRv);
200
  void Clear();
201
  bool Delete(FontFace& aFontFace);
202
  bool Has(FontFace& aFontFace);
203
  uint32_t Size();
204
  already_AddRefed<mozilla::dom::FontFaceSetIterator> Entries();
205
  already_AddRefed<mozilla::dom::FontFaceSetIterator> Values();
206
  void ForEach(JSContext* aCx, FontFaceSetForEachCallback& aCallback,
207
               JS::Handle<JS::Value> aThisArg,
208
               mozilla::ErrorResult& aRv);
209
210
  // For ServoStyleSet to know ahead of time whether a font is loadable.
211
  void CacheFontLoadability();
212
213
private:
214
  ~FontFaceSet();
215
216
  /**
217
   * Returns whether the given FontFace is currently "in" the FontFaceSet.
218
   */
219
  bool HasAvailableFontFace(FontFace* aFontFace);
220
221
  /**
222
   * Removes any listeners and observers.
223
   */
224
  void Disconnect();
225
226
  void RemoveDOMContentLoadedListener();
227
228
  /**
229
   * Returns whether there might be any pending font loads, which should cause
230
   * the mReady Promise not to be resolved yet.
231
   */
232
  bool MightHavePendingFontLoads();
233
234
  /**
235
   * Checks to see whether it is time to replace mReady and dispatch a
236
   * "loading" event.
237
   */
238
  void CheckLoadingStarted();
239
240
  /**
241
   * Checks to see whether it is time to resolve mReady and dispatch any
242
   * "loadingdone" and "loadingerror" events.
243
   */
244
  void CheckLoadingFinished();
245
246
  /**
247
   * Callback for invoking CheckLoadingFinished after going through the
248
   * event loop.  See OnFontFaceStatusChanged.
249
   */
250
  void CheckLoadingFinishedAfterDelay();
251
252
  /**
253
   * Dispatches a FontFaceSetLoadEvent to this object.
254
   */
255
  void DispatchLoadingFinishedEvent(
256
                                const nsAString& aType,
257
                                nsTArray<OwningNonNull<FontFace>>&& aFontFaces);
258
259
  // Note: if you add new cycle collected objects to FontFaceRecord,
260
  // make sure to update FontFaceSet's cycle collection macros
261
  // accordingly.
262
  struct FontFaceRecord {
263
    RefPtr<FontFace> mFontFace;
264
    SheetType mSheetType;  // only relevant for mRuleFaces entries
265
266
    // When true, indicates that when finished loading, the FontFace should be
267
    // included in the subsequent loadingdone/loadingerror event fired at the
268
    // FontFaceSet.
269
    bool mLoadEventShouldFire;
270
  };
271
272
  static already_AddRefed<gfxUserFontEntry> FindOrCreateUserFontEntryFromFontFace(
273
                                                   const nsACString& aFamilyName,
274
                                                   FontFace* aFontFace,
275
                                                   SheetType aSheetType);
276
277
  // search for @font-face rule that matches a userfont font entry
278
  RawServoFontFaceRule* FindRuleForUserFontEntry(gfxUserFontEntry* aUserFontEntry);
279
280
  nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
281
                     const gfxFontFaceSrc* aFontFaceSrc);
282
  gfxFontSrcPrincipal* GetStandardFontLoadPrincipal();
283
  nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
284
                         gfxFontSrcPrincipal** aPrincipal,
285
                         bool* aBypassCache);
286
  bool IsFontLoadAllowed(const gfxFontFaceSrc& aSrc);
287
288
  void DispatchFontLoadViolations(nsTArray<nsCOMPtr<nsIRunnable>>& aViolations);
289
  nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
290
                            const gfxFontFaceSrc* aFontFaceSrc,
291
                            uint8_t*& aBuffer,
292
                            uint32_t& aBufferLength);
293
  nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
294
                      const char* aMessage,
295
                      uint32_t aFlags,
296
                      nsresult aStatus);
297
  void MarkUserFontSetDirty();
298
299
  void InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType,
300
                          nsTArray<FontFaceRecord>& aOldRecords,
301
                          bool& aFontSetModified);
302
  void InsertNonRuleFontFace(FontFace* aFontFace, bool& aFontSetModified);
303
304
#ifdef DEBUG
305
  bool HasRuleFontFace(FontFace* aFontFace);
306
#endif
307
308
  /**
309
   * Returns whether we have any loading FontFace objects in the FontFaceSet.
310
   */
311
  bool HasLoadingFontFaces();
312
313
  // Whether mReady is pending, or would be when created.
314
  bool ReadyPromiseIsPending() const;
315
316
  // Helper function for HasLoadingFontFaces.
317
  void UpdateHasLoadingFontFaces();
318
319
  void ParseFontShorthandForMatching(
320
              const nsAString& aFont,
321
              RefPtr<SharedFontList>& aFamilyList,
322
              FontWeight& aWeight,
323
              FontStretch& aStretch,
324
              FontSlantStyle& aStyle,
325
              ErrorResult& aRv);
326
  void FindMatchingFontFaces(const nsAString& aFont,
327
                             const nsAString& aText,
328
                             nsTArray<FontFace*>& aFontFaces,
329
                             mozilla::ErrorResult& aRv);
330
331
  void DispatchLoadingEventAndReplaceReadyPromise();
332
  void DispatchCheckLoadingFinishedAfterDelay();
333
334
  TimeStamp GetNavigationStartTimeStamp();
335
336
  RefPtr<UserFontSet> mUserFontSet;
337
338
  // The document this is a FontFaceSet for.
339
  nsCOMPtr<nsIDocument> mDocument;
340
341
  // The document's node principal, which is the principal font loads for
342
  // this FontFaceSet will generally use.  (This principal is not used for
343
  // @font-face rules in UA and user sheets, where the principal of the
344
  // sheet is used instead.)
345
  //
346
  // This field is used from GetStandardFontLoadPrincipal.  When on a
347
  // style worker thread, we use mStandardFontLoadPrincipal assuming
348
  // it is up to date.
349
  //
350
  // Because mDocument's principal can change over time,
351
  // its value must be updated by a call to ResetStandardFontLoadPrincipal.
352
  RefPtr<gfxFontSrcPrincipal> mStandardFontLoadPrincipal;
353
354
  // A Promise that is fulfilled once all of the FontFace objects
355
  // in mRuleFaces and mNonRuleFaces that started or were loading at the
356
  // time the Promise was created have finished loading.  It is rejected if
357
  // any of those fonts failed to load.  mReady is replaced with
358
  // a new Promise object whenever mReady is settled and another
359
  // FontFace in mRuleFaces or mNonRuleFaces starts to load.
360
  // Note that mReady is created lazily when GetReady() is called.
361
  RefPtr<mozilla::dom::Promise> mReady;
362
  // Whether the ready promise must be resolved when it's created.
363
  bool mResolveLazilyCreatedReadyPromise;
364
365
  // Set of all loaders pointing to us. These are not strong pointers,
366
  // but that's OK because nsFontFaceLoader always calls RemoveLoader on
367
  // us before it dies (unless we die first).
368
  nsTHashtable< nsPtrHashKey<nsFontFaceLoader> > mLoaders;
369
370
  // The @font-face rule backed FontFace objects in the FontFaceSet.
371
  nsTArray<FontFaceRecord> mRuleFaces;
372
373
  // The non rule backed FontFace objects that have been added to this
374
  // FontFaceSet.
375
  nsTArray<FontFaceRecord> mNonRuleFaces;
376
377
  // The overall status of the loading or loaded fonts in the FontFaceSet.
378
  mozilla::dom::FontFaceSetLoadStatus mStatus;
379
380
  // A map from gfxFontFaceSrc pointer identity to whether the load is allowed
381
  // by CSP or other checks. We store this here because querying CSP off the
382
  // main thread is not a great idea.
383
  //
384
  // We could use just the pointer and use this as a hash set, but then we'd
385
  // have no way to verify that we've checked all the loads we should.
386
  nsDataHashtable<nsPtrHashKey<const gfxFontFaceSrc>, bool> mAllowedFontLoads;
387
388
  // Whether mNonRuleFaces has changed since last time UpdateRules ran.
389
  bool mNonRuleFacesDirty;
390
391
  // Whether any FontFace objects in mRuleFaces or mNonRuleFaces are
392
  // loading.  Only valid when mHasLoadingFontFacesIsDirty is false.  Don't use
393
  // this variable directly; call the HasLoadingFontFaces method instead.
394
  bool mHasLoadingFontFaces;
395
396
  // This variable is only valid when mLoadingDirty is false.
397
  bool mHasLoadingFontFacesIsDirty;
398
399
  // Whether CheckLoadingFinished calls should be ignored.  See comment in
400
  // OnFontFaceStatusChanged.
401
  bool mDelayedLoadCheck;
402
403
  // Whether the docshell for our document indicated that loads should
404
  // bypass the cache.
405
  bool mBypassCache;
406
407
  // Whether the docshell for our document indicates that we are in private
408
  // browsing mode.
409
  bool mPrivateBrowsing;
410
};
411
412
} // namespace dom
413
} // namespace mozilla
414
415
#endif // !defined(mozilla_dom_FontFaceSet_h)