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