1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #ifndef nsHtml5SpeculativeLoad_h
6 #define nsHtml5SpeculativeLoad_h
9 #include "nsContentUtils.h"
10 #include "nsHtml5DocumentMode.h"
11 #include "nsHtml5String.h"
12 #include "ReferrerInfo.h"
14 class nsHtml5TreeOpExecutor
;
16 enum eHtml5SpeculativeLoad
{
17 eSpeculativeLoadUninitialized
,
20 eSpeculativeLoadMetaReferrer
,
21 eSpeculativeLoadImage
,
22 eSpeculativeLoadOpenPicture
,
23 eSpeculativeLoadEndPicture
,
24 eSpeculativeLoadPictureSource
,
25 eSpeculativeLoadScript
,
26 eSpeculativeLoadScriptFromHead
,
27 eSpeculativeLoadStyle
,
28 eSpeculativeLoadManifest
,
29 eSpeculativeLoadSetDocumentCharset
,
30 eSpeculativeLoadSetDocumentMode
,
31 eSpeculativeLoadPreconnect
,
33 eSpeculativeLoadFetch
,
34 eSpeculativeLoadMaybeComplainAboutCharset
37 class nsHtml5SpeculativeLoad
{
38 using Encoding
= mozilla::Encoding
;
40 using NotNull
= mozilla::NotNull
<T
>;
43 nsHtml5SpeculativeLoad();
44 ~nsHtml5SpeculativeLoad();
46 inline void InitBase(nsHtml5String aUrl
) {
47 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
48 "Trying to reinitialize a speculative load!");
49 mOpCode
= eSpeculativeLoadBase
;
50 aUrl
.ToString(mUrlOrSizes
);
53 inline void InitMetaCSP(nsHtml5String aCSP
) {
54 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
55 "Trying to reinitialize a speculative load!");
56 mOpCode
= eSpeculativeLoadCSP
;
57 nsString csp
; // Not Auto, because using it to hold nsStringBuffer*
59 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Assign(
60 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(csp
));
63 inline void InitMetaReferrerPolicy(nsHtml5String aReferrerPolicy
) {
64 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
65 "Trying to reinitialize a speculative load!");
66 mOpCode
= eSpeculativeLoadMetaReferrer
;
68 referrerPolicy
; // Not Auto, because using it to hold nsStringBuffer*
69 aReferrerPolicy
.ToString(referrerPolicy
);
70 mReferrerPolicyOrIntegrity
.Assign(
71 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
75 inline void InitImage(nsHtml5String aUrl
, nsHtml5String aCrossOrigin
,
76 nsHtml5String aMedia
, nsHtml5String aReferrerPolicy
,
77 nsHtml5String aSrcset
, nsHtml5String aSizes
,
79 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
80 "Trying to reinitialize a speculative load!");
81 mOpCode
= eSpeculativeLoadImage
;
82 aUrl
.ToString(mUrlOrSizes
);
83 aCrossOrigin
.ToString(mCrossOrigin
);
84 aMedia
.ToString(mMedia
);
86 referrerPolicy
; // Not Auto, because using it to hold nsStringBuffer*
87 aReferrerPolicy
.ToString(referrerPolicy
);
88 mReferrerPolicyOrIntegrity
.Assign(
89 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
91 aSrcset
.ToString(mCharsetOrSrcset
);
93 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
);
94 mIsLinkPreload
= aLinkPreload
;
97 inline void InitFont(nsHtml5String aUrl
, nsHtml5String aCrossOrigin
,
98 nsHtml5String aMedia
, nsHtml5String aReferrerPolicy
) {
99 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
100 "Trying to reinitialize a speculative load!");
101 mOpCode
= eSpeculativeLoadFont
;
102 aUrl
.ToString(mUrlOrSizes
);
103 aCrossOrigin
.ToString(mCrossOrigin
);
104 aMedia
.ToString(mMedia
);
106 referrerPolicy
; // Not Auto, because using it to hold nsStringBuffer*
107 aReferrerPolicy
.ToString(referrerPolicy
);
108 mReferrerPolicyOrIntegrity
.Assign(
109 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
111 // This can be only triggered by <link rel=preload type=font>
112 mIsLinkPreload
= true;
115 inline void InitFetch(nsHtml5String aUrl
, nsHtml5String aCrossOrigin
,
116 nsHtml5String aMedia
, nsHtml5String aReferrerPolicy
) {
117 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
118 "Trying to reinitialize a speculative load!");
119 mOpCode
= eSpeculativeLoadFetch
;
120 aUrl
.ToString(mUrlOrSizes
);
121 aCrossOrigin
.ToString(mCrossOrigin
);
122 aMedia
.ToString(mMedia
);
124 referrerPolicy
; // Not Auto, because using it to hold nsStringBuffer*
125 aReferrerPolicy
.ToString(referrerPolicy
);
126 mReferrerPolicyOrIntegrity
.Assign(
127 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
130 // This method can be only be triggered by <link rel=preload type=fetch>,
131 // hence this operation is always a preload.
132 mIsLinkPreload
= true;
135 // <picture> elements have multiple <source> nodes followed by an <img>,
136 // where we use the first valid source, which may be the img. Because we
137 // can't determine validity at this point without parsing CSS and getting
138 // main thread state, we push preload operations for picture pushed and
139 // popped, so that the target of the preload ops can determine what picture
140 // and nesting level each source/img from the main preloading code exists
142 inline void InitOpenPicture() {
143 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
144 "Trying to reinitialize a speculative load!");
145 mOpCode
= eSpeculativeLoadOpenPicture
;
148 inline void InitEndPicture() {
149 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
150 "Trying to reinitialize a speculative load!");
151 mOpCode
= eSpeculativeLoadEndPicture
;
154 inline void InitPictureSource(nsHtml5String aSrcset
, nsHtml5String aSizes
,
155 nsHtml5String aType
, nsHtml5String aMedia
) {
156 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
157 "Trying to reinitialize a speculative load!");
158 mOpCode
= eSpeculativeLoadPictureSource
;
159 aSrcset
.ToString(mCharsetOrSrcset
);
160 aSizes
.ToString(mUrlOrSizes
);
162 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
);
163 aMedia
.ToString(mMedia
);
166 inline void InitScript(nsHtml5String aUrl
, nsHtml5String aCharset
,
167 nsHtml5String aType
, nsHtml5String aCrossOrigin
,
168 nsHtml5String aMedia
, nsHtml5String aNonce
,
169 nsHtml5String aFetchPriority
, nsHtml5String aIntegrity
,
170 nsHtml5String aReferrerPolicy
, bool aParserInHead
,
171 bool aAsync
, bool aDefer
, bool aLinkPreload
) {
172 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
173 "Trying to reinitialize a speculative load!");
175 aParserInHead
? eSpeculativeLoadScriptFromHead
: eSpeculativeLoadScript
;
176 aUrl
.ToString(mUrlOrSizes
);
177 aCharset
.ToString(mCharsetOrSrcset
);
179 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
);
180 aCrossOrigin
.ToString(mCrossOrigin
);
181 aMedia
.ToString(mMedia
);
182 aNonce
.ToString(mNonce
);
183 aFetchPriority
.ToString(mFetchPriority
);
184 aIntegrity
.ToString(mReferrerPolicyOrIntegrity
);
185 nsAutoString referrerPolicy
;
186 aReferrerPolicy
.ToString(referrerPolicy
);
188 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
190 mScriptReferrerPolicy
=
191 mozilla::dom::ReferrerInfo::ReferrerPolicyAttributeFromString(
196 mIsLinkPreload
= aLinkPreload
;
199 inline void InitImportStyle(nsString
&& aUrl
) {
200 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
201 "Trying to reinitialize a speculative load!");
202 mOpCode
= eSpeculativeLoadStyle
;
203 mUrlOrSizes
= std::move(aUrl
);
204 mCharsetOrSrcset
.SetIsVoid(true);
205 mCrossOrigin
.SetIsVoid(true);
206 mMedia
.SetIsVoid(true);
207 mReferrerPolicyOrIntegrity
.SetIsVoid(true);
208 mNonce
.SetIsVoid(true);
209 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.SetIsVoid(
213 inline void InitStyle(nsHtml5String aUrl
, nsHtml5String aCharset
,
214 nsHtml5String aCrossOrigin
, nsHtml5String aMedia
,
215 nsHtml5String aReferrerPolicy
, nsHtml5String aNonce
,
216 nsHtml5String aIntegrity
, bool aLinkPreload
) {
217 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
218 "Trying to reinitialize a speculative load!");
219 mOpCode
= eSpeculativeLoadStyle
;
220 aUrl
.ToString(mUrlOrSizes
);
221 aCharset
.ToString(mCharsetOrSrcset
);
222 aCrossOrigin
.ToString(mCrossOrigin
);
223 aMedia
.ToString(mMedia
);
225 referrerPolicy
; // Not Auto, because using it to hold nsStringBuffer*
226 aReferrerPolicy
.ToString(referrerPolicy
);
227 mReferrerPolicyOrIntegrity
.Assign(
228 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
230 aNonce
.ToString(mNonce
);
232 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
);
233 mIsLinkPreload
= aLinkPreload
;
237 * "Speculative" manifest loads aren't truly speculative--if a manifest
238 * gets loaded, we are committed to it. There can never be a <script>
239 * before the manifest, so the situation of having to undo a manifest due
240 * to document.write() never arises. The reason why a parser
241 * thread-discovered manifest gets loaded via the speculative load queue
242 * as opposed to tree operation queue is that the manifest must get
243 * processed before any actual speculative loads such as scripts. Thus,
244 * manifests seen by the parser thread have to maintain the queue order
245 * relative to true speculative loads. See bug 541079.
247 inline void InitManifest(nsHtml5String aUrl
) {
248 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
249 "Trying to reinitialize a speculative load!");
250 mOpCode
= eSpeculativeLoadManifest
;
251 aUrl
.ToString(mUrlOrSizes
);
255 * We communicate the encoding change via the speculative operation
256 * queue in order to act upon it as soon as possible and so as not to
257 * have speculative loads generated after an encoding change fail to
258 * make use of the encoding change.
260 inline void InitSetDocumentCharset(NotNull
<const Encoding
*> aEncoding
,
261 int32_t aCharsetSource
,
262 bool aCommitEncodingSpeculation
) {
263 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
264 "Trying to reinitialize a speculative load!");
265 mOpCode
= eSpeculativeLoadSetDocumentCharset
;
266 mCharsetOrSrcset
.~nsString();
267 mEncoding
= aEncoding
;
268 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Assign(
269 (char16_t
)aCharsetSource
);
270 mCommitEncodingSpeculation
= aCommitEncodingSpeculation
;
273 inline void InitMaybeComplainAboutCharset(const char* aMsgId
, bool aError
,
274 int32_t aLineNumber
) {
275 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
276 "Trying to reinitialize a speculative load!");
277 mOpCode
= eSpeculativeLoadMaybeComplainAboutCharset
;
278 mCharsetOrSrcset
.~nsString();
281 // Transport a 32-bit integer as two 16-bit code units of a string
282 // in order to avoid adding an integer field to the object.
283 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1733043 for a better
284 // eventual approach.
285 char16_t high
= (char16_t
)(((uint32_t)aLineNumber
) >> 16);
286 char16_t low
= (char16_t
)(((uint32_t)aLineNumber
) & 0xFFFF);
287 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Assign(high
);
288 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Append(low
);
292 * Speculative document mode setting isn't really speculative. Once it
293 * happens, we are committed to it. However, this information needs to
294 * travel in the speculation queue in order to have this information
295 * available before parsing the speculatively loaded style sheets.
297 inline void InitSetDocumentMode(nsHtml5DocumentMode aMode
) {
298 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
299 "Trying to reinitialize a speculative load!");
300 mOpCode
= eSpeculativeLoadSetDocumentMode
;
301 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Assign(
305 inline void InitPreconnect(nsHtml5String aUrl
, nsHtml5String aCrossOrigin
) {
306 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
307 "Trying to reinitialize a speculative load!");
308 mOpCode
= eSpeculativeLoadPreconnect
;
309 aUrl
.ToString(mUrlOrSizes
);
310 aCrossOrigin
.ToString(mCrossOrigin
);
313 void Perform(nsHtml5TreeOpExecutor
* aExecutor
);
316 nsHtml5SpeculativeLoad(const nsHtml5SpeculativeLoad
&) = delete;
317 nsHtml5SpeculativeLoad
& operator=(const nsHtml5SpeculativeLoad
&) = delete;
319 eHtml5SpeculativeLoad mOpCode
;
322 * Whether the refering element has async attribute.
327 * Whether the refering element has defer attribute.
332 * True if and only if this is a speculative load initiated by <link
333 * rel="preload"> or <link rel="modulepreload"> tag encounter. Passed to the
334 * handling loader as an indication to raise the priority.
339 * Whether the charset complaint is an error.
344 * Whether setting document encoding involves also committing to an encoding
347 bool mCommitEncodingSpeculation
;
349 /* If mOpCode is eSpeculativeLoadPictureSource, this is the value of the
350 * "sizes" attribute. If the attribute is not set, this will be a void
351 * string. Otherwise it empty or the value of the url.
353 nsString mUrlOrSizes
;
355 * If mOpCode is eSpeculativeLoadScript[FromHead], this is the value of the
356 * "integrity" attribute. If the attribute is not set, this will be a void
357 * string. Otherwise it is empty or the value of the referrer policy.
359 nsString mReferrerPolicyOrIntegrity
;
361 * If mOpCode is eSpeculativeLoadStyle or eSpeculativeLoadScript[FromHead]
362 * then this is the value of the "charset" attribute. For
363 * eSpeculativeLoadSetDocumentCharset it is the charset that the
364 * document's charset is being set to. If mOpCode is eSpeculativeLoadImage
365 * or eSpeculativeLoadPictureSource, this is the value of the "srcset"
366 * attribute. If the attribute is not set, this will be a void string.
367 * Otherwise it's empty.
368 * For eSpeculativeLoadMaybeComplainAboutCharset mMsgId is used.
371 nsString mCharsetOrSrcset
;
372 const Encoding
* mEncoding
;
376 * If mOpCode is eSpeculativeLoadSetDocumentCharset, this is a
377 * one-character string whose single character's code point is to be
378 * interpreted as a charset source integer. If mOpCode is
379 * eSpeculativeLoadSetDocumentMode, this is a one-character string whose
380 * single character's code point is to be interpreted as an
381 * nsHtml5DocumentMode. If mOpCode is eSpeculativeLoadCSP, this is a meta
382 * element's CSP value. If mOpCode is eSpeculativeLoadImage, this is the
383 * value of the "sizes" attribute. If the attribute is not set, this will
384 * be a void string. If mOpCode is eSpeculativeLoadStyle, this
385 * is the value of the "integrity" attribute. If the attribute is not set,
386 * this will be a void string. Otherwise, it is empty or the value of the type
389 nsString mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
;
391 * If mOpCode is eSpeculativeLoadImage or eSpeculativeLoadScript[FromHead]
392 * or eSpeculativeLoadPreconnect or eSpeculativeLoadStyle this is the value of
393 * the "crossorigin" attribute. If the attribute is not set, this will be a
396 nsString mCrossOrigin
;
398 * If mOpCode is eSpeculativeLoadPictureSource or eSpeculativeLoadStyle or
399 * Fetch or Image or Media or Script this is the value of the relevant "media"
400 * attribute of the <link rel="preload"> or <link rel="stylesheet">. If the
401 * attribute is not set, or the preload didn't originate from a <link>, this
402 * will be a void string.
406 * If mOpCode is eSpeculativeLoadScript[FromHead] this represents the value
407 * of the "nonce" attribute.
411 * If mOpCode is eSpeculativeLoadNoModuleScript[FromHead] or
412 * eSpeculativeLoadScript[FromHead] this represents the value of the
413 * "fetchpriority" attribute.
415 nsString mFetchPriority
;
417 * If mOpCode is eSpeculativeLoadScript[FromHead] this represents the value
418 * of the "referrerpolicy" attribute. This field holds one of the values
419 * (REFERRER_POLICY_*) defined in nsIHttpChannel.
421 mozilla::dom::ReferrerPolicy mScriptReferrerPolicy
;
424 #endif // nsHtml5SpeculativeLoad_h