diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/Cargo.toml | 6 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 3 | ||||
-rw-r--r-- | components/script/dom/history.rs | 16 | ||||
-rw-r--r-- | components/script/dom/htmliframeelement.rs | 14 | ||||
-rw-r--r-- | components/script/dom/servoparser/html.rs | 6 | ||||
-rw-r--r-- | components/script/dom/servoparser/mod.rs | 71 | ||||
-rw-r--r-- | components/script/dom/servoparser/xml.rs | 10 | ||||
-rw-r--r-- | components/script/dom/webidls/Window.webidl | 2 | ||||
-rw-r--r-- | components/script/dom/window.rs | 7 | ||||
-rw-r--r-- | components/script/script_thread.rs | 4 | ||||
-rw-r--r-- | components/script/webdriver_handlers.rs | 15 |
11 files changed, 97 insertions, 57 deletions
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 8752120cb89..bc6c17a8871 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -28,7 +28,7 @@ angle = {git = "https://github.com/servo/angle", branch = "servo"} app_units = "0.4.1" audio-video-metadata = "0.1.2" atomic_refcell = "0.1" -base64 = "0.4.2" +base64 = "0.5.2" bitflags = "0.7" bluetooth_traits = {path = "../bluetooth_traits"} byteorder = "1.0" @@ -48,7 +48,7 @@ gfx_traits = {path = "../gfx_traits"} half = "1.0" heapsize = "0.3.6" heapsize_derive = "0.1" -html5ever = {version = "0.16", features = ["heap_size", "unstable"]} +html5ever = {version = "0.17", features = ["heap_size", "unstable"]} hyper = "0.10" hyper_serde = "0.6" image = "0.12" @@ -90,7 +90,7 @@ time = "0.1.12" unicode-segmentation = "1.1.0" url = {version = "1.2", features = ["heap_size", "query_encoding"]} uuid = {version = "0.4", features = ["v4"]} -xml5ever = {version = "0.6", features = ["unstable"]} +xml5ever = {version = "0.7", features = ["unstable"]} webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]} webvr = {path = "../webvr"} webvr_traits = {path = "../webvr_traits"} diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index dca1b0e2ea5..64ef88da5e3 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -49,6 +49,7 @@ use euclid::rect::Rect; use euclid::size::Size2D; use html5ever::{Prefix, LocalName, Namespace, QualName}; use html5ever::buffer_queue::BufferQueue; +use html5ever::tendril::IncompleteUtf8; use hyper::header::Headers; use hyper::method::Method; use hyper::mime::Mime; @@ -341,7 +342,7 @@ unsafe_no_jsmanaged_fields!(BrowsingContextId, FrameType, PipelineId, TopLevelBr unsafe_no_jsmanaged_fields!(TimerEventId, TimerSource); unsafe_no_jsmanaged_fields!(TimelineMarkerType); unsafe_no_jsmanaged_fields!(WorkerId); -unsafe_no_jsmanaged_fields!(BufferQueue, QuirksMode); +unsafe_no_jsmanaged_fields!(BufferQueue, QuirksMode, IncompleteUtf8); unsafe_no_jsmanaged_fields!(Runtime); unsafe_no_jsmanaged_fields!(Headers, Method); unsafe_no_jsmanaged_fields!(WindowProxyHandler); diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs index 5488d02d9bf..b9601d2ca1c 100644 --- a/components/script/dom/history.rs +++ b/components/script/dom/history.rs @@ -44,10 +44,9 @@ impl History { if !self.window.Document().is_fully_active() { return Err(Error::Security); } - let global_scope = self.window.upcast::<GlobalScope>(); - let pipeline = global_scope.pipeline_id(); - let msg = ConstellationMsg::TraverseHistory(Some(pipeline), direction); - let _ = global_scope.constellation_chan().send(msg); + let top_level_browsing_context_id = self.window.window_proxy().top_level_browsing_context_id(); + let msg = ConstellationMsg::TraverseHistory(top_level_browsing_context_id, direction); + let _ = self.window.upcast::<GlobalScope>().constellation_chan().send(msg); Ok(()) } } @@ -58,13 +57,12 @@ impl HistoryMethods for History { if !self.window.Document().is_fully_active() { return Err(Error::Security); } - let global_scope = self.window.upcast::<GlobalScope>(); - let pipeline = global_scope.pipeline_id(); + let top_level_browsing_context_id = self.window.window_proxy().top_level_browsing_context_id(); let (sender, recv) = ipc::channel().expect("Failed to create channel to send jsh length."); - let msg = ConstellationMsg::JointSessionHistoryLength(pipeline, sender); - let _ = global_scope.constellation_chan().send(msg); + let msg = ConstellationMsg::JointSessionHistoryLength(top_level_browsing_context_id, sender); + let _ = self.window.upcast::<GlobalScope>().constellation_chan().send(msg); Ok(recv.recv().unwrap()) - } +} // https://html.spec.whatwg.org/multipage/#dom-history-go fn Go(&self, delta: i32) -> ErrorResult { diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 00755213c75..23feab87329 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -540,18 +540,16 @@ unsafe fn build_mozbrowser_event_detail(event: MozBrowserEvent, pub fn Navigate(iframe: &HTMLIFrameElement, direction: TraversalDirection) -> ErrorResult { if iframe.Mozbrowser() { - if iframe.upcast::<Node>().is_in_doc_with_browsing_context() { + if let Some(top_level_browsing_context_id) = iframe.top_level_browsing_context_id() { let window = window_from_node(iframe); - let msg = ConstellationMsg::TraverseHistory(iframe.pipeline_id(), direction); + let msg = ConstellationMsg::TraverseHistory(top_level_browsing_context_id, direction); window.upcast::<GlobalScope>().constellation_chan().send(msg).unwrap(); + return Ok(()); } - - Ok(()) - } else { - debug!(concat!("this frame is not mozbrowser: mozbrowser attribute missing, or not a top", - "level window, or mozbrowser preference not set (use --pref dom.mozbrowser.enabled)")); - Err(Error::NotSupported) } + debug!(concat!("this frame is not mozbrowser: mozbrowser attribute missing, or not a top", + "level window, or mozbrowser preference not set (use --pref dom.mozbrowser.enabled)")); + Err(Error::NotSupported) } impl HTMLIFrameElementMethods for HTMLIFrameElement { diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs index f25e95507e4..2f0bdd8f7f1 100644 --- a/components/script/dom/servoparser/html.rs +++ b/components/script/dom/servoparser/html.rs @@ -87,7 +87,7 @@ impl Tokenizer { } pub fn url(&self) -> &ServoUrl { - &self.inner.sink().sink().base_url + &self.inner.sink.sink.base_url } pub fn set_plaintext_state(&mut self) { @@ -109,9 +109,9 @@ unsafe impl JSTraceable for HtmlTokenizer<TreeBuilder<JS<Node>, Sink>> { } } - let tree_builder = self.sink(); + let tree_builder = &self.sink; tree_builder.trace_handles(&tracer); - tree_builder.sink().trace(trc); + tree_builder.sink.trace(trc); } } diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index 39c199a34f7..af017d58958 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -29,11 +29,9 @@ use dom::processinginstruction::ProcessingInstruction; use dom::text::Text; use dom::virtualmethods::vtable_for; use dom_struct::dom_struct; -use encoding::all::UTF_8; -use encoding::types::{DecoderTrap, Encoding}; use html5ever::{Attribute, QualName, ExpandedName}; use html5ever::buffer_queue::BufferQueue; -use html5ever::tendril::StrTendril; +use html5ever::tendril::{StrTendril, ByteTendril, IncompleteUtf8}; use html5ever::tree_builder::{NodeOrText, TreeSink, NextParserState, QuirksMode, ElementFlags}; use hyper::header::ContentType; use hyper::mime::{Mime, SubLevel, TopLevel}; @@ -76,6 +74,9 @@ pub struct ServoParser { /// Input received from network. #[ignore_heap_size_of = "Defined in html5ever"] network_input: DOMRefCell<BufferQueue>, + /// Part of an UTF-8 code point spanning input chunks + #[ignore_heap_size_of = "Defined in html5ever"] + incomplete_utf8: DOMRefCell<Option<IncompleteUtf8>>, /// Input received from script. Used only to support document.write(). #[ignore_heap_size_of = "Defined in html5ever"] script_input: DOMRefCell<BufferQueue>, @@ -105,7 +106,7 @@ impl ServoParser { Tokenizer::Html(self::html::Tokenizer::new(document, url, None)), LastChunkState::NotReceived, ParserKind::Normal); - parser.parse_chunk(String::from(input)); + parser.parse_string_chunk(String::from(input)); } // https://html.spec.whatwg.org/multipage/#parsing-html-fragments @@ -148,7 +149,7 @@ impl ServoParser { Some(fragment_context))), LastChunkState::Received, ParserKind::Normal); - parser.parse_chunk(String::from(input)); + parser.parse_string_chunk(String::from(input)); // Step 14. let root_element = document.GetDocumentElement().expect("no document element"); @@ -164,7 +165,7 @@ impl ServoParser { ParserKind::ScriptCreated); document.set_current_parser(Some(&parser)); if !type_.eq_ignore_ascii_case("text/html") { - parser.parse_chunk("<pre>\n".to_owned()); + parser.parse_string_chunk("<pre>\n".to_owned()); parser.tokenizer.borrow_mut().set_plaintext_state(); } } @@ -174,7 +175,7 @@ impl ServoParser { Tokenizer::Xml(self::xml::Tokenizer::new(document, url)), LastChunkState::NotReceived, ParserKind::Normal); - parser.parse_chunk(String::from(input)); + parser.parse_string_chunk(String::from(input)); } pub fn script_nesting_level(&self) -> usize { @@ -309,6 +310,7 @@ impl ServoParser { ServoParser { reflector: Reflector::new(), document: JS::from_ref(document), + incomplete_utf8: DOMRefCell::new(None), network_input: DOMRefCell::new(BufferQueue::new()), script_input: DOMRefCell::new(BufferQueue::new()), tokenizer: DOMRefCell::new(tokenizer), @@ -331,7 +333,28 @@ impl ServoParser { ServoParserBinding::Wrap) } - fn push_input_chunk(&self, chunk: String) { + fn push_bytes_input_chunk(&self, chunk: Vec<u8>) { + let mut chunk = ByteTendril::from(&*chunk); + let mut network_input = self.network_input.borrow_mut(); + let mut incomplete_utf8 = self.incomplete_utf8.borrow_mut(); + + if let Some(mut incomplete) = incomplete_utf8.take() { + let result = incomplete.try_complete(chunk, |s| network_input.push_back(s)); + match result { + Err(()) => { + *incomplete_utf8 = Some(incomplete); + return + } + Ok(remaining) => { + chunk = remaining + } + } + } + + *incomplete_utf8 = chunk.decode_utf8_lossy(|s| network_input.push_back(s)); + } + + fn push_string_input_chunk(&self, chunk: String) { self.network_input.borrow_mut().push_back(chunk.into()); } @@ -354,6 +377,11 @@ impl ServoParser { // This parser will continue to parse while there is either pending input or // the parser remains unsuspended. + if self.last_chunk_received.get() { + if let Some(_) = self.incomplete_utf8.borrow_mut().take() { + self.network_input.borrow_mut().push_back(StrTendril::from("\u{FFFD}")) + } + } self.tokenize(|tokenizer| tokenizer.feed(&mut *self.network_input.borrow_mut())); if self.suspended.get() { @@ -367,9 +395,17 @@ impl ServoParser { } } - fn parse_chunk(&self, input: String) { + fn parse_string_chunk(&self, input: String) { + self.document.set_current_parser(Some(self)); + self.push_string_input_chunk(input); + if !self.suspended.get() { + self.parse_sync(); + } + } + + fn parse_bytes_chunk(&self, input: Vec<u8>) { self.document.set_current_parser(Some(self)); - self.push_input_chunk(input); + self.push_bytes_input_chunk(input); if !self.suspended.get() { self.parse_sync(); } @@ -407,6 +443,7 @@ impl ServoParser { assert!(self.last_chunk_received.get()); assert!(self.script_input.borrow().is_empty()); assert!(self.network_input.borrow().is_empty()); + assert!(self.incomplete_utf8.borrow().is_none()); // Step 1. self.document.set_ready_state(DocumentReadyState::Interactive); @@ -558,7 +595,7 @@ impl FetchResponseListener for ParserContext { Some(ContentType(Mime(TopLevel::Image, _, _))) => { self.is_synthesized_document = true; let page = "<html><body></body></html>".into(); - parser.push_input_chunk(page); + parser.push_string_input_chunk(page); parser.parse_sync(); let doc = &parser.document; @@ -571,7 +608,7 @@ impl FetchResponseListener for ParserContext { Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) => { // https://html.spec.whatwg.org/multipage/#read-text let page = "<pre>\n".into(); - parser.push_input_chunk(page); + parser.push_string_input_chunk(page); parser.parse_sync(); parser.tokenizer.borrow_mut().set_plaintext_state(); }, @@ -582,7 +619,7 @@ impl FetchResponseListener 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); - parser.push_input_chunk(page); + parser.push_string_input_chunk(page); parser.parse_sync(); } if let Some(reason) = network_error { @@ -590,7 +627,7 @@ impl FetchResponseListener for ParserContext { let page_bytes = read_resource_file("neterror.html").unwrap(); let page = String::from_utf8(page_bytes).unwrap(); let page = page.replace("${reason}", &reason); - parser.push_input_chunk(page); + parser.push_string_input_chunk(page); parser.parse_sync(); } }, @@ -606,7 +643,7 @@ impl FetchResponseListener for ParserContext { toplevel.as_str(), sublevel.as_str()); self.is_synthesized_document = true; - parser.push_input_chunk(page); + parser.push_string_input_chunk(page); parser.parse_sync(); }, None => { @@ -620,8 +657,6 @@ impl FetchResponseListener for ParserContext { 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, @@ -629,7 +664,7 @@ impl FetchResponseListener for ParserContext { if parser.aborted.get() { return; } - parser.parse_chunk(data); + parser.parse_bytes_chunk(payload); } fn process_response_eof(&mut self, status: Result<(), NetworkError>) { diff --git a/components/script/dom/servoparser/xml.rs b/components/script/dom/servoparser/xml.rs index da5e1987253..508a6692919 100644 --- a/components/script/dom/servoparser/xml.rs +++ b/components/script/dom/servoparser/xml.rs @@ -44,13 +44,13 @@ impl Tokenizer { if !input.is_empty() { while let Some(chunk) = input.pop_front() { self.inner.feed(chunk); - if let Some(script) = self.inner.sink().sink().script.take() { + if let Some(script) = self.inner.sink.sink.script.take() { return Err(script); } } } else { self.inner.run(); - if let Some(script) = self.inner.sink().sink().script.take() { + if let Some(script) = self.inner.sink.sink.script.take() { return Err(script); } } @@ -62,7 +62,7 @@ impl Tokenizer { } pub fn url(&self) -> &ServoUrl { - &self.inner.sink().sink().base_url + &self.inner.sink.sink.base_url } } @@ -80,8 +80,8 @@ unsafe impl JSTraceable for XmlTokenizer<XmlTreeBuilder<JS<Node>, Sink>> { } } - let tree_builder = self.sink(); + let tree_builder = &self.sink; tree_builder.trace_handles(&tracer); - tree_builder.sink().trace(trc); + tree_builder.sink.trace(trc); } } diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl index 548821ac971..3c962f2795e 100644 --- a/components/script/dom/webidls/Window.webidl +++ b/components/script/dom/webidls/Window.webidl @@ -23,7 +23,7 @@ //[Replaceable] readonly attribute BarProp toolbar; attribute DOMString status; void close(); - //readonly attribute boolean closed; + readonly attribute boolean closed; //void stop(); //void focus(); //void blur(); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 7d25b985c2c..b4459bf15db 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -509,6 +509,13 @@ impl WindowMethods for Window { } } + // https://html.spec.whatwg.org/multipage/#dom-window-closed + fn Closed(&self) -> bool { + self.window_proxy.get() + .map(|ref proxy| proxy.is_browsing_context_discarded()) + .unwrap_or(true) + } + // https://html.spec.whatwg.org/multipage/#dom-window-close fn Close(&self) { self.main_thread_script_chan() diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index d66baaeda81..405616fedec 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -1280,8 +1280,8 @@ impl ScriptThread { webdriver_handlers::handle_get_rect(&*documents, pipeline_id, node_id, reply), WebDriverScriptCommand::GetElementText(node_id, reply) => webdriver_handlers::handle_get_text(&*documents, pipeline_id, node_id, reply), - WebDriverScriptCommand::GetPipelineId(browsing_context_id, reply) => - webdriver_handlers::handle_get_pipeline_id(&*documents, pipeline_id, browsing_context_id, reply), + WebDriverScriptCommand::GetBrowsingContextId(webdriver_frame_id, reply) => + webdriver_handlers::handle_get_browsing_context_id(&*documents, pipeline_id, webdriver_frame_id, reply), WebDriverScriptCommand::GetUrl(reply) => webdriver_handlers::handle_get_url(&*documents, pipeline_id, reply), WebDriverScriptCommand::IsEnabled(element_id, reply) => diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index 7bc31263c25..1aa2ad05dab 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -29,6 +29,7 @@ use hyper_serde::Serde; use ipc_channel::ipc::{self, IpcSender}; use js::jsapi::{HandleValue, JSContext}; use js::jsval::UndefinedValue; +use msg::constellation_msg::BrowsingContextId; use msg::constellation_msg::PipelineId; use net_traits::CookieSource::{HTTP, NonHTTP}; use net_traits::CoreResourceMsg::{GetCookiesDataForUrl, SetCookieForUrl}; @@ -109,23 +110,23 @@ pub fn handle_execute_async_script(documents: &Documents, window.upcast::<GlobalScope>().evaluate_js_on_global_with_result(&eval, rval.handle_mut()); } -pub fn handle_get_pipeline_id(documents: &Documents, - pipeline: PipelineId, - webdriver_frame_id: WebDriverFrameId, - reply: IpcSender<Result<Option<PipelineId>, ()>>) { +pub fn handle_get_browsing_context_id(documents: &Documents, + pipeline: PipelineId, + webdriver_frame_id: WebDriverFrameId, + reply: IpcSender<Result<BrowsingContextId, ()>>) { let result = match webdriver_frame_id { WebDriverFrameId::Short(_) => { // This isn't supported yet - Ok(None) + Err(()) }, WebDriverFrameId::Element(x) => { find_node_by_unique_id(documents, pipeline, x) - .and_then(|node| node.downcast::<HTMLIFrameElement>().map(|elem| elem.pipeline_id())) + .and_then(|node| node.downcast::<HTMLIFrameElement>().and_then(|elem| elem.browsing_context_id())) .ok_or(()) }, WebDriverFrameId::Parent => { documents.find_window(pipeline) - .map(|window| window.parent_info().map(|(parent_id, _)| parent_id)) + .and_then(|window| window.window_proxy().parent().map(|parent| parent.browsing_context_id())) .ok_or(()) } }; |