diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/layout/context.rs | 15 | ||||
-rw-r--r-- | components/layout/display_list_builder.rs | 3 | ||||
-rw-r--r-- | components/layout/fragment.rs | 5 | ||||
-rw-r--r-- | components/net/image_cache_task.rs | 54 | ||||
-rw-r--r-- | components/net_traits/image_cache_task.rs | 29 | ||||
-rw-r--r-- | components/script/dom/canvasrenderingcontext2d.rs | 12 | ||||
-rw-r--r-- | components/script/dom/htmlimageelement.rs | 11 | ||||
-rw-r--r-- | components/script/script_task.rs | 2 |
8 files changed, 93 insertions, 38 deletions
diff --git a/components/layout/context.rs b/components/layout/context.rs index cf909115048..393794bb57b 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -16,7 +16,8 @@ use gfx::font_cache_task::FontCacheTask; use gfx::font_context::FontContext; use msg::constellation_msg::ConstellationChan; use net_traits::image::base::Image; -use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageState}; +use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageResponse, ImageState}; +use net_traits::image_cache_task::{UsePlaceholder}; use script::layout_interface::{Animation, LayoutChan, ReflowGoal}; use std::boxed; use std::cell::Cell; @@ -158,9 +159,11 @@ impl<'a> LayoutContext<'a> { } } - pub fn get_or_request_image(&self, url: Url) -> Option<Arc<Image>> { + pub fn get_or_request_image(&self, url: Url, use_placeholder: UsePlaceholder) + -> Option<Arc<Image>> { // See if the image is already available - let result = self.shared.image_cache_task.get_image_if_available(url.clone()); + let result = self.shared.image_cache_task.get_image_if_available(url.clone(), + use_placeholder); match result { Ok(image) => Some(image), @@ -178,7 +181,11 @@ impl<'a> LayoutContext<'a> { self.shared.image_cache_task.request_image(url, ImageCacheChan(sync_tx), None); - sync_rx.recv().unwrap().image + match sync_rx.recv().unwrap().image_response { + ImageResponse::Loaded(image) | + ImageResponse::PlaceholderLoaded(image) => Some(image), + ImageResponse::None => None, + } } // Not yet requested, async mode - request image from the cache (ImageState::NotRequested, false) => { diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index fbbb46b68b9..7a0f4242ac2 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -34,6 +34,7 @@ use gfx::paint_task::{PaintLayer, THREAD_TINT_COLORS}; use msg::compositor_msg::{ScrollPolicy, LayerId}; use msg::constellation_msg::ConstellationChan; use msg::constellation_msg::Msg as ConstellationMsg; +use net_traits::image_cache_task::UsePlaceholder; use png::{self, PixelsByColorType}; use std::cmp; use std::default::Default; @@ -440,7 +441,7 @@ impl FragmentDisplayListBuilding for Fragment { clip: &ClippingRegion, image_url: &Url) { let background = style.get_background(); - let image = layout_context.get_or_request_image(image_url.clone()); + let image = layout_context.get_or_request_image(image_url.clone(), UsePlaceholder::No); if let Some(image) = image { debug!("(building display list) building background image"); diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 4a34ef23e7e..db4a8c9c54a 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -27,6 +27,7 @@ use gfx::text::glyph::CharIndex; use gfx::text::text_run::{TextRun, TextRunSlice}; use msg::constellation_msg::{ConstellationChan, Msg, PipelineId, SubpageId}; use net_traits::image::base::Image; +use net_traits::image_cache_task::UsePlaceholder; use rustc_serialize::{Encodable, Encoder}; use script_traits::UntrustedNodeAddress; use std::borrow::ToOwned; @@ -335,7 +336,9 @@ impl ImageFragmentInfo { .map(Au::from_px) } - let image = url.and_then(|url| layout_context.get_or_request_image(url)); + let image = url.and_then(|url| { + layout_context.get_or_request_image(url, UsePlaceholder::Yes) + }); ImageFragmentInfo { replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node, diff --git a/components/net/image_cache_task.rs b/components/net/image_cache_task.rs index 66636487542..7b322f85b40 100644 --- a/components/net/image_cache_task.rs +++ b/components/net/image_cache_task.rs @@ -4,7 +4,8 @@ use collections::borrow::ToOwned; use net_traits::image::base::{Image, load_from_memory}; -use net_traits::image_cache_task::{ImageState, ImageCacheTask, ImageCacheChan, ImageCacheCommand, ImageCacheResult}; +use net_traits::image_cache_task::{ImageState, ImageCacheTask, ImageCacheChan, ImageCacheCommand}; +use net_traits::image_cache_task::{ImageCacheResult, ImageResponse, UsePlaceholder}; use net_traits::load_whole_resource; use std::collections::HashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -53,13 +54,13 @@ impl PendingLoad { /// failure) are still stored here, so that they aren't /// fetched again. struct CompletedLoad { - image: Option<Arc<Image>>, + image_response: ImageResponse, } impl CompletedLoad { - fn new(image: Option<Arc<Image>>) -> CompletedLoad { + fn new(image_response: ImageResponse) -> CompletedLoad { CompletedLoad { - image: image, + image_response: image_response, } } } @@ -79,11 +80,11 @@ impl ImageListener { } } - fn notify(self, image: Option<Arc<Image>>) { + fn notify(self, image_response: ImageResponse) { let ImageCacheChan(ref sender) = self.sender; let msg = ImageCacheResult { responder: self.responder, - image: image, + image_response: image_response, }; sender.send(msg).ok(); } @@ -210,10 +211,19 @@ impl ImageCache { ImageCacheCommand::RequestImage(url, result_chan, responder) => { self.request_image(url, result_chan, responder); } - ImageCacheCommand::GetImageIfAvailable(url, consumer) => { + ImageCacheCommand::GetImageIfAvailable(url, use_placeholder, consumer) => { let result = match self.completed_loads.get(&url) { Some(completed_load) => { - completed_load.image.clone().ok_or(ImageState::LoadError) + match (completed_load.image_response.clone(), use_placeholder) { + (ImageResponse::Loaded(image), _) | + (ImageResponse::PlaceholderLoaded(image), UsePlaceholder::Yes) => { + Ok(image) + } + (ImageResponse::PlaceholderLoaded(_), UsePlaceholder::No) | + (ImageResponse::None, _) => { + Err(ImageState::LoadError) + } + } } None => { let pending_load = self.pending_loads.get(&url); @@ -255,8 +265,13 @@ impl ImageCache { }); } Err(_) => { - let placeholder_image = self.placeholder_image.clone(); - self.complete_load(msg.url, placeholder_image); + match self.placeholder_image.clone() { + Some(placeholder_image) => { + self.complete_load(msg.url, ImageResponse::PlaceholderLoaded( + placeholder_image)) + } + None => self.complete_load(msg.url, ImageResponse::None), + } } } } @@ -265,31 +280,37 @@ impl ImageCache { // Handle a message from one of the decoder worker threads fn handle_decoder(&mut self, msg: DecoderMsg) { - let image = msg.image.map(Arc::new); + let image = match msg.image { + None => ImageResponse::None, + Some(image) => ImageResponse::Loaded(Arc::new(image)), + }; self.complete_load(msg.url, image); } // Change state of a url from pending -> loaded. - fn complete_load(&mut self, url: Url, image: Option<Arc<Image>>) { + fn complete_load(&mut self, url: Url, image_response: ImageResponse) { let pending_load = self.pending_loads.remove(&url).unwrap(); - let completed_load = CompletedLoad::new(image.clone()); + let completed_load = CompletedLoad::new(image_response.clone()); self.completed_loads.insert(url, completed_load); for listener in pending_load.listeners.into_iter() { - listener.notify(image.clone()); + listener.notify(image_response.clone()); } } // Request an image from the cache - fn request_image(&mut self, url: Url, result_chan: ImageCacheChan, responder: Option<Box<ImageResponder>>) { + fn request_image(&mut self, + url: Url, + result_chan: ImageCacheChan, + responder: Option<Box<ImageResponder>>) { let image_listener = ImageListener::new(result_chan, responder); // 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.clone()); + image_listener.notify(completed_load.image_response.clone()); } None => { // Check if the load is already pending @@ -366,3 +387,4 @@ pub fn new_image_cache_task(resource_task: ResourceTask) -> ImageCacheTask { ImageCacheTask::new(cmd_sender) } + diff --git a/components/net_traits/image_cache_task.rs b/components/net_traits/image_cache_task.rs index dd6bb3c98ff..3614cf4d58a 100644 --- a/components/net_traits/image_cache_task.rs +++ b/components/net_traits/image_cache_task.rs @@ -12,7 +12,7 @@ use std::sync::mpsc::{channel, Sender}; /// image load completes. It is typically used to trigger a reflow /// and/or repaint. pub trait ImageResponder : Send { - fn respond(&self, Option<Arc<Image>>); + fn respond(&self, ImageResponse); } /// The current state of an image in the cache. @@ -23,6 +23,17 @@ pub enum ImageState { NotRequested, } +/// The returned image. +#[derive(Clone)] +pub enum ImageResponse { + /// The requested image was loaded. + Loaded(Arc<Image>), + /// The requested image failed to load, so a placeholder was loaded instead. + PlaceholderLoaded(Arc<Image>), + /// Neither the requested image nor the placeholder could be loaded. + None +} + /// Channel for sending commands to the image cache. #[derive(Clone)] pub struct ImageCacheChan(pub Sender<ImageCacheResult>); @@ -31,7 +42,7 @@ pub struct ImageCacheChan(pub Sender<ImageCacheResult>); /// caller. pub struct ImageCacheResult { pub responder: Option<Box<ImageResponder>>, - pub image: Option<Arc<Image>>, + pub image_response: ImageResponse, } /// Commands that the image cache understands. @@ -45,12 +56,18 @@ pub enum ImageCacheCommand { /// 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 task. - GetImageIfAvailable(Url, Sender<Result<Arc<Image>, ImageState>>), + GetImageIfAvailable(Url, UsePlaceholder, Sender<Result<Arc<Image>, ImageState>>), /// Clients must wait for a response before shutting down the ResourceTask Exit(Sender<()>), } +#[derive(Copy, Clone, PartialEq)] +pub enum UsePlaceholder { + No, + Yes, +} + /// The client side of the image cache task. This can be safely cloned /// and passed to different tasks. #[derive(Clone)] @@ -78,9 +95,10 @@ impl ImageCacheTask { } /// Get the current state of an image. See ImageCacheCommand::GetImageIfAvailable. - pub fn get_image_if_available(&self, url: Url) -> Result<Arc<Image>, ImageState> { + pub fn get_image_if_available(&self, url: Url, use_placeholder: UsePlaceholder) + -> Result<Arc<Image>, ImageState> { let (sender, receiver) = channel(); - let msg = ImageCacheCommand::GetImageIfAvailable(url, sender); + let msg = ImageCacheCommand::GetImageIfAvailable(url, use_placeholder, sender); self.chan.send(msg).unwrap(); receiver.recv().unwrap() } @@ -92,3 +110,4 @@ impl ImageCacheTask { response_port.recv().unwrap(); } } + diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 147c8646e2e..e27cfe74fe8 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -33,14 +33,12 @@ use canvas_traits::{FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle} use canvas_traits::{LineCapStyle, LineJoinStyle, CompositionOrBlending}; use canvas::canvas_paint_task::CanvasPaintTask; -use net_traits::image::base::Image; -use net_traits::image_cache_task::ImageCacheChan; +use net_traits::image_cache_task::{ImageCacheChan, ImageResponse}; use png::PixelsByColorType; use num::{Float, ToPrimitive}; use std::borrow::ToOwned; use std::cell::RefCell; -use std::sync::{Arc}; use std::sync::mpsc::{channel, Sender}; use util::str::DOMString; @@ -260,8 +258,8 @@ impl CanvasRenderingContext2D { }; let img = match self.request_image_from_cache(url) { - Some(img) => img, - None => return None, + ImageResponse::Loaded(img) => img, + ImageResponse::PlaceholderLoaded(_) | ImageResponse::None => return None, }; let image_size = Size2D(img.width as f64, img.height as f64); @@ -277,7 +275,7 @@ impl CanvasRenderingContext2D { return Some((image_data, image_size)); } - fn request_image_from_cache(&self, url: Url) -> Option<Arc<Image>> { + fn request_image_from_cache(&self, url: Url) -> ImageResponse { let canvas = self.canvas.root(); let window = window_from_node(canvas.r()).root(); let window = window.r(); @@ -285,7 +283,7 @@ impl CanvasRenderingContext2D { let (response_chan, response_port) = channel(); image_cache.request_image(url, ImageCacheChan(response_chan), None); let result = response_port.recv().unwrap(); - result.image + result.image_response } fn create_drawable_rect(&self, x: f64, y: f64, w: f64, h: f64) -> Option<Rect<f32>> { diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index a88f4b5ea7b..09b6c950da4 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -25,7 +25,7 @@ use util::str::DOMString; use string_cache::Atom; use net_traits::image::base::Image; -use net_traits::image_cache_task::ImageResponder; +use net_traits::image_cache_task::{ImageResponder, ImageResponse}; use url::{Url, UrlParser}; use std::borrow::ToOwned; @@ -74,11 +74,16 @@ impl Responder { } impl ImageResponder for Responder { - fn respond(&self, image: Option<Arc<Image>>) { + fn respond(&self, image: ImageResponse) { // Update the image field let element = self.element.to_temporary().root(); let element_ref = element.r(); - *element_ref.image.borrow_mut() = image; + *element_ref.image.borrow_mut() = match image { + ImageResponse::Loaded(image) | ImageResponse::PlaceholderLoaded(image) => { + Some(image) + } + ImageResponse::None => None, + }; // Mark the node dirty let node = NodeCast::from_ref(element.r()); diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 014e32f2f97..df049115e20 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -799,7 +799,7 @@ impl ScriptTask { } fn handle_msg_from_image_cache(&self, msg: ImageCacheResult) { - msg.responder.unwrap().respond(msg.image); + msg.responder.unwrap().respond(msg.image_response); } fn handle_webdriver_msg(&self, pipeline_id: PipelineId, msg: WebDriverScriptCommand) { |