diff options
author | Anthony Ramine <n.oxyde@gmail.com> | 2017-01-26 12:42:38 +0100 |
---|---|---|
committer | Anthony Ramine <n.oxyde@gmail.com> | 2017-02-03 16:50:12 +0100 |
commit | ac254046e448e4edde86f2d68f27330fbd9ec1e6 (patch) | |
tree | 323d38fdd2d1fe80765e7f0f3ed287d7f3a49bb4 /components/script/dom/servoparser/mod.rs | |
parent | 8c3abd6c79d2be83e1e088b18ab3b8bbc0cca201 (diff) | |
download | servo-ac254046e448e4edde86f2d68f27330fbd9ec1e6.tar.gz servo-ac254046e448e4edde86f2d68f27330fbd9ec1e6.zip |
Implement document.open and document.close (fixes #14591)
Diffstat (limited to 'components/script/dom/servoparser/mod.rs')
-rw-r--r-- | components/script/dom/servoparser/mod.rs | 115 |
1 files changed, 100 insertions, 15 deletions
diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index 0d8e02d273e..67f1b23e583 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -38,6 +38,7 @@ use script_thread::ScriptThread; use script_traits::DocumentActivity; use servo_config::resource_files::read_resource_file; use servo_url::ServoUrl; +use std::ascii::AsciiExt; use std::cell::Cell; use std::mem; @@ -75,6 +76,10 @@ pub struct ServoParser { suspended: Cell<bool>, /// https://html.spec.whatwg.org/multipage/#script-nesting-level script_nesting_level: Cell<usize>, + /// https://html.spec.whatwg.org/multipage/#abort-a-parser + aborted: Cell<bool>, + /// https://html.spec.whatwg.org/multipage/#script-created-parser + script_created_parser: bool, } #[derive(PartialEq)] @@ -87,7 +92,8 @@ impl ServoParser { pub fn parse_html_document(document: &Document, input: DOMString, url: ServoUrl) { let parser = ServoParser::new(document, Tokenizer::Html(self::html::Tokenizer::new(document, url, None)), - LastChunkState::NotReceived); + LastChunkState::NotReceived, + ParserKind::Normal); parser.parse_chunk(String::from(input)); } @@ -129,7 +135,8 @@ impl ServoParser { Tokenizer::Html(self::html::Tokenizer::new(&document, url.clone(), Some(fragment_context))), - LastChunkState::Received); + LastChunkState::Received, + ParserKind::Normal); parser.parse_chunk(String::from(input)); // Step 14. @@ -139,10 +146,23 @@ impl ServoParser { } } + pub fn parse_html_script_input(document: &Document, url: ServoUrl, type_: &str) { + let parser = ServoParser::new(document, + Tokenizer::Html(self::html::Tokenizer::new(document, url, None)), + LastChunkState::NotReceived, + ParserKind::ScriptCreated); + document.set_current_parser(Some(&parser)); + if !type_.eq_ignore_ascii_case("text/html") { + parser.parse_chunk("<pre>\n".to_owned()); + parser.tokenizer.borrow_mut().set_plaintext_state(); + } + } + pub fn parse_xml_document(document: &Document, input: DOMString, url: ServoUrl) { let parser = ServoParser::new(document, Tokenizer::Xml(self::xml::Tokenizer::new(document, url)), - LastChunkState::NotReceived); + LastChunkState::NotReceived, + ParserKind::Normal); parser.parse_chunk(String::from(input)); } @@ -150,6 +170,10 @@ impl ServoParser { self.script_nesting_level.get() } + pub fn is_script_created(&self) -> bool { + self.script_created_parser + } + /// Corresponds to the latter part of the "Otherwise" branch of the 'An end /// tag whose tag name is "script"' of /// https://html.spec.whatwg.org/multipage/#parsing-main-incdata @@ -186,9 +210,13 @@ impl ServoParser { } } + pub fn can_write(&self) -> bool { + self.script_created_parser || self.script_nesting_level.get() > 0 + } + /// Steps 6-8 of https://html.spec.whatwg.org/multipage/#document.write() pub fn write(&self, text: Vec<DOMString>) { - assert!(self.script_nesting_level.get() > 0); + assert!(self.can_write()); if self.document.has_pending_parsing_blocking_script() { // There is already a pending parsing blocking script so the @@ -225,10 +253,47 @@ impl ServoParser { assert!(input.is_empty()); } + // Steps 4-6 of https://html.spec.whatwg.org/multipage/#dom-document-close + pub fn close(&self) { + assert!(self.script_created_parser); + + // Step 4. + self.last_chunk_received.set(true); + + if self.suspended.get() { + // Step 5. + return; + } + + // Step 6. + self.parse_sync(); + } + + // https://html.spec.whatwg.org/multipage/#abort-a-parser + pub fn abort(&self) { + assert!(!self.aborted.get()); + self.aborted.set(true); + + // Step 1. + *self.script_input.borrow_mut() = BufferQueue::new(); + *self.network_input.borrow_mut() = BufferQueue::new(); + + // Step 2. + self.document.set_ready_state(DocumentReadyState::Interactive); + + // Step 3. + self.tokenizer.borrow_mut().end(); + self.document.set_current_parser(None); + + // Step 4. + self.document.set_ready_state(DocumentReadyState::Interactive); + } + #[allow(unrooted_must_root)] fn new_inherited(document: &Document, tokenizer: Tokenizer, - last_chunk_state: LastChunkState) + last_chunk_state: LastChunkState, + kind: ParserKind) -> Self { ServoParser { reflector: Reflector::new(), @@ -239,15 +304,18 @@ impl ServoParser { last_chunk_received: Cell::new(last_chunk_state == LastChunkState::Received), suspended: Default::default(), script_nesting_level: Default::default(), + aborted: Default::default(), + script_created_parser: kind == ParserKind::ScriptCreated, } } #[allow(unrooted_must_root)] fn new(document: &Document, tokenizer: Tokenizer, - last_chunk_state: LastChunkState) + last_chunk_state: LastChunkState, + kind: ParserKind) -> Root<Self> { - reflect_dom_object(box ServoParser::new_inherited(document, tokenizer, last_chunk_state), + reflect_dom_object(box ServoParser::new_inherited(document, tokenizer, last_chunk_state, kind), document.window(), ServoParserBinding::Wrap) } @@ -301,6 +369,7 @@ impl ServoParser { { loop { assert!(!self.suspended.get()); + assert!(!self.aborted.get()); self.document.reflow_if_reflow_timer_expired(); let script = match feed(&mut *self.tokenizer.borrow_mut()) { @@ -358,6 +427,12 @@ impl Iterator for FragmentParsingResult { } } +#[derive(HeapSizeOf, JSTraceable, PartialEq)] +enum ParserKind { + Normal, + ScriptCreated, +} + #[derive(HeapSizeOf, JSTraceable)] #[must_root] enum Tokenizer { @@ -454,6 +529,9 @@ impl FetchResponseListener for ParserContext { Some(parser) => parser, None => return, }; + if parser.aborted.get() { + return; + } self.parser = Some(Trusted::new(&*parser)); @@ -512,15 +590,19 @@ impl FetchResponseListener for ParserContext { } fn process_response_chunk(&mut self, payload: Vec<u8>) { - if !self.is_synthesized_document { - // FIXME: use Vec<u8> (html5ever #34) - let data = UTF_8.decode(&payload, DecoderTrap::Replace).unwrap(); - let parser = match self.parser.as_ref() { - Some(parser) => parser.root(), - None => return, - }; - parser.parse_chunk(data); + if self.is_synthesized_document { + return; + } + // FIXME: use Vec<u8> (html5ever #34) + let data = UTF_8.decode(&payload, DecoderTrap::Replace).unwrap(); + let parser = match self.parser.as_ref() { + Some(parser) => parser.root(), + None => return, + }; + if parser.aborted.get() { + return; } + parser.parse_chunk(data); } fn process_response_eof(&mut self, status: Result<(), NetworkError>) { @@ -528,6 +610,9 @@ impl FetchResponseListener for ParserContext { Some(parser) => parser.root(), None => return, }; + if parser.aborted.get() { + return; + } if let Err(NetworkError::Internal(ref reason)) = status { // Show an error page for network errors, |