Skip to content

Commit 4ea225e

Browse files
committed
Implement support for form owner
1 parent f026acf commit 4ea225e

File tree

6 files changed

+131
-47
lines changed

6 files changed

+131
-47
lines changed

dom_sink/src/owned_dom.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,17 @@ impl TreeSink for Sink {
197197
x == y
198198
}
199199

200+
fn same_home_subtree(&self, _x: Handle, _y: Handle) -> bool {
201+
true
202+
}
203+
204+
fn associate_with_form(&mut self, _target: Handle, _form: Handle) {
205+
}
206+
207+
fn has_parent_node(&self, node: Handle) -> bool {
208+
!node.parent.is_null()
209+
}
210+
200211
fn elem_name(&self, target: Handle) -> QualName {
201212
match target.node {
202213
Element(ref name, _) => name.clone(),
@@ -230,8 +241,9 @@ impl TreeSink for Sink {
230241

231242
fn append_before_sibling(&mut self,
232243
sibling: Handle,
233-
child: NodeOrText<Handle>) -> Result<(), NodeOrText<Handle>> {
234-
let (mut parent, i) = unwrap_or_return!(get_parent_and_index(sibling), Err(child));
244+
child: NodeOrText<Handle>) {
245+
let (mut parent, i) = get_parent_and_index(sibling)
246+
.expect("append_before_sibling called on node without parent");
235247

236248
let mut child = match (child, i) {
237249
// No previous node.
@@ -241,7 +253,7 @@ impl TreeSink for Sink {
241253
(AppendText(text), i) => {
242254
let prev = parent.children[i-1];
243255
if append_to_existing_text(prev, &text) {
244-
return Ok(());
256+
return;
245257
}
246258
self.new_node(Text(text))
247259
}
@@ -259,7 +271,6 @@ impl TreeSink for Sink {
259271

260272
child.parent = parent;
261273
parent.children.insert(i, child);
262-
Ok(())
263274
}
264275

265276
fn append_doctype_to_document(&mut self, name: String, public_id: String, system_id: String) {

dom_sink/src/rcdom.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,18 @@ impl TreeSink for RcDom {
163163
new_node(Comment(text))
164164
}
165165

166+
fn same_home_subtree(&self, _x: Handle, _y: Handle) -> bool {
167+
true
168+
}
169+
170+
fn associate_with_form(&mut self, _target: Handle, _form: Handle) {
171+
}
172+
173+
fn has_parent_node(&self, node: Handle) -> bool {
174+
let node = node.borrow();
175+
node.parent.is_some()
176+
}
177+
166178
fn append(&mut self, parent: Handle, child: NodeOrText<Handle>) {
167179
// Append to an existing Text node if we have one.
168180
match child {
@@ -181,8 +193,9 @@ impl TreeSink for RcDom {
181193

182194
fn append_before_sibling(&mut self,
183195
sibling: Handle,
184-
child: NodeOrText<Handle>) -> Result<(), NodeOrText<Handle>> {
185-
let (parent, i) = unwrap_or_return!(get_parent_and_index(&sibling), Err(child));
196+
child: NodeOrText<Handle>) {
197+
let (parent, i) = get_parent_and_index(&sibling)
198+
.expect("append_before_sibling called on node without parent");
186199

187200
let child = match (child, i) {
188201
// No previous node.
@@ -193,7 +206,7 @@ impl TreeSink for RcDom {
193206
let parent = parent.borrow();
194207
let prev = &parent.children[i-1];
195208
if append_to_existing_text(prev, &text) {
196-
return Ok(());
209+
return;
197210
}
198211
new_node(Text(text))
199212
}
@@ -211,7 +224,6 @@ impl TreeSink for RcDom {
211224

212225
child.borrow_mut().parent = Some(parent.clone().downgrade());
213226
parent.borrow_mut().children.insert(i, child);
214-
Ok(())
215227
}
216228

217229
fn append_doctype_to_document(&mut self, name: String, public_id: String, system_id: String) {

src/tree_builder/actions.rs

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

208208
// Insert at the "appropriate place for inserting a node".
209209
fn insert_appropriately(&mut self, child: NodeOrText<Handle>, override_target: Option<Handle>) {
210-
declare_tag_set!(foster_target = table tbody tfoot thead tr);
211-
let target = override_target.unwrap_or_else(|| self.current_node());
212-
if !(self.foster_parenting && self.elem_in(target.clone(), foster_target)) {
213-
// No foster parenting (the common case).
214-
return self.sink.append(target, child);
215-
}
216-
217-
// Foster parenting
218-
// FIXME: <template>
219-
let last_table = self.open_elems.iter()
220-
.enumerate()
221-
.rev()
222-
.filter(|&(_, e)| self.html_elem_named(e.clone(), atom!(table)))
223-
.next();
224-
225-
match last_table {
226-
None => {
227-
let html_elem = self.html_elem();
228-
self.sink.append(html_elem, child);
229-
}
230-
Some((idx, last_table)) => {
231-
// Try inserting "inside last table's parent node, immediately before last table"
232-
match self.sink.append_before_sibling(last_table.clone(), child) {
233-
Ok(()) => (),
234-
235-
// If last_table has no parent, we regain ownership of the child.
236-
// Insert "inside previous element, after its last child (if any)"
237-
Err(child) => {
238-
let previous_element = self.open_elems[idx-1].clone();
239-
self.sink.append(previous_element, child);
240-
}
241-
}
242-
}
243-
}
210+
let insertion_point = self.appropriate_place_for_insertion(override_target);
211+
self.insert_at(insertion_point, child);
244212
}
245213

246214
fn adoption_agency(&mut self, subject: Atom) {
@@ -755,10 +723,39 @@ impl<Handle, Sink> TreeBuilderActions<Handle>
755723
// FIXME: application cache selection algorithm
756724
}
757725

726+
// https://html.spec.whatwg.org/multipage/syntax.html#create-an-element-for-the-token
758727
fn insert_element(&mut self, push: PushFlag, ns: Namespace, name: Atom, attrs: Vec<Attribute>)
759728
-> Handle {
760-
let elem = self.sink.create_element(QualName::new(ns, name), attrs);
761-
self.insert_appropriately(AppendNode(elem.clone()), None);
729+
declare_tag_set!(form_associatable =
730+
button fieldset input keygen label
731+
object output select textarea img);
732+
733+
declare_tag_set!(reassociatable = form_associatable - img);
734+
735+
let qname = QualName::new(ns, name);
736+
let elem = self.sink.create_element(qname.clone(), attrs.clone());
737+
738+
let insertion_point = self.appropriate_place_for_insertion(None);
739+
let tree_node = match insertion_point {
740+
LastChild(ref p) |
741+
BeforeSibling(ref p) => p.clone()
742+
};
743+
744+
// Step 4.
745+
// TODO: Handle template element case
746+
if form_associatable(qname.clone())
747+
&& self.form_elem.is_some()
748+
&& !(reassociatable(qname.clone())
749+
&& attrs.iter().any(|a| a.name == qualname!("","form"))) {
750+
751+
let form = self.form_elem.as_ref().unwrap().clone();
752+
if self.sink.same_home_subtree(tree_node, form.clone()) {
753+
self.sink.associate_with_form(elem.clone(), form)
754+
}
755+
}
756+
757+
self.insert_at(insertion_point, AppendNode(elem.clone()));
758+
762759
match push {
763760
Push => self.push(&elem),
764761
NoPush => (),

src/tree_builder/interface.rs

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

64+
/// Are two handles present in the same tree
65+
/// https://html.spec.whatwg.org/multipage/infrastructure.html#home-subtree
66+
fn same_home_subtree(&self, x: Self::Handle, y: Self::Handle) -> bool;
67+
6468
/// What is the name of this element?
6569
///
6670
/// Should never be called on a non-element node;
@@ -76,15 +80,18 @@ pub trait TreeSink {
7680
/// Create a comment node.
7781
fn create_comment(&mut self, text: String) -> Self::Handle;
7882

83+
/// Does the node have a parent?
84+
fn has_parent_node(&self, node: Self::Handle) -> bool;
85+
7986
/// Append a node as the last child of the given node. If this would
8087
/// produce adjacent sibling text nodes, it should concatenate the text
8188
/// instead.
8289
///
8390
/// The child node will not already have a parent.
8491
fn append(&mut self, parent: Self::Handle, child: NodeOrText<Self::Handle>);
8592

86-
/// Append a node as the sibling immediately before the given node. If that node
87-
/// has no parent, do nothing and return Err(new_node).
93+
/// Append a node as the sibling immediately before the given node.
94+
/// This method will only be called if has_parent_node(sibling) is true
8895
///
8996
/// The tree builder promises that `sibling` is not a text node. However its
9097
/// old previous sibling, which would become the new node's previous sibling,
@@ -94,7 +101,7 @@ pub trait TreeSink {
94101
/// NB: `new_node` may have an old parent, from which it should be removed.
95102
fn append_before_sibling(&mut self,
96103
sibling: Self::Handle,
97-
new_node: NodeOrText<Self::Handle>) -> Result<(), NodeOrText<Self::Handle>>;
104+
new_node: NodeOrText<Self::Handle>);
98105

99106
/// Append a `DOCTYPE` element to the `Document` node.
100107
fn append_doctype_to_document(&mut self, name: String, public_id: String, system_id: String);
@@ -103,6 +110,9 @@ pub trait TreeSink {
103110
/// with that name already exists.
104111
fn add_attrs_if_missing(&mut self, target: Self::Handle, attrs: Vec<Attribute>);
105112

113+
/// Associate the given form-associatable element with the form element
114+
fn associate_with_form(&mut self, target: Self::Handle, form: Self::Handle);
115+
106116
/// Detach the given node from its parent.
107117
fn remove_from_parent(&mut self, target: Self::Handle);
108118

src/tree_builder/mod.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ pub struct TreeBuilder<Handle, Sink> {
145145
// FIXME: Auto-generate the trace hooks like Servo does.
146146
}
147147

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

369412
impl<Handle, Sink> TokenSink

src/tree_builder/types.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub use self::SplitStatus::*;
1616
pub use self::Token::*;
1717
pub use self::ProcessResult::*;
1818
pub use self::FormatEntry::*;
19+
pub use self::InsertionPoint::*;
1920

2021
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
2122
pub enum InsertionMode {
@@ -74,3 +75,13 @@ pub enum FormatEntry<Handle> {
7475
Element(Handle, Tag),
7576
Marker,
7677
}
78+
79+
pub enum InsertionPoint<Handle> {
80+
/// Holds the parent
81+
LastChild(Handle),
82+
/// Holds the sibling before which the node will be inserted
83+
/// TODO: Is the parent node needed? Is there a problem with using
84+
/// the sibling to find if the form element is in the same home
85+
/// subtree?
86+
BeforeSibling(Handle)
87+
}

0 commit comments

Comments
 (0)