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