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