diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 3be9d0162cc..43dc5d5a62f 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -702,20 +702,20 @@ impl IOCompositor { None => return, }; - let point = result.point_in_viewport.to_untyped(); - let node_address = Some(UntrustedNodeAddress(result.tag.0 as *const c_void)); - let event_to_send = match mouse_window_event { - MouseWindowEvent::Click(button, _) => { - MouseButtonEvent(MouseEventType::Click, button, point, node_address) - } - MouseWindowEvent::MouseDown(button, _) => { - MouseButtonEvent(MouseEventType::MouseDown, button, point, node_address) - } - MouseWindowEvent::MouseUp(button, _) => { - MouseButtonEvent(MouseEventType::MouseUp, button, point, node_address) - } + let (button, event_type) = match mouse_window_event { + MouseWindowEvent::Click(button, _) => (button, MouseEventType::Click), + MouseWindowEvent::MouseDown(button, _) => (button, MouseEventType::MouseDown), + MouseWindowEvent::MouseUp(button, _) => (button, MouseEventType::MouseUp), }; + let event_to_send = MouseButtonEvent( + event_type, + button, + result.point_in_viewport.to_untyped(), + Some(UntrustedNodeAddress(result.tag.0 as *const c_void)), + Some(result.point_relative_to_item.to_untyped()), + ); + let pipeline_id = PipelineId::from_webrender(result.pipeline); let msg = ConstellationMsg::ForwardEvent(pipeline_id, event_to_send); if let Err(e) = self.constellation_chan.send(msg) { diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index ceb7016f9f2..c9e310074c3 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -48,74 +48,6 @@ pub struct DisplayList { pub list: Vec, } -struct ScrollOffsetLookup<'a> { - parents: &'a mut HashMap, - calculated_total_offsets: ScrollOffsetMap, - raw_offsets: &'a ScrollOffsetMap, -} - -impl<'a> ScrollOffsetLookup<'a> { - fn new(parents: &'a mut HashMap, - raw_offsets: &'a ScrollOffsetMap) - -> ScrollOffsetLookup<'a> { - ScrollOffsetLookup { - parents: parents, - calculated_total_offsets: HashMap::new(), - raw_offsets: raw_offsets, - } - } - - fn new_for_reference_frame(&mut self, - clip_id: ClipId, - transform: &Transform3D, - point: &mut Point2D) - -> Option { - // If a transform function causes the current transformation matrix of an object - // to be non-invertible, the object and its content do not get displayed. - let inv_transform = match transform.inverse() { - Some(transform) => transform, - None => return None, - }; - - let scroll_offset = self.full_offset_for_clip_scroll_node(&clip_id); - *point = Point2D::new(point.x - Au::from_f32_px(scroll_offset.x), - point.y - Au::from_f32_px(scroll_offset.y)); - let frac_point = inv_transform.transform_point2d(&Point2D::new(point.x.to_f32_px(), - point.y.to_f32_px())); - *point = Point2D::new(Au::from_f32_px(frac_point.x), Au::from_f32_px(frac_point.y)); - - let mut sublookup = ScrollOffsetLookup { - parents: &mut self.parents, - calculated_total_offsets: HashMap::new(), - raw_offsets: self.raw_offsets, - }; - sublookup.calculated_total_offsets.insert(clip_id, Vector2D::zero()); - Some(sublookup) - } - - fn add_clip_scroll_node(&mut self, clip_scroll_node: &ClipScrollNode) { - self.parents.insert(clip_scroll_node.id, clip_scroll_node.parent_id); - } - - fn full_offset_for_clip_scroll_node(&mut self, id: &ClipId) -> Vector2D { - if let Some(offset) = self.calculated_total_offsets.get(id) { - return *offset; - } - - let parent_offset = if !id.is_root_scroll_node() { - let parent_id = *self.parents.get(id).unwrap(); - self.full_offset_for_clip_scroll_node(&parent_id) - } else { - Vector2D::zero() - }; - - let offset = parent_offset + - self.raw_offsets.get(id).cloned().unwrap_or_else(Vector2D::zero); - self.calculated_total_offsets.insert(*id, offset); - offset - } -} - impl DisplayList { /// Return the bounds of this display list based on the dimensions of the root /// stacking context. @@ -128,82 +60,23 @@ impl DisplayList { } // Returns the text index within a node for the point of interest. - pub fn text_index(&self, - node: OpaqueNode, - client_point: &Point2D, - scroll_offsets: &ScrollOffsetMap) - -> Option { - let mut result = Vec::new(); + pub fn text_index(&self, node: OpaqueNode, point_in_item: &Point2D) -> Option { let mut traversal = DisplayListTraversal::new(self); - self.text_index_contents(node, - &mut traversal, - client_point, - &mut ScrollOffsetLookup::new(&mut HashMap::new(), scroll_offsets), - &mut result); - result.pop() - } - - fn text_index_contents<'a>(&self, - node: OpaqueNode, - traversal: &mut DisplayListTraversal<'a>, - point: &Point2D, - offset_lookup: &mut ScrollOffsetLookup, - result: &mut Vec) { while let Some(item) = traversal.next() { match item { - &DisplayItem::PushStackingContext(ref context_item) => { - self.text_index_stacking_context(&context_item.stacking_context, - item.scroll_node_id(), - node, - traversal, - point, - offset_lookup, - result); - } - &DisplayItem::DefineClipScrollNode(ref item) => { - offset_lookup.add_clip_scroll_node(&item.node); - } - &DisplayItem::PopStackingContext(_) => return, &DisplayItem::Text(ref text) => { let base = item.base(); if base.metadata.node == node { - let offset = *point - text.baseline_origin; - let index = text.text_run.range_index_of_advance(&text.range, offset.x); - result.push(index); + let point = *point_in_item + item.base().bounds.origin.to_vector(); + let offset = point - text.baseline_origin; + return Some(text.text_run.range_index_of_advance(&text.range, offset.x)); } }, _ => {}, } } - } - fn text_index_stacking_context<'a>(&self, - stacking_context: &StackingContext, - clip_id: ClipId, - node: OpaqueNode, - traversal: &mut DisplayListTraversal<'a>, - point: &Point2D, - offset_lookup: &mut ScrollOffsetLookup, - result: &mut Vec) { - let mut point = *point - stacking_context.bounds.origin.to_vector(); - if stacking_context.scroll_policy == ScrollPolicy::Fixed { - let old_offset = offset_lookup.calculated_total_offsets.get(&clip_id).cloned(); - offset_lookup.calculated_total_offsets.insert(clip_id, Vector2D::zero()); - - self.text_index_contents(node, traversal, &point, offset_lookup, result); - - match old_offset { - Some(offset) => offset_lookup.calculated_total_offsets.insert(clip_id, offset), - None => offset_lookup.calculated_total_offsets.remove(&clip_id), - }; - } else if let Some(transform) = stacking_context.transform { - if let Some(ref mut sublookup) = - offset_lookup.new_for_reference_frame(clip_id, &transform, &mut point) { - self.text_index_contents(node, traversal, &point, sublookup, result); - } - } else { - self.text_index_contents(node, traversal, &point, offset_lookup, result); - } + None } pub fn print(&self) { diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index ab3e620c16e..5672715834c 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -1358,18 +1358,19 @@ impl LayoutThread { let node = unsafe { ServoLayoutNode::new(&node) }; rw_data.content_boxes_response = process_content_boxes_request(node, root_flow); }, - ReflowGoal::TextIndexQuery(node, mouse_x, mouse_y) => { + ReflowGoal::TextIndexQuery(node, point_in_node) => { let node = unsafe { ServoLayoutNode::new(&node) }; let opaque_node = node.opaque(); - let client_point = Point2D::new(Au::from_px(mouse_x), - Au::from_px(mouse_y)); - rw_data.text_index_response = - TextIndexResponse(rw_data.display_list - .as_ref() - .expect("Tried to hit test with no display list") - .text_index(opaque_node, - &client_point, - &rw_data.scroll_offsets)); + let point_in_node = Point2D::new( + Au::from_f32_px(point_in_node.x), + Au::from_f32_px(point_in_node.y) + ); + rw_data.text_index_response = TextIndexResponse( + rw_data.display_list + .as_ref() + .expect("Tried to hit test with no display list") + .text_index(opaque_node, &point_in_node) + ); }, ReflowGoal::NodeGeometryQuery(node) => { let node = unsafe { ServoLayoutNode::new(&node) }; diff --git a/components/script/dom/activation.rs b/components/script/dom/activation.rs index 1b3355372dd..029e77ed449 100644 --- a/components/script/dom/activation.rs +++ b/components/script/dom/activation.rs @@ -93,6 +93,7 @@ pub fn synthetic_click_activation(element: &Element, alt_key, meta_key, 0, + None, None); let event = mouse.upcast::(); if source == ActivationSource::FromClick { diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index fd8bf37a897..cc566cdb912 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -836,7 +836,8 @@ impl Document { _button: MouseButton, client_point: Point2D, mouse_event_type: MouseEventType, - node_address: Option + node_address: Option, + point_in_node: Option> ) { let mouse_event_type_string = match mouse_event_type { MouseEventType::Click => "click".to_owned(), @@ -871,22 +872,25 @@ impl Document { let client_x = client_point.x as i32; let client_y = client_point.y as i32; let click_count = 1; - let event = MouseEvent::new(&self.window, - DOMString::from(mouse_event_type_string), - EventBubbles::Bubbles, - EventCancelable::Cancelable, - Some(&self.window), - click_count, - client_x, - client_y, - client_x, - client_y, // TODO: Get real screen coordinates? - false, - false, - false, - false, - 0i16, - None); + let event = MouseEvent::new( + &self.window, + DOMString::from(mouse_event_type_string), + EventBubbles::Bubbles, + EventCancelable::Cancelable, + Some(&self.window), + click_count, + client_x, + client_y, + client_x, + client_y, // TODO: Get real screen coordinates? + false, + false, + false, + false, + 0i16, + None, + point_in_node, + ); let event = event.upcast::(); // https://w3c.github.io/uievents/#trusted-events @@ -943,22 +947,25 @@ impl Document { let client_x = click_pos.x as i32; let client_y = click_pos.y as i32; - let event = MouseEvent::new(&self.window, - DOMString::from("dblclick"), - EventBubbles::Bubbles, - EventCancelable::Cancelable, - Some(&self.window), - click_count, - client_x, - client_y, - client_x, - client_y, - false, - false, - false, - false, - 0i16, - None); + let event = MouseEvent::new( + &self.window, + DOMString::from("dblclick"), + EventBubbles::Bubbles, + EventCancelable::Cancelable, + Some(&self.window), + click_count, + client_x, + client_y, + client_x, + client_y, + false, + false, + false, + false, + 0i16, + None, + None + ); event.upcast::().fire(target.upcast()); // When a double click occurs, self.last_click_info is left as None so that a @@ -1034,22 +1041,25 @@ impl Document { 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), - EventBubbles::Bubbles, - EventCancelable::Cancelable, - Some(&self.window), - 0i32, - client_x, - client_y, - client_x, - client_y, - false, - false, - false, - false, - 0i16, - None); + let mouse_event = MouseEvent::new( + &self.window, + DOMString::from(event_name), + EventBubbles::Bubbles, + EventCancelable::Cancelable, + Some(&self.window), + 0i32, + client_x, + client_y, + client_x, + client_y, + false, + false, + false, + false, + 0i16, + None, + None + ); let event = mouse_event.upcast::(); event.fire(target); } diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index ad82972d0e3..f30fdab885f 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -11,8 +11,6 @@ use dom::bindings::codegen::Bindings::FileListBinding::FileListMethods; use dom::bindings::codegen::Bindings::HTMLInputElementBinding; use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods; use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods; -use dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods; -use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::error::{Error, ErrorResult}; use dom::bindings::inheritance::Castable; use dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, RootedReference}; @@ -1106,23 +1104,19 @@ impl VirtualMethods for HTMLInputElement { // dispatch_key_event (document.rs) triggers a click event when releasing // the space key. There's no nice way to catch this so let's use this for // now. - if !(mouse_event.ScreenX() == 0 && mouse_event.ScreenY() == 0 && - mouse_event.GetRelatedTarget().is_none()) { - let window = window_from_node(self); - let translated_x = mouse_event.ClientX() + window.PageXOffset(); - let translated_y = mouse_event.ClientY() + window.PageYOffset(); - let TextIndexResponse(index) = window.text_index_query( - self.upcast::().to_trusted_node_address(), - translated_x, - translated_y - ); - if let Some(i) = index { - self.textinput.borrow_mut().set_edit_point_index(i as usize); - // trigger redraw - self.upcast::().dirty(NodeDamage::OtherNodeDamage); - event.PreventDefault(); - } + if let Some(point_in_target) = mouse_event.point_in_target() { + let window = window_from_node(self); + let TextIndexResponse(index) = window.text_index_query( + self.upcast::().to_trusted_node_address(), + point_in_target + ); + if let Some(i) = index { + self.textinput.borrow_mut().set_edit_point_index(i as usize); + // trigger redraw + self.upcast::().dirty(NodeDamage::OtherNodeDamage); + event.PreventDefault(); } + } } } } else if event.type_() == atom!("keydown") && !event.DefaultPrevented() && diff --git a/components/script/dom/mouseevent.rs b/components/script/dom/mouseevent.rs index 7e6fbd52eb8..62ec6f16ed3 100644 --- a/components/script/dom/mouseevent.rs +++ b/components/script/dom/mouseevent.rs @@ -15,6 +15,7 @@ use dom::eventtarget::EventTarget; use dom::uievent::UIEvent; use dom::window::Window; use dom_struct::dom_struct; +use euclid::Point2D; use servo_config::prefs::PREFS; use std::cell::Cell; use std::default::Default; @@ -32,6 +33,7 @@ pub struct MouseEvent { meta_key: Cell, button: Cell, related_target: MutNullableDom, + point_in_target: Cell>> } impl MouseEvent { @@ -48,6 +50,7 @@ impl MouseEvent { meta_key: Cell::new(false), button: Cell::new(0), related_target: Default::default(), + point_in_target: Cell::new(None), } } @@ -57,28 +60,34 @@ impl MouseEvent { MouseEventBinding::Wrap) } - pub fn new(window: &Window, - type_: DOMString, - can_bubble: EventBubbles, - cancelable: EventCancelable, - view: Option<&Window>, - detail: i32, - screen_x: i32, - screen_y: i32, - client_x: i32, - client_y: i32, - ctrl_key: bool, - alt_key: bool, - shift_key: bool, - meta_key: bool, - button: i16, - related_target: Option<&EventTarget>) -> DomRoot { + pub fn new( + window: &Window, + type_: DOMString, + can_bubble: EventBubbles, + cancelable: EventCancelable, + view: Option<&Window>, + detail: i32, + screen_x: i32, + screen_y: i32, + client_x: i32, + client_y: i32, + ctrl_key: bool, + alt_key: bool, + shift_key: bool, + meta_key: bool, + button: i16, + related_target: Option<&EventTarget>, + point_in_target: Option> + ) -> DomRoot { let ev = MouseEvent::new_uninitialized(window); - ev.InitMouseEvent(type_, bool::from(can_bubble), bool::from(cancelable), - view, detail, - screen_x, screen_y, client_x, client_y, - ctrl_key, alt_key, shift_key, meta_key, - button, related_target); + ev.InitMouseEvent( + type_, bool::from(can_bubble), bool::from(cancelable), + view, detail, + screen_x, screen_y, client_x, client_y, + ctrl_key, alt_key, shift_key, meta_key, + button, related_target, + ); + ev.point_in_target.set(point_in_target); ev } @@ -87,18 +96,24 @@ impl MouseEvent { init: &MouseEventBinding::MouseEventInit) -> Fallible> { let bubbles = EventBubbles::from(init.parent.parent.parent.bubbles); let cancelable = EventCancelable::from(init.parent.parent.parent.cancelable); - let event = MouseEvent::new(window, - type_, - bubbles, - cancelable, - init.parent.parent.view.r(), - init.parent.parent.detail, - init.screenX, init.screenY, - init.clientX, init.clientY, init.parent.ctrlKey, - init.parent.altKey, init.parent.shiftKey, init.parent.metaKey, - init.button, init.relatedTarget.r()); + let event = MouseEvent::new( + window, + type_, + bubbles, + cancelable, + init.parent.parent.view.r(), + init.parent.parent.detail, + init.screenX, init.screenY, + init.clientX, init.clientY, init.parent.ctrlKey, + init.parent.altKey, init.parent.shiftKey, init.parent.metaKey, + init.button, init.relatedTarget.r(), None + ); Ok(event) } + + pub fn point_in_target(&self) -> Option> { + self.point_in_target.get() + } } impl MouseEventMethods for MouseEvent { @@ -166,22 +181,24 @@ impl MouseEventMethods for MouseEvent { } // https://w3c.github.io/uievents/#widl-MouseEvent-initMouseEvent - fn InitMouseEvent(&self, - type_arg: DOMString, - can_bubble_arg: bool, - cancelable_arg: bool, - view_arg: Option<&Window>, - detail_arg: i32, - screen_x_arg: i32, - screen_y_arg: i32, - client_x_arg: i32, - client_y_arg: i32, - ctrl_key_arg: bool, - alt_key_arg: bool, - shift_key_arg: bool, - meta_key_arg: bool, - button_arg: i16, - related_target_arg: Option<&EventTarget>) { + fn InitMouseEvent( + &self, + type_arg: DOMString, + can_bubble_arg: bool, + cancelable_arg: bool, + view_arg: Option<&Window>, + detail_arg: i32, + screen_x_arg: i32, + screen_y_arg: i32, + client_x_arg: i32, + client_y_arg: i32, + ctrl_key_arg: bool, + alt_key_arg: bool, + shift_key_arg: bool, + meta_key_arg: bool, + button_arg: i16, + related_target_arg: Option<&EventTarget>, + ) { if self.upcast::().dispatching() { return; } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 9d2137911d7..847440c6358 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1481,8 +1481,12 @@ impl Window { self.layout_rpc.margin_style() } - pub fn text_index_query(&self, node: TrustedNodeAddress, mouse_x: i32, mouse_y: i32) -> TextIndexResponse { - if !self.reflow(ReflowGoal::TextIndexQuery(node, mouse_x, mouse_y), ReflowReason::Query) { + pub fn text_index_query( + &self, + node: TrustedNodeAddress, + point_in_node: Point2D + ) -> TextIndexResponse { + if !self.reflow(ReflowGoal::TextIndexQuery(node, point_in_node), ReflowReason::Query) { return TextIndexResponse(None); } self.layout_rpc.text_index() diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 1413a0c40dc..8f6871f8e56 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -2187,8 +2187,15 @@ impl ScriptThread { self.handle_resize_event(pipeline_id, new_size, size_type); } - MouseButtonEvent(event_type, button, point, node_address) => { - self.handle_mouse_event(pipeline_id, event_type, button, point, node_address); + MouseButtonEvent(event_type, button, point, node_address, point_in_node) => { + self.handle_mouse_event( + pipeline_id, + event_type, + button, + point, + node_address, + point_in_node + ); } MouseMoveEvent(point, node_address) => { @@ -2299,7 +2306,8 @@ impl ScriptThread { mouse_event_type: MouseEventType, button: MouseButton, point: Point2D, - node_address: Option + node_address: Option, + point_in_node: Option> ) { let document = match { self.documents.borrow().find_document(pipeline_id) } { Some(document) => document, @@ -2310,7 +2318,8 @@ impl ScriptThread { button, point, mouse_event_type, - node_address + node_address, + point_in_node ); } diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs index 6f8009ecdd8..083167d6c34 100644 --- a/components/script_layout_interface/message.rs +++ b/components/script_layout_interface/message.rs @@ -120,7 +120,7 @@ pub enum ReflowGoal { ResolvedStyleQuery(TrustedNodeAddress, Option, PropertyId), OffsetParentQuery(TrustedNodeAddress), MarginStyleQuery(TrustedNodeAddress), - TextIndexQuery(TrustedNodeAddress, i32, i32), + TextIndexQuery(TrustedNodeAddress, Point2D), NodesFromPointQuery(Point2D, NodesFromPointQueryType), } diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 1b9beaf37ff..bcd4b765588 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -436,7 +436,13 @@ pub enum CompositorEvent { /// The window was resized. ResizeEvent(WindowSizeData, WindowSizeType), /// A mouse button state changed. - MouseButtonEvent(MouseEventType, MouseButton, Point2D, Option), + MouseButtonEvent( + MouseEventType, + MouseButton, + Point2D, + Option, + Option> + ), /// The mouse was moved over a point (or was moved out of the recognizable region). MouseMoveEvent(Option>, Option), /// A touch event was generated with a touch ID and location.