Backed out 5 changesets (bug 1918027) build bustages @ EditorBase.cpp CLOSED TREE
Backed out changeset d9b4046afbae (bug 1918027) Backed out changeset d45421faa30c (bug 1918027) Backed out changeset 363a68600396 (bug 1918027) Backed out changeset 965a766c81be (bug 1918027) Backed out changeset 7c609b24857b (bug 1918027)
This commit is contained in:
@@ -1414,7 +1414,6 @@ Document::Document(const char* aContentType)
|
||||
mForceLoadAtTop(false),
|
||||
mFireMutationEvents(true),
|
||||
mHasPolicyWithRequireTrustedTypesForDirective(false),
|
||||
mClipboardCopyTriggered(false),
|
||||
mXMLDeclarationBits(0),
|
||||
mOnloadBlockCount(0),
|
||||
mWriteLevel(0),
|
||||
|
||||
@@ -3688,9 +3688,6 @@ 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.
|
||||
@@ -4969,10 +4966,6 @@ 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,8 +758,7 @@ class MOZ_RAII AutoHandlingPasteEvent final {
|
||||
bool nsCopySupport::FireClipboardEvent(
|
||||
EventMessage aEventMessage,
|
||||
mozilla::Maybe<nsIClipboard::ClipboardType> aClipboardType,
|
||||
PresShell* aPresShell, Selection* aSelection, DataTransfer* aDataTransfer,
|
||||
bool* aActionTaken) {
|
||||
PresShell* aPresShell, Selection* aSelection, bool* aActionTaken) {
|
||||
if (aActionTaken) {
|
||||
*aActionTaken = false;
|
||||
}
|
||||
@@ -826,18 +825,9 @@ bool nsCopySupport::FireClipboardEvent(
|
||||
bool doDefault = true;
|
||||
RefPtr<DataTransfer> clipboardData;
|
||||
if (chromeShell || StaticPrefs::dom_event_clipboardevents_enabled()) {
|
||||
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
|
||||
? aDataTransfer
|
||||
: MakeRefPtr<DataTransfer>(
|
||||
doc->GetScopeObject(), aEventMessage,
|
||||
originalEventMessage == ePaste, aClipboardType);
|
||||
clipboardData =
|
||||
new DataTransfer(doc->GetScopeObject(), aEventMessage,
|
||||
originalEventMessage == ePaste, aClipboardType);
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
InternalClipboardEvent evt(true, originalEventMessage);
|
||||
@@ -861,7 +851,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 && !aDataTransfer) {
|
||||
if (clipboardData) {
|
||||
clipboardData->Disconnect();
|
||||
|
||||
// NOTE: Disconnect may not actually clear the DataTransfer if the
|
||||
@@ -969,10 +959,6 @@ 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,7 +23,6 @@ class nsILoadContext;
|
||||
namespace mozilla {
|
||||
class PresShell;
|
||||
namespace dom {
|
||||
class DataTransfer;
|
||||
class Document;
|
||||
class Selection;
|
||||
class WindowContext;
|
||||
@@ -105,10 +104,6 @@ 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.
|
||||
*
|
||||
@@ -119,7 +114,7 @@ class nsCopySupport {
|
||||
mozilla::EventMessage aEventMessage,
|
||||
mozilla::Maybe<nsIClipboard::ClipboardType> aClipboardType,
|
||||
mozilla::PresShell* aPresShell, mozilla::dom::Selection* aSelection,
|
||||
mozilla::dom::DataTransfer* aDataTransfer, bool* aActionTaken = nullptr);
|
||||
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, nullptr, &actionTaken);
|
||||
presShell, nullptr, &actionTaken);
|
||||
|
||||
return actionTaken ? NS_OK : NS_SUCCESS_DOM_NO_OPERATION;
|
||||
}
|
||||
|
||||
@@ -210,7 +210,6 @@ DataTransfer::DataTransfer(
|
||||
const uint32_t aEffectAllowed, bool aCursorState, bool aIsExternal,
|
||||
bool aUserCancelled, bool aIsCrossDomainSubFrameDrop,
|
||||
mozilla::Maybe<nsIClipboard::ClipboardType> aClipboardType,
|
||||
nsCOMPtr<nsIClipboardDataSnapshot> aClipboardDataSnapshot,
|
||||
DataTransferItemList* aItems, Element* aDragImage, uint32_t aDragImageX,
|
||||
uint32_t aDragImageY, bool aShowFailAnimation)
|
||||
: mParent(aParent),
|
||||
@@ -223,7 +222,6 @@ DataTransfer::DataTransfer(
|
||||
mUserCancelled(aUserCancelled),
|
||||
mIsCrossDomainSubFrameDrop(aIsCrossDomainSubFrameDrop),
|
||||
mClipboardType(aClipboardType),
|
||||
mClipboardDataSnapshot(std::move(aClipboardDataSnapshot)),
|
||||
mDragImage(aDragImage),
|
||||
mDragImageX(aDragImageX),
|
||||
mDragImageY(aDragImageY),
|
||||
@@ -729,18 +727,9 @@ void DataTransfer::GetExternalClipboardFormats(const bool& aPlainTextOnly,
|
||||
formats, *mClipboardType, wc, getter_AddRefs(clipboardDataSnapshot));
|
||||
}
|
||||
} else {
|
||||
AutoTArray<nsCString, std::size(kNonPlainTextExternalFormats) + 4> formats;
|
||||
AutoTArray<nsCString, std::size(kNonPlainTextExternalFormats)> formats;
|
||||
formats.AppendElements(
|
||||
Span<const nsLiteralCString>(kNonPlainTextExternalFormats));
|
||||
// We will be using this snapshot to provide the data to paste in
|
||||
// EditorBase, so add a few extra formats here to make sure we have
|
||||
// everything. Note that these extra formats will not be returned in aResult
|
||||
// because of the checks below.
|
||||
formats.AppendElement(kNativeHTMLMime);
|
||||
formats.AppendElement(kJPEGImageMime);
|
||||
formats.AppendElement(kGIFImageMime);
|
||||
formats.AppendElement(kMozTextInternal);
|
||||
|
||||
if (doContentAnalysis) {
|
||||
rv = GetClipboardDataSnapshotWithContentAnalysisSync(
|
||||
formats, *mClipboardType, wc, getter_AddRefs(clipboardDataSnapshot));
|
||||
@@ -936,9 +925,8 @@ nsresult DataTransfer::Clone(nsISupports* aParent, EventMessage aEventMessage,
|
||||
DataTransfer** aNewDataTransfer) {
|
||||
RefPtr<DataTransfer> newDataTransfer = new DataTransfer(
|
||||
aParent, aEventMessage, mEffectAllowed, mCursorState, mIsExternal,
|
||||
aUserCancelled, aIsCrossDomainSubFrameDrop, mClipboardType,
|
||||
mClipboardDataSnapshot, mItems, mDragImage, mDragImageX, mDragImageY,
|
||||
mShowFailAnimation);
|
||||
aUserCancelled, aIsCrossDomainSubFrameDrop, mClipboardType, mItems,
|
||||
mDragImage, mDragImageX, mDragImageY, mShowFailAnimation);
|
||||
|
||||
newDataTransfer.forget(aNewDataTransfer);
|
||||
return NS_OK;
|
||||
@@ -1655,34 +1643,4 @@ nsIDragSession* DataTransfer::GetOwnerDragSession() {
|
||||
return dragSession;
|
||||
}
|
||||
|
||||
void DataTransfer::ClearForPaste() {
|
||||
MOZ_ASSERT(mEventMessage == ePaste,
|
||||
"ClearForPaste() should only be called on ePaste messages");
|
||||
Disconnect();
|
||||
|
||||
// NOTE: Disconnect may not actually clear the DataTransfer if the
|
||||
// dom.events.dataTransfer.protected.enabled pref is not on, so we make
|
||||
// sure we clear here, as not clearing could provide the DataTransfer
|
||||
// access to information from the system clipboard at an arbitrary point
|
||||
// in the future.
|
||||
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
|
||||
|
||||
@@ -87,7 +87,6 @@ class DataTransfer final : public nsISupports, public nsWrapperCache {
|
||||
bool aIsExternal, bool aUserCancelled,
|
||||
bool aIsCrossDomainSubFrameDrop,
|
||||
mozilla::Maybe<nsIClipboard::ClipboardType> aClipboardType,
|
||||
nsCOMPtr<nsIClipboardDataSnapshot> aClipboardDataSnapshot,
|
||||
DataTransferItemList* aItems, Element* aDragImage,
|
||||
uint32_t aDragImageX, uint32_t aDragImageY,
|
||||
bool aShowFailAnimation);
|
||||
@@ -444,11 +443,6 @@ class DataTransfer final : public nsISupports, public nsWrapperCache {
|
||||
mozilla::Span<const char> aString,
|
||||
std::function<void(ParseExternalCustomTypesStringData&&)>&& aCallback);
|
||||
|
||||
// Clears this DataTransfer that was used for paste
|
||||
void ClearForPaste();
|
||||
|
||||
bool HasPrivateHTMLFlavor() const;
|
||||
|
||||
protected:
|
||||
// Retrieve a list of clipboard formats supported
|
||||
//
|
||||
|
||||
@@ -6191,25 +6191,11 @@ 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, dataTransfer)) {
|
||||
aPresShell, selection)) {
|
||||
*aStatus = nsEventStatus_eConsumeNoDefault;
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -6244,11 +6230,11 @@ nsresult EventStateManager::HandleMiddleClickPaste(
|
||||
// quotation. Otherwise, paste it as is.
|
||||
if (aMouseEvent->IsControl()) {
|
||||
DebugOnly<nsresult> rv = aEditorBase->PasteAsQuotationAsAction(
|
||||
clipboardType, EditorBase::DispatchPasteEvent::No, dataTransfer);
|
||||
clipboardType, EditorBase::DispatchPasteEvent::No);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste as quotation");
|
||||
} else {
|
||||
DebugOnly<nsresult> rv = aEditorBase->PasteAsAction(
|
||||
clipboardType, EditorBase::DispatchPasteEvent::No, dataTransfer);
|
||||
clipboardType, EditorBase::DispatchPasteEvent::No);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste");
|
||||
}
|
||||
*aStatus = nsEventStatus_eConsumeNoDefault;
|
||||
|
||||
@@ -723,7 +723,7 @@ add_task(async function test_input_copypaste_dataTransfer_multiple() {
|
||||
try { cd.mozClearDataAt("text/plain", 1); } catch (ex) { exh = true; }
|
||||
ok(exh, "exception occured mozClearDataAt 1");
|
||||
|
||||
cd.setData("text/x-moz-url", "http://www.mozilla.org\nMozilla Page Title");
|
||||
cd.setData("text/x-moz-url", "http://www.mozilla.org");
|
||||
SpecialPowers.wrap(cd).mozSetDataAt("text/x-custom", "Custom Text with \u0000 null", 0);
|
||||
is(SpecialPowers.wrap(cd).mozItemCount, 1, "mozItemCount after set multiple types");
|
||||
return false;
|
||||
@@ -751,7 +751,7 @@ add_task(async function test_input_copypaste_dataTransfer_multiple() {
|
||||
// Firefox for Android's clipboard code doesn't handle x-moz-url. Therefore
|
||||
// disabling the following test. Enable this once bug #840101 is fixed.
|
||||
if (!navigator.appVersion.includes("Android")) {
|
||||
is(cd.getData("text/x-moz-url"), "http://www.mozilla.org\nMozilla Page Title", "paste text/x-moz-url multiple types");
|
||||
is(cd.getData("text/x-moz-url"), "http://www.mozilla.org", "paste text/x-moz-url multiple types");
|
||||
is(cd.getData("text/x-custom"), "Custom Text with \u0000 null", "paste text/custom multiple types");
|
||||
} else {
|
||||
is(cd.getData("text/x-custom"), "", "paste text/custom multiple types");
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
#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
|
||||
@@ -1585,26 +1584,10 @@ 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,
|
||||
DataTransfer* aDataTransfer /* = nullptr */) {
|
||||
Maybe<nsIClipboard::ClipboardType> aClipboardType) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
|
||||
const bool isPasting =
|
||||
@@ -1634,8 +1617,7 @@ EditorBase::DispatchClipboardEventAndUpdateClipboard(
|
||||
|
||||
bool actionTaken = false;
|
||||
const bool doDefault = nsCopySupport::FireClipboardEvent(
|
||||
aEventMessage, aClipboardType, presShell, sel, aDataTransfer,
|
||||
&actionTaken);
|
||||
aEventMessage, aClipboardType, presShell, sel, &actionTaken);
|
||||
NotifyOfDispatchingClipboardEvent();
|
||||
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
@@ -1830,33 +1812,13 @@ 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
|
||||
? 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;
|
||||
}
|
||||
@@ -1868,22 +1830,13 @@ nsresult EditorBase::PasteAsAction(nsIClipboard::ClipboardType aClipboardType,
|
||||
}
|
||||
const RefPtr<Element> focusedElement = focusManager->GetFocusedElement();
|
||||
|
||||
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());
|
||||
}
|
||||
Result<ClipboardEventResult, nsresult> ret =
|
||||
DispatchClipboardEventAndUpdateClipboard(ePaste, Some(aClipboardType));
|
||||
if (MOZ_UNLIKELY(ret.isErr())) {
|
||||
NS_WARNING(
|
||||
"EditorBase::DispatchClipboardEventAndUpdateClipboard(ePaste) "
|
||||
"failed");
|
||||
return EditorBase::ToGenericNSResult(ret.unwrapErr());
|
||||
}
|
||||
switch (ret.inspect()) {
|
||||
case ClipboardEventResult::DoDefault:
|
||||
@@ -1912,7 +1865,7 @@ nsresult EditorBase::PasteAsAction(nsIClipboard::ClipboardType aClipboardType,
|
||||
}
|
||||
if (editorBase != this) {
|
||||
nsresult rv = editorBase->PasteAsAction(
|
||||
aClipboardType, DispatchPasteEvent::No, dataTransfer, aPrincipal);
|
||||
aClipboardType, DispatchPasteEvent::No, aPrincipal);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::PasteAsAction(DispatchPasteEvent::No) failed");
|
||||
@@ -1923,7 +1876,8 @@ nsresult EditorBase::PasteAsAction(nsIClipboard::ClipboardType aClipboardType,
|
||||
// The caller must already have dispatched a "paste" event.
|
||||
editActionData.NotifyOfDispatchingClipboardEvent();
|
||||
}
|
||||
nsresult rv = HandlePaste(editActionData, aClipboardType, dataTransfer);
|
||||
|
||||
nsresult rv = HandlePaste(editActionData, aClipboardType);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EditorBase::HandlePaste() failed");
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
}
|
||||
@@ -1931,7 +1885,6 @@ 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);
|
||||
@@ -1940,26 +1893,6 @@ 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
|
||||
? 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())) {
|
||||
@@ -1973,22 +1906,13 @@ nsresult EditorBase::PasteAsQuotationAsAction(
|
||||
}
|
||||
const RefPtr<Element> focusedElement = focusManager->GetFocusedElement();
|
||||
|
||||
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());
|
||||
}
|
||||
Result<ClipboardEventResult, nsresult> ret =
|
||||
DispatchClipboardEventAndUpdateClipboard(ePaste, Some(aClipboardType));
|
||||
if (MOZ_UNLIKELY(ret.isErr())) {
|
||||
NS_WARNING(
|
||||
"EditorBase::DispatchClipboardEventAndUpdateClipboard(ePaste) "
|
||||
"failed");
|
||||
return EditorBase::ToGenericNSResult(ret.unwrapErr());
|
||||
}
|
||||
switch (ret.inspect()) {
|
||||
case ClipboardEventResult::DoDefault:
|
||||
@@ -2017,7 +1941,7 @@ nsresult EditorBase::PasteAsQuotationAsAction(
|
||||
}
|
||||
if (editorBase != this) {
|
||||
nsresult rv = editorBase->PasteAsQuotationAsAction(
|
||||
aClipboardType, DispatchPasteEvent::No, dataTransfer, aPrincipal);
|
||||
aClipboardType, DispatchPasteEvent::No, aPrincipal);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::PasteAsQuotationAsAction("
|
||||
"DispatchPasteEvent::No) failed");
|
||||
@@ -2029,8 +1953,7 @@ nsresult EditorBase::PasteAsQuotationAsAction(
|
||||
editActionData.NotifyOfDispatchingClipboardEvent();
|
||||
}
|
||||
|
||||
nsresult rv =
|
||||
HandlePasteAsQuotation(editActionData, aClipboardType, dataTransfer);
|
||||
nsresult rv = HandlePasteAsQuotation(editActionData, aClipboardType);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::HandlePasteAsQuotation() failed");
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
@@ -6645,7 +6568,7 @@ void EditorBase::AutoEditActionDataSetter::InitializeDataTransfer(
|
||||
}
|
||||
|
||||
void EditorBase::AutoEditActionDataSetter::InitializeDataTransferWithClipboard(
|
||||
SettingDataTransfer aSettingDataTransfer, DataTransfer* aDataTransfer,
|
||||
SettingDataTransfer aSettingDataTransfer,
|
||||
nsIClipboard::ClipboardType aClipboardType) {
|
||||
MOZ_ASSERT(!HasTriedToDispatchBeforeInputEvent(),
|
||||
"It's too late to set dataTransfer since this may have already "
|
||||
@@ -6657,22 +6580,12 @@ 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...
|
||||
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));
|
||||
}
|
||||
mDataTransfer =
|
||||
new DataTransfer(scopeObject,
|
||||
aSettingDataTransfer == SettingDataTransfer::eWithFormat
|
||||
? ePaste
|
||||
: ePasteNoFormatting,
|
||||
true /* is external */, Some(aClipboardType));
|
||||
}
|
||||
|
||||
void EditorBase::AutoEditActionDataSetter::AppendTargetRange(
|
||||
@@ -7252,102 +7165,4 @@ 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,7 +108,6 @@ 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;
|
||||
@@ -242,14 +241,6 @@ 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
|
||||
*/
|
||||
@@ -761,9 +752,6 @@ 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.
|
||||
@@ -772,7 +760,6 @@ class EditorBase : public nsIEditor,
|
||||
MOZ_CAN_RUN_SCRIPT nsresult
|
||||
PasteAsAction(nsIClipboard::ClipboardType aClipboardType,
|
||||
DispatchPasteEvent aDispatchPasteEvent,
|
||||
DataTransfer* aDataTransfer = nullptr,
|
||||
nsIPrincipal* aPrincipal = nullptr);
|
||||
|
||||
/**
|
||||
@@ -800,9 +787,6 @@ 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.
|
||||
@@ -810,7 +794,6 @@ class EditorBase : public nsIEditor,
|
||||
MOZ_CAN_RUN_SCRIPT nsresult
|
||||
PasteAsQuotationAsAction(nsIClipboard::ClipboardType aClipboardType,
|
||||
DispatchPasteEvent aDispatchPasteEvent,
|
||||
DataTransfer* aDataTransfer = nullptr,
|
||||
nsIPrincipal* aPrincipal = nullptr);
|
||||
|
||||
/**
|
||||
@@ -1168,7 +1151,7 @@ class EditorBase : public nsIEditor,
|
||||
* because it'll be set to InputEvent.dataTransfer and which should be
|
||||
* read-only.
|
||||
*/
|
||||
void InitializeDataTransfer(DataTransfer* aDataTransfer);
|
||||
void InitializeDataTransfer(dom::DataTransfer* aDataTransfer);
|
||||
/**
|
||||
* InitializeDataTransfer(nsITransferable*) creates new DataTransfer
|
||||
* instance, initializes it with aTransferable and sets mDataTransfer to
|
||||
@@ -1185,9 +1168,9 @@ class EditorBase : public nsIEditor,
|
||||
* initializes it with clipboard and sets mDataTransfer to it.
|
||||
*/
|
||||
void InitializeDataTransferWithClipboard(
|
||||
SettingDataTransfer aSettingDataTransfer, DataTransfer* aDataTransfer,
|
||||
SettingDataTransfer aSettingDataTransfer,
|
||||
nsIClipboard::ClipboardType aClipboardType);
|
||||
DataTransfer* GetDataTransfer() const { return mDataTransfer; }
|
||||
dom::DataTransfer* GetDataTransfer() const { return mDataTransfer; }
|
||||
|
||||
/**
|
||||
* AppendTargetRange() appends aTargetRange to target ranges. This should
|
||||
@@ -1437,7 +1420,7 @@ class EditorBase : public nsIEditor,
|
||||
nsString mData;
|
||||
|
||||
// The dataTransfer should be set to InputEvent.dataTransfer.
|
||||
RefPtr<DataTransfer> mDataTransfer;
|
||||
RefPtr<dom::DataTransfer> mDataTransfer;
|
||||
|
||||
// They are used for result of InputEvent.getTargetRanges() of beforeinput.
|
||||
OwningNonNullStaticRangeArray mTargetRanges;
|
||||
@@ -1558,10 +1541,6 @@ 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.
|
||||
@@ -1603,7 +1582,7 @@ class EditorBase : public nsIEditor,
|
||||
* content with current edit action. The result is proper for
|
||||
* InputEvent.dataTransfer value.
|
||||
*/
|
||||
DataTransfer* GetInputEventDataTransfer() const {
|
||||
dom::DataTransfer* GetInputEventDataTransfer() const {
|
||||
return mEditActionData ? mEditActionData->GetDataTransfer() : nullptr;
|
||||
}
|
||||
|
||||
@@ -2579,7 +2558,7 @@ class EditorBase : public nsIEditor,
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult
|
||||
InsertDroppedDataTransferAsAction(AutoEditActionDataSetter& aEditActionData,
|
||||
DataTransfer& aDataTransfer,
|
||||
dom::DataTransfer& aDataTransfer,
|
||||
const EditorDOMPoint& aDroppedAt,
|
||||
nsIPrincipal* aSourcePrincipal) = 0;
|
||||
|
||||
@@ -2739,8 +2718,7 @@ class EditorBase : public nsIEditor,
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<ClipboardEventResult, nsresult>
|
||||
DispatchClipboardEventAndUpdateClipboard(
|
||||
EventMessage aEventMessage,
|
||||
mozilla::Maybe<nsIClipboard::ClipboardType> aClipboardType,
|
||||
DataTransfer* aDataTransfer = nullptr);
|
||||
mozilla::Maybe<nsIClipboard::ClipboardType> aClipboardType);
|
||||
|
||||
/**
|
||||
* Called after PasteAsAction() dispatches "paste" event and it's not
|
||||
@@ -2748,8 +2726,7 @@ class EditorBase : public nsIEditor,
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult HandlePaste(
|
||||
AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) = 0;
|
||||
nsIClipboard::ClipboardType aClipboardType) = 0;
|
||||
|
||||
/**
|
||||
* Called after PasteAsQuotationAsAction() dispatches "paste" event and it's
|
||||
@@ -2757,12 +2734,11 @@ class EditorBase : public nsIEditor,
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult HandlePasteAsQuotation(
|
||||
AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) = 0;
|
||||
nsIClipboard::ClipboardType aClipboardType) = 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,
|
||||
@@ -2783,17 +2759,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,
|
||||
@@ -2837,10 +2813,8 @@ 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()) {
|
||||
@@ -2895,8 +2869,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)
|
||||
@@ -2951,8 +2925,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;
|
||||
@@ -3007,10 +2981,9 @@ 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,
|
||||
nullptr, aPrincipal);
|
||||
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,
|
||||
nullptr, aPrincipal);
|
||||
aPrincipal);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::PasteAsQuotationAsAction(nsIClipboard::"
|
||||
"kGlobalClipboard, DispatchPasteEvent::Yes) failed");
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#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
|
||||
@@ -344,43 +343,6 @@ 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,9 +241,6 @@ 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.
|
||||
@@ -251,7 +248,6 @@ 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;
|
||||
@@ -1100,8 +1096,9 @@ class HTMLEditor final : public EditorBase,
|
||||
SelectionHandling aSelectionHandling) final;
|
||||
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertDroppedDataTransferAsAction(
|
||||
AutoEditActionDataSetter& aEditActionData, DataTransfer& aDataTransfer,
|
||||
const EditorDOMPoint& aDroppedAt, nsIPrincipal* aSourcePrincipal) final;
|
||||
AutoEditActionDataSetter& aEditActionData,
|
||||
dom::DataTransfer& aDataTransfer, const EditorDOMPoint& aDroppedAt,
|
||||
nsIPrincipal* aSourcePrincipal) final;
|
||||
|
||||
/**
|
||||
* GetInlineStyles() retrieves the style of aElement and modifies each item of
|
||||
@@ -3138,12 +3135,10 @@ class HTMLEditor final : public EditorBase,
|
||||
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
HandlePaste(AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) final;
|
||||
nsIClipboard::ClipboardType aClipboardType) final;
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
HandlePasteAsQuotation(AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) final;
|
||||
nsIClipboard::ClipboardType aClipboardType) final;
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
HandlePasteTransferable(AutoEditActionDataSetter& aEditActionData,
|
||||
nsITransferable& aTransferable) final;
|
||||
@@ -3157,9 +3152,8 @@ class HTMLEditor final : public EditorBase,
|
||||
* nsIClipboard::kSelectionClipboard.
|
||||
* @param aEditingHost The editing host.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT nsresult
|
||||
PasteInternal(nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer, const Element& aEditingHost);
|
||||
MOZ_CAN_RUN_SCRIPT nsresult PasteInternal(
|
||||
nsIClipboard::ClipboardType aClipboardType, const Element& aEditingHost);
|
||||
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
InsertWithQuotationsAsSubAction(const nsAString& aQuotedText) final;
|
||||
@@ -3439,7 +3433,7 @@ class HTMLEditor final : public EditorBase,
|
||||
RefPtr<dom::BlobImpl> mBlob;
|
||||
RefPtr<HTMLEditor> mHTMLEditor;
|
||||
RefPtr<const Element> mEditingHost;
|
||||
RefPtr<DataTransfer> mDataTransfer;
|
||||
RefPtr<dom::DataTransfer> mDataTransfer;
|
||||
EditorDOMPoint mPointToInsert;
|
||||
EditAction mEditAction;
|
||||
SafeToInsertData mSafeToInsertData;
|
||||
@@ -3741,8 +3735,7 @@ class HTMLEditor final : public EditorBase,
|
||||
|
||||
// Methods for handling plaintext quotations
|
||||
MOZ_CAN_RUN_SCRIPT nsresult PasteAsPlaintextQuotation(
|
||||
nsIClipboard::ClipboardType aSelectionType, DataTransfer* aDataTransfer,
|
||||
const Element& aEditingHost);
|
||||
nsIClipboard::ClipboardType aSelectionType, const Element& aEditingHost);
|
||||
|
||||
enum class AddCites { No, Yes };
|
||||
/**
|
||||
@@ -3788,13 +3781,13 @@ class HTMLEditor final : public EditorBase,
|
||||
* @param aIndex index of aDataTransfer's item to insert.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT nsresult InsertFromDataTransfer(
|
||||
const DataTransfer* aDataTransfer, uint32_t aIndex,
|
||||
const dom::DataTransfer* aDataTransfer, uint32_t aIndex,
|
||||
nsIPrincipal* aSourcePrincipal, const EditorDOMPoint& aDroppedAt,
|
||||
DeleteSelectedContent aDeleteSelectedContent,
|
||||
const Element& aEditingHost);
|
||||
|
||||
static HavePrivateHTMLFlavor DataTransferOrClipboardHasPrivateHTMLFlavor(
|
||||
DataTransfer* aDataTransfer, nsIClipboard* clipboard);
|
||||
static HavePrivateHTMLFlavor ClipboardHasPrivateHTMLFlavor(
|
||||
nsIClipboard* clipboard);
|
||||
|
||||
/**
|
||||
* CF_HTML:
|
||||
|
||||
@@ -127,11 +127,10 @@ 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,
|
||||
nullptr, aPrincipal);
|
||||
nsresult rv = MOZ_KnownLive(htmlEditor)
|
||||
->PasteNoFormattingAsAction(
|
||||
nsIClipboard::kGlobalClipboard,
|
||||
EditorBase::DispatchPasteEvent::Yes, aPrincipal);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"HTMLEditor::PasteNoFormattingAsAction(DispatchPasteEvent::Yes) failed");
|
||||
|
||||
@@ -1486,8 +1486,6 @@ 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 =
|
||||
@@ -2348,15 +2346,8 @@ nsresult HTMLEditor::InsertFromDataTransfer(
|
||||
}
|
||||
|
||||
// static
|
||||
HTMLEditor::HavePrivateHTMLFlavor
|
||||
HTMLEditor::DataTransferOrClipboardHasPrivateHTMLFlavor(
|
||||
DataTransfer* aDataTransfer, nsIClipboard* aClipboard) {
|
||||
nsresult rv;
|
||||
if (aDataTransfer) {
|
||||
return aDataTransfer->HasPrivateHTMLFlavor() ? HavePrivateHTMLFlavor::Yes
|
||||
: HavePrivateHTMLFlavor::No;
|
||||
}
|
||||
// otherwise, fall back to clipboard
|
||||
HTMLEditor::HavePrivateHTMLFlavor HTMLEditor::ClipboardHasPrivateHTMLFlavor(
|
||||
nsIClipboard* aClipboard) {
|
||||
if (NS_WARN_IF(!aClipboard)) {
|
||||
return HavePrivateHTMLFlavor::No;
|
||||
}
|
||||
@@ -2365,7 +2356,7 @@ HTMLEditor::DataTransferOrClipboardHasPrivateHTMLFlavor(
|
||||
// we know we have our own internal html format on clipboard.
|
||||
bool hasPrivateHTMLFlavor = false;
|
||||
AutoTArray<nsCString, 1> flavArray = {nsDependentCString(kHTMLContext)};
|
||||
rv = aClipboard->HasDataMatchingFlavors(
|
||||
nsresult rv = aClipboard->HasDataMatchingFlavors(
|
||||
flavArray, nsIClipboard::kGlobalClipboard, &hasPrivateHTMLFlavor);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsIClipboard::HasDataMatchingFlavors(nsIClipboard::"
|
||||
@@ -2375,10 +2366,9 @@ HTMLEditor::DataTransferOrClipboardHasPrivateHTMLFlavor(
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::HandlePaste(AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) {
|
||||
nsIClipboard::ClipboardType aClipboardType) {
|
||||
aEditActionData.InitializeDataTransferWithClipboard(
|
||||
SettingDataTransfer::eWithFormat, aDataTransfer, aClipboardType);
|
||||
SettingDataTransfer::eWithFormat, aClipboardType);
|
||||
nsresult rv = aEditActionData.CanHandleAndMaybeDispatchBeforeInputEvent();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING_ASSERTION(rv == NS_ERROR_EDITOR_ACTION_CANCELED,
|
||||
@@ -2390,13 +2380,12 @@ nsresult HTMLEditor::HandlePaste(AutoEditActionDataSetter& aEditActionData,
|
||||
if (NS_WARN_IF(!editingHost)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = PasteInternal(aClipboardType, aDataTransfer, *editingHost);
|
||||
rv = PasteInternal(aClipboardType, *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());
|
||||
|
||||
@@ -2425,10 +2414,14 @@ nsresult HTMLEditor::PasteInternal(nsIClipboard::ClipboardType aClipboardType,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Get the Data from the clipboard
|
||||
rv = GetDataFromDataTransferOrClipboard(aDataTransfer, transferable,
|
||||
aClipboardType);
|
||||
auto* windowContext = GetDocument()->GetWindowContext();
|
||||
if (!windowContext) {
|
||||
NS_WARNING("No window context");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = clipboard->GetData(transferable, aClipboardType, windowContext);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("EditorBase::GetDataFromDataTransferOrClipboard() failed");
|
||||
NS_WARNING("nsIClipboard::GetData() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -2438,7 +2431,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 =
|
||||
DataTransferOrClipboardHasPrivateHTMLFlavor(aDataTransfer, clipboard);
|
||||
ClipboardHasPrivateHTMLFlavor(clipboard);
|
||||
if (clipboardHasPrivateHTMLFlavor == HavePrivateHTMLFlavor::Yes) {
|
||||
nsCOMPtr<nsITransferable> contextTransferable =
|
||||
do_CreateInstance("@mozilla.org/widget/transferable;1");
|
||||
@@ -2455,8 +2448,10 @@ nsresult HTMLEditor::PasteInternal(nsIClipboard::ClipboardType aClipboardType,
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rvIgnored),
|
||||
"nsITransferable::AddDataFlavor(kHTMLContext) failed, but ignored");
|
||||
GetDataFromDataTransferOrClipboard(aDataTransfer, contextTransferable,
|
||||
aClipboardType);
|
||||
rvIgnored =
|
||||
clipboard->GetData(contextTransferable, aClipboardType, windowContext);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"nsIClipboard::GetData() failed, but ignored");
|
||||
nsCOMPtr<nsISupports> contextDataObj;
|
||||
rv = contextTransferable->GetTransferData(kHTMLContext,
|
||||
getter_AddRefs(contextDataObj));
|
||||
@@ -2485,8 +2480,10 @@ nsresult HTMLEditor::PasteInternal(nsIClipboard::ClipboardType aClipboardType,
|
||||
NS_SUCCEEDED(rvIgnored),
|
||||
"nsITransferable::AddDataFlavor(kHTMLInfo) failed, but ignored");
|
||||
|
||||
GetDataFromDataTransferOrClipboard(aDataTransfer, infoTransferable,
|
||||
aClipboardType);
|
||||
rvIgnored =
|
||||
clipboard->GetData(infoTransferable, aClipboardType, windowContext);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"nsIClipboard::GetData() failed, but ignored");
|
||||
nsCOMPtr<nsISupports> infoDataObj;
|
||||
rv = infoTransferable->GetTransferData(kHTMLInfo,
|
||||
getter_AddRefs(infoDataObj));
|
||||
@@ -2554,28 +2551,10 @@ nsresult HTMLEditor::HandlePasteTransferable(
|
||||
|
||||
nsresult HTMLEditor::PasteNoFormattingAsAction(
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DispatchPasteEvent aDispatchPasteEvent,
|
||||
DataTransfer* aDataTransfer /* = nullptr */,
|
||||
nsIPrincipal* aPrincipal /* = nullptr */) {
|
||||
DispatchPasteEvent aDispatchPasteEvent, nsIPrincipal* aPrincipal) {
|
||||
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 ? 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);
|
||||
@@ -2583,7 +2562,7 @@ nsresult HTMLEditor::PasteNoFormattingAsAction(
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
editActionData.InitializeDataTransferWithClipboard(
|
||||
SettingDataTransfer::eWithoutFormat, dataTransfer, aClipboardType);
|
||||
SettingDataTransfer::eWithoutFormat, aClipboardType);
|
||||
|
||||
if (aDispatchPasteEvent == DispatchPasteEvent::Yes) {
|
||||
RefPtr<nsFocusManager> focusManager = nsFocusManager::GetFocusManager();
|
||||
@@ -2592,22 +2571,14 @@ nsresult HTMLEditor::PasteNoFormattingAsAction(
|
||||
}
|
||||
const RefPtr<Element> focusedElement = focusManager->GetFocusedElement();
|
||||
|
||||
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());
|
||||
}
|
||||
Result<ClipboardEventResult, nsresult> ret =
|
||||
DispatchClipboardEventAndUpdateClipboard(ePasteNoFormatting,
|
||||
Some(aClipboardType));
|
||||
if (MOZ_UNLIKELY(ret.isErr())) {
|
||||
NS_WARNING(
|
||||
"EditorBase::DispatchClipboardEventAndUpdateClipboard("
|
||||
"ePasteNoFormatting) failed");
|
||||
return EditorBase::ToGenericNSResult(ret.unwrapErr());
|
||||
}
|
||||
switch (ret.inspect()) {
|
||||
case ClipboardEventResult::DoDefault:
|
||||
@@ -2636,17 +2607,17 @@ nsresult HTMLEditor::PasteNoFormattingAsAction(
|
||||
}
|
||||
if (editorBase != this) {
|
||||
if (editorBase->IsHTMLEditor()) {
|
||||
nsresult rv = MOZ_KnownLive(editorBase->AsHTMLEditor())
|
||||
->PasteNoFormattingAsAction(
|
||||
aClipboardType, DispatchPasteEvent::No,
|
||||
dataTransfer, aPrincipal);
|
||||
nsresult rv =
|
||||
MOZ_KnownLive(editorBase->AsHTMLEditor())
|
||||
->PasteNoFormattingAsAction(
|
||||
aClipboardType, DispatchPasteEvent::No, aPrincipal);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"HTMLEditor::PasteNoFormattingAsAction("
|
||||
"DispatchPasteEvent::No) failed");
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
}
|
||||
nsresult rv = editorBase->PasteAsAction(
|
||||
aClipboardType, DispatchPasteEvent::No, dataTransfer, aPrincipal);
|
||||
aClipboardType, DispatchPasteEvent::No, aPrincipal);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::PasteAsAction(DispatchPasteEvent::No) failed");
|
||||
@@ -2681,6 +2652,24 @@ 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()) {
|
||||
@@ -2694,10 +2683,11 @@ nsresult HTMLEditor::PasteNoFormattingAsAction(
|
||||
"ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
rv = GetDataFromDataTransferOrClipboard(dataTransfer, transferable,
|
||||
aClipboardType);
|
||||
|
||||
// Get the Data from the clipboard
|
||||
rv = clipboard->GetData(transferable, aClipboardType, windowContext);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("EditorBase::GetDataFromDataTransferOrClipboard() failed");
|
||||
NS_WARNING("nsIClipboard::GetData() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -2808,11 +2798,11 @@ bool HTMLEditor::CanPasteTransferable(nsITransferable* aTransferable) {
|
||||
|
||||
nsresult HTMLEditor::HandlePasteAsQuotation(
|
||||
AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType, DataTransfer* aDataTransfer) {
|
||||
nsIClipboard::ClipboardType aClipboardType) {
|
||||
MOZ_ASSERT(aClipboardType == nsIClipboard::kGlobalClipboard ||
|
||||
aClipboardType == nsIClipboard::kSelectionClipboard);
|
||||
aEditActionData.InitializeDataTransferWithClipboard(
|
||||
SettingDataTransfer::eWithFormat, aDataTransfer, aClipboardType);
|
||||
SettingDataTransfer::eWithFormat, aClipboardType);
|
||||
if (NS_WARN_IF(!aEditActionData.CanHandle())) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
@@ -2832,8 +2822,7 @@ nsresult HTMLEditor::HandlePasteAsQuotation(
|
||||
|
||||
if (IsPlaintextMailComposer() ||
|
||||
editingHost->IsContentEditablePlainTextOnly()) {
|
||||
nsresult rv =
|
||||
PasteAsPlaintextQuotation(aClipboardType, aDataTransfer, *editingHost);
|
||||
nsresult rv = PasteAsPlaintextQuotation(aClipboardType, *editingHost);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"HTMLEditor::PasteAsPlaintextQuotation() failed");
|
||||
return rv;
|
||||
@@ -2934,15 +2923,22 @@ nsresult HTMLEditor::HandlePasteAsQuotation(
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = PasteInternal(aClipboardType, aDataTransfer, *editingHost);
|
||||
rv = PasteInternal(aClipboardType, *editingHost);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::PasteInternal() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::PasteAsPlaintextQuotation(
|
||||
nsIClipboard::ClipboardType aSelectionType, DataTransfer* aDataTransfer,
|
||||
const Element& aEditingHost) {
|
||||
nsIClipboard::ClipboardType aSelectionType, const Element& aEditingHost) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Create generic Transferable for getting the data
|
||||
nsCOMPtr<nsITransferable> transferable =
|
||||
do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
|
||||
@@ -2974,8 +2970,9 @@ nsresult HTMLEditor::PasteAsPlaintextQuotation(
|
||||
"nsITransferable::AddDataFlavor(kTextMime) failed, but ignored");
|
||||
|
||||
// Get the Data from the clipboard
|
||||
GetDataFromDataTransferOrClipboard(aDataTransfer, transferable,
|
||||
aSelectionType);
|
||||
rvIgnored = clipboard->GetData(transferable, aSelectionType, windowContext);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"nsIClipboard::GetData() failed, but ignored");
|
||||
|
||||
// Now we ask the transferable for the data
|
||||
// it still owns the data, we just have a pointer to it.
|
||||
|
||||
@@ -565,13 +565,22 @@ bool TextEditor::IsCopyToClipboardAllowedInternal() const {
|
||||
|
||||
nsresult TextEditor::HandlePasteAsQuotation(
|
||||
AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType, DataTransfer* aDataTransfer) {
|
||||
nsIClipboard::ClipboardType aClipboardType) {
|
||||
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
|
||||
@@ -589,9 +598,13 @@ 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
|
||||
nsresult rv =
|
||||
GetDataFromDataTransferOrClipboard(aDataTransfer, trans, aClipboardType);
|
||||
rv = clipboard->GetData(trans, aClipboardType, windowContext);
|
||||
|
||||
// Now we ask the transferable for the data
|
||||
// it still owns the data, we just have a pointer to it.
|
||||
|
||||
@@ -465,8 +465,9 @@ class TextEditor final : public EditorBase,
|
||||
SelectionHandling aSelectionHandling) final;
|
||||
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertDroppedDataTransferAsAction(
|
||||
AutoEditActionDataSetter& aEditActionData, DataTransfer& aDataTransfer,
|
||||
const EditorDOMPoint& aDroppedAt, nsIPrincipal* aSourcePrincipal) final;
|
||||
AutoEditActionDataSetter& aEditActionData,
|
||||
dom::DataTransfer& aDataTransfer, const EditorDOMPoint& aDroppedAt,
|
||||
nsIPrincipal* aSourcePrincipal) final;
|
||||
|
||||
/**
|
||||
* HandleDeleteSelectionInternal() is a helper method of
|
||||
@@ -567,12 +568,10 @@ class TextEditor final : public EditorBase,
|
||||
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
HandlePaste(AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) final;
|
||||
nsIClipboard::ClipboardType aClipboardType) final;
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
HandlePasteAsQuotation(AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) final;
|
||||
nsIClipboard::ClipboardType aClipboardType) final;
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
HandlePasteTransferable(AutoEditActionDataSetter& aEditActionData,
|
||||
nsITransferable& aTransferable) final;
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
#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"
|
||||
@@ -162,8 +161,7 @@ nsresult TextEditor::InsertDroppedDataTransferAsAction(
|
||||
}
|
||||
|
||||
nsresult TextEditor::HandlePaste(AutoEditActionDataSetter& aEditActionData,
|
||||
nsIClipboard::ClipboardType aClipboardType,
|
||||
DataTransfer* aDataTransfer) {
|
||||
nsIClipboard::ClipboardType aClipboardType) {
|
||||
if (NS_WARN_IF(!GetDocument())) {
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -195,13 +193,17 @@ nsresult TextEditor::HandlePaste(AutoEditActionDataSetter& aEditActionData,
|
||||
return NS_OK; // XXX Why?
|
||||
}
|
||||
// Get the Data from the clipboard.
|
||||
rv = GetDataFromDataTransferOrClipboard(aDataTransfer, transferable,
|
||||
aClipboardType);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("EditorBase::GetDataFromDataTransferOrClipboard() failed");
|
||||
return rv;
|
||||
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);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsIClipboard::GetData() failed, but ignored");
|
||||
return NS_OK; // XXX Why?
|
||||
}
|
||||
// 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, nullptr);
|
||||
presShell, nullptr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,16 +6,6 @@ support-files = [
|
||||
|
||||
["browser_clipboard_content_analysis.js"]
|
||||
|
||||
["browser_clipboard_paste_changingclipboardexternal_content_analysis.js"]
|
||||
support-files = [
|
||||
"clipboard_paste_changingclipboardexternal.html",
|
||||
]
|
||||
|
||||
["browser_clipboard_paste_changingclipboardinternal_content_analysis.js"]
|
||||
support-files = [
|
||||
"clipboard_paste_changingclipboardinternal.html",
|
||||
]
|
||||
|
||||
["browser_clipboard_paste_file_content_analysis.js"]
|
||||
support-files = [
|
||||
"clipboard_paste_file.html",
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let mockCA = makeMockContentAnalysis();
|
||||
|
||||
add_setup(async function test_setup() {
|
||||
mockCA = await mockContentAnalysisService(mockCA);
|
||||
});
|
||||
|
||||
const PAGE_URL =
|
||||
"https://example.com/browser/toolkit/components/contentanalysis/tests/browser/clipboard_paste_changingclipboardexternal.html";
|
||||
const CLIPBOARD_TEXT_STRING_ORIGINAL = "Original text";
|
||||
const CLIPBOARD_TEXT_STRING_NEW = "New text";
|
||||
|
||||
// Test that if the clipboard contents change externally (i.e. the user
|
||||
// does a copy from some other application) while Content Analysis is ongoing,
|
||||
// the new contents are ignored and the original contents of the clipboard
|
||||
// are put in the DOM element.
|
||||
add_task(async function testClipboardPasteWithContentAnalysis() {
|
||||
mockCA.setupForTest(true, true);
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE_URL);
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
await testPasteWithElementId("testDiv", browser);
|
||||
await testPasteWithElementId("testInput", browser);
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
function setClipboardData(clipboardString) {
|
||||
const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(
|
||||
Ci.nsITransferable
|
||||
);
|
||||
trans.init(null);
|
||||
trans.addDataFlavor("text/plain");
|
||||
const str = Cc["@mozilla.org/supports-string;1"].createInstance(
|
||||
Ci.nsISupportsString
|
||||
);
|
||||
str.data = clipboardString;
|
||||
trans.setTransferData("text/plain", str);
|
||||
|
||||
// Write to clipboard.
|
||||
Services.clipboard.setData(trans, null, Ci.nsIClipboard.kGlobalClipboard);
|
||||
}
|
||||
|
||||
async function testPasteWithElementId(elementId, browser) {
|
||||
setClipboardData(CLIPBOARD_TEXT_STRING_ORIGINAL);
|
||||
let resultPromise = SpecialPowers.spawn(browser, [], () => {
|
||||
return new Promise(resolve => {
|
||||
content.document.addEventListener(
|
||||
"testresult",
|
||||
event => {
|
||||
resolve(event.detail.result);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// Paste into content
|
||||
await SpecialPowers.spawn(browser, [elementId], async elementId => {
|
||||
content.document.getElementById(elementId).focus();
|
||||
});
|
||||
let doPastePromise = BrowserTestUtils.synthesizeKey(
|
||||
"v",
|
||||
{ accelKey: true },
|
||||
browser
|
||||
);
|
||||
// While scan is ongoing, set clipboard to new value
|
||||
await new Promise(res => {
|
||||
mockCA.eventTarget.addEventListener(
|
||||
"inAnalyzeContentRequest",
|
||||
() => {
|
||||
res();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
setClipboardData(CLIPBOARD_TEXT_STRING_NEW);
|
||||
// We don't expect another CA call, but set this so that if we get one
|
||||
// we'll get a test failure rather than an annoying-to-debug timeout.
|
||||
mockCA.waitForEvent = false;
|
||||
mockCA.eventTarget.dispatchEvent(
|
||||
new CustomEvent("returnContentAnalysisResponse")
|
||||
);
|
||||
await doPastePromise;
|
||||
let result = await resultPromise;
|
||||
is(result, undefined, "Got unexpected result from page");
|
||||
|
||||
is(mockCA.calls.length, 1, "Correct number of calls to Content Analysis");
|
||||
assertContentAnalysisRequest(mockCA.calls[0], CLIPBOARD_TEXT_STRING_ORIGINAL);
|
||||
mockCA.clearCalls();
|
||||
let value = await getElementValue(browser, elementId);
|
||||
// Since the clipboard was set externally during the content analysis call,
|
||||
// it should not be set in the HTML element (and the original value
|
||||
// should be used). This is to prevent cases where the user pastes some
|
||||
// content in the page, content analysis is taking a while, and they move
|
||||
// on to do something else on their machine and copy some sensitive data
|
||||
// like a password for use elsewhere - in this case we don't want the page
|
||||
// to see that sensitive data.
|
||||
is(value, CLIPBOARD_TEXT_STRING_ORIGINAL, "element has correct value");
|
||||
mockCA.waitForEvent = true;
|
||||
}
|
||||
|
||||
function assertContentAnalysisRequest(request, expectedText) {
|
||||
is(request.url.spec, PAGE_URL, "request has correct URL");
|
||||
is(
|
||||
request.analysisType,
|
||||
Ci.nsIContentAnalysisRequest.eBulkDataEntry,
|
||||
"request has correct analysisType"
|
||||
);
|
||||
is(
|
||||
request.operationTypeForDisplay,
|
||||
Ci.nsIContentAnalysisRequest.eClipboard,
|
||||
"request has correct operationTypeForDisplay"
|
||||
);
|
||||
is(request.filePath, "", "request filePath should match");
|
||||
is(request.textContent, expectedText, "request textContent should match");
|
||||
is(request.printDataHandle, 0, "request printDataHandle should not be 0");
|
||||
is(request.printDataSize, 0, "request printDataSize should not be 0");
|
||||
ok(!!request.requestToken.length, "request requestToken should not be empty");
|
||||
}
|
||||
|
||||
async function getElementValue(browser, elementId) {
|
||||
return await SpecialPowers.spawn(browser, [elementId], async elementId => {
|
||||
let element = content.document.getElementById(elementId);
|
||||
return element.value ?? element.innerText;
|
||||
});
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let mockCA = makeMockContentAnalysis();
|
||||
|
||||
add_setup(async function test_setup() {
|
||||
mockCA = await mockContentAnalysisService(mockCA);
|
||||
});
|
||||
|
||||
const PAGE_URL =
|
||||
"https://example.com/browser/toolkit/components/contentanalysis/tests/browser/clipboard_paste_changingclipboardinternal.html";
|
||||
const CLIPBOARD_TEXT_STRING_ORIGINAL = "Original text";
|
||||
const CLIPBOARD_TEXT_STRING_NEW = "New text";
|
||||
|
||||
// Test that if the JS paste event handler changes the clipboard contents
|
||||
// while Content Analysis is ongoing, the new contents are properly put
|
||||
// in the DOM element. (whether a new CA scan is done or not depends on
|
||||
// the browser.contentanalysis.bypass_for_same_tab_operations pref)
|
||||
async function testClipboardPasteWithContentAnalysis(bypassForSameTab) {
|
||||
mockCA.setupForTest(true);
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[
|
||||
"browser.contentanalysis.bypass_for_same_tab_operations",
|
||||
bypassForSameTab,
|
||||
],
|
||||
],
|
||||
});
|
||||
registerCleanupFunction(async function () {
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE_URL);
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
await testPasteWithElementId("testDiv", browser, bypassForSameTab);
|
||||
await testPasteWithElementId("testInput", browser, bypassForSameTab);
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
|
||||
add_task(
|
||||
async function testClipboardPasteWithContentAnalysisWithBypassForSameTab() {
|
||||
await testClipboardPasteWithContentAnalysis(true);
|
||||
}
|
||||
);
|
||||
|
||||
add_task(
|
||||
async function testClipboardPasteWithContentAnalysisWithNoBypassForSameTab() {
|
||||
await testClipboardPasteWithContentAnalysis(false);
|
||||
}
|
||||
);
|
||||
|
||||
function setClipboardData(clipboardString) {
|
||||
const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(
|
||||
Ci.nsITransferable
|
||||
);
|
||||
trans.init(null);
|
||||
trans.addDataFlavor("text/plain");
|
||||
const str = Cc["@mozilla.org/supports-string;1"].createInstance(
|
||||
Ci.nsISupportsString
|
||||
);
|
||||
str.data = clipboardString;
|
||||
trans.setTransferData("text/plain", str);
|
||||
|
||||
// Write to clipboard.
|
||||
Services.clipboard.setData(trans, null, Ci.nsIClipboard.kGlobalClipboard);
|
||||
}
|
||||
|
||||
async function testPasteWithElementId(elementId, browser, bypassForSameTab) {
|
||||
setClipboardData(CLIPBOARD_TEXT_STRING_ORIGINAL);
|
||||
let resultPromise = SpecialPowers.spawn(browser, [], () => {
|
||||
return new Promise(resolve => {
|
||||
content.document.addEventListener(
|
||||
"testresult",
|
||||
event => {
|
||||
resolve(event.detail.result);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// Paste into content
|
||||
await SpecialPowers.spawn(browser, [elementId], async elementId => {
|
||||
content.document.getElementById(elementId).focus();
|
||||
});
|
||||
await BrowserTestUtils.synthesizeKey("v", { accelKey: true }, browser);
|
||||
let result = await resultPromise;
|
||||
is(result, undefined, "Got unexpected result from page");
|
||||
|
||||
is(
|
||||
mockCA.calls.length,
|
||||
bypassForSameTab ? 1 : 2,
|
||||
"Correct number of calls to Content Analysis"
|
||||
);
|
||||
assertContentAnalysisRequest(mockCA.calls[0], CLIPBOARD_TEXT_STRING_ORIGINAL);
|
||||
if (!bypassForSameTab) {
|
||||
assertContentAnalysisRequest(mockCA.calls[1], CLIPBOARD_TEXT_STRING_NEW);
|
||||
}
|
||||
// Note that if bypassForSameTab is true we don't expect to check CLIPBOARD_TEXT_STRING_NEW
|
||||
// since it was set from the webpage.
|
||||
mockCA.clearCalls();
|
||||
let value = await getElementValue(browser, elementId);
|
||||
// Since the clipboard was set during the paste event, that new
|
||||
// value should get set in the HTML element.
|
||||
is(value, CLIPBOARD_TEXT_STRING_NEW, "element has correct value");
|
||||
}
|
||||
|
||||
function assertContentAnalysisRequest(request, expectedText) {
|
||||
is(request.url.spec, PAGE_URL, "request has correct URL");
|
||||
is(
|
||||
request.analysisType,
|
||||
Ci.nsIContentAnalysisRequest.eBulkDataEntry,
|
||||
"request has correct analysisType"
|
||||
);
|
||||
is(
|
||||
request.operationTypeForDisplay,
|
||||
Ci.nsIContentAnalysisRequest.eClipboard,
|
||||
"request has correct operationTypeForDisplay"
|
||||
);
|
||||
is(request.filePath, "", "request filePath should match");
|
||||
is(request.textContent, expectedText, "request textContent should match");
|
||||
is(request.printDataHandle, 0, "request printDataHandle should not be 0");
|
||||
is(request.printDataSize, 0, "request printDataSize should not be 0");
|
||||
ok(!!request.requestToken.length, "request requestToken should not be empty");
|
||||
}
|
||||
|
||||
async function getElementValue(browser, elementId) {
|
||||
return await SpecialPowers.spawn(browser, [elementId], async elementId => {
|
||||
let element = content.document.getElementById(elementId);
|
||||
return element.value ?? element.innerText;
|
||||
});
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<div id="content">
|
||||
<div
|
||||
id="testDiv"
|
||||
contenteditable="true"
|
||||
onpaste="handlePaste(event)"></div>
|
||||
<input id="testInput" type="text" onpaste="handlePaste(event)">
|
||||
</div>
|
||||
<script class="testbody" type="application/javascript">
|
||||
function is(a, b, msg) {
|
||||
if (!Object.is(a, b)) {
|
||||
throw new Error(`FAIL: expected ${b} got ${a} - ${msg}`);
|
||||
}
|
||||
}
|
||||
|
||||
function checkPasteHelper(event) {
|
||||
is(event.clipboardData.getData('text/plain'), "Original text", "getData(text/plain) should return Original text");
|
||||
is(event.clipboardData.types.length, 1, "Correct number of types");
|
||||
}
|
||||
|
||||
function handlePaste(e) {
|
||||
let result = null;
|
||||
try {
|
||||
result = checkPasteHelper(e);
|
||||
} catch (e) {
|
||||
result = e.toString();
|
||||
}
|
||||
|
||||
document.dispatchEvent(new CustomEvent('testresult', {
|
||||
detail: { result }
|
||||
}));
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,44 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<div id="content">
|
||||
<div
|
||||
id="testDiv"
|
||||
contenteditable="true"
|
||||
onpaste="handlePaste(event)"></div>
|
||||
<input id="testInput" type="text" onpaste="handlePaste(event)">
|
||||
</div>
|
||||
<script class="testbody" type="application/javascript">
|
||||
function is(a, b, msg) {
|
||||
if (!Object.is(a, b)) {
|
||||
throw new Error(`FAIL: expected ${b} got ${a} - ${msg}`);
|
||||
}
|
||||
}
|
||||
|
||||
function checkPasteHelper(event) {
|
||||
is(event.clipboardData.getData('text/plain'), "Original text", "getData(text/plain) should return Original text");
|
||||
is(event.clipboardData.types.length, 1, "Correct number of types");
|
||||
document.execCommand("copy");
|
||||
}
|
||||
|
||||
document.addEventListener("copy", e => {
|
||||
e.preventDefault();
|
||||
e.clipboardData.setData("text/plain", "New text");
|
||||
});
|
||||
|
||||
function handlePaste(e) {
|
||||
let result = null;
|
||||
try {
|
||||
result = checkPasteHelper(e);
|
||||
} catch (e) {
|
||||
result = e.toString();
|
||||
}
|
||||
|
||||
document.dispatchEvent(new CustomEvent('testresult', {
|
||||
detail: { result }
|
||||
}));
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -133,24 +133,10 @@ function makeMockContentAnalysis() {
|
||||
isActive: true,
|
||||
mightBeActive: true,
|
||||
errorValue: undefined,
|
||||
waitForEventToFinish: false,
|
||||
// This is a dummy event target that uses custom events for bidirectional
|
||||
// communication between the individual test and the mock CA object.
|
||||
// Events are:
|
||||
// inAnalyzeContentRequest:
|
||||
// If waitForEvent was true, this is sent by mock CA when its
|
||||
// AnalyzeContentRequest is ready to issue a response. It will wait
|
||||
// for returnContentAnalysisResponse to be received before issuing
|
||||
// the response.
|
||||
// returnContentAnalysisResponse:
|
||||
// If waitForEvent was true, this must be sent by the test to tell
|
||||
// AnalyzeContentRequest to issue its response.
|
||||
eventTarget: new EventTarget(),
|
||||
|
||||
setupForTest(shouldAllowRequest, waitForEvent) {
|
||||
setupForTest(shouldAllowRequest) {
|
||||
this.shouldAllowRequest = shouldAllowRequest;
|
||||
this.errorValue = undefined;
|
||||
this.waitForEvent = !!waitForEvent;
|
||||
this.clearCalls();
|
||||
},
|
||||
|
||||
@@ -187,21 +173,6 @@ function makeMockContentAnalysis() {
|
||||
}
|
||||
// Use setTimeout to simulate an async activity
|
||||
await new Promise(res => setTimeout(res, 0));
|
||||
if (this.waitForEvent) {
|
||||
let waitPromise = new Promise(res => {
|
||||
this.eventTarget.addEventListener(
|
||||
"returnContentAnalysisResponse",
|
||||
() => {
|
||||
res();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
this.eventTarget.dispatchEvent(
|
||||
new CustomEvent("inAnalyzeContentRequest")
|
||||
);
|
||||
await waitPromise;
|
||||
}
|
||||
return makeContentAnalysisResponse(
|
||||
this.getAction(),
|
||||
request.requestToken
|
||||
@@ -213,9 +184,7 @@ function makeMockContentAnalysis() {
|
||||
"Mock ContentAnalysis service: analyzeContentRequestCallback, this.shouldAllowRequest=" +
|
||||
this.shouldAllowRequest +
|
||||
", this.errorValue=" +
|
||||
this.errorValue +
|
||||
", this.waitForEvent=" +
|
||||
this.waitForEvent
|
||||
this.errorValue
|
||||
);
|
||||
this.calls.push(request);
|
||||
if (this.errorValue) {
|
||||
@@ -225,21 +194,6 @@ function makeMockContentAnalysis() {
|
||||
// Use setTimeout to simulate an async activity (and because IOUtils.stat
|
||||
// is async).
|
||||
setTimeout(async () => {
|
||||
if (this.waitForEvent) {
|
||||
let waitPromise = new Promise(res => {
|
||||
this.eventTarget.addEventListener(
|
||||
"returnContentAnalysisResponse",
|
||||
() => {
|
||||
res();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
this.eventTarget.dispatchEvent(
|
||||
new CustomEvent("inAnalyzeContentRequest")
|
||||
);
|
||||
await waitPromise;
|
||||
}
|
||||
let isDir = false;
|
||||
try {
|
||||
isDir = (await IOUtils.stat(request.filePath)).type == "directory";
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsITransferable.h"
|
||||
#include "nsThreadManager.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
|
||||
using mozilla::dom::ContentParent;
|
||||
@@ -116,20 +115,9 @@ IPCResult ClipboardReadRequestParent::RecvGetData(
|
||||
IPCResult ClipboardReadRequestParent::RecvGetDataSync(
|
||||
const nsTArray<nsCString>& aFlavors,
|
||||
dom::IPCTransferableDataOrError* aTransferableDataOrError) {
|
||||
auto destroySoon = [&] {
|
||||
// Delete this actor, but don't do it in the middle of this sync IPC call
|
||||
// Make sure nothing else gets processed before this deletion, so use
|
||||
// DispatchDirectTaskToCurrentThread()
|
||||
RefPtr<nsIRunnable> task = NS_NewRunnableFunction(
|
||||
"ClipboardReadRequestParent_SyncError", [self = RefPtr{this}]() {
|
||||
Unused << PClipboardReadRequestParent::Send__delete__(self);
|
||||
});
|
||||
nsThreadManager::get().DispatchDirectTaskToCurrentThread(task);
|
||||
};
|
||||
|
||||
bool valid = false;
|
||||
if (NS_FAILED(mClipboardDataSnapshot->GetValid(&valid)) || !valid) {
|
||||
destroySoon();
|
||||
Unused << PClipboardReadRequestParent::Send__delete__(this);
|
||||
*aTransferableDataOrError = NS_ERROR_FAILURE;
|
||||
return IPC_OK();
|
||||
}
|
||||
@@ -146,7 +134,7 @@ IPCResult ClipboardReadRequestParent::RecvGetDataSync(
|
||||
if (NS_FAILED(rv)) {
|
||||
*aTransferableDataOrError = rv;
|
||||
if (NS_FAILED(mClipboardDataSnapshot->GetValid(&valid)) || !valid) {
|
||||
destroySoon();
|
||||
Unused << PClipboardReadRequestParent::Send__delete__(this);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user