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