Bug 501154, consolidate places where clipboard events are fired from, r=smaug,sr=neil
authorNeil Deakin <neil@mozilla.com>
Fri, 19 Mar 2010 14:32:13 -0400
changeset 39646 27259a0fcbe68ba9593b05d824bbf16e8cdd5599
parent 39645 2b8a0778faf08b138a7a7ac244c4aeab6fb38b90
child 39647 b25b7ed1e55ae2f99d41a2996c2bca57a2c5909b
push idunknown
push userunknown
push dateunknown
reviewerssmaug, neil
bugs501154
milestone1.9.3a4pre
Bug 501154, consolidate places where clipboard events are fired from, r=smaug,sr=neil
content/base/public/nsCopySupport.h
content/base/src/nsCopySupport.cpp
content/events/src/nsContentEventHandler.cpp
docshell/base/nsIContentViewerEdit.idl
dom/base/nsGlobalWindowCommands.cpp
dom/tests/mochitest/general/Makefile.in
dom/tests/mochitest/general/test_clipboard_events.html
editor/libeditor/html/nsHTMLDataTransfer.cpp
editor/libeditor/text/nsPlaintextDataTransfer.cpp
editor/libeditor/text/nsPlaintextEditor.cpp
editor/libeditor/text/nsPlaintextEditor.h
layout/base/nsDocumentViewer.cpp
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
--- a/content/base/public/nsCopySupport.h
+++ b/content/base/public/nsCopySupport.h
@@ -43,16 +43,17 @@
 class nsISelection;
 class nsIDocument;
 class nsIImageLoadingContent;
 class nsIContent;
 class nsITransferable;
 class nsACString;
 class nsAString;
 class nsIDOMNode;
+class nsIPresShell;
 
 class nsCopySupport
 {
   // class of static helper functions for copy support
   public:
     static nsresult HTMLCopy(nsISelection *aSel, nsIDocument *aDoc, PRInt16 aClipboardID);
     static nsresult DoHooks(nsIDocument *aDoc, nsITransferable *aTrans,
                             PRBool *aDoPutOnClipboard);
@@ -61,21 +62,56 @@ class nsCopySupport
     // Get the selection, or entire document, in the format specified by the mime type
     // (text/html or text/plain). If aSel is non-null, use it, otherwise get the entire
     // doc.
     static nsresult GetContents(const nsACString& aMimeType, PRUint32 aFlags, nsISelection *aSel, nsIDocument *aDoc, nsAString& outdata);
     
     static nsresult ImageCopy(nsIImageLoadingContent* aImageElement,
                               PRInt32 aCopyFlags);
 
-    // Given the current selection, find the target that
-    // before[copy,cut,paste] and [copy,cut,paste] events will fire on.
-    static nsresult GetClipboardEventTarget(nsISelection *aSel,
-                                            nsIDOMNode **aEventTarget);
-
     // Get the selection as a transferable. Similar to HTMLCopy except does
     // not deal with the clipboard.
     static nsresult GetTransferableForSelection(nsISelection * aSelection,
                                                 nsIDocument * aDocument,
                                                 nsITransferable ** aTransferable);
+
+    /**
+     * Retrieve the selection for the given document. If the current focus
+     * within the document has its own selection, aSelection will be set to it
+     * and this focused content node returned. Otherwise, aSelection will be
+     * set to the document's selection and null will be returned.
+     */
+    static nsIContent* GetSelectionForCopy(nsIDocument* aDocument,
+                                           nsISelection** aSelection);
+
+    /**
+     * Returns true if a copy operation is currently permitted based on the
+     * current focus and selection within the specified document.
+     */
+    static PRBool CanCopy(nsIDocument* aDocument);
+
+    /**
+     * Fires a cut, copy or paste event, on the given presshell, depending
+     * on the value of aType, which should be either NS_CUT, NS_COPY or
+     * NS_PASTE, and perform the default copy action if the event was not
+     * cancelled.
+     *
+     * If aSelection is specified, then this selection is used as the target
+     * of the operation. Otherwise, GetSelectionForCopy is used to retrieve
+     * the current selection.
+     *
+     * This will fire a cut, copy or paste event at the node at the start
+     * point of the selection. If a cut or copy event is not cancelled, the
+     * selection is copied to the clipboard and true is returned. Paste events
+     * have no default behaviour but true will be returned. It is expected
+     * that the caller will execute any needed default paste behaviour. Also,
+     * note that this method only copies text to the clipboard, the caller is
+     * responsible for removing the content during a cut operation if true is
+     * returned.
+     *
+     * If the event is cancelled or an error occurs, false will be returned.
+     */
+    static PRBool FireClipboardEvent(PRInt32 aType,
+                                     nsIPresShell* aPresShell,
+                                     nsISelection* aSelection);
 };
 
 #endif
--- a/content/base/src/nsCopySupport.cpp
+++ b/content/base/src/nsCopySupport.cpp
@@ -45,28 +45,36 @@
 #include "nsIServiceManager.h"
 #include "nsIClipboard.h"
 #include "nsISelection.h"
 #include "nsWidgetsCID.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIDOMRange.h"
 #include "imgIContainer.h"
+#include "nsIPresShell.h"
+#include "nsFocusManager.h"
+#include "nsEventDispatcher.h"
 
 #include "nsIDocShell.h"
 #include "nsIContentViewerEdit.h"
 #include "nsIClipboardDragDropHooks.h"
 #include "nsIClipboardDragDropHookList.h"
+#include "nsIClipboardHelper.h"
+#include "nsISelectionController.h"
 
+#include "nsPIDOMWindow.h"
 #include "nsIDocument.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIHTMLDocument.h"
 #include "nsGkAtoms.h"
+#include "nsGUIEvent.h"
+#include "nsIFrame.h"
 
 // image copy stuff
 #include "nsIImageLoadingContent.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsContentUtils.h"
 #include "nsContentCID.h"
 
 static NS_DEFINE_CID(kCClipboardCID,           NS_CLIPBOARD_CID);
@@ -577,31 +585,133 @@ static nsresult AppendDOMNode(nsITransfe
     rv = AppendString(aTransferable, info, kHTMLInfo);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // add a special flavor, even if we don't have html context data
   return AppendString(aTransferable, context, kHTMLContext);
 }
 
