blob: de22ad9da8f9aa7c715208c345e3fbf00b43ee55 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2013 The Chromium Authors
[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
[email protected]efb5f572012-01-29 10:57:3314#include "base/command_line.h"
Avi Drissmanadac21992023-01-11 23:46:3915#include "base/functional/callback_helpers.h"
skyostil95082a62015-06-05 19:53:0716#include "base/location.h"
Wez9a58a152018-06-07 18:59:3317#include "base/no_destructor.h"
fdoray896bea12016-06-10 15:52:0118#include "base/run_loop.h"
[email protected]21aa99682013-06-11 07:17:0119#include "base/strings/string_number_conversions.h"
20#include "base/strings/string_util.h"
[email protected]74ebfb12013-06-07 20:48:0021#include "base/strings/utf_string_conversions.h"
avi66a07722015-12-25 23:38:1222#include "build/build_config.h"
Javier Fernández García-Boente13150a042022-04-04 21:08:2223#include "components/custom_handlers/protocol_handler.h"
24#include "components/custom_handlers/protocol_handler_registry.h"
25#include "components/custom_handlers/simple_protocol_handler_registry_factory.h"
26#include "content/public/browser/browser_context.h"
Julie Jeongeun Kim88ce9ec2023-07-28 02:25:4027#include "content/public/browser/color_chooser.h"
[email protected]b50452f2014-08-18 12:31:4428#include "content/public/browser/devtools_agent_host.h"
Tommy Steimel71f154462024-05-22 19:05:0729#include "content/public/browser/document_picture_in_picture_window_controller.h"
Julie Jeongeun Kimec508272023-03-17 04:17:1230#include "content/public/browser/file_select_listener.h"
[email protected]0b659b32012-03-26 21:29:3231#include "content/public/browser/navigation_controller.h"
[email protected]b7c504c2013-05-07 14:42:1232#include "content/public/browser/navigation_entry.h"
Becca Hughes112832e2019-06-11 17:19:0233#include "content/public/browser/picture_in_picture_window_controller.h"
arthursonzognib93a4472020-04-10 07:38:0034#include "content/public/browser/presentation_receiver_flags.h"
Yutaka Hirano2109e582018-02-14 07:24:4635#include "content/public/browser/render_process_host.h"
[email protected]0b659b32012-03-26 21:29:3236#include "content/public/browser/render_view_host.h"
avif9ab5d942015-10-15 14:05:4437#include "content/public/browser/render_widget_host.h"
Xianzhu Wang6be66b012020-05-06 17:17:2538#include "content/public/browser/renderer_preferences_util.h"
[email protected]0b659b32012-03-26 21:29:3239#include "content/public/browser/web_contents.h"
guoweis8efb6d892015-10-12 18:26:1740#include "content/public/common/content_switches.h"
danakjde3e2a02020-05-12 16:51:2041#include "content/shell/app/resource.h"
[email protected]de7d61ff2013-08-20 11:30:4142#include "content/shell/browser/shell_content_browser_client.h"
43#include "content/shell/browser/shell_devtools_frontend.h"
44#include "content/shell/browser/shell_javascript_dialog_manager.h"
[email protected]b7c504c2013-05-07 14:42:1245#include "content/shell/common/shell_switches.h"
Scott Violeta35f9a42018-03-22 22:00:4446#include "media/media_buildflags.h"
Antonio Gomesb5bf548f2019-09-12 17:40:1547#include "third_party/blink/public/common/peerconnection/webrtc_ip_handling_policy.h"
Mario Sanchez Prada0bd8b8c2020-10-21 17:49:2348#include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h"
Julie Jeongeun Kimec508272023-03-17 04:17:1249#include "third_party/blink/public/mojom/choosers/file_chooser.mojom-forward.h"
Brad Triebwasser767c27a2022-08-25 22:56:0550#include "third_party/blink/public/mojom/window_features/window_features.mojom.h"
[email protected]9fbd3f862011-09-20 23:31:3451
[email protected]9fbd3f862011-09-20 23:31:3452namespace content {
53
arthursonzogni75ede192021-07-06 14:45:4654namespace {
Wezcbf4a042018-06-13 16:29:1255// Null until/unless the default main message loop is running.
Lei Zhangebdd085d2022-10-25 17:24:2656base::OnceClosure& GetMainMessageLoopQuitClosure() {
57 static base::NoDestructor<base::OnceClosure> closure;
58 return *closure;
59}
Wez9a58a152018-06-07 18:59:3360
Lei Zhangebdd085d2022-10-25 17:24:2661constexpr int kDefaultTestWindowWidthDip = 800;
62constexpr int kDefaultTestWindowHeightDip = 600;
[email protected]1e57cab2013-05-28 04:26:1163
arthursonzogni75ede192021-07-06 14:45:4664// Owning pointer. We can not use unique_ptr as a global. That introduces a
65// static constructor/destructor.
66// Acquired in Shell::Init(), released in Shell::Shutdown().
67ShellPlatformDelegate* g_platform;
68} // namespace
69
[email protected]e99ca5112011-09-26 17:22:5470std::vector<Shell*> Shell::windows_;
danakja9fe91c2019-05-01 19:02:2971base::OnceCallback<void(Shell*)> Shell::shell_created_callback_;
[email protected]9fbd3f862011-09-20 23:31:3472
Bo Liu300c6052018-06-12 04:46:0773Shell::Shell(std::unique_ptr<WebContents> web_contents,
74 bool should_set_delegate)
erikchenbee5c9622018-04-27 19:30:2575 : WebContentsObserver(web_contents.get()),
danakjde3e2a02020-05-12 16:51:2076 web_contents_(std::move(web_contents)) {
Bo Liu300c6052018-06-12 04:46:0777 if (should_set_delegate)
78 web_contents_->SetDelegate(this);
arthursonzognifdd49912017-08-31 08:55:2679
danakjd4b48df52020-07-02 18:16:4880 if (!switches::IsRunWebTestsSwitchPresent()) {
Xianzhu Wang6be66b012020-05-06 17:17:2581 UpdateFontRendererPreferencesFromSystemSettings(
82 web_contents_->GetMutableRendererPrefs());
Francois Doraye6161152018-03-27 22:05:3783 }
Pavel Feldmanc7cd063c2017-10-06 20:04:2884
[email protected]9e00e6352012-07-30 17:05:1885 windows_.push_back(this);
86
danakja9fe91c2019-05-01 19:02:2987 if (shell_created_callback_)
88 std::move(shell_created_callback_).Run(this);
[email protected]9fbd3f862011-09-20 23:31:3489}
90
91Shell::~Shell() {
danakjde3e2a02020-05-12 16:51:2092 g_platform->CleanUp(this);
[email protected]e99ca5112011-09-26 17:22:5493
94 for (size_t i = 0; i < windows_.size(); ++i) {
95 if (windows_[i] == this) {
96 windows_.erase(windows_.begin() + i);
97 break;
98 }
99 }
[email protected]11a65b692012-03-30 11:29:16100
Sergey Ulanovf0875d12019-01-03 20:33:23101 web_contents_->SetDelegate(nullptr);
102 web_contents_.reset();
Arthur Sonzogni9e72df3f2021-07-02 14:32:17103
arthursonzogni75ede192021-07-06 14:45:46104 if (windows().empty())
105 g_platform->DidCloseLastWindow();
[email protected]9fbd3f862011-09-20 23:31:34106}
107
erikchenbee5c9622018-04-27 19:30:25108Shell* Shell::CreateShell(std::unique_ptr<WebContents> web_contents,
Bo Liu300c6052018-06-12 04:46:07109 const gfx::Size& initial_size,
110 bool should_set_delegate) {
erikchenbee5c9622018-04-27 19:30:25111 WebContents* raw_web_contents = web_contents.get();
Bo Liu300c6052018-06-12 04:46:07112 Shell* shell = new Shell(std::move(web_contents), should_set_delegate);
danakjde3e2a02020-05-12 16:51:20113 g_platform->CreatePlatformWindow(shell, initial_size);
[email protected]1596efb2013-01-17 22:13:01114
creisb6561df2016-02-11 20:20:54115 // Note: Do not make RenderFrameHost or RenderViewHost specific state changes
116 // here, because they will be forgotten after a cross-process navigation. Use
117 // RenderFrameCreated or RenderViewCreated instead.
Kent Tamuracd3ebc42018-05-16 06:44:22118 if (switches::IsRunWebTestsSwitchPresent()) {
erikchenbee5c9622018-04-27 19:30:25119 raw_web_contents->GetMutableRendererPrefs()->use_custom_colors = false;
Bruce Long1e3e1f542019-10-16 17:56:28120 raw_web_contents->SyncRendererPrefs();
[email protected]1596efb2013-01-17 22:13:01121 }
122
lukasza381b0492016-03-10 16:48:43123 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
guoweis4ee48592015-12-02 06:37:07124 if (command_line->HasSwitch(switches::kForceWebRtcIPHandlingPolicy)) {
erikchenbee5c9622018-04-27 19:30:25125 raw_web_contents->GetMutableRendererPrefs()->webrtc_ip_handling_policy =
guoweis4ee48592015-12-02 06:37:07126 command_line->GetSwitchValueASCII(
127 switches::kForceWebRtcIPHandlingPolicy);
guoweis8efb6d892015-10-12 18:26:17128 }
guoweis8efb6d892015-10-12 18:26:17129
danakj8de3b7492020-07-02 22:41:42130 g_platform->SetContents(shell);
131 g_platform->DidCreateOrAttachWebContents(shell, raw_web_contents);
danakj3dd7a6102020-12-30 19:58:39132 // If the RenderFrame was created during WebContents construction (as happens
133 // for windows opened from the renderer) then the Shell won't hear about the
134 // main frame being created as a WebContentsObservers. This gives the delegate
135 // a chance to act on the main frame accordingly.
Dave Tapuska327c06c92022-06-13 20:31:51136 if (raw_web_contents->GetPrimaryMainFrame()->IsRenderFrameLive())
danakj3dd7a6102020-12-30 19:58:39137 g_platform->MainFrameCreated(shell);
danakj7da833932020-06-23 21:49:40138
[email protected]3fd84032012-01-12 18:20:17139 return shell;
140}
141
arthursonzogni75ede192021-07-06 14:45:46142// static
Wezcbf4a042018-06-13 16:29:12143void Shell::SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure) {
Lei Zhangebdd085d2022-10-25 17:24:26144 GetMainMessageLoopQuitClosure() = std::move(quit_closure);
Wezcbf4a042018-06-13 16:29:12145}
146
arthursonzogni75ede192021-07-06 14:45:46147// static
Wez7d3eb012018-06-20 22:51:28148void Shell::QuitMainMessageLoopForTesting() {
Lei Zhangebdd085d2022-10-25 17:24:26149 auto& quit_loop = GetMainMessageLoopQuitClosure();
150 if (quit_loop)
151 std::move(quit_loop).Run();
Wez7d3eb012018-06-20 22:51:28152}
153
arthursonzogni75ede192021-07-06 14:45:46154// static
[email protected]9e00e6352012-07-30 17:05:18155void Shell::SetShellCreatedCallback(
danakja9fe91c2019-05-01 19:02:29156 base::OnceCallback<void(Shell*)> shell_created_callback) {
157 DCHECK(!shell_created_callback_);
Tommy Nyquist4b749d02018-03-20 21:46:29158 shell_created_callback_ = std::move(shell_created_callback);
[email protected]9e00e6352012-07-30 17:05:18159}
160
danakjde3e2a02020-05-12 16:51:20161// static
162bool Shell::ShouldHideToolbar() {
163 return base::CommandLine::ForCurrentProcess()->HasSwitch(
164 switches::kContentShellHideToolbar);
165}
166
arthursonzogni75ede192021-07-06 14:45:46167// static
David Benjaminf62c6662019-03-21 20:25:04168Shell* Shell::FromWebContents(WebContents* web_contents) {
169 for (Shell* window : windows_) {
170 if (window->web_contents() && window->web_contents() == web_contents) {
171 return window;
[email protected]74830f02012-01-30 22:27:04172 }
173 }
Ivan Kotenkov2c0d2bb32017-11-01 15:41:28174 return nullptr;
[email protected]74830f02012-01-30 22:27:04175}
176
arthursonzogni75ede192021-07-06 14:45:46177// static
danakjde3e2a02020-05-12 16:51:20178void Shell::Initialize(std::unique_ptr<ShellPlatformDelegate> platform) {
arthursonzogni75ede192021-07-06 14:45:46179 DCHECK(!g_platform);
danakjde3e2a02020-05-12 16:51:20180 g_platform = platform.release();
181 g_platform->Initialize(GetShellDefaultSize());
[email protected]6153b272013-01-25 22:29:23182}
183
arthursonzogni75ede192021-07-06 14:45:46184// static
185void Shell::Shutdown() {
186 if (!g_platform) // Shutdown has already been called.
187 return;
188
189 DevToolsAgentHost::DetachAllClients();
190
191 while (!Shell::windows().empty())
192 Shell::windows().back()->Close();
193
194 delete g_platform;
195 g_platform = nullptr;
196
197 for (auto it = RenderProcessHost::AllHostsIterator(); !it.IsAtEnd();
198 it.Advance()) {
W. James MacLean94cc84962021-09-07 21:51:40199 it.GetCurrentValue()->DisableRefCounts();
arthursonzogni75ede192021-07-06 14:45:46200 }
Lei Zhangebdd085d2022-10-25 17:24:26201 auto& quit_loop = GetMainMessageLoopQuitClosure();
202 if (quit_loop)
203 std::move(quit_loop).Run();
arthursonzogni75ede192021-07-06 14:45:46204
205 // Pump the message loop to allow window teardown tasks to run.
206 base::RunLoop().RunUntilIdle();
207}
208
[email protected]a2904092013-10-15 04:53:59209gfx::Size Shell::AdjustWindowSize(const gfx::Size& initial_size) {
210 if (!initial_size.IsEmpty())
211 return initial_size;
pdrcab84ee2015-03-13 21:47:04212 return GetShellDefaultSize();
[email protected]a2904092013-10-15 04:53:59213}
214
arthursonzogni75ede192021-07-06 14:45:46215// static
[email protected]bdcf9152012-07-19 17:43:21216Shell* Shell::CreateNewWindow(BrowserContext* browser_context,
[email protected]e99ca5112011-09-26 17:22:54217 const GURL& url,
lukasza04130152016-10-21 20:26:32218 const scoped_refptr<SiteInstance>& site_instance,
[email protected]cdb806722013-01-10 14:18:23219 const gfx::Size& initial_size) {
[email protected]54944cde2012-12-09 09:24:59220 WebContents::CreateParams create_params(browser_context, site_instance);
mark a. foltzef394fce2017-10-21 09:11:02221 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
222 switches::kForcePresentationReceiverForTesting)) {
Johann5a6cf012023-01-17 20:24:13223 create_params.starting_sandbox_flags = kPresentationReceiverSandboxFlags;
mark a. foltzef394fce2017-10-21 09:11:02224 }
erikchenbee5c9622018-04-27 19:30:25225 std::unique_ptr<WebContents> web_contents =
Erik Chenbb8e738e2018-04-28 14:10:43226 WebContents::Create(create_params);
erikchenbee5c9622018-04-27 19:30:25227 Shell* shell =
danakjfc5184932019-09-12 18:08:32228 CreateShell(std::move(web_contents), AdjustWindowSize(initial_size),
Bo Liu300c6052018-06-12 04:46:07229 true /* should_set_delegate */);
danakj7da833932020-06-23 21:49:40230
[email protected]e99ca5112011-09-26 17:22:54231 if (!url.is_empty())
232 shell->LoadURL(url);
[email protected]9fbd3f862011-09-20 23:31:34233 return shell;
234}
235
danakj3dd7a6102020-12-30 19:58:39236void Shell::RenderFrameCreated(RenderFrameHost* frame_host) {
Dave Tapuska327c06c92022-06-13 20:31:51237 if (frame_host == web_contents_->GetPrimaryMainFrame())
danakj3dd7a6102020-12-30 19:58:39238 g_platform->MainFrameCreated(this);
danakj24577b12020-05-13 22:38:18239}
240
[email protected]9fbd3f862011-09-20 23:31:34241void Shell::LoadURL(const GURL& url) {
Alex Moshchuk7e26eca2018-03-03 01:34:29242 LoadURLForFrame(
243 url, std::string(),
244 ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
245 ui::PAGE_TRANSITION_FROM_ADDRESS_BAR));
[email protected]d2494ff2013-02-20 08:22:37246}
247
Alex Moshchuk7e26eca2018-03-03 01:34:29248void Shell::LoadURLForFrame(const GURL& url,
249 const std::string& frame_name,
250 ui::PageTransition transition_type) {
[email protected]d2494ff2013-02-20 08:22:37251 NavigationController::LoadURLParams params(url);
[email protected]d2494ff2013-02-20 08:22:37252 params.frame_name = frame_name;
Alex Moshchuk7e26eca2018-03-03 01:34:29253 params.transition_type = transition_type;
[email protected]d2494ff2013-02-20 08:22:37254 web_contents_->GetController().LoadURLWithParams(params);
[email protected]9fbd3f862011-09-20 23:31:34255}
256
arthursonzogni75ede192021-07-06 14:45:46257void Shell::LoadDataWithBaseURL(const GURL& url,
258 const std::string& data,
259 const GURL& base_url) {
boliuec93ea92016-02-17 22:23:07260 bool load_as_string = false;
261 LoadDataWithBaseURLInternal(url, data, base_url, load_as_string);
262}
263
Xiaohan Wangbd084422022-01-15 18:47:51264#if BUILDFLAG(IS_ANDROID)
boliuec93ea92016-02-17 22:23:07265void Shell::LoadDataAsStringWithBaseURL(const GURL& url,
266 const std::string& data,
267 const GURL& base_url) {
268 bool load_as_string = true;
269 LoadDataWithBaseURLInternal(url, data, base_url, load_as_string);
270}
271#endif
272
273void Shell::LoadDataWithBaseURLInternal(const GURL& url,
274 const std::string& data,
275 const GURL& base_url,
276 bool load_as_string) {
Xiaohan Wangbd084422022-01-15 18:47:51277#if !BUILDFLAG(IS_ANDROID)
boliuec93ea92016-02-17 22:23:07278 DCHECK(!load_as_string); // Only supported on Android.
279#endif
280
Peter Kasting8104ba82024-01-31 15:23:40281 NavigationController::LoadURLParams params{GURL()};
boliuec93ea92016-02-17 22:23:07282 const std::string data_url_header = "data:text/html;charset=utf-8,";
283 if (load_as_string) {
284 params.url = GURL(data_url_header);
285 std::string data_url_as_string = data_url_header + data;
Xiaohan Wangbd084422022-01-15 18:47:51286#if BUILDFLAG(IS_ANDROID)
Jongmok Kimc5491082022-10-19 09:17:59287 params.data_url_as_string = base::MakeRefCounted<base::RefCountedString>(
288 std::move(data_url_as_string));
boliuec93ea92016-02-17 22:23:07289#endif
290 } else {
291 params.url = GURL(data_url_header + data);
292 }
293
[email protected]76bdecb2014-04-16 17:58:08294 params.load_type = NavigationController::LOAD_TYPE_DATA;
295 params.base_url_for_data_url = base_url;
Shu Yang112ad492024-07-25 17:11:54296 params.virtual_url_for_special_cases = url;
[email protected]76bdecb2014-04-16 17:58:08297 params.override_user_agent = NavigationController::UA_OVERRIDE_FALSE;
298 web_contents_->GetController().LoadURLWithParams(params);
[email protected]76bdecb2014-04-16 17:58:08299}
300
Dibyajyoti Pal3de66ad2024-08-23 23:34:03301WebContents* Shell::AddNewContents(
302 WebContents* source,
303 std::unique_ptr<WebContents> new_contents,
304 const GURL& target_url,
305 WindowOpenDisposition disposition,
306 const blink::mojom::WindowFeatures& window_features,
307 bool user_gesture,
308 bool* was_blocked) {
Tommy Steimel71f154462024-05-22 19:05:07309#if !BUILDFLAG(IS_ANDROID)
310 // If the shell is opening a document picture-in-picture window, it needs to
311 // inform the DocumentPictureInPictureWindowController.
312 if (disposition == WindowOpenDisposition::NEW_PICTURE_IN_PICTURE) {
313 DocumentPictureInPictureWindowController* controller =
314 PictureInPictureWindowController::
315 GetOrCreateDocumentPictureInPictureController(source);
316 controller->SetChildWebContents(new_contents.get());
317 controller->Show();
318 }
319#endif // !BUILDFLAG(IS_ANDROID)
320
Bo Liu300c6052018-06-12 04:46:07321 CreateShell(
Brad Triebwasser767c27a2022-08-25 22:56:05322 std::move(new_contents), AdjustWindowSize(window_features.bounds.size()),
Bo Liu300c6052018-06-12 04:46:07323 !delay_popup_contents_delegate_for_testing_ /* should_set_delegate */);
Dibyajyoti Pal3de66ad2024-08-23 23:34:03324 return nullptr;
[email protected]a2904092013-10-15 04:53:59325}
326
[email protected]9fbd3f862011-09-20 23:31:34327void Shell::GoBackOrForward(int offset) {
[email protected]0b659b32012-03-26 21:29:32328 web_contents_->GetController().GoToOffset(offset);
[email protected]9fbd3f862011-09-20 23:31:34329}
330
331void Shell::Reload() {
toyoshim6142d96f2016-12-19 09:07:25332 web_contents_->GetController().Reload(ReloadType::NORMAL, false);
[email protected]9fbd3f862011-09-20 23:31:34333}
334
toyoshime5aaf6a2016-05-18 08:07:48335void Shell::ReloadBypassingCache() {
toyoshim6142d96f2016-12-19 09:07:25336 web_contents_->GetController().Reload(ReloadType::BYPASSING_CACHE, false);
toyoshime5aaf6a2016-05-18 08:07:48337}
338
[email protected]9fbd3f862011-09-20 23:31:34339void Shell::Stop() {
[email protected]0b659b32012-03-26 21:29:32340 web_contents_->Stop();
[email protected]9fbd3f862011-09-20 23:31:34341}
342
Nate Chapin9aabf5f2021-11-12 00:31:19343void Shell::UpdateNavigationControls(bool should_show_loading_ui) {
[email protected]0b659b32012-03-26 21:29:32344 int current_index = web_contents_->GetController().GetCurrentEntryIndex();
345 int max_index = web_contents_->GetController().GetEntryCount() - 1;
[email protected]9fbd3f862011-09-20 23:31:34346
danakjde3e2a02020-05-12 16:51:20347 g_platform->EnableUIControl(this, ShellPlatformDelegate::BACK_BUTTON,
348 current_index > 0);
349 g_platform->EnableUIControl(this, ShellPlatformDelegate::FORWARD_BUTTON,
350 current_index < max_index);
351 g_platform->EnableUIControl(
352 this, ShellPlatformDelegate::STOP_BUTTON,
Nate Chapin9aabf5f2021-11-12 00:31:19353 should_show_loading_ui && web_contents_->IsLoading());
[email protected]9fbd3f862011-09-20 23:31:34354}
355
[email protected]7c17b6992012-08-09 16:16:30356void Shell::ShowDevTools() {
mohsen6eb57fb2016-07-22 03:14:08357 if (!devtools_frontend_) {
Dave Tapuska5198f0e2021-11-18 15:41:11358 auto* devtools_frontend = ShellDevToolsFrontend::Show(web_contents());
359 devtools_frontend_ = devtools_frontend->GetWeakPtr();
mohsen6eb57fb2016-07-22 03:14:08360 }
[email protected]3142e5d2014-02-07 00:54:46361
mohsen6eb57fb2016-07-22 03:14:08362 devtools_frontend_->Activate();
[email protected]7c17b6992012-08-09 16:16:30363}
364
[email protected]001841c92012-12-11 17:00:13365void Shell::CloseDevTools() {
[email protected]0773e0c2013-01-25 15:57:57366 if (!devtools_frontend_)
[email protected]001841c92012-12-11 17:00:13367 return;
[email protected]0773e0c2013-01-25 15:57:57368 devtools_frontend_->Close();
Ivan Kotenkov2c0d2bb32017-11-01 15:41:28369 devtools_frontend_ = nullptr;
[email protected]001841c92012-12-11 17:00:13370}
371
danakjde3e2a02020-05-12 16:51:20372void Shell::ResizeWebContentForTests(const gfx::Size& content_size) {
373 g_platform->ResizeWebContent(this, content_size);
374}
danakjde3e2a02020-05-12 16:51:20375
[email protected]9fbd3f862011-09-20 23:31:34376gfx::NativeView Shell::GetContentView() {
[email protected]59383c782013-04-17 16:43:27377 if (!web_contents_)
Avi Drissmandad01b0e2023-06-16 22:55:46378 return gfx::NativeView();
[email protected]fc2b46b2014-05-03 16:33:45379 return web_contents_->GetNativeView();
[email protected]9fbd3f862011-09-20 23:31:34380}
381
Xiaohan Wangbd084422022-01-15 18:47:51382#if !BUILDFLAG(IS_ANDROID)
danakjde3e2a02020-05-12 16:51:20383gfx::NativeWindow Shell::window() {
384 return g_platform->GetNativeWindow(this);
385}
386#endif
387
Xiaohan Wangbd084422022-01-15 18:47:51388#if BUILDFLAG(IS_MAC)
danakjde3e2a02020-05-12 16:51:20389void Shell::ActionPerformed(int control) {
390 switch (control) {
391 case IDC_NAV_BACK:
392 GoBackOrForward(-1);
393 break;
394 case IDC_NAV_FORWARD:
395 GoBackOrForward(1);
396 break;
397 case IDC_NAV_RELOAD:
398 Reload();
399 break;
400 case IDC_NAV_STOP:
401 Stop();
402 break;
403 }
404}
405
406void Shell::URLEntered(const std::string& url_string) {
407 if (!url_string.empty()) {
408 GURL url(url_string);
409 if (!url.has_scheme())
410 url = GURL("http://" + url_string);
411 LoadURL(url);
412 }
413}
414#endif
415
HuanPo Lin0d795c62024-03-28 03:54:05416WebContents* Shell::OpenURLFromTab(
417 WebContents* source,
418 const OpenURLParams& params,
419 base::OnceCallback<void(content::NavigationHandle&)>
420 navigation_handle_callback) {
lukasza04130152016-10-21 20:26:32421 WebContents* target = nullptr;
422 switch (params.disposition) {
423 case WindowOpenDisposition::CURRENT_TAB:
424 target = source;
425 break;
426
427 // Normally, the difference between NEW_POPUP and NEW_WINDOW is that a popup
428 // should have no toolbar, no status bar, no menu bar, no scrollbars and be
429 // not resizable. For simplicity and to enable new testing scenarios in
Kent Tamura21d1de62018-12-10 04:45:20430 // content shell and web tests, popups don't get special treatment below
lukasza04130152016-10-21 20:26:32431 // (i.e. they will have a toolbar and other things described here).
432 case WindowOpenDisposition::NEW_POPUP:
lukaszabe2f0da2017-04-25 00:43:00433 case WindowOpenDisposition::NEW_WINDOW:
Kent Tamura21d1de62018-12-10 04:45:20434 // content_shell doesn't really support tabs, but some web tests use
lukaszabe2f0da2017-04-25 00:43:00435 // middle click (which translates into kNavigationPolicyNewBackgroundTab),
436 // so we treat the cases below just like a NEW_WINDOW disposition.
437 case WindowOpenDisposition::NEW_BACKGROUND_TAB:
438 case WindowOpenDisposition::NEW_FOREGROUND_TAB: {
lukasza04130152016-10-21 20:26:32439 Shell* new_window =
440 Shell::CreateNewWindow(source->GetBrowserContext(),
441 GURL(), // Don't load anything just yet.
442 params.source_site_instance,
443 gfx::Size()); // Use default size.
444 target = new_window->web_contents();
lukasza04130152016-10-21 20:26:32445 break;
446 }
447
448 // No tabs in content_shell:
449 case WindowOpenDisposition::SINGLETON_TAB:
lukasza04130152016-10-21 20:26:32450 // No incognito mode in content_shell:
451 case WindowOpenDisposition::OFF_THE_RECORD:
Kent Tamura21d1de62018-12-10 04:45:20452 // TODO(lukasza): Investigate if some web tests might need support for
lukasza04130152016-10-21 20:26:32453 // SAVE_TO_DISK disposition. This would probably require that
Gyuyoung Kim26c7bc92020-04-29 00:53:00454 // WebTestControlHost always sets up and cleans up a temporary directory
lukasza04130152016-10-21 20:26:32455 // as the default downloads destinations for the duration of a test.
456 case WindowOpenDisposition::SAVE_TO_DISK:
457 // Ignoring requests with disposition == IGNORE_ACTION...
458 case WindowOpenDisposition::IGNORE_ACTION:
459 default:
460 return nullptr;
461 }
alexmos5a98a052016-01-06 00:15:02462
HuanPo Lin0d795c62024-03-28 03:54:05463 base::WeakPtr<NavigationHandle> navigation_handle =
464 target->GetController().LoadURLWithParams(
465 NavigationController::LoadURLParams(params));
466
467 if (navigation_handle_callback && navigation_handle) {
468 std::move(navigation_handle_callback).Run(*navigation_handle);
469 }
470
lukasza04130152016-10-21 20:26:32471 return target;
alexmos5a98a052016-01-06 00:15:02472}
473
[email protected]e3b10d12014-03-28 16:06:09474void Shell::LoadingStateChanged(WebContents* source,
Nate Chapin9aabf5f2021-11-12 00:31:19475 bool should_show_loading_ui) {
476 UpdateNavigationControls(should_show_loading_ui);
danakjde3e2a02020-05-12 16:51:20477 g_platform->SetIsLoading(this, source->IsLoading());
[email protected]e99ca5112011-09-26 17:22:54478}
479
Xiaohan Wangbd084422022-01-15 18:47:51480#if BUILDFLAG(IS_ANDROID)
danakjde3e2a02020-05-12 16:51:20481void Shell::SetOverlayMode(bool use_overlay_mode) {
482 g_platform->SetOverlayMode(this, use_overlay_mode);
483}
484#endif
485
Dave Tapuskaa4189512019-10-15 20:27:34486void Shell::EnterFullscreenModeForTab(
Mike Wasserman4ca09792020-05-29 17:44:43487 RenderFrameHost* requesting_frame,
Dave Tapuskaa4189512019-10-15 20:27:34488 const blink::mojom::FullscreenOptions& options) {
Mike Wasserman4ca09792020-05-29 17:44:43489 ToggleFullscreenModeForTab(WebContents::FromRenderFrameHost(requesting_frame),
490 true);
mlamouri7a78d6fd2015-01-17 13:23:53491}
492
493void Shell::ExitFullscreenModeForTab(WebContents* web_contents) {
494 ToggleFullscreenModeForTab(web_contents, false);
495}
496
[email protected]99c014c2012-11-27 12:03:42497void Shell::ToggleFullscreenModeForTab(WebContents* web_contents,
498 bool enter_fullscreen) {
Dave Tapuska1efc3012023-02-23 17:27:17499#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
danakjde3e2a02020-05-12 16:51:20500 g_platform->ToggleFullscreenModeForTab(this, web_contents, enter_fullscreen);
[email protected]99c014c2012-11-27 12:03:42501#endif
[email protected]99c014c2012-11-27 12:03:42502 if (is_fullscreen_ != enter_fullscreen) {
503 is_fullscreen_ = enter_fullscreen;
Dave Tapuska327c06c92022-06-13 20:31:51504 web_contents->GetPrimaryMainFrame()
Lucas Furukawa Gadanie7649422021-02-03 03:04:32505 ->GetRenderViewHost()
Fady Samuel0b911822018-04-25 13:22:16506 ->GetWidget()
507 ->SynchronizeVisualProperties();
[email protected]99c014c2012-11-27 12:03:42508 }
509}
510
Lucas Furukawa Gadani4909f3c2019-06-18 22:36:52511bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) {
Dave Tapuska1efc3012023-02-23 17:27:17512#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
danakjde3e2a02020-05-12 16:51:20513 return g_platform->IsFullscreenForTabOrPending(this, web_contents);
[email protected]99c014c2012-11-27 12:03:42514#else
515 return is_fullscreen_;
516#endif
517}
518
Eric Willigers052f0432019-10-04 04:06:57519blink::mojom::DisplayMode Shell::GetDisplayMode(
520 const WebContents* web_contents) {
521 // TODO: should return blink::mojom::DisplayModeFullscreen wherever user puts
Lukasz Anforowicz52b93722018-06-20 16:11:39522 // a browser window into fullscreen (not only in case of renderer-initiated
523 // fullscreen mode): crbug.com/476874.
524 return IsFullscreenForTabOrPending(web_contents)
Eric Willigers052f0432019-10-04 04:06:57525 ? blink::mojom::DisplayMode::kFullscreen
526 : blink::mojom::DisplayMode::kBrowser;
mikhail.pozdnyakovc0e251b2015-04-15 06:51:12527}
528
Javier Fernández García-Boente13150a042022-04-04 21:08:22529#if !BUILDFLAG(IS_ANDROID)
530void Shell::RegisterProtocolHandler(RenderFrameHost* requesting_frame,
531 const std::string& protocol,
532 const GURL& url,
533 bool user_gesture) {
Johann5a6cf012023-01-17 20:24:13534 BrowserContext* context = requesting_frame->GetBrowserContext();
Javier Fernández García-Boente13150a042022-04-04 21:08:22535 if (context->IsOffTheRecord())
536 return;
537
538 custom_handlers::ProtocolHandler handler =
539 custom_handlers::ProtocolHandler::CreateProtocolHandler(
540 protocol, url, GetProtocolHandlerSecurityLevel(requesting_frame));
541
542 // The parameters's normalization process defined in the spec has been already
543 // applied in the WebContentImpl class, so at this point it shouldn't be
544 // possible to create an invalid handler.
545 // https://html.spec.whatwg.org/multipage/system-state.html#normalize-protocol-handler-parameters
546 DCHECK(handler.IsValid());
547
548 custom_handlers::ProtocolHandlerRegistry* registry = custom_handlers::
549 SimpleProtocolHandlerRegistryFactory::GetForBrowserContext(context, true);
550 DCHECK(registry);
551 if (registry->SilentlyHandleRegisterHandlerRequest(handler))
552 return;
553
Javier Fernández García-Boentea2b1f18b2022-04-11 22:05:53554 if (!user_gesture && !windows_.empty()) {
555 // TODO(jfernandez): This is not strictly needed, but we need a way to
556 // inform the observers in browser tests that the request has been
557 // cancelled, to avoid timeouts. Chrome just holds the handler as pending in
558 // the PageContentSettingsDelegate, but we don't have such thing in the
559 // Content Shell.
560 registry->OnDenyRegisterProtocolHandler(handler);
561 return;
562 }
563
Javier Fernández García-Boente13150a042022-04-04 21:08:22564 // FencedFrames can not register to handle any protocols.
565 if (requesting_frame->IsNestedWithinFencedFrame()) {
566 registry->OnIgnoreRegisterProtocolHandler(handler);
567 return;
568 }
569
570 // TODO(jfernandez): Are we interested at all on using the
571 // PermissionRequestManager in the ContentShell ?
Javier Fernández García-Boentec0e70552023-02-03 09:41:13572 if (registry->registration_mode() ==
573 custom_handlers::RphRegistrationMode::kAutoAccept) {
574 registry->OnAcceptRegisterProtocolHandler(handler);
575 }
Javier Fernández García-Boente13150a042022-04-04 21:08:22576}
577#endif
578
Takumi Fujimoto4661871d2024-01-25 02:04:18579void Shell::RequestPointerLock(WebContents* web_contents,
[email protected]f78439002012-11-28 14:45:59580 bool user_gesture,
581 bool last_unlocked_by_target) {
Dave Tapuskab4998782020-10-08 17:22:47582 // Give the platform a chance to handle the lock request, if it doesn't
583 // indicate it handled it, allow the request.
Takumi Fujimoto4661871d2024-01-25 02:04:18584 if (!g_platform->HandlePointerLockRequest(this, web_contents, user_gesture,
Dave Tapuskab4998782020-10-08 17:22:47585 last_unlocked_by_target)) {
Takumi Fujimoto4661871d2024-01-25 02:04:18586 web_contents->GotResponseToPointerLockRequest(
Dave Tapuskab4998782020-10-08 17:22:47587 blink::mojom::PointerLockResult::kSuccess);
588 }
[email protected]f78439002012-11-28 14:45:59589}
590
danakjde3e2a02020-05-12 16:51:20591void Shell::Close() {
592 // Shell is "self-owned" and destroys itself. The ShellPlatformDelegate
593 // has the chance to co-opt this and do its own destruction.
594 if (!g_platform->DestroyShell(this))
595 delete this;
596}
597
[email protected]9e00e6352012-07-30 17:05:18598void Shell::CloseContents(WebContents* source) {
599 Close();
600}
601
Lucas Furukawa Gadani4909f3c2019-06-18 22:36:52602bool Shell::CanOverscrollContent() {
[email protected]067310262012-11-22 14:30:41603#if defined(USE_AURA)
604 return true;
605#else
606 return false;
607#endif
608}
609
Mugdha Lakhani5f8de7cc2020-03-10 20:43:36610void Shell::NavigationStateChanged(WebContents* source,
611 InvalidateTypes changed_flags) {
612 if (changed_flags & INVALIDATE_TYPE_URL)
danakjde3e2a02020-05-12 16:51:20613 g_platform->SetAddressBarURL(this, source->GetVisibleURL());
[email protected]e99ca5112011-09-26 17:22:54614}
615
mathiash72a5e462014-11-19 08:18:50616JavaScriptDialogManager* Shell::GetJavaScriptDialogManager(
617 WebContents* source) {
danakj8de3b7492020-07-02 22:41:42618 if (!dialog_manager_)
619 dialog_manager_ = g_platform->CreateJavaScriptDialogManager(this);
620 if (!dialog_manager_)
621 dialog_manager_ = std::make_unique<ShellJavaScriptDialogManager>();
[email protected]71a88bb2013-02-01 22:05:15622 return dialog_manager_.get();
[email protected]f2210022012-03-29 00:36:08623}
624
Xiaohan Wangbd084422022-01-15 18:47:51625#if BUILDFLAG(IS_MAC)
Johann5a6cf012023-01-17 20:24:13626void Shell::PrimaryPageChanged(Page& page) {
Julie Jeongeun Kimc37853f2022-12-16 11:00:32627 g_platform->DidNavigatePrimaryMainFramePostCommit(
Johann5a6cf012023-01-17 20:24:13628 this, WebContents::FromRenderFrameHost(&page.GetMainDocument()));
Xianzhu Wang0f021a82020-07-03 01:29:47629}
630
danakjde3e2a02020-05-12 16:51:20631bool Shell::HandleKeyboardEvent(WebContents* source,
Kartar Singh5c8e0b22024-05-30 10:32:14632 const input::NativeWebKeyboardEvent& event) {
danakjde3e2a02020-05-12 16:51:20633 return g_platform->HandleKeyboardEvent(this, source, event);
634}
635#endif
636
avia90ae4e2016-11-11 20:49:33637bool Shell::DidAddMessageToConsole(WebContents* source,
Lowell Manners1de5242e2019-04-25 10:18:46638 blink::mojom::ConsoleMessageLevel log_level,
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58639 const std::u16string& message,
avia90ae4e2016-11-11 20:49:33640 int32_t line_no,
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58641 const std::u16string& source_id) {
Kent Tamuracd3ebc42018-05-16 06:44:22642 return switches::IsRunWebTestsSwitchPresent();
[email protected]efb5f572012-01-29 10:57:33643}
644
Lukasz Anforowicz52b93722018-06-20 16:11:39645void Shell::RendererUnresponsive(
646 WebContents* source,
647 RenderWidgetHost* render_widget_host,
648 base::RepeatingClosure hang_monitor_restarter) {
danakj245441f2020-07-03 15:18:41649 LOG(WARNING) << "renderer unresponsive";
[email protected]5bf68f22012-08-31 07:38:10650}
651
[email protected]233567d2013-02-27 20:22:02652void Shell::ActivateContents(WebContents* contents) {
Xiaohan Wangbd084422022-01-15 18:47:51653#if !BUILDFLAG(IS_MAC)
danakjd4b48df52020-07-02 18:16:48654 // TODO(danakj): Move this to ShellPlatformDelegate.
danakj674bf1c02020-05-01 18:37:51655 contents->Focus();
656#else
657 // Mac headless mode is quite different than other platforms. Normally
658 // focusing the WebContents would cause the OS to focus the window. Because
659 // headless mac doesn't actually have system windows, we can't go down the
660 // normal path and have to fake it out in the browser process.
danakjde3e2a02020-05-12 16:51:20661 g_platform->ActivateContents(this, contents);
danakj674bf1c02020-05-01 18:37:51662#endif
[email protected]233567d2013-02-27 20:22:02663}
664
Tom Burginf0e48622024-05-16 15:06:12665#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
Julie Jeongeun Kim88ce9ec2023-07-28 02:25:40666std::unique_ptr<ColorChooser> Shell::OpenColorChooser(
667 WebContents* web_contents,
668 SkColor color,
669 const std::vector<blink::mojom::ColorSuggestionPtr>& suggestions) {
670 return g_platform->OpenColorChooser(web_contents, color, suggestions);
671}
672#endif
673
Julie Jeongeun Kimec508272023-03-17 04:17:12674void Shell::RunFileChooser(RenderFrameHost* render_frame_host,
675 scoped_refptr<FileSelectListener> listener,
676 const blink::mojom::FileChooserParams& params) {
Bo Liu3afe2582023-08-11 23:02:56677 run_file_chooser_count_++;
678 if (hold_file_chooser_) {
679 held_file_chooser_listener_ = std::move(listener);
680 } else {
681 g_platform->RunFileChooser(render_frame_host, std::move(listener), params);
682 }
683}
684
685void Shell::EnumerateDirectory(WebContents* web_contents,
686 scoped_refptr<FileSelectListener> listener,
687 const base::FilePath& path) {
688 run_file_chooser_count_++;
689 if (hold_file_chooser_) {
690 held_file_chooser_listener_ = std::move(listener);
691 } else {
692 listener->FileSelectionCanceled();
693 }
Julie Jeongeun Kimec508272023-03-17 04:17:12694}
695
Jiacheng Guo3168d132024-05-31 04:31:06696bool Shell::IsBackForwardCacheSupported(WebContents& web_contents) {
Dave Tapuskadfff7382021-04-23 19:46:41697 return true;
698}
699
Johanna0b3e9b2023-01-19 23:23:35700PreloadingEligibility Shell::IsPrerender2Supported(WebContents& web_contents) {
701 return PreloadingEligibility::kEligible;
Lingqi Chi8159aec2021-06-15 01:46:03702}
703
Adithya Srinivasanb7204c82020-08-17 14:26:33704namespace {
705class PendingCallback : public base::RefCounted<PendingCallback> {
706 public:
707 explicit PendingCallback(base::OnceCallback<void()> cb)
708 : callback_(std::move(cb)) {}
709
710 private:
711 friend class base::RefCounted<PendingCallback>;
712 ~PendingCallback() { std::move(callback_).Run(); }
713 base::OnceCallback<void()> callback_;
714};
715} // namespace
716
Lukasz Anforowicz82a5ca92019-10-24 18:45:37717bool Shell::ShouldAllowRunningInsecureContent(WebContents* web_contents,
718 bool allowed_per_prefs,
719 const url::Origin& origin,
720 const GURL& resource_url) {
danakj8de3b7492020-07-02 22:41:42721 if (allowed_per_prefs)
722 return true;
carloskd9d97942017-02-16 08:58:09723
danakj8de3b7492020-07-02 22:41:42724 return g_platform->ShouldAllowRunningInsecureContent(this);
carloskd9d97942017-02-16 08:58:09725}
726
François Beaufort1388f2892022-01-29 08:22:47727PictureInPictureResult Shell::EnterPictureInPicture(WebContents* web_contents) {
Becca Hughes112832e2019-06-11 17:19:02728 // During tests, returning success to pretend the window was created and allow
729 // tests to run accordingly.
730 if (!switches::IsRunWebTestsSwitchPresent())
731 return PictureInPictureResult::kNotSupported;
Becca Hughes112832e2019-06-11 17:19:02732 return PictureInPictureResult::kSuccess;
Mounir Lamouri11e9ef432018-05-22 03:10:16733}
734
Bo Liu300c6052018-06-12 04:46:07735bool Shell::ShouldResumeRequestsForCreatedWindow() {
736 return !delay_popup_contents_delegate_for_testing_;
737}
738
danakjee2390a82020-06-10 16:53:37739void Shell::SetContentsBounds(WebContents* source, const gfx::Rect& bounds) {
740 DCHECK(source == web_contents()); // There's only one WebContents per Shell.
741
742 if (switches::IsRunWebTestsSwitchPresent()) {
743 // Note that chrome drops these requests on normal windows.
744 // TODO(danakj): The position is dropped here but we use the size. Web tests
745 // can't move the window in headless mode anyways, but maybe we should be
746 // letting them pretend?
747 g_platform->ResizeWebContent(this, bounds.size());
748 }
749}
750
pdrcab84ee2015-03-13 21:47:04751gfx::Size Shell::GetShellDefaultSize() {
danakj6c16fe92020-09-18 23:51:32752 static gfx::Size default_shell_size; // Only go through this method once.
753
pdrcab84ee2015-03-13 21:47:04754 if (!default_shell_size.IsEmpty())
755 return default_shell_size;
danakj6c16fe92020-09-18 23:51:32756
pdrcab84ee2015-03-13 21:47:04757 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
758 if (command_line->HasSwitch(switches::kContentShellHostWindowSize)) {
759 const std::string size_str = command_line->GetSwitchValueASCII(
arthursonzogni75ede192021-07-06 14:45:46760 switches::kContentShellHostWindowSize);
pdrcab84ee2015-03-13 21:47:04761 int width, height;
danakj6c16fe92020-09-18 23:51:32762 if (sscanf(size_str.c_str(), "%dx%d", &width, &height) == 2) {
763 default_shell_size = gfx::Size(width, height);
764 } else {
765 LOG(ERROR) << "Invalid size \"" << size_str << "\" given to --"
766 << switches::kContentShellHostWindowSize;
767 }
768 }
769
770 if (default_shell_size.IsEmpty()) {
arthursonzogni75ede192021-07-06 14:45:46771 default_shell_size =
772 gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip);
pdrcab84ee2015-03-13 21:47:04773 }
danakj6c16fe92020-09-18 23:51:32774
pdrcab84ee2015-03-13 21:47:04775 return default_shell_size;
776}
777
Xiaohan Wangbd084422022-01-15 18:47:51778#if BUILDFLAG(IS_ANDROID)
danakjde3e2a02020-05-12 16:51:20779void Shell::LoadProgressChanged(double progress) {
780 g_platform->LoadProgressChanged(this, progress);
781}
782#endif
783
Avi Drissman93002212017-09-27 03:20:52784void Shell::TitleWasSet(NavigationEntry* entry) {
[email protected]1ef02d242013-10-07 16:18:53785 if (entry)
danakjde3e2a02020-05-12 16:51:20786 g_platform->SetTitle(this, entry->GetTitle());
[email protected]aecc085b2012-06-01 18:15:53787}
788
[email protected]9fbd3f862011-09-20 23:31:34789} // namespace content