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/message_loop/message_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "content/public/browser/devtools_agent_host.h"
15 #include "content/public/browser/navigation_controller.h"
16 #include "content/public/browser/navigation_entry.h"
17 #include "content/public/browser/render_view_host.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/browser/web_contents_observer.h"
20 #include "content/public/common/renderer_preferences.h"
21 #include "content/shell/browser/layout_test/layout_test_devtools_frontend.h"
22 #include "content/shell/browser/layout_test/layout_test_javascript_dialog_manager.h"
23 #include "content/shell/browser/notify_done_forwarder.h"
24 #include "content/shell/browser/shell_browser_main_parts.h"
25 #include "content/shell/browser/shell_content_browser_client.h"
26 #include "content/shell/browser/shell_devtools_frontend.h"
27 #include "content/shell/browser/shell_javascript_dialog_manager.h"
28 #include "content/shell/browser/webkit_test_controller.h"
29 #include "content/shell/common/shell_messages.h"
30 #include "content/shell/common/shell_switches.h"
34 const int kDefaultTestWindowWidthDip
= 800;
35 const int kDefaultTestWindowHeightDip
= 600;
37 std::vector
<Shell
*> Shell::windows_
;
38 base::Callback
<void(Shell
*)> Shell::shell_created_callback_
;
40 bool Shell::quit_message_loop_
= true;
42 class Shell::DevToolsWebContentsObserver
: public WebContentsObserver
{
44 DevToolsWebContentsObserver(Shell
* shell
, WebContents
* web_contents
)
45 : WebContentsObserver(web_contents
),
49 // WebContentsObserver
50 void WebContentsDestroyed() override
{
51 shell_
->OnDevToolsWebContentsDestroyed();
57 DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver
);
60 Shell::Shell(WebContents
* web_contents
)
61 : WebContentsObserver(web_contents
),
62 devtools_frontend_(NULL
),
63 is_fullscreen_(false),
67 const base::CommandLine
& command_line
=
68 *base::CommandLine::ForCurrentProcess();
69 if (command_line
.HasSwitch(switches::kRunLayoutTest
))
71 windows_
.push_back(this);
73 if (!shell_created_callback_
.is_null()) {
74 shell_created_callback_
.Run(this);
75 shell_created_callback_
.Reset();
82 for (size_t i
= 0; i
< windows_
.size(); ++i
) {
83 if (windows_
[i
] == this) {
84 windows_
.erase(windows_
.begin() + i
);
89 if (windows_
.empty() && quit_message_loop_
) {
92 base::MessageLoop::current()->PostTask(FROM_HERE
,
93 base::MessageLoop::QuitClosure());
97 Shell
* Shell::CreateShell(WebContents
* web_contents
,
98 const gfx::Size
& initial_size
) {
99 Shell
* shell
= new Shell(web_contents
);
100 shell
->PlatformCreateWindow(initial_size
.width(), initial_size
.height());
102 shell
->web_contents_
.reset(web_contents
);
103 web_contents
->SetDelegate(shell
);
105 shell
->PlatformSetContents();
107 shell
->PlatformResizeSubViews();
109 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
110 switches::kRunLayoutTest
)) {
111 web_contents
->GetMutableRendererPrefs()->use_custom_colors
= false;
112 web_contents
->GetRenderViewHost()->SyncRendererPrefs();
118 void Shell::CloseAllWindows() {
119 base::AutoReset
<bool> auto_reset(&quit_message_loop_
, false);
120 DevToolsAgentHost::DetachAllClients();
121 std::vector
<Shell
*> open_windows(windows_
);
122 for (size_t i
= 0; i
< open_windows
.size(); ++i
)
123 open_windows
[i
]->Close();
125 base::MessageLoop::current()->RunUntilIdle();
128 void Shell::SetShellCreatedCallback(
129 base::Callback
<void(Shell
*)> shell_created_callback
) {
130 DCHECK(shell_created_callback_
.is_null());
131 shell_created_callback_
= shell_created_callback
;
134 Shell
* Shell::FromRenderViewHost(RenderViewHost
* rvh
) {
135 for (size_t i
= 0; i
< windows_
.size(); ++i
) {
136 if (windows_
[i
]->web_contents() &&
137 windows_
[i
]->web_contents()->GetRenderViewHost() == rvh
) {
145 void Shell::Initialize() {
146 PlatformInitialize(GetShellDefaultSize());
149 gfx::Size
Shell::AdjustWindowSize(const gfx::Size
& initial_size
) {
150 if (!initial_size
.IsEmpty())
152 return GetShellDefaultSize();
155 Shell
* Shell::CreateNewWindow(BrowserContext
* browser_context
,
157 SiteInstance
* site_instance
,
158 const gfx::Size
& initial_size
) {
159 WebContents::CreateParams
create_params(browser_context
, site_instance
);
160 create_params
.initial_size
= AdjustWindowSize(initial_size
);
161 WebContents
* web_contents
= WebContents::Create(create_params
);
162 Shell
* shell
= CreateShell(web_contents
, create_params
.initial_size
);
168 void Shell::LoadURL(const GURL
& url
) {
169 LoadURLForFrame(url
, std::string());
172 void Shell::LoadURLForFrame(const GURL
& url
, const std::string
& frame_name
) {
173 NavigationController::LoadURLParams
params(url
);
174 params
.transition_type
= ui::PageTransitionFromInt(
175 ui::PAGE_TRANSITION_TYPED
| ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
);
176 params
.frame_name
= frame_name
;
177 web_contents_
->GetController().LoadURLWithParams(params
);
178 web_contents_
->Focus();
181 void Shell::LoadDataWithBaseURL(const GURL
& url
, const std::string
& data
,
182 const GURL
& base_url
) {
183 const GURL data_url
= GURL("data:text/html;charset=utf-8," + data
);
184 NavigationController::LoadURLParams
params(data_url
);
185 params
.load_type
= NavigationController::LOAD_TYPE_DATA
;
186 params
.base_url_for_data_url
= base_url
;
187 params
.virtual_url_for_data_url
= url
;
188 params
.override_user_agent
= NavigationController::UA_OVERRIDE_FALSE
;
189 web_contents_
->GetController().LoadURLWithParams(params
);
190 web_contents_
->Focus();
193 void Shell::AddNewContents(WebContents
* source
,
194 WebContents
* new_contents
,
195 WindowOpenDisposition disposition
,
196 const gfx::Rect
& initial_rect
,
199 CreateShell(new_contents
, AdjustWindowSize(initial_rect
.size()));
200 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
201 switches::kRunLayoutTest
))
202 NotifyDoneForwarder::CreateForWebContents(new_contents
);
205 void Shell::GoBackOrForward(int offset
) {
206 web_contents_
->GetController().GoToOffset(offset
);
207 web_contents_
->Focus();
210 void Shell::Reload() {
211 web_contents_
->GetController().Reload(false);
212 web_contents_
->Focus();
216 web_contents_
->Stop();
217 web_contents_
->Focus();
220 void Shell::UpdateNavigationControls(bool to_different_document
) {
221 int current_index
= web_contents_
->GetController().GetCurrentEntryIndex();
222 int max_index
= web_contents_
->GetController().GetEntryCount() - 1;
224 PlatformEnableUIControl(BACK_BUTTON
, current_index
> 0);
225 PlatformEnableUIControl(FORWARD_BUTTON
, current_index
< max_index
);
226 PlatformEnableUIControl(STOP_BUTTON
,
227 to_different_document
&& web_contents_
->IsLoading());
230 void Shell::ShowDevTools() {
234 void Shell::ShowDevToolsForElementAt(int x
, int y
) {
236 devtools_frontend_
->InspectElementAt(x
, y
);
239 void Shell::CloseDevTools() {
240 if (!devtools_frontend_
)
242 devtools_observer_
.reset();
243 devtools_frontend_
->Close();
244 devtools_frontend_
= NULL
;
247 gfx::NativeView
Shell::GetContentView() {
250 return web_contents_
->GetNativeView();
253 WebContents
* Shell::OpenURLFromTab(WebContents
* source
,
254 const OpenURLParams
& params
) {
255 // CURRENT_TAB is the only one we implement for now.
256 if (params
.disposition
!= CURRENT_TAB
)
258 NavigationController::LoadURLParams
load_url_params(params
.url
);
259 load_url_params
.source_site_instance
= params
.source_site_instance
;
260 load_url_params
.referrer
= params
.referrer
;
261 load_url_params
.frame_tree_node_id
= params
.frame_tree_node_id
;
262 load_url_params
.transition_type
= params
.transition
;
263 load_url_params
.extra_headers
= params
.extra_headers
;
264 load_url_params
.should_replace_current_entry
=
265 params
.should_replace_current_entry
;
267 if (params
.transferred_global_request_id
!= GlobalRequestID()) {
268 load_url_params
.is_renderer_initiated
= params
.is_renderer_initiated
;
269 load_url_params
.transferred_global_request_id
=
270 params
.transferred_global_request_id
;
271 } else if (params
.is_renderer_initiated
) {
272 load_url_params
.is_renderer_initiated
= true;
275 source
->GetController().LoadURLWithParams(load_url_params
);
279 void Shell::LoadingStateChanged(WebContents
* source
,
280 bool to_different_document
) {
281 UpdateNavigationControls(to_different_document
);
282 PlatformSetIsLoading(source
->IsLoading());
285 void Shell::EnterFullscreenModeForTab(WebContents
* web_contents
,
286 const GURL
& origin
) {
287 ToggleFullscreenModeForTab(web_contents
, true);
290 void Shell::ExitFullscreenModeForTab(WebContents
* web_contents
) {
291 ToggleFullscreenModeForTab(web_contents
, false);
294 void Shell::ToggleFullscreenModeForTab(WebContents
* web_contents
,
295 bool enter_fullscreen
) {
296 #if defined(OS_ANDROID)
297 PlatformToggleFullscreenModeForTab(web_contents
, enter_fullscreen
);
299 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
300 switches::kRunLayoutTest
))
302 if (is_fullscreen_
!= enter_fullscreen
) {
303 is_fullscreen_
= enter_fullscreen
;
304 web_contents
->GetRenderViewHost()->WasResized();
308 bool Shell::IsFullscreenForTabOrPending(const WebContents
* web_contents
) const {
309 #if defined(OS_ANDROID)
310 return PlatformIsFullscreenForTabOrPending(web_contents
);
312 return is_fullscreen_
;
316 void Shell::RequestToLockMouse(WebContents
* web_contents
,
318 bool last_unlocked_by_target
) {
319 web_contents
->GotResponseToLockMouseRequest(true);
322 void Shell::CloseContents(WebContents
* source
) {
326 bool Shell::CanOverscrollContent() const {
327 #if defined(USE_AURA)
334 void Shell::DidNavigateMainFramePostCommit(WebContents
* web_contents
) {
335 PlatformSetAddressBarURL(web_contents
->GetLastCommittedURL());
338 JavaScriptDialogManager
* Shell::GetJavaScriptDialogManager(
339 WebContents
* source
) {
340 if (!dialog_manager_
) {
341 const base::CommandLine
& command_line
=
342 *base::CommandLine::ForCurrentProcess();
343 dialog_manager_
.reset(command_line
.HasSwitch(switches::kRunLayoutTest
)
344 ? new LayoutTestJavaScriptDialogManager
345 : new ShellJavaScriptDialogManager
);
347 return dialog_manager_
.get();
350 bool Shell::AddMessageToConsole(WebContents
* source
,
352 const base::string16
& message
,
354 const base::string16
& source_id
) {
355 return base::CommandLine::ForCurrentProcess()->HasSwitch(
356 switches::kRunLayoutTest
);
359 void Shell::RendererUnresponsive(WebContents
* source
) {
360 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
361 switches::kRunLayoutTest
))
363 WebKitTestController::Get()->RendererUnresponsive();
366 void Shell::ActivateContents(WebContents
* contents
) {
367 contents
->GetRenderViewHost()->Focus();
370 void Shell::DeactivateContents(WebContents
* contents
) {
371 contents
->GetRenderViewHost()->Blur();
374 void Shell::WorkerCrashed(WebContents
* source
) {
375 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
376 switches::kRunLayoutTest
))
378 WebKitTestController::Get()->WorkerCrashed();
381 bool Shell::HandleContextMenu(const content::ContextMenuParams
& params
) {
382 return PlatformHandleContextMenu(params
);
385 void Shell::WebContentsFocused(WebContents
* contents
) {
386 #if defined(TOOLKIT_VIEWS)
387 PlatformWebContentsFocused(contents
);
391 gfx::Size
Shell::GetShellDefaultSize() {
392 static gfx::Size default_shell_size
;
393 if (!default_shell_size
.IsEmpty())
394 return default_shell_size
;
395 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
396 if (command_line
->HasSwitch(switches::kContentShellHostWindowSize
)) {
397 const std::string size_str
= command_line
->GetSwitchValueASCII(
398 switches::kContentShellHostWindowSize
);
400 CHECK_EQ(2, sscanf(size_str
.c_str(), "%dx%d", &width
, &height
));
401 default_shell_size
= gfx::Size(width
, height
);
403 default_shell_size
= gfx::Size(
404 kDefaultTestWindowWidthDip
, kDefaultTestWindowHeightDip
);
406 return default_shell_size
;
409 void Shell::TitleWasSet(NavigationEntry
* entry
, bool explicit_set
) {
411 PlatformSetTitle(entry
->GetTitle());
414 void Shell::InnerShowDevTools() {
415 if (!devtools_frontend_
) {
416 devtools_frontend_
= ShellDevToolsFrontend::Show(web_contents());
417 devtools_observer_
.reset(new DevToolsWebContentsObserver(
418 this, devtools_frontend_
->frontend_shell()->web_contents()));
421 devtools_frontend_
->Activate();
422 devtools_frontend_
->Focus();
425 void Shell::OnDevToolsWebContentsDestroyed() {
426 devtools_observer_
.reset();
427 devtools_frontend_
= NULL
;
430 } // namespace content