diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs index 6d8f894a074..749174d1417 100644 --- a/components/script/dom/servoparser/html.rs +++ b/components/script/dom/servoparser/html.rs @@ -14,7 +14,7 @@ use dom::documenttype::DocumentType; use dom::element::Element; use dom::htmlscriptelement::HTMLScriptElement; use dom::htmltemplateelement::HTMLTemplateElement; -use dom::node::Node; +use dom::node::{Node, TreeIterator}; use dom::processinginstruction::ProcessingInstruction; use dom::servoparser::Sink; use html5ever::QualName; @@ -115,79 +115,137 @@ unsafe impl JSTraceable for HtmlTokenizer, Sink>> { } } +fn start_element(node: &Element, serializer: &mut S) -> io::Result<()> { + let name = QualName::new(None, node.namespace().clone(), + node.local_name().clone()); + let attrs = node.attrs().iter().map(|attr| { + let qname = QualName::new(None, attr.namespace().clone(), + attr.local_name().clone()); + let value = attr.value().clone(); + (qname, value) + }).collect::>(); + let attr_refs = attrs.iter().map(|&(ref qname, ref value)| { + let ar: AttrRef = (&qname, &**value); + ar + }); + serializer.start_elem(name, attr_refs)?; + Ok(()) +} + +fn end_element(node: &Element, serializer: &mut S) -> io::Result<()> { + let name = QualName::new(None, node.namespace().clone(), + node.local_name().clone()); + serializer.end_elem(name) +} + + +enum SerializationCommand { + OpenElement(Root), + CloseElement(Root), + SerializeNonelement(Root), +} + +struct SerializationIterator { + stack: Vec, +} + +fn rev_children_iter(n: &Node) -> impl Iterator>{ + match n.downcast::() { + Some(t) => t.Content().upcast::().rev_children(), + None => n.rev_children(), + } +} + +impl SerializationIterator { + fn new(node: &Node, skip_first: bool) -> SerializationIterator { + let mut ret = SerializationIterator { + stack: vec![], + }; + if skip_first { + for c in rev_children_iter(node) { + ret.push_node(&*c); + } + } else { + ret.push_node(node); + } + ret + } + + fn push_node(&mut self, n: &Node) { + match n.downcast::() { + Some(e) => self.stack.push(SerializationCommand::OpenElement(Root::from_ref(e))), + None => self.stack.push(SerializationCommand::SerializeNonelement(Root::from_ref(n))), + } + } +} + +impl Iterator for SerializationIterator { + type Item = SerializationCommand; + + fn next(&mut self) -> Option { + let res = self.stack.pop(); + + if let Some(SerializationCommand::OpenElement(ref e)) = res { + self.stack.push(SerializationCommand::CloseElement(e.clone())); + for c in rev_children_iter(&*e.upcast::()) { + self.push_node(&c); + } + } + + res + } +} + impl<'a> Serialize for &'a Node { fn serialize(&self, serializer: &mut S, traversal_scope: TraversalScope) -> io::Result<()> { let node = *self; - match (traversal_scope, node.type_id()) { - (_, NodeTypeId::Element(..)) => { - let elem = node.downcast::().unwrap(); - let name = QualName::new(None, elem.namespace().clone(), - elem.local_name().clone()); - if traversal_scope == IncludeNode { - let attrs = elem.attrs().iter().map(|attr| { - let qname = QualName::new(None, attr.namespace().clone(), - attr.local_name().clone()); - let value = attr.value().clone(); - (qname, value) - }).collect::>(); - let attr_refs = attrs.iter().map(|&(ref qname, ref value)| { - let ar: AttrRef = (&qname, &**value); - ar - }); - serializer.start_elem(name.clone(), attr_refs)?; + + + let iter = SerializationIterator::new(node, traversal_scope == ChildrenOnly); + + for cmd in iter { + match cmd { + SerializationCommand::OpenElement(n) => { + start_element(&n, serializer)?; } - let children = if let Some(tpl) = node.downcast::() { - // https://github.com/w3c/DOM-Parsing/issues/1 - tpl.Content().upcast::().children() - } else { - node.children() - }; - - for handle in children { - (&*handle).serialize(serializer, IncludeNode)?; + SerializationCommand::CloseElement(n) => { + end_element(&&n, serializer)?; } - if traversal_scope == IncludeNode { - serializer.end_elem(name.clone())?; + SerializationCommand::SerializeNonelement(n) => { + match n.type_id() { + NodeTypeId::DocumentType => { + let doctype = n.downcast::().unwrap(); + serializer.write_doctype(&doctype.name())?; + }, + + NodeTypeId::CharacterData(CharacterDataTypeId::Text) => { + let cdata = n.downcast::().unwrap(); + serializer.write_text(&cdata.data())?; + }, + + NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => { + let cdata = n.downcast::().unwrap(); + serializer.write_comment(&cdata.data())?; + }, + + NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => { + let pi = n.downcast::().unwrap(); + let data = pi.upcast::().data(); + serializer.write_processing_instruction(&pi.target(), &data)?; + }, + + NodeTypeId::DocumentFragment => {} + + NodeTypeId::Document(_) => panic!("Can't serialize Document node itself"), + NodeTypeId::Element(_) => panic!("Element shouldn't appear here"), + } } - Ok(()) - }, - - (ChildrenOnly, NodeTypeId::Document(_)) => { - for handle in node.children() { - (&*handle).serialize(serializer, IncludeNode)?; - } - Ok(()) - }, - - (ChildrenOnly, _) => Ok(()), - - (IncludeNode, NodeTypeId::DocumentType) => { - let doctype = node.downcast::().unwrap(); - serializer.write_doctype(&doctype.name()) - }, - - (IncludeNode, NodeTypeId::CharacterData(CharacterDataTypeId::Text)) => { - let cdata = node.downcast::().unwrap(); - serializer.write_text(&cdata.data()) - }, - - (IncludeNode, NodeTypeId::CharacterData(CharacterDataTypeId::Comment)) => { - let cdata = node.downcast::().unwrap(); - serializer.write_comment(&cdata.data()) - }, - - (IncludeNode, NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)) => { - let pi = node.downcast::().unwrap(); - let data = pi.upcast::().data(); - serializer.write_processing_instruction(&pi.target(), &data) - }, - - (IncludeNode, NodeTypeId::DocumentFragment) => Ok(()), - - (IncludeNode, NodeTypeId::Document(_)) => panic!("Can't serialize Document node itself"), + } } + + Ok(()) } } diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 6506961c996..ddd21a26cc8 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -13737,6 +13737,12 @@ {} ] ], + "mozilla/deep_serialization_succeeds.html": [ + [ + "/_mozilla/mozilla/deep_serialization_succeeds.html", + {} + ] + ], "mozilla/deterministic-raf.html": [ [ "/_mozilla/mozilla/deterministic-raf.html", @@ -26886,6 +26892,10 @@ "67d8cdd3e3a1656ba315fcbf6dae7236680bac16", "reftest" ], + "mozilla/deep_serialization_succeeds.html": [ + "cb3d201d577c17d19babf1f6c04ba882fa42048e", + "testharness" + ], "mozilla/details_ui_closed.html": [ "2acbe3afbec267bad4dd986803e636740a707507", "reftest" diff --git a/tests/wpt/mozilla/tests/mozilla/deep_serialization_succeeds.html b/tests/wpt/mozilla/tests/mozilla/deep_serialization_succeeds.html new file mode 100644 index 00000000000..086dc4d34de --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/deep_serialization_succeeds.html @@ -0,0 +1,28 @@ + + + +Deep Serialization Test + + + + +
+ + +