diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/script/dom/servoxmlparser.rs | 28 | ||||
-rw-r--r-- | components/script/lib.rs | 1 | ||||
-rw-r--r-- | components/script/parse/xml.rs | 79 | ||||
-rw-r--r-- | components/script/script_task.rs | 41 |
4 files changed, 145 insertions, 4 deletions
diff --git a/components/script/dom/servoxmlparser.rs b/components/script/dom/servoxmlparser.rs index 9de29cb392d..987c43f4982 100644 --- a/components/script/dom/servoxmlparser.rs +++ b/components/script/dom/servoxmlparser.rs @@ -2,9 +2,37 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use dom::bindings::js::{JS, Root}; use dom::bindings::reflector::Reflector; +use dom::bindings::trace::JSTraceable; +use dom::document::Document; +use dom::node::Node; +use dom::text::Text; +use url::Url; +use util::str::DOMString; +use xml5ever::tree_builder::{NodeOrText, TreeSink}; #[must_root] +#[derive(JSTraceable, HeapSizeOf)] +pub struct Sink { + pub base_url: Option<Url>, + pub document: JS<Document>, +} + +impl Sink { + #[allow(unrooted_must_root)] // method is only run at parse time + pub fn get_or_create(&self, child: NodeOrText<JS<Node>>) -> Root<Node> { + match child { + NodeOrText::AppendNode(n) => Root::from_ref(&*n), + NodeOrText::AppendText(t) => { + let s: String = t.into(); + let text = Text::new(DOMString::from(s), &self.document); + Root::upcast(text) + } + } + } +} +#[must_root] #[dom_struct] pub struct ServoXMLParser { reflector_: Reflector, diff --git a/components/script/lib.rs b/components/script/lib.rs index f652100bc49..692e4671951 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -79,6 +79,7 @@ extern crate url; extern crate util; extern crate uuid; extern crate websocket; +extern crate xml5ever; pub mod clipboard_provider; pub mod cors; diff --git a/components/script/parse/xml.rs b/components/script/parse/xml.rs index 907c1600f0c..2c2f97d3a78 100644 --- a/components/script/parse/xml.rs +++ b/components/script/parse/xml.rs @@ -4,12 +4,89 @@ #![allow(unrooted_must_root)] +use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; +use dom::bindings::inheritance::Castable; +use dom::bindings::js::{JS, RootedReference}; +use dom::comment::Comment; use dom::document::Document; +use dom::documenttype::DocumentType; +use dom::element::{Element, ElementCreator}; +use dom::node::Node; +use dom::processinginstruction::ProcessingInstruction; +use dom::servoxmlparser; +use msg::constellation_msg::PipelineId; +use std::borrow::Cow; +use string_cache::QualName; +use tendril::StrTendril; use url::Url; use util::str::DOMString; +use xml5ever::tokenizer::Attribute; +use xml5ever::tree_builder::{NodeOrText, TreeSink}; + +impl<'a> TreeSink for servoxmlparser::Sink { + type Handle = JS<Node>; + + fn parse_error(&mut self, msg: Cow<'static, str>) { + debug!("Parse error: {}", msg); + } + + fn get_document(&mut self) -> JS<Node> { + JS::from_ref(self.document.upcast()) + } + + fn elem_name(&self, target: &JS<Node>) -> QualName { + let elem = target.downcast::<Element>() + .expect("tried to get name of non-Element in XML parsing"); + QualName { + ns: elem.namespace().clone(), + local: elem.local_name().clone(), + } + } + + fn create_element(&mut self, name: QualName, attrs: Vec<Attribute>) + -> JS<Node> { + let elem = Element::create(name, None, &*self.document, + ElementCreator::ParserCreated); + + for attr in attrs { + elem.set_attribute_from_parser(attr.name, DOMString::from(String::from(attr.value)), None); + } + + JS::from_ref(elem.upcast()) + } + + fn create_comment(&mut self, text: StrTendril) -> JS<Node> { + let comment = Comment::new(DOMString::from(String::from(text)), &*self.document); + JS::from_ref(comment.upcast()) + } + + fn append(&mut self, parent: JS<Node>, child: NodeOrText<JS<Node>>) { + let child = self.get_or_create(child); + + assert!(parent.AppendChild(child.r()).is_ok()); + } + + fn append_doctype_to_document(&mut self, name: StrTendril, public_id: StrTendril, + system_id: StrTendril) { + let doc = &*self.document; + let doctype = DocumentType::new( + DOMString::from(String::from(name)), Some(DOMString::from(String::from(public_id))), + Some(DOMString::from(String::from(system_id))), doc); + doc.upcast::<Node>().AppendChild(doctype.upcast()).expect("Appending failed"); + } + + fn create_pi(&mut self, target: StrTendril, data: StrTendril) -> JS<Node> { + let doc = &*self.document; + let pi = ProcessingInstruction::new( + DOMString::from(String::from(target)), DOMString::from(String::from(data)), + doc); + JS::from_ref(pi.upcast()) + } +} + pub enum ParseContext { - Owner(Option<i32>) + Owner(Option<PipelineId>) } diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 736c95b0d2d..374b9ec70a9 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -75,6 +75,7 @@ use net_traits::{AsyncResponseTarget, ControlMsg, LoadConsumer, Metadata, Resour use network_listener::NetworkListener; use page::{Frame, IterablePage, Page}; use parse::html::{ParseContext, parse_html}; +use parse::xml::{self, parse_xml}; use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan}; use profile_traits::time::{self, ProfilerCategory, profile}; use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent}; @@ -1659,22 +1660,43 @@ impl ScriptTask { }); let content_type = match metadata.content_type { + + Some(ContentType(Mime(TopLevel::Text, SubLevel::Xml, _))) => { + Some(DOMString::from("text/xml")) + } + Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) => { Some(DOMString::from("text/plain")) } + _ => None }; let loader = DocumentLoader::new_with_task(self.resource_task.clone(), Some(page.pipeline()), Some(incomplete.url.clone())); - let document = Document::new(window.r(), + let document; + match metadata.content_type { + + Some(ContentType(Mime(TopLevel::Text, SubLevel::Xml, _))) => { + document = Document::new(window.r(), + Some(final_url.clone()), + IsHTMLDocument::NonHTMLDocument, + content_type, + last_modified, + DocumentSource::NotFromParser, + loader); + } + _ => { + document = Document::new(window.r(), Some(final_url.clone()), IsHTMLDocument::HTMLDocument, content_type, last_modified, DocumentSource::FromParser, loader); + } + } let frame_element = frame_element.r().map(Castable::upcast); window.init_browsing_context(document.r(), frame_element); @@ -1724,8 +1746,21 @@ impl ScriptTask { DOMString::new() }; - parse_html(document.r(), parse_input, final_url, - ParseContext::Owner(Some(incomplete.pipeline_id))); + match metadata.content_type { + + Some(ContentType(Mime(TopLevel::Text, SubLevel::Xml, _))) => { + parse_xml(document.r(), + parse_input, + final_url, + xml::ParseContext::Owner(Some(incomplete.pipeline_id))); + } + _ => { + parse_html(document.r(), + parse_input, + final_url, + ParseContext::Owner(Some(incomplete.pipeline_id))); + } + } page_remover.neuter(); |