render_frame_host_impl.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
1// Copyright 2013 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/frame_host/render_frame_host_impl.h"
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/containers/hash_tables.h"
10#include "base/lazy_instance.h"
11#include "base/metrics/histogram.h"
12#include "base/metrics/user_metrics_action.h"
13#include "base/time/time.h"
14#include "content/browser/accessibility/accessibility_mode_helper.h"
15#include "content/browser/accessibility/browser_accessibility_manager.h"
16#include "content/browser/accessibility/browser_accessibility_state_impl.h"
17#include "content/browser/child_process_security_policy_impl.h"
18#include "content/browser/frame_host/cross_process_frame_connector.h"
19#include "content/browser/frame_host/cross_site_transferring_request.h"
20#include "content/browser/frame_host/frame_tree.h"
21#include "content/browser/frame_host/frame_tree_node.h"
22#include "content/browser/frame_host/navigator.h"
23#include "content/browser/frame_host/render_frame_host_delegate.h"
24#include "content/browser/frame_host/render_frame_proxy_host.h"
25#include "content/browser/renderer_host/input/input_router.h"
26#include "content/browser/renderer_host/input/timeout_monitor.h"
27#include "content/browser/renderer_host/render_process_host_impl.h"
28#include "content/browser/renderer_host/render_view_host_impl.h"
29#include "content/browser/renderer_host/render_widget_host_impl.h"
30#include "content/browser/renderer_host/render_widget_host_view_base.h"
31#include "content/browser/transition_request_manager.h"
32#include "content/common/accessibility_messages.h"
33#include "content/common/desktop_notification_messages.h"
34#include "content/common/frame_messages.h"
35#include "content/common/input_messages.h"
36#include "content/common/inter_process_time_ticks_converter.h"
37#include "content/common/platform_notification_messages.h"
38#include "content/common/render_frame_setup.mojom.h"
39#include "content/common/swapped_out_messages.h"
40#include "content/public/browser/ax_event_notification_details.h"
41#include "content/public/browser/browser_accessibility_state.h"
42#include "content/public/browser/browser_thread.h"
43#include "content/public/browser/content_browser_client.h"
44#include "content/public/browser/desktop_notification_delegate.h"
45#include "content/public/browser/render_process_host.h"
46#include "content/public/browser/render_widget_host_view.h"
47#include "content/public/browser/user_metrics.h"
48#include "content/public/common/content_constants.h"
49#include "content/public/common/content_switches.h"
50#include "content/public/common/url_constants.h"
51#include "content/public/common/url_utils.h"
52#include "ui/accessibility/ax_tree.h"
53#include "url/gurl.h"
54
55using base::TimeDelta;
56
57namespace content {
58
59namespace {
60
61// The (process id, routing id) pair that identifies one RenderFrame.
62typedef std::pair<int32, int32> RenderFrameHostID;
63typedef base::hash_map<RenderFrameHostID, RenderFrameHostImpl*>
64    RoutingIDFrameMap;
65base::LazyInstance<RoutingIDFrameMap> g_routing_id_frame_map =
66    LAZY_INSTANCE_INITIALIZER;
67
68class DesktopNotificationDelegateImpl : public DesktopNotificationDelegate {
69 public:
70  DesktopNotificationDelegateImpl(RenderFrameHost* render_frame_host,
71                                  int notification_id)
72      : render_process_id_(render_frame_host->GetProcess()->GetID()),
73        render_frame_id_(render_frame_host->GetRoutingID()),
74        notification_id_(notification_id) {}
75
76  virtual ~DesktopNotificationDelegateImpl() {}
77
78  virtual void NotificationDisplayed() OVERRIDE {
79    RenderFrameHost* rfh =
80        RenderFrameHost::FromID(render_process_id_, render_frame_id_);
81    if (!rfh)
82      return;
83
84    rfh->Send(new DesktopNotificationMsg_PostDisplay(
85        rfh->GetRoutingID(), notification_id_));
86  }
87
88  virtual void NotificationError() OVERRIDE {
89    RenderFrameHost* rfh =
90        RenderFrameHost::FromID(render_process_id_, render_frame_id_);
91    if (!rfh)
92      return;
93
94    rfh->Send(new DesktopNotificationMsg_PostError(
95        rfh->GetRoutingID(), notification_id_));
96  }
97
98  virtual void NotificationClosed(bool by_user) OVERRIDE {
99    RenderFrameHost* rfh =
100        RenderFrameHost::FromID(render_process_id_, render_frame_id_);
101    if (!rfh)
102      return;
103
104    rfh->Send(new DesktopNotificationMsg_PostClose(
105        rfh->GetRoutingID(), notification_id_, by_user));
106    static_cast<RenderFrameHostImpl*>(rfh)->NotificationClosed(
107        notification_id_);
108  }
109
110  virtual void NotificationClick() OVERRIDE {
111    RenderFrameHost* rfh =
112        RenderFrameHost::FromID(render_process_id_, render_frame_id_);
113    if (!rfh)
114      return;
115
116    rfh->Send(new DesktopNotificationMsg_PostClick(
117        rfh->GetRoutingID(), notification_id_));
118  }
119
120 private:
121  int render_process_id_;
122  int render_frame_id_;
123  int notification_id_;
124};
125
126// Translate a WebKit text direction into a base::i18n one.
127base::i18n::TextDirection WebTextDirectionToChromeTextDirection(
128    blink::WebTextDirection dir) {
129  switch (dir) {
130    case blink::WebTextDirectionLeftToRight:
131      return base::i18n::LEFT_TO_RIGHT;
132    case blink::WebTextDirectionRightToLeft:
133      return base::i18n::RIGHT_TO_LEFT;
134    default:
135      NOTREACHED();
136      return base::i18n::UNKNOWN_DIRECTION;
137  }
138}
139
140}  // namespace
141
142RenderFrameHost* RenderFrameHost::FromID(int render_process_id,
143                                         int render_frame_id) {
144  return RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
145}
146
147// static
148RenderFrameHostImpl* RenderFrameHostImpl::FromID(int process_id,
149                                                 int routing_id) {
150  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
151  RoutingIDFrameMap* frames = g_routing_id_frame_map.Pointer();
152  RoutingIDFrameMap::iterator it = frames->find(
153      RenderFrameHostID(process_id, routing_id));
154  return it == frames->end() ? NULL : it->second;
155}
156
157RenderFrameHostImpl::RenderFrameHostImpl(RenderViewHostImpl* render_view_host,
158                                         RenderFrameHostDelegate* delegate,
159                                         FrameTree* frame_tree,
160                                         FrameTreeNode* frame_tree_node,
161                                         int routing_id,
162                                         bool is_swapped_out)
163    : render_view_host_(render_view_host),
164      delegate_(delegate),
165      cross_process_frame_connector_(NULL),
166      render_frame_proxy_host_(NULL),
167      frame_tree_(frame_tree),
168      frame_tree_node_(frame_tree_node),
169      routing_id_(routing_id),
170      is_swapped_out_(is_swapped_out),
171      renderer_initialized_(false),
172      navigations_suspended_(false),
173      weak_ptr_factory_(this) {
174  frame_tree_->RegisterRenderFrameHost(this);
175  GetProcess()->AddRoute(routing_id_, this);
176  g_routing_id_frame_map.Get().insert(std::make_pair(
177      RenderFrameHostID(GetProcess()->GetID(), routing_id_),
178      this));
179
180  if (GetProcess()->GetServiceRegistry()) {
181    RenderFrameSetupPtr setup;
182    GetProcess()->GetServiceRegistry()->ConnectToRemoteService(&setup);
183    mojo::ServiceProviderPtr service_provider;
184    setup->GetServiceProviderForFrame(routing_id_,
185                                      mojo::Get(&service_provider));
186    service_registry_.BindRemoteServiceProvider(
187        service_provider.PassMessagePipe());
188  }
189}
190
191RenderFrameHostImpl::~RenderFrameHostImpl() {
192  GetProcess()->RemoveRoute(routing_id_);
193  g_routing_id_frame_map.Get().erase(
194      RenderFrameHostID(GetProcess()->GetID(), routing_id_));
195
196  if (delegate_)
197    delegate_->RenderFrameDeleted(this);
198
199  // Notify the FrameTree that this RFH is going away, allowing it to shut down
200  // the corresponding RenderViewHost if it is no longer needed.
201  frame_tree_->UnregisterRenderFrameHost(this);
202}
203
204int RenderFrameHostImpl::GetRoutingID() {
205  return routing_id_;
206}
207
208SiteInstance* RenderFrameHostImpl::GetSiteInstance() {
209  return render_view_host_->GetSiteInstance();
210}
211
212RenderProcessHost* RenderFrameHostImpl::GetProcess() {
213  // TODO(nasko): This should return its own process, once we have working
214  // cross-process navigation for subframes.
215  return render_view_host_->GetProcess();
216}
217
218RenderFrameHost* RenderFrameHostImpl::GetParent() {
219  FrameTreeNode* parent_node = frame_tree_node_->parent();
220  if (!parent_node)
221    return NULL;
222  return parent_node->current_frame_host();
223}
224
225const std::string& RenderFrameHostImpl::GetFrameName() {
226  return frame_tree_node_->frame_name();
227}
228
229bool RenderFrameHostImpl::IsCrossProcessSubframe() {
230  FrameTreeNode* parent_node = frame_tree_node_->parent();
231  if (!parent_node)
232    return false;
233  return GetSiteInstance() !=
234      parent_node->current_frame_host()->GetSiteInstance();
235}
236
237GURL RenderFrameHostImpl::GetLastCommittedURL() {
238  return frame_tree_node_->current_url();
239}
240
241gfx::NativeView RenderFrameHostImpl::GetNativeView() {
242  RenderWidgetHostView* view = render_view_host_->GetView();
243  if (!view)
244    return NULL;
245  return view->GetNativeView();
246}
247
248void RenderFrameHostImpl::ExecuteJavaScript(
249    const base::string16& javascript) {
250  Send(new FrameMsg_JavaScriptExecuteRequest(routing_id_,
251                                             javascript,
252                                             0, false));
253}
254
255void RenderFrameHostImpl::ExecuteJavaScript(
256     const base::string16& javascript,
257     const JavaScriptResultCallback& callback) {
258  static int next_id = 1;
259  int key = next_id++;
260  Send(new FrameMsg_JavaScriptExecuteRequest(routing_id_,
261                                             javascript,
262                                             key, true));
263  javascript_callbacks_.insert(std::make_pair(key, callback));
264}
265
266RenderViewHost* RenderFrameHostImpl::GetRenderViewHost() {
267  return render_view_host_;
268}
269
270ServiceRegistry* RenderFrameHostImpl::GetServiceRegistry() {
271  static_cast<RenderProcessHostImpl*>(GetProcess())->EnsureMojoActivated();
272  return &service_registry_;
273}
274
275bool RenderFrameHostImpl::Send(IPC::Message* message) {
276  if (IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart) {
277    return render_view_host_->input_router()->SendInput(
278        make_scoped_ptr(message));
279  }
280
281  // Route IPCs through the RenderFrameProxyHost when in swapped out state.
282  // Note: For subframes in --site-per-process mode, we don't use swapped out
283  // RenderFrameHosts.
284  if (frame_tree_node_->IsMainFrame() && render_view_host_->IsSwappedOut()) {
285    DCHECK(render_frame_proxy_host_);
286    return render_frame_proxy_host_->Send(message);
287  }
288
289  return GetProcess()->Send(message);
290}
291
292bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
293  // Filter out most IPC messages if this renderer is swapped out.
294  // We still want to handle certain ACKs to keep our state consistent.
295  // TODO(nasko): Only check RenderViewHost state, as this object's own state
296  // isn't yet properly updated. Transition this check once the swapped out
297  // state is correct in RenderFrameHost itself.
298  if (render_view_host_->IsSwappedOut()) {
299    if (!SwappedOutMessages::CanHandleWhileSwappedOut(msg)) {
300      // If this is a synchronous message and we decided not to handle it,
301      // we must send an error reply, or else the renderer will be stuck
302      // and won't respond to future requests.
303      if (msg.is_sync()) {
304        IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg);
305        reply->set_reply_error();
306        Send(reply);
307      }
308      // Don't continue looking for someone to handle it.
309      return true;
310    }
311  }
312
313  if (delegate_->OnMessageReceived(this, msg))
314    return true;
315
316  RenderFrameProxyHost* proxy =
317      frame_tree_node_->render_manager()->GetProxyToParent();
318  if (proxy && proxy->cross_process_frame_connector() &&
319      proxy->cross_process_frame_connector()->OnMessageReceived(msg))
320    return true;
321
322  bool handled = true;
323  IPC_BEGIN_MESSAGE_MAP(RenderFrameHostImpl, msg)
324    IPC_MESSAGE_HANDLER(FrameHostMsg_AddMessageToConsole, OnAddMessageToConsole)
325    IPC_MESSAGE_HANDLER(FrameHostMsg_Detach, OnDetach)
326    IPC_MESSAGE_HANDLER(FrameHostMsg_FrameFocused, OnFrameFocused)
327    IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartProvisionalLoadForFrame,
328                        OnDidStartProvisionalLoadForFrame)
329    IPC_MESSAGE_HANDLER(FrameHostMsg_DidFailProvisionalLoadWithError,
330                        OnDidFailProvisionalLoadWithError)
331    IPC_MESSAGE_HANDLER(FrameHostMsg_DidRedirectProvisionalLoad,
332                        OnDidRedirectProvisionalLoad)
333    IPC_MESSAGE_HANDLER(FrameHostMsg_DidFailLoadWithError,
334                        OnDidFailLoadWithError)
335    IPC_MESSAGE_HANDLER_GENERIC(FrameHostMsg_DidCommitProvisionalLoad,
336                                OnNavigate(msg))
337    IPC_MESSAGE_HANDLER(FrameHostMsg_OpenURL, OnOpenURL)
338    IPC_MESSAGE_HANDLER(FrameHostMsg_DocumentOnLoadCompleted,
339                        OnDocumentOnLoadCompleted)
340    IPC_MESSAGE_HANDLER(FrameHostMsg_BeforeUnload_ACK, OnBeforeUnloadACK)
341    IPC_MESSAGE_HANDLER(FrameHostMsg_SwapOut_ACK, OnSwapOutACK)
342    IPC_MESSAGE_HANDLER(FrameHostMsg_ContextMenu, OnContextMenu)
343    IPC_MESSAGE_HANDLER(FrameHostMsg_JavaScriptExecuteResponse,
344                        OnJavaScriptExecuteResponse)
345    IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_RunJavaScriptMessage,
346                                    OnRunJavaScriptMessage)
347    IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_RunBeforeUnloadConfirm,
348                                    OnRunBeforeUnloadConfirm)
349    IPC_MESSAGE_HANDLER(FrameHostMsg_DidAccessInitialDocument,
350                        OnDidAccessInitialDocument)
351    IPC_MESSAGE_HANDLER(FrameHostMsg_DidDisownOpener, OnDidDisownOpener)
352    IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateTitle, OnUpdateTitle)
353    IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateEncoding, OnUpdateEncoding)
354    IPC_MESSAGE_HANDLER(FrameHostMsg_BeginNavigation,
355                        OnBeginNavigation)
356    IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_RequestPermission,
357                        OnRequestPlatformNotificationPermission)
358    IPC_MESSAGE_HANDLER(DesktopNotificationHostMsg_Show,
359                        OnShowDesktopNotification)
360    IPC_MESSAGE_HANDLER(DesktopNotificationHostMsg_Cancel,
361                        OnCancelDesktopNotification)
362    IPC_MESSAGE_HANDLER(FrameHostMsg_TextSurroundingSelectionResponse,
363                        OnTextSurroundingSelectionResponse)
364    IPC_MESSAGE_HANDLER(AccessibilityHostMsg_Events, OnAccessibilityEvents)
365    IPC_MESSAGE_HANDLER(AccessibilityHostMsg_LocationChanges,
366                        OnAccessibilityLocationChanges)
367  IPC_END_MESSAGE_MAP()
368
369  return handled;
370}
371
372void RenderFrameHostImpl::AccessibilitySetFocus(int object_id) {
373  Send(new AccessibilityMsg_SetFocus(routing_id_, object_id));
374}
375
376void RenderFrameHostImpl::AccessibilityDoDefaultAction(int object_id) {
377  Send(new AccessibilityMsg_DoDefaultAction(routing_id_, object_id));
378}
379
380void RenderFrameHostImpl::AccessibilityShowMenu(
381    const gfx::Point& global_point) {
382  RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
383      render_view_host_->GetView());
384  if (view)
385    view->AccessibilityShowMenu(global_point);
386}
387
388void RenderFrameHostImpl::AccessibilityScrollToMakeVisible(
389    int acc_obj_id, const gfx::Rect& subfocus) {
390  Send(new AccessibilityMsg_ScrollToMakeVisible(
391      routing_id_, acc_obj_id, subfocus));
392}
393
394void RenderFrameHostImpl::AccessibilityScrollToPoint(
395    int acc_obj_id, const gfx::Point& point) {
396  Send(new AccessibilityMsg_ScrollToPoint(
397      routing_id_, acc_obj_id, point));
398}
399
400void RenderFrameHostImpl::AccessibilitySetTextSelection(
401    int object_id, int start_offset, int end_offset) {
402  Send(new AccessibilityMsg_SetTextSelection(
403      routing_id_, object_id, start_offset, end_offset));
404}
405
406bool RenderFrameHostImpl::AccessibilityViewHasFocus() const {
407  RenderWidgetHostView* view = render_view_host_->GetView();
408  if (view)
409    return view->HasFocus();
410  return false;
411}
412
413gfx::Rect RenderFrameHostImpl::AccessibilityGetViewBounds() const {
414  RenderWidgetHostView* view = render_view_host_->GetView();
415  if (view)
416    return view->GetViewBounds();
417  return gfx::Rect();
418}
419
420gfx::Point RenderFrameHostImpl::AccessibilityOriginInScreen(
421    const gfx::Rect& bounds) const {
422  RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
423      render_view_host_->GetView());
424  if (view)
425    return view->AccessibilityOriginInScreen(bounds);
426  return gfx::Point();
427}
428
429void RenderFrameHostImpl::AccessibilityHitTest(const gfx::Point& point) {
430  Send(new AccessibilityMsg_HitTest(routing_id_, point));
431}
432
433void RenderFrameHostImpl::AccessibilityFatalError() {
434  Send(new AccessibilityMsg_FatalError(routing_id_));
435  browser_accessibility_manager_.reset(NULL);
436}
437
438gfx::AcceleratedWidget
439    RenderFrameHostImpl::AccessibilityGetAcceleratedWidget() {
440  RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
441      render_view_host_->GetView());
442  if (view)
443    return view->AccessibilityGetAcceleratedWidget();
444  return gfx::kNullAcceleratedWidget;
445}
446
447gfx::NativeViewAccessible
448    RenderFrameHostImpl::AccessibilityGetNativeViewAccessible() {
449  RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
450      render_view_host_->GetView());
451  if (view)
452    return view->AccessibilityGetNativeViewAccessible();
453  return NULL;
454}
455
456bool RenderFrameHostImpl::CreateRenderFrame(int parent_routing_id) {
457  TRACE_EVENT0("frame_host", "RenderFrameHostImpl::CreateRenderFrame");
458  DCHECK(!IsRenderFrameLive()) << "Creating frame twice";
459
460  // The process may (if we're sharing a process with another host that already
461  // initialized it) or may not (we have our own process or the old process
462  // crashed) have been initialized. Calling Init multiple times will be
463  // ignored, so this is safe.
464  if (!GetProcess()->Init())
465    return false;
466
467  DCHECK(GetProcess()->HasConnection());
468
469  renderer_initialized_ = true;
470  Send(new FrameMsg_NewFrame(routing_id_, parent_routing_id));
471
472  return true;
473}
474
475bool RenderFrameHostImpl::IsRenderFrameLive() {
476  return GetProcess()->HasConnection() && renderer_initialized_;
477}
478
479void RenderFrameHostImpl::Init() {
480  GetProcess()->ResumeRequestsForView(routing_id_);
481}
482
483void RenderFrameHostImpl::OnAddMessageToConsole(
484    int32 level,
485    const base::string16& message,
486    int32 line_no,
487    const base::string16& source_id) {
488  if (delegate_->AddMessageToConsole(level, message, line_no, source_id))
489    return;
490
491  // Pass through log level only on WebUI pages to limit console spew.
492  int32 resolved_level =
493      HasWebUIScheme(delegate_->GetMainFrameLastCommittedURL()) ? level : 0;
494
495  if (resolved_level >= ::logging::GetMinLogLevel()) {
496    logging::LogMessage("CONSOLE", line_no, resolved_level).stream() << "\"" <<
497        message << "\", source: " << source_id << " (" << line_no << ")";
498  }
499}
500
501void RenderFrameHostImpl::OnCreateChildFrame(int new_routing_id,
502                                             const std::string& frame_name) {
503  RenderFrameHostImpl* new_frame = frame_tree_->AddFrame(
504      frame_tree_node_, new_routing_id, frame_name);
505  if (delegate_)
506    delegate_->RenderFrameCreated(new_frame);
507}
508
509void RenderFrameHostImpl::OnDetach() {
510  frame_tree_->RemoveFrame(frame_tree_node_);
511}
512
513void RenderFrameHostImpl::OnFrameFocused() {
514  frame_tree_->SetFocusedFrame(frame_tree_node_);
515}
516
517void RenderFrameHostImpl::OnOpenURL(
518    const FrameHostMsg_OpenURL_Params& params) {
519  GURL validated_url(params.url);
520  GetProcess()->FilterURL(false, &validated_url);
521
522  frame_tree_node_->navigator()->RequestOpenURL(
523      this, validated_url, params.referrer, params.disposition,
524      params.should_replace_current_entry, params.user_gesture);
525}
526
527void RenderFrameHostImpl::OnDocumentOnLoadCompleted() {
528  // This message is only sent for top-level frames. TODO(avi): when frame tree
529  // mirroring works correctly, add a check here to enforce it.
530  delegate_->DocumentOnLoadCompleted(this);
531}
532
533void RenderFrameHostImpl::OnDidStartProvisionalLoadForFrame(
534    const GURL& url,
535    bool is_transition_navigation) {
536  frame_tree_node_->navigator()->DidStartProvisionalLoad(
537      this, url, is_transition_navigation);
538}
539
540void RenderFrameHostImpl::OnDidFailProvisionalLoadWithError(
541    const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) {
542  frame_tree_node_->navigator()->DidFailProvisionalLoadWithError(this, params);
543}
544
545void RenderFrameHostImpl::OnDidFailLoadWithError(
546    const GURL& url,
547    int error_code,
548    const base::string16& error_description) {
549  GURL validated_url(url);
550  GetProcess()->FilterURL(false, &validated_url);
551
552  frame_tree_node_->navigator()->DidFailLoadWithError(
553      this, validated_url, error_code, error_description);
554}
555
556void RenderFrameHostImpl::OnDidRedirectProvisionalLoad(
557    int32 page_id,
558    const GURL& source_url,
559    const GURL& target_url) {
560  frame_tree_node_->navigator()->DidRedirectProvisionalLoad(
561      this, page_id, source_url, target_url);
562}
563
564// Called when the renderer navigates.  For every frame loaded, we'll get this
565// notification containing parameters identifying the navigation.
566//
567// Subframes are identified by the page transition type.  For subframes loaded
568// as part of a wider page load, the page_id will be the same as for the top
569// level frame.  If the user explicitly requests a subframe navigation, we will
570// get a new page_id because we need to create a new navigation entry for that
571// action.
572void RenderFrameHostImpl::OnNavigate(const IPC::Message& msg) {
573  // Read the parameters out of the IPC message directly to avoid making another
574  // copy when we filter the URLs.
575  PickleIterator iter(msg);
576  FrameHostMsg_DidCommitProvisionalLoad_Params validated_params;
577  if (!IPC::ParamTraits<FrameHostMsg_DidCommitProvisionalLoad_Params>::
578      Read(&msg, &iter, &validated_params))
579    return;
580
581  // If we're waiting for a cross-site beforeunload ack from this renderer and
582  // we receive a Navigate message from the main frame, then the renderer was
583  // navigating already and sent it before hearing the FrameMsg_Stop message.
584  // We do not want to cancel the pending navigation in this case, since the
585  // old page will soon be stopped.  Instead, treat this as a beforeunload ack
586  // to allow the pending navigation to continue.
587  if (render_view_host_->is_waiting_for_beforeunload_ack_ &&
588      render_view_host_->unload_ack_is_for_cross_site_transition_ &&
589      PageTransitionIsMainFrame(validated_params.transition)) {
590    OnBeforeUnloadACK(true, send_before_unload_start_time_,
591                      base::TimeTicks::Now());
592    return;
593  }
594
595  // If we're waiting for an unload ack from this renderer and we receive a
596  // Navigate message, then the renderer was navigating before it received the
597  // unload request.  It will either respond to the unload request soon or our
598  // timer will expire.  Either way, we should ignore this message, because we
599  // have already committed to closing this renderer.
600  if (render_view_host_->IsWaitingForUnloadACK())
601    return;
602
603  RenderProcessHost* process = GetProcess();
604
605  // Attempts to commit certain off-limits URL should be caught more strictly
606  // than our FilterURL checks below.  If a renderer violates this policy, it
607  // should be killed.
608  if (!CanCommitURL(validated_params.url)) {
609    VLOG(1) << "Blocked URL " << validated_params.url.spec();
610    validated_params.url = GURL(url::kAboutBlankURL);
611    RecordAction(base::UserMetricsAction("CanCommitURL_BlockedAndKilled"));
612    // Kills the process.
613    process->ReceivedBadMessage();
614  }
615
616  // Without this check, an evil renderer can trick the browser into creating
617  // a navigation entry for a banned URL.  If the user clicks the back button
618  // followed by the forward button (or clicks reload, or round-trips through
619  // session restore, etc), we'll think that the browser commanded the
620  // renderer to load the URL and grant the renderer the privileges to request
621  // the URL.  To prevent this attack, we block the renderer from inserting
622  // banned URLs into the navigation controller in the first place.
623  process->FilterURL(false, &validated_params.url);
624  process->FilterURL(true, &validated_params.referrer.url);
625  for (std::vector<GURL>::iterator it(validated_params.redirects.begin());
626      it != validated_params.redirects.end(); ++it) {
627    process->FilterURL(false, &(*it));
628  }
629  process->FilterURL(true, &validated_params.searchable_form_url);
630
631  // Without this check, the renderer can trick the browser into using
632  // filenames it can't access in a future session restore.
633  if (!render_view_host_->CanAccessFilesOfPageState(
634          validated_params.page_state)) {
635    GetProcess()->ReceivedBadMessage();
636    return;
637  }
638
639  frame_tree_node()->navigator()->DidNavigate(this, validated_params);
640}
641
642RenderWidgetHostImpl* RenderFrameHostImpl::GetRenderWidgetHost() {
643  return static_cast<RenderWidgetHostImpl*>(render_view_host_);
644}
645
646int RenderFrameHostImpl::GetEnabledBindings() {
647  return render_view_host_->GetEnabledBindings();
648}
649
650void RenderFrameHostImpl::OnCrossSiteResponse(
651    const GlobalRequestID& global_request_id,
652    scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
653    const std::vector<GURL>& transfer_url_chain,
654    const Referrer& referrer,
655    PageTransition page_transition,
656    bool should_replace_current_entry) {
657  frame_tree_node_->render_manager()->OnCrossSiteResponse(
658      this, global_request_id, cross_site_transferring_request.Pass(),
659      transfer_url_chain, referrer, page_transition,
660      should_replace_current_entry);
661}
662
663void RenderFrameHostImpl::OnDeferredAfterResponseStarted(
664    const GlobalRequestID& global_request_id,
665    const TransitionLayerData& transition_data) {
666  frame_tree_node_->render_manager()->OnDeferredAfterResponseStarted(
667      global_request_id, this);
668
669  if (GetParent() || !delegate_->WillHandleDeferAfterResponseStarted())
670    frame_tree_node_->render_manager()->ResumeResponseDeferredAtStart();
671  else
672    delegate_->DidDeferAfterResponseStarted(transition_data);
673}
674
675void RenderFrameHostImpl::SwapOut(RenderFrameProxyHost* proxy) {
676  // TODO(creis): Move swapped out state to RFH.  Until then, only update it
677  // when swapping out the main frame.
678  if (!GetParent()) {
679    // If this RenderViewHost is not in the default state, it must have already
680    // gone through this, therefore just return.
681    if (render_view_host_->rvh_state_ != RenderViewHostImpl::STATE_DEFAULT)
682      return;
683
684    render_view_host_->SetState(
685        RenderViewHostImpl::STATE_PENDING_SWAP_OUT);
686    render_view_host_->unload_event_monitor_timeout_->Start(
687        base::TimeDelta::FromMilliseconds(
688            RenderViewHostImpl::kUnloadTimeoutMS));
689  }
690
691  set_render_frame_proxy_host(proxy);
692
693  if (render_view_host_->IsRenderViewLive())
694    Send(new FrameMsg_SwapOut(routing_id_, proxy->GetRoutingID()));
695
696  if (!GetParent())
697    delegate_->SwappedOut(this);
698  else
699    set_swapped_out(true);
700}
701
702void RenderFrameHostImpl::OnBeforeUnloadACK(
703    bool proceed,
704    const base::TimeTicks& renderer_before_unload_start_time,
705    const base::TimeTicks& renderer_before_unload_end_time) {
706  // TODO(creis): Support properly beforeunload on subframes. For now just
707  // pretend that the handler ran and allowed the navigation to proceed.
708  if (GetParent()) {
709    render_view_host_->is_waiting_for_beforeunload_ack_ = false;
710    frame_tree_node_->render_manager()->OnBeforeUnloadACK(
711        render_view_host_->unload_ack_is_for_cross_site_transition_, proceed,
712        renderer_before_unload_end_time);
713    return;
714  }
715
716  render_view_host_->decrement_in_flight_event_count();
717  render_view_host_->StopHangMonitorTimeout();
718  // If this renderer navigated while the beforeunload request was in flight, we
719  // may have cleared this state in OnNavigate, in which case we can ignore
720  // this message.
721  // However renderer might also be swapped out but we still want to proceed
722  // with navigation, otherwise it would block future navigations. This can
723  // happen when pending cross-site navigation is canceled by a second one just
724  // before OnNavigate while current RVH is waiting for commit but second
725  // navigation is started from the beginning.
726  if (!render_view_host_->is_waiting_for_beforeunload_ack_) {
727    return;
728  }
729
730  render_view_host_->is_waiting_for_beforeunload_ack_ = false;
731
732  base::TimeTicks before_unload_end_time;
733  if (!send_before_unload_start_time_.is_null() &&
734      !renderer_before_unload_start_time.is_null() &&
735      !renderer_before_unload_end_time.is_null()) {
736    // When passing TimeTicks across process boundaries, we need to compensate
737    // for any skew between the processes. Here we are converting the
738    // renderer's notion of before_unload_end_time to TimeTicks in the browser
739    // process. See comments in inter_process_time_ticks_converter.h for more.
740    InterProcessTimeTicksConverter converter(
741        LocalTimeTicks::FromTimeTicks(send_before_unload_start_time_),
742        LocalTimeTicks::FromTimeTicks(base::TimeTicks::Now()),
743        RemoteTimeTicks::FromTimeTicks(renderer_before_unload_start_time),
744        RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time));
745    LocalTimeTicks browser_before_unload_end_time =
746        converter.ToLocalTimeTicks(
747            RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time));
748    before_unload_end_time = browser_before_unload_end_time.ToTimeTicks();
749
750    // Collect UMA on the inter-process skew.
751    bool is_skew_additive = false;
752    if (converter.IsSkewAdditiveForMetrics()) {
753      is_skew_additive = true;
754      base::TimeDelta skew = converter.GetSkewForMetrics();
755      if (skew >= base::TimeDelta()) {
756        UMA_HISTOGRAM_TIMES(
757            "InterProcessTimeTicks.BrowserBehind_RendererToBrowser", skew);
758      } else {
759        UMA_HISTOGRAM_TIMES(
760            "InterProcessTimeTicks.BrowserAhead_RendererToBrowser", -skew);
761      }
762    }
763    UMA_HISTOGRAM_BOOLEAN(
764        "InterProcessTimeTicks.IsSkewAdditive_RendererToBrowser",
765        is_skew_additive);
766  }
767  frame_tree_node_->render_manager()->OnBeforeUnloadACK(
768      render_view_host_->unload_ack_is_for_cross_site_transition_, proceed,
769      before_unload_end_time);
770
771  // If canceled, notify the delegate to cancel its pending navigation entry.
772  if (!proceed)
773    render_view_host_->GetDelegate()->DidCancelLoading();
774}
775
776void RenderFrameHostImpl::OnSwapOutACK() {
777  OnSwappedOut(false);
778}
779
780void RenderFrameHostImpl::OnSwappedOut(bool timed_out) {
781  // For now, we only need to update the RVH state machine for top-level swaps.
782  if (!GetParent())
783    render_view_host_->OnSwappedOut(timed_out);
784}
785
786void RenderFrameHostImpl::OnContextMenu(const ContextMenuParams& params) {
787  // Validate the URLs in |params|.  If the renderer can't request the URLs
788  // directly, don't show them in the context menu.
789  ContextMenuParams validated_params(params);
790  RenderProcessHost* process = GetProcess();
791
792  // We don't validate |unfiltered_link_url| so that this field can be used
793  // when users want to copy the original link URL.
794  process->FilterURL(true, &validated_params.link_url);
795  process->FilterURL(true, &validated_params.src_url);
796  process->FilterURL(false, &validated_params.page_url);
797  process->FilterURL(true, &validated_params.frame_url);
798
799  delegate_->ShowContextMenu(this, validated_params);
800}
801
802void RenderFrameHostImpl::OnJavaScriptExecuteResponse(
803    int id, const base::ListValue& result) {
804  const base::Value* result_value;
805  if (!result.Get(0, &result_value)) {
806    // Programming error or rogue renderer.
807    NOTREACHED() << "Got bad arguments for OnJavaScriptExecuteResponse";
808    return;
809  }
810
811  std::map<int, JavaScriptResultCallback>::iterator it =
812      javascript_callbacks_.find(id);
813  if (it != javascript_callbacks_.end()) {
814    it->second.Run(result_value);
815    javascript_callbacks_.erase(it);
816  } else {
817    NOTREACHED() << "Received script response for unknown request";
818  }
819}
820
821void RenderFrameHostImpl::OnRunJavaScriptMessage(
822    const base::string16& message,
823    const base::string16& default_prompt,
824    const GURL& frame_url,
825    JavaScriptMessageType type,
826    IPC::Message* reply_msg) {
827  // While a JS message dialog is showing, tabs in the same process shouldn't
828  // process input events.
829  GetProcess()->SetIgnoreInputEvents(true);
830  render_view_host_->StopHangMonitorTimeout();
831  delegate_->RunJavaScriptMessage(this, message, default_prompt,
832                                  frame_url, type, reply_msg);
833}
834
835void RenderFrameHostImpl::OnRunBeforeUnloadConfirm(
836    const GURL& frame_url,
837    const base::string16& message,
838    bool is_reload,
839    IPC::Message* reply_msg) {
840  // While a JS before unload dialog is showing, tabs in the same process
841  // shouldn't process input events.
842  GetProcess()->SetIgnoreInputEvents(true);
843  render_view_host_->StopHangMonitorTimeout();
844  delegate_->RunBeforeUnloadConfirm(this, message, is_reload, reply_msg);
845}
846
847void RenderFrameHostImpl::OnRequestPlatformNotificationPermission(
848    const GURL& origin, int request_id) {
849  base::Callback<void(blink::WebNotificationPermission)> done_callback =
850      base::Bind(
851          &RenderFrameHostImpl::PlatformNotificationPermissionRequestDone,
852          weak_ptr_factory_.GetWeakPtr(),
853          request_id);
854
855  GetContentClient()->browser()->RequestDesktopNotificationPermission(
856      origin, this, done_callback);
857}
858
859void RenderFrameHostImpl::OnShowDesktopNotification(
860    int notification_id,
861    const ShowDesktopNotificationHostMsgParams& params) {
862  scoped_ptr<DesktopNotificationDelegateImpl> delegate(
863      new DesktopNotificationDelegateImpl(this, notification_id));
864
865  base::Closure cancel_callback;
866  GetContentClient()->browser()->ShowDesktopNotification(
867      params,
868      this,
869      delegate.PassAs<DesktopNotificationDelegate>(),
870      &cancel_callback);
871  cancel_notification_callbacks_[notification_id] = cancel_callback;
872}
873
874void RenderFrameHostImpl::OnCancelDesktopNotification(int notification_id) {
875  if (!cancel_notification_callbacks_.count(notification_id)) {
876    NOTREACHED();
877    return;
878  }
879  cancel_notification_callbacks_[notification_id].Run();
880  cancel_notification_callbacks_.erase(notification_id);
881}
882
883void RenderFrameHostImpl::OnTextSurroundingSelectionResponse(
884    const base::string16& content,
885    size_t start_offset,
886    size_t end_offset) {
887  render_view_host_->OnTextSurroundingSelectionResponse(
888      content, start_offset, end_offset);
889}
890
891void RenderFrameHostImpl::OnDidAccessInitialDocument() {
892  delegate_->DidAccessInitialDocument();
893}
894
895void RenderFrameHostImpl::OnDidDisownOpener() {
896  // This message is only sent for top-level frames. TODO(avi): when frame tree
897  // mirroring works correctly, add a check here to enforce it.
898  delegate_->DidDisownOpener(this);
899}
900
901void RenderFrameHostImpl::OnUpdateTitle(
902    int32 page_id,
903    const base::string16& title,
904    blink::WebTextDirection title_direction) {
905  // This message is only sent for top-level frames. TODO(avi): when frame tree
906  // mirroring works correctly, add a check here to enforce it.
907  if (title.length() > kMaxTitleChars) {
908    NOTREACHED() << "Renderer sent too many characters in title.";
909    return;
910  }
911
912  delegate_->UpdateTitle(this, page_id, title,
913                         WebTextDirectionToChromeTextDirection(
914                             title_direction));
915}
916
917void RenderFrameHostImpl::OnUpdateEncoding(const std::string& encoding_name) {
918  // This message is only sent for top-level frames. TODO(avi): when frame tree
919  // mirroring works correctly, add a check here to enforce it.
920  delegate_->UpdateEncoding(this, encoding_name);
921}
922
923void RenderFrameHostImpl::OnBeginNavigation(
924    const FrameHostMsg_BeginNavigation_Params& params) {
925  CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
926      switches::kEnableBrowserSideNavigation));
927  frame_tree_node()->render_manager()->OnBeginNavigation(params);
928}
929
930void RenderFrameHostImpl::OnAccessibilityEvents(
931    const std::vector<AccessibilityHostMsg_EventParams>& params) {
932  RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
933      render_view_host_->GetView());
934
935  AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode();
936  if ((accessibility_mode != AccessibilityModeOff) && view &&
937      RenderViewHostImpl::IsRVHStateActive(render_view_host_->rvh_state())) {
938    if (accessibility_mode & AccessibilityModeFlagPlatform) {
939      GetOrCreateBrowserAccessibilityManager();
940      if (browser_accessibility_manager_)
941        browser_accessibility_manager_->OnAccessibilityEvents(params);
942    }
943
944    std::vector<AXEventNotificationDetails> details;
945    details.reserve(params.size());
946    for (size_t i = 0; i < params.size(); ++i) {
947      const AccessibilityHostMsg_EventParams& param = params[i];
948      AXEventNotificationDetails detail(param.update.node_id_to_clear,
949                                        param.update.nodes,
950                                        param.event_type,
951                                        param.id,
952                                        GetProcess()->GetID(),
953                                        routing_id_);
954      details.push_back(detail);
955    }
956
957    delegate_->AccessibilityEventReceived(details);
958  }
959
960  // Always send an ACK or the renderer can be in a bad state.
961  Send(new AccessibilityMsg_Events_ACK(routing_id_));
962
963  // The rest of this code is just for testing; bail out if we're not
964  // in that mode.
965  if (accessibility_testing_callback_.is_null())
966    return;
967
968  for (size_t i = 0; i < params.size(); i++) {
969    const AccessibilityHostMsg_EventParams& param = params[i];
970    if (static_cast<int>(param.event_type) < 0)
971      continue;
972    if (!ax_tree_for_testing_) {
973      ax_tree_for_testing_.reset(new ui::AXTree(param.update));
974    } else {
975      CHECK(ax_tree_for_testing_->Unserialize(param.update))
976          << ax_tree_for_testing_->error();
977    }
978    accessibility_testing_callback_.Run(param.event_type, param.id);
979  }
980}
981
982void RenderFrameHostImpl::OnAccessibilityLocationChanges(
983    const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
984  RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
985      render_view_host_->GetView());
986  if (view &&
987      RenderViewHostImpl::IsRVHStateActive(render_view_host_->rvh_state())) {
988    AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode();
989    if (accessibility_mode & AccessibilityModeFlagPlatform) {
990      if (!browser_accessibility_manager_) {
991        browser_accessibility_manager_.reset(
992            view->CreateBrowserAccessibilityManager(this));
993      }
994      if (browser_accessibility_manager_)
995        browser_accessibility_manager_->OnLocationChanges(params);
996    }
997    // TODO(aboxhall): send location change events to web contents observers too
998  }
999}
1000
1001void RenderFrameHostImpl::SetPendingShutdown(const base::Closure& on_swap_out) {
1002  render_view_host_->SetPendingShutdown(on_swap_out);
1003}
1004
1005bool RenderFrameHostImpl::CanCommitURL(const GURL& url) {
1006  // TODO(creis): We should also check for WebUI pages here.  Also, when the
1007  // out-of-process iframes implementation is ready, we should check for
1008  // cross-site URLs that are not allowed to commit in this process.
1009
1010  // Give the client a chance to disallow URLs from committing.
1011  return GetContentClient()->browser()->CanCommitURL(GetProcess(), url);
1012}
1013
1014void RenderFrameHostImpl::Navigate(const FrameMsg_Navigate_Params& params) {
1015  TRACE_EVENT0("frame_host", "RenderFrameHostImpl::Navigate");
1016  // Browser plugin guests are not allowed to navigate outside web-safe schemes,
1017  // so do not grant them the ability to request additional URLs.
1018  if (!GetProcess()->IsIsolatedGuest()) {
1019    ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL(
1020        GetProcess()->GetID(), params.url);
1021    if (params.url.SchemeIs(url::kDataScheme) &&
1022        params.base_url_for_data_url.SchemeIs(url::kFileScheme)) {
1023      // If 'data:' is used, and we have a 'file:' base url, grant access to
1024      // local files.
1025      ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL(
1026          GetProcess()->GetID(), params.base_url_for_data_url);
1027    }
1028  }
1029
1030  // Only send the message if we aren't suspended at the start of a cross-site
1031  // request.
1032  if (navigations_suspended_) {
1033    // Shouldn't be possible to have a second navigation while suspended, since
1034    // navigations will only be suspended during a cross-site request.  If a
1035    // second navigation occurs, RenderFrameHostManager will cancel this pending
1036    // RFH and create a new pending RFH.
1037    DCHECK(!suspended_nav_params_.get());
1038    suspended_nav_params_.reset(new FrameMsg_Navigate_Params(params));
1039  } else {
1040    // Get back to a clean state, in case we start a new navigation without
1041    // completing a RVH swap or unload handler.
1042    render_view_host_->SetState(RenderViewHostImpl::STATE_DEFAULT);
1043
1044    Send(new FrameMsg_Navigate(routing_id_, params));
1045  }
1046
1047  // Force the throbber to start. We do this because Blink's "started
1048  // loading" message will be received asynchronously from the UI of the
1049  // browser. But we want to keep the throbber in sync with what's happening
1050  // in the UI. For example, we want to start throbbing immediately when the
1051  // user naivgates even if the renderer is delayed. There is also an issue
1052  // with the throbber starting because the WebUI (which controls whether the
1053  // favicon is displayed) happens synchronously. If the start loading
1054  // messages was asynchronous, then the default favicon would flash in.
1055  //
1056  // Blink doesn't send throb notifications for JavaScript URLs, so we
1057  // don't want to either.
1058  if (!params.url.SchemeIs(url::kJavaScriptScheme))
1059    delegate_->DidStartLoading(this, true);
1060}
1061
1062void RenderFrameHostImpl::NavigateToURL(const GURL& url) {
1063  FrameMsg_Navigate_Params params;
1064  params.page_id = -1;
1065  params.pending_history_list_offset = -1;
1066  params.current_history_list_offset = -1;
1067  params.current_history_list_length = 0;
1068  params.url = url;
1069  params.transition = PAGE_TRANSITION_LINK;
1070  params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1071  params.browser_navigation_start = base::TimeTicks::Now();
1072  Navigate(params);
1073}
1074
1075void RenderFrameHostImpl::Stop() {
1076  Send(new FrameMsg_Stop(routing_id_));
1077}
1078
1079void RenderFrameHostImpl::DispatchBeforeUnload(bool for_cross_site_transition) {
1080  // TODO(creis): Support subframes.
1081  if (!render_view_host_->IsRenderViewLive() || GetParent()) {
1082    // We don't have a live renderer, so just skip running beforeunload.
1083    render_view_host_->is_waiting_for_beforeunload_ack_ = true;
1084    render_view_host_->unload_ack_is_for_cross_site_transition_ =
1085        for_cross_site_transition;
1086    base::TimeTicks now = base::TimeTicks::Now();
1087    OnBeforeUnloadACK(true, now, now);
1088    return;
1089  }
1090
1091  // This may be called more than once (if the user clicks the tab close button
1092  // several times, or if she clicks the tab close button then the browser close
1093  // button), and we only send the message once.
1094  if (render_view_host_->is_waiting_for_beforeunload_ack_) {
1095    // Some of our close messages could be for the tab, others for cross-site
1096    // transitions. We always want to think it's for closing the tab if any
1097    // of the messages were, since otherwise it might be impossible to close
1098    // (if there was a cross-site "close" request pending when the user clicked
1099    // the close button). We want to keep the "for cross site" flag only if
1100    // both the old and the new ones are also for cross site.
1101    render_view_host_->unload_ack_is_for_cross_site_transition_ =
1102        render_view_host_->unload_ack_is_for_cross_site_transition_ &&
1103        for_cross_site_transition;
1104  } else {
1105    // Start the hang monitor in case the renderer hangs in the beforeunload
1106    // handler.
1107    render_view_host_->is_waiting_for_beforeunload_ack_ = true;
1108    render_view_host_->unload_ack_is_for_cross_site_transition_ =
1109        for_cross_site_transition;
1110    // Increment the in-flight event count, to ensure that input events won't
1111    // cancel the timeout timer.
1112    render_view_host_->increment_in_flight_event_count();
1113    render_view_host_->StartHangMonitorTimeout(
1114        TimeDelta::FromMilliseconds(RenderViewHostImpl::kUnloadTimeoutMS));
1115    send_before_unload_start_time_ = base::TimeTicks::Now();
1116    Send(new FrameMsg_BeforeUnload(routing_id_));
1117  }
1118}
1119
1120void RenderFrameHostImpl::ExtendSelectionAndDelete(size_t before,
1121                                                   size_t after) {
1122  Send(new InputMsg_ExtendSelectionAndDelete(routing_id_, before, after));
1123}
1124
1125void RenderFrameHostImpl::JavaScriptDialogClosed(
1126    IPC::Message* reply_msg,
1127    bool success,
1128    const base::string16& user_input,
1129    bool dialog_was_suppressed) {
1130  GetProcess()->SetIgnoreInputEvents(false);
1131  bool is_waiting = render_view_host_->is_waiting_for_beforeunload_ack() ||
1132                    render_view_host_->IsWaitingForUnloadACK();
1133
1134  // If we are executing as part of (before)unload event handling, we don't
1135  // want to use the regular hung_renderer_delay_ms_ if the user has agreed to
1136  // leave the current page. In this case, use the regular timeout value used
1137  // during the (before)unload handling.
1138  if (is_waiting) {
1139    render_view_host_->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(
1140        success ? RenderViewHostImpl::kUnloadTimeoutMS
1141                : render_view_host_->hung_renderer_delay_ms_));
1142  }
1143
1144  FrameHostMsg_RunJavaScriptMessage::WriteReplyParams(reply_msg,
1145                                                      success, user_input);
1146  Send(reply_msg);
1147
1148  // If we are waiting for an unload or beforeunload ack and the user has
1149  // suppressed messages, kill the tab immediately; a page that's spamming
1150  // alerts in onbeforeunload is presumably malicious, so there's no point in
1151  // continuing to run its script and dragging out the process.
1152  // This must be done after sending the reply since RenderView can't close
1153  // correctly while waiting for a response.
1154  if (is_waiting && dialog_was_suppressed)
1155    render_view_host_->delegate_->RendererUnresponsive(
1156        render_view_host_,
1157        render_view_host_->is_waiting_for_beforeunload_ack(),
1158        render_view_host_->IsWaitingForUnloadACK());
1159}
1160
1161void RenderFrameHostImpl::NotificationClosed(int notification_id) {
1162  cancel_notification_callbacks_.erase(notification_id);
1163}
1164
1165void RenderFrameHostImpl::PlatformNotificationPermissionRequestDone(
1166    int request_id, blink::WebNotificationPermission permission) {
1167  Send(new PlatformNotificationMsg_PermissionRequestComplete(
1168      routing_id_, request_id, permission));
1169}
1170
1171void RenderFrameHostImpl::SetAccessibilityMode(AccessibilityMode mode) {
1172  Send(new FrameMsg_SetAccessibilityMode(routing_id_, mode));
1173}
1174
1175void RenderFrameHostImpl::SetAccessibilityCallbackForTesting(
1176    const base::Callback<void(ui::AXEvent, int)>& callback) {
1177  accessibility_testing_callback_ = callback;
1178}
1179
1180const ui::AXTree* RenderFrameHostImpl::GetAXTreeForTesting() {
1181  return ax_tree_for_testing_.get();
1182}
1183
1184BrowserAccessibilityManager*
1185    RenderFrameHostImpl::GetOrCreateBrowserAccessibilityManager() {
1186  RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
1187      render_view_host_->GetView());
1188  if (view &&
1189      !browser_accessibility_manager_) {
1190    browser_accessibility_manager_.reset(
1191        view->CreateBrowserAccessibilityManager(this));
1192  }
1193  return browser_accessibility_manager_.get();
1194}
1195
1196#if defined(OS_WIN)
1197void RenderFrameHostImpl::SetParentNativeViewAccessible(
1198    gfx::NativeViewAccessible accessible_parent) {
1199  RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
1200      render_view_host_->GetView());
1201  if (view)
1202    view->SetParentNativeViewAccessible(accessible_parent);
1203}
1204
1205gfx::NativeViewAccessible
1206RenderFrameHostImpl::GetParentNativeViewAccessible() const {
1207  return delegate_->GetParentNativeViewAccessible();
1208}
1209#endif  // defined(OS_WIN)
1210
1211void RenderFrameHostImpl::ClearPendingTransitionRequestData() {
1212  BrowserThread::PostTask(
1213      BrowserThread::IO,
1214      FROM_HERE,
1215      base::Bind(
1216          &TransitionRequestManager::ClearPendingTransitionRequestData,
1217          base::Unretained(TransitionRequestManager::GetInstance()),
1218          GetProcess()->GetID(),
1219          routing_id_));
1220}
1221
1222void RenderFrameHostImpl::SetNavigationsSuspended(
1223    bool suspend,
1224    const base::TimeTicks& proceed_time) {
1225  // This should only be called to toggle the state.
1226  DCHECK(navigations_suspended_ != suspend);
1227
1228  navigations_suspended_ = suspend;
1229  if (!suspend && suspended_nav_params_) {
1230    // There's navigation message params waiting to be sent. Now that we're not
1231    // suspended anymore, resume navigation by sending them. If we were swapped
1232    // out, we should also stop filtering out the IPC messages now.
1233    render_view_host_->SetState(RenderViewHostImpl::STATE_DEFAULT);
1234
1235    DCHECK(!proceed_time.is_null());
1236    suspended_nav_params_->browser_navigation_start = proceed_time;
1237    Send(new FrameMsg_Navigate(routing_id_, *suspended_nav_params_));
1238    suspended_nav_params_.reset();
1239  }
1240}
1241
1242void RenderFrameHostImpl::CancelSuspendedNavigations() {
1243  // Clear any state if a pending navigation is canceled or preempted.
1244  if (suspended_nav_params_)
1245    suspended_nav_params_.reset();
1246  navigations_suspended_ = false;
1247}
1248
1249}  // namespace content
1250