Skip to content

Commit e6110ef

Browse files
mukilancanova
authored andcommitted
Implement support for form owner
1 parent 33e9523 commit e6110ef

File tree

7 files changed

+149
-54
lines changed

7 files changed

+149
-54
lines changed

examples/noop-tree-builder.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ impl TreeSink for Sink {
5757
x == y
5858
}
5959

60+
fn same_home_subtree(&self, _x: usize, _y: usize) -> bool {
61+
true
62+
}
63+
6064
fn elem_name(&self, target: usize) -> QualName {
6165
self.names.get(&target).expect("not an element").clone()
6266
}
@@ -71,13 +75,15 @@ impl TreeSink for Sink {
7175
self.get_id()
7276
}
7377

78+
fn has_parent_node(&self, _node: usize) -> bool {
79+
// `node` will have a parent unless a script moved it, and we're
80+
// not running scripts. Therefore we can aways return true.
81+
true
82+
}
83+
7484
fn append_before_sibling(&mut self,
7585
_sibling: usize,
76-
_new_node: NodeOrText<usize>) -> Result<(), NodeOrText<usize>> {
77-
// `sibling` will have a parent unless a script moved it, and we're
78-
// not running scripts. Therefore we can aways return `Ok(())`.
79-
Ok(())
80-
}
86+
_new_node: NodeOrText<usize>) { }
8187

