auto merge of #1313 : pcwalton/servo/parallel-layout, r=larsbergstrom

This is one small step toward parallel layout.

r? @larsbergstrom
This commit is contained in:
bors-servo 2013-11-26 12:26:18 -08:00
commit a76f761ed3
4 changed files with 67 additions and 63 deletions

View file

@ -675,15 +675,15 @@ impl LayoutTask {
// to the script task, and ultimately cause the image to be // to the script task, and ultimately cause the image to be
// re-requested. We probably don't need to go all the way back to // re-requested. We probably don't need to go all the way back to
// the script task for this. // the script task for this.
fn make_on_image_available_cb(&self) -> @ImageResponder { fn make_on_image_available_cb(&self) -> ~ImageResponder:Send {
// This has a crazy signature because the image cache needs to // This has a crazy signature because the image cache needs to
// make multiple copies of the callback, and the dom event // make multiple copies of the callback, and the dom event
// channel is not a copyable type, so this is actually a // channel is not a copyable type, so this is actually a
// little factory to produce callbacks // little factory to produce callbacks
@LayoutImageResponder { ~LayoutImageResponder {
id: self.id.clone(), id: self.id.clone(),
script_chan: self.script_chan.clone(), script_chan: self.script_chan.clone(),
} as @ImageResponder } as ~ImageResponder:Send
} }
/// Handles a message to destroy layout data. Layout data must be destroyed on *this* task /// Handles a message to destroy layout data. Layout data must be destroyed on *this* task

View file

@ -48,22 +48,13 @@ pub enum Msg {
Exit(Chan<()>), Exit(Chan<()>),
} }
#[deriving(Clone)]
pub enum ImageResponseMsg { pub enum ImageResponseMsg {
ImageReady(Arc<~Image>), ImageReady(Arc<~Image>),
ImageNotReady, ImageNotReady,
ImageFailed ImageFailed
} }
impl ImageResponseMsg {
fn clone(&self) -> ImageResponseMsg {
match *self {
ImageReady(ref img) => ImageReady(img.clone()),
ImageNotReady => ImageNotReady,
ImageFailed => ImageFailed,
}
}
}
impl Eq for ImageResponseMsg { impl Eq for ImageResponseMsg {
fn eq(&self, other: &ImageResponseMsg) -> bool { fn eq(&self, other: &ImageResponseMsg) -> bool {
// FIXME: Bad copies // FIXME: Bad copies
@ -243,11 +234,11 @@ impl ImageCache {
} }
} }
fn set_state(&self, url: Url, state: ImageState) { fn set_state(&mut self, url: Url, state: ImageState) {
self.state_map.insert(url, state); self.state_map.insert(url, state);
} }
fn prefetch(&self, url: Url) { fn prefetch(&mut self, url: Url) {
match self.get_state(url.clone()) { match self.get_state(url.clone()) {
Init => { Init => {
let to_cache = self.chan.clone(); let to_cache = self.chan.clone();
@ -278,7 +269,7 @@ impl ImageCache {
} }
} }
fn store_prefetched_image_data(&self, url: Url, data: Result<Cell<~[u8]>, ()>) { fn store_prefetched_image_data(&mut self, url: Url, data: Result<Cell<~[u8]>, ()>) {
match self.get_state(url.clone()) { match self.get_state(url.clone()) {
Prefetching(next_step) => { Prefetching(next_step) => {
match data { match data {
@ -307,7 +298,7 @@ impl ImageCache {
} }
} }
fn decode(&self, url: Url) { fn decode(&mut self, url: Url) {
match self.get_state(url.clone()) { match self.get_state(url.clone()) {
Init => fail!(~"decoding image before prefetch"), Init => fail!(~"decoding image before prefetch"),
@ -350,7 +341,7 @@ impl ImageCache {
} }
} }
fn store_image(&self, url: Url, image: Option<Arc<~Image>>) { fn store_image(&mut self, url: Url, image: Option<Arc<~Image>>) {
match self.get_state(url.clone()) { match self.get_state(url.clone()) {
Decoding => { Decoding => {
@ -377,7 +368,7 @@ impl ImageCache {
} }
fn purge_waiters(&self, url: Url, f: &fn() -> ImageResponseMsg) { fn purge_waiters(&mut self, url: Url, f: &fn() -> ImageResponseMsg) {
match self.wait_map.pop(&url) { match self.wait_map.pop(&url) {
Some(waiters) => { Some(waiters) => {
for response in waiters.iter() { for response in waiters.iter() {
@ -399,7 +390,7 @@ impl ImageCache {
} }
} }
fn wait_for_image(&self, url: Url, response: Chan<ImageResponseMsg>) { fn wait_for_image(&mut self, url: Url, response: Chan<ImageResponseMsg>) {
match self.get_state(url.clone()) { match self.get_state(url.clone()) {
Init => fail!(~"request for image before prefetch"), Init => fail!(~"request for image before prefetch"),

View file

@ -33,10 +33,11 @@ pub fn LocalImageCache(image_cache_task: ImageCacheTask) -> LocalImageCache {
pub struct LocalImageCache { pub struct LocalImageCache {
priv image_cache_task: ImageCacheTask, priv image_cache_task: ImageCacheTask,
priv round_number: uint, priv round_number: uint,
priv on_image_available: Option<@ImageResponder>, priv on_image_available: Option<~ImageResponder:Send>,
priv state_map: UrlMap<@mut ImageState> priv state_map: UrlMap<ImageState>
} }
#[deriving(Clone)]
struct ImageState { struct ImageState {
prefetched: bool, prefetched: bool,
decoded: bool, decoded: bool,
@ -47,56 +48,67 @@ struct ImageState {
impl LocalImageCache { impl LocalImageCache {
/// The local cache will only do a single remote request for a given /// The local cache will only do a single remote request for a given
/// URL in each 'round'. Layout should call this each time it begins /// URL in each 'round'. Layout should call this each time it begins
pub fn next_round(&mut self, on_image_available: @ImageResponder) { pub fn next_round(&mut self, on_image_available: ~ImageResponder:Send) {
self.round_number += 1; self.round_number += 1;
self.on_image_available = Some(on_image_available); self.on_image_available = Some(on_image_available);
} }
pub fn prefetch(&self, url: &Url) { pub fn prefetch(&mut self, url: &Url) {
let state = self.get_state(url); {
if !state.prefetched { let state = self.get_state(url);
self.image_cache_task.send(Prefetch((*url).clone())); if state.prefetched {
return
}
state.prefetched = true; state.prefetched = true;
} }
self.image_cache_task.send(Prefetch((*url).clone()));
} }
pub fn decode(&self, url: &Url) { pub fn decode(&mut self, url: &Url) {
let state = self.get_state(url); {
if !state.decoded { let state = self.get_state(url);
self.image_cache_task.send(Decode((*url).clone())); if state.decoded {
return
}
state.decoded = true; state.decoded = true;
} }
self.image_cache_task.send(Decode((*url).clone()));
} }
// FIXME: Should return a Future // FIXME: Should return a Future
pub fn get_image(&self, url: &Url) -> Port<ImageResponseMsg> { pub fn get_image(&mut self, url: &Url) -> Port<ImageResponseMsg> {
let state = self.get_state(url); {
let state = self.get_state(url);
// Save the previous round number for comparison // Save the previous round number for comparison
let last_round = state.last_request_round; let last_round = state.last_request_round;
// Set the current round number for this image // Set the current round number for this image
state.last_request_round = self.round_number; state.last_request_round = self.round_number;
match state.last_response { match state.last_response {
ImageReady(ref image) => { ImageReady(ref image) => {
let (port, chan) = comm::stream();
chan.send(ImageReady(image.clone()));
return port;
}
ImageNotReady => {
if last_round == self.round_number {
let (port, chan) = comm::stream(); let (port, chan) = comm::stream();
chan.send(ImageNotReady); chan.send(ImageReady(image.clone()));
return port;
}
ImageNotReady => {
if last_round == self.round_number {
let (port, chan) = comm::stream();
chan.send(ImageNotReady);
return port;
} else {
// We haven't requested the image from the
// remote cache this round
}
}
ImageFailed => {
let (port, chan) = comm::stream();
chan.send(ImageFailed);
return port; return port;
} else {
// We haven't requested the image from the
// remote cache this round
} }
}
ImageFailed => {
let (port, chan) = comm::stream();
chan.send(ImageFailed);
return port;
} }
} }
@ -113,7 +125,7 @@ impl LocalImageCache {
// on the image to load and triggering layout // on the image to load and triggering layout
let image_cache_task = self.image_cache_task.clone(); let image_cache_task = self.image_cache_task.clone();
assert!(self.on_image_available.is_some()); assert!(self.on_image_available.is_some());
let on_image_available = self.on_image_available.unwrap().respond(); let on_image_available = self.on_image_available.as_ref().unwrap().respond();
let url = (*url).clone(); let url = (*url).clone();
do task::spawn { do task::spawn {
let (response_port, response_chan) = comm::stream(); let (response_port, response_chan) = comm::stream();
@ -130,24 +142,24 @@ impl LocalImageCache {
ImageNotReady => ImageNotReady, ImageNotReady => ImageNotReady,
ImageFailed => ImageFailed ImageFailed => ImageFailed
}; };
state.last_response = response_copy; self.get_state(url).last_response = response_copy;
let (port, chan) = comm::stream(); let (port, chan) = comm::stream();
chan.send(response); chan.send(response);
return port; return port;
} }
fn get_state(&self, url: &Url) -> @mut ImageState { fn get_state<'a>(&'a mut self, url: &Url) -> &'a mut ImageState {
let state = do self.state_map.find_or_insert_with(url.clone()) |_| { let state = self.state_map.find_or_insert_with(url.clone(), |_| {
let new_state = @mut ImageState { let new_state = ImageState {
prefetched: false, prefetched: false,
decoded: false, decoded: false,
last_request_round: 0, last_request_round: 0,
last_response: ImageNotReady last_response: ImageNotReady
}; };
new_state new_state
}; });
*state // Unborrowing the state state
} }
} }

View file

@ -147,8 +147,9 @@ mod make_url_tests {
} }
pub type UrlMap<T> = @mut HashMap<Url, T>; pub type UrlMap<T> = HashMap<Url, T>;
pub fn url_map<T: Clone + 'static>() -> UrlMap<T> { pub fn url_map<T: Clone + 'static>() -> UrlMap<T> {
@mut HashMap::new() HashMap::new()
} }