Bug 784887 - Use Native Gesture detector for MozGesture events. r=blassey
authorWes Johnston <wjohnston@mozilla.com>
Tue, 02 Oct 2012 13:18:21 -0700
changeset 109043 f1646acf98b30d1e2b6f9ee6c8a85cf11c3e8196
parent 109042 d5a3c148545c244b31b1a7217c31b49873f0a0f9
child 109044 25a38fc220d67790171cd7d4adaa9c28c06f746d
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewersblassey
bugs784887
milestone18.0a1
Bug 784887 - Use Native Gesture detector for MozGesture events. r=blassey
mobile/android/base/GeckoEvent.java
mobile/android/base/ui/PanZoomController.java
widget/android/AndroidJavaWrappers.cpp
widget/android/AndroidJavaWrappers.h
widget/android/nsWindow.cpp
widget/android/nsWindow.h
--- a/mobile/android/base/GeckoEvent.java
+++ b/mobile/android/base/GeckoEvent.java
@@ -62,16 +62,17 @@ public class GeckoEvent {
     private static final int UNUSED3_EVENT = 23;
     private static final int ACTIVITY_RESUMING = 24;
     private static final int SCREENSHOT = 25;
     private static final int UNUSED2_EVENT = 26;
     private static final int SCREENORIENTATION_CHANGED = 27;
     private static final int COMPOSITOR_PAUSE = 28;
     private static final int COMPOSITOR_RESUME = 29;
     private static final int PAINT_LISTEN_START_EVENT = 30;
+    private static final int NATIVE_GESTURE_EVENT = 31;
 
     /**
      * These DOM_KEY_LOCATION constants mirror the DOM KeyboardEvent's constants.
      * @see https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent#Key_location_constants
      */
     private static final int DOM_KEY_LOCATION_STANDARD = 0;
     private static final int DOM_KEY_LOCATION_LEFT = 1;
     private static final int DOM_KEY_LOCATION_RIGHT = 2;
@@ -93,16 +94,20 @@ public class GeckoEvent {
     public static final int IME_RANGE_SELECTEDRAWTEXT = 3;
     public static final int IME_RANGE_CONVERTEDTEXT = 4;
     public static final int IME_RANGE_SELECTEDCONVERTEDTEXT = 5;
 
     public static final int IME_RANGE_UNDERLINE = 1;
     public static final int IME_RANGE_FORECOLOR = 2;
     public static final int IME_RANGE_BACKCOLOR = 4;
 
+    public static final int ACTION_MAGNIFY_START = 11;
+    public static final int ACTION_MAGNIFY = 12;
+    public static final int ACTION_MAGNIFY_END = 13;
+
     final public int mType;
     public int mAction;
     public long mTime;
     public Point[] mPoints;
     public int[] mPointIndicies;
     public int mPointerIndex; // index of the point that has changed
     public float[] mOrientations;
     public float[] mPressures;
@@ -255,16 +260,31 @@ public class GeckoEvent {
             case KeyEvent.KEYCODE_BUTTON_15:
             case KeyEvent.KEYCODE_BUTTON_16:
                 return true;
             default:
                 return false;
         }
     }
 
+    public static GeckoEvent createNativeGestureEvent(int action, PointF pt, double size) {
+        GeckoEvent event = new GeckoEvent(NATIVE_GESTURE_EVENT);
+        event.mAction = action;
+        event.mCount = 1;
+        event.mPoints = new Point[1];
+
+        PointF geckoPoint = new PointF(pt.x, pt.y);
+        geckoPoint = GeckoApp.mAppContext.getLayerView().convertViewPointToLayerPoint(geckoPoint);
+        event.mPoints[0] = new Point(Math.round(geckoPoint.x), Math.round(geckoPoint.y));
+
+        event.mX = size;
+        event.mTime = System.currentTimeMillis();
+        return event;
+    }
+
     public static GeckoEvent createMotionEvent(MotionEvent m) {
         GeckoEvent event = new GeckoEvent(MOTION_EVENT);
         event.initMotionEvent(m);
         return event;
     }
 
     private void initMotionEvent(MotionEvent m) {
         mAction = m.getAction();
--- a/mobile/android/base/ui/PanZoomController.java
+++ b/mobile/android/base/ui/PanZoomController.java
@@ -865,16 +865,18 @@ public class PanZoomController
 
         if (!mTarget.getZoomConstraints().getAllowZoom())
             return false;
 
         setState(PanZoomState.PINCHING);
         mLastZoomFocus = new PointF(detector.getFocusX(), detector.getFocusY());
         cancelTouch();
 
+        GeckoAppShell.sendEventToGecko(GeckoEvent.createNativeGestureEvent(GeckoEvent.ACTION_MAGNIFY_START, mLastZoomFocus, getMetrics().zoomFactor));
+
         return true;
     }
 
     @Override
     public boolean onScale(SimpleScaleGestureDetector detector) {
         if (GeckoApp.mAppContext == null || GeckoApp.mAppContext.mDOMFullScreen)
             return false;
 
@@ -933,29 +935,36 @@ public class PanZoomController
             scrollBy(new PointF(mLastZoomFocus.x - detector.getFocusX(),
                     mLastZoomFocus.y - detector.getFocusY()));
             PointF focus = new PointF(detector.getFocusX(), detector.getFocusY());
             scaleWithFocus(newZoomFactor, focus);
         }
 
         mLastZoomFocus.set(detector.getFocusX(), detector.getFocusY());
 
+        GeckoEvent event = GeckoEvent.createNativeGestureEvent(GeckoEvent.ACTION_MAGNIFY, mLastZoomFocus, getMetrics().zoomFactor);
+        GeckoAppShell.sendEventToGecko(event);
+
         return true;
     }
 
     @Override
     public void onScaleEnd(SimpleScaleGestureDetector detector) {
         if (mState == PanZoomState.ANIMATED_ZOOM)
             return;
 
         // switch back to the touching state
         startTouch(detector.getFocusX(), detector.getFocusY(), detector.getEventTime());
 
         // Force a viewport synchronisation
         mTarget.setForceRedraw();
+
+        PointF point = new PointF(detector.getFocusX(), detector.getFocusY());
+        GeckoEvent event = GeckoEvent.createNativeGestureEvent(GeckoEvent.ACTION_MAGNIFY_END, point, getMetrics().zoomFactor);
+        GeckoAppShell.sendEventToGecko(event);
     }
 
     /**
      * Scales the viewport, keeping the given focus point in the same place before and after the
      * scale operation. You must hold the monitor while calling this.
      */
     private void scaleWithFocus(float zoomFactor, PointF focus) {
         ViewportMetrics viewportMetrics = getMutableMetrics();
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -506,16 +506,25 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jo
             mDomKeyLocation = jenv->GetIntField(jobj, jDomKeyLocationField);
             mFlags = jenv->GetIntField(jobj, jFlagsField);
             mKeyCode = jenv->GetIntField(jobj, jKeyCodeField);
             mUnicodeChar = jenv->GetIntField(jobj, jUnicodeCharField);
             mRepeatCount = jenv->GetIntField(jobj, jRepeatCountField);
             ReadCharactersField(jenv);
             break;
 
+        case NATIVE_GESTURE_EVENT:
+            mTime = jenv->GetLongField(jobj, jTimeField);
+            mMetaState = jenv->GetIntField(jobj, jMetaStateField);
+            mCount = jenv->GetIntField(jobj, jCountField);
+            ReadPointArray(mPoints, jenv, jPoints, mCount);
+            mX = jenv->GetDoubleField(jobj, jXField);
+
+            break;
+
         case MOTION_EVENT:
             mTime = jenv->GetLongField(jobj, jTimeField);
             mMetaState = jenv->GetIntField(jobj, jMetaStateField);
             mCount = jenv->GetIntField(jobj, jCountField);
             mPointerIndex = jenv->GetIntField(jobj, jPointerIndexField);
 
             ReadPointArray(mPointRadii, jenv, jPointRadii, mCount);
             ReadFloatArray(mOrientations, jenv, jOrientations, mCount);
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -550,16 +550,19 @@ public:
         ACTION_MOVE = 2,
         ACTION_CANCEL = 3,
         ACTION_OUTSIDE = 4,
         ACTION_POINTER_DOWN = 5,
         ACTION_POINTER_UP = 6,
         ACTION_HOVER_MOVE = 7,
         ACTION_HOVER_ENTER = 9,
         ACTION_HOVER_EXIT = 10,
+        ACTION_MAGNIFY_START = 11,
+        ACTION_MAGNIFY = 12,
+        ACTION_MAGNIFY_END = 13,
         ACTION_POINTER_ID_MASK = 0xff00,
         ACTION_POINTER_ID_SHIFT = 8,
         EDGE_TOP = 0x00000001,
         EDGE_BOTTOM = 0x00000002,
         EDGE_LEFT = 0x00000004,
         EDGE_RIGHT = 0x00000008,
         SAMPLE_X = 0,
         SAMPLE_Y = 1,
@@ -756,16 +759,17 @@ public:
         UNUSED3_EVENT = 23,
         ACTIVITY_RESUMING = 24,
         SCREENSHOT = 25,
         UNUSED2_EVENT = 26,
         SCREENORIENTATION_CHANGED = 27,
         COMPOSITOR_PAUSE = 28,
         COMPOSITOR_RESUME = 29,
         PAINT_LISTEN_START_EVENT = 30,
+        NATIVE_GESTURE_EVENT = 31,
         dummy_java_enum_list_end
     };
 
     enum {
         IME_COMPOSITION_END = 0,
         IME_COMPOSITION_BEGIN = 1,
         IME_SET_TEXT = 2,
         IME_GET_TEXT = 3,
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -225,20 +225,16 @@ nsWindow::Create(nsIWidget *aParent,
         gTopLevelWindows.AppendElement(this);
     }
 
     if (parent) {
         parent->mChildren.AppendElement(this);
         mParent = parent;
     }
 
-    float dpi = GetDPI();
-    mSwipeMaxPinchDelta = SWIPE_MAX_PINCH_DELTA_INCHES * dpi;
-    mSwipeMinDistance = SWIPE_MIN_DISTANCE_INCHES * dpi;
-
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::Destroy(void)
 {
     nsBaseWidget::mOnDestroyCalled = true;
 
@@ -840,27 +836,37 @@ nsWindow::OnGlobalAndroidEvent(AndroidGe
                 ALOG("MOTION_EVENT %f,%f -> %p (visible: %d children: %d)", pt.x, pt.y, (void*)target,
                      target ? target->mIsVisible : 0,
                      target ? target->mChildren.Length() : 0);
 
                 DumpWindows();
 #endif
                 if (target) {
                     bool preventDefaultActions = target->OnMultitouchEvent(ae);
-                    if (!preventDefaultActions && ae->Count() == 2) {
-                        target->OnGestureEvent(ae);
-                    }
-
                     if (!preventDefaultActions && ae->Count() < 2)
                         target->OnMouseEvent(ae);
                 }
             }
             break;
         }
 
+        case AndroidGeckoEvent::NATIVE_GESTURE_EVENT: {
+            nsIntPoint pt(0,0);
+            nsTArray<nsIntPoint> points = ae->Points();
+            if (points.Length() > 0) {
+                pt = points[0];
+            }
+            pt.x = clamped(pt.x, 0, NS_MAX(gAndroidBounds.width - 1, 0));
+            pt.y = clamped(pt.y, 0, NS_MAX(gAndroidBounds.height - 1, 0));
+            nsWindow *target = win->FindWindowForPoint(pt);
+
+            target->OnNativeGestureEvent(ae);
+            break;
+        }
+
         case AndroidGeckoEvent::KEY_EVENT:
             win->UserActivity();
             if (win->mFocus)
                 win->mFocus->OnKeyEvent(ae);
             break;
 
         case AndroidGeckoEvent::DRAW:
             layers::renderTraceEventStart("Global draw start", "414141");
@@ -1333,24 +1339,16 @@ send_again:
         return;
 
     if (msg == NS_MOUSE_BUTTON_DOWN) {
         msg = NS_MOUSE_MOVE;
         goto send_again;
     }
 }
 
-static double
-getDistance(const nsIntPoint &p1, const nsIntPoint &p2)
-{
-    double deltaX = p2.x - p1.x;
-    double deltaY = p2.y - p1.y;
-    return sqrt(deltaX*deltaX + deltaY*deltaY);
-}
-
 bool nsWindow::OnMultitouchEvent(AndroidGeckoEvent *ae)
 {
     nsRefPtr<nsWindow> kungFuDeathGrip(this);
 
     // This is set to true once we have called SetPreventPanning() exactly
     // once for a given sequence of touch events. It is reset on the start
     // of the next sequence.
     static bool sDefaultPreventedNotified = false;
@@ -1445,90 +1443,44 @@ nsWindow::DispatchMultitouchEvent(nsTouc
     }
 
     nsEventStatus status;
     DispatchEvent(&event, status);
     return (status == nsEventStatus_eConsumeNoDefault);
 }
 
 void
-nsWindow::OnGestureEvent(AndroidGeckoEvent *ae)
+nsWindow::OnNativeGestureEvent(AndroidGeckoEvent *ae)
 {
-    uint32_t msg = 0;
-
-    nsIntPoint midPoint;
-    midPoint.x = ((ae->Points()[0].x + ae->Points()[1].x) / 2);
-    midPoint.y = ((ae->Points()[0].y + ae->Points()[1].y) / 2);
-    nsIntPoint refPoint = midPoint - WidgetToScreenOffset();
-
-    double pinchDist = getDistance(ae->Points()[0], ae->Points()[1]);
-    double pinchDelta = 0;
-
-    switch (ae->Action() & AndroidMotionEvent::ACTION_MASK) {
-        case AndroidMotionEvent::ACTION_POINTER_DOWN:
-            msg = NS_SIMPLE_GESTURE_MAGNIFY_START;
-            mStartPoint = new nsIntPoint(midPoint);
-            mStartDist = mLastDist = pinchDist;
-            mGestureFinished = false;
-            break;
-        case AndroidMotionEvent::ACTION_MOVE:
-            msg = NS_SIMPLE_GESTURE_MAGNIFY_UPDATE;
-            pinchDelta = pinchDist - mLastDist;
-            mLastDist = pinchDist;
-            break;
-        case AndroidMotionEvent::ACTION_POINTER_UP:
-            msg = NS_SIMPLE_GESTURE_MAGNIFY;
-            pinchDelta = pinchDist - mStartDist;
-            mStartPoint = nullptr;
-            break;
-        default:
-            return;
-    }
+  nsIntPoint pt(ae->Points()[0].x,
+                ae->Points()[0].y);
+  double delta = ae->X();
+  int msg = 0;
 
-    if (!mGestureFinished) {
-        nsRefPtr<nsWindow> kungFuDeathGrip(this);
-        DispatchGestureEvent(msg, 0, pinchDelta, refPoint, ae->Time());
-        if (Destroyed())
-            return;
-
-        // If the cumulative pinch delta goes past the threshold, treat this
-        // as a pinch only, and not a swipe.
-        if (fabs(pinchDist - mStartDist) > mSwipeMaxPinchDelta)
-            mStartPoint = nullptr;
-
-        // If we have traveled more than SWIPE_MIN_DISTANCE from the start
-        // point, stop the pinch gesture and fire a swipe event.
-        if (mStartPoint) {
-            double swipeDistance = getDistance(midPoint, *mStartPoint);
-            if (swipeDistance > mSwipeMinDistance) {
-                uint32_t direction = 0;
-                nsIntPoint motion = midPoint - *mStartPoint;
+  switch (ae->Action() & AndroidMotionEvent::ACTION_MASK) {
+      case AndroidMotionEvent::ACTION_MAGNIFY_START:
+          msg = NS_SIMPLE_GESTURE_MAGNIFY_START;
+          mStartDist = delta;
+          mLastDist = delta;
+          break;
+      case AndroidMotionEvent::ACTION_MAGNIFY:
+          msg = NS_SIMPLE_GESTURE_MAGNIFY_UPDATE;
+          delta -= mLastDist;
+          mLastDist += delta;
+          break;
+      case AndroidMotionEvent::ACTION_MAGNIFY_END:
+          msg = NS_SIMPLE_GESTURE_MAGNIFY;
+          delta -= mStartDist;
+          break;
+      default:
+          return;
+  }
 
-                if (motion.x < -swipeDistance/2)
-                    direction |= nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
-                if (motion.x > swipeDistance/2)
-                    direction |= nsIDOMSimpleGestureEvent::DIRECTION_RIGHT;
-                if (motion.y < -swipeDistance/2)
-                    direction |= nsIDOMSimpleGestureEvent::DIRECTION_UP;
-                if (motion.y > swipeDistance/2)
-                    direction |= nsIDOMSimpleGestureEvent::DIRECTION_DOWN;
-
-                // Finish the pinch gesture, then fire the swipe event:
-                msg = NS_SIMPLE_GESTURE_MAGNIFY;
-                DispatchGestureEvent(msg, 0, pinchDist - mStartDist, refPoint, ae->Time());
-                if (Destroyed())
-                    return;
-                msg = NS_SIMPLE_GESTURE_SWIPE;
-                DispatchGestureEvent(msg, direction, 0, refPoint, ae->Time());
-
-                // Don't generate any more gesture events for this touch.
-                mGestureFinished = true;
-            }
-        }
-    }
+  nsRefPtr<nsWindow> kungFuDeathGrip(this);
+  DispatchGestureEvent(msg, 0, delta, pt, ae->Time());
 }
 
 void
 nsWindow::DispatchGestureEvent(uint32_t msg, uint32_t direction, double delta,
                                const nsIntPoint &refPoint, uint64_t time)
 {
     nsSimpleGestureEvent event(true, msg, this, direction, delta);
 
--- a/widget/android/nsWindow.h
+++ b/widget/android/nsWindow.h
@@ -45,17 +45,17 @@ public:
     static gfxIntSize GetAndroidScreenBounds();
     static nsWindow* TopWindow();
 
     nsWindow* FindWindowForPoint(const nsIntPoint& pt);
 
     void OnAndroidEvent(mozilla::AndroidGeckoEvent *ae);
     void OnDraw(mozilla::AndroidGeckoEvent *ae);
     bool OnMultitouchEvent(mozilla::AndroidGeckoEvent *ae);
-    void OnGestureEvent(mozilla::AndroidGeckoEvent *ae);
+    void OnNativeGestureEvent(mozilla::AndroidGeckoEvent *ae);
     void OnMouseEvent(mozilla::AndroidGeckoEvent *ae);
     void OnKeyEvent(mozilla::AndroidGeckoEvent *ae);
     void OnIMEEvent(mozilla::AndroidGeckoEvent *ae);
 
     void OnSizeChanged(const gfxIntSize& aSize);
 
     void InitEvent(nsGUIEvent& event, nsIntPoint* aPoint = 0);
 
@@ -172,24 +172,18 @@ protected:
     // event (like a keypress or mouse click).
     void UserActivity();
 
     bool mIsVisible;
     nsTArray<nsWindow*> mChildren;
     nsWindow* mParent;
     nsWindow* mFocus;
 
-    bool mGestureFinished;
     double mStartDist;
     double mLastDist;
-    nsAutoPtr<nsIntPoint> mStartPoint;
-
-    // Multitouch swipe thresholds in screen pixels
-    double mSwipeMaxPinchDelta;
-    double mSwipeMinDistance;
 
     nsCOMPtr<nsIIdleServiceInternal> mIdleService;
 
     bool mIMEComposing;
     nsString mIMEComposingText;
     nsString mIMELastDispatchedComposingText;
     nsAutoTArray<nsTextRange, 4> mIMERanges;