diff --git a/src/components/gfx/render_task.rs b/src/components/gfx/render_task.rs index 3d507531145..4521f9074e9 100644 --- a/src/components/gfx/render_task.rs +++ b/src/components/gfx/render_task.rs @@ -32,7 +32,7 @@ pub struct RenderLayer { pub enum Msg { RenderMsg(RenderLayer), - ReRenderMsg(~[BufferRequest], f32, PipelineId), + ReRenderMsg(~[BufferRequest], f32, PipelineId, uint), PaintPermissionGranted, PaintPermissionRevoked, ExitMsg(Chan<()>), @@ -89,6 +89,8 @@ struct RenderTask { paint_permission: bool, /// Cached copy of last layers rendered last_paint_msg: Option<(arc::Arc, Size2D)>, + /// A counter for epoch messages + epoch_counter: uint, } impl RenderTask { @@ -123,6 +125,7 @@ impl RenderTask { paint_permission: false, last_paint_msg: None, + epoch_counter: 0, }; render_task.start(); @@ -136,18 +139,24 @@ impl RenderTask { match self.port.recv() { RenderMsg(render_layer) => { if self.paint_permission { - self.compositor.set_layer_page_size(self.id, render_layer.size); + self.epoch_counter += 1; + self.compositor.set_layer_page_size(self.id, render_layer.size, self.epoch_counter); } self.render_layer = Some(render_layer); } - ReRenderMsg(tiles, scale, id) => { - self.render(tiles, scale, id); + ReRenderMsg(tiles, scale, id, epoch) => { + if self.epoch_counter == epoch { + self.render(tiles, scale, id); + } else { + debug!("renderer epoch mismatch: %? != %?", self.epoch_counter, epoch); + } } PaintPermissionGranted => { self.paint_permission = true; match self.render_layer { Some(ref render_layer) => { - self.compositor.set_layer_page_size(self.id, render_layer.size); + self.epoch_counter += 1; + self.compositor.set_layer_page_size(self.id, render_layer.size, self.epoch_counter); } None => {} } @@ -235,7 +244,7 @@ impl RenderTask { debug!("render_task: returning surface"); if self.paint_permission { - self.compositor.paint(id, layer_buffer_set.clone()); + self.compositor.paint(id, layer_buffer_set.clone(), self.epoch_counter); } debug!("caching paint msg"); self.last_paint_msg = Some((layer_buffer_set, render_layer.size)); diff --git a/src/components/main/compositing/compositor_layer.rs b/src/components/main/compositing/compositor_layer.rs index 2993bc339f5..edba5e63569 100644 --- a/src/components/main/compositing/compositor_layer.rs +++ b/src/components/main/compositing/compositor_layer.rs @@ -43,6 +43,9 @@ pub struct CompositorLayer { /// When set to true, this layer is ignored by its parents. This is useful for /// soft deletion or when waiting on a page size. hidden: bool, + /// A monotonically increasing counter that keeps track of the current epoch. + /// add_buffer() calls that don't match the current epoch will be ignored. + epoch: uint, } /// Helper struct for keeping CompositorLayer children organized. @@ -79,7 +82,8 @@ impl CompositorLayer { max_mem)), }, root_layer: @mut ContainerLayer(), - hidden: true, + hidden: page_size.is_none(), + epoch: 0, } } @@ -89,20 +93,38 @@ impl CompositorLayer { max_mem: Option) -> CompositorLayer { let SendableFrameTree { pipeline, children } = frame_tree; let mut layer = CompositorLayer::new(pipeline, None, tile_size, max_mem); - layer.children = (do children.consume_iter().transform |child| { + layer.children = (do children.move_iter().map |child| { let SendableChildFrameTree { frame_tree, rect } = child; let container = @mut ContainerLayer(); - container.scissor = rect; + match rect { + Some(rect) => { + container.scissor = Some(Rect(Point2D(100f32, 200f32), Size2D(700f32, 800f32))); + container.common.transform = identity().translate(100f32, 200f32, 0f32); + + // FIXME: The top two lines are temporary until layout window sizes are fixed. + // When they are, uncomment the next 2 lines: + + // container.scissor = Some(rect); + // container.common.transform = identity().translate(rect.origin.x, + // rect.origin.y, + // 0f32); + + } + None => {} + }; + + let child_layer = ~CompositorLayer::from_frame_tree(frame_tree, tile_size, max_mem); + container.add_child(ContainerLayerKind(child_layer.root_layer)); + CompositorLayerChild { - child: ~CompositorLayer::from_frame_tree(frame_tree, - tile_size, - max_mem), + child: child_layer, container: container, } }).collect(); layer } + // Move the layer by as relative specified amount in page coordinates. Does not change // the position of the layer relative to its parent. This also takes in a cursor position // to see if the mouse is over child layers first. If a layer successfully scrolled, returns @@ -195,7 +217,7 @@ impl CompositorLayer { let (request, r) = quadtree.get_tile_rects_page(rect, scale); redisplay = r; // workaround to make redisplay visible outside block if !request.is_empty() { - self.pipeline.render_chan.send(ReRenderMsg(request, scale, self.pipeline.id.clone())); + self.pipeline.render_chan.send(ReRenderMsg(request, scale, self.pipeline.id.clone(), self.epoch)); } } if redisplay { @@ -230,7 +252,7 @@ impl CompositorLayer { // If the layer is hidden and has a defined page size, unhide it. // This method returns false if the specified layer is not found. pub fn set_clipping_rect(&mut self, pipeline_id: PipelineId, new_rect: Rect) -> bool { - for child_node in self.children.iter() { + for child_node in self.children.mut_iter() { if pipeline_id != child_node.child.pipeline.id { loop; } @@ -254,8 +276,9 @@ impl CompositorLayer { // Set the layer's page size. This signals that the renderer is ready for BufferRequests. // If the layer is hidden and has a defined clipping rect, unhide it. // This method returns false if the specified layer is not found. - pub fn resize(&mut self, pipeline_id: PipelineId, new_size: Size2D, window_size: Size2D) -> bool { + pub fn resize(&mut self, pipeline_id: PipelineId, new_size: Size2D, window_size: Size2D, epoch: uint) -> bool { if self.pipeline.id == pipeline_id { + self.epoch = epoch; self.page_size = Some(new_size); // TODO: might get buffers back here match self.quadtree { @@ -271,16 +294,17 @@ impl CompositorLayer { self.hidden = false; return true; } - self.resize_helper(pipeline_id, new_size) + self.resize_helper(pipeline_id, new_size, epoch) } // A helper method to resize sublayers. - fn resize_helper(&mut self, pipeline_id: PipelineId, new_size: Size2D) -> bool { - for self.children.mut_iter().advance |child_node| { + fn resize_helper(&mut self, pipeline_id: PipelineId, new_size: Size2D, epoch: uint) -> bool { + for child_node in self.children.mut_iter() { if pipeline_id != child_node.child.pipeline.id { loop; } let child = &mut child_node.child; + child.epoch = epoch; child.page_size = Some(new_size); // TODO: might get buffers back here match child.quadtree { @@ -303,7 +327,7 @@ impl CompositorLayer { } // ID does not match ours, so recurse on descendents (including hidden children) - self.children.mut_iter().transform(|x| &mut x.child).any(|x| x.resize_helper(pipeline_id, new_size)) + self.children.mut_iter().map(|x| &mut x.child).any(|x| x.resize_helper(pipeline_id, new_size, epoch)) } // Collect buffers from the quadtree. This method IS NOT recursive, so child CompositorLayers @@ -336,7 +360,7 @@ impl CompositorLayer { } }; } - + // Add new tiles. let quadtree = match self.quadtree { NoTree(_, _) => fail!("CompositorLayer: cannot get buffer request for %?, @@ -381,8 +405,14 @@ impl CompositorLayer { } // Add LayerBuffers to the specified layer. Returns false if the layer is not found. - pub fn add_buffers(&mut self, pipeline_id: PipelineId, new_buffers: &LayerBufferSet) -> bool { + // If the epoch of the message does not match the layer's epoch, the message is ignored. + pub fn add_buffers(&mut self, pipeline_id: PipelineId, new_buffers: &LayerBufferSet, epoch: uint) -> bool { if self.pipeline.id == pipeline_id { + if self.epoch != epoch { + debug!("compositor epoch mismatch: %? != %?, id: %?", self.epoch, epoch, self.pipeline.id); + // TODO: send buffers back + return true; + } { // block here to prevent double mutable borrow of self let quadtree = match self.quadtree { NoTree(_, _) => fail!("CompositorLayer: cannot get buffer request for %?, @@ -400,7 +430,7 @@ impl CompositorLayer { return true; } // ID does not match ours, so recurse on descendents (including hidden children). - self.children.mut_iter().map(|x| &mut x.child).any(|x| x.add_buffers(pipeline_id, new_buffers)) + self.children.mut_iter().map(|x| &mut x.child).any(|x| x.add_buffers(pipeline_id, new_buffers, epoch)) } // Deletes a specified sublayer, including hidden children. Returns false if the layer is not found. diff --git a/src/components/main/compositing/mod.rs b/src/components/main/compositing/mod.rs index bd307b11411..13852e1e8b2 100644 --- a/src/components/main/compositing/mod.rs +++ b/src/components/main/compositing/mod.rs @@ -79,17 +79,17 @@ impl RenderListener for CompositorChan { port.recv() } - fn paint(&self, id: PipelineId, layer_buffer_set: arc::Arc) { - self.chan.send(Paint(id, layer_buffer_set)) + fn paint(&self, id: PipelineId, layer_buffer_set: arc::Arc, epoch: uint) { + self.chan.send(Paint(id, layer_buffer_set, epoch)) } fn new_layer(&self, id: PipelineId, page_size: Size2D) { let Size2D { width, height } = page_size; self.chan.send(NewLayer(id, Size2D(width as f32, height as f32))) } - fn set_layer_page_size(&self, id: PipelineId, page_size: Size2D) { + fn set_layer_page_size(&self, id: PipelineId, page_size: Size2D, epoch: uint) { let Size2D { width, height } = page_size; - self.chan.send(SetLayerPageSize(id, Size2D(width as f32, height as f32))) + self.chan.send(SetLayerPageSize(id, Size2D(width as f32, height as f32), epoch)) } fn set_layer_clip_rect(&self, id: PipelineId, new_rect: Rect) { let new_rect = Rect(Point2D(new_rect.origin.x as f32, @@ -136,11 +136,10 @@ pub enum Msg { /// Requests the compositors GL context. GetGLContext(Chan), - // TODO: Attach epochs to these messages /// Alerts the compositor that there is a new layer to be rendered. NewLayer(PipelineId, Size2D), /// Alerts the compositor that the specified layer's page has changed size. - SetLayerPageSize(PipelineId, Size2D), + SetLayerPageSize(PipelineId, Size2D, uint), /// Alerts the compositor that the specified layer's clipping rect has changed. SetLayerClipRect(PipelineId, Rect), /// Alerts the compositor that the specified layer has been deleted. @@ -149,7 +148,7 @@ pub enum Msg { InvalidateRect(PipelineId, Rect), /// Requests that the compositor paint the given layer buffer set for the given page size. - Paint(PipelineId, arc::Arc), + Paint(PipelineId, arc::Arc, uint), /// Alerts the compositor to the current status of page loading. ChangeReadyState(ReadyState), /// Alerts the compositor to the current status of rendering. @@ -235,8 +234,12 @@ impl CompositorTask { let window_size_page = Size2D(window_size.width as f32 / world_zoom, window_size.height as f32 / world_zoom); for layer in compositor_layer.mut_iter() { - recomposite = layer.get_buffer_request(Rect(Point2D(0f32, 0f32), window_size_page), - world_zoom) || recomposite; + if !layer.hidden { + recomposite = layer.get_buffer_request(Rect(Point2D(0f32, 0f32), window_size_page), + world_zoom) || recomposite; + } else { + debug!("layer is hidden!"); //eschweic + } } }; @@ -298,13 +301,12 @@ impl CompositorTask { ask_for_tiles(); } - SetLayerPageSize(id, new_size) => { - println(fmt!("Compositor: id %? sent new layer of size %?", id, new_size)); + SetLayerPageSize(id, new_size, epoch) => { match compositor_layer { Some(ref mut layer) => { let page_window = Size2D(window_size.width as f32 / world_zoom, window_size.height as f32 / world_zoom); - assert!(layer.resize(id, new_size, page_window)); + assert!(layer.resize(id, new_size, page_window, epoch)); ask_for_tiles(); } None => {} @@ -331,12 +333,12 @@ impl CompositorTask { } } - Paint(id, new_layer_buffer_set) => { + Paint(id, new_layer_buffer_set, epoch) => { debug!("osmain: received new frame"); match compositor_layer { Some(ref mut layer) => { - assert!(layer.add_buffers(id, new_layer_buffer_set.get())); + assert!(layer.add_buffers(id, new_layer_buffer_set.get(), epoch)); recomposite = true; } None => { diff --git a/src/components/main/compositing/quadtree.rs b/src/components/main/compositing/quadtree.rs index 0ffc9fa31e7..6d1b323952e 100644 --- a/src/components/main/compositing/quadtree.rs +++ b/src/components/main/compositing/quadtree.rs @@ -211,11 +211,30 @@ impl Quadtree { (ret, redisplay) } - - /// Resize the quadtree. This can add more space, changing the root node, or it can shrink, making - /// an internal node the new root. - /// TODO: return tiles after shrinking + /// Creates a new quadtree at the specified size. This should be called when the window changes size. + /// TODO: return old tiles. pub fn resize(&mut self, width: uint, height: uint) { + // Spaces must be squares and powers of 2, so expand the space until it is + let longer = width.max(&height); + let num_tiles = div_ceil(longer, self.max_tile_size); + let power_of_two = next_power_of_two(num_tiles); + let size = power_of_two * self.max_tile_size; + + self.root = ~QuadtreeNode { + tile: None, + origin: Point2D(0f32, 0f32), + size: size as f32, + quadrants: [None, None, None, None], + status: Normal, + tile_mem: 0, + }; + self.clip_size = Size2D(width, height); + } + + /// Resize the underlying quadtree without removing tiles already in place. + /// Might be useful later on, but resize() should be used for now. + /// TODO: return tiles after shrinking + pub fn bad_resize(&mut self, width: uint, height: uint) { self.clip_size = Size2D(width, height); let longer = width.max(&height); let new_num_tiles = div_ceil(longer, self.max_tile_size); diff --git a/src/components/main/constellation.rs b/src/components/main/constellation.rs index 16783f21315..966c6cdb312 100644 --- a/src/components/main/constellation.rs +++ b/src/components/main/constellation.rs @@ -26,6 +26,7 @@ use servo_util::time::ProfilerChan; use std::hashmap::{HashMap, HashSet}; use std::util::replace; use extra::future::{Future, from_value}; +use extra::url::Url; /// Maintains the pipelines and navigation context and grants permission to composite pub struct Constellation { @@ -108,7 +109,7 @@ impl FrameTree { /// Returns the frame tree whose key is id fn find_mut(@mut self, id: PipelineId) -> Option<@mut FrameTree> { - do self.iter().find_ |frame_tree| { + do self.iter().find |frame_tree| { id == frame_tree.pipeline.id } } @@ -118,7 +119,7 @@ impl FrameTree { fn replace_child(@mut self, id: PipelineId, new_child: @mut FrameTree) - -> Result<@mut FrameTree, @mut FrameTree> { + -> Either<@mut FrameTree, @mut FrameTree> { let mut child = (do self.iter().filter_map |frame_tree| { (do frame_tree.children.iter().find |child| { child.frame_tree.pipeline.id == id @@ -407,7 +408,7 @@ impl Constellation { for current_frame in self.current_frame().iter() { debug!("Constellation: Sending size for frame in current frame tree."); let source_frame = current_frame.find_mut(pipeline_id); - for source_frame.iter().advance |source_frame| { + for source_frame in source_frame.iter() { for child_frame_tree in source_frame.children.mut_iter() { let pipeline = &child_frame_tree.frame_tree.pipeline; if pipeline.subpage_id.expect("Constellation: child frame does not have a @@ -646,6 +647,11 @@ impl Constellation { // TODO(tkuehn): In fact, this kind of message might be provably // impossible to occur. if current_frame.contains(pipeline_id) { + //debug!("updating compositor frame tree with %?", current_frame); + //self.set_ids(current_frame); + for frame in current_frame.iter() { + frame.pipeline.grant_paint_permission(); + } return; } } diff --git a/src/components/main/pipeline.rs b/src/components/main/pipeline.rs index a1760dc7868..33e70ed6ebf 100644 --- a/src/components/main/pipeline.rs +++ b/src/components/main/pipeline.rs @@ -161,7 +161,7 @@ impl Pipeline { } pub fn reload(&mut self) { - do self.url.clone().map_consume() |url| { + do self.url.clone().map_move() |url| { self.load(url); }; } diff --git a/src/components/msg/compositor_msg.rs b/src/components/msg/compositor_msg.rs index 284b14099b1..929b5a158d3 100644 --- a/src/components/msg/compositor_msg.rs +++ b/src/components/msg/compositor_msg.rs @@ -59,10 +59,10 @@ pub enum ReadyState { pub trait RenderListener { fn get_gl_context(&self) -> AzGLContext; fn new_layer(&self, PipelineId, Size2D); - fn set_layer_page_size(&self, PipelineId, Size2D); + fn set_layer_page_size(&self, PipelineId, Size2D, uint); fn set_layer_clip_rect(&self, PipelineId, Rect); fn delete_layer(&self, PipelineId); - fn paint(&self, id: PipelineId, layer_buffer_set: arc::Arc); + fn paint(&self, id: PipelineId, layer_buffer_set: arc::Arc, uint); fn set_render_state(&self, render_state: RenderState); } diff --git a/src/components/script/dom/htmliframeelement.rs b/src/components/script/dom/htmliframeelement.rs index 4b8199e0bdd..288a988928a 100644 --- a/src/components/script/dom/htmliframeelement.rs +++ b/src/components/script/dom/htmliframeelement.rs @@ -31,7 +31,7 @@ struct IFrameSize { impl IFrameSize { pub fn set_rect(&mut self, rect: Rect) { let future_chan = replace(&mut self.future_chan, None); - do future_chan.map_consume |future_chan| { + do future_chan.map_move |future_chan| { let Size2D { width, height } = rect.size; future_chan.send(Size2D(width as uint, height as uint)); }; diff --git a/src/components/script/html/hubbub_html_parser.rs b/src/components/script/html/hubbub_html_parser.rs index f78807a8a35..e14ddac2f4b 100644 --- a/src/components/script/html/hubbub_html_parser.rs +++ b/src/components/script/html/hubbub_html_parser.rs @@ -401,7 +401,7 @@ pub fn parse_html(cx: *JSContext, future_chan: Some(chan), constellation_chan: constellation_chan.clone(), }); - iframe_chan.send(HtmlDiscoveredIFrame(iframe_url, subpage_id, size_future)); + iframe_chan.send(HtmlDiscoveredIFrame((iframe_url, subpage_id, size_future))); } } }