From 77e8ba7eaf3ca00f25d0507cf17de2f50741f335 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Tue, 25 Aug 2020 07:06:43 +0000 Subject: Issue #618 - Implement async attribute for inline module scripts. (uplift) This commit does several things: - Moves the pref check from ScriptLoader to ns[I]Document so it can be called on the document. - Changes the atrribute freezing function to a better name that takes the document as a parameter. - Sets the proper async/defer attributes on HTML script elements based on keywords and whether they are module scripts or not. --- dom/base/nsDocument.cpp | 13 +++++++++++++ dom/base/nsIDocument.h | 2 ++ dom/html/HTMLScriptElement.cpp | 23 +++++++++++++++-------- dom/html/HTMLScriptElement.h | 2 +- dom/script/ScriptElement.cpp | 4 ++-- dom/script/ScriptLoader.cpp | 33 ++++++++++++--------------------- dom/script/ScriptLoader.h | 2 -- dom/script/nsIScriptElement.h | 29 +++++++++++++++++++++++++---- dom/svg/SVGScriptElement.cpp | 2 +- dom/svg/SVGScriptElement.h | 2 +- parser/html/nsHtml5TreeOperation.cpp | 2 +- 11 files changed, 73 insertions(+), 41 deletions(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index d0634b0f9..de793bfab 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -12745,3 +12745,16 @@ nsIDocument::GetSelection(ErrorResult& aRv) return nsGlobalWindow::Cast(window)->GetSelection(aRv); } + +bool +nsIDocument::ModuleScriptsEnabled() +{ + static bool sEnabledForContent = false; + static bool sCachedPref = false; + if (!sCachedPref) { + sCachedPref = true; + Preferences::AddBoolVarCache(&sEnabledForContent, "dom.moduleScripts.enabled", false); + } + + return nsContentUtils::IsChromeDoc(this) || sEnabledForContent; +} \ No newline at end of file diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index 506acc7e4..29afa5439 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -2872,6 +2872,8 @@ public: virtual void ScheduleIntersectionObserverNotification() = 0; virtual void NotifyIntersectionObservers() = 0; + bool ModuleScriptsEnabled(); + protected: bool GetUseCounter(mozilla::UseCounter aUseCounter) { diff --git a/dom/html/HTMLScriptElement.cpp b/dom/html/HTMLScriptElement.cpp index ddeb925eb..6b0b4be59 100644 --- a/dom/html/HTMLScriptElement.cpp +++ b/dom/html/HTMLScriptElement.cpp @@ -279,12 +279,20 @@ HTMLScriptElement::GetScriptCharset(nsAString& charset) } void -HTMLScriptElement::FreezeUriAsyncDefer() +HTMLScriptElement::FreezeExecutionAttrs(nsIDocument* aOwnerDoc) { if (mFrozen) { return; } + MOZ_ASSERT(!mIsModule && !mAsync && !mDefer && !mExternal); + + // Determine whether this is a classic script or a module script. + nsAutoString type; + GetScriptType(type); + mIsModule = aOwnerDoc->ModuleScriptsEnabled() && + !type.IsEmpty() && type.LowerCaseEqualsASCII("module"); + // variation of this code in nsSVGScriptElement - check if changes // need to be transfered when modifying. Note that we don't use GetSrc here // because it will return the base URL when the attr value is "". @@ -299,14 +307,13 @@ HTMLScriptElement::FreezeUriAsyncDefer() // At this point mUri will be null for invalid URLs. mExternal = true; - - bool defer, async; - GetAsync(&async); - GetDefer(&defer); - - mDefer = !async && defer; - mAsync = async; } + + bool defer, async; + GetAsync(&async); + mAsync = (mExternal || mIsModule) && async; + GetDefer(&defer); + mDefer = mExternal && !async && defer; mFrozen = true; } diff --git a/dom/html/HTMLScriptElement.h b/dom/html/HTMLScriptElement.h index 073cf7faf..ffe9d3fbd 100644 --- a/dom/html/HTMLScriptElement.h +++ b/dom/html/HTMLScriptElement.h @@ -41,7 +41,7 @@ public: virtual bool GetScriptType(nsAString& type) override; virtual void GetScriptText(nsAString& text) override; virtual void GetScriptCharset(nsAString& charset) override; - virtual void FreezeUriAsyncDefer() override; + virtual void FreezeExecutionAttrs(nsIDocument* aOwnerDoc) override; virtual CORSMode GetCORSMode() const override; // nsIContent diff --git a/dom/script/ScriptElement.cpp b/dom/script/ScriptElement.cpp index 9cb239c66..eb20dbf32 100644 --- a/dom/script/ScriptElement.cpp +++ b/dom/script/ScriptElement.cpp @@ -128,11 +128,11 @@ ScriptElement::MaybeProcessScript() return false; } - FreezeUriAsyncDefer(); + nsIDocument* ownerDoc = cont->OwnerDoc(); + FreezeExecutionAttrs(ownerDoc); mAlreadyStarted = true; - nsIDocument* ownerDoc = cont->OwnerDoc(); nsCOMPtr parser = ((nsIScriptElement*) this)->GetCreatorParser(); if (parser) { nsCOMPtr sink = parser->GetContentSink(); diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp index 59c4ecae4..989301b91 100644 --- a/dom/script/ScriptLoader.cpp +++ b/dom/script/ScriptLoader.cpp @@ -390,19 +390,6 @@ ScriptLoader::CheckContentPolicy(nsIDocument* aDocument, return NS_OK; } -bool -ScriptLoader::ModuleScriptsEnabled() -{ - static bool sEnabledForContent = false; - static bool sCachedPref = false; - if (!sCachedPref) { - sCachedPref = true; - Preferences::AddBoolVarCache(&sEnabledForContent, "dom.moduleScripts.enabled", false); - } - - return nsContentUtils::IsChromeDoc(mDocument) || sEnabledForContent; -} - bool ScriptLoader::ModuleMapContainsURL(nsIURI* aURL) const { @@ -1227,14 +1214,12 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) nsCOMPtr scriptContent = do_QueryInterface(aElement); - // Determine whether this is a classic script or a module script. nsAutoString type; bool hasType = aElement->GetScriptType(type); - ScriptKind scriptKind = ScriptKind::Classic; - if (ModuleScriptsEnabled() && - !type.IsEmpty() && type.LowerCaseEqualsASCII("module")) { - scriptKind = ScriptKind::Module; - } + + ScriptKind scriptKind = aElement->GetScriptIsModule() ? + ScriptKind::Module : + ScriptKind::Classic; // Step 13. Check that the script is not an eventhandler if (IsScriptEventHandler(scriptKind, scriptContent)) { @@ -1268,7 +1253,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) // the nomodule attribute will be ignored". // "The nomodule attribute must not be specified on module scripts (and will // be ignored if it is)." - if (ModuleScriptsEnabled() && + if (mDocument->ModuleScriptsEnabled() && scriptKind == ScriptKind::Classic && scriptContent->IsHTMLElement() && scriptContent->HasAttr(kNameSpaceID_None, nsGkAtoms::nomodule)) { @@ -1480,6 +1465,12 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) request->mIsInline = true; request->mLineNo = aElement->GetScriptLineNumber(); + // Only the 'async' attribute is heeded on an inline module script and + // inline classic scripts ignore both these attributes. + MOZ_ASSERT(!aElement->GetScriptDeferred()); + MOZ_ASSERT_IF(!request->IsModuleRequest(), !aElement->GetScriptAsync()); + request->SetScriptMode(false, aElement->GetScriptAsync()); + if (request->IsModuleRequest()) { ModuleLoadRequest* modReq = request->AsModuleRequest(); modReq->mBaseURL = mDocument->GetDocBaseURI(); @@ -2601,7 +2592,7 @@ ScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset, } // TODO: Preload module scripts. - if (ModuleScriptsEnabled() && aType.LowerCaseEqualsASCII("module")) { + if (mDocument->ModuleScriptsEnabled() && aType.LowerCaseEqualsASCII("module")) { return; } diff --git a/dom/script/ScriptLoader.h b/dom/script/ScriptLoader.h index e9b663acd..ed1e6acbc 100644 --- a/dom/script/ScriptLoader.h +++ b/dom/script/ScriptLoader.h @@ -606,8 +606,6 @@ private: JS::SourceBufferHolder GetScriptSource(ScriptLoadRequest* aRequest, nsAutoString& inlineData); - bool ModuleScriptsEnabled(); - void SetModuleFetchStarted(ModuleLoadRequest *aRequest); void SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest *aRequest, nsresult aResult); diff --git a/dom/script/nsIScriptElement.h b/dom/script/nsIScriptElement.h index 470d51c94..e3e1bc49a 100644 --- a/dom/script/nsIScriptElement.h +++ b/dom/script/nsIScriptElement.h @@ -13,6 +13,7 @@ #include "nsIScriptLoaderObserver.h" #include "nsWeakPtr.h" #include "nsIParser.h" +#include "nsIDocument.h" #include "nsContentCreatorFunctions.h" #include "nsIDOMHTMLScriptElement.h" #include "mozilla/CORSMode.h" @@ -37,6 +38,7 @@ public: mForceAsync(aFromParser == mozilla::dom::NOT_FROM_PARSER || aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT), mFrozen(false), + mIsModule(false), mDefer(false), mAsync(false), mExternal(false), @@ -73,11 +75,25 @@ public: virtual void GetScriptCharset(nsAString& charset) = 0; /** - * Freezes the return values of GetScriptDeferred(), GetScriptAsync() and - * GetScriptURI() so that subsequent modifications to the attributes don't - * change execution behavior. + * Freezes the return values of the following methods so that subsequent + * modifications to the attributes don't change execution behavior: + * - GetScriptIsModule() + * - GetScriptDeferred() + * - GetScriptAsync() + * - GetScriptURI() + * - GetScriptExternal() */ - virtual void FreezeUriAsyncDefer() = 0; + virtual void FreezeExecutionAttrs(nsIDocument* aOwnerDoc) = 0; + + /** + * Is the script a module script? + * Currently only supported by HTML scripts. + */ + bool GetScriptIsModule() + { + NS_PRECONDITION(mFrozen, "Execution attributes not yet frozen: Not ready for this call!"); + return mIsModule; + } /** * Is the script deferred. Currently only supported by HTML scripts. @@ -292,6 +308,11 @@ protected: */ bool mFrozen; + /** + * The effective moduleness. + */ + bool mIsModule; + /** * The effective deferredness. */ diff --git a/dom/svg/SVGScriptElement.cpp b/dom/svg/SVGScriptElement.cpp index f2fb3ff5c..1e0647104 100644 --- a/dom/svg/SVGScriptElement.cpp +++ b/dom/svg/SVGScriptElement.cpp @@ -137,7 +137,7 @@ SVGScriptElement::GetScriptCharset(nsAString& charset) } void -SVGScriptElement::FreezeUriAsyncDefer() +SVGScriptElement::FreezeExecutionAttrs(nsIDocument* aOwnerDoc) { if (mFrozen) { return; diff --git a/dom/svg/SVGScriptElement.h b/dom/svg/SVGScriptElement.h index 9f098e047..d89f860fb 100644 --- a/dom/svg/SVGScriptElement.h +++ b/dom/svg/SVGScriptElement.h @@ -44,7 +44,7 @@ public: virtual bool GetScriptType(nsAString& type) override; virtual void GetScriptText(nsAString& text) override; virtual void GetScriptCharset(nsAString& charset) override; - virtual void FreezeUriAsyncDefer() override; + virtual void FreezeExecutionAttrs(nsIDocument* aOwnerDoc) override; virtual CORSMode GetCORSMode() const override; // ScriptElement diff --git a/parser/html/nsHtml5TreeOperation.cpp b/parser/html/nsHtml5TreeOperation.cpp index 3877e01b8..02cb3caac 100644 --- a/parser/html/nsHtml5TreeOperation.cpp +++ b/parser/html/nsHtml5TreeOperation.cpp @@ -833,7 +833,7 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, nsCOMPtr sele = do_QueryInterface(node); NS_ASSERTION(sele, "Node didn't QI to script."); sele->SetScriptLineNumber(mFour.integer); - sele->FreezeUriAsyncDefer(); + sele->FreezeExecutionAttrs(node->OwnerDoc()); return NS_OK; } case eTreeOpSvgLoad: { -- cgit v1.2.3