1 // Copyright 2018 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/web_contents/web_contents_impl.h"
7 #include "content/public/common/content_features.h"
8 #include "content/public/test/browser_test.h"
9 #include "content/public/test/browser_test_utils.h"
10 #include "content/public/test/content_browser_test.h"
11 #include "content/public/test/content_browser_test_utils.h"
12 #include "content/shell/browser/shell.h"
13 #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h"
14 #include "third_party/blink/public/common/input/web_input_event.h"
15
16 using blink::WebInputEvent;
17
18 namespace {
19
20 const std::string kWheelEventListenerDataURL = R"HTML(
21 <!DOCTYPE html>
22 <meta name='viewport' content='width=device-width'/>
23 <style>
24 html, body {
25 margin: 0;
26 }
27 .spacer { height: 10000px; }
28 </style>
29 <div class=spacer></div>
30 <script>
31 window.addEventListener('wheel', () => { while (true); });
32 document.title='ready';
33 </script>)HTML";
34
35 const std::string kMouseWheelEventListenerDataURL = R"HTML(
36 <!DOCTYPE html>
37 <meta name='viewport' content='width=device-width'/>
38 <style>
39 html, body {
40 margin: 0;
41 }
42 .spacer { height: 10000px; }
43 </style>
44 <div class=spacer></div>
45 <script>
46 document.addEventListener('mousewheel', () => { while (true); });
47 document.title='ready';
48 </script>)HTML";
49 } // namespace
50
51 namespace content {
52
53 class WheelEventListenerBrowserTest : public ContentBrowserTest {
54 public:
55 WheelEventListenerBrowserTest() = default;
56 ~WheelEventListenerBrowserTest() override = default;
57
58 protected:
GetWidgetHost()59 RenderWidgetHostImpl* GetWidgetHost() {
60 return RenderWidgetHostImpl::From(
61 shell()->web_contents()->GetRenderViewHost()->GetWidget());
62 }
63
LoadURL(const std::string & page_data)64 void LoadURL(const std::string& page_data) {
65 const GURL data_url("data:text/html," + page_data);
66 EXPECT_TRUE(NavigateToURL(shell(), data_url));
67
68 RenderWidgetHostImpl* host = GetWidgetHost();
69 host->GetView()->SetSize(gfx::Size(400, 400));
70
71 base::string16 ready_title(base::ASCIIToUTF16("ready"));
72 TitleWatcher watcher(shell()->web_contents(), ready_title);
73 ignore_result(watcher.WaitAndGetTitle());
74
75 MainThreadFrameObserver main_thread_sync(host);
76 main_thread_sync.Wait();
77 }
78
ScrollByMouseWheel()79 void ScrollByMouseWheel() {
80 // Send a wheel event and wait for its ack.
81 auto wheel_msg_watcher = std::make_unique<InputMsgWatcher>(
82 GetWidgetHost(), blink::WebInputEvent::Type::kMouseWheel);
83 double x = 10;
84 double y = 10;
85 blink::WebMouseWheelEvent wheel_event =
86 blink::SyntheticWebMouseWheelEventBuilder::Build(
87 x, y, x, y, -20, -20, 0,
88 ui::ScrollGranularity::kScrollByPrecisePixel);
89 wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
90 GetWidgetHost()->ForwardWheelEvent(wheel_event);
91 EXPECT_EQ(blink::mojom::InputEventResultState::kSetNonBlocking,
92 wheel_msg_watcher->WaitForAck());
93 }
94
WaitForScroll()95 void WaitForScroll() {
96 RenderFrameSubmissionObserver observer(
97 GetWidgetHost()->render_frame_metadata_provider());
98 gfx::Vector2dF default_scroll_offset;
99 while (observer.LastRenderFrameMetadata()
100 .root_scroll_offset.value_or(default_scroll_offset)
101 .y() <= 0) {
102 observer.WaitForMetadataChange();
103 }
104 }
105
106 private:
107 base::test::ScopedFeatureList feature_list_;
108 DISALLOW_COPY_AND_ASSIGN(WheelEventListenerBrowserTest);
109 };
110
IN_PROC_BROWSER_TEST_F(WheelEventListenerBrowserTest,DocumentWheelEventListenersPassiveByDefault)111 IN_PROC_BROWSER_TEST_F(WheelEventListenerBrowserTest,
112 DocumentWheelEventListenersPassiveByDefault) {
113 LoadURL(kWheelEventListenerDataURL);
114
115 // Send a wheel event and wait for its ack.
116 ScrollByMouseWheel();
117
118 // Wait for the page to scroll, the test will timeout if the wheel event
119 // listener added to window is not treated as passive.
120 WaitForScroll();
121 }
122
IN_PROC_BROWSER_TEST_F(WheelEventListenerBrowserTest,DocumentMouseWheelEventListenersPassiveByDefault)123 IN_PROC_BROWSER_TEST_F(WheelEventListenerBrowserTest,
124 DocumentMouseWheelEventListenersPassiveByDefault) {
125 LoadURL(kMouseWheelEventListenerDataURL);
126
127 // Send a wheel event and wait for its ack.
128 ScrollByMouseWheel();
129
130 // Wait for the page to scroll, the test will timeout if the mousewheel event
131 // listener added to document is not treated as passive.
132 WaitForScroll();
133 }
134
135 } // namespace content
136