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 Shell::kDefaultTestWindowWidthDip = 800;
35 const int Shell::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 CommandLine& command_line = *CommandLine::ForCurrentProcess();
68 if (command_line.HasSwitch(switches::kDumpRenderTree))
70 windows_.push_back(this);
72 if (!shell_created_callback_.is_null()) {
73 shell_created_callback_.Run(this);
74 shell_created_callback_.Reset();
81 for (size_t i = 0; i < windows_.size(); ++i) {
82 if (windows_[i] == this) {
83 windows_.erase(windows_.begin() + i);
88 if (windows_.empty() && quit_message_loop_) {
91 base::MessageLoop::current()->PostTask(FROM_HERE,
92 base::MessageLoop::QuitClosure());
96 Shell* Shell::CreateShell(WebContents* web_contents,
97 const gfx::Size& initial_size) {
98 Shell* shell = new Shell(web_contents);
99 shell->PlatformCreateWindow(initial_size.width(), initial_size.height());
101 shell->web_contents_.reset(web_contents);
102 web_contents->SetDelegate(shell);
104 shell->PlatformSetContents();
106 shell->PlatformResizeSubViews();
108 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
109 web_contents->GetMutableRendererPrefs()->use_custom_colors = false;
110 web_contents->GetRenderViewHost()->SyncRendererPrefs();
116 void Shell::CloseAllWindows() {
117 base::AutoReset<bool> auto_reset(&quit_message_loop_, false);
118 DevToolsAgentHost::DetachAllClients();
119 std::vector<Shell*> open_windows(windows_);
120 for (size_t i = 0; i < open_windows.size(); ++i)
121 open_windows[i]->Close();
123 base::MessageLoop::current()->RunUntilIdle();
126 void Shell::SetShellCreatedCallback(
127 base::Callback<void(Shell*)> shell_created_callback) {
128 DCHECK(shell_created_callback_.is_null());
129 shell_created_callback_ = shell_created_callback;
132 Shell* Shell::FromRenderViewHost(RenderViewHost* rvh) {
133 for (size_t i = 0; i < windows_.size(); ++i) {
134 if (windows_[i]->web_contents() &&
135 windows_[i]->web_contents()->GetRenderViewHost() == rvh) {
143 void Shell::Initialize() {
145 gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip));
148 gfx::Size Shell::AdjustWindowSize(const gfx::Size& initial_size) {
149 if (!initial_size.IsEmpty())
151 return gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip);
154 Shell* Shell::CreateNewWindow(BrowserContext* browser_context,
156 SiteInstance* site_instance,
158 const gfx::Size& initial_size) {
159 WebContents::CreateParams create_params(browser_context, site_instance);
160 create_params.routing_id = routing_id;
161 create_params.initial_size = AdjustWindowSize(initial_size);
162 WebContents* web_contents = WebContents::Create(create_params);
163 Shell* shell = CreateShell(web_contents, create_params.initial_size);
169 void Shell::LoadURL(const GURL& url) {
170 LoadURLForFrame(url, std::string());
173 void Shell::LoadURLForFrame(const GURL& url, const std::string& frame_name) {
174 NavigationController::LoadURLParams params(url);
175 params.transition_type = ui::PageTransitionFromInt(
176 ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
177 params.frame_name = frame_name;
178 web_contents_->GetController().LoadURLWithParams(params);
179 web_contents_->Focus();
182 void Shell::LoadDataWithBaseURL(const GURL& url, const std::string& data,
183 const GURL& base_url) {
184 const GURL data_url = GURL("data:text/html;charset=utf-8," + data);
185 NavigationController::LoadURLParams params(data_url);
186 params.load_type = NavigationController::LOAD_TYPE_DATA;
187 params.base_url_for_data_url = base_url;
188 params.virtual_url_for_data_url = url;
189 params.override_user_agent = NavigationController::UA_OVERRIDE_FALSE;
190 web_contents_->GetController().LoadURLWithParams(params);
191 web_contents_->Focus();
194 void Shell::AddNewContents(WebContents* source,
195 WebContents* new_contents,
196 WindowOpenDisposition disposition,
197 const gfx::Rect& initial_pos,
200 CreateShell(new_contents, AdjustWindowSize(initial_pos.size()));
201 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
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() {
231 InnerShowDevTools("", "");
234 void Shell::ShowDevToolsForElementAt(int x, int y) {
235 InnerShowDevTools("", "");
236 devtools_frontend_->InspectElementAt(x, y);
239 void Shell::ShowDevToolsForTest(const std::string& settings,
240 const std::string& frontend_url) {
241 InnerShowDevTools(settings, frontend_url);
244 void Shell::CloseDevTools() {
245 if (!devtools_frontend_)
247 devtools_observer_.reset();
248 devtools_frontend_->Close();
249 devtools_frontend_ = NULL;
252 gfx::NativeView Shell::GetContentView() {
255 return web_contents_->GetNativeView();
258 WebContents* Shell::OpenURLFromTab(WebContents* source,
259 const OpenURLParams& params) {
260 // CURRENT_TAB is the only one we implement for now.
261 if (params.disposition != CURRENT_TAB)
263 NavigationController::LoadURLParams load_url_params(params.url);
264 load_url_params.referrer = params.referrer;
265 load_url_params.frame_tree_node_id = params.frame_tree_node_id;
266 load_url_params.transition_type = params.transition;
267 load_url_params.extra_headers = params.extra_headers;
268 load_url_params.should_replace_current_entry =
269 params.should_replace_current_entry;
271 if (params.transferred_global_request_id != GlobalRequestID()) {
272 load_url_params.is_renderer_initiated = params.is_renderer_initiated;
273 load_url_params.transferred_global_request_id =
274 params.transferred_global_request_id;
275 } else if (params.is_renderer_initiated) {
276 load_url_params.is_renderer_initiated = true;
279 source->GetController().LoadURLWithParams(load_url_params);
283 void Shell::LoadingStateChanged(WebContents* source,
284 bool to_different_document) {
285 UpdateNavigationControls(to_different_document);
286 PlatformSetIsLoading(source->IsLoading());
289 void Shell::ToggleFullscreenModeForTab(WebContents* web_contents,
290 bool enter_fullscreen) {
291 #if defined(OS_ANDROID)
292 PlatformToggleFullscreenModeForTab(web_contents, enter_fullscreen);
294 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
296 if (is_fullscreen_ != enter_fullscreen) {
297 is_fullscreen_ = enter_fullscreen;
298 web_contents->GetRenderViewHost()->WasResized();
302 bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) const {
303 #if defined(OS_ANDROID)
304 return PlatformIsFullscreenForTabOrPending(web_contents);
306 return is_fullscreen_;
310 void Shell::RequestToLockMouse(WebContents* web_contents,
312 bool last_unlocked_by_target) {
313 web_contents->GotResponseToLockMouseRequest(true);
316 void Shell::CloseContents(WebContents* source) {
320 bool Shell::CanOverscrollContent() const {
321 #if defined(USE_AURA)
328 void Shell::DidNavigateMainFramePostCommit(WebContents* web_contents) {
329 PlatformSetAddressBarURL(web_contents->GetLastCommittedURL());
332 JavaScriptDialogManager* Shell::GetJavaScriptDialogManager() {
333 if (!dialog_manager_) {
334 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
335 dialog_manager_.reset(command_line.HasSwitch(switches::kDumpRenderTree)
336 ? new LayoutTestJavaScriptDialogManager
337 : new ShellJavaScriptDialogManager);
339 return dialog_manager_.get();
342 bool Shell::AddMessageToConsole(WebContents* source,
344 const base::string16& message,
346 const base::string16& source_id) {
347 return CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
350 void Shell::RendererUnresponsive(WebContents* source) {
351 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
353 WebKitTestController::Get()->RendererUnresponsive();
356 void Shell::ActivateContents(WebContents* contents) {
357 contents->GetRenderViewHost()->Focus();
360 void Shell::DeactivateContents(WebContents* contents) {
361 contents->GetRenderViewHost()->Blur();
364 void Shell::WorkerCrashed(WebContents* source) {
365 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
367 WebKitTestController::Get()->WorkerCrashed();
370 bool Shell::HandleContextMenu(const content::ContextMenuParams& params) {
371 return PlatformHandleContextMenu(params);
374 void Shell::WebContentsFocused(WebContents* contents) {
375 #if defined(TOOLKIT_VIEWS)
376 PlatformWebContentsFocused(contents);
380 void Shell::TitleWasSet(NavigationEntry* entry, bool explicit_set) {
382 PlatformSetTitle(entry->GetTitle());
385 void Shell::InnerShowDevTools(const std::string& settings,
386 const std::string& frontend_url) {
387 if (!devtools_frontend_) {
388 if (CommandLine::ForCurrentProcess()->HasSwitch(
389 switches::kDumpRenderTree)) {
390 devtools_frontend_ = LayoutTestDevToolsFrontend::Show(
391 web_contents(), settings, frontend_url);
393 devtools_frontend_ = ShellDevToolsFrontend::Show(web_contents());
395 devtools_observer_.reset(new DevToolsWebContentsObserver(
396 this, devtools_frontend_->frontend_shell()->web_contents()));
399 devtools_frontend_->Activate();
400 devtools_frontend_->Focus();
403 void Shell::OnDevToolsWebContentsDestroyed() {
404 devtools_observer_.reset();
405 devtools_frontend_ = NULL;
408 } // namespace content