From 89bfa26f000f6f0008093b1787bca1643f4ecef3 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Thu, 3 Jul 2025 15:04:06 +0200 Subject: [PATCH] libservo|compositor: Have scroll offset directionality match that of WebRender and the web (#37752) Previously, our Servo-specific spatial tree scroll offsets were opposite to that of WebRender and also the web platform. This is due to the fact, likely, that `winit` wheel directionality is also flipped. This change has both the Servo spatial tree and the API take offsets that are consistent with the web. Any possible changes to the meaning of wheel directionality will be handled in a followup change. This is a breaking change to the Servo API. Testing: This change updates unit tests. Signed-off-by: Martin Robinson Co-authored-by: Oriol Brufau --- components/compositing/compositor.rs | 14 ++++------ components/compositing/touch.rs | 13 +++++++-- components/compositing/webview_renderer.rs | 2 +- components/layout/layout_impl.rs | 3 +- components/servo/webview.rs | 2 ++ components/shared/compositing/display_list.rs | 27 ++++++------------ .../shared/compositing/tests/compositor.rs | 28 +++++++++---------- ports/servoshell/desktop/app_state.rs | 16 +++++------ ports/servoshell/desktop/headed_window.rs | 3 +- ports/servoshell/egl/android.rs | 26 ----------------- ports/servoshell/egl/app_state.rs | 24 ---------------- .../java/org/servo/servoview/JNIServo.java | 4 --- .../main/java/org/servo/servoview/Servo.java | 8 ------ .../java/org/servo/servoview/ServoView.java | 16 +++-------- 14 files changed, 54 insertions(+), 132 deletions(-) diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 79a74db93c7..81a17b5dfda 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -44,7 +44,7 @@ use style_traits::CSSPixel; use webrender::{CaptureBits, RenderApi, Transaction}; use webrender_api::units::{ DeviceIntPoint, DeviceIntRect, DevicePixel, DevicePoint, DeviceRect, LayoutPoint, LayoutRect, - LayoutSize, LayoutVector2D, WorldPoint, + LayoutSize, WorldPoint, }; use webrender_api::{ self, BuiltDisplayList, DirtyRect, DisplayListPayload, DocumentId, Epoch as WebRenderEpoch, @@ -714,11 +714,9 @@ impl IOCompositor { // is inverted compared to `winit`s wheel delta. Hence, // here we invert the sign to mimic wheel scroll // implementation in `headed_window.rs`. - let dx = -dx; - let dy = -dy; let delta = WheelDelta { - x: dx, - y: dy, + x: -dx, + y: -dy, z: 0.0, mode: WheelMode::DeltaPixel, }; @@ -768,7 +766,7 @@ impl IOCompositor { txn.set_scroll_offsets( external_scroll_id, vec![SampledScrollOffset { - offset: -offset, + offset, generation: 0, }], ); @@ -1169,7 +1167,6 @@ impl IOCompositor { continue; }; - let offset = LayoutVector2D::new(-offset.x, -offset.y); transaction.set_scroll_offsets( external_id, vec![SampledScrollOffset { @@ -1731,11 +1728,10 @@ impl IOCompositor { self.send_root_pipeline_display_list_in_transaction(&mut transaction); } for update in scroll_offset_updates { - let offset = LayoutVector2D::new(-update.offset.x, -update.offset.y); transaction.set_scroll_offsets( update.external_scroll_id, vec![SampledScrollOffset { - offset, + offset: update.offset, generation: 0, }], ); diff --git a/components/compositing/touch.rs b/components/compositing/touch.rs index 1fe8d14817d..357ca48d70e 100644 --- a/components/compositing/touch.rs +++ b/components/compositing/touch.rs @@ -406,7 +406,9 @@ impl TouchHandler { *velocity /= 2.0; // update the touch point every time when panning. touch_sequence.active_touch_points[idx].point = point; - TouchMoveAction::Scroll(delta, point) + + // Scroll offsets are opposite to the direction of finger motion. + TouchMoveAction::Scroll(-delta, point) } else if delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX || delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX { @@ -417,7 +419,9 @@ impl TouchHandler { touch_sequence.prevent_click = true; // update the touch point touch_sequence.active_touch_points[idx].point = point; - TouchMoveAction::Scroll(delta, point) + + // Scroll offsets are opposite to the direction of finger motion. + TouchMoveAction::Scroll(-delta, point) } else { // We don't update the touchpoint, so multiple small moves can // accumulate and merge into a larger move. @@ -435,8 +439,11 @@ impl TouchHandler { touch_sequence.active_touch_points[idx].point = point; let (d1, c1) = touch_sequence.pinch_distance_and_center(); let magnification = d1 / d0; + let scroll_delta = c1 - c0 * Scale::new(magnification); - TouchMoveAction::Zoom(magnification, scroll_delta) + + // Scroll offsets are opposite to the direction of finger motion. + TouchMoveAction::Zoom(magnification, -scroll_delta) } else { // We don't update the touchpoint, so multiple small moves can // accumulate and merge into a larger move. diff --git a/components/compositing/webview_renderer.rs b/components/compositing/webview_renderer.rs index 2f0575837fe..d810e3286fb 100644 --- a/components/compositing/webview_renderer.rs +++ b/components/compositing/webview_renderer.rs @@ -339,7 +339,7 @@ impl WebViewRenderer { pub(crate) fn on_vsync(&mut self) { if let Some(fling_action) = self.touch_handler.on_vsync() { self.on_scroll_window_event( - ScrollLocation::Delta(fling_action.delta), + ScrollLocation::Delta(-fling_action.delta), fling_action.cursor, ); } diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs index cd0e84e3710..cac6ec75b04 100644 --- a/components/layout/layout_impl.rs +++ b/components/layout/layout_impl.rs @@ -476,7 +476,6 @@ impl Layout for LayoutThread { .borrow_mut() .as_mut() .and_then(|tree| tree.compositor_info.scroll_tree.scroll_offset(id)) - .map(|scroll_offset| -scroll_offset) } } @@ -1083,7 +1082,7 @@ impl LayoutThread { .scroll_tree .set_scroll_offset_for_node_with_external_scroll_id( external_scroll_id, - -offset, + offset, ScrollType::Script, ) { diff --git a/components/servo/webview.rs b/components/servo/webview.rs index 9fbc21b46f0..f71f31634a9 100644 --- a/components/servo/webview.rs +++ b/components/servo/webview.rs @@ -434,6 +434,8 @@ impl WebView { )) } + /// Ask the [`WebView`] to scroll web content. Note that positive scroll offsets reveal more + /// content on the bottom and right of the page. pub fn notify_scroll_event(&self, location: ScrollLocation, point: DeviceIntPoint) { self.inner() .compositor diff --git a/components/shared/compositing/display_list.rs b/components/shared/compositing/display_list.rs index c426f58a85c..60692a9d913 100644 --- a/components/shared/compositing/display_list.rs +++ b/components/shared/compositing/display_list.rs @@ -130,11 +130,11 @@ impl ScrollableNodeInfo { let original_layer_scroll_offset = self.offset; if scrollable_size.width > 0. && self.scroll_sensitivity.x.contains(context) { - self.offset.x = new_offset.x.min(0.0).max(-scrollable_size.width); + self.offset.x = new_offset.x.clamp(0.0, scrollable_size.width); } if scrollable_size.height > 0. && self.scroll_sensitivity.y.contains(context) { - self.offset.y = new_offset.y.min(0.0).max(-scrollable_size.height); + self.offset.y = new_offset.y.clamp(0.0, scrollable_size.height); } if self.offset != original_layer_scroll_offset { @@ -158,7 +158,7 @@ impl ScrollableNodeInfo { let delta = match scroll_location { ScrollLocation::Delta(delta) => delta, ScrollLocation::Start => { - if self.offset.y.round() >= 0.0 { + if self.offset.y.round() <= 0.0 { // Nothing to do on this layer. return None; } @@ -167,8 +167,8 @@ impl ScrollableNodeInfo { return Some(self.offset); }, ScrollLocation::End => { - let end_pos = -self.scrollable_size().height; - if self.offset.y.round() <= end_pos { + let end_pos = self.scrollable_size().height; + if self.offset.y.round() >= end_pos { // Nothing to do on this layer. return None; } @@ -231,20 +231,9 @@ impl ScrollTreeNode { /// Set the offset for this node, returns false if this was a /// non-scrolling node for which you cannot set the offset. - pub fn set_offset(&mut self, new_offset: LayoutVector2D) -> bool { - match self.info { - SpatialTreeNodeInfo::Scroll(ref mut info) => { - let scrollable_size = info.scrollable_size(); - if scrollable_size.width > 0. { - info.offset.x = (new_offset.x).min(0.0).max(-scrollable_size.width); - } - - if scrollable_size.height > 0. { - info.offset.y = (new_offset.y).min(0.0).max(-scrollable_size.height); - } - true - }, - _ => false, + pub fn set_offset(&mut self, new_offset: LayoutVector2D) { + if let SpatialTreeNodeInfo::Scroll(ref mut info) = self.info { + info.scroll_to_offset(new_offset, ScrollType::Script); } } diff --git a/components/shared/compositing/tests/compositor.rs b/components/shared/compositing/tests/compositor.rs index a061d467086..157b51be3a8 100644 --- a/components/shared/compositing/tests/compositor.rs +++ b/components/shared/compositing/tests/compositor.rs @@ -46,11 +46,11 @@ fn test_scroll_tree_simple_scroll() { let (scrolled_id, offset) = scroll_tree .scroll_node_or_ancestor( &id, - ScrollLocation::Delta(LayoutVector2D::new(-20.0, -40.0)), + ScrollLocation::Delta(LayoutVector2D::new(20.0, 40.0)), ScrollType::Script, ) .unwrap(); - let expected_offset = LayoutVector2D::new(-20.0, -40.0); + let expected_offset = LayoutVector2D::new(20.0, 40.0); assert_eq!(scrolled_id, ExternalScrollId(0, pipeline_id)); assert_eq!(offset, expected_offset); assert_eq!(scroll_tree.get_node(&id).offset(), Some(expected_offset)); @@ -58,7 +58,7 @@ fn test_scroll_tree_simple_scroll() { let (scrolled_id, offset) = scroll_tree .scroll_node_or_ancestor( &id, - ScrollLocation::Delta(LayoutVector2D::new(20.0, 40.0)), + ScrollLocation::Delta(LayoutVector2D::new(-20.0, -40.0)), ScrollType::Script, ) .unwrap(); @@ -67,10 +67,10 @@ fn test_scroll_tree_simple_scroll() { assert_eq!(offset, expected_offset); assert_eq!(scroll_tree.get_node(&id).offset(), Some(expected_offset)); - // Scroll offsets must be negative. + // Scroll offsets must be positive. let result = scroll_tree.scroll_node_or_ancestor( &id, - ScrollLocation::Delta(LayoutVector2D::new(20.0, 40.0)), + ScrollLocation::Delta(LayoutVector2D::new(-20.0, -40.0)), ScrollType::Script, ); assert!(result.is_none()); @@ -99,11 +99,11 @@ fn test_scroll_tree_simple_scroll_chaining() { let (scrolled_id, offset) = scroll_tree .scroll_node_or_ancestor( &unscrollable_child_id, - ScrollLocation::Delta(LayoutVector2D::new(-20.0, -40.0)), + ScrollLocation::Delta(LayoutVector2D::new(20.0, 40.0)), ScrollType::Script, ) .unwrap(); - let expected_offset = LayoutVector2D::new(-20.0, -40.0); + let expected_offset = LayoutVector2D::new(20.0, 40.0); assert_eq!(scrolled_id, ExternalScrollId(0, pipeline_id)); assert_eq!(offset, expected_offset); assert_eq!( @@ -114,11 +114,11 @@ fn test_scroll_tree_simple_scroll_chaining() { let (scrolled_id, offset) = scroll_tree .scroll_node_or_ancestor( &unscrollable_child_id, - ScrollLocation::Delta(LayoutVector2D::new(-10.0, -15.0)), + ScrollLocation::Delta(LayoutVector2D::new(10.0, 15.0)), ScrollType::Script, ) .unwrap(); - let expected_offset = LayoutVector2D::new(-30.0, -55.0); + let expected_offset = LayoutVector2D::new(30.0, 55.0); assert_eq!(scrolled_id, ExternalScrollId(0, pipeline_id)); assert_eq!(offset, expected_offset); assert_eq!( @@ -140,7 +140,7 @@ fn test_scroll_tree_chain_when_at_extent() { .scroll_node_or_ancestor(&child_id, ScrollLocation::End, ScrollType::Script) .unwrap(); - let expected_offset = LayoutVector2D::new(0.0, -100.0); + let expected_offset = LayoutVector2D::new(0.0, 100.0); assert_eq!(scrolled_id, ExternalScrollId(1, pipeline_id)); assert_eq!(offset, expected_offset); assert_eq!( @@ -153,11 +153,11 @@ fn test_scroll_tree_chain_when_at_extent() { let (scrolled_id, offset) = scroll_tree .scroll_node_or_ancestor( &child_id, - ScrollLocation::Delta(LayoutVector2D::new(0.0, -10.0)), + ScrollLocation::Delta(LayoutVector2D::new(0.0, 10.0)), ScrollType::Script, ) .unwrap(); - let expected_offset = LayoutVector2D::new(0.0, -10.0); + let expected_offset = LayoutVector2D::new(0.0, 10.0); assert_eq!(scrolled_id, ExternalScrollId(0, pipeline_id)); assert_eq!(offset, expected_offset); assert_eq!( @@ -187,11 +187,11 @@ fn test_scroll_tree_chain_through_overflow_hidden() { let (scrolled_id, offset) = scroll_tree .scroll_node_or_ancestor( &overflow_hidden_id, - ScrollLocation::Delta(LayoutVector2D::new(-20.0, -40.0)), + ScrollLocation::Delta(LayoutVector2D::new(20.0, 40.0)), ScrollType::InputEvents, ) .unwrap(); - let expected_offset = LayoutVector2D::new(-20.0, -40.0); + let expected_offset = LayoutVector2D::new(20.0, 40.0); assert_eq!(scrolled_id, ExternalScrollId(0, pipeline_id)); assert_eq!(offset, expected_offset); assert_eq!( diff --git a/ports/servoshell/desktop/app_state.rs b/ports/servoshell/desktop/app_state.rs index bad4ea4eaa8..db6a0a7f0c8 100644 --- a/ports/servoshell/desktop/app_state.rs +++ b/ports/servoshell/desktop/app_state.rs @@ -361,14 +361,14 @@ impl RunningAppState { .shortcut(Modifiers::empty(), Key::PageDown, || { let scroll_location = ScrollLocation::Delta(Vector2D::new( 0.0, - -self.inner().window.page_height() + 2.0 * LINE_HEIGHT, + self.inner().window.page_height() - 2.0 * LINE_HEIGHT, )); webview.notify_scroll_event(scroll_location, origin); }) .shortcut(Modifiers::empty(), Key::PageUp, || { let scroll_location = ScrollLocation::Delta(Vector2D::new( 0.0, - self.inner().window.page_height() - 2.0 * LINE_HEIGHT, + -self.inner().window.page_height() + 2.0 * LINE_HEIGHT, )); webview.notify_scroll_event(scroll_location, origin); }) @@ -379,19 +379,19 @@ impl RunningAppState { webview.notify_scroll_event(ScrollLocation::End, origin); }) .shortcut(Modifiers::empty(), Key::ArrowUp, || { - let location = ScrollLocation::Delta(Vector2D::new(0.0, 3.0 * LINE_HEIGHT)); - webview.notify_scroll_event(location, origin); - }) - .shortcut(Modifiers::empty(), Key::ArrowDown, || { let location = ScrollLocation::Delta(Vector2D::new(0.0, -3.0 * LINE_HEIGHT)); webview.notify_scroll_event(location, origin); }) + .shortcut(Modifiers::empty(), Key::ArrowDown, || { + let location = ScrollLocation::Delta(Vector2D::new(0.0, 3.0 * LINE_HEIGHT)); + webview.notify_scroll_event(location, origin); + }) .shortcut(Modifiers::empty(), Key::ArrowLeft, || { - let location = ScrollLocation::Delta(Vector2D::new(LINE_HEIGHT, 0.0)); + let location = ScrollLocation::Delta(Vector2D::new(-LINE_HEIGHT, 0.0)); webview.notify_scroll_event(location, origin); }) .shortcut(Modifiers::empty(), Key::ArrowRight, || { - let location = ScrollLocation::Delta(Vector2D::new(-LINE_HEIGHT, 0.0)); + let location = ScrollLocation::Delta(Vector2D::new(LINE_HEIGHT, 0.0)); webview.notify_scroll_event(location, origin); }); } diff --git a/ports/servoshell/desktop/headed_window.rs b/ports/servoshell/desktop/headed_window.rs index 3769a43629c..341b8c12e67 100644 --- a/ports/servoshell/desktop/headed_window.rs +++ b/ports/servoshell/desktop/headed_window.rs @@ -630,10 +630,9 @@ impl WindowPortsMethods for Window { dy = 0.0; } - let scroll_location = ScrollLocation::Delta(Vector2D::new(dx as f32, dy as f32)); - // Send events webview.notify_input_event(InputEvent::Wheel(WheelEvent::new(delta, point))); + let scroll_location = ScrollLocation::Delta(-Vector2D::new(dx as f32, dy as f32)); webview.notify_scroll_event(scroll_location, point.to_i32()); }, WindowEvent::Touch(touch) => { diff --git a/ports/servoshell/egl/android.rs b/ports/servoshell/egl/android.rs index 5a3047c8542..88cc05a6ed9 100644 --- a/ports/servoshell/egl/android.rs +++ b/ports/servoshell/egl/android.rs @@ -244,32 +244,6 @@ pub extern "C" fn Java_org_servo_servoview_JNIServo_goForward<'local>( call(&mut env, |s| s.go_forward()); } -#[unsafe(no_mangle)] -pub extern "C" fn Java_org_servo_servoview_JNIServo_scrollStart<'local>( - mut env: JNIEnv<'local>, - _: JClass<'local>, - dx: jint, - dy: jint, - x: jint, - y: jint, -) { - debug!("scrollStart"); - call(&mut env, |s| s.scroll_start(dx as f32, dy as f32, x, y)); -} - -#[unsafe(no_mangle)] -pub extern "C" fn Java_org_servo_servoview_JNIServo_scrollEnd<'local>( - mut env: JNIEnv<'local>, - _: JClass<'local>, - dx: jint, - dy: jint, - x: jint, - y: jint, -) { - debug!("scrollEnd"); - call(&mut env, |s| s.scroll_end(dx as f32, dy as f32, x, y)); -} - #[unsafe(no_mangle)] pub extern "C" fn Java_org_servo_servoview_JNIServo_scroll<'local>( mut env: JNIEnv<'local>, diff --git a/ports/servoshell/egl/app_state.rs b/ports/servoshell/egl/app_state.rs index e767e1a8c2b..11ba656d7fc 100644 --- a/ports/servoshell/egl/app_state.rs +++ b/ports/servoshell/egl/app_state.rs @@ -474,18 +474,6 @@ impl RunningAppState { self.perform_updates(); } - /// Start scrolling. - /// x/y are scroll coordinates. - /// dx/dy are scroll deltas. - #[cfg(not(target_env = "ohos"))] - pub fn scroll_start(&self, dx: f32, dy: f32, x: i32, y: i32) { - let delta = Vector2D::new(dx, dy); - let scroll_location = ScrollLocation::Delta(delta); - self.active_webview() - .notify_scroll_event(scroll_location, Point2D::new(x, y)); - self.perform_updates(); - } - /// Scroll. /// x/y are scroll coordinates. /// dx/dy are scroll deltas. @@ -497,18 +485,6 @@ impl RunningAppState { self.perform_updates(); } - /// End scrolling. - /// x/y are scroll coordinates. - /// dx/dy are scroll deltas. - #[cfg(not(target_env = "ohos"))] - pub fn scroll_end(&self, dx: f32, dy: f32, x: i32, y: i32) { - let delta = Vector2D::new(dx, dy); - let scroll_location = ScrollLocation::Delta(delta); - self.active_webview() - .notify_scroll_event(scroll_location, Point2D::new(x, y)); - self.perform_updates(); - } - /// Touch event: press down pub fn touch_down(&self, x: f32, y: f32, pointer_id: i32) { self.active_webview() diff --git a/support/android/apk/servoview/src/main/java/org/servo/servoview/JNIServo.java b/support/android/apk/servoview/src/main/java/org/servo/servoview/JNIServo.java index 131c1410b2c..5b2e13ddd24 100644 --- a/support/android/apk/servoview/src/main/java/org/servo/servoview/JNIServo.java +++ b/support/android/apk/servoview/src/main/java/org/servo/servoview/JNIServo.java @@ -41,12 +41,8 @@ public class JNIServo { public native void loadUri(String uri); - public native void scrollStart(int dx, int dy, int x, int y); - public native void scroll(int dx, int dy, int x, int y); - public native void scrollEnd(int dx, int dy, int x, int y); - public native void touchDown(float x, float y, int pointer_id); public native void touchMove(float x, float y, int pointer_id); diff --git a/support/android/apk/servoview/src/main/java/org/servo/servoview/Servo.java b/support/android/apk/servoview/src/main/java/org/servo/servoview/Servo.java index 9687278c0bf..399dfea31e6 100644 --- a/support/android/apk/servoview/src/main/java/org/servo/servoview/Servo.java +++ b/support/android/apk/servoview/src/main/java/org/servo/servoview/Servo.java @@ -107,18 +107,10 @@ public class Servo { mRunCallback.inGLThread(() -> mJNI.loadUri(uri)); } - public void scrollStart(int dx, int dy, int x, int y) { - mRunCallback.inGLThread(() -> mJNI.scrollStart(dx, dy, x, y)); - } - public void scroll(int dx, int dy, int x, int y) { mRunCallback.inGLThread(() -> mJNI.scroll(dx, dy, x, y)); } - public void scrollEnd(int dx, int dy, int x, int y) { - mRunCallback.inGLThread(() -> mJNI.scrollEnd(dx, dy, x, y)); - } - public void touchDown(float x, float y, int pointerId) { mRunCallback.inGLThread(() -> mJNI.touchDown(x, y, pointerId)); } diff --git a/support/android/apk/servoview/src/main/java/org/servo/servoview/ServoView.java b/support/android/apk/servoview/src/main/java/org/servo/servoview/ServoView.java index 5001f910ed4..7a8d0c9cd6f 100644 --- a/support/android/apk/servoview/src/main/java/org/servo/servoview/ServoView.java +++ b/support/android/apk/servoview/src/main/java/org/servo/servoview/ServoView.java @@ -143,7 +143,7 @@ public class ServoView extends SurfaceView if (mFlinging && mScroller.isFinished()) { mFlinging = false; - mServo.scrollEnd(0, 0, mCurX, mCurY); + mServo.scroll(0, 0, -mCurX, -mCurY); } if (mFlinging) { @@ -172,7 +172,7 @@ public class ServoView extends SurfaceView int x = Math.min(mCurX, this.getHeight()); int y = Math.min(mCurY, this.getWidth()); - mServo.scroll(dx, dy, x, y); + mServo.scroll(-dx, -dy, x, y); } if (zoomNecessary) { @@ -229,18 +229,10 @@ public class ServoView extends SurfaceView } } - public void scrollStart(int dx, int dy, int x, int y) { - mServo.scrollStart(dx, dy, x, y); - } - public void scroll(int dx, int dy, int x, int y) { mServo.scroll(dx, dy, x, y); } - public void scrollEnd(int dx, int dy, int x, int y) { - mServo.scrollEnd(dx, dy, x, y); - } - public void click(float x, float y) { mServo.click(x, y); } @@ -257,7 +249,7 @@ public class ServoView extends SurfaceView mCurY = velocityY < 0 ? mPageHeight : 0; mLastY = mCurY; mScroller.fling(mCurX, mCurY, (int) velocityX, (int) velocityY, 0, mPageWidth, 0, mPageHeight); - mServo.scrollStart(0, 0, mCurX, mCurY); + mServo.scroll(0, 0, mCurX, mCurY); startLooping(); return true; } @@ -309,7 +301,7 @@ public class ServoView extends SurfaceView } public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - mServo.scroll((int) -distanceX, (int) -distanceY, (int) e2.getX(), (int) e2.getY()); + mServo.scroll((int) distanceX, (int) distanceY, (int) e2.getX(), (int) e2.getY()); return true; }