Issue #1375 - Fix IsWebComponentsEnabled checks

This commit is contained in:
Matt A. Tobin 2020-04-17 07:43:40 -04:00 • committed by Roy Tam
commit ca48752304
13 changed files with 154 additions and 137 deletions

View file

@ -2242,6 +2242,29 @@ WarnIfSandboxIneffective(nsIDocShell* aDocShell,
} }
} }
bool
nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
{
if (!nsContentUtils::IsWebComponentsEnabled()) {
return false;
}
JS::Rooted<JSObject*> obj(aCx, aObject);
JSAutoCompartment ac(aCx, obj);
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
if (doc && doc->IsStyledByServo()) {
NS_WARNING("stylo: Web Components not supported yet");
return false;
}
return true;
}
nsresult nsresult
nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel, nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
nsILoadGroup* aLoadGroup, nsILoadGroup* aLoadGroup,
@ -5581,65 +5604,12 @@ nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI,
return attribute.forget(); return attribute.forget();
} }
bool
nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
{
JS::Rooted<JSObject*> obj(aCx, aObject);
if (nsContentUtils::IsWebComponentsEnabled()) {
return true;
}
// Check for the webcomponents permission. See Bug 1181555.
JSAutoCompartment ac(aCx, obj);
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
return IsWebComponentsEnabled(window);
}
bool bool
nsDocument::IsWebComponentsEnabled(const nsINode* aNode) nsDocument::IsWebComponentsEnabled(const nsINode* aNode)
{ {
return aNode->OwnerDoc()->IsWebComponentsEnabled(); return aNode->OwnerDoc()->IsWebComponentsEnabled();
} }
bool
nsDocument::IsWebComponentsEnabled(dom::NodeInfo* aNodeInfo)
{
if (nsContentUtils::IsWebComponentsEnabled()) {
return true;
}
nsIDocument* doc = aNodeInfo->GetDocument();
// Use GetScopeObject() here so that data documents work the same way as the
// main document they're associated with.
nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(doc->GetScopeObject());
return IsWebComponentsEnabled(window);
}
bool
nsDocument::IsWebComponentsEnabled(nsPIDOMWindowInner* aWindow)
{
if (aWindow) {
nsresult rv;
nsCOMPtr<nsIPermissionManager> permMgr =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, false);
uint32_t perm;
rv = permMgr->TestPermissionFromWindow(
aWindow, "moz-extremely-unstable-and-will-change-webcomponents", &perm);
NS_ENSURE_SUCCESS(rv, false);
return perm == nsIPermissionManager::ALLOW_ACTION;
}
return false;
}
NS_IMETHODIMP NS_IMETHODIMP
nsDocument::GetElementsByTagName(const nsAString& aTagname, nsDocument::GetElementsByTagName(const nsAString& aTagname,
nsIDOMNodeList** aReturn) nsIDOMNodeList** aReturn)

View file

@ -755,6 +755,11 @@ public:
virtual void NotifyLayerManagerRecreated() override; virtual void NotifyLayerManagerRecreated() override;
// Check whether web components are enabled for the global of aObject.
static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
// Check whether web components are enabled for the document this node belongs
// to.
static bool IsWebComponentsEnabled(const nsINode* aNode);
private: private:
void AddOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet); void AddOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet);
nsRadioGroupStruct* GetRadioGroupInternal(const nsAString& aName) const; nsRadioGroupStruct* GetRadioGroupInternal(const nsAString& aName) const;
@ -1341,17 +1346,6 @@ protected:
nsWeakPtr mFullscreenRoot; nsWeakPtr mFullscreenRoot;
public: public:
// Check whether web components are enabled for the global of aObject.
static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
// Check whether web components are enabled for the document this node belongs
// to.
static bool IsWebComponentsEnabled(const nsINode* aNode);
// Check whether web components are enabled for the global of the document
// this nodeinfo comes from.
static bool IsWebComponentsEnabled(mozilla::dom::NodeInfo* aNodeInfo);
// Check whether web components are enabled for the given window.
static bool IsWebComponentsEnabled(nsPIDOMWindowInner* aWindow);
RefPtr<mozilla::EventListenerManager> mListenerManager; RefPtr<mozilla::EventListenerManager> mListenerManager;
RefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList; RefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
RefPtr<nsScriptLoader> mScriptLoader; RefPtr<nsScriptLoader> mScriptLoader;

View file

@ -236,17 +236,17 @@ dictionary ShadowRootInit {
// https://dom.spec.whatwg.org/#element // https://dom.spec.whatwg.org/#element
partial interface Element { partial interface Element {
// Shadow DOM v1 // Shadow DOM v1
[Throws, Pref="nsDocument::IsWebComponentsEnabled"] [Throws, Func="nsDocument::IsWebComponentsEnabled"]
ShadowRoot attachShadow(ShadowRootInit shadowRootInitDict); ShadowRoot attachShadow(ShadowRootInit shadowRootInitDict);
[BinaryName="shadowRootByMode", Func="nsDocument::IsWebComponentsEnabled"] [BinaryName="shadowRootByMode", Func="nsDocument::IsWebComponentsEnabled"]
readonly attribute ShadowRoot? shadowRoot; readonly attribute ShadowRoot? shadowRoot;
[BinaryName="assignedSlotByMode", Pref="nsDocument::IsWebComponentsEnabled"] [BinaryName="assignedSlotByMode", Func="nsDocument::IsWebComponentsEnabled"]
readonly attribute HTMLSlotElement? assignedSlot; readonly attribute HTMLSlotElement? assignedSlot;
[CEReactions, Unscopable, SetterThrows, Pref="nsDocument::IsWebComponentsEnabled"] [CEReactions, Unscopable, SetterThrows, Func="nsDocument::IsWebComponentsEnabled"]
attribute DOMString slot; attribute DOMString slot;
// [deprecated] Shadow DOM v0 // [deprecated] Shadow DOM v0
[Throws, Pref="nsDocument::IsWebComponentsEnabled"] [Throws, Func="nsDocument::IsWebComponentsEnabled"]
ShadowRoot createShadowRoot(); ShadowRoot createShadowRoot();
}; };

View file

@ -7,15 +7,17 @@
<script> <script>
function insertShadowSVG() { function insertShadowSVG() {
var x = document.getElementById("x"); var x = document.getElementById("x");
x.createShadowRoot(); if (x.createShadowRoot) {
x.shadowRoot.innerHTML = x.createShadowRoot();
'<svg width="50px" height="10px"> \ x.shadowRoot.innerHTML =
<switch> \ '<svg width="50px" height="10px"> \
<foreignObject width="50px" height="50px"> \ <switch> \
<div style="width: 100px; height: 10px; background: red;"></div> \ <foreignObject width="50px" height="50px"> \
</foreignObject> \ <div style="width: 100px; height: 10px; background: red;"></div> \
</switch> \ </foreignObject> \
</svg>'; </switch> \
</svg>';
}
document.documentElement.removeAttribute("class"); document.documentElement.removeAttribute("class");
} }
window.addEventListener("MozReftestInvalidate", insertShadowSVG, false); window.addEventListener("MozReftestInvalidate", insertShadowSVG, false);

View file

@ -1851,7 +1851,7 @@ test-pref(layout.css.grid.enabled,true) == 1053035-1-grid.html 1053035-1-ref.htm
== 1062108-1.html 1062108-1-ref.html == 1062108-1.html 1062108-1-ref.html
== 1062792-1.html 1062792-1-ref.html == 1062792-1.html 1062792-1-ref.html
== 1062963-floatmanager-reflow.html 1062963-floatmanager-reflow-ref.html == 1062963-floatmanager-reflow.html 1062963-floatmanager-reflow-ref.html
test-pref(dom.webcomponents.enabled,true) == 1066554-1.html 1066554-1-ref.html test-pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == 1066554-1.html 1066554-1-ref.html
== 1069716-1.html 1069716-1-ref.html == 1069716-1.html 1069716-1-ref.html
== 1078262-1.html about:blank == 1078262-1.html about:blank
test-pref(layout.testing.overlay-scrollbars.always-visible,false) == 1081072-1.html 1081072-1-ref.html test-pref(layout.testing.overlay-scrollbars.always-visible,false) == 1081072-1.html 1081072-1-ref.html

View file

@ -74,36 +74,40 @@ div.after::after {content: " Y";}
return e; return e;
} }
document.body.offsetHeight; function run() {
document.body.offsetHeight;
shadow("host1").innerHTML = '<content></content> c'; shadow("host1").innerHTML = '<content></content> c';
shadow("host2").innerHTML = 'a <content style="display:contents"></content> c'; shadow("host2").innerHTML = 'a <content style="display:contents"></content> c';
shadow("host3").innerHTML = 'a <content style="display:contents"></content>'; shadow("host3").innerHTML = 'a <content style="display:contents"></content>';
shadow("host4").innerHTML = '<content style="display:contents"></content>'; shadow("host4").innerHTML = '<content style="display:contents"></content>';
shadow("host5").innerHTML = 'a <content style="display:contents"></content>'; shadow("host5").innerHTML = 'a <content style="display:contents"></content>';
shadow("host6").innerHTML = '<z style="color:blue; display:contents"><content></content></z> c'; shadow("host6").innerHTML = '<z style="color:blue; display:contents"><content></content></z> c';
shadow("host7").innerHTML = 'a <content style="display:contents"></content> c'; shadow("host7").innerHTML = 'a <content style="display:contents"></content> c';
shadow("host8").innerHTML = 'a <z style="color:blue; display:contents"><content style="display:contents"></z></content>'; shadow("host8").innerHTML = 'a <z style="color:blue; display:contents"><content style="display:contents"></z></content>';
shadow("host9").innerHTML = '<content style="display:contents"></content>'; shadow("host9").innerHTML = '<content style="display:contents"></content>';
shadow("hostA").innerHTML = 'a <content style="display:contents"></content>'; shadow("hostA").innerHTML = 'a <content style="display:contents"></content>';
shadow("hostB").innerHTML = 'a <content select=".c"></content> <content select=".b"></content> B'; shadow("hostB").innerHTML = 'a <content select=".c"></content> <content select=".b"></content> B';
shadow("hostC").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B'; shadow("hostC").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B';
shadow("hostD").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B <content select=".b"></content>'; shadow("hostD").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B <content select=".b"></content>';
shadow("hostE").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B'; shadow("hostE").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B';
shadow("hostF").innerHTML = '<content select=".c"></content> <content select=".b"></content> B'; shadow("hostF").innerHTML = '<content select=".c"></content> <content select=".b"></content> B';
shadow("hostG").innerHTML = '<content select=".b"></content>'; shadow("hostG").innerHTML = '<content select=".b"></content>';
shadow("hostH").innerHTML = '<content select=".b"></content>'; shadow("hostH").innerHTML = '<content select=".b"></content>';
shadow("hostI").innerHTML = 'A<content select=".b"></content>'; shadow("hostI").innerHTML = 'A<content select=".b"></content>';
shadow("hostJ").innerHTML = 'A<content select=".b"></content>'; shadow("hostJ").innerHTML = 'A<content select=".b"></content>';
shadow("hostK").innerHTML = '<content select=".b"></content>'; shadow("hostK").innerHTML = '<content select=".b"></content>';
shadow("hostL").innerHTML = '<content select=".b"></content>'; shadow("hostL").innerHTML = '<content select=".b"></content>';
shadow("hostM").innerHTML = '<content select="b"></content><content select="i"></content>'; shadow("hostM").innerHTML = '<content select="b"></content><content select="i"></content>';
shadow("hostN").innerHTML = '<content select="b"></content><content select="i"></content>'; shadow("hostN").innerHTML = '<content select="b"></content><content select="i"></content>';
shadow("hostO").innerHTML = '<content select="b"></content><content select="i"></content>'; shadow("hostO").innerHTML = '<content select="b"></content><content select="i"></content>';
shadow("hostP").innerHTML = '<content select="b"></content><content select="i"></content>'; shadow("hostP").innerHTML = '<content select="b"></content><content select="i"></content>';
shadow("hostQ").innerHTML = '<content select="b"></content><content select="i"></content>'; shadow("hostQ").innerHTML = '<content select="b"></content><content select="i"></content>';
shadow("hostR").innerHTML = '<content select="span"></content>'; shadow("hostR").innerHTML = '<content select="span"></content>';
// TODO(bug 1021572?) shadow("hostY").innerHTML = '<content select="b"><style scoped>:scope{color:green}</style></content>'; shadow("hostW").innerHTML = '<z style="color:red"><content select="b"></content></z>';
shadow("hostX").innerHTML = '<z style="color:red"><content select="b"></content></z>';
// TODO(bug 1021572?) shadow("hostY").innerHTML = '<content select="b"><style scoped>:scope{color:green}</style></content>';
}
function tweak() { function tweak() {
document.body.offsetHeight; document.body.offsetHeight;
@ -224,7 +228,12 @@ div.after::after {content: " Y";}
},0); },0);
} }
window.addEventListener("MozReftestInvalidate", tweak, false); if (document.body.createShadowRoot) {
run();
window.addEventListener("MozReftestInvalidate", tweak, false);
} else {
document.documentElement.removeAttribute("class");
}
</script> </script>
</body> </body>
</html> </html>

