OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/render_widget.h" | 5 #include "content/renderer/render_widget.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/macros.h" | 9 #include "base/macros.h" |
| 10 #include "base/test/histogram_tester.h" |
10 #include "content/common/input/synthetic_web_input_event_builders.h" | 11 #include "content/common/input/synthetic_web_input_event_builders.h" |
11 #include "content/common/input/web_input_event_traits.h" | 12 #include "content/common/input/web_input_event_traits.h" |
12 #include "content/common/input_messages.h" | 13 #include "content/common/input_messages.h" |
13 #include "content/public/test/mock_render_thread.h" | 14 #include "content/public/test/mock_render_thread.h" |
14 #include "content/test/fake_compositor_dependencies.h" | 15 #include "content/test/fake_compositor_dependencies.h" |
15 #include "content/test/mock_render_process.h" | 16 #include "content/test/mock_render_process.h" |
16 #include "ipc/ipc_test_sink.h" | 17 #include "ipc/ipc_test_sink.h" |
| 18 #include "testing/gmock/include/gmock/gmock.h" |
17 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
18 #include "third_party/WebKit/public/web/WebInputEvent.h" | 20 #include "third_party/WebKit/public/web/WebInputEvent.h" |
19 #include "ui/gfx/geometry/rect.h" | 21 #include "ui/gfx/geometry/rect.h" |
20 | 22 |
| 23 using testing::_; |
| 24 |
21 namespace content { | 25 namespace content { |
22 | 26 |
| 27 namespace { |
| 28 |
| 29 const char* EVENT_LISTENER_RESULT_HISTOGRAM = "Event.PassiveListeners"; |
| 30 |
| 31 enum { |
| 32 PASSIVE_LISTENER_UMA_ENUM_PASSIVE, |
| 33 PASSIVE_LISTENER_UMA_ENUM_UNCANCELABLE, |
| 34 PASSIVE_LISTENER_UMA_ENUM_SUPPRESSED, |
| 35 PASSIVE_LISTENER_UMA_ENUM_CANCELABLE, |
| 36 PASSIVE_LISTENER_UMA_ENUM_CANCELABLE_AND_CANCELED, |
| 37 PASSIVE_LISTENER_UMA_ENUM_FORCED_NON_BLOCKING, |
| 38 PASSIVE_LISTENER_UMA_ENUM_COUNT |
| 39 }; |
| 40 |
| 41 class MockWebWidget : public blink::WebWidget { |
| 42 public: |
| 43 MOCK_METHOD1(handleInputEvent, |
| 44 blink::WebInputEventResult(const blink::WebInputEvent&)); |
| 45 }; |
| 46 |
| 47 } // namespace |
| 48 |
23 class InteractiveRenderWidget : public RenderWidget { | 49 class InteractiveRenderWidget : public RenderWidget { |
24 public: | 50 public: |
25 explicit InteractiveRenderWidget(CompositorDependencies* compositor_deps) | 51 explicit InteractiveRenderWidget(CompositorDependencies* compositor_deps) |
26 : RenderWidget(compositor_deps, | 52 : RenderWidget(compositor_deps, |
27 blink::WebPopupTypeNone, | 53 blink::WebPopupTypeNone, |
28 blink::WebScreenInfo(), | 54 blink::WebScreenInfo(), |
29 false, | 55 false, |
30 false, | 56 false, |
31 false), | 57 false), |
32 always_overscroll_(false) { | 58 always_overscroll_(false) { |
| 59 webwidget_ = &mock_webwidget_; |
33 // A RenderWidget is not fully initialized until it has a routing ID. | 60 // A RenderWidget is not fully initialized until it has a routing ID. |
34 SetRoutingID(++next_routing_id_); | 61 SetRoutingID(++next_routing_id_); |
35 } | 62 } |
36 | 63 |
37 void SetTouchRegion(const std::vector<gfx::Rect>& rects) { | 64 void SetTouchRegion(const std::vector<gfx::Rect>& rects) { |
38 rects_ = rects; | 65 rects_ = rects; |
39 } | 66 } |
40 | 67 |
41 void SendInputEvent(const blink::WebInputEvent& event) { | 68 void SendInputEvent(const blink::WebInputEvent& event) { |
42 OnHandleInputEvent( | 69 OnHandleInputEvent( |
43 &event, ui::LatencyInfo(), | 70 &event, ui::LatencyInfo(), |
44 WebInputEventTraits::ShouldBlockEventStream(event) | 71 WebInputEventTraits::ShouldBlockEventStream(event) |
45 ? InputEventDispatchType::DISPATCH_TYPE_BLOCKING | 72 ? InputEventDispatchType::DISPATCH_TYPE_BLOCKING |
46 : InputEventDispatchType::DISPATCH_TYPE_NON_BLOCKING); | 73 : InputEventDispatchType::DISPATCH_TYPE_NON_BLOCKING); |
47 } | 74 } |
48 | 75 |
49 void set_always_overscroll(bool overscroll) { | 76 void set_always_overscroll(bool overscroll) { |
50 always_overscroll_ = overscroll; | 77 always_overscroll_ = overscroll; |
51 } | 78 } |
52 | 79 |
53 IPC::TestSink* sink() { return &sink_; } | 80 IPC::TestSink* sink() { return &sink_; } |
54 | 81 |
| 82 MockWebWidget* mock_webwidget() { return &mock_webwidget_; } |
| 83 |
55 protected: | 84 protected: |
56 ~InteractiveRenderWidget() override {} | 85 ~InteractiveRenderWidget() override { webwidget_ = nullptr; } |
57 | 86 |
58 // Overridden from RenderWidget: | 87 // Overridden from RenderWidget: |
59 bool HasTouchEventHandlersAt(const gfx::Point& point) const override { | 88 bool HasTouchEventHandlersAt(const gfx::Point& point) const override { |
60 for (std::vector<gfx::Rect>::const_iterator iter = rects_.begin(); | 89 for (std::vector<gfx::Rect>::const_iterator iter = rects_.begin(); |
61 iter != rects_.end(); ++iter) { | 90 iter != rects_.end(); ++iter) { |
62 if ((*iter).Contains(point)) | 91 if ((*iter).Contains(point)) |
63 return true; | 92 return true; |
64 } | 93 } |
65 return false; | 94 return false; |
66 } | 95 } |
(...skipping 17 matching lines...) Expand all Loading... |
84 bool Send(IPC::Message* msg) override { | 113 bool Send(IPC::Message* msg) override { |
85 sink_.OnMessageReceived(*msg); | 114 sink_.OnMessageReceived(*msg); |
86 delete msg; | 115 delete msg; |
87 return true; | 116 return true; |
88 } | 117 } |
89 | 118 |
90 private: | 119 private: |
91 std::vector<gfx::Rect> rects_; | 120 std::vector<gfx::Rect> rects_; |
92 IPC::TestSink sink_; | 121 IPC::TestSink sink_; |
93 bool always_overscroll_; | 122 bool always_overscroll_; |
| 123 MockWebWidget mock_webwidget_; |
94 static int next_routing_id_; | 124 static int next_routing_id_; |
95 | 125 |
96 DISALLOW_COPY_AND_ASSIGN(InteractiveRenderWidget); | 126 DISALLOW_COPY_AND_ASSIGN(InteractiveRenderWidget); |
97 }; | 127 }; |
98 | 128 |
99 int InteractiveRenderWidget::next_routing_id_ = 0; | 129 int InteractiveRenderWidget::next_routing_id_ = 0; |
100 | 130 |
101 class RenderWidgetUnittest : public testing::Test { | 131 class RenderWidgetUnittest : public testing::Test { |
102 public: | 132 public: |
103 RenderWidgetUnittest() | 133 RenderWidgetUnittest() |
104 : widget_(new InteractiveRenderWidget(&compositor_deps_)) {} | 134 : widget_(new InteractiveRenderWidget(&compositor_deps_)) {} |
105 ~RenderWidgetUnittest() override {} | 135 ~RenderWidgetUnittest() override {} |
106 | 136 |
107 InteractiveRenderWidget* widget() const { return widget_.get(); } | 137 InteractiveRenderWidget* widget() const { return widget_.get(); } |
108 | 138 |
| 139 const base::HistogramTester& histogram_tester() const { |
| 140 return histogram_tester_; |
| 141 } |
| 142 |
109 private: | 143 private: |
110 MockRenderProcess render_process_; | 144 MockRenderProcess render_process_; |
111 MockRenderThread render_thread_; | 145 MockRenderThread render_thread_; |
112 FakeCompositorDependencies compositor_deps_; | 146 FakeCompositorDependencies compositor_deps_; |
113 scoped_refptr<InteractiveRenderWidget> widget_; | 147 scoped_refptr<InteractiveRenderWidget> widget_; |
| 148 base::HistogramTester histogram_tester_; |
114 | 149 |
115 DISALLOW_COPY_AND_ASSIGN(RenderWidgetUnittest); | 150 DISALLOW_COPY_AND_ASSIGN(RenderWidgetUnittest); |
116 }; | 151 }; |
117 | 152 |
118 TEST_F(RenderWidgetUnittest, TouchHitTestSinglePoint) { | 153 TEST_F(RenderWidgetUnittest, TouchHitTestSinglePoint) { |
119 SyntheticWebTouchEvent touch; | 154 SyntheticWebTouchEvent touch; |
120 touch.PressPoint(10, 10); | 155 touch.PressPoint(10, 10); |
121 | 156 |
| 157 EXPECT_CALL(*widget()->mock_webwidget(), handleInputEvent(_)) |
| 158 .WillRepeatedly( |
| 159 ::testing::Return(blink::WebInputEventResult::NotHandled)); |
| 160 |
122 widget()->SendInputEvent(touch); | 161 widget()->SendInputEvent(touch); |
123 ASSERT_EQ(1u, widget()->sink()->message_count()); | 162 ASSERT_EQ(1u, widget()->sink()->message_count()); |
124 | 163 |
125 // Since there's currently no touch-event handling region, the response should | 164 // Since there's currently no touch-event handling region, the response should |
126 // be 'no consumer exists'. | 165 // be 'no consumer exists'. |
127 const IPC::Message* message = widget()->sink()->GetMessageAt(0); | 166 const IPC::Message* message = widget()->sink()->GetMessageAt(0); |
128 EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type()); | 167 EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type()); |
129 InputHostMsg_HandleInputEvent_ACK::Param params; | 168 InputHostMsg_HandleInputEvent_ACK::Param params; |
130 InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms); | 169 InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms); |
131 InputEventAckState ack_state = base::get<0>(params).state; | 170 InputEventAckState ack_state = base::get<0>(params).state; |
132 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, ack_state); | 171 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, ack_state); |
133 widget()->sink()->ClearMessages(); | 172 widget()->sink()->ClearMessages(); |
134 | 173 |
135 std::vector<gfx::Rect> rects; | 174 std::vector<gfx::Rect> rects; |
136 rects.push_back(gfx::Rect(0, 0, 20, 20)); | 175 rects.push_back(gfx::Rect(0, 0, 20, 20)); |
137 rects.push_back(gfx::Rect(25, 0, 10, 10)); | 176 rects.push_back(gfx::Rect(25, 0, 10, 10)); |
138 widget()->SetTouchRegion(rects); | 177 widget()->SetTouchRegion(rects); |
139 | 178 |
| 179 EXPECT_CALL(*widget()->mock_webwidget(), handleInputEvent(_)) |
| 180 .WillRepeatedly( |
| 181 ::testing::Return(blink::WebInputEventResult::NotHandled)); |
| 182 |
140 widget()->SendInputEvent(touch); | 183 widget()->SendInputEvent(touch); |
141 ASSERT_EQ(1u, widget()->sink()->message_count()); | 184 ASSERT_EQ(1u, widget()->sink()->message_count()); |
142 message = widget()->sink()->GetMessageAt(0); | 185 message = widget()->sink()->GetMessageAt(0); |
143 EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type()); | 186 EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type()); |
144 InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms); | 187 InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms); |
145 ack_state = base::get<0>(params).state; | 188 ack_state = base::get<0>(params).state; |
146 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, ack_state); | 189 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, ack_state); |
147 widget()->sink()->ClearMessages(); | 190 widget()->sink()->ClearMessages(); |
148 } | 191 } |
149 | 192 |
150 TEST_F(RenderWidgetUnittest, TouchHitTestMultiplePoints) { | 193 TEST_F(RenderWidgetUnittest, TouchHitTestMultiplePoints) { |
151 std::vector<gfx::Rect> rects; | 194 std::vector<gfx::Rect> rects; |
152 rects.push_back(gfx::Rect(0, 0, 20, 20)); | 195 rects.push_back(gfx::Rect(0, 0, 20, 20)); |
153 rects.push_back(gfx::Rect(25, 0, 10, 10)); | 196 rects.push_back(gfx::Rect(25, 0, 10, 10)); |
154 widget()->SetTouchRegion(rects); | 197 widget()->SetTouchRegion(rects); |
155 | 198 |
156 SyntheticWebTouchEvent touch; | 199 SyntheticWebTouchEvent touch; |
157 touch.PressPoint(25, 25); | 200 touch.PressPoint(25, 25); |
158 | 201 |
| 202 EXPECT_CALL(*widget()->mock_webwidget(), handleInputEvent(_)) |
| 203 .WillRepeatedly( |
| 204 ::testing::Return(blink::WebInputEventResult::NotHandled)); |
| 205 |
159 widget()->SendInputEvent(touch); | 206 widget()->SendInputEvent(touch); |
160 ASSERT_EQ(1u, widget()->sink()->message_count()); | 207 ASSERT_EQ(1u, widget()->sink()->message_count()); |
161 | 208 |
162 // Since there's currently no touch-event handling region, the response should | 209 // Since there's currently no touch-event handling region, the response should |
163 // be 'no consumer exists'. | 210 // be 'no consumer exists'. |
164 const IPC::Message* message = widget()->sink()->GetMessageAt(0); | 211 const IPC::Message* message = widget()->sink()->GetMessageAt(0); |
165 EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type()); | 212 EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type()); |
166 InputHostMsg_HandleInputEvent_ACK::Param params; | 213 InputHostMsg_HandleInputEvent_ACK::Param params; |
167 InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms); | 214 InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms); |
168 InputEventAckState ack_state = base::get<0>(params).state; | 215 InputEventAckState ack_state = base::get<0>(params).state; |
169 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, ack_state); | 216 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, ack_state); |
170 widget()->sink()->ClearMessages(); | 217 widget()->sink()->ClearMessages(); |
171 | 218 |
172 // Press a second touch point. This time, on a touch-handling region. | 219 // Press a second touch point. This time, on a touch-handling region. |
173 touch.PressPoint(10, 10); | 220 touch.PressPoint(10, 10); |
174 widget()->SendInputEvent(touch); | 221 widget()->SendInputEvent(touch); |
175 ASSERT_EQ(1u, widget()->sink()->message_count()); | 222 ASSERT_EQ(1u, widget()->sink()->message_count()); |
176 message = widget()->sink()->GetMessageAt(0); | 223 message = widget()->sink()->GetMessageAt(0); |
177 EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type()); | 224 EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type()); |
178 InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms); | 225 InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms); |
179 ack_state = base::get<0>(params).state; | 226 ack_state = base::get<0>(params).state; |
180 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, ack_state); | 227 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, ack_state); |
181 widget()->sink()->ClearMessages(); | 228 widget()->sink()->ClearMessages(); |
182 } | 229 } |
183 | 230 |
184 TEST_F(RenderWidgetUnittest, EventOverscroll) { | 231 TEST_F(RenderWidgetUnittest, EventOverscroll) { |
185 widget()->set_always_overscroll(true); | 232 widget()->set_always_overscroll(true); |
186 | 233 |
| 234 EXPECT_CALL(*widget()->mock_webwidget(), handleInputEvent(_)) |
| 235 .WillRepeatedly( |
| 236 ::testing::Return(blink::WebInputEventResult::NotHandled)); |
| 237 |
187 blink::WebGestureEvent scroll; | 238 blink::WebGestureEvent scroll; |
188 scroll.type = blink::WebInputEvent::GestureScrollUpdate; | 239 scroll.type = blink::WebInputEvent::GestureScrollUpdate; |
189 scroll.x = -10; | 240 scroll.x = -10; |
190 scroll.data.scrollUpdate.deltaY = 10; | 241 scroll.data.scrollUpdate.deltaY = 10; |
191 widget()->SendInputEvent(scroll); | 242 widget()->SendInputEvent(scroll); |
192 | 243 |
193 // Overscroll notifications received while handling an input event should | 244 // Overscroll notifications received while handling an input event should |
194 // be bundled with the event ack IPC. | 245 // be bundled with the event ack IPC. |
195 ASSERT_EQ(1u, widget()->sink()->message_count()); | 246 ASSERT_EQ(1u, widget()->sink()->message_count()); |
196 const IPC::Message* message = widget()->sink()->GetMessageAt(0); | 247 const IPC::Message* message = widget()->sink()->GetMessageAt(0); |
(...skipping 22 matching lines...) Expand all Loading... |
219 InputHostMsg_DidOverscroll::Param params; | 270 InputHostMsg_DidOverscroll::Param params; |
220 InputHostMsg_DidOverscroll::Read(message, ¶ms); | 271 InputHostMsg_DidOverscroll::Read(message, ¶ms); |
221 const DidOverscrollParams& overscroll = base::get<0>(params); | 272 const DidOverscrollParams& overscroll = base::get<0>(params); |
222 EXPECT_EQ(gfx::Vector2dF(10, 5), overscroll.latest_overscroll_delta); | 273 EXPECT_EQ(gfx::Vector2dF(10, 5), overscroll.latest_overscroll_delta); |
223 EXPECT_EQ(gfx::Vector2dF(5, 5), overscroll.accumulated_overscroll); | 274 EXPECT_EQ(gfx::Vector2dF(5, 5), overscroll.accumulated_overscroll); |
224 EXPECT_EQ(gfx::PointF(1, 1), overscroll.causal_event_viewport_point); | 275 EXPECT_EQ(gfx::PointF(1, 1), overscroll.causal_event_viewport_point); |
225 EXPECT_EQ(gfx::Vector2dF(-10, -5), overscroll.current_fling_velocity); | 276 EXPECT_EQ(gfx::Vector2dF(-10, -5), overscroll.current_fling_velocity); |
226 widget()->sink()->ClearMessages(); | 277 widget()->sink()->ClearMessages(); |
227 } | 278 } |
228 | 279 |
| 280 TEST_F(RenderWidgetUnittest, RenderWidgetInputEventUmaMetrics) { |
| 281 SyntheticWebTouchEvent touch; |
| 282 touch.PressPoint(10, 10); |
| 283 |
| 284 EXPECT_CALL(*widget()->mock_webwidget(), handleInputEvent(_)) |
| 285 .Times(4) |
| 286 .WillRepeatedly( |
| 287 ::testing::Return(blink::WebInputEventResult::NotHandled)); |
| 288 |
| 289 widget()->SendInputEvent(touch); |
| 290 histogram_tester().ExpectBucketCount(EVENT_LISTENER_RESULT_HISTOGRAM, |
| 291 PASSIVE_LISTENER_UMA_ENUM_CANCELABLE, 1); |
| 292 |
| 293 touch.dispatchType = blink::WebInputEvent::DispatchType::EventNonBlocking; |
| 294 widget()->SendInputEvent(touch); |
| 295 histogram_tester().ExpectBucketCount(EVENT_LISTENER_RESULT_HISTOGRAM, |
| 296 PASSIVE_LISTENER_UMA_ENUM_UNCANCELABLE, |
| 297 1); |
| 298 |
| 299 touch.dispatchType = |
| 300 blink::WebInputEvent::DispatchType::ListenersNonBlockingPassive; |
| 301 widget()->SendInputEvent(touch); |
| 302 histogram_tester().ExpectBucketCount(EVENT_LISTENER_RESULT_HISTOGRAM, |
| 303 PASSIVE_LISTENER_UMA_ENUM_PASSIVE, 1); |
| 304 |
| 305 touch.dispatchType = |
| 306 blink::WebInputEvent::DispatchType::ListenersForcedNonBlockingPassive; |
| 307 widget()->SendInputEvent(touch); |
| 308 histogram_tester().ExpectBucketCount( |
| 309 EVENT_LISTENER_RESULT_HISTOGRAM, |
| 310 PASSIVE_LISTENER_UMA_ENUM_FORCED_NON_BLOCKING, 1); |
| 311 |
| 312 EXPECT_CALL(*widget()->mock_webwidget(), handleInputEvent(_)) |
| 313 .WillOnce( |
| 314 ::testing::Return(blink::WebInputEventResult::HandledSuppressed)); |
| 315 touch.dispatchType = blink::WebInputEvent::DispatchType::Blocking; |
| 316 widget()->SendInputEvent(touch); |
| 317 histogram_tester().ExpectBucketCount(EVENT_LISTENER_RESULT_HISTOGRAM, |
| 318 PASSIVE_LISTENER_UMA_ENUM_SUPPRESSED, 1); |
| 319 |
| 320 EXPECT_CALL(*widget()->mock_webwidget(), handleInputEvent(_)) |
| 321 .WillOnce( |
| 322 ::testing::Return(blink::WebInputEventResult::HandledApplication)); |
| 323 touch.dispatchType = blink::WebInputEvent::DispatchType::Blocking; |
| 324 widget()->SendInputEvent(touch); |
| 325 histogram_tester().ExpectBucketCount( |
| 326 EVENT_LISTENER_RESULT_HISTOGRAM, |
| 327 PASSIVE_LISTENER_UMA_ENUM_CANCELABLE_AND_CANCELED, 1); |
| 328 } |
| 329 |
229 } // namespace content | 330 } // namespace content |
OLD | NEW |