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