diff --git a/src/components/compositing/compositor.rs b/src/components/compositing/compositor.rs index f92a2920531..522aba58245 100644 --- a/src/components/compositing/compositor.rs +++ b/src/components/compositing/compositor.rs @@ -3,9 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use compositor_data::CompositorData; -use compositor_task::{Msg, CompositorTask, Exit, ChangeReadyState, SetUnRenderedColor}; -use compositor_task::{SetIds, GetGraphicsMetadata, CreateRootCompositorLayerIfNecessary}; -use compositor_task::{CreateDescendantCompositorLayerIfNecessary, SetLayerPageSize}; +use compositor_task::{Msg, CompositorTask, Exit, ChangeReadyState, SetIds}; +use compositor_task::{GetGraphicsMetadata, CreateOrUpdateRootLayer, CreateOrUpdateDescendantLayer}; use compositor_task::{SetLayerClipRect, Paint, ScrollFragmentPoint, LoadComplete}; use compositor_task::{ShutdownComplete, ChangeRenderState}; use constellation::SendableFrameTree; @@ -279,10 +278,6 @@ impl IOCompositor { self.change_render_state(render_state); } - (Ok(SetUnRenderedColor(pipeline_id, layer_id, color)), NotShuttingDown) => { - self.set_unrendered_color(pipeline_id, layer_id, color); - } - (Ok(SetIds(frame_tree, response_chan, new_constellation_chan)), _) => { self.set_ids(frame_tree, response_chan, new_constellation_chan); } @@ -291,27 +286,28 @@ impl IOCompositor { chan.send(Some(azure_hl::current_graphics_metadata())); } - (Ok(CreateRootCompositorLayerIfNecessary(pipeline_id, layer_id, size, color)), + (Ok(CreateOrUpdateRootLayer(pipeline_id, layer_id, epoch, size, color)), NotShuttingDown) => { - self.create_root_compositor_layer_if_necessary(pipeline_id, - layer_id, - size, - color); + self.create_or_update_root_layer(pipeline_id, + layer_id, + epoch, + size, + color); } - (Ok(CreateDescendantCompositorLayerIfNecessary(pipeline_id, - layer_id, - rect, - scroll_behavior)), + (Ok(CreateOrUpdateDescendantLayer(pipeline_id, + layer_id, + epoch, + rect, + scroll_behavior, + color)), NotShuttingDown) => { - self.create_descendant_compositor_layer_if_necessary(pipeline_id, - layer_id, - rect, - scroll_behavior); - } - - (Ok(SetLayerPageSize(pipeline_id, layer_id, new_size, epoch)), NotShuttingDown) => { - self.set_layer_page_size(pipeline_id, layer_id, new_size, epoch); + self.create_or_update_descendant_layer(pipeline_id, + layer_id, + epoch, + rect, + scroll_behavior, + color); } (Ok(SetLayerClipRect(pipeline_id, layer_id, new_rect)), NotShuttingDown) => { @@ -346,20 +342,6 @@ impl IOCompositor { } } - fn set_unrendered_color(&mut self, pipeline_id: PipelineId, layer_id: LayerId, color: Color) { - match self.scene.root { - Some(ref root_layer) => { - match CompositorData::find_layer_with_pipeline_and_layer_id(root_layer.clone(), - pipeline_id, - layer_id) { - Some(ref layer) => CompositorData::set_unrendered_color(layer.clone(), color), - None => { } - } - } - None => { } - } - } - fn set_ids(&mut self, frame_tree: SendableFrameTree, response_chan: Sender<()>, @@ -373,40 +355,67 @@ impl IOCompositor { self.send_window_size(); } - fn create_root_compositor_layer_if_necessary(&mut self, - id: PipelineId, - layer_id: LayerId, - size: Size2D, - unrendered_color: Color) { - let (root_pipeline, root_layer_id) = match self.scene.root { - Some(ref root_layer) if root_layer.extra_data.borrow().pipeline.id == id => { - (root_layer.extra_data.borrow().pipeline.clone(), - CompositorData::id_of_first_child(root_layer.clone())) - } - _ => { - match self.root_pipeline { - Some(ref root_pipeline) => { - (root_pipeline.clone(), LayerId::null()) - }, - _ => fail!("Compositor: Received new layer without initialized pipeline"), - } - } - }; + fn update_layer_if_exists(&mut self, + pipeline_id: PipelineId, + layer_id: LayerId, + epoch: Epoch, + rect: Rect, + unrendered_color: Color) + -> bool { - if layer_id != root_layer_id { + match self.scene.root { + Some(ref root_layer) => { + match CompositorData::find_layer_with_pipeline_and_layer_id(root_layer.clone(), + pipeline_id, + layer_id) { + Some(existing_layer) => { + CompositorData::update_layer(existing_layer.clone(), + epoch, + rect, + unrendered_color); + true + } + None => false, + } + } + None => false, + } + } + + fn create_or_update_root_layer(&mut self, + pipeline_id: PipelineId, + layer_id: LayerId, + epoch: Epoch, + size: Size2D, + unrendered_color: Color) { + let new_root_rect = Rect(Point2D(0f32, 0f32), size); + let need_new_root_layer = !self.update_layer_if_exists(pipeline_id, + layer_id, + epoch, + new_root_rect, + unrendered_color); + + if need_new_root_layer { + let root_pipeline = match self.root_pipeline { + Some(ref root_pipeline) => root_pipeline.clone(), + None => fail!("Compositor: Making new layer without initialized pipeline"), + }; let new_compositor_data = CompositorData::new_root(root_pipeline, + epoch, size, - self.opts.cpu_painting); + self.opts.cpu_painting, + unrendered_color); let new_root = Rc::new(Layer::new(size, self.opts.tile_size, new_compositor_data)); - new_root.extra_data.borrow_mut().unrendered_color = unrendered_color; - CompositorData::add_child_if_necessary(new_root.clone(), - layer_id, - Rect(Point2D(0f32, 0f32), size), - size, - Scrollable); + CompositorData::add_child(new_root.clone(), + layer_id, + epoch, + new_root_rect, + size, + Scrollable, + unrendered_color); // Release all tiles from the layer before dropping it. match self.scene.root { @@ -416,14 +425,41 @@ impl IOCompositor { self.scene.root = Some(new_root); } + self.scroll_layer_to_fragment_point_if_necessary(pipeline_id, layer_id); self.ask_for_tiles(); } - fn create_descendant_compositor_layer_if_necessary(&mut self, - pipeline_id: PipelineId, - layer_id: LayerId, - rect: Rect, - scroll_policy: ScrollPolicy) { + fn create_or_update_descendant_layer(&mut self, + pipeline_id: PipelineId, + layer_id: LayerId, + epoch: Epoch, + rect: Rect, + scroll_policy: ScrollPolicy, + unrendered_color: Color) { + if !self.update_layer_if_exists(pipeline_id, + layer_id, + epoch, + rect, + unrendered_color) { + self.create_descendant_layer(pipeline_id, + layer_id, + epoch, + rect, + scroll_policy, + unrendered_color); + } + self.scroll_layer_to_fragment_point_if_necessary(pipeline_id, layer_id); + self.ask_for_tiles(); + } + + fn create_descendant_layer(&self, + pipeline_id: PipelineId, + layer_id: LayerId, + epoch: Epoch, + rect: Rect, + scroll_policy: ScrollPolicy, + unrendered_color: Color) { + match self.scene.root { Some(ref root_layer) => { let parent_layer_id = root_layer.extra_data.borrow().id; @@ -432,11 +468,13 @@ impl IOCompositor { parent_layer_id) { Some(ref mut parent_layer) => { let page_size = root_layer.extra_data.borrow().page_size.unwrap(); - CompositorData::add_child_if_necessary(parent_layer.clone(), - layer_id, - rect, - page_size, - scroll_policy); + CompositorData::add_child(parent_layer.clone(), + layer_id, + epoch, + rect, + page_size, + scroll_policy, + unrendered_color); } None => { fail!("Compositor: couldn't find parent layer"); @@ -445,8 +483,6 @@ impl IOCompositor { } None => fail!("Compositor: Received new layer without initialized pipeline") } - - self.ask_for_tiles(); } /// The size of the content area in CSS px at the current zoom level @@ -467,33 +503,24 @@ impl IOCompositor { })); } - fn set_layer_page_size(&mut self, - pipeline_id: PipelineId, - layer_id: LayerId, - new_size: Size2D, - epoch: Epoch) { + fn scroll_layer_to_fragment_point_if_necessary(&mut self, + pipeline_id: PipelineId, + layer_id: LayerId) { let page_window = self.page_window(); - let (ask, move): (bool, bool) = match self.scene.root { - Some(ref layer) => { - CompositorData::resize(layer.clone(), - pipeline_id, - layer_id, - new_size, - page_window, - epoch); - let move = self.fragment_point.take().map_or(false, |point| { - CompositorData::move(layer.clone(), pipeline_id, layer_id, point, page_window) - }); - - (true, move) + let needs_recomposite = match self.scene.root { + Some(ref mut root_layer) => { + self.fragment_point.take().map_or(false, |fragment_point| { + CompositorData::move(root_layer.clone(), + pipeline_id, + layer_id, + fragment_point, + page_window) + }) } - None => (false, false) + None => fail!("Compositor: Tried to scroll to fragment without root layer."), }; - if ask { - self.recomposite_if(move); - self.ask_for_tiles(); - } + self.recomposite_if(needs_recomposite); } fn set_layer_clip_rect(&mut self, diff --git a/src/components/compositing/compositor_data.rs b/src/components/compositing/compositor_data.rs index 86d4fa2aeb0..f75a7347253 100644 --- a/src/components/compositing/compositor_data.rs +++ b/src/components/compositing/compositor_data.rs @@ -13,7 +13,6 @@ use geom::point::{Point2D, TypedPoint2D}; use geom::rect::{Rect, TypedRect}; use geom::size::{Size2D, TypedSize2D}; use gfx::render_task::{ReRenderMsg, UnusedBufferMsg}; -use gfx; use layers::layers::{Layer, Flip, LayerBuffer, LayerBufferSet, NoFlip, TextureLayer}; use layers::quadtree::{Tile, Normal, Hidden}; use layers::platform::surface::{NativeCompositingGraphicsContext, NativeSurfaceMethods}; @@ -103,71 +102,65 @@ impl Clampable for f32 { impl CompositorData { pub fn new(pipeline: CompositionPipeline, layer_id: LayerId, + epoch: Epoch, bounds: Rect, page_size: Option>, cpu_painting: bool, wants_scroll_events: WantsScrollEventsFlag, scroll_policy: ScrollPolicy, - hidden: bool) -> CompositorData { + unrendered_color: Color) + -> CompositorData { CompositorData { pipeline: pipeline, id: layer_id, scroll_offset: TypedPoint2D(0f32, 0f32), bounds: bounds, page_size: page_size, - hidden: hidden, + hidden: false, wants_scroll_events: wants_scroll_events, scroll_policy: scroll_policy, cpu_painting: cpu_painting, - unrendered_color: gfx::color::rgba(0.0, 0.0, 0.0, 0.0), + unrendered_color: unrendered_color, scissor: None, - epoch: Epoch(0), + epoch: epoch, } } pub fn new_root(pipeline: CompositionPipeline, + epoch: Epoch, page_size: Size2D, - cpu_painting: bool) -> CompositorData { + cpu_painting: bool, + unrendered_color: Color) -> CompositorData { CompositorData::new(pipeline, LayerId::null(), + epoch, Rect(Point2D(0f32, 0f32), page_size), Some(page_size), cpu_painting, WantsScrollEvents, FixedPosition, - false) - } - - - pub fn id_of_first_child(layer: Rc>) -> LayerId { - layer.children().iter().next().expect("no first child!").extra_data.borrow().id + unrendered_color) } /// Adds a child layer to the layer with the given ID and the given pipeline, if it doesn't /// exist yet. The child layer will have the same pipeline, tile size, memory limit, and CPU /// painting status as its parent. - pub fn add_child_if_necessary(layer: Rc>, - child_layer_id: LayerId, - rect: Rect, - page_size: Size2D, - scroll_policy: ScrollPolicy) { - // See if we've already made this child layer. - let pipeline_id = layer.extra_data.borrow().pipeline.id; - if layer.children().iter().any(|kid| { - kid.extra_data.borrow().pipeline.id == pipeline_id && - kid.extra_data.borrow().id == child_layer_id - }) { - return; - } - + pub fn add_child(layer: Rc>, + child_layer_id: LayerId, + epoch: Epoch, + rect: Rect, + page_size: Size2D, + scroll_policy: ScrollPolicy, + unrendered_color: Color) { let new_compositor_data = CompositorData::new(layer.extra_data.borrow().pipeline.clone(), child_layer_id, + epoch, rect, Some(page_size), layer.extra_data.borrow().cpu_painting, DoesntWantScrollEvents, scroll_policy, - false); + unrendered_color); let new_kid = Rc::new(Layer::new(page_size, Layer::tile_size(layer.clone()), new_compositor_data)); @@ -423,46 +416,45 @@ impl CompositorData { } } - // 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(layer: Rc>, - pipeline_id: PipelineId, - layer_id: LayerId, - new_size: Size2D, - window_size: TypedSize2D, - epoch: Epoch) - -> bool { - debug!("compositor_data: starting resize()"); - if layer.extra_data.borrow().pipeline.id != pipeline_id || - layer.extra_data.borrow().id != layer_id { - return CompositorData::resize_helper(layer.clone(), - pipeline_id, - layer_id, - new_size, - epoch) - } - - debug!("compositor_data: layer found for resize()"); + pub fn update_layer(layer: Rc>, + epoch: Epoch, + rect: Rect, + unrendered_color: Color) { layer.extra_data.borrow_mut().epoch = epoch; + layer.extra_data.borrow_mut().unrendered_color = unrendered_color; + CompositorData::resize(layer.clone(), rect.size); + } + + // Resize and unhide a pre-existing layer. A new layer's size is set during creation. + fn resize(layer: Rc>, + new_size: Size2D) { + debug!("compositor_data: starting resize_helper()"); + + debug!("compositor_data: layer found for resize_helper()"); layer.extra_data.borrow_mut().page_size = Some(new_size); let unused_buffers = Layer::resize(layer.clone(), new_size); if !unused_buffers.is_empty() { - let _ = layer.extra_data.borrow().pipeline - .render_chan - .send_opt(UnusedBufferMsg(unused_buffers)); + let msg = UnusedBufferMsg(unused_buffers); + let _ = layer.extra_data.borrow().pipeline.render_chan.send_opt(msg); + } + + let scissor_clone = layer.extra_data.borrow().scissor.clone(); + match scissor_clone { + Some(scissor) => { + // Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the + // cursor position to make sure the scroll isn't propagated downwards. + let size: TypedSize2D = Size2D::from_untyped(&scissor.size); + CompositorData::handle_scroll_event(layer.clone(), + TypedPoint2D(0f32, 0f32), + TypedPoint2D(-1f32, -1f32), + size); + layer.extra_data.borrow_mut().hidden = false; + } + None => {} // Nothing to do } - // Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the cursor position - // to make sure the scroll isn't propagated downwards. - CompositorData::handle_scroll_event(layer.clone(), - TypedPoint2D(0f32, 0f32), - TypedPoint2D(-1f32, -1f32), - window_size); - layer.extra_data.borrow_mut().hidden = false; CompositorData::set_occlusions(layer.clone()); - true } pub fn move(layer: Rc>, @@ -537,8 +529,6 @@ impl CompositorData { (NoFlip, TextureTarget2D) } - - fn find_child_with_pipeline_and_layer_id(layer: Rc>, pipeline_id: PipelineId, layer_id: LayerId) @@ -573,60 +563,6 @@ impl CompositorData { return None; } - // A helper method to resize sublayers. - fn resize_helper(layer: Rc>, - pipeline_id: PipelineId, - layer_id: LayerId, - new_size: Size2D, - epoch: Epoch) - -> bool { - debug!("compositor_data: starting resize_helper()"); - - let found = match CompositorData::find_child_with_pipeline_and_layer_id(layer.clone(), - pipeline_id, - layer_id) { - Some(child) => { - debug!("compositor_data: layer found for resize_helper()"); - child.extra_data.borrow_mut().epoch = epoch; - child.extra_data.borrow_mut().page_size = Some(new_size); - - let unused_buffers = Layer::resize(child.clone(), new_size); - if !unused_buffers.is_empty() { - let msg = UnusedBufferMsg(unused_buffers); - let _ = child.extra_data.borrow().pipeline.render_chan.send_opt(msg); - } - - let scissor_clone = child.extra_data.borrow().scissor.clone(); - match scissor_clone { - Some(scissor) => { - // Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the - // cursor position to make sure the scroll isn't propagated downwards. - let size: TypedSize2D = Size2D::from_untyped(&scissor.size); - CompositorData::handle_scroll_event(child.clone(), - TypedPoint2D(0f32, 0f32), - TypedPoint2D(-1f32, -1f32), - size); - child.extra_data.borrow_mut().hidden = false; - } - None => {} // Nothing to do - } - true - } - None => false, - }; - - if found { // Boolean flag to get around double borrow of self - CompositorData::set_occlusions(layer.clone()); - return true - } - - // If we got here, the layer's ID does not match ours, so recurse on descendents (including - // hidden children). - layer.children().iter().any(|kid| { - CompositorData::resize_helper(kid.clone(), pipeline_id, layer_id, new_size, epoch) - }) - } - // Collect buffers from the quadtree. This method IS NOT recursive, so child layers // are not rebuilt directly from this method. pub fn build_layer_tree(layer: Rc>, @@ -766,9 +702,5 @@ impl CompositorData { CompositorData::forget_all_tiles(kid.clone()); } } - - pub fn set_unrendered_color(layer: Rc>, color: Color) { - layer.extra_data.borrow_mut().unrendered_color = color; - } } diff --git a/src/components/compositing/compositor_task.rs b/src/components/compositing/compositor_task.rs index 1b8e9653744..78779439996 100644 --- a/src/components/compositing/compositor_task.rs +++ b/src/components/compositing/compositor_task.rs @@ -92,23 +92,22 @@ impl RenderListener for CompositorChan { metadata.position.size.height as f32); let rect = Rect(origin, size); if first { - self.chan.send(CreateRootCompositorLayerIfNecessary(pipeline_id, - metadata.id, - size, - metadata.background_color)); + self.chan.send(CreateOrUpdateRootLayer(pipeline_id, + metadata.id, + epoch, + size, + metadata.background_color)); first = false } else { self.chan - .send(CreateDescendantCompositorLayerIfNecessary(pipeline_id, - metadata.id, - rect, - metadata.scroll_policy)); + .send(CreateOrUpdateDescendantLayer(pipeline_id, + metadata.id, + epoch, + rect, + metadata.scroll_policy, + metadata.background_color)); } - self.chan.send(SetUnRenderedColor(pipeline_id, - metadata.id, - metadata.background_color)); - self.chan.send(SetLayerPageSize(pipeline_id, metadata.id, size, epoch)); self.chan.send(SetLayerClipRect(pipeline_id, metadata.id, rect)); } } @@ -161,12 +160,10 @@ pub enum Msg { /// Tells the compositor to create the root layer for a pipeline if necessary (i.e. if no layer /// with that ID exists). - CreateRootCompositorLayerIfNecessary(PipelineId, LayerId, Size2D, Color), + CreateOrUpdateRootLayer(PipelineId, LayerId, Epoch, Size2D, Color), /// Tells the compositor to create a descendant layer for a pipeline if necessary (i.e. if no /// layer with that ID exists). - CreateDescendantCompositorLayerIfNecessary(PipelineId, LayerId, Rect, ScrollPolicy), - /// Alerts the compositor that the specified layer has changed size. - SetLayerPageSize(PipelineId, LayerId, Size2D, Epoch), + CreateOrUpdateDescendantLayer(PipelineId, LayerId, Epoch, Rect, ScrollPolicy, Color), /// Alerts the compositor that the specified layer's clipping rect has changed. SetLayerClipRect(PipelineId, LayerId, Rect), /// Scroll a page in a window @@ -179,8 +176,6 @@ pub enum Msg { ChangeRenderState(RenderState), /// Sets the channel to the current layout and render tasks, along with their id SetIds(SendableFrameTree, Sender<()>, ConstellationChan), - /// Sets the color of unrendered content for a layer. - SetUnRenderedColor(PipelineId, LayerId, Color), /// The load of a page for a given URL has completed. LoadComplete(PipelineId, Url), } diff --git a/src/components/compositing/headless.rs b/src/components/compositing/headless.rs index c588b57cfad..a76cbfa9905 100644 --- a/src/components/compositing/headless.rs +++ b/src/components/compositing/headless.rs @@ -2,9 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use compositor_task::{Msg, Exit, ChangeReadyState, SetUnRenderedColor}; -use compositor_task::{SetIds, GetGraphicsMetadata, CreateRootCompositorLayerIfNecessary}; -use compositor_task::{CreateDescendantCompositorLayerIfNecessary, SetLayerPageSize}; +use compositor_task::{Msg, Exit, ChangeReadyState, SetIds}; +use compositor_task::{GetGraphicsMetadata, CreateOrUpdateRootLayer, CreateOrUpdateDescendantLayer}; use compositor_task::{SetLayerClipRect, Paint, ScrollFragmentPoint, LoadComplete}; use compositor_task::{ShutdownComplete, ChangeRenderState}; @@ -89,11 +88,11 @@ impl NullCompositor { // we'll notice and think about whether it needs a response, like // SetIds. - CreateRootCompositorLayerIfNecessary(..) | - CreateDescendantCompositorLayerIfNecessary(..) | SetLayerPageSize(..) | + CreateOrUpdateRootLayer(..) | + CreateOrUpdateDescendantLayer(..) | SetLayerClipRect(..) | Paint(..) | ChangeReadyState(..) | ChangeRenderState(..) | ScrollFragmentPoint(..) | - SetUnRenderedColor(..) | LoadComplete(..) => () + LoadComplete(..) => () } } }