Almost finish moving context_menu_node_ from RenderViewImpl to RenderFrameImpl.

The remaining uses of context_menu_node_ are easy to convert, but I've left them to a future cl so as to not make this cl any bigger. The main part of this cl is to move the Copy edit command from RenderViewHost to RenderFrameHost. To do that, I also had to convert Cut and Paste at the same time because of BrowserView.

BUG=304341
[email protected]

Review URL: https://codereview.chromium.org/183923030

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@255735 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 884eb91..931ed78 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -1445,6 +1445,8 @@
   RecordUsedItem(id);
 
   RenderViewHost* rvh = source_web_contents_->GetRenderViewHost();
+  RenderFrameHost* render_frame_host =
+      RenderFrameHost::FromID(render_process_id_, render_frame_id_);
 
   // Process custom actions range.
   if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
@@ -1457,8 +1459,6 @@
         source_web_contents_, false, std::string());
     }
 #endif
-    RenderFrameHost* render_frame_host =
-        RenderFrameHost::FromID(render_process_id_, render_frame_id_);
     if (render_frame_host)
       render_frame_host->ExecuteCustomContextMenuCommand(action, context);
     return;
@@ -1798,15 +1798,18 @@
       break;
 
     case IDC_CONTENT_CONTEXT_CUT:
-      rvh->Cut();
+      if (render_frame_host)
+        render_frame_host->Cut();
       break;
 
     case IDC_CONTENT_CONTEXT_COPY:
-      rvh->Copy();
+      if (render_frame_host)
+        render_frame_host->Copy();
       break;
 
     case IDC_CONTENT_CONTEXT_PASTE:
-      rvh->Paste();
+      if (render_frame_host)
+        render_frame_host->Paste();
       break;
 
     case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
diff --git a/chrome/browser/ui/cocoa/applescript/tab_applescript.mm b/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
index 7602e39..1113e8e 100644
--- a/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
+++ b/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
@@ -17,6 +17,7 @@
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/save_page_type.h"
 #include "content/public/browser/web_contents.h"
@@ -26,6 +27,7 @@
 using content::NavigationController;
 using content::NavigationEntry;
 using content::OpenURLParams;
+using content::RenderFrameHost;
 using content::RenderViewHost;
 using content::Referrer;
 using content::WebContents;
