shell.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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/notification_details.h" 19#include "content/public/browser/notification_source.h" 20#include "content/public/browser/notification_types.h" 21#include "content/public/browser/render_view_host.h" 22#include "content/public/browser/web_contents.h" 23#include "content/public/browser/web_contents_observer.h" 24#include "content/public/browser/web_contents_view.h" 25#include "content/public/common/renderer_preferences.h" 26#include "content/shell/browser/notify_done_forwarder.h" 27#include "content/shell/browser/shell_browser_main_parts.h" 28#include "content/shell/browser/shell_content_browser_client.h" 29#include "content/shell/browser/shell_devtools_frontend.h" 30#include "content/shell/browser/shell_javascript_dialog_manager.h" 31#include "content/shell/browser/webkit_test_controller.h" 32#include "content/shell/common/shell_messages.h" 33#include "content/shell/common/shell_switches.h" 34 35namespace content { 36 37const int Shell::kDefaultTestWindowWidthDip = 800; 38const int Shell::kDefaultTestWindowHeightDip = 600; 39 40std::vector<Shell*> Shell::windows_; 41base::Callback<void(Shell*)> Shell::shell_created_callback_; 42 43bool Shell::quit_message_loop_ = true; 44 45class Shell::DevToolsWebContentsObserver : public WebContentsObserver { 46 public: 47 DevToolsWebContentsObserver(Shell* shell, WebContents* web_contents) 48 : WebContentsObserver(web_contents), 49 shell_(shell) { 50 } 51 52 // WebContentsObserver 53 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE { 54 shell_->OnDevToolsWebContentsDestroyed(); 55 } 56 57 private: 58 Shell* shell_; 59 60 DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver); 61}; 62 63Shell::Shell(WebContents* web_contents) 64 : devtools_frontend_(NULL), 65 is_fullscreen_(false), 66 window_(NULL), 67 url_edit_view_(NULL), 68#if defined(OS_WIN) && !defined(USE_AURA) 69 default_edit_wnd_proc_(0), 70#endif 71 headless_(false) { 72 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 73 if (command_line.HasSwitch(switches::kDumpRenderTree)) 74 headless_ = true; 75 registrar_.Add(this, NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED, 76 Source<WebContents>(web_contents)); 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 base::MessageLoop::current()->RunUntilIdle(); 127} 128 129void Shell::SetShellCreatedCallback( 130 base::Callback<void(Shell*)> shell_created_callback) { 131 DCHECK(shell_created_callback_.is_null()); 132 shell_created_callback_ = shell_created_callback; 133} 134 135Shell* Shell::FromRenderViewHost(RenderViewHost* rvh) { 136 for (size_t i = 0; i < windows_.size(); ++i) { 137 if (windows_[i]->web_contents() && 138 windows_[i]->web_contents()->GetRenderViewHost() == rvh) { 139 return windows_[i]; 140 } 141 } 142 return NULL; 143} 144 145// static 146void Shell::Initialize() { 147 PlatformInitialize( 148 gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip)); 149} 150 151Shell* Shell::CreateNewWindow(BrowserContext* browser_context, 152 const GURL& url, 153 SiteInstance* site_instance, 154 int routing_id, 155 const gfx::Size& initial_size) { 156 WebContents::CreateParams create_params(browser_context, site_instance); 157 create_params.routing_id = routing_id; 158 if (!initial_size.IsEmpty()) 159 create_params.initial_size = initial_size; 160 else 161 create_params.initial_size = 162 gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip); 163 WebContents* web_contents = WebContents::Create(create_params); 164 Shell* shell = CreateShell(web_contents, create_params.initial_size); 165 if (!url.is_empty()) 166 shell->LoadURL(url); 167 return shell; 168} 169 170void Shell::LoadURL(const GURL& url) { 171 LoadURLForFrame(url, std::string()); 172} 173 174void Shell::LoadURLForFrame(const GURL& url, const std::string& frame_name) { 175 NavigationController::LoadURLParams params(url); 176 params.transition_type = PageTransitionFromInt( 177 PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR); 178 params.frame_name = frame_name; 179 web_contents_->GetController().LoadURLWithParams(params); 180 web_contents_->GetView()->Focus(); 181} 182 183void Shell::GoBackOrForward(int offset) { 184 web_contents_->GetController().GoToOffset(offset); 185 web_contents_->GetView()->Focus(); 186} 187 188void Shell::Reload() { 189 web_contents_->GetController().Reload(false); 190 web_contents_->GetView()->Focus(); 191} 192 193void Shell::Stop() { 194 web_contents_->Stop(); 195 web_contents_->GetView()->Focus(); 196} 197 198void Shell::UpdateNavigationControls() { 199 int current_index = web_contents_->GetController().GetCurrentEntryIndex(); 200 int max_index = web_contents_->GetController().GetEntryCount() - 1; 201 202 PlatformEnableUIControl(BACK_BUTTON, current_index > 0); 203 PlatformEnableUIControl(FORWARD_BUTTON, current_index < max_index); 204 PlatformEnableUIControl(STOP_BUTTON, web_contents_->IsLoading()); 205} 206 207void Shell::ShowDevTools() { 208 if (devtools_frontend_) { 209 devtools_frontend_->Focus(); 210 return; 211 } 212 devtools_frontend_ = ShellDevToolsFrontend::Show(web_contents()); 213 devtools_observer_.reset(new DevToolsWebContentsObserver( 214 this, devtools_frontend_->frontend_shell()->web_contents())); 215} 216 217void Shell::CloseDevTools() { 218 if (!devtools_frontend_) 219 return; 220 devtools_observer_.reset(); 221 devtools_frontend_->Close(); 222 devtools_frontend_ = NULL; 223} 224 225gfx::NativeView Shell::GetContentView() { 226 if (!web_contents_) 227 return NULL; 228 return web_contents_->GetView()->GetNativeView(); 229} 230 231WebContents* Shell::OpenURLFromTab(WebContents* source, 232 const OpenURLParams& params) { 233 // CURRENT_TAB is the only one we implement for now. 234 if (params.disposition != CURRENT_TAB) 235 return NULL; 236 NavigationController::LoadURLParams load_url_params(params.url); 237 load_url_params.referrer = params.referrer; 238 load_url_params.transition_type = params.transition; 239 load_url_params.extra_headers = params.extra_headers; 240 load_url_params.should_replace_current_entry = 241 params.should_replace_current_entry; 242 243 if (params.transferred_global_request_id != GlobalRequestID()) { 244 load_url_params.is_renderer_initiated = params.is_renderer_initiated; 245 load_url_params.transferred_global_request_id = 246 params.transferred_global_request_id; 247 } else if (params.is_renderer_initiated) { 248 load_url_params.is_renderer_initiated = true; 249 } 250 251 source->GetController().LoadURLWithParams(load_url_params); 252 return source; 253} 254 255void Shell::LoadingStateChanged(WebContents* source) { 256 UpdateNavigationControls(); 257 PlatformSetIsLoading(source->IsLoading()); 258} 259 260void Shell::ToggleFullscreenModeForTab(WebContents* web_contents, 261 bool enter_fullscreen) { 262#if defined(OS_ANDROID) 263 PlatformToggleFullscreenModeForTab(web_contents, enter_fullscreen); 264#endif 265 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 266 return; 267 if (is_fullscreen_ != enter_fullscreen) { 268 is_fullscreen_ = enter_fullscreen; 269 web_contents->GetRenderViewHost()->WasResized(); 270 } 271} 272 273bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) const { 274#if defined(OS_ANDROID) 275 return PlatformIsFullscreenForTabOrPending(web_contents); 276#else 277 return is_fullscreen_; 278#endif 279} 280 281void Shell::RequestToLockMouse(WebContents* web_contents, 282 bool user_gesture, 283 bool last_unlocked_by_target) { 284 web_contents->GotResponseToLockMouseRequest(true); 285} 286 287void Shell::CloseContents(WebContents* source) { 288 Close(); 289} 290 291bool Shell::CanOverscrollContent() const { 292#if defined(USE_AURA) 293 return true; 294#else 295 return false; 296#endif 297} 298 299void Shell::WebContentsCreated(WebContents* source_contents, 300 int64 source_frame_id, 301 const string16& frame_name, 302 const GURL& target_url, 303 WebContents* new_contents) { 304 CreateShell(new_contents, source_contents->GetView()->GetContainerSize()); 305 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 306 NotifyDoneForwarder::CreateForWebContents(new_contents); 307} 308 309void Shell::DidNavigateMainFramePostCommit(WebContents* web_contents) { 310 PlatformSetAddressBarURL(web_contents->GetLastCommittedURL()); 311} 312 313JavaScriptDialogManager* Shell::GetJavaScriptDialogManager() { 314 if (!dialog_manager_) 315 dialog_manager_.reset(new ShellJavaScriptDialogManager()); 316 return dialog_manager_.get(); 317} 318 319bool Shell::AddMessageToConsole(WebContents* source, 320 int32 level, 321 const string16& message, 322 int32 line_no, 323 const string16& source_id) { 324 return CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree); 325} 326 327void Shell::RendererUnresponsive(WebContents* source) { 328 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 329 return; 330 WebKitTestController::Get()->RendererUnresponsive(); 331} 332 333void Shell::ActivateContents(WebContents* contents) { 334 contents->GetRenderViewHost()->Focus(); 335} 336 337void Shell::DeactivateContents(WebContents* contents) { 338 contents->GetRenderViewHost()->Blur(); 339} 340 341void Shell::WorkerCrashed(WebContents* source) { 342 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 343 return; 344 WebKitTestController::Get()->WorkerCrashed(); 345} 346 347void Shell::Observe(int type, 348 const NotificationSource& source, 349 const NotificationDetails& details) { 350 if (type == NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED) { 351 std::pair<NavigationEntry*, bool>* title = 352 Details<std::pair<NavigationEntry*, bool> >(details).ptr(); 353 354 if (title->first) { 355 string16 text = title->first->GetTitle(); 356 PlatformSetTitle(text); 357 } 358 } else { 359 NOTREACHED(); 360 } 361} 362 363void Shell::OnDevToolsWebContentsDestroyed() { 364 devtools_observer_.reset(); 365 devtools_frontend_ = NULL; 366} 367 368} // namespace content 369