| Index: content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java
|
| diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java
|
| index 32c8ad50218014ba0a9ced775a0746b8214555a7..528fb4c706698d0addb6f70142b226b58fffa81e 100644
|
| --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java
|
| +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java
|
| @@ -122,10 +122,14 @@ class ContentViewGestureHandler implements LongPressDelegate {
|
| // fling ends.
|
| private boolean mFlingMayBeActive;
|
|
|
| + // Used to remove the touch slop from the initial scroll event in a scroll gesture.
|
| private boolean mSeenFirstScrollEvent;
|
|
|
| private boolean mPinchInProgress = false;
|
|
|
| + // Guard against nested |trySendPendingEventsToNative()| loops.
|
| + private boolean mSendingPendingEventsToNative = false;
|
| +
|
| private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout();
|
|
|
| //On single tap this will store the x, y coordinates of the touch.
|
| @@ -779,14 +783,7 @@ class ContentViewGestureHandler implements LongPressDelegate {
|
| endDoubleTapDragIfNecessary(null);
|
| }
|
|
|
| - if (offerTouchEventToJavaScript(event)) {
|
| - // offerTouchEventToJavaScript returns true to indicate the event was sent
|
| - // to the render process. If it is not subsequently handled, it will
|
| - // be returned via confirmTouchEvent(false) and eventually passed to
|
| - // processTouchEvent asynchronously.
|
| - return true;
|
| - }
|
| - return processTouchEvent(event);
|
| + return queueEvent(event);
|
| } finally {
|
| TraceEvent.end("onTouchEvent");
|
| }
|
| @@ -842,8 +839,18 @@ class ContentViewGestureHandler implements LongPressDelegate {
|
| }
|
| }
|
|
|
| - private boolean offerTouchEventToJavaScript(MotionEvent event) {
|
| - if (mTouchHandlingState == NO_TOUCH_HANDLER) return false;
|
| + /**
|
| + * Queues or coalesces |event| into the pending queue.
|
| + * - If there are no touch handlers, |event| will skip the queue and be processed immediately.
|
| + * - If there are no pending events, |event| will be sent to native or processed immediately,
|
| + * depending on the disposition of the current gesture sequence.
|
| + * @return Whether the event was queued OR processed.
|
| + */
|
| + private boolean queueEvent(MotionEvent event) {
|
| + if (mTouchHandlingState == NO_TOUCH_HANDLER) {
|
| + assert mPendingMotionEvents.isEmpty();
|
| + return processTouchEvent(event);
|
| + }
|
|
|
| if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
|
| // Avoid flooding the renderer process with move events: if the previous pending
|
| @@ -854,7 +861,7 @@ class ContentViewGestureHandler implements LongPressDelegate {
|
| && previousEvent != mPendingMotionEvents.peekFirst()
|
| && previousEvent.getActionMasked() == MotionEvent.ACTION_MOVE
|
| && previousEvent.getPointerCount() == event.getPointerCount()) {
|
| - TraceEvent.instant("offerTouchEventToJavaScript:EventCoalesced",
|
| + TraceEvent.instant("queueEvent:EventCoalesced",
|
| "QueueSize = " + mPendingMotionEvents.size());
|
| MotionEvent.PointerCoords[] coords =
|
| new MotionEvent.PointerCoords[event.getPointerCount()];
|
| @@ -866,25 +873,17 @@ class ContentViewGestureHandler implements LongPressDelegate {
|
| return true;
|
| }
|
| }
|
| - if (mPendingMotionEvents.isEmpty()) {
|
| - // Add the event to the pending queue prior to calling sendPendingEventToNative.
|
| - // When sending an event to native, the callback to confirmTouchEvent can be
|
| - // synchronous or asynchronous and confirmTouchEvent expects the event to be
|
| - // in the queue when it is called.
|
| - MotionEvent clone = MotionEvent.obtain(event);
|
| - mPendingMotionEvents.add(clone);
|
| -
|
| - int forward = sendPendingEventToNative();
|
| - if (forward != EVENT_FORWARDED_TO_NATIVE) mPendingMotionEvents.remove(clone);
|
| - return forward != EVENT_NOT_FORWARDED;
|
| +
|
| + // Copy the event, as the original may get mutated after this method returns.
|
| + MotionEvent clone = MotionEvent.obtain(event);
|
| + mPendingMotionEvents.add(clone);
|
| + if (mPendingMotionEvents.size() == 1) {
|
| + trySendPendingEventsToNative();
|
| } else {
|
| - TraceEvent.instant("offerTouchEventToJavaScript:EventQueued",
|
| + TraceEvent.instant("queueEvent:EventQueued",
|
| "QueueSize = " + mPendingMotionEvents.size());
|
| - // Copy the event, as the original may get mutated after this method returns.
|
| - MotionEvent clone = MotionEvent.obtain(event);
|
| - mPendingMotionEvents.add(clone);
|
| - return true;
|
| }
|
| + return true;
|
| }
|
|
|
| private int sendPendingEventToNative() {
|
| @@ -1029,19 +1028,27 @@ class ContentViewGestureHandler implements LongPressDelegate {
|
| }
|
|
|
| private void trySendPendingEventsToNative() {
|
| - while (!mPendingMotionEvents.isEmpty()) {
|
| - int forward = sendPendingEventToNative();
|
| - if (forward == EVENT_FORWARDED_TO_NATIVE) break;
|
| -
|
| - // Even though we missed sending one event to native, as long as we haven't
|
| - // received INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, we should keep sending
|
| - // events on the queue to native.
|
| - MotionEvent event = mPendingMotionEvents.removeFirst();
|
| - if (mTouchHandlingState != JAVASCRIPT_CONSUMING_GESTURE
|
| - && forward != EVENT_DROPPED) {
|
| - processTouchEvent(event);
|
| + // Avoid nested send loops (possible when acks are synchronous), instead
|
| + // relying on the top-most call to dispatch any queued events.
|
| + if (mSendingPendingEventsToNative) return;
|
| + try {
|
| + mSendingPendingEventsToNative = true;
|
| + while (!mPendingMotionEvents.isEmpty()) {
|
| + int forward = sendPendingEventToNative();
|
| + if (forward == EVENT_FORWARDED_TO_NATIVE) break;
|
| +
|
| + // Even though we missed sending one event to native, as long as we haven't
|
| + // received INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, we should keep sending
|
| + // events on the queue to native.
|
| + MotionEvent event = mPendingMotionEvents.removeFirst();
|
| + if (mTouchHandlingState != JAVASCRIPT_CONSUMING_GESTURE
|
| + && forward != EVENT_DROPPED) {
|
| + processTouchEvent(event);
|
| + }
|
| + recycleEvent(event);
|
| }
|
| - recycleEvent(event);
|
| + } finally {
|
| + mSendingPendingEventsToNative = false;
|
| }
|
| }
|
|
|
|
|