diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs
index 88afa725..60e594bc 100644
--- a/html5ever/src/tree_builder/mod.rs
+++ b/html5ever/src/tree_builder/mod.rs
@@ -1378,6 +1378,47 @@ where
}
//§ END
+ fn should_attach_declarative_shadow(&self, tag: &Tag) -> bool {
+ let adjusted_insertion_location = self.appropriate_place_for_insertion(None);
+
+ let (intended_parent, _node2) = match adjusted_insertion_location {
+ LastChild(ref p) | BeforeSibling(ref p) => (p.clone(), None),
+ TableFosterParenting {
+ ref element,
+ ref prev_element,
+ } => (element.clone(), Some(prev_element.clone())),
+ };
+
+ // template start tag's shadowrootmode is not in the none state
+ let is_shadow_root_mode = tag.attrs.iter().any(|attr| {
+ attr.name.local == local_name!("shadowrootmode")
+ && (attr.value.to_string() == String::from("open") || attr.value.to_string() == String::from("close"))
+ });
+
+ // Check if intended_parent's document allows declarative shadow roots
+ let allow_declarative_shadow_roots = self.sink.allow_declarative_shadow_roots(&intended_parent);
+
+ // the adjusted current node is not the topmost element in the stack of open elements
+ let adjusted_current_node_not_topmost = match self.open_elems.borrow().first() {
+ // The stack grows downwards; the topmost node on the stack is the first one added to the stack
+ // The current node is the bottommost node in this stack of open elements.
+ //
+ // (1) The adjusted current node is the context element if the parser was created as part of the HTML fragment parsing algorithm
+ // and the stack of open elements has only one element in it (fragment case);
+ // (2) otherwise, the adjusted current node is the current node (the bottomost node)
+ //
+ // => adjusted current node != topmost element in the stack when the stack size > 1
+ Some(_) => self.open_elems.borrow().len() > 1,
+ None => true,
+ };
+
+ return is_shadow_root_mode && allow_declarative_shadow_roots && adjusted_current_node_not_topmost;
+ }
+
+ fn attach_declarative_shadow(&self, tag: &Tag) -> Result<(), String> {
+ self.sink.attach_declarative_shadow(self.open_elems.borrow().last().unwrap(), tag.attrs.clone())
+ }
+
fn create_formatting_element_for(&self, tag: Tag) -> Handle {
// FIXME: This really wants unit tests.
let mut first_match = None;
diff --git a/html5ever/src/tree_builder/rules.rs b/html5ever/src/tree_builder/rules.rs
index eec6faf7..870e0ce3 100644
--- a/html5ever/src/tree_builder/rules.rs
+++ b/html5ever/src/tree_builder/rules.rs
@@ -105,6 +105,7 @@ where
}),
//§ parsing-main-inhead
+ // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inhead
InHead => match_token!(token {
CharacterTokens(NotSplit, text) => SplitWhitespace(text),
CharacterTokens(Whitespace, text) => self.append_text(text),
@@ -153,11 +154,21 @@ where