blob: 7944f2f960bae757a24e7abc402f0eb96b98cd6e [file] [log] [blame]
[email protected]de7d61ff2013-08-20 11:30:411// Copyright 2013 The Chromium Authors. All rights reserved.
[email protected]9fbd3f862011-09-20 23:31:342// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]de7d61ff2013-08-20 11:30:415#include "content/shell/browser/shell.h"
[email protected]9fbd3f862011-09-20 23:31:346
avi66a07722015-12-25 23:38:127#include <stddef.h>
8
Lukasz Anforowicz52b93722018-06-20 16:11:399#include <map>
Peter Boströmdd7e40ec2021-04-05 20:40:1010#include <memory>
Lukasz Anforowicz52b93722018-06-20 16:11:3911#include <string>
12#include <utility>
13
Gabriel Charettea6b6f552021-03-22 15:50:3514#include "base/callback_helpers.h"
[email protected]efb5f572012-01-29 10:57:3315#include "base/command_line.h"
skyostil95082a62015-06-05 19:53:0716#include "base/location.h"
avi66a07722015-12-25 23:38:1217#include "base/macros.h"
Wez9a58a152018-06-07 18:59:3318#include "base/no_destructor.h"
fdoray896bea12016-06-10 15:52:0119#include "base/run_loop.h"
skyostil95082a62015-06-05 19:53:0720#include "base/single_thread_task_runner.h"
[email protected]21aa99682013-06-11 07:17:0121#include "base/strings/string_number_conversions.h"
22#include "base/strings/string_util.h"
23#include "base/strings/stringprintf.h"
[email protected]74ebfb12013-06-07 20:48:0024#include "base/strings/utf_string_conversions.h"
gab30f26df2016-05-11 19:37:5525#include "base/threading/thread_task_runner_handle.h"
avi66a07722015-12-25 23:38:1226#include "build/build_config.h"
[email protected]b50452f2014-08-18 12:31:4427#include "content/public/browser/devtools_agent_host.h"
[email protected]0b659b32012-03-26 21:29:3228#include "content/public/browser/navigation_controller.h"
[email protected]b7c504c2013-05-07 14:42:1229#include "content/public/browser/navigation_entry.h"
Becca Hughes112832e2019-06-11 17:19:0230#include "content/public/browser/picture_in_picture_window_controller.h"
arthursonzognib93a4472020-04-10 07:38:0031#include "content/public/browser/presentation_receiver_flags.h"
Yutaka Hirano2109e582018-02-14 07:24:4632#include "content/public/browser/render_process_host.h"
[email protected]0b659b32012-03-26 21:29:3233#include "content/public/browser/render_view_host.h"
avif9ab5d942015-10-15 14:05:4434#include "content/public/browser/render_widget_host.h"
Xianzhu Wang6be66b012020-05-06 17:17:2535#include "content/public/browser/renderer_preferences_util.h"
[email protected]0b659b32012-03-26 21:29:3236#include "content/public/browser/web_contents.h"
guoweis8efb6d892015-10-12 18:26:1737#include "content/public/common/content_switches.h"
danakjde3e2a02020-05-12 16:51:2038#include "content/shell/app/resource.h"
[email protected]de7d61ff2013-08-20 11:30:4139#include "content/shell/browser/shell_content_browser_client.h"
40#include "content/shell/browser/shell_devtools_frontend.h"
41#include "content/shell/browser/shell_javascript_dialog_manager.h"
[email protected]b7c504c2013-05-07 14:42:1242#include "content/shell/common/shell_switches.h"
Scott Violeta35f9a42018-03-22 22:00:4443#include "media/media_buildflags.h"
Antonio Gomesb5bf548f2019-09-12 17:40:1544#include "third_party/blink/public/common/peerconnection/webrtc_ip_handling_policy.h"
Mario Sanchez Prada0bd8b8c2020-10-21 17:49:2345#include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h"
[email protected]9fbd3f862011-09-20 23:31:3446
[email protected]9fbd3f862011-09-20 23:31:3447namespace content {
48
Wezcbf4a042018-06-13 16:29:1249// Null until/unless the default main message loop is running.
50base::NoDestructor<base::OnceClosure> g_quit_main_message_loop;
Wez9a58a152018-06-07 18:59:3351
pdrcab84ee2015-03-13 21:47:0452const int kDefaultTestWindowWidthDip = 800;
53const int kDefaultTestWindowHeightDip = 600;
[email protected]1e57cab2013-05-28 04:26:1154
[email protected]e99ca5112011-09-26 17:22:5455std::vector<Shell*> Shell::windows_;
danakja9fe91c2019-05-01 19:02:2956base::OnceCallback<void(Shell*)> Shell::shell_created_callback_;
[email protected]9fbd3f862011-09-20 23:31:3457
danakjde3e2a02020-05-12 16:51:2058ShellPlatformDelegate* g_platform;
59
[email protected]7fff43e2013-05-21 20:21:1060class Shell::DevToolsWebContentsObserver : public WebContentsObserver {
61 public:
62 DevToolsWebContentsObserver(Shell* shell, WebContents* web_contents)
63 : WebContentsObserver(web_contents),
64 shell_(shell) {
65 }
66
67 // WebContentsObserver
dchenge933b3e2014-10-21 11:44:0968 void WebContentsDestroyed() override {
[email protected]7fff43e2013-05-21 20:21:1069 shell_->OnDevToolsWebContentsDestroyed();
70 }
71
72 private:
73 Shell* shell_;
74
75 DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver);
76};
77
Bo Liu300c6052018-06-12 04:46:0778Shell::Shell(std::unique_ptr<WebContents> web_contents,
79 bool should_set_delegate)
erikchenbee5c9622018-04-27 19:30:2580 : WebContentsObserver(web_contents.get()),
danakjde3e2a02020-05-12 16:51:2081 web_contents_(std::move(web_contents)) {
Bo Liu300c6052018-06-12 04:46:0782 if (should_set_delegate)
83 web_contents_->SetDelegate(this);
arthursonzognifdd49912017-08-31 08:55:2684
danakjd4b48df52020-07-02 18:16:4885 if (!switches::IsRunWebTestsSwitchPresent()) {
Xianzhu Wang6be66b012020-05-06 17:17:2586 UpdateFontRendererPreferencesFromSystemSettings(
87 web_contents_->GetMutableRendererPrefs());
Francois Doraye6161152018-03-27 22:05:3788 }
Pavel Feldmanc7cd063c2017-10-06 20:04:2889
[email protected]9e00e6352012-07-30 17:05:1890 windows_.push_back(this);
91
danakja9fe91c2019-05-01 19:02:2992 if (shell_created_callback_)
93 std::move(shell_created_callback_).Run(this);
[email protected]9fbd3f862011-09-20 23:31:3494}
95
96Shell::~Shell() {
danakjde3e2a02020-05-12 16:51:2097 g_platform->CleanUp(this);
[email protected]e99ca5112011-09-26 17:22:5498
99 for (size_t i = 0; i < windows_.size(); ++i) {
100 if (windows_[i] == this) {
101 windows_.erase(windows_.begin() + i);
102 break;
103 }
104 }
[email protected]11a65b692012-03-30 11:29:16105
danakjde3e2a02020-05-12 16:51:20106 // Always destroy WebContents before destroying ShellPlatformDelegate.
107 // WebContents destruction sequence may depend on the resources destroyed with
108 // ShellPlatformDelegate (e.g. the display::Screen singleton).
Sergey Ulanovf0875d12019-01-03 20:33:23109 web_contents_->SetDelegate(nullptr);
110 web_contents_.reset();
111
Wez9a58a152018-06-07 18:59:33112 if (windows_.empty()) {
Peter Kastinged599662020-05-18 18:40:42113 delete g_platform;
114 g_platform = nullptr;
danakjde3e2a02020-05-12 16:51:20115
Yutaka Hirano2109e582018-02-14 07:24:46116 for (auto it = RenderProcessHost::AllHostsIterator(); !it.IsAtEnd();
117 it.Advance()) {
118 it.GetCurrentValue()->DisableKeepAliveRefCount();
119 }
Wezcbf4a042018-06-13 16:29:12120 if (*g_quit_main_message_loop)
121 std::move(*g_quit_main_message_loop).Run();
[email protected]b53adf452014-02-07 12:55:08122 }
[email protected]9fbd3f862011-09-20 23:31:34123}
124
erikchenbee5c9622018-04-27 19:30:25125Shell* Shell::CreateShell(std::unique_ptr<WebContents> web_contents,
Bo Liu300c6052018-06-12 04:46:07126 const gfx::Size& initial_size,
127 bool should_set_delegate) {
erikchenbee5c9622018-04-27 19:30:25128 WebContents* raw_web_contents = web_contents.get();
Bo Liu300c6052018-06-12 04:46:07129 Shell* shell = new Shell(std::move(web_contents), should_set_delegate);
danakjde3e2a02020-05-12 16:51:20130 g_platform->CreatePlatformWindow(shell, initial_size);
[email protected]1596efb2013-01-17 22:13:01131
creisb6561df2016-02-11 20:20:54132 // Note: Do not make RenderFrameHost or RenderViewHost specific state changes
133 // here, because they will be forgotten after a cross-process navigation. Use
134 // RenderFrameCreated or RenderViewCreated instead.
Kent Tamuracd3ebc42018-05-16 06:44:22135 if (switches::IsRunWebTestsSwitchPresent()) {
erikchenbee5c9622018-04-27 19:30:25136 raw_web_contents->GetMutableRendererPrefs()->use_custom_colors = false;
Bruce Long1e3e1f542019-10-16 17:56:28137 raw_web_contents->SyncRendererPrefs();
[email protected]1596efb2013-01-17 22:13:01138 }
139
lukasza381b0492016-03-10 16:48:43140 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
guoweis4ee48592015-12-02 06:37:07141 if (command_line->HasSwitch(switches::kForceWebRtcIPHandlingPolicy)) {
erikchenbee5c9622018-04-27 19:30:25142 raw_web_contents->GetMutableRendererPrefs()->webrtc_ip_handling_policy =
guoweis4ee48592015-12-02 06:37:07143 command_line->GetSwitchValueASCII(
144 switches::kForceWebRtcIPHandlingPolicy);
guoweis8efb6d892015-10-12 18:26:17145 }
guoweis8efb6d892015-10-12 18:26:17146
danakj8de3b7492020-07-02 22:41:42147 g_platform->SetContents(shell);
148 g_platform->DidCreateOrAttachWebContents(shell, raw_web_contents);
danakj3dd7a6102020-12-30 19:58:39149 // If the RenderFrame was created during WebContents construction (as happens
150 // for windows opened from the renderer) then the Shell won't hear about the
151 // main frame being created as a WebContentsObservers. This gives the delegate
152 // a chance to act on the main frame accordingly.
153 if (raw_web_contents->GetMainFrame()->IsRenderFrameCreated())
154 g_platform->MainFrameCreated(shell);
danakj7da833932020-06-23 21:49:40155
[email protected]3fd84032012-01-12 18:20:17156 return shell;
157}
158
[email protected]11a65b692012-03-30 11:29:16159void Shell::CloseAllWindows() {
[email protected]b50452f2014-08-18 12:31:44160 DevToolsAgentHost::DetachAllClients();
Wezcbf4a042018-06-13 16:29:12161
Peter Kastinged599662020-05-18 18:40:42162 std::vector<Shell*> open_windows(windows_);
163 for (Shell* open_window : open_windows)
164 open_window->Close();
165 DCHECK(windows_.empty());
Wezcbf4a042018-06-13 16:29:12166
Peter Kastinged599662020-05-18 18:40:42167 // Pump the message loop to allow window teardown tasks to run.
168 base::RunLoop().RunUntilIdle();
[email protected]11a65b692012-03-30 11:29:16169}
170
Wezcbf4a042018-06-13 16:29:12171void Shell::SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure) {
172 *g_quit_main_message_loop = std::move(quit_closure);
173}
174
Wez7d3eb012018-06-20 22:51:28175void Shell::QuitMainMessageLoopForTesting() {
Wezc93f15a92020-02-25 21:57:44176 if (*g_quit_main_message_loop)
177 std::move(*g_quit_main_message_loop).Run();
Wez7d3eb012018-06-20 22:51:28178}
179
[email protected]9e00e6352012-07-30 17:05:18180void Shell::SetShellCreatedCallback(
danakja9fe91c2019-05-01 19:02:29181 base::OnceCallback<void(Shell*)> shell_created_callback) {
182 DCHECK(!shell_created_callback_);
Tommy Nyquist4b749d02018-03-20 21:46:29183 shell_created_callback_ = std::move(shell_created_callback);
[email protected]9e00e6352012-07-30 17:05:18184}
185
danakjde3e2a02020-05-12 16:51:20186// static
187bool Shell::ShouldHideToolbar() {
188 return base::CommandLine::ForCurrentProcess()->HasSwitch(
189 switches::kContentShellHideToolbar);
190}
191
David Benjaminf62c6662019-03-21 20:25:04192Shell* Shell::FromWebContents(WebContents* web_contents) {
193 for (Shell* window : windows_) {
194 if (window->web_contents() && window->web_contents() == web_contents) {
195 return window;
[email protected]74830f02012-01-30 22:27:04196 }
197 }
Ivan Kotenkov2c0d2bb32017-11-01 15:41:28198 return nullptr;
[email protected]74830f02012-01-30 22:27:04199}
200
danakjde3e2a02020-05-12 16:51:20201void Shell::Initialize(std::unique_ptr<ShellPlatformDelegate> platform) {
202 g_platform = platform.release();
203 g_platform->Initialize(GetShellDefaultSize());
[email protected]6153b272013-01-25 22:29:23204}
205
[email protected]a2904092013-10-15 04:53:59206gfx::Size Shell::AdjustWindowSize(const gfx::Size& initial_size) {
207 if (!initial_size.IsEmpty())
208 return initial_size;
pdrcab84ee2015-03-13 21:47:04209 return GetShellDefaultSize();
[email protected]a2904092013-10-15 04:53:59210}
211
[email protected]bdcf9152012-07-19 17:43:21212Shell* Shell::CreateNewWindow(BrowserContext* browser_context,
[email protected]e99ca5112011-09-26 17:22:54213 const GURL& url,
lukasza04130152016-10-21 20:26:32214 const scoped_refptr<SiteInstance>& site_instance,
[email protected]cdb806722013-01-10 14:18:23215 const gfx::Size& initial_size) {
[email protected]54944cde2012-12-09 09:24:59216 WebContents::CreateParams create_params(browser_context, site_instance);
mark a. foltzef394fce2017-10-21 09:11:02217 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
218 switches::kForcePresentationReceiverForTesting)) {
219 create_params.starting_sandbox_flags =
arthursonzognib93a4472020-04-10 07:38:00220 content::kPresentationReceiverSandboxFlags;
mark a. foltzef394fce2017-10-21 09:11:02221 }
erikchenbee5c9622018-04-27 19:30:25222 std::unique_ptr<WebContents> web_contents =
Erik Chenbb8e738e2018-04-28 14:10:43223 WebContents::Create(create_params);
erikchenbee5c9622018-04-27 19:30:25224 Shell* shell =
danakjfc5184932019-09-12 18:08:32225 CreateShell(std::move(web_contents), AdjustWindowSize(initial_size),
Bo Liu300c6052018-06-12 04:46:07226 true /* should_set_delegate */);
danakj7da833932020-06-23 21:49:40227
[email protected]e99ca5112011-09-26 17:22:54228 if (!url.is_empty())
229 shell->LoadURL(url);
[email protected]9fbd3f862011-09-20 23:31:34230 return shell;
231}
232
danakj3dd7a6102020-12-30 19:58:39233void Shell::RenderFrameCreated(RenderFrameHost* frame_host) {
234 if (frame_host == web_contents_->GetMainFrame())
235 g_platform->MainFrameCreated(this);
danakj24577b12020-05-13 22:38:18236}
237
[email protected]9fbd3f862011-09-20 23:31:34238void Shell::LoadURL(const GURL& url) {
Alex Moshchuk7e26eca2018-03-03 01:34:29239 LoadURLForFrame(
240 url, std::string(),
241 ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
242 ui::PAGE_TRANSITION_FROM_ADDRESS_BAR));
[email protected]d2494ff2013-02-20 08:22:37243}
244
Alex Moshchuk7e26eca2018-03-03 01:34:29245void Shell::LoadURLForFrame(const GURL& url,
246 const std::string& frame_name,
247 ui::PageTransition transition_type) {
[email protected]d2494ff2013-02-20 08:22:37248 NavigationController::LoadURLParams params(url);
[email protected]d2494ff2013-02-20 08:22:37249 params.frame_name = frame_name;
Alex Moshchuk7e26eca2018-03-03 01:34:29250 params.transition_type = transition_type;
[email protected]d2494ff2013-02-20 08:22:37251 web_contents_->GetController().LoadURLWithParams(params);
[email protected]9fbd3f862011-09-20 23:31:34252}
253
[email protected]76bdecb2014-04-16 17:58:08254void Shell::LoadDataWithBaseURL(const GURL& url, const std::string& data,
255 const GURL& base_url) {
boliuec93ea92016-02-17 22:23:07256 bool load_as_string = false;
257 LoadDataWithBaseURLInternal(url, data, base_url, load_as_string);
258}
259
260#if defined(OS_ANDROID)
261void Shell::LoadDataAsStringWithBaseURL(const GURL& url,
262 const std::string& data,
263 const GURL& base_url) {
264 bool load_as_string = true;
265 LoadDataWithBaseURLInternal(url, data, base_url, load_as_string);
266}
267#endif
268
269void Shell::LoadDataWithBaseURLInternal(const GURL& url,
270 const std::string& data,
271 const GURL& base_url,
272 bool load_as_string) {
273#if !defined(OS_ANDROID)
274 DCHECK(!load_as_string); // Only supported on Android.
275#endif
276
277 NavigationController::LoadURLParams params(GURL::EmptyGURL());
278 const std::string data_url_header = "data:text/html;charset=utf-8,";
279 if (load_as_string) {
280 params.url = GURL(data_url_header);
281 std::string data_url_as_string = data_url_header + data;
282#if defined(OS_ANDROID)
283 params.data_url_as_string =
284 base::RefCountedString::TakeString(&data_url_as_string);
285#endif
286 } else {
287 params.url = GURL(data_url_header + data);
288 }
289
[email protected]76bdecb2014-04-16 17:58:08290 params.load_type = NavigationController::LOAD_TYPE_DATA;
291 params.base_url_for_data_url = base_url;
292 params.virtual_url_for_data_url = url;
293 params.override_user_agent = NavigationController::UA_OVERRIDE_FALSE;
294 web_contents_->GetController().LoadURLWithParams(params);
[email protected]76bdecb2014-04-16 17:58:08295}
296
[email protected]a2904092013-10-15 04:53:59297void Shell::AddNewContents(WebContents* source,
erikchenbee5c9622018-04-27 19:30:25298 std::unique_ptr<WebContents> new_contents,
Joel Hockey891e88062020-04-30 05:38:44299 const GURL& target_url,
[email protected]a2904092013-10-15 04:53:59300 WindowOpenDisposition disposition,
bokan107a47f2015-02-03 23:23:39301 const gfx::Rect& initial_rect,
[email protected]a2904092013-10-15 04:53:59302 bool user_gesture,
303 bool* was_blocked) {
Bo Liu300c6052018-06-12 04:46:07304 CreateShell(
305 std::move(new_contents), AdjustWindowSize(initial_rect.size()),
306 !delay_popup_contents_delegate_for_testing_ /* should_set_delegate */);
[email protected]a2904092013-10-15 04:53:59307}
308
[email protected]9fbd3f862011-09-20 23:31:34309void Shell::GoBackOrForward(int offset) {
[email protected]0b659b32012-03-26 21:29:32310 web_contents_->GetController().GoToOffset(offset);
[email protected]9fbd3f862011-09-20 23:31:34311}
312
313void Shell::Reload() {
toyoshim6142d96f2016-12-19 09:07:25314 web_contents_->GetController().Reload(ReloadType::NORMAL, false);
[email protected]9fbd3f862011-09-20 23:31:34315}
316
toyoshime5aaf6a2016-05-18 08:07:48317void Shell::ReloadBypassingCache() {
toyoshim6142d96f2016-12-19 09:07:25318 web_contents_->GetController().Reload(ReloadType::BYPASSING_CACHE, false);
toyoshime5aaf6a2016-05-18 08:07:48319}
320
[email protected]9fbd3f862011-09-20 23:31:34321void Shell::Stop() {
[email protected]0b659b32012-03-26 21:29:32322 web_contents_->Stop();
[email protected]9fbd3f862011-09-20 23:31:34323}
324
[email protected]e3b10d12014-03-28 16:06:09325void Shell::UpdateNavigationControls(bool to_different_document) {
[email protected]0b659b32012-03-26 21:29:32326 int current_index = web_contents_->GetController().GetCurrentEntryIndex();
327 int max_index = web_contents_->GetController().GetEntryCount() - 1;
[email protected]9fbd3f862011-09-20 23:31:34328
danakjde3e2a02020-05-12 16:51:20329 g_platform->EnableUIControl(this, ShellPlatformDelegate::BACK_BUTTON,
330 current_index > 0);
331 g_platform->EnableUIControl(this, ShellPlatformDelegate::FORWARD_BUTTON,
332 current_index < max_index);
333 g_platform->EnableUIControl(
334 this, ShellPlatformDelegate::STOP_BUTTON,
[email protected]e3b10d12014-03-28 16:06:09335 to_different_document && web_contents_->IsLoading());
[email protected]9fbd3f862011-09-20 23:31:34336}
337
[email protected]7c17b6992012-08-09 16:16:30338void Shell::ShowDevTools() {
mohsen6eb57fb2016-07-22 03:14:08339 if (!devtools_frontend_) {
340 devtools_frontend_ = ShellDevToolsFrontend::Show(web_contents());
Peter Boströmdd7e40ec2021-04-05 20:40:10341 devtools_observer_ = std::make_unique<DevToolsWebContentsObserver>(
342 this, devtools_frontend_->frontend_shell()->web_contents());
mohsen6eb57fb2016-07-22 03:14:08343 }
[email protected]3142e5d2014-02-07 00:54:46344
mohsen6eb57fb2016-07-22 03:14:08345 devtools_frontend_->Activate();
[email protected]7c17b6992012-08-09 16:16:30346}
347
[email protected]001841c92012-12-11 17:00:13348void Shell::CloseDevTools() {
[email protected]0773e0c2013-01-25 15:57:57349 if (!devtools_frontend_)
[email protected]001841c92012-12-11 17:00:13350 return;
[email protected]7fff43e2013-05-21 20:21:10351 devtools_observer_.reset();
[email protected]0773e0c2013-01-25 15:57:57352 devtools_frontend_->Close();
Ivan Kotenkov2c0d2bb32017-11-01 15:41:28353 devtools_frontend_ = nullptr;
[email protected]001841c92012-12-11 17:00:13354}
355
danakjde3e2a02020-05-12 16:51:20356void Shell::ResizeWebContentForTests(const gfx::Size& content_size) {
357 g_platform->ResizeWebContent(this, content_size);
358}
danakjde3e2a02020-05-12 16:51:20359
[email protected]9fbd3f862011-09-20 23:31:34360gfx::NativeView Shell::GetContentView() {
[email protected]59383c782013-04-17 16:43:27361 if (!web_contents_)
Ivan Kotenkov2c0d2bb32017-11-01 15:41:28362 return nullptr;
[email protected]fc2b46b2014-05-03 16:33:45363 return web_contents_->GetNativeView();
[email protected]9fbd3f862011-09-20 23:31:34364}
365
danakjde3e2a02020-05-12 16:51:20366#if !defined(OS_ANDROID)
367gfx::NativeWindow Shell::window() {
368 return g_platform->GetNativeWindow(this);
369}
370#endif
371
Avi Drissman7c57be72020-07-29 20:09:46372#if defined(OS_MAC)
danakjde3e2a02020-05-12 16:51:20373void Shell::ActionPerformed(int control) {
374 switch (control) {
375 case IDC_NAV_BACK:
376 GoBackOrForward(-1);
377 break;
378 case IDC_NAV_FORWARD:
379 GoBackOrForward(1);
380 break;
381 case IDC_NAV_RELOAD:
382 Reload();
383 break;
384 case IDC_NAV_STOP:
385 Stop();
386 break;
387 }
388}
389
390void Shell::URLEntered(const std::string& url_string) {
391 if (!url_string.empty()) {
392 GURL url(url_string);
393 if (!url.has_scheme())
394 url = GURL("http://" + url_string);
395 LoadURL(url);
396 }
397}
398#endif
399
alexmos5a98a052016-01-06 00:15:02400WebContents* Shell::OpenURLFromTab(WebContents* source,
401 const OpenURLParams& params) {
lukasza04130152016-10-21 20:26:32402 WebContents* target = nullptr;
403 switch (params.disposition) {
404 case WindowOpenDisposition::CURRENT_TAB:
405 target = source;
406 break;
407
408 // Normally, the difference between NEW_POPUP and NEW_WINDOW is that a popup
409 // should have no toolbar, no status bar, no menu bar, no scrollbars and be
410 // not resizable. For simplicity and to enable new testing scenarios in
Kent Tamura21d1de62018-12-10 04:45:20411 // content shell and web tests, popups don't get special treatment below
lukasza04130152016-10-21 20:26:32412 // (i.e. they will have a toolbar and other things described here).
413 case WindowOpenDisposition::NEW_POPUP:
lukaszabe2f0da2017-04-25 00:43:00414 case WindowOpenDisposition::NEW_WINDOW:
Kent Tamura21d1de62018-12-10 04:45:20415 // content_shell doesn't really support tabs, but some web tests use
lukaszabe2f0da2017-04-25 00:43:00416 // middle click (which translates into kNavigationPolicyNewBackgroundTab),
417 // so we treat the cases below just like a NEW_WINDOW disposition.
418 case WindowOpenDisposition::NEW_BACKGROUND_TAB:
419 case WindowOpenDisposition::NEW_FOREGROUND_TAB: {
lukasza04130152016-10-21 20:26:32420 Shell* new_window =
421 Shell::CreateNewWindow(source->GetBrowserContext(),
422 GURL(), // Don't load anything just yet.
423 params.source_site_instance,
424 gfx::Size()); // Use default size.
425 target = new_window->web_contents();
lukasza04130152016-10-21 20:26:32426 break;
427 }
428
429 // No tabs in content_shell:
430 case WindowOpenDisposition::SINGLETON_TAB:
lukasza04130152016-10-21 20:26:32431 // No incognito mode in content_shell:
432 case WindowOpenDisposition::OFF_THE_RECORD:
Kent Tamura21d1de62018-12-10 04:45:20433 // TODO(lukasza): Investigate if some web tests might need support for
lukasza04130152016-10-21 20:26:32434 // SAVE_TO_DISK disposition. This would probably require that
Gyuyoung Kim26c7bc92020-04-29 00:53:00435 // WebTestControlHost always sets up and cleans up a temporary directory
lukasza04130152016-10-21 20:26:32436 // as the default downloads destinations for the duration of a test.
437 case WindowOpenDisposition::SAVE_TO_DISK:
438 // Ignoring requests with disposition == IGNORE_ACTION...
439 case WindowOpenDisposition::IGNORE_ACTION:
440 default:
441 return nullptr;
442 }
alexmos5a98a052016-01-06 00:15:02443
Lukasz Anforowicz82a5ca92019-10-24 18:45:37444 target->GetController().LoadURLWithParams(
445 NavigationController::LoadURLParams(params));
lukasza04130152016-10-21 20:26:32446 return target;
alexmos5a98a052016-01-06 00:15:02447}
448
[email protected]e3b10d12014-03-28 16:06:09449void Shell::LoadingStateChanged(WebContents* source,
450 bool to_different_document) {
451 UpdateNavigationControls(to_different_document);
danakjde3e2a02020-05-12 16:51:20452 g_platform->SetIsLoading(this, source->IsLoading());
[email protected]e99ca5112011-09-26 17:22:54453}
454
danakjde3e2a02020-05-12 16:51:20455#if defined(OS_ANDROID)
456void Shell::SetOverlayMode(bool use_overlay_mode) {
457 g_platform->SetOverlayMode(this, use_overlay_mode);
458}
459#endif
460
Dave Tapuskaa4189512019-10-15 20:27:34461void Shell::EnterFullscreenModeForTab(
Mike Wasserman4ca09792020-05-29 17:44:43462 RenderFrameHost* requesting_frame,
Dave Tapuskaa4189512019-10-15 20:27:34463 const blink::mojom::FullscreenOptions& options) {
Mike Wasserman4ca09792020-05-29 17:44:43464 ToggleFullscreenModeForTab(WebContents::FromRenderFrameHost(requesting_frame),
465 true);
mlamouri7a78d6fd2015-01-17 13:23:53466}
467
468void Shell::ExitFullscreenModeForTab(WebContents* web_contents) {
469 ToggleFullscreenModeForTab(web_contents, false);
470}
471
[email protected]99c014c2012-11-27 12:03:42472void Shell::ToggleFullscreenModeForTab(WebContents* web_contents,
473 bool enter_fullscreen) {
474#if defined(OS_ANDROID)
danakjde3e2a02020-05-12 16:51:20475 g_platform->ToggleFullscreenModeForTab(this, web_contents, enter_fullscreen);
[email protected]99c014c2012-11-27 12:03:42476#endif
[email protected]99c014c2012-11-27 12:03:42477 if (is_fullscreen_ != enter_fullscreen) {
478 is_fullscreen_ = enter_fullscreen;
Lucas Furukawa Gadanie7649422021-02-03 03:04:32479 web_contents->GetMainFrame()
480 ->GetRenderViewHost()
Fady Samuel0b911822018-04-25 13:22:16481 ->GetWidget()
482 ->SynchronizeVisualProperties();
[email protected]99c014c2012-11-27 12:03:42483 }
484}
485
Lucas Furukawa Gadani4909f3c2019-06-18 22:36:52486bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) {
[email protected]99c014c2012-11-27 12:03:42487#if defined(OS_ANDROID)
danakjde3e2a02020-05-12 16:51:20488 return g_platform->IsFullscreenForTabOrPending(this, web_contents);
[email protected]99c014c2012-11-27 12:03:42489#else
490 return is_fullscreen_;
491#endif
492}
493
Eric Willigers052f0432019-10-04 04:06:57494blink::mojom::DisplayMode Shell::GetDisplayMode(
495 const WebContents* web_contents) {
496 // TODO: should return blink::mojom::DisplayModeFullscreen wherever user puts
Lukasz Anforowicz52b93722018-06-20 16:11:39497 // a browser window into fullscreen (not only in case of renderer-initiated
498 // fullscreen mode): crbug.com/476874.
499 return IsFullscreenForTabOrPending(web_contents)
Eric Willigers052f0432019-10-04 04:06:57500 ? blink::mojom::DisplayMode::kFullscreen
501 : blink::mojom::DisplayMode::kBrowser;
mikhail.pozdnyakovc0e251b2015-04-15 06:51:12502}
503
[email protected]f78439002012-11-28 14:45:59504void Shell::RequestToLockMouse(WebContents* web_contents,
505 bool user_gesture,
506 bool last_unlocked_by_target) {
Dave Tapuskab4998782020-10-08 17:22:47507 // Give the platform a chance to handle the lock request, if it doesn't
508 // indicate it handled it, allow the request.
509 if (!g_platform->HandleRequestToLockMouse(this, web_contents, user_gesture,
510 last_unlocked_by_target)) {
511 web_contents->GotResponseToLockMouseRequest(
512 blink::mojom::PointerLockResult::kSuccess);
513 }
[email protected]f78439002012-11-28 14:45:59514}
515
danakjde3e2a02020-05-12 16:51:20516void Shell::Close() {
517 // Shell is "self-owned" and destroys itself. The ShellPlatformDelegate
518 // has the chance to co-opt this and do its own destruction.
519 if (!g_platform->DestroyShell(this))
520 delete this;
521}
522
[email protected]9e00e6352012-07-30 17:05:18523void Shell::CloseContents(WebContents* source) {
524 Close();
525}
526
Lucas Furukawa Gadani4909f3c2019-06-18 22:36:52527bool Shell::CanOverscrollContent() {
[email protected]067310262012-11-22 14:30:41528#if defined(USE_AURA)
529 return true;
530#else
531 return false;
532#endif
533}
534
Mugdha Lakhani5f8de7cc2020-03-10 20:43:36535void Shell::NavigationStateChanged(WebContents* source,
536 InvalidateTypes changed_flags) {
537 if (changed_flags & INVALIDATE_TYPE_URL)
danakjde3e2a02020-05-12 16:51:20538 g_platform->SetAddressBarURL(this, source->GetVisibleURL());
[email protected]e99ca5112011-09-26 17:22:54539}
540
mathiash72a5e462014-11-19 08:18:50541JavaScriptDialogManager* Shell::GetJavaScriptDialogManager(
542 WebContents* source) {
danakj8de3b7492020-07-02 22:41:42543 if (!dialog_manager_)
544 dialog_manager_ = g_platform->CreateJavaScriptDialogManager(this);
545 if (!dialog_manager_)
546 dialog_manager_ = std::make_unique<ShellJavaScriptDialogManager>();
[email protected]71a88bb2013-02-01 22:05:15547 return dialog_manager_.get();
[email protected]f2210022012-03-29 00:36:08548}
549
Avi Drissman7c57be72020-07-29 20:09:46550#if defined(OS_MAC)
Xianzhu Wang0f021a82020-07-03 01:29:47551void Shell::DidNavigateMainFramePostCommit(WebContents* contents) {
552 g_platform->DidNavigateMainFramePostCommit(this, contents);
553}
554
danakjde3e2a02020-05-12 16:51:20555bool Shell::HandleKeyboardEvent(WebContents* source,
556 const NativeWebKeyboardEvent& event) {
557 return g_platform->HandleKeyboardEvent(this, source, event);
558}
559#endif
560
avia90ae4e2016-11-11 20:49:33561bool Shell::DidAddMessageToConsole(WebContents* source,
Lowell Manners1de5242e2019-04-25 10:18:46562 blink::mojom::ConsoleMessageLevel log_level,
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58563 const std::u16string& message,
avia90ae4e2016-11-11 20:49:33564 int32_t line_no,
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58565 const std::u16string& source_id) {
Kent Tamuracd3ebc42018-05-16 06:44:22566 return switches::IsRunWebTestsSwitchPresent();
[email protected]efb5f572012-01-29 10:57:33567}
568
Lucas Furukawa Gadani06548fb2019-01-15 05:01:25569void Shell::PortalWebContentsCreated(WebContents* portal_web_contents) {
danakj8de3b7492020-07-02 22:41:42570 g_platform->DidCreateOrAttachWebContents(this, portal_web_contents);
Lucas Furukawa Gadani06548fb2019-01-15 05:01:25571}
572
Lukasz Anforowicz52b93722018-06-20 16:11:39573void Shell::RendererUnresponsive(
574 WebContents* source,
575 RenderWidgetHost* render_widget_host,
576 base::RepeatingClosure hang_monitor_restarter) {
danakj245441f2020-07-03 15:18:41577 LOG(WARNING) << "renderer unresponsive";
[email protected]5bf68f22012-08-31 07:38:10578}
579
[email protected]233567d2013-02-27 20:22:02580void Shell::ActivateContents(WebContents* contents) {
Avi Drissman7c57be72020-07-29 20:09:46581#if !defined(OS_MAC)
danakjd4b48df52020-07-02 18:16:48582 // TODO(danakj): Move this to ShellPlatformDelegate.
danakj674bf1c02020-05-01 18:37:51583 contents->Focus();
584#else
585 // Mac headless mode is quite different than other platforms. Normally
586 // focusing the WebContents would cause the OS to focus the window. Because
587 // headless mac doesn't actually have system windows, we can't go down the
588 // normal path and have to fake it out in the browser process.
danakjde3e2a02020-05-12 16:51:20589 g_platform->ActivateContents(this, contents);
danakj674bf1c02020-05-01 18:37:51590#endif
[email protected]233567d2013-02-27 20:22:02591}
592
Dave Tapuskadfff7382021-04-23 19:46:41593bool Shell::IsBackForwardCacheSupported() {
594 return true;
595}
596
Kevin McNee7422bc42020-02-20 18:49:55597std::unique_ptr<WebContents> Shell::ActivatePortalWebContents(
598 WebContents* predecessor_contents,
599 std::unique_ptr<WebContents> portal_contents) {
600 DCHECK_EQ(predecessor_contents, web_contents_.get());
601 portal_contents->SetDelegate(this);
Lucas Furukawa Gadanic5c0cd02018-10-04 20:32:33602 web_contents_->SetDelegate(nullptr);
Kevin McNee7422bc42020-02-20 18:49:55603 std::swap(web_contents_, portal_contents);
danakjde3e2a02020-05-12 16:51:20604 g_platform->SetContents(this);
605 g_platform->SetAddressBarURL(this, web_contents_->GetVisibleURL());
Lucas Furukawa Gadanic5c0cd02018-10-04 20:32:33606 LoadingStateChanged(web_contents_.get(), true);
Kevin McNee7422bc42020-02-20 18:49:55607 return portal_contents;
Lucas Furukawa Gadanic5c0cd02018-10-04 20:32:33608}
609
Adithya Srinivasanb7204c82020-08-17 14:26:33610namespace {
611class PendingCallback : public base::RefCounted<PendingCallback> {
612 public:
613 explicit PendingCallback(base::OnceCallback<void()> cb)
614 : callback_(std::move(cb)) {}
615
616 private:
617 friend class base::RefCounted<PendingCallback>;
618 ~PendingCallback() { std::move(callback_).Run(); }
619 base::OnceCallback<void()> callback_;
620};
621} // namespace
622
623void Shell::UpdateInspectedWebContentsIfNecessary(
624 content::WebContents* old_contents,
625 content::WebContents* new_contents,
626 base::OnceCallback<void()> callback) {
627 scoped_refptr<PendingCallback> pending_callback =
628 base::MakeRefCounted<PendingCallback>(std::move(callback));
629 for (auto* shell_devtools_bindings :
630 ShellDevToolsBindings::GetInstancesForWebContents(old_contents)) {
631 shell_devtools_bindings->UpdateInspectedWebContents(
632 new_contents,
633 base::BindOnce(base::DoNothing::Once<scoped_refptr<PendingCallback>>(),
634 pending_callback));
635 }
636}
637
Lukasz Anforowicz82a5ca92019-10-24 18:45:37638bool Shell::ShouldAllowRunningInsecureContent(WebContents* web_contents,
639 bool allowed_per_prefs,
640 const url::Origin& origin,
641 const GURL& resource_url) {
danakj8de3b7492020-07-02 22:41:42642 if (allowed_per_prefs)
643 return true;
carloskd9d97942017-02-16 08:58:09644
danakj8de3b7492020-07-02 22:41:42645 return g_platform->ShouldAllowRunningInsecureContent(this);
carloskd9d97942017-02-16 08:58:09646}
647
Becca Hughes112832e2019-06-11 17:19:02648PictureInPictureResult Shell::EnterPictureInPicture(
Lukasz Anforowicz82a5ca92019-10-24 18:45:37649 WebContents* web_contents,
Becca Hughes112832e2019-06-11 17:19:02650 const viz::SurfaceId& surface_id,
651 const gfx::Size& natural_size) {
652 // During tests, returning success to pretend the window was created and allow
653 // tests to run accordingly.
654 if (!switches::IsRunWebTestsSwitchPresent())
655 return PictureInPictureResult::kNotSupported;
Becca Hughes112832e2019-06-11 17:19:02656 return PictureInPictureResult::kSuccess;
Mounir Lamouri11e9ef432018-05-22 03:10:16657}
658
Bo Liu300c6052018-06-12 04:46:07659bool Shell::ShouldResumeRequestsForCreatedWindow() {
660 return !delay_popup_contents_delegate_for_testing_;
661}
662
danakjee2390a82020-06-10 16:53:37663void Shell::SetContentsBounds(WebContents* source, const gfx::Rect& bounds) {
664 DCHECK(source == web_contents()); // There's only one WebContents per Shell.
665
666 if (switches::IsRunWebTestsSwitchPresent()) {
667 // Note that chrome drops these requests on normal windows.
668 // TODO(danakj): The position is dropped here but we use the size. Web tests
669 // can't move the window in headless mode anyways, but maybe we should be
670 // letting them pretend?
671 g_platform->ResizeWebContent(this, bounds.size());
672 }
673}
674
pdrcab84ee2015-03-13 21:47:04675gfx::Size Shell::GetShellDefaultSize() {
danakj6c16fe92020-09-18 23:51:32676 static gfx::Size default_shell_size; // Only go through this method once.
677
pdrcab84ee2015-03-13 21:47:04678 if (!default_shell_size.IsEmpty())
679 return default_shell_size;
danakj6c16fe92020-09-18 23:51:32680
pdrcab84ee2015-03-13 21:47:04681 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
682 if (command_line->HasSwitch(switches::kContentShellHostWindowSize)) {
683 const std::string size_str = command_line->GetSwitchValueASCII(
684 switches::kContentShellHostWindowSize);
685 int width, height;
danakj6c16fe92020-09-18 23:51:32686 if (sscanf(size_str.c_str(), "%dx%d", &width, &height) == 2) {
687 default_shell_size = gfx::Size(width, height);
688 } else {
689 LOG(ERROR) << "Invalid size \"" << size_str << "\" given to --"
690 << switches::kContentShellHostWindowSize;
691 }
692 }
693
694 if (default_shell_size.IsEmpty()) {
pdrcab84ee2015-03-13 21:47:04695 default_shell_size = gfx::Size(
696 kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip);
697 }
danakj6c16fe92020-09-18 23:51:32698
pdrcab84ee2015-03-13 21:47:04699 return default_shell_size;
700}
701
danakjde3e2a02020-05-12 16:51:20702#if defined(OS_ANDROID)
703void Shell::LoadProgressChanged(double progress) {
704 g_platform->LoadProgressChanged(this, progress);
705}
706#endif
707
Avi Drissman93002212017-09-27 03:20:52708void Shell::TitleWasSet(NavigationEntry* entry) {
[email protected]1ef02d242013-10-07 16:18:53709 if (entry)
danakjde3e2a02020-05-12 16:51:20710 g_platform->SetTitle(this, entry->GetTitle());
[email protected]aecc085b2012-06-01 18:15:53711}
712
[email protected]7fff43e2013-05-21 20:21:10713void Shell::OnDevToolsWebContentsDestroyed() {
714 devtools_observer_.reset();
Ivan Kotenkov2c0d2bb32017-11-01 15:41:28715 devtools_frontend_ = nullptr;
[email protected]7fff43e2013-05-21 20:21:10716}
717
[email protected]9fbd3f862011-09-20 23:31:34718} // namespace content