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