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.
This commit is contained in:
bors-servo 2014-10-01 14:33:26 -06:00
commit 479d8567d1

View file

@ -139,36 +139,63 @@ fn scroll_layer_and_all_child_layers(layer: Rc<Layer<CompositorData>>,
return result; 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 // 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 // sends the event off to the appropriate pipeline. NB: the cursor position is in
// page coordinates. // page coordinates.
pub fn send_mouse_event(layer: Rc<Layer<CompositorData>>, pub fn send_mouse_event(layer: Rc<Layer<CompositorData>>,
event: MouseWindowEvent, event: MouseWindowEvent,
cursor: TypedPoint2D<LayerPixel, f32>) { cursor: TypedPoint2D<LayerPixel, f32>) {
let content_offset = *layer.content_offset.borrow(); match find_topmost_layer_at_point(layer.clone(), cursor) {
let cursor = cursor - content_offset; Some(result) => {
for child in layer.children().iter() { let event_point = result.point.to_untyped();
let child_bounds = child.bounds.borrow(); let message = match event {
if child_bounds.contains(&cursor) { MouseWindowClickEvent(button, _) => ClickEvent(button, event_point),
send_mouse_event(child.clone(), event, cursor - child_bounds.origin); MouseWindowMouseDownEvent(button, _) => MouseDownEvent(button, event_point),
return; 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>>, pub fn send_mouse_move_event(layer: Rc<Layer<CompositorData>>,
cursor: TypedPoint2D<LayerPixel, f32>) { cursor: TypedPoint2D<LayerPixel, f32>) {
let message = MouseMoveEvent(cursor.to_untyped()); match find_topmost_layer_at_point(layer.clone(), cursor) {
let ScriptControlChan(ref chan) = layer.extra_data.borrow().pipeline.script_chan; Some(result) => {
let _ = chan.send_opt(SendEventMsg(layer.extra_data.borrow().pipeline.id.clone(), message)); 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 => {},
}
} }