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