From b1f05816373f5e68ce242e0b1a45a50851f868bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sat, 20 Feb 2016 20:19:13 +0100 Subject: [PATCH] script: Fix MouseOver handling Now we only query for the topmost node, and apply the hover state to all of the parent elements. This fixes things like #9705, where the hover state was applied only to the children. This also makes us more conformant with other browsers in the case of taking in account margins and paddings. For example, prior to this PR, when your mouse was over the inner element, in the bottom part, `hover` styles didn't apply to the parent. ```html
``` Fixes #9705 --- components/layout/query.rs | 7 ++---- components/script/dom/document.rs | 33 +++++++++++++++------------ components/script/layout_interface.rs | 3 ++- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/components/layout/query.rs b/components/layout/query.rs index 348a3ad556d..54acfe92e90 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -107,11 +107,8 @@ impl LayoutRPC for LayoutRPCImpl { if mouse_over_list.is_empty() { Err(()) } else { - let response_list = - mouse_over_list.iter() - .map(|metadata| metadata.node.to_untrusted_node_address()) - .collect(); - Ok(MouseOverResponse(response_list)) + let response = mouse_over_list[0].node.to_untrusted_node_address(); + Ok(MouseOverResponse(response)) } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 501ad242305..4062fb7415f 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -574,11 +574,11 @@ impl Document { } } - pub fn get_nodes_under_mouse(&self, page_point: &Point2D) -> Vec { + pub fn get_node_under_mouse(&self, page_point: &Point2D) -> Option { assert!(self.GetDocumentElement().is_some()); match self.window.layout().mouse_over(*page_point) { - Ok(MouseOverResponse(node_address)) => node_address, - Err(()) => vec![], + Ok(MouseOverResponse(node_address)) => Some(node_address), + Err(()) => None, } } @@ -808,18 +808,21 @@ impl Document { client_point: Option>, prev_mouse_over_targets: &mut RootedVec>) { // Build a list of elements that are currently under the mouse. - let mouse_over_addresses = client_point.as_ref().map(|client_point| { + let mouse_over_address = 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() - .filter_map(Root::downcast::) - .next() - .unwrap() - }).collect::>>(); + self.get_node_under_mouse(&page_point) + }).unwrap_or(None); + + let mut mouse_over_targets = RootedVec::>::new(); + + if let Some(address) = mouse_over_address { + let node = node::from_untrusted_node_address(js_runtime, address); + for node in node.inclusive_ancestors() + .filter_map(Root::downcast::) { + mouse_over_targets.push(JS::from_rooted(&node)); + } + } // Remove hover from any elements in the previous list that are no longer // under the mouse. @@ -856,9 +859,9 @@ impl Document { } // Send mousemove event to topmost target - if mouse_over_addresses.len() > 0 { + if let Some(address) = mouse_over_address { let top_most_node = node::from_untrusted_node_address(js_runtime, - mouse_over_addresses[0]); + address); let client_point = client_point.unwrap(); // Must succeed because hit test succeeded. // If the target is an iframe, forward the event to the child document. diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index 17f553d43e8..4ad7c241f14 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -106,6 +106,7 @@ pub trait LayoutRPC { fn node_geometry(&self) -> NodeGeometryResponse; /// Requests the node containing the point of interest fn hit_test(&self, point: Point2D) -> Result; + /// Query layout for the topmost node under the mouse. fn mouse_over(&self, point: Point2D) -> Result; /// Query layout for the resolved value of a given CSS property fn resolved_style(&self) -> ResolvedStyleResponse; @@ -139,7 +140,7 @@ pub struct NodeGeometryResponse { pub client_rect: Rect, } pub struct HitTestResponse(pub UntrustedNodeAddress); -pub struct MouseOverResponse(pub Vec); +pub struct MouseOverResponse(pub UntrustedNodeAddress); pub struct ResolvedStyleResponse(pub Option); #[derive(Clone)]