OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 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 "base/test/scoped_feature_list.h" | |
6 #include "content/browser/renderer_host/render_widget_host_impl.h" | |
7 #include "content/browser/renderer_host/render_widget_host_input_event_router.h" | |
8 #include "content/browser/web_contents/web_contents_impl.h" | |
9 #include "content/common/input/synthetic_web_input_event_builders.h" | |
10 #include "content/public/common/content_features.h" | |
11 #include "content/public/test/browser_test_utils.h" | |
12 #include "content/public/test/content_browser_test.h" | |
13 #include "content/public/test/content_browser_test_utils.h" | |
14 #include "content/shell/browser/shell.h" | |
15 #include "ui/events/gesture_detection/gesture_configuration.h" | |
16 | |
17 #if defined(OS_ANDROID) | |
18 #include "content/browser/renderer_host/render_widget_host_view_android.h" | |
19 #endif | |
20 | |
21 using blink::WebMouseWheelEvent; | |
22 | |
23 namespace { | |
24 void GiveItSomeTime() { | |
25 base::RunLoop run_loop; | |
26 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
27 FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromMilliseconds(10)); | |
28 run_loop.Run(); | |
29 } | |
30 | |
31 const char kWheelEventLatchingDataURL[] = | |
32 "data:text/html;charset=utf-8," | |
33 "<!DOCTYPE html>" | |
34 "<style>" | |
35 "body { height: 10000px;" | |
tdresser
2017/06/09 18:13:11
This brace style is atypical - we'd normally put t
sahel
2017/06/13 15:43:20
Done.
| |
36 "}" | |
37 "#scrollableDiv { position: absolute;" | |
38 " left: 100px;" | |
39 " top: 200px;" | |
40 " width: 400px;" | |
41 " height: 800px;" | |
42 " overflow: scroll;" | |
43 " background: red;" | |
44 "}" | |
45 "#nestedDiv { width: 400px;" | |
46 " height: 8000px;" | |
47 " opacity: 0;" | |
48 "}" | |
49 "</style>" | |
50 "<div id='scrollableDiv'>" | |
51 " <div id='nestedDiv'></div>" | |
52 "</div>" | |
53 "<script>" | |
54 " var scrollableDiv = document.getElementById('scrollableDiv');" | |
55 " var scrollableDivWheelEventCounter = 0;" | |
56 " var documentWheelEventCounter = 0;" | |
57 " scrollableDiv.addEventListener('wheel'," | |
58 " function(e) { scrollableDivWheelEventCounter++;" | |
59 " e.stopPropagation(); });" | |
60 " document.scrollingElement.addEventListener('wheel'," | |
61 " function(e) { documentWheelEventCounter++; });" | |
62 "</script>"; | |
63 } // namespace | |
64 | |
65 namespace content { | |
66 class WheelScrollLatchingBrowserTest : public ContentBrowserTest { | |
67 public: | |
68 WheelScrollLatchingBrowserTest(bool wheel_scroll_latching_enabled = true) | |
69 : wheel_scroll_latching_enabled_(wheel_scroll_latching_enabled) { | |
70 ui::GestureConfiguration::GetInstance()->set_scroll_debounce_interval_in_ms( | |
71 0); | |
72 | |
73 if (wheel_scroll_latching_enabled_) | |
74 EnableWheelScrollLatching(); | |
75 else | |
76 DisableWheelScrollLatching(); | |
77 } | |
78 ~WheelScrollLatchingBrowserTest() override {} | |
79 | |
80 protected: | |
81 RenderWidgetHostImpl* GetWidgetHost() { | |
82 return RenderWidgetHostImpl::From( | |
83 web_contents()->GetRenderViewHost()->GetWidget()); | |
84 } | |
85 | |
86 WebContentsImpl* web_contents() const { | |
87 return static_cast<WebContentsImpl*>(shell()->web_contents()); | |
88 } | |
89 | |
90 RenderWidgetHostInputEventRouter* GetRouter() { | |
91 return web_contents()->GetInputEventRouter(); | |
92 } | |
93 | |
94 RenderWidgetHostViewBase* GetRootView() { | |
95 return static_cast<RenderWidgetHostViewBase*>(web_contents() | |
96 ->GetFrameTree() | |
97 ->root() | |
98 ->current_frame_host() | |
99 ->GetView()); | |
100 } | |
101 | |
102 float GetPageScaleFactor() { | |
103 return GetWidgetHost()->last_frame_metadata().page_scale_factor; | |
104 } | |
105 | |
106 void LoadURL() { | |
107 const GURL data_url(kWheelEventLatchingDataURL); | |
108 NavigateToURL(shell(), data_url); | |
109 | |
110 RenderWidgetHostImpl* host = GetWidgetHost(); | |
111 host->GetView()->SetSize(gfx::Size(600, 600)); | |
112 | |
113 // The page is loaded in the renderer, wait for a new frame to arrive. | |
114 while (!host->ScheduleComposite()) | |
115 GiveItSomeTime(); | |
116 } | |
117 int ExecuteScriptAndExtractInt(const std::string& script) { | |
118 int value = 0; | |
119 EXPECT_TRUE(content::ExecuteScriptAndExtractInt( | |
120 shell(), "domAutomationController.send(" + script + ")", &value)); | |
121 return value; | |
122 } | |
123 void EnableWheelScrollLatching() { | |
124 feature_list_.InitFromCommandLine( | |
125 features::kTouchpadAndWheelScrollLatching.name, ""); | |
126 } | |
127 void DisableWheelScrollLatching() { | |
128 feature_list_.InitFromCommandLine( | |
129 "", features::kTouchpadAndWheelScrollLatching.name); | |
130 } | |
131 | |
132 void WheelEventTargetTest() { | |
133 LoadURL(); | |
134 EXPECT_EQ(0, ExecuteScriptAndExtractInt("documentWheelEventCounter")); | |
135 EXPECT_EQ(0, ExecuteScriptAndExtractInt("scrollableDivWheelEventCounter")); | |
136 | |
137 FrameWatcher frame_watcher(shell()->web_contents()); | |
138 scoped_refptr<InputMsgWatcher> input_msg_watcher(new InputMsgWatcher( | |
139 GetWidgetHost(), blink::WebInputEvent::kMouseWheel)); | |
140 float scale_factor = GetPageScaleFactor(); | |
141 | |
142 float scrollable_div_top = | |
143 ExecuteScriptAndExtractInt("scrollableDiv.getBoundingClientRect().top"); | |
144 float x = scale_factor * | |
145 (ExecuteScriptAndExtractInt( | |
146 "scrollableDiv.getBoundingClientRect().left") + | |
147 ExecuteScriptAndExtractInt( | |
148 "scrollableDiv.getBoundingClientRect().right")) / | |
149 2; | |
150 float y = scale_factor * 0.5 * scrollable_div_top; | |
151 float delta_x = 0; | |
152 float delta_y = -0.5 * scrollable_div_top; | |
153 blink::WebMouseWheelEvent wheel_event = | |
154 SyntheticWebMouseWheelEventBuilder::Build(x, y, x, y, delta_x, delta_y, | |
155 0, true); | |
156 if (wheel_scroll_latching_enabled_) | |
157 wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan; | |
158 GetRouter()->RouteMouseWheelEvent(GetRootView(), &wheel_event, | |
159 ui::LatencyInfo()); | |
160 | |
161 // Runs until we get the InputMsgAck callback | |
tdresser
2017/06/09 18:13:11
Trailing .
sahel
2017/06/13 15:43:20
Done.
| |
162 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, | |
163 input_msg_watcher->WaitForAck()); | |
164 | |
165 while (ExecuteScriptAndExtractInt("document.scrollingElement.scrollTop") < | |
166 -delta_y) | |
167 frame_watcher.WaitFrames(1); | |
168 | |
169 EXPECT_EQ(0, ExecuteScriptAndExtractInt("scrollableDiv.scrollTop")); | |
170 EXPECT_EQ(1, ExecuteScriptAndExtractInt("documentWheelEventCounter")); | |
171 EXPECT_EQ(0, ExecuteScriptAndExtractInt("scrollableDivWheelEventCounter")); | |
172 | |
173 if (wheel_scroll_latching_enabled_) | |
174 wheel_event.phase = blink::WebMouseWheelEvent::kPhaseChanged; | |
175 GetRouter()->RouteMouseWheelEvent(GetRootView(), &wheel_event, | |
176 ui::LatencyInfo()); | |
177 | |
178 // Runs until we get the InputMsgAck callback | |
tdresser
2017/06/09 18:13:11
Trailing .
sahel
2017/06/13 15:43:20
Done.
| |
179 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, | |
180 input_msg_watcher->WaitForAck()); | |
181 | |
182 if (wheel_scroll_latching_enabled_) { | |
183 while (frame_watcher.LastMetadata().root_scroll_offset.y() < -2 * delta_y) | |
184 frame_watcher.WaitFrames(1); | |
185 | |
186 EXPECT_EQ(0, ExecuteScriptAndExtractInt("scrollableDiv.scrollTop")); | |
187 EXPECT_EQ(2, ExecuteScriptAndExtractInt("documentWheelEventCounter")); | |
188 EXPECT_EQ(0, | |
189 ExecuteScriptAndExtractInt("scrollableDivWheelEventCounter")); | |
190 } else { | |
191 while (ExecuteScriptAndExtractInt("scrollableDiv.scrollTop") < -delta_y) | |
192 frame_watcher.WaitFrames(1); | |
193 | |
194 EXPECT_EQ(1, ExecuteScriptAndExtractInt("documentWheelEventCounter")); | |
195 EXPECT_EQ(1, | |
196 ExecuteScriptAndExtractInt("scrollableDivWheelEventCounter")); | |
197 } | |
198 } | |
199 | |
200 private: | |
201 base::test::ScopedFeatureList feature_list_; | |
202 bool wheel_scroll_latching_enabled_; | |
203 }; | |
204 | |
205 class WheelScrollLatchingDisabledBrowserTest | |
206 : public WheelScrollLatchingBrowserTest { | |
207 public: | |
208 WheelScrollLatchingDisabledBrowserTest() | |
209 : WheelScrollLatchingBrowserTest(false) {} | |
210 ~WheelScrollLatchingDisabledBrowserTest() override {} | |
211 }; | |
212 | |
213 // Start scrolling by mouse wheel on the document: the wheel event will be sent | |
214 // to the document's scrolling element, the scrollable div will be under the | |
215 // cursor after applying the scrolling. Continue scrolling by mouse wheel, since | |
216 // wheel scroll latching is enabled the wheel event will be still sent to the | |
217 // document's scrolling element and the document's scrolling element will | |
218 // continue scrolling. | |
219 IN_PROC_BROWSER_TEST_F(WheelScrollLatchingBrowserTest, WheelEventTarget) { | |
220 WheelEventTargetTest(); | |
221 } | |
222 | |
223 // Start scrolling by mouse wheel on the document: the wheel event will be sent | |
224 // to the document's scrolling element, the scrollable div will be under the | |
225 // cursor after applying the scrolloffsets. Continue scrolling by mouse wheel, | |
226 // since wheel scroll latching is disabled the wheel event will be still sent to | |
227 // the scrollable div which is currently under the cursor. The div will start | |
228 // scrolling. | |
229 IN_PROC_BROWSER_TEST_F(WheelScrollLatchingDisabledBrowserTest, | |
230 WheelEventTarget) { | |
231 WheelEventTargetTest(); | |
232 } | |
233 | |
234 } // namespace content | |
OLD | NEW |