-// Find the target that onbefore[copy,cut,paste] and on[copy,cut,paste]
-// events will fire on -- the start node of the copy selection.
-nsresult nsCopySupport::GetClipboardEventTarget(nsISelection *aSel,
-                                                nsIDOMNode **aEventTarget)
+nsIContent*
+nsCopySupport::GetSelectionForCopy(nsIDocument* aDocument, nsISelection** aSelection)
 {
-  NS_ENSURE_ARG(aSel);
-  NS_ENSURE_ARG_POINTER(aEventTarget);
-  *aEventTarget = nsnull;
+  *aSelection = nsnull;
+
+  nsIPresShell* presShell = aDocument->GetPrimaryShell();
+  if (!presShell)
+    return nsnull;
+
+  // check if the focused node in the window has a selection
+  nsCOMPtr<nsPIDOMWindow> focusedWindow;
+  nsIContent* content =
+    nsFocusManager::GetFocusedDescendant(aDocument->GetWindow(), PR_FALSE,
+                                         getter_AddRefs(focusedWindow));
+  if (content) {
+    nsIFrame* frame = content->GetPrimaryFrame();
+    if (frame) {
+      nsCOMPtr<nsISelectionController> selCon;
+      frame->GetSelectionController(presShell->GetPresContext(), getter_AddRefs(selCon));
+      if (selCon) {
+        selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSelection);
+        return content;
+      }
+    }
+  }
+
+  // if no selection was found, use the main selection for the window
+  NS_IF_ADDREF(*aSelection = presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL));
+  return nsnull;
+}
+
+PRBool
+nsCopySupport::CanCopy(nsIDocument* aDocument)
+{
+  if (!aDocument)
+    return PR_FALSE;
+
+  nsCOMPtr<nsISelection> sel;
+  GetSelectionForCopy(aDocument, getter_AddRefs(sel));
+
+  PRBool isCollapsed;
+  sel->GetIsCollapsed(&isCollapsed);
+  return !isCollapsed;
+}
+
+PRBool
+nsCopySupport::FireClipboardEvent(PRInt32 aType, nsIPresShell* aPresShell, nsISelection* aSelection)
+{
+  NS_ASSERTION(aType == NS_CUT || aType == NS_COPY || aType == NS_PASTE,
+               "Invalid clipboard event type");
+
+  nsCOMPtr<nsIPresShell> presShell = aPresShell;
+  if (!presShell)
+    return PR_FALSE;
+
+  nsCOMPtr<nsIDocument> doc = presShell->GetDocument();
+  if (!doc)
+    return PR_FALSE;
+
+  nsCOMPtr<nsPIDOMWindow> piWindow = doc->GetWindow();
+  if (!piWindow)
+    return PR_FALSE;
 
-  nsCOMPtr<nsIDOMRange> range;
-  nsresult rv = aSel->GetRangeAt(0, getter_AddRefs(range));
-  if (rv == NS_ERROR_INVALID_ARG) // empty selection
-    return NS_ERROR_FAILURE;
-  NS_ENSURE_SUCCESS(rv, rv);
+  // if a selection was not supplied, try to find it
+  nsCOMPtr<nsIContent> content;
+  nsCOMPtr<nsISelection> sel = aSelection;
+  if (!sel)
+    content = GetSelectionForCopy(doc, getter_AddRefs(sel));
+
+  // retrieve the event target node from the start of the selection
+  if (sel) {
+    // Only cut or copy when there is an uncollapsed selection
+    if (aType == NS_CUT || aType == NS_COPY) {
+      PRBool isCollapsed;
+      sel->GetIsCollapsed(&isCollapsed);
+      if (isCollapsed)
+        return PR_FALSE;
+    }
+
+    nsCOMPtr<nsIDOMRange> range;
+    nsresult rv = sel->GetRangeAt(0, getter_AddRefs(range));
+    if (NS_SUCCEEDED(rv) && range) {
+      nsCOMPtr<nsIDOMNode> startContainer;
+      range->GetStartContainer(getter_AddRefs(startContainer));
+      if (startContainer)
+        content = do_QueryInterface(startContainer);
+    }
+  }
 
-  if (!range)
-    return NS_ERROR_FAILURE;
+  // if no content node was set, just get the root
+  if (!content) {
+    content = doc->GetRootContent();
+    if (!content)
+      return PR_FALSE;
+  }
+
+  // It seems to be unsafe to fire an event handler during reflow (bug 393696)
+  if (!nsContentUtils::IsSafeToRunScript())
+    return PR_FALSE;
 
-  rv = range->GetStartContainer(aEventTarget);
-  NS_ENSURE_SUCCESS(rv, rv);
+  // next, fire the cut or copy event
+  nsEventStatus status = nsEventStatus_eIgnore;
+  nsEvent evt(PR_TRUE, aType);
+  nsEventDispatcher::Dispatch(content, presShell->GetPresContext(), &evt, nsnull,
+                              &status);
+  // if the event was cancelled, don't do the clipboard operation
+  if (status == nsEventStatus_eConsumeNoDefault)
+    return PR_FALSE;
 
-  return (*aEventTarget) ? NS_OK : NS_ERROR_FAILURE;
+  // no need to do anything special during a paste. Either an event listener
+  // took care of it and cancelled the event, or the caller will handle it.
+  // Return true to indicate the event wasn't cancelled.
+  if (aType == NS_PASTE)
+    return PR_TRUE;
+
+  // call the copy code
+  if (NS_FAILED(nsCopySupport::HTMLCopy(sel, doc, nsIClipboard::kGlobalClipboard)))
+    return PR_FALSE;
+
+  // Now that we have copied, update the clipboard commands. This should have
+  // the effect of updating the paste menu item.
+  piWindow->UpdateCommands(NS_LITERAL_STRING("clipboard"));
+
+  return PR_TRUE;
 }
--- a/content/events/src/nsContentEventHandler.cpp
+++ b/content/events/src/nsContentEventHandler.cpp
@@ -84,18 +84,18 @@ nsContentEventHandler::InitCommon()
 
   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_AVAILABLE);
 
   // If text frame which has overflowing selection underline is dirty,
   // we need to flush the pending reflow here.
   nsresult rv = mPresShell->FlushPendingNotifications(Flush_Layout);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = mPresShell->GetSelectionForCopy(getter_AddRefs(mSelection));
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCopySupport::GetSelectionForCopy(mPresShell->GetDocument(),
+                                     getter_AddRefs(mSelection));
   NS_ASSERTION(mSelection,
                "GetSelectionForCopy succeeded, but the result is null");
 
 
   nsCOMPtr<nsIDOMRange> firstRange;
   rv = mSelection->GetRangeAt(0, getter_AddRefs(firstRange));
   // This shell doesn't support selection.
   if (NS_FAILED(rv))
--- a/docshell/base/nsIContentViewerEdit.idl
+++ b/docshell/base/nsIContentViewerEdit.idl
@@ -35,39 +35,30 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(1691a02f-53b2-4cb8-8769-48e7efc908b8)]
+[scriptable, uuid(AF13EA3A-D488-4308-B843-526E055AB943)]
 interface nsIContentViewerEdit : nsISupports
 {
-	void search();
-	readonly attribute boolean searchable;
-
 	void clearSelection();
 	void selectAll();
 
 	void copySelection();
 	readonly attribute boolean copyable;
 
 	void copyLinkLocation();
 	readonly attribute boolean inLink;
 
 	const long COPY_IMAGE_TEXT = 0x0001;
 	const long COPY_IMAGE_HTML = 0x0002;
 	const long COPY_IMAGE_DATA = 0x0004;
 	const long COPY_IMAGE_ALL = -1;
 	void copyImage(in long aCopyFlags);
 	readonly attribute boolean inImage;
 
-	void cutSelection();
-	readonly attribute boolean cutable;
-
-	void paste();
-	readonly attribute boolean pasteable;
-
 	AString getContents(in string aMimeType, in boolean aSelectionOnly);
 	readonly attribute boolean canGetContents;
 };
--- a/dom/base/nsGlobalWindowCommands.cpp
+++ b/dom/base/nsGlobalWindowCommands.cpp
@@ -54,16 +54,18 @@
 #include "nsPresContext.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsISelectionController.h"
 #include "nsIWebNavigation.h"
 #include "nsIContentViewerEdit.h"
 #include "nsIContentViewer.h"
 #include "nsFocusManager.h"
+#include "nsCopySupport.h"
+#include "nsGUIEvent.h"
 
 #include "nsIClipboardDragDropHooks.h"
 #include "nsIClipboardDragDropHookList.h"
 
 const char * const sSelectAllString = "cmd_selectAll";
 const char * const sSelectNoneString = "cmd_selectNone";
 const char * const sCopyImageLocationString = "cmd_copyImageLocation";
 const char * const sCopyImageContentsString = "cmd_copyImageContents";
@@ -402,17 +404,81 @@ nsSelectCommand::DoSelectCommand(const c
 
   return rv;
 }
 
 #if 0
 #pragma mark -
 #endif
 
-class nsClipboardBaseCommand : public nsIControllerCommand
+class nsClipboardCommand : public nsIControllerCommand
+{
+public:
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSICONTROLLERCOMMAND
+};
+
+NS_IMPL_ISUPPORTS1(nsClipboardCommand, nsIControllerCommand)
+
+nsresult
+nsClipboardCommand::IsCommandEnabled(const char* aCommandName, nsISupports *aContext, PRBool *outCmdEnabled)
+{
+  NS_ENSURE_ARG_POINTER(outCmdEnabled);
+  *outCmdEnabled = PR_FALSE;
+
+  if (strcmp(aCommandName, "cmd_copy"))
+    return NS_OK;
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aContext);
+  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsIDocument> doc = do_QueryInterface(window->GetExtantDocument());
+  *outCmdEnabled = nsCopySupport::CanCopy(doc);
+  return NS_OK;
+}
+
+nsresult
+nsClipboardCommand::DoCommand(const char *aCommandName, nsISupports *aContext)
+{
+  if (strcmp(aCommandName, "cmd_copy"))
+    return NS_OK;
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aContext);
+  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
+
+  nsIDocShell *docShell = window->GetDocShell();
+  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsIPresShell> presShell;
+  docShell->GetPresShell(getter_AddRefs(presShell));
+  NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
+
+  nsCopySupport::FireClipboardEvent(NS_COPY, presShell, nsnull);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsClipboardCommand::GetCommandStateParams(const char *aCommandName,
+                                              nsICommandParams *aParams, nsISupports *aCommandContext)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+nsClipboardCommand::DoCommandParams(const char *aCommandName, nsICommandParams* aParams, nsISupports *aContext)
+{
+  return DoCommand(aCommandName, aContext);
+}
+
+#if 0
+#pragma mark -
+#endif
+
+class nsSelectionCommand : public nsIControllerCommand
 {
 public:
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSICONTROLLERCOMMAND
 
 protected:
 
@@ -420,74 +486,74 @@ protected:
   virtual nsresult    DoClipboardCommand(const char *aCommandName, nsIContentViewerEdit* aEdit, nsICommandParams* aParams) = 0;
   
   static nsresult     GetContentViewerEditFromContext(nsISupports *aContext, nsIContentViewerEdit **aEditInterface);
   
   // no member variables, please, we're stateless!
 };
 
 
-NS_IMPL_ISUPPORTS1(nsClipboardBaseCommand, nsIControllerCommand)
+NS_IMPL_ISUPPORTS1(nsSelectionCommand, nsIControllerCommand)
 
 
 /*---------------------------------------------------------------------------
 
-  nsClipboardBaseCommand
+  nsSelectionCommand
 
 ----------------------------------------------------------------------------*/
 
 NS_IMETHODIMP
-nsClipboardBaseCommand::IsCommandEnabled(const char * aCommandName,
-                                         nsISupports *aCommandContext,
-                                         PRBool *outCmdEnabled)
+nsSelectionCommand::IsCommandEnabled(const char * aCommandName,
+                                     nsISupports *aCommandContext,
+                                     PRBool *outCmdEnabled)
 {
   NS_ENSURE_ARG_POINTER(outCmdEnabled);
   *outCmdEnabled = PR_FALSE;
 
   nsCOMPtr<nsIContentViewerEdit> contentEdit;
   GetContentViewerEditFromContext(aCommandContext,  getter_AddRefs(contentEdit));
   NS_ENSURE_TRUE(contentEdit, NS_ERROR_NOT_INITIALIZED);
 
   return IsClipboardCommandEnabled(aCommandName, contentEdit, outCmdEnabled);
 }
 
 NS_IMETHODIMP
-nsClipboardBaseCommand::DoCommand(const char *aCommandName,
-                                  nsISupports *aCommandContext)
+nsSelectionCommand::DoCommand(const char *aCommandName,
+                              nsISupports *aCommandContext)
 {
   nsCOMPtr<nsIContentViewerEdit> contentEdit;
   GetContentViewerEditFromContext(aCommandContext,  getter_AddRefs(contentEdit));
   NS_ENSURE_TRUE(contentEdit, NS_ERROR_NOT_INITIALIZED);
 
   return DoClipboardCommand(aCommandName, contentEdit, nsnull);
 }
 
 NS_IMETHODIMP
-nsClipboardBaseCommand::GetCommandStateParams(const char *aCommandName,
-                                              nsICommandParams *aParams,
-                                              nsISupports *aCommandContext)
+nsSelectionCommand::GetCommandStateParams(const char *aCommandName,
+                                          nsICommandParams *aParams,
+                                          nsISupports *aCommandContext)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
-nsClipboardBaseCommand::DoCommandParams(const char *aCommandName,
-                                        nsICommandParams *aParams,
-                                        nsISupports *aCommandContext)
+nsSelectionCommand::DoCommandParams(const char *aCommandName,
+                                    nsICommandParams *aParams,
+                                    nsISupports *aCommandContext)
 {
   nsCOMPtr<nsIContentViewerEdit> contentEdit;
   GetContentViewerEditFromContext(aCommandContext,  getter_AddRefs(contentEdit));
   NS_ENSURE_TRUE(contentEdit, NS_ERROR_NOT_INITIALIZED);
 
   return DoClipboardCommand(aCommandName, contentEdit, aParams);
 }
 
 nsresult
-nsClipboardBaseCommand::GetContentViewerEditFromContext(nsISupports *aContext,
-                                                        nsIContentViewerEdit **aEditInterface)
+nsSelectionCommand::GetContentViewerEditFromContext(nsISupports *aContext,
+                                                    nsIContentViewerEdit **aEditInterface)
 {
   NS_ENSURE_ARG(aEditInterface);
   *aEditInterface = nsnull;
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aContext);
   NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG);
 
   nsIDocShell *docShell = window->GetDocShell();
@@ -503,89 +569,32 @@ nsClipboardBaseCommand::GetContentViewer
   return NS_OK;
 }
 
 #if 0
 #pragma mark -
 #endif
 
 #define NS_DECL_CLIPBOARD_COMMAND(_cmd)                                                     \
-class _cmd : public nsClipboardBaseCommand                                                  \
+class _cmd : public nsSelectionCommand                                                  \
 {                                                                                           \
 protected:                                                                                  \
                                                                                             \
   virtual nsresult    IsClipboardCommandEnabled(const char* aCommandName,                   \
                                   nsIContentViewerEdit* aEdit, PRBool *outCmdEnabled);      \
   virtual nsresult    DoClipboardCommand(const char* aCommandName,                          \
                                   nsIContentViewerEdit* aEdit, nsICommandParams* aParams);  \
   /* no member variables, please, we're stateless! */                                       \
 };
 
-NS_DECL_CLIPBOARD_COMMAND(nsClipboardCopyCommand)
-NS_DECL_CLIPBOARD_COMMAND(nsClipboardCutCommand)
-NS_DECL_CLIPBOARD_COMMAND(nsClipboardPasteCommand)
 NS_DECL_CLIPBOARD_COMMAND(nsClipboardCopyLinkCommand)
 NS_DECL_CLIPBOARD_COMMAND(nsClipboardImageCommands)
 NS_DECL_CLIPBOARD_COMMAND(nsClipboardSelectAllNoneCommands)
 NS_DECL_CLIPBOARD_COMMAND(nsClipboardGetContentsCommand)
 
-#if 0
-#pragma mark -
-#endif
-
-
-nsresult
-nsClipboardCutCommand::IsClipboardCommandEnabled(const char* aCommandName, nsIContentViewerEdit* aEdit, PRBool *outCmdEnabled)
-{
-  return aEdit->GetCutable(outCmdEnabled);
-}
-
-nsresult
-nsClipboardCutCommand::DoClipboardCommand(const char *aCommandName, nsIContentViewerEdit* aEdit, nsICommandParams* aParams)
-{
-  return aEdit->CutSelection();
-}
-
-#if 0
-#pragma mark -
-#endif
-
-nsresult
-nsClipboardCopyCommand::IsClipboardCommandEnabled(const char* aCommandName, nsIContentViewerEdit* aEdit, PRBool *outCmdEnabled)
-{
-  return aEdit->GetCopyable(outCmdEnabled);
-}
-
-nsresult
-nsClipboardCopyCommand::DoClipboardCommand(const char *aCommandName, nsIContentViewerEdit* aEdit, nsICommandParams* aParams)
-{
-  return aEdit->CopySelection();
-}
-
-#if 0
-#pragma mark -
-#endif
-
-nsresult
-nsClipboardPasteCommand::IsClipboardCommandEnabled(const char* aCommandName, nsIContentViewerEdit* aEdit, PRBool *outCmdEnabled)
-{
-  return aEdit->GetPasteable(outCmdEnabled);
-}
-
-nsresult
-nsClipboardPasteCommand::DoClipboardCommand(const char *aCommandName, nsIContentViewerEdit* aEdit, nsICommandParams* aParams)
-{
-  return aEdit->Paste();
-}
-
-
-#if 0
-#pragma mark -
-#endif
-
 nsresult
 nsClipboardCopyLinkCommand::IsClipboardCommandEnabled(const char* aCommandName, nsIContentViewerEdit* aEdit, PRBool *outCmdEnabled)
 {
   return aEdit->GetInLink(outCmdEnabled);
 }
 
 nsresult
 nsClipboardCopyLinkCommand::DoClipboardCommand(const char *aCommandName, nsIContentViewerEdit* aEdit, nsICommandParams* aParams)
@@ -960,19 +969,19 @@ nsWindowCommandRegistration::RegisterWin
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectLinePreviousString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectLineNextString);
   // XXX these commands were never implemented. fix me.
   // NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectPagePreviousString);
   // NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectPageNextString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectTopString);
   NS_REGISTER_LAST_COMMAND(nsSelectCommand, sSelectBottomString);
 
-  NS_REGISTER_ONE_COMMAND(nsClipboardCopyCommand, "cmd_copy");
-  NS_REGISTER_ONE_COMMAND(nsClipboardCutCommand, "cmd_cut");
-  NS_REGISTER_ONE_COMMAND(nsClipboardPasteCommand, "cmd_paste");
+  NS_REGISTER_ONE_COMMAND(nsClipboardCommand, "cmd_cut");
+  NS_REGISTER_ONE_COMMAND(nsClipboardCommand, "cmd_copy");
+  NS_REGISTER_ONE_COMMAND(nsClipboardCommand, "cmd_paste");
   NS_REGISTER_ONE_COMMAND(nsClipboardCopyLinkCommand, "cmd_copyLink");
   NS_REGISTER_FIRST_COMMAND(nsClipboardImageCommands, sCopyImageLocationString);
   NS_REGISTER_NEXT_COMMAND(nsClipboardImageCommands, sCopyImageContentsString);
   NS_REGISTER_LAST_COMMAND(nsClipboardImageCommands, sCopyImageString);
   NS_REGISTER_FIRST_COMMAND(nsClipboardSelectAllNoneCommands, sSelectAllString);
   NS_REGISTER_LAST_COMMAND(nsClipboardSelectAllNoneCommands, sSelectNoneString);
 
   NS_REGISTER_ONE_COMMAND(nsClipboardGetContentsCommand, "cmd_getContents");
--- a/dom/tests/mochitest/general/Makefile.in
+++ b/dom/tests/mochitest/general/Makefile.in
@@ -50,12 +50,13 @@ include $(topsrcdir)/config/rules.mk
 		test_bug504220.html \
 		test_domWindowUtils.html \
 		test_domWindowUtils_scrollXY.html \
 		test_innerScreen.xul \
 		test_offsets.html \
 		test_offsets.js \
 		test_offsets.xul \
 		test_windowProperties.html \
+		test_clipboard_events.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/test_clipboard_events.html
@@ -0,0 +1,322 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Clipboard Events</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>      
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="border: 3px solid black; padding: 3em;">CONTENT TEXT<input id="content-input" value="INPUT TEXT"></div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript;version=1.7">
+
+// Enable full privledges for clipboard read/write operations.
+netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+
+var content = document.getElementById("content");
+var contentInput = document.getElementById("content-input");
+var clipboardInitialValue = "empty";
+
+// Test that clearing and reading the clipboard works.  A random number
+// is used to make sure that leftover clipboard values from a previous
+// test run don't cause a false-positive test.
+var cb_text = "empty_" + Math.random();
+setClipboardText(cb_text);
+is(getClipboardText(), cb_text, "set/get clipboard text failed");
+
+// Some test functions need to be run with delays.
+var delayedTests = [];
+
+// Ensure window focus before running tests, otherwise key events can
+// misfire.  We set the onfocus event handler here to actually begin
+// running tests, and call window.focus() afterwards.
+window.onfocus = function()
+{
+  window.onfocus = null;
+  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+
+  // A list of test functions to run.  Before each test function is run, the
+  // clipboard is initialized to clipboardInitialValue, and the contents of
+  // div#content are set as the window's selection.
+  var testFunctions = [
+    test_dom_oncopy,
+    test_dom_oncut,
+    test_dom_onpaste,
+    test_dom_oncopy_abort,
+    test_input_oncopy,
+    test_input_oncut,
+    test_input_onpaste,
+    test_input_oncopy_abort,
+    test_input_oncut_abort,
+    test_input_onpaste_abort,
+    ];
+  
+  // Run the main tests.  This will also populate the delayedTests array
+  for (let i = 0; i < testFunctions.length; i++) {
+    // Init clipboard
+    setClipboardText(clipboardInitialValue);
+  
+    // Reset value of contentInput.
+    contentInput.value = "INPUT TEXT";
+    
+    var func = testFunctions[i];
+    func();
+  }
+  
+  SimpleTest.finish();
+}
+
+// Calling .focus begins the test run.
+SimpleTest.waitForExplicitFinish();
+window.focus();
+
+function getClipboardText() {
+  var trans = Components.classes["@mozilla.org/widget/transferable;1"]
+    .createInstance();
+  trans = trans.QueryInterface(Components.interfaces.nsITransferable);
+  trans.addDataFlavor("text/unicode");
+  
+  var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
+    .getService();
+  clipboard = clipboard.QueryInterface(Components.interfaces.nsIClipboard);
+  clipboard.getData(trans, clipboard.kGlobalClipboard);
+
+  var str = new Object();
+  var strLen = new Object();
+    
+  try {
+    trans.getTransferData("text/unicode", str, strLen);
+  } catch(e) {
+    // NS_ERROR_FAILURE will occur if the transferable object has no
+    // text/unicode data in it.  In that case, it's not an error:
+    if (e instanceof Components.interfaces.nsIXPCException &&
+      e.result == Components.results.NS_ERROR_FAILURE) {
+      return null;
+    } else {
+      // if we don't know how to handle it then rethrow
+      throw e;
+    }
+  }
+    
+  if (!str) return null;
+
+  str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
+  if (!str) return null;
+ 
+  str = str.data.substring(0, strLen.value / 2);
+  if (!str) return null;
+ 
+  return str;
+}
+
+
+function setClipboardText(text) {
+  var helper = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
+    .getService(Components.interfaces.nsIClipboardHelper);
+  helper.copyString(text);
+}
+
+function selectContentDiv() {
+  // Set selection
+  var selection = window.getSelection();
+  selection.removeAllRanges();
+  selection.selectAllChildren(content);
+}
+
+function selectContentInput() {
+  contentInput.select();
+  contentInput.focus();
+}
+
+function test_dom_oncopy() {
+  // Setup an oncopy event handler, fire copy.  Ensure that the event
+  // handler was called, and the clipboard contents have set to CONTENT TEXT.
+  // Test firing oncopy event on ctrl-c:
+  selectContentDiv();
+  var oncopy_fired = false;
+  content.oncopy = function() { oncopy_fired = true; };
+  try {
+    synthesizeKey("c", {accelKey: 1});
+    ok(oncopy_fired, "copy event firing on DOM element");
+    is(getClipboardText(), "CONTENT TEXT",
+      "copy on DOM element set clipboard correctly");
+  } finally {
+    content.oncopy = null;
+  }
+}
+
+function test_dom_oncut() {
+  // Setup an oncut event handler, fire cut.  Ensure that the event handler
+  // was called.  The <div> doesn't handle a cut, so ensure that the
+  // clipboard text is clipboardInitialValue, NOT "CONTENT TEXT".
+  selectContentDiv();
+  var oncut_fired = false;
+  content.oncut = function() { oncut_fired = true; };
+  try {
+    synthesizeKey("x", {accelKey: 1});
+    ok(!oncut_fired, "cut event firing on DOM element")
+    is(getClipboardText(), clipboardInitialValue,
+      "cut on DOM element did not modify clipboard");
+  } finally {
+    content.oncut = null;
+  }
+}
+
+
+function test_dom_onpaste() {
+  // Setup an onpaste event handler, fire paste.  Ensure that the event
+  // handler was called.
+  selectContentDiv();
+  var onpaste_fired = false;
+  content.onpaste = function() { onpaste_fired = true; };
+  try {
+    synthesizeKey("v", {accelKey: 1});
+    ok(!onpaste_fired, "paste event firing on DOM element");
+  } finally {
+    content.onpaste = null;
+  }
+}
+
+
+function test_dom_oncopy_abort() {
+  // Setup an oncopy event handler that aborts the copy, and fire the copy
+  // event.  Ensure that the event handler was fired, and the clipboard
+  // contents have not been modified.
+  selectContentDiv();
+  var oncopy_fired = false;
+  content.oncopy = function() { oncopy_fired = true; return false; };
+  try {
+    synthesizeKey("c", {accelKey: 1});
+    ok(oncopy_fired, "copy event (to-be-cancelled) firing on DOM element");
+    is(getClipboardText(), clipboardInitialValue,
+      "aborted copy on DOM element did not modify clipboard");
+  } finally {
+    content.oncopy = null;
+  }
+}
+
+
+function test_input_oncopy() {
+  // Setup an oncopy event handler, fire copy.  Ensure that the event
+  // handler was called, and the clipboard contents have set to INPUT TEXT.
+  // Test firing oncopy event on ctrl-c:
+  selectContentInput();
+  var oncopy_fired = false;
+  contentInput.oncopy = function() { oncopy_fired = true; };
+  try {
+    synthesizeKey("c", {accelKey: 1});
+    ok(oncopy_fired, "copy event firing on plaintext editor");
+    is(getClipboardText(), "INPUT TEXT",
+      "copy on plaintext editor set clipboard correctly");
+  } finally {
+    contentInput.oncopy = null;
+  }
+}
+
+
+function test_input_oncut() {
+  // Setup an oncut event handler, and fire cut.  Ensure that the event
+  // handler was fired, the clipboard contains the INPUT TEXT, and
+  // that the input itself is empty.
+  selectContentInput();
+  var oncut_fired = false;
+  contentInput.oncut = function() { oncut_fired = true; };
+  try {
+    synthesizeKey("x", {accelKey: 1});
+    ok(oncut_fired, "cut event firing on plaintext editor");
+    is(getClipboardText(), "INPUT TEXT",
+      "cut on plaintext editor set clipboard correctly");
+    is(contentInput.value, "",
+      "cut on plaintext editor emptied editor");
+  } finally {
+    contentInput.oncut = null;
+  }
+}
+
+
+function test_input_onpaste() {
+  // Setup an onpaste event handler, and fire paste.  Ensure that the event
+  // handler was fired, the clipboard contents didn't change, and that the
+  // input value did change (ie. paste succeeded).
+  selectContentInput();
+  var onpaste_fired = false;
+  contentInput.onpaste = function() { onpaste_fired = true; };
+  try {
+    synthesizeKey("v", {accelKey: 1});
+    ok(onpaste_fired, "paste event firing on plaintext editor");
+    is(getClipboardText(), clipboardInitialValue,
+      "paste on plaintext editor did not modify clipboard contents");
+    is(contentInput.value, clipboardInitialValue,
+      "paste on plaintext editor did modify editor value");
+  } finally {
+    contentInput.onpaste = null;
+  }
+}
+
+
+function test_input_oncopy_abort() {
+  // Setup an oncopy event handler, fire copy.  Ensure that the event
+  // handler was called, and that the clipboard value did NOT change.
+  selectContentInput();
+  var oncopy_fired = false;
+  contentInput.oncopy = function() { oncopy_fired = true; return false; };
+  try {
+    synthesizeKey("c", {accelKey: 1});
+    ok(oncopy_fired, "copy event (to-be-cancelled) firing on plaintext editor");
+    is(getClipboardText(), clipboardInitialValue,
+      "aborted copy on plaintext editor did not modify clipboard");
+  } finally {
+    contentInput.oncopy = null;
+  }
+}
+
+
+function test_input_oncut_abort() {
+  // Setup an oncut event handler, and fire cut.  Ensure that the event
+  // handler was fired, the clipboard contains the INPUT TEXT, and
+  // that the input itself is empty.
+  selectContentInput();
+  var oncut_fired = false;
+  contentInput.oncut = function() { oncut_fired = true; return false; };
+  try {
+    synthesizeKey("x", {accelKey: 1});
+    ok(oncut_fired, "cut event (to-be-cancelled) firing on plaintext editor");
+    is(getClipboardText(), clipboardInitialValue,
+      "aborted cut on plaintext editor did not modify clipboard.");
+    is(contentInput.value, "INPUT TEXT",
+      "aborted cut on plaintext editor did not modify editor contents");
+  } finally {
+    contentInput.oncut = null;
+  }
+}
+
+
+function test_input_onpaste_abort() {
+  // Setup an onpaste event handler, and fire paste.  Ensure that the event
+  // handler was fired, the clipboard contents didn't change, and that the
+  // input value did change (ie. paste succeeded).
+  selectContentInput();
+  var onpaste_fired = false;
+  contentInput.onpaste = function() { onpaste_fired = true; return false; };
+  try {
+    synthesizeKey("v", {accelKey: 1});
+    ok(onpaste_fired,
+      "paste event (to-be-cancelled) firing on plaintext editor");
+    is(getClipboardText(), clipboardInitialValue,
+      "aborted paste on plaintext editor did not modify clipboard");
+    is(contentInput.value, "INPUT TEXT",
+      "aborted paste on plaintext editor did not modify modified editor value");
+  } finally {
+    contentInput.onpaste = null;
+  }
+}
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -1842,24 +1842,21 @@ PRBool nsHTMLEditor::HavePrivateHTMLFlav
     return bHavePrivateHTMLFlavor;
     
   return PR_FALSE;
 }
 
 
 NS_IMETHODIMP nsHTMLEditor::Paste(PRInt32 aSelectionType)
 {
-  ForceCompositionEnd();
-
-  PRBool preventDefault;
-  nsresult rv = FireClipboardEvent(NS_PASTE, &preventDefault);
-  if (NS_FAILED(rv) || preventDefault)
-    return rv;
+  if (!FireClipboardEvent(NS_PASTE))
+    return NS_OK;
 
   // Get Clipboard Service
+  nsresult rv;
   nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1", &rv));
   if (NS_FAILED(rv))
     return rv;
   
   // find out if we have our internal html flavor on the clipboard.  We don't want to mess
   // around with cfhtml if we do.
   PRBool bHavePrivateHTMLFlavor = HavePrivateHTMLFlavor(clipboard);
 
@@ -1927,36 +1924,30 @@ NS_IMETHODIMP nsHTMLEditor::Paste(PRInt3
     }
   }
 
   return rv;
 }
 
 NS_IMETHODIMP nsHTMLEditor::PasteTransferable(nsITransferable *aTransferable)
 {
-  ForceCompositionEnd();
-
-  PRBool preventDefault;
-  nsresult rv = FireClipboardEvent(NS_PASTE, &preventDefault);
-  if (NS_FAILED(rv) || preventDefault)
-    return rv;
+  if (!FireClipboardEvent(NS_PASTE))
+    return NS_OK;
 
   // handle transferable hooks
   nsCOMPtr<nsIDOMDocument> domdoc;
   GetDocument(getter_AddRefs(domdoc));
   if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, aTransferable))
     return NS_OK;
 
   // Beware! This may flush notifications via synchronous
   // ScrollSelectionIntoView.
   nsAutoString contextStr, infoStr;
