shell.cc revision f2477e01787aa58f445919b809d89e252beef54f
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.
4
5#include "content/shell/browser/shell.h"
6
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_manager.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/browser/web_contents_view.h"
22#include "content/public/common/renderer_preferences.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"
31
32#if defined(USE_AURA) && !defined(TOOLKIT_VIEWS)
33#include "content/shell/browser/shell_aura.h"
34#endif
35
36namespace content {
37
38const int Shell::kDefaultTestWindowWidthDip = 800;
39const int Shell::kDefaultTestWindowHeightDip = 600;
40
41std::vector<Shell*> Shell::windows_;
42base::Callback<void(Shell*)> Shell::shell_created_callback_;
43
44bool Shell::quit_message_loop_ = true;
45
46class Shell::DevToolsWebContentsObserver : public WebContentsObserver {
47 public:
48  DevToolsWebContentsObserver(Shell* shell, WebContents* web_contents)
49      : WebContentsObserver(web_contents),
50        shell_(shell) {
51  }
52
53  // WebContentsObserver
54  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE {
55    shell_->OnDevToolsWebContentsDestroyed();
56  }
57
58 private:
59  Shell* shell_;
60
61  DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver);
62};
63
64Shell::Shell(WebContents* web_contents)
65    : WebContentsObserver(web_contents),
66      devtools_frontend_(NULL),
67      is_fullscreen_(false),
68      window_(NULL),
69      url_edit_view_(NULL),
70#if defined(OS_WIN) && !defined(USE_AURA)
71      default_edit_wnd_proc_(0),
72#endif
73      headless_(false) {
74  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
75  if (command_line.HasSwitch(switches::kDumpRenderTree))
76    headless_ = true;
77  windows_.push_back(this);
78
79  if (!shell_created_callback_.is_null()) {
80    shell_created_callback_.Run(this);
81    shell_created_callback_.Reset();
82  }
83}
84
85Shell::~Shell() {
86  PlatformCleanUp();
87
88  for (size_t i = 0; i < windows_.size(); ++i) {
89    if (windows_[i] == this) {
90      windows_.erase(windows_.begin() + i);
91      break;
92    }
93  }
94
95  if (windows_.empty() && quit_message_loop_)
96    base::MessageLoop::current()->PostTask(FROM_HERE,
97                                           base::MessageLoop::QuitClosure());
98}
99
100Shell* Shell::CreateShell(WebContents* web_contents,
101                          const gfx::Size& initial_size) {
102  Shell* shell = new Shell(web_contents);
103  shell->PlatformCreateWindow(initial_size.width(), initial_size.height());
104
105  shell->web_contents_.reset(web_contents);
106  web_contents->SetDelegate(shell);
107
108  shell->PlatformSetContents();
109
110  shell->PlatformResizeSubViews();
111
112  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
113    web_contents->GetMutableRendererPrefs()->use_custom_colors = false;
114    web_contents->GetRenderViewHost()->SyncRendererPrefs();
115  }
116
117  return shell;
118}
119
120void Shell::CloseAllWindows() {
121  base::AutoReset<bool> auto_reset(&quit_message_loop_, false);
122  DevToolsManager::GetInstance()->CloseAllClientHosts();
123  std::vector<Shell*> open_windows(windows_);
124  for (size_t i = 0; i < open_windows.size(); ++i)
125    open_windows[i]->Close();
126  PlatformExit();
127  base::MessageLoop::current()->RunUntilIdle();
128}
129
130void Shell::SetShellCreatedCallback(
131    base::Callback<void(Shell*)> shell_created_callback) {
132  DCHECK(shell_created_callback_.is_null());
133  shell_created_callback_ = shell_created_callback;
134}
135
136Shell* 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) {
140      return windows_[i];
141    }
142  }
143  return NULL;
144}
145
146// static
147void Shell::Initialize() {
148  PlatformInitialize(
149      gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip));
150}
151
152gfx::Size Shell::AdjustWindowSize(const gfx::Size& initial_size) {
153  if (!initial_size.IsEmpty())
154    return initial_size;
155  return gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip);
156}
157
158Shell* Shell::CreateNewWindow(BrowserContext* browser_context,
159                              const GURL& url,
160                              SiteInstance* site_instance,
161                              int routing_id,
162                              const gfx::Size& initial_size) {
163  WebContents::CreateParams create_params(browser_context, site_instance);
164  create_params.routing_id = routing_id;
165  create_params.initial_size = AdjustWindowSize(initial_size);
166  WebContents* web_contents = WebContents::Create(create_params);
167  Shell* shell = CreateShell(web_contents, create_params.initial_size);
168  if (!url.is_empty())
169    shell->LoadURL(url);
170  return shell;
171}
172
173void Shell::LoadURL(const GURL& url) {
174  LoadURLForFrame(url, std::string());
175}
176
177void Shell::LoadURLForFrame(const GURL& url, const std::string& frame_name) {
178  NavigationController::LoadURLParams params(url);
179  params.transition_type = PageTransitionFromInt(
180      PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR);
181  params.frame_name = frame_name;
182  web_contents_->GetController().LoadURLWithParams(params);
183  web_contents_->GetView()->Focus();
184}
185
186void Shell::AddNewContents(WebContents* source,
187                           WebContents* new_contents,
188                           WindowOpenDisposition disposition,
189                           const gfx::Rect& initial_pos,
190                           bool user_gesture,
191                           bool* was_blocked) {
192  CreateShell(new_contents, AdjustWindowSize(initial_pos.size()));
193  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
194    NotifyDoneForwarder::CreateForWebContents(new_contents);
195}
196
197void Shell::GoBackOrForward(int offset) {
198  web_contents_->GetController().GoToOffset(offset);
199  web_contents_->GetView()->Focus();
200}
201
202void Shell::Reload() {
203  web_contents_->GetController().Reload(false);
204  web_contents_->GetView()->Focus();
205}
206
207void Shell::Stop() {
208  web_contents_->Stop();
209  web_contents_->GetView()->Focus();
210}
211
212void Shell::UpdateNavigationControls() {
213  int current_index = web_contents_->GetController().GetCurrentEntryIndex();
214  int max_index = web_contents_->GetController().GetEntryCount() - 1;
215
216  PlatformEnableUIControl(BACK_BUTTON, current_index > 0);
217  PlatformEnableUIControl(FORWARD_BUTTON, current_index < max_index);
218  PlatformEnableUIControl(STOP_BUTTON, web_contents_->IsLoading());
219}
220
221void Shell::ShowDevTools() {
222  if (devtools_frontend_) {
223    devtools_frontend_->Focus();
224    return;
225  }
226  devtools_frontend_ = ShellDevToolsFrontend::Show(web_contents());
227  devtools_observer_.reset(new DevToolsWebContentsObserver(
228      this, devtools_frontend_->frontend_shell()->web_contents()));
229}
230
231void Shell::CloseDevTools() {
232  if (!devtools_frontend_)
233    return;
234  devtools_observer_.reset();
235  devtools_frontend_->Close();
236  devtools_frontend_ = NULL;
237}
238
239gfx::NativeView Shell::GetContentView() {
240  if (!web_contents_)
241    return NULL;
242  return web_contents_->GetView()->GetNativeView();
243}
244
245WebContents* Shell::OpenURLFromTab(WebContents* source,
246                                   const OpenURLParams& params) {
247  // CURRENT_TAB is the only one we implement for now.
248  if (params.disposition != CURRENT_TAB)
249      return NULL;
250  NavigationController::LoadURLParams load_url_params(params.url);
251  load_url_params.referrer = params.referrer;
252  load_url_params.frame_tree_node_id = params.frame_tree_node_id;
253  load_url_params.transition_type = params.transition;
254  load_url_params.extra_headers = params.extra_headers;
255  load_url_params.should_replace_current_entry =
256      params.should_replace_current_entry;
257
258  if (params.transferred_global_request_id != GlobalRequestID()) {
259    load_url_params.is_renderer_initiated = params.is_renderer_initiated;
260    load_url_params.transferred_global_request_id =
261        params.transferred_global_request_id;
262  } else if (params.is_renderer_initiated) {
263    load_url_params.is_renderer_initiated = true;
264  }
265
266  source->GetController().LoadURLWithParams(load_url_params);
267  return source;
268}
269
270void Shell::LoadingStateChanged(WebContents* source) {
271  UpdateNavigationControls();
272  PlatformSetIsLoading(source->IsLoading());
273}
274
275void Shell::ToggleFullscreenModeForTab(WebContents* web_contents,
276                                       bool enter_fullscreen) {
277#if defined(OS_ANDROID)
278  PlatformToggleFullscreenModeForTab(web_contents, enter_fullscreen);
279#endif
280  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
281    return;
282  if (is_fullscreen_ != enter_fullscreen) {
283    is_fullscreen_ = enter_fullscreen;
284    web_contents->GetRenderViewHost()->WasResized();
285  }
286}
287
288bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) const {
289#if defined(OS_ANDROID)
290  return PlatformIsFullscreenForTabOrPending(web_contents);
291#else
292  return is_fullscreen_;
293#endif
294}
295
296void Shell::RequestToLockMouse(WebContents* web_contents,
297                               bool user_gesture,
298                               bool last_unlocked_by_target) {
299  web_contents->GotResponseToLockMouseRequest(true);
300}
301
302void Shell::CloseContents(WebContents* source) {
303  Close();
304}
305
306bool Shell::CanOverscrollContent() const {
307#if defined(USE_AURA)
308  return true;
309#else
310  return false;
311#endif
312}
313
314void Shell::DidNavigateMainFramePostCommit(WebContents* web_contents) {
315  PlatformSetAddressBarURL(web_contents->GetLastCommittedURL());
316}
317
318JavaScriptDialogManager* Shell::GetJavaScriptDialogManager() {
319  if (!dialog_manager_)
320    dialog_manager_.reset(new ShellJavaScriptDialogManager());
321  return dialog_manager_.get();
322}
323
324bool Shell::AddMessageToConsole(WebContents* source,
325                                int32 level,
326                                const string16& message,
327                                int32 line_no,
328                                const string16& source_id) {
329  return CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
330}
331
332void Shell::RendererUnresponsive(WebContents* source) {
333  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
334    return;
335  WebKitTestController::Get()->RendererUnresponsive();
336}
337
338void Shell::ActivateContents(WebContents* contents) {
339  contents->GetRenderViewHost()->Focus();
340}
341
342void Shell::DeactivateContents(WebContents* contents) {
343  contents->GetRenderViewHost()->Blur();
344}
345
346void Shell::WorkerCrashed(WebContents* source) {
347  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
348    return;
349  WebKitTestController::Get()->WorkerCrashed();
350}
351
352void Shell::TitleWasSet(NavigationEntry* entry, bool explicit_set) {
353  if (entry)
354    PlatformSetTitle(entry->GetTitle());
355}
356
357void Shell::OnDevToolsWebContentsDestroyed() {
358  devtools_observer_.reset();
359  devtools_frontend_ = NULL;
360}
361
362}  // namespace content
363