+2017-10-08 Ryosuke Niwa <rniwa@webkit.org>
+
+ dragenter and dragleave shouldn't use the same data transfer object
+ https://bugs.webkit.org/show_bug.cgi?id=178056
+
+ Reviewed by Darin Adler.
+
+ Added a regression test for checking the uniqueness of dataTransfer object for dragenter and dragleave events.
+ Unfortunately, the test is only runnable in Mac WebKit1 port due to the lack of support in WebKitTestRunner.
+
+ * TestExpectations:
+ * editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave-expected.txt: Added.
+ * editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave.html: Added.
+ * platform/mac-wk1/TestExpectations:
+
2017-10-08 Jer Noble <jer.noble@apple.com>
SourceBuffer remove throws out way more content than requested
editing/pasteboard/data-transfer-get-data-on-drop-plain-text.html [ Skip ]
editing/pasteboard/data-transfer-get-data-on-drop-rich-text.html [ Skip ]
editing/pasteboard/data-transfer-get-data-on-drop-url.html [ Skip ]
+editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave.html [ Skip ]
editing/pasteboard/drag-end-crash-accessing-item-list.html [ Skip ]
editing/pasteboard/data-transfer-item-list-add-file-on-drag.html [ Skip ]
--- /dev/null
+PASS dragstart for source had an unique dataTransfer object
+PASS dragenter for passover had an unique dataTransfer object
+PASS dragenter for destination had an unique dataTransfer object
+PASS dragleave for passover had an unique dataTransfer object
+PASS dragover for destination had an unique dataTransfer object
+PASS drop for destination had an unique dataTransfer object
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+<body>
+<style>
+#container > div { width: 100px; height: 50px; margin: 0px; }
+</style>
+<p id="description"></p>
+<div id="container">
+<div draggable="true" id="source" style="background: #9cf">Drag this</div>
+<div id="passover" style="background: #ff9">Drag over here</div>
+<div id="destination" style="background: #fc9">And drop here</div>
+</div>
+<div id="console"></div>
+<script src="../../resources/js-test-pre.js"></script>
+<script>
+
+var jsTestIsAsync = true;
+
+source.addEventListener("dragstart", (event) => {
+ event.dataTransfer.effectAllowed = 'copy';
+ event.dataTransfer.setData('text', 'hello, world');
+ dataTransferMap.clear();
+ testUniquenessAndAdd(event.dataTransfer, 'source', 'dragstart');
+});
+
+const dataTransferMap = new Map;
+function testUniquenessAndAdd(dataTransfer, label, eventType) {
+ const existingEntry = dataTransferMap.get(dataTransfer);
+ if (existingEntry) {
+ testFailed(`${eventType} for ${label} had the same dataTransfer object as ${existingEntry.eventType} for ${existingEntry.label}`);
+ return;
+ }
+ testPassed(`${eventType} for ${label} had an unique dataTransfer object`);
+ dataTransferMap.set(dataTransfer, {label, eventType});
+}
+
+passover.addEventListener("dragenter", (event) => {
+ testUniquenessAndAdd(event.dataTransfer, 'passover', 'dragenter');
+});
+passover.addEventListener("dragleave", (event) => {
+ testUniquenessAndAdd(event.dataTransfer, 'passover', 'dragleave');
+});
+destination.addEventListener("dragenter", (event) => {
+ testUniquenessAndAdd(event.dataTransfer, 'destination', 'dragenter');
+});
+destination.addEventListener("dragleave", (event) => {
+ testUniquenessAndAdd(event.dataTransfer, 'destination', 'dragleave');
+});
+destination.addEventListener("dragover", (event) => {
+ testUniquenessAndAdd(event.dataTransfer, 'destination', 'dragover');
+ event.preventDefault();
+});
+destination.addEventListener("drop", (event) => {
+ testUniquenessAndAdd(event.dataTransfer, 'destination', 'drop');
+ finishJSTest();
+});
+
+if (window.eventSender) {
+ eventSender.mouseMoveTo(source.offsetLeft + 10, source.offsetTop + 10);
+ eventSender.mouseDown();
+ eventSender.leapForward(500);
+ eventSender.mouseMoveTo(passover.offsetLeft + 10, passover.offsetTop + 10);
+ eventSender.leapForward(100);
+ eventSender.mouseMoveTo(destination.offsetLeft + 10, destination.offsetTop + 10);
+ eventSender.mouseUp();
+ document.getElementById('container').remove();
+}
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
editing/pasteboard/data-transfer-get-data-on-drop-plain-text.html [ Pass ]
editing/pasteboard/data-transfer-get-data-on-drop-rich-text.html [ Pass ]
editing/pasteboard/data-transfer-get-data-on-drop-url.html [ Pass ]
+editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave.html [ Pass ]
editing/pasteboard/drag-end-crash-accessing-item-list.html [ Pass ]
editing/pasteboard/data-transfer-item-list-add-file-on-drag.html [ Pass ]
webkit.org/b/116564 editing/pasteboard/copy-without-selection.html [ Skip ]
editing/pasteboard/smart-paste-004.html [ Failure ]
# TODO Drag & Drop doesn't work correctly in DRT <rdar://5621244>
+editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave.html [ Skip ]
editing/pasteboard/drag-and-drop-objectimage-contenteditable.html [ Skip ]
editing/pasteboard/drag-image-in-about-blank-frame.html [ Skip ]
editing/pasteboard/drop-file-svg.html [ Skip ]
+2017-10-08 Ryosuke Niwa <rniwa@webkit.org>
+
+ dragenter and dragleave shouldn't use the same data transfer object
+ https://bugs.webkit.org/show_bug.cgi?id=178056
+
+ Reviewed by Darin Adler.
+
+ This patch fixes the bug that we were using a single DataTransfer to fire dragleave and dragenter events
+ when the drag target moves from one element to another.
+
+ It alos refactors DragController and EventHandler code so that the construction of DataTransfer object
+ happens in EventHandler instead of DragController, and extracts createForUpdatingDropTarget out of
+ createForDrop to have a better encapsulation over the data store mode.
+
+ drag related functions in EventHandler now takes std::unique_ptr<Pasteboard>&&, drag operation mask set
+ by the drag source, and a boolean indicating whether this drag & drop is for files or not. updateDragAndDrop
+ takes a closure which makes a pasteboard because it has to create two instances of DataTransfer one for
+ dragleave event and another one for dragenter event in some cases.
+
+ Test: editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave.html
+
+ * dom/DataTransfer.cpp:
+ (WebCore::DataTransfer::createForDrop): Now takes Pasteboard instead of DragData.
+ (WebCore::DataTransfer::createForUpdatingDropTarget): Extracted out of createForDrop. Moved the code to
+ use Readonly mode in dashboad here from createDataTransferToUpdateDrag in DragController.cpp.
+ * dom/DataTransfer.h:
+ * page/DragController.cpp:
+ (WebCore::createDataTransferToUpdateDrag): Deleted.
+ (WebCore::DragController::dragExited):
+ (WebCore::DragController::performDragOperation):
+ (WebCore::DragController::tryDHTMLDrag):
+ * page/EventHandler.cpp:
+ (WebCore::EventHandler::dispatchDragEvent): Made this fucntion take DataTransfer& instead of DataTransfer*.
+ (WebCore::findDropZone): Ditto.
+ (WebCore::EventHandler::dispatchDragEnterOrDragOverEvent): Added.
+ (WebCore::EventHandler::updateDragAndDrop):
+ (WebCore::EventHandler::cancelDragAndDrop):
+ (WebCore::EventHandler::performDragAndDrop):
+ (WebCore::EventHandler::dispatchDragSrcEvent):
+ (WebCore::EventHandler::dispatchDragStartEventOnSourceElement):
+ * page/EventHandler.h:
+
2017-10-08 Jer Noble <jer.noble@apple.com>
SourceBuffer remove throws out way more content than requested
return adoptRef(*new DataTransfer(StoreMode::ReadWrite, std::make_unique<StaticPasteboard>(), Type::DragAndDropData));
}
-Ref<DataTransfer> DataTransfer::createForDrop(StoreMode accessMode, const DragData& dragData)
+Ref<DataTransfer> DataTransfer::createForDrop(std::unique_ptr<Pasteboard>&& pasteboard, DragOperation sourceOperation, bool draggingFiles)
{
- auto type = dragData.containsFiles() ? Type::DragAndDropFiles : Type::DragAndDropData;
- return adoptRef(*new DataTransfer(accessMode, Pasteboard::createForDragAndDrop(dragData), type));
+ auto dataTransfer = adoptRef(*new DataTransfer(DataTransfer::StoreMode::Readonly, WTFMove(pasteboard), draggingFiles ? Type::DragAndDropFiles : Type::DragAndDropData));
+ dataTransfer->setSourceOperation(sourceOperation);
+ return dataTransfer;
+}
+
+Ref<DataTransfer> DataTransfer::createForUpdatingDropTarget(Document& document, std::unique_ptr<Pasteboard>&& pasteboard, DragOperation sourceOperation, bool draggingFiles)
+{
+ auto mode = DataTransfer::StoreMode::Protected;
+#if ENABLE(DASHBOARD_SUPPORT)
+ if (document.settings().usesDashboardBackwardCompatibilityMode() && document.securityOrigin().isLocal())
+ mode = DataTransfer::StoreMode::Readonly;
+#else
+ UNUSED_PARAM(document);
+#endif
+ auto dataTransfer = adoptRef(*new DataTransfer(mode, WTFMove(pasteboard), draggingFiles ? Type::DragAndDropFiles : Type::DragAndDropData));
+ dataTransfer->setSourceOperation(sourceOperation);
+ return dataTransfer;
}
void DataTransfer::setDragImage(Element* element, int x, int y)
class CachedImage;
class DataTransferItemList;
+class Document;
class DragData;
class DragImageLoader;
class Element;
#if ENABLE(DRAG_SUPPORT)
static Ref<DataTransfer> createForDrag();
static Ref<DataTransfer> createForDragStartEvent();
- static Ref<DataTransfer> createForDrop(StoreMode, const DragData&);
+ static Ref<DataTransfer> createForDrop(std::unique_ptr<Pasteboard>&&, DragOperation, bool draggingFiles);
+ static Ref<DataTransfer> createForUpdatingDropTarget(Document&, std::unique_ptr<Pasteboard>&&, DragOperation, bool draggingFiles);
bool dropEffectIsUninitialized() const { return m_dropEffect == "uninitialized"; }
return dragEnteredOrUpdated(dragData);
}
-static Ref<DataTransfer> createDataTransferToUpdateDrag(const DragData& dragData, const Settings& settings, RefPtr<Document>&& documentUnderMouse)
-{
- auto accessMode = DataTransfer::StoreMode::Protected;
-
-#if ENABLE(DASHBOARD_SUPPORT)
- if (settings.usesDashboardBackwardCompatibilityMode() && (!documentUnderMouse || documentUnderMouse->securityOrigin().isLocal()))
- accessMode = DataTransfer::StoreMode::Readonly;
-#else
- UNUSED_PARAM(settings);
- UNUSED_PARAM(documentUnderMouse);
-#endif
-
- auto dataTransfer = DataTransfer::createForDrop(accessMode, dragData);
- dataTransfer->setSourceOperation(dragData.draggingSourceOperationMask());
-
- return dataTransfer;
-}
-
void DragController::dragExited(const DragData& dragData)
{
- if (RefPtr<FrameView> v = m_page.mainFrame().view()) {
- auto dataTransfer = createDataTransferToUpdateDrag(dragData, m_page.mainFrame().settings(), m_documentUnderMouse.copyRef());
- m_page.mainFrame().eventHandler().cancelDragAndDrop(createMouseEvent(dragData), dataTransfer);
- dataTransfer->makeInvalidForSecurity();
- }
+ auto& mainFrame = m_page.mainFrame();
+ if (mainFrame.view())
+ mainFrame.eventHandler().cancelDragAndDrop(createMouseEvent(dragData), Pasteboard::createForDragAndDrop(dragData), dragData.draggingSourceOperationMask(), dragData.containsFiles());
mouseMovedIntoDocument(nullptr);
if (m_fileInputElementUnderMouse)
m_fileInputElementUnderMouse->setCanReceiveDroppedFiles(false);
m_client.willPerformDragDestinationAction(DragDestinationActionDHTML, dragData);
Ref<MainFrame> mainFrame(m_page.mainFrame());
bool preventedDefault = false;
- if (mainFrame->view()) {
- // Sending an event can result in the destruction of the view and part.
- auto dataTransfer = DataTransfer::createForDrop(DataTransfer::StoreMode::Readonly, dragData);
- dataTransfer->setSourceOperation(dragData.draggingSourceOperationMask());
- preventedDefault = mainFrame->eventHandler().performDragAndDrop(createMouseEvent(dragData), dataTransfer);
- dataTransfer->makeInvalidForSecurity();
- }
+ if (mainFrame->view())
+ preventedDefault = mainFrame->eventHandler().performDragAndDrop(createMouseEvent(dragData), Pasteboard::createForDragAndDrop(dragData), dragData.draggingSourceOperationMask(), dragData.containsFiles());
if (preventedDefault) {
clearDragCaret();
m_documentUnderMouse = nullptr;
if (!viewProtector)
return false;
- auto dataTransfer = createDataTransferToUpdateDrag(dragData, mainFrame->settings(), m_documentUnderMouse.copyRef());
-
- PlatformMouseEvent event = createMouseEvent(dragData);
- if (!mainFrame->eventHandler().updateDragAndDrop(event, dataTransfer)) {
- dataTransfer->makeInvalidForSecurity();
+ DragOperation sourceOperation = dragData.draggingSourceOperationMask();
+ auto targetResponse = mainFrame->eventHandler().updateDragAndDrop(createMouseEvent(dragData), [&dragData]() { return Pasteboard::createForDragAndDrop(dragData); }, sourceOperation, dragData.containsFiles());
+ if (!targetResponse.accept)
return false;
- }
- operation = dataTransfer->destinationOperation();
- DragOperation srcOpMask = dragData.draggingSourceOperationMask();
- if (dataTransfer->dropEffectIsUninitialized())
- operation = defaultOperationForDrag(srcOpMask);
- else if (!(srcOpMask & operation)) {
- // The element picked an operation which is not supported by the source
+ if (!targetResponse.operation)
+ operation = defaultOperationForDrag(sourceOperation);
+ else if (!(sourceOperation & targetResponse.operation.value())) // The element picked an operation which is not supported by the source
operation = DragOperationNone;
- }
+ else
+ operation = targetResponse.operation.value();
- dataTransfer->makeInvalidForSecurity();
return true;
}
#if ENABLE(DRAG_SUPPORT)
-bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Element& dragTarget, const PlatformMouseEvent& event, DataTransfer* dataTransfer)
+bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Element& dragTarget, const PlatformMouseEvent& event, DataTransfer& dataTransfer)
{
Ref<Frame> protectedFrame(m_frame);
FrameView* view = m_frame.view();
event.movementDelta().x(), event.movementDelta().y(),
#endif
event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
- 0, 0, event.force(), NoTap, dataTransfer);
+ 0, 0, event.force(), NoTap, &dataTransfer);
dragTarget.dispatchEvent(me);
return me->defaultPrevented();
return false;
}
-static bool findDropZone(Node* target, DataTransfer* dataTransfer)
+static bool findDropZone(Node& target, DataTransfer& dataTransfer)
{
- ASSERT(target);
- Element* element = is<Element>(*target) ? downcast<Element>(target) : target->parentElement();
+ RefPtr<Element> element = is<Element>(target) ? &downcast<Element>(target) : target.parentElement();
for (; element; element = element->parentElement()) {
SpaceSplitString keywords(element->attributeWithoutSynchronization(webkitdropzoneAttr), true);
bool matched = false;
if (dragOperation == DragOperationNone)
dragOperation = op;
} else
- matched = matched || hasDropZoneType(*dataTransfer, keywords[i].string());
+ matched = matched || hasDropZoneType(dataTransfer, keywords[i].string());
if (matched && dragOperation != DragOperationNone)
break;
}
if (matched) {
- dataTransfer->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
+ dataTransfer.setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
return true;
}
}
return false;
}
-
-bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, DataTransfer& dataTransfer)
-{
- Ref<Frame> protectedFrame(m_frame);
- bool accept = false;
+EventHandler::DragTargetResponse EventHandler::dispatchDragEnterOrDragOverEvent(const AtomicString& eventType, Element& target, const PlatformMouseEvent& event,
+ std::unique_ptr<Pasteboard>&& pasteboard, DragOperation sourceOperation, bool draggingFiles)
+{
+ auto dataTransfer = DataTransfer::createForUpdatingDropTarget(target.document(), WTFMove(pasteboard), sourceOperation, draggingFiles);
+ bool accept = dispatchDragEvent(eventType, target, event, dataTransfer.get());
+ if (!accept)
+ accept = findDropZone(target, dataTransfer);
+ dataTransfer->makeInvalidForSecurity();
+ if (accept && !dataTransfer->dropEffectIsUninitialized())
+ return { true, dataTransfer->destinationOperation() };
+ return { accept, std::nullopt };
+}
+EventHandler::DragTargetResponse EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, const std::function<std::unique_ptr<Pasteboard>()>& makePasteboard, DragOperation sourceOperation, bool draggingFiles)
+{
+ Ref<Frame> protectedFrame(m_frame);
if (!m_frame.view())
- return false;
+ return { };
HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowUserAgentShadowContent);
MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, event);
m_autoscrollController->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());
+ DragTargetResponse response;
if (m_dragTarget != newTarget) {
// FIXME: this ordering was explicitly chosen to match WinIE. However,
// it is sometimes incorrect when dragging within subframes, as seen with
Frame* targetFrame;
if (targetIsFrame(newTarget.get(), targetFrame)) {
if (targetFrame)
- accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
+ response = targetFrame->eventHandler().updateDragAndDrop(event, makePasteboard, sourceOperation, draggingFiles);
} else if (newTarget) {
// As per section 7.9.4 of the HTML 5 spec., we must always fire a drag event before firing a dragenter, dragleave, or dragover event.
if (dragState().source && dragState().shouldDispatchEvents) {
// for now we don't care if event handler cancels default behavior, since there is none
dispatchDragSrcEvent(eventNames().dragEvent, event);
}
- accept = dispatchDragEvent(eventNames().dragenterEvent, *newTarget, event, &dataTransfer);
- if (!accept)
- accept = findDropZone(newTarget.get(), &dataTransfer);
+ response = dispatchDragEnterOrDragOverEvent(eventNames().dragenterEvent, *newTarget, event, makePasteboard(), sourceOperation, draggingFiles);
}
if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
+ // FIXME: Recursing again here doesn't make sense if the newTarget and m_dragTarget were in the same frame.
if (targetFrame)
- accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
- } else if (m_dragTarget)
- dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, &dataTransfer);
+ response = targetFrame->eventHandler().updateDragAndDrop(event, makePasteboard, sourceOperation, draggingFiles);
+ } else if (m_dragTarget) {
+ auto dataTransfer = DataTransfer::createForUpdatingDropTarget(m_dragTarget->document(), makePasteboard(), sourceOperation, draggingFiles);
+ dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, dataTransfer.get());
+ dataTransfer->makeInvalidForSecurity();
+ }
if (newTarget) {
// We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
Frame* targetFrame;
if (targetIsFrame(newTarget.get(), targetFrame)) {
if (targetFrame)
- accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
+ response = targetFrame->eventHandler().updateDragAndDrop(event, makePasteboard, sourceOperation, draggingFiles);
} else if (newTarget) {
// Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
if (!m_shouldOnlyFireDragOverEvent && dragState().source && dragState().shouldDispatchEvents) {
// for now we don't care if event handler cancels default behavior, since there is none
dispatchDragSrcEvent(eventNames().dragEvent, event);
}
- accept = dispatchDragEvent(eventNames().dragoverEvent, *newTarget, event, &dataTransfer);
- if (!accept)
- accept = findDropZone(newTarget.get(), &dataTransfer);
+ response = dispatchDragEnterOrDragOverEvent(eventNames().dragoverEvent, *newTarget, event, makePasteboard(), sourceOperation, draggingFiles);
m_shouldOnlyFireDragOverEvent = false;
}
}
m_dragTarget = WTFMove(newTarget);
- return accept;
+ return response;
}
-void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, DataTransfer& dataTransfer)
+void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, std::unique_ptr<Pasteboard>&& pasteboard, DragOperation sourceOperation, bool draggingFiles)
{
Ref<Frame> protectedFrame(m_frame);
Frame* targetFrame;
if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
if (targetFrame)
- targetFrame->eventHandler().cancelDragAndDrop(event, dataTransfer);
+ targetFrame->eventHandler().cancelDragAndDrop(event, WTFMove(pasteboard), sourceOperation, draggingFiles);
} else if (m_dragTarget) {
if (dragState().source && dragState().shouldDispatchEvents)
dispatchDragSrcEvent(eventNames().dragEvent, event);
- dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, &dataTransfer);
+
+ auto dataTransfer = DataTransfer::createForUpdatingDropTarget(m_dragTarget->document(), WTFMove(pasteboard), sourceOperation, draggingFiles);
+ dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, dataTransfer.get());
+ dataTransfer->makeInvalidForSecurity();
}
clearDragState();
}
-bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, DataTransfer& dataTransfer)
+bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, std::unique_ptr<Pasteboard>&& pasteboard, DragOperation sourceOperation, bool draggingFiles)
{
Ref<Frame> protectedFrame(m_frame);
bool preventedDefault = false;
if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
if (targetFrame)
- preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, dataTransfer);
- } else if (m_dragTarget)
- preventedDefault = dispatchDragEvent(eventNames().dropEvent, *m_dragTarget, event, &dataTransfer);
+ preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, WTFMove(pasteboard), sourceOperation, draggingFiles);
+ } else if (m_dragTarget) {
+ auto dataTransfer = DataTransfer::createForDrop(WTFMove(pasteboard), sourceOperation, draggingFiles);
+ preventedDefault = dispatchDragEvent(eventNames().dropEvent, *m_dragTarget, event, dataTransfer);
+ dataTransfer->makeInvalidForSecurity();
+ }
clearDragState();
return preventedDefault;
}
// Return value indicates if we should continue "default processing", i.e., whether event handler canceled.
bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
{
- return !dispatchDragEvent(eventType, *dragState().source, event, dragState().dataTransfer.get());
+ ASSERT(dragState().dataTransfer);
+ return !dispatchDragEvent(eventType, *dragState().source, event, *dragState().dataTransfer);
}
bool EventHandler::dispatchDragStartEventOnSourceElement(DataTransfer& dataTransfer)
{
- return !dispatchDragEvent(eventNames().dragstartEvent, *dragState().source, m_mouseDown, &dataTransfer) && !m_frame.selection().selection().isInPasswordField();
+ return !dispatchDragEvent(eventNames().dragstartEvent, *dragState().source, m_mouseDown, dataTransfer) && !m_frame.selection().selection().isInPasswordField();
}
static bool ExactlyOneBitSet(DragSourceAction n)
class KeyboardEvent;
class MouseEventWithHitTestResults;
class Node;
+class Pasteboard;
class PlatformGestureEvent;
class PlatformKeyboardEvent;
class PlatformTouchEvent;
WEBCORE_EXPORT void setCapturingMouseEventsElement(Element*);
#if ENABLE(DRAG_SUPPORT)
- bool updateDragAndDrop(const PlatformMouseEvent&, DataTransfer&);
- void cancelDragAndDrop(const PlatformMouseEvent&, DataTransfer&);
- bool performDragAndDrop(const PlatformMouseEvent&, DataTransfer&);
+ struct DragTargetResponse {
+ bool accept { false };
+ std::optional<DragOperation> operation;
+ };
+ DragTargetResponse updateDragAndDrop(const PlatformMouseEvent&, const std::function<std::unique_ptr<Pasteboard>()>&, DragOperation sourceOperation, bool draggingFiles);
+ void cancelDragAndDrop(const PlatformMouseEvent&, std::unique_ptr<Pasteboard>&&, DragOperation, bool draggingFiles);
+ bool performDragAndDrop(const PlatformMouseEvent&, std::unique_ptr<Pasteboard>&&, DragOperation, bool draggingFiles);
void updateDragStateAfterEditDragIfNeeded(Element& rootEditableElement);
RefPtr<Element> draggedElement() const;
#endif
bool dispatchMouseEvent(const AtomicString& eventType, Node* target, bool cancelable, int clickCount, const PlatformMouseEvent&, bool setUnder);
#if ENABLE(DRAG_SUPPORT)
- bool dispatchDragEvent(const AtomicString& eventType, Element& target, const PlatformMouseEvent&, DataTransfer*);
+ bool dispatchDragEvent(const AtomicString& eventType, Element& target, const PlatformMouseEvent&, DataTransfer&);
+ DragTargetResponse dispatchDragEnterOrDragOverEvent(const AtomicString& eventType, Element& target, const PlatformMouseEvent&, std::unique_ptr<Pasteboard>&& , DragOperation, bool draggingFiles);
void invalidateDataTransfer();
bool handleDrag(const MouseEventWithHitTestResults&, CheckDragHysteresis);