Bug 1251346 - Fennec should not generate touch events from mouse events. r=kats
authorRandall Barker <rbarker@mozilla.com>
Fri, 11 Mar 2016 15:29:50 -0800
changeset 288660 64aa2a8a7e73f5d7e49d1ab355b6ee6d38a2e627
parent 288659 7c53fd9ec1fef76b87533ac4158fd4eca7eef049
child 288661 c37cf1c267357c4df8e5f70af39a8d544a957f85
push id30087
push usercbook@mozilla.com
push dateTue, 15 Mar 2016 09:43:43 +0000
treeherdermozilla-central@5e14887312d4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1251346
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1251346 - Fennec should not generate touch events from mouse events. r=kats
mobile/android/base/java/org/mozilla/gecko/gfx/DynamicToolbarAnimator.java
mobile/android/base/java/org/mozilla/gecko/gfx/NativePanZoomController.java
widget/InputData.cpp
widget/InputData.h
widget/android/GeneratedJNINatives.h
widget/android/GeneratedJNIWrappers.cpp
widget/android/GeneratedJNIWrappers.h
widget/android/nsWindow.cpp
--- a/mobile/android/base/java/org/mozilla/gecko/gfx/DynamicToolbarAnimator.java
+++ b/mobile/android/base/java/org/mozilla/gecko/gfx/DynamicToolbarAnimator.java
@@ -372,17 +372,18 @@ public class DynamicToolbarAnimator {
         // Animations should never co-exist with the user touching the screen.
         if (mAnimationTask != null) {
             mTarget.getView().removeRenderTask(mAnimationTask);
             mAnimationTask = null;
         }
 
         // we only care about single-finger drags here; any other kind of event
         // should reset and cause us to start over.
-        if (event.getActionMasked() != MotionEvent.ACTION_MOVE ||
+        if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE ||
+            event.getActionMasked() != MotionEvent.ACTION_MOVE ||
             event.getPointerCount() != 1)
         {
             if (mTouchStart != null) {
                 Log.v(LOGTAG, "Resetting touch sequence due to non-move");
                 mTouchStart = null;
             }
 
             if (event.getActionMasked() == MotionEvent.ACTION_UP) {
--- a/mobile/android/base/java/org/mozilla/gecko/gfx/NativePanZoomController.java
+++ b/mobile/android/base/java/org/mozilla/gecko/gfx/NativePanZoomController.java
@@ -41,19 +41,19 @@ class NativePanZoomController extends JN
 
     @WrapForJNI
     private native boolean handleScrollEvent(
             long time, int metaState,
             float x, float y,
             float hScroll, float vScroll);
 
     @WrapForJNI
-    private native boolean handleHoverEvent(
+    private native boolean handleMouseEvent(
             int action, long time, int metaState,
-            float x, float y);
+            float x, float y, int buttons);
 
     private boolean handleMotionEvent(MotionEvent event, boolean keepInViewCoordinates) {
         if (mDestroyed) {
             return false;
         }
 
         final int action = event.getActionMasked();
         final int count = event.getPointerCount();
@@ -122,33 +122,33 @@ class NativePanZoomController extends JN
 
         final float flipFactor = mNegateWheelScroll ? -1.0f : 1.0f;
         final float hScroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL) * flipFactor * mPointerScrollFactor;
         final float vScroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL) * flipFactor * mPointerScrollFactor;
 
         return handleScrollEvent(event.getEventTime(), event.getMetaState(), x, y, hScroll, vScroll);
     }
 
-    private boolean handleHoverEvent(MotionEvent event) {
+    private boolean handleMouseEvent(MotionEvent event) {
         if (mDestroyed) {
             return false;
         }
 
         final int count = event.getPointerCount();
 
         if (count <= 0) {
             return false;
         }
 
         final MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
         event.getPointerCoords(0, coords);
         final float x = coords.x;
         final float y = coords.y;
 
-        return handleHoverEvent(event.getActionMasked(), event.getEventTime(), event.getMetaState(), x, y);
+        return handleMouseEvent(event.getActionMasked(), event.getEventTime(), event.getMetaState(), x, y, event.getButtonState());
     }
 
 
     NativePanZoomController(PanZoomTarget target, View view) {
         mTarget = target;
         mView = (LayerView) view;
 
         String[] prefs = { "ui.scrolling.negate_wheel_scroll" };
@@ -166,29 +166,33 @@ class NativePanZoomController extends JN
             mPointerScrollFactor = outValue.getDimension(view.getContext().getResources().getDisplayMetrics());
         } else {
             mPointerScrollFactor = MAX_SCROLL;
         }
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        return handleMotionEvent(event, /* keepInViewCoordinates */ true);
+        if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
+            return handleMouseEvent(event);
+        } else {
+            return handleMotionEvent(event, /* keepInViewCoordinates */ true);
+        }
     }
 
     @Override
     public boolean onMotionEvent(MotionEvent event) {
         final int action = event.getActionMasked();
         if (action == MotionEvent.ACTION_SCROLL && event.getDownTime() >= mLastDownTime) {
             mLastDownTime = event.getDownTime();
             return handleScrollEvent(event);
         } else if ((action == MotionEvent.ACTION_HOVER_MOVE) ||
                    (action == MotionEvent.ACTION_HOVER_ENTER) ||
                    (action == MotionEvent.ACTION_HOVER_EXIT)) {
-            return handleHoverEvent(event);
+            return handleMouseEvent(event);
         } else {
             return false;
         }
     }
 
     @Override
     public boolean onKeyEvent(KeyEvent event) {
         // FIXME implement this
--- a/widget/InputData.cpp
+++ b/widget/InputData.cpp
@@ -98,25 +98,28 @@ MouseInput::TransformToLocal(const Scree
 
 WidgetMouseEvent
 MouseInput::ToWidgetMouseEvent(nsIWidget* aWidget) const
 {
   MOZ_ASSERT(NS_IsMainThread(),
              "Can only convert To WidgetTouchEvent on main thread");
 
   EventMessage msg = eVoidEvent;
+  uint32_t clickCount = 0;
   switch (mType) {
     case MOUSE_MOVE:
       msg = eMouseMove;
       break;
     case MOUSE_UP:
       msg = eMouseUp;
+      clickCount = 1;
       break;
     case MOUSE_DOWN:
       msg = eMouseDown;
+      clickCount = 1;
       break;
     case MOUSE_DRAG_START:
       msg = eDragStart;
       break;
     case MOUSE_DRAG_END:
       msg = eDragEnd;
       break;
     case MOUSE_WIDGET_ENTER:
@@ -153,16 +156,19 @@ MouseInput::ToWidgetMouseEvent(nsIWidget
 
   event.buttons = mButtons;
   event.modifiers = modifiers;
   event.time = mTime;
   event.timeStamp = mTimeStamp;
   event.refPoint =
     RoundedToInt(ViewAs<LayoutDevicePixel>(mOrigin,
       PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
+  event.clickCount = clickCount;
+  event.inputSource = mInputSource;
+  event.ignoreRootScrollFrame = true;
 
   return event;
 }
 
 MultiTouchInput::MultiTouchInput(const WidgetTouchEvent& aTouchEvent)
   : InputData(MULTITOUCH_INPUT, aTouchEvent.time, aTouchEvent.timeStamp,
               aTouchEvent.modifiers)
   , mHandledByAPZ(aTouchEvent.mFlags.mHandledByAPZ)
--- a/widget/InputData.h
+++ b/widget/InputData.h
@@ -267,41 +267,44 @@ public:
   enum ButtonType
   {
     LEFT_BUTTON,
     MIDDLE_BUTTON,
     RIGHT_BUTTON,
     NONE
   };
 
-  MouseInput(MouseType aType, ButtonType aButtonType, int16_t aButtons, const ScreenPoint& aPoint,
+  MouseInput(MouseType aType, ButtonType aButtonType, uint16_t aInputSource, int16_t aButtons, const ScreenPoint& aPoint,
              uint32_t aTime, TimeStamp aTimeStamp, Modifiers aModifiers)
     : InputData(MOUSE_INPUT, aTime, aTimeStamp, aModifiers)
     , mType(aType)
     , mButtonType(aButtonType)
+    , mInputSource(aInputSource)
     , mButtons(aButtons)
     , mOrigin(aPoint)
   {}
 
   MouseInput()
     : InputData(MOUSE_INPUT)
     , mType(MOUSE_NONE)
     , mButtonType(NONE)
+    , mInputSource(0)
     , mButtons(0)
   {}
 
   explicit MouseInput(const WidgetMouseEventBase& aMouseEvent);
 
   bool IsLeftButton() const { return mButtonType == LEFT_BUTTON; }
 
   bool TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform);
   WidgetMouseEvent ToWidgetMouseEvent(nsIWidget* aWidget) const;
 
   MouseType mType;
   ButtonType mButtonType;
+  uint16_t mInputSource;
   int16_t mButtons;
   ScreenPoint mOrigin;
   ParentLayerPoint mLocalOrigin;
 };
 
 /**
  * Encapsulation class for pan events, can be used off-main-thread.
  * These events are currently only used for scrolling on desktop.
--- a/widget/android/GeneratedJNINatives.h
+++ b/widget/android/GeneratedJNINatives.h
@@ -289,24 +289,24 @@ public:
         mozilla::jni::MakeNativeMethod<NativePanZoomController::AdjustScrollForSurfaceShift_t>(
                 mozilla::jni::NativeStub<NativePanZoomController::AdjustScrollForSurfaceShift_t, Impl>
                 ::template Wrap<&Impl::AdjustScrollForSurfaceShift>),
 
         mozilla::jni::MakeNativeMethod<NativePanZoomController::DisposeNative_t>(
                 mozilla::jni::NativeStub<NativePanZoomController::DisposeNative_t, Impl>
                 ::template Wrap<&Impl::DisposeNative>),
 
-        mozilla::jni::MakeNativeMethod<NativePanZoomController::HandleHoverEvent_t>(
-                mozilla::jni::NativeStub<NativePanZoomController::HandleHoverEvent_t, Impl>
-                ::template Wrap<&Impl::HandleHoverEvent>),
-
         mozilla::jni::MakeNativeMethod<NativePanZoomController::HandleMotionEvent_t>(
                 mozilla::jni::NativeStub<NativePanZoomController::HandleMotionEvent_t, Impl>
                 ::template Wrap<&Impl::HandleMotionEvent>),
 
+        mozilla::jni::MakeNativeMethod<NativePanZoomController::HandleMouseEvent_t>(
+                mozilla::jni::NativeStub<NativePanZoomController::HandleMouseEvent_t, Impl>
+                ::template Wrap<&Impl::HandleMouseEvent>),
+
         mozilla::jni::MakeNativeMethod<NativePanZoomController::HandleScrollEvent_t>(
                 mozilla::jni::NativeStub<NativePanZoomController::HandleScrollEvent_t, Impl>
                 ::template Wrap<&Impl::HandleScrollEvent>),
 
         mozilla::jni::MakeNativeMethod<NativePanZoomController::AbortAnimation_t>(
                 mozilla::jni::NativeStub<NativePanZoomController::AbortAnimation_t, Impl>
                 ::template Wrap<&Impl::AbortAnimation>),
 
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -1533,22 +1533,22 @@ constexpr char NativePanZoomController::
 auto NativePanZoomController::Destroy() const -> void
 {
     return mozilla::jni::Method<Destroy_t>::Call(NativePanZoomController::mCtx, nullptr);
 }
 
 constexpr char NativePanZoomController::DisposeNative_t::name[];
 constexpr char NativePanZoomController::DisposeNative_t::signature[];
 
-constexpr char NativePanZoomController::HandleHoverEvent_t::name[];
-constexpr char NativePanZoomController::HandleHoverEvent_t::signature[];
-
 constexpr char NativePanZoomController::HandleMotionEvent_t::name[];
 constexpr char NativePanZoomController::HandleMotionEvent_t::signature[];
 
+constexpr char NativePanZoomController::HandleMouseEvent_t::name[];
+constexpr char NativePanZoomController::HandleMouseEvent_t::signature[];
+
 constexpr char NativePanZoomController::HandleScrollEvent_t::name[];
 constexpr char NativePanZoomController::HandleScrollEvent_t::signature[];
 
 constexpr char NativePanZoomController::AbortAnimation_t::name[];
 constexpr char NativePanZoomController::AbortAnimation_t::signature[];
 
 constexpr char NativePanZoomController::SetIsLongpressEnabled_t::name[];
 constexpr char NativePanZoomController::SetIsLongpressEnabled_t::signature[];
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -3620,34 +3620,16 @@ public:
         static constexpr char name[] = "disposeNative";
         static constexpr char signature[] =
                 "()V";
         static const bool isStatic = false;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
     };
 
-    struct HandleHoverEvent_t {
-        typedef NativePanZoomController Owner;
-        typedef bool ReturnType;
-        typedef bool SetterType;
-        typedef mozilla::jni::Args<
-                int32_t,
-                int64_t,
-                int32_t,
-                float,
-                float> Args;
-        static constexpr char name[] = "handleHoverEvent";
-        static constexpr char signature[] =
-                "(IJIFF)Z";
-        static const bool isStatic = false;
-        static const mozilla::jni::ExceptionMode exceptionMode =
-                mozilla::jni::ExceptionMode::ABORT;
-    };
-
     struct HandleMotionEvent_t {
         typedef NativePanZoomController Owner;
         typedef bool ReturnType;
         typedef bool SetterType;
         typedef mozilla::jni::Args<
                 int32_t,
                 int32_t,
                 int64_t,
@@ -3662,16 +3644,35 @@ public:
         static constexpr char name[] = "handleMotionEvent";
         static constexpr char signature[] =
                 "(IIJI[I[F[F[F[F[F[F)Z";
         static const bool isStatic = false;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
     };
 
+    struct HandleMouseEvent_t {
+        typedef NativePanZoomController Owner;
+        typedef bool ReturnType;
+        typedef bool SetterType;
+        typedef mozilla::jni::Args<
+                int32_t,
+                int64_t,
+                int32_t,
+                float,
+                float,
+                int32_t> Args;
+        static constexpr char name[] = "handleMouseEvent";
+        static constexpr char signature[] =
+                "(IJIFFI)Z";
+        static const bool isStatic = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+    };
+
     struct HandleScrollEvent_t {
         typedef NativePanZoomController Owner;
         typedef bool ReturnType;
         typedef bool SetterType;
         typedef mozilla::jni::Args<
                 int64_t,
                 int32_t,
                 float,
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -378,25 +378,27 @@ public:
  */
 class nsWindow::NPZCSupport final
     : public NativePanZoomController::Natives<NPZCSupport>
 {
     nsWindow* mWindow;
     // Lock for keeping mWindow alive when accessed off of the Gecko thread.
     Mutex mWindowLock;
     NativePanZoomController::GlobalRef mNPZC;
+    int mPreviousButtons;
 
 public:
     typedef NativePanZoomController::Natives<NPZCSupport> Base;
 
     NPZCSupport(nsWindow* aWindow,
                 const NativePanZoomController::LocalRef& aNPZC)
         : mWindow(aWindow)
         , mWindowLock("NPZCSupport")
         , mNPZC(aNPZC)
+        , mPreviousButtons(0)
     {
         if (mWindow->mNPZCSupport) {
             mWindow->mNPZCSupport->DetachFromWindow();
         }
         mWindow->mNPZCSupport = this;
     }
 
     ~NPZCSupport()
@@ -575,54 +577,111 @@ public:
             WidgetWheelEvent wheelEvent = input.ToWidgetWheelEvent(window);
             window->ProcessUntransformedAPZEvent(&wheelEvent, guid,
                                                  blockId, status);
         });
 
         return true;
     }
 
-    bool HandleHoverEvent(int32_t aAction, int64_t aTime, int32_t aMetaState,
-                          float aX, float aY)
+    static MouseInput::ButtonType GetButtonType(int button)
+    {
+        MouseInput::ButtonType result = MouseInput::NONE;
+
+        switch (button) {
+            case widget::sdk::MotionEvent::BUTTON_PRIMARY:
+                result = MouseInput::LEFT_BUTTON;
+                break;
+            case widget::sdk::MotionEvent::BUTTON_SECONDARY:
+                result = MouseInput::RIGHT_BUTTON;
+                break;
+            case widget::sdk::MotionEvent::BUTTON_TERTIARY:
+                result = MouseInput::MIDDLE_BUTTON;
+                break;
+            default:
+                break;
+        }
+
+        return result;
+    }
+
+    static int16_t ConvertButtons(int buttons) {
+        int16_t result = 0;
+
+        if (buttons & widget::sdk::MotionEvent::BUTTON_PRIMARY) {
+            result |= WidgetMouseEventBase::eLeftButtonFlag;
+        }
+        if (buttons & widget::sdk::MotionEvent::BUTTON_SECONDARY) {
+            result |= WidgetMouseEventBase::eRightButtonFlag;
+        }
+        if (buttons & widget::sdk::MotionEvent::BUTTON_TERTIARY) {
+            result |= WidgetMouseEventBase::eMiddleButtonFlag;
+        }
+        if (buttons & widget::sdk::MotionEvent::BUTTON_BACK) {
+            result |= WidgetMouseEventBase::e4thButtonFlag;
+        }
+        if (buttons & widget::sdk::MotionEvent::BUTTON_FORWARD) {
+            result |= WidgetMouseEventBase::e5thButtonFlag;
+        }
+
+        return result;
+    }
+
+    bool HandleMouseEvent(int32_t aAction, int64_t aTime, int32_t aMetaState,
+                          float aX, float aY, int buttons)
     {
         MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
 
         MutexAutoLock lock(mWindowLock);
         if (!mWindow) {
             // We already shut down.
             return false;
         }
 
         RefPtr<APZCTreeManager> controller = mWindow->mAPZC;
         if (!controller) {
             return false;
         }
 
-        MouseInput::MouseType type = MouseInput::MOUSE_NONE;
+        MouseInput::MouseType mouseType = MouseInput::MOUSE_NONE;
+        MouseInput::ButtonType buttonType = MouseInput::NONE;
         switch (aAction) {
+            case AndroidMotionEvent::ACTION_DOWN:
+                mouseType = MouseInput::MOUSE_DOWN;
+                buttonType = GetButtonType(buttons ^ mPreviousButtons);
+                mPreviousButtons = buttons;
+                break;
+            case AndroidMotionEvent::ACTION_UP:
+                mouseType = MouseInput::MOUSE_UP;
+                buttonType = GetButtonType(buttons ^ mPreviousButtons);
+                mPreviousButtons = buttons;
+                break;
+            case AndroidMotionEvent::ACTION_MOVE:
+                mouseType = MouseInput::MOUSE_MOVE;
+                break;
             case AndroidMotionEvent::ACTION_HOVER_MOVE:
-                type = MouseInput::MOUSE_MOVE;
+                mouseType = MouseInput::MOUSE_MOVE;
                 break;
             case AndroidMotionEvent::ACTION_HOVER_ENTER:
-                type = MouseInput::MOUSE_WIDGET_ENTER;
+                mouseType = MouseInput::MOUSE_WIDGET_ENTER;
                 break;
             case AndroidMotionEvent::ACTION_HOVER_EXIT:
-                type = MouseInput::MOUSE_WIDGET_EXIT;
+                mouseType = MouseInput::MOUSE_WIDGET_EXIT;
                 break;
             default:
                 break;
         }
 
-        if (type == MouseInput::MOUSE_NONE) {
+        if (mouseType == MouseInput::MOUSE_NONE) {
             return false;
         }
 
         ScreenPoint origin = ScreenPoint(aX, aY);
 
-        MouseInput input(type, MouseInput::NONE, 0, origin, aTime, TimeStamp(), GetModifiers(aMetaState));
+        MouseInput input(mouseType, buttonType, nsIDOMMouseEvent::MOZ_SOURCE_MOUSE, ConvertButtons(buttons), origin, aTime, TimeStamp(), GetModifiers(aMetaState));
 
         ScrollableLayerGuid guid;
         uint64_t blockId;
         nsEventStatus status = controller->ReceiveInputEvent(input, &guid, &blockId);
 
         if (status == nsEventStatus_eConsumeNoDefault) {
             return true;
         }