summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjonross <jonross@chromium.org>2016-03-08 06:03:26 -0800
committerCommit bot <commit-bot@chromium.org>2016-03-08 14:04:36 +0000
commitc3385cc179280dd4b09733b2954be7e9ae3b5112 (patch)
treefcb8a119477033e1e18f3b8ca5b4bd0b0445b7ea
parent1d3dd7dbbeea929087e089ae1e8acdaa4fae80aa (diff)
downloadchromium_src-c3385cc179280dd4b09733b2954be7e9ae3b5112.zip
chromium_src-c3385cc179280dd4b09733b2954be7e9ae3b5112.tar.gz
chromium_src-c3385cc179280dd4b09733b2954be7e9ae3b5112.tar.bz2
Update WindowTree::OnWindowInputEventAck to include handled
To support post-target accelerators we plan to have the client application report whether an input event was handled or not, when ack-ing the event. This change updates WindowTree::OnWindowInputEventAck to include a boolean parameter |handled|. PlatformWindowMus will always mark events as handled. CompositorMusConnection will base the handled state on the ack state of the renderer. TEST=WindowTreeClientImplTest, WindowTreeApptest, WindowTreeTest, CompositorMusConnectionTest BUG=560478 Review URL: https://codereview.chromium.org/1749323002 Cr-Commit-Position: refs/heads/master@{#379821}
-rw-r--r--components/mus/public/cpp/input_event_handler.h13
-rw-r--r--components/mus/public/cpp/lib/window_tree_client_impl.cc14
-rw-r--r--components/mus/public/cpp/tests/test_window_tree.cc2
-rw-r--r--components/mus/public/cpp/tests/test_window_tree.h2
-rw-r--r--components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc21
-rw-r--r--components/mus/public/interfaces/window_tree.mojom7
-rw-r--r--components/mus/ws/window_tree.cc2
-rw-r--r--components/mus/ws/window_tree.h2
-rw-r--r--components/mus/ws/window_tree_apptest.cc2
-rw-r--r--components/mus/ws/window_tree_unittest.cc2
-rw-r--r--content/renderer/input/input_handler_manager.h9
-rw-r--r--content/renderer/input/render_widget_input_handler.h8
-rw-r--r--content/renderer/mus/compositor_mus_connection.cc21
-rw-r--r--content/renderer/mus/compositor_mus_connection.h13
-rw-r--r--content/renderer/mus/compositor_mus_connection_unittest.cc466
-rw-r--r--content/renderer/mus/render_widget_mus_connection.cc8
-rw-r--r--content/renderer/mus/render_widget_mus_connection.h5
-rw-r--r--content/test/BUILD.gn3
-rw-r--r--ui/views/mus/platform_window_mus.cc4
-rw-r--r--ui/views/mus/platform_window_mus.h7
20 files changed, 555 insertions, 56 deletions
diff --git a/components/mus/public/cpp/input_event_handler.h b/components/mus/public/cpp/input_event_handler.h
index ebd1597..597653b 100644
--- a/components/mus/public/cpp/input_event_handler.h
+++ b/components/mus/public/cpp/input_event_handler.h
@@ -16,11 +16,14 @@ class Window;
class InputEventHandler {
public:
// The event handler can asynchronously ack the event by taking ownership of
- // the |ack_callback|. If the handler does not take ownership of the callback,
- // then WindowTreeClientImpl will ack the event.
- virtual void OnWindowInputEvent(Window* target,
- mojom::EventPtr event,
- scoped_ptr<base::Closure>* ack_callback) = 0;
+ // the |ack_callback|. The callback takes a bool representing whether the
+ // handler has consumed the event. If the handler does not take ownership of
+ // the callback, then WindowTreeClientImpl will ack the event as not consumed.
+ virtual void OnWindowInputEvent(
+ Window* target,
+ mojom::EventPtr event,
+ scoped_ptr<base::Callback<void(bool)>>* ack_callback) = 0;
+
protected:
virtual ~InputEventHandler() {}
};
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.cc b/components/mus/public/cpp/lib/window_tree_client_impl.cc
index cdcd7b6..7c0a477 100644
--- a/components/mus/public/cpp/lib/window_tree_client_impl.cc
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.cc
@@ -820,17 +820,21 @@ void WindowTreeClientImpl::OnWindowInputEvent(uint32_t event_id,
mojom::EventPtr event) {
Window* window = GetWindowById(window_id);
if (!window || !window->input_event_handler_) {
- tree_->OnWindowInputEventAck(event_id);
+ tree_->OnWindowInputEventAck(event_id, false);
return;
}
- scoped_ptr<base::Closure> ack_callback(
- new base::Closure(base::Bind(&mojom::WindowTree::OnWindowInputEventAck,
- base::Unretained(tree_), event_id)));
+ scoped_ptr<base::Callback<void(bool)>> ack_callback(
+ new base::Callback<void(bool)>(
+ base::Bind(&mojom::WindowTree::OnWindowInputEventAck,
+ base::Unretained(tree_), event_id)));
window->input_event_handler_->OnWindowInputEvent(window, std::move(event),
&ack_callback);
+
+ // The handler did not take ownership of the callback, so we send the ack,
+ // marking the event as not consumed.
if (ack_callback)
- ack_callback->Run();
+ ack_callback->Run(false);
}
void WindowTreeClientImpl::OnWindowFocused(Id focused_window_id) {
diff --git a/components/mus/public/cpp/tests/test_window_tree.cc b/components/mus/public/cpp/tests/test_window_tree.cc
index 398a661..7301bd9 100644
--- a/components/mus/public/cpp/tests/test_window_tree.cc
+++ b/components/mus/public/cpp/tests/test_window_tree.cc
@@ -132,7 +132,7 @@ void TestWindowTree::SetImeVisibility(uint32_t window_id,
bool visible,
mojo::TextInputStatePtr state) {}
-void TestWindowTree::OnWindowInputEventAck(uint32_t event_id) {
+void TestWindowTree::OnWindowInputEventAck(uint32_t event_id, bool handled) {
EXPECT_FALSE(acked_events_.count(event_id));
acked_events_.insert(event_id);
}
diff --git a/components/mus/public/cpp/tests/test_window_tree.h b/components/mus/public/cpp/tests/test_window_tree.h
index d392341..daaebb30 100644
--- a/components/mus/public/cpp/tests/test_window_tree.h
+++ b/components/mus/public/cpp/tests/test_window_tree.h
@@ -87,7 +87,7 @@ class TestWindowTree : public mojom::WindowTree {
void SetImeVisibility(uint32_t window_id,
bool visible,
mojo::TextInputStatePtr state) override;
- void OnWindowInputEventAck(uint32_t event_id) override;
+ void OnWindowInputEventAck(uint32_t event_id, bool handled) override;
void GetWindowManagerClient(
mojo::AssociatedInterfaceRequest<mojom::WindowManagerClient> internal)
override;
diff --git a/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc b/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc
index 69c498b..b822257 100644
--- a/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc
+++ b/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc
@@ -27,6 +27,12 @@
#include "ui/events/event_utils.h"
#include "ui/gfx/geometry/rect.h"
+namespace {
+
+void DoNothingBool(bool result) {}
+
+} // namespace
+
namespace mus {
mojo::Array<uint8_t> Int32ToPropertyTransportValue(int32_t value) {
@@ -122,21 +128,22 @@ class TestInputEventHandler : public InputEventHandler {
void AckEvent() {
DCHECK(should_manually_ack_);
DCHECK(!ack_callback_.is_null());
- ack_callback_.Run();
- ack_callback_ = base::Closure();
+ ack_callback_.Run(true);
+ ack_callback_ = base::Bind(&::DoNothingBool);
}
void Reset() {
received_event_ = false;
- ack_callback_ = base::Closure();
+ ack_callback_ = base::Bind(&::DoNothingBool);
}
bool received_event() const { return received_event_; }
private:
// InputEventHandler:
- void OnWindowInputEvent(Window* target,
- mojom::EventPtr event,
- scoped_ptr<base::Closure>* ack_callback) override {
+ void OnWindowInputEvent(
+ Window* target,
+ mojom::EventPtr event,
+ scoped_ptr<base::Callback<void(bool)>>* ack_callback) override {
EXPECT_FALSE(received_event_)
<< "Observer was not reset after receiving event.";
received_event_ = true;
@@ -148,7 +155,7 @@ class TestInputEventHandler : public InputEventHandler {
bool received_event_;
bool should_manually_ack_;
- base::Closure ack_callback_;
+ base::Callback<void(bool)> ack_callback_;
DISALLOW_COPY_AND_ASSIGN(TestInputEventHandler);
};
diff --git a/components/mus/public/interfaces/window_tree.mojom b/components/mus/public/interfaces/window_tree.mojom
index 5114297..09d2972 100644
--- a/components/mus/public/interfaces/window_tree.mojom
+++ b/components/mus/public/interfaces/window_tree.mojom
@@ -246,7 +246,7 @@ interface WindowTree {
SetImeVisibility(uint32 window_id, bool visible, mojo.TextInputState? state);
// See documentation for WindowTreeClient::OnWindowInputEvent().
- OnWindowInputEventAck(uint32 event_id);
+ OnWindowInputEventAck(uint32 event_id, bool handled);
// See description of WindowManager for details.
GetWindowManagerClient(associated WindowManagerClient& internal);
@@ -350,8 +350,9 @@ interface WindowTreeClient {
// Invoked when an event is targeted at the specified window. The client must
// call WindowTree::OnWindowInputEventAck() with the same |event_id| to notify
- // that the event has been processed. The client will not receive farther
- // events until the event is ack'ed.
+ // that the event has been processed, and with a boolean |handled| to notify
+ // if the event was consumed. The client will not receive farther events until
+ // the event is ack'ed.
OnWindowInputEvent(uint32 event_id, uint32 window, Event event);
OnWindowFocused(uint32 focused_window_id);
diff --git a/components/mus/ws/window_tree.cc b/components/mus/ws/window_tree.cc
index 7782e8b..0356a8e 100644
--- a/components/mus/ws/window_tree.cc
+++ b/components/mus/ws/window_tree.cc
@@ -1145,7 +1145,7 @@ void WindowTree::SetImeVisibility(Id transport_window_id,
}
}
-void WindowTree::OnWindowInputEventAck(uint32_t event_id) {
+void WindowTree::OnWindowInputEventAck(uint32_t event_id, bool handled) {
if (event_ack_id_ == 0 || event_id != event_ack_id_) {
// TODO(sad): Something bad happened. Kill the client?
NOTIMPLEMENTED() << "Wrong event acked.";
diff --git a/components/mus/ws/window_tree.h b/components/mus/ws/window_tree.h
index 378186d..0c103e7 100644
--- a/components/mus/ws/window_tree.h
+++ b/components/mus/ws/window_tree.h
@@ -344,7 +344,7 @@ class WindowTree : public mojom::WindowTree,
void SetImeVisibility(Id transport_window_id,
bool visible,
mojo::TextInputStatePtr state) override;
- void OnWindowInputEventAck(uint32_t event_id) override;
+ void OnWindowInputEventAck(uint32_t event_id, bool handled) override;
void SetClientArea(
Id transport_window_id,
mojo::InsetsPtr insets,
diff --git a/components/mus/ws/window_tree_apptest.cc b/components/mus/ws/window_tree_apptest.cc
index 8970435..b143ab0 100644
--- a/components/mus/ws/window_tree_apptest.cc
+++ b/components/mus/ws/window_tree_apptest.cc
@@ -355,7 +355,7 @@ class TestWindowTreeClientImpl : public mojom::WindowTreeClient,
// Ack input events to clear the state on the server. These can be received
// during test startup. X11Window::DispatchEvent sends a synthetic move
// event to notify of entry.
- tree()->OnWindowInputEventAck(event_id);
+ tree()->OnWindowInputEventAck(event_id, true);
// Don't log input events as none of the tests care about them and they
// may come in at random points.
}
diff --git a/components/mus/ws/window_tree_unittest.cc b/components/mus/ws/window_tree_unittest.cc
index 17f59eb..99d88fe 100644
--- a/components/mus/ws/window_tree_unittest.cc
+++ b/components/mus/ws/window_tree_unittest.cc
@@ -198,7 +198,7 @@ class WindowTreeTest : public testing::Test {
void AckPreviousEvent() {
DisplayTestApi test_api(display_);
while (test_api.tree_awaiting_input_ack())
- test_api.tree_awaiting_input_ack()->OnWindowInputEventAck(0);
+ test_api.tree_awaiting_input_ack()->OnWindowInputEventAck(0, true);
}
void DispatchEventAndAckImmediately(const ui::Event& event) {
diff --git a/content/renderer/input/input_handler_manager.h b/content/renderer/input/input_handler_manager.h
index c8bfb75..a77a67e 100644
--- a/content/renderer/input/input_handler_manager.h
+++ b/content/renderer/input/input_handler_manager.h
@@ -47,7 +47,7 @@ class InputHandlerManager {
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
InputHandlerManagerClient* client,
scheduler::RendererScheduler* renderer_scheduler);
- ~InputHandlerManager();
+ virtual ~InputHandlerManager();
// Callable from the main thread only.
void AddInputHandler(int routing_id,
@@ -68,9 +68,10 @@ class InputHandlerManager {
void RemoveInputHandler(int routing_id);
// Called from the compositor's thread.
- InputEventAckState HandleInputEvent(int routing_id,
- const blink::WebInputEvent* input_event,
- ui::LatencyInfo* latency_info);
+ virtual InputEventAckState HandleInputEvent(
+ int routing_id,
+ const blink::WebInputEvent* input_event,
+ ui::LatencyInfo* latency_info);
// Called from the compositor's thread.
void DidOverscroll(int routing_id, const DidOverscrollParams& params);
diff --git a/content/renderer/input/render_widget_input_handler.h b/content/renderer/input/render_widget_input_handler.h
index 3be968c..a82968b 100644
--- a/content/renderer/input/render_widget_input_handler.h
+++ b/content/renderer/input/render_widget_input_handler.h
@@ -34,12 +34,12 @@ class CONTENT_EXPORT RenderWidgetInputHandler {
public:
RenderWidgetInputHandler(RenderWidgetInputHandlerDelegate* delegate,
RenderWidget* widget);
- ~RenderWidgetInputHandler();
+ virtual ~RenderWidgetInputHandler();
// Handle input events from the input event provider.
- void HandleInputEvent(const blink::WebInputEvent& input_event,
- const ui::LatencyInfo& latency_info,
- InputEventDispatchType dispatch_type);
+ virtual void HandleInputEvent(const blink::WebInputEvent& input_event,
+ const ui::LatencyInfo& latency_info,
+ InputEventDispatchType dispatch_type);
// Handle overscroll from Blink.
void DidOverscrollFromBlink(
diff --git a/content/renderer/mus/compositor_mus_connection.cc b/content/renderer/mus/compositor_mus_connection.cc
index 6973de6..f469f56 100644
--- a/content/renderer/mus/compositor_mus_connection.cc
+++ b/content/renderer/mus/compositor_mus_connection.cc
@@ -11,6 +11,12 @@
#include "mojo/converters/blink/blink_input_events_type_converters.h"
#include "ui/events/latency_info.h"
+namespace {
+
+void DoNothingBool(bool result) {}
+
+} // namespace
+
namespace content {
CompositorMusConnection::CompositorMusConnection(
@@ -71,21 +77,22 @@ void CompositorMusConnection::OnConnectionLostOnMainThread() {
void CompositorMusConnection::OnWindowInputEventOnMainThread(
scoped_ptr<blink::WebInputEvent> web_event,
- const base::Closure& ack) {
+ const base::Callback<void(bool)>& ack) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
RenderWidgetMusConnection* connection =
RenderWidgetMusConnection::Get(routing_id_);
if (!connection) {
- ack.Run();
+ ack.Run(false);
return;
}
connection->OnWindowInputEvent(std::move(web_event), ack);
}
void CompositorMusConnection::OnWindowInputEventAckOnMainThread(
- const base::Closure& ack) {
+ const base::Callback<void(bool)>& ack,
+ bool handled) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
- compositor_task_runner_->PostTask(FROM_HERE, ack);
+ compositor_task_runner_->PostTask(FROM_HERE, base::Bind(ack, handled));
}
void CompositorMusConnection::OnConnectionLost(
@@ -109,7 +116,7 @@ void CompositorMusConnection::OnEmbed(mus::Window* root) {
void CompositorMusConnection::OnWindowInputEvent(
mus::Window* window,
mus::mojom::EventPtr event,
- scoped_ptr<base::Closure>* ack_callback) {
+ scoped_ptr<base::Callback<void(bool)>>* ack_callback) {
DCHECK(compositor_task_runner_->BelongsToCurrentThread());
scoped_ptr<blink::WebInputEvent> web_event =
event.To<scoped_ptr<blink::WebInputEvent>>();
@@ -117,9 +124,11 @@ void CompositorMusConnection::OnWindowInputEvent(
ui::LatencyInfo info;
InputEventAckState ack_state = input_handler_manager_->HandleInputEvent(
routing_id_, web_event.get(), &info);
+ // TODO(jonross): We probably need to ack the event based on the consumed
+ // state.
if (ack_state != INPUT_EVENT_ACK_STATE_NOT_CONSUMED)
return;
- base::Closure ack = base::Bind(&base::DoNothing);
+ base::Callback<void(bool)> ack = base::Bind(&::DoNothingBool);
const bool send_ack =
WebInputEventTraits::WillReceiveAckFromRenderer(*web_event);
if (send_ack) {
diff --git a/content/renderer/mus/compositor_mus_connection.h b/content/renderer/mus/compositor_mus_connection.h
index 7b0f696..a2c377e 100644
--- a/content/renderer/mus/compositor_mus_connection.h
+++ b/content/renderer/mus/compositor_mus_connection.h
@@ -42,6 +42,7 @@ class CompositorMusConnection
scoped_ptr<mus::WindowSurfaceBinding> surface_binding);
private:
+ friend class CompositorMusConnectionTest;
friend class base::RefCountedThreadSafe<CompositorMusConnection>;
~CompositorMusConnection() override;
@@ -56,18 +57,20 @@ class CompositorMusConnection
void OnWindowInputEventOnMainThread(
scoped_ptr<blink::WebInputEvent> web_event,
- const base::Closure& ack);
+ const base::Callback<void(bool)>& ack);
- void OnWindowInputEventAckOnMainThread(const base::Closure& ack);
+ void OnWindowInputEventAckOnMainThread(const base::Callback<void(bool)>& ack,
+ bool handled);
// WindowTreeDelegate implementation:
void OnConnectionLost(mus::WindowTreeConnection* connection) override;
void OnEmbed(mus::Window* root) override;
// InputEventHandler implementation:
- void OnWindowInputEvent(mus::Window* window,
- mus::mojom::EventPtr event,
- scoped_ptr<base::Closure>* ack_callback) override;
+ void OnWindowInputEvent(
+ mus::Window* window,
+ mus::mojom::EventPtr event,
+ scoped_ptr<base::Callback<void(bool)>>* ack_callback) override;
const int routing_id_;
mus::Window* root_;
diff --git a/content/renderer/mus/compositor_mus_connection_unittest.cc b/content/renderer/mus/compositor_mus_connection_unittest.cc
new file mode 100644
index 0000000..0b75f2f
--- /dev/null
+++ b/content/renderer/mus/compositor_mus_connection_unittest.cc
@@ -0,0 +1,466 @@
+// Copyright 2016 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/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/time/time.h"
+#include "components/mus/public/cpp/tests/test_window.h"
+#include "components/mus/public/interfaces/input_event_constants.mojom.h"
+#include "components/mus/public/interfaces/input_events.mojom.h"
+#include "components/mus/public/interfaces/input_key_codes.mojom.h"
+#include "content/common/input/did_overscroll_params.h"
+#include "content/common/input/input_event_ack.h"
+#include "content/common/input/input_event_ack_state.h"
+#include "content/public/test/mock_render_thread.h"
+#include "content/renderer/input/input_handler_manager.h"
+#include "content/renderer/input/input_handler_manager_client.h"
+#include "content/renderer/input/render_widget_input_handler.h"
+#include "content/renderer/mus/render_widget_mus_connection.h"
+#include "content/renderer/render_widget.h"
+#include "content/test/fake_compositor_dependencies.h"
+#include "content/test/fake_renderer_scheduler.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Wrapper for the callback provided to
+// CompositorMusConnection:OnWindowInputEvent. This tracks whether the it was
+// called, along with the result.
+class TestCallback : public base::RefCounted<TestCallback> {
+ public:
+ TestCallback() : called_(false), result_(false) {}
+
+ bool called() { return called_; }
+ bool result() { return result_; }
+
+ void BoolCallback(bool result) {
+ called_ = true;
+ result_ = result;
+ }
+
+ private:
+ friend class base::RefCounted<TestCallback>;
+
+ ~TestCallback() {}
+
+ bool called_;
+ bool result_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestCallback);
+};
+
+// Allows for overriding the behaviour of HandleInputEvent, to simulate input
+// handlers which consume events before they are sent to the renderer.
+class TestInputHandlerManager : public content::InputHandlerManager {
+ public:
+ TestInputHandlerManager(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ content::InputHandlerManagerClient* client,
+ scheduler::RendererScheduler* renderer_scheduler)
+ : InputHandlerManager(task_runner, client, renderer_scheduler),
+ override_result_(false),
+ result_(content::InputEventAckState::INPUT_EVENT_ACK_STATE_UNKNOWN) {}
+ ~TestInputHandlerManager() override {}
+
+ // Stops overriding the behaviour of HandleInputEvent
+ void ClearHandleInputEventOverride();
+
+ // Overrides the behaviour of HandleInputEvent, returing |result|.
+ void SetHandleInputEventResult(content::InputEventAckState result);
+
+ // content::InputHandlerManager:
+ content::InputEventAckState HandleInputEvent(
+ int routing_id,
+ const blink::WebInputEvent* input_event,
+ ui::LatencyInfo* latency_info) override;
+
+ private:
+ // If true content::InputHandlerManager::HandleInputEvent is not called.
+ bool override_result_;
+
+ // The result to return in HandleInputEvent if |override_result_|.
+ content::InputEventAckState result_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestInputHandlerManager);
+};
+
+void TestInputHandlerManager::ClearHandleInputEventOverride() {
+ override_result_ = false;
+}
+
+void TestInputHandlerManager::SetHandleInputEventResult(
+ content::InputEventAckState result) {
+ override_result_ = true;
+ result_ = result;
+}
+
+content::InputEventAckState TestInputHandlerManager::HandleInputEvent(
+ int routing_id,
+ const blink::WebInputEvent* input_event,
+ ui::LatencyInfo* latency_info) {
+ if (override_result_)
+ return result_;
+ return content::InputHandlerManager::HandleInputEvent(routing_id, input_event,
+ latency_info);
+}
+
+// Empty implementation of InputHandlerManagerClient.
+class TestInputHandlerManagerClient
+ : public content::InputHandlerManagerClient {
+ public:
+ TestInputHandlerManagerClient() {}
+ ~TestInputHandlerManagerClient() override{};
+
+ // content::InputHandlerManagerClient:
+ void SetBoundHandler(const Handler& handler) override {}
+ void DidAddInputHandler(
+ int routing_id,
+ ui::SynchronousInputHandlerProxy* synchronous_handler) override {}
+ void DidRemoveInputHandler(int routing_id) override {}
+ void DidOverscroll(int routing_id,
+ const content::DidOverscrollParams& params) override {}
+ void DidStopFlinging(int routing_id) override {}
+ void NonBlockingInputEventHandled(int routing_id,
+ blink::WebInputEvent::Type type) override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestInputHandlerManagerClient);
+};
+
+// Implementation of RenderWidget for testing, performs no initialization.
+class TestRenderWidget : public content::RenderWidget {
+ public:
+ explicit TestRenderWidget(content::CompositorDependencies* compositor_deps)
+ : content::RenderWidget(compositor_deps,
+ blink::WebPopupTypeNone,
+ blink::WebScreenInfo(),
+ true,
+ false,
+ false) {}
+
+ protected:
+ ~TestRenderWidget() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestRenderWidget);
+};
+
+// Test override of RenderWidgetInputHandler to allow the control of
+// HandleInputEvent. This will perform no actions on input until a
+// RenderWidgetInputHandlerDelegate is set. Once set this will always ack
+// received events.
+class TestRenderWidgetInputHandler : public content::RenderWidgetInputHandler {
+ public:
+ TestRenderWidgetInputHandler(content::RenderWidget* render_widget);
+ ~TestRenderWidgetInputHandler() override {}
+
+ void set_delegate(content::RenderWidgetInputHandlerDelegate* delegate) {
+ delegate_ = delegate;
+ }
+ void set_state(content::InputEventAckState state) { state_ = state; }
+
+ // content::RenderWidgetInputHandler:
+ void HandleInputEvent(const blink::WebInputEvent& input_event,
+ const ui::LatencyInfo& latency_info,
+ content::InputEventDispatchType dispatch_type) override;
+
+ private:
+ // The input delegate which receives event acks.
+ content::RenderWidgetInputHandlerDelegate* delegate_;
+
+ // The result of input handling to send to |delegate_| during the ack.
+ content::InputEventAckState state_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestRenderWidgetInputHandler);
+};
+
+TestRenderWidgetInputHandler::TestRenderWidgetInputHandler(
+ content::RenderWidget* render_widget)
+ : content::RenderWidgetInputHandler(render_widget, render_widget),
+ delegate_(nullptr),
+ state_(content::InputEventAckState::INPUT_EVENT_ACK_STATE_UNKNOWN) {}
+
+void TestRenderWidgetInputHandler::HandleInputEvent(
+ const blink::WebInputEvent& input_event,
+ const ui::LatencyInfo& latency_info,
+ content::InputEventDispatchType dispatch_type) {
+ if (delegate_) {
+ scoped_ptr<content::InputEventAck> ack(
+ new content::InputEventAck(input_event.type, state_));
+ delegate_->OnInputEventAck(std::move(ack));
+ }
+}
+
+} // namespace
+
+namespace content {
+
+// Test suite for CompositorMusConnection, this does not setup a full renderer
+// environment. This does not establish a connection to a mus server, nor does
+// it initialize one.
+class CompositorMusConnectionTest : public testing::Test {
+ public:
+ CompositorMusConnectionTest() {}
+ ~CompositorMusConnectionTest() override {}
+
+ // Initializes |event| with valid parameters for a key event, so that it can
+ // be converted to a web event by CompositorMusConnection.
+ void GenerateKeyEvent(mus::mojom::EventPtr& event);
+
+ // Calls CompositorMusConnection::OnWindowInputEvent.
+ void OnWindowInputEvent(mus::Window* window,
+ mus::mojom::EventPtr event,
+ scoped_ptr<base::Callback<void(bool)>>* ack_callback);
+
+ // Confirms the state of pending tasks enqueued on each task runner, and runs
+ // until idle.
+ void VerifyAndRunQueues(bool main_task_runner_enqueued,
+ bool compositor_task_runner_enqueued);
+
+ CompositorMusConnection* compositor_connection() {
+ return compositor_connection_.get();
+ }
+ RenderWidgetMusConnection* connection() { return connection_; }
+ TestInputHandlerManager* input_handler_manager() {
+ return input_handler_manager_.get();
+ }
+ TestRenderWidgetInputHandler* render_widget_input_handler() {
+ return render_widget_input_handler_.get();
+ }
+
+ // testing::Test:
+ void SetUp() override;
+ void TearDown() override;
+
+ private:
+ // Mocks/Fakes of the testing environment.
+ TestInputHandlerManagerClient input_handler_manager_client_;
+ FakeCompositorDependencies compositor_dependencies_;
+ FakeRendererScheduler renderer_scheduler_;
+ MockRenderThread render_thread_;
+ scoped_refptr<TestRenderWidget> render_widget_;
+ mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request_;
+
+ // Not owned, RenderWidgetMusConnection tracks in static state. Cleared during
+ // TearDown.
+ RenderWidgetMusConnection* connection_;
+
+ // Test versions of task runners, see VerifyAndRunQueues to use in testing.
+ scoped_refptr<base::TestSimpleTaskRunner> main_task_runner_;
+ scoped_refptr<base::TestSimpleTaskRunner> compositor_task_runner_;
+
+ // Actual CompositorMusConnection for testing.
+ scoped_refptr<CompositorMusConnection> compositor_connection_;
+
+ // Test implementations, to control input given to |compositor_connection_|.
+ scoped_ptr<TestInputHandlerManager> input_handler_manager_;
+ scoped_ptr<TestRenderWidgetInputHandler> render_widget_input_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompositorMusConnectionTest);
+};
+
+void CompositorMusConnectionTest::GenerateKeyEvent(
+ mus::mojom::EventPtr& event) {
+ event->action = mus::mojom::EventType::KEY_PRESSED;
+ event->time_stamp = base::TimeTicks::Now().ToInternalValue();
+ event->key_data = mus::mojom::KeyData::New();
+ event->key_data->is_char = true;
+ event->key_data->windows_key_code = mus::mojom::KeyboardCode::A;
+}
+
+void CompositorMusConnectionTest::OnWindowInputEvent(
+ mus::Window* window,
+ mus::mojom::EventPtr event,
+ scoped_ptr<base::Callback<void(bool)>>* ack_callback) {
+ compositor_connection_->OnWindowInputEvent(window, std::move(event),
+ ack_callback);
+}
+
+void CompositorMusConnectionTest::VerifyAndRunQueues(
+ bool main_task_runner_enqueued,
+ bool compositor_task_runner_enqueued) {
+ // Run through the enqueued actions.
+ EXPECT_EQ(main_task_runner_enqueued, main_task_runner_->HasPendingTask());
+ main_task_runner_->RunUntilIdle();
+
+ EXPECT_EQ(compositor_task_runner_enqueued,
+ compositor_task_runner_->HasPendingTask());
+ compositor_task_runner_->RunUntilIdle();
+}
+
+void CompositorMusConnectionTest::SetUp() {
+ testing::Test::SetUp();
+
+ main_task_runner_ = new base::TestSimpleTaskRunner();
+ compositor_task_runner_ = new base::TestSimpleTaskRunner();
+
+ input_handler_manager_.reset(new TestInputHandlerManager(
+ compositor_task_runner_, &input_handler_manager_client_,
+ &renderer_scheduler_));
+
+ const int routing_id = 42;
+ compositor_connection_ = new CompositorMusConnection(
+ routing_id, main_task_runner_, compositor_task_runner_,
+ std::move(request_), input_handler_manager_.get());
+
+ // CompositorMusConnection attempts to create connection to the non-existant
+ // server. Clear that.
+ compositor_task_runner_->ClearPendingTasks();
+
+ render_widget_ = new TestRenderWidget(&compositor_dependencies_);
+ render_widget_input_handler_.reset(
+ new TestRenderWidgetInputHandler(render_widget_.get()));
+ connection_ = RenderWidgetMusConnection::GetOrCreate(routing_id);
+ connection_->SetInputHandler(render_widget_input_handler_.get());
+}
+
+void CompositorMusConnectionTest::TearDown() {
+ // Clear static state.
+ connection_->OnConnectionLost();
+ testing::Test::TearDown();
+}
+
+// Tests that for events which the renderer will ack, yet not consume, that
+// CompositorMusConnection consumes the ack during OnWindowInputEvent, and calls
+// it with the correct state once processed.
+TEST_F(CompositorMusConnectionTest, NotConsumed) {
+ TestRenderWidgetInputHandler* input_handler = render_widget_input_handler();
+ input_handler->set_delegate(connection());
+ input_handler->set_state(
+ InputEventAckState::INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ mus::TestWindow test_window;
+ mus::mojom::EventPtr event = mus::mojom::Event::New();
+ GenerateKeyEvent(event);
+ scoped_refptr<TestCallback> test_callback(new TestCallback);
+ scoped_ptr<base::Callback<void(bool)>> ack_callback(
+ new base::Callback<void(bool)>(
+ base::Bind(&::TestCallback::BoolCallback, test_callback)));
+
+ OnWindowInputEvent(&test_window, std::move(event), &ack_callback);
+ // OnWindowInputEvent is expected to clear the callback if it plans on
+ // handling the ack.
+ EXPECT_FALSE(ack_callback.get());
+
+ VerifyAndRunQueues(true, true);
+
+ // The ack callback should have been called
+ EXPECT_TRUE(test_callback->called());
+ EXPECT_FALSE(test_callback->result());
+}
+
+// Tests that for events which the renderer will ack, and consume, that
+// CompositorMusConnection consumes the ack during OnWindowInputEvent, and calls
+// it with the correct state once processed.
+TEST_F(CompositorMusConnectionTest, Consumed) {
+ TestRenderWidgetInputHandler* input_handler = render_widget_input_handler();
+ input_handler->set_delegate(connection());
+ input_handler->set_state(InputEventAckState::INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ mus::TestWindow test_window;
+ mus::mojom::EventPtr event = mus::mojom::Event::New();
+ GenerateKeyEvent(event);
+ scoped_refptr<TestCallback> test_callback(new TestCallback);
+ scoped_ptr<base::Callback<void(bool)>> ack_callback(
+ new base::Callback<void(bool)>(
+ base::Bind(&::TestCallback::BoolCallback, test_callback)));
+
+ OnWindowInputEvent(&test_window, std::move(event), &ack_callback);
+ // OnWindowInputEvent is expected to clear the callback if it plans on
+ // handling the ack.
+ EXPECT_FALSE(ack_callback.get());
+
+ VerifyAndRunQueues(true, true);
+
+ // The ack callback should have been called
+ EXPECT_TRUE(test_callback->called());
+ EXPECT_TRUE(test_callback->result());
+}
+
+// Tests that when the RenderWidgetInputHandler does not ack before a new event
+// arrives, that only the most recent ack is fired.
+TEST_F(CompositorMusConnectionTest, LostAck) {
+ mus::TestWindow test_window;
+ mus::mojom::EventPtr event1 = mus::mojom::Event::New();
+ GenerateKeyEvent(event1);
+ scoped_refptr<TestCallback> test_callback1(new TestCallback);
+ scoped_ptr<base::Callback<void(bool)>> ack_callback1(
+ new base::Callback<void(bool)>(
+ base::Bind(&::TestCallback::BoolCallback, test_callback1)));
+
+ OnWindowInputEvent(&test_window, std::move(event1), &ack_callback1);
+ EXPECT_FALSE(ack_callback1.get());
+ // When simulating the timeout the ack is never enqueued
+ VerifyAndRunQueues(true, false);
+
+ // Setting a delegate will lead to the next event being acked. Having a
+ // cleared queue simulates the input handler timing out on an event.
+ TestRenderWidgetInputHandler* input_handler = render_widget_input_handler();
+ input_handler->set_delegate(connection());
+ input_handler->set_state(InputEventAckState::INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ mus::mojom::EventPtr event2 = mus::mojom::Event::New();
+ GenerateKeyEvent(event2);
+ scoped_refptr<TestCallback> test_callback2(new TestCallback);
+ scoped_ptr<base::Callback<void(bool)>> ack_callback2(
+ new base::Callback<void(bool)>(
+ base::Bind(&::TestCallback::BoolCallback, test_callback2)));
+ OnWindowInputEvent(&test_window, std::move(event2), &ack_callback2);
+ EXPECT_FALSE(ack_callback2.get());
+
+ VerifyAndRunQueues(true, true);
+
+ // Only the most recent ack was called.
+ EXPECT_FALSE(test_callback1->called());
+ EXPECT_TRUE(test_callback2->called());
+ EXPECT_TRUE(test_callback2->result());
+}
+
+// Tests that when an input handler consumes the event, that
+// CompositorMusConnection does not consume the ack, nor calls it.
+TEST_F(CompositorMusConnectionTest, InputHandlerConsumes) {
+ input_handler_manager()->SetHandleInputEventResult(
+ InputEventAckState::INPUT_EVENT_ACK_STATE_CONSUMED);
+ mus::TestWindow test_window;
+ mus::mojom::EventPtr event = mus::mojom::Event::New();
+ GenerateKeyEvent(event);
+ scoped_refptr<TestCallback> test_callback(new TestCallback);
+ scoped_ptr<base::Callback<void(bool)>> ack_callback(
+ new base::Callback<void(bool)>(
+ base::Bind(&::TestCallback::BoolCallback, test_callback)));
+
+ OnWindowInputEvent(&test_window, std::move(event), &ack_callback);
+
+ EXPECT_TRUE(ack_callback.get());
+ VerifyAndRunQueues(false, false);
+ EXPECT_FALSE(test_callback->called());
+}
+
+// Tests that when the renderer will not ack an event, that
+// CompositorMusConnection does not consume the ack, nor calls it.
+TEST_F(CompositorMusConnectionTest, RendererWillNotSendAck) {
+ mus::TestWindow test_window;
+ mus::mojom::EventPtr event = mus::mojom::Event::New();
+ event->action = mus::mojom::EventType::POINTER_DOWN;
+ event->time_stamp = base::TimeTicks::Now().ToInternalValue();
+ event->pointer_data = mus::mojom::PointerData::New();
+
+ scoped_refptr<TestCallback> test_callback(new TestCallback);
+ scoped_ptr<base::Callback<void(bool)>> ack_callback(
+ new base::Callback<void(bool)>(
+ base::Bind(&::TestCallback::BoolCallback, test_callback)));
+
+ OnWindowInputEvent(&test_window, std::move(event), &ack_callback);
+ EXPECT_TRUE(ack_callback.get());
+
+ VerifyAndRunQueues(true, false);
+ EXPECT_FALSE(test_callback->called());
+}
+
+} // namespace content
diff --git a/content/renderer/mus/render_widget_mus_connection.cc b/content/renderer/mus/render_widget_mus_connection.cc
index c2dc1d1..bced0df 100644
--- a/content/renderer/mus/render_widget_mus_connection.cc
+++ b/content/renderer/mus/render_widget_mus_connection.cc
@@ -118,8 +118,8 @@ void RenderWidgetMusConnection::OnDidOverscroll(
void RenderWidgetMusConnection::OnInputEventAck(
scoped_ptr<InputEventAck> input_event_ack) {
DCHECK(!pending_ack_.is_null());
- // TODO(fsamuel): Use the state in |input_event_ack|.
- pending_ack_.Run();
+ pending_ack_.Run(input_event_ack->state ==
+ InputEventAckState::INPUT_EVENT_ACK_STATE_CONSUMED);
pending_ack_.Reset();
}
@@ -161,12 +161,12 @@ void RenderWidgetMusConnection::OnConnectionLost() {
void RenderWidgetMusConnection::OnWindowInputEvent(
scoped_ptr<blink::WebInputEvent> input_event,
- const base::Closure& ack) {
+ const base::Callback<void(bool)>& ack) {
DCHECK(thread_checker_.CalledOnValidThread());
// If we don't yet have a RenderWidgetInputHandler then we don't yet have
// an initialized RenderWidget.
if (!input_handler_) {
- ack.Run();
+ ack.Run(false);
return;
}
// TODO(fsamuel): It would be nice to add this DCHECK but the reality is an
diff --git a/content/renderer/mus/render_widget_mus_connection.h b/content/renderer/mus/render_widget_mus_connection.h
index 26f1b4b..1c9bc03 100644
--- a/content/renderer/mus/render_widget_mus_connection.h
+++ b/content/renderer/mus/render_widget_mus_connection.h
@@ -33,6 +33,7 @@ class RenderWidgetMusConnection : public RenderWidgetInputHandlerDelegate {
private:
friend class CompositorMusConnection;
+ friend class CompositorMusConnectionTest;
explicit RenderWidgetMusConnection(int routing_id);
~RenderWidgetMusConnection() override;
@@ -56,14 +57,14 @@ class RenderWidgetMusConnection : public RenderWidgetInputHandlerDelegate {
void OnConnectionLost();
void OnWindowInputEvent(scoped_ptr<blink::WebInputEvent> input_event,
- const base::Closure& ack);
+ const base::Callback<void(bool)>& ack);
const int routing_id_;
RenderWidgetInputHandler* input_handler_;
scoped_ptr<mus::WindowSurfaceBinding> window_surface_binding_;
scoped_refptr<CompositorMusConnection> compositor_mus_connection_;
- base::Closure pending_ack_;
+ base::Callback<void(bool)> pending_ack_;
// Used to verify single threaded access.
base::ThreadChecker thread_checker_;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 55e264e..1070e26 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -765,10 +765,13 @@ test("content_unittests") {
if (use_aura) {
deps += [
+ "//content/public/renderer:renderer_sources",
+ "//content/renderer/mus:mus",
"//ui/aura",
"//ui/aura_extra",
"//ui/wm",
]
+ sources += [ "../renderer/mus/compositor_mus_connection_unittest.cc" ]
} else {
sources -= [
"../browser/renderer_host/render_widget_host_view_aura_unittest.cc",
diff --git a/ui/views/mus/platform_window_mus.cc b/ui/views/mus/platform_window_mus.cc
index 3961390..2a1fc4e 100644
--- a/ui/views/mus/platform_window_mus.cc
+++ b/ui/views/mus/platform_window_mus.cc
@@ -223,11 +223,11 @@ void PlatformWindowMus::OnRequestClose(mus::Window* window) {
void PlatformWindowMus::OnWindowInputEvent(
mus::Window* view,
mus::mojom::EventPtr event,
- scoped_ptr<base::Closure>* ack_callback) {
+ scoped_ptr<base::Callback<void(bool)>>* ack_callback) {
// It's possible dispatching the event will spin a nested message loop. Ack
// the callback now, otherwise we appear unresponsive for the life of the
// nested message loop.
- (*ack_callback)->Run();
+ (*ack_callback)->Run(true);
ack_callback->reset();
scoped_ptr<ui::Event> ui_event(event.To<scoped_ptr<ui::Event>>());
delegate_->DispatchEvent(ui_event.get());
diff --git a/ui/views/mus/platform_window_mus.h b/ui/views/mus/platform_window_mus.h
index 2d95a21..725430c 100644
--- a/ui/views/mus/platform_window_mus.h
+++ b/ui/views/mus/platform_window_mus.h
@@ -82,9 +82,10 @@ class VIEWS_MUS_EXPORT PlatformWindowMus
void OnRequestClose(mus::Window* window) override;
// mus::InputEventHandler:
- void OnWindowInputEvent(mus::Window* view,
- mus::mojom::EventPtr event,
- scoped_ptr<base::Closure>* ack_callback) override;
+ void OnWindowInputEvent(
+ mus::Window* view,
+ mus::mojom::EventPtr event,
+ scoped_ptr<base::Callback<void(bool)>>* ack_callback) override;
ui::PlatformWindowDelegate* delegate_;
mus::Window* mus_window_;