View file

@ -48,17 +48,19 @@ div.after::after {content: " Y";}
return e; return e;
} }
document.body.offsetHeight; function run() {
document.body.offsetHeight;
shadow("host1").innerHTML = '<content></content> c'; shadow("host1").innerHTML = '<content></content> c';
shadow("host2").innerHTML = 'a <content></content> c'; shadow("host2").innerHTML = 'a <content></content> c';
shadow("host3").innerHTML = 'a <content></content>'; shadow("host3").innerHTML = 'a <content></content>';
shadow("host4").innerHTML = '<content></content>'; shadow("host4").innerHTML = '<content></content>';
shadow("host5").innerHTML = 'a <content></content>'; shadow("host5").innerHTML = 'a <content></content>';
shadow("host6").innerHTML = '<z style="color:blue; display:contents"><content></content></z> c'; shadow("host6").innerHTML = '<z style="color:blue; display:contents"><content></content></z> c';
shadow("host7").innerHTML = 'a <content select=".c"></content> <content select=".b"></content> B'; shadow("host7").innerHTML = 'a <content select=".c"></content> <content select=".b"></content> B';
shadow("host8").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B'; shadow("host8").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B';
shadow("host9").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B <content select=".b"></content>'; shadow("host9").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B <content select=".b"></content>';
}
function tweak() { function tweak() {
document.body.offsetHeight; document.body.offsetHeight;
@ -105,7 +107,12 @@ div.after::after {content: " Y";}
},0); },0);
} }
window.addEventListener("MozReftestInvalidate", tweak, false); if (document.body.createShadowRoot) {
run();
window.addEventListener("MozReftestInvalidate", tweak, false);
} else {
document.documentElement.removeAttribute("class");
}
</script> </script>
</body> </body>
</html> </html>

