Changeset 86472 in webkit


Ignore:
Timestamp:
May 13, 2011 4:31:49 PM (13 years ago)
Author:
dcheng@chromium.org
Message:

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:
Location:
trunk
Files:
2 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r86467 r86472  
     12011-05-13  Daniel Cheng  <dcheng@chromium.org>
     2
     3        Reviewed by Tony Chang.
     4
     5        Improve drag start logic
     6        https://bugs.webkit.org/show_bug.cgi?id=59409
     7
     8        Add a new test to test drag start edge cases on Mac (because of a non-zero text drag delay)
     9        as well as rebase an existing test.
     10
     11        * fast/css/user-drag-none.html: Text nodes are no longer draggable.
     12        * platform/mac/editing/pasteboard/drag-selections-to-contenteditable-expected.txt: Added.
     13        * platform/mac/editing/pasteboard/drag-selections-to-contenteditable.html: Added.
     14
    1152011-05-13  Anders Carlsson  <andersca@apple.com>
    216
  • trunk/LayoutTests/fast/css/user-drag-none.html

    r55353 r86472  
    2020    </div>
    2121
    22     <div class="box" expect="IMG text text A nil">
     22    <div class="box" expect="IMG A A A nil">
    2323        <a href="#"><img src="resources/greenbox.png">x<br><span>y</span></a>
    2424    </div>
    2525
    26     <div class="box" expect="IMG text text A nil">
     26    <div class="box" expect="IMG A A A nil">
    2727        <a href="#" class="drag-element"><img src="resources/greenbox.png">x<br><span>y</span></a>
    2828    </div>
     
    3232    </div>
    3333
    34     <div class="box" expect="A text text A nil">
     34    <div class="box" expect="A A A A nil">
    3535        <a href="#"><img class="drag-none" src="resources/greenbox.png">x<br><span>y</span></a>
    3636    </div>
    3737
    38     <div class="box" expect="A text text A nil">
     38    <div class="box" expect="A A A A nil">
    3939        <a href="#" class="drag-element"><img class="drag-none" src="resources/greenbox.png">x<br><span>y</span></a>
    4040    </div>
     
    4444    </div>
    4545
    46     <div class="box drag-element" expect="A text text A DIV">
     46    <div class="box drag-element" expect="A A A A DIV">
    4747        <a href="#"><img class="drag-none" src="resources/greenbox.png">x<br><span>y</span></a>
    4848    </div>
    4949
    50     <div class="box drag-element" expect="A text text A DIV">
     50    <div class="box drag-element" expect="A A A A DIV">
    5151        <a href="#" class="drag-element"><img class="drag-none" src="resources/greenbox.png">x<br><span>y</span></a>
    5252    </div>
  • trunk/Source/WebCore/ChangeLog

    r86469 r86472  
     12011-05-13  Daniel Cheng  <dcheng@chromium.org>
     2
     3        Reviewed by Tony Chang.
     4
     5        Improve drag start logic
     6        https://bugs.webkit.org/show_bug.cgi?id=59409
     7
     8        Rewrite and simplify the dragging logic to better match IE, Firefox, and the behavior
     9        defined in the spec. Among other things:
     10        - draggableNode() no longer returns text nodes when dragging anchors.
     11        - When starting a drag over an image in a selection, prefer to drag the selection.
     12        - Several redundant hit tests have been removed.
     13        - Minor refactoring to make the logic easier to follow.
     14
     15        Test: platform/mac/editing/pasteboard/drag-selections-to-contenteditable.html
     16
     17        * WebCore.xcodeproj/project.pbxproj:
     18        * page/DragController.cpp:
     19        (WebCore::DragController::draggableNode):
     20        (WebCore::DragController::startDrag):
     21        * page/DragController.h:
     22        * page/DragState.h:
     23        (WebCore::DragState::shouldDispatchEvents):
     24        * page/EventHandler.cpp:
     25        (WebCore::EventHandler::EventHandler):
     26        (WebCore::EventHandler::eventMayStartDrag):
     27        (WebCore::EventHandler::updateDragSourceActionsAllowed):
     28        (WebCore::EventHandler::updateDragAndDrop):
     29        (WebCore::EventHandler::cancelDragAndDrop):
     30        (WebCore::EventHandler::dragHysteresisExceeded):
     31        (WebCore::EventHandler::dragSourceEndedAt):
     32        (WebCore::ExactlyOneBitSet):
     33        (WebCore::EventHandler::handleDrag):
     34        * page/EventHandler.h:
     35
    1362011-05-13  Oliver Hunt  <oliver@apple.com>
    237
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r86451 r86472  
    16761676                81BE20D211F4BC3200915DFA /* JSIDBCursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 81BE20A711F4B66F00915DFA /* JSIDBCursor.cpp */; };
    16771677                81BE20D311F4BC3200915DFA /* JSIDBCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 81BE20A811F4B66F00915DFA /* JSIDBCursor.h */; };
    1678                 81F65FF613788FAA00FF6F2D /* DragState.h in Headers */ = {isa = PBXBuildFile; fileRef = 81F65FF513788FAA00FF6F2D /* DragState.h */; };
     1678                81F65FF613788FAA00FF6F2D /* DragState.h in Headers */ = {isa = PBXBuildFile; fileRef = 81F65FF513788FAA00FF6F2D /* DragState.h */; settings = {ATTRIBUTES = (Private, ); }; };
    16791679                82AB1743124B99EC00C5069D /* InspectorCSSAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 82AB1741124B99EC00C5069D /* InspectorCSSAgent.cpp */; };
    16801680                82AB1744124B99EC00C5069D /* InspectorCSSAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 82AB1742124B99EC00C5069D /* InspectorCSSAgent.h */; };
  • trunk/Source/WebCore/page/DragController.cpp

    r86128 r86472  
    570570}
    571571
    572 Node* DragController::draggableNode(const Frame* src, Node* startNode, bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const
    573 {
    574     if (!dhtmlOK && !uaOK)
    575         return 0;
     572Node* DragController::draggableNode(const Frame* src, Node* startNode, const IntPoint& dragOrigin, DragState& state) const
     573{
     574    state.m_dragType = (src->selection()->contains(dragOrigin)) ? DragSourceActionSelection : DragSourceActionNone;
    576575
    577576    for (const RenderObject* renderer = startNode->renderer(); renderer; renderer = renderer->parent()) {
    578577        Node* node = renderer->node();
    579         if (node && node->nodeType() == Node::TEXT_NODE) {
    580             // Since there's no way for the author to address the -webkit-user-drag style for a text node,
    581             // we use our own judgement.
    582             if (uaOK && mayStartDragAtEventLocation(src, IntPoint(x, y), node)) {
    583                 dhtmlWillDrag = false;
     578        if (!node)
     579            // Anonymous render blocks don't correspond to actual DOM nodes, so we skip over them
     580            // for the purposes of finding a draggable node.
     581            continue;
     582        if (!(state.m_dragType & DragSourceActionSelection) && node->isTextNode() && node->canStartSelection())
     583            // In this case we have a click in the unselected portion of text. If this text is
     584            // selectable, we want to start the selection process instead of looking for a parent
     585            // to try to drag.
     586            return 0;
     587        if (node->isElementNode()) {
     588            EUserDrag dragMode = renderer->style()->userDrag();
     589            if ((m_dragSourceAction & DragSourceActionDHTML) && dragMode == DRAG_ELEMENT) {
     590                state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionDHTML);
    584591                return node;
    585592            }
    586             if (node->canStartSelection())
    587                 // In this case we have a click in the unselected portion of text. If this text is
    588                 // selectable, we want to start the selection process instead of looking for a parent
    589                 // to try to drag.
    590                 return 0;
    591         } else {
    592             EUserDrag dragMode = renderer->style()->userDrag();
    593             if (dhtmlOK && dragMode == DRAG_ELEMENT) {
    594                 dhtmlWillDrag = true;
    595                 return node;
     593            if (dragMode == DRAG_AUTO) {
     594                if ((m_dragSourceAction & DragSourceActionImage)
     595                    && node->hasTagName(HTMLNames::imgTag)
     596                    && src->settings()->loadsImagesAutomatically()) {
     597                    state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionImage);
     598                    return node;
     599                }
     600                if ((m_dragSourceAction & DragSourceActionLink)
     601                    && node->hasTagName(HTMLNames::aTag)
     602                    && static_cast<HTMLAnchorElement*>(node)->isLiveLink()) {
     603                    state.m_dragType = static_cast<DragSourceAction>(state.m_dragType | DragSourceActionLink);
     604                    return node;
     605                }
    596606            }
    597             if (uaOK && dragMode == DRAG_AUTO && mayStartDragAtEventLocation(src, IntPoint(x, y), node)) {
    598                 dhtmlWillDrag = false;
    599                 return node;
    600             }
    601         }
    602     }
    603     return 0;
    604 }
    605 
    606 bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPoint& framePos, Node* node) const
    607 {
    608     ASSERT(frame);
    609     ASSERT(frame->settings());
    610 
    611     if (!frame->view() || !frame->contentRenderer())
    612         return false;
    613 
    614     HitTestResult mouseDownTarget = HitTestResult(framePos);
    615 
    616     mouseDownTarget = frame->eventHandler()->hitTestResultAtPoint(framePos, true);
    617     if (node)
    618         mouseDownTarget.setInnerNonSharedNode(node);
    619 
    620     if (mouseDownTarget.image()
    621         && !mouseDownTarget.absoluteImageURL().isEmpty()
    622         && frame->settings()->loadsImagesAutomatically()
    623         && m_dragSourceAction & DragSourceActionImage)
    624         return true;
    625 
    626     if (!mouseDownTarget.absoluteLinkURL().isEmpty()
    627         && m_dragSourceAction & DragSourceActionLink
    628         && mouseDownTarget.isLiveLink()
    629         && mouseDownTarget.URLElement()->renderer() && mouseDownTarget.URLElement()->renderer()->style()->userDrag() != DRAG_NONE)
    630         return true;
    631 
    632     if (mouseDownTarget.isSelected()
    633         && m_dragSourceAction & DragSourceActionSelection)
    634         return true;
    635 
    636     return false;
     607        }
     608    }
     609
     610    // We either have nothing to drag or we have a selection and we're not over a draggable element.
     611    return (state.m_dragType & DragSourceActionSelection) ? startNode : 0;
    637612}
    638613
     
    696671}
    697672
    698 bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag)
     673bool DragController::startDrag(Frame* src, const DragState& state, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin)
    699674{
    700675    ASSERT(src);
    701     ASSERT(clipboard);
    702676
    703677    if (!src->view() || !src->contentRenderer())
    704678        return false;
    705679
    706     HitTestResult dragSource = HitTestResult(dragOrigin);
    707     dragSource = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true);
    708     KURL linkURL = dragSource.absoluteLinkURL();
    709     KURL imageURL = dragSource.absoluteImageURL();
    710     bool isSelected = dragSource.isSelected();
     680    HitTestResult hitTestResult = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true);
     681    if (!state.m_dragSrc->contains(hitTestResult.innerNode()))
     682        // The original node being dragged isn't under the drag origin anymore... maybe it was
     683        // hidden or moved out from under the cursor. Regardless, we don't want to start a drag on
     684        // something that's not actually under the drag origin.
     685        return false;
     686    KURL linkURL = hitTestResult.absoluteLinkURL();
     687    KURL imageURL = hitTestResult.absoluteImageURL();
    711688
    712689    IntPoint mouseDraggedPoint = src->view()->windowToContents(dragEvent.pos());
     
    719696    IntPoint dragImageOffset(0, 0);
    720697
    721     if (isDHTMLDrag)
     698    Clipboard* clipboard = state.m_dragClipboard.get();
     699    if (state.m_dragType == DragSourceActionDHTML)
    722700        dragImage = clipboard->createDragImage(dragImageOffset);
    723     else {
    724         // This drag operation is not a DHTML drag and may go outside the WebView.
    725         // We provide a default set of allowed drag operations that follows from:
     701    if (state.m_dragType == DragSourceActionSelection || !imageURL.isEmpty() || !linkURL.isEmpty())
     702        // Selection, image, and link drags receive a default set of allowed drag operations that
     703        // follows from:
    726704        // http://trac.webkit.org/browser/trunk/WebKit/mac/WebView/WebHTMLView.mm?rev=48526#L3430
    727         m_sourceDragOperation = (DragOperation)(DragOperationGeneric | DragOperationCopy);
    728     }
     705        m_sourceDragOperation = static_cast<DragOperation>(m_sourceDragOperation | DragOperationGeneric | DragOperationCopy);
    729706
    730707    // We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging.
     
    737714    bool startedDrag = true; // optimism - we almost always manage to start the drag
    738715
    739     Node* node = dragSource.innerNonSharedNode();
     716    Node* node = state.m_dragSrc.get();
    740717
    741718    Image* image = getImage(static_cast<Element*>(node));
    742     if (!imageURL.isEmpty() && node && node->isElementNode() && image
    743             && (m_dragSourceAction & DragSourceActionImage)) {
     719    if (state.m_dragType == DragSourceActionSelection) {
     720        if (!clipboard->hasData()) {
     721            if (isNodeInTextFormControl(src->selection()->start().deprecatedNode()))
     722                clipboard->writePlainText(src->editor()->selectedText());
     723            else {
     724                RefPtr<Range> selectionRange = src->selection()->toNormalizedRange();
     725                ASSERT(selectionRange);
     726
     727                clipboard->writeRange(selectionRange.get(), src);
     728            }
     729        }
     730        m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard);
     731        if (!dragImage) {
     732            dragImage = createDragImageForSelection(src);
     733            dragLoc = dragLocForSelectionDrag(src);
     734            m_dragOffset = IntPoint(dragOrigin.x() - dragLoc.x(), dragOrigin.y() - dragLoc.y());
     735        }
     736        doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
     737    } else if (!imageURL.isEmpty() && node && node->isElementNode() && image
     738               && (m_dragSourceAction & DragSourceActionImage)) {
    744739        // We shouldn't be starting a drag for an image that can't provide an extension.
    745740        // This is an early detection for problems encountered later upon drop.
     
    748743        if (!clipboard->hasData()) {
    749744            m_draggingImageURL = imageURL;
    750             prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, dragSource.altDisplayString());
     745            prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, hitTestResult.altDisplayString());
    751746        }
    752747
     
    754749
    755750        if (!dragImage) {
    756             IntRect imageRect = dragSource.imageRect();
     751            IntRect imageRect = hitTestResult.imageRect();
    757752            imageRect.setLocation(m_page->mainFrame()->view()->windowToContents(src->view()->contentsToWindow(imageRect.location())));
    758             doImageDrag(element, dragOrigin, dragSource.imageRect(), clipboard, src, m_dragOffset);
     753            doImageDrag(element, dragOrigin, hitTestResult.imageRect(), clipboard, src, m_dragOffset);
    759754        } else
    760755            // DHTML defined drag image
     
    765760            // Simplify whitespace so the title put on the clipboard resembles what the user sees
    766761            // on the web page. This includes replacing newlines with spaces.
    767             clipboard->writeURL(linkURL, dragSource.textContent().simplifyWhiteSpace(), src);
     762            clipboard->writeURL(linkURL, hitTestResult.textContent().simplifyWhiteSpace(), src);
    768763
    769764        if (src->selection()->isCaret() && src->selection()->isContentEditable()) {
     
    779774        m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard);
    780775        if (!dragImage) {
    781             dragImage = createDragImageForLink(linkURL, dragSource.textContent(), src);
     776            dragImage = createDragImageForLink(linkURL, hitTestResult.textContent(), src);
    782777            IntSize size = dragImageSize(dragImage);
    783778            m_dragOffset = IntPoint(-size.width() / 2, -LinkDragBorderInset);
     
    785780        }
    786781        doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true);
    787     } else if (isSelected && (m_dragSourceAction & DragSourceActionSelection)) {
    788         if (!clipboard->hasData()) {
    789             if (isNodeInTextFormControl(src->selection()->start().deprecatedNode()))
    790                 clipboard->writePlainText(src->editor()->selectedText());
    791             else {
    792                 RefPtr<Range> selectionRange = src->selection()->toNormalizedRange();
    793                 ASSERT(selectionRange);
    794 
    795                 clipboard->writeRange(selectionRange.get(), src);
    796             }
    797         }
    798         m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard);
    799         if (!dragImage) {
    800             dragImage = createDragImageForSelection(src);
    801             dragLoc = dragLocForSelectionDrag(src);
    802             m_dragOffset = IntPoint((int)(dragOrigin.x() - dragLoc.x()), (int)(dragOrigin.y() - dragLoc.y()));
    803         }
    804         doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
    805     } else if (isDHTMLDrag) {
     782    } else if (state.m_dragType == DragSourceActionDHTML) {
    806783        ASSERT(m_dragSourceAction & DragSourceActionDHTML);
    807784        m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard);
    808785        doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
    809786    } else {
    810         // 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
    811         // under the mousedown point, so linkURL, imageURL and isSelected are all false/empty.
     787        // draggableNode() determined an image or link node was draggable, but it turns out the
     788        // image or link had no URL, so there is nothing to drag.
    812789        startedDrag = false;
    813790    }
  • trunk/Source/WebCore/page/DragController.h

    r86128 r86472  
    3838    class DragClient;
    3939    class DragData;
     40    struct DragState;
    4041    class Element;
    4142    class Frame;
     
    7677        DragSourceAction delegateDragSourceAction(const IntPoint& pagePoint);
    7778       
    78         Node* draggableNode(const Frame*, Node*, bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const;
    79         bool mayStartDragAtEventLocation(const Frame*, const IntPoint& framePos, Node*) const;
     79        Node* draggableNode(const Frame*, Node*, const IntPoint&, DragState&) const;
    8080        void dragEnded();
    8181       
    8282        void placeDragCaret(const IntPoint&);
    8383       
    84         bool startDrag(Frame* src, Clipboard*, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag);
     84        bool startDrag(Frame* src, const DragState&, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin);
    8585        static const IntSize& maxDragImageSize();
    8686       
  • trunk/Source/WebCore/page/DragState.h

    r86129 r86472  
    2727#define DragState_h
    2828
     29#include "DragActions.h"
    2930#include <wtf/Forward.h>
     31#include <wtf/Noncopyable.h>
    3032#include <wtf/RefPtr.h>
    3133
    3234namespace WebCore {
     35
     36class Clipboard;
     37class Node;
    3338
    3439struct DragState {
     
    3641    WTF_MAKE_FAST_ALLOCATED;
    3742public:
     43    enum EventDispatchPolicy {
     44        DoNotDispatchEvents,
     45        DispatchEvents,
     46    };
    3847    DragState() { }
     48    bool shouldDispatchEvents() const { return m_eventDispatchPolicy == DispatchEvents; }
    3949    RefPtr<Node> m_dragSrc; // element that may be a drag source, for the current mouse gesture
    40     bool m_dragSrcIsLink;
    41     bool m_dragSrcIsImage;
    42     bool m_dragSrcInSelection;
    43     bool m_dragSrcMayBeDHTML;
    44     bool m_dragSrcMayBeUA; // Are DHTML and/or the UserAgent allowed to drag out?
    45     bool m_dragSrcIsDHTML;
     50    EventDispatchPolicy m_eventDispatchPolicy;
     51    DragSourceAction m_dragType;
    4652    RefPtr<Clipboard> m_dragClipboard; // used on only the source side of dragging
    4753};
  • trunk/Source/WebCore/page/EventHandler.cpp

    r86461 r86472  
    8080#include "WheelEvent.h"
    8181#include "WindowsKeyboardCodes.h"
     82#include <wtf/Assertions.h>
    8283#include <wtf/CurrentTime.h>
    8384#include <wtf/StdLibExtras.h>
     
    179180#if ENABLE(DRAG_SUPPORT)
    180181    , m_mouseDownMayStartDrag(false)
     182    , m_dragMayStartSelectionInstead(false)
    181183#endif
    182184    , m_mouseDownWasSingleClickInSelection(false)
     
    595597        return false;
    596598   
    597     bool DHTMLFlag;
    598     bool UAFlag;
    599     allowDHTMLDrag(DHTMLFlag, UAFlag);
    600     if (!DHTMLFlag && !UAFlag)
    601         return false;
    602 
    603599    FrameView* view = m_frame->view();
    604600    if (!view)
     
    609605        return false;
    610606
     607    updateDragSourceActionsAllowed();
    611608    HitTestRequest request(HitTestRequest::ReadOnly);
    612609    HitTestResult result(view->windowToContents(event.pos()));
    613610    m_frame->contentRenderer()->layer()->hitTest(request, result);
    614     bool srcIsDHTML;
    615     return result.innerNode() && page->dragController()->draggableNode(m_frame, result.innerNode(), DHTMLFlag, UAFlag, result.point().x(), result.point().y(), srcIsDHTML);
     611    DragState state;
     612    return result.innerNode() && page->dragController()->draggableNode(m_frame, result.innerNode(), result.point(), state);
    616613}
    617614
     
    900897
    901898#if ENABLE(DRAG_SUPPORT)
    902 void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const
    903 {
    904     flagDHTML = false;
    905     flagUA = false;
    906 
     899DragSourceAction EventHandler::updateDragSourceActionsAllowed() const
     900{
    907901    if (!m_frame)
    908         return;
     902        return DragSourceActionNone;
    909903
    910904    Page* page = m_frame->page();
    911905    if (!page)
    912         return;
     906        return DragSourceActionNone;
    913907
    914908    FrameView* view = m_frame->view();
    915909    if (!view)
    916         return;
    917 
    918     unsigned mask = page->dragController()->delegateDragSourceAction(view->contentsToWindow(m_mouseDownPos));
    919     flagDHTML = (mask & DragSourceActionDHTML) != DragSourceActionNone;
    920     flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection));
     910        return DragSourceActionNone;
     911
     912    return page->dragController()->delegateDragSourceAction(view->contentsToWindow(m_mouseDownPos));
    921913}
    922914#endif // ENABLE(DRAG_SUPPORT)
     
    18101802        if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) {
    18111803            // 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.
    1812             if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
     1804            if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
    18131805                // for now we don't care if event handler cancels default behavior, since there is none
    18141806                dispatchDragSrcEvent(eventNames().dragEvent, event);
     
    18281820        if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) {
    18291821            // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
    1830             if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
     1822            if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
    18311823                // for now we don't care if event handler cancels default behavior, since there is none
    18321824                dispatchDragSrcEvent(eventNames().dragEvent, event);
     
    18441836{
    18451837    if (m_dragTarget && canHandleDragAndDropForTarget(CancelDragAndDrop, m_dragTarget.get(), event, clipboard)) {
    1846         if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML)
     1838        if (dragState().m_dragSrc && dragState().shouldDispatchEvents())
    18471839            dispatchDragSrcEvent(eventNames().dragEvent, event);
    18481840        dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
     
    26372629   
    26382630    int threshold = GeneralDragHysteresis;
    2639     if (dragState().m_dragSrcIsImage)
     2631    switch (dragState().m_dragType) {
     2632    case DragSourceActionSelection:
     2633        threshold = TextDragHysteresis;
     2634        break;
     2635    case DragSourceActionImage:
    26402636        threshold = ImageDragHysteresis;
    2641     else if (dragState().m_dragSrcIsLink)
     2637        break;
     2638    case DragSourceActionLink:
    26422639        threshold = LinkDragHysteresis;
    2643     else if (dragState().m_dragSrcInSelection)
    2644         threshold = TextDragHysteresis;
     2640        break;
     2641    case DragSourceActionDHTML:
     2642        break;
     2643    case DragSourceActionNone:
     2644    case DragSourceActionAny:
     2645        ASSERT_NOT_REACHED();
     2646    }
    26452647   
    26462648    return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
     
    26552657void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
    26562658{
    2657     if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
     2659    if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
    26582660        dragState().m_dragClipboard->setDestinationOperation(operation);
    26592661        // for now we don't care if event handler cancels default behavior, since there is none
     
    26732675}
    26742676   
     2677static bool ExactlyOneBitSet(DragSourceAction n)
     2678{
     2679    return n && !(n & (n - 1));
     2680}
     2681
    26752682bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event)
    26762683{
     
    26902697   
    26912698    if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
    2692         allowDHTMLDrag(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA);
    2693         if (!dragState().m_dragSrcMayBeDHTML && !dragState().m_dragSrcMayBeUA)
    2694             m_mouseDownMayStartDrag = false; // no element is draggable
    2695     }
    2696 
    2697     if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
     2699        dragState().m_eventDispatchPolicy = (updateDragSourceActionsAllowed() & DragSourceActionDHTML) ? DragState::DispatchEvents: DragState::DoNotDispatchEvents;
     2700
    26982701        // try to find an element that wants to be dragged
    26992702        HitTestRequest request(HitTestRequest::ReadOnly);
     
    27022705        Node* node = result.innerNode();
    27032706        if (node && m_frame->page())
    2704             dragState().m_dragSrc = m_frame->page()->dragController()->draggableNode(m_frame, node, dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA,
    2705                                                                                      m_mouseDownPos.x(), m_mouseDownPos.y(), dragState().m_dragSrcIsDHTML);
     2707            dragState().m_dragSrc = m_frame->page()->dragController()->draggableNode(m_frame, node, m_mouseDownPos, dragState());
    27062708        else
    27072709            dragState().m_dragSrc = 0;
     
    27092711        if (!dragState().m_dragSrc)
    27102712            m_mouseDownMayStartDrag = false; // no element is draggable
    2711         else {
    2712             // remember some facts about this source, while we have a HitTestResult handy
    2713             node = result.URLElement();
    2714             dragState().m_dragSrcIsLink = node && node->isLink();
    2715            
    2716             node = result.innerNonSharedNode();
    2717             dragState().m_dragSrcIsImage = node && node->renderer() && node->renderer()->isImage();
    2718            
    2719             dragState().m_dragSrcInSelection = m_frame->selection()->contains(m_mouseDownPos);
    2720         }               
     2713        else
     2714            m_dragMayStartSelectionInstead = (dragState().m_dragType & DragSourceActionSelection);
    27212715    }
    27222716   
    27232717    // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
    27242718    // or else we bail on the dragging stuff and allow selection to occur
    2725     if (m_mouseDownMayStartDrag && !dragState().m_dragSrcIsImage && dragState().m_dragSrcInSelection && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
    2726         m_mouseDownMayStartDrag = false;
    2727         dragState().m_dragSrc = 0;
    2728         // ...but if this was the first click in the window, we don't even want to start selection
    2729         if (eventActivatedView(event.event()))
    2730             m_mouseDownMayStartSelect = false;
     2719    if (m_mouseDownMayStartDrag && m_dragMayStartSelectionInstead && (dragState().m_dragType & DragSourceActionSelection) && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
     2720        ASSERT(event.event().eventType() == MouseEventMoved);
     2721        if ((dragState().m_dragType & DragSourceActionImage)) {
     2722            // ... unless the mouse is over an image, then we start dragging just the image
     2723            dragState().m_dragType = DragSourceActionImage;
     2724        } else if (!(dragState().m_dragType & (DragSourceActionDHTML | DragSourceActionLink))) {
     2725            // ... but only bail if we're not over an unselectable element.
     2726            m_mouseDownMayStartDrag = false;
     2727            dragState().m_dragSrc = 0;
     2728            // ... but if this was the first click in the window, we don't even want to start selection
     2729            if (eventActivatedView(event.event()))
     2730                m_mouseDownMayStartSelect = false;
     2731        } else {
     2732            // Prevent the following case from occuring:
     2733            // 1. User starts a drag immediately after mouse down over an unselectable element.
     2734            // 2. We enter this block and decided that since we're over an unselectable element,
     2735            //    don't cancel the drag.
     2736            // 3. The drag gets resolved as a potential selection drag below /but/ we haven't
     2737            //    exceeded the drag hysteresis yet.
     2738            // 4. We enter this block again, and since it's now marked as a selection drag, we
     2739            //    cancel the drag.
     2740            m_dragMayStartSelectionInstead = false;
     2741        }
    27312742    }
    27322743   
     
    27342745        return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
    27352746   
     2747    if (!ExactlyOneBitSet(dragState().m_dragType)) {
     2748        ASSERT((dragState().m_dragType & DragSourceActionSelection));
     2749        ASSERT((dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionDHTML
     2750                || (dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionImage
     2751                || (dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionLink);
     2752        dragState().m_dragType = DragSourceActionSelection;
     2753    }
     2754
    27362755    // We are starting a text/image/url drag, so the cursor should be an arrow
    27372756    if (FrameView* view = m_frame->view()) {
     
    27522771    dragState().m_dragClipboard = createDraggingClipboard(); 
    27532772   
    2754     if (dragState().m_dragSrcMayBeDHTML) {
     2773    if (dragState().shouldDispatchEvents()) {
    27552774        // Check to see if the is a DOM based drag, if it is get the DOM specified drag
    27562775        // image and offset
    2757         if (dragState().m_dragSrcIsDHTML) {
     2776        if (dragState().m_dragType == DragSourceActionDHTML) {
    27582777            if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
    27592778                // FIXME: This doesn't work correctly with transforms.
     
    27912810        Page* page = m_frame->page();
    27922811        DragController* dragController = page ? page->dragController() : 0;
    2793         bool startedDrag = dragController && dragController->startDrag(m_frame, dragState().m_dragClipboard.get(), srcOp, event.event(), m_mouseDownPos, dragState().m_dragSrcIsDHTML);
    2794         if (!startedDrag && dragState().m_dragSrcMayBeDHTML) {
     2812        bool startedDrag = dragController && dragController->startDrag(m_frame, dragState(), srcOp, event.event(), m_mouseDownPos);
     2813        if (!startedDrag && dragState().shouldDispatchEvents()) {
    27952814            // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
    27962815            dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
  • trunk/Source/WebCore/page/EventHandler.h

    r86461 r86472  
    2828
    2929#include "DragActions.h"
     30#include "DragState.h"
    3031#include "FocusDirection.h"
    3132#include "HitTestRequest.h"
     
    5051class Clipboard;
    5152class Cursor;
    52 struct DragState;
    5353class Event;
    5454class EventTarget;
     
    324324
    325325#if ENABLE(DRAG_SUPPORT)
    326     void allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const;
     326    DragSourceAction updateDragSourceActionsAllowed() const;
    327327#endif
    328328
     
    361361#if ENABLE(DRAG_SUPPORT)
    362362    bool m_mouseDownMayStartDrag;
     363    bool m_dragMayStartSelectionInstead;
    363364#endif
    364365    bool m_mouseDownWasSingleClickInSelection;
Note: See TracChangeset for help on using the changeset viewer.