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