Commit 0eb6dc60 authored by dcheng@chromium.org's avatar dcheng@chromium.org

2011-05-13 Daniel Cheng <dcheng@chromium.org>

        Reviewed by Tony Chang.

        Improve drag start logic
        https://bugs.webkit.org/show_bug.cgi?id=59409

        Add a new test to test drag start edge cases on Mac (because of a non-zero text drag delay)
        as well as rebase an existing test.

        * fast/css/user-drag-none.html: Text nodes are no longer draggable.
        * platform/mac/editing/pasteboard/drag-selections-to-contenteditable-expected.txt: Added.
        * platform/mac/editing/pasteboard/drag-selections-to-contenteditable.html: Added.
2011-05-13  Daniel Cheng  <dcheng@chromium.org>

        Reviewed by Tony Chang.

        Improve drag start logic
        https://bugs.webkit.org/show_bug.cgi?id=59409

        Rewrite and simplify the dragging logic to better match IE, Firefox, and the behavior
        defined in the spec. Among other things:
        - draggableNode() no longer returns text nodes when dragging anchors.
        - When starting a drag over an image in a selection, prefer to drag the selection.
        - Several redundant hit tests have been removed.
        - Minor refactoring to make the logic easier to follow.

        Test: platform/mac/editing/pasteboard/drag-selections-to-contenteditable.html

        * WebCore.xcodeproj/project.pbxproj:
        * page/DragController.cpp:
        (WebCore::DragController::draggableNode):
        (WebCore::DragController::startDrag):
        * page/DragController.h:
        * page/DragState.h:
        (WebCore::DragState::shouldDispatchEvents):
        * page/EventHandler.cpp:
        (WebCore::EventHandler::EventHandler):
        (WebCore::EventHandler::eventMayStartDrag):
        (WebCore::EventHandler::updateDragSourceActionsAllowed):
        (WebCore::EventHandler::updateDragAndDrop):
        (WebCore::EventHandler::cancelDragAndDrop):
        (WebCore::EventHandler::dragHysteresisExceeded):
        (WebCore::EventHandler::dragSourceEndedAt):
        (WebCore::ExactlyOneBitSet):
        (WebCore::EventHandler::handleDrag):
        * page/EventHandler.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@86472 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 14c5dd6c
2011-05-13 Daniel Cheng <dcheng@chromium.org>
Reviewed by Tony Chang.
Improve drag start logic
https://bugs.webkit.org/show_bug.cgi?id=59409
Add a new test to test drag start edge cases on Mac (because of a non-zero text drag delay)
as well as rebase an existing test.
* fast/css/user-drag-none.html: Text nodes are no longer draggable.
* platform/mac/editing/pasteboard/drag-selections-to-contenteditable-expected.txt: Added.
* platform/mac/editing/pasteboard/drag-selections-to-contenteditable.html: Added.
2011-05-13 Anders Carlsson <andersca@apple.com>
Reviewed by Sam Weinig.
......@@ -19,11 +19,11 @@
<img class="drag-none" src="resources/greenbox.png">
</div>
<div class="box" expect="IMG text text A nil">
<div class="box" expect="IMG A A A nil">
<a href="#"><img src="resources/greenbox.png">x<br><span>y</span></a>
</div>
<div class="box" expect="IMG text text A nil">
<div class="box" expect="IMG A A A nil">
<a href="#" class="drag-element"><img src="resources/greenbox.png">x<br><span>y</span></a>
</div>
......@@ -31,11 +31,11 @@
<a href="#" class="drag-none"><img src="resources/greenbox.png">x<br><span>y</span></a>
</div>
<div class="box" expect="A text text A nil">
<div class="box" expect="A A A A nil">
<a href="#"><img class="drag-none" src="resources/greenbox.png">x<br><span>y</span></a>
</div>
<div class="box" expect="A text text A nil">
<div class="box" expect="A A A A nil">
<a href="#" class="drag-element"><img class="drag-none" src="resources/greenbox.png">x<br><span>y</span></a>
</div>
......@@ -43,11 +43,11 @@
<a href="#" class="drag-none"><img src="resources/greenbox.png">x<br><span>y</span></a>
</div>
<div class="box drag-element" expect="A text text A DIV">
<div class="box drag-element" expect="A A A A DIV">
<a href="#"><img class="drag-none" src="resources/greenbox.png">x<br><span>y</span></a>
</div>
<div class="box drag-element" expect="A text text A DIV">
<div class="box drag-element" expect="A A A A DIV">
<a href="#" class="drag-element"><img class="drag-none" src="resources/greenbox.png">x<br><span>y</span></a>
</div>
</div>
......
  Link Random text.
Link Random text.
This test checks selection drag edge cases on Mac. To run the test manually:
Select everything above, start the drag over the image, and with no delay, drag it to the content editable area. Only the image should be dragged.
Select everything above, start the drag over the link, and with no delay, drag it to the content editable area. The entire selection should be dragged.
Select everything above, start the drag over the text, and with no delay, drag it to the content editable area. Nothing should be dragged, but a bunch of text should be selected instead.
Dumping info about contenteditable div:
Number of children: 4
Contents:
IMG
IMG
A
SPAN
Number of selected ranges: 1
<html>
<head>
<script>
function log(message) {
var console = document.getElementById("console");
var div = document.createElement("div");
var text = document.createTextNode(message);
console.appendChild(div);
div.appendChild(text);
}
function runTest() {
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
} else
return;
selectSelection();
dragElementToContentEditable(document.getElementById("dragimage"));
selectSelection();
dragElementToContentEditable(document.getElementById("draglink"));
selectSelection();
dragElementToContentEditable(document.getElementById("dragtext"));
var target = document.getElementById("target");
log("Dumping info about contenteditable div:");
log("Number of children: " + target.children.length);
log("Contents:");
log(target.children[0].tagName);
log(target.children[1].tagName);
log(target.children[2].tagName);
log(target.children[3].tagName);
log("Number of selected ranges: " + window.getSelection().rangeCount);
layoutTestController.notifyDone();
}
function selectSelection() {
window.getSelection().selectAllChildren(document.getElementById("selection"));
}
function dragElementToContentEditable(dragSource)
{
x = dragSource.offsetLeft + dragSource.offsetWidth / 2;
y = dragSource.offsetTop + dragSource.offsetHeight / 2;
eventSender.mouseMoveTo(x, y);
eventSender.mouseDown();
var dropTarget = document.getElementById("target");
x = dropTarget.offsetLeft + dropTarget.offsetWidth / 2;
y = dropTarget.offsetTop + dropTarget.offsetHeight / 2;
eventSender.mouseMoveTo(x, y);
eventSender.mouseUp();
}
</script>
</head>
<body style="padding:0; margin:0" onload="runTest();">
<div id="target" style="border: 1px solid black; width: 300px; height: 200px;" contenteditable="true"></div>
<div id="selection">
<img id="dragimage" src="../../../../editing/resources/abe.png">
<a href="#" id="draglink">Link</a>
<span id="dragtext">Random text.</span></div>
<p>This test checks selection drag edge cases on Mac. To run the test manually:
<ol>
<li>Select everything above, start the drag over the image, and with no delay, drag it to the content editable area. Only the image should be dragged.
<li>Select everything above, start the drag over the link, and with no delay, drag it to the content editable area. The entire selection should be dragged.
<li>Select everything above, start the drag over the text, and with no delay, drag it to the content editable area. Nothing should be dragged, but a bunch of text should be selected instead.
</ol>
</p>
<div id="console"></ul>
</body>
2011-05-13 Daniel Cheng <dcheng@chromium.org>
Reviewed by Tony Chang.
Improve drag start logic
https://bugs.webkit.org/show_bug.cgi?id=59409
Rewrite and simplify the dragging logic to better match IE, Firefox, and the behavior
defined in the spec. Among other things:
- draggableNode() no longer returns text nodes when dragging anchors.
- When starting a drag over an image in a selection, prefer to drag the selection.
- Several redundant hit tests have been removed.
- Minor refactoring to make the logic easier to follow.
Test: platform/mac/editing/pasteboard/drag-selections-to-contenteditable.html
* WebCore.xcodeproj/project.pbxproj:
* page/DragController.cpp:
(WebCore::DragController::draggableNode):
(WebCore::DragController::startDrag):
* page/DragController.h:
* page/DragState.h:
(WebCore::DragState::shouldDispatchEvents):
* page/EventHandler.cpp:
(WebCore::EventHandler::EventHandler):
(WebCore::EventHandler::eventMayStartDrag):
(WebCore::EventHandler::updateDragSourceActionsAllowed):
(WebCore::EventHandler::updateDragAndDrop):
(WebCore::EventHandler::cancelDragAndDrop):
(WebCore::EventHandler::dragHysteresisExceeded):
(WebCore::EventHandler::dragSourceEndedAt):
(WebCore::ExactlyOneBitSet):
(WebCore::EventHandler::handleDrag):
* page/EventHandler.h:
2011-05-13 Oliver Hunt <oliver@apple.com>
Reviewed by Geoffrey Garen.
......@@ -1675,7 +1675,7 @@
81BE209911F4AB8D00915DFA /* IDBCursorBackendInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = 81BE209411F4AB8D00915DFA /* IDBCursorBackendInterface.h */; };
81BE20D211F4BC3200915DFA /* JSIDBCursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 81BE20A711F4B66F00915DFA /* JSIDBCursor.cpp */; };
81BE20D311F4BC3200915DFA /* JSIDBCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 81BE20A811F4B66F00915DFA /* JSIDBCursor.h */; };
81F65FF613788FAA00FF6F2D /* DragState.h in Headers */ = {isa = PBXBuildFile; fileRef = 81F65FF513788FAA00FF6F2D /* DragState.h */; };
81F65FF613788FAA00FF6F2D /* DragState.h in Headers */ = {isa = PBXBuildFile; fileRef = 81F65FF513788FAA00FF6F2D /* DragState.h */; settings = {ATTRIBUTES = (Private, ); }; };
82AB1743124B99EC00C5069D /* InspectorCSSAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 82AB1741124B99EC00C5069D /* InspectorCSSAgent.cpp */; };
82AB1744124B99EC00C5069D /* InspectorCSSAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 82AB1742124B99EC00C5069D /* InspectorCSSAgent.h */; };
82AB1773125C826700C5069D /* InspectorStyleSheet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 82AB176F125C826700C5069D /* InspectorStyleSheet.cpp */; };
......@@ -569,71 +569,46 @@ bool DragController::tryDHTMLDrag(DragData* dragData, DragOperation& operation)
return true;
}
Node* DragController::draggableNode(const Frame* src, Node* startNode, bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const
Node* DragController::draggableNode(const Frame* src, Node* startNode, const IntPoint& dragOrigin, DragState& state) const
{
if (!dhtmlOK && !uaOK)
return 0;
state.m_dragType = (src->selection()->contains(dragOrigin)) ? DragSourceActionSelection : DragSourceActionNone;
for (const RenderObject* renderer = startNode->renderer(); renderer; renderer = renderer->parent()) {
Node* node = renderer->node();
if (node && node->nodeType() == Node::TEXT_NODE) {
// Since there's no way for the author to address the -webkit-user-drag style for a text node,
// we use our own judgement.
if (uaOK && mayStartDragAtEventLocation(src, IntPoint(x, y), node)) {
dhtmlWillDrag = false;
return node;
}
if (node->canStartSelection())
// In this case we have a click in the unselected portion of text. If this text is
// selectable, we want to start the selection process instead of looking for a parent
// to try to drag.
return 0;
} else {
if (!node)
// Anonymous render blocks don't correspond to actual DOM nodes, so we skip over them
// for the purposes of finding a draggable node.
continue;
if (!(state.m_dragType & DragSourceActionSelection) && node->isTextNode() && node->canStartSelection())
// In this case we have a click in the unselected portion of text. If this text is
// selectable, we want to start the selection process instead of looking for a parent
// to try to drag.
return 0;
if (node->isElementNode()) {
EUserDrag dragMode = renderer->style()->userDrag();
if (dhtmlOK && dragMode == DRAG_ELEMENT) {
dhtmlWillDrag = true;
if ((m_dragSourceAction & DragSourceActionDHTML) && dragMode == DRAG_ELEMENT) {
state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionDHTML);
return node;
}
if (uaOK && dragMode == DRAG_AUTO && mayStartDragAtEventLocation(src, IntPoint(x, y), node)) {
dhtmlWillDrag = false;
return node;
if (dragMode == DRAG_AUTO) {
if ((m_dragSourceAction & DragSourceActionImage)
&& node->hasTagName(HTMLNames::imgTag)
&& src->settings()->loadsImagesAutomatically()) {
state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionImage);
return node;
}
if ((m_dragSourceAction & DragSourceActionLink)
&& node->hasTagName(HTMLNames::aTag)
&& static_cast<HTMLAnchorElement*>(node)->isLiveLink()) {
state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionLink);
return node;
}
}
}
}
return 0;
}
bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPoint& framePos, Node* node) const
{
ASSERT(frame);
ASSERT(frame->settings());
if (!frame->view() || !frame->contentRenderer())
return false;
HitTestResult mouseDownTarget = HitTestResult(framePos);
mouseDownTarget = frame->eventHandler()->hitTestResultAtPoint(framePos, true);
if (node)
mouseDownTarget.setInnerNonSharedNode(node);
if (mouseDownTarget.image()
&& !mouseDownTarget.absoluteImageURL().isEmpty()
&& frame->settings()->loadsImagesAutomatically()
&& m_dragSourceAction & DragSourceActionImage)
return true;
if (!mouseDownTarget.absoluteLinkURL().isEmpty()
&& m_dragSourceAction & DragSourceActionLink
&& mouseDownTarget.isLiveLink()
&& mouseDownTarget.URLElement()->renderer() && mouseDownTarget.URLElement()->renderer()->style()->userDrag() != DRAG_NONE)
return true;
if (mouseDownTarget.isSelected()
&& m_dragSourceAction & DragSourceActionSelection)
return true;
return false;
// We either have nothing to drag or we have a selection and we're not over a draggable element.
return (state.m_dragType & DragSourceActionSelection) ? startNode : 0;
}
static CachedImage* getCachedImage(Element* element)
......@@ -695,19 +670,21 @@ static IntPoint dragLocForSelectionDrag(Frame* src)
return IntPoint(xpos, ypos);
}
bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag)
bool DragController::startDrag(Frame* src, const DragState& state, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin)
{
ASSERT(src);
ASSERT(clipboard);
if (!src->view() || !src->contentRenderer())
return false;
HitTestResult dragSource = HitTestResult(dragOrigin);
dragSource = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true);
KURL linkURL = dragSource.absoluteLinkURL();
KURL imageURL = dragSource.absoluteImageURL();
bool isSelected = dragSource.isSelected();
HitTestResult hitTestResult = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true);
if (!state.m_dragSrc->contains(hitTestResult.innerNode()))
// The original node being dragged isn't under the drag origin anymore... maybe it was
// hidden or moved out from under the cursor. Regardless, we don't want to start a drag on
// something that's not actually under the drag origin.
return false;
KURL linkURL = hitTestResult.absoluteLinkURL();
KURL imageURL = hitTestResult.absoluteImageURL();
IntPoint mouseDraggedPoint = src->view()->windowToContents(dragEvent.pos());
......@@ -718,14 +695,14 @@ bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation s
IntPoint dragLoc(0, 0);
IntPoint dragImageOffset(0, 0);
if (isDHTMLDrag)
Clipboard* clipboard = state.m_dragClipboard.get();
if (state.m_dragType == DragSourceActionDHTML)
dragImage = clipboard->createDragImage(dragImageOffset);
else {
// This drag operation is not a DHTML drag and may go outside the WebView.
// We provide a default set of allowed drag operations that follows from:
if (state.m_dragType == DragSourceActionSelection || !imageURL.isEmpty() || !linkURL.isEmpty())
// Selection, image, and link drags receive a default set of allowed drag operations that
// follows from:
// http://trac.webkit.org/browser/trunk/WebKit/mac/WebView/WebHTMLView.mm?rev=48526#L3430
m_sourceDragOperation = (DragOperation)(DragOperationGeneric | DragOperationCopy);
}
m_sourceDragOperation = static_cast<DragOperation>(m_sourceDragOperation | DragOperationGeneric | DragOperationCopy);
// We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging.
// This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp.
......@@ -736,26 +713,44 @@ bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation s
bool startedDrag = true; // optimism - we almost always manage to start the drag
Node* node = dragSource.innerNonSharedNode();
Node* node = state.m_dragSrc.get();
Image* image = getImage(static_cast<Element*>(node));
if (!imageURL.isEmpty() && node && node->isElementNode() && image
&& (m_dragSourceAction & DragSourceActionImage)) {
if (state.m_dragType == DragSourceActionSelection) {
if (!clipboard->hasData()) {
if (isNodeInTextFormControl(src->selection()->start().deprecatedNode()))
clipboard->writePlainText(src->editor()->selectedText());
else {
RefPtr<Range> selectionRange = src->selection()->toNormalizedRange();
ASSERT(selectionRange);
clipboard->writeRange(selectionRange.get(), src);
}
}
m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard);
if (!dragImage) {
dragImage = createDragImageForSelection(src);
dragLoc = dragLocForSelectionDrag(src);
m_dragOffset = IntPoint(dragOrigin.x() - dragLoc.x(), dragOrigin.y() - dragLoc.y());
}
doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
} else if (!imageURL.isEmpty() && node && node->isElementNode() && image
&& (m_dragSourceAction & DragSourceActionImage)) {
// We shouldn't be starting a drag for an image that can't provide an extension.
// This is an early detection for problems encountered later upon drop.
ASSERT(!image->filenameExtension().isEmpty());
Element* element = static_cast<Element*>(node);
if (!clipboard->hasData()) {
m_draggingImageURL = imageURL;
prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, dragSource.altDisplayString());
prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, hitTestResult.altDisplayString());
}
m_client->willPerformDragSourceAction(DragSourceActionImage, dragOrigin, clipboard);
if (!dragImage) {
IntRect imageRect = dragSource.imageRect();
IntRect imageRect = hitTestResult.imageRect();
imageRect.setLocation(m_page->mainFrame()->view()->windowToContents(src->view()->contentsToWindow(imageRect.location())));
doImageDrag(element, dragOrigin, dragSource.imageRect(), clipboard, src, m_dragOffset);
doImageDrag(element, dragOrigin, hitTestResult.imageRect(), clipboard, src, m_dragOffset);
} else
// DHTML defined drag image
doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
......@@ -764,7 +759,7 @@ bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation s
if (!clipboard->hasData())
// Simplify whitespace so the title put on the clipboard resembles what the user sees
// on the web page. This includes replacing newlines with spaces.
clipboard->writeURL(linkURL, dragSource.textContent().simplifyWhiteSpace(), src);
clipboard->writeURL(linkURL, hitTestResult.textContent().simplifyWhiteSpace(), src);
if (src->selection()->isCaret() && src->selection()->isContentEditable()) {
// a user can initiate a drag on a link without having any text
......@@ -778,37 +773,19 @@ bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation s
m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard);
if (!dragImage) {
dragImage = createDragImageForLink(linkURL, dragSource.textContent(), src);
dragImage = createDragImageForLink(linkURL, hitTestResult.textContent(), src);
IntSize size = dragImageSize(dragImage);
m_dragOffset = IntPoint(-size.width() / 2, -LinkDragBorderInset);
dragLoc = IntPoint(mouseDraggedPoint.x() + m_dragOffset.x(), mouseDraggedPoint.y() + m_dragOffset.y());
}
doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true);
} else if (isSelected && (m_dragSourceAction & DragSourceActionSelection)) {
if (!clipboard->hasData()) {
if (isNodeInTextFormControl(src->selection()->start().deprecatedNode()))
clipboard->writePlainText(src->editor()->selectedText());
else {
RefPtr<Range> selectionRange = src->selection()->toNormalizedRange();
ASSERT(selectionRange);
clipboard->writeRange(selectionRange.get(), src);
}
}
m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard);
if (!dragImage) {
dragImage = createDragImageForSelection(src);
dragLoc = dragLocForSelectionDrag(src);
m_dragOffset = IntPoint((int)(dragOrigin.x() - dragLoc.x()), (int)(dragOrigin.y() - dragLoc.y()));
}
doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
} else if (isDHTMLDrag) {
} else if (state.m_dragType == DragSourceActionDHTML) {
ASSERT(m_dragSourceAction & DragSourceActionDHTML);
m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard);
doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
} else {
// Only way I know to get here is if to get here is if the original element clicked on in the mousedown is no longer
// under the mousedown point, so linkURL, imageURL and isSelected are all false/empty.
// draggableNode() determined an image or link node was draggable, but it turns out the
// image or link had no URL, so there is nothing to drag.
startedDrag = false;
}
......
......@@ -37,6 +37,7 @@ namespace WebCore {
class Document;
class DragClient;
class DragData;
struct DragState;
class Element;
class Frame;
class FrameSelection;
......@@ -75,13 +76,12 @@ namespace WebCore {
DragDestinationAction dragDestinationAction() const { return m_dragDestinationAction; }
DragSourceAction delegateDragSourceAction(const IntPoint& pagePoint);
Node* draggableNode(const Frame*, Node*, bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const;
bool mayStartDragAtEventLocation(const Frame*, const IntPoint& framePos, Node*) const;
Node* draggableNode(const Frame*, Node*, const IntPoint&, DragState&) const;
void dragEnded();
void placeDragCaret(const IntPoint&);
bool startDrag(Frame* src, Clipboard*, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag);
bool startDrag(Frame* src, const DragState&, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin);
static const IntSize& maxDragImageSize();
static const int LinkDragBorderInset;
......
......@@ -26,23 +26,29 @@
#ifndef DragState_h
#define DragState_h
#include "DragActions.h"
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
#include <wtf/RefPtr.h>
namespace WebCore {
class Clipboard;
class Node;
struct DragState {
WTF_MAKE_NONCOPYABLE(DragState);
WTF_MAKE_FAST_ALLOCATED;
public:
enum EventDispatchPolicy {
DoNotDispatchEvents,
DispatchEvents,
};
DragState() { }
bool shouldDispatchEvents() const { return m_eventDispatchPolicy == DispatchEvents; }
RefPtr<Node> m_dragSrc; // element that may be a drag source, for the current mouse gesture
bool m_dragSrcIsLink;
bool m_dragSrcIsImage;
bool m_dragSrcInSelection;
bool m_dragSrcMayBeDHTML;
bool m_dragSrcMayBeUA; // Are DHTML and/or the UserAgent allowed to drag out?
bool m_dragSrcIsDHTML;
EventDispatchPolicy m_eventDispatchPolicy;
DragSourceAction m_dragType;
RefPtr<Clipboard> m_dragClipboard; // used on only the source side of dragging
};
......
......@@ -79,6 +79,7 @@
#include "UserTypingGestureIndicator.h"
#include "WheelEvent.h"
#include "WindowsKeyboardCodes.h"
#include <wtf/Assertions.h>
#include <wtf/CurrentTime.h>
#include <wtf/StdLibExtras.h>
......@@ -178,6 +179,7 @@ EventHandler::EventHandler(Frame* frame)
, m_mouseDownMayStartSelect(false)
#if ENABLE(DRAG_SUPPORT)
, m_mouseDownMayStartDrag(false)
, m_dragMayStartSelectionInstead(false)
#endif
, m_mouseDownWasSingleClickInSelection(false)
, m_beganSelectingText(false)
......@@ -594,12 +596,6 @@ bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
if (event.button() != LeftButton || event.clickCount() != 1)
return false;
bool DHTMLFlag;
bool UAFlag;
allowDHTMLDrag(DHTMLFlag, UAFlag);
if (!DHTMLFlag && !UAFlag)
return false;
FrameView* view = m_frame->view();
if (!view)
return false;
......@@ -608,11 +604,12 @@ bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
if (!page)
return false;
updateDragSourceActionsAllowed();
HitTestRequest request(HitTestRequest::ReadOnly);
HitTestResult result(view->windowToContents(event.pos()));
m_frame->contentRenderer()->layer()->hitTest(request, result);
bool srcIsDHTML;
return result.innerNode() && page->dragController()->draggableNode(m_frame, result.innerNode(), DHTMLFlag, UAFlag, result.point().x(), result.point().y(), srcIsDHTML);
DragState state;
return result.innerNode() && page->dragController()->draggableNode(m_frame, result.innerNode(), result.point(), state);
}
void EventHandler::updateSelectionForMouseDrag()
......@@ -899,25 +896,20 @@ void EventHandler::setAutoscrollRenderer(RenderObject* renderer)
}
#if ENABLE(DRAG_SUPPORT)
void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const
DragSourceAction EventHandler::updateDragSourceActionsAllowed() const
{
flagDHTML = false;
flagUA = false;
if (!m_frame)
return;
return DragSourceActionNone;
Page* page = m_frame->page();
if (!page)
return;
return DragSourceActionNone;
FrameView* view = m_frame->view();
if (!view)
return;
return DragSourceActionNone;
unsigned mask = page->dragController()->delegateDragSourceAction(view->contentsToWindow(m_mouseDownPos));
flagDHTML = (mask & DragSourceActionDHTML) != DragSourceActionNone;
flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection));
return page->dragController()->delegateDragSourceAction(view->contentsToWindow(m_mouseDownPos));
}
#endif // ENABLE(DRAG_SUPPORT)
......@@ -1809,7 +1801,7 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard*
// Moreover, this ordering conforms to section 7.9.4 of the HTML 5 spec. <http://dev.w3.org/html5/spec/Overview.html#drag-and-drop-processing-model>.
if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) {
// 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().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
// for now we don't care if event handler cancels default behavior, since there is none
dispatchDragSrcEvent(eventNames().dragEvent, event);
}
......@@ -1827,7 +1819,7 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard*
} else {
if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) {
// 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().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
// for now we don't care if event handler cancels default behavior, since there is none
dispatchDragSrcEvent(eventNames().dragEvent, event);
}
......@@ -1843,7 +1835,7 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard*
void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)