Title: [223031] trunk
Revision
223031
Author
[email protected]
Date
2017-10-08 03:08:52 -0700 (Sun, 08 Oct 2017)

Log Message

dragenter and dragleave shouldn't use the same data transfer object
https://bugs.webkit.org/show_bug.cgi?id=178056

Reviewed by Darin Adler.

Source/WebCore:

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:

LayoutTests:

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:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (223030 => 223031)


--- trunk/LayoutTests/ChangeLog	2017-10-08 08:00:41 UTC (rev 223030)
+++ trunk/LayoutTests/ChangeLog	2017-10-08 10:08:52 UTC (rev 223031)
@@ -1,3 +1,18 @@
+2017-10-08  Ryosuke Niwa  <[email protected]>
+
+        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  <[email protected]>
 
         SourceBuffer remove throws out way more content than requested

Modified: trunk/LayoutTests/TestExpectations (223030 => 223031)


--- trunk/LayoutTests/TestExpectations	2017-10-08 08:00:41 UTC (rev 223030)
+++ trunk/LayoutTests/TestExpectations	2017-10-08 10:08:52 UTC (rev 223031)
@@ -73,6 +73,7 @@
 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 ]
 

Added: trunk/LayoutTests/editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave-expected.txt (0 => 223031)


--- trunk/LayoutTests/editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave-expected.txt	2017-10-08 10:08:52 UTC (rev 223031)
@@ -0,0 +1,10 @@
+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
+

Added: trunk/LayoutTests/editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave.html (0 => 223031)


--- trunk/LayoutTests/editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave.html	2017-10-08 10:08:52 UTC (rev 223031)
@@ -0,0 +1,71 @@
+<!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=""
+<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=""
+</body>
+</html>

Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (223030 => 223031)


--- trunk/LayoutTests/platform/mac-wk1/TestExpectations	2017-10-08 08:00:41 UTC (rev 223030)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations	2017-10-08 10:08:52 UTC (rev 223031)
@@ -11,6 +11,7 @@
 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 ]
 

Modified: trunk/LayoutTests/platform/win/TestExpectations (223030 => 223031)


--- trunk/LayoutTests/platform/win/TestExpectations	2017-10-08 08:00:41 UTC (rev 223030)
+++ trunk/LayoutTests/platform/win/TestExpectations	2017-10-08 10:08:52 UTC (rev 223031)
@@ -1155,6 +1155,7 @@
 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 ]

Modified: trunk/Source/WebCore/ChangeLog (223030 => 223031)


--- trunk/Source/WebCore/ChangeLog	2017-10-08 08:00:41 UTC (rev 223030)
+++ trunk/Source/WebCore/ChangeLog	2017-10-08 10:08:52 UTC (rev 223031)
@@ -1,3 +1,45 @@
+2017-10-08  Ryosuke Niwa  <[email protected]>
+
+        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  <[email protected]>
 
         SourceBuffer remove throws out way more content than requested

Modified: trunk/Source/WebCore/dom/DataTransfer.cpp (223030 => 223031)


--- trunk/Source/WebCore/dom/DataTransfer.cpp	2017-10-08 08:00:41 UTC (rev 223030)
+++ trunk/Source/WebCore/dom/DataTransfer.cpp	2017-10-08 10:08:52 UTC (rev 223031)
@@ -337,12 +337,27 @@
     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)
 {
     if (!forDrag() || !canWriteData())

Modified: trunk/Source/WebCore/dom/DataTransfer.h (223030 => 223031)


--- trunk/Source/WebCore/dom/DataTransfer.h	2017-10-08 08:00:41 UTC (rev 223030)
+++ trunk/Source/WebCore/dom/DataTransfer.h	2017-10-08 10:08:52 UTC (rev 223031)
@@ -32,6 +32,7 @@
 
 class CachedImage;
 class DataTransferItemList;
+class Document;
 class DragData;
 class DragImageLoader;
 class Element;
@@ -83,7 +84,8 @@
 #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"; }
 

Modified: trunk/Source/WebCore/page/DragController.cpp (223030 => 223031)


--- trunk/Source/WebCore/page/DragController.cpp	2017-10-08 08:00:41 UTC (rev 223030)
+++ trunk/Source/WebCore/page/DragController.cpp	2017-10-08 10:08:52 UTC (rev 223031)
@@ -220,31 +220,11 @@
     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);
@@ -282,13 +262,8 @@
         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;
@@ -709,24 +684,18 @@
     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;
 }
 

Modified: trunk/Source/WebCore/page/EventHandler.cpp (223030 => 223031)


--- trunk/Source/WebCore/page/EventHandler.cpp	2017-10-08 08:00:41 UTC (rev 223030)
+++ trunk/Source/WebCore/page/EventHandler.cpp	2017-10-08 10:08:52 UTC (rev 223031)
@@ -2180,7 +2180,7 @@
 
 #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();
@@ -2197,7 +2197,7 @@
         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();
@@ -2248,10 +2248,9 @@
     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;
@@ -2262,26 +2261,36 @@
                 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)
+
+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);
-
-    bool accept = false;
-
     if (!m_frame.view())
-        return false;
+        return { };
 
     HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowUserAgentShadowContent);
     MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, event);
@@ -2297,6 +2306,7 @@
 
     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
@@ -2306,7 +2316,7 @@
         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) {
@@ -2313,16 +2323,18 @@
                 // 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
@@ -2333,7 +2345,7 @@
         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) {
@@ -2340,17 +2352,15 @@
                 // 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);
 
@@ -2357,16 +2367,19 @@
     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);
 
@@ -2374,9 +2387,12 @@
     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;
 }
@@ -3545,12 +3561,13 @@
 // 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)

Modified: trunk/Source/WebCore/page/EventHandler.h (223030 => 223031)


--- trunk/Source/WebCore/page/EventHandler.h	2017-10-08 08:00:41 UTC (rev 223030)
+++ trunk/Source/WebCore/page/EventHandler.h	2017-10-08 10:08:52 UTC (rev 223031)
@@ -75,6 +75,7 @@
 class KeyboardEvent;
 class MouseEventWithHitTestResults;
 class Node;
+class Pasteboard;
 class PlatformGestureEvent;
 class PlatformKeyboardEvent;
 class PlatformTouchEvent;
@@ -155,9 +156,13 @@
     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
@@ -392,7 +397,8 @@
     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);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to