Skip to content

Commit 24df05e

Browse files
Implement declarative shadow DOM (#568)
1 parent feced06 commit 24df05e

File tree

4 files changed

+70
-1
lines changed

4 files changed

+70
-1
lines changed

html5ever/src/tree_builder/mod.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,47 @@ where
13781378
}
13791379
//§ END
13801380

1381+
fn should_attach_declarative_shadow(&self, tag: &Tag) -> bool {
1382+
let adjusted_insertion_location = self.appropriate_place_for_insertion(None);
1383+
1384+
let (intended_parent, _node2) = match adjusted_insertion_location {
1385+
LastChild(ref p) | BeforeSibling(ref p) => (p.clone(), None),
1386+
TableFosterParenting {
1387+
ref element,
1388+
ref prev_element,
1389+
} => (element.clone(), Some(prev_element.clone())),
1390+
};
1391+
1392+
// template start tag's shadowrootmode is not in the none state
1393+
let is_shadow_root_mode = tag.attrs.iter().any(|attr| {
1394+
attr.name.local == local_name!("shadowrootmode")
1395+
&& (attr.value.to_string() == String::from("open") || attr.value.to_string() == String::from("close"))
1396+
});
1397+
1398+
// Check if intended_parent's document allows declarative shadow roots
1399+
let allow_declarative_shadow_roots = self.sink.allow_declarative_shadow_roots(&intended_parent);
1400+
1401+
// the adjusted current node is not the topmost element in the stack of open elements
1402+
let adjusted_current_node_not_topmost = match self.open_elems.borrow().first() {
1403+
// The stack grows downwards; the topmost node on the stack is the first one added to the stack
1404+
// The current node is the bottommost node in this stack of open elements.
1405+
//
1406+
// (1) The adjusted current node is the context element if the parser was created as part of the HTML fragment parsing algorithm
1407+
// and the stack of open elements has only one element in it (fragment case);
1408+
// (2) otherwise, the adjusted current node is the current node (the bottomost node)
1409+
//
1410+
// => adjusted current node != topmost element in the stack when the stack size > 1
1411+
Some(_) => self.open_elems.borrow().len() > 1,
1412+
None => true,
1413+
};
1414+
1415+
return is_shadow_root_mode && allow_declarative_shadow_roots && adjusted_current_node_not_topmost;
1416+
}
1417+
1418+
fn attach_declarative_shadow(&self, tag: &Tag) -> Result<(), String> {
1419+
self.sink.attach_declarative_shadow(self.open_elems.borrow().last().unwrap(), tag.attrs.clone())
1420+
}
1421+
13811422
fn create_formatting_element_for(&self, tag: Tag) -> Handle {
13821423
// FIXME: This really wants unit tests.
13831424
let mut first_match = None;

html5ever/src/tree_builder/rules.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ where
105105
}),
106106

107107
//§ parsing-main-inhead
108+
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inhead
108109
InHead => match_token!(token {
109110
CharacterTokens(NotSplit, text) => SplitWhitespace(text),
110111
CharacterTokens(Whitespace, text) => self.append_text(text),
@@ -153,11 +154,21 @@ where
153154
</body> </html> </br> => else,
154155

155156
tag @ <template> => {
156-
self.insert_element_for(tag);
157157
self.active_formatting.borrow_mut().push(Marker);
158158
self.frameset_ok.set(false);
159159
self.mode.set(InTemplate);
160160
self.template_modes.borrow_mut().push(InTemplate);
161+
162+
if (self.should_attach_declarative_shadow(&tag)) {
163+
if let Err(_) = self.attach_declarative_shadow(&tag) {
164+
// TODO:
165+
// insert at the adjusted insertion location
166+
// with the result of insert a foreign element for template tag
167+
}
168+
} else {
169+
self.insert_element_for(tag);
170+
}
171+
161172
Done
162173
}
163174

markup5ever/interface/tree_builder.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,19 @@ pub trait TreeSink {
260260
fn complete_script(&self, _node: &Self::Handle) -> NextParserState {
261261
NextParserState::Continue
262262
}
263+
264+
fn allow_declarative_shadow_roots(&self, _intended_parent: &Self::Handle) -> bool {
265+
return true;
266+
}
267+
268+
/// Attach declarative shadow
269+
fn attach_declarative_shadow(
270+
&self,
271+
_location: &Self::Handle,
272+
_attrs: Vec<Attribute>,
273+
) -> Result<(), String> {
274+
Err(String::from("No implementation for attach_declarative_shadow"))
275+
}
263276
}
264277

265278
/// Trace hooks for a garbage-collected DOM.

markup5ever/local_names.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,10 @@ separator
849849
separators
850850
set
851851
setdiff
852+
shadowrootclonable
853+
shadowrootdelegatesfocus
854+
shadowrootmode
855+
shadowrootserializable
852856
shape
853857
shape-rendering
854858
show

0 commit comments

Comments
 (0)