render_frame_impl.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
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/renderer/render_frame_impl.h"
6
7#include <map>
8#include <string>
9
10#include "base/auto_reset.h"
11#include "base/command_line.h"
12#include "base/debug/alias.h"
13#include "base/debug/dump_without_crashing.h"
14#include "base/i18n/char_iterator.h"
15#include "base/metrics/histogram.h"
16#include "base/process/kill.h"
17#include "base/process/process.h"
18#include "base/strings/utf_string_conversions.h"
19#include "base/time/time.h"
20#include "content/child/appcache/appcache_dispatcher.h"
21#include "content/child/plugin_messages.h"
22#include "content/child/quota_dispatcher.h"
23#include "content/child/request_extra_data.h"
24#include "content/child/service_worker/service_worker_network_provider.h"
25#include "content/child/service_worker/web_service_worker_provider_impl.h"
26#include "content/child/web_socket_stream_handle_impl.h"
27#include "content/common/clipboard_messages.h"
28#include "content/common/frame_messages.h"
29#include "content/common/input_messages.h"
30#include "content/common/service_worker/service_worker_types.h"
31#include "content/common/socket_stream_handle_data.h"
32#include "content/common/swapped_out_messages.h"
33#include "content/common/view_messages.h"
34#include "content/public/common/bindings_policy.h"
35#include "content/public/common/content_constants.h"
36#include "content/public/common/content_switches.h"
37#include "content/public/common/context_menu_params.h"
38#include "content/public/common/url_constants.h"
39#include "content/public/common/url_utils.h"
40#include "content/public/renderer/content_renderer_client.h"
41#include "content/public/renderer/context_menu_client.h"
42#include "content/public/renderer/document_state.h"
43#include "content/public/renderer/history_item_serialization.h"
44#include "content/public/renderer/navigation_state.h"
45#include "content/public/renderer/render_frame_observer.h"
46#include "content/renderer/accessibility/renderer_accessibility.h"
47#include "content/renderer/browser_plugin/browser_plugin.h"
48#include "content/renderer/browser_plugin/browser_plugin_manager.h"
49#include "content/renderer/child_frame_compositing_helper.h"
50#include "content/renderer/context_menu_params_builder.h"
51#include "content/renderer/dom_automation_controller.h"
52#include "content/renderer/image_loading_helper.h"
53#include "content/renderer/ime_event_guard.h"
54#include "content/renderer/internal_document_state_data.h"
55#include "content/renderer/java/java_bridge_dispatcher.h"
56#include "content/renderer/media/webcontentdecryptionmodule_impl.h"
57#include "content/renderer/npapi/plugin_channel_host.h"
58#include "content/renderer/render_process.h"
59#include "content/renderer/render_thread_impl.h"
60#include "content/renderer/render_view_impl.h"
61#include "content/renderer/render_widget_fullscreen_pepper.h"
62#include "content/renderer/renderer_webapplicationcachehost_impl.h"
63#include "content/renderer/shared_worker_repository.h"
64#include "content/renderer/v8_value_converter_impl.h"
65#include "content/renderer/websharedworker_proxy.h"
66#include "net/base/data_url.h"
67#include "net/base/net_errors.h"
68#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
69#include "net/http/http_util.h"
70#include "third_party/WebKit/public/platform/WebStorageQuotaCallbacks.h"
71#include "third_party/WebKit/public/platform/WebString.h"
72#include "third_party/WebKit/public/platform/WebURL.h"
73#include "third_party/WebKit/public/platform/WebURLError.h"
74#include "third_party/WebKit/public/platform/WebURLResponse.h"
75#include "third_party/WebKit/public/platform/WebVector.h"
76#include "third_party/WebKit/public/web/WebDocument.h"
77#include "third_party/WebKit/public/web/WebFrame.h"
78#include "third_party/WebKit/public/web/WebGlyphCache.h"
79#include "third_party/WebKit/public/web/WebNavigationPolicy.h"
80#include "third_party/WebKit/public/web/WebPlugin.h"
81#include "third_party/WebKit/public/web/WebPluginParams.h"
82#include "third_party/WebKit/public/web/WebRange.h"
83#include "third_party/WebKit/public/web/WebScriptSource.h"
84#include "third_party/WebKit/public/web/WebSearchableFormData.h"
85#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
86#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
87#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
88#include "third_party/WebKit/public/web/WebView.h"
89#include "webkit/child/weburlresponse_extradata_impl.h"
90
91#if defined(ENABLE_PLUGINS)
92#include "content/renderer/npapi/webplugin_impl.h"
93#include "content/renderer/pepper/pepper_browser_connection.h"
94#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
95#include "content/renderer/pepper/pepper_webplugin_impl.h"
96#include "content/renderer/pepper/plugin_module.h"
97#endif
98
99#if defined(ENABLE_WEBRTC)
100#include "content/renderer/media/rtc_peer_connection_handler.h"
101#endif
102
103using blink::WebContextMenuData;
104using blink::WebData;
105using blink::WebDataSource;
106using blink::WebDocument;
107using blink::WebElement;
108using blink::WebFrame;
109using blink::WebHistoryItem;
110using blink::WebHTTPBody;
111using blink::WebNavigationPolicy;
112using blink::WebNavigationType;
113using blink::WebNode;
114using blink::WebPluginParams;
115using blink::WebRange;
116using blink::WebReferrerPolicy;
117using blink::WebScriptSource;
118using blink::WebSearchableFormData;
119using blink::WebSecurityOrigin;
120using blink::WebSecurityPolicy;
121using blink::WebServiceWorkerProvider;
122using blink::WebStorageQuotaCallbacks;
123using blink::WebString;
124using blink::WebURL;
125using blink::WebURLError;
126using blink::WebURLRequest;
127using blink::WebURLResponse;
128using blink::WebUserGestureIndicator;
129using blink::WebVector;
130using blink::WebView;
131using base::Time;
132using base::TimeDelta;
133using webkit_glue::WebURLResponseExtraDataImpl;
134
135namespace content {
136
137namespace {
138
139const size_t kExtraCharsBeforeAndAfterSelection = 100;
140
141typedef std::map<blink::WebFrame*, RenderFrameImpl*> FrameMap;
142base::LazyInstance<FrameMap> g_frame_map = LAZY_INSTANCE_INITIALIZER;
143
144int64 ExtractPostId(const WebHistoryItem& item) {
145  if (item.isNull())
146    return -1;
147
148  if (item.httpBody().isNull())
149    return -1;
150
151  return item.httpBody().identifier();
152}
153
154WebURLResponseExtraDataImpl* GetExtraDataFromResponse(
155    const WebURLResponse& response) {
156  return static_cast<WebURLResponseExtraDataImpl*>(response.extraData());
157}
158
159void GetRedirectChain(WebDataSource* ds, std::vector<GURL>* result) {
160  // Replace any occurrences of swappedout:// with about:blank.
161  const WebURL& blank_url = GURL(kAboutBlankURL);
162  WebVector<WebURL> urls;
163  ds->redirectChain(urls);
164  result->reserve(urls.size());
165  for (size_t i = 0; i < urls.size(); ++i) {
166    if (urls[i] != GURL(kSwappedOutURL))
167      result->push_back(urls[i]);
168    else
169      result->push_back(blank_url);
170  }
171}
172
173NOINLINE static void CrashIntentionally() {
174  // NOTE(shess): Crash directly rather than using NOTREACHED() so
175  // that the signature is easier to triage in crash reports.
176  volatile int* zero = NULL;
177  *zero = 0;
178}
179
180#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
181NOINLINE static void MaybeTriggerAsanError(const GURL& url) {
182  // NOTE(rogerm): We intentionally perform an invalid heap access here in
183  //     order to trigger an Address Sanitizer (ASAN) error report.
184  static const char kCrashDomain[] = "crash";
185  static const char kHeapOverflow[] = "/heap-overflow";
186  static const char kHeapUnderflow[] = "/heap-underflow";
187  static const char kUseAfterFree[] = "/use-after-free";
188  static const int kArraySize = 5;
189
190  if (!url.DomainIs(kCrashDomain, sizeof(kCrashDomain) - 1))
191    return;
192
193  if (!url.has_path())
194    return;
195
196  scoped_ptr<int[]> array(new int[kArraySize]);
197  std::string crash_type(url.path());
198  int dummy = 0;
199  if (crash_type == kHeapOverflow) {
200    dummy = array[kArraySize];
201  } else if (crash_type == kHeapUnderflow ) {
202    dummy = array[-1];
203  } else if (crash_type == kUseAfterFree) {
204    int* dangling = array.get();
205    array.reset();
206    dummy = dangling[kArraySize / 2];
207  }
208
209  // Make sure the assignments to the dummy value aren't optimized away.
210  base::debug::Alias(&dummy);
211}
212#endif  // ADDRESS_SANITIZER || SYZYASAN
213
214static void MaybeHandleDebugURL(const GURL& url) {
215  if (!url.SchemeIs(kChromeUIScheme))
216    return;
217  if (url == GURL(kChromeUICrashURL)) {
218    CrashIntentionally();
219  } else if (url == GURL(kChromeUIKillURL)) {
220    base::KillProcess(base::GetCurrentProcessHandle(), 1, false);
221  } else if (url == GURL(kChromeUIHangURL)) {
222    for (;;) {
223      base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
224    }
225  } else if (url == GURL(kChromeUIShorthangURL)) {
226    base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(20));
227  }
228
229#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
230  MaybeTriggerAsanError(url);
231#endif  // ADDRESS_SANITIZER || SYZYASAN
232}
233
234// Returns false unless this is a top-level navigation.
235static bool IsTopLevelNavigation(WebFrame* frame) {
236  return frame->parent() == NULL;
237}
238
239// Returns false unless this is a top-level navigation that crosses origins.
240static bool IsNonLocalTopLevelNavigation(const GURL& url,
241                                         WebFrame* frame,
242                                         WebNavigationType type,
243                                         bool is_form_post) {
244  if (!IsTopLevelNavigation(frame))
245    return false;
246
247  // Navigations initiated within Webkit are not sent out to the external host
248  // in the following cases.
249  // 1. The url scheme is not http/https
250  // 2. The origin of the url and the opener is the same in which case the
251  //    opener relationship is maintained.
252  // 3. Reloads/form submits/back forward navigations
253  if (!url.SchemeIs(kHttpScheme) && !url.SchemeIs(kHttpsScheme))
254    return false;
255
256  if (type != blink::WebNavigationTypeReload &&
257      type != blink::WebNavigationTypeBackForward && !is_form_post) {
258    // The opener relationship between the new window and the parent allows the
259    // new window to script the parent and vice versa. This is not allowed if
260    // the origins of the two domains are different. This can be treated as a
261    // top level navigation and routed back to the host.
262    blink::WebFrame* opener = frame->opener();
263    if (!opener)
264      return true;
265
266    if (url.GetOrigin() != GURL(opener->document().url()).GetOrigin())
267      return true;
268  }
269  return false;
270}
271
272}  // namespace
273
274static RenderFrameImpl* (*g_create_render_frame_impl)(RenderViewImpl*, int32) =
275    NULL;
276
277// static
278RenderFrameImpl* RenderFrameImpl::Create(RenderViewImpl* render_view,
279                                         int32 routing_id) {
280  DCHECK(routing_id != MSG_ROUTING_NONE);
281
282  if (g_create_render_frame_impl)
283    return g_create_render_frame_impl(render_view, routing_id);
284  else
285    return new RenderFrameImpl(render_view, routing_id);
286}
287
288// static
289RenderFrame* RenderFrame::FromWebFrame(blink::WebFrame* web_frame) {
290  return RenderFrameImpl::FromWebFrame(web_frame);
291}
292
293RenderFrameImpl* RenderFrameImpl::FromWebFrame(blink::WebFrame* web_frame) {
294  FrameMap::iterator iter = g_frame_map.Get().find(web_frame);
295  if (iter != g_frame_map.Get().end())
296    return iter->second;
297  return NULL;
298}
299
300// static
301void RenderFrameImpl::InstallCreateHook(
302    RenderFrameImpl* (*create_render_frame_impl)(RenderViewImpl*, int32)) {
303  CHECK(!g_create_render_frame_impl);
304  g_create_render_frame_impl = create_render_frame_impl;
305}
306
307// RenderFrameImpl ----------------------------------------------------------
308RenderFrameImpl::RenderFrameImpl(RenderViewImpl* render_view, int routing_id)
309    : frame_(NULL),
310      render_view_(render_view->AsWeakPtr()),
311      routing_id_(routing_id),
312      is_loading_(false),
313      is_swapped_out_(false),
314      is_detaching_(false),
315      cookie_jar_(this),
316      selection_text_offset_(0),
317      selection_range_(gfx::Range::InvalidRange()),
318      handling_select_range_(false) {
319  RenderThread::Get()->AddRoute(routing_id_, this);
320
321#if defined(OS_ANDROID)
322  new JavaBridgeDispatcher(this);
323#endif
324}
325
326RenderFrameImpl::~RenderFrameImpl() {
327  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, RenderFrameGone());
328  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, OnDestruct());
329  RenderThread::Get()->RemoveRoute(routing_id_);
330}
331
332void RenderFrameImpl::SetWebFrame(blink::WebFrame* web_frame) {
333  DCHECK(!frame_);
334
335  std::pair<FrameMap::iterator, bool> result = g_frame_map.Get().insert(
336      std::make_pair(web_frame, this));
337  CHECK(result.second) << "Inserting a duplicate item.";
338
339  frame_ = web_frame;
340
341#if defined(ENABLE_PLUGINS)
342  new PepperBrowserConnection(this);
343#endif
344  new SharedWorkerRepository(this);
345
346  if (!frame_->parent())
347    new ImageLoadingHelper(this);
348
349  // We delay calling this until we have the WebFrame so that any observer or
350  // embedder can call GetWebFrame on any RenderFrame.
351  GetContentClient()->renderer()->RenderFrameCreated(this);
352}
353
354RenderWidget* RenderFrameImpl::GetRenderWidget() {
355  return render_view_.get();
356}
357
358#if defined(ENABLE_PLUGINS)
359void RenderFrameImpl::PepperPluginCreated(RendererPpapiHost* host) {
360  FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
361                    DidCreatePepperPlugin(host));
362}
363
364void RenderFrameImpl::PepperDidChangeCursor(
365    PepperPluginInstanceImpl* instance,
366    const blink::WebCursorInfo& cursor) {
367  // Update the cursor appearance immediately if the requesting plugin is the
368  // one which receives the last mouse event. Otherwise, the new cursor won't be
369  // picked up until the plugin gets the next input event. That is bad if, e.g.,
370  // the plugin would like to set an invisible cursor when there isn't any user
371  // input for a while.
372  if (instance == render_view_->pepper_last_mouse_event_target())
373    GetRenderWidget()->didChangeCursor(cursor);
374}
375
376void RenderFrameImpl::PepperDidReceiveMouseEvent(
377    PepperPluginInstanceImpl* instance) {
378  render_view_->set_pepper_last_mouse_event_target(instance);
379}
380
381void RenderFrameImpl::PepperTextInputTypeChanged(
382    PepperPluginInstanceImpl* instance) {
383  if (instance != render_view_->focused_pepper_plugin())
384    return;
385
386  GetRenderWidget()->UpdateTextInputType();
387  if (render_view_->renderer_accessibility())
388    render_view_->renderer_accessibility()->FocusedNodeChanged(WebNode());
389}
390
391void RenderFrameImpl::PepperCaretPositionChanged(
392    PepperPluginInstanceImpl* instance) {
393  if (instance != render_view_->focused_pepper_plugin())
394    return;
395  GetRenderWidget()->UpdateSelectionBounds();
396}
397
398void RenderFrameImpl::PepperCancelComposition(
399    PepperPluginInstanceImpl* instance) {
400  if (instance != render_view_->focused_pepper_plugin())
401    return;
402  Send(new ViewHostMsg_ImeCancelComposition(render_view_->GetRoutingID()));;
403#if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
404  GetRenderWidget()->UpdateCompositionInfo(true);
405#endif
406}
407
408void RenderFrameImpl::PepperSelectionChanged(
409    PepperPluginInstanceImpl* instance) {
410  if (instance != render_view_->focused_pepper_plugin())
411    return;
412  SyncSelectionIfRequired();
413}
414
415RenderWidgetFullscreenPepper* RenderFrameImpl::CreatePepperFullscreenContainer(
416    PepperPluginInstanceImpl* plugin) {
417  GURL active_url;
418  if (render_view_->webview() && render_view_->webview()->mainFrame())
419    active_url = GURL(render_view_->webview()->mainFrame()->document().url());
420  RenderWidgetFullscreenPepper* widget = RenderWidgetFullscreenPepper::Create(
421      GetRenderWidget()->routing_id(), plugin, active_url,
422      GetRenderWidget()->screenInfo());
423  widget->show(blink::WebNavigationPolicyIgnore);
424  return widget;
425}
426
427bool RenderFrameImpl::IsPepperAcceptingCompositionEvents() const {
428  if (!render_view_->focused_pepper_plugin())
429    return false;
430  return render_view_->focused_pepper_plugin()->
431      IsPluginAcceptingCompositionEvents();
432}
433
434void RenderFrameImpl::PluginCrashed(const base::FilePath& plugin_path,
435                                   base::ProcessId plugin_pid) {
436  // TODO(jam): dispatch this IPC in RenderFrameHost and switch to use
437  // routing_id_ as a result.
438  Send(new FrameHostMsg_PluginCrashed(routing_id_, plugin_path, plugin_pid));
439}
440
441void RenderFrameImpl::SimulateImeSetComposition(
442    const base::string16& text,
443    const std::vector<blink::WebCompositionUnderline>& underlines,
444    int selection_start,
445    int selection_end) {
446  render_view_->OnImeSetComposition(
447      text, underlines, selection_start, selection_end);
448}
449
450void RenderFrameImpl::SimulateImeConfirmComposition(
451    const base::string16& text,
452    const gfx::Range& replacement_range) {
453  render_view_->OnImeConfirmComposition(text, replacement_range, false);
454}
455
456
457void RenderFrameImpl::OnImeSetComposition(
458    const base::string16& text,
459    const std::vector<blink::WebCompositionUnderline>& underlines,
460    int selection_start,
461    int selection_end) {
462  // When a PPAPI plugin has focus, we bypass WebKit.
463  if (!IsPepperAcceptingCompositionEvents()) {
464    pepper_composition_text_ = text;
465  } else {
466    // TODO(kinaba) currently all composition events are sent directly to
467    // plugins. Use DOM event mechanism after WebKit is made aware about
468    // plugins that support composition.
469    // The code below mimics the behavior of WebCore::Editor::setComposition.
470
471    // Empty -> nonempty: composition started.
472    if (pepper_composition_text_.empty() && !text.empty()) {
473      render_view_->focused_pepper_plugin()->HandleCompositionStart(
474          base::string16());
475    }
476    // Nonempty -> empty: composition canceled.
477    if (!pepper_composition_text_.empty() && text.empty()) {
478      render_view_->focused_pepper_plugin()->HandleCompositionEnd(
479          base::string16());
480    }
481    pepper_composition_text_ = text;
482    // Nonempty: composition is ongoing.
483    if (!pepper_composition_text_.empty()) {
484      render_view_->focused_pepper_plugin()->HandleCompositionUpdate(
485          pepper_composition_text_, underlines, selection_start,
486          selection_end);
487    }
488  }
489}
490
491void RenderFrameImpl::OnImeConfirmComposition(
492    const base::string16& text,
493    const gfx::Range& replacement_range,
494    bool keep_selection) {
495  // When a PPAPI plugin has focus, we bypass WebKit.
496  // Here, text.empty() has a special meaning. It means to commit the last
497  // update of composition text (see
498  // RenderWidgetHost::ImeConfirmComposition()).
499  const base::string16& last_text = text.empty() ? pepper_composition_text_
500                                                 : text;
501
502  // last_text is empty only when both text and pepper_composition_text_ is.
503  // Ignore it.
504  if (last_text.empty())
505    return;
506
507  if (!IsPepperAcceptingCompositionEvents()) {
508    base::i18n::UTF16CharIterator iterator(&last_text);
509    int32 i = 0;
510    while (iterator.Advance()) {
511      blink::WebKeyboardEvent char_event;
512      char_event.type = blink::WebInputEvent::Char;
513      char_event.timeStampSeconds = base::Time::Now().ToDoubleT();
514      char_event.modifiers = 0;
515      char_event.windowsKeyCode = last_text[i];
516      char_event.nativeKeyCode = last_text[i];
517
518      const int32 char_start = i;
519      for (; i < iterator.array_pos(); ++i) {
520        char_event.text[i - char_start] = last_text[i];
521        char_event.unmodifiedText[i - char_start] = last_text[i];
522      }
523
524      if (GetRenderWidget()->webwidget())
525        GetRenderWidget()->webwidget()->handleInputEvent(char_event);
526    }
527  } else {
528    // Mimics the order of events sent by WebKit.
529    // See WebCore::Editor::setComposition() for the corresponding code.
530    render_view_->focused_pepper_plugin()->HandleCompositionEnd(last_text);
531    render_view_->focused_pepper_plugin()->HandleTextInput(last_text);
532  }
533  pepper_composition_text_.clear();
534}
535
536#endif  // ENABLE_PLUGINS
537
538bool RenderFrameImpl::Send(IPC::Message* message) {
539  if (is_detaching_ ||
540      ((is_swapped_out_ || render_view_->is_swapped_out()) &&
541       !SwappedOutMessages::CanSendWhileSwappedOut(message))) {
542    delete message;
543    return false;
544  }
545
546  return RenderThread::Get()->Send(message);
547}
548
549bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) {
550  ObserverListBase<RenderFrameObserver>::Iterator it(observers_);
551  RenderFrameObserver* observer;
552  while ((observer = it.GetNext()) != NULL) {
553    if (observer->OnMessageReceived(msg))
554      return true;
555  }
556
557  bool handled = true;
558  bool msg_is_ok = true;
559  IPC_BEGIN_MESSAGE_MAP_EX(RenderFrameImpl, msg, msg_is_ok)
560    IPC_MESSAGE_HANDLER(FrameMsg_Navigate, OnNavigate)
561    IPC_MESSAGE_HANDLER(FrameMsg_BeforeUnload, OnBeforeUnload)
562    IPC_MESSAGE_HANDLER(FrameMsg_SwapOut, OnSwapOut)
563    IPC_MESSAGE_HANDLER(FrameMsg_BuffersSwapped, OnBuffersSwapped)
564    IPC_MESSAGE_HANDLER_GENERIC(FrameMsg_CompositorFrameSwapped,
565                                OnCompositorFrameSwapped(msg))
566    IPC_MESSAGE_HANDLER(FrameMsg_ChildFrameProcessGone, OnChildFrameProcessGone)
567    IPC_MESSAGE_HANDLER(FrameMsg_ContextMenuClosed, OnContextMenuClosed)
568    IPC_MESSAGE_HANDLER(FrameMsg_CustomContextMenuAction,
569                        OnCustomContextMenuAction)
570    IPC_MESSAGE_HANDLER(InputMsg_Undo, OnUndo)
571    IPC_MESSAGE_HANDLER(InputMsg_Redo, OnRedo)
572    IPC_MESSAGE_HANDLER(InputMsg_Cut, OnCut)
573    IPC_MESSAGE_HANDLER(InputMsg_Copy, OnCopy)
574    IPC_MESSAGE_HANDLER(InputMsg_Paste, OnPaste)
575    IPC_MESSAGE_HANDLER(InputMsg_PasteAndMatchStyle, OnPasteAndMatchStyle)
576    IPC_MESSAGE_HANDLER(InputMsg_Delete, OnDelete)
577    IPC_MESSAGE_HANDLER(InputMsg_SelectAll, OnSelectAll)
578    IPC_MESSAGE_HANDLER(InputMsg_SelectRange, OnSelectRange)
579    IPC_MESSAGE_HANDLER(InputMsg_Unselect, OnUnselect)
580    IPC_MESSAGE_HANDLER(FrameMsg_CSSInsertRequest, OnCSSInsertRequest)
581    IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequest,
582                        OnJavaScriptExecuteRequest)
583    IPC_MESSAGE_HANDLER(FrameMsg_SetEditableSelectionOffsets,
584                        OnSetEditableSelectionOffsets)
585    IPC_MESSAGE_HANDLER(FrameMsg_SetCompositionFromExistingText,
586                        OnSetCompositionFromExistingText)
587    IPC_MESSAGE_HANDLER(FrameMsg_ExtendSelectionAndDelete,
588                        OnExtendSelectionAndDelete)
589#if defined(OS_MACOSX)
590    IPC_MESSAGE_HANDLER(InputMsg_CopyToFindPboard, OnCopyToFindPboard)
591#endif
592    IPC_MESSAGE_HANDLER(FrameMsg_Reload, OnReload)
593  IPC_END_MESSAGE_MAP_EX()
594
595  if (!msg_is_ok) {
596    // The message had a handler, but its deserialization failed.
597    // Kill the renderer to avoid potential spoofing attacks.
598    CHECK(false) << "Unable to deserialize message in RenderFrameImpl.";
599  }
600
601  return handled;
602}
603
604void RenderFrameImpl::OnNavigate(const FrameMsg_Navigate_Params& params) {
605  MaybeHandleDebugURL(params.url);
606  if (!render_view_->webview())
607    return;
608
609  render_view_->OnNavigate(params);
610
611  bool is_reload = RenderViewImpl::IsReload(params);
612  WebURLRequest::CachePolicy cache_policy =
613      WebURLRequest::UseProtocolCachePolicy;
614
615  // If this is a stale back/forward (due to a recent navigation the browser
616  // didn't know about), ignore it.
617  if (render_view_->IsBackForwardToStaleEntry(params, is_reload))
618    return;
619
620  // Swap this renderer back in if necessary.
621  if (render_view_->is_swapped_out_) {
622    // We marked the view as hidden when swapping the view out, so be sure to
623    // reset the visibility state before navigating to the new URL.
624    render_view_->webview()->setVisibilityState(
625        render_view_->visibilityState(), false);
626
627    // If this is an attempt to reload while we are swapped out, we should not
628    // reload swappedout://, but the previous page, which is stored in
629    // params.state.  Setting is_reload to false will treat this like a back
630    // navigation to accomplish that.
631    is_reload = false;
632    cache_policy = WebURLRequest::ReloadIgnoringCacheData;
633
634    // We refresh timezone when a view is swapped in since timezone
635    // can get out of sync when the system timezone is updated while
636    // the view is swapped out.
637    RenderThreadImpl::NotifyTimezoneChange();
638
639    render_view_->SetSwappedOut(false);
640    is_swapped_out_ = false;
641  }
642
643  if (params.should_clear_history_list) {
644    CHECK_EQ(params.pending_history_list_offset, -1);
645    CHECK_EQ(params.current_history_list_offset, -1);
646    CHECK_EQ(params.current_history_list_length, 0);
647  }
648  render_view_->history_list_offset_ = params.current_history_list_offset;
649  render_view_->history_list_length_ = params.current_history_list_length;
650  if (render_view_->history_list_length_ >= 0) {
651    render_view_->history_page_ids_.resize(
652        render_view_->history_list_length_, -1);
653  }
654  if (params.pending_history_list_offset >= 0 &&
655      params.pending_history_list_offset < render_view_->history_list_length_) {
656    render_view_->history_page_ids_[params.pending_history_list_offset] =
657        params.page_id;
658  }
659
660  GetContentClient()->SetActiveURL(params.url);
661
662  WebFrame* frame = frame_;
663  if (!params.frame_to_navigate.empty()) {
664    // TODO(nasko): Move this lookup to the browser process.
665    frame = render_view_->webview()->findFrameByName(
666        WebString::fromUTF8(params.frame_to_navigate));
667    CHECK(frame) << "Invalid frame name passed: " << params.frame_to_navigate;
668  }
669
670  if (is_reload && frame->currentHistoryItem().isNull()) {
671    // We cannot reload if we do not have any history state.  This happens, for
672    // example, when recovering from a crash.
673    is_reload = false;
674    cache_policy = WebURLRequest::ReloadIgnoringCacheData;
675  }
676
677  render_view_->pending_navigation_params_.reset(
678      new FrameMsg_Navigate_Params(params));
679
680  // If we are reloading, then WebKit will use the history state of the current
681  // page, so we should just ignore any given history state.  Otherwise, if we
682  // have history state, then we need to navigate to it, which corresponds to a
683  // back/forward navigation event.
684  if (is_reload) {
685    bool reload_original_url =
686        (params.navigation_type ==
687            FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL);
688    bool ignore_cache = (params.navigation_type ==
689                             FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE);
690
691    if (reload_original_url)
692      frame->reloadWithOverrideURL(params.url, true);
693    else
694      frame->reload(ignore_cache);
695  } else if (params.page_state.IsValid()) {
696    // We must know the page ID of the page we are navigating back to.
697    DCHECK_NE(params.page_id, -1);
698    WebHistoryItem item = PageStateToHistoryItem(params.page_state);
699    if (!item.isNull()) {
700      // Ensure we didn't save the swapped out URL in UpdateState, since the
701      // browser should never be telling us to navigate to swappedout://.
702      CHECK(item.urlString() != WebString::fromUTF8(kSwappedOutURL));
703      frame->loadHistoryItem(item, cache_policy);
704    }
705  } else if (!params.base_url_for_data_url.is_empty()) {
706    // A loadData request with a specified base URL.
707    std::string mime_type, charset, data;
708    if (net::DataURL::Parse(params.url, &mime_type, &charset, &data)) {
709      frame->loadData(
710          WebData(data.c_str(), data.length()),
711          WebString::fromUTF8(mime_type),
712          WebString::fromUTF8(charset),
713          params.base_url_for_data_url,
714          params.history_url_for_data_url,
715          false);
716    } else {
717      CHECK(false) <<
718          "Invalid URL passed: " << params.url.possibly_invalid_spec();
719    }
720  } else {
721    // Navigate to the given URL.
722    WebURLRequest request(params.url);
723
724    // A session history navigation should have been accompanied by state.
725    CHECK_EQ(params.page_id, -1);
726
727    if (frame->isViewSourceModeEnabled())
728      request.setCachePolicy(WebURLRequest::ReturnCacheDataElseLoad);
729
730    if (params.referrer.url.is_valid()) {
731      WebString referrer = WebSecurityPolicy::generateReferrerHeader(
732          params.referrer.policy,
733          params.url,
734          WebString::fromUTF8(params.referrer.url.spec()));
735      if (!referrer.isEmpty())
736        request.setHTTPReferrer(referrer, params.referrer.policy);
737    }
738
739    if (!params.extra_headers.empty()) {
740      for (net::HttpUtil::HeadersIterator i(params.extra_headers.begin(),
741                                            params.extra_headers.end(), "\n");
742           i.GetNext(); ) {
743        request.addHTTPHeaderField(WebString::fromUTF8(i.name()),
744                                   WebString::fromUTF8(i.values()));
745      }
746    }
747
748    if (params.is_post) {
749      request.setHTTPMethod(WebString::fromUTF8("POST"));
750
751      // Set post data.
752      WebHTTPBody http_body;
753      http_body.initialize();
754      const char* data = NULL;
755      if (params.browser_initiated_post_data.size()) {
756        data = reinterpret_cast<const char*>(
757            &params.browser_initiated_post_data.front());
758      }
759      http_body.appendData(
760          WebData(data, params.browser_initiated_post_data.size()));
761      request.setHTTPBody(http_body);
762    }
763
764    frame->loadRequest(request);
765
766    // If this is a cross-process navigation, the browser process will send
767    // along the proper navigation start value.
768    if (!params.browser_navigation_start.is_null() &&
769        frame->provisionalDataSource()) {
770      // browser_navigation_start is likely before this process existed, so we
771      // can't use InterProcessTimeTicksConverter. Instead, the best we can do
772      // is just ensure we don't report a bogus value in the future.
773      base::TimeTicks navigation_start = std::min(
774          base::TimeTicks::Now(), params.browser_navigation_start);
775      double navigation_start_seconds =
776          (navigation_start - base::TimeTicks()).InSecondsF();
777      frame->provisionalDataSource()->setNavigationStartTime(
778          navigation_start_seconds);
779    }
780  }
781
782  // In case LoadRequest failed before DidCreateDataSource was called.
783  render_view_->pending_navigation_params_.reset();
784}
785
786void RenderFrameImpl::OnBeforeUnload() {
787  // TODO(creis): Right now, this is only called on the main frame.  Make the
788  // browser process send dispatchBeforeUnloadEvent to every frame that needs
789  // it.
790  CHECK(!frame_->parent());
791
792  base::TimeTicks before_unload_start_time = base::TimeTicks::Now();
793  bool proceed = frame_->dispatchBeforeUnloadEvent();
794  base::TimeTicks before_unload_end_time = base::TimeTicks::Now();
795  Send(new FrameHostMsg_BeforeUnload_ACK(routing_id_, proceed,
796                                         before_unload_start_time,
797                                         before_unload_end_time));
798}
799
800void RenderFrameImpl::OnSwapOut() {
801  // Only run unload if we're not swapped out yet, but send the ack either way.
802  if (!is_swapped_out_ || !render_view_->is_swapped_out_) {
803    // Swap this RenderFrame out so the frame can navigate to a page rendered by
804    // a different process.  This involves running the unload handler and
805    // clearing the page.  Once WasSwappedOut is called, we also allow this
806    // process to exit if there are no other active RenderFrames in it.
807
808    // Send an UpdateState message before we get swapped out.
809    render_view_->SyncNavigationState();
810
811    // Synchronously run the unload handler before sending the ACK.
812    // TODO(creis): Call dispatchUnloadEvent unconditionally here to support
813    // unload on subframes as well.
814    if (!frame_->parent())
815      frame_->dispatchUnloadEvent();
816
817    // Swap out and stop sending any IPC messages that are not ACKs.
818    if (!frame_->parent())
819      render_view_->SetSwappedOut(true);
820    is_swapped_out_ = true;
821
822    // Now that we're swapped out and filtering IPC messages, stop loading to
823    // ensure that no other in-progress navigation continues.  We do this here
824    // to avoid sending a DidStopLoading message to the browser process.
825    // TODO(creis): Should we be stopping all frames here and using
826    // StopAltErrorPageFetcher with RenderView::OnStop, or just stopping this
827    // frame?
828    if (!frame_->parent())
829      render_view_->OnStop();
830    else
831      frame_->stopLoading();
832
833    // Let subframes know that the frame is now rendered remotely, for the
834    // purposes of compositing and input events.
835    if (frame_->parent())
836      frame_->setIsRemote(true);
837
838    // Replace the page with a blank dummy URL. The unload handler will not be
839    // run a second time, thanks to a check in FrameLoader::stopLoading.
840    // TODO(creis): Need to add a better way to do this that avoids running the
841    // beforeunload handler. For now, we just run it a second time silently.
842    render_view_->NavigateToSwappedOutURL(frame_);
843
844    if (frame_->parent())
845      render_view_->RegisterSwappedOutChildFrame(this);
846
847    // Let WebKit know that this view is hidden so it can drop resources and
848    // stop compositing.
849    // TODO(creis): Support this for subframes as well.
850    if (!frame_->parent()) {
851      render_view_->webview()->setVisibilityState(
852          blink::WebPageVisibilityStateHidden, false);
853    }
854  }
855
856  // It is now safe to show modal dialogs again.
857  // TODO(creis): Deal with modal dialogs from subframes.
858  if (!frame_->parent())
859    render_view_->suppress_dialogs_until_swap_out_ = false;
860
861  Send(new FrameHostMsg_SwapOut_ACK(routing_id_));
862}
863
864void RenderFrameImpl::OnBuffersSwapped(
865    const FrameMsg_BuffersSwapped_Params& params) {
866  if (!compositing_helper_.get()) {
867    compositing_helper_ =
868        ChildFrameCompositingHelper::CreateCompositingHelperForRenderFrame(
869            frame_, this, routing_id_);
870    compositing_helper_->EnableCompositing(true);
871  }
872  compositing_helper_->OnBuffersSwapped(
873      params.size,
874      params.mailbox,
875      params.gpu_route_id,
876      params.gpu_host_id,
877      render_view_->GetWebView()->deviceScaleFactor());
878}
879
880void RenderFrameImpl::OnCompositorFrameSwapped(const IPC::Message& message) {
881  FrameMsg_CompositorFrameSwapped::Param param;
882  if (!FrameMsg_CompositorFrameSwapped::Read(&message, &param))
883    return;
884  scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
885  param.a.frame.AssignTo(frame.get());
886
887  if (!compositing_helper_.get()) {
888    compositing_helper_ =
889        ChildFrameCompositingHelper::CreateCompositingHelperForRenderFrame(
890            frame_, this, routing_id_);
891    compositing_helper_->EnableCompositing(true);
892  }
893  compositing_helper_->OnCompositorFrameSwapped(frame.Pass(),
894                                                param.a.producing_route_id,
895                                                param.a.output_surface_id,
896                                                param.a.producing_host_id);
897}
898
899void RenderFrameImpl::OnContextMenuClosed(
900    const CustomContextMenuContext& custom_context) {
901  if (custom_context.request_id) {
902    // External request, should be in our map.
903    ContextMenuClient* client =
904        pending_context_menus_.Lookup(custom_context.request_id);
905    if (client) {
906      client->OnMenuClosed(custom_context.request_id);
907      pending_context_menus_.Remove(custom_context.request_id);
908    }
909  } else {
910    // Internal request, forward to WebKit.
911    context_menu_node_.reset();
912  }
913}
914
915void RenderFrameImpl::OnCustomContextMenuAction(
916    const CustomContextMenuContext& custom_context,
917    unsigned action) {
918  if (custom_context.request_id) {
919    // External context menu request, look in our map.
920    ContextMenuClient* client =
921        pending_context_menus_.Lookup(custom_context.request_id);
922    if (client)
923      client->OnMenuAction(custom_context.request_id, action);
924  } else {
925    // Internal request, forward to WebKit.
926    render_view_->webview()->performCustomContextMenuAction(action);
927  }
928}
929
930void RenderFrameImpl::OnUndo() {
931  frame_->executeCommand(WebString::fromUTF8("Undo"), GetFocusedElement());
932}
933
934void RenderFrameImpl::OnRedo() {
935  frame_->executeCommand(WebString::fromUTF8("Redo"), GetFocusedElement());
936}
937
938void RenderFrameImpl::OnCut() {
939  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
940  frame_->executeCommand(WebString::fromUTF8("Cut"), GetFocusedElement());
941}
942
943void RenderFrameImpl::OnCopy() {
944  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
945  WebNode current_node = context_menu_node_.isNull() ?
946      GetFocusedElement() : context_menu_node_;
947  frame_->executeCommand(WebString::fromUTF8("Copy"), current_node);
948}
949
950void RenderFrameImpl::OnPaste() {
951  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
952  frame_->executeCommand(WebString::fromUTF8("Paste"), GetFocusedElement());
953}
954
955void RenderFrameImpl::OnPasteAndMatchStyle() {
956  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
957  frame_->executeCommand(
958      WebString::fromUTF8("PasteAndMatchStyle"), GetFocusedElement());
959}
960
961#if defined(OS_MACOSX)
962void RenderFrameImpl::OnCopyToFindPboard() {
963  // Since the find pasteboard supports only plain text, this can be simpler
964  // than the |OnCopy()| case.
965  if (frame_->hasSelection()) {
966    base::string16 selection = frame_->selectionAsText();
967    RenderThread::Get()->Send(
968        new ClipboardHostMsg_FindPboardWriteStringAsync(selection));
969  }
970}
971#endif
972
973void RenderFrameImpl::OnDelete() {
974  frame_->executeCommand(WebString::fromUTF8("Delete"), GetFocusedElement());
975}
976
977void RenderFrameImpl::OnSelectAll() {
978  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
979  frame_->executeCommand(WebString::fromUTF8("SelectAll"), GetFocusedElement());
980}
981
982void RenderFrameImpl::OnSelectRange(const gfx::Point& start,
983                                    const gfx::Point& end) {
984  // This IPC is dispatched by RenderWidgetHost, so use its routing id.
985  Send(new ViewHostMsg_SelectRange_ACK(GetRenderWidget()->routing_id()));
986
987  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
988  frame_->selectRange(start, end);
989}
990
991void RenderFrameImpl::OnUnselect() {
992  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
993  frame_->executeCommand(WebString::fromUTF8("Unselect"), GetFocusedElement());
994}
995
996void RenderFrameImpl::OnCSSInsertRequest(const std::string& css) {
997  frame_->document().insertStyleSheet(WebString::fromUTF8(css));
998}
999
1000void RenderFrameImpl::OnJavaScriptExecuteRequest(
1001    const base::string16& jscript,
1002    int id,
1003    bool notify_result) {
1004  TRACE_EVENT_INSTANT0("test_tracing", "OnJavaScriptExecuteRequest",
1005                       TRACE_EVENT_SCOPE_THREAD);
1006
1007  v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
1008  v8::Handle<v8::Value> result =
1009      frame_->executeScriptAndReturnValue(WebScriptSource(jscript));
1010  if (notify_result) {
1011    base::ListValue list;
1012    if (!result.IsEmpty()) {
1013      v8::Local<v8::Context> context = frame_->mainWorldScriptContext();
1014      v8::Context::Scope context_scope(context);
1015      V8ValueConverterImpl converter;
1016      converter.SetDateAllowed(true);
1017      converter.SetRegExpAllowed(true);
1018      base::Value* result_value = converter.FromV8Value(result, context);
1019      list.Set(0, result_value ? result_value : base::Value::CreateNullValue());
1020    } else {
1021      list.Set(0, base::Value::CreateNullValue());
1022    }
1023    Send(new FrameHostMsg_JavaScriptExecuteResponse(routing_id_, id, list));
1024  }
1025}
1026
1027void RenderFrameImpl::OnSetEditableSelectionOffsets(int start, int end) {
1028  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
1029  if (!GetRenderWidget()->ShouldHandleImeEvent())
1030    return;
1031  ImeEventGuard guard(GetRenderWidget());
1032  frame_->setEditableSelectionOffsets(start, end);
1033}
1034
1035void RenderFrameImpl::OnSetCompositionFromExistingText(
1036    int start, int end,
1037    const std::vector<blink::WebCompositionUnderline>& underlines) {
1038  if (!GetRenderWidget()->ShouldHandleImeEvent())
1039    return;
1040  ImeEventGuard guard(GetRenderWidget());
1041  frame_->setCompositionFromExistingText(start, end, underlines);
1042}
1043
1044void RenderFrameImpl::OnExtendSelectionAndDelete(int before, int after) {
1045  if (!GetRenderWidget()->ShouldHandleImeEvent())
1046    return;
1047  ImeEventGuard guard(GetRenderWidget());
1048  frame_->extendSelectionAndDelete(before, after);
1049}
1050
1051
1052void RenderFrameImpl::OnReload(bool ignore_cache) {
1053  frame_->reload(ignore_cache);
1054}
1055
1056bool RenderFrameImpl::ShouldUpdateSelectionTextFromContextMenuParams(
1057    const base::string16& selection_text,
1058    size_t selection_text_offset,
1059    const gfx::Range& selection_range,
1060    const ContextMenuParams& params) {
1061  base::string16 trimmed_selection_text;
1062  if (!selection_text.empty() && !selection_range.is_empty()) {
1063    const int start = selection_range.GetMin() - selection_text_offset;
1064    const size_t length = selection_range.length();
1065    if (start >= 0 && start + length <= selection_text.length()) {
1066      base::TrimWhitespace(selection_text.substr(start, length), base::TRIM_ALL,
1067                           &trimmed_selection_text);
1068    }
1069  }
1070  base::string16 trimmed_params_text;
1071  base::TrimWhitespace(params.selection_text, base::TRIM_ALL,
1072                       &trimmed_params_text);
1073  return trimmed_params_text != trimmed_selection_text;
1074}
1075
1076void RenderFrameImpl::DidCommitCompositorFrame() {
1077  if (compositing_helper_)
1078    compositing_helper_->DidCommitCompositorFrame();
1079}
1080
1081RenderView* RenderFrameImpl::GetRenderView() {
1082  return render_view_.get();
1083}
1084
1085int RenderFrameImpl::GetRoutingID() {
1086  return routing_id_;
1087}
1088
1089blink::WebFrame* RenderFrameImpl::GetWebFrame() {
1090  DCHECK(frame_);
1091  return frame_;
1092}
1093
1094WebPreferences& RenderFrameImpl::GetWebkitPreferences() {
1095  return render_view_->GetWebkitPreferences();
1096}
1097
1098int RenderFrameImpl::ShowContextMenu(ContextMenuClient* client,
1099                                     const ContextMenuParams& params) {
1100  DCHECK(client);  // A null client means "internal" when we issue callbacks.
1101  ContextMenuParams our_params(params);
1102  our_params.custom_context.request_id = pending_context_menus_.Add(client);
1103  Send(new FrameHostMsg_ContextMenu(routing_id_, our_params));
1104  return our_params.custom_context.request_id;
1105}
1106
1107void RenderFrameImpl::CancelContextMenu(int request_id) {
1108  DCHECK(pending_context_menus_.Lookup(request_id));
1109  pending_context_menus_.Remove(request_id);
1110}
1111
1112blink::WebNode RenderFrameImpl::GetContextMenuNode() const {
1113  return context_menu_node_;
1114}
1115
1116blink::WebPlugin* RenderFrameImpl::CreatePlugin(
1117    blink::WebFrame* frame,
1118    const WebPluginInfo& info,
1119    const blink::WebPluginParams& params) {
1120  DCHECK_EQ(frame_, frame);
1121#if defined(ENABLE_PLUGINS)
1122  bool pepper_plugin_was_registered = false;
1123  scoped_refptr<PluginModule> pepper_module(PluginModule::Create(
1124      this, info, &pepper_plugin_was_registered));
1125  if (pepper_plugin_was_registered) {
1126    if (pepper_module.get()) {
1127      return new PepperWebPluginImpl(pepper_module.get(), params, this);
1128    }
1129  }
1130#if defined(OS_CHROMEOS)
1131  LOG(WARNING) << "Pepper module/plugin creation failed.";
1132  return NULL;
1133#else
1134  // TODO(jam): change to take RenderFrame.
1135  return new WebPluginImpl(frame, params, info.path, render_view_, this);
1136#endif
1137#else
1138  return NULL;
1139#endif
1140}
1141
1142void RenderFrameImpl::LoadURLExternally(
1143    blink::WebFrame* frame,
1144    const blink::WebURLRequest& request,
1145    blink::WebNavigationPolicy policy) {
1146  DCHECK(!frame_ || frame_ == frame);
1147  loadURLExternally(frame, request, policy);
1148}
1149
1150void RenderFrameImpl::ExecuteJavaScript(const base::string16& javascript) {
1151  OnJavaScriptExecuteRequest(javascript, 0, false);
1152}
1153
1154void RenderFrameImpl::OnChildFrameProcessGone() {
1155  if (compositing_helper_)
1156    compositing_helper_->ChildFrameGone();
1157}
1158
1159// blink::WebFrameClient implementation ----------------------------------------
1160
1161blink::WebPlugin* RenderFrameImpl::createPlugin(
1162    blink::WebFrame* frame,
1163    const blink::WebPluginParams& params) {
1164  DCHECK_EQ(frame_, frame);
1165  blink::WebPlugin* plugin = NULL;
1166  if (GetContentClient()->renderer()->OverrideCreatePlugin(
1167          this, frame, params, &plugin)) {
1168    return plugin;
1169  }
1170
1171  if (base::UTF16ToASCII(params.mimeType) == kBrowserPluginMimeType) {
1172    return render_view_->GetBrowserPluginManager()->CreateBrowserPlugin(
1173        render_view_.get(), frame);
1174  }
1175
1176#if defined(ENABLE_PLUGINS)
1177  WebPluginInfo info;
1178  std::string mime_type;
1179  bool found = false;
1180  Send(new FrameHostMsg_GetPluginInfo(
1181      routing_id_, params.url, frame->top()->document().url(),
1182      params.mimeType.utf8(), &found, &info, &mime_type));
1183  if (!found)
1184    return NULL;
1185
1186  WebPluginParams params_to_use = params;
1187  params_to_use.mimeType = WebString::fromUTF8(mime_type);
1188  return CreatePlugin(frame, info, params_to_use);
1189#else
1190  return NULL;
1191#endif  // defined(ENABLE_PLUGINS)
1192}
1193
1194blink::WebMediaPlayer* RenderFrameImpl::createMediaPlayer(
1195    blink::WebFrame* frame,
1196    const blink::WebURL& url,
1197    blink::WebMediaPlayerClient* client) {
1198  DCHECK(!frame_ || frame_ == frame);
1199  // TODO(nasko): Moving the implementation here involves moving a few media
1200  // related client objects here or referencing them in the RenderView. Needs
1201  // more work to understand where the proper place for those objects is.
1202  return render_view_->CreateMediaPlayer(this, frame, url, client);
1203}
1204
1205blink::WebContentDecryptionModule*
1206RenderFrameImpl::createContentDecryptionModule(
1207    blink::WebFrame* frame,
1208    const blink::WebSecurityOrigin& security_origin,
1209    const blink::WebString& key_system) {
1210  DCHECK(!frame_ || frame_ == frame);
1211  return WebContentDecryptionModuleImpl::Create(
1212      frame, security_origin, key_system);
1213}
1214
1215blink::WebApplicationCacheHost* RenderFrameImpl::createApplicationCacheHost(
1216    blink::WebFrame* frame,
1217    blink::WebApplicationCacheHostClient* client) {
1218  if (!frame || !frame->view())
1219    return NULL;
1220  DCHECK(!frame_ || frame_ == frame);
1221  return new RendererWebApplicationCacheHostImpl(
1222      RenderViewImpl::FromWebView(frame->view()), client,
1223      RenderThreadImpl::current()->appcache_dispatcher()->backend_proxy());
1224}
1225
1226blink::WebWorkerPermissionClientProxy*
1227RenderFrameImpl::createWorkerPermissionClientProxy(blink::WebFrame* frame) {
1228  if (!frame || !frame->view())
1229    return NULL;
1230  DCHECK(!frame_ || frame_ == frame);
1231  return GetContentClient()->renderer()->CreateWorkerPermissionClientProxy(
1232      this, frame);
1233}
1234
1235blink::WebCookieJar* RenderFrameImpl::cookieJar(blink::WebFrame* frame) {
1236  DCHECK(!frame_ || frame_ == frame);
1237  return &cookie_jar_;
1238}
1239
1240blink::WebServiceWorkerProvider* RenderFrameImpl::createServiceWorkerProvider(
1241    blink::WebFrame* frame) {
1242  DCHECK(!frame_ || frame_ == frame);
1243  // At this point we should have non-null data source.
1244  DCHECK(frame->dataSource());
1245  ServiceWorkerNetworkProvider* provider =
1246      ServiceWorkerNetworkProvider::FromDocumentState(
1247          DocumentState::FromDataSource(frame->dataSource()));
1248  int provider_id = provider ?
1249      provider->provider_id() :
1250      kInvalidServiceWorkerProviderId;
1251  return new WebServiceWorkerProviderImpl(
1252      ChildThread::current()->thread_safe_sender(), provider_id);
1253}
1254
1255void RenderFrameImpl::didAccessInitialDocument(blink::WebFrame* frame) {
1256  DCHECK(!frame_ || frame_ == frame);
1257  render_view_->didAccessInitialDocument(frame);
1258}
1259
1260blink::WebFrame* RenderFrameImpl::createChildFrame(
1261    blink::WebFrame* parent,
1262    const blink::WebString& name) {
1263  // Synchronously notify the browser of a child frame creation to get the
1264  // routing_id for the RenderFrame.
1265  int child_routing_id = MSG_ROUTING_NONE;
1266  Send(new FrameHostMsg_CreateChildFrame(routing_id_,
1267                                         base::UTF16ToUTF8(name),
1268                                         &child_routing_id));
1269  // Allocation of routing id failed, so we can't create a child frame. This can
1270  // happen if this RenderFrameImpl's IPCs are being filtered when in swapped
1271  // out state.
1272  if (child_routing_id == MSG_ROUTING_NONE) {
1273    base::debug::Alias(parent);
1274    base::debug::Alias(&routing_id_);
1275    bool render_view_is_swapped_out = GetRenderWidget()->is_swapped_out();
1276    base::debug::Alias(&render_view_is_swapped_out);
1277    bool render_view_is_closing = GetRenderWidget()->closing();
1278    base::debug::Alias(&render_view_is_closing);
1279    base::debug::Alias(&is_swapped_out_);
1280    base::debug::DumpWithoutCrashing();
1281    return NULL;
1282  }
1283
1284  RenderFrameImpl* child_render_frame = RenderFrameImpl::Create(
1285      render_view_.get(), child_routing_id);
1286  blink::WebFrame* web_frame = WebFrame::create(child_render_frame);
1287  parent->appendChild(web_frame);
1288  child_render_frame->SetWebFrame(web_frame);
1289
1290  return web_frame;
1291}
1292
1293void RenderFrameImpl::didDisownOpener(blink::WebFrame* frame) {
1294  DCHECK(!frame_ || frame_ == frame);
1295  render_view_->didDisownOpener(frame);
1296}
1297
1298void RenderFrameImpl::frameDetached(blink::WebFrame* frame) {
1299  // NOTE: This function is called on the frame that is being detached and not
1300  // the parent frame.  This is different from createChildFrame() which is
1301  // called on the parent frame.
1302  CHECK(!is_detaching_);
1303  DCHECK(!frame_ || frame_ == frame);
1304
1305  bool is_subframe = !!frame->parent();
1306
1307  Send(new FrameHostMsg_Detach(routing_id_));
1308
1309  render_view_->UnregisterSwappedOutChildFrame(this);
1310
1311  // The |is_detaching_| flag disables Send(). FrameHostMsg_Detach must be
1312  // sent before setting |is_detaching_| to true. In contrast, Observers
1313  // should only be notified afterwards so they cannot call back into here and
1314  // have IPCs fired off.
1315  is_detaching_ = true;
1316
1317  // Call back to RenderViewImpl for observers to be notified.
1318  // TODO(nasko): Remove once we have RenderFrameObserver.
1319  render_view_->frameDetached(frame);
1320
1321  // We need to clean up subframes by removing them from the map and deleting
1322  // the RenderFrameImpl.  In contrast, the main frame is owned by its
1323  // containing RenderViewHost (so that they have the same lifetime), so only
1324  // removal from the map is needed and no deletion.
1325  FrameMap::iterator it = g_frame_map.Get().find(frame);
1326  CHECK(it != g_frame_map.Get().end());
1327  CHECK_EQ(it->second, this);
1328  g_frame_map.Get().erase(it);
1329
1330  if (is_subframe)
1331    frame->parent()->removeChild(frame);
1332
1333  // |frame| is invalid after here.
1334  frame->close();
1335
1336  if (is_subframe) {
1337    delete this;
1338    // Object is invalid after this point.
1339  }
1340}
1341
1342void RenderFrameImpl::frameFocused() {
1343  Send(new FrameHostMsg_FrameFocused(routing_id_));
1344}
1345
1346void RenderFrameImpl::willClose(blink::WebFrame* frame) {
1347  DCHECK(!frame_ || frame_ == frame);
1348  // Call back to RenderViewImpl for observers to be notified.
1349  // TODO(nasko): Remove once we have RenderFrameObserver.
1350  render_view_->willClose(frame);
1351}
1352
1353void RenderFrameImpl::didChangeName(blink::WebFrame* frame,
1354                                    const blink::WebString& name) {
1355  DCHECK(!frame_ || frame_ == frame);
1356  if (!render_view_->renderer_preferences_.report_frame_name_changes)
1357    return;
1358
1359  render_view_->Send(
1360      new ViewHostMsg_UpdateFrameName(render_view_->GetRoutingID(),
1361                                      routing_id_,
1362                                      !frame->parent(),
1363                                      base::UTF16ToUTF8(name)));
1364}
1365
1366void RenderFrameImpl::didMatchCSS(
1367    blink::WebFrame* frame,
1368    const blink::WebVector<blink::WebString>& newly_matching_selectors,
1369    const blink::WebVector<blink::WebString>& stopped_matching_selectors) {
1370  DCHECK(!frame_ || frame_ == frame);
1371  render_view_->didMatchCSS(
1372      frame, newly_matching_selectors, stopped_matching_selectors);
1373}
1374
1375void RenderFrameImpl::loadURLExternally(blink::WebFrame* frame,
1376                                        const blink::WebURLRequest& request,
1377                                        blink::WebNavigationPolicy policy) {
1378  DCHECK(!frame_ || frame_ == frame);
1379  loadURLExternally(frame, request, policy, WebString());
1380}
1381
1382void RenderFrameImpl::loadURLExternally(
1383    blink::WebFrame* frame,
1384    const blink::WebURLRequest& request,
1385    blink::WebNavigationPolicy policy,
1386    const blink::WebString& suggested_name) {
1387  DCHECK(!frame_ || frame_ == frame);
1388  Referrer referrer(RenderViewImpl::GetReferrerFromRequest(frame, request));
1389  if (policy == blink::WebNavigationPolicyDownload) {
1390    render_view_->Send(new ViewHostMsg_DownloadUrl(render_view_->GetRoutingID(),
1391                                                   request.url(), referrer,
1392                                                   suggested_name));
1393  } else {
1394    OpenURL(frame, request.url(), referrer, policy);
1395  }
1396}
1397
1398blink::WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation(
1399    blink::WebFrame* frame,
1400    blink::WebDataSource::ExtraData* extra_data,
1401    const blink::WebURLRequest& request,
1402    blink::WebNavigationType type,
1403    blink::WebNavigationPolicy default_policy,
1404    bool is_redirect) {
1405  DCHECK(!frame_ || frame_ == frame);
1406  return DecidePolicyForNavigation(
1407      this, frame, extra_data, request, type, default_policy, is_redirect);
1408}
1409
1410void RenderFrameImpl::willSendSubmitEvent(blink::WebFrame* frame,
1411                                          const blink::WebFormElement& form) {
1412  DCHECK(!frame_ || frame_ == frame);
1413  // Call back to RenderViewImpl for observers to be notified.
1414  // TODO(nasko): Remove once we have RenderFrameObserver.
1415  render_view_->willSendSubmitEvent(frame, form);
1416}
1417
1418void RenderFrameImpl::willSubmitForm(blink::WebFrame* frame,
1419                                     const blink::WebFormElement& form) {
1420  DCHECK(!frame_ || frame_ == frame);
1421  DocumentState* document_state =
1422      DocumentState::FromDataSource(frame->provisionalDataSource());
1423  NavigationState* navigation_state = document_state->navigation_state();
1424  InternalDocumentStateData* internal_data =
1425      InternalDocumentStateData::FromDocumentState(document_state);
1426
1427  if (PageTransitionCoreTypeIs(navigation_state->transition_type(),
1428                               PAGE_TRANSITION_LINK)) {
1429    navigation_state->set_transition_type(PAGE_TRANSITION_FORM_SUBMIT);
1430  }
1431
1432  // Save these to be processed when the ensuing navigation is committed.
1433  WebSearchableFormData web_searchable_form_data(form);
1434  internal_data->set_searchable_form_url(web_searchable_form_data.url());
1435  internal_data->set_searchable_form_encoding(
1436      web_searchable_form_data.encoding().utf8());
1437
1438  // Call back to RenderViewImpl for observers to be notified.
1439  // TODO(nasko): Remove once we have RenderFrameObserver.
1440  render_view_->willSubmitForm(frame, form);
1441}
1442
1443void RenderFrameImpl::didCreateDataSource(blink::WebFrame* frame,
1444                                          blink::WebDataSource* datasource) {
1445  DCHECK(!frame_ || frame_ == frame);
1446
1447  // TODO(nasko): Move implementation here. Needed state:
1448  // * pending_navigation_params_
1449  // * webview
1450  // Needed methods:
1451  // * PopulateDocumentStateFromPending
1452  // * CreateNavigationStateFromPending
1453  render_view_->didCreateDataSource(frame, datasource);
1454
1455  // Create the serviceworker's per-document network observing object.
1456  scoped_ptr<ServiceWorkerNetworkProvider>
1457      network_provider(new ServiceWorkerNetworkProvider());
1458  ServiceWorkerNetworkProvider::AttachToDocumentState(
1459      DocumentState::FromDataSource(datasource),
1460      network_provider.Pass());
1461}
1462
1463void RenderFrameImpl::didStartProvisionalLoad(blink::WebFrame* frame) {
1464  DCHECK(!frame_ || frame_ == frame);
1465  WebDataSource* ds = frame->provisionalDataSource();
1466
1467  // In fast/loader/stop-provisional-loads.html, we abort the load before this
1468  // callback is invoked.
1469  if (!ds)
1470    return;
1471
1472  DocumentState* document_state = DocumentState::FromDataSource(ds);
1473
1474  // We should only navigate to swappedout:// when is_swapped_out_ is true.
1475  CHECK((ds->request().url() != GURL(kSwappedOutURL)) ||
1476        is_swapped_out_ ||
1477        render_view_->is_swapped_out()) <<
1478        "Heard swappedout:// when not swapped out.";
1479
1480  // Update the request time if WebKit has better knowledge of it.
1481  if (document_state->request_time().is_null()) {
1482    double event_time = ds->triggeringEventTime();
1483    if (event_time != 0.0)
1484      document_state->set_request_time(Time::FromDoubleT(event_time));
1485  }
1486
1487  // Start time is only set after request time.
1488  document_state->set_start_load_time(Time::Now());
1489
1490  bool is_top_most = !frame->parent();
1491  if (is_top_most) {
1492    render_view_->set_navigation_gesture(
1493        WebUserGestureIndicator::isProcessingUserGesture() ?
1494            NavigationGestureUser : NavigationGestureAuto);
1495  } else if (ds->replacesCurrentHistoryItem()) {
1496    // Subframe navigations that don't add session history items must be
1497    // marked with AUTO_SUBFRAME. See also didFailProvisionalLoad for how we
1498    // handle loading of error pages.
1499    document_state->navigation_state()->set_transition_type(
1500        PAGE_TRANSITION_AUTO_SUBFRAME);
1501  }
1502
1503  FOR_EACH_OBSERVER(
1504      RenderViewObserver, render_view_->observers(),
1505      DidStartProvisionalLoad(frame));
1506
1507  FOR_EACH_OBSERVER(
1508      RenderFrameObserver, observers_,
1509      DidStartProvisionalLoad());
1510
1511  int parent_routing_id = frame->parent() ?
1512      FromWebFrame(frame->parent())->GetRoutingID() : -1;
1513  Send(new FrameHostMsg_DidStartProvisionalLoadForFrame(
1514       routing_id_, parent_routing_id, ds->request().url()));
1515}
1516
1517void RenderFrameImpl::didReceiveServerRedirectForProvisionalLoad(
1518    blink::WebFrame* frame) {
1519  DCHECK(!frame_ || frame_ == frame);
1520  if (frame->parent())
1521    return;
1522  // Received a redirect on the main frame.
1523  WebDataSource* data_source = frame->provisionalDataSource();
1524  if (!data_source) {
1525    // Should only be invoked when we have a data source.
1526    NOTREACHED();
1527    return;
1528  }
1529  std::vector<GURL> redirects;
1530  GetRedirectChain(data_source, &redirects);
1531  if (redirects.size() >= 2) {
1532    Send(new FrameHostMsg_DidRedirectProvisionalLoad(
1533        routing_id_,
1534        render_view_->page_id_,
1535        redirects[redirects.size() - 2],
1536        redirects.back()));
1537  }
1538}
1539
1540void RenderFrameImpl::didFailProvisionalLoad(
1541    blink::WebFrame* frame,
1542    const blink::WebURLError& error) {
1543  DCHECK(!frame_ || frame_ == frame);
1544  WebDataSource* ds = frame->provisionalDataSource();
1545  DCHECK(ds);
1546
1547  const WebURLRequest& failed_request = ds->request();
1548
1549  // Call out to RenderViewImpl, so observers are notified.
1550  render_view_->didFailProvisionalLoad(frame, error);
1551
1552  FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
1553                    DidFailProvisionalLoad(error));
1554
1555  bool show_repost_interstitial =
1556      (error.reason == net::ERR_CACHE_MISS &&
1557       EqualsASCII(failed_request.httpMethod(), "POST"));
1558
1559  FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
1560  params.frame_unique_name = frame->uniqueName();
1561  params.error_code = error.reason;
1562  GetContentClient()->renderer()->GetNavigationErrorStrings(
1563      render_view_.get(),
1564      frame,
1565      failed_request,
1566      error,
1567      NULL,
1568      &params.error_description);
1569  params.url = error.unreachableURL;
1570  params.showing_repost_interstitial = show_repost_interstitial;
1571  Send(new FrameHostMsg_DidFailProvisionalLoadWithError(
1572      routing_id_, params));
1573
1574  // Don't display an error page if this is simply a cancelled load.  Aside
1575  // from being dumb, WebCore doesn't expect it and it will cause a crash.
1576  if (error.reason == net::ERR_ABORTED)
1577    return;
1578
1579  // Don't display "client blocked" error page if browser has asked us not to.
1580  if (error.reason == net::ERR_BLOCKED_BY_CLIENT &&
1581      render_view_->renderer_preferences_.disable_client_blocked_error_page) {
1582    return;
1583  }
1584
1585  // Allow the embedder to suppress an error page.
1586  if (GetContentClient()->renderer()->ShouldSuppressErrorPage(this,
1587          error.unreachableURL)) {
1588    return;
1589  }
1590
1591  if (RenderThreadImpl::current() &&
1592      RenderThreadImpl::current()->layout_test_mode()) {
1593    return;
1594  }
1595
1596  // Make sure we never show errors in view source mode.
1597  frame->enableViewSourceMode(false);
1598
1599  DocumentState* document_state = DocumentState::FromDataSource(ds);
1600  NavigationState* navigation_state = document_state->navigation_state();
1601
1602  // If this is a failed back/forward/reload navigation, then we need to do a
1603  // 'replace' load.  This is necessary to avoid messing up session history.
1604  // Otherwise, we do a normal load, which simulates a 'go' navigation as far
1605  // as session history is concerned.
1606  //
1607  // AUTO_SUBFRAME loads should always be treated as loads that do not advance
1608  // the page id.
1609  //
1610  // TODO(davidben): This should also take the failed navigation's replacement
1611  // state into account, if a location.replace() failed.
1612  bool replace =
1613      navigation_state->pending_page_id() != -1 ||
1614      PageTransitionCoreTypeIs(navigation_state->transition_type(),
1615                               PAGE_TRANSITION_AUTO_SUBFRAME);
1616
1617  // If we failed on a browser initiated request, then make sure that our error
1618  // page load is regarded as the same browser initiated request.
1619  if (!navigation_state->is_content_initiated()) {
1620    render_view_->pending_navigation_params_.reset(
1621        new FrameMsg_Navigate_Params);
1622    render_view_->pending_navigation_params_->page_id =
1623        navigation_state->pending_page_id();
1624    render_view_->pending_navigation_params_->pending_history_list_offset =
1625        navigation_state->pending_history_list_offset();
1626    render_view_->pending_navigation_params_->should_clear_history_list =
1627        navigation_state->history_list_was_cleared();
1628    render_view_->pending_navigation_params_->transition =
1629        navigation_state->transition_type();
1630    render_view_->pending_navigation_params_->request_time =
1631        document_state->request_time();
1632    render_view_->pending_navigation_params_->should_replace_current_entry =
1633        replace;
1634  }
1635
1636  // Load an error page.
1637  render_view_->LoadNavigationErrorPage(
1638      frame, failed_request, error, replace);
1639}
1640
1641void RenderFrameImpl::didCommitProvisionalLoad(blink::WebFrame* frame,
1642                                               bool is_new_navigation) {
1643  DCHECK(!frame_ || frame_ == frame);
1644  DocumentState* document_state =
1645      DocumentState::FromDataSource(frame->dataSource());
1646  NavigationState* navigation_state = document_state->navigation_state();
1647  InternalDocumentStateData* internal_data =
1648      InternalDocumentStateData::FromDocumentState(document_state);
1649
1650  if (document_state->commit_load_time().is_null())
1651    document_state->set_commit_load_time(Time::Now());
1652
1653  if (internal_data->must_reset_scroll_and_scale_state()) {
1654    render_view_->webview()->resetScrollAndScaleState();
1655    internal_data->set_must_reset_scroll_and_scale_state(false);
1656  }
1657  internal_data->set_use_error_page(false);
1658
1659  if (is_new_navigation) {
1660    // When we perform a new navigation, we need to update the last committed
1661    // session history entry with state for the page we are leaving.
1662    render_view_->UpdateSessionHistory(frame);
1663
1664    // We bump our Page ID to correspond with the new session history entry.
1665    render_view_->page_id_ = render_view_->next_page_id_++;
1666
1667    // Don't update history_page_ids_ (etc) for kSwappedOutURL, since
1668    // we don't want to forget the entry that was there, and since we will
1669    // never come back to kSwappedOutURL.  Note that we have to call
1670    // UpdateSessionHistory and update page_id_ even in this case, so that
1671    // the current entry gets a state update and so that we don't send a
1672    // state update to the wrong entry when we swap back in.
1673    if (render_view_->GetLoadingUrl(frame) != GURL(kSwappedOutURL)) {
1674      // Advance our offset in session history, applying the length limit.
1675      // There is now no forward history.
1676      render_view_->history_list_offset_++;
1677      if (render_view_->history_list_offset_ >= kMaxSessionHistoryEntries)
1678        render_view_->history_list_offset_ = kMaxSessionHistoryEntries - 1;
1679      render_view_->history_list_length_ =
1680          render_view_->history_list_offset_ + 1;
1681      render_view_->history_page_ids_.resize(
1682          render_view_->history_list_length_, -1);
1683      render_view_->history_page_ids_[render_view_->history_list_offset_] =
1684          render_view_->page_id_;
1685    }
1686  } else {
1687    // Inspect the navigation_state on this frame to see if the navigation
1688    // corresponds to a session history navigation...  Note: |frame| may or
1689    // may not be the toplevel frame, but for the case of capturing session
1690    // history, the first committed frame suffices.  We keep track of whether
1691    // we've seen this commit before so that only capture session history once
1692    // per navigation.
1693    //
1694    // Note that we need to check if the page ID changed. In the case of a
1695    // reload, the page ID doesn't change, and UpdateSessionHistory gets the
1696    // previous URL and the current page ID, which would be wrong.
1697    if (navigation_state->pending_page_id() != -1 &&
1698        navigation_state->pending_page_id() != render_view_->page_id_ &&
1699        !navigation_state->request_committed()) {
1700      // This is a successful session history navigation!
1701      render_view_->UpdateSessionHistory(frame);
1702      render_view_->page_id_ = navigation_state->pending_page_id();
1703
1704      render_view_->history_list_offset_ =
1705          navigation_state->pending_history_list_offset();
1706
1707      // If the history list is valid, our list of page IDs should be correct.
1708      DCHECK(render_view_->history_list_length_ <= 0 ||
1709             render_view_->history_list_offset_ < 0 ||
1710             render_view_->history_list_offset_ >=
1711                 render_view_->history_list_length_ ||
1712             render_view_->history_page_ids_[render_view_->history_list_offset_]
1713                  == render_view_->page_id_);
1714    }
1715  }
1716
1717  render_view_->didCommitProvisionalLoad(frame, is_new_navigation);
1718  FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
1719                    DidCommitProvisionalLoad(is_new_navigation));
1720
1721  // Remember that we've already processed this request, so we don't update
1722  // the session history again.  We do this regardless of whether this is
1723  // a session history navigation, because if we attempted a session history
1724  // navigation without valid HistoryItem state, WebCore will think it is a
1725  // new navigation.
1726  navigation_state->set_request_committed(true);
1727
1728  UpdateURL(frame);
1729
1730  // Check whether we have new encoding name.
1731  render_view_->UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
1732}
1733
1734void RenderFrameImpl::didClearWindowObject(blink::WebFrame* frame,
1735                                           int world_id) {
1736  DCHECK(!frame_ || frame_ == frame);
1737  // TODO(nasko): Move implementation here. Needed state:
1738  // * enabled_bindings_
1739  // * dom_automation_controller_
1740  // * stats_collection_controller_
1741
1742  render_view_->didClearWindowObject(frame, world_id);
1743
1744  // Only install controllers into the main world.
1745  if (world_id)
1746    return;
1747
1748  if (render_view_->GetEnabledBindings() & BINDINGS_POLICY_DOM_AUTOMATION)
1749    DomAutomationController::Install(this, frame);
1750
1751  FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
1752                    DidClearWindowObject(world_id));
1753}
1754
1755void RenderFrameImpl::didCreateDocumentElement(blink::WebFrame* frame) {
1756  DCHECK(!frame_ || frame_ == frame);
1757
1758  // Notify the browser about non-blank documents loading in the top frame.
1759  GURL url = frame->document().url();
1760  if (url.is_valid() && url.spec() != kAboutBlankURL) {
1761    // TODO(nasko): Check if webview()->mainFrame() is the same as the
1762    // frame->tree()->top().
1763    if (frame == render_view_->webview()->mainFrame()) {
1764      render_view_->Send(new ViewHostMsg_DocumentAvailableInMainFrame(
1765          render_view_->GetRoutingID()));
1766    }
1767  }
1768
1769  // Call back to RenderViewImpl for observers to be notified.
1770  // TODO(nasko): Remove once we have RenderFrameObserver.
1771  render_view_->didCreateDocumentElement(frame);
1772}
1773
1774void RenderFrameImpl::didReceiveTitle(blink::WebFrame* frame,
1775                                      const blink::WebString& title,
1776                                      blink::WebTextDirection direction) {
1777  DCHECK(!frame_ || frame_ == frame);
1778  // TODO(nasko): Investigate wheather implementation should move here.
1779  render_view_->didReceiveTitle(frame, title, direction);
1780}
1781
1782void RenderFrameImpl::didChangeIcon(blink::WebFrame* frame,
1783                                    blink::WebIconURL::Type icon_type) {
1784  DCHECK(!frame_ || frame_ == frame);
1785  // TODO(nasko): Investigate wheather implementation should move here.
1786  render_view_->didChangeIcon(frame, icon_type);
1787}
1788
1789void RenderFrameImpl::didFinishDocumentLoad(blink::WebFrame* frame) {
1790  DCHECK(!frame_ || frame_ == frame);
1791  WebDataSource* ds = frame->dataSource();
1792  DocumentState* document_state = DocumentState::FromDataSource(ds);
1793  document_state->set_finish_document_load_time(Time::Now());
1794
1795  Send(new FrameHostMsg_DidFinishDocumentLoad(routing_id_));
1796
1797  // Call back to RenderViewImpl for observers to be notified.
1798  // TODO(nasko): Remove once we have RenderFrameObserver for this method.
1799  render_view_->didFinishDocumentLoad(frame);
1800
1801  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidFinishDocumentLoad());
1802
1803  // Check whether we have new encoding name.
1804  render_view_->UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
1805}
1806
1807void RenderFrameImpl::didHandleOnloadEvents(blink::WebFrame* frame) {
1808  DCHECK(!frame_ || frame_ == frame);
1809  // TODO(nasko): Move implementation here. Needed state:
1810  // * page_id_
1811  render_view_->didHandleOnloadEvents(frame);
1812}
1813
1814void RenderFrameImpl::didFailLoad(blink::WebFrame* frame,
1815                                  const blink::WebURLError& error) {
1816  DCHECK(!frame_ || frame_ == frame);
1817  // TODO(nasko): Move implementation here. No state needed.
1818  WebDataSource* ds = frame->dataSource();
1819  DCHECK(ds);
1820
1821  render_view_->didFailLoad(frame, error);
1822
1823  const WebURLRequest& failed_request = ds->request();
1824  base::string16 error_description;
1825  GetContentClient()->renderer()->GetNavigationErrorStrings(
1826      render_view_.get(),
1827      frame,
1828      failed_request,
1829      error,
1830      NULL,
1831      &error_description);
1832  Send(new FrameHostMsg_DidFailLoadWithError(routing_id_,
1833                                             failed_request.url(),
1834                                             error.reason,
1835                                             error_description));
1836}
1837
1838void RenderFrameImpl::didFinishLoad(blink::WebFrame* frame) {
1839  DCHECK(!frame_ || frame_ == frame);
1840  WebDataSource* ds = frame->dataSource();
1841  DocumentState* document_state = DocumentState::FromDataSource(ds);
1842  if (document_state->finish_load_time().is_null()) {
1843    if (!frame->parent()) {
1844      TRACE_EVENT_INSTANT0("WebCore", "LoadFinished",
1845                           TRACE_EVENT_SCOPE_PROCESS);
1846    }
1847    document_state->set_finish_load_time(Time::Now());
1848  }
1849
1850  render_view_->didFinishLoad(frame);
1851  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidFinishLoad());
1852
1853  // Don't send this message while the frame is swapped out.
1854  if (is_swapped_out())
1855    return;
1856
1857  Send(new FrameHostMsg_DidFinishLoad(routing_id_,
1858                                      ds->request().url()));
1859}
1860
1861void RenderFrameImpl::didNavigateWithinPage(blink::WebFrame* frame,
1862                                            bool is_new_navigation) {
1863  DCHECK(!frame_ || frame_ == frame);
1864  // If this was a reference fragment navigation that we initiated, then we
1865  // could end up having a non-null pending navigation params.  We just need to
1866  // update the ExtraData on the datasource so that others who read the
1867  // ExtraData will get the new NavigationState.  Similarly, if we did not
1868  // initiate this navigation, then we need to take care to reset any pre-
1869  // existing navigation state to a content-initiated navigation state.
1870  // DidCreateDataSource conveniently takes care of this for us.
1871  didCreateDataSource(frame, frame->dataSource());
1872
1873  DocumentState* document_state =
1874      DocumentState::FromDataSource(frame->dataSource());
1875  NavigationState* new_state = document_state->navigation_state();
1876  new_state->set_was_within_same_page(true);
1877
1878  didCommitProvisionalLoad(frame, is_new_navigation);
1879}
1880
1881void RenderFrameImpl::didUpdateCurrentHistoryItem(blink::WebFrame* frame) {
1882  DCHECK(!frame_ || frame_ == frame);
1883  // TODO(nasko): Move implementation here. Needed methods:
1884  // * StartNavStateSyncTimerIfNecessary
1885  render_view_->didUpdateCurrentHistoryItem(frame);
1886}
1887
1888void RenderFrameImpl::didChangeSelection(bool is_empty_selection) {
1889  if (!GetRenderWidget()->handling_input_event() && !handling_select_range_)
1890    return;
1891
1892  if (is_empty_selection)
1893    selection_text_.clear();
1894
1895  // UpdateTextInputType should be called before SyncSelectionIfRequired.
1896  // UpdateTextInputType may send TextInputTypeChanged to notify the focus
1897  // was changed, and SyncSelectionIfRequired may send SelectionChanged
1898  // to notify the selection was changed.  Focus change should be notified
1899  // before selection change.
1900  GetRenderWidget()->UpdateTextInputType();
1901  SyncSelectionIfRequired();
1902#if defined(OS_ANDROID)
1903  GetRenderWidget()->UpdateTextInputState(false, true);
1904#endif
1905}
1906
1907void RenderFrameImpl::showContextMenu(const blink::WebContextMenuData& data) {
1908  ContextMenuParams params = ContextMenuParamsBuilder::Build(data);
1909  params.source_type = GetRenderWidget()->context_menu_source_type();
1910  if (params.source_type == ui::MENU_SOURCE_TOUCH_EDIT_MENU) {
1911    params.x = GetRenderWidget()->touch_editing_context_menu_location().x();
1912    params.y = GetRenderWidget()->touch_editing_context_menu_location().y();
1913  }
1914  GetRenderWidget()->OnShowHostContextMenu(&params);
1915
1916  // Plugins, e.g. PDF, don't currently update the render view when their
1917  // selected text changes, but the context menu params do contain the updated
1918  // selection. If that's the case, update the render view's state just prior
1919  // to showing the context menu.
1920  // TODO(asvitkine): http://crbug.com/152432
1921  if (ShouldUpdateSelectionTextFromContextMenuParams(
1922          selection_text_, selection_text_offset_, selection_range_, params)) {
1923    selection_text_ = params.selection_text;
1924    // TODO(asvitkine): Text offset and range is not available in this case.
1925    selection_text_offset_ = 0;
1926    selection_range_ = gfx::Range(0, selection_text_.length());
1927    // This IPC is dispatched by RenderWidetHost, so use its routing ID.
1928    Send(new ViewHostMsg_SelectionChanged(
1929        GetRenderWidget()->routing_id(), selection_text_,
1930        selection_text_offset_, selection_range_));
1931  }
1932
1933  // Serializing a GURL longer than kMaxURLChars will fail, so don't do
1934  // it.  We replace it with an empty GURL so the appropriate items are disabled
1935  // in the context menu.
1936  // TODO(jcivelli): http://crbug.com/45160 This prevents us from saving large
1937  //                 data encoded images.  We should have a way to save them.
1938  if (params.src_url.spec().size() > GetMaxURLChars())
1939    params.src_url = GURL();
1940  context_menu_node_ = data.node;
1941
1942#if defined(OS_ANDROID)
1943  gfx::Rect start_rect;
1944  gfx::Rect end_rect;
1945  GetRenderWidget()->GetSelectionBounds(&start_rect, &end_rect);
1946  params.selection_start = gfx::Point(start_rect.x(), start_rect.bottom());
1947  params.selection_end = gfx::Point(end_rect.right(), end_rect.bottom());
1948#endif
1949
1950  Send(new FrameHostMsg_ContextMenu(routing_id_, params));
1951}
1952
1953void RenderFrameImpl::clearContextMenu() {
1954  context_menu_node_.reset();
1955}
1956
1957void RenderFrameImpl::willRequestAfterPreconnect(
1958    blink::WebFrame* frame,
1959    blink::WebURLRequest& request) {
1960  DCHECK(!frame_ || frame_ == frame);
1961  // FIXME(kohei): This will never be set.
1962  WebString custom_user_agent;
1963
1964  DCHECK(!request.extraData());
1965
1966  bool was_after_preconnect_request = true;
1967  // The args after |was_after_preconnect_request| are not used, and set to
1968  // correct values at |willSendRequest|.
1969  RequestExtraData* extra_data = new RequestExtraData();
1970  extra_data->set_custom_user_agent(custom_user_agent);
1971  extra_data->set_was_after_preconnect_request(was_after_preconnect_request);
1972  request.setExtraData(extra_data);
1973}
1974
1975void RenderFrameImpl::willSendRequest(
1976    blink::WebFrame* frame,
1977    unsigned identifier,
1978    blink::WebURLRequest& request,
1979    const blink::WebURLResponse& redirect_response) {
1980  DCHECK(!frame_ || frame_ == frame);
1981  // The request my be empty during tests.
1982  if (request.url().isEmpty())
1983    return;
1984
1985  WebFrame* top_frame = frame->top();
1986  if (!top_frame)
1987    top_frame = frame;
1988  WebDataSource* provisional_data_source = top_frame->provisionalDataSource();
1989  WebDataSource* top_data_source = top_frame->dataSource();
1990  WebDataSource* data_source =
1991      provisional_data_source ? provisional_data_source : top_data_source;
1992
1993  PageTransition transition_type = PAGE_TRANSITION_LINK;
1994  DocumentState* document_state = DocumentState::FromDataSource(data_source);
1995  DCHECK(document_state);
1996  InternalDocumentStateData* internal_data =
1997      InternalDocumentStateData::FromDocumentState(document_state);
1998  NavigationState* navigation_state = document_state->navigation_state();
1999  transition_type = navigation_state->transition_type();
2000
2001  GURL request_url(request.url());
2002  GURL new_url;
2003  if (GetContentClient()->renderer()->WillSendRequest(
2004          frame,
2005          transition_type,
2006          request_url,
2007          request.firstPartyForCookies(),
2008          &new_url)) {
2009    request.setURL(WebURL(new_url));
2010  }
2011
2012  if (internal_data->is_cache_policy_override_set())
2013    request.setCachePolicy(internal_data->cache_policy_override());
2014
2015  // The request's extra data may indicate that we should set a custom user
2016  // agent. This needs to be done here, after WebKit is through with setting the
2017  // user agent on its own.
2018  WebString custom_user_agent;
2019  bool was_after_preconnect_request = false;
2020  if (request.extraData()) {
2021    RequestExtraData* old_extra_data =
2022        static_cast<RequestExtraData*>(
2023            request.extraData());
2024    custom_user_agent = old_extra_data->custom_user_agent();
2025    was_after_preconnect_request =
2026        old_extra_data->was_after_preconnect_request();
2027
2028    if (!custom_user_agent.isNull()) {
2029      if (custom_user_agent.isEmpty())
2030        request.clearHTTPHeaderField("User-Agent");
2031      else
2032        request.setHTTPHeaderField("User-Agent", custom_user_agent);
2033    }
2034  }
2035
2036  // Attach |should_replace_current_entry| state to requests so that, should
2037  // this navigation later require a request transfer, all state is preserved
2038  // when it is re-created in the new process.
2039  bool should_replace_current_entry = false;
2040  if (navigation_state->is_content_initiated()) {
2041    should_replace_current_entry = data_source->replacesCurrentHistoryItem();
2042  } else {
2043    // If the navigation is browser-initiated, the NavigationState contains the
2044    // correct value instead of the WebDataSource.
2045    //
2046    // TODO(davidben): Avoid this awkward duplication of state. See comment on
2047    // NavigationState::should_replace_current_entry().
2048    should_replace_current_entry =
2049        navigation_state->should_replace_current_entry();
2050  }
2051
2052  int provider_id = kInvalidServiceWorkerProviderId;
2053  if (request.targetType() == blink::WebURLRequest::TargetIsMainFrame ||
2054      request.targetType() == blink::WebURLRequest::TargetIsSubframe) {
2055    // |provisionalDataSource| may be null in some content::ResourceFetcher
2056    // use cases, we don't hook those requests.
2057    if (frame->provisionalDataSource()) {
2058      ServiceWorkerNetworkProvider* provider =
2059          ServiceWorkerNetworkProvider::FromDocumentState(
2060              DocumentState::FromDataSource(frame->provisionalDataSource()));
2061      provider_id = provider->provider_id();
2062    }
2063  } else if (frame->dataSource()) {
2064    ServiceWorkerNetworkProvider* provider =
2065        ServiceWorkerNetworkProvider::FromDocumentState(
2066            DocumentState::FromDataSource(frame->dataSource()));
2067    provider_id = provider->provider_id();
2068  }
2069
2070  int parent_routing_id = frame->parent() ?
2071      FromWebFrame(frame->parent())->GetRoutingID() : -1;
2072  RequestExtraData* extra_data = new RequestExtraData();
2073  extra_data->set_visibility_state(render_view_->visibilityState());
2074  extra_data->set_custom_user_agent(custom_user_agent);
2075  extra_data->set_was_after_preconnect_request(was_after_preconnect_request);
2076  extra_data->set_render_frame_id(routing_id_);
2077  extra_data->set_is_main_frame(frame == top_frame);
2078  extra_data->set_frame_origin(
2079      GURL(frame->document().securityOrigin().toString()));
2080  extra_data->set_parent_is_main_frame(frame->parent() == top_frame);
2081  extra_data->set_parent_render_frame_id(parent_routing_id);
2082  extra_data->set_allow_download(navigation_state->allow_download());
2083  extra_data->set_transition_type(transition_type);
2084  extra_data->set_should_replace_current_entry(should_replace_current_entry);
2085  extra_data->set_transferred_request_child_id(
2086      navigation_state->transferred_request_child_id());
2087  extra_data->set_transferred_request_request_id(
2088      navigation_state->transferred_request_request_id());
2089  extra_data->set_service_worker_provider_id(provider_id);
2090  request.setExtraData(extra_data);
2091
2092  DocumentState* top_document_state =
2093      DocumentState::FromDataSource(top_data_source);
2094  if (top_document_state) {
2095    // TODO(gavinp): separate out prefetching and prerender field trials
2096    // if the rel=prerender rel type is sticking around.
2097    if (request.targetType() == WebURLRequest::TargetIsPrefetch)
2098      top_document_state->set_was_prefetcher(true);
2099
2100    if (was_after_preconnect_request)
2101      top_document_state->set_was_after_preconnect_request(true);
2102  }
2103
2104  // This is an instance where we embed a copy of the routing id
2105  // into the data portion of the message. This can cause problems if we
2106  // don't register this id on the browser side, since the download manager
2107  // expects to find a RenderViewHost based off the id.
2108  request.setRequestorID(render_view_->GetRoutingID());
2109  request.setHasUserGesture(WebUserGestureIndicator::isProcessingUserGesture());
2110
2111  if (!navigation_state->extra_headers().empty()) {
2112    for (net::HttpUtil::HeadersIterator i(
2113        navigation_state->extra_headers().begin(),
2114        navigation_state->extra_headers().end(), "\n");
2115        i.GetNext(); ) {
2116      if (LowerCaseEqualsASCII(i.name(), "referer")) {
2117        WebString referrer = WebSecurityPolicy::generateReferrerHeader(
2118            blink::WebReferrerPolicyDefault,
2119            request.url(),
2120            WebString::fromUTF8(i.values()));
2121        request.setHTTPReferrer(referrer, blink::WebReferrerPolicyDefault);
2122      } else {
2123        request.setHTTPHeaderField(WebString::fromUTF8(i.name()),
2124                                   WebString::fromUTF8(i.values()));
2125      }
2126    }
2127  }
2128
2129  if (!render_view_->renderer_preferences_.enable_referrers)
2130    request.setHTTPReferrer(WebString(), blink::WebReferrerPolicyDefault);
2131}
2132
2133void RenderFrameImpl::didReceiveResponse(
2134    blink::WebFrame* frame,
2135    unsigned identifier,
2136    const blink::WebURLResponse& response) {
2137  DCHECK(!frame_ || frame_ == frame);
2138  // Only do this for responses that correspond to a provisional data source
2139  // of the top-most frame.  If we have a provisional data source, then we
2140  // can't have any sub-resources yet, so we know that this response must
2141  // correspond to a frame load.
2142  if (!frame->provisionalDataSource() || frame->parent())
2143    return;
2144
2145  // If we are in view source mode, then just let the user see the source of
2146  // the server's error page.
2147  if (frame->isViewSourceModeEnabled())
2148    return;
2149
2150  DocumentState* document_state =
2151      DocumentState::FromDataSource(frame->provisionalDataSource());
2152  int http_status_code = response.httpStatusCode();
2153
2154  // Record page load flags.
2155  WebURLResponseExtraDataImpl* extra_data =
2156      GetExtraDataFromResponse(response);
2157  if (extra_data) {
2158    document_state->set_was_fetched_via_spdy(
2159        extra_data->was_fetched_via_spdy());
2160    document_state->set_was_npn_negotiated(
2161        extra_data->was_npn_negotiated());
2162    document_state->set_npn_negotiated_protocol(
2163        extra_data->npn_negotiated_protocol());
2164    document_state->set_was_alternate_protocol_available(
2165        extra_data->was_alternate_protocol_available());
2166    document_state->set_connection_info(
2167        extra_data->connection_info());
2168    document_state->set_was_fetched_via_proxy(
2169        extra_data->was_fetched_via_proxy());
2170  }
2171  InternalDocumentStateData* internal_data =
2172      InternalDocumentStateData::FromDocumentState(document_state);
2173  internal_data->set_http_status_code(http_status_code);
2174  // Whether or not the http status code actually corresponds to an error is
2175  // only checked when the page is done loading, if |use_error_page| is
2176  // still true.
2177  internal_data->set_use_error_page(true);
2178}
2179
2180void RenderFrameImpl::didFinishResourceLoad(blink::WebFrame* frame,
2181                                            unsigned identifier) {
2182  DCHECK(!frame_ || frame_ == frame);
2183  // TODO(nasko): Move implementation here. Needed state:
2184  // * devtools_agent_
2185  // Needed methods:
2186  // * LoadNavigationErrorPage
2187  render_view_->didFinishResourceLoad(frame, identifier);
2188}
2189
2190void RenderFrameImpl::didLoadResourceFromMemoryCache(
2191    blink::WebFrame* frame,
2192    const blink::WebURLRequest& request,
2193    const blink::WebURLResponse& response) {
2194  DCHECK(!frame_ || frame_ == frame);
2195  // The recipients of this message have no use for data: URLs: they don't
2196  // affect the page's insecure content list and are not in the disk cache. To
2197  // prevent large (1M+) data: URLs from crashing in the IPC system, we simply
2198  // filter them out here.
2199  GURL url(request.url());
2200  if (url.SchemeIs("data"))
2201    return;
2202
2203  // Let the browser know we loaded a resource from the memory cache.  This
2204  // message is needed to display the correct SSL indicators.
2205  render_view_->Send(new ViewHostMsg_DidLoadResourceFromMemoryCache(
2206      render_view_->GetRoutingID(),
2207      url,
2208      response.securityInfo(),
2209      request.httpMethod().utf8(),
2210      response.mimeType().utf8(),
2211      ResourceType::FromTargetType(request.targetType())));
2212}
2213
2214void RenderFrameImpl::didDisplayInsecureContent(blink::WebFrame* frame) {
2215  DCHECK(!frame_ || frame_ == frame);
2216  render_view_->Send(new ViewHostMsg_DidDisplayInsecureContent(
2217      render_view_->GetRoutingID()));
2218}
2219
2220void RenderFrameImpl::didRunInsecureContent(
2221    blink::WebFrame* frame,
2222    const blink::WebSecurityOrigin& origin,
2223    const blink::WebURL& target) {
2224  DCHECK(!frame_ || frame_ == frame);
2225  render_view_->Send(new ViewHostMsg_DidRunInsecureContent(
2226      render_view_->GetRoutingID(),
2227      origin.toString().utf8(),
2228      target));
2229}
2230
2231void RenderFrameImpl::didAbortLoading(blink::WebFrame* frame) {
2232  DCHECK(!frame_ || frame_ == frame);
2233#if defined(ENABLE_PLUGINS)
2234  if (frame != render_view_->webview()->mainFrame())
2235    return;
2236  PluginChannelHost::Broadcast(
2237      new PluginHostMsg_DidAbortLoading(render_view_->GetRoutingID()));
2238#endif
2239}
2240
2241void RenderFrameImpl::didCreateScriptContext(blink::WebFrame* frame,
2242                                             v8::Handle<v8::Context> context,
2243                                             int extension_group,
2244                                             int world_id) {
2245  DCHECK(!frame_ || frame_ == frame);
2246  GetContentClient()->renderer()->DidCreateScriptContext(
2247      frame, context, extension_group, world_id);
2248}
2249
2250void RenderFrameImpl::willReleaseScriptContext(blink::WebFrame* frame,
2251                                               v8::Handle<v8::Context> context,
2252                                               int world_id) {
2253  DCHECK(!frame_ || frame_ == frame);
2254
2255  FOR_EACH_OBSERVER(RenderFrameObserver,
2256                    observers_,
2257                    WillReleaseScriptContext(context, world_id));
2258}
2259
2260void RenderFrameImpl::didFirstVisuallyNonEmptyLayout(blink::WebFrame* frame) {
2261  DCHECK(!frame_ || frame_ == frame);
2262  render_view_->didFirstVisuallyNonEmptyLayout(frame);
2263}
2264
2265void RenderFrameImpl::didChangeContentsSize(blink::WebFrame* frame,
2266                                            const blink::WebSize& size) {
2267  DCHECK(!frame_ || frame_ == frame);
2268  // TODO(nasko): Move implementation here. Needed state:
2269  // * cached_has_main_frame_horizontal_scrollbar_
2270  // * cached_has_main_frame_vertical_scrollbar_
2271  render_view_->didChangeContentsSize(frame, size);
2272}
2273
2274void RenderFrameImpl::didChangeScrollOffset(blink::WebFrame* frame) {
2275  DCHECK(!frame_ || frame_ == frame);
2276  // TODO(nasko): Move implementation here. Needed methods:
2277  // * StartNavStateSyncTimerIfNecessary
2278  render_view_->didChangeScrollOffset(frame);
2279}
2280
2281void RenderFrameImpl::willInsertBody(blink::WebFrame* frame) {
2282  DCHECK(!frame_ || frame_ == frame);
2283  if (!frame->parent()) {
2284    render_view_->Send(new ViewHostMsg_WillInsertBody(
2285        render_view_->GetRoutingID()));
2286  }
2287}
2288
2289void RenderFrameImpl::reportFindInPageMatchCount(int request_id,
2290                                                 int count,
2291                                                 bool final_update) {
2292  int active_match_ordinal = -1;  // -1 = don't update active match ordinal
2293  if (!count)
2294    active_match_ordinal = 0;
2295
2296  render_view_->Send(new ViewHostMsg_Find_Reply(
2297      render_view_->GetRoutingID(), request_id, count,
2298      gfx::Rect(), active_match_ordinal, final_update));
2299}
2300
2301void RenderFrameImpl::reportFindInPageSelection(
2302    int request_id,
2303    int active_match_ordinal,
2304    const blink::WebRect& selection_rect) {
2305  render_view_->Send(new ViewHostMsg_Find_Reply(
2306      render_view_->GetRoutingID(), request_id, -1, selection_rect,
2307      active_match_ordinal, false));
2308}
2309
2310void RenderFrameImpl::requestStorageQuota(
2311    blink::WebFrame* frame,
2312    blink::WebStorageQuotaType type,
2313    unsigned long long requested_size,
2314    blink::WebStorageQuotaCallbacks callbacks) {
2315  DCHECK(!frame_ || frame_ == frame);
2316  WebSecurityOrigin origin = frame->document().securityOrigin();
2317  if (origin.isUnique()) {
2318    // Unique origins cannot store persistent state.
2319    callbacks.didFail(blink::WebStorageQuotaErrorAbort);
2320    return;
2321  }
2322  ChildThread::current()->quota_dispatcher()->RequestStorageQuota(
2323      render_view_->GetRoutingID(), GURL(origin.toString()),
2324      static_cast<quota::StorageType>(type), requested_size,
2325      QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper(callbacks));
2326}
2327
2328void RenderFrameImpl::willOpenSocketStream(
2329    blink::WebSocketStreamHandle* handle) {
2330  WebSocketStreamHandleImpl* impl =
2331      static_cast<WebSocketStreamHandleImpl*>(handle);
2332  impl->SetUserData(handle, new SocketStreamHandleData(routing_id_));
2333}
2334
2335void RenderFrameImpl::willStartUsingPeerConnectionHandler(
2336    blink::WebFrame* frame,
2337    blink::WebRTCPeerConnectionHandler* handler) {
2338  DCHECK(!frame_ || frame_ == frame);
2339#if defined(ENABLE_WEBRTC)
2340  static_cast<RTCPeerConnectionHandler*>(handler)->associateWithFrame(frame);
2341#endif
2342}
2343
2344bool RenderFrameImpl::willCheckAndDispatchMessageEvent(
2345    blink::WebFrame* sourceFrame,
2346    blink::WebFrame* targetFrame,
2347    blink::WebSecurityOrigin targetOrigin,
2348    blink::WebDOMMessageEvent event) {
2349  DCHECK(!frame_ || frame_ == targetFrame);
2350  // TODO(nasko): Move implementation here. Needed state:
2351  // * is_swapped_out_
2352  return render_view_->willCheckAndDispatchMessageEvent(
2353      sourceFrame, targetFrame, targetOrigin, event);
2354}
2355
2356blink::WebString RenderFrameImpl::userAgentOverride(
2357    blink::WebFrame* frame,
2358    const blink::WebURL& url) {
2359  DCHECK(!frame_ || frame_ == frame);
2360  if (!render_view_->webview() || !render_view_->webview()->mainFrame() ||
2361      render_view_->renderer_preferences_.user_agent_override.empty()) {
2362    return blink::WebString();
2363  }
2364
2365  // If we're in the middle of committing a load, the data source we need
2366  // will still be provisional.
2367  WebFrame* main_frame = render_view_->webview()->mainFrame();
2368  WebDataSource* data_source = NULL;
2369  if (main_frame->provisionalDataSource())
2370    data_source = main_frame->provisionalDataSource();
2371  else
2372    data_source = main_frame->dataSource();
2373
2374  InternalDocumentStateData* internal_data = data_source ?
2375      InternalDocumentStateData::FromDataSource(data_source) : NULL;
2376  if (internal_data && internal_data->is_overriding_user_agent())
2377    return WebString::fromUTF8(
2378        render_view_->renderer_preferences_.user_agent_override);
2379  return blink::WebString();
2380}
2381
2382blink::WebString RenderFrameImpl::doNotTrackValue(blink::WebFrame* frame) {
2383  DCHECK(!frame_ || frame_ == frame);
2384  if (render_view_->renderer_preferences_.enable_do_not_track)
2385    return WebString::fromUTF8("1");
2386  return WebString();
2387}
2388
2389bool RenderFrameImpl::allowWebGL(blink::WebFrame* frame, bool default_value) {
2390  DCHECK(!frame_ || frame_ == frame);
2391  if (!default_value)
2392    return false;
2393
2394  bool blocked = true;
2395  render_view_->Send(new ViewHostMsg_Are3DAPIsBlocked(
2396      render_view_->GetRoutingID(),
2397      GURL(frame->top()->document().securityOrigin().toString()),
2398      THREE_D_API_TYPE_WEBGL,
2399      &blocked));
2400  return !blocked;
2401}
2402
2403void RenderFrameImpl::didLoseWebGLContext(blink::WebFrame* frame,
2404                                          int arb_robustness_status_code) {
2405  DCHECK(!frame_ || frame_ == frame);
2406  render_view_->Send(new ViewHostMsg_DidLose3DContext(
2407      GURL(frame->top()->document().securityOrigin().toString()),
2408      THREE_D_API_TYPE_WEBGL,
2409      arb_robustness_status_code));
2410}
2411
2412void RenderFrameImpl::forwardInputEvent(const blink::WebInputEvent* event) {
2413  Send(new FrameHostMsg_ForwardInputEvent(routing_id_, event));
2414}
2415
2416void RenderFrameImpl::initializeChildFrame(const blink::WebRect& frame_rect,
2417                                           float scale_factor) {
2418  Send(new FrameHostMsg_InitializeChildFrame(
2419      routing_id_, frame_rect, scale_factor));
2420}
2421
2422void RenderFrameImpl::AddObserver(RenderFrameObserver* observer) {
2423  observers_.AddObserver(observer);
2424}
2425
2426void RenderFrameImpl::RemoveObserver(RenderFrameObserver* observer) {
2427  observer->RenderFrameGone();
2428  observers_.RemoveObserver(observer);
2429}
2430
2431void RenderFrameImpl::OnStop() {
2432  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, OnStop());
2433}
2434
2435// Tell the embedding application that the URL of the active page has changed.
2436void RenderFrameImpl::UpdateURL(blink::WebFrame* frame) {
2437  DCHECK(!frame_ || frame_ == frame);
2438  WebDataSource* ds = frame->dataSource();
2439  DCHECK(ds);
2440
2441  const WebURLRequest& request = ds->request();
2442  const WebURLRequest& original_request = ds->originalRequest();
2443  const WebURLResponse& response = ds->response();
2444
2445  DocumentState* document_state = DocumentState::FromDataSource(ds);
2446  NavigationState* navigation_state = document_state->navigation_state();
2447  InternalDocumentStateData* internal_data =
2448      InternalDocumentStateData::FromDocumentState(document_state);
2449
2450  FrameHostMsg_DidCommitProvisionalLoad_Params params;
2451  params.http_status_code = response.httpStatusCode();
2452  params.is_post = false;
2453  params.post_id = -1;
2454  params.page_id = render_view_->page_id_;
2455  params.frame_unique_name = frame->uniqueName();
2456  params.socket_address.set_host(response.remoteIPAddress().utf8());
2457  params.socket_address.set_port(response.remotePort());
2458  WebURLResponseExtraDataImpl* extra_data = GetExtraDataFromResponse(response);
2459  if (extra_data)
2460    params.was_fetched_via_proxy = extra_data->was_fetched_via_proxy();
2461  params.was_within_same_page = navigation_state->was_within_same_page();
2462  params.security_info = response.securityInfo();
2463
2464  // Set the URL to be displayed in the browser UI to the user.
2465  params.url = render_view_->GetLoadingUrl(frame);
2466  DCHECK(!is_swapped_out_ || params.url == GURL(kSwappedOutURL));
2467
2468  if (frame->document().baseURL() != params.url)
2469    params.base_url = frame->document().baseURL();
2470
2471  GetRedirectChain(ds, &params.redirects);
2472  params.should_update_history = !ds->hasUnreachableURL() &&
2473      !response.isMultipartPayload() && (response.httpStatusCode() != 404);
2474
2475  params.searchable_form_url = internal_data->searchable_form_url();
2476  params.searchable_form_encoding = internal_data->searchable_form_encoding();
2477
2478  params.gesture = render_view_->navigation_gesture_;
2479  render_view_->navigation_gesture_ = NavigationGestureUnknown;
2480
2481  // Make navigation state a part of the DidCommitProvisionalLoad message so
2482  // that commited entry has it at all times.
2483  WebHistoryItem item = frame->currentHistoryItem();
2484  if (item.isNull()) {
2485    item.initialize();
2486    item.setURLString(request.url().spec().utf16());
2487  }
2488  params.page_state = HistoryItemToPageState(item);
2489
2490  if (!frame->parent()) {
2491    // Top-level navigation.
2492
2493    // Reset the zoom limits in case a plugin had changed them previously. This
2494    // will also call us back which will cause us to send a message to
2495    // update WebContentsImpl.
2496    render_view_->webview()->zoomLimitsChanged(
2497        ZoomFactorToZoomLevel(kMinimumZoomFactor),
2498        ZoomFactorToZoomLevel(kMaximumZoomFactor));
2499
2500    // Set zoom level, but don't do it for full-page plugin since they don't use
2501    // the same zoom settings.
2502    HostZoomLevels::iterator host_zoom =
2503        render_view_->host_zoom_levels_.find(GURL(request.url()));
2504    if (render_view_->webview()->mainFrame()->document().isPluginDocument()) {
2505      // Reset the zoom levels for plugins.
2506      render_view_->webview()->setZoomLevel(0);
2507    } else {
2508      if (host_zoom != render_view_->host_zoom_levels_.end())
2509        render_view_->webview()->setZoomLevel(host_zoom->second);
2510    }
2511
2512    if (host_zoom != render_view_->host_zoom_levels_.end()) {
2513      // This zoom level was merely recorded transiently for this load.  We can
2514      // erase it now.  If at some point we reload this page, the browser will
2515      // send us a new, up-to-date zoom level.
2516      render_view_->host_zoom_levels_.erase(host_zoom);
2517    }
2518
2519    // Update contents MIME type for main frame.
2520    params.contents_mime_type = ds->response().mimeType().utf8();
2521
2522    params.transition = navigation_state->transition_type();
2523    if (!PageTransitionIsMainFrame(params.transition)) {
2524      // If the main frame does a load, it should not be reported as a subframe
2525      // navigation.  This can occur in the following case:
2526      // 1. You're on a site with frames.
2527      // 2. You do a subframe navigation.  This is stored with transition type
2528      //    MANUAL_SUBFRAME.
2529      // 3. You navigate to some non-frame site, say, google.com.
2530      // 4. You navigate back to the page from step 2.  Since it was initially
2531      //    MANUAL_SUBFRAME, it will be that same transition type here.
2532      // We don't want that, because any navigation that changes the toplevel
2533      // frame should be tracked as a toplevel navigation (this allows us to
2534      // update the URL bar, etc).
2535      params.transition = PAGE_TRANSITION_LINK;
2536    }
2537
2538    // If the page contained a client redirect (meta refresh, document.loc...),
2539    // set the referrer and transition appropriately.
2540    if (ds->isClientRedirect()) {
2541      params.referrer =
2542          Referrer(params.redirects[0], ds->request().referrerPolicy());
2543      params.transition = static_cast<PageTransition>(
2544          params.transition | PAGE_TRANSITION_CLIENT_REDIRECT);
2545    } else {
2546      params.referrer = RenderViewImpl::GetReferrerFromRequest(
2547          frame, ds->request());
2548    }
2549
2550    base::string16 method = request.httpMethod();
2551    if (EqualsASCII(method, "POST")) {
2552      params.is_post = true;
2553      params.post_id = ExtractPostId(item);
2554    }
2555
2556    // Send the user agent override back.
2557    params.is_overriding_user_agent = internal_data->is_overriding_user_agent();
2558
2559    // Track the URL of the original request.  We use the first entry of the
2560    // redirect chain if it exists because the chain may have started in another
2561    // process.
2562    if (params.redirects.size() > 0)
2563      params.original_request_url = params.redirects.at(0);
2564    else
2565      params.original_request_url = original_request.url();
2566
2567    params.history_list_was_cleared =
2568        navigation_state->history_list_was_cleared();
2569
2570    // Save some histogram data so we can compute the average memory used per
2571    // page load of the glyphs.
2572    UMA_HISTOGRAM_COUNTS_10000("Memory.GlyphPagesPerLoad",
2573                               blink::WebGlyphCache::pageCount());
2574
2575    // This message needs to be sent before any of allowScripts(),
2576    // allowImages(), allowPlugins() is called for the new page, so that when
2577    // these functions send a ViewHostMsg_ContentBlocked message, it arrives
2578    // after the FrameHostMsg_DidCommitProvisionalLoad message.
2579    Send(new FrameHostMsg_DidCommitProvisionalLoad(routing_id_, params));
2580  } else {
2581    // Subframe navigation: the type depends on whether this navigation
2582    // generated a new session history entry. When they do generate a session
2583    // history entry, it means the user initiated the navigation and we should
2584    // mark it as such. This test checks if this is the first time UpdateURL
2585    // has been called since WillNavigateToURL was called to initiate the load.
2586    if (render_view_->page_id_ > render_view_->last_page_id_sent_to_browser_)
2587      params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
2588    else
2589      params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
2590
2591    DCHECK(!navigation_state->history_list_was_cleared());
2592    params.history_list_was_cleared = false;
2593
2594    // Don't send this message while the subframe is swapped out.
2595    if (!is_swapped_out())
2596      Send(new FrameHostMsg_DidCommitProvisionalLoad(routing_id_, params));
2597  }
2598
2599  render_view_->last_page_id_sent_to_browser_ =
2600      std::max(render_view_->last_page_id_sent_to_browser_,
2601               render_view_->page_id_);
2602
2603  // If we end up reusing this WebRequest (for example, due to a #ref click),
2604  // we don't want the transition type to persist.  Just clear it.
2605  navigation_state->set_transition_type(PAGE_TRANSITION_LINK);
2606}
2607
2608WebElement RenderFrameImpl::GetFocusedElement() {
2609  WebDocument doc = frame_->document();
2610  if (!doc.isNull())
2611    return doc.focusedElement();
2612
2613  return WebElement();
2614}
2615
2616void RenderFrameImpl::didStartLoading(bool to_different_document) {
2617  if (is_loading_) {
2618    DVLOG(1) << "didStartLoading called while loading";
2619    return;
2620  }
2621
2622  is_loading_ = true;
2623
2624  bool view_was_loading = render_view_->is_loading();
2625  render_view_->FrameDidStartLoading(frame_);
2626
2627  if (!view_was_loading)
2628    Send(new FrameHostMsg_DidStartLoading(routing_id_, to_different_document));
2629}
2630
2631void RenderFrameImpl::didStopLoading() {
2632  if (!is_loading_) {
2633    DVLOG(1) << "DidStopLoading called while not loading";
2634    return;
2635  }
2636
2637  DCHECK(render_view_->is_loading());
2638  is_loading_ = false;
2639
2640  render_view_->FrameDidStopLoading(frame_);
2641
2642  // NOTE: For now we're doing the safest thing, and sending out notification
2643  // when done loading. This currently isn't an issue as the favicon is only
2644  // displayed when done loading. Ideally we would send notification when
2645  // finished parsing the head, but webkit doesn't support that yet.
2646  // The feed discovery code would also benefit from access to the head.
2647  // NOTE: Sending of the IPC message happens through the top-level frame.
2648  if (!render_view_->is_loading())
2649    Send(new FrameHostMsg_DidStopLoading(routing_id_));
2650}
2651
2652void RenderFrameImpl::didChangeLoadProgress(double load_progress) {
2653  render_view_->FrameDidChangeLoadProgress(frame_, load_progress);
2654}
2655
2656WebNavigationPolicy RenderFrameImpl::DecidePolicyForNavigation(
2657    RenderFrame* render_frame,
2658    WebFrame* frame,
2659    WebDataSource::ExtraData* extraData,
2660    const WebURLRequest& request,
2661    WebNavigationType type,
2662    WebNavigationPolicy default_policy,
2663    bool is_redirect) {
2664#ifdef OS_ANDROID
2665  // The handlenavigation API is deprecated and will be removed once
2666  // crbug.com/325351 is resolved.
2667  if (request.url() != GURL(kSwappedOutURL) &&
2668      GetContentClient()->renderer()->HandleNavigation(
2669          render_frame,
2670          static_cast<DocumentState*>(extraData),
2671          render_view_->opener_id_,
2672          frame,
2673          request,
2674          type,
2675          default_policy,
2676          is_redirect)) {
2677    return blink::WebNavigationPolicyIgnore;
2678  }
2679#endif
2680
2681  Referrer referrer(RenderViewImpl::GetReferrerFromRequest(frame, request));
2682
2683  if (is_swapped_out_ || render_view_->is_swapped_out()) {
2684    if (request.url() != GURL(kSwappedOutURL)) {
2685      // Targeted links may try to navigate a swapped out frame.  Allow the
2686      // browser process to navigate the tab instead.  Note that it is also
2687      // possible for non-targeted navigations (from this view) to arrive
2688      // here just after we are swapped out.  It's ok to send them to the
2689      // browser, as long as they're for the top level frame.
2690      // TODO(creis): Ensure this supports targeted form submissions when
2691      // fixing http://crbug.com/101395.
2692      if (frame->parent() == NULL) {
2693        OpenURL(frame, request.url(), referrer, default_policy);
2694        return blink::WebNavigationPolicyIgnore;  // Suppress the load here.
2695      }
2696
2697      // We should otherwise ignore in-process iframe navigations, if they
2698      // arrive just after we are swapped out.
2699      return blink::WebNavigationPolicyIgnore;
2700    }
2701
2702    // Allow kSwappedOutURL to complete.
2703    return default_policy;
2704  }
2705
2706  // Webkit is asking whether to navigate to a new URL.
2707  // This is fine normally, except if we're showing UI from one security
2708  // context and they're trying to navigate to a different context.
2709  const GURL& url = request.url();
2710
2711  // A content initiated navigation may have originated from a link-click,
2712  // script, drag-n-drop operation, etc.
2713  bool is_content_initiated = static_cast<DocumentState*>(extraData)->
2714          navigation_state()->is_content_initiated();
2715
2716  // Experimental:
2717  // If --enable-strict-site-isolation or --site-per-process is enabled, send
2718  // all top-level navigations to the browser to let it swap processes when
2719  // crossing site boundaries.  This is currently expected to break some script
2720  // calls and navigations, such as form submissions.
2721  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
2722  bool force_swap_due_to_flag =
2723      command_line.HasSwitch(switches::kEnableStrictSiteIsolation) ||
2724      command_line.HasSwitch(switches::kSitePerProcess);
2725  if (force_swap_due_to_flag &&
2726      !frame->parent() && (is_content_initiated || is_redirect)) {
2727    WebString origin_str = frame->document().securityOrigin().toString();
2728    GURL frame_url(origin_str.utf8().data());
2729    // TODO(cevans): revisit whether this site check is still necessary once
2730    // crbug.com/101395 is fixed.
2731    bool same_domain_or_host =
2732        net::registry_controlled_domains::SameDomainOrHost(
2733            frame_url,
2734            url,
2735            net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
2736    if (!same_domain_or_host || frame_url.scheme() != url.scheme()) {
2737      OpenURL(frame, url, referrer, default_policy);
2738      return blink::WebNavigationPolicyIgnore;
2739    }
2740  }
2741
2742  // If the browser is interested, then give it a chance to look at the request.
2743  if (is_content_initiated) {
2744    bool is_form_post = ((type == blink::WebNavigationTypeFormSubmitted) ||
2745                         (type == blink::WebNavigationTypeFormResubmitted)) &&
2746                        EqualsASCII(request.httpMethod(), "POST");
2747    bool browser_handles_request =
2748        render_view_->renderer_preferences_
2749            .browser_handles_non_local_top_level_requests
2750        && IsNonLocalTopLevelNavigation(url, frame, type, is_form_post);
2751    if (!browser_handles_request) {
2752      browser_handles_request = IsTopLevelNavigation(frame) &&
2753          render_view_->renderer_preferences_
2754              .browser_handles_all_top_level_requests;
2755    }
2756
2757    if (browser_handles_request) {
2758      // Reset these counters as the RenderView could be reused for the next
2759      // navigation.
2760      render_view_->page_id_ = -1;
2761      render_view_->last_page_id_sent_to_browser_ = -1;
2762      OpenURL(frame, url, referrer, default_policy);
2763      return blink::WebNavigationPolicyIgnore;  // Suppress the load here.
2764    }
2765  }
2766
2767  // Use the frame's original request's URL rather than the document's URL for
2768  // subsequent checks.  For a popup, the document's URL may become the opener
2769  // window's URL if the opener has called document.write().
2770  // See http://crbug.com/93517.
2771  GURL old_url(frame->dataSource()->request().url());
2772
2773  // Detect when we're crossing a permission-based boundary (e.g. into or out of
2774  // an extension or app origin, leaving a WebUI page, etc). We only care about
2775  // top-level navigations (not iframes). But we sometimes navigate to
2776  // about:blank to clear a tab, and we want to still allow that.
2777  //
2778  // Note: this is known to break POST submissions when crossing process
2779  // boundaries until http://crbug.com/101395 is fixed.  This is better for
2780  // security than loading a WebUI, extension or app page in the wrong process.
2781  // POST requests don't work because this mechanism does not preserve form
2782  // POST data. We will need to send the request's httpBody data up to the
2783  // browser process, and issue a special POST navigation in WebKit (via
2784  // FrameLoader::loadFrameRequest). See ResourceDispatcher and WebURLLoaderImpl
2785  // for examples of how to send the httpBody data.
2786  if (!frame->parent() && is_content_initiated && !url.SchemeIs(kAboutScheme)) {
2787    bool send_referrer = false;
2788
2789    // All navigations to or from WebUI URLs or within WebUI-enabled
2790    // RenderProcesses must be handled by the browser process so that the
2791    // correct bindings and data sources can be registered.
2792    // Similarly, navigations to view-source URLs or within ViewSource mode
2793    // must be handled by the browser process (except for reloads - those are
2794    // safe to leave within the renderer).
2795    // Lastly, access to file:// URLs from non-file:// URL pages must be
2796    // handled by the browser so that ordinary renderer processes don't get
2797    // blessed with file permissions.
2798    int cumulative_bindings = RenderProcess::current()->GetEnabledBindings();
2799    bool is_initial_navigation = render_view_->page_id_ == -1;
2800    bool should_fork = HasWebUIScheme(url) || HasWebUIScheme(old_url) ||
2801        (cumulative_bindings & BINDINGS_POLICY_WEB_UI) ||
2802        url.SchemeIs(kViewSourceScheme) ||
2803        (frame->isViewSourceModeEnabled() &&
2804            type != blink::WebNavigationTypeReload);
2805
2806    if (!should_fork && url.SchemeIs(kFileScheme)) {
2807      // Fork non-file to file opens.  Check the opener URL if this is the
2808      // initial navigation in a newly opened window.
2809      GURL source_url(old_url);
2810      if (is_initial_navigation && source_url.is_empty() && frame->opener())
2811        source_url = frame->opener()->top()->document().url();
2812      DCHECK(!source_url.is_empty());
2813      should_fork = !source_url.SchemeIs(kFileScheme);
2814    }
2815
2816    if (!should_fork) {
2817      // Give the embedder a chance.
2818      should_fork = GetContentClient()->renderer()->ShouldFork(
2819          frame, url, request.httpMethod().utf8(), is_initial_navigation,
2820          is_redirect, &send_referrer);
2821    }
2822
2823    if (should_fork) {
2824      OpenURL(
2825          frame, url, send_referrer ? referrer : Referrer(), default_policy);
2826      return blink::WebNavigationPolicyIgnore;  // Suppress the load here.
2827    }
2828  }
2829
2830  // Detect when a page is "forking" a new tab that can be safely rendered in
2831  // its own process.  This is done by sites like Gmail that try to open links
2832  // in new windows without script connections back to the original page.  We
2833  // treat such cases as browser navigations (in which we will create a new
2834  // renderer for a cross-site navigation), rather than WebKit navigations.
2835  //
2836  // We use the following heuristic to decide whether to fork a new page in its
2837  // own process:
2838  // The parent page must open a new tab to about:blank, set the new tab's
2839  // window.opener to null, and then redirect the tab to a cross-site URL using
2840  // JavaScript.
2841  //
2842  // TODO(creis): Deprecate this logic once we can rely on rel=noreferrer
2843  // (see below).
2844  bool is_fork =
2845      // Must start from a tab showing about:blank, which is later redirected.
2846      old_url == GURL(kAboutBlankURL) &&
2847      // Must be the first real navigation of the tab.
2848      render_view_->historyBackListCount() < 1 &&
2849      render_view_->historyForwardListCount() < 1 &&
2850      // The parent page must have set the child's window.opener to null before
2851      // redirecting to the desired URL.
2852      frame->opener() == NULL &&
2853      // Must be a top-level frame.
2854      frame->parent() == NULL &&
2855      // Must not have issued the request from this page.
2856      is_content_initiated &&
2857      // Must be targeted at the current tab.
2858      default_policy == blink::WebNavigationPolicyCurrentTab &&
2859      // Must be a JavaScript navigation, which appears as "other".
2860      type == blink::WebNavigationTypeOther;
2861
2862  if (is_fork) {
2863    // Open the URL via the browser, not via WebKit.
2864    OpenURL(frame, url, Referrer(), default_policy);
2865    return blink::WebNavigationPolicyIgnore;
2866  }
2867
2868  return default_policy;
2869}
2870
2871void RenderFrameImpl::OpenURL(WebFrame* frame,
2872                              const GURL& url,
2873                              const Referrer& referrer,
2874                              WebNavigationPolicy policy) {
2875  DCHECK_EQ(frame_, frame);
2876
2877  FrameHostMsg_OpenURL_Params params;
2878  params.url = url;
2879  params.referrer = referrer;
2880  params.disposition = RenderViewImpl::NavigationPolicyToDisposition(policy);
2881  WebDataSource* ds = frame->provisionalDataSource();
2882  if (ds) {
2883    DocumentState* document_state = DocumentState::FromDataSource(ds);
2884    NavigationState* navigation_state = document_state->navigation_state();
2885    if (navigation_state->is_content_initiated()) {
2886      params.should_replace_current_entry = ds->replacesCurrentHistoryItem();
2887    } else {
2888      // This is necessary to preserve the should_replace_current_entry value on
2889      // cross-process redirects, in the event it was set by a previous process.
2890      //
2891      // TODO(davidben): Avoid this awkward duplication of state. See comment on
2892      // NavigationState::should_replace_current_entry().
2893      params.should_replace_current_entry =
2894          navigation_state->should_replace_current_entry();
2895    }
2896  } else {
2897    params.should_replace_current_entry = false;
2898  }
2899  params.user_gesture = WebUserGestureIndicator::isProcessingUserGesture();
2900  if (GetContentClient()->renderer()->AllowPopup())
2901    params.user_gesture = true;
2902
2903  if (policy == blink::WebNavigationPolicyNewBackgroundTab ||
2904      policy == blink::WebNavigationPolicyNewForegroundTab ||
2905      policy == blink::WebNavigationPolicyNewWindow ||
2906      policy == blink::WebNavigationPolicyNewPopup) {
2907    WebUserGestureIndicator::consumeUserGesture();
2908  }
2909
2910  Send(new FrameHostMsg_OpenURL(routing_id_, params));
2911}
2912
2913void RenderFrameImpl::SyncSelectionIfRequired() {
2914  base::string16 text;
2915  size_t offset;
2916  gfx::Range range;
2917#if defined(ENABLE_PLUGINS)
2918  if (render_view_->focused_pepper_plugin_) {
2919    render_view_->focused_pepper_plugin_->GetSurroundingText(&text, &range);
2920    offset = 0;  // Pepper API does not support offset reporting.
2921    // TODO(kinaba): cut as needed.
2922  } else
2923#endif
2924  {
2925    size_t location, length;
2926    if (!GetRenderWidget()->webwidget()->caretOrSelectionRange(
2927            &location, &length)) {
2928      return;
2929    }
2930
2931    range = gfx::Range(location, location + length);
2932
2933    if (GetRenderWidget()->webwidget()->textInputInfo().type !=
2934            blink::WebTextInputTypeNone) {
2935      // If current focused element is editable, we will send 100 more chars
2936      // before and after selection. It is for input method surrounding text
2937      // feature.
2938      if (location > kExtraCharsBeforeAndAfterSelection)
2939        offset = location - kExtraCharsBeforeAndAfterSelection;
2940      else
2941        offset = 0;
2942      length = location + length - offset + kExtraCharsBeforeAndAfterSelection;
2943      WebRange webrange = WebRange::fromDocumentRange(frame_, offset, length);
2944      if (!webrange.isNull())
2945        text = WebRange::fromDocumentRange(
2946            frame_, offset, length).toPlainText();
2947    } else {
2948      offset = location;
2949      text = frame_->selectionAsText();
2950      // http://crbug.com/101435
2951      // In some case, frame->selectionAsText() returned text's length is not
2952      // equal to the length returned from webwidget()->caretOrSelectionRange().
2953      // So we have to set the range according to text.length().
2954      range.set_end(range.start() + text.length());
2955    }
2956  }
2957
2958  // Sometimes we get repeated didChangeSelection calls from webkit when
2959  // the selection hasn't actually changed. We don't want to report these
2960  // because it will cause us to continually claim the X clipboard.
2961  if (selection_text_offset_ != offset ||
2962      selection_range_ != range ||
2963      selection_text_ != text) {
2964    selection_text_ = text;
2965    selection_text_offset_ = offset;
2966    selection_range_ = range;
2967    // This IPC is dispatched by RenderWidetHost, so use its routing ID.
2968    Send(new ViewHostMsg_SelectionChanged(
2969        GetRenderWidget()->routing_id(), text, offset, range));
2970  }
2971  GetRenderWidget()->UpdateSelectionBounds();
2972}
2973
2974}  // namespace content
2975