1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/shell/browser/shell.h"
7 #include "base/auto_reset.h"
8 #include "base/command_line.h"
9 #include "base/location.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "content/public/browser/devtools_agent_host.h"
17 #include "content/public/browser/navigation_controller.h"
18 #include "content/public/browser/navigation_entry.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/browser/web_contents_observer.h"
22 #include "content/public/common/renderer_preferences.h"
23 #include "content/shell/browser/blink_test_controller.h"
24 #include "content/shell/browser/layout_test/layout_test_bluetooth_chooser_factory.h"
25 #include "content/shell/browser/layout_test/layout_test_devtools_frontend.h"
26 #include "content/shell/browser/layout_test/layout_test_javascript_dialog_manager.h"
27 #include "content/shell/browser/notify_done_forwarder.h"
28 #include "content/shell/browser/shell_browser_main_parts.h"
29 #include "content/shell/browser/shell_content_browser_client.h"
30 #include "content/shell/browser/shell_devtools_frontend.h"
31 #include "content/shell/browser/shell_javascript_dialog_manager.h"
32 #include "content/shell/common/shell_messages.h"
33 #include "content/shell/common/shell_switches.h"
37 const int kDefaultTestWindowWidthDip
= 800;
38 const int kDefaultTestWindowHeightDip
= 600;
40 std::vector
<Shell
*> Shell::windows_
;
41 base::Callback
<void(Shell
*)> Shell::shell_created_callback_
;
43 bool Shell::quit_message_loop_
= true;
45 class Shell::DevToolsWebContentsObserver
: public WebContentsObserver
{
47 DevToolsWebContentsObserver(Shell
* shell
, WebContents
* web_contents
)
48 : WebContentsObserver(web_contents
),
52 // WebContentsObserver
53 void WebContentsDestroyed() override
{
54 shell_
->OnDevToolsWebContentsDestroyed();
60 DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver
);
63 Shell::Shell(WebContents
* web_contents
)
64 : WebContentsObserver(web_contents
),
65 devtools_frontend_(NULL
),
66 is_fullscreen_(false),
70 const base::CommandLine
& command_line
=
71 *base::CommandLine::ForCurrentProcess();
72 if (command_line
.HasSwitch(switches::kRunLayoutTest
))
74 windows_
.push_back(this);
76 if (!shell_created_callback_
.is_null()) {
77 shell_created_callback_
.Run(this);
78 shell_created_callback_
.Reset();
85 for (size_t i
= 0; i
< windows_
.size(); ++i
) {
86 if (windows_
[i
] == this) {
87 windows_
.erase(windows_
.begin() + i
);
92 if (windows_
.empty() && quit_message_loop_
) {
95 base::ThreadTaskRunnerHandle::Get()->PostTask(
96 FROM_HERE
, base::MessageLoop::QuitClosure());
100 Shell
* Shell::CreateShell(WebContents
* web_contents
,
101 const gfx::Size
& initial_size
) {
102 Shell
* shell
= new Shell(web_contents
);
103 shell
->PlatformCreateWindow(initial_size
.width(), initial_size
.height());
105 shell
->web_contents_
.reset(web_contents
);
106 web_contents
->SetDelegate(shell
);
108 shell
->PlatformSetContents();
110 shell
->PlatformResizeSubViews();
112 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
113 switches::kRunLayoutTest
)) {
114 web_contents
->GetMutableRendererPrefs()->use_custom_colors
= false;
115 web_contents
->GetRenderViewHost()->SyncRendererPrefs();
121 void Shell::CloseAllWindows() {
122 base::AutoReset
<bool> auto_reset(&quit_message_loop_
, false);
123 DevToolsAgentHost::DetachAllClients();
124 std::vector
<Shell
*> open_windows(windows_
);
125 for (size_t i
= 0; i
< open_windows
.size(); ++i
)
126 open_windows
[i
]->Close();
127 base::MessageLoop::current()->RunUntilIdle();
131 void Shell::SetShellCreatedCallback(
132 base::Callback
<void(Shell
*)> shell_created_callback
) {
133 DCHECK(shell_created_callback_
.is_null());
134 shell_created_callback_
= shell_created_callback
;
137 Shell
* Shell::FromRenderViewHost(RenderViewHost
* rvh
) {
138 for (size_t i
= 0; i
< windows_
.size(); ++i
) {
139 if (windows_
[i
]->web_contents() &&
140 windows_
[i
]->web_contents()->GetRenderViewHost() == rvh
) {
148 void Shell::Initialize() {
149 PlatformInitialize(GetShellDefaultSize());
152 gfx::Size
Shell::AdjustWindowSize(const gfx::Size
& initial_size
) {
153 if (!initial_size
.IsEmpty())
155 return GetShellDefaultSize();
158 Shell
* Shell::CreateNewWindow(BrowserContext
* browser_context
,
160 SiteInstance
* site_instance
,
161 const gfx::Size
& initial_size
) {
162 WebContents::CreateParams
create_params(browser_context
, site_instance
);
163 create_params
.initial_size
= AdjustWindowSize(initial_size
);
164 WebContents
* web_contents
= WebContents::Create(create_params
);
165 Shell
* shell
= CreateShell(web_contents
, create_params
.initial_size
);
171 void Shell::LoadURL(const GURL
& url
) {
172 LoadURLForFrame(url
, std::string());
175 void Shell::LoadURLForFrame(const GURL
& url
, const std::string
& frame_name
) {
176 NavigationController::LoadURLParams
params(url
);
177 params
.transition_type
= ui::PageTransitionFromInt(
178 ui::PAGE_TRANSITION_TYPED
| ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
);
179 params
.frame_name
= frame_name
;
180 web_contents_
->GetController().LoadURLWithParams(params
);
181 web_contents_
->Focus();
184 void Shell::LoadDataWithBaseURL(const GURL
& url
, const std::string
& data
,
185 const GURL
& base_url
) {
186 const GURL data_url
= GURL("data:text/html;charset=utf-8," + data
);
187 NavigationController::LoadURLParams
params(data_url
);
188 params
.load_type
= NavigationController::LOAD_TYPE_DATA
;
189 params
.base_url_for_data_url
= base_url
;
190 params
.virtual_url_for_data_url
= url
;
191 params
.override_user_agent
= NavigationController::UA_OVERRIDE_FALSE
;
192 web_contents_
->GetController().LoadURLWithParams(params
);
193 web_contents_
->Focus();
196 void Shell::AddNewContents(WebContents
* source
,
197 WebContents
* new_contents
,
198 WindowOpenDisposition disposition
,
199 const gfx::Rect
& initial_rect
,
202 CreateShell(new_contents
, AdjustWindowSize(initial_rect
.size()));
203 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
204 switches::kRunLayoutTest
))
205 NotifyDoneForwarder::CreateForWebContents(new_contents
);
208 void Shell::GoBackOrForward(int offset
) {
209 web_contents_
->GetController().GoToOffset(offset
);
210 web_contents_
->Focus();
213 void Shell::Reload() {
214 web_contents_
->GetController().Reload(false);
215 web_contents_
->Focus();
219 web_contents_
->Stop();
220 web_contents_
->Focus();
223 void Shell::UpdateNavigationControls(bool to_different_document
) {
224 int current_index
= web_contents_
->GetController().GetCurrentEntryIndex();
225 int max_index
= web_contents_
->GetController().GetEntryCount() - 1;
227 PlatformEnableUIControl(BACK_BUTTON
, current_index
> 0);
228 PlatformEnableUIControl(FORWARD_BUTTON
, current_index
< max_index
);
229 PlatformEnableUIControl(STOP_BUTTON
,
230 to_different_document
&& web_contents_
->IsLoading());
233 void Shell::ShowDevTools() {
237 void Shell::ShowDevToolsForElementAt(int x
, int y
) {
239 devtools_frontend_
->InspectElementAt(x
, y
);
242 void Shell::CloseDevTools() {
243 if (!devtools_frontend_
)
245 devtools_observer_
.reset();
246 devtools_frontend_
->Close();
247 devtools_frontend_
= NULL
;
250 gfx::NativeView
Shell::GetContentView() {
253 return web_contents_
->GetNativeView();
256 WebContents
* Shell::OpenURLFromTab(WebContents
* source
,
257 const OpenURLParams
& params
) {
258 // CURRENT_TAB is the only one we implement for now.
259 if (params
.disposition
!= CURRENT_TAB
)
261 NavigationController::LoadURLParams
load_url_params(params
.url
);
262 load_url_params
.source_site_instance
= params
.source_site_instance
;
263 load_url_params
.referrer
= params
.referrer
;
264 load_url_params
.frame_tree_node_id
= params
.frame_tree_node_id
;
265 load_url_params
.transition_type
= params
.transition
;
266 load_url_params
.extra_headers
= params
.extra_headers
;
267 load_url_params
.should_replace_current_entry
=
268 params
.should_replace_current_entry
;
270 if (params
.transferred_global_request_id
!= GlobalRequestID()) {
271 load_url_params
.is_renderer_initiated
= params
.is_renderer_initiated
;
272 load_url_params
.transferred_global_request_id
=
273 params
.transferred_global_request_id
;
274 } else if (params
.is_renderer_initiated
) {
275 load_url_params
.is_renderer_initiated
= true;
278 source
->GetController().LoadURLWithParams(load_url_params
);
282 void Shell::LoadingStateChanged(WebContents
* source
,
283 bool to_different_document
) {
284 UpdateNavigationControls(to_different_document
);
285 PlatformSetIsLoading(source
->IsLoading());
288 void Shell::EnterFullscreenModeForTab(WebContents
* web_contents
,
289 const GURL
& origin
) {
290 ToggleFullscreenModeForTab(web_contents
, true);
293 void Shell::ExitFullscreenModeForTab(WebContents
* web_contents
) {
294 ToggleFullscreenModeForTab(web_contents
, false);
297 void Shell::ToggleFullscreenModeForTab(WebContents
* web_contents
,
298 bool enter_fullscreen
) {
299 #if defined(OS_ANDROID)
300 PlatformToggleFullscreenModeForTab(web_contents
, enter_fullscreen
);
302 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
303 switches::kRunLayoutTest
))
305 if (is_fullscreen_
!= enter_fullscreen
) {
306 is_fullscreen_
= enter_fullscreen
;
307 web_contents
->GetRenderViewHost()->WasResized();
311 bool Shell::IsFullscreenForTabOrPending(const WebContents
* web_contents
) const {
312 #if defined(OS_ANDROID)
313 return PlatformIsFullscreenForTabOrPending(web_contents
);
315 return is_fullscreen_
;
319 blink::WebDisplayMode
Shell::GetDisplayMode(
320 const WebContents
* web_contents
) const {
321 // TODO : should return blink::WebDisplayModeFullscreen wherever user puts
322 // a browser window into fullscreen (not only in case of renderer-initiated
323 // fullscreen mode): crbug.com/476874.
324 return IsFullscreenForTabOrPending(web_contents
) ?
325 blink::WebDisplayModeFullscreen
: blink::WebDisplayModeBrowser
;
328 void Shell::RequestToLockMouse(WebContents
* web_contents
,
330 bool last_unlocked_by_target
) {
331 web_contents
->GotResponseToLockMouseRequest(true);
334 void Shell::CloseContents(WebContents
* source
) {
338 bool Shell::CanOverscrollContent() const {
339 #if defined(USE_AURA)
346 void Shell::DidNavigateMainFramePostCommit(WebContents
* web_contents
) {
347 PlatformSetAddressBarURL(web_contents
->GetLastCommittedURL());
350 JavaScriptDialogManager
* Shell::GetJavaScriptDialogManager(
351 WebContents
* source
) {
352 if (!dialog_manager_
) {
353 const base::CommandLine
& command_line
=
354 *base::CommandLine::ForCurrentProcess();
355 dialog_manager_
.reset(command_line
.HasSwitch(switches::kRunLayoutTest
)
356 ? new LayoutTestJavaScriptDialogManager
357 : new ShellJavaScriptDialogManager
);
359 return dialog_manager_
.get();
362 scoped_ptr
<BluetoothChooser
> Shell::RunBluetoothChooser(
363 WebContents
* web_contents
,
364 const BluetoothChooser::EventHandler
& event_handler
,
365 const GURL
& origin
) {
366 const base::CommandLine
& command_line
=
367 *base::CommandLine::ForCurrentProcess();
368 if (command_line
.HasSwitch(switches::kRunLayoutTest
)) {
369 return BlinkTestController::Get()->RunBluetoothChooser(
370 web_contents
, event_handler
, origin
);
375 bool Shell::AddMessageToConsole(WebContents
* source
,
377 const base::string16
& message
,
379 const base::string16
& source_id
) {
380 return base::CommandLine::ForCurrentProcess()->HasSwitch(
381 switches::kRunLayoutTest
);
384 void Shell::RendererUnresponsive(WebContents
* source
) {
385 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
386 switches::kRunLayoutTest
))
388 BlinkTestController::Get()->RendererUnresponsive();
391 void Shell::ActivateContents(WebContents
* contents
) {
392 contents
->GetRenderViewHost()->Focus();
395 void Shell::DeactivateContents(WebContents
* contents
) {
396 contents
->GetRenderViewHost()->Blur();
399 bool Shell::HandleContextMenu(const content::ContextMenuParams
& params
) {
400 return PlatformHandleContextMenu(params
);
403 gfx::Size
Shell::GetShellDefaultSize() {
404 static gfx::Size default_shell_size
;
405 if (!default_shell_size
.IsEmpty())
406 return default_shell_size
;
407 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
408 if (command_line
->HasSwitch(switches::kContentShellHostWindowSize
)) {
409 const std::string size_str
= command_line
->GetSwitchValueASCII(
410 switches::kContentShellHostWindowSize
);
412 CHECK_EQ(2, sscanf(size_str
.c_str(), "%dx%d", &width
, &height
));
413 default_shell_size
= gfx::Size(width
, height
);
415 default_shell_size
= gfx::Size(
416 kDefaultTestWindowWidthDip
, kDefaultTestWindowHeightDip
);
418 return default_shell_size
;
421 void Shell::TitleWasSet(NavigationEntry
* entry
, bool explicit_set
) {
423 PlatformSetTitle(entry
->GetTitle());
426 void Shell::InnerShowDevTools() {
427 if (!devtools_frontend_
) {
428 devtools_frontend_
= ShellDevToolsFrontend::Show(web_contents());
429 devtools_observer_
.reset(new DevToolsWebContentsObserver(
430 this, devtools_frontend_
->frontend_shell()->web_contents()));
433 devtools_frontend_
->Activate();
434 devtools_frontend_
->Focus();
437 void Shell::OnDevToolsWebContentsDestroyed() {
438 devtools_observer_
.reset();
439 devtools_frontend_
= NULL
;
442 } // namespace content