<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[195949] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/195949">195949</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-01-31 20:09:02 -0800 (Sun, 31 Jan 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>AX: Add a boundary value to AXTextStateChangeType
https://bugs.webkit.org/show_bug.cgi?id=153085

Patch by Doug Russell &lt;d_russell@apple.com&gt; 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.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreaccessibilityAXObjectCachecpp">trunk/Source/WebCore/accessibility/AXObjectCache.cpp</a></li>
<li><a href="#trunkSourceWebCoreaccessibilityAXTextStateChangeIntenth">trunk/Source/WebCore/accessibility/AXTextStateChangeIntent.h</a></li>
<li><a href="#trunkSourceWebCoreaccessibilitymacAXObjectCacheMacmm">trunk/Source/WebCore/accessibility/mac/AXObjectCacheMac.mm</a></li>
<li><a href="#trunkSourceWebCoreeditingFrameSelectioncpp">trunk/Source/WebCore/editing/FrameSelection.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditingFrameSelectionh">trunk/Source/WebCore/editing/FrameSelection.h</a></li>
<li><a href="#trunkSourceWebCoreeditingVisiblePositioncpp">trunk/Source/WebCore/editing/VisiblePosition.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditingVisiblePositionh">trunk/Source/WebCore/editing/VisiblePosition.h</a></li>
<li><a href="#trunkSourceWebCoreeditingVisibleUnitscpp">trunk/Source/WebCore/editing/VisibleUnits.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditingVisibleUnitsh">trunk/Source/WebCore/editing/VisibleUnits.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsaccessibilitymacselectionboundaryuserinfoexpectedtxt">trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo-expected.txt</a></li>
<li><a href="#trunkLayoutTestsaccessibilitymacselectionboundaryuserinfohtml">trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (195948 => 195949)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/LayoutTests/ChangeLog        2016-02-01 04:09:02 UTC (rev 195949)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2016-01-31  Doug Russell  &lt;d_russell@apple.com&gt;
+
+        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.
+
</ins><span class="cx"> 2016-01-31  Daniel Bates  &lt;dabates@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         CSP: Use the served CSP header for dedicated workers
</span></span></pre></div>
<a id="trunkLayoutTestsaccessibilitymacselectionboundaryuserinfoexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo-expected.txt (0 => 195949)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,97 @@
</span><ins>+This tests selection change notifications at text boundaries.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+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
+
+

