| // 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 "content/renderer/mus/compositor_mus_connection.h" |
| |
| #include "base/memory/ptr_util.h" |
| #include "base/single_thread_task_runner.h" |
| #include "content/renderer/input/input_handler_manager.h" |
| #include "content/renderer/mus/render_widget_mus_connection.h" |
| #include "ui/events/blink/blink_event_util.h" |
| #include "ui/events/blink/web_input_event.h" |
| #include "ui/events/blink/web_input_event_traits.h" |
| #include "ui/events/latency_info.h" |
| #include "ui/events/mojo/event.mojom.h" |
| |
| using ui::mojom::EventResult; |
| |
| namespace { |
| |
| void DoNothingWithEventResult(EventResult result) {} |
| |
| gfx::Point GetScreenLocationFromEvent(const ui::LocatedEvent& event) { |
| return event.root_location(); |
| } |
| |
| } // namespace |
| |
| namespace content { |
| |
| CompositorMusConnection::CompositorMusConnection( |
| int routing_id, |
| const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, |
| const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner, |
| mojo::InterfaceRequest<ui::mojom::WindowTreeClient> request, |
| InputHandlerManager* input_handler_manager) |
| : routing_id_(routing_id), |
| root_(nullptr), |
| main_task_runner_(main_task_runner), |
| compositor_task_runner_(compositor_task_runner), |
| input_handler_manager_(input_handler_manager) { |
| DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| compositor_task_runner_->PostTask( |
| FROM_HERE, base::Bind(&CompositorMusConnection:: |
| CreateWindowTreeClientOnCompositorThread, |
| this, base::Passed(std::move(request)))); |
| } |
| |
| void CompositorMusConnection::AttachCompositorFrameSinkOnMainThread( |
| std::unique_ptr<ui::WindowCompositorFrameSinkBinding> |
| compositor_frame_sink_binding) { |
| DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| compositor_task_runner_->PostTask( |
| FROM_HERE, |
| base::Bind( |
| &CompositorMusConnection::AttachCompositorFrameSinkOnCompositorThread, |
| this, base::Passed(std::move(compositor_frame_sink_binding)))); |
| } |
| |
| CompositorMusConnection::~CompositorMusConnection() { |
| base::AutoLock auto_lock(window_tree_client_lock_); |
| // Destruction must happen on the compositor task runner. |
| DCHECK(!window_tree_client_); |
| } |
| |
| void CompositorMusConnection::AttachCompositorFrameSinkOnCompositorThread( |
| std::unique_ptr<ui::WindowCompositorFrameSinkBinding> |
| compositor_frame_sink_binding) { |
| DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| window_compositor_frame_sink_binding_ = |
| std::move(compositor_frame_sink_binding); |
| if (root_) { |
| root_->AttachCompositorFrameSink( |
| std::move(window_compositor_frame_sink_binding_)); |
| } |
| } |
| |
| void CompositorMusConnection::CreateWindowTreeClientOnCompositorThread( |
| mojo::InterfaceRequest<ui::mojom::WindowTreeClient> request) { |
| DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| DCHECK(!window_tree_client_); |
| std::unique_ptr<ui::WindowTreeClient> window_tree_client = |
| base::MakeUnique<ui::WindowTreeClient>(this, nullptr, std::move(request)); |
| base::AutoLock auto_lock(window_tree_client_lock_); |
| window_tree_client_ = std::move(window_tree_client); |
| } |
| |
| void CompositorMusConnection::OnConnectionLostOnMainThread() { |
| DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| RenderWidgetMusConnection* connection = |
| RenderWidgetMusConnection::Get(routing_id_); |
| if (!connection) |
| return; |
| connection->OnConnectionLost(); |
| } |
| |
| void CompositorMusConnection::OnWindowInputEventOnMainThread( |
| blink::WebScopedInputEvent web_event, |
| const base::Callback<void(EventResult)>& ack) { |
| DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| RenderWidgetMusConnection* connection = |
| RenderWidgetMusConnection::Get(routing_id_); |
| if (!connection) { |
| ack.Run(EventResult::UNHANDLED); |
| return; |
| } |
| connection->OnWindowInputEvent(std::move(web_event), ack); |
| } |
| |
| void CompositorMusConnection::OnWindowInputEventAckOnMainThread( |
| const base::Callback<void(EventResult)>& ack, |
| EventResult result) { |
| DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| compositor_task_runner_->PostTask(FROM_HERE, base::Bind(ack, result)); |
| } |
| |
| std::unique_ptr<blink::WebInputEvent> CompositorMusConnection::Convert( |
| const ui::Event& event) { |
| if (event.IsMousePointerEvent()) { |
| const ui::MouseEvent mouse_event(*event.AsPointerEvent()); |
| blink::WebMouseEvent blink_event = ui::MakeWebMouseEvent( |
| mouse_event, base::Bind(&GetScreenLocationFromEvent)); |
| return base::MakeUnique<blink::WebMouseEvent>(blink_event); |
| } else if (event.IsTouchPointerEvent()) { |
| ui::TouchEvent touch_event(*event.AsPointerEvent()); |
| pointer_state_.OnTouch(touch_event); |
| blink::WebTouchEvent blink_event = ui::CreateWebTouchEventFromMotionEvent( |
| pointer_state_, touch_event.may_cause_scrolling()); |
| pointer_state_.CleanupRemovedTouchPoints(touch_event); |
| return base::MakeUnique<blink::WebTouchEvent>(blink_event); |
| } else if (event.IsMouseWheelEvent()) { |
| blink::WebMouseWheelEvent blink_event = ui::MakeWebMouseWheelEvent( |
| *event.AsMouseWheelEvent(), base::Bind(&GetScreenLocationFromEvent)); |
| return base::MakeUnique<blink::WebMouseWheelEvent>(blink_event); |
| } else if (event.IsKeyEvent()) { |
| blink::WebKeyboardEvent blink_event = |
| ui::MakeWebKeyboardEvent(*event.AsKeyEvent()); |
| return base::MakeUnique<blink::WebKeyboardEvent>(blink_event); |
| } |
| return nullptr; |
| } |
| |
| void CompositorMusConnection::DeleteWindowTreeClient() { |
| DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| std::unique_ptr<ui::WindowTreeClient> window_tree_client; |
| { |
| base::AutoLock auto_lock(window_tree_client_lock_); |
| window_tree_client = std::move(window_tree_client_); |
| } |
| main_task_runner_->PostTask( |
| FROM_HERE, |
| base::Bind(&CompositorMusConnection::OnConnectionLostOnMainThread, this)); |
| } |
| |
| void CompositorMusConnection::OnEmbed(ui::Window* root) { |
| DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| root_ = root; |
| root_->set_input_event_handler(this); |
| if (window_compositor_frame_sink_binding_) { |
| root->AttachCompositorFrameSink( |
| std::move(window_compositor_frame_sink_binding_)); |
| } |
| } |
| |
| void CompositorMusConnection::OnEmbedRootDestroyed(ui::Window* window) { |
| DeleteWindowTreeClient(); |
| } |
| |
| void CompositorMusConnection::OnLostConnection(ui::WindowTreeClient* client) { |
| DeleteWindowTreeClient(); |
| } |
| |
| void CompositorMusConnection::OnPointerEventObserved( |
| const ui::PointerEvent& event, |
| ui::Window* target) { |
| // Compositor does not use StartPointerWatcher(). |
| } |
| |
| void CompositorMusConnection::OnWindowInputEvent( |
| ui::Window* window, |
| const ui::Event& event, |
| std::unique_ptr<base::Callback<void(EventResult)>>* ack_callback) { |
| DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| |
| // Take ownership of the callback, indicating that we will handle it. |
| std::unique_ptr<base::Callback<void(EventResult)>> callback = |
| std::move(*ack_callback); |
| blink::WebScopedInputEvent web_event(Convert(event).release()); |
| // TODO(sad): We probably need to plumb LatencyInfo through Mus. |
| ui::LatencyInfo info; |
| input_handler_manager_->HandleInputEvent( |
| routing_id_, std::move(web_event), info, |
| base::Bind( |
| &CompositorMusConnection::DidHandleWindowInputEventAndOverscroll, |
| this, base::Passed(std::move(callback)))); |
| } |
| |
| void CompositorMusConnection::DidHandleWindowInputEventAndOverscroll( |
| std::unique_ptr<base::Callback<void(EventResult)>> ack_callback, |
| InputEventAckState ack_state, |
| blink::WebScopedInputEvent web_event, |
| const ui::LatencyInfo& latency_info, |
| std::unique_ptr<ui::DidOverscrollParams> overscroll_params) { |
| // TODO(jonross): We probably need to ack the event based on the consumed |
| // state. |
| if (ack_state != INPUT_EVENT_ACK_STATE_NOT_CONSUMED) { |
| // We took the ownership of the callback, so we need to send the ack, and |
| // mark the event as not consumed to preserve existing behavior. |
| ack_callback->Run(EventResult::UNHANDLED); |
| return; |
| } |
| base::Callback<void(EventResult)> ack = |
| base::Bind(&::DoNothingWithEventResult); |
| const bool send_ack = |
| ui::WebInputEventTraits::ShouldBlockEventStream(*web_event); |
| if (send_ack) { |
| // Ultimately, this ACK needs to go back to the Mus client lib which is not |
| // thread-safe and lives on the compositor thread. For ACKs that are passed |
| // to the main thread we pass them back to the compositor thread via |
| // OnWindowInputEventAckOnMainThread. |
| ack = |
| base::Bind(&CompositorMusConnection::OnWindowInputEventAckOnMainThread, |
| this, *ack_callback); |
| } else { |
| // We took the ownership of the callback, so we need to send the ack, and |
| // mark the event as not consumed to preserve existing behavior. |
| ack_callback->Run(EventResult::UNHANDLED); |
| } |
| ack_callback.reset(); |
| |
| main_task_runner_->PostTask( |
| FROM_HERE, |
| base::Bind(&CompositorMusConnection::OnWindowInputEventOnMainThread, this, |
| base::Passed(std::move(web_event)), ack)); |
| } |
| |
| } // namespace content |