-  rv = InsertFromTransferable(aTransferable, nsnull, contextStr, infoStr,
-                              nsnull, 0, PR_TRUE);
-
-  return rv;
+  return InsertFromTransferable(aTransferable, nsnull, contextStr, infoStr,
+                                nsnull, 0, PR_TRUE);
 }
 
 // 
 // HTML PasteNoFormatting. Ignore any HTML styles and formating in paste source
 //
 NS_IMETHODIMP nsHTMLEditor::PasteNoFormatting(PRInt32 aSelectionType)
 {
   ForceCompositionEnd();
--- a/editor/libeditor/text/nsPlaintextDataTransfer.cpp
+++ b/editor/libeditor/text/nsPlaintextDataTransfer.cpp
@@ -55,16 +55,17 @@
 #include "nsIDocumentEncoder.h"
 #include "nsISupportsPrimitives.h"
 
 // Drag & Drop, Clipboard
 #include "nsIClipboard.h"
 #include "nsITransferable.h"
 #include "nsIDragService.h"
 #include "nsIDOMNSUIEvent.h"
+#include "nsCopySupport.h"
 
 // Misc
 #include "nsEditorUtils.h"
 #include "nsContentCID.h"
 #include "nsISelectionPrivate.h"
 #include "nsFrameSelection.h"
 #include "nsEventDispatcher.h"
 
@@ -404,24 +405,21 @@ NS_IMETHODIMP nsPlaintextEditor::DoDrag(
   aDragEvent->StopPropagation();
   aDragEvent->PreventDefault();
 
   return rv;
 }
 
 NS_IMETHODIMP nsPlaintextEditor::Paste(PRInt32 aSelectionType)
 {
-  ForceCompositionEnd();
-
-  PRBool preventDefault;
-  nsresult rv = FireClipboardEvent(NS_PASTE, &preventDefault);
-  if (NS_FAILED(rv) || preventDefault)
-    return rv;
+  if (!FireClipboardEvent(NS_PASTE))
+    return NS_OK;
 
   // Get Clipboard Service
+  nsresult rv;
   nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1", &rv));
   if ( NS_FAILED(rv) )
     return rv;
 
   // Get the nsITransferable interface for getting the data from the clipboard
   nsCOMPtr<nsITransferable> trans;
   rv = PrepareTransferable(getter_AddRefs(trans));
   if (NS_SUCCEEDED(rv) && trans)
@@ -441,37 +439,31 @@ NS_IMETHODIMP nsPlaintextEditor::Paste(P
     }
   }
 
   return rv;
 }
 
 NS_IMETHODIMP nsPlaintextEditor::PasteTransferable(nsITransferable *aTransferable)
 {
-  ForceCompositionEnd();
-
-  PRBool preventDefault;
-  nsresult rv = FireClipboardEvent(NS_PASTE, &preventDefault);
-  if (NS_FAILED(rv) || preventDefault)
-    return rv;
+  if (!FireClipboardEvent(NS_PASTE))
+    return NS_OK;
 
   if (!IsModifiable())
     return NS_OK;
 
   // handle transferable hooks
   nsCOMPtr<nsIDOMDocument> domdoc;
   GetDocument(getter_AddRefs(domdoc));
   if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, aTransferable))
     return NS_OK;
 
   // Beware! This may flush notifications via synchronous
   // ScrollSelectionIntoView.
-  rv = InsertTextFromTransferable(aTransferable, nsnull, nsnull, PR_TRUE);
-
-  return rv;
+  return InsertTextFromTransferable(aTransferable, nsnull, nsnull, PR_TRUE);
 }
 
 NS_IMETHODIMP nsPlaintextEditor::CanPaste(PRInt32 aSelectionType, PRBool *aCanPaste)
 {
   NS_ENSURE_ARG_POINTER(aCanPaste);
   *aCanPaste = PR_FALSE;
 
   // can't paste if readonly
--- a/editor/libeditor/text/nsPlaintextEditor.cpp
+++ b/editor/libeditor/text/nsPlaintextEditor.cpp
@@ -1137,138 +1137,76 @@ nsPlaintextEditor::Redo(PRUint32 aCount)
   {
     result = nsEditor::Redo(aCount);
     result = mRules->DidDoAction(selection, &ruleInfo, result);
   } 
    
   return result;
 }
 
-nsresult nsPlaintextEditor::GetClipboardEventTarget(nsIDOMNode** aEventTarget)
+PRBool
+nsPlaintextEditor::CanCutOrCopy()
 {
-  NS_ENSURE_ARG_POINTER(aEventTarget);
-  *aEventTarget = nsnull;
-
   nsCOMPtr<nsISelection> selection;
-  nsresult res = GetSelection(getter_AddRefs(selection));
-  if (NS_FAILED(res))
-    return res;
+  if (NS_FAILED(GetSelection(getter_AddRefs(selection))))
+    return PR_FALSE;
 
-  return nsCopySupport::GetClipboardEventTarget(selection, aEventTarget);
+  PRBool isCollapsed;
+  selection->GetIsCollapsed(&isCollapsed);
+  return !isCollapsed;
 }
 
-nsresult nsPlaintextEditor::FireClipboardEvent(PRUint32 msg,
-                                               PRBool* aPreventDefault)
+PRBool
+nsPlaintextEditor::FireClipboardEvent(PRInt32 aType)
 {
-  *aPreventDefault = PR_FALSE;
+  if (aType == NS_PASTE)
+    ForceCompositionEnd();
 
-  nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
-  if (!ps)
-    return NS_ERROR_NOT_INITIALIZED;
-
-  // Unsafe to fire event during reflow (bug 396108)
-  PRBool isReflowing = PR_TRUE;
-  nsresult rv = ps->IsReflowLocked(&isReflowing);
-  if (NS_FAILED(rv) || isReflowing)
-    return NS_OK;
+  nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShellWeak);
+  NS_ENSURE_TRUE(presShell, PR_FALSE);
 
-  nsCOMPtr<nsIDOMNode> eventTarget;
-  rv = GetClipboardEventTarget(getter_AddRefs(eventTarget));
-  if (NS_FAILED(rv))
-    // On failure to get event target, just forget about it and don't fire.
-    return NS_OK;
+  nsCOMPtr<nsISelection> selection;
+  if (NS_FAILED(GetSelection(getter_AddRefs(selection))))
+    return PR_FALSE;
 
-  nsEventStatus status = nsEventStatus_eIgnore;
-  nsEvent evt(PR_TRUE, msg);
-  nsEventDispatcher::Dispatch(eventTarget, ps->GetPresContext(), &evt,
-                              nsnull, &status);
-  // if event handler return'd false (PreventDefault)
-  if (status == nsEventStatus_eConsumeNoDefault)
-    *aPreventDefault = PR_TRUE;
+  if (!nsCopySupport::FireClipboardEvent(aType, presShell, selection))
+    return PR_FALSE;
 
-  // Did the event handler cause the editor to be destroyed? (ie. the input
-  // element was removed from the document)  Don't proceed with command,
-  // could crash, definitely does during paste.
-  if (mDidPreDestroy)
-    return NS_ERROR_NOT_INITIALIZED;
-
-  return NS_OK;
+  // If the event handler caused the editor to be destroyed, return false.
+  // Otherwise return true to indicate that the event was not cancelled.
+  return !mDidPreDestroy;
 }
 
 NS_IMETHODIMP nsPlaintextEditor::Cut()
 {
-  PRBool preventDefault;
-  nsresult rv = FireClipboardEvent(NS_CUT, &preventDefault);
-  if (NS_FAILED(rv) || preventDefault)
-    return rv;
-
-  nsCOMPtr<nsISelection> selection;
-  rv = GetSelection(getter_AddRefs(selection));
-  if (NS_FAILED(rv))
-    return rv;
-
-  PRBool isCollapsed;
-  if (NS_SUCCEEDED(selection->GetIsCollapsed(&isCollapsed)) && isCollapsed)
-    return NS_OK;  // just return ok so no JS error is thrown
-
-  // ps should be guaranteed by FireClipboardEvent not failing
-  nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
-  rv = ps->DoCopy();
-  if (NS_SUCCEEDED(rv))
-    rv = DeleteSelection(eNone);
-  return rv;
+  if (FireClipboardEvent(NS_CUT))
+    return DeleteSelection(eNone);
+  return NS_OK;
 }
 
 NS_IMETHODIMP nsPlaintextEditor::CanCut(PRBool *aCanCut)
 {
   NS_ENSURE_ARG_POINTER(aCanCut);
-  *aCanCut = PR_FALSE;
-
-  nsCOMPtr<nsISelection> selection;
-  nsresult rv = GetSelection(getter_AddRefs(selection));
-  if (NS_FAILED(rv)) return rv;
-    
-  PRBool isCollapsed;
-  rv = selection->GetIsCollapsed(&isCollapsed);
-  if (NS_FAILED(rv)) return rv;
-
-  *aCanCut = !isCollapsed && IsModifiable();
+  *aCanCut = IsModifiable() && CanCutOrCopy();
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPlaintextEditor::Copy()
 {
-  PRBool preventDefault;
-  nsresult rv = FireClipboardEvent(NS_COPY, &preventDefault);
-  if (NS_FAILED(rv) || preventDefault)
-    return rv;
-
-  // ps should be guaranteed by FireClipboardEvent not failing
-  nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
-  return ps->DoCopy();
+  FireClipboardEvent(NS_COPY);
+  return NS_OK;
 }
 
 NS_IMETHODIMP nsPlaintextEditor::CanCopy(PRBool *aCanCopy)
 {
   NS_ENSURE_ARG_POINTER(aCanCopy);
-  *aCanCopy = PR_FALSE;
-
-  nsCOMPtr<nsISelection> selection;
-  nsresult rv = GetSelection(getter_AddRefs(selection));
-  if (NS_FAILED(rv)) return rv;
-    
-  PRBool isCollapsed;
-  rv = selection->GetIsCollapsed(&isCollapsed);
-  if (NS_FAILED(rv)) return rv;
-
-  *aCanCopy = !isCollapsed;
+  *aCanCopy = CanCutOrCopy();
   return NS_OK;
 }
 
-
 // Shared between OutputToString and OutputToStream
 NS_IMETHODIMP
 nsPlaintextEditor::GetAndInitDocEncoder(const nsAString& aFormatType,
                                         PRUint32 aFlags,
                                         const nsACString& aCharset,
                                         nsIDocumentEncoder** encoder)
 {
   nsCOMPtr<nsIPresShell> presShell;
--- a/editor/libeditor/text/nsPlaintextEditor.h
+++ b/editor/libeditor/text/nsPlaintextEditor.h
@@ -214,20 +214,18 @@ protected:
 
   /* small utility routine to test the eEditorReadonly bit */
   PRBool IsModifiable();
 
   //XXX Kludge: Used to suppress spurious drag/drop events (bug 50703)
   PRBool   mIgnoreSpuriousDragEvent;
   NS_IMETHOD IgnoreSpuriousDragEvent(PRBool aIgnoreSpuriousDragEvent) {mIgnoreSpuriousDragEvent = aIgnoreSpuriousDragEvent; return NS_OK;}
 
-  // Wrapper for nsCopySupport::GetClipboardEventTarget, finds target to fire
-  // [cut,copy,paste] and [beforecut,beforecopy,beforepaste] events at.
-  nsresult GetClipboardEventTarget(nsIDOMNode** aEventTarget);
-  nsresult FireClipboardEvent(PRUint32 msg, PRBool* aPreventDefault);
+  PRBool CanCutOrCopy();
+  PRBool FireClipboardEvent(PRInt32 aType);
 
 // Data members
 protected:
 
   nsCOMPtr<nsIEditRules>        mRules;
   PRBool  mWrapToWindow;
   PRInt32 mWrapColumn;
   PRInt32 mMaxTextLength;
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -393,19 +393,16 @@ private:
   nsresult GetPopupImageNode(nsIImageLoadingContent** aNode);
 
   void PrepareToStartLoad(void);
 
   nsresult SyncParentSubDocMap();
 
   nsresult GetDocumentSelection(nsISelection **aSelection);
 
-  nsresult GetClipboardEventTarget(nsIDOMNode **aEventTarget);
-  nsresult FireClipboardEvent(PRUint32 msg, PRBool* aPreventDefault);
-
   void DestroyPresShell();
 
 #ifdef NS_PRINTING
   // Called when the DocViewer is notified that the state
   // of Printing or PP has changed
   void SetIsPrintingInDocShellTree(nsIDocShellTreeNode* aParentNode, 
                                    PRBool               aIsPrintingOrPP, 
                                    PRBool               aStartAtTop);
@@ -2405,18 +2402,17 @@ DocumentViewerImpl::CreateDeviceContext(
     widget = widget->GetTopLevelWidget();
   }
 
   mDeviceContext->Init(widget);
   return NS_OK;
 }
 
 // Return the selection for the document. Note that text fields have their
-// own selection, which cannot be accessed with this method. Use
-// mPresShell->GetSelectionForCopy() instead.
+// own selection, which cannot be accessed with this method.
 nsresult DocumentViewerImpl::GetDocumentSelection(nsISelection **aSelection)
 {
   NS_ENSURE_ARG_POINTER(aSelection);
   if (!mPresShell) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   nsCOMPtr<nsISelectionController> selcon;
@@ -2426,50 +2422,37 @@ nsresult DocumentViewerImpl::GetDocument
                                 aSelection);
   return NS_ERROR_FAILURE;
 }
 
 /* ========================================================================================
  * nsIContentViewerEdit
  * ======================================================================================== */
 
