mirror of
https://github.com/servo/servo.git
synced 2025-08-02 12:10:29 +01:00
auto merge of #4578 : mrobinson/servo/fix-compositor-timing-issues, r=larsbergstrom
Clean up compositor data structures and fix timing issues that cause Compositor panics.
This commit is contained in:
commit
c1d218cf02
2 changed files with 172 additions and 123 deletions
|
@ -19,7 +19,7 @@ use geom::rect::{Rect, TypedRect};
|
|||
use geom::size::TypedSize2D;
|
||||
use geom::scale_factor::ScaleFactor;
|
||||
use gfx::paint_task::Msg as PaintMsg;
|
||||
use gfx::paint_task::{PaintChan, PaintRequest};
|
||||
use gfx::paint_task::PaintRequest;
|
||||
use layers::geometry::{DevicePixel, LayerPixel};
|
||||
use layers::layers::{BufferRequest, Layer, LayerBufferSet};
|
||||
use layers::rendergl;
|
||||
|
@ -64,6 +64,9 @@ pub struct IOCompositor<Window: WindowMethods> {
|
|||
/// The root pipeline.
|
||||
root_pipeline: Option<CompositionPipeline>,
|
||||
|
||||
/// Tracks details about each active pipeline that the compositor knows about.
|
||||
pipeline_details: HashMap<PipelineId, PipelineDetails>,
|
||||
|
||||
/// The canvas to paint a page.
|
||||
scene: Scene<CompositorData>,
|
||||
|
||||
|
@ -102,12 +105,6 @@ pub struct IOCompositor<Window: WindowMethods> {
|
|||
/// The time of the last zoom action has started.
|
||||
zoom_time: f64,
|
||||
|
||||
/// Current display/reflow status of each pipeline.
|
||||
ready_states: HashMap<PipelineId, ReadyState>,
|
||||
|
||||
/// Current paint status of each pipeline.
|
||||
paint_states: HashMap<PipelineId, PaintState>,
|
||||
|
||||
/// Whether the page being rendered has loaded completely.
|
||||
/// Differs from ReadyState because we can finish loading (ready)
|
||||
/// many times for a single page.
|
||||
|
@ -130,9 +127,6 @@ pub struct IOCompositor<Window: WindowMethods> {
|
|||
|
||||
/// Pending scroll events.
|
||||
pending_scroll_events: Vec<ScrollEvent>,
|
||||
|
||||
/// PaintTask channels that we know about, used to return unused buffers.
|
||||
paint_channels: HashMap<PipelineId, PaintChan>,
|
||||
}
|
||||
|
||||
pub struct ScrollEvent {
|
||||
|
@ -159,6 +153,27 @@ struct HitTestResult {
|
|||
point: TypedPoint2D<LayerPixel, f32>,
|
||||
}
|
||||
|
||||
struct PipelineDetails {
|
||||
/// The pipeline associated with this PipelineDetails object.
|
||||
pipeline: Option<CompositionPipeline>,
|
||||
|
||||
/// The status of this pipeline's ScriptTask.
|
||||
ready_state: ReadyState,
|
||||
|
||||
/// The status of this pipeline's PaintTask.
|
||||
paint_state: PaintState,
|
||||
}
|
||||
|
||||
impl PipelineDetails {
|
||||
fn new() -> PipelineDetails {
|
||||
PipelineDetails {
|
||||
pipeline: None,
|
||||
ready_state: ReadyState::Blank,
|
||||
paint_state: PaintState::Painting,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Window: WindowMethods> IOCompositor<Window> {
|
||||
fn new(window: Rc<Window>,
|
||||
sender: Box<CompositorProxy+Send>,
|
||||
|
@ -178,6 +193,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
port: receiver,
|
||||
context: None,
|
||||
root_pipeline: None,
|
||||
pipeline_details: HashMap::new(),
|
||||
scene: Scene::new(Rect {
|
||||
origin: Point2D::zero(),
|
||||
size: window_size.as_f32(),
|
||||
|
@ -192,8 +208,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
viewport_zoom: ScaleFactor(1.0),
|
||||
zoom_action: false,
|
||||
zoom_time: 0f64,
|
||||
ready_states: HashMap::new(),
|
||||
paint_states: HashMap::new(),
|
||||
got_load_complete_message: false,
|
||||
got_set_frame_tree_message: false,
|
||||
constellation_chan: constellation_chan,
|
||||
|
@ -202,7 +216,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
fragment_point: None,
|
||||
outstanding_paint_msgs: 0,
|
||||
last_composite_time: 0,
|
||||
paint_channels: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,7 +360,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
}
|
||||
|
||||
(Msg::PaintTaskExited(pipeline_id), ShutdownState::NotShuttingDown) => {
|
||||
if self.paint_channels.remove(&pipeline_id).is_none() {
|
||||
if self.pipeline_details.remove(&pipeline_id).is_none() {
|
||||
panic!("Saw PaintTaskExited message from an unknown pipeline!");
|
||||
}
|
||||
}
|
||||
|
@ -362,14 +375,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
}
|
||||
|
||||
fn change_ready_state(&mut self, pipeline_id: PipelineId, ready_state: ReadyState) {
|
||||
match self.ready_states.entry(pipeline_id) {
|
||||
Occupied(entry) => {
|
||||
*entry.into_mut() = ready_state;
|
||||
}
|
||||
Vacant(entry) => {
|
||||
entry.set(ready_state);
|
||||
}
|
||||
}
|
||||
self.get_or_create_pipeline_details(pipeline_id).ready_state = ready_state;
|
||||
self.window.set_ready_state(self.get_earliest_pipeline_ready_state());
|
||||
|
||||
// If we're painting in headless mode, schedule a recomposite.
|
||||
|
@ -379,27 +385,43 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
}
|
||||
|
||||
fn get_earliest_pipeline_ready_state(&self) -> ReadyState {
|
||||
if self.ready_states.len() == 0 {
|
||||
if self.pipeline_details.len() == 0 {
|
||||
return ReadyState::Blank;
|
||||
}
|
||||
return self.ready_states.values().fold(ReadyState::FinishedLoading,
|
||||
|a, &b| cmp::min(a, b));
|
||||
|
||||
return self.pipeline_details.values().fold(ReadyState::FinishedLoading,
|
||||
|v, ref details| {
|
||||
cmp::min(v, details.ready_state)
|
||||
});
|
||||
}
|
||||
|
||||
fn change_paint_state(&mut self, pipeline_id: PipelineId, paint_state: PaintState) {
|
||||
match self.paint_states.entry(pipeline_id) {
|
||||
Occupied(entry) => {
|
||||
*entry.into_mut() = paint_state;
|
||||
}
|
||||
Vacant(entry) => {
|
||||
entry.set(paint_state);
|
||||
}
|
||||
}
|
||||
|
||||
self.get_or_create_pipeline_details(pipeline_id).paint_state = paint_state;
|
||||
self.window.set_paint_state(paint_state);
|
||||
}
|
||||
|
||||
pub fn get_or_create_pipeline_details<'a>(&'a mut self,
|
||||
pipeline_id: PipelineId)
|
||||
-> &'a mut PipelineDetails {
|
||||
if !self.pipeline_details.contains_key(&pipeline_id) {
|
||||
self.pipeline_details.insert(pipeline_id, PipelineDetails::new());
|
||||
}
|
||||
return self.pipeline_details.get_mut(&pipeline_id).unwrap();
|
||||
}
|
||||
|
||||
pub fn get_pipeline<'a>(&'a self, pipeline_id: PipelineId) -> &'a CompositionPipeline {
|
||||
match self.pipeline_details.get(&pipeline_id) {
|
||||
Some(ref details) => {
|
||||
match details.pipeline {
|
||||
Some(ref pipeline) => pipeline,
|
||||
None => panic!("Compositor layer has an unitialized pipeline ({}).",
|
||||
pipeline_id),
|
||||
|
||||
}
|
||||
}
|
||||
None => panic!("Compositor layer has an unknown pipeline ({}).", pipeline_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn change_page_title(&mut self, _: PipelineId, title: Option<String>) {
|
||||
self.window.set_page_title(title);
|
||||
}
|
||||
|
@ -409,10 +431,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
}
|
||||
|
||||
fn all_pipelines_in_idle_paint_state(&self) -> bool {
|
||||
if self.ready_states.len() == 0 {
|
||||
if self.pipeline_details.len() == 0 {
|
||||
return false;
|
||||
}
|
||||
return self.paint_states.values().all(|&value| value == PaintState::Idle);
|
||||
return self.pipeline_details.values().all(|ref details| {
|
||||
details.paint_state == PaintState::Idle
|
||||
});
|
||||
}
|
||||
|
||||
fn has_paint_msg_tracking(&self) -> bool {
|
||||
|
@ -454,7 +478,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
|
||||
// If we have an old root layer, release all old tiles before replacing it.
|
||||
match self.scene.root {
|
||||
Some(ref mut layer) => layer.clear_all_tiles(),
|
||||
Some(ref layer) => layer.clear_all_tiles(self),
|
||||
None => { }
|
||||
}
|
||||
self.scene.root = Some(self.create_frame_tree_root_layers(frame_tree, None));
|
||||
|
@ -481,13 +505,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
scroll_policy: ScrollPolicy::Scrollable,
|
||||
};
|
||||
|
||||
let root_layer = CompositorData::new_layer(pipeline.clone(),
|
||||
layer_properties,
|
||||
let root_layer = CompositorData::new_layer(layer_properties,
|
||||
WantsScrollEventsFlag::WantsScrollEvents,
|
||||
opts::get().tile_size);
|
||||
if !self.paint_channels.contains_key(&pipeline.id) {
|
||||
self.paint_channels.insert(pipeline.id, pipeline.paint_chan.clone());
|
||||
}
|
||||
|
||||
self.get_or_create_pipeline_details(pipeline.id).pipeline = Some(pipeline.clone());
|
||||
|
||||
// All root layers mask to bounds.
|
||||
*root_layer.masks_to_bounds.borrow_mut() = true;
|
||||
|
@ -504,10 +526,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
frame_tree: &SendableFrameTree,
|
||||
frame_rect: Option<TypedRect<PagePx, f32>>)
|
||||
-> Rc<Layer<CompositorData>> {
|
||||
// Initialize the ReadyState and PaintState for this pipeline.
|
||||
self.ready_states.insert(frame_tree.pipeline.id, ReadyState::Blank);
|
||||
self.paint_states.insert(frame_tree.pipeline.id, PaintState::Painting);
|
||||
|
||||
let root_layer = self.create_root_layer_for_pipeline_and_rect(&frame_tree.pipeline,
|
||||
frame_rect);
|
||||
for kid in frame_tree.children.iter() {
|
||||
|
@ -517,17 +535,25 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
}
|
||||
|
||||
fn update_frame_tree(&mut self, frame_tree_diff: &FrameTreeDiff) {
|
||||
let parent_layer = self.find_pipeline_root_layer(frame_tree_diff.parent_pipeline.id);
|
||||
let pipeline_id = frame_tree_diff.parent_pipeline.id;
|
||||
let parent_layer = match self.find_pipeline_root_layer(pipeline_id) {
|
||||
Some(root_layer) => root_layer,
|
||||
None => {
|
||||
debug!("Ignoring FrameTreeUpdate message for pipeline ({}) shutting down.",
|
||||
pipeline_id);
|
||||
return;
|
||||
}
|
||||
};
|
||||
parent_layer.add_child(
|
||||
self.create_root_layer_for_pipeline_and_rect(&frame_tree_diff.pipeline,
|
||||
frame_tree_diff.rect));
|
||||
}
|
||||
|
||||
fn find_pipeline_root_layer(&self, pipeline_id: PipelineId) -> Rc<Layer<CompositorData>> {
|
||||
match self.find_layer_with_pipeline_and_layer_id(pipeline_id, LayerId::null()) {
|
||||
Some(ref layer) => layer.clone(),
|
||||
None => panic!("Tried to create or update layer for unknown pipeline"),
|
||||
fn find_pipeline_root_layer(&self, pipeline_id: PipelineId) -> Option<Rc<Layer<CompositorData>>> {
|
||||
if !self.pipeline_details.contains_key(&pipeline_id) {
|
||||
panic!("Tried to create or update layer for unknown pipeline")
|
||||
}
|
||||
self.find_layer_with_pipeline_and_layer_id(pipeline_id, LayerId::null())
|
||||
}
|
||||
|
||||
fn update_layer_if_exists(&mut self, properties: LayerProperties) -> bool {
|
||||
|
@ -541,14 +567,21 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
}
|
||||
|
||||
fn create_or_update_base_layer(&mut self, layer_properties: LayerProperties) {
|
||||
let pipeline_id = layer_properties.pipeline_id;
|
||||
let root_layer = match self.find_pipeline_root_layer(pipeline_id) {
|
||||
Some(root_layer) => root_layer,
|
||||
None => {
|
||||
debug!("Ignoring CreateOrUpdateBaseLayer message for pipeline ({}) shutting down.",
|
||||
pipeline_id);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let need_new_base_layer = !self.update_layer_if_exists(layer_properties);
|
||||
if need_new_base_layer {
|
||||
let root_layer = self.find_pipeline_root_layer(layer_properties.pipeline_id);
|
||||
root_layer.update_layer_except_bounds(layer_properties);
|
||||
|
||||
let root_layer_pipeline = root_layer.extra_data.borrow().pipeline.clone();
|
||||
let base_layer = CompositorData::new_layer(
|
||||
root_layer_pipeline.clone(),
|
||||
layer_properties,
|
||||
WantsScrollEventsFlag::DoesntWantScrollEvents,
|
||||
opts::get().tile_size);
|
||||
|
@ -575,10 +608,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
}
|
||||
|
||||
fn create_descendant_layer(&self, layer_properties: LayerProperties) {
|
||||
let root_layer = self.find_pipeline_root_layer(layer_properties.pipeline_id);
|
||||
let root_layer_pipeline = root_layer.extra_data.borrow().pipeline.clone();
|
||||
let new_layer = CompositorData::new_layer(root_layer_pipeline,
|
||||
layer_properties,
|
||||
let root_layer = match self.find_pipeline_root_layer(layer_properties.pipeline_id) {
|
||||
Some(root_layer) => root_layer,
|
||||
None => return, // This pipeline is in the process of shutting down.
|
||||
};
|
||||
|
||||
let new_layer = CompositorData::new_layer(layer_properties,
|
||||
WantsScrollEventsFlag::DoesntWantScrollEvents,
|
||||
root_layer.tile_size);
|
||||
root_layer.add_child(new_layer);
|
||||
|
@ -660,17 +695,16 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
new_layer_buffer_set: Box<LayerBufferSet>,
|
||||
epoch: Epoch) {
|
||||
match self.find_layer_with_pipeline_and_layer_id(pipeline_id, layer_id) {
|
||||
Some(layer) => self.assign_painted_buffers_to_layer(layer, new_layer_buffer_set, epoch),
|
||||
None => {
|
||||
match self.paint_channels.entry(pipeline_id) {
|
||||
Occupied(entry) => {
|
||||
let message = PaintMsg::UnusedBuffer(new_layer_buffer_set.buffers);
|
||||
let _ = entry.get().send_opt(message);
|
||||
},
|
||||
Vacant(_) => panic!("Received a buffer from an unknown pipeline!"),
|
||||
}
|
||||
Some(layer) => {
|
||||
self.assign_painted_buffers_to_layer(layer, new_layer_buffer_set, epoch);
|
||||
return;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
let pipeline = self.get_pipeline(pipeline_id);
|
||||
let message = PaintMsg::UnusedBuffer(new_layer_buffer_set.buffers);
|
||||
let _ = pipeline.paint_chan.send_opt(message);
|
||||
}
|
||||
|
||||
fn assign_painted_buffers_to_layer(&mut self,
|
||||
|
@ -687,7 +721,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
|
||||
// FIXME(pcwalton): This is going to cause problems with inconsistent frames since
|
||||
// we only composite one layer at a time.
|
||||
assert!(layer.add_buffers(new_layer_buffer_set, epoch));
|
||||
assert!(layer.add_buffers(self, new_layer_buffer_set, epoch));
|
||||
self.composite_if_necessary();
|
||||
}
|
||||
|
||||
|
@ -785,7 +819,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
debug!("osmain: loading URL `{}`", url_string);
|
||||
self.got_load_complete_message = false;
|
||||
let root_pipeline_id = match self.scene.root {
|
||||
Some(ref layer) => layer.extra_data.borrow().pipeline.id.clone(),
|
||||
Some(ref layer) => layer.get_pipeline_id(),
|
||||
None => panic!("Compositor: Received WindowEvent::LoadUrl without initialized compositor \
|
||||
layers"),
|
||||
};
|
||||
|
@ -803,14 +837,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
MouseWindowEvent::MouseUp(_, p) => p,
|
||||
};
|
||||
match self.find_topmost_layer_at_point(point / self.scene.scale) {
|
||||
Some(result) => result.layer.send_mouse_event(mouse_window_event, result.point),
|
||||
Some(result) => result.layer.send_mouse_event(self, mouse_window_event, result.point),
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn on_mouse_window_move_event_class(&self, cursor: TypedPoint2D<DevicePixel, f32>) {
|
||||
match self.find_topmost_layer_at_point(cursor / self.scene.scale) {
|
||||
Some(result) => result.layer.send_mouse_move_event(result.point),
|
||||
Some(result) => result.layer.send_mouse_move_event(self, result.point),
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
|
@ -922,25 +956,21 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
|
||||
fn convert_buffer_requests_to_pipeline_requests_map(&self,
|
||||
requests: Vec<(Rc<Layer<CompositorData>>,
|
||||
Vec<BufferRequest>)>) ->
|
||||
HashMap<PipelineId, (PaintChan,
|
||||
Vec<PaintRequest>)> {
|
||||
Vec<BufferRequest>)>)
|
||||
-> HashMap<PipelineId, Vec<PaintRequest>> {
|
||||
let scale = self.device_pixels_per_page_px();
|
||||
let mut results:
|
||||
HashMap<PipelineId, (PaintChan, Vec<PaintRequest>)> = HashMap::new();
|
||||
let mut results: HashMap<PipelineId, Vec<PaintRequest>> = HashMap::new();
|
||||
|
||||
for (layer, mut layer_requests) in requests.into_iter() {
|
||||
let &(_, ref mut vec) =
|
||||
match results.entry(layer.extra_data.borrow().pipeline.id) {
|
||||
Occupied(mut entry) => {
|
||||
*entry.get_mut() =
|
||||
(layer.extra_data.borrow().pipeline.paint_chan.clone(), vec!());
|
||||
entry.into_mut()
|
||||
}
|
||||
Vacant(entry) => {
|
||||
entry.set((layer.extra_data.borrow().pipeline.paint_chan.clone(), vec!()))
|
||||
}
|
||||
};
|
||||
let vec = match results.entry(layer.get_pipeline_id()) {
|
||||
Occupied(mut entry) => {
|
||||
*entry.get_mut() = Vec::new();
|
||||
entry.into_mut()
|
||||
}
|
||||
Vacant(entry) => {
|
||||
entry.set(Vec::new())
|
||||
}
|
||||
};
|
||||
|
||||
// All the BufferRequests are in layer/device coordinates, but the paint task
|
||||
// wants to know the page coordinates. We scale them before sending them.
|
||||
|
@ -976,7 +1006,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
if layer.extra_data.borrow().id == LayerId::null() {
|
||||
let layer_rect = Rect(-layer.extra_data.borrow().scroll_offset.to_untyped(),
|
||||
layer.bounds.borrow().size.to_untyped());
|
||||
let pipeline = &layer.extra_data.borrow().pipeline;
|
||||
let pipeline = self.get_pipeline(layer.get_pipeline_id());
|
||||
let ScriptControlChan(ref chan) = pipeline.script_chan;
|
||||
chan.send(ConstellationControlMsg::Viewport(pipeline.id.clone(), layer_rect));
|
||||
}
|
||||
|
@ -1012,9 +1042,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.convert_buffer_requests_to_pipeline_requests_map(layers_and_requests);
|
||||
|
||||
let mut num_paint_msgs_sent = 0;
|
||||
for (_pipeline_id, (chan, requests)) in pipeline_requests.into_iter() {
|
||||
for (pipeline_id, requests) in pipeline_requests.into_iter() {
|
||||
num_paint_msgs_sent += 1;
|
||||
let _ = chan.send_opt(PaintMsg::Paint(requests));
|
||||
let _ = self.get_pipeline(pipeline_id).paint_chan.send_opt(PaintMsg::Paint(requests));
|
||||
}
|
||||
|
||||
self.add_outstanding_paint_msg(num_paint_msgs_sent);
|
||||
|
@ -1232,7 +1262,7 @@ fn find_layer_with_pipeline_and_layer_id_for_layer(layer: Rc<Layer<CompositorDat
|
|||
pipeline_id: PipelineId,
|
||||
layer_id: LayerId)
|
||||
-> Option<Rc<Layer<CompositorData>>> {
|
||||
if layer.extra_data.borrow().pipeline.id == pipeline_id &&
|
||||
if layer.extra_data.borrow().pipeline_id == pipeline_id &&
|
||||
layer.extra_data.borrow().id == layer_id {
|
||||
return Some(layer);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use compositor_task::LayerProperties;
|
||||
use pipeline::CompositionPipeline;
|
||||
use compositor::IOCompositor;
|
||||
use windowing::{MouseWindowEvent, WindowMethods};
|
||||
|
||||
use azure::azure_hl;
|
||||
|
@ -20,13 +20,15 @@ use layers::platform::surface::NativeSurfaceMethods;
|
|||
use script_traits::CompositorEvent::{ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent};
|
||||
use script_traits::{ScriptControlChan, ConstellationControlMsg};
|
||||
use servo_msg::compositor_msg::{Epoch, LayerId, ScrollPolicy};
|
||||
use servo_msg::constellation_msg::PipelineId;
|
||||
use std::num::Float;
|
||||
use std::num::FloatMath;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct CompositorData {
|
||||
/// This layer's pipeline. BufferRequests and mouse events will be sent through this.
|
||||
pub pipeline: CompositionPipeline,
|
||||
/// This layer's pipeline id. The compositor can associate this id with an
|
||||
/// actual CompositionPipeline.
|
||||
pub pipeline_id: PipelineId,
|
||||
|
||||
/// The ID of this layer within the pipeline.
|
||||
pub id: LayerId,
|
||||
|
@ -47,13 +49,12 @@ pub struct CompositorData {
|
|||
}
|
||||
|
||||
impl CompositorData {
|
||||
pub fn new_layer(pipeline: CompositionPipeline,
|
||||
layer_properties: LayerProperties,
|
||||
pub fn new_layer(layer_properties: LayerProperties,
|
||||
wants_scroll_events: WantsScrollEventsFlag,
|
||||
tile_size: uint)
|
||||
-> Rc<Layer<CompositorData>> {
|
||||
let new_compositor_data = CompositorData {
|
||||
pipeline: pipeline,
|
||||
pipeline_id: layer_properties.pipeline_id,
|
||||
id: layer_properties.id,
|
||||
wants_scroll_events: wants_scroll_events,
|
||||
scroll_policy: layer_properties.scroll_policy,
|
||||
|
@ -68,20 +69,24 @@ impl CompositorData {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait CompositorLayer {
|
||||
pub trait CompositorLayer<Window: WindowMethods> {
|
||||
fn update_layer_except_bounds(&self, layer_properties: LayerProperties);
|
||||
|
||||
fn update_layer(&self, layer_properties: LayerProperties);
|
||||
|
||||
fn add_buffers(&self, new_buffers: Box<LayerBufferSet>, epoch: Epoch) -> bool;
|
||||
fn add_buffers(&self,
|
||||
compositor: &IOCompositor<Window>,
|
||||
new_buffers: Box<LayerBufferSet>,
|
||||
epoch: Epoch)
|
||||
-> bool;
|
||||
|
||||
/// Destroys all layer tiles, sending the buffers back to the painter to be destroyed or
|
||||
/// reused.
|
||||
fn clear(&self);
|
||||
fn clear(&self, compositor: &IOCompositor<Window>);
|
||||
|
||||
/// Destroys tiles for this layer and all descendent layers, sending the buffers back to the
|
||||
/// painter to be destroyed or reused.
|
||||
fn clear_all_tiles(&self);
|
||||
fn clear_all_tiles(&self, compositor: &IOCompositor<Window>);
|
||||
|
||||
/// 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;
|
||||
|
@ -104,10 +109,12 @@ pub trait CompositorLayer {
|
|||
// sends the event off to the appropriate pipeline. NB: the cursor position is in
|
||||
// page coordinates.
|
||||
fn send_mouse_event(&self,
|
||||
compositor: &IOCompositor<Window>,
|
||||
event: MouseWindowEvent,
|
||||
cursor: TypedPoint2D<LayerPixel, f32>);
|
||||
|
||||
fn send_mouse_move_event(&self,
|
||||
compositor: &IOCompositor<Window>,
|
||||
cursor: TypedPoint2D<LayerPixel, f32>);
|
||||
|
||||
fn clamp_scroll_offset_and_scroll_layer(&self,
|
||||
|
@ -120,6 +127,9 @@ pub trait CompositorLayer {
|
|||
|
||||
/// Return a flag describing how this layer deals with scroll events.
|
||||
fn wants_scroll_events(&self) -> WantsScrollEventsFlag;
|
||||
|
||||
/// Return the pipeline id associated with this layer.
|
||||
fn get_pipeline_id(&self) -> PipelineId;
|
||||
}
|
||||
|
||||
#[deriving(Copy, PartialEq, Clone)]
|
||||
|
@ -165,7 +175,7 @@ pub enum ScrollEventResult {
|
|||
ScrollPositionUnchanged,
|
||||
}
|
||||
|
||||
impl CompositorLayer for Layer<CompositorData> {
|
||||
impl<Window: WindowMethods> CompositorLayer<Window> for Layer<CompositorData> {
|
||||
fn update_layer_except_bounds(&self, layer_properties: LayerProperties) {
|
||||
self.extra_data.borrow_mut().epoch = layer_properties.epoch;
|
||||
self.extra_data.borrow_mut().scroll_policy = layer_properties.scroll_policy;
|
||||
|
@ -190,33 +200,35 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
//
|
||||
// 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.
|
||||
fn add_buffers(&self, new_buffers: Box<LayerBufferSet>, epoch: Epoch) -> bool {
|
||||
fn add_buffers(&self,
|
||||
compositor: &IOCompositor<Window>,
|
||||
new_buffers: Box<LayerBufferSet>,
|
||||
epoch: Epoch)
|
||||
-> bool {
|
||||
if self.extra_data.borrow().epoch != epoch {
|
||||
debug!("add_buffers: compositor epoch mismatch: {} != {}, id: {}",
|
||||
self.extra_data.borrow().epoch,
|
||||
epoch,
|
||||
self.extra_data.borrow().pipeline.id);
|
||||
let msg = PaintMsg::UnusedBuffer(new_buffers.buffers);
|
||||
let _ = self.extra_data.borrow().pipeline.paint_chan.send_opt(msg);
|
||||
self.get_pipeline_id());
|
||||
let pipeline = compositor.get_pipeline(self.get_pipeline_id());
|
||||
let _ = pipeline.paint_chan.send_opt(PaintMsg::UnusedBuffer(new_buffers.buffers));
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
for buffer in new_buffers.buffers.into_iter().rev() {
|
||||
self.add_buffer(buffer);
|
||||
}
|
||||
for buffer in new_buffers.buffers.into_iter().rev() {
|
||||
self.add_buffer(buffer);
|
||||
}
|
||||
|
||||
let unused_buffers = self.collect_unused_buffers();
|
||||
if !unused_buffers.is_empty() { // send back unused buffers
|
||||
let msg = PaintMsg::UnusedBuffer(unused_buffers);
|
||||
let _ = self.extra_data.borrow().pipeline.paint_chan.send_opt(msg);
|
||||
}
|
||||
let unused_buffers = self.collect_unused_buffers();
|
||||
if !unused_buffers.is_empty() { // send back unused buffers
|
||||
let pipeline = compositor.get_pipeline(self.get_pipeline_id());
|
||||
let _ = pipeline.paint_chan.send_opt(PaintMsg::UnusedBuffer(unused_buffers));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn clear(&self) {
|
||||
fn clear(&self, compositor: &IOCompositor<Window>) {
|
||||
let mut buffers = self.collect_buffers();
|
||||
|
||||
if !buffers.is_empty() {
|
||||
|
@ -227,16 +239,17 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
buffer.mark_wont_leak()
|
||||
}
|
||||
|
||||
let _ = self.extra_data.borrow().pipeline.paint_chan.send_opt(PaintMsg::UnusedBuffer(buffers));
|
||||
let pipeline = compositor.get_pipeline(self.get_pipeline_id());
|
||||
let _ = pipeline.paint_chan.send_opt(PaintMsg::UnusedBuffer(buffers));
|
||||
}
|
||||
}
|
||||
|
||||
/// Destroys tiles for this layer and all descendent layers, sending the buffers back to the
|
||||
/// painter to be destroyed or reused.
|
||||
fn clear_all_tiles(&self) {
|
||||
self.clear();
|
||||
fn clear_all_tiles(&self, compositor: &IOCompositor<Window>) {
|
||||
self.clear(compositor);
|
||||
for kid in self.children().iter() {
|
||||
kid.clear_all_tiles();
|
||||
kid.clear_all_tiles(compositor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,6 +327,7 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
}
|
||||
|
||||
fn send_mouse_event(&self,
|
||||
compositor: &IOCompositor<Window>,
|
||||
event: MouseWindowEvent,
|
||||
cursor: TypedPoint2D<LayerPixel, f32>) {
|
||||
let event_point = cursor.to_untyped();
|
||||
|
@ -325,15 +339,17 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
MouseWindowEvent::MouseUp(button, _) =>
|
||||
MouseUpEvent(button, event_point),
|
||||
};
|
||||
let pipeline = &self.extra_data.borrow().pipeline;
|
||||
|
||||
let pipeline = compositor.get_pipeline(self.get_pipeline_id());
|
||||
let ScriptControlChan(ref chan) = pipeline.script_chan;
|
||||
let _ = chan.send_opt(ConstellationControlMsg::SendEvent(pipeline.id.clone(), message));
|
||||
}
|
||||
|
||||
fn send_mouse_move_event(&self,
|
||||
compositor: &IOCompositor<Window>,
|
||||
cursor: TypedPoint2D<LayerPixel, f32>) {
|
||||
let message = MouseMoveEvent(cursor.to_untyped());
|
||||
let pipeline = &self.extra_data.borrow().pipeline;
|
||||
let pipeline = compositor.get_pipeline(self.get_pipeline_id());
|
||||
let ScriptControlChan(ref chan) = pipeline.script_chan;
|
||||
let _ = chan.send_opt(ConstellationControlMsg::SendEvent(pipeline.id.clone(), message));
|
||||
}
|
||||
|
@ -362,4 +378,7 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
self.extra_data.borrow().wants_scroll_events
|
||||
}
|
||||
|
||||
fn get_pipeline_id(&self) -> PipelineId {
|
||||
self.extra_data.borrow().pipeline_id
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue