servo: Load images through the image cache

Source-Repo: https://github.com/servo/servo
Source-Revision: 38321d9b70c9822063d6f6c34f9efd9a573d2c65
This commit is contained in:
Brian Anderson 2012-08-10 20:11:18 -07:00
Родитель 15e6ad14e8
Коммит 499ce66ce0
4 изменённых файлов: 86 добавлений и 35 удалений

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

@ -84,6 +84,7 @@ class Content<S:Sink send copy> {
let jsrt: jsrt;
let mut document: option<@Document>;
let mut doc_url: option<url>;
let resource_task: ResourceTask;
@ -97,6 +98,7 @@ class Content<S:Sink send copy> {
self.jsrt = jsrt();
self.document = none;
self.doc_url = none;
self.sink.add_event_listener(self.event_port.chan());
@ -135,8 +137,9 @@ class Content<S:Sink send copy> {
#debug["%?", js_scripts];
let document = Document(root, css_rules);
self.relayout(document);
self.relayout(document, &url);
self.document = some(@document);
self.doc_url = some(copy url);
//XXXjdm it was easier to duplicate the relevant ExecuteMsg code;
// they should be merged somehow in the future.
@ -181,7 +184,7 @@ class Content<S:Sink send copy> {
}
}
fn relayout(document: Document) {
fn relayout(document: Document, doc_url: &url) {
#debug("content: performing relayout");
// Now, join the layout so that they will see the latest
@ -190,7 +193,7 @@ class Content<S:Sink send copy> {
// Send new document and relevant styles to layout
// FIXME: Put CSS rules in an arc or something.
self.layout.send(BuildMsg(document.root, clone(&document.css_rules)));
self.layout.send(BuildMsg(document.root, clone(&document.css_rules), copy *doc_url));
// Indicate that reader was forked so any further
// changes will be isolated.
@ -206,7 +209,8 @@ class Content<S:Sink send copy> {
// Nothing to do.
}
some(document) => {
self.relayout(*document);
assert self.doc_url.is_some();
self.relayout(*document, &self.doc_url.get());
}
}
return true;

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

@ -16,7 +16,10 @@ import text::TextBox;
import traverse::extended_full_traversal;
import style::style::{SpecifiedStyle};
import vec::{push, push_all};
import std::net::url::url;
import resource::image_cache_task;
import image_cache_task::ImageCacheTask;
import core::to_str::to_str;
import arc::{arc, clone};
enum BoxKind {
@ -51,7 +54,7 @@ class Appearance {
let mut temp = none;
temp <-> self.background_image;
let holder <- option::unwrap(temp);
image = some(holder.get_image());
image = holder.get_image();
self.background_image = some(holder);
}
@ -81,16 +84,21 @@ class Box {
class ImageHolder {
// Invariant: at least one of url and image is not none, except
// occasionally while get_image is being called
let mut url : option<~str>;
let mut url : option<url>;
let mut image : option<arc<~Image>>;
let image_cache_task: ImageCacheTask;
new(-url : ~str) {
self.url = some(url);
new(-url : url, image_cache_task: ImageCacheTask) {
self.url = some(copy url);
self.image = none;
self.image_cache_task = image_cache_task;
// Tell the image cache we're going to be interested in this url
image_cache_task.send(image_cache_task::Prefetch(move url));
}
// This function should not be called by two tasks at the same time
fn get_image() -> ~arc<~Image> {
fn get_image() -> option<~arc<~Image>> {
// If this is the first time we've called this function, load
// the image and store it for the future
if self.image.is_none() {
@ -99,20 +107,32 @@ class ImageHolder {
let mut temp = none;
temp <-> self.url;
let url = option::unwrap(temp);
let image = load(url);
self.image = some(arc(~image));
let response_port = port();
self.image_cache_task.send(image_cache_task::GetImage(copy url, response_port.chan()));
self.image = match response_port.recv() {
image_cache_task::ImageReady(image) => some(clone(&image)),
image_cache_task::ImageNotReady => {
#info("image was not ready for %s", url.to_str());
// FIXME: Need to schedule another layout when the image is ready
none
}
};
}
// Temporarily swap out the arc of the image so we can clone
// it without breaking purity, then put it back and return the
// clone. This is not threadsafe.
let mut temp = none;
temp <-> self.image;
let im_arc = option::unwrap(temp);
self.image = some(clone(&im_arc));
if self.image.is_some() {
// Temporarily swap out the arc of the image so we can clone
// it without breaking purity, then put it back and return the
// clone. This is not threadsafe.
let mut temp = none;
temp <-> self.image;
let im_arc = option::unwrap(temp);
self.image = some(clone(&im_arc));
return ~im_arc;
return some(~im_arc);
} else {
return none;
}
}
}

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

@ -10,6 +10,8 @@ import dom::style::Stylesheet;
import gfx::geometry::px_to_au;
import gfx::renderer::Renderer;
import resource::image_cache_task::ImageCacheTask;
import std::net::url::url;
import style::apply::apply_style;
import task::*;
import comm::*;
@ -17,12 +19,12 @@ import comm::*;
type Layout = chan<Msg>;
enum Msg {
BuildMsg(Node, arc<Stylesheet>),
BuildMsg(Node, arc<Stylesheet>, url),
PingMsg(chan<content::PingMsg>),
ExitMsg
}
fn Layout(renderer: Renderer, _image_cache_task: ImageCacheTask) -> Layout {
fn Layout(renderer: Renderer, image_cache_task: ImageCacheTask) -> Layout {
do spawn_listener::<Msg>|request| {
loop {
match request.recv() {
@ -31,7 +33,7 @@ fn Layout(renderer: Renderer, _image_cache_task: ImageCacheTask) -> Layout {
#debug("layout: ExitMsg received");
break;
}
BuildMsg(node, styles) => {
BuildMsg(node, styles, doc_url) => {
#debug("layout: received layout request for:");
node.dump();
@ -42,7 +44,8 @@ fn Layout(renderer: Renderer, _image_cache_task: ImageCacheTask) -> Layout {
let this_box = node.construct_boxes();
this_box.dump();
this_box.apply_css_style();
apply_style(this_box, &doc_url, image_cache_task);
this_box.reflow_subtree(px_to_au(800));
let dlist = build_display_list(this_box);

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

@ -7,16 +7,34 @@ import image::base::load;
import base::{Box, BTree, NTree, LayoutData, SpecifiedStyle, ImageHolder,
BlockBox, InlineBox, IntrinsicBox, TextBox};
import traverse::{top_down_traversal};
import std::net::url::url;
import resource::image_cache_task::ImageCacheTask;
trait ApplyStyleBoxMethods {
fn apply_css_style();
fn apply_style();
struct StyleApplicator {
box: @Box;
doc_url: &url;
image_cache_task: ImageCacheTask;
}
fn apply_style(box: @Box, doc_url: &url, image_cache_task: ImageCacheTask) {
let applicator = StyleApplicator {
box: box,
doc_url: doc_url,
image_cache_task: image_cache_task
};
applicator.apply_css_style();
}
#[doc="A wrapper around a set of functions that can be applied as a top-down traversal of layout
boxes."]
fn inheritance_wrapper(box : @Box) {
box.apply_style();
fn inheritance_wrapper(box : @Box, doc_url: &url, image_cache_task: ImageCacheTask) {
let applicator = StyleApplicator {
box: box,
doc_url: doc_url,
image_cache_task: image_cache_task
};
applicator.apply_style();
inhereit_height(box);
inhereit_width(box);
}
@ -81,9 +99,13 @@ fn inhereit_width(box : @Box) {
}
}
impl @Box : ApplyStyleBoxMethods {
impl StyleApplicator {
fn apply_css_style() {
top_down_traversal(self, inheritance_wrapper);
let doc_url = copy *self.doc_url;
let image_cache_task = self.image_cache_task;
do top_down_traversal(self.box) |box, move doc_url| {
inheritance_wrapper(box, &doc_url, image_cache_task);
}
}
#[doc="Applies CSS style to a layout box.
@ -94,13 +116,14 @@ impl @Box : ApplyStyleBoxMethods {
"]
fn apply_style() {
// Right now, we only handle images.
do self.node.read |node| {
do self.box.node.read |node| {
match node.kind {
~Element(element) => {
let style = self.node.get_specified_style();
let style = self.box.node.get_specified_style();
self.appearance.background_color = match style.background_color {
self.box.appearance.background_color = match style.background_color {
some(col) => col,
none => node.kind.default_color()
};
@ -112,7 +135,8 @@ impl @Box : ApplyStyleBoxMethods {
if url.is_some() {
// FIXME: Some sort of BASE HREF support!
// FIXME: Parse URLs!
self.appearance.background_image = some(ImageHolder(option::unwrap(url)))
let new_url = make_url(option::unwrap(url), some(copy *self.doc_url));
self.box.appearance.background_image = some(ImageHolder(new_url, self.image_cache_task))
};
}
_ => { /* Ignore. */ }