aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
authorAnthony Ramine <n.oxyde@gmail.com>2016-10-10 16:11:00 +0200
committerAnthony Ramine <n.oxyde@gmail.com>2016-10-11 15:08:37 +0200
commit1405be691776e48836f651c3c616dc12322a0932 (patch)
treeae98c4b4e517879cfec1742464e1e44dca1afb4e /components/script
parent609299e1e45e93939f75f8439fc7ac3276ca5881 (diff)
downloadservo-1405be691776e48836f651c3c616dc12322a0932.tar.gz
servo-1405be691776e48836f651c3c616dc12322a0932.zip
Unify ServoHTMLParser and ServoXMLParser in ServoParser
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/document.rs8
-rw-r--r--components/script/dom/mod.rs2
-rw-r--r--components/script/dom/servohtmlparser.rs235
-rw-r--r--components/script/dom/servoparser.rs215
-rw-r--r--components/script/dom/servoxmlparser.rs185
-rw-r--r--components/script/dom/webidls/ServoHTMLParser.webidl11
-rw-r--r--components/script/dom/webidls/ServoParser.webidl2
-rw-r--r--components/script/dom/webidls/ServoXMLParser.webidl11
-rw-r--r--components/script/parse/html.rs54
-rw-r--r--components/script/parse/mod.rs192
-rw-r--r--components/script/parse/xml.rs22
-rw-r--r--components/script/script_thread.rs9
12 files changed, 300 insertions, 646 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 2fdd36667cf..242d2bf98c1 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -76,6 +76,7 @@ use dom::popstateevent::PopStateEvent;
use dom::processinginstruction::ProcessingInstruction;
use dom::progressevent::ProgressEvent;
use dom::range::Range;
+use dom::servoparser::ServoParser;
use dom::storageevent::StorageEvent;
use dom::stylesheetlist::StyleSheetList;
use dom::text::Text;
@@ -103,7 +104,6 @@ use net_traits::request::RequestInit;
use net_traits::response::HttpsState;
use num_traits::ToPrimitive;
use origin::Origin;
-use parse::{MutNullableParserField, ParserRef, ParserRoot};
use script_layout_interface::message::{Msg, ReflowQueryType};
use script_thread::{MainThreadScriptMsg, Runnable};
use script_traits::{AnimationState, CompositorEvent, MouseButton, MouseEventType, MozBrowserEvent};
@@ -226,7 +226,7 @@ pub struct Document {
/// Tracks all outstanding loads related to this document.
loader: DOMRefCell<DocumentLoader>,
/// The current active HTML parser, to allow resuming after interruptions.
- current_parser: MutNullableParserField,
+ current_parser: MutNullableHeap<JS<ServoParser>>,
/// When we should kick off a reflow. This happens during parsing.
reflow_timeout: Cell<Option<u64>>,
/// The cached first `base` element with an `href` attribute.
@@ -1627,11 +1627,11 @@ impl Document {
global_scope.constellation_chan().send(load_event).unwrap();
}
- pub fn set_current_parser(&self, script: Option<ParserRef>) {
+ pub fn set_current_parser(&self, script: Option<&ServoParser>) {
self.current_parser.set(script);
}
- pub fn get_current_parser(&self) -> Option<ParserRoot> {
+ pub fn get_current_parser(&self) -> Option<Root<ServoParser>> {
self.current_parser.get()
}
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index bf68603ff13..afc91be7c4b 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -386,9 +386,7 @@ pub mod serviceworker;
pub mod serviceworkercontainer;
pub mod serviceworkerglobalscope;
pub mod serviceworkerregistration;
-pub mod servohtmlparser;
pub mod servoparser;
-pub mod servoxmlparser;
pub mod storage;
pub mod storageevent;
pub mod stylesheet;
diff --git a/components/script/dom/servohtmlparser.rs b/components/script/dom/servohtmlparser.rs
deleted file mode 100644
index ec01187e2b4..00000000000
--- a/components/script/dom/servohtmlparser.rs
+++ /dev/null
@@ -1,235 +0,0 @@
-/* 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::cell::DOMRefCell;
-use dom::bindings::codegen::Bindings::ServoHTMLParserBinding;
-use dom::bindings::inheritance::Castable;
-use dom::bindings::js::{JS, Root};
-use dom::bindings::reflector::reflect_dom_object;
-use dom::bindings::trace::JSTraceable;
-use dom::document::Document;
-use dom::globalscope::GlobalScope;
-use dom::node::Node;
-use dom::servoparser::ServoParser;
-use dom::window::Window;
-use html5ever::tokenizer;
-use html5ever::tree_builder;
-use html5ever::tree_builder::{TreeBuilder, TreeBuilderOpts};
-use js::jsapi::JSTracer;
-use msg::constellation_msg::PipelineId;
-use parse::{Parser, ParserRef};
-use profile_traits::time::{TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType, profile};
-use profile_traits::time::ProfilerCategory;
-use script_thread::ScriptThread;
-use std::cell::Cell;
-use std::default::Default;
-use url::Url;
-
-#[must_root]
-#[derive(JSTraceable, HeapSizeOf)]
-pub struct Sink {
- pub base_url: Option<Url>,
- pub document: JS<Document>,
-}
-
-/// FragmentContext is used only to pass this group of related values
-/// into functions.
-#[derive(Copy, Clone)]
-pub struct FragmentContext<'a> {
- pub context_elem: &'a Node,
- pub form_elem: Option<&'a Node>,
-}
-
-pub type Tokenizer = tokenizer::Tokenizer<TreeBuilder<JS<Node>, Sink>>;
-
-#[dom_struct]
-pub struct ServoHTMLParser {
- servoparser: ServoParser,
- #[ignore_heap_size_of = "Defined in html5ever"]
- tokenizer: DOMRefCell<Tokenizer>,
- /// True if this parser should avoid passing any further data to the tokenizer.
- suspended: Cell<bool>,
-}
-
-impl<'a> Parser for &'a ServoHTMLParser {
- fn parse_chunk(self, input: String) {
- self.upcast().document().set_current_parser(Some(ParserRef::HTML(self)));
- self.upcast().push_input_chunk(input);
- if !self.is_suspended() {
- self.parse_sync();
- }
- }
-
- fn finish(self) {
- assert!(!self.suspended.get());
- assert!(!self.upcast().has_pending_input());
-
- self.tokenizer.borrow_mut().end();
- debug!("finished parsing");
-
- self.upcast().document().set_current_parser(None);
-
- if let Some(pipeline) = self.upcast().pipeline() {
- ScriptThread::parsing_complete(pipeline);
- }
- }
-}
-
-impl ServoHTMLParser {
- #[allow(unrooted_must_root)]
- pub fn new(base_url: Option<Url>, document: &Document, pipeline: Option<PipelineId>)
- -> Root<ServoHTMLParser> {
- let sink = Sink {
- base_url: base_url,
- document: JS::from_ref(document),
- };
-
- let tb = TreeBuilder::new(sink, TreeBuilderOpts {
- ignore_missing_rules: true,
- .. Default::default()
- });
-
- let tok = tokenizer::Tokenizer::new(tb, Default::default());
-
- let parser = ServoHTMLParser {
- servoparser: ServoParser::new_inherited(document, pipeline, false),
- tokenizer: DOMRefCell::new(tok),
- suspended: Cell::new(false),
- };
-
- reflect_dom_object(box parser, document.window(), ServoHTMLParserBinding::Wrap)
- }
-
- #[allow(unrooted_must_root)]
- pub fn new_for_fragment(base_url: Option<Url>, document: &Document,
- fragment_context: FragmentContext) -> Root<ServoHTMLParser> {
- let sink = Sink {
- base_url: base_url,
- document: JS::from_ref(document),
- };
-
- let tb_opts = TreeBuilderOpts {
- ignore_missing_rules: true,
- .. Default::default()
- };
- let tb = TreeBuilder::new_for_fragment(sink,
- JS::from_ref(fragment_context.context_elem),
- fragment_context.form_elem.map(|n| JS::from_ref(n)),
- tb_opts);
-
- let tok_opts = tokenizer::TokenizerOpts {
- initial_state: Some(tb.tokenizer_state_for_context_elem()),
- .. Default::default()
- };
- let tok = tokenizer::Tokenizer::new(tb, tok_opts);
-
- let parser = ServoHTMLParser {
- servoparser: ServoParser::new_inherited(document, None, true),
- tokenizer: DOMRefCell::new(tok),
- suspended: Cell::new(false),
- };
-
- reflect_dom_object(box parser, document.window(), ServoHTMLParserBinding::Wrap)
- }
-
- #[inline]
- pub fn tokenizer(&self) -> &DOMRefCell<Tokenizer> {
- &self.tokenizer
- }
-
- pub fn set_plaintext_state(&self) {
- self.tokenizer.borrow_mut().set_plaintext_state()
- }
-
- pub fn end_tokenizer(&self) {
- self.tokenizer.borrow_mut().end()
- }
-}
-
-impl ServoHTMLParser {
- pub fn parse_sync(&self) {
- let metadata = TimerMetadata {
- url: self.upcast().document().url().as_str().into(),
- iframe: TimerMetadataFrameType::RootWindow,
- incremental: TimerMetadataReflowType::FirstReflow,
- };
- profile(ProfilerCategory::ScriptParseHTML,
- Some(metadata),
- self.upcast().document().window().upcast::<GlobalScope>().time_profiler_chan().clone(),
- || self.do_parse_sync())
- }
-
- fn do_parse_sync(&self) {
- // This parser will continue to parse while there is either pending input or
- // the parser remains unsuspended.
- loop {
- self.upcast().document().reflow_if_reflow_timer_expired();
- if let Some(chunk) = self.upcast().take_next_input_chunk() {
- self.tokenizer.borrow_mut().feed(chunk.into());
- } else {
- self.tokenizer.borrow_mut().run();
- }
-
- // Document parsing is blocked on an external resource.
- if self.suspended.get() {
- return;
- }
-
- if !self.upcast().has_pending_input() {
- break;
- }
- }
-
- if self.upcast().last_chunk_received() {
- self.finish();
- }
- }
-
- pub fn window(&self) -> &Window {
- self.upcast().document().window()
- }
-
- pub fn suspend(&self) {
- assert!(!self.suspended.get());
- self.suspended.set(true);
- }
-
- pub fn resume(&self) {
- assert!(self.suspended.get());
- self.suspended.set(false);
- self.parse_sync();
- }
-
- pub fn is_suspended(&self) -> bool {
- self.suspended.get()
- }
-}
-
-struct Tracer {
- trc: *mut JSTracer,
-}
-
-impl tree_builder::Tracer for Tracer {
- type Handle = JS<Node>;
- #[allow(unrooted_must_root)]
- fn trace_handle(&self, node: &JS<Node>) {
- node.trace(self.trc);
- }
-}
-
-impl JSTraceable for Tokenizer {
- fn trace(&self, trc: *mut JSTracer) {
- let tracer = Tracer {
- trc: trc,
- };
- let tracer = &tracer as &tree_builder::Tracer<Handle=JS<Node>>;
-
- let tree_builder = self.sink();
- tree_builder.trace_handles(tracer);
- tree_builder.sink().trace(trc);
- }
-}
diff --git a/components/script/dom/servoparser.rs b/components/script/dom/servoparser.rs
index 4a2bc0de400..9566919b9f4 100644
--- a/components/script/dom/servoparser.rs
+++ b/components/script/dom/servoparser.rs
@@ -3,11 +3,27 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::cell::DOMRefCell;
-use dom::bindings::reflector::Reflector;
-use dom::bindings::js::JS;
+use dom::bindings::codegen::Bindings::ServoParserBinding;
+use dom::bindings::inheritance::Castable;
+use dom::bindings::js::{JS, Root};
+use dom::bindings::reflector::{Reflector, reflect_dom_object};
+use dom::bindings::trace::JSTraceable;
use dom::document::Document;
+use dom::globalscope::GlobalScope;
+use dom::node::Node;
+use dom::window::Window;
+use html5ever::tokenizer::Tokenizer as HtmlTokenizer;
+use html5ever::tree_builder::Tracer as HtmlTracer;
+use html5ever::tree_builder::TreeBuilder as HtmlTreeBuilder;
+use js::jsapi::JSTracer;
use msg::constellation_msg::PipelineId;
+use parse::Sink;
+use profile_traits::time::{TimerMetadata, TimerMetadataFrameType};
+use profile_traits::time::{TimerMetadataReflowType, ProfilerCategory, profile};
+use script_thread::ScriptThread;
use std::cell::Cell;
+use xml5ever::tokenizer::XmlTokenizer;
+use xml5ever::tree_builder::{Tracer as XmlTracer, XmlTreeBuilder};
#[dom_struct]
pub struct ServoParser {
@@ -19,14 +35,20 @@ pub struct ServoParser {
pipeline: Option<PipelineId>,
/// Input chunks received but not yet passed to the parser.
pending_input: DOMRefCell<Vec<String>>,
+ /// The tokenizer of this parser.
+ tokenizer: DOMRefCell<Tokenizer>,
/// Whether to expect any further input from the associated network request.
last_chunk_received: Cell<bool>,
+ /// Whether this parser should avoid passing any further data to the tokenizer.
+ suspended: Cell<bool>,
}
impl ServoParser {
- pub fn new_inherited(
+ #[allow(unrooted_must_root)]
+ fn new_inherited(
document: &Document,
pipeline: Option<PipelineId>,
+ tokenizer: Tokenizer,
last_chunk_received: bool)
-> Self {
ServoParser {
@@ -34,10 +56,25 @@ impl ServoParser {
document: JS::from_ref(document),
pipeline: pipeline,
pending_input: DOMRefCell::new(vec![]),
+ tokenizer: DOMRefCell::new(tokenizer),
last_chunk_received: Cell::new(last_chunk_received),
+ suspended: Default::default(),
}
}
+ #[allow(unrooted_must_root)]
+ pub fn new(
+ document: &Document,
+ pipeline: Option<PipelineId>,
+ tokenizer: Tokenizer,
+ last_chunk_received: bool)
+ -> Root<Self> {
+ reflect_dom_object(
+ box ServoParser::new_inherited(document, pipeline, tokenizer, last_chunk_received),
+ document.window(),
+ ServoParserBinding::Wrap)
+ }
+
pub fn document(&self) -> &Document {
&self.document
}
@@ -70,4 +107,176 @@ impl ServoParser {
pub fn mark_last_chunk_received(&self) {
self.last_chunk_received.set(true)
}
+
+ pub fn set_plaintext_state(&self) {
+ self.tokenizer.borrow_mut().set_plaintext_state()
+ }
+
+ pub fn end_tokenizer(&self) {
+ self.tokenizer.borrow_mut().end()
+ }
+
+ pub fn window(&self) -> &Window {
+ self.document().window()
+ }
+
+ pub fn suspend(&self) {
+ assert!(!self.suspended.get());
+ self.suspended.set(true);
+ }
+
+ pub fn resume(&self) {
+ assert!(self.suspended.get());
+ self.suspended.set(false);
+ self.parse_sync();
+ }
+
+ pub fn is_suspended(&self) -> bool {
+ self.suspended.get()
+ }
+
+ pub fn parse_sync(&self) {
+ let metadata = TimerMetadata {
+ url: self.document().url().as_str().into(),
+ iframe: TimerMetadataFrameType::RootWindow,
+ incremental: TimerMetadataReflowType::FirstReflow,
+ };
+ let profiler_category = self.tokenizer.borrow().profiler_category();
+ profile(profiler_category,
+ Some(metadata),
+ self.document().window().upcast::<GlobalScope>().time_profiler_chan().clone(),
+ || self.do_parse_sync())
+ }
+
+ fn do_parse_sync(&self) {
+ // This parser will continue to parse while there is either pending input or
+ // the parser remains unsuspended.
+ loop {
+ self.document().reflow_if_reflow_timer_expired();
+ if let Some(chunk) = self.take_next_input_chunk() {
+ self.tokenizer.borrow_mut().feed(chunk);
+ } else {
+ self.tokenizer.borrow_mut().run();
+ }
+
+ // Document parsing is blocked on an external resource.
+ if self.suspended.get() {
+ return;
+ }
+
+ if !self.has_pending_input() {
+ break;
+ }
+ }
+
+ if self.last_chunk_received() {
+ self.finish();
+ }
+ }
+
+ pub fn parse_chunk(&self, input: String) {
+ self.document().set_current_parser(Some(self));
+ self.push_input_chunk(input);
+ if !self.is_suspended() {
+ self.parse_sync();
+ }
+ }
+
+ pub fn finish(&self) {
+ assert!(!self.suspended.get());
+ assert!(!self.has_pending_input());
+
+ self.tokenizer.borrow_mut().end();
+ debug!("finished parsing");
+
+ self.document().set_current_parser(None);
+
+ if let Some(pipeline) = self.pipeline() {
+ ScriptThread::parsing_complete(pipeline);
+ }
+ }
+}
+
+#[derive(HeapSizeOf)]
+#[must_root]
+pub enum Tokenizer {
+ HTML(
+ #[ignore_heap_size_of = "Defined in html5ever"]
+ HtmlTokenizer<HtmlTreeBuilder<JS<Node>, Sink>>
+ ),
+ XML(
+ #[ignore_heap_size_of = "Defined in xml5ever"]
+ XmlTokenizer<XmlTreeBuilder<JS<Node>, Sink>>
+ ),
+}
+
+impl Tokenizer {
+ pub fn feed(&mut self, input: String) {
+ match *self {
+ Tokenizer::HTML(ref mut tokenizer) => tokenizer.feed(input.into()),
+ Tokenizer::XML(ref mut tokenizer) => tokenizer.feed(input.into()),
+ }
+ }
+
+ pub fn run(&mut self) {
+ match *self {
+ Tokenizer::HTML(ref mut tokenizer) => tokenizer.run(),
+ Tokenizer::XML(ref mut tokenizer) => tokenizer.run(),
+ }
+ }
+
+ pub fn end(&mut self) {
+ match *self {
+ Tokenizer::HTML(ref mut tokenizer) => tokenizer.end(),
+ Tokenizer::XML(ref mut tokenizer) => tokenizer.end(),
+ }
+ }
+
+ pub fn set_plaintext_state(&mut self) {
+ match *self {
+ Tokenizer::HTML(ref mut tokenizer) => tokenizer.set_plaintext_state(),
+ Tokenizer::XML(_) => { /* todo */ },
+ }
+ }
+
+ pub fn profiler_category(&self) -> ProfilerCategory {
+ match *self {
+ Tokenizer::HTML(_) => ProfilerCategory::ScriptParseHTML,
+ Tokenizer::XML(_) => ProfilerCategory::ScriptParseXML,
+ }
+ }
+}
+
+impl JSTraceable for Tokenizer {
+ fn trace(&self, trc: *mut JSTracer) {
+ struct Tracer(*mut JSTracer);
+ let tracer = Tracer(trc);
+
+ match *self {
+ Tokenizer::HTML(ref tokenizer) => {
+ impl HtmlTracer for Tracer {
+ type Handle = JS<Node>;
+ #[allow(unrooted_must_root)]
+ fn trace_handle(&self, node: &JS<Node>) {
+ node.trace(self.0);
+ }
+ }
+ let tree_builder = tokenizer.sink();
+ tree_builder.trace_handles(&tracer);
+ tree_builder.sink().trace(trc);
+ },
+ Tokenizer::XML(ref tokenizer) => {
+ impl XmlTracer for Tracer {
+ type Handle = JS<Node>;
+ #[allow(unrooted_must_root)]
+ fn trace_handle(&self, node: JS<Node>) {
+ node.trace(self.0);
+ }
+ }
+ let tree_builder = tokenizer.sink();
+ tree_builder.trace_handles(&tracer);
+ tree_builder.sink().trace(trc);
+ }
+ }
+ }
}
diff --git a/components/script/dom/servoxmlparser.rs b/components/script/dom/servoxmlparser.rs
deleted file mode 100644
index 919dcfdb946..00000000000
--- a/components/script/dom/servoxmlparser.rs
+++ /dev/null
@@ -1,185 +0,0 @@
-/* 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/. */
-
-use dom::bindings::cell::DOMRefCell;
-use dom::bindings::codegen::Bindings::ServoXMLParserBinding;
-use dom::bindings::inheritance::Castable;
-use dom::bindings::js::{JS, Root};
-use dom::bindings::reflector::reflect_dom_object;
-use dom::bindings::trace::JSTraceable;
-use dom::document::Document;
-use dom::globalscope::GlobalScope;
-use dom::node::Node;
-use dom::servoparser::ServoParser;
-use dom::window::Window;
-use js::jsapi::JSTracer;
-use msg::constellation_msg::PipelineId;
-use parse::{Parser, ParserRef};
-use profile_traits::time::{ProfilerCategory, TimerMetadata};
-use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType, profile};
-use script_thread::ScriptThread;
-use std::cell::Cell;
-use url::Url;
-use xml5ever::tokenizer;
-use xml5ever::tree_builder::{self, XmlTreeBuilder};
-
-pub type Tokenizer = tokenizer::XmlTokenizer<XmlTreeBuilder<JS<Node>, Sink>>;
-
-#[must_root]
-#[derive(JSTraceable, HeapSizeOf)]
-pub struct Sink {
- pub base_url: Option<Url>,
- pub document: JS<Document>,
-}
-
-#[must_root]
-#[dom_struct]
-pub struct ServoXMLParser {
- servoparser: ServoParser,
- #[ignore_heap_size_of = "Defined in xml5ever"]
- tokenizer: DOMRefCell<Tokenizer>,
- /// True if this parser should avoid passing any further data to the tokenizer.
- suspended: Cell<bool>,
-}
-
-impl<'a> Parser for &'a ServoXMLParser {
- fn parse_chunk(self, input: String) {
- self.upcast().document().set_current_parser(Some(ParserRef::XML(self)));
- self.upcast().push_input_chunk(input);
- if !self.is_suspended() {
- self.parse_sync();
- }
- }
-
- fn finish(self) {
- assert!(!self.suspended.get());
- assert!(!self.upcast().has_pending_input());
-
- self.tokenizer.borrow_mut().end();
- debug!("finished parsing");
-
- self.upcast().document().set_current_parser(None);
-
- if let Some(pipeline) = self.upcast().pipeline() {
- ScriptThread::parsing_complete(pipeline);
- }
- }
-}
-
-impl ServoXMLParser {
- #[allow(unrooted_must_root)]
- pub fn new(base_url: Option<Url>, document: &Document, pipeline: Option<PipelineId>)
- -> Root<ServoXMLParser> {
- let sink = Sink {
- base_url: base_url,
- document: JS::from_ref(document),
- };
-
- let tb = XmlTreeBuilder::new(sink);
-
- let tok = tokenizer::XmlTokenizer::new(tb, Default::default());
-
- let parser = ServoXMLParser {
- servoparser: ServoParser::new_inherited(document, pipeline, false),
- tokenizer: DOMRefCell::new(tok),
- suspended: Cell::new(false),
- };
-
- reflect_dom_object(box parser, document.window(), ServoXMLParserBinding::Wrap)
- }
-
- pub fn window(&self) -> &Window {
- self.upcast().document().window()
- }
-
- pub fn resume(&self) {
- assert!(self.suspended.get());
- self.suspended.set(false);
- self.parse_sync();
- }
-
- pub fn suspend(&self) {
- assert!(!self.suspended.get());
- self.suspended.set(true);
- }
-
- pub fn is_suspended(&self) -> bool {
- self.suspended.get()
- }
-
- pub fn parse_sync(&self) {
- let metadata = TimerMetadata {
- url: self.upcast().document().url().as_str().into(),
- iframe: TimerMetadataFrameType::RootWindow,
- incremental: TimerMetadataReflowType::FirstReflow,
- };
- profile(ProfilerCategory::ScriptParseXML,
- Some(metadata),
- self.upcast().document().window().upcast::<GlobalScope>().time_profiler_chan().clone(),
- || self.do_parse_sync())
- }
-
- fn do_parse_sync(&self) {
- // This parser will continue to parse while there is either pending input or
- // the parser remains unsuspended.
- loop {
- self.upcast().document().reflow_if_reflow_timer_expired();
- if let Some(chunk) = self.upcast().take_next_input_chunk() {
- self.tokenizer.borrow_mut().feed(chunk.into());
- } else {
- self.tokenizer.borrow_mut().run();
- }
-
- // Document parsing is blocked on an external resource.
- if self.suspended.get() {
- return;
- }
-
- if !self.upcast().has_pending_input() {
- break;
- }
- }
-
- if self.upcast().last_chunk_received() {
- self.finish();
- }
- }
-
- pub fn set_plaintext_state(&self) {
- //self.tokenizer.borrow_mut().set_plaintext_state()
- }
-
- pub fn end_tokenizer(&self) {
- self.tokenizer.borrow_mut().end()
- }
-
- pub fn tokenizer(&self) -> &DOMRefCell<Tokenizer> {
- &self.tokenizer
- }
-}
-
-struct Tracer {
- trc: *mut JSTracer,
-}
-
-impl tree_builder::Tracer for Tracer {
- type Handle = JS<Node>;
- #[allow(unrooted_must_root)]
- fn trace_handle(&self, node: JS<Node>) {
- node.trace(self.trc);
- }
-}
-
-impl JSTraceable for Tokenizer {
- fn trace(&self, trc: *mut JSTracer) {
- let tracer = Tracer {
- trc: trc,
- };
- let tracer = &tracer as &tree_builder::Tracer<Handle=JS<Node>>;
-
- let tree_builder = self.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
deleted file mode 100644
index ddf9382ff9a..00000000000
--- a/components/script/dom/webidls/ServoHTMLParser.webidl
+++ /dev/null
@@ -1,11 +0,0 @@
-/* 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/. */
-
-// This interface is entirely internal to Servo, and should not be accessible to
-// web pages.
-
-// FIXME: find a better way to hide this from content (#3688)
-[NoInterfaceObject, Exposed=(Window,Worker)]
-interface ServoHTMLParser : ServoParser {
-};
diff --git a/components/script/dom/webidls/ServoParser.webidl b/components/script/dom/webidls/ServoParser.webidl
index 435ca1fb90f..c3b0926d824 100644
--- a/components/script/dom/webidls/ServoParser.webidl
+++ b/components/script/dom/webidls/ServoParser.webidl
@@ -6,5 +6,5 @@
// web pages.
[Exposed=(Window,Worker),
- Inline]
+ NoInterfaceObject]
interface ServoParser {};
diff --git a/components/script/dom/webidls/ServoXMLParser.webidl b/components/script/dom/webidls/ServoXMLParser.webidl
deleted file mode 100644
index 3f6f03822ad..00000000000
--- a/components/script/dom/webidls/ServoXMLParser.webidl
+++ /dev/null
@@ -1,11 +0,0 @@
-/* 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/. */
-
-// This interface is entirely internal to Servo, and should not be accessible to
-// web pages.
-
-[NoInterfaceObject, Exposed=(Window,Worker)]
-interface ServoXMLParser : ServoParser {
-};
-
diff --git a/components/script/parse/html.rs b/components/script/parse/html.rs
index 39684bd1b3e..dd4a17c40c8 100644
--- a/components/script/parse/html.rs
+++ b/components/script/parse/html.rs
@@ -23,17 +23,18 @@ use dom::htmltemplateelement::HTMLTemplateElement;
use dom::node::{document_from_node, window_from_node};
use dom::node::Node;
use dom::processinginstruction::ProcessingInstruction;
-use dom::servohtmlparser;
-use dom::servohtmlparser::{FragmentContext, ServoHTMLParser};
+use dom::servoparser::{ServoParser, Tokenizer};
use dom::text::Text;
use html5ever::Attribute;
use html5ever::serialize::{AttrRef, Serializable, Serializer};
use html5ever::serialize::TraversalScope;
use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
use html5ever::tendril::StrTendril;
-use html5ever::tree_builder::{NextParserState, NodeOrText, QuirksMode, TreeSink};
+use html5ever::tokenizer::{Tokenizer as HtmlTokenizer, TokenizerOpts};
+use html5ever::tree_builder::{NextParserState, NodeOrText, QuirksMode};
+use html5ever::tree_builder::{TreeBuilder, TreeBuilderOpts, TreeSink};
use msg::constellation_msg::PipelineId;
-use parse::Parser;
+use parse::Sink;
use std::borrow::Cow;
use std::io::{self, Write};
use string_cache::QualName;
@@ -53,7 +54,7 @@ fn insert(parent: &Node, reference_child: Option<&Node>, child: NodeOrText<JS<No
}
}
-impl<'a> TreeSink for servohtmlparser::Sink {
+impl<'a> TreeSink for Sink {
type Output = Self;
fn finish(self) -> Self { self }
@@ -246,6 +247,14 @@ impl<'a> Serializable for &'a Node {
}
}
+/// FragmentContext is used only to pass this group of related values
+/// into functions.
+#[derive(Copy, Clone)]
+pub struct FragmentContext<'a> {
+ pub context_elem: &'a Node,
+ pub form_elem: Option<&'a Node>,
+}
+
pub enum ParseContext<'a> {
Fragment(FragmentContext<'a>),
Owner(Option<PipelineId>),
@@ -255,11 +264,38 @@ pub fn parse_html(document: &Document,
input: DOMString,
url: Url,
context: ParseContext) {
+ let sink = Sink {
+ base_url: url,
+ document: JS::from_ref(document),
+ };
+
+ let options = TreeBuilderOpts {
+ ignore_missing_rules: true,
+ .. Default::default()
+ };
+
let parser = match context {
- ParseContext::Owner(owner) =>
- ServoHTMLParser::new(Some(url), document, owner),
- ParseContext::Fragment(fc) =>
- ServoHTMLParser::new_for_fragment(Some(url), document, fc),
+ ParseContext::Owner(owner) => {
+ let tb = TreeBuilder::new(sink, options);
+ let tok = HtmlTokenizer::new(tb, Default::default());
+
+ ServoParser::new(document, owner, Tokenizer::HTML(tok), false)
+ },
+ ParseContext::Fragment(fc) => {
+ let tb = TreeBuilder::new_for_fragment(
+ sink,
+ JS::from_ref(fc.context_elem),
+ fc.form_elem.map(|n| JS::from_ref(n)),
+ options);
+
+ let tok_options = TokenizerOpts {
+ initial_state: Some(tb.tokenizer_state_for_context_elem()),
+ .. Default::default()
+ };
+ let tok = HtmlTokenizer::new(tb, tok_options);
+
+ ServoParser::new(document, None, Tokenizer::HTML(tok), true)
+ }
};
parser.parse_chunk(String::from(input));
}
diff --git a/components/script/parse/mod.rs b/components/script/parse/mod.rs
index dc874baef45..6ef786eaa93 100644
--- a/components/script/parse/mod.rs
+++ b/components/script/parse/mod.rs
@@ -6,16 +6,13 @@ use document_loader::LoadType;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::HTMLImageElementBinding::HTMLImageElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
-use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root};
use dom::bindings::refcounted::Trusted;
use dom::bindings::str::DOMString;
+use dom::document::Document;
use dom::htmlimageelement::HTMLImageElement;
use dom::node::Node;
-use dom::servohtmlparser::ServoHTMLParser;
use dom::servoparser::ServoParser;
-use dom::servoxmlparser::ServoXMLParser;
-use dom::window::Window;
use encoding::all::UTF_8;
use encoding::types::{DecoderTrap, Encoding};
use hyper::header::ContentType;
@@ -25,164 +22,17 @@ use msg::constellation_msg::PipelineId;
use net_traits::{AsyncResponseListener, Metadata, NetworkError};
use network_listener::PreInvoke;
use script_thread::ScriptThread;
-use std::cell::UnsafeCell;
-use std::ptr;
use url::Url;
use util::resource_files::read_resource_file;
pub mod html;
pub mod xml;
-pub trait Parser {
- fn parse_chunk(self, input: String);
- fn finish(self);
-}
-
-#[must_root]
-#[derive(JSTraceable, HeapSizeOf)]
-pub enum ParserField {
- HTML(JS<ServoHTMLParser>),
- XML(JS<ServoXMLParser>),
-}
-
-#[must_root]
-#[derive(JSTraceable, HeapSizeOf)]
-pub struct MutNullableParserField {
- #[ignore_heap_size_of = "XXXjdm"]
- ptr: UnsafeCell<Option<ParserField>>,
-}
-
-impl Default for MutNullableParserField {
- #[allow(unrooted_must_root)]
- fn default() -> MutNullableParserField {
- MutNullableParserField {
- ptr: UnsafeCell::new(None),
- }
- }
-}
-
-impl MutNullableParserField {
- #[allow(unsafe_code)]
- pub fn set(&self, val: Option<ParserRef>) {
- unsafe {
- *self.ptr.get() = val.map(|val| {
- match val {
- ParserRef::HTML(parser) => ParserField::HTML(JS::from_ref(parser)),
- ParserRef::XML(parser) => ParserField::XML(JS::from_ref(parser)),
- }
- });
- }
- }
-
- #[allow(unsafe_code, unrooted_must_root)]
- pub fn get(&self) -> Option<ParserRoot> {
- unsafe {
- ptr::read(self.ptr.get()).map(|o| {
- match o {
- ParserField::HTML(parser) => ParserRoot::HTML(Root::from_ref(&*parser)),
- ParserField::XML(parser) => ParserRoot::XML(Root::from_ref(&*parser)),
- }
- })
- }
- }
-}
-
-pub enum ParserRoot {
- HTML(Root<ServoHTMLParser>),
- XML(Root<ServoXMLParser>),
-}
-
-impl ParserRoot {
- pub fn r(&self) -> ParserRef {
- match *self {
- ParserRoot::HTML(ref parser) => ParserRef::HTML(parser.r()),
- ParserRoot::XML(ref parser) => ParserRef::XML(parser.r()),
- }
- }
-}
-
-pub enum TrustedParser {
- HTML(Trusted<ServoHTMLParser>),
- XML(Trusted<ServoXMLParser>),
-}
-
-impl TrustedParser {
- pub fn root(&self) -> ParserRoot {
- match *self {
- TrustedParser::HTML(ref parser) => ParserRoot::HTML(parser.root()),
- TrustedParser::XML(ref parser) => ParserRoot::XML(parser.root()),
- }
- }
-}
-
-pub enum ParserRef<'a> {
- HTML(&'a ServoHTMLParser),
- XML(&'a ServoXMLParser),
-}
-
-impl<'a> ParserRef<'a> {
- pub fn as_servo_parser(&self) -> &ServoParser {
- match *self {
- ParserRef::HTML(parser) => parser.upcast(),
- ParserRef::XML(parser) => parser.upcast(),
- }
- }
-
- pub fn parse_chunk(&self, input: String) {
- match *self {
- ParserRef::HTML(parser) => parser.parse_chunk(input),
- ParserRef::XML(parser) => parser.parse_chunk(input),
- }
- }
-
- pub fn window(&self) -> &Window {
- match *self {
- ParserRef::HTML(parser) => parser.window(),
- ParserRef::XML(parser) => parser.window(),
- }
- }
-
- pub fn resume(&self) {
- match *self {
- ParserRef::HTML(parser) => parser.resume(),
- ParserRef::XML(parser) => parser.resume(),
- }
- }
-
- pub fn suspend(&self) {
- match *self {
- ParserRef::HTML(parser) => parser.suspend(),
- ParserRef::XML(parser) => parser.suspend(),
- }
- }
-
- pub fn is_suspended(&self) -> bool {
- match *self {
- ParserRef::HTML(parser) => parser.is_suspended(),
- ParserRef::XML(parser) => parser.is_suspended(),
- }
- }
-
- pub fn set_plaintext_state(&self) {
- match *self {
- ParserRef::HTML(parser) => parser.set_plaintext_state(),
- ParserRef::XML(parser) => parser.set_plaintext_state(),
- }
- }
-
- pub fn parse_sync(&self) {
- match *self {
- ParserRef::HTML(parser) => parser.parse_sync(),
- ParserRef::XML(parser) => parser.parse_sync(),
- }
- }
-}
-
/// The context required for asynchronously fetching a document
/// and parsing it progressively.
pub struct ParserContext {
/// The parser that initiated the request.
- parser: Option<TrustedParser>,
+ parser: Option<Trusted<ServoParser>>,
/// Is this a synthesized document
is_synthesized_document: bool,
/// The pipeline associated with this document.
@@ -224,23 +74,16 @@ impl AsyncResponseListener for ParserContext {
None => return,
};
- let parser = parser.r();
- let servo_parser = parser.as_servo_parser();
- self.parser = Some(match parser {
- ParserRef::HTML(parser) => TrustedParser::HTML(
- Trusted::new(parser)),
- ParserRef::XML(parser) => TrustedParser::XML(
- Trusted::new(parser)),
- });
+ self.parser = Some(Trusted::new(&*parser));
match content_type {
Some(ContentType(Mime(TopLevel::Image, _, _))) => {
self.is_synthesized_document = true;
let page = "<html><body></body></html>".into();
- servo_parser.push_input_chunk(page);
+ parser.push_input_chunk(page);
parser.parse_sync();
- let doc = servo_parser.document();
+ let doc = parser.document();
let doc_body = Root::upcast::<Node>(doc.GetBody().unwrap());
let img = HTMLImageElement::new(atom!("img"), None, doc);
img.SetSrc(DOMString::from(self.url.to_string()));
@@ -250,7 +93,7 @@ impl AsyncResponseListener for ParserContext {
Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) => {
// https://html.spec.whatwg.org/multipage/#read-text
let page = "<pre>\n".into();
- servo_parser.push_input_chunk(page);
+ parser.push_input_chunk(page);
parser.parse_sync();
parser.set_plaintext_state();
},
@@ -260,7 +103,7 @@ impl AsyncResponseListener for ParserContext {
let page_bytes = read_resource_file("badcert.html").unwrap();
let page = String::from_utf8(page_bytes).unwrap();
let page = page.replace("${reason}", &reason);
- servo_parser.push_input_chunk(page);
+ parser.push_input_chunk(page);
parser.parse_sync();
}
},
@@ -275,7 +118,7 @@ impl AsyncResponseListener for ParserContext {
let page = format!("<html><body><p>Unknown content type ({}/{}).</p></body></html>",
toplevel.as_str(), sublevel.as_str());
self.is_synthesized_document = true;
- servo_parser.push_input_chunk(page);
+ parser.push_input_chunk(page);
parser.parse_sync();
},
None => {
@@ -293,7 +136,7 @@ impl AsyncResponseListener for ParserContext {
Some(parser) => parser.root(),
None => return,
};
- parser.r().parse_chunk(data);
+ parser.parse_chunk(data);
}
}
@@ -307,24 +150,20 @@ impl AsyncResponseListener for ParserContext {
// Show an error page for network errors,
// certificate errors are handled earlier.
self.is_synthesized_document = true;
- let parser = parser.r();
let page_bytes = read_resource_file("neterror.html").unwrap();
let page = String::from_utf8(page_bytes).unwrap();
let page = page.replace("${reason}", reason);
- parser.as_servo_parser().push_input_chunk(page);
+ parser.push_input_chunk(page);
parser.parse_sync();
} else if let Err(err) = status {
// TODO(Savago): we should send a notification to callers #5463.
debug!("Failed to load page URL {}, error: {:?}", self.url, err);
}
- let parser = parser.r();
- let servo_parser = parser.as_servo_parser();
-
- servo_parser.document()
+ parser.document()
.finish_load(LoadType::PageSource(self.url.clone()));
- servo_parser.mark_last_chunk_received();
+ parser.mark_last_chunk_received();
if !parser.is_suspended() {
parser.parse_sync();
}
@@ -332,3 +171,10 @@ impl AsyncResponseListener for ParserContext {
}
impl PreInvoke for ParserContext {}
+
+#[derive(JSTraceable, HeapSizeOf)]
+#[must_root]
+pub struct Sink {
+ pub base_url: Url,
+ pub document: JS<Document>,
+}
diff --git a/components/script/parse/xml.rs b/components/script/parse/xml.rs
index ee0959d04ef..3777b7f497c 100644
--- a/components/script/parse/xml.rs
+++ b/components/script/parse/xml.rs
@@ -15,20 +15,19 @@ use dom::element::{Element, ElementCreator};
use dom::htmlscriptelement::HTMLScriptElement;
use dom::node::Node;
use dom::processinginstruction::ProcessingInstruction;
-use dom::servoxmlparser;
-use dom::servoxmlparser::ServoXMLParser;
+use dom::servoparser::{ServoParser, Tokenizer};
use dom::text::Text;
use html5ever;
use msg::constellation_msg::PipelineId;
-use parse::Parser;
+use parse::Sink;
use std::borrow::Cow;
use string_cache::{Atom, QualName, Namespace};
use url::Url;
use xml5ever::tendril::StrTendril;
-use xml5ever::tokenizer::{Attribute, QName};
-use xml5ever::tree_builder::{NextParserState, NodeOrText, TreeSink};
+use xml5ever::tokenizer::{Attribute, QName, XmlTokenizer};
+use xml5ever::tree_builder::{NextParserState, NodeOrText, TreeSink, XmlTreeBuilder};
-impl<'a> TreeSink for servoxmlparser::Sink {
+impl<'a> TreeSink for Sink {
type Handle = JS<Node>;
fn parse_error(&mut self, msg: Cow<'static, str>) {
@@ -134,8 +133,15 @@ pub fn parse_xml(document: &Document,
url: Url,
context: ParseContext) {
let parser = match context {
- ParseContext::Owner(owner) =>
- ServoXMLParser::new(Some(url), document, owner),
+ ParseContext::Owner(owner) => {
+ let tb = XmlTreeBuilder::new(Sink {
+ base_url: url,
+ document: JS::from_ref(document),
+ });
+ let tok = XmlTokenizer::new(tb, Default::default());
+
+ ServoParser::new(document, owner, Tokenizer::XML(tok), false)
+ }
};
parser.parse_chunk(String::from(input));
}
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index b52fe1da126..ceb6842a13b 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -44,6 +44,7 @@ use dom::htmlanchorelement::HTMLAnchorElement;
use dom::node::{Node, NodeDamage, window_from_node};
use dom::serviceworker::TrustedServiceWorkerAddress;
use dom::serviceworkerregistration::ServiceWorkerRegistration;
+use dom::servoparser::ServoParser;
use dom::uievent::UIEvent;
use dom::window::{ReflowReason, Window};
use dom::worker::TrustedWorkerAddress;
@@ -70,7 +71,7 @@ use net_traits::{IpcSend, LoadData as NetLoadData};
use net_traits::bluetooth_thread::BluetoothMethodMsg;
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
use network_listener::NetworkListener;
-use parse::{ParserContext, ParserRoot};
+use parse::ParserContext;
use parse::html::{ParseContext, parse_html};
use parse::xml::{self, parse_xml};
use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan};
@@ -489,7 +490,7 @@ impl ScriptThreadFactory for ScriptThread {
impl ScriptThread {
pub fn page_headers_available(id: &PipelineId, metadata: Option<Metadata>)
- -> Option<ParserRoot> {
+ -> Option<Root<ServoParser>> {
SCRIPT_THREAD_ROOT.with(|root| {
let script_thread = unsafe { &*root.get().unwrap() };
script_thread.handle_page_headers_available(id, metadata)
@@ -1413,7 +1414,7 @@ impl ScriptThread {
/// We have received notification that the response associated with a load has completed.
/// Kick off the document and frame tree creation process using the result.
fn handle_page_headers_available(&self, id: &PipelineId,
- metadata: Option<Metadata>) -> Option<ParserRoot> {
+ metadata: Option<Metadata>) -> Option<Root<ServoParser>> {
let idx = self.incomplete_loads.borrow().iter().position(|load| { load.pipeline_id == *id });
// The matching in progress load structure may not exist if
// the pipeline exited before the page load completed.
@@ -1543,7 +1544,7 @@ impl ScriptThread {
/// The entry point to document loading. Defines bindings, sets up the window and document
/// objects, parses HTML and CSS, and kicks off initial layout.
- fn load(&self, metadata: Metadata, incomplete: InProgressLoad) -> ParserRoot {
+ fn load(&self, metadata: Metadata, incomplete: InProgressLoad) -> Root<ServoParser> {
let final_url = metadata.final_url.clone();
{
// send the final url to the layout thread.