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