Index: content/browser/android/content_view_core_impl.cc |
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc |
index 182c0a6f336ca2071a3303065f41072bb9fa2e4b..efe44b462b7d3b250561f009f30973be249720c7 100644 |
--- a/content/browser/android/content_view_core_impl.cc |
+++ b/content/browser/android/content_view_core_impl.cc |
@@ -33,6 +33,7 @@ |
#include "content/browser/renderer_host/render_widget_host_view_android.h" |
#include "content/browser/ssl/ssl_host_state.h" |
#include "content/browser/web_contents/web_contents_view_android.h" |
+#include "content/common/input/web_input_event_traits.h" |
#include "content/common/input_messages.h" |
#include "content/common/view_messages.h" |
#include "content/public/browser/browser_accessibility_state.h" |
@@ -110,6 +111,94 @@ ScopedJavaLocalRef<jobject> CreateJavaRect( |
static_cast<int>(rect.bottom()))); |
} |
+bool PossiblyTriggeredByTimeout(const WebGestureEvent& event) { |
+ switch (event.type) { |
+ case WebInputEvent::GestureShowPress: |
+ case WebInputEvent::GestureLongPress: |
+ return true; |
+ // On Android, a GestureTap may be sent after a certain timeout window |
+ // if there is no GestureDoubleTap follow-up. |
+ case WebInputEvent::GestureTap: |
+ return true; |
+ // On Android, a GestureTapCancel may be triggered by the loss of window |
+ // focus (e.g., following a GestureLongPress). |
+ case WebInputEvent::GestureTapCancel: |
+ return true; |
+ default: |
+ break; |
+ } |
+ return false; |
+} |
+ |
+GestureEventPacket::GestureSource |
+ToGestureSource(const WebGestureEvent& event) { |
+ return PossiblyTriggeredByTimeout(event) ? GestureEventPacket::TOUCH_TIMEOUT |
+ : GestureEventPacket::SYNTHETIC; |
+} |
+ |
+int ToContentViewGestureHandlerType(WebInputEvent::Type type) { |
+ // These values should match exactly those in ContentViewGestureHandler. |
+ enum ContentViewGestureHandlerType { |
+ GESTURE_SHOW_PRESS = 0, |
+ GESTURE_DOUBLE_TAP = 1, |
+ GESTURE_SINGLE_TAP_UP = 2, |
+ GESTURE_SINGLE_TAP_CONFIRMED = 3, |
+ GESTURE_SINGLE_TAP_UNCONFIRMED = 4, |
+ GESTURE_LONG_PRESS = 5, |
+ GESTURE_SCROLL_START = 6, |
+ GESTURE_SCROLL_BY = 7, |
+ GESTURE_SCROLL_END = 8, |
+ GESTURE_FLING_START = 9, |
+ GESTURE_FLING_CANCEL = 10, |
+ GESTURE_PINCH_BEGIN = 11, |
+ GESTURE_PINCH_BY = 12, |
+ GESTURE_PINCH_END = 13, |
+ GESTURE_TAP_CANCEL = 14, |
+ GESTURE_LONG_TAP = 15, |
+ GESTURE_TAP_DOWN = 16 |
+ }; |
+ switch (type) { |
+ case WebInputEvent::GestureScrollBegin: |
+ return GESTURE_SCROLL_START; |
+ case WebInputEvent::GestureScrollEnd: |
+ return GESTURE_SCROLL_END; |
+ case WebInputEvent::GestureScrollUpdate: |
+ return GESTURE_SCROLL_BY; |
+ case WebInputEvent::GestureFlingStart: |
+ return GESTURE_FLING_START; |
+ case WebInputEvent::GestureFlingCancel: |
+ return GESTURE_FLING_CANCEL; |
+ case WebInputEvent::GestureShowPress: |
+ return GESTURE_SHOW_PRESS; |
+ case WebInputEvent::GestureTap: |
+ return GESTURE_SINGLE_TAP_CONFIRMED; |
+ case WebInputEvent::GestureTapUnconfirmed: |
+ return GESTURE_SINGLE_TAP_UNCONFIRMED; |
+ case WebInputEvent::GestureTapDown: |
+ return GESTURE_TAP_DOWN; |
+ case WebInputEvent::GestureTapCancel: |
+ return GESTURE_TAP_CANCEL; |
+ case WebInputEvent::GestureDoubleTap: |
+ return GESTURE_DOUBLE_TAP; |
+ case WebInputEvent::GestureLongPress: |
+ return GESTURE_LONG_PRESS; |
+ case WebInputEvent::GestureLongTap: |
+ return GESTURE_LONG_TAP; |
+ case WebInputEvent::GesturePinchBegin: |
+ return GESTURE_PINCH_BEGIN; |
+ case WebInputEvent::GesturePinchEnd: |
+ return GESTURE_PINCH_END; |
+ case WebInputEvent::GesturePinchUpdate: |
+ return GESTURE_PINCH_BY; |
+ case WebInputEvent::GestureTwoFingerTap: |
+ case WebInputEvent::GestureScrollUpdateWithoutPropagation: |
+ default: |
+ NOTREACHED() << "Invalid source gesture type: " |
+ << WebInputEventTraits::GetName(type); |
+ return -1; |
+ }; |
+} |
+ |
} // namespace |
// Enables a callback when the underlying WebContents is destroyed, to enable |
@@ -176,7 +265,9 @@ ContentViewCoreImpl::ContentViewCoreImpl(JNIEnv* env, |
view_android_(view_android), |
window_android_(window_android), |
device_orientation_(0), |
- geolocation_needs_pause_(false) { |
+ geolocation_needs_pause_(false), |
+ gesture_event_queue_(this), |
+ handling_touch_event_(false) { |
CHECK(web_contents) << |
"A ContentViewCoreImpl should be created with a valid WebContents."; |
@@ -302,6 +393,23 @@ void ContentViewCoreImpl::RenderViewReady() { |
SendOrientationChangeEventInternal(); |
} |
+void ContentViewCoreImpl::ForwardGestureEvent( |
+ const blink::WebGestureEvent& event) { |
+ JNIEnv* env = AttachCurrentThread(); |
+ ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); |
+ if (j_obj.is_null()) |
+ return; |
+ |
+ if (!Java_ContentViewCore_onForwardingGestureEvent( |
+ env, j_obj.obj(), |
+ ToContentViewGestureHandlerType(event.type), event.x, event.y)) |
+ return; |
+ |
+ RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); |
+ if (rwhv) |
+ rwhv->SendGestureEvent(event); |
+} |
+ |
RenderWidgetHostViewAndroid* |
ContentViewCoreImpl::GetRenderWidgetHostViewAndroid() { |
RenderWidgetHostView* rwhv = NULL; |
@@ -495,21 +603,18 @@ void ContentViewCoreImpl::ShowSelectPopupMenu( |
} |
void ContentViewCoreImpl::ConfirmTouchEvent(InputEventAckState ack_result) { |
- JNIEnv* env = AttachCurrentThread(); |
- ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); |
- if (j_obj.is_null()) |
- return; |
- Java_ContentViewCore_confirmTouchEvent(env, j_obj.obj(), |
- static_cast<jint>(ack_result)); |
+ gesture_event_queue_.OnTouchEventAck(ack_result); |
} |
-void ContentViewCoreImpl::OnFlingStartEventAck(InputEventAckState ack_result) { |
+void ContentViewCoreImpl::OnUnhandledFlingStartEventAck(bool had_consumer, |
+ float vx, |
+ float vy) { |
JNIEnv* env = AttachCurrentThread(); |
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); |
if (j_obj.is_null()) |
return; |
- Java_ContentViewCore_onFlingStartEventAck(env, j_obj.obj(), |
- static_cast<jint>(ack_result)); |
+ Java_ContentViewCore_onUnhandledFlingStartEventAck(env, j_obj.obj(), |
+ had_consumer, vx, vy); |
} |
void ContentViewCoreImpl::OnScrollBeginEventAck() { |
@@ -536,16 +641,6 @@ void ContentViewCoreImpl::OnScrollEndEventAck() { |
Java_ContentViewCore_onScrollEndEventAck(env, j_obj.obj()); |
} |
-void ContentViewCoreImpl::HasTouchEventHandlers(bool need_touch_events) { |
- JNIEnv* env = AttachCurrentThread(); |
- ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); |
- if (j_obj.is_null()) |
- return; |
- Java_ContentViewCore_hasTouchEventHandlers(env, |
- j_obj.obj(), |
- need_touch_events); |
-} |
- |
bool ContentViewCoreImpl::HasFocus() { |
JNIEnv* env = AttachCurrentThread(); |
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); |
@@ -919,21 +1014,32 @@ void ContentViewCoreImpl::SendOrientationChangeEvent(JNIEnv* env, |
} |
} |
-jboolean ContentViewCoreImpl::SendTouchEvent(JNIEnv* env, |
- jobject obj, |
- jlong time_ms, |
- jint type, |
- jobjectArray pts) { |
+void ContentViewCoreImpl::OnTouchEventHandlingBegin(JNIEnv* env, |
+ jobject obj, |
+ jlong time_ms, |
+ jint type, |
+ jobjectArray pts) { |
+ DCHECK(!handling_touch_event_); |
+ handling_touch_event_ = true; |
+ |
+ blink::WebTouchEvent event; |
+ TouchPoint::BuildWebTouchEvent(env, type, time_ms, GetDpiScale(), pts, event); |
+ pending_touch_event_ = event; |
+ |
+ pending_gesture_packet_ = GestureEventPacket::FromTouch(event); |
+} |
+ |
+void ContentViewCoreImpl::OnTouchEventHandlingEnd(JNIEnv* env, jobject obj) { |
+ DCHECK(handling_touch_event_); |
+ handling_touch_event_ = false; |
+ |
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); |
- if (rwhv) { |
- using blink::WebTouchEvent; |
- blink::WebTouchEvent event; |
- TouchPoint::BuildWebTouchEvent(env, type, time_ms, GetDpiScale(), pts, |
- event); |
- rwhv->SendTouchEvent(event); |
- return true; |
- } |
- return false; |
+ if (!rwhv) |
+ return; |
+ |
+ // Note: Order is important here, as the touch may be ack'ed synchronously |
+ gesture_event_queue_.OnGestureEventPacket(pending_gesture_packet_); |
+ rwhv->SendTouchEvent(pending_touch_event_); |
} |
float ContentViewCoreImpl::GetTouchPaddingDip() { |
@@ -1003,9 +1109,18 @@ WebGestureEvent ContentViewCoreImpl::MakeGestureEvent( |
void ContentViewCoreImpl::SendGestureEvent( |
const blink::WebGestureEvent& event) { |
- RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); |
- if (rwhv) |
- rwhv->SendGestureEvent(event); |
+ if (handling_touch_event_) { |
+ pending_gesture_packet_.Push(event); |
+ return; |
+ } |
+ gesture_event_queue_.OnGestureEventPacket( |
+ GestureEventPacket::FromGesture(ToGestureSource(event), event)); |
+} |
+ |
+void ContentViewCoreImpl::SendSyntheticGestureEvent( |
+ const blink::WebGestureEvent& event) { |
+ gesture_event_queue_.OnGestureEventPacket( |
+ GestureEventPacket::FromGesture(GestureEventPacket::SYNTHETIC, event)); |
} |
void ContentViewCoreImpl::ScrollBegin(JNIEnv* env, |
@@ -1065,12 +1180,14 @@ void ContentViewCoreImpl::SingleTap(JNIEnv* env, jobject obj, jlong time_ms, |
WebInputEvent::GestureTap, time_ms, x, y); |
event.data.tap.tapCount = 1; |
- if (!disambiguation_popup_tap) { |
- const float touch_padding_dip = GetTouchPaddingDip(); |
- event.data.tap.width = touch_padding_dip; |
- event.data.tap.height = touch_padding_dip; |
+ if (disambiguation_popup_tap) { |
+ SendSyntheticGestureEvent(event); |
+ return; |
} |
+ const float touch_padding_dip = GetTouchPaddingDip(); |
+ event.data.tap.width = touch_padding_dip; |
+ event.data.tap.height = touch_padding_dip; |
SendGestureEvent(event); |
} |
@@ -1089,9 +1206,9 @@ void ContentViewCoreImpl::SingleTapUnconfirmed(JNIEnv* env, jobject obj, |
SendGestureEvent(event); |
} |
-void ContentViewCoreImpl::ShowPressState(JNIEnv* env, jobject obj, |
- jlong time_ms, |
- jfloat x, jfloat y) { |
+void ContentViewCoreImpl::ShowPress(JNIEnv* env, jobject obj, |
+ jlong time_ms, |
+ jfloat x, jfloat y) { |
WebGestureEvent event = MakeGestureEvent( |
WebInputEvent::GestureShowPress, time_ms, x, y); |
SendGestureEvent(event); |
@@ -1128,12 +1245,14 @@ void ContentViewCoreImpl::LongPress(JNIEnv* env, jobject obj, jlong time_ms, |
WebGestureEvent event = MakeGestureEvent( |
WebInputEvent::GestureLongPress, time_ms, x, y); |
- if (!disambiguation_popup_tap) { |
- const float touch_padding_dip = GetTouchPaddingDip(); |
- event.data.longPress.width = touch_padding_dip; |
- event.data.longPress.height = touch_padding_dip; |
+ if (disambiguation_popup_tap) { |
+ SendSyntheticGestureEvent(event); |
+ return; |
} |
+ const float touch_padding_dip = GetTouchPaddingDip(); |
+ event.data.longPress.width = touch_padding_dip; |
+ event.data.longPress.height = touch_padding_dip; |
SendGestureEvent(event); |
} |
@@ -1143,12 +1262,14 @@ void ContentViewCoreImpl::LongTap(JNIEnv* env, jobject obj, jlong time_ms, |
WebGestureEvent event = MakeGestureEvent( |
WebInputEvent::GestureLongTap, time_ms, x, y); |
- if (!disambiguation_popup_tap) { |
- const float touch_padding_dip = GetTouchPaddingDip(); |
- event.data.longPress.width = touch_padding_dip; |
- event.data.longPress.height = touch_padding_dip; |
+ if (disambiguation_popup_tap) { |
+ SendSyntheticGestureEvent(event); |
+ return; |
} |
+ const float touch_padding_dip = GetTouchPaddingDip(); |
+ event.data.longPress.width = touch_padding_dip; |
+ event.data.longPress.height = touch_padding_dip; |
SendGestureEvent(event); |
} |