Skip to content

Commit

Permalink
Bug 1839954 - support async defer and module scripts r=emilio
Browse files Browse the repository at this point in the history
https://www.w3.org/2012/01/05-svg-irc#T21-07-03 says that async and defer should be supported as does the specification https://www.w3.org/TR/SVG2/interact.html#ScriptElement

w3c/svgwg#918 tracks getting the SVGScriptElement webidl updated.

Differential Revision: https://phabricator.services.mozilla.com/D181936
  • Loading branch information
longsonr committed Jul 6, 2023
1 parent 5f94d39 commit 14b255f
Show file tree
Hide file tree
Showing 15 changed files with 160 additions and 41 deletions.
4 changes: 2 additions & 2 deletions dom/base/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18114,12 +18114,12 @@ void Document::RecordNavigationTiming(ReadyState aReadyState) {
}
}

bool Document::ModuleScriptsEnabled() {
bool Document::ModuleScriptsEnabled() const {
return nsContentUtils::IsChromeDoc(this) ||
StaticPrefs::dom_moduleScripts_enabled();
}

bool Document::ImportMapsEnabled() {
bool Document::ImportMapsEnabled() const {
return nsContentUtils::IsChromeDoc(this) ||
StaticPrefs::dom_importMaps_enabled();
}
Expand Down
4 changes: 2 additions & 2 deletions dom/base/Document.h
Original file line number Diff line number Diff line change
Expand Up @@ -4029,9 +4029,9 @@ class Document : public nsINode,

mozilla::dom::FeaturePolicy* FeaturePolicy() const;

bool ModuleScriptsEnabled();
bool ModuleScriptsEnabled() const;

bool ImportMapsEnabled();
bool ImportMapsEnabled() const;

/**
* Find the (non-anonymous) content in this document for aFrame. It will
Expand Down
24 changes: 2 additions & 22 deletions dom/html/HTMLScriptElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,33 +150,13 @@ void HTMLScriptElement::GetScriptCharset(nsAString& charset) {
GetCharset(charset);
}

void HTMLScriptElement::FreezeExecutionAttrs(Document* aOwnerDoc) {
void HTMLScriptElement::FreezeExecutionAttrs(const Document* aOwnerDoc) {
if (mFrozen) {
return;
}

MOZ_ASSERT((mKind != ScriptKind::eModule) &&
(mKind != ScriptKind::eImportMap) && !mAsync && !mDefer &&
!mExternal);

// Determine whether this is a(n) classic/module/importmap script.
nsAutoString type;
GetScriptType(type);
if (!type.IsEmpty()) {
if (aOwnerDoc->ModuleScriptsEnabled() &&
type.LowerCaseEqualsASCII("module")) {
mKind = ScriptKind::eModule;
}

// https://html.spec.whatwg.org/multipage/scripting.html#prepare-the-script-element
// Step 11. Otherwise, if the script block's type string is an ASCII
// case-insensitive match for the string "importmap", then set el's type to
// "importmap".
if (aOwnerDoc->ImportMapsEnabled() &&
type.LowerCaseEqualsASCII("importmap")) {
mKind = ScriptKind::eImportMap;
}
}
DetermineKindFromType(aOwnerDoc);

// variation of this code in SVGScriptElement - check if changes
// need to be transfered when modifying. Note that we don't use GetSrc here
Expand Down
2 changes: 1 addition & 1 deletion dom/html/HTMLScriptElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class HTMLScriptElement final : public nsGenericHTMLElement,
// nsIScriptElement
virtual void GetScriptText(nsAString& text) const override;
virtual void GetScriptCharset(nsAString& charset) override;
virtual void FreezeExecutionAttrs(Document* aOwnerDoc) override;
virtual void FreezeExecutionAttrs(const Document* aOwnerDoc) override;
virtual CORSMode GetCORSMode() const override;
virtual mozilla::dom::ReferrerPolicy GetReferrerPolicy() override;

Expand Down
29 changes: 29 additions & 0 deletions dom/script/nsIScriptElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@

#include "nsIScriptElement.h"

#include "mozilla/dom/Document.h"
#include "mozilla/dom/ReferrerPolicyBinding.h"
#include "nsIParser.h"
#include "nsIWeakReference.h"

using JS::loader::ScriptKind;

void nsIScriptElement::SetCreatorParser(nsIParser* aParser) {
mCreatorParser = do_GetWeakReference(aParser);
}
Expand Down Expand Up @@ -51,3 +54,29 @@ already_AddRefed<nsIParser> nsIScriptElement::GetCreatorParser() {
mozilla::dom::ReferrerPolicy nsIScriptElement::GetReferrerPolicy() {
return mozilla::dom::ReferrerPolicy::_empty;
}

void nsIScriptElement::DetermineKindFromType(
const mozilla::dom::Document* aOwnerDoc) {
MOZ_ASSERT((mKind != ScriptKind::eModule) &&
(mKind != ScriptKind::eImportMap) && !mAsync && !mDefer &&
!mExternal);

nsAutoString type;
GetScriptType(type);

if (!type.IsEmpty()) {
if (aOwnerDoc->ModuleScriptsEnabled() &&
type.LowerCaseEqualsASCII("module")) {
mKind = ScriptKind::eModule;
}

// https://html.spec.whatwg.org/multipage/scripting.html#prepare-the-script-element
// Step 11. Otherwise, if the script block's type string is an ASCII
// case-insensitive match for the string "importmap", then set el's type to
// "importmap".
if (aOwnerDoc->ImportMapsEnabled() &&
type.LowerCaseEqualsASCII("importmap")) {
mKind = ScriptKind::eImportMap;
}
}
}
15 changes: 10 additions & 5 deletions dom/script/nsIScriptElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,34 +106,34 @@ class nsIScriptElement : public nsIScriptLoaderObserver {
* - GetScriptURI()
* - GetScriptExternal()
*/
virtual void FreezeExecutionAttrs(mozilla::dom::Document*) = 0;
virtual void FreezeExecutionAttrs(const mozilla::dom::Document*) = 0;

/**
* Is the script a module script. Currently only supported by HTML scripts.
* Is the script a module script.
*/
bool GetScriptIsModule() {
MOZ_ASSERT(mFrozen, "Not ready for this call yet!");
return mKind == JS::loader::ScriptKind::eModule;
}

/**
* Is the script an import map. Currently only supported by HTML scripts.
* Is the script an import map.
*/
bool GetScriptIsImportMap() {
MOZ_ASSERT(mFrozen, "Not ready for this call yet!");
return mKind == JS::loader::ScriptKind::eImportMap;
}

/**
* Is the script deferred. Currently only supported by HTML scripts.
* Is the script deferred.
*/
bool GetScriptDeferred() {
MOZ_ASSERT(mFrozen, "Not ready for this call yet!");
return mDefer;
}

/**
* Is the script async. Currently only supported by HTML scripts.
* Is the script async.
*/
bool GetScriptAsync() {
MOZ_ASSERT(mFrozen, "Not ready for this call yet!");
Expand Down Expand Up @@ -276,6 +276,11 @@ class nsIScriptElement : public nsIScriptLoaderObserver {
*/
virtual nsIContent* GetAsContent() = 0;

/**
* Determine whether this is a(n) classic/module/importmap script.
*/
void DetermineKindFromType(const mozilla::dom::Document* aOwnerDoc);

/**
* The start line number of the script.
*/
Expand Down
13 changes: 12 additions & 1 deletion dom/svg/SVGScriptElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

NS_IMPL_NS_NEW_SVG_ELEMENT_CHECK_PARSER(Script)

using JS::loader::ScriptKind;

namespace mozilla::dom {

JSObject* SVGScriptElement::WrapNode(JSContext* aCx,
Expand Down Expand Up @@ -106,11 +108,14 @@ void SVGScriptElement::GetScriptCharset(nsAString& charset) {
charset.Truncate();
}

void SVGScriptElement::FreezeExecutionAttrs(Document* aOwnerDoc) {
void SVGScriptElement::FreezeExecutionAttrs(const Document* aOwnerDoc) {
if (mFrozen) {
return;
}

// Determine whether this is a(n) classic/module/importmap script.
DetermineKindFromType(aOwnerDoc);

if (mStringAttributes[HREF].IsExplicitlySet() ||
mStringAttributes[XLINK_HREF].IsExplicitlySet()) {
// variation of this code in nsHTMLScriptElement - check if changes
Expand Down Expand Up @@ -150,6 +155,12 @@ void SVGScriptElement::FreezeExecutionAttrs(Document* aOwnerDoc) {
mExternal = true;
}

bool async = (mExternal || mKind == ScriptKind::eModule) && Async();
bool defer = mExternal && Defer();

mDefer = !async && defer;
mAsync = async;

mFrozen = true;
}

Expand Down
9 changes: 8 additions & 1 deletion dom/svg/SVGScriptElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class SVGScriptElement final : public SVGScriptElementBase,
// nsIScriptElement
void GetScriptText(nsAString& text) const override;
void GetScriptCharset(nsAString& charset) override;
void FreezeExecutionAttrs(Document* aOwnerDoc) override;
void FreezeExecutionAttrs(const Document* aOwnerDoc) override;
CORSMode GetCORSMode() const override;

// ScriptElement
Expand All @@ -59,6 +59,13 @@ class SVGScriptElement final : public SVGScriptElementBase,
// WebIDL
void GetType(nsAString& aType);
void SetType(const nsAString& aType, ErrorResult& rv);
bool Async() { return mForceAsync || GetBoolAttr(nsGkAtoms::async); }
void SetAsync(bool aValue) {
mForceAsync = false;
SetBoolAttr(nsGkAtoms::async, aValue);
}
bool Defer() { return GetBoolAttr(nsGkAtoms::defer); }
void SetDefer(bool aDefer) { SetBoolAttr(nsGkAtoms::defer, aDefer); }
void GetCrossOrigin(nsAString& aCrossOrigin);
void SetCrossOrigin(const nsAString& aCrossOrigin, ErrorResult& aError);
already_AddRefed<DOMSVGAnimatedString> Href();
Expand Down
5 changes: 3 additions & 2 deletions dom/webidl/SVGScriptElement.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
interface SVGScriptElement : SVGElement {
[SetterThrows]
attribute DOMString type;

// CORS attribute
// See https://github.com/w3c/svgwg/issues/918
attribute boolean async;
attribute boolean defer;
[SetterThrows]
attribute DOMString? crossOrigin;
};
Expand Down

This file was deleted.

29 changes: 29 additions & 0 deletions testing/web-platform/tests/svg/interact/scripted/async-01.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions testing/web-platform/tests/svg/interact/scripted/defer-01.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions testing/web-platform/tests/svg/interact/scripted/defer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
t.step(() => {
assert_equals(script_run_status, "deferred", "script run status");
});
t.done();
13 changes: 13 additions & 0 deletions testing/web-platform/tests/svg/interact/scripted/log.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import time

def main(request, response):
response.headers.append(b"Content-Type", b"text/javascript")
try:
script_id = int(request.GET.first(b"id"))
delay = int(request.GET.first(b"sec"))
except:
response.set_error(400, u"Invalid parameter")

time.sleep(int(delay))

return u"log('%s')" % script_id
20 changes: 20 additions & 0 deletions testing/web-platform/tests/svg/interact/scripted/module-01.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 14b255f

Please sign in to comment.