servo: Begin working on ImageCacheTask

Source-Repo: https://github.com/servo/servo
Source-Revision: 3708fcf9e083d0efd416fb87935cce398a79963f
This commit is contained in:
Brian Anderson 2012-08-10 12:18:47 -07:00
Родитель 5222a86193
Коммит 84494cac2d
4 изменённых файлов: 272 добавлений и 48 удалений

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

@ -1,7 +1,15 @@
export ImageBuffer, SharedImageBuffer;
export image;
export load;
import stb_image::image::{image, load};
import core::arc::arc;
// FIXME: Images must not be copied every frame. Instead we should atomically
// reference count them.
type SharedImageBuffer = arc<ImageBuffer>;
struct ImageBuffer {
data: ~[u8];
}

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

@ -0,0 +1,201 @@
export Msg, Prefetch, GetImage, Exit;
export ImageResponseMsg, ImageReady, ImageNotReady;
export ImageCacheTask;
export image_cache_task;
import image::base::{ImageBuffer, SharedImageBuffer};
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;
enum Msg {
Prefetch(url),
GetImage(url, chan<ImageResponseMsg>),
Exit
}
enum ImageResponseMsg {
ImageReady(ImageBuffer),
ImageNotReady
}
type ImageCacheTask = chan<Msg>;
fn image_cache_task(resource_task: ResourceTask) -> ImageCacheTask {
do spawn_listener |from_client| {
ImageCache {
resource_task: resource_task,
from_client: from_client,
prefetch_map: url_map()
}.run();
}
}
struct ImageCache {
resource_task: ResourceTask;
from_client: port<Msg>;
prefetch_map: UrlMap<PrefetchData>;
}
struct PrefetchData {
response_port: @port<resource_task::ProgressMsg>;
data: @mut ~[u8];
}
impl ImageCache {
fn run() {
loop {
match self.from_client.recv() {
Prefetch(url) => {
if self.prefetch_map.contains_key(url) {
// We're already waiting for this image
again
}
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 ~[]
};
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";
}
}
Exit => break
}
}
}
}
#[test]
fn should_exit_on_request() {
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::Exit => break,
_ => ()
}
}
};
let image_cache_task = image_cache_task(mock_resource_task);
let url = make_url(~"file", none);
image_cache_task.send(Exit);
mock_resource_task.send(resource_task::Exit);
}
#[test]
#[should_fail]
fn should_fail_if_unprefetched_image_is_requested() {
let mock_resource_task = do spawn_listener |from_client| {
};
let image_cache_task = image_cache_task(mock_resource_task);
let url = make_url(~"file", none);
let request = port();
image_cache_task.send(GetImage(url, request.chan()));
request.recv();
}
#[test]
fn should_request_url_from_resource_task_on_prefetch() {
let url_requested = port();
let url_requested_chan = url_requested.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(url, _) => url_requested_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));
url_requested.recv();
image_cache_task.send(Exit);
mock_resource_task.send(resource_task::Exit);
}
#[test]
fn should_not_request_url_from_resource_task_on_multiple_prefetches() {
let url_requested = port();
let url_requested_chan = url_requested.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(url, _) => url_requested_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));
image_cache_task.send(Prefetch(url));
url_requested.recv();
image_cache_task.send(Exit);
mock_resource_task.send(resource_task::Exit);
assert !url_requested.peek()
}
#[test]
fn should_return_image_not_ready_if_data_has_not_arrived() {
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::Exit => break,
_ => ()
}
}
};
let image_cache_task = image_cache_task(mock_resource_task);
let url = make_url(~"file", none);
image_cache_task.send(Prefetch(url));
let response_port = port();
image_cache_task.send(GetImage(url, response_port.chan()));
assert response_port.recv() == ImageNotReady;
image_cache_task.send(Exit);
mock_resource_task.send(resource_task::Exit);
}

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

@ -114,6 +114,7 @@ mod resource {
mod resource_task;
mod file_loader;
mod http_loader;
mod image_cache_task;
}
import servo_text = text;

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

