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 nsHtml5String aFetchPriority
) {
100 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
101 "Trying to reinitialize a speculative load!");
102 mOpCode
= eSpeculativeLoadFont
;
103 aUrl
.ToString(mUrlOrSizes
);
104 aCrossOrigin
.ToString(mCrossOrigin
);
105 aMedia
.ToString(mMedia
);
107 referrerPolicy
; // Not Auto, because using it to hold nsStringBuffer*
108 aReferrerPolicy
.ToString(referrerPolicy
);
109 mReferrerPolicyOrIntegrity
.Assign(
110 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
112 aFetchPriority
.ToString(mFetchPriority
);
113 // This can be only triggered by <link rel=preload type=font>
114 mIsLinkPreload
= true;
117 inline void InitFetch(nsHtml5String aUrl
, nsHtml5String aCrossOrigin
,
118 nsHtml5String aMedia
, nsHtml5String aReferrerPolicy
,
119 nsHtml5String aFetchPriority
) {
120 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
121 "Trying to reinitialize a speculative load!");
122 mOpCode
= eSpeculativeLoadFetch
;
123 aUrl
.ToString(mUrlOrSizes
);
124 aCrossOrigin
.ToString(mCrossOrigin
);
125 aMedia
.ToString(mMedia
);
127 referrerPolicy
; // Not Auto, because using it to hold nsStringBuffer*
128 aReferrerPolicy
.ToString(referrerPolicy
);
129 mReferrerPolicyOrIntegrity
.Assign(
130 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
132 aFetchPriority
.ToString(mFetchPriority
);
134 // This method can be only be triggered by <link rel=preload type=fetch>,
135 // hence this operation is always a preload.
136 mIsLinkPreload
= true;
139 // <picture> elements have multiple <source> nodes followed by an <img>,
140 // where we use the first valid source, which may be the img. Because we
141 // can't determine validity at this point without parsing CSS and getting
142 // main thread state, we push preload operations for picture pushed and
143 // popped, so that the target of the preload ops can determine what picture
144 // and nesting level each source/img from the main preloading code exists
146 inline void InitOpenPicture() {
147 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
148 "Trying to reinitialize a speculative load!");
149 mOpCode
= eSpeculativeLoadOpenPicture
;
152 inline void InitEndPicture() {
153 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
154 "Trying to reinitialize a speculative load!");
155 mOpCode
= eSpeculativeLoadEndPicture
;
158 inline void InitPictureSource(nsHtml5String aSrcset
, nsHtml5String aSizes
,
159 nsHtml5String aType
, nsHtml5String aMedia
) {
160 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
161 "Trying to reinitialize a speculative load!");
162 mOpCode
= eSpeculativeLoadPictureSource
;
163 aSrcset
.ToString(mCharsetOrSrcset
);
164 aSizes
.ToString(mUrlOrSizes
);
166 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
);
167 aMedia
.ToString(mMedia
);
170 inline void InitScript(nsHtml5String aUrl
, nsHtml5String aCharset
,
171 nsHtml5String aType
, nsHtml5String aCrossOrigin
,
172 nsHtml5String aMedia
, nsHtml5String aNonce
,
173 nsHtml5String aFetchPriority
, nsHtml5String aIntegrity
,
174 nsHtml5String aReferrerPolicy
, bool aParserInHead
,
175 bool aAsync
, bool aDefer
, bool aLinkPreload
) {
176 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
177 "Trying to reinitialize a speculative load!");
179 aParserInHead
? eSpeculativeLoadScriptFromHead
: eSpeculativeLoadScript
;
180 aUrl
.ToString(mUrlOrSizes
);
181 aCharset
.ToString(mCharsetOrSrcset
);
183 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
);
184 aCrossOrigin
.ToString(mCrossOrigin
);
185 aMedia
.ToString(mMedia
);
186 aNonce
.ToString(mNonce
);
187 aFetchPriority
.ToString(mFetchPriority
);
188 aIntegrity
.ToString(mReferrerPolicyOrIntegrity
);
189 nsAutoString referrerPolicy
;
190 aReferrerPolicy
.ToString(referrerPolicy
);
192 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
194 mScriptReferrerPolicy
=
195 mozilla::dom::ReferrerInfo::ReferrerPolicyAttributeFromString(
200 mIsLinkPreload
= aLinkPreload
;
203 inline void InitImportStyle(nsString
&& aUrl
) {
204 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
205 "Trying to reinitialize a speculative load!");
206 mOpCode
= eSpeculativeLoadStyle
;
207 mUrlOrSizes
= std::move(aUrl
);
208 mCharsetOrSrcset
.SetIsVoid(true);
209 mCrossOrigin
.SetIsVoid(true);
210 mMedia
.SetIsVoid(true);
211 mReferrerPolicyOrIntegrity
.SetIsVoid(true);
212 mNonce
.SetIsVoid(true);
213 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.SetIsVoid(
217 inline void InitStyle(nsHtml5String aUrl
, nsHtml5String aCharset
,
218 nsHtml5String aCrossOrigin
, nsHtml5String aMedia
,
219 nsHtml5String aReferrerPolicy
, nsHtml5String aNonce
,
220 nsHtml5String aIntegrity
, bool aLinkPreload
,
221 nsHtml5String aFetchPriority
) {
222 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
223 "Trying to reinitialize a speculative load!");
224 mOpCode
= eSpeculativeLoadStyle
;
225 aUrl
.ToString(mUrlOrSizes
);
226 aCharset
.ToString(mCharsetOrSrcset
);
227 aCrossOrigin
.ToString(mCrossOrigin
);
228 aMedia
.ToString(mMedia
);
230 referrerPolicy
; // Not Auto, because using it to hold nsStringBuffer*
231 aReferrerPolicy
.ToString(referrerPolicy
);
232 mReferrerPolicyOrIntegrity
.Assign(
233 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
235 aNonce
.ToString(mNonce
);
237 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
);
238 mIsLinkPreload
= aLinkPreload
;
239 aFetchPriority
.ToString(mFetchPriority
);
243 * "Speculative" manifest loads aren't truly speculative--if a manifest
244 * gets loaded, we are committed to it. There can never be a <script>
245 * before the manifest, so the situation of having to undo a manifest due
246 * to document.write() never arises. The reason why a parser
247 * thread-discovered manifest gets loaded via the speculative load queue
248 * as opposed to tree operation queue is that the manifest must get
249 * processed before any actual speculative loads such as scripts. Thus,
250 * manifests seen by the parser thread have to maintain the queue order
251 * relative to true speculative loads. See bug 541079.
253 inline void InitManifest(nsHtml5String aUrl
) {
254 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
255 "Trying to reinitialize a speculative load!");
256 mOpCode
= eSpeculativeLoadManifest
;
257 aUrl
.ToString(mUrlOrSizes
);
261 * We communicate the encoding change via the speculative operation
262 * queue in order to act upon it as soon as possible and so as not to
263 * have speculative loads generated after an encoding change fail to
264 * make use of the encoding change.
266 inline void InitSetDocumentCharset(NotNull
<const Encoding
*> aEncoding
,
267 int32_t aCharsetSource
,
268 bool aCommitEncodingSpeculation
) {
269 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
270 "Trying to reinitialize a speculative load!");
271 mOpCode
= eSpeculativeLoadSetDocumentCharset
;
272 mCharsetOrSrcset
.~nsString();
273 mEncoding
= aEncoding
;
274 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Assign(
275 (char16_t
)aCharsetSource
);
276 mCommitEncodingSpeculation
= aCommitEncodingSpeculation
;
279 inline void InitMaybeComplainAboutCharset(const char* aMsgId
, bool aError
,
280 int32_t aLineNumber
) {
281 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
282 "Trying to reinitialize a speculative load!");
283 mOpCode
= eSpeculativeLoadMaybeComplainAboutCharset
;
284 mCharsetOrSrcset
.~nsString();
287 // Transport a 32-bit integer as two 16-bit code units of a string
288 // in order to avoid adding an integer field to the object.
289 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1733043 for a better
290 // eventual approach.
291 char16_t high
= (char16_t
)(((uint32_t)aLineNumber
) >> 16);
292 char16_t low
= (char16_t
)(((uint32_t)aLineNumber
) & 0xFFFF);
293 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Assign(high
);
294 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Append(low
);
298 * Speculative document mode setting isn't really speculative. Once it
299 * happens, we are committed to it. However, this information needs to
300 * travel in the speculation queue in order to have this information
301 * available before parsing the speculatively loaded style sheets.
303 inline void InitSetDocumentMode(nsHtml5DocumentMode aMode
) {
304 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
305 "Trying to reinitialize a speculative load!");
306 mOpCode
= eSpeculativeLoadSetDocumentMode
;
307 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Assign(
311 inline void InitPreconnect(nsHtml5String aUrl
, nsHtml5String aCrossOrigin
) {
312 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
313 "Trying to reinitialize a speculative load!");
314 mOpCode
= eSpeculativeLoadPreconnect
;
315 aUrl
.ToString(mUrlOrSizes
);
316 aCrossOrigin
.ToString(mCrossOrigin
);
319 void Perform(nsHtml5TreeOpExecutor
* aExecutor
);
322 nsHtml5SpeculativeLoad(const nsHtml5SpeculativeLoad
&) = delete;
323 nsHtml5SpeculativeLoad
& operator=(const nsHtml5SpeculativeLoad
&) = delete;
325 eHtml5SpeculativeLoad mOpCode
;
328 * Whether the refering element has async attribute.
333 * Whether the refering element has defer attribute.
338 * True if and only if this is a speculative load initiated by <link
339 * rel="preload"> or <link rel="modulepreload"> tag encounter. Passed to the
340 * handling loader as an indication to raise the priority.
345 * Whether the charset complaint is an error.
350 * Whether setting document encoding involves also committing to an encoding
353 bool mCommitEncodingSpeculation
;
355 /* If mOpCode is eSpeculativeLoadPictureSource, this is the value of the
356 * "sizes" attribute. If the attribute is not set, this will be a void
357 * string. Otherwise it empty or the value of the url.
359 nsString mUrlOrSizes
;
361 * If mOpCode is eSpeculativeLoadScript[FromHead], this is the value of the
362 * "integrity" attribute. If the attribute is not set, this will be a void
363 * string. Otherwise it is empty or the value of the referrer policy.
365 nsString mReferrerPolicyOrIntegrity
;
367 * If mOpCode is eSpeculativeLoadStyle or eSpeculativeLoadScript[FromHead]
368 * then this is the value of the "charset" attribute. For
369 * eSpeculativeLoadSetDocumentCharset it is the charset that the
370 * document's charset is being set to. If mOpCode is eSpeculativeLoadImage
371 * or eSpeculativeLoadPictureSource, this is the value of the "srcset"
372 * attribute. If the attribute is not set, this will be a void string.
373 * Otherwise it's empty.
374 * For eSpeculativeLoadMaybeComplainAboutCharset mMsgId is used.
377 nsString mCharsetOrSrcset
;
378 const Encoding
* mEncoding
;
382 * If mOpCode is eSpeculativeLoadSetDocumentCharset, this is a
383 * one-character string whose single character's code point is to be
384 * interpreted as a charset source integer. If mOpCode is
385 * eSpeculativeLoadSetDocumentMode, this is a one-character string whose
386 * single character's code point is to be interpreted as an
387 * nsHtml5DocumentMode. If mOpCode is eSpeculativeLoadCSP, this is a meta
388 * element's CSP value. If mOpCode is eSpeculativeLoadImage, this is the
389 * value of the "sizes" attribute. If the attribute is not set, this will
390 * be a void string. If mOpCode is eSpeculativeLoadStyle, this
391 * is the value of the "integrity" attribute. If the attribute is not set,
392 * this will be a void string. Otherwise, it is empty or the value of the type
395 nsString mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
;
397 * If mOpCode is eSpeculativeLoadImage or eSpeculativeLoadScript[FromHead]
398 * or eSpeculativeLoadPreconnect or eSpeculativeLoadStyle this is the value of
399 * the "crossorigin" attribute. If the attribute is not set, this will be a
402 nsString mCrossOrigin
;
404 * If mOpCode is eSpeculativeLoadPictureSource or eSpeculativeLoadStyle or
405 * Fetch or Image or Media or Script this is the value of the relevant "media"
406 * attribute of the <link rel="preload"> or <link rel="stylesheet">. If the
407 * attribute is not set, or the preload didn't originate from a <link>, this
408 * will be a void string.
412 * If mOpCode is eSpeculativeLoadScript[FromHead] this represents the value
413 * of the "nonce" attribute.
417 * If mOpCode is eSpeculativeLoadNoModuleScript[FromHead] or
418 * eSpeculativeLoadScript[FromHead] this represents the value of the
419 * "fetchpriority" attribute.
421 nsString mFetchPriority
;
423 * If mOpCode is eSpeculativeLoadScript[FromHead] this represents the value
424 * of the "referrerpolicy" attribute. This field holds one of the values
425 * (REFERRER_POLICY_*) defined in nsIHttpChannel.
427 mozilla::dom::ReferrerPolicy mScriptReferrerPolicy
;
430 #endif // nsHtml5SpeculativeLoad_h