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