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