aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/Cargo.toml1
-rw-r--r--components/script/cors.rs490
-rw-r--r--components/script/dom/bindings/codegen/Bindings.conf6
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py18
-rw-r--r--components/script/dom/bindings/codegen/Configuration.py10
-rw-r--r--components/script/dom/bindings/trace.rs4
-rw-r--r--components/script/dom/blob.rs9
-rw-r--r--components/script/dom/htmliframeelement.rs46
-rw-r--r--components/script/dom/htmllinkelement.rs2
-rw-r--r--components/script/dom/htmlmediaelement.rs2
-rw-r--r--components/script/dom/htmlscriptelement.rs2
-rw-r--r--components/script/dom/node.rs6
-rw-r--r--components/script/dom/webglrenderingcontext.rs403
-rw-r--r--components/script/dom/webgltexture.rs11
-rw-r--r--components/script/dom/webidls/BrowserElement.webidl8
-rw-r--r--components/script/dom/webidls/Element.webidl8
-rw-r--r--components/script/dom/webidls/HTMLIFrameElement.webidl8
-rw-r--r--components/script/dom/webidls/WebGLRenderingContext.webidl10
-rw-r--r--components/script/dom/webidls/Window.webidl24
-rw-r--r--components/script/dom/window.rs62
-rw-r--r--components/script/dom/xmlhttprequest.rs324
-rw-r--r--components/script/lib.rs16
-rw-r--r--components/script/network_listener.rs35
-rw-r--r--components/script/script_thread.rs43
-rw-r--r--components/script/timers.rs5
-rw-r--r--components/script/webdriver_handlers.rs3
26 files changed, 669 insertions, 887 deletions
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml
index 056bb6f72bb..95f1044fd36 100644
--- a/components/script/Cargo.toml
+++ b/components/script/Cargo.toml
@@ -60,7 +60,6 @@ smallvec = "0.1"
string_cache = {version = "0.2.18", features = ["heap_size", "unstable"]}
style = {path = "../style"}
time = "0.1.12"
-unicase = "1.0"
url = {version = "1.0.0", features = ["heap_size", "query_encoding"]}
util = {path = "../util"}
uuid = {version = "0.2", features = ["v4"]}
diff --git a/components/script/cors.rs b/components/script/cors.rs
deleted file mode 100644
index f9d0bbbd264..00000000000
--- a/components/script/cors.rs
+++ /dev/null
@@ -1,490 +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/. */
-
-//! A partial implementation of CORS
-//! For now this library is XHR-specific.
-//! For stuff involving `<img>`, `<iframe>`, `<form>`, etc please check what
-//! the request mode should be and compare with the fetch spec
-//! This library will eventually become the core of the Fetch crate
-//! with CORSRequest being expanded into FetchRequest (etc)
-
-use hyper::client::Request;
-use hyper::header::{AccessControlAllowHeaders, AccessControlRequestHeaders};
-use hyper::header::{AccessControlAllowMethods, AccessControlRequestMethod};
-use hyper::header::{AccessControlAllowOrigin, AccessControlMaxAge};
-use hyper::header::{ContentType, Host};
-use hyper::header::{HeaderView, Headers};
-use hyper::method::Method;
-use hyper::mime::{Mime, SubLevel, TopLevel};
-use hyper::status::StatusClass::Success;
-use net_traits::{AsyncResponseListener, Metadata, NetworkError, ResponseAction};
-use network_listener::{NetworkListener, PreInvoke};
-use script_runtime::ScriptChan;
-use std::ascii::AsciiExt;
-use std::borrow::ToOwned;
-use std::sync::{Arc, Mutex};
-use time::{self, Timespec, now};
-use unicase::UniCase;
-use url::Url;
-use util::thread::spawn_named;
-
-/// Interface for network listeners concerned with CORS checks. Proper network requests
-/// should be initiated from this method, based on the response provided.
-pub trait AsyncCORSResponseListener {
- fn response_available(&self, response: CORSResponse);
-}
-
-#[derive(Clone, HeapSizeOf)]
-pub struct CORSRequest {
- pub origin: Url,
- pub destination: Url,
- pub mode: RequestMode,
- #[ignore_heap_size_of = "Defined in hyper"]
- pub method: Method,
- #[ignore_heap_size_of = "Defined in hyper"]
- pub headers: Headers,
- /// CORS preflight flag (https://fetch.spec.whatwg.org/#concept-http-fetch)
- /// Indicates that a CORS preflight request and/or cache check is to be performed
- pub preflight_flag: bool,
-}
-
-/// https://fetch.spec.whatwg.org/#concept-request-mode
-/// This only covers some of the request modes. The
-/// `same-origin` and `no CORS` modes are unnecessary for XHR.
-#[derive(PartialEq, Copy, Clone, HeapSizeOf)]
-pub enum RequestMode {
- CORS, // CORS
- ForcedPreflight, // CORS-with-forced-preflight
-}
-
-impl CORSRequest {
- /// Creates a CORS request if necessary. Will return an error when fetching is forbidden
- pub fn maybe_new(referer: Url,
- destination: Url,
- mode: RequestMode,
- method: Method,
- headers: Headers,
- same_origin_data_url_flag: bool)
- -> Result<Option<CORSRequest>, ()> {
- if referer.origin() == destination.origin() {
- return Ok(None); // Not cross-origin, proceed with a normal fetch
- }
- match destination.scheme() {
- // As per (https://fetch.spec.whatwg.org/#main-fetch 5.1.9), about URLs can be fetched
- // the same as a basic request.
- "about" if destination.path() == "blank" => Ok(None),
- // As per (https://fetch.spec.whatwg.org/#main-fetch 5.1.9), data URLs can be fetched
- // the same as a basic request if the request's method is GET and the
- // same-origin data-URL flag is set.
- "data" if same_origin_data_url_flag && method == Method::Get => Ok(None),
- "http" | "https" => {
- let mut req = CORSRequest::new(referer, destination, mode, method, headers);
- req.preflight_flag = !is_simple_method(&req.method) ||
- mode == RequestMode::ForcedPreflight;
- if req.headers.iter().any(|h| !is_simple_header(&h)) {
- req.preflight_flag = true;
- }
- Ok(Some(req))
- },
- _ => Err(()),
- }
- }
-
- fn new(mut referer: Url,
- destination: Url,
- mode: RequestMode,
- method: Method,
- headers: Headers)
- -> CORSRequest {
- referer.set_fragment(None);
- referer.set_query(None);
- referer.set_path("");
- CORSRequest {
- origin: referer,
- destination: destination,
- mode: mode,
- method: method,
- headers: headers,
- preflight_flag: false,
- }
- }
-
- pub fn http_fetch_async(&self,
- listener: Box<AsyncCORSResponseListener + Send>,
- script_chan: Box<ScriptChan + Send>) {
- struct CORSContext {
- listener: Box<AsyncCORSResponseListener + Send>,
- response: Option<CORSResponse>,
- }
-
- // This is shoe-horning the CORSReponse stuff into the rest of the async network
- // framework right now. It would be worth redesigning http_fetch to do this properly.
- impl AsyncResponseListener for CORSContext {
- fn headers_available(&mut self, _metadata: Result<Metadata, NetworkError>) {
- }
-
- fn data_available(&mut self, _payload: Vec<u8>) {
- }
-
- fn response_complete(&mut self, _status: Result<(), NetworkError>) {
- let response = self.response.take().unwrap();
- self.listener.response_available(response);
- }
- }
- impl PreInvoke for CORSContext {}
-
- let context = CORSContext {
- listener: listener,
- response: None,
- };
- let listener = NetworkListener {
- context: Arc::new(Mutex::new(context)),
- script_chan: script_chan,
- };
-
- // TODO: this exists only to make preflight check non-blocking
- // perhaps should be handled by the resource thread?
- let req = self.clone();
- spawn_named("cors".to_owned(), move || {
- let response = req.http_fetch();
- let mut context = listener.context.lock();
- let context = context.as_mut().unwrap();
- context.response = Some(response);
- listener.notify(ResponseAction::ResponseComplete(Ok(())));
- });
- }
-
- /// http://fetch.spec.whatwg.org/#concept-http-fetch
- /// This method assumes that the CORS flag is set
- /// This does not perform the full HTTP fetch, rather it handles part of the CORS filtering
- /// if self.mode is ForcedPreflight, then the CORS-with-forced-preflight
- /// fetch flag is set as well
- pub fn http_fetch(&self) -> CORSResponse {
- let response = CORSResponse::new();
- // Step 2: Handle service workers (unimplemented)
- // Step 3
- // Substep 1: Service workers (unimplemented )
- // Substep 2
- let cache = &mut CORSCache(vec!()); // XXXManishearth Should come from user agent
- if self.preflight_flag &&
- !cache.match_method(self, &self.method) &&
- !self.headers.iter().all(|h| is_simple_header(&h) && cache.match_header(self, h.name())) &&
- (!is_simple_method(&self.method) || self.mode == RequestMode::ForcedPreflight) {
- return self.preflight_fetch();
- // Everything after this is part of XHR::fetch()
- // Expect the organization of code to improve once we have a fetch crate
- }
- response
- }
-
- /// https://fetch.spec.whatwg.org/#cors-preflight-fetch
- fn preflight_fetch(&self) -> CORSResponse {
- let error = CORSResponse::new_error();
- let mut cors_response = CORSResponse::new();
-
- // Step 1
- let mut preflight = self.clone();
- preflight.method = Method::Options;
- preflight.headers = Headers::new();
- // Step 2
- preflight.headers.set(AccessControlRequestMethod(self.method.clone()));
-
- // Steps 3-5
- let mut header_names = vec![];
- for header in self.headers.iter() {
- header_names.push(header.name().to_owned());
- }
- header_names.sort();
- preflight.headers
- .set(AccessControlRequestHeaders(header_names.into_iter().map(UniCase).collect()));
-
- let preflight_request = Request::new(preflight.method, preflight.destination);
- let mut req = match preflight_request {
- Ok(req) => req,
- Err(_) => return error,
- };
-
- let host = req.headers().get::<Host>().unwrap().clone();
- *req.headers_mut() = preflight.headers.clone();
- req.headers_mut().set(host);
- let stream = match req.start() {
- Ok(s) => s,
- Err(_) => return error,
- };
- // Step 6
- let response = match stream.send() {
- Ok(r) => r,
- Err(_) => return error,
- };
-
- // Step 7: We don't perform a CORS check here
- // FYI, fn allow_cross_origin_request() performs the CORS check
- match response.status.class() {
- Success => {}
- _ => return error,
- }
- cors_response.headers = response.headers.clone();
- // Substeps 1-3 (parsing rules: https://fetch.spec.whatwg.org/#http-new-header-syntax)
- let methods_substep4 = [self.method.clone()];
- let mut methods = match response.headers.get() {
- Some(&AccessControlAllowMethods(ref v)) => &**v,
- _ => return error,
- };
- let headers = match response.headers.get() {
- Some(&AccessControlAllowHeaders(ref h)) => h,
- _ => return error,
- };
- // Substep 4
- if methods.is_empty() && preflight.mode == RequestMode::ForcedPreflight {
- methods = &methods_substep4;
- }
- // Substep 5
- if !is_simple_method(&self.method) && !methods.iter().any(|m| m == &self.method) {
- return error;
- }
- // Substep 6
- for h in self.headers.iter() {
- if is_simple_header(&h) {
- continue;
- }
- if !headers.iter().any(|ref h2| h.name().eq_ignore_ascii_case(h2)) {
- return error;
- }
- }
- // Substeps 7-8
- let max_age = match response.headers.get() {
- Some(&AccessControlMaxAge(num)) => num,
- None => 0,
- };
- // Substep 9: Impose restrictions on max-age, if any (unimplemented)
- // Substeps 10-12: Add a cache (partially implemented, XXXManishearth)
- // This cache should come from the user agent, creating a new one here to check
- // for compile time errors
- let cache = &mut CORSCache(vec![]);
- for m in methods {
- let cache_match = cache.match_method_and_update(self, m, max_age);
- if !cache_match {
- cache.insert(CORSCacheEntry::new(self.origin.clone(),
- self.destination.clone(),
- max_age,
- false,
- HeaderOrMethod::MethodData(m.clone())));
- }
- }
- // Substeps 13-14
- for h in response.headers.iter() {
- let cache_match = cache.match_header_and_update(self, h.name(), max_age);
- if !cache_match {
- cache.insert(CORSCacheEntry::new(self.origin.clone(),
- self.destination.clone(),
- max_age,
- false,
- HeaderOrMethod::HeaderData(h.to_string())));
- }
- }
- // Substep 15
- cors_response
- }
-}
-
-
-pub struct CORSResponse {
- pub network_error: bool,
- pub headers: Headers,
-}
-
-impl CORSResponse {
- fn new() -> CORSResponse {
- CORSResponse {
- network_error: false,
- headers: Headers::new(),
- }
- }
-
- fn new_error() -> CORSResponse {
- CORSResponse {
- network_error: true,
- headers: Headers::new(),
- }
- }
-}
-
-// CORS Cache stuff
-
-/// A CORS cache object. Anchor it somewhere to the user agent.
-#[derive(Clone)]
-pub struct CORSCache(Vec<CORSCacheEntry>);
-
-/// Union type for CORS cache entries
-/// Each entry might pertain to a header or method
-#[derive(Clone)]
-pub enum HeaderOrMethod {
- HeaderData(String),
- MethodData(Method),
-}
-
-impl HeaderOrMethod {
- fn match_header(&self, header_name: &str) -> bool {
- match *self {
- HeaderOrMethod::HeaderData(ref s) => (&**s).eq_ignore_ascii_case(header_name),
- _ => false,
- }
- }
-
- fn match_method(&self, method: &Method) -> bool {
- match *self {
- HeaderOrMethod::MethodData(ref m) => m == method,
- _ => false,
- }
- }
-}
-
-// An entry in the CORS cache
-#[derive(Clone)]
-pub struct CORSCacheEntry {
- pub origin: Url,
- pub url: Url,
- pub max_age: u32,
- pub credentials: bool,
- pub header_or_method: HeaderOrMethod,
- created: Timespec,
-}
-
-impl CORSCacheEntry {
- fn new(origin: Url,
- url: Url,
- max_age: u32,
- credentials: bool,
- header_or_method: HeaderOrMethod)
- -> CORSCacheEntry {
- CORSCacheEntry {
- origin: origin,
- url: url,
- max_age: max_age,
- credentials: credentials,
- header_or_method: header_or_method,
- created: time::now().to_timespec(),
- }
- }
-}
-
-impl CORSCache {
- /// https://fetch.spec.whatwg.org/#concept-cache-clear
- #[allow(dead_code)]
- fn clear(&mut self, request: &CORSRequest) {
- let CORSCache(buf) = self.clone();
- let new_buf: Vec<CORSCacheEntry> =
- buf.into_iter()
- .filter(|e| e.origin == request.origin && request.destination == e.url)
- .collect();
- *self = CORSCache(new_buf);
- }
-
- // Remove old entries
- fn cleanup(&mut self) {
- let CORSCache(buf) = self.clone();
- let now = time::now().to_timespec();
- let new_buf: Vec<CORSCacheEntry> = buf.into_iter()
- .filter(|e| now.sec > e.created.sec + e.max_age as i64)
- .collect();
- *self = CORSCache(new_buf);
- }
-
- /// https://fetch.spec.whatwg.org/#concept-cache-match-header
- fn find_entry_by_header<'a>(&'a mut self,
- request: &CORSRequest,
- header_name: &str)
- -> Option<&'a mut CORSCacheEntry> {
- self.cleanup();
- // Credentials are not yet implemented here
- self.0.iter_mut().find(|e| {
- e.origin.scheme() == request.origin.scheme() &&
- e.origin.host_str() == request.origin.host_str() &&
- e.origin.port() == request.origin.port() &&
- e.url == request.destination &&
- e.header_or_method.match_header(header_name)
- })
- }
-
- fn match_header(&mut self, request: &CORSRequest, header_name: &str) -> bool {
- self.find_entry_by_header(request, header_name).is_some()
- }
-
- fn match_header_and_update(&mut self,
- request: &CORSRequest,
- header_name: &str,
- new_max_age: u32)
- -> bool {
- self.find_entry_by_header(request, header_name).map(|e| e.max_age = new_max_age).is_some()
- }
-
- fn find_entry_by_method<'a>(&'a mut self,
- request: &CORSRequest,
- method: &Method)
- -> Option<&'a mut CORSCacheEntry> {
- // we can take the method from CORSRequest itself
- self.cleanup();
- // Credentials are not yet implemented here
- self.0.iter_mut().find(|e| {
- e.origin.scheme() == request.origin.scheme() &&
- e.origin.host_str() == request.origin.host_str() &&
- e.origin.port() == request.origin.port() &&
- e.url == request.destination &&
- e.header_or_method.match_method(method)
- })
- }
-
- /// https://fetch.spec.whatwg.org/#concept-cache-match-method
- fn match_method(&mut self, request: &CORSRequest, method: &Method) -> bool {
- self.find_entry_by_method(request, method).is_some()
- }
-
- fn match_method_and_update(&mut self,
- request: &CORSRequest,
- method: &Method,
- new_max_age: u32)
- -> bool {
- self.find_entry_by_method(request, method).map(|e| e.max_age = new_max_age).is_some()
- }
-
- fn insert(&mut self, entry: CORSCacheEntry) {
- self.cleanup();
- self.0.push(entry);
- }
-}
-
-fn is_simple_header(h: &HeaderView) -> bool {
- // FIXME: use h.is::<HeaderType>() when AcceptLanguage and
- // ContentLanguage headers exist
- match &*h.name().to_ascii_lowercase() {
- "accept" | "accept-language" | "content-language" => true,
- "content-type" => match h.value() {
- Some(&ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) |
- Some(&ContentType(Mime(TopLevel::Application, SubLevel::WwwFormUrlEncoded, _))) |
- Some(&ContentType(Mime(TopLevel::Multipart, SubLevel::FormData, _))) => true,
-
- _ => false,
-
- },
- _ => false,
- }
-}
-
-fn is_simple_method(m: &Method) -> bool {
- match *m {
- Method::Get | Method::Head | Method::Post => true,
- _ => false,
- }
-}
-
-/// Perform a CORS check on a header list and CORS request
-/// https://fetch.spec.whatwg.org/#cors-check
-pub fn allow_cross_origin_request(req: &CORSRequest, headers: &Headers) -> bool {
- match headers.get::<AccessControlAllowOrigin>() {
- Some(&AccessControlAllowOrigin::Any) => true, // Not always true, depends on credentials mode
- Some(&AccessControlAllowOrigin::Value(ref url)) => req.origin.as_str() == *url,
- Some(&AccessControlAllowOrigin::Null) |
- None => false,
- }
-}
diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf
index 314151f8c58..44d835589c4 100644
--- a/components/script/dom/bindings/codegen/Bindings.conf
+++ b/components/script/dom/bindings/codegen/Bindings.conf
@@ -23,6 +23,12 @@ DOMInterfaces = {
'URL': {
'weakReferenceable': True,
+},
+
+'WindowProxy' : {
+ 'nativeType': 'BrowsingContext',
+ 'path': 'dom::browsingcontext::BrowsingContext',
+ 'register': False,
}
}
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index c356a7d066c..057246f05aa 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -1695,7 +1695,7 @@ class CGImports(CGWrapper):
"""
Generates the appropriate import/use statements.
"""
- def __init__(self, child, descriptors, callbacks, imports, ignored_warnings=None):
+ def __init__(self, child, descriptors, callbacks, imports, config, ignored_warnings=None):
"""
Adds a set of imports.
"""
@@ -1756,7 +1756,11 @@ class CGImports(CGWrapper):
for c in callbacks:
types += relatedTypesForSignatures(c)
- imports += ['dom::types::%s' % getIdentifier(t).name for t in types if isImportable(t)]
+ descriptorProvider = config.getDescriptorProvider()
+ for t in types:
+ if isImportable(t):
+ descriptor = descriptorProvider.getDescriptor(getIdentifier(t).name)
+ imports += ['%s' % descriptor.path]
statements = []
if len(ignored_warnings) > 0:
@@ -2090,7 +2094,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, config):
# Sort unionStructs by key, retrieve value
unionStructs = (i[1] for i in sorted(unionStructs.items(), key=operator.itemgetter(0)))
- return CGImports(CGList(unionStructs, "\n\n"), [], [], imports, ignored_warnings=[])
+ return CGImports(CGList(unionStructs, "\n\n"), [], [], imports, config, ignored_warnings=[])
class Argument():
@@ -5460,7 +5464,8 @@ class CGBindingRoot(CGThing):
# (hence hasInterfaceObject=False).
descriptors.extend(config.getDescriptors(webIDLFile=webIDLFile,
hasInterfaceObject=False,
- isCallback=False))
+ isCallback=False,
+ register=True))
dictionaries = config.getDictionaries(webIDLFile=webIDLFile)
@@ -5588,6 +5593,7 @@ class CGBindingRoot(CGThing):
'dom::bindings::str::{ByteString, DOMString, USVString}',
'dom::bindings::trace::RootedVec',
'dom::bindings::weakref::{DOM_WEAK_SLOT, WeakBox, WeakReferenceable}',
+ 'dom::browsingcontext::BrowsingContext',
'mem::heap_size_of_raw_self_and_children',
'libc',
'util::prefs',
@@ -5602,7 +5608,7 @@ class CGBindingRoot(CGThing):
'std::rc::Rc',
'std::default::Default',
'std::ffi::CString',
- ])
+ ], config)
# Add the auto-generated comment.
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
@@ -6278,7 +6284,7 @@ class GlobalGenRoots():
'dom::bindings::codegen',
'dom::bindings::codegen::PrototypeList::Proxies',
'libc',
- ], ignored_warnings=[])
+ ], config, ignored_warnings=[])
@staticmethod
def InterfaceTypes(config):
diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py
index 3ee7fb37e77..7aad0f75f75 100644
--- a/components/script/dom/bindings/codegen/Configuration.py
+++ b/components/script/dom/bindings/codegen/Configuration.py
@@ -173,6 +173,7 @@ class Descriptor(DescriptorProvider):
# Read the desc, and fill in the relevant defaults.
ifaceName = self.interface.identifier.name
+ typeName = desc.get('nativeType', ifaceName)
# Callback types do not use JS smart pointers, so we should not use the
# built-in rooting mechanisms for them.
@@ -184,12 +185,13 @@ class Descriptor(DescriptorProvider):
self.nativeType = ty
else:
self.needsRooting = True
- self.returnType = "Root<%s>" % ifaceName
- self.argumentType = "&%s" % ifaceName
- self.nativeType = "*const %s" % ifaceName
+ self.returnType = "Root<%s>" % typeName
+ self.argumentType = "&%s" % typeName
+ self.nativeType = "*const %s" % typeName
- self.concreteType = ifaceName
+ self.concreteType = typeName
self.register = desc.get('register', True)
+ self.path = desc.get('path', 'dom::types::%s' % typeName)
self.outerObjectHook = desc.get('outerObjectHook', 'None')
self.proxy = False
self.weakReferenceable = desc.get('weakReferenceable', False)
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index f33a8834a08..34ec7d19e14 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -43,6 +43,7 @@ use dom::bindings::utils::WindowProxyHandler;
use encoding::types::EncodingRef;
use euclid::length::Length as EuclidLength;
use euclid::matrix2d::Matrix2D;
+use euclid::point::Point2D;
use euclid::rect::Rect;
use euclid::size::Size2D;
use html5ever::tree_builder::QuirksMode;
@@ -57,6 +58,7 @@ use js::rust::Runtime;
use layout_interface::LayoutRPC;
use libc;
use msg::constellation_msg::{FrameType, PipelineId, SubpageId, WindowSizeData, WindowSizeType, ReferrerPolicy};
+use net_traits::filemanager_thread::SelectedFileId;
use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread};
use net_traits::response::HttpsState;
@@ -278,6 +280,7 @@ no_jsmanaged_fields!(usize, u8, u16, u32, u64);
no_jsmanaged_fields!(isize, i8, i16, i32, i64);
no_jsmanaged_fields!(Sender<T>);
no_jsmanaged_fields!(Receiver<T>);
+no_jsmanaged_fields!(Point2D<T>);
no_jsmanaged_fields!(Rect<T>);
no_jsmanaged_fields!(Size2D<T>);
no_jsmanaged_fields!(Arc<T>);
@@ -324,6 +327,7 @@ no_jsmanaged_fields!(USVString);
no_jsmanaged_fields!(ReferrerPolicy);
no_jsmanaged_fields!(ResourceThreads);
no_jsmanaged_fields!(SystemTime);
+no_jsmanaged_fields!(SelectedFileId);
impl JSTraceable for Box<ScriptChan + Send> {
#[inline]
diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs
index b89aa3b9ac2..d8beec236a8 100644
--- a/components/script/dom/blob.rs
+++ b/components/script/dom/blob.rs
@@ -14,14 +14,13 @@ use dom::bindings::str::DOMString;
use encoding::all::UTF_8;
use encoding::types::{EncoderTrap, Encoding};
use ipc_channel::ipc;
-use net_traits::filemanager_thread::FileManagerThreadMsg;
+use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId};
use num_traits::ToPrimitive;
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::cell::Cell;
use std::cmp::{max, min};
use std::sync::Arc;
-use uuid::Uuid;
#[derive(Clone, JSTraceable)]
pub struct DataSlice {
@@ -95,7 +94,7 @@ impl DataSlice {
#[derive(Clone, JSTraceable)]
pub enum BlobImpl {
/// File-based, cached backend
- File(Uuid, DOMRefCell<Option<DataSlice>>),
+ File(SelectedFileId, DOMRefCell<Option<DataSlice>>),
/// Memory-based backend
Memory(DataSlice),
}
@@ -107,7 +106,7 @@ impl BlobImpl {
}
/// Construct file-backed BlobImpl from File ID
- pub fn new_from_file(file_id: Uuid) -> BlobImpl {
+ pub fn new_from_file(file_id: SelectedFileId) -> BlobImpl {
BlobImpl::File(file_id, DOMRefCell::new(None))
}
@@ -184,7 +183,7 @@ impl Blob {
}
}
-fn read_file(global: GlobalRef, id: Uuid) -> Result<DataSlice, ()> {
+fn read_file(global: GlobalRef, id: SelectedFileId) -> Result<DataSlice, ()> {
let file_manager = global.filemanager_thread();
let (chan, recv) = ipc::channel().map_err(|_|())?;
let _ = file_manager.send(FileManagerThreadMsg::ReadFile(chan, id));
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs
index 1c0e0c9cf1a..57248c03e97 100644
--- a/components/script/dom/htmliframeelement.rs
+++ b/components/script/dom/htmliframeelement.rs
@@ -19,11 +19,13 @@ use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::error::{Error, ErrorResult};
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
-use dom::bindings::js::{Root, LayoutJS};
+use dom::bindings::js::{JS, MutNullableHeap, Root, LayoutJS};
use dom::bindings::reflector::Reflectable;
use dom::bindings::str::DOMString;
+use dom::browsingcontext::BrowsingContext;
use dom::customevent::CustomEvent;
use dom::document::Document;
+use dom::domtokenlist::DOMTokenList;
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
use dom::event::Event;
use dom::eventtarget::EventTarget;
@@ -63,13 +65,14 @@ pub struct HTMLIFrameElement {
htmlelement: HTMLElement,
pipeline_id: Cell<Option<PipelineId>>,
subpage_id: Cell<Option<SubpageId>>,
- sandbox: Cell<Option<u8>>,
+ sandbox: MutNullableHeap<JS<DOMTokenList>>,
+ sandbox_allowance: Cell<Option<u8>>,
load_blocker: DOMRefCell<Option<LoadBlocker>>,
}
impl HTMLIFrameElement {
pub fn is_sandboxed(&self) -> bool {
- self.sandbox.get().is_some()
+ self.sandbox_allowance.get().is_some()
}
/// <https://html.spec.whatwg.org/multipage/#otherwise-steps-for-iframe-or-frame-elements>,
@@ -193,7 +196,8 @@ impl HTMLIFrameElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
pipeline_id: Cell::new(None),
subpage_id: Cell::new(None),
- sandbox: Cell::new(None),
+ sandbox: Default::default(),
+ sandbox_allowance: Cell::new(None),
load_blocker: DOMRefCell::new(None),
}
}
@@ -256,6 +260,15 @@ impl HTMLIFrameElement {
}
}
+ pub fn get_content_window(&self) -> Option<Root<Window>> {
+ self.subpage_id.get().and_then(|subpage_id| {
+ let window = window_from_node(self);
+ let window = window.r();
+ let browsing_context = window.browsing_context();
+ browsing_context.find_child_by_subpage(subpage_id)
+ })
+ }
+
}
pub trait HTMLIFrameElementLayoutMethods {
@@ -412,28 +425,21 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
}
// https://html.spec.whatwg.org/multipage/#dom-iframe-sandbox
- fn Sandbox(&self) -> DOMString {
- self.upcast::<Element>().get_string_attribute(&atom!("sandbox"))
- }
-
- // https://html.spec.whatwg.org/multipage/#dom-iframe-sandbox
- fn SetSandbox(&self, sandbox: DOMString) {
- self.upcast::<Element>().set_tokenlist_attribute(&atom!("sandbox"), sandbox);
+ fn Sandbox(&self) -> Root<DOMTokenList> {
+ self.sandbox.or_init(|| DOMTokenList::new(self.upcast::<Element>(), &atom!("sandbox")))
}
// https://html.spec.whatwg.org/multipage/#dom-iframe-contentwindow
- fn GetContentWindow(&self) -> Option<Root<Window>> {
- self.subpage_id.get().and_then(|subpage_id| {
- let window = window_from_node(self);
- let window = window.r();
- let browsing_context = window.browsing_context();
- browsing_context.find_child_by_subpage(subpage_id)
- })
+ fn GetContentWindow(&self) -> Option<Root<BrowsingContext>> {
+ match self.get_content_window() {
+ Some(ref window) => Some(window.browsing_context()),
+ None => None
+ }
}
// https://html.spec.whatwg.org/multipage/#dom-iframe-contentdocument
fn GetContentDocument(&self) -> Option<Root<Document>> {
- self.GetContentWindow().and_then(|window| {
+ self.get_content_window().and_then(|window| {
// FIXME(#10964): this should use the Document's origin and the
// origin of the incumbent settings object.
let self_url = self.get_url();
@@ -515,7 +521,7 @@ impl VirtualMethods for HTMLIFrameElement {
self.super_type().unwrap().attribute_mutated(attr, mutation);
match attr.local_name() {
&atom!("sandbox") => {
- self.sandbox.set(mutation.new_value(attr).map(|value| {
+ self.sandbox_allowance.set(mutation.new_value(attr).map(|value| {
let mut modes = SandboxAllowance::AllowNothing as u8;
for token in value.as_tokens() {
modes |= match &*token.to_ascii_lowercase() {
diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs
index 2b0056a8d65..79b6ed32f0b 100644
--- a/components/script/dom/htmllinkelement.rs
+++ b/components/script/dom/htmllinkelement.rs
@@ -227,7 +227,7 @@ impl HTMLLinkElement {
sender: action_sender,
};
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
- listener.notify(message.to().unwrap());
+ listener.notify_action(message.to().unwrap());
});
if self.parser_inserted.get() {
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index 7256ae1b131..70563ec95c7 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -484,7 +484,7 @@ impl HTMLMediaElement {
sender: action_sender,
};
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
- listener.notify(message.to().unwrap());
+ listener.notify_action(message.to().unwrap());
});
// FIXME: we're supposed to block the load event much earlier than now
diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs
index 1f9f49516dd..f280f670e4b 100644
--- a/components/script/dom/htmlscriptelement.rs
+++ b/components/script/dom/htmlscriptelement.rs
@@ -314,7 +314,7 @@ impl HTMLScriptElement {
sender: action_sender,
};
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
- listener.notify(message.to().unwrap());
+ listener.notify_action(message.to().unwrap());
});
doc.load_async(LoadType::Script(url), response_target);
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 3032abe0685..a3289cca56e 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -298,6 +298,10 @@ impl Node {
self.owner_doc().content_and_heritage_changed(self, NodeDamage::OtherNodeDamage);
child.owner_doc().content_and_heritage_changed(child, NodeDamage::OtherNodeDamage);
}
+
+ pub fn to_untrusted_node_address(&self) -> UntrustedNodeAddress {
+ UntrustedNodeAddress(self.reflector().get_jsobject().get() as *const c_void)
+ }
}
pub struct QuerySelectorIterator {
@@ -622,7 +626,7 @@ impl Node {
pub fn scroll_offset(&self) -> Point2D<f32> {
let document = self.owner_doc();
let window = document.window();
- window.scroll_offset_query(self.to_trusted_node_address())
+ window.scroll_offset_query(self)
}
// https://dom.spec.whatwg.org/#dom-childnode-before
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 70379e772d2..b23ec913eca 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -40,6 +40,7 @@ use util::vec::byte_swap;
use webrender_traits::WebGLError::*;
use webrender_traits::{WebGLCommand, WebGLError, WebGLFramebufferBindingRequest, WebGLParameter};
+type ImagePixelResult = Result<(Vec<u8>, Size2D<i32>), ()>;
pub const MAX_UNIFORM_AND_ATTRIBUTE_LEN: usize = 256;
macro_rules! handle_potential_webgl_error {
@@ -263,6 +264,73 @@ impl WebGLRenderingContext {
}
}
+ fn get_image_pixels(&self,
+ source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>)
+ -> ImagePixelResult {
+ let source = match source {
+ Some(s) => s,
+ None => return Err(()),
+ };
+
+ // NOTE: Getting the pixels probably can be short-circuited if some
+ // parameter is invalid.
+ //
+ // Nontheless, since it's the error case, I'm not totally sure the
+ // complexity is worth it.
+ let (pixels, size) = match source {
+ ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::ImageData(image_data) => {
+ let global = self.global();
+ (image_data.get_data_array(&global.r()), image_data.get_size())
+ },
+ ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLImageElement(image) => {
+ let img_url = match image.get_url() {
+ Some(url) => url,
+ None => return Err(()),
+ };
+
+ let window = window_from_node(&*self.canvas);
+
+ let img = match canvas_utils::request_image_from_cache(window.r(), img_url) {
+ ImageResponse::Loaded(img) => img,
+ ImageResponse::PlaceholderLoaded(_) | ImageResponse::None |
+ ImageResponse::MetadataLoaded(_)
+ => return Err(()),
+ };
+
+ let size = Size2D::new(img.width as i32, img.height as i32);
+
+ // TODO(emilio): Validate that the format argument
+ // is coherent with the image.
+ //
+ // RGB8 should be easy to support too
+ let mut data = match img.format {
+ PixelFormat::RGBA8 => img.bytes.to_vec(),
+ _ => unimplemented!(),
+ };
+
+ byte_swap(&mut data);
+
+ (data, size)
+ },
+ // TODO(emilio): Getting canvas data is implemented in CanvasRenderingContext2D,
+ // but we need to refactor it moving it to `HTMLCanvasElement` and support
+ // WebGLContext (probably via GetPixels()).
+ ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLCanvasElement(canvas) => {
+ let canvas = canvas.r();
+ if let Some((mut data, size)) = canvas.fetch_all_data() {
+ byte_swap(&mut data);
+ (data, size)
+ } else {
+ return Err(());
+ }
+ },
+ ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLVideoElement(_rooted_video)
+ => unimplemented!(),
+ };
+
+ return Ok((pixels, size));
+ }
+
fn validate_tex_internal_format(&self, internal_format: u32) -> bool {
// GL_INVALID_VALUE is generated if internal_format is not an
// accepted format.
@@ -281,6 +349,79 @@ impl WebGLRenderingContext {
}
}
+ fn validate_tex_format(&self, format: u32) -> bool {
+ // GL_INVALID_VALUE is generated if internal_format is not an
+ // accepted format.
+ match format {
+ constants::DEPTH_COMPONENT |
+ constants::ALPHA |
+ constants::RGB |
+ constants::RGBA |
+ constants::LUMINANCE |
+ constants::LUMINANCE_ALPHA => true,
+
+ _ => {
+ self.webgl_error(InvalidEnum);
+ false
+ },
+ }
+ }
+
+ #[allow(unsafe_code)]
+ fn validate_tex_image_2d_data(&self,
+ width: i32,
+ height: i32,
+ format: u32,
+ data_type: u32,
+ data: Option<*mut JSObject>)
+ -> Result<i32, ()> {
+ // TODO(emilio, #10693): Add type-safe wrappers to validations
+ let (element_size, components_per_element) = match data_type {
+ constants::UNSIGNED_BYTE => (1, 1),
+ constants::UNSIGNED_SHORT_5_6_5 => (2, 3),
+ constants::UNSIGNED_SHORT_5_5_5_1 |
+ constants::UNSIGNED_SHORT_4_4_4_4 => (2, 4),
+ _ => unreachable!(), // previously validated
+ };
+
+ let components = match format {
+ constants::DEPTH_COMPONENT => 1,
+ constants::ALPHA => 1,
+ constants::LUMINANCE => 1,
+ constants::LUMINANCE_ALPHA => 2,
+ constants::RGB => 3,
+ constants::RGBA => 4,
+ _ => unreachable!(), // previously validated
+ };
+
+ // If data is non-null, the type of pixels must match the type of the
+ // data to be read.
+ // If it is UNSIGNED_BYTE, a Uint8Array must be supplied;
+ // if it is UNSIGNED_SHORT_5_6_5, UNSIGNED_SHORT_4_4_4_4,
+ // or UNSIGNED_SHORT_5_5_5_1, a Uint16Array must be supplied.
+ // If the types do not match, an INVALID_OPERATION error is generated.
+ let received_size = if let Some(data) = data {
+ if unsafe { array_buffer_view_data_checked::<u16>(data).is_some() } {
+ 2
+ } else if unsafe { array_buffer_view_data_checked::<u8>(data).is_some() } {
+ 1
+ } else {
+ self.webgl_error(InvalidOperation);
+ return Err(());
+ }
+ } else {
+ element_size
+ };
+
+ if received_size != element_size {
+ self.webgl_error(InvalidOperation);
+ return Err(());
+ }
+
+ // NOTE: width and height are positive or zero due to validate()
+ let expected_byte_length = width * height * element_size * components / components_per_element;
+ return Ok(expected_byte_length);
+ }
fn validate_tex_image_2d_parameters(&self,
target: u32,
@@ -307,6 +448,10 @@ impl WebGLRenderingContext {
return false;
},
}
+ // Validate format
+ if !self.validate_tex_format(format) {
+ return false;
+ }
// Validate internal_format
if !self.validate_tex_internal_format(internal_format) {
@@ -461,8 +606,8 @@ impl WebGLRenderingContext {
width as u32,
height as u32, 1,
internal_format,
- level as u32));
-
+ level as u32,
+ Some(data_type)));
// TODO(emilio): Invert axis, convert colorspace, premultiply alpha if requested
let msg = WebGLCommand::TexImage2D(target, level, internal_format as i32,
@@ -472,6 +617,71 @@ impl WebGLRenderingContext {
.send(CanvasMsg::WebGL(msg))
.unwrap()
}
+
+ fn tex_sub_image_2d(&self,
+ target: u32,
+ level: i32,
+ xoffset: i32,
+ yoffset: i32,
+ width: i32,
+ height: i32,
+ format: u32,
+ data_type: u32,
+ pixels: Vec<u8>) { // NB: pixels should NOT be premultipied
+ // This should be validated before reaching this function
+ debug_assert!(self.validate_tex_image_2d_parameters(target, level,
+ format,
+ width, height,
+ 0, format,
+ data_type));
+
+ let slot = match target {
+ constants::TEXTURE_2D
+ => self.bound_texture_2d.get(),
+ constants::TEXTURE_CUBE_MAP
+ => self.bound_texture_cube_map.get(),
+
+ _ => return self.webgl_error(InvalidEnum),
+ };
+
+ let texture = slot.as_ref().expect("No bound texture found after validation");
+
+ if format == constants::RGBA &&
+ data_type == constants::UNSIGNED_BYTE &&
+ self.texture_unpacking_settings.get().contains(PREMULTIPLY_ALPHA) {
+ // TODO(emilio): premultiply here.
+ }
+
+ // We have already validated level
+ let face_index = self.face_index_for_target(target).unwrap();
+ let image_info = texture.image_info_at_face(face_index, level as u32);
+
+ // GL_INVALID_VALUE is generated if:
+ // - xoffset or yoffset is less than 0
+ // - x offset plus the width is greater than the texture width
+ // - y offset plus the height is greater than the texture height
+ if xoffset < 0 || ((xoffset + width) as u32) > image_info.width() ||
+ yoffset < 0 || ((yoffset + height) as u32) > image_info.height() {
+ return self.webgl_error(InvalidValue);
+ }
+
+ // Using internal_format() to do this check
+ // because we are sure format is as same as internal_format.
+ if format != image_info.internal_format().unwrap() ||
+ data_type != image_info.data_type().unwrap() {
+ return self.webgl_error(InvalidOperation);
+ }
+
+ // TODO(emilio): Flip Y axis if necessary here
+
+ // TODO(emilio): Invert axis, convert colorspace, premultiply alpha if requested
+ let msg = WebGLCommand::TexSubImage2D(target, level, xoffset, yoffset,
+ width, height, format, data_type, pixels);
+
+ self.ipc_renderer
+ .send(CanvasMsg::WebGL(msg))
+ .unwrap()
+ }
}
impl Drop for WebGLRenderingContext {
@@ -889,7 +1099,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
width as u32,
height as u32, 1,
internal_format,
- level as u32));
+ level as u32,
+ None));
let msg = WebGLCommand::CopyTexImage2D(target, level, internal_format, x, y,
width, height, border);
@@ -1881,7 +2092,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
.unwrap()
}
- #[allow(unsafe_code)]
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
fn TexImage2D(&self,
_cx: *mut JSContext,
@@ -1904,51 +2114,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
return; // Error handled in validate()
}
- // TODO(emilio, #10693): Add type-safe wrappers to validations
- let (element_size, components_per_element) = match data_type {
- constants::UNSIGNED_BYTE => (1, 1),
- constants::UNSIGNED_SHORT_5_6_5 => (2, 3),
- constants::UNSIGNED_SHORT_5_5_5_1 |
- constants::UNSIGNED_SHORT_4_4_4_4 => (2, 4),
- _ => unreachable!(), // previously validated
- };
-
- let components = match format {
- constants::DEPTH_COMPONENT => 1,
- constants::ALPHA => 1,
- constants::LUMINANCE => 1,
- constants::LUMINANCE_ALPHA => 2,
- constants::RGB => 3,
- constants::RGBA => 4,
- _ => unreachable!(), // previously validated
- };
-
- // If data is non-null, the type of pixels must match the type of the
- // data to be read.
- // If it is UNSIGNED_BYTE, a Uint8Array must be supplied;
- // if it is UNSIGNED_SHORT_5_6_5, UNSIGNED_SHORT_4_4_4_4,
- // or UNSIGNED_SHORT_5_5_5_1, a Uint16Array must be supplied.
- // If the types do not match, an INVALID_OPERATION error is generated.
- let received_size = if let Some(data) = data {
- if unsafe { array_buffer_view_data_checked::<u16>(data).is_some() } {
- 2
- } else if unsafe { array_buffer_view_data_checked::<u8>(data).is_some() } {
- 1
- } else {
- return self.webgl_error(InvalidOperation);
- }
- } else {
- element_size
+ let expected_byte_length = match self.validate_tex_image_2d_data(width,
+ height,
+ format,
+ data_type,
+ data) {
+ Ok(byte_length) => byte_length,
+ Err(_) => return,
};
- if received_size != element_size {
- return self.webgl_error(InvalidOperation);
- }
-
- // NOTE: width and height are positive or zero due to validate()
- let expected_byte_length = width * height * element_size * components / components_per_element;
-
-
// If data is null, a buffer of sufficient size
// initialized to 0 is passed.
let buff = if let Some(data) = data {
@@ -1976,79 +2150,102 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
format: u32,
data_type: u32,
source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>) {
- let source = match source {
- Some(s) => s,
- None => return,
+ // Get pixels from image source
+ let (pixels, size) = match self.get_image_pixels(source) {
+ Ok((pixels, size)) => (pixels, size),
+ Err(_) => return,
};
+ // NB: Border must be zero
+ if !self.validate_tex_image_2d_parameters(target, level, internal_format,
+ size.width, size.height, 0,
+ format, data_type) {
+ return; // Error handled in validate()
+ }
- // NOTE: Getting the pixels probably can be short-circuited if some
- // parameter is invalid.
- //
- // Nontheless, since it's the error case, I'm not totally sure the
- // complexity is worth it.
- let (pixels, size) = match source {
- ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::ImageData(image_data) => {
- let global = self.global();
- (image_data.get_data_array(&global.r()), image_data.get_size())
- },
- ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLImageElement(image) => {
- let img_url = match image.get_url() {
- Some(url) => url,
- None => return,
- };
+ self.tex_image_2d(target, level,
+ internal_format,
+ size.width, size.height, 0,
+ format, data_type, pixels);
+ }
- let window = window_from_node(&*self.canvas);
+ // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
+ fn TexSubImage2D(&self,
+ _cx: *mut JSContext,
+ target: u32,
+ level: i32,
+ xoffset: i32,
+ yoffset: i32,
+ width: i32,
+ height: i32,
+ format: u32,
+ data_type: u32,
+ data: Option<*mut JSObject>) {
+ if !self.validate_tex_image_2d_parameters(target,
+ level,
+ format,
+ width, height,
+ 0,
+ format,
+ data_type) {
+ return; // Error handled in validate()
+ }
- let img = match canvas_utils::request_image_from_cache(window.r(), img_url) {
- ImageResponse::Loaded(img) => img,
- ImageResponse::PlaceholderLoaded(_) | ImageResponse::None |
- ImageResponse::MetadataLoaded(_)
- => return,
- };
+ let expected_byte_length = match self.validate_tex_image_2d_data(width,
+ height,
+ format,
+ data_type,
+ data) {
+ Ok(byte_length) => byte_length,
+ Err(()) => return,
+ };
- let size = Size2D::new(img.width as i32, img.height as i32);
+ // If data is null, a buffer of sufficient size
+ // initialized to 0 is passed.
+ let buff = if let Some(data) = data {
+ array_buffer_view_to_vec::<u8>(data)
+ .expect("Can't reach here without being an ArrayBufferView!")
+ } else {
+ vec![0u8; expected_byte_length as usize]
+ };
- // TODO(emilio): Validate that the format argument
- // is coherent with the image.
- //
- // RGB8 should be easy to support too
- let mut data = match img.format {
- PixelFormat::RGBA8 => img.bytes.to_vec(),
- _ => unimplemented!(),
- };
+ if expected_byte_length != 0 &&
+ buff.len() != expected_byte_length as usize {
+ return self.webgl_error(InvalidOperation);
+ }
- byte_swap(&mut data);
+ self.tex_sub_image_2d(target, level,
+ xoffset, yoffset,
+ width, height,
+ format, data_type, buff);
+ }
- (data, size)
- },
- // TODO(emilio): Getting canvas data is implemented in CanvasRenderingContext2D,
- // but we need to refactor it moving it to `HTMLCanvasElement` and support
- // WebGLContext (probably via GetPixels()).
- ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLCanvasElement(canvas) => {
- let canvas = canvas.r();
- if let Some((mut data, size)) = canvas.fetch_all_data() {
- byte_swap(&mut data);
- (data, size)
- } else {
- return
- }
- },
- ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLVideoElement(_rooted_video)
- => unimplemented!(),
+ // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
+ fn TexSubImage2D_(&self,
+ target: u32,
+ level: i32,
+ xoffset: i32,
+ yoffset: i32,
+ format: u32,
+ data_type: u32,
+ source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>) {
+ // Get pixels from image source
+ let (pixels, size) = match self.get_image_pixels(source) {
+ Ok((pixels, size)) => (pixels, size),
+ Err(_) => return,
};
// NB: Border must be zero
- if !self.validate_tex_image_2d_parameters(target, level, internal_format,
+ if !self.validate_tex_image_2d_parameters(target, level, format,
size.width, size.height, 0,
format, data_type) {
return; // Error handled in validate()
}
- self.tex_image_2d(target, level,
- internal_format,
- size.width, size.height, 0,
- format, data_type, pixels)
+ self.tex_sub_image_2d(target, level,
+ xoffset, yoffset,
+ size.width, size.height,
+ format, data_type, pixels);
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs
index ccd05182968..bd9f34515ba 100644
--- a/components/script/dom/webgltexture.rs
+++ b/components/script/dom/webgltexture.rs
@@ -109,13 +109,15 @@ impl WebGLTexture {
height: u32,
depth: u32,
internal_format: u32,
- level: u32) -> WebGLResult<()> {
+ level: u32,
+ data_type: Option<u32>) -> WebGLResult<()> {
let image_info = ImageInfo {
width: width,
height: height,
depth: depth,
internal_format: Some(internal_format),
is_initialized: true,
+ data_type: data_type,
};
let face = match target {
@@ -274,6 +276,7 @@ impl WebGLTexture {
depth: 0,
internal_format: base_image_info.internal_format,
is_initialized: base_image_info.is_initialized(),
+ data_type: base_image_info.data_type,
};
self.set_image_infos_at_level(level, image_info);
@@ -346,6 +349,7 @@ pub struct ImageInfo {
depth: u32,
internal_format: Option<u32>,
is_initialized: bool,
+ data_type: Option<u32>,
}
impl ImageInfo {
@@ -356,6 +360,7 @@ impl ImageInfo {
depth: 0,
internal_format: None,
is_initialized: false,
+ data_type: None,
}
}
@@ -371,6 +376,10 @@ impl ImageInfo {
self.internal_format
}
+ pub fn data_type(&self) -> Option<u32> {
+ self.data_type
+ }
+
fn is_power_of_two(&self) -> bool {
self.width.is_power_of_two() && self.height.is_power_of_two() && self.depth.is_power_of_two()
}
diff --git a/components/script/dom/webidls/BrowserElement.webidl b/components/script/dom/webidls/BrowserElement.webidl
index ae3b8e310e3..9351cc9377a 100644
--- a/components/script/dom/webidls/BrowserElement.webidl
+++ b/components/script/dom/webidls/BrowserElement.webidl
@@ -159,16 +159,16 @@ interface BrowserElementPrivileged {
// unsigned long count,
// unsigned long modifiers);
- [Func="Window::global_is_mozbrowser", Throws]
+ [Func="::dom::window::Window::global_is_mozbrowser", Throws]
void goBack();
- [Func="Window::global_is_mozbrowser", Throws]
+ [Func="::dom::window::Window::global_is_mozbrowser", Throws]
void goForward();
- [Func="Window::global_is_mozbrowser", Throws]
+ [Func="::dom::window::Window::global_is_mozbrowser", Throws]
void reload(optional boolean hardReload = false);
- [Func="Window::global_is_mozbrowser", Throws]
+ [Func="::dom::window::Window::global_is_mozbrowser", Throws]
void stop();
//[Throws,
diff --git a/components/script/dom/webidls/Element.webidl b/components/script/dom/webidls/Element.webidl
index 48aeed7fbbb..d09f4846c98 100644
--- a/components/script/dom/webidls/Element.webidl
+++ b/components/script/dom/webidls/Element.webidl
@@ -84,14 +84,22 @@ partial interface Element {
DOMRectList getClientRects();
DOMRect getBoundingClientRect();
+ [Func="::script_can_initiate_scroll"]
void scroll(optional ScrollToOptions options);
+ [Func="::script_can_initiate_scroll"]
void scroll(unrestricted double x, unrestricted double y);
+ [Func="::script_can_initiate_scroll"]
void scrollTo(optional ScrollToOptions options);
+ [Func="::script_can_initiate_scroll"]
void scrollTo(unrestricted double x, unrestricted double y);
+ [Func="::script_can_initiate_scroll"]
void scrollBy(optional ScrollToOptions options);
+ [Func="::script_can_initiate_scroll"]
void scrollBy(unrestricted double x, unrestricted double y);
+ [Func="::script_can_initiate_scroll"]
attribute unrestricted double scrollTop;
+ [Func="::script_can_initiate_scroll"]
attribute unrestricted double scrollLeft;
readonly attribute long scrollWidth;
readonly attribute long scrollHeight;
diff --git a/components/script/dom/webidls/HTMLIFrameElement.webidl b/components/script/dom/webidls/HTMLIFrameElement.webidl
index 65ccbe84048..5fe4ef7a661 100644
--- a/components/script/dom/webidls/HTMLIFrameElement.webidl
+++ b/components/script/dom/webidls/HTMLIFrameElement.webidl
@@ -7,14 +7,14 @@ interface HTMLIFrameElement : HTMLElement {
attribute DOMString src;
// attribute DOMString srcdoc;
// attribute DOMString name;
- attribute DOMString sandbox;
+ [SameObject, PutForwards=value]
+ readonly attribute DOMTokenList sandbox;
// attribute boolean seamless;
// attribute boolean allowFullscreen;
attribute DOMString width;
attribute DOMString height;
readonly attribute Document? contentDocument;
- //readonly attribute WindowProxy? contentWindow;
- readonly attribute Window? contentWindow;
+ readonly attribute WindowProxy? contentWindow;
// also has obsolete members
};
@@ -31,7 +31,7 @@ partial interface HTMLIFrameElement {
};
partial interface HTMLIFrameElement {
- [Func="Window::global_is_mozbrowser"]
+ [Func="::dom::window::Window::global_is_mozbrowser"]
attribute boolean mozbrowser;
};
diff --git a/components/script/dom/webidls/WebGLRenderingContext.webidl b/components/script/dom/webidls/WebGLRenderingContext.webidl
index 3ed1c8cdb31..679fedf354b 100644
--- a/components/script/dom/webidls/WebGLRenderingContext.webidl
+++ b/components/script/dom/webidls/WebGLRenderingContext.webidl
@@ -646,11 +646,11 @@ interface WebGLRenderingContextBase
void texParameterf(GLenum target, GLenum pname, GLfloat param);
void texParameteri(GLenum target, GLenum pname, GLint param);
- //void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
- // GLsizei width, GLsizei height,
- // GLenum format, GLenum type, ArrayBufferView? pixels);
- //void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
- // GLenum format, GLenum type, TexImageSource? source); // May throw DOMException
+ void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type, optional object data);
+ void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLenum format, GLenum type, TexImageSource? source); // May throw DOMException
void uniform1f(WebGLUniformLocation? location, GLfloat x);
//void uniform1fv(WebGLUniformLocation? location, Float32Array v);
diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl
index b263d53bb7b..1bf0f7f2c50 100644
--- a/components/script/dom/webidls/Window.webidl
+++ b/components/script/dom/webidls/Window.webidl
@@ -6,10 +6,8 @@
[PrimaryGlobal]
/*sealed*/ interface Window : EventTarget {
// the current browsing context
- //[Unforgeable] readonly attribute WindowProxy window;
- //[Replaceable] readonly attribute WindowProxy self;
- readonly attribute Window window;
- [BinaryName="Self_"] readonly attribute Window self;
+ [Unforgeable] readonly attribute WindowProxy window;
+ [BinaryName="Self_", Replaceable] readonly attribute WindowProxy self;
[Unforgeable] readonly attribute Document document;
// attribute DOMString name;
[/*PutForwards=href, */Unforgeable] readonly attribute Location location;
@@ -28,14 +26,11 @@
//void blur();
// other browsing contexts
- //[Replaceable] readonly attribute WindowProxy frames;
- readonly attribute Window frames;
+ [Replaceable] readonly attribute WindowProxy frames;
//[Replaceable] readonly attribute unsigned long length;
- //[Unforgeable] readonly attribute WindowProxy top;
- readonly attribute Window top;
+ [Unforgeable] readonly attribute WindowProxy top;
// attribute any opener;
- //readonly attribute WindowProxy parent;
- readonly attribute Window parent;
+ readonly attribute WindowProxy parent;
readonly attribute Element? frameElement;
//WindowProxy open(optional DOMString url = "about:blank", optional DOMString target = "_blank",
// optional DOMString features = "", optional boolean replace = false);
@@ -65,6 +60,9 @@
Window implements GlobalEventHandlers;
Window implements WindowEventHandlers;
+[NoInterfaceObject]
+interface WindowProxy {};
+
// https://html.spec.whatwg.org/multipage/#timers
[NoInterfaceObject/*, Exposed=Window,Worker*/]
interface WindowTimers {
@@ -138,11 +136,17 @@ partial interface Window {
readonly attribute long pageXOffset;
readonly attribute long scrollY;
readonly attribute long pageYOffset;
+ [Func="::script_can_initiate_scroll"]
void scroll(optional ScrollToOptions options);
+ [Func="::script_can_initiate_scroll"]
void scroll(unrestricted double x, unrestricted double y);
+ [Func="::script_can_initiate_scroll"]
void scrollTo(optional ScrollToOptions options);
+ [Func="::script_can_initiate_scroll"]
void scrollTo(unrestricted double x, unrestricted double y);
+ [Func="::script_can_initiate_scroll"]
void scrollBy(optional ScrollToOptions options);
+ [Func="::script_can_initiate_scroll"]
void scrollBy(unrestricted double x, unrestricted double y);
// client
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index c8d327897d2..34f7c1acdb0 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -12,6 +12,7 @@ use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::EventHandlerBinding::OnBeforeUnloadEventHandlerNonNull;
use dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
+use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions};
use dom::bindings::codegen::Bindings::WindowBinding::{self, FrameRequestCallback, WindowMethods};
use dom::bindings::error::{Error, ErrorResult, Fallible, report_pending_exception};
@@ -68,7 +69,7 @@ use script_traits::{ScriptMsg as ConstellationMsg, TimerEventRequest, TimerSourc
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::cell::Cell;
-use std::collections::HashSet;
+use std::collections::{HashMap, HashSet};
use std::default::Default;
use std::ffi::CString;
use std::io::{Write, stderr, stdout};
@@ -264,6 +265,9 @@ pub struct Window {
error_reporter: CSSErrorReporter,
+ /// A list of scroll offsets for each scrollable element.
+ scroll_offsets: DOMRefCell<HashMap<UntrustedNodeAddress, Point2D<f32>>>,
+
#[ignore_heap_size_of = "Defined in ipc-channel"]
panic_chan: IpcSender<PanicMsg>,
}
@@ -354,6 +358,13 @@ impl Window {
pub fn css_error_reporter(&self) -> Box<ParseErrorReporter + Send> {
self.error_reporter.clone()
}
+
+ /// Sets a new list of scroll offsets.
+ ///
+ /// This is called when layout gives us new ones and WebRender is in use.
+ pub fn set_scroll_offsets(&self, offsets: HashMap<UntrustedNodeAddress, Point2D<f32>>) {
+ *self.scroll_offsets.borrow_mut() = offsets
+ }
}
#[cfg(any(target_os = "macos", target_os = "linux"))]
@@ -558,32 +569,35 @@ impl WindowMethods for Window {
}
// https://html.spec.whatwg.org/multipage/#dom-window
- fn Window(&self) -> Root<Window> {
- Root::from_ref(self)
+ fn Window(&self) -> Root<BrowsingContext> {
+ self.browsing_context()
}
// https://html.spec.whatwg.org/multipage/#dom-self
- fn Self_(&self) -> Root<Window> {
- self.Window()
+ fn Self_(&self) -> Root<BrowsingContext> {
+ self.browsing_context()
}
// https://html.spec.whatwg.org/multipage/#dom-frames
- fn Frames(&self) -> Root<Window> {
- self.Window()
+ fn Frames(&self) -> Root<BrowsingContext> {
+ self.browsing_context()
}
// https://html.spec.whatwg.org/multipage/#dom-parent
- fn Parent(&self) -> Root<Window> {
- self.parent().unwrap_or(self.Window())
+ fn Parent(&self) -> Root<BrowsingContext> {
+ match self.parent() {
+ Some(window) => window.browsing_context(),
+ None => self.Window()
+ }
}
// https://html.spec.whatwg.org/multipage/#dom-top
- fn Top(&self) -> Root<Window> {
- let mut window = self.Window();
+ fn Top(&self) -> Root<BrowsingContext> {
+ let mut window = Root::from_ref(self);
while let Some(parent) = window.parent() {
window = parent;
}
- window
+ window.browsing_context()
}
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/
@@ -1240,7 +1254,28 @@ impl Window {
self.layout_rpc.node_overflow().0.unwrap()
}
- pub fn scroll_offset_query(&self, node: TrustedNodeAddress) -> Point2D<f32> {
+ pub fn scroll_offset_query(&self, node: &Node) -> Point2D<f32> {
+ // WebRender always keeps the scroll offsets up to date and stored here in the window. So,
+ // if WR is in use, all we need to do is to check our list of scroll offsets and return the
+ // result.
+ if opts::get().use_webrender {
+ let mut node = Root::from_ref(node);
+ loop {
+ if let Some(scroll_offset) = self.scroll_offsets
+ .borrow()
+ .get(&node.to_untrusted_node_address()) {
+ return *scroll_offset
+ }
+ node = match node.GetParentNode() {
+ Some(node) => node,
+ None => break,
+ }
+ }
+ let offset = self.current_viewport.get().origin;
+ return Point2D::new(offset.x.to_f32_px(), offset.y.to_f32_px())
+ }
+
+ let node = node.to_trusted_node_address();
if !self.reflow(ReflowGoal::ForScriptQuery,
ReflowQueryType::NodeLayerIdQuery(node),
ReflowReason::Query) {
@@ -1639,6 +1674,7 @@ impl Window {
webdriver_script_chan: DOMRefCell::new(None),
ignore_further_async_events: Arc::new(AtomicBool::new(false)),
error_reporter: error_reporter,
+ scroll_offsets: DOMRefCell::new(HashMap::new()),
panic_chan: panic_chan,
};
diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs
index 318d3bbc1ec..785a5928c9f 100644
--- a/components/script/dom/xmlhttprequest.rs
+++ b/components/script/dom/xmlhttprequest.rs
@@ -2,8 +2,6 @@
* 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 cors::CORSResponse;
-use cors::{AsyncCORSResponseListener, CORSRequest, RequestMode, allow_cross_origin_request};
use document_loader::DocumentLoader;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
@@ -35,27 +33,28 @@ use encoding::label::encoding_from_whatwg_label;
use encoding::types::{DecoderTrap, EncoderTrap, Encoding, EncodingRef};
use euclid::length::Length;
use hyper::header::Headers;
-use hyper::header::{Accept, ContentLength, ContentType, qitem};
+use hyper::header::{ContentLength, ContentType};
use hyper::http::RawStatus;
use hyper::method::Method;
-use hyper::mime::{self, Mime};
+use hyper::mime::{self, Mime, Attr as MimeAttr, Value as MimeValue};
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use js::jsapi::JS_ClearPendingException;
use js::jsapi::{JSContext, JS_ParseJSON, RootedValue};
use js::jsval::{JSVal, NullValue, UndefinedValue};
use msg::constellation_msg::{PipelineId, ReferrerPolicy};
-use net_traits::CoreResourceMsg::Load;
+use net_traits::CoreResourceMsg::Fetch;
+use net_traits::request::{CredentialsMode, Destination, RequestInit, RequestMode};
use net_traits::trim_http_whitespace;
-use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata, NetworkError, RequestSource};
-use net_traits::{LoadConsumer, LoadContext, LoadData, ResourceCORSData, CoreResourceThread, LoadOrigin};
+use net_traits::{CoreResourceThread, LoadOrigin};
+use net_traits::{FetchResponseListener, Metadata, NetworkError, RequestSource};
use network_listener::{NetworkListener, PreInvoke};
use parse::html::{ParseContext, parse_html};
use parse::xml::{self, parse_xml};
use script_runtime::ScriptChan;
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
-use std::cell::{Cell, RefCell};
+use std::cell::Cell;
use std::default::Default;
use std::str;
use std::sync::{Arc, Mutex};
@@ -82,7 +81,6 @@ pub struct GenerationId(u32);
struct XHRContext {
xhr: TrustedXHRAddress,
gen_id: GenerationId,
- cors_request: Option<CORSRequest>,
buf: DOMRefCell<Vec<u8>>,
sync_status: DOMRefCell<Option<ErrorResult>>,
}
@@ -142,7 +140,6 @@ pub struct XMLHttpRequest {
request_body_len: Cell<usize>,
sync: Cell<bool>,
upload_complete: Cell<bool>,
- upload_events: Cell<bool>,
send_flag: Cell<bool>,
timeout_cancel: DOMRefCell<Option<OneshotTimerHandle>>,
@@ -187,7 +184,6 @@ impl XMLHttpRequest {
request_body_len: Cell::new(0),
sync: Cell::new(false),
upload_complete: Cell::new(false),
- upload_events: Cell::new(false),
send_flag: Cell::new(false),
timeout_cancel: DOMRefCell::new(None),
@@ -216,75 +212,40 @@ impl XMLHttpRequest {
}
}
- fn check_cors(context: Arc<Mutex<XHRContext>>,
- load_data: LoadData,
- req: CORSRequest,
- script_chan: Box<ScriptChan + Send>,
- core_resource_thread: CoreResourceThread) {
- struct CORSContext {
- xhr: Arc<Mutex<XHRContext>>,
- load_data: RefCell<Option<LoadData>>,
- req: CORSRequest,
- script_chan: Box<ScriptChan + Send>,
- core_resource_thread: CoreResourceThread,
- }
-
- impl AsyncCORSResponseListener for CORSContext {
- fn response_available(&self, response: CORSResponse) {
- if response.network_error {
- let mut context = self.xhr.lock().unwrap();
- let xhr = context.xhr.root();
- xhr.process_partial_response(XHRProgress::Errored(context.gen_id, Error::Network));
- *context.sync_status.borrow_mut() = Some(Err(Error::Network));
- return;
- }
-
- let mut load_data = self.load_data.borrow_mut().take().unwrap();
- load_data.cors = Some(ResourceCORSData {
- preflight: self.req.preflight_flag,
- origin: self.req.origin.clone()
- });
-
- XMLHttpRequest::initiate_async_xhr(self.xhr.clone(), self.script_chan.clone(),
- self.core_resource_thread.clone(), load_data);
- }
- }
-
- let cors_context = CORSContext {
- xhr: context,
- load_data: RefCell::new(Some(load_data)),
- req: req.clone(),
- script_chan: script_chan.clone(),
- core_resource_thread: core_resource_thread,
- };
-
- req.http_fetch_async(box cors_context, script_chan);
- }
-
fn initiate_async_xhr(context: Arc<Mutex<XHRContext>>,
script_chan: Box<ScriptChan + Send>,
core_resource_thread: CoreResourceThread,
- load_data: LoadData) {
- impl AsyncResponseListener for XHRContext {
- fn headers_available(&mut self, metadata: Result<Metadata, NetworkError>) {
- let xhr = self.xhr.root();
- let rv = xhr.process_headers_available(self.cors_request.clone(),
- self.gen_id,
- metadata);
- if rv.is_err() {
+ init: RequestInit) {
+ impl FetchResponseListener for XHRContext {
+ fn process_request_body(&mut self) {
+ // todo
+ }
+ fn process_request_eof(&mut self) {
+ // todo
+ }
+ fn process_response(&mut self, metadata: Result<Metadata, NetworkError>) {
+ let xhr = self.xhr.root();
+ let rv = xhr.process_headers_available(self.gen_id,
+ metadata);
+ if rv.is_err() {
+ *self.sync_status.borrow_mut() = Some(rv);
+ }
+ }
+ fn process_response_chunk(&mut self, mut chunk: Vec<u8>) {
+ self.buf.borrow_mut().append(&mut chunk);
+ self.xhr.root().process_data_available(self.gen_id, self.buf.borrow().clone());
+ }
+ fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
+ let rv = match response {
+ Ok(()) => {
+ self.xhr.root().process_response_complete(self.gen_id, Ok(()))
+ }
+ Err(e) => {
+ self.xhr.root().process_response_complete(self.gen_id, Err(e))
+ }
+ };
*self.sync_status.borrow_mut() = Some(rv);
}
- }
-
- fn data_available(&mut self, payload: Vec<u8>) {
- self.buf.borrow_mut().extend_from_slice(&payload);
- self.xhr.root().process_data_available(self.gen_id, self.buf.borrow().clone());
- }
-
- fn response_complete(&mut self, status: Result<(), NetworkError>) {
- let rv = self.xhr.root().process_response_complete(self.gen_id, status);
- *self.sync_status.borrow_mut() = Some(rv);
- }
}
impl PreInvoke for XHRContext {
@@ -298,13 +259,10 @@ impl XMLHttpRequest {
context: context,
script_chan: script_chan,
};
- let response_target = AsyncResponseTarget {
- sender: action_sender,
- };
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
- listener.notify(message.to().unwrap());
+ listener.notify_fetch(message.to().unwrap());
});
- core_resource_thread.send(Load(load_data, LoadConsumer::Listener(response_target), None)).unwrap();
+ core_resource_thread.send(Fetch(init, action_sender)).unwrap();
}
}
@@ -563,12 +521,15 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
Method::Get | Method::Head => None,
_ => data
};
- // Step 4
+ // Step 4 (first half)
let extracted = data.as_ref().map(|d| d.extract());
+
self.request_body_len.set(extracted.as_ref().map_or(0, |e| e.0.len()));
+ // todo preserved headers?
+
// Step 6
- self.upload_events.set(false);
+ self.upload_complete.set(false);
// Step 7
self.upload_complete.set(match extracted {
None => true,
@@ -580,11 +541,6 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
// Step 9
if !self.sync.get() {
- let event_target = self.upload.upcast::<EventTarget>();
- if event_target.has_handlers() {
- self.upload_events.set(true);
- }
-
// If one of the event handlers below aborts the fetch by calling
// abort or open we will need the current generation id to detect it.
// Substep 1
@@ -604,67 +560,108 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
}
// Step 5
- let global = self.global();
+ //TODO - set referrer_policy/referrer_url in request
+ let has_handlers = self.upload.upcast::<EventTarget>().has_handlers();
+ let credentials_mode = if self.with_credentials.get() {
+ CredentialsMode::Include
+ } else {
+ CredentialsMode::CredentialsSameOrigin
+ };
+ let use_url_credentials = if let Some(ref url) = *self.request_url.borrow() {
+ !url.username().is_empty() || url.password().is_some()
+ } else {
+ unreachable!()
+ };
- let mut load_data =
- LoadData::new(LoadContext::Browsing,
- self.request_url.borrow().clone().unwrap(),
- self);
+ let bypass_cross_origin_check = {
+ // We want to be able to do cross-origin requests in browser.html.
+ // If the XHR happens in a top level window and the mozbrowser
+ // preference is enabled, we allow bypassing the CORS check.
+ // This is a temporary measure until we figure out Servo privilege
+ // story. See https://github.com/servo/servo/issues/9582
+ if let GlobalRoot::Window(win) = self.global() {
+ let is_root_pipeline = win.parent_info().is_none();
+ let is_mozbrowser_enabled = mozbrowser_enabled();
+ is_root_pipeline && is_mozbrowser_enabled
+ } else {
+ false
+ }
+ };
- if load_data.url.origin().ne(&global.r().get_url().origin()) {
- load_data.credentials_flag = self.WithCredentials();
- }
- load_data.data = extracted.as_ref().map(|e| e.0.clone());
+ let mut request = RequestInit {
+ method: self.request_method.borrow().clone(),
+ url: self.request_url.borrow().clone().unwrap(),
+ headers: (*self.request_headers.borrow()).clone(),
+ unsafe_request: true,
+ same_origin_data: true,
+ // XXXManishearth figure out how to avoid this clone
+ body: extracted.as_ref().map(|e| e.0.clone()),
+ // XXXManishearth actually "subresource", but it doesn't exist
+ // https://github.com/whatwg/xhr/issues/71
+ destination: Destination::None,
+ synchronous: self.sync.get(),
+ mode: RequestMode::CORSMode,
+ use_cors_preflight: has_handlers,
+ credentials_mode: credentials_mode,
+ use_url_credentials: use_url_credentials,
+ origin: self.global().r().get_url(),
+ referer_url: self.referrer_url.clone(),
+ referrer_policy: self.referrer_policy.clone(),
+ };
- // XHR spec differs from http, and says UTF-8 should be in capitals,
- // instead of "utf-8", which is what Hyper defaults to. So not
- // using content types provided by Hyper.
- let n = "content-type";
- match extracted {
- Some((_, Some(ref content_type))) =>
- load_data.headers.set_raw(n.to_owned(), vec![content_type.bytes().collect()]),
- _ => (),
+ if bypass_cross_origin_check {
+ request.mode = RequestMode::Navigate;
}
- load_data.preserved_headers = (*self.request_headers.borrow()).clone();
+ // step 4 (second half)
+ match extracted {
+ Some((_, ref content_type)) => {
+ // this should handle Document bodies too, not just BodyInit
+ let encoding = if let Some(BodyInit::String(_)) = data {
+ // XHR spec differs from http, and says UTF-8 should be in capitals,
+ // instead of "utf-8", which is what Hyper defaults to. So not
+ // using content types provided by Hyper.
+ Some(MimeValue::Ext("UTF-8".to_string()))
+ } else {
+ None
+ };
- if !load_data.preserved_headers.has::<Accept>() {
- let mime = Mime(mime::TopLevel::Star, mime::SubLevel::Star, vec![]);
- load_data.preserved_headers.set(Accept(vec![qitem(mime)]));
- }
+ let mut content_type_set = false;
+ if let Some(ref ct) = *content_type {
+ if !request.headers.has::<ContentType>() {
+ request.headers.set_raw("content-type", vec![ct.bytes().collect()]);
+ content_type_set = true;
+ }
+ }
- load_data.method = (*self.request_method.borrow()).clone();
+ if !content_type_set {
+ let ct = request.headers.get::<ContentType>().map(|x| x.clone());
+ if let Some(mut ct) = ct {
+ if let Some(encoding) = encoding {
+ for param in &mut (ct.0).2 {
+ if param.0 == MimeAttr::Charset {
+ if !param.0.as_str().eq_ignore_ascii_case(encoding.as_str()) {
+ *param = (MimeAttr::Charset, encoding.clone());
+ }
+ }
+ }
+ }
+ // remove instead of mutate in place
+ // https://github.com/hyperium/hyper/issues/821
+ request.headers.remove_raw("content-type");
+ request.headers.set(ct);
+ }
+ }
- // CORS stuff
- let global = self.global();
- let referer_url = self.global().r().get_url();
- let mode = if self.upload_events.get() {
- RequestMode::ForcedPreflight
- } else {
- RequestMode::CORS
- };
- let mut combined_headers = load_data.headers.clone();
- combined_headers.extend(load_data.preserved_headers.iter());
- let cors_request = CORSRequest::maybe_new(referer_url.clone(),
- load_data.url.clone(),
- mode,
- load_data.method.clone(),
- combined_headers,
- true);
- match cors_request {
- Ok(None) => {
- let bytes = referer_url[..Position::AfterPath].as_bytes().to_vec();
- self.request_headers.borrow_mut().set_raw("Referer".to_owned(), vec![bytes]);
- },
- Ok(Some(ref req)) => self.insert_trusted_header("origin".to_owned(),
- req.origin.to_string()),
- _ => {}
+ }
+ _ => (),
}
- debug!("request_headers = {:?}", *self.request_headers.borrow());
+ debug!("request.headers = {:?}", request.headers);
self.fetch_time.set(time::now().to_timespec().sec);
- let rv = self.fetch(load_data, cors_request, global.r());
+
+ let rv = self.fetch(request, self.global().r());
// Step 10
if self.sync.get() {
return rv;
@@ -879,7 +876,7 @@ impl XMLHttpRequest {
event.fire(self.upcast());
}
- fn process_headers_available(&self, cors_request: Option<CORSRequest>,
+ fn process_headers_available(&self,
gen_id: GenerationId, metadata: Result<Metadata, NetworkError>)
-> Result<(), Error> {
let metadata = match metadata {
@@ -890,35 +887,6 @@ impl XMLHttpRequest {
},
};
- let bypass_cross_origin_check = {
- // We want to be able to do cross-origin requests in browser.html.
- // If the XHR happens in a top level window and the mozbrowser
- // preference is enabled, we allow bypassing the CORS check.
- // This is a temporary measure until we figure out Servo privilege
- // story. See https://github.com/servo/servo/issues/9582
- if let GlobalRoot::Window(win) = self.global() {
- let is_root_pipeline = win.parent_info().is_none();
- let is_mozbrowser_enabled = mozbrowser_enabled();
- is_root_pipeline && is_mozbrowser_enabled
- } else {
- false
- }
- };
-
- if !bypass_cross_origin_check {
- if let Some(ref req) = cors_request {
- match metadata.headers {
- Some(ref h) if allow_cross_origin_request(req, h) => {},
- _ => {
- self.process_partial_response(XHRProgress::Errored(gen_id, Error::Network));
- return Err(Error::Network);
- }
- }
- }
- } else {
- debug!("Bypassing cross origin check");
- }
-
*self.response_url.borrow_mut() = metadata.final_url[..Position::AfterQuery].to_owned();
// XXXManishearth Clear cache entries in case of a network error
@@ -1318,25 +1286,12 @@ impl XMLHttpRequest {
}
fn fetch(&self,
- load_data: LoadData,
- cors_request: Result<Option<CORSRequest>, ()>,
+ init: RequestInit,
global: GlobalRef) -> ErrorResult {
- let cors_request = match cors_request {
- Err(_) => {
- // Happens in case of unsupported cross-origin URI schemes.
- // Supported schemes are http, https, data, and about.
- self.process_partial_response(XHRProgress::Errored(
- self.generation_id.get(), Error::Network));
- return Err(Error::Network);
- }
- Ok(req) => req,
- };
-
let xhr = Trusted::new(self);
let context = Arc::new(Mutex::new(XHRContext {
xhr: xhr,
- cors_request: cors_request.clone(),
gen_id: self.generation_id.get(),
buf: DOMRefCell::new(vec!()),
sync_status: DOMRefCell::new(None),
@@ -1350,13 +1305,8 @@ impl XMLHttpRequest {
};
let core_resource_thread = global.core_resource_thread();
- if let Some(req) = cors_request {
- XMLHttpRequest::check_cors(context.clone(), load_data, req.clone(),
- script_chan.clone(), core_resource_thread);
- } else {
- XMLHttpRequest::initiate_async_xhr(context.clone(), script_chan,
- core_resource_thread, load_data);
- }
+ XMLHttpRequest::initiate_async_xhr(context.clone(), script_chan,
+ core_resource_thread, init);
if let Some(script_port) = script_port {
loop {
diff --git a/components/script/lib.rs b/components/script/lib.rs
index 50b0c47ac6b..2f76a112c0a 100644
--- a/components/script/lib.rs
+++ b/components/script/lib.rs
@@ -79,7 +79,6 @@ extern crate style;
extern crate time;
#[cfg(any(target_os = "macos", target_os = "linux"))]
extern crate tinyfiledialogs;
-extern crate unicase;
extern crate url;
#[macro_use]
extern crate util;
@@ -91,7 +90,6 @@ extern crate xml5ever;
mod blob_url_store;
pub mod bluetooth_blacklist;
pub mod clipboard_provider;
-pub mod cors;
mod devtools;
pub mod document_loader;
#[macro_use]
@@ -112,8 +110,9 @@ mod unpremultiplytable;
mod webdriver_handlers;
use dom::bindings::codegen::RegisterBindings;
-use js::jsapi::SetDOMProxyInformation;
+use js::jsapi::{Handle, JSContext, JSObject, SetDOMProxyInformation};
use std::ptr;
+use util::opts;
#[cfg(target_os = "linux")]
#[allow(unsafe_code)]
@@ -168,3 +167,14 @@ pub fn init() {
perform_platform_specific_initialization();
}
+
+/// FIXME(pcwalton): Currently WebRender cannot handle DOM-initiated scrolls. Remove this when it
+/// can. See PR #11680 for details.
+///
+/// This function is only marked `unsafe` because the `[Func=foo]` WebIDL attribute requires it. It
+/// shouldn't actually do anything unsafe.
+#[allow(unsafe_code)]
+pub unsafe fn script_can_initiate_scroll(_: *mut JSContext, _: Handle<*mut JSObject>) -> bool {
+ !opts::get().use_webrender
+}
+
diff --git a/components/script/network_listener.rs b/components/script/network_listener.rs
index cff0723d277..13aa26c25e4 100644
--- a/components/script/network_listener.rs
+++ b/components/script/network_listener.rs
@@ -2,7 +2,8 @@
* 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 net_traits::{AsyncResponseListener, ResponseAction};
+use net_traits::{Action, AsyncResponseListener, FetchResponseListener};
+use net_traits::{FetchResponseMsg, ResponseAction};
use script_runtime::ScriptThreadEventCategory::NetworkEvent;
use script_runtime::{CommonScriptMsg, ScriptChan};
use script_thread::Runnable;
@@ -10,13 +11,13 @@ use std::sync::{Arc, Mutex};
/// An off-thread sink for async network event runnables. All such events are forwarded to
/// a target thread, where they are invoked on the provided context object.
-pub struct NetworkListener<T: AsyncResponseListener + PreInvoke + Send + 'static> {
- pub context: Arc<Mutex<T>>,
+pub struct NetworkListener<Listener: PreInvoke + Send + 'static> {
+ pub context: Arc<Mutex<Listener>>,
pub script_chan: Box<ScriptChan + Send>,
}
-impl<T: AsyncResponseListener + PreInvoke + Send + 'static> NetworkListener<T> {
- pub fn notify(&self, action: ResponseAction) {
+impl<Listener: PreInvoke + Send + 'static> NetworkListener<Listener> {
+ pub fn notify<A: Action<Listener> + Send + 'static>(&self, action: A) {
if let Err(err) = self.script_chan.send(CommonScriptMsg::RunnableMsg(NetworkEvent, box ListenerRunnable {
context: self.context.clone(),
action: action,
@@ -26,6 +27,20 @@ impl<T: AsyncResponseListener + PreInvoke + Send + 'static> NetworkListener<T> {
}
}
+// helps type inference
+impl<Listener: AsyncResponseListener + PreInvoke + Send + 'static> NetworkListener<Listener> {
+ pub fn notify_action(&self, action: ResponseAction) {
+ self.notify(action);
+ }
+}
+
+// helps type inference
+impl<Listener: FetchResponseListener + PreInvoke + Send + 'static> NetworkListener<Listener> {
+ pub fn notify_fetch(&self, action: FetchResponseMsg) {
+ self.notify(action);
+ }
+}
+
/// A gating mechanism that runs before invoking the runnable on the target thread.
/// If the `should_invoke` method returns false, the runnable is discarded without
/// being invoked.
@@ -36,13 +51,13 @@ pub trait PreInvoke {
}
/// A runnable for moving the async network events between threads.
-struct ListenerRunnable<T: AsyncResponseListener + PreInvoke + Send> {
- context: Arc<Mutex<T>>,
- action: ResponseAction,
+struct ListenerRunnable<A: Action<Listener> + Send + 'static, Listener: PreInvoke + Send> {
+ context: Arc<Mutex<Listener>>,
+ action: A,
}
-impl<T: AsyncResponseListener + PreInvoke + Send> Runnable for ListenerRunnable<T> {
- fn handler(self: Box<ListenerRunnable<T>>) {
+impl<A: Action<Listener> + Send + 'static, Listener: PreInvoke + Send> Runnable for ListenerRunnable<A, Listener> {
+ fn handler(self: Box<ListenerRunnable<A, Listener>>) {
let this = *self;
let mut context = this.context.lock().unwrap();
if context.should_invoke() {
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index eec1853239e..8cf97710bc7 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -85,11 +85,12 @@ use script_traits::{CompositorEvent, ConstellationControlMsg, EventResult};
use script_traits::{InitialScriptState, MouseButton, MouseEventType, MozBrowserEvent};
use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg};
use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource};
-use script_traits::{TouchEventType, TouchId};
+use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress};
use std::borrow::ToOwned;
use std::cell::{Cell, RefCell};
use std::collections::{HashMap, HashSet};
use std::option::Option;
+use std::ptr;
use std::rc::Rc;
use std::result::Result;
use std::sync::atomic::{Ordering, AtomicBool};
@@ -728,9 +729,9 @@ impl ScriptThread {
self.handle_viewport(id, rect);
})
}
- FromConstellation(ConstellationControlMsg::SetScrollState(id, scroll_offset)) => {
+ FromConstellation(ConstellationControlMsg::SetScrollState(id, scroll_state)) => {
self.profile_event(ScriptThreadEventCategory::SetScrollState, || {
- self.handle_set_scroll_state(id, &scroll_offset);
+ self.handle_set_scroll_state(id, &scroll_state);
})
}
FromConstellation(ConstellationControlMsg::TickAllAnimations(
@@ -1087,7 +1088,7 @@ impl ScriptThread {
load.window_size = Some(size);
return;
}
- panic!("resize sent to nonexistent pipeline");
+ warn!("resize sent to nonexistent pipeline");
}
fn handle_viewport(&self, id: PipelineId, rect: Rect<f32>) {
@@ -1110,17 +1111,31 @@ impl ScriptThread {
panic!("Page rect message sent to nonexistent pipeline");
}
- fn handle_set_scroll_state(&self, id: PipelineId, scroll_state: &Point2D<f32>) {
- let context = self.browsing_context.get();
- if let Some(context) = context {
- if let Some(inner_context) = context.find(id) {
- let window = inner_context.active_window();
- window.update_viewport_for_scroll(-scroll_state.x, -scroll_state.y);
- return
+ fn handle_set_scroll_state(&self,
+ id: PipelineId,
+ scroll_states: &[(UntrustedNodeAddress, Point2D<f32>)]) {
+ let window = match self.browsing_context.get() {
+ Some(context) => {
+ match context.find(id) {
+ Some(inner_context) => inner_context.active_window(),
+ None => {
+ panic!("Set scroll state message sent to nonexistent pipeline: {:?}", id)
+ }
+ }
}
- }
+ None => panic!("Set scroll state message sent to nonexistent pipeline: {:?}", id),
+ };
- panic!("Set scroll state message message sent to nonexistent pipeline: {:?}", id);
+ let mut scroll_offsets = HashMap::new();
+ for &(node_address, ref scroll_offset) in scroll_states {
+ if node_address == UntrustedNodeAddress(ptr::null()) {
+ window.update_viewport_for_scroll(-scroll_offset.x, -scroll_offset.y);
+ } else {
+ scroll_offsets.insert(node_address,
+ Point2D::new(-scroll_offset.x, -scroll_offset.y));
+ }
+ }
+ window.set_scroll_offsets(scroll_offsets)
}
fn handle_new_layout(&self, new_layout_info: NewLayoutInfo) {
@@ -1947,7 +1962,7 @@ impl ScriptThread {
script_chan: self.chan.clone(),
};
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
- listener.notify(message.to().unwrap());
+ listener.notify_action(message.to().unwrap());
});
let response_target = AsyncResponseTarget {
sender: action_sender,
diff --git a/components/script/timers.rs b/components/script/timers.rs
index 53113e06682..504dbb8aaaf 100644
--- a/components/script/timers.rs
+++ b/components/script/timers.rs
@@ -176,7 +176,10 @@ impl OneshotTimers {
let base_time = self.base_time();
// Since the event id was the expected one, at least one timer should be due.
- assert!(base_time >= self.timers.borrow().last().unwrap().scheduled_for);
+ if base_time < self.timers.borrow().last().unwrap().scheduled_for {
+ warn!("Unexpected timing!");
+ return;
+ }
// select timers to run to prevent firing timers
// that were installed during fire of another timer
diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs
index 910ffa6c426..3c9d1ffcfb2 100644
--- a/components/script/webdriver_handlers.rs
+++ b/components/script/webdriver_handlers.rs
@@ -6,7 +6,6 @@ use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclar
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
-use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
use dom::bindings::codegen::Bindings::HTMLOptionElementBinding::HTMLOptionElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
@@ -105,7 +104,7 @@ pub fn handle_get_frame_id(context: &BrowsingContext,
match find_node_by_unique_id(context, pipeline, x) {
Some(ref node) => {
match node.downcast::<HTMLIFrameElement>() {
- Some(ref elem) => Ok(elem.GetContentWindow()),
+ Some(ref elem) => Ok(elem.get_content_window()),
None => Err(())
}
},