diff options
-rw-r--r-- | components/compositing/compositor.rs | 40 | ||||
-rw-r--r-- | components/compositing/compositor_layer.rs | 2 | ||||
-rw-r--r-- | components/script/dom/document.rs | 65 |
3 files changed, 61 insertions, 46 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index e91bc951086..0ce000d1b9d 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -242,7 +242,9 @@ enum ShutdownState { } struct HitTestResult { + /// The topmost layer containing the requested point layer: Rc<Layer<CompositorData>>, + /// The point in client coordinates of the innermost window or frame containing `layer` point: TypedPoint2D<LayerPixel, f32>, } @@ -1934,45 +1936,53 @@ impl<Window: WindowMethods> IOCompositor<Window> { fn find_topmost_layer_at_point_for_layer(&self, layer: Rc<Layer<CompositorData>>, - point: TypedPoint2D<LayerPixel, f32>, - clip_rect: &TypedRect<LayerPixel, f32>) + point_in_parent_layer: TypedPoint2D<LayerPixel, f32>, + clip_rect_in_parent_layer: &TypedRect<LayerPixel, f32>) -> Option<HitTestResult> { let layer_bounds = *layer.bounds.borrow(); let masks_to_bounds = *layer.masks_to_bounds.borrow(); if layer_bounds.is_empty() && masks_to_bounds { return None; } + let scroll_offset = layer.extra_data.borrow().scroll_offset; - let clipped_layer_bounds = match clip_rect.intersection(&layer_bounds) { + // Total offset from parent coordinates to this layer's coordinates. + // FIXME: This offset is incorrect for fixed-position layers. + let layer_offset = scroll_offset + layer_bounds.origin; + + let clipped_layer_bounds = match clip_rect_in_parent_layer.intersection(&layer_bounds) { Some(rect) => rect, None => return None, }; let clip_rect_for_children = if masks_to_bounds { - Rect::new(Point2D::zero(), clipped_layer_bounds.size) + &clipped_layer_bounds } else { - clipped_layer_bounds.translate(&clip_rect.origin) - }; + clip_rect_in_parent_layer + }.translate(&-layer_offset); - let child_point = point - layer_bounds.origin; + let child_point = point_in_parent_layer - layer_offset; for child in layer.children().iter().rev() { // Translate the clip rect into the child's coordinate system. - let clip_rect_for_child = - clip_rect_for_children.translate(&-*child.content_offset.borrow()); let result = self.find_topmost_layer_at_point_for_layer(child.clone(), child_point, - &clip_rect_for_child); - if result.is_some() { - return result; + &clip_rect_for_children); + if let Some(mut result) = result { + // Return the point in layer coordinates of the topmost frame containing the point. + let pipeline_id = layer.extra_data.borrow().pipeline_id; + let child_pipeline_id = result.layer.extra_data.borrow().pipeline_id; + if pipeline_id == child_pipeline_id { + result.point = result.point + layer_offset; + } + return Some(result); } } - let point = point - *layer.content_offset.borrow(); - if !clipped_layer_bounds.contains(&point) { + if !clipped_layer_bounds.contains(&point_in_parent_layer) { return None; } - return Some(HitTestResult { layer: layer, point: point }); + return Some(HitTestResult { layer: layer, point: point_in_parent_layer }); } fn find_topmost_layer_at_point(&self, diff --git a/components/compositing/compositor_layer.rs b/components/compositing/compositor_layer.rs index b47cff1ccca..ceb034c83bd 100644 --- a/components/compositing/compositor_layer.rs +++ b/components/compositing/compositor_layer.rs @@ -121,7 +121,7 @@ pub trait CompositorLayer { // 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. + // client coordinates. fn send_mouse_event<Window>(&self, compositor: &IOCompositor<Window>, event: MouseWindowEvent, diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index b8ca6723e2c..19adfbd490d 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -492,9 +492,9 @@ impl Document { }) } - pub fn hit_test(&self, point: &Point2D<f32>) -> Option<UntrustedNodeAddress> { + pub fn hit_test(&self, page_point: &Point2D<f32>) -> Option<UntrustedNodeAddress> { assert!(self.GetDocumentElement().is_some()); - match self.window.layout().hit_test(*point) { + match self.window.layout().hit_test(*page_point) { Ok(HitTestResponse(node_address)) => Some(node_address), Err(()) => { debug!("layout query error"); @@ -503,9 +503,9 @@ impl Document { } } - pub fn get_nodes_under_mouse(&self, point: &Point2D<f32>) -> Vec<UntrustedNodeAddress> { + pub fn get_nodes_under_mouse(&self, page_point: &Point2D<f32>) -> Vec<UntrustedNodeAddress> { assert!(self.GetDocumentElement().is_some()); - match self.window.layout().mouse_over(*point) { + match self.window.layout().mouse_over(*page_point) { Ok(MouseOverResponse(node_address)) => node_address, Err(()) => vec![], } @@ -604,15 +604,18 @@ impl Document { pub fn handle_mouse_event(&self, js_runtime: *mut JSRuntime, _button: MouseButton, - point: Point2D<f32>, + client_point: Point2D<f32>, mouse_event_type: MouseEventType) { let mouse_event_type_string = match mouse_event_type { MouseEventType::Click => "click".to_owned(), MouseEventType::MouseUp => "mouseup".to_owned(), MouseEventType::MouseDown => "mousedown".to_owned(), }; - debug!("{}: at {:?}", mouse_event_type_string, point); - let node = match self.hit_test(&point) { + debug!("{}: at {:?}", mouse_event_type_string, client_point); + + let page_point = Point2D::new(client_point.x + self.window.PageXOffset() as f32, + client_point.y + self.window.PageYOffset() as f32); + let node = match self.hit_test(&page_point) { Some(node_address) => { debug!("node address is {:?}", node_address); node::from_untrusted_node_address(js_runtime, node_address) @@ -643,8 +646,8 @@ impl Document { } // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#event-type-click - let x = point.x as i32; - let y = point.y as i32; + let client_x = client_point.x as i32; + let client_y = client_point.y as i32; let clickCount = 1; let event = MouseEvent::new(&self.window, DOMString::from(mouse_event_type_string), @@ -652,10 +655,10 @@ impl Document { EventCancelable::Cancelable, Some(&self.window), clickCount, - x, - y, - x, - y, // TODO: Get real screen coordinates? + client_x, + client_y, + client_x, + client_y, // TODO: Get real screen coordinates? false, false, false, @@ -683,9 +686,9 @@ impl Document { ReflowReason::MouseEvent); } - pub fn fire_mouse_event(&self, point: Point2D<f32>, target: &EventTarget, event_name: String) { - let x = point.x.to_i32().unwrap_or(0); - let y = point.y.to_i32().unwrap_or(0); + pub fn fire_mouse_event(&self, client_point: Point2D<f32>, target: &EventTarget, event_name: String) { + let client_x = client_point.x.to_i32().unwrap_or(0); + let client_y = client_point.y.to_i32().unwrap_or(0); let mouse_event = MouseEvent::new(&self.window, DOMString::from(event_name), @@ -693,10 +696,10 @@ impl Document { EventCancelable::Cancelable, Some(&self.window), 0i32, - x, - y, - x, - y, + client_x, + client_y, + client_x, + client_y, false, false, false, @@ -709,12 +712,14 @@ impl Document { pub fn handle_mouse_move_event(&self, js_runtime: *mut JSRuntime, - point: Option<Point2D<f32>>, + client_point: Option<Point2D<f32>>, prev_mouse_over_targets: &mut RootedVec<JS<Element>>) { // Build a list of elements that are currently under the mouse. - let mouse_over_addresses = point.as_ref() - .map(|point| self.get_nodes_under_mouse(point)) - .unwrap_or(vec![]); + let mouse_over_addresses = client_point.as_ref().map(|client_point| { + let page_point = Point2D::new(client_point.x + self.window.PageXOffset() as f32, + client_point.y + self.window.PageYOffset() as f32); + self.get_nodes_under_mouse(&page_point) + }).unwrap_or(vec![]); let mut mouse_over_targets = mouse_over_addresses.iter().map(|node_address| { node::from_untrusted_node_address(js_runtime, *node_address) .inclusive_ancestors() @@ -735,8 +740,8 @@ impl Document { // FIXME: we should be dispatching this event but we lack an actual // point to pass to it. - if let Some(point) = point { - self.fire_mouse_event(point, &target, "mouseout".to_owned()); + if let Some(client_point) = client_point { + self.fire_mouse_event(client_point, &target, "mouseout".to_owned()); } } } @@ -751,8 +756,8 @@ impl Document { let target = target.upcast(); - if let Some(point) = point { - self.fire_mouse_event(point, target, "mouseover".to_owned()); + if let Some(client_point) = client_point { + self.fire_mouse_event(client_point, target, "mouseover".to_owned()); } } } @@ -763,8 +768,8 @@ impl Document { mouse_over_addresses[0]); let target = top_most_node.upcast(); - if let Some(point) = point { - self.fire_mouse_event(point, target, "mousemove".to_owned()); + if let Some(client_point) = client_point { + self.fire_mouse_event(client_point, target, "mousemove".to_owned()); } } |