summaryrefslogtreecommitdiffstats
path: root/layout/style/FontFaceSetImpl.h
blob: 00953ec92ff6cc48e3a77e9b8663443b3e4ef68a (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
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 mozilla_dom_FontFaceSetImpl_h
#define mozilla_dom_FontFaceSetImpl_h

#include "mozilla/dom/FontFace.h"
#include "mozilla/dom/FontFaceSetBinding.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/FontPropertyTypes.h"
#include "mozilla/RecursiveMutex.h"
#include "gfxUserFontSet.h"
#include "nsICSSLoaderObserver.h"
#include "nsIDOMEventListener.h"

#include <functional>

struct gfxFontFaceSrc;
class gfxFontSrcPrincipal;
class gfxUserFontEntry;
class nsFontFaceLoader;
class nsIChannel;
class nsIPrincipal;
class nsPIDOMWindowInner;

namespace mozilla {
struct StyleLockedFontFaceRule;
class PostTraversalTask;
class Runnable;
class SharedFontList;
namespace dom {
class FontFace;
}  // namespace dom
}  // namespace mozilla

namespace mozilla::dom {

class FontFaceSetImpl : public nsISupports, public gfxUserFontSet {
  NS_DECL_THREADSAFE_ISUPPORTS

 public:
  // gfxUserFontSet

  already_AddRefed<gfxFontSrcPrincipal> GetStandardFontLoadPrincipal()
      const final;

  void RecordFontLoadDone(uint32_t aFontSize, TimeStamp aDoneTime) override;

  bool BypassCache() final { return mBypassCache; }

  void ForgetLocalFaces() final;

 protected:
  virtual nsresult CreateChannelForSyncLoadFontData(
      nsIChannel** aOutChannel, gfxUserFontEntry* aFontToLoad,
      const gfxFontFaceSrc* aFontFaceSrc) = 0;

  // gfxUserFontSet

  bool GetPrivateBrowsing() override { return mPrivateBrowsing; }
  nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
                            const gfxFontFaceSrc* aFontFaceSrc,
                            uint8_t*& aBuffer,
                            uint32_t& aBufferLength) override;
  nsresult LogMessage(gfxUserFontEntry* aUserFontEntry, uint32_t aSrcIndex,
                      const char* aMessage,
                      uint32_t aFlags = nsIScriptError::errorFlag,
                      nsresult aStatus = NS_OK) override;
  void DoRebuildUserFontSet() override;
  already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
      nsTArray<gfxFontFaceSrc>&& aFontFaceSrcList,
      gfxUserFontAttributes&& aAttr) override;

  already_AddRefed<gfxUserFontFamily> GetFamily(
      const nsACString& aFamilyName) final;

  explicit FontFaceSetImpl(FontFaceSet* aOwner);

  void DestroyLoaders();

 public:
  virtual void Destroy();
  virtual bool IsOnOwningThread() = 0;
#ifdef DEBUG
  virtual void AssertIsOnOwningThread() = 0;
#else
  void AssertIsOnOwningThread() {}
#endif
  virtual void DispatchToOwningThread(const char* aName,
                                      std::function<void()>&& aFunc) = 0;

  // Called by nsFontFaceLoader when the loader has completed normally.
  // It's removed from the mLoaders set.
  virtual void RemoveLoader(nsFontFaceLoader* aLoader);

  virtual bool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules) {
    MOZ_ASSERT_UNREACHABLE("Not implemented!");
    return false;
  }

  // search for @font-face rule that matches a platform font entry
  virtual StyleLockedFontFaceRule* FindRuleForEntry(gfxFontEntry* aFontEntry) {
    MOZ_ASSERT_UNREACHABLE("Not implemented!");
    return nullptr;
  }

  /**
   * Finds an existing entry in the user font cache or creates a new user
   * font entry for the given FontFace object.
   */
  static already_AddRefed<gfxUserFontEntry>
  FindOrCreateUserFontEntryFromFontFace(FontFaceImpl* aFontFace,
                                        gfxUserFontAttributes&& aAttr,
                                        StyleOrigin);

  /**
   * Notification method called by a FontFace to indicate that its loading
   * status has changed.
   */
  virtual void OnFontFaceStatusChanged(FontFaceImpl* aFontFace);

  /**
   * Notification method called by the nsPresContext to indicate that the
   * refresh driver ticked and flushed style and layout.
   * were just flushed.
   */
  virtual void DidRefresh() { MOZ_ASSERT_UNREACHABLE("Not implemented!"); }

  virtual void FlushUserFontSet() = 0;

  static nsPresContext* GetPresContextFor(gfxUserFontSet* aUserFontSet) {
    const auto* set = static_cast<FontFaceSetImpl*>(aUserFontSet);
    return set ? set->GetPresContext() : nullptr;
  }

  virtual void RefreshStandardFontLoadPrincipal();

  virtual dom::Document* GetDocument() const { return nullptr; }

  virtual already_AddRefed<URLExtraData> GetURLExtraData() = 0;

  // -- Web IDL --------------------------------------------------------------

  virtual void EnsureReady() {}
  dom::FontFaceSetLoadStatus Status();

  virtual bool Add(FontFaceImpl* aFontFace, ErrorResult& aRv);
  virtual void Clear();
  virtual bool Delete(FontFaceImpl* aFontFace);

  // For ServoStyleSet to know ahead of time whether a font is loadable.
  virtual void CacheFontLoadability() {
    MOZ_ASSERT_UNREACHABLE("Not implemented!");
  }

  virtual void MarkUserFontSetDirty() {}

  /**
   * Checks to see whether it is time to resolve mReady and dispatch any
   * "loadingdone" and "loadingerror" events.
   */
  virtual void CheckLoadingFinished();

  virtual void FindMatchingFontFaces(const nsACString& aFont,
                                     const nsAString& aText,
                                     nsTArray<FontFace*>& aFontFaces,
                                     ErrorResult& aRv);

  virtual void DispatchCheckLoadingFinishedAfterDelay();

 protected:
  ~FontFaceSetImpl() override;

  virtual uint64_t GetInnerWindowID() = 0;

  /**
   * Returns whether the given FontFace is currently "in" the FontFaceSet.
   */
  bool HasAvailableFontFace(FontFaceImpl* aFontFace);

  /**
   * Returns whether there might be any pending font loads, which should cause
   * the mReady Promise not to be resolved yet.
   */
  virtual bool MightHavePendingFontLoads();

  /**
   * Checks to see whether it is time to replace mReady and dispatch a
   * "loading" event.
   */
  void CheckLoadingStarted();

  /**
   * Callback for invoking CheckLoadingFinished after going through the
   * event loop.  See OnFontFaceStatusChanged.
   */
  void CheckLoadingFinishedAfterDelay();

  void OnLoadingStarted();
  void OnLoadingFinished();

  // Note: if you add new cycle collected objects to FontFaceRecord,
  // make sure to update FontFaceSet's cycle collection macros
  // accordingly.
  struct FontFaceRecord {
    RefPtr<FontFaceImpl> mFontFace;
    Maybe<StyleOrigin> mOrigin;  // only relevant for mRuleFaces entries
  };

  // search for @font-face rule that matches a userfont font entry
  virtual StyleLockedFontFaceRule* FindRuleForUserFontEntry(
      gfxUserFontEntry* aUserFontEntry) {
    return nullptr;
  }

  virtual void FindMatchingFontFaces(
      const nsTHashSet<FontFace*>& aMatchingFaces,
      nsTArray<FontFace*>& aFontFaces);

  class UpdateUserFontEntryRunnable;
  void UpdateUserFontEntry(gfxUserFontEntry* aEntry,
                           gfxUserFontAttributes&& aAttr);

  nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
                         gfxFontSrcPrincipal** aPrincipal, bool* aBypassCache);

  void InsertNonRuleFontFace(FontFaceImpl* aFontFace, bool& aFontSetModified);

  /**
   * Returns whether we have any loading FontFace objects in the FontFaceSet.
   */
  bool HasLoadingFontFaces();

  // Whether mReady is pending, or would be when created.
  bool ReadyPromiseIsPending() const;

  // Helper function for HasLoadingFontFaces.
  virtual void UpdateHasLoadingFontFaces();

  void ParseFontShorthandForMatching(const nsACString& aFont,
                                     StyleFontFamilyList& aFamilyList,
                                     FontWeight& aWeight, FontStretch& aStretch,
                                     FontSlantStyle& aStyle, ErrorResult& aRv);

  virtual TimeStamp GetNavigationStartTimeStamp() = 0;

  mutable RecursiveMutex mMutex;

  FontFaceSet* MOZ_NON_OWNING_REF mOwner MOZ_GUARDED_BY(mMutex);

  // The document's node principal, which is the principal font loads for
  // this FontFaceSet will generally use.  (This principal is not used for
  // @font-face rules in UA and user sheets, where the principal of the
  // sheet is used instead.)
  //
  // This field is used from GetStandardFontLoadPrincipal.  When on a
  // style worker thread, we use mStandardFontLoadPrincipal assuming
  // it is up to date.
  //
  // Because mDocument's principal can change over time,
  // its value must be updated by a call to ResetStandardFontLoadPrincipal.
  mutable RefPtr<gfxFontSrcPrincipal> mStandardFontLoadPrincipal
      MOZ_GUARDED_BY(mMutex);

  // Set of all loaders pointing to us. These are not strong pointers,
  // but that's OK because nsFontFaceLoader always calls RemoveLoader on
  // us before it dies (unless we die first).
  nsTHashtable<nsPtrHashKey<nsFontFaceLoader>> mLoaders MOZ_GUARDED_BY(mMutex);

  // The non rule backed FontFace objects that have been added to this
  // FontFaceSet.
  nsTArray<FontFaceRecord> mNonRuleFaces MOZ_GUARDED_BY(mMutex);

  // The overall status of the loading or loaded fonts in the FontFaceSet.
  dom::FontFaceSetLoadStatus mStatus MOZ_GUARDED_BY(mMutex);

  // A map from gfxFontFaceSrc pointer identity to whether the load is allowed
  // by CSP or other checks. We store this here because querying CSP off the
  // main thread is not a great idea.
  //
  // We could use just the pointer and use this as a hash set, but then we'd
  // have no way to verify that we've checked all the loads we should.
  nsTHashMap<nsPtrHashKey<const gfxFontFaceSrc>, bool> mAllowedFontLoads
      MOZ_GUARDED_BY(mMutex);

  // Whether mNonRuleFaces has changed since last time UpdateRules ran.
  bool mNonRuleFacesDirty MOZ_GUARDED_BY(mMutex);

  // Whether any FontFace objects in mRuleFaces or mNonRuleFaces are
  // loading.  Only valid when mHasLoadingFontFacesIsDirty is false.  Don't use
  // this variable directly; call the HasLoadingFontFaces method instead.
  bool mHasLoadingFontFaces MOZ_GUARDED_BY(mMutex);

  // This variable is only valid when mLoadingDirty is false.
  bool mHasLoadingFontFacesIsDirty MOZ_GUARDED_BY(mMutex);

  // Whether CheckLoadingFinished calls should be ignored.  See comment in
  // OnFontFaceStatusChanged.
  bool mDelayedLoadCheck MOZ_GUARDED_BY(mMutex);

  // Whether the docshell for our document indicated that loads should
  // bypass the cache.
  bool mBypassCache;

  // Whether the docshell for our document indicates that we are in private
  // browsing mode.
  bool mPrivateBrowsing;
};

}  // namespace mozilla::dom

#endif  // !defined(mozilla_dom_FontFaceSetImpl_h)