@@ -184,33 +186,33 @@
 }
 
 - (void)handlesCutScriptCommand:(NSScriptCommand*)command {
-  RenderViewHost* view = webContents_->GetRenderViewHost();
-  if (!view) {
+  RenderFrameHost* frame = webContents_->GetFocusedFrame();
+  if (!frame) {
     NOTREACHED();
     return;
   }
 
-  view->Cut();
+  frame->Cut();
 }
 
 - (void)handlesCopyScriptCommand:(NSScriptCommand*)command {
-  RenderViewHost* view = webContents_->GetRenderViewHost();
-  if (!view) {
+  RenderFrameHost* frame = webContents_->GetFocusedFrame();
+  if (!frame) {
     NOTREACHED();
     return;
   }
 
-  view->Copy();
+  frame->Copy();
 }
 
 - (void)handlesPasteScriptCommand:(NSScriptCommand*)command {
-  RenderViewHost* view = webContents_->GetRenderViewHost();
-  if (!view) {
+  RenderFrameHost* frame = webContents_->GetFocusedFrame();
+  if (!frame) {
     NOTREACHED();
     return;
   }
 
-  view->Paste();
+  frame->Paste();
 }
 
 - (void)handlesSelectAllScriptCommand:(NSScriptCommand*)command {
diff --git a/chrome/browser/ui/gtk/gtk_window_util.cc b/chrome/browser/ui/gtk/gtk_window_util.cc
index 90d80f70..d074f32 100644
--- a/chrome/browser/ui/gtk/gtk_window_util.cc
+++ b/chrome/browser/ui/gtk/gtk_window_util.cc
@@ -5,12 +5,13 @@
 #include "chrome/browser/ui/gtk/gtk_window_util.h"
 
 #include <dlfcn.h>
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "ui/base/base_window.h"
 
-using content::RenderWidgetHost;
+using content::RenderFrameHost;
 using content::WebContents;
 
 namespace gtk_window_util {
@@ -31,7 +32,7 @@
 // TODO(suzhe): This approach does not work for plugins.
 void DoCutCopyPaste(GtkWindow* window,
                     WebContents* web_contents,
-                    void (RenderWidgetHost::*method)(),
+                    void (RenderFrameHost::*method)(),
                     const char* signal) {
   GtkWidget* widget = gtk_window_get_focus(window);
   if (widget == NULL)
@@ -39,7 +40,8 @@
 
   if (web_contents &&
       widget == web_contents->GetView()->GetContentNativeView()) {
-    (web_contents->GetRenderViewHost()->*method)();
+    RenderFrameHost* frame = web_contents->GetFocusedFrame();
+    (frame->*method)();
   } else {
     guint id;
     if ((id = g_signal_lookup(signal, G_OBJECT_TYPE(widget))) != 0)
@@ -49,17 +51,17 @@
 
 void DoCut(GtkWindow* window, WebContents* web_contents) {
   DoCutCopyPaste(window, web_contents,
-                 &RenderWidgetHost::Cut, "cut-clipboard");
+                 &RenderFrameHost::Cut, "cut-clipboard");
 }
 
 void DoCopy(GtkWindow* window, WebContents* web_contents) {
   DoCutCopyPaste(window, web_contents,
-                 &RenderWidgetHost::Copy, "copy-clipboard");
+                 &RenderFrameHost::Copy, "copy-clipboard");
 }
 
 void DoPaste(GtkWindow* window, WebContents* web_contents) {
   DoCutCopyPaste(window, web_contents,
-                 &RenderWidgetHost::Paste, "paste-clipboard");
+                 &RenderFrameHost::Paste, "paste-clipboard");
 }
 
 // Ubuntu patches their version of GTK+ so that there is always a
diff --git a/chrome/browser/ui/pdf/pdf_browsertest.cc b/chrome/browser/ui/pdf/pdf_browsertest.cc
index cceea4b..59e8d8a97 100644
--- a/chrome/browser/ui/pdf/pdf_browsertest.cc
+++ b/chrome/browser/ui/pdf/pdf_browsertest.cc
@@ -19,6 +19,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/notification_observer.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
@@ -291,7 +292,7 @@
   clipboard->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, objects);
 
   browser()->tab_strip_model()->GetActiveWebContents()->
-      GetRenderViewHost()->Copy();
+      GetMainFrame()->Copy();
   ASSERT_NO_FATAL_FAILURE(WaitForResponse());
 
   std::string text;
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 4ca5f16..025faff 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -100,8 +100,8 @@
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/browser/notification_service.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
@@ -1419,19 +1419,19 @@
 // won't do anything. We'll need something like an overall clipboard command
 // manager to do that.
 void BrowserView::Cut() {
-  // If a WebContent is focused, call RenderWidgetHost::Cut. Otherwise, e.g. if
+  // If a WebContent is focused, call RenderFrameHost::Cut. Otherwise, e.g. if
   // Omnibox is focused, send a Ctrl+x key event to Chrome. Using RWH interface
   // rather than the fake key event for a WebContent is important since the fake
   // event might be consumed by the web content (crbug.com/137908).
-  DoCutCopyPaste(&content::RenderWidgetHost::Cut, IDS_APP_CUT);
+  DoCutCopyPaste(&content::RenderFrameHost::Cut, IDS_APP_CUT);
 }
 
 void BrowserView::Copy() {
-  DoCutCopyPaste(&content::RenderWidgetHost::Copy, IDS_APP_COPY);
+  DoCutCopyPaste(&content::RenderFrameHost::Copy, IDS_APP_COPY);
 }
 
 void BrowserView::Paste() {
-  DoCutCopyPaste(&content::RenderWidgetHost::Paste, IDS_APP_PASTE);
+  DoCutCopyPaste(&content::RenderFrameHost::Paste, IDS_APP_PASTE);
 }
 
 WindowOpenDisposition BrowserView::GetDispositionForPopupBounds(
@@ -2508,7 +2508,7 @@
   toolbar_->ShowBrowserActionPopup(extension);
 }
 
-void BrowserView::DoCutCopyPaste(void (content::RenderWidgetHost::*method)(),
+void BrowserView::DoCutCopyPaste(void (content::RenderFrameHost::*method)(),
                                  int command_id) {
   WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents();
   if (!contents)
@@ -2535,7 +2535,7 @@
 
 bool BrowserView::DoCutCopyPasteForWebContents(
     WebContents* contents,
-    void (content::RenderWidgetHost::*method)()) {
+    void (content::RenderFrameHost::*method)()) {
   gfx::NativeView native_view = contents->GetView()->GetContentNativeView();
   if (!native_view)
     return false;
@@ -2544,7 +2544,9 @@
 #elif defined(OS_WIN)
   if (native_view == ::GetFocus()) {
 #endif
-    (contents->GetRenderViewHost()->*method)();
+    content::RenderFrameHost* frame = contents->GetFocusedFrame();
+    if (frame)
+      (frame->*method)();
     return true;
   }
 
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 1775ca9..6778b88 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -67,7 +67,7 @@
 }
 
 namespace content {
-class RenderWidgetHost;
+class RenderFrameHost;
 }
 
 namespace extensions {
@@ -570,17 +570,17 @@
   void UpdateAcceleratorMetrics(const ui::Accelerator& accelerator,
                                 int command_id);
 
-  // Calls |method| which is either RenderWidgetHost::Cut, ::Copy, or ::Paste,
+  // Calls |method| which is either RenderFrameHost::Cut, ::Copy, or ::Paste,
   // first trying the content WebContents, then the devtools WebContents, and
   // lastly the Views::Textfield if one is focused.
-  void DoCutCopyPaste(void (content::RenderWidgetHost::*method)(),
+  void DoCutCopyPaste(void (content::RenderFrameHost::*method)(),
                       int command_id);
 
-  // Calls |method| which is either RenderWidgetHost::Cut, ::Copy, or ::Paste on
+  // Calls |method| which is either RenderFrameHost::Cut, ::Copy, or ::Paste on
   // the given WebContents, returning true if it consumed the event.
   bool DoCutCopyPasteForWebContents(
       content::WebContents* contents,
-      void (content::RenderWidgetHost::*method)());
+      void (content::RenderFrameHost::*method)());
 
   // Shows the next app-modal dialog box, if there is one to be shown, or moves
   // an existing showing one to the front.
diff --git a/content/browser/frame_host/frame_tree.cc b/content/browser/frame_host/frame_tree.cc
index 23fc768..1accb0e9 100644
--- a/content/browser/frame_host/frame_tree.cc
+++ b/content/browser/frame_host/frame_tree.cc
@@ -71,7 +71,8 @@
                               render_view_delegate,
                               render_widget_delegate,
                               manager_delegate,
-                              std::string())) {
+                              std::string())),
+      focused_frame_tree_node_id_(-1) {
 }
 
 FrameTree::~FrameTree() {
@@ -138,6 +139,7 @@
 
 void FrameTree::ResetForMainFrameSwap() {
   root_->ResetForNewProcess();
+  focused_frame_tree_node_id_ = -1;
 }
 
 void FrameTree::RenderProcessGone(RenderViewHost* render_view_host) {
@@ -154,6 +156,14 @@
   return root_->current_frame_host();
 }
 
+FrameTreeNode* FrameTree::GetFocusedFrame() {
+  return FindByID(focused_frame_tree_node_id_);
+}
+
+void FrameTree::SetFocusedFrame(FrameTreeNode* node) {
+  focused_frame_tree_node_id_ = node->frame_tree_node_id();
+}
+
 void FrameTree::SetFrameRemoveListener(
     const base::Callback<void(RenderViewHostImpl*, int)>& on_frame_removed) {
   on_frame_removed_ = on_frame_removed;
diff --git a/content/browser/frame_host/frame_tree.h b/content/browser/frame_host/frame_tree.h
index 1a436182..c7fdc4e 100644
--- a/content/browser/frame_host/frame_tree.h
+++ b/content/browser/frame_host/frame_tree.h
@@ -88,6 +88,12 @@
   // Convenience accessor for the main frame's RenderFrameHostImpl.
   RenderFrameHostImpl* GetMainFrame() const;
 
+  // Returns the focused frame.
+  FrameTreeNode* GetFocusedFrame();
+
+  // Sets the focused frame.
+  void SetFocusedFrame(FrameTreeNode* node);
+
   // Allows a client to listen for frame removal.  The listener should expect
   // to receive the RenderViewHostImpl containing the frame and the renderer-
   // specific frame routing ID of the removed frame.
@@ -145,6 +151,8 @@
 
   scoped_ptr<FrameTreeNode> root_;
 
+  int64 focused_frame_tree_node_id_;
+
   base::Callback<void(RenderViewHostImpl*, int)> on_frame_removed_;
 
   DISALLOW_COPY_AND_ASSIGN(FrameTree);
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 2574edf..bb57d97 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -16,6 +16,7 @@
 #include "content/browser/frame_host/render_frame_host_delegate.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/common/frame_messages.h"
+#include "content/common/input_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_process_host.h"
@@ -131,6 +132,21 @@
   Send(new FrameMsg_CustomContextMenuAction(routing_id_, context, action));
 }
 
+void RenderFrameHostImpl::Cut() {
+  Send(new InputMsg_Cut(routing_id_));
+  RecordAction(base::UserMetricsAction("Cut"));
+}
+
+void RenderFrameHostImpl::Copy() {
+  Send(new InputMsg_Copy(routing_id_));
+  RecordAction(base::UserMetricsAction("Copy"));
+}
+
+void RenderFrameHostImpl::Paste() {
+  Send(new InputMsg_Paste(routing_id_));
+  RecordAction(base::UserMetricsAction("Paste"));
+}
+
 void RenderFrameHostImpl::InsertCSS(const std::string& css) {
   Send(new FrameMsg_CSSInsertRequest(routing_id_, css));
 }
@@ -155,6 +171,7 @@
   bool msg_is_ok = true;
   IPC_BEGIN_MESSAGE_MAP_EX(RenderFrameHostImpl, msg, msg_is_ok)
     IPC_MESSAGE_HANDLER(FrameHostMsg_Detach, OnDetach)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_FrameFocused, OnFrameFocused)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartProvisionalLoadForFrame,
                         OnDidStartProvisionalLoadForFrame)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidFailProvisionalLoadWithError,
@@ -198,6 +215,10 @@
   frame_tree_->RemoveFrame(frame_tree_node_);
 }
 
+void RenderFrameHostImpl::OnFrameFocused() {
+  frame_tree_->SetFocusedFrame(frame_tree_node_);
+}
+
 void RenderFrameHostImpl::OnOpenURL(
     const FrameHostMsg_OpenURL_Params& params) {
   GURL validated_url(params.url);
@@ -428,7 +449,7 @@
     // completing a RVH swap or unload handler.
     render_view_host_->SetState(RenderViewHostImpl::STATE_DEFAULT);
 
-    Send(new FrameMsg_Navigate(GetRoutingID(), params));
+    Send(new FrameMsg_Navigate(routing_id_, params));
   }
 
   // Force the throbber to start. We do this because Blink's "started
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 1d688f3f..edc92ac 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -55,6 +55,9 @@
       const CustomContextMenuContext& context) OVERRIDE;
   virtual void ExecuteCustomContextMenuCommand(
       int action, const CustomContextMenuContext& context) OVERRIDE;
