aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/Cargo.toml6
-rw-r--r--components/script/dom/bindings/trace.rs3
-rw-r--r--components/script/dom/history.rs16
-rw-r--r--components/script/dom/htmliframeelement.rs14
-rw-r--r--components/script/dom/servoparser/html.rs6
-rw-r--r--components/script/dom/servoparser/mod.rs71
-rw-r--r--components/script/dom/servoparser/xml.rs10
-rw-r--r--components/script/dom/webidls/Window.webidl2
-rw-r--r--components/script/dom/window.rs7
-rw-r--r--components/script/script_thread.rs4
-rw-r--r--components/script/webdriver_handlers.rs15
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(())
}
};