Bug 1596458 part 2. Fix the innerHTML setter for shadow DOM cases in XML to supply the right context. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D53077

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Boris Zbarsky 2019-11-15 12:45:40 +00:00
Родитель 39eb418bd8
Коммит e9cfb6db8e
3 изменённых файлов: 91 добавлений и 8 удалений

Просмотреть файл

@ -1961,16 +1961,17 @@ void FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML,
nsAutoScriptLoaderDisabler sld(doc);
nsAtom* contextLocalName = NodeInfo()->NameAtom();
int32_t contextNameSpaceID = GetNameSpaceID();
FragmentOrElement* parseContext = this;
if (ShadowRoot* shadowRoot = ShadowRoot::FromNode(this)) {
// Fix up the context to be the host of the ShadowRoot.
contextLocalName = shadowRoot->GetHost()->NodeInfo()->NameAtom();
contextNameSpaceID = shadowRoot->GetHost()->GetNameSpaceID();
// Fix up the context to be the host of the ShadowRoot. See
// https://w3c.github.io/DOM-Parsing/#dom-innerhtml-innerhtml setter step 1.
parseContext = shadowRoot->GetHost();
}
if (doc->IsHTMLDocument()) {
nsAtom* contextLocalName = parseContext->NodeInfo()->NameAtom();
int32_t contextNameSpaceID = parseContext->GetNameSpaceID();
int32_t oldChildCount = target->GetChildCount();
aError = nsContentUtils::ParseFragmentHTML(
aInnerHTML, target, contextLocalName, contextNameSpaceID,
@ -1981,14 +1982,14 @@ void FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML,
oldChildCount);
} else {
RefPtr<DocumentFragment> df = nsContentUtils::CreateContextualFragment(
target, aInnerHTML, true, aError);
parseContext, aInnerHTML, true, aError);
if (!aError.Failed()) {
// Suppress assertion about node removal mutation events that can't have
// listeners anyway, because no one has had the chance to register
// mutation listeners on the fragment that comes from the parser.
nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
static_cast<nsINode*>(target)->AppendChild(*df, aError);
target->AppendChild(*df, aError);
mb.NodesAdded();
}
}

Просмотреть файл

@ -26,6 +26,7 @@ interface ShadowRoot : DocumentFragment
Element? getElementById(DOMString elementId);
// https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin
[CEReactions, SetterThrows]
attribute [TreatNullAs=EmptyString] DOMString innerHTML;

Просмотреть файл

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:bar="bar">
<head>
<title>Test for Shadow DOM innerHTML setter in XML</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
<![CDATA[
// We define our custom elements lazily so we don't mess
// with the DOM during parsing.
customElements.define("custom-el-1",
class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
try { this.shadowRoot.innerHTML = "<span/>"; } catch (e) {}
}
});
function defineElements() {
// We define our custom elements whose behavior involves
// ancestors of our parent lazily, because otherwise the
// constructor runs before the element is in the DOM and has
// the ancestors set up.
customElements.define("custom-el-2",
class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
try { this.shadowRoot.innerHTML = "<span/>"; } catch (e) {}
}
});
customElements.define("custom-el-with-prefix",
class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
try {
this.shadowRoot.innerHTML = "<bar:span/>";
} catch (e) {
// Test will fail due to us not having the kid
}
}
});
}
]]>
</script>
</head>
<body>
<custom-el-1 id="htmlDefault"/>
<span xmlns="foo" xmlns:html="http://www.w3.org/1999/xhtml">
<html:custom-el-2 id="fooDefault"/>
</span>
<custom-el-with-prefix id="prefixTest"/>
<script>
<![CDATA[
const htmlNS = "http://www.w3.org/1999/xhtml";
test(() => {
var el = document.getElementById("htmlDefault");
var kid = el.shadowRoot.firstChild;
assert_equals(kid.namespaceURI, htmlNS,
"Kid's namespace should be our default");
}, "InnerHTML behavior on custom element in default XHTML namespace");
test(defineElements, "Setting up the custom elements");
test(() => {
var el = document.getElementById("fooDefault");
var kid = el.shadowRoot.firstChild;
assert_equals(kid.namespaceURI, "foo",
"Kid's namespace should be our default");
}, "InnerHTML behavior on custom element in default 'foo' namespace");
test(() => {
var el = document.getElementById("prefixTest");
var kid = el.shadowRoot.firstChild;
assert_equals(kid.namespaceURI, "bar",
"Kid's namespace should be based on ancestor prefix");
}, "InnerHTML behavior with prefixes on custom element");
]]>
</script>
</body>
</html>