@ -1,7 +1,8 @@
export make_url;
export make_url, UrlMap, url_map;
import std::net::url;
import url::{get_scheme, url};
import std::map::hashmap;
/**
Create a URL object from a string. Does various helpful browsery things like
@ -41,55 +42,68 @@ fn make_url(str_url: ~str, current_url: option<url>) -> url {
url::from_str(str_url).get()
}
#[test]
fn should_create_absolute_file_url_if_current_url_is_none_and_str_url_looks_filey() {
let file = ~"local.html";
let url = make_url(file, none);
#debug("url: %?", url);
assert url.scheme == ~"file";
assert url.path.contains(os::getcwd());
mod make_url_tests {
#[test]
fn should_create_absolute_file_url_if_current_url_is_none_and_str_url_looks_filey() {
let file = ~"local.html";
let url = make_url(file, none);
#debug("url: %?", url);
assert url.scheme == ~"file";
assert url.path.contains(os::getcwd());
}
#[test]
fn should_create_url_based_on_old_url_1() {
let old_str = ~"http://example.com";
let old_url = make_url(old_str, none);
let new_str = ~"index.html";
let new_url = make_url(new_str, some(old_url));
assert new_url.scheme == ~"http";
assert new_url.host == ~"example.com";
assert new_url.path == ~"/index.html";
}
#[test]
fn should_create_url_based_on_old_url_2() {
let old_str = ~"http://example.com/";
let old_url = make_url(old_str, none);
let new_str = ~"index.html";
let new_url = make_url(new_str, some(old_url));
assert new_url.scheme == ~"http";
assert new_url.host == ~"example.com";
assert new_url.path == ~"/index.html";
}
#[test]
fn should_create_url_based_on_old_url_3() {
let old_str = ~"http://example.com/index.html";
let old_url = make_url(old_str, none);
let new_str = ~"crumpet.html";
let new_url = make_url(new_str, some(old_url));
assert new_url.scheme == ~"http";
assert new_url.host == ~"example.com";
assert new_url.path == ~"/crumpet.html";
}
#[test]
fn should_create_url_based_on_old_url_4() {
let old_str = ~"http://example.com/snarf/index.html";
let old_url = make_url(old_str, none);
let new_str = ~"crumpet.html";
let new_url = make_url(new_str, some(old_url));
assert new_url.scheme == ~"http";
assert new_url.host == ~"example.com";
assert new_url.path == ~"/snarf/crumpet.html";
}
}
#[test]
fn should_create_url_based_on_old_url_1() {
let old_str = ~"http://example.com";
let old_url = make_url(old_str, none);
let new_str = ~"index.html";
let new_url = make_url(new_str, some(old_url));
assert new_url.scheme == ~"http";
assert new_url.host == ~"example.com";
assert new_url.path == ~"/index.html";
}
type UrlMap<T: copy> = hashmap<url, T>;
#[test]
fn should_create_url_based_on_old_url_2() {
let old_str = ~"http://example.com/";
let old_url = make_url(old_str, none);
let new_str = ~"index.html";
let new_url = make_url(new_str, some(old_url));
assert new_url.scheme == ~"http";
assert new_url.host == ~"example.com";
assert new_url.path == ~"/index.html";
}
fn url_map<T: copy>() -> UrlMap<T> {
import core::to_str::to_str;
#[test]
fn should_create_url_based_on_old_url_3() {
let old_str = ~"http://example.com/index.html";
let old_url = make_url(old_str, none);
let new_str = ~"crumpet.html";
let new_url = make_url(new_str, some(old_url));
assert new_url.scheme == ~"http";
assert new_url.host == ~"example.com";
assert new_url.path == ~"/crumpet.html";
}
#[test]
fn should_create_url_based_on_old_url_4() {
let old_str = ~"http://example.com/snarf/index.html";
let old_url = make_url(old_str, none);
let new_str = ~"crumpet.html";
let new_url = make_url(new_str, some(old_url));
assert new_url.scheme == ~"http";
assert new_url.host == ~"example.com";
assert new_url.path == ~"/snarf/crumpet.html";
hashmap::<url, T>(|a| str::hash(&a.to_str()),
|a, b| str::eq(&a.to_str(), &b.to_str()))
}