зеркало из https://github.com/mozilla/gecko-dev.git
servo: Load images through the image cache
Source-Repo: https://github.com/servo/servo Source-Revision: 38321d9b70c9822063d6f6c34f9efd9a573d2c65
This commit is contained in:
Родитель
15e6ad14e8
Коммит
499ce66ce0
|
@ -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. */ }
|
||||
|
|
Загрузка…
Ссылка в новой задаче