aboutsummaryrefslogtreecommitdiffstats
path: root/components/compositing
diff options
context:
space:
mode:
authorGlenn Watson <gw@intuitionlibrary.com>2015-08-13 09:46:58 +1000
committerGlenn Watson <gw@intuitionlibrary.com>2015-08-13 09:46:58 +1000
commit6506468e193be9363972ce58e70cf93755f9f8ec (patch)
treef05547cad57ec7993ef74bc9f2db09520984ad97 /components/compositing
parente44ae6404fd25ed51a543141ca8f9cc2a3443817 (diff)
downloadservo-6506468e193be9363972ce58e70cf93755f9f8ec.tar.gz
servo-6506468e193be9363972ce58e70cf93755f9f8ec.zip
Ensure compositor layers are collected when removed from layout.
Diffstat (limited to 'components/compositing')
-rw-r--r--components/compositing/compositor.rs12
-rw-r--r--components/compositing/compositor_layer.rs45
2 files changed, 57 insertions, 0 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs
index c7fc95d59a7..d70956e906e 100644
--- a/components/compositing/compositor.rs
+++ b/components/compositing/compositor.rs
@@ -379,6 +379,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
(Msg::InitializeLayersForPipeline(pipeline_id, epoch, properties),
ShutdownState::NotShuttingDown) => {
self.get_or_create_pipeline_details(pipeline_id).current_epoch = epoch;
+ self.collect_old_layers(pipeline_id, &properties);
for (index, layer_properties) in properties.iter().enumerate() {
if index == 0 {
self.create_or_update_base_layer(pipeline_id, *layer_properties);
@@ -671,6 +672,17 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.find_layer_with_pipeline_and_layer_id(pipeline_id, LayerId::null())
}
+ fn collect_old_layers(&mut self,
+ pipeline_id: PipelineId,
+ new_layers: &Vec<LayerProperties>) {
+ let root_layer = match self.scene.root {
+ Some(ref root_layer) => root_layer.clone(),
+ None => return,
+ };
+
+ root_layer.collect_old_layers(self, pipeline_id, new_layers);
+ }
+
fn remove_pipeline_root_layer(&mut self, pipeline_id: PipelineId) {
let root_layer = match self.scene.root {
Some(ref root_layer) => root_layer.clone(),
diff --git a/components/compositing/compositor_layer.rs b/components/compositing/compositor_layer.rs
index 0d3c27ab53f..380660be6b5 100644
--- a/components/compositing/compositor_layer.rs
+++ b/components/compositing/compositor_layer.rs
@@ -98,6 +98,14 @@ pub trait CompositorLayer {
pipeline_id: PipelineId)
where Window: WindowMethods;
+ /// Traverses the existing layer hierarchy and removes any layers that
+ /// currently exist but which are no longer required.
+ fn collect_old_layers<Window>(&self,
+ compositor: &mut IOCompositor<Window>,
+ pipeline_id: PipelineId,
+ new_layers: &Vec<LayerProperties>)
+ where Window: WindowMethods;
+
/// Destroys all tiles of all layers, including children, *without* sending them back to the
/// painter. You must call this only when the paint task is destined to be going down;
/// otherwise, you will leak tiles.
@@ -272,6 +280,43 @@ impl CompositorLayer for Layer<CompositorData> {
}
}
+ fn collect_old_layers<Window>(&self,
+ compositor: &mut IOCompositor<Window>,
+ pipeline_id: PipelineId,
+ new_layers: &Vec<LayerProperties>)
+ where Window: WindowMethods {
+ // Traverse children first so that layers are removed
+ // bottom up - allowing each layer being removed to properly
+ // clean up any tiles it owns.
+ for kid in self.children().iter() {
+ kid.collect_old_layers(compositor, pipeline_id, new_layers);
+ }
+
+ // Retain child layers that also exist in the new layer list.
+ self.children().retain(|child| {
+ let extra_data = child.extra_data.borrow();
+
+ // Never remove root layers or layers from other pipelines.
+ if pipeline_id != extra_data.pipeline_id ||
+ extra_data.id == LayerId::null() {
+ true
+ } else {
+ // Keep this layer if it exists in the new layer list.
+ let keep_layer = new_layers.iter().position(|properties| {
+ properties.id == extra_data.id
+ }).is_some();
+
+ // When removing a layer, clear any tiles and surfaces
+ // associated with the layer.
+ if !keep_layer {
+ child.clear_all_tiles(compositor);
+ }
+
+ keep_layer
+ }
+ });
+ }
+
/// Destroys all tiles of all layers, including children, *without* sending them back to the
/// painter. You must call this only when the paint task is destined to be going down;
/// otherwise, you will leak tiles.