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