aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--components/constellation/constellation.rs13
-rw-r--r--components/constellation/pipeline.rs12
-rw-r--r--components/layout/context.rs15
-rw-r--r--components/layout/display_list_builder.rs2
-rw-r--r--components/layout/fragment.rs2
-rw-r--r--components/layout_thread/lib.rs19
-rw-r--r--components/layout_traits/lib.rs5
-rw-r--r--components/net/lib.rs6
-rw-r--r--components/net_traits/Cargo.toml1
-rw-r--r--components/net_traits/image_cache.rs (renamed from components/net/image_cache_thread.rs)741
-rw-r--r--components/net_traits/image_cache_thread.rs169
-rw-r--r--components/net_traits/lib.rs3
-rw-r--r--components/script/dom/bindings/trace.rs4
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs2
-rw-r--r--components/script/dom/htmlcanvaselement.rs6
-rw-r--r--components/script/dom/htmlimageelement.rs23
-rw-r--r--components/script/dom/webglrenderingcontext.rs2
-rw-r--r--components/script/dom/window.rs20
-rw-r--r--components/script/layout_image.rs6
-rw-r--r--components/script/script_thread.rs15
-rw-r--r--components/script_layout_interface/lib.rs2
-rw-r--r--components/script_layout_interface/message.rs4
-rw-r--r--components/script_traits/lib.rs7
-rw-r--r--components/servo/lib.rs3
25 files changed, 441 insertions, 642 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ee28bed693f..4b74259ba71 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1755,6 +1755,7 @@ dependencies = [
"hyper 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper_serde 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "immeta 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs
index 0682cbe526b..109e8bfd59e 100644
--- a/components/constellation/constellation.rs
+++ b/components/constellation/constellation.rs
@@ -87,7 +87,6 @@ use msg::constellation_msg::{FrameId, FrameType, PipelineId};
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
use net_traits::{self, IpcSend, ResourceThreads};
-use net_traits::image_cache_thread::ImageCacheThread;
use net_traits::pub_domains::reg_host;
use net_traits::storage_thread::{StorageThreadMsg, StorageType};
use offscreen_gl_context::{GLContextAttributes, GLLimits};
@@ -175,10 +174,6 @@ pub struct Constellation<Message, LTF, STF> {
/// browsing.
private_resource_threads: ResourceThreads,
- /// A channel for the constellation to send messages to the image
- /// cache thread.
- image_cache_thread: ImageCacheThread,
-
/// A channel for the constellation to send messages to the font
/// cache thread.
font_cache_thread: FontCacheThread,
@@ -302,9 +297,6 @@ pub struct InitialConstellationState {
/// A channel to the bluetooth thread.
pub bluetooth_thread: IpcSender<BluetoothRequest>,
- /// A channel to the image cache thread.
- pub image_cache_thread: ImageCacheThread,
-
/// A channel to the font cache thread.
pub font_cache_thread: FontCacheThread,
@@ -518,7 +510,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
bluetooth_thread: state.bluetooth_thread,
public_resource_threads: state.public_resource_threads,
private_resource_threads: state.private_resource_threads,
- image_cache_thread: state.image_cache_thread,
font_cache_thread: state.font_cache_thread,
swmanager_chan: None,
swmanager_receiver: swmanager_receiver,
@@ -657,7 +648,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
devtools_chan: self.devtools_chan.clone(),
bluetooth_thread: self.bluetooth_thread.clone(),
swmanager_thread: self.swmanager_sender.clone(),
- image_cache_thread: self.image_cache_thread.clone(),
font_cache_thread: self.font_cache_thread.clone(),
resource_threads: resource_threads,
time_profiler_chan: self.time_profiler_chan.clone(),
@@ -1210,9 +1200,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let (core_sender, core_receiver) = ipc::channel().expect("Failed to create IPC channel!");
let (storage_sender, storage_receiver) = ipc::channel().expect("Failed to create IPC channel!");
- debug!("Exiting image cache.");
- self.image_cache_thread.exit();
-
debug!("Exiting core resource threads.");
if let Err(e) = self.public_resource_threads.send(net_traits::CoreResourceMsg::Exit(core_sender)) {
warn!("Exit resource thread failed ({})", e);
diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs
index 877c850a3cb..637b3787775 100644
--- a/components/constellation/pipeline.rs
+++ b/components/constellation/pipeline.rs
@@ -17,7 +17,7 @@ use ipc_channel::router::ROUTER;
use layout_traits::LayoutThreadFactory;
use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespaceId};
use net_traits::{IpcSend, ResourceThreads};
-use net_traits::image_cache_thread::ImageCacheThread;
+use net_traits::image_cache::ImageCache;
use profile_traits::mem as profile_mem;
use profile_traits::time;
use script_traits::{ConstellationControlMsg, DevicePixel, DiscardBrowsingContext};
@@ -133,9 +133,6 @@ pub struct InitialPipelineState {
/// A channel to the service worker manager thread
pub swmanager_thread: IpcSender<SWManagerMsg>,
- /// A channel to the image cache thread.
- pub image_cache_thread: ImageCacheThread,
-
/// A channel to the font cache thread.
pub font_cache_thread: FontCacheThread,
@@ -250,7 +247,6 @@ impl Pipeline {
devtools_chan: script_to_devtools_chan,
bluetooth_thread: state.bluetooth_thread,
swmanager_thread: state.swmanager_thread,
- image_cache_thread: state.image_cache_thread,
font_cache_thread: state.font_cache_thread,
resource_threads: state.resource_threads,
time_profiler_chan: state.time_profiler_chan,
@@ -451,7 +447,6 @@ pub struct UnprivilegedPipelineContent {
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
bluetooth_thread: IpcSender<BluetoothRequest>,
swmanager_thread: IpcSender<SWManagerMsg>,
- image_cache_thread: ImageCacheThread,
font_cache_thread: FontCacheThread,
resource_threads: ResourceThreads,
time_profiler_chan: time::ProfilerChan,
@@ -477,6 +472,7 @@ impl UnprivilegedPipelineContent {
where LTF: LayoutThreadFactory<Message=Message>,
STF: ScriptThreadFactory<Message=Message>
{
+ let image_cache = ImageCache::new(self.webrender_api_sender.create_api());
let layout_pair = STF::create(InitialScriptState {
id: self.id,
frame_id: self.frame_id,
@@ -489,7 +485,7 @@ impl UnprivilegedPipelineContent {
scheduler_chan: self.scheduler_chan,
bluetooth_thread: self.bluetooth_thread,
resource_threads: self.resource_threads,
- image_cache_thread: self.image_cache_thread.clone(),
+ image_cache: image_cache.clone(),
time_profiler_chan: self.time_profiler_chan.clone(),
mem_profiler_chan: self.mem_profiler_chan.clone(),
devtools_chan: self.devtools_chan,
@@ -507,7 +503,7 @@ impl UnprivilegedPipelineContent {
self.pipeline_port,
self.layout_to_constellation_chan,
self.script_chan,
- self.image_cache_thread,
+ image_cache.clone(),
self.font_cache_thread,
self.time_profiler_chan,
self.mem_profiler_chan,
diff --git a/components/layout/context.rs b/components/layout/context.rs
index e2ffeb1cbd9..72be2555720 100644
--- a/components/layout/context.rs
+++ b/components/layout/context.rs
@@ -9,8 +9,8 @@ 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, CanRequestImages};
-use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
+use net_traits::image_cache::{CanRequestImages, ImageCache, ImageState};
+use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
use opaque_node::OpaqueNodeMethods;
use parking_lot::RwLock;
use script_layout_interface::{PendingImage, PendingImageState};
@@ -79,8 +79,8 @@ pub struct LayoutContext<'a> {
/// Bits shared by the layout and style system.
pub style_context: SharedStyleContext<'a>,
- /// The shared image cache thread.
- pub image_cache_thread: Mutex<ImageCacheThread>,
+ /// Reference to the script thread image cache.
+ pub image_cache: Arc<ImageCache>,
/// Interface to the font cache thread.
pub font_cache_thread: Mutex<FontCacheThread>,
@@ -126,10 +126,9 @@ impl<'a> LayoutContext<'a> {
};
// See if the image is already available
- let result = self.image_cache_thread.lock().unwrap()
- .find_image_or_metadata(url.clone(),
- use_placeholder,
- can_request);
+ let result = self.image_cache.find_image_or_metadata(url.clone(),
+ use_placeholder,
+ can_request);
match result {
Ok(image_or_metadata) => Some(image_or_metadata),
// Image failed to load, so just return nothing
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index f97c3ad63b1..f2aac544103 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -36,7 +36,7 @@ use list_item::ListItemFlow;
use model::{self, MaybeAuto};
use msg::constellation_msg::PipelineId;
use net_traits::image::base::PixelFormat;
-use net_traits::image_cache_thread::UsePlaceholder;
+use net_traits::image_cache::UsePlaceholder;
use range::Range;
use servo_config::opts;
use servo_url::ServoUrl;
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index 51976521428..cf2f892878f 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -27,7 +27,7 @@ use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, SizeC
use model::{style_length, ToGfxMatrix};
use msg::constellation_msg::PipelineId;
use net_traits::image::base::{Image, ImageMetadata};
-use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
+use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
use range::*;
use script_layout_interface::HTMLCanvasData;
use script_layout_interface::SVGSVGData;
diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs
index 2279b8f2058..629e5ff6a73 100644
--- a/components/layout_thread/lib.rs
+++ b/components/layout_thread/lib.rs
@@ -76,8 +76,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::ImageCacheThread;
-use net_traits::image_cache_thread::UsePlaceholder;
+use net_traits::image_cache::{ImageCache, UsePlaceholder};
use parking_lot::RwLock;
use profile_traits::mem::{self, Report, ReportKind, ReportsChan};
use profile_traits::time::{self, TimerMetadata, profile};
@@ -157,8 +156,8 @@ pub struct LayoutThread {
/// The channel on which messages can be sent to the memory profiler.
mem_profiler_chan: mem::ProfilerChan,
- /// The channel on which messages can be sent to the image cache.
- image_cache_thread: ImageCacheThread,
+ /// Reference to the script thread image cache.
+ image_cache: Arc<ImageCache>,
/// Public interface to the font cache thread.
font_cache_thread: FontCacheThread,
@@ -245,7 +244,7 @@ impl LayoutThreadFactory for LayoutThread {
pipeline_port: IpcReceiver<LayoutControlMsg>,
constellation_chan: IpcSender<ConstellationMsg>,
script_chan: IpcSender<ConstellationControlMsg>,
- image_cache_thread: ImageCacheThread,
+ image_cache: Arc<ImageCache>,
font_cache_thread: FontCacheThread,
time_profiler_chan: time::ProfilerChan,
mem_profiler_chan: mem::ProfilerChan,
@@ -268,7 +267,7 @@ impl LayoutThreadFactory for LayoutThread {
pipeline_port,
constellation_chan,
script_chan,
- image_cache_thread,
+ image_cache.clone(),
font_cache_thread,
time_profiler_chan,
mem_profiler_chan.clone(),
@@ -382,7 +381,7 @@ impl LayoutThread {
pipeline_port: IpcReceiver<LayoutControlMsg>,
constellation_chan: IpcSender<ConstellationMsg>,
script_chan: IpcSender<ConstellationControlMsg>,
- image_cache_thread: ImageCacheThread,
+ image_cache: Arc<ImageCache>,
font_cache_thread: FontCacheThread,
time_profiler_chan: time::ProfilerChan,
mem_profiler_chan: mem::ProfilerChan,
@@ -432,7 +431,7 @@ impl LayoutThread {
constellation_chan: constellation_chan.clone(),
time_profiler_chan: time_profiler_chan,
mem_profiler_chan: mem_profiler_chan,
- image_cache_thread: image_cache_thread,
+ image_cache: image_cache.clone(),
font_cache_thread: font_cache_thread,
first_reflow: true,
font_cache_receiver: font_cache_receiver,
@@ -522,7 +521,7 @@ impl LayoutThread {
quirks_mode: self.quirks_mode.unwrap(),
animation_only_restyle: false,
},
- image_cache_thread: Mutex::new(self.image_cache_thread.clone()),
+ image_cache: self.image_cache.clone(),
font_cache_thread: Mutex::new(self.font_cache_thread.clone()),
webrender_image_cache: self.webrender_image_cache.clone(),
pending_images: if request_images { Some(Mutex::new(vec![])) } else { None },
@@ -693,7 +692,7 @@ impl LayoutThread {
info.pipeline_port,
info.constellation_chan,
info.script_chan.clone(),
- self.image_cache_thread.clone(),
+ info.image_cache.clone(),
self.font_cache_thread.clone(),
self.time_profiler_chan.clone(),
self.mem_profiler_chan.clone(),
diff --git a/components/layout_traits/lib.rs b/components/layout_traits/lib.rs
index 632300aa61b..9d97a89a53c 100644
--- a/components/layout_traits/lib.rs
+++ b/components/layout_traits/lib.rs
@@ -21,11 +21,12 @@ extern crate webrender_traits;
use gfx::font_cache_thread::FontCacheThread;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use msg::constellation_msg::{FrameId, PipelineId};
-use net_traits::image_cache_thread::ImageCacheThread;
+use net_traits::image_cache::ImageCache;
use profile_traits::{mem, time};
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
use script_traits::LayoutMsg as ConstellationMsg;
use servo_url::ServoUrl;
+use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender};
// A static method creating a layout thread
@@ -40,7 +41,7 @@ pub trait LayoutThreadFactory {
pipeline_port: IpcReceiver<LayoutControlMsg>,
constellation_chan: IpcSender<ConstellationMsg>,
script_chan: IpcSender<ConstellationControlMsg>,
- image_cache_thread: ImageCacheThread,
+ image_cache: Arc<ImageCache>,
font_cache_thread: FontCacheThread,
time_profiler_chan: time::ProfilerChan,
mem_profiler_chan: mem::ProfilerChan,
diff --git a/components/net/lib.rs b/components/net/lib.rs
index f7724b08222..c850d1c3662 100644
--- a/components/net/lib.rs
+++ b/components/net/lib.rs
@@ -4,8 +4,6 @@
#![deny(unsafe_code)]
#![feature(box_syntax)]
-#![feature(mpsc_select)]
-#![feature(step_by)]
extern crate base64;
extern crate brotli;
@@ -14,7 +12,6 @@ extern crate devtools_traits;
extern crate flate2;
extern crate hyper;
extern crate hyper_serde;
-extern crate immeta;
extern crate ipc_channel;
#[macro_use] extern crate log;
#[macro_use] #[no_link] extern crate matches;
@@ -32,14 +29,12 @@ extern crate serde_derive;
extern crate serde_json;
extern crate servo_config;
extern crate servo_url;
-extern crate threadpool;
extern crate time;
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
extern crate tinyfiledialogs;
extern crate unicase;
extern crate url;
extern crate uuid;
-extern crate webrender_traits;
extern crate websocket;
mod blob_loader;
@@ -51,7 +46,6 @@ mod data_loader;
pub mod filemanager_thread;
pub mod hsts;
mod http_loader;
-pub mod image_cache_thread;
pub mod mime_classifier;
pub mod resource_thread;
mod storage_thread;
diff --git a/components/net_traits/Cargo.toml b/components/net_traits/Cargo.toml
index 565b3d81c6c..52fb9370079 100644
--- a/components/net_traits/Cargo.toml
+++ b/components/net_traits/Cargo.toml
@@ -16,6 +16,7 @@ heapsize_derive = "0.1"
hyper = "0.9.9"
hyper_serde = "0.5"
image = "0.12"
+immeta = "0.3.1"
ipc-channel = "0.7"
lazy_static = "0.2"
log = "0.3.5"
diff --git a/components/net/image_cache_thread.rs b/components/net_traits/image_cache.rs
index a9cdca099d7..92ca3d27373 100644
--- a/components/net/image_cache_thread.rs
+++ b/components/net_traits/image_cache.rs
@@ -2,35 +2,81 @@
* 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 NetworkError;
+use image::base::{Image, ImageMetadata, PixelFormat, load_from_memory};
use immeta::load_from_buf;
-use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
-use ipc_channel::router::ROUTER;
-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, CanRequestImages};
+use ipc_channel::ipc::IpcSender;
use servo_config::resource_files::resources_dir_path;
use servo_url::ServoUrl;
-use std::borrow::ToOwned;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::fs::File;
use std::io::{self, Read};
use std::mem;
-use std::sync::Arc;
-use std::sync::mpsc::{Receiver, Sender, channel};
+use std::sync::{Arc, Mutex};
+use std::sync::mpsc::channel;
use std::thread;
-use threadpool::ThreadPool;
use webrender_traits;
///
/// TODO(gw): Remaining work on image cache:
/// * Make use of the prefetch support in various parts of the code.
-/// * Profile time in GetImageIfAvailable - might be worth caching these results per paint / layout thread.
+/// * Profile time in GetImageIfAvailable - might be worth caching these
+/// results per paint / layout thread.
///
/// MAYBE(Yoric):
-/// * For faster lookups, it might be useful to store the LoadKey in the DOM once we have performed a first load.
+/// * For faster lookups, it might be useful to store the LoadKey in the
+/// DOM once we have performed a first load.
+
+
+// ======================================================================
+// Helper functions.
+// ======================================================================
+
+fn convert_format(format: PixelFormat) -> webrender_traits::ImageFormat {
+ match format {
+ PixelFormat::K8 | PixelFormat::KA8 => {
+ panic!("Not support by webrender yet");
+ }
+ PixelFormat::RGB8 => webrender_traits::ImageFormat::RGB8,
+ PixelFormat::RGBA8 => webrender_traits::ImageFormat::RGBA8,
+ }
+}
+
+fn decode_bytes_sync(key: LoadKey, bytes: &[u8]) -> DecoderMsg {
+ let image = load_from_memory(bytes);
+ DecoderMsg {
+ key: key,
+ image: image
+ }
+}
+
+fn get_placeholder_image(webrender_api: &webrender_traits::RenderApi) -> io::Result<Arc<Image>> {
+ let mut placeholder_path = try!(resources_dir_path());
+ placeholder_path.push("rippy.png");
+ let mut file = try!(File::open(&placeholder_path));
+ let mut image_data = vec![];
+ try!(file.read_to_end(&mut image_data));
+ let mut image = load_from_memory(&image_data).unwrap();
+ let format = convert_format(image.format);
+ let mut bytes = Vec::new();
+ bytes.extend_from_slice(&*image.bytes);
+ let descriptor = webrender_traits::ImageDescriptor {
+ width: image.width,
+ height: image.height,
+ stride: None,
+ format: format,
+ offset: 0,
+ is_opaque: is_image_opaque(format, &bytes),
+ };
+ let data = webrender_traits::ImageData::new(bytes);
+ let image_key = webrender_api.generate_image_key();
+ webrender_api.add_image(image_key, descriptor, data, None);
+ image.id = Some(image_key);
+ Ok(Arc::new(image))
+}
+
// TODO(gw): This is a port of the old is_image_opaque code from WR.
// Consider using SIMD to speed this up if it shows in profiles.
@@ -52,80 +98,24 @@ fn is_image_opaque(format: webrender_traits::ImageFormat, bytes: &[u8]) -> bool
}
}
-/// Represents an image that is either being loaded
-/// by the resource thread, or decoded by a worker thread.
-struct PendingLoad {
- // The bytes loaded so far. Reset to an empty vector once loading
- // is complete and the buffer has been transmitted to the decoder.
- bytes: ImageBytes,
-
- // Image metadata, if available.
- metadata: Option<ImageMetadata>,
-
- // Once loading is complete, the result of the operation.
- result: Option<Result<(), NetworkError>>,
- listeners: Vec<ImageResponder>,
-
- // The url being loaded. Do not forget that this may be several Mb
- // if we are loading a data: url.
- url: ServoUrl,
-}
-
-enum ImageBytes {
- InProgress(Vec<u8>),
- Complete(Arc<Vec<u8>>),
-}
-
-impl ImageBytes {
- fn extend_from_slice(&mut self, data: &[u8]) {
- match *self {
- ImageBytes::InProgress(ref mut bytes) => bytes.extend_from_slice(data),
- ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
- }
- }
+fn premultiply(data: &mut [u8]) {
+ let length = data.len();
- fn mark_complete(&mut self) -> Arc<Vec<u8>> {
- let bytes = {
- let own_bytes = match *self {
- ImageBytes::InProgress(ref mut bytes) => bytes,
- ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
- };
- mem::replace(own_bytes, vec![])
- };
- let bytes = Arc::new(bytes);
- *self = ImageBytes::Complete(bytes.clone());
- bytes
- }
+ for i in (0..length).step_by(4) {
+ let b = data[i + 0] as u32;
+ let g = data[i + 1] as u32;
+ let r = data[i + 2] as u32;
+ let a = data[i + 3] as u32;
- fn as_slice(&self) -> &[u8] {
- match *self {
- ImageBytes::InProgress(ref bytes) => &bytes,
- ImageBytes::Complete(ref bytes) => &*bytes,
- }
+ data[i + 0] = (b * a / 255) as u8;
+ data[i + 1] = (g * a / 255) as u8;
+ data[i + 2] = (r * a / 255) as u8;
}
}
-enum LoadResult {
- Loaded(Image),
- PlaceholderLoaded(Arc<Image>),
- None
-}
-
-impl PendingLoad {
- fn new(url: ServoUrl) -> PendingLoad {
- PendingLoad {
- bytes: ImageBytes::InProgress(vec!()),
- metadata: None,
- result: None,
- listeners: vec!(),
- url: url,
- }
- }
-
- fn add_listener(&mut self, listener: ImageResponder) {
- self.listeners.push(listener);
- }
-}
+// ======================================================================
+// Aux structs and enums.
+// ======================================================================
// Represents all the currently pending loads/decodings. For
// performance reasons, loads are indexed by a dedicated load key.
@@ -142,14 +132,6 @@ struct AllPendingLoads {
keygen: LoadKeyGenerator,
}
-/// 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 {
fn new() -> AllPendingLoads {
AllPendingLoads {
@@ -159,12 +141,6 @@ impl AllPendingLoads {
}
}
- // `true` if there is no currently pending load, `false` otherwise.
- fn is_empty(&self) -> bool {
- assert!(self.loads.is_empty() == self.url_to_load_key.is_empty());
- self.loads.is_empty()
- }
-
// get a PendingLoad from its LoadKey.
fn get_by_key_mut(&mut self, key: &LoadKey) -> Option<&mut PendingLoad> {
self.loads.get_mut(key)
@@ -206,6 +182,23 @@ impl AllPendingLoads {
}
}
+/// 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)>),
+}
+
+/// 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,
+}
+
/// Represents an image that has completed loading.
/// Images that fail to load (due to network or decode
/// failure) are still stored here, so that they aren't
@@ -224,272 +217,203 @@ impl CompletedLoad {
}
}
-// A key used to communicate during loading.
-type LoadKey = PendingImageId;
+/// Message that the decoder worker threads send to the image cache.
+struct DecoderMsg {
+ key: LoadKey,
+ image: Option<Image>,
+}
-struct LoadKeyGenerator {
- counter: u64
+enum ImageBytes {
+ InProgress(Vec<u8>),
+ Complete(Arc<Vec<u8>>),
}
-impl LoadKeyGenerator {
- fn new() -> LoadKeyGenerator {
- LoadKeyGenerator {
- counter: 0
+impl ImageBytes {
+ fn extend_from_slice(&mut self, data: &[u8]) {
+ match *self {
+ ImageBytes::InProgress(ref mut bytes) => bytes.extend_from_slice(data),
+ ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
}
}
- fn next(&mut self) -> PendingImageId {
- self.counter += 1;
- PendingImageId(self.counter)
+
+ fn mark_complete(&mut self) -> Arc<Vec<u8>> {
+ let bytes = {
+ let own_bytes = match *self {
+ ImageBytes::InProgress(ref mut bytes) => bytes,
+ ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
+ };
+ mem::replace(own_bytes, vec![])
+ };
+ let bytes = Arc::new(bytes);
+ *self = ImageBytes::Complete(bytes.clone());
+ bytes
}
-}
-struct ResourceLoadInfo {
- action: FetchResponseMsg,
- key: LoadKey,
+ fn as_slice(&self) -> &[u8] {
+ match *self {
+ ImageBytes::InProgress(ref bytes) => &bytes,
+ ImageBytes::Complete(ref bytes) => &*bytes,
+ }
+ }
}
-/// Implementation of the image cache
-struct ImageCache {
- decoder_sender: Sender<DecoderMsg>,
-
- // Worker threads for decoding images.
- thread_pool: ThreadPool,
-
- // Images that are loading over network, or decoding.
- pending_loads: AllPendingLoads,
+/// Indicating either entire image or just metadata availability
+#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
+pub enum ImageOrMetadataAvailable {
+ ImageAvailable(Arc<Image>),
+ MetadataAvailable(ImageMetadata),
+}
- // Images that have finished loading (successful or not)
- completed_loads: HashMap<ServoUrl, CompletedLoad>,
+/// This is optionally passed to the image cache when requesting
+/// and image, and returned to the specified event loop when the
+/// image load completes. It is typically used to trigger a reflow
+/// and/or repaint.
+#[derive(Clone, Deserialize, Serialize)]
+pub struct ImageResponder {
+ id: PendingImageId,
+ sender: IpcSender<PendingImageResponse>,
+}
- // The placeholder image used when an image fails to load
- placeholder_image: Option<Arc<Image>>,
+impl ImageResponder {
+ pub fn new(sender: IpcSender<PendingImageResponse>, id: PendingImageId) -> ImageResponder {
+ ImageResponder {
+ sender: sender,
+ id: id,
+ }
+ }
- // Webrender API instance.
- webrender_api: webrender_traits::RenderApi,
+ pub fn respond(&self, response: ImageResponse) {
+ debug!("Notifying listener");
+ // 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,
+ });
+ }
}
-/// Message that the decoder worker threads send to main image cache thread.
-struct DecoderMsg {
- key: LoadKey,
- image: Option<Image>,
+/// The returned image.
+#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
+pub enum ImageResponse {
+ /// The requested image was loaded.
+ Loaded(Arc<Image>),
+ /// The request image metadata was loaded.
+ MetadataLoaded(ImageMetadata),
+ /// 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,
}
-struct Receivers {
- cmd_receiver: Receiver<ImageCacheCommand>,
- decoder_receiver: Receiver<DecoderMsg>,
+/// The current state of an image in the cache.
+#[derive(PartialEq, Copy, Clone, Deserialize, Serialize)]
+pub enum ImageState {
+ Pending(PendingImageId),
+ LoadError,
+ NotRequested(PendingImageId),
}
-impl Receivers {
- #[allow(unsafe_code)]
- fn recv(&self) -> SelectResult {
- let cmd_receiver = &self.cmd_receiver;
- let decoder_receiver = &self.decoder_receiver;
- select! {
- msg = cmd_receiver.recv() => {
- SelectResult::Command(msg.unwrap())
- },
- msg = decoder_receiver.recv() => {
- SelectResult::Decoder(msg.unwrap())
- }
- }
- }
-}
+// A key used to communicate during loading.
+type LoadKey = PendingImageId;
-/// The types of messages that the main image cache thread receives.
-enum SelectResult {
- Command(ImageCacheCommand),
- Decoder(DecoderMsg),
+struct LoadKeyGenerator {
+ counter: u64
}
-fn convert_format(format: PixelFormat) -> webrender_traits::ImageFormat {
- match format {
- PixelFormat::K8 | PixelFormat::KA8 => {
- panic!("Not support by webrender yet");
+impl LoadKeyGenerator {
+ fn new() -> LoadKeyGenerator {
+ LoadKeyGenerator {
+ counter: 0
}
- PixelFormat::RGB8 => webrender_traits::ImageFormat::RGB8,
- PixelFormat::RGBA8 => webrender_traits::ImageFormat::RGBA8,
+ }
+ fn next(&mut self) -> PendingImageId {
+ self.counter += 1;
+ PendingImageId(self.counter)
}
}
-fn get_placeholder_image(webrender_api: &webrender_traits::RenderApi) -> io::Result<Arc<Image>> {
- let mut placeholder_path = try!(resources_dir_path());
- placeholder_path.push("rippy.png");
- let mut file = try!(File::open(&placeholder_path));
- let mut image_data = vec![];
- try!(file.read_to_end(&mut image_data));
- let mut image = load_from_memory(&image_data).unwrap();
- let format = convert_format(image.format);
- let mut bytes = Vec::new();
- bytes.extend_from_slice(&*image.bytes);
- let descriptor = webrender_traits::ImageDescriptor {
- width: image.width,
- height: image.height,
- stride: None,
- format: format,
- offset: 0,
- is_opaque: is_image_opaque(format, &bytes),
- };
- let data = webrender_traits::ImageData::new(bytes);
- let image_key = webrender_api.generate_image_key();
- webrender_api.add_image(image_key, descriptor, data, None);
- image.id = Some(image_key);
- Ok(Arc::new(image))
+enum LoadResult {
+ Loaded(Image),
+ PlaceholderLoaded(Arc<Image>),
+ None
}
-fn premultiply(data: &mut [u8]) {
- let length = data.len();
+/// 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);
- for i in (0..length).step_by(4) {
- let b = data[i + 0] as u32;
- let g = data[i + 1] as u32;
- let r = data[i + 2] as u32;
- let a = data[i + 3] as u32;
-
- data[i + 0] = (b * a / 255) as u8;
- data[i + 1] = (g * a / 255) as u8;
- data[i + 2] = (r * a / 255) as u8;
- }
+#[derive(Deserialize, Serialize)]
+pub struct PendingImageResponse {
+ pub response: ImageResponse,
+ pub id: PendingImageId,
}
-impl ImageCache {
- fn run(webrender_api: webrender_traits::RenderApi,
- ipc_command_receiver: IpcReceiver<ImageCacheCommand>) {
- // Preload the placeholder image, used when images fail to load.
- let placeholder_image = get_placeholder_image(&webrender_api).ok();
-
- // Ask the router to proxy messages received over IPC to us.
- let cmd_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_command_receiver);
-
- let (decoder_sender, decoder_receiver) = channel();
- let mut cache = ImageCache {
- decoder_sender: decoder_sender,
- thread_pool: ThreadPool::new(4),
- pending_loads: AllPendingLoads::new(),
- completed_loads: HashMap::new(),
- placeholder_image: placeholder_image,
- webrender_api: webrender_api,
- };
+/// Represents an image that is either being loaded
+/// by the resource thread, or decoded by a worker thread.
+struct PendingLoad {
+ // The bytes loaded so far. Reset to an empty vector once loading
+ // is complete and the buffer has been transmitted to the decoder.
+ bytes: ImageBytes,
- let receivers = Receivers {
- cmd_receiver: cmd_receiver,
- decoder_receiver: decoder_receiver,
- };
+ // Image metadata, if available.
+ metadata: Option<ImageMetadata>,
- let mut exit_sender: Option<IpcSender<()>> = None;
+ // Once loading is complete, the result of the operation.
+ result: Option<Result<(), NetworkError>>,
+ listeners: Vec<ImageResponder>,
- loop {
- match receivers.recv() {
- SelectResult::Command(cmd) => {
- exit_sender = cache.handle_cmd(cmd);
- }
- SelectResult::Decoder(msg) => {
- cache.handle_decoder(msg);
- }
- }
+ // The url being loaded. Do not forget that this may be several Mb
+ // if we are loading a data: url.
+ url: ServoUrl,
+}
- // Can only exit when all pending loads are complete.
- if let Some(ref exit_sender) = exit_sender {
- if cache.pending_loads.is_empty() {
- exit_sender.send(()).unwrap();
- break;
- }
- }
+impl PendingLoad {
+ fn new(url: ServoUrl) -> PendingLoad {
+ PendingLoad {
+ bytes: ImageBytes::InProgress(vec!()),
+ metadata: None,
+ result: None,
+ listeners: vec!(),
+ url: url,
}
}
- // Handle a request from a client
- fn handle_cmd(&mut self, cmd: ImageCacheCommand) -> Option<IpcSender<()>> {
- match cmd {
- ImageCacheCommand::Exit(sender) => {
- return Some(sender);
- }
- ImageCacheCommand::AddListener(id, responder) => {
- self.add_listener(id, responder);
- }
- 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, data) => {
- self.handle_progress(ResourceLoadInfo {
- action: data,
- key: id
- });
- }
- };
-
- None
+ fn add_listener(&mut self, listener: ImageResponder) {
+ self.listeners.push(listener);
}
+}
- // Handle progress messages from the resource thread
- fn handle_progress(&mut self, msg: ResourceLoadInfo) {
- match (msg.action, msg.key) {
- (FetchResponseMsg::ProcessRequestBody, _) |
- (FetchResponseMsg::ProcessRequestEOF, _) => return,
- (FetchResponseMsg::ProcessResponse(_response), _) => {}
- (FetchResponseMsg::ProcessResponseChunk(data), _) => {
- debug!("got some data for {:?}", msg.key);
- let pending_load = self.pending_loads.get_by_key_mut(&msg.key).unwrap();
- pending_load.bytes.extend_from_slice(&data);
- //jmr0 TODO: possibly move to another task?
- if let None = pending_load.metadata {
- if let Ok(metadata) = load_from_buf(&pending_load.bytes.as_slice()) {
- let dimensions = metadata.dimensions();
- let img_metadata = ImageMetadata { width: dimensions.width,
- height: dimensions.height };
- for listener in &pending_load.listeners {
- listener.respond(ImageResponse::MetadataLoaded(img_metadata.clone()));
- }
- pending_load.metadata = Some(img_metadata);
- }
- }
- }
- (FetchResponseMsg::ProcessResponseEOF(result), key) => {
- debug!("received EOF for {:?}", key);
- match result {
- Ok(()) => {
- let pending_load = self.pending_loads.get_by_key_mut(&msg.key).unwrap();
- pending_load.result = Some(result);
- let bytes = pending_load.bytes.mark_complete();
- let sender = self.decoder_sender.clone();
- debug!("async decoding {} ({:?})", pending_load.url, key);
+#[derive(Copy, Clone, PartialEq, Hash, Eq, Deserialize, Serialize)]
+pub enum UsePlaceholder {
+ No,
+ Yes,
+}
- self.thread_pool.execute(move || {
- let msg = decode_bytes_sync(key, &*bytes);
- sender.send(msg).unwrap();
- });
- }
- Err(_) => {
- debug!("processing error for {:?}", key);
- match self.placeholder_image.clone() {
- Some(placeholder_image) => {
- self.complete_load(msg.key, LoadResult::PlaceholderLoaded(
- placeholder_image))
- }
- None => self.complete_load(msg.key, LoadResult::None),
- }
- }
- }
- }
- }
- }
+// ======================================================================
+// ImageCache implementation.
+// ======================================================================
- // Handle a message from one of the decoder worker threads
- fn handle_decoder(&mut self, msg: DecoderMsg) {
- let image = match msg.image {
- None => LoadResult::None,
- Some(image) => LoadResult::Loaded(image),
- };
- self.complete_load(msg.key, image);
- }
+pub struct ImageCache {
+ // Images that are loading over network, or decoding.
+ pending_loads: Mutex<AllPendingLoads>,
+
+ // Images that have finished loading (successful or not)
+ completed_loads: Mutex<HashMap<ServoUrl, CompletedLoad>>,
+
+ // The placeholder image used when an image fails to load
+ placeholder_image: Option<Arc<Image>>,
+ // Webrender API instance.
+ webrender_api: Mutex<webrender_traits::RenderApi>,
+}
+
+impl ImageCache {
// Change state of a url from pending -> loaded.
- fn complete_load(&mut self, key: LoadKey, mut load_result: LoadResult) {
- let pending_load = match self.pending_loads.remove(&key) {
+ fn complete_load(&self, key: LoadKey, mut load_result: LoadResult) {
+ let mut pending_loads = self.pending_loads.lock().unwrap();
+ let pending_load = match pending_loads.remove(&key) {
Some(load) => load,
None => return,
};
@@ -511,8 +435,9 @@ impl ImageCache {
is_opaque: is_image_opaque(format, &bytes),
};
let data = webrender_traits::ImageData::new(bytes);
- let image_key = self.webrender_api.generate_image_key();
- self.webrender_api.add_image(image_key, descriptor, data, None);
+ let webrender_api = self.webrender_api.lock().unwrap();
+ let image_key = webrender_api.generate_image_key();
+ webrender_api.add_image(image_key, descriptor, data, None);
image.id = Some(image_key);
}
LoadResult::PlaceholderLoaded(..) | LoadResult::None => {}
@@ -525,39 +450,20 @@ impl ImageCache {
};
let completed_load = CompletedLoad::new(image_response.clone(), key);
- self.completed_loads.insert(pending_load.url.into(), completed_load);
+ self.completed_loads.lock().unwrap().insert(pending_load.url.into(), completed_load);
for listener in pending_load.listeners {
listener.respond(image_response.clone());
}
}
- /// 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);
- }
-
/// Return a completed image if it exists, or None if there is no complete load
/// or the complete load is not fully decoded or is unavailable.
fn get_completed_image_if_available(&self,
url: &ServoUrl,
placeholder: UsePlaceholder)
-> Option<Result<ImageOrMetadataAvailable, ImageState>> {
- self.completed_loads.get(url).map(|completed_load| {
+ self.completed_loads.lock().unwrap().get(url).map(|completed_load| {
match (&completed_load.image_response, placeholder) {
(&ImageResponse::Loaded(ref image), _) |
(&ImageResponse::PlaceholderLoaded(ref image), UsePlaceholder::Yes) => {
@@ -572,29 +478,53 @@ impl ImageCache {
})
}
- /// Return any available metadata or image for the given URL, or an indication that
- /// the image is not yet available if it is in progress, or else reserve a slot in
- /// the cache for the URL if the consumer can request images.
- fn get_image_or_meta_if_available(&mut self,
- url: ServoUrl,
- placeholder: UsePlaceholder,
- can_request: CanRequestImages)
- -> Result<ImageOrMetadataAvailable, ImageState> {
- if let Some(result) = self.get_completed_image_if_available(&url, placeholder) {
+ /// Handle a message from one of the decoder worker threads or from a sync
+ /// decoding operation.
+ fn handle_decoder(&self, msg: DecoderMsg) {
+ let image = match msg.image {
+ None => LoadResult::None,
+ Some(image) => LoadResult::Loaded(image),
+ };
+ self.complete_load(msg.key, image);
+ }
+
+ // Public API
+
+ pub fn new(webrender_api: webrender_traits::RenderApi) -> Arc<ImageCache> {
+ debug!("New image cache");
+ Arc::new(ImageCache {
+ pending_loads: Mutex::new(AllPendingLoads::new()),
+ completed_loads: Mutex::new(HashMap::new()),
+ placeholder_image: get_placeholder_image(&webrender_api).ok(),
+ webrender_api: Mutex::new(webrender_api),
+ })
+ }
+
+ /// Return any available metadata or image for the given URL,
+ /// or an indication that the image is not yet available if it is in progress,
+ /// or else reserve a slot in the cache for the URL if the consumer can request images.
+ pub fn find_image_or_metadata(&self,
+ url: ServoUrl,
+ use_placeholder: UsePlaceholder,
+ can_request: CanRequestImages)
+ -> Result<ImageOrMetadataAvailable, ImageState> {
+ debug!("Find image or metadata for {}", url);
+ if let Some(result) = self.get_completed_image_if_available(&url, use_placeholder) {
debug!("{} is available", url);
return result;
}
let decoded = {
- let result = self.pending_loads.get_cached(url.clone(), can_request);
+ let mut pending_loads = self.pending_loads.lock().unwrap();
+ let result = pending_loads.get_cached(url.clone(), can_request);
match result {
CacheResult::Hit(key, pl) => match (&pl.result, &pl.metadata) {
(&Some(Ok(_)), _) => {
- debug!("sync decoding {} ({:?})", url, key);
+ debug!("Sync decoding {} ({:?})", url, key);
decode_bytes_sync(key, &pl.bytes.as_slice())
}
(&None, &Some(ref meta)) => {
- debug!("metadata available for {} ({:?})", url, key);
+ debug!("Metadata available for {} ({:?})", url, key);
return Ok(ImageOrMetadataAvailable::MetadataAvailable(meta.clone()))
}
(&Some(Err(_)), _) | (&None, &None) => {
@@ -603,43 +533,104 @@ impl ImageCache {
}
},
CacheResult::Miss(Some((key, _pl))) => {
- debug!("should be requesting {} ({:?})", url, key);
+ debug!("Should be requesting {} ({:?})", url, key);
return Err(ImageState::NotRequested(key));
}
CacheResult::Miss(None) => {
- debug!("couldn't find an entry for {}", url);
+ debug!("Couldn't find an entry for {}", url);
return Err(ImageState::LoadError);
}
}
};
- // In the case where a decode is ongoing (or waiting in a queue) but we have the
- // full response available, we decode the bytes synchronously and ignore the
- // async decode when it finishes later.
+ // In the case where a decode is ongoing (or waiting in a queue) but we
+ // have the full response available, we decode the bytes synchronously
+ // and ignore the async decode when it finishes later.
// TODO: make this behaviour configurable according to the caller's needs.
self.handle_decoder(decoded);
- match self.get_completed_image_if_available(&url, placeholder) {
+ match self.get_completed_image_if_available(&url, use_placeholder) {
Some(result) => result,
None => Err(ImageState::LoadError),
}
}
-}
-
-/// Create a new image cache.
-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(webrender_api, ipc_command_receiver)
- }).expect("Thread spawning failed");
+ /// 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, listener: ImageResponder) {
+ if let Some(load) = self.pending_loads.lock().unwrap().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.lock().unwrap().values().find(|l| l.id == id) {
+ listener.respond(load.image_response.clone());
+ return;
+ }
+ warn!("Couldn't find cached entry for listener {:?}", id);
+ }
- ImageCacheThread::new(ipc_command_sender)
-}
+ /// Inform the image cache about a response for a pending request.
+ pub fn notify_pending_response(&self, id: PendingImageId, action: FetchResponseMsg) {
+ match (action, id) {
+ (FetchResponseMsg::ProcessRequestBody, _) |
+ (FetchResponseMsg::ProcessRequestEOF, _) => return,
+ (FetchResponseMsg::ProcessResponse(_response), _) => {}
+ (FetchResponseMsg::ProcessResponseChunk(data), _) => {
+ debug!("Got some data for {:?}", id);
+ let mut pending_loads = self.pending_loads.lock().unwrap();
+ let pending_load = pending_loads.get_by_key_mut(&id).unwrap();
+ pending_load.bytes.extend_from_slice(&data);
+ //jmr0 TODO: possibly move to another task?
+ if let None = pending_load.metadata {
+ if let Ok(metadata) = load_from_buf(&pending_load.bytes.as_slice()) {
+ let dimensions = metadata.dimensions();
+ let img_metadata = ImageMetadata { width: dimensions.width,
+ height: dimensions.height };
+ for listener in &pending_load.listeners {
+ listener.respond(ImageResponse::MetadataLoaded(img_metadata.clone()));
+ }
+ pending_load.metadata = Some(img_metadata);
+ }
+ }
+ }
+ (FetchResponseMsg::ProcessResponseEOF(result), key) => {
+ debug!("Received EOF for {:?}", key);
+ match result {
+ Ok(()) => {
+ let bytes = {
+ let mut pending_loads = self.pending_loads.lock().unwrap();
+ let pending_load = pending_loads.get_by_key_mut(&id).unwrap();
+ pending_load.result = Some(result);
+ debug!("Async decoding {} ({:?})", pending_load.url, key);
+ pending_load.bytes.mark_complete()
+ };
+
+ let (tx, rx) = channel();
+ thread::Builder::new().name(
+ "Image decoding async operation".to_owned()).spawn(move || {
+ let msg = decode_bytes_sync(key, &*bytes);
+ tx.send(msg).unwrap();
+ }).expect("Thread spawning failed");
-fn decode_bytes_sync(key: LoadKey, bytes: &[u8]) -> DecoderMsg {
- let image = load_from_memory(bytes);
- DecoderMsg {
- key: key,
- image: image
+ if let Some(msg) = rx.recv().ok() {
+ debug!("Image decoded {:?}", key);
+ self.handle_decoder(msg);
+ };
+ }
+ Err(_) => {
+ debug!("Processing error for {:?}", key);
+ match self.placeholder_image.clone() {
+ Some(placeholder_image) => {
+ self.complete_load(id, LoadResult::PlaceholderLoaded(
+ placeholder_image))
+ }
+ None => self.complete_load(id, LoadResult::None),
+ }
+ }
+ }
+ }
+ }
}
}
diff --git a/components/net_traits/image_cache_thread.rs b/components/net_traits/image_cache_thread.rs
deleted file mode 100644
index 49bd1ea1c8f..00000000000
--- a/components/net_traits/image_cache_thread.rs
+++ /dev/null
@@ -1,169 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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;
-use std::sync::Arc;
-
-/// This is optionally passed to the image cache when requesting
-/// and image, and returned to the specified event loop when the
-/// image load completes. It is typically used to trigger a reflow
-/// and/or repaint.
-#[derive(Clone, Deserialize, Serialize)]
-pub struct ImageResponder {
- id: PendingImageId,
- sender: IpcSender<PendingImageResponse>,
-}
-
-#[derive(Deserialize, Serialize)]
-pub struct PendingImageResponse {
- pub response: ImageResponse,
- pub id: PendingImageId,
-}
-
-impl ImageResponder {
- pub fn new(sender: IpcSender<PendingImageResponse>, id: PendingImageId) -> ImageResponder {
- ImageResponder {
- sender: sender,
- id: id,
- }
- }
-
- pub fn respond(&self, response: ImageResponse) {
- // 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(PendingImageId),
- LoadError,
- NotRequested(PendingImageId),
-}
-
-/// The returned image.
-#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
-pub enum ImageResponse {
- /// The requested image was loaded.
- Loaded(Arc<Image>),
- /// The request image metadata was loaded.
- MetadataLoaded(ImageMetadata),
- /// 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,
-}
-
-/// Indicating either entire image or just metadata availability
-#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
-pub enum ImageOrMetadataAvailable {
- ImageAvailable(Arc<Image>),
- MetadataAvailable(ImageMetadata),
-}
-
-/// Commands that the image cache understands.
-#[derive(Deserialize, Serialize)]
-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,
- CanRequestImages,
- 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(PendingImageId, FetchResponseMsg),
-
- /// Clients must wait for a response before shutting down the ResourceThread
- Exit(IpcSender<()>),
-}
-
-#[derive(Copy, Clone, PartialEq, Hash, Eq, Deserialize, Serialize)]
-pub enum UsePlaceholder {
- No,
- 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)]
-pub struct ImageCacheThread {
- chan: IpcSender<ImageCacheCommand>,
-}
-
-/// The public API for the image cache thread.
-impl ImageCacheThread {
- /// Construct a new image cache
- pub fn new(chan: IpcSender<ImageCacheCommand>) -> ImageCacheThread {
- ImageCacheThread {
- chan: chan,
- }
- }
-
- /// Get the current state of an image, returning its metadata if available.
- /// See ImageCacheCommand::GetImageOrMetadataIfAvailable.
- ///
- /// FIXME: We shouldn't do IPC for data uris!
- pub fn find_image_or_metadata(&self,
- url: ServoUrl,
- use_placeholder: UsePlaceholder,
- can_request: CanRequestImages)
- -> Result<ImageOrMetadataAvailable, ImageState> {
- let (sender, receiver) = ipc::channel().unwrap();
- let msg = ImageCacheCommand::GetImageOrMetadataIfAvailable(url,
- use_placeholder,
- can_request,
- sender);
- let _ = self.chan.send(msg);
- try!(receiver.recv().map_err(|_| ImageState::LoadError))
- }
-
- /// 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");
- }
-
- /// 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");
- }
-
- /// 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/net_traits/lib.rs b/components/net_traits/lib.rs
index f11f2e2a28a..bc4c8938e76 100644
--- a/components/net_traits/lib.rs
+++ b/components/net_traits/lib.rs
@@ -15,6 +15,7 @@ extern crate heapsize_derive;
extern crate hyper;
extern crate hyper_serde;
extern crate image as piston_image;
+extern crate immeta;
extern crate ipc_channel;
#[macro_use]
extern crate lazy_static;
@@ -50,7 +51,7 @@ use storage_thread::StorageThreadMsg;
pub mod blob_url_store;
pub mod filemanager_thread;
pub mod hosts;
-pub mod image_cache_thread;
+pub mod image_cache;
pub mod net_error_list;
pub mod pub_domains;
pub mod request;
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index ee90766b1e2..25e738a0d1c 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::{ImageCacheThread, PendingImageId};
+use net_traits::image_cache::{ImageCache, PendingImageId};
use net_traits::request::{Request, RequestInit};
use net_traits::response::{Response, ResponseBody};
use net_traits::response::HttpsState;
@@ -321,7 +321,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, ImageCacheThread, PendingImageId);
+unsafe_no_jsmanaged_fields!(Image, ImageMetadata, ImageCache, 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 07338d8b731..432dbe800aa 100644
--- a/components/script/dom/canvasrenderingcontext2d.rs
+++ b/components/script/dom/canvasrenderingcontext2d.rs
@@ -40,7 +40,7 @@ use euclid::rect::Rect;
use euclid::size::Size2D;
use ipc_channel::ipc::{self, IpcSender};
use net_traits::image::base::PixelFormat;
-use net_traits::image_cache_thread::ImageResponse;
+use net_traits::image_cache::ImageResponse;
use num_traits::ToPrimitive;
use script_traits::ScriptMsg as ConstellationMsg;
use servo_url::ServoUrl;
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index ed8aca71c1d..dad4ebcc207 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -338,12 +338,12 @@ impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes {
pub mod utils {
use dom::window::Window;
- use net_traits::image_cache_thread::{ImageResponse, UsePlaceholder, ImageOrMetadataAvailable};
- use net_traits::image_cache_thread::CanRequestImages;
+ use net_traits::image_cache::{ImageResponse, UsePlaceholder, ImageOrMetadataAvailable};
+ use net_traits::image_cache::CanRequestImages;
use servo_url::ServoUrl;
pub fn request_image_from_cache(window: &Window, url: ServoUrl) -> ImageResponse {
- let image_cache = window.image_cache_thread();
+ let image_cache = window.image_cache();
let response =
image_cache.find_image_or_metadata(url.into(),
UsePlaceholder::No,
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index 610b0a3fae0..83691c174d2 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -40,9 +40,9 @@ use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
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::image_cache::{ImageResponder, ImageResponse, PendingImageId, ImageState};
+use net_traits::image_cache::{UsePlaceholder, ImageOrMetadataAvailable, CanRequestImages};
+use net_traits::image_cache::ImageCache;
use net_traits::request::{RequestInit, Type as RequestType};
use network_listener::{NetworkListener, PreInvoke};
use num_traits::ToPrimitive;
@@ -120,8 +120,8 @@ impl Runnable for ImageResponseHandlerRunnable {
/// The context required for asynchronously loading an external image.
struct ImageContext {
- /// A handle with which to communicate with the image cache.
- image_cache: ImageCacheThread,
+ /// Reference to the script thread image cache.
+ image_cache: Arc<ImageCache>,
/// Indicates whether the request failed, and why
status: Result<(), NetworkError>,
/// The cache ID for this request.
@@ -186,7 +186,7 @@ impl HTMLImageElement {
Some(LoadBlocker::new(&*document, LoadType::Image(img_url.clone())));
}
- fn add_cache_listener_for_element(image_cache: &ImageCacheThread,
+ fn add_cache_listener_for_element(image_cache: Arc<ImageCache>,
id: PendingImageId,
elem: &HTMLImageElement) {
let trusted_node = Trusted::new(elem);
@@ -197,8 +197,9 @@ impl HTMLImageElement {
let wrapper = window.get_runnable_wrapper();
let generation = elem.generation.get();
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.
+ debug!("Got image {:?}", message);
+ // Return the image via a message to the script thread, which marks
+ // the element as dirty and triggers a reflow.
let runnable = ImageResponseHandlerRunnable::new(
trusted_node.clone(), message.to().unwrap(), generation);
let _ = task_source.queue_with_wrapper(box runnable, &wrapper);
@@ -208,7 +209,7 @@ impl HTMLImageElement {
}
let window = window_from_node(self);
- let image_cache = window.image_cache_thread();
+ let image_cache = window.image_cache();
let response =
image_cache.find_image_or_metadata(img_url.clone().into(),
UsePlaceholder::Yes,
@@ -223,7 +224,7 @@ impl HTMLImageElement {
}
Err(ImageState::Pending(id)) => {
- add_cache_listener_for_element(image_cache, id, self);
+ add_cache_listener_for_element(image_cache.clone(), id, self);
}
Err(ImageState::LoadError) => {
@@ -242,7 +243,7 @@ impl HTMLImageElement {
let window = window_from_node(self);
let context = Arc::new(Mutex::new(ImageContext {
- image_cache: window.image_cache_thread().clone(),
+ image_cache: window.image_cache(),
status: Ok(()),
id: id,
}));
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 5261b96d1c5..f13f7f02d9b 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -42,7 +42,7 @@ use js::jsapi::{JSContext, JSObject, Type, Rooted};
use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, UndefinedValue};
use js::typedarray::{TypedArray, TypedArrayElement, Float32, Int32};
use net_traits::image::base::PixelFormat;
-use net_traits::image_cache_thread::ImageResponse;
+use net_traits::image_cache::ImageResponse;
use offscreen_gl_context::{GLContextAttributes, GLLimits};
use script_traits::ScriptMsg as ConstellationMsg;
use std::cell::Cell;
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 9f25edc3a07..a21d09c97ec 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -62,8 +62,8 @@ use js::rust::Runtime;
use layout_image::fetch_image_for_layout;
use msg::constellation_msg::{FrameType, PipelineId};
use net_traits::{ResourceThreads, ReferrerPolicy};
-use net_traits::image_cache_thread::{ImageResponder, ImageResponse};
-use net_traits::image_cache_thread::{PendingImageResponse, ImageCacheThread, PendingImageId};
+use net_traits::image_cache::{ImageCache, ImageResponder, ImageResponse};
+use net_traits::image_cache::{PendingImageId, PendingImageResponse};
use net_traits::storage_thread::StorageType;
use num_traits::ToPrimitive;
use open;
@@ -167,8 +167,8 @@ pub struct Window {
#[ignore_heap_size_of = "task sources are hard"]
file_reading_task_source: FileReadingTaskSource,
navigator: MutNullableJS<Navigator>,
- #[ignore_heap_size_of = "channels are hard"]
- image_cache_thread: ImageCacheThread,
+ #[ignore_heap_size_of = "Arc"]
+ image_cache: Arc<ImageCache>,
#[ignore_heap_size_of = "channels are hard"]
image_cache_chan: Sender<ImageCacheMsg>,
browsing_context: MutNullableJS<BrowsingContext>,
@@ -315,8 +315,8 @@ impl Window {
(box SendableMainThreadScriptChan(tx), box rx)
}
- pub fn image_cache_thread(&self) -> &ImageCacheThread {
- &self.image_cache_thread
+ pub fn image_cache(&self) -> Arc<ImageCache> {
+ self.image_cache.clone()
}
/// This can panic if it is called after the browsing context has been discarded
@@ -1227,7 +1227,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, self.image_cache_thread.clone());
+ fetch_image_for_layout(url.clone(), &*node, id, self.image_cache.clone());
}
let mut images = self.pending_layout_images.borrow_mut();
@@ -1239,7 +1239,7 @@ impl Window {
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));
+ self.image_cache.add_listener(id, ImageResponder::new(responder, id));
nodes.push(JS::from_ref(&*node));
}
}
@@ -1703,7 +1703,7 @@ impl Window {
history_task_source: HistoryTraversalTaskSource,
file_task_source: FileReadingTaskSource,
image_cache_chan: Sender<ImageCacheMsg>,
- image_cache_thread: ImageCacheThread,
+ image_cache: Arc<ImageCache>,
resource_threads: ResourceThreads,
bluetooth_thread: IpcSender<BluetoothRequest>,
mem_profiler_chan: MemProfilerChan,
@@ -1747,8 +1747,8 @@ impl Window {
history_traversal_task_source: history_task_source,
file_reading_task_source: file_task_source,
image_cache_chan: image_cache_chan,
+ image_cache: image_cache.clone(),
navigator: Default::default(),
- image_cache_thread: image_cache_thread,
history: Default::default(),
browsing_context: Default::default(),
document: Default::default(),
diff --git a/components/script/layout_image.rs b/components/script/layout_image.rs
index d903b435c26..1d573c9b94d 100644
--- a/components/script/layout_image.rs
+++ b/components/script/layout_image.rs
@@ -12,7 +12,7 @@ use dom::node::{Node, document_from_node};
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use net_traits::{FetchResponseMsg, FetchResponseListener, FetchMetadata, NetworkError};
-use net_traits::image_cache_thread::{ImageCacheThread, PendingImageId};
+use net_traits::image_cache::{ImageCache, PendingImageId};
use net_traits::request::{Type as RequestType, RequestInit as FetchRequestInit};
use network_listener::{NetworkListener, PreInvoke};
use servo_url::ServoUrl;
@@ -20,7 +20,7 @@ use std::sync::{Arc, Mutex};
struct LayoutImageContext {
id: PendingImageId,
- cache: ImageCacheThread,
+ cache: Arc<ImageCache>,
}
impl FetchResponseListener for LayoutImageContext {
@@ -49,7 +49,7 @@ impl PreInvoke for LayoutImageContext {}
pub fn fetch_image_for_layout(url: ServoUrl,
node: &Node,
id: PendingImageId,
- cache: ImageCacheThread) {
+ cache: Arc<ImageCache>) {
let context = Arc::new(Mutex::new(LayoutImageContext {
id: id,
cache: cache,
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index ac96836d92a..4399fb32630 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::{PendingImageResponse, ImageCacheThread};
+use net_traits::image_cache::{ImageCache, PendingImageResponse};
use net_traits::request::{CredentialsMode, Destination, RequestInit};
use net_traits::storage_thread::StorageType;
use network_listener::NetworkListener;
@@ -233,7 +233,7 @@ enum MixedMessage {
FromScript(MainThreadScriptMsg),
FromDevtools(DevtoolScriptControlMsg),
FromImageCache((PipelineId, PendingImageResponse)),
- FromScheduler(TimerEvent)
+ FromScheduler(TimerEvent),
}
/// Messages used to control the script event loop
@@ -408,8 +408,8 @@ pub struct ScriptThread {
registration_map: DOMRefCell<HashMap<ServoUrl, JS<ServiceWorkerRegistration>>>,
/// A job queue for Service Workers keyed by their scope url
job_queue_map: Rc<JobQueue>,
- /// A handle to the image cache thread.
- image_cache_thread: ImageCacheThread,
+ /// Image cache for this script thread.
+ image_cache: Arc<ImageCache>,
/// A handle to the resource thread. This is an `Arc` to avoid running out of file descriptors if
/// there are many iframes.
resource_threads: ResourceThreads,
@@ -450,7 +450,6 @@ pub struct ScriptThread {
/// The channel on which the image cache can send messages to ourself.
image_cache_channel: Sender<ImageCacheMsg>,
-
/// For providing contact with the time profiler.
time_profiler_chan: time::ProfilerChan,
@@ -685,7 +684,7 @@ impl ScriptThread {
registration_map: DOMRefCell::new(HashMap::new()),
job_queue_map: Rc::new(JobQueue::new()),
- image_cache_thread: state.image_cache_thread,
+ image_cache: state.image_cache.clone(),
image_cache_channel: image_cache_channel,
image_cache_port: image_cache_port,
@@ -1267,7 +1266,7 @@ impl ScriptThread {
pipeline_port: pipeline_port,
constellation_chan: self.layout_to_constellation_chan.clone(),
script_chan: self.control_chan.clone(),
- image_cache_thread: self.image_cache_thread.clone(),
+ image_cache: self.image_cache.clone(),
content_process_shutdown_chan: content_process_shutdown_chan,
layout_threads: layout_threads,
});
@@ -1756,7 +1755,7 @@ impl ScriptThread {
HistoryTraversalTaskSource(history_sender.clone()),
self.file_reading_task_source.clone(),
self.image_cache_channel.clone(),
- self.image_cache_thread.clone(),
+ self.image_cache.clone(),
self.resource_threads.clone(),
self.bluetooth_thread.clone(),
self.mem_profiler_chan.clone(),
diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs
index 1793e06909d..674b5325e81 100644
--- a/components/script_layout_interface/lib.rs
+++ b/components/script_layout_interface/lib.rs
@@ -43,7 +43,7 @@ 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 net_traits::image_cache::PendingImageId;
use script_traits::UntrustedNodeAddress;
use servo_url::ServoUrl;
use std::sync::atomic::AtomicIsize;
diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs
index feb2b533fd2..69dfd125e12 100644
--- a/components/script_layout_interface/message.rs
+++ b/components/script_layout_interface/message.rs
@@ -9,7 +9,7 @@ use euclid::rect::Rect;
use gfx_traits::Epoch;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use msg::constellation_msg::PipelineId;
-use net_traits::image_cache_thread::ImageCacheThread;
+use net_traits::image_cache::ImageCache;
use profile_traits::mem::ReportsChan;
use rpc::LayoutRPC;
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
@@ -143,7 +143,7 @@ pub struct NewLayoutThreadInfo {
pub pipeline_port: IpcReceiver<LayoutControlMsg>,
pub constellation_chan: IpcSender<ConstellationMsg>,
pub script_chan: IpcSender<ConstellationControlMsg>,
- pub image_cache_thread: ImageCacheThread,
+ pub image_cache: Arc<ImageCache>,
pub content_process_shutdown_chan: Option<IpcSender<()>>,
pub layout_threads: usize,
}
diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs
index 96042083d39..63d3818d5b1 100644
--- a/components/script_traits/lib.rs
+++ b/components/script_traits/lib.rs
@@ -57,7 +57,7 @@ use msg::constellation_msg::{FrameId, FrameType, Key, KeyModifiers, KeyState};
use msg::constellation_msg::{PipelineId, PipelineNamespaceId, TraversalDirection};
use net_traits::{ReferrerPolicy, ResourceThreads};
use net_traits::image::base::Image;
-use net_traits::image_cache_thread::ImageCacheThread;
+use net_traits::image_cache::ImageCache;
use net_traits::response::HttpsState;
use net_traits::storage_thread::StorageType;
use profile_traits::mem;
@@ -67,6 +67,7 @@ use servo_url::ImmutableOrigin;
use servo_url::ServoUrl;
use std::collections::HashMap;
use std::fmt;
+use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender};
use style_traits::{CSSPixel, UnsafeNode};
use webdriver_msg::{LoadStatus, WebDriverScriptCommand};
@@ -483,8 +484,8 @@ pub struct InitialScriptState {
pub resource_threads: ResourceThreads,
/// A channel to the bluetooth thread.
pub bluetooth_thread: IpcSender<BluetoothRequest>,
- /// A channel to the image cache thread.
- pub image_cache_thread: ImageCacheThread,
+ /// The image cache for this script thread.
+ pub image_cache: Arc<ImageCache>,
/// A channel to the time profiler thread.
pub time_profiler_chan: profile_traits::time::ProfilerChan,
/// A channel to the memory profiler thread.
diff --git a/components/servo/lib.rs b/components/servo/lib.rs
index a493c62fdb6..e3afaada420 100644
--- a/components/servo/lib.rs
+++ b/components/servo/lib.rs
@@ -82,7 +82,6 @@ use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
use gfx::font_cache_thread::FontCacheThread;
use ipc_channel::ipc::{self, IpcSender};
use log::{Log, LogMetadata, LogRecord};
-use net::image_cache_thread::new_image_cache_thread;
use net::resource_thread::new_resource_threads;
use net_traits::IpcSend;
use profile::mem as profile_mem;
@@ -290,7 +289,6 @@ 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(webrender_api_sender.create_api());
let font_cache_thread = FontCacheThread::new(public_resource_threads.sender(),
Some(webrender_api_sender.create_api()));
@@ -301,7 +299,6 @@ fn create_constellation(user_agent: Cow<'static, str>,
debugger_chan: debugger_chan,
devtools_chan: devtools_chan,
bluetooth_thread: bluetooth_thread,
- image_cache_thread: image_cache_thread,
font_cache_thread: font_cache_thread,
public_resource_threads: public_resource_threads,
private_resource_threads: private_resource_threads,