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