diff options
author | Josh Matthews <josh@joshmatthews.net> | 2016-11-21 18:13:40 -0500 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2017-02-22 14:19:35 -0500 |
commit | c890c9143cc1ae82e1116b8fb0c4e9eb478b8a03 (patch) | |
tree | 131dcf8dd5a2880562101497d958c02a31903183 /components/net_traits/image_cache_thread.rs | |
parent | 78e8c31a4d1890260dda83f2db85672f693c1e97 (diff) | |
download | servo-c890c9143cc1ae82e1116b8fb0c4e9eb478b8a03.tar.gz servo-c890c9143cc1ae82e1116b8fb0c4e9eb478b8a03.zip |
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.
Diffstat (limited to 'components/net_traits/image_cache_thread.rs')
-rw-r--r-- | components/net_traits/image_cache_thread.rs | 103 |
1 files changed, 40 insertions, 63 deletions
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<ImageResponse>, + id: PendingImageId, + sender: IpcSender<PendingImageResponse>, +} + +#[derive(Deserialize, Serialize)] +pub struct PendingImageResponse { + pub response: ImageResponse, + pub id: PendingImageId, } impl ImageResponder { - pub fn new(sender: IpcSender<ImageResponse>) -> ImageResponder { + pub fn new(sender: IpcSender<PendingImageResponse>, 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<ImageCacheResult>); - -/// The result of an image cache command that is returned to the -/// caller. -#[derive(Deserialize, Serialize)] -pub struct ImageCacheResult { - pub responder: Option<ImageResponder>, - 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<ImageResponder>), - - /// 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<ImageResponder>), - - /// 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<Result<Arc<Image>, 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<Result<ImageOrMetadataAvailable, ImageState>>), + /// 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<u8>), + StoreDecodeImage(PendingImageId, Vec<u8>), /// 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<ImageResponder>) { - 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<ImageResponder>) { - 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<Arc<Image>, 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<u8>) { - 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<u8>) { + 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(); |