From 18e36b497a691445fa5e9e8205f6ca23a7cf2d9d Mon Sep 17 00:00:00 2001 From: Michael Layzell Date: Wed, 6 Sep 2017 11:26:50 -0400 Subject: [PATCH] Bug 1199729 - Part 3: Clear the DataTransfer after handling Drag and Clipboard events, r=baku --- dom/base/nsCopySupport.cpp | 17 ++++++++++------- dom/events/EventStateManager.cpp | 27 ++++++++++++++++++++------- layout/base/PresShell.cpp | 17 +++++++++++++++++ 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/dom/base/nsCopySupport.cpp b/dom/base/nsCopySupport.cpp index 99b6af473f30..98e0e1c9247d 100644 --- a/dom/base/nsCopySupport.cpp +++ b/dom/base/nsCopySupport.cpp @@ -840,17 +840,20 @@ nsCopySupport::FireClipboardEvent(EventMessage aEventMessage, doDefault = (status != nsEventStatus_eConsumeNoDefault); } + // When this function exits, the event dispatch is over. We want to disconnect + // our DataTransfer, which means setting its mode to `Protected` and clearing + // all stored data, before we return. + auto clearAfter = MakeScopeExit([&] { + if (clipboardData) { + clipboardData->SetMode(DataTransfer::Mode::Protected); + clipboardData->ClearAll(); + } + }); + // No need to do anything special during a paste. Either an event listener // took care of it and cancelled the event, or the caller will handle it. // Return true to indicate that the event wasn't cancelled. if (originalEventMessage == ePaste) { - // Clear and mark the clipboardData as readonly. This prevents someone - // from reading the clipboard contents after the paste event has fired. - if (clipboardData) { - clipboardData->ClearAll(); - clipboardData->SetMode(DataTransfer::Mode::Protected); - } - if (aActionTaken) { *aActionTaken = true; } diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index a7b9a8e4ec5b..d4988af9e5a8 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -1772,6 +1772,12 @@ EventStateManager::GenerateDragGesture(nsPresContext* aPresContext, RefPtr dataTransfer = new DataTransfer(window, eDragStart, false, -1); + auto protectDataTransfer = MakeScopeExit([&] { + if (dataTransfer) { + dataTransfer->SetMode(DataTransfer::Mode::Protected); + dataTransfer->ClearAll(); + } + }); nsCOMPtr selection; nsCOMPtr eventContent, targetContent; @@ -1839,11 +1845,6 @@ EventStateManager::GenerateDragGesture(nsPresContext* aPresContext, nullptr); } - // now that the dataTransfer has been updated in the dragstart and - // draggesture events, make it read only so that the data doesn't - // change during the drag. - dataTransfer->SetMode(DataTransfer::Mode::ReadOnly); - if (status != nsEventStatus_eConsumeNoDefault) { bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer, targetContent, selection); @@ -2006,6 +2007,18 @@ EventStateManager::DoDefaultDragStart(nsPresContext* aPresContext, if (!transArray) return false; + // After this function returns, the DataTransfer will be cleared so it appears + // empty to content. We need to pass a DataTransfer into the Drag Session, so + // we need to make a copy. + RefPtr dataTransfer; + aDataTransfer->Clone(aDragTarget, eDrop, aDataTransfer->MozUserCancelled(), + false, getter_AddRefs(dataTransfer)); + + // Copy over the drop effect, as Clone doesn't copy it for us. + uint32_t dropEffect; + aDataTransfer->GetDropEffectInt(&dropEffect); + dataTransfer->SetDropEffectInt(dropEffect); + // XXXndeakin don't really want to create a new drag DOM event // here, but we need something to pass to the InvokeDragSession // methods. @@ -2018,7 +2031,7 @@ EventStateManager::DoDefaultDragStart(nsPresContext* aPresContext, // other than a selection is being dragged. if (!dragImage && aSelection) { dragService->InvokeDragSessionWithSelection(aSelection, transArray, - action, event, aDataTransfer); + action, event, dataTransfer); } else { // if dragging within a XUL tree and no custom drag image was @@ -2045,7 +2058,7 @@ EventStateManager::DoDefaultDragStart(nsPresContext* aPresContext, dragImage ? dragImage->AsDOMNode() : nullptr, imageX, imageY, event, - aDataTransfer); + dataTransfer); } return true; diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index 5d4c117f21d8..9b1710cc4b58 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -8242,6 +8242,23 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, case eMouseMove: nsIPresShell::AllowMouseCapture(false); break; + case eDrag: + case eDragEnd: + case eDragEnter: + case eDragExit: + case eDragLeave: + case eDragOver: + case eDrop: { + // After any drag event other than dragstart (which is handled separately, + // as we need to collect the data first), the DataTransfer needs to be + // made protected, and then disconnected. + DataTransfer* dataTransfer = aEvent->AsDragEvent()->mDataTransfer; + if (dataTransfer) { + dataTransfer->SetMode(DataTransfer::Mode::Protected); + dataTransfer->ClearAll(); + } + break; + } default: break; }