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