summaryrefslogtreecommitdiffstats
path: root/blimp
diff options
context:
space:
mode:
authorkhushalsagar <khushalsagar@chromium.org>2015-12-08 18:27:53 -0800
committerCommit bot <commit-bot@chromium.org>2015-12-09 02:29:28 +0000
commit0f46911a547ea49a6461da202d0b49d10309be05 (patch)
tree70143cc2c679e27150ec2a502ed65e133b1d8f66 /blimp
parent80c0f7b8d97cdad39047eb210c63b08d04bbdd9a (diff)
downloadchromium_src-0f46911a547ea49a6461da202d0b49d10309be05.zip
chromium_src-0f46911a547ea49a6461da202d0b49d10309be05.tar.gz
chromium_src-0f46911a547ea49a6461da202d0b49d10309be05.tar.bz2
blimp: Add support for basic input handling.
- Add BlimpInputManager to store all input state for the current render widget. - Grab and convert Android motion events to ui::MotionEvent sent to the BlimpInputManager to generate WebGestureEvents using ui::FilteredGestureProvider. - Forward the WebInputEvents to the ui::InputHandlerProxy to be handled by the cc::InputHandler on the compositor thread. - Send the WebInputEvents not handled by the compositor to the engine. BUG=548806 Review URL: https://codereview.chromium.org/1430623004 Cr-Commit-Position: refs/heads/master@{#363928}
Diffstat (limited to 'blimp')
-rw-r--r--blimp/client/BUILD.gn10
-rw-r--r--blimp/client/DEPS5
-rw-r--r--blimp/client/android/blimp_view.cc66
-rw-r--r--blimp/client/android/blimp_view.h30
-rw-r--r--blimp/client/android/java/src/org/chromium/blimp/BlimpView.java56
-rw-r--r--blimp/client/compositor/blimp_compositor.cc30
-rw-r--r--blimp/client/compositor/blimp_compositor.h18
-rw-r--r--blimp/client/input/blimp_input_handler_wrapper.cc97
-rw-r--r--blimp/client/input/blimp_input_handler_wrapper.h67
-rw-r--r--blimp/client/input/blimp_input_manager.cc155
-rw-r--r--blimp/client/input/blimp_input_manager.h106
11 files changed, 637 insertions, 3 deletions
diff --git a/blimp/client/BUILD.gn b/blimp/client/BUILD.gn
index 48f647b..41e5ca0 100644
--- a/blimp/client/BUILD.gn
+++ b/blimp/client/BUILD.gn
@@ -22,12 +22,20 @@ component("blimp_client") {
"compositor/render_widget_message_processor.h",
"compositor/test/dummy_layer_driver.cc",
"compositor/test/dummy_layer_driver.h",
+ "input/blimp_input_handler_wrapper.cc",
+ "input/blimp_input_handler_wrapper.h",
+ "input/blimp_input_manager.cc",
+ "input/blimp_input_manager.h",
"navigation_message_processor.cc",
"navigation_message_processor.h",
]
defines = [ "BLIMP_CLIENT_IMPLEMENTATION=1" ]
+ public_deps = [
+ "//ui/events",
+ ]
+
deps = [
"//base",
"//blimp/common:blimp_common",
@@ -38,6 +46,8 @@ component("blimp_client") {
"//gpu/command_buffer/client:gl_in_process_context",
"//gpu/command_buffer/common:gles2_utils",
"//gpu/skia_bindings",
+ "//ui/events/blink",
+ "//ui/events/gestures/blink",
"//ui/gfx/geometry",
"//ui/gl",
"//url:url",
diff --git a/blimp/client/DEPS b/blimp/client/DEPS
index 1240c91a..19da9c3 100644
--- a/blimp/client/DEPS
+++ b/blimp/client/DEPS
@@ -9,6 +9,11 @@ include_rules = [
"+net/base",
"+skia",
"+third_party/skia",
+ "+third_party/WebKit/public/web/WebInputEvent.h",
+ "+ui/events/android",
+ "+ui/events/blink",
+ "+ui/events/gesture_detection",
+ "+ui/events/gestures/blink",
"+ui/gfx",
"+ui/gl",
"+url",
diff --git a/blimp/client/android/blimp_view.cc b/blimp/client/android/blimp_view.cc
index cec7e3a..79633f7 100644
--- a/blimp/client/android/blimp_view.cc
+++ b/blimp/client/android/blimp_view.cc
@@ -8,6 +8,7 @@
#include "blimp/client/compositor/blimp_compositor_android.h"
#include "jni/BlimpView_jni.h"
+#include "ui/events/android/motion_event_android.h"
#include "ui/gfx/geometry/size.h"
namespace blimp {
@@ -35,7 +36,8 @@ BlimpView::BlimpView(JNIEnv* env,
const gfx::Size& real_size,
const gfx::Size& size,
float dp_to_px)
- : compositor_(BlimpCompositorAndroid::Create(real_size, size, dp_to_px)),
+ : device_scale_factor_(dp_to_px),
+ compositor_(BlimpCompositorAndroid::Create(real_size, size, dp_to_px)),
current_surface_format_(0),
window_(gfx::kNullAcceleratedWidget) {
java_obj_.Reset(env, jobj);
@@ -94,4 +96,66 @@ void BlimpView::ReleaseAcceleratedWidget() {
window_ = gfx::kNullAcceleratedWidget;
}
+jboolean BlimpView::OnTouchEvent(JNIEnv* env,
+ jobject obj,
+ jobject motion_event,
+ jlong time_ms,
+ jint android_action,
+ jint pointer_count,
+ jint history_size,
+ jint action_index,
+ jfloat pos_x_0,
+ jfloat pos_y_0,
+ jfloat pos_x_1,
+ jfloat pos_y_1,
+ jint pointer_id_0,
+ jint pointer_id_1,
+ jfloat touch_major_0,
+ jfloat touch_major_1,
+ jfloat touch_minor_0,
+ jfloat touch_minor_1,
+ jfloat orientation_0,
+ jfloat orientation_1,
+ jfloat tilt_0,
+ jfloat tilt_1,
+ jfloat raw_pos_x,
+ jfloat raw_pos_y,
+ jint android_tool_type_0,
+ jint android_tool_type_1,
+ jint android_button_state,
+ jint android_meta_state) {
+ ui::MotionEventAndroid::Pointer pointer0(pointer_id_0,
+ pos_x_0,
+ pos_y_0,
+ touch_major_0,
+ touch_minor_0,
+ orientation_0,
+ tilt_0,
+ android_tool_type_0);
+ ui::MotionEventAndroid::Pointer pointer1(pointer_id_1,
+ pos_x_1,
+ pos_y_1,
+ touch_major_1,
+ touch_minor_1,
+ orientation_1,
+ tilt_1,
+ android_tool_type_1);
+ ui::MotionEventAndroid event(1.f / device_scale_factor_,
+ env,
+ motion_event,
+ time_ms,
+ android_action,
+ pointer_count,
+ history_size,
+ action_index,
+ android_button_state,
+ android_meta_state,
+ raw_pos_x - pos_x_0,
+ raw_pos_y - pos_y_0,
+ pointer0,
+ pointer1);
+
+ return compositor_->OnTouchEvent(event);
+}
+
} // namespace blimp
diff --git a/blimp/client/android/blimp_view.h b/blimp/client/android/blimp_view.h
index 97dc3ed..8a1609c 100644
--- a/blimp/client/android/blimp_view.h
+++ b/blimp/client/android/blimp_view.h
@@ -48,6 +48,34 @@ class BlimpView {
void OnSurfaceCreated(JNIEnv* env, jobject jobj);
void OnSurfaceDestroyed(JNIEnv* env, jobject jobj);
void SetVisibility(JNIEnv* env, jobject jobj, jboolean visible);
+ jboolean OnTouchEvent(JNIEnv* env,
+ jobject obj,
+ jobject motion_event,
+ jlong time_ms,
+ jint android_action,
+ jint pointer_count,
+ jint history_size,
+ jint action_index,
+ jfloat pos_x_0,
+ jfloat pos_y_0,
+ jfloat pos_x_1,
+ jfloat pos_y_1,
+ jint pointer_id_0,
+ jint pointer_id_1,
+ jfloat touch_major_0,
+ jfloat touch_major_1,
+ jfloat touch_minor_0,
+ jfloat touch_minor_1,
+ jfloat orientation_0,
+ jfloat orientation_1,
+ jfloat tilt_0,
+ jfloat tilt_1,
+ jfloat raw_pos_x,
+ jfloat raw_pos_y,
+ jint android_tool_type_0,
+ jint android_tool_type_1,
+ jint android_button_state,
+ jint android_meta_state);
private:
virtual ~BlimpView();
@@ -57,6 +85,8 @@ class BlimpView {
// Reference to the Java object which owns this class.
base::android::ScopedJavaGlobalRef<jobject> java_obj_;
+ const float device_scale_factor_;
+
scoped_ptr<BlimpCompositorAndroid> compositor_;
// The format of the current surface owned by |compositor_|. See
diff --git a/blimp/client/android/java/src/org/chromium/blimp/BlimpView.java b/blimp/client/android/java/src/org/chromium/blimp/BlimpView.java
index a902680..d5fb577 100644
--- a/blimp/client/android/java/src/org/chromium/blimp/BlimpView.java
+++ b/blimp/client/android/java/src/org/chromium/blimp/BlimpView.java
@@ -8,6 +8,7 @@ import android.content.Context;
import android.graphics.Point;
import android.os.Build;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
@@ -86,6 +87,37 @@ public class BlimpView extends SurfaceView implements SurfaceHolder.Callback2 {
nativeSetVisibility(mNativeBlimpViewPtr, visible);
}
+ // View overrides.
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (mNativeBlimpViewPtr == 0) return false;
+
+ int eventAction = event.getActionMasked();
+
+ if (!isValidTouchEventActionForNative(eventAction)) return false;
+
+ int pointerCount = event.getPointerCount();
+ boolean consumed = nativeOnTouchEvent(mNativeBlimpViewPtr, event,
+ event.getEventTime(), eventAction,
+ pointerCount, event.getHistorySize(), event.getActionIndex(),
+ event.getX(), event.getY(),
+ pointerCount > 1 ? event.getX(1) : 0,
+ pointerCount > 1 ? event.getY(1) : 0,
+ event.getPointerId(0), pointerCount > 1 ? event.getPointerId(1) : -1,
+ event.getTouchMajor(), pointerCount > 1 ? event.getTouchMajor(1) : 0,
+ event.getTouchMinor(), pointerCount > 1 ? event.getTouchMinor(1) : 0,
+ event.getOrientation(), pointerCount > 1 ? event.getOrientation(1) : 0,
+ event.getAxisValue(MotionEvent.AXIS_TILT),
+ pointerCount > 1 ? event.getAxisValue(MotionEvent.AXIS_TILT, 1) : 0,
+ event.getRawX(), event.getRawY(),
+ event.getToolType(0),
+ pointerCount > 1 ? event.getToolType(1) : MotionEvent.TOOL_TYPE_UNKNOWN,
+ event.getButtonState(),
+ event.getMetaState());
+
+ return consumed;
+ }
+
// SurfaceView overrides.
@Override
protected void onFinishInflate() {
@@ -117,6 +149,18 @@ public class BlimpView extends SurfaceView implements SurfaceHolder.Callback2 {
@Override
public void surfaceRedrawNeeded(SurfaceHolder holder) {}
+ private static boolean isValidTouchEventActionForNative(int eventAction) {
+ // Only these actions have any effect on gesture detection. Other
+ // actions have no corresponding WebTouchEvent type and may confuse the
+ // touch pipline, so we ignore them entirely.
+ return eventAction == MotionEvent.ACTION_DOWN
+ || eventAction == MotionEvent.ACTION_UP
+ || eventAction == MotionEvent.ACTION_CANCEL
+ || eventAction == MotionEvent.ACTION_MOVE
+ || eventAction == MotionEvent.ACTION_POINTER_DOWN
+ || eventAction == MotionEvent.ACTION_POINTER_UP;
+ }
+
// Native Methods
private native long nativeInit(int physicalWidth, int physicalHeight, int displayWidth,
int displayHeight, float dpToPixel);
@@ -127,4 +171,16 @@ public class BlimpView extends SurfaceView implements SurfaceHolder.Callback2 {
private native void nativeOnSurfaceCreated(long nativeBlimpView);
private native void nativeOnSurfaceDestroyed(long nativeBlimpView);
private native void nativeSetVisibility(long nativeBlimpView, boolean visible);
+ private native boolean nativeOnTouchEvent(
+ long nativeBlimpView, MotionEvent event,
+ long timeMs, int action, int pointerCount, int historySize, int actionIndex,
+ float x0, float y0, float x1, float y1,
+ int pointerId0, int pointerId1,
+ float touchMajor0, float touchMajor1,
+ float touchMinor0, float touchMinor1,
+ float orientation0, float orientation1,
+ float tilt0, float tilt1,
+ float rawX, float rawY,
+ int androidToolType0, int androidToolType1,
+ int androidButtonState, int androidMetaState);
}
diff --git a/blimp/client/compositor/blimp_compositor.cc b/blimp/client/compositor/blimp_compositor.cc
index 9c783dc..a585996 100644
--- a/blimp/client/compositor/blimp_compositor.cc
+++ b/blimp/client/compositor/blimp_compositor.cc
@@ -71,6 +71,10 @@ BlimpCompositor::~BlimpCompositor() {
// tasks on |compositor_thread_|.
host_.reset();
settings_.reset();
+
+ // We must destroy |host_| before the |input_manager_|.
+ input_manager_.reset();
+
if (compositor_thread_)
compositor_thread_->Stop();
}
@@ -131,6 +135,12 @@ void BlimpCompositor::ReleaseAcceleratedWidget() {
window_ = gfx::kNullAcceleratedWidget;
}
+bool BlimpCompositor::OnTouchEvent(const ui::MotionEvent& motion_event) {
+ if (input_manager_)
+ return input_manager_->OnTouchEvent(motion_event);
+ return false;
+}
+
void BlimpCompositor::WillBeginMainFrame() {}
void BlimpCompositor::DidBeginMainFrame() {}
@@ -189,6 +199,12 @@ void BlimpCompositor::OnRenderWidgetInitialized() {
// Destroy the old LayerTreeHost state.
host_.reset();
+ // Destroy the old input manager state.
+ // It is important to destroy the LayerTreeHost before destroying the input
+ // manager as it has a reference to the cc::InputHandlerClient owned by the
+ // BlimpInputManager.
+ input_manager_.reset();
+
// Reset other state.
output_surface_request_pending_ = false;
@@ -212,6 +228,11 @@ void BlimpCompositor::GenerateLayerTreeSettings(
PopulateCommonLayerTreeSettings(settings);
}
+void BlimpCompositor::SendWebInputEvent(
+ const blink::WebInputEvent& input_event) {
+ render_widget_processor_.SendInputEvent(kDummyTabId, input_event);
+}
+
void BlimpCompositor::CreateLayerTreeHost(
scoped_ptr<cc::proto::CompositorMessage> message) {
if (!settings_) {
@@ -244,6 +265,15 @@ void BlimpCompositor::CreateLayerTreeHost(
cc::Layer::Create(BlimpCompositor::LayerSettings()));
host_->SetRootLayer(root);
g_dummy_layer_driver.Pointer()->SetParentLayer(root);
+
+ // TODO(khushalsagar): Create this after successful initialization of the
+ // remote client compositor when implemented.
+ DCHECK(!input_manager_);
+ input_manager_ =
+ BlimpInputManager::Create(this,
+ base::ThreadTaskRunnerHandle::Get(),
+ GetCompositorTaskRunner(),
+ host_->GetInputHandler());
}
scoped_refptr<base::SingleThreadTaskRunner>
diff --git a/blimp/client/compositor/blimp_compositor.h b/blimp/client/compositor/blimp_compositor.h
index e382a3e..b95d46a 100644
--- a/blimp/client/compositor/blimp_compositor.h
+++ b/blimp/client/compositor/blimp_compositor.h
@@ -12,6 +12,7 @@
#include "base/memory/scoped_ptr.h"
#include "blimp/client/blimp_client_export.h"
#include "blimp/client/compositor/render_widget_message_processor.h"
+#include "blimp/client/input/blimp_input_manager.h"
#include "cc/layers/layer_settings.h"
#include "cc/trees/layer_tree_host_client.h"
#include "cc/trees/layer_tree_settings.h"
@@ -42,8 +43,8 @@ class BlimpMessage;
class BLIMP_CLIENT_EXPORT BlimpCompositor
: public cc::LayerTreeHostClient,
public cc::RemoteProtoChannel,
- public RenderWidgetMessageProcessor::RenderWidgetMessageDelegate {
-
+ public RenderWidgetMessageProcessor::RenderWidgetMessageDelegate,
+ public BlimpInputManagerClient {
public:
~BlimpCompositor() override;
@@ -73,6 +74,9 @@ class BLIMP_CLIENT_EXPORT BlimpCompositor
// compositor.
void ReleaseAcceleratedWidget();
+ // Forwards the touch event to the |input_manager_|.
+ bool OnTouchEvent(const ui::MotionEvent& motion_event);
+
protected:
// |dp_to_px| is the scale factor required to move from dp (device pixels) to
// px. See https://developer.android.com/guide/practices/screens_support.html
@@ -117,6 +121,9 @@ class BLIMP_CLIENT_EXPORT BlimpCompositor
void OnCompositorMessageReceived(
scoped_ptr<cc::proto::CompositorMessage> message) override;
+ // BlimpInputManagerClient implementation.
+ void SendWebInputEvent(const blink::WebInputEvent& input_event) override;
+
// Helper method to build the internal CC compositor instance from |message|.
void CreateLayerTreeHost(scoped_ptr<cc::proto::CompositorMessage> message);
@@ -158,6 +165,13 @@ class BLIMP_CLIENT_EXPORT BlimpCompositor
// multiple tabs.
RenderWidgetMessageProcessor render_widget_processor_;
+ // Handles input events for the current render widget. The lifetime of the
+ // input manager is tied to the lifetime of the |host_| which owns the
+ // cc::InputHandler. The input events are forwarded to this input handler by
+ // the manager to be handled by the client compositor for the current render
+ // widget.
+ scoped_ptr<BlimpInputManager> input_manager_;
+
DISALLOW_COPY_AND_ASSIGN(BlimpCompositor);
};
diff --git a/blimp/client/input/blimp_input_handler_wrapper.cc b/blimp/client/input/blimp_input_handler_wrapper.cc
new file mode 100644
index 0000000..dbd6fe7
--- /dev/null
+++ b/blimp/client/input/blimp_input_handler_wrapper.cc
@@ -0,0 +1,97 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "blimp/client/input/blimp_input_handler_wrapper.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "blimp/client/input/blimp_input_manager.h"
+#include "ui/events/gestures/blink/web_gesture_curve_impl.h"
+
+namespace blimp {
+
+BlimpInputHandlerWrapper::BlimpInputHandlerWrapper(
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ const base::WeakPtr<BlimpInputManager> input_manager_weak_ptr,
+ cc::InputHandler* input_handler)
+ : main_task_runner_(main_task_runner),
+ input_manager_weak_ptr_(input_manager_weak_ptr) {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+ DCHECK(input_handler);
+ input_handler_proxy_.reset(
+ new ui::InputHandlerProxy(input_handler, this));
+}
+
+BlimpInputHandlerWrapper::~BlimpInputHandlerWrapper() {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+
+ // The input handler proxy must have been shutdown by the cc::InputHandler
+ // before the InputHandlerWrapper is destroyed.
+ DCHECK(!input_handler_proxy_);
+}
+
+void BlimpInputHandlerWrapper::HandleWebInputEvent(
+ const blink::WebInputEvent& input_event) {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+
+ // We might not have the input handler proxy anymore.
+ if (!input_handler_proxy_)
+ return;
+
+ ui::InputHandlerProxy::EventDisposition disposition =
+ input_handler_proxy_->HandleInputEvent(input_event);
+
+ bool consumed = disposition == ui::InputHandlerProxy::DID_NOT_HANDLE;
+
+ main_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BlimpInputManager::DidHandleWebInputEvent,
+ input_manager_weak_ptr_, input_event, consumed));
+}
+
+void BlimpInputHandlerWrapper::WillShutdown() {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+
+ input_handler_proxy_.reset();
+}
+
+void BlimpInputHandlerWrapper::TransferActiveWheelFlingAnimation(
+ const blink::WebActiveWheelFlingParameters& params) {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+
+ NOTIMPLEMENTED() <<
+ "Transferring Fling Animations to the engine is not supported";
+}
+
+blink::WebGestureCurve* BlimpInputHandlerWrapper::CreateFlingAnimationCurve(
+ blink::WebGestureDevice device_source,
+ const blink::WebFloatPoint& velocity,
+ const blink::WebSize& cumulative_scroll) {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+
+ return ui::WebGestureCurveImpl::CreateFromDefaultPlatformCurve(
+ gfx::Vector2dF(velocity.x, velocity.y),
+ gfx::Vector2dF(cumulative_scroll.width,
+ cumulative_scroll.height),
+ false /* on_main_thread */).release();
+}
+
+void BlimpInputHandlerWrapper::DidOverscroll(
+ const gfx::Vector2dF& accumulated_overscroll,
+ const gfx::Vector2dF& latest_overscroll_delta,
+ const gfx::Vector2dF& current_fling_velocity,
+ const gfx::PointF& causal_event_viewport_point) {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+}
+
+void BlimpInputHandlerWrapper::DidStopFlinging() {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+}
+
+void BlimpInputHandlerWrapper::DidAnimateForInput() {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+}
+
+} // namespace blimp
diff --git a/blimp/client/input/blimp_input_handler_wrapper.h b/blimp/client/input/blimp_input_handler_wrapper.h
new file mode 100644
index 0000000..7bb55d8
--- /dev/null
+++ b/blimp/client/input/blimp_input_handler_wrapper.h
@@ -0,0 +1,67 @@
+// Copyright 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BLIMP_CLIENT_INPUT_BLIMP_INPUT_HANDLER_WRAPPER_H_
+#define BLIMP_CLIENT_INPUT_BLIMP_INPUT_HANDLER_WRAPPER_H_
+
+#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_checker.h"
+#include "ui/events/blink/input_handler_proxy.h"
+#include "ui/events/blink/input_handler_proxy_client.h"
+
+namespace blimp {
+class BlimpInputManager;
+
+// The BlimpInputHandlerWrapper isolates all input handling processing done on
+// the compositor thread from the BlimpInputManager. It takes web input events
+// from the BlimpInputManager and sends them to the ui::InputHandlerProxy.
+// The class is created and lives on the compositor thread.
+class BlimpInputHandlerWrapper : public ui::InputHandlerProxyClient {
+ public:
+ BlimpInputHandlerWrapper(
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ const base::WeakPtr<BlimpInputManager> input_manager_weak_ptr,
+ cc::InputHandler* input_handler);
+
+ ~BlimpInputHandlerWrapper() override;
+
+ // Called by the BlimpInputManager to process a web input event. This will
+ // call BlimpInputManager::HandleWebInputEvent with the result on the main
+ // thread.
+ void HandleWebInputEvent(const blink::WebInputEvent& input_event);
+
+ private:
+ // InputHandlerProxyClient implementation.
+ void WillShutdown() override;
+ void TransferActiveWheelFlingAnimation(
+ const blink::WebActiveWheelFlingParameters& params) override;
+ blink::WebGestureCurve* CreateFlingAnimationCurve(
+ blink::WebGestureDevice device_source,
+ const blink::WebFloatPoint& velocity,
+ const blink::WebSize& cumulative_scroll) override;
+ void DidOverscroll(const gfx::Vector2dF& accumulated_overscroll,
+ const gfx::Vector2dF& latest_overscroll_delta,
+ const gfx::Vector2dF& current_fling_velocity,
+ const gfx::PointF& causal_event_viewport_point) override;
+ void DidStopFlinging() override;
+ void DidAnimateForInput() override;
+
+ base::ThreadChecker compositor_thread_checker_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+
+ // Used to queue calls to the BlimpInputManager to be run on the main
+ // thread. This ensures that any tasks queued are abandoned after the
+ // BlimpInputManager is destroyed.
+ base::WeakPtr<BlimpInputManager> input_manager_weak_ptr_;
+
+ scoped_ptr<ui::InputHandlerProxy> input_handler_proxy_;
+
+ DISALLOW_COPY_AND_ASSIGN(BlimpInputHandlerWrapper);
+};
+
+} // namespace blimp
+
+#endif // BLIMP_CLIENT_INPUT_BLIMP_INPUT_HANDLER_WRAPPER_H_
diff --git a/blimp/client/input/blimp_input_manager.cc b/blimp/client/input/blimp_input_manager.cc
new file mode 100644
index 0000000..dedfac69
--- /dev/null
+++ b/blimp/client/input/blimp_input_manager.cc
@@ -0,0 +1,155 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "blimp/client/input/blimp_input_manager.h"
+
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "ui/events/blink/blink_event_util.h"
+#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
+
+namespace blimp {
+
+scoped_ptr<BlimpInputManager> BlimpInputManager::Create(
+ BlimpInputManagerClient* client,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
+ const base::WeakPtr<cc::InputHandler>& input_handler) {
+ return make_scoped_ptr(new BlimpInputManager(client,
+ main_task_runner,
+ compositor_task_runner,
+ input_handler));
+}
+
+BlimpInputManager::BlimpInputManager(
+ BlimpInputManagerClient* client,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
+ const base::WeakPtr<cc::InputHandler>& input_handler)
+ : client_(client),
+ gesture_provider_(ui::GetGestureProviderConfig(
+ ui::GestureProviderConfigType::CURRENT_PLATFORM), this),
+ main_task_runner_(main_task_runner),
+ compositor_task_runner_(compositor_task_runner),
+ main_thread_blocked_(false),
+ weak_factory_(this) {
+ DCHECK(IsMainThread());
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &BlimpInputManager::CreateInputHandlerWrapperOnCompositorThread,
+ base::Unretained(this), weak_factory_.GetWeakPtr(),
+ input_handler));
+}
+
+BlimpInputManager::~BlimpInputManager() {
+ DCHECK(IsMainThread());
+
+ base::WaitableEvent shutdown_event(false /* manual_reset */,
+ false /* initially_signaled */);
+ {
+ base::AutoReset<bool> auto_reset_main_thread_blocked(
+ &main_thread_blocked_, true);
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &BlimpInputManager::ShutdownOnCompositorThread,
+ base::Unretained(this), &shutdown_event));
+ shutdown_event.Wait();
+ }
+}
+
+bool BlimpInputManager::OnTouchEvent(const ui::MotionEvent& motion_event) {
+ DCHECK(IsMainThread());
+
+ ui::FilteredGestureProvider::TouchHandlingResult result =
+ gesture_provider_.OnTouchEvent(motion_event);
+ if (!result.succeeded)
+ return false;
+
+ blink::WebTouchEvent touch =
+ ui::CreateWebTouchEventFromMotionEvent(motion_event,
+ result.did_generate_scroll);
+
+ // Touch events are queued in the Gesture Provider until acknowledged to
+ // allow them to be consumed by the touch event handlers in blink which can
+ // prevent-default on the event. Since we currently do not support touch
+ // handlers the event is always acknowledged as not consumed.
+ gesture_provider_.OnTouchEventAck(touch.uniqueTouchEventId, false);
+
+ return true;
+}
+
+void BlimpInputManager::OnGestureEvent(const ui::GestureEventData& gesture) {
+ DCHECK(IsMainThread());
+
+ blink::WebGestureEvent web_gesture =
+ ui::CreateWebGestureEventFromGestureEventData(gesture);
+ // TODO(khushalsagar): Remove this workaround after Android fixes UiAutomator
+ // to stop providing shift meta values to synthetic MotionEvents. This
+ // prevents unintended shift+click interpretation of all accessibility clicks.
+ // See crbug.com/443247.
+ if (web_gesture.type == blink::WebInputEvent::GestureTap &&
+ web_gesture.modifiers == blink::WebInputEvent::ShiftKey) {
+ web_gesture.modifiers = 0;
+ }
+
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &BlimpInputManager::HandleWebInputEventOnCompositorThread,
+ base::Unretained(this), web_gesture));
+}
+
+void BlimpInputManager::CreateInputHandlerWrapperOnCompositorThread(
+ base::WeakPtr<BlimpInputManager> input_manager_weak_ptr,
+ const base::WeakPtr<cc::InputHandler>& input_handler) {
+ DCHECK(IsCompositorThread());
+
+ // The input_handler might have been destroyed at this point.
+ if (!input_handler)
+ return;
+
+ DCHECK(!input_handler_wrapper_);
+ input_handler_wrapper_ = make_scoped_ptr(
+ new BlimpInputHandlerWrapper(main_task_runner_,
+ input_manager_weak_ptr,
+ input_handler.get()));
+}
+
+void BlimpInputManager::HandleWebInputEventOnCompositorThread(
+ const blink::WebInputEvent& input_event) {
+ DCHECK(IsCompositorThread());
+
+ if (input_handler_wrapper_)
+ input_handler_wrapper_->HandleWebInputEvent(input_event);
+}
+
+void BlimpInputManager::ShutdownOnCompositorThread(
+ base::WaitableEvent* shutdown_event) {
+ DCHECK(IsCompositorThread());
+ DCHECK(main_thread_blocked_);
+
+ input_handler_wrapper_.reset();
+ shutdown_event->Signal();
+}
+
+void BlimpInputManager::DidHandleWebInputEvent(
+ const blink::WebInputEvent& input_event, bool consumed) {
+ DCHECK(IsMainThread());
+
+ if (!consumed)
+ client_->SendWebInputEvent(input_event);
+}
+
+bool BlimpInputManager::IsMainThread() const {
+ return main_task_runner_->BelongsToCurrentThread();
+}
+
+bool BlimpInputManager::IsCompositorThread() const {
+ return compositor_task_runner_->BelongsToCurrentThread();
+}
+
+} // namespace blimp
diff --git a/blimp/client/input/blimp_input_manager.h b/blimp/client/input/blimp_input_manager.h
new file mode 100644
index 0000000..7acddd4
--- /dev/null
+++ b/blimp/client/input/blimp_input_manager.h
@@ -0,0 +1,106 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BLIMP_CLIENT_INPUT_BLIMP_INPUT_MANAGER_H_
+#define BLIMP_CLIENT_INPUT_BLIMP_INPUT_MANAGER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "blimp/client/input/blimp_input_handler_wrapper.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/events/gesture_detection/filtered_gesture_provider.h"
+#include "ui/events/gesture_detection/motion_event.h"
+
+namespace blimp {
+
+class BlimpInputManagerClient {
+ public:
+ virtual void SendWebInputEvent(
+ const blink::WebInputEvent& input_event) = 0;
+};
+
+// The BlimpInputManager handles input events for a specific web widget. The
+// class processes ui::events to generate web input events which are forwarded
+// to the compositor to be handled on the compositor thread. If the event can
+// not be handled locally by the compositor, it is given to the
+// BlimpInputManagerClient to be sent to the engine.
+//
+// The BlimpInputManager is created and destroyed on the main thread but can be
+// called from the main or compositor thread. It is safe for the
+// BlimpInputManager to be called on the compositor thread because:
+// 1) The only compositor threaded callers of the BlimpInputManager are the
+// BlimpInputManager itself.
+// 2) BlimpInputManager blocks the main thread in its dtor to ensure that all
+// tasks queued to call it on the compositor thread have been run before it is
+// destroyed on the main thread.
+//
+// It is *important* to destroy the cc::InputHandler on the compositor thread
+// before destroying the BlimpInputManager.
+
+class BlimpInputManager : public ui::GestureProviderClient {
+ public:
+ static scoped_ptr<BlimpInputManager> Create(
+ BlimpInputManagerClient* client,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
+ const base::WeakPtr<cc::InputHandler>& input_handler);
+
+ ~BlimpInputManager() override;
+
+ // Called to process a ui::MotionEvent. Returns true if the event was
+ // successfully processed.
+ bool OnTouchEvent(const ui::MotionEvent& motion_event);
+
+ // Called by the BlimpInputHandlerWrapper after an input event was handled on
+ // the compositor thread.
+ // |consumed| is false if the event was not handled by the compositor and
+ // should be sent to the engine.
+ void DidHandleWebInputEvent(const blink::WebInputEvent& input_event,
+ bool consumed);
+
+ private:
+ BlimpInputManager(
+ BlimpInputManagerClient* client,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
+ const base::WeakPtr<cc::InputHandler>& input_handler);
+
+ // ui::GestureProviderClient implementation.
+ void OnGestureEvent(const ui::GestureEventData& gesture) override;
+
+ // Called on the compositor thread.
+ void CreateInputHandlerWrapperOnCompositorThread(
+ base::WeakPtr<BlimpInputManager> input_manager_weak_ptr,
+ const base::WeakPtr<cc::InputHandler>& input_handler);
+ void HandleWebInputEventOnCompositorThread(
+ const blink::WebInputEvent& input_event);
+ void ShutdownOnCompositorThread(base::WaitableEvent* shutdown_event);
+
+ bool IsMainThread() const;
+ bool IsCompositorThread() const;
+
+ BlimpInputManagerClient* client_;
+
+ ui::FilteredGestureProvider gesture_provider_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
+
+ // Used for debug assertions to ensure that the main thread is blocked during
+ // shutdown. Set in the destructor before the main thread is blocked and
+ // read in ShutdownOnCompositorThread.
+ bool main_thread_blocked_;
+
+ scoped_ptr<BlimpInputHandlerWrapper> input_handler_wrapper_;
+
+ base::WeakPtrFactory<BlimpInputManager> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BlimpInputManager);
+};
+
+} // namespace blimp
+
+#endif // BLIMP_CLIENT_INPUT_BLIMP_INPUT_MANAGER_H_