From c890c9143cc1ae82e1116b8fb0c4e9eb478b8a03 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Mon, 21 Nov 2016 18:13:40 -0500 Subject: [PATCH 01/10] Make script thread initiate requests for images needed by layout. In support of this goal, the layout thread collects information about CSS images that are missing image data and hands it off to the script thread after layout completes. The script thread stores a list of nodes that will need to be reflowed after the associated network request is complete. The script thread ensures that the nodes are not GCed while a request is ongoing, which the layout thread is incapable of guaranteeing. The image cache's API has also been redesigned in support of this work. No network requests are made by the new image cache, since it does not possess the document-specific information necessary to initiate them. Instead, there is now a single, synchronous query operation that optionally reserves a slot when a cache entry for a URL cannot be found. This reserved slot is then the responsibility of the queryer to populate with the contents of the network response for the URL once it is complete. Any subsequent queries for the same URL will be informed that the response is pending until that occurs. The changes to layout also remove the synchronous image loading code path, which means that reftests now test the same code that non-test binaries execute. The decision to take a screenshot now considers whether there are any outstanding image requests for layout in order to avoid intermittent failures in reftests that use CSS images. --- components/layout/construct.rs | 3 + components/layout/context.rs | 99 ++++---- components/layout/display_list_builder.rs | 3 +- components/layout/fragment.rs | 9 +- components/layout/query.rs | 11 + components/layout_thread/lib.rs | 70 ++---- components/net/image_cache_thread.rs | 214 +++++------------- components/net_traits/image_cache_thread.rs | 103 ++++----- components/script/dom/bindings/trace.rs | 4 +- .../script/dom/canvasrenderingcontext2d.rs | 4 +- components/script/dom/htmlcanvaselement.rs | 11 +- components/script/dom/htmlimageelement.rs | 188 ++++++++++++++- components/script/dom/window.rs | 145 ++++++++++-- components/script/script_thread.rs | 26 ++- components/script_layout_interface/lib.rs | 18 ++ components/script_layout_interface/rpc.rs | 4 +- .../script_plugins/unrooted_must_root.rs | 1 + components/servo/lib.rs | 3 +- 18 files changed, 528 insertions(+), 388 deletions(-) diff --git a/components/layout/construct.rs b/components/layout/construct.rs index bbfe17d22b7..afdf903c500 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -351,11 +351,13 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> } Some(LayoutNodeType::Element(LayoutElementType::HTMLImageElement)) => { let image_info = box ImageFragmentInfo::new(node.image_url(), + node, &self.layout_context); SpecificFragmentInfo::Image(image_info) } Some(LayoutNodeType::Element(LayoutElementType::HTMLObjectElement)) => { let image_info = box ImageFragmentInfo::new(node.object_data(), + node, &self.layout_context); SpecificFragmentInfo::Image(image_info) } @@ -1219,6 +1221,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let marker_fragments = match node.style(self.style_context()).get_list().list_style_image { Either::First(ref url_value) => { let image_info = box ImageFragmentInfo::new(url_value.url().map(|u| u.clone()), + node, &self.layout_context); vec![Fragment::new(node, SpecificFragmentInfo::Image(image_info), self.layout_context)] } diff --git a/components/layout/context.rs b/components/layout/context.rs index e67e7da6fb1..13029dd80bf 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -5,22 +5,22 @@ //! Data needed by the layout thread. use fnv::FnvHasher; -use gfx::display_list::WebRenderImageInfo; +use gfx::display_list::{WebRenderImageInfo, OpaqueNode}; use gfx::font_cache_thread::FontCacheThread; use gfx::font_context::FontContext; use heapsize::HeapSizeOf; -use ipc_channel::ipc; -use net_traits::image::base::Image; -use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread, ImageResponse, ImageState}; +use net_traits::image_cache_thread::{ImageCacheThread, ImageState}; use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder}; +use opaque_node::OpaqueNodeMethods; use parking_lot::RwLock; -use servo_config::opts; +use script_layout_interface::{PendingImage, PendingImageState}; use servo_url::ServoUrl; use std::borrow::{Borrow, BorrowMut}; use std::cell::{RefCell, RefMut}; use std::collections::HashMap; use std::hash::BuildHasherDefault; use std::sync::{Arc, Mutex}; +use std::thread; use style::context::{SharedStyleContext, ThreadLocalStyleContext}; use style::dom::TElement; @@ -82,9 +82,6 @@ pub struct LayoutContext { /// The shared image cache thread. pub image_cache_thread: Mutex, - /// A channel for the image cache to send responses to. - pub image_cache_sender: Mutex, - /// Interface to the font cache thread. pub font_cache_thread: Mutex, @@ -92,6 +89,18 @@ pub struct LayoutContext { pub webrender_image_cache: Arc>>>, + + /// A list of in-progress image loads to be shared with the script thread. + /// A None value means that this layout was not initiated by the script thread. + pub pending_images: Mutex> +} + +impl Drop for LayoutContext { + fn drop(&mut self) { + if !thread::panicking() { + assert!(self.pending_images.lock().unwrap().is_empty()); + } + } } impl LayoutContext { @@ -100,49 +109,11 @@ impl LayoutContext { &self.style_context } - fn get_or_request_image_synchronously(&self, url: ServoUrl, use_placeholder: UsePlaceholder) - -> Option> { - debug_assert!(opts::get().output_file.is_some() || opts::get().exit_after_load); - - // See if the image is already available - let result = self.image_cache_thread.lock().unwrap() - .find_image(url.clone(), use_placeholder); - - match result { - Ok(image) => return Some(image), - Err(ImageState::LoadError) => { - // Image failed to load, so just return nothing - return None - } - Err(_) => {} - } - - // If we are emitting an output file, then we need to block on - // image load or we risk emitting an output file missing the image. - let (sync_tx, sync_rx) = ipc::channel().unwrap(); - self.image_cache_thread.lock().unwrap().request_image(url, ImageCacheChan(sync_tx), None); - loop { - match sync_rx.recv() { - Err(_) => return None, - Ok(response) => { - match response.image_response { - ImageResponse::Loaded(image) | ImageResponse::PlaceholderLoaded(image) => { - return Some(image) - } - ImageResponse::None | ImageResponse::MetadataLoaded(_) => {} - } - } - } - } - } - - pub fn get_or_request_image_or_meta(&self, url: ServoUrl, use_placeholder: UsePlaceholder) - -> Option { - // If we are emitting an output file, load the image synchronously. - if opts::get().output_file.is_some() || opts::get().exit_after_load { - return self.get_or_request_image_synchronously(url, use_placeholder) - .map(|img| ImageOrMetadataAvailable::ImageAvailable(img)); - } + pub fn get_or_request_image_or_meta(&self, + node: OpaqueNode, + url: ServoUrl, + use_placeholder: UsePlaceholder) + -> Option { // See if the image is already available let result = self.image_cache_thread.lock().unwrap() .find_image_or_metadata(url.clone(), @@ -151,20 +122,32 @@ impl LayoutContext { Ok(image_or_metadata) => Some(image_or_metadata), // Image failed to load, so just return nothing Err(ImageState::LoadError) => None, - // Not yet requested, async mode - request image or metadata from the cache - Err(ImageState::NotRequested) => { - let sender = self.image_cache_sender.lock().unwrap().clone(); - self.image_cache_thread.lock().unwrap() - .request_image_and_metadata(url, sender, None); + // Not yet requested - request image or metadata from the cache + Err(ImageState::NotRequested(id)) => { + let image = PendingImage { + state: PendingImageState::Unrequested(url), + node: node.to_untrusted_node_address(), + id: id, + }; + self.pending_images.lock().unwrap().push(image); None } // Image has been requested, is still pending. Return no image for this paint loop. // When the image loads it will trigger a reflow and/or repaint. - Err(ImageState::Pending) => None, + Err(ImageState::Pending(id)) => { + let image = PendingImage { + state: PendingImageState::PendingResponse, + node: node.to_untrusted_node_address(), + id: id, + }; + self.pending_images.lock().unwrap().push(image); + None + } } } pub fn get_webrender_image_for_url(&self, + node: OpaqueNode, url: ServoUrl, use_placeholder: UsePlaceholder) -> Option { @@ -174,7 +157,7 @@ impl LayoutContext { return Some((*existing_webrender_image).clone()) } - match self.get_or_request_image_or_meta(url.clone(), use_placeholder) { + match self.get_or_request_image_or_meta(node, url.clone(), use_placeholder) { Some(ImageOrMetadataAvailable::ImageAvailable(image)) => { let image_info = WebRenderImageInfo::from_image(&*image); if image_info.key.is_none() { diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 848188d14a0..5eb4534a0c5 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -683,7 +683,8 @@ impl FragmentDisplayListBuilding for Fragment { index: usize) { let background = style.get_background(); let webrender_image = state.layout_context - .get_webrender_image_for_url(image_url.clone(), + .get_webrender_image_for_url(self.node, + image_url.clone(), UsePlaceholder::No); if let Some(webrender_image) = webrender_image { diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index ec1e87e6dd2..9cc0efbce6e 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -367,11 +367,14 @@ impl ImageFragmentInfo { /// /// FIXME(pcwalton): The fact that image fragments store the cache in the fragment makes little /// sense to me. - pub fn new(url: Option, - layout_context: &LayoutContext) + pub fn new(url: Option, + node: &N, + layout_context: &LayoutContext) -> ImageFragmentInfo { let image_or_metadata = url.and_then(|url| { - layout_context.get_or_request_image_or_meta(url, UsePlaceholder::Yes) + layout_context.get_or_request_image_or_meta(node.opaque(), + url, + UsePlaceholder::Yes) }); let (image, metadata) = match image_or_metadata { diff --git a/components/layout/query.rs b/components/layout/query.rs index 5c78a1bc75d..2f26fede59f 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -17,6 +17,7 @@ use gfx_traits::ScrollRootId; use inline::LAST_FRAGMENT_OF_ELEMENT; use ipc_channel::ipc::IpcSender; use opaque_node::OpaqueNodeMethods; +use script_layout_interface::PendingImage; use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse}; use script_layout_interface::rpc::{HitTestResponse, LayoutRPC}; use script_layout_interface::rpc::{MarginStyleResponse, NodeGeometryResponse}; @@ -27,6 +28,7 @@ use script_traits::LayoutMsg as ConstellationMsg; use script_traits::UntrustedNodeAddress; use sequential; use std::cmp::{min, max}; +use std::mem; use std::ops::Deref; use std::sync::{Arc, Mutex}; use style::computed_values; @@ -89,6 +91,9 @@ pub struct LayoutThreadData { /// Index in a text fragment. We need this do determine the insertion point. pub text_index_response: TextIndexResponse, + + /// A list of images requests that need to be initiated. + pub pending_images: Vec, } pub struct LayoutRPCImpl(pub Arc>); @@ -216,6 +221,12 @@ impl LayoutRPC for LayoutRPCImpl { let rw_data = rw_data.lock().unwrap(); rw_data.text_index_response.clone() } + + fn pending_images(&self) -> Vec { + let &LayoutRPCImpl(ref rw_data) = self; + let mut rw_data = rw_data.lock().unwrap(); + mem::replace(&mut rw_data.pending_images, vec![]) + } } struct UnioningFragmentBorderBoxIterator { diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 8626385a026..af56555e399 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -75,7 +75,7 @@ use layout::wrapper::LayoutNodeLayoutData; use layout::wrapper::drop_style_and_layout_data; use layout_traits::LayoutThreadFactory; use msg::constellation_msg::{FrameId, PipelineId}; -use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread}; +use net_traits::image_cache_thread::ImageCacheThread; use net_traits::image_cache_thread::UsePlaceholder; use parking_lot::RwLock; use profile_traits::mem::{self, Report, ReportKind, ReportsChan}; @@ -98,6 +98,7 @@ use servo_url::ServoUrl; use std::borrow::ToOwned; use std::collections::HashMap; use std::hash::BuildHasherDefault; +use std::mem as std_mem; use std::ops::{Deref, DerefMut}; use std::process; use std::sync::{Arc, Mutex, MutexGuard}; @@ -137,12 +138,6 @@ pub struct LayoutThread { /// The port on which we receive messages from the constellation. pipeline_port: Receiver, - /// The port on which we receive messages from the image cache - image_cache_receiver: Receiver, - - /// The channel on which the image cache can send messages to ourself. - image_cache_sender: ImageCacheChan, - /// The port on which we receive messages from the font cache thread. font_cache_receiver: Receiver<()>, @@ -404,11 +399,6 @@ impl LayoutThread { // Proxy IPC messages from the pipeline to the layout thread. let pipeline_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(pipeline_port); - // Ask the router to proxy IPC messages from the image cache thread to the layout thread. - let (ipc_image_cache_sender, ipc_image_cache_receiver) = ipc::channel().unwrap(); - let image_cache_receiver = - ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_image_cache_receiver); - // Ask the router to proxy IPC messages from the font cache thread to the layout thread. let (ipc_font_cache_sender, ipc_font_cache_receiver) = ipc::channel().unwrap(); let font_cache_receiver = @@ -437,8 +427,6 @@ impl LayoutThread { image_cache_thread: image_cache_thread, font_cache_thread: font_cache_thread, first_reflow: true, - image_cache_receiver: image_cache_receiver, - image_cache_sender: ImageCacheChan(ipc_image_cache_sender), font_cache_receiver: font_cache_receiver, font_cache_sender: ipc_font_cache_sender, parallel_traversal: parallel_traversal, @@ -470,6 +458,7 @@ impl LayoutThread { margin_style_response: MarginStyleResponse::empty(), stacking_context_scroll_offsets: HashMap::new(), text_index_response: TextIndexResponse(None), + pending_images: vec![], })), error_reporter: CSSErrorReporter { pipelineid: id, @@ -530,9 +519,9 @@ impl LayoutThread { default_computed_values: Arc::new(ComputedValues::initial_values().clone()), }, image_cache_thread: Mutex::new(self.image_cache_thread.clone()), - image_cache_sender: Mutex::new(self.image_cache_sender.clone()), font_cache_thread: Mutex::new(self.font_cache_thread.clone()), webrender_image_cache: self.webrender_image_cache.clone(), + pending_images: Mutex::new(vec![]), } } @@ -541,14 +530,12 @@ impl LayoutThread { enum Request { FromPipeline(LayoutControlMsg), FromScript(Msg), - FromImageCache, FromFontCache, } let request = { let port_from_script = &self.port; let port_from_pipeline = &self.pipeline_port; - let port_from_image_cache = &self.image_cache_receiver; let port_from_font_cache = &self.font_cache_receiver; select! { msg = port_from_pipeline.recv() => { @@ -557,10 +544,6 @@ impl LayoutThread { msg = port_from_script.recv() => { Request::FromScript(msg.unwrap()) }, - msg = port_from_image_cache.recv() => { - msg.unwrap(); - Request::FromImageCache - }, msg = port_from_font_cache.recv() => { msg.unwrap(); Request::FromFontCache @@ -590,9 +573,6 @@ impl LayoutThread { Request::FromScript(msg) => { self.handle_request_helper(msg, possibly_locked_rw_data) }, - Request::FromImageCache => { - self.repaint(possibly_locked_rw_data) - }, Request::FromFontCache => { let _rw_data = possibly_locked_rw_data.lock(); self.outstanding_web_fonts.fetch_sub(1, Ordering::SeqCst); @@ -603,37 +583,6 @@ impl LayoutThread { } } - /// Repaint the scene, without performing style matching. This is typically - /// used when an image arrives asynchronously and triggers a relayout and - /// repaint. - /// TODO: In the future we could detect if the image size hasn't changed - /// since last time and avoid performing a complete layout pass. - fn repaint<'a, 'b>(&mut self, possibly_locked_rw_data: &mut RwData<'a, 'b>) -> bool { - let mut rw_data = possibly_locked_rw_data.lock(); - - if let Some(mut root_flow) = self.root_flow.clone() { - let flow = flow::mut_base(FlowRef::deref_mut(&mut root_flow)); - flow.restyle_damage.insert(REPAINT); - } - - let reflow_info = Reflow { - goal: ReflowGoal::ForDisplay, - page_clip_rect: max_rect(), - }; - let mut layout_context = self.build_layout_context(&*rw_data, - false, - reflow_info.goal); - - self.perform_post_style_recalc_layout_passes(&reflow_info, - None, - None, - &mut *rw_data, - &mut layout_context); - - - true - } - /// Receives and dispatches messages from other threads. fn handle_request_helper<'a, 'b>(&mut self, request: Msg, @@ -1247,6 +1196,9 @@ impl LayoutThread { query_type: &ReflowQueryType, rw_data: &mut LayoutThreadData, context: &mut LayoutContext) { + rw_data.pending_images = + std_mem::replace(&mut context.pending_images.lock().unwrap(), vec![]); + let mut root_flow = match self.root_flow.clone() { Some(root_flow) => root_flow, None => return, @@ -1387,6 +1339,14 @@ impl LayoutThread { None, &mut *rw_data, &mut layout_context); + + let mut pending_images = layout_context.pending_images.lock().unwrap(); + if pending_images.len() > 0 { + //XXXjdm we drop all the images on the floor, but there's no guarantee that + // the node references are valid since the script thread isn't paused. + // need to figure out what to do here! + pending_images.truncate(0); + } } fn reflow_with_newly_loaded_web_font<'a, 'b>(&mut self, possibly_locked_rw_data: &mut RwData<'a, 'b>) { diff --git a/components/net/image_cache_thread.rs b/components/net/image_cache_thread.rs index 51d8324bd48..17a852833c2 100644 --- a/components/net/image_cache_thread.rs +++ b/components/net/image_cache_thread.rs @@ -5,12 +5,11 @@ use immeta::load_from_buf; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; -use net_traits::{CoreResourceThread, NetworkError, fetch_async, FetchResponseMsg}; +use net_traits::{NetworkError, FetchResponseMsg}; use net_traits::image::base::{Image, ImageMetadata, PixelFormat, load_from_memory}; -use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheCommand, ImageCacheThread, ImageState}; -use net_traits::image_cache_thread::{ImageCacheResult, ImageOrMetadataAvailable, ImageResponse, UsePlaceholder}; -use net_traits::image_cache_thread::ImageResponder; -use net_traits::request::{Destination, RequestInit, Type as RequestType}; +use net_traits::image_cache_thread::{ImageCacheCommand, ImageCacheThread, ImageState}; +use net_traits::image_cache_thread::{ImageOrMetadataAvailable, ImageResponse, UsePlaceholder}; +use net_traits::image_cache_thread::{ImageResponder, PendingImageId}; use servo_config::resource_files::resources_dir_path; use servo_url::ServoUrl; use std::borrow::ToOwned; @@ -65,7 +64,7 @@ struct PendingLoad { // Once loading is complete, the result of the operation. result: Option>, - listeners: Vec, + listeners: Vec, // The url being loaded. Do not forget that this may be several Mb // if we are loading a data: url. @@ -89,7 +88,7 @@ impl PendingLoad { } } - fn add_listener(&mut self, listener: ImageListener) { + fn add_listener(&mut self, listener: ImageResponder) { self.listeners.push(listener); } } @@ -131,20 +130,11 @@ impl AllPendingLoads { self.loads.is_empty() } - // get a PendingLoad from its LoadKey. Prefer this to `get_by_url`, - // for performance reasons. + // get a PendingLoad from its LoadKey. fn get_by_key_mut(&mut self, key: &LoadKey) -> Option<&mut PendingLoad> { self.loads.get_mut(key) } - // get a PendingLoad from its url. When possible, prefer `get_by_key_mut`. - fn get_by_url(&self, url: &ServoUrl) -> Option<&PendingLoad> { - self.url_to_load_key.get(url). - and_then(|load_key| - self.loads.get(load_key) - ) - } - fn remove(&mut self, key: &LoadKey) -> Option { self.loads.remove(key). and_then(|pending_load| { @@ -182,27 +172,20 @@ impl AllPendingLoads { /// fetched again. struct CompletedLoad { image_response: ImageResponse, + id: PendingImageId, } impl CompletedLoad { - fn new(image_response: ImageResponse) -> CompletedLoad { + fn new(image_response: ImageResponse, id: PendingImageId) -> CompletedLoad { CompletedLoad { image_response: image_response, + id: id, } } } -/// Stores information to notify a client when the state -/// of an image changes. -struct ImageListener { - sender: ImageCacheChan, - responder: Option, - send_metadata_msg: bool, -} - // A key used to communicate during loading. -#[derive(Eq, Hash, PartialEq, Clone, Copy)] -struct LoadKey(u64); +type LoadKey = PendingImageId; struct LoadKeyGenerator { counter: u64 @@ -214,34 +197,9 @@ impl LoadKeyGenerator { counter: 0 } } - fn next(&mut self) -> LoadKey { + fn next(&mut self) -> PendingImageId { self.counter += 1; - LoadKey(self.counter) - } -} - -impl ImageListener { - fn new(sender: ImageCacheChan, responder: Option, send_metadata_msg: bool) -> ImageListener { - ImageListener { - sender: sender, - responder: responder, - send_metadata_msg: send_metadata_msg, - } - } - - fn notify(&self, image_response: ImageResponse) { - if !self.send_metadata_msg { - if let ImageResponse::MetadataLoaded(_) = image_response { - return; - } - } - - let ImageCacheChan(ref sender) = self.sender; - let msg = ImageCacheResult { - responder: self.responder.clone(), - image_response: image_response, - }; - sender.send(msg).ok(); + PendingImageId(self.counter) } } @@ -259,9 +217,6 @@ struct ImageCache { // Worker threads for decoding images. thread_pool: ThreadPool, - // Resource thread handle - core_resource_thread: CoreResourceThread, - // Images that are loading over network, or decoding. pending_loads: AllPendingLoads, @@ -347,8 +302,7 @@ fn get_placeholder_image(webrender_api: &webrender_traits::RenderApi) -> io::Res } impl ImageCache { - fn run(core_resource_thread: CoreResourceThread, - webrender_api: webrender_traits::RenderApi, + fn run(webrender_api: webrender_traits::RenderApi, ipc_command_receiver: IpcReceiver) { // Preload the placeholder image, used when images fail to load. let placeholder_image = get_placeholder_image(&webrender_api).ok(); @@ -364,7 +318,6 @@ impl ImageCache { thread_pool: ThreadPool::new(4), pending_loads: AllPendingLoads::new(), completed_loads: HashMap::new(), - core_resource_thread: core_resource_thread, placeholder_image: placeholder_image, webrender_api: webrender_api, }; @@ -406,22 +359,15 @@ impl ImageCache { ImageCacheCommand::Exit(sender) => { return Some(sender); } - ImageCacheCommand::RequestImage(url, result_chan, responder) => { - self.request_image(url, result_chan, responder, false); - } - ImageCacheCommand::RequestImageAndMetadata(url, result_chan, responder) => { - self.request_image(url, result_chan, responder, true); - } - ImageCacheCommand::GetImageIfAvailable(url, use_placeholder, consumer) => { - let result = self.get_image_if_available(url, use_placeholder); - let _ = consumer.send(result); + ImageCacheCommand::AddListener(id, responder) => { + self.add_listener(id, responder); } ImageCacheCommand::GetImageOrMetadataIfAvailable(url, use_placeholder, consumer) => { let result = self.get_image_or_meta_if_available(url, use_placeholder); let _ = consumer.send(result); } - ImageCacheCommand::StoreDecodeImage(url, image_vector) => { - self.store_decode_image(url, image_vector); + ImageCacheCommand::StoreDecodeImage(id, image_vector) => { + self.store_decode_image(id, image_vector); } }; @@ -445,7 +391,7 @@ impl ImageCache { height: dimensions.height }; pending_load.metadata = Some(img_metadata.clone()); for listener in &pending_load.listeners { - listener.notify(ImageResponse::MetadataLoaded(img_metadata.clone()).clone()); + listener.respond(ImageResponse::MetadataLoaded(img_metadata.clone())); } } } @@ -518,85 +464,35 @@ impl ImageCache { LoadResult::None => ImageResponse::None, }; - let completed_load = CompletedLoad::new(image_response.clone()); + let completed_load = CompletedLoad::new(image_response.clone(), key); self.completed_loads.insert(pending_load.url.into(), completed_load); for listener in pending_load.listeners { - listener.notify(image_response.clone()); + listener.respond(image_response.clone()); } } - // Request an image from the cache. If the image hasn't been - // loaded/decoded yet, it will be loaded/decoded in the - // background. If send_metadata_msg is set, the channel will be notified - // that image metadata is available, possibly before the image has finished - // loading. - fn request_image(&mut self, - url: ServoUrl, - result_chan: ImageCacheChan, - responder: Option, - send_metadata_msg: bool) { - let image_listener = ImageListener::new(result_chan, responder, send_metadata_msg); - - // Check if already completed - match self.completed_loads.get(&url) { - Some(completed_load) => { - // It's already completed, return a notify straight away - image_listener.notify(completed_load.image_response.clone()); - } - None => { - // Check if the load is already pending - let (cache_result, load_key, mut pending_load) = self.pending_loads.get_cached(url.clone()); - pending_load.add_listener(image_listener); - match cache_result { - CacheResult::Miss => { - // A new load request! Request the load from - // the resource thread. - // https://html.spec.whatwg.org/multipage/#update-the-image-data - // step 12. - // - // TODO(emilio): ServoUrl in more places please! - let request = RequestInit { - url: url.clone(), - type_: RequestType::Image, - destination: Destination::Image, - origin: url.clone(), - .. RequestInit::default() - }; - - let progress_sender = self.progress_sender.clone(); - fetch_async(request, &self.core_resource_thread, move |action| { - let action = match action { - FetchResponseMsg::ProcessRequestBody | - FetchResponseMsg::ProcessRequestEOF => return, - a => a - }; - progress_sender.send(ResourceLoadInfo { - action: action, - key: load_key, - }).unwrap(); - }); - } - CacheResult::Hit => { - // Request is already on its way. - } - } + /// Add a listener for a given image if it is still pending, or notify the + /// listener if the image is complete. + fn add_listener(&mut self, + id: PendingImageId, + listener: ImageResponder) { + if let Some(load) = self.pending_loads.get_by_key_mut(&id) { + if let Some(ref metadata) = load.metadata { + listener.respond(ImageResponse::MetadataLoaded(metadata.clone())); } + load.add_listener(listener); + return; } + if let Some(load) = self.completed_loads.values().find(|l| l.id == id) { + listener.respond(load.image_response.clone()); + return; + } + warn!("Couldn't find cached entry for listener {:?}", id); } - fn get_image_if_available(&mut self, - url: ServoUrl, - placeholder: UsePlaceholder, ) - -> Result, ImageState> { - let img_or_metadata = self.get_image_or_meta_if_available(url, placeholder); - match img_or_metadata { - Ok(ImageOrMetadataAvailable::ImageAvailable(image)) => Ok(image), - Ok(ImageOrMetadataAvailable::MetadataAvailable(_)) => Err(ImageState::Pending), - Err(err) => Err(err), - } - } - + /// Return a completed image if it exists, or None if there is no complete load + /// of the complete load is not fully decoded or is unavailable. fn get_image_or_meta_if_available(&mut self, url: ServoUrl, placeholder: UsePlaceholder) @@ -616,46 +512,42 @@ impl ImageCache { } } None => { - let pl = match self.pending_loads.get_by_url(&url) { - Some(pl) => pl, - None => return Err(ImageState::NotRequested), - }; - - let meta = match pl.metadata { - Some(ref meta) => meta, - None => return Err(ImageState::Pending), - }; - - Ok(ImageOrMetadataAvailable::MetadataAvailable(meta.clone())) + let (result, key, pl) = self.pending_loads.get_cached(url); + match result { + CacheResult::Hit => match pl.metadata { + Some(ref meta) => + Ok(ImageOrMetadataAvailable::MetadataAvailable(meta.clone())), + None => + Err(ImageState::Pending(key)), + }, + CacheResult::Miss => Err(ImageState::NotRequested(key)), + } } } } fn store_decode_image(&mut self, - ref_url: ServoUrl, + id: PendingImageId, loaded_bytes: Vec) { - let (cache_result, load_key, _) = self.pending_loads.get_cached(ref_url.clone()); - assert!(cache_result == CacheResult::Miss); let action = FetchResponseMsg::ProcessResponseChunk(loaded_bytes); let _ = self.progress_sender.send(ResourceLoadInfo { action: action, - key: load_key, + key: id, }); let action = FetchResponseMsg::ProcessResponseEOF(Ok(())); let _ = self.progress_sender.send(ResourceLoadInfo { action: action, - key: load_key, + key: id, }); } } /// Create a new image cache. -pub fn new_image_cache_thread(core_resource_thread: CoreResourceThread, - webrender_api: webrender_traits::RenderApi) -> ImageCacheThread { +pub fn new_image_cache_thread(webrender_api: webrender_traits::RenderApi) -> ImageCacheThread { let (ipc_command_sender, ipc_command_receiver) = ipc::channel().unwrap(); thread::Builder::new().name("ImageCacheThread".to_owned()).spawn(move || { - ImageCache::run(core_resource_thread, webrender_api, ipc_command_receiver) + ImageCache::run(webrender_api, ipc_command_receiver) }).expect("Thread spawning failed"); ImageCacheThread::new(ipc_command_sender) diff --git a/components/net_traits/image_cache_thread.rs b/components/net_traits/image_cache_thread.rs index 4fb7aedee04..a000bd8b6bc 100644 --- a/components/net_traits/image_cache_thread.rs +++ b/components/net_traits/image_cache_thread.rs @@ -13,27 +13,45 @@ use std::sync::Arc; /// and/or repaint. #[derive(Clone, Deserialize, Serialize)] pub struct ImageResponder { - sender: IpcSender, + id: PendingImageId, + sender: IpcSender, +} + +#[derive(Deserialize, Serialize)] +pub struct PendingImageResponse { + pub response: ImageResponse, + pub id: PendingImageId, } impl ImageResponder { - pub fn new(sender: IpcSender) -> ImageResponder { + pub fn new(sender: IpcSender, id: PendingImageId) -> ImageResponder { ImageResponder { sender: sender, + id: id, } } pub fn respond(&self, response: ImageResponse) { - self.sender.send(response).unwrap() + // This send can fail if thread waiting for this notification has panicked. + // That's not a case that's worth warning about. + // TODO(#15501): are there cases in which we should perform cleanup? + let _ = self.sender.send(PendingImageResponse { + response: response, + id: self.id, + }); } } +/// The unique id for an image that has previously been requested. +#[derive(Copy, Clone, PartialEq, Eq, Deserialize, Serialize, HeapSizeOf, Hash, Debug)] +pub struct PendingImageId(pub u64); + /// The current state of an image in the cache. #[derive(PartialEq, Copy, Clone, Deserialize, Serialize)] pub enum ImageState { - Pending, + Pending(PendingImageId), LoadError, - NotRequested, + NotRequested(PendingImageId), } /// The returned image. @@ -56,45 +74,19 @@ pub enum ImageOrMetadataAvailable { MetadataAvailable(ImageMetadata), } -/// Channel used by the image cache to send results. -#[derive(Clone, Deserialize, Serialize)] -pub struct ImageCacheChan(pub IpcSender); - -/// The result of an image cache command that is returned to the -/// caller. -#[derive(Deserialize, Serialize)] -pub struct ImageCacheResult { - pub responder: Option, - pub image_response: ImageResponse, -} - /// Commands that the image cache understands. #[derive(Deserialize, Serialize)] pub enum ImageCacheCommand { - /// Request an image asynchronously from the cache. Supply a channel - /// to receive the result, and optionally an image responder - /// that is passed to the result channel. - RequestImage(ServoUrl, ImageCacheChan, Option), - - /// Requests an image and a "metadata-ready" notification message asynchronously from the - /// cache. The cache will make an effort to send metadata before the image is completely - /// loaded. Supply a channel to receive the results, and optionally an image responder - /// that is passed to the result channel. - RequestImageAndMetadata(ServoUrl, ImageCacheChan, Option), - - /// Synchronously check the state of an image in the cache. - /// TODO(gw): Profile this on some real world sites and see - /// if it's worth caching the results of this locally in each - /// layout / paint thread. - GetImageIfAvailable(ServoUrl, UsePlaceholder, IpcSender, ImageState>>), - /// Synchronously check the state of an image in the cache. If the image is in a loading /// state and but its metadata has been made available, it will be sent as a response. GetImageOrMetadataIfAvailable(ServoUrl, UsePlaceholder, IpcSender>), + /// Add a new listener for the given pending image. + AddListener(PendingImageId, ImageResponder), + /// Instruct the cache to store this data as a newly-complete network request and continue /// decoding the result into pixel data - StoreDecodeImage(ServoUrl, Vec), + StoreDecodeImage(PendingImageId, Vec), /// Clients must wait for a response before shutting down the ResourceThread Exit(IpcSender<()>), @@ -122,30 +114,6 @@ impl ImageCacheThread { } } - /// Asynchronously request an image. See ImageCacheCommand::RequestImage. - pub fn request_image(&self, url: ServoUrl, result_chan: ImageCacheChan, responder: Option) { - let msg = ImageCacheCommand::RequestImage(url, result_chan, responder); - let _ = self.chan.send(msg); - } - - /// Asynchronously request an image and metadata. - /// See ImageCacheCommand::RequestImageAndMetadata - pub fn request_image_and_metadata(&self, - url: ServoUrl, - result_chan: ImageCacheChan, - responder: Option) { - let msg = ImageCacheCommand::RequestImageAndMetadata(url, result_chan, responder); - let _ = self.chan.send(msg); - } - - /// Get the current state of an image. See ImageCacheCommand::GetImageIfAvailable. - pub fn find_image(&self, url: ServoUrl, use_placeholder: UsePlaceholder) -> Result, ImageState> { - let (sender, receiver) = ipc::channel().unwrap(); - let msg = ImageCacheCommand::GetImageIfAvailable(url, use_placeholder, sender); - let _ = self.chan.send(msg); - try!(receiver.recv().map_err(|_| ImageState::LoadError)) - } - /// Get the current state of an image, returning its metadata if available. /// See ImageCacheCommand::GetImageOrMetadataIfAvailable. /// @@ -160,14 +128,23 @@ impl ImageCacheThread { try!(receiver.recv().map_err(|_| ImageState::LoadError)) } - /// Decode the given image bytes and cache the result for the given URL. - pub fn store_complete_image_bytes(&self, url: ServoUrl, image_data: Vec) { - let msg = ImageCacheCommand::StoreDecodeImage(url, image_data); - let _ = self.chan.send(msg); + /// Add a new listener for the given pending image id. If the image is already present, + /// the responder will still receive the expected response. + pub fn add_listener(&self, id: PendingImageId, responder: ImageResponder) { + let msg = ImageCacheCommand::AddListener(id, responder); + self.chan.send(msg).expect("Image cache thread is not available"); + } + + /// Decode the given image bytes and cache the result for the given pending ID. + pub fn store_complete_image_bytes(&self, id: PendingImageId, image_data: Vec) { + let msg = ImageCacheCommand::StoreDecodeImage(id, image_data); + self.chan.send(msg).expect("Image cache thread is not available"); } /// Shutdown the image cache thread. pub fn exit(&self) { + // If the image cache is not available when we're trying to shut it down, + // that is not worth warning about. let (response_chan, response_port) = ipc::channel().unwrap(); let _ = self.chan.send(ImageCacheCommand::Exit(response_chan)); let _ = response_port.recv(); diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 0e605780a20..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; @@ -320,7 +320,7 @@ unsafe_no_jsmanaged_fields!(bool, f32, f64, String, AtomicBool, AtomicUsize, Uui unsafe_no_jsmanaged_fields!(usize, u8, u16, u32, u64); unsafe_no_jsmanaged_fields!(isize, i8, i16, i32, i64); unsafe_no_jsmanaged_fields!(ServoUrl, ImmutableOrigin, MutableOrigin); -unsafe_no_jsmanaged_fields!(Image, ImageMetadata, ImageCacheChan, ImageCacheThread); +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/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index b174d2ec9a8..47dc1d46a3d 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -337,15 +337,18 @@ 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; use servo_url::ServoUrl; pub fn request_image_from_cache(window: &Window, url: ServoUrl) -> ImageResponse { - let image_cache = window.image_cache_thread(); + panic!() + /*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 + match result { + ImageCacheResult::InitiateRequest(..) => panic!("unexpected image request initiator"), + ImageCacheResult::Response(result) => result.image_response, + }*/ } } diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index ec9f2e1ec80..e762675bc70 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,17 @@ use euclid::point::Point2D; use html5ever_atoms::LocalName; use ipc_channel::ipc; use ipc_channel::router::ROUTER; +use net_traits::{FetchResponseListener, FetchMetadata, Metadata, NetworkError}; 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}; +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 +59,12 @@ enum State { Broken, } #[derive(JSTraceable, HeapSizeOf)] +#[must_root] struct ImageRequest { state: State, parsed_url: Option, source_url: Option, + blocker: Option, #[ignore_heap_size_of = "Arc"] image: Option>, metadata: Option, @@ -74,6 +82,64 @@ impl HTMLImageElement { } } +struct ImageRequestRunnable { + element: Trusted, + img_url: ServoUrl, + id: PendingImageId, +} + +impl ImageRequestRunnable { + fn new(element: Trusted, + img_url: ServoUrl, + id: PendingImageId) + -> ImageRequestRunnable { + ImageRequestRunnable { + element: element, + img_url: img_url, + id: id, + } + } +} + +impl Runnable for ImageRequestRunnable { + fn handler(self: Box) { + let this = *self; + let trusted_node = this.element.clone(); + let element = this.element.root(); + + let document = document_from_node(&*element); + let window = window_from_node(&*element); + + let context = Arc::new(Mutex::new(ImageContext { + elem: trusted_node, + data: vec!(), + metadata: None, + url: this.img_url.clone(), + status: Ok(()), + id: this.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: this.img_url.clone(), + origin: document.url().clone(), + type_: RequestType::Image, + pipeline_id: Some(document.global().pipeline_id()), + .. RequestInit::default() + }; + + document.fetch_async(LoadType::Image(this.img_url), request, action_sender); + } +} struct ImageResponseHandlerRunnable { element: Trusted, @@ -122,23 +188,83 @@ impl Runnable for ImageResponseHandlerRunnable { element.upcast::().fire_event(atom!("error")); } + LoadBlocker::terminate(&mut element.current_request.borrow_mut().blocker); + // Trigger reflow let window = window_from_node(&*document); window.add_pending_reflow(); } } +/// The context required for asynchronously loading an external image. +struct ImageContext { + /// The element that initiated the request. + elem: Trusted, + /// The response body received to date. + data: Vec, + /// The response metadata received to date. + metadata: Option, + /// 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 FetchResponseListener for ImageContext { + fn process_request_body(&mut self) {} + fn process_request_eof(&mut self) {} + + fn process_response(&mut self, metadata: Result) { + self.metadata = metadata.ok().map(|meta| match meta { + FetchMetadata::Unfiltered(m) => m, + FetchMetadata::Filtered { unsafe_, .. } => unsafe_ + }); + + let status_code = self.metadata.as_ref().and_then(|m| { + match m.status { + Some((c, _)) => Some(c), + _ => None, + } + }).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, mut payload: Vec) { + if self.status.is_ok() { + self.data.append(&mut payload); + } + } + + fn process_response_eof(&mut self, _response: Result<(), NetworkError>) { + let elem = self.elem.root(); + let document = document_from_node(&*elem); + let window = document.window(); + let image_cache = window.image_cache_thread(); + image_cache.store_complete_image_bytes(self.id, self.data.clone()); + document.finish_load(LoadType::Image(self.url.clone())); + } +} + +impl PreInvoke for ImageContext {} + 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)) => { @@ -147,22 +273,57 @@ impl HTMLImageElement { self.current_request.borrow_mut().parsed_url = Some(img_url.clone()); self.current_request.borrow_mut().source_url = Some(src); + LoadBlocker::terminate(&mut self.current_request.borrow_mut().blocker); + self.current_request.borrow_mut().blocker = + Some(LoadBlocker::new(&*document, LoadType::Image(img_url.clone()))); + 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(); + let img_url_cloned = img_url.clone(); + let trusted_node_clone = trusted_node.clone(); 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); + let runnable = ImageResponseHandlerRunnable::new( + trusted_node_clone.clone(), message.to().unwrap()); + let _ = task_source.queue_with_wrapper(box runnable, &wrapper); }); - image_cache.request_image_and_metadata(img_url.into(), - window.image_cache_chan(), - Some(ImageResponder::new(responder_sender))); + let image_cache = window.image_cache_thread(); + let response = + image_cache.find_image_or_metadata(img_url_cloned.into(), UsePlaceholder::Yes); + match response { + Ok(ImageOrMetadataAvailable::ImageAvailable(image)) => { + let event = box ImageResponseHandlerRunnable::new( + trusted_node, ImageResponse::Loaded(image)); + event.handler(); + } + + Ok(ImageOrMetadataAvailable::MetadataAvailable(m)) => { + let event = box ImageResponseHandlerRunnable::new( + trusted_node, ImageResponse::MetadataLoaded(m)); + event.handler(); + } + + Err(ImageState::Pending(id)) => { + image_cache.add_listener(id, ImageResponder::new(responder_sender, id)); + } + + Err(ImageState::LoadError) => { + let event = box ImageResponseHandlerRunnable::new( + trusted_node, ImageResponse::None); + event.handler(); + } + + Err(ImageState::NotRequested(id)) => { + image_cache.add_listener(id, ImageResponder::new(responder_sender, id)); + let runnable = box ImageRequestRunnable::new( + Trusted::new(self), img_url, id); + runnable.handler(); + } + } } else { // https://html.spec.whatwg.org/multipage/#update-the-image-data // Step 11 (error substeps) @@ -202,6 +363,7 @@ impl HTMLImageElement { } } } + fn new_inherited(local_name: LocalName, prefix: Option, document: &Document) -> HTMLImageElement { HTMLImageElement { htmlelement: HTMLElement::new_inherited(local_name, prefix, document), @@ -210,14 +372,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/window.rs b/components/script/dom/window.rs index b6392fbdd19..fcf6a0019c0 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -6,6 +6,7 @@ use app_units::Au; use bluetooth_traits::BluetoothRequest; use cssparser::Parser; use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType}; +use document_loader::LoadType; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState}; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; @@ -42,7 +43,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, document_from_node, NodeDamage}; use dom::performance::Performance; use dom::promise::Promise; use dom::screen::Screen; @@ -52,20 +53,25 @@ 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 msg::constellation_msg::{FrameType, PipelineId}; -use net_traits::{ResourceThreads, ReferrerPolicy}; -use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread}; +use net_traits::{ResourceThreads, ReferrerPolicy, FetchResponseListener, FetchMetadata}; +use net_traits::NetworkError; +use net_traits::image_cache_thread::{ImageResponder, ImageResponse}; +use net_traits::image_cache_thread::{PendingImageResponse, ImageCacheThread, PendingImageId}; +use net_traits::request::{Type as RequestType, RequestInit as FetchRequestInit}; use net_traits::storage_thread::StorageType; +use network_listener::{NetworkListener, PreInvoke}; use num_traits::ToPrimitive; use open; 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}; @@ -73,7 +79,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}; @@ -87,6 +93,7 @@ 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; @@ -165,7 +172,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, browsing_context: MutNullableJS, document: MutNullableJS, history: MutNullableJS, @@ -253,7 +260,13 @@ pub struct Window { webvr_thread: Option>, /// A map for storing the previous permission state read results. - permission_state_invocation_results: DOMRefCell> + permission_state_invocation_results: DOMRefCell>, + + /// 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>>>, } impl Window { @@ -295,10 +308,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 } @@ -346,6 +355,28 @@ impl Window { pub fn permission_state_invocation_results(&self) -> &DOMRefCell> { &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"))] @@ -1168,6 +1199,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); + } + + 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::().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 } @@ -1227,7 +1283,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::(); let event = ConstellationMsg::SetDocumentState(global_scope.pipeline_id(), DocumentState::Idle); global_scope.constellation_chan().send(event).unwrap(); @@ -1635,7 +1692,7 @@ impl Window { network_task_source: NetworkingTaskSource, history_task_source: HistoryTraversalTaskSource, file_task_source: FileReadingTaskSource, - image_cache_chan: ImageCacheChan, + image_cache_chan: Sender, image_cache_thread: ImageCacheThread, resource_threads: ResourceThreads, bluetooth_thread: IpcSender, @@ -1717,6 +1774,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 { @@ -1836,3 +1894,64 @@ impl Runnable for PostMessageHandler { message.handle()); } } + +struct LayoutImageContext { + node: Trusted, + data: Vec, + id: PendingImageId, + url: ServoUrl, +} + +impl FetchResponseListener for LayoutImageContext { + fn process_request_body(&mut self) {} + fn process_request_eof(&mut self) {} + fn process_response(&mut self, _metadata: Result) {/*XXXjdm*/} + + fn process_response_chunk(&mut self, mut payload: Vec) { + self.data.append(&mut payload); + } + + fn process_response_eof(&mut self, _response: Result<(), NetworkError>) { + let node = self.node.root(); + let document = document_from_node(&*node); + let window = document.window(); + let image_cache = window.image_cache_thread(); + image_cache.store_complete_image_bytes(self.id, self.data.clone()); + document.finish_load(LoadType::Image(self.url.clone())); + } +} + +impl PreInvoke for LayoutImageContext {} + +fn fetch_image_for_layout(url: ServoUrl, node: &Node, id: PendingImageId) { + let context = Arc::new(Mutex::new(LayoutImageContext { + node: Trusted::new(node), + data: vec![], + id: id, + url: url.clone(), + })); + + let document = document_from_node(node); + let window = window_from_node(node); + + 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 = FetchRequestInit { + url: url.clone(), + origin: document.url().clone(), + type_: RequestType::Image, + pipeline_id: Some(document.global().pipeline_id()), + .. FetchRequestInit::default() + }; + + //XXXjdm should not block load event + document.fetch_async(LoadType::Image(url), request, action_sender); +} diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 2ab421c707b..192923294a6 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -73,7 +73,7 @@ use microtask::{MicrotaskQueue, Microtask}; use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespace}; use net_traits::{CoreResourceMsg, FetchMetadata, FetchResponseListener}; use net_traits::{IpcSend, Metadata, ReferrerPolicy, ResourceThreads}; -use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread}; +use net_traits::image_cache_thread::{PendingImageResponse, ImageCacheThread}; use net_traits::request::{CredentialsMode, Destination, RequestInit}; use net_traits::storage_thread::StorageType; use network_listener::NetworkListener; @@ -120,6 +120,8 @@ use url::Position; use webdriver_handlers; use webvr_traits::WebVRMsg; +pub type ImageCacheMsg = (PipelineId, PendingImageResponse); + thread_local!(pub static STACK_ROOTS: Cell> = Cell::new(None)); thread_local!(static SCRIPT_THREAD_ROOT: Cell> = Cell::new(None)); @@ -230,7 +232,7 @@ enum MixedMessage { FromConstellation(ConstellationControlMsg), FromScript(MainThreadScriptMsg), FromDevtools(DevtoolScriptControlMsg), - FromImageCache(ImageCacheResult), + FromImageCache((PipelineId, PendingImageResponse)), FromScheduler(TimerEvent) } @@ -444,10 +446,10 @@ pub struct ScriptThread { layout_to_constellation_chan: IpcSender, /// The port on which we receive messages from the image cache - image_cache_port: Receiver, + image_cache_port: Receiver, /// The channel on which the image cache can send messages to ourself. - image_cache_channel: ImageCacheChan, + image_cache_channel: Sender, /// For providing contact with the time profiler. time_profiler_chan: time::ProfilerChan, @@ -646,11 +648,6 @@ impl ScriptThread { let (ipc_devtools_sender, ipc_devtools_receiver) = ipc::channel().unwrap(); let devtools_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_devtools_receiver); - // Ask the router to proxy IPC messages from the image cache thread to us. - let (ipc_image_cache_channel, ipc_image_cache_port) = ipc::channel().unwrap(); - let image_cache_port = - ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_image_cache_port); - let (timer_event_chan, timer_event_port) = channel(); // Ask the router to proxy IPC messages from the control port to us. @@ -658,6 +655,8 @@ impl ScriptThread { let boxed_script_sender = MainThreadScriptChan(chan.clone()).clone(); + let (image_cache_channel, image_cache_port) = channel(); + ScriptThread { documents: DOMRefCell::new(Documents::new()), browsing_contexts: DOMRefCell::new(HashMap::new()), @@ -666,7 +665,7 @@ impl ScriptThread { job_queue_map: Rc::new(JobQueue::new()), image_cache_thread: state.image_cache_thread, - image_cache_channel: ImageCacheChan(ipc_image_cache_channel), + image_cache_channel: image_cache_channel, image_cache_port: image_cache_port, resource_threads: state.resource_threads, @@ -1111,8 +1110,11 @@ impl ScriptThread { } } - fn handle_msg_from_image_cache(&self, msg: ImageCacheResult) { - msg.responder.unwrap().respond(msg.image_response); + fn handle_msg_from_image_cache(&self, (id, response): (PipelineId, PendingImageResponse)) { + let window = self.documents.borrow().find_window(id); + if let Some(ref window) = window { + window.pending_image_notification(response); + } } fn handle_webdriver_msg(&self, pipeline_id: PipelineId, msg: WebDriverScriptCommand) { diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index 87b76763d7d..1793e06909d 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -43,6 +43,9 @@ use canvas_traits::CanvasMsg; use core::nonzero::NonZero; use ipc_channel::ipc::IpcSender; use libc::c_void; +use net_traits::image_cache_thread::PendingImageId; +use script_traits::UntrustedNodeAddress; +use servo_url::ServoUrl; use std::sync::atomic::AtomicIsize; use style::data::ElementData; @@ -137,3 +140,18 @@ pub fn is_image_data(uri: &str) -> bool { static TYPES: &'static [&'static str] = &["data:image/png", "data:image/gif", "data:image/jpeg"]; TYPES.iter().any(|&type_| uri.starts_with(type_)) } + +/// Whether the pending image needs to be fetched or is waiting on an existing fetch. +pub enum PendingImageState { + Unrequested(ServoUrl), + PendingResponse, +} + +/// The data associated with an image that is not yet present in the image cache. +/// Used by the script thread to hold on to DOM elements that need to be repainted +/// when an image fetch is complete. +pub struct PendingImage { + pub state: PendingImageState, + pub node: UntrustedNodeAddress, + pub id: PendingImageId, +} diff --git a/components/script_layout_interface/rpc.rs b/components/script_layout_interface/rpc.rs index 2fb75f6b959..78e99571ee7 100644 --- a/components/script_layout_interface/rpc.rs +++ b/components/script_layout_interface/rpc.rs @@ -2,6 +2,7 @@ * 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 PendingImage; use app_units::Au; use euclid::point::Point2D; use euclid::rect::Rect; @@ -37,7 +38,8 @@ pub trait LayoutRPC { fn offset_parent(&self) -> OffsetParentResponse; /// Query layout for the resolve values of the margin properties for an element. fn margin_style(&self) -> MarginStyleResponse; - + /// Requests the list of not-yet-loaded images that were encountered in the last reflow. + fn pending_images(&self) -> Vec; fn nodes_from_point(&self, page_point: Point2D, client_point: Point2D) -> Vec; fn text_index(&self) -> TextIndexResponse; diff --git a/components/script_plugins/unrooted_must_root.rs b/components/script_plugins/unrooted_must_root.rs index 660a0c58781..ad74f6c4b8f 100644 --- a/components/script_plugins/unrooted_must_root.rs +++ b/components/script_plugins/unrooted_must_root.rs @@ -52,6 +52,7 @@ fn is_unrooted_ty(cx: &LateContext, ty: &ty::TyS, in_new_function: bool) -> bool } else if match_def_path(cx, did.did, &["core", "cell", "Ref"]) || match_def_path(cx, did.did, &["core", "cell", "RefMut"]) || match_def_path(cx, did.did, &["core", "slice", "Iter"]) + || match_def_path(cx, did.did, &["std", "collections", "hash", "map", "Entry"]) || match_def_path(cx, did.did, &["std", "collections", "hash", "map", "OccupiedEntry"]) || match_def_path(cx, did.did, &["std", "collections", "hash", "map", "VacantEntry"]) { // Structures which are semantically similar to an &ptr. diff --git a/components/servo/lib.rs b/components/servo/lib.rs index afda35f1582..69b9bbeceb8 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -281,8 +281,7 @@ fn create_constellation(user_agent: Cow<'static, str>, devtools_chan.clone(), time_profiler_chan.clone(), config_dir); - let image_cache_thread = new_image_cache_thread(public_resource_threads.sender(), - webrender_api_sender.create_api()); + let image_cache_thread = new_image_cache_thread(webrender_api_sender.create_api()); let font_cache_thread = FontCacheThread::new(public_resource_threads.sender(), Some(webrender_api_sender.create_api())); From 541ecbfe21d0e79d1eb8b6f197325adc5065b684 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Tue, 13 Dec 2016 22:58:42 -0500 Subject: [PATCH 02/10] Fetch complete images from the cache for canvas operations. --- components/script/dom/htmlcanvaselement.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 47dc1d46a3d..9f77f8b9ce1 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -337,18 +337,19 @@ impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes { pub mod utils { use dom::window::Window; - use net_traits::image_cache_thread::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 { - panic!() - /*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(); - match result { - ImageCacheResult::InitiateRequest(..) => panic!("unexpected image request initiator"), - ImageCacheResult::Response(result) => result.image_response, - }*/ + let image_cache = window.image_cache_thread(); + //XXXjdm add a image cache mode that doesn't store anything for NotRequested? + let response = + image_cache.find_image_or_metadata(url.into(), UsePlaceholder::No); + match response { + Ok(ImageOrMetadataAvailable::ImageAvailable(image)) => + ImageResponse::Loaded(image), + _ => ImageResponse::None, + } } } From 980eb5ac33b16d7310d0b5b20d8c3f94b4b2c241 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 29 Dec 2016 14:07:57 -0500 Subject: [PATCH 03/10] Avoid dropping image requests on the ground from non-script-initiated reflow. --- components/layout/context.rs | 39 +++++++++++++------ components/layout_thread/lib.rs | 29 +++++++------- components/net/image_cache_thread.rs | 42 +++++++++++++-------- components/net_traits/image_cache_thread.rs | 22 +++++++++-- components/script/dom/htmlcanvaselement.rs | 5 ++- components/script/dom/htmlimageelement.rs | 6 ++- 6 files changed, 96 insertions(+), 47 deletions(-) diff --git a/components/layout/context.rs b/components/layout/context.rs index 13029dd80bf..1dff9f6ea5e 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -9,7 +9,7 @@ use gfx::display_list::{WebRenderImageInfo, OpaqueNode}; use gfx::font_cache_thread::FontCacheThread; use gfx::font_context::FontContext; use heapsize::HeapSizeOf; -use net_traits::image_cache_thread::{ImageCacheThread, ImageState}; +use net_traits::image_cache_thread::{ImageCacheThread, ImageState, CanRequestImages}; use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder}; use opaque_node::OpaqueNodeMethods; use parking_lot::RwLock; @@ -92,13 +92,15 @@ pub struct LayoutContext { /// A list of in-progress image loads to be shared with the script thread. /// A None value means that this layout was not initiated by the script thread. - pub pending_images: Mutex> + pub pending_images: Option>> } impl Drop for LayoutContext { fn drop(&mut self) { if !thread::panicking() { - assert!(self.pending_images.lock().unwrap().is_empty()); + if let Some(ref pending_images) = self.pending_images { + assert!(pending_images.lock().unwrap().is_empty()); + } } } } @@ -114,10 +116,20 @@ impl LayoutContext { url: ServoUrl, use_placeholder: UsePlaceholder) -> Option { + //XXXjdm For cases where we do not request an image, we still need to + // ensure the node gets another script-initiated reflow or it + // won't be requested at all. + let can_request = if self.pending_images.is_some() { + CanRequestImages::Yes + } else { + CanRequestImages::No + }; + // See if the image is already available let result = self.image_cache_thread.lock().unwrap() .find_image_or_metadata(url.clone(), - use_placeholder); + use_placeholder, + can_request); match result { Ok(image_or_metadata) => Some(image_or_metadata), // Image failed to load, so just return nothing @@ -129,18 +141,23 @@ impl LayoutContext { node: node.to_untrusted_node_address(), id: id, }; - self.pending_images.lock().unwrap().push(image); + self.pending_images.as_ref().unwrap().lock().unwrap().push(image); None } // Image has been requested, is still pending. Return no image for this paint loop. // When the image loads it will trigger a reflow and/or repaint. Err(ImageState::Pending(id)) => { - let image = PendingImage { - state: PendingImageState::PendingResponse, - node: node.to_untrusted_node_address(), - id: id, - }; - self.pending_images.lock().unwrap().push(image); + //XXXjdm if self.pending_images is not available, we should make sure that + // this node gets marked dirty again so it gets a script-initiated + // reflow that deals with this properly. + if let Some(ref pending_images) = self.pending_images { + let image = PendingImage { + state: PendingImageState::PendingResponse, + node: node.to_untrusted_node_address(), + id: id, + }; + pending_images.lock().unwrap().push(image); + } None } } diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index af56555e399..8d6f2377130 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -495,7 +495,8 @@ impl LayoutThread { fn build_layout_context(&self, rw_data: &LayoutThreadData, screen_size_changed: bool, - goal: ReflowGoal) + goal: ReflowGoal, + request_images: bool) -> LayoutContext { let thread_local_style_context_creation_data = ThreadLocalStyleContextCreationInfo::new(self.new_animations_sender.clone()); @@ -521,7 +522,7 @@ impl LayoutThread { image_cache_thread: Mutex::new(self.image_cache_thread.clone()), font_cache_thread: Mutex::new(self.font_cache_thread.clone()), webrender_image_cache: self.webrender_image_cache.clone(), - pending_images: Mutex::new(vec![]), + pending_images: if request_images { Some(Mutex::new(vec![])) } else { None }, } } @@ -1115,7 +1116,8 @@ impl LayoutThread { // Create a layout context for use throughout the following passes. let mut layout_context = self.build_layout_context(&*rw_data, viewport_size_changed, - data.reflow_info.goal); + data.reflow_info.goal, + true); // NB: Type inference falls apart here for some reason, so we need to be very verbose. :-( let traversal_driver = if self.parallel_flag && self.parallel_traversal.is_some() { @@ -1196,8 +1198,11 @@ impl LayoutThread { query_type: &ReflowQueryType, rw_data: &mut LayoutThreadData, context: &mut LayoutContext) { - rw_data.pending_images = - std_mem::replace(&mut context.pending_images.lock().unwrap(), vec![]); + let pending_images = match context.pending_images { + Some(ref pending) => std_mem::replace(&mut *pending.lock().unwrap(), vec![]), + None => vec![], + }; + rw_data.pending_images = pending_images; let mut root_flow = match self.root_flow.clone() { Some(root_flow) => root_flow, @@ -1319,7 +1324,8 @@ impl LayoutThread { let mut layout_context = self.build_layout_context(&*rw_data, false, - reflow_info.goal); + reflow_info.goal, + false); if let Some(mut root_flow) = self.root_flow.clone() { // Perform an abbreviated style recalc that operates without access to the DOM. @@ -1340,13 +1346,7 @@ impl LayoutThread { &mut *rw_data, &mut layout_context); - let mut pending_images = layout_context.pending_images.lock().unwrap(); - if pending_images.len() > 0 { - //XXXjdm we drop all the images on the floor, but there's no guarantee that - // the node references are valid since the script thread isn't paused. - // need to figure out what to do here! - pending_images.truncate(0); - } + assert!(layout_context.pending_images.is_none()); } fn reflow_with_newly_loaded_web_font<'a, 'b>(&mut self, possibly_locked_rw_data: &mut RwData<'a, 'b>) { @@ -1360,7 +1360,8 @@ impl LayoutThread { let mut layout_context = self.build_layout_context(&*rw_data, false, - reflow_info.goal); + reflow_info.goal, + false); // No need to do a style recalc here. if self.root_flow.is_none() { diff --git a/components/net/image_cache_thread.rs b/components/net/image_cache_thread.rs index 17a852833c2..6c2da2c7c08 100644 --- a/components/net/image_cache_thread.rs +++ b/components/net/image_cache_thread.rs @@ -9,7 +9,7 @@ use net_traits::{NetworkError, FetchResponseMsg}; use net_traits::image::base::{Image, ImageMetadata, PixelFormat, load_from_memory}; use net_traits::image_cache_thread::{ImageCacheCommand, ImageCacheThread, ImageState}; use net_traits::image_cache_thread::{ImageOrMetadataAvailable, ImageResponse, UsePlaceholder}; -use net_traits::image_cache_thread::{ImageResponder, PendingImageId}; +use net_traits::image_cache_thread::{ImageResponder, PendingImageId, CanRequestImages}; use servo_config::resource_files::resources_dir_path; use servo_url::ServoUrl; use std::borrow::ToOwned; @@ -108,11 +108,12 @@ struct AllPendingLoads { keygen: LoadKeyGenerator, } -// Result of accessing a cache. -#[derive(Eq, PartialEq)] -enum CacheResult { - Hit, // The value was in the cache. - Miss, // The value was not in the cache and needed to be regenerated. +/// Result of accessing a cache. +enum CacheResult<'a> { + /// The value was in the cache. + Hit(LoadKey, &'a mut PendingLoad), + /// The value was not in the cache and needed to be regenerated. + Miss(Option<(LoadKey, &'a mut PendingLoad)>), } impl AllPendingLoads { @@ -143,13 +144,18 @@ impl AllPendingLoads { }) } - fn get_cached(&mut self, url: ServoUrl) -> (CacheResult, LoadKey, &mut PendingLoad) { + fn get_cached<'a>(&'a mut self, url: ServoUrl, can_request: CanRequestImages) + -> CacheResult<'a> { match self.url_to_load_key.entry(url.clone()) { Occupied(url_entry) => { let load_key = url_entry.get(); - (CacheResult::Hit, *load_key, self.loads.get_mut(load_key).unwrap()) + CacheResult::Hit(*load_key, self.loads.get_mut(load_key).unwrap()) } Vacant(url_entry) => { + if can_request == CanRequestImages::No { + return CacheResult::Miss(None); + } + let load_key = self.keygen.next(); url_entry.insert(load_key); @@ -158,7 +164,7 @@ impl AllPendingLoads { Occupied(_) => unreachable!(), Vacant(load_entry) => { let mut_load = load_entry.insert(pending_load); - (CacheResult::Miss, load_key, mut_load) + CacheResult::Miss(Some((load_key, mut_load))) } } } @@ -362,8 +368,12 @@ impl ImageCache { ImageCacheCommand::AddListener(id, responder) => { self.add_listener(id, responder); } - ImageCacheCommand::GetImageOrMetadataIfAvailable(url, use_placeholder, consumer) => { - let result = self.get_image_or_meta_if_available(url, use_placeholder); + ImageCacheCommand::GetImageOrMetadataIfAvailable(url, + use_placeholder, + can_request, + consumer) => { + let result = self.get_image_or_meta_if_available(url, use_placeholder, can_request); + // TODO(#15501): look for opportunities to clean up cache if this send fails. let _ = consumer.send(result); } ImageCacheCommand::StoreDecodeImage(id, image_vector) => { @@ -495,7 +505,8 @@ impl ImageCache { /// of the complete load is not fully decoded or is unavailable. fn get_image_or_meta_if_available(&mut self, url: ServoUrl, - placeholder: UsePlaceholder) + placeholder: UsePlaceholder, + can_request: CanRequestImages) -> Result { match self.completed_loads.get(&url) { Some(completed_load) => { @@ -512,15 +523,16 @@ impl ImageCache { } } None => { - let (result, key, pl) = self.pending_loads.get_cached(url); + let result = self.pending_loads.get_cached(url, can_request); match result { - CacheResult::Hit => match pl.metadata { + CacheResult::Hit(key, pl) => match pl.metadata { Some(ref meta) => Ok(ImageOrMetadataAvailable::MetadataAvailable(meta.clone())), None => Err(ImageState::Pending(key)), }, - CacheResult::Miss => Err(ImageState::NotRequested(key)), + CacheResult::Miss(Some((key, _pl))) => Err(ImageState::NotRequested(key)), + CacheResult::Miss(None) => Err(ImageState::LoadError), } } } diff --git a/components/net_traits/image_cache_thread.rs b/components/net_traits/image_cache_thread.rs index a000bd8b6bc..481a4f551ea 100644 --- a/components/net_traits/image_cache_thread.rs +++ b/components/net_traits/image_cache_thread.rs @@ -79,7 +79,10 @@ pub enum ImageOrMetadataAvailable { pub enum ImageCacheCommand { /// Synchronously check the state of an image in the cache. If the image is in a loading /// state and but its metadata has been made available, it will be sent as a response. - GetImageOrMetadataIfAvailable(ServoUrl, UsePlaceholder, IpcSender>), + GetImageOrMetadataIfAvailable(ServoUrl, + UsePlaceholder, + CanRequestImages, + IpcSender>), /// Add a new listener for the given pending image. AddListener(PendingImageId, ImageResponder), @@ -98,6 +101,15 @@ pub enum UsePlaceholder { Yes, } +/// Whether a consumer is in a position to request images or not. This can occur when +/// animations are being processed by the layout thread while the script thread is executing +/// in parallel. +#[derive(Copy, Clone, PartialEq, Deserialize, Serialize)] +pub enum CanRequestImages { + No, + Yes, +} + /// The client side of the image cache thread. This can be safely cloned /// and passed to different threads. #[derive(Clone, Deserialize, Serialize)] @@ -120,10 +132,14 @@ impl ImageCacheThread { /// FIXME: We shouldn't do IPC for data uris! pub fn find_image_or_metadata(&self, url: ServoUrl, - use_placeholder: UsePlaceholder) + use_placeholder: UsePlaceholder, + can_request: CanRequestImages) -> Result { let (sender, receiver) = ipc::channel().unwrap(); - let msg = ImageCacheCommand::GetImageOrMetadataIfAvailable(url, use_placeholder, sender); + let msg = ImageCacheCommand::GetImageOrMetadataIfAvailable(url, + use_placeholder, + can_request, + sender); let _ = self.chan.send(msg); try!(receiver.recv().map_err(|_| ImageState::LoadError)) } diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 9f77f8b9ce1..a51463f4674 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -343,9 +343,10 @@ pub mod utils { pub fn request_image_from_cache(window: &Window, url: ServoUrl) -> ImageResponse { let image_cache = window.image_cache_thread(); - //XXXjdm add a image cache mode that doesn't store anything for NotRequested? let response = - image_cache.find_image_or_metadata(url.into(), UsePlaceholder::No); + image_cache.find_image_or_metadata(url.into(), + UsePlaceholder::No, + CanRequestImages::No); match response { Ok(ImageOrMetadataAvailable::ImageAvailable(image)) => ImageResponse::Loaded(image), diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index e762675bc70..f104330c741 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -39,7 +39,7 @@ use ipc_channel::router::ROUTER; use net_traits::{FetchResponseListener, FetchMetadata, Metadata, NetworkError}; use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image_cache_thread::{ImageResponder, ImageResponse, PendingImageId, ImageState}; -use net_traits::image_cache_thread::{UsePlaceholder, ImageOrMetadataAvailable}; +use net_traits::image_cache_thread::{UsePlaceholder, ImageOrMetadataAvailable, CanRequestImages}; use net_traits::request::{RequestInit, Type as RequestType}; use network_listener::{NetworkListener, PreInvoke}; use num_traits::ToPrimitive; @@ -293,7 +293,9 @@ impl HTMLImageElement { let image_cache = window.image_cache_thread(); let response = - image_cache.find_image_or_metadata(img_url_cloned.into(), UsePlaceholder::Yes); + image_cache.find_image_or_metadata(img_url_cloned.into(), + UsePlaceholder::Yes, + CanRequestImages::Yes); match response { Ok(ImageOrMetadataAvailable::ImageAvailable(image)) => { let event = box ImageResponseHandlerRunnable::new( From e0837134ffad28af81bbe2ca3a7a51e3ffb082ca Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Wed, 4 Jan 2017 15:12:15 -0500 Subject: [PATCH 04/10] Remove synchronous forks of drawImage tests, and enable proper asynchronous drawImage tests. --- .../drawimage_html_image_1.html.ini | 3 - .../drawimage_html_image_10.html.ini | 3 - .../drawimage_html_image_11.html.ini | 3 - .../drawimage_html_image_12.html.ini | 3 - .../drawimage_html_image_13.html.ini | 3 - .../drawimage_html_image_2.html.ini | 3 - .../drawimage_html_image_3.html.ini | 3 - .../drawimage_html_image_4.html.ini | 3 - .../drawimage_html_image_5.html.ini | 3 - .../drawimage_html_image_6.html.ini | 3 - .../drawimage_html_image_7.html.ini | 3 - .../drawimage_html_image_8.html.ini | 3 - .../drawimage_html_image_9.html.ini | 3 - tests/wpt/metadata/MANIFEST.json | 22 +- .../current-pixel-density/basic.html.ini | 3 - tests/wpt/mozilla/meta/MANIFEST.json | 327 +----------------- .../canvas/drawimage_html_image_1.html | 29 -- .../canvas/drawimage_html_image_10.html | 33 -- .../canvas/drawimage_html_image_10_ref.html | 19 - .../canvas/drawimage_html_image_11.html | 31 -- .../canvas/drawimage_html_image_11_ref.html | 19 - .../canvas/drawimage_html_image_12.html | 31 -- .../canvas/drawimage_html_image_12_ref.html | 32 -- .../canvas/drawimage_html_image_13.html | 39 --- .../canvas/drawimage_html_image_13_ref.html | 20 -- .../canvas/drawimage_html_image_1_ref.html | 19 - .../canvas/drawimage_html_image_2.html | 30 -- .../canvas/drawimage_html_image_2_ref.html | 23 -- .../canvas/drawimage_html_image_3.html | 30 -- .../canvas/drawimage_html_image_3_ref.html | 23 -- .../canvas/drawimage_html_image_4.html | 31 -- .../canvas/drawimage_html_image_4_ref.html | 29 -- .../canvas/drawimage_html_image_5.html | 30 -- .../canvas/drawimage_html_image_5_ref.html | 38 -- .../canvas/drawimage_html_image_6.html | 31 -- .../canvas/drawimage_html_image_6_ref.html | 25 -- .../canvas/drawimage_html_image_7.html | 31 -- .../canvas/drawimage_html_image_7_ref.html | 35 -- .../canvas/drawimage_html_image_8.html | 31 -- .../canvas/drawimage_html_image_8_ref.html | 35 -- .../canvas/drawimage_html_image_9.html | 38 -- .../canvas/drawimage_html_image_9_ref.html | 19 - .../fill_and_stroke_getters_setters.html | 16 +- .../drawimage_html_image_1.html | 2 + .../drawimage_html_image_10.html | 2 + .../drawimage_html_image_11.html | 2 + .../drawimage_html_image_12.html | 2 + .../drawimage_html_image_2.html | 2 + .../drawimage_html_image_3.html | 2 + .../drawimage_html_image_4.html | 2 + .../drawimage_html_image_5.html | 2 + .../drawimage_html_image_6.html | 2 + .../drawimage_html_image_7.html | 2 + .../drawimage_html_image_8.html | 2 + 54 files changed, 44 insertions(+), 1136 deletions(-) delete mode 100644 tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_1.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_10.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_11.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_12.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_13.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_2.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_3.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_4.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_5.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_6.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_7.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_8.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_9.html.ini delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_1.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_10.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_10_ref.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_11.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_11_ref.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_12.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_12_ref.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_13.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_13_ref.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_1_ref.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_2.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_2_ref.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_3.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_3_ref.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_4.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_4_ref.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_5.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_5_ref.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_6.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_6_ref.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_7.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_7_ref.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_8.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_8_ref.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_9.html delete mode 100644 tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_9_ref.html diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_1.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_1.html.ini deleted file mode 100644 index 396d39eeb09..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_1.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawimage_html_image_1.html] - type: reftest - disabled: see _mozilla diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_10.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_10.html.ini deleted file mode 100644 index 4dcc60a0824..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_10.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawimage_html_image_10.html] - type: reftest - disabled: see _mozilla diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_11.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_11.html.ini deleted file mode 100644 index f26feab7168..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_11.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawimage_html_image_11.html] - type: reftest - disabled: see _mozilla diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_12.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_12.html.ini deleted file mode 100644 index 8eb54f816a9..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_12.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawimage_html_image_12.html] - type: reftest - disabled: see _mozilla diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_13.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_13.html.ini deleted file mode 100644 index 856288b3d70..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_13.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawimage_html_image_13.html] - type: reftest - disabled: see _mozilla diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_2.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_2.html.ini deleted file mode 100644 index 3ba92dd7d75..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_2.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawimage_html_image_2.html] - type: reftest - disabled: see _mozilla diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_3.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_3.html.ini deleted file mode 100644 index 277d697527d..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_3.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawimage_html_image_3.html] - type: reftest - disabled: see _mozilla diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_4.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_4.html.ini deleted file mode 100644 index 6ced959e23b..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_4.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawimage_html_image_4.html] - type: reftest - disabled: see _mozilla diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_5.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_5.html.ini deleted file mode 100644 index 8cd1d610a01..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_5.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawimage_html_image_5.html] - type: reftest - disabled: see _mozilla diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_6.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_6.html.ini deleted file mode 100644 index 8d2dfb702fb..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_6.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawimage_html_image_6.html] - type: reftest - disabled: see _mozilla diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_7.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_7.html.ini deleted file mode 100644 index e24ff5c2fae..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_7.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawimage_html_image_7.html] - type: reftest - disabled: see _mozilla diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_8.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_8.html.ini deleted file mode 100644 index 13688c76798..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_8.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawimage_html_image_8.html] - type: reftest - disabled: see _mozilla diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_9.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_9.html.ini deleted file mode 100644 index 0cf6369939f..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_9.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawimage_html_image_9.html] - type: reftest - disabled: see _mozilla diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index edbb4f2386e..587ce32e6f0 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -130647,11 +130647,11 @@ "support" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_1.html": [ - "8cff9e2344fbbe84b2ce315f260e69c6ad92dd51", + "461f306d3083248243d7e5a4aac376be59adefd3", "reftest" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_10.html": [ - "ca239d9a40410e4331863f2d11daabae3e590af3", + "970d92ab928086b48dce22c2a873a0e5adde1355", "reftest" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_10_ref.html": [ @@ -130659,7 +130659,7 @@ "support" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_11.html": [ - "04415ce09b3b52561f5d179e7a6a8050199189c9", + "9faf39bcfb3ed5f86b78fabcb8566386ca519b6e", "reftest" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_11_ref.html": [ @@ -130667,7 +130667,7 @@ "support" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_12.html": [ - "efee9a63933437315c9adec573113d8dee786659", + "8f4e8952d6959d7ad3c32ca02a6b91eb29c9bc28", "reftest" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_12_ref.html": [ @@ -130687,7 +130687,7 @@ "support" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_2.html": [ - "b03f11e43e455e2d1f453ecc2a4de00e00005ebc", + "310d7bf19699754d6248599820e17850f0a8de2c", "reftest" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_2_ref.html": [ @@ -130695,7 +130695,7 @@ "support" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_3.html": [ - "134fa026f56880acb111a8e91efe3a8bcc03bb6b", + "368a40dff341c6677a23c5ffeb4a69dc447360e6", "reftest" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_3_ref.html": [ @@ -130703,7 +130703,7 @@ "support" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_4.html": [ - "5d7254f7bbc8c6feffb2a4fcfeecb06fe6ed3d6c", + "a0aa4f32aeb8b0b4178b0efa1446455387f281eb", "reftest" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_4_ref.html": [ @@ -130711,7 +130711,7 @@ "support" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_5.html": [ - "6a02b961aa4a5eb013366cd85dbea06fd2c08da0", + "7d92f1f10e7bc29564d7a8b8e49d42f552ad0782", "reftest" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_5_ref.html": [ @@ -130719,7 +130719,7 @@ "support" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_6.html": [ - "ce7cbe3b76274177301acca263f7cdd6c4033aa1", + "c60e69eaf1e92c6e2cd53936e52683054fbddd32", "reftest" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_6_ref.html": [ @@ -130727,7 +130727,7 @@ "support" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_7.html": [ - "f5469ba799e0845bc59766d76713ee052f3e6966", + "d305b82f0329bbedd5e950287619e8a7dc926536", "reftest" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_7_ref.html": [ @@ -130735,7 +130735,7 @@ "support" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_8.html": [ - "37958b2fb55bd90567c7c0b64b599165b20992b9", + "00a95cb5ad9f256101ea65f296a201d7074ef9f5", "reftest" ], "2dcontext/drawing-images-to-the-canvas/drawimage_html_image_8_ref.html": [ diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/current-pixel-density/basic.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/current-pixel-density/basic.html.ini index 1435a098642..2aa027d16bf 100644 --- a/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/current-pixel-density/basic.html.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/current-pixel-density/basic.html.ini @@ -1,8 +1,5 @@ [basic.html] type: testharness - [] - expected: FAIL - [] expected: FAIL diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 62275196fbf..96de8d62563 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -6317,162 +6317,6 @@ {} ] ], - "mozilla/canvas/drawimage_html_image_1.html": [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_1.html", - [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_1_ref.html", - "==" - ] - ], - {} - ] - ], - "mozilla/canvas/drawimage_html_image_10.html": [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_10.html", - [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_10_ref.html", - "==" - ] - ], - {} - ] - ], - "mozilla/canvas/drawimage_html_image_11.html": [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_11.html", - [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_11_ref.html", - "==" - ] - ], - {} - ] - ], - "mozilla/canvas/drawimage_html_image_12.html": [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_12.html", - [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_12_ref.html", - "==" - ] - ], - {} - ] - ], - "mozilla/canvas/drawimage_html_image_13.html": [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_13.html", - [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_13_ref.html", - "==" - ] - ], - {} - ] - ], - "mozilla/canvas/drawimage_html_image_2.html": [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_2.html", - [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_2_ref.html", - "==" - ] - ], - {} - ] - ], - "mozilla/canvas/drawimage_html_image_3.html": [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_3.html", - [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_3_ref.html", - "==" - ] - ], - {} - ] - ], - "mozilla/canvas/drawimage_html_image_4.html": [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_4.html", - [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_4_ref.html", - "==" - ] - ], - {} - ] - ], - "mozilla/canvas/drawimage_html_image_5.html": [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_5.html", - [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_5_ref.html", - "==" - ] - ], - {} - ] - ], - "mozilla/canvas/drawimage_html_image_6.html": [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_6.html", - [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_6_ref.html", - "==" - ] - ], - {} - ] - ], - "mozilla/canvas/drawimage_html_image_7.html": [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_7.html", - [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_7_ref.html", - "==" - ] - ], - {} - ] - ], - "mozilla/canvas/drawimage_html_image_8.html": [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_8.html", - [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_8_ref.html", - "==" - ] - ], - {} - ] - ], - "mozilla/canvas/drawimage_html_image_9.html": [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_9.html", - [ - [ - "/_mozilla/mozilla/canvas/drawimage_html_image_9_ref.html", - "==" - ] - ], - {} - ] - ], "mozilla/details_ui_closed.html": [ [ "/_mozilla/mozilla/details_ui_closed.html", @@ -9529,71 +9373,6 @@ {} ] ], - "mozilla/canvas/drawimage_html_image_10_ref.html": [ - [ - {} - ] - ], - "mozilla/canvas/drawimage_html_image_11_ref.html": [ - [ - {} - ] - ], - "mozilla/canvas/drawimage_html_image_12_ref.html": [ - [ - {} - ] - ], - "mozilla/canvas/drawimage_html_image_13_ref.html": [ - [ - {} - ] - ], - "mozilla/canvas/drawimage_html_image_1_ref.html": [ - [ - {} - ] - ], - "mozilla/canvas/drawimage_html_image_2_ref.html": [ - [ - {} - ] - ], - "mozilla/canvas/drawimage_html_image_3_ref.html": [ - [ - {} - ] - ], - "mozilla/canvas/drawimage_html_image_4_ref.html": [ - [ - {} - ] - ], - "mozilla/canvas/drawimage_html_image_5_ref.html": [ - [ - {} - ] - ], - "mozilla/canvas/drawimage_html_image_6_ref.html": [ - [ - {} - ] - ], - "mozilla/canvas/drawimage_html_image_7_ref.html": [ - [ - {} - ] - ], - "mozilla/canvas/drawimage_html_image_8_ref.html": [ - [ - {} - ] - ], - "mozilla/canvas/drawimage_html_image_9_ref.html": [ - [ - {} - ] - ], "mozilla/click_prevent.html": [ [ {} @@ -25242,112 +25021,8 @@ "9fb338806987e20f1bac3c09231e1e5718ac4b23", "testharness" ], - "mozilla/canvas/drawimage_html_image_1.html": [ - "90ea4e0cfef9731726582e1867d1ced66b6bcc2b", - "reftest" - ], - "mozilla/canvas/drawimage_html_image_10.html": [ - "51a931987a4e22674014d9e9a3f298029f546bbe", - "reftest" - ], - "mozilla/canvas/drawimage_html_image_10_ref.html": [ - "9a70c803aaf5bd8a843b18d6d16779575d4dc6f8", - "support" - ], - "mozilla/canvas/drawimage_html_image_11.html": [ - "9b4da400d9486407b834f8f60416a11cfe68f6cf", - "reftest" - ], - "mozilla/canvas/drawimage_html_image_11_ref.html": [ - "b51c787c97490eed29787cadf62b0c5e5cbd9180", - "support" - ], - "mozilla/canvas/drawimage_html_image_12.html": [ - "a8b04a034bd5fecab74cef610b8320b8d41d5131", - "reftest" - ], - "mozilla/canvas/drawimage_html_image_12_ref.html": [ - "5529c622869289c1a64987216b525766003d5f8c", - "support" - ], - "mozilla/canvas/drawimage_html_image_13.html": [ - "9a47d53761733409f2582e13d5f1b1f9d9e9046e", - "reftest" - ], - "mozilla/canvas/drawimage_html_image_13_ref.html": [ - "30150e3530438d42704fda8b3623286658f6c724", - "support" - ], - "mozilla/canvas/drawimage_html_image_1_ref.html": [ - "9a70c803aaf5bd8a843b18d6d16779575d4dc6f8", - "support" - ], - "mozilla/canvas/drawimage_html_image_2.html": [ - "ed1d7f348d2966af1a95c75e49837a72c032b2c6", - "reftest" - ], - "mozilla/canvas/drawimage_html_image_2_ref.html": [ - "a95c84aace62371b4a58c381acaab51499cdeedb", - "support" - ], - "mozilla/canvas/drawimage_html_image_3.html": [ - "cc8ce7169bdf21905d73597931878422a1cf780c", - "reftest" - ], - "mozilla/canvas/drawimage_html_image_3_ref.html": [ - "59d699ac4347a4af4246c0333e14a91a201da15c", - "support" - ], - "mozilla/canvas/drawimage_html_image_4.html": [ - "45f850d0062a0cfe3c448420fa9e5fea88b2a90a", - "reftest" - ], - "mozilla/canvas/drawimage_html_image_4_ref.html": [ - "6204815172949961351ea34906f99d05063bc78f", - "support" - ], - "mozilla/canvas/drawimage_html_image_5.html": [ - "a023a6543b9207f86b3928859f903ca90f57e824", - "reftest" - ], - "mozilla/canvas/drawimage_html_image_5_ref.html": [ - "839c4941a71523e7b543080aae8722972b20ebbb", - "support" - ], - "mozilla/canvas/drawimage_html_image_6.html": [ - "f9509bb99560ce023f40a0b700b5950bf0a44dda", - "reftest" - ], - "mozilla/canvas/drawimage_html_image_6_ref.html": [ - "359acc11d83341062450e86162d831a9fc1ae158", - "support" - ], - "mozilla/canvas/drawimage_html_image_7.html": [ - "402c02c6aad4732f4fe31405c00a7acf24c71e10", - "reftest" - ], - "mozilla/canvas/drawimage_html_image_7_ref.html": [ - "53efd12eca32f7898ddeabdca9b2e61f952b296d", - "support" - ], - "mozilla/canvas/drawimage_html_image_8.html": [ - "17ffa3edbdb9bbf572710e1981732d299062c5ba", - "reftest" - ], - "mozilla/canvas/drawimage_html_image_8_ref.html": [ - "89f6e5589e3619835d67e8d919ab6a507fb3bbb5", - "support" - ], - "mozilla/canvas/drawimage_html_image_9.html": [ - "5f89f092758cac8462399555528d8135c6c46692", - "reftest" - ], - "mozilla/canvas/drawimage_html_image_9_ref.html": [ - "5e4587978bcf32905a2676da269a5a09d7938718", - "support" - ], "mozilla/canvas/fill_and_stroke_getters_setters.html": [ - "4ae37c115dff4361db2be1849fa5143be19df438", + "0a56ed81ad6a34c2f86fcd2296665e5e0466d4b9", "testharness" ], "mozilla/caption.html": [ diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_1.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_1.html deleted file mode 100644 index ea5be1227cf..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_1.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_10.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_10.html deleted file mode 100644 index 68363633382..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_10.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_10_ref.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_10_ref.html deleted file mode 100644 index 60545df17ff..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_10_ref.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - -
- - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_11.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_11.html deleted file mode 100644 index d21d3d925b1..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_11.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_11_ref.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_11_ref.html deleted file mode 100644 index 10d8885f2b0..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_11_ref.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - -
- - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_12.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_12.html deleted file mode 100644 index dc9c8d6bb7d..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_12.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_12_ref.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_12_ref.html deleted file mode 100644 index 5f6f22111da..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_12_ref.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - -
-
-
- - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_13.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_13.html deleted file mode 100644 index 5e663d197b2..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_13.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_13_ref.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_13_ref.html deleted file mode 100644 index 9ac306a5cc6..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_13_ref.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - -
- - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_1_ref.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_1_ref.html deleted file mode 100644 index 60545df17ff..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_1_ref.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - -
- - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_2.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_2.html deleted file mode 100644 index 9eeaae95ebb..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_2.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_2_ref.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_2_ref.html deleted file mode 100644 index c4535283500..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_2_ref.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - -
- - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_3.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_3.html deleted file mode 100644 index 63b303944ba..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_3.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_3_ref.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_3_ref.html deleted file mode 100644 index b72687a8ace..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_3_ref.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - -
- - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_4.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_4.html deleted file mode 100644 index dfaf4018d69..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_4.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_4_ref.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_4_ref.html deleted file mode 100644 index baa6591a220..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_4_ref.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - -
- -
- - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_5.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_5.html deleted file mode 100644 index a359fdf35b5..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_5.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_5_ref.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_5_ref.html deleted file mode 100644 index d8ec95525de..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_5_ref.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - -
-
- -
-
- - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_6.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_6.html deleted file mode 100644 index 4482ca3c319..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_6.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_6_ref.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_6_ref.html deleted file mode 100644 index d7343375508..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_6_ref.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - -
- - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_7.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_7.html deleted file mode 100644 index cf6daa0d4c3..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_7.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_7_ref.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_7_ref.html deleted file mode 100644 index e823ffbb75a..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_7_ref.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - -
-
-
- - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_8.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_8.html deleted file mode 100644 index c1ebfa81648..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_8.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_8_ref.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_8_ref.html deleted file mode 100644 index 1a025d26d99..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_8_ref.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - -
-
-
- - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_9.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_9.html deleted file mode 100644 index f0fc85d384a..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_9.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_9_ref.html b/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_9_ref.html deleted file mode 100644 index 5341e05c1e1..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/canvas/drawimage_html_image_9_ref.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - -
- - diff --git a/tests/wpt/mozilla/tests/mozilla/canvas/fill_and_stroke_getters_setters.html b/tests/wpt/mozilla/tests/mozilla/canvas/fill_and_stroke_getters_setters.html index 7ddaa5bfbf0..aec8c864348 100644 --- a/tests/wpt/mozilla/tests/mozilla/canvas/fill_and_stroke_getters_setters.html +++ b/tests/wpt/mozilla/tests/mozilla/canvas/fill_and_stroke_getters_setters.html @@ -16,12 +16,16 @@ function roundtrip(property, vals) { } } -var img = document.createElement('img'); -img.src = '../2x2.png'; -var pattern = ctx.createPattern(img, 'repeat'); +async_test(function(t) { + var img = document.createElement('img'); + img.src = '../2x2.png'; + img.onload = t.step_func_done(function() { + var pattern = ctx.createPattern(img, 'repeat'); -var gradient = ctx.createLinearGradient(0.0, 0.0, 1.0, 1.0); + var gradient = ctx.createLinearGradient(0.0, 0.0, 1.0, 1.0); -roundtrip('strokeStyle', ['#ff0000', gradient, pattern]); -roundtrip('fillStyle', ['#ff0000', gradient, pattern]); + roundtrip('strokeStyle', ['#ff0000', gradient, pattern]); + roundtrip('fillStyle', ['#ff0000', gradient, pattern]); + }); +}); diff --git a/tests/wpt/web-platform-tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_1.html b/tests/wpt/web-platform-tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_1.html index b9de85a9774..95b25b5adca 100644 --- a/tests/wpt/web-platform-tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_1.html +++ b/tests/wpt/web-platform-tests/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_1.html @@ -1,4 +1,5 @@ +