Skip to content

Commit

Permalink
Update declarative Shadow DOM opt-in mechanics
Browse files Browse the repository at this point in the history
The issue thread [1] has had more discussion, after the initial draft
of declarative Shadow DOM opt-in landed [2]. This CL implements those
bits of feedback. In particular:
 - There is no public allowDeclarativeShadowDom state available on
   Document or DocumentFragment.
 - All APIs use call parameters to avoid state, with the exception
   of DOMParser.
 - innerHTML no longer supports Declarative Shadow DOM.
 - A new setInnerHTML() function allows opt-in access to DSD.
 - Several of the more obscure APIs do not have an opt-in for
   declarative Shadow DOM, such as XHR, createContextualFragment, and
   document.write.
 - The sandbox flag has been removed from iframes completely. The new
   plan is to use DocumentPolicy to enable declarative Shadow DOM for
   iframes. For now, iframes always support declarative Shadow DOM.
 - 'allowDeclarativeShadowDOM' has become 'allowShadowRoot'.

[1] whatwg/dom#912 (comment)
[2] https://chromium-review.googlesource.com/c/chromium/src/+/2513525

Bug: 1042130

Change-Id: I3a2becf2a113cc8647b29077d2efea1c990d4547
Cq-Do-Not-Cancel-Tryjobs: true
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2530222
Auto-Submit: Mason Freed <[email protected]>
Reviewed-by: Kouhei Ueno <[email protected]>
Reviewed-by: Kinuko Yasuda <[email protected]>
Commit-Queue: Mason Freed <[email protected]>
Cr-Commit-Position: refs/heads/master@{#826643}
GitOrigin-RevId: d5bf4401a47f04cbfbcca5d7fb4be5f99fa41e19
  • Loading branch information
mfreed7 authored and copybara-github committed Nov 12, 2020
1 parent 1850224 commit 8e7a96f
Show file tree
Hide file tree
Showing 45 changed files with 277 additions and 280 deletions.
1 change: 0 additions & 1 deletion blink/common/feature_policy/feature_policy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,6 @@ mojom::FeaturePolicyFeature FeaturePolicy::FeatureForSandboxFlag(
kPropagatesToAuxiliaryBrowsingContexts:
case network::mojom::WebSandboxFlags::kTopNavigationByUserActivation:
case network::mojom::WebSandboxFlags::kStorageAccessByUserActivation:
case network::mojom::WebSandboxFlags::kDeclarativeShadowDom:
break;
}
return mojom::FeaturePolicyFeature::kNotFound;
Expand Down
4 changes: 4 additions & 0 deletions blink/renderer/bindings/generated_in_core.gni
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ generated_dictionary_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_matrix_2d_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_matrix_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_matrix_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_parser_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_parser_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_point_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_point_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_quad_init.cc",
Expand Down Expand Up @@ -299,6 +301,8 @@ generated_dictionary_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_scroll_to_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_security_policy_violation_event_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_security_policy_violation_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_set_inner_html_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_set_inner_html_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_shadow_root_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_shadow_root_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_stream_pipe_options.h",
Expand Down
2 changes: 2 additions & 0 deletions blink/renderer/bindings/idl_in_core.gni
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/dom/pointer_lock_options.idl",
"//third_party/blink/renderer/core/dom/processing_instruction.idl",
"//third_party/blink/renderer/core/dom/range.idl",
"//third_party/blink/renderer/core/dom/set_inner_html_options.idl",
"//third_party/blink/renderer/core/dom/shadow_root.idl",
"//third_party/blink/renderer/core/dom/shadow_root_init.idl",
"//third_party/blink/renderer/core/dom/static_range.idl",
Expand Down Expand Up @@ -664,6 +665,7 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/workers/worklet_options.idl",
"//third_party/blink/renderer/core/xml/document_xpath_evaluator.idl",
"//third_party/blink/renderer/core/xml/dom_parser.idl",
"//third_party/blink/renderer/core/xml/dom_parser_init.idl",
"//third_party/blink/renderer/core/xml/xml_serializer.idl",
"//third_party/blink/renderer/core/xml/xpath_evaluator.idl",
"//third_party/blink/renderer/core/xml/xpath_expression.idl",
Expand Down
2 changes: 2 additions & 0 deletions blink/renderer/core/core_idl_files.gni
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ core_dictionary_idl_files =
"dom/idle_request_options.idl",
"dom/mutation_observer_init.idl",
"dom/pointer_lock_options.idl",
"dom/set_inner_html_options.idl",
"dom/shadow_root_init.idl",
"dom/events/add_event_listener_options.idl",
"dom/events/custom_event_init.idl",
Expand Down Expand Up @@ -758,6 +759,7 @@ core_dictionary_idl_files =
"trustedtypes/trusted_type_policy_options.idl",
"workers/worker_options.idl",
"workers/worklet_options.idl",
"xml/dom_parser_init.idl",
],
"abspath")

