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