Title: [195949] trunk
Revision
195949
Author
[email protected]
Date
2016-01-31 20:09:02 -0800 (Sun, 31 Jan 2016)

Log Message

AX: Add a boundary value to AXTextStateChangeType
https://bugs.webkit.org/show_bug.cgi?id=153085

Patch by Doug Russell <[email protected]> on 2016-01-31
Reviewed by Darin Adler.

Post an AT notification when navigation is attempted past
an editable element's boundaries.

Source/WebCore:

Test: accessibility/mac/selection-boundary-userinfo.html

* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::showIntent):
* accessibility/AXTextStateChangeIntent.h:
* accessibility/mac/AXObjectCacheMac.mm:
(platformChangeTypeForWebCoreChangeType):
(WebCore::AXObjectCache::postTextStateChangePlatformNotification):
* editing/FrameSelection.cpp:
(WebCore::FrameSelection::modifyMovingRight):
(WebCore::FrameSelection::modifyMovingForward):
(WebCore::FrameSelection::modifyMovingLeft):
(WebCore::FrameSelection::modifyMovingBackward):
(WebCore::textSelectionWithDirectionAndGranularity):
(WebCore::FrameSelection::modify):
(WebCore::FrameSelection::modifyExtendingBackward): Deleted.
(WebCore::FrameSelection::textSelectionIntent): Deleted.
* editing/FrameSelection.h:
* editing/VisiblePosition.cpp:
(WebCore::VisiblePosition::next):
(WebCore::VisiblePosition::previous):
(WebCore::VisiblePosition::left):
(WebCore::VisiblePosition::right):
(WebCore::VisiblePosition::honorEditingBoundaryAtOrBefore):
(WebCore::VisiblePosition::honorEditingBoundaryAtOrAfter):
(WebCore::VisiblePosition::leftVisuallyDistinctCandidate): Deleted.
(WebCore::VisiblePosition::rightVisuallyDistinctCandidate): Deleted.
* editing/VisiblePosition.h:
* editing/VisibleUnits.cpp:
(WebCore::startOfLine):
(WebCore::logicalStartOfLine):
(WebCore::endOfLine):
(WebCore::logicalEndOfLine):
(WebCore::leftBoundaryOfLine):
(WebCore::rightBoundaryOfLine):
(WebCore::inSameLogicalLine): Deleted.
(WebCore::endOfEditableContent): Deleted.
(WebCore::isEndOfEditableOrNonEditableContent): Deleted.
* editing/VisibleUnits.h:

LayoutTests:

* accessibility/mac/selection-boundary-userinfo-expected.txt: Added.
* accessibility/mac/selection-boundary-userinfo.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (195948 => 195949)


--- trunk/LayoutTests/ChangeLog	2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/LayoutTests/ChangeLog	2016-02-01 04:09:02 UTC (rev 195949)
@@ -1,3 +1,16 @@
+2016-01-31  Doug Russell  <[email protected]>
+
+        AX: Add a boundary value to AXTextStateChangeType
+        https://bugs.webkit.org/show_bug.cgi?id=153085
+
+        Reviewed by Darin Adler.
+
+        Post an AT notification when navigation is attempted past
+        an editable element's boundaries.
+
+        * accessibility/mac/selection-boundary-userinfo-expected.txt: Added.
+        * accessibility/mac/selection-boundary-userinfo.html: Added.
+
 2016-01-31  Daniel Bates  <[email protected]>
 
         CSP: Use the served CSP header for dedicated workers

Added: trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo-expected.txt (0 => 195949)


--- trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo-expected.txt	2016-02-01 04:09:02 UTC (rev 195949)
@@ -0,0 +1,97 @@
+This tests selection change notifications at text boundaries.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS addedNotification is true
+PASS results[i] is AXTextStateChangeTypeSelectionMove
+PASS results[i] is AXTextSelectionDirectionDiscontiguous
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityCharacter
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityCharacter
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityWord
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityWord
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionBeginning
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionEnd
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityDocument
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityDocument
+PASS results[i] is AXTextStateChangeTypeSelectionMove
+PASS results[i] is AXTextSelectionDirectionDiscontiguous
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityCharacter
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityCharacter
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityWord
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityWord
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionBeginning
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionEnd
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionMove
+PASS results[i] is AXTextSelectionDirectionDiscontiguous
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityCharacter
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityCharacter
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityWord
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityWord
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionBeginning
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionEnd
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityDocument
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityDocument
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+
+ 
+

Added: trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo.html (0 => 195949)


--- trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo.html	                        (rev 0)
+++ trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo.html	2016-02-01 04:09:02 UTC (rev 195949)
@@ -0,0 +1,185 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body id="body">
+
+<div role="textbox" tabindex=0 id="textbox" contenteditable=true>
+    <p><br>
+</div>
+
+<br>
+
+<input type="text" id="input">
+
+<br>
+
+<textarea id="textarea"></textarea>
+
+<script>
+
+    description("This tests selection change notifications at text boundaries.");
+
+    var AXTextStateChangeTypeSelectionMove = 2;
+    var AXTextStateChangeTypeSelectionExtend = AXTextStateChangeTypeSelectionMove + 1;
+    var AXTextStateChangeTypeSelectionBoundary = AXTextStateChangeTypeSelectionExtend + 1;
+
+    var AXTextSelectionDirectionBeginning = 1;
+    var AXTextSelectionDirectionEnd = AXTextSelectionDirectionBeginning + 1;
+    var AXTextSelectionDirectionPrevious = AXTextSelectionDirectionEnd + 1;
+    var AXTextSelectionDirectionNext = AXTextSelectionDirectionPrevious + 1;
+    var AXTextSelectionDirectionDiscontiguous = AXTextSelectionDirectionNext + 1;
+
+    var AXTextSelectionGranularityCharacter = 1;
+    var AXTextSelectionGranularityWord = AXTextSelectionGranularityCharacter + 1;
+    var AXTextSelectionGranularityLine = AXTextSelectionGranularityWord + 1;
+    var AXTextSelectionGranularitySentence = AXTextSelectionGranularityLine + 1;
+    var AXTextSelectionGranularityParagraph = AXTextSelectionGranularitySentence + 1;
+    var AXTextSelectionGranularityDocument = AXTextSelectionGranularityParagraph + 2;
+
+    function move(includeVertical) {
+        // Move by character
+        eventSender.keyDown("leftArrow");
+        eventSender.keyDown("rightArrow");
+        if (includeVertical) {
+            // Move by line
+            eventSender.keyDown("upArrow");
+            eventSender.keyDown("downArrow");
+        }
+        // Move by word
+        eventSender.keyDown("leftArrow", ["altKey"]);
+        eventSender.keyDown("rightArrow", ["altKey"]);
+        // Move to beginning/end of line
+        eventSender.keyDown("leftArrow", ["metaKey"]);
+        eventSender.keyDown("rightArrow", ["metaKey"]);
+        if (includeVertical) {
+            // Move to beginning/end of document
+            eventSender.keyDown("upArrow", ["metaKey"]);
+            eventSender.keyDown("downArrow", ["metaKey"]);
+        }
+    }
+
+    var webArea = 0;
+    var count = 0;
+    var results = [];
+    var i = 0;
+    function notificationCallback(notification, userInfo) {
+        if (notification == "AXSelectedTextChanged") {
+            count++;
+            if (userInfo) {
+                results.push(userInfo["AXTextStateChangeType"]);
+                if (userInfo["AXTextSelectionDirection"])
+                    results.push(userInfo["AXTextSelectionDirection"]);
+                if (userInfo["AXTextSelectionGranularity"])
+                    results.push(userInfo["AXTextSelectionGranularity"]);
+            }
+            if (count == 29) {
+
+                function shouldBeResults(includeVertical) {
+                    // Focusing into the textbox
+                    shouldBe("results[i]", "AXTextStateChangeTypeSelectionMove"); i++;
+                    shouldBe("results[i]", "AXTextSelectionDirectionDiscontiguous");  i++;
+
+                    // Left Arrow
+                    shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary");  i++;
+                    shouldBe("results[i]", "AXTextSelectionDirectionPrevious");  i++;
+                    shouldBe("results[i]", "AXTextSelectionGranularityCharacter");  i++;
+
+                    // Right Arrow
+                    shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary");  i++;
+                    shouldBe("results[i]", "AXTextSelectionDirectionNext");  i++;
+                    shouldBe("results[i]", "AXTextSelectionGranularityCharacter");  i++;
+
+                    if (includeVertical) {
+                        // Up Arrow
+                        shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary");  i++;
+                        shouldBe("results[i]", "AXTextSelectionDirectionPrevious"); i++;
+                        shouldBe("results[i]", "AXTextSelectionGranularityLine"); i++;
+
+                        // Down Arrow
+                        shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+                        shouldBe("results[i]", "AXTextSelectionDirectionNext"); i++;
+                        shouldBe("results[i]", "AXTextSelectionGranularityLine"); i++;
+                    }
+
+                    // Option Left Arrow
+                    shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+                    shouldBe("results[i]", "AXTextSelectionDirectionPrevious"); i++;
+                    shouldBe("results[i]", "AXTextSelectionGranularityWord"); i++;
+
+                    // Option Right Arrow
+                    shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+                    shouldBe("results[i]", "AXTextSelectionDirectionNext"); i++;
+                    shouldBe("results[i]", "AXTextSelectionGranularityWord"); i++;
+
+                    // Command Left Arrow
+                    shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+                    shouldBe("results[i]", "AXTextSelectionDirectionBeginning"); i++;
+                    shouldBe("results[i]", "AXTextSelectionGranularityLine"); i++;
+
+                    // Command Right Arrow
+                    shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+                    shouldBe("results[i]", "AXTextSelectionDirectionEnd"); i++;
+                    shouldBe("results[i]", "AXTextSelectionGranularityLine"); i++;
+
+                    if (includeVertical) {
+                        // Command Up Arrow
+                        shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+                        // FIXME: This should be AXTextSelectionDirectionBeginning.
+                        shouldBe("results[i]", "AXTextSelectionDirectionPrevious"); i++;
+                        shouldBe("results[i]", "AXTextSelectionGranularityDocument"); i++;
+
+                        // Command Down Arrow
+                        shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+                        // FIXME: This should be AXTextSelectionDirectionEnd.
+                        shouldBe("results[i]", "AXTextSelectionDirectionNext"); i++;
+                        shouldBe("results[i]", "AXTextSelectionGranularityDocument"); i++;
+                    }
+                }
+
+                // Content Editable Div
+                shouldBeResults(true);
+
+                // Text Field
+                shouldBeResults(false);
+
+                // Text Area
+                shouldBeResults(true);
+
+                webArea.removeNotificationListener();
+                window.testRunner.notifyDone();
+            }
+        }
+    }
+
+    if (window.accessibilityController) {
+        window.testRunner.waitUntilDone();
+
+        accessibilityController.enableEnhancedAccessibility(true);
+
+        webArea = accessibilityController.rootElement.childAtIndex(0);
+        var addedNotification = webArea.addNotificationListener(notificationCallback);
+        shouldBe("addedNotification", "true");
+
+        textbox = document.getElementById("textbox");
+        textbox.focus();
+
+        move(true);
+
+        textbox = document.getElementById("input");
+        textbox.focus();
+
+        move(false);
+
+        textbox = document.getElementById("textarea");
+        textbox.focus();
+
+        move(true);
+    }
+
+</script>
+
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (195948 => 195949)


--- trunk/Source/WebCore/ChangeLog	2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/ChangeLog	2016-02-01 04:09:02 UTC (rev 195949)
@@ -1,3 +1,53 @@
+2016-01-31  Doug Russell  <[email protected]>
+
+        AX: Add a boundary value to AXTextStateChangeType
+        https://bugs.webkit.org/show_bug.cgi?id=153085
+
+        Reviewed by Darin Adler.
+
+        Post an AT notification when navigation is attempted past
+        an editable element's boundaries.
+
+        Test: accessibility/mac/selection-boundary-userinfo.html
+
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::AXObjectCache::showIntent):
+        * accessibility/AXTextStateChangeIntent.h:
+        * accessibility/mac/AXObjectCacheMac.mm:
+        (platformChangeTypeForWebCoreChangeType):
+        (WebCore::AXObjectCache::postTextStateChangePlatformNotification):
+        * editing/FrameSelection.cpp:
+        (WebCore::FrameSelection::modifyMovingRight):
+        (WebCore::FrameSelection::modifyMovingForward):
+        (WebCore::FrameSelection::modifyMovingLeft):
+        (WebCore::FrameSelection::modifyMovingBackward):
+        (WebCore::textSelectionWithDirectionAndGranularity):
+        (WebCore::FrameSelection::modify):
+        (WebCore::FrameSelection::modifyExtendingBackward): Deleted.
+        (WebCore::FrameSelection::textSelectionIntent): Deleted.
+        * editing/FrameSelection.h:
+        * editing/VisiblePosition.cpp:
+        (WebCore::VisiblePosition::next):
+        (WebCore::VisiblePosition::previous):
+        (WebCore::VisiblePosition::left):
+        (WebCore::VisiblePosition::right):
+        (WebCore::VisiblePosition::honorEditingBoundaryAtOrBefore):
+        (WebCore::VisiblePosition::honorEditingBoundaryAtOrAfter):
+        (WebCore::VisiblePosition::leftVisuallyDistinctCandidate): Deleted.
+        (WebCore::VisiblePosition::rightVisuallyDistinctCandidate): Deleted.
+        * editing/VisiblePosition.h:
+        * editing/VisibleUnits.cpp:
+        (WebCore::startOfLine):
+        (WebCore::logicalStartOfLine):
+        (WebCore::endOfLine):
+        (WebCore::logicalEndOfLine):
+        (WebCore::leftBoundaryOfLine):
+        (WebCore::rightBoundaryOfLine):
+        (WebCore::inSameLogicalLine): Deleted.
+        (WebCore::endOfEditableContent): Deleted.
+        (WebCore::isEndOfEditableOrNonEditableContent): Deleted.
+        * editing/VisibleUnits.h:
+
 2016-01-31  Daniel Bates  <[email protected]>
 
         CSP: Use the served CSP header for dedicated workers

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (195948 => 195949)


--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2016-02-01 04:09:02 UTC (rev 195949)
@@ -995,6 +995,9 @@
     case AXTextStateChangeTypeSelectionExtend:
         dataLog("Extend::");
         break;
+    case AXTextStateChangeTypeSelectionBoundary:
+        dataLog("Boundary::");
+        break;
     }
     switch (intent.type) {
     case AXTextStateChangeTypeUnknown:
@@ -1029,6 +1032,7 @@
         break;
     case AXTextStateChangeTypeSelectionMove:
     case AXTextStateChangeTypeSelectionExtend:
+    case AXTextStateChangeTypeSelectionBoundary:
         switch (intent.selection.direction) {
         case AXTextSelectionDirectionUnknown:
             dataLog("Unknown::");

Modified: trunk/Source/WebCore/accessibility/AXTextStateChangeIntent.h (195948 => 195949)


--- trunk/Source/WebCore/accessibility/AXTextStateChangeIntent.h	2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/accessibility/AXTextStateChangeIntent.h	2016-02-01 04:09:02 UTC (rev 195949)
@@ -32,7 +32,8 @@
     AXTextStateChangeTypeUnknown,
     AXTextStateChangeTypeEdit,
     AXTextStateChangeTypeSelectionMove,
-    AXTextStateChangeTypeSelectionExtend
+    AXTextStateChangeTypeSelectionExtend,
+    AXTextStateChangeTypeSelectionBoundary
 };
 
 enum AXTextEditType {

Modified: trunk/Source/WebCore/accessibility/mac/AXObjectCacheMac.mm (195948 => 195949)


--- trunk/Source/WebCore/accessibility/mac/AXObjectCacheMac.mm	2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/accessibility/mac/AXObjectCacheMac.mm	2016-02-01 04:09:02 UTC (rev 195949)
@@ -158,6 +158,8 @@
         return kAXTextStateChangeTypeSelectionMove;
     case WebCore::AXTextStateChangeTypeSelectionExtend:
         return kAXTextStateChangeTypeSelectionExtend;
+    case WebCore::AXTextStateChangeTypeSelectionBoundary:
+        return kAXTextStateChangeTypeSelectionBoundary;
     }
 }
 
@@ -365,6 +367,7 @@
         switch (intent.type) {
         case AXTextStateChangeTypeSelectionMove:
         case AXTextStateChangeTypeSelectionExtend:
+        case AXTextStateChangeTypeSelectionBoundary:
             [userInfo setObject:@(platformDirectionForWebCoreDirection(intent.selection.direction)) forKey:NSAccessibilityTextSelectionDirection];
             switch (intent.selection.direction) {
             case AXTextSelectionDirectionUnknown:
@@ -378,13 +381,13 @@
             case AXTextSelectionDirectionDiscontiguous:
                 break;
             }
+            if (intent.selection.focusChange)
+                [userInfo setObject:@(intent.selection.focusChange) forKey:NSAccessibilityTextSelectionChangedFocus];
             break;
         case AXTextStateChangeTypeUnknown:
         case AXTextStateChangeTypeEdit:
             break;
         }
-        if (intent.selection.focusChange)
-            [userInfo setObject:[NSNumber numberWithBool:intent.selection.focusChange] forKey:NSAccessibilityTextSelectionChangedFocus];
     }
     if (!selection.isNone()) {
         if (id textMarkerRange = [object->wrapper() textMarkerRangeFromVisiblePositions:selection.visibleStart() endPosition:selection.visibleEnd()])

Modified: trunk/Source/WebCore/editing/FrameSelection.cpp (195948 => 195949)


--- trunk/Source/WebCore/editing/FrameSelection.cpp	2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/editing/FrameSelection.cpp	2016-02-01 04:09:02 UTC (rev 195949)
@@ -760,8 +760,10 @@
     return pos;
 }
 
-VisiblePosition FrameSelection::modifyMovingRight(TextGranularity granularity)
+VisiblePosition FrameSelection::modifyMovingRight(TextGranularity granularity, bool* reachedBoundary)
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
     VisiblePosition pos;
     switch (granularity) {
     case CharacterGranularity:
@@ -771,11 +773,14 @@
             else
                 pos = VisiblePosition(m_selection.start(), m_selection.affinity());
         } else
-            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).right(true);
+            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).right(true, reachedBoundary);
         break;
     case WordGranularity: {
         bool skipsSpaceWhenMovingRight = m_frame && m_frame->editor().behavior().shouldSkipSpaceWhenMovingRight();
-        pos = rightWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()), skipsSpaceWhenMovingRight);
+        VisiblePosition currentPosition(m_selection.extent(), m_selection.affinity());
+        pos = rightWordPosition(currentPosition, skipsSpaceWhenMovingRight);
+        if (reachedBoundary)
+            *reachedBoundary = pos == currentPosition;
         break;
     }
     case SentenceGranularity:
@@ -785,10 +790,10 @@
     case ParagraphBoundary:
     case DocumentBoundary:
         // FIXME: Implement all of the above.
-        pos = modifyMovingForward(granularity);
+        pos = modifyMovingForward(granularity, reachedBoundary);
         break;
     case LineBoundary:
-        pos = rightBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
+        pos = rightBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock(), reachedBoundary);
         break;
     case DocumentGranularity:
         ASSERT_NOT_REACHED();
@@ -797,8 +802,26 @@
     return pos;
 }
 
-VisiblePosition FrameSelection::modifyMovingForward(TextGranularity granularity)
+VisiblePosition FrameSelection::modifyMovingForward(TextGranularity granularity, bool* reachedBoundary)
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
+    VisiblePosition currentPosition;
+    switch (granularity) {
+    case WordGranularity:
+    case SentenceGranularity:
+        currentPosition = VisiblePosition(m_selection.extent(), m_selection.affinity());
+        break;
+    case LineGranularity:
+    case ParagraphGranularity:
+    case SentenceBoundary:
+    case ParagraphBoundary:
+    case DocumentBoundary:
+        currentPosition = endForPlatform();
+        break;
+    default:
+        break;
+    }
     VisiblePosition pos;
     // FIXME: Stay in editable content for the less common granularities.
     switch (granularity) {
@@ -806,45 +829,59 @@
         if (isRange())
             pos = VisiblePosition(m_selection.end(), m_selection.affinity());
         else
-            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(CannotCrossEditingBoundary);
+            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(CannotCrossEditingBoundary, reachedBoundary);
         break;
     case WordGranularity:
-        pos = nextWordPositionForPlatform(VisiblePosition(m_selection.extent(), m_selection.affinity()));
+        pos = nextWordPositionForPlatform(currentPosition);
         break;
     case SentenceGranularity:
-        pos = nextSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
+        pos = nextSentencePosition(currentPosition);
         break;
     case LineGranularity: {
         // down-arrowing from a range selection that ends at the start of a line needs
         // to leave the selection at that line start (no need to call nextLinePosition!)
-        pos = endForPlatform();
+        pos = currentPosition;
         if (!isRange() || !isStartOfLine(pos))
             pos = nextLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(START));
         break;
     }
     case ParagraphGranularity:
-        pos = nextParagraphPosition(endForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
+        pos = nextParagraphPosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(START));
         break;
     case DocumentGranularity:
         ASSERT_NOT_REACHED();
         break;
     case SentenceBoundary:
-        pos = endOfSentence(endForPlatform());
+        pos = endOfSentence(currentPosition);
         break;
     case LineBoundary:
-        pos = logicalEndOfLine(endForPlatform());
+        pos = logicalEndOfLine(endForPlatform(), reachedBoundary);
         break;
     case ParagraphBoundary:
-        pos = endOfParagraph(endForPlatform());
+        pos = endOfParagraph(currentPosition);
         break;
     case DocumentBoundary:
-        pos = endForPlatform();
+        pos = currentPosition;
         if (isEditablePosition(pos.deepEquivalent()))
             pos = endOfEditableContent(pos);
         else
             pos = endOfDocument(pos);
         break;
     }
+    switch (granularity) {
+    case WordGranularity:
+    case SentenceGranularity:
+    case LineGranularity:
+    case ParagraphGranularity:
+    case SentenceBoundary:
+    case ParagraphBoundary:
+    case DocumentBoundary:
+        if (reachedBoundary)
+            *reachedBoundary = pos == currentPosition;
+        break;
+    default:
+        break;
+    }
     return pos;
 }
 
@@ -944,8 +981,10 @@
     return pos;
 }
 
-VisiblePosition FrameSelection::modifyMovingLeft(TextGranularity granularity)
+VisiblePosition FrameSelection::modifyMovingLeft(TextGranularity granularity, bool* reachedBoundary)
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
     VisiblePosition pos;
     switch (granularity) {
     case CharacterGranularity:
@@ -955,11 +994,14 @@
             else
                 pos = VisiblePosition(m_selection.end(), m_selection.affinity());
         else
-            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).left(true);
+            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).left(true, reachedBoundary);
         break;
     case WordGranularity: {
         bool skipsSpaceWhenMovingRight = m_frame && m_frame->editor().behavior().shouldSkipSpaceWhenMovingRight();
-        pos = leftWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()), skipsSpaceWhenMovingRight);
+        VisiblePosition currentPosition(m_selection.extent(), m_selection.affinity());
+        pos = leftWordPosition(currentPosition, skipsSpaceWhenMovingRight);
+        if (reachedBoundary)
+            *reachedBoundary = pos == currentPosition;
         break;
     }
     case SentenceGranularity:
@@ -969,10 +1011,10 @@
     case ParagraphBoundary:
     case DocumentBoundary:
         // FIXME: Implement all of the above.
-        pos = modifyMovingBackward(granularity);
+        pos = modifyMovingBackward(granularity, reachedBoundary);
         break;
     case LineBoundary:
-        pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
+        pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock(), reachedBoundary);
         break;
     case DocumentGranularity:
         ASSERT_NOT_REACHED();
@@ -981,39 +1023,57 @@
     return pos;
 }
 
-VisiblePosition FrameSelection::modifyMovingBackward(TextGranularity granularity)
+VisiblePosition FrameSelection::modifyMovingBackward(TextGranularity granularity, bool* reachedBoundary)
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
+    VisiblePosition currentPosition;
+    switch (granularity) {
+    case WordGranularity:
+    case SentenceGranularity:
+        currentPosition = VisiblePosition(m_selection.extent(), m_selection.affinity());
+        break;
+    case LineGranularity:
+    case ParagraphGranularity:
+    case SentenceBoundary:
+    case ParagraphBoundary:
+    case DocumentBoundary:
+        currentPosition = startForPlatform();
+        break;
+    default:
+        break;
+    }
     VisiblePosition pos;
     switch (granularity) {
     case CharacterGranularity:
         if (isRange())
             pos = VisiblePosition(m_selection.start(), m_selection.affinity());
         else
-            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(CannotCrossEditingBoundary);
+            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(CannotCrossEditingBoundary, reachedBoundary);
         break;
     case WordGranularity:
-        pos = previousWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
+        pos = previousWordPosition(currentPosition);
         break;
     case SentenceGranularity:
-        pos = previousSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
+        pos = previousSentencePosition(currentPosition);
         break;
     case LineGranularity:
-        pos = previousLinePosition(startForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
+        pos = previousLinePosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(START));
         break;
     case ParagraphGranularity:
-        pos = previousParagraphPosition(startForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
+        pos = previousParagraphPosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(START));
         break;
     case SentenceBoundary:
-        pos = startOfSentence(startForPlatform());
+        pos = startOfSentence(currentPosition);
         break;
     case LineBoundary:
-        pos = logicalStartOfLine(startForPlatform());
+        pos = logicalStartOfLine(startForPlatform(), reachedBoundary);
         break;
     case ParagraphBoundary:
-        pos = startOfParagraph(startForPlatform());
+        pos = startOfParagraph(currentPosition);
         break;
     case DocumentBoundary:
-        pos = startForPlatform();
+        pos = currentPosition;
         if (isEditablePosition(pos.deepEquivalent()))
             pos = startOfEditableContent(pos);
         else
@@ -1023,6 +1083,20 @@
         ASSERT_NOT_REACHED();
         break;
     }
+    switch (granularity) {
+    case WordGranularity:
+    case SentenceGranularity:
+    case LineGranularity:
+    case ParagraphGranularity:
+    case SentenceBoundary:
+    case ParagraphBoundary:
+    case DocumentBoundary:
+        if (reachedBoundary)
+            *reachedBoundary = pos == currentPosition;
+        break;
+    default:
+        break;
+    }
     return pos;
 }
 
@@ -1099,6 +1173,68 @@
     return intent;
 }
 
+static AXTextSelection textSelectionWithDirectionAndGranularity(SelectionDirection direction, TextGranularity granularity)
+{
+    // FIXME: Account for BIDI in DirectionRight & DirectionLeft. (In a RTL block, Right would map to Previous/Beginning and Left to Next/End.)
+    AXTextSelectionDirection intentDirection = AXTextSelectionDirectionUnknown;
+    switch (direction) {
+    case DirectionForward:
+        intentDirection = AXTextSelectionDirectionNext;
+        break;
+    case DirectionRight:
+        intentDirection = AXTextSelectionDirectionNext;
+        break;
+    case DirectionBackward:
+        intentDirection = AXTextSelectionDirectionPrevious;
+        break;
+    case DirectionLeft:
+        intentDirection = AXTextSelectionDirectionPrevious;
+        break;
+    }
+    AXTextSelectionGranularity intentGranularity = AXTextSelectionGranularityUnknown;
+    switch (granularity) {
+    case CharacterGranularity:
+        intentGranularity = AXTextSelectionGranularityCharacter;
+        break;
+    case WordGranularity:
+        intentGranularity = AXTextSelectionGranularityWord;
+        break;
+    case SentenceGranularity:
+    case SentenceBoundary: // FIXME: Boundary should affect direction.
+        intentGranularity = AXTextSelectionGranularitySentence;
+        break;
+    case LineGranularity:
+        intentGranularity = AXTextSelectionGranularityLine;
+        break;
+    case ParagraphGranularity:
+    case ParagraphBoundary: // FIXME: Boundary should affect direction.
+        intentGranularity = AXTextSelectionGranularityParagraph;
+        break;
+    case DocumentGranularity:
+    case DocumentBoundary: // FIXME: Boundary should affect direction.
+        intentGranularity = AXTextSelectionGranularityDocument;
+        break;
+    case LineBoundary:
+        intentGranularity = AXTextSelectionGranularityLine;
+        switch (direction) {
+        case DirectionForward:
+            intentDirection = AXTextSelectionDirectionEnd;
+            break;
+        case DirectionRight:
+            intentDirection = AXTextSelectionDirectionEnd;
+            break;
+        case DirectionBackward:
+            intentDirection = AXTextSelectionDirectionBeginning;
+            break;
+        case DirectionLeft:
+            intentDirection = AXTextSelectionDirectionBeginning;
+            break;
+        }
+        break;
+    }
+    return { intentDirection, intentGranularity, false };
+}
+
 bool FrameSelection::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity, EUserTriggered userTriggered)
 {
     if (userTriggered == UserTriggered) {
@@ -1116,13 +1252,14 @@
 
     willBeModified(alter, direction);
 
+    bool shouldNotify = false;
     bool wasRange = m_selection.isRange();
     Position originalStartPosition = m_selection.start();
     VisiblePosition position;
     switch (direction) {
     case DirectionRight:
         if (alter == AlterationMove)
-            position = modifyMovingRight(granularity);
+            position = modifyMovingRight(granularity, &shouldNotify);
         else
             position = modifyExtendingRight(granularity);
         break;
@@ -1130,11 +1267,11 @@
         if (alter == AlterationExtend)
             position = modifyExtendingForward(granularity);
         else
-            position = modifyMovingForward(granularity);
+            position = modifyMovingForward(granularity, &shouldNotify);
         break;
     case DirectionLeft:
         if (alter == AlterationMove)
-            position = modifyMovingLeft(granularity);
+            position = modifyMovingLeft(granularity, &shouldNotify);
         else
             position = modifyExtendingLeft(granularity);
         break;
@@ -1142,9 +1279,14 @@
         if (alter == AlterationExtend)
             position = modifyExtendingBackward(granularity);
         else
-            position = modifyMovingBackward(granularity);
+            position = modifyMovingBackward(granularity, &shouldNotify);
         break;
     }
+    
+    if (shouldNotify && userTriggered == UserTriggered && m_frame && AXObjectCache::accessibilityEnabled()) {
+        notifyAccessibilityForSelectionChange({ AXTextStateChangeTypeSelectionBoundary, textSelectionWithDirectionAndGranularity(direction, granularity) });
+        return true;
+    }
 
     if (position.isNull())
         return false;

Modified: trunk/Source/WebCore/editing/FrameSelection.h (195948 => 195949)


--- trunk/Source/WebCore/editing/FrameSelection.h	2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/editing/FrameSelection.h	2016-02-01 04:09:02 UTC (rev 195949)
@@ -291,12 +291,12 @@
 
     VisiblePosition modifyExtendingRight(TextGranularity);
     VisiblePosition modifyExtendingForward(TextGranularity);
-    VisiblePosition modifyMovingRight(TextGranularity);
-    VisiblePosition modifyMovingForward(TextGranularity);
+    VisiblePosition modifyMovingRight(TextGranularity, bool* reachedBoundary = nullptr);
+    VisiblePosition modifyMovingForward(TextGranularity, bool* reachedBoundary = nullptr);
     VisiblePosition modifyExtendingLeft(TextGranularity);
     VisiblePosition modifyExtendingBackward(TextGranularity);
-    VisiblePosition modifyMovingLeft(TextGranularity);
-    VisiblePosition modifyMovingBackward(TextGranularity);
+    VisiblePosition modifyMovingLeft(TextGranularity, bool* reachedBoundary = nullptr);
+    VisiblePosition modifyMovingBackward(TextGranularity, bool* reachedBoundary = nullptr);
 
     LayoutUnit lineDirectionPointForBlockDirectionNavigation(EPositionType);
 

Modified: trunk/Source/WebCore/editing/VisiblePosition.cpp (195948 => 195949)


--- trunk/Source/WebCore/editing/VisiblePosition.cpp	2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/editing/VisiblePosition.cpp	2016-02-01 04:09:02 UTC (rev 195949)
@@ -63,8 +63,10 @@
         m_affinity = DOWNSTREAM;
 }
 
-VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule) const
+VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule, bool* reachedBoundary) const
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
     // FIXME: Support CanSkipEditingBoundary
     ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
     VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity);
@@ -72,19 +74,24 @@
     if (rule == CanCrossEditingBoundary)
         return next;
 
-    return honorEditingBoundaryAtOrAfter(next);
+    return honorEditingBoundaryAtOrAfter(next, reachedBoundary);
 }
 
-VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule) const
+VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule, bool* reachedBoundary) const
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
     // FIXME: Support CanSkipEditingBoundary
     ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
     // find first previous DOM position that is visible
     Position pos = previousVisuallyDistinctCandidate(m_deepPosition);
     
     // return null visible position if there is no previous visible position
-    if (pos.atStartOfTree())
+    if (pos.atStartOfTree()) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
         return VisiblePosition();
+    }
         
     VisiblePosition prev = VisiblePosition(pos, DOWNSTREAM);
     ASSERT(prev != *this);
@@ -102,7 +109,7 @@
     if (rule == CanCrossEditingBoundary)
         return prev;
     
-    return honorEditingBoundaryAtOrBefore(prev);
+    return honorEditingBoundaryAtOrBefore(prev, reachedBoundary);
 }
 
 Position VisiblePosition::leftVisuallyDistinctCandidate() const
@@ -253,12 +260,17 @@
     }
 }
 
-VisiblePosition VisiblePosition::left(bool stayInEditableContent) const
+VisiblePosition VisiblePosition::left(bool stayInEditableContent, bool* reachedBoundary) const
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
     Position pos = leftVisuallyDistinctCandidate();
     // FIXME: Why can't we move left from the last position in a tree?
-    if (pos.atStartOfTree() || pos.atEndOfTree())
+    if (pos.atStartOfTree() || pos.atEndOfTree()) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
         return VisiblePosition();
+    }
 
     VisiblePosition left = VisiblePosition(pos, DOWNSTREAM);
     ASSERT(left != *this);
@@ -267,7 +279,7 @@
         return left;
 
     // FIXME: This may need to do something different from "before".
-    return honorEditingBoundaryAtOrBefore(left);
+    return honorEditingBoundaryAtOrBefore(left, reachedBoundary);
 }
 
 Position VisiblePosition::rightVisuallyDistinctCandidate() const
@@ -421,12 +433,17 @@
     }
 }
 
-VisiblePosition VisiblePosition::right(bool stayInEditableContent) const
+VisiblePosition VisiblePosition::right(bool stayInEditableContent, bool* reachedBoundary) const
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
     Position pos = rightVisuallyDistinctCandidate();
     // FIXME: Why can't we move left from the last position in a tree?
-    if (pos.atStartOfTree() || pos.atEndOfTree())
+    if (pos.atStartOfTree() || pos.atEndOfTree()) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
         return VisiblePosition();
+    }
 
     VisiblePosition right = VisiblePosition(pos, DOWNSTREAM);
     ASSERT(right != *this);
@@ -435,56 +452,78 @@
         return right;
 
     // FIXME: This may need to do something different from "after".
-    return honorEditingBoundaryAtOrAfter(right);
+    return honorEditingBoundaryAtOrAfter(right, reachedBoundary);
 }
 