View file

@ -7,9 +7,11 @@
<script> <script>
function insertShadowMathML() { function insertShadowMathML() {
var x = document.getElementById("x"); var x = document.getElementById("x");
x.createShadowRoot(); if (x.createShadowRoot) {
x.shadowRoot.innerHTML = x.createShadowRoot();
'<math><msup><mi>X</mi><mi>X</mi></msup></math>'; x.shadowRoot.innerHTML =
'<math><msup><mi>X</mi><mi>X</mi></msup></math>';
}
document.documentElement.removeAttribute("class"); document.documentElement.removeAttribute("class");
} }
window.addEventListener("MozReftestInvalidate", insertShadowMathML, false); window.addEventListener("MozReftestInvalidate", insertShadowMathML, false);

View file

@ -3,6 +3,11 @@
<head> <head>
<script> <script>
function tweak() { function tweak() {
if (!document.body.createShadowRoot) {
document.documentElement.className = "";
return;
}
var host = document.getElementById("host"); var host = document.getElementById("host");
var shadow = host.createShadowRoot(); var shadow = host.createShadowRoot();

View file

@ -7,9 +7,11 @@
<script> <script>
var host, root; var host, root;
host = document.getElementById("host"); function run() {
root = host.attachShadow({mode: 'open'}); host = document.getElementById("host");
root.innerHTML = 'a <slot></slot> c'; root = host.createShadowRoot();
root.innerHTML = 'a <content></content> c';
}
function tweak() { function tweak() {
var span = document.createElement("span"); var span = document.createElement("span");
@ -21,7 +23,12 @@
document.documentElement.removeAttribute("class"); document.documentElement.removeAttribute("class");
} }
window.addEventListener("MozReftestInvalidate", tweak); if (document.body.createShadowRoot) {
run();
window.addEventListener("MozReftestInvalidate", tweak, false);
} else {
document.documentElement.className = "";
}
</script> </script>
</body> </body>
</html> </html>

View file

@ -7,9 +7,11 @@
<script> <script>
var host, root; var host, root;
host = document.getElementById("host"); function run() {
root = host.attachShadow({mode: 'open'}); host = document.getElementById("host");
root.innerHTML = "<span>a</span>"; root = host.createShadowRoot();
root.innerHTML = "<span>a</span>";
}
function tweak() { function tweak() {
var span = document.createElement("span"); var span = document.createElement("span");
@ -22,7 +24,12 @@
document.documentElement.removeAttribute("class"); document.documentElement.removeAttribute("class");
} }
window.addEventListener("MozReftestInvalidate", tweak); if (document.body.createShadowRoot) {
run();
window.addEventListener("MozReftestInvalidate", tweak);
} else {
document.documentElement.className = "";
}
</script> </script>
</body> </body>
</html> </html>

View file

@ -7,9 +7,11 @@
<script> <script>
var host, root; var host, root;
host = document.getElementById("host"); function run() {
root = host.attachShadow({mode: 'open'}); host = document.getElementById("host");
root.innerHTML = '<style>input ~ div { background: red; transition: background 100ms; } input:checked ~ div { background: green; }</style><input id="one" type="checkbox"><div style="height: 50px; width: 50px;"></div>'; root = host.createShadowRoot();
root.innerHTML = '<style>input ~ div { background: red; transition: background 100ms; } input:checked ~ div { background: green; }</style><input id="one" type="checkbox"><div style="height: 50px; width: 50px;"></div>';
}
function tweak() { function tweak() {
var el = root.getElementById("one"); var el = root.getElementById("one");
@ -19,7 +21,12 @@
}); });
} }
window.addEventListener("MozReftestInvalidate", tweak); if (document.body.createShadowRoot) {
run();
window.addEventListener("MozReftestInvalidate", tweak);
} else {
document.documentElement.className = "";
}
</script> </script>
</body> </body>
</html> </html>

View file

@ -6,8 +6,10 @@
<div id="outer"><span id="distnode">text</span></div> <div id="outer"><span id="distnode">text</span></div>
<script> <script>
var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'}); function run() {
shadowRoot.innerHTML = '<div><slot></slot></div>'; var shadowRoot = document.getElementById('outer').createShadowRoot();
shadowRoot.innerHTML = '<div><content></content></div>';
}
function tweak() { function tweak() {
var distNode = document.getElementById("distnode"); var distNode = document.getElementById("distnode");
@ -16,7 +18,12 @@
document.documentElement.removeAttribute("class"); document.documentElement.removeAttribute("class");
} }
if (document.body.createShadowRoot) {
run();
window.addEventListener("MozReftestInvalidate", tweak); window.addEventListener("MozReftestInvalidate", tweak);
} else {
document.documentElement.className = "";
}
</script> </script>
</body> </body>
</html> </html>