+
</ins></span></pre></div>
<a id="trunkLayoutTestsaccessibilitymacselectionboundaryuserinfohtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo.html (0 => 195949)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,185 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body id=&quot;body&quot;&gt;
+
+&lt;div role=&quot;textbox&quot; tabindex=0 id=&quot;textbox&quot; contenteditable=true&gt;
+    &lt;p&gt;&lt;br&gt;
+&lt;/div&gt;
+
+&lt;br&gt;
+
+&lt;input type=&quot;text&quot; id=&quot;input&quot;&gt;
+
+&lt;br&gt;
+
+&lt;textarea id=&quot;textarea&quot;&gt;&lt;/textarea&gt;
+
+&lt;script&gt;
+
+    description(&quot;This tests selection change notifications at text boundaries.&quot;);
+
+    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(&quot;leftArrow&quot;);
+        eventSender.keyDown(&quot;rightArrow&quot;);
+        if (includeVertical) {
+            // Move by line
+            eventSender.keyDown(&quot;upArrow&quot;);
+            eventSender.keyDown(&quot;downArrow&quot;);
+        }
+        // Move by word
+        eventSender.keyDown(&quot;leftArrow&quot;, [&quot;altKey&quot;]);
+        eventSender.keyDown(&quot;rightArrow&quot;, [&quot;altKey&quot;]);
+        // Move to beginning/end of line
+        eventSender.keyDown(&quot;leftArrow&quot;, [&quot;metaKey&quot;]);
+        eventSender.keyDown(&quot;rightArrow&quot;, [&quot;metaKey&quot;]);
+        if (includeVertical) {
+            // Move to beginning/end of document
+            eventSender.keyDown(&quot;upArrow&quot;, [&quot;metaKey&quot;]);
+            eventSender.keyDown(&quot;downArrow&quot;, [&quot;metaKey&quot;]);
+        }
+    }
+
+    var webArea = 0;
+    var count = 0;
+    var results = [];
+    var i = 0;
+    function notificationCallback(notification, userInfo) {
+        if (notification == &quot;AXSelectedTextChanged&quot;) {
+            count++;
+            if (userInfo) {
+                results.push(userInfo[&quot;AXTextStateChangeType&quot;]);
+                if (userInfo[&quot;AXTextSelectionDirection&quot;])
+                    results.push(userInfo[&quot;AXTextSelectionDirection&quot;]);
+                if (userInfo[&quot;AXTextSelectionGranularity&quot;])
+                    results.push(userInfo[&quot;AXTextSelectionGranularity&quot;]);
+            }
+            if (count == 29) {
+
+                function shouldBeResults(includeVertical) {
+                    // Focusing into the textbox
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextStateChangeTypeSelectionMove&quot;); i++;
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionDirectionDiscontiguous&quot;);  i++;
+
+                    // Left Arrow
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextStateChangeTypeSelectionBoundary&quot;);  i++;
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionDirectionPrevious&quot;);  i++;
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionGranularityCharacter&quot;);  i++;
+
+                    // Right Arrow
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextStateChangeTypeSelectionBoundary&quot;);  i++;
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionDirectionNext&quot;);  i++;
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionGranularityCharacter&quot;);  i++;
+
+                    if (includeVertical) {
+                        // Up Arrow
+                        shouldBe(&quot;results[i]&quot;, &quot;AXTextStateChangeTypeSelectionBoundary&quot;);  i++;
+                        shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionDirectionPrevious&quot;); i++;
+                        shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionGranularityLine&quot;); i++;
+
+                        // Down Arrow
+                        shouldBe(&quot;results[i]&quot;, &quot;AXTextStateChangeTypeSelectionBoundary&quot;); i++;
+                        shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionDirectionNext&quot;); i++;
+                        shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionGranularityLine&quot;); i++;
+                    }
+
+                    // Option Left Arrow
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextStateChangeTypeSelectionBoundary&quot;); i++;
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionDirectionPrevious&quot;); i++;
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionGranularityWord&quot;); i++;
+
+                    // Option Right Arrow
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextStateChangeTypeSelectionBoundary&quot;); i++;
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionDirectionNext&quot;); i++;
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionGranularityWord&quot;); i++;
+
+                    // Command Left Arrow
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextStateChangeTypeSelectionBoundary&quot;); i++;
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionDirectionBeginning&quot;); i++;
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionGranularityLine&quot;); i++;
+
+                    // Command Right Arrow
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextStateChangeTypeSelectionBoundary&quot;); i++;
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionDirectionEnd&quot;); i++;
+                    shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionGranularityLine&quot;); i++;
+
+                    if (includeVertical) {
+                        // Command Up Arrow
+                        shouldBe(&quot;results[i]&quot;, &quot;AXTextStateChangeTypeSelectionBoundary&quot;); i++;
+                        // FIXME: This should be AXTextSelectionDirectionBeginning.
+                        shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionDirectionPrevious&quot;); i++;
+                        shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionGranularityDocument&quot;); i++;
+
+                        // Command Down Arrow
+                        shouldBe(&quot;results[i]&quot;, &quot;AXTextStateChangeTypeSelectionBoundary&quot;); i++;
+                        // FIXME: This should be AXTextSelectionDirectionEnd.
+                        shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionDirectionNext&quot;); i++;
+                        shouldBe(&quot;results[i]&quot;, &quot;AXTextSelectionGranularityDocument&quot;); 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(&quot;addedNotification&quot;, &quot;true&quot;);
+
+        textbox = document.getElementById(&quot;textbox&quot;);
+        textbox.focus();
+
+        move(true);
+
+        textbox = document.getElementById(&quot;input&quot;);
+        textbox.focus();
+
+        move(false);
+
+        textbox = document.getElementById(&quot;textarea&quot;);
+        textbox.focus();
+
+        move(true);
+    }
+
+&lt;/script&gt;
+
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (195948 => 195949)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,3 +1,53 @@
</span><ins>+2016-01-31  Doug Russell  &lt;d_russell@apple.com&gt;
+
+        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:
+
</ins><span class="cx"> 2016-01-31  Daniel Bates  &lt;dabates@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         CSP: Use the served CSP header for dedicated workers
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilityAXObjectCachecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (195948 => 195949)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -995,6 +995,9 @@
</span><span class="cx">     case AXTextStateChangeTypeSelectionExtend:
</span><span class="cx">         dataLog(&quot;Extend::&quot;);
</span><span class="cx">         break;
</span><ins>+    case AXTextStateChangeTypeSelectionBoundary:
+        dataLog(&quot;Boundary::&quot;);
+        break;
</ins><span class="cx">     }
</span><span class="cx">     switch (intent.type) {
</span><span class="cx">     case AXTextStateChangeTypeUnknown:
</span><span class="lines">@@ -1029,6 +1032,7 @@
</span><span class="cx">         break;
</span><span class="cx">     case AXTextStateChangeTypeSelectionMove:
</span><span class="cx">     case AXTextStateChangeTypeSelectionExtend:
</span><ins>+    case AXTextStateChangeTypeSelectionBoundary:
</ins><span class="cx">         switch (intent.selection.direction) {
</span><span class="cx">         case AXTextSelectionDirectionUnknown:
</span><span class="cx">             dataLog(&quot;Unknown::&quot;);
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilityAXTextStateChangeIntenth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/AXTextStateChangeIntent.h (195948 => 195949)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -32,7 +32,8 @@
</span><span class="cx">     AXTextStateChangeTypeUnknown,
</span><span class="cx">     AXTextStateChangeTypeEdit,
</span><span class="cx">     AXTextStateChangeTypeSelectionMove,
</span><del>-    AXTextStateChangeTypeSelectionExtend
</del><ins>+    AXTextStateChangeTypeSelectionExtend,
+    AXTextStateChangeTypeSelectionBoundary
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> enum AXTextEditType {
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilitymacAXObjectCacheMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/mac/AXObjectCacheMac.mm (195948 => 195949)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -158,6 +158,8 @@
</span><span class="cx">         return kAXTextStateChangeTypeSelectionMove;
</span><span class="cx">     case WebCore::AXTextStateChangeTypeSelectionExtend:
</span><span class="cx">         return kAXTextStateChangeTypeSelectionExtend;
</span><ins>+    case WebCore::AXTextStateChangeTypeSelectionBoundary:
+        return kAXTextStateChangeTypeSelectionBoundary;
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -365,6 +367,7 @@
</span><span class="cx">         switch (intent.type) {
</span><span class="cx">         case AXTextStateChangeTypeSelectionMove:
</span><span class="cx">         case AXTextStateChangeTypeSelectionExtend:
</span><ins>+        case AXTextStateChangeTypeSelectionBoundary:
</ins><span class="cx">             [userInfo setObject:@(platformDirectionForWebCoreDirection(intent.selection.direction)) forKey:NSAccessibilityTextSelectionDirection];
</span><span class="cx">             switch (intent.selection.direction) {
</span><span class="cx">             case AXTextSelectionDirectionUnknown:
</span><span class="lines">@@ -378,13 +381,13 @@
</span><span class="cx">             case AXTextSelectionDirectionDiscontiguous:
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><ins>+            if (intent.selection.focusChange)
+                [userInfo setObject:@(intent.selection.focusChange) forKey:NSAccessibilityTextSelectionChangedFocus];
</ins><span class="cx">             break;
</span><span class="cx">         case AXTextStateChangeTypeUnknown:
</span><span class="cx">         case AXTextStateChangeTypeEdit:
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-        if (intent.selection.focusChange)
-            [userInfo setObject:[NSNumber numberWithBool:intent.selection.focusChange] forKey:NSAccessibilityTextSelectionChangedFocus];
</del><span class="cx">     }
</span><span class="cx">     if (!selection.isNone()) {
</span><span class="cx">         if (id textMarkerRange = [object-&gt;wrapper() textMarkerRangeFromVisiblePositions:selection.visibleStart() endPosition:selection.visibleEnd()])
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingFrameSelectioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/FrameSelection.cpp (195948 => 195949)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -760,8 +760,10 @@
</span><span class="cx">     return pos;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition FrameSelection::modifyMovingRight(TextGranularity granularity)
</del><ins>+VisiblePosition FrameSelection::modifyMovingRight(TextGranularity granularity, bool* reachedBoundary)
</ins><span class="cx"> {
</span><ins>+    if (reachedBoundary)
+        *reachedBoundary = false;
</ins><span class="cx">     VisiblePosition pos;
</span><span class="cx">     switch (granularity) {
</span><span class="cx">     case CharacterGranularity:
</span><span class="lines">@@ -771,11 +773,14 @@
</span><span class="cx">             else
</span><span class="cx">                 pos = VisiblePosition(m_selection.start(), m_selection.affinity());
</span><span class="cx">         } else
</span><del>-            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).right(true);
</del><ins>+            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).right(true, reachedBoundary);
</ins><span class="cx">         break;
</span><span class="cx">     case WordGranularity: {
</span><span class="cx">         bool skipsSpaceWhenMovingRight = m_frame &amp;&amp; m_frame-&gt;editor().behavior().shouldSkipSpaceWhenMovingRight();
</span><del>-        pos = rightWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()), skipsSpaceWhenMovingRight);
</del><ins>+        VisiblePosition currentPosition(m_selection.extent(), m_selection.affinity());
+        pos = rightWordPosition(currentPosition, skipsSpaceWhenMovingRight);
+        if (reachedBoundary)
+            *reachedBoundary = pos == currentPosition;
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     case SentenceGranularity:
</span><span class="lines">@@ -785,10 +790,10 @@
</span><span class="cx">     case ParagraphBoundary:
</span><span class="cx">     case DocumentBoundary:
</span><span class="cx">         // FIXME: Implement all of the above.
</span><del>-        pos = modifyMovingForward(granularity);
</del><ins>+        pos = modifyMovingForward(granularity, reachedBoundary);
</ins><span class="cx">         break;
</span><span class="cx">     case LineBoundary:
</span><del>-        pos = rightBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
</del><ins>+        pos = rightBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock(), reachedBoundary);
</ins><span class="cx">         break;
</span><span class="cx">     case DocumentGranularity:
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="lines">@@ -797,8 +802,26 @@
</span><span class="cx">     return pos;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition FrameSelection::modifyMovingForward(TextGranularity granularity)
</del><ins>+VisiblePosition FrameSelection::modifyMovingForward(TextGranularity granularity, bool* reachedBoundary)
</ins><span class="cx"> {
</span><ins>+    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;
+    }
</ins><span class="cx">     VisiblePosition pos;
</span><span class="cx">     // FIXME: Stay in editable content for the less common granularities.
</span><span class="cx">     switch (granularity) {
</span><span class="lines">@@ -806,45 +829,59 @@
</span><span class="cx">         if (isRange())
</span><span class="cx">             pos = VisiblePosition(m_selection.end(), m_selection.affinity());
</span><span class="cx">         else
</span><del>-            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(CannotCrossEditingBoundary);
</del><ins>+            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(CannotCrossEditingBoundary, reachedBoundary);
</ins><span class="cx">         break;
</span><span class="cx">     case WordGranularity:
</span><del>-        pos = nextWordPositionForPlatform(VisiblePosition(m_selection.extent(), m_selection.affinity()));
</del><ins>+        pos = nextWordPositionForPlatform(currentPosition);
</ins><span class="cx">         break;
</span><span class="cx">     case SentenceGranularity:
</span><del>-        pos = nextSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
</del><ins>+        pos = nextSentencePosition(currentPosition);
</ins><span class="cx">         break;
</span><span class="cx">     case LineGranularity: {
</span><span class="cx">         // down-arrowing from a range selection that ends at the start of a line needs
</span><span class="cx">         // to leave the selection at that line start (no need to call nextLinePosition!)
</span><del>-        pos = endForPlatform();
</del><ins>+        pos = currentPosition;
</ins><span class="cx">         if (!isRange() || !isStartOfLine(pos))
</span><span class="cx">             pos = nextLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(START));
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     case ParagraphGranularity:
</span><del>-        pos = nextParagraphPosition(endForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
</del><ins>+        pos = nextParagraphPosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(START));
</ins><span class="cx">         break;
</span><span class="cx">     case DocumentGranularity:
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         break;
</span><span class="cx">     case SentenceBoundary:
</span><del>-        pos = endOfSentence(endForPlatform());
</del><ins>+        pos = endOfSentence(currentPosition);
</ins><span class="cx">         break;
</span><span class="cx">     case LineBoundary:
</span><del>-        pos = logicalEndOfLine(endForPlatform());
</del><ins>+        pos = logicalEndOfLine(endForPlatform(), reachedBoundary);
</ins><span class="cx">         break;
</span><span class="cx">     case ParagraphBoundary:
</span><del>-        pos = endOfParagraph(endForPlatform());
</del><ins>+        pos = endOfParagraph(currentPosition);
</ins><span class="cx">         break;
</span><span class="cx">     case DocumentBoundary:
</span><del>-        pos = endForPlatform();
</del><ins>+        pos = currentPosition;
</ins><span class="cx">         if (isEditablePosition(pos.deepEquivalent()))
</span><span class="cx">             pos = endOfEditableContent(pos);
</span><span class="cx">         else
</span><span class="cx">             pos = endOfDocument(pos);
</span><span class="cx">         break;
</span><span class="cx">     }
</span><ins>+    switch (granularity) {
+    case WordGranularity:
+    case SentenceGranularity:
+    case LineGranularity:
+    case ParagraphGranularity:
+    case SentenceBoundary:
+    case ParagraphBoundary:
+    case DocumentBoundary:
+        if (reachedBoundary)
+            *reachedBoundary = pos == currentPosition;
+        break;
+    default:
+        break;
+    }
</ins><span class="cx">     return pos;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -944,8 +981,10 @@
</span><span class="cx">     return pos;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition FrameSelection::modifyMovingLeft(TextGranularity granularity)
</del><ins>+VisiblePosition FrameSelection::modifyMovingLeft(TextGranularity granularity, bool* reachedBoundary)
</ins><span class="cx"> {
</span><ins>+    if (reachedBoundary)
+        *reachedBoundary = false;
</ins><span class="cx">     VisiblePosition pos;
</span><span class="cx">     switch (granularity) {
</span><span class="cx">     case CharacterGranularity:
</span><span class="lines">@@ -955,11 +994,14 @@
</span><span class="cx">             else
</span><span class="cx">                 pos = VisiblePosition(m_selection.end(), m_selection.affinity());
</span><span class="cx">         else
</span><del>-            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).left(true);
</del><ins>+            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).left(true, reachedBoundary);
</ins><span class="cx">         break;
</span><span class="cx">     case WordGranularity: {
</span><span class="cx">         bool skipsSpaceWhenMovingRight = m_frame &amp;&amp; m_frame-&gt;editor().behavior().shouldSkipSpaceWhenMovingRight();
</span><del>-        pos = leftWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()), skipsSpaceWhenMovingRight);
</del><ins>+        VisiblePosition currentPosition(m_selection.extent(), m_selection.affinity());
+        pos = leftWordPosition(currentPosition, skipsSpaceWhenMovingRight);
+        if (reachedBoundary)
+            *reachedBoundary = pos == currentPosition;
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     case SentenceGranularity:
</span><span class="lines">@@ -969,10 +1011,10 @@
</span><span class="cx">     case ParagraphBoundary:
</span><span class="cx">     case DocumentBoundary:
</span><span class="cx">         // FIXME: Implement all of the above.
</span><del>-        pos = modifyMovingBackward(granularity);
</del><ins>+        pos = modifyMovingBackward(granularity, reachedBoundary);
</ins><span class="cx">         break;
</span><span class="cx">     case LineBoundary:
</span><del>-        pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
</del><ins>+        pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock(), reachedBoundary);
</ins><span class="cx">         break;
</span><span class="cx">     case DocumentGranularity:
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="lines">@@ -981,39 +1023,57 @@
</span><span class="cx">     return pos;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition FrameSelection::modifyMovingBackward(TextGranularity granularity)
</del><ins>+VisiblePosition FrameSelection::modifyMovingBackward(TextGranularity granularity, bool* reachedBoundary)
</ins><span class="cx"> {
</span><ins>+    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;
+    }
</ins><span class="cx">     VisiblePosition pos;
</span><span class="cx">     switch (granularity) {
</span><span class="cx">     case CharacterGranularity:
</span><span class="cx">         if (isRange())
</span><span class="cx">             pos = VisiblePosition(m_selection.start(), m_selection.affinity());
</span><span class="cx">         else
</span><del>-            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(CannotCrossEditingBoundary);
</del><ins>+            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(CannotCrossEditingBoundary, reachedBoundary);
</ins><span class="cx">         break;
</span><span class="cx">     case WordGranularity:
</span><del>-        pos = previousWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
</del><ins>+        pos = previousWordPosition(currentPosition);
</ins><span class="cx">         break;
</span><span class="cx">     case SentenceGranularity:
</span><del>-        pos = previousSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
</del><ins>+        pos = previousSentencePosition(currentPosition);
</ins><span class="cx">         break;
</span><span class="cx">     case LineGranularity:
</span><del>-        pos = previousLinePosition(startForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
</del><ins>+        pos = previousLinePosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(START));
</ins><span class="cx">         break;
</span><span class="cx">     case ParagraphGranularity:
</span><del>-        pos = previousParagraphPosition(startForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
</del><ins>+        pos = previousParagraphPosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(START));
</ins><span class="cx">         break;
</span><span class="cx">     case SentenceBoundary:
</span><del>-        pos = startOfSentence(startForPlatform());
</del><ins>+        pos = startOfSentence(currentPosition);
</ins><span class="cx">         break;
</span><span class="cx">     case LineBoundary:
</span><del>-        pos = logicalStartOfLine(startForPlatform());
</del><ins>+        pos = logicalStartOfLine(startForPlatform(), reachedBoundary);
</ins><span class="cx">         break;
</span><span class="cx">     case ParagraphBoundary:
</span><del>-        pos = startOfParagraph(startForPlatform());
</del><ins>+        pos = startOfParagraph(currentPosition);
</ins><span class="cx">         break;
</span><span class="cx">     case DocumentBoundary:
</span><del>-        pos = startForPlatform();
</del><ins>+        pos = currentPosition;
</ins><span class="cx">         if (isEditablePosition(pos.deepEquivalent()))
</span><span class="cx">             pos = startOfEditableContent(pos);
</span><span class="cx">         else
</span><span class="lines">@@ -1023,6 +1083,20 @@
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         break;
</span><span class="cx">     }
</span><ins>+    switch (granularity) {
+    case WordGranularity:
+    case SentenceGranularity:
+    case LineGranularity:
+    case ParagraphGranularity:
+    case SentenceBoundary:
+    case ParagraphBoundary:
+    case DocumentBoundary:
+        if (reachedBoundary)
+            *reachedBoundary = pos == currentPosition;
+        break;
+    default:
+        break;
+    }
</ins><span class="cx">     return pos;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1099,6 +1173,68 @@
</span><span class="cx">     return intent;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static AXTextSelection textSelectionWithDirectionAndGranularity(SelectionDirection direction, TextGranularity granularity)
+{
+    // FIXME: Account for BIDI in DirectionRight &amp; 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 };
+}
+
</ins><span class="cx"> bool FrameSelection::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity, EUserTriggered userTriggered)
</span><span class="cx"> {
</span><span class="cx">     if (userTriggered == UserTriggered) {
</span><span class="lines">@@ -1116,13 +1252,14 @@
</span><span class="cx"> 
</span><span class="cx">     willBeModified(alter, direction);
</span><span class="cx"> 
</span><ins>+    bool shouldNotify = false;
</ins><span class="cx">     bool wasRange = m_selection.isRange();
</span><span class="cx">     Position originalStartPosition = m_selection.start();
</span><span class="cx">     VisiblePosition position;
</span><span class="cx">     switch (direction) {
</span><span class="cx">     case DirectionRight:
</span><span class="cx">         if (alter == AlterationMove)
</span><del>-            position = modifyMovingRight(granularity);
</del><ins>+            position = modifyMovingRight(granularity, &amp;shouldNotify);
</ins><span class="cx">         else
</span><span class="cx">             position = modifyExtendingRight(granularity);
</span><span class="cx">         break;
</span><span class="lines">@@ -1130,11 +1267,11 @@
</span><span class="cx">         if (alter == AlterationExtend)
</span><span class="cx">             position = modifyExtendingForward(granularity);
</span><span class="cx">         else
</span><del>-            position = modifyMovingForward(granularity);
</del><ins>+            position = modifyMovingForward(granularity, &amp;shouldNotify);
</ins><span class="cx">         break;
</span><span class="cx">     case DirectionLeft:
</span><span class="cx">         if (alter == AlterationMove)
</span><del>-            position = modifyMovingLeft(granularity);
</del><ins>+            position = modifyMovingLeft(granularity, &amp;shouldNotify);
</ins><span class="cx">         else
</span><span class="cx">             position = modifyExtendingLeft(granularity);
</span><span class="cx">         break;
</span><span class="lines">@@ -1142,9 +1279,14 @@
</span><span class="cx">         if (alter == AlterationExtend)
</span><span class="cx">             position = modifyExtendingBackward(granularity);
</span><span class="cx">         else
</span><del>-            position = modifyMovingBackward(granularity);
</del><ins>+            position = modifyMovingBackward(granularity, &amp;shouldNotify);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><ins>+    
+    if (shouldNotify &amp;&amp; userTriggered == UserTriggered &amp;&amp; m_frame &amp;&amp; AXObjectCache::accessibilityEnabled()) {
+        notifyAccessibilityForSelectionChange({ AXTextStateChangeTypeSelectionBoundary, textSelectionWithDirectionAndGranularity(direction, granularity) });
+        return true;
+    }
</ins><span class="cx"> 
</span><span class="cx">     if (position.isNull())
</span><span class="cx">         return false;
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingFrameSelectionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/FrameSelection.h (195948 => 195949)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -291,12 +291,12 @@
</span><span class="cx"> 
</span><span class="cx">     VisiblePosition modifyExtendingRight(TextGranularity);
</span><span class="cx">     VisiblePosition modifyExtendingForward(TextGranularity);
</span><del>-    VisiblePosition modifyMovingRight(TextGranularity);
-    VisiblePosition modifyMovingForward(TextGranularity);
</del><ins>+    VisiblePosition modifyMovingRight(TextGranularity, bool* reachedBoundary = nullptr);
+    VisiblePosition modifyMovingForward(TextGranularity, bool* reachedBoundary = nullptr);
</ins><span class="cx">     VisiblePosition modifyExtendingLeft(TextGranularity);
</span><span class="cx">     VisiblePosition modifyExtendingBackward(TextGranularity);
</span><del>-    VisiblePosition modifyMovingLeft(TextGranularity);
-    VisiblePosition modifyMovingBackward(TextGranularity);
</del><ins>+    VisiblePosition modifyMovingLeft(TextGranularity, bool* reachedBoundary = nullptr);
+    VisiblePosition modifyMovingBackward(TextGranularity, bool* reachedBoundary = nullptr);
</ins><span class="cx"> 
</span><span class="cx">     LayoutUnit lineDirectionPointForBlockDirectionNavigation(EPositionType);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingVisiblePositioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/VisiblePosition.cpp (195948 => 195949)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -63,8 +63,10 @@
</span><span class="cx">         m_affinity = DOWNSTREAM;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule) const
</del><ins>+VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule, bool* reachedBoundary) const
</ins><span class="cx"> {
</span><ins>+    if (reachedBoundary)
+        *reachedBoundary = false;
</ins><span class="cx">     // FIXME: Support CanSkipEditingBoundary
</span><span class="cx">     ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
</span><span class="cx">     VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity);
</span><span class="lines">@@ -72,19 +74,24 @@
</span><span class="cx">     if (rule == CanCrossEditingBoundary)
</span><span class="cx">         return next;
</span><span class="cx"> 
</span><del>-    return honorEditingBoundaryAtOrAfter(next);
</del><ins>+    return honorEditingBoundaryAtOrAfter(next, reachedBoundary);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule) const
</del><ins>+VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule, bool* reachedBoundary) const
</ins><span class="cx"> {
</span><ins>+    if (reachedBoundary)
+        *reachedBoundary = false;
</ins><span class="cx">     // FIXME: Support CanSkipEditingBoundary
</span><span class="cx">     ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
</span><span class="cx">     // find first previous DOM position that is visible
</span><span class="cx">     Position pos = previousVisuallyDistinctCandidate(m_deepPosition);
</span><span class="cx">     
</span><span class="cx">     // return null visible position if there is no previous visible position
</span><del>-    if (pos.atStartOfTree())
</del><ins>+    if (pos.atStartOfTree()) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
</ins><span class="cx">         return VisiblePosition();
</span><ins>+    }
</ins><span class="cx">         
</span><span class="cx">     VisiblePosition prev = VisiblePosition(pos, DOWNSTREAM);
</span><span class="cx">     ASSERT(prev != *this);
</span><span class="lines">@@ -102,7 +109,7 @@
</span><span class="cx">     if (rule == CanCrossEditingBoundary)
</span><span class="cx">         return prev;
</span><span class="cx">     
</span><del>-    return honorEditingBoundaryAtOrBefore(prev);
</del><ins>+    return honorEditingBoundaryAtOrBefore(prev, reachedBoundary);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Position VisiblePosition::leftVisuallyDistinctCandidate() const
</span><span class="lines">@@ -253,12 +260,17 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition VisiblePosition::left(bool stayInEditableContent) const
</del><ins>+VisiblePosition VisiblePosition::left(bool stayInEditableContent, bool* reachedBoundary) const
</ins><span class="cx"> {
</span><ins>+    if (reachedBoundary)
+        *reachedBoundary = false;
</ins><span class="cx">     Position pos = leftVisuallyDistinctCandidate();
</span><span class="cx">     // FIXME: Why can't we move left from the last position in a tree?
</span><del>-    if (pos.atStartOfTree() || pos.atEndOfTree())
</del><ins>+    if (pos.atStartOfTree() || pos.atEndOfTree()) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
</ins><span class="cx">         return VisiblePosition();
</span><ins>+    }
</ins><span class="cx"> 
</span><span class="cx">     VisiblePosition left = VisiblePosition(pos, DOWNSTREAM);
</span><span class="cx">     ASSERT(left != *this);
</span><span class="lines">@@ -267,7 +279,7 @@
</span><span class="cx">         return left;
</span><span class="cx"> 
</span><span class="cx">     // FIXME: This may need to do something different from &quot;before&quot;.
</span><del>-    return honorEditingBoundaryAtOrBefore(left);
</del><ins>+    return honorEditingBoundaryAtOrBefore(left, reachedBoundary);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Position VisiblePosition::rightVisuallyDistinctCandidate() const
</span><span class="lines">@@ -421,12 +433,17 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition VisiblePosition::right(bool stayInEditableContent) const
</del><ins>+VisiblePosition VisiblePosition::right(bool stayInEditableContent, bool* reachedBoundary) const
</ins><span class="cx"> {
</span><ins>+    if (reachedBoundary)
+        *reachedBoundary = false;
</ins><span class="cx">     Position pos = rightVisuallyDistinctCandidate();
</span><span class="cx">     // FIXME: Why can't we move left from the last position in a tree?
</span><del>-    if (pos.atStartOfTree() || pos.atEndOfTree())
</del><ins>+    if (pos.atStartOfTree() || pos.atEndOfTree()) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
</ins><span class="cx">         return VisiblePosition();
</span><ins>+    }
</ins><span class="cx"> 
</span><span class="cx">     VisiblePosition right = VisiblePosition(pos, DOWNSTREAM);
</span><span class="cx">     ASSERT(right != *this);
</span><span class="lines">@@ -435,56 +452,78 @@
</span><span class="cx">         return right;
</span><span class="cx"> 
</span><span class="cx">     // FIXME: This may need to do something different from &quot;after&quot;.
</span><del>-    return honorEditingBoundaryAtOrAfter(right);
</del><ins>+    return honorEditingBoundaryAtOrAfter(right, reachedBoundary);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition VisiblePosition::honorEditingBoundaryAtOrBefore(const VisiblePosition &amp;pos) const
</del><ins>+VisiblePosition VisiblePosition::honorEditingBoundaryAtOrBefore(const VisiblePosition &amp;pos, bool* reachedBoundary) const
</ins><span class="cx"> {
</span><ins>+    if (reachedBoundary)
+        *reachedBoundary = false;
</ins><span class="cx">     if (pos.isNull())
</span><span class="cx">         return pos;
</span><span class="cx">     
</span><span class="cx">     Node* highestRoot = highestEditableRoot(deepEquivalent());
</span><span class="cx">     
</span><span class="cx">     // Return empty position if pos is not somewhere inside the editable region containing this position
</span><del>-    if (highestRoot &amp;&amp; !pos.deepEquivalent().deprecatedNode()-&gt;isDescendantOf(highestRoot))
</del><ins>+    if (highestRoot &amp;&amp; !pos.deepEquivalent().deprecatedNode()-&gt;isDescendantOf(highestRoot)) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
</ins><span class="cx">         return VisiblePosition();
</span><del>-        
</del><ins>+    }
+    
</ins><span class="cx">     // Return pos itself if the two are from the very same editable region, or both are non-editable
</span><span class="cx">     // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
</span><span class="cx">     // to it is allowed.  VisibleSelection::adjustForEditableContent has this problem too.
</span><del>-    if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
</del><ins>+    if (highestEditableRoot(pos.deepEquivalent()) == highestRoot) {
+        if (reachedBoundary)
+            *reachedBoundary = *this == pos;
</ins><span class="cx">         return pos;
</span><ins>+    }
</ins><span class="cx">   
</span><span class="cx">     // Return empty position if this position is non-editable, but pos is editable
</span><span class="cx">     // FIXME: Move to the previous non-editable region.
</span><del>-    if (!highestRoot)
</del><ins>+    if (!highestRoot) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
</ins><span class="cx">         return VisiblePosition();
</span><ins>+    }
</ins><span class="cx"> 
</span><span class="cx">     // Return the last position before pos that is in the same editable region as this position
</span><span class="cx">     return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition VisiblePosition::honorEditingBoundaryAtOrAfter(const VisiblePosition &amp;pos) const
</del><ins>+VisiblePosition VisiblePosition::honorEditingBoundaryAtOrAfter(const VisiblePosition &amp;pos, bool* reachedBoundary) const
</ins><span class="cx"> {
</span><ins>+    if (reachedBoundary)
+        *reachedBoundary = false;
</ins><span class="cx">     if (pos.isNull())
</span><span class="cx">         return pos;
</span><span class="cx">     
</span><span class="cx">     Node* highestRoot = highestEditableRoot(deepEquivalent());
</span><span class="cx">     
</span><span class="cx">     // Return empty position if pos is not somewhere inside the editable region containing this position
</span><del>-    if (highestRoot &amp;&amp; !pos.deepEquivalent().deprecatedNode()-&gt;isDescendantOf(highestRoot))
</del><ins>+    if (highestRoot &amp;&amp; !pos.deepEquivalent().deprecatedNode()-&gt;isDescendantOf(highestRoot)) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
</ins><span class="cx">         return VisiblePosition();
</span><ins>+    }
</ins><span class="cx">     
</span><span class="cx">     // Return pos itself if the two are from the very same editable region, or both are non-editable
</span><span class="cx">     // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
</span><span class="cx">     // to it is allowed.  VisibleSelection::adjustForEditableContent has this problem too.
</span><del>-    if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
</del><ins>+    if (highestEditableRoot(pos.deepEquivalent()) == highestRoot) {
+        if (reachedBoundary)
+            *reachedBoundary = *this == pos;
</ins><span class="cx">         return pos;
</span><ins>+    }
</ins><span class="cx"> 
</span><span class="cx">     // Return empty position if this position is non-editable, but pos is editable
</span><span class="cx">     // FIXME: Move to the next non-editable region.
</span><del>-    if (!highestRoot)
</del><ins>+    if (!highestRoot) {
+        if (reachedBoundary)
+            *reachedBoundary = true;
</ins><span class="cx">         return VisiblePosition();
</span><ins>+    }
</ins><span class="cx"> 
</span><span class="cx">     // Return the next position after pos that is in the same editable region as this position
</span><span class="cx">     return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingVisiblePositionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/VisiblePosition.h (195948 => 195949)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -69,13 +69,13 @@
</span><span class="cx">     // FIXME: Change the following functions' parameter from a boolean to StayInEditableContent.
</span><span class="cx"> 
</span><span class="cx">     // next() and previous() will increment/decrement by a character cluster.
</span><del>-    WEBCORE_EXPORT VisiblePosition next(EditingBoundaryCrossingRule = CanCrossEditingBoundary) const;
-    WEBCORE_EXPORT VisiblePosition previous(EditingBoundaryCrossingRule = CanCrossEditingBoundary) const;
-    VisiblePosition honorEditingBoundaryAtOrBefore(const VisiblePosition&amp;) const;
-    VisiblePosition honorEditingBoundaryAtOrAfter(const VisiblePosition&amp;) const;
</del><ins>+    WEBCORE_EXPORT VisiblePosition next(EditingBoundaryCrossingRule = CanCrossEditingBoundary, bool* reachedBoundary = nullptr) const;
+    WEBCORE_EXPORT VisiblePosition previous(EditingBoundaryCrossingRule = CanCrossEditingBoundary, bool* reachedBoundary = nullptr) const;
+    VisiblePosition honorEditingBoundaryAtOrBefore(const VisiblePosition&amp;, bool* reachedBoundary = nullptr) const;
+    VisiblePosition honorEditingBoundaryAtOrAfter(const VisiblePosition&amp;, bool* reachedBoundary = nullptr) const;
</ins><span class="cx"> 
</span><del>-    WEBCORE_EXPORT VisiblePosition left(bool stayInEditableContent = false) const;
-    WEBCORE_EXPORT VisiblePosition right(bool stayInEditableContent = false) const;
</del><ins>+    WEBCORE_EXPORT VisiblePosition left(bool stayInEditableContent = false, bool* reachedBoundary = nullptr) const;
+    WEBCORE_EXPORT VisiblePosition right(bool stayInEditableContent = false, bool* reachedBoundary = nullptr) const;
</ins><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT UChar32 characterAfter() const;
</span><span class="cx">     UChar32 characterBefore() const { return previous().characterAfter(); }
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingVisibleUnitscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/VisibleUnits.cpp (195948 => 195949)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -774,31 +774,37 @@
</span><span class="cx">         : positionBeforeNode(startNode);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static VisiblePosition startOfLine(const VisiblePosition&amp; c, LineEndpointComputationMode mode)
</del><ins>+static VisiblePosition startOfLine(const VisiblePosition&amp; c, LineEndpointComputationMode mode, bool* reachedBoundary)
</ins><span class="cx"> {
</span><ins>+    if (reachedBoundary)
+        *reachedBoundary = false;
</ins><span class="cx">     // TODO: this is the current behavior that might need to be fixed.
</span><span class="cx">     // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
</span><span class="cx">     VisiblePosition visPos = startPositionForLine(c, mode);
</span><span class="cx"> 
</span><span class="cx">     if (mode == UseLogicalOrdering) {
</span><span class="cx">         if (Node* editableRoot = highestEditableRoot(c.deepEquivalent())) {
</span><del>-            if (!editableRoot-&gt;contains(visPos.deepEquivalent().containerNode()))
-                return firstPositionInNode(editableRoot);
</del><ins>+            if (!editableRoot-&gt;contains(visPos.deepEquivalent().containerNode())) {
+                VisiblePosition newPosition = firstPositionInNode(editableRoot);
+                if (reachedBoundary)
+                    *reachedBoundary = c == newPosition;
+                return newPosition;
+            }
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return c.honorEditingBoundaryAtOrBefore(visPos);
</del><ins>+    return c.honorEditingBoundaryAtOrBefore(visPos, reachedBoundary);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // FIXME: Rename this function to reflect the fact it ignores bidi levels.
</span><span class="cx"> VisiblePosition startOfLine(const VisiblePosition&amp; currentPosition)
</span><span class="cx"> {
</span><del>-    return startOfLine(currentPosition, UseInlineBoxOrdering);
</del><ins>+    return startOfLine(currentPosition, UseInlineBoxOrdering, nullptr);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition logicalStartOfLine(const VisiblePosition&amp; currentPosition)
</del><ins>+VisiblePosition logicalStartOfLine(const VisiblePosition&amp; currentPosition, bool* reachedBoundary)
</ins><span class="cx"> {
</span><del>-    return startOfLine(currentPosition, UseLogicalOrdering);
</del><ins>+    return startOfLine(currentPosition, UseLogicalOrdering, reachedBoundary);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VisiblePosition endPositionForLine(const VisiblePosition&amp; c, LineEndpointComputationMode mode)
</span><span class="lines">@@ -858,8 +864,10 @@
</span><span class="cx">     return a.isNotNull() &amp;&amp; logicalStartOfLine(a) == logicalStartOfLine(b);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static VisiblePosition endOfLine(const VisiblePosition&amp; c, LineEndpointComputationMode mode)
</del><ins>+static VisiblePosition endOfLine(const VisiblePosition&amp; c, LineEndpointComputationMode mode, bool* reachedBoundary)
</ins><span class="cx"> {
</span><ins>+    if (reachedBoundary)
+        *reachedBoundary = false;
</ins><span class="cx">     // TODO: this is the current behavior that might need to be fixed.
</span><span class="cx">     // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
</span><span class="cx">     VisiblePosition visPos = endPositionForLine(c, mode);
</span><span class="lines">@@ -874,11 +882,15 @@
</span><span class="cx">             visPos = visPos.previous();
</span><span class="cx"> 
</span><span class="cx">         if (Node* editableRoot = highestEditableRoot(c.deepEquivalent())) {
</span><del>-            if (!editableRoot-&gt;contains(visPos.deepEquivalent().containerNode()))
-                return lastPositionInNode(editableRoot);
</del><ins>+            if (!editableRoot-&gt;contains(visPos.deepEquivalent().containerNode())) {
+                VisiblePosition newPosition = lastPositionInNode(editableRoot);
+                if (reachedBoundary)
+                    *reachedBoundary = c == newPosition;
+                return newPosition;
+            }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        return c.honorEditingBoundaryAtOrAfter(visPos);
</del><ins>+        return c.honorEditingBoundaryAtOrAfter(visPos, reachedBoundary);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Make sure the end of line is at the same line as the given input position. Else use the previous position to 
</span><span class="lines">@@ -893,18 +905,18 @@
</span><span class="cx">         visPos = endPositionForLine(visPos, UseInlineBoxOrdering);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    return c.honorEditingBoundaryAtOrAfter(visPos);
</del><ins>+    return c.honorEditingBoundaryAtOrAfter(visPos, reachedBoundary);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // FIXME: Rename this function to reflect the fact it ignores bidi levels.
</span><span class="cx"> VisiblePosition endOfLine(const VisiblePosition&amp; currentPosition)
</span><span class="cx"> {
</span><del>-    return endOfLine(currentPosition, UseInlineBoxOrdering);
</del><ins>+    return endOfLine(currentPosition, UseInlineBoxOrdering, nullptr);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition logicalEndOfLine(const VisiblePosition&amp; currentPosition)
</del><ins>+VisiblePosition logicalEndOfLine(const VisiblePosition&amp; currentPosition, bool* reachedBoundary)
</ins><span class="cx"> {
</span><del>-    return endOfLine(currentPosition, UseLogicalOrdering);
</del><ins>+    return endOfLine(currentPosition, UseLogicalOrdering, reachedBoundary);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool inSameLine(const VisiblePosition&amp; a, const VisiblePosition&amp; b)
</span><span class="lines">@@ -1440,14 +1452,14 @@
</span><span class="cx">     return p.isNotNull() &amp;&amp; p.next().isNull();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition leftBoundaryOfLine(const VisiblePosition&amp; c, TextDirection direction)
</del><ins>+VisiblePosition leftBoundaryOfLine(const VisiblePosition&amp; c, TextDirection direction, bool* reachedBoundary)
</ins><span class="cx"> {
</span><del>-    return direction == LTR ? logicalStartOfLine(c) : logicalEndOfLine(c);
</del><ins>+    return direction == LTR ? logicalStartOfLine(c, reachedBoundary) : logicalEndOfLine(c, reachedBoundary);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-VisiblePosition rightBoundaryOfLine(const VisiblePosition&amp; c, TextDirection direction)
</del><ins>+VisiblePosition rightBoundaryOfLine(const VisiblePosition&amp; c, TextDirection direction, bool* reachedBoundary)
</ins><span class="cx"> {
</span><del>-    return direction == LTR ? logicalEndOfLine(c) : logicalStartOfLine(c);
</del><ins>+    return direction == LTR ? logicalEndOfLine(c, reachedBoundary) : logicalStartOfLine(c, reachedBoundary);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static bool directionIsDownstream(SelectionDirection direction)
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingVisibleUnitsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/VisibleUnits.h (195948 => 195949)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -60,11 +60,11 @@
</span><span class="cx"> WEBCORE_EXPORT bool inSameLine(const VisiblePosition &amp;, const VisiblePosition &amp;);
</span><span class="cx"> WEBCORE_EXPORT bool isStartOfLine(const VisiblePosition &amp;);
</span><span class="cx"> WEBCORE_EXPORT bool isEndOfLine(const VisiblePosition &amp;);
</span><del>-VisiblePosition logicalStartOfLine(const VisiblePosition &amp;);
-VisiblePosition logicalEndOfLine(const VisiblePosition &amp;);
</del><ins>+VisiblePosition logicalStartOfLine(const VisiblePosition &amp;, bool* reachedBoundary = nullptr);
+VisiblePosition logicalEndOfLine(const VisiblePosition &amp;, bool* reachedBoundary = nullptr);
</ins><span class="cx"> bool isLogicalEndOfLine(const VisiblePosition &amp;);
</span><del>-VisiblePosition leftBoundaryOfLine(const VisiblePosition&amp;, TextDirection);
-VisiblePosition rightBoundaryOfLine(const VisiblePosition&amp;, TextDirection);
</del><ins>+VisiblePosition leftBoundaryOfLine(const VisiblePosition&amp;, TextDirection, bool* reachedBoundary);
+VisiblePosition rightBoundaryOfLine(const VisiblePosition&amp;, TextDirection, bool* reachedBoundary);
</ins><span class="cx"> 
</span><span class="cx"> // paragraphs (perhaps a misnomer, can be divided by line break elements)
</span><span class="cx"> WEBCORE_EXPORT VisiblePosition startOfParagraph(const VisiblePosition&amp;, EditingBoundaryCrossingRule = CannotCrossEditingBoundary);
</span></span></pre>
</div>
</div>

</body>
</html>