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: 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 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 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 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 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 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 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 147 void Shell::Initialize() { 148 PlatformInitialize( 149 gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip)); 150 } 151 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 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 173 void Shell::LoadURL(const GURL& url) { 174 LoadURLForFrame(url, std::string()); 175 } 176 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 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 197 void Shell::GoBackOrForward(int offset) { 198 web_contents_->GetController().GoToOffset(offset); 199 web_contents_->GetView()->Focus(); 200 } 201 202 void Shell::Reload() { 203 web_contents_->GetController().Reload(false); 204 web_contents_->GetView()->Focus(); 205 } 206 207 void Shell::Stop() { 208 web_contents_->Stop(); 209 web_contents_->GetView()->Focus(); 210 } 211 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 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 231 void Shell::CloseDevTools() { 232 if (!devtools_frontend_) 233 return; 234 devtools_observer_.reset(); 235 devtools_frontend_->Close(); 236 devtools_frontend_ = NULL; 237 } 238 239 gfx::NativeView Shell::GetContentView() { 240 if (!web_contents_) 241 return NULL; 242 return web_contents_->GetView()->GetNativeView(); 243 } 244 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 270 void Shell::LoadingStateChanged(WebContents* source) { 271 UpdateNavigationControls(); 272 PlatformSetIsLoading(source->IsLoading()); 273 } 274 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 288 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 296 void Shell::RequestToLockMouse(WebContents* web_contents, 297 bool user_gesture, 298 bool last_unlocked_by_target) { 299 web_contents->GotResponseToLockMouseRequest(true); 300 } 301 302 void Shell::CloseContents(WebContents* source) { 303 Close(); 304 } 305 306 bool Shell::CanOverscrollContent() const { 307 #if defined(USE_AURA) 308 return true; 309 #else 310 return false; 311 #endif 312 } 313 314 void Shell::DidNavigateMainFramePostCommit(WebContents* web_contents) { 315 PlatformSetAddressBarURL(web_contents->GetLastCommittedURL()); 316 } 317 318 JavaScriptDialogManager* Shell::GetJavaScriptDialogManager() { 319 if (!dialog_manager_) 320 dialog_manager_.reset(new ShellJavaScriptDialogManager()); 321 return dialog_manager_.get(); 322 } 323 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 332 void Shell::RendererUnresponsive(WebContents* source) { 333 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 334 return; 335 WebKitTestController::Get()->RendererUnresponsive(); 336 } 337 338 void Shell::ActivateContents(WebContents* contents) { 339 contents->GetRenderViewHost()->Focus(); 340 } 341 342 void Shell::DeactivateContents(WebContents* contents) { 343 contents->GetRenderViewHost()->Blur(); 344 } 345 346 void Shell::WorkerCrashed(WebContents* source) { 347 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 348 return; 349 WebKitTestController::Get()->WorkerCrashed(); 350 } 351 352 void Shell::TitleWasSet(NavigationEntry* entry, bool explicit_set) { 353 if (entry) 354 PlatformSetTitle(entry->GetTitle()); 355 } 356 357 void Shell::OnDevToolsWebContentsDestroyed() { 358 devtools_observer_.reset(); 359 devtools_frontend_ = NULL; 360 } 361 362 } // namespace content 363