1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "third_party/blink/renderer/core/page/chrome_client_impl.h"
32 #include "base/run_loop.h"
33 #include "cc/trees/layer_tree_host.h"
34 #include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36 #include "third_party/blink/public/common/feature_policy/feature_policy.h"
37 #include "third_party/blink/public/common/input/web_input_event.h"
38 #include "third_party/blink/public/mojom/choosers/color_chooser.mojom-blink.h"
39 #include "third_party/blink/public/web/web_local_frame.h"
40 #include "third_party/blink/public/web/web_local_frame_client.h"
41 #include "third_party/blink/public/web/web_view.h"
42 #include "third_party/blink/public/web/web_view_client.h"
43 #include "third_party/blink/renderer/core/exported/web_view_impl.h"
44 #include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
45 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
46 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
47 #include "third_party/blink/renderer/core/html/forms/color_chooser_client.h"
48 #include "third_party/blink/renderer/core/html/forms/date_time_chooser.h"
49 #include "third_party/blink/renderer/core/html/forms/date_time_chooser_client.h"
50 #include "third_party/blink/renderer/core/html/forms/file_chooser.h"
51 #include "third_party/blink/renderer/core/html/forms/html_select_element.h"
52 #include "third_party/blink/renderer/core/html/forms/mock_file_chooser.h"
53 #include "third_party/blink/renderer/core/loader/frame_load_request.h"
54 #include "third_party/blink/renderer/core/page/page.h"
55 #include "third_party/blink/renderer/core/page/scoped_page_pauser.h"
56 #include "third_party/blink/renderer/platform/language.h"
57
58 namespace blink {
59
60 class ViewCreatingClient : public frame_test_helpers::TestWebViewClient {
61 public:
CreateView(WebLocalFrame * opener,const WebURLRequest &,const WebWindowFeatures &,const WebString & name,WebNavigationPolicy,network::mojom::blink::WebSandboxFlags,const FeaturePolicyFeatureState &,const SessionStorageNamespaceId &,bool & consumed_user_gesture)62 WebView* CreateView(WebLocalFrame* opener,
63 const WebURLRequest&,
64 const WebWindowFeatures&,
65 const WebString& name,
66 WebNavigationPolicy,
67 network::mojom::blink::WebSandboxFlags,
68 const FeaturePolicyFeatureState&,
69 const SessionStorageNamespaceId&,
70 bool& consumed_user_gesture) override {
71 return web_view_helper_.InitializeWithOpener(opener);
72 }
73
74 private:
75 frame_test_helpers::WebViewHelper web_view_helper_;
76 };
77
78 class CreateWindowTest : public testing::Test {
79 protected:
SetUp()80 void SetUp() override {
81 web_view_ = helper_.Initialize(nullptr, &web_view_client_);
82 main_frame_ = helper_.LocalMainFrame();
83 chrome_client_impl_ =
84 To<ChromeClientImpl>(&web_view_->GetPage()->GetChromeClient());
85 }
86
87 ViewCreatingClient web_view_client_;
88 frame_test_helpers::WebViewHelper helper_;
89 WebViewImpl* web_view_;
90 WebLocalFrame* main_frame_;
91 Persistent<ChromeClientImpl> chrome_client_impl_;
92 };
93
TEST_F(CreateWindowTest,CreateWindowFromPausedPage)94 TEST_F(CreateWindowTest, CreateWindowFromPausedPage) {
95 ScopedPagePauser pauser;
96 LocalFrame* frame = To<WebLocalFrameImpl>(main_frame_)->GetFrame();
97 FrameLoadRequest request(frame->DomWindow(), ResourceRequest());
98 request.SetNavigationPolicy(kNavigationPolicyNewForegroundTab);
99 WebWindowFeatures features;
100 bool consumed_user_gesture = false;
101 EXPECT_EQ(nullptr,
102 chrome_client_impl_->CreateWindow(
103 frame, request, "", features,
104 network::mojom::blink::WebSandboxFlags::kNone,
105 FeaturePolicyFeatureState(), "", consumed_user_gesture));
106 }
107
108 class FakeColorChooserClient : public GarbageCollected<FakeColorChooserClient>,
109 public ColorChooserClient {
110 public:
FakeColorChooserClient(Element * owner_element)111 FakeColorChooserClient(Element* owner_element)
112 : owner_element_(owner_element) {}
113 ~FakeColorChooserClient() override = default;
114
Trace(Visitor * visitor) const115 void Trace(Visitor* visitor) const override {
116 visitor->Trace(owner_element_);
117 ColorChooserClient::Trace(visitor);
118 }
119
120 // ColorChooserClient
DidChooseColor(const Color & color)121 void DidChooseColor(const Color& color) override {}
DidEndChooser()122 void DidEndChooser() override {}
OwnerElement() const123 Element& OwnerElement() const override { return *owner_element_; }
ElementRectRelativeToViewport() const124 IntRect ElementRectRelativeToViewport() const override { return IntRect(); }
CurrentColor()125 Color CurrentColor() override { return Color(); }
ShouldShowSuggestions() const126 bool ShouldShowSuggestions() const override { return false; }
Suggestions() const127 Vector<mojom::blink::ColorSuggestionPtr> Suggestions() const override {
128 return Vector<mojom::blink::ColorSuggestionPtr>();
129 }
130
131 private:
132 Member<Element> owner_element_;
133 };
134
135 class FakeDateTimeChooserClient
136 : public GarbageCollected<FakeDateTimeChooserClient>,
137 public DateTimeChooserClient {
138 public:
FakeDateTimeChooserClient(Element * owner_element)139 FakeDateTimeChooserClient(Element* owner_element)
140 : owner_element_(owner_element) {}
141 ~FakeDateTimeChooserClient() override = default;
142
Trace(Visitor * visitor) const143 void Trace(Visitor* visitor) const override {
144 visitor->Trace(owner_element_);
145 DateTimeChooserClient::Trace(visitor);
146 }
147
148 // DateTimeChooserClient
OwnerElement() const149 Element& OwnerElement() const override { return *owner_element_; }
DidChooseValue(const String &)150 void DidChooseValue(const String&) override {}
DidChooseValue(double)151 void DidChooseValue(double) override {}
DidEndChooser()152 void DidEndChooser() override {}
153
154 private:
155 Member<Element> owner_element_;
156 };
157
158 // TODO(crbug.com/779126): A number of popups are not supported in immersive
159 // mode. The PagePopupSuppressionTests ensure that these unsupported popups
160 // do not appear in immersive mode.
161 class PagePopupSuppressionTest : public testing::Test {
162 public:
163 PagePopupSuppressionTest() = default;
164
CanOpenColorChooser()165 bool CanOpenColorChooser() {
166 LocalFrame* frame = main_frame_->GetFrame();
167 Color color;
168 return !!chrome_client_impl_->OpenColorChooser(frame, color_chooser_client_,
169 color);
170 }
171
CanOpenDateTimeChooser()172 bool CanOpenDateTimeChooser() {
173 LocalFrame* frame = main_frame_->GetFrame();
174 DateTimeChooserParameters params;
175 params.locale = DefaultLanguage();
176 return !!chrome_client_impl_->OpenDateTimeChooser(
177 frame, date_time_chooser_client_, params);
178 }
179
GetSettings()180 Settings* GetSettings() {
181 LocalFrame* frame = main_frame_->GetFrame();
182 return frame->GetDocument()->GetSettings();
183 }
184
185 protected:
SetUp()186 void SetUp() override {
187 web_view_ = helper_.Initialize();
188 main_frame_ = helper_.LocalMainFrame();
189 chrome_client_impl_ =
190 To<ChromeClientImpl>(&web_view_->GetPage()->GetChromeClient());
191 LocalFrame* frame = helper_.LocalMainFrame()->GetFrame();
192 color_chooser_client_ = MakeGarbageCollected<FakeColorChooserClient>(
193 frame->GetDocument()->documentElement());
194 date_time_chooser_client_ = MakeGarbageCollected<FakeDateTimeChooserClient>(
195 frame->GetDocument()->documentElement());
196 select_ = MakeGarbageCollected<HTMLSelectElement>(*(frame->GetDocument()));
197 }
198
199 protected:
200 frame_test_helpers::WebViewHelper helper_;
201 WebViewImpl* web_view_;
202 Persistent<WebLocalFrameImpl> main_frame_;
203 Persistent<ChromeClientImpl> chrome_client_impl_;
204 Persistent<FakeColorChooserClient> color_chooser_client_;
205 Persistent<FakeDateTimeChooserClient> date_time_chooser_client_;
206 Persistent<HTMLSelectElement> select_;
207 };
208
TEST_F(PagePopupSuppressionTest,SuppressColorChooser)209 TEST_F(PagePopupSuppressionTest, SuppressColorChooser) {
210 // By default, the popup should be shown.
211 EXPECT_TRUE(CanOpenColorChooser());
212
213 Settings* settings = GetSettings();
214 settings->SetImmersiveModeEnabled(true);
215
216 EXPECT_FALSE(CanOpenColorChooser());
217
218 settings->SetImmersiveModeEnabled(false);
219 EXPECT_TRUE(CanOpenColorChooser());
220 }
221
TEST_F(PagePopupSuppressionTest,SuppressDateTimeChooser)222 TEST_F(PagePopupSuppressionTest, SuppressDateTimeChooser) {
223 // By default, the popup should be shown.
224 EXPECT_TRUE(CanOpenDateTimeChooser());
225
226 Settings* settings = GetSettings();
227 settings->SetImmersiveModeEnabled(true);
228
229 EXPECT_FALSE(CanOpenDateTimeChooser());
230
231 settings->SetImmersiveModeEnabled(false);
232 EXPECT_TRUE(CanOpenDateTimeChooser());
233 }
234
235 // A FileChooserClient which makes FileChooser::OpenFileChooser() success.
236 class MockFileChooserClient : public GarbageCollected<MockFileChooserClient>,
237 public FileChooserClient {
238 public:
MockFileChooserClient(LocalFrame * frame)239 explicit MockFileChooserClient(LocalFrame* frame) : frame_(frame) {}
Trace(Visitor * visitor) const240 void Trace(Visitor* visitor) const override {
241 visitor->Trace(frame_);
242 FileChooserClient::Trace(visitor);
243 }
244
245 private:
246 // FilesChosen() and WillOpenPopup() are never called in the test.
FilesChosen(FileChooserFileInfoList,const base::FilePath &)247 void FilesChosen(FileChooserFileInfoList, const base::FilePath&) override {}
WillOpenPopup()248 void WillOpenPopup() override {}
249
FrameOrNull() const250 LocalFrame* FrameOrNull() const override { return frame_; }
251
252 Member<LocalFrame> frame_;
253 };
254
255 class FileChooserQueueTest : public testing::Test {
256 protected:
SetUp()257 void SetUp() override {
258 web_view_ = helper_.Initialize();
259 chrome_client_impl_ =
260 To<ChromeClientImpl>(&web_view_->GetPage()->GetChromeClient());
261 }
262
263 frame_test_helpers::WebViewHelper helper_;
264 WebViewImpl* web_view_;
265 Persistent<ChromeClientImpl> chrome_client_impl_;
266 };
267
TEST_F(FileChooserQueueTest,DerefQueuedChooser)268 TEST_F(FileChooserQueueTest, DerefQueuedChooser) {
269 LocalFrame* frame = helper_.LocalMainFrame()->GetFrame();
270 base::RunLoop run_loop_for_chooser1;
271 MockFileChooser chooser(frame->GetBrowserInterfaceBroker(),
272 run_loop_for_chooser1.QuitClosure());
273 auto* client1 = MakeGarbageCollected<MockFileChooserClient>(frame);
274 auto* client2 = MakeGarbageCollected<MockFileChooserClient>(frame);
275 mojom::blink::FileChooserParams params;
276 params.title = g_empty_string;
277 scoped_refptr<FileChooser> chooser1 = client1->NewFileChooser(params);
278 scoped_refptr<FileChooser> chooser2 = client2->NewFileChooser(params);
279
280 chrome_client_impl_->OpenFileChooser(frame, chooser1);
281 chrome_client_impl_->OpenFileChooser(frame, chooser2);
282 EXPECT_EQ(2u, chrome_client_impl_->file_chooser_queue_.size());
283 chooser2.reset();
284
285 // Kicks ChromeClientImpl::DidCompleteFileChooser() for chooser1.
286 run_loop_for_chooser1.Run();
287 chooser.ResponseOnOpenFileChooser(FileChooserFileInfoList());
288
289 EXPECT_EQ(1u, chrome_client_impl_->file_chooser_queue_.size());
290 base::RunLoop run_loop_for_chooser2;
291
292 chooser.SetQuitClosure(run_loop_for_chooser2.QuitClosure());
293 run_loop_for_chooser2.Run();
294
295 chooser.ResponseOnOpenFileChooser(FileChooserFileInfoList());
296 }
297
298 } // namespace blink
299