servo: Decode images in the ImageCache

Source-Repo: https://github.com/servo/servo
Source-Revision: 872a82b9f0cf628676960cd87a3b9e72f688b4f2

--HG--
rename : servo/src/test/test.jpeg => servo/src/servo/image/test.jpeg
This commit is contained in:
Brian Anderson 2012-08-10 15:41:08 -07:00
Родитель bc7302cc9e
Коммит f997cd28ed
3 изменённых файлов: 144 добавлений и 14 удалений

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

@ -2,6 +2,7 @@ export Image;
export load;
export load_from_memory;
export test_image_bin;
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.
type Image = image;
fn test_image_bin() -> ~[u8] {
#include_bin("test.jpeg")
}

Двоичные данные
servo/src/servo/image/test.jpeg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 86 KiB

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

@ -3,13 +3,15 @@ export ImageResponseMsg, ImageReady, ImageNotReady;
export ImageCacheTask;
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 util::url::{make_url, UrlMap, url_map};
import comm::{chan, port};
import task::spawn_listener;
import resource::resource_task;
import resource_task::ResourceTask;
import core::arc::arc;
import clone_arc = core::arc::clone;
enum Msg {
Prefetch(url),
@ -18,7 +20,7 @@ enum Msg {
}
enum ImageResponseMsg {
ImageReady(Image),
ImageReady(arc<~Image>),
ImageNotReady
}
@ -29,7 +31,8 @@ fn image_cache_task(resource_task: ResourceTask) -> ImageCacheTask {
ImageCache {
resource_task: resource_task,
from_client: from_client,
prefetch_map: url_map()
prefetch_map: url_map(),
image_map: url_map()
}.run();
}
}
@ -37,12 +40,13 @@ fn image_cache_task(resource_task: ResourceTask) -> ImageCacheTask {
struct ImageCache {
resource_task: ResourceTask;
from_client: port<Msg>;
prefetch_map: UrlMap<PrefetchData>;
prefetch_map: UrlMap<@PrefetchData>;
image_map: UrlMap<@arc<~Image>>;
}
struct PrefetchData {
response_port: @port<resource_task::ProgressMsg>;
data: @mut ~[u8];
response_port: port<resource_task::ProgressMsg>;
mut data: ~[u8];
}
impl ImageCache {
@ -59,18 +63,53 @@ impl ImageCache {
let response_port = port();
self.resource_task.send(resource_task::Load(url, response_port.chan()));
let prefetch_data = PrefetchData {
response_port: @response_port,
data: @mut ~[]
let prefetch_data = @PrefetchData {
response_port: response_port,
data: ~[]
};
self.prefetch_map.insert(url, prefetch_data);
}
GetImage(url, response) => {
if self.prefetch_map.contains_key(url) {
response.send(ImageNotReady);
} else {
fail ~"got a request for image data without prefetch";
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);
}
}
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
@ -198,4 +237,90 @@ fn should_return_image_not_ready_if_data_has_not_arrived() {
assert response_port.recv() == ImageNotReady;
image_cache_task.send(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);
}