Bug 1839315: part 4) Link from `SheetLoadData::mWasAlternate` to spec. r=emilio DONTBUILD
[gecko.git] / layout / style / FontFaceSetWorkerImpl.cpp
blob7f74beda97cf53a3978f763b25f54a86b055a446
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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "FontFaceSetWorkerImpl.h"
8 #include "FontPreloader.h"
9 #include "mozilla/dom/WorkerPrivate.h"
10 #include "mozilla/dom/WorkerRef.h"
11 #include "mozilla/dom/WorkerRunnable.h"
12 #include "mozilla/LoadInfo.h"
13 #include "nsContentPolicyUtils.h"
14 #include "nsFontFaceLoader.h"
15 #include "nsINetworkPredictor.h"
16 #include "nsIWebNavigation.h"
18 using namespace mozilla;
19 using namespace mozilla::css;
21 namespace mozilla::dom {
23 #define LOG(...) \
24 MOZ_LOG(gfxUserFontSet::GetUserFontsLog(), mozilla::LogLevel::Debug, \
25 (__VA_ARGS__))
26 #define LOG_ENABLED() \
27 MOZ_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), LogLevel::Debug)
29 NS_IMPL_ISUPPORTS_INHERITED0(FontFaceSetWorkerImpl, FontFaceSetImpl);
31 FontFaceSetWorkerImpl::FontFaceSetWorkerImpl(FontFaceSet* aOwner)
32 : FontFaceSetImpl(aOwner) {}
34 FontFaceSetWorkerImpl::~FontFaceSetWorkerImpl() = default;
36 bool FontFaceSetWorkerImpl::Initialize(WorkerPrivate* aWorkerPrivate) {
37 MOZ_ASSERT(aWorkerPrivate);
39 RefPtr<StrongWorkerRef> workerRef =
40 StrongWorkerRef::Create(aWorkerPrivate, "FontFaceSetWorkerImpl",
41 [self = RefPtr{this}] { self->Destroy(); });
42 if (NS_WARN_IF(!workerRef)) {
43 return false;
47 RecursiveMutexAutoLock lock(mMutex);
48 mWorkerRef = new ThreadSafeWorkerRef(workerRef);
51 class InitRunnable final : public WorkerMainThreadRunnable {
52 public:
53 InitRunnable(WorkerPrivate* aWorkerPrivate, FontFaceSetWorkerImpl* aImpl)
54 : WorkerMainThreadRunnable(aWorkerPrivate,
55 "FontFaceSetWorkerImpl :: Initialize"_ns),
56 mImpl(aImpl) {}
58 protected:
59 ~InitRunnable() override = default;
61 bool MainThreadRun() override {
62 mImpl->InitializeOnMainThread();
63 return true;
66 FontFaceSetWorkerImpl* mImpl;
69 IgnoredErrorResult rv;
70 auto runnable = MakeRefPtr<InitRunnable>(aWorkerPrivate, this);
71 runnable->Dispatch(Canceling, rv);
72 return !NS_WARN_IF(rv.Failed());
75 void FontFaceSetWorkerImpl::InitializeOnMainThread() {
76 MOZ_ASSERT(NS_IsMainThread());
77 RecursiveMutexAutoLock lock(mMutex);
79 if (!mWorkerRef) {
80 return;
83 WorkerPrivate* workerPrivate = mWorkerRef->Private();
84 nsIPrincipal* principal = workerPrivate->GetPrincipal();
85 nsIPrincipal* loadingPrincipal = workerPrivate->GetLoadingPrincipal();
86 nsIPrincipal* partitionedPrincipal = workerPrivate->GetPartitionedPrincipal();
87 nsIPrincipal* defaultPrincipal = principal ? principal : loadingPrincipal;
89 nsLoadFlags loadFlags = workerPrivate->GetLoadFlags();
90 uint32_t loadType = 0;
92 // Get the top-level worker.
93 WorkerPrivate* topWorkerPrivate = workerPrivate;
94 WorkerPrivate* parent = workerPrivate->GetParent();
95 while (parent) {
96 topWorkerPrivate = parent;
97 parent = topWorkerPrivate->GetParent();
100 // If the top-level worker is a dedicated worker and has a window, and the
101 // window has a docshell, the caching behavior of this worker should match
102 // that of that docshell. This matches the behaviour from
103 // WorkerScriptLoader::LoadScript.
104 if (topWorkerPrivate->IsDedicatedWorker()) {
105 nsCOMPtr<nsPIDOMWindowInner> window = topWorkerPrivate->GetWindow();
106 if (window) {
107 nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
108 if (docShell) {
109 docShell->GetDefaultLoadFlags(&loadFlags);
110 docShell->GetLoadType(&loadType);
115 // Record the state of the "bypass cache" flags now. In theory the load type
116 // of a docshell could change after the document is loaded, but handling that
117 // doesn't seem too important. This matches the behaviour from
118 // FontFaceSetDocumentImpl::Initialize.
119 mBypassCache =
120 ((loadType >> 16) & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE) ||
121 (loadFlags & nsIRequest::LOAD_BYPASS_CACHE);
123 // Same for the "private browsing" flag.
124 if (defaultPrincipal) {
125 mPrivateBrowsing = defaultPrincipal->GetPrivateBrowsingId() > 0;
128 mStandardFontLoadPrincipal =
129 MakeRefPtr<gfxFontSrcPrincipal>(defaultPrincipal, partitionedPrincipal);
131 mURLExtraData =
132 new URLExtraData(workerPrivate->GetBaseURI(),
133 workerPrivate->GetReferrerInfo(), defaultPrincipal);
136 void FontFaceSetWorkerImpl::Destroy() {
137 RecursiveMutexAutoLock lock(mMutex);
139 mWorkerRef = nullptr;
140 FontFaceSetImpl::Destroy();
143 bool FontFaceSetWorkerImpl::IsOnOwningThread() {
144 RecursiveMutexAutoLock lock(mMutex);
145 if (!mWorkerRef) {
146 return false;
149 return mWorkerRef->Private()->IsOnCurrentThread();
152 #ifdef DEBUG
153 void FontFaceSetWorkerImpl::AssertIsOnOwningThread() {
154 RecursiveMutexAutoLock lock(mMutex);
155 if (mWorkerRef) {
156 MOZ_ASSERT(mWorkerRef->Private()->IsOnCurrentThread());
157 } else {
158 // Asserting during cycle collection if we are tearing down the worker is
159 // difficult. The only other thread that uses FontFace(Set)Impl objects is
160 // the main thread (if created from a worker).
161 MOZ_ASSERT(!NS_IsMainThread());
164 #endif
166 void FontFaceSetWorkerImpl::DispatchToOwningThread(
167 const char* aName, std::function<void()>&& aFunc) {
168 RecursiveMutexAutoLock lock(mMutex);
169 if (!mWorkerRef) {
170 return;
173 WorkerPrivate* workerPrivate = mWorkerRef->Private();
174 if (workerPrivate->IsOnCurrentThread()) {
175 NS_DispatchToCurrentThread(
176 NS_NewCancelableRunnableFunction(aName, std::move(aFunc)));
177 return;
180 class FontFaceSetWorkerRunnable final : public WorkerRunnable {
181 public:
182 FontFaceSetWorkerRunnable(WorkerPrivate* aWorkerPrivate,
183 std::function<void()>&& aFunc)
184 : WorkerRunnable(aWorkerPrivate), mFunc(std::move(aFunc)) {}
186 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
187 mFunc();
188 return true;
191 private:
192 std::function<void()> mFunc;
195 RefPtr<FontFaceSetWorkerRunnable> runnable =
196 new FontFaceSetWorkerRunnable(workerPrivate, std::move(aFunc));
197 runnable->Dispatch();
200 uint64_t FontFaceSetWorkerImpl::GetInnerWindowID() {
201 RecursiveMutexAutoLock lock(mMutex);
202 if (!mWorkerRef) {
203 return 0;
206 return mWorkerRef->Private()->WindowID();
209 void FontFaceSetWorkerImpl::FlushUserFontSet() {
210 RecursiveMutexAutoLock lock(mMutex);
212 // If there was a change to the mNonRuleFaces array, then there could
213 // have been a modification to the user font set.
214 const bool modified = mNonRuleFacesDirty;
215 mNonRuleFacesDirty = false;
217 for (size_t i = 0, i_end = mNonRuleFaces.Length(); i < i_end; ++i) {
218 InsertNonRuleFontFace(mNonRuleFaces[i].mFontFace);
221 // Remove any residual families that have no font entries.
222 for (auto it = mFontFamilies.Iter(); !it.Done(); it.Next()) {
223 if (!it.Data()->FontListLength()) {
224 it.Remove();
228 if (modified) {
229 IncrementGeneration(true);
230 mHasLoadingFontFacesIsDirty = true;
231 CheckLoadingStarted();
232 CheckLoadingFinished();
236 already_AddRefed<gfxUserFontFamily> FontFaceSetWorkerImpl::LookupFamily(
237 const nsACString& aName) const {
238 RecursiveMutexAutoLock lock(mMutex);
239 return gfxUserFontSet::LookupFamily(aName);
242 nsresult FontFaceSetWorkerImpl::StartLoad(gfxUserFontEntry* aUserFontEntry,
243 uint32_t aSrcIndex) {
244 RecursiveMutexAutoLock lock(mMutex);
246 if (NS_WARN_IF(!mWorkerRef)) {
247 return NS_ERROR_FAILURE;
250 nsresult rv;
252 nsCOMPtr<nsIStreamLoader> streamLoader;
254 const gfxFontFaceSrc& src = aUserFontEntry->SourceAt(aSrcIndex);
256 nsCOMPtr<nsILoadGroup> loadGroup(mWorkerRef->Private()->GetLoadGroup());
257 nsCOMPtr<nsIChannel> channel;
258 rv = FontPreloader::BuildChannel(
259 getter_AddRefs(channel), src.mURI->get(), CORS_ANONYMOUS,
260 dom::ReferrerPolicy::_empty /* not used */, aUserFontEntry, &src,
261 mWorkerRef->Private(), loadGroup, nullptr, false);
262 NS_ENSURE_SUCCESS(rv, rv);
264 RefPtr<nsFontFaceLoader> fontLoader =
265 new nsFontFaceLoader(aUserFontEntry, aSrcIndex, this, channel);
267 if (LOG_ENABLED()) {
268 nsCOMPtr<nsIURI> referrer =
269 src.mReferrerInfo ? src.mReferrerInfo->GetOriginalReferrer() : nullptr;
270 LOG("userfonts (%p) download start - font uri: (%s) referrer uri: (%s)\n",
271 fontLoader.get(), src.mURI->GetSpecOrDefault().get(),
272 referrer ? referrer->GetSpecOrDefault().get() : "");
275 rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader, fontLoader);
276 NS_ENSURE_SUCCESS(rv, rv);
278 rv = channel->AsyncOpen(streamLoader);
279 if (NS_FAILED(rv)) {
280 fontLoader->DropChannel(); // explicitly need to break ref cycle
283 mLoaders.PutEntry(fontLoader);
285 net::PredictorLearn(src.mURI->get(), mWorkerRef->Private()->GetBaseURI(),
286 nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE, loadGroup);
288 if (NS_SUCCEEDED(rv)) {
289 fontLoader->StartedLoading(streamLoader);
290 // let the font entry remember the loader, in case we need to cancel it
291 aUserFontEntry->SetLoader(fontLoader);
294 return rv;
297 bool FontFaceSetWorkerImpl::IsFontLoadAllowed(const gfxFontFaceSrc& aSrc) {
298 MOZ_ASSERT(aSrc.mSourceType == gfxFontFaceSrc::eSourceType_URL);
299 MOZ_ASSERT(NS_IsMainThread());
301 RecursiveMutexAutoLock lock(mMutex);
303 if (aSrc.mUseOriginPrincipal) {
304 return true;
307 if (NS_WARN_IF(!mWorkerRef)) {
308 return false;
311 RefPtr<gfxFontSrcPrincipal> gfxPrincipal =
312 aSrc.mURI->InheritsSecurityContext() ? nullptr
313 : aSrc.LoadPrincipal(*this);
315 nsIPrincipal* principal =
316 gfxPrincipal ? gfxPrincipal->NodePrincipal() : nullptr;
318 nsCOMPtr<nsILoadInfo> secCheckLoadInfo = new net::LoadInfo(
319 mWorkerRef->Private()->GetLoadingPrincipal(), // loading principal
320 principal, // triggering principal
321 nullptr, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
322 nsIContentPolicy::TYPE_FONT);
324 int16_t shouldLoad = nsIContentPolicy::ACCEPT;
325 nsresult rv = NS_CheckContentLoadPolicy(aSrc.mURI->get(), secCheckLoadInfo,
326 ""_ns, // mime type
327 &shouldLoad,
328 nsContentUtils::GetContentPolicy());
330 return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
333 nsresult FontFaceSetWorkerImpl::CreateChannelForSyncLoadFontData(
334 nsIChannel** aOutChannel, gfxUserFontEntry* aFontToLoad,
335 const gfxFontFaceSrc* aFontFaceSrc) {
336 RecursiveMutexAutoLock lock(mMutex);
337 if (NS_WARN_IF(!mWorkerRef)) {
338 return NS_ERROR_FAILURE;
341 gfxFontSrcPrincipal* principal = aFontToLoad->GetPrincipal();
343 // We only get here for data: loads, so it doesn't really matter whether we
344 // use SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT or not, to be more
345 // restrictive we use SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT.
346 return NS_NewChannelWithTriggeringPrincipal(
347 aOutChannel, aFontFaceSrc->mURI->get(),
348 mWorkerRef->Private()->GetLoadingPrincipal(),
349 principal ? principal->NodePrincipal() : nullptr,
350 nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT,
351 aFontFaceSrc->mUseOriginPrincipal ? nsIContentPolicy::TYPE_UA_FONT
352 : nsIContentPolicy::TYPE_FONT);
355 nsPresContext* FontFaceSetWorkerImpl::GetPresContext() const { return nullptr; }
357 TimeStamp FontFaceSetWorkerImpl::GetNavigationStartTimeStamp() {
358 RecursiveMutexAutoLock lock(mMutex);
359 if (!mWorkerRef) {
360 return TimeStamp();
363 return mWorkerRef->Private()->CreationTimeStamp();
366 already_AddRefed<URLExtraData> FontFaceSetWorkerImpl::GetURLExtraData() {
367 RecursiveMutexAutoLock lock(mMutex);
368 return RefPtr{mURLExtraData}.forget();
371 #undef LOG_ENABLED
372 #undef LOG
374 } // namespace mozilla::dom