-NS_IMETHODIMP DocumentViewerImpl::Search()
-{
-  // Nothing to do here.
-  return NS_OK;
-}
-
-NS_IMETHODIMP DocumentViewerImpl::GetSearchable(PRBool *aSearchable)
-{
-  // Nothing to do here.
-  *aSearchable = PR_FALSE;
-  return NS_OK;
-}
-
 NS_IMETHODIMP DocumentViewerImpl::ClearSelection()
 {
   nsresult rv;
   nsCOMPtr<nsISelection> selection;
 
-  // use mPresShell->GetSelectionForCopy() ?
+  // use nsCopySupport::GetSelectionForCopy() ?
   rv = GetDocumentSelection(getter_AddRefs(selection));
   if (NS_FAILED(rv)) return rv;
 
   return selection->CollapseToStart();
 }
 
 NS_IMETHODIMP DocumentViewerImpl::SelectAll()
 {
   // XXX this is a temporary implementation copied from nsWebShell
   // for now. I think nsDocument and friends should have some helper
   // functions to make this easier.
   nsCOMPtr<nsISelection> selection;
   nsresult rv;
 
-  // use mPresShell->GetSelectionForCopy() ?
+  // use nsCopySupport::GetSelectionForCopy() ?
   rv = GetDocumentSelection(getter_AddRefs(selection));
   if (NS_FAILED(rv)) return rv;
 
   nsCOMPtr<nsIDOMHTMLDocument> htmldoc = do_QueryInterface(mDocument);
   nsCOMPtr<nsIDOMNode> bodyNode;
 
   if (htmldoc)
   {
@@ -2489,22 +2472,18 @@ NS_IMETHODIMP DocumentViewerImpl::Select
   if (NS_FAILED(rv)) return rv;
 
   rv = selection->SelectAllChildren(bodyNode);
   return rv;
 }
 
 NS_IMETHODIMP DocumentViewerImpl::CopySelection()
 {
-  PRBool preventDefault;
-  nsresult rv = FireClipboardEvent(NS_COPY, &preventDefault);
-  if (NS_FAILED(rv) || preventDefault)
-    return rv;
-
-  return mPresShell->DoCopy();
+  nsCopySupport::FireClipboardEvent(NS_COPY, mPresShell, nsnull);
+  return NS_OK;
 }
 
 NS_IMETHODIMP DocumentViewerImpl::CopyLinkLocation()
 {
   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
   nsCOMPtr<nsIDOMNode> node;
   GetPopupLinkNode(getter_AddRefs(node));
   // make noise if we're not in a link
@@ -2527,128 +2506,57 @@ NS_IMETHODIMP DocumentViewerImpl::CopyIm
   nsCOMPtr<nsIImageLoadingContent> node;
   GetPopupImageNode(getter_AddRefs(node));
   // make noise if we're not in an image
   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
 
   return nsCopySupport::ImageCopy(node, aCopyFlags);
 }
 
-nsresult DocumentViewerImpl::GetClipboardEventTarget(nsIDOMNode** aEventTarget)
-{
-  NS_ENSURE_ARG_POINTER(aEventTarget);
-  *aEventTarget = nsnull;
-
-  if (!mPresShell)
-    return NS_ERROR_NOT_INITIALIZED;
-
-  nsCOMPtr<nsISelection> sel;
-  nsresult rv = mPresShell->GetSelectionForCopy(getter_AddRefs(sel));
-  if (NS_FAILED(rv))
-    return rv;
-  if (!sel)
-    return NS_ERROR_FAILURE;
-
-  return nsCopySupport::GetClipboardEventTarget(sel, aEventTarget);
-}
-
-nsresult DocumentViewerImpl::FireClipboardEvent(PRUint32 msg,
-                                                PRBool* aPreventDefault)
-{
-  *aPreventDefault = PR_FALSE;
-
-  NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_INITIALIZED);
-  NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
-
-  // It seems to be unsafe to fire an event handler during reflow (bug 393696)
-  PRBool isReflowing = PR_TRUE;
-  nsresult rv = mPresShell->IsReflowLocked(&isReflowing);
-  if (NS_FAILED(rv) || isReflowing)
-    return NS_OK;
-
-  nsCOMPtr<nsIDOMNode> eventTarget;
-  rv = GetClipboardEventTarget(getter_AddRefs(eventTarget));
-  if (NS_FAILED(rv))
-    // On failure to get event target, just forget about it and don't fire.
-    return NS_OK;
-
-  nsEventStatus status = nsEventStatus_eIgnore;
-  nsEvent evt(PR_TRUE, msg);
-  nsEventDispatcher::Dispatch(eventTarget, mPresContext, &evt, nsnull,
-                              &status);
-  // if event handler return'd false (PreventDefault)
-  if (status == nsEventStatus_eConsumeNoDefault)
-    *aPreventDefault = PR_TRUE;
-
-  // Ensure that the calling function can use mPresShell -- if the event
-  // handler closed this window, mPresShell will be gone.
-  NS_ENSURE_STATE(mPresShell);
-
-  return NS_OK;
-}
 
 NS_IMETHODIMP DocumentViewerImpl::GetCopyable(PRBool *aCopyable)
 {
   NS_ENSURE_ARG_POINTER(aCopyable);
-  *aCopyable = PR_FALSE;
-
-  NS_ENSURE_STATE(mPresShell);
-  nsCOMPtr<nsISelection> selection;
-  nsresult rv = mPresShell->GetSelectionForCopy(getter_AddRefs(selection));
-  if (NS_FAILED(rv))
-    return rv;
-
-  PRBool isCollapsed;
-  selection->GetIsCollapsed(&isCollapsed);
-
-  *aCopyable = !isCollapsed;
-  return NS_OK;
-}
-
-NS_IMETHODIMP DocumentViewerImpl::CutSelection()
-{
-  // preventDefault's value is ignored because cut from the document has no
-  // default behaviour.
-  PRBool preventDefault;
-  return FireClipboardEvent(NS_CUT, &preventDefault);
-}
-
-NS_IMETHODIMP DocumentViewerImpl::GetCutable(PRBool *aCutable)
-{
-  NS_ENSURE_ARG_POINTER(aCutable);
-  *aCutable = PR_FALSE;
-  return NS_OK;
-}
-
-NS_IMETHODIMP DocumentViewerImpl::Paste()
-{
-  // preventDefault's value is ignored because paste into the document has no
-  // default behaviour.
-  PRBool preventDefault;
-  return FireClipboardEvent(NS_PASTE, &preventDefault);
-}
-
-NS_IMETHODIMP DocumentViewerImpl::GetPasteable(PRBool *aPasteable)
-{
-  NS_ENSURE_ARG_POINTER(aPasteable);
-  *aPasteable = PR_FALSE;
+  *aCopyable = nsCopySupport::CanCopy(mDocument);
   return NS_OK;
 }
 
 /* AString getContents (in string mimeType, in boolean selectionOnly); */
 NS_IMETHODIMP DocumentViewerImpl::GetContents(const char *mimeType, PRBool selectionOnly, nsAString& aOutValue)
 {
+  aOutValue.Truncate();
+
   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
-  return mPresShell->DoGetContents(nsDependentCString(mimeType), 0, selectionOnly, aOutValue);
+  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
+
+  // Now we have the selection.  Make sure it's nonzero:
+  nsCOMPtr<nsISelection> sel;
+  if (selectionOnly) {
+    nsCopySupport::GetSelectionForCopy(mDocument, getter_AddRefs(sel));
+    NS_ENSURE_TRUE(sel, NS_ERROR_FAILURE);
+  
+    PRBool isCollapsed;
+    sel->GetIsCollapsed(&isCollapsed);
+    if (isCollapsed)
+      return NS_OK;
+  }
+
+  // call the copy code
+  return nsCopySupport::GetContents(nsDependentCString(mimeType), 0, sel,
+                                    mDocument, aOutValue);
 }
 
 /* readonly attribute boolean canGetContents; */
 NS_IMETHODIMP DocumentViewerImpl::GetCanGetContents(PRBool *aCanGetContents)
 {
-  return GetCopyable(aCanGetContents);
+  NS_ENSURE_ARG_POINTER(aCanGetContents);
+  *aCanGetContents = PR_FALSE;
+  NS_ENSURE_STATE(mDocument);
+  *aCanGetContents = nsCopySupport::CanCopy(mDocument);
+  return NS_OK;
 }
 
 #ifdef XP_MAC
 #pragma mark -
 #endif
 
 /* ========================================================================================
  * nsIContentViewerFile
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -122,18 +122,18 @@ typedef struct CapturingContentInfo {
   nsIContent* mContent;
 
   CapturingContentInfo() :
     mAllowed(PR_FALSE), mRetargetToElement(PR_FALSE), mPreventDrag(PR_FALSE),
     mContent(nsnull) { }
 } CapturingContentInfo;
 
 #define NS_IPRESSHELL_IID     \
-  { 0xe5e070ce, 0xbc17, 0x4b5f, \
-    { 0xb2, 0x21, 0xbf, 0xc3, 0xe1, 0x68, 0xbe, 0x9b } }
+{ 0x0e170e5f, 0xf6d4, 0x44c5, \
+  { 0xbc, 0x2c, 0x44, 0x94, 0x20, 0x7e, 0xcc, 0x30 } }
 
 // Constants for ScrollContentIntoView() function
 #define NS_PRESSHELL_SCROLL_TOP      0
 #define NS_PRESSHELL_SCROLL_BOTTOM   100
 #define NS_PRESSHELL_SCROLL_LEFT     0
 #define NS_PRESSHELL_SCROLL_RIGHT    100
 #define NS_PRESSHELL_SCROLL_CENTER   50
 #define NS_PRESSHELL_SCROLL_ANYWHERE -1
@@ -574,37 +574,21 @@ public:
   /**
    * Notification sent by a frame informing the pres shell that it is about to
    * be destroyed.
    * This allows any outstanding references to the frame to be cleaned up
    */
   NS_IMETHOD NotifyDestroyingFrame(nsIFrame* aFrame) = 0;
 
   /**
-   * Notify the Clipboard that we have something to copy.
-   */
-  NS_IMETHOD DoCopy() = 0;
-
-  /**
-   * Get the selection of the focussed element (either the page selection,
-   * or the selection for a text field).
-   */
-  NS_IMETHOD GetSelectionForCopy(nsISelection** outSelection) = 0;
-
-  /**
    * Get link location.
    */
   NS_IMETHOD GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocation) = 0;
 
   /**
-   * Get the doc or the selection as text or html.
-   */
-  NS_IMETHOD DoGetContents(const nsACString& aMimeType, PRUint32 aFlags, PRBool aSelectionOnly, nsAString& outValue) = 0;
-
-  /**
    * Get the caret, if it exists. AddRefs it.
    */
   NS_IMETHOD GetCaret(nsCaret **aOutCaret) = 0;
 
   /**
    * Invalidate the caret's current position if it's outside of its frame's
    * boundaries. This function is useful if you're batching selection
    * notifications and might remove the caret's frame out from under it.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -733,22 +733,18 @@ public:
                                          PRIntn        aHPercent,
                                          PRUint32      aFlags);
   virtual nsRectVisibility GetRectVisibility(nsIFrame *aFrame,
                                              const nsRect &aRect, 
                                              nscoord aMinTwips);
 
   NS_IMETHOD SetIgnoreFrameDestruction(PRBool aIgnore);
   NS_IMETHOD NotifyDestroyingFrame(nsIFrame* aFrame);
-  
-  NS_IMETHOD DoCopy();
-  NS_IMETHOD GetSelectionForCopy(nsISelection** outSelection);
 
   NS_IMETHOD GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocationString);
-  NS_IMETHOD DoGetContents(const nsACString& aMimeType, PRUint32 aFlags, PRBool aSelectionOnly, nsAString& outValue);
 
   NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState, PRBool aLeavingPage);
 
   NS_IMETHOD IsPaintingSuppressed(PRBool* aResult);
   NS_IMETHOD UnsuppressPainting();
   
   NS_IMETHOD DisableThemeSupport();
   virtual PRBool IsThemeSupportEnabled();
@@ -4293,67 +4289,16 @@ NS_IMETHODIMP PresShell::GetLinkLocation
 
     return NS_OK;
   }
 
   // if no link, fail.
   return NS_ERROR_FAILURE;
 }
 
-NS_IMETHODIMP
-PresShell::GetSelectionForCopy(nsISelection** outSelection)
-{
-  nsresult rv = NS_OK;
-
-  *outSelection = nsnull;
-
-  if (!mDocument) return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIContent> content;
-  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
-  if (fm) {
-    nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(mDocument->GetWindow());
-
-    nsCOMPtr<nsIDOMElement> focusedElement;
-    fm->GetFocusedElementForWindow(window, PR_FALSE, nsnull, getter_AddRefs(focusedElement));
-    content = do_QueryInterface(focusedElement);
-  }
-
-  nsCOMPtr<nsISelection> sel;
-  if (content)
-  {
-    //check to see if we need to get selection from frame
-    //optimization that MAY need to be expanded as more things implement their own "selection"
-    nsCOMPtr<nsIDOMNSHTMLInputElement>    htmlInputElement(do_QueryInterface(content));
-    nsCOMPtr<nsIDOMNSHTMLTextAreaElement> htmlTextAreaElement(do_QueryInterface(content));
-    if (htmlInputElement || htmlTextAreaElement)
-    {
-      nsIFrame *htmlInputFrame = content->GetPrimaryFrame();
-      if (!htmlInputFrame) return NS_ERROR_FAILURE;
-
-      nsCOMPtr<nsISelectionController> selCon;
-      rv = htmlInputFrame->
-        GetSelectionController(mPresContext,getter_AddRefs(selCon));
-      if (NS_FAILED(rv)) return rv;
-      if (!selCon) return NS_ERROR_FAILURE;
-
-      rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
-                                getter_AddRefs(sel));
-    }
-  }
-  if (!sel) {
-    sel = mSelection->GetSelection(nsISelectionController::SELECTION_NORMAL);
-    rv = NS_OK;
-  }
-
-  *outSelection = sel;
-  NS_IF_ADDREF(*outSelection);
-  return rv;
-}
-
 NS_IMETHODIMP_(void)
 PresShell::DispatchSynthMouseMove(nsGUIEvent *aEvent,
                                   PRBool aFlushOnHoverChange)
 {
   PRUint32 hoverGenerationBefore = mFrameConstructor->GetHoverGeneration();
   nsEventStatus status;
   nsIView* targetView;
   targetView = nsIView::GetViewFor(aEvent->widget);
@@ -4401,77 +4346,16 @@ PresShell::ClearMouseCapture(nsIView* aV
 
   // disable mouse capture until the next mousedown as a dialog has opened
   // or a drag has started. Otherwise, someone could start capture during
   // the modal dialog or drag.
   gCaptureInfo.mAllowed = PR_FALSE;
 }
 
 NS_IMETHODIMP
-PresShell::DoGetContents(const nsACString& aMimeType, PRUint32 aFlags, PRBool aSelectionOnly, nsAString& aOutValue)
-{
-  aOutValue.Truncate();
-  
-  if (!mDocument) return NS_ERROR_FAILURE;
-
-  nsresult rv;
-  nsCOMPtr<nsISelection> sel;
-
-  // Now we have the selection.  Make sure it's nonzero:
-  if (aSelectionOnly)
-  {
-    rv = GetSelectionForCopy(getter_AddRefs(sel));
-    if (NS_FAILED(rv)) return rv;
-    if (!sel) return NS_ERROR_FAILURE;
-  
-    PRBool isCollapsed;
-    sel->GetIsCollapsed(&isCollapsed);
-    if (isCollapsed)
-      return NS_OK;
-  }
-  
-  // call the copy code
-  return nsCopySupport::GetContents(aMimeType, aFlags, sel,
-                                    mDocument, aOutValue);
-}
-
-NS_IMETHODIMP
-PresShell::DoCopy()
-{
-  if (!mDocument) return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsISelection> sel;
-  nsresult rv = GetSelectionForCopy(getter_AddRefs(sel));
-  if (NS_FAILED(rv)) 
-    return rv;
-  if (!sel) 
-    return NS_ERROR_FAILURE;
-
-  // Now we have the selection.  Make sure it's nonzero:
-  PRBool isCollapsed;
-  sel->GetIsCollapsed(&isCollapsed);
-  if (isCollapsed)
-    return NS_OK;
-
-  // call the copy code
-  rv = nsCopySupport::HTMLCopy(sel, mDocument, nsIClipboard::kGlobalClipboard);
-  if (NS_FAILED(rv))
-    return rv;
-
-  // Now that we have copied, update the Paste menu item
-  nsPIDOMWindow *domWindow = mDocument->GetWindow();
-  if (domWindow)
-  {
-    domWindow->UpdateCommands(NS_LITERAL_STRING("clipboard"));
-  }
-  
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 PresShell::CaptureHistoryState(nsILayoutHistoryState** aState, PRBool aLeavingPage)
 {
   nsresult rv = NS_OK;
 
   NS_PRECONDITION(nsnull != aState, "null state pointer");
 
   // We actually have to mess with the docshell here, since we want to
   // store the state back in it.