• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 namespace content {
37 
38 const int Shell::kDefaultTestWindowWidthDip = 800;
39 const int Shell::kDefaultTestWindowHeightDip = 600;
40 
41 std::vector<Shell*> Shell::windows_;
42 base::Callback<void(Shell*)> Shell::shell_created_callback_;
43 
44 bool Shell::quit_message_loop_ = true;
45 
46 class Shell::DevToolsWebContentsObserver : public WebContentsObserver {
47  public:
DevToolsWebContentsObserver(Shell * shell,WebContents * web_contents)48   DevToolsWebContentsObserver(Shell* shell, WebContents* web_contents)
49       : WebContentsObserver(web_contents),
50         shell_(shell) {
51   }
52 
53   // WebContentsObserver
WebContentsDestroyed(WebContents * web_contents)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 
Shell(WebContents * web_contents)64 Shell::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 
~Shell()85 Shell::~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 
CreateShell(WebContents * web_contents,const gfx::Size & initial_size)100 Shell* 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 
CloseAllWindows()120 void 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 
SetShellCreatedCallback(base::Callback<void (Shell *)> shell_created_callback)130 void 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 
FromRenderViewHost(RenderViewHost * rvh)136 Shell* 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
Initialize()147 void Shell::Initialize() {
148   PlatformInitialize(
149       gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip));
150 }
151 
AdjustWindowSize(const gfx::Size & initial_size)152 gfx::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 
CreateNewWindow(BrowserContext * browser_context,const GURL & url,SiteInstance * site_instance,int routing_id,const gfx::Size & initial_size)158 Shell* 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 
LoadURL(const GURL & url)173 void Shell::LoadURL(const GURL& url) {
174   LoadURLForFrame(url, std::string());
175 }
176 
LoadURLForFrame(const GURL & url,const std::string & frame_name)177 void 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 
AddNewContents(WebContents * source,WebContents * new_contents,WindowOpenDisposition disposition,const gfx::Rect & initial_pos,bool user_gesture,bool * was_blocked)186 void 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 
GoBackOrForward(int offset)197 void Shell::GoBackOrForward(int offset) {
198   web_contents_->GetController().GoToOffset(offset);
199   web_contents_->GetView()->Focus();
200 }
201 
Reload()202 void Shell::Reload() {
203   web_contents_->GetController().Reload(false);
204   web_contents_->GetView()->Focus();
205 }
206 
Stop()207 void Shell::Stop() {
208   web_contents_->Stop();
209   web_contents_->GetView()->Focus();
210 }
211 
UpdateNavigationControls()212 void 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 
ShowDevTools()221 void 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 
CloseDevTools()231 void Shell::CloseDevTools() {
232   if (!devtools_frontend_)
233     return;
234   devtools_observer_.reset();
235   devtools_frontend_->Close();
236   devtools_frontend_ = NULL;
237 }
238 
GetContentView()239 gfx::NativeView Shell::GetContentView() {
240   if (!web_contents_)
241     return NULL;
242   return web_contents_->GetView()->GetNativeView();
243 }
244 
OpenURLFromTab(WebContents * source,const OpenURLParams & params)245 WebContents* 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 
LoadingStateChanged(WebContents * source)270 void Shell::LoadingStateChanged(WebContents* source) {
271   UpdateNavigationControls();
272   PlatformSetIsLoading(source->IsLoading());
273 }
274 
ToggleFullscreenModeForTab(WebContents * web_contents,bool enter_fullscreen)275 void 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 
IsFullscreenForTabOrPending(const WebContents * web_contents) const288 bool 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 
RequestToLockMouse(WebContents * web_contents,bool user_gesture,bool last_unlocked_by_target)296 void Shell::RequestToLockMouse(WebContents* web_contents,
297                                bool user_gesture,
298                                bool last_unlocked_by_target) {
299   web_contents->GotResponseToLockMouseRequest(true);
300 }
301 
CloseContents(WebContents * source)302 void Shell::CloseContents(WebContents* source) {
303   Close();
304 }
305 
CanOverscrollContent() const306 bool Shell::CanOverscrollContent() const {
307 #if defined(USE_AURA)
308   return true;
309 #else
310   return false;
311 #endif
312 }
313 
DidNavigateMainFramePostCommit(WebContents * web_contents)314 void Shell::DidNavigateMainFramePostCommit(WebContents* web_contents) {
315   PlatformSetAddressBarURL(web_contents->GetLastCommittedURL());
316 }
317 
GetJavaScriptDialogManager()318 JavaScriptDialogManager* Shell::GetJavaScriptDialogManager() {
319   if (!dialog_manager_)
320     dialog_manager_.reset(new ShellJavaScriptDialogManager());
321   return dialog_manager_.get();
322 }
323 
AddMessageToConsole(WebContents * source,int32 level,const base::string16 & message,int32 line_no,const base::string16 & source_id)324 bool Shell::AddMessageToConsole(WebContents* source,
325                                 int32 level,
326                                 const base::string16& message,
327                                 int32 line_no,
328                                 const base::string16& source_id) {
329   return CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
330 }
331 
RendererUnresponsive(WebContents * source)332 void Shell::RendererUnresponsive(WebContents* source) {
333   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
334     return;
335   WebKitTestController::Get()->RendererUnresponsive();
336 }
337 
ActivateContents(WebContents * contents)338 void Shell::ActivateContents(WebContents* contents) {
339   contents->GetRenderViewHost()->Focus();
340 }
341 
DeactivateContents(WebContents * contents)342 void Shell::DeactivateContents(WebContents* contents) {
343   contents->GetRenderViewHost()->Blur();
344 }
345 
WorkerCrashed(WebContents * source)346 void Shell::WorkerCrashed(WebContents* source) {
347   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
348     return;
349   WebKitTestController::Get()->WorkerCrashed();
350 }
351 
TitleWasSet(NavigationEntry * entry,bool explicit_set)352 void Shell::TitleWasSet(NavigationEntry* entry, bool explicit_set) {
353   if (entry)
354     PlatformSetTitle(entry->GetTitle());
355 }
356 
OnDevToolsWebContentsDestroyed()357 void Shell::OnDevToolsWebContentsDestroyed() {
358   devtools_observer_.reset();
359   devtools_frontend_ = NULL;
360 }
361 
362 }  // namespace content
363