Commit 69b72d55 authored by Mason Freed's avatar Mason Freed Committed by Commit Bot

Implement basic declarative Shadow DOM

This CL adds the DeclarativeShadowDOM runtime enabled feature, and
implements a basic approach. There are no tests yet, as this is an
evolving spec/approach. But this allows basic testing of attaching
the shadow root upon the closing <template> tag.

See the explainer [1], the issue discussion [2], the intent to
prototype [3], and the chromestatus entry [4].

To test this feature:
  --enable-blink-features=DeclarativeShadowDOM

and then:
  <div>
    <template shadowroot=open>
      <div></div>
      <slot></slot>
    </template>
    <span>
  </div>

[1] https://github.com/mfreed7/declarative-shadow-dom/blob/master/README.md
[2] https://github.com/whatwg/dom/issues/831
[3] https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/nJDc-1s3R9U
[4] https://chromestatus.com/feature/5191745052606464

Bug: 1042130

Change-Id: I5057c932a89fc401735d024348799d30c97e959e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2018336
Auto-Submit: Mason Freed <masonfreed@chromium.org>
Reviewed-by: default avatarKouhei Ueno <kouhei@chromium.org>
Commit-Queue: Mason Freed <masonfreed@chromium.org>
Cr-Commit-Position: refs/heads/master@{#741538}
parent b422ae79
...@@ -3528,6 +3528,21 @@ ShadowRoot& Element::CreateAndAttachShadowRoot(ShadowRootType type) { ...@@ -3528,6 +3528,21 @@ ShadowRoot& Element::CreateAndAttachShadowRoot(ShadowRootType type) {
return *shadow_root; return *shadow_root;
} }
void Element::AttachDeclarativeShadowRoot(HTMLTemplateElement* template_element,
ShadowRootType type) {
DCHECK(template_element);
DCHECK(type == ShadowRootType::kOpen || type == ShadowRootType::kClosed);
if (!CanAttachShadowRoot()) {
// TODO(masonfreed): Eventually, this should be a DOMException.
LOG(ERROR) << "Invalid shadow root host element";
return;
}
ShadowRoot* shadow_root = &AttachShadowRootInternal(
type, /*delegates_focus=*/false, /*manual_slotting=*/false);
shadow_root->appendChild(template_element->content());
template_element->remove();
}
ShadowRoot* Element::GetShadowRoot() const { ShadowRoot* Element::GetShadowRoot() const {
return HasRareData() ? GetElementRareData()->GetShadowRoot() : nullptr; return HasRareData() ? GetElementRareData()->GetShadowRoot() : nullptr;
} }
......
...@@ -65,6 +65,7 @@ class ElementRareData; ...@@ -65,6 +65,7 @@ class ElementRareData;
class ExceptionState; class ExceptionState;
class FloatQuad; class FloatQuad;
class FloatSize; class FloatSize;
class HTMLTemplateElement;
class Image; class Image;
class InputDeviceCapabilities; class InputDeviceCapabilities;
class Locale; class Locale;
...@@ -574,6 +575,9 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable { ...@@ -574,6 +575,9 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
ShadowRoot* createShadowRoot(ExceptionState&); ShadowRoot* createShadowRoot(ExceptionState&);
ShadowRoot* attachShadow(const ShadowRootInit*, ExceptionState&); ShadowRoot* attachShadow(const ShadowRootInit*, ExceptionState&);
void AttachDeclarativeShadowRoot(HTMLTemplateElement* template_element,
ShadowRootType type);
ShadowRoot& CreateV0ShadowRootForTesting() { ShadowRoot& CreateV0ShadowRootForTesting() {
return CreateShadowRootInternal(); return CreateShadowRootInternal();
} }
......
...@@ -295,6 +295,7 @@ ...@@ -295,6 +295,7 @@
"scrolling", "scrolling",
"select", "select",
"selected", "selected",
"shadowroot",
"shape", "shape",
"size", "size",
"sizes", "sizes",
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/document_fragment.h" #include "third_party/blink/renderer/core/dom/document_fragment.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h" #include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/frame/web_feature.h" #include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element.h" #include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h" #include "third_party/blink/renderer/core/html/forms/html_form_element.h"
...@@ -909,10 +910,38 @@ bool HTMLTreeBuilder::ProcessTemplateEndTag(AtomicHTMLToken* token) { ...@@ -909,10 +910,38 @@ bool HTMLTreeBuilder::ProcessTemplateEndTag(AtomicHTMLToken* token) {
tree_.GenerateImpliedEndTags(); tree_.GenerateImpliedEndTags();
if (!tree_.CurrentStackItem()->HasTagName(html_names::kTemplateTag)) if (!tree_.CurrentStackItem()->HasTagName(html_names::kTemplateTag))
ParseError(token); ParseError(token);
tree_.OpenElements()->PopUntilPopped(html_names::kTemplateTag); tree_.OpenElements()->PopUntil(html_names::kTemplateTag.LocalName());
HTMLStackItem* template_stack_item =
tree_.OpenElements()->TopRecord()->StackItem();
tree_.OpenElements()->Pop();
HTMLStackItem* shadow_host_stack_item =
tree_.OpenElements()->TopRecord()->StackItem();
tree_.ActiveFormattingElements()->ClearToLastMarker(); tree_.ActiveFormattingElements()->ClearToLastMarker();
template_insertion_modes_.pop_back(); template_insertion_modes_.pop_back();
ResetInsertionModeAppropriately(); ResetInsertionModeAppropriately();
if (RuntimeEnabledFeatures::DeclarativeShadowDOMEnabled() &&
template_stack_item && template_stack_item->IsElementNode() &&
shadow_host_stack_item && shadow_host_stack_item->IsElementNode()) {
// TODO(masonfreed): Add a use counter here.
HTMLTemplateElement* template_element =
DynamicTo<HTMLTemplateElement>(template_stack_item->GetElement());
DCHECK(template_element);
Element* shadow_host = shadow_host_stack_item->GetElement();
DCHECK(shadow_host);
const auto& shadow_mode =
template_element->FastGetAttribute(html_names::kShadowrootAttr);
if (shadow_mode != g_null_atom) {
bool is_open = EqualIgnoringASCIICase(shadow_mode, "open");
if (is_open || EqualIgnoringASCIICase(shadow_mode, "closed")) {
shadow_host->AttachDeclarativeShadowRoot(
template_element,
is_open ? ShadowRootType::kOpen : ShadowRootType::kClosed);
} else {
// TODO(masonfreed): eventually, console warning here.
LOG(ERROR) << "Invalid shadowroot value " << shadow_mode;
}
}
}
return true; return true;
} }
......
...@@ -571,6 +571,10 @@ ...@@ -571,6 +571,10 @@
name: "Database", name: "Database",
status: "stable", status: "stable",
}, },
{
name: "DeclarativeShadowDOM",
status: "test",
},
{ {
name: "DecodeJpeg420ImagesToYUV", name: "DecodeJpeg420ImagesToYUV",
status: "test", status: "test",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment