mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Decode images in the ImageCache
This commit is contained in:
parent
61e8c5c457
commit
872a82b9f0
3 changed files with 144 additions and 14 deletions
|
@ -2,6 +2,7 @@ export Image;
|
||||||
|
|
||||||
export load;
|
export load;
|
||||||
export load_from_memory;
|
export load_from_memory;
|
||||||
|
export test_image_bin;
|
||||||
|
|
||||||
import stb_image::image::{image, load, load_from_memory};
|
import stb_image::image::{image, load, load_from_memory};
|
||||||
|
|
||||||
|
@ -9,3 +10,7 @@ import stb_image::image::{image, load, load_from_memory};
|
||||||
// reference count them.
|
// reference count them.
|
||||||
|
|
||||||
type Image = image;
|
type Image = image;
|
||||||
|
|
||||||
|
fn test_image_bin() -> ~[u8] {
|
||||||
|
#include_bin("test.jpeg")
|
||||||
|
}
|
BIN
src/servo/image/test.jpeg
Normal file
BIN
src/servo/image/test.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 86 KiB |
|
@ -3,13 +3,15 @@ export ImageResponseMsg, ImageReady, ImageNotReady;
|
||||||
export ImageCacheTask;
|
export ImageCacheTask;
|
||||||
export image_cache_task;
|
export image_cache_task;
|
||||||
|
|
||||||
import image::base::{Image, load_from_memory};
|
import image::base::{Image, load_from_memory, test_image_bin};
|
||||||
import std::net::url::url;
|
import std::net::url::url;
|
||||||
import util::url::{make_url, UrlMap, url_map};
|
import util::url::{make_url, UrlMap, url_map};
|
||||||
import comm::{chan, port};
|
import comm::{chan, port};
|
||||||
import task::spawn_listener;
|
import task::spawn_listener;
|
||||||
import resource::resource_task;
|
import resource::resource_task;
|
||||||
import resource_task::ResourceTask;
|
import resource_task::ResourceTask;
|
||||||
|
import core::arc::arc;
|
||||||
|
import clone_arc = core::arc::clone;
|
||||||
|
|
||||||
enum Msg {
|
enum Msg {
|
||||||
Prefetch(url),
|
Prefetch(url),
|
||||||
|
@ -18,7 +20,7 @@ enum Msg {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ImageResponseMsg {
|
enum ImageResponseMsg {
|
||||||
ImageReady(Image),
|
ImageReady(arc<~Image>),
|
||||||
ImageNotReady
|
ImageNotReady
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +31,8 @@ fn image_cache_task(resource_task: ResourceTask) -> ImageCacheTask {
|
||||||
ImageCache {
|
ImageCache {
|
||||||
resource_task: resource_task,
|
resource_task: resource_task,
|
||||||
from_client: from_client,
|
from_client: from_client,
|
||||||
prefetch_map: url_map()
|
prefetch_map: url_map(),
|
||||||
|
image_map: url_map()
|
||||||
}.run();
|
}.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,12 +40,13 @@ fn image_cache_task(resource_task: ResourceTask) -> ImageCacheTask {
|
||||||
struct ImageCache {
|
struct ImageCache {
|
||||||
resource_task: ResourceTask;
|
resource_task: ResourceTask;
|
||||||
from_client: port<Msg>;
|
from_client: port<Msg>;
|
||||||
prefetch_map: UrlMap<PrefetchData>;
|
prefetch_map: UrlMap<@PrefetchData>;
|
||||||
|
image_map: UrlMap<@arc<~Image>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PrefetchData {
|
struct PrefetchData {
|
||||||
response_port: @port<resource_task::ProgressMsg>;
|
response_port: port<resource_task::ProgressMsg>;
|
||||||
data: @mut ~[u8];
|
mut data: ~[u8];
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImageCache {
|
impl ImageCache {
|
||||||
|
@ -59,18 +63,53 @@ impl ImageCache {
|
||||||
let response_port = port();
|
let response_port = port();
|
||||||
self.resource_task.send(resource_task::Load(url, response_port.chan()));
|
self.resource_task.send(resource_task::Load(url, response_port.chan()));
|
||||||
|
|
||||||
let prefetch_data = PrefetchData {
|
let prefetch_data = @PrefetchData {
|
||||||
response_port: @response_port,
|
response_port: response_port,
|
||||||
data: @mut ~[]
|
data: ~[]
|
||||||
};
|
};
|
||||||
|
|
||||||
self.prefetch_map.insert(url, prefetch_data);
|
self.prefetch_map.insert(url, prefetch_data);
|
||||||
}
|
}
|
||||||
GetImage(url, response) => {
|
GetImage(url, response) => {
|
||||||
if self.prefetch_map.contains_key(url) {
|
match self.prefetch_map.find(url) {
|
||||||
|
some(prefetch_data) => {
|
||||||
|
|
||||||
|
let mut image_sent = false;
|
||||||
|
|
||||||
|
while prefetch_data.response_port.peek() {
|
||||||
|
match prefetch_data.response_port.recv() {
|
||||||
|
resource_task::Payload(data) => {
|
||||||
|
prefetch_data.data += data;
|
||||||
|
}
|
||||||
|
resource_task::Done(result::ok(*)) => {
|
||||||
|
// We've got the entire image binary
|
||||||
|
let mut data = ~[];
|
||||||
|
data <-> prefetch_data.data;
|
||||||
|
// FIXME: Need to do this in parallel
|
||||||
|
let image = @arc(~load_from_memory(data));
|
||||||
|
response.send(ImageReady(clone_arc(image)));
|
||||||
|
self.prefetch_map.remove(url);
|
||||||
|
self.image_map.insert(url, image);
|
||||||
|
image_sent = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
resource_task::Done(result::err(*)) => {
|
||||||
|
fail ~"FIXME: what happens now?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !image_sent {
|
||||||
response.send(ImageNotReady);
|
response.send(ImageNotReady);
|
||||||
} else {
|
}
|
||||||
fail ~"got a request for image data without prefetch";
|
}
|
||||||
|
none => {
|
||||||
|
// FIXME: Probably faster to hit this map before the prefetch map
|
||||||
|
match self.image_map.find(url) {
|
||||||
|
some(image) => response.send(ImageReady(clone_arc(image))),
|
||||||
|
none => fail ~"got a request for image data without prefetch"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Exit => break
|
Exit => break
|
||||||
|
@ -199,3 +238,89 @@ fn should_return_image_not_ready_if_data_has_not_arrived() {
|
||||||
image_cache_task.send(Exit);
|
image_cache_task.send(Exit);
|
||||||
mock_resource_task.send(resource_task::Exit);
|
mock_resource_task.send(resource_task::Exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_return_decoded_image_data_if_data_has_arrived() {
|
||||||
|
|
||||||
|
let image_bin_sent = port();
|
||||||
|
let image_bin_sent_chan = image_bin_sent.chan();
|
||||||
|
|
||||||
|
let mock_resource_task = do spawn_listener |from_client| {
|
||||||
|
|
||||||
|
// infer me
|
||||||
|
let from_client: port<resource_task::ControlMsg> = from_client;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match from_client.recv() {
|
||||||
|
resource_task::Load(_, response) => {
|
||||||
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
|
response.send(resource_task::Done(result::ok(())));
|
||||||
|
image_bin_sent_chan.send(());
|
||||||
|
}
|
||||||
|
resource_task::Exit => break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let image_cache_task = image_cache_task(mock_resource_task);
|
||||||
|
let url = make_url(~"file", none);
|
||||||
|
|
||||||
|
image_cache_task.send(Prefetch(url));
|
||||||
|
|
||||||
|
// Wait until our mock resource task has sent the image to the image cache
|
||||||
|
image_bin_sent.recv();
|
||||||
|
|
||||||
|
let response_port = port();
|
||||||
|
image_cache_task.send(GetImage(url, response_port.chan()));
|
||||||
|
match response_port.recv() {
|
||||||
|
ImageReady(_) => (),
|
||||||
|
_ => fail
|
||||||
|
}
|
||||||
|
|
||||||
|
image_cache_task.send(Exit);
|
||||||
|
mock_resource_task.send(resource_task::Exit);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_return_decoded_image_data_for_multiple_requests() {
|
||||||
|
|
||||||
|
let image_bin_sent = port();
|
||||||
|
let image_bin_sent_chan = image_bin_sent.chan();
|
||||||
|
|
||||||
|
let mock_resource_task = do spawn_listener |from_client| {
|
||||||
|
|
||||||
|
// infer me
|
||||||
|
let from_client: port<resource_task::ControlMsg> = from_client;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match from_client.recv() {
|
||||||
|
resource_task::Load(_, response) => {
|
||||||
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
|
response.send(resource_task::Done(result::ok(())));
|
||||||
|
image_bin_sent_chan.send(());
|
||||||
|
}
|
||||||
|
resource_task::Exit => break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let image_cache_task = image_cache_task(mock_resource_task);
|
||||||
|
let url = make_url(~"file", none);
|
||||||
|
|
||||||
|
image_cache_task.send(Prefetch(url));
|
||||||
|
|
||||||
|
// Wait until our mock resource task has sent the image to the image cache
|
||||||
|
image_bin_sent.recv();
|
||||||
|
|
||||||
|
for iter::repeat(2) {
|
||||||
|
let response_port = port();
|
||||||
|
image_cache_task.send(GetImage(url, response_port.chan()));
|
||||||
|
match response_port.recv() {
|
||||||
|
ImageReady(_) => (),
|
||||||
|
_ => fail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image_cache_task.send(Exit);
|
||||||
|
mock_resource_task.send(resource_task::Exit);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue