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
{
24 MOZ_LOG(gfxUserFontSet::GetUserFontsLog(), mozilla::LogLevel::Debug, \
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
)) {
47 RecursiveMutexAutoLock
lock(mMutex
);
48 mWorkerRef
= new ThreadSafeWorkerRef(workerRef
);
51 class InitRunnable final
: public WorkerMainThreadRunnable
{
53 InitRunnable(WorkerPrivate
* aWorkerPrivate
, FontFaceSetWorkerImpl
* aImpl
)
54 : WorkerMainThreadRunnable(aWorkerPrivate
,
55 "FontFaceSetWorkerImpl :: Initialize"_ns
),
59 ~InitRunnable() override
= default;
61 bool MainThreadRun() override
{
62 mImpl
->InitializeOnMainThread();
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
);
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();
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();
107 nsCOMPtr
<nsIDocShell
> docShell
= window
->GetDocShell();
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.
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
);
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
);
149 return mWorkerRef
->Private()->IsOnCurrentThread();
153 void FontFaceSetWorkerImpl::AssertIsOnOwningThread() {
154 RecursiveMutexAutoLock
lock(mMutex
);
156 MOZ_ASSERT(mWorkerRef
->Private()->IsOnCurrentThread());
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());
166 void FontFaceSetWorkerImpl::DispatchToOwningThread(
167 const char* aName
, std::function
<void()>&& aFunc
) {
168 RecursiveMutexAutoLock
lock(mMutex
);
173 WorkerPrivate
* workerPrivate
= mWorkerRef
->Private();
174 if (workerPrivate
->IsOnCurrentThread()) {
175 NS_DispatchToCurrentThread(
176 NS_NewCancelableRunnableFunction(aName
, std::move(aFunc
)));
180 class FontFaceSetWorkerRunnable final
: public WorkerRunnable
{
182 FontFaceSetWorkerRunnable(WorkerPrivate
* aWorkerPrivate
,
183 std::function
<void()>&& aFunc
)
184 : WorkerRunnable(aWorkerPrivate
), mFunc(std::move(aFunc
)) {}
186 bool WorkerRun(JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
) override
{
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
);
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()) {
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
;
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
);
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
);
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
);
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
) {
307 if (NS_WARN_IF(!mWorkerRef
)) {
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
,
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
);
363 return mWorkerRef
->Private()->CreationTimeStamp();
366 already_AddRefed
<URLExtraData
> FontFaceSetWorkerImpl::GetURLExtraData() {
367 RecursiveMutexAutoLock
lock(mMutex
);
368 return RefPtr
{mURLExtraData
}.forget();
374 } // namespace mozilla::dom