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