aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <metajack+bors@gmail.com>2014-10-01 14:33:26 -0600
committerbors-servo <metajack+bors@gmail.com>2014-10-01 14:33:26 -0600
commit479d8567d12aa0845c835fdae7d0dd45d7c63d4f (patch)
treed5ff98b77d38415e669baacdc2d55b4eeb1b3488
parentda6878a4e2925cefe9aa9368890d5791f965433e (diff)
parent8d93ac460d3130a7e9f6cc394ae4fa8392b9bbd3 (diff)
downloadservo-479d8567d12aa0845c835fdae7d0dd45d7c63d4f.tar.gz
servo-479d8567d12aa0845c835fdae7d0dd45d7c63d4f.zip
auto merge of #3538 : mrobinson/servo/events-and-layers, r=zwarich
Select the topmost layer at a given point to send mouse events and when sending the event, ensure that they are relative to the layer origin, rather than in absolute page coordinates. Fixes #3504.
-rw-r--r--components/compositing/events.rs65
1 files changed, 46 insertions, 19 deletions
diff --git a/components/compositing/events.rs b/components/compositing/events.rs
index 28feffa26a4..371f033b724 100644
--- a/components/compositing/events.rs
+++ b/components/compositing/events.rs
@@ -139,36 +139,63 @@ fn scroll_layer_and_all_child_layers(layer: Rc<Layer<CompositorData>>,
return result;
}
+struct HitTestResult {
+ layer: Rc<Layer<CompositorData>>,
+ point: TypedPoint2D<LayerPixel, f32>,
+}
+
+pub fn find_topmost_layer_at_point(layer: Rc<Layer<CompositorData>>,
+ point: TypedPoint2D<LayerPixel, f32>)
+ -> Option<HitTestResult> {
+ let child_point = point - layer.bounds.borrow().origin;
+ for child in layer.children().iter().rev() {
+ let result = find_topmost_layer_at_point(child.clone(), child_point);
+ if result.is_some() {
+ return result;
+ }
+ }
+
+ let point = point - *layer.content_offset.borrow();
+ if !layer.bounds.borrow().contains(&point) {
+ return None;
+ }
+
+ return Some(HitTestResult { layer: layer, point: point });
+}
+
// 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<LayerPixel, f32>) {
- let content_offset = *layer.content_offset.borrow();
- let cursor = cursor - content_offset;
- 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);
- return;
- }
+ match find_topmost_layer_at_point(layer.clone(), cursor) {
+ Some(result) => {
+ let event_point = result.point.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 = &result.layer.extra_data.borrow().pipeline;
+ let ScriptControlChan(ref chan) = pipeline.script_chan;
+ let _ = chan.send_opt(SendEventMsg(pipeline.id.clone(), message));
+ },
+ None => {},
}
- // This mouse event is mine!
- 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<LayerPixel, 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));
+ match find_topmost_layer_at_point(layer.clone(), cursor) {
+ Some(result) => {
+ let message = MouseMoveEvent(result.point.to_untyped());
+ let pipeline = &result.layer.extra_data.borrow().pipeline;
+ let ScriptControlChan(ref chan) = pipeline.script_chan;
+ let _ = chan.send_opt(SendEventMsg(pipeline.id.clone(), message));
+ },
+ None => {},
+ }
}