• 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_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"
30 
31 namespace content {
32 
33 const int Shell::kDefaultTestWindowWidthDip = 800;
34 const int Shell::kDefaultTestWindowHeightDip = 600;
35 
36 std::vector<Shell*> Shell::windows_;
37 base::Callback<void(Shell*)> Shell::shell_created_callback_;
38 
39 bool Shell::quit_message_loop_ = true;
40 
41 class Shell::DevToolsWebContentsObserver : public WebContentsObserver {
42  public:
DevToolsWebContentsObserver(Shell * shell,WebContents * web_contents)43   DevToolsWebContentsObserver(Shell* shell, WebContents* web_contents)
44       : WebContentsObserver(web_contents),
45         shell_(shell) {
46   }
47 
48   // WebContentsObserver
WebContentsDestroyed()49   virtual void WebContentsDestroyed() OVERRIDE {
50     shell_->OnDevToolsWebContentsDestroyed();
51   }
52 
53  private:
54   Shell* shell_;
55 
56   DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver);
57 };
58 
Shell(WebContents * web_contents)59 Shell::Shell(WebContents* web_contents)
60     : WebContentsObserver(web_contents),
61       devtools_frontend_(NULL),
62       is_fullscreen_(false),
63       window_(NULL),
64       url_edit_view_(NULL),
65       headless_(false) {
66   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
67   if (command_line.HasSwitch(switches::kDumpRenderTree))
68     headless_ = true;
69   windows_.push_back(this);
70 
71   if (!shell_created_callback_.is_null()) {
72     shell_created_callback_.Run(this);
73     shell_created_callback_.Reset();
74   }
75 }
76 
~Shell()77 Shell::~Shell() {
78   PlatformCleanUp();
79 
80   for (size_t i = 0; i < windows_.size(); ++i) {
81     if (windows_[i] == this) {
82       windows_.erase(windows_.begin() + i);
83       break;
84     }
85   }
86 
87   if (windows_.empty() && quit_message_loop_) {
88     if (headless_)
89       PlatformExit();
90     base::MessageLoop::current()->PostTask(FROM_HERE,
91                                            base::MessageLoop::QuitClosure());
92   }
93 }
94 
CreateShell(WebContents * web_contents,const gfx::Size & initial_size)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());
99 
100   shell->web_contents_.reset(web_contents);
101   web_contents->SetDelegate(shell);
102 
103   shell->PlatformSetContents();
104 
105   shell->PlatformResizeSubViews();
106 
107   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
108     web_contents->GetMutableRendererPrefs()->use_custom_colors = false;
109     web_contents->GetRenderViewHost()->SyncRendererPrefs();
110   }
111 
112   return shell;
113 }
114 
CloseAllWindows()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();
121   PlatformExit();
122   base::MessageLoop::current()->RunUntilIdle();
123 }
124 
SetShellCreatedCallback(base::Callback<void (Shell *)> shell_created_callback)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;
129 }
130 
FromRenderViewHost(RenderViewHost * rvh)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) {
135       return windows_[i];
136     }
137   }
138   return NULL;
139 }
140 
141 // static
Initialize()142 void Shell::Initialize() {
143   PlatformInitialize(
144       gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip));
145 }
146 
AdjustWindowSize(const gfx::Size & initial_size)147 gfx::Size Shell::AdjustWindowSize(const gfx::Size& initial_size) {
148   if (!initial_size.IsEmpty())
149     return initial_size;
150   return gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip);
151 }
152 
CreateNewWindow(BrowserContext * browser_context,const GURL & url,SiteInstance * site_instance,int routing_id,const gfx::Size & initial_size)153 Shell* Shell::CreateNewWindow(BrowserContext* browser_context,
154                               const GURL& url,
155                               SiteInstance* site_instance,
156                               int routing_id,
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);
163   if (!url.is_empty())
164     shell->LoadURL(url);
165   return shell;
166 }
167 
LoadURL(const GURL & url)168 void Shell::LoadURL(const GURL& url) {
169   LoadURLForFrame(url, std::string());
170 }
171 
LoadURLForFrame(const GURL & url,const std::string & frame_name)172 void Shell::LoadURLForFrame(const GURL& url, const std::string& frame_name) {
173   NavigationController::LoadURLParams params(url);
174   params.transition_type = ui::PageTransitionFromInt(
175       ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
176   params.frame_name = frame_name;
177   web_contents_->GetController().LoadURLWithParams(params);
178   web_contents_->Focus();
179 }
180 
LoadDataWithBaseURL(const GURL & url,const std::string & data,const GURL & base_url)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();
191 }
192 
AddNewContents(WebContents * source,WebContents * new_contents,WindowOpenDisposition disposition,const gfx::Rect & initial_pos,bool user_gesture,bool * was_blocked)193 void Shell::AddNewContents(WebContents* source,
194                            WebContents* new_contents,
195                            WindowOpenDisposition disposition,
196                            const gfx::Rect& initial_pos,
197                            bool user_gesture,
198                            bool* was_blocked) {
199   CreateShell(new_contents, AdjustWindowSize(initial_pos.size()));
200   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
201     NotifyDoneForwarder::CreateForWebContents(new_contents);
202 }
203 
GoBackOrForward(int offset)204 void Shell::GoBackOrForward(int offset) {
205   web_contents_->GetController().GoToOffset(offset);
206   web_contents_->Focus();
207 }
208 
Reload()209 void Shell::Reload() {
210   web_contents_->GetController().Reload(false);
211   web_contents_->Focus();
212 }
213 
Stop()214 void Shell::Stop() {
215   web_contents_->Stop();
216   web_contents_->Focus();
217 }
218 
UpdateNavigationControls(bool to_different_document)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;
222 
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());
227 }
228 
ShowDevTools()229 void Shell::ShowDevTools() {
230   InnerShowDevTools("", "");
231 }
232 
ShowDevToolsForElementAt(int x,int y)233 void Shell::ShowDevToolsForElementAt(int x, int y) {
234   InnerShowDevTools("", "");
235   devtools_frontend_->InspectElementAt(x, y);
236 }
237 
ShowDevToolsForTest(const std::string & settings,const std::string & frontend_url)238 void Shell::ShowDevToolsForTest(const std::string& settings,
239                                 const std::string& frontend_url) {
240   InnerShowDevTools(settings, frontend_url);
241 }
242 
CloseDevTools()243 void Shell::CloseDevTools() {
244   if (!devtools_frontend_)
245     return;
246   devtools_observer_.reset();
247   devtools_frontend_->Close();
248   devtools_frontend_ = NULL;
249 }
250 
GetContentView()251 gfx::NativeView Shell::GetContentView() {
252   if (!web_contents_)
253     return NULL;
254   return web_contents_->GetNativeView();
255 }
256 
OpenURLFromTab(WebContents * source,const OpenURLParams & params)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)
261       return NULL;
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;
269 
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;
276   }
277 
278   source->GetController().LoadURLWithParams(load_url_params);
279   return source;
280 }
281 
LoadingStateChanged(WebContents * source,bool to_different_document)282 void Shell::LoadingStateChanged(WebContents* source,
283     bool to_different_document) {
284   UpdateNavigationControls(to_different_document);
285   PlatformSetIsLoading(source->IsLoading());
286 }
287 
ToggleFullscreenModeForTab(WebContents * web_contents,bool enter_fullscreen)288 void Shell::ToggleFullscreenModeForTab(WebContents* web_contents,
289                                        bool enter_fullscreen) {
290 #if defined(OS_ANDROID)
291   PlatformToggleFullscreenModeForTab(web_contents, enter_fullscreen);
292 #endif
293   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
294     return;
295   if (is_fullscreen_ != enter_fullscreen) {
296     is_fullscreen_ = enter_fullscreen;
297     web_contents->GetRenderViewHost()->WasResized();
298   }
299 }
300 
IsFullscreenForTabOrPending(const WebContents * web_contents) const301 bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) const {
302 #if defined(OS_ANDROID)
303   return PlatformIsFullscreenForTabOrPending(web_contents);
304 #else
305   return is_fullscreen_;
306 #endif
307 }
308 
RequestToLockMouse(WebContents * web_contents,bool user_gesture,bool last_unlocked_by_target)309 void Shell::RequestToLockMouse(WebContents* web_contents,
310                                bool user_gesture,
311                                bool last_unlocked_by_target) {
312   web_contents->GotResponseToLockMouseRequest(true);
313 }
314 
CloseContents(WebContents * source)315 void Shell::CloseContents(WebContents* source) {
316   Close();
317 }
318 
CanOverscrollContent() const319 bool Shell::CanOverscrollContent() const {
320 #if defined(USE_AURA)
321   return true;
322 #else
323   return false;
324 #endif
325 }
326 
DidNavigateMainFramePostCommit(WebContents * web_contents)327 void Shell::DidNavigateMainFramePostCommit(WebContents* web_contents) {
328   PlatformSetAddressBarURL(web_contents->GetLastCommittedURL());
329 }
330 
GetJavaScriptDialogManager()331 JavaScriptDialogManager* Shell::GetJavaScriptDialogManager() {
332   if (!dialog_manager_)
333     dialog_manager_.reset(new ShellJavaScriptDialogManager());
334   return dialog_manager_.get();
335 }
336 
AddMessageToConsole(WebContents * source,int32 level,const base::string16 & message,int32 line_no,const base::string16 & source_id)337 bool Shell::AddMessageToConsole(WebContents* source,
338                                 int32 level,
339                                 const base::string16& message,
340                                 int32 line_no,
341                                 const base::string16& source_id) {
342   return CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
343 }
344 
RendererUnresponsive(WebContents * source)345 void Shell::RendererUnresponsive(WebContents* source) {
346   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
347     return;
348   WebKitTestController::Get()->RendererUnresponsive();
349 }
350 
ActivateContents(WebContents * contents)351 void Shell::ActivateContents(WebContents* contents) {
352   contents->GetRenderViewHost()->Focus();
353 }
354 
DeactivateContents(WebContents * contents)355 void Shell::DeactivateContents(WebContents* contents) {
356   contents->GetRenderViewHost()->Blur();
357 }
358 
WorkerCrashed(WebContents * source)359 void Shell::WorkerCrashed(WebContents* source) {
360   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
361     return;
362   WebKitTestController::Get()->WorkerCrashed();
363 }
364 
HandleContextMenu(const content::ContextMenuParams & params)365 bool Shell::HandleContextMenu(const content::ContextMenuParams& params) {
366   return PlatformHandleContextMenu(params);
367 }
368 
WebContentsFocused(WebContents * contents)369 void Shell::WebContentsFocused(WebContents* contents) {
370 #if defined(TOOLKIT_VIEWS)
371   PlatformWebContentsFocused(contents);
372 #endif
373 }
374 
TitleWasSet(NavigationEntry * entry,bool explicit_set)375 void Shell::TitleWasSet(NavigationEntry* entry, bool explicit_set) {
376   if (entry)
377     PlatformSetTitle(entry->GetTitle());
378 }
379 
InnerShowDevTools(const std::string & settings,const std::string & frontend_url)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()));
387   }
388 
389   devtools_frontend_->Activate();
390   devtools_frontend_->Focus();
391 }
392 
OnDevToolsWebContentsDestroyed()393 void Shell::OnDevToolsWebContentsDestroyed() {
394   devtools_observer_.reset();
395   devtools_frontend_ = NULL;
396 }
397 
398 }  // namespace content
399