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