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_devtools_frontend.h"
25 #include "content/shell/browser/layout_test/layout_test_javascript_dialog_manager.h"
26 #include "content/shell/browser/notify_done_forwarder.h"
27 #include "content/shell/browser/shell_browser_main_parts.h"
28 #include "content/shell/browser/shell_content_browser_client.h"
29 #include "content/shell/browser/shell_devtools_frontend.h"
30 #include "content/shell/browser/shell_javascript_dialog_manager.h"
31 #include "content/shell/common/shell_messages.h"
32 #include "content/shell/common/shell_switches.h"
36 const int kDefaultTestWindowWidthDip
= 800;
37 const int kDefaultTestWindowHeightDip
= 600;
39 std::vector
<Shell
*> Shell::windows_
;
40 base::Callback
<void(Shell
*)> Shell::shell_created_callback_
;
42 bool Shell::quit_message_loop_
= true;
44 class Shell::DevToolsWebContentsObserver
: public WebContentsObserver
{
46 DevToolsWebContentsObserver(Shell
* shell
, WebContents
* web_contents
)
47 : WebContentsObserver(web_contents
),
51 // WebContentsObserver
52 void WebContentsDestroyed() override
{
53 shell_
->OnDevToolsWebContentsDestroyed();
59 DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver
);
62 Shell::Shell(WebContents
* web_contents
)
63 : WebContentsObserver(web_contents
),
64 devtools_frontend_(NULL
),
65 is_fullscreen_(false),
69 const base::CommandLine
& command_line
=
70 *base::CommandLine::ForCurrentProcess();
71 if (command_line
.HasSwitch(switches::kRunLayoutTest
))
73 windows_
.push_back(this);
75 if (!shell_created_callback_
.is_null()) {
76 shell_created_callback_
.Run(this);
77 shell_created_callback_
.Reset();
84 for (size_t i
= 0; i
< windows_
.size(); ++i
) {
85 if (windows_
[i
] == this) {
86 windows_
.erase(windows_
.begin() + i
);
91 if (windows_
.empty() && quit_message_loop_
) {
94 base::ThreadTaskRunnerHandle::Get()->PostTask(
95 FROM_HERE
, base::MessageLoop::QuitClosure());
99 Shell
* Shell::CreateShell(WebContents
* web_contents
,
100 const gfx::Size
& initial_size
) {
101 Shell
* shell
= new Shell(web_contents
);
102 shell
->PlatformCreateWindow(initial_size
.width(), initial_size
.height());
104 shell
->web_contents_
.reset(web_contents
);
105 web_contents
->SetDelegate(shell
);
107 shell
->PlatformSetContents();
109 shell
->PlatformResizeSubViews();
111 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
112 switches::kRunLayoutTest
)) {
113 web_contents
->GetMutableRendererPrefs()->use_custom_colors
= false;
114 web_contents
->GetRenderViewHost()->SyncRendererPrefs();
120 void Shell::CloseAllWindows() {
121 base::AutoReset
<bool> auto_reset(&quit_message_loop_
, false);
122 DevToolsAgentHost::DetachAllClients();
123 std::vector
<Shell
*> open_windows(windows_
);
124 for (size_t i
= 0; i
< open_windows
.size(); ++i
)
125 open_windows
[i
]->Close();
126 base::MessageLoop::current()->RunUntilIdle();
130 void Shell::SetShellCreatedCallback(
131 base::Callback
<void(Shell
*)> shell_created_callback
) {
132 DCHECK(shell_created_callback_
.is_null());
133 shell_created_callback_
= shell_created_callback
;
136 Shell
* Shell::FromRenderViewHost(RenderViewHost
* rvh
) {
137 for (size_t i
= 0; i
< windows_
.size(); ++i
) {
138 if (windows_
[i
]->web_contents() &&
139 windows_
[i
]->web_contents()->GetRenderViewHost() == rvh
) {
147 void Shell::Initialize() {
148 PlatformInitialize(GetShellDefaultSize());
151 gfx::Size
Shell::AdjustWindowSize(const gfx::Size
& initial_size
) {
152 if (!initial_size
.IsEmpty())
154 return GetShellDefaultSize();
157 Shell
* Shell::CreateNewWindow(BrowserContext
* browser_context
,
159 SiteInstance
* site_instance
,
160 const gfx::Size
& initial_size
) {
161 WebContents::CreateParams
create_params(browser_context
, site_instance
);
162 create_params
.initial_size
= AdjustWindowSize(initial_size
);
163 WebContents
* web_contents
= WebContents::Create(create_params
);
164 Shell
* shell
= CreateShell(web_contents
, create_params
.initial_size
);
170 void Shell::LoadURL(const GURL
& url
) {
171 LoadURLForFrame(url
, std::string());
174 void Shell::LoadURLForFrame(const GURL
& url
, const std::string
& frame_name
) {
175 NavigationController::LoadURLParams
params(url
);
176 params
.transition_type
= ui::PageTransitionFromInt(
177 ui::PAGE_TRANSITION_TYPED
| ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
);
178 params
.frame_name
= frame_name
;
179 web_contents_
->GetController().LoadURLWithParams(params
);
180 web_contents_
->Focus();
183 void Shell::LoadDataWithBaseURL(const GURL
& url
, const std::string
& data
,
184 const GURL
& base_url
) {
185 const GURL data_url
= GURL("data:text/html;charset=utf-8," + data
);
186 NavigationController::LoadURLParams
params(data_url
);
187 params
.load_type
= NavigationController::LOAD_TYPE_DATA
;
188 params
.base_url_for_data_url
= base_url
;
189 params
.virtual_url_for_data_url
= url
;
190 params
.override_user_agent
= NavigationController::UA_OVERRIDE_FALSE
;
191 web_contents_
->GetController().LoadURLWithParams(params
);
192 web_contents_
->Focus();
195 void Shell::AddNewContents(WebContents
* source
,
196 WebContents
* new_contents
,
197 WindowOpenDisposition disposition
,
198 const gfx::Rect
& initial_rect
,
201 CreateShell(new_contents
, AdjustWindowSize(initial_rect
.size()));
202 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
203 switches::kRunLayoutTest
))
204 NotifyDoneForwarder::CreateForWebContents(new_contents
);
207 void Shell::GoBackOrForward(int offset
) {
208 web_contents_
->GetController().GoToOffset(offset
);
209 web_contents_
->Focus();
212 void Shell::Reload() {
213 web_contents_
->GetController().Reload(false);
214 web_contents_
->Focus();
218 web_contents_
->Stop();
219 web_contents_
->Focus();
222 void Shell::UpdateNavigationControls(bool to_different_document
) {
223 int current_index
= web_contents_
->GetController().GetCurrentEntryIndex();
224 int max_index
= web_contents_
->GetController().GetEntryCount() - 1;
226 PlatformEnableUIControl(BACK_BUTTON
, current_index
> 0);
227 PlatformEnableUIControl(FORWARD_BUTTON
, current_index
< max_index
);
228 PlatformEnableUIControl(STOP_BUTTON
,
229 to_different_document
&& web_contents_
->IsLoading());
232 void Shell::ShowDevTools() {
236 void Shell::ShowDevToolsForElementAt(int x
, int y
) {
238 devtools_frontend_
->InspectElementAt(x
, y
);
241 void Shell::CloseDevTools() {
242 if (!devtools_frontend_
)
244 devtools_observer_
.reset();
245 devtools_frontend_
->Close();
246 devtools_frontend_
= NULL
;
249 gfx::NativeView
Shell::GetContentView() {
252 return web_contents_
->GetNativeView();
255 WebContents
* Shell::OpenURLFromTab(WebContents
* source
,
256 const OpenURLParams
& params
) {
257 // CURRENT_TAB is the only one we implement for now.
258 if (params
.disposition
!= CURRENT_TAB
)
260 NavigationController::LoadURLParams
load_url_params(params
.url
);
261 load_url_params
.source_site_instance
= params
.source_site_instance
;
262 load_url_params
.referrer
= params
.referrer
;
263 load_url_params
.frame_tree_node_id
= params
.frame_tree_node_id
;
264 load_url_params
.transition_type
= params
.transition
;
265 load_url_params
.extra_headers
= params
.extra_headers
;
266 load_url_params
.should_replace_current_entry
=
267 params
.should_replace_current_entry
;
269 if (params
.transferred_global_request_id
!= GlobalRequestID()) {
270 load_url_params
.is_renderer_initiated
= params
.is_renderer_initiated
;
271 load_url_params
.transferred_global_request_id
=
272 params
.transferred_global_request_id
;
273 } else if (params
.is_renderer_initiated
) {
274 load_url_params
.is_renderer_initiated
= true;
277 source
->GetController().LoadURLWithParams(load_url_params
);
281 void Shell::LoadingStateChanged(WebContents
* source
,
282 bool to_different_document
) {
283 UpdateNavigationControls(to_different_document
);
284 PlatformSetIsLoading(source
->IsLoading());
287 void Shell::EnterFullscreenModeForTab(WebContents
* web_contents
,
288 const GURL
& origin
) {
289 ToggleFullscreenModeForTab(web_contents
, true);
292 void Shell::ExitFullscreenModeForTab(WebContents
* web_contents
) {
293 ToggleFullscreenModeForTab(web_contents
, false);
296 void Shell::ToggleFullscreenModeForTab(WebContents
* web_contents
,
297 bool enter_fullscreen
) {
298 #if defined(OS_ANDROID)
299 PlatformToggleFullscreenModeForTab(web_contents
, enter_fullscreen
);
301 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
302 switches::kRunLayoutTest
))
304 if (is_fullscreen_
!= enter_fullscreen
) {
305 is_fullscreen_
= enter_fullscreen
;
306 web_contents
->GetRenderViewHost()->WasResized();
310 bool Shell::IsFullscreenForTabOrPending(const WebContents
* web_contents
) const {
311 #if defined(OS_ANDROID)
312 return PlatformIsFullscreenForTabOrPending(web_contents
);
314 return is_fullscreen_
;
318 blink::WebDisplayMode
Shell::GetDisplayMode(
319 const WebContents
* web_contents
) const {
320 // TODO : should return blink::WebDisplayModeFullscreen wherever user puts
321 // a browser window into fullscreen (not only in case of renderer-initiated
322 // fullscreen mode): crbug.com/476874.
323 return IsFullscreenForTabOrPending(web_contents
) ?
324 blink::WebDisplayModeFullscreen
: blink::WebDisplayModeBrowser
;
327 void Shell::RequestToLockMouse(WebContents
* web_contents
,
329 bool last_unlocked_by_target
) {
330 web_contents
->GotResponseToLockMouseRequest(true);
333 void Shell::CloseContents(WebContents
* source
) {
337 bool Shell::CanOverscrollContent() const {
338 #if defined(USE_AURA)
345 void Shell::DidNavigateMainFramePostCommit(WebContents
* web_contents
) {
346 PlatformSetAddressBarURL(web_contents
->GetLastCommittedURL());
349 JavaScriptDialogManager
* Shell::GetJavaScriptDialogManager(
350 WebContents
* source
) {
351 if (!dialog_manager_
) {
352 const base::CommandLine
& command_line
=
353 *base::CommandLine::ForCurrentProcess();
354 dialog_manager_
.reset(command_line
.HasSwitch(switches::kRunLayoutTest
)
355 ? new LayoutTestJavaScriptDialogManager
356 : new ShellJavaScriptDialogManager
);
358 return dialog_manager_
.get();
361 bool Shell::AddMessageToConsole(WebContents
* source
,
363 const base::string16
& message
,
365 const base::string16
& source_id
) {
366 return base::CommandLine::ForCurrentProcess()->HasSwitch(
367 switches::kRunLayoutTest
);
370 void Shell::RendererUnresponsive(WebContents
* source
) {
371 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
372 switches::kRunLayoutTest
))
374 BlinkTestController::Get()->RendererUnresponsive();
377 void Shell::ActivateContents(WebContents
* contents
) {
378 contents
->GetRenderViewHost()->Focus();
381 void Shell::DeactivateContents(WebContents
* contents
) {
382 contents
->GetRenderViewHost()->Blur();
385 bool Shell::HandleContextMenu(const content::ContextMenuParams
& params
) {
386 return PlatformHandleContextMenu(params
);
389 gfx::Size
Shell::GetShellDefaultSize() {
390 static gfx::Size default_shell_size
;
391 if (!default_shell_size
.IsEmpty())
392 return default_shell_size
;
393 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
394 if (command_line
->HasSwitch(switches::kContentShellHostWindowSize
)) {
395 const std::string size_str
= command_line
->GetSwitchValueASCII(
396 switches::kContentShellHostWindowSize
);
398 CHECK_EQ(2, sscanf(size_str
.c_str(), "%dx%d", &width
, &height
));
399 default_shell_size
= gfx::Size(width
, height
);
401 default_shell_size
= gfx::Size(
402 kDefaultTestWindowWidthDip
, kDefaultTestWindowHeightDip
);
404 return default_shell_size
;
407 void Shell::TitleWasSet(NavigationEntry
* entry
, bool explicit_set
) {
409 PlatformSetTitle(entry
->GetTitle());
412 void Shell::InnerShowDevTools() {
413 if (!devtools_frontend_
) {
414 devtools_frontend_
= ShellDevToolsFrontend::Show(web_contents());
415 devtools_observer_
.reset(new DevToolsWebContentsObserver(
416 this, devtools_frontend_
->frontend_shell()->web_contents()));
419 devtools_frontend_
->Activate();
420 devtools_frontend_
->Focus();
423 void Shell::OnDevToolsWebContentsDestroyed() {
424 devtools_observer_
.reset();
425 devtools_frontend_
= NULL
;
428 } // namespace content