From 0d2ec852ac63f3513394df7937bddb72daed8005 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 5 Jan 2017 21:57:20 -0500 Subject: [PATCH] Send response for image requests progressively to image cache. --- components/net/image_cache_thread.rs | 24 +++------- components/net_traits/image_cache_thread.rs | 9 ++-- components/net_traits/lib.rs | 4 +- components/script/dom/htmlimageelement.rs | 49 ++++++++++++--------- components/script/dom/window.rs | 29 +++++++----- 5 files changed, 58 insertions(+), 57 deletions(-) diff --git a/components/net/image_cache_thread.rs b/components/net/image_cache_thread.rs index d9948514989d..798c2ba0f619 100644 --- a/components/net/image_cache_thread.rs +++ b/components/net/image_cache_thread.rs @@ -396,8 +396,11 @@ impl ImageCache { // TODO(#15501): look for opportunities to clean up cache if this send fails. let _ = consumer.send(result); } - ImageCacheCommand::StoreDecodeImage(id, image_vector) => { - self.store_decode_image(id, image_vector); + ImageCacheCommand::StoreDecodeImage(id, data) => { + self.handle_progress(ResourceLoadInfo { + action: data, + key: id + }); } }; @@ -409,7 +412,7 @@ impl ImageCache { match (msg.action, msg.key) { (FetchResponseMsg::ProcessRequestBody, _) | (FetchResponseMsg::ProcessRequestEOF, _) => return, - (FetchResponseMsg::ProcessResponse(_), _) => {} + (FetchResponseMsg::ProcessResponse(_response), _) => {} (FetchResponseMsg::ProcessResponseChunk(data), _) => { let pending_load = self.pending_loads.get_by_key_mut(&msg.key).unwrap(); pending_load.bytes.extend_from_slice(&data); @@ -581,21 +584,6 @@ impl ImageCache { None => Err(ImageState::LoadError), } } - - fn store_decode_image(&mut self, - id: PendingImageId, - loaded_bytes: Vec) { - let action = FetchResponseMsg::ProcessResponseChunk(loaded_bytes); - self.handle_progress(ResourceLoadInfo { - action: action, - key: id, - }); - let action = FetchResponseMsg::ProcessResponseEOF(Ok(())); - self.handle_progress(ResourceLoadInfo { - action: action, - key: id, - }); - } } /// Create a new image cache. diff --git a/components/net_traits/image_cache_thread.rs b/components/net_traits/image_cache_thread.rs index 481a4f551ea7..49bd1ea1c8f8 100644 --- a/components/net_traits/image_cache_thread.rs +++ b/components/net_traits/image_cache_thread.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 FetchResponseMsg; use image::base::{Image, ImageMetadata}; use ipc_channel::ipc::{self, IpcSender}; use servo_url::ServoUrl; @@ -89,7 +90,7 @@ pub enum ImageCacheCommand { /// Instruct the cache to store this data as a newly-complete network request and continue /// decoding the result into pixel data - StoreDecodeImage(PendingImageId, Vec), + StoreDecodeImage(PendingImageId, FetchResponseMsg), /// Clients must wait for a response before shutting down the ResourceThread Exit(IpcSender<()>), @@ -151,9 +152,9 @@ impl ImageCacheThread { 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); + /// Inform the image cache about a response for a pending request. + pub fn notify_pending_response(&self, id: PendingImageId, data: FetchResponseMsg) { + let msg = ImageCacheCommand::StoreDecodeImage(id, data); self.chan.send(msg).expect("Image cache thread is not available"); } diff --git a/components/net_traits/lib.rs b/components/net_traits/lib.rs index 8f1e004e8b01..d2ffee09887b 100644 --- a/components/net_traits/lib.rs +++ b/components/net_traits/lib.rs @@ -192,7 +192,7 @@ pub trait FetchTaskTarget { fn process_response_eof(&mut self, response: &Response); } -#[derive(Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] pub enum FilteredMetadata { Basic(Metadata), Cors(Metadata), @@ -200,7 +200,7 @@ pub enum FilteredMetadata { OpaqueRedirect } -#[derive(Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] pub enum FetchMetadata { Unfiltered(Metadata), Filtered { diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index f104330c741c..61eed1739943 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -36,10 +36,11 @@ 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::{FetchResponseListener, FetchMetadata, NetworkError, FetchResponseMsg}; 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, CanRequestImages}; +use net_traits::image_cache_thread::ImageCacheThread; use net_traits::request::{RequestInit, Type as RequestType}; use network_listener::{NetworkListener, PreInvoke}; use num_traits::ToPrimitive; @@ -112,8 +113,6 @@ impl Runnable for ImageRequestRunnable { let context = Arc::new(Mutex::new(ImageContext { elem: trusted_node, - data: vec!(), - metadata: None, url: this.img_url.clone(), status: Ok(()), id: this.id, @@ -200,10 +199,6 @@ impl Runnable for ImageResponseHandlerRunnable { 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 @@ -212,21 +207,31 @@ struct ImageContext { id: PendingImageId, } +impl ImageContext { + fn image_cache(&self) -> ImageCacheThread { + let elem = self.elem.root(); + window_from_node(&*elem).image_cache_thread().clone() + } +} + impl FetchResponseListener for ImageContext { fn process_request_body(&mut self) {} fn process_request_eof(&mut self) {} fn process_response(&mut self, metadata: Result) { - self.metadata = metadata.ok().map(|meta| match meta { - FetchMetadata::Unfiltered(m) => m, - FetchMetadata::Filtered { unsafe_, .. } => unsafe_ + self.image_cache().notify_pending_response( + self.id, + FetchResponseMsg::ProcessResponse(metadata.clone())); + + let metadata = metadata.ok().map(|meta| { + match meta { + FetchMetadata::Unfiltered(m) => m, + FetchMetadata::Filtered { unsafe_, .. } => unsafe_ + } }); - let status_code = self.metadata.as_ref().and_then(|m| { - match m.status { - Some((c, _)) => Some(c), - _ => None, - } + let status_code = metadata.as_ref().and_then(|m| { + m.status.as_ref().map(|&(code, _)| code) }).unwrap_or(0); self.status = match status_code { @@ -236,18 +241,20 @@ impl FetchResponseListener for ImageContext { }; } - fn process_response_chunk(&mut self, mut payload: Vec) { + fn process_response_chunk(&mut self, payload: Vec) { if self.status.is_ok() { - self.data.append(&mut payload); + self.image_cache().notify_pending_response( + self.id, + FetchResponseMsg::ProcessResponseChunk(payload)); } } - fn process_response_eof(&mut self, _response: Result<(), NetworkError>) { + 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()); + let image_cache = self.image_cache(); + image_cache.notify_pending_response(self.id, + FetchResponseMsg::ProcessResponseEOF(response)); document.finish_load(LoadType::Image(self.url.clone())); } } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index fcf6a0019c04..71dbdc8e8d4e 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -59,8 +59,8 @@ use js::jsapi::{JS_GC, JS_GetRuntime}; use js::jsval::UndefinedValue; use js::rust::Runtime; use msg::constellation_msg::{FrameType, PipelineId}; +use net_traits::{FetchResponseMsg, NetworkError}; 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}; @@ -1207,7 +1207,7 @@ impl Window { 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); + fetch_image_for_layout(url.clone(), &*node, id, self.image_cache_thread.clone()); } let mut images = self.pending_layout_images.borrow_mut(); @@ -1897,38 +1897,43 @@ impl Runnable for PostMessageHandler { struct LayoutImageContext { node: Trusted, - data: Vec, id: PendingImageId, url: ServoUrl, + cache: ImageCacheThread, } 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(&mut self, metadata: Result) { + self.cache.notify_pending_response( + self.id, + FetchResponseMsg::ProcessResponse(metadata)); + } - fn process_response_chunk(&mut self, mut payload: Vec) { - self.data.append(&mut payload); + fn process_response_chunk(&mut self, payload: Vec) { + self.cache.notify_pending_response( + self.id, + FetchResponseMsg::ProcessResponseChunk(payload)); } - fn process_response_eof(&mut self, _response: Result<(), NetworkError>) { + 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()); + self.cache.notify_pending_response(self.id, + FetchResponseMsg::ProcessResponseEOF(response)); document.finish_load(LoadType::Image(self.url.clone())); } } impl PreInvoke for LayoutImageContext {} -fn fetch_image_for_layout(url: ServoUrl, node: &Node, id: PendingImageId) { +fn fetch_image_for_layout(url: ServoUrl, node: &Node, id: PendingImageId, cache: ImageCacheThread) { let context = Arc::new(Mutex::new(LayoutImageContext { node: Trusted::new(node), - data: vec![], id: id, url: url.clone(), + cache: cache, })); let document = document_from_node(node);