summaryrefslogtreecommitdiffstats
path: root/parser/html/nsHtml5SpeculativeLoad.h
diff options
context:
space:
mode:
Diffstat (limited to 'parser/html/nsHtml5SpeculativeLoad.h')
-rw-r--r--parser/html/nsHtml5SpeculativeLoad.h419
1 files changed, 419 insertions, 0 deletions
diff --git a/parser/html/nsHtml5SpeculativeLoad.h b/parser/html/nsHtml5SpeculativeLoad.h
new file mode 100644
index 0000000000..4b2f755857
--- /dev/null
+++ b/parser/html/nsHtml5SpeculativeLoad.h
@@ -0,0 +1,419 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsHtml5SpeculativeLoad_h
+#define nsHtml5SpeculativeLoad_h
+
+#include "nsString.h"
+#include "nsContentUtils.h"
+#include "nsHtml5DocumentMode.h"
+#include "nsHtml5String.h"
+#include "ReferrerInfo.h"
+
+class nsHtml5TreeOpExecutor;
+
+enum eHtml5SpeculativeLoad {
+ eSpeculativeLoadUninitialized,
+ eSpeculativeLoadBase,
+ eSpeculativeLoadCSP,
+ eSpeculativeLoadMetaReferrer,
+ eSpeculativeLoadImage,
+ eSpeculativeLoadOpenPicture,
+ eSpeculativeLoadEndPicture,
+ eSpeculativeLoadPictureSource,
+ eSpeculativeLoadScript,
+ eSpeculativeLoadScriptFromHead,
+ eSpeculativeLoadNoModuleScript,
+ eSpeculativeLoadNoModuleScriptFromHead,
+ eSpeculativeLoadStyle,
+ eSpeculativeLoadManifest,
+ eSpeculativeLoadSetDocumentCharset,
+ eSpeculativeLoadSetDocumentMode,
+ eSpeculativeLoadPreconnect,
+ eSpeculativeLoadFont,
+ eSpeculativeLoadFetch,
+ eSpeculativeLoadMaybeComplainAboutCharset
+};
+
+class nsHtml5SpeculativeLoad {
+ using Encoding = mozilla::Encoding;
+ template <typename T>
+ using NotNull = mozilla::NotNull<T>;
+
+ public:
+ nsHtml5SpeculativeLoad();
+ ~nsHtml5SpeculativeLoad();
+
+ inline void InitBase(nsHtml5String aUrl) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadBase;
+ aUrl.ToString(mUrlOrSizes);
+ }
+
+ inline void InitMetaCSP(nsHtml5String aCSP) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadCSP;
+ nsString csp; // Not Auto, because using it to hold nsStringBuffer*
+ aCSP.ToString(csp);
+ mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Assign(
+ nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(csp));
+ }
+
+ inline void InitMetaReferrerPolicy(nsHtml5String aReferrerPolicy) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadMetaReferrer;
+ nsString
+ referrerPolicy; // Not Auto, because using it to hold nsStringBuffer*
+ aReferrerPolicy.ToString(referrerPolicy);
+ mReferrerPolicyOrIntegrity.Assign(
+ nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
+ referrerPolicy));
+ }
+
+ inline void InitImage(nsHtml5String aUrl, nsHtml5String aCrossOrigin,
+ nsHtml5String aMedia, nsHtml5String aReferrerPolicy,
+ nsHtml5String aSrcset, nsHtml5String aSizes,
+ bool aLinkPreload) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadImage;
+ aUrl.ToString(mUrlOrSizes);
+ aCrossOrigin.ToString(mCrossOrigin);
+ aMedia.ToString(mMedia);
+ nsString
+ referrerPolicy; // Not Auto, because using it to hold nsStringBuffer*
+ aReferrerPolicy.ToString(referrerPolicy);
+ mReferrerPolicyOrIntegrity.Assign(
+ nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
+ referrerPolicy));
+ aSrcset.ToString(mCharsetOrSrcset);
+ aSizes.ToString(
+ mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity);
+ mIsLinkPreload = aLinkPreload;
+ mInitTimestamp = mozilla::TimeStamp::Now();
+ }
+
+ inline void InitFont(nsHtml5String aUrl, nsHtml5String aCrossOrigin,
+ nsHtml5String aMedia, nsHtml5String aReferrerPolicy) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadFont;
+ aUrl.ToString(mUrlOrSizes);
+ aCrossOrigin.ToString(mCrossOrigin);
+ aMedia.ToString(mMedia);
+ nsString
+ referrerPolicy; // Not Auto, because using it to hold nsStringBuffer*
+ aReferrerPolicy.ToString(referrerPolicy);
+ mReferrerPolicyOrIntegrity.Assign(
+ nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
+ referrerPolicy));
+ // This can be only triggered by <link rel=preload type=font>
+ mIsLinkPreload = true;
+ }
+
+ inline void InitFetch(nsHtml5String aUrl, nsHtml5String aCrossOrigin,
+ nsHtml5String aMedia, nsHtml5String aReferrerPolicy) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadFetch;
+ aUrl.ToString(mUrlOrSizes);
+ aCrossOrigin.ToString(mCrossOrigin);
+ aMedia.ToString(mMedia);
+ nsString
+ referrerPolicy; // Not Auto, because using it to hold nsStringBuffer*
+ aReferrerPolicy.ToString(referrerPolicy);
+ mReferrerPolicyOrIntegrity.Assign(
+ nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
+ referrerPolicy));
+
+ // This method can be only be triggered by <link rel=preload type=fetch>,
+ // hence this operation is always a preload.
+ mIsLinkPreload = true;
+ }
+
+ // <picture> elements have multiple <source> nodes followed by an <img>,
+ // where we use the first valid source, which may be the img. Because we
+ // can't determine validity at this point without parsing CSS and getting
+ // main thread state, we push preload operations for picture pushed and
+ // popped, so that the target of the preload ops can determine what picture
+ // and nesting level each source/img from the main preloading code exists
+ // at.
+ inline void InitOpenPicture() {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadOpenPicture;
+ }
+
+ inline void InitEndPicture() {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadEndPicture;
+ }
+
+ inline void InitPictureSource(nsHtml5String aSrcset, nsHtml5String aSizes,
+ nsHtml5String aType, nsHtml5String aMedia) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadPictureSource;
+ aSrcset.ToString(mCharsetOrSrcset);
+ aSizes.ToString(mUrlOrSizes);
+ aType.ToString(
+ mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity);
+ aMedia.ToString(mMedia);
+ }
+
+ inline void InitScript(nsHtml5String aUrl, nsHtml5String aCharset,
+ nsHtml5String aType, nsHtml5String aCrossOrigin,
+ nsHtml5String aMedia, nsHtml5String aIntegrity,
+ nsHtml5String aReferrerPolicy, bool aParserInHead,
+ bool aAsync, bool aDefer, bool aNoModule,
+ bool aLinkPreload) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ if (aNoModule) {
+ mOpCode = aParserInHead ? eSpeculativeLoadNoModuleScriptFromHead
+ : eSpeculativeLoadNoModuleScript;
+ } else {
+ mOpCode = aParserInHead ? eSpeculativeLoadScriptFromHead
+ : eSpeculativeLoadScript;
+ }
+ aUrl.ToString(mUrlOrSizes);
+ aCharset.ToString(mCharsetOrSrcset);
+ aType.ToString(
+ mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity);
+ aCrossOrigin.ToString(mCrossOrigin);
+ aMedia.ToString(mMedia);
+ aIntegrity.ToString(mReferrerPolicyOrIntegrity);
+ nsAutoString referrerPolicy;
+ aReferrerPolicy.ToString(referrerPolicy);
+ referrerPolicy =
+ nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
+ referrerPolicy);
+ mScriptReferrerPolicy =
+ mozilla::dom::ReferrerInfo::ReferrerPolicyAttributeFromString(
+ referrerPolicy);
+
+ mIsAsync = aAsync;
+ mIsDefer = aDefer;
+ mIsLinkPreload = aLinkPreload;
+ }
+
+ inline void InitImportStyle(nsString&& aUrl) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadStyle;
+ mUrlOrSizes = std::move(aUrl);
+ mCharsetOrSrcset.SetIsVoid(true);
+ mCrossOrigin.SetIsVoid(true);
+ mMedia.SetIsVoid(true);
+ mReferrerPolicyOrIntegrity.SetIsVoid(true);
+ mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.SetIsVoid(
+ true);
+ }
+
+ inline void InitStyle(nsHtml5String aUrl, nsHtml5String aCharset,
+ nsHtml5String aCrossOrigin, nsHtml5String aMedia,
+ nsHtml5String aReferrerPolicy, nsHtml5String aIntegrity,
+ bool aLinkPreload) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadStyle;
+ aUrl.ToString(mUrlOrSizes);
+ aCharset.ToString(mCharsetOrSrcset);
+ aCrossOrigin.ToString(mCrossOrigin);
+ aMedia.ToString(mMedia);
+ nsString
+ referrerPolicy; // Not Auto, because using it to hold nsStringBuffer*
+ aReferrerPolicy.ToString(referrerPolicy);
+ mReferrerPolicyOrIntegrity.Assign(
+ nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
+ referrerPolicy));
+ aIntegrity.ToString(
+ mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity);
+ mIsLinkPreload = aLinkPreload;
+ }
+
+ /**
+ * "Speculative" manifest loads aren't truly speculative--if a manifest
+ * gets loaded, we are committed to it. There can never be a <script>
+ * before the manifest, so the situation of having to undo a manifest due
+ * to document.write() never arises. The reason why a parser
+ * thread-discovered manifest gets loaded via the speculative load queue
+ * as opposed to tree operation queue is that the manifest must get
+ * processed before any actual speculative loads such as scripts. Thus,
+ * manifests seen by the parser thread have to maintain the queue order
+ * relative to true speculative loads. See bug 541079.
+ */
+ inline void InitManifest(nsHtml5String aUrl) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadManifest;
+ aUrl.ToString(mUrlOrSizes);
+ }
+
+ /**
+ * We communicate the encoding change via the speculative operation
+ * queue in order to act upon it as soon as possible and so as not to
+ * have speculative loads generated after an encoding change fail to
+ * make use of the encoding change.
+ */
+ inline void InitSetDocumentCharset(NotNull<const Encoding*> aEncoding,
+ int32_t aCharsetSource,
+ bool aCommitEncodingSpeculation) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadSetDocumentCharset;
+ mCharsetOrSrcset.~nsString();
+ mEncoding = aEncoding;
+ mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Assign(
+ (char16_t)aCharsetSource);
+ mCommitEncodingSpeculation = aCommitEncodingSpeculation;
+ }
+
+ inline void InitMaybeComplainAboutCharset(const char* aMsgId, bool aError,
+ int32_t aLineNumber) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadMaybeComplainAboutCharset;
+ mCharsetOrSrcset.~nsString();
+ mMsgId = aMsgId;
+ mIsError = aError;
+ // Transport a 32-bit integer as two 16-bit code units of a string
+ // in order to avoid adding an integer field to the object.
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=1733043 for a better
+ // eventual approach.
+ char16_t high = (char16_t)(((uint32_t)aLineNumber) >> 16);
+ char16_t low = (char16_t)(((uint32_t)aLineNumber) & 0xFFFF);
+ mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Assign(high);
+ mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Append(low);
+ }
+
+ /**
+ * Speculative document mode setting isn't really speculative. Once it
+ * happens, we are committed to it. However, this information needs to
+ * travel in the speculation queue in order to have this information
+ * available before parsing the speculatively loaded style sheets.
+ */
+ inline void InitSetDocumentMode(nsHtml5DocumentMode aMode) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadSetDocumentMode;
+ mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Assign(
+ (char16_t)aMode);
+ }
+
+ inline void InitPreconnect(nsHtml5String aUrl, nsHtml5String aCrossOrigin) {
+ MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadPreconnect;
+ aUrl.ToString(mUrlOrSizes);
+ aCrossOrigin.ToString(mCrossOrigin);
+ }
+
+ void Perform(nsHtml5TreeOpExecutor* aExecutor);
+
+ private:
+ nsHtml5SpeculativeLoad(const nsHtml5SpeculativeLoad&) = delete;
+ nsHtml5SpeculativeLoad& operator=(const nsHtml5SpeculativeLoad&) = delete;
+
+ eHtml5SpeculativeLoad mOpCode;
+
+ /**
+ * Whether the refering element has async attribute.
+ */
+ bool mIsAsync;
+
+ /**
+ * Whether the refering element has defer attribute.
+ */
+ bool mIsDefer;
+
+ /**
+ * True if and only if this is a speculative load initiated by <link
+ * rel="preload"> or <link rel="modulepreload"> tag encounter. Passed to the
+ * handling loader as an indication to raise the priority.
+ */
+ bool mIsLinkPreload;
+
+ /**
+ * Whether the charset complaint is an error.
+ */
+ bool mIsError;
+
+ /**
+ * Whether setting document encoding involves also committing to an encoding
+ * speculation.
+ */
+ bool mCommitEncodingSpeculation;
+
+ /* If mOpCode is eSpeculativeLoadPictureSource, this is the value of the
+ * "sizes" attribute. If the attribute is not set, this will be a void
+ * string. Otherwise it empty or the value of the url.
+ */
+ nsString mUrlOrSizes;
+ /**
+ * If mOpCode is eSpeculativeLoadScript[FromHead], this is the value of the
+ * "integrity" attribute. If the attribute is not set, this will be a void
+ * string. Otherwise it is empty or the value of the referrer policy.
+ */
+ nsString mReferrerPolicyOrIntegrity;
+ /**
+ * If mOpCode is eSpeculativeLoadStyle or eSpeculativeLoadScript[FromHead]
+ * then this is the value of the "charset" attribute. For
+ * eSpeculativeLoadSetDocumentCharset it is the charset that the
+ * document's charset is being set to. If mOpCode is eSpeculativeLoadImage
+ * or eSpeculativeLoadPictureSource, this is the value of the "srcset"
+ * attribute. If the attribute is not set, this will be a void string.
+ * Otherwise it's empty.
+ * For eSpeculativeLoadMaybeComplainAboutCharset mMsgId is used.
+ */
+ union {
+ nsString mCharsetOrSrcset;
+ const Encoding* mEncoding;
+ const char* mMsgId;
+ };
+ /**
+ * If mOpCode is eSpeculativeLoadSetDocumentCharset, this is a
+ * one-character string whose single character's code point is to be
+ * interpreted as a charset source integer. If mOpCode is
+ * eSpeculativeLoadSetDocumentMode, this is a one-character string whose
+ * single character's code point is to be interpreted as an
+ * nsHtml5DocumentMode. If mOpCode is eSpeculativeLoadCSP, this is a meta
+ * element's CSP value. If mOpCode is eSpeculativeLoadImage, this is the
+ * value of the "sizes" attribute. If the attribute is not set, this will
+ * be a void string. If mOpCode is eSpeculativeLoadStyle, this
+ * is the value of the "integrity" attribute. If the attribute is not set,
+ * this will be a void string. Otherwise, it is empty or the value of the type
+ * attribute.
+ */
+ nsString mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity;
+ /**
+ * If mOpCode is eSpeculativeLoadImage or eSpeculativeLoadScript[FromHead]
+ * or eSpeculativeLoadPreconnect or eSpeculativeLoadStyle this is the value of
+ * the "crossorigin" attribute. If the attribute is not set, this will be a
+ * void string.
+ */
+ nsString mCrossOrigin;
+ /**
+ * If mOpCode is eSpeculativeLoadPictureSource or eSpeculativeLoadStyle or
+ * Fetch or Image or Media or Script this is the value of the relevant "media"
+ * attribute of the <link rel="preload"> or <link rel="stylesheet">. If the
+ * attribute is not set, or the preload didn't originate from a <link>, this
+ * will be a void string.
+ */
+ nsString mMedia;
+ /**
+ * If mOpCode is eSpeculativeLoadScript[FromHead] this represents the value
+ * of the "referrerpolicy" attribute. This field holds one of the values
+ * (REFERRER_POLICY_*) defined in nsIHttpChannel.
+ */
+ mozilla::dom::ReferrerPolicy mScriptReferrerPolicy;
+
+ mozilla::TimeStamp mInitTimestamp;
+};
+
+#endif // nsHtml5SpeculativeLoad_h