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