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