Load images through the image cache

This commit is contained in:
Brian Anderson 2012-08-10 20:11:18 -07:00
parent b31da68ef2
commit 38321d9b70
4 changed files with 86 additions and 35 deletions

View file

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

View file

@ -16,7 +16,10 @@ import text::TextBox;
import traverse::extended_full_traversal; import traverse::extended_full_traversal;
import style::style::{SpecifiedStyle}; import style::style::{SpecifiedStyle};
import vec::{push, push_all}; 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}; import arc::{arc, clone};
enum BoxKind { enum BoxKind {
@ -51,7 +54,7 @@ class Appearance {
let mut temp = none; let mut temp = none;
temp <-> self.background_image; temp <-> self.background_image;
let holder <- option::unwrap(temp); let holder <- option::unwrap(temp);
image = some(holder.get_image()); image = holder.get_image();
self.background_image = some(holder); self.background_image = some(holder);
} }
@ -81,16 +84,21 @@ class Box {
class ImageHolder { class ImageHolder {
// Invariant: at least one of url and image is not none, except // Invariant: at least one of url and image is not none, except
// occasionally while get_image is being called // occasionally while get_image is being called
let mut url : option<~str>; let mut url : option<url>;
let mut image : option<arc<~Image>>; let mut image : option<arc<~Image>>;
let image_cache_task: ImageCacheTask;
new(-url : ~str) { new(-url : url, image_cache_task: ImageCacheTask) {
self.url = some(url); self.url = some(copy url);
self.image = none; 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 // 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 // If this is the first time we've called this function, load
// the image and store it for the future // the image and store it for the future
if self.image.is_none() { if self.image.is_none() {
@ -99,20 +107,32 @@ class ImageHolder {
let mut temp = none; let mut temp = none;
temp <-> self.url; temp <-> self.url;
let url = option::unwrap(temp); 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 if self.image.is_some() {
// it without breaking purity, then put it back and return the // Temporarily swap out the arc of the image so we can clone
// clone. This is not threadsafe. // it without breaking purity, then put it back and return the
let mut temp = none; // clone. This is not threadsafe.
temp <-> self.image; let mut temp = none;
let im_arc = option::unwrap(temp); temp <-> self.image;
self.image = some(clone(&im_arc)); let im_arc = option::unwrap(temp);
self.image = some(clone(&im_arc));
return ~im_arc; return some(~im_arc);
} else {
return none;
}
} }
} }

View file

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

View file

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