1 // Copyright (c) 2012 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/shell.h"
7 #include "base/auto_reset.h"
8 #include "base/command_line.h"
9 #include "base/message_loop.h"
10 #include "base/path_service.h"
11 #include "base/stringprintf.h"
12 #include "base/string_number_conversions.h"
13 #include "base/string_util.h"
14 #include "base/utf_string_conversions.h"
15 #include "content/public/browser/devtools_manager.h"
16 #include "content/public/browser/navigation_entry.h"
17 #include "content/public/browser/navigation_controller.h"
18 #include "content/public/browser/notification_details.h"
19 #include "content/public/browser/notification_source.h"
20 #include "content/public/browser/notification_types.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/browser/web_contents_view.h"
24 #include "content/public/common/renderer_preferences.h"
25 #include "content/shell/notify_done_forwarder.h"
26 #include "content/shell/shell_browser_main_parts.h"
27 #include "content/shell/shell_content_browser_client.h"
28 #include "content/shell/shell_devtools_frontend.h"
29 #include "content/shell/shell_javascript_dialog_manager.h"
30 #include "content/shell/shell_messages.h"
31 #include "content/shell/shell_switches.h"
32 #include "content/shell/webkit_test_controller.h"
34 // Content area size for newly created windows.
35 static const int kTestWindowWidth
= 800;
36 static const int kTestWindowHeight
= 600;
40 std::vector
<Shell
*> Shell::windows_
;
41 base::Callback
<void(Shell
*)> Shell::shell_created_callback_
;
43 bool Shell::quit_message_loop_
= true;
45 Shell::Shell(WebContents
* web_contents
)
46 : devtools_frontend_(NULL
),
47 is_fullscreen_(false),
50 #if defined(OS_WIN) && !defined(USE_AURA)
51 default_edit_wnd_proc_(0),
54 const CommandLine
& command_line
= *CommandLine::ForCurrentProcess();
55 if (command_line
.HasSwitch(switches::kDumpRenderTree
) &&
56 !command_line
.HasSwitch(switches::kDisableHeadlessForLayoutTests
)) {
59 registrar_
.Add(this, NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED
,
60 Source
<WebContents
>(web_contents
));
61 windows_
.push_back(this);
63 if (!shell_created_callback_
.is_null()) {
64 shell_created_callback_
.Run(this);
65 shell_created_callback_
.Reset();
72 for (size_t i
= 0; i
< windows_
.size(); ++i
) {
73 if (windows_
[i
] == this) {
74 windows_
.erase(windows_
.begin() + i
);
79 if (windows_
.empty() && quit_message_loop_
)
80 MessageLoop::current()->PostTask(FROM_HERE
, MessageLoop::QuitClosure());
83 Shell
* Shell::CreateShell(WebContents
* web_contents
) {
84 Shell
* shell
= new Shell(web_contents
);
85 shell
->PlatformCreateWindow(kTestWindowWidth
, kTestWindowHeight
);
87 shell
->web_contents_
.reset(web_contents
);
88 web_contents
->SetDelegate(shell
);
90 shell
->PlatformSetContents();
92 shell
->PlatformResizeSubViews();
94 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
)) {
95 web_contents
->GetMutableRendererPrefs()->use_custom_colors
= false;
96 web_contents
->GetRenderViewHost()->SyncRendererPrefs();
102 void Shell::CloseAllWindows() {
103 base::AutoReset
<bool> auto_reset(&quit_message_loop_
, false);
104 DevToolsManager::GetInstance()->CloseAllClientHosts();
105 std::vector
<Shell
*> open_windows(windows_
);
106 for (size_t i
= 0; i
< open_windows
.size(); ++i
)
107 open_windows
[i
]->Close();
108 MessageLoop::current()->RunUntilIdle();
111 void Shell::SetShellCreatedCallback(
112 base::Callback
<void(Shell
*)> shell_created_callback
) {
113 DCHECK(shell_created_callback_
.is_null());
114 shell_created_callback_
= shell_created_callback
;
117 Shell
* Shell::FromRenderViewHost(RenderViewHost
* rvh
) {
118 for (size_t i
= 0; i
< windows_
.size(); ++i
) {
119 if (windows_
[i
]->web_contents() &&
120 windows_
[i
]->web_contents()->GetRenderViewHost() == rvh
) {
128 void Shell::Initialize() {
129 PlatformInitialize(gfx::Size(kTestWindowWidth
, kTestWindowHeight
));
132 Shell
* Shell::CreateNewWindow(BrowserContext
* browser_context
,
134 SiteInstance
* site_instance
,
136 const gfx::Size
& initial_size
) {
137 WebContents::CreateParams
create_params(browser_context
, site_instance
);
138 create_params
.routing_id
= routing_id
;
139 if (!initial_size
.IsEmpty())
140 create_params
.initial_size
= initial_size
;
142 create_params
.initial_size
= gfx::Size(kTestWindowWidth
, kTestWindowHeight
);
143 WebContents
* web_contents
= WebContents::Create(create_params
);
144 Shell
* shell
= CreateShell(web_contents
);
150 void Shell::LoadURL(const GURL
& url
) {
151 LoadURLForFrame(url
, std::string());
154 void Shell::LoadURLForFrame(const GURL
& url
, const std::string
& frame_name
) {
155 NavigationController::LoadURLParams
params(url
);
156 params
.transition_type
= PageTransitionFromInt(
157 PAGE_TRANSITION_TYPED
| PAGE_TRANSITION_FROM_ADDRESS_BAR
);
158 params
.frame_name
= frame_name
;
159 web_contents_
->GetController().LoadURLWithParams(params
);
160 web_contents_
->GetView()->Focus();
163 void Shell::GoBackOrForward(int offset
) {
164 web_contents_
->GetController().GoToOffset(offset
);
165 web_contents_
->GetView()->Focus();
168 void Shell::Reload() {
169 web_contents_
->GetController().Reload(false);
170 web_contents_
->GetView()->Focus();
174 web_contents_
->Stop();
175 web_contents_
->GetView()->Focus();
178 void Shell::UpdateNavigationControls() {
179 int current_index
= web_contents_
->GetController().GetCurrentEntryIndex();
180 int max_index
= web_contents_
->GetController().GetEntryCount() - 1;
182 PlatformEnableUIControl(BACK_BUTTON
, current_index
> 0);
183 PlatformEnableUIControl(FORWARD_BUTTON
, current_index
< max_index
);
184 PlatformEnableUIControl(STOP_BUTTON
, web_contents_
->IsLoading());
187 void Shell::ShowDevTools() {
188 if (devtools_frontend_
) {
189 devtools_frontend_
->Focus();
192 devtools_frontend_
= ShellDevToolsFrontend::Show(web_contents());
194 NOTIFICATION_WEB_CONTENTS_DESTROYED
,
196 devtools_frontend_
->frontend_shell()->web_contents()));
199 void Shell::CloseDevTools() {
200 if (!devtools_frontend_
)
202 registrar_
.Remove(this,
203 NOTIFICATION_WEB_CONTENTS_DESTROYED
,
205 devtools_frontend_
->frontend_shell()->web_contents()));
206 devtools_frontend_
->Close();
207 devtools_frontend_
= NULL
;
210 gfx::NativeView
Shell::GetContentView() {
211 if (!web_contents_
.get())
213 return web_contents_
->GetView()->GetNativeView();
216 WebContents
* Shell::OpenURLFromTab(WebContents
* source
,
217 const OpenURLParams
& params
) {
218 // The only one we implement for now.
219 DCHECK(params
.disposition
== CURRENT_TAB
);
220 source
->GetController().LoadURL(
221 params
.url
, params
.referrer
, params
.transition
, std::string());
225 void Shell::LoadingStateChanged(WebContents
* source
) {
226 UpdateNavigationControls();
227 PlatformSetIsLoading(source
->IsLoading());
230 void Shell::ToggleFullscreenModeForTab(WebContents
* web_contents
,
231 bool enter_fullscreen
) {
232 #if defined(OS_ANDROID)
233 PlatformToggleFullscreenModeForTab(web_contents
, enter_fullscreen
);
235 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
))
237 if (is_fullscreen_
!= enter_fullscreen
) {
238 is_fullscreen_
= enter_fullscreen
;
239 web_contents
->GetRenderViewHost()->WasResized();
243 bool Shell::IsFullscreenForTabOrPending(const WebContents
* web_contents
) const {
244 #if defined(OS_ANDROID)
245 return PlatformIsFullscreenForTabOrPending(web_contents
);
247 return is_fullscreen_
;
251 void Shell::RequestToLockMouse(WebContents
* web_contents
,
253 bool last_unlocked_by_target
) {
254 web_contents
->GotResponseToLockMouseRequest(true);
257 void Shell::CloseContents(WebContents
* source
) {
261 bool Shell::CanOverscrollContent() const {
262 #if defined(USE_AURA)
269 void Shell::WebContentsCreated(WebContents
* source_contents
,
270 int64 source_frame_id
,
271 const string16
& frame_name
,
272 const GURL
& target_url
,
273 WebContents
* new_contents
) {
274 CreateShell(new_contents
);
275 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
))
276 NotifyDoneForwarder::CreateForWebContents(new_contents
);
279 void Shell::DidNavigateMainFramePostCommit(WebContents
* web_contents
) {
280 PlatformSetAddressBarURL(web_contents
->GetURL());
283 JavaScriptDialogManager
* Shell::GetJavaScriptDialogManager() {
284 if (!dialog_manager_
.get())
285 dialog_manager_
.reset(new ShellJavaScriptDialogManager());
286 return dialog_manager_
.get();
289 bool Shell::AddMessageToConsole(WebContents
* source
,
291 const string16
& message
,
293 const string16
& source_id
) {
294 return CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
);
297 void Shell::RendererUnresponsive(WebContents
* source
) {
298 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
))
300 WebKitTestController::Get()->RendererUnresponsive();
303 void Shell::ActivateContents(WebContents
* contents
) {
304 contents
->GetRenderViewHost()->Focus();
307 void Shell::DeactivateContents(WebContents
* contents
) {
308 contents
->GetRenderViewHost()->Blur();
311 void Shell::Observe(int type
,
312 const NotificationSource
& source
,
313 const NotificationDetails
& details
) {
314 if (type
== NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED
) {
315 std::pair
<NavigationEntry
*, bool>* title
=
316 Details
<std::pair
<NavigationEntry
*, bool> >(details
).ptr();
319 string16 text
= title
->first
->GetTitle();
320 PlatformSetTitle(text
);
322 } else if (type
== NOTIFICATION_WEB_CONTENTS_DESTROYED
) {
323 devtools_frontend_
= NULL
;
324 registrar_
.Remove(this, NOTIFICATION_WEB_CONTENTS_DESTROYED
, source
);
330 } // namespace content