mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Cargoify servo
This commit is contained in:
parent
db2f642c32
commit
c6ab60dbfc
1761 changed files with 8423 additions and 2294 deletions
178
components/compositing/events.rs
Normal file
178
components/compositing/events.rs
Normal file
|
@ -0,0 +1,178 @@
|
|||
/* 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 geom::length::Length;
|
||||
use geom::point::TypedPoint2D;
|
||||
use geom::scale_factor::ScaleFactor;
|
||||
use geom::size::TypedSize2D;
|
||||
use layers::geometry::DevicePixel;
|
||||
use layers::layers::Layer;
|
||||
use script_traits::{ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent, SendEventMsg};
|
||||
use script_traits::{ScriptControlChan};
|
||||
use servo_msg::compositor_msg::{FixedPosition, LayerId};
|
||||
use servo_msg::constellation_msg::PipelineId;
|
||||
use servo_util::geometry::PagePx;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
||||
use geom::matrix::identity;
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 true; otherwise
|
||||
/// returns false, so a parent layer can scroll instead.
|
||||
pub fn handle_scroll_event(layer: Rc<Layer<CompositorData>>,
|
||||
delta: TypedPoint2D<DevicePixel, f32>,
|
||||
cursor: TypedPoint2D<DevicePixel, f32>,
|
||||
window_size: TypedSize2D<DevicePixel, f32>)
|
||||
-> bool {
|
||||
// If this layer doesn't want scroll events, neither it nor its children can handle scroll
|
||||
// events.
|
||||
if layer.extra_data.borrow().wants_scroll_events != WantsScrollEvents {
|
||||
return false
|
||||
}
|
||||
|
||||
// Allow children to scroll.
|
||||
let content_offset = layer.content_offset.borrow().clone();
|
||||
let cursor = cursor - content_offset;
|
||||
for child in layer.children().iter() {
|
||||
let child_bounds = child.bounds.borrow();
|
||||
if child_bounds.contains(&cursor) &&
|
||||
handle_scroll_event(child.clone(),
|
||||
delta,
|
||||
cursor - child_bounds.origin,
|
||||
child_bounds.size) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
clamp_scroll_offset_and_scroll_layer(layer, content_offset + delta, window_size)
|
||||
|
||||
}
|
||||
|
||||
pub fn clamp_scroll_offset_and_scroll_layer(layer: Rc<Layer<CompositorData>>,
|
||||
mut new_offset: TypedPoint2D<DevicePixel, f32>,
|
||||
window_size: TypedSize2D<DevicePixel, f32>)
|
||||
-> bool {
|
||||
let layer_size = layer.bounds.borrow().size;
|
||||
let min_x = (window_size.width - layer_size.width).get().min(0.0);
|
||||
new_offset.x = Length(new_offset.x.get().clamp(&min_x, &0.0));
|
||||
|
||||
let min_y = (window_size.height - layer_size.height).get().min(0.0);
|
||||
new_offset.y = Length(new_offset.y.get().clamp(&min_y, &0.0));
|
||||
|
||||
if *layer.content_offset.borrow() == new_offset {
|
||||
return false
|
||||
}
|
||||
|
||||
// FIXME: This allows the base layer to record the current content offset without
|
||||
// updating its transform. This should be replaced with something less strange.
|
||||
*layer.content_offset.borrow_mut() = new_offset;
|
||||
scroll_layer_and_all_child_layers(layer.clone(), new_offset)
|
||||
}
|
||||
|
||||
fn scroll_layer_and_all_child_layers(layer: Rc<Layer<CompositorData>>,
|
||||
new_offset: TypedPoint2D<DevicePixel, f32>)
|
||||
-> bool {
|
||||
let mut result = false;
|
||||
|
||||
// Only scroll this layer if it's not fixed-positioned.
|
||||
if layer.extra_data.borrow().scroll_policy != FixedPosition {
|
||||
*layer.transform.borrow_mut() = identity().translate(new_offset.x.get(),
|
||||
new_offset.y.get(),
|
||||
0.0);
|
||||
*layer.content_offset.borrow_mut() = new_offset;
|
||||
result = true
|
||||
}
|
||||
|
||||
for child in layer.children().iter() {
|
||||
result |= scroll_layer_and_all_child_layers(child.clone(), new_offset);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 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.
|
||||
pub fn send_mouse_event(layer: Rc<Layer<CompositorData>>,
|
||||
event: MouseWindowEvent,
|
||||
cursor: TypedPoint2D<DevicePixel, f32>,
|
||||
device_pixels_per_page_px: ScaleFactor<PagePx, DevicePixel, f32>) {
|
||||
let cursor = cursor - *layer.content_offset.borrow();
|
||||
for child in layer.children().iter() {
|
||||
let child_bounds = child.bounds.borrow();
|
||||
if child_bounds.contains(&cursor) {
|
||||
send_mouse_event(child.clone(),
|
||||
event,
|
||||
cursor - child_bounds.origin,
|
||||
device_pixels_per_page_px);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// This mouse event is mine!
|
||||
let cursor = cursor / device_pixels_per_page_px;
|
||||
let message = match event {
|
||||
MouseWindowClickEvent(button, _) => ClickEvent(button, cursor.to_untyped()),
|
||||
MouseWindowMouseDownEvent(button, _) => MouseDownEvent(button, cursor.to_untyped()),
|
||||
MouseWindowMouseUpEvent(button, _) => MouseUpEvent(button, cursor.to_untyped()),
|
||||
};
|
||||
let ScriptControlChan(ref chan) = layer.extra_data.borrow().pipeline.script_chan;
|
||||
let _ = chan.send_opt(SendEventMsg(layer.extra_data.borrow().pipeline.id.clone(), message));
|
||||
}
|
||||
|
||||
pub fn send_mouse_move_event(layer: Rc<Layer<CompositorData>>,
|
||||
cursor: TypedPoint2D<PagePx, f32>) {
|
||||
let message = MouseMoveEvent(cursor.to_untyped());
|
||||
let ScriptControlChan(ref chan) = layer.extra_data.borrow().pipeline.script_chan;
|
||||
let _ = chan.send_opt(SendEventMsg(layer.extra_data.borrow().pipeline.id.clone(), message));
|
||||
}
|
||||
|
||||
pub fn move(layer: Rc<Layer<CompositorData>>,
|
||||
pipeline_id: PipelineId,
|
||||
layer_id: LayerId,
|
||||
origin: TypedPoint2D<DevicePixel, f32>,
|
||||
window_size: TypedSize2D<DevicePixel, f32>)
|
||||
-> bool {
|
||||
// Search children for the right layer to move.
|
||||
if layer.extra_data.borrow().pipeline.id != pipeline_id ||
|
||||
layer.extra_data.borrow().id != layer_id {
|
||||
return layer.children().iter().any(|kid| {
|
||||
move(kid.clone(),
|
||||
pipeline_id,
|
||||
layer_id,
|
||||
origin,
|
||||
window_size)
|
||||
});
|
||||
}
|
||||
|
||||
if layer.extra_data.borrow().wants_scroll_events != WantsScrollEvents {
|
||||
return false
|
||||
}
|
||||
|
||||
clamp_scroll_offset_and_scroll_layer(layer, TypedPoint2D(0f32, 0f32) - origin, window_size)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue