Skip to content

Commit 69f7069

Browse files
mukilancanova
authored andcommittedFeb 6, 2017
Implement support for form owner
1 parent 33e9523 commit 69f7069

File tree

7 files changed

+145
-54
lines changed

7 files changed

+145
-54
lines changed
 

‎examples/noop-tree-builder.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ impl TreeSink for Sink {
5757
x == y
5858
}
5959

60+
fn same_tree(&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) { }

‎examples/print-tree-actions.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ impl TreeSink for Sink {
8282
id
8383
}
8484

85+
fn has_parent_node(&self, _node: usize) -> bool {
86+
// `node` will have a parent unless a script moved it, and we're
87+
// not running scripts. Therefore we can aways return true
88+
true
89+
}
90+
8591
fn append(&mut self, parent: usize, child: NodeOrText<usize>) {
8692
match child {
8793
AppendNode(n)
@@ -93,17 +99,13 @@ impl TreeSink for Sink {
9399

94100
fn append_before_sibling(&mut self,
95101
sibling: usize,
96-
new_node: NodeOrText<usize>) -> Result<(), NodeOrText<usize>> {
102+
new_node: NodeOrText<usize>) {
97103
match new_node {
98104
AppendNode(n)
99105
=> println!("Append node {} before {}", n, sibling),
100106
AppendText(t)
101107
=> println!("Append text before {}: \"{}\"", sibling, escape_default(&t)),
102108
}
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(())
107109
}
108110

109111
fn append_doctype_to_document(&mut self,
@@ -121,6 +123,12 @@ impl TreeSink for Sink {
121123
}
122124
}
123125

126+
fn associate_with_form(&mut self, _target: usize, _form: usize) {
127+
// No form owner support. Since same_tree always returns
128+
// true we cannot be sure that this associate_with_form call is
129+
// valid
130+
}
131+
124132
fn remove_from_parent(&mut self, target: usize) {
125133
println!("Remove {} from parent", target);
126134
}

‎src/rcdom.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,11 @@ impl TreeSink for RcDom {
223223
new_node(Comment(text))
224224
}
225225

226+
fn has_parent_node(&self, node: Handle) -> bool {
227+
let node = node.borrow();
228+
node.parent.is_some()
229+
}
230+
226231
fn append(&mut self, parent: Handle, child: NodeOrText<Handle>) {
227232
// Append to an existing Text node if we have one.
228233
match child {
@@ -241,8 +246,9 @@ impl TreeSink for RcDom {
241246

242247
fn append_before_sibling(&mut self,
243248
sibling: Handle,
244-
child: NodeOrText<Handle>) -> Result<(), NodeOrText<Handle>> {
245-
let (parent, i) = unwrap_or_return!(get_parent_and_index(&sibling), Err(child));
249+
child: NodeOrText<Handle>) {
250+
let (parent, i) = get_parent_and_index(&sibling)
251+
.expect("append_before_sibling called on node without parent");
246252

247253
let child = match (child, i) {
248254
// No previous node.
@@ -253,7 +259,7 @@ impl TreeSink for RcDom {
253259
let parent = parent.borrow();
254260
let prev = &parent.children[i-1];
255261
if append_to_existing_text(prev, &text) {
256-
return Ok(());
262+
return;
257263
}
258264
new_node(Text(text))
259265
}
@@ -271,7 +277,6 @@ impl TreeSink for RcDom {
271277

272278
child.borrow_mut().parent = Some(Rc::downgrade(&parent));
273279
parent.borrow_mut().children.insert(i, child);
274-
Ok(())
275280
}
276281

277282
fn append_doctype_to_document(&mut self,

‎src/tree_builder/actions.rs

+34-36
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,40 @@ impl<Handle, Sink> TreeBuilderActions<Handle>
775743
// FIXME: application cache selection algorithm
776744
}
777745

746+
// https://html.spec.whatwg.org/multipage/#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" "object"
751+
"output" "select" "textarea" "img");
752+
753+
declare_tag_set!(listed = [form_associatable] - "img");
754+
755+
// Step 7.
756+
let qname = QualName::new(ns, name);
757+
let elem = self.sink.create_element(qname.clone(), attrs.clone());
758+
759+
let insertion_point = self.appropriate_place_for_insertion(None);
760+
let tree_node = match insertion_point {
761+
LastChild(ref p) |
762+
BeforeSibling(ref p) => p.clone()
763+
};
764+
765+
// Step 12.
766+
if form_associatable(qname.clone()) &&
767+
self.form_elem.is_some() &&
768+
!self.in_html_elem_named(local_name!("template")) &&
769+
!(listed(qname.clone()) &&
770+
attrs.iter().any(|a| a.name == qualname!("","form"))) {
771+
772+
let form = self.form_elem.as_ref().unwrap().clone();
773+
if self.sink.same_tree(tree_node, form.clone()) {
774+
self.sink.associate_with_form(elem.clone(), form)
775+
}
776+
}
777+
778+
self.insert_at(insertion_point, AppendNode(elem.clone()));
779+
782780
match push {
783781
Push => self.push(&elem),
784782
NoPush => (),

‎src/tree_builder/interface.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ 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+
fn same_tree(&self, x: Self::Handle, y: Self::Handle) -> bool {
77+
true
78+
}
79+
7580
/// What is the name of this element?
7681
///
7782
/// Should never be called on a non-element node;
@@ -93,15 +98,18 @@ pub trait TreeSink {
9398
/// Create a comment node.
9499
fn create_comment(&mut self, text: StrTendril) -> Self::Handle;
95100

101+
/// Does the node have a parent?
102+
fn has_parent_node(&self, node: Self::Handle) -> bool;
103+
96104
/// Append a node as the last child of the given node. If this would
97105
/// produce adjacent sibling text nodes, it should concatenate the text
98106
/// instead.
99107
///
100108
/// The child node will not already have a parent.
101109
fn append(&mut self, parent: Self::Handle, child: NodeOrText<Self::Handle>);
102110

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).
111+
/// Append a node as the sibling immediately before the given node.
112+
/// This method will only be called if has_parent_node(sibling) is true
105113
///
106114
/// The tree builder promises that `sibling` is not a text node. However its
107115
/// old previous sibling, which would become the new node's previous sibling,
@@ -111,7 +119,7 @@ pub trait TreeSink {
111119
/// NB: `new_node` may have an old parent, from which it should be removed.
112120
fn append_before_sibling(&mut self,
113121
sibling: Self::Handle,
114-
new_node: NodeOrText<Self::Handle>) -> Result<(), NodeOrText<Self::Handle>>;
122+
new_node: NodeOrText<Self::Handle>);
115123

116124
/// Append a `DOCTYPE` element to the `Document` node.
117125
fn append_doctype_to_document(&mut self,
@@ -124,6 +132,9 @@ pub trait TreeSink {
124132
/// with something else than an element.
125133
fn add_attrs_if_missing(&mut self, target: Self::Handle, attrs: Vec<Attribute>);
126134

135+
/// Associate the given form-associatable element with the form element
136+
fn associate_with_form(&mut self, target: Self::Handle, form: Self::Handle) {}
137+
127138
/// Detach the given node from its parent.
128139
fn remove_from_parent(&mut self, target: Self::Handle);
129140

‎src/tree_builder/mod.rs

+53-1
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,53 @@ 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(&mut self,
374+
override_target: Option<Handle>)
375+
-> InsertionPoint<Handle> {
376+
use self::tag_sets::*;
377+
378+
declare_tag_set!(foster_target = "table" "tbody" "tfoot" "thead" "tr");
379+
let target = override_target.unwrap_or_else(|| self.current_node());
380+
if !(self.foster_parenting && self.elem_in(target.clone(), foster_target)) {
381+
if self.html_elem_named(target.clone(), local_name!("template")) {
382+
// No foster parenting (inside template).
383+
let contents = self.sink.get_template_contents(target);
384+
return LastChild(contents);
385+
} else {
386+
// No foster parenting (the common case).
387+
return LastChild(target);
388+
}
389+
}
390+
391+
// Foster parenting
392+
let mut iter = self.open_elems.iter().rev().peekable();
393+
while let Some(elem) = iter.next() {
394+
if self.html_elem_named(elem.clone(), local_name!("template")) {
395+
let contents = self.sink.get_template_contents(elem.clone());
396+
return LastChild(contents);
397+
} else if self.html_elem_named(elem.clone(), local_name!("table")) {
398+
// Try inserting "inside last table's parent node, immediately before last table"
399+
if self.sink.has_parent_node(elem.clone()) {
400+
return BeforeSibling(elem.clone());
401+
} else {
402+
// If elem has no parent, we regain ownership of the child.
403+
// Insert "inside previous element, after its last child (if any)"
404+
let previous_element = (*iter.peek().unwrap()).clone();
405+
return LastChild(previous_element);
406+
}
407+
}
408+
}
409+
let html_elem = self.html_elem();
410+
LastChild(html_elem)
411+
}
412+
413+
fn insert_at(&mut self, insertion_point: InsertionPoint<Handle>, child: NodeOrText<Handle>) {
414+
match insertion_point {
415+
LastChild(parent) => self.sink.append(parent, child),
416+
BeforeSibling(sibling) => self.sink.append_before_sibling(sibling, child)
417+
}
418+
}
372419
}
373420

374421
impl<Handle, Sink> TokenSink
@@ -529,13 +576,18 @@ mod test {
529576
self.rcdom.create_comment(text)
530577
}
531578

579+
fn has_parent_node(&self, node: Handle) -> bool {
580+
let node = node.borrow();
581+
node.parent.is_some()
582+
}
583+
532584
fn append(&mut self, parent: Handle, child: NodeOrText<Handle>) {
533585
self.rcdom.append(parent, child)
534586
}
535587

536588
fn append_before_sibling(&mut self,
537589
sibling: Handle,
538-
child: NodeOrText<Handle>) -> Result<(), NodeOrText<Handle>> {
590+
child: NodeOrText<Handle>) {
539591
self.rcdom.append_before_sibling(sibling, child)
540592
}
541593

‎src/tree_builder/types.rs

+11
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)
Please sign in to comment.