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