diff --git a/dom/base/nsCopySupport.cpp b/dom/base/nsCopySupport.cpp index 3f6db3928d..60a94d9884 100644 --- a/dom/base/nsCopySupport.cpp +++ b/dom/base/nsCopySupport.cpp @@ -38,6 +38,7 @@ #include "nsIFrame.h" #include "nsIURI.h" #include "nsISimpleEnumerator.h" +#include "nsIFormControl.h" // image copy stuff #include "nsIImageLoadingContent.h" @@ -583,8 +584,14 @@ nsCopySupport::CanCopy(nsIDocument* aDocument) } bool -nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPresShell* aPresShell, nsISelection* aSelection) +nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPresShell* aPresShell, + nsISelection* aSelection, bool* aActionTaken) { + // Keep track of action taken or not to pass up the chain. + if (aActionTaken) { + *aActionTaken = false; + } + NS_ASSERTION(aType == NS_CUT || aType == NS_COPY || aType == NS_PASTE, "Invalid clipboard event type"); @@ -609,14 +616,6 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres // retrieve the event target node from the start of the selection nsresult rv; if (sel) { - // Only cut or copy when there is an uncollapsed selection - if (aType == NS_CUT || aType == NS_COPY) { - bool isCollapsed; - sel->GetIsCollapsed(&isCollapsed); - if (isCollapsed) - return false; - } - nsCOMPtr range; rv = sel->GetRangeAt(0, getter_AddRefs(range)); if (NS_SUCCEEDED(rv) && range) { @@ -670,7 +669,9 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres clipboardData->ClearAll(); clipboardData->SetReadOnly(); } - + if (aActionTaken) { + *aActionTaken = true; + } return doDefault; } @@ -684,15 +685,38 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres // use the data added to the data transfer and copy that instead. uint32_t count = 0; if (doDefault) { - // get the data from the selection if any - bool isCollapsed; - sel->GetIsCollapsed(&isCollapsed); - if (isCollapsed) { - return false; + // find the focused node + nsCOMPtr srcNode = content; + if (content->IsInNativeAnonymousSubtree()) { + srcNode = content->FindFirstNonChromeOnlyAccessContent(); } - // call the copy code - rv = HTMLCopy(sel, doc, aClipboardType); - if (NS_FAILED(rv)) { + + // check if we are looking at a password input + nsCOMPtr formControl = do_QueryInterface(srcNode); + if (formControl) { + if (formControl->GetType() == NS_FORM_INPUT_PASSWORD) { + return false; + } + } + + // when cutting non-editable content, do nothing + // XXX this may be the wrong editable flag to check + if (aType != NS_CUT || content->IsEditable()) { + // get the data from the selection if any + bool isCollapsed; + sel->GetIsCollapsed(&isCollapsed); + if (isCollapsed) { + if (aActionTaken) { + *aActionTaken = true; + } + return false; + } + // call the copy code + rv = HTMLCopy(sel, doc, aClipboardType); + if (NS_FAILED(rv)) { + return false; + } + } else { return false; } } else if (clipboardData) { @@ -720,6 +744,9 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres if (doDefault || count) { piWindow->UpdateCommands(NS_LITERAL_STRING("clipboard"), nullptr, 0); } - + if (aActionTaken) { + *aActionTaken = true; + } + return doDefault; } diff --git a/dom/base/nsCopySupport.h b/dom/base/nsCopySupport.h index b8db3b4810..ef1eb0578e 100644 --- a/dom/base/nsCopySupport.h +++ b/dom/base/nsCopySupport.h @@ -82,12 +82,16 @@ class nsCopySupport * * aClipboardType specifies which clipboard to use, from nsIClipboard. * + * If aActionTaken is non-NULL, it will be set to true if an action was + * taken, whether it be the default action or the default being prevented. + * * If the event is cancelled or an error occurs, false will be returned. */ static bool FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPresShell* aPresShell, - nsISelection* aSelection); + nsISelection* aSelection, + bool* aActionTaken = nullptr); }; #endif diff --git a/dom/base/nsGlobalWindowCommands.cpp b/dom/base/nsGlobalWindowCommands.cpp index 1d210af9c7..743e1b8cba 100644 --- a/dom/base/nsGlobalWindowCommands.cpp +++ b/dom/base/nsGlobalWindowCommands.cpp @@ -508,7 +508,9 @@ nsClipboardCommand::IsCommandEnabled(const char* aCommandName, nsISupports *aCon nsresult nsClipboardCommand::DoCommand(const char *aCommandName, nsISupports *aContext) { - if (strcmp(aCommandName, "cmd_copy") && + // Careful: inverse logic. + if (strcmp(aCommandName, "cmd_cut") && + strcmp(aCommandName, "cmd_copy") && strcmp(aCommandName, "cmd_copyAndCollapseToEnd")) return NS_OK; @@ -521,7 +523,13 @@ nsClipboardCommand::DoCommand(const char *aCommandName, nsISupports *aContext) nsCOMPtr presShell = docShell->GetPresShell(); NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); - nsCopySupport::FireClipboardEvent(NS_COPY, nsIClipboard::kGlobalClipboard, presShell, nullptr); + int32_t eventType = NS_COPY; + if (strcmp(aCommandName, "cmd_cut") == 0) { + eventType = NS_CUT; + } + + bool actionTaken = false; + nsCopySupport::FireClipboardEvent(eventType, nsIClipboard::kGlobalClipboard, presShell, nullptr, &actionTaken); if (!strcmp(aCommandName, "cmd_copyAndCollapseToEnd")) { dom::Selection *sel = @@ -530,7 +538,10 @@ nsClipboardCommand::DoCommand(const char *aCommandName, nsISupports *aContext) sel->CollapseToEnd(); } - return NS_OK; + if (actionTaken) { + return NS_OK; + } + return NS_ERROR_FAILURE; } NS_IMETHODIMP diff --git a/dom/tests/mochitest/general/test_clipboard_events.html b/dom/tests/mochitest/general/test_clipboard_events.html index 5daa0d4f2a..eeae382cd5 100644 --- a/dom/tests/mochitest/general/test_clipboard_events.html +++ b/dom/tests/mochitest/general/test_clipboard_events.html @@ -150,7 +150,7 @@ function test_dom_oncut() { content.oncut = function() { oncut_fired = true; }; try { synthesizeKey("x", {accelKey: 1}); - ok(!oncut_fired, "cut event firing on DOM element") + ok(oncut_fired, "cut event firing on DOM element") is(getClipboardText(), clipboardInitialValue, "cut on DOM element did not modify clipboard"); } finally { diff --git a/editor/libeditor/nsPlaintextEditor.cpp b/editor/libeditor/nsPlaintextEditor.cpp index 4cfc35a904..a76d4634fd 100644 --- a/editor/libeditor/nsPlaintextEditor.cpp +++ b/editor/libeditor/nsPlaintextEditor.cpp @@ -1168,7 +1168,7 @@ nsPlaintextEditor::CanCutOrCopy(PasswordFieldAllowed aPasswordFieldAllowed) } bool -nsPlaintextEditor::FireClipboardEvent(int32_t aType, int32_t aSelectionType) +nsPlaintextEditor::FireClipboardEvent(int32_t aType, int32_t aSelectionType, bool* aActionTaken) { if (aType == NS_PASTE) ForceCompositionEnd(); @@ -1181,7 +1181,7 @@ nsPlaintextEditor::FireClipboardEvent(int32_t aType, int32_t aSelectionType) return false; } - if (!nsCopySupport::FireClipboardEvent(aType, aSelectionType, presShell, selection)) + if (!nsCopySupport::FireClipboardEvent(aType, aSelectionType, presShell, selection, aActionTaken)) return false; // If the event handler caused the editor to be destroyed, return false. @@ -1191,9 +1191,11 @@ nsPlaintextEditor::FireClipboardEvent(int32_t aType, int32_t aSelectionType) NS_IMETHODIMP nsPlaintextEditor::Cut() { - if (FireClipboardEvent(NS_CUT, nsIClipboard::kGlobalClipboard)) - return DeleteSelection(eNone, eStrip); - return NS_OK; + bool actionTaken = false; + if (FireClipboardEvent(NS_CUT, nsIClipboard::kGlobalClipboard, &actionTaken)) { + DeleteSelection(eNone, eStrip); + } + return actionTaken ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP nsPlaintextEditor::CanCut(bool *aCanCut) @@ -1208,8 +1210,10 @@ NS_IMETHODIMP nsPlaintextEditor::CanCut(bool *aCanCut) NS_IMETHODIMP nsPlaintextEditor::Copy() { - FireClipboardEvent(NS_COPY, nsIClipboard::kGlobalClipboard); - return NS_OK; + bool actionTaken = false; + FireClipboardEvent(NS_COPY, nsIClipboard::kGlobalClipboard, &actionTaken); + + return actionTaken ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP nsPlaintextEditor::CanCopy(bool *aCanCopy) diff --git a/editor/libeditor/nsPlaintextEditor.h b/editor/libeditor/nsPlaintextEditor.h index 8e5e9a8970..597b879221 100644 --- a/editor/libeditor/nsPlaintextEditor.h +++ b/editor/libeditor/nsPlaintextEditor.h @@ -209,7 +209,7 @@ protected: ePasswordFieldNotAllowed }; bool CanCutOrCopy(PasswordFieldAllowed aPasswordFieldAllowed); - bool FireClipboardEvent(int32_t aType, int32_t aSelectionType); + bool FireClipboardEvent(int32_t aType, int32_t aSelectionType, bool* aActionTaken = nullptr); bool UpdateMetaCharset(nsIDOMDocument* aDocument, const nsACString& aCharacterSet);