Expand Down
14 changes: 5 additions & 9 deletions blink/renderer/core/dom/document.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6962,20 +6962,16 @@ void Document::MarkFirstPaint() {
MaybeExecuteDelayedAsyncScripts();
}

using AllowState = blink::Document::DeclarativeShadowDomAllowState;
AllowState Document::GetDeclarativeShadowDomAllowState() const {
return declarative_shadow_dom_allow_state_;
using AllowState = blink::Document::DeclarativeShadowRootAllowState;
AllowState Document::GetDeclarativeShadowRootAllowState() const {
return declarative_shadow_root_allow_state_;
}

void Document::setAllowDeclarativeShadowDom(bool val) {
declarative_shadow_dom_allow_state_ =
void Document::setAllowDeclarativeShadowRoot(bool val) {
declarative_shadow_root_allow_state_ =
val ? AllowState::kAllow : AllowState::kDeny;
}

bool Document::allowDeclarativeShadowDom() const {
return declarative_shadow_dom_allow_state_ == AllowState::kAllow;
}

void Document::FinishedParsing() {
DCHECK(!GetScriptableDocumentParser() || !parser_->IsParsing());
DCHECK(!GetScriptableDocumentParser() || ready_state_ != kLoading);
Expand Down
11 changes: 5 additions & 6 deletions blink/renderer/core/dom/document.h
Original file line number Diff line number Diff line change
Expand Up @@ -1662,14 +1662,13 @@ class CORE_EXPORT Document : public ContainerNode,
void MarkFirstPaint();
void MaybeExecuteDelayedAsyncScripts();

enum class DeclarativeShadowDomAllowState : uint8_t {
enum class DeclarativeShadowRootAllowState : uint8_t {
kNotSet,
kAllow,
kDeny
};
DeclarativeShadowDomAllowState GetDeclarativeShadowDomAllowState() const;
void setAllowDeclarativeShadowDom(bool val);
bool allowDeclarativeShadowDom() const;
DeclarativeShadowRootAllowState GetDeclarativeShadowRootAllowState() const;
void setAllowDeclarativeShadowRoot(bool val);

void SetFindInPageActiveMatchNode(Node*);
const Node* GetFindInPageActiveMatchNode() const;
Expand Down Expand Up @@ -2212,8 +2211,8 @@ class CORE_EXPORT Document : public ContainerNode,
int async_script_count_ = 0;
bool first_paint_recorded_ = false;

DeclarativeShadowDomAllowState declarative_shadow_dom_allow_state_ =
DeclarativeShadowDomAllowState::kNotSet;
DeclarativeShadowRootAllowState declarative_shadow_root_allow_state_ =
DeclarativeShadowRootAllowState::kNotSet;

WeakMember<Node> find_in_page_active_match_node_;

Expand Down
3 changes: 0 additions & 3 deletions blink/renderer/core/dom/document.idl
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,6 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
// https://w3c.github.io/webappsec-feature-policy/#the-policy-object
readonly attribute FeaturePolicy featurePolicy;

// Declarative Shadow DOM API
[RuntimeEnabled=DeclarativeShadowDOM] attribute boolean allowDeclarativeShadowDom;

// Deprecated prefixed page visibility API.
// TODO(davidben): This is a property so attaching a deprecation warning results in false positives when outputting
// document in the console. It's possible https://crbug.com/43394 will resolve this.
Expand Down
2 changes: 0 additions & 2 deletions blink/renderer/core/dom/document_fragment.idl
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
Exposed=Window
] interface DocumentFragment : Node {
[CallWith=Document] constructor();

[RuntimeEnabled=DeclarativeShadowDOM] attribute boolean allowDeclarativeShadowDom;
};

DocumentFragment includes ParentNode;
Expand Down
1 change: 1 addition & 0 deletions blink/renderer/core/dom/dom_implementation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ Document* DOMImplementation::createHTMLDocument(const String& title) {
.WithExecutionContext(document_->GetExecutionContext())
.WithRegistrationContext(document_->RegistrationContext());
auto* d = MakeGarbageCollected<HTMLDocument>(init);
d->setAllowDeclarativeShadowRoot(false);
d->open();
d->write("<!doctype html><html><head></head><body></body></html>");
if (!title.IsNull()) {
Expand Down
32 changes: 26 additions & 6 deletions blink/renderer/core/dom/element.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_pointer_lock_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_scroll_into_view_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_scroll_to_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_set_inner_html_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_shadow_root_init.h"
#include "third_party/blink/renderer/core/accessibility/ax_context.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
Expand Down Expand Up @@ -4462,14 +4463,17 @@ String Element::outerHTML() const {
return CreateMarkup(this);
}

void Element::setInnerHTML(const String& html,
ExceptionState& exception_state) {
probe::BreakableLocation(GetExecutionContext(), "Element.setInnerHTML");
void Element::SetInnerHTMLInternal(const String& html,
const SetInnerHTMLOptions* options,
ExceptionState& exception_state) {
if (html.IsEmpty() && !HasNonInBodyInsertionMode()) {
setTextContent(html);
} else {
bool allow_shadow_root =
options->hasAllowShadowRoot() && options->allowShadowRoot();
if (DocumentFragment* fragment = CreateFragmentForInnerOuterHTML(
html, this, kAllowScriptingContent, "innerHTML", exception_state)) {
html, this, kAllowScriptingContent, "innerHTML", allow_shadow_root,
exception_state)) {
ContainerNode* container = this;
if (auto* template_element = DynamicTo<HTMLTemplateElement>(*this)) {
// Allow replacing innerHTML on declarative shadow templates, prior to
Expand All @@ -4483,6 +4487,21 @@ void Element::setInnerHTML(const String& html,
}
}

void Element::setInnerHTML(const String& html,
ExceptionState& exception_state) {
probe::BreakableLocation(GetExecutionContext(), "Element.setInnerHTML");
const SetInnerHTMLOptions options;
SetInnerHTMLInternal(html, &options, exception_state);
}

void Element::setInnerHTMLWithOptions(const String& html,
const SetInnerHTMLOptions* options,
ExceptionState& exception_state) {
DCHECK(RuntimeEnabledFeatures::DeclarativeShadowDOMEnabled(
GetExecutionContext()));
SetInnerHTMLInternal(html, options, exception_state);
}

String Element::getInnerHTML(const GetInnerHTMLOptions* options) const {
DCHECK(RuntimeEnabledFeatures::DeclarativeShadowDOMEnabled(
GetExecutionContext()));
Expand Down Expand Up @@ -4521,7 +4540,8 @@ void Element::setOuterHTML(const String& html,
Node* next = nextSibling();

DocumentFragment* fragment = CreateFragmentForInnerOuterHTML(
html, parent, kAllowScriptingContent, "outerHTML", exception_state);
html, parent, kAllowScriptingContent, "outerHTML",
/*allow_shadow_root=*/false, exception_state);
if (exception_state.HadException())
return;

Expand Down Expand Up @@ -4703,7 +4723,7 @@ void Element::insertAdjacentHTML(const String& where,
// Step 3 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
DocumentFragment* fragment = CreateFragmentForInnerOuterHTML(
markup, context_element, kAllowScriptingContent, "insertAdjacentHTML",
exception_state);
/*allow_shadow_root=*/false, exception_state);
if (!fragment)
return;
InsertAdjacent(where, fragment, exception_state);
Expand Down
8 changes: 8 additions & 0 deletions blink/renderer/core/dom/element.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class ExceptionState;
class FloatQuad;
class FloatSize;
class FocusOptions;
class SetInnerHTMLOptions;
class GetInnerHTMLOptions;
class HTMLTemplateElement;
class Image;
Expand Down Expand Up @@ -697,6 +698,9 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
String innerHTML() const;
String outerHTML() const;
void setInnerHTML(const String&, ExceptionState& = ASSERT_NO_EXCEPTION);
void setInnerHTMLWithOptions(const String&,
const SetInnerHTMLOptions*,
ExceptionState& = ASSERT_NO_EXCEPTION);
String getInnerHTML(const GetInnerHTMLOptions* options) const;
void setOuterHTML(const String&, ExceptionState& = ASSERT_NO_EXCEPTION);

Expand Down Expand Up @@ -1185,6 +1189,10 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
const QualifiedName&,
const AtomicString&);

void SetInnerHTMLInternal(const String&,
const SetInnerHTMLOptions*,
ExceptionState&);

ElementRareData* GetElementRareData() const;
ElementRareData& EnsureElementRareData();

Expand Down
5 changes: 3 additions & 2 deletions blink/renderer/core/dom/element.idl
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ callback ScrollStateCallback = void (ScrollState scrollState);
[Affects=Nothing, CEReactions, CustomElementCallbacks, RaisesException=Setter] attribute [TreatNullAs=EmptyString, StringContext=TrustedHTML] DOMString outerHTML;
[CEReactions, CustomElementCallbacks, RaisesException] void insertAdjacentHTML(DOMString position, HTMLString text);

// Declarative Shadow DOM getInnerHTML() function.
[RuntimeEnabled=DeclarativeShadowDOM, RuntimeCallStatsCounter=ElementGetInnerHTML] HTMLString getInnerHTML(optional GetInnerHTMLOptions options = {});
// Declarative Shadow DOM setInnerHTML/getInnerHTML() functions.
[Affects=Nothing, RuntimeEnabled=DeclarativeShadowDOM, RuntimeCallStatsCounter=ElementSetInnerHTML, RaisesException, ImplementedAs=setInnerHTMLWithOptions] void setInnerHTML(DOMString html, optional SetInnerHTMLOptions options = {});
[Affects=Nothing, RuntimeEnabled=DeclarativeShadowDOM, RuntimeCallStatsCounter=ElementGetInnerHTML] HTMLString getInnerHTML(optional GetInnerHTMLOptions options = {});

// Pointer Lock
// https://w3c.github.io/pointerlock/#extensions-to-the-element-interface
Expand Down
7 changes: 7 additions & 0 deletions blink/renderer/core/dom/set_inner_html_options.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

dictionary SetInnerHTMLOptions {
boolean allowShadowRoot = false;
};
27 changes: 23 additions & 4 deletions blink/renderer/core/dom/shadow_root.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/dom/shadow_root.h"

#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_set_inner_html_options.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
#include "third_party/blink/renderer/core/css/style_change_reason.h"
#include "third_party/blink/renderer/core/css/style_engine.h"
Expand Down Expand Up @@ -116,12 +117,30 @@ String ShadowRoot::innerHTML() const {
return CreateMarkup(this, kChildrenOnly);
}

void ShadowRoot::setInnerHTML(const String& markup,
ExceptionState& exception_state) {
void ShadowRoot::SetInnerHTMLInternal(const String& html,
const SetInnerHTMLOptions* options,
ExceptionState& exception_state) {
bool allow_shadow_root =
options->hasAllowShadowRoot() && options->allowShadowRoot();
if (DocumentFragment* fragment = CreateFragmentForInnerOuterHTML(
markup, &host(), kAllowScriptingContent, "innerHTML",
exception_state))
html, &host(), kAllowScriptingContent, "innerHTML", allow_shadow_root,
exception_state)) {
ReplaceChildrenWithFragment(this, fragment, exception_state);
}
}

void ShadowRoot::setInnerHTML(const String& html,
ExceptionState& exception_state) {
const SetInnerHTMLOptions options;
SetInnerHTMLInternal(html, &options, exception_state);
}

void ShadowRoot::setInnerHTMLWithOptions(const String& html,
const SetInnerHTMLOptions* options,
ExceptionState& exception_state) {
DCHECK(RuntimeEnabledFeatures::DeclarativeShadowDOMEnabled(
GetExecutionContext()));
SetInnerHTMLInternal(html, options, exception_state);
}

void ShadowRoot::RebuildLayoutTree(WhitespaceAttacher& whitespace_attacher) {
Expand Down
8 changes: 8 additions & 0 deletions blink/renderer/core/dom/shadow_root.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace blink {

class Document;
class ExceptionState;
class SetInnerHTMLOptions;
class ShadowRootV0;
class SlotAssignment;
class WhitespaceAttacher;
Expand Down Expand Up @@ -138,6 +139,9 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {

String innerHTML() const;
void setInnerHTML(const String&, ExceptionState& = ASSERT_NO_EXCEPTION);
void setInnerHTMLWithOptions(const String&,
const SetInnerHTMLOptions*,
ExceptionState& = ASSERT_NO_EXCEPTION);

Node* Clone(Document&, CloneChildrenFlag) const override;

Expand Down Expand Up @@ -188,6 +192,10 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {

SlotAssignment& EnsureSlotAssignment();

void SetInnerHTMLInternal(const String&,
const SetInnerHTMLOptions*,
ExceptionState&);

void AddChildShadowRoot() { ++child_shadow_root_count_; }
void RemoveChildShadowRoot() {
DCHECK_GT(child_shadow_root_count_, 0u);
Expand Down
4 changes: 4 additions & 0 deletions blink/renderer/core/dom/shadow_root.idl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ interface ShadowRoot : DocumentFragment {
[CEReactions, CustomElementCallbacks, RaisesException=Setter] attribute [TreatNullAs=EmptyString, StringContext=TrustedHTML] DOMString innerHTML;
readonly attribute boolean delegatesFocus;
[RuntimeEnabled=ManualSlotting] readonly attribute SlotAssignmentMode slotAssignment;

// Declarative Shadow DOM setInnerHTML function.
// TODO(crbug.com/1147752): Add getInnerHTML() here also.
[Affects=Nothing, RuntimeEnabled=DeclarativeShadowDOM, RaisesException, ImplementedAs=setInnerHTMLWithOptions] void setInnerHTML(DOMString html, optional SetInnerHTMLOptions options = {});
};

ShadowRoot includes DocumentOrShadowRoot;
10 changes: 6 additions & 4 deletions blink/renderer/core/dom/slot_assignment_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"

#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_set_inner_html_options.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node.h"
Expand Down Expand Up @@ -64,13 +65,14 @@ class SlotAssignmentTest : public testing::Test {
void SlotAssignmentTest::SetUp() {
dummy_page_holder_ = std::make_unique<DummyPageHolder>(IntSize(800, 600));
document_ = &dummy_page_holder_->GetDocument();
document_->setAllowDeclarativeShadowDom(true);
DCHECK(document_);
}

void SlotAssignmentTest::SetBody(const char* html) {
Element* body = GetDocument().body();
body->setInnerHTML(String::FromUTF8(html));
SetInnerHTMLOptions options;
options.setAllowShadowRoot(true);
body->setInnerHTMLWithOptions(String::FromUTF8(html), &options);
RemoveWhiteSpaceOnlyTextNode(*body);
}

Expand Down Expand Up @@ -133,9 +135,9 @@ TEST_F(SlotAssignmentTest, AssignedNodesAreSet) {
TEST_F(SlotAssignmentTest, ScheduleVisualUpdate) {
SetBody(R"HTML(
<div id="host">
<shadowroot>
<template shadowroot=open>
<slot></slot>
</shadowroot>
</template>
<div></div>
</div>
)HTML");
Expand Down
Loading

0 comments on commit 8e7a96f

Please sign in to comment.