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