shell.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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 36namespace content { 37 38const int Shell::kDefaultTestWindowWidthDip = 800; 39const int Shell::kDefaultTestWindowHeightDip = 600; 40 41std::vector<Shell*> Shell::windows_; 42base::Callback<void(Shell*)> Shell::shell_created_callback_; 43 44bool Shell::quit_message_loop_ = true; 45 46class 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 64Shell::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 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 151gfx::Size Shell::AdjustWindowSize(const gfx::Size& initial_size) { 152 if (!initial_size.IsEmpty()) 153 return initial_size; 154 return gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip); 155} 156 157Shell* Shell::CreateNewWindow(BrowserContext* browser_context, 158 const GURL& url, 159 SiteInstance* site_instance, 160 int routing_id, 161 const gfx::Size& initial_size) { 162 WebContents::CreateParams create_params(browser_context, site_instance); 163 create_params.routing_id = routing_id; 164 create_params.initial_size = AdjustWindowSize(initial_size); 165 WebContents* web_contents = WebContents::Create(create_params); 166 Shell* shell = CreateShell(web_contents, create_params.initial_size); 167 if (!url.is_empty()) 168 shell->LoadURL(url); 169 return shell; 170} 171 172void Shell::LoadURL(const GURL& url) { 173 LoadURLForFrame(url, std::string()); 174} 175 176void Shell::LoadURLForFrame(const GURL& url, const std::string& frame_name) { 177 NavigationController::LoadURLParams params(url); 178 params.transition_type = PageTransitionFromInt( 179 PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR); 180 params.frame_name = frame_name; 181 web_contents_->GetController().LoadURLWithParams(params); 182 web_contents_->GetView()->Focus(); 183} 184 185void Shell::AddNewContents(WebContents* source, 186 WebContents* new_contents, 187 WindowOpenDisposition disposition, 188 const gfx::Rect& initial_pos, 189 bool user_gesture, 190 bool* was_blocked) { 191 CreateShell(new_contents, AdjustWindowSize(initial_pos.size())); 192 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 193 NotifyDoneForwarder::CreateForWebContents(new_contents); 194} 195 196void Shell::GoBackOrForward(int offset) { 197 web_contents_->GetController().GoToOffset(offset); 198 web_contents_->GetView()->Focus(); 199} 200 201void Shell::Reload() { 202 web_contents_->GetController().Reload(false); 203 web_contents_->GetView()->Focus(); 204} 205 206void Shell::Stop() { 207 web_contents_->Stop(); 208 web_contents_->GetView()->Focus(); 209} 210 211void Shell::UpdateNavigationControls() { 212 int current_index = web_contents_->GetController().GetCurrentEntryIndex(); 213 int max_index = web_contents_->GetController().GetEntryCount() - 1; 214 215 PlatformEnableUIControl(BACK_BUTTON, current_index > 0); 216 PlatformEnableUIControl(FORWARD_BUTTON, current_index < max_index); 217 PlatformEnableUIControl(STOP_BUTTON, web_contents_->IsLoading()); 218} 219 220void Shell::ShowDevTools() { 221 if (devtools_frontend_) { 222 devtools_frontend_->Focus(); 223 return; 224 } 225 devtools_frontend_ = ShellDevToolsFrontend::Show(web_contents()); 226 devtools_observer_.reset(new DevToolsWebContentsObserver( 227 this, devtools_frontend_->frontend_shell()->web_contents())); 228} 229 230void Shell::CloseDevTools() { 231 if (!devtools_frontend_) 232 return; 233 devtools_observer_.reset(); 234 devtools_frontend_->Close(); 235 devtools_frontend_ = NULL; 236} 237 238gfx::NativeView Shell::GetContentView() { 239 if (!web_contents_) 240 return NULL; 241 return web_contents_->GetView()->GetNativeView(); 242} 243 244WebContents* Shell::OpenURLFromTab(WebContents* source, 245 const OpenURLParams& params) { 246 // CURRENT_TAB is the only one we implement for now. 247 if (params.disposition != CURRENT_TAB) 248 return NULL; 249 NavigationController::LoadURLParams load_url_params(params.url); 250 load_url_params.referrer = params.referrer; 251 load_url_params.transition_type = params.transition; 252 load_url_params.extra_headers = params.extra_headers; 253 load_url_params.should_replace_current_entry = 254 params.should_replace_current_entry; 255 256 if (params.transferred_global_request_id != GlobalRequestID()) { 257 load_url_params.is_renderer_initiated = params.is_renderer_initiated; 258 load_url_params.transferred_global_request_id = 259 params.transferred_global_request_id; 260 } else if (params.is_renderer_initiated) { 261 load_url_params.is_renderer_initiated = true; 262 } 263 264 source->GetController().LoadURLWithParams(load_url_params); 265 return source; 266} 267 268void Shell::LoadingStateChanged(WebContents* source) { 269 UpdateNavigationControls(); 270 PlatformSetIsLoading(source->IsLoading()); 271} 272 273void Shell::ToggleFullscreenModeForTab(WebContents* web_contents, 274 bool enter_fullscreen) { 275#if defined(OS_ANDROID) 276 PlatformToggleFullscreenModeForTab(web_contents, enter_fullscreen); 277#endif 278 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 279 return; 280 if (is_fullscreen_ != enter_fullscreen) { 281 is_fullscreen_ = enter_fullscreen; 282 web_contents->GetRenderViewHost()->WasResized(); 283 } 284} 285 286bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) const { 287#if defined(OS_ANDROID) 288 return PlatformIsFullscreenForTabOrPending(web_contents); 289#else 290 return is_fullscreen_; 291#endif 292} 293 294void Shell::RequestToLockMouse(WebContents* web_contents, 295 bool user_gesture, 296 bool last_unlocked_by_target) { 297 web_contents->GotResponseToLockMouseRequest(true); 298} 299 300void Shell::CloseContents(WebContents* source) { 301 Close(); 302} 303 304bool Shell::CanOverscrollContent() const { 305#if defined(USE_AURA) 306 return true; 307#else 308 return false; 309#endif 310} 311 312void Shell::DidNavigateMainFramePostCommit(WebContents* web_contents) { 313 PlatformSetAddressBarURL(web_contents->GetLastCommittedURL()); 314} 315 316JavaScriptDialogManager* Shell::GetJavaScriptDialogManager() { 317 if (!dialog_manager_) 318 dialog_manager_.reset(new ShellJavaScriptDialogManager()); 319 return dialog_manager_.get(); 320} 321 322bool Shell::AddMessageToConsole(WebContents* source, 323 int32 level, 324 const string16& message, 325 int32 line_no, 326 const string16& source_id) { 327 return CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree); 328} 329 330void Shell::RendererUnresponsive(WebContents* source) { 331 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 332 return; 333 WebKitTestController::Get()->RendererUnresponsive(); 334} 335 336void Shell::ActivateContents(WebContents* contents) { 337 contents->GetRenderViewHost()->Focus(); 338} 339 340void Shell::DeactivateContents(WebContents* contents) { 341 contents->GetRenderViewHost()->Blur(); 342} 343 344void Shell::WorkerCrashed(WebContents* source) { 345 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 346 return; 347 WebKitTestController::Get()->WorkerCrashed(); 348} 349 350void Shell::TitleWasSet(NavigationEntry* entry, bool explicit_set) { 351 if (entry) 352 PlatformSetTitle(entry->GetTitle()); 353} 354 355void Shell::OnDevToolsWebContentsDestroyed() { 356 devtools_observer_.reset(); 357 devtools_frontend_ = NULL; 358} 359 360} // namespace content 361