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/. */
7 #ifndef mozilla_css_SheetLoadData_h
8 #define mozilla_css_SheetLoadData_h
10 #include "mozilla/css/Loader.h"
11 #include "mozilla/css/SheetParsingMode.h"
12 #include "mozilla/Encoding.h"
13 #include "mozilla/PreloaderBase.h"
14 #include "mozilla/SharedSubResourceCache.h"
15 #include "mozilla/NotNull.h"
16 #include "nsProxyRelease.h"
20 enum class FetchPriority
: uint8_t;
22 class AsyncEventDispatcher
;
24 } // namespace mozilla
25 class nsICSSLoaderObserver
;
29 class nsIReferrerInfo
;
31 namespace mozilla::css
{
33 /*********************************************
34 * Data needed to properly load a stylesheet *
35 *********************************************/
37 static_assert(eAuthorSheetFeatures
== 0 && eUserSheetFeatures
== 1 &&
38 eAgentSheetFeatures
== 2,
39 "sheet parsing mode constants won't fit "
40 "in SheetLoadData::mParsingMode");
42 enum class SyncLoad
: bool { No
, Yes
};
44 class SheetLoadData final
45 : public PreloaderBase
,
46 public SharedSubResourceCacheLoadingValueBase
<SheetLoadData
> {
47 using MediaMatched
= dom::LinkStyle::MediaMatched
;
48 using IsAlternate
= dom::LinkStyle::IsAlternate
;
49 using UseSystemPrincipal
= css::Loader::UseSystemPrincipal
;
52 virtual ~SheetLoadData();
55 static void PrioritizeAsPreload(nsIChannel
* aChannel
);
57 // If this is a deferred load, start it now.
58 void StartPendingLoad();
60 // Data for loading a sheet linked from a document
61 SheetLoadData(css::Loader
*, const nsAString
& aTitle
, nsIURI
*, StyleSheet
*,
62 SyncLoad
, nsINode
* aOwningNode
, IsAlternate
, MediaMatched
,
63 StylePreloadKind
, nsICSSLoaderObserver
* aObserver
,
64 nsIPrincipal
* aTriggeringPrincipal
, nsIReferrerInfo
*,
65 const nsAString
& aNonce
, dom::FetchPriority aFetchPriority
);
67 // Data for loading a sheet linked from an @import rule
68 SheetLoadData(css::Loader
*, nsIURI
*, StyleSheet
*, SheetLoadData
* aParentData
,
69 nsICSSLoaderObserver
* aObserver
,
70 nsIPrincipal
* aTriggeringPrincipal
, nsIReferrerInfo
*);
72 // Data for loading a non-document sheet
73 SheetLoadData(css::Loader
*, nsIURI
*, StyleSheet
*, SyncLoad
,
74 UseSystemPrincipal
, StylePreloadKind
,
75 const Encoding
* aPreloadEncoding
,
76 nsICSSLoaderObserver
* aObserver
,
77 nsIPrincipal
* aTriggeringPrincipal
, nsIReferrerInfo
*,
78 const nsAString
& aNonce
, dom::FetchPriority aFetchPriority
);
80 nsIReferrerInfo
* ReferrerInfo() const { return mReferrerInfo
; }
82 const nsString
& Nonce() const { return mNonce
; }
84 already_AddRefed
<AsyncEventDispatcher
> PrepareLoadEventIfNeeded();
86 NotNull
<const Encoding
*> DetermineNonBOMEncoding(const nsACString
& aSegment
,
89 // The caller may have the bytes for the stylesheet split across two strings,
90 // so aBytes1 and aBytes2 refer to those pieces.
91 nsresult
VerifySheetReadyToParse(nsresult aStatus
, const nsACString
& aBytes1
,
92 const nsACString
& aBytes2
,
93 nsIChannel
* aChannel
);
97 css::Loader
& Loader() { return *mLoader
; }
99 void DidCancelLoad() { mIsCancelled
= true; }
101 // Hold a ref to the CSSLoader so we can call back to it to let it
102 // know the load finished
103 const RefPtr
<css::Loader
> mLoader
;
105 // Title needed to pull datas out of the pending datas table when
106 // the preferred title is changed
107 const nsString mTitle
;
109 // The encoding we decided to use for the sheet
110 const Encoding
* mEncoding
;
112 // URI we're loading. Null for inline or constructable sheets.
113 nsCOMPtr
<nsIURI
> mURI
;
115 // The sheet we're loading data for
116 const RefPtr
<StyleSheet
> mSheet
;
118 // Load data for the sheet that @import-ed us if we were @import-ed
120 const RefPtr
<SheetLoadData
> mParentData
;
122 // The expiration time of the channel that has loaded this data, if
124 uint32_t mExpirationTime
= 0;
126 // Number of sheets we @import-ed that are still loading
127 uint32_t mPendingChildren
;
129 // mSyncLoad is true when the load needs to be synchronous.
130 // For LoadSheetSync, <link> to chrome stylesheets in UA Widgets,
131 // and children of sync loads.
132 const bool mSyncLoad
: 1;
134 // mIsNonDocumentSheet is true if the load was triggered by LoadSheetSync or
135 // LoadSheet or an @import from such a sheet. Non-document sheet loads can
136 // proceed even if we have no document.
137 const bool mIsNonDocumentSheet
: 1;
139 // Whether this stylesheet is for a child sheet load. This is necessary
140 // because the sheet could be detached mid-load by CSSOM.
141 const bool mIsChildSheet
: 1;
143 // mIsBeingParsed is true if this stylesheet is currently being parsed.
144 bool mIsBeingParsed
: 1;
146 // mIsLoading is set to true when a sheet load is initiated. This field is
147 // also used by the SharedSubResourceCache to avoid having multiple loads for
148 // the same resource.
151 // mIsCancelled is set to true when a sheet load is stopped by
152 // Stop() or StopLoadingSheet() (which was removed in Bug 556446).
153 // SheetLoadData::OnStreamComplete() checks this to avoid parsing
154 // sheets that have been cancelled and such.
155 bool mIsCancelled
: 1;
157 // mMustNotify is true if the load data is being loaded async and the original
158 // function call that started the load has returned.
160 // This applies only to observer notifications; load/error events are fired
161 // for any SheetLoadData that has a non-null owner node (though mMustNotify is
162 // used to avoid an event loop round-trip in that case).
163 bool mMustNotify
: 1;
165 // Whether we had an owner node at the point of creation. This allows
166 // differentiating between "Link" header stylesheets and LinkStyle-owned
168 const bool mHadOwnerNode
: 1;
170 // mWasAlternate is true if the sheet was an alternate
171 // (https://html.spec.whatwg.org/#rel-alternate) when the load data was
173 const bool mWasAlternate
: 1;
175 // mMediaMatched is true if the sheet matched its medialist when the load data
177 const bool mMediaMatched
: 1;
179 // mUseSystemPrincipal is true if the system principal should be used for
180 // this sheet, no matter what the channel principal is. Only true for sync
182 const bool mUseSystemPrincipal
: 1;
184 // If true, this SheetLoadData is being used as a way to handle
185 // async observer notification for an already-complete sheet.
186 bool mSheetAlreadyComplete
: 1;
188 // If true, the sheet is being loaded cross-origin without CORS permissions.
189 // This is completely normal and CORS isn't needed for such loads. This
190 // flag is simply useful in determining whether to set mBlockResourceTiming
191 // for a child sheet.
192 bool mIsCrossOriginNoCORS
: 1;
194 // If this flag is true, LoadSheet will call SetReportResourceTiming(false)
195 // on the timedChannel. This is to mark resources that are loaded by a
196 // cross-origin stylesheet with a no-cors policy.
197 // https://www.w3.org/TR/resource-timing/#processing-model
198 bool mBlockResourceTiming
: 1;
200 // Boolean flag indicating whether the load has failed. This will be set
201 // to true if this load, or the load of any descendant import, fails.
202 bool mLoadFailed
: 1;
204 // Whether this is a preload, and which kind of preload it is.
206 // TODO(emilio): This can become a bitfield once we build with a GCC version
207 // that has the fix for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414,
208 // which causes a false positive warning here.
209 const StylePreloadKind mPreloadKind
;
211 nsINode
* GetRequestingNode() const;
213 // The observer that wishes to be notified of load completion
214 nsCOMPtr
<nsICSSLoaderObserver
> mObserver
;
216 // The principal that identifies who started loading us.
217 const nsCOMPtr
<nsIPrincipal
> mTriggeringPrincipal
;
219 // Referrer info of the load.
220 const nsCOMPtr
<nsIReferrerInfo
> mReferrerInfo
;
222 // The cryptographic nonce of the load used for CSP checks.
223 const nsString mNonce
;
225 const dom::FetchPriority mFetchPriority
;
227 // The encoding guessed from attributes and the document character set.
228 const NotNull
<const Encoding
*> mGuessedEncoding
;
230 // The quirks mode of the loader at the time the load was triggered.
231 const nsCompatibility mCompatMode
;
233 // Whether SheetComplete was called.
234 bool mSheetCompleteCalled
= false;
236 // Whether we intentionally are not calling SheetComplete because nobody is
237 // listening for the load.
238 bool mIntentionallyDropped
= false;
240 bool ShouldDefer() const { return mWasAlternate
|| !mMediaMatched
; }
242 RefPtr
<StyleSheet
> ValueForCache() const;
243 uint32_t ExpirationTime() const { return mExpirationTime
; }
245 // If there are no child sheets outstanding, mark us as complete.
246 // Otherwise, the children are holding strong refs to the data
247 // and will call SheetComplete() on it when they complete.
248 void SheetFinishedParsingAsync() {
249 MOZ_ASSERT(mIsBeingParsed
);
250 mIsBeingParsed
= false;
251 if (!mPendingChildren
) {
252 mLoader
->SheetComplete(*this, NS_OK
);
256 bool IsPreload() const { return mPreloadKind
!= StylePreloadKind::None
; }
257 bool IsLinkRelPreload() const { return css::IsLinkRelPreload(mPreloadKind
); }
259 bool BlocksLoadEvent() const {
260 const auto& root
= RootLoadData();
261 return !root
.IsLinkRelPreload() && !root
.IsSyncLoad();
264 bool IsSyncLoad() const override
{ return mSyncLoad
; }
265 bool IsLoading() const override
{ return mIsLoading
; }
266 bool IsCancelled() const override
{ return mIsCancelled
; }
268 void StartLoading() override
{ mIsLoading
= true; }
269 void SetLoadCompleted() override
{ mIsLoading
= false; }
270 void Cancel() override
{ mIsCancelled
= true; }
273 const SheetLoadData
& RootLoadData() const {
274 const auto* top
= this;
275 while (top
->mParentData
) {
276 top
= top
->mParentData
;
282 using SheetLoadDataHolder
= nsMainThreadPtrHolder
<SheetLoadData
>;
284 } // namespace mozilla::css
286 #endif // mozilla_css_SheetLoadData_h