diff options
author | Keegan McAllister <kmcallister@mozilla.com> | 2014-09-19 14:02:22 -0700 |
---|---|---|
committer | Keegan McAllister <kmcallister@mozilla.com> | 2014-10-16 13:06:34 -0700 |
commit | 9da7679367eba53d0f86bff30bc8b005940f044e (patch) | |
tree | ac2dadb2f3f98939c3245b5ed58c6beba1730c8c /components/script/dom | |
parent | 3fbb25cc430c9dcf3ed06b6e86b8a64738493e86 (diff) | |
download | servo-9da7679367eba53d0f86bff30bc8b005940f044e.tar.gz servo-9da7679367eba53d0f86bff30bc8b005940f044e.zip |
Use html5ever for HTML parsing
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/trace.rs | 15 | ||||
-rw-r--r-- | components/script/dom/document.rs | 21 | ||||
-rw-r--r-- | components/script/dom/element.rs | 22 | ||||
-rw-r--r-- | components/script/dom/node.rs | 22 | ||||
-rw-r--r-- | components/script/dom/servohtmlparser.rs | 105 | ||||
-rw-r--r-- | components/script/dom/webidls/ServoHTMLParser.webidl | 9 |
6 files changed, 167 insertions, 27 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 18fb7c6e8d8..a7fffe4a11e 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -42,7 +42,6 @@ use std::collections::hashmap::HashMap; use collections::hash::Hash; use style::PropertyDeclarationBlock; use std::comm::{Receiver, Sender}; -use hubbub::hubbub::QuirksMode; use string_cache::{Atom, Namespace}; use js::rust::Cx; use http::headers::response::HeaderCollection as ResponseHeaderCollection; @@ -55,7 +54,9 @@ use servo_msg::constellation_msg::ConstellationChan; use servo_util::smallvec::{SmallVec1, SmallVec}; use servo_util::str::LengthOrPercentageOrAuto; use layout_interface::{LayoutRPC, LayoutChan}; +use dom::node::{Node, TrustedNodeAddress}; use dom::bindings::utils::WindowProxyHandler; +use html5ever::tree_builder::QuirksMode; impl<T: Reflectable> JSTraceable for JS<T> { fn trace(&self, trc: *mut JSTracer) { @@ -207,6 +208,7 @@ untraceable!(ConstellationChan) untraceable!(LayoutChan) untraceable!(WindowProxyHandler) untraceable!(UntrustedNodeAddress) +untraceable!(LengthOrPercentageOrAuto) impl<'a> JSTraceable for &'a str { #[inline] @@ -236,5 +238,12 @@ impl JSTraceable for Box<LayoutRPC+'static> { } } -untraceable!(LengthOrPercentageOrAuto) - +impl JSTraceable for TrustedNodeAddress { + fn trace(&self, s: *mut JSTracer) { + let TrustedNodeAddress(addr) = *self; + let node = addr as *const Node; + unsafe { + JS::from_raw(node).trace(s) + } + } +} diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 4843fe0207c..8d767be9016 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -52,12 +52,12 @@ use dom::range::Range; use dom::treewalker::TreeWalker; use dom::uievent::UIEvent; use dom::window::{Window, WindowHelpers}; -use html::hubbub_html_parser::build_element_from_tag; -use hubbub::hubbub::{QuirksMode, NoQuirks, LimitedQuirks, FullQuirks}; +use parse::html::build_element_from_tag; use servo_util::namespace; use servo_util::str::{DOMString, split_html_space_chars}; -use string_cache::Atom; +use html5ever::tree_builder::{QuirksMode, NoQuirks, LimitedQuirks, Quirks}; +use string_cache::{Atom, QualName}; use url::Url; use std::collections::hashmap::HashMap; @@ -426,7 +426,7 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { fn CompatMode(self) -> DOMString { match self.quirks_mode.get() { LimitedQuirks | NoQuirks => "CSS1Compat".to_string(), - FullQuirks => "BackCompat".to_string() + Quirks => "BackCompat".to_string() } } @@ -492,7 +492,8 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { return Err(InvalidCharacter); } let local_name = local_name.as_slice().to_ascii_lower(); - Ok(build_element_from_tag(local_name, ns!(HTML), None, self)) + let name = QualName::new(ns!(HTML), Atom::from_slice(local_name.as_slice())); + Ok(build_element_from_tag(name, None, self)) } // http://dom.spec.whatwg.org/#dom-document-createelementns @@ -512,9 +513,9 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { QName => {} } - let (prefix_from_qname, - local_name_from_qname) = get_attribute_parts(qualified_name.as_slice()); - match (&ns, prefix_from_qname.clone(), local_name_from_qname.as_slice()) { + let (prefix_from_qname, local_name_from_qname) + = get_attribute_parts(qualified_name.as_slice()); + match (&ns, prefix_from_qname, local_name_from_qname) { // throw if prefix is not null and namespace is null (&ns!(""), Some(_), _) => { debug!("Namespace can't be null with a non-null prefix"); @@ -536,8 +537,8 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { } if ns == ns!(HTML) { - Ok(build_element_from_tag(local_name_from_qname.to_string(), ns, - prefix_from_qname.map(|s| s.to_string()), self)) + let name = QualName::new(ns!(HTML), Atom::from_slice(local_name_from_qname)); + Ok(build_element_from_tag(name, prefix_from_qname.map(|s| s.to_string()), self)) } else { Ok(Element::new(local_name_from_qname.to_string(), ns, prefix_from_qname.map(|s| s.to_string()), self)) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 793ca673dac..0ad67d7ee67 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -42,7 +42,7 @@ use servo_util::str::{DOMString, LengthOrPercentageOrAuto}; use std::ascii::StrAsciiExt; use std::default::Default; use std::mem; -use string_cache::{Atom, Namespace}; +use string_cache::{Atom, Namespace, QualName}; use url::UrlParser; #[dom_struct] @@ -397,9 +397,8 @@ pub trait AttributeHandlers { fn get_attributes(self, local_name: &Atom) -> Vec<Temporary<Attr>>; fn set_attribute_from_parser(self, - local_name: Atom, + name: QualName, value: DOMString, - namespace: Namespace, prefix: Option<DOMString>); fn set_attribute(self, name: &Atom, value: AttrValue); fn do_set_attribute(self, local_name: Atom, value: AttrValue, @@ -445,19 +444,24 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { } fn set_attribute_from_parser(self, - local_name: Atom, + qname: QualName, value: DOMString, - namespace: Namespace, prefix: Option<DOMString>) { + // Don't set if the attribute already exists, so we can handle add_attrs_if_missing + if self.attrs.borrow().iter().map(|attr| attr.root()) + .any(|a| *a.local_name() == qname.local && *a.namespace() == qname.ns) { + return; + } + let name = match prefix { - None => local_name.clone(), + None => qname.local.clone(), Some(ref prefix) => { - let name = format!("{:s}:{:s}", *prefix, local_name.as_slice()); + let name = format!("{:s}:{:s}", *prefix, qname.local.as_slice()); Atom::from_slice(name.as_slice()) }, }; - let value = self.parse_attribute(&namespace, &local_name, value); - self.do_set_attribute(local_name, value, name, namespace, prefix, |_| false) + let value = self.parse_attribute(&qname.ns, &qname.local, value); + self.do_set_attribute(qname.local, value, name, qname.ns, prefix, |_| false) } fn set_attribute(self, name: &Atom, value: AttrValue) { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 94753b96d48..724f9423bb3 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -44,9 +44,9 @@ use dom::text::Text; use dom::virtualmethods::{VirtualMethods, vtable_for}; use dom::window::Window; use geom::rect::Rect; -use html::hubbub_html_parser::build_element_from_tag; +use parse::html::build_element_from_tag; use layout_interface::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC, - LayoutChan, ReapLayoutDataMsg, TrustedNodeAddress}; + LayoutChan, ReapLayoutDataMsg}; use devtools_traits::NodeInfo; use script_traits::UntrustedNodeAddress; use servo_util::geometry::Au; @@ -56,7 +56,7 @@ use style::{parse_selector_list_from_str, matches}; use js::jsapi::{JSContext, JSObject, JSTracer, JSRuntime}; use js::jsfriendapi; use libc; -use libc::uintptr_t; +use libc::{uintptr_t, c_void}; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::default::Default; use std::iter::{Map, Filter}; @@ -65,6 +65,7 @@ use style; use style::ComputedValues; use sync::Arc; use uuid; +use string_cache::QualName; // // The basic Node structure @@ -1530,8 +1531,12 @@ impl Node { }, ElementNodeTypeId(..) => { let element: JSRef<Element> = ElementCast::to_ref(node).unwrap(); - let element = build_element_from_tag(element.local_name().as_slice().to_string(), - element.namespace().clone(), Some(element.prefix().as_slice().to_string()), *document); + let name = QualName { + ns: element.namespace().clone(), + local: element.local_name().clone() + }; + let element = build_element_from_tag(name, + Some(element.prefix().as_slice().to_string()), *document); NodeCast::from_temporary(element) }, TextNodeTypeId => { @@ -2159,6 +2164,13 @@ impl Reflectable for Node { } } +/// The address of a node known to be valid. These are sent from script to layout, +/// and are also used in the HTML parser interface. + +#[allow(raw_pointer_deriving)] +#[deriving(Clone, PartialEq, Eq)] +pub struct TrustedNodeAddress(pub *const c_void); + pub fn document_from_node<T: NodeBase+Reflectable>(derived: JSRef<T>) -> Temporary<Document> { let node: JSRef<Node> = NodeCast::from_ref(derived); node.owner_doc() diff --git a/components/script/dom/servohtmlparser.rs b/components/script/dom/servohtmlparser.rs new file mode 100644 index 00000000000..c4d594186c8 --- /dev/null +++ b/components/script/dom/servohtmlparser.rs @@ -0,0 +1,105 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +//! The bulk of the HTML parser integration is in `script::parse::html`. +//! This module is mostly about its interaction with DOM memory management. + +use dom::bindings::codegen::Bindings::ServoHTMLParserBinding; +use dom::bindings::global; +use dom::bindings::trace::JSTraceable; +use dom::bindings::js::{JS, JSRef, Temporary}; +use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; +use dom::node::TrustedNodeAddress; +use dom::document::Document; +use parse::html::JSMessage; + +use std::default::Default; +use std::cell::RefCell; +use url::Url; +use js::jsapi::JSTracer; +use html5ever::tokenizer; +use html5ever::tree_builder; +use html5ever::tree_builder::{TreeBuilder, TreeBuilderOpts}; + +#[must_root] +#[jstraceable] +pub struct Sink { + pub js_chan: Sender<JSMessage>, + pub base_url: Option<Url>, + pub document: JS<Document>, +} + +pub type Tokenizer = tokenizer::Tokenizer<TreeBuilder<TrustedNodeAddress, Sink>>; + +// NB: JSTraceable is *not* auto-derived. +// You must edit the impl below if you add fields! +#[must_root] +#[privatize] +pub struct ServoHTMLParser { + reflector_: Reflector, + tokenizer: RefCell<Tokenizer>, +} + +impl ServoHTMLParser { + #[allow(unrooted_must_root)] + pub fn new(js_chan: Sender<JSMessage>, base_url: Option<Url>, document: JSRef<Document>) + -> Temporary<ServoHTMLParser> { + let window = document.window().root(); + let sink = Sink { + js_chan: js_chan, + base_url: base_url, + document: JS::from_rooted(document), + }; + + let tb = TreeBuilder::new(sink, TreeBuilderOpts { + ignore_missing_rules: true, + .. Default::default() + }); + + let tok = tokenizer::Tokenizer::new(tb, Default::default()); + + let parser = ServoHTMLParser { + reflector_: Reflector::new(), + tokenizer: RefCell::new(tok), + }; + + reflect_dom_object(box parser, &global::Window(*window), ServoHTMLParserBinding::Wrap) + } + + #[inline] + pub fn tokenizer<'a>(&'a self) -> &'a RefCell<Tokenizer> { + &self.tokenizer + } +} + +impl Reflectable for ServoHTMLParser { + fn reflector<'a>(&'a self) -> &'a Reflector { + &self.reflector_ + } +} + +struct Tracer { + trc: *mut JSTracer, +} + +impl tree_builder::Tracer<TrustedNodeAddress> for Tracer { + fn trace_handle(&self, node: TrustedNodeAddress) { + node.trace(self.trc); + } +} + +impl JSTraceable for ServoHTMLParser { + fn trace(&self, trc: *mut JSTracer) { + let tracer = Tracer { + trc: trc, + }; + let tracer = &tracer as &tree_builder::Tracer<TrustedNodeAddress>; + + self.reflector_.trace(trc); + let tokenizer = self.tokenizer.borrow(); + let tree_builder = tokenizer.sink(); + tree_builder.trace_handles(tracer); + tree_builder.sink().trace(trc); + } +} diff --git a/components/script/dom/webidls/ServoHTMLParser.webidl b/components/script/dom/webidls/ServoHTMLParser.webidl new file mode 100644 index 00000000000..02ad2667a96 --- /dev/null +++ b/components/script/dom/webidls/ServoHTMLParser.webidl @@ -0,0 +1,9 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +// FIXME: find a better way to hide this from content (#3688) +[NoInterfaceObject] +interface ServoHTMLParser { +}; |