+  virtual void Cut() OVERRIDE;
+  virtual void Copy() OVERRIDE;
+  virtual void Paste() OVERRIDE;
   virtual void InsertCSS(const std::string& css) OVERRIDE;
   virtual RenderViewHost* GetRenderViewHost() OVERRIDE;
 
@@ -150,6 +153,7 @@
 
   // IPC Message handlers.
   void OnDetach();
+  void OnFrameFocused();
   void OnOpenURL(const FrameHostMsg_OpenURL_Params& params);
   void OnDidStartProvisionalLoadForFrame(int parent_routing_id,
                                          bool main_frame,
diff --git a/content/browser/renderer_host/DEPS b/content/browser/renderer_host/DEPS
index 2696801e..7d21550 100644
--- a/content/browser/renderer_host/DEPS
+++ b/content/browser/renderer_host/DEPS
@@ -29,6 +29,12 @@
   "render_process_host_impl\.cc": [
     "+content/browser/frame_host/render_frame_message_filter.h",
   ],
+  "render_widget_host_view_mac\.mm": [
+    "+content/browser/frame_host",
+  ],
+  "ime_adapter_android\.cc": [
+    "+content/browser/frame_host",
+  ],
   # TODO(nasko): Remove these exceptions once we've untangled the dependency
   # of RenderViewHost on the FrameTree.
   "render_view_host_impl\.(cc|h)": [
diff --git a/content/browser/renderer_host/ime_adapter_android.cc b/content/browser/renderer_host/ime_adapter_android.cc
index 04e89259..9bdf431 100644
--- a/content/browser/renderer_host/ime_adapter_android.cc
+++ b/content/browser/renderer_host/ime_adapter_android.cc
@@ -11,9 +11,14 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_android.h"
 #include "content/common/view_messages.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "jni/ImeAdapter_jni.h"
 #include "third_party/WebKit/public/web/WebCompositionUnderline.h"
@@ -240,27 +245,21 @@
 }
 
 void ImeAdapterAndroid::Cut(JNIEnv* env, jobject) {
-  RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
-  if (!rwhi)
-    return;
-
-  rwhi->Cut();
+  RenderFrameHost* rfh = GetFocusedFrame();
+  if (rfh)
+    rfh->Cut();
 }
 
 void ImeAdapterAndroid::Copy(JNIEnv* env, jobject) {
-  RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
-  if (!rwhi)
-    return;
-
-  rwhi->Copy();
+  RenderFrameHost* rfh = GetFocusedFrame();
+  if (rfh)
+    rfh->Copy();
 }
 
 void ImeAdapterAndroid::Paste(JNIEnv* env, jobject) {
-  RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
-  if (!rwhi)
-    return;
-
-  rwhi->Paste();
+  RenderFrameHost* rfh = GetFocusedFrame();
+  if (rfh)
+    rfh->Paste();
 }
 
 void ImeAdapterAndroid::ResetImeAdapter(JNIEnv* env, jobject) {
@@ -268,6 +267,7 @@
 }
 
 RenderWidgetHostImpl* ImeAdapterAndroid::GetRenderWidgetHostImpl() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(rwhva_);
   RenderWidgetHost* rwh = rwhva_->GetRenderWidgetHost();
   if (!rwh)
@@ -276,4 +276,21 @@
   return RenderWidgetHostImpl::From(rwh);
 }
 
