зеркало из https://github.com/mozilla/gecko-dev.git
servo: Begin working on ImageCacheTask
Source-Repo: https://github.com/servo/servo Source-Revision: 3708fcf9e083d0efd416fb87935cce398a79963f
This commit is contained in:
Родитель
5222a86193
Коммит
84494cac2d
|
@ -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()))
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче