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