diff --git a/servo/src/servo/content.rs b/servo/src/servo/content.rs index d1cfa2bcbd54..53d05a00680a 100644 --- a/servo/src/servo/content.rs +++ b/servo/src/servo/content.rs @@ -84,6 +84,7 @@ class Content { let jsrt: jsrt; let mut document: option<@Document>; + let mut doc_url: option; let resource_task: ResourceTask; @@ -97,6 +98,7 @@ class Content { 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 { #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 { } } - 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 { // 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 { // Nothing to do. } some(document) => { - self.relayout(*document); + assert self.doc_url.is_some(); + self.relayout(*document, &self.doc_url.get()); } } return true; diff --git a/servo/src/servo/layout/base.rs b/servo/src/servo/layout/base.rs index 0679a86a0eed..d6af5d1b88e6 100644 --- a/servo/src/servo/layout/base.rs +++ b/servo/src/servo/layout/base.rs @@ -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; let mut image : option>; + 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; + } } } diff --git a/servo/src/servo/layout/layout_task.rs b/servo/src/servo/layout/layout_task.rs index 28c7de42c717..3ee70d057662 100644 --- a/servo/src/servo/layout/layout_task.rs +++ b/servo/src/servo/layout/layout_task.rs @@ -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; enum Msg { - BuildMsg(Node, arc), + BuildMsg(Node, arc, url), PingMsg(chan), ExitMsg } -fn Layout(renderer: Renderer, _image_cache_task: ImageCacheTask) -> Layout { +fn Layout(renderer: Renderer, image_cache_task: ImageCacheTask) -> Layout { do spawn_listener::|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); diff --git a/servo/src/servo/layout/style/apply.rs b/servo/src/servo/layout/style/apply.rs index d17ad86fbb66..28ff3211639f 100644 --- a/servo/src/servo/layout/style/apply.rs +++ b/servo/src/servo/layout/style/apply.rs @@ -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. */ }