servo: Merge #9892 - ImageCache cleanup (from Ms2ger:imagecache); r=jdm

Source-Repo: https://github.com/servo/servo
Source-Revision: 1330e7e58f3da6a6fa855d9d44350873ea38c2b7
This commit is contained in:
Ms2ger 2016-03-07 21:01:30 +05:01
Родитель 83f634f244
Коммит 4bdf8a7018
1 изменённых файлов: 65 добавлений и 81 удалений

Просмотреть файл

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use immeta::load_from_buf;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
use ipc_channel::router::ROUTER;
use net_traits::image::base::{Image, ImageMetadata, load_from_memory, PixelFormat};
use net_traits::image_cache_thread::ImageResponder;
@ -18,7 +18,7 @@ use std::fs::File;
use std::io::Read;
use std::mem;
use std::sync::Arc;
use std::sync::mpsc::{Receiver, Select, Sender, channel};
use std::sync::mpsc::{Sender, channel};
use url::Url;
use util::resource_files::resources_dir_path;
use util::thread::spawn_named;
@ -232,15 +232,8 @@ struct ResourceLoadInfo {
/// Implementation of the image cache
struct ImageCache {
// Receive commands from clients
cmd_receiver: Receiver<ImageCacheCommand>,
// Receive notifications from the resource thread
progress_receiver: Receiver<ResourceLoadInfo>,
progress_sender: Sender<ResourceLoadInfo>,
// Receive notifications from the decoder thread pool
decoder_receiver: Receiver<DecoderMsg>,
decoder_sender: Sender<DecoderMsg>,
// Worker threads for decoding images.
@ -286,49 +279,74 @@ fn convert_format(format: PixelFormat) -> webrender_traits::ImageFormat {
}
impl ImageCache {
fn run(&mut self) {
fn run(resource_thread: ResourceThread,
webrender_api: Option<webrender_traits::RenderApi>,
ipc_command_receiver: IpcReceiver<ImageCacheCommand>) {
// Preload the placeholder image, used when images fail to load.
let mut placeholder_path = resources_dir_path();
placeholder_path.push("rippy.png");
let mut image_data = vec![];
let result = File::open(&placeholder_path).and_then(|mut file| {
file.read_to_end(&mut image_data)
});
let placeholder_image = result.ok().map(|_| {
let mut image = load_from_memory(&image_data).unwrap();
if let Some(ref webrender_api) = webrender_api {
let format = convert_format(image.format);
let mut bytes = Vec::new();
bytes.extend_from_slice(&*image.bytes);
image.id = Some(webrender_api.add_image(image.width, image.height, format, bytes));
}
Arc::new(image)
});
// 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 (progress_sender, progress_receiver) = channel();
let (decoder_sender, decoder_receiver) = channel();
let mut cache = ImageCache {
progress_sender: progress_sender,
decoder_sender: decoder_sender,
thread_pool: ThreadPool::new(4),
pending_loads: AllPendingLoads::new(),
completed_loads: HashMap::new(),
resource_thread: resource_thread,
placeholder_image: placeholder_image,
webrender_api: webrender_api,
};
let mut exit_sender: Option<IpcSender<()>> = None;
loop {
let result = {
let sel = Select::new();
let mut cmd_handle = sel.handle(&self.cmd_receiver);
let mut progress_handle = sel.handle(&self.progress_receiver);
let mut decoder_handle = sel.handle(&self.decoder_receiver);
unsafe {
cmd_handle.add();
progress_handle.add();
decoder_handle.add();
}
let ret = sel.wait();
if ret == cmd_handle.id() {
SelectResult::Command(self.cmd_receiver.recv().unwrap())
} else if ret == decoder_handle.id() {
SelectResult::Decoder(self.decoder_receiver.recv().unwrap())
} else {
SelectResult::Progress(self.progress_receiver.recv().unwrap())
let result = select! {
msg = cmd_receiver.recv() => {
SelectResult::Command(msg.unwrap())
},
msg = decoder_receiver.recv() => {
SelectResult::Decoder(msg.unwrap())
},
msg = progress_receiver.recv() => {
SelectResult::Progress(msg.unwrap())
}
};
match result {
SelectResult::Command(cmd) => {
exit_sender = self.handle_cmd(cmd);
exit_sender = cache.handle_cmd(cmd);
}
SelectResult::Progress(msg) => {
self.handle_progress(msg);
cache.handle_progress(msg);
}
SelectResult::Decoder(msg) => {
self.handle_decoder(msg);
cache.handle_decoder(msg);
}
}
// Can only exit when all pending loads are complete.
if let Some(ref exit_sender) = exit_sender {
if self.pending_loads.is_empty() {
if cache.pending_loads.is_empty() {
exit_sender.send(()).unwrap();
break;
}
@ -536,12 +554,17 @@ impl ImageCache {
}
}
None => {
self.pending_loads.get_by_url(&url).as_ref().
map_or(Err(ImageState::NotRequested), |pl| pl.metadata.as_ref().
map_or(Err(ImageState::Pending), |meta|
Ok(ImageOrMetadataAvailable::MetadataAvailable(meta.clone()))
)
)
let pl = match self.pending_loads.get_by_url(&url) {
Some(pl) => pl,
None => return Err(ImageState::NotRequested),
};
let meta = match pl.metadata {
Some(ref meta) => meta,
None => return Err(ImageState::Pending),
};
Ok(ImageOrMetadataAvailable::MetadataAvailable(meta.clone()))
}
}
}
@ -551,48 +574,9 @@ impl ImageCache {
pub fn new_image_cache_thread(resource_thread: ResourceThread,
webrender_api: Option<webrender_traits::RenderApi>) -> ImageCacheThread {
let (ipc_command_sender, ipc_command_receiver) = ipc::channel().unwrap();
let (progress_sender, progress_receiver) = channel();
let (decoder_sender, decoder_receiver) = channel();
spawn_named("ImageCacheThread".to_owned(), move || {
// Preload the placeholder image, used when images fail to load.
let mut placeholder_path = resources_dir_path();
placeholder_path.push("rippy.png");
let mut image_data = vec![];
let result = File::open(&placeholder_path).and_then(|mut file| {
file.read_to_end(&mut image_data)
});
let placeholder_image = result.ok().map(|_| {
let mut image = load_from_memory(&image_data).unwrap();
if let Some(ref webrender_api) = webrender_api {
let format = convert_format(image.format);
let mut bytes = Vec::new();
bytes.extend_from_slice(&*image.bytes);
image.id = Some(webrender_api.add_image(image.width, image.height, format, bytes));
}
Arc::new(image)
});
// 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 mut cache = ImageCache {
cmd_receiver: cmd_receiver,
progress_sender: progress_sender,
progress_receiver: progress_receiver,
decoder_sender: decoder_sender,
decoder_receiver: decoder_receiver,
thread_pool: ThreadPool::new(4),
pending_loads: AllPendingLoads::new(),
completed_loads: HashMap::new(),
resource_thread: resource_thread,
placeholder_image: placeholder_image,
webrender_api: webrender_api,
};
cache.run();
ImageCache::run(resource_thread, webrender_api, ipc_command_receiver)
});
ImageCacheThread::new(ipc_command_sender)