aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/bindings/trace.rs10
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs4
-rw-r--r--components/script/dom/document.rs33
-rw-r--r--components/script/dom/domimplementation.rs4
-rw-r--r--components/script/dom/domparser.rs4
-rw-r--r--components/script/dom/htmlcanvaselement.rs17
-rw-r--r--components/script/dom/htmliframeelement.rs2
-rw-r--r--components/script/dom/htmlimageelement.rs235
-rw-r--r--components/script/dom/node.rs2
-rw-r--r--components/script/dom/servoparser/mod.rs2
-rw-r--r--components/script/dom/window.rs90
-rw-r--r--components/script/dom/xmldocument.rs7
-rw-r--r--components/script/dom/xmlhttprequest.rs2
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,