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 eSpeculativeLoadNoModuleScript
,
28 eSpeculativeLoadNoModuleScriptFromHead
,
29 eSpeculativeLoadStyle
,
30 eSpeculativeLoadManifest
,
31 eSpeculativeLoadSetDocumentCharset
,
32 eSpeculativeLoadSetDocumentMode
,
33 eSpeculativeLoadPreconnect
,
35 eSpeculativeLoadFetch
,
36 eSpeculativeLoadMaybeComplainAboutCharset
39 class nsHtml5SpeculativeLoad
{
40 using Encoding
= mozilla::Encoding
;
42 using NotNull
= mozilla::NotNull
<T
>;
45 nsHtml5SpeculativeLoad();
46 ~nsHtml5SpeculativeLoad();
48 inline void InitBase(nsHtml5String aUrl
) {
49 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
50 "Trying to reinitialize a speculative load!");
51 mOpCode
= eSpeculativeLoadBase
;
52 aUrl
.ToString(mUrlOrSizes
);
55 inline void InitMetaCSP(nsHtml5String aCSP
) {
56 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
57 "Trying to reinitialize a speculative load!");
58 mOpCode
= eSpeculativeLoadCSP
;
59 nsString csp
; // Not Auto, because using it to hold nsStringBuffer*
61 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Assign(
62 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(csp
));
65 inline void InitMetaReferrerPolicy(nsHtml5String aReferrerPolicy
) {
66 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
67 "Trying to reinitialize a speculative load!");
68 mOpCode
= eSpeculativeLoadMetaReferrer
;
70 referrerPolicy
; // Not Auto, because using it to hold nsStringBuffer*
71 aReferrerPolicy
.ToString(referrerPolicy
);
72 mReferrerPolicyOrIntegrity
.Assign(
73 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
77 inline void InitImage(nsHtml5String aUrl
, nsHtml5String aCrossOrigin
,
78 nsHtml5String aMedia
, nsHtml5String aReferrerPolicy
,
79 nsHtml5String aSrcset
, nsHtml5String aSizes
,
81 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
82 "Trying to reinitialize a speculative load!");
83 mOpCode
= eSpeculativeLoadImage
;
84 aUrl
.ToString(mUrlOrSizes
);
85 aCrossOrigin
.ToString(mCrossOrigin
);
86 aMedia
.ToString(mMedia
);
88 referrerPolicy
; // Not Auto, because using it to hold nsStringBuffer*
89 aReferrerPolicy
.ToString(referrerPolicy
);
90 mReferrerPolicyOrIntegrity
.Assign(
91 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
93 aSrcset
.ToString(mCharsetOrSrcset
);
95 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
);
96 mIsLinkPreload
= aLinkPreload
;
97 mInitTimestamp
= mozilla::TimeStamp::Now();
100 inline void InitFont(nsHtml5String aUrl
, nsHtml5String aCrossOrigin
,
101 nsHtml5String aMedia
, nsHtml5String aReferrerPolicy
) {
102 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
103 "Trying to reinitialize a speculative load!");
104 mOpCode
= eSpeculativeLoadFont
;
105 aUrl
.ToString(mUrlOrSizes
);
106 aCrossOrigin
.ToString(mCrossOrigin
);
107 aMedia
.ToString(mMedia
);
109 referrerPolicy
; // Not Auto, because using it to hold nsStringBuffer*
110 aReferrerPolicy
.ToString(referrerPolicy
);
111 mReferrerPolicyOrIntegrity
.Assign(
112 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
114 // This can be only triggered by <link rel=preload type=font>
115 mIsLinkPreload
= true;
118 inline void InitFetch(nsHtml5String aUrl
, nsHtml5String aCrossOrigin
,
119 nsHtml5String aMedia
, nsHtml5String aReferrerPolicy
) {
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
>(
133 // This method can be only be triggered by <link rel=preload type=fetch>,
134 // hence this operation is always a preload.
135 mIsLinkPreload
= true;
138 // <picture> elements have multiple <source> nodes followed by an <img>,
139 // where we use the first valid source, which may be the img. Because we
140 // can't determine validity at this point without parsing CSS and getting
141 // main thread state, we push preload operations for picture pushed and
142 // popped, so that the target of the preload ops can determine what picture
143 // and nesting level each source/img from the main preloading code exists
145 inline void InitOpenPicture() {
146 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
147 "Trying to reinitialize a speculative load!");
148 mOpCode
= eSpeculativeLoadOpenPicture
;
151 inline void InitEndPicture() {
152 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
153 "Trying to reinitialize a speculative load!");
154 mOpCode
= eSpeculativeLoadEndPicture
;
157 inline void InitPictureSource(nsHtml5String aSrcset
, nsHtml5String aSizes
,
158 nsHtml5String aType
, nsHtml5String aMedia
) {
159 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
160 "Trying to reinitialize a speculative load!");
161 mOpCode
= eSpeculativeLoadPictureSource
;
162 aSrcset
.ToString(mCharsetOrSrcset
);
163 aSizes
.ToString(mUrlOrSizes
);
165 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
);
166 aMedia
.ToString(mMedia
);
169 inline void InitScript(nsHtml5String aUrl
, nsHtml5String aCharset
,
170 nsHtml5String aType
, nsHtml5String aCrossOrigin
,
171 nsHtml5String aMedia
, nsHtml5String aIntegrity
,
172 nsHtml5String aReferrerPolicy
, bool aParserInHead
,
173 bool aAsync
, bool aDefer
, bool aNoModule
,
175 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
176 "Trying to reinitialize a speculative load!");
178 mOpCode
= aParserInHead
? eSpeculativeLoadNoModuleScriptFromHead
179 : eSpeculativeLoadNoModuleScript
;
181 mOpCode
= aParserInHead
? eSpeculativeLoadScriptFromHead
182 : eSpeculativeLoadScript
;
184 aUrl
.ToString(mUrlOrSizes
);
185 aCharset
.ToString(mCharsetOrSrcset
);
187 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
);
188 aCrossOrigin
.ToString(mCrossOrigin
);
189 aMedia
.ToString(mMedia
);
190 aIntegrity
.ToString(mReferrerPolicyOrIntegrity
);
191 nsAutoString referrerPolicy
;
192 aReferrerPolicy
.ToString(referrerPolicy
);
194 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
196 mScriptReferrerPolicy
=
197 mozilla::dom::ReferrerInfo::ReferrerPolicyAttributeFromString(
202 mIsLinkPreload
= aLinkPreload
;
205 inline void InitImportStyle(nsString
&& aUrl
) {
206 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
207 "Trying to reinitialize a speculative load!");
208 mOpCode
= eSpeculativeLoadStyle
;
209 mUrlOrSizes
= std::move(aUrl
);
210 mCharsetOrSrcset
.SetIsVoid(true);
211 mCrossOrigin
.SetIsVoid(true);
212 mMedia
.SetIsVoid(true);
213 mReferrerPolicyOrIntegrity
.SetIsVoid(true);
214 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.SetIsVoid(
218 inline void InitStyle(nsHtml5String aUrl
, nsHtml5String aCharset
,
219 nsHtml5String aCrossOrigin
, nsHtml5String aMedia
,
220 nsHtml5String aReferrerPolicy
, nsHtml5String aIntegrity
,
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
>(
236 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
);
237 mIsLinkPreload
= aLinkPreload
;
241 * "Speculative" manifest loads aren't truly speculative--if a manifest
242 * gets loaded, we are committed to it. There can never be a <script>
243 * before the manifest, so the situation of having to undo a manifest due
244 * to document.write() never arises. The reason why a parser
245 * thread-discovered manifest gets loaded via the speculative load queue
246 * as opposed to tree operation queue is that the manifest must get
247 * processed before any actual speculative loads such as scripts. Thus,
248 * manifests seen by the parser thread have to maintain the queue order
249 * relative to true speculative loads. See bug 541079.
251 inline void InitManifest(nsHtml5String aUrl
) {
252 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
253 "Trying to reinitialize a speculative load!");
254 mOpCode
= eSpeculativeLoadManifest
;
255 aUrl
.ToString(mUrlOrSizes
);
259 * We communicate the encoding change via the speculative operation
260 * queue in order to act upon it as soon as possible and so as not to
261 * have speculative loads generated after an encoding change fail to
262 * make use of the encoding change.
264 inline void InitSetDocumentCharset(NotNull
<const Encoding
*> aEncoding
,
265 int32_t aCharsetSource
,
266 bool aCommitEncodingSpeculation
) {
267 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
268 "Trying to reinitialize a speculative load!");
269 mOpCode
= eSpeculativeLoadSetDocumentCharset
;
270 mCharsetOrSrcset
.~nsString();
271 mEncoding
= aEncoding
;
272 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Assign(
273 (char16_t
)aCharsetSource
);
274 mCommitEncodingSpeculation
= aCommitEncodingSpeculation
;
277 inline void InitMaybeComplainAboutCharset(const char* aMsgId
, bool aError
,
278 int32_t aLineNumber
) {
279 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
280 "Trying to reinitialize a speculative load!");
281 mOpCode
= eSpeculativeLoadMaybeComplainAboutCharset
;
282 mCharsetOrSrcset
.~nsString();
285 // Transport a 32-bit integer as two 16-bit code units of a string
286 // in order to avoid adding an integer field to the object.
287 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1733043 for a better
288 // eventual approach.
289 char16_t high
= (char16_t
)(((uint32_t)aLineNumber
) >> 16);
290 char16_t low
= (char16_t
)(((uint32_t)aLineNumber
) & 0xFFFF);
291 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Assign(high
);
292 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Append(low
);
296 * Speculative document mode setting isn't really speculative. Once it
297 * happens, we are committed to it. However, this information needs to
298 * travel in the speculation queue in order to have this information
299 * available before parsing the speculatively loaded style sheets.
301 inline void InitSetDocumentMode(nsHtml5DocumentMode aMode
) {
302 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
303 "Trying to reinitialize a speculative load!");
304 mOpCode
= eSpeculativeLoadSetDocumentMode
;
305 mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Assign(
309 inline void InitPreconnect(nsHtml5String aUrl
, nsHtml5String aCrossOrigin
) {
310 MOZ_ASSERT(mOpCode
== eSpeculativeLoadUninitialized
,
311 "Trying to reinitialize a speculative load!");
312 mOpCode
= eSpeculativeLoadPreconnect
;
313 aUrl
.ToString(mUrlOrSizes
);
314 aCrossOrigin
.ToString(mCrossOrigin
);
317 void Perform(nsHtml5TreeOpExecutor
* aExecutor
);
320 nsHtml5SpeculativeLoad(const nsHtml5SpeculativeLoad
&) = delete;
321 nsHtml5SpeculativeLoad
& operator=(const nsHtml5SpeculativeLoad
&) = delete;
323 eHtml5SpeculativeLoad mOpCode
;
326 * Whether the refering element has async attribute.
331 * Whether the refering element has defer attribute.
336 * True if and only if this is a speculative load initiated by <link
337 * rel="preload"> or <link rel="modulepreload"> tag encounter. Passed to the
338 * handling loader as an indication to raise the priority.
343 * Whether the charset complaint is an error.
348 * Whether setting document encoding involves also committing to an encoding
351 bool mCommitEncodingSpeculation
;
353 /* If mOpCode is eSpeculativeLoadPictureSource, this is the value of the
354 * "sizes" attribute. If the attribute is not set, this will be a void
355 * string. Otherwise it empty or the value of the url.
357 nsString mUrlOrSizes
;
359 * If mOpCode is eSpeculativeLoadScript[FromHead], this is the value of the
360 * "integrity" attribute. If the attribute is not set, this will be a void
361 * string. Otherwise it is empty or the value of the referrer policy.
363 nsString mReferrerPolicyOrIntegrity
;
365 * If mOpCode is eSpeculativeLoadStyle or eSpeculativeLoadScript[FromHead]
366 * then this is the value of the "charset" attribute. For
367 * eSpeculativeLoadSetDocumentCharset it is the charset that the
368 * document's charset is being set to. If mOpCode is eSpeculativeLoadImage
369 * or eSpeculativeLoadPictureSource, this is the value of the "srcset"
370 * attribute. If the attribute is not set, this will be a void string.
371 * Otherwise it's empty.
372 * For eSpeculativeLoadMaybeComplainAboutCharset mMsgId is used.
375 nsString mCharsetOrSrcset
;
376 const Encoding
* mEncoding
;
380 * If mOpCode is eSpeculativeLoadSetDocumentCharset, this is a
381 * one-character string whose single character's code point is to be
382 * interpreted as a charset source integer. If mOpCode is
383 * eSpeculativeLoadSetDocumentMode, this is a one-character string whose
384 * single character's code point is to be interpreted as an
385 * nsHtml5DocumentMode. If mOpCode is eSpeculativeLoadCSP, this is a meta
386 * element's CSP value. If mOpCode is eSpeculativeLoadImage, this is the
387 * value of the "sizes" attribute. If the attribute is not set, this will
388 * be a void string. If mOpCode is eSpeculativeLoadStyle, this
389 * is the value of the "integrity" attribute. If the attribute is not set,
390 * this will be a void string. Otherwise, it is empty or the value of the type
393 nsString mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
;
395 * If mOpCode is eSpeculativeLoadImage or eSpeculativeLoadScript[FromHead]
396 * or eSpeculativeLoadPreconnect or eSpeculativeLoadStyle this is the value of
397 * the "crossorigin" attribute. If the attribute is not set, this will be a
400 nsString mCrossOrigin
;
402 * If mOpCode is eSpeculativeLoadPictureSource or eSpeculativeLoadStyle or
403 * Fetch or Image or Media or Script this is the value of the relevant "media"
404 * attribute of the <link rel="preload"> or <link rel="stylesheet">. If the
405 * attribute is not set, or the preload didn't originate from a <link>, this
406 * will be a void string.
410 * If mOpCode is eSpeculativeLoadScript[FromHead] this represents the value
411 * of the "referrerpolicy" attribute. This field holds one of the values
412 * (REFERRER_POLICY_*) defined in nsIHttpChannel.
414 mozilla::dom::ReferrerPolicy mScriptReferrerPolicy
;
416 mozilla::TimeStamp mInitTimestamp
;
419 #endif // nsHtml5SpeculativeLoad_h