8288
fn parse_error(&mut self, _msg: Cow<'static, str>) { }
8389
fn set_quirks_mode(&mut self, _mode: QuirksMode) { }
@@ -87,6 +93,7 @@ impl TreeSink for Sink {
8793
fn add_attrs_if_missing(&mut self, target: usize, _attrs: Vec<Attribute>) {
8894
assert!(self.names.contains_key(&target), "not an element");
8995
}
96+
fn associate_with_form(&mut self, _target: usize, _form: usize) { }
9097
fn remove_from_parent(&mut self, _target: usize) { }
9198
fn reparent_children(&mut self, _node: usize, _new_parent: usize) { }
9299
fn mark_script_already_started(&mut self, _node: usize) { }

examples/print-tree-actions.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ impl TreeSink for Sink {
6565
x == y
6666
}
6767

68+
fn same_home_subtree(&self, _x: usize, _y: usize) -> bool {
69+
true
70+
}
71+
6872
fn elem_name(&self, target: usize) -> QualName {
6973
self.names.get(&target).expect("not an element").clone()
7074
}
@@ -82,6 +86,12 @@ impl TreeSink for Sink {
8286
id
8387
}
8488

89+
fn has_parent_node(&self, _node: usize) -> bool {
90+
// `node` will have a parent unless a script moved it, and we're
91+
// not running scripts. Therefore we can aways return true
92+
true
93+
}
94+
8595
fn append(&mut self, parent: usize, child: NodeOrText<usize>) {
8696
match child {
8797
AppendNode(n)
@@ -93,17 +103,13 @@ impl TreeSink for Sink {
93103

94104
fn append_before_sibling(&mut self,
95105
sibling: usize,
96-
new_node: NodeOrText<usize>) -> Result<(), NodeOrText<usize>> {
106+
new_node: NodeOrText<usize>) {
97107
match new_node {
98108
AppendNode(n)
99109
=> println!("Append node {} before {}", n, sibling),
100110
AppendText(t)
101111
=> println!("Append text before {}: \"{}\"", sibling, escape_default(&t)),
102112
}
103-
104-
// `sibling` will have a parent unless a script moved it, and we're
105-
// not running scripts. Therefore we can aways return `Ok(())`.
106-
Ok(())
107113
}
108114

109115
fn append_doctype_to_document(&mut self,
@@ -121,6 +127,12 @@ impl TreeSink for Sink {
121127
}
122128
}
123129

130+
fn associate_with_form(&mut self, _target: usize, _form: usize) {
131+
// No form owner support. Since same_home_subtree always returns
132+
// true we cannot be sure that this associate_with_form call is
133+
// valid
134+
}
135+
124136
fn remove_from_parent(&mut self, target: usize) {
125137
println!("Remove {} from parent", target);
126138
}

src/rcdom.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,17 @@ impl TreeSink for RcDom {
223223
new_node(Comment(text))
224224
}
225225

226+
fn same_home_subtree(&self, _x: Handle, _y: Handle) -> bool {
227+
true
228+
}
229+
230+
fn associate_with_form(&mut self, _target: Handle, _form: Handle) {}
231+
232+
fn has_parent_node(&self, node: Handle) -> bool {
233+
let node = node.borrow();
234+
node.parent.is_some()
235+
}
236+
226237
fn append(&mut self, parent: Handle, child: NodeOrText<Handle>) {
227238
// Append to an existing Text node if we have one.
228239
match child {
@@ -241,8 +252,9 @@ impl TreeSink for RcDom {
241252

242253
fn append_before_sibling(&mut self,
243254
sibling: Handle,
244-
child: NodeOrText<Handle>) -> Result<(), NodeOrText<Handle>> {
245-
let (parent, i) = unwrap_or_return!(get_parent_and_index(&sibling), Err(child));
255+
child: NodeOrText<Handle>) {
256+
let (parent, i) = get_parent_and_index(&sibling)
257+
.expect("append_before_sibling called on node without parent");
246258

247259
let child = match (child, i) {
248260
// No previous node.
@@ -253,7 +265,7 @@ impl TreeSink for RcDom {
253265
let parent = parent.borrow();
254266
let prev = &parent.children[i-1];
255267
if append_to_existing_text(prev, &text) {
256-
return Ok(());
268+
return;
257269
}
258270
new_node(Text(text))
259271
}
@@ -271,7 +283,6 @@ impl TreeSink for RcDom {
271283

272284
child.borrow_mut().parent = Some(Rc::downgrade(&parent));
273285
parent.borrow_mut().children.insert(i, child);
274-
Ok(())
275286
}
276287

277288
fn append_doctype_to_document(&mut self,

src/tree_builder/actions.rs

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -210,40 +210,8 @@ impl<Handle, Sink> TreeBuilderActions<Handle>
210210

211211
// Insert at the "appropriate place for inserting a node".
212212
fn insert_appropriately(&mut self, child: NodeOrText<Handle>, override_target: Option<Handle>) {
213-
declare_tag_set!(foster_target = "table" "tbody" "tfoot" "thead" "tr");
214-
let target = override_target.unwrap_or_else(|| self.current_node());
215-
if !(self.foster_parenting && self.elem_in(target.clone(), foster_target)) {
216-
if self.html_elem_named(target.clone(), local_name!("template")) {
217-
// No foster parenting (inside template).
218-
let contents = self.sink.get_template_contents(target);
219-
self.sink.append(contents, child);
220-
} else {
221-
// No foster parenting (the common case).
222-
self.sink.append(target, child);
223-
}
224-
return;
225-
}
226-
227-
// Foster parenting
228-
let mut iter = self.open_elems.iter().rev().peekable();
229-
while let Some(elem) = iter.next() {
230-
if self.html_elem_named(elem.clone(), local_name!("template")) {
231-
let contents = self.sink.get_template_contents(elem.clone());
232-
self.sink.append(contents, child);
233-
return;
234-
} else if self.html_elem_named(elem.clone(), local_name!("table")) {
235-
// Try inserting "inside last table's parent node, immediately before last table"
236-
if let Err(child) = self.sink.append_before_sibling(elem.clone(), child) {
237-
// If last_table has no parent, we regain ownership of the child.
238-
// Insert "inside previous element, after its last child (if any)"
239-
let previous_element = (*iter.peek().unwrap()).clone();
240-
self.sink.append(previous_element, child);
241-
}
242-
return;
243-
}
244-
}
245-
let html_elem = self.html_elem();
246-
self.sink.append(html_elem, child);
213+
let insertion_point = self.appropriate_place_for_insertion(override_target);
214+
self.insert_at(insertion_point, child);
247215
}
248216

249217
fn adoption_agency(&mut self, subject: LocalName) {
@@ -775,10 +743,39 @@ impl<Handle, Sink> TreeBuilderActions<Handle>
775743
// FIXME: application cache selection algorithm
776744
}
777745

746+
// https://html.spec.whatwg.org/multipage/syntax.html#create-an-element-for-the-token
778747
fn insert_element(&mut self, push: PushFlag, ns: Namespace, name: LocalName, attrs: Vec<Attribute>)
779748
-> Handle {
780-
let elem = self.sink.create_element(QualName::new(ns, name), attrs);
781-
self.insert_appropriately(AppendNode(elem.clone()), None);
749+
declare_tag_set!(form_associatable =
750+
"button" "fieldset" "input" "keygen" "label"
751+
"object" "output" "select" "textarea" "img");
752+
753+
declare_tag_set!(reassociatable = [form_associatable] - "img");
754+
755+
let qname = QualName::new(ns, name);
756+
let elem = self.sink.create_element(qname.clone(), attrs.clone());
757+
758+
let insertion_point = self.appropriate_place_for_insertion(None);
759+
let tree_node = match insertion_point {
760+
LastChild(ref p) |
761+
BeforeSibling(ref p) => p.clone()
762+
};
763+
764+
// Step 4.
765+
// TODO: Handle template element case
766+
if form_associatable(qname.clone())
767+
&& self.form_elem.is_some()
768+
&& !(reassociatable(qname.clone())
769+
&& attrs.iter().any(|a| a.name == qualname!("","form"))) {
770+
771+
let form = self.form_elem.as_ref().unwrap().clone();
772+
if self.sink.same_home_subtree(tree_node, form.clone()) {
773+
self.sink.associate_with_form(elem.clone(), form)
774+
}
775+
}
776+
777+
self.insert_at(insertion_point, AppendNode(elem.clone()));
778+
782779
match push {
783780
Push => self.push(&elem),
784781
NoPush => (),

src/tree_builder/interface.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ pub trait TreeSink {
7272
/// Do two handles refer to the same node?
7373
fn same_node(&self, x: Self::Handle, y: Self::Handle) -> bool;
7474

75+
/// Are two handles present in the same tree
76+
/// https://html.spec.whatwg.org/multipage/infrastructure.html#home-subtree
77+
fn same_home_subtree(&self, x: Self::Handle, y: Self::Handle) -> bool;
78+
7579
/// What is the name of this element?
7680
///
7781
/// Should never be called on a non-element node;
@@ -93,15 +97,18 @@ pub trait TreeSink {
9397
/// Create a comment node.
9498
fn create_comment(&mut self, text: StrTendril) -> Self::Handle;
9599

100+
/// Does the node have a parent?
101+
fn has_parent_node(&self, node: Self::Handle) -> bool;
102+
96103
/// Append a node as the last child of the given node. If this would
97104
/// produce adjacent sibling text nodes, it should concatenate the text
98105
/// instead.
99106
///
100107
/// The child node will not already have a parent.
101108
fn append(&mut self, parent: Self::Handle, child: NodeOrText<Self::Handle>);
102109

103-
/// Append a node as the sibling immediately before the given node. If that node
104-
/// has no parent, do nothing and return Err(new_node).
110+
/// Append a node as the sibling immediately before the given node.
111+
/// This method will only be called if has_parent_node(sibling) is true
105112
///
106113
/// The tree builder promises that `sibling` is not a text node. However its
107114
/// old previous sibling, which would become the new node's previous sibling,
@@ -111,7 +118,7 @@ pub trait TreeSink {
111118
/// NB: `new_node` may have an old parent, from which it should be removed.
112119
fn append_before_sibling(&mut self,
113120
sibling: Self::Handle,
114-
new_node: NodeOrText<Self::Handle>) -> Result<(), NodeOrText<Self::Handle>>;
121+
new_node: NodeOrText<Self::Handle>);
115122

116123
/// Append a `DOCTYPE` element to the `Document` node.
117124
fn append_doctype_to_document(&mut self,
@@ -124,6 +131,9 @@ pub trait TreeSink {
124131
/// with something else than an element.
125132
fn add_attrs_if_missing(&mut self, target: Self::Handle, attrs: Vec<Attribute>);
126133

134+
/// Associate the given form-associatable element with the form element
135+
fn associate_with_form(&mut self, target: Self::Handle, form: Self::Handle);
136+
127137
/// Detach the given node from its parent.
128138
fn remove_from_parent(&mut self, target: Self::Handle);
129139

src/tree_builder/mod.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,48 @@ impl<Handle, Sink> TreeBuilder<Handle, Sink>
369369
pub fn is_fragment(&self) -> bool {
370370
self.context_elem.is_some()
371371
}
372+
373+
fn appropriate_place_for_insertion(&self, override_target: Option<Handle>) -> InsertionPoint<Handle> {
374+
use self::tag_sets::*;
375+
376+
declare_tag_set!(foster_target = "table" "tbody" "tfoot" "thead" "tr");
377+
let target = override_target.unwrap_or_else(|| self.current_node());
378+
if !(self.foster_parenting && self.elem_in(target.clone(), foster_target)) {
379+
// No foster parenting (the common case).
380+
return LastChild(target)
381+
}
382+
383+
// Foster parenting
384+
// FIXME: <template>
385+
let last_table = self.open_elems.iter()
386+
.enumerate()
387+
.rev()
388+
.filter(|&(_, e)| self.html_elem_named(e.clone(), local_name!("table")))
389+
.next();
390+
391+
match last_table {
392+
None => {
393+
LastChild(self.html_elem())
394+
}
395+
Some((idx, last_table)) => {
396+
// Try inserting "inside last table's parent node, immediately before last table"
397+
if self.sink.has_parent_node(last_table.clone()) {
398+
BeforeSibling(last_table.clone())
399+
} else {
400+
// Insert "inside previous element, after its last child (if any)"
401+
let previous_element = self.open_elems[idx-1].clone();
402+
LastChild(previous_element)
403+
}
404+
}
405+
}
406+
}
407+
408+
fn insert_at(&mut self, insertion_point: InsertionPoint<Handle>, child: NodeOrText<Handle>) {
409+
match insertion_point {
410+
LastChild(parent) => self.sink.append(parent, child),
411+
BeforeSibling(sibling) => self.sink.append_before_sibling(sibling, child)
412+
}
413+
}
372414
}
373415

374416
impl<Handle, Sink> TokenSink
@@ -529,13 +571,18 @@ mod test {
529571
self.rcdom.create_comment(text)
530572
}
531573

574+
fn has_parent_node(&self, node: Handle) -> bool {
575+
let node = node.borrow();
576+
node.parent.is_some()
577+
}
578+
532579
fn append(&mut self, parent: Handle, child: NodeOrText<Handle>) {
533580
self.rcdom.append(parent, child)
534581
}
535582

536583
fn append_before_sibling(&mut self,
537584
sibling: Handle,
538-
child: NodeOrText<Handle>) -> Result<(), NodeOrText<Handle>> {
585+
child: NodeOrText<Handle>) {
539586
self.rcdom.append_before_sibling(sibling, child)
540587
}
541588

src/tree_builder/types.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub use self::SplitStatus::*;
1919
pub use self::Token::*;
2020
pub use self::ProcessResult::*;
2121
pub use self::FormatEntry::*;
22+
pub use self::InsertionPoint::*;
2223

2324
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
2425
pub enum InsertionMode {
@@ -80,3 +81,13 @@ pub enum FormatEntry<Handle> {
8081
Element(Handle, Tag),
8182
Marker,
8283
}
84+
85+
pub enum InsertionPoint<Handle> {
86+
/// Holds the parent
87+
LastChild(Handle),
88+
/// Holds the sibling before which the node will be inserted
89+
/// TODO: Is the parent node needed? Is there a problem with using
90+
/// the sibling to find if the form element is in the same home
91+
/// subtree?
92+
BeforeSibling(Handle)
93+
}

0 commit comments

Comments
 (0)