mirror of
https://github.com/servo/servo.git
synced 2025-06-24 00:54:32 +01:00
Instead of relying on a scene-wide background color, all layers can now have their own background color.
196 lines
7.7 KiB
Rust
196 lines
7.7 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* 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::LayerProperties;
|
|
use events;
|
|
use pipeline::CompositionPipeline;
|
|
|
|
use azure::azure_hl;
|
|
use geom::point::TypedPoint2D;
|
|
use geom::size::Size2D;
|
|
use geom::rect::Rect;
|
|
use gfx::render_task::UnusedBufferMsg;
|
|
use layers::color::Color;
|
|
use layers::geometry::LayerPixel;
|
|
use layers::layers::{Layer, LayerBufferSet};
|
|
use layers::platform::surface::NativeSurfaceMethods;
|
|
use servo_msg::compositor_msg::{Epoch, LayerId};
|
|
use servo_msg::compositor_msg::ScrollPolicy;
|
|
use servo_msg::constellation_msg::PipelineId;
|
|
use std::rc::Rc;
|
|
|
|
pub struct CompositorData {
|
|
/// This layer's pipeline. BufferRequests and mouse events will be sent through this.
|
|
pub pipeline: CompositionPipeline,
|
|
|
|
/// The ID of this layer within the pipeline.
|
|
pub id: LayerId,
|
|
|
|
/// The behavior of this layer when a scroll message is received.
|
|
pub wants_scroll_events: WantsScrollEventsFlag,
|
|
|
|
/// Whether an ancestor layer that receives scroll events moves this layer.
|
|
pub scroll_policy: ScrollPolicy,
|
|
|
|
/// A monotonically increasing counter that keeps track of the current epoch.
|
|
/// add_buffer() calls that don't match the current epoch will be ignored.
|
|
pub epoch: Epoch,
|
|
|
|
/// The scroll offset originating from this scrolling root. This allows scrolling roots
|
|
/// to track their current scroll position even while their content_offset does not change.
|
|
pub scroll_offset: TypedPoint2D<LayerPixel, f32>,
|
|
}
|
|
|
|
#[deriving(PartialEq, Clone)]
|
|
pub enum WantsScrollEventsFlag {
|
|
WantsScrollEvents,
|
|
DoesntWantScrollEvents,
|
|
}
|
|
|
|
fn to_layers_color(color: &azure_hl::Color) -> Color {
|
|
Color { r: color.r, g: color.g, b: color.b, a: color.a }
|
|
}
|
|
|
|
impl CompositorData {
|
|
pub fn new_layer(pipeline: CompositionPipeline,
|
|
layer_properties: LayerProperties,
|
|
wants_scroll_events: WantsScrollEventsFlag,
|
|
tile_size: uint)
|
|
-> Rc<Layer<CompositorData>> {
|
|
let new_compositor_data = CompositorData {
|
|
pipeline: pipeline,
|
|
id: layer_properties.id,
|
|
wants_scroll_events: wants_scroll_events,
|
|
scroll_policy: layer_properties.scroll_policy,
|
|
epoch: layer_properties.epoch,
|
|
scroll_offset: TypedPoint2D(0., 0.),
|
|
};
|
|
|
|
Rc::new(Layer::new(Rect::from_untyped(&layer_properties.rect),
|
|
tile_size,
|
|
to_layers_color(&layer_properties.background_color),
|
|
new_compositor_data))
|
|
}
|
|
|
|
pub fn update_layer_except_size(layer: Rc<Layer<CompositorData>>,
|
|
layer_properties: LayerProperties) {
|
|
layer.extra_data.borrow_mut().epoch = layer_properties.epoch;
|
|
layer.extra_data.borrow_mut().scroll_policy = layer_properties.scroll_policy;
|
|
|
|
*layer.background_color.borrow_mut() = to_layers_color(&layer_properties.background_color);
|
|
|
|
layer.contents_changed();
|
|
}
|
|
|
|
pub fn update_layer(layer: Rc<Layer<CompositorData>>, layer_properties: LayerProperties) {
|
|
layer.resize(Size2D::from_untyped(&layer_properties.rect.size));
|
|
|
|
// 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.
|
|
events::handle_scroll_event(layer.clone(),
|
|
TypedPoint2D(0f32, 0f32),
|
|
TypedPoint2D(-1f32, -1f32));
|
|
CompositorData::update_layer_except_size(layer, layer_properties);
|
|
}
|
|
|
|
pub fn find_layer_with_pipeline_and_layer_id(layer: Rc<Layer<CompositorData>>,
|
|
pipeline_id: PipelineId,
|
|
layer_id: LayerId)
|
|
-> Option<Rc<Layer<CompositorData>>> {
|
|
if layer.extra_data.borrow().pipeline.id == pipeline_id &&
|
|
layer.extra_data.borrow().id == layer_id {
|
|
return Some(layer.clone());
|
|
}
|
|
|
|
for kid in layer.children().iter() {
|
|
match CompositorData::find_layer_with_pipeline_and_layer_id(kid.clone(),
|
|
pipeline_id,
|
|
layer_id) {
|
|
v @ Some(_) => { return v; }
|
|
None => { }
|
|
}
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
// Add LayerBuffers to the specified layer. Returns the layer buffer set back if the layer that
|
|
// matches the given pipeline ID was not found; otherwise returns None and consumes the layer
|
|
// buffer set.
|
|
//
|
|
// If the epoch of the message does not match the layer's epoch, the message is ignored, the
|
|
// layer buffer set is consumed, and None is returned.
|
|
pub fn add_buffers(layer: Rc<Layer<CompositorData>>,
|
|
new_buffers: Box<LayerBufferSet>,
|
|
epoch: Epoch)
|
|
-> bool {
|
|
if layer.extra_data.borrow().epoch != epoch {
|
|
debug!("add_buffers: compositor epoch mismatch: {:?} != {:?}, id: {:?}",
|
|
layer.extra_data.borrow().epoch,
|
|
epoch,
|
|
layer.extra_data.borrow().pipeline.id);
|
|
let msg = UnusedBufferMsg(new_buffers.buffers);
|
|
let _ = layer.extra_data.borrow().pipeline.render_chan.send_opt(msg);
|
|
return false;
|
|
}
|
|
|
|
{
|
|
for buffer in new_buffers.buffers.into_iter().rev() {
|
|
layer.add_buffer(buffer);
|
|
}
|
|
|
|
let unused_buffers = layer.collect_unused_buffers();
|
|
if !unused_buffers.is_empty() { // send back unused buffers
|
|
let msg = UnusedBufferMsg(unused_buffers);
|
|
let _ = layer.extra_data.borrow().pipeline.render_chan.send_opt(msg);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Destroys all layer tiles, sending the buffers back to the renderer to be destroyed or
|
|
/// reused.
|
|
fn clear(layer: Rc<Layer<CompositorData>>) {
|
|
let mut buffers = layer.collect_buffers();
|
|
|
|
if !buffers.is_empty() {
|
|
// We have no way of knowing without a race whether the render task is even up and
|
|
// running, but mark the buffers as not leaking. If the render task died, then the
|
|
// buffers are going to be cleaned up.
|
|
for buffer in buffers.iter_mut() {
|
|
buffer.mark_wont_leak()
|
|
}
|
|
|
|
let _ = layer.extra_data.borrow().pipeline.render_chan.send_opt(UnusedBufferMsg(buffers));
|
|
}
|
|
}
|
|
|
|
/// Destroys tiles for this layer and all descendent layers, sending the buffers back to the
|
|
/// renderer to be destroyed or reused.
|
|
pub fn clear_all_tiles(layer: Rc<Layer<CompositorData>>) {
|
|
CompositorData::clear(layer.clone());
|
|
for kid in layer.children().iter() {
|
|
CompositorData::clear_all_tiles(kid.clone());
|
|
}
|
|
}
|
|
|
|
/// Destroys all tiles of all layers, including children, *without* sending them back to the
|
|
/// renderer. You must call this only when the render task is destined to be going down;
|
|
/// otherwise, you will leak tiles.
|
|
///
|
|
/// This is used during shutdown, when we know the render task is going away.
|
|
pub fn forget_all_tiles(layer: Rc<Layer<CompositorData>>) {
|
|
let tiles = layer.collect_buffers();
|
|
for tile in tiles.into_iter() {
|
|
let mut tile = tile;
|
|
tile.mark_wont_leak()
|
|
}
|
|
|
|
for kid in layer.children().iter() {
|
|
CompositorData::forget_all_tiles(kid.clone());
|
|
}
|
|
}
|
|
}
|
|
|