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