diff options
Diffstat (limited to 'components/script/dom/servoparser/async_html.rs')
-rw-r--r-- | components/script/dom/servoparser/async_html.rs | 397 |
1 files changed, 269 insertions, 128 deletions
diff --git a/components/script/dom/servoparser/async_html.rs b/components/script/dom/servoparser/async_html.rs index 5fe911deb0b..051ea86cfb0 100644 --- a/components/script/dom/servoparser/async_html.rs +++ b/components/script/dom/servoparser/async_html.rs @@ -58,49 +58,77 @@ struct Attribute { #[derive(JSTraceable, MallocSizeOf)] enum ParseOperation { - GetTemplateContents { target: ParseNodeId, contents: ParseNodeId }, + GetTemplateContents { + target: ParseNodeId, + contents: ParseNodeId, + }, CreateElement { node: ParseNodeId, name: QualName, attrs: Vec<Attribute>, - current_line: u64 + current_line: u64, }, - CreateComment { text: String, node: ParseNodeId }, - AppendBeforeSibling { sibling: ParseNodeId, node: NodeOrText }, - AppendBasedOnParentNode { element: ParseNodeId, prev_element: ParseNodeId, node: NodeOrText }, - Append { parent: ParseNodeId, node: NodeOrText }, + CreateComment { + text: String, + node: ParseNodeId, + }, + AppendBeforeSibling { + sibling: ParseNodeId, + node: NodeOrText, + }, + AppendBasedOnParentNode { + element: ParseNodeId, + prev_element: ParseNodeId, + node: NodeOrText, + }, + Append { + parent: ParseNodeId, + node: NodeOrText, + }, AppendDoctypeToDocument { name: String, public_id: String, - system_id: String + system_id: String, }, - AddAttrsIfMissing { target: ParseNodeId, attrs: Vec<Attribute> }, - RemoveFromParent { target: ParseNodeId }, - MarkScriptAlreadyStarted { node: ParseNodeId }, - ReparentChildren { parent: ParseNodeId, new_parent: ParseNodeId }, + AddAttrsIfMissing { + target: ParseNodeId, + attrs: Vec<Attribute>, + }, + RemoveFromParent { + target: ParseNodeId, + }, + MarkScriptAlreadyStarted { + node: ParseNodeId, + }, + ReparentChildren { + parent: ParseNodeId, + new_parent: ParseNodeId, + }, AssociateWithForm { target: ParseNodeId, form: ParseNodeId, element: ParseNodeId, - prev_element: Option<ParseNodeId> + prev_element: Option<ParseNodeId>, }, CreatePI { node: ParseNodeId, target: String, - data: String + data: String, }, - Pop { node: ParseNodeId }, + Pop { + node: ParseNodeId, + }, SetQuirksMode { #[ignore_malloc_size_of = "Defined in style"] - mode: ServoQuirksMode + mode: ServoQuirksMode, }, } @@ -109,12 +137,12 @@ enum ToTokenizerMsg { // From HtmlTokenizer TokenizerResultDone { #[ignore_malloc_size_of = "Defined in html5ever"] - updated_input: VecDeque<SendTendril<UTF8>> + updated_input: VecDeque<SendTendril<UTF8>>, }, TokenizerResultScript { script: ParseNode, #[ignore_malloc_size_of = "Defined in html5ever"] - updated_input: VecDeque<SendTendril<UTF8>> + updated_input: VecDeque<SendTendril<UTF8>>, }, End, // Sent to Tokenizer to signify HtmlTokenizer's end method has returned @@ -126,7 +154,7 @@ enum ToTokenizerMsg { enum ToHtmlTokenizerMsg { Feed { #[ignore_malloc_size_of = "Defined in html5ever"] - input: VecDeque<SendTendril<UTF8>> + input: VecDeque<SendTendril<UTF8>>, }, End, SetPlainTextState, @@ -180,10 +208,10 @@ pub struct Tokenizer { impl Tokenizer { pub fn new( - document: &Document, - url: ServoUrl, - fragment_context: Option<super::FragmentContext>) - -> Self { + document: &Document, + url: ServoUrl, + fragment_context: Option<super::FragmentContext>, + ) -> Self { // Messages from the Tokenizer (main thread) to HtmlTokenizer (parser thread) let (to_html_tokenizer_sender, html_tokenizer_receiver) = channel(); // Messages from HtmlTokenizer and Sink (parser thread) to Tokenizer (main thread) @@ -194,7 +222,7 @@ impl Tokenizer { receiver: tokenizer_receiver, html_tokenizer_sender: to_html_tokenizer_sender, nodes: HashMap::new(), - url: url + url: url, }; tokenizer.insert_node(0, Dom::from_ref(document.upcast())); @@ -218,14 +246,18 @@ impl Tokenizer { // Create new thread for HtmlTokenizer. This is where parser actions // will be generated from the input provided. These parser actions are then passed // onto the main thread to be executed. - thread::Builder::new().name(String::from("HTML Parser")).spawn(move || { - run(sink, - fragment_context_is_some, - ctxt_parse_node, - form_parse_node, - to_tokenizer_sender, - html_tokenizer_receiver); - }).expect("HTML Parser thread spawning failed"); + thread::Builder::new() + .name(String::from("HTML Parser")) + .spawn(move || { + run( + sink, + fragment_context_is_some, + ctxt_parse_node, + form_parse_node, + to_tokenizer_sender, + html_tokenizer_receiver, + ); + }).expect("HTML Parser thread spawning failed"); tokenizer } @@ -238,31 +270,47 @@ impl Tokenizer { // Send message to parser thread, asking it to start reading from the input. // Parser operation messages will be sent to main thread as they are evaluated. - self.html_tokenizer_sender.send(ToHtmlTokenizerMsg::Feed { input: send_tendrils }).unwrap(); + self.html_tokenizer_sender + .send(ToHtmlTokenizerMsg::Feed { + input: send_tendrils, + }).unwrap(); loop { - match self.receiver.recv().expect("Unexpected channel panic in main thread.") { + match self + .receiver + .recv() + .expect("Unexpected channel panic in main thread.") + { ToTokenizerMsg::ProcessOperation(parse_op) => self.process_operation(parse_op), ToTokenizerMsg::TokenizerResultDone { updated_input } => { let buffer_queue = create_buffer_queue(updated_input); *input = buffer_queue; return Ok(()); }, - ToTokenizerMsg::TokenizerResultScript { script, updated_input } => { + ToTokenizerMsg::TokenizerResultScript { + script, + updated_input, + } => { let buffer_queue = create_buffer_queue(updated_input); *input = buffer_queue; let script = self.get_node(&script.id); return Err(DomRoot::from_ref(script.downcast().unwrap())); - } + }, ToTokenizerMsg::End => unreachable!(), }; } } pub fn end(&mut self) { - self.html_tokenizer_sender.send(ToHtmlTokenizerMsg::End).unwrap(); + self.html_tokenizer_sender + .send(ToHtmlTokenizerMsg::End) + .unwrap(); loop { - match self.receiver.recv().expect("Unexpected channel panic in main thread.") { + match self + .receiver + .recv() + .expect("Unexpected channel panic in main thread.") + { ToTokenizerMsg::ProcessOperation(parse_op) => self.process_operation(parse_op), ToTokenizerMsg::End => return, _ => unreachable!(), @@ -275,7 +323,9 @@ impl Tokenizer { } pub fn set_plaintext_state(&mut self) { - self.html_tokenizer_sender.send(ToHtmlTokenizerMsg::SetPlainTextState).unwrap(); + self.html_tokenizer_sender + .send(ToHtmlTokenizerMsg::SetPlainTextState) + .unwrap(); } fn insert_node(&mut self, id: ParseNodeId, node: Dom<Node>) { @@ -286,26 +336,27 @@ impl Tokenizer { self.nodes.get(id).expect("Node not found!") } - fn append_before_sibling(&mut self, sibling: ParseNodeId, node: NodeOrText) { let node = match node { - NodeOrText::Node(n) => HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id))), - NodeOrText::Text(text) => HtmlNodeOrText::AppendText( - Tendril::from(text) - ) + NodeOrText::Node(n) => { + HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id))) + }, + NodeOrText::Text(text) => HtmlNodeOrText::AppendText(Tendril::from(text)), }; let sibling = &**self.get_node(&sibling); - let parent = &*sibling.GetParentNode().expect("append_before_sibling called on node without parent"); + let parent = &*sibling + .GetParentNode() + .expect("append_before_sibling called on node without parent"); super::insert(parent, Some(sibling), node); } fn append(&mut self, parent: ParseNodeId, node: NodeOrText) { let node = match node { - NodeOrText::Node(n) => HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id))), - NodeOrText::Text(text) => HtmlNodeOrText::AppendText( - Tendril::from(text) - ) + NodeOrText::Node(n) => { + HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id))) + }, + NodeOrText::Text(text) => HtmlNodeOrText::AppendText(Tendril::from(text)), }; let parent = &**self.get_node(&parent); @@ -327,15 +378,23 @@ impl Tokenizer { fn process_operation(&mut self, op: ParseOperation) { let document = DomRoot::from_ref(&**self.get_node(&0)); - let document = document.downcast::<Document>().expect("Document node should be downcasted!"); + let document = document + .downcast::<Document>() + .expect("Document node should be downcasted!"); match op { ParseOperation::GetTemplateContents { target, contents } => { let target = DomRoot::from_ref(&**self.get_node(&target)); - let template = target.downcast::<HTMLTemplateElement>().expect( - "Tried to extract contents from non-template element while parsing"); + let template = target + .downcast::<HTMLTemplateElement>() + .expect("Tried to extract contents from non-template element while parsing"); self.insert_node(contents, Dom::from_ref(template.Content().upcast())); - } - ParseOperation::CreateElement { node, name, attrs, current_line } => { + }, + ParseOperation::CreateElement { + node, + name, + attrs, + current_line, + } => { let attrs = attrs .into_iter() .map(|attr| ElementAttribute::new(attr.name, DOMString::from(attr.value))) @@ -345,60 +404,85 @@ impl Tokenizer { attrs, &*self.document, ElementCreator::ParserCreated(current_line), - ParsingAlgorithm::Normal + ParsingAlgorithm::Normal, ); self.insert_node(node, Dom::from_ref(element.upcast())); - } + }, ParseOperation::CreateComment { text, node } => { let comment = Comment::new(DOMString::from(text), document); self.insert_node(node, Dom::from_ref(&comment.upcast())); - } + }, ParseOperation::AppendBeforeSibling { sibling, node } => { self.append_before_sibling(sibling, node); - } + }, ParseOperation::Append { parent, node } => { self.append(parent, node); - } - ParseOperation::AppendBasedOnParentNode { element, prev_element, node } => { + }, + ParseOperation::AppendBasedOnParentNode { + element, + prev_element, + node, + } => { if self.has_parent_node(element) { self.append_before_sibling(element, node); } else { self.append(prev_element, node); } - } - ParseOperation::AppendDoctypeToDocument { name, public_id, system_id } => { + }, + ParseOperation::AppendDoctypeToDocument { + name, + public_id, + system_id, + } => { let doctype = DocumentType::new( - DOMString::from(String::from(name)), Some(DOMString::from(public_id)), - Some(DOMString::from(system_id)), document); + DOMString::from(String::from(name)), + Some(DOMString::from(public_id)), + Some(DOMString::from(system_id)), + document, + ); - document.upcast::<Node>().AppendChild(doctype.upcast()).expect("Appending failed"); - } + document + .upcast::<Node>() + .AppendChild(doctype.upcast()) + .expect("Appending failed"); + }, ParseOperation::AddAttrsIfMissing { target, attrs } => { - let elem = self.get_node(&target).downcast::<Element>() + let elem = self + .get_node(&target) + .downcast::<Element>() .expect("tried to set attrs on non-Element in HTML parsing"); for attr in attrs { elem.set_attribute_from_parser(attr.name, DOMString::from(attr.value), None); } - } + }, ParseOperation::RemoveFromParent { target } => { if let Some(ref parent) = self.get_node(&target).GetParentNode() { parent.RemoveChild(&**self.get_node(&target)).unwrap(); } - } + }, ParseOperation::MarkScriptAlreadyStarted { node } => { let script = self.get_node(&node).downcast::<HTMLScriptElement>(); script.map(|script| script.set_already_started(true)); - } + }, ParseOperation::ReparentChildren { parent, new_parent } => { let parent = self.get_node(&parent); let new_parent = self.get_node(&new_parent); while let Some(child) = parent.GetFirstChild() { new_parent.AppendChild(&child).unwrap(); } - } - ParseOperation::AssociateWithForm { target, form, element, prev_element } => { + }, + ParseOperation::AssociateWithForm { + target, + form, + element, + prev_element, + } => { let tree_node = prev_element.map_or(element, |prev| { - if self.has_parent_node(element) { element } else { prev } + if self.has_parent_node(element) { + element + } else { + prev + } }); if !self.same_tree(tree_node, form) { @@ -416,47 +500,51 @@ impl Tokenizer { control.set_form_owner_from_parser(&form); } else { // TODO remove this code when keygen is implemented. - assert_eq!(node.NodeName(), "KEYGEN", "Unknown form-associatable element"); + assert_eq!( + node.NodeName(), + "KEYGEN", + "Unknown form-associatable element" + ); } - } + }, ParseOperation::Pop { node } => { vtable_for(self.get_node(&node)).pop(); - } + }, ParseOperation::CreatePI { node, target, data } => { let pi = ProcessingInstruction::new( DOMString::from(target), DOMString::from(data), - document); + document, + ); self.insert_node(node, Dom::from_ref(pi.upcast())); - } + }, ParseOperation::SetQuirksMode { mode } => { document.set_quirks_mode(mode); - } + }, } } } -fn run(sink: Sink, - fragment_context_is_some: bool, - ctxt_parse_node: Option<ParseNode>, - form_parse_node: Option<ParseNode>, - sender: Sender<ToTokenizerMsg>, - receiver: Receiver<ToHtmlTokenizerMsg>) { +fn run( + sink: Sink, + fragment_context_is_some: bool, + ctxt_parse_node: Option<ParseNode>, + form_parse_node: Option<ParseNode>, + sender: Sender<ToTokenizerMsg>, + receiver: Receiver<ToHtmlTokenizerMsg>, +) { let options = TreeBuilderOpts { ignore_missing_rules: true, - .. Default::default() + ..Default::default() }; let mut html_tokenizer = if fragment_context_is_some { - let tb = TreeBuilder::new_for_fragment( - sink, - ctxt_parse_node.unwrap(), - form_parse_node, - options); + let tb = + TreeBuilder::new_for_fragment(sink, ctxt_parse_node.unwrap(), form_parse_node, options); let tok_options = TokenizerOpts { initial_state: Some(tb.tokenizer_state_for_context_elem()), - .. Default::default() + ..Default::default() }; HtmlTokenizer::new(tb, tok_options) @@ -465,7 +553,10 @@ fn run(sink: Sink, }; loop { - match receiver.recv().expect("Unexpected channel panic in html parser thread") { + match receiver + .recv() + .expect("Unexpected channel panic in html parser thread") + { ToHtmlTokenizerMsg::Feed { input } => { let mut input = create_buffer_queue(input); let res = html_tokenizer.feed(&mut input); @@ -479,7 +570,10 @@ fn run(sink: Sink, let res = match res { TokenizerResult::Done => ToTokenizerMsg::TokenizerResultDone { updated_input }, - TokenizerResult::Script(script) => ToTokenizerMsg::TokenizerResultScript { script, updated_input } + TokenizerResult::Script(script) => ToTokenizerMsg::TokenizerResultScript { + script, + updated_input, + }, }; sender.send(res).unwrap(); }, @@ -488,7 +582,7 @@ fn run(sink: Sink, sender.send(ToTokenizerMsg::End).unwrap(); break; }, - ToHtmlTokenizerMsg::SetPlainTextState => html_tokenizer.set_plaintext_state() + ToHtmlTokenizerMsg::SetPlainTextState => html_tokenizer.set_plaintext_state(), }; } } @@ -517,7 +611,7 @@ impl Sink { id: 0, qual_name: None, }, - sender: sender + sender: sender, }; let data = ParseNodeData::default(); sink.insert_parse_node_data(0, data); @@ -536,7 +630,9 @@ impl Sink { } fn send_op(&self, op: ParseOperation) { - self.sender.send(ToTokenizerMsg::ProcessOperation(op)).unwrap(); + self.sender + .send(ToTokenizerMsg::ProcessOperation(op)) + .unwrap(); } fn insert_parse_node_data(&mut self, id: ParseNodeId, data: ParseNodeData) { @@ -544,18 +640,24 @@ impl Sink { } fn get_parse_node_data<'a>(&'a self, id: &'a ParseNodeId) -> &'a ParseNodeData { - self.parse_node_data.get(id).expect("Parse Node data not found!") + self.parse_node_data + .get(id) + .expect("Parse Node data not found!") } fn get_parse_node_data_mut<'a>(&'a mut self, id: &'a ParseNodeId) -> &'a mut ParseNodeData { - self.parse_node_data.get_mut(id).expect("Parse Node data not found!") + self.parse_node_data + .get_mut(id) + .expect("Parse Node data not found!") } } #[allow(unrooted_must_root)] impl TreeSink for Sink { type Output = Self; - fn finish(self) -> Self { self } + fn finish(self) -> Self { + self + } type Handle = ParseNode; @@ -572,7 +674,10 @@ impl TreeSink for Sink { let data = self.get_parse_node_data_mut(&target.id); data.contents = Some(node.clone()); } - self.send_op(ParseOperation::GetTemplateContents { target: target.id, contents: node.id }); + self.send_op(ParseOperation::GetTemplateContents { + target: target.id, + contents: node.id, + }); node } @@ -581,38 +686,52 @@ impl TreeSink for Sink { } fn elem_name<'a>(&self, target: &'a Self::Handle) -> ExpandedName<'a> { - target.qual_name.as_ref().expect("Expected qual name of node!").expanded() + target + .qual_name + .as_ref() + .expect("Expected qual name of node!") + .expanded() } - fn create_element(&mut self, name: QualName, html_attrs: Vec<HtmlAttribute>, _flags: ElementFlags) - -> Self::Handle { + fn create_element( + &mut self, + name: QualName, + html_attrs: Vec<HtmlAttribute>, + _flags: ElementFlags, + ) -> Self::Handle { let mut node = self.new_parse_node(); node.qual_name = Some(name.clone()); { let node_data = self.get_parse_node_data_mut(&node.id); - node_data.is_integration_point = html_attrs.iter() - .any(|attr| { + node_data.is_integration_point = html_attrs.iter().any(|attr| { let attr_value = &String::from(attr.value.clone()); (attr.name.local == local_name!("encoding") && attr.name.ns == ns!()) && - (attr_value.eq_ignore_ascii_case("text/html") || - attr_value.eq_ignore_ascii_case("application/xhtml+xml")) + (attr_value.eq_ignore_ascii_case("text/html") || + attr_value.eq_ignore_ascii_case("application/xhtml+xml")) }); } - let attrs = html_attrs.into_iter() - .map(|attr| Attribute { name: attr.name, value: String::from(attr.value) }).collect(); + let attrs = html_attrs + .into_iter() + .map(|attr| Attribute { + name: attr.name, + value: String::from(attr.value), + }).collect(); self.send_op(ParseOperation::CreateElement { node: node.id, name, attrs, - current_line: self.current_line + current_line: self.current_line, }); node } fn create_comment(&mut self, text: StrTendril) -> Self::Handle { let node = self.new_parse_node(); - self.send_op(ParseOperation::CreateComment { text: String::from(text), node: node.id }); + self.send_op(ParseOperation::CreateComment { + text: String::from(text), + node: node.id, + }); node } @@ -621,7 +740,7 @@ impl TreeSink for Sink { self.send_op(ParseOperation::CreatePI { node: node.id, target: String::from(target), - data: String::from(data) + data: String::from(data), }); node } @@ -641,14 +760,19 @@ impl TreeSink for Sink { }); } - fn append_before_sibling(&mut self, - sibling: &Self::Handle, - new_node: HtmlNodeOrText<Self::Handle>) { + fn append_before_sibling( + &mut self, + sibling: &Self::Handle, + new_node: HtmlNodeOrText<Self::Handle>, + ) { let new_node = match new_node { HtmlNodeOrText::AppendNode(node) => NodeOrText::Node(node), - HtmlNodeOrText::AppendText(text) => NodeOrText::Text(String::from(text)) + HtmlNodeOrText::AppendText(text) => NodeOrText::Text(String::from(text)), }; - self.send_op(ParseOperation::AppendBeforeSibling { sibling: sibling.id, node: new_node }); + self.send_op(ParseOperation::AppendBeforeSibling { + sibling: sibling.id, + node: new_node, + }); } fn append_based_on_parent_node( @@ -659,12 +783,12 @@ impl TreeSink for Sink { ) { let child = match child { HtmlNodeOrText::AppendNode(node) => NodeOrText::Node(node), - HtmlNodeOrText::AppendText(text) => NodeOrText::Text(String::from(text)) + HtmlNodeOrText::AppendText(text) => NodeOrText::Text(String::from(text)), }; self.send_op(ParseOperation::AppendBasedOnParentNode { element: elem.id, prev_element: prev_elem.id, - node: child + node: child, }); } @@ -684,24 +808,38 @@ impl TreeSink for Sink { fn append(&mut self, parent: &Self::Handle, child: HtmlNodeOrText<Self::Handle>) { let child = match child { HtmlNodeOrText::AppendNode(node) => NodeOrText::Node(node), - HtmlNodeOrText::AppendText(text) => NodeOrText::Text(String::from(text)) + HtmlNodeOrText::AppendText(text) => NodeOrText::Text(String::from(text)), }; - self.send_op(ParseOperation::Append { parent: parent.id, node: child }); + self.send_op(ParseOperation::Append { + parent: parent.id, + node: child, + }); } - fn append_doctype_to_document(&mut self, name: StrTendril, public_id: StrTendril, - system_id: StrTendril) { + fn append_doctype_to_document( + &mut self, + name: StrTendril, + public_id: StrTendril, + system_id: StrTendril, + ) { self.send_op(ParseOperation::AppendDoctypeToDocument { name: String::from(name), public_id: String::from(public_id), - system_id: String::from(system_id) + system_id: String::from(system_id), }); } fn add_attrs_if_missing(&mut self, target: &Self::Handle, html_attrs: Vec<HtmlAttribute>) { - let attrs = html_attrs.into_iter() - .map(|attr| Attribute { name: attr.name, value: String::from(attr.value) }).collect(); - self.send_op(ParseOperation::AddAttrsIfMissing { target: target.id, attrs }); + let attrs = html_attrs + .into_iter() + .map(|attr| Attribute { + name: attr.name, + value: String::from(attr.value), + }).collect(); + self.send_op(ParseOperation::AddAttrsIfMissing { + target: target.id, + attrs, + }); } fn remove_from_parent(&mut self, target: &Self::Handle) { @@ -717,7 +855,10 @@ impl TreeSink for Sink { } fn reparent_children(&mut self, parent: &Self::Handle, new_parent: &Self::Handle) { - self.send_op(ParseOperation::ReparentChildren { parent: parent.id, new_parent: new_parent.id }); + self.send_op(ParseOperation::ReparentChildren { + parent: parent.id, + new_parent: new_parent.id, + }); } /// <https://html.spec.whatwg.org/multipage/#html-integration-point> |