mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Combine events and CompositorData methods into CompositorLayer
This is a more natural collection of methods, as they all operate directly on layers and accept a layer as their first argument.
This commit is contained in:
parent
96f6c53b52
commit
c0fa32e7aa
4 changed files with 279 additions and 280 deletions
|
@ -2,13 +2,13 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use compositor_data::{CompositorData, DoesntWantScrollEvents, WantsScrollEvents};
|
use compositor_data::{CompositorData, CompositorLayer, DoesntWantScrollEvents};
|
||||||
|
use compositor_data::{ScrollPositionChanged, WantsScrollEvents};
|
||||||
use compositor_task::{Msg, CompositorTask, Exit, ChangeReadyState, SetIds, LayerProperties};
|
use compositor_task::{Msg, CompositorTask, Exit, ChangeReadyState, SetIds, LayerProperties};
|
||||||
use compositor_task::{GetGraphicsMetadata, CreateOrUpdateRootLayer, CreateOrUpdateDescendantLayer};
|
use compositor_task::{GetGraphicsMetadata, CreateOrUpdateRootLayer, CreateOrUpdateDescendantLayer};
|
||||||
use compositor_task::{SetLayerOrigin, Paint, ScrollFragmentPoint, LoadComplete};
|
use compositor_task::{SetLayerOrigin, Paint, ScrollFragmentPoint, LoadComplete};
|
||||||
use compositor_task::{ShutdownComplete, ChangeRenderState, RenderMsgDiscarded};
|
use compositor_task::{ShutdownComplete, ChangeRenderState, RenderMsgDiscarded};
|
||||||
use constellation::SendableFrameTree;
|
use constellation::SendableFrameTree;
|
||||||
use events::{LayerEventHandling, ScrollPositionChanged};
|
|
||||||
use pipeline::CompositionPipeline;
|
use pipeline::CompositionPipeline;
|
||||||
use windowing;
|
use windowing;
|
||||||
use windowing::{FinishedWindowEvent, IdleWindowEvent, LoadUrlWindowEvent, MouseWindowClickEvent};
|
use windowing::{FinishedWindowEvent, IdleWindowEvent, LoadUrlWindowEvent, MouseWindowClickEvent};
|
||||||
|
@ -237,7 +237,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
// Clear out the compositor layers so that painting tasks can destroy the buffers.
|
// Clear out the compositor layers so that painting tasks can destroy the buffers.
|
||||||
match self.scene.root {
|
match self.scene.root {
|
||||||
None => {}
|
None => {}
|
||||||
Some(ref layer) => CompositorData::forget_all_tiles(layer.clone()),
|
Some(ref layer) => layer.forget_all_tiles(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drain compositor port, sometimes messages contain channels that are blocking
|
// Drain compositor port, sometimes messages contain channels that are blocking
|
||||||
|
@ -407,7 +407,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) => CompositorData::clear_all_tiles(layer.clone()),
|
Some(ref mut layer) => layer.clear_all_tiles(),
|
||||||
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));
|
||||||
|
@ -455,21 +455,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
return root_layer;
|
return root_layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_layer_with_pipeline_and_layer_id(&self,
|
|
||||||
pipeline_id: PipelineId,
|
|
||||||
layer_id: LayerId)
|
|
||||||
-> Option<Rc<Layer<CompositorData>>> {
|
|
||||||
match self.scene.root {
|
|
||||||
Some(ref root_layer) => {
|
|
||||||
CompositorData::find_layer_with_pipeline_and_layer_id(root_layer.clone(),
|
|
||||||
pipeline_id,
|
|
||||||
layer_id)
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_pipeline_root_layer(&self, pipeline_id: PipelineId) -> Rc<Layer<CompositorData>> {
|
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()) {
|
match self.find_layer_with_pipeline_and_layer_id(pipeline_id, LayerId::null()) {
|
||||||
Some(ref layer) => layer.clone(),
|
Some(ref layer) => layer.clone(),
|
||||||
|
@ -480,7 +465,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
fn update_layer_if_exists(&mut self, properties: LayerProperties) -> bool {
|
fn update_layer_if_exists(&mut self, properties: LayerProperties) -> bool {
|
||||||
match self.find_layer_with_pipeline_and_layer_id(properties.pipeline_id, properties.id) {
|
match self.find_layer_with_pipeline_and_layer_id(properties.pipeline_id, properties.id) {
|
||||||
Some(existing_layer) => {
|
Some(existing_layer) => {
|
||||||
CompositorData::update_layer(existing_layer.clone(), properties);
|
existing_layer.update_layer(properties);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
None => false,
|
None => false,
|
||||||
|
@ -491,7 +476,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
let need_new_root_layer = !self.update_layer_if_exists(layer_properties);
|
let need_new_root_layer = !self.update_layer_if_exists(layer_properties);
|
||||||
if need_new_root_layer {
|
if need_new_root_layer {
|
||||||
let root_layer = self.find_pipeline_root_layer(layer_properties.pipeline_id);
|
let root_layer = self.find_pipeline_root_layer(layer_properties.pipeline_id);
|
||||||
CompositorData::update_layer_except_size(root_layer.clone(), layer_properties);
|
root_layer.update_layer_except_size(layer_properties);
|
||||||
|
|
||||||
let root_layer_pipeline = root_layer.extra_data.borrow().pipeline.clone();
|
let root_layer_pipeline = root_layer.extra_data.borrow().pipeline.clone();
|
||||||
let first_child = CompositorData::new_layer(root_layer_pipeline.clone(),
|
let first_child = CompositorData::new_layer(root_layer_pipeline.clone(),
|
||||||
|
@ -602,7 +587,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
|
|
||||||
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(ref layer) => {
|
Some(ref layer) => {
|
||||||
assert!(CompositorData::add_buffers(layer.clone(), new_layer_buffer_set, epoch));
|
assert!(layer.add_buffers(new_layer_buffer_set, epoch));
|
||||||
self.recomposite = true;
|
self.recomposite = true;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -1032,4 +1017,39 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_layer_with_pipeline_and_layer_id(&self,
|
||||||
|
pipeline_id: PipelineId,
|
||||||
|
layer_id: LayerId)
|
||||||
|
-> Option<Rc<Layer<CompositorData>>> {
|
||||||
|
match self.scene.root {
|
||||||
|
Some(ref layer) =>
|
||||||
|
find_layer_with_pipeline_and_layer_id_for_layer(layer.clone(),
|
||||||
|
pipeline_id,
|
||||||
|
layer_id),
|
||||||
|
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_layer_with_pipeline_and_layer_id_for_layer(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
for kid in layer.children().iter() {
|
||||||
|
let result = find_layer_with_pipeline_and_layer_id_for_layer(kid.clone(),
|
||||||
|
pipeline_id,
|
||||||
|
layer_id);
|
||||||
|
if result.is_some() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,21 +3,25 @@
|
||||||
* 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 events::LayerEventHandling;
|
|
||||||
use pipeline::CompositionPipeline;
|
use pipeline::CompositionPipeline;
|
||||||
|
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent};
|
||||||
|
use windowing::MouseWindowMouseUpEvent;
|
||||||
|
use windowing::WindowMethods;
|
||||||
|
|
||||||
use azure::azure_hl;
|
use azure::azure_hl;
|
||||||
use geom::point::TypedPoint2D;
|
use geom::length::Length;
|
||||||
use geom::size::Size2D;
|
use geom::matrix::identity;
|
||||||
|
use geom::point::{Point2D, TypedPoint2D};
|
||||||
|
use geom::size::{Size2D, TypedSize2D};
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use gfx::render_task::UnusedBufferMsg;
|
use gfx::render_task::UnusedBufferMsg;
|
||||||
use layers::color::Color;
|
use layers::color::Color;
|
||||||
use layers::geometry::LayerPixel;
|
use layers::geometry::LayerPixel;
|
||||||
use layers::layers::{Layer, LayerBufferSet};
|
use layers::layers::{Layer, LayerBufferSet};
|
||||||
use layers::platform::surface::NativeSurfaceMethods;
|
use layers::platform::surface::NativeSurfaceMethods;
|
||||||
use servo_msg::compositor_msg::{Epoch, LayerId};
|
use script_traits::{ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent, SendEventMsg};
|
||||||
use servo_msg::compositor_msg::ScrollPolicy;
|
use script_traits::{ScriptControlChan};
|
||||||
use servo_msg::constellation_msg::PipelineId;
|
use servo_msg::compositor_msg::{Epoch, FixedPosition, LayerId, ScrollPolicy};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct CompositorData {
|
pub struct CompositorData {
|
||||||
|
@ -42,16 +46,6 @@ pub struct CompositorData {
|
||||||
pub scroll_offset: TypedPoint2D<LayerPixel, f32>,
|
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 {
|
impl CompositorData {
|
||||||
pub fn new_layer(pipeline: CompositionPipeline,
|
pub fn new_layer(pipeline: CompositionPipeline,
|
||||||
layer_properties: LayerProperties,
|
layer_properties: LayerProperties,
|
||||||
|
@ -72,45 +66,119 @@ impl CompositorData {
|
||||||
to_layers_color(&layer_properties.background_color),
|
to_layers_color(&layer_properties.background_color),
|
||||||
new_compositor_data))
|
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) {
|
pub trait CompositorLayer {
|
||||||
layer.resize(Size2D::from_untyped(&layer_properties.rect.size));
|
fn update_layer_except_size(&self, layer_properties: LayerProperties);
|
||||||
|
|
||||||
|
fn update_layer(&self, layer_properties: LayerProperties);
|
||||||
|
|
||||||
|
fn add_buffers(&self, new_buffers: Box<LayerBufferSet>, epoch: Epoch) -> bool;
|
||||||
|
|
||||||
|
/// Destroys all layer tiles, sending the buffers back to the renderer to be destroyed or
|
||||||
|
/// reused.
|
||||||
|
fn clear(&self);
|
||||||
|
|
||||||
|
/// Destroys tiles for this layer and all descendent layers, sending the buffers back to the
|
||||||
|
/// renderer to be destroyed or reused.
|
||||||
|
fn clear_all_tiles(&self);
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
fn forget_all_tiles(&self);
|
||||||
|
|
||||||
|
/// Move the layer's descendants that don't want scroll events and scroll by a relative
|
||||||
|
/// specified amount in page coordinates. This also takes in a cursor position to see if the
|
||||||
|
/// mouse is over child layers first. If a layer successfully scrolled returns either
|
||||||
|
/// ScrollPositionUnchanged or ScrollPositionChanged. If no layer was targeted by the event
|
||||||
|
/// returns ScrollEventUnhandled.
|
||||||
|
fn handle_scroll_event(&self,
|
||||||
|
delta: TypedPoint2D<LayerPixel, f32>,
|
||||||
|
cursor: TypedPoint2D<LayerPixel, f32>)
|
||||||
|
-> ScrollEventResult;
|
||||||
|
|
||||||
|
// Takes in a MouseWindowEvent, determines if it should be passed to children, and
|
||||||
|
// sends the event off to the appropriate pipeline. NB: the cursor position is in
|
||||||
|
// page coordinates.
|
||||||
|
fn send_mouse_event(&self,
|
||||||
|
event: MouseWindowEvent,
|
||||||
|
cursor: TypedPoint2D<LayerPixel, f32>);
|
||||||
|
|
||||||
|
fn send_mouse_move_event(&self,
|
||||||
|
cursor: TypedPoint2D<LayerPixel, f32>);
|
||||||
|
|
||||||
|
fn clamp_scroll_offset_and_scroll_layer(&self,
|
||||||
|
new_offset: TypedPoint2D<LayerPixel, f32>)
|
||||||
|
-> ScrollEventResult;
|
||||||
|
|
||||||
|
fn scroll_layer_and_all_child_layers(&self,
|
||||||
|
new_offset: TypedPoint2D<LayerPixel, f32>)
|
||||||
|
-> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 }
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Clampable {
|
||||||
|
fn clamp(&self, mn: &Self, mx: &Self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clampable for f32 {
|
||||||
|
/// Returns the number constrained within the range `mn <= self <= mx`.
|
||||||
|
/// If any of the numbers are `NAN` then `NAN` is returned.
|
||||||
|
#[inline]
|
||||||
|
fn clamp(&self, mn: &f32, mx: &f32) -> f32 {
|
||||||
|
match () {
|
||||||
|
_ if self.is_nan() => *self,
|
||||||
|
_ if !(*self <= *mx) => *mx,
|
||||||
|
_ if !(*self >= *mn) => *mn,
|
||||||
|
_ => *self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_content_size_for_layer(layer: &Layer<CompositorData>)
|
||||||
|
-> TypedSize2D<LayerPixel, f32> {
|
||||||
|
layer.children().iter().fold(Rect::zero(),
|
||||||
|
|unioned_rect, child_rect| {
|
||||||
|
unioned_rect.union(&*child_rect.bounds.borrow())
|
||||||
|
}).size
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(PartialEq)]
|
||||||
|
pub enum ScrollEventResult {
|
||||||
|
ScrollEventUnhandled,
|
||||||
|
ScrollPositionChanged,
|
||||||
|
ScrollPositionUnchanged,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompositorLayer for Layer<CompositorData> {
|
||||||
|
fn update_layer_except_size(&self, layer_properties: LayerProperties) {
|
||||||
|
self.extra_data.borrow_mut().epoch = layer_properties.epoch;
|
||||||
|
self.extra_data.borrow_mut().scroll_policy = layer_properties.scroll_policy;
|
||||||
|
|
||||||
|
*self.background_color.borrow_mut() = to_layers_color(&layer_properties.background_color);
|
||||||
|
|
||||||
|
self.contents_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_layer(&self, layer_properties: LayerProperties) {
|
||||||
|
self.resize(Size2D::from_untyped(&layer_properties.rect.size));
|
||||||
|
|
||||||
// Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the
|
// 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.
|
// cursor position to make sure the scroll isn't propagated downwards.
|
||||||
layer.handle_scroll_event(TypedPoint2D(0f32, 0f32), TypedPoint2D(-1f32, -1f32));
|
self.handle_scroll_event(TypedPoint2D(0f32, 0f32), TypedPoint2D(-1f32, -1f32));
|
||||||
CompositorData::update_layer_except_size(layer, layer_properties);
|
self.update_layer_except_size(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
|
// Add LayerBuffers to the specified layer. Returns the layer buffer set back if the layer that
|
||||||
|
@ -119,39 +187,34 @@ impl 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.
|
||||||
pub fn add_buffers(layer: Rc<Layer<CompositorData>>,
|
fn add_buffers(&self, new_buffers: Box<LayerBufferSet>, epoch: Epoch) -> bool {
|
||||||
new_buffers: Box<LayerBufferSet>,
|
if self.extra_data.borrow().epoch != epoch {
|
||||||
epoch: Epoch)
|
|
||||||
-> bool {
|
|
||||||
if layer.extra_data.borrow().epoch != epoch {
|
|
||||||
debug!("add_buffers: compositor epoch mismatch: {:?} != {:?}, id: {:?}",
|
debug!("add_buffers: compositor epoch mismatch: {:?} != {:?}, id: {:?}",
|
||||||
layer.extra_data.borrow().epoch,
|
self.extra_data.borrow().epoch,
|
||||||
epoch,
|
epoch,
|
||||||
layer.extra_data.borrow().pipeline.id);
|
self.extra_data.borrow().pipeline.id);
|
||||||
let msg = UnusedBufferMsg(new_buffers.buffers);
|
let msg = UnusedBufferMsg(new_buffers.buffers);
|
||||||
let _ = layer.extra_data.borrow().pipeline.render_chan.send_opt(msg);
|
let _ = self.extra_data.borrow().pipeline.render_chan.send_opt(msg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
for buffer in new_buffers.buffers.into_iter().rev() {
|
for buffer in new_buffers.buffers.into_iter().rev() {
|
||||||
layer.add_buffer(buffer);
|
self.add_buffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
let unused_buffers = layer.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 = UnusedBufferMsg(unused_buffers);
|
let msg = UnusedBufferMsg(unused_buffers);
|
||||||
let _ = layer.extra_data.borrow().pipeline.render_chan.send_opt(msg);
|
let _ = self.extra_data.borrow().pipeline.render_chan.send_opt(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destroys all layer tiles, sending the buffers back to the renderer to be destroyed or
|
fn clear(&self) {
|
||||||
/// reused.
|
let mut buffers = self.collect_buffers();
|
||||||
fn clear(layer: Rc<Layer<CompositorData>>) {
|
|
||||||
let mut buffers = layer.collect_buffers();
|
|
||||||
|
|
||||||
if !buffers.is_empty() {
|
if !buffers.is_empty() {
|
||||||
// We have no way of knowing without a race whether the render task is even up and
|
// We have no way of knowing without a race whether the render task is even up and
|
||||||
|
@ -161,16 +224,16 @@ impl CompositorData {
|
||||||
buffer.mark_wont_leak()
|
buffer.mark_wont_leak()
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = layer.extra_data.borrow().pipeline.render_chan.send_opt(UnusedBufferMsg(buffers));
|
let _ = self.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
|
/// Destroys tiles for this layer and all descendent layers, sending the buffers back to the
|
||||||
/// renderer to be destroyed or reused.
|
/// renderer to be destroyed or reused.
|
||||||
pub fn clear_all_tiles(layer: Rc<Layer<CompositorData>>) {
|
fn clear_all_tiles(&self) {
|
||||||
CompositorData::clear(layer.clone());
|
self.clear();
|
||||||
for kid in layer.children().iter() {
|
for kid in self.children().iter() {
|
||||||
CompositorData::clear_all_tiles(kid.clone());
|
kid.clear_all_tiles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,16 +242,119 @@ impl CompositorData {
|
||||||
/// otherwise, you will leak tiles.
|
/// otherwise, you will leak tiles.
|
||||||
///
|
///
|
||||||
/// This is used during shutdown, when we know the render task is going away.
|
/// This is used during shutdown, when we know the render task is going away.
|
||||||
pub fn forget_all_tiles(layer: Rc<Layer<CompositorData>>) {
|
fn forget_all_tiles(&self) {
|
||||||
let tiles = layer.collect_buffers();
|
let tiles = self.collect_buffers();
|
||||||
for tile in tiles.into_iter() {
|
for tile in tiles.into_iter() {
|
||||||
let mut tile = tile;
|
let mut tile = tile;
|
||||||
tile.mark_wont_leak()
|
tile.mark_wont_leak()
|
||||||
}
|
}
|
||||||
|
|
||||||
for kid in layer.children().iter() {
|
for kid in self.children().iter() {
|
||||||
CompositorData::forget_all_tiles(kid.clone());
|
kid.forget_all_tiles();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_event(&self,
|
||||||
|
delta: TypedPoint2D<LayerPixel, f32>,
|
||||||
|
cursor: TypedPoint2D<LayerPixel, f32>)
|
||||||
|
-> ScrollEventResult {
|
||||||
|
// If this layer doesn't want scroll events, neither it nor its children can handle scroll
|
||||||
|
// events.
|
||||||
|
if self.extra_data.borrow().wants_scroll_events != WantsScrollEvents {
|
||||||
|
return ScrollEventUnhandled;
|
||||||
|
}
|
||||||
|
|
||||||
|
//// Allow children to scroll.
|
||||||
|
let scroll_offset = self.extra_data.borrow().scroll_offset;
|
||||||
|
let new_cursor = cursor - scroll_offset;
|
||||||
|
for child in self.children().iter() {
|
||||||
|
let child_bounds = child.bounds.borrow();
|
||||||
|
if child_bounds.contains(&new_cursor) {
|
||||||
|
let result = child.handle_scroll_event(delta, new_cursor - child_bounds.origin);
|
||||||
|
if result != ScrollEventUnhandled {
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.clamp_scroll_offset_and_scroll_layer(scroll_offset + delta)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clamp_scroll_offset_and_scroll_layer(&self,
|
||||||
|
new_offset: TypedPoint2D<LayerPixel, f32>)
|
||||||
|
-> ScrollEventResult {
|
||||||
|
let layer_size = self.bounds.borrow().size;
|
||||||
|
let content_size = calculate_content_size_for_layer(self);
|
||||||
|
let min_x = (layer_size.width - content_size.width).get().min(0.0);
|
||||||
|
let min_y = (layer_size.height - content_size.height).get().min(0.0);
|
||||||
|
let new_offset : TypedPoint2D<LayerPixel, f32> =
|
||||||
|
Point2D(Length(new_offset.x.get().clamp(&min_x, &0.0)),
|
||||||
|
Length(new_offset.y.get().clamp(&min_y, &0.0)));
|
||||||
|
|
||||||
|
if self.extra_data.borrow().scroll_offset == new_offset {
|
||||||
|
return ScrollPositionUnchanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The scroll offset is just a record of the scroll position of this scrolling root,
|
||||||
|
// but scroll_layer_and_all_child_layers actually moves the child layers.
|
||||||
|
self.extra_data.borrow_mut().scroll_offset = new_offset;
|
||||||
|
|
||||||
|
let mut result = false;
|
||||||
|
for child in self.children().iter() {
|
||||||
|
result |= child.scroll_layer_and_all_child_layers(new_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if result {
|
||||||
|
return ScrollPositionChanged;
|
||||||
|
} else {
|
||||||
|
return ScrollPositionUnchanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_mouse_event(&self,
|
||||||
|
event: MouseWindowEvent,
|
||||||
|
cursor: TypedPoint2D<LayerPixel, f32>) {
|
||||||
|
let event_point = cursor.to_untyped();
|
||||||
|
let message = match event {
|
||||||
|
MouseWindowClickEvent(button, _) => ClickEvent(button, event_point),
|
||||||
|
MouseWindowMouseDownEvent(button, _) => MouseDownEvent(button, event_point),
|
||||||
|
MouseWindowMouseUpEvent(button, _) => MouseUpEvent(button, event_point),
|
||||||
|
};
|
||||||
|
let pipeline = &self.extra_data.borrow().pipeline;
|
||||||
|
let ScriptControlChan(ref chan) = pipeline.script_chan;
|
||||||
|
let _ = chan.send_opt(SendEventMsg(pipeline.id.clone(), message));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_mouse_move_event(&self,
|
||||||
|
cursor: TypedPoint2D<LayerPixel, f32>) {
|
||||||
|
let message = MouseMoveEvent(cursor.to_untyped());
|
||||||
|
let pipeline = &self.extra_data.borrow().pipeline;
|
||||||
|
let ScriptControlChan(ref chan) = pipeline.script_chan;
|
||||||
|
let _ = chan.send_opt(SendEventMsg(pipeline.id.clone(), message));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scroll_layer_and_all_child_layers(&self,
|
||||||
|
new_offset: TypedPoint2D<LayerPixel, f32>)
|
||||||
|
-> bool {
|
||||||
|
let mut result = false;
|
||||||
|
|
||||||
|
// Only scroll this layer if it's not fixed-positioned.
|
||||||
|
if self.extra_data.borrow().scroll_policy != FixedPosition {
|
||||||
|
let new_offset = new_offset.to_untyped();
|
||||||
|
*self.transform.borrow_mut() = identity().translate(new_offset.x,
|
||||||
|
new_offset.y,
|
||||||
|
0.0);
|
||||||
|
*self.content_offset.borrow_mut() = Point2D::from_untyped(&new_offset);
|
||||||
|
result = true
|
||||||
|
}
|
||||||
|
|
||||||
|
let offset_for_children = new_offset + self.extra_data.borrow().scroll_offset;
|
||||||
|
for child in self.children().iter() {
|
||||||
|
result |= child.scroll_layer_and_all_child_layers(offset_for_children);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,186 +0,0 @@
|
||||||
/* 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_data::{CompositorData, WantsScrollEvents};
|
|
||||||
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent};
|
|
||||||
use windowing::MouseWindowMouseUpEvent;
|
|
||||||
use windowing::WindowMethods;
|
|
||||||
|
|
||||||
use geom::length::Length;
|
|
||||||
use geom::matrix::identity;
|
|
||||||
use geom::point::{Point2D, TypedPoint2D};
|
|
||||||
use geom::rect::Rect;
|
|
||||||
use geom::size::TypedSize2D;
|
|
||||||
use layers::geometry::LayerPixel;
|
|
||||||
use layers::layers::Layer;
|
|
||||||
use script_traits::{ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent, SendEventMsg};
|
|
||||||
use script_traits::{ScriptControlChan};
|
|
||||||
use servo_msg::compositor_msg::FixedPosition;
|
|
||||||
|
|
||||||
trait Clampable {
|
|
||||||
fn clamp(&self, mn: &Self, mx: &Self) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clampable for f32 {
|
|
||||||
/// Returns the number constrained within the range `mn <= self <= mx`.
|
|
||||||
/// If any of the numbers are `NAN` then `NAN` is returned.
|
|
||||||
#[inline]
|
|
||||||
fn clamp(&self, mn: &f32, mx: &f32) -> f32 {
|
|
||||||
match () {
|
|
||||||
_ if self.is_nan() => *self,
|
|
||||||
_ if !(*self <= *mx) => *mx,
|
|
||||||
_ if !(*self >= *mn) => *mn,
|
|
||||||
_ => *self,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deriving(PartialEq)]
|
|
||||||
pub enum ScrollEventResult {
|
|
||||||
ScrollEventUnhandled,
|
|
||||||
ScrollPositionChanged,
|
|
||||||
ScrollPositionUnchanged,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait LayerEventHandling {
|
|
||||||
/// Move the layer's descendants that don't want scroll events and scroll by a relative
|
|
||||||
/// specified amount in page coordinates. This also takes in a cursor position to see if the
|
|
||||||
/// mouse is over child layers first. If a layer successfully scrolled returns either
|
|
||||||
/// ScrollPositionUnchanged or ScrollPositionChanged. If no layer was targeted by the event
|
|
||||||
/// returns ScrollEventUnhandled.
|
|
||||||
fn handle_scroll_event(&self,
|
|
||||||
delta: TypedPoint2D<LayerPixel, f32>,
|
|
||||||
cursor: TypedPoint2D<LayerPixel, f32>)
|
|
||||||
-> ScrollEventResult;
|
|
||||||
|
|
||||||
// Takes in a MouseWindowEvent, determines if it should be passed to children, and
|
|
||||||
// sends the event off to the appropriate pipeline. NB: the cursor position is in
|
|
||||||
// page coordinates.
|
|
||||||
fn send_mouse_event(&self,
|
|
||||||
event: MouseWindowEvent,
|
|
||||||
cursor: TypedPoint2D<LayerPixel, f32>);
|
|
||||||
|
|
||||||
fn send_mouse_move_event(&self,
|
|
||||||
cursor: TypedPoint2D<LayerPixel, f32>);
|
|
||||||
|
|
||||||
fn clamp_scroll_offset_and_scroll_layer(&self,
|
|
||||||
new_offset: TypedPoint2D<LayerPixel, f32>)
|
|
||||||
-> ScrollEventResult;
|
|
||||||
fn scroll_layer_and_all_child_layers(&self,
|
|
||||||
new_offset: TypedPoint2D<LayerPixel, f32>)
|
|
||||||
-> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn calculate_content_size_for_layer(layer: &Layer<CompositorData>)
|
|
||||||
-> TypedSize2D<LayerPixel, f32> {
|
|
||||||
layer.children().iter().fold(Rect::zero(),
|
|
||||||
|unioned_rect, child_rect| {
|
|
||||||
unioned_rect.union(&*child_rect.bounds.borrow())
|
|
||||||
}).size
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LayerEventHandling for Layer<CompositorData> {
|
|
||||||
fn handle_scroll_event(&self,
|
|
||||||
delta: TypedPoint2D<LayerPixel, f32>,
|
|
||||||
cursor: TypedPoint2D<LayerPixel, f32>)
|
|
||||||
-> ScrollEventResult {
|
|
||||||
// If this layer doesn't want scroll events, neither it nor its children can handle scroll
|
|
||||||
// events.
|
|
||||||
if self.extra_data.borrow().wants_scroll_events != WantsScrollEvents {
|
|
||||||
return ScrollEventUnhandled;
|
|
||||||
}
|
|
||||||
|
|
||||||
//// Allow children to scroll.
|
|
||||||
let scroll_offset = self.extra_data.borrow().scroll_offset;
|
|
||||||
let new_cursor = cursor - scroll_offset;
|
|
||||||
for child in self.children().iter() {
|
|
||||||
let child_bounds = child.bounds.borrow();
|
|
||||||
if child_bounds.contains(&new_cursor) {
|
|
||||||
let result = child.handle_scroll_event(delta, new_cursor - child_bounds.origin);
|
|
||||||
if result != ScrollEventUnhandled {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.clamp_scroll_offset_and_scroll_layer(scroll_offset + delta)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clamp_scroll_offset_and_scroll_layer(&self,
|
|
||||||
new_offset: TypedPoint2D<LayerPixel, f32>)
|
|
||||||
-> ScrollEventResult {
|
|
||||||
let layer_size = self.bounds.borrow().size;
|
|
||||||
let content_size = calculate_content_size_for_layer(self);
|
|
||||||
let min_x = (layer_size.width - content_size.width).get().min(0.0);
|
|
||||||
let min_y = (layer_size.height - content_size.height).get().min(0.0);
|
|
||||||
let new_offset : TypedPoint2D<LayerPixel, f32> =
|
|
||||||
Point2D(Length(new_offset.x.get().clamp(&min_x, &0.0)),
|
|
||||||
Length(new_offset.y.get().clamp(&min_y, &0.0)));
|
|
||||||
|
|
||||||
if self.extra_data.borrow().scroll_offset == new_offset {
|
|
||||||
return ScrollPositionUnchanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The scroll offset is just a record of the scroll position of this scrolling root,
|
|
||||||
// but scroll_layer_and_all_child_layers actually moves the child layers.
|
|
||||||
self.extra_data.borrow_mut().scroll_offset = new_offset;
|
|
||||||
|
|
||||||
let mut result = false;
|
|
||||||
for child in self.children().iter() {
|
|
||||||
result |= child.scroll_layer_and_all_child_layers(new_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
if result {
|
|
||||||
return ScrollPositionChanged;
|
|
||||||
} else {
|
|
||||||
return ScrollPositionUnchanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_mouse_event(&self,
|
|
||||||
event: MouseWindowEvent,
|
|
||||||
cursor: TypedPoint2D<LayerPixel, f32>) {
|
|
||||||
let event_point = cursor.to_untyped();
|
|
||||||
let message = match event {
|
|
||||||
MouseWindowClickEvent(button, _) => ClickEvent(button, event_point),
|
|
||||||
MouseWindowMouseDownEvent(button, _) => MouseDownEvent(button, event_point),
|
|
||||||
MouseWindowMouseUpEvent(button, _) => MouseUpEvent(button, event_point),
|
|
||||||
};
|
|
||||||
let pipeline = &self.extra_data.borrow().pipeline;
|
|
||||||
let ScriptControlChan(ref chan) = pipeline.script_chan;
|
|
||||||
let _ = chan.send_opt(SendEventMsg(pipeline.id.clone(), message));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_mouse_move_event(&self,
|
|
||||||
cursor: TypedPoint2D<LayerPixel, f32>) {
|
|
||||||
let message = MouseMoveEvent(cursor.to_untyped());
|
|
||||||
let pipeline = &self.extra_data.borrow().pipeline;
|
|
||||||
let ScriptControlChan(ref chan) = pipeline.script_chan;
|
|
||||||
let _ = chan.send_opt(SendEventMsg(pipeline.id.clone(), message));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scroll_layer_and_all_child_layers(&self,
|
|
||||||
new_offset: TypedPoint2D<LayerPixel, f32>)
|
|
||||||
-> bool {
|
|
||||||
let mut result = false;
|
|
||||||
|
|
||||||
// Only scroll this layer if it's not fixed-positioned.
|
|
||||||
if self.extra_data.borrow().scroll_policy != FixedPosition {
|
|
||||||
let new_offset = new_offset.to_untyped();
|
|
||||||
*self.transform.borrow_mut() = identity().translate(new_offset.x,
|
|
||||||
new_offset.y,
|
|
||||||
0.0);
|
|
||||||
*self.content_offset.borrow_mut() = Point2D::from_untyped(&new_offset);
|
|
||||||
result = true
|
|
||||||
}
|
|
||||||
|
|
||||||
let offset_for_children = new_offset + self.extra_data.borrow().scroll_offset;
|
|
||||||
for child in self.children().iter() {
|
|
||||||
result |= child.scroll_layer_and_all_child_layers(offset_for_children);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -44,7 +44,6 @@ pub use constellation::Constellation;
|
||||||
pub mod compositor_task;
|
pub mod compositor_task;
|
||||||
|
|
||||||
mod compositor_data;
|
mod compositor_data;
|
||||||
mod events;
|
|
||||||
|
|
||||||
mod compositor;
|
mod compositor;
|
||||||
mod headless;
|
mod headless;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue