Skip to content
Permalink
Browse files
2009-09-09 Jens Alfke <snej@chromium.org>
        Reviewed by Eric Seidel.

        Initialize DataTransfer's effectAllowed and dropEffect properties correctly
        according to HTML5 spec (sec. 7.9.2-7.9.3).
        https://bugs.webkit.org/show_bug.cgi?id=26700

        * fast/events/drag-dropeffect-expected.txt: Added.
        * fast/events/drag-dropeffect.html: Added.
2009-09-09  Jens Alfke  <snej@chromium.org>

        Reviewed by Eric Seidel.

        Initialize DataTransfer's effectAllowed and dropEffect properties correctly
        according to HTML5 spec (sec. 7.9.2-7.9.3).
        https://bugs.webkit.org/show_bug.cgi?id=26700
        - At the start of a drag operation, the value of effectAllowed should be
          the string "uninitialized".
        - At end of dragstart handler, if effectAllowed hasn't been set yet, it
          should be set to "copy".
        - on dragenter and dragover event, dropEffect should be initialized to a
          default value based on the value of effectAllowed.
        - at end of dragenter and dragover the dropEffect should be set to "none"
          if the value set by the handler doesn't match the effectAllowed.
        - on dragleave event, dropEffect should be "none".
        - on drop event, dropEffect should be the previously negotiated value.

        Test: fast/events/drag-dropeffect.html

        * WebCore.base.exp:
            Added a parameter to EventHandler::dragSourceMovedTo.
        * dom/Clipboard.cpp:
        (WebCore::Clipboard::Clipboard):
            Initialize m_effectAllowed to "uninitialized".
        (WebCore::Clipboard::sourceOperation):
            Treat "uninitialized" as meaning no value has been set.
        * page/DragController.cpp:
        (WebCore::DragController::DragController):
            Initialize new member m_destinationDragOperation.
        (WebCore::DragController::dragExited):
            Set m_destinationDragOperation to none on dragExit.
        (WebCore::DragController::performDrag):
            Set m_destinationDragOperation to current dropEffect.
        (WebCore::DragController::dragEnteredOrUpdated):
            Make sure to clear the operation if drag source doesn't allow it.
        (WebCore::DragController::tryDHTMLDrag):
            Set a default value for the dst drag op before sending dragEnter/Over.
        (WebCore::DragController::startDrag):
            Clear m_destinationDragOperation at start of drag.
        * page/DragController.h:
        (WebCore::DragController::destinationDragOperation):
            Added new member m_destinationDragOperation, and its public getter.
        * page/EventHandler.cpp:
        (WebCore::EventHandler::updateDragAndDrop):
            dropEffect should be 'none' during dropleave handler, per spec.
        (WebCore::EventHandler::dragSourceMovedTo):
            Added DragOperation parameter, so the handler sees the current dropEffect.
        (WebCore::EventHandler::handleDrag):
            Assume DragOperationEvery for non-DHTML drags.
        * page/EventHandler.h:
            Added DragOperation parameter to dragSourceMovedTo().
2009-09-09  Jens Alfke  <snej@chromium.org>

        Reviewed by Eric Seidel.

        Initialize DataTransfer's effectAllowed and dropEffect properties correctly
        according to HTML5 spec (sec. 7.9.2-7.9.3).
        https://bugs.webkit.org/show_bug.cgi?id=26700

        * WebView/WebFrame.mm:
        (-[WebFrame _dragSourceMovedTo:]):
            Pass current drag operation (if known) to EventHandler::dragSourceMovedTo().

Canonical link: https://commits.webkit.org/39798@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@48229 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
eseidel committed Sep 9, 2009
1 parent e821b19 commit 01926e1fe6e7cd4132217dd6870e52f9a77d8cf8
Showing 12 changed files with 340 additions and 9 deletions.
@@ -1,3 +1,14 @@
2009-09-09 Jens Alfke <snej@chromium.org>

Reviewed by Eric Seidel.

Initialize DataTransfer's effectAllowed and dropEffect properties correctly
according to HTML5 spec (sec. 7.9.2-7.9.3).
https://bugs.webkit.org/show_bug.cgi?id=26700

* fast/events/drag-dropeffect-expected.txt: Added.
* fast/events/drag-dropeffect.html: Added.

2009-09-09 Zan Dobersek <zandobersek@gmail.com>

Reviewed by Gustavo Noronha.
@@ -0,0 +1,34 @@

This automated layout test checks that effectAllowed and dropEffect are set properly in drag callbacks.
If you're running this in a browser, you can simulate part of it by dragging Abe onto the box.

*** Testing a successful drag...
PASS effectAllowed in dragStart = 'uninitialized'
PASS dropEffect in dragStart = 'none'
PASS effectAllowed in dragEnter = 'copyMove'
PASS dropEffect in dragEnter = 'copy'
PASS effectAllowed in drop = 'copyMove'
PASS dropEffect in drop = 'move'
PASS effectAllowed in dragEnd = 'copyMove'
PASS dropEffect in dragEnd = 'move'
PASS calls to dragStart = '1'
PASS calls to dragEnd = '1'
PASS calls to dragEnter = '1'
PASS calls to drop = '1'
*** Testing a failed drag...
PASS effectAllowed in dragStart = 'uninitialized'
PASS dropEffect in dragStart = 'none'
PASS effectAllowed in dragEnter = 'link'
PASS dropEffect in dragEnter = 'link'
PASS effectAllowed in dragLeave = 'link'
PASS dropEffect in dragLeave = 'none'
PASS effectAllowed in dragEnd = 'link'
PASS dropEffect in dragEnd = 'none'
PASS calls to dragStart = '1'
PASS calls to dragEnd = '1'
PASS calls to dragEnter = '1'
PASS calls to drop = '0'
PASS successfullyParsed is true

TEST COMPLETE

@@ -0,0 +1,188 @@
<html>
<head>
<script src="../js/resources/js-test-pre.js"></script>
</head>
<body onload="runTest()">

<image id="dragSource" src="resources/abe.png" width="76" height="103"
ondragstart="dragStart(event)" ondrag="drag(event)" ondragend="dragEnd(event)">
<div id="dragTarget" style="width: 100px; height: 100px; border: 1px solid gray;"
ondragenter="dragEnter(event)" ondragover="dragOver(event)"
ondragleave="dragLeave(event)" ondrop="drop(event)">
</div>

<p>This automated layout test checks that effectAllowed and dropEffect are set properly in drag
callbacks.<br>
If you're running this in a browser, you can simulate part of it by dragging Abe onto the box.</p>
<div id="console"></div>

<script>

function assert(result, what)
{
if (!result)
testFailed("Expected that " + what);
else
testPassed(what);
}

function assertEqual(test, expected, what, quiet)
{
if (test !== expected)
testFailed(what + " = '" + test + "' ... expected '" + expected + "'");
else if (!quiet)
testPassed(what + " = '" + test + "'");
}


var dragStartCalled = 0, dragCalled = 0, dragEndCalled = 0;
var dragEnterCalled = 0, dragOverCalled = 0, dragLeaveCalled = 0, dropCalled = 0;

var effectAllowedToSet = "copyMove";
var defaultDropEffect = "copy";
var dropEffectToSet = "move";
var expectedDropEffect = "move";


// DRAG SOURCE EVENT HANDLERS:
function dragStart(event)
{
dragStartCalled++;
assertEqual(event.dataTransfer.effectAllowed, "uninitialized", "effectAllowed in dragStart");
assertEqual(event.dataTransfer.dropEffect, "none", "dropEffect in dragStart");
event.dataTransfer.effectAllowed = effectAllowedToSet;
}

function drag(event)
{
dragCalled++;
assertEqual(event.dataTransfer.effectAllowed, effectAllowedToSet, "effectAllowed in drag", true);
assertEqual(event.dataTransfer.dropEffect,
dragLeaveCalled < dragEnterCalled ?expectedDropEffect :"none",
"dropEffect in drag",
true);
}

function dragEnd(event)
{
dragEndCalled++;
assertEqual(event.dataTransfer.effectAllowed, effectAllowedToSet, "effectAllowed in dragEnd");
assertEqual(event.dataTransfer.dropEffect,
dragLeaveCalled < dragEnterCalled ? expectedDropEffect : "none",
"dropEffect in dragEnd");
}


// DRAG DESTINATION EVENT HANDLERS:
function dragEnter(event)
{
dragEnterCalled++;
assertEqual(event.dataTransfer.effectAllowed, effectAllowedToSet, "effectAllowed in dragEnter");
assertEqual(event.dataTransfer.dropEffect, defaultDropEffect, "dropEffect in dragEnter");
event.dataTransfer.dropEffect = dropEffectToSet;
event.preventDefault();
}

function dragOver(event)
{
dragOverCalled++;
assertEqual(event.dataTransfer.effectAllowed, effectAllowedToSet, "effectAllowed in dragOver", true);
assertEqual(event.dataTransfer.dropEffect, defaultDropEffect, "dropEffect in dragOver", true);
event.dataTransfer.dropEffect = dropEffectToSet;
event.preventDefault();
}

function dragLeave(event)
{
dragLeaveCalled++;
assertEqual(event.dataTransfer.effectAllowed, effectAllowedToSet, "effectAllowed in dragLeave");
assertEqual(event.dataTransfer.dropEffect, "none", "dropEffect in dragLeave");
event.preventDefault();
}

function drop(event)
{
dropCalled++;
assertEqual(event.dataTransfer.effectAllowed, effectAllowedToSet, "effectAllowed in drop");
assertEqual(event.dataTransfer.dropEffect, expectedDropEffect, "dropEffect in drop");
event.preventDefault();
}


function performDrag(srcId, dstId)
{
function moveMouseToCenterOf(id)
{
var element = document.getElementById(id);
var x = element.offsetLeft + element.offsetWidth / 2;
var y = element.offsetTop + element.offsetHeight / 2;
eventSender.mouseMoveTo(x, y);
}

dragStartCalled = dragCalled = dragEndCalled = 0;
dragEnterCalled = dragOverCalled = dragLeaveCalled = dropCalled = 0;

moveMouseToCenterOf(srcId);
eventSender.mouseDown();
moveMouseToCenterOf(dstId);
eventSender.mouseUp();
}

function runTest()
{
if (!window.layoutTestController)
return;
try {

debug("*** Testing a successful drag...");
effectAllowedToSet = "copyMove";
defaultDropEffect = "copy";
dropEffectToSet = "move";
expectedDropEffect = "move";
performDrag('dragSource', 'dragTarget');

assertEqual(dragStartCalled, 1, "calls to dragStart");
// Whether drag is called depends on timing. In a real-life drag it will be called, but
// with the artificial mouse events generated by the test controller, it may not be.
// So I've removed the assertion that dragCalled > 0.
assertEqual(dragEndCalled, 1, "calls to dragEnd");
assertEqual(dragEnterCalled, 1, "calls to dragEnter");
// dragOver won't necessarily be called if there was only one mouse event over
// the drop target, as in performDrag.
// dragLeave isn't called because the drag never exits the drop target.
assertEqual(dropCalled, 1, "calls to drop");

debug("*** Testing a failed drag...");
effectAllowedToSet = "link";
defaultDropEffect = "link";
dropEffectToSet = "move";
expectedDropEffect = "none";
performDrag('dragSource', 'dragTarget');

assertEqual(dragStartCalled, 1, "calls to dragStart");
// As described above, drag might not be called, under test conditions, so don't check dragCalled.
assertEqual(dragEndCalled, 1, "calls to dragEnd");
assertEqual(dragEnterCalled, 1, "calls to dragEnter");
assertEqual(dropCalled, 0, "calls to drop");

// Finally run the post-test function:
isSuccessfullyParsed();

} catch (x) {
debug("FAILED by throwing " + x);
}
// OK, now DRT can quit.
layoutTestController.notifyDone();
}

// Tell DRT not to quit immediately, because the actual runTest() function won't be called
// until the onload event is sent (otherwise the fake drag stuff crashes: bug 29101.)
layoutTestController.waitUntilDone();

var successfullyParsed = true;
</script>

<script src="../js/resources/js-test-post-function.js"></script>

</body>
</html>
@@ -1,3 +1,56 @@
2009-09-09 Jens Alfke <snej@chromium.org>

Reviewed by Eric Seidel.

Initialize DataTransfer's effectAllowed and dropEffect properties correctly
according to HTML5 spec (sec. 7.9.2-7.9.3).
https://bugs.webkit.org/show_bug.cgi?id=26700
- At the start of a drag operation, the value of effectAllowed should be
the string "uninitialized".
- At end of dragstart handler, if effectAllowed hasn't been set yet, it
should be set to "copy".
- on dragenter and dragover event, dropEffect should be initialized to a
default value based on the value of effectAllowed.
- at end of dragenter and dragover the dropEffect should be set to "none"
if the value set by the handler doesn't match the effectAllowed.
- on dragleave event, dropEffect should be "none".
- on drop event, dropEffect should be the previously negotiated value.

Test: fast/events/drag-dropeffect.html

* WebCore.base.exp:
Added a parameter to EventHandler::dragSourceMovedTo.
* dom/Clipboard.cpp:
(WebCore::Clipboard::Clipboard):
Initialize m_effectAllowed to "uninitialized".
(WebCore::Clipboard::sourceOperation):
Treat "uninitialized" as meaning no value has been set.
* page/DragController.cpp:
(WebCore::DragController::DragController):
Initialize new member m_destinationDragOperation.
(WebCore::DragController::dragExited):
Set m_destinationDragOperation to none on dragExit.
(WebCore::DragController::performDrag):
Set m_destinationDragOperation to current dropEffect.
(WebCore::DragController::dragEnteredOrUpdated):
Make sure to clear the operation if drag source doesn't allow it.
(WebCore::DragController::tryDHTMLDrag):
Set a default value for the dst drag op before sending dragEnter/Over.
(WebCore::DragController::startDrag):
Clear m_destinationDragOperation at start of drag.
* page/DragController.h:
(WebCore::DragController::destinationDragOperation):
Added new member m_destinationDragOperation, and its public getter.
* page/EventHandler.cpp:
(WebCore::EventHandler::updateDragAndDrop):
dropEffect should be 'none' during dropleave handler, per spec.
(WebCore::EventHandler::dragSourceMovedTo):
Added DragOperation parameter, so the handler sees the current dropEffect.
(WebCore::EventHandler::handleDrag):
Assume DragOperationEvery for non-DHTML drags.
* page/EventHandler.h:
Added DragOperation parameter to dragSourceMovedTo().

2009-09-09 Dumitru Daniliuc <dumi@chromium.org>

Reviewed by Dimitri Glazkov.
@@ -224,7 +224,7 @@ __ZN7WebCore12EventHandler14currentNSEventEv
__ZN7WebCore12EventHandler14scrollOverflowENS_15ScrollDirectionENS_17ScrollGranularityE
__ZN7WebCore12EventHandler15sendScrollEventEv
__ZN7WebCore12EventHandler17dragSourceEndedAtERKNS_18PlatformMouseEventENS_13DragOperationE
__ZN7WebCore12EventHandler17dragSourceMovedToERKNS_18PlatformMouseEventE
__ZN7WebCore12EventHandler17dragSourceMovedToERKNS_18PlatformMouseEventENS_13DragOperationE
__ZN7WebCore12EventHandler17eventMayStartDragEP7NSEvent
__ZN7WebCore12EventHandler20handleTextInputEventERKNS_6StringEPNS_5EventEbb
__ZN7WebCore12EventHandler20hitTestResultAtPointERKNS_8IntPointEbbNS_17HitTestScrollbarsE
@@ -40,6 +40,10 @@ Clipboard::Clipboard(ClipboardAccessPolicy policy, bool isForDragging)
, m_forDragging(isForDragging)
, m_dragImage(0)
{
if (isForDragging) {
// per HTML5 spec, sec. 7.9.2
m_effectAllowed = "uninitialized";
}
}

void Clipboard::setAccessPolicy(ClipboardAccessPolicy policy)
@@ -98,7 +102,7 @@ static String IEOpFromDragOp(DragOperation op)

bool Clipboard::sourceOperation(DragOperation& op) const
{
if (m_effectAllowed.isNull())
if (m_effectAllowed.isNull() || m_effectAllowed == "uninitialized")
return false;
op = dragOpFromIEOp(m_effectAllowed);
return true;
@@ -83,6 +83,7 @@ DragController::DragController(Page* page, DragClient* client)
, m_didInitiateDrag(false)
, m_isHandlingDrag(false)
, m_sourceDragOperation(DragOperationNone)
, m_destinationDragOperation(DragOperationNone)
{
}

@@ -158,6 +159,7 @@ void DragController::dragExited(DragData* dragData)
ClipboardAccessPolicy policy = (!m_documentUnderMouse || m_documentUnderMouse->securityOrigin()->isLocal()) ? ClipboardReadable : ClipboardTypesReadable;
RefPtr<Clipboard> clipboard = dragData->createClipboard(policy);
clipboard->setSourceOperation(dragData->draggingSourceOperationMask());
clipboard->setDestinationOperation(DragOperationNone); // HTML5 spec, sec. 7.9.3
mainFrame->eventHandler()->cancelDragAndDrop(createMouseEvent(dragData), clipboard.get());
clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security
}
@@ -181,6 +183,7 @@ bool DragController::performDrag(DragData* dragData)
// Sending an event can result in the destruction of the view and part.
RefPtr<Clipboard> clipboard = dragData->createClipboard(ClipboardReadable);
clipboard->setSourceOperation(dragData->draggingSourceOperationMask());
clipboard->setDestinationOperation(m_destinationDragOperation); // HTML5 spec, sec. 7.9.3
mainFrame->eventHandler()->performDragAndDrop(createMouseEvent(dragData), clipboard.get());
clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security
}
@@ -229,7 +232,12 @@ DragOperation DragController::dragEnteredOrUpdated(DragData* dragData)
DragOperation operation = DragOperationNone;
bool handledByDocument = tryDocumentDrag(dragData, m_dragDestinationAction, operation);
if (!handledByDocument && (m_dragDestinationAction & DragDestinationActionLoad))
return operationForLoad(dragData);
operation = operationForLoad(dragData);

// Restrict the operation to what the drag source allows:
if ((operation & dragData->draggingSourceOperationMask()) != operation)
operation = DragOperationNone;
m_destinationDragOperation = operation;
return operation;
}

@@ -491,6 +499,8 @@ bool DragController::tryDHTMLDrag(DragData* dragData, DragOperation& operation)
RefPtr<Clipboard> clipboard = dragData->createClipboard(policy);
DragOperation srcOpMask = dragData->draggingSourceOperationMask();
clipboard->setSourceOperation(srcOpMask);
m_destinationDragOperation = defaultOperationForDrag(srcOpMask); // HTML5 spec, sec. 7.9.3
clipboard->setDestinationOperation(m_destinationDragOperation);

PlatformMouseEvent event = createMouseEvent(dragData);
if (!mainFrame->eventHandler()->updateDragAndDrop(event, clipboard.get())) {
@@ -623,6 +633,7 @@ bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation s

m_draggingImageURL = KURL();
m_sourceDragOperation = srcOp;
m_destinationDragOperation = DragOperationNone;

DragImageRef dragImage = 0;
IntPoint dragLoc(0, 0);
@@ -65,6 +65,7 @@ namespace WebCore {
void setIsHandlingDrag(bool handling) { m_isHandlingDrag = handling; }
bool isHandlingDrag() const { return m_isHandlingDrag; }
DragOperation sourceDragOperation() const { return m_sourceDragOperation; }
DragOperation destinationDragOperation() const { return m_destinationDragOperation; }
void setDraggingImageURL(const KURL& url) { m_draggingImageURL = url; }
const KURL& draggingImageURL() const { return m_draggingImageURL; }
void setDragInitiator(Document* initiator) { m_dragInitiator = initiator; m_didInitiateDrag = true; }
@@ -122,6 +123,7 @@ namespace WebCore {
bool m_didInitiateDrag;
bool m_isHandlingDrag;
DragOperation m_sourceDragOperation; // Set in startDrag when a drag starts from a mouse down within WebKit
DragOperation m_destinationDragOperation; // Last operation set by event handler
IntPoint m_dragOffset;
KURL m_draggingImageURL;
};

0 comments on commit 01926e1

Please sign in to comment.