diff options
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/trace.rs | 10 | ||||
-rw-r--r-- | components/script/dom/canvasrenderingcontext2d.rs | 4 | ||||
-rw-r--r-- | components/script/dom/document.rs | 33 | ||||
-rw-r--r-- | components/script/dom/domimplementation.rs | 4 | ||||
-rw-r--r-- | components/script/dom/domparser.rs | 4 | ||||
-rw-r--r-- | components/script/dom/htmlcanvaselement.rs | 17 | ||||
-rw-r--r-- | components/script/dom/htmliframeelement.rs | 2 | ||||
-rw-r--r-- | components/script/dom/htmlimageelement.rs | 235 | ||||
-rw-r--r-- | components/script/dom/node.rs | 2 | ||||
-rw-r--r-- | components/script/dom/servoparser/mod.rs | 2 | ||||
-rw-r--r-- | components/script/dom/window.rs | 90 | ||||
-rw-r--r-- | components/script/dom/xmldocument.rs | 7 | ||||
-rw-r--r-- | components/script/dom/xmlhttprequest.rs | 2 |
13 files changed, 317 insertions, 95 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index aeddcdabe4b..4d38b39d333 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -62,7 +62,7 @@ use msg::constellation_msg::{FrameId, FrameType, PipelineId}; use net_traits::{Metadata, NetworkError, ReferrerPolicy, ResourceThreads}; use net_traits::filemanager_thread::RelativePos; use net_traits::image::base::{Image, ImageMetadata}; -use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread}; +use net_traits::image_cache_thread::{ImageCacheThread, PendingImageId}; use net_traits::request::{Request, RequestInit}; use net_traits::response::{Response, ResponseBody}; use net_traits::response::HttpsState; @@ -79,7 +79,7 @@ use script_traits::{UntrustedNodeAddress, WindowSizeData, WindowSizeType}; use selectors::matching::ElementSelectorFlags; use serde::{Deserialize, Serialize}; use servo_atoms::Atom; -use servo_url::ServoUrl; +use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl}; use smallvec::SmallVec; use std::cell::{Cell, RefCell, UnsafeCell}; use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; @@ -104,7 +104,6 @@ use style::stylesheets::SupportsRule; use style::values::specified::Length; use style::viewport::ViewportRule; use time::Duration; -use url::Origin as UrlOrigin; use uuid::Uuid; use webrender_traits::{WebGLBufferId, WebGLError, WebGLFramebufferId, WebGLProgramId}; use webrender_traits::{WebGLRenderbufferId, WebGLShaderId, WebGLTextureId}; @@ -317,10 +316,11 @@ unsafe impl<A: JSTraceable, B: JSTraceable, C: JSTraceable> JSTraceable for (A, } } -unsafe_no_jsmanaged_fields!(bool, f32, f64, String, ServoUrl, AtomicBool, AtomicUsize, UrlOrigin, Uuid, char); +unsafe_no_jsmanaged_fields!(bool, f32, f64, String, AtomicBool, AtomicUsize, Uuid, char); unsafe_no_jsmanaged_fields!(usize, u8, u16, u32, u64); unsafe_no_jsmanaged_fields!(isize, i8, i16, i32, i64); -unsafe_no_jsmanaged_fields!(Image, ImageMetadata, ImageCacheChan, ImageCacheThread); +unsafe_no_jsmanaged_fields!(ServoUrl, ImmutableOrigin, MutableOrigin); +unsafe_no_jsmanaged_fields!(Image, ImageMetadata, ImageCacheThread, PendingImageId); unsafe_no_jsmanaged_fields!(Metadata); unsafe_no_jsmanaged_fields!(NetworkError); unsafe_no_jsmanaged_fields!(Atom, Prefix, LocalName, Namespace, QualName); diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index fff339e1cc7..065b966d939 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -429,7 +429,9 @@ impl CanvasRenderingContext2D { let img = match self.request_image_from_cache(url) { ImageResponse::Loaded(img) => img, - ImageResponse::PlaceholderLoaded(_) | ImageResponse::None | ImageResponse::MetadataLoaded(_) => { + ImageResponse::PlaceholderLoaded(_) | + ImageResponse::None | + ImageResponse::MetadataLoaded(_) => { return None; } }; diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 56053555f7c..c836a46f1da 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -105,7 +105,6 @@ use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl}; use net_traits::request::RequestInit; use net_traits::response::HttpsState; use num_traits::ToPrimitive; -use origin::Origin; use script_layout_interface::message::{Msg, ReflowQueryType}; use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory}; use script_thread::{MainThreadScriptMsg, Runnable}; @@ -116,7 +115,7 @@ use script_traits::{TouchEventType, TouchId}; use script_traits::UntrustedNodeAddress; use servo_atoms::Atom; use servo_config::prefs::PREFS; -use servo_url::ServoUrl; +use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl}; use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::cell::{Cell, Ref, RefMut}; @@ -136,6 +135,7 @@ use style::str::{HTML_SPACE_CHARACTERS, split_html_space_chars, str_join}; use style::stylesheets::Stylesheet; use task_source::TaskSource; use time; +use url::Host; use url::percent_encoding::percent_decode; pub enum TouchEventResult { @@ -277,7 +277,7 @@ pub struct Document { https_state: Cell<HttpsState>, touchpad_pressure_phase: Cell<TouchpadPressurePhase>, /// The document's origin. - origin: Origin, + origin: MutableOrigin, /// https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-states referrer_policy: Cell<Option<ReferrerPolicy>>, /// https://html.spec.whatwg.org/multipage/#dom-document-referrer @@ -424,7 +424,7 @@ impl Document { } } - pub fn origin(&self) -> &Origin { + pub fn origin(&self) -> &MutableOrigin { &self.origin } @@ -1949,7 +1949,7 @@ impl Document { pub fn new_inherited(window: &Window, has_browsing_context: HasBrowsingContext, url: Option<ServoUrl>, - origin: Origin, + origin: MutableOrigin, is_html_document: IsHTMLDocument, content_type: Option<DOMString>, last_modified: Option<String>, @@ -2053,7 +2053,7 @@ impl Document { Ok(Document::new(window, HasBrowsingContext::No, None, - doc.origin().alias(), + doc.origin().clone(), IsHTMLDocument::NonHTMLDocument, None, None, @@ -2067,7 +2067,7 @@ impl Document { pub fn new(window: &Window, has_browsing_context: HasBrowsingContext, url: Option<ServoUrl>, - origin: Origin, + origin: MutableOrigin, doctype: IsHTMLDocument, content_type: Option<DOMString>, last_modified: Option<String>, @@ -2154,7 +2154,7 @@ impl Document { HasBrowsingContext::No, None, // https://github.com/whatwg/html/issues/2109 - Origin::opaque_identifier(), + MutableOrigin::new(ImmutableOrigin::new_opaque()), doctype, None, None, @@ -2411,16 +2411,17 @@ impl DocumentMethods for Document { // https://html.spec.whatwg.org/multipage/#relaxing-the-same-origin-restriction fn Domain(&self) -> DOMString { // Step 1. - if self.browsing_context().is_none() { + if !self.has_browsing_context { return DOMString::new(); } - if let Some(host) = self.origin.host() { - // Step 4. - DOMString::from(host.to_string()) - } else { + // Step 2. + match self.origin.effective_domain() { // Step 3. - DOMString::new() + None => DOMString::new(), + // Step 4. + Some(Host::Domain(domain)) => DOMString::from(domain), + Some(host) => DOMString::from(host.to_string()), } } @@ -3077,7 +3078,7 @@ impl DocumentMethods for Document { return Ok(DOMString::new()); } - if !self.origin.is_scheme_host_port_tuple() { + if !self.origin.is_tuple() { return Err(Error::Security); } @@ -3097,7 +3098,7 @@ impl DocumentMethods for Document { return Ok(()); } - if !self.origin.is_scheme_host_port_tuple() { + if !self.origin.is_tuple() { return Err(Error::Security); } diff --git a/components/script/dom/domimplementation.rs b/components/script/dom/domimplementation.rs index 4ec27cc5b36..1de0a24863b 100644 --- a/components/script/dom/domimplementation.rs +++ b/components/script/dom/domimplementation.rs @@ -80,7 +80,7 @@ impl DOMImplementationMethods for DOMImplementation { let doc = XMLDocument::new(win, HasBrowsingContext::No, None, - self.document.origin().alias(), + self.document.origin().clone(), IsHTMLDocument::NonHTMLDocument, Some(DOMString::from(content_type)), None, @@ -127,7 +127,7 @@ impl DOMImplementationMethods for DOMImplementation { let doc = Document::new(win, HasBrowsingContext::No, None, - self.document.origin().alias(), + self.document.origin().clone(), IsHTMLDocument::HTMLDocument, None, None, diff --git a/components/script/dom/domparser.rs b/components/script/dom/domparser.rs index d89ec3c1595..67d16934c66 100644 --- a/components/script/dom/domparser.rs +++ b/components/script/dom/domparser.rs @@ -61,7 +61,7 @@ impl DOMParserMethods for DOMParser { let document = Document::new(&self.window, HasBrowsingContext::No, Some(url.clone()), - doc.origin().alias(), + doc.origin().clone(), IsHTMLDocument::HTMLDocument, Some(content_type), None, @@ -79,7 +79,7 @@ impl DOMParserMethods for DOMParser { let document = Document::new(&self.window, HasBrowsingContext::No, Some(url.clone()), - doc.origin().alias(), + doc.origin().clone(), IsHTMLDocument::NonHTMLDocument, Some(content_type), None, diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index b174d2ec9a8..a51463f4674 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -337,15 +337,20 @@ impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes { pub mod utils { use dom::window::Window; - use ipc_channel::ipc; - use net_traits::image_cache_thread::{ImageCacheChan, ImageResponse}; + use net_traits::image_cache_thread::{ImageResponse, UsePlaceholder, ImageOrMetadataAvailable}; + use net_traits::image_cache_thread::CanRequestImages; use servo_url::ServoUrl; pub fn request_image_from_cache(window: &Window, url: ServoUrl) -> ImageResponse { let image_cache = window.image_cache_thread(); - let (response_chan, response_port) = ipc::channel().unwrap(); - image_cache.request_image(url.into(), ImageCacheChan(response_chan), None); - let result = response_port.recv().unwrap(); - result.image_response + let response = + image_cache.find_image_or_metadata(url.into(), + UsePlaceholder::No, + CanRequestImages::No); + match response { + Ok(ImageOrMetadataAvailable::ImageAvailable(image)) => + ImageResponse::Loaded(image), + _ => ImageResponse::None, + } } } diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 3a1c9daf1c9..4ab82735384 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -167,7 +167,7 @@ impl HTMLIFrameElement { layout_threads: PREFS.get("layout.threads").as_u64().expect("count") as usize, }; - ScriptThread::process_attach_layout(new_layout_info, document.origin().alias()); + ScriptThread::process_attach_layout(new_layout_info, document.origin().clone()); } else { let load_info = IFrameLoadInfoWithData { info: load_info, diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index ec9f2e1ec80..af98b013410 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::{Au, AU_PER_PX}; +use document_loader::{LoadType, LoadBlocker}; use dom::activation::Activatable; use dom::attr::Attr; use dom::bindings::cell::DOMRefCell; @@ -16,6 +17,7 @@ use dom::bindings::error::Fallible; use dom::bindings::inheritance::Castable; use dom::bindings::js::{LayoutJS, Root}; use dom::bindings::refcounted::Trusted; +use dom::bindings::reflector::DomObject; use dom::bindings::str::DOMString; use dom::document::Document; use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers}; @@ -34,13 +36,18 @@ use euclid::point::Point2D; use html5ever_atoms::LocalName; use ipc_channel::ipc; use ipc_channel::router::ROUTER; +use net_traits::{FetchResponseListener, FetchMetadata, NetworkError, FetchResponseMsg}; use net_traits::image::base::{Image, ImageMetadata}; -use net_traits::image_cache_thread::{ImageResponder, ImageResponse}; +use net_traits::image_cache_thread::{ImageResponder, ImageResponse, PendingImageId, ImageState}; +use net_traits::image_cache_thread::{UsePlaceholder, ImageOrMetadataAvailable, CanRequestImages}; +use net_traits::image_cache_thread::ImageCacheThread; +use net_traits::request::{RequestInit, Type as RequestType}; +use network_listener::{NetworkListener, PreInvoke}; use num_traits::ToPrimitive; use script_thread::Runnable; use servo_url::ServoUrl; use std::i32; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use style::attr::{AttrValue, LengthOrPercentageOrAuto}; use task_source::TaskSource; @@ -53,10 +60,12 @@ enum State { Broken, } #[derive(JSTraceable, HeapSizeOf)] +#[must_root] struct ImageRequest { state: State, parsed_url: Option<ServoUrl>, source_url: Option<DOMString>, + blocker: Option<LoadBlocker>, #[ignore_heap_size_of = "Arc"] image: Option<Arc<Image>>, metadata: Option<ImageMetadata>, @@ -74,7 +83,6 @@ impl HTMLImageElement { } } - struct ImageResponseHandlerRunnable { element: Trusted<HTMLImageElement>, image: ImageResponse, @@ -94,75 +102,225 @@ impl Runnable for ImageResponseHandlerRunnable { fn name(&self) -> &'static str { "ImageResponseHandlerRunnable" } fn handler(self: Box<Self>) { - // Update the image field let element = self.element.root(); - let (image, metadata, trigger_image_load, trigger_image_error) = match self.image { + element.process_image_response(self.image); + } +} + +/// The context required for asynchronously loading an external image. +struct ImageContext { + /// The element that initiated the request. + elem: Trusted<HTMLImageElement>, + /// The initial URL requested. + url: ServoUrl, + /// Indicates whether the request failed, and why + status: Result<(), NetworkError>, + /// The cache ID for this request. + id: PendingImageId, +} + +impl ImageContext { + fn image_cache(&self) -> ImageCacheThread { + let elem = self.elem.root(); + window_from_node(&*elem).image_cache_thread().clone() + } +} + +impl FetchResponseListener for ImageContext { + fn process_request_body(&mut self) {} + fn process_request_eof(&mut self) {} + + fn process_response(&mut self, metadata: Result<FetchMetadata, NetworkError>) { + self.image_cache().notify_pending_response( + self.id, + FetchResponseMsg::ProcessResponse(metadata.clone())); + + let metadata = metadata.ok().map(|meta| { + match meta { + FetchMetadata::Unfiltered(m) => m, + FetchMetadata::Filtered { unsafe_, .. } => unsafe_ + } + }); + + let status_code = metadata.as_ref().and_then(|m| { + m.status.as_ref().map(|&(code, _)| code) + }).unwrap_or(0); + + self.status = match status_code { + 0 => Err(NetworkError::Internal("No http status code received".to_owned())), + 200...299 => Ok(()), // HTTP ok status codes + _ => Err(NetworkError::Internal(format!("HTTP error code {}", status_code))) + }; + } + + fn process_response_chunk(&mut self, payload: Vec<u8>) { + if self.status.is_ok() { + self.image_cache().notify_pending_response( + self.id, + FetchResponseMsg::ProcessResponseChunk(payload)); + } + } + + fn process_response_eof(&mut self, response: Result<(), NetworkError>) { + let elem = self.elem.root(); + let document = document_from_node(&*elem); + let image_cache = self.image_cache(); + image_cache.notify_pending_response(self.id, + FetchResponseMsg::ProcessResponseEOF(response)); + document.finish_load(LoadType::Image(self.url.clone())); + } +} + +impl PreInvoke for ImageContext {} + +impl HTMLImageElement { + /// Update the current image with a valid URL. + fn update_image_with_url(&self, img_url: ServoUrl, src: DOMString) { + { + let mut current_request = self.current_request.borrow_mut(); + current_request.parsed_url = Some(img_url.clone()); + current_request.source_url = Some(src); + + LoadBlocker::terminate(&mut current_request.blocker); + let document = document_from_node(self); + current_request.blocker = + Some(LoadBlocker::new(&*document, LoadType::Image(img_url.clone()))); + } + + fn add_cache_listener_for_element(image_cache: &ImageCacheThread, + id: PendingImageId, + elem: &HTMLImageElement) { + let trusted_node = Trusted::new(elem); + let (responder_sender, responder_receiver) = ipc::channel().unwrap(); + + let window = window_from_node(elem); + let task_source = window.networking_task_source(); + let wrapper = window.get_runnable_wrapper(); + ROUTER.add_route(responder_receiver.to_opaque(), box move |message| { + // Return the image via a message to the script thread, which marks the element + // as dirty and triggers a reflow. + let runnable = ImageResponseHandlerRunnable::new( + trusted_node.clone(), message.to().unwrap()); + let _ = task_source.queue_with_wrapper(box runnable, &wrapper); + }); + + image_cache.add_listener(id, ImageResponder::new(responder_sender, id)); + } + + let window = window_from_node(self); + let image_cache = window.image_cache_thread(); + let response = + image_cache.find_image_or_metadata(img_url.clone().into(), + UsePlaceholder::Yes, + CanRequestImages::Yes); + match response { + Ok(ImageOrMetadataAvailable::ImageAvailable(image)) => { + self.process_image_response(ImageResponse::Loaded(image)); + } + + Ok(ImageOrMetadataAvailable::MetadataAvailable(m)) => { + self.process_image_response(ImageResponse::MetadataLoaded(m)); + } + + Err(ImageState::Pending(id)) => { + add_cache_listener_for_element(image_cache, id, self); + } + + Err(ImageState::LoadError) => { + self.process_image_response(ImageResponse::None); + } + + Err(ImageState::NotRequested(id)) => { + add_cache_listener_for_element(image_cache, id, self); + self.request_image(img_url, id); + } + } + } + + fn request_image(&self, img_url: ServoUrl, id: PendingImageId) { + let document = document_from_node(self); + let window = window_from_node(self); + + let context = Arc::new(Mutex::new(ImageContext { + elem: Trusted::new(self), + url: img_url.clone(), + status: Ok(()), + id: id, + })); + + let (action_sender, action_receiver) = ipc::channel().unwrap(); + let listener = NetworkListener { + context: context, + task_source: window.networking_task_source(), + wrapper: Some(window.get_runnable_wrapper()), + }; + ROUTER.add_route(action_receiver.to_opaque(), box move |message| { + listener.notify_fetch(message.to().unwrap()); + }); + + let request = RequestInit { + url: img_url.clone(), + origin: document.url().clone(), + type_: RequestType::Image, + pipeline_id: Some(document.global().pipeline_id()), + .. RequestInit::default() + }; + + document.fetch_async(LoadType::Image(img_url), request, action_sender); + } + + fn process_image_response(&self, image: ImageResponse) { + let (image, metadata, trigger_image_load, trigger_image_error) = match image { ImageResponse::Loaded(image) | ImageResponse::PlaceholderLoaded(image) => { - (Some(image.clone()), Some(ImageMetadata { height: image.height, width: image.width } ), true, false) + (Some(image.clone()), + Some(ImageMetadata { height: image.height, width: image.width }), + true, + false) } ImageResponse::MetadataLoaded(meta) => { (None, Some(meta), false, false) } ImageResponse::None => (None, None, false, true) }; - element.current_request.borrow_mut().image = image; - element.current_request.borrow_mut().metadata = metadata; + self.current_request.borrow_mut().image = image; + self.current_request.borrow_mut().metadata = metadata; // Mark the node dirty - let document = document_from_node(&*element); - element.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); + self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); // Fire image.onload if trigger_image_load { - element.upcast::<EventTarget>().fire_event(atom!("load")); + self.upcast::<EventTarget>().fire_event(atom!("load")); } // Fire image.onerror if trigger_image_error { - element.upcast::<EventTarget>().fire_event(atom!("error")); + self.upcast::<EventTarget>().fire_event(atom!("error")); } + LoadBlocker::terminate(&mut self.current_request.borrow_mut().blocker); + // Trigger reflow - let window = window_from_node(&*document); + let window = window_from_node(self); window.add_pending_reflow(); } -} -impl HTMLImageElement { /// Makes the local `image` member match the status of the `src` attribute and starts /// prefetching the image. This method must be called after `src` is changed. fn update_image(&self, value: Option<(DOMString, ServoUrl)>) { let document = document_from_node(self); let window = document.window(); - let image_cache = window.image_cache_thread(); match value { None => { self.current_request.borrow_mut().parsed_url = None; self.current_request.borrow_mut().source_url = None; + LoadBlocker::terminate(&mut self.current_request.borrow_mut().blocker); self.current_request.borrow_mut().image = None; } Some((src, base_url)) => { let img_url = base_url.join(&src); if let Ok(img_url) = img_url { - self.current_request.borrow_mut().parsed_url = Some(img_url.clone()); - self.current_request.borrow_mut().source_url = Some(src); - - let trusted_node = Trusted::new(self); - let (responder_sender, responder_receiver) = ipc::channel().unwrap(); - let task_source = window.networking_task_source(); - let wrapper = window.get_runnable_wrapper(); - ROUTER.add_route(responder_receiver.to_opaque(), box move |message| { - // Return the image via a message to the script thread, which marks the element - // as dirty and triggers a reflow. - let image_response = message.to().unwrap(); - let runnable = box ImageResponseHandlerRunnable::new( - trusted_node.clone(), image_response); - let _ = task_source.queue_with_wrapper(runnable, &wrapper); - }); - - image_cache.request_image_and_metadata(img_url.into(), - window.image_cache_chan(), - Some(ImageResponder::new(responder_sender))); + self.update_image_with_url(img_url, src); } else { // https://html.spec.whatwg.org/multipage/#update-the-image-data // Step 11 (error substeps) @@ -202,6 +360,7 @@ impl HTMLImageElement { } } } + fn new_inherited(local_name: LocalName, prefix: Option<DOMString>, document: &Document) -> HTMLImageElement { HTMLImageElement { htmlelement: HTMLElement::new_inherited(local_name, prefix, document), @@ -210,14 +369,16 @@ impl HTMLImageElement { parsed_url: None, source_url: None, image: None, - metadata: None + metadata: None, + blocker: None, }), pending_request: DOMRefCell::new(ImageRequest { state: State::Unavailable, parsed_url: None, source_url: None, image: None, - metadata: None + metadata: None, + blocker: None, }), } } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index df335be75a6..96d3fceaff5 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -1729,7 +1729,7 @@ impl Node { let document = Document::new(window, HasBrowsingContext::No, Some(document.url()), // https://github.com/whatwg/dom/issues/378 - document.origin().alias(), + document.origin().clone(), is_html_doc, None, None, DocumentActivity::Inactive, DocumentSource::NotFromParser, loader, diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index 39077930200..149957576a2 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -110,7 +110,7 @@ impl ServoParser { let document = Document::new(window, HasBrowsingContext::No, Some(url.clone()), - context_document.origin().alias(), + context_document.origin().clone(), IsHTMLDocument::HTMLDocument, None, None, diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 1fbe57ba165..93cdd1c31d0 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -42,7 +42,7 @@ use dom::location::Location; use dom::mediaquerylist::{MediaQueryList, WeakMediaQueryListVec}; use dom::messageevent::MessageEvent; use dom::navigator::Navigator; -use dom::node::{Node, from_untrusted_node_address, window_from_node}; +use dom::node::{Node, from_untrusted_node_address, window_from_node, NodeDamage}; use dom::performance::Performance; use dom::promise::Promise; use dom::screen::Screen; @@ -52,21 +52,23 @@ use euclid::{Point2D, Rect, Size2D}; use fetch; use gfx_traits::ScrollRootId; use ipc_channel::ipc::{self, IpcSender}; +use ipc_channel::router::ROUTER; use js::jsapi::{HandleObject, HandleValue, JSAutoCompartment, JSContext}; use js::jsapi::{JS_GC, JS_GetRuntime}; use js::jsval::UndefinedValue; use js::rust::Runtime; +use layout_image::fetch_image_for_layout; use msg::constellation_msg::{FrameType, PipelineId}; use net_traits::{ResourceThreads, ReferrerPolicy}; -use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread}; +use net_traits::image_cache_thread::{ImageResponder, ImageResponse}; +use net_traits::image_cache_thread::{PendingImageResponse, ImageCacheThread, PendingImageId}; use net_traits::storage_thread::StorageType; use num_traits::ToPrimitive; use open; -use origin::Origin; use profile_traits::mem::ProfilerChan as MemProfilerChan; use profile_traits::time::ProfilerChan as TimeProfilerChan; use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64}; -use script_layout_interface::TrustedNodeAddress; +use script_layout_interface::{TrustedNodeAddress, PendingImageState}; use script_layout_interface::message::{Msg, Reflow, ReflowQueryType, ScriptReflow}; use script_layout_interface::reporter::CSSErrorReporter; use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC}; @@ -74,7 +76,7 @@ use script_layout_interface::rpc::{MarginStyleResponse, NodeScrollRootIdResponse use script_layout_interface::rpc::{ResolvedStyleResponse, TextIndexResponse}; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThreadEventCategory}; use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable, RunnableWrapper}; -use script_thread::SendableMainThreadScriptChan; +use script_thread::{SendableMainThreadScriptChan, ImageCacheMsg}; use script_traits::{ConstellationControlMsg, LoadData, MozBrowserEvent, UntrustedNodeAddress}; use script_traits::{DocumentState, TimerEvent, TimerEventId}; use script_traits::{ScriptMsg as ConstellationMsg, TimerEventRequest, WindowSizeData, WindowSizeType}; @@ -83,11 +85,12 @@ use servo_atoms::Atom; use servo_config::opts; use servo_config::prefs::PREFS; use servo_geometry::{f32_rect_to_au_rect, max_rect}; -use servo_url::ServoUrl; +use servo_url::{ImmutableOrigin, ServoUrl}; use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::cell::Cell; use std::collections::{HashMap, HashSet}; +use std::collections::hash_map::Entry; use std::default::Default; use std::io::{Write, stderr, stdout}; use std::mem; @@ -166,7 +169,7 @@ pub struct Window { #[ignore_heap_size_of = "channels are hard"] image_cache_thread: ImageCacheThread, #[ignore_heap_size_of = "channels are hard"] - image_cache_chan: ImageCacheChan, + image_cache_chan: Sender<ImageCacheMsg>, browsing_context: MutNullableJS<BrowsingContext>, document: MutNullableJS<Document>, history: MutNullableJS<History>, @@ -254,7 +257,13 @@ pub struct Window { webvr_thread: Option<IpcSender<WebVRMsg>>, /// A map for storing the previous permission state read results. - permission_state_invocation_results: DOMRefCell<HashMap<String, PermissionState>> + permission_state_invocation_results: DOMRefCell<HashMap<String, PermissionState>>, + + /// All of the elements that have an outstanding image request that was + /// initiated by layout during a reflow. They are stored in the script thread + /// to ensure that the element can be marked dirty when the image data becomes + /// available at some point in the future. + pending_layout_images: DOMRefCell<HashMap<PendingImageId, Vec<JS<Node>>>>, } impl Window { @@ -296,10 +305,6 @@ impl Window { &self.script_chan.0 } - pub fn image_cache_chan(&self) -> ImageCacheChan { - self.image_cache_chan.clone() - } - pub fn parent_info(&self) -> Option<(PipelineId, FrameType)> { self.parent_info } @@ -347,6 +352,28 @@ impl Window { pub fn permission_state_invocation_results(&self) -> &DOMRefCell<HashMap<String, PermissionState>> { &self.permission_state_invocation_results } + + pub fn pending_image_notification(&self, response: PendingImageResponse) { + //XXXjdm could be more efficient to send the responses to the layout thread, + // rather than making the layout thread talk to the image cache to + // obtain the same data. + let mut images = self.pending_layout_images.borrow_mut(); + let nodes = images.entry(response.id); + let nodes = match nodes { + Entry::Occupied(nodes) => nodes, + Entry::Vacant(_) => return, + }; + for node in nodes.get() { + node.dirty(NodeDamage::OtherNodeDamage); + } + match response.response { + ImageResponse::MetadataLoaded(_) => {} + ImageResponse::Loaded(_) | + ImageResponse::PlaceholderLoaded(_) | + ImageResponse::None => { nodes.remove(); } + } + self.add_pending_reflow(); + } } #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] @@ -660,10 +687,10 @@ impl WindowMethods for Window { "/" => { // TODO(#12715): Should be the origin of the incumbent settings // object, not self's. - Some(self.Document().origin().copy()) + Some(self.Document().origin().immutable().clone()) }, url => match ServoUrl::parse(&url) { - Ok(url) => Some(Origin::new(&url)), + Ok(url) => Some(url.origin().clone()), Err(_) => return Err(Error::Syntax), } }; @@ -1169,6 +1196,31 @@ impl Window { self.emit_timeline_marker(marker.end()); } + let pending_images = self.layout_rpc.pending_images(); + for image in pending_images { + let id = image.id; + let js_runtime = self.js_runtime.borrow(); + let js_runtime = js_runtime.as_ref().unwrap(); + let node = from_untrusted_node_address(js_runtime.rt(), image.node); + + if let PendingImageState::Unrequested(ref url) = image.state { + fetch_image_for_layout(url.clone(), &*node, id, self.image_cache_thread.clone()); + } + + let mut images = self.pending_layout_images.borrow_mut(); + let nodes = images.entry(id).or_insert(vec![]); + if nodes.iter().find(|n| &***n as *const _ == &*node as *const _).is_none() { + let (responder, responder_listener) = ipc::channel().unwrap(); + let pipeline = self.upcast::<GlobalScope>().pipeline_id(); + let image_cache_chan = self.image_cache_chan.clone(); + ROUTER.add_route(responder_listener.to_opaque(), box move |message| { + let _ = image_cache_chan.send((pipeline, message.to().unwrap())); + }); + self.image_cache_thread.add_listener(id, ImageResponder::new(responder, id)); + nodes.push(JS::from_ref(&*node)); + } + } + true } @@ -1228,7 +1280,8 @@ impl Window { let ready_state = document.ReadyState(); - if ready_state == DocumentReadyState::Complete && !reftest_wait { + let pending_images = self.pending_layout_images.borrow().is_empty(); + if ready_state == DocumentReadyState::Complete && !reftest_wait && pending_images { let global_scope = self.upcast::<GlobalScope>(); let event = ConstellationMsg::SetDocumentState(global_scope.pipeline_id(), DocumentState::Idle); global_scope.constellation_chan().send(event).unwrap(); @@ -1636,7 +1689,7 @@ impl Window { network_task_source: NetworkingTaskSource, history_task_source: HistoryTraversalTaskSource, file_task_source: FileReadingTaskSource, - image_cache_chan: ImageCacheChan, + image_cache_chan: Sender<ImageCacheMsg>, image_cache_thread: ImageCacheThread, resource_threads: ResourceThreads, bluetooth_thread: IpcSender<BluetoothRequest>, @@ -1718,6 +1771,7 @@ impl Window { test_runner: Default::default(), webvr_thread: webvr_thread, permission_state_invocation_results: DOMRefCell::new(HashMap::new()), + pending_layout_images: DOMRefCell::new(HashMap::new()), }; unsafe { @@ -1793,13 +1847,13 @@ fn debug_reflow_events(id: PipelineId, goal: &ReflowGoal, query_type: &ReflowQue struct PostMessageHandler { destination: Trusted<Window>, - origin: Option<Origin>, + origin: Option<ImmutableOrigin>, message: StructuredCloneData, } impl PostMessageHandler { fn new(window: &Window, - origin: Option<Origin>, + origin: Option<ImmutableOrigin>, message: StructuredCloneData) -> PostMessageHandler { PostMessageHandler { destination: Trusted::new(window), diff --git a/components/script/dom/xmldocument.rs b/components/script/dom/xmldocument.rs index eaf90fbfe01..c832e018360 100644 --- a/components/script/dom/xmldocument.rs +++ b/components/script/dom/xmldocument.rs @@ -15,9 +15,8 @@ use dom::location::Location; use dom::node::Node; use dom::window::Window; use js::jsapi::{JSContext, JSObject}; -use origin::Origin; use script_traits::DocumentActivity; -use servo_url::ServoUrl; +use servo_url::{MutableOrigin, ServoUrl}; // https://dom.spec.whatwg.org/#xmldocument #[dom_struct] @@ -29,7 +28,7 @@ impl XMLDocument { fn new_inherited(window: &Window, has_browsing_context: HasBrowsingContext, url: Option<ServoUrl>, - origin: Origin, + origin: MutableOrigin, is_html_document: IsHTMLDocument, content_type: Option<DOMString>, last_modified: Option<String>, @@ -55,7 +54,7 @@ impl XMLDocument { pub fn new(window: &Window, has_browsing_context: HasBrowsingContext, url: Option<ServoUrl>, - origin: Origin, + origin: MutableOrigin, doctype: IsHTMLDocument, content_type: Option<DOMString>, last_modified: Option<String>, diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 6fe89476994..c5c3c635129 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -1225,7 +1225,7 @@ impl XMLHttpRequest { Document::new(win, HasBrowsingContext::No, parsed_url, - doc.origin().alias(), + doc.origin().clone(), is_html_document, content_type, None, |