Bug 1918027 part 3 - share DataTransfer between clipboard event and calls to HandlePaste() r=edgar,dlp-reviewers,masayuki,handyman
This handles a race condition so if the user copies new data to the clipboard while Content Analysis is ongoing, the original data will be used in the paste action. Differential Revision: https://phabricator.services.mozilla.com/D228719
This commit is contained in:
@@ -1414,6 +1414,7 @@ Document::Document(const char* aContentType)
|
||||
mForceLoadAtTop(false),
|
||||
mFireMutationEvents(true),
|
||||
mHasPolicyWithRequireTrustedTypesForDirective(false),
|
||||
mClipboardCopyTriggered(false),
|
||||
mXMLDeclarationBits(0),
|
||||
mOnloadBlockCount(0),
|
||||
mWriteLevel(0),
|
||||
|
||||
@@ -3688,6 +3688,9 @@ class Document : public nsINode,
|
||||
mHasPolicyWithRequireTrustedTypesForDirective =
|
||||
aHasPolicyWithRequireTrustedTypesForDirective;
|
||||
}
|
||||
bool IsClipboardCopyTriggered() const { return mClipboardCopyTriggered; }
|
||||
void ClearClipboardCopyTriggered() { mClipboardCopyTriggered = false; }
|
||||
void SetClipboardCopyTriggered() { mClipboardCopyTriggered = true; }
|
||||
|
||||
// Even if mutation events are disabled by default,
|
||||
// dom.mutation_events.forceEnable can be used to enable them per site.
|
||||
@@ -4966,6 +4969,10 @@ class Document : public nsINode,
|
||||
// Whether the document's CSP contains a require-trusted-types-for directive.
|
||||
bool mHasPolicyWithRequireTrustedTypesForDirective : 1;
|
||||
|
||||
// Whether a copy event happened. Used to detect when this happens
|
||||
// while a paste event is being handled in JS.
|
||||
bool mClipboardCopyTriggered : 1;
|
||||
|
||||
Maybe<bool> mMutationEventsEnabled;
|
||||
|
||||
// The fingerprinting protections overrides for this document. The value will
|
||||
|
||||
@@ -758,7 +758,8 @@ class MOZ_RAII AutoHandlingPasteEvent final {
|
||||
bool nsCopySupport::FireClipboardEvent(
|
||||
EventMessage aEventMessage,
|
||||
mozilla::Maybe<nsIClipboard::ClipboardType> aClipboardType,
|
||||
PresShell* aPresShell, Selection* aSelection, bool* aActionTaken) {
|
||||
PresShell* aPresShell, Selection* aSelection, DataTransfer* aDataTransfer,
|
||||
bool* aActionTaken) {
|
||||
if (aActionTaken) {
|
||||
*aActionTaken = false;
|
||||
}
|
||||
@@ -825,9 +826,18 @@ bool nsCopySupport::FireClipboardEvent(
|
||||
bool doDefault = true;
|
||||
RefPtr<DataTransfer> clipboardData;
|
||||
if (chromeShell || StaticPrefs::dom_event_clipboardevents_enabled()) {
|
||||
clipboardData =
|
||||
new DataTransfer(doc->GetScopeObject(), aEventMessage,
|
||||
originalEventMessage == ePaste, aClipboardType);
|
||||
MOZ_ASSERT_IF(aDataTransfer,
|
||||
aDataTransfer->GetParentObject() == doc->GetScopeObject());
|
||||
MOZ_ASSERT_IF(aDataTransfer, (aDataTransfer->GetEventMessage() == ePaste) &&
|
||||
(aEventMessage == ePaste ||
|
||||
aEventMessage == ePasteNoFormatting));
|
||||
MOZ_ASSERT_IF(aDataTransfer,
|
||||
aDataTransfer->ClipboardType() == aClipboardType);
|
||||
clipboardData = aDataTransfer
|
||||
? RefPtr<DataTransfer>(aDataTransfer)
|
||||
: MakeRefPtr<DataTransfer>(
|
||||
doc->GetScopeObject(), aEventMessage,
|
||||
originalEventMessage == ePaste, aClipboardType);
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
InternalClipboardEvent evt(true, originalEventMessage);
|
||||
@@ -851,7 +861,7 @@ bool nsCopySupport::FireClipboardEvent(
|
||||
// our DataTransfer, which means setting its mode to `Protected` and clearing
|
||||
// all stored data, before we return.
|
||||
auto clearAfter = MakeScopeExit([&] {
|
||||
if (clipboardData) {
|
||||
if (clipboardData && !aDataTransfer) {
|
||||
clipboardData->Disconnect();
|
||||
|
||||
// NOTE: Disconnect may not actually clear the DataTransfer if the
|
||||
@@ -959,6 +969,10 @@ bool nsCopySupport::FireClipboardEvent(
|
||||
// the effect of updating the enabled state of the paste menu item.
|
||||
if (doDefault || count) {
|
||||
piWindow->UpdateCommands(u"clipboard"_ns);
|
||||
if (aPresShell && aPresShell->GetDocument()) {
|
||||
// Record that a copy to the clipboard was triggered by JS code
|
||||
aPresShell->GetDocument()->SetClipboardCopyTriggered();
|
||||
}
|
||||
}
|
||||
|
||||
if (aActionTaken) {
|
||||
|
||||
@@ -23,6 +23,7 @@ class nsILoadContext;
|
||||
namespace mozilla {
|
||||
class PresShell;
|
||||
namespace dom {
|
||||
class DataTransfer;
|
||||
class Document;
|
||||
class Selection;
|
||||
class WindowContext;
|
||||
@@ -104,6 +105,10 @@ class nsCopySupport {
|
||||
*
|
||||
* aClipboardType specifies which clipboard to use, from nsIClipboard.
|
||||
*
|
||||
* If aDataTransfer is non-NULL, that data will be used to fire the clipboard
|
||||
* event, and the caller is responsible for calling Disconnect(). (and
|
||||
* possibly ClearAll())
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
@@ -114,7 +119,7 @@ class nsCopySupport {
|
||||
mozilla::EventMessage aEventMessage,
|
||||
mozilla::Maybe<nsIClipboard::ClipboardType> aClipboardType,
|
||||
mozilla::PresShell* aPresShell, mozilla::dom::Selection* aSelection,
|
||||
bool* aActionTaken = nullptr);
|
||||
mozilla::dom::DataTransfer* aDataTransfer, bool* aActionTaken = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -578,7 +578,7 @@ nsresult nsClipboardCommand::DoCommand(const char* aCommandName,
|
||||
bool actionTaken = false;
|
||||
nsCopySupport::FireClipboardEvent(eventMessage,
|
||||
Some(nsIClipboard::kGlobalClipboard),
|
||||
presShell, nullptr, &actionTaken);
|
||||
presShell, nullptr, nullptr, &actionTaken);
|
||||
|
||||
return actionTaken ? NS_OK : NS_SUCCESS_DOM_NO_OPERATION;
|
||||
}
|
||||
|
||||
@@ -1668,4 +1668,21 @@ void DataTransfer::ClearForPaste() {
|
||||
ClearAll();
|
||||
}
|
||||
|
||||
bool DataTransfer::HasPrivateHTMLFlavor() const {
|
||||
MOZ_ASSERT(mEventMessage == ePaste,
|
||||
"Only works for ePaste messages, where the mClipboardDataSnapshot "
|
||||
"is available.");
|
||||
nsIClipboardDataSnapshot* snapshot = GetClipboardDataSnapshot();
|
||||
if (!snapshot) {
|
||||
NS_WARNING("DataTransfer::GetClipboardDataSnapshot() returned null");
|
||||
return false;
|
||||
}
|
||||
nsTArray<nsCString> snapshotFlavors;
|
||||
if (NS_FAILED(snapshot->GetFlavorList(snapshotFlavors))) {
|
||||
NS_WARNING("nsIClipboardDataSnapshot::GetFlavorList() failed");
|
||||
return false;
|
||||
}
|
||||
return snapshotFlavors.Contains(kHTMLContext);
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
||||
@@ -447,6 +447,8 @@ class DataTransfer final : public nsISupports, public nsWrapperCache {
|
||||
// Clears this DataTransfer that was used for paste
|
||||
void ClearForPaste();
|
||||
|
||||
bool HasPrivateHTMLFlavor() const;
|
||||
|
||||
protected:
|
||||
// Retrieve a list of clipboard formats supported
|
||||
//
|
||||
|
||||
@@ -6191,11 +6191,25 @@ nsresult EventStateManager::HandleMiddleClickPaste(
|
||||
clipboardType = nsIClipboard::kSelectionClipboard;
|
||||
}
|
||||
|
||||
RefPtr<DataTransfer> dataTransfer;
|
||||
if (aEditorBase) {
|
||||
// Create the same DataTransfer object here so we can share it between
|
||||
// the clipboard event and the call to HandlePaste below. This prevents
|
||||
// race conditions with Content Analysis on like we see in bug 1918027.
|
||||
dataTransfer =
|
||||
aEditorBase->CreateDataTransferForPaste(ePaste, clipboardType);
|
||||
}
|
||||
const auto clearDataTransfer = MakeScopeExit([&] {
|
||||
if (dataTransfer) {
|
||||
dataTransfer->ClearForPaste();
|
||||
}
|
||||
});
|
||||
|
||||
// Fire ePaste event by ourselves since we need to dispatch "paste" event
|
||||
// even if the middle click event was consumed for compatibility with
|
||||
// Chromium.
|
||||
if (!nsCopySupport::FireClipboardEvent(ePaste, Some(clipboardType),
|
||||
aPresShell, selection)) {
|
||||
aPresShell, selection, dataTransfer)) {
|
||||
*aStatus = nsEventStatus_eConsumeNoDefault;
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -6230,11 +6244,11 @@ nsresult EventStateManager::HandleMiddleClickPaste(
|
||||
// quotation. Otherwise, paste it as is.
|
||||
if (aMouseEvent->IsControl()) {
|
||||
DebugOnly<nsresult> rv = aEditorBase->PasteAsQuotationAsAction(
|
||||
clipboardType, EditorBase::DispatchPasteEvent::No);
|
||||
clipboardType, EditorBase::DispatchPasteEvent::No, dataTransfer);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste as quotation");
|
||||
} else {
|
||||
DebugOnly<nsresult> rv = aEditorBase->PasteAsAction(
|
||||
clipboardType, EditorBase::DispatchPasteEvent::No);
|
||||
clipboardType, EditorBase::DispatchPasteEvent::No, dataTransfer);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste");
|
||||
}
|
||||
*aStatus = nsEventStatus_eConsumeNoDefault;
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
#include "mozilla/dom/BorrowedAttrInfo.h" // for BorrowedAttrInfo
|
||||
#include "mozilla/dom/BrowsingContext.h" // for BrowsingContext
|
||||
#include "mozilla/dom/CharacterData.h" // for CharacterData
|
||||
#include "mozilla/dom/ContentParent.h" // for ContentParent
|
||||
#include "mozilla/dom/DataTransfer.h" // for DataTransfer
|
||||
#include "mozilla/dom/Document.h" // for Document
|
||||
#include "mozilla/dom/DocumentInlines.h" // for GetObservingPresShell
|
||||
@@ -1584,10 +1585,26 @@ bool EditorBase::CheckForClipboardCommandListener(
|
||||
return false;
|
||||
}
|
||||
|
||||
already_AddRefed<DataTransfer> EditorBase::CreateDataTransferForPaste(
|
||||
EventMessage aEventMessage,
|
||||
nsIClipboard::ClipboardType aClipboardType) const {
|
||||
nsIGlobalObject* scopeObject = nullptr;
|
||||
if (PresShell* presShell = GetPresShell()) {
|
||||
if (Document* doc = presShell->GetDocument()) {
|
||||
scopeObject = doc->GetScopeObject();
|
||||
}
|
||||
}
|
||||
|
||||
auto dataTransfer = MakeRefPtr<DataTransfer>(scopeObject, aEventMessage, true,
|
||||
Some(aClipboardType));
|
||||
return dataTransfer.forget();
|
||||
}
|
||||
|
||||
Result<EditorBase::ClipboardEventResult, nsresult>
|
||||
EditorBase::DispatchClipboardEventAndUpdateClipboard(
|
||||
EventMessage aEventMessage,
|
||||
Maybe<nsIClipboard::ClipboardType> aClipboardType) {
|
||||
Maybe<nsIClipboard::ClipboardType> aClipboardType,
|
||||
DataTransfer* aDataTransfer /* = nullptr */) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
|
||||
const bool isPasting =
|
||||
@@ -1617,7 +1634,8 @@ EditorBase::DispatchClipboardEventAndUpdateClipboard(
|
||||
|
||||
bool actionTaken = false;
|
||||
const bool doDefault = nsCopySupport::FireClipboardEvent(
|
||||
aEventMessage, aClipboardType, presShell, sel, &actionTaken);
|
||||
aEventMessage, aClipboardType, presShell, sel, aDataTransfer,
|
||||
&actionTaken);
|
||||
NotifyOfDispatchingClipboardEvent();
|
||||
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
@@ -1812,13 +1830,33 @@ NS_IMETHODIMP EditorBase::Paste(nsIClipboard::ClipboardType aClipboardType) {
|
||||
|
||||
nsresult EditorBase::PasteAsAction(nsIClipboard::ClipboardType aClipboardType,
|
||||
DispatchPasteEvent aDispatchPasteEvent,
|
||||
DataTransfer* aDataTransfer /* = nullptr */,
|
||||
nsIPrincipal* aPrincipal /* = nullptr */) {
|
||||
if (IsHTMLEditor() && IsReadonly()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Create the same DataTransfer object here so we can share it between
|
||||
// the clipboard event and the call to HandlePaste below. This prevents
|
||||
// race conditions with Content Analysis on like we see in bug 1918027.
|
||||
// Note that this is not needed if we're not going to dispatch the paste
|
||||
// event.
|
||||
RefPtr<DataTransfer> dataTransfer;
|
||||
if (aDispatchPasteEvent == DispatchPasteEvent::Yes) {
|
||||
dataTransfer = aDataTransfer
|
||||
? RefPtr<DataTransfer>(aDataTransfer)
|
||||
: RefPtr<DataTransfer>(CreateDataTransferForPaste(
|
||||
ePaste, aClipboardType));
|
||||
}
|
||||
AutoEditActionDataSetter editActionData(*this, EditAction::ePaste,
|
||||
aPrincipal);
|
||||
const auto clearDataTransfer = MakeScopeExit([&] {
|
||||
// If the caller passed in aDataTransfer, they are responsible for clearing
|
||||
// this.
|
||||
if (!aDataTransfer && dataTransfer) {
|
||||
dataTransfer->ClearForPaste();
|
||||
}
|
||||
});
|
||||
if (NS_WARN_IF(!editActionData.CanHandle())) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
@@ -1830,13 +1868,22 @@ nsresult EditorBase::PasteAsAction(nsIClipboard::ClipboardType aClipboardType,
|
||||
}
|
||||
const RefPtr<Element> focusedElement = focusManager->GetFocusedElement();
|
||||
|
||||
Result<ClipboardEventResult, nsresult> ret =
|
||||
DispatchClipboardEventAndUpdateClipboard(ePaste, Some(aClipboardType));
|
||||
if (MOZ_UNLIKELY(ret.isErr())) {
|
||||
NS_WARNING(
|
||||
"EditorBase::DispatchClipboardEventAndUpdateClipboard(ePaste) "
|
||||
"failed");
|
||||
return EditorBase::ToGenericNSResult(ret.unwrapErr());
|
||||
Result<ClipboardEventResult, nsresult> ret = Err(NS_ERROR_FAILURE);
|
||||
{
|
||||
// This method is not set up to pass back the new aDataTransfer
|
||||
// if it changes. If we need this in the future, we can change
|
||||
// aDataTransfer to be a RefPtr<DataTransfer>*.
|
||||
MOZ_ASSERT(!aDataTransfer);
|
||||
AutoTrackDataTransferForPaste trackDataTransfer(*this, dataTransfer);
|
||||
|
||||
ret = DispatchClipboardEventAndUpdateClipboard(
|
||||
ePaste, Some(aClipboardType), dataTransfer);
|
||||
if (MOZ_UNLIKELY(ret.isErr())) {
|
||||
NS_WARNING(
|
||||
"EditorBase::DispatchClipboardEventAndUpdateClipboard(ePaste) "
|
||||
"failed");
|
||||
return EditorBase::ToGenericNSResult(ret.unwrapErr());
|
||||
}
|
||||
}
|
||||
switch (ret.inspect()) {
|
||||
case ClipboardEventResult::DoDefault:
|
||||
@@ -1865,7 +1912,7 @@ nsresult EditorBase::PasteAsAction(nsIClipboard::ClipboardType aClipboardType,
|
||||
}
|
||||
if (editorBase != this) {
|
||||
nsresult rv = editorBase->PasteAsAction(
|
||||
aClipboardType, DispatchPasteEvent::No, aPrincipal);
|
||||
aClipboardType, DispatchPasteEvent::No, dataTransfer, aPrincipal);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::PasteAsAction(DispatchPasteEvent::No) failed");
|
||||
@@ -1876,8 +1923,7 @@ nsresult EditorBase::PasteAsAction(nsIClipboard::ClipboardType aClipboardType,
|
||||
// The caller must already have dispatched a "paste" event.
|
||||
editActionData.NotifyOfDispatchingClipboardEvent();
|
||||
}
|
||||
|
||||
nsresult rv = HandlePaste(editActionData, aClipboardType);
|
||||
nsresult rv = HandlePaste(editActionData, aClipboardType, dataTransfer);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EditorBase::HandlePaste() failed");
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
}
|
||||
@@ -1885,6 +1931,7 @@ nsresult EditorBase::PasteAsAction(nsIClipboard::ClipboardType aClipboardType,
|
||||
nsresult EditorBase::PasteAsQuotationAsAction(
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DispatchPasteEvent aDispatchPasteEvent,
|
||||
DataTransfer* aDataTransfer /* = nullptr */,
|
||||
nsIPrincipal* aPrincipal /* = nullptr */) {
|
||||
MOZ_ASSERT(aClipboardType == nsIClipboard::kGlobalClipboard ||
|
||||
aClipboardType == nsIClipboard::kSelectionClipboard);
|
||||
@@ -1893,6 +1940,26 @@ nsresult EditorBase::PasteAsQuotationAsAction(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Create the same DataTransfer object here so we can share it between
|
||||
// the clipboard event and the call to HandlePasteAsQuotation below. This
|
||||
// prevents race conditions with Content Analysis on like we see in bug
|
||||
// 1918027.
|
||||
// Note that this is not needed if we're not going to dispatch the paste
|
||||
// event.
|
||||
RefPtr<DataTransfer> dataTransfer;
|
||||
if (aDispatchPasteEvent == DispatchPasteEvent::Yes) {
|
||||
dataTransfer = aDataTransfer
|
||||
? RefPtr<DataTransfer>(aDataTransfer)
|
||||
: RefPtr<DataTransfer>(CreateDataTransferForPaste(
|
||||
ePaste, aClipboardType));
|
||||
}
|
||||
const auto clearDataTransfer = MakeScopeExit([&] {
|
||||
// If the caller passed in aDataTransfer, they are responsible for clearing
|
||||
// this.
|
||||
if (!aDataTransfer && dataTransfer) {
|
||||
dataTransfer->ClearForPaste();
|
||||
}
|
||||
});
|
||||
AutoEditActionDataSetter editActionData(*this, EditAction::ePasteAsQuotation,
|
||||
aPrincipal);
|
||||
if (NS_WARN_IF(!editActionData.CanHandle())) {
|
||||
@@ -1906,13 +1973,22 @@ nsresult EditorBase::PasteAsQuotationAsAction(
|
||||
}
|
||||
const RefPtr<Element> focusedElement = focusManager->GetFocusedElement();
|
||||
|
||||
Result<ClipboardEventResult, nsresult> ret =
|
||||
DispatchClipboardEventAndUpdateClipboard(ePaste, Some(aClipboardType));
|
||||
if (MOZ_UNLIKELY(ret.isErr())) {
|
||||
NS_WARNING(
|
||||
"EditorBase::DispatchClipboardEventAndUpdateClipboard(ePaste) "
|
||||
"failed");
|
||||
return EditorBase::ToGenericNSResult(ret.unwrapErr());
|
||||
Result<ClipboardEventResult, nsresult> ret = Err(NS_ERROR_FAILURE);
|
||||
{
|
||||
// This method is not set up to pass back the new aDataTransfer
|
||||
// if it changes. If we need this in the future, we can change
|
||||
// aDataTransfer to be a RefPtr<DataTransfer>*.
|
||||
MOZ_ASSERT(!aDataTransfer);
|
||||
AutoTrackDataTransferForPaste trackDataTransfer(*this, dataTransfer);
|
||||
|
||||
ret = DispatchClipboardEventAndUpdateClipboard(
|
||||
ePaste, Some(aClipboardType), dataTransfer);
|
||||
if (MOZ_UNLIKELY(ret.isErr())) {
|
||||
NS_WARNING(
|
||||
"EditorBase::DispatchClipboardEventAndUpdateClipboard(ePaste) "
|
||||
"failed");
|
||||
return EditorBase::ToGenericNSResult(ret.unwrapErr());
|
||||
}
|
||||
}
|
||||
switch (ret.inspect()) {
|
||||
case ClipboardEventResult::DoDefault:
|
||||
@@ -1941,7 +2017,7 @@ nsresult EditorBase::PasteAsQuotationAsAction(
|
||||
}
|
||||
if (editorBase != this) {
|
||||
nsresult rv = editorBase->PasteAsQuotationAsAction(
|
||||
aClipboardType, DispatchPasteEvent::No, aPrincipal);
|
||||
aClipboardType, DispatchPasteEvent::No, dataTransfer, aPrincipal);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::PasteAsQuotationAsAction("
|
||||
"DispatchPasteEvent::No) failed");
|
||||
@@ -1953,7 +2029,8 @@ nsresult EditorBase::PasteAsQuotationAsAction(
|
||||
editActionData.NotifyOfDispatchingClipboardEvent();
|
||||
}
|
||||
|
||||
nsresult rv = HandlePasteAsQuotation(editActionData, aClipboardType);
|
||||
nsresult rv =
|
||||
HandlePasteAsQuotation(editActionData, aClipboardType, dataTransfer);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::HandlePasteAsQuotation() failed");
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
@@ -6568,7 +6645,7 @@ void EditorBase::AutoEditActionDataSetter::InitializeDataTransfer(
|
||||
}
|
||||
|
||||
void EditorBase::AutoEditActionDataSetter::InitializeDataTransferWithClipboard(
|
||||
SettingDataTransfer aSettingDataTransfer,
|
||||
SettingDataTransfer aSettingDataTransfer, DataTransfer* aDataTransfer,
|
||||
nsIClipboard::ClipboardType aClipboardType) {
|
||||
MOZ_ASSERT(!HasTriedToDispatchBeforeInputEvent(),
|
||||
"It's too late to set dataTransfer since this may have already "
|
||||
@@ -6580,12 +6657,22 @@ void EditorBase::AutoEditActionDataSetter::InitializeDataTransferWithClipboard(
|
||||
// mDataTransfer will be used for eEditorInput event, but we can keep
|
||||
// using ePaste and ePasteNoFormatting here. If we need to use eEditorInput,
|
||||
// we need to create eEditorInputNoFormatting or something...
|
||||
mDataTransfer =
|
||||
new DataTransfer(scopeObject,
|
||||
aSettingDataTransfer == SettingDataTransfer::eWithFormat
|
||||
? ePaste
|
||||
: ePasteNoFormatting,
|
||||
true /* is external */, Some(aClipboardType));
|
||||
EventMessage message =
|
||||
(aSettingDataTransfer == SettingDataTransfer::eWithFormat)
|
||||
? ePaste
|
||||
: ePasteNoFormatting;
|
||||
if (aDataTransfer) {
|
||||
// The DataTransfer being passed in will be used in a paste event, which
|
||||
// means it will be cleared after that event is done firing. We don't want
|
||||
// that for "input" and "beforeinput" events, so make a copy of its data.
|
||||
aDataTransfer->Clone(scopeObject, message,
|
||||
/* aUserCancelled = */ false,
|
||||
/* aIsCrossDomainSubFrameDrop = */ false,
|
||||
getter_AddRefs(mDataTransfer));
|
||||
} else {
|
||||
mDataTransfer = MakeRefPtr<DataTransfer>(
|
||||
scopeObject, message, true /* is external */, Some(aClipboardType));
|
||||
}
|
||||
}
|
||||
|
||||
void EditorBase::AutoEditActionDataSetter::AppendTargetRange(
|
||||
@@ -7165,4 +7252,102 @@ void EditorBase::StopPreservingSelection() {
|
||||
SavedSelectionRef().RemoveAllRanges();
|
||||
}
|
||||
|
||||
nsresult EditorBase::GetDataFromDataTransferOrClipboard(
|
||||
DataTransfer* aDataTransfer, nsITransferable* aTransferable,
|
||||
nsIClipboard::ClipboardType aClipboardType) const {
|
||||
MOZ_ASSERT(aTransferable);
|
||||
if (aDataTransfer) {
|
||||
MOZ_ASSERT(aDataTransfer->ClipboardType() == Some(aClipboardType));
|
||||
nsresult rv = [aDataTransfer, aTransferable]() -> nsresult {
|
||||
nsIClipboardDataSnapshot* snapshot =
|
||||
aDataTransfer->GetClipboardDataSnapshot();
|
||||
MOZ_ASSERT(snapshot);
|
||||
bool snapshotIsValid = false;
|
||||
snapshot->GetValid(&snapshotIsValid);
|
||||
if (!snapshotIsValid) {
|
||||
NS_WARNING("DataTransfer::GetClipboardDataSnapshot() is not valid");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
AutoTArray<nsCString, 10> transferableFlavors;
|
||||
nsresult rv =
|
||||
aTransferable->FlavorsTransferableCanImport(transferableFlavors);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsITransferable::FlavorsTransferableCanImport() failed");
|
||||
return rv;
|
||||
}
|
||||
if (transferableFlavors.Length() == 1) {
|
||||
// avoid creating unneeded temporary transferables
|
||||
rv = snapshot->GetDataSync(aTransferable);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsIClipboardDataSnapshot::GetDataSync() failed");
|
||||
return rv;
|
||||
}
|
||||
AutoTArray<nsCString, 5> snapshotFlavors;
|
||||
rv = snapshot->GetFlavorList(snapshotFlavors);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsIClipboardDataSnapshot::GetFlavorList() failed");
|
||||
return rv;
|
||||
}
|
||||
for (const auto& transferableFlavor : transferableFlavors) {
|
||||
if (snapshotFlavors.Contains(transferableFlavor)) {
|
||||
AutoTArray<nsCString, 1> singleTypeArray{transferableFlavor};
|
||||
auto singleTransferableToCheck =
|
||||
ContentParent::CreateClipboardTransferable(singleTypeArray);
|
||||
if (singleTransferableToCheck.isErr()) {
|
||||
NS_WARNING("Failed to CreateClipboardTransferable()");
|
||||
return singleTransferableToCheck.unwrapErr();
|
||||
}
|
||||
nsCOMPtr<nsITransferable> singleTransferable =
|
||||
singleTransferableToCheck.unwrap();
|
||||
rv = snapshot->GetDataSync(singleTransferable);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsIClipboardDataSnapshot::GetDataSync() failed");
|
||||
return rv;
|
||||
}
|
||||
nsCOMPtr<nsISupports> data;
|
||||
rv = singleTransferable->GetTransferData(transferableFlavor.get(),
|
||||
getter_AddRefs(data));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsITransferable::GetTransferData() failed");
|
||||
return rv;
|
||||
}
|
||||
rv = aTransferable->SetTransferData(transferableFlavor.get(), data);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsITransferable::SetTransferData() failed");
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// Couldn't find any data so return an error so we try the fallback.
|
||||
return NS_ERROR_FAILURE;
|
||||
}();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return NS_OK;
|
||||
}
|
||||
// If this fails, the snapshot may have become invalidated. Fall back
|
||||
// to getting data from the clipboard.
|
||||
}
|
||||
|
||||
// Get Clipboard Service
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIClipboard> clipboard =
|
||||
do_GetService("@mozilla.org/widget/clipboard;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to get nsIClipboard service");
|
||||
return rv;
|
||||
}
|
||||
|
||||
auto* windowContext = GetDocument()->GetWindowContext();
|
||||
if (!windowContext) {
|
||||
NS_WARNING("No window context");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = clipboard->GetData(aTransferable, aClipboardType, windowContext);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsIClipboard::GetData() failed");
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -108,6 +108,7 @@ class EditorBase : public nsIEditor,
|
||||
* method to edit the DOM tree, you can make your new method public.
|
||||
****************************************************************************/
|
||||
|
||||
using DataTransfer = dom::DataTransfer;
|
||||
using Document = dom::Document;
|
||||
using Element = dom::Element;
|
||||
using InterlinePosition = dom::Selection::InterlinePosition;
|
||||
@@ -241,6 +242,14 @@ class EditorBase : public nsIEditor,
|
||||
return selection ? selection->GetAncestorLimiter() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a DataTransfer object that can be shared between the paste event
|
||||
* and pasting into a DOM element.
|
||||
*/
|
||||
already_AddRefed<DataTransfer> CreateDataTransferForPaste(
|
||||
EventMessage aEventMessage,
|
||||
nsIClipboard::ClipboardType aClipboardType) const;
|
||||
|
||||
/**
|
||||
* Fast non-refcounting editor root element accessor
|
||||
*/
|
||||
@@ -752,6 +761,9 @@ class EditorBase : public nsIEditor,
|
||||
* nsIClipboard::kSelectionClipboard.
|
||||
* @param aDispatchPasteEvent Yes if this should dispatch ePaste event
|
||||
* before pasting. Otherwise, No.
|
||||
* @param aDataTransfer The object containing the data to use for the
|
||||
* paste operation. May be nullptr, in which case
|
||||
* this will just get the data from the clipboard.
|
||||
* @param aPrincipal Set subject principal if it may be called by
|
||||
* JS. If set to nullptr, will be treated as
|
||||
* called by system.
|
||||
@@ -760,6 +772,7 @@ class EditorBase : public nsIEditor,
|
||||
MOZ_CAN_RUN_SCRIPT nsresult
|
||||
PasteAsAction(nsIClipboard::ClipboardType aClipboardType,
|
||||
DispatchPasteEvent aDispatchPasteEvent,
|
||||
DataTransfer* aDataTransfer = nullptr,
|
||||
nsIPrincipal* aPrincipal = nullptr);
|
||||
|
||||
/**
|
||||
@@ -787,6 +800,9 @@ class EditorBase : public nsIEditor,
|
||||
* nsIClipboard::kSelectionClipboard.
|
||||
* @param aDispatchPasteEvent Yes if this should dispatch ePaste event
|
||||
* before pasting. Otherwise, No.
|
||||
* @param aDataTransfer The object containing the data to use for the
|
||||
* paste operation. May be nullptr, in which case
|
||||
* this will just get the data from the clipboard.
|
||||
* @param aPrincipal Set subject principal if it may be called by
|
||||
* JS. If set to nullptr, will be treated as
|
||||
* called by system.
|
||||
@@ -794,6 +810,7 @@ class EditorBase : public nsIEditor,
|
||||
MOZ_CAN_RUN_SCRIPT nsresult
|
||||
PasteAsQuotationAsAction(nsIClipboard::ClipboardType aClipboardType,
|
||||
DispatchPasteEvent aDispatchPasteEvent,
|
||||
DataTransfer* aDataTransfer = nullptr,
|
||||
nsIPrincipal* aPrincipal = nullptr);
|
||||
|
||||
/**
|
||||
@@ -1151,7 +1168,7 @@ class EditorBase : public nsIEditor,
|
||||
* because it'll be set to InputEvent.dataTransfer and which should be
|
||||
* read-only.
|
||||
*/
|
||||
void InitializeDataTransfer(dom::DataTransfer* aDataTransfer);
|
||||
void InitializeDataTransfer(DataTransfer* aDataTransfer);
|
||||
/**
|
||||
* InitializeDataTransfer(nsITransferable*) creates new DataTransfer
|
||||
* instance, initializes it with aTransferable and sets mDataTransfer to
|
||||
@@ -1168,9 +1185,9 @@ class EditorBase : public nsIEditor,
|
||||
* initializes it with clipboard and sets mDataTransfer to it.
|
||||
*/
|
||||
void InitializeDataTransferWithClipboard(
|
||||
SettingDataTransfer aSettingDataTransfer,
|
||||
SettingDataTransfer aSettingDataTransfer, DataTransfer* aDataTransfer,
|
||||
nsIClipboard::ClipboardType aClipboardType);
|
||||
dom::DataTransfer* GetDataTransfer() const { return mDataTransfer; }
|
||||
DataTransfer* GetDataTransfer() const { return mDataTransfer; }
|
||||
|
||||
/**
|
||||
* AppendTargetRange() appends aTargetRange to target ranges. This should
|
||||
@@ -1420,7 +1437,7 @@ class EditorBase : public nsIEditor,
|
||||
nsString mData;
|
||||
|
||||
// The dataTransfer should be set to InputEvent.dataTransfer.
|
||||
RefPtr<dom::DataTransfer> mDataTransfer;
|
||||
RefPtr<DataTransfer> mDataTransfer;
|
||||
|
||||
// They are used for result of InputEvent.getTargetRanges() of beforeinput.
|
||||
OwningNonNullStaticRangeArray mTargetRanges;
|
||||
@@ -1541,6 +1558,10 @@ class EditorBase : public nsIEditor,
|
||||
return mEditActionData->IsAborted();
|
||||
}
|
||||
|
||||
nsresult GetDataFromDataTransferOrClipboard(
|
||||
DataTransfer* aDataTransfer, nsITransferable* aTransferable,
|
||||
nsIClipboard::ClipboardType aClipboardType) const;
|
||||
|
||||
/**
|
||||
* SelectionRef() returns cached normal Selection. This is pretty faster than
|
||||
* EditorBase::GetSelection() if available.
|
||||
@@ -1582,7 +1603,7 @@ class EditorBase : public nsIEditor,
|
||||
* content with current edit action. The result is proper for
|
||||
* InputEvent.dataTransfer value.
|
||||
*/
|
||||
dom::DataTransfer* GetInputEventDataTransfer() const {
|
||||
DataTransfer* GetInputEventDataTransfer() const {
|
||||
return mEditActionData ? mEditActionData->GetDataTransfer() : nullptr;
|
||||
}
|
||||
|
||||
@@ -2558,7 +2579,7 @@ class EditorBase : public nsIEditor,
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult
|
||||
InsertDroppedDataTransferAsAction(AutoEditActionDataSetter& aEditActionData,
|
||||
dom::DataTransfer& aDataTransfer,
|
||||
DataTransfer& aDataTransfer,
|
||||
const EditorDOMPoint& aDroppedAt,
|
||||
nsIPrincipal* aSourcePrincipal) = 0;
|
||||
|
||||
@@ -2718,7 +2739,8 @@ class EditorBase : public nsIEditor,
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<ClipboardEventResult, nsresult>
|
||||
DispatchClipboardEventAndUpdateClipboard(
|
||||
EventMessage aEventMessage,
|
||||
mozilla::Maybe<nsIClipboard::ClipboardType> aClipboardType);
|
||||
mozilla::Maybe<nsIClipboard::ClipboardType> aClipboardType,
|
||||
DataTransfer* aDataTransfer = nullptr);
|
||||
|
||||
/**
|
||||
* Called after PasteAsAction() dispatches "paste" event and it's not
|
||||
@@ -2726,7 +2748,8 @@ class EditorBase : public nsIEditor,
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult HandlePaste(
|
||||
AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType) = 0;
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) = 0;
|
||||
|
||||
/**
|
||||
* Called after PasteAsQuotationAsAction() dispatches "paste" event and it's
|
||||
@@ -2734,11 +2757,12 @@ class EditorBase : public nsIEditor,
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult HandlePasteAsQuotation(
|
||||
AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType) = 0;
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) = 0;
|
||||
|
||||
/**
|
||||
* Called after PasteTransferableAsAction() dispatches "paste" event and it's
|
||||
* not canceled.
|
||||
* Called after PasteTransferableAsAction() dispatches "paste" event and
|
||||
* it's not canceled.
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult HandlePasteTransferable(
|
||||
AutoEditActionDataSetter& aEditActionData,
|
||||
@@ -2759,17 +2783,17 @@ class EditorBase : public nsIEditor,
|
||||
|
||||
protected: // helper classes which may be used by friends
|
||||
/**
|
||||
* Stack based helper class for batching a collection of transactions inside
|
||||
* a placeholder transaction. Different from AutoTransactionBatch, this
|
||||
* notifies editor observers of before/end edit action handling, and
|
||||
* Stack based helper class for batching a collection of transactions
|
||||
* inside a placeholder transaction. Different from AutoTransactionBatch,
|
||||
* this notifies editor observers of before/end edit action handling, and
|
||||
* dispatches "input" event if it's necessary.
|
||||
*/
|
||||
class MOZ_RAII AutoPlaceholderBatch final {
|
||||
public:
|
||||
/**
|
||||
* @param aRequesterFuncName function name which wants to end the batch.
|
||||
* This won't be stored nor exposed to selection listeners etc, used only
|
||||
* for logging. This MUST be alive when the destructor runs.
|
||||
* This won't be stored nor exposed to selection listeners etc, used
|
||||
* only for logging. This MUST be alive when the destructor runs.
|
||||
*/
|
||||
AutoPlaceholderBatch(EditorBase& aEditorBase,
|
||||
ScrollSelectionIntoView aScrollSelectionIntoView,
|
||||
@@ -2813,8 +2837,10 @@ class EditorBase : public nsIEditor,
|
||||
EditorBase& aEditorBase, EditSubAction aEditSubAction,
|
||||
nsIEditor::EDirection aDirection, ErrorResult& aRv)
|
||||
: mEditorBase(aEditorBase), mIsTopLevel(true) {
|
||||
// The top level edit sub action has already be set if this is nested call
|
||||
// XXX Looks like that this is not aware of unexpected nested edit action
|
||||
// The top level edit sub action has already be set if this is nested
|
||||
// call
|
||||
// XXX Looks like that this is not aware of unexpected nested edit
|
||||
// action
|
||||
// handling via selectionchange event listener or mutation event
|
||||
// listener.
|
||||
if (!mEditorBase.GetTopLevelEditSubAction()) {
|
||||
@@ -2869,8 +2895,8 @@ class EditorBase : public nsIEditor,
|
||||
public:
|
||||
/**
|
||||
* @param aRequesterFuncName function name which wants to end the batch.
|
||||
* This won't be stored nor exposed to selection listeners etc, used only
|
||||
* for logging. This MUST be alive when the destructor runs.
|
||||
* This won't be stored nor exposed to selection listeners etc, used
|
||||
* only for logging. This MUST be alive when the destructor runs.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT explicit AutoUpdateViewBatch(
|
||||
EditorBase& aEditorBase, const char* aRequesterFuncName)
|
||||
@@ -2925,8 +2951,8 @@ class EditorBase : public nsIEditor,
|
||||
mutable nsString mCachedDocumentEncoderType;
|
||||
|
||||
// Listens to all low level actions on the doc.
|
||||
// Edit action listener is currently used by highlighter of the findbar and
|
||||
// the spellchecker. So, we should reserve only 2 items.
|
||||
// Edit action listener is currently used by highlighter of the findbar
|
||||
// and the spellchecker. So, we should reserve only 2 items.
|
||||
using AutoActionListenerArray =
|
||||
AutoTArray<OwningNonNull<nsIEditActionListener>, 2>;
|
||||
AutoActionListenerArray mActionListeners;
|
||||
@@ -2981,9 +3007,10 @@ class EditorBase : public nsIEditor,
|
||||
friend class AutoSelectionRestorer; // RangeUpdaterRef, SavedSelectionRef
|
||||
friend class CaretPoint; // AllowsTransactionsToChangeSelection,
|
||||
// CollapseSelectionTo
|
||||
friend class CompositionTransaction; // CollapseSelectionTo, DoDeleteText,
|
||||
// DoInsertText, DoReplaceText,
|
||||
// HideCaret, RangeupdaterRef
|
||||
friend class CompositionTransaction; // CollapseSelectionTo,
|
||||
// DoDeleteText, DoInsertText,
|
||||
// DoReplaceText, HideCaret,
|
||||
// RangeupdaterRef
|
||||
friend class DeleteNodeTransaction; // RangeUpdaterRef
|
||||
friend class DeleteRangeTransaction; // AllowsTransactionsToChangeSelection,
|
||||
// CollapseSelectionTo
|
||||
|
||||
@@ -468,7 +468,7 @@ nsresult PasteCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
|
||||
nsIPrincipal* aPrincipal) const {
|
||||
nsresult rv = aEditorBase.PasteAsAction(nsIClipboard::kGlobalClipboard,
|
||||
EditorBase::DispatchPasteEvent::Yes,
|
||||
aPrincipal);
|
||||
nullptr, aPrincipal);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::PasteAsAction(nsIClipboard::"
|
||||
"kGlobalClipboard, DispatchPasteEvent::Yes) failed");
|
||||
@@ -963,7 +963,7 @@ nsresult PasteQuotationCommand::DoCommand(Command aCommand,
|
||||
nsIPrincipal* aPrincipal) const {
|
||||
nsresult rv = aEditorBase.PasteAsQuotationAsAction(
|
||||
nsIClipboard::kGlobalClipboard, EditorBase::DispatchPasteEvent::Yes,
|
||||
aPrincipal);
|
||||
nullptr, aPrincipal);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::PasteAsQuotationAsAction(nsIClipboard::"
|
||||
"kGlobalClipboard, DispatchPasteEvent::Yes) failed");
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "mozilla/IntegerRange.h" // for IntegerRange
|
||||
#include "mozilla/Maybe.h" // for Maybe
|
||||
#include "mozilla/Result.h" // for Result<>
|
||||
#include "mozilla/dom/DataTransfer.h" // for dom::DataTransfer
|
||||
#include "mozilla/dom/Element.h" // for dom::Element
|
||||
#include "mozilla/dom/HTMLBRElement.h" // for dom::HTMLBRElement
|
||||
#include "mozilla/dom/Selection.h" // for dom::Selection
|
||||
@@ -343,6 +344,43 @@ class MOZ_STACK_CLASS AutoSelectionRangeArray final {
|
||||
AutoTArray<mozilla::OwningNonNull<nsRange>, 8> mRanges;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* AutoTrackDataTransferForPaste keeps track of whether the paste event handler
|
||||
* in JS has modified the clipboard.
|
||||
*****************************************************************************/
|
||||
class MOZ_STACK_CLASS AutoTrackDataTransferForPaste {
|
||||
public:
|
||||
MOZ_CAN_RUN_SCRIPT AutoTrackDataTransferForPaste(
|
||||
const EditorBase& aEditorBase,
|
||||
RefPtr<dom::DataTransfer>& aDataTransferForPaste)
|
||||
: mEditorBase(aEditorBase),
|
||||
mDataTransferForPaste(aDataTransferForPaste.get_address()) {
|
||||
mEditorBase.GetDocument()->ClearClipboardCopyTriggered();
|
||||
}
|
||||
|
||||
~AutoTrackDataTransferForPaste() { FlushAndStopTracking(); }
|
||||
|
||||
private:
|
||||
void FlushAndStopTracking() {
|
||||
if (!mDataTransferForPaste ||
|
||||
!mEditorBase.GetDocument()->IsClipboardCopyTriggered()) {
|
||||
return;
|
||||
}
|
||||
// The paste event copied new data to the clipboard, so we need to use
|
||||
// that data to paste into the DOM element below.
|
||||
if (*mDataTransferForPaste) {
|
||||
(*mDataTransferForPaste)->ClearForPaste();
|
||||
}
|
||||
// Just null this out so this data won't be used and we will get it directly
|
||||
// from the clipboard in the future.
|
||||
*mDataTransferForPaste = nullptr;
|
||||
mDataTransferForPaste = nullptr;
|
||||
}
|
||||
|
||||
MOZ_KNOWN_LIVE const EditorBase& mEditorBase;
|
||||
RefPtr<dom::DataTransfer>* mDataTransferForPaste;
|
||||
};
|
||||
|
||||
class EditorUtils final {
|
||||
public:
|
||||
using EditorType = EditorBase::EditorType;
|
||||
|
||||
@@ -241,6 +241,9 @@ class HTMLEditor final : public EditorBase,
|
||||
* nsIClipboard::kSelectionClipboard.
|
||||
* @param aDispatchPasteEvent Yes if this should dispatch ePaste event
|
||||
* before pasting. Otherwise, No.
|
||||
* @param aDataTransfer The object containing the data to use for the
|
||||
* paste operation. May be nullptr, in which case
|
||||
* this will just get the data from the clipboard.
|
||||
* @param aPrincipal Set subject principal if it may be called by
|
||||
* JS. If set to nullptr, will be treated as
|
||||
* called by system.
|
||||
@@ -248,6 +251,7 @@ class HTMLEditor final : public EditorBase,
|
||||
MOZ_CAN_RUN_SCRIPT nsresult
|
||||
PasteNoFormattingAsAction(nsIClipboard::ClipboardType aClipboardType,
|
||||
DispatchPasteEvent aDispatchPasteEvent,
|
||||
DataTransfer* aDataTransfer = nullptr,
|
||||
nsIPrincipal* aPrincipal = nullptr);
|
||||
|
||||
bool CanPasteTransferable(nsITransferable* aTransferable) final;
|
||||
@@ -1096,9 +1100,8 @@ class HTMLEditor final : public EditorBase,
|
||||
SelectionHandling aSelectionHandling) final;
|
||||
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertDroppedDataTransferAsAction(
|
||||
AutoEditActionDataSetter& aEditActionData,
|
||||
dom::DataTransfer& aDataTransfer, const EditorDOMPoint& aDroppedAt,
|
||||
nsIPrincipal* aSourcePrincipal) final;
|
||||
AutoEditActionDataSetter& aEditActionData, DataTransfer& aDataTransfer,
|
||||
const EditorDOMPoint& aDroppedAt, nsIPrincipal* aSourcePrincipal) final;
|
||||
|
||||
/**
|
||||
* GetInlineStyles() retrieves the style of aElement and modifies each item of
|
||||
@@ -3135,10 +3138,12 @@ class HTMLEditor final : public EditorBase,
|
||||
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
HandlePaste(AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType) final;
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) final;
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
HandlePasteAsQuotation(AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType) final;
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) final;
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
HandlePasteTransferable(AutoEditActionDataSetter& aEditActionData,
|
||||
nsITransferable& aTransferable) final;
|
||||
@@ -3152,8 +3157,9 @@ class HTMLEditor final : public EditorBase,
|
||||
* nsIClipboard::kSelectionClipboard.
|
||||
* @param aEditingHost The editing host.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT nsresult PasteInternal(
|
||||
nsIClipboard::ClipboardType aClipboardType, const Element& aEditingHost);
|
||||
MOZ_CAN_RUN_SCRIPT nsresult
|
||||
PasteInternal(nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer, const Element& aEditingHost);
|
||||
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
InsertWithQuotationsAsSubAction(const nsAString& aQuotedText) final;
|
||||
@@ -3433,7 +3439,7 @@ class HTMLEditor final : public EditorBase,
|
||||
RefPtr<dom::BlobImpl> mBlob;
|
||||
RefPtr<HTMLEditor> mHTMLEditor;
|
||||
RefPtr<const Element> mEditingHost;
|
||||
RefPtr<dom::DataTransfer> mDataTransfer;
|
||||
RefPtr<DataTransfer> mDataTransfer;
|
||||
EditorDOMPoint mPointToInsert;
|
||||
EditAction mEditAction;
|
||||
SafeToInsertData mSafeToInsertData;
|
||||
@@ -3735,7 +3741,8 @@ class HTMLEditor final : public EditorBase,
|
||||
|
||||
// Methods for handling plaintext quotations
|
||||
MOZ_CAN_RUN_SCRIPT nsresult PasteAsPlaintextQuotation(
|
||||
nsIClipboard::ClipboardType aSelectionType, const Element& aEditingHost);
|
||||
nsIClipboard::ClipboardType aSelectionType, DataTransfer* aDataTransfer,
|
||||
const Element& aEditingHost);
|
||||
|
||||
enum class AddCites { No, Yes };
|
||||
/**
|
||||
@@ -3781,13 +3788,13 @@ class HTMLEditor final : public EditorBase,
|
||||
* @param aIndex index of aDataTransfer's item to insert.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT nsresult InsertFromDataTransfer(
|
||||
const dom::DataTransfer* aDataTransfer, uint32_t aIndex,
|
||||
const DataTransfer* aDataTransfer, uint32_t aIndex,
|
||||
nsIPrincipal* aSourcePrincipal, const EditorDOMPoint& aDroppedAt,
|
||||
DeleteSelectedContent aDeleteSelectedContent,
|
||||
const Element& aEditingHost);
|
||||
|
||||
static HavePrivateHTMLFlavor ClipboardHasPrivateHTMLFlavor(
|
||||
nsIClipboard* clipboard);
|
||||
static HavePrivateHTMLFlavor DataTransferOrClipboardHasPrivateHTMLFlavor(
|
||||
DataTransfer* aDataTransfer, nsIClipboard* clipboard);
|
||||
|
||||
/**
|
||||
* CF_HTML:
|
||||
|
||||
@@ -127,10 +127,11 @@ nsresult PasteNoFormattingCommand::DoCommand(Command aCommand,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Known live because we hold a ref above in "editor"
|
||||
nsresult rv = MOZ_KnownLive(htmlEditor)
|
||||
->PasteNoFormattingAsAction(
|
||||
nsIClipboard::kGlobalClipboard,
|
||||
EditorBase::DispatchPasteEvent::Yes, aPrincipal);
|
||||
nsresult rv =
|
||||
MOZ_KnownLive(htmlEditor)
|
||||
->PasteNoFormattingAsAction(nsIClipboard::kGlobalClipboard,
|
||||
EditorBase::DispatchPasteEvent::Yes,
|
||||
nullptr, aPrincipal);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"HTMLEditor::PasteNoFormattingAsAction(DispatchPasteEvent::Yes) failed");
|
||||
|
||||
@@ -1486,6 +1486,8 @@ void HTMLEditor::HTMLTransferablePreparer::AddDataFlavorsInBestOrder(
|
||||
// Create the desired DataFlavor for the type of data
|
||||
// we want to get out of the transferable
|
||||
// This should only happen in html editors, not plaintext
|
||||
// Note that if you add more flavors here you will need to add them
|
||||
// to DataTransfer::GetExternalClipboardFormats as well.
|
||||
if (!mHTMLEditor.IsPlaintextMailComposer() &&
|
||||
!(mEditingHost && mEditingHost->IsContentEditablePlainTextOnly())) {
|
||||
DebugOnly<nsresult> rvIgnored =
|
||||
@@ -2346,8 +2348,15 @@ nsresult HTMLEditor::InsertFromDataTransfer(
|
||||
}
|
||||
|
||||
// static
|
||||
HTMLEditor::HavePrivateHTMLFlavor HTMLEditor::ClipboardHasPrivateHTMLFlavor(
|
||||
nsIClipboard* aClipboard) {
|
||||
HTMLEditor::HavePrivateHTMLFlavor
|
||||
HTMLEditor::DataTransferOrClipboardHasPrivateHTMLFlavor(
|
||||
DataTransfer* aDataTransfer, nsIClipboard* aClipboard) {
|
||||
nsresult rv;
|
||||
if (aDataTransfer) {
|
||||
return aDataTransfer->HasPrivateHTMLFlavor() ? HavePrivateHTMLFlavor::Yes
|
||||
: HavePrivateHTMLFlavor::No;
|
||||
}
|
||||
// otherwise, fall back to clipboard
|
||||
if (NS_WARN_IF(!aClipboard)) {
|
||||
return HavePrivateHTMLFlavor::No;
|
||||
}
|
||||
@@ -2356,7 +2365,7 @@ HTMLEditor::HavePrivateHTMLFlavor HTMLEditor::ClipboardHasPrivateHTMLFlavor(
|
||||
// we know we have our own internal html format on clipboard.
|
||||
bool hasPrivateHTMLFlavor = false;
|
||||
AutoTArray<nsCString, 1> flavArray = {nsDependentCString(kHTMLContext)};
|
||||
nsresult rv = aClipboard->HasDataMatchingFlavors(
|
||||
rv = aClipboard->HasDataMatchingFlavors(
|
||||
flavArray, nsIClipboard::kGlobalClipboard, &hasPrivateHTMLFlavor);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsIClipboard::HasDataMatchingFlavors(nsIClipboard::"
|
||||
@@ -2366,9 +2375,10 @@ HTMLEditor::HavePrivateHTMLFlavor HTMLEditor::ClipboardHasPrivateHTMLFlavor(
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::HandlePaste(AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType) {
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) {
|
||||
aEditActionData.InitializeDataTransferWithClipboard(
|
||||
SettingDataTransfer::eWithFormat, aClipboardType);
|
||||
SettingDataTransfer::eWithFormat, aDataTransfer, aClipboardType);
|
||||
nsresult rv = aEditActionData.CanHandleAndMaybeDispatchBeforeInputEvent();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING_ASSERTION(rv == NS_ERROR_EDITOR_ACTION_CANCELED,
|
||||
@@ -2380,12 +2390,13 @@ nsresult HTMLEditor::HandlePaste(AutoEditActionDataSetter& aEditActionData,
|
||||
if (NS_WARN_IF(!editingHost)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = PasteInternal(aClipboardType, *editingHost);
|
||||
rv = PasteInternal(aClipboardType, aDataTransfer, *editingHost);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::PasteInternal() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::PasteInternal(nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer,
|
||||
const Element& aEditingHost) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
|
||||
@@ -2414,14 +2425,10 @@ nsresult HTMLEditor::PasteInternal(nsIClipboard::ClipboardType aClipboardType,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Get the Data from the clipboard
|
||||
auto* windowContext = GetDocument()->GetWindowContext();
|
||||
if (!windowContext) {
|
||||
NS_WARNING("No window context");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = clipboard->GetData(transferable, aClipboardType, windowContext);
|
||||
rv = GetDataFromDataTransferOrClipboard(aDataTransfer, transferable,
|
||||
aClipboardType);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsIClipboard::GetData() failed");
|
||||
NS_WARNING("EditorBase::GetDataFromDataTransferOrClipboard() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -2431,7 +2438,7 @@ nsresult HTMLEditor::PasteInternal(nsIClipboard::ClipboardType aClipboardType,
|
||||
// If we have our internal html flavor on the clipboard, there is special
|
||||
// context to use instead of cfhtml context.
|
||||
const HavePrivateHTMLFlavor clipboardHasPrivateHTMLFlavor =
|
||||
ClipboardHasPrivateHTMLFlavor(clipboard);
|
||||
DataTransferOrClipboardHasPrivateHTMLFlavor(aDataTransfer, clipboard);
|
||||
if (clipboardHasPrivateHTMLFlavor == HavePrivateHTMLFlavor::Yes) {
|
||||
nsCOMPtr<nsITransferable> contextTransferable =
|
||||
do_CreateInstance("@mozilla.org/widget/transferable;1");
|
||||
@@ -2448,10 +2455,8 @@ nsresult HTMLEditor::PasteInternal(nsIClipboard::ClipboardType aClipboardType,
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rvIgnored),
|
||||
"nsITransferable::AddDataFlavor(kHTMLContext) failed, but ignored");
|
||||
rvIgnored =
|
||||
clipboard->GetData(contextTransferable, aClipboardType, windowContext);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"nsIClipboard::GetData() failed, but ignored");
|
||||
GetDataFromDataTransferOrClipboard(aDataTransfer, contextTransferable,
|
||||
aClipboardType);
|
||||
nsCOMPtr<nsISupports> contextDataObj;
|
||||
rv = contextTransferable->GetTransferData(kHTMLContext,
|
||||
getter_AddRefs(contextDataObj));
|
||||
@@ -2480,10 +2485,8 @@ nsresult HTMLEditor::PasteInternal(nsIClipboard::ClipboardType aClipboardType,
|
||||
NS_SUCCEEDED(rvIgnored),
|
||||
"nsITransferable::AddDataFlavor(kHTMLInfo) failed, but ignored");
|
||||
|
||||
rvIgnored =
|
||||
clipboard->GetData(infoTransferable, aClipboardType, windowContext);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"nsIClipboard::GetData() failed, but ignored");
|
||||
GetDataFromDataTransferOrClipboard(aDataTransfer, infoTransferable,
|
||||
aClipboardType);
|
||||
nsCOMPtr<nsISupports> infoDataObj;
|
||||
rv = infoTransferable->GetTransferData(kHTMLInfo,
|
||||
getter_AddRefs(infoDataObj));
|
||||
@@ -2551,10 +2554,28 @@ nsresult HTMLEditor::HandlePasteTransferable(
|
||||
|
||||
nsresult HTMLEditor::PasteNoFormattingAsAction(
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DispatchPasteEvent aDispatchPasteEvent, nsIPrincipal* aPrincipal) {
|
||||
DispatchPasteEvent aDispatchPasteEvent,
|
||||
DataTransfer* aDataTransfer /* = nullptr */,
|
||||
nsIPrincipal* aPrincipal /* = nullptr */) {
|
||||
if (IsReadonly()) {
|
||||
return NS_OK;
|
||||
}
|
||||
// Create the same DataTransfer object here so we can share it between
|
||||
// the clipboard event and its data with the call to
|
||||
// InsertFromTransferableWithSelection below. This prevents
|
||||
// race conditions with Content Analysis on like we see in bug 1918027.
|
||||
RefPtr<DataTransfer> dataTransfer =
|
||||
aDataTransfer ? RefPtr<DataTransfer>(aDataTransfer)
|
||||
: RefPtr<DataTransfer>(CreateDataTransferForPaste(
|
||||
ePasteNoFormatting, aClipboardType));
|
||||
|
||||
auto clearDataTransfer = MakeScopeExit([&] {
|
||||
// If the caller passed in aDataTransfer, they are responsible for clearing
|
||||
// this.
|
||||
if (!aDataTransfer && dataTransfer) {
|
||||
dataTransfer->ClearForPaste();
|
||||
}
|
||||
});
|
||||
|
||||
AutoEditActionDataSetter editActionData(*this, EditAction::ePaste,
|
||||
aPrincipal);
|
||||
@@ -2562,7 +2583,7 @@ nsresult HTMLEditor::PasteNoFormattingAsAction(
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
editActionData.InitializeDataTransferWithClipboard(
|
||||
SettingDataTransfer::eWithoutFormat, aClipboardType);
|
||||
SettingDataTransfer::eWithoutFormat, dataTransfer, aClipboardType);
|
||||
|
||||
if (aDispatchPasteEvent == DispatchPasteEvent::Yes) {
|
||||
RefPtr<nsFocusManager> focusManager = nsFocusManager::GetFocusManager();
|
||||
@@ -2571,14 +2592,22 @@ nsresult HTMLEditor::PasteNoFormattingAsAction(
|
||||
}
|
||||
const RefPtr<Element> focusedElement = focusManager->GetFocusedElement();
|
||||
|
||||
Result<ClipboardEventResult, nsresult> ret =
|
||||
DispatchClipboardEventAndUpdateClipboard(ePasteNoFormatting,
|
||||
Some(aClipboardType));
|
||||
if (MOZ_UNLIKELY(ret.isErr())) {
|
||||
NS_WARNING(
|
||||
"EditorBase::DispatchClipboardEventAndUpdateClipboard("
|
||||
"ePasteNoFormatting) failed");
|
||||
return EditorBase::ToGenericNSResult(ret.unwrapErr());
|
||||
Result<ClipboardEventResult, nsresult> ret = Err(NS_ERROR_FAILURE);
|
||||
{
|
||||
// This method is not set up to pass back the new aDataTransfer
|
||||
// if it changes. If we need this in the future, we can change
|
||||
// aDataTransfer to be a RefPtr<DataTransfer>*.
|
||||
MOZ_ASSERT(!aDataTransfer);
|
||||
AutoTrackDataTransferForPaste trackDataTransfer(*this, dataTransfer);
|
||||
|
||||
ret = DispatchClipboardEventAndUpdateClipboard(
|
||||
ePasteNoFormatting, Some(aClipboardType), dataTransfer);
|
||||
if (MOZ_UNLIKELY(ret.isErr())) {
|
||||
NS_WARNING(
|
||||
"EditorBase::DispatchClipboardEventAndUpdateClipboard("
|
||||
"ePasteNoFormatting) failed");
|
||||
return EditorBase::ToGenericNSResult(ret.unwrapErr());
|
||||
}
|
||||
}
|
||||
switch (ret.inspect()) {
|
||||
case ClipboardEventResult::DoDefault:
|
||||
@@ -2607,17 +2636,17 @@ nsresult HTMLEditor::PasteNoFormattingAsAction(
|
||||
}
|
||||
if (editorBase != this) {
|
||||
if (editorBase->IsHTMLEditor()) {
|
||||
nsresult rv =
|
||||
MOZ_KnownLive(editorBase->AsHTMLEditor())
|
||||
->PasteNoFormattingAsAction(
|
||||
aClipboardType, DispatchPasteEvent::No, aPrincipal);
|
||||
nsresult rv = MOZ_KnownLive(editorBase->AsHTMLEditor())
|
||||
->PasteNoFormattingAsAction(
|
||||
aClipboardType, DispatchPasteEvent::No,
|
||||
dataTransfer, aPrincipal);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"HTMLEditor::PasteNoFormattingAsAction("
|
||||
"DispatchPasteEvent::No) failed");
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
}
|
||||
nsresult rv = editorBase->PasteAsAction(
|
||||
aClipboardType, DispatchPasteEvent::No, aPrincipal);
|
||||
aClipboardType, DispatchPasteEvent::No, dataTransfer, aPrincipal);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::PasteAsAction(DispatchPasteEvent::No) failed");
|
||||
@@ -2652,24 +2681,6 @@ nsresult HTMLEditor::PasteNoFormattingAsAction(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get Clipboard Service
|
||||
nsCOMPtr<nsIClipboard> clipboard(
|
||||
do_GetService("@mozilla.org/widget/clipboard;1", &rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to get nsIClipboard service");
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!GetDocument()) {
|
||||
NS_WARNING("Editor didn't have document, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
auto* windowContext = GetDocument()->GetWindowContext();
|
||||
if (!windowContext) {
|
||||
NS_WARNING("Editor didn't have document window context, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Result<nsCOMPtr<nsITransferable>, nsresult> maybeTransferable =
|
||||
EditorUtils::CreateTransferableForPlainText(*GetDocument());
|
||||
if (maybeTransferable.isErr()) {
|
||||
@@ -2683,11 +2694,10 @@ nsresult HTMLEditor::PasteNoFormattingAsAction(
|
||||
"ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get the Data from the clipboard
|
||||
rv = clipboard->GetData(transferable, aClipboardType, windowContext);
|
||||
rv = GetDataFromDataTransferOrClipboard(dataTransfer, transferable,
|
||||
aClipboardType);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsIClipboard::GetData() failed");
|
||||
NS_WARNING("EditorBase::GetDataFromDataTransferOrClipboard() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -2798,11 +2808,11 @@ bool HTMLEditor::CanPasteTransferable(nsITransferable* aTransferable) {
|
||||
|
||||
nsresult HTMLEditor::HandlePasteAsQuotation(
|
||||
AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType) {
|
||||
nsIClipboard::ClipboardType aClipboardType, DataTransfer* aDataTransfer) {
|
||||
MOZ_ASSERT(aClipboardType == nsIClipboard::kGlobalClipboard ||
|
||||
aClipboardType == nsIClipboard::kSelectionClipboard);
|
||||
aEditActionData.InitializeDataTransferWithClipboard(
|
||||
SettingDataTransfer::eWithFormat, aClipboardType);
|
||||
SettingDataTransfer::eWithFormat, aDataTransfer, aClipboardType);
|
||||
if (NS_WARN_IF(!aEditActionData.CanHandle())) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
@@ -2822,7 +2832,8 @@ nsresult HTMLEditor::HandlePasteAsQuotation(
|
||||
|
||||
if (IsPlaintextMailComposer() ||
|
||||
editingHost->IsContentEditablePlainTextOnly()) {
|
||||
nsresult rv = PasteAsPlaintextQuotation(aClipboardType, *editingHost);
|
||||
nsresult rv =
|
||||
PasteAsPlaintextQuotation(aClipboardType, aDataTransfer, *editingHost);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"HTMLEditor::PasteAsPlaintextQuotation() failed");
|
||||
return rv;
|
||||
@@ -2923,22 +2934,15 @@ nsresult HTMLEditor::HandlePasteAsQuotation(
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = PasteInternal(aClipboardType, *editingHost);
|
||||
rv = PasteInternal(aClipboardType, aDataTransfer, *editingHost);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::PasteInternal() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::PasteAsPlaintextQuotation(
|
||||
nsIClipboard::ClipboardType aSelectionType, const Element& aEditingHost) {
|
||||
// Get Clipboard Service
|
||||
nsIClipboard::ClipboardType aSelectionType, DataTransfer* aDataTransfer,
|
||||
const Element& aEditingHost) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIClipboard> clipboard =
|
||||
do_GetService("@mozilla.org/widget/clipboard;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to get nsIClipboard service");
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Create generic Transferable for getting the data
|
||||
nsCOMPtr<nsITransferable> transferable =
|
||||
do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
|
||||
@@ -2970,9 +2974,8 @@ nsresult HTMLEditor::PasteAsPlaintextQuotation(
|
||||
"nsITransferable::AddDataFlavor(kTextMime) failed, but ignored");
|
||||
|
||||
// Get the Data from the clipboard
|
||||
rvIgnored = clipboard->GetData(transferable, aSelectionType, windowContext);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"nsIClipboard::GetData() failed, but ignored");
|
||||
GetDataFromDataTransferOrClipboard(aDataTransfer, transferable,
|
||||
aSelectionType);
|
||||
|
||||
// Now we ask the transferable for the data
|
||||
// it still owns the data, we just have a pointer to it.
|
||||
|
||||
@@ -565,22 +565,13 @@ bool TextEditor::IsCopyToClipboardAllowedInternal() const {
|
||||
|
||||
nsresult TextEditor::HandlePasteAsQuotation(
|
||||
AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType) {
|
||||
nsIClipboard::ClipboardType aClipboardType, DataTransfer* aDataTransfer) {
|
||||
MOZ_ASSERT(aClipboardType == nsIClipboard::kGlobalClipboard ||
|
||||
aClipboardType == nsIClipboard::kSelectionClipboard);
|
||||
if (NS_WARN_IF(!GetDocument())) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get Clipboard Service
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIClipboard> clipboard =
|
||||
do_GetService("@mozilla.org/widget/clipboard;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to get nsIClipboard service");
|
||||
return rv;
|
||||
}
|
||||
|
||||
// XXX Why don't we dispatch ePaste event here?
|
||||
|
||||
// Get the nsITransferable interface for getting the data from the clipboard
|
||||
@@ -598,13 +589,9 @@ nsresult TextEditor::HandlePasteAsQuotation(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
auto* windowContext = GetDocument()->GetWindowContext();
|
||||
if (!windowContext) {
|
||||
NS_WARNING("Editor didn't have document window context");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Get the Data from the clipboard
|
||||
rv = clipboard->GetData(trans, aClipboardType, windowContext);
|
||||
nsresult rv =
|
||||
GetDataFromDataTransferOrClipboard(aDataTransfer, trans, aClipboardType);
|
||||
|
||||
// Now we ask the transferable for the data
|
||||
// it still owns the data, we just have a pointer to it.
|
||||
|
||||
@@ -465,9 +465,8 @@ class TextEditor final : public EditorBase,
|
||||
SelectionHandling aSelectionHandling) final;
|
||||
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertDroppedDataTransferAsAction(
|
||||
AutoEditActionDataSetter& aEditActionData,
|
||||
dom::DataTransfer& aDataTransfer, const EditorDOMPoint& aDroppedAt,
|
||||
nsIPrincipal* aSourcePrincipal) final;
|
||||
AutoEditActionDataSetter& aEditActionData, DataTransfer& aDataTransfer,
|
||||
const EditorDOMPoint& aDroppedAt, nsIPrincipal* aSourcePrincipal) final;
|
||||
|
||||
/**
|
||||
* HandleDeleteSelectionInternal() is a helper method of
|
||||
@@ -568,10 +567,12 @@ class TextEditor final : public EditorBase,
|
||||
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
HandlePaste(AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType) final;
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) final;
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
HandlePasteAsQuotation(AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType) final;
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) final;
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
HandlePasteTransferable(AutoEditActionDataSetter& aEditActionData,
|
||||
nsITransferable& aTransferable) final;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/DataTransfer.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/DocumentInlines.h"
|
||||
@@ -161,7 +162,8 @@ nsresult TextEditor::InsertDroppedDataTransferAsAction(
|
||||
}
|
||||
|
||||
nsresult TextEditor::HandlePaste(AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType) {
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) {
|
||||
if (NS_WARN_IF(!GetDocument())) {
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -193,17 +195,13 @@ nsresult TextEditor::HandlePaste(AutoEditActionDataSetter& aEditActionData,
|
||||
return NS_OK; // XXX Why?
|
||||
}
|
||||
// Get the Data from the clipboard.
|
||||
auto* windowContext = GetDocument()->GetWindowContext();
|
||||
if (!windowContext) {
|
||||
NS_WARNING("Editor didn't have document window context");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = clipboard->GetData(transferable, aClipboardType, windowContext);
|
||||
|
||||
rv = GetDataFromDataTransferOrClipboard(aDataTransfer, transferable,
|
||||
aClipboardType);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsIClipboard::GetData() failed, but ignored");
|
||||
return NS_OK; // XXX Why?
|
||||
NS_WARNING("EditorBase::GetDataFromDataTransferOrClipboard() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
// XXX Why don't we check this first?
|
||||
if (!IsModifiable()) {
|
||||
return NS_OK;
|
||||
|
||||
@@ -2430,7 +2430,7 @@ MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP nsDocumentViewer::SelectAll() {
|
||||
NS_IMETHODIMP nsDocumentViewer::CopySelection() {
|
||||
RefPtr<PresShell> presShell = mPresShell;
|
||||
nsCopySupport::FireClipboardEvent(eCopy, Some(nsIClipboard::kGlobalClipboard),
|
||||
presShell, nullptr);
|
||||
presShell, nullptr, nullptr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user