-VisiblePosition VisiblePosition::honorEditingBoundaryAtOrBefore(const VisiblePosition &pos) const
+VisiblePosition VisiblePosition::honorEditingBoundaryAtOrBefore(const VisiblePosition &pos, bool* reachedBoundary) const
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
     if (pos.isNull())
         return pos;
     
     Node* highestRoot = highestEditableRoot(deepEquivalent());
     
     // Return empty position if pos is not somewhere inside the editable region containing this position
-    if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
+    if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot)) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
         return VisiblePosition();
-        
+    }
+    
     // Return pos itself if the two are from the very same editable region, or both are non-editable
     // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
     // to it is allowed.  VisibleSelection::adjustForEditableContent has this problem too.
-    if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
+    if (highestEditableRoot(pos.deepEquivalent()) == highestRoot) {
+        if (reachedBoundary)
+            *reachedBoundary = *this == pos;
         return pos;
+    }
   
     // Return empty position if this position is non-editable, but pos is editable
     // FIXME: Move to the previous non-editable region.
-    if (!highestRoot)
+    if (!highestRoot) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
         return VisiblePosition();
+    }
 
     // Return the last position before pos that is in the same editable region as this position
     return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);
 }
 
-VisiblePosition VisiblePosition::honorEditingBoundaryAtOrAfter(const VisiblePosition &pos) const
+VisiblePosition VisiblePosition::honorEditingBoundaryAtOrAfter(const VisiblePosition &pos, bool* reachedBoundary) const
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
     if (pos.isNull())
         return pos;
     
     Node* highestRoot = highestEditableRoot(deepEquivalent());
     
     // Return empty position if pos is not somewhere inside the editable region containing this position
-    if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
+    if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot)) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
         return VisiblePosition();
+    }
     
     // Return pos itself if the two are from the very same editable region, or both are non-editable
     // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
     // to it is allowed.  VisibleSelection::adjustForEditableContent has this problem too.
-    if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
+    if (highestEditableRoot(pos.deepEquivalent()) == highestRoot) {
+        if (reachedBoundary)
+            *reachedBoundary = *this == pos;
         return pos;
+    }
 
     // Return empty position if this position is non-editable, but pos is editable
     // FIXME: Move to the next non-editable region.
-    if (!highestRoot)
+    if (!highestRoot) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
         return VisiblePosition();
+    }
 
     // Return the next position after pos that is in the same editable region as this position
     return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);

Modified: trunk/Source/WebCore/editing/VisiblePosition.h (195948 => 195949)


--- trunk/Source/WebCore/editing/VisiblePosition.h	2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/editing/VisiblePosition.h	2016-02-01 04:09:02 UTC (rev 195949)
@@ -69,13 +69,13 @@
     // FIXME: Change the following functions' parameter from a boolean to StayInEditableContent.
 
     // next() and previous() will increment/decrement by a character cluster.
-    WEBCORE_EXPORT VisiblePosition next(EditingBoundaryCrossingRule = CanCrossEditingBoundary) const;
-    WEBCORE_EXPORT VisiblePosition previous(EditingBoundaryCrossingRule = CanCrossEditingBoundary) const;
-    VisiblePosition honorEditingBoundaryAtOrBefore(const VisiblePosition&) const;
-    VisiblePosition honorEditingBoundaryAtOrAfter(const VisiblePosition&) const;
+    WEBCORE_EXPORT VisiblePosition next(EditingBoundaryCrossingRule = CanCrossEditingBoundary, bool* reachedBoundary = nullptr) const;
+    WEBCORE_EXPORT VisiblePosition previous(EditingBoundaryCrossingRule = CanCrossEditingBoundary, bool* reachedBoundary = nullptr) const;
+    VisiblePosition honorEditingBoundaryAtOrBefore(const VisiblePosition&, bool* reachedBoundary = nullptr) const;
+    VisiblePosition honorEditingBoundaryAtOrAfter(const VisiblePosition&, bool* reachedBoundary = nullptr) const;
 
-    WEBCORE_EXPORT VisiblePosition left(bool stayInEditableContent = false) const;
-    WEBCORE_EXPORT VisiblePosition right(bool stayInEditableContent = false) const;
+    WEBCORE_EXPORT VisiblePosition left(bool stayInEditableContent = false, bool* reachedBoundary = nullptr) const;
+    WEBCORE_EXPORT VisiblePosition right(bool stayInEditableContent = false, bool* reachedBoundary = nullptr) const;
 
     WEBCORE_EXPORT UChar32 characterAfter() const;
     UChar32 characterBefore() const { return previous().characterAfter(); }

Modified: trunk/Source/WebCore/editing/VisibleUnits.cpp (195948 => 195949)


--- trunk/Source/WebCore/editing/VisibleUnits.cpp	2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/editing/VisibleUnits.cpp	2016-02-01 04:09:02 UTC (rev 195949)
@@ -774,31 +774,37 @@
         : positionBeforeNode(startNode);
 }
 
-static VisiblePosition startOfLine(const VisiblePosition& c, LineEndpointComputationMode mode)
+static VisiblePosition startOfLine(const VisiblePosition& c, LineEndpointComputationMode mode, bool* reachedBoundary)
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
     // TODO: this is the current behavior that might need to be fixed.
     // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
     VisiblePosition visPos = startPositionForLine(c, mode);
 
     if (mode == UseLogicalOrdering) {
         if (Node* editableRoot = highestEditableRoot(c.deepEquivalent())) {
-            if (!editableRoot->contains(visPos.deepEquivalent().containerNode()))
-                return firstPositionInNode(editableRoot);
+            if (!editableRoot->contains(visPos.deepEquivalent().containerNode())) {
+                VisiblePosition newPosition = firstPositionInNode(editableRoot);
+                if (reachedBoundary)
+                    *reachedBoundary = c == newPosition;
+                return newPosition;
+            }
         }
     }
 
-    return c.honorEditingBoundaryAtOrBefore(visPos);
+    return c.honorEditingBoundaryAtOrBefore(visPos, reachedBoundary);
 }
 
 // FIXME: Rename this function to reflect the fact it ignores bidi levels.
 VisiblePosition startOfLine(const VisiblePosition& currentPosition)
 {
-    return startOfLine(currentPosition, UseInlineBoxOrdering);
+    return startOfLine(currentPosition, UseInlineBoxOrdering, nullptr);
 }
 
-VisiblePosition logicalStartOfLine(const VisiblePosition& currentPosition)
+VisiblePosition logicalStartOfLine(const VisiblePosition& currentPosition, bool* reachedBoundary)
 {
-    return startOfLine(currentPosition, UseLogicalOrdering);
+    return startOfLine(currentPosition, UseLogicalOrdering, reachedBoundary);
 }
 
 static VisiblePosition endPositionForLine(const VisiblePosition& c, LineEndpointComputationMode mode)
@@ -858,8 +864,10 @@
     return a.isNotNull() && logicalStartOfLine(a) == logicalStartOfLine(b);
 }
 
-static VisiblePosition endOfLine(const VisiblePosition& c, LineEndpointComputationMode mode)
+static VisiblePosition endOfLine(const VisiblePosition& c, LineEndpointComputationMode mode, bool* reachedBoundary)
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
     // TODO: this is the current behavior that might need to be fixed.
     // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
     VisiblePosition visPos = endPositionForLine(c, mode);
@@ -874,11 +882,15 @@
             visPos = visPos.previous();
 
         if (Node* editableRoot = highestEditableRoot(c.deepEquivalent())) {
-            if (!editableRoot->contains(visPos.deepEquivalent().containerNode()))
-                return lastPositionInNode(editableRoot);
+            if (!editableRoot->contains(visPos.deepEquivalent().containerNode())) {
+                VisiblePosition newPosition = lastPositionInNode(editableRoot);
+                if (reachedBoundary)
+                    *reachedBoundary = c == newPosition;
+                return newPosition;
+            }
         }
 
-        return c.honorEditingBoundaryAtOrAfter(visPos);
+        return c.honorEditingBoundaryAtOrAfter(visPos, reachedBoundary);
     }
 
     // Make sure the end of line is at the same line as the given input position. Else use the previous position to 
@@ -893,18 +905,18 @@
         visPos = endPositionForLine(visPos, UseInlineBoxOrdering);
     }
     
-    return c.honorEditingBoundaryAtOrAfter(visPos);
+    return c.honorEditingBoundaryAtOrAfter(visPos, reachedBoundary);
 }
 
 // FIXME: Rename this function to reflect the fact it ignores bidi levels.
 VisiblePosition endOfLine(const VisiblePosition& currentPosition)
 {
-    return endOfLine(currentPosition, UseInlineBoxOrdering);
+    return endOfLine(currentPosition, UseInlineBoxOrdering, nullptr);
 }
 
-VisiblePosition logicalEndOfLine(const VisiblePosition& currentPosition)
+VisiblePosition logicalEndOfLine(const VisiblePosition& currentPosition, bool* reachedBoundary)
 {
-    return endOfLine(currentPosition, UseLogicalOrdering);
+    return endOfLine(currentPosition, UseLogicalOrdering, reachedBoundary);
 }
 
 bool inSameLine(const VisiblePosition& a, const VisiblePosition& b)
@@ -1440,14 +1452,14 @@
     return p.isNotNull() && p.next().isNull();
 }
 
-VisiblePosition leftBoundaryOfLine(const VisiblePosition& c, TextDirection direction)
+VisiblePosition leftBoundaryOfLine(const VisiblePosition& c, TextDirection direction, bool* reachedBoundary)
 {
-    return direction == LTR ? logicalStartOfLine(c) : logicalEndOfLine(c);
+    return direction == LTR ? logicalStartOfLine(c, reachedBoundary) : logicalEndOfLine(c, reachedBoundary);
 }
 
-VisiblePosition rightBoundaryOfLine(const VisiblePosition& c, TextDirection direction)
+VisiblePosition rightBoundaryOfLine(const VisiblePosition& c, TextDirection direction, bool* reachedBoundary)
 {
-    return direction == LTR ? logicalEndOfLine(c) : logicalStartOfLine(c);
+    return direction == LTR ? logicalEndOfLine(c, reachedBoundary) : logicalStartOfLine(c, reachedBoundary);
 }
 
 static bool directionIsDownstream(SelectionDirection direction)

Modified: trunk/Source/WebCore/editing/VisibleUnits.h (195948 => 195949)


--- trunk/Source/WebCore/editing/VisibleUnits.h	2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/editing/VisibleUnits.h	2016-02-01 04:09:02 UTC (rev 195949)
@@ -60,11 +60,11 @@
 WEBCORE_EXPORT bool inSameLine(const VisiblePosition &, const VisiblePosition &);
 WEBCORE_EXPORT bool isStartOfLine(const VisiblePosition &);
 WEBCORE_EXPORT bool isEndOfLine(const VisiblePosition &);
-VisiblePosition logicalStartOfLine(const VisiblePosition &);
-VisiblePosition logicalEndOfLine(const VisiblePosition &);
+VisiblePosition logicalStartOfLine(const VisiblePosition &, bool* reachedBoundary = nullptr);
+VisiblePosition logicalEndOfLine(const VisiblePosition &, bool* reachedBoundary = nullptr);
 bool isLogicalEndOfLine(const VisiblePosition &);
-VisiblePosition leftBoundaryOfLine(const VisiblePosition&, TextDirection);
-VisiblePosition rightBoundaryOfLine(const VisiblePosition&, TextDirection);
+VisiblePosition leftBoundaryOfLine(const VisiblePosition&, TextDirection, bool* reachedBoundary);
+VisiblePosition rightBoundaryOfLine(const VisiblePosition&, TextDirection, bool* reachedBoundary);
 
 // paragraphs (perhaps a misnomer, can be divided by line break elements)
 WEBCORE_EXPORT VisiblePosition startOfParagraph(const VisiblePosition&, EditingBoundaryCrossingRule = CannotCrossEditingBoundary);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to