+RenderFrameHost* ImeAdapterAndroid::GetFocusedFrame() {
+  RenderWidgetHostImpl* rwh = GetRenderWidgetHostImpl();
+  if (!rwh)
+    return NULL;
+  if (!rwh->IsRenderView())
+    return NULL;
+  RenderViewHost* rvh = RenderViewHost::From(rwh);
+  RenderFrameHostImpl* rfh =
+      static_cast<RenderFrameHostImpl*>(rvh->GetMainFrame());
+  FrameTreeNode* focused_frame =
+      rfh->frame_tree_node()->frame_tree()->GetFocusedFrame();
+  if (!focused_frame)
+    return NULL;
+
+  return focused_frame->current_frame_host();
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/ime_adapter_android.h b/content/browser/renderer_host/ime_adapter_android.h
index 7ea05923..d3f7feef 100644
--- a/content/browser/renderer_host/ime_adapter_android.h
+++ b/content/browser/renderer_host/ime_adapter_android.h
@@ -11,6 +11,7 @@
 
 namespace content {
 
+class RenderFrameHost;
 class RenderWidgetHostImpl;
 class RenderWidgetHostViewAndroid;
 struct NativeWebKeyboardEvent;
@@ -60,6 +61,7 @@
 
  private:
   RenderWidgetHostImpl* GetRenderWidgetHostImpl();
+  RenderFrameHost* GetFocusedFrame();
 
   RenderWidgetHostViewAndroid* rwhva_;
   JavaObjectWeakGlobalRef java_ime_adapter_;
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index c715fca..73c306d 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2233,16 +2233,6 @@
   RecordAction(base::UserMetricsAction("Redo"));
 }
 
-void RenderWidgetHostImpl::Cut() {
-  Send(new InputMsg_Cut(GetRoutingID()));
-  RecordAction(base::UserMetricsAction("Cut"));
-}
-
-void RenderWidgetHostImpl::Copy() {
-  Send(new InputMsg_Copy(GetRoutingID()));
-  RecordAction(base::UserMetricsAction("Copy"));
-}
-
 void RenderWidgetHostImpl::CopyToFindPboard() {
 #if defined(OS_MACOSX)
   // Windows/Linux don't have the concept of a find pasteboard.
@@ -2251,11 +2241,6 @@
 #endif
 }
 
-void RenderWidgetHostImpl::Paste() {
-  Send(new InputMsg_Paste(GetRoutingID()));
-  RecordAction(base::UserMetricsAction("Paste"));
-}
-
 void RenderWidgetHostImpl::PasteAndMatchStyle() {
   Send(new InputMsg_PasteAndMatchStyle(GetRoutingID()));
   RecordAction(base::UserMetricsAction("PasteAndMatchStyle"));
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 7792b8b4..aa895184 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -123,10 +123,7 @@
   // RenderWidgetHost implementation.
   virtual void Undo() OVERRIDE;
   virtual void Redo() OVERRIDE;
-  virtual void Cut() OVERRIDE;
-  virtual void Copy() OVERRIDE;
   virtual void CopyToFindPboard() OVERRIDE;
-  virtual void Paste() OVERRIDE;
   virtual void PasteAndMatchStyle() OVERRIDE;
   virtual void Delete() OVERRIDE;
   virtual void SelectAll() OVERRIDE;
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 3e6253a..52e88b4 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -2395,12 +2395,9 @@
 
 TEST_InputRouterRoutes_NOARGS(Undo);
 TEST_InputRouterRoutes_NOARGS(Redo);
-TEST_InputRouterRoutes_NOARGS(Cut);
-TEST_InputRouterRoutes_NOARGS(Copy);
 #if defined(OS_MACOSX)
 TEST_InputRouterRoutes_NOARGS(CopyToFindPboard);
 #endif
-TEST_InputRouterRoutes_NOARGS(Paste);
 TEST_InputRouterRoutes_NOARGS(PasteAndMatchStyle);
 TEST_InputRouterRoutes_NOARGS(Delete);
 TEST_InputRouterRoutes_NOARGS(SelectAll);
@@ -2411,6 +2408,18 @@
 
 #undef TEST_InputRouterRoutes_NOARGS
 
+#define TEST_InputRouterRoutes_NOARGS_FromRFH(INPUTMSG) \
+  TEST_F(RenderWidgetHostTest, InputRouterRoutes##INPUTMSG) { \
+    host_->SetupForInputRouterTest(); \
+    host_->Send(new INPUTMSG(host_->GetRoutingID())); \
+    EXPECT_TRUE(host_->mock_input_router()->send_event_called_); \
+  }
+
+TEST_InputRouterRoutes_NOARGS_FromRFH(InputMsg_Cut);
+TEST_InputRouterRoutes_NOARGS_FromRFH(InputMsg_Copy);
+TEST_InputRouterRoutes_NOARGS_FromRFH(InputMsg_Paste);
+#undef TEST_InputRouterRoutes_NOARGS_FromRFH
+
 TEST_F(RenderWidgetHostTest, InputRouterRoutesReplace) {
   host_->SetupForInputRouterTest();
   host_->Replace(base::string16());
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index 2d73673..31fdb5e 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -30,6 +30,7 @@
 namespace content {
 class CompositingIOSurfaceMac;
 class CompositingIOSurfaceContext;
+class RenderFrameHost;
 class RenderWidgetHostViewMac;
 class RenderWidgetHostViewMacEditCommandHelper;
 }
@@ -402,6 +403,9 @@
   gfx::Range ConvertCharacterRangeToCompositionRange(
       const gfx::Range& request_range);
 
+  // Returns the focused frame. May return NULL.
+  RenderFrameHost* GetFocusedFrame();
+
   // These member variables should be private, but the associated ObjC class
   // needs access to them and can't be made a friend.
 
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index e3940a0..0321e80 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -27,6 +27,9 @@
 #include "base/sys_info.h"
 #import "content/browser/accessibility/browser_accessibility_cocoa.h"
 #include "content/browser/accessibility/browser_accessibility_manager_mac.h"
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/backing_store_mac.h"
 #include "content/browser/renderer_host/backing_store_manager.h"
 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
@@ -72,7 +75,10 @@
 using content::BrowserAccessibility;
 using content::BrowserAccessibilityManager;
 using content::EditCommand;
+using content::FrameTreeNode;
 using content::NativeWebKeyboardEvent;
+using content::RenderFrameHost;
+using content::RenderViewHost;
 using content::RenderViewHostImpl;
 using content::RenderWidgetHostImpl;
 using content::RenderWidgetHostViewMac;
@@ -1714,6 +1720,21 @@
       request_range.end() - composition_range_.start());
 }
 
+RenderFrameHost* RenderWidgetHostViewMac::GetFocusedFrame() {
+  if (!render_widget_host_->IsRenderView())
+    return NULL;
+
+  RenderViewHost* rvh = RenderViewHost::From(render_widget_host_);
+  RenderFrameHostImpl* rfh =
+      static_cast<RenderFrameHostImpl*>(rvh->GetMainFrame());
+  FrameTreeNode* focused_frame =
+      rfh->frame_tree_node()->frame_tree()->GetFocusedFrame();
+  if (!focused_frame)
+    return NULL;
+
+  return focused_frame->current_frame_host();
+}
+
 bool RenderWidgetHostViewMac::GetCachedFirstRectForCharacterRange(
     NSRange range,
     NSRect* rect,
@@ -3967,17 +3988,15 @@
 }
 
 - (void)cut:(id)sender {
-  if (renderWidgetHostView_->render_widget_host_->IsRenderView()) {
-    static_cast<RenderViewHostImpl*>(
-        renderWidgetHostView_->render_widget_host_)->Cut();
-  }
+  RenderFrameHost* host = renderWidgetHostView_->GetFocusedFrame();
+  if (host)
+    host->Cut();
 }
 
 - (void)copy:(id)sender {
-  if (renderWidgetHostView_->render_widget_host_->IsRenderView()) {
-    static_cast<RenderViewHostImpl*>(
-        renderWidgetHostView_->render_widget_host_)->Copy();
-  }
+  RenderFrameHost* host = renderWidgetHostView_->GetFocusedFrame();
+  if (host)
+    host->Copy();
 }
 
 - (void)copyToFindPboard:(id)sender {
@@ -3988,10 +4007,9 @@
 }
 
 - (void)paste:(id)sender {
-  if (renderWidgetHostView_->render_widget_host_->IsRenderView()) {
-    static_cast<RenderViewHostImpl*>(
-        renderWidgetHostView_->render_widget_host_)->Paste();
-  }
+  RenderFrameHost* host = renderWidgetHostView_->GetFocusedFrame();
+  if (host)
+    host->Paste();
 }
 
 - (void)pasteAndMatchStyle:(id)sender {
diff --git a/content/browser/web_contents/touch_editable_impl_aura.cc b/content/browser/web_contents/touch_editable_impl_aura.cc
index 3f3ff90..558d278 100644
--- a/content/browser/web_contents/touch_editable_impl_aura.cc
+++ b/content/browser/web_contents/touch_editable_impl_aura.cc
@@ -7,7 +7,10 @@
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
 #include "content/common/view_messages.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/web_contents.h"
 #include "grit/ui_strings.h"
 #include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/screen_position_client.h"
@@ -334,15 +337,18 @@
   if (!rwhva_)
     return;
   RenderWidgetHost* host = rwhva_->GetRenderWidgetHost();
+  RenderViewHost* rvh = RenderViewHost::From(host);
+  WebContents* wc = WebContents::FromRenderViewHost(rvh);
+  RenderFrameHost* focused_frame = wc->GetFocusedFrame();
   switch (command_id) {
     case IDS_APP_CUT:
-      host->Cut();
+      focused_frame->Cut();
       break;
     case IDS_APP_COPY:
-      host->Copy();
+      focused_frame->Copy();
       break;
     case IDS_APP_PASTE:
-      host->Paste();
+      focused_frame->Paste();
       break;
     case IDS_APP_DELETE:
       host->Delete();
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 808f58a0..9d5fb1f 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -584,6 +584,12 @@
   return frame_tree_.root()->current_frame_host();
 }
 
+RenderFrameHost* WebContentsImpl::GetFocusedFrame() {
+  if (!frame_tree_.GetFocusedFrame())
+    return NULL;
+  return frame_tree_.GetFocusedFrame()->current_frame_host();
+}
+
 void WebContentsImpl::ForEachFrame(
     const base::Callback<void(RenderFrameHost*)>& on_frame) {
   frame_tree_.ForEach(base::Bind(&ForEachFrameInternal, on_frame));
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index a309497..d4f4045 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -186,6 +186,7 @@
   virtual BrowserContext* GetBrowserContext() const OVERRIDE;
   virtual RenderProcessHost* GetRenderProcessHost() const OVERRIDE;
   virtual RenderFrameHost* GetMainFrame() OVERRIDE;
+  virtual RenderFrameHost* GetFocusedFrame() OVERRIDE;
   virtual void ForEachFrame(
       const base::Callback<void(RenderFrameHost*)>& on_frame) OVERRIDE;
   virtual void SendToAllFrames(IPC::Message* message) OVERRIDE;
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc
index d1c7829..d07908a 100644
--- a/content/browser/web_contents/web_contents_view_aura.cc
+++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -1145,8 +1145,9 @@
 
 void WebContentsViewAura::ShowContextMenu(RenderFrameHost* render_frame_host,
                                           const ContextMenuParams& params) {
-  if (touch_editable_)
+  if (touch_editable_) {
     touch_editable_->EndTouchEditing(false);
+  }
   if (delegate_) {
     delegate_->ShowContextMenu(render_frame_host, params);
     // WARNING: we may have been deleted during the call to ShowContextMenu().
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index fe89c6a..8fd3a70 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -316,6 +316,9 @@
 // detached from the DOM.
 IPC_MESSAGE_ROUTED0(FrameHostMsg_Detach)
 
+// Sent by the renderer when the frame becomes focused.
+IPC_MESSAGE_ROUTED0(FrameHostMsg_FrameFocused)
+
 // Sent when the renderer starts a provisional load for a frame.
 IPC_MESSAGE_ROUTED3(FrameHostMsg_DidStartProvisionalLoadForFrame,
                     int32 /* parent_routing_id */,
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h
index 2ebc7b2..c9ea335 100644
--- a/content/public/browser/render_frame_host.h
+++ b/content/public/browser/render_frame_host.h
@@ -60,6 +60,11 @@
   virtual void ExecuteCustomContextMenuCommand(
       int action, const CustomContextMenuContext& context) = 0;
 
+  // Edit operations.
+  virtual void Cut() = 0;
+  virtual void Copy() = 0;
+  virtual void Paste() = 0;
+
   // Requests the renderer to insert CSS into the frame's document.
   virtual void InsertCSS(const std::string& css) = 0;
 
diff --git a/content/public/browser/render_widget_host.h b/content/public/browser/render_widget_host.h
index 2eb913b2..fbddb79 100644
--- a/content/public/browser/render_widget_host.h
+++ b/content/public/browser/render_widget_host.h
@@ -124,12 +124,10 @@
   virtual ~RenderWidgetHost() {}
 
   // Edit operations.
+  // TODO(jam): move the rest of these to RenderFrameHost
   virtual void Undo() = 0;
   virtual void Redo() = 0;
-  virtual void Cut() = 0;
-  virtual void Copy() = 0;
   virtual void CopyToFindPboard() = 0;
-  virtual void Paste() = 0;
   virtual void PasteAndMatchStyle() = 0;
   virtual void Delete() = 0;
   virtual void SelectAll() = 0;
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 0467cb8..62ff348 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -174,6 +174,9 @@
   // Returns the main frame for the currently active view.
   virtual RenderFrameHost* GetMainFrame() = 0;
 
+  // Returns the focused frame for the currently active view.
+  virtual RenderFrameHost* GetFocusedFrame() = 0;
+
   // Calls |on_frame| for each frame in the currently active view.
   virtual void ForEachFrame(
       const base::Callback<void(RenderFrameHost*)>& on_frame) = 0;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 0898ccb5..6200b3480 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -7,6 +7,7 @@
 #include <map>
 #include <string>
 
+#include "base/auto_reset.h"
 #include "base/command_line.h"
 #include "base/debug/alias.h"
 #include "base/debug/dump_without_crashing.h"
@@ -24,6 +25,7 @@
 #include "content/child/service_worker/web_service_worker_provider_impl.h"
 #include "content/child/web_socket_stream_handle_impl.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"
@@ -94,11 +96,13 @@
 using blink::WebData;
 using blink::WebDataSource;
 using blink::WebDocument;
+using blink::WebElement;
 using blink::WebFrame;
 using blink::WebHistoryItem;
 using blink::WebHTTPBody;
 using blink::WebNavigationPolicy;
 using blink::WebNavigationType;
+using blink::WebNode;
 using blink::WebPluginParams;
 using blink::WebReferrerPolicy;
 using blink::WebSearchableFormData;
@@ -358,10 +362,8 @@
     return;
 
   GetRenderWidget()->UpdateTextInputType();
-  if (render_view_->renderer_accessibility()) {
-    render_view_->renderer_accessibility()->FocusedNodeChanged(
-        blink::WebNode());
-  }
+  if (render_view_->renderer_accessibility())
+    render_view_->renderer_accessibility()->FocusedNodeChanged(WebNode());
 }
 
 void RenderFrameImpl::PepperCaretPositionChanged(
@@ -542,6 +544,9 @@
     IPC_MESSAGE_HANDLER(FrameMsg_ContextMenuClosed, OnContextMenuClosed)
     IPC_MESSAGE_HANDLER(FrameMsg_CustomContextMenuAction,
                         OnCustomContextMenuAction)
+    IPC_MESSAGE_HANDLER(InputMsg_Cut, OnCut)
+    IPC_MESSAGE_HANDLER(InputMsg_Copy, OnCopy)
+    IPC_MESSAGE_HANDLER(InputMsg_Paste, OnPaste)
     IPC_MESSAGE_HANDLER(FrameMsg_CSSInsertRequest, OnCSSInsertRequest)
   IPC_END_MESSAGE_MAP_EX()
 
@@ -841,6 +846,26 @@
   }
 }
 
+void RenderFrameImpl::OnCut() {
+  base::AutoReset<bool> handling_select_range(
+      &render_view_->handling_select_range_, true);
+  frame_->executeCommand(WebString::fromUTF8("Cut"), GetFocusedElement());
+}
+
+void RenderFrameImpl::OnCopy() {
+  base::AutoReset<bool> handling_select_range(
+      &render_view_->handling_select_range_, true);
+  WebNode current_node = render_view_->context_menu_node_.isNull() ?
+      GetFocusedElement() : render_view_->context_menu_node_;
+  frame_->executeCommand(WebString::fromUTF8("Copy"), current_node);
+}
+
+void RenderFrameImpl::OnPaste() {
+  base::AutoReset<bool> handling_select_range(
+      &render_view_->handling_select_range_, true);
+  frame_->executeCommand(WebString::fromUTF8("Paste"), GetFocusedElement());
+}
+
 void RenderFrameImpl::OnCSSInsertRequest(const std::string& css) {
   frame_->document().insertStyleSheet(WebString::fromUTF8(css));
 }
@@ -1107,6 +1132,10 @@
   }
 }
 
+void RenderFrameImpl::frameFocused() {
+  Send(new FrameHostMsg_FrameFocused(routing_id_));
+}
+
 void RenderFrameImpl::willClose(blink::WebFrame* frame) {
   DCHECK(!frame_ || frame_ == frame);
   // Call back to RenderViewImpl for observers to be notified.
@@ -2368,6 +2397,14 @@
   navigation_state->set_transition_type(PAGE_TRANSITION_LINK);
 }
 
+WebElement RenderFrameImpl::GetFocusedElement() {
+  WebDocument doc = frame_->document();
+  if (!doc.isNull())
+    return doc.focusedElement();
+
+  return WebElement();
+}
+
 void RenderFrameImpl::didStartLoading() {
   Send(new FrameHostMsg_DidStartLoading(routing_id_));
 }
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 4813d13..313f192 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -201,6 +201,7 @@
                                              const blink::WebString& name);
   virtual void didDisownOpener(blink::WebFrame* frame);
   virtual void frameDetached(blink::WebFrame* frame);
+  virtual void frameFocused();
   virtual void willClose(blink::WebFrame* frame);
   virtual void didChangeName(blink::WebFrame* frame,
                              const blink::WebString& name);
@@ -350,6 +351,10 @@
 
   void UpdateURL(blink::WebFrame* frame);
 
+  // Gets the focused element. If no such element exists then the element will
+  // be NULL.
+  blink::WebElement GetFocusedElement();
+
   // IPC message handlers ------------------------------------------------------
   //
   // The documentation for these functions should be in
@@ -362,7 +367,11 @@
   void OnContextMenuClosed(const CustomContextMenuContext& custom_context);
   void OnCustomContextMenuAction(const CustomContextMenuContext& custom_context,
                                  unsigned action);
+  void OnCut();
+  void OnCopy();
+  void OnPaste();
   void OnCSSInsertRequest(const std::string& css);
+
   // Virtual since overridden by WebTestProxy for layout tests.
   virtual blink::WebNavigationPolicy DecidePolicyForNavigation(
       RenderFrame* render_frame,
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 552224a..296fce9 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1084,12 +1084,9 @@
   bool handled = true;
   bool msg_is_ok = true;
   IPC_BEGIN_MESSAGE_MAP_EX(RenderViewImpl, message, msg_is_ok)
-    IPC_MESSAGE_HANDLER(InputMsg_Copy, OnCopy)
-    IPC_MESSAGE_HANDLER(InputMsg_Cut, OnCut)
     IPC_MESSAGE_HANDLER(InputMsg_Delete, OnDelete)
     IPC_MESSAGE_HANDLER(InputMsg_ExecuteEditCommand, OnExecuteEditCommand)
     IPC_MESSAGE_HANDLER(InputMsg_MoveCaret, OnMoveCaret)
-    IPC_MESSAGE_HANDLER(InputMsg_Paste, OnPaste)
     IPC_MESSAGE_HANDLER(InputMsg_PasteAndMatchStyle, OnPasteAndMatchStyle)
     IPC_MESSAGE_HANDLER(InputMsg_Redo, OnRedo)
     IPC_MESSAGE_HANDLER(InputMsg_Replace, OnReplace)
@@ -1287,26 +1284,6 @@
   target_url_status_ = TARGET_NONE;
 }
 
-void RenderViewImpl::OnCopy() {
-  if (!webview())
-    return;
-
-  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
-  WebNode current_node = context_menu_node_.isNull() ?
-      GetFocusedElement() : context_menu_node_;
-  webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Copy"),
-                                            current_node);
-}
-
-void RenderViewImpl::OnCut() {
-  if (!webview())
-    return;
-
-  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
-  webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Cut"),
-                                            GetFocusedElement());
-}
-
 void RenderViewImpl::OnDelete() {
   if (!webview())
     return;
@@ -1333,15 +1310,6 @@
   webview()->focusedFrame()->moveCaretSelection(point);
 }
 
-void RenderViewImpl::OnPaste() {
-  if (!webview())
-    return;
-
-  base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
-  webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Paste"),
-                                            GetFocusedElement());
-}
-
 void RenderViewImpl::OnPasteAndMatchStyle() {
   if (!webview())
     return;
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index a80c631d..edae802 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -841,12 +841,9 @@
   // The documentation for these functions should be in
   // content/common/*_messages.h for the message that the function is handling.
 
-  void OnCopy();
-  void OnCut();
   void OnDelete();
   void OnExecuteEditCommand(const std::string& name, const std::string& value);
   void OnMoveCaret(const gfx::Point& point);
-  void OnPaste();
   void OnPasteAndMatchStyle();
   void OnRedo();
   void OnReplace(const base::string16& text);
diff --git a/content/shell/browser/shell_web_contents_view_delegate_gtk.cc b/content/shell/browser/shell_web_contents_view_delegate_gtk.cc
index e3b3222..9b4ac3f 100644
--- a/content/shell/browser/shell_web_contents_view_delegate_gtk.cc
+++ b/content/shell/browser/shell_web_contents_view_delegate_gtk.cc
@@ -5,6 +5,7 @@
 #include "content/shell/browser/shell_web_contents_view_delegate.h"
 
 #include "base/command_line.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host_view.h"
@@ -220,15 +221,21 @@
 }
 
 void ShellWebContentsViewDelegate::OnCutMenuActivated(GtkWidget* widget) {
-  web_contents_->GetRenderViewHost()->Cut();
+  RenderFrameHost* frame = web_contents_->GetFocusedFrame();
+  if (frame)
+    frame->Cut();
 }
 
 void ShellWebContentsViewDelegate::OnCopyMenuActivated(GtkWidget* widget) {
-  web_contents_->GetRenderViewHost()->Copy();
+  RenderFrameHost* frame = web_contents_->GetFocusedFrame();
+  if (frame)
+    frame->Copy();
 }
 
 void ShellWebContentsViewDelegate::OnPasteMenuActivated(GtkWidget* widget) {
-  web_contents_->GetRenderViewHost()->Paste();
+  RenderFrameHost* frame = web_contents_->GetFocusedFrame();
+  if (frame)
+    frame->Paste();
 }
 
 void ShellWebContentsViewDelegate::OnDeleteMenuActivated(GtkWidget* widget) {
diff --git a/content/shell/browser/shell_web_contents_view_delegate_mac.mm b/content/shell/browser/shell_web_contents_view_delegate_mac.mm
index dc2045c..91541c95 100644
--- a/content/shell/browser/shell_web_contents_view_delegate_mac.mm
+++ b/content/shell/browser/shell_web_contents_view_delegate_mac.mm
@@ -7,6 +7,7 @@
 #import  <Cocoa/Cocoa.h>
 
 #include "base/command_line.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host_view.h"
@@ -222,15 +223,19 @@
 }
 
 void ShellWebContentsViewDelegate::ActionPerformed(int tag) {
+  RenderFrameHost* frame = web_contents_->GetFocusedFrame();
   switch (tag) {
     case ShellContextMenuItemCutTag:
-      web_contents_->GetRenderViewHost()->Cut();
+      if (frame)
+        frame->Cut();
       break;
     case ShellContextMenuItemCopyTag:
-      web_contents_->GetRenderViewHost()->Copy();
+      if (frame)
+        frame->Copy();
       break;
     case ShellContextMenuItemPasteTag:
-      web_contents_->GetRenderViewHost()->Paste();
+      if (frame)
+        frame->Paste();
       break;
     case ShellContextMenuItemDeleteTag:
       web_contents_->GetRenderViewHost()->Delete();
diff --git a/content/shell/browser/shell_web_contents_view_delegate_win.cc b/content/shell/browser/shell_web_contents_view_delegate_win.cc
index 68ab07c73..177cdb2 100644
--- a/content/shell/browser/shell_web_contents_view_delegate_win.cc
+++ b/content/shell/browser/shell_web_contents_view_delegate_win.cc
@@ -5,6 +5,7 @@
 #include "content/shell/browser/shell_web_contents_view_delegate.h"
 
 #include "base/command_line.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host_view.h"
@@ -190,15 +191,19 @@
 }
 
 void ShellWebContentsViewDelegate::MenuItemSelected(int selection) {
+  RenderFrameHost* frame = web_contents_->GetFocusedFrame();
   switch (selection) {
     case ShellContextMenuItemCutId:
-      web_contents_->GetRenderViewHost()->Cut();
+       if (frame)
+         frame->Cut();
       break;
     case ShellContextMenuItemCopyId:
-      web_contents_->GetRenderViewHost()->Copy();
+      if (frame)
+        frame->Copy();
       break;
     case ShellContextMenuItemPasteId:
-      web_contents_->GetRenderViewHost()->Paste();
+      if (frame)
+        frame->Paste();
       break;
     case ShellContextMenuItemDeleteId:
       web_contents_->GetRenderViewHost()->Delete();