| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/renderer/mus/compositor_mus_connection.h" |
| 6 |
| 7 #include "base/macros.h" |
| 8 #include "base/memory/ref_counted.h" |
| 9 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/test/test_simple_task_runner.h" |
| 11 #include "base/time/time.h" |
| 12 #include "components/mus/public/cpp/tests/test_window.h" |
| 13 #include "components/mus/public/interfaces/input_event_constants.mojom.h" |
| 14 #include "components/mus/public/interfaces/input_events.mojom.h" |
| 15 #include "components/mus/public/interfaces/input_key_codes.mojom.h" |
| 16 #include "content/common/input/did_overscroll_params.h" |
| 17 #include "content/common/input/input_event_ack.h" |
| 18 #include "content/common/input/input_event_ack_state.h" |
| 19 #include "content/public/test/mock_render_thread.h" |
| 20 #include "content/renderer/input/input_handler_manager.h" |
| 21 #include "content/renderer/input/input_handler_manager_client.h" |
| 22 #include "content/renderer/input/render_widget_input_handler.h" |
| 23 #include "content/renderer/mus/render_widget_mus_connection.h" |
| 24 #include "content/renderer/render_widget.h" |
| 25 #include "content/test/fake_compositor_dependencies.h" |
| 26 #include "content/test/fake_renderer_scheduler.h" |
| 27 #include "mojo/public/cpp/bindings/interface_request.h" |
| 28 #include "testing/gtest/include/gtest/gtest.h" |
| 29 |
| 30 namespace { |
| 31 |
| 32 // Wrapper for the callback provided to |
| 33 // CompositorMusConnection:OnWindowInputEvent. This tracks whether the it was |
| 34 // called, along with the result. |
| 35 class TestCallback : public base::RefCounted<TestCallback> { |
| 36 public: |
| 37 TestCallback() : called_(false), result_(false) {} |
| 38 |
| 39 bool called() { return called_; } |
| 40 bool result() { return result_; } |
| 41 |
| 42 void BoolCallback(bool result) { |
| 43 called_ = true; |
| 44 result_ = result; |
| 45 } |
| 46 |
| 47 private: |
| 48 friend class base::RefCounted<TestCallback>; |
| 49 |
| 50 ~TestCallback() {} |
| 51 |
| 52 bool called_; |
| 53 bool result_; |
| 54 |
| 55 DISALLOW_COPY_AND_ASSIGN(TestCallback); |
| 56 }; |
| 57 |
| 58 // Allows for overriding the behaviour of HandleInputEvent, to simulate input |
| 59 // handlers which consume events before they are sent to the renderer. |
| 60 class TestInputHandlerManager : public content::InputHandlerManager { |
| 61 public: |
| 62 TestInputHandlerManager( |
| 63 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| 64 content::InputHandlerManagerClient* client, |
| 65 scheduler::RendererScheduler* renderer_scheduler) |
| 66 : InputHandlerManager(task_runner, client, renderer_scheduler), |
| 67 override_result_(false), |
| 68 result_(content::InputEventAckState::INPUT_EVENT_ACK_STATE_UNKNOWN) {} |
| 69 ~TestInputHandlerManager() override {} |
| 70 |
| 71 // Stops overriding the behaviour of HandleInputEvent |
| 72 void ClearHandleInputEventOverride(); |
| 73 |
| 74 // Overrides the behaviour of HandleInputEvent, returing |result|. |
| 75 void SetHandleInputEventResult(content::InputEventAckState result); |
| 76 |
| 77 // content::InputHandlerManager: |
| 78 content::InputEventAckState HandleInputEvent( |
| 79 int routing_id, |
| 80 const blink::WebInputEvent* input_event, |
| 81 ui::LatencyInfo* latency_info) override; |
| 82 |
| 83 private: |
| 84 // If true content::InputHandlerManager::HandleInputEvent is not called. |
| 85 bool override_result_; |
| 86 |
| 87 // The result to return in HandleInputEvent if |override_result_|. |
| 88 content::InputEventAckState result_; |
| 89 |
| 90 DISALLOW_COPY_AND_ASSIGN(TestInputHandlerManager); |
| 91 }; |
| 92 |
| 93 void TestInputHandlerManager::ClearHandleInputEventOverride() { |
| 94 override_result_ = false; |
| 95 } |
| 96 |
| 97 void TestInputHandlerManager::SetHandleInputEventResult( |
| 98 content::InputEventAckState result) { |
| 99 override_result_ = true; |
| 100 result_ = result; |
| 101 } |
| 102 |
| 103 content::InputEventAckState TestInputHandlerManager::HandleInputEvent( |
| 104 int routing_id, |
| 105 const blink::WebInputEvent* input_event, |
| 106 ui::LatencyInfo* latency_info) { |
| 107 if (override_result_) |
| 108 return result_; |
| 109 return content::InputHandlerManager::HandleInputEvent(routing_id, input_event, |
| 110 latency_info); |
| 111 } |
| 112 |
| 113 // Empty implementation of InputHandlerManagerClient. |
| 114 class TestInputHandlerManagerClient |
| 115 : public content::InputHandlerManagerClient { |
| 116 public: |
| 117 TestInputHandlerManagerClient() {} |
| 118 ~TestInputHandlerManagerClient() override{}; |
| 119 |
| 120 // content::InputHandlerManagerClient: |
| 121 void SetBoundHandler(const Handler& handler) override {} |
| 122 void DidAddInputHandler( |
| 123 int routing_id, |
| 124 ui::SynchronousInputHandlerProxy* synchronous_handler) override {} |
| 125 void DidRemoveInputHandler(int routing_id) override {} |
| 126 void DidOverscroll(int routing_id, |
| 127 const content::DidOverscrollParams& params) override {} |
| 128 void DidStopFlinging(int routing_id) override {} |
| 129 void NonBlockingInputEventHandled(int routing_id, |
| 130 blink::WebInputEvent::Type type) override {} |
| 131 |
| 132 private: |
| 133 DISALLOW_COPY_AND_ASSIGN(TestInputHandlerManagerClient); |
| 134 }; |
| 135 |
| 136 // Implementation of RenderWidget for testing, performs no initialization. |
| 137 class TestRenderWidget : public content::RenderWidget { |
| 138 public: |
| 139 explicit TestRenderWidget(content::CompositorDependencies* compositor_deps) |
| 140 : content::RenderWidget(compositor_deps, |
| 141 blink::WebPopupTypeNone, |
| 142 blink::WebScreenInfo(), |
| 143 true, |
| 144 false, |
| 145 false) {} |
| 146 |
| 147 protected: |
| 148 ~TestRenderWidget() override {} |
| 149 |
| 150 private: |
| 151 DISALLOW_COPY_AND_ASSIGN(TestRenderWidget); |
| 152 }; |
| 153 |
| 154 // Test override of RenderWidgetInputHandler to allow the control of |
| 155 // HandleInputEvent. This will perform no actions on input until a |
| 156 // RenderWidgetInputHandlerDelegate is set. Once set this will always ack |
| 157 // received events. |
| 158 class TestRenderWidgetInputHandler : public content::RenderWidgetInputHandler { |
| 159 public: |
| 160 TestRenderWidgetInputHandler(content::RenderWidget* render_widget); |
| 161 ~TestRenderWidgetInputHandler() override {} |
| 162 |
| 163 void set_delegate(content::RenderWidgetInputHandlerDelegate* delegate) { |
| 164 delegate_ = delegate; |
| 165 } |
| 166 void set_state(content::InputEventAckState state) { state_ = state; } |
| 167 |
| 168 // content::RenderWidgetInputHandler: |
| 169 void HandleInputEvent(const blink::WebInputEvent& input_event, |
| 170 const ui::LatencyInfo& latency_info, |
| 171 content::InputEventDispatchType dispatch_type) override; |
| 172 |
| 173 private: |
| 174 // The input delegate which receives event acks. |
| 175 content::RenderWidgetInputHandlerDelegate* delegate_; |
| 176 |
| 177 // The result of input handling to send to |delegate_| during the ack. |
| 178 content::InputEventAckState state_; |
| 179 |
| 180 DISALLOW_COPY_AND_ASSIGN(TestRenderWidgetInputHandler); |
| 181 }; |
| 182 |
| 183 TestRenderWidgetInputHandler::TestRenderWidgetInputHandler( |
| 184 content::RenderWidget* render_widget) |
| 185 : content::RenderWidgetInputHandler(render_widget, render_widget), |
| 186 delegate_(nullptr), |
| 187 state_(content::InputEventAckState::INPUT_EVENT_ACK_STATE_UNKNOWN) {} |
| 188 |
| 189 void TestRenderWidgetInputHandler::HandleInputEvent( |
| 190 const blink::WebInputEvent& input_event, |
| 191 const ui::LatencyInfo& latency_info, |
| 192 content::InputEventDispatchType dispatch_type) { |
| 193 if (delegate_) { |
| 194 scoped_ptr<content::InputEventAck> ack( |
| 195 new content::InputEventAck(input_event.type, state_)); |
| 196 delegate_->OnInputEventAck(std::move(ack)); |
| 197 } |
| 198 } |
| 199 |
| 200 } // namespace |
| 201 |
| 202 namespace content { |
| 203 |
| 204 // Test suite for CompositorMusConnection, this does not setup a full renderer |
| 205 // environment. This does not establish a connection to a mus server, nor does |
| 206 // it initialize one. |
| 207 class CompositorMusConnectionTest : public testing::Test { |
| 208 public: |
| 209 CompositorMusConnectionTest() {} |
| 210 ~CompositorMusConnectionTest() override {} |
| 211 |
| 212 // Initializes |event| with valid parameters for a key event, so that it can |
| 213 // be converted to a web event by CompositorMusConnection. |
| 214 void GenerateKeyEvent(mus::mojom::EventPtr& event); |
| 215 |
| 216 // Calls CompositorMusConnection::OnWindowInputEvent. |
| 217 void OnWindowInputEvent(mus::Window* window, |
| 218 mus::mojom::EventPtr event, |
| 219 scoped_ptr<base::Callback<void(bool)>>* ack_callback); |
| 220 |
| 221 // Confirms the state of pending tasks enqueued on each task runner, and runs |
| 222 // until idle. |
| 223 void VerifyAndRunQueues(bool main_task_runner_enqueued, |
| 224 bool compositor_task_runner_enqueued); |
| 225 |
| 226 CompositorMusConnection* compositor_connection() { |
| 227 return compositor_connection_.get(); |
| 228 } |
| 229 RenderWidgetMusConnection* connection() { return connection_; } |
| 230 TestInputHandlerManager* input_handler_manager() { |
| 231 return input_handler_manager_.get(); |
| 232 } |
| 233 TestRenderWidgetInputHandler* render_widget_input_handler() { |
| 234 return render_widget_input_handler_.get(); |
| 235 } |
| 236 |
| 237 // testing::Test: |
| 238 void SetUp() override; |
| 239 void TearDown() override; |
| 240 |
| 241 private: |
| 242 // Mocks/Fakes of the testing environment. |
| 243 TestInputHandlerManagerClient input_handler_manager_client_; |
| 244 FakeCompositorDependencies compositor_dependencies_; |
| 245 FakeRendererScheduler renderer_scheduler_; |
| 246 MockRenderThread render_thread_; |
| 247 scoped_refptr<TestRenderWidget> render_widget_; |
| 248 mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request_; |
| 249 |
| 250 // Not owned, RenderWidgetMusConnection tracks in static state. Cleared during |
| 251 // TearDown. |
| 252 RenderWidgetMusConnection* connection_; |
| 253 |
| 254 // Test versions of task runners, see VerifyAndRunQueues to use in testing. |
| 255 scoped_refptr<base::TestSimpleTaskRunner> main_task_runner_; |
| 256 scoped_refptr<base::TestSimpleTaskRunner> compositor_task_runner_; |
| 257 |
| 258 // Actual CompositorMusConnection for testing. |
| 259 scoped_refptr<CompositorMusConnection> compositor_connection_; |
| 260 |
| 261 // Test implementations, to control input given to |compositor_connection_|. |
| 262 scoped_ptr<TestInputHandlerManager> input_handler_manager_; |
| 263 scoped_ptr<TestRenderWidgetInputHandler> render_widget_input_handler_; |
| 264 |
| 265 DISALLOW_COPY_AND_ASSIGN(CompositorMusConnectionTest); |
| 266 }; |
| 267 |
| 268 void CompositorMusConnectionTest::GenerateKeyEvent( |
| 269 mus::mojom::EventPtr& event) { |
| 270 event->action = mus::mojom::EventType::KEY_PRESSED; |
| 271 event->time_stamp = base::TimeTicks::Now().ToInternalValue(); |
| 272 event->key_data = mus::mojom::KeyData::New(); |
| 273 event->key_data->is_char = true; |
| 274 event->key_data->windows_key_code = mus::mojom::KeyboardCode::A; |
| 275 } |
| 276 |
| 277 void CompositorMusConnectionTest::OnWindowInputEvent( |
| 278 mus::Window* window, |
| 279 mus::mojom::EventPtr event, |
| 280 scoped_ptr<base::Callback<void(bool)>>* ack_callback) { |
| 281 compositor_connection_->OnWindowInputEvent(window, std::move(event), |
| 282 ack_callback); |
| 283 } |
| 284 |
| 285 void CompositorMusConnectionTest::VerifyAndRunQueues( |
| 286 bool main_task_runner_enqueued, |
| 287 bool compositor_task_runner_enqueued) { |
| 288 // Run through the enqueued actions. |
| 289 EXPECT_EQ(main_task_runner_enqueued, main_task_runner_->HasPendingTask()); |
| 290 main_task_runner_->RunUntilIdle(); |
| 291 |
| 292 EXPECT_EQ(compositor_task_runner_enqueued, |
| 293 compositor_task_runner_->HasPendingTask()); |
| 294 compositor_task_runner_->RunUntilIdle(); |
| 295 } |
| 296 |
| 297 void CompositorMusConnectionTest::SetUp() { |
| 298 testing::Test::SetUp(); |
| 299 |
| 300 main_task_runner_ = new base::TestSimpleTaskRunner(); |
| 301 compositor_task_runner_ = new base::TestSimpleTaskRunner(); |
| 302 |
| 303 input_handler_manager_.reset(new TestInputHandlerManager( |
| 304 compositor_task_runner_, &input_handler_manager_client_, |
| 305 &renderer_scheduler_)); |
| 306 |
| 307 const int routing_id = 42; |
| 308 compositor_connection_ = new CompositorMusConnection( |
| 309 routing_id, main_task_runner_, compositor_task_runner_, |
| 310 std::move(request_), input_handler_manager_.get()); |
| 311 |
| 312 // CompositorMusConnection attempts to create connection to the non-existant |
| 313 // server. Clear that. |
| 314 compositor_task_runner_->ClearPendingTasks(); |
| 315 |
| 316 render_widget_ = new TestRenderWidget(&compositor_dependencies_); |
| 317 render_widget_input_handler_.reset( |
| 318 new TestRenderWidgetInputHandler(render_widget_.get())); |
| 319 connection_ = RenderWidgetMusConnection::GetOrCreate(routing_id); |
| 320 connection_->SetInputHandler(render_widget_input_handler_.get()); |
| 321 } |
| 322 |
| 323 void CompositorMusConnectionTest::TearDown() { |
| 324 // Clear static state. |
| 325 connection_->OnConnectionLost(); |
| 326 testing::Test::TearDown(); |
| 327 } |
| 328 |
| 329 // Tests that for events which the renderer will ack, yet not consume, that |
| 330 // CompositorMusConnection consumes the ack during OnWindowInputEvent, and calls |
| 331 // it with the correct state once processed. |
| 332 TEST_F(CompositorMusConnectionTest, NotConsumed) { |
| 333 TestRenderWidgetInputHandler* input_handler = render_widget_input_handler(); |
| 334 input_handler->set_delegate(connection()); |
| 335 input_handler->set_state( |
| 336 InputEventAckState::INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 337 |
| 338 mus::TestWindow test_window; |
| 339 mus::mojom::EventPtr event = mus::mojom::Event::New(); |
| 340 GenerateKeyEvent(event); |
| 341 scoped_refptr<TestCallback> test_callback(new TestCallback); |
| 342 scoped_ptr<base::Callback<void(bool)>> ack_callback( |
| 343 new base::Callback<void(bool)>( |
| 344 base::Bind(&::TestCallback::BoolCallback, test_callback))); |
| 345 |
| 346 OnWindowInputEvent(&test_window, std::move(event), &ack_callback); |
| 347 // OnWindowInputEvent is expected to clear the callback if it plans on |
| 348 // handling the ack. |
| 349 EXPECT_FALSE(ack_callback.get()); |
| 350 |
| 351 VerifyAndRunQueues(true, true); |
| 352 |
| 353 // The ack callback should have been called |
| 354 EXPECT_TRUE(test_callback->called()); |
| 355 EXPECT_FALSE(test_callback->result()); |
| 356 } |
| 357 |
| 358 // Tests that for events which the renderer will ack, and consume, that |
| 359 // CompositorMusConnection consumes the ack during OnWindowInputEvent, and calls |
| 360 // it with the correct state once processed. |
| 361 TEST_F(CompositorMusConnectionTest, Consumed) { |
| 362 TestRenderWidgetInputHandler* input_handler = render_widget_input_handler(); |
| 363 input_handler->set_delegate(connection()); |
| 364 input_handler->set_state(InputEventAckState::INPUT_EVENT_ACK_STATE_CONSUMED); |
| 365 |
| 366 mus::TestWindow test_window; |
| 367 mus::mojom::EventPtr event = mus::mojom::Event::New(); |
| 368 GenerateKeyEvent(event); |
| 369 scoped_refptr<TestCallback> test_callback(new TestCallback); |
| 370 scoped_ptr<base::Callback<void(bool)>> ack_callback( |
| 371 new base::Callback<void(bool)>( |
| 372 base::Bind(&::TestCallback::BoolCallback, test_callback))); |
| 373 |
| 374 OnWindowInputEvent(&test_window, std::move(event), &ack_callback); |
| 375 // OnWindowInputEvent is expected to clear the callback if it plans on |
| 376 // handling the ack. |
| 377 EXPECT_FALSE(ack_callback.get()); |
| 378 |
| 379 VerifyAndRunQueues(true, true); |
| 380 |
| 381 // The ack callback should have been called |
| 382 EXPECT_TRUE(test_callback->called()); |
| 383 EXPECT_TRUE(test_callback->result()); |
| 384 } |
| 385 |
| 386 // Tests that when the RenderWidgetInputHandler does not ack before a new event |
| 387 // arrives, that only the most recent ack is fired. |
| 388 TEST_F(CompositorMusConnectionTest, LostAck) { |
| 389 mus::TestWindow test_window; |
| 390 mus::mojom::EventPtr event1 = mus::mojom::Event::New(); |
| 391 GenerateKeyEvent(event1); |
| 392 scoped_refptr<TestCallback> test_callback1(new TestCallback); |
| 393 scoped_ptr<base::Callback<void(bool)>> ack_callback1( |
| 394 new base::Callback<void(bool)>( |
| 395 base::Bind(&::TestCallback::BoolCallback, test_callback1))); |
| 396 |
| 397 OnWindowInputEvent(&test_window, std::move(event1), &ack_callback1); |
| 398 EXPECT_FALSE(ack_callback1.get()); |
| 399 // When simulating the timeout the ack is never enqueued |
| 400 VerifyAndRunQueues(true, false); |
| 401 |
| 402 // Setting a delegate will lead to the next event being acked. Having a |
| 403 // cleared queue simulates the input handler timing out on an event. |
| 404 TestRenderWidgetInputHandler* input_handler = render_widget_input_handler(); |
| 405 input_handler->set_delegate(connection()); |
| 406 input_handler->set_state(InputEventAckState::INPUT_EVENT_ACK_STATE_CONSUMED); |
| 407 |
| 408 mus::mojom::EventPtr event2 = mus::mojom::Event::New(); |
| 409 GenerateKeyEvent(event2); |
| 410 scoped_refptr<TestCallback> test_callback2(new TestCallback); |
| 411 scoped_ptr<base::Callback<void(bool)>> ack_callback2( |
| 412 new base::Callback<void(bool)>( |
| 413 base::Bind(&::TestCallback::BoolCallback, test_callback2))); |
| 414 OnWindowInputEvent(&test_window, std::move(event2), &ack_callback2); |
| 415 EXPECT_FALSE(ack_callback2.get()); |
| 416 |
| 417 VerifyAndRunQueues(true, true); |
| 418 |
| 419 // Only the most recent ack was called. |
| 420 EXPECT_FALSE(test_callback1->called()); |
| 421 EXPECT_TRUE(test_callback2->called()); |
| 422 EXPECT_TRUE(test_callback2->result()); |
| 423 } |
| 424 |
| 425 // Tests that when an input handler consumes the event, that |
| 426 // CompositorMusConnection does not consume the ack, nor calls it. |
| 427 TEST_F(CompositorMusConnectionTest, InputHandlerConsumes) { |
| 428 input_handler_manager()->SetHandleInputEventResult( |
| 429 InputEventAckState::INPUT_EVENT_ACK_STATE_CONSUMED); |
| 430 mus::TestWindow test_window; |
| 431 mus::mojom::EventPtr event = mus::mojom::Event::New(); |
| 432 GenerateKeyEvent(event); |
| 433 scoped_refptr<TestCallback> test_callback(new TestCallback); |
| 434 scoped_ptr<base::Callback<void(bool)>> ack_callback( |
| 435 new base::Callback<void(bool)>( |
| 436 base::Bind(&::TestCallback::BoolCallback, test_callback))); |
| 437 |
| 438 OnWindowInputEvent(&test_window, std::move(event), &ack_callback); |
| 439 |
| 440 EXPECT_TRUE(ack_callback.get()); |
| 441 VerifyAndRunQueues(false, false); |
| 442 EXPECT_FALSE(test_callback->called()); |
| 443 } |
| 444 |
| 445 // Tests that when the renderer will not ack an event, that |
| 446 // CompositorMusConnection does not consume the ack, nor calls it. |
| 447 TEST_F(CompositorMusConnectionTest, RendererWillNotSendAck) { |
| 448 mus::TestWindow test_window; |
| 449 mus::mojom::EventPtr event = mus::mojom::Event::New(); |
| 450 event->action = mus::mojom::EventType::POINTER_DOWN; |
| 451 event->time_stamp = base::TimeTicks::Now().ToInternalValue(); |
| 452 event->pointer_data = mus::mojom::PointerData::New(); |
| 453 |
| 454 scoped_refptr<TestCallback> test_callback(new TestCallback); |
| 455 scoped_ptr<base::Callback<void(bool)>> ack_callback( |
| 456 new base::Callback<void(bool)>( |
| 457 base::Bind(&::TestCallback::BoolCallback, test_callback))); |
| 458 |
| 459 OnWindowInputEvent(&test_window, std::move(event), &ack_callback); |
| 460 EXPECT_TRUE(ack_callback.get()); |
| 461 |
| 462 VerifyAndRunQueues(true, false); |
| 463 EXPECT_FALSE(test_callback->called()); |
| 464 } |
| 465 |
| 466 } // namespace content |
| OLD | NEW |