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/path_service.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 "content/public/browser/devtools_agent_host.h"
16 #include "content/public/browser/navigation_controller.h"
17 #include "content/public/browser/navigation_entry.h"
18 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/browser/web_contents_observer.h"
21 #include "content/public/common/renderer_preferences.h"
22 #include "content/shell/browser/notify_done_forwarder.h"
23 #include "content/shell/browser/shell_browser_main_parts.h"
24 #include "content/shell/browser/shell_content_browser_client.h"
25 #include "content/shell/browser/shell_devtools_frontend.h"
26 #include "content/shell/browser/shell_javascript_dialog_manager.h"
27 #include "content/shell/browser/webkit_test_controller.h"
28 #include "content/shell/common/shell_messages.h"
29 #include "content/shell/common/shell_switches.h"
33 const int Shell::kDefaultTestWindowWidthDip
= 800;
34 const int Shell::kDefaultTestWindowHeightDip
= 600;
36 std::vector
<Shell
*> Shell::windows_
;
37 base::Callback
<void(Shell
*)> Shell::shell_created_callback_
;
39 bool Shell::quit_message_loop_
= true;
41 class Shell::DevToolsWebContentsObserver
: public WebContentsObserver
{
43 DevToolsWebContentsObserver(Shell
* shell
, WebContents
* web_contents
)
44 : WebContentsObserver(web_contents
),
48 // WebContentsObserver
49 virtual void WebContentsDestroyed() OVERRIDE
{
50 shell_
->OnDevToolsWebContentsDestroyed();
56 DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver
);
59 Shell::Shell(WebContents
* web_contents
)
60 : WebContentsObserver(web_contents
),
61 devtools_frontend_(NULL
),
62 is_fullscreen_(false),
66 const CommandLine
& command_line
= *CommandLine::ForCurrentProcess();
67 if (command_line
.HasSwitch(switches::kDumpRenderTree
))
69 windows_
.push_back(this);
71 if (!shell_created_callback_
.is_null()) {
72 shell_created_callback_
.Run(this);
73 shell_created_callback_
.Reset();
80 for (size_t i
= 0; i
< windows_
.size(); ++i
) {
81 if (windows_
[i
] == this) {
82 windows_
.erase(windows_
.begin() + i
);
87 if (windows_
.empty() && quit_message_loop_
) {
90 base::MessageLoop::current()->PostTask(FROM_HERE
,
91 base::MessageLoop::QuitClosure());
95 Shell
* Shell::CreateShell(WebContents
* web_contents
,
96 const gfx::Size
& initial_size
) {
97 Shell
* shell
= new Shell(web_contents
);
98 shell
->PlatformCreateWindow(initial_size
.width(), initial_size
.height());
100 shell
->web_contents_
.reset(web_contents
);
101 web_contents
->SetDelegate(shell
);
103 shell
->PlatformSetContents();
105 shell
->PlatformResizeSubViews();
107 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
)) {
108 web_contents
->GetMutableRendererPrefs()->use_custom_colors
= false;
109 web_contents
->GetRenderViewHost()->SyncRendererPrefs();
115 void Shell::CloseAllWindows() {
116 base::AutoReset
<bool> auto_reset(&quit_message_loop_
, false);
117 DevToolsAgentHost::DetachAllClients();
118 std::vector
<Shell
*> open_windows(windows_
);
119 for (size_t i
= 0; i
< open_windows
.size(); ++i
)
120 open_windows
[i
]->Close();
122 base::MessageLoop::current()->RunUntilIdle();
125 void Shell::SetShellCreatedCallback(
126 base::Callback
<void(Shell
*)> shell_created_callback
) {
127 DCHECK(shell_created_callback_
.is_null());
128 shell_created_callback_
= shell_created_callback
;
131 Shell
* Shell::FromRenderViewHost(RenderViewHost
* rvh
) {
132 for (size_t i
= 0; i
< windows_
.size(); ++i
) {
133 if (windows_
[i
]->web_contents() &&
134 windows_
[i
]->web_contents()->GetRenderViewHost() == rvh
) {
142 void Shell::Initialize() {
144 gfx::Size(kDefaultTestWindowWidthDip
, kDefaultTestWindowHeightDip
));
147 gfx::Size
Shell::AdjustWindowSize(const gfx::Size
& initial_size
) {
148 if (!initial_size
.IsEmpty())
150 return gfx::Size(kDefaultTestWindowWidthDip
, kDefaultTestWindowHeightDip
);
153 Shell
* Shell::CreateNewWindow(BrowserContext
* browser_context
,
155 SiteInstance
* site_instance
,
157 const gfx::Size
& initial_size
) {
158 WebContents::CreateParams
create_params(browser_context
, site_instance
);
159 create_params
.routing_id
= routing_id
;
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
= PageTransitionFromInt(
175 PAGE_TRANSITION_TYPED
| 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_pos
,
199 CreateShell(new_contents
, AdjustWindowSize(initial_pos
.size()));
200 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
))
201 NotifyDoneForwarder::CreateForWebContents(new_contents
);
204 void Shell::GoBackOrForward(int offset
) {
205 web_contents_
->GetController().GoToOffset(offset
);
206 web_contents_
->Focus();
209 void Shell::Reload() {
210 web_contents_
->GetController().Reload(false);
211 web_contents_
->Focus();
215 web_contents_
->Stop();
216 web_contents_
->Focus();
219 void Shell::UpdateNavigationControls(bool to_different_document
) {
220 int current_index
= web_contents_
->GetController().GetCurrentEntryIndex();
221 int max_index
= web_contents_
->GetController().GetEntryCount() - 1;
223 PlatformEnableUIControl(BACK_BUTTON
, current_index
> 0);
224 PlatformEnableUIControl(FORWARD_BUTTON
, current_index
< max_index
);
225 PlatformEnableUIControl(STOP_BUTTON
,
226 to_different_document
&& web_contents_
->IsLoading());
229 void Shell::ShowDevTools() {
230 InnerShowDevTools("", "");
233 void Shell::ShowDevToolsForElementAt(int x
, int y
) {
234 InnerShowDevTools("", "");
235 devtools_frontend_
->InspectElementAt(x
, y
);
238 void Shell::ShowDevToolsForTest(const std::string
& settings
,
239 const std::string
& frontend_url
) {
240 InnerShowDevTools(settings
, frontend_url
);
243 void Shell::CloseDevTools() {
244 if (!devtools_frontend_
)
246 devtools_observer_
.reset();
247 devtools_frontend_
->Close();
248 devtools_frontend_
= NULL
;
251 gfx::NativeView
Shell::GetContentView() {
254 return web_contents_
->GetNativeView();
257 WebContents
* Shell::OpenURLFromTab(WebContents
* source
,
258 const OpenURLParams
& params
) {
259 // CURRENT_TAB is the only one we implement for now.
260 if (params
.disposition
!= CURRENT_TAB
)
262 NavigationController::LoadURLParams
load_url_params(params
.url
);
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::ToggleFullscreenModeForTab(WebContents
* web_contents
,
289 bool enter_fullscreen
) {
290 #if defined(OS_ANDROID)
291 PlatformToggleFullscreenModeForTab(web_contents
, enter_fullscreen
);
293 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
))
295 if (is_fullscreen_
!= enter_fullscreen
) {
296 is_fullscreen_
= enter_fullscreen
;
297 web_contents
->GetRenderViewHost()->WasResized();
301 bool Shell::IsFullscreenForTabOrPending(const WebContents
* web_contents
) const {
302 #if defined(OS_ANDROID)
303 return PlatformIsFullscreenForTabOrPending(web_contents
);
305 return is_fullscreen_
;
309 void Shell::RequestToLockMouse(WebContents
* web_contents
,
311 bool last_unlocked_by_target
) {
312 web_contents
->GotResponseToLockMouseRequest(true);
315 void Shell::CloseContents(WebContents
* source
) {
319 bool Shell::CanOverscrollContent() const {
320 #if defined(USE_AURA)
327 void Shell::DidNavigateMainFramePostCommit(WebContents
* web_contents
) {
328 PlatformSetAddressBarURL(web_contents
->GetLastCommittedURL());
331 JavaScriptDialogManager
* Shell::GetJavaScriptDialogManager() {
332 if (!dialog_manager_
)
333 dialog_manager_
.reset(new ShellJavaScriptDialogManager());
334 return dialog_manager_
.get();
337 bool Shell::AddMessageToConsole(WebContents
* source
,
339 const base::string16
& message
,
341 const base::string16
& source_id
) {
342 return CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
);
345 void Shell::RendererUnresponsive(WebContents
* source
) {
346 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
))
348 WebKitTestController::Get()->RendererUnresponsive();
351 void Shell::ActivateContents(WebContents
* contents
) {
352 contents
->GetRenderViewHost()->Focus();
355 void Shell::DeactivateContents(WebContents
* contents
) {
356 contents
->GetRenderViewHost()->Blur();
359 void Shell::WorkerCrashed(WebContents
* source
) {
360 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
))
362 WebKitTestController::Get()->WorkerCrashed();
365 bool Shell::HandleContextMenu(const content::ContextMenuParams
& params
) {
366 return PlatformHandleContextMenu(params
);
369 void Shell::WebContentsFocused(WebContents
* contents
) {
370 #if defined(TOOLKIT_VIEWS)
371 PlatformWebContentsFocused(contents
);
375 void Shell::TitleWasSet(NavigationEntry
* entry
, bool explicit_set
) {
377 PlatformSetTitle(entry
->GetTitle());
380 void Shell::InnerShowDevTools(const std::string
& settings
,
381 const std::string
& frontend_url
) {
382 if (!devtools_frontend_
) {
383 devtools_frontend_
= ShellDevToolsFrontend::Show(
384 web_contents(), settings
, frontend_url
);
385 devtools_observer_
.reset(new DevToolsWebContentsObserver(
386 this, devtools_frontend_
->frontend_shell()->web_contents()));
389 devtools_frontend_
->Activate();
390 devtools_frontend_
->Focus();
393 void Shell::OnDevToolsWebContentsDestroyed() {
394 devtools_observer_
.reset();
395 devtools_frontend_
= NULL
;
398 } // namespace content