Send response for image requests progressively to image cache.

This commit is contained in:
Josh Matthews 2017-01-05 21:57:20 -05:00
parent 21118f0a8a
commit 0d2ec852ac
5 changed files with 59 additions and 58 deletions

View file

@ -396,8 +396,11 @@ impl ImageCache {
// TODO(#15501): look for opportunities to clean up cache if this send fails. // TODO(#15501): look for opportunities to clean up cache if this send fails.
let _ = consumer.send(result); let _ = consumer.send(result);
} }
ImageCacheCommand::StoreDecodeImage(id, image_vector) => { ImageCacheCommand::StoreDecodeImage(id, data) => {
self.store_decode_image(id, image_vector); self.handle_progress(ResourceLoadInfo {
action: data,
key: id
});
} }
}; };
@ -409,7 +412,7 @@ impl ImageCache {
match (msg.action, msg.key) { match (msg.action, msg.key) {
(FetchResponseMsg::ProcessRequestBody, _) | (FetchResponseMsg::ProcessRequestBody, _) |
(FetchResponseMsg::ProcessRequestEOF, _) => return, (FetchResponseMsg::ProcessRequestEOF, _) => return,
(FetchResponseMsg::ProcessResponse(_), _) => {} (FetchResponseMsg::ProcessResponse(_response), _) => {}
(FetchResponseMsg::ProcessResponseChunk(data), _) => { (FetchResponseMsg::ProcessResponseChunk(data), _) => {
let pending_load = self.pending_loads.get_by_key_mut(&msg.key).unwrap(); let pending_load = self.pending_loads.get_by_key_mut(&msg.key).unwrap();
pending_load.bytes.extend_from_slice(&data); pending_load.bytes.extend_from_slice(&data);
@ -581,21 +584,6 @@ impl ImageCache {
None => Err(ImageState::LoadError), None => Err(ImageState::LoadError),
} }
} }
fn store_decode_image(&mut self,
id: PendingImageId,
loaded_bytes: Vec<u8>) {
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. /// Create a new image cache.

View file

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use FetchResponseMsg;
use image::base::{Image, ImageMetadata}; use image::base::{Image, ImageMetadata};
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use servo_url::ServoUrl; 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 /// Instruct the cache to store this data as a newly-complete network request and continue
/// decoding the result into pixel data /// decoding the result into pixel data
StoreDecodeImage(PendingImageId, Vec<u8>), StoreDecodeImage(PendingImageId, FetchResponseMsg),
/// Clients must wait for a response before shutting down the ResourceThread /// Clients must wait for a response before shutting down the ResourceThread
Exit(IpcSender<()>), Exit(IpcSender<()>),
@ -151,9 +152,9 @@ impl ImageCacheThread {
self.chan.send(msg).expect("Image cache thread is not available"); 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. /// Inform the image cache about a response for a pending request.
pub fn store_complete_image_bytes(&self, id: PendingImageId, image_data: Vec<u8>) { pub fn notify_pending_response(&self, id: PendingImageId, data: FetchResponseMsg) {
let msg = ImageCacheCommand::StoreDecodeImage(id, image_data); let msg = ImageCacheCommand::StoreDecodeImage(id, data);
self.chan.send(msg).expect("Image cache thread is not available"); self.chan.send(msg).expect("Image cache thread is not available");
} }

View file

@ -192,7 +192,7 @@ pub trait FetchTaskTarget {
fn process_response_eof(&mut self, response: &Response); fn process_response_eof(&mut self, response: &Response);
} }
#[derive(Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub enum FilteredMetadata { pub enum FilteredMetadata {
Basic(Metadata), Basic(Metadata),
Cors(Metadata), Cors(Metadata),
@ -200,7 +200,7 @@ pub enum FilteredMetadata {
OpaqueRedirect OpaqueRedirect
} }
#[derive(Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub enum FetchMetadata { pub enum FetchMetadata {
Unfiltered(Metadata), Unfiltered(Metadata),
Filtered { Filtered {

View file

@ -36,10 +36,11 @@ use euclid::point::Point2D;
use html5ever_atoms::LocalName; use html5ever_atoms::LocalName;
use ipc_channel::ipc; use ipc_channel::ipc;
use ipc_channel::router::ROUTER; 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::base::{Image, ImageMetadata};
use net_traits::image_cache_thread::{ImageResponder, ImageResponse, PendingImageId, ImageState}; 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::{UsePlaceholder, ImageOrMetadataAvailable, CanRequestImages};
use net_traits::image_cache_thread::ImageCacheThread;
use net_traits::request::{RequestInit, Type as RequestType}; use net_traits::request::{RequestInit, Type as RequestType};
use network_listener::{NetworkListener, PreInvoke}; use network_listener::{NetworkListener, PreInvoke};
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
@ -112,8 +113,6 @@ impl Runnable for ImageRequestRunnable {
let context = Arc::new(Mutex::new(ImageContext { let context = Arc::new(Mutex::new(ImageContext {
elem: trusted_node, elem: trusted_node,
data: vec!(),
metadata: None,
url: this.img_url.clone(), url: this.img_url.clone(),
status: Ok(()), status: Ok(()),
id: this.id, id: this.id,
@ -200,10 +199,6 @@ impl Runnable for ImageResponseHandlerRunnable {
struct ImageContext { struct ImageContext {
/// The element that initiated the request. /// The element that initiated the request.
elem: Trusted<HTMLImageElement>, elem: Trusted<HTMLImageElement>,
/// The response body received to date.
data: Vec<u8>,
/// The response metadata received to date.
metadata: Option<Metadata>,
/// The initial URL requested. /// The initial URL requested.
url: ServoUrl, url: ServoUrl,
/// Indicates whether the request failed, and why /// Indicates whether the request failed, and why
@ -212,21 +207,31 @@ struct ImageContext {
id: PendingImageId, 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 { impl FetchResponseListener for ImageContext {
fn process_request_body(&mut self) {} fn process_request_body(&mut self) {}
fn process_request_eof(&mut self) {} fn process_request_eof(&mut self) {}
fn process_response(&mut self, metadata: Result<FetchMetadata, NetworkError>) { fn process_response(&mut self, metadata: Result<FetchMetadata, NetworkError>) {
self.metadata = metadata.ok().map(|meta| match meta { self.image_cache().notify_pending_response(
FetchMetadata::Unfiltered(m) => m, self.id,
FetchMetadata::Filtered { unsafe_, .. } => unsafe_ 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| { let status_code = metadata.as_ref().and_then(|m| {
match m.status { m.status.as_ref().map(|&(code, _)| code)
Some((c, _)) => Some(c),
_ => None,
}
}).unwrap_or(0); }).unwrap_or(0);
self.status = match status_code { self.status = match status_code {
@ -236,18 +241,20 @@ impl FetchResponseListener for ImageContext {
}; };
} }
fn process_response_chunk(&mut self, mut payload: Vec<u8>) { fn process_response_chunk(&mut self, payload: Vec<u8>) {
if self.status.is_ok() { 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 elem = self.elem.root();
let document = document_from_node(&*elem); let document = document_from_node(&*elem);
let window = document.window(); let image_cache = self.image_cache();
let image_cache = window.image_cache_thread(); image_cache.notify_pending_response(self.id,
image_cache.store_complete_image_bytes(self.id, self.data.clone()); FetchResponseMsg::ProcessResponseEOF(response));
document.finish_load(LoadType::Image(self.url.clone())); document.finish_load(LoadType::Image(self.url.clone()));
} }
} }

View file

@ -59,8 +59,8 @@ use js::jsapi::{JS_GC, JS_GetRuntime};
use js::jsval::UndefinedValue; use js::jsval::UndefinedValue;
use js::rust::Runtime; use js::rust::Runtime;
use msg::constellation_msg::{FrameType, PipelineId}; use msg::constellation_msg::{FrameType, PipelineId};
use net_traits::{FetchResponseMsg, NetworkError};
use net_traits::{ResourceThreads, ReferrerPolicy, FetchResponseListener, FetchMetadata}; 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::{ImageResponder, ImageResponse};
use net_traits::image_cache_thread::{PendingImageResponse, ImageCacheThread, PendingImageId}; use net_traits::image_cache_thread::{PendingImageResponse, ImageCacheThread, PendingImageId};
use net_traits::request::{Type as RequestType, RequestInit as FetchRequestInit}; 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); let node = from_untrusted_node_address(js_runtime.rt(), image.node);
if let PendingImageState::Unrequested(ref url) = image.state { 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(); let mut images = self.pending_layout_images.borrow_mut();
@ -1897,38 +1897,43 @@ impl Runnable for PostMessageHandler {
struct LayoutImageContext { struct LayoutImageContext {
node: Trusted<Node>, node: Trusted<Node>,
data: Vec<u8>,
id: PendingImageId, id: PendingImageId,
url: ServoUrl, url: ServoUrl,
cache: ImageCacheThread,
} }
impl FetchResponseListener for LayoutImageContext { impl FetchResponseListener for LayoutImageContext {
fn process_request_body(&mut self) {} fn process_request_body(&mut self) {}
fn process_request_eof(&mut self) {} fn process_request_eof(&mut self) {}
fn process_response(&mut self, _metadata: Result<FetchMetadata, NetworkError>) {/*XXXjdm*/} fn process_response(&mut self, metadata: Result<FetchMetadata, NetworkError>) {
self.cache.notify_pending_response(
fn process_response_chunk(&mut self, mut payload: Vec<u8>) { self.id,
self.data.append(&mut payload); FetchResponseMsg::ProcessResponse(metadata));
} }
fn process_response_eof(&mut self, _response: Result<(), NetworkError>) { fn process_response_chunk(&mut self, payload: Vec<u8>) {
self.cache.notify_pending_response(
self.id,
FetchResponseMsg::ProcessResponseChunk(payload));
}
fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
let node = self.node.root(); let node = self.node.root();
let document = document_from_node(&*node); let document = document_from_node(&*node);
let window = document.window(); self.cache.notify_pending_response(self.id,
let image_cache = window.image_cache_thread(); FetchResponseMsg::ProcessResponseEOF(response));
image_cache.store_complete_image_bytes(self.id, self.data.clone());
document.finish_load(LoadType::Image(self.url.clone())); document.finish_load(LoadType::Image(self.url.clone()));
} }
} }
impl PreInvoke for LayoutImageContext {} 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 { let context = Arc::new(Mutex::new(LayoutImageContext {
node: Trusted::new(node), node: Trusted::new(node),
data: vec![],
id: id, id: id,
url: url.clone(), url: url.clone(),
cache: cache,
})); }));
let document = document_from_node(node); let document = document_from_node(node);