Adjust getHTML behavior to match recent consensus
This includes two changes: 1. Rename includeShadowRoots to serializableShadowRoots 2. Do not throw an exception if serializableShadowRoots is false but shadowRoots is non-empty. I also added IDL defaults for both parameters to clean up the C++. I also added a test of the use counter for getHTML(). Bug: 41490936 Change-Id: Ieedd81b5165d9652c3a7b68dea4a4fa5fb088560 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5304121 Auto-Submit: Mason Freed <masonf@chromium.org> Commit-Queue: Mason Freed <masonf@chromium.org> Reviewed-by: Di Zhang <dizhangg@chromium.org> Cr-Commit-Position: refs/heads/main@{#1262930}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
0cd121fecf
commit
9ab453c8e7
third_party/blink
renderer
web_tests
editing
pasteboard
external
wpt
shadow-dom
declarative
shadow-dom
@ -1730,22 +1730,16 @@ String ContainerNode::getInnerHTML(const GetInnerHTMLOptions* options) const {
|
||||
String ContainerNode::getHTML(const GetHTMLOptions* options,
|
||||
ExceptionState& exception_state) const {
|
||||
CHECK(RuntimeEnabledFeatures::ElementGetHTMLEnabled());
|
||||
DCHECK(options && options->hasSerializableShadowRoots())
|
||||
<< "Should have IDL default";
|
||||
DCHECK(options->hasShadowRoots()) << "Should have IDL default";
|
||||
DCHECK(IsShadowRoot() || IsElementNode());
|
||||
if (options->hasIncludeShadowRoots() && !options->includeShadowRoots() &&
|
||||
options->hasShadowRoots() && !options->shadowRoots().empty()) {
|
||||
exception_state.ThrowDOMException(
|
||||
DOMExceptionCode::kNotSupportedError,
|
||||
"If includeShadowRoots is false, then shadowRoots must be empty.");
|
||||
return "";
|
||||
}
|
||||
ShadowRootInclusion shadow_root_inclusion{
|
||||
options->hasIncludeShadowRoots() && options->includeShadowRoots()
|
||||
options->serializableShadowRoots()
|
||||
? ShadowRootInclusion::Behavior::kIncludeAllSerializableShadowRoots
|
||||
: ShadowRootInclusion::Behavior::kOnlyProvidedShadowRoots};
|
||||
if (options->hasShadowRoots()) {
|
||||
for (auto& shadow_root : options->shadowRoots()) {
|
||||
shadow_root_inclusion.include_shadow_roots.insert(shadow_root);
|
||||
}
|
||||
for (auto& shadow_root : options->shadowRoots()) {
|
||||
shadow_root_inclusion.include_shadow_roots.insert(shadow_root);
|
||||
}
|
||||
return CreateMarkup(this, kChildrenOnly, kDoNotResolveURLs,
|
||||
shadow_root_inclusion);
|
||||
|
@ -3,6 +3,6 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
dictionary GetHTMLOptions {
|
||||
boolean includeShadowRoots;
|
||||
sequence<ShadowRoot> shadowRoots;
|
||||
boolean serializableShadowRoots = false;
|
||||
sequence<ShadowRoot> shadowRoots = [];
|
||||
};
|
||||
|
@ -46,7 +46,7 @@ function testPaste(originalMarkupOrElement, expected, descr) {
|
||||
nodeDest.focus();
|
||||
assert_true(document.execCommand("SelectAll", false));
|
||||
assert_true(document.execCommand("Paste", false));
|
||||
confirmedMarkup = nodeDest.getInnerHTML({includeShadowRoots: true});
|
||||
confirmedMarkup = nodeDest.getHTML({serializableShadowRoots: true});
|
||||
nodeDest.remove();
|
||||
|
||||
assert_equals(confirmedMarkup, expected);
|
||||
@ -71,10 +71,10 @@ testPaste("<div><b><i><span style=\"font-weight: normal\">plain text<b><i>bold i
|
||||
testPaste("<span>foo</span><template>Hello</template><span>bar</span>", "foobar");
|
||||
// Note that an empty <div> is left in the resulting pasted text, which isn't ideal:
|
||||
testPaste("<span>foo</span><div><template>Hello</template></div><span>bar</span>", "foo<div></div>bar");
|
||||
// Contained shadow DOM is stripped, but content is retained (streaming DSD API, shadowrootmode attribute):
|
||||
testPaste("<span>foo</span><div><template shadowrootmode='open'>Hello</template></div><span>bar</span>", "foo<div>Hello</div>bar");
|
||||
testPaste("<span>foo</span><div><template shadowrootmode='open'><slot></slot>DEF</template>ABC</div><span>bar</span>", "foo<div><slot>ABC</slot>DEF</div>bar");
|
||||
// Make sure non-declarative <template shadowrootmode> doesn't form a shadow root on paste:
|
||||
// Contained shadow DOM is stripped, but content is retained:
|
||||
testPaste("<span>foo</span><div><template shadowrootmode='open' serializable>Hello</template></div><span>bar</span>", "foo<div>Hello</div>bar");
|
||||
testPaste("<span>foo</span><div><template shadowrootmode='open' serializable><slot></slot>DEF</template>ABC</div><span>bar</span>", "foo<div><slot>ABC</slot>DEF</div>bar");
|
||||
// Make sure regular (non-DSD) template doesn't form a shadow root on paste:
|
||||
const nodeWithTemplate = createEditable("<span>foo</span><div>ABC<template>Hello</template></div><span>bar</span>");
|
||||
nodeWithTemplate.querySelector('template').setAttribute('shadowrootmode','open');
|
||||
testPaste(nodeWithTemplate, "foo<div>ABC</div>bar");
|
||||
|
@ -69,29 +69,28 @@ function testElementType(allowsShadowDom, elementType, runGetHTMLOnShadowRoot, d
|
||||
const emptyElement = `<${elementType}></${elementType}>`;
|
||||
if (isOpen) {
|
||||
if (expectedSerializable) {
|
||||
assert_equals(wrapper.getHTML({includeShadowRoots: true}), correctHtml);
|
||||
assert_equals(wrapper.getHTML({serializableShadowRoots: true}), correctHtml);
|
||||
} else {
|
||||
assert_equals(wrapper.getHTML({includeShadowRoots: true}), emptyElement);
|
||||
assert_equals(wrapper.getHTML({serializableShadowRoots: true}), emptyElement);
|
||||
}
|
||||
} else {
|
||||
// Closed shadow roots should not be returned unless shadowRoots specifically contains the shadow root:
|
||||
assert_equals(wrapper.getHTML({includeShadowRoots: true}), emptyElement);
|
||||
assert_equals(wrapper.getHTML({includeShadowRoots: true, shadowRoots: []}), emptyElement);
|
||||
assert_equals(wrapper.getHTML({serializableShadowRoots: true}), emptyElement);
|
||||
assert_equals(wrapper.getHTML({serializableShadowRoots: true, shadowRoots: []}), emptyElement);
|
||||
}
|
||||
// If we provide the shadow root, serialize it, regardless of includeShadowRoots.
|
||||
assert_equals(wrapper.getHTML({includeShadowRoots: true, shadowRoots: [shadowRoot]}),correctHtml);
|
||||
// If we provide the shadow root, serialize it, regardless of serializableShadowRoots.
|
||||
assert_equals(wrapper.getHTML({serializableShadowRoots: true, shadowRoots: [shadowRoot]}),correctHtml);
|
||||
assert_equals(wrapper.getHTML({serializableShadowRoots: false, shadowRoots: [shadowRoot]}),correctHtml);
|
||||
assert_equals(wrapper.getHTML({shadowRoots: [shadowRoot]}),correctHtml);
|
||||
// This should always throw - includeShadowRoots false, but we've provided roots.
|
||||
assert_throws_dom("NotSupportedError",() => wrapper.getHTML({includeShadowRoots: false, shadowRoots: [shadowRoot]}));
|
||||
} else {
|
||||
// For non-shadow hosts, getHTML() should also match .innerHTML
|
||||
assert_equals(wrapper.getHTML({includeShadowRoots: true}),wrapper.innerHTML);
|
||||
assert_equals(wrapper.getHTML({serializableShadowRoots: true}),wrapper.innerHTML);
|
||||
}
|
||||
|
||||
// Either way, make sure getHTML({includeShadowRoots: false}) matches .innerHTML
|
||||
assert_equals(wrapper.getHTML({includeShadowRoots: false}),wrapper.innerHTML,'getHTML() with includeShadowRoots false should return the same as .innerHTML');
|
||||
// ...and that the default for includeShadowRoots is false.
|
||||
assert_equals(wrapper.getHTML(),wrapper.innerHTML,'The default for includeShadowRoots should be false');
|
||||
// Either way, make sure getHTML({serializableShadowRoots: false}) matches .innerHTML
|
||||
assert_equals(wrapper.getHTML({serializableShadowRoots: false}),wrapper.innerHTML,'getHTML() with serializableShadowRoots false should return the same as .innerHTML');
|
||||
// ...and that the default for serializableShadowRoots is false.
|
||||
assert_equals(wrapper.getHTML(),wrapper.innerHTML,'The default for serializableShadowRoots should be false');
|
||||
|
||||
}, `${runGetHTMLOnShadowRoot ? 'ShadowRoot' : 'Element'}.getHTML() on <${elementType}>${allowsShadowDom ? `, with ${declarativeShadowDom ? 'declarative' : 'imperative'} shadow, mode=${mode}, delegatesFocus=${delegatesFocus}, serializable=${serializable}, clonable=${clonable}.` : ''}`);
|
||||
}
|
||||
|
13
third_party/blink/web_tests/shadow-dom/gethtml-use-counter.html
vendored
Normal file
13
third_party/blink/web_tests/shadow-dom/gethtml-use-counter.html
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
test(() => {
|
||||
const kElementGetHTML = 4781; // From web_feature.mojom
|
||||
assert_false(internals.isUseCounted(document, kElementGetHTML));
|
||||
document.body.getHTML({serializableShadowRoots: true});
|
||||
assert_true(internals.isUseCounted(document, kElementGetHTML));
|
||||
}, 'Use of getHTML is use counted.');
|
||||
</script>
|
Reference in New Issue
Block a user