render_frame_impl.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/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/asan_invalid_access.h"
14#include "base/debug/dump_without_crashing.h"
15#include "base/i18n/char_iterator.h"
16#include "base/metrics/histogram.h"
17#include "base/process/kill.h"
18#include "base/process/process.h"
19#include "base/strings/string16.h"
20#include "base/strings/utf_string_conversions.h"
21#include "base/time/time.h"
22#include "content/child/appcache/appcache_dispatcher.h"
23#include "content/child/plugin_messages.h"
24#include "content/child/quota_dispatcher.h"
25#include "content/child/request_extra_data.h"
26#include "content/child/service_worker/service_worker_network_provider.h"
27#include "content/child/service_worker/web_service_worker_provider_impl.h"
28#include "content/child/web_socket_stream_handle_impl.h"
29#include "content/child/web_url_request_util.h"
30#include "content/child/webmessageportchannel_impl.h"
31#include "content/child/websocket_bridge.h"
32#include "content/child/weburlresponse_extradata_impl.h"
33#include "content/common/clipboard_messages.h"
34#include "content/common/frame_messages.h"
35#include "content/common/input_messages.h"
36#include "content/common/service_worker/service_worker_types.h"
37#include "content/common/socket_stream_handle_data.h"
38#include "content/common/swapped_out_messages.h"
39#include "content/common/view_messages.h"
40#include "content/public/common/bindings_policy.h"
41#include "content/public/common/content_constants.h"
42#include "content/public/common/content_switches.h"
43#include "content/public/common/context_menu_params.h"
44#include "content/public/common/url_constants.h"
45#include "content/public/common/url_utils.h"
46#include "content/public/renderer/content_renderer_client.h"
47#include "content/public/renderer/context_menu_client.h"
48#include "content/public/renderer/document_state.h"
49#include "content/public/renderer/navigation_state.h"
50#include "content/public/renderer/render_frame_observer.h"
51#include "content/renderer/accessibility/renderer_accessibility.h"
52#include "content/renderer/accessibility/renderer_accessibility_complete.h"
53#include "content/renderer/accessibility/renderer_accessibility_focus_only.h"
54#include "content/renderer/browser_plugin/browser_plugin.h"
55#include "content/renderer/browser_plugin/browser_plugin_manager.h"
56#include "content/renderer/child_frame_compositing_helper.h"
57#include "content/renderer/context_menu_params_builder.h"
58#include "content/renderer/devtools/devtools_agent.h"
59#include "content/renderer/dom_automation_controller.h"
60#include "content/renderer/dom_utils.h"
61#include "content/renderer/geolocation_dispatcher.h"
62#include "content/renderer/history_controller.h"
63#include "content/renderer/history_serialization.h"
64#include "content/renderer/image_loading_helper.h"
65#include "content/renderer/ime_event_guard.h"
66#include "content/renderer/internal_document_state_data.h"
67#include "content/renderer/media/audio_renderer_mixer_manager.h"
68#include "content/renderer/media/media_stream_dispatcher.h"
69#include "content/renderer/media/media_stream_impl.h"
70#include "content/renderer/media/media_stream_renderer_factory.h"
71#include "content/renderer/media/midi_dispatcher.h"
72#include "content/renderer/media/render_media_log.h"
73#include "content/renderer/media/webcontentdecryptionmodule_impl.h"
74#include "content/renderer/media/webmediaplayer_impl.h"
75#include "content/renderer/media/webmediaplayer_ms.h"
76#include "content/renderer/media/webmediaplayer_params.h"
77#include "content/renderer/notification_permission_dispatcher.h"
78#include "content/renderer/notification_provider.h"
79#include "content/renderer/npapi/plugin_channel_host.h"
80#include "content/renderer/push_messaging_dispatcher.h"
81#include "content/renderer/render_frame_proxy.h"
82#include "content/renderer/render_process.h"
83#include "content/renderer/render_thread_impl.h"
84#include "content/renderer/render_view_impl.h"
85#include "content/renderer/render_widget_fullscreen_pepper.h"
86#include "content/renderer/renderer_webapplicationcachehost_impl.h"
87#include "content/renderer/renderer_webcolorchooser_impl.h"
88#include "content/renderer/screen_orientation/screen_orientation_dispatcher.h"
89#include "content/renderer/shared_worker_repository.h"
90#include "content/renderer/v8_value_converter_impl.h"
91#include "content/renderer/websharedworker_proxy.h"
92#include "media/base/audio_renderer_mixer_input.h"
93#include "net/base/data_url.h"
94#include "net/base/net_errors.h"
95#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
96#include "net/http/http_util.h"
97#include "third_party/WebKit/public/platform/WebStorageQuotaCallbacks.h"
98#include "third_party/WebKit/public/platform/WebString.h"
99#include "third_party/WebKit/public/platform/WebURL.h"
100#include "third_party/WebKit/public/platform/WebURLError.h"
101#include "third_party/WebKit/public/platform/WebURLResponse.h"
102#include "third_party/WebKit/public/platform/WebVector.h"
103#include "third_party/WebKit/public/web/WebColorSuggestion.h"
104#include "third_party/WebKit/public/web/WebDocument.h"
105#include "third_party/WebKit/public/web/WebGlyphCache.h"
106#include "third_party/WebKit/public/web/WebLocalFrame.h"
107#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
108#include "third_party/WebKit/public/web/WebNavigationPolicy.h"
109#include "third_party/WebKit/public/web/WebPlugin.h"
110#include "third_party/WebKit/public/web/WebPluginParams.h"
111#include "third_party/WebKit/public/web/WebRange.h"
112#include "third_party/WebKit/public/web/WebScriptSource.h"
113#include "third_party/WebKit/public/web/WebSearchableFormData.h"
114#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
115#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
116#include "third_party/WebKit/public/web/WebSurroundingText.h"
117#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
118#include "third_party/WebKit/public/web/WebView.h"
119
120#if defined(ENABLE_PLUGINS)
121#include "content/renderer/npapi/webplugin_impl.h"
122#include "content/renderer/pepper/pepper_browser_connection.h"
123#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
124#include "content/renderer/pepper/pepper_webplugin_impl.h"
125#include "content/renderer/pepper/plugin_module.h"
126#endif
127
128#if defined(ENABLE_WEBRTC)
129#include "content/renderer/media/rtc_peer_connection_handler.h"
130#endif
131
132#if defined(OS_ANDROID)
133#include <cpu-features.h>
134
135#include "content/common/gpu/client/context_provider_command_buffer.h"
136#include "content/renderer/android/synchronous_compositor_factory.h"
137#include "content/renderer/java/gin_java_bridge_dispatcher.h"
138#include "content/renderer/media/android/renderer_media_player_manager.h"
139#include "content/renderer/media/android/stream_texture_factory_impl.h"
140#include "content/renderer/media/android/webmediaplayer_android.h"
141#endif
142
143#if defined(ENABLE_BROWSER_CDMS)
144#include "content/renderer/media/crypto/renderer_cdm_manager.h"
145#endif
146
147using blink::WebContextMenuData;
148using blink::WebData;
149using blink::WebDataSource;
150using blink::WebDocument;
151using blink::WebElement;
152using blink::WebExternalPopupMenu;
153using blink::WebExternalPopupMenuClient;
154using blink::WebFrame;
155using blink::WebHistoryItem;
156using blink::WebHTTPBody;
157using blink::WebLocalFrame;
158using blink::WebMediaPlayer;
159using blink::WebMediaPlayerClient;
160using blink::WebNavigationPolicy;
161using blink::WebNavigationType;
162using blink::WebNode;
163using blink::WebPluginParams;
164using blink::WebPopupMenuInfo;
165using blink::WebRange;
166using blink::WebReferrerPolicy;
167using blink::WebScriptSource;
168using blink::WebSearchableFormData;
169using blink::WebSecurityOrigin;
170using blink::WebSecurityPolicy;
171using blink::WebServiceWorkerProvider;
172using blink::WebStorageQuotaCallbacks;
173using blink::WebString;
174using blink::WebURL;
175using blink::WebURLError;
176using blink::WebURLRequest;
177using blink::WebURLResponse;
178using blink::WebUserGestureIndicator;
179using blink::WebVector;
180using blink::WebView;
181using base::Time;
182using base::TimeDelta;
183
184namespace content {
185
186namespace {
187
188const char kDefaultAcceptHeader[] =
189    "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/"
190    "*;q=0.8";
191const char kAcceptHeader[] = "Accept";
192
193const size_t kExtraCharsBeforeAndAfterSelection = 100;
194
195typedef std::map<int, RenderFrameImpl*> RoutingIDFrameMap;
196static base::LazyInstance<RoutingIDFrameMap> g_routing_id_frame_map =
197    LAZY_INSTANCE_INITIALIZER;
198
199typedef std::map<blink::WebFrame*, RenderFrameImpl*> FrameMap;
200base::LazyInstance<FrameMap> g_frame_map = LAZY_INSTANCE_INITIALIZER;
201
202int64 ExtractPostId(const WebHistoryItem& item) {
203  if (item.isNull())
204    return -1;
205
206  if (item.httpBody().isNull())
207    return -1;
208
209  return item.httpBody().identifier();
210}
211
212WebURLResponseExtraDataImpl* GetExtraDataFromResponse(
213    const WebURLResponse& response) {
214  return static_cast<WebURLResponseExtraDataImpl*>(response.extraData());
215}
216
217void GetRedirectChain(WebDataSource* ds, std::vector<GURL>* result) {
218  // Replace any occurrences of swappedout:// with about:blank.
219  const WebURL& blank_url = GURL(url::kAboutBlankURL);
220  WebVector<WebURL> urls;
221  ds->redirectChain(urls);
222  result->reserve(urls.size());
223  for (size_t i = 0; i < urls.size(); ++i) {
224    if (urls[i] != GURL(kSwappedOutURL))
225      result->push_back(urls[i]);
226    else
227      result->push_back(blank_url);
228  }
229}
230
231// Returns the original request url. If there is no redirect, the original
232// url is the same as ds->request()->url(). If the WebDataSource belongs to a
233// frame was loaded by loadData, the original url will be ds->unreachableURL()
234static GURL GetOriginalRequestURL(WebDataSource* ds) {
235  // WebDataSource has unreachable URL means that the frame is loaded through
236  // blink::WebFrame::loadData(), and the base URL will be in the redirect
237  // chain. However, we never visited the baseURL. So in this case, we should
238  // use the unreachable URL as the original URL.
239  if (ds->hasUnreachableURL())
240    return ds->unreachableURL();
241
242  std::vector<GURL> redirects;
243  GetRedirectChain(ds, &redirects);
244  if (!redirects.empty())
245    return redirects.at(0);
246
247  return ds->originalRequest().url();
248}
249
250NOINLINE static void CrashIntentionally() {
251  // NOTE(shess): Crash directly rather than using NOTREACHED() so
252  // that the signature is easier to triage in crash reports.
253  volatile int* zero = NULL;
254  *zero = 0;
255}
256
257#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
258NOINLINE static void MaybeTriggerAsanError(const GURL& url) {
259  // NOTE(rogerm): We intentionally perform an invalid heap access here in
260  //     order to trigger an Address Sanitizer (ASAN) error report.
261  const char kCrashDomain[] = "crash";
262  const char kHeapOverflow[] = "/heap-overflow";
263  const char kHeapUnderflow[] = "/heap-underflow";
264  const char kUseAfterFree[] = "/use-after-free";
265#if defined(SYZYASAN)
266  const char kCorruptHeapBlock[] = "/corrupt-heap-block";
267  const char kCorruptHeap[] = "/corrupt-heap";
268#endif
269
270  if (!url.DomainIs(kCrashDomain, sizeof(kCrashDomain) - 1))
271    return;
272
273  if (!url.has_path())
274    return;
275
276  std::string crash_type(url.path());
277  if (crash_type == kHeapOverflow) {
278    base::debug::AsanHeapOverflow();
279  } else if (crash_type == kHeapUnderflow ) {
280    base::debug::AsanHeapUnderflow();
281  } else if (crash_type == kUseAfterFree) {
282    base::debug::AsanHeapUseAfterFree();
283#if defined(SYZYASAN)
284  } else if (crash_type == kCorruptHeapBlock) {
285    base::debug::AsanCorruptHeapBlock();
286  } else if (crash_type == kCorruptHeap) {
287    base::debug::AsanCorruptHeap();
288#endif
289  }
290}
291#endif  // ADDRESS_SANITIZER || SYZYASAN
292
293static void MaybeHandleDebugURL(const GURL& url) {
294  if (!url.SchemeIs(kChromeUIScheme))
295    return;
296  if (url == GURL(kChromeUICrashURL)) {
297    CrashIntentionally();
298  } else if (url == GURL(kChromeUIDumpURL)) {
299    // This URL will only correctly create a crash dump file if content is
300    // hosted in a process that has correctly called
301    // base::debug::SetDumpWithoutCrashingFunction.  Refer to the documentation
302    // of base::debug::DumpWithoutCrashing for more details.
303    base::debug::DumpWithoutCrashing();
304  } else if (url == GURL(kChromeUIKillURL)) {
305    base::KillProcess(base::GetCurrentProcessHandle(), 1, false);
306  } else if (url == GURL(kChromeUIHangURL)) {
307    for (;;) {
308      base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
309    }
310  } else if (url == GURL(kChromeUIShorthangURL)) {
311    base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(20));
312  }
313
314#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
315  MaybeTriggerAsanError(url);
316#endif  // ADDRESS_SANITIZER || SYZYASAN
317}
318
319// Returns false unless this is a top-level navigation.
320static bool IsTopLevelNavigation(WebFrame* frame) {
321  return frame->parent() == NULL;
322}
323
324// Returns false unless this is a top-level navigation that crosses origins.
325static bool IsNonLocalTopLevelNavigation(const GURL& url,
326                                         WebFrame* frame,
327                                         WebNavigationType type,
328                                         bool is_form_post) {
329  if (!IsTopLevelNavigation(frame))
330    return false;
331
332  // Navigations initiated within Webkit are not sent out to the external host
333  // in the following cases.
334  // 1. The url scheme is not http/https
335  // 2. The origin of the url and the opener is the same in which case the
336  //    opener relationship is maintained.
337  // 3. Reloads/form submits/back forward navigations
338  if (!url.SchemeIs(url::kHttpScheme) && !url.SchemeIs(url::kHttpsScheme))
339    return false;
340
341  if (type != blink::WebNavigationTypeReload &&
342      type != blink::WebNavigationTypeBackForward && !is_form_post) {
343    // The opener relationship between the new window and the parent allows the
344    // new window to script the parent and vice versa. This is not allowed if
345    // the origins of the two domains are different. This can be treated as a
346    // top level navigation and routed back to the host.
347    blink::WebFrame* opener = frame->opener();
348    if (!opener)
349      return true;
350
351    if (url.GetOrigin() != GURL(opener->document().url()).GetOrigin())
352      return true;
353  }
354  return false;
355}
356
357}  // namespace
358
359static RenderFrameImpl* (*g_create_render_frame_impl)(RenderViewImpl*, int32) =
360    NULL;
361
362// static
363RenderFrameImpl* RenderFrameImpl::Create(RenderViewImpl* render_view,
364                                         int32 routing_id) {
365  DCHECK(routing_id != MSG_ROUTING_NONE);
366
367  if (g_create_render_frame_impl)
368    return g_create_render_frame_impl(render_view, routing_id);
369  else
370    return new RenderFrameImpl(render_view, routing_id);
371}
372
373// static
374RenderFrameImpl* RenderFrameImpl::FromRoutingID(int32 routing_id) {
375  RoutingIDFrameMap::iterator iter =
376      g_routing_id_frame_map.Get().find(routing_id);
377  if (iter != g_routing_id_frame_map.Get().end())
378    return iter->second;
379  return NULL;
380}
381
382// static
383void RenderFrameImpl::CreateFrame(int routing_id, int parent_routing_id) {
384  // TODO(nasko): For now, this message is only sent for subframes, as the
385  // top level frame is created when the RenderView is created through the
386  // ViewMsg_New IPC.
387  CHECK_NE(MSG_ROUTING_NONE, parent_routing_id);
388
389  RenderFrameProxy* proxy = RenderFrameProxy::FromRoutingID(parent_routing_id);
390
391  // If the browser is sending a valid parent routing id, it should already be
392  // created and registered.
393  CHECK(proxy);
394  blink::WebRemoteFrame* parent_web_frame = proxy->web_frame();
395
396  // Create the RenderFrame and WebLocalFrame, linking the two.
397  RenderFrameImpl* render_frame =
398      RenderFrameImpl::Create(proxy->render_view(), routing_id);
399  blink::WebLocalFrame* web_frame =
400      parent_web_frame->createLocalChild("", render_frame);
401  render_frame->SetWebFrame(web_frame);
402  render_frame->Initialize();
403}
404
405// static
406RenderFrame* RenderFrame::FromWebFrame(blink::WebFrame* web_frame) {
407  return RenderFrameImpl::FromWebFrame(web_frame);
408}
409
410// static
411RenderFrameImpl* RenderFrameImpl::FromWebFrame(blink::WebFrame* web_frame) {
412  FrameMap::iterator iter = g_frame_map.Get().find(web_frame);
413  if (iter != g_frame_map.Get().end())
414    return iter->second;
415  return NULL;
416}
417
418// static
419void RenderFrameImpl::InstallCreateHook(
420    RenderFrameImpl* (*create_render_frame_impl)(RenderViewImpl*, int32)) {
421  CHECK(!g_create_render_frame_impl);
422  g_create_render_frame_impl = create_render_frame_impl;
423}
424
425// RenderFrameImpl ----------------------------------------------------------
426RenderFrameImpl::RenderFrameImpl(RenderViewImpl* render_view, int routing_id)
427    : frame_(NULL),
428      render_view_(render_view->AsWeakPtr()),
429      routing_id_(routing_id),
430      is_swapped_out_(false),
431      render_frame_proxy_(NULL),
432      is_detaching_(false),
433      cookie_jar_(this),
434      selection_text_offset_(0),
435      selection_range_(gfx::Range::InvalidRange()),
436      handling_select_range_(false),
437      notification_permission_dispatcher_(NULL),
438      notification_provider_(NULL),
439      web_user_media_client_(NULL),
440      midi_dispatcher_(NULL),
441#if defined(OS_ANDROID)
442      media_player_manager_(NULL),
443#endif
444#if defined(ENABLE_BROWSER_CDMS)
445      cdm_manager_(NULL),
446#endif
447#if defined(VIDEO_HOLE)
448      contains_media_player_(false),
449#endif
450      geolocation_dispatcher_(NULL),
451      push_messaging_dispatcher_(NULL),
452      screen_orientation_dispatcher_(NULL),
453      accessibility_mode_(AccessibilityModeOff),
454      renderer_accessibility_(NULL),
455      weak_factory_(this) {
456  std::pair<RoutingIDFrameMap::iterator, bool> result =
457      g_routing_id_frame_map.Get().insert(std::make_pair(routing_id_, this));
458  CHECK(result.second) << "Inserting a duplicate item.";
459
460  RenderThread::Get()->AddRoute(routing_id_, this);
461
462  render_view_->RegisterRenderFrame(this);
463
464#if defined(OS_ANDROID)
465  new GinJavaBridgeDispatcher(this);
466#endif
467
468#if defined(ENABLE_NOTIFICATIONS)
469  notification_provider_ = new NotificationProvider(this);
470#endif
471}
472
473RenderFrameImpl::~RenderFrameImpl() {
474  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, RenderFrameGone());
475  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, OnDestruct());
476
477#if defined(VIDEO_HOLE)
478  if (contains_media_player_)
479    render_view_->UnregisterVideoHoleFrame(this);
480#endif
481
482  render_view_->UnregisterRenderFrame(this);
483  g_routing_id_frame_map.Get().erase(routing_id_);
484  RenderThread::Get()->RemoveRoute(routing_id_);
485}
486
487void RenderFrameImpl::SetWebFrame(blink::WebLocalFrame* web_frame) {
488  DCHECK(!frame_);
489
490  std::pair<FrameMap::iterator, bool> result = g_frame_map.Get().insert(
491      std::make_pair(web_frame, this));
492  CHECK(result.second) << "Inserting a duplicate item.";
493
494  frame_ = web_frame;
495}
496
497void RenderFrameImpl::Initialize() {
498#if defined(ENABLE_PLUGINS)
499  new PepperBrowserConnection(this);
500#endif
501  new SharedWorkerRepository(this);
502
503  if (!frame_->parent())
504    new ImageLoadingHelper(this);
505
506  // We delay calling this until we have the WebFrame so that any observer or
507  // embedder can call GetWebFrame on any RenderFrame.
508  GetContentClient()->renderer()->RenderFrameCreated(this);
509}
510
511RenderWidget* RenderFrameImpl::GetRenderWidget() {
512  return render_view_.get();
513}
514
515#if defined(ENABLE_PLUGINS)
516void RenderFrameImpl::PepperPluginCreated(RendererPpapiHost* host) {
517  FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
518                    DidCreatePepperPlugin(host));
519}
520
521void RenderFrameImpl::PepperDidChangeCursor(
522    PepperPluginInstanceImpl* instance,
523    const blink::WebCursorInfo& cursor) {
524  // Update the cursor appearance immediately if the requesting plugin is the
525  // one which receives the last mouse event. Otherwise, the new cursor won't be
526  // picked up until the plugin gets the next input event. That is bad if, e.g.,
527  // the plugin would like to set an invisible cursor when there isn't any user
528  // input for a while.
529  if (instance == render_view_->pepper_last_mouse_event_target())
530    GetRenderWidget()->didChangeCursor(cursor);
531}
532
533void RenderFrameImpl::PepperDidReceiveMouseEvent(
534    PepperPluginInstanceImpl* instance) {
535  render_view_->set_pepper_last_mouse_event_target(instance);
536}
537
538void RenderFrameImpl::PepperTextInputTypeChanged(
539    PepperPluginInstanceImpl* instance) {
540  if (instance != render_view_->focused_pepper_plugin())
541    return;
542
543  GetRenderWidget()->UpdateTextInputState(
544      RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
545  if (renderer_accessibility())
546    renderer_accessibility()->FocusedNodeChanged(WebNode());
547}
548
549void RenderFrameImpl::PepperCaretPositionChanged(
550    PepperPluginInstanceImpl* instance) {
551  if (instance != render_view_->focused_pepper_plugin())
552    return;
553  GetRenderWidget()->UpdateSelectionBounds();
554}
555
556void RenderFrameImpl::PepperCancelComposition(
557    PepperPluginInstanceImpl* instance) {
558  if (instance != render_view_->focused_pepper_plugin())
559    return;
560  Send(new InputHostMsg_ImeCancelComposition(render_view_->GetRoutingID()));;
561#if defined(OS_MACOSX) || defined(USE_AURA)
562  GetRenderWidget()->UpdateCompositionInfo(true);
563#endif
564}
565
566void RenderFrameImpl::PepperSelectionChanged(
567    PepperPluginInstanceImpl* instance) {
568  if (instance != render_view_->focused_pepper_plugin())
569    return;
570  SyncSelectionIfRequired();
571}
572
573RenderWidgetFullscreenPepper* RenderFrameImpl::CreatePepperFullscreenContainer(
574    PepperPluginInstanceImpl* plugin) {
575  GURL active_url;
576  if (render_view_->webview() && render_view_->webview()->mainFrame())
577    active_url = GURL(render_view_->webview()->mainFrame()->document().url());
578  RenderWidgetFullscreenPepper* widget = RenderWidgetFullscreenPepper::Create(
579      GetRenderWidget()->routing_id(), plugin, active_url,
580      GetRenderWidget()->screenInfo());
581  widget->show(blink::WebNavigationPolicyIgnore);
582  return widget;
583}
584
585bool RenderFrameImpl::IsPepperAcceptingCompositionEvents() const {
586  if (!render_view_->focused_pepper_plugin())
587    return false;
588  return render_view_->focused_pepper_plugin()->
589      IsPluginAcceptingCompositionEvents();
590}
591
592void RenderFrameImpl::PluginCrashed(const base::FilePath& plugin_path,
593                                   base::ProcessId plugin_pid) {
594  // TODO(jam): dispatch this IPC in RenderFrameHost and switch to use
595  // routing_id_ as a result.
596  Send(new FrameHostMsg_PluginCrashed(routing_id_, plugin_path, plugin_pid));
597}
598
599void RenderFrameImpl::SimulateImeSetComposition(
600    const base::string16& text,
601    const std::vector<blink::WebCompositionUnderline>& underlines,
602    int selection_start,
603    int selection_end) {
604  render_view_->OnImeSetComposition(
605      text, underlines, selection_start, selection_end);
606}
607
608void RenderFrameImpl::SimulateImeConfirmComposition(
609    const base::string16& text,
610    const gfx::Range& replacement_range) {
611  render_view_->OnImeConfirmComposition(text, replacement_range, false);
612}
613
614
615void RenderFrameImpl::OnImeSetComposition(
616    const base::string16& text,
617    const std::vector<blink::WebCompositionUnderline>& underlines,
618    int selection_start,
619    int selection_end) {
620  // When a PPAPI plugin has focus, we bypass WebKit.
621  if (!IsPepperAcceptingCompositionEvents()) {
622    pepper_composition_text_ = text;
623  } else {
624    // TODO(kinaba) currently all composition events are sent directly to
625    // plugins. Use DOM event mechanism after WebKit is made aware about
626    // plugins that support composition.
627    // The code below mimics the behavior of WebCore::Editor::setComposition.
628
629    // Empty -> nonempty: composition started.
630    if (pepper_composition_text_.empty() && !text.empty()) {
631      render_view_->focused_pepper_plugin()->HandleCompositionStart(
632          base::string16());
633    }
634    // Nonempty -> empty: composition canceled.
635    if (!pepper_composition_text_.empty() && text.empty()) {
636      render_view_->focused_pepper_plugin()->HandleCompositionEnd(
637          base::string16());
638    }
639    pepper_composition_text_ = text;
640    // Nonempty: composition is ongoing.
641    if (!pepper_composition_text_.empty()) {
642      render_view_->focused_pepper_plugin()->HandleCompositionUpdate(
643          pepper_composition_text_, underlines, selection_start,
644          selection_end);
645    }
646  }
647}
648
649void RenderFrameImpl::OnImeConfirmComposition(
650    const base::string16& text,
651    const gfx::Range& replacement_range,
652    bool keep_selection) {
653  // When a PPAPI plugin has focus, we bypass WebKit.
654  // Here, text.empty() has a special meaning. It means to commit the last
655  // update of composition text (see
656  // RenderWidgetHost::ImeConfirmComposition()).
657  const base::string16& last_text = text.empty() ? pepper_composition_text_
658                                                 : text;
659
660  // last_text is empty only when both text and pepper_composition_text_ is.
661  // Ignore it.
662  if (last_text.empty())
663    return;
664
665  if (!IsPepperAcceptingCompositionEvents()) {
666    base::i18n::UTF16CharIterator iterator(&last_text);
667    int32 i = 0;
668    while (iterator.Advance()) {
669      blink::WebKeyboardEvent char_event;
670      char_event.type = blink::WebInputEvent::Char;
671      char_event.timeStampSeconds = base::Time::Now().ToDoubleT();
672      char_event.modifiers = 0;
673      char_event.windowsKeyCode = last_text[i];
674      char_event.nativeKeyCode = last_text[i];
675
676      const int32 char_start = i;
677      for (; i < iterator.array_pos(); ++i) {
678        char_event.text[i - char_start] = last_text[i];
679        char_event.unmodifiedText[i - char_start] = last_text[i];
680      }
681
682      if (GetRenderWidget()->webwidget())
683        GetRenderWidget()->webwidget()->handleInputEvent(char_event);
684    }
685  } else {
686    // Mimics the order of events sent by WebKit.
687    // See WebCore::Editor::setComposition() for the corresponding code.
688    render_view_->focused_pepper_plugin()->HandleCompositionEnd(last_text);
689    render_view_->focused_pepper_plugin()->HandleTextInput(last_text);
690  }
691  pepper_composition_text_.clear();
692}
693
694#endif  // ENABLE_PLUGINS
695
696MediaStreamDispatcher* RenderFrameImpl::GetMediaStreamDispatcher() {
697  if (!web_user_media_client_)
698    InitializeUserMediaClient();
699  return web_user_media_client_ ?
700      web_user_media_client_->media_stream_dispatcher() : NULL;
701}
702
703bool RenderFrameImpl::Send(IPC::Message* message) {
704  if (is_detaching_) {
705    delete message;
706    return false;
707  }
708  if (frame_->parent() == NULL &&
709      (is_swapped_out_ || render_view_->is_swapped_out())) {
710    if (!SwappedOutMessages::CanSendWhileSwappedOut(message)) {
711      delete message;
712      return false;
713    }
714
715    // In most cases, send IPCs through the proxy when swapped out. In some
716    // calls the associated RenderViewImpl routing id is used to send
717    // messages, so don't use the proxy.
718    if (render_frame_proxy_ && message->routing_id() == routing_id_)
719      return render_frame_proxy_->Send(message);
720  }
721
722  return RenderThread::Get()->Send(message);
723}
724
725bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) {
726  // TODO(kenrb): document() should not be null, but as a transitional step
727  // we have RenderFrameProxy 'wrapping' a RenderFrameImpl, passing messages
728  // to this method. This happens for a top-level remote frame, where a
729  // document-less RenderFrame is replaced by a RenderFrameProxy but kept
730  // around and is still able to receive messages.
731  if (!frame_->document().isNull())
732    GetContentClient()->SetActiveURL(frame_->document().url());
733
734  ObserverListBase<RenderFrameObserver>::Iterator it(observers_);
735  RenderFrameObserver* observer;
736  while ((observer = it.GetNext()) != NULL) {
737    if (observer->OnMessageReceived(msg))
738      return true;
739  }
740
741  bool handled = true;
742  IPC_BEGIN_MESSAGE_MAP(RenderFrameImpl, msg)
743    IPC_MESSAGE_HANDLER(FrameMsg_Navigate, OnNavigate)
744    IPC_MESSAGE_HANDLER(FrameMsg_BeforeUnload, OnBeforeUnload)
745    IPC_MESSAGE_HANDLER(FrameMsg_SwapOut, OnSwapOut)
746    IPC_MESSAGE_HANDLER(FrameMsg_Stop, OnStop)
747    IPC_MESSAGE_HANDLER(FrameMsg_ContextMenuClosed, OnContextMenuClosed)
748    IPC_MESSAGE_HANDLER(FrameMsg_CustomContextMenuAction,
749                        OnCustomContextMenuAction)
750    IPC_MESSAGE_HANDLER(InputMsg_Undo, OnUndo)
751    IPC_MESSAGE_HANDLER(InputMsg_Redo, OnRedo)
752    IPC_MESSAGE_HANDLER(InputMsg_Cut, OnCut)
753    IPC_MESSAGE_HANDLER(InputMsg_Copy, OnCopy)
754    IPC_MESSAGE_HANDLER(InputMsg_Paste, OnPaste)
755    IPC_MESSAGE_HANDLER(InputMsg_PasteAndMatchStyle, OnPasteAndMatchStyle)
756    IPC_MESSAGE_HANDLER(InputMsg_Delete, OnDelete)
757    IPC_MESSAGE_HANDLER(InputMsg_SelectAll, OnSelectAll)
758    IPC_MESSAGE_HANDLER(InputMsg_SelectRange, OnSelectRange)
759    IPC_MESSAGE_HANDLER(InputMsg_Unselect, OnUnselect)
760    IPC_MESSAGE_HANDLER(InputMsg_Replace, OnReplace)
761    IPC_MESSAGE_HANDLER(InputMsg_ReplaceMisspelling, OnReplaceMisspelling)
762    IPC_MESSAGE_HANDLER(InputMsg_ExtendSelectionAndDelete,
763                        OnExtendSelectionAndDelete)
764    IPC_MESSAGE_HANDLER(InputMsg_SetCompositionFromExistingText,
765                        OnSetCompositionFromExistingText)
766    IPC_MESSAGE_HANDLER(FrameMsg_CSSInsertRequest, OnCSSInsertRequest)
767    IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequest,
768                        OnJavaScriptExecuteRequest)
769    IPC_MESSAGE_HANDLER(FrameMsg_SetEditableSelectionOffsets,
770                        OnSetEditableSelectionOffsets)
771    IPC_MESSAGE_HANDLER(FrameMsg_SetupTransitionView, OnSetupTransitionView)
772    IPC_MESSAGE_HANDLER(FrameMsg_BeginExitTransition, OnBeginExitTransition)
773    IPC_MESSAGE_HANDLER(FrameMsg_Reload, OnReload)
774    IPC_MESSAGE_HANDLER(FrameMsg_TextSurroundingSelectionRequest,
775                        OnTextSurroundingSelectionRequest)
776    IPC_MESSAGE_HANDLER(FrameMsg_AddStyleSheetByURL,
777                        OnAddStyleSheetByURL)
778    IPC_MESSAGE_HANDLER(FrameMsg_SetAccessibilityMode,
779                        OnSetAccessibilityMode)
780#if defined(OS_MACOSX)
781    IPC_MESSAGE_HANDLER(InputMsg_CopyToFindPboard, OnCopyToFindPboard)
782#endif
783  IPC_END_MESSAGE_MAP()
784
785  return handled;
786}
787
788void RenderFrameImpl::OnNavigate(const FrameMsg_Navigate_Params& params) {
789  MaybeHandleDebugURL(params.url);
790  if (!render_view_->webview())
791    return;
792
793  FOR_EACH_OBSERVER(
794      RenderViewObserver, render_view_->observers_, Navigate(params.url));
795
796  bool is_reload = RenderViewImpl::IsReload(params);
797  WebURLRequest::CachePolicy cache_policy =
798      WebURLRequest::UseProtocolCachePolicy;
799
800  // If this is a stale back/forward (due to a recent navigation the browser
801  // didn't know about), ignore it.
802  if (render_view_->IsBackForwardToStaleEntry(params, is_reload))
803    return;
804
805  // Swap this renderer back in if necessary.
806  if (render_view_->is_swapped_out_ &&
807      GetWebFrame() == render_view_->webview()->mainFrame()) {
808    // We marked the view as hidden when swapping the view out, so be sure to
809    // reset the visibility state before navigating to the new URL.
810    render_view_->webview()->setVisibilityState(
811        render_view_->visibilityState(), false);
812
813    // If this is an attempt to reload while we are swapped out, we should not
814    // reload swappedout://, but the previous page, which is stored in
815    // params.state.  Setting is_reload to false will treat this like a back
816    // navigation to accomplish that.
817    is_reload = false;
818    cache_policy = WebURLRequest::ReloadIgnoringCacheData;
819
820    // We refresh timezone when a view is swapped in since timezone
821    // can get out of sync when the system timezone is updated while
822    // the view is swapped out.
823    RenderThreadImpl::NotifyTimezoneChange();
824
825    render_view_->SetSwappedOut(false);
826    is_swapped_out_ = false;
827  }
828
829  if (params.should_clear_history_list) {
830    CHECK_EQ(params.pending_history_list_offset, -1);
831    CHECK_EQ(params.current_history_list_offset, -1);
832    CHECK_EQ(params.current_history_list_length, 0);
833  }
834  render_view_->history_list_offset_ = params.current_history_list_offset;
835  render_view_->history_list_length_ = params.current_history_list_length;
836  if (render_view_->history_list_length_ >= 0) {
837    render_view_->history_page_ids_.resize(
838        render_view_->history_list_length_, -1);
839  }
840  if (params.pending_history_list_offset >= 0 &&
841      params.pending_history_list_offset < render_view_->history_list_length_) {
842    render_view_->history_page_ids_[params.pending_history_list_offset] =
843        params.page_id;
844  }
845
846  GetContentClient()->SetActiveURL(params.url);
847
848  WebFrame* frame = frame_;
849  if (!params.frame_to_navigate.empty()) {
850    // TODO(nasko): Move this lookup to the browser process.
851    frame = render_view_->webview()->findFrameByName(
852        WebString::fromUTF8(params.frame_to_navigate));
853    CHECK(frame) << "Invalid frame name passed: " << params.frame_to_navigate;
854  }
855
856  if (is_reload && !render_view_->history_controller()->GetCurrentEntry()) {
857    // We cannot reload if we do not have any history state.  This happens, for
858    // example, when recovering from a crash.
859    is_reload = false;
860    cache_policy = WebURLRequest::ReloadIgnoringCacheData;
861  }
862
863  render_view_->pending_navigation_params_.reset(
864      new FrameMsg_Navigate_Params(params));
865
866  // If we are reloading, then WebKit will use the history state of the current
867  // page, so we should just ignore any given history state.  Otherwise, if we
868  // have history state, then we need to navigate to it, which corresponds to a
869  // back/forward navigation event.
870  if (is_reload) {
871    bool reload_original_url =
872        (params.navigation_type ==
873            FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL);
874    bool ignore_cache = (params.navigation_type ==
875                             FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE);
876
877    if (reload_original_url)
878      frame->reloadWithOverrideURL(params.url, true);
879    else
880      frame->reload(ignore_cache);
881  } else if (params.page_state.IsValid()) {
882    // We must know the page ID of the page we are navigating back to.
883    DCHECK_NE(params.page_id, -1);
884    scoped_ptr<HistoryEntry> entry =
885        PageStateToHistoryEntry(params.page_state);
886    if (entry) {
887      // Ensure we didn't save the swapped out URL in UpdateState, since the
888      // browser should never be telling us to navigate to swappedout://.
889      CHECK(entry->root().urlString() != WebString::fromUTF8(kSwappedOutURL));
890      render_view_->history_controller()->GoToEntry(entry.Pass(), cache_policy);
891    }
892  } else if (!params.base_url_for_data_url.is_empty()) {
893    // A loadData request with a specified base URL.
894    std::string mime_type, charset, data;
895    if (net::DataURL::Parse(params.url, &mime_type, &charset, &data)) {
896      frame->loadData(
897          WebData(data.c_str(), data.length()),
898          WebString::fromUTF8(mime_type),
899          WebString::fromUTF8(charset),
900          params.base_url_for_data_url,
901          params.history_url_for_data_url,
902          false);
903    } else {
904      CHECK(false) <<
905          "Invalid URL passed: " << params.url.possibly_invalid_spec();
906    }
907  } else {
908    // Navigate to the given URL.
909    WebURLRequest request(params.url);
910
911    // A session history navigation should have been accompanied by state.
912    CHECK_EQ(params.page_id, -1);
913
914    if (frame->isViewSourceModeEnabled())
915      request.setCachePolicy(WebURLRequest::ReturnCacheDataElseLoad);
916
917    if (params.referrer.url.is_valid()) {
918      WebString referrer = WebSecurityPolicy::generateReferrerHeader(
919          params.referrer.policy,
920          params.url,
921          WebString::fromUTF8(params.referrer.url.spec()));
922      if (!referrer.isEmpty())
923        request.setHTTPReferrer(referrer, params.referrer.policy);
924    }
925
926    if (!params.extra_headers.empty()) {
927      for (net::HttpUtil::HeadersIterator i(params.extra_headers.begin(),
928                                            params.extra_headers.end(), "\n");
929           i.GetNext(); ) {
930        request.addHTTPHeaderField(WebString::fromUTF8(i.name()),
931                                   WebString::fromUTF8(i.values()));
932      }
933    }
934
935    if (params.is_post) {
936      request.setHTTPMethod(WebString::fromUTF8("POST"));
937
938      // Set post data.
939      WebHTTPBody http_body;
940      http_body.initialize();
941      const char* data = NULL;
942      if (params.browser_initiated_post_data.size()) {
943        data = reinterpret_cast<const char*>(
944            &params.browser_initiated_post_data.front());
945      }
946      http_body.appendData(
947          WebData(data, params.browser_initiated_post_data.size()));
948      request.setHTTPBody(http_body);
949    }
950
951    // Record this before starting the load, we need a lower bound of this time
952    // to sanitize the navigationStart override set below.
953    base::TimeTicks renderer_navigation_start = base::TimeTicks::Now();
954    frame->loadRequest(request);
955
956    // The browser provides the navigation_start time to bootstrap the
957    // Navigation Timing information for the browser-initiated navigations. In
958    // case of cross-process navigations, this carries over the time of
959    // finishing the onbeforeunload handler of the previous page.
960    DCHECK(!params.browser_navigation_start.is_null());
961    if (frame->provisionalDataSource()) {
962      // |browser_navigation_start| is likely before this process existed, so we
963      // can't use InterProcessTimeTicksConverter. We need at least to ensure
964      // that the browser-side navigation start we set is not later than the one
965      // on the renderer side.
966      base::TimeTicks navigation_start = std::min(
967          params.browser_navigation_start, renderer_navigation_start);
968      double navigation_start_seconds =
969          (navigation_start - base::TimeTicks()).InSecondsF();
970      frame->provisionalDataSource()->setNavigationStartTime(
971          navigation_start_seconds);
972    }
973  }
974
975  // In case LoadRequest failed before DidCreateDataSource was called.
976  render_view_->pending_navigation_params_.reset();
977}
978
979void RenderFrameImpl::BindServiceRegistry(
980    mojo::ScopedMessagePipeHandle service_provider_handle) {
981  service_registry_.BindRemoteServiceProvider(service_provider_handle.Pass());
982}
983
984void RenderFrameImpl::OnBeforeUnload() {
985  // TODO(creis): Right now, this is only called on the main frame.  Make the
986  // browser process send dispatchBeforeUnloadEvent to every frame that needs
987  // it.
988  CHECK(!frame_->parent());
989
990  base::TimeTicks before_unload_start_time = base::TimeTicks::Now();
991  bool proceed = frame_->dispatchBeforeUnloadEvent();
992  base::TimeTicks before_unload_end_time = base::TimeTicks::Now();
993  Send(new FrameHostMsg_BeforeUnload_ACK(routing_id_, proceed,
994                                         before_unload_start_time,
995                                         before_unload_end_time));
996}
997
998void RenderFrameImpl::OnSwapOut(int proxy_routing_id) {
999  RenderFrameProxy* proxy = NULL;
1000  bool is_site_per_process =
1001      CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess);
1002  bool is_main_frame = !frame_->parent();
1003
1004  // Only run unload if we're not swapped out yet, but send the ack either way.
1005  if (!is_swapped_out_ || !render_view_->is_swapped_out_) {
1006    // Swap this RenderFrame out so the frame can navigate to a page rendered by
1007    // a different process.  This involves running the unload handler and
1008    // clearing the page.  We also allow this process to exit if there are no
1009    // other active RenderFrames in it.
1010
1011    // Send an UpdateState message before we get swapped out. Create the
1012    // RenderFrameProxy as well so its routing id is registered for receiving
1013    // IPC messages.
1014    render_view_->SyncNavigationState();
1015    proxy = RenderFrameProxy::CreateProxyToReplaceFrame(this,
1016                                                        proxy_routing_id);
1017
1018    // Synchronously run the unload handler before sending the ACK.
1019    // TODO(creis): Call dispatchUnloadEvent unconditionally here to support
1020    // unload on subframes as well.
1021    if (is_main_frame)
1022      frame_->dispatchUnloadEvent();
1023
1024    // Swap out and stop sending any IPC messages that are not ACKs.
1025    // TODO(nasko): Do we need RenderFrameImpl::is_swapped_out_ anymore?
1026    if (is_main_frame)
1027      render_view_->SetSwappedOut(true);
1028    is_swapped_out_ = true;
1029
1030    // Now that we're swapped out and filtering IPC messages, stop loading to
1031    // ensure that no other in-progress navigation continues.  We do this here
1032    // to avoid sending a DidStopLoading message to the browser process.
1033    // TODO(creis): Should we be stopping all frames here and using
1034    // StopAltErrorPageFetcher with RenderView::OnStop, or just stopping this
1035    // frame?
1036    OnStop();
1037
1038    // Let subframes know that the frame is now rendered remotely, for the
1039    // purposes of compositing and input events.
1040    if (!is_main_frame)
1041      frame_->setIsRemote(true);
1042
1043    // Replace the page with a blank dummy URL. The unload handler will not be
1044    // run a second time, thanks to a check in FrameLoader::stopLoading.
1045    // TODO(creis): Need to add a better way to do this that avoids running the
1046    // beforeunload handler. For now, we just run it a second time silently.
1047    if (!is_site_per_process || is_main_frame)
1048      render_view_->NavigateToSwappedOutURL(frame_);
1049
1050    // Let WebKit know that this view is hidden so it can drop resources and
1051    // stop compositing.
1052    // TODO(creis): Support this for subframes as well.
1053    if (is_main_frame) {
1054      render_view_->webview()->setVisibilityState(
1055          blink::WebPageVisibilityStateHidden, false);
1056    }
1057  }
1058
1059  // It is now safe to show modal dialogs again.
1060  // TODO(creis): Deal with modal dialogs from subframes.
1061  if (is_main_frame)
1062    render_view_->suppress_dialogs_until_swap_out_ = false;
1063
1064  Send(new FrameHostMsg_SwapOut_ACK(routing_id_));
1065
1066  // Now that all of the cleanup is complete and the browser side is notified,
1067  // start using the RenderFrameProxy, if one is created.
1068  if (proxy) {
1069    if (!is_main_frame) {
1070      frame_->swap(proxy->web_frame());
1071      if (is_site_per_process) {
1072        // TODO(nasko): delete the frame here, since we've replaced it with a
1073        // proxy.
1074      }
1075    } else {
1076      set_render_frame_proxy(proxy);
1077    }
1078  }
1079
1080  // Safe to exit if no one else is using the process.
1081  if (is_main_frame)
1082    render_view_->WasSwappedOut();
1083}
1084
1085void RenderFrameImpl::OnContextMenuClosed(
1086    const CustomContextMenuContext& custom_context) {
1087  if (custom_context.request_id) {
1088    // External request, should be in our map.
1089    ContextMenuClient* client =
1090        pending_context_menus_.Lookup(custom_context.request_id);
1091    if (client) {
1092      client->OnMenuClosed(custom_context.request_id);
1093      pending_context_menus_.Remove(custom_context.request_id);
1094    }
1095  } else {
1096    if (custom_context.link_followed.is_valid()) {
1097        frame_->sendPings(
1098            DomUtils::ExtractParentAnchorNode(context_menu_node_),
1099            custom_context.link_followed);
1100    }
1101    // Internal request, forward to WebKit.
1102    context_menu_node_.reset();
1103  }
1104}
1105
1106void RenderFrameImpl::OnCustomContextMenuAction(
1107    const CustomContextMenuContext& custom_context,
1108    unsigned action) {
1109  if (custom_context.request_id) {
1110    // External context menu request, look in our map.
1111    ContextMenuClient* client =
1112        pending_context_menus_.Lookup(custom_context.request_id);
1113    if (client)
1114      client->OnMenuAction(custom_context.request_id, action);
1115  } else {
1116    // Internal request, forward to WebKit.
1117    render_view_->webview()->performCustomContextMenuAction(action);
1118  }
1119}
1120
1121void RenderFrameImpl::OnUndo() {
1122  frame_->executeCommand(WebString::fromUTF8("Undo"), GetFocusedElement());
1123}
1124
1125void RenderFrameImpl::OnRedo() {
1126  frame_->executeCommand(WebString::fromUTF8("Redo"), GetFocusedElement());
1127}
1128
1129void RenderFrameImpl::OnCut() {
1130  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
1131  frame_->executeCommand(WebString::fromUTF8("Cut"), GetFocusedElement());
1132}
1133
1134void RenderFrameImpl::OnCopy() {
1135  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
1136  WebNode current_node = context_menu_node_.isNull() ?
1137      GetFocusedElement() : context_menu_node_;
1138  frame_->executeCommand(WebString::fromUTF8("Copy"), current_node);
1139}
1140
1141void RenderFrameImpl::OnPaste() {
1142  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
1143  frame_->executeCommand(WebString::fromUTF8("Paste"), GetFocusedElement());
1144}
1145
1146void RenderFrameImpl::OnPasteAndMatchStyle() {
1147  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
1148  frame_->executeCommand(
1149      WebString::fromUTF8("PasteAndMatchStyle"), GetFocusedElement());
1150}
1151
1152#if defined(OS_MACOSX)
1153void RenderFrameImpl::OnCopyToFindPboard() {
1154  // Since the find pasteboard supports only plain text, this can be simpler
1155  // than the |OnCopy()| case.
1156  if (frame_->hasSelection()) {
1157    base::string16 selection = frame_->selectionAsText();
1158    RenderThread::Get()->Send(
1159        new ClipboardHostMsg_FindPboardWriteStringAsync(selection));
1160  }
1161}
1162#endif
1163
1164void RenderFrameImpl::OnDelete() {
1165  frame_->executeCommand(WebString::fromUTF8("Delete"), GetFocusedElement());
1166}
1167
1168void RenderFrameImpl::OnSelectAll() {
1169  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
1170  frame_->executeCommand(WebString::fromUTF8("SelectAll"), GetFocusedElement());
1171}
1172
1173void RenderFrameImpl::OnSelectRange(const gfx::Point& start,
1174                                    const gfx::Point& end) {
1175  // This IPC is dispatched by RenderWidgetHost, so use its routing id.
1176  Send(new ViewHostMsg_SelectRange_ACK(GetRenderWidget()->routing_id()));
1177
1178  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
1179  frame_->selectRange(start, end);
1180}
1181
1182void RenderFrameImpl::OnUnselect() {
1183  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
1184  frame_->executeCommand(WebString::fromUTF8("Unselect"), GetFocusedElement());
1185}
1186
1187void RenderFrameImpl::OnReplace(const base::string16& text) {
1188  if (!frame_->hasSelection())
1189    frame_->selectWordAroundCaret();
1190
1191  frame_->replaceSelection(text);
1192}
1193
1194void RenderFrameImpl::OnReplaceMisspelling(const base::string16& text) {
1195  if (!frame_->hasSelection())
1196    return;
1197
1198  frame_->replaceMisspelledRange(text);
1199}
1200
1201void RenderFrameImpl::OnCSSInsertRequest(const std::string& css) {
1202  frame_->document().insertStyleSheet(WebString::fromUTF8(css));
1203}
1204
1205void RenderFrameImpl::OnJavaScriptExecuteRequest(
1206    const base::string16& jscript,
1207    int id,
1208    bool notify_result) {
1209  TRACE_EVENT_INSTANT0("test_tracing", "OnJavaScriptExecuteRequest",
1210                       TRACE_EVENT_SCOPE_THREAD);
1211
1212  v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
1213  v8::Handle<v8::Value> result =
1214      frame_->executeScriptAndReturnValue(WebScriptSource(jscript));
1215  if (notify_result) {
1216    base::ListValue list;
1217    if (!result.IsEmpty()) {
1218      v8::Local<v8::Context> context = frame_->mainWorldScriptContext();
1219      v8::Context::Scope context_scope(context);
1220      V8ValueConverterImpl converter;
1221      converter.SetDateAllowed(true);
1222      converter.SetRegExpAllowed(true);
1223      base::Value* result_value = converter.FromV8Value(result, context);
1224      list.Set(0, result_value ? result_value : base::Value::CreateNullValue());
1225    } else {
1226      list.Set(0, base::Value::CreateNullValue());
1227    }
1228    Send(new FrameHostMsg_JavaScriptExecuteResponse(routing_id_, id, list));
1229  }
1230}
1231
1232void RenderFrameImpl::OnSetEditableSelectionOffsets(int start, int end) {
1233  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
1234  if (!GetRenderWidget()->ShouldHandleImeEvent())
1235    return;
1236  ImeEventGuard guard(GetRenderWidget());
1237  frame_->setEditableSelectionOffsets(start, end);
1238}
1239
1240void RenderFrameImpl::OnSetCompositionFromExistingText(
1241    int start, int end,
1242    const std::vector<blink::WebCompositionUnderline>& underlines) {
1243  if (!GetRenderWidget()->ShouldHandleImeEvent())
1244    return;
1245  ImeEventGuard guard(GetRenderWidget());
1246  frame_->setCompositionFromExistingText(start, end, underlines);
1247}
1248
1249void RenderFrameImpl::OnExtendSelectionAndDelete(int before, int after) {
1250  if (!GetRenderWidget()->ShouldHandleImeEvent())
1251    return;
1252  ImeEventGuard guard(GetRenderWidget());
1253  frame_->extendSelectionAndDelete(before, after);
1254}
1255
1256void RenderFrameImpl::OnSetAccessibilityMode(AccessibilityMode new_mode) {
1257  if (accessibility_mode_ == new_mode)
1258    return;
1259  accessibility_mode_ = new_mode;
1260  if (renderer_accessibility_) {
1261    delete renderer_accessibility_;
1262    renderer_accessibility_ = NULL;
1263  }
1264  if (accessibility_mode_ == AccessibilityModeOff)
1265    return;
1266
1267  if (accessibility_mode_ & AccessibilityModeFlagFullTree)
1268    renderer_accessibility_ = new RendererAccessibilityComplete(this);
1269#if !defined(OS_ANDROID)
1270  else
1271    renderer_accessibility_ = new RendererAccessibilityFocusOnly(this);
1272#endif
1273}
1274
1275void RenderFrameImpl::OnReload(bool ignore_cache) {
1276  frame_->reload(ignore_cache);
1277}
1278
1279void RenderFrameImpl::OnTextSurroundingSelectionRequest(size_t max_length) {
1280  blink::WebSurroundingText surroundingText;
1281  surroundingText.initialize(frame_->selectionRange(), max_length);
1282
1283  if (surroundingText.isNull()) {
1284    // |surroundingText| might not be correctly initialized, for example if
1285    // |frame_->selectionRange().isNull()|, in other words, if there was no
1286    // selection.
1287    Send(new FrameHostMsg_TextSurroundingSelectionResponse(
1288        routing_id_, base::string16(), 0, 0));
1289    return;
1290  }
1291
1292  Send(new FrameHostMsg_TextSurroundingSelectionResponse(
1293      routing_id_,
1294      surroundingText.textContent(),
1295      surroundingText.startOffsetInTextContent(),
1296      surroundingText.endOffsetInTextContent()));
1297}
1298
1299void RenderFrameImpl::OnAddStyleSheetByURL(const std::string& url) {
1300  frame_->addStyleSheetByURL(WebString::fromUTF8(url));
1301}
1302
1303void RenderFrameImpl::OnSetupTransitionView(const std::string& markup) {
1304  frame_->document().setIsTransitionDocument();
1305  frame_->navigateToSandboxedMarkup(WebData(markup.data(), markup.length()));
1306}
1307
1308void RenderFrameImpl::OnBeginExitTransition(const std::string& css_selector) {
1309  frame_->document().setIsTransitionDocument();
1310  frame_->document().beginExitTransition(WebString::fromUTF8(css_selector));
1311}
1312
1313bool RenderFrameImpl::ShouldUpdateSelectionTextFromContextMenuParams(
1314    const base::string16& selection_text,
1315    size_t selection_text_offset,
1316    const gfx::Range& selection_range,
1317    const ContextMenuParams& params) {
1318  base::string16 trimmed_selection_text;
1319  if (!selection_text.empty() && !selection_range.is_empty()) {
1320    const int start = selection_range.GetMin() - selection_text_offset;
1321    const size_t length = selection_range.length();
1322    if (start >= 0 && start + length <= selection_text.length()) {
1323      base::TrimWhitespace(selection_text.substr(start, length), base::TRIM_ALL,
1324                           &trimmed_selection_text);
1325    }
1326  }
1327  base::string16 trimmed_params_text;
1328  base::TrimWhitespace(params.selection_text, base::TRIM_ALL,
1329                       &trimmed_params_text);
1330  return trimmed_params_text != trimmed_selection_text;
1331}
1332
1333bool RenderFrameImpl::RunJavaScriptMessage(JavaScriptMessageType type,
1334                                           const base::string16& message,
1335                                           const base::string16& default_value,
1336                                           const GURL& frame_url,
1337                                           base::string16* result) {
1338  // Don't allow further dialogs if we are waiting to swap out, since the
1339  // PageGroupLoadDeferrer in our stack prevents it.
1340  if (render_view()->suppress_dialogs_until_swap_out_)
1341    return false;
1342
1343  bool success = false;
1344  base::string16 result_temp;
1345  if (!result)
1346    result = &result_temp;
1347
1348  render_view()->SendAndRunNestedMessageLoop(
1349      new FrameHostMsg_RunJavaScriptMessage(
1350        routing_id_, message, default_value, frame_url, type, &success,
1351        result));
1352  return success;
1353}
1354
1355void RenderFrameImpl::LoadNavigationErrorPage(
1356    const WebURLRequest& failed_request,
1357    const WebURLError& error,
1358    bool replace) {
1359  std::string error_html;
1360  GetContentClient()->renderer()->GetNavigationErrorStrings(
1361      render_view(), frame_, failed_request, error, &error_html, NULL);
1362
1363  frame_->loadHTMLString(error_html,
1364                         GURL(kUnreachableWebDataURL),
1365                         error.unreachableURL,
1366                         replace);
1367}
1368
1369void RenderFrameImpl::DidCommitCompositorFrame() {
1370  FOR_EACH_OBSERVER(
1371      RenderFrameObserver, observers_, DidCommitCompositorFrame());
1372}
1373
1374RenderView* RenderFrameImpl::GetRenderView() {
1375  return render_view_.get();
1376}
1377
1378int RenderFrameImpl::GetRoutingID() {
1379  return routing_id_;
1380}
1381
1382blink::WebFrame* RenderFrameImpl::GetWebFrame() {
1383  DCHECK(frame_);
1384  return frame_;
1385}
1386
1387WebPreferences& RenderFrameImpl::GetWebkitPreferences() {
1388  return render_view_->GetWebkitPreferences();
1389}
1390
1391int RenderFrameImpl::ShowContextMenu(ContextMenuClient* client,
1392                                     const ContextMenuParams& params) {
1393  DCHECK(client);  // A null client means "internal" when we issue callbacks.
1394  ContextMenuParams our_params(params);
1395  our_params.custom_context.request_id = pending_context_menus_.Add(client);
1396  Send(new FrameHostMsg_ContextMenu(routing_id_, our_params));
1397  return our_params.custom_context.request_id;
1398}
1399
1400void RenderFrameImpl::CancelContextMenu(int request_id) {
1401  DCHECK(pending_context_menus_.Lookup(request_id));
1402  pending_context_menus_.Remove(request_id);
1403}
1404
1405blink::WebNode RenderFrameImpl::GetContextMenuNode() const {
1406  return context_menu_node_;
1407}
1408
1409blink::WebPlugin* RenderFrameImpl::CreatePlugin(
1410    blink::WebFrame* frame,
1411    const WebPluginInfo& info,
1412    const blink::WebPluginParams& params) {
1413  DCHECK_EQ(frame_, frame);
1414#if defined(ENABLE_PLUGINS)
1415  bool pepper_plugin_was_registered = false;
1416  scoped_refptr<PluginModule> pepper_module(PluginModule::Create(
1417      this, info, &pepper_plugin_was_registered));
1418  if (pepper_plugin_was_registered) {
1419    if (pepper_module.get()) {
1420      return new PepperWebPluginImpl(pepper_module.get(), params, this);
1421    }
1422  }
1423#if defined(OS_CHROMEOS)
1424  LOG(WARNING) << "Pepper module/plugin creation failed.";
1425  return NULL;
1426#else
1427  // TODO(jam): change to take RenderFrame.
1428  return new WebPluginImpl(frame, params, info.path, render_view_, this);
1429#endif
1430#else
1431  return NULL;
1432#endif
1433}
1434
1435void RenderFrameImpl::LoadURLExternally(blink::WebLocalFrame* frame,
1436                                        const blink::WebURLRequest& request,
1437                                        blink::WebNavigationPolicy policy) {
1438  DCHECK(!frame_ || frame_ == frame);
1439  loadURLExternally(frame, request, policy, WebString());
1440}
1441
1442void RenderFrameImpl::ExecuteJavaScript(const base::string16& javascript) {
1443  OnJavaScriptExecuteRequest(javascript, 0, false);
1444}
1445
1446ServiceRegistry* RenderFrameImpl::GetServiceRegistry() {
1447  return &service_registry_;
1448}
1449
1450bool RenderFrameImpl::IsFTPDirectoryListing() {
1451  WebURLResponseExtraDataImpl* extra_data =
1452      GetExtraDataFromResponse(frame_->dataSource()->response());
1453  return extra_data ? extra_data->is_ftp_directory_listing() : false;
1454}
1455
1456void RenderFrameImpl::AttachGuest(int element_instance_id) {
1457  render_view_->GetBrowserPluginManager()->Attach(element_instance_id);
1458}
1459
1460// blink::WebFrameClient implementation ----------------------------------------
1461
1462blink::WebPlugin* RenderFrameImpl::createPlugin(
1463    blink::WebLocalFrame* frame,
1464    const blink::WebPluginParams& params) {
1465  DCHECK_EQ(frame_, frame);
1466  blink::WebPlugin* plugin = NULL;
1467  if (GetContentClient()->renderer()->OverrideCreatePlugin(
1468          this, frame, params, &plugin)) {
1469    return plugin;
1470  }
1471
1472  if (base::UTF16ToUTF8(params.mimeType) == kBrowserPluginMimeType) {
1473    return render_view_->GetBrowserPluginManager()->CreateBrowserPlugin(
1474        render_view_.get(), frame, false);
1475  }
1476
1477#if defined(ENABLE_PLUGINS)
1478  WebPluginInfo info;
1479  std::string mime_type;
1480  bool found = false;
1481  Send(new FrameHostMsg_GetPluginInfo(
1482      routing_id_, params.url, frame->top()->document().url(),
1483      params.mimeType.utf8(), &found, &info, &mime_type));
1484  if (!found)
1485    return NULL;
1486
1487  if (info.type == content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN) {
1488    return render_view_->GetBrowserPluginManager()->CreateBrowserPlugin(
1489        render_view_.get(), frame, true);
1490  }
1491
1492
1493  WebPluginParams params_to_use = params;
1494  params_to_use.mimeType = WebString::fromUTF8(mime_type);
1495  return CreatePlugin(frame, info, params_to_use);
1496#else
1497  return NULL;
1498#endif  // defined(ENABLE_PLUGINS)
1499}
1500
1501blink::WebMediaPlayer* RenderFrameImpl::createMediaPlayer(
1502    blink::WebLocalFrame* frame,
1503    const blink::WebURL& url,
1504    blink::WebMediaPlayerClient* client) {
1505#if defined(VIDEO_HOLE)
1506  if (!contains_media_player_) {
1507    render_view_->RegisterVideoHoleFrame(this);
1508    contains_media_player_ = true;
1509  }
1510#endif  // defined(VIDEO_HOLE)
1511
1512  blink::WebMediaStream web_stream(
1513      blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url));
1514  if (!web_stream.isNull())
1515    return CreateWebMediaPlayerForMediaStream(url, client);
1516
1517#if defined(OS_ANDROID)
1518  return CreateAndroidWebMediaPlayer(url, client);
1519#else
1520  WebMediaPlayerParams params(
1521      base::Bind(&ContentRendererClient::DeferMediaLoad,
1522                 base::Unretained(GetContentClient()->renderer()),
1523                 static_cast<RenderFrame*>(this)),
1524      RenderThreadImpl::current()->GetAudioRendererMixerManager()->CreateInput(
1525          render_view_->routing_id_, routing_id_));
1526  return new WebMediaPlayerImpl(frame, client, weak_factory_.GetWeakPtr(),
1527                                params);
1528#endif  // defined(OS_ANDROID)
1529}
1530
1531blink::WebContentDecryptionModule*
1532RenderFrameImpl::createContentDecryptionModule(
1533    blink::WebLocalFrame* frame,
1534    const blink::WebSecurityOrigin& security_origin,
1535    const blink::WebString& key_system) {
1536  DCHECK(!frame_ || frame_ == frame);
1537  return WebContentDecryptionModuleImpl::Create(
1538#if defined(ENABLE_PEPPER_CDMS)
1539      frame,
1540#elif defined(ENABLE_BROWSER_CDMS)
1541      GetCdmManager(),
1542#endif
1543      security_origin,
1544      key_system);
1545}
1546
1547blink::WebApplicationCacheHost* RenderFrameImpl::createApplicationCacheHost(
1548    blink::WebLocalFrame* frame,
1549    blink::WebApplicationCacheHostClient* client) {
1550  if (!frame || !frame->view())
1551    return NULL;
1552  DCHECK(!frame_ || frame_ == frame);
1553  return new RendererWebApplicationCacheHostImpl(
1554      RenderViewImpl::FromWebView(frame->view()), client,
1555      RenderThreadImpl::current()->appcache_dispatcher()->backend_proxy());
1556}
1557
1558blink::WebWorkerPermissionClientProxy*
1559RenderFrameImpl::createWorkerPermissionClientProxy(
1560    blink::WebLocalFrame* frame) {
1561  if (!frame || !frame->view())
1562    return NULL;
1563  DCHECK(!frame_ || frame_ == frame);
1564  return GetContentClient()->renderer()->CreateWorkerPermissionClientProxy(
1565      this, frame);
1566}
1567
1568WebExternalPopupMenu* RenderFrameImpl::createExternalPopupMenu(
1569    const WebPopupMenuInfo& popup_menu_info,
1570    WebExternalPopupMenuClient* popup_menu_client) {
1571  return render_view_->createExternalPopupMenu(popup_menu_info,
1572                                               popup_menu_client);
1573}
1574
1575blink::WebCookieJar* RenderFrameImpl::cookieJar(blink::WebLocalFrame* frame) {
1576  DCHECK(!frame_ || frame_ == frame);
1577  return &cookie_jar_;
1578}
1579
1580blink::WebServiceWorkerProvider* RenderFrameImpl::createServiceWorkerProvider(
1581    blink::WebLocalFrame* frame) {
1582  DCHECK(!frame_ || frame_ == frame);
1583  // At this point we should have non-null data source.
1584  DCHECK(frame->dataSource());
1585  if (!ChildThread::current())
1586    return NULL;  // May be null in some tests.
1587  ServiceWorkerNetworkProvider* provider =
1588      ServiceWorkerNetworkProvider::FromDocumentState(
1589          DocumentState::FromDataSource(frame->dataSource()));
1590  return new WebServiceWorkerProviderImpl(
1591      ChildThread::current()->thread_safe_sender(),
1592      provider ? provider->context() : NULL);
1593}
1594
1595void RenderFrameImpl::didAccessInitialDocument(blink::WebLocalFrame* frame) {
1596  DCHECK(!frame_ || frame_ == frame);
1597  // Notify the browser process that it is no longer safe to show the pending
1598  // URL of the main frame, since a URL spoof is now possible.
1599  if (!frame->parent() && render_view_->page_id_ == -1)
1600    Send(new FrameHostMsg_DidAccessInitialDocument(routing_id_));
1601}
1602
1603blink::WebFrame* RenderFrameImpl::createChildFrame(
1604    blink::WebLocalFrame* parent,
1605    const blink::WebString& name) {
1606  // Synchronously notify the browser of a child frame creation to get the
1607  // routing_id for the RenderFrame.
1608  int child_routing_id = MSG_ROUTING_NONE;
1609  Send(new FrameHostMsg_CreateChildFrame(routing_id_,
1610                                         base::UTF16ToUTF8(name),
1611                                         &child_routing_id));
1612  // Allocation of routing id failed, so we can't create a child frame. This can
1613  // happen if this RenderFrameImpl's IPCs are being filtered when in swapped
1614  // out state.
1615  if (child_routing_id == MSG_ROUTING_NONE) {
1616#if !defined(OS_LINUX)
1617    // DumpWithoutCrashing() crashes on Linux in renderer processes when
1618    // breakpad and sandboxing are enabled: crbug.com/349600
1619    base::debug::Alias(parent);
1620    base::debug::Alias(&routing_id_);
1621    bool render_view_is_swapped_out = GetRenderWidget()->is_swapped_out();
1622    base::debug::Alias(&render_view_is_swapped_out);
1623    bool render_view_is_closing = GetRenderWidget()->closing();
1624    base::debug::Alias(&render_view_is_closing);
1625    base::debug::Alias(&is_swapped_out_);
1626    base::debug::DumpWithoutCrashing();
1627#endif
1628    return NULL;
1629  }
1630
1631  // Create the RenderFrame and WebLocalFrame, linking the two.
1632  RenderFrameImpl* child_render_frame = RenderFrameImpl::Create(
1633      render_view_.get(), child_routing_id);
1634  blink::WebLocalFrame* web_frame = WebLocalFrame::create(child_render_frame);
1635  child_render_frame->SetWebFrame(web_frame);
1636
1637  // Add the frame to the frame tree and initialize it.
1638  parent->appendChild(web_frame);
1639  child_render_frame->Initialize();
1640
1641  return web_frame;
1642}
1643
1644void RenderFrameImpl::didDisownOpener(blink::WebLocalFrame* frame) {
1645  DCHECK(!frame_ || frame_ == frame);
1646  // We only need to notify the browser if the active, top-level frame clears
1647  // its opener.  We can ignore cases where a swapped out frame clears its
1648  // opener after hearing about it from the browser, and the browser does not
1649  // (yet) care about subframe openers.
1650  if (render_view_->is_swapped_out_ || frame->parent())
1651    return;
1652
1653  // Notify WebContents and all its swapped out RenderViews.
1654  Send(new FrameHostMsg_DidDisownOpener(routing_id_));
1655}
1656
1657void RenderFrameImpl::frameDetached(blink::WebFrame* frame) {
1658  // NOTE: This function is called on the frame that is being detached and not
1659  // the parent frame.  This is different from createChildFrame() which is
1660  // called on the parent frame.
1661  CHECK(!is_detaching_);
1662  DCHECK(!frame_ || frame_ == frame);
1663
1664  bool is_subframe = !!frame->parent();
1665
1666  Send(new FrameHostMsg_Detach(routing_id_));
1667
1668  // The |is_detaching_| flag disables Send(). FrameHostMsg_Detach must be
1669  // sent before setting |is_detaching_| to true. In contrast, Observers
1670  // should only be notified afterwards so they cannot call back into here and
1671  // have IPCs fired off.
1672  is_detaching_ = true;
1673
1674  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
1675                    FrameDetached(frame));
1676
1677  // We need to clean up subframes by removing them from the map and deleting
1678  // the RenderFrameImpl.  In contrast, the main frame is owned by its
1679  // containing RenderViewHost (so that they have the same lifetime), so only
1680  // removal from the map is needed and no deletion.
1681  FrameMap::iterator it = g_frame_map.Get().find(frame);
1682  CHECK(it != g_frame_map.Get().end());
1683  CHECK_EQ(it->second, this);
1684  g_frame_map.Get().erase(it);
1685
1686  if (is_subframe)
1687    frame->parent()->removeChild(frame);
1688
1689  // |frame| is invalid after here.
1690  frame->close();
1691
1692  if (is_subframe) {
1693    delete this;
1694    // Object is invalid after this point.
1695  }
1696}
1697
1698void RenderFrameImpl::frameFocused() {
1699  Send(new FrameHostMsg_FrameFocused(routing_id_));
1700}
1701
1702void RenderFrameImpl::willClose(blink::WebFrame* frame) {
1703  DCHECK(!frame_ || frame_ == frame);
1704
1705  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, FrameWillClose());
1706  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
1707                    FrameWillClose(frame));
1708}
1709
1710void RenderFrameImpl::didChangeName(blink::WebLocalFrame* frame,
1711                                    const blink::WebString& name) {
1712  DCHECK(!frame_ || frame_ == frame);
1713  if (!render_view_->renderer_preferences_.report_frame_name_changes)
1714    return;
1715
1716  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidChangeName(name));
1717}
1718
1719void RenderFrameImpl::didMatchCSS(
1720    blink::WebLocalFrame* frame,
1721    const blink::WebVector<blink::WebString>& newly_matching_selectors,
1722    const blink::WebVector<blink::WebString>& stopped_matching_selectors) {
1723  DCHECK(!frame_ || frame_ == frame);
1724
1725  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
1726                    DidMatchCSS(frame,
1727                                newly_matching_selectors,
1728                                stopped_matching_selectors));
1729}
1730
1731bool RenderFrameImpl::shouldReportDetailedMessageForSource(
1732    const blink::WebString& source) {
1733  return GetContentClient()->renderer()->ShouldReportDetailedMessageForSource(
1734      source);
1735}
1736
1737void RenderFrameImpl::didAddMessageToConsole(
1738    const blink::WebConsoleMessage& message,
1739    const blink::WebString& source_name,
1740    unsigned source_line,
1741    const blink::WebString& stack_trace) {
1742  logging::LogSeverity log_severity = logging::LOG_VERBOSE;
1743  switch (message.level) {
1744    case blink::WebConsoleMessage::LevelDebug:
1745      log_severity = logging::LOG_VERBOSE;
1746      break;
1747    case blink::WebConsoleMessage::LevelLog:
1748    case blink::WebConsoleMessage::LevelInfo:
1749      log_severity = logging::LOG_INFO;
1750      break;
1751    case blink::WebConsoleMessage::LevelWarning:
1752      log_severity = logging::LOG_WARNING;
1753      break;
1754    case blink::WebConsoleMessage::LevelError:
1755      log_severity = logging::LOG_ERROR;
1756      break;
1757    default:
1758      NOTREACHED();
1759  }
1760
1761  if (shouldReportDetailedMessageForSource(source_name)) {
1762    FOR_EACH_OBSERVER(
1763        RenderFrameObserver, observers_,
1764        DetailedConsoleMessageAdded(message.text,
1765                                    source_name,
1766                                    stack_trace,
1767                                    source_line,
1768                                    static_cast<int32>(log_severity)));
1769  }
1770
1771  Send(new FrameHostMsg_AddMessageToConsole(routing_id_,
1772                                            static_cast<int32>(log_severity),
1773                                            message.text,
1774                                            static_cast<int32>(source_line),
1775                                            source_name));
1776}
1777
1778void RenderFrameImpl::loadURLExternally(
1779    blink::WebLocalFrame* frame,
1780    const blink::WebURLRequest& request,
1781    blink::WebNavigationPolicy policy,
1782    const blink::WebString& suggested_name) {
1783  DCHECK(!frame_ || frame_ == frame);
1784  Referrer referrer(RenderViewImpl::GetReferrerFromRequest(frame, request));
1785  if (policy == blink::WebNavigationPolicyDownload) {
1786    render_view_->Send(new ViewHostMsg_DownloadUrl(render_view_->GetRoutingID(),
1787                                                   request.url(), referrer,
1788                                                   suggested_name, false));
1789  } else if (policy == blink::WebNavigationPolicyDownloadTo) {
1790    render_view_->Send(new ViewHostMsg_DownloadUrl(render_view_->GetRoutingID(),
1791                                                   request.url(), referrer,
1792                                                   suggested_name, true));
1793  } else {
1794    OpenURL(frame, request.url(), referrer, policy);
1795  }
1796}
1797
1798blink::WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation(
1799    const NavigationPolicyInfo& info) {
1800  DCHECK(!frame_ || frame_ == info.frame);
1801  return DecidePolicyForNavigation(this, info);
1802}
1803
1804blink::WebHistoryItem RenderFrameImpl::historyItemForNewChildFrame(
1805    blink::WebFrame* frame) {
1806  DCHECK(!frame_ || frame_ == frame);
1807  return render_view_->history_controller()->GetItemForNewChildFrame(this);
1808}
1809
1810void RenderFrameImpl::willSendSubmitEvent(blink::WebLocalFrame* frame,
1811                                          const blink::WebFormElement& form) {
1812  DCHECK(!frame_ || frame_ == frame);
1813
1814  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
1815                    WillSendSubmitEvent(frame, form));
1816}
1817
1818void RenderFrameImpl::willSubmitForm(blink::WebLocalFrame* frame,
1819                                     const blink::WebFormElement& form) {
1820  DCHECK(!frame_ || frame_ == frame);
1821  DocumentState* document_state =
1822      DocumentState::FromDataSource(frame->provisionalDataSource());
1823  NavigationState* navigation_state = document_state->navigation_state();
1824  InternalDocumentStateData* internal_data =
1825      InternalDocumentStateData::FromDocumentState(document_state);
1826
1827  if (PageTransitionCoreTypeIs(navigation_state->transition_type(),
1828                               PAGE_TRANSITION_LINK)) {
1829    navigation_state->set_transition_type(PAGE_TRANSITION_FORM_SUBMIT);
1830  }
1831
1832  // Save these to be processed when the ensuing navigation is committed.
1833  WebSearchableFormData web_searchable_form_data(form);
1834  internal_data->set_searchable_form_url(web_searchable_form_data.url());
1835  internal_data->set_searchable_form_encoding(
1836      web_searchable_form_data.encoding().utf8());
1837
1838  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
1839                    WillSubmitForm(frame, form));
1840}
1841
1842void RenderFrameImpl::didCreateDataSource(blink::WebLocalFrame* frame,
1843                                          blink::WebDataSource* datasource) {
1844  DCHECK(!frame_ || frame_ == frame);
1845
1846  // TODO(nasko): Move implementation here. Needed state:
1847  // * pending_navigation_params_
1848  // * webview
1849  // Needed methods:
1850  // * PopulateDocumentStateFromPending
1851  // * CreateNavigationStateFromPending
1852  render_view_->didCreateDataSource(frame, datasource);
1853
1854  // Create the serviceworker's per-document network observing object.
1855  scoped_ptr<ServiceWorkerNetworkProvider>
1856      network_provider(new ServiceWorkerNetworkProvider());
1857  ServiceWorkerNetworkProvider::AttachToDocumentState(
1858      DocumentState::FromDataSource(datasource),
1859      network_provider.Pass());
1860}
1861
1862void RenderFrameImpl::didStartProvisionalLoad(blink::WebLocalFrame* frame,
1863                                              bool is_transition_navigation) {
1864  DCHECK(!frame_ || frame_ == frame);
1865  WebDataSource* ds = frame->provisionalDataSource();
1866
1867  // In fast/loader/stop-provisional-loads.html, we abort the load before this
1868  // callback is invoked.
1869  if (!ds)
1870    return;
1871
1872  DocumentState* document_state = DocumentState::FromDataSource(ds);
1873
1874  // We should only navigate to swappedout:// when is_swapped_out_ is true.
1875  CHECK((ds->request().url() != GURL(kSwappedOutURL)) ||
1876        is_swapped_out_ ||
1877        render_view_->is_swapped_out()) <<
1878        "Heard swappedout:// when not swapped out.";
1879
1880  // Update the request time if WebKit has better knowledge of it.
1881  if (document_state->request_time().is_null()) {
1882    double event_time = ds->triggeringEventTime();
1883    if (event_time != 0.0)
1884      document_state->set_request_time(Time::FromDoubleT(event_time));
1885  }
1886
1887  // Start time is only set after request time.
1888  document_state->set_start_load_time(Time::Now());
1889
1890  bool is_top_most = !frame->parent();
1891  if (is_top_most) {
1892    render_view_->set_navigation_gesture(
1893        WebUserGestureIndicator::isProcessingUserGesture() ?
1894            NavigationGestureUser : NavigationGestureAuto);
1895  } else if (ds->replacesCurrentHistoryItem()) {
1896    // Subframe navigations that don't add session history items must be
1897    // marked with AUTO_SUBFRAME. See also didFailProvisionalLoad for how we
1898    // handle loading of error pages.
1899    document_state->navigation_state()->set_transition_type(
1900        PAGE_TRANSITION_AUTO_SUBFRAME);
1901  }
1902
1903  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
1904                    DidStartProvisionalLoad(frame));
1905  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidStartProvisionalLoad());
1906
1907  Send(new FrameHostMsg_DidStartProvisionalLoadForFrame(
1908       routing_id_, ds->request().url(), is_transition_navigation));
1909}
1910
1911void RenderFrameImpl::didReceiveServerRedirectForProvisionalLoad(
1912    blink::WebLocalFrame* frame) {
1913  DCHECK(!frame_ || frame_ == frame);
1914  render_view_->history_controller()->RemoveChildrenForRedirect(this);
1915  if (frame->parent())
1916    return;
1917  // Received a redirect on the main frame.
1918  WebDataSource* data_source = frame->provisionalDataSource();
1919  if (!data_source) {
1920    // Should only be invoked when we have a data source.
1921    NOTREACHED();
1922    return;
1923  }
1924  std::vector<GURL> redirects;
1925  GetRedirectChain(data_source, &redirects);
1926  if (redirects.size() >= 2) {
1927    Send(new FrameHostMsg_DidRedirectProvisionalLoad(
1928        routing_id_,
1929        render_view_->page_id_,
1930        redirects[redirects.size() - 2],
1931        redirects.back()));
1932  }
1933}
1934
1935void RenderFrameImpl::didFailProvisionalLoad(blink::WebLocalFrame* frame,
1936                                             const blink::WebURLError& error) {
1937  DCHECK(!frame_ || frame_ == frame);
1938  WebDataSource* ds = frame->provisionalDataSource();
1939  DCHECK(ds);
1940
1941  const WebURLRequest& failed_request = ds->request();
1942
1943  // Notify the browser that we failed a provisional load with an error.
1944  //
1945  // Note: It is important this notification occur before DidStopLoading so the
1946  //       SSL manager can react to the provisional load failure before being
1947  //       notified the load stopped.
1948  //
1949  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
1950                    DidFailProvisionalLoad(frame, error));
1951  FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
1952                    DidFailProvisionalLoad(error));
1953
1954  bool show_repost_interstitial =
1955      (error.reason == net::ERR_CACHE_MISS &&
1956       EqualsASCII(failed_request.httpMethod(), "POST"));
1957
1958  FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
1959  params.error_code = error.reason;
1960  GetContentClient()->renderer()->GetNavigationErrorStrings(
1961      render_view_.get(),
1962      frame,
1963      failed_request,
1964      error,
1965      NULL,
1966      &params.error_description);
1967  params.url = error.unreachableURL;
1968  params.showing_repost_interstitial = show_repost_interstitial;
1969  Send(new FrameHostMsg_DidFailProvisionalLoadWithError(
1970      routing_id_, params));
1971
1972  // Don't display an error page if this is simply a cancelled load.  Aside
1973  // from being dumb, WebCore doesn't expect it and it will cause a crash.
1974  if (error.reason == net::ERR_ABORTED)
1975    return;
1976
1977  // Don't display "client blocked" error page if browser has asked us not to.
1978  if (error.reason == net::ERR_BLOCKED_BY_CLIENT &&
1979      render_view_->renderer_preferences_.disable_client_blocked_error_page) {
1980    return;
1981  }
1982
1983  // Allow the embedder to suppress an error page.
1984  if (GetContentClient()->renderer()->ShouldSuppressErrorPage(this,
1985          error.unreachableURL)) {
1986    return;
1987  }
1988
1989  if (RenderThreadImpl::current() &&
1990      RenderThreadImpl::current()->layout_test_mode()) {
1991    return;
1992  }
1993
1994  // Make sure we never show errors in view source mode.
1995  frame->enableViewSourceMode(false);
1996
1997  DocumentState* document_state = DocumentState::FromDataSource(ds);
1998  NavigationState* navigation_state = document_state->navigation_state();
1999
2000  // If this is a failed back/forward/reload navigation, then we need to do a
2001  // 'replace' load.  This is necessary to avoid messing up session history.
2002  // Otherwise, we do a normal load, which simulates a 'go' navigation as far
2003  // as session history is concerned.
2004  //
2005  // AUTO_SUBFRAME loads should always be treated as loads that do not advance
2006  // the page id.
2007  //
2008  // TODO(davidben): This should also take the failed navigation's replacement
2009  // state into account, if a location.replace() failed.
2010  bool replace =
2011      navigation_state->pending_page_id() != -1 ||
2012      PageTransitionCoreTypeIs(navigation_state->transition_type(),
2013                               PAGE_TRANSITION_AUTO_SUBFRAME);
2014
2015  // If we failed on a browser initiated request, then make sure that our error
2016  // page load is regarded as the same browser initiated request.
2017  if (!navigation_state->is_content_initiated()) {
2018    render_view_->pending_navigation_params_.reset(
2019        new FrameMsg_Navigate_Params);
2020    render_view_->pending_navigation_params_->page_id =
2021        navigation_state->pending_page_id();
2022    render_view_->pending_navigation_params_->pending_history_list_offset =
2023        navigation_state->pending_history_list_offset();
2024    render_view_->pending_navigation_params_->should_clear_history_list =
2025        navigation_state->history_list_was_cleared();
2026    render_view_->pending_navigation_params_->transition =
2027        navigation_state->transition_type();
2028    render_view_->pending_navigation_params_->request_time =
2029        document_state->request_time();
2030    render_view_->pending_navigation_params_->should_replace_current_entry =
2031        replace;
2032  }
2033
2034  // Load an error page.
2035  LoadNavigationErrorPage(failed_request, error, replace);
2036}
2037
2038void RenderFrameImpl::didCommitProvisionalLoad(
2039    blink::WebLocalFrame* frame,
2040    const blink::WebHistoryItem& item,
2041    blink::WebHistoryCommitType commit_type) {
2042  DCHECK(!frame_ || frame_ == frame);
2043  DocumentState* document_state =
2044      DocumentState::FromDataSource(frame->dataSource());
2045  NavigationState* navigation_state = document_state->navigation_state();
2046
2047  // When we perform a new navigation, we need to update the last committed
2048  // session history entry with state for the page we are leaving. Do this
2049  // before updating the HistoryController state.
2050  render_view_->UpdateSessionHistory(frame);
2051
2052  render_view_->history_controller()->UpdateForCommit(this, item, commit_type,
2053      navigation_state->was_within_same_page());
2054
2055  InternalDocumentStateData* internal_data =
2056      InternalDocumentStateData::FromDocumentState(document_state);
2057
2058  if (document_state->commit_load_time().is_null())
2059    document_state->set_commit_load_time(Time::Now());
2060
2061  if (internal_data->must_reset_scroll_and_scale_state()) {
2062    render_view_->webview()->resetScrollAndScaleState();
2063    internal_data->set_must_reset_scroll_and_scale_state(false);
2064  }
2065  internal_data->set_use_error_page(false);
2066
2067  bool is_new_navigation = commit_type == blink::WebStandardCommit;
2068  if (is_new_navigation) {
2069    // We bump our Page ID to correspond with the new session history entry.
2070    render_view_->page_id_ = render_view_->next_page_id_++;
2071
2072    // Don't update history_page_ids_ (etc) for kSwappedOutURL, since
2073    // we don't want to forget the entry that was there, and since we will
2074    // never come back to kSwappedOutURL.  Note that we have to call
2075    // UpdateSessionHistory and update page_id_ even in this case, so that
2076    // the current entry gets a state update and so that we don't send a
2077    // state update to the wrong entry when we swap back in.
2078    if (GetLoadingUrl() != GURL(kSwappedOutURL)) {
2079      // Advance our offset in session history, applying the length limit.
2080      // There is now no forward history.
2081      render_view_->history_list_offset_++;
2082      if (render_view_->history_list_offset_ >= kMaxSessionHistoryEntries)
2083        render_view_->history_list_offset_ = kMaxSessionHistoryEntries - 1;
2084      render_view_->history_list_length_ =
2085          render_view_->history_list_offset_ + 1;
2086      render_view_->history_page_ids_.resize(
2087          render_view_->history_list_length_, -1);
2088      render_view_->history_page_ids_[render_view_->history_list_offset_] =
2089          render_view_->page_id_;
2090    }
2091  } else {
2092    // Inspect the navigation_state on this frame to see if the navigation
2093    // corresponds to a session history navigation...  Note: |frame| may or
2094    // may not be the toplevel frame, but for the case of capturing session
2095    // history, the first committed frame suffices.  We keep track of whether
2096    // we've seen this commit before so that only capture session history once
2097    // per navigation.
2098    //
2099    // Note that we need to check if the page ID changed. In the case of a
2100    // reload, the page ID doesn't change, and UpdateSessionHistory gets the
2101    // previous URL and the current page ID, which would be wrong.
2102    if (navigation_state->pending_page_id() != -1 &&
2103        navigation_state->pending_page_id() != render_view_->page_id_ &&
2104        !navigation_state->request_committed()) {
2105      // This is a successful session history navigation!
2106      render_view_->page_id_ = navigation_state->pending_page_id();
2107
2108      render_view_->history_list_offset_ =
2109          navigation_state->pending_history_list_offset();
2110
2111      // If the history list is valid, our list of page IDs should be correct.
2112      DCHECK(render_view_->history_list_length_ <= 0 ||
2113             render_view_->history_list_offset_ < 0 ||
2114             render_view_->history_list_offset_ >=
2115                 render_view_->history_list_length_ ||
2116             render_view_->history_page_ids_[render_view_->history_list_offset_]
2117                  == render_view_->page_id_);
2118    }
2119  }
2120
2121  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers_,
2122                    DidCommitProvisionalLoad(frame, is_new_navigation));
2123  FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
2124                    DidCommitProvisionalLoad(is_new_navigation));
2125
2126  if (!frame->parent()) {  // Only for top frames.
2127    RenderThreadImpl* render_thread_impl = RenderThreadImpl::current();
2128    if (render_thread_impl) {  // Can be NULL in tests.
2129      render_thread_impl->histogram_customizer()->
2130          RenderViewNavigatedToHost(GURL(GetLoadingUrl()).host(),
2131                                    RenderViewImpl::GetRenderViewCount());
2132    }
2133  }
2134
2135  // Remember that we've already processed this request, so we don't update
2136  // the session history again.  We do this regardless of whether this is
2137  // a session history navigation, because if we attempted a session history
2138  // navigation without valid HistoryItem state, WebCore will think it is a
2139  // new navigation.
2140  navigation_state->set_request_committed(true);
2141
2142  SendDidCommitProvisionalLoad(frame);
2143
2144  // Check whether we have new encoding name.
2145  UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
2146}
2147
2148void RenderFrameImpl::didClearWindowObject(blink::WebLocalFrame* frame) {
2149  DCHECK(!frame_ || frame_ == frame);
2150  // TODO(nasko): Move implementation here. Needed state:
2151  // * enabled_bindings_
2152  // * dom_automation_controller_
2153  // * stats_collection_controller_
2154
2155  render_view_->didClearWindowObject(frame);
2156
2157  if (render_view_->GetEnabledBindings() & BINDINGS_POLICY_DOM_AUTOMATION)
2158    DomAutomationController::Install(this, frame);
2159
2160  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidClearWindowObject());
2161}
2162
2163void RenderFrameImpl::didCreateDocumentElement(blink::WebLocalFrame* frame) {
2164  DCHECK(!frame_ || frame_ == frame);
2165
2166  // Notify the browser about non-blank documents loading in the top frame.
2167  GURL url = frame->document().url();
2168  if (url.is_valid() && url.spec() != url::kAboutBlankURL) {
2169    // TODO(nasko): Check if webview()->mainFrame() is the same as the
2170    // frame->tree()->top().
2171    blink::WebFrame* main_frame = render_view_->webview()->mainFrame();
2172    if (frame == main_frame) {
2173      // For now, don't remember plugin zoom values.  We don't want to mix them
2174      // with normal web content (i.e. a fixed layout plugin would usually want
2175      // them different).
2176      render_view_->Send(new ViewHostMsg_DocumentAvailableInMainFrame(
2177          render_view_->GetRoutingID(),
2178          main_frame->document().isPluginDocument()));
2179    }
2180  }
2181
2182  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
2183                    DidCreateDocumentElement(frame));
2184}
2185
2186void RenderFrameImpl::didReceiveTitle(blink::WebLocalFrame* frame,
2187                                      const blink::WebString& title,
2188                                      blink::WebTextDirection direction) {
2189  DCHECK(!frame_ || frame_ == frame);
2190  // Ignore all but top level navigations.
2191  if (!frame->parent()) {
2192    base::string16 title16 = title;
2193    base::debug::TraceLog::GetInstance()->UpdateProcessLabel(
2194        routing_id_, base::UTF16ToUTF8(title16));
2195
2196    base::string16 shortened_title = title16.substr(0, kMaxTitleChars);
2197    Send(new FrameHostMsg_UpdateTitle(routing_id_,
2198                                      render_view_->page_id_,
2199                                      shortened_title, direction));
2200  }
2201
2202  // Also check whether we have new encoding name.
2203  UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
2204}
2205
2206void RenderFrameImpl::didChangeIcon(blink::WebLocalFrame* frame,
2207                                    blink::WebIconURL::Type icon_type) {
2208  DCHECK(!frame_ || frame_ == frame);
2209  // TODO(nasko): Investigate wheather implementation should move here.
2210  render_view_->didChangeIcon(frame, icon_type);
2211}
2212
2213void RenderFrameImpl::didFinishDocumentLoad(blink::WebLocalFrame* frame) {
2214  DCHECK(!frame_ || frame_ == frame);
2215  WebDataSource* ds = frame->dataSource();
2216  DocumentState* document_state = DocumentState::FromDataSource(ds);
2217  document_state->set_finish_document_load_time(Time::Now());
2218
2219  Send(new FrameHostMsg_DidFinishDocumentLoad(routing_id_));
2220
2221  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
2222                    DidFinishDocumentLoad(frame));
2223  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidFinishDocumentLoad());
2224
2225  // Check whether we have new encoding name.
2226  UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
2227}
2228
2229void RenderFrameImpl::didHandleOnloadEvents(blink::WebLocalFrame* frame) {
2230  DCHECK(!frame_ || frame_ == frame);
2231  if (!frame->parent())
2232    Send(new FrameHostMsg_DocumentOnLoadCompleted(routing_id_));
2233}
2234
2235void RenderFrameImpl::didFailLoad(blink::WebLocalFrame* frame,
2236                                  const blink::WebURLError& error) {
2237  DCHECK(!frame_ || frame_ == frame);
2238  // TODO(nasko): Move implementation here. No state needed.
2239  WebDataSource* ds = frame->dataSource();
2240  DCHECK(ds);
2241
2242  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
2243                    DidFailLoad(frame, error));
2244
2245  const WebURLRequest& failed_request = ds->request();
2246  base::string16 error_description;
2247  GetContentClient()->renderer()->GetNavigationErrorStrings(
2248      render_view_.get(),
2249      frame,
2250      failed_request,
2251      error,
2252      NULL,
2253      &error_description);
2254  Send(new FrameHostMsg_DidFailLoadWithError(routing_id_,
2255                                             failed_request.url(),
2256                                             error.reason,
2257                                             error_description));
2258}
2259
2260void RenderFrameImpl::didFinishLoad(blink::WebLocalFrame* frame) {
2261  DCHECK(!frame_ || frame_ == frame);
2262  WebDataSource* ds = frame->dataSource();
2263  DocumentState* document_state = DocumentState::FromDataSource(ds);
2264  if (document_state->finish_load_time().is_null()) {
2265    if (!frame->parent()) {
2266      TRACE_EVENT_INSTANT0("WebCore", "LoadFinished",
2267                           TRACE_EVENT_SCOPE_PROCESS);
2268    }
2269    document_state->set_finish_load_time(Time::Now());
2270  }
2271
2272  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
2273                    DidFinishLoad(frame));
2274  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidFinishLoad());
2275
2276  // Don't send this message while the frame is swapped out.
2277  if (is_swapped_out())
2278    return;
2279
2280  Send(new FrameHostMsg_DidFinishLoad(routing_id_,
2281                                      ds->request().url()));
2282}
2283
2284void RenderFrameImpl::didNavigateWithinPage(blink::WebLocalFrame* frame,
2285    const blink::WebHistoryItem& item,
2286    blink::WebHistoryCommitType commit_type) {
2287  DCHECK(!frame_ || frame_ == frame);
2288  // If this was a reference fragment navigation that we initiated, then we
2289  // could end up having a non-null pending navigation params.  We just need to
2290  // update the ExtraData on the datasource so that others who read the
2291  // ExtraData will get the new NavigationState.  Similarly, if we did not
2292  // initiate this navigation, then we need to take care to reset any pre-
2293  // existing navigation state to a content-initiated navigation state.
2294  // DidCreateDataSource conveniently takes care of this for us.
2295  didCreateDataSource(frame, frame->dataSource());
2296
2297  DocumentState* document_state =
2298      DocumentState::FromDataSource(frame->dataSource());
2299  NavigationState* new_state = document_state->navigation_state();
2300  new_state->set_was_within_same_page(true);
2301
2302  didCommitProvisionalLoad(frame, item, commit_type);
2303}
2304
2305void RenderFrameImpl::didUpdateCurrentHistoryItem(blink::WebLocalFrame* frame) {
2306  DCHECK(!frame_ || frame_ == frame);
2307  // TODO(nasko): Move implementation here. Needed methods:
2308  // * StartNavStateSyncTimerIfNecessary
2309  render_view_->didUpdateCurrentHistoryItem(frame);
2310}
2311
2312void RenderFrameImpl::addNavigationTransitionData(
2313    const blink::WebString& allowed_destination_host_pattern,
2314    const blink::WebString& selector,
2315    const blink::WebString& markup) {
2316  Send(new FrameHostMsg_AddNavigationTransitionData(
2317      routing_id_, allowed_destination_host_pattern.utf8(), selector.utf8(),
2318      markup.utf8()));
2319}
2320
2321void RenderFrameImpl::didChangeThemeColor() {
2322  if (frame_->parent())
2323    return;
2324
2325  Send(new FrameHostMsg_DidChangeThemeColor(
2326      routing_id_, frame_->document().themeColor()));
2327}
2328
2329void RenderFrameImpl::requestNotificationPermission(
2330    const blink::WebSecurityOrigin& origin,
2331    blink::WebNotificationPermissionCallback* callback) {
2332  if (!notification_permission_dispatcher_) {
2333    notification_permission_dispatcher_ =
2334        new NotificationPermissionDispatcher(this);
2335  }
2336
2337  notification_permission_dispatcher_->RequestPermission(origin, callback);
2338}
2339
2340blink::WebNotificationPresenter* RenderFrameImpl::notificationPresenter() {
2341  return notification_provider_;
2342}
2343
2344void RenderFrameImpl::didChangeSelection(bool is_empty_selection) {
2345  if (!GetRenderWidget()->handling_input_event() && !handling_select_range_)
2346    return;
2347
2348  if (is_empty_selection)
2349    selection_text_.clear();
2350
2351  // UpdateTextInputState should be called before SyncSelectionIfRequired.
2352  // UpdateTextInputState may send TextInputStateChanged to notify the focus
2353  // was changed, and SyncSelectionIfRequired may send SelectionChanged
2354  // to notify the selection was changed.  Focus change should be notified
2355  // before selection change.
2356  GetRenderWidget()->UpdateTextInputState(
2357      RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
2358  SyncSelectionIfRequired();
2359}
2360
2361blink::WebColorChooser* RenderFrameImpl::createColorChooser(
2362    blink::WebColorChooserClient* client,
2363    const blink::WebColor& initial_color,
2364    const blink::WebVector<blink::WebColorSuggestion>& suggestions) {
2365  RendererWebColorChooserImpl* color_chooser =
2366      new RendererWebColorChooserImpl(this, client);
2367  std::vector<content::ColorSuggestion> color_suggestions;
2368  for (size_t i = 0; i < suggestions.size(); i++) {
2369    color_suggestions.push_back(content::ColorSuggestion(suggestions[i]));
2370  }
2371  color_chooser->Open(static_cast<SkColor>(initial_color), color_suggestions);
2372  return color_chooser;
2373}
2374
2375void RenderFrameImpl::runModalAlertDialog(const blink::WebString& message) {
2376  RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_ALERT,
2377                       message,
2378                       base::string16(),
2379                       frame_->document().url(),
2380                       NULL);
2381}
2382
2383bool RenderFrameImpl::runModalConfirmDialog(const blink::WebString& message) {
2384  return RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_CONFIRM,
2385                              message,
2386                              base::string16(),
2387                              frame_->document().url(),
2388                              NULL);
2389}
2390
2391bool RenderFrameImpl::runModalPromptDialog(
2392    const blink::WebString& message,
2393    const blink::WebString& default_value,
2394    blink::WebString* actual_value) {
2395  base::string16 result;
2396  bool ok = RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_PROMPT,
2397                                 message,
2398                                 default_value,
2399                                 frame_->document().url(),
2400                                 &result);
2401  if (ok)
2402    actual_value->assign(result);
2403  return ok;
2404}
2405
2406bool RenderFrameImpl::runModalBeforeUnloadDialog(
2407    bool is_reload,
2408    const blink::WebString& message) {
2409  // If we are swapping out, we have already run the beforeunload handler.
2410  // TODO(creis): Fix OnSwapOut to clear the frame without running beforeunload
2411  // at all, to avoid running it twice.
2412  if (render_view()->is_swapped_out_)
2413    return true;
2414
2415  // Don't allow further dialogs if we are waiting to swap out, since the
2416  // PageGroupLoadDeferrer in our stack prevents it.
2417  if (render_view()->suppress_dialogs_until_swap_out_)
2418    return false;
2419
2420  bool success = false;
2421  // This is an ignored return value, but is included so we can accept the same
2422  // response as RunJavaScriptMessage.
2423  base::string16 ignored_result;
2424  render_view()->SendAndRunNestedMessageLoop(
2425      new FrameHostMsg_RunBeforeUnloadConfirm(
2426          routing_id_, frame_->document().url(), message, is_reload,
2427          &success, &ignored_result));
2428  return success;
2429}
2430
2431void RenderFrameImpl::showContextMenu(const blink::WebContextMenuData& data) {
2432  ContextMenuParams params = ContextMenuParamsBuilder::Build(data);
2433  params.source_type = GetRenderWidget()->context_menu_source_type();
2434  GetRenderWidget()->OnShowHostContextMenu(&params);
2435  if (GetRenderWidget()->has_host_context_menu_location()) {
2436    params.x = GetRenderWidget()->host_context_menu_location().x();
2437    params.y = GetRenderWidget()->host_context_menu_location().y();
2438  }
2439
2440  // Plugins, e.g. PDF, don't currently update the render view when their
2441  // selected text changes, but the context menu params do contain the updated
2442  // selection. If that's the case, update the render view's state just prior
2443  // to showing the context menu.
2444  // TODO(asvitkine): http://crbug.com/152432
2445  if (ShouldUpdateSelectionTextFromContextMenuParams(
2446          selection_text_, selection_text_offset_, selection_range_, params)) {
2447    selection_text_ = params.selection_text;
2448    // TODO(asvitkine): Text offset and range is not available in this case.
2449    selection_text_offset_ = 0;
2450    selection_range_ = gfx::Range(0, selection_text_.length());
2451    // This IPC is dispatched by RenderWidetHost, so use its routing ID.
2452    Send(new ViewHostMsg_SelectionChanged(
2453        GetRenderWidget()->routing_id(), selection_text_,
2454        selection_text_offset_, selection_range_));
2455  }
2456
2457  // Serializing a GURL longer than kMaxURLChars will fail, so don't do
2458  // it.  We replace it with an empty GURL so the appropriate items are disabled
2459  // in the context menu.
2460  // TODO(jcivelli): http://crbug.com/45160 This prevents us from saving large
2461  //                 data encoded images.  We should have a way to save them.
2462  if (params.src_url.spec().size() > GetMaxURLChars())
2463    params.src_url = GURL();
2464  context_menu_node_ = data.node;
2465
2466#if defined(OS_ANDROID)
2467  gfx::Rect start_rect;
2468  gfx::Rect end_rect;
2469  GetRenderWidget()->GetSelectionBounds(&start_rect, &end_rect);
2470  params.selection_start = gfx::Point(start_rect.x(), start_rect.bottom());
2471  params.selection_end = gfx::Point(end_rect.right(), end_rect.bottom());
2472#endif
2473
2474  Send(new FrameHostMsg_ContextMenu(routing_id_, params));
2475}
2476
2477void RenderFrameImpl::clearContextMenu() {
2478  context_menu_node_.reset();
2479}
2480
2481void RenderFrameImpl::willSendRequest(
2482    blink::WebLocalFrame* frame,
2483    unsigned identifier,
2484    blink::WebURLRequest& request,
2485    const blink::WebURLResponse& redirect_response) {
2486  DCHECK(!frame_ || frame_ == frame);
2487  // The request my be empty during tests.
2488  if (request.url().isEmpty())
2489    return;
2490
2491  // Set the first party for cookies url if it has not been set yet (new
2492  // requests). For redirects, it is updated by WebURLLoaderImpl.
2493  if (request.firstPartyForCookies().isEmpty()) {
2494    if (request.frameType() == blink::WebURLRequest::FrameTypeTopLevel) {
2495      request.setFirstPartyForCookies(request.url());
2496    } else {
2497      // TODO(nasko): When the top-level frame is remote, there is no document.
2498      // This is broken and should be fixed to propagate the first party.
2499      WebFrame* top = frame->top();
2500      if (top->isWebLocalFrame()) {
2501        request.setFirstPartyForCookies(
2502            frame->top()->document().firstPartyForCookies());
2503      }
2504    }
2505  }
2506
2507  WebFrame* top_frame = frame->top();
2508  // TODO(nasko): Hack around asking about top-frame data source. This means
2509  // for out-of-process iframes we are treating the current frame as the
2510  // top-level frame, which is wrong.
2511  if (!top_frame || top_frame->isWebRemoteFrame())
2512    top_frame = frame;
2513  WebDataSource* provisional_data_source = top_frame->provisionalDataSource();
2514  WebDataSource* top_data_source = top_frame->dataSource();
2515  WebDataSource* data_source =
2516      provisional_data_source ? provisional_data_source : top_data_source;
2517
2518  PageTransition transition_type = PAGE_TRANSITION_LINK;
2519  DocumentState* document_state = DocumentState::FromDataSource(data_source);
2520  DCHECK(document_state);
2521  InternalDocumentStateData* internal_data =
2522      InternalDocumentStateData::FromDocumentState(document_state);
2523  NavigationState* navigation_state = document_state->navigation_state();
2524  transition_type = navigation_state->transition_type();
2525
2526  GURL request_url(request.url());
2527  GURL new_url;
2528  if (GetContentClient()->renderer()->WillSendRequest(
2529          frame,
2530          transition_type,
2531          request_url,
2532          request.firstPartyForCookies(),
2533          &new_url)) {
2534    request.setURL(WebURL(new_url));
2535  }
2536
2537  if (internal_data->is_cache_policy_override_set())
2538    request.setCachePolicy(internal_data->cache_policy_override());
2539
2540  // The request's extra data may indicate that we should set a custom user
2541  // agent. This needs to be done here, after WebKit is through with setting the
2542  // user agent on its own. Similarly, it may indicate that we should set an
2543  // X-Requested-With header. This must be done here to avoid breaking CORS
2544  // checks.
2545  WebString custom_user_agent;
2546  WebString requested_with;
2547  if (request.extraData()) {
2548    RequestExtraData* old_extra_data =
2549        static_cast<RequestExtraData*>(request.extraData());
2550
2551    custom_user_agent = old_extra_data->custom_user_agent();
2552    if (!custom_user_agent.isNull()) {
2553      if (custom_user_agent.isEmpty())
2554        request.clearHTTPHeaderField("User-Agent");
2555      else
2556        request.setHTTPHeaderField("User-Agent", custom_user_agent);
2557    }
2558
2559    requested_with = old_extra_data->requested_with();
2560    if (!requested_with.isNull()) {
2561      if (requested_with.isEmpty())
2562        request.clearHTTPHeaderField("X-Requested-With");
2563      else
2564        request.setHTTPHeaderField("X-Requested-With", requested_with);
2565    }
2566  }
2567
2568  // Add the default accept header for frame request if it has not been set
2569  // already.
2570  if ((request.frameType() == blink::WebURLRequest::FrameTypeTopLevel ||
2571       request.frameType() == blink::WebURLRequest::FrameTypeNested) &&
2572      request.httpHeaderField(WebString::fromUTF8(kAcceptHeader)).isEmpty()) {
2573    request.setHTTPHeaderField(WebString::fromUTF8(kAcceptHeader),
2574                               WebString::fromUTF8(kDefaultAcceptHeader));
2575  }
2576
2577  // Add an empty HTTP origin header for non GET methods if none is currently
2578  // present.
2579  request.addHTTPOriginIfNeeded(WebString());
2580
2581  // Attach |should_replace_current_entry| state to requests so that, should
2582  // this navigation later require a request transfer, all state is preserved
2583  // when it is re-created in the new process.
2584  bool should_replace_current_entry = false;
2585  if (navigation_state->is_content_initiated()) {
2586    should_replace_current_entry = data_source->replacesCurrentHistoryItem();
2587  } else {
2588    // If the navigation is browser-initiated, the NavigationState contains the
2589    // correct value instead of the WebDataSource.
2590    //
2591    // TODO(davidben): Avoid this awkward duplication of state. See comment on
2592    // NavigationState::should_replace_current_entry().
2593    should_replace_current_entry =
2594        navigation_state->should_replace_current_entry();
2595  }
2596
2597  int provider_id = kInvalidServiceWorkerProviderId;
2598  if (request.frameType() == blink::WebURLRequest::FrameTypeTopLevel ||
2599      request.frameType() == blink::WebURLRequest::FrameTypeNested) {
2600    // |provisionalDataSource| may be null in some content::ResourceFetcher
2601    // use cases, we don't hook those requests.
2602    if (frame->provisionalDataSource()) {
2603      ServiceWorkerNetworkProvider* provider =
2604          ServiceWorkerNetworkProvider::FromDocumentState(
2605              DocumentState::FromDataSource(frame->provisionalDataSource()));
2606      provider_id = provider->provider_id();
2607    }
2608  } else if (frame->dataSource()) {
2609    ServiceWorkerNetworkProvider* provider =
2610        ServiceWorkerNetworkProvider::FromDocumentState(
2611            DocumentState::FromDataSource(frame->dataSource()));
2612    provider_id = provider->provider_id();
2613  }
2614
2615  WebFrame* parent = frame->parent();
2616  int parent_routing_id = MSG_ROUTING_NONE;
2617  if (!parent) {
2618    parent_routing_id = -1;
2619  } else if (parent->isWebLocalFrame()) {
2620    parent_routing_id = FromWebFrame(parent)->GetRoutingID();
2621  } else {
2622    parent_routing_id = RenderFrameProxy::FromWebFrame(parent)->routing_id();
2623  }
2624
2625  RequestExtraData* extra_data = new RequestExtraData();
2626  extra_data->set_visibility_state(render_view_->visibilityState());
2627  extra_data->set_custom_user_agent(custom_user_agent);
2628  extra_data->set_requested_with(requested_with);
2629  extra_data->set_render_frame_id(routing_id_);
2630  extra_data->set_is_main_frame(frame == top_frame);
2631  extra_data->set_frame_origin(
2632      GURL(frame->document().securityOrigin().toString()));
2633  extra_data->set_parent_is_main_frame(frame->parent() == top_frame);
2634  extra_data->set_parent_render_frame_id(parent_routing_id);
2635  extra_data->set_allow_download(navigation_state->allow_download());
2636  extra_data->set_transition_type(transition_type);
2637  extra_data->set_should_replace_current_entry(should_replace_current_entry);
2638  extra_data->set_transferred_request_child_id(
2639      navigation_state->transferred_request_child_id());
2640  extra_data->set_transferred_request_request_id(
2641      navigation_state->transferred_request_request_id());
2642  extra_data->set_service_worker_provider_id(provider_id);
2643  request.setExtraData(extra_data);
2644
2645  DocumentState* top_document_state =
2646      DocumentState::FromDataSource(top_data_source);
2647  if (top_document_state) {
2648    // TODO(gavinp): separate out prefetching and prerender field trials
2649    // if the rel=prerender rel type is sticking around.
2650    if (request.requestContext() == WebURLRequest::RequestContextPrefetch)
2651      top_document_state->set_was_prefetcher(true);
2652  }
2653
2654  // This is an instance where we embed a copy of the routing id
2655  // into the data portion of the message. This can cause problems if we
2656  // don't register this id on the browser side, since the download manager
2657  // expects to find a RenderViewHost based off the id.
2658  request.setRequestorID(render_view_->GetRoutingID());
2659  request.setHasUserGesture(WebUserGestureIndicator::isProcessingUserGesture());
2660
2661  if (!navigation_state->extra_headers().empty()) {
2662    for (net::HttpUtil::HeadersIterator i(
2663        navigation_state->extra_headers().begin(),
2664        navigation_state->extra_headers().end(), "\n");
2665        i.GetNext(); ) {
2666      if (LowerCaseEqualsASCII(i.name(), "referer")) {
2667        WebString referrer = WebSecurityPolicy::generateReferrerHeader(
2668            blink::WebReferrerPolicyDefault,
2669            request.url(),
2670            WebString::fromUTF8(i.values()));
2671        request.setHTTPReferrer(referrer, blink::WebReferrerPolicyDefault);
2672      } else {
2673        request.setHTTPHeaderField(WebString::fromUTF8(i.name()),
2674                                   WebString::fromUTF8(i.values()));
2675      }
2676    }
2677  }
2678
2679  if (!render_view_->renderer_preferences_.enable_referrers)
2680    request.setHTTPReferrer(WebString(), blink::WebReferrerPolicyDefault);
2681}
2682
2683void RenderFrameImpl::didReceiveResponse(
2684    blink::WebLocalFrame* frame,
2685    unsigned identifier,
2686    const blink::WebURLResponse& response) {
2687  DCHECK(!frame_ || frame_ == frame);
2688  // Only do this for responses that correspond to a provisional data source
2689  // of the top-most frame.  If we have a provisional data source, then we
2690  // can't have any sub-resources yet, so we know that this response must
2691  // correspond to a frame load.
2692  if (!frame->provisionalDataSource() || frame->parent())
2693    return;
2694
2695  // If we are in view source mode, then just let the user see the source of
2696  // the server's error page.
2697  if (frame->isViewSourceModeEnabled())
2698    return;
2699
2700  DocumentState* document_state =
2701      DocumentState::FromDataSource(frame->provisionalDataSource());
2702  int http_status_code = response.httpStatusCode();
2703
2704  // Record page load flags.
2705  WebURLResponseExtraDataImpl* extra_data = GetExtraDataFromResponse(response);
2706  if (extra_data) {
2707    document_state->set_was_fetched_via_spdy(
2708        extra_data->was_fetched_via_spdy());
2709    document_state->set_was_npn_negotiated(
2710        extra_data->was_npn_negotiated());
2711    document_state->set_npn_negotiated_protocol(
2712        extra_data->npn_negotiated_protocol());
2713    document_state->set_was_alternate_protocol_available(
2714        extra_data->was_alternate_protocol_available());
2715    document_state->set_connection_info(
2716        extra_data->connection_info());
2717    document_state->set_was_fetched_via_proxy(
2718        extra_data->was_fetched_via_proxy());
2719  }
2720  InternalDocumentStateData* internal_data =
2721      InternalDocumentStateData::FromDocumentState(document_state);
2722  internal_data->set_http_status_code(http_status_code);
2723  // Whether or not the http status code actually corresponds to an error is
2724  // only checked when the page is done loading, if |use_error_page| is
2725  // still true.
2726  internal_data->set_use_error_page(true);
2727}
2728
2729void RenderFrameImpl::didFinishResourceLoad(blink::WebLocalFrame* frame,
2730                                            unsigned identifier) {
2731  DCHECK(!frame_ || frame_ == frame);
2732  InternalDocumentStateData* internal_data =
2733      InternalDocumentStateData::FromDataSource(frame->dataSource());
2734  if (!internal_data->use_error_page())
2735    return;
2736
2737  // Do not show error page when DevTools is attached.
2738  if (render_view_->devtools_agent_->IsAttached())
2739    return;
2740
2741  // Display error page, if appropriate.
2742  std::string error_domain = "http";
2743  int http_status_code = internal_data->http_status_code();
2744  if (GetContentClient()->renderer()->HasErrorPage(
2745          http_status_code, &error_domain)) {
2746    WebURLError error;
2747    error.unreachableURL = frame->document().url();
2748    error.domain = WebString::fromUTF8(error_domain);
2749    error.reason = http_status_code;
2750    LoadNavigationErrorPage(frame->dataSource()->request(), error, true);
2751  }
2752}
2753
2754void RenderFrameImpl::didLoadResourceFromMemoryCache(
2755    blink::WebLocalFrame* frame,
2756    const blink::WebURLRequest& request,
2757    const blink::WebURLResponse& response) {
2758  DCHECK(!frame_ || frame_ == frame);
2759  // The recipients of this message have no use for data: URLs: they don't
2760  // affect the page's insecure content list and are not in the disk cache. To
2761  // prevent large (1M+) data: URLs from crashing in the IPC system, we simply
2762  // filter them out here.
2763  GURL url(request.url());
2764  if (url.SchemeIs("data"))
2765    return;
2766
2767  // Let the browser know we loaded a resource from the memory cache.  This
2768  // message is needed to display the correct SSL indicators.
2769  render_view_->Send(new ViewHostMsg_DidLoadResourceFromMemoryCache(
2770      render_view_->GetRoutingID(),
2771      url,
2772      response.securityInfo(),
2773      request.httpMethod().utf8(),
2774      response.mimeType().utf8(),
2775      WebURLRequestToResourceType(request)));
2776}
2777
2778void RenderFrameImpl::didDisplayInsecureContent(blink::WebLocalFrame* frame) {
2779  DCHECK(!frame_ || frame_ == frame);
2780  render_view_->Send(new ViewHostMsg_DidDisplayInsecureContent(
2781      render_view_->GetRoutingID()));
2782}
2783
2784void RenderFrameImpl::didRunInsecureContent(
2785    blink::WebLocalFrame* frame,
2786    const blink::WebSecurityOrigin& origin,
2787    const blink::WebURL& target) {
2788  DCHECK(!frame_ || frame_ == frame);
2789  render_view_->Send(new ViewHostMsg_DidRunInsecureContent(
2790      render_view_->GetRoutingID(),
2791      origin.toString().utf8(),
2792      target));
2793}
2794
2795void RenderFrameImpl::didAbortLoading(blink::WebLocalFrame* frame) {
2796  DCHECK(!frame_ || frame_ == frame);
2797#if defined(ENABLE_PLUGINS)
2798  if (frame != render_view_->webview()->mainFrame())
2799    return;
2800  PluginChannelHost::Broadcast(
2801      new PluginHostMsg_DidAbortLoading(render_view_->GetRoutingID()));
2802#endif
2803}
2804
2805void RenderFrameImpl::didCreateScriptContext(blink::WebLocalFrame* frame,
2806                                             v8::Handle<v8::Context> context,
2807                                             int extension_group,
2808                                             int world_id) {
2809  DCHECK(!frame_ || frame_ == frame);
2810  GetContentClient()->renderer()->DidCreateScriptContext(
2811      frame, context, extension_group, world_id);
2812}
2813
2814void RenderFrameImpl::willReleaseScriptContext(blink::WebLocalFrame* frame,
2815                                               v8::Handle<v8::Context> context,
2816                                               int world_id) {
2817  DCHECK(!frame_ || frame_ == frame);
2818
2819  FOR_EACH_OBSERVER(RenderFrameObserver,
2820                    observers_,
2821                    WillReleaseScriptContext(context, world_id));
2822}
2823
2824void RenderFrameImpl::didFirstVisuallyNonEmptyLayout(
2825    blink::WebLocalFrame* frame) {
2826  DCHECK(!frame_ || frame_ == frame);
2827  if (frame->parent())
2828    return;
2829
2830  InternalDocumentStateData* data =
2831      InternalDocumentStateData::FromDataSource(frame->dataSource());
2832  data->set_did_first_visually_non_empty_layout(true);
2833
2834#if defined(OS_ANDROID)
2835  GetRenderWidget()->DidChangeBodyBackgroundColor(
2836      render_view_->webwidget_->backgroundColor());
2837#endif
2838
2839  GetRenderWidget()->QueueMessage(
2840      new FrameHostMsg_DidFirstVisuallyNonEmptyPaint(routing_id_),
2841      MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE);
2842}
2843
2844void RenderFrameImpl::didChangeScrollOffset(blink::WebLocalFrame* frame) {
2845  DCHECK(!frame_ || frame_ == frame);
2846  // TODO(nasko): Move implementation here. Needed methods:
2847  // * StartNavStateSyncTimerIfNecessary
2848  render_view_->didChangeScrollOffset(frame);
2849}
2850
2851void RenderFrameImpl::willInsertBody(blink::WebLocalFrame* frame) {
2852  DCHECK(!frame_ || frame_ == frame);
2853  if (!frame->parent()) {
2854    render_view_->Send(new ViewHostMsg_WillInsertBody(
2855        render_view_->GetRoutingID()));
2856  }
2857}
2858
2859void RenderFrameImpl::reportFindInPageMatchCount(int request_id,
2860                                                 int count,
2861                                                 bool final_update) {
2862  int active_match_ordinal = -1;  // -1 = don't update active match ordinal
2863  if (!count)
2864    active_match_ordinal = 0;
2865
2866  render_view_->Send(new ViewHostMsg_Find_Reply(
2867      render_view_->GetRoutingID(), request_id, count,
2868      gfx::Rect(), active_match_ordinal, final_update));
2869}
2870
2871void RenderFrameImpl::reportFindInPageSelection(
2872    int request_id,
2873    int active_match_ordinal,
2874    const blink::WebRect& selection_rect) {
2875  render_view_->Send(new ViewHostMsg_Find_Reply(
2876      render_view_->GetRoutingID(), request_id, -1, selection_rect,
2877      active_match_ordinal, false));
2878}
2879
2880void RenderFrameImpl::requestStorageQuota(
2881    blink::WebLocalFrame* frame,
2882    blink::WebStorageQuotaType type,
2883    unsigned long long requested_size,
2884    blink::WebStorageQuotaCallbacks callbacks) {
2885  DCHECK(!frame_ || frame_ == frame);
2886  WebSecurityOrigin origin = frame->document().securityOrigin();
2887  if (origin.isUnique()) {
2888    // Unique origins cannot store persistent state.
2889    callbacks.didFail(blink::WebStorageQuotaErrorAbort);
2890    return;
2891  }
2892  ChildThread::current()->quota_dispatcher()->RequestStorageQuota(
2893      render_view_->GetRoutingID(),
2894      GURL(origin.toString()),
2895      static_cast<storage::StorageType>(type),
2896      requested_size,
2897      QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper(callbacks));
2898}
2899
2900void RenderFrameImpl::willOpenSocketStream(
2901    blink::WebSocketStreamHandle* handle) {
2902  WebSocketStreamHandleImpl* impl =
2903      static_cast<WebSocketStreamHandleImpl*>(handle);
2904  impl->SetUserData(handle, new SocketStreamHandleData(routing_id_));
2905}
2906
2907void RenderFrameImpl::willOpenWebSocket(blink::WebSocketHandle* handle) {
2908  WebSocketBridge* impl = static_cast<WebSocketBridge*>(handle);
2909  impl->set_render_frame_id(routing_id_);
2910}
2911
2912blink::WebGeolocationClient* RenderFrameImpl::geolocationClient() {
2913  if (!geolocation_dispatcher_)
2914    geolocation_dispatcher_ = new GeolocationDispatcher(this);
2915  return geolocation_dispatcher_;
2916}
2917
2918blink::WebPushClient* RenderFrameImpl::pushClient() {
2919  if (!push_messaging_dispatcher_)
2920    push_messaging_dispatcher_ = new PushMessagingDispatcher(this);
2921  return push_messaging_dispatcher_;
2922}
2923
2924void RenderFrameImpl::willStartUsingPeerConnectionHandler(
2925    blink::WebLocalFrame* frame,
2926    blink::WebRTCPeerConnectionHandler* handler) {
2927  DCHECK(!frame_ || frame_ == frame);
2928#if defined(ENABLE_WEBRTC)
2929  static_cast<RTCPeerConnectionHandler*>(handler)->associateWithFrame(frame);
2930#endif
2931}
2932
2933blink::WebUserMediaClient* RenderFrameImpl::userMediaClient() {
2934  if (!web_user_media_client_)
2935    InitializeUserMediaClient();
2936  return web_user_media_client_;
2937}
2938
2939blink::WebMIDIClient* RenderFrameImpl::webMIDIClient() {
2940  if (!midi_dispatcher_)
2941    midi_dispatcher_ = new MidiDispatcher(this);
2942  return midi_dispatcher_;
2943}
2944
2945bool RenderFrameImpl::willCheckAndDispatchMessageEvent(
2946    blink::WebLocalFrame* source_frame,
2947    blink::WebFrame* target_frame,
2948    blink::WebSecurityOrigin target_origin,
2949    blink::WebDOMMessageEvent event) {
2950  DCHECK(!frame_ || frame_ == target_frame);
2951
2952  if (!render_view_->is_swapped_out_)
2953    return false;
2954
2955  ViewMsg_PostMessage_Params params;
2956  params.is_data_raw_string = false;
2957  params.data = event.data().toString();
2958  params.source_origin = event.origin();
2959  if (!target_origin.isNull())
2960    params.target_origin = target_origin.toString();
2961
2962  blink::WebMessagePortChannelArray channels = event.releaseChannels();
2963  if (!channels.isEmpty()) {
2964    std::vector<int> message_port_ids(channels.size());
2965     // Extract the port IDs from the channel array.
2966     for (size_t i = 0; i < channels.size(); ++i) {
2967       WebMessagePortChannelImpl* webchannel =
2968           static_cast<WebMessagePortChannelImpl*>(channels[i]);
2969       message_port_ids[i] = webchannel->message_port_id();
2970       webchannel->QueueMessages();
2971       DCHECK_NE(message_port_ids[i], MSG_ROUTING_NONE);
2972     }
2973     params.message_port_ids = message_port_ids;
2974  }
2975
2976  // Include the routing ID for the source frame (if one exists), which the
2977  // browser process will translate into the routing ID for the equivalent
2978  // frame in the target process.
2979  params.source_routing_id = MSG_ROUTING_NONE;
2980  if (source_frame) {
2981    RenderViewImpl* source_view =
2982        RenderViewImpl::FromWebView(source_frame->view());
2983    if (source_view)
2984      params.source_routing_id = source_view->routing_id();
2985  }
2986
2987  Send(new ViewHostMsg_RouteMessageEvent(render_view_->routing_id_, params));
2988  return true;
2989}
2990
2991blink::WebString RenderFrameImpl::userAgentOverride(blink::WebLocalFrame* frame,
2992                                                    const blink::WebURL& url) {
2993  DCHECK(!frame_ || frame_ == frame);
2994  if (!render_view_->webview() || !render_view_->webview()->mainFrame() ||
2995      render_view_->renderer_preferences_.user_agent_override.empty()) {
2996    return blink::WebString();
2997  }
2998
2999  // If we're in the middle of committing a load, the data source we need
3000  // will still be provisional.
3001  WebFrame* main_frame = render_view_->webview()->mainFrame();
3002  WebDataSource* data_source = NULL;
3003  if (main_frame->provisionalDataSource())
3004    data_source = main_frame->provisionalDataSource();
3005  else
3006    data_source = main_frame->dataSource();
3007
3008  InternalDocumentStateData* internal_data = data_source ?
3009      InternalDocumentStateData::FromDataSource(data_source) : NULL;
3010  if (internal_data && internal_data->is_overriding_user_agent())
3011    return WebString::fromUTF8(
3012        render_view_->renderer_preferences_.user_agent_override);
3013  return blink::WebString();
3014}
3015
3016blink::WebString RenderFrameImpl::doNotTrackValue(blink::WebLocalFrame* frame) {
3017  DCHECK(!frame_ || frame_ == frame);
3018  if (render_view_->renderer_preferences_.enable_do_not_track)
3019    return WebString::fromUTF8("1");
3020  return WebString();
3021}
3022
3023bool RenderFrameImpl::allowWebGL(blink::WebLocalFrame* frame,
3024                                 bool default_value) {
3025  DCHECK(!frame_ || frame_ == frame);
3026  if (!default_value)
3027    return false;
3028
3029  bool blocked = true;
3030  render_view_->Send(new ViewHostMsg_Are3DAPIsBlocked(
3031      render_view_->GetRoutingID(),
3032      GURL(frame->top()->document().securityOrigin().toString()),
3033      THREE_D_API_TYPE_WEBGL,
3034      &blocked));
3035  return !blocked;
3036}
3037
3038void RenderFrameImpl::didLoseWebGLContext(blink::WebLocalFrame* frame,
3039                                          int arb_robustness_status_code) {
3040  DCHECK(!frame_ || frame_ == frame);
3041  render_view_->Send(new ViewHostMsg_DidLose3DContext(
3042      GURL(frame->top()->document().securityOrigin().toString()),
3043      THREE_D_API_TYPE_WEBGL,
3044      arb_robustness_status_code));
3045}
3046
3047void RenderFrameImpl::forwardInputEvent(const blink::WebInputEvent* event) {
3048  Send(new FrameHostMsg_ForwardInputEvent(routing_id_, event));
3049}
3050
3051void RenderFrameImpl::initializeChildFrame(const blink::WebRect& frame_rect,
3052                                           float scale_factor) {
3053  Send(new FrameHostMsg_InitializeChildFrame(
3054      routing_id_, frame_rect, scale_factor));
3055}
3056
3057blink::WebScreenOrientationClient*
3058    RenderFrameImpl::webScreenOrientationClient() {
3059  if (!screen_orientation_dispatcher_)
3060    screen_orientation_dispatcher_ = new ScreenOrientationDispatcher(this);
3061  return screen_orientation_dispatcher_;
3062}
3063
3064void RenderFrameImpl::DidPlay(blink::WebMediaPlayer* player) {
3065  Send(new FrameHostMsg_MediaPlayingNotification(
3066      routing_id_, reinterpret_cast<int64>(player), player->hasVideo(),
3067      player->hasAudio()));
3068}
3069
3070void RenderFrameImpl::DidPause(blink::WebMediaPlayer* player) {
3071  Send(new FrameHostMsg_MediaPausedNotification(
3072      routing_id_, reinterpret_cast<int64>(player)));
3073}
3074
3075void RenderFrameImpl::PlayerGone(blink::WebMediaPlayer* player) {
3076  DidPause(player);
3077}
3078
3079void RenderFrameImpl::AddObserver(RenderFrameObserver* observer) {
3080  observers_.AddObserver(observer);
3081}
3082
3083void RenderFrameImpl::RemoveObserver(RenderFrameObserver* observer) {
3084  observer->RenderFrameGone();
3085  observers_.RemoveObserver(observer);
3086}
3087
3088void RenderFrameImpl::OnStop() {
3089  DCHECK(frame_);
3090  frame_->stopLoading();
3091  if (!frame_->parent())
3092    FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers_, OnStop());
3093
3094  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, OnStop());
3095}
3096
3097void RenderFrameImpl::WasHidden() {
3098  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WasHidden());
3099}
3100
3101void RenderFrameImpl::WasShown() {
3102  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WasShown());
3103}
3104
3105bool RenderFrameImpl::IsHidden() {
3106  return GetRenderWidget()->is_hidden();
3107}
3108
3109// Tell the embedding application that the URL of the active page has changed.
3110void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame* frame) {
3111  DCHECK(!frame_ || frame_ == frame);
3112  WebDataSource* ds = frame->dataSource();
3113  DCHECK(ds);
3114
3115  const WebURLRequest& request = ds->request();
3116  const WebURLResponse& response = ds->response();
3117
3118  DocumentState* document_state = DocumentState::FromDataSource(ds);
3119  NavigationState* navigation_state = document_state->navigation_state();
3120  InternalDocumentStateData* internal_data =
3121      InternalDocumentStateData::FromDocumentState(document_state);
3122
3123  FrameHostMsg_DidCommitProvisionalLoad_Params params;
3124  params.http_status_code = response.httpStatusCode();
3125  params.is_post = false;
3126  params.post_id = -1;
3127  params.page_id = render_view_->page_id_;
3128  // We need to track the RenderViewHost routing_id because of downstream
3129  // dependencies (crbug.com/392171 DownloadRequestHandle, SaveFileManager,
3130  // ResourceDispatcherHostImpl, MediaStreamUIProxy,
3131  // SpeechRecognitionDispatcherHost and possibly others). They look up the view
3132  // based on the ID stored in the resource requests. Once those dependencies
3133  // are unwound or moved to RenderFrameHost (crbug.com/304341) we can move the
3134  // client to be based on the routing_id of the RenderFrameHost.
3135  params.render_view_routing_id = render_view_->routing_id();
3136  params.socket_address.set_host(response.remoteIPAddress().utf8());
3137  params.socket_address.set_port(response.remotePort());
3138  WebURLResponseExtraDataImpl* extra_data = GetExtraDataFromResponse(response);
3139  if (extra_data)
3140    params.was_fetched_via_proxy = extra_data->was_fetched_via_proxy();
3141  params.was_within_same_page = navigation_state->was_within_same_page();
3142  params.security_info = response.securityInfo();
3143
3144  // Set the URL to be displayed in the browser UI to the user.
3145  params.url = GetLoadingUrl();
3146  DCHECK(!is_swapped_out_ || params.url == GURL(kSwappedOutURL));
3147
3148  if (frame->document().baseURL() != params.url)
3149    params.base_url = frame->document().baseURL();
3150
3151  GetRedirectChain(ds, &params.redirects);
3152  params.should_update_history = !ds->hasUnreachableURL() &&
3153      !response.isMultipartPayload() && (response.httpStatusCode() != 404);
3154
3155  params.searchable_form_url = internal_data->searchable_form_url();
3156  params.searchable_form_encoding = internal_data->searchable_form_encoding();
3157
3158  params.gesture = render_view_->navigation_gesture_;
3159  render_view_->navigation_gesture_ = NavigationGestureUnknown;
3160
3161  // Make navigation state a part of the DidCommitProvisionalLoad message so
3162  // that commited entry has it at all times.
3163  HistoryEntry* entry = render_view_->history_controller()->GetCurrentEntry();
3164  if (entry)
3165    params.page_state = HistoryEntryToPageState(entry);
3166  else
3167    params.page_state = PageState::CreateFromURL(request.url());
3168
3169  if (!frame->parent()) {
3170    // Top-level navigation.
3171
3172    // Reset the zoom limits in case a plugin had changed them previously. This
3173    // will also call us back which will cause us to send a message to
3174    // update WebContentsImpl.
3175    render_view_->webview()->zoomLimitsChanged(
3176        ZoomFactorToZoomLevel(kMinimumZoomFactor),
3177        ZoomFactorToZoomLevel(kMaximumZoomFactor));
3178
3179    // Set zoom level, but don't do it for full-page plugin since they don't use
3180    // the same zoom settings.
3181    HostZoomLevels::iterator host_zoom =
3182        render_view_->host_zoom_levels_.find(GURL(request.url()));
3183    if (render_view_->webview()->mainFrame()->document().isPluginDocument()) {
3184      // Reset the zoom levels for plugins.
3185      render_view_->webview()->setZoomLevel(0);
3186    } else {
3187      if (host_zoom != render_view_->host_zoom_levels_.end())
3188        render_view_->webview()->setZoomLevel(host_zoom->second);
3189    }
3190
3191    if (host_zoom != render_view_->host_zoom_levels_.end()) {
3192      // This zoom level was merely recorded transiently for this load.  We can
3193      // erase it now.  If at some point we reload this page, the browser will
3194      // send us a new, up-to-date zoom level.
3195      render_view_->host_zoom_levels_.erase(host_zoom);
3196    }
3197
3198    // Update contents MIME type for main frame.
3199    params.contents_mime_type = ds->response().mimeType().utf8();
3200
3201    params.transition = navigation_state->transition_type();
3202    if (!PageTransitionIsMainFrame(params.transition)) {
3203      // If the main frame does a load, it should not be reported as a subframe
3204      // navigation.  This can occur in the following case:
3205      // 1. You're on a site with frames.
3206      // 2. You do a subframe navigation.  This is stored with transition type
3207      //    MANUAL_SUBFRAME.
3208      // 3. You navigate to some non-frame site, say, google.com.
3209      // 4. You navigate back to the page from step 2.  Since it was initially
3210      //    MANUAL_SUBFRAME, it will be that same transition type here.
3211      // We don't want that, because any navigation that changes the toplevel
3212      // frame should be tracked as a toplevel navigation (this allows us to
3213      // update the URL bar, etc).
3214      params.transition = PAGE_TRANSITION_LINK;
3215    }
3216
3217    // If the page contained a client redirect (meta refresh, document.loc...),
3218    // set the referrer and transition appropriately.
3219    if (ds->isClientRedirect()) {
3220      params.referrer =
3221          Referrer(params.redirects[0], ds->request().referrerPolicy());
3222      params.transition = static_cast<PageTransition>(
3223          params.transition | PAGE_TRANSITION_CLIENT_REDIRECT);
3224    } else {
3225      params.referrer = RenderViewImpl::GetReferrerFromRequest(
3226          frame, ds->request());
3227    }
3228
3229    base::string16 method = request.httpMethod();
3230    if (EqualsASCII(method, "POST")) {
3231      params.is_post = true;
3232      params.post_id = ExtractPostId(entry->root());
3233    }
3234
3235    // Send the user agent override back.
3236    params.is_overriding_user_agent = internal_data->is_overriding_user_agent();
3237
3238    // Track the URL of the original request.  We use the first entry of the
3239    // redirect chain if it exists because the chain may have started in another
3240    // process.
3241    params.original_request_url = GetOriginalRequestURL(ds);
3242
3243    params.history_list_was_cleared =
3244        navigation_state->history_list_was_cleared();
3245
3246    // Save some histogram data so we can compute the average memory used per
3247    // page load of the glyphs.
3248    UMA_HISTOGRAM_COUNTS_10000("Memory.GlyphPagesPerLoad",
3249                               blink::WebGlyphCache::pageCount());
3250
3251    // This message needs to be sent before any of allowScripts(),
3252    // allowImages(), allowPlugins() is called for the new page, so that when
3253    // these functions send a ViewHostMsg_ContentBlocked message, it arrives
3254    // after the FrameHostMsg_DidCommitProvisionalLoad message.
3255    Send(new FrameHostMsg_DidCommitProvisionalLoad(routing_id_, params));
3256  } else {
3257    // Subframe navigation: the type depends on whether this navigation
3258    // generated a new session history entry. When they do generate a session
3259    // history entry, it means the user initiated the navigation and we should
3260    // mark it as such. This test checks if this is the first time
3261    // SendDidCommitProvisionalLoad has been called since WillNavigateToURL was
3262    // called to initiate the load.
3263    if (render_view_->page_id_ > render_view_->last_page_id_sent_to_browser_)
3264      params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
3265    else
3266      params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
3267
3268    DCHECK(!navigation_state->history_list_was_cleared());
3269    params.history_list_was_cleared = false;
3270
3271    // Don't send this message while the subframe is swapped out.
3272    if (!is_swapped_out())
3273      Send(new FrameHostMsg_DidCommitProvisionalLoad(routing_id_, params));
3274  }
3275
3276  render_view_->last_page_id_sent_to_browser_ =
3277      std::max(render_view_->last_page_id_sent_to_browser_,
3278               render_view_->page_id_);
3279
3280  // If we end up reusing this WebRequest (for example, due to a #ref click),
3281  // we don't want the transition type to persist.  Just clear it.
3282  navigation_state->set_transition_type(PAGE_TRANSITION_LINK);
3283}
3284
3285WebElement RenderFrameImpl::GetFocusedElement() {
3286  WebDocument doc = frame_->document();
3287  if (!doc.isNull())
3288    return doc.focusedElement();
3289
3290  return WebElement();
3291}
3292
3293void RenderFrameImpl::didStartLoading(bool to_different_document) {
3294  render_view_->FrameDidStartLoading(frame_);
3295  Send(new FrameHostMsg_DidStartLoading(routing_id_, to_different_document));
3296}
3297
3298void RenderFrameImpl::didStopLoading() {
3299  render_view_->FrameDidStopLoading(frame_);
3300  Send(new FrameHostMsg_DidStopLoading(routing_id_));
3301}
3302
3303void RenderFrameImpl::didChangeLoadProgress(double load_progress) {
3304  Send(new FrameHostMsg_DidChangeLoadProgress(routing_id_, load_progress));
3305}
3306
3307void RenderFrameImpl::HandleWebAccessibilityEvent(
3308    const blink::WebAXObject& obj, blink::WebAXEvent event) {
3309  if (renderer_accessibility_)
3310    renderer_accessibility_->HandleWebAccessibilityEvent(obj, event);
3311}
3312
3313void RenderFrameImpl::FocusedNodeChanged(const WebNode& node) {
3314  if (renderer_accessibility_)
3315    renderer_accessibility_->FocusedNodeChanged(node);
3316}
3317
3318WebNavigationPolicy RenderFrameImpl::DecidePolicyForNavigation(
3319    RenderFrame* render_frame,
3320    const NavigationPolicyInfo& info) {
3321#ifdef OS_ANDROID
3322  // The handlenavigation API is deprecated and will be removed once
3323  // crbug.com/325351 is resolved.
3324  if (info.urlRequest.url() != GURL(kSwappedOutURL) &&
3325      GetContentClient()->renderer()->HandleNavigation(
3326          render_frame,
3327          static_cast<DocumentState*>(info.extraData),
3328          render_view_->opener_id_,
3329          info.frame,
3330          info.urlRequest,
3331          info.navigationType,
3332          info.defaultPolicy,
3333          info.isRedirect)) {
3334    return blink::WebNavigationPolicyIgnore;
3335  }
3336#endif
3337
3338  Referrer referrer(RenderViewImpl::GetReferrerFromRequest(info.frame,
3339                                                           info.urlRequest));
3340  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
3341
3342  bool is_subframe = !!info.frame->parent();
3343
3344  if (command_line.HasSwitch(switches::kSitePerProcess) && is_subframe) {
3345    // There's no reason to ignore navigations on subframes, since the swap out
3346    // logic no longer applies.
3347  } else {
3348    if (is_swapped_out_ || render_view_->is_swapped_out()) {
3349      if (info.urlRequest.url() != GURL(kSwappedOutURL)) {
3350        // Targeted links may try to navigate a swapped out frame.  Allow the
3351        // browser process to navigate the tab instead.  Note that it is also
3352        // possible for non-targeted navigations (from this view) to arrive
3353        // here just after we are swapped out.  It's ok to send them to the
3354        // browser, as long as they're for the top level frame.
3355        // TODO(creis): Ensure this supports targeted form submissions when
3356        // fixing http://crbug.com/101395.
3357        if (info.frame->parent() == NULL) {
3358          OpenURL(info.frame, info.urlRequest.url(), referrer,
3359                  info.defaultPolicy);
3360          return blink::WebNavigationPolicyIgnore;  // Suppress the load here.
3361        }
3362
3363        // We should otherwise ignore in-process iframe navigations, if they
3364        // arrive just after we are swapped out.
3365        return blink::WebNavigationPolicyIgnore;
3366      }
3367
3368      // Allow kSwappedOutURL to complete.
3369      return info.defaultPolicy;
3370    }
3371  }
3372
3373  // Webkit is asking whether to navigate to a new URL.
3374  // This is fine normally, except if we're showing UI from one security
3375  // context and they're trying to navigate to a different context.
3376  const GURL& url = info.urlRequest.url();
3377
3378  // A content initiated navigation may have originated from a link-click,
3379  // script, drag-n-drop operation, etc.
3380  bool is_content_initiated = static_cast<DocumentState*>(info.extraData)->
3381          navigation_state()->is_content_initiated();
3382
3383  // Experimental:
3384  // If --enable-strict-site-isolation or --site-per-process is enabled, send
3385  // all top-level navigations to the browser to let it swap processes when
3386  // crossing site boundaries.  This is currently expected to break some script
3387  // calls and navigations, such as form submissions.
3388  bool force_swap_due_to_flag =
3389      command_line.HasSwitch(switches::kEnableStrictSiteIsolation) ||
3390      command_line.HasSwitch(switches::kSitePerProcess);
3391  if (force_swap_due_to_flag &&
3392      !info.frame->parent() && (is_content_initiated || info.isRedirect)) {
3393    WebString origin_str = info.frame->document().securityOrigin().toString();
3394    GURL frame_url(origin_str.utf8().data());
3395    // TODO(cevans): revisit whether this site check is still necessary once
3396    // crbug.com/101395 is fixed.
3397    bool same_domain_or_host =
3398        net::registry_controlled_domains::SameDomainOrHost(
3399            frame_url,
3400            url,
3401            net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
3402    if (!same_domain_or_host || frame_url.scheme() != url.scheme()) {
3403      OpenURL(info.frame, url, referrer, info.defaultPolicy);
3404      return blink::WebNavigationPolicyIgnore;
3405    }
3406  }
3407
3408  // If the browser is interested, then give it a chance to look at the request.
3409  if (is_content_initiated) {
3410    bool is_form_post =
3411        ((info.navigationType == blink::WebNavigationTypeFormSubmitted) ||
3412            (info.navigationType == blink::WebNavigationTypeFormResubmitted)) &&
3413        EqualsASCII(info.urlRequest.httpMethod(), "POST");
3414    bool browser_handles_request =
3415        render_view_->renderer_preferences_
3416            .browser_handles_non_local_top_level_requests
3417        && IsNonLocalTopLevelNavigation(url, info.frame, info.navigationType,
3418                                        is_form_post);
3419    if (!browser_handles_request) {
3420      browser_handles_request = IsTopLevelNavigation(info.frame) &&
3421          render_view_->renderer_preferences_
3422              .browser_handles_all_top_level_requests;
3423    }
3424
3425    if (browser_handles_request) {
3426      // Reset these counters as the RenderView could be reused for the next
3427      // navigation.
3428      render_view_->page_id_ = -1;
3429      render_view_->last_page_id_sent_to_browser_ = -1;
3430      OpenURL(info.frame, url, referrer, info.defaultPolicy);
3431      return blink::WebNavigationPolicyIgnore;  // Suppress the load here.
3432    }
3433  }
3434
3435  // Use the frame's original request's URL rather than the document's URL for
3436  // subsequent checks.  For a popup, the document's URL may become the opener
3437  // window's URL if the opener has called document.write().
3438  // See http://crbug.com/93517.
3439  GURL old_url(info.frame->dataSource()->request().url());
3440
3441  // Detect when we're crossing a permission-based boundary (e.g. into or out of
3442  // an extension or app origin, leaving a WebUI page, etc). We only care about
3443  // top-level navigations (not iframes). But we sometimes navigate to
3444  // about:blank to clear a tab, and we want to still allow that.
3445  //
3446  // Note: this is known to break POST submissions when crossing process
3447  // boundaries until http://crbug.com/101395 is fixed.  This is better for
3448  // security than loading a WebUI, extension or app page in the wrong process.
3449  // POST requests don't work because this mechanism does not preserve form
3450  // POST data. We will need to send the request's httpBody data up to the
3451  // browser process, and issue a special POST navigation in WebKit (via
3452  // FrameLoader::loadFrameRequest). See ResourceDispatcher and WebURLLoaderImpl
3453  // for examples of how to send the httpBody data.
3454  if (!info.frame->parent() && is_content_initiated &&
3455      !url.SchemeIs(url::kAboutScheme)) {
3456    bool send_referrer = false;
3457
3458    // All navigations to or from WebUI URLs or within WebUI-enabled
3459    // RenderProcesses must be handled by the browser process so that the
3460    // correct bindings and data sources can be registered.
3461    // Similarly, navigations to view-source URLs or within ViewSource mode
3462    // must be handled by the browser process (except for reloads - those are
3463    // safe to leave within the renderer).
3464    // Lastly, access to file:// URLs from non-file:// URL pages must be
3465    // handled by the browser so that ordinary renderer processes don't get
3466    // blessed with file permissions.
3467    int cumulative_bindings = RenderProcess::current()->GetEnabledBindings();
3468    bool is_initial_navigation = render_view_->page_id_ == -1;
3469    bool should_fork = HasWebUIScheme(url) || HasWebUIScheme(old_url) ||
3470        (cumulative_bindings & BINDINGS_POLICY_WEB_UI) ||
3471        url.SchemeIs(kViewSourceScheme) ||
3472        (info.frame->isViewSourceModeEnabled() &&
3473            info.navigationType != blink::WebNavigationTypeReload);
3474
3475    if (!should_fork && url.SchemeIs(url::kFileScheme)) {
3476      // Fork non-file to file opens.  Check the opener URL if this is the
3477      // initial navigation in a newly opened window.
3478      GURL source_url(old_url);
3479      if (is_initial_navigation && source_url.is_empty() &&
3480          info.frame->opener())
3481        source_url = info.frame->opener()->top()->document().url();
3482      DCHECK(!source_url.is_empty());
3483      should_fork = !source_url.SchemeIs(url::kFileScheme);
3484    }
3485
3486    if (!should_fork) {
3487      // Give the embedder a chance.
3488      should_fork = GetContentClient()->renderer()->ShouldFork(
3489          info.frame, url, info.urlRequest.httpMethod().utf8(),
3490          is_initial_navigation, info.isRedirect, &send_referrer);
3491    }
3492
3493    if (should_fork) {
3494      OpenURL(info.frame, url, send_referrer ? referrer : Referrer(),
3495              info.defaultPolicy);
3496      return blink::WebNavigationPolicyIgnore;  // Suppress the load here.
3497    }
3498  }
3499
3500  // Detect when a page is "forking" a new tab that can be safely rendered in
3501  // its own process.  This is done by sites like Gmail that try to open links
3502  // in new windows without script connections back to the original page.  We
3503  // treat such cases as browser navigations (in which we will create a new
3504  // renderer for a cross-site navigation), rather than WebKit navigations.
3505  //
3506  // We use the following heuristic to decide whether to fork a new page in its
3507  // own process:
3508  // The parent page must open a new tab to about:blank, set the new tab's
3509  // window.opener to null, and then redirect the tab to a cross-site URL using
3510  // JavaScript.
3511  //
3512  // TODO(creis): Deprecate this logic once we can rely on rel=noreferrer
3513  // (see below).
3514  bool is_fork =
3515      // Must start from a tab showing about:blank, which is later redirected.
3516      old_url == GURL(url::kAboutBlankURL) &&
3517      // Must be the first real navigation of the tab.
3518      render_view_->historyBackListCount() < 1 &&
3519      render_view_->historyForwardListCount() < 1 &&
3520      // The parent page must have set the child's window.opener to null before
3521      // redirecting to the desired URL.
3522      info.frame->opener() == NULL &&
3523      // Must be a top-level frame.
3524      info.frame->parent() == NULL &&
3525      // Must not have issued the request from this page.
3526      is_content_initiated &&
3527      // Must be targeted at the current tab.
3528      info.defaultPolicy == blink::WebNavigationPolicyCurrentTab &&
3529      // Must be a JavaScript navigation, which appears as "other".
3530      info.navigationType == blink::WebNavigationTypeOther;
3531
3532  if (is_fork) {
3533    // Open the URL via the browser, not via WebKit.
3534    OpenURL(info.frame, url, Referrer(), info.defaultPolicy);
3535    return blink::WebNavigationPolicyIgnore;
3536  }
3537
3538  return info.defaultPolicy;
3539}
3540
3541void RenderFrameImpl::OpenURL(WebFrame* frame,
3542                              const GURL& url,
3543                              const Referrer& referrer,
3544                              WebNavigationPolicy policy) {
3545  DCHECK_EQ(frame_, frame);
3546
3547  FrameHostMsg_OpenURL_Params params;
3548  params.url = url;
3549  params.referrer = referrer;
3550  params.disposition = RenderViewImpl::NavigationPolicyToDisposition(policy);
3551  WebDataSource* ds = frame->provisionalDataSource();
3552  if (ds) {
3553    DocumentState* document_state = DocumentState::FromDataSource(ds);
3554    NavigationState* navigation_state = document_state->navigation_state();
3555    if (navigation_state->is_content_initiated()) {
3556      params.should_replace_current_entry = ds->replacesCurrentHistoryItem();
3557    } else {
3558      // This is necessary to preserve the should_replace_current_entry value on
3559      // cross-process redirects, in the event it was set by a previous process.
3560      //
3561      // TODO(davidben): Avoid this awkward duplication of state. See comment on
3562      // NavigationState::should_replace_current_entry().
3563      params.should_replace_current_entry =
3564          navigation_state->should_replace_current_entry();
3565    }
3566  } else {
3567    params.should_replace_current_entry = false;
3568  }
3569  params.user_gesture = WebUserGestureIndicator::isProcessingUserGesture();
3570  if (GetContentClient()->renderer()->AllowPopup())
3571    params.user_gesture = true;
3572
3573  if (policy == blink::WebNavigationPolicyNewBackgroundTab ||
3574      policy == blink::WebNavigationPolicyNewForegroundTab ||
3575      policy == blink::WebNavigationPolicyNewWindow ||
3576      policy == blink::WebNavigationPolicyNewPopup) {
3577    WebUserGestureIndicator::consumeUserGesture();
3578  }
3579
3580  Send(new FrameHostMsg_OpenURL(routing_id_, params));
3581}
3582
3583void RenderFrameImpl::UpdateEncoding(WebFrame* frame,
3584                                     const std::string& encoding_name) {
3585  // Only update main frame's encoding_name.
3586  if (!frame->parent())
3587    Send(new FrameHostMsg_UpdateEncoding(routing_id_, encoding_name));
3588}
3589
3590void RenderFrameImpl::SyncSelectionIfRequired() {
3591  base::string16 text;
3592  size_t offset;
3593  gfx::Range range;
3594#if defined(ENABLE_PLUGINS)
3595  if (render_view_->focused_pepper_plugin_) {
3596    render_view_->focused_pepper_plugin_->GetSurroundingText(&text, &range);
3597    offset = 0;  // Pepper API does not support offset reporting.
3598    // TODO(kinaba): cut as needed.
3599  } else
3600#endif
3601  {
3602    size_t location, length;
3603    if (!GetRenderWidget()->webwidget()->caretOrSelectionRange(
3604            &location, &length)) {
3605      return;
3606    }
3607
3608    range = gfx::Range(location, location + length);
3609
3610    if (GetRenderWidget()->webwidget()->textInputInfo().type !=
3611            blink::WebTextInputTypeNone) {
3612      // If current focused element is editable, we will send 100 more chars
3613      // before and after selection. It is for input method surrounding text
3614      // feature.
3615      if (location > kExtraCharsBeforeAndAfterSelection)
3616        offset = location - kExtraCharsBeforeAndAfterSelection;
3617      else
3618        offset = 0;
3619      length = location + length - offset + kExtraCharsBeforeAndAfterSelection;
3620      WebRange webrange = WebRange::fromDocumentRange(frame_, offset, length);
3621      if (!webrange.isNull())
3622        text = WebRange::fromDocumentRange(
3623            frame_, offset, length).toPlainText();
3624    } else {
3625      offset = location;
3626      text = frame_->selectionAsText();
3627      // http://crbug.com/101435
3628      // In some case, frame->selectionAsText() returned text's length is not
3629      // equal to the length returned from webwidget()->caretOrSelectionRange().
3630      // So we have to set the range according to text.length().
3631      range.set_end(range.start() + text.length());
3632    }
3633  }
3634
3635  // Sometimes we get repeated didChangeSelection calls from webkit when
3636  // the selection hasn't actually changed. We don't want to report these
3637  // because it will cause us to continually claim the X clipboard.
3638  if (selection_text_offset_ != offset ||
3639      selection_range_ != range ||
3640      selection_text_ != text) {
3641    selection_text_ = text;
3642    selection_text_offset_ = offset;
3643    selection_range_ = range;
3644    // This IPC is dispatched by RenderWidetHost, so use its routing ID.
3645    Send(new ViewHostMsg_SelectionChanged(
3646        GetRenderWidget()->routing_id(), text, offset, range));
3647  }
3648  GetRenderWidget()->UpdateSelectionBounds();
3649}
3650
3651void RenderFrameImpl::InitializeUserMediaClient() {
3652  if (!RenderThreadImpl::current())  // Will be NULL during unit tests.
3653    return;
3654
3655#if defined(OS_ANDROID)
3656  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableWebRTC))
3657    return;
3658#endif
3659
3660#if defined(ENABLE_WEBRTC)
3661  DCHECK(!web_user_media_client_);
3662  web_user_media_client_ = new MediaStreamImpl(
3663      this,
3664      RenderThreadImpl::current()->GetPeerConnectionDependencyFactory(),
3665      make_scoped_ptr(new MediaStreamDispatcher(this)).Pass());
3666#endif
3667}
3668
3669WebMediaPlayer* RenderFrameImpl::CreateWebMediaPlayerForMediaStream(
3670    const blink::WebURL& url,
3671    WebMediaPlayerClient* client) {
3672#if defined(ENABLE_WEBRTC)
3673#if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL)
3674  bool found_neon =
3675      (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
3676  UMA_HISTOGRAM_BOOLEAN("Platform.WebRtcNEONFound", found_neon);
3677#endif  // defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL)
3678  return new WebMediaPlayerMS(frame_, client, weak_factory_.GetWeakPtr(),
3679                              new RenderMediaLog(),
3680                              CreateRendererFactory());
3681#else
3682  return NULL;
3683#endif  // defined(ENABLE_WEBRTC)
3684}
3685
3686scoped_ptr<MediaStreamRendererFactory>
3687RenderFrameImpl::CreateRendererFactory() {
3688#if defined(ENABLE_WEBRTC)
3689  return scoped_ptr<MediaStreamRendererFactory>(
3690      new MediaStreamRendererFactory());
3691#else
3692  return scoped_ptr<MediaStreamRendererFactory>(
3693      static_cast<MediaStreamRendererFactory*>(NULL));
3694#endif
3695}
3696
3697GURL RenderFrameImpl::GetLoadingUrl() const {
3698  WebDataSource* ds = frame_->dataSource();
3699  if (ds->hasUnreachableURL())
3700    return ds->unreachableURL();
3701
3702  const WebURLRequest& request = ds->request();
3703  return request.url();
3704}
3705
3706#if defined(OS_ANDROID)
3707
3708WebMediaPlayer* RenderFrameImpl::CreateAndroidWebMediaPlayer(
3709      const blink::WebURL& url,
3710      WebMediaPlayerClient* client) {
3711  GpuChannelHost* gpu_channel_host =
3712      RenderThreadImpl::current()->EstablishGpuChannelSync(
3713          CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE);
3714  if (!gpu_channel_host) {
3715    LOG(ERROR) << "Failed to establish GPU channel for media player";
3716    return NULL;
3717  }
3718
3719  scoped_refptr<StreamTextureFactory> stream_texture_factory;
3720  if (SynchronousCompositorFactory* factory =
3721          SynchronousCompositorFactory::GetInstance()) {
3722    stream_texture_factory = factory->CreateStreamTextureFactory(routing_id_);
3723  } else {
3724    scoped_refptr<webkit::gpu::ContextProviderWebContext> context_provider =
3725        RenderThreadImpl::current()->SharedMainThreadContextProvider();
3726
3727    if (!context_provider.get()) {
3728      LOG(ERROR) << "Failed to get context3d for media player";
3729      return NULL;
3730    }
3731
3732    stream_texture_factory = StreamTextureFactoryImpl::Create(
3733        context_provider, gpu_channel_host, routing_id_);
3734  }
3735
3736  return new WebMediaPlayerAndroid(
3737      frame_,
3738      client,
3739      weak_factory_.GetWeakPtr(),
3740      GetMediaPlayerManager(),
3741      GetCdmManager(),
3742      stream_texture_factory,
3743      RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy(),
3744      new RenderMediaLog());
3745}
3746
3747RendererMediaPlayerManager* RenderFrameImpl::GetMediaPlayerManager() {
3748  if (!media_player_manager_)
3749    media_player_manager_ = new RendererMediaPlayerManager(this);
3750  return media_player_manager_;
3751}
3752
3753#endif  // defined(OS_ANDROID)
3754
3755#if defined(ENABLE_BROWSER_CDMS)
3756RendererCdmManager* RenderFrameImpl::GetCdmManager() {
3757  if (!cdm_manager_)
3758    cdm_manager_ = new RendererCdmManager(this);
3759  return cdm_manager_;
3760}
3761#endif  // defined(ENABLE_BROWSER_CDMS)
3762
3763}  // namespace content
3764