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