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