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