Title: [87096] trunk
Revision
87096
Author
[email protected]
Date
2011-05-23 13:49:37 -0700 (Mon, 23 May 2011)

Log Message

2011-05-23  Ryosuke Niwa  <[email protected]>

        Reviewed by Alexey Proskuryakov.

        selectstart is fired for every mouse move
        https://bugs.webkit.org/show_bug.cgi?id=19489

        Added tests to ensure selectstart is dispatches exactly once when selecting text by a mouse drag,
        a mouse click, a double click, or a triple click. Also rebaselined a test that previously logged
        extra selectstart dispatches.

        * fast/events/selectstart-by-double-triple-clicks-expected.txt: Added.
        * fast/events/selectstart-by-double-triple-clicks.html: Added.
        * fast/events/selectstart-by-drag.html:
        * fast/events/selectstart-by-single-click-with-shift-expected.txt: Added.
        * fast/events/selectstart-by-single-click-with-shift.html: Added.
2011-05-23  Ryosuke Niwa  <[email protected]>

        Reviewed by Alexey Proskuryakov.

        selectstart is fired for every mouse move
        https://bugs.webkit.org/show_bug.cgi?id=19489

        Fixed the bug by dispatching selectstart event immediately before modifying selection in
        handleMousePressEventSingleClick and updateSelectionForMouseDrag.

        Also replaced a boolean EventHandler::m_beganSelectingText by an enum-valued m_selectionInitiationState
        to retain 3 states:
        1. HaveNotStartedSelection - Selection has not been set by a mouse drag or a mouse click
        2. PlacedCaret - A caret was placed by a mouse click, double click, or triple click, and is about
        to replace selection if a mouse drag never occurs.
        3. ExtendedSelection - A range selection was set by a mouse click, a double click, a triple click,
        or a mouse drag; otherwise a caret selection was set by a mouse drag.

        State 1 corresponds to m_beganSelectingText being false and state 3 corresponds to m_beganSelectingText
        being true. State 2 is used in updateSelectionForMouseDrag to avoid dispatching selectstart twice.

        States 1 and 2 are set by updateSelectionForMouseDownDispatchingSelectStart and state 3 is set by
        updateSelectionForMouseDrag.

        Test: fast/events/selectstart-by-double-triple-clicks.html
              fast/events/selectstart-by-drag.html
              fast/events/selectstart-by-single-click-with-shift.html

        * page/EventHandler.cpp: Removed canMouseDragExtendSelect.
        (WebCore::EventHandler::EventHandler): Initializes m_selectionInitiationState.
        (WebCore::dispatchSelectStart): Returns true only if selectstart was successfully fired
        and default action was not prevented.
        (WebCore::EventHandler::updateSelectionForMouseDownDispatchingSelectStart): Updates m_selectionInitiationState
        and modifies the selection if dispatchSelectStart returns true.
        (WebCore::EventHandler::selectClosestWordFromMouseEvent): Calls updateSelectionForMouseDownDispatchingSelectStart.
        (WebCore::EventHandler::selectClosestWordOrLinkFromMouseEvent): Ditto.
        (WebCore::EventHandler::handleMousePressEventDoubleClick):
        (WebCore::EventHandler::handleMousePressEventTripleClick): Ditto.
        (WebCore::EventHandler::handleMousePressEventSingleClick): Ditto.
        (WebCore::canMouseDownStartSelect): No longer dispatches startselect; also renamed from
        EventHandler::canMouseDownStartSelect.
        (WebCore::EventHandler::handleMousePressEvent): No longer calls canMouseDragExtendSelect.
        (WebCore::EventHandler::handleMouseDraggedEvent):
        (WebCore::EventHandler::updateSelectionForMouseDrag): Exit early if m_selectionInitiationState is
        HaveNotStartedSelection and dispatchSelectStart returns false. Since setSelectionIfPossible dispatches
        selectstart event before assigning PlacedCaret or ExtendedSelection to m_selectionInitiationState,
        there is no need to dispatch event for those two cases.
        (WebCore::EventHandler::handleMouseReleaseEvent):
        * page/EventHandler.h: Removed canMouseDownStartSelect and canMouseDragExtendSelect from EventHandler
        and added setSelectionIfPossible.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (87095 => 87096)


--- trunk/LayoutTests/ChangeLog	2011-05-23 20:47:06 UTC (rev 87095)
+++ trunk/LayoutTests/ChangeLog	2011-05-23 20:49:37 UTC (rev 87096)
@@ -1,3 +1,20 @@
+2011-05-23  Ryosuke Niwa  <[email protected]>
+
+        Reviewed by Alexey Proskuryakov.
+
+        selectstart is fired for every mouse move
+        https://bugs.webkit.org/show_bug.cgi?id=19489
+
+        Added tests to ensure selectstart is dispatches exactly once when selecting text by a mouse drag,
+        a mouse click, a double click, or a triple click. Also rebaselined a test that previously logged
+        extra selectstart dispatches.
+
+        * fast/events/selectstart-by-double-triple-clicks-expected.txt: Added.
+        * fast/events/selectstart-by-double-triple-clicks.html: Added.
+        * fast/events/selectstart-by-drag.html:
+        * fast/events/selectstart-by-single-click-with-shift-expected.txt: Added.
+        * fast/events/selectstart-by-single-click-with-shift.html: Added.
+
 2011-05-22  Robert Hogan  <[email protected]>
 
         Reviewed by Andreas Kling.

Added: trunk/LayoutTests/fast/events/selectstart-by-double-triple-clicks-expected.txt (0 => 87096)


--- trunk/LayoutTests/fast/events/selectstart-by-double-triple-clicks-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/events/selectstart-by-double-triple-clicks-expected.txt	2011-05-23 20:49:37 UTC (rev 87096)
@@ -0,0 +1,11 @@
+This test ensures selectstart is fired exactly once when selecting text by a mouse drag.
+
+Initial state: PASS
+Mouse down: PASS
+Mouse up: PASS
+Second mouse down: PASS
+Second mouse up: PASS
+Third mouse down: PASS
+Third mouse up: PASS
+Done.
+

Added: trunk/LayoutTests/fast/events/selectstart-by-double-triple-clicks.html (0 => 87096)


--- trunk/LayoutTests/fast/events/selectstart-by-double-triple-clicks.html	                        (rev 0)
+++ trunk/LayoutTests/fast/events/selectstart-by-double-triple-clicks.html	2011-05-23 20:49:37 UTC (rev 87096)
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>This test ensures selectstart is fired exactly once when selecting text by a mouse drag.
+</p><span style='font-size: 50px; padding: 10px;'>hello world</span><pre><script>
+
+var span = document.getElementsByTagName('span')[0];
+span.focus();
+
+var selectStartCount = 0;
+span.addEventListener('selectstart', function (event) { selectStartCount++; });
+
+function expect(title, expectedCount, expectedType, expectedString) {
+    document.write(title + ': ');
+    var actualSelectionType = window.getSelection().isCollapsed ? 'caret' : 'range';
+    var actualString = window.getSelection().toString();
+
+    if (selectStartCount != expectedCount)
+        document.writeln('FAIL - expected ' + expectedCount + ' events but got ' + selectStartCount + ' events');
+    else if (actualSelectionType != expectedType)
+        document.writeln('FAIL - expected selection to be ' + expectedType + ' but was ' + actualSelectionType);
+    else if (actualString && actualString != expectedString)
+        document.writeln('FAIL - expected selection to be "' + expectedString + '" but was "' + actualString + '"');
+    else
+        document.writeln('PASS');
+}
+
+if (window.layoutTestController && !window.eventSender)
+    document.write('This test requires eventSender');
+else if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+
+    var y = span.offsetTop + span.offsetHeight / 2;
+    expect('Initial state', 0, 'caret');
+    eventSender.mouseMoveTo(span.offsetLeft + 5, y);
+    eventSender.mouseDown();
+    expect('Mouse down', 1, 'caret');
+    eventSender.leapForward(200);
+    eventSender.mouseUp();
+    expect('Mouse up', 1, 'caret');
+
+    eventSender.leapForward(200);
+    eventSender.mouseDown();
+    expect('Second mouse down', 2, 'range', 'hello');
+    eventSender.leapForward(200);
+    eventSender.mouseUp();
+    expect('Second mouse up', 2, 'range', 'hello');
+
+    eventSender.leapForward(200);
+    eventSender.mouseDown();
+    expect('Third mouse down', 3, 'range', 'hello world\n');
+    eventSender.leapForward(200);
+    eventSender.mouseUp();
+    expect('Third mouse up', 3, 'range', 'hello world\n');
+
+    document.writeln('Done.');
+    span.parentNode.removeChild(span);
+}
+
+</script></pre>
+</body>
+</html>

Added: trunk/LayoutTests/fast/events/selectstart-by-drag-expected.txt (0 => 87096)


--- trunk/LayoutTests/fast/events/selectstart-by-drag-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/events/selectstart-by-drag-expected.txt	2011-05-23 20:49:37 UTC (rev 87096)
@@ -0,0 +1,14 @@
+This test ensures selectstart is fired exactly once when selecting text by a mouse drag.
+
+Initial state: PASS
+Mouse down: PASS
+Moving slightly to the right: PASS
+Moving slightly to the left: PASS
+Moving to the right: PASS
+Moving further to the right: PASS
+Moving back to the left: PASS
+Moving to the right again: PASS
+Mouse down on the right: PASS
+Moving to the left: PASS
+Done.
+

Added: trunk/LayoutTests/fast/events/selectstart-by-drag.html (0 => 87096)


--- trunk/LayoutTests/fast/events/selectstart-by-drag.html	                        (rev 0)
+++ trunk/LayoutTests/fast/events/selectstart-by-drag.html	2011-05-23 20:49:37 UTC (rev 87096)
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>This test ensures selectstart is fired exactly once when selecting text by a mouse drag.
+</p><span style='font-size: 50px; padding: 10px;' contenteditable>hello
+</span><pre><script>
+
+var span = document.getElementsByTagName('span')[0];
+span.focus();
+
+var selectStartCount = 0;
+span.addEventListener('selectstart', function (event) { selectStartCount++; });
+
+function expect(title, expectedCount, expectedType) {
+    document.write(title + ': ');
+    var actualSelectionType = window.getSelection().isCollapsed ? 'caret' : 'range';
+
+    if (selectStartCount != expectedCount)
+        document.writeln('FAIL - expected ' + expectedCount + ' events but got ' + selectStartCount + ' events');
+    else if (actualSelectionType != expectedType)
+        document.writeln('FAIL - expected selection to be ' + expectedType + ' but was ' + actualSelectionType);
+    else
+        document.writeln('PASS');
+}
+
+if (window.layoutTestController && !window.eventSender)
+    document.write('This test requires eventSender');
+else if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+
+    var y = span.offsetTop + span.offsetHeight / 2;
+
+    function leapForwardAndMove(x) {
+        eventSender.leapForward(200);
+        eventSender.mouseMoveTo(span.offsetLeft + x, y);
+    }
+
+    expect('Initial state', 0, 'caret');
+    eventSender.dragMode = false;
+    eventSender.mouseMoveTo(span.offsetLeft + 5, y);
+    eventSender.mouseDown();
+    expect('Mouse down', 1, 'caret');
+
+    leapForwardAndMove(5);
+    expect('Moving slightly to the right', 1, 'caret');
+
+    leapForwardAndMove(-5);
+    expect('Moving slightly to the left', 1, 'caret');
+
+    leapForwardAndMove(span.offsetWidth / 2);
+    expect('Moving to the right', 1, 'range');
+
+    leapForwardAndMove(span.offsetWidth);
+    expect('Moving further to the right', 1, 'range');
+
+    leapForwardAndMove(0);
+    expect('Moving back to the left', 1, 'caret');
+
+    leapForwardAndMove(span.offsetWidth);
+    expect('Moving to the right again', 1, 'range');
+
+    eventSender.mouseUp();
+    window.getSelection().setPosition(span, 0);
+    eventSender.leapForward(1000);
+
+    eventSender.mouseMoveTo(span.offsetLeft + span.offsetWidth - 5, y);
+    eventSender.mouseDown();
+    expect('Mouse down on the right', 2, 'caret');
+
+    leapForwardAndMove(span.offsetWidth / 2);
+    expect('Moving to the left', 2, 'range');
+
+    eventSender.mouseUp();
+
+    document.writeln('Done.');
+    span.parentNode.removeChild(span);
+}
+
+</script></pre>
+</body>
+</html>

Added: trunk/LayoutTests/fast/events/selectstart-by-single-click-with-shift-expected.txt (0 => 87096)


--- trunk/LayoutTests/fast/events/selectstart-by-single-click-with-shift-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/events/selectstart-by-single-click-with-shift-expected.txt	2011-05-23 20:49:37 UTC (rev 87096)
@@ -0,0 +1,10 @@
+This test ensures selectstart is fired exactly once when selecting text by a mouse drag.
+
+Initial state: PASS
+Mouse down: PASS
+Mouse up: PASS
+Moving to the right: PASS
+Second mouse down: PASS
+Second mouse up: PASS
+Done.
+

Added: trunk/LayoutTests/fast/events/selectstart-by-single-click-with-shift.html (0 => 87096)


--- trunk/LayoutTests/fast/events/selectstart-by-single-click-with-shift.html	                        (rev 0)
+++ trunk/LayoutTests/fast/events/selectstart-by-single-click-with-shift.html	2011-05-23 20:49:37 UTC (rev 87096)
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>This test ensures selectstart is fired exactly once when selecting text by a mouse drag.
+</p><span style='font-size: 50px; padding: 10px;'>hello world
+</span><pre><script>
+
+var span = document.getElementsByTagName('span')[0];
+span.focus();
+
+var selectStartCount = 0;
+span.addEventListener('selectstart', function (event) { selectStartCount++; });
+
+function expect(title, expectedCount, expectedType) {
+    document.write(title + ': ');
+    var actualSelectionType = window.getSelection().isCollapsed ? 'caret' : 'range';
+
+    if (selectStartCount != expectedCount)
+        document.writeln('FAIL - expected ' + expectedCount + ' events but got ' + selectStartCount + ' events');
+    else if (actualSelectionType != expectedType)
+        document.writeln('FAIL - expected selection to be ' + expectedType + ' but was ' + actualSelectionType);
+    else
+        document.writeln('PASS');
+}
+
+if (window.layoutTestController && !window.eventSender)
+    document.write('This test requires eventSender');
+else if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+
+    var y = span.offsetTop + span.offsetHeight / 2;
+    expect('Initial state', 0, 'caret');
+    eventSender.mouseMoveTo(span.offsetLeft + 5, y);
+    eventSender.mouseDown();
+    expect('Mouse down', 1, 'caret');
+    eventSender.leapForward(200);
+    eventSender.mouseUp();
+    expect('Mouse up', 1, 'caret');
+
+    eventSender.mouseMoveTo(span.offsetLeft + span.offsetWidth - 5, y);
+    expect('Moving to the right', 1, 'caret');
+    eventSender.mouseDown(0, ['shiftKey']);
+    expect('Second mouse down', 2, 'range');
+    eventSender.leapForward(200);
+    eventSender.mouseUp();
+    expect('Second mouse up', 2, 'range');
+
+    document.writeln('Done.');
+    span.parentNode.removeChild(span);
+}
+
+</script></pre>
+</body>
+</html>

Modified: trunk/LayoutTests/platform/mac/fast/events/objc-event-api-expected.txt (87095 => 87096)


--- trunk/LayoutTests/platform/mac/fast/events/objc-event-api-expected.txt	2011-05-23 20:47:06 UTC (rev 87095)
+++ trunk/LayoutTests/platform/mac/fast/events/objc-event-api-expected.txt	2011-05-23 20:49:37 UTC (rev 87096)
@@ -341,11 +341,6 @@
   screenX:       -9999
   screenY:       -9999
   modifier keys: c:0 s:0 a:0 m:0
-event type:      selectstart
-  target:        <html>
-  eventPhase:    3
-  bubbles:       1
-  cancelable:    1
 event type:      mouseup
   target:        <html>
   eventPhase:    3

Modified: trunk/Source/WebCore/ChangeLog (87095 => 87096)


--- trunk/Source/WebCore/ChangeLog	2011-05-23 20:47:06 UTC (rev 87095)
+++ trunk/Source/WebCore/ChangeLog	2011-05-23 20:49:37 UTC (rev 87096)
@@ -1,3 +1,54 @@
+2011-05-23  Ryosuke Niwa  <[email protected]>
+
+        Reviewed by Alexey Proskuryakov.
+
+        selectstart is fired for every mouse move
+        https://bugs.webkit.org/show_bug.cgi?id=19489
+
+        Fixed the bug by dispatching selectstart event immediately before modifying selection in
+        handleMousePressEventSingleClick and updateSelectionForMouseDrag.
+
+        Also replaced a boolean EventHandler::m_beganSelectingText by an enum-valued m_selectionInitiationState
+        to retain 3 states:
+        1. HaveNotStartedSelection - Selection has not been set by a mouse drag or a mouse click
+        2. PlacedCaret - A caret was placed by a mouse click, double click, or triple click, and is about
+        to replace selection if a mouse drag never occurs.
+        3. ExtendedSelection - A range selection was set by a mouse click, a double click, a triple click,
+        or a mouse drag; otherwise a caret selection was set by a mouse drag.
+
+        State 1 corresponds to m_beganSelectingText being false and state 3 corresponds to m_beganSelectingText
+        being true. State 2 is used in updateSelectionForMouseDrag to avoid dispatching selectstart twice.
+
+        States 1 and 2 are set by updateSelectionForMouseDownDispatchingSelectStart and state 3 is set by
+        updateSelectionForMouseDrag.
+
+        Test: fast/events/selectstart-by-double-triple-clicks.html
+              fast/events/selectstart-by-drag.html
+              fast/events/selectstart-by-single-click-with-shift.html
+
+        * page/EventHandler.cpp: Removed canMouseDragExtendSelect.
+        (WebCore::EventHandler::EventHandler): Initializes m_selectionInitiationState.
+        (WebCore::dispatchSelectStart): Returns true only if selectstart was successfully fired
+        and default action was not prevented.
+        (WebCore::EventHandler::updateSelectionForMouseDownDispatchingSelectStart): Updates m_selectionInitiationState
+        and modifies the selection if dispatchSelectStart returns true.
+        (WebCore::EventHandler::selectClosestWordFromMouseEvent): Calls updateSelectionForMouseDownDispatchingSelectStart.
+        (WebCore::EventHandler::selectClosestWordOrLinkFromMouseEvent): Ditto.
+        (WebCore::EventHandler::handleMousePressEventDoubleClick):
+        (WebCore::EventHandler::handleMousePressEventTripleClick): Ditto.
+        (WebCore::EventHandler::handleMousePressEventSingleClick): Ditto.
+        (WebCore::canMouseDownStartSelect): No longer dispatches startselect; also renamed from
+        EventHandler::canMouseDownStartSelect.
+        (WebCore::EventHandler::handleMousePressEvent): No longer calls canMouseDragExtendSelect.
+        (WebCore::EventHandler::handleMouseDraggedEvent):
+        (WebCore::EventHandler::updateSelectionForMouseDrag): Exit early if m_selectionInitiationState is
+        HaveNotStartedSelection and dispatchSelectStart returns false. Since setSelectionIfPossible dispatches
+        selectstart event before assigning PlacedCaret or ExtendedSelection to m_selectionInitiationState,
+        there is no need to dispatch event for those two cases.
+        (WebCore::EventHandler::handleMouseReleaseEvent):
+        * page/EventHandler.h: Removed canMouseDownStartSelect and canMouseDragExtendSelect from EventHandler
+        and added setSelectionIfPossible.
+
 2011-05-23  Adam Klein  <[email protected]>
 
         Reviewed by Jian Li.

Modified: trunk/Source/WebCore/page/EventHandler.cpp (87095 => 87096)


--- trunk/Source/WebCore/page/EventHandler.cpp	2011-05-23 20:47:06 UTC (rev 87095)
+++ trunk/Source/WebCore/page/EventHandler.cpp	2011-05-23 20:49:37 UTC (rev 87096)
@@ -182,7 +182,7 @@
     , m_dragMayStartSelectionInstead(false)
 #endif
     , m_mouseDownWasSingleClickInSelection(false)
-    , m_beganSelectingText(false)
+    , m_selectionInitiationState(HaveNotStartedSelection)
     , m_panScrollInProgress(false)
     , m_panScrollButtonPressed(false)
     , m_springLoadedPanScrollInProgress(false)
@@ -281,6 +281,31 @@
         selection->setSelection(newSelection, granularity, MakeNonDirectionalSelection);
 }
 
+static inline bool dispatchSelectStart(Node* node)
+{
+    if (!node || !node->renderer())
+        return true;
+
+    return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
+}
+
+bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& newSelection, TextGranularity granularity)
+{
+    if (!dispatchSelectStart(targetNode))
+        return false;
+
+    if (newSelection.isRange())
+        m_selectionInitiationState = ExtendedSelection;
+    else {
+        granularity = CharacterGranularity;
+        m_selectionInitiationState = PlacedCaret;
+    }
+
+    setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
+
+    return true;
+}
+
 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
 {
     Node* innerNode = targetNode(result);
@@ -288,20 +313,15 @@
 
     if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
         VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
-        TextGranularity granularity = CharacterGranularity;
         if (pos.isNotNull()) {
             newSelection = VisibleSelection(pos);
             newSelection.expandUsingGranularity(WordGranularity);
         }
-    
-        if (newSelection.isRange()) {
-            granularity = WordGranularity;
-            m_beganSelectingText = true;
-            if (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled()) 
-                newSelection.appendTrailingWhitespace();            
-        }
 
-        setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
+        if (newSelection.isRange() && result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled()) 
+            newSelection.appendTrailingWhitespace();
+
+        updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, WordGranularity);
     }
 }
 
@@ -318,14 +338,8 @@
         VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
         if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
             newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
-    
-        TextGranularity granularity = CharacterGranularity;
-        if (newSelection.isRange()) {
-            granularity = WordGranularity;
-            m_beganSelectingText = true;
-        }
 
-        setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
+        updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, WordGranularity);
     }
 }
 
@@ -340,7 +354,7 @@
         // selectClosestWordFromMouseEvent, but do set
         // m_beganSelectingText to prevent handleMouseReleaseEvent
         // from setting caret selection.
-        m_beganSelectingText = true;
+        m_selectionInitiationState = ExtendedSelection;
     else
         selectClosestWordFromMouseEvent(event);
 
@@ -362,16 +376,8 @@
         newSelection = VisibleSelection(pos);
         newSelection.expandUsingGranularity(ParagraphGranularity);
     }
-    
-    TextGranularity granularity = CharacterGranularity;
-    if (newSelection.isRange()) {
-        granularity = ParagraphGranularity;
-        m_beganSelectingText = true;
-    }
 
-    setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
-
-    return true;
+    return updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, ParagraphGranularity);
 }
 
 static int textDistance(const Position& start, const Position& end)
@@ -422,21 +428,27 @@
                 newSelection = VisibleSelection(end, pos);
             else
                 newSelection = VisibleSelection(start, pos);
-        } else {
+        } else
             newSelection.setExtent(pos);
-        }
 
         if (m_frame->selection()->granularity() != CharacterGranularity) {
             granularity = m_frame->selection()->granularity();
             newSelection.expandUsingGranularity(m_frame->selection()->granularity());
         }
-
-        m_beganSelectingText = true;
     } else
         newSelection = VisibleSelection(visiblePos);
+    
+    return updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity);
+}
 
-    setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
+static inline bool canMouseDownStartSelect(Node* node)
+{
+    if (!node || !node->renderer())
+        return true;
 
+    if (!node->canStartSelection())
+        return false;
+
     return true;
 }
 
@@ -497,7 +509,7 @@
 
     bool swallowEvent = false;
     m_mousePressed = true;
-    m_beganSelectingText = false;
+    m_selectionInitiationState = HaveNotStartedSelection;
 
     if (event.event().clickCount() == 2)
         swallowEvent = handleMousePressEventDoubleClick(event);
@@ -573,7 +585,7 @@
         m_mouseDownMayStartAutoscroll = false;
     }
 
-    if (!m_beganSelectingText) {
+    if (m_selectionInitiationState != ExtendedSelection) {
         HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
         HitTestResult result(m_mouseDownPos);
         m_frame->document()->renderView()->layer()->hitTest(request, result);
@@ -661,9 +673,6 @@
     if (!target)
         return;
 
-    if (!canMouseDragExtendSelect(target))
-        return;
-
     VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame->selection()->selection(), hitTestResult.localPoint(), target);
 
     // Don't modify the selection if we're not on a node.
@@ -684,8 +693,12 @@
                     return;
 #endif
 
-    if (!m_beganSelectingText) {
-        m_beganSelectingText = true;
+    if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
+        return;
+
+    if (m_selectionInitiationState != ExtendedSelection) {
+        // Always extend selection here because it's caused by a mouse drag
+        m_selectionInitiationState = ExtendedSelection;
         newSelection = VisibleSelection(targetPosition);
     }
 
@@ -741,7 +754,7 @@
     // press and it's not a context menu click.  We do this so when clicking
     // on the selection, the selection goes away.  However, if we are
     // editing, place the caret.
-    if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText
+    if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
 #if ENABLE(DRAG_SUPPORT)
             && m_dragStartPos == event.event().pos()
 #endif
@@ -2334,29 +2347,6 @@
     mouseMoved(fakeMouseMoveEvent);
 }
 
-// Whether or not a mouse down can begin the creation of a selection.  Fires the selectStart event.
-bool EventHandler::canMouseDownStartSelect(Node* node)
-{
-    if (!node || !node->renderer())
-        return true;
-    
-    // Some controls and images can't start a select on a mouse down.
-    if (!node->canStartSelection())
-        return false;
-            
-    return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
-}
-
-#if ENABLE(DRAG_SUPPORT)
-bool EventHandler::canMouseDragExtendSelect(Node* node)
-{
-    if (!node || !node->renderer())
-        return true;
-            
-    return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
-}
-#endif // ENABLE(DRAG_SUPPORT)
-
 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
 {
     m_frameSetBeingResized = frameSet;

Modified: trunk/Source/WebCore/page/EventHandler.h (87095 => 87096)


--- trunk/Source/WebCore/page/EventHandler.h	2011-05-23 20:47:06 UTC (rev 87095)
+++ trunk/Source/WebCore/page/EventHandler.h	2011-05-23 20:49:37 UTC (rev 87096)
@@ -33,6 +33,7 @@
 #include "PlatformMouseEvent.h"
 #include "ScrollTypes.h"
 #include "TextEventInputType.h"
+#include "TextGranularity.h"
 #include "Timer.h"
 #include <wtf/Forward.h>
 #include <wtf/OwnPtr.h>
@@ -71,6 +72,7 @@
 class Scrollbar;
 class TextEvent;
 class TouchEvent;
+class VisibleSelection;
 class WheelEvent;
 class Widget;
 
@@ -230,6 +232,7 @@
 #endif // ENABLE(DRAG_SUPPORT)
 
     bool eventActivatedView(const PlatformMouseEvent&) const;
+    bool updateSelectionForMouseDownDispatchingSelectStart(Node*, const VisibleSelection&, TextGranularity);
     void selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults&);
     void selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults&);
 
@@ -256,11 +259,6 @@
 
     void hoverTimerFired(Timer<EventHandler>*);
 
-    static bool canMouseDownStartSelect(Node*);
-#if ENABLE(DRAG_SUPPORT)
-    static bool canMouseDragExtendSelect(Node*);
-#endif
-
     void handleAutoscroll(RenderObject*);
     void startAutoscrollTimer();
     void setAutoscrollRenderer(RenderObject*);
@@ -367,7 +365,8 @@
     bool m_dragMayStartSelectionInstead;
 #endif
     bool m_mouseDownWasSingleClickInSelection;
-    bool m_beganSelectingText;
+    enum SelectionInitiationState { HaveNotStartedSelection, PlacedCaret, ExtendedSelection };
+    SelectionInitiationState m_selectionInitiationState;
 
 #if ENABLE(DRAG_SUPPORT)
     IntPoint m_dragStartPos;
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to