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