Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / renderer / render_frame_impl.cc
index a2b838a..32e605c 100644 (file)
@@ -7,50 +7,98 @@
 #include <map>
 #include <string>
 
+#include "base/auto_reset.h"
 #include "base/command_line.h"
 #include "base/debug/alias.h"
+#include "base/debug/asan_invalid_access.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/i18n/char_iterator.h"
 #include "base/metrics/histogram.h"
 #include "base/process/kill.h"
 #include "base/process/process.h"
+#include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "content/child/appcache/appcache_dispatcher.h"
 #include "content/child/plugin_messages.h"
 #include "content/child/quota_dispatcher.h"
 #include "content/child/request_extra_data.h"
+#include "content/child/service_worker/service_worker_network_provider.h"
+#include "content/child/service_worker/service_worker_provider_context.h"
 #include "content/child/service_worker/web_service_worker_provider_impl.h"
+#include "content/child/web_socket_stream_handle_impl.h"
+#include "content/child/web_url_request_util.h"
+#include "content/child/webmessageportchannel_impl.h"
+#include "content/child/websocket_bridge.h"
+#include "content/child/weburlresponse_extradata_impl.h"
+#include "content/common/clipboard_messages.h"
 #include "content/common/frame_messages.h"
+#include "content/common/input_messages.h"
+#include "content/common/service_worker/service_worker_types.h"
 #include "content/common/socket_stream_handle_data.h"
 #include "content/common/swapped_out_messages.h"
 #include "content/common/view_messages.h"
+#include "content/public/common/bindings_policy.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/context_menu_params.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/url_utils.h"
+#include "content/public/renderer/browser_plugin_delegate.h"
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/public/renderer/context_menu_client.h"
 #include "content/public/renderer/document_state.h"
-#include "content/public/renderer/history_item_serialization.h"
 #include "content/public/renderer/navigation_state.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "content/renderer/accessibility/renderer_accessibility.h"
+#include "content/renderer/accessibility/renderer_accessibility_complete.h"
+#include "content/renderer/accessibility/renderer_accessibility_focus_only.h"
 #include "content/renderer/browser_plugin/browser_plugin.h"
 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
 #include "content/renderer/child_frame_compositing_helper.h"
 #include "content/renderer/context_menu_params_builder.h"
+#include "content/renderer/devtools/devtools_agent.h"
+#include "content/renderer/dom_automation_controller.h"
+#include "content/renderer/dom_utils.h"
+#include "content/renderer/external_popup_menu.h"
+#include "content/renderer/geolocation_dispatcher.h"
+#include "content/renderer/history_controller.h"
+#include "content/renderer/history_serialization.h"
+#include "content/renderer/image_loading_helper.h"
+#include "content/renderer/ime_event_guard.h"
 #include "content/renderer/internal_document_state_data.h"
+#include "content/renderer/manifest/manifest_manager.h"
+#include "content/renderer/media/audio_renderer_mixer_manager.h"
+#include "content/renderer/media/crypto/encrypted_media_player_support_impl.h"
+#include "content/renderer/media/media_stream_dispatcher.h"
+#include "content/renderer/media/media_stream_renderer_factory.h"
+#include "content/renderer/media/midi_dispatcher.h"
+#include "content/renderer/media/render_media_log.h"
+#include "content/renderer/media/user_media_client_impl.h"
+#include "content/renderer/media/webcontentdecryptionmodule_impl.h"
+#include "content/renderer/media/webmediaplayer_ms.h"
+#include "content/renderer/notification_permission_dispatcher.h"
+#include "content/renderer/notification_provider.h"
 #include "content/renderer/npapi/plugin_channel_host.h"
+#include "content/renderer/push_messaging_dispatcher.h"
+#include "content/renderer/render_frame_proxy.h"
+#include "content/renderer/render_process.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/render_view_impl.h"
 #include "content/renderer/render_widget_fullscreen_pepper.h"
 #include "content/renderer/renderer_webapplicationcachehost_impl.h"
+#include "content/renderer/renderer_webcolorchooser_impl.h"
+#include "content/renderer/screen_orientation/screen_orientation_dispatcher.h"
 #include "content/renderer/shared_worker_repository.h"
+#include "content/renderer/v8_value_converter_impl.h"
 #include "content/renderer/websharedworker_proxy.h"
+#include "media/base/audio_renderer_mixer_input.h"
+#include "media/blink/webmediaplayer_impl.h"
+#include "media/blink/webmediaplayer_params.h"
+#include "media/filters/gpu_video_accelerator_factories.h"
 #include "net/base/data_url.h"
 #include "net/base/net_errors.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/http/http_util.h"
 #include "third_party/WebKit/public/platform/WebStorageQuotaCallbacks.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebURLError.h"
 #include "third_party/WebKit/public/platform/WebURLResponse.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/web/WebColorSuggestion.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebGlyphCache.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
 #include "third_party/WebKit/public/web/WebNavigationPolicy.h"
 #include "third_party/WebKit/public/web/WebPlugin.h"
 #include "third_party/WebKit/public/web/WebPluginParams.h"
+#include "third_party/WebKit/public/web/WebRange.h"
+#include "third_party/WebKit/public/web/WebScriptSource.h"
 #include "third_party/WebKit/public/web/WebSearchableFormData.h"
 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
+#include "third_party/WebKit/public/web/WebSurroundingText.h"
 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
 #include "third_party/WebKit/public/web/WebView.h"
-#include "webkit/child/weburlresponse_extradata_impl.h"
 
 #if defined(ENABLE_PLUGINS)
 #include "content/renderer/npapi/webplugin_impl.h"
 #include "content/renderer/media/rtc_peer_connection_handler.h"
 #endif
 
+#if defined(OS_ANDROID)
+#include <cpu-features.h>
+
+#include "content/common/gpu/client/context_provider_command_buffer.h"
+#include "content/renderer/android/synchronous_compositor_factory.h"
+#include "content/renderer/java/gin_java_bridge_dispatcher.h"
+#include "content/renderer/media/android/renderer_media_player_manager.h"
+#include "content/renderer/media/android/stream_texture_factory_impl.h"
+#include "content/renderer/media/android/webmediaplayer_android.h"
+#endif
+
+#if defined(ENABLE_BROWSER_CDMS)
+#include "content/renderer/media/crypto/renderer_cdm_manager.h"
+#endif
+
+#if defined(OS_TIZEN) && defined(ENABLE_MURPHY)
+#include "xwalk/tizen/renderer/media/renderer_mediaplayer_manager.h"
+#include "xwalk/tizen/renderer/media/mediaplayer_impl.h"
+#endif
+
 using blink::WebContextMenuData;
 using blink::WebData;
 using blink::WebDataSource;
 using blink::WebDocument;
+using blink::WebElement;
+using blink::WebExternalPopupMenu;
+using blink::WebExternalPopupMenuClient;
 using blink::WebFrame;
 using blink::WebHistoryItem;
 using blink::WebHTTPBody;
+using blink::WebLocalFrame;
+using blink::WebMediaPlayer;
+using blink::WebMediaPlayerClient;
 using blink::WebNavigationPolicy;
+using blink::WebNavigationType;
+using blink::WebNode;
 using blink::WebPluginParams;
+using blink::WebPopupMenuInfo;
+using blink::WebRange;
 using blink::WebReferrerPolicy;
+using blink::WebScriptSource;
 using blink::WebSearchableFormData;
 using blink::WebSecurityOrigin;
 using blink::WebSecurityPolicy;
@@ -108,12 +191,22 @@ using blink::WebVector;
 using blink::WebView;
 using base::Time;
 using base::TimeDelta;
-using webkit_glue::WebURLResponseExtraDataImpl;
 
 namespace content {
 
 namespace {
 
+const char kDefaultAcceptHeader[] =
+    "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/"
+    "*;q=0.8";
+const char kAcceptHeader[] = "Accept";
+
+const size_t kExtraCharsBeforeAndAfterSelection = 100;
+
+typedef std::map<int, RenderFrameImpl*> RoutingIDFrameMap;
+static base::LazyInstance<RoutingIDFrameMap> g_routing_id_frame_map =
+    LAZY_INSTANCE_INITIALIZER;
+
 typedef std::map<blink::WebFrame*, RenderFrameImpl*> FrameMap;
 base::LazyInstance<FrameMap> g_frame_map = LAZY_INSTANCE_INITIALIZER;
 
@@ -129,13 +222,12 @@ int64 ExtractPostId(const WebHistoryItem& item) {
 
 WebURLResponseExtraDataImpl* GetExtraDataFromResponse(
     const WebURLResponse& response) {
-  return static_cast<WebURLResponseExtraDataImpl*>(
-      response.extraData());
+  return static_cast<WebURLResponseExtraDataImpl*>(response.extraData());
 }
 
 void GetRedirectChain(WebDataSource* ds, std::vector<GURL>* result) {
   // Replace any occurrences of swappedout:// with about:blank.
-  const WebURL& blank_url = GURL(kAboutBlankURL);
+  const WebURL& blank_url = GURL(url::kAboutBlankURL);
   WebVector<WebURL> urls;
   ds->redirectChain(urls);
   result->reserve(urls.size());
@@ -147,6 +239,25 @@ void GetRedirectChain(WebDataSource* ds, std::vector<GURL>* result) {
   }
 }
 
+// Returns the original request url. If there is no redirect, the original
+// url is the same as ds->request()->url(). If the WebDataSource belongs to a
+// frame was loaded by loadData, the original url will be ds->unreachableURL()
+static GURL GetOriginalRequestURL(WebDataSource* ds) {
+  // WebDataSource has unreachable URL means that the frame is loaded through
+  // blink::WebFrame::loadData(), and the base URL will be in the redirect
+  // chain. However, we never visited the baseURL. So in this case, we should
+  // use the unreachable URL as the original URL.
+  if (ds->hasUnreachableURL())
+    return ds->unreachableURL();
+
+  std::vector<GURL> redirects;
+  GetRedirectChain(ds, &redirects);
+  if (!redirects.empty())
+    return redirects.at(0);
+
+  return ds->originalRequest().url();
+}
+
 NOINLINE static void CrashIntentionally() {
   // NOTE(shess): Crash directly rather than using NOTREACHED() so
   // that the signature is easier to triage in crash reports.
@@ -154,15 +265,18 @@ NOINLINE static void CrashIntentionally() {
   *zero = 0;
 }
 
-#if defined(ADDRESS_SANITIZER)
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
 NOINLINE static void MaybeTriggerAsanError(const GURL& url) {
   // NOTE(rogerm): We intentionally perform an invalid heap access here in
   //     order to trigger an Address Sanitizer (ASAN) error report.
-  static const char kCrashDomain[] = "crash";
-  static const char kHeapOverflow[] = "/heap-overflow";
-  static const char kHeapUnderflow[] = "/heap-underflow";
-  static const char kUseAfterFree[] = "/use-after-free";
-  static const int kArraySize = 5;
+  const char kCrashDomain[] = "crash";
+  const char kHeapOverflow[] = "/heap-overflow";
+  const char kHeapUnderflow[] = "/heap-underflow";
+  const char kUseAfterFree[] = "/use-after-free";
+#if defined(SYZYASAN)
+  const char kCorruptHeapBlock[] = "/corrupt-heap-block";
+  const char kCorruptHeap[] = "/corrupt-heap";
+#endif
 
   if (!url.DomainIs(kCrashDomain, sizeof(kCrashDomain) - 1))
     return;
@@ -170,29 +284,34 @@ NOINLINE static void MaybeTriggerAsanError(const GURL& url) {
   if (!url.has_path())
     return;
 
-  scoped_ptr<int[]> array(new int[kArraySize]);
   std::string crash_type(url.path());
-  int dummy = 0;
   if (crash_type == kHeapOverflow) {
-    dummy = array[kArraySize];
+    base::debug::AsanHeapOverflow();
   } else if (crash_type == kHeapUnderflow ) {
-    dummy = array[-1];
+    base::debug::AsanHeapUnderflow();
   } else if (crash_type == kUseAfterFree) {
-    int* dangling = array.get();
-    array.reset();
-    dummy = dangling[kArraySize / 2];
+    base::debug::AsanHeapUseAfterFree();
+#if defined(SYZYASAN)
+  } else if (crash_type == kCorruptHeapBlock) {
+    base::debug::AsanCorruptHeapBlock();
+  } else if (crash_type == kCorruptHeap) {
+    base::debug::AsanCorruptHeap();
+#endif
   }
-
-  // Make sure the assignments to the dummy value aren't optimized away.
-  base::debug::Alias(&dummy);
 }
-#endif  // ADDRESS_SANITIZER
+#endif  // ADDRESS_SANITIZER || SYZYASAN
 
 static void MaybeHandleDebugURL(const GURL& url) {
   if (!url.SchemeIs(kChromeUIScheme))
     return;
   if (url == GURL(kChromeUICrashURL)) {
     CrashIntentionally();
+  } else if (url == GURL(kChromeUIDumpURL)) {
+    // This URL will only correctly create a crash dump file if content is
+    // hosted in a process that has correctly called
+    // base::debug::SetDumpWithoutCrashingFunction.  Refer to the documentation
+    // of base::debug::DumpWithoutCrashing for more details.
+    base::debug::DumpWithoutCrashing();
   } else if (url == GURL(kChromeUIKillURL)) {
     base::KillProcess(base::GetCurrentProcessHandle(), 1, false);
   } else if (url == GURL(kChromeUIHangURL)) {
@@ -203,9 +322,47 @@ static void MaybeHandleDebugURL(const GURL& url) {
     base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(20));
   }
 
-#if defined(ADDRESS_SANITIZER)
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
   MaybeTriggerAsanError(url);
-#endif  // ADDRESS_SANITIZER
+#endif  // ADDRESS_SANITIZER || SYZYASAN
+}
+
+// Returns false unless this is a top-level navigation.
+static bool IsTopLevelNavigation(WebFrame* frame) {
+  return frame->parent() == NULL;
+}
+
+// Returns false unless this is a top-level navigation that crosses origins.
+static bool IsNonLocalTopLevelNavigation(const GURL& url,
+                                         WebFrame* frame,
+                                         WebNavigationType type,
+                                         bool is_form_post) {
+  if (!IsTopLevelNavigation(frame))
+    return false;
+
+  // Navigations initiated within Webkit are not sent out to the external host
+  // in the following cases.
+  // 1. The url scheme is not http/https
+  // 2. The origin of the url and the opener is the same in which case the
+  //    opener relationship is maintained.
+  // 3. Reloads/form submits/back forward navigations
+  if (!url.SchemeIs(url::kHttpScheme) && !url.SchemeIs(url::kHttpsScheme))
+    return false;
+
+  if (type != blink::WebNavigationTypeReload &&
+      type != blink::WebNavigationTypeBackForward && !is_form_post) {
+    // The opener relationship between the new window and the parent allows the
+    // new window to script the parent and vice versa. This is not allowed if
+    // the origins of the two domains are different. This can be treated as a
+    // top level navigation and routed back to the host.
+    blink::WebFrame* opener = frame->opener();
+    if (!opener)
+      return true;
+
+    if (url.GetOrigin() != GURL(opener->document().url()).GetOrigin())
+      return true;
+  }
+  return false;
 }
 
 }  // namespace
@@ -225,10 +382,43 @@ RenderFrameImpl* RenderFrameImpl::Create(RenderViewImpl* render_view,
 }
 
 // static
+RenderFrameImpl* RenderFrameImpl::FromRoutingID(int32 routing_id) {
+  RoutingIDFrameMap::iterator iter =
+      g_routing_id_frame_map.Get().find(routing_id);
+  if (iter != g_routing_id_frame_map.Get().end())
+    return iter->second;
+  return NULL;
+}
+
+// static
+void RenderFrameImpl::CreateFrame(int routing_id, int parent_routing_id) {
+  // TODO(nasko): For now, this message is only sent for subframes, as the
+  // top level frame is created when the RenderView is created through the
+  // ViewMsg_New IPC.
+  CHECK_NE(MSG_ROUTING_NONE, parent_routing_id);
+
+  RenderFrameProxy* proxy = RenderFrameProxy::FromRoutingID(parent_routing_id);
+
+  // If the browser is sending a valid parent routing id, it should already be
+  // created and registered.
+  CHECK(proxy);
+  blink::WebRemoteFrame* parent_web_frame = proxy->web_frame();
+
+  // Create the RenderFrame and WebLocalFrame, linking the two.
+  RenderFrameImpl* render_frame =
+      RenderFrameImpl::Create(proxy->render_view(), routing_id);
+  blink::WebLocalFrame* web_frame =
+      parent_web_frame->createLocalChild("", render_frame);
+  render_frame->SetWebFrame(web_frame);
+  render_frame->Initialize();
+}
+
+// static
 RenderFrame* RenderFrame::FromWebFrame(blink::WebFrame* web_frame) {
   return RenderFrameImpl::FromWebFrame(web_frame);
 }
 
+// static
 RenderFrameImpl* RenderFrameImpl::FromWebFrame(blink::WebFrame* web_frame) {
   FrameMap::iterator iter = g_frame_map.Get().find(web_frame);
   if (iter != g_frame_map.Get().end())
@@ -249,18 +439,69 @@ RenderFrameImpl::RenderFrameImpl(RenderViewImpl* render_view, int routing_id)
       render_view_(render_view->AsWeakPtr()),
       routing_id_(routing_id),
       is_swapped_out_(false),
+      render_frame_proxy_(NULL),
       is_detaching_(false),
-      cookie_jar_(this) {
+      cookie_jar_(this),
+      selection_text_offset_(0),
+      selection_range_(gfx::Range::InvalidRange()),
+      handling_select_range_(false),
+      notification_permission_dispatcher_(NULL),
+      notification_provider_(NULL),
+      web_user_media_client_(NULL),
+      midi_dispatcher_(NULL),
+#if defined(OS_ANDROID)
+      media_player_manager_(NULL),
+#endif
+#if defined(ENABLE_BROWSER_CDMS)
+      cdm_manager_(NULL),
+#endif
+#if defined(VIDEO_HOLE)
+      contains_media_player_(false),
+#endif
+#if defined(OS_TIZEN) && defined(ENABLE_MURPHY)
+      media_player_manager_(NULL),
+#endif
+      geolocation_dispatcher_(NULL),
+      push_messaging_dispatcher_(NULL),
+      screen_orientation_dispatcher_(NULL),
+      manifest_manager_(NULL),
+      accessibility_mode_(AccessibilityModeOff),
+      renderer_accessibility_(NULL),
+      weak_factory_(this) {
+  std::pair<RoutingIDFrameMap::iterator, bool> result =
+      g_routing_id_frame_map.Get().insert(std::make_pair(routing_id_, this));
+  CHECK(result.second) << "Inserting a duplicate item.";
+
   RenderThread::Get()->AddRoute(routing_id_, this);
+
+  render_view_->RegisterRenderFrame(this);
+
+#if defined(OS_ANDROID)
+  new GinJavaBridgeDispatcher(this);
+#endif
+
+#if defined(ENABLE_NOTIFICATIONS)
+  notification_provider_ = new NotificationProvider(this);
+#endif
+
+  manifest_manager_ = new ManifestManager(this);
 }
 
 RenderFrameImpl::~RenderFrameImpl() {
   FOR_EACH_OBSERVER(RenderFrameObserver, observers_, RenderFrameGone());
   FOR_EACH_OBSERVER(RenderFrameObserver, observers_, OnDestruct());
+
+#if defined(VIDEO_HOLE)
+  if (contains_media_player_)
+    render_view_->UnregisterVideoHoleFrame(this);
+#endif
+
+  render_view_->UnregisterRenderFrame(this);
+  g_routing_id_frame_map.Get().erase(routing_id_);
   RenderThread::Get()->RemoveRoute(routing_id_);
 }
 
-void RenderFrameImpl::SetWebFrame(blink::WebFrame* web_frame) {
+void RenderFrameImpl::SetWebFrame(blink::WebLocalFrame* web_frame) {
   DCHECK(!frame_);
 
   std::pair<FrameMap::iterator, bool> result = g_frame_map.Get().insert(
@@ -268,12 +509,17 @@ void RenderFrameImpl::SetWebFrame(blink::WebFrame* web_frame) {
   CHECK(result.second) << "Inserting a duplicate item.";
 
   frame_ = web_frame;
+}
 
+void RenderFrameImpl::Initialize() {
 #if defined(ENABLE_PLUGINS)
   new PepperBrowserConnection(this);
 #endif
   new SharedWorkerRepository(this);
 
+  if (!frame_->parent())
+    new ImageLoadingHelper(this);
+
   // We delay calling this until we have the WebFrame so that any observer or
   // embedder can call GetWebFrame on any RenderFrame.
   GetContentClient()->renderer()->RenderFrameCreated(this);
@@ -311,11 +557,10 @@ void RenderFrameImpl::PepperTextInputTypeChanged(
   if (instance != render_view_->focused_pepper_plugin())
     return;
 
-  GetRenderWidget()->UpdateTextInputType();
-  if (render_view_->renderer_accessibility()) {
-    render_view_->renderer_accessibility()->FocusedNodeChanged(
-        blink::WebNode());
-  }
+  GetRenderWidget()->UpdateTextInputState(
+      RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
+  if (renderer_accessibility())
+    renderer_accessibility()->FocusedNodeChanged(WebNode());
 }
 
 void RenderFrameImpl::PepperCaretPositionChanged(
@@ -329,8 +574,8 @@ void RenderFrameImpl::PepperCancelComposition(
     PepperPluginInstanceImpl* instance) {
   if (instance != render_view_->focused_pepper_plugin())
     return;
-  Send(new ViewHostMsg_ImeCancelComposition(render_view_->GetRoutingID()));;
-#if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
+  Send(new InputHostMsg_ImeCancelComposition(render_view_->GetRoutingID()));;
+#if defined(OS_MACOSX) || defined(USE_AURA)
   GetRenderWidget()->UpdateCompositionInfo(true);
 #endif
 }
@@ -339,7 +584,7 @@ void RenderFrameImpl::PepperSelectionChanged(
     PepperPluginInstanceImpl* instance) {
   if (instance != render_view_->focused_pepper_plugin())
     return;
-  render_view_->SyncSelectionIfRequired();
+  SyncSelectionIfRequired();
 }
 
 RenderWidgetFullscreenPepper* RenderFrameImpl::CreatePepperFullscreenContainer(
@@ -465,18 +710,52 @@ void RenderFrameImpl::OnImeConfirmComposition(
 
 #endif  // ENABLE_PLUGINS
 
+MediaStreamDispatcher* RenderFrameImpl::GetMediaStreamDispatcher() {
+  if (!web_user_media_client_)
+    InitializeUserMediaClient();
+  return web_user_media_client_ ?
+      web_user_media_client_->media_stream_dispatcher() : NULL;
+}
+
 bool RenderFrameImpl::Send(IPC::Message* message) {
-  if (is_detaching_ ||
-      ((is_swapped_out_ || render_view_->is_swapped_out()) &&
-       !SwappedOutMessages::CanSendWhileSwappedOut(message))) {
+  if (is_detaching_) {
     delete message;
     return false;
   }
+  if (frame_->parent() == NULL &&
+      (is_swapped_out_ || render_view_->is_swapped_out())) {
+    if (!SwappedOutMessages::CanSendWhileSwappedOut(message)) {
+      delete message;
+      return false;
+    }
+
+    // In most cases, send IPCs through the proxy when swapped out. In some
+    // calls the associated RenderViewImpl routing id is used to send
+    // messages, so don't use the proxy.
+    if (render_frame_proxy_ && message->routing_id() == routing_id_)
+      return render_frame_proxy_->Send(message);
+  }
 
   return RenderThread::Get()->Send(message);
 }
 
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+void RenderFrameImpl::DidHideExternalPopupMenu() {
+  // We need to clear external_popup_menu_ as soon as ExternalPopupMenu::close
+  // is called. Otherwise, createExternalPopupMenu() for new popup will fail.
+  external_popup_menu_.reset();
+}
+#endif
+
 bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) {
+  // TODO(kenrb): document() should not be null, but as a transitional step
+  // we have RenderFrameProxy 'wrapping' a RenderFrameImpl, passing messages
+  // to this method. This happens for a top-level remote frame, where a
+  // document-less RenderFrame is replaced by a RenderFrameProxy but kept
+  // around and is still able to receive messages.
+  if (!frame_->document().isNull())
+    GetContentClient()->SetActiveURL(frame_->document().url());
+
   ObserverListBase<RenderFrameObserver>::Iterator it(observers_);
   RenderFrameObserver* observer;
   while ((observer = it.GetNext()) != NULL) {
@@ -485,34 +764,67 @@ bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) {
   }
 
   bool handled = true;
-  bool msg_is_ok = true;
-  IPC_BEGIN_MESSAGE_MAP_EX(RenderFrameImpl, msg, msg_is_ok)
+  IPC_BEGIN_MESSAGE_MAP(RenderFrameImpl, msg)
     IPC_MESSAGE_HANDLER(FrameMsg_Navigate, OnNavigate)
+    IPC_MESSAGE_HANDLER(FrameMsg_BeforeUnload, OnBeforeUnload)
     IPC_MESSAGE_HANDLER(FrameMsg_SwapOut, OnSwapOut)
-    IPC_MESSAGE_HANDLER(FrameMsg_BuffersSwapped, OnBuffersSwapped)
-    IPC_MESSAGE_HANDLER_GENERIC(FrameMsg_CompositorFrameSwapped,
-                                OnCompositorFrameSwapped(msg))
-    IPC_MESSAGE_HANDLER(FrameMsg_ChildFrameProcessGone, OnChildFrameProcessGone)
+    IPC_MESSAGE_HANDLER(FrameMsg_Stop, OnStop)
     IPC_MESSAGE_HANDLER(FrameMsg_ContextMenuClosed, OnContextMenuClosed)
     IPC_MESSAGE_HANDLER(FrameMsg_CustomContextMenuAction,
                         OnCustomContextMenuAction)
-  IPC_END_MESSAGE_MAP_EX()
-
-  if (!msg_is_ok) {
-    // The message had a handler, but its deserialization failed.
-    // Kill the renderer to avoid potential spoofing attacks.
-    CHECK(false) << "Unable to deserialize message in RenderFrameImpl.";
-  }
+    IPC_MESSAGE_HANDLER(InputMsg_Undo, OnUndo)
+    IPC_MESSAGE_HANDLER(InputMsg_Redo, OnRedo)
+    IPC_MESSAGE_HANDLER(InputMsg_Cut, OnCut)
+    IPC_MESSAGE_HANDLER(InputMsg_Copy, OnCopy)
+    IPC_MESSAGE_HANDLER(InputMsg_Paste, OnPaste)
+    IPC_MESSAGE_HANDLER(InputMsg_PasteAndMatchStyle, OnPasteAndMatchStyle)
+    IPC_MESSAGE_HANDLER(InputMsg_Delete, OnDelete)
+    IPC_MESSAGE_HANDLER(InputMsg_SelectAll, OnSelectAll)
+    IPC_MESSAGE_HANDLER(InputMsg_SelectRange, OnSelectRange)
+    IPC_MESSAGE_HANDLER(InputMsg_Unselect, OnUnselect)
+    IPC_MESSAGE_HANDLER(InputMsg_Replace, OnReplace)
+    IPC_MESSAGE_HANDLER(InputMsg_ReplaceMisspelling, OnReplaceMisspelling)
+    IPC_MESSAGE_HANDLER(InputMsg_ExtendSelectionAndDelete,
+                        OnExtendSelectionAndDelete)
+    IPC_MESSAGE_HANDLER(InputMsg_SetCompositionFromExistingText,
+                        OnSetCompositionFromExistingText)
+    IPC_MESSAGE_HANDLER(FrameMsg_CSSInsertRequest, OnCSSInsertRequest)
+    IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequest,
+                        OnJavaScriptExecuteRequest)
+    IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequestForTests,
+                        OnJavaScriptExecuteRequestForTests)
+    IPC_MESSAGE_HANDLER(FrameMsg_SetEditableSelectionOffsets,
+                        OnSetEditableSelectionOffsets)
+    IPC_MESSAGE_HANDLER(FrameMsg_SetupTransitionView, OnSetupTransitionView)
+    IPC_MESSAGE_HANDLER(FrameMsg_BeginExitTransition, OnBeginExitTransition)
+    IPC_MESSAGE_HANDLER(FrameMsg_Reload, OnReload)
+    IPC_MESSAGE_HANDLER(FrameMsg_TextSurroundingSelectionRequest,
+                        OnTextSurroundingSelectionRequest)
+    IPC_MESSAGE_HANDLER(FrameMsg_AddStyleSheetByURL,
+                        OnAddStyleSheetByURL)
+    IPC_MESSAGE_HANDLER(FrameMsg_SetAccessibilityMode,
+                        OnSetAccessibilityMode)
+    IPC_MESSAGE_HANDLER(FrameMsg_DisownOpener, OnDisownOpener)
+#if defined(OS_ANDROID)
+    IPC_MESSAGE_HANDLER(FrameMsg_SelectPopupMenuItems, OnSelectPopupMenuItems)
+#elif defined(OS_MACOSX)
+    IPC_MESSAGE_HANDLER(FrameMsg_SelectPopupMenuItem, OnSelectPopupMenuItem)
+    IPC_MESSAGE_HANDLER(InputMsg_CopyToFindPboard, OnCopyToFindPboard)
+#endif
+  IPC_END_MESSAGE_MAP()
 
   return handled;
 }
 
 void RenderFrameImpl::OnNavigate(const FrameMsg_Navigate_Params& params) {
+  TRACE_EVENT2("navigation", "RenderFrameImpl::OnNavigate",
+               "id", routing_id_, "url", params.url.possibly_invalid_spec());
   MaybeHandleDebugURL(params.url);
   if (!render_view_->webview())
     return;
 
-  render_view_->OnNavigate(params);
+  FOR_EACH_OBSERVER(
+      RenderViewObserver, render_view_->observers_, Navigate(params.url));
 
   bool is_reload = RenderViewImpl::IsReload(params);
   WebURLRequest::CachePolicy cache_policy =
@@ -524,7 +836,8 @@ void RenderFrameImpl::OnNavigate(const FrameMsg_Navigate_Params& params) {
     return;
 
   // Swap this renderer back in if necessary.
-  if (render_view_->is_swapped_out_) {
+  if (render_view_->is_swapped_out_ &&
+      GetWebFrame() == render_view_->webview()->mainFrame()) {
     // We marked the view as hidden when swapping the view out, so be sure to
     // reset the visibility state before navigating to the new URL.
     render_view_->webview()->setVisibilityState(
@@ -540,7 +853,7 @@ void RenderFrameImpl::OnNavigate(const FrameMsg_Navigate_Params& params) {
     // We refresh timezone when a view is swapped in since timezone
     // can get out of sync when the system timezone is updated while
     // the view is swapped out.
-    RenderViewImpl::NotifyTimezoneChange(render_view_->webview()->mainFrame());
+    RenderThreadImpl::NotifyTimezoneChange();
 
     render_view_->SetSwappedOut(false);
     is_swapped_out_ = false;
@@ -573,7 +886,7 @@ void RenderFrameImpl::OnNavigate(const FrameMsg_Navigate_Params& params) {
     CHECK(frame) << "Invalid frame name passed: " << params.frame_to_navigate;
   }
 
-  if (is_reload && frame->currentHistoryItem().isNull()) {
+  if (is_reload && !render_view_->history_controller()->GetCurrentEntry()) {
     // We cannot reload if we do not have any history state.  This happens, for
     // example, when recovering from a crash.
     is_reload = false;
@@ -601,12 +914,13 @@ void RenderFrameImpl::OnNavigate(const FrameMsg_Navigate_Params& params) {
   } else if (params.page_state.IsValid()) {
     // We must know the page ID of the page we are navigating back to.
     DCHECK_NE(params.page_id, -1);
-    WebHistoryItem item = PageStateToHistoryItem(params.page_state);
-    if (!item.isNull()) {
+    scoped_ptr<HistoryEntry> entry =
+        PageStateToHistoryEntry(params.page_state);
+    if (entry) {
       // Ensure we didn't save the swapped out URL in UpdateState, since the
       // browser should never be telling us to navigate to swappedout://.
-      CHECK(item.urlString() != WebString::fromUTF8(kSwappedOutURL));
-      frame->loadHistoryItem(item, cache_policy);
+      CHECK(entry->root().urlString() != WebString::fromUTF8(kSwappedOutURL));
+      render_view_->history_controller()->GoToEntry(entry.Pass(), cache_policy);
     }
   } else if (!params.base_url_for_data_url.is_empty()) {
     // A loadData request with a specified base URL.
@@ -667,17 +981,23 @@ void RenderFrameImpl::OnNavigate(const FrameMsg_Navigate_Params& params) {
       request.setHTTPBody(http_body);
     }
 
+    // Record this before starting the load, we need a lower bound of this time
+    // to sanitize the navigationStart override set below.
+    base::TimeTicks renderer_navigation_start = base::TimeTicks::Now();
     frame->loadRequest(request);
 
-    // If this is a cross-process navigation, the browser process will send
-    // along the proper navigation start value.
-    if (!params.browser_navigation_start.is_null() &&
-        frame->provisionalDataSource()) {
-      // browser_navigation_start is likely before this process existed, so we
-      // can't use InterProcessTimeTicksConverter. Instead, the best we can do
-      // is just ensure we don't report a bogus value in the future.
+    // The browser provides the navigation_start time to bootstrap the
+    // Navigation Timing information for the browser-initiated navigations. In
+    // case of cross-process navigations, this carries over the time of
+    // finishing the onbeforeunload handler of the previous page.
+    DCHECK(!params.browser_navigation_start.is_null());
+    if (frame->provisionalDataSource()) {
+      // |browser_navigation_start| is likely before this process existed, so we
+      // can't use InterProcessTimeTicksConverter. We need at least to ensure
+      // that the browser-side navigation start we set is not later than the one
+      // on the renderer side.
       base::TimeTicks navigation_start = std::min(
-          base::TimeTicks::Now(), params.browser_navigation_start);
+          params.browser_navigation_start, renderer_navigation_start);
       double navigation_start_seconds =
           (navigation_start - base::TimeTicks()).InSecondsF();
       frame->provisionalDataSource()->setNavigationStartTime(
@@ -689,21 +1009,58 @@ void RenderFrameImpl::OnNavigate(const FrameMsg_Navigate_Params& params) {
   render_view_->pending_navigation_params_.reset();
 }
 
-void RenderFrameImpl::OnSwapOut() {
-  // Only run unload if we're not swapped out yet, but send the ack either way.
-  if (!is_swapped_out_) {
-    // Swap this RenderView out so the tab can navigate to a page rendered by a
-    // different process.  This involves running the unload handler and clearing
-    // the page.  Once WasSwappedOut is called, we also allow this process to
-    // exit if there are no other active RenderViews in it.
+void RenderFrameImpl::BindServiceRegistry(
+    mojo::ScopedMessagePipeHandle service_provider_handle) {
+  service_registry_.BindRemoteServiceProvider(service_provider_handle.Pass());
+}
+
+void RenderFrameImpl::OnBeforeUnload() {
+  TRACE_EVENT1("navigation", "RenderFrameImpl::OnBeforeUnload",
+               "id", routing_id_);
+  // TODO(creis): Right now, this is only called on the main frame.  Make the
+  // browser process send dispatchBeforeUnloadEvent to every frame that needs
+  // it.
+  CHECK(!frame_->parent());
 
-    // Send an UpdateState message before we get swapped out.
+  base::TimeTicks before_unload_start_time = base::TimeTicks::Now();
+  bool proceed = frame_->dispatchBeforeUnloadEvent();
+  base::TimeTicks before_unload_end_time = base::TimeTicks::Now();
+  Send(new FrameHostMsg_BeforeUnload_ACK(routing_id_, proceed,
+                                         before_unload_start_time,
+                                         before_unload_end_time));
+}
+
+void RenderFrameImpl::OnSwapOut(int proxy_routing_id) {
+  TRACE_EVENT1("navigation", "RenderFrameImpl::OnSwapOut", "id", routing_id_);
+  RenderFrameProxy* proxy = NULL;
+  bool is_site_per_process =
+      CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess);
+  bool is_main_frame = !frame_->parent();
+
+  // Only run unload if we're not swapped out yet, but send the ack either way.
+  if (!is_swapped_out_ || !render_view_->is_swapped_out_) {
+    // Swap this RenderFrame out so the frame can navigate to a page rendered by
+    // a different process.  This involves running the unload handler and
+    // clearing the page.  We also allow this process to exit if there are no
+    // other active RenderFrames in it.
+
+    // Send an UpdateState message before we get swapped out. Create the
+    // RenderFrameProxy as well so its routing id is registered for receiving
+    // IPC messages.
     render_view_->SyncNavigationState();
+    proxy = RenderFrameProxy::CreateProxyToReplaceFrame(this,
+                                                        proxy_routing_id);
 
     // Synchronously run the unload handler before sending the ACK.
-    // TODO(creis): Add a WebFrame::dispatchUnloadEvent and call it here.
+    // TODO(creis): Call dispatchUnloadEvent unconditionally here to support
+    // unload on subframes as well.
+    if (is_main_frame)
+      frame_->dispatchUnloadEvent();
 
     // Swap out and stop sending any IPC messages that are not ACKs.
+    // TODO(nasko): Do we need RenderFrameImpl::is_swapped_out_ anymore?
+    if (is_main_frame)
+      render_view_->SetSwappedOut(true);
     is_swapped_out_ = true;
 
     // Now that we're swapped out and filtering IPC messages, stop loading to
@@ -712,53 +1069,53 @@ void RenderFrameImpl::OnSwapOut() {
     // TODO(creis): Should we be stopping all frames here and using
     // StopAltErrorPageFetcher with RenderView::OnStop, or just stopping this
     // frame?
-    frame_->stopLoading();
+    OnStop();
+
+    // Transfer settings such as initial drawing parameters to the remote frame
+    // that will replace this frame.
+    if (!is_main_frame)
+      proxy->web_frame()->initializeFromFrame(frame_);
 
     // Replace the page with a blank dummy URL. The unload handler will not be
     // run a second time, thanks to a check in FrameLoader::stopLoading.
     // TODO(creis): Need to add a better way to do this that avoids running the
     // beforeunload handler. For now, we just run it a second time silently.
-    render_view_->NavigateToSwappedOutURL(frame_);
-
-    render_view_->RegisterSwappedOutChildFrame(this);
+    if (!is_site_per_process || is_main_frame)
+      render_view_->NavigateToSwappedOutURL(frame_);
+
+    // Let WebKit know that this view is hidden so it can drop resources and
+    // stop compositing.
+    // TODO(creis): Support this for subframes as well.
+    if (is_main_frame) {
+      render_view_->webview()->setVisibilityState(
+          blink::WebPageVisibilityStateHidden, false);
+    }
   }
 
+  // It is now safe to show modal dialogs again.
+  // TODO(creis): Deal with modal dialogs from subframes.
+  if (is_main_frame)
+    render_view_->suppress_dialogs_until_swap_out_ = false;
+
   Send(new FrameHostMsg_SwapOut_ACK(routing_id_));
-}
 
-void RenderFrameImpl::OnBuffersSwapped(
-    const FrameMsg_BuffersSwapped_Params& params) {
-  if (!compositing_helper_.get()) {
-    compositing_helper_ =
-        ChildFrameCompositingHelper::CreateCompositingHelperForRenderFrame(
-            frame_, this, routing_id_);
-    compositing_helper_->EnableCompositing(true);
+  // Now that all of the cleanup is complete and the browser side is notified,
+  // start using the RenderFrameProxy, if one is created.
+  if (proxy) {
+    if (!is_main_frame) {
+      frame_->swap(proxy->web_frame());
+      if (is_site_per_process) {
+        // TODO(nasko): delete the frame here, since we've replaced it with a
+        // proxy.
+      }
+    } else {
+      set_render_frame_proxy(proxy);
+    }
   }
-  compositing_helper_->OnBuffersSwapped(
-      params.size,
-      params.mailbox,
-      params.gpu_route_id,
-      params.gpu_host_id,
-      render_view_->GetWebView()->deviceScaleFactor());
-}
-
-void RenderFrameImpl::OnCompositorFrameSwapped(const IPC::Message& message) {
-  FrameMsg_CompositorFrameSwapped::Param param;
-  if (!FrameMsg_CompositorFrameSwapped::Read(&message, &param))
-    return;
-  scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
-  param.a.frame.AssignTo(frame.get());
 
-  if (!compositing_helper_.get()) {
-    compositing_helper_ =
-        ChildFrameCompositingHelper::CreateCompositingHelperForRenderFrame(
-            frame_, this, routing_id_);
-    compositing_helper_->EnableCompositing(true);
-  }
-  compositing_helper_->OnCompositorFrameSwapped(frame.Pass(),
-                                                param.a.producing_route_id,
-                                                param.a.output_surface_id,
-                                                param.a.producing_host_id);
+  // Safe to exit if no one else is using the process.
+  if (is_main_frame)
+    render_view_->WasSwappedOut();
 }
 
 void RenderFrameImpl::OnContextMenuClosed(
@@ -772,8 +1129,13 @@ void RenderFrameImpl::OnContextMenuClosed(
       pending_context_menus_.Remove(custom_context.request_id);
     }
   } else {
+    if (custom_context.link_followed.is_valid()) {
+        frame_->sendPings(
+            DomUtils::ExtractParentAnchorNode(context_menu_node_),
+            custom_context.link_followed);
+    }
     // Internal request, forward to WebKit.
-    render_view_->context_menu_node_.reset();
+    context_menu_node_.reset();
   }
 }
 
@@ -792,6 +1154,256 @@ void RenderFrameImpl::OnCustomContextMenuAction(
   }
 }
 
+void RenderFrameImpl::OnUndo() {
+  frame_->executeCommand(WebString::fromUTF8("Undo"), GetFocusedElement());
+}
+
+void RenderFrameImpl::OnRedo() {
+  frame_->executeCommand(WebString::fromUTF8("Redo"), GetFocusedElement());
+}
+
+void RenderFrameImpl::OnCut() {
+  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
+  frame_->executeCommand(WebString::fromUTF8("Cut"), GetFocusedElement());
+}
+
+void RenderFrameImpl::OnCopy() {
+  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
+  WebNode current_node = context_menu_node_.isNull() ?
+      GetFocusedElement() : context_menu_node_;
+  frame_->executeCommand(WebString::fromUTF8("Copy"), current_node);
+}
+
+void RenderFrameImpl::OnPaste() {
+  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
+  frame_->executeCommand(WebString::fromUTF8("Paste"), GetFocusedElement());
+}
+
+void RenderFrameImpl::OnPasteAndMatchStyle() {
+  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
+  frame_->executeCommand(
+      WebString::fromUTF8("PasteAndMatchStyle"), GetFocusedElement());
+}
+
+#if defined(OS_MACOSX)
+void RenderFrameImpl::OnCopyToFindPboard() {
+  // Since the find pasteboard supports only plain text, this can be simpler
+  // than the |OnCopy()| case.
+  if (frame_->hasSelection()) {
+    base::string16 selection = frame_->selectionAsText();
+    RenderThread::Get()->Send(
+        new ClipboardHostMsg_FindPboardWriteStringAsync(selection));
+  }
+}
+#endif
+
+void RenderFrameImpl::OnDelete() {
+  frame_->executeCommand(WebString::fromUTF8("Delete"), GetFocusedElement());
+}
+
+void RenderFrameImpl::OnSelectAll() {
+  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
+  frame_->executeCommand(WebString::fromUTF8("SelectAll"), GetFocusedElement());
+}
+
+void RenderFrameImpl::OnSelectRange(const gfx::Point& start,
+                                    const gfx::Point& end) {
+  // This IPC is dispatched by RenderWidgetHost, so use its routing id.
+  Send(new ViewHostMsg_SelectRange_ACK(GetRenderWidget()->routing_id()));
+
+  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
+  frame_->selectRange(start, end);
+}
+
+void RenderFrameImpl::OnUnselect() {
+  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
+  frame_->executeCommand(WebString::fromUTF8("Unselect"), GetFocusedElement());
+}
+
+void RenderFrameImpl::OnReplace(const base::string16& text) {
+  if (!frame_->hasSelection())
+    frame_->selectWordAroundCaret();
+
+  frame_->replaceSelection(text);
+}
+
+void RenderFrameImpl::OnReplaceMisspelling(const base::string16& text) {
+  if (!frame_->hasSelection())
+    return;
+
+  frame_->replaceMisspelledRange(text);
+}
+
+void RenderFrameImpl::OnCSSInsertRequest(const std::string& css) {
+  frame_->document().insertStyleSheet(WebString::fromUTF8(css));
+}
+
+void RenderFrameImpl::OnJavaScriptExecuteRequest(
+    const base::string16& jscript,
+    int id,
+    bool notify_result) {
+  TRACE_EVENT_INSTANT0("test_tracing", "OnJavaScriptExecuteRequest",
+                       TRACE_EVENT_SCOPE_THREAD);
+
+  v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
+  v8::Handle<v8::Value> result =
+      frame_->executeScriptAndReturnValue(WebScriptSource(jscript));
+
+  HandleJavascriptExecutionResult(jscript, id, notify_result, result);
+}
+
+void RenderFrameImpl::OnJavaScriptExecuteRequestForTests(
+    const base::string16& jscript,
+    int id,
+    bool notify_result) {
+  TRACE_EVENT_INSTANT0("test_tracing", "OnJavaScriptExecuteRequestForTests",
+                       TRACE_EVENT_SCOPE_THREAD);
+
+  v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
+  v8::Handle<v8::Value> result =
+      frame_->executeScriptAndReturnValueForTests(WebScriptSource(jscript));
+
+  HandleJavascriptExecutionResult(jscript, id, notify_result, result);
+}
+
+void RenderFrameImpl::HandleJavascriptExecutionResult(
+    const base::string16& jscript,
+    int id,
+    bool notify_result,
+    v8::Handle<v8::Value> result) {
+  if (notify_result) {
+    base::ListValue list;
+    if (!result.IsEmpty()) {
+      v8::Local<v8::Context> context = frame_->mainWorldScriptContext();
+      v8::Context::Scope context_scope(context);
+      V8ValueConverterImpl converter;
+      converter.SetDateAllowed(true);
+      converter.SetRegExpAllowed(true);
+      base::Value* result_value = converter.FromV8Value(result, context);
+      list.Set(0, result_value ? result_value : base::Value::CreateNullValue());
+    } else {
+      list.Set(0, base::Value::CreateNullValue());
+    }
+    Send(new FrameHostMsg_JavaScriptExecuteResponse(routing_id_, id, list));
+  }
+}
+
+void RenderFrameImpl::OnSetEditableSelectionOffsets(int start, int end) {
+  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
+  if (!GetRenderWidget()->ShouldHandleImeEvent())
+    return;
+  ImeEventGuard guard(GetRenderWidget());
+  frame_->setEditableSelectionOffsets(start, end);
+}
+
+void RenderFrameImpl::OnSetCompositionFromExistingText(
+    int start, int end,
+    const std::vector<blink::WebCompositionUnderline>& underlines) {
+  if (!GetRenderWidget()->ShouldHandleImeEvent())
+    return;
+  ImeEventGuard guard(GetRenderWidget());
+  frame_->setCompositionFromExistingText(start, end, underlines);
+}
+
+void RenderFrameImpl::OnExtendSelectionAndDelete(int before, int after) {
+  if (!GetRenderWidget()->ShouldHandleImeEvent())
+    return;
+  ImeEventGuard guard(GetRenderWidget());
+  frame_->extendSelectionAndDelete(before, after);
+}
+
+void RenderFrameImpl::OnSetAccessibilityMode(AccessibilityMode new_mode) {
+  if (accessibility_mode_ == new_mode)
+    return;
+  accessibility_mode_ = new_mode;
+  if (renderer_accessibility_) {
+    delete renderer_accessibility_;
+    renderer_accessibility_ = NULL;
+  }
+  if (accessibility_mode_ == AccessibilityModeOff)
+    return;
+
+  if (accessibility_mode_ & AccessibilityModeFlagFullTree)
+    renderer_accessibility_ = new RendererAccessibilityComplete(this);
+#if !defined(OS_ANDROID)
+  else
+    renderer_accessibility_ = new RendererAccessibilityFocusOnly(this);
+#endif
+}
+
+void RenderFrameImpl::OnDisownOpener() {
+  // TODO(creis): We should only see this for main frames for now.  To support
+  // disowning the opener on subframes, we will need to move WebContentsImpl's
+  // opener_ to FrameTreeNode.
+  CHECK(!frame_->parent());
+
+  if (frame_->opener())
+    frame_->setOpener(NULL);
+}
+
+#if defined(OS_ANDROID)
+void RenderFrameImpl::OnSelectPopupMenuItems(
+    bool canceled,
+    const std::vector<int>& selected_indices) {
+  // It is possible to receive more than one of these calls if the user presses
+  // a select faster than it takes for the show-select-popup IPC message to make
+  // it to the browser UI thread. Ignore the extra-messages.
+  // TODO(jcivelli): http:/b/5793321 Implement a better fix, as detailed in bug.
+  if (!external_popup_menu_)
+    return;
+
+  external_popup_menu_->DidSelectItems(canceled, selected_indices);
+  external_popup_menu_.reset();
+}
+#endif
+
+#if defined(OS_MACOSX)
+void RenderFrameImpl::OnSelectPopupMenuItem(int selected_index) {
+  if (external_popup_menu_ == NULL)
+    return;
+  external_popup_menu_->DidSelectItem(selected_index);
+  external_popup_menu_.reset();
+}
+#endif
+
+void RenderFrameImpl::OnReload(bool ignore_cache) {
+  frame_->reload(ignore_cache);
+}
+
+void RenderFrameImpl::OnTextSurroundingSelectionRequest(size_t max_length) {
+  blink::WebSurroundingText surroundingText;
+  surroundingText.initialize(frame_->selectionRange(), max_length);
+
+  if (surroundingText.isNull()) {
+    // |surroundingText| might not be correctly initialized, for example if
+    // |frame_->selectionRange().isNull()|, in other words, if there was no
+    // selection.
+    Send(new FrameHostMsg_TextSurroundingSelectionResponse(
+        routing_id_, base::string16(), 0, 0));
+    return;
+  }
+
+  Send(new FrameHostMsg_TextSurroundingSelectionResponse(
+      routing_id_,
+      surroundingText.textContent(),
+      surroundingText.startOffsetInTextContent(),
+      surroundingText.endOffsetInTextContent()));
+}
+
+void RenderFrameImpl::OnAddStyleSheetByURL(const std::string& url) {
+  frame_->addStyleSheetByURL(WebString::fromUTF8(url));
+}
+
+void RenderFrameImpl::OnSetupTransitionView(const std::string& markup) {
+  frame_->document().setIsTransitionDocument();
+  frame_->navigateToSandboxedMarkup(WebData(markup.data(), markup.length()));
+}
+
+void RenderFrameImpl::OnBeginExitTransition(const std::string& css_selector) {
+  frame_->document().setIsTransitionDocument();
+  frame_->document().beginExitTransition(WebString::fromUTF8(css_selector));
+}
+
 bool RenderFrameImpl::ShouldUpdateSelectionTextFromContextMenuParams(
     const base::string16& selection_text,
     size_t selection_text_offset,
@@ -802,18 +1414,55 @@ bool RenderFrameImpl::ShouldUpdateSelectionTextFromContextMenuParams(
     const int start = selection_range.GetMin() - selection_text_offset;
     const size_t length = selection_range.length();
     if (start >= 0 && start + length <= selection_text.length()) {
-      TrimWhitespace(selection_text.substr(start, length), TRIM_ALL,
-                     &trimmed_selection_text);
+      base::TrimWhitespace(selection_text.substr(start, length), base::TRIM_ALL,
+                           &trimmed_selection_text);
     }
   }
   base::string16 trimmed_params_text;
-  TrimWhitespace(params.selection_text, TRIM_ALL, &trimmed_params_text);
+  base::TrimWhitespace(params.selection_text, base::TRIM_ALL,
+                       &trimmed_params_text);
   return trimmed_params_text != trimmed_selection_text;
 }
 
+bool RenderFrameImpl::RunJavaScriptMessage(JavaScriptMessageType type,
+                                           const base::string16& message,
+                                           const base::string16& default_value,
+                                           const GURL& frame_url,
+                                           base::string16* result) {
+  // Don't allow further dialogs if we are waiting to swap out, since the
+  // PageGroupLoadDeferrer in our stack prevents it.
+  if (render_view()->suppress_dialogs_until_swap_out_)
+    return false;
+
+  bool success = false;
+  base::string16 result_temp;
+  if (!result)
+    result = &result_temp;
+
+  render_view()->SendAndRunNestedMessageLoop(
+      new FrameHostMsg_RunJavaScriptMessage(
+        routing_id_, message, default_value, frame_url, type, &success,
+        result));
+  return success;
+}
+
+void RenderFrameImpl::LoadNavigationErrorPage(
+    const WebURLRequest& failed_request,
+    const WebURLError& error,
+    bool replace) {
+  std::string error_html;
+  GetContentClient()->renderer()->GetNavigationErrorStrings(
+      render_view(), frame_, failed_request, error, &error_html, NULL);
+
+  frame_->loadHTMLString(error_html,
+                         GURL(kUnreachableWebDataURL),
+                         error.unreachableURL,
+                         replace);
+}
+
 void RenderFrameImpl::DidCommitCompositorFrame() {
-  if (compositing_helper_)
-    compositing_helper_->DidCommitCompositorFrame();
+  FOR_EACH_OBSERVER(
+      RenderFrameObserver, observers_, DidCommitCompositorFrame());
 }
 
 RenderView* RenderFrameImpl::GetRenderView() {
@@ -824,7 +1473,7 @@ int RenderFrameImpl::GetRoutingID() {
   return routing_id_;
 }
 
-blink::WebFrame* RenderFrameImpl::GetWebFrame() {
+blink::WebLocalFrame* RenderFrameImpl::GetWebFrame() {
   DCHECK(frame_);
   return frame_;
 }
@@ -847,10 +1496,15 @@ void RenderFrameImpl::CancelContextMenu(int request_id) {
   pending_context_menus_.Remove(request_id);
 }
 
+blink::WebNode RenderFrameImpl::GetContextMenuNode() const {
+  return context_menu_node_;
+}
+
 blink::WebPlugin* RenderFrameImpl::CreatePlugin(
     blink::WebFrame* frame,
     const WebPluginInfo& info,
     const blink::WebPluginParams& params) {
+  DCHECK_EQ(frame_, frame);
 #if defined(ENABLE_PLUGINS)
   bool pepper_plugin_was_registered = false;
   scoped_refptr<PluginModule> pepper_module(PluginModule::Create(
@@ -872,32 +1526,49 @@ blink::WebPlugin* RenderFrameImpl::CreatePlugin(
 #endif
 }
 
-void RenderFrameImpl::LoadURLExternally(
-    blink::WebFrame* frame,
-    const blink::WebURLRequest& request,
-    blink::WebNavigationPolicy policy) {
-  loadURLExternally(frame, request, policy);
+void RenderFrameImpl::LoadURLExternally(blink::WebLocalFrame* frame,
+                                        const blink::WebURLRequest& request,
+                                        blink::WebNavigationPolicy policy) {
+  DCHECK(!frame_ || frame_ == frame);
+  loadURLExternally(frame, request, policy, WebString());
+}
+
+void RenderFrameImpl::ExecuteJavaScript(const base::string16& javascript) {
+  OnJavaScriptExecuteRequest(javascript, 0, false);
+}
+
+ServiceRegistry* RenderFrameImpl::GetServiceRegistry() {
+  return &service_registry_;
+}
+
+bool RenderFrameImpl::IsFTPDirectoryListing() {
+  WebURLResponseExtraDataImpl* extra_data =
+      GetExtraDataFromResponse(frame_->dataSource()->response());
+  return extra_data ? extra_data->is_ftp_directory_listing() : false;
 }
 
-void RenderFrameImpl::OnChildFrameProcessGone() {
-  if (compositing_helper_)
-    compositing_helper_->ChildFrameGone();
+void RenderFrameImpl::AttachGuest(int element_instance_id) {
+  render_view_->GetBrowserPluginManager()->Attach(element_instance_id);
 }
 
 // blink::WebFrameClient implementation ----------------------------------------
 
 blink::WebPlugin* RenderFrameImpl::createPlugin(
-    blink::WebFrame* frame,
+    blink::WebLocalFrame* frame,
     const blink::WebPluginParams& params) {
+  DCHECK_EQ(frame_, frame);
   blink::WebPlugin* plugin = NULL;
   if (GetContentClient()->renderer()->OverrideCreatePlugin(
           this, frame, params, &plugin)) {
     return plugin;
   }
 
-  if (UTF16ToASCII(params.mimeType) == kBrowserPluginMimeType) {
+  if (base::UTF16ToUTF8(params.mimeType) == kBrowserPluginMimeType) {
+    scoped_ptr<BrowserPluginDelegate> browser_plugin_delegate(
+        GetContentClient()->renderer()->CreateBrowserPluginDelegate(
+            this, std::string()));
     return render_view_->GetBrowserPluginManager()->CreateBrowserPlugin(
-        render_view_.get(), frame);
+        render_view_.get(), frame, browser_plugin_delegate.Pass());
   }
 
 #if defined(ENABLE_PLUGINS)
@@ -910,6 +1581,15 @@ blink::WebPlugin* RenderFrameImpl::createPlugin(
   if (!found)
     return NULL;
 
+  if (info.type == content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN) {
+    scoped_ptr<BrowserPluginDelegate> browser_plugin_delegate(
+        GetContentClient()->renderer()->CreateBrowserPluginDelegate(
+            this, base::UTF16ToUTF8(params.mimeType)));
+    return render_view_->GetBrowserPluginManager()->CreateBrowserPlugin(
+        render_view_.get(), frame, browser_plugin_delegate.Pass());
+  }
+
+
   WebPluginParams params_to_use = params;
   params_to_use.mimeType = WebString::fromUTF8(mime_type);
   return CreatePlugin(frame, info, params_to_use);
@@ -919,65 +1599,176 @@ blink::WebPlugin* RenderFrameImpl::createPlugin(
 }
 
 blink::WebMediaPlayer* RenderFrameImpl::createMediaPlayer(
-    blink::WebFrame* frame,
+    blink::WebLocalFrame* frame,
     const blink::WebURL& url,
     blink::WebMediaPlayerClient* client) {
-  // TODO(nasko): Moving the implementation here involves moving a few media
-  // related client objects here or referencing them in the RenderView. Needs
-  // more work to understand where the proper place for those objects is.
-  return render_view_->CreateMediaPlayer(this, frame, url, client);
+  return createMediaPlayer(frame, url, client, NULL);
+}
+
+blink::WebMediaPlayer* RenderFrameImpl::createMediaPlayer(
+    blink::WebLocalFrame* frame,
+    const blink::WebURL& url,
+    blink::WebMediaPlayerClient* client,
+    blink::WebContentDecryptionModule* initial_cdm) {
+#if defined(VIDEO_HOLE)
+  if (!contains_media_player_) {
+    render_view_->RegisterVideoHoleFrame(this);
+    contains_media_player_ = true;
+  }
+#endif  // defined(VIDEO_HOLE)
+
+  blink::WebMediaStream web_stream(
+      blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url));
+  if (!web_stream.isNull())
+    return CreateWebMediaPlayerForMediaStream(url, client);
+
+#if defined(OS_ANDROID)
+  return CreateAndroidWebMediaPlayer(url, client, initial_cdm);
+#else
+  RenderThreadImpl* render_thread = RenderThreadImpl::current();
+  media::WebMediaPlayerParams params(
+      base::Bind(&ContentRendererClient::DeferMediaLoad,
+                 base::Unretained(GetContentClient()->renderer()),
+                 static_cast<RenderFrame*>(this)),
+      render_thread->GetAudioRendererMixerManager()->CreateInput(
+          render_view_->routing_id_, routing_id_),
+      *render_thread->GetAudioHardwareConfig(),
+      new RenderMediaLog(),
+      render_thread->GetGpuFactories(),
+      render_thread->GetMediaThreadTaskRunner(),
+      render_thread->compositor_message_loop_proxy(),
+      base::Bind(&EncryptedMediaPlayerSupportImpl::Create),
+      initial_cdm);
+
+#if defined(OS_TIZEN) && defined(ENABLE_MURPHY)
+  tizen::MediaPlayerImpl* media_player = new tizen::MediaPlayerImpl(
+      frame, client, weak_factory_.GetWeakPtr(),
+      GetTizenMediaPlayerManager(), params);
+  return media_player;
+#endif
+  return new media::WebMediaPlayerImpl(frame,
+                                       client,
+                                       weak_factory_.GetWeakPtr(),
+                                       params);
+#endif  // defined(OS_ANDROID)
+}
+
+#if defined(OS_TIZEN) && defined(ENABLE_MURPHY)
+tizen::RendererMediaPlayerManager*
+RenderFrameImpl::GetTizenMediaPlayerManager() {
+  if (!media_player_manager_)
+    media_player_manager_ = new tizen::RendererMediaPlayerManager(this);
+
+  return media_player_manager_;
+}
+#endif
+
+blink::WebContentDecryptionModule*
+RenderFrameImpl::createContentDecryptionModule(
+    blink::WebLocalFrame* frame,
+    const blink::WebSecurityOrigin& security_origin,
+    const blink::WebString& key_system) {
+  DCHECK(!frame_ || frame_ == frame);
+  return WebContentDecryptionModuleImpl::Create(
+#if defined(ENABLE_PEPPER_CDMS)
+      frame,
+#elif defined(ENABLE_BROWSER_CDMS)
+      GetCdmManager(),
+#endif
+      security_origin,
+      key_system);
 }
 
 blink::WebApplicationCacheHost* RenderFrameImpl::createApplicationCacheHost(
-    blink::WebFrame* frame,
+    blink::WebLocalFrame* frame,
     blink::WebApplicationCacheHostClient* client) {
   if (!frame || !frame->view())
     return NULL;
+  DCHECK(!frame_ || frame_ == frame);
   return new RendererWebApplicationCacheHostImpl(
       RenderViewImpl::FromWebView(frame->view()), client,
       RenderThreadImpl::current()->appcache_dispatcher()->backend_proxy());
 }
 
 blink::WebWorkerPermissionClientProxy*
-RenderFrameImpl::createWorkerPermissionClientProxy(WebFrame* frame) {
+RenderFrameImpl::createWorkerPermissionClientProxy(
+    blink::WebLocalFrame* frame) {
   if (!frame || !frame->view())
     return NULL;
+  DCHECK(!frame_ || frame_ == frame);
   return GetContentClient()->renderer()->CreateWorkerPermissionClientProxy(
       this, frame);
 }
 
-blink::WebCookieJar* RenderFrameImpl::cookieJar(blink::WebFrame* frame) {
+WebExternalPopupMenu* RenderFrameImpl::createExternalPopupMenu(
+    const WebPopupMenuInfo& popup_menu_info,
+    WebExternalPopupMenuClient* popup_menu_client) {
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+  // An IPC message is sent to the browser to build and display the actual
+  // popup. The user could have time to click a different select by the time
+  // the popup is shown. In that case external_popup_menu_ is non NULL.
+  // By returning NULL in that case, we instruct Blink to cancel that new
+  // popup. So from the user perspective, only the first one will show, and
+  // will have to close the first one before another one can be shown.
+  if (external_popup_menu_)
+    return NULL;
+  external_popup_menu_.reset(
+      new ExternalPopupMenu(this, popup_menu_info, popup_menu_client));
+  if (render_view_->screen_metrics_emulator_) {
+    render_view_->SetExternalPopupOriginAdjustmentsForEmulation(
+        external_popup_menu_.get(),
+        render_view_->screen_metrics_emulator_.get());
+  }
+  return external_popup_menu_.get();
+#else
+  return NULL;
+#endif
+}
+
+blink::WebCookieJar* RenderFrameImpl::cookieJar(blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
   return &cookie_jar_;
 }
 
 blink::WebServiceWorkerProvider* RenderFrameImpl::createServiceWorkerProvider(
-    blink::WebFrame* frame,
-    blink::WebServiceWorkerProviderClient* client) {
+    blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
+  // At this point we should have non-null data source.
+  DCHECK(frame->dataSource());
+  if (!ChildThread::current())
+    return NULL;  // May be null in some tests.
+  ServiceWorkerNetworkProvider* provider =
+      ServiceWorkerNetworkProvider::FromDocumentState(
+          DocumentState::FromDataSource(frame->dataSource()));
   return new WebServiceWorkerProviderImpl(
       ChildThread::current()->thread_safe_sender(),
-      make_scoped_ptr(client));
+      provider ? provider->context() : NULL);
 }
 
-void RenderFrameImpl::didAccessInitialDocument(blink::WebFrame* frame) {
-  render_view_->didAccessInitialDocument(frame);
+void RenderFrameImpl::didAccessInitialDocument(blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
+  // Notify the browser process that it is no longer safe to show the pending
+  // URL of the main frame, since a URL spoof is now possible.
+  if (!frame->parent() && render_view_->page_id_ == -1)
+    Send(new FrameHostMsg_DidAccessInitialDocument(routing_id_));
 }
 
 blink::WebFrame* RenderFrameImpl::createChildFrame(
-    blink::WebFrame* parent,
+    blink::WebLocalFrame* parent,
     const blink::WebString& name) {
-  long long child_frame_identifier = WebFrame::generateEmbedderIdentifier();
   // Synchronously notify the browser of a child frame creation to get the
   // routing_id for the RenderFrame.
-  int routing_id = MSG_ROUTING_NONE;
+  int child_routing_id = MSG_ROUTING_NONE;
   Send(new FrameHostMsg_CreateChildFrame(routing_id_,
-                                         parent->identifier(),
-                                         child_frame_identifier,
                                          base::UTF16ToUTF8(name),
-                                         &routing_id));
+                                         &child_routing_id));
   // Allocation of routing id failed, so we can't create a child frame. This can
   // happen if this RenderFrameImpl's IPCs are being filtered when in swapped
   // out state.
-  if (routing_id == MSG_ROUTING_NONE) {
+  if (child_routing_id == MSG_ROUTING_NONE) {
+#if !defined(OS_LINUX)
+    // DumpWithoutCrashing() crashes on Linux in renderer processes when
+    // breakpad and sandboxing are enabled: crbug.com/349600
     base::debug::Alias(parent);
     base::debug::Alias(&routing_id_);
     bool render_view_is_swapped_out = GetRenderWidget()->is_swapped_out();
@@ -986,21 +1777,34 @@ blink::WebFrame* RenderFrameImpl::createChildFrame(
     base::debug::Alias(&render_view_is_closing);
     base::debug::Alias(&is_swapped_out_);
     base::debug::DumpWithoutCrashing();
+#endif
     return NULL;
   }
 
+  // Create the RenderFrame and WebLocalFrame, linking the two.
   RenderFrameImpl* child_render_frame = RenderFrameImpl::Create(
-      render_view_.get(), routing_id);
-  blink::WebFrame* web_frame = WebFrame::create(child_render_frame,
-                                                child_frame_identifier);
-  parent->appendChild(web_frame);
+      render_view_.get(), child_routing_id);
+  blink::WebLocalFrame* web_frame = WebLocalFrame::create(child_render_frame);
   child_render_frame->SetWebFrame(web_frame);
 
+  // Add the frame to the frame tree and initialize it.
+  parent->appendChild(web_frame);
+  child_render_frame->Initialize();
+
   return web_frame;
 }
 
-void RenderFrameImpl::didDisownOpener(blink::WebFrame* frame) {
-  render_view_->didDisownOpener(frame);
+void RenderFrameImpl::didDisownOpener(blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
+  // We only need to notify the browser if the active, top-level frame clears
+  // its opener.  We can ignore cases where a swapped out frame clears its
+  // opener after hearing about it from the browser, and the browser does not
+  // (yet) care about subframe openers.
+  if (render_view_->is_swapped_out_ || frame->parent())
+    return;
+
+  // Notify WebContents and all its swapped out RenderViews.
+  Send(new FrameHostMsg_DidDisownOpener(routing_id_));
 }
 
 void RenderFrameImpl::frameDetached(blink::WebFrame* frame) {
@@ -1008,17 +1812,11 @@ void RenderFrameImpl::frameDetached(blink::WebFrame* frame) {
   // the parent frame.  This is different from createChildFrame() which is
   // called on the parent frame.
   CHECK(!is_detaching_);
+  DCHECK(!frame_ || frame_ == frame);
 
   bool is_subframe = !!frame->parent();
 
-  int64 parent_frame_id = -1;
-  if (is_subframe)
-    parent_frame_id = frame->parent()->identifier();
-
-  Send(new FrameHostMsg_Detach(routing_id_, parent_frame_id,
-                               frame->identifier()));
-
-  render_view_->UnregisterSwappedOutChildFrame(this);
+  Send(new FrameHostMsg_Detach(routing_id_));
 
   // The |is_detaching_| flag disables Send(). FrameHostMsg_Detach must be
   // sent before setting |is_detaching_| to true. In contrast, Observers
@@ -1026,9 +1824,8 @@ void RenderFrameImpl::frameDetached(blink::WebFrame* frame) {
   // have IPCs fired off.
   is_detaching_ = true;
 
-  // Call back to RenderViewImpl for observers to be notified.
-  // TODO(nasko): Remove once we have RenderFrameObserver.
-  render_view_->frameDetached(frame);
+  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+                    FrameDetached(frame));
 
   // We need to clean up subframes by removing them from the map and deleting
   // the RenderFrameImpl.  In contrast, the main frame is owned by its
@@ -1051,93 +1848,134 @@ void RenderFrameImpl::frameDetached(blink::WebFrame* frame) {
   }
 }
 
+void RenderFrameImpl::frameFocused() {
+  Send(new FrameHostMsg_FrameFocused(routing_id_));
+}
+
 void RenderFrameImpl::willClose(blink::WebFrame* frame) {
-  // Call back to RenderViewImpl for observers to be notified.
-  // TODO(nasko): Remove once we have RenderFrameObserver.
-  render_view_->willClose(frame);
+  DCHECK(!frame_ || frame_ == frame);
+
+  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, FrameWillClose());
+  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+                    FrameWillClose(frame));
 }
 
-void RenderFrameImpl::didChangeName(blink::WebFrame* frame,
+void RenderFrameImpl::didChangeName(blink::WebLocalFrame* frame,
                                     const blink::WebString& name) {
+  DCHECK(!frame_ || frame_ == frame);
   if (!render_view_->renderer_preferences_.report_frame_name_changes)
     return;
 
-  render_view_->Send(
-      new ViewHostMsg_UpdateFrameName(render_view_->GetRoutingID(),
-                                      frame->identifier(),
-                                      !frame->parent(),
-                                      base::UTF16ToUTF8(name)));
+  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidChangeName(name));
 }
 
 void RenderFrameImpl::didMatchCSS(
-    blink::WebFrame* frame,
+    blink::WebLocalFrame* frame,
     const blink::WebVector<blink::WebString>& newly_matching_selectors,
     const blink::WebVector<blink::WebString>& stopped_matching_selectors) {
-  render_view_->didMatchCSS(
-      frame, newly_matching_selectors, stopped_matching_selectors);
-}
+  DCHECK(!frame_ || frame_ == frame);
+
+  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+                    DidMatchCSS(frame,
+                                newly_matching_selectors,
+                                stopped_matching_selectors));
+}
+
+bool RenderFrameImpl::shouldReportDetailedMessageForSource(
+    const blink::WebString& source) {
+  return GetContentClient()->renderer()->ShouldReportDetailedMessageForSource(
+      source);
+}
+
+void RenderFrameImpl::didAddMessageToConsole(
+    const blink::WebConsoleMessage& message,
+    const blink::WebString& source_name,
+    unsigned source_line,
+    const blink::WebString& stack_trace) {
+  logging::LogSeverity log_severity = logging::LOG_VERBOSE;
+  switch (message.level) {
+    case blink::WebConsoleMessage::LevelDebug:
+      log_severity = logging::LOG_VERBOSE;
+      break;
+    case blink::WebConsoleMessage::LevelLog:
+    case blink::WebConsoleMessage::LevelInfo:
+      log_severity = logging::LOG_INFO;
+      break;
+    case blink::WebConsoleMessage::LevelWarning:
+      log_severity = logging::LOG_WARNING;
+      break;
+    case blink::WebConsoleMessage::LevelError:
+      log_severity = logging::LOG_ERROR;
+      break;
+    default:
+      NOTREACHED();
+  }
 
-void RenderFrameImpl::loadURLExternally(blink::WebFrame* frame,
-                                        const blink::WebURLRequest& request,
-                                        blink::WebNavigationPolicy policy) {
-  loadURLExternally(frame, request, policy, WebString());
+  if (shouldReportDetailedMessageForSource(source_name)) {
+    FOR_EACH_OBSERVER(
+        RenderFrameObserver, observers_,
+        DetailedConsoleMessageAdded(message.text,
+                                    source_name,
+                                    stack_trace,
+                                    source_line,
+                                    static_cast<int32>(log_severity)));
+  }
+
+  Send(new FrameHostMsg_AddMessageToConsole(routing_id_,
+                                            static_cast<int32>(log_severity),
+                                            message.text,
+                                            static_cast<int32>(source_line),
+                                            source_name));
 }
 
 void RenderFrameImpl::loadURLExternally(
-    blink::WebFrame* frame,
+    blink::WebLocalFrame* frame,
     const blink::WebURLRequest& request,
     blink::WebNavigationPolicy policy,
     const blink::WebString& suggested_name) {
+  DCHECK(!frame_ || frame_ == frame);
   Referrer referrer(RenderViewImpl::GetReferrerFromRequest(frame, request));
   if (policy == blink::WebNavigationPolicyDownload) {
     render_view_->Send(new ViewHostMsg_DownloadUrl(render_view_->GetRoutingID(),
                                                    request.url(), referrer,
                                                    suggested_name));
   } else {
-    render_view_->OpenURL(frame, request.url(), referrer, policy);
+    OpenURL(frame, request.url(), referrer, policy);
   }
 }
 
 blink::WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation(
-    blink::WebFrame* frame,
-    blink::WebDataSource::ExtraData* extra_data,
-    const blink::WebURLRequest& request,
-    blink::WebNavigationType type,
-    blink::WebNavigationPolicy default_policy,
-    bool is_redirect) {
-  return render_view_->DecidePolicyForNavigation(
-      this, frame, extra_data, request, type, default_policy, is_redirect);
+    const NavigationPolicyInfo& info) {
+  DCHECK(!frame_ || frame_ == info.frame);
+  return DecidePolicyForNavigation(this, info);
 }
 
-blink::WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation(
-    blink::WebFrame* frame,
-    const blink::WebURLRequest& request,
-    blink::WebNavigationType type,
-    blink::WebNavigationPolicy default_policy,
-    bool is_redirect) {
-  return decidePolicyForNavigation(frame,
-                                   frame->provisionalDataSource()->extraData(),
-                                   request, type, default_policy, is_redirect);
+blink::WebHistoryItem RenderFrameImpl::historyItemForNewChildFrame(
+    blink::WebFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
+  return render_view_->history_controller()->GetItemForNewChildFrame(this);
 }
 
-void RenderFrameImpl::willSendSubmitEvent(blink::WebFrame* frame,
+void RenderFrameImpl::willSendSubmitEvent(blink::WebLocalFrame* frame,
                                           const blink::WebFormElement& form) {
-  // Call back to RenderViewImpl for observers to be notified.
-  // TODO(nasko): Remove once we have RenderFrameObserver.
-  render_view_->willSendSubmitEvent(frame, form);
+  DCHECK(!frame_ || frame_ == frame);
+
+  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+                    WillSendSubmitEvent(frame, form));
 }
 
-void RenderFrameImpl::willSubmitForm(blink::WebFrame* frame,
+void RenderFrameImpl::willSubmitForm(blink::WebLocalFrame* frame,
                                      const blink::WebFormElement& form) {
+  DCHECK(!frame_ || frame_ == frame);
   DocumentState* document_state =
       DocumentState::FromDataSource(frame->provisionalDataSource());
   NavigationState* navigation_state = document_state->navigation_state();
   InternalDocumentStateData* internal_data =
       InternalDocumentStateData::FromDocumentState(document_state);
 
-  if (PageTransitionCoreTypeIs(navigation_state->transition_type(),
-                               PAGE_TRANSITION_LINK)) {
-    navigation_state->set_transition_type(PAGE_TRANSITION_FORM_SUBMIT);
+  if (ui::PageTransitionCoreTypeIs(navigation_state->transition_type(),
+                                   ui::PAGE_TRANSITION_LINK)) {
+    navigation_state->set_transition_type(ui::PAGE_TRANSITION_FORM_SUBMIT);
   }
 
   // Save these to be processed when the ensuing navigation is committed.
@@ -1146,13 +1984,14 @@ void RenderFrameImpl::willSubmitForm(blink::WebFrame* frame,
   internal_data->set_searchable_form_encoding(
       web_searchable_form_data.encoding().utf8());
 
-  // Call back to RenderViewImpl for observers to be notified.
-  // TODO(nasko): Remove once we have RenderFrameObserver.
-  render_view_->willSubmitForm(frame, form);
+  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+                    WillSubmitForm(frame, form));
 }
 
-void RenderFrameImpl::didCreateDataSource(blink::WebFrame* frame,
+void RenderFrameImpl::didCreateDataSource(blink::WebLocalFrame* frame,
                                           blink::WebDataSource* datasource) {
+  DCHECK(!frame_ || frame_ == frame);
+
   // TODO(nasko): Move implementation here. Needed state:
   // * pending_navigation_params_
   // * webview
@@ -1160,9 +1999,18 @@ void RenderFrameImpl::didCreateDataSource(blink::WebFrame* frame,
   // * PopulateDocumentStateFromPending
   // * CreateNavigationStateFromPending
   render_view_->didCreateDataSource(frame, datasource);
+
+  // Create the serviceworker's per-document network observing object.
+  scoped_ptr<ServiceWorkerNetworkProvider>
+      network_provider(new ServiceWorkerNetworkProvider());
+  ServiceWorkerNetworkProvider::AttachToDocumentState(
+      DocumentState::FromDataSource(datasource),
+      network_provider.Pass());
 }
 
-void RenderFrameImpl::didStartProvisionalLoad(blink::WebFrame* frame) {
+void RenderFrameImpl::didStartProvisionalLoad(blink::WebLocalFrame* frame,
+                                              bool is_transition_navigation) {
+  DCHECK(!frame_ || frame_ == frame);
   WebDataSource* ds = frame->provisionalDataSource();
 
   // In fast/loader/stop-provisional-loads.html, we abort the load before this
@@ -1170,6 +2018,8 @@ void RenderFrameImpl::didStartProvisionalLoad(blink::WebFrame* frame) {
   if (!ds)
     return;
 
+  TRACE_EVENT2("navigation", "RenderFrameImpl::didStartProvisionalLoad",
+               "id", routing_id_, "url", ds->request().url().string().utf8());
   DocumentState* document_state = DocumentState::FromDataSource(ds);
 
   // We should only navigate to swappedout:// when is_swapped_out_ is true.
@@ -1198,56 +2048,41 @@ void RenderFrameImpl::didStartProvisionalLoad(blink::WebFrame* frame) {
     // marked with AUTO_SUBFRAME. See also didFailProvisionalLoad for how we
     // handle loading of error pages.
     document_state->navigation_state()->set_transition_type(
-        PAGE_TRANSITION_AUTO_SUBFRAME);
+        ui::PAGE_TRANSITION_AUTO_SUBFRAME);
   }
 
-  FOR_EACH_OBSERVER(
-      RenderViewObserver, render_view_->observers(),
-      DidStartProvisionalLoad(frame));
-
-  FOR_EACH_OBSERVER(
-      RenderFrameObserver, observers_,
-      DidStartProvisionalLoad());
+  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+                    DidStartProvisionalLoad(frame));
+  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidStartProvisionalLoad());
 
   Send(new FrameHostMsg_DidStartProvisionalLoadForFrame(
-       routing_id_, frame->identifier(),
-       frame->parent() ? frame->parent()->identifier() : -1,
-       is_top_most, ds->request().url()));
+       routing_id_, ds->request().url(), is_transition_navigation));
 }
 
 void RenderFrameImpl::didReceiveServerRedirectForProvisionalLoad(
-    blink::WebFrame* frame) {
-  if (frame->parent())
-    return;
-  // Received a redirect on the main frame.
-  WebDataSource* data_source = frame->provisionalDataSource();
-  if (!data_source) {
-    // Should only be invoked when we have a data source.
-    NOTREACHED();
-    return;
-  }
-  std::vector<GURL> redirects;
-  GetRedirectChain(data_source, &redirects);
-  if (redirects.size() >= 2) {
-    Send(new FrameHostMsg_DidRedirectProvisionalLoad(
-        routing_id_,
-        render_view_->page_id_,
-        redirects[redirects.size() - 2],
-        redirects.back()));
-  }
+    blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
+  render_view_->history_controller()->RemoveChildrenForRedirect(this);
 }
 
-void RenderFrameImpl::didFailProvisionalLoad(
-    blink::WebFrame* frame,
-    const blink::WebURLError& error) {
+void RenderFrameImpl::didFailProvisionalLoad(blink::WebLocalFrame* frame,
+                                             const blink::WebURLError& error) {
+  TRACE_EVENT1("navigation", "RenderFrameImpl::didFailProvisionalLoad",
+               "id", routing_id_);
+  DCHECK(!frame_ || frame_ == frame);
   WebDataSource* ds = frame->provisionalDataSource();
   DCHECK(ds);
 
   const WebURLRequest& failed_request = ds->request();
 
-  // Call out to RenderViewImpl, so observers are notified.
-  render_view_->didFailProvisionalLoad(frame, error);
-
+  // Notify the browser that we failed a provisional load with an error.
+  //
+  // Note: It is important this notification occur before DidStopLoading so the
+  //       SSL manager can react to the provisional load failure before being
+  //       notified the load stopped.
+  //
+  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+                    DidFailProvisionalLoad(frame, error));
   FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
                     DidFailProvisionalLoad(error));
 
@@ -1256,9 +2091,6 @@ void RenderFrameImpl::didFailProvisionalLoad(
        EqualsASCII(failed_request.httpMethod(), "POST"));
 
   FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
-  params.frame_id = frame->identifier();
-  params.frame_unique_name = frame->uniqueName();
-  params.is_main_frame = !frame->parent();
   params.error_code = error.reason;
   GetContentClient()->renderer()->GetNavigationErrorStrings(
       render_view_.get(),
@@ -1312,8 +2144,8 @@ void RenderFrameImpl::didFailProvisionalLoad(
   // state into account, if a location.replace() failed.
   bool replace =
       navigation_state->pending_page_id() != -1 ||
-      PageTransitionCoreTypeIs(navigation_state->transition_type(),
-                               PAGE_TRANSITION_AUTO_SUBFRAME);
+      ui::PageTransitionCoreTypeIs(navigation_state->transition_type(),
+                               ui::PAGE_TRANSITION_AUTO_SUBFRAME);
 
   // If we failed on a browser initiated request, then make sure that our error
   // page load is regarded as the same browser initiated request.
@@ -1335,15 +2167,29 @@ void RenderFrameImpl::didFailProvisionalLoad(
   }
 
   // Load an error page.
-  render_view_->LoadNavigationErrorPage(
-      frame, failed_request, error, replace);
+  LoadNavigationErrorPage(failed_request, error, replace);
 }
 
-void RenderFrameImpl::didCommitProvisionalLoad(blink::WebFrame* frame,
-                                               bool is_new_navigation) {
+void RenderFrameImpl::didCommitProvisionalLoad(
+    blink::WebLocalFrame* frame,
+    const blink::WebHistoryItem& item,
+    blink::WebHistoryCommitType commit_type) {
+  TRACE_EVENT2("navigation", "RenderFrameImpl::didCommitProvisionalLoad",
+               "id", routing_id_,
+               "url", GetLoadingUrl().possibly_invalid_spec());
+  DCHECK(!frame_ || frame_ == frame);
   DocumentState* document_state =
       DocumentState::FromDataSource(frame->dataSource());
   NavigationState* navigation_state = document_state->navigation_state();
+
+  // When we perform a new navigation, we need to update the last committed
+  // session history entry with state for the page we are leaving. Do this
+  // before updating the HistoryController state.
+  render_view_->UpdateSessionHistory(frame);
+
+  render_view_->history_controller()->UpdateForCommit(this, item, commit_type,
+      navigation_state->was_within_same_page());
+
   InternalDocumentStateData* internal_data =
       InternalDocumentStateData::FromDocumentState(document_state);
 
@@ -1356,11 +2202,8 @@ void RenderFrameImpl::didCommitProvisionalLoad(blink::WebFrame* frame,
   }
   internal_data->set_use_error_page(false);
 
+  bool is_new_navigation = commit_type == blink::WebStandardCommit;
   if (is_new_navigation) {
-    // When we perform a new navigation, we need to update the last committed
-    // session history entry with state for the page we are leaving.
-    render_view_->UpdateSessionHistory(frame);
-
     // We bump our Page ID to correspond with the new session history entry.
     render_view_->page_id_ = render_view_->next_page_id_++;
 
@@ -1370,7 +2213,7 @@ void RenderFrameImpl::didCommitProvisionalLoad(blink::WebFrame* frame,
     // UpdateSessionHistory and update page_id_ even in this case, so that
     // the current entry gets a state update and so that we don't send a
     // state update to the wrong entry when we swap back in.
-    if (render_view_->GetLoadingUrl(frame) != GURL(kSwappedOutURL)) {
+    if (GetLoadingUrl() != GURL(kSwappedOutURL)) {
       // Advance our offset in session history, applying the length limit.
       // There is now no forward history.
       render_view_->history_list_offset_++;
@@ -1398,7 +2241,6 @@ void RenderFrameImpl::didCommitProvisionalLoad(blink::WebFrame* frame,
         navigation_state->pending_page_id() != render_view_->page_id_ &&
         !navigation_state->request_committed()) {
       // This is a successful session history navigation!
-      render_view_->UpdateSessionHistory(frame);
       render_view_->page_id_ = navigation_state->pending_page_id();
 
       render_view_->history_list_offset_ =
@@ -1414,10 +2256,22 @@ void RenderFrameImpl::didCommitProvisionalLoad(blink::WebFrame* frame,
     }
   }
 
-  render_view_->didCommitProvisionalLoad(frame, is_new_navigation);
+  Send(new FrameHostMsg_DidAssignPageId(routing_id_, render_view_->page_id_));
+
+  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers_,
+                    DidCommitProvisionalLoad(frame, is_new_navigation));
   FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
                     DidCommitProvisionalLoad(is_new_navigation));
 
+  if (!frame->parent()) {  // Only for top frames.
+    RenderThreadImpl* render_thread_impl = RenderThreadImpl::current();
+    if (render_thread_impl) {  // Can be NULL in tests.
+      render_thread_impl->histogram_customizer()->
+          RenderViewNavigatedToHost(GURL(GetLoadingUrl()).host(),
+                                    RenderViewImpl::GetRenderViewCount());
+    }
+  }
+
   // Remember that we've already processed this request, so we don't update
   // the session history again.  We do this regardless of whether this is
   // a session history navigation, because if we attempted a session history
@@ -1425,80 +2279,112 @@ void RenderFrameImpl::didCommitProvisionalLoad(blink::WebFrame* frame,
   // new navigation.
   navigation_state->set_request_committed(true);
 
-  UpdateURL(frame);
+  SendDidCommitProvisionalLoad(frame);
 
   // Check whether we have new encoding name.
-  render_view_->UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
+  UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
 }
 
-void RenderFrameImpl::didClearWindowObject(blink::WebFrame* frame,
-                                           int world_id) {
+void RenderFrameImpl::didClearWindowObject(blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
   // TODO(nasko): Move implementation here. Needed state:
   // * enabled_bindings_
   // * dom_automation_controller_
   // * stats_collection_controller_
-  render_view_->didClearWindowObject(frame, world_id);
+
+  render_view_->didClearWindowObject(frame);
+
+  if (render_view_->GetEnabledBindings() & BINDINGS_POLICY_DOM_AUTOMATION)
+    DomAutomationController::Install(this, frame);
+
+  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidClearWindowObject());
 }
 
-void RenderFrameImpl::didCreateDocumentElement(blink::WebFrame* frame) {
+void RenderFrameImpl::didCreateDocumentElement(blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
+
   // Notify the browser about non-blank documents loading in the top frame.
   GURL url = frame->document().url();
-  if (url.is_valid() && url.spec() != kAboutBlankURL) {
+  if (url.is_valid() && url.spec() != url::kAboutBlankURL) {
     // TODO(nasko): Check if webview()->mainFrame() is the same as the
     // frame->tree()->top().
-    if (frame == render_view_->webview()->mainFrame()) {
+    blink::WebFrame* main_frame = render_view_->webview()->mainFrame();
+    if (frame == main_frame) {
+      // For now, don't remember plugin zoom values.  We don't want to mix them
+      // with normal web content (i.e. a fixed layout plugin would usually want
+      // them different).
       render_view_->Send(new ViewHostMsg_DocumentAvailableInMainFrame(
-          render_view_->GetRoutingID()));
+          render_view_->GetRoutingID(),
+          main_frame->document().isPluginDocument()));
     }
   }
 
-  // Call back to RenderViewImpl for observers to be notified.
-  // TODO(nasko): Remove once we have RenderFrameObserver.
-  render_view_->didCreateDocumentElement(frame);
+  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+                    DidCreateDocumentElement(frame));
 }
 
-void RenderFrameImpl::didReceiveTitle(blink::WebFrame* frame,
+void RenderFrameImpl::didReceiveTitle(blink::WebLocalFrame* frame,
                                       const blink::WebString& title,
                                       blink::WebTextDirection direction) {
-  // TODO(nasko): Investigate wheather implementation should move here.
-  render_view_->didReceiveTitle(frame, title, direction);
+  DCHECK(!frame_ || frame_ == frame);
+  // Ignore all but top level navigations.
+  if (!frame->parent()) {
+    base::string16 title16 = title;
+    base::debug::TraceLog::GetInstance()->UpdateProcessLabel(
+        routing_id_, base::UTF16ToUTF8(title16));
+
+    base::string16 shortened_title = title16.substr(0, kMaxTitleChars);
+    Send(new FrameHostMsg_UpdateTitle(routing_id_,
+                                      render_view_->page_id_,
+                                      shortened_title, direction));
+  }
+
+  // Also check whether we have new encoding name.
+  UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
 }
 
-void RenderFrameImpl::didChangeIcon(blink::WebFrame* frame,
+void RenderFrameImpl::didChangeIcon(blink::WebLocalFrame* frame,
                                     blink::WebIconURL::Type icon_type) {
+  DCHECK(!frame_ || frame_ == frame);
   // TODO(nasko): Investigate wheather implementation should move here.
   render_view_->didChangeIcon(frame, icon_type);
 }
 
-void RenderFrameImpl::didFinishDocumentLoad(blink::WebFrame* frame) {
+void RenderFrameImpl::didFinishDocumentLoad(blink::WebLocalFrame* frame) {
+  TRACE_EVENT1("navigation", "RenderFrameImpl::didFinishDocumentLoad",
+               "id", routing_id_);
+  DCHECK(!frame_ || frame_ == frame);
   WebDataSource* ds = frame->dataSource();
   DocumentState* document_state = DocumentState::FromDataSource(ds);
   document_state->set_finish_document_load_time(Time::Now());
 
-  Send(
-      new FrameHostMsg_DidFinishDocumentLoad(routing_id_, frame->identifier()));
+  Send(new FrameHostMsg_DidFinishDocumentLoad(routing_id_));
 
-  // Call back to RenderViewImpl for observers to be notified.
-  // TODO(nasko): Remove once we have RenderFrameObserver for this method.
-  render_view_->didFinishDocumentLoad(frame);
+  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+                    DidFinishDocumentLoad(frame));
+  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidFinishDocumentLoad());
 
   // Check whether we have new encoding name.
-  render_view_->UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
+  UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
 }
 
-void RenderFrameImpl::didHandleOnloadEvents(blink::WebFrame* frame) {
-  // TODO(nasko): Move implementation here. Needed state:
-  // * page_id_
-  render_view_->didHandleOnloadEvents(frame);
+void RenderFrameImpl::didHandleOnloadEvents(blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
+  if (!frame->parent())
+    Send(new FrameHostMsg_DocumentOnLoadCompleted(routing_id_));
 }
 
-void RenderFrameImpl::didFailLoad(blink::WebFrame* frame,
+void RenderFrameImpl::didFailLoad(blink::WebLocalFrame* frame,
                                   const blink::WebURLError& error) {
+  TRACE_EVENT1("navigation", "RenderFrameImpl::didFailLoad",
+               "id", routing_id_);
+  DCHECK(!frame_ || frame_ == frame);
   // TODO(nasko): Move implementation here. No state needed.
   WebDataSource* ds = frame->dataSource();
   DCHECK(ds);
 
-  render_view_->didFailLoad(frame, error);
+  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+                    DidFailLoad(frame, error));
 
   const WebURLRequest& failed_request = ds->request();
   base::string16 error_description;
@@ -1510,23 +2396,43 @@ void RenderFrameImpl::didFailLoad(blink::WebFrame* frame,
       NULL,
       &error_description);
   Send(new FrameHostMsg_DidFailLoadWithError(routing_id_,
-                                             frame->identifier(),
                                              failed_request.url(),
-                                             !frame->parent(),
                                              error.reason,
                                              error_description));
 }
 
-void RenderFrameImpl::didFinishLoad(blink::WebFrame* frame) {
-  // TODO(nasko): Move implementation here. No state needed, just observers
-  // notification before sending message to the browser process.
-  render_view_->didFinishLoad(frame);
-  FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
-                    DidFinishLoad());
+void RenderFrameImpl::didFinishLoad(blink::WebLocalFrame* frame) {
+  TRACE_EVENT1("navigation", "RenderFrameImpl::didFinishLoad",
+               "id", routing_id_);
+  DCHECK(!frame_ || frame_ == frame);
+  WebDataSource* ds = frame->dataSource();
+  DocumentState* document_state = DocumentState::FromDataSource(ds);
+  if (document_state->finish_load_time().is_null()) {
+    if (!frame->parent()) {
+      TRACE_EVENT_INSTANT0("WebCore", "LoadFinished",
+                           TRACE_EVENT_SCOPE_PROCESS);
+    }
+    document_state->set_finish_load_time(Time::Now());
+  }
+
+  FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
+                    DidFinishLoad(frame));
+  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidFinishLoad());
+
+  // Don't send this message while the frame is swapped out.
+  if (is_swapped_out())
+    return;
+
+  Send(new FrameHostMsg_DidFinishLoad(routing_id_,
+                                      ds->request().url()));
 }
 
-void RenderFrameImpl::didNavigateWithinPage(blink::WebFrame* frame,
-                                            bool is_new_navigation) {
+void RenderFrameImpl::didNavigateWithinPage(blink::WebLocalFrame* frame,
+    const blink::WebHistoryItem& item,
+    blink::WebHistoryCommitType commit_type) {
+  TRACE_EVENT1("navigation", "RenderFrameImpl::didNavigateWithinPage",
+               "id", routing_id_);
+  DCHECK(!frame_ || frame_ == frame);
   // If this was a reference fragment navigation that we initiated, then we
   // could end up having a non-null pending navigation params.  We just need to
   // update the ExtraData on the datasource so that others who read the
@@ -1541,48 +2447,223 @@ void RenderFrameImpl::didNavigateWithinPage(blink::WebFrame* frame,
   NavigationState* new_state = document_state->navigation_state();
   new_state->set_was_within_same_page(true);
 
-  didCommitProvisionalLoad(frame, is_new_navigation);
+  didCommitProvisionalLoad(frame, item, commit_type);
 }
 
-void RenderFrameImpl::didUpdateCurrentHistoryItem(blink::WebFrame* frame) {
+void RenderFrameImpl::didUpdateCurrentHistoryItem(blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
   // TODO(nasko): Move implementation here. Needed methods:
   // * StartNavStateSyncTimerIfNecessary
   render_view_->didUpdateCurrentHistoryItem(frame);
 }
 
-void RenderFrameImpl::willRequestAfterPreconnect(
-    blink::WebFrame* frame,
-    blink::WebURLRequest& request) {
-  // FIXME(kohei): This will never be set.
-  WebString custom_user_agent;
+void RenderFrameImpl::addNavigationTransitionData(
+    const blink::WebString& allowed_destination_host_pattern,
+    const blink::WebString& selector,
+    const blink::WebString& markup) {
+  Send(new FrameHostMsg_AddNavigationTransitionData(
+      routing_id_, allowed_destination_host_pattern.utf8(), selector.utf8(),
+      markup.utf8()));
+}
+
+void RenderFrameImpl::didChangeThemeColor() {
+  if (frame_->parent())
+    return;
+
+  Send(new FrameHostMsg_DidChangeThemeColor(
+      routing_id_, frame_->document().themeColor()));
+}
+
+void RenderFrameImpl::requestNotificationPermission(
+    const blink::WebSecurityOrigin& origin,
+    blink::WebNotificationPermissionCallback* callback) {
+  if (!notification_permission_dispatcher_) {
+    notification_permission_dispatcher_ =
+        new NotificationPermissionDispatcher(this);
+  }
 
-  DCHECK(!request.extraData());
+  notification_permission_dispatcher_->RequestPermission(origin, callback);
+}
 
-  bool was_after_preconnect_request = true;
-  // The args after |was_after_preconnect_request| are not used, and set to
-  // correct values at |willSendRequest|.
-  request.setExtraData(new webkit_glue::WebURLRequestExtraDataImpl(
-      custom_user_agent, was_after_preconnect_request));
+blink::WebNotificationPresenter* RenderFrameImpl::notificationPresenter() {
+  return notification_provider_;
+}
+
+void RenderFrameImpl::didChangeSelection(bool is_empty_selection) {
+  if (!GetRenderWidget()->handling_input_event() && !handling_select_range_)
+    return;
+
+  if (is_empty_selection)
+    selection_text_.clear();
+
+  // UpdateTextInputState should be called before SyncSelectionIfRequired.
+  // UpdateTextInputState may send TextInputStateChanged to notify the focus
+  // was changed, and SyncSelectionIfRequired may send SelectionChanged
+  // to notify the selection was changed.  Focus change should be notified
+  // before selection change.
+  GetRenderWidget()->UpdateTextInputState(
+      RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
+  SyncSelectionIfRequired();
+}
+
+blink::WebColorChooser* RenderFrameImpl::createColorChooser(
+    blink::WebColorChooserClient* client,
+    const blink::WebColor& initial_color,
+    const blink::WebVector<blink::WebColorSuggestion>& suggestions) {
+  RendererWebColorChooserImpl* color_chooser =
+      new RendererWebColorChooserImpl(this, client);
+  std::vector<content::ColorSuggestion> color_suggestions;
+  for (size_t i = 0; i < suggestions.size(); i++) {
+    color_suggestions.push_back(content::ColorSuggestion(suggestions[i]));
+  }
+  color_chooser->Open(static_cast<SkColor>(initial_color), color_suggestions);
+  return color_chooser;
+}
+
+void RenderFrameImpl::runModalAlertDialog(const blink::WebString& message) {
+  RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_ALERT,
+                       message,
+                       base::string16(),
+                       frame_->document().url(),
+                       NULL);
+}
+
+bool RenderFrameImpl::runModalConfirmDialog(const blink::WebString& message) {
+  return RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_CONFIRM,
+                              message,
+                              base::string16(),
+                              frame_->document().url(),
+                              NULL);
+}
+
+bool RenderFrameImpl::runModalPromptDialog(
+    const blink::WebString& message,
+    const blink::WebString& default_value,
+    blink::WebString* actual_value) {
+  base::string16 result;
+  bool ok = RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_PROMPT,
+                                 message,
+                                 default_value,
+                                 frame_->document().url(),
+                                 &result);
+  if (ok)
+    actual_value->assign(result);
+  return ok;
+}
+
+bool RenderFrameImpl::runModalBeforeUnloadDialog(
+    bool is_reload,
+    const blink::WebString& message) {
+  // If we are swapping out, we have already run the beforeunload handler.
+  // TODO(creis): Fix OnSwapOut to clear the frame without running beforeunload
+  // at all, to avoid running it twice.
+  if (render_view()->is_swapped_out_)
+    return true;
+
+  // Don't allow further dialogs if we are waiting to swap out, since the
+  // PageGroupLoadDeferrer in our stack prevents it.
+  if (render_view()->suppress_dialogs_until_swap_out_)
+    return false;
+
+  bool success = false;
+  // This is an ignored return value, but is included so we can accept the same
+  // response as RunJavaScriptMessage.
+  base::string16 ignored_result;
+  render_view()->SendAndRunNestedMessageLoop(
+      new FrameHostMsg_RunBeforeUnloadConfirm(
+          routing_id_, frame_->document().url(), message, is_reload,
+          &success, &ignored_result));
+  return success;
+}
+
+void RenderFrameImpl::showContextMenu(const blink::WebContextMenuData& data) {
+  ContextMenuParams params = ContextMenuParamsBuilder::Build(data);
+  params.source_type = GetRenderWidget()->context_menu_source_type();
+  GetRenderWidget()->OnShowHostContextMenu(&params);
+  if (GetRenderWidget()->has_host_context_menu_location()) {
+    params.x = GetRenderWidget()->host_context_menu_location().x();
+    params.y = GetRenderWidget()->host_context_menu_location().y();
+  }
+
+  // Plugins, e.g. PDF, don't currently update the render view when their
+  // selected text changes, but the context menu params do contain the updated
+  // selection. If that's the case, update the render view's state just prior
+  // to showing the context menu.
+  // TODO(asvitkine): http://crbug.com/152432
+  if (ShouldUpdateSelectionTextFromContextMenuParams(
+          selection_text_, selection_text_offset_, selection_range_, params)) {
+    selection_text_ = params.selection_text;
+    // TODO(asvitkine): Text offset and range is not available in this case.
+    selection_text_offset_ = 0;
+    selection_range_ = gfx::Range(0, selection_text_.length());
+    // This IPC is dispatched by RenderWidetHost, so use its routing ID.
+    Send(new ViewHostMsg_SelectionChanged(
+        GetRenderWidget()->routing_id(), selection_text_,
+        selection_text_offset_, selection_range_));
+  }
+
+  // Serializing a GURL longer than kMaxURLChars will fail, so don't do
+  // it.  We replace it with an empty GURL so the appropriate items are disabled
+  // in the context menu.
+  // TODO(jcivelli): http://crbug.com/45160 This prevents us from saving large
+  //                 data encoded images.  We should have a way to save them.
+  if (params.src_url.spec().size() > GetMaxURLChars())
+    params.src_url = GURL();
+  context_menu_node_ = data.node;
+
+#if defined(OS_ANDROID)
+  gfx::Rect start_rect;
+  gfx::Rect end_rect;
+  GetRenderWidget()->GetSelectionBounds(&start_rect, &end_rect);
+  params.selection_start = gfx::Point(start_rect.x(), start_rect.bottom());
+  params.selection_end = gfx::Point(end_rect.right(), end_rect.bottom());
+#endif
+
+  Send(new FrameHostMsg_ContextMenu(routing_id_, params));
+}
+
+void RenderFrameImpl::clearContextMenu() {
+  context_menu_node_.reset();
 }
 
 void RenderFrameImpl::willSendRequest(
-    blink::WebFrame* frame,
+    blink::WebLocalFrame* frame,
     unsigned identifier,
     blink::WebURLRequest& request,
     const blink::WebURLResponse& redirect_response) {
+  DCHECK(!frame_ || frame_ == frame);
   // The request my be empty during tests.
   if (request.url().isEmpty())
     return;
 
+  // Set the first party for cookies url if it has not been set yet (new
+  // requests). For redirects, it is updated by WebURLLoaderImpl.
+  if (request.firstPartyForCookies().isEmpty()) {
+    if (request.frameType() == blink::WebURLRequest::FrameTypeTopLevel) {
+      request.setFirstPartyForCookies(request.url());
+    } else {
+      // TODO(nasko): When the top-level frame is remote, there is no document.
+      // This is broken and should be fixed to propagate the first party.
+      WebFrame* top = frame->top();
+      if (top->isWebLocalFrame()) {
+        request.setFirstPartyForCookies(
+            frame->top()->document().firstPartyForCookies());
+      }
+    }
+  }
+
   WebFrame* top_frame = frame->top();
-  if (!top_frame)
+  // TODO(nasko): Hack around asking about top-frame data source. This means
+  // for out-of-process iframes we are treating the current frame as the
+  // top-level frame, which is wrong.
+  if (!top_frame || top_frame->isWebRemoteFrame())
     top_frame = frame;
   WebDataSource* provisional_data_source = top_frame->provisionalDataSource();
   WebDataSource* top_data_source = top_frame->dataSource();
   WebDataSource* data_source =
       provisional_data_source ? provisional_data_source : top_data_source;
 
-  PageTransition transition_type = PAGE_TRANSITION_LINK;
+  ui::PageTransition transition_type = ui::PAGE_TRANSITION_LINK;
   DocumentState* document_state = DocumentState::FromDataSource(data_source);
   DCHECK(document_state);
   InternalDocumentStateData* internal_data =
@@ -1606,25 +2687,45 @@ void RenderFrameImpl::willSendRequest(
 
   // The request's extra data may indicate that we should set a custom user
   // agent. This needs to be done here, after WebKit is through with setting the
-  // user agent on its own.
+  // user agent on its own. Similarly, it may indicate that we should set an
+  // X-Requested-With header. This must be done here to avoid breaking CORS
+  // checks.
   WebString custom_user_agent;
-  bool was_after_preconnect_request = false;
+  WebString requested_with;
   if (request.extraData()) {
-    webkit_glue::WebURLRequestExtraDataImpl* old_extra_data =
-        static_cast<webkit_glue::WebURLRequestExtraDataImpl*>(
-            request.extraData());
-    custom_user_agent = old_extra_data->custom_user_agent();
-    was_after_preconnect_request =
-        old_extra_data->was_after_preconnect_request();
+    RequestExtraData* old_extra_data =
+        static_cast<RequestExtraData*>(request.extraData());
 
+    custom_user_agent = old_extra_data->custom_user_agent();
     if (!custom_user_agent.isNull()) {
       if (custom_user_agent.isEmpty())
         request.clearHTTPHeaderField("User-Agent");
       else
         request.setHTTPHeaderField("User-Agent", custom_user_agent);
     }
+
+    requested_with = old_extra_data->requested_with();
+    if (!requested_with.isNull()) {
+      if (requested_with.isEmpty())
+        request.clearHTTPHeaderField("X-Requested-With");
+      else
+        request.setHTTPHeaderField("X-Requested-With", requested_with);
+    }
+  }
+
+  // Add the default accept header for frame request if it has not been set
+  // already.
+  if ((request.frameType() == blink::WebURLRequest::FrameTypeTopLevel ||
+       request.frameType() == blink::WebURLRequest::FrameTypeNested) &&
+      request.httpHeaderField(WebString::fromUTF8(kAcceptHeader)).isEmpty()) {
+    request.setHTTPHeaderField(WebString::fromUTF8(kAcceptHeader),
+                               WebString::fromUTF8(kDefaultAcceptHeader));
   }
 
+  // Add an empty HTTP origin header for non GET methods if none is currently
+  // present.
+  request.addHTTPOriginIfNeeded(WebString());
+
   // Attach |should_replace_current_entry| state to requests so that, should
   // this navigation later require a request transfer, all state is preserved
   // when it is re-created in the new process.
@@ -1640,32 +2741,62 @@ void RenderFrameImpl::willSendRequest(
     should_replace_current_entry =
         navigation_state->should_replace_current_entry();
   }
-  request.setExtraData(
-      new RequestExtraData(render_view_->visibilityState(),
-                           custom_user_agent,
-                           was_after_preconnect_request,
-                           routing_id_,
-                           (frame == top_frame),
-                           frame->identifier(),
-                           GURL(frame->document().securityOrigin().toString()),
-                           frame->parent() == top_frame,
-                           frame->parent() ? frame->parent()->identifier() : -1,
-                           navigation_state->allow_download(),
-                           transition_type,
-                           should_replace_current_entry,
-                           navigation_state->transferred_request_child_id(),
-                           navigation_state->transferred_request_request_id()));
+
+  int provider_id = kInvalidServiceWorkerProviderId;
+  if (request.frameType() == blink::WebURLRequest::FrameTypeTopLevel ||
+      request.frameType() == blink::WebURLRequest::FrameTypeNested) {
+    // |provisionalDataSource| may be null in some content::ResourceFetcher
+    // use cases, we don't hook those requests.
+    if (frame->provisionalDataSource()) {
+      ServiceWorkerNetworkProvider* provider =
+          ServiceWorkerNetworkProvider::FromDocumentState(
+              DocumentState::FromDataSource(frame->provisionalDataSource()));
+      provider_id = provider->provider_id();
+    }
+  } else if (frame->dataSource()) {
+    ServiceWorkerNetworkProvider* provider =
+        ServiceWorkerNetworkProvider::FromDocumentState(
+            DocumentState::FromDataSource(frame->dataSource()));
+    provider_id = provider->provider_id();
+  }
+
+  WebFrame* parent = frame->parent();
+  int parent_routing_id = MSG_ROUTING_NONE;
+  if (!parent) {
+    parent_routing_id = -1;
+  } else if (parent->isWebLocalFrame()) {
+    parent_routing_id = FromWebFrame(parent)->GetRoutingID();
+  } else {
+    parent_routing_id = RenderFrameProxy::FromWebFrame(parent)->routing_id();
+  }
+
+  RequestExtraData* extra_data = new RequestExtraData();
+  extra_data->set_visibility_state(render_view_->visibilityState());
+  extra_data->set_custom_user_agent(custom_user_agent);
+  extra_data->set_requested_with(requested_with);
+  extra_data->set_render_frame_id(routing_id_);
+  extra_data->set_is_main_frame(frame == top_frame);
+  extra_data->set_frame_origin(
+      GURL(frame->document().securityOrigin().toString()));
+  extra_data->set_parent_is_main_frame(frame->parent() == top_frame);
+  extra_data->set_parent_render_frame_id(parent_routing_id);
+  extra_data->set_allow_download(navigation_state->allow_download());
+  extra_data->set_transition_type(transition_type);
+  extra_data->set_should_replace_current_entry(should_replace_current_entry);
+  extra_data->set_transferred_request_child_id(
+      navigation_state->transferred_request_child_id());
+  extra_data->set_transferred_request_request_id(
+      navigation_state->transferred_request_request_id());
+  extra_data->set_service_worker_provider_id(provider_id);
+  request.setExtraData(extra_data);
 
   DocumentState* top_document_state =
       DocumentState::FromDataSource(top_data_source);
   if (top_document_state) {
     // TODO(gavinp): separate out prefetching and prerender field trials
     // if the rel=prerender rel type is sticking around.
-    if (request.targetType() == WebURLRequest::TargetIsPrefetch)
+    if (request.requestContext() == WebURLRequest::RequestContextPrefetch)
       top_document_state->set_was_prefetcher(true);
-
-    if (was_after_preconnect_request)
-      top_document_state->set_was_after_preconnect_request(true);
   }
 
   // This is an instance where we embed a copy of the routing id
@@ -1698,9 +2829,10 @@ void RenderFrameImpl::willSendRequest(
 }
 
 void RenderFrameImpl::didReceiveResponse(
-    blink::WebFrame* frame,
+    blink::WebLocalFrame* frame,
     unsigned identifier,
     const blink::WebURLResponse& response) {
+  DCHECK(!frame_ || frame_ == frame);
   // Only do this for responses that correspond to a provisional data source
   // of the top-most frame.  If we have a provisional data source, then we
   // can't have any sub-resources yet, so we know that this response must
@@ -1742,25 +2874,42 @@ void RenderFrameImpl::didReceiveResponse(
   internal_data->set_use_error_page(true);
 }
 
-void RenderFrameImpl::didFinishResourceLoad(blink::WebFrame* frame,
+void RenderFrameImpl::didFinishResourceLoad(blink::WebLocalFrame* frame,
                                             unsigned identifier) {
-  // TODO(nasko): Move implementation here. Needed state:
-  // * devtools_agent_
-  // Needed methods:
-  // * LoadNavigationErrorPage
-  render_view_->didFinishResourceLoad(frame, identifier);
+  DCHECK(!frame_ || frame_ == frame);
+  InternalDocumentStateData* internal_data =
+      InternalDocumentStateData::FromDataSource(frame->dataSource());
+  if (!internal_data->use_error_page())
+    return;
+
+  // Do not show error page when DevTools is attached.
+  if (render_view_->devtools_agent_->IsAttached())
+    return;
+
+  // Display error page, if appropriate.
+  std::string error_domain = "http";
+  int http_status_code = internal_data->http_status_code();
+  if (GetContentClient()->renderer()->HasErrorPage(
+          http_status_code, &error_domain)) {
+    WebURLError error;
+    error.unreachableURL = frame->document().url();
+    error.domain = WebString::fromUTF8(error_domain);
+    error.reason = http_status_code;
+    LoadNavigationErrorPage(frame->dataSource()->request(), error, true);
+  }
 }
 
 void RenderFrameImpl::didLoadResourceFromMemoryCache(
-    blink::WebFrame* frame,
+    blink::WebLocalFrame* frame,
     const blink::WebURLRequest& request,
     const blink::WebURLResponse& response) {
+  DCHECK(!frame_ || frame_ == frame);
   // The recipients of this message have no use for data: URLs: they don't
   // affect the page's insecure content list and are not in the disk cache. To
   // prevent large (1M+) data: URLs from crashing in the IPC system, we simply
   // filter them out here.
   GURL url(request.url());
-  if (url.SchemeIs("data"))
+  if (url.SchemeIs(url::kDataScheme))
     return;
 
   // Let the browser know we loaded a resource from the memory cache.  This
@@ -1771,25 +2920,28 @@ void RenderFrameImpl::didLoadResourceFromMemoryCache(
       response.securityInfo(),
       request.httpMethod().utf8(),
       response.mimeType().utf8(),
-      ResourceType::FromTargetType(request.targetType())));
+      WebURLRequestToResourceType(request)));
 }
 
-void RenderFrameImpl::didDisplayInsecureContent(blink::WebFrame* frame) {
+void RenderFrameImpl::didDisplayInsecureContent(blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
   render_view_->Send(new ViewHostMsg_DidDisplayInsecureContent(
       render_view_->GetRoutingID()));
 }
 
 void RenderFrameImpl::didRunInsecureContent(
-    blink::WebFrame* frame,
+    blink::WebLocalFrame* frame,
     const blink::WebSecurityOrigin& origin,
     const blink::WebURL& target) {
+  DCHECK(!frame_ || frame_ == frame);
   render_view_->Send(new ViewHostMsg_DidRunInsecureContent(
       render_view_->GetRoutingID(),
       origin.toString().utf8(),
       target));
 }
 
-void RenderFrameImpl::didAbortLoading(blink::WebFrame* frame) {
+void RenderFrameImpl::didAbortLoading(blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
 #if defined(ENABLE_PLUGINS)
   if (frame != render_view_->webview()->mainFrame())
     return;
@@ -1798,46 +2950,54 @@ void RenderFrameImpl::didAbortLoading(blink::WebFrame* frame) {
 #endif
 }
 
-void RenderFrameImpl::didExhaustMemoryAvailableForScript(
-    blink::WebFrame* frame) {
-  render_view_->Send(new ViewHostMsg_JSOutOfMemory(
-      render_view_->GetRoutingID()));
-}
-
-void RenderFrameImpl::didCreateScriptContext(blink::WebFrame* frame,
+void RenderFrameImpl::didCreateScriptContext(blink::WebLocalFrame* frame,
                                              v8::Handle<v8::Context> context,
                                              int extension_group,
                                              int world_id) {
+  DCHECK(!frame_ || frame_ == frame);
   GetContentClient()->renderer()->DidCreateScriptContext(
       frame, context, extension_group, world_id);
 }
 
-void RenderFrameImpl::willReleaseScriptContext(blink::WebFrame* frame,
+void RenderFrameImpl::willReleaseScriptContext(blink::WebLocalFrame* frame,
                                                v8::Handle<v8::Context> context,
                                                int world_id) {
-  GetContentClient()->renderer()->WillReleaseScriptContext(
-      frame, context, world_id);
-}
+  DCHECK(!frame_ || frame_ == frame);
 
-void RenderFrameImpl::didFirstVisuallyNonEmptyLayout(blink::WebFrame* frame) {
-  render_view_->didFirstVisuallyNonEmptyLayout(frame);
+  FOR_EACH_OBSERVER(RenderFrameObserver,
+                    observers_,
+                    WillReleaseScriptContext(context, world_id));
 }
 
-void RenderFrameImpl::didChangeContentsSize(blink::WebFrame* frame,
-                                            const blink::WebSize& size) {
-  // TODO(nasko): Move implementation here. Needed state:
-  // * cached_has_main_frame_horizontal_scrollbar_
-  // * cached_has_main_frame_vertical_scrollbar_
-  render_view_->didChangeContentsSize(frame, size);
+void RenderFrameImpl::didFirstVisuallyNonEmptyLayout(
+    blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
+  if (frame->parent())
+    return;
+
+  InternalDocumentStateData* data =
+      InternalDocumentStateData::FromDataSource(frame->dataSource());
+  data->set_did_first_visually_non_empty_layout(true);
+
+#if defined(OS_ANDROID)
+  GetRenderWidget()->DidChangeBodyBackgroundColor(
+      render_view_->webwidget_->backgroundColor());
+#endif
+
+  GetRenderWidget()->QueueMessage(
+      new FrameHostMsg_DidFirstVisuallyNonEmptyPaint(routing_id_),
+      MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE);
 }
 
-void RenderFrameImpl::didChangeScrollOffset(blink::WebFrame* frame) {
+void RenderFrameImpl::didChangeScrollOffset(blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
   // TODO(nasko): Move implementation here. Needed methods:
   // * StartNavStateSyncTimerIfNecessary
   render_view_->didChangeScrollOffset(frame);
 }
 
-void RenderFrameImpl::willInsertBody(blink::WebFrame* frame) {
+void RenderFrameImpl::willInsertBody(blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
   if (!frame->parent()) {
     render_view_->Send(new ViewHostMsg_WillInsertBody(
         render_view_->GetRoutingID()));
@@ -1866,11 +3026,11 @@ void RenderFrameImpl::reportFindInPageSelection(
 }
 
 void RenderFrameImpl::requestStorageQuota(
-    blink::WebFrame* frame,
+    blink::WebLocalFrame* frame,
     blink::WebStorageQuotaType type,
     unsigned long long requested_size,
     blink::WebStorageQuotaCallbacks callbacks) {
-  DCHECK(frame);
+  DCHECK(!frame_ || frame_ == frame);
   WebSecurityOrigin origin = frame->document().securityOrigin();
   if (origin.isUnique()) {
     // Unique origins cannot store persistent state.
@@ -1878,38 +3038,107 @@ void RenderFrameImpl::requestStorageQuota(
     return;
   }
   ChildThread::current()->quota_dispatcher()->RequestStorageQuota(
-      render_view_->GetRoutingID(), GURL(origin.toString()),
-      static_cast<quota::StorageType>(type), requested_size,
+      render_view_->GetRoutingID(),
+      GURL(origin.toString()),
+      static_cast<storage::StorageType>(type),
+      requested_size,
       QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper(callbacks));
 }
 
 void RenderFrameImpl::willOpenSocketStream(
     blink::WebSocketStreamHandle* handle) {
-  SocketStreamHandleData::AddToHandle(handle, routing_id_);
+  WebSocketStreamHandleImpl* impl =
+      static_cast<WebSocketStreamHandleImpl*>(handle);
+  impl->SetUserData(handle, new SocketStreamHandleData(routing_id_));
+}
+
+void RenderFrameImpl::willOpenWebSocket(blink::WebSocketHandle* handle) {
+  WebSocketBridge* impl = static_cast<WebSocketBridge*>(handle);
+  impl->set_render_frame_id(routing_id_);
+}
+
+blink::WebGeolocationClient* RenderFrameImpl::geolocationClient() {
+  if (!geolocation_dispatcher_)
+    geolocation_dispatcher_ = new GeolocationDispatcher(this);
+  return geolocation_dispatcher_;
+}
+
+blink::WebPushClient* RenderFrameImpl::pushClient() {
+  if (!push_messaging_dispatcher_)
+    push_messaging_dispatcher_ = new PushMessagingDispatcher(this);
+  return push_messaging_dispatcher_;
 }
 
 void RenderFrameImpl::willStartUsingPeerConnectionHandler(
-    blink::WebFrame* frame,
+    blink::WebLocalFrame* frame,
     blink::WebRTCPeerConnectionHandler* handler) {
+  DCHECK(!frame_ || frame_ == frame);
 #if defined(ENABLE_WEBRTC)
   static_cast<RTCPeerConnectionHandler*>(handler)->associateWithFrame(frame);
 #endif
 }
 
+blink::WebUserMediaClient* RenderFrameImpl::userMediaClient() {
+  if (!web_user_media_client_)
+    InitializeUserMediaClient();
+  return web_user_media_client_;
+}
+
+blink::WebMIDIClient* RenderFrameImpl::webMIDIClient() {
+  if (!midi_dispatcher_)
+    midi_dispatcher_ = new MidiDispatcher(this);
+  return midi_dispatcher_;
+}
+
 bool RenderFrameImpl::willCheckAndDispatchMessageEvent(
-    blink::WebFrame* sourceFrame,
-    blink::WebFrame* targetFrame,
-    blink::WebSecurityOrigin targetOrigin,
+    blink::WebLocalFrame* source_frame,
+    blink::WebFrame* target_frame,
+    blink::WebSecurityOrigin target_origin,
     blink::WebDOMMessageEvent event) {
-  // TODO(nasko): Move implementation here. Needed state:
-  // * is_swapped_out_
-  return render_view_->willCheckAndDispatchMessageEvent(
-      sourceFrame, targetFrame, targetOrigin, event);
+  DCHECK(!frame_ || frame_ == target_frame);
+
+  if (!render_view_->is_swapped_out_)
+    return false;
+
+  ViewMsg_PostMessage_Params params;
+  params.is_data_raw_string = false;
+  params.data = event.data().toString();
+  params.source_origin = event.origin();
+  if (!target_origin.isNull())
+    params.target_origin = target_origin.toString();
+
+  blink::WebMessagePortChannelArray channels = event.releaseChannels();
+  if (!channels.isEmpty()) {
+    std::vector<int> message_port_ids(channels.size());
+     // Extract the port IDs from the channel array.
+     for (size_t i = 0; i < channels.size(); ++i) {
+       WebMessagePortChannelImpl* webchannel =
+           static_cast<WebMessagePortChannelImpl*>(channels[i]);
+       message_port_ids[i] = webchannel->message_port_id();
+       webchannel->QueueMessages();
+       DCHECK_NE(message_port_ids[i], MSG_ROUTING_NONE);
+     }
+     params.message_port_ids = message_port_ids;
+  }
+
+  // Include the routing ID for the source frame (if one exists), which the
+  // browser process will translate into the routing ID for the equivalent
+  // frame in the target process.
+  params.source_routing_id = MSG_ROUTING_NONE;
+  if (source_frame) {
+    RenderViewImpl* source_view =
+        RenderViewImpl::FromWebView(source_frame->view());
+    if (source_view)
+      params.source_routing_id = source_view->routing_id();
+  }
+
+  Send(new ViewHostMsg_RouteMessageEvent(render_view_->routing_id_, params));
+  return true;
 }
 
-blink::WebString RenderFrameImpl::userAgentOverride(
-    blink::WebFrame* frame,
-    const blink::WebURL& url) {
+blink::WebString RenderFrameImpl::userAgentOverride(blink::WebLocalFrame* frame,
+                                                    const blink::WebURL& url) {
+  DCHECK(!frame_ || frame_ == frame);
   if (!render_view_->webview() || !render_view_->webview()->mainFrame() ||
       render_view_->renderer_preferences_.user_agent_override.empty()) {
     return blink::WebString();
@@ -1932,13 +3161,16 @@ blink::WebString RenderFrameImpl::userAgentOverride(
   return blink::WebString();
 }
 
-blink::WebString RenderFrameImpl::doNotTrackValue(blink::WebFrame* frame) {
+blink::WebString RenderFrameImpl::doNotTrackValue(blink::WebLocalFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
   if (render_view_->renderer_preferences_.enable_do_not_track)
     return WebString::fromUTF8("1");
   return WebString();
 }
 
-bool RenderFrameImpl::allowWebGL(blink::WebFrame* frame, bool default_value) {
+bool RenderFrameImpl::allowWebGL(blink::WebLocalFrame* frame,
+                                 bool default_value) {
+  DCHECK(!frame_ || frame_ == frame);
   if (!default_value)
     return false;
 
@@ -1951,69 +3183,67 @@ bool RenderFrameImpl::allowWebGL(blink::WebFrame* frame, bool default_value) {
   return !blocked;
 }
 
-void RenderFrameImpl::didLoseWebGLContext(blink::WebFrame* frame,
+void RenderFrameImpl::didLoseWebGLContext(blink::WebLocalFrame* frame,
                                           int arb_robustness_status_code) {
+  DCHECK(!frame_ || frame_ == frame);
   render_view_->Send(new ViewHostMsg_DidLose3DContext(
       GURL(frame->top()->document().securityOrigin().toString()),
       THREE_D_API_TYPE_WEBGL,
       arb_robustness_status_code));
 }
 
-void RenderFrameImpl::showContextMenu(const blink::WebContextMenuData& data) {
-  ContextMenuParams params = ContextMenuParamsBuilder::Build(data);
-  params.source_type = GetRenderWidget()->context_menu_source_type();
-  if (params.source_type == ui::MENU_SOURCE_TOUCH_EDIT_MENU) {
-    params.x = GetRenderWidget()->touch_editing_context_menu_location().x();
-    params.y = GetRenderWidget()->touch_editing_context_menu_location().y();
-  }
-  GetRenderWidget()->OnShowHostContextMenu(&params);
+void RenderFrameImpl::forwardInputEvent(const blink::WebInputEvent* event) {
+  Send(new FrameHostMsg_ForwardInputEvent(routing_id_, event));
+}
 
-  // Plugins, e.g. PDF, don't currently update the render view when their
-  // selected text changes, but the context menu params do contain the updated
-  // selection. If that's the case, update the render view's state just prior
-  // to showing the context menu.
-  // TODO(asvitkine): http://crbug.com/152432
-  if (ShouldUpdateSelectionTextFromContextMenuParams(
-          render_view_->selection_text_,
-          render_view_->selection_text_offset_,
-          render_view_->selection_range_,
-          params)) {
-    render_view_->selection_text_ = params.selection_text;
-    // TODO(asvitkine): Text offset and range is not available in this case.
-    render_view_->selection_text_offset_ = 0;
-    render_view_->selection_range_ =
-        gfx::Range(0, render_view_->selection_text_.length());
-    Send(new ViewHostMsg_SelectionChanged(
-        routing_id_,
-        render_view_->selection_text_,
-        render_view_->selection_text_offset_,
-        render_view_->selection_range_));
-  }
+blink::WebScreenOrientationClient*
+    RenderFrameImpl::webScreenOrientationClient() {
+  if (!screen_orientation_dispatcher_)
+    screen_orientation_dispatcher_ = new ScreenOrientationDispatcher(this);
+  return screen_orientation_dispatcher_;
+}
 
-  params.frame_id = frame_->identifier();
+bool RenderFrameImpl::isControlledByServiceWorker() {
+  // If we're in the middle of committing a load, the data source we need
+  // will still be provisional.
+  WebFrame* main_frame = render_view_->webview()->mainFrame();
+  WebDataSource* data_source = NULL;
+  if (main_frame->provisionalDataSource())
+    data_source = main_frame->provisionalDataSource();
+  else
+    data_source = main_frame->dataSource();
+  ServiceWorkerNetworkProvider* provider =
+      ServiceWorkerNetworkProvider::FromDocumentState(
+          DocumentState::FromDataSource(data_source));
+  return provider->context()->controller_handle_id() !=
+      kInvalidServiceWorkerHandleId;
+}
 
-  // Serializing a GURL longer than kMaxURLChars will fail, so don't do
-  // it.  We replace it with an empty GURL so the appropriate items are disabled
-  // in the context menu.
-  // TODO(jcivelli): http://crbug.com/45160 This prevents us from saving large
-  //                 data encoded images.  We should have a way to save them.
-  if (params.src_url.spec().size() > GetMaxURLChars())
-    params.src_url = GURL();
-  render_view_->context_menu_node_ = data.node;
+void RenderFrameImpl::postAccessibilityEvent(const blink::WebAXObject& obj,
+                                             blink::WebAXEvent event) {
+  HandleWebAccessibilityEvent(obj, event);
+}
 
-#if defined(OS_ANDROID)
-  gfx::Rect start_rect;
-  gfx::Rect end_rect;
-  render_view_->GetSelectionBounds(&start_rect, &end_rect);
-  params.selection_start = gfx::Point(start_rect.x(), start_rect.bottom());
-  params.selection_end = gfx::Point(end_rect.right(), end_rect.bottom());
-#endif
+void RenderFrameImpl::didChangeManifest(blink::WebLocalFrame* frame)
+{
+  DCHECK(!frame_ || frame_ == frame);
 
-  Send(new FrameHostMsg_ContextMenu(routing_id_, params));
+  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidChangeManifest());
 }
 
-void RenderFrameImpl::forwardInputEvent(const blink::WebInputEvent* event) {
-  Send(new FrameHostMsg_ForwardInputEvent(routing_id_, event));
+void RenderFrameImpl::DidPlay(blink::WebMediaPlayer* player) {
+  Send(new FrameHostMsg_MediaPlayingNotification(
+      routing_id_, reinterpret_cast<int64>(player), player->hasVideo(),
+      player->hasAudio()));
+}
+
+void RenderFrameImpl::DidPause(blink::WebMediaPlayer* player) {
+  Send(new FrameHostMsg_MediaPausedNotification(
+      routing_id_, reinterpret_cast<int64>(player)));
+}
+
+void RenderFrameImpl::PlayerGone(blink::WebMediaPlayer* player) {
+  DidPause(player);
 }
 
 void RenderFrameImpl::AddObserver(RenderFrameObserver* observer) {
@@ -2026,16 +3256,33 @@ void RenderFrameImpl::RemoveObserver(RenderFrameObserver* observer) {
 }
 
 void RenderFrameImpl::OnStop() {
+  DCHECK(frame_);
+  frame_->stopLoading();
+  if (!frame_->parent())
+    FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers_, OnStop());
+
   FOR_EACH_OBSERVER(RenderFrameObserver, observers_, OnStop());
 }
 
+void RenderFrameImpl::WasHidden() {
+  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WasHidden());
+}
+
+void RenderFrameImpl::WasShown() {
+  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WasShown());
+}
+
+bool RenderFrameImpl::IsHidden() {
+  return GetRenderWidget()->is_hidden();
+}
+
 // Tell the embedding application that the URL of the active page has changed.
-void RenderFrameImpl::UpdateURL(WebFrame* frame) {
+void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame* frame) {
+  DCHECK(!frame_ || frame_ == frame);
   WebDataSource* ds = frame->dataSource();
   DCHECK(ds);
 
   const WebURLRequest& request = ds->request();
-  const WebURLRequest& original_request = ds->originalRequest();
   const WebURLResponse& response = ds->response();
 
   DocumentState* document_state = DocumentState::FromDataSource(ds);
@@ -2045,11 +3292,18 @@ void RenderFrameImpl::UpdateURL(WebFrame* frame) {
 
   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   params.http_status_code = response.httpStatusCode();
+  params.url_is_unreachable = ds->hasUnreachableURL();
   params.is_post = false;
   params.post_id = -1;
   params.page_id = render_view_->page_id_;
-  params.frame_id = frame->identifier();
-  params.frame_unique_name = frame->uniqueName();
+  // We need to track the RenderViewHost routing_id because of downstream
+  // dependencies (crbug.com/392171 DownloadRequestHandle, SaveFileManager,
+  // ResourceDispatcherHostImpl, MediaStreamUIProxy,
+  // SpeechRecognitionDispatcherHost and possibly others). They look up the view
+  // based on the ID stored in the resource requests. Once those dependencies
+  // are unwound or moved to RenderFrameHost (crbug.com/304341) we can move the
+  // client to be based on the routing_id of the RenderFrameHost.
+  params.render_view_routing_id = render_view_->routing_id();
   params.socket_address.set_host(response.remoteIPAddress().utf8());
   params.socket_address.set_port(response.remotePort());
   WebURLResponseExtraDataImpl* extra_data = GetExtraDataFromResponse(response);
@@ -2059,7 +3313,7 @@ void RenderFrameImpl::UpdateURL(WebFrame* frame) {
   params.security_info = response.securityInfo();
 
   // Set the URL to be displayed in the browser UI to the user.
-  params.url = render_view_->GetLoadingUrl(frame);
+  params.url = GetLoadingUrl();
   DCHECK(!is_swapped_out_ || params.url == GURL(kSwappedOutURL));
 
   if (frame->document().baseURL() != params.url)
@@ -2077,12 +3331,11 @@ void RenderFrameImpl::UpdateURL(WebFrame* frame) {
 
   // Make navigation state a part of the DidCommitProvisionalLoad message so
   // that commited entry has it at all times.
-  WebHistoryItem item = frame->currentHistoryItem();
-  if (item.isNull()) {
-    item.initialize();
-    item.setURLString(request.url().spec().utf16());
-  }
-  params.page_state = HistoryItemToPageState(item);
+  HistoryEntry* entry = render_view_->history_controller()->GetCurrentEntry();
+  if (entry)
+    params.page_state = HistoryEntryToPageState(entry);
+  else
+    params.page_state = PageState::CreateFromURL(request.url());
 
   if (!frame->parent()) {
     // Top-level navigation.
@@ -2117,7 +3370,7 @@ void RenderFrameImpl::UpdateURL(WebFrame* frame) {
     params.contents_mime_type = ds->response().mimeType().utf8();
 
     params.transition = navigation_state->transition_type();
-    if (!PageTransitionIsMainFrame(params.transition)) {
+    if (!ui::PageTransitionIsMainFrame(params.transition)) {
       // If the main frame does a load, it should not be reported as a subframe
       // navigation.  This can occur in the following case:
       // 1. You're on a site with frames.
@@ -2129,7 +3382,7 @@ void RenderFrameImpl::UpdateURL(WebFrame* frame) {
       // We don't want that, because any navigation that changes the toplevel
       // frame should be tracked as a toplevel navigation (this allows us to
       // update the URL bar, etc).
-      params.transition = PAGE_TRANSITION_LINK;
+      params.transition = ui::PAGE_TRANSITION_LINK;
     }
 
     // If the page contained a client redirect (meta refresh, document.loc...),
@@ -2137,8 +3390,8 @@ void RenderFrameImpl::UpdateURL(WebFrame* frame) {
     if (ds->isClientRedirect()) {
       params.referrer =
           Referrer(params.redirects[0], ds->request().referrerPolicy());
-      params.transition = static_cast<PageTransition>(
-          params.transition | PAGE_TRANSITION_CLIENT_REDIRECT);
+      params.transition = ui::PageTransitionFromInt(
+          params.transition | ui::PAGE_TRANSITION_CLIENT_REDIRECT);
     } else {
       params.referrer = RenderViewImpl::GetReferrerFromRequest(
           frame, ds->request());
@@ -2147,7 +3400,7 @@ void RenderFrameImpl::UpdateURL(WebFrame* frame) {
     base::string16 method = request.httpMethod();
     if (EqualsASCII(method, "POST")) {
       params.is_post = true;
-      params.post_id = ExtractPostId(item);
+      params.post_id = ExtractPostId(entry->root());
     }
 
     // Send the user agent override back.
@@ -2156,10 +3409,7 @@ void RenderFrameImpl::UpdateURL(WebFrame* frame) {
     // Track the URL of the original request.  We use the first entry of the
     // redirect chain if it exists because the chain may have started in another
     // process.
-    if (params.redirects.size() > 0)
-      params.original_request_url = params.redirects.at(0);
-    else
-      params.original_request_url = original_request.url();
+    params.original_request_url = GetOriginalRequestURL(ds);
 
     params.history_list_was_cleared =
         navigation_state->history_list_was_cleared();
@@ -2178,12 +3428,13 @@ void RenderFrameImpl::UpdateURL(WebFrame* frame) {
     // Subframe navigation: the type depends on whether this navigation
     // generated a new session history entry. When they do generate a session
     // history entry, it means the user initiated the navigation and we should
-    // mark it as such. This test checks if this is the first time UpdateURL
-    // has been called since WillNavigateToURL was called to initiate the load.
+    // mark it as such. This test checks if this is the first time
+    // SendDidCommitProvisionalLoad has been called since WillNavigateToURL was
+    // called to initiate the load.
     if (render_view_->page_id_ > render_view_->last_page_id_sent_to_browser_)
-      params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
+      params.transition = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
     else
-      params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
+      params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
 
     DCHECK(!navigation_state->history_list_was_cleared());
     params.history_list_was_cleared = false;
@@ -2199,15 +3450,487 @@ void RenderFrameImpl::UpdateURL(WebFrame* frame) {
 
   // If we end up reusing this WebRequest (for example, due to a #ref click),
   // we don't want the transition type to persist.  Just clear it.
-  navigation_state->set_transition_type(PAGE_TRANSITION_LINK);
+  navigation_state->set_transition_type(ui::PAGE_TRANSITION_LINK);
 }
 
-void RenderFrameImpl::didStartLoading() {
-  Send(new FrameHostMsg_DidStartLoading(routing_id_));
+WebElement RenderFrameImpl::GetFocusedElement() {
+  WebDocument doc = frame_->document();
+  if (!doc.isNull())
+    return doc.focusedElement();
+
+  return WebElement();
+}
+
+void RenderFrameImpl::didStartLoading(bool to_different_document) {
+  TRACE_EVENT1("navigation", "RenderFrameImpl::didStartLoading",
+               "id", routing_id_);
+  render_view_->FrameDidStartLoading(frame_);
+  Send(new FrameHostMsg_DidStartLoading(routing_id_, to_different_document));
 }
 
 void RenderFrameImpl::didStopLoading() {
+  TRACE_EVENT1("navigation", "RenderFrameImpl::didStopLoading",
+               "id", routing_id_);
+  render_view_->FrameDidStopLoading(frame_);
   Send(new FrameHostMsg_DidStopLoading(routing_id_));
 }
 
+void RenderFrameImpl::didChangeLoadProgress(double load_progress) {
+  Send(new FrameHostMsg_DidChangeLoadProgress(routing_id_, load_progress));
+}
+
+void RenderFrameImpl::HandleWebAccessibilityEvent(
+    const blink::WebAXObject& obj, blink::WebAXEvent event) {
+  if (renderer_accessibility_)
+    renderer_accessibility_->HandleWebAccessibilityEvent(obj, event);
+}
+
+void RenderFrameImpl::FocusedNodeChanged(const WebNode& node) {
+  if (renderer_accessibility_)
+    renderer_accessibility_->FocusedNodeChanged(node);
+}
+
+WebNavigationPolicy RenderFrameImpl::DecidePolicyForNavigation(
+    RenderFrame* render_frame,
+    const NavigationPolicyInfo& info) {
+#ifdef OS_ANDROID
+  // The handlenavigation API is deprecated and will be removed once
+  // crbug.com/325351 is resolved.
+  if (info.urlRequest.url() != GURL(kSwappedOutURL) &&
+      GetContentClient()->renderer()->HandleNavigation(
+          render_frame,
+          static_cast<DocumentState*>(info.extraData),
+          render_view_->opener_id_,
+          info.frame,
+          info.urlRequest,
+          info.navigationType,
+          info.defaultPolicy,
+          info.isRedirect)) {
+    return blink::WebNavigationPolicyIgnore;
+  }
+#endif
+
+  Referrer referrer(RenderViewImpl::GetReferrerFromRequest(info.frame,
+                                                           info.urlRequest));
+  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+
+  bool is_subframe = !!info.frame->parent();
+
+  if (command_line.HasSwitch(switches::kSitePerProcess) && is_subframe) {
+    // There's no reason to ignore navigations on subframes, since the swap out
+    // logic no longer applies.
+  } else {
+    if (is_swapped_out_ || render_view_->is_swapped_out()) {
+      if (info.urlRequest.url() != GURL(kSwappedOutURL)) {
+        // Targeted links may try to navigate a swapped out frame.  Allow the
+        // browser process to navigate the tab instead.  Note that it is also
+        // possible for non-targeted navigations (from this view) to arrive
+        // here just after we are swapped out.  It's ok to send them to the
+        // browser, as long as they're for the top level frame.
+        // TODO(creis): Ensure this supports targeted form submissions when
+        // fixing http://crbug.com/101395.
+        if (info.frame->parent() == NULL) {
+          OpenURL(info.frame, info.urlRequest.url(), referrer,
+                  info.defaultPolicy);
+          return blink::WebNavigationPolicyIgnore;  // Suppress the load here.
+        }
+
+        // We should otherwise ignore in-process iframe navigations, if they
+        // arrive just after we are swapped out.
+        return blink::WebNavigationPolicyIgnore;
+      }
+
+      // Allow kSwappedOutURL to complete.
+      return info.defaultPolicy;
+    }
+  }
+
+  // Webkit is asking whether to navigate to a new URL.
+  // This is fine normally, except if we're showing UI from one security
+  // context and they're trying to navigate to a different context.
+  const GURL& url = info.urlRequest.url();
+
+  // A content initiated navigation may have originated from a link-click,
+  // script, drag-n-drop operation, etc.
+  bool is_content_initiated = static_cast<DocumentState*>(info.extraData)->
+          navigation_state()->is_content_initiated();
+
+  // Experimental:
+  // If --enable-strict-site-isolation or --site-per-process is enabled, send
+  // all top-level navigations to the browser to let it swap processes when
+  // crossing site boundaries.  This is currently expected to break some script
+  // calls and navigations, such as form submissions.
+  bool force_swap_due_to_flag =
+      command_line.HasSwitch(switches::kEnableStrictSiteIsolation) ||
+      command_line.HasSwitch(switches::kSitePerProcess);
+  if (force_swap_due_to_flag &&
+      !info.frame->parent() && (is_content_initiated || info.isRedirect)) {
+    WebString origin_str = info.frame->document().securityOrigin().toString();
+    GURL frame_url(origin_str.utf8().data());
+    // TODO(cevans): revisit whether this site check is still necessary once
+    // crbug.com/101395 is fixed.
+    bool same_domain_or_host =
+        net::registry_controlled_domains::SameDomainOrHost(
+            frame_url,
+            url,
+            net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+    if (!same_domain_or_host || frame_url.scheme() != url.scheme()) {
+      OpenURL(info.frame, url, referrer, info.defaultPolicy);
+      return blink::WebNavigationPolicyIgnore;
+    }
+  }
+
+  // If the browser is interested, then give it a chance to look at the request.
+  if (is_content_initiated) {
+    bool is_form_post =
+        ((info.navigationType == blink::WebNavigationTypeFormSubmitted) ||
+            (info.navigationType == blink::WebNavigationTypeFormResubmitted)) &&
+        EqualsASCII(info.urlRequest.httpMethod(), "POST");
+    bool browser_handles_request =
+        render_view_->renderer_preferences_
+            .browser_handles_non_local_top_level_requests
+        && IsNonLocalTopLevelNavigation(url, info.frame, info.navigationType,
+                                        is_form_post);
+    if (!browser_handles_request) {
+      browser_handles_request = IsTopLevelNavigation(info.frame) &&
+          render_view_->renderer_preferences_
+              .browser_handles_all_top_level_requests;
+    }
+
+    if (browser_handles_request) {
+      OpenURL(info.frame, url, referrer, info.defaultPolicy);
+      return blink::WebNavigationPolicyIgnore;  // Suppress the load here.
+    }
+  }
+
+  // Use the frame's original request's URL rather than the document's URL for
+  // subsequent checks.  For a popup, the document's URL may become the opener
+  // window's URL if the opener has called document.write().
+  // See http://crbug.com/93517.
+  GURL old_url(info.frame->dataSource()->request().url());
+
+  // Detect when we're crossing a permission-based boundary (e.g. into or out of
+  // an extension or app origin, leaving a WebUI page, etc). We only care about
+  // top-level navigations (not iframes). But we sometimes navigate to
+  // about:blank to clear a tab, and we want to still allow that.
+  //
+  // Note: this is known to break POST submissions when crossing process
+  // boundaries until http://crbug.com/101395 is fixed.  This is better for
+  // security than loading a WebUI, extension or app page in the wrong process.
+  // POST requests don't work because this mechanism does not preserve form
+  // POST data. We will need to send the request's httpBody data up to the
+  // browser process, and issue a special POST navigation in WebKit (via
+  // FrameLoader::loadFrameRequest). See ResourceDispatcher and WebURLLoaderImpl
+  // for examples of how to send the httpBody data.
+  if (!info.frame->parent() && is_content_initiated &&
+      !url.SchemeIs(url::kAboutScheme)) {
+    bool send_referrer = false;
+
+    // All navigations to or from WebUI URLs or within WebUI-enabled
+    // RenderProcesses must be handled by the browser process so that the
+    // correct bindings and data sources can be registered.
+    // Similarly, navigations to view-source URLs or within ViewSource mode
+    // must be handled by the browser process (except for reloads - those are
+    // safe to leave within the renderer).
+    // Lastly, access to file:// URLs from non-file:// URL pages must be
+    // handled by the browser so that ordinary renderer processes don't get
+    // blessed with file permissions.
+    int cumulative_bindings = RenderProcess::current()->GetEnabledBindings();
+    bool is_initial_navigation = render_view_->page_id_ == -1;
+    bool should_fork = HasWebUIScheme(url) || HasWebUIScheme(old_url) ||
+        (cumulative_bindings & BINDINGS_POLICY_WEB_UI) ||
+        url.SchemeIs(kViewSourceScheme) ||
+        (info.frame->isViewSourceModeEnabled() &&
+            info.navigationType != blink::WebNavigationTypeReload);
+
+    if (!should_fork && url.SchemeIs(url::kFileScheme)) {
+      // Fork non-file to file opens.  Check the opener URL if this is the
+      // initial navigation in a newly opened window.
+      GURL source_url(old_url);
+      if (is_initial_navigation && source_url.is_empty() &&
+          info.frame->opener())
+        source_url = info.frame->opener()->top()->document().url();
+      DCHECK(!source_url.is_empty());
+      should_fork = !source_url.SchemeIs(url::kFileScheme);
+    }
+
+    if (!should_fork) {
+      // Give the embedder a chance.
+      should_fork = GetContentClient()->renderer()->ShouldFork(
+          info.frame, url, info.urlRequest.httpMethod().utf8(),
+          is_initial_navigation, info.isRedirect, &send_referrer);
+    }
+
+    if (should_fork) {
+      OpenURL(info.frame, url, send_referrer ? referrer : Referrer(),
+              info.defaultPolicy);
+      return blink::WebNavigationPolicyIgnore;  // Suppress the load here.
+    }
+  }
+
+  // Detect when a page is "forking" a new tab that can be safely rendered in
+  // its own process.  This is done by sites like Gmail that try to open links
+  // in new windows without script connections back to the original page.  We
+  // treat such cases as browser navigations (in which we will create a new
+  // renderer for a cross-site navigation), rather than WebKit navigations.
+  //
+  // We use the following heuristic to decide whether to fork a new page in its
+  // own process:
+  // The parent page must open a new tab to about:blank, set the new tab's
+  // window.opener to null, and then redirect the tab to a cross-site URL using
+  // JavaScript.
+  //
+  // TODO(creis): Deprecate this logic once we can rely on rel=noreferrer
+  // (see below).
+  bool is_fork =
+      // Must start from a tab showing about:blank, which is later redirected.
+      old_url == GURL(url::kAboutBlankURL) &&
+      // Must be the first real navigation of the tab.
+      render_view_->historyBackListCount() < 1 &&
+      render_view_->historyForwardListCount() < 1 &&
+      // The parent page must have set the child's window.opener to null before
+      // redirecting to the desired URL.
+      info.frame->opener() == NULL &&
+      // Must be a top-level frame.
+      info.frame->parent() == NULL &&
+      // Must not have issued the request from this page.
+      is_content_initiated &&
+      // Must be targeted at the current tab.
+      info.defaultPolicy == blink::WebNavigationPolicyCurrentTab &&
+      // Must be a JavaScript navigation, which appears as "other".
+      info.navigationType == blink::WebNavigationTypeOther;
+
+  if (is_fork) {
+    // Open the URL via the browser, not via WebKit.
+    OpenURL(info.frame, url, Referrer(), info.defaultPolicy);
+    return blink::WebNavigationPolicyIgnore;
+  }
+
+  return info.defaultPolicy;
+}
+
+void RenderFrameImpl::OpenURL(WebFrame* frame,
+                              const GURL& url,
+                              const Referrer& referrer,
+                              WebNavigationPolicy policy) {
+  DCHECK_EQ(frame_, frame);
+
+  FrameHostMsg_OpenURL_Params params;
+  params.url = url;
+  params.referrer = referrer;
+  params.disposition = RenderViewImpl::NavigationPolicyToDisposition(policy);
+  WebDataSource* ds = frame->provisionalDataSource();
+  if (ds) {
+    DocumentState* document_state = DocumentState::FromDataSource(ds);
+    NavigationState* navigation_state = document_state->navigation_state();
+    if (navigation_state->is_content_initiated()) {
+      params.should_replace_current_entry = ds->replacesCurrentHistoryItem();
+    } else {
+      // This is necessary to preserve the should_replace_current_entry value on
+      // cross-process redirects, in the event it was set by a previous process.
+      //
+      // TODO(davidben): Avoid this awkward duplication of state. See comment on
+      // NavigationState::should_replace_current_entry().
+      params.should_replace_current_entry =
+          navigation_state->should_replace_current_entry();
+    }
+  } else {
+    params.should_replace_current_entry = false;
+  }
+  params.user_gesture = WebUserGestureIndicator::isProcessingUserGesture();
+  if (GetContentClient()->renderer()->AllowPopup())
+    params.user_gesture = true;
+
+  if (policy == blink::WebNavigationPolicyNewBackgroundTab ||
+      policy == blink::WebNavigationPolicyNewForegroundTab ||
+      policy == blink::WebNavigationPolicyNewWindow ||
+      policy == blink::WebNavigationPolicyNewPopup) {
+    WebUserGestureIndicator::consumeUserGesture();
+  }
+
+  Send(new FrameHostMsg_OpenURL(routing_id_, params));
+}
+
+void RenderFrameImpl::UpdateEncoding(WebFrame* frame,
+                                     const std::string& encoding_name) {
+  // Only update main frame's encoding_name.
+  if (!frame->parent())
+    Send(new FrameHostMsg_UpdateEncoding(routing_id_, encoding_name));
+}
+
+void RenderFrameImpl::SyncSelectionIfRequired() {
+  base::string16 text;
+  size_t offset;
+  gfx::Range range;
+#if defined(ENABLE_PLUGINS)
+  if (render_view_->focused_pepper_plugin_) {
+    render_view_->focused_pepper_plugin_->GetSurroundingText(&text, &range);
+    offset = 0;  // Pepper API does not support offset reporting.
+    // TODO(kinaba): cut as needed.
+  } else
+#endif
+  {
+    size_t location, length;
+    if (!GetRenderWidget()->webwidget()->caretOrSelectionRange(
+            &location, &length)) {
+      return;
+    }
+
+    range = gfx::Range(location, location + length);
+
+    if (GetRenderWidget()->webwidget()->textInputInfo().type !=
+            blink::WebTextInputTypeNone) {
+      // If current focused element is editable, we will send 100 more chars
+      // before and after selection. It is for input method surrounding text
+      // feature.
+      if (location > kExtraCharsBeforeAndAfterSelection)
+        offset = location - kExtraCharsBeforeAndAfterSelection;
+      else
+        offset = 0;
+      length = location + length - offset + kExtraCharsBeforeAndAfterSelection;
+      WebRange webrange = WebRange::fromDocumentRange(frame_, offset, length);
+      if (!webrange.isNull())
+        text = WebRange::fromDocumentRange(
+            frame_, offset, length).toPlainText();
+    } else {
+      offset = location;
+      text = frame_->selectionAsText();
+      // http://crbug.com/101435
+      // In some case, frame->selectionAsText() returned text's length is not
+      // equal to the length returned from webwidget()->caretOrSelectionRange().
+      // So we have to set the range according to text.length().
+      range.set_end(range.start() + text.length());
+    }
+  }
+
+  // Sometimes we get repeated didChangeSelection calls from webkit when
+  // the selection hasn't actually changed. We don't want to report these
+  // because it will cause us to continually claim the X clipboard.
+  if (selection_text_offset_ != offset ||
+      selection_range_ != range ||
+      selection_text_ != text) {
+    selection_text_ = text;
+    selection_text_offset_ = offset;
+    selection_range_ = range;
+    // This IPC is dispatched by RenderWidetHost, so use its routing ID.
+    Send(new ViewHostMsg_SelectionChanged(
+        GetRenderWidget()->routing_id(), text, offset, range));
+  }
+  GetRenderWidget()->UpdateSelectionBounds();
+}
+
+void RenderFrameImpl::InitializeUserMediaClient() {
+  if (!RenderThreadImpl::current())  // Will be NULL during unit tests.
+    return;
+
+#if defined(OS_ANDROID)
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableWebRTC))
+    return;
+#endif
+
+#if defined(ENABLE_WEBRTC)
+  DCHECK(!web_user_media_client_);
+  web_user_media_client_ = new UserMediaClientImpl(
+      this,
+      RenderThreadImpl::current()->GetPeerConnectionDependencyFactory(),
+      make_scoped_ptr(new MediaStreamDispatcher(this)).Pass());
+#endif
+}
+
+WebMediaPlayer* RenderFrameImpl::CreateWebMediaPlayerForMediaStream(
+    const blink::WebURL& url,
+    WebMediaPlayerClient* client) {
+#if defined(ENABLE_WEBRTC)
+#if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL)
+  bool found_neon =
+      (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
+  UMA_HISTOGRAM_BOOLEAN("Platform.WebRtcNEONFound", found_neon);
+#endif  // defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL)
+  return new WebMediaPlayerMS(frame_, client, weak_factory_.GetWeakPtr(),
+                              new RenderMediaLog(),
+                              CreateRendererFactory());
+#else
+  return NULL;
+#endif  // defined(ENABLE_WEBRTC)
+}
+
+scoped_ptr<MediaStreamRendererFactory>
+RenderFrameImpl::CreateRendererFactory() {
+#if defined(ENABLE_WEBRTC)
+  return scoped_ptr<MediaStreamRendererFactory>(
+      new MediaStreamRendererFactory());
+#else
+  return scoped_ptr<MediaStreamRendererFactory>(
+      static_cast<MediaStreamRendererFactory*>(NULL));
+#endif
+}
+
+GURL RenderFrameImpl::GetLoadingUrl() const {
+  WebDataSource* ds = frame_->dataSource();
+  if (ds->hasUnreachableURL())
+    return ds->unreachableURL();
+
+  const WebURLRequest& request = ds->request();
+  return request.url();
+}
+
+#if defined(OS_ANDROID)
+
+WebMediaPlayer* RenderFrameImpl::CreateAndroidWebMediaPlayer(
+    const blink::WebURL& url,
+    WebMediaPlayerClient* client,
+    blink::WebContentDecryptionModule* initial_cdm) {
+  GpuChannelHost* gpu_channel_host =
+      RenderThreadImpl::current()->EstablishGpuChannelSync(
+          CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE);
+  if (!gpu_channel_host) {
+    LOG(ERROR) << "Failed to establish GPU channel for media player";
+    return NULL;
+  }
+
+  scoped_refptr<StreamTextureFactory> stream_texture_factory;
+  if (SynchronousCompositorFactory* factory =
+          SynchronousCompositorFactory::GetInstance()) {
+    stream_texture_factory = factory->CreateStreamTextureFactory(routing_id_);
+  } else {
+    scoped_refptr<webkit::gpu::ContextProviderWebContext> context_provider =
+        RenderThreadImpl::current()->SharedMainThreadContextProvider();
+
+    if (!context_provider.get()) {
+      LOG(ERROR) << "Failed to get context3d for media player";
+      return NULL;
+    }
+
+    stream_texture_factory = StreamTextureFactoryImpl::Create(
+        context_provider, gpu_channel_host, routing_id_);
+  }
+
+  return new WebMediaPlayerAndroid(
+      frame_,
+      client,
+      weak_factory_.GetWeakPtr(),
+      GetMediaPlayerManager(),
+      GetCdmManager(),
+      initial_cdm,
+      stream_texture_factory,
+      RenderThreadImpl::current()->GetMediaThreadTaskRunner(),
+      new RenderMediaLog());
+}
+
+RendererMediaPlayerManager* RenderFrameImpl::GetMediaPlayerManager() {
+  if (!media_player_manager_)
+    media_player_manager_ = new RendererMediaPlayerManager(this);
+  return media_player_manager_;
+}
+
+#endif  // defined(OS_ANDROID)
+
+#if defined(ENABLE_BROWSER_CDMS)
+RendererCdmManager* RenderFrameImpl::GetCdmManager() {
+  if (!cdm_manager_)
+    cdm_manager_ = new RendererCdmManager(this);
+  return cdm_manager_;
+}
+#endif  // defined(ENABLE_BROWSER_CDMS)
+
 }  // namespace content