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