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