diff options
author | khushalsagar <khushalsagar@chromium.org> | 2015-12-08 18:27:53 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-12-09 02:29:28 +0000 |
commit | 0f46911a547ea49a6461da202d0b49d10309be05 (patch) | |
tree | 70143cc2c679e27150ec2a502ed65e133b1d8f66 /blimp | |
parent | 80c0f7b8d97cdad39047eb210c63b08d04bbdd9a (diff) | |
download | chromium_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.gn | 10 | ||||
-rw-r--r-- | blimp/client/DEPS | 5 | ||||
-rw-r--r-- | blimp/client/android/blimp_view.cc | 66 | ||||
-rw-r--r-- | blimp/client/android/blimp_view.h | 30 | ||||
-rw-r--r-- | blimp/client/android/java/src/org/chromium/blimp/BlimpView.java | 56 | ||||
-rw-r--r-- | blimp/client/compositor/blimp_compositor.cc | 30 | ||||
-rw-r--r-- | blimp/client/compositor/blimp_compositor.h | 18 | ||||
-rw-r--r-- | blimp/client/input/blimp_input_handler_wrapper.cc | 97 | ||||
-rw-r--r-- | blimp/client/input/blimp_input_handler_wrapper.h | 67 | ||||
-rw-r--r-- | blimp/client/input/blimp_input_manager.cc | 155 | ||||
-rw-r--r-- | blimp/client/input/blimp_input_manager.h | 106 |
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_ |