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