1 // Copyright (c) 2012 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/browser/web_contents/web_contents_impl.h" 6 7 #include <utility> 8 9 #include "base/command_line.h" 10 #include "base/debug/trace_event.h" 11 #include "base/lazy_instance.h" 12 #include "base/logging.h" 13 #include "base/metrics/histogram.h" 14 #include "base/metrics/stats_counters.h" 15 #include "base/process/process.h" 16 #include "base/strings/string16.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_util.h" 19 #include "base/strings/utf_string_conversions.h" 20 #include "base/time/time.h" 21 #include "content/browser/browser_plugin/browser_plugin_embedder.h" 22 #include "content/browser/browser_plugin/browser_plugin_guest.h" 23 #include "content/browser/browser_plugin/browser_plugin_guest_manager.h" 24 #include "content/browser/child_process_security_policy_impl.h" 25 #include "content/browser/devtools/devtools_manager_impl.h" 26 #include "content/browser/dom_storage/dom_storage_context_wrapper.h" 27 #include "content/browser/dom_storage/session_storage_namespace_impl.h" 28 #include "content/browser/download/download_stats.h" 29 #include "content/browser/download/mhtml_generation_manager.h" 30 #include "content/browser/download/save_package.h" 31 #include "content/browser/frame_host/interstitial_page_impl.h" 32 #include "content/browser/frame_host/navigation_entry_impl.h" 33 #include "content/browser/frame_host/navigator_impl.h" 34 #include "content/browser/frame_host/render_frame_host_impl.h" 35 #include "content/browser/host_zoom_map_impl.h" 36 #include "content/browser/loader/resource_dispatcher_host_impl.h" 37 #include "content/browser/message_port_message_filter.h" 38 #include "content/browser/message_port_service.h" 39 #include "content/browser/power_save_blocker_impl.h" 40 #include "content/browser/renderer_host/render_process_host_impl.h" 41 #include "content/browser/renderer_host/render_view_host_impl.h" 42 #include "content/browser/renderer_host/render_widget_host_impl.h" 43 #include "content/browser/site_instance_impl.h" 44 #include "content/browser/web_contents/web_contents_view_guest.h" 45 #include "content/browser/webui/generic_handler.h" 46 #include "content/browser/webui/web_ui_controller_factory_registry.h" 47 #include "content/browser/webui/web_ui_impl.h" 48 #include "content/common/browser_plugin/browser_plugin_constants.h" 49 #include "content/common/browser_plugin/browser_plugin_messages.h" 50 #include "content/common/frame_messages.h" 51 #include "content/common/image_messages.h" 52 #include "content/common/ssl_status_serialization.h" 53 #include "content/common/view_messages.h" 54 #include "content/port/browser/render_view_host_delegate_view.h" 55 #include "content/port/browser/render_widget_host_view_port.h" 56 #include "content/public/browser/browser_context.h" 57 #include "content/public/browser/color_chooser.h" 58 #include "content/public/browser/content_browser_client.h" 59 #include "content/public/browser/devtools_agent_host.h" 60 #include "content/public/browser/download_manager.h" 61 #include "content/public/browser/download_url_parameters.h" 62 #include "content/public/browser/invalidate_type.h" 63 #include "content/public/browser/javascript_dialog_manager.h" 64 #include "content/public/browser/load_from_memory_cache_details.h" 65 #include "content/public/browser/load_notification_details.h" 66 #include "content/public/browser/navigation_details.h" 67 #include "content/public/browser/notification_details.h" 68 #include "content/public/browser/notification_service.h" 69 #include "content/public/browser/resource_request_details.h" 70 #include "content/public/browser/storage_partition.h" 71 #include "content/public/browser/user_metrics.h" 72 #include "content/public/browser/web_contents_delegate.h" 73 #include "content/public/browser/web_contents_observer.h" 74 #include "content/public/browser/web_contents_view.h" 75 #include "content/public/common/bindings_policy.h" 76 #include "content/public/common/content_constants.h" 77 #include "content/public/common/content_switches.h" 78 #include "content/public/common/page_zoom.h" 79 #include "content/public/common/result_codes.h" 80 #include "content/public/common/url_constants.h" 81 #include "content/public/common/url_utils.h" 82 #include "net/base/mime_util.h" 83 #include "net/base/net_util.h" 84 #include "net/http/http_cache.h" 85 #include "net/http/http_transaction_factory.h" 86 #include "net/url_request/url_request_context.h" 87 #include "net/url_request/url_request_context_getter.h" 88 #include "ui/base/layout.h" 89 #include "ui/gfx/display.h" 90 #include "ui/gfx/screen.h" 91 #include "ui/gl/gl_switches.h" 92 #include "webkit/common/webpreferences.h" 93 94 #if defined(OS_ANDROID) 95 #include "content/browser/android/date_time_chooser_android.h" 96 #include "content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h" 97 #include "content/browser/web_contents/web_contents_android.h" 98 #include "content/common/java_bridge_messages.h" 99 #include "content/public/browser/android/content_view_core.h" 100 #endif 101 102 #if defined(OS_MACOSX) 103 #include "base/mac/foundation_util.h" 104 #include "ui/gl/io_surface_support_mac.h" 105 #endif 106 107 // Cross-Site Navigations 108 // 109 // If a WebContentsImpl is told to navigate to a different web site (as 110 // determined by SiteInstance), it will replace its current RenderViewHost with 111 // a new RenderViewHost dedicated to the new SiteInstance. This works as 112 // follows: 113 // 114 // - RVHM::Navigate determines whether the destination is cross-site, and if so, 115 // it creates a pending_render_view_host_. 116 // - The pending RVH is "suspended," so that no navigation messages are sent to 117 // its renderer until the beforeunload JavaScript handler has a chance to 118 // run in the current RVH. 119 // - The pending RVH tells CrossSiteRequestManager (a thread-safe singleton) 120 // that it has a pending cross-site request. We will check this on the IO 121 // thread when deciding how to handle the response. 122 // - The current RVH runs its beforeunload handler. If it returns false, we 123 // cancel all the pending logic. Otherwise we allow the pending RVH to send 124 // the navigation request to its renderer. 125 // - ResourceDispatcherHost receives a ResourceRequest on the IO thread for the 126 // main resource load on the pending RVH. It creates a 127 // CrossSiteResourceHandler to check whether a process swap is needed when 128 // the request is ready to commit. 129 // - When RDH receives a response, the BufferedResourceHandler determines 130 // whether it is a download. If so, it sends a message to the new renderer 131 // causing it to cancel the request, and the download proceeds. For now, the 132 // pending RVH remains until the next DidNavigate event for this 133 // WebContentsImpl. This isn't ideal, but it doesn't affect any functionality. 134 // - After RDH receives a response and determines that it is safe and not a 135 // download, the CrossSiteResourceHandler checks whether a process swap is 136 // needed (either because CrossSiteRequestManager has state for it or because 137 // a transfer was needed for a redirect). 138 // - If so, CrossSiteResourceHandler pauses the response to first run the old 139 // page's unload handler. It does this by asynchronously calling the 140 // OnCrossSiteResponse method of RenderFrameHostManager on the UI thread, 141 // which sends a SwapOut message to the current RVH. 142 // - Once the unload handler is finished, RVHM::SwappedOut checks if a transfer 143 // to a new process is needed, based on the stored pending_nav_params_. (This 144 // is independent of whether we started out with a cross-process navigation.) 145 // - If not, it just tells the ResourceDispatcherHost to resume the response 146 // to its current RenderViewHost. 147 // - If so, it cancels the current pending RenderViewHost and sets up a new 148 // navigation using RequestTransferURL. When the transferred request 149 // arrives in the ResourceDispatcherHost, we transfer the response and 150 // resume it. 151 // - The pending renderer sends a FrameNavigate message that invokes the 152 // DidNavigate method. This replaces the current RVH with the 153 // pending RVH. 154 // - The previous renderer is kept swapped out in RenderFrameHostManager in case 155 // the user goes back. The process only stays live if another tab is using 156 // it, but if so, the existing frame relationships will be maintained. 157 158 namespace content { 159 namespace { 160 161 const char kDotGoogleDotCom[] = ".google.com"; 162 163 #if defined(OS_ANDROID) 164 const char kWebContentsAndroidKey[] = "web_contents_android"; 165 #endif // OS_ANDROID 166 167 base::LazyInstance<std::vector<WebContentsImpl::CreatedCallback> > 168 g_created_callbacks = LAZY_INSTANCE_INITIALIZER; 169 170 static int StartDownload(content::RenderViewHost* rvh, 171 const GURL& url, 172 bool is_favicon, 173 uint32_t max_bitmap_size) { 174 static int g_next_image_download_id = 0; 175 rvh->Send(new ImageMsg_DownloadImage(rvh->GetRoutingID(), 176 ++g_next_image_download_id, 177 url, 178 is_favicon, 179 max_bitmap_size)); 180 return g_next_image_download_id; 181 } 182 183 ViewMsg_Navigate_Type::Value GetNavigationType( 184 BrowserContext* browser_context, const NavigationEntryImpl& entry, 185 NavigationController::ReloadType reload_type) { 186 switch (reload_type) { 187 case NavigationControllerImpl::RELOAD: 188 return ViewMsg_Navigate_Type::RELOAD; 189 case NavigationControllerImpl::RELOAD_IGNORING_CACHE: 190 return ViewMsg_Navigate_Type::RELOAD_IGNORING_CACHE; 191 case NavigationControllerImpl::RELOAD_ORIGINAL_REQUEST_URL: 192 return ViewMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL; 193 case NavigationControllerImpl::NO_RELOAD: 194 break; // Fall through to rest of function. 195 } 196 197 // |RenderViewImpl::PopulateStateFromPendingNavigationParams| differentiates 198 // between |RESTORE_WITH_POST| and |RESTORE|. 199 if (entry.restore_type() == 200 NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY) { 201 if (entry.GetHasPostData()) 202 return ViewMsg_Navigate_Type::RESTORE_WITH_POST; 203 return ViewMsg_Navigate_Type::RESTORE; 204 } 205 206 return ViewMsg_Navigate_Type::NORMAL; 207 } 208 209 void MakeNavigateParams(const NavigationEntryImpl& entry, 210 const NavigationControllerImpl& controller, 211 WebContentsDelegate* delegate, 212 NavigationController::ReloadType reload_type, 213 ViewMsg_Navigate_Params* params) { 214 params->page_id = entry.GetPageID(); 215 params->should_clear_history_list = entry.should_clear_history_list(); 216 params->should_replace_current_entry = entry.should_replace_entry(); 217 if (entry.should_clear_history_list()) { 218 // Set the history list related parameters to the same values a 219 // NavigationController would return before its first navigation. This will 220 // fully clear the RenderView's view of the session history. 221 params->pending_history_list_offset = -1; 222 params->current_history_list_offset = -1; 223 params->current_history_list_length = 0; 224 } else { 225 params->pending_history_list_offset = controller.GetIndexOfEntry(&entry); 226 params->current_history_list_offset = 227 controller.GetLastCommittedEntryIndex(); 228 params->current_history_list_length = controller.GetEntryCount(); 229 } 230 params->url = entry.GetURL(); 231 if (!entry.GetBaseURLForDataURL().is_empty()) { 232 params->base_url_for_data_url = entry.GetBaseURLForDataURL(); 233 params->history_url_for_data_url = entry.GetVirtualURL(); 234 } 235 params->referrer = entry.GetReferrer(); 236 params->transition = entry.GetTransitionType(); 237 params->page_state = entry.GetPageState(); 238 params->navigation_type = 239 GetNavigationType(controller.GetBrowserContext(), entry, reload_type); 240 params->request_time = base::Time::Now(); 241 params->extra_headers = entry.extra_headers(); 242 params->transferred_request_child_id = 243 entry.transferred_global_request_id().child_id; 244 params->transferred_request_request_id = 245 entry.transferred_global_request_id().request_id; 246 params->is_overriding_user_agent = entry.GetIsOverridingUserAgent(); 247 // Avoid downloading when in view-source mode. 248 params->allow_download = !entry.IsViewSourceMode(); 249 params->is_post = entry.GetHasPostData(); 250 if (entry.GetBrowserInitiatedPostData()) { 251 params->browser_initiated_post_data.assign( 252 entry.GetBrowserInitiatedPostData()->front(), 253 entry.GetBrowserInitiatedPostData()->front() + 254 entry.GetBrowserInitiatedPostData()->size()); 255 } 256 257 params->redirects = entry.redirect_chain(); 258 259 params->can_load_local_resources = entry.GetCanLoadLocalResources(); 260 params->frame_to_navigate = entry.GetFrameToNavigate(); 261 262 if (delegate) 263 delegate->AddNavigationHeaders(params->url, ¶ms->extra_headers); 264 } 265 266 void NotifyCacheOnIO( 267 scoped_refptr<net::URLRequestContextGetter> request_context, 268 const GURL& url, 269 const std::string& http_method) { 270 request_context->GetURLRequestContext()->http_transaction_factory()-> 271 GetCache()->OnExternalCacheHit(url, http_method); 272 } 273 274 // Helper function for retrieving all the sites in a frame tree. 275 bool CollectSites(BrowserContext* context, 276 std::set<GURL>* sites, 277 FrameTreeNode* node) { 278 sites->insert(SiteInstance::GetSiteForURL(context, node->current_url())); 279 return true; 280 } 281 282 } // namespace 283 284 WebContents* WebContents::Create(const WebContents::CreateParams& params) { 285 return WebContentsImpl::CreateWithOpener( 286 params, static_cast<WebContentsImpl*>(params.opener)); 287 } 288 289 WebContents* WebContents::CreateWithSessionStorage( 290 const WebContents::CreateParams& params, 291 const SessionStorageNamespaceMap& session_storage_namespace_map) { 292 WebContentsImpl* new_contents = new WebContentsImpl( 293 params.browser_context, NULL); 294 295 for (SessionStorageNamespaceMap::const_iterator it = 296 session_storage_namespace_map.begin(); 297 it != session_storage_namespace_map.end(); 298 ++it) { 299 new_contents->GetController() 300 .SetSessionStorageNamespace(it->first, it->second.get()); 301 } 302 303 new_contents->Init(params); 304 return new_contents; 305 } 306 307 void WebContentsImpl::AddCreatedCallback(const CreatedCallback& callback) { 308 g_created_callbacks.Get().push_back(callback); 309 } 310 311 void WebContentsImpl::RemoveCreatedCallback(const CreatedCallback& callback) { 312 for (size_t i = 0; i < g_created_callbacks.Get().size(); ++i) { 313 if (g_created_callbacks.Get().at(i).Equals(callback)) { 314 g_created_callbacks.Get().erase(g_created_callbacks.Get().begin() + i); 315 return; 316 } 317 } 318 } 319 320 WebContents* WebContents::FromRenderViewHost(const RenderViewHost* rvh) { 321 return rvh->GetDelegate()->GetAsWebContents(); 322 } 323 324 // WebContentsImpl::DestructionObserver ---------------------------------------- 325 326 class WebContentsImpl::DestructionObserver : public WebContentsObserver { 327 public: 328 DestructionObserver(WebContentsImpl* owner, WebContents* watched_contents) 329 : WebContentsObserver(watched_contents), 330 owner_(owner) { 331 } 332 333 // WebContentsObserver: 334 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE { 335 owner_->OnWebContentsDestroyed(static_cast<WebContentsImpl*>(web_contents)); 336 } 337 338 private: 339 WebContentsImpl* owner_; 340 341 DISALLOW_COPY_AND_ASSIGN(DestructionObserver); 342 }; 343 344 // WebContentsImpl ------------------------------------------------------------- 345 346 WebContentsImpl::WebContentsImpl( 347 BrowserContext* browser_context, 348 WebContentsImpl* opener) 349 : delegate_(NULL), 350 controller_(this, browser_context), 351 render_view_host_delegate_view_(NULL), 352 opener_(opener), 353 #if defined(OS_WIN) && defined(USE_AURA) 354 accessible_parent_(NULL), 355 #endif 356 frame_tree_(new NavigatorImpl(&controller_, this), 357 this, this, this, this), 358 is_loading_(false), 359 crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING), 360 crashed_error_code_(0), 361 waiting_for_response_(false), 362 load_state_(net::LOAD_STATE_IDLE, base::string16()), 363 upload_size_(0), 364 upload_position_(0), 365 displayed_insecure_content_(false), 366 capturer_count_(0), 367 should_normally_be_visible_(true), 368 is_being_destroyed_(false), 369 notify_disconnection_(false), 370 dialog_manager_(NULL), 371 is_showing_before_unload_dialog_(false), 372 closed_by_user_gesture_(false), 373 minimum_zoom_percent_(static_cast<int>(kMinimumZoomFactor * 100)), 374 maximum_zoom_percent_(static_cast<int>(kMaximumZoomFactor * 100)), 375 temporary_zoom_settings_(false), 376 color_chooser_identifier_(0), 377 render_view_message_source_(NULL), 378 fullscreen_widget_routing_id_(MSG_ROUTING_NONE) { 379 for (size_t i = 0; i < g_created_callbacks.Get().size(); i++) 380 g_created_callbacks.Get().at(i).Run(this); 381 frame_tree_.SetFrameRemoveListener( 382 base::Bind(&WebContentsImpl::OnFrameRemoved, 383 base::Unretained(this))); 384 } 385 386 WebContentsImpl::~WebContentsImpl() { 387 is_being_destroyed_ = true; 388 389 ClearAllPowerSaveBlockers(); 390 391 for (std::set<RenderWidgetHostImpl*>::iterator iter = 392 created_widgets_.begin(); iter != created_widgets_.end(); ++iter) { 393 (*iter)->DetachDelegate(); 394 } 395 created_widgets_.clear(); 396 397 // Clear out any JavaScript state. 398 if (dialog_manager_) 399 dialog_manager_->WebContentsDestroyed(this); 400 401 if (color_chooser_) 402 color_chooser_->End(); 403 404 NotifyDisconnected(); 405 406 // Notify any observer that have a reference on this WebContents. 407 NotificationService::current()->Notify( 408 NOTIFICATION_WEB_CONTENTS_DESTROYED, 409 Source<WebContents>(this), 410 NotificationService::NoDetails()); 411 412 // TODO(brettw) this should be moved to the view. 413 #if defined(OS_WIN) && !defined(USE_AURA) 414 // If we still have a window handle, destroy it. GetNativeView can return 415 // NULL if this contents was part of a window that closed. 416 if (view_->GetNativeView()) { 417 RenderViewHost* host = GetRenderViewHost(); 418 if (host && host->GetView()) 419 RenderWidgetHostViewPort::FromRWHV(host->GetView())->WillWmDestroy(); 420 } 421 #endif 422 423 RenderViewHost* pending_rvh = GetRenderManager()->pending_render_view_host(); 424 if (pending_rvh) { 425 FOR_EACH_OBSERVER(WebContentsObserver, 426 observers_, 427 RenderViewDeleted(pending_rvh)); 428 } 429 430 FOR_EACH_OBSERVER(WebContentsObserver, 431 observers_, 432 RenderViewDeleted(GetRenderManager()->current_host())); 433 434 FOR_EACH_OBSERVER(WebContentsObserver, 435 observers_, 436 WebContentsImplDestroyed()); 437 438 SetDelegate(NULL); 439 440 STLDeleteContainerPairSecondPointers(destruction_observers_.begin(), 441 destruction_observers_.end()); 442 } 443 444 WebContentsImpl* WebContentsImpl::CreateWithOpener( 445 const WebContents::CreateParams& params, 446 WebContentsImpl* opener) { 447 TRACE_EVENT0("browser", "WebContentsImpl::CreateWithOpener"); 448 WebContentsImpl* new_contents = new WebContentsImpl( 449 params.browser_context, opener); 450 451 new_contents->Init(params); 452 return new_contents; 453 } 454 455 // static 456 BrowserPluginGuest* WebContentsImpl::CreateGuest( 457 BrowserContext* browser_context, 458 SiteInstance* site_instance, 459 int guest_instance_id, 460 scoped_ptr<base::DictionaryValue> extra_params) { 461 WebContentsImpl* new_contents = new WebContentsImpl(browser_context, NULL); 462 463 // This makes |new_contents| act as a guest. 464 // For more info, see comment above class BrowserPluginGuest. 465 BrowserPluginGuest::Create( 466 guest_instance_id, site_instance, new_contents, extra_params.Pass()); 467 468 WebContents::CreateParams create_params(browser_context, site_instance); 469 new_contents->Init(create_params); 470 471 // We are instantiating a WebContents for browser plugin. Set its subframe bit 472 // to true. 473 static_cast<RenderViewHostImpl*>( 474 new_contents->GetRenderViewHost())->set_is_subframe(true); 475 476 return new_contents->browser_plugin_guest_.get(); 477 } 478 479 RenderFrameHostManager* WebContentsImpl::GetRenderManagerForTesting() { 480 return GetRenderManager(); 481 } 482 483 bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host, 484 const IPC::Message& message) { 485 return OnMessageReceived(render_view_host, NULL, message); 486 } 487 488 bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host, 489 RenderFrameHost* render_frame_host, 490 const IPC::Message& message) { 491 DCHECK(render_view_host || render_frame_host); 492 if (GetWebUI() && 493 static_cast<WebUIImpl*>(GetWebUI())->OnMessageReceived(message)) { 494 return true; 495 } 496 497 ObserverListBase<WebContentsObserver>::Iterator it(observers_); 498 WebContentsObserver* observer; 499 while ((observer = it.GetNext()) != NULL) 500 if (observer->OnMessageReceived(message)) 501 return true; 502 503 // Message handlers should be aware of which RenderViewHost sent the 504 // message, which is temporarily stored in render_view_message_source_. 505 render_view_message_source_ = render_view_host; 506 bool handled = true; 507 bool message_is_ok = true; 508 IPC_BEGIN_MESSAGE_MAP_EX(WebContentsImpl, message, message_is_ok) 509 IPC_MESSAGE_HANDLER(FrameHostMsg_PepperPluginHung, OnPepperPluginHung) 510 IPC_MESSAGE_HANDLER(FrameHostMsg_PluginCrashed, OnPluginCrashed) 511 IPC_MESSAGE_HANDLER(ViewHostMsg_DidLoadResourceFromMemoryCache, 512 OnDidLoadResourceFromMemoryCache) 513 IPC_MESSAGE_HANDLER(ViewHostMsg_DidDisplayInsecureContent, 514 OnDidDisplayInsecureContent) 515 IPC_MESSAGE_HANDLER(ViewHostMsg_DidRunInsecureContent, 516 OnDidRunInsecureContent) 517 IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentLoadedInFrame, 518 OnDocumentLoadedInFrame) 519 IPC_MESSAGE_HANDLER(ViewHostMsg_DidFinishLoad, OnDidFinishLoad) 520 IPC_MESSAGE_HANDLER(ViewHostMsg_DidFailLoadWithError, 521 OnDidFailLoadWithError) 522 IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset, OnGoToEntryAtOffset) 523 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateZoomLimits, OnUpdateZoomLimits) 524 IPC_MESSAGE_HANDLER(ViewHostMsg_EnumerateDirectory, OnEnumerateDirectory) 525 IPC_MESSAGE_HANDLER(ViewHostMsg_JSOutOfMemory, OnJSOutOfMemory) 526 IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterProtocolHandler, 527 OnRegisterProtocolHandler) 528 IPC_MESSAGE_HANDLER(ViewHostMsg_Find_Reply, OnFindReply) 529 IPC_MESSAGE_HANDLER(ViewHostMsg_AppCacheAccessed, OnAppCacheAccessed) 530 IPC_MESSAGE_HANDLER(ViewHostMsg_OpenColorChooser, OnOpenColorChooser) 531 IPC_MESSAGE_HANDLER(ViewHostMsg_EndColorChooser, OnEndColorChooser) 532 IPC_MESSAGE_HANDLER(ViewHostMsg_SetSelectedColorInColorChooser, 533 OnSetSelectedColorInColorChooser) 534 IPC_MESSAGE_HANDLER(ViewHostMsg_WebUISend, OnWebUISend) 535 IPC_MESSAGE_HANDLER(ViewHostMsg_RequestPpapiBrokerPermission, 536 OnRequestPpapiBrokerPermission) 537 IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginHostMsg_AllocateInstanceID, 538 OnBrowserPluginMessage(message)) 539 IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginHostMsg_Attach, 540 OnBrowserPluginMessage(message)) 541 IPC_MESSAGE_HANDLER(ImageHostMsg_DidDownloadImage, OnDidDownloadImage) 542 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFaviconURL, OnUpdateFaviconURL) 543 #if defined(OS_ANDROID) 544 IPC_MESSAGE_HANDLER(ViewHostMsg_FindMatchRects_Reply, 545 OnFindMatchRectsReply) 546 IPC_MESSAGE_HANDLER(ViewHostMsg_OpenDateTimeDialog, 547 OnOpenDateTimeDialog) 548 IPC_MESSAGE_HANDLER_DELAY_REPLY(JavaBridgeHostMsg_GetChannelHandle, 549 OnJavaBridgeGetChannelHandle) 550 #endif 551 IPC_MESSAGE_HANDLER(ViewHostMsg_MediaNotification, OnMediaNotification) 552 IPC_MESSAGE_HANDLER(ViewHostMsg_DidFirstVisuallyNonEmptyPaint, 553 OnFirstVisuallyNonEmptyPaint) 554 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowValidationMessage, 555 OnShowValidationMessage) 556 IPC_MESSAGE_HANDLER(ViewHostMsg_HideValidationMessage, 557 OnHideValidationMessage) 558 IPC_MESSAGE_HANDLER(ViewHostMsg_MoveValidationMessage, 559 OnMoveValidationMessage) 560 IPC_MESSAGE_UNHANDLED(handled = false) 561 IPC_END_MESSAGE_MAP_EX() 562 render_view_message_source_ = NULL; 563 564 if (!message_is_ok) { 565 RecordAction(UserMetricsAction("BadMessageTerminate_RVD")); 566 GetRenderProcessHost()->ReceivedBadMessage(); 567 } 568 569 return handled; 570 } 571 572 void WebContentsImpl::RunFileChooser( 573 RenderViewHost* render_view_host, 574 const FileChooserParams& params) { 575 if (delegate_) 576 delegate_->RunFileChooser(this, params); 577 } 578 579 NavigationControllerImpl& WebContentsImpl::GetController() { 580 return controller_; 581 } 582 583 const NavigationControllerImpl& WebContentsImpl::GetController() const { 584 return controller_; 585 } 586 587 BrowserContext* WebContentsImpl::GetBrowserContext() const { 588 return controller_.GetBrowserContext(); 589 } 590 591 const GURL& WebContentsImpl::GetURL() const { 592 // We may not have a navigation entry yet. 593 NavigationEntry* entry = controller_.GetVisibleEntry(); 594 return entry ? entry->GetVirtualURL() : GURL::EmptyGURL(); 595 } 596 597 const GURL& WebContentsImpl::GetVisibleURL() const { 598 // We may not have a navigation entry yet. 599 NavigationEntry* entry = controller_.GetVisibleEntry(); 600 return entry ? entry->GetVirtualURL() : GURL::EmptyGURL(); 601 } 602 603 const GURL& WebContentsImpl::GetLastCommittedURL() const { 604 // We may not have a navigation entry yet. 605 NavigationEntry* entry = controller_.GetLastCommittedEntry(); 606 return entry ? entry->GetVirtualURL() : GURL::EmptyGURL(); 607 } 608 609 WebContentsDelegate* WebContentsImpl::GetDelegate() { 610 return delegate_; 611 } 612 613 void WebContentsImpl::SetDelegate(WebContentsDelegate* delegate) { 614 // TODO(cbentzel): remove this debugging code? 615 if (delegate == delegate_) 616 return; 617 if (delegate_) 618 delegate_->Detach(this); 619 delegate_ = delegate; 620 if (delegate_) { 621 delegate_->Attach(this); 622 // Ensure the visible RVH reflects the new delegate's preferences. 623 if (view_) 624 view_->SetOverscrollControllerEnabled(delegate->CanOverscrollContent()); 625 } 626 } 627 628 RenderProcessHost* WebContentsImpl::GetRenderProcessHost() const { 629 RenderViewHostImpl* host = GetRenderManager()->current_host(); 630 return host ? host->GetProcess() : NULL; 631 } 632 633 RenderFrameHost* WebContentsImpl::GetMainFrame() { 634 return frame_tree_.root()->render_frame_host(); 635 } 636 637 RenderViewHost* WebContentsImpl::GetRenderViewHost() const { 638 return GetRenderManager()->current_host(); 639 } 640 641 void WebContentsImpl::GetRenderViewHostAtPosition( 642 int x, 643 int y, 644 const base::Callback<void(RenderViewHost*, int, int)>& callback) { 645 BrowserPluginEmbedder* embedder = GetBrowserPluginEmbedder(); 646 if (embedder) 647 embedder->GetRenderViewHostAtPosition(x, y, callback); 648 else 649 callback.Run(GetRenderViewHost(), x, y); 650 } 651 652 WebContents* WebContentsImpl::GetEmbedderWebContents() const { 653 BrowserPluginGuest* guest = GetBrowserPluginGuest(); 654 if (guest) 655 return guest->embedder_web_contents(); 656 return NULL; 657 } 658 659 int WebContentsImpl::GetEmbeddedInstanceID() const { 660 BrowserPluginGuest* guest = GetBrowserPluginGuest(); 661 if (guest) 662 return guest->instance_id(); 663 return 0; 664 } 665 666 int WebContentsImpl::GetRoutingID() const { 667 if (!GetRenderViewHost()) 668 return MSG_ROUTING_NONE; 669 670 return GetRenderViewHost()->GetRoutingID(); 671 } 672 673 int WebContentsImpl::GetFullscreenWidgetRoutingID() const { 674 return fullscreen_widget_routing_id_; 675 } 676 677 RenderWidgetHostView* WebContentsImpl::GetRenderWidgetHostView() const { 678 return GetRenderManager()->GetRenderWidgetHostView(); 679 } 680 681 RenderWidgetHostViewPort* WebContentsImpl::GetRenderWidgetHostViewPort() const { 682 BrowserPluginGuest* guest = GetBrowserPluginGuest(); 683 if (guest && guest->embedder_web_contents()) { 684 return guest->embedder_web_contents()->GetRenderWidgetHostViewPort(); 685 } 686 return RenderWidgetHostViewPort::FromRWHV(GetRenderWidgetHostView()); 687 } 688 689 RenderWidgetHostView* WebContentsImpl::GetFullscreenRenderWidgetHostView() 690 const { 691 RenderWidgetHost* const widget_host = 692 RenderWidgetHostImpl::FromID(GetRenderProcessHost()->GetID(), 693 GetFullscreenWidgetRoutingID()); 694 return widget_host ? widget_host->GetView() : NULL; 695 } 696 697 WebContentsView* WebContentsImpl::GetView() const { 698 return view_.get(); 699 } 700 701 WebUI* WebContentsImpl::CreateWebUI(const GURL& url) { 702 WebUIImpl* web_ui = new WebUIImpl(this); 703 WebUIController* controller = WebUIControllerFactoryRegistry::GetInstance()-> 704 CreateWebUIControllerForURL(web_ui, url); 705 if (controller) { 706 web_ui->AddMessageHandler(new GenericHandler()); 707 web_ui->SetController(controller); 708 return web_ui; 709 } 710 711 delete web_ui; 712 return NULL; 713 } 714 715 WebUI* WebContentsImpl::GetWebUI() const { 716 return GetRenderManager()->web_ui() ? GetRenderManager()->web_ui() 717 : GetRenderManager()->pending_web_ui(); 718 } 719 720 WebUI* WebContentsImpl::GetCommittedWebUI() const { 721 return GetRenderManager()->web_ui(); 722 } 723 724 void WebContentsImpl::SetUserAgentOverride(const std::string& override) { 725 if (GetUserAgentOverride() == override) 726 return; 727 728 renderer_preferences_.user_agent_override = override; 729 730 // Send the new override string to the renderer. 731 RenderViewHost* host = GetRenderViewHost(); 732 if (host) 733 host->SyncRendererPrefs(); 734 735 // Reload the page if a load is currently in progress to avoid having 736 // different parts of the page loaded using different user agents. 737 NavigationEntry* entry = controller_.GetVisibleEntry(); 738 if (is_loading_ && entry != NULL && entry->GetIsOverridingUserAgent()) 739 controller_.ReloadIgnoringCache(true); 740 741 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 742 UserAgentOverrideSet(override)); 743 } 744 745 const std::string& WebContentsImpl::GetUserAgentOverride() const { 746 return renderer_preferences_.user_agent_override; 747 } 748 749 #if defined(OS_WIN) && defined(USE_AURA) 750 void WebContentsImpl::SetParentNativeViewAccessible( 751 gfx::NativeViewAccessible accessible_parent) { 752 accessible_parent_ = accessible_parent; 753 if (GetRenderViewHost()) 754 GetRenderViewHostImpl()->SetParentNativeViewAccessible(accessible_parent); 755 } 756 #endif 757 758 const base::string16& WebContentsImpl::GetTitle() const { 759 // Transient entries take precedence. They are used for interstitial pages 760 // that are shown on top of existing pages. 761 NavigationEntry* entry = controller_.GetTransientEntry(); 762 std::string accept_languages = 763 GetContentClient()->browser()->GetAcceptLangs( 764 GetBrowserContext()); 765 if (entry) { 766 return entry->GetTitleForDisplay(accept_languages); 767 } 768 WebUI* our_web_ui = GetRenderManager()->pending_web_ui() ? 769 GetRenderManager()->pending_web_ui() : GetRenderManager()->web_ui(); 770 if (our_web_ui) { 771 // Don't override the title in view source mode. 772 entry = controller_.GetVisibleEntry(); 773 if (!(entry && entry->IsViewSourceMode())) { 774 // Give the Web UI the chance to override our title. 775 const base::string16& title = our_web_ui->GetOverriddenTitle(); 776 if (!title.empty()) 777 return title; 778 } 779 } 780 781 // We use the title for the last committed entry rather than a pending 782 // navigation entry. For example, when the user types in a URL, we want to 783 // keep the old page's title until the new load has committed and we get a new 784 // title. 785 entry = controller_.GetLastCommittedEntry(); 786 787 // We make an exception for initial navigations. 788 if (controller_.IsInitialNavigation()) { 789 // We only want to use the title from the visible entry in one of two cases: 790 // 1. There's already a committed entry for an initial navigation, in which 791 // case we are doing a history navigation in a new tab (e.g., Ctrl+Back). 792 // 2. The pending entry has been explicitly assigned a title to display. 793 // 794 // If there's no last committed entry and no assigned title, we should fall 795 // back to |page_title_when_no_navigation_entry_| rather than showing the 796 // URL. 797 if (entry || 798 (controller_.GetVisibleEntry() && 799 !controller_.GetVisibleEntry()->GetTitle().empty())) { 800 entry = controller_.GetVisibleEntry(); 801 } 802 } 803 804 if (entry) { 805 return entry->GetTitleForDisplay(accept_languages); 806 } 807 808 // |page_title_when_no_navigation_entry_| is finally used 809 // if no title cannot be retrieved. 810 return page_title_when_no_navigation_entry_; 811 } 812 813 int32 WebContentsImpl::GetMaxPageID() { 814 return GetMaxPageIDForSiteInstance(GetSiteInstance()); 815 } 816 817 int32 WebContentsImpl::GetMaxPageIDForSiteInstance( 818 SiteInstance* site_instance) { 819 if (max_page_ids_.find(site_instance->GetId()) == max_page_ids_.end()) 820 max_page_ids_[site_instance->GetId()] = -1; 821 822 return max_page_ids_[site_instance->GetId()]; 823 } 824 825 void WebContentsImpl::UpdateMaxPageID(int32 page_id) { 826 UpdateMaxPageIDForSiteInstance(GetSiteInstance(), page_id); 827 } 828 829 void WebContentsImpl::UpdateMaxPageIDForSiteInstance( 830 SiteInstance* site_instance, int32 page_id) { 831 if (GetMaxPageIDForSiteInstance(site_instance) < page_id) 832 max_page_ids_[site_instance->GetId()] = page_id; 833 } 834 835 void WebContentsImpl::CopyMaxPageIDsFrom(WebContents* web_contents) { 836 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents); 837 max_page_ids_ = contents->max_page_ids_; 838 } 839 840 SiteInstance* WebContentsImpl::GetSiteInstance() const { 841 return GetRenderManager()->current_host()->GetSiteInstance(); 842 } 843 844 SiteInstance* WebContentsImpl::GetPendingSiteInstance() const { 845 RenderViewHost* dest_rvh = GetRenderManager()->pending_render_view_host() ? 846 GetRenderManager()->pending_render_view_host() : 847 GetRenderManager()->current_host(); 848 return dest_rvh->GetSiteInstance(); 849 } 850 851 bool WebContentsImpl::IsLoading() const { 852 return is_loading_; 853 } 854 855 bool WebContentsImpl::IsWaitingForResponse() const { 856 return waiting_for_response_; 857 } 858 859 const net::LoadStateWithParam& WebContentsImpl::GetLoadState() const { 860 return load_state_; 861 } 862 863 const base::string16& WebContentsImpl::GetLoadStateHost() const { 864 return load_state_host_; 865 } 866 867 uint64 WebContentsImpl::GetUploadSize() const { 868 return upload_size_; 869 } 870 871 uint64 WebContentsImpl::GetUploadPosition() const { 872 return upload_position_; 873 } 874 875 std::set<GURL> WebContentsImpl::GetSitesInTab() const { 876 std::set<GURL> sites; 877 frame_tree_.ForEach(Bind(&CollectSites, 878 base::Unretained(GetBrowserContext()), 879 base::Unretained(&sites))); 880 return sites; 881 } 882 883 const std::string& WebContentsImpl::GetEncoding() const { 884 return encoding_; 885 } 886 887 bool WebContentsImpl::DisplayedInsecureContent() const { 888 return displayed_insecure_content_; 889 } 890 891 void WebContentsImpl::IncrementCapturerCount() { 892 DCHECK(!is_being_destroyed_); 893 ++capturer_count_; 894 DVLOG(1) << "There are now " << capturer_count_ 895 << " capturing(s) of WebContentsImpl@" << this; 896 } 897 898 void WebContentsImpl::DecrementCapturerCount() { 899 --capturer_count_; 900 DVLOG(1) << "There are now " << capturer_count_ 901 << " capturing(s) of WebContentsImpl@" << this; 902 DCHECK_LE(0, capturer_count_); 903 904 if (is_being_destroyed_) 905 return; 906 907 if (IsHidden()) { 908 DVLOG(1) << "Executing delayed WasHidden()."; 909 WasHidden(); 910 } 911 } 912 913 int WebContentsImpl::GetCapturerCount() const { 914 return capturer_count_; 915 } 916 917 bool WebContentsImpl::IsCrashed() const { 918 return (crashed_status_ == base::TERMINATION_STATUS_PROCESS_CRASHED || 919 crashed_status_ == base::TERMINATION_STATUS_ABNORMAL_TERMINATION || 920 crashed_status_ == base::TERMINATION_STATUS_PROCESS_WAS_KILLED); 921 } 922 923 void WebContentsImpl::SetIsCrashed(base::TerminationStatus status, 924 int error_code) { 925 if (status == crashed_status_) 926 return; 927 928 crashed_status_ = status; 929 crashed_error_code_ = error_code; 930 NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB); 931 } 932 933 base::TerminationStatus WebContentsImpl::GetCrashedStatus() const { 934 return crashed_status_; 935 } 936 937 bool WebContentsImpl::IsBeingDestroyed() const { 938 return is_being_destroyed_; 939 } 940 941 void WebContentsImpl::NotifyNavigationStateChanged(unsigned changed_flags) { 942 if (delegate_) 943 delegate_->NavigationStateChanged(this, changed_flags); 944 } 945 946 base::TimeTicks WebContentsImpl::GetLastSelectedTime() const { 947 return last_selected_time_; 948 } 949 950 void WebContentsImpl::WasShown() { 951 controller_.SetActive(true); 952 RenderWidgetHostViewPort* rwhv = 953 RenderWidgetHostViewPort::FromRWHV(GetRenderWidgetHostView()); 954 if (rwhv) { 955 rwhv->Show(); 956 #if defined(OS_MACOSX) 957 rwhv->SetActive(true); 958 #endif 959 } 960 961 last_selected_time_ = base::TimeTicks::Now(); 962 963 // The resize rect might have changed while this was inactive -- send the new 964 // one to make sure it's up to date. 965 RenderViewHostImpl* rvh = 966 static_cast<RenderViewHostImpl*>(GetRenderViewHost()); 967 if (rvh) { 968 rvh->ResizeRectChanged(GetRootWindowResizerRect()); 969 } 970 971 FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasShown()); 972 973 should_normally_be_visible_ = true; 974 } 975 976 void WebContentsImpl::WasHidden() { 977 // If there are entities capturing screenshots or video (e.g., mirroring), 978 // don't activate the "disable rendering" optimization. 979 if (capturer_count_ == 0) { 980 // |GetRenderViewHost()| can be NULL if the user middle clicks a link to 981 // open a tab in the background, then closes the tab before selecting it. 982 // This is because closing the tab calls WebContentsImpl::Destroy(), which 983 // removes the |GetRenderViewHost()|; then when we actually destroy the 984 // window, OnWindowPosChanged() notices and calls WasHidden() (which 985 // calls us). 986 RenderWidgetHostViewPort* rwhv = 987 RenderWidgetHostViewPort::FromRWHV(GetRenderWidgetHostView()); 988 if (rwhv) 989 rwhv->Hide(); 990 } 991 992 FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasHidden()); 993 994 should_normally_be_visible_ = false; 995 } 996 997 bool WebContentsImpl::NeedToFireBeforeUnload() { 998 // TODO(creis): Should we fire even for interstitial pages? 999 return WillNotifyDisconnection() && 1000 !ShowingInterstitialPage() && 1001 !static_cast<RenderViewHostImpl*>( 1002 GetRenderViewHost())->SuddenTerminationAllowed(); 1003 } 1004 1005 void WebContentsImpl::Stop() { 1006 GetRenderManager()->Stop(); 1007 FOR_EACH_OBSERVER(WebContentsObserver, observers_, NavigationStopped()); 1008 } 1009 1010 WebContents* WebContentsImpl::Clone() { 1011 // We use our current SiteInstance since the cloned entry will use it anyway. 1012 // We pass our own opener so that the cloned page can access it if it was 1013 // before. 1014 CreateParams create_params(GetBrowserContext(), GetSiteInstance()); 1015 create_params.initial_size = view_->GetContainerSize(); 1016 WebContentsImpl* tc = CreateWithOpener(create_params, opener_); 1017 tc->GetController().CopyStateFrom(controller_); 1018 FOR_EACH_OBSERVER(WebContentsObserver, 1019 observers_, 1020 DidCloneToNewWebContents(this, tc)); 1021 return tc; 1022 } 1023 1024 void WebContentsImpl::Observe(int type, 1025 const NotificationSource& source, 1026 const NotificationDetails& details) { 1027 switch (type) { 1028 case NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: { 1029 RenderWidgetHost* host = Source<RenderWidgetHost>(source).ptr(); 1030 for (PendingWidgetViews::iterator i = pending_widget_views_.begin(); 1031 i != pending_widget_views_.end(); ++i) { 1032 if (host->GetView() == i->second) { 1033 pending_widget_views_.erase(i); 1034 break; 1035 } 1036 } 1037 break; 1038 } 1039 default: 1040 NOTREACHED(); 1041 } 1042 } 1043 1044 WebContents* WebContentsImpl::GetWebContents() { 1045 return this; 1046 } 1047 1048 void WebContentsImpl::Init(const WebContents::CreateParams& params) { 1049 // This is set before initializing the render manager since 1050 // RenderFrameHostManager::Init calls back into us via its delegate to ask if 1051 // it should be hidden. 1052 should_normally_be_visible_ = !params.initially_hidden; 1053 1054 GetRenderManager()->Init( 1055 params.browser_context, params.site_instance, params.routing_id, 1056 params.main_frame_routing_id); 1057 1058 view_.reset(GetContentClient()->browser()-> 1059 OverrideCreateWebContentsView(this, &render_view_host_delegate_view_)); 1060 if (view_) { 1061 CHECK(render_view_host_delegate_view_); 1062 } else { 1063 WebContentsViewDelegate* delegate = 1064 GetContentClient()->browser()->GetWebContentsViewDelegate(this); 1065 1066 if (browser_plugin_guest_) { 1067 scoped_ptr<WebContentsViewPort> platform_view(CreateWebContentsView( 1068 this, delegate, &render_view_host_delegate_view_)); 1069 1070 WebContentsViewGuest* rv = new WebContentsViewGuest( 1071 this, browser_plugin_guest_.get(), platform_view.Pass(), 1072 render_view_host_delegate_view_); 1073 render_view_host_delegate_view_ = rv; 1074 view_.reset(rv); 1075 } else { 1076 // Regular WebContentsView. 1077 view_.reset(CreateWebContentsView( 1078 this, delegate, &render_view_host_delegate_view_)); 1079 } 1080 CHECK(render_view_host_delegate_view_); 1081 } 1082 CHECK(view_.get()); 1083 1084 gfx::Size initial_size = params.initial_size; 1085 view_->CreateView(initial_size, params.context); 1086 1087 // Listen for whether our opener gets destroyed. 1088 if (opener_) 1089 AddDestructionObserver(opener_); 1090 1091 registrar_.Add(this, 1092 NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, 1093 NotificationService::AllBrowserContextsAndSources()); 1094 #if defined(OS_ANDROID) 1095 java_bridge_dispatcher_host_manager_.reset( 1096 new JavaBridgeDispatcherHostManager(this)); 1097 date_time_chooser_.reset(new DateTimeChooserAndroid()); 1098 #endif 1099 } 1100 1101 void WebContentsImpl::OnWebContentsDestroyed(WebContentsImpl* web_contents) { 1102 RemoveDestructionObserver(web_contents); 1103 1104 // Clear the opener if it has been closed. 1105 if (web_contents == opener_) { 1106 opener_ = NULL; 1107 return; 1108 } 1109 // Clear a pending contents that has been closed before being shown. 1110 for (PendingContents::iterator iter = pending_contents_.begin(); 1111 iter != pending_contents_.end(); 1112 ++iter) { 1113 if (iter->second != web_contents) 1114 continue; 1115 pending_contents_.erase(iter); 1116 return; 1117 } 1118 NOTREACHED(); 1119 } 1120 1121 void WebContentsImpl::AddDestructionObserver(WebContentsImpl* web_contents) { 1122 if (!ContainsKey(destruction_observers_, web_contents)) { 1123 destruction_observers_[web_contents] = 1124 new DestructionObserver(this, web_contents); 1125 } 1126 } 1127 1128 void WebContentsImpl::RemoveDestructionObserver(WebContentsImpl* web_contents) { 1129 DestructionObservers::iterator iter = 1130 destruction_observers_.find(web_contents); 1131 if (iter != destruction_observers_.end()) { 1132 delete destruction_observers_[web_contents]; 1133 destruction_observers_.erase(iter); 1134 } 1135 } 1136 1137 void WebContentsImpl::AddObserver(WebContentsObserver* observer) { 1138 observers_.AddObserver(observer); 1139 } 1140 1141 void WebContentsImpl::RemoveObserver(WebContentsObserver* observer) { 1142 observers_.RemoveObserver(observer); 1143 } 1144 1145 void WebContentsImpl::Activate() { 1146 if (delegate_) 1147 delegate_->ActivateContents(this); 1148 } 1149 1150 void WebContentsImpl::Deactivate() { 1151 if (delegate_) 1152 delegate_->DeactivateContents(this); 1153 } 1154 1155 void WebContentsImpl::LostCapture() { 1156 if (delegate_) 1157 delegate_->LostCapture(); 1158 } 1159 1160 void WebContentsImpl::RenderWidgetDeleted( 1161 RenderWidgetHostImpl* render_widget_host) { 1162 if (is_being_destroyed_) { 1163 // |created_widgets_| might have been destroyed. 1164 return; 1165 } 1166 1167 std::set<RenderWidgetHostImpl*>::iterator iter = 1168 created_widgets_.find(render_widget_host); 1169 if (iter != created_widgets_.end()) 1170 created_widgets_.erase(iter); 1171 1172 if (render_widget_host && 1173 render_widget_host->GetRoutingID() == fullscreen_widget_routing_id_) { 1174 if (delegate_ && delegate_->EmbedsFullscreenWidget()) 1175 delegate_->ToggleFullscreenModeForTab(this, false); 1176 FOR_EACH_OBSERVER(WebContentsObserver, 1177 observers_, 1178 DidDestroyFullscreenWidget( 1179 fullscreen_widget_routing_id_)); 1180 fullscreen_widget_routing_id_ = MSG_ROUTING_NONE; 1181 } 1182 } 1183 1184 bool WebContentsImpl::PreHandleKeyboardEvent( 1185 const NativeWebKeyboardEvent& event, 1186 bool* is_keyboard_shortcut) { 1187 return delegate_ && 1188 delegate_->PreHandleKeyboardEvent(this, event, is_keyboard_shortcut); 1189 } 1190 1191 void WebContentsImpl::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { 1192 if (browser_plugin_embedder_ && 1193 browser_plugin_embedder_->HandleKeyboardEvent(event)) { 1194 return; 1195 } 1196 1197 if (delegate_) 1198 delegate_->HandleKeyboardEvent(this, event); 1199 } 1200 1201 bool WebContentsImpl::PreHandleWheelEvent( 1202 const blink::WebMouseWheelEvent& event) { 1203 #if !defined(OS_MACOSX) 1204 // On platforms other than Mac, control+mousewheel changes zoom. On Mac, this 1205 // isn't done for two reasons: 1206 // -the OS already has a gesture to do this through pinch-zoom 1207 // -if a user starts an inertial scroll, let's go, and presses control 1208 // (i.e. control+tab) then the OS's buffered scroll events will come in 1209 // with control key set which isn't what the user wants 1210 if (delegate_ && 1211 event.wheelTicksY && 1212 (event.modifiers & blink::WebInputEvent::ControlKey)) { 1213 delegate_->ContentsZoomChange(event.wheelTicksY > 0); 1214 return true; 1215 } 1216 #endif 1217 1218 return false; 1219 } 1220 1221 #if defined(OS_WIN) && defined(USE_AURA) 1222 gfx::NativeViewAccessible WebContentsImpl::GetParentNativeViewAccessible() { 1223 return accessible_parent_; 1224 } 1225 #endif 1226 1227 void WebContentsImpl::HandleMouseDown() { 1228 if (delegate_) 1229 delegate_->HandleMouseDown(); 1230 } 1231 1232 void WebContentsImpl::HandleMouseUp() { 1233 if (delegate_) 1234 delegate_->HandleMouseUp(); 1235 } 1236 1237 void WebContentsImpl::HandlePointerActivate() { 1238 if (delegate_) 1239 delegate_->HandlePointerActivate(); 1240 } 1241 1242 void WebContentsImpl::HandleGestureBegin() { 1243 if (delegate_) 1244 delegate_->HandleGestureBegin(); 1245 } 1246 1247 void WebContentsImpl::HandleGestureEnd() { 1248 if (delegate_) 1249 delegate_->HandleGestureEnd(); 1250 } 1251 1252 void WebContentsImpl::ToggleFullscreenMode(bool enter_fullscreen) { 1253 // This method is being called to enter or leave renderer-initiated fullscreen 1254 // mode. Either way, make sure any existing fullscreen widget is shut down 1255 // first. 1256 RenderWidgetHostView* const widget_view = GetFullscreenRenderWidgetHostView(); 1257 if (widget_view) 1258 RenderWidgetHostImpl::From(widget_view->GetRenderWidgetHost())->Shutdown(); 1259 1260 if (delegate_) 1261 delegate_->ToggleFullscreenModeForTab(this, enter_fullscreen); 1262 } 1263 1264 bool WebContentsImpl::IsFullscreenForCurrentTab() const { 1265 return delegate_ ? delegate_->IsFullscreenForTabOrPending(this) : false; 1266 } 1267 1268 void WebContentsImpl::RequestToLockMouse(bool user_gesture, 1269 bool last_unlocked_by_target) { 1270 if (delegate_) { 1271 delegate_->RequestToLockMouse(this, user_gesture, last_unlocked_by_target); 1272 } else { 1273 GotResponseToLockMouseRequest(false); 1274 } 1275 } 1276 1277 void WebContentsImpl::LostMouseLock() { 1278 if (delegate_) 1279 delegate_->LostMouseLock(); 1280 } 1281 1282 void WebContentsImpl::CreateNewWindow( 1283 int render_process_id, 1284 int route_id, 1285 int main_frame_route_id, 1286 const ViewHostMsg_CreateWindow_Params& params, 1287 SessionStorageNamespace* session_storage_namespace) { 1288 // We usually create the new window in the same BrowsingInstance (group of 1289 // script-related windows), by passing in the current SiteInstance. However, 1290 // if the opener is being suppressed (in a non-guest), we create a new 1291 // SiteInstance in its own BrowsingInstance. 1292 bool is_guest = GetRenderProcessHost()->IsGuest(); 1293 1294 // If the opener is to be suppressed, the new window can be in any process. 1295 // Since routing ids are process specific, we must not have one passed in 1296 // as argument here. 1297 DCHECK(!params.opener_suppressed || route_id == MSG_ROUTING_NONE); 1298 1299 scoped_refptr<SiteInstance> site_instance = 1300 params.opener_suppressed && !is_guest ? 1301 SiteInstance::CreateForURL(GetBrowserContext(), params.target_url) : 1302 GetSiteInstance(); 1303 1304 // A message to create a new window can only come from the active process for 1305 // this WebContentsImpl instance. If any other process sends the request, 1306 // it is invalid and the process must be terminated. 1307 if (GetRenderProcessHost()->GetID() != render_process_id) { 1308 base::ProcessHandle process_handle = 1309 RenderProcessHost::FromID(render_process_id)->GetHandle(); 1310 if (process_handle != base::kNullProcessHandle) { 1311 RecordAction( 1312 UserMetricsAction("Terminate_ProcessMismatch_CreateNewWindow")); 1313 base::KillProcess(process_handle, content::RESULT_CODE_KILLED, false); 1314 } 1315 return; 1316 } 1317 1318 // We must assign the SessionStorageNamespace before calling Init(). 1319 // 1320 // http://crbug.com/142685 1321 const std::string& partition_id = 1322 GetContentClient()->browser()-> 1323 GetStoragePartitionIdForSite(GetBrowserContext(), 1324 site_instance->GetSiteURL()); 1325 StoragePartition* partition = BrowserContext::GetStoragePartition( 1326 GetBrowserContext(), site_instance.get()); 1327 DOMStorageContextWrapper* dom_storage_context = 1328 static_cast<DOMStorageContextWrapper*>(partition->GetDOMStorageContext()); 1329 SessionStorageNamespaceImpl* session_storage_namespace_impl = 1330 static_cast<SessionStorageNamespaceImpl*>(session_storage_namespace); 1331 CHECK(session_storage_namespace_impl->IsFromContext(dom_storage_context)); 1332 1333 if (delegate_ && 1334 !delegate_->ShouldCreateWebContents(this, 1335 route_id, 1336 params.window_container_type, 1337 params.frame_name, 1338 params.target_url, 1339 partition_id, 1340 session_storage_namespace)) { 1341 GetRenderViewHost()->GetProcess()->ResumeRequestsForView(route_id); 1342 GetRenderViewHost()->GetProcess()->ResumeRequestsForView( 1343 main_frame_route_id); 1344 return; 1345 } 1346 1347 // Create the new web contents. This will automatically create the new 1348 // WebContentsView. In the future, we may want to create the view separately. 1349 WebContentsImpl* new_contents = 1350 new WebContentsImpl(GetBrowserContext(), 1351 params.opener_suppressed ? NULL : this); 1352 1353 new_contents->GetController().SetSessionStorageNamespace( 1354 partition_id, 1355 session_storage_namespace); 1356 CreateParams create_params(GetBrowserContext(), site_instance.get()); 1357 create_params.routing_id = route_id; 1358 create_params.main_frame_routing_id = main_frame_route_id; 1359 if (!is_guest) { 1360 create_params.context = view_->GetNativeView(); 1361 create_params.initial_size = view_->GetContainerSize(); 1362 } else { 1363 // This makes |new_contents| act as a guest. 1364 // For more info, see comment above class BrowserPluginGuest. 1365 int instance_id = GetBrowserPluginGuestManager()->get_next_instance_id(); 1366 WebContentsImpl* new_contents_impl = 1367 static_cast<WebContentsImpl*>(new_contents); 1368 BrowserPluginGuest::CreateWithOpener(instance_id, 1369 new_contents_impl->opener() != NULL, 1370 new_contents_impl, 1371 GetBrowserPluginGuest()); 1372 } 1373 if (params.disposition == NEW_BACKGROUND_TAB) 1374 create_params.initially_hidden = true; 1375 new_contents->Init(create_params); 1376 1377 // Save the window for later if we're not suppressing the opener (since it 1378 // will be shown immediately). 1379 if (!params.opener_suppressed) { 1380 if (!is_guest) { 1381 WebContentsViewPort* new_view = new_contents->view_.get(); 1382 1383 // TODO(brettw): It seems bogus that we have to call this function on the 1384 // newly created object and give it one of its own member variables. 1385 new_view->CreateViewForWidget(new_contents->GetRenderViewHost()); 1386 } 1387 // Save the created window associated with the route so we can show it 1388 // later. 1389 DCHECK_NE(MSG_ROUTING_NONE, route_id); 1390 pending_contents_[route_id] = new_contents; 1391 AddDestructionObserver(new_contents); 1392 } 1393 1394 if (delegate_) { 1395 delegate_->WebContentsCreated( 1396 this, params.opener_frame_id, params.frame_name, 1397 params.target_url, new_contents); 1398 } 1399 1400 if (params.opener_suppressed) { 1401 // When the opener is suppressed, the original renderer cannot access the 1402 // new window. As a result, we need to show and navigate the window here. 1403 bool was_blocked = false; 1404 if (delegate_) { 1405 gfx::Rect initial_pos; 1406 delegate_->AddNewContents( 1407 this, new_contents, params.disposition, initial_pos, 1408 params.user_gesture, &was_blocked); 1409 } 1410 if (!was_blocked) { 1411 OpenURLParams open_params(params.target_url, 1412 Referrer(), 1413 CURRENT_TAB, 1414 PAGE_TRANSITION_LINK, 1415 true /* is_renderer_initiated */); 1416 open_params.user_gesture = params.user_gesture; 1417 new_contents->OpenURL(open_params); 1418 } 1419 } 1420 } 1421 1422 void WebContentsImpl::CreateNewWidget(int render_process_id, 1423 int route_id, 1424 blink::WebPopupType popup_type) { 1425 CreateNewWidget(render_process_id, route_id, false, popup_type); 1426 } 1427 1428 void WebContentsImpl::CreateNewFullscreenWidget(int render_process_id, 1429 int route_id) { 1430 CreateNewWidget(render_process_id, route_id, true, blink::WebPopupTypeNone); 1431 } 1432 1433 void WebContentsImpl::CreateNewWidget(int render_process_id, 1434 int route_id, 1435 bool is_fullscreen, 1436 blink::WebPopupType popup_type) { 1437 RenderProcessHost* process = GetRenderProcessHost(); 1438 // A message to create a new widget can only come from the active process for 1439 // this WebContentsImpl instance. If any other process sends the request, 1440 // it is invalid and the process must be terminated. 1441 if (process->GetID() != render_process_id) { 1442 base::ProcessHandle process_handle = 1443 RenderProcessHost::FromID(render_process_id)->GetHandle(); 1444 if (process_handle != base::kNullProcessHandle) { 1445 RecordAction( 1446 UserMetricsAction("Terminate_ProcessMismatch_CreateNewWidget")); 1447 base::KillProcess(process_handle, content::RESULT_CODE_KILLED, false); 1448 } 1449 return; 1450 } 1451 1452 RenderWidgetHostImpl* widget_host = 1453 new RenderWidgetHostImpl(this, process, route_id, IsHidden()); 1454 created_widgets_.insert(widget_host); 1455 1456 RenderWidgetHostViewPort* widget_view = RenderWidgetHostViewPort::FromRWHV( 1457 view_->CreateViewForPopupWidget(widget_host)); 1458 if (!widget_view) 1459 return; 1460 if (!is_fullscreen) { 1461 // Popups should not get activated. 1462 widget_view->SetPopupType(popup_type); 1463 } 1464 // Save the created widget associated with the route so we can show it later. 1465 pending_widget_views_[route_id] = widget_view; 1466 1467 #if defined(OS_MACOSX) 1468 // A RenderWidgetHostViewMac has lifetime scoped to the view. We'll retain it 1469 // to allow it to survive the trip without being hosted. 1470 base::mac::NSObjectRetain(widget_view->GetNativeView()); 1471 #endif 1472 } 1473 1474 void WebContentsImpl::ShowCreatedWindow(int route_id, 1475 WindowOpenDisposition disposition, 1476 const gfx::Rect& initial_pos, 1477 bool user_gesture) { 1478 WebContentsImpl* contents = GetCreatedWindow(route_id); 1479 if (contents) { 1480 WebContentsDelegate* delegate = GetDelegate(); 1481 if (delegate) { 1482 delegate->AddNewContents( 1483 this, contents, disposition, initial_pos, user_gesture, NULL); 1484 } 1485 } 1486 } 1487 1488 void WebContentsImpl::ShowCreatedWidget(int route_id, 1489 const gfx::Rect& initial_pos) { 1490 ShowCreatedWidget(route_id, false, initial_pos); 1491 } 1492 1493 void WebContentsImpl::ShowCreatedFullscreenWidget(int route_id) { 1494 ShowCreatedWidget(route_id, true, gfx::Rect()); 1495 } 1496 1497 void WebContentsImpl::ShowCreatedWidget(int route_id, 1498 bool is_fullscreen, 1499 const gfx::Rect& initial_pos) { 1500 if (delegate_) 1501 delegate_->RenderWidgetShowing(); 1502 1503 RenderWidgetHostViewPort* widget_host_view = 1504 RenderWidgetHostViewPort::FromRWHV(GetCreatedWidget(route_id)); 1505 if (!widget_host_view) 1506 return; 1507 if (is_fullscreen) { 1508 DCHECK_EQ(MSG_ROUTING_NONE, fullscreen_widget_routing_id_); 1509 fullscreen_widget_routing_id_ = route_id; 1510 if (delegate_ && delegate_->EmbedsFullscreenWidget()) { 1511 widget_host_view->InitAsChild(GetRenderWidgetHostView()->GetNativeView()); 1512 delegate_->ToggleFullscreenModeForTab(this, true); 1513 } else { 1514 widget_host_view->InitAsFullscreen(GetRenderWidgetHostViewPort()); 1515 } 1516 FOR_EACH_OBSERVER(WebContentsObserver, 1517 observers_, 1518 DidShowFullscreenWidget(route_id)); 1519 if (!widget_host_view->HasFocus()) 1520 widget_host_view->Focus(); 1521 } else { 1522 widget_host_view->InitAsPopup(GetRenderWidgetHostViewPort(), initial_pos); 1523 } 1524 1525 RenderWidgetHostImpl* render_widget_host_impl = 1526 RenderWidgetHostImpl::From(widget_host_view->GetRenderWidgetHost()); 1527 render_widget_host_impl->Init(); 1528 // Only allow privileged mouse lock for fullscreen render widget, which is 1529 // used to implement Pepper Flash fullscreen. 1530 render_widget_host_impl->set_allow_privileged_mouse_lock(is_fullscreen); 1531 1532 #if defined(OS_MACOSX) 1533 // A RenderWidgetHostViewMac has lifetime scoped to the view. Now that it's 1534 // properly embedded (or purposefully ignored) we can release the retain we 1535 // took in CreateNewWidget(). 1536 base::mac::NSObjectRelease(widget_host_view->GetNativeView()); 1537 #endif 1538 } 1539 1540 WebContentsImpl* WebContentsImpl::GetCreatedWindow(int route_id) { 1541 PendingContents::iterator iter = pending_contents_.find(route_id); 1542 1543 // Certain systems can block the creation of new windows. If we didn't succeed 1544 // in creating one, just return NULL. 1545 if (iter == pending_contents_.end()) { 1546 return NULL; 1547 } 1548 1549 WebContentsImpl* new_contents = iter->second; 1550 pending_contents_.erase(route_id); 1551 RemoveDestructionObserver(new_contents); 1552 1553 // Don't initialize the guest WebContents immediately. 1554 if (new_contents->GetRenderProcessHost()->IsGuest()) 1555 return new_contents; 1556 1557 if (!new_contents->GetRenderProcessHost()->HasConnection() || 1558 !new_contents->GetRenderViewHost()->GetView()) 1559 return NULL; 1560 1561 // TODO(brettw): It seems bogus to reach into here and initialize the host. 1562 static_cast<RenderViewHostImpl*>(new_contents->GetRenderViewHost())->Init(); 1563 return new_contents; 1564 } 1565 1566 RenderWidgetHostView* WebContentsImpl::GetCreatedWidget(int route_id) { 1567 PendingWidgetViews::iterator iter = pending_widget_views_.find(route_id); 1568 if (iter == pending_widget_views_.end()) { 1569 DCHECK(false); 1570 return NULL; 1571 } 1572 1573 RenderWidgetHostView* widget_host_view = iter->second; 1574 pending_widget_views_.erase(route_id); 1575 1576 RenderWidgetHost* widget_host = widget_host_view->GetRenderWidgetHost(); 1577 if (!widget_host->GetProcess()->HasConnection()) { 1578 // The view has gone away or the renderer crashed. Nothing to do. 1579 return NULL; 1580 } 1581 1582 return widget_host_view; 1583 } 1584 1585 void WebContentsImpl::ShowContextMenu(const ContextMenuParams& params) { 1586 // Allow WebContentsDelegates to handle the context menu operation first. 1587 if (delegate_ && delegate_->HandleContextMenu(params)) 1588 return; 1589 1590 render_view_host_delegate_view_->ShowContextMenu(params); 1591 } 1592 1593 void WebContentsImpl::RequestMediaAccessPermission( 1594 const MediaStreamRequest& request, 1595 const MediaResponseCallback& callback) { 1596 if (delegate_) 1597 delegate_->RequestMediaAccessPermission(this, request, callback); 1598 else 1599 callback.Run(MediaStreamDevices(), scoped_ptr<MediaStreamUI>()); 1600 } 1601 1602 SessionStorageNamespace* WebContentsImpl::GetSessionStorageNamespace( 1603 SiteInstance* instance) { 1604 return controller_.GetSessionStorageNamespace(instance); 1605 } 1606 1607 FrameTree* WebContentsImpl::GetFrameTree() { 1608 return &frame_tree_; 1609 } 1610 1611 void WebContentsImpl::OnShowValidationMessage( 1612 const gfx::Rect& anchor_in_root_view, 1613 const string16& main_text, 1614 const string16& sub_text) { 1615 if (delegate_) 1616 delegate_->ShowValidationMessage( 1617 this, anchor_in_root_view, main_text, sub_text); 1618 } 1619 1620 void WebContentsImpl::OnHideValidationMessage() { 1621 if (delegate_) 1622 delegate_->HideValidationMessage(this); 1623 } 1624 1625 void WebContentsImpl::OnMoveValidationMessage( 1626 const gfx::Rect& anchor_in_root_view) { 1627 if (delegate_) 1628 delegate_->MoveValidationMessage(this, anchor_in_root_view); 1629 } 1630 1631 void WebContentsImpl::DidSendScreenRects(RenderWidgetHostImpl* rwh) { 1632 if (browser_plugin_embedder_) 1633 browser_plugin_embedder_->DidSendScreenRects(); 1634 } 1635 1636 void WebContentsImpl::UpdatePreferredSize(const gfx::Size& pref_size) { 1637 preferred_size_ = pref_size; 1638 if (delegate_) 1639 delegate_->UpdatePreferredSize(this, pref_size); 1640 } 1641 1642 void WebContentsImpl::ResizeDueToAutoResize(const gfx::Size& new_size) { 1643 if (delegate_) 1644 delegate_->ResizeDueToAutoResize(this, new_size); 1645 } 1646 1647 WebContents* WebContentsImpl::OpenURL(const OpenURLParams& params) { 1648 if (!delegate_) 1649 return NULL; 1650 1651 WebContents* new_contents = delegate_->OpenURLFromTab(this, params); 1652 return new_contents; 1653 } 1654 1655 bool WebContentsImpl::Send(IPC::Message* message) { 1656 if (!GetRenderViewHost()) { 1657 delete message; 1658 return false; 1659 } 1660 1661 return GetRenderViewHost()->Send(message); 1662 } 1663 1664 bool WebContentsImpl::NavigateToPendingEntry( 1665 NavigationController::ReloadType reload_type) { 1666 return NavigateToEntry( 1667 *NavigationEntryImpl::FromNavigationEntry(controller_.GetPendingEntry()), 1668 reload_type); 1669 } 1670 1671 void WebContentsImpl::RenderViewForInterstitialPageCreated( 1672 RenderViewHost* render_view_host) { 1673 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 1674 RenderViewForInterstitialPageCreated(render_view_host)); 1675 } 1676 1677 void WebContentsImpl::AttachInterstitialPage( 1678 InterstitialPageImpl* interstitial_page) { 1679 DCHECK(interstitial_page); 1680 GetRenderManager()->set_interstitial_page(interstitial_page); 1681 1682 // Cancel any visible dialogs so that they don't interfere with the 1683 // interstitial. 1684 if (dialog_manager_) 1685 dialog_manager_->CancelActiveAndPendingDialogs(this); 1686 1687 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 1688 DidAttachInterstitialPage()); 1689 } 1690 1691 void WebContentsImpl::DetachInterstitialPage() { 1692 if (GetInterstitialPage()) 1693 GetRenderManager()->remove_interstitial_page(); 1694 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 1695 DidDetachInterstitialPage()); 1696 } 1697 1698 bool WebContentsImpl::NavigateToEntry( 1699 const NavigationEntryImpl& entry, 1700 NavigationController::ReloadType reload_type) { 1701 TRACE_EVENT0("browser", "WebContentsImpl::NavigateToEntry"); 1702 1703 // The renderer will reject IPC messages with URLs longer than 1704 // this limit, so don't attempt to navigate with a longer URL. 1705 if (entry.GetURL().spec().size() > GetMaxURLChars()) { 1706 LOG(WARNING) << "Refusing to load URL as it exceeds " << GetMaxURLChars() 1707 << " characters."; 1708 return false; 1709 } 1710 1711 // TODO(creis): Use entry->frame_tree_node_id() to pick which 1712 // RenderFrameHostManager to use. 1713 RenderViewHostImpl* dest_render_view_host = 1714 static_cast<RenderViewHostImpl*>(GetRenderManager()->Navigate(entry)); 1715 if (!dest_render_view_host) 1716 return false; // Unable to create the desired render view host. 1717 1718 // For security, we should never send non-Web-UI URLs to a Web UI renderer. 1719 // Double check that here. 1720 int enabled_bindings = dest_render_view_host->GetEnabledBindings(); 1721 bool data_urls_allowed = delegate_ && delegate_->CanLoadDataURLsInWebUI(); 1722 bool is_allowed_in_web_ui_renderer = 1723 WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI( 1724 GetBrowserContext(), entry.GetURL(), data_urls_allowed); 1725 if ((enabled_bindings & BINDINGS_POLICY_WEB_UI) && 1726 !is_allowed_in_web_ui_renderer) { 1727 // Log the URL to help us diagnose any future failures of this CHECK. 1728 GetContentClient()->SetActiveURL(entry.GetURL()); 1729 CHECK(0); 1730 } 1731 1732 // Notify observers that we will navigate in this RV. 1733 FOR_EACH_OBSERVER(WebContentsObserver, 1734 observers_, 1735 AboutToNavigateRenderView(dest_render_view_host)); 1736 1737 // Used for page load time metrics. 1738 current_load_start_ = base::TimeTicks::Now(); 1739 1740 // Navigate in the desired RenderViewHost. 1741 ViewMsg_Navigate_Params navigate_params; 1742 MakeNavigateParams(entry, controller_, delegate_, reload_type, 1743 &navigate_params); 1744 dest_render_view_host->Navigate(navigate_params); 1745 1746 if (entry.GetPageID() == -1) { 1747 // HACK!! This code suppresses javascript: URLs from being added to 1748 // session history, which is what we want to do for javascript: URLs that 1749 // do not generate content. What we really need is a message from the 1750 // renderer telling us that a new page was not created. The same message 1751 // could be used for mailto: URLs and the like. 1752 if (entry.GetURL().SchemeIs(kJavaScriptScheme)) 1753 return false; 1754 } 1755 1756 // Notify observers about navigation. 1757 FOR_EACH_OBSERVER( 1758 WebContentsObserver, 1759 observers_, 1760 DidStartNavigationToPendingEntry(entry.GetURL(), reload_type)); 1761 1762 if (delegate_) 1763 delegate_->DidNavigateToPendingEntry(this); 1764 1765 return true; 1766 } 1767 1768 void WebContentsImpl::SetHistoryLengthAndPrune( 1769 const SiteInstance* site_instance, 1770 int history_length, 1771 int32 minimum_page_id) { 1772 // SetHistoryLengthAndPrune doesn't work when there are pending cross-site 1773 // navigations. Callers should ensure that this is the case. 1774 if (GetRenderManager()->pending_render_view_host()) { 1775 NOTREACHED(); 1776 return; 1777 } 1778 RenderViewHostImpl* rvh = GetRenderViewHostImpl(); 1779 if (!rvh) { 1780 NOTREACHED(); 1781 return; 1782 } 1783 if (site_instance && rvh->GetSiteInstance() != site_instance) { 1784 NOTREACHED(); 1785 return; 1786 } 1787 Send(new ViewMsg_SetHistoryLengthAndPrune(GetRoutingID(), 1788 history_length, 1789 minimum_page_id)); 1790 } 1791 1792 void WebContentsImpl::FocusThroughTabTraversal(bool reverse) { 1793 if (ShowingInterstitialPage()) { 1794 GetRenderManager()->interstitial_page()->FocusThroughTabTraversal(reverse); 1795 return; 1796 } 1797 GetRenderViewHostImpl()->SetInitialFocus(reverse); 1798 } 1799 1800 bool WebContentsImpl::ShowingInterstitialPage() const { 1801 return GetRenderManager()->interstitial_page() != NULL; 1802 } 1803 1804 InterstitialPage* WebContentsImpl::GetInterstitialPage() const { 1805 return GetRenderManager()->interstitial_page(); 1806 } 1807 1808 bool WebContentsImpl::IsSavable() { 1809 // WebKit creates Document object when MIME type is application/xhtml+xml, 1810 // so we also support this MIME type. 1811 return contents_mime_type_ == "text/html" || 1812 contents_mime_type_ == "text/xml" || 1813 contents_mime_type_ == "application/xhtml+xml" || 1814 contents_mime_type_ == "text/plain" || 1815 contents_mime_type_ == "text/css" || 1816 net::IsSupportedJavascriptMimeType(contents_mime_type_.c_str()); 1817 } 1818 1819 void WebContentsImpl::OnSavePage() { 1820 // If we can not save the page, try to download it. 1821 if (!IsSavable()) { 1822 RecordDownloadSource(INITIATED_BY_SAVE_PACKAGE_ON_NON_HTML); 1823 SaveFrame(GetURL(), Referrer()); 1824 return; 1825 } 1826 1827 Stop(); 1828 1829 // Create the save package and possibly prompt the user for the name to save 1830 // the page as. The user prompt is an asynchronous operation that runs on 1831 // another thread. 1832 save_package_ = new SavePackage(this); 1833 save_package_->GetSaveInfo(); 1834 } 1835 1836 // Used in automated testing to bypass prompting the user for file names. 1837 // Instead, the names and paths are hard coded rather than running them through 1838 // file name sanitation and extension / mime checking. 1839 bool WebContentsImpl::SavePage(const base::FilePath& main_file, 1840 const base::FilePath& dir_path, 1841 SavePageType save_type) { 1842 // Stop the page from navigating. 1843 Stop(); 1844 1845 save_package_ = new SavePackage(this, save_type, main_file, dir_path); 1846 return save_package_->Init(SavePackageDownloadCreatedCallback()); 1847 } 1848 1849 void WebContentsImpl::SaveFrame(const GURL& url, 1850 const Referrer& referrer) { 1851 if (!GetURL().is_valid()) 1852 return; 1853 bool is_main_frame = (url == GetURL()); 1854 1855 DownloadManager* dlm = 1856 BrowserContext::GetDownloadManager(GetBrowserContext()); 1857 if (!dlm) 1858 return; 1859 int64 post_id = -1; 1860 if (is_main_frame) { 1861 const NavigationEntry* entry = controller_.GetLastCommittedEntry(); 1862 if (entry) 1863 post_id = entry->GetPostID(); 1864 } 1865 scoped_ptr<DownloadUrlParameters> params( 1866 DownloadUrlParameters::FromWebContents(this, url)); 1867 params->set_referrer(referrer); 1868 params->set_post_id(post_id); 1869 params->set_prefer_cache(true); 1870 if (post_id >= 0) 1871 params->set_method("POST"); 1872 params->set_prompt(true); 1873 dlm->DownloadUrl(params.Pass()); 1874 } 1875 1876 void WebContentsImpl::GenerateMHTML( 1877 const base::FilePath& file, 1878 const base::Callback<void(int64)>& callback) { 1879 MHTMLGenerationManager::GetInstance()->SaveMHTML(this, file, callback); 1880 } 1881 1882 // TODO(nasko): Rename this method to IsVisibleEntry. 1883 bool WebContentsImpl::IsActiveEntry(int32 page_id) { 1884 NavigationEntryImpl* visible_entry = 1885 NavigationEntryImpl::FromNavigationEntry(controller_.GetVisibleEntry()); 1886 return (visible_entry != NULL && 1887 visible_entry->site_instance() == GetSiteInstance() && 1888 visible_entry->GetPageID() == page_id); 1889 } 1890 1891 const std::string& WebContentsImpl::GetContentsMimeType() const { 1892 return contents_mime_type_; 1893 } 1894 1895 bool WebContentsImpl::WillNotifyDisconnection() const { 1896 return notify_disconnection_; 1897 } 1898 1899 void WebContentsImpl::SetOverrideEncoding(const std::string& encoding) { 1900 SetEncoding(encoding); 1901 Send(new ViewMsg_SetPageEncoding(GetRoutingID(), encoding)); 1902 } 1903 1904 void WebContentsImpl::ResetOverrideEncoding() { 1905 encoding_.clear(); 1906 Send(new ViewMsg_ResetPageEncodingToDefault(GetRoutingID())); 1907 } 1908 1909 RendererPreferences* WebContentsImpl::GetMutableRendererPrefs() { 1910 return &renderer_preferences_; 1911 } 1912 1913 void WebContentsImpl::Close() { 1914 Close(GetRenderViewHost()); 1915 } 1916 1917 void WebContentsImpl::DragSourceEndedAt(int client_x, int client_y, 1918 int screen_x, int screen_y, blink::WebDragOperation operation) { 1919 if (browser_plugin_embedder_.get()) 1920 browser_plugin_embedder_->DragSourceEndedAt(client_x, client_y, 1921 screen_x, screen_y, operation); 1922 if (GetRenderViewHost()) 1923 GetRenderViewHostImpl()->DragSourceEndedAt(client_x, client_y, 1924 screen_x, screen_y, operation); 1925 } 1926 1927 void WebContentsImpl::DragSourceMovedTo(int client_x, int client_y, 1928 int screen_x, int screen_y) { 1929 if (browser_plugin_embedder_.get()) 1930 browser_plugin_embedder_->DragSourceMovedTo(client_x, client_y, 1931 screen_x, screen_y); 1932 if (GetRenderViewHost()) 1933 GetRenderViewHostImpl()->DragSourceMovedTo(client_x, client_y, 1934 screen_x, screen_y); 1935 } 1936 1937 void WebContentsImpl::SystemDragEnded() { 1938 if (GetRenderViewHost()) 1939 GetRenderViewHostImpl()->DragSourceSystemDragEnded(); 1940 if (delegate_) 1941 delegate_->DragEnded(); 1942 if (browser_plugin_embedder_.get()) 1943 browser_plugin_embedder_->SystemDragEnded(); 1944 } 1945 1946 void WebContentsImpl::UserGestureDone() { 1947 OnUserGesture(); 1948 } 1949 1950 void WebContentsImpl::SetClosedByUserGesture(bool value) { 1951 closed_by_user_gesture_ = value; 1952 } 1953 1954 bool WebContentsImpl::GetClosedByUserGesture() const { 1955 return closed_by_user_gesture_; 1956 } 1957 1958 double WebContentsImpl::GetZoomLevel() const { 1959 HostZoomMapImpl* zoom_map = static_cast<HostZoomMapImpl*>( 1960 HostZoomMap::GetForBrowserContext(GetBrowserContext())); 1961 if (!zoom_map) 1962 return 0; 1963 1964 double zoom_level; 1965 if (temporary_zoom_settings_) { 1966 zoom_level = zoom_map->GetTemporaryZoomLevel( 1967 GetRenderProcessHost()->GetID(), GetRenderViewHost()->GetRoutingID()); 1968 } else { 1969 GURL url; 1970 NavigationEntry* entry = GetController().GetLastCommittedEntry(); 1971 // Since zoom map is updated using rewritten URL, use rewritten URL 1972 // to get the zoom level. 1973 url = entry ? entry->GetURL() : GURL::EmptyGURL(); 1974 zoom_level = zoom_map->GetZoomLevelForHostAndScheme(url.scheme(), 1975 net::GetHostOrSpecFromURL(url)); 1976 } 1977 return zoom_level; 1978 } 1979 1980 int WebContentsImpl::GetZoomPercent(bool* enable_increment, 1981 bool* enable_decrement) const { 1982 *enable_decrement = *enable_increment = false; 1983 // Calculate the zoom percent from the factor. Round up to the nearest whole 1984 // number. 1985 int percent = static_cast<int>( 1986 ZoomLevelToZoomFactor(GetZoomLevel()) * 100 + 0.5); 1987 *enable_decrement = percent > minimum_zoom_percent_; 1988 *enable_increment = percent < maximum_zoom_percent_; 1989 return percent; 1990 } 1991 1992 void WebContentsImpl::ViewSource() { 1993 if (!delegate_) 1994 return; 1995 1996 NavigationEntry* entry = GetController().GetLastCommittedEntry(); 1997 if (!entry) 1998 return; 1999 2000 delegate_->ViewSourceForTab(this, entry->GetURL()); 2001 } 2002 2003 void WebContentsImpl::ViewFrameSource(const GURL& url, 2004 const PageState& page_state) { 2005 if (!delegate_) 2006 return; 2007 2008 delegate_->ViewSourceForFrame(this, url, page_state); 2009 } 2010 2011 int WebContentsImpl::GetMinimumZoomPercent() const { 2012 return minimum_zoom_percent_; 2013 } 2014 2015 int WebContentsImpl::GetMaximumZoomPercent() const { 2016 return maximum_zoom_percent_; 2017 } 2018 2019 gfx::Size WebContentsImpl::GetPreferredSize() const { 2020 return preferred_size_; 2021 } 2022 2023 bool WebContentsImpl::GotResponseToLockMouseRequest(bool allowed) { 2024 return GetRenderViewHost() ? 2025 GetRenderViewHostImpl()->GotResponseToLockMouseRequest(allowed) : false; 2026 } 2027 2028 bool WebContentsImpl::HasOpener() const { 2029 return opener_ != NULL; 2030 } 2031 2032 void WebContentsImpl::DidChooseColorInColorChooser(SkColor color) { 2033 Send(new ViewMsg_DidChooseColorResponse( 2034 GetRoutingID(), color_chooser_identifier_, color)); 2035 } 2036 2037 void WebContentsImpl::DidEndColorChooser() { 2038 Send(new ViewMsg_DidEndColorChooser(GetRoutingID(), 2039 color_chooser_identifier_)); 2040 color_chooser_.reset(); 2041 color_chooser_identifier_ = 0; 2042 } 2043 2044 int WebContentsImpl::DownloadImage(const GURL& url, 2045 bool is_favicon, 2046 uint32_t max_bitmap_size, 2047 const ImageDownloadCallback& callback) { 2048 RenderViewHost* host = GetRenderViewHost(); 2049 int id = StartDownload(host, url, is_favicon, max_bitmap_size); 2050 image_download_map_[id] = callback; 2051 return id; 2052 } 2053 2054 void WebContentsImpl::SetZoomLevel(double level) { 2055 Send(new ViewMsg_SetZoomLevel(GetRoutingID(), level)); 2056 BrowserPluginEmbedder* embedder = GetBrowserPluginEmbedder(); 2057 if (embedder) 2058 embedder->SetZoomLevel(level); 2059 } 2060 2061 bool WebContentsImpl::FocusLocationBarByDefault() { 2062 NavigationEntry* entry = controller_.GetVisibleEntry(); 2063 if (entry && entry->GetURL() == GURL(kAboutBlankURL)) 2064 return true; 2065 return delegate_ && delegate_->ShouldFocusLocationBarByDefault(this); 2066 } 2067 2068 void WebContentsImpl::SetFocusToLocationBar(bool select_all) { 2069 if (delegate_) 2070 delegate_->SetFocusToLocationBar(select_all); 2071 } 2072 2073 void WebContentsImpl::DidStartProvisionalLoad( 2074 RenderFrameHostImpl* render_frame_host, 2075 int64 frame_id, 2076 int64 parent_frame_id, 2077 bool is_main_frame, 2078 const GURL& validated_url, 2079 bool is_error_page, 2080 bool is_iframe_srcdoc) { 2081 if (is_main_frame) 2082 DidChangeLoadProgress(0); 2083 2084 // Notify observers about the start of the provisional load. 2085 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2086 DidStartProvisionalLoadForFrame(frame_id, parent_frame_id, 2087 is_main_frame, validated_url, is_error_page, 2088 is_iframe_srcdoc, render_frame_host->render_view_host())); 2089 2090 if (is_main_frame) { 2091 FOR_EACH_OBSERVER( 2092 WebContentsObserver, 2093 observers_, 2094 ProvisionalChangeToMainFrameUrl(validated_url, 2095 render_frame_host->render_view_host())); 2096 } 2097 } 2098 2099 void WebContentsImpl::NotifyChangedNavigationState( 2100 InvalidateTypes changed_flags) { 2101 NotifyNavigationStateChanged(changed_flags); 2102 } 2103 2104 void WebContentsImpl::DidRedirectProvisionalLoad( 2105 RenderViewHost* render_view_host, 2106 int32 page_id, 2107 const GURL& source_url, 2108 const GURL& target_url) { 2109 // TODO(creis): Remove this method and have the pre-rendering code listen to 2110 // WebContentsObserver::DidGetRedirectForResourceRequest instead. 2111 // See http://crbug.com/78512. 2112 GURL validated_source_url(source_url); 2113 GURL validated_target_url(target_url); 2114 RenderProcessHost* render_process_host = 2115 render_view_host->GetProcess(); 2116 RenderViewHost::FilterURL(render_process_host, false, &validated_source_url); 2117 RenderViewHost::FilterURL(render_process_host, false, &validated_target_url); 2118 NavigationEntry* entry; 2119 if (page_id == -1) { 2120 entry = controller_.GetPendingEntry(); 2121 } else { 2122 entry = controller_.GetEntryWithPageID(render_view_host->GetSiteInstance(), 2123 page_id); 2124 } 2125 if (!entry || entry->GetURL() != validated_source_url) 2126 return; 2127 2128 // Notify observers about the provisional change in the main frame URL. 2129 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2130 ProvisionalChangeToMainFrameUrl(validated_target_url, 2131 render_view_host)); 2132 } 2133 2134 void WebContentsImpl::DidFailProvisionalLoadWithError( 2135 RenderViewHost* render_view_host, 2136 const ViewHostMsg_DidFailProvisionalLoadWithError_Params& params) { 2137 VLOG(1) << "Failed Provisional Load: " << params.url.possibly_invalid_spec() 2138 << ", error_code: " << params.error_code 2139 << ", error_description: " << params.error_description 2140 << ", is_main_frame: " << params.is_main_frame 2141 << ", showing_repost_interstitial: " << 2142 params.showing_repost_interstitial 2143 << ", frame_id: " << params.frame_id; 2144 GURL validated_url(params.url); 2145 RenderProcessHost* render_process_host = 2146 render_view_host->GetProcess(); 2147 RenderViewHost::FilterURL(render_process_host, false, &validated_url); 2148 2149 if (net::ERR_ABORTED == params.error_code) { 2150 // EVIL HACK ALERT! Ignore failed loads when we're showing interstitials. 2151 // This means that the interstitial won't be torn down properly, which is 2152 // bad. But if we have an interstitial, go back to another tab type, and 2153 // then load the same interstitial again, we could end up getting the first 2154 // interstitial's "failed" message (as a result of the cancel) when we're on 2155 // the second one. 2156 // 2157 // We can't tell this apart, so we think we're tearing down the current page 2158 // which will cause a crash later one. There is also some code in 2159 // RenderFrameHostManager::RendererAbortedProvisionalLoad that is commented 2160 // out because of this problem. 2161 // 2162 // http://code.google.com/p/chromium/issues/detail?id=2855 2163 // Because this will not tear down the interstitial properly, if "back" is 2164 // back to another tab type, the interstitial will still be somewhat alive 2165 // in the previous tab type. If you navigate somewhere that activates the 2166 // tab with the interstitial again, you'll see a flash before the new load 2167 // commits of the interstitial page. 2168 if (ShowingInterstitialPage()) { 2169 LOG(WARNING) << "Discarding message during interstitial."; 2170 return; 2171 } 2172 2173 GetRenderManager()->RendererAbortedProvisionalLoad(render_view_host); 2174 } 2175 2176 // Do not usually clear the pending entry if one exists, so that the user's 2177 // typed URL is not lost when a navigation fails or is aborted. However, in 2178 // cases that we don't show the pending entry (e.g., renderer-initiated 2179 // navigations in an existing tab), we don't keep it around. That prevents 2180 // spoofs on in-page navigations that don't go through 2181 // DidStartProvisionalLoadForFrame. 2182 // In general, we allow the view to clear the pending entry and typed URL if 2183 // the user requests (e.g., hitting Escape with focus in the address bar). 2184 // Note: don't touch the transient entry, since an interstitial may exist. 2185 if (controller_.GetPendingEntry() != controller_.GetVisibleEntry()) 2186 controller_.DiscardPendingEntry(); 2187 2188 FOR_EACH_OBSERVER(WebContentsObserver, 2189 observers_, 2190 DidFailProvisionalLoad(params.frame_id, 2191 params.frame_unique_name, 2192 params.is_main_frame, 2193 validated_url, 2194 params.error_code, 2195 params.error_description, 2196 render_view_host)); 2197 } 2198 2199 void WebContentsImpl::OnDidLoadResourceFromMemoryCache( 2200 const GURL& url, 2201 const std::string& security_info, 2202 const std::string& http_method, 2203 const std::string& mime_type, 2204 ResourceType::Type resource_type) { 2205 base::StatsCounter cache("WebKit.CacheHit"); 2206 cache.Increment(); 2207 2208 // Send out a notification that we loaded a resource from our memory cache. 2209 int cert_id = 0; 2210 net::CertStatus cert_status = 0; 2211 int security_bits = -1; 2212 int connection_status = 0; 2213 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids; 2214 DeserializeSecurityInfo(security_info, &cert_id, &cert_status, 2215 &security_bits, &connection_status, 2216 &signed_certificate_timestamp_ids); 2217 // TODO(alcutter,eranm): Pass signed_certificate_timestamp_ids into details 2218 LoadFromMemoryCacheDetails details( 2219 url, GetRenderProcessHost()->GetID(), cert_id, cert_status, http_method, 2220 mime_type, resource_type); 2221 2222 controller_.ssl_manager()->DidLoadFromMemoryCache(details); 2223 2224 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2225 DidLoadResourceFromMemoryCache(details)); 2226 2227 if (url.is_valid() && url.SchemeIsHTTPOrHTTPS()) { 2228 scoped_refptr<net::URLRequestContextGetter> request_context( 2229 resource_type == ResourceType::MEDIA ? 2230 GetBrowserContext()->GetMediaRequestContextForRenderProcess( 2231 GetRenderProcessHost()->GetID()) : 2232 GetBrowserContext()->GetRequestContextForRenderProcess( 2233 GetRenderProcessHost()->GetID())); 2234 BrowserThread::PostTask( 2235 BrowserThread::IO, 2236 FROM_HERE, 2237 base::Bind(&NotifyCacheOnIO, request_context, url, http_method)); 2238 } 2239 } 2240 2241 void WebContentsImpl::OnDidDisplayInsecureContent() { 2242 RecordAction(UserMetricsAction("SSL.DisplayedInsecureContent")); 2243 displayed_insecure_content_ = true; 2244 SSLManager::NotifySSLInternalStateChanged( 2245 GetController().GetBrowserContext()); 2246 } 2247 2248 void WebContentsImpl::OnDidRunInsecureContent( 2249 const std::string& security_origin, const GURL& target_url) { 2250 LOG(WARNING) << security_origin << " ran insecure content from " 2251 << target_url.possibly_invalid_spec(); 2252 RecordAction(UserMetricsAction("SSL.RanInsecureContent")); 2253 if (EndsWith(security_origin, kDotGoogleDotCom, false)) 2254 RecordAction(UserMetricsAction("SSL.RanInsecureContentGoogle")); 2255 controller_.ssl_manager()->DidRunInsecureContent(security_origin); 2256 displayed_insecure_content_ = true; 2257 SSLManager::NotifySSLInternalStateChanged( 2258 GetController().GetBrowserContext()); 2259 } 2260 2261 void WebContentsImpl::OnDocumentLoadedInFrame(int64 frame_id) { 2262 FOR_EACH_OBSERVER( 2263 WebContentsObserver, observers_, 2264 DocumentLoadedInFrame(frame_id, render_view_message_source_)); 2265 } 2266 2267 void WebContentsImpl::OnDidFinishLoad( 2268 int64 frame_id, 2269 const GURL& url, 2270 bool is_main_frame) { 2271 GURL validated_url(url); 2272 RenderProcessHost* render_process_host = 2273 render_view_message_source_->GetProcess(); 2274 RenderViewHost::FilterURL(render_process_host, false, &validated_url); 2275 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2276 DidFinishLoad(frame_id, validated_url, is_main_frame, 2277 render_view_message_source_)); 2278 } 2279 2280 void WebContentsImpl::OnDidFailLoadWithError( 2281 int64 frame_id, 2282 const GURL& url, 2283 bool is_main_frame, 2284 int error_code, 2285 const base::string16& error_description) { 2286 GURL validated_url(url); 2287 RenderProcessHost* render_process_host = 2288 render_view_message_source_->GetProcess(); 2289 RenderViewHost::FilterURL(render_process_host, false, &validated_url); 2290 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2291 DidFailLoad(frame_id, validated_url, is_main_frame, 2292 error_code, error_description, 2293 render_view_message_source_)); 2294 } 2295 2296 void WebContentsImpl::OnGoToEntryAtOffset(int offset) { 2297 if (!delegate_ || delegate_->OnGoToEntryOffset(offset)) { 2298 NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry( 2299 controller_.GetEntryAtOffset(offset)); 2300 if (!entry) 2301 return; 2302 // Note that we don't call NavigationController::GotToOffset() as we don't 2303 // want to create a pending navigation entry (it might end up lingering 2304 // http://crbug.com/51680). 2305 entry->SetTransitionType( 2306 PageTransitionFromInt( 2307 entry->GetTransitionType() | 2308 PAGE_TRANSITION_FORWARD_BACK)); 2309 NavigateToEntry(*entry, NavigationControllerImpl::NO_RELOAD); 2310 2311 // If the entry is being restored and doesn't have a SiteInstance yet, fill 2312 // it in now that we know. This allows us to find the entry when it commits. 2313 if (!entry->site_instance() && 2314 entry->restore_type() != NavigationEntryImpl::RESTORE_NONE) { 2315 entry->set_site_instance( 2316 static_cast<SiteInstanceImpl*>(GetPendingSiteInstance())); 2317 } 2318 } 2319 } 2320 2321 void WebContentsImpl::OnUpdateZoomLimits(int minimum_percent, 2322 int maximum_percent, 2323 bool remember) { 2324 minimum_zoom_percent_ = minimum_percent; 2325 maximum_zoom_percent_ = maximum_percent; 2326 temporary_zoom_settings_ = !remember; 2327 } 2328 2329 void WebContentsImpl::OnEnumerateDirectory(int request_id, 2330 const base::FilePath& path) { 2331 if (!delegate_) 2332 return; 2333 2334 ChildProcessSecurityPolicyImpl* policy = 2335 ChildProcessSecurityPolicyImpl::GetInstance(); 2336 if (policy->CanReadFile(GetRenderProcessHost()->GetID(), path)) 2337 delegate_->EnumerateDirectory(this, request_id, path); 2338 } 2339 2340 void WebContentsImpl::OnJSOutOfMemory() { 2341 if (delegate_) 2342 delegate_->JSOutOfMemory(this); 2343 } 2344 2345 void WebContentsImpl::OnRegisterProtocolHandler(const std::string& protocol, 2346 const GURL& url, 2347 const base::string16& title, 2348 bool user_gesture) { 2349 if (!delegate_) 2350 return; 2351 2352 ChildProcessSecurityPolicyImpl* policy = 2353 ChildProcessSecurityPolicyImpl::GetInstance(); 2354 if (policy->IsPseudoScheme(protocol)) 2355 return; 2356 2357 delegate_->RegisterProtocolHandler(this, protocol, url, title, user_gesture); 2358 } 2359 2360 void WebContentsImpl::OnFindReply(int request_id, 2361 int number_of_matches, 2362 const gfx::Rect& selection_rect, 2363 int active_match_ordinal, 2364 bool final_update) { 2365 if (delegate_) { 2366 delegate_->FindReply(this, request_id, number_of_matches, selection_rect, 2367 active_match_ordinal, final_update); 2368 } 2369 } 2370 2371 #if defined(OS_ANDROID) 2372 void WebContentsImpl::OnFindMatchRectsReply( 2373 int version, 2374 const std::vector<gfx::RectF>& rects, 2375 const gfx::RectF& active_rect) { 2376 if (delegate_) 2377 delegate_->FindMatchRectsReply(this, version, rects, active_rect); 2378 } 2379 2380 void WebContentsImpl::OnOpenDateTimeDialog( 2381 const ViewHostMsg_DateTimeDialogValue_Params& value) { 2382 date_time_chooser_->ShowDialog(ContentViewCore::FromWebContents(this), 2383 GetRenderViewHost(), 2384 value.dialog_type, 2385 value.dialog_value, 2386 value.minimum, 2387 value.maximum, 2388 value.step, 2389 value.suggestions); 2390 } 2391 2392 void WebContentsImpl::OnJavaBridgeGetChannelHandle(IPC::Message* reply_msg) { 2393 java_bridge_dispatcher_host_manager_->OnGetChannelHandle( 2394 render_view_message_source_, reply_msg); 2395 } 2396 2397 #endif 2398 2399 void WebContentsImpl::OnPepperPluginHung(int plugin_child_id, 2400 const base::FilePath& path, 2401 bool is_hung) { 2402 UMA_HISTOGRAM_COUNTS("Pepper.PluginHung", 1); 2403 2404 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2405 PluginHungStatusChanged(plugin_child_id, path, is_hung)); 2406 } 2407 2408 void WebContentsImpl::OnPluginCrashed(const base::FilePath& plugin_path, 2409 base::ProcessId plugin_pid) { 2410 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2411 PluginCrashed(plugin_path, plugin_pid)); 2412 } 2413 2414 void WebContentsImpl::OnAppCacheAccessed(const GURL& manifest_url, 2415 bool blocked_by_policy) { 2416 // Notify observers about navigation. 2417 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2418 AppCacheAccessed(manifest_url, blocked_by_policy)); 2419 } 2420 2421 void WebContentsImpl::OnOpenColorChooser( 2422 int color_chooser_id, 2423 SkColor color, 2424 const std::vector<ColorSuggestion>& suggestions) { 2425 ColorChooser* new_color_chooser = 2426 delegate_->OpenColorChooser(this, color, suggestions); 2427 if (!new_color_chooser) 2428 return; 2429 if (color_chooser_) 2430 color_chooser_->End(); 2431 color_chooser_.reset(new_color_chooser); 2432 color_chooser_identifier_ = color_chooser_id; 2433 } 2434 2435 void WebContentsImpl::OnEndColorChooser(int color_chooser_id) { 2436 if (color_chooser_ && 2437 color_chooser_id == color_chooser_identifier_) 2438 color_chooser_->End(); 2439 } 2440 2441 void WebContentsImpl::OnSetSelectedColorInColorChooser(int color_chooser_id, 2442 SkColor color) { 2443 if (color_chooser_ && 2444 color_chooser_id == color_chooser_identifier_) 2445 color_chooser_->SetSelectedColor(color); 2446 } 2447 2448 // This exists for render views that don't have a WebUI, but do have WebUI 2449 // bindings enabled. 2450 void WebContentsImpl::OnWebUISend(const GURL& source_url, 2451 const std::string& name, 2452 const base::ListValue& args) { 2453 if (delegate_) 2454 delegate_->WebUISend(this, source_url, name, args); 2455 } 2456 2457 void WebContentsImpl::OnRequestPpapiBrokerPermission( 2458 int routing_id, 2459 const GURL& url, 2460 const base::FilePath& plugin_path) { 2461 if (!delegate_) { 2462 OnPpapiBrokerPermissionResult(routing_id, false); 2463 return; 2464 } 2465 2466 if (!delegate_->RequestPpapiBrokerPermission( 2467 this, url, plugin_path, 2468 base::Bind(&WebContentsImpl::OnPpapiBrokerPermissionResult, 2469 base::Unretained(this), routing_id))) { 2470 NOTIMPLEMENTED(); 2471 OnPpapiBrokerPermissionResult(routing_id, false); 2472 } 2473 } 2474 2475 void WebContentsImpl::OnPpapiBrokerPermissionResult(int routing_id, 2476 bool result) { 2477 Send(new ViewMsg_PpapiBrokerPermissionResult(routing_id, result)); 2478 } 2479 2480 void WebContentsImpl::OnBrowserPluginMessage(const IPC::Message& message) { 2481 // This creates a BrowserPluginEmbedder, which handles all the BrowserPlugin 2482 // specific messages for this WebContents. This means that any message from 2483 // a BrowserPlugin prior to this will be ignored. 2484 // For more info, see comment above classes BrowserPluginEmbedder and 2485 // BrowserPluginGuest. 2486 CHECK(!browser_plugin_embedder_.get()); 2487 browser_plugin_embedder_.reset(BrowserPluginEmbedder::Create(this)); 2488 browser_plugin_embedder_->OnMessageReceived(message); 2489 } 2490 2491 void WebContentsImpl::OnDidDownloadImage( 2492 int id, 2493 int http_status_code, 2494 const GURL& image_url, 2495 const std::vector<SkBitmap>& bitmaps, 2496 const std::vector<gfx::Size>& original_bitmap_sizes) { 2497 if (bitmaps.size() != original_bitmap_sizes.size()) 2498 return; 2499 2500 ImageDownloadMap::iterator iter = image_download_map_.find(id); 2501 if (iter == image_download_map_.end()) { 2502 // Currently WebContents notifies us of ANY downloads so that it is 2503 // possible to get here. 2504 return; 2505 } 2506 if (!iter->second.is_null()) { 2507 iter->second.Run( 2508 id, http_status_code, image_url, bitmaps, original_bitmap_sizes); 2509 } 2510 image_download_map_.erase(id); 2511 } 2512 2513 void WebContentsImpl::OnUpdateFaviconURL( 2514 int32 page_id, 2515 const std::vector<FaviconURL>& candidates) { 2516 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2517 DidUpdateFaviconURL(page_id, candidates)); 2518 } 2519 2520 void WebContentsImpl::OnMediaNotification(int64 player_cookie, 2521 bool has_video, 2522 bool has_audio, 2523 bool is_playing) { 2524 // Chrome OS does its own detection of audio and video. 2525 #if !defined(OS_CHROMEOS) 2526 if (is_playing) { 2527 scoped_ptr<PowerSaveBlocker> blocker; 2528 if (has_video) { 2529 blocker = PowerSaveBlocker::Create( 2530 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, 2531 "Playing video"); 2532 #if defined(OS_ANDROID) 2533 static_cast<PowerSaveBlockerImpl*>(blocker.get())-> 2534 InitDisplaySleepBlocker(GetView()->GetNativeView()); 2535 #endif 2536 } else if (has_audio) { 2537 blocker = PowerSaveBlocker::Create( 2538 PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, 2539 "Playing audio"); 2540 } 2541 2542 if (blocker) { 2543 power_save_blockers_[render_view_message_source_][player_cookie] = 2544 blocker.release(); 2545 } 2546 } else { 2547 delete power_save_blockers_[render_view_message_source_][player_cookie]; 2548 power_save_blockers_[render_view_message_source_].erase(player_cookie); 2549 } 2550 #endif // !defined(OS_CHROMEOS) 2551 } 2552 2553 void WebContentsImpl::OnFirstVisuallyNonEmptyPaint(int32 page_id) { 2554 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2555 DidFirstVisuallyNonEmptyPaint(page_id)); 2556 } 2557 2558 void WebContentsImpl::DidChangeVisibleSSLState() { 2559 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2560 DidChangeVisibleSSLState()); 2561 } 2562 2563 void WebContentsImpl::NotifyBeforeFormRepostWarningShow() { 2564 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2565 BeforeFormRepostWarningShow()); 2566 } 2567 2568 2569 void WebContentsImpl::ActivateAndShowRepostFormWarningDialog() { 2570 Activate(); 2571 if (delegate_) 2572 delegate_->ShowRepostFormWarningDialog(this); 2573 } 2574 2575 // Notifies the RenderWidgetHost instance about the fact that the page is 2576 // loading, or done loading. 2577 void WebContentsImpl::SetIsLoading(RenderViewHost* render_view_host, 2578 bool is_loading, 2579 LoadNotificationDetails* details) { 2580 if (is_loading == is_loading_) 2581 return; 2582 2583 if (!is_loading) { 2584 load_state_ = net::LoadStateWithParam(net::LOAD_STATE_IDLE, 2585 base::string16()); 2586 load_state_host_.clear(); 2587 upload_size_ = 0; 2588 upload_position_ = 0; 2589 } 2590 2591 GetRenderManager()->SetIsLoading(is_loading); 2592 2593 is_loading_ = is_loading; 2594 waiting_for_response_ = is_loading; 2595 2596 if (delegate_) 2597 delegate_->LoadingStateChanged(this); 2598 NotifyNavigationStateChanged(INVALIDATE_TYPE_LOAD); 2599 2600 std::string url = (details ? details->url.possibly_invalid_spec() : "NULL"); 2601 if (is_loading) { 2602 TRACE_EVENT_ASYNC_BEGIN1("browser", "WebContentsImpl Loading", this, 2603 "URL", url); 2604 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2605 DidStartLoading(render_view_host)); 2606 } else { 2607 TRACE_EVENT_ASYNC_END1("browser", "WebContentsImpl Loading", this, 2608 "URL", url); 2609 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2610 DidStopLoading(render_view_host)); 2611 } 2612 2613 // TODO(avi): Remove. http://crbug.com/170921 2614 int type = is_loading ? NOTIFICATION_LOAD_START : NOTIFICATION_LOAD_STOP; 2615 NotificationDetails det = NotificationService::NoDetails(); 2616 if (details) 2617 det = Details<LoadNotificationDetails>(details); 2618 NotificationService::current()->Notify( 2619 type, Source<NavigationController>(&controller_), det); 2620 } 2621 2622 void WebContentsImpl::DidNavigateMainFramePostCommit( 2623 const LoadCommittedDetails& details, 2624 const ViewHostMsg_FrameNavigate_Params& params) { 2625 if (details.is_navigation_to_different_page()) { 2626 // Clear the status bubble. This is a workaround for a bug where WebKit 2627 // doesn't let us know that the cursor left an element during a 2628 // transition (this is also why the mouse cursor remains as a hand after 2629 // clicking on a link); see bugs 1184641 and 980803. We don't want to 2630 // clear the bubble when a user navigates to a named anchor in the same 2631 // page. 2632 UpdateTargetURL(details.entry->GetPageID(), GURL()); 2633 } 2634 2635 if (!details.is_in_page) { 2636 // Once the main frame is navigated, we're no longer considered to have 2637 // displayed insecure content. 2638 displayed_insecure_content_ = false; 2639 SSLManager::NotifySSLInternalStateChanged( 2640 GetController().GetBrowserContext()); 2641 } 2642 2643 // Notify observers about navigation. 2644 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2645 DidNavigateMainFrame(details, params)); 2646 } 2647 2648 void WebContentsImpl::DidNavigateAnyFramePostCommit( 2649 RenderViewHost* render_view_host, 2650 const LoadCommittedDetails& details, 2651 const ViewHostMsg_FrameNavigate_Params& params) { 2652 // If we navigate off the page, close all JavaScript dialogs. 2653 if (dialog_manager_ && !details.is_in_page) 2654 dialog_manager_->CancelActiveAndPendingDialogs(this); 2655 2656 // Notify observers about navigation. 2657 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2658 DidNavigateAnyFrame(details, params)); 2659 } 2660 2661 bool WebContentsImpl::ShouldAssignSiteForURL(const GURL& url) { 2662 // about:blank should not "use up" a new SiteInstance. The SiteInstance can 2663 // still be used for a normal web site. 2664 if (url == GURL(kAboutBlankURL)) 2665 return false; 2666 2667 // The embedder will then have the opportunity to determine if the URL 2668 // should "use up" the SiteInstance. 2669 return GetContentClient()->browser()->ShouldAssignSiteForURL(url); 2670 } 2671 2672 void WebContentsImpl::UpdateMaxPageIDIfNecessary(RenderViewHost* rvh) { 2673 // If we are creating a RVH for a restored controller, then we need to make 2674 // sure the RenderView starts with a next_page_id_ larger than the number 2675 // of restored entries. This must be called before the RenderView starts 2676 // navigating (to avoid a race between the browser updating max_page_id and 2677 // the renderer updating next_page_id_). Because of this, we only call this 2678 // from CreateRenderView and allow that to notify the RenderView for us. 2679 int max_restored_page_id = controller_.GetMaxRestoredPageID(); 2680 if (max_restored_page_id > 2681 GetMaxPageIDForSiteInstance(rvh->GetSiteInstance())) 2682 UpdateMaxPageIDForSiteInstance(rvh->GetSiteInstance(), 2683 max_restored_page_id); 2684 } 2685 2686 bool WebContentsImpl::UpdateTitleForEntry(NavigationEntryImpl* entry, 2687 const base::string16& title) { 2688 // For file URLs without a title, use the pathname instead. In the case of a 2689 // synthesized title, we don't want the update to count toward the "one set 2690 // per page of the title to history." 2691 base::string16 final_title; 2692 bool explicit_set; 2693 if (entry && entry->GetURL().SchemeIsFile() && title.empty()) { 2694 final_title = UTF8ToUTF16(entry->GetURL().ExtractFileName()); 2695 explicit_set = false; // Don't count synthetic titles toward the set limit. 2696 } else { 2697 TrimWhitespace(title, TRIM_ALL, &final_title); 2698 explicit_set = true; 2699 } 2700 2701 // If a page is created via window.open and never navigated, 2702 // there will be no navigation entry. In this situation, 2703 // |page_title_when_no_navigation_entry_| will be used for page title. 2704 if (entry) { 2705 if (final_title == entry->GetTitle()) 2706 return false; // Nothing changed, don't bother. 2707 2708 entry->SetTitle(final_title); 2709 } else { 2710 if (page_title_when_no_navigation_entry_ == final_title) 2711 return false; // Nothing changed, don't bother. 2712 2713 page_title_when_no_navigation_entry_ = final_title; 2714 } 2715 2716 // Lastly, set the title for the view. 2717 view_->SetPageTitle(final_title); 2718 2719 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2720 TitleWasSet(entry, explicit_set)); 2721 2722 // TODO(avi): Remove. http://crbug.com/170921 2723 std::pair<NavigationEntry*, bool> details = 2724 std::make_pair(entry, explicit_set); 2725 NotificationService::current()->Notify( 2726 NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED, 2727 Source<WebContents>(this), 2728 Details<std::pair<NavigationEntry*, bool> >(&details)); 2729 2730 return true; 2731 } 2732 2733 void WebContentsImpl::NotifySwapped(RenderViewHost* old_host, 2734 RenderViewHost* new_host) { 2735 // After sending out a swap notification, we need to send a disconnect 2736 // notification so that clients that pick up a pointer to |this| can NULL the 2737 // pointer. See Bug 1230284. 2738 notify_disconnection_ = true; 2739 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2740 RenderViewHostChanged(old_host, new_host)); 2741 2742 // TODO(avi): Remove. http://crbug.com/170921 2743 std::pair<RenderViewHost*, RenderViewHost*> details = 2744 std::make_pair(old_host, new_host); 2745 NotificationService::current()->Notify( 2746 NOTIFICATION_RENDER_VIEW_HOST_CHANGED, 2747 Source<WebContents>(this), 2748 Details<std::pair<RenderViewHost*, RenderViewHost*> >(&details)); 2749 2750 // Ensure that the associated embedder gets cleared after a RenderViewHost 2751 // gets swapped, so we don't reuse the same embedder next time a 2752 // RenderViewHost is attached to this WebContents. 2753 RemoveBrowserPluginEmbedder(); 2754 } 2755 2756 // TODO(avi): Remove this entire function because this notification is already 2757 // covered by two observer functions. http://crbug.com/170921 2758 void WebContentsImpl::NotifyDisconnected() { 2759 if (!notify_disconnection_) 2760 return; 2761 2762 notify_disconnection_ = false; 2763 NotificationService::current()->Notify( 2764 NOTIFICATION_WEB_CONTENTS_DISCONNECTED, 2765 Source<WebContents>(this), 2766 NotificationService::NoDetails()); 2767 } 2768 2769 void WebContentsImpl::NotifyNavigationEntryCommitted( 2770 const LoadCommittedDetails& load_details) { 2771 FOR_EACH_OBSERVER( 2772 WebContentsObserver, observers_, NavigationEntryCommitted(load_details)); 2773 } 2774 2775 bool WebContentsImpl::OnMessageReceived(RenderFrameHost* render_frame_host, 2776 const IPC::Message& message) { 2777 return OnMessageReceived(NULL, render_frame_host, message); 2778 } 2779 2780 void WebContentsImpl::RenderFrameCreated(RenderFrameHost* render_frame_host) { 2781 // Note this is only for subframes, the notification for the main frame 2782 // happens in RenderViewCreated. 2783 FOR_EACH_OBSERVER(WebContentsObserver, 2784 observers_, 2785 RenderFrameCreated(render_frame_host)); 2786 } 2787 2788 void WebContentsImpl::RenderFrameDeleted(RenderFrameHost* render_frame_host) { 2789 FOR_EACH_OBSERVER(WebContentsObserver, 2790 observers_, 2791 RenderFrameDeleted(render_frame_host)); 2792 } 2793 2794 RenderViewHostDelegateView* WebContentsImpl::GetDelegateView() { 2795 return render_view_host_delegate_view_; 2796 } 2797 2798 RenderViewHostDelegate::RendererManagement* 2799 WebContentsImpl::GetRendererManagementDelegate() { 2800 return GetRenderManager(); 2801 } 2802 2803 RendererPreferences WebContentsImpl::GetRendererPrefs( 2804 BrowserContext* browser_context) const { 2805 return renderer_preferences_; 2806 } 2807 2808 WebContents* WebContentsImpl::GetAsWebContents() { 2809 return this; 2810 } 2811 2812 gfx::Rect WebContentsImpl::GetRootWindowResizerRect() const { 2813 if (delegate_) 2814 return delegate_->GetRootWindowResizerRect(); 2815 return gfx::Rect(); 2816 } 2817 2818 void WebContentsImpl::RemoveBrowserPluginEmbedder() { 2819 if (browser_plugin_embedder_) 2820 browser_plugin_embedder_.reset(); 2821 } 2822 2823 void WebContentsImpl::RenderViewCreated(RenderViewHost* render_view_host) { 2824 // Don't send notifications if we are just creating a swapped-out RVH for 2825 // the opener chain. These won't be used for view-source or WebUI, so it's 2826 // ok to return early. 2827 if (static_cast<RenderViewHostImpl*>(render_view_host)->is_swapped_out()) 2828 return; 2829 2830 if (delegate_) 2831 view_->SetOverscrollControllerEnabled(delegate_->CanOverscrollContent()); 2832 2833 NotificationService::current()->Notify( 2834 NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED, 2835 Source<WebContents>(this), 2836 Details<RenderViewHost>(render_view_host)); 2837 2838 // When we're creating views, we're still doing initial setup, so we always 2839 // use the pending Web UI rather than any possibly existing committed one. 2840 if (GetRenderManager()->pending_web_ui()) 2841 GetRenderManager()->pending_web_ui()->RenderViewCreated(render_view_host); 2842 2843 NavigationEntry* entry = controller_.GetPendingEntry(); 2844 if (entry && entry->IsViewSourceMode()) { 2845 // Put the renderer in view source mode. 2846 render_view_host->Send( 2847 new ViewMsg_EnableViewSourceMode(render_view_host->GetRoutingID())); 2848 } 2849 2850 view_->RenderViewCreated(render_view_host); 2851 2852 FOR_EACH_OBSERVER( 2853 WebContentsObserver, observers_, RenderViewCreated(render_view_host)); 2854 2855 // We tell the observers now instead of when the main RenderFrameHostImpl is 2856 // constructed because otherwise it would be too early (i.e. IPCs sent to the 2857 // frame would be dropped because it's not created yet). 2858 RenderFrameHost* main_frame = GetMainFrame(); 2859 FOR_EACH_OBSERVER( 2860 WebContentsObserver, observers_, RenderFrameCreated(main_frame)); 2861 } 2862 2863 void WebContentsImpl::RenderViewReady(RenderViewHost* rvh) { 2864 if (rvh != GetRenderViewHost()) { 2865 // Don't notify the world, since this came from a renderer in the 2866 // background. 2867 return; 2868 } 2869 2870 notify_disconnection_ = true; 2871 // TODO(avi): Remove. http://crbug.com/170921 2872 NotificationService::current()->Notify( 2873 NOTIFICATION_WEB_CONTENTS_CONNECTED, 2874 Source<WebContents>(this), 2875 NotificationService::NoDetails()); 2876 2877 bool was_crashed = IsCrashed(); 2878 SetIsCrashed(base::TERMINATION_STATUS_STILL_RUNNING, 0); 2879 2880 // Restore the focus to the tab (otherwise the focus will be on the top 2881 // window). 2882 if (was_crashed && !FocusLocationBarByDefault() && 2883 (!delegate_ || delegate_->ShouldFocusPageAfterCrash())) { 2884 view_->Focus(); 2885 } 2886 2887 FOR_EACH_OBSERVER(WebContentsObserver, observers_, RenderViewReady()); 2888 } 2889 2890 void WebContentsImpl::RenderViewTerminated(RenderViewHost* rvh, 2891 base::TerminationStatus status, 2892 int error_code) { 2893 if (rvh != GetRenderViewHost()) { 2894 // The pending page's RenderViewHost is gone. 2895 return; 2896 } 2897 2898 // Cancel any visible dialogs so they are not left dangling over the sad tab. 2899 if (dialog_manager_) 2900 dialog_manager_->CancelActiveAndPendingDialogs(this); 2901 2902 ClearPowerSaveBlockers(rvh); 2903 SetIsLoading(rvh, false, NULL); 2904 NotifyDisconnected(); 2905 SetIsCrashed(status, error_code); 2906 GetView()->OnTabCrashed(GetCrashedStatus(), crashed_error_code_); 2907 2908 FOR_EACH_OBSERVER(WebContentsObserver, 2909 observers_, 2910 RenderProcessGone(GetCrashedStatus())); 2911 } 2912 2913 void WebContentsImpl::RenderViewDeleted(RenderViewHost* rvh) { 2914 ClearPowerSaveBlockers(rvh); 2915 GetRenderManager()->RenderViewDeleted(rvh); 2916 FOR_EACH_OBSERVER(WebContentsObserver, observers_, RenderViewDeleted(rvh)); 2917 } 2918 2919 void WebContentsImpl::DidGetResourceResponseStart( 2920 const ResourceRequestDetails& details) { 2921 controller_.ssl_manager()->DidStartResourceResponse(details); 2922 2923 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2924 DidGetResourceResponseStart(details)); 2925 2926 // TODO(avi): Remove. http://crbug.com/170921 2927 NotificationService::current()->Notify( 2928 NOTIFICATION_RESOURCE_RESPONSE_STARTED, 2929 Source<WebContents>(this), 2930 Details<const ResourceRequestDetails>(&details)); 2931 } 2932 2933 void WebContentsImpl::DidGetRedirectForResourceRequest( 2934 const ResourceRedirectDetails& details) { 2935 controller_.ssl_manager()->DidReceiveResourceRedirect(details); 2936 2937 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2938 DidGetRedirectForResourceRequest(details)); 2939 2940 // TODO(avi): Remove. http://crbug.com/170921 2941 NotificationService::current()->Notify( 2942 NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, 2943 Source<WebContents>(this), 2944 Details<const ResourceRedirectDetails>(&details)); 2945 } 2946 2947 void WebContentsImpl::DidNavigate( 2948 RenderViewHost* rvh, 2949 const ViewHostMsg_FrameNavigate_Params& params) { 2950 if (frame_tree_.IsFirstNavigationAfterSwap()) { 2951 // First navigation should be a main frame navigation. 2952 DCHECK(PageTransitionIsMainFrame(params.transition)); 2953 frame_tree_.OnFirstNavigationAfterSwap(params.frame_id); 2954 } 2955 2956 if (PageTransitionIsMainFrame(params.transition)) { 2957 // When overscroll navigation gesture is enabled, a screenshot of the page 2958 // in its current state is taken so that it can be used during the 2959 // nav-gesture. It is necessary to take the screenshot here, before calling 2960 // RenderFrameHostManager::DidNavigateMainFrame, because that can change 2961 // WebContents::GetRenderViewHost to return the new host, instead of the one 2962 // that may have just been swapped out. 2963 if (delegate_ && delegate_->CanOverscrollContent()) 2964 controller_.TakeScreenshot(); 2965 2966 GetRenderManager()->DidNavigateMainFrame(rvh); 2967 } 2968 2969 // Update the site of the SiteInstance if it doesn't have one yet, unless 2970 // assigning a site is not necessary for this URL. In that case, the 2971 // SiteInstance can still be considered unused until a navigation to a real 2972 // page. 2973 if (!static_cast<SiteInstanceImpl*>(GetSiteInstance())->HasSite() && 2974 ShouldAssignSiteForURL(params.url)) { 2975 static_cast<SiteInstanceImpl*>(GetSiteInstance())->SetSite(params.url); 2976 } 2977 2978 // Need to update MIME type here because it's referred to in 2979 // UpdateNavigationCommands() called by RendererDidNavigate() to 2980 // determine whether or not to enable the encoding menu. 2981 // It's updated only for the main frame. For a subframe, 2982 // RenderView::UpdateURL does not set params.contents_mime_type. 2983 // (see http://code.google.com/p/chromium/issues/detail?id=2929 ) 2984 // TODO(jungshik): Add a test for the encoding menu to avoid 2985 // regressing it again. 2986 if (PageTransitionIsMainFrame(params.transition)) 2987 contents_mime_type_ = params.contents_mime_type; 2988 2989 LoadCommittedDetails details; 2990 bool did_navigate = controller_.RendererDidNavigate(params, &details); 2991 2992 // For now, keep track of each frame's URL in its FrameTreeNode. This lets 2993 // us estimate our process count for implementing OOP iframes. 2994 // TODO(creis): Remove this when we track which pages commit in each frame. 2995 frame_tree_.SetFrameUrl(params.frame_id, params.url); 2996 2997 // Send notification about committed provisional loads. This notification is 2998 // different from the NAV_ENTRY_COMMITTED notification which doesn't include 2999 // the actual URL navigated to and isn't sent for AUTO_SUBFRAME navigations. 3000 if (details.type != NAVIGATION_TYPE_NAV_IGNORE) { 3001 // For AUTO_SUBFRAME navigations, an event for the main frame is generated 3002 // that is not recorded in the navigation history. For the purpose of 3003 // tracking navigation events, we treat this event as a sub frame navigation 3004 // event. 3005 bool is_main_frame = did_navigate ? details.is_main_frame : false; 3006 PageTransition transition_type = params.transition; 3007 // Whether or not a page transition was triggered by going backward or 3008 // forward in the history is only stored in the navigation controller's 3009 // entry list. 3010 if (did_navigate && 3011 (controller_.GetLastCommittedEntry()->GetTransitionType() & 3012 PAGE_TRANSITION_FORWARD_BACK)) { 3013 transition_type = PageTransitionFromInt( 3014 params.transition | PAGE_TRANSITION_FORWARD_BACK); 3015 } 3016 // Notify observers about the commit of the provisional load. 3017 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 3018 DidCommitProvisionalLoadForFrame( 3019 params.frame_id, 3020 params.frame_unique_name, 3021 is_main_frame, 3022 params.url, 3023 transition_type, 3024 rvh)); 3025 } 3026 3027 if (!did_navigate) 3028 return; // No navigation happened. 3029 3030 // DO NOT ADD MORE STUFF TO THIS FUNCTION! Your component should either listen 3031 // for the appropriate notification (best) or you can add it to 3032 // DidNavigateMainFramePostCommit / DidNavigateAnyFramePostCommit (only if 3033 // necessary, please). 3034 3035 // Run post-commit tasks. 3036 if (details.is_main_frame) { 3037 DidNavigateMainFramePostCommit(details, params); 3038 if (delegate_) { 3039 delegate_->DidNavigateMainFramePostCommit(this); 3040 view_->SetOverscrollControllerEnabled(delegate_->CanOverscrollContent()); 3041 } 3042 } 3043 DidNavigateAnyFramePostCommit(rvh, details, params); 3044 } 3045 3046 void WebContentsImpl::UpdateState(RenderViewHost* rvh, 3047 int32 page_id, 3048 const PageState& page_state) { 3049 // Ensure that this state update comes from either the active RVH or one of 3050 // the swapped out RVHs. We don't expect to hear from any other RVHs. 3051 DCHECK(rvh == GetRenderViewHost() || 3052 GetRenderManager()->IsOnSwappedOutList(rvh)); 3053 3054 // We must be prepared to handle state updates for any page, these occur 3055 // when the user is scrolling and entering form data, as well as when we're 3056 // leaving a page, in which case our state may have already been moved to 3057 // the next page. The navigation controller will look up the appropriate 3058 // NavigationEntry and update it when it is notified via the delegate. 3059 3060 int entry_index = controller_.GetEntryIndexWithPageID( 3061 rvh->GetSiteInstance(), page_id); 3062 if (entry_index < 0) 3063 return; 3064 NavigationEntry* entry = controller_.GetEntryAtIndex(entry_index); 3065 3066 if (page_state == entry->GetPageState()) 3067 return; // Nothing to update. 3068 entry->SetPageState(page_state); 3069 controller_.NotifyEntryChanged(entry, entry_index); 3070 } 3071 3072 void WebContentsImpl::UpdateTitle(RenderViewHost* rvh, 3073 int32 page_id, 3074 const base::string16& title, 3075 base::i18n::TextDirection title_direction) { 3076 // If we have a title, that's a pretty good indication that we've started 3077 // getting useful data. 3078 SetNotWaitingForResponse(); 3079 3080 // Try to find the navigation entry, which might not be the current one. 3081 // For example, it might be from a pending RVH for the pending entry. 3082 NavigationEntryImpl* entry = controller_.GetEntryWithPageID( 3083 rvh->GetSiteInstance(), page_id); 3084 3085 // We can handle title updates when we don't have an entry in 3086 // UpdateTitleForEntry, but only if the update is from the current RVH. 3087 if (!entry && rvh != GetRenderViewHost()) 3088 return; 3089 3090 // TODO(evan): make use of title_direction. 3091 // http://code.google.com/p/chromium/issues/detail?id=27094 3092 if (!UpdateTitleForEntry(entry, title)) 3093 return; 3094 3095 // Broadcast notifications when the UI should be updated. 3096 if (entry == controller_.GetEntryAtOffset(0)) 3097 NotifyNavigationStateChanged(INVALIDATE_TYPE_TITLE); 3098 } 3099 3100 void WebContentsImpl::UpdateEncoding(RenderViewHost* render_view_host, 3101 const std::string& encoding) { 3102 SetEncoding(encoding); 3103 } 3104 3105 void WebContentsImpl::UpdateTargetURL(int32 page_id, const GURL& url) { 3106 if (delegate_) 3107 delegate_->UpdateTargetURL(this, page_id, url); 3108 } 3109 3110 void WebContentsImpl::Close(RenderViewHost* rvh) { 3111 #if defined(OS_MACOSX) 3112 // The UI may be in an event-tracking loop, such as between the 3113 // mouse-down and mouse-up in text selection or a button click. 3114 // Defer the close until after tracking is complete, so that we 3115 // don't free objects out from under the UI. 3116 // TODO(shess): This could get more fine-grained. For instance, 3117 // closing a tab in another window while selecting text in the 3118 // current window's Omnibox should be just fine. 3119 if (view_->IsEventTracking()) { 3120 view_->CloseTabAfterEventTracking(); 3121 return; 3122 } 3123 #endif 3124 3125 // Ignore this if it comes from a RenderViewHost that we aren't showing. 3126 if (delegate_ && rvh == GetRenderViewHost()) 3127 delegate_->CloseContents(this); 3128 } 3129 3130 void WebContentsImpl::SwappedOut(RenderViewHost* rvh) { 3131 if (delegate_ && rvh == GetRenderViewHost()) 3132 delegate_->SwappedOut(this); 3133 3134 // Allow the navigation to proceed. 3135 GetRenderManager()->SwappedOut(rvh); 3136 } 3137 3138 void WebContentsImpl::RequestMove(const gfx::Rect& new_bounds) { 3139 if (delegate_ && delegate_->IsPopupOrPanel(this)) 3140 delegate_->MoveContents(this, new_bounds); 3141 } 3142 3143 void WebContentsImpl::DidStartLoading(RenderViewHost* render_view_host) { 3144 SetIsLoading(render_view_host, true, NULL); 3145 } 3146 3147 void WebContentsImpl::DidStopLoading(RenderViewHost* render_view_host) { 3148 scoped_ptr<LoadNotificationDetails> details; 3149 3150 // Use the last committed entry rather than the active one, in case a 3151 // pending entry has been created. 3152 NavigationEntry* entry = controller_.GetLastCommittedEntry(); 3153 3154 // An entry may not exist for a stop when loading an initial blank page or 3155 // if an iframe injected by script into a blank page finishes loading. 3156 if (entry) { 3157 base::TimeDelta elapsed = base::TimeTicks::Now() - current_load_start_; 3158 3159 details.reset(new LoadNotificationDetails( 3160 entry->GetVirtualURL(), 3161 entry->GetTransitionType(), 3162 elapsed, 3163 &controller_, 3164 controller_.GetCurrentEntryIndex())); 3165 } 3166 3167 SetIsLoading(render_view_host, false, details.get()); 3168 } 3169 3170 void WebContentsImpl::DidCancelLoading() { 3171 controller_.DiscardNonCommittedEntries(); 3172 3173 // Update the URL display. 3174 NotifyNavigationStateChanged(INVALIDATE_TYPE_URL); 3175 } 3176 3177 void WebContentsImpl::DidChangeLoadProgress(double progress) { 3178 if (delegate_) 3179 delegate_->LoadProgressChanged(this, progress); 3180 } 3181 3182 void WebContentsImpl::DidDisownOpener(RenderViewHost* rvh) { 3183 if (opener_) { 3184 // Clear our opener so that future cross-process navigations don't have an 3185 // opener assigned. 3186 RemoveDestructionObserver(opener_); 3187 opener_ = NULL; 3188 } 3189 3190 // Notify all swapped out RenderViewHosts for this tab. This is important 3191 // in case we go back to them, or if another window in those processes tries 3192 // to access window.opener. 3193 GetRenderManager()->DidDisownOpener(rvh); 3194 } 3195 3196 void WebContentsImpl::DidAccessInitialDocument() { 3197 // Update the URL display. 3198 NotifyNavigationStateChanged(content::INVALIDATE_TYPE_URL); 3199 } 3200 3201 void WebContentsImpl::DocumentAvailableInMainFrame( 3202 RenderViewHost* render_view_host) { 3203 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 3204 DocumentAvailableInMainFrame()); 3205 } 3206 3207 void WebContentsImpl::DocumentOnLoadCompletedInMainFrame( 3208 RenderViewHost* render_view_host, 3209 int32 page_id) { 3210 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 3211 DocumentOnLoadCompletedInMainFrame(page_id)); 3212 3213 // TODO(avi): Remove. http://crbug.com/170921 3214 NotificationService::current()->Notify( 3215 NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, 3216 Source<WebContents>(this), 3217 Details<int>(&page_id)); 3218 } 3219 3220 void WebContentsImpl::RequestOpenURL(RenderViewHost* rvh, 3221 const GURL& url, 3222 const Referrer& referrer, 3223 WindowOpenDisposition disposition, 3224 int64 source_frame_id, 3225 bool should_replace_current_entry, 3226 bool user_gesture) { 3227 // If this came from a swapped out RenderViewHost, we only allow the request 3228 // if we are still in the same BrowsingInstance. 3229 if (static_cast<RenderViewHostImpl*>(rvh)->is_swapped_out() && 3230 !rvh->GetSiteInstance()->IsRelatedSiteInstance(GetSiteInstance())) { 3231 return; 3232 } 3233 3234 // Delegate to RequestTransferURL because this is just the generic 3235 // case where |old_request_id| is empty. 3236 // TODO(creis): Pass the redirect_chain into this method to support client 3237 // redirects. http://crbug.com/311721. 3238 std::vector<GURL> redirect_chain; 3239 RequestTransferURL(url, redirect_chain, referrer, PAGE_TRANSITION_LINK, 3240 disposition, source_frame_id, GlobalRequestID(), 3241 should_replace_current_entry, user_gesture); 3242 } 3243 3244 void WebContentsImpl::RequestTransferURL( 3245 const GURL& url, 3246 const std::vector<GURL>& redirect_chain, 3247 const Referrer& referrer, 3248 PageTransition page_transition, 3249 WindowOpenDisposition disposition, 3250 int64 source_frame_id, 3251 const GlobalRequestID& old_request_id, 3252 bool should_replace_current_entry, 3253 bool user_gesture) { 3254 WebContents* new_contents = NULL; 3255 GURL dest_url(url); 3256 if (!GetContentClient()->browser()->ShouldAllowOpenURL( 3257 GetSiteInstance(), url)) 3258 dest_url = GURL(kAboutBlankURL); 3259 3260 // TODO(creis): Look up the FrameTreeNode ID corresponding to source_frame_id. 3261 int frame_tree_node_id = -1; 3262 OpenURLParams params(dest_url, referrer, source_frame_id, 3263 frame_tree_node_id, disposition, 3264 page_transition, true /* is_renderer_initiated */); 3265 if (redirect_chain.size() > 0) 3266 params.redirect_chain = redirect_chain; 3267 params.transferred_global_request_id = old_request_id; 3268 params.should_replace_current_entry = should_replace_current_entry; 3269 params.user_gesture = user_gesture; 3270 3271 if (GetRenderManager()->web_ui()) { 3272 // Web UI pages sometimes want to override the page transition type for 3273 // link clicks (e.g., so the new tab page can specify AUTO_BOOKMARK for 3274 // automatically generated suggestions). We don't override other types 3275 // like TYPED because they have different implications (e.g., autocomplete). 3276 if (PageTransitionCoreTypeIs(params.transition, PAGE_TRANSITION_LINK)) 3277 params.transition = GetRenderManager()->web_ui()->GetLinkTransitionType(); 3278 3279 // Note also that we hide the referrer for Web UI pages. We don't really 3280 // want web sites to see a referrer of "chrome://blah" (and some 3281 // chrome: URLs might have search terms or other stuff we don't want to 3282 // send to the site), so we send no referrer. 3283 params.referrer = Referrer(); 3284 3285 // Navigations in Web UI pages count as browser-initiated navigations. 3286 params.is_renderer_initiated = false; 3287 } 3288 3289 new_contents = OpenURL(params); 3290 3291 if (new_contents) { 3292 // Notify observers. 3293 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 3294 DidOpenRequestedURL(new_contents, 3295 dest_url, 3296 referrer, 3297 disposition, 3298 params.transition, 3299 source_frame_id)); 3300 } 3301 } 3302 3303 void WebContentsImpl::RouteCloseEvent(RenderViewHost* rvh) { 3304 // Tell the active RenderViewHost to run unload handlers and close, as long 3305 // as the request came from a RenderViewHost in the same BrowsingInstance. 3306 // In most cases, we receive this from a swapped out RenderViewHost. 3307 // It is possible to receive it from one that has just been swapped in, 3308 // in which case we might as well deliver the message anyway. 3309 if (rvh->GetSiteInstance()->IsRelatedSiteInstance(GetSiteInstance())) 3310 GetRenderViewHost()->ClosePage(); 3311 } 3312 3313 void WebContentsImpl::RouteMessageEvent( 3314 RenderViewHost* rvh, 3315 const ViewMsg_PostMessage_Params& params) { 3316 // Only deliver the message to the active RenderViewHost if the request 3317 // came from a RenderViewHost in the same BrowsingInstance or if this 3318 // WebContents is dedicated to a browser plugin guest. 3319 // Note: This check means that an embedder could theoretically receive a 3320 // postMessage from anyone (not just its own guests). However, this is 3321 // probably not a risk for apps since other pages won't have references 3322 // to App windows. 3323 if (!rvh->GetSiteInstance()->IsRelatedSiteInstance(GetSiteInstance()) && 3324 !GetBrowserPluginGuest() && !GetBrowserPluginEmbedder()) 3325 return; 3326 3327 ViewMsg_PostMessage_Params new_params(params); 3328 3329 if (!params.message_port_ids.empty()) { 3330 MessagePortMessageFilter* message_port_message_filter = 3331 static_cast<RenderProcessHostImpl*>(GetRenderProcessHost()) 3332 ->message_port_message_filter(); 3333 std::vector<int> new_routing_ids(params.message_port_ids.size()); 3334 for (size_t i = 0; i < params.message_port_ids.size(); ++i) { 3335 new_routing_ids[i] = message_port_message_filter->GetNextRoutingID(); 3336 MessagePortService::GetInstance()->UpdateMessagePort( 3337 params.message_port_ids[i], 3338 message_port_message_filter, 3339 new_routing_ids[i]); 3340 } 3341 new_params.new_routing_ids = new_routing_ids; 3342 } 3343 3344 // If there is a source_routing_id, translate it to the routing ID for 3345 // the equivalent swapped out RVH in the target process. If we need 3346 // to create a swapped out RVH for the source tab, we create its opener 3347 // chain as well, since those will also be accessible to the target page. 3348 if (new_params.source_routing_id != MSG_ROUTING_NONE) { 3349 // Try to look up the WebContents for the source page. 3350 WebContentsImpl* source_contents = NULL; 3351 RenderViewHostImpl* source_rvh = RenderViewHostImpl::FromID( 3352 rvh->GetProcess()->GetID(), params.source_routing_id); 3353 if (source_rvh) { 3354 source_contents = static_cast<WebContentsImpl*>( 3355 source_rvh->GetDelegate()->GetAsWebContents()); 3356 } 3357 3358 if (source_contents) { 3359 if (GetBrowserPluginGuest()) { 3360 // We create a swapped out RenderView for the embedder in the guest's 3361 // render process but we intentionally do not expose the embedder's 3362 // opener chain to it. 3363 new_params.source_routing_id = 3364 source_contents->CreateSwappedOutRenderView(GetSiteInstance()); 3365 } else { 3366 new_params.source_routing_id = 3367 source_contents->CreateOpenerRenderViews(GetSiteInstance()); 3368 } 3369 } else { 3370 // We couldn't find it, so don't pass a source frame. 3371 new_params.source_routing_id = MSG_ROUTING_NONE; 3372 } 3373 } 3374 3375 // In most cases, we receive this from a swapped out RenderViewHost. 3376 // It is possible to receive it from one that has just been swapped in, 3377 // in which case we might as well deliver the message anyway. 3378 Send(new ViewMsg_PostMessageEvent(GetRoutingID(), new_params)); 3379 } 3380 3381 void WebContentsImpl::RunJavaScriptMessage( 3382 RenderViewHost* rvh, 3383 const base::string16& message, 3384 const base::string16& default_prompt, 3385 const GURL& frame_url, 3386 JavaScriptMessageType javascript_message_type, 3387 IPC::Message* reply_msg, 3388 bool* did_suppress_message) { 3389 // Suppress JavaScript dialogs when requested. Also suppress messages when 3390 // showing an interstitial as it's shown over the previous page and we don't 3391 // want the hidden page's dialogs to interfere with the interstitial. 3392 bool suppress_this_message = 3393 static_cast<RenderViewHostImpl*>(rvh)->is_swapped_out() || 3394 ShowingInterstitialPage() || 3395 !delegate_ || 3396 delegate_->ShouldSuppressDialogs() || 3397 !delegate_->GetJavaScriptDialogManager(); 3398 3399 if (!suppress_this_message) { 3400 std::string accept_lang = GetContentClient()->browser()-> 3401 GetAcceptLangs(GetBrowserContext()); 3402 dialog_manager_ = delegate_->GetJavaScriptDialogManager(); 3403 dialog_manager_->RunJavaScriptDialog( 3404 this, 3405 frame_url.GetOrigin(), 3406 accept_lang, 3407 javascript_message_type, 3408 message, 3409 default_prompt, 3410 base::Bind(&WebContentsImpl::OnDialogClosed, 3411 base::Unretained(this), 3412 rvh, 3413 reply_msg), 3414 &suppress_this_message); 3415 } 3416 3417 *did_suppress_message = suppress_this_message; 3418 3419 if (suppress_this_message) { 3420 // If we are suppressing messages, just reply as if the user immediately 3421 // pressed "Cancel". 3422 OnDialogClosed(rvh, reply_msg, false, base::string16()); 3423 } 3424 3425 // OnDialogClosed (two lines up) may have caused deletion of this object (see 3426 // http://crbug.com/288961 ). The only safe thing to do here is return. 3427 } 3428 3429 void WebContentsImpl::RunBeforeUnloadConfirm(RenderViewHost* rvh, 3430 const base::string16& message, 3431 bool is_reload, 3432 IPC::Message* reply_msg) { 3433 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(rvh); 3434 if (delegate_) 3435 delegate_->WillRunBeforeUnloadConfirm(); 3436 3437 bool suppress_this_message = 3438 rvhi->is_swapped_out() || 3439 !delegate_ || 3440 delegate_->ShouldSuppressDialogs() || 3441 !delegate_->GetJavaScriptDialogManager(); 3442 if (suppress_this_message) { 3443 // The reply must be sent to the RVH that sent the request. 3444 rvhi->JavaScriptDialogClosed(reply_msg, true, base::string16()); 3445 return; 3446 } 3447 3448 is_showing_before_unload_dialog_ = true; 3449 dialog_manager_ = delegate_->GetJavaScriptDialogManager(); 3450 dialog_manager_->RunBeforeUnloadDialog( 3451 this, message, is_reload, 3452 base::Bind(&WebContentsImpl::OnDialogClosed, base::Unretained(this), rvh, 3453 reply_msg)); 3454 } 3455 3456 bool WebContentsImpl::AddMessageToConsole(int32 level, 3457 const base::string16& message, 3458 int32 line_no, 3459 const base::string16& source_id) { 3460 if (!delegate_) 3461 return false; 3462 return delegate_->AddMessageToConsole(this, level, message, line_no, 3463 source_id); 3464 } 3465 3466 WebPreferences WebContentsImpl::GetWebkitPrefs() { 3467 // We want to base the page config off of the actual URL, rather than the 3468 // virtual URL. 3469 // TODO(nasko): Investigate how to remove the GetActiveEntry usage here, 3470 // as it is deprecated and can be out of sync with GetRenderViewHost(). 3471 GURL url = controller_.GetActiveEntry() 3472 ? controller_.GetActiveEntry()->GetURL() : GURL::EmptyGURL(); 3473 3474 return GetRenderManager()->current_host()->GetWebkitPrefs(url); 3475 } 3476 3477 int WebContentsImpl::CreateSwappedOutRenderView( 3478 SiteInstance* instance) { 3479 return GetRenderManager()->CreateRenderView(instance, MSG_ROUTING_NONE, 3480 true, true); 3481 } 3482 3483 void WebContentsImpl::OnUserGesture() { 3484 // Notify observers. 3485 FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidGetUserGesture()); 3486 3487 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get(); 3488 if (rdh) // NULL in unittests. 3489 rdh->OnUserGesture(this); 3490 } 3491 3492 void WebContentsImpl::OnIgnoredUIEvent() { 3493 // Notify observers. 3494 FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidGetIgnoredUIEvent()); 3495 } 3496 3497 void WebContentsImpl::RendererUnresponsive(RenderViewHost* rvh, 3498 bool is_during_beforeunload, 3499 bool is_during_unload) { 3500 // Don't show hung renderer dialog for a swapped out RVH. 3501 if (rvh != GetRenderViewHost()) 3502 return; 3503 3504 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(rvh); 3505 3506 // Ignore renderer unresponsive event if debugger is attached to the tab 3507 // since the event may be a result of the renderer sitting on a breakpoint. 3508 // See http://crbug.com/65458 3509 if (DevToolsAgentHost::IsDebuggerAttached(this)) 3510 return; 3511 3512 if (is_during_beforeunload || is_during_unload) { 3513 // Hang occurred while firing the beforeunload/unload handler. 3514 // Pretend the handler fired so tab closing continues as if it had. 3515 rvhi->set_sudden_termination_allowed(true); 3516 3517 if (!GetRenderManager()->ShouldCloseTabOnUnresponsiveRenderer()) 3518 return; 3519 3520 // If the tab hangs in the beforeunload/unload handler there's really 3521 // nothing we can do to recover. If the hang is in the beforeunload handler, 3522 // pretend the beforeunload listeners have all fired and allow the delegate 3523 // to continue closing; the user will not have the option of cancelling the 3524 // close. Otherwise, pretend the unload listeners have all fired and close 3525 // the tab. 3526 bool close = true; 3527 if (is_during_beforeunload) { 3528 delegate_->BeforeUnloadFired(this, true, &close); 3529 } 3530 if (close) 3531 Close(rvh); 3532 return; 3533 } 3534 3535 if (!GetRenderViewHostImpl() || !GetRenderViewHostImpl()->IsRenderViewLive()) 3536 return; 3537 3538 if (delegate_) 3539 delegate_->RendererUnresponsive(this); 3540 } 3541 3542 void WebContentsImpl::RendererResponsive(RenderViewHost* render_view_host) { 3543 if (delegate_) 3544 delegate_->RendererResponsive(this); 3545 } 3546 3547 void WebContentsImpl::LoadStateChanged( 3548 const GURL& url, 3549 const net::LoadStateWithParam& load_state, 3550 uint64 upload_position, 3551 uint64 upload_size) { 3552 load_state_ = load_state; 3553 upload_position_ = upload_position; 3554 upload_size_ = upload_size; 3555 load_state_host_ = net::IDNToUnicode(url.host(), 3556 GetContentClient()->browser()->GetAcceptLangs( 3557 GetBrowserContext())); 3558 if (load_state_.state == net::LOAD_STATE_READING_RESPONSE) 3559 SetNotWaitingForResponse(); 3560 if (IsLoading()) { 3561 NotifyNavigationStateChanged(INVALIDATE_TYPE_LOAD | INVALIDATE_TYPE_TAB); 3562 } 3563 } 3564 3565 void WebContentsImpl::WorkerCrashed() { 3566 if (delegate_) 3567 delegate_->WorkerCrashed(this); 3568 } 3569 3570 void WebContentsImpl::BeforeUnloadFiredFromRenderManager( 3571 bool proceed, const base::TimeTicks& proceed_time, 3572 bool* proceed_to_fire_unload) { 3573 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 3574 BeforeUnloadFired(proceed_time)); 3575 if (delegate_) 3576 delegate_->BeforeUnloadFired(this, proceed, proceed_to_fire_unload); 3577 // Note: |this| might be deleted at this point. 3578 } 3579 3580 void WebContentsImpl::RenderProcessGoneFromRenderManager( 3581 RenderViewHost* render_view_host) { 3582 DCHECK(crashed_status_ != base::TERMINATION_STATUS_STILL_RUNNING); 3583 RenderViewTerminated(render_view_host, crashed_status_, crashed_error_code_); 3584 } 3585 3586 void WebContentsImpl::UpdateRenderViewSizeForRenderManager() { 3587 // TODO(brettw) this is a hack. See WebContentsView::SizeContents. 3588 gfx::Size size = GetSizeForNewRenderView(); 3589 // 0x0 isn't a valid window size (minimal window size is 1x1) but it may be 3590 // here during container initialization and normal window size will be set 3591 // later. In case of tab duplication this resizing to 0x0 prevents setting 3592 // normal size later so just ignore it. 3593 if (!size.IsEmpty()) 3594 view_->SizeContents(size); 3595 } 3596 3597 void WebContentsImpl::CancelModalDialogsForRenderManager() { 3598 // We need to cancel modal dialogs when doing a process swap, since the load 3599 // deferrer would prevent us from swapping out. 3600 if (dialog_manager_) 3601 dialog_manager_->CancelActiveAndPendingDialogs(this); 3602 } 3603 3604 void WebContentsImpl::NotifySwappedFromRenderManager(RenderViewHost* old_host, 3605 RenderViewHost* new_host) { 3606 NotifySwapped(old_host, new_host); 3607 3608 // Make sure the visible RVH reflects the new delegate's preferences. 3609 if (delegate_) 3610 view_->SetOverscrollControllerEnabled(delegate_->CanOverscrollContent()); 3611 3612 view_->RenderViewSwappedIn(new_host); 3613 } 3614 3615 int WebContentsImpl::CreateOpenerRenderViewsForRenderManager( 3616 SiteInstance* instance) { 3617 if (!opener_) 3618 return MSG_ROUTING_NONE; 3619 3620 // Recursively create RenderViews for anything else in the opener chain. 3621 return opener_->CreateOpenerRenderViews(instance); 3622 } 3623 3624 int WebContentsImpl::CreateOpenerRenderViews(SiteInstance* instance) { 3625 int opener_route_id = MSG_ROUTING_NONE; 3626 3627 // If this tab has an opener, ensure it has a RenderView in the given 3628 // SiteInstance as well. 3629 if (opener_) 3630 opener_route_id = opener_->CreateOpenerRenderViews(instance); 3631 3632 // If any of the renderers (current, pending, or swapped out) for this 3633 // WebContents has the same SiteInstance, use it. 3634 if (GetRenderManager()->current_host()->GetSiteInstance() == instance) 3635 return GetRenderManager()->current_host()->GetRoutingID(); 3636 3637 if (GetRenderManager()->pending_render_view_host() && 3638 GetRenderManager()->pending_render_view_host()->GetSiteInstance() == 3639 instance) 3640 return GetRenderManager()->pending_render_view_host()->GetRoutingID(); 3641 3642 RenderViewHostImpl* rvh = GetRenderManager()->GetSwappedOutRenderViewHost( 3643 instance); 3644 if (rvh) 3645 return rvh->GetRoutingID(); 3646 3647 // Create a swapped out RenderView in the given SiteInstance if none exists, 3648 // setting its opener to the given route_id. Return the new view's route_id. 3649 return GetRenderManager()->CreateRenderView(instance, opener_route_id, 3650 true, true); 3651 } 3652 3653 NavigationControllerImpl& WebContentsImpl::GetControllerForRenderManager() { 3654 return GetController(); 3655 } 3656 3657 WebUIImpl* WebContentsImpl::CreateWebUIForRenderManager(const GURL& url) { 3658 return static_cast<WebUIImpl*>(CreateWebUI(url)); 3659 } 3660 3661 NavigationEntry* 3662 WebContentsImpl::GetLastCommittedNavigationEntryForRenderManager() { 3663 return controller_.GetLastCommittedEntry(); 3664 } 3665 3666 bool WebContentsImpl::CreateRenderViewForRenderManager( 3667 RenderViewHost* render_view_host, int opener_route_id) { 3668 TRACE_EVENT0("browser", "WebContentsImpl::CreateRenderViewForRenderManager"); 3669 // Can be NULL during tests. 3670 RenderWidgetHostView* rwh_view = view_->CreateViewForWidget(render_view_host); 3671 3672 // Now that the RenderView has been created, we need to tell it its size. 3673 if (rwh_view) 3674 rwh_view->SetSize(GetSizeForNewRenderView()); 3675 3676 // Make sure we use the correct starting page_id in the new RenderView. 3677 UpdateMaxPageIDIfNecessary(render_view_host); 3678 int32 max_page_id = 3679 GetMaxPageIDForSiteInstance(render_view_host->GetSiteInstance()); 3680 3681 if (!static_cast<RenderViewHostImpl*>( 3682 render_view_host)->CreateRenderView(base::string16(), 3683 opener_route_id, 3684 max_page_id)) { 3685 return false; 3686 } 3687 3688 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 3689 // Force a ViewMsg_Resize to be sent, needed to make plugins show up on 3690 // linux. See crbug.com/83941. 3691 if (rwh_view) { 3692 if (RenderWidgetHost* render_widget_host = rwh_view->GetRenderWidgetHost()) 3693 render_widget_host->WasResized(); 3694 } 3695 #endif 3696 3697 return true; 3698 } 3699 3700 #if defined(OS_ANDROID) 3701 base::android::ScopedJavaLocalRef<jobject> 3702 WebContentsImpl::GetJavaWebContents() { 3703 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3704 3705 WebContentsAndroid* web_contents_android = 3706 static_cast<WebContentsAndroid*>(GetUserData(kWebContentsAndroidKey)); 3707 if (!web_contents_android) { 3708 web_contents_android = new WebContentsAndroid(this); 3709 SetUserData(kWebContentsAndroidKey, web_contents_android); 3710 } 3711 return web_contents_android->GetJavaObject(); 3712 } 3713 3714 bool WebContentsImpl::CreateRenderViewForInitialEmptyDocument() { 3715 return CreateRenderViewForRenderManager(GetRenderViewHost(), 3716 MSG_ROUTING_NONE); 3717 } 3718 #endif 3719 3720 void WebContentsImpl::OnDialogClosed(RenderViewHost* rvh, 3721 IPC::Message* reply_msg, 3722 bool success, 3723 const base::string16& user_input) { 3724 if (is_showing_before_unload_dialog_ && !success) { 3725 // If a beforeunload dialog is canceled, we need to stop the throbber from 3726 // spinning, since we forced it to start spinning in Navigate. 3727 DidStopLoading(rvh); 3728 controller_.DiscardNonCommittedEntries(); 3729 3730 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 3731 BeforeUnloadDialogCancelled()); 3732 } 3733 is_showing_before_unload_dialog_ = false; 3734 static_cast<RenderViewHostImpl*>( 3735 rvh)->JavaScriptDialogClosed(reply_msg, success, user_input); 3736 } 3737 3738 void WebContentsImpl::SetEncoding(const std::string& encoding) { 3739 encoding_ = GetContentClient()->browser()-> 3740 GetCanonicalEncodingNameByAliasName(encoding); 3741 } 3742 3743 void WebContentsImpl::CreateViewAndSetSizeForRVH(RenderViewHost* rvh) { 3744 RenderWidgetHostView* rwh_view = view_->CreateViewForWidget(rvh); 3745 // Can be NULL during tests. 3746 if (rwh_view) 3747 rwh_view->SetSize(GetView()->GetContainerSize()); 3748 } 3749 3750 bool WebContentsImpl::IsHidden() { 3751 return capturer_count_ == 0 && !should_normally_be_visible_; 3752 } 3753 3754 RenderFrameHostManager* WebContentsImpl::GetRenderManager() const { 3755 return frame_tree_.root()->render_manager(); 3756 } 3757 3758 RenderViewHostImpl* WebContentsImpl::GetRenderViewHostImpl() { 3759 return static_cast<RenderViewHostImpl*>(GetRenderViewHost()); 3760 } 3761 3762 BrowserPluginGuest* WebContentsImpl::GetBrowserPluginGuest() const { 3763 return browser_plugin_guest_.get(); 3764 } 3765 3766 void WebContentsImpl::SetBrowserPluginGuest(BrowserPluginGuest* guest) { 3767 CHECK(!browser_plugin_guest_); 3768 browser_plugin_guest_.reset(guest); 3769 } 3770 3771 BrowserPluginEmbedder* WebContentsImpl::GetBrowserPluginEmbedder() const { 3772 return browser_plugin_embedder_.get(); 3773 } 3774 3775 BrowserPluginGuestManager* 3776 WebContentsImpl::GetBrowserPluginGuestManager() const { 3777 return static_cast<BrowserPluginGuestManager*>( 3778 GetBrowserContext()->GetUserData( 3779 browser_plugin::kBrowserPluginGuestManagerKeyName)); 3780 } 3781 3782 void WebContentsImpl::ClearPowerSaveBlockers( 3783 RenderViewHost* render_view_host) { 3784 STLDeleteValues(&power_save_blockers_[render_view_host]); 3785 power_save_blockers_.erase(render_view_host); 3786 } 3787 3788 void WebContentsImpl::ClearAllPowerSaveBlockers() { 3789 for (PowerSaveBlockerMap::iterator i(power_save_blockers_.begin()); 3790 i != power_save_blockers_.end(); ++i) 3791 STLDeleteValues(&power_save_blockers_[i->first]); 3792 power_save_blockers_.clear(); 3793 } 3794 3795 gfx::Size WebContentsImpl::GetSizeForNewRenderView() const { 3796 gfx::Size size; 3797 if (delegate_) 3798 size = delegate_->GetSizeForNewRenderView(this); 3799 if (size.IsEmpty()) 3800 size = view_->GetContainerSize(); 3801 return size; 3802 } 3803 3804 void WebContentsImpl::OnFrameRemoved( 3805 RenderViewHostImpl* render_view_host, 3806 int64 frame_id) { 3807 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 3808 FrameDetached(render_view_host, frame_id)); 3809 } 3810 3811 } // namespace content 3812