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 108929 f1646acf98b30d1e2b6f9ee6c8a85cf11c3e8196
parent 108928 d5a3c148545c244b31b1a7217c31b49873f0a0f9
child 108930 25a38fc220d67790171cd7d4adaa9c28c06f746d
push id15764
push userwjohnston@mozilla.com
push dateTue, 02 Oct 2012 20:18:49 +0000
treeherdermozilla-inbound@f1646acf98b3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersblassey
bugs784887
milestone18.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 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;