<!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>[196352] 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/196352">196352</a></dd>
<dt>Author</dt> <dd>n_wang@apple.com</dd>
<dt>Date</dt> <dd>2016-02-09 18:33:04 -0800 (Tue, 09 Feb 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>AX: Implement word related text marker functions using TextIterator
https://bugs.webkit.org/show_bug.cgi?id=153939
<rdar://problem/24269605>
Reviewed by Chris Fleizach.
Source/WebCore:
Using CharacterOffset to implement word related text marker calls. Reused
logic from previousBoundary and nextBoundary in VisibleUnits class.
Test: accessibility/mac/text-marker-word-nav.html
* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::traverseToOffsetInRange):
(WebCore::AXObjectCache::rangeForNodeContents):
(WebCore::isReplacedNodeOrBR):
(WebCore::characterOffsetsInOrder):
(WebCore::resetNodeAndOffsetForReplacedNode):
(WebCore::setRangeStartOrEndWithCharacterOffset):
(WebCore::AXObjectCache::rangeForUnorderedCharacterOffsets):
(WebCore::AXObjectCache::setTextMarkerDataWithCharacterOffset):
(WebCore::AXObjectCache::startOrEndCharacterOffsetForRange):
(WebCore::AXObjectCache::startOrEndTextMarkerDataForRange):
(WebCore::AXObjectCache::characterOffsetForNodeAndOffset):
(WebCore::AXObjectCache::textMarkerDataForCharacterOffset):
(WebCore::AXObjectCache::previousNode):
(WebCore::AXObjectCache::visiblePositionFromCharacterOffset):
(WebCore::AXObjectCache::characterOffsetFromVisiblePosition):
(WebCore::AXObjectCache::textMarkerDataForVisiblePosition):
(WebCore::AXObjectCache::nextCharacterOffset):
(WebCore::AXObjectCache::previousCharacterOffset):
(WebCore::startWordBoundary):
(WebCore::endWordBoundary):
(WebCore::AXObjectCache::startCharacterOffsetOfWord):
(WebCore::AXObjectCache::endCharacterOffsetOfWord):
(WebCore::AXObjectCache::previousWordStartCharacterOffset):
(WebCore::AXObjectCache::nextWordEndCharacterOffset):
(WebCore::AXObjectCache::leftWordRange):
(WebCore::AXObjectCache::rightWordRange):
(WebCore::characterForCharacterOffset):
(WebCore::AXObjectCache::characterAfter):
(WebCore::AXObjectCache::characterBefore):
(WebCore::parentEditingBoundary):
(WebCore::AXObjectCache::nextWordBoundary):
(WebCore::AXObjectCache::previousWordBoundary):
(WebCore::AXObjectCache::rootAXEditableElement):
* accessibility/AXObjectCache.h:
(WebCore::AXObjectCache::removeNodeForUse):
(WebCore::AXObjectCache::isNodeInUse):
* accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
(-[WebAccessibilityObjectWrapper previousTextMarkerForNode:offset:]):
(-[WebAccessibilityObjectWrapper textMarkerForNode:offset:ignoreStart:]):
(-[WebAccessibilityObjectWrapper textMarkerForNode:offset:]):
(textMarkerForCharacterOffset):
(-[WebAccessibilityObjectWrapper accessibilityAttributeValue:forParameter:]):
* editing/VisibleUnits.cpp:
(WebCore::rightWordPosition):
(WebCore::prepend):
(WebCore::appendRepeatedCharacter):
(WebCore::suffixLengthForRange):
(WebCore::prefixLengthForRange):
(WebCore::backwardSearchForBoundaryWithTextIterator):
(WebCore::forwardSearchForBoundaryWithTextIterator):
(WebCore::previousBoundary):
(WebCore::nextBoundary):
* editing/VisibleUnits.h:
Tools:
* DumpRenderTree/AccessibilityUIElement.cpp:
(endTextMarkerCallback):
(leftWordTextMarkerRangeForTextMarkerCallback):
(rightWordTextMarkerRangeForTextMarkerCallback):
(previousWordStartTextMarkerForTextMarkerCallback):
(nextWordEndTextMarkerForTextMarkerCallback):
(setSelectedVisibleTextRangeCallback):
(AccessibilityUIElement::setSelectedVisibleTextRange):
(AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
(AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
(AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
(AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(AccessibilityUIElement::getJSClass):
* DumpRenderTree/AccessibilityUIElement.h:
* DumpRenderTree/ios/AccessibilityUIElementIOS.mm:
(AccessibilityUIElement::setSelectedVisibleTextRange):
(AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
(AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
(AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
(AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
* DumpRenderTree/mac/AccessibilityUIElementMac.mm:
(AccessibilityUIElement::setSelectedVisibleTextRange):
(AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
(AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
(AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
(AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(AccessibilityUIElement::supportedActions):
* WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp:
(WTR::AccessibilityUIElement::setBoolAttributeValue):
(WTR::AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
* WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
* WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl:
* WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm:
(WTR::AccessibilityUIElement::endTextMarker):
(WTR::AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::mathPostscriptsDescription):
* WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm:
(WTR::AccessibilityUIElement::endTextMarker):
(WTR::AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(WTR::_convertMathMultiscriptPairsToString):
LayoutTests:
* accessibility/mac/text-marker-word-nav-expected.txt: Added.
* accessibility/mac/text-marker-word-nav.html: Added.
* accessibility/text-marker/text-marker-previous-next-expected.txt:
* accessibility/text-marker/text-marker-previous-next.html:</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsaccessibilitytextmarkertextmarkerpreviousnextexpectedtxt">trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next-expected.txt</a></li>
<li><a href="#trunkLayoutTestsaccessibilitytextmarkertextmarkerpreviousnexthtml">trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next.html</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="#trunkSourceWebCoreaccessibilityAXObjectCacheh">trunk/Source/WebCore/accessibility/AXObjectCache.h</a></li>
<li><a href="#trunkSourceWebCoreaccessibilitymacWebAccessibilityObjectWrapperMacmm">trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm</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>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsDumpRenderTreeAccessibilityUIElementcpp">trunk/Tools/DumpRenderTree/AccessibilityUIElement.cpp</a></li>
<li><a href="#trunkToolsDumpRenderTreeAccessibilityUIElementh">trunk/Tools/DumpRenderTree/AccessibilityUIElement.h</a></li>
<li><a href="#trunkToolsDumpRenderTreeiosAccessibilityUIElementIOSmm">trunk/Tools/DumpRenderTree/ios/AccessibilityUIElementIOS.mm</a></li>
<li><a href="#trunkToolsDumpRenderTreemacAccessibilityUIElementMacmm">trunk/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm</a></li>
<li><a href="#trunkToolsWebKitTestRunnerInjectedBundleAccessibilityUIElementcpp">trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp</a></li>
<li><a href="#trunkToolsWebKitTestRunnerInjectedBundleAccessibilityUIElementh">trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h</a></li>
<li><a href="#trunkToolsWebKitTestRunnerInjectedBundleBindingsAccessibilityUIElementidl">trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl</a></li>
<li><a href="#trunkToolsWebKitTestRunnerInjectedBundleiosAccessibilityUIElementIOSmm">trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm</a></li>
<li><a href="#trunkToolsWebKitTestRunnerInjectedBundlemacAccessibilityUIElementMacmm">trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsaccessibilitymactextmarkerwordnavexpectedtxt">trunk/LayoutTests/accessibility/mac/text-marker-word-nav-expected.txt</a></li>
<li><a href="#trunkLayoutTestsaccessibilitymactextmarkerwordnavhtml">trunk/LayoutTests/accessibility/mac/text-marker-word-nav.html</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/LayoutTests/ChangeLog        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2016-02-09 Nan Wang <n_wang@apple.com>
+
+ AX: Implement word related text marker functions using TextIterator
+ https://bugs.webkit.org/show_bug.cgi?id=153939
+ <rdar://problem/24269605>
+
+ Reviewed by Chris Fleizach.
+
+ * accessibility/mac/text-marker-word-nav-expected.txt: Added.
+ * accessibility/mac/text-marker-word-nav.html: Added.
+ * accessibility/text-marker/text-marker-previous-next-expected.txt:
+ * accessibility/text-marker/text-marker-previous-next.html:
+
</ins><span class="cx"> 2016-02-09 Ryan Haddad <ryanhaddad@apple.com>
</span><span class="cx">
</span><span class="cx"> Mark perf/adding-radio-buttons.html as flaky on ios-simulator
</span></span></pre></div>
<a id="trunkLayoutTestsaccessibilitymactextmarkerwordnavexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/accessibility/mac/text-marker-word-nav-expected.txt (0 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/accessibility/mac/text-marker-word-nav-expected.txt         (rev 0)
+++ trunk/LayoutTests/accessibility/mac/text-marker-word-nav-expected.txt        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -0,0 +1,125 @@
</span><ins>+word1 test
+Thisislongword I'll try. Test Contenteditable is working.
+c d
+can't select
+巧克力是食物吗?
+كيف حالك؟
+both spaces
+line breaks
+some
+text
+test audio file
+This tests that word navigation is working correctly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Current character is: w
+Left word is: word1
+Right word is: word1
+Pre word start to next word end: word1
+
+Current character is: T
+Left word is: Thisislongword
+Right word is: Thisislongword
+Pre word start to next word end: Thisislongword
+
+Current character is:
+Left word is:
+Right word is: I'll
+Pre word start to next word end: I'll
+
+Current character is:
+Left word is:
+Right word is: try
+Pre word start to next word end: try
+
+Current character is: e
+Left word is: editable
+Right word is: editable
+Pre word start to next word end: editable
+
+Current character is:
+Left word is:
+Right word is: [ATTACHMENT]
+Pre word start to next word end: [ATTACHMENT]
+
+Current character is: [ATTACHMENT]
+Left word is: [ATTACHMENT]
+Right word is: d
+Pre word start to next word end: [ATTACHMENT]d
+
+Current character is: c
+Left word is: can't
+Right word is: can't
+Pre word start to next word end: can't
+
+Current character is: 克
+Left word is: 巧克力
+Right word is: 巧克力
+Pre word start to next word end: 巧克力
+
+Current character is: 力
+Left word is: 巧克力
+Right word is: 是
+Pre word start to next word end: 巧克力是
+
+Current character is: 是
+Left word is: 是
+Right word is: 食物
+Pre word start to next word end: 是食物
+
+Current character is: ف
+Left word is: كيف
+Right word is:
+Pre word start to next word end: كيف
+
+Current character is:
+Left word is:
+Right word is: حالك
+Pre word start to next word end: حالك
+
+Current character is: h
+Left word is: both
+Right word is:
+Pre word start to next word end: both
+
+Current character is: s
+Left word is: spaces
+Right word is: 'line break'
+Pre word start to next word end: spaces'line break'
+
+Current character is: e
+Left word is: some
+Right word is: 'line break'
+Pre word start to next word end: some'line break'
+
+Current character is: 'line break'
+Left word is: 'line break'
+Right word is: text
+Pre word start to next word end: 'line break'text
+
+Current character is:
+Left word is:
+Right word is: [ATTACHMENT]
+Pre word start to next word end: [ATTACHMENT]
+
+Current character is: [ATTACHMENT]
+Left word is: [ATTACHMENT]
+Right word is: file
+Pre word start to next word end: [ATTACHMENT]file
+
+Current character is: f
+Left word is: file
+Right word is: file
+Pre word start to next word end: file
+
+Test going forward.
+End word: file
+
+Test going backwards.
+Start word: word1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsaccessibilitymactextmarkerwordnavhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/accessibility/mac/text-marker-word-nav.html (0 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/accessibility/mac/text-marker-word-nav.html         (rev 0)
+++ trunk/LayoutTests/accessibility/mac/text-marker-word-nav.html        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -0,0 +1,195 @@
</span><ins>+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<meta charset="utf-8">
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<style>
+.userselect { user-select: none; -webkit-user-select: none; }
+</style>
+<body id="body">
+
+<div id="text" tabindex="0">word1 test</div>
+<span id="span">Thisis</span>longword I<span>'ll try.</span>
+Test Content<span id="target" contenteditable="true">editable is working.</span>
+
+<div id="text2">
+c <img src="#" aria-label="blah" style="background-color: #aaaaaa; width: 100px; height: 100px;">d
+</div>
+
+<div class="userselect" id="text3">can't select</div>
+
+<div id="text4">
+巧克力是食物吗?
+</div>
+<div id="text4a">
+كيف حالك؟
+</div>
+
+<pre id="text5">
+both spaces
+line breaks
+</pre>
+
+<div id="text6">
+some<br>text
+</div>
+
+<div id="text7">
+test audio <audio controls><source src="test.mp3" type="audio/mpeg"></audio>file
+</div>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+
+ description("This tests that word navigation is working correctly.");
+
+ if (window.accessibilityController) {
+
+ var text = accessibilityController.accessibleElementById("text");
+ // Get the actual text node.
+ text = text.childAtIndex(0);
+
+ // Check that we can get the word range. Land at "w" in "word1 test".
+ var textMarkerRange = text.textMarkerRangeForElement(text);
+ var startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+ var currentMarker = advanceAndVerify(startMarker, 1, text);
+
+ // Check the case with span
+ // At "T" in "Thisis", should return the word as "Thisislongword".
+ currentMarker = advanceAndVerify(currentMarker, 10, text);
+ // At " " before "I", the word should be "I'll".
+ currentMarker = advanceAndVerify(currentMarker, 14, text);
+ // At " " before "try", the word should excludes "."
+ currentMarker = advanceAndVerify(currentMarker, 5, text);
+
+ // Check the case with contenteditable
+ // At "e" in "editable", the word should NOT include "Content" before it.
+ currentMarker = advanceAndVerify(currentMarker, 17, text);
+
+ // Check the case with replaced node, the replaced node should be considered a word.
+ var text2 = accessibilityController.accessibleElementById("text2");
+ textMarkerRange = text2.textMarkerRangeForElement(text2);
+ currentMarker = text2.startTextMarkerForTextMarkerRange(textMarkerRange);
+ currentMarker = advanceAndVerify(currentMarker, 2, text2);
+ currentMarker = advanceAndVerify(currentMarker, 1, text2);
+
+ // Check user-select:none is also working.
+ var text3 = accessibilityController.accessibleElementById("text3");
+ textMarkerRange = text3.textMarkerRangeForElement(text3);
+ currentMarker = text3.startTextMarkerForTextMarkerRange(textMarkerRange);
+ currentMarker = advanceAndVerify(currentMarker, 1, text3);
+
+ // Check multi-language, Chinese here.
+ var text4 = accessibilityController.accessibleElementById("text4");
+ textMarkerRange = text4.textMarkerRangeForElement(text4);
+ currentMarker = text4.startTextMarkerForTextMarkerRange(textMarkerRange);
+ currentMarker = advanceAndVerify(currentMarker, 2, text4);
+ currentMarker = advanceAndVerify(currentMarker, 1, text4);
+ currentMarker = advanceAndVerify(currentMarker, 1, text4);
+ // And Arabic
+ var text4a = accessibilityController.accessibleElementById("text4a");
+ textMarkerRange = text4a.textMarkerRangeForElement(text4a);
+ currentMarker = text4a.startTextMarkerForTextMarkerRange(textMarkerRange);
+ currentMarker = advanceAndVerify(currentMarker, 3, text4a);
+ currentMarker = advanceAndVerify(currentMarker, 1, text4a);
+
+ // Check text in pre tag with line breaks.
+ var text5 = accessibilityController.accessibleElementById("text5");
+ textMarkerRange = text5.textMarkerRangeForElement(text5);
+ currentMarker = text5.startTextMarkerForTextMarkerRange(textMarkerRange);
+ // At "h" in "both", right word should be " ".
+ currentMarker = advanceAndVerify(currentMarker, 4, text5);
+ // At the end of first line, right word should be new line.
+ currentMarker = advanceAndVerify(currentMarker, 9, text5);
+
+ // Check text with br tag in it.
+ var text6 = accessibilityController.accessibleElementById("text6");
+ textMarkerRange = text6.textMarkerRangeForElement(text6);
+ currentMarker = text6.startTextMarkerForTextMarkerRange(textMarkerRange);
+ currentMarker = advanceAndVerify(currentMarker, 4, text6);
+ currentMarker = advanceAndVerify(currentMarker, 1, text6);
+
+ // Check <audio> element.
+ var text7 = accessibilityController.accessibleElementById("text7");
+ textMarkerRange = text7.textMarkerRangeForElement(text7);
+ currentMarker = text7.startTextMarkerForTextMarkerRange(textMarkerRange);
+ currentMarker = advanceAndVerify(currentMarker, 11, text7);
+ currentMarker = advanceAndVerify(currentMarker, 1, text7);
+ currentMarker = advanceAndVerify(currentMarker, 1, text7);
+
+ // Check the word marker runs from start to end, and backwards.
+ // Make sure it won't hang.
+ verifyDocument(text);
+
+ function advanceAndVerify(currentMarker, offset, obj) {
+ var previousMarker;
+ for (var i = 0; i < offset; i++) {
+ previousMarker = currentMarker;
+ currentMarker = obj.nextTextMarker(previousMarker);
+ }
+ verifyWordRangeForTextMarker(previousMarker, currentMarker, obj);
+ return currentMarker;
+ }
+
+ function replaceAttachmentInString(str) {
+ var newline = '\n';
+ str = str.replace(String.fromCharCode(65532), "[ATTACHMENT]");
+ str = str.replace(newline, "'line break'");
+ return str;
+ }
+
+ function verifyWordRangeForTextMarker(preMarker, textMarker, obj) {
+ var markerRange = obj.textMarkerRangeForMarkers(preMarker, textMarker);
+ var currentCharacter = replaceAttachmentInString(obj.stringForTextMarkerRange(markerRange));
+ debug("Current character is: " + currentCharacter);
+
+ var previousWordRange = obj.leftWordTextMarkerRangeForTextMarker(textMarker);
+ var nextWordRange = obj.rightWordTextMarkerRangeForTextMarker(textMarker);
+ var preWord = replaceAttachmentInString(obj.stringForTextMarkerRange(previousWordRange));
+ var nextWord = replaceAttachmentInString(obj.stringForTextMarkerRange(nextWordRange));
+ debug("Left word is: " + preWord);
+ debug("Right word is: " + nextWord);
+
+ var preWordStart = obj.previousWordStartTextMarkerForTextMarker(textMarker);
+ var nextWordEnd = obj.nextWordEndTextMarkerForTextMarker(textMarker);
+ var preAndNextWordRange = obj.textMarkerRangeForMarkers(preWordStart, nextWordEnd);
+ var preAndNextWord = replaceAttachmentInString(obj.stringForTextMarkerRange(preAndNextWordRange));
+ debug("Pre word start to next word end: " + preAndNextWord + "\n");
+ }
+
+ function verifyDocument(obj) {
+ var start = obj.startTextMarker;
+
+ // Going forward.
+ debug("Test going forward.");
+ var current = start;
+ var endWord = "file";
+ var currWord = "";
+ while(currWord != endWord) {
+ var nextWordRange = obj.rightWordTextMarkerRangeForTextMarker(current);
+ currWord = obj.stringForTextMarkerRange(nextWordRange);
+ current = obj.nextWordEndTextMarkerForTextMarker(current);
+ }
+ debug("End word: " + replaceAttachmentInString(currWord));
+
+ // Going backwards.
+ debug("\nTest going backwards.");
+ var startWord = "word1";
+ currWord = "";
+ while(currWord != startWord) {
+ var previousWordRange = obj.leftWordTextMarkerRangeForTextMarker(current);
+ currWord = obj.stringForTextMarkerRange(previousWordRange);
+ current = obj.previousWordStartTextMarkerForTextMarker(current);
+ }
+ debug("Start word: " + replaceAttachmentInString(currWord));
+ }
+ }
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkLayoutTestsaccessibilitytextmarkertextmarkerpreviousnextexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next-expected.txt (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next-expected.txt        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next-expected.txt        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -12,9 +12,9 @@
</span><span class="cx"> PASS text.textMarkerRangeLength(textMarkerRange) is 4
</span><span class="cx"> PASS text.accessibilityElementForTextMarker(startMarker).isEqual(text) is true
</span><span class="cx"> PASS text.accessibilityElementForTextMarker(endMarker).isEqual(text) is true
</span><del>-PASS text.stringForTextMarkerRange(markerRange) is ''
</del><ins>+PASS text.stringForTextMarkerRange(markerRange) is newline
</ins><span class="cx"> PASS text.stringForTextMarkerRange(markerRange) is 't'
</span><del>-PASS text.stringForTextMarkerRange(markerRange) is ''
</del><ins>+PASS text.stringForTextMarkerRange(markerRange) is newline
</ins><span class="cx"> PASS text.stringForTextMarkerRange(markerRange) is 't'
</span><span class="cx"> PASS text2.textMarkerRangeLength(textMarkerRange2) is 5
</span><span class="cx"> Object string for range: c [ATTACHMENT] d
</span></span></pre></div>
<a id="trunkLayoutTestsaccessibilitytextmarkertextmarkerpreviousnexthtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next.html (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next.html        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next.html        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -50,7 +50,8 @@
</span><span class="cx"> currentMarker = text.nextTextMarker(currentMarker);
</span><span class="cx"> }
</span><span class="cx"> markerRange = text.textMarkerRangeForMarkers(previousMarker, currentMarker);
</span><del>- shouldBe("text.stringForTextMarkerRange(markerRange)", "''");
</del><ins>+ var newline = '\n';
+ shouldBe("text.stringForTextMarkerRange(markerRange)", "newline");
</ins><span class="cx">
</span><span class="cx"> // Advance one more character, it will lande at "t" in "text1".
</span><span class="cx"> previousMarker = currentMarker;
</span><span class="lines">@@ -62,7 +63,7 @@
</span><span class="cx"> previousMarker = text.previousTextMarker(previousMarker);
</span><span class="cx"> currentMarker = text.previousTextMarker(currentMarker);
</span><span class="cx"> markerRange = text.textMarkerRangeForMarkers(previousMarker, currentMarker);
</span><del>- shouldBe("text.stringForTextMarkerRange(markerRange)", "''");
</del><ins>+ shouldBe("text.stringForTextMarkerRange(markerRange)", "newline");
</ins><span class="cx">
</span><span class="cx"> // Traverse backwards one more character, it will land at the last character of "text".
</span><span class="cx"> previousMarker = text.previousTextMarker(previousMarker);
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Source/WebCore/ChangeLog        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -1,3 +1,71 @@
</span><ins>+2016-02-09 Nan Wang <n_wang@apple.com>
+
+ AX: Implement word related text marker functions using TextIterator
+ https://bugs.webkit.org/show_bug.cgi?id=153939
+ <rdar://problem/24269605>
+
+ Reviewed by Chris Fleizach.
+
+ Using CharacterOffset to implement word related text marker calls. Reused
+ logic from previousBoundary and nextBoundary in VisibleUnits class.
+
+ Test: accessibility/mac/text-marker-word-nav.html
+
+ * accessibility/AXObjectCache.cpp:
+ (WebCore::AXObjectCache::traverseToOffsetInRange):
+ (WebCore::AXObjectCache::rangeForNodeContents):
+ (WebCore::isReplacedNodeOrBR):
+ (WebCore::characterOffsetsInOrder):
+ (WebCore::resetNodeAndOffsetForReplacedNode):
+ (WebCore::setRangeStartOrEndWithCharacterOffset):
+ (WebCore::AXObjectCache::rangeForUnorderedCharacterOffsets):
+ (WebCore::AXObjectCache::setTextMarkerDataWithCharacterOffset):
+ (WebCore::AXObjectCache::startOrEndCharacterOffsetForRange):
+ (WebCore::AXObjectCache::startOrEndTextMarkerDataForRange):
+ (WebCore::AXObjectCache::characterOffsetForNodeAndOffset):
+ (WebCore::AXObjectCache::textMarkerDataForCharacterOffset):
+ (WebCore::AXObjectCache::previousNode):
+ (WebCore::AXObjectCache::visiblePositionFromCharacterOffset):
+ (WebCore::AXObjectCache::characterOffsetFromVisiblePosition):
+ (WebCore::AXObjectCache::textMarkerDataForVisiblePosition):
+ (WebCore::AXObjectCache::nextCharacterOffset):
+ (WebCore::AXObjectCache::previousCharacterOffset):
+ (WebCore::startWordBoundary):
+ (WebCore::endWordBoundary):
+ (WebCore::AXObjectCache::startCharacterOffsetOfWord):
+ (WebCore::AXObjectCache::endCharacterOffsetOfWord):
+ (WebCore::AXObjectCache::previousWordStartCharacterOffset):
+ (WebCore::AXObjectCache::nextWordEndCharacterOffset):
+ (WebCore::AXObjectCache::leftWordRange):
+ (WebCore::AXObjectCache::rightWordRange):
+ (WebCore::characterForCharacterOffset):
+ (WebCore::AXObjectCache::characterAfter):
+ (WebCore::AXObjectCache::characterBefore):
+ (WebCore::parentEditingBoundary):
+ (WebCore::AXObjectCache::nextWordBoundary):
+ (WebCore::AXObjectCache::previousWordBoundary):
+ (WebCore::AXObjectCache::rootAXEditableElement):
+ * accessibility/AXObjectCache.h:
+ (WebCore::AXObjectCache::removeNodeForUse):
+ (WebCore::AXObjectCache::isNodeInUse):
+ * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+ (-[WebAccessibilityObjectWrapper previousTextMarkerForNode:offset:]):
+ (-[WebAccessibilityObjectWrapper textMarkerForNode:offset:ignoreStart:]):
+ (-[WebAccessibilityObjectWrapper textMarkerForNode:offset:]):
+ (textMarkerForCharacterOffset):
+ (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:forParameter:]):
+ * editing/VisibleUnits.cpp:
+ (WebCore::rightWordPosition):
+ (WebCore::prepend):
+ (WebCore::appendRepeatedCharacter):
+ (WebCore::suffixLengthForRange):
+ (WebCore::prefixLengthForRange):
+ (WebCore::backwardSearchForBoundaryWithTextIterator):
+ (WebCore::forwardSearchForBoundaryWithTextIterator):
+ (WebCore::previousBoundary):
+ (WebCore::nextBoundary):
+ * editing/VisibleUnits.h:
+
</ins><span class="cx"> 2016-02-09 Daniel Bates <dabates@apple.com>
</span><span class="cx">
</span><span class="cx"> CSP: Extract helper classes into their own files
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilityAXObjectCachecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -81,6 +81,7 @@
</span><span class="cx"> #include "RenderTableRow.h"
</span><span class="cx"> #include "RenderView.h"
</span><span class="cx"> #include "ScrollView.h"
</span><ins>+#include "TextBoundaries.h"
</ins><span class="cx"> #include "TextIterator.h"
</span><span class="cx"> #include <wtf/DataLog.h>
</span><span class="cx">
</span><span class="lines">@@ -1470,6 +1471,7 @@
</span><span class="cx">
</span><span class="cx"> for (; !iterator.atEnd(); iterator.advance()) {
</span><span class="cx"> int currentLength = iterator.text().length();
</span><ins>+ bool hasReplacedNodeOrBR = false;
</ins><span class="cx">
</span><span class="cx"> Node& node = iterator.range()->startContainer();
</span><span class="cx"> currentNode = &node;
</span><span class="lines">@@ -1482,17 +1484,28 @@
</span><span class="cx"> offsetSoFar++;
</span><span class="cx"> currentLength++;
</span><span class="cx"> currentNode = childNode;
</span><ins>+ hasReplacedNodeOrBR = true;
</ins><span class="cx"> } else
</span><span class="cx"> continue;
</span><span class="cx"> } else {
</span><span class="cx"> // Ignore space, new line, tag node.
</span><del>- if (currentLength == 1 && isSpaceOrNewline(iterator.text()[0]))
- continue;
</del><ins>+ if (currentLength == 1) {
+ if (isSpaceOrNewline(iterator.text()[0])) {
+ // If the node has BR tag, we want to set the currentNode to it.
+ int subOffset = iterator.range()->startOffset();
+ Node* childNode = node.traverseToChildAt(subOffset);
+ if (childNode && childNode->renderer() && childNode->renderer()->isBR()) {
+ currentNode = childNode;
+ hasReplacedNodeOrBR = true;
+ } else
+ continue;
+ }
+ }
</ins><span class="cx"> offsetSoFar += currentLength;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> lastLength = currentLength;
</span><del>- lastStartOffset = iterator.range()->startOffset();
</del><ins>+ lastStartOffset = hasReplacedNodeOrBR ? 0 : iterator.range()->startOffset();
</ins><span class="cx">
</span><span class="cx"> // Break early if we have advanced enough characters.
</span><span class="cx"> if (!toNodeEnd && offsetSoFar >= offset) {
</span><span class="lines">@@ -1546,6 +1559,11 @@
</span><span class="cx"> range->selectNodeContents(node, ec);
</span><span class="cx"> return ec ? nullptr : range;
</span><span class="cx"> }
</span><ins>+
+static bool isReplacedNodeOrBR(Node* node)
+{
+ return node && (AccessibilityObject::replacedNodeNeedsCharacter(node) || node->hasTagName(brTag));
+}
</ins><span class="cx">
</span><span class="cx"> static bool characterOffsetsInOrder(const CharacterOffset& characterOffset1, const CharacterOffset& characterOffset2)
</span><span class="cx"> {
</span><span class="lines">@@ -1555,8 +1573,18 @@
</span><span class="cx"> if (characterOffset1.node == characterOffset2.node)
</span><span class="cx"> return characterOffset1.offset <= characterOffset2.offset;
</span><span class="cx">
</span><del>- RefPtr<Range> range1 = AXObjectCache::rangeForNodeContents(characterOffset1.node);
- RefPtr<Range> range2 = AXObjectCache::rangeForNodeContents(characterOffset2.node);
</del><ins>+ Node* node1 = characterOffset1.node;
+ Node* node2 = characterOffset2.node;
+ if (!node1->offsetInCharacters() && !isReplacedNodeOrBR(node1))
+ node1 = node1->traverseToChildAt(characterOffset1.offset);
+ if (!node2->offsetInCharacters() && !isReplacedNodeOrBR(node2))
+ node2 = node2->traverseToChildAt(characterOffset2.offset);
+
+ if (!node1 || !node2)
+ return false;
+
+ RefPtr<Range> range1 = AXObjectCache::rangeForNodeContents(node1);
+ RefPtr<Range> range2 = AXObjectCache::rangeForNodeContents(node2);
</ins><span class="cx"> return range1->compareBoundaryPoints(Range::START_TO_START, range2.get(), IGNORE_EXCEPTION) <= 0;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -1572,9 +1600,26 @@
</span><span class="cx"> return replacedNode->parentNode();
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static bool isReplacedNodeOrBR(Node* node)
</del><ins>+static void setRangeStartOrEndWithCharacterOffset(RefPtr<Range> range, CharacterOffset& characterOffset, bool isStart, ExceptionCode& ec)
</ins><span class="cx"> {
</span><del>- return AccessibilityObject::replacedNodeNeedsCharacter(node) || node->hasTagName(brTag);
</del><ins>+ if (!range) {
+ ec = RangeError;
+ return;
+ }
+ if (characterOffset.isNull()) {
+ ec = TypeError;
+ return;
+ }
+
+ int offset = characterOffset.startIndex + characterOffset.offset;
+ Node* node = characterOffset.node;
+ if (isReplacedNodeOrBR(node))
+ node = resetNodeAndOffsetForReplacedNode(node, offset, characterOffset.offset);
+
+ if (isStart)
+ range->setStart(node, offset, ec);
+ else
+ range->setEnd(node, offset, ec);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> RefPtr<Range> AXObjectCache::rangeForUnorderedCharacterOffsets(const CharacterOffset& characterOffset1, const CharacterOffset& characterOffset2)
</span><span class="lines">@@ -1586,34 +1631,11 @@
</span><span class="cx"> CharacterOffset startCharacterOffset = alreadyInOrder ? characterOffset1 : characterOffset2;
</span><span class="cx"> CharacterOffset endCharacterOffset = alreadyInOrder ? characterOffset2 : characterOffset1;
</span><span class="cx">
</span><del>- int startOffset = startCharacterOffset.startIndex + startCharacterOffset.offset;
- int endOffset = endCharacterOffset.startIndex + endCharacterOffset.offset;
- Node* startNode = startCharacterOffset.node;
- Node* endNode = endCharacterOffset.node;
-
- // Consider the case when the replaced node is at the start/end of the range.
- bool startNodeIsReplacedOrBR = isReplacedNodeOrBR(startNode);
- bool endNodeIsReplacedOrBR = isReplacedNodeOrBR(endNode);
- if (startNodeIsReplacedOrBR || endNodeIsReplacedOrBR) {
- // endOffset can be out of bounds sometimes if the node is a replaced node or has brTag and it has no children.
- if (startNode == endNode && !startNode->hasChildNodes()) {
- RefPtr<Range> nodeRange = AXObjectCache::rangeForNodeContents(startNode);
- int nodeLength = TextIterator::rangeLength(nodeRange.get());
- if (endCharacterOffset.offset > nodeLength)
- endOffset = endCharacterOffset.startIndex + nodeLength;
- } else {
- if (startNodeIsReplacedOrBR)
- startNode = resetNodeAndOffsetForReplacedNode(startNode, startOffset, startCharacterOffset.offset);
- if (endNodeIsReplacedOrBR)
- endNode = resetNodeAndOffsetForReplacedNode(startNode, endOffset, startCharacterOffset.offset);
- }
- }
-
</del><span class="cx"> RefPtr<Range> result = Range::create(m_document);
</span><del>- ExceptionCode ecStart = 0, ecEnd = 0;
- result->setStart(startNode, startOffset, ecStart);
- result->setEnd(endNode, endOffset, ecEnd);
- if (ecStart || ecEnd)
</del><ins>+ ExceptionCode ec = 0;
+ setRangeStartOrEndWithCharacterOffset(result, startCharacterOffset, true, ec);
+ setRangeStartOrEndWithCharacterOffset(result, endCharacterOffset, false, ec);
+ if (ec)
</ins><span class="cx"> return nullptr;
</span><span class="cx">
</span><span class="cx"> return result;
</span><span class="lines">@@ -1635,7 +1657,7 @@
</span><span class="cx"> return;
</span><span class="cx">
</span><span class="cx"> // Convert to visible position.
</span><del>- VisiblePosition visiblePosition = visiblePositionFromCharacterOffset(obj.get(), characterOffset);
</del><ins>+ VisiblePosition visiblePosition = visiblePositionFromCharacterOffset(characterOffset);
</ins><span class="cx"> int vpOffset = 0;
</span><span class="cx"> if (!visiblePosition.isNull()) {
</span><span class="cx"> Position deepPos = visiblePosition.deepEquivalent();
</span><span class="lines">@@ -1652,53 +1674,64 @@
</span><span class="cx"> this->setNodeInUse(domNode);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void AXObjectCache::startOrEndTextMarkerDataForRange(TextMarkerData& textMarkerData, RefPtr<Range> range, bool isStart)
</del><ins>+CharacterOffset AXObjectCache::startOrEndCharacterOffsetForRange(RefPtr<Range> range, bool isStart)
</ins><span class="cx"> {
</span><del>- memset(&textMarkerData, 0, sizeof(TextMarkerData));
-
</del><span class="cx"> if (!range)
</span><del>- return;
</del><ins>+ return CharacterOffset();
</ins><span class="cx">
</span><span class="cx"> // If it's end text marker, we want to go to the end of the range, and stay within the range.
</span><span class="cx"> bool stayWithinRange = !isStart;
</span><span class="cx">
</span><ins>+ RefPtr<Range> copyRange = range;
</ins><span class="cx"> // Change the start of the range, so the character offset starts from node beginning.
</span><span class="cx"> int offset = 0;
</span><del>- Node* node = &range->startContainer();
</del><ins>+ Node* node = &copyRange->startContainer();
</ins><span class="cx"> if (node->offsetInCharacters()) {
</span><ins>+ copyRange = Range::create(range->ownerDocument(), &range->startContainer(), range->startOffset(), &range->endContainer(), range->endOffset());
</ins><span class="cx"> CharacterOffset nodeStartOffset = traverseToOffsetInRange(rangeForNodeContents(node), 0, false);
</span><del>- offset = std::max(range->startOffset() - nodeStartOffset.startIndex, 0);
- range->setStart(node, nodeStartOffset.startIndex);
</del><ins>+ offset = std::max(copyRange->startOffset() - nodeStartOffset.startIndex, 0);
+ copyRange->setStart(node, nodeStartOffset.startIndex);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- CharacterOffset characterOffset = traverseToOffsetInRange(range, offset, !isStart, stayWithinRange);
- setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
</del><ins>+ return traverseToOffsetInRange(copyRange, offset, !isStart, stayWithinRange);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-void AXObjectCache::textMarkerDataForCharacterOffset(TextMarkerData& textMarkerData, Node& node, int offset, bool toNodeEnd)
</del><ins>+void AXObjectCache::startOrEndTextMarkerDataForRange(TextMarkerData& textMarkerData, RefPtr<Range> range, bool isStart)
</ins><span class="cx"> {
</span><span class="cx"> memset(&textMarkerData, 0, sizeof(TextMarkerData));
</span><span class="cx">
</span><ins>+ CharacterOffset characterOffset = startOrEndCharacterOffsetForRange(range, isStart);
+ if (characterOffset.isNull())
+ return;
+
+ setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
+}
+
+CharacterOffset AXObjectCache::characterOffsetForNodeAndOffset(Node& node, int offset, bool toNodeEnd, bool ignoreStart)
+{
</ins><span class="cx"> Node* domNode = &node;
</span><span class="cx"> if (!domNode)
</span><del>- return;
</del><ins>+ return CharacterOffset();
</ins><span class="cx">
</span><del>- // If offset <= 0, means we want to go to the previous node.
- if (offset <= 0 && !toNodeEnd) {
</del><ins>+ // ignoreStart is used to determine if we should go to previous node or
+ // stay in current node when offset is 0.
+ if (!toNodeEnd && (offset < 0 || (!offset && ignoreStart))) {
</ins><span class="cx"> // Set the offset to the amount of characters we need to go backwards.
</span><del>- offset = - offset + 1;
- while (offset > 0 && textMarkerData.characterOffset <= offset) {
- offset -= textMarkerData.characterOffset;
</del><ins>+ offset = - offset;
+ CharacterOffset charOffset = CharacterOffset();
+ while (offset >= 0 && charOffset.offset <= offset) {
+ offset -= charOffset.offset;
</ins><span class="cx"> domNode = previousNode(domNode);
</span><span class="cx"> if (domNode) {
</span><del>- textMarkerDataForCharacterOffset(textMarkerData, *domNode, 0, true);
- offset--;
</del><ins>+ charOffset = characterOffsetForNodeAndOffset(*domNode, 0, true);
</ins><span class="cx"> } else
</span><del>- return;
</del><ins>+ return CharacterOffset();
+ if (!offset)
+ break;
</ins><span class="cx"> }
</span><span class="cx"> if (offset > 0)
</span><del>- textMarkerDataForCharacterOffset(textMarkerData, *domNode, offset, false);
- return;
</del><ins>+ charOffset = characterOffsetForNodeAndOffset(*charOffset.node, charOffset.offset - offset, false);
+ return charOffset;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> RefPtr<Range> range = rangeForNodeContents(domNode);
</span><span class="lines">@@ -1709,11 +1742,19 @@
</span><span class="cx"> while (!characterOffset.isNull() && characterOffset.remaining() && !toNodeEnd) {
</span><span class="cx"> domNode = nextNode(domNode);
</span><span class="cx"> if (!domNode)
</span><del>- return;
</del><ins>+ return CharacterOffset();
</ins><span class="cx"> range = rangeForNodeContents(domNode);
</span><span class="cx"> characterOffset = traverseToOffsetInRange(range, characterOffset.remaining(), toNodeEnd);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ return characterOffset;
+}
+
+void AXObjectCache::textMarkerDataForCharacterOffset(TextMarkerData& textMarkerData, Node& node, int offset, bool toNodeEnd, bool ignoreStart)
+{
+ memset(&textMarkerData, 0, sizeof(TextMarkerData));
+
+ CharacterOffset characterOffset = characterOffsetForNodeAndOffset(node, offset, toNodeEnd, ignoreStart);
</ins><span class="cx"> setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -1737,8 +1778,12 @@
</span><span class="cx"> return NodeTraversal::previousSkippingChildren(*node);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-VisiblePosition AXObjectCache::visiblePositionFromCharacterOffset(AccessibilityObject* obj, const CharacterOffset& characterOffset)
</del><ins>+VisiblePosition AXObjectCache::visiblePositionFromCharacterOffset(const CharacterOffset& characterOffset)
</ins><span class="cx"> {
</span><ins>+ if (characterOffset.isNull())
+ return VisiblePosition();
+
+ RefPtr<AccessibilityObject> obj = this->getOrCreate(characterOffset.node);
</ins><span class="cx"> if (!obj)
</span><span class="cx"> return VisiblePosition();
</span><span class="cx">
</span><span class="lines">@@ -1752,13 +1797,20 @@
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-CharacterOffset AXObjectCache::characterOffsetFromVisiblePosition(AccessibilityObject* obj, const VisiblePosition& visiblePos)
</del><ins>+CharacterOffset AXObjectCache::characterOffsetFromVisiblePosition(const VisiblePosition& visiblePos)
</ins><span class="cx"> {
</span><ins>+ if (visiblePos.isNull())
+ return CharacterOffset();
+
+ Position deepPos = visiblePos.deepEquivalent();
+ Node* domNode = deepPos.deprecatedNode();
+ ASSERT(domNode);
+
+ RefPtr<AccessibilityObject> obj = this->getOrCreate(domNode);
</ins><span class="cx"> if (!obj)
</span><del>- return 0;
</del><ins>+ return CharacterOffset();
</ins><span class="cx">
</span><span class="cx"> // Use nextVisiblePosition to calculate how many characters we need to traverse to the current position.
</span><del>- Position deepPos = visiblePos.deepEquivalent();
</del><span class="cx"> VisiblePositionRange vpRange = obj->visiblePositionRange();
</span><span class="cx"> VisiblePosition vp = vpRange.start;
</span><span class="cx"> int characterOffset = 0;
</span><span class="lines">@@ -1816,13 +1868,256 @@
</span><span class="cx"> textMarkerData.affinity = visiblePos.affinity();
</span><span class="cx">
</span><span class="cx"> // convert to character offset
</span><del>- CharacterOffset characterOffset = characterOffsetFromVisiblePosition(obj.get(), visiblePos);
</del><ins>+ CharacterOffset characterOffset = characterOffsetFromVisiblePosition(visiblePos);
</ins><span class="cx"> textMarkerData.characterOffset = characterOffset.offset;
</span><span class="cx"> textMarkerData.characterStartIndex = characterOffset.startIndex;
</span><span class="cx">
</span><span class="cx"> cache->setNodeInUse(domNode);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+CharacterOffset AXObjectCache::nextCharacterOffset(const CharacterOffset& characterOffset)
+{
+ if (characterOffset.isNull())
+ return CharacterOffset();
+
+ return characterOffsetForNodeAndOffset(*characterOffset.node, characterOffset.offset + 1);
+}
+
+CharacterOffset AXObjectCache::previousCharacterOffset(const CharacterOffset& characterOffset)
+{
+ if (characterOffset.isNull())
+ return CharacterOffset();
+
+ return characterOffsetForNodeAndOffset(*characterOffset.node, characterOffset.offset - 1, false, false);
+}
+
+static unsigned startWordBoundary(StringView text, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
+{
+ ASSERT(offset);
+ if (mayHaveMoreContext && !startOfLastWordBoundaryContext(text.substring(0, offset))) {
+ needMoreContext = true;
+ return 0;
+ }
+ needMoreContext = false;
+ int start, end;
+ U16_BACK_1(text, 0, offset);
+ findWordBoundary(text, offset, &start, &end);
+ return start;
+}
+
+static unsigned endWordBoundary(StringView text, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
+{
+ ASSERT(offset <= text.length());
+ if (mayHaveMoreContext && endOfFirstWordBoundaryContext(text.substring(offset)) == text.length() - offset) {
+ needMoreContext = true;
+ return text.length();
+ }
+ needMoreContext = false;
+ int end;
+ findEndWordBoundary(text, offset, &end);
+ return end;
+}
+
+CharacterOffset AXObjectCache::startCharacterOffsetOfWord(const CharacterOffset& characterOffset, EWordSide side)
+{
+ if (characterOffset.isNull())
+ return CharacterOffset();
+
+ CharacterOffset c = characterOffset;
+ if (side == RightWordIfOnBoundary) {
+ // FIXME: need to remove this when isEndOfParagraph is implemented for CharacterOffset.
+ VisiblePosition vp = visiblePositionFromCharacterOffset(c);
+ if (isEndOfParagraph(vp))
+ return c;
+
+ c = nextCharacterOffset(characterOffset);
+ if (c.isNull())
+ return characterOffset;
+ }
+
+ return previousWordBoundary(c, startWordBoundary);
+}
+
+CharacterOffset AXObjectCache::endCharacterOffsetOfWord(const CharacterOffset& characterOffset, EWordSide side)
+{
+ if (characterOffset.isNull())
+ return CharacterOffset();
+
+ CharacterOffset c = characterOffset;
+ if (side == LeftWordIfOnBoundary) {
+ // FIXME: need to remove this when isStartOfParagraph is implemented for CharacterOffset.
+ VisiblePosition vp = visiblePositionFromCharacterOffset(c);
+ if (isStartOfParagraph(vp))
+ return c;
+
+ c = previousCharacterOffset(characterOffset);
+ if (c.isNull())
+ return characterOffset;
+ }
+
+ return nextWordBoundary(c, endWordBoundary);
+}
+
+CharacterOffset AXObjectCache::previousWordStartCharacterOffset(const CharacterOffset& characterOffset)
+{
+ if (characterOffset.isNull())
+ return CharacterOffset();
+
+ CharacterOffset previousOffset = previousCharacterOffset(characterOffset);
+ if (previousOffset.isNull())
+ return CharacterOffset();
+
+ return startCharacterOffsetOfWord(previousOffset, RightWordIfOnBoundary);
+}
+
+CharacterOffset AXObjectCache::nextWordEndCharacterOffset(const CharacterOffset& characterOffset)
+{
+ if (characterOffset.isNull())
+ return CharacterOffset();
+
+ CharacterOffset nextOffset = nextCharacterOffset(characterOffset);
+ if (nextOffset.isNull())
+ return CharacterOffset();
+
+ return endCharacterOffsetOfWord(nextOffset, LeftWordIfOnBoundary);
+}
+
+RefPtr<Range> AXObjectCache::leftWordRange(const CharacterOffset& characterOffset)
+{
+ CharacterOffset start = previousWordStartCharacterOffset(characterOffset);
+ CharacterOffset end = endCharacterOffsetOfWord(start);
+ return rangeForUnorderedCharacterOffsets(start, end);
+}
+
+RefPtr<Range> AXObjectCache::rightWordRange(const CharacterOffset& characterOffset)
+{
+ CharacterOffset start = startCharacterOffsetOfWord(characterOffset);
+ CharacterOffset end = nextWordEndCharacterOffset(start);
+ return rangeForUnorderedCharacterOffsets(start, end);
+}
+
+static UChar32 characterForCharacterOffset(const CharacterOffset& characterOffset)
+{
+ if (characterOffset.isNull() || !characterOffset.node->isTextNode())
+ return 0;
+
+ UChar32 ch = 0;
+ unsigned offset = characterOffset.startIndex + characterOffset.offset;
+ if (offset < characterOffset.node->textContent().length())
+ U16_NEXT(characterOffset.node->textContent(), offset, characterOffset.node->textContent().length(), ch);
+ return ch;
+}
+
+UChar32 AXObjectCache::characterAfter(const CharacterOffset& characterOffset)
+{
+ return characterForCharacterOffset(nextCharacterOffset(characterOffset));
+}
+
+UChar32 AXObjectCache::characterBefore(const CharacterOffset& characterOffset)
+{
+ return characterForCharacterOffset(characterOffset);
+}
+
+static Node* parentEditingBoundary(Node* node)
+{
+ if (!node)
+ return nullptr;
+
+ Node* documentElement = node->document().documentElement();
+ if (!documentElement)
+ return nullptr;
+
+ Node* boundary = node;
+ while (boundary != documentElement && boundary->nonShadowBoundaryParentNode() && node->hasEditableStyle() == boundary->parentNode()->hasEditableStyle())
+ boundary = boundary->nonShadowBoundaryParentNode();
+
+ return boundary;
+}
+
+CharacterOffset AXObjectCache::nextWordBoundary(CharacterOffset& characterOffset, BoundarySearchFunction searchFunction)
+{
+ if (characterOffset.isNull())
+ return CharacterOffset();
+
+ Node* boundary = parentEditingBoundary(characterOffset.node);
+ if (!boundary)
+ return CharacterOffset();
+
+ RefPtr<Range> searchRange = rangeForNodeContents(boundary);
+ Vector<UChar, 1024> string;
+ unsigned prefixLength = 0;
+
+ ExceptionCode ec = 0;
+ if (requiresContextForWordBoundary(characterAfter(characterOffset))) {
+ RefPtr<Range> backwardsScanRange(boundary->document().createRange());
+ setRangeStartOrEndWithCharacterOffset(backwardsScanRange, characterOffset, false, ec);
+ prefixLength = prefixLengthForRange(backwardsScanRange, string);
+ }
+
+ setRangeStartOrEndWithCharacterOffset(searchRange, characterOffset, true, ec);
+ CharacterOffset end = startOrEndCharacterOffsetForRange(searchRange, false);
+
+ ASSERT(!ec);
+ if (ec)
+ return CharacterOffset();
+
+ TextIterator it(searchRange.get(), TextIteratorEmitsObjectReplacementCharacters);
+ unsigned next = forwardSearchForBoundaryWithTextIterator(it, string, prefixLength, searchFunction);
+
+ if (it.atEnd() && next == string.size())
+ return end;
+ if (next > prefixLength)
+ return characterOffsetForNodeAndOffset(*characterOffset.node, characterOffset.offset + next - prefixLength);
+
+ return characterOffset;
+}
+
+CharacterOffset AXObjectCache::previousWordBoundary(CharacterOffset& characterOffset, BoundarySearchFunction searchFunction)
+{
+ if (characterOffset.isNull())
+ return CharacterOffset();
+
+ Node* boundary = parentEditingBoundary(characterOffset.node);
+ if (!boundary)
+ return CharacterOffset();
+
+ RefPtr<Range> searchRange = rangeForNodeContents(boundary);
+ Vector<UChar, 1024> string;
+ unsigned suffixLength = 0;
+
+ ExceptionCode ec = 0;
+ if (requiresContextForWordBoundary(characterBefore(characterOffset))) {
+ RefPtr<Range> forwardsScanRange(boundary->document().createRange());
+ forwardsScanRange->setEndAfter(boundary, ec);
+ setRangeStartOrEndWithCharacterOffset(forwardsScanRange, characterOffset, true, ec);
+ suffixLength = suffixLengthForRange(forwardsScanRange, string);
+ }
+
+ setRangeStartOrEndWithCharacterOffset(searchRange, characterOffset, false, ec);
+ CharacterOffset start = startOrEndCharacterOffsetForRange(searchRange, true);
+
+ ASSERT(!ec);
+ if (ec)
+ return CharacterOffset();
+
+ SimplifiedBackwardsTextIterator it(*searchRange);
+ unsigned next = backwardSearchForBoundaryWithTextIterator(it, string, suffixLength, searchFunction);
+
+ if (!next)
+ return it.atEnd() ? start : characterOffset;
+
+ Node& node = it.atEnd() ? searchRange->startContainer() : it.range()->startContainer();
+ if ((node.isTextNode() && static_cast<int>(next) <= node.maxCharacterOffset()) || (node.renderer() && node.renderer()->isBR() && !next)) {
+ // The next variable contains a usable index into a text node
+ if (&node == characterOffset.node)
+ next -= characterOffset.startIndex;
+ return characterOffsetForNodeAndOffset(node, next, false);
+ }
+
+ int characterCount = characterOffset.offset - (string.size() - suffixLength - next);
+ return characterOffsetForNodeAndOffset(*characterOffset.node, characterCount, false, false);
+}
+
</ins><span class="cx"> const Element* AXObjectCache::rootAXEditableElement(const Node* node)
</span><span class="cx"> {
</span><span class="cx"> const Element* result = node->rootEditableElement();
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilityAXObjectCacheh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/AXObjectCache.h (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/accessibility/AXObjectCache.h        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.h        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> #include "AccessibilityObject.h"
</span><span class="cx"> #include "Range.h"
</span><span class="cx"> #include "Timer.h"
</span><ins>+#include "VisibleUnits.h"
</ins><span class="cx"> #include <limits.h>
</span><span class="cx"> #include <wtf/Forward.h>
</span><span class="cx"> #include <wtf/HashMap.h>
</span><span class="lines">@@ -186,12 +187,20 @@
</span><span class="cx"> void textMarkerDataForVisiblePosition(TextMarkerData&, const VisiblePosition&);
</span><span class="cx"> VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&);
</span><span class="cx"> CharacterOffset characterOffsetForTextMarkerData(TextMarkerData&);
</span><del>- void textMarkerDataForCharacterOffset(TextMarkerData&, Node&, int, bool toNodeEnd = false);
</del><ins>+ void textMarkerDataForCharacterOffset(TextMarkerData&, Node&, int, bool toNodeEnd = false, bool ignoreStart = true);
</ins><span class="cx"> void startOrEndTextMarkerDataForRange(TextMarkerData&, RefPtr<Range>, bool);
</span><span class="cx"> AccessibilityObject* accessibilityObjectForTextMarkerData(TextMarkerData&);
</span><span class="cx"> RefPtr<Range> rangeForUnorderedCharacterOffsets(const CharacterOffset&, const CharacterOffset&);
</span><span class="cx"> static RefPtr<Range> rangeForNodeContents(Node*);
</span><span class="cx"> static int lengthForRange(Range*);
</span><ins>+
+ // Word boundary
+ CharacterOffset startCharacterOffsetOfWord(const CharacterOffset&, EWordSide = RightWordIfOnBoundary);
+ CharacterOffset endCharacterOffsetOfWord(const CharacterOffset&, EWordSide = RightWordIfOnBoundary);
+ CharacterOffset nextWordEndCharacterOffset(const CharacterOffset&);
+ CharacterOffset previousWordStartCharacterOffset(const CharacterOffset&);
+ RefPtr<Range> leftWordRange(const CharacterOffset&);
+ RefPtr<Range> rightWordRange(const CharacterOffset&);
</ins><span class="cx">
</span><span class="cx"> enum AXNotification {
</span><span class="cx"> AXActiveDescendantChanged,
</span><span class="lines">@@ -283,12 +292,21 @@
</span><span class="cx"> void removeNodeForUse(Node* n) { m_textMarkerNodes.remove(n); }
</span><span class="cx"> bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); }
</span><span class="cx">
</span><ins>+ // CharacterOffset functions.
</ins><span class="cx"> Node* nextNode(Node*) const;
</span><span class="cx"> Node* previousNode(Node*) const;
</span><span class="cx"> CharacterOffset traverseToOffsetInRange(RefPtr<Range>, int, bool, bool stayWithinRange = false);
</span><del>- VisiblePosition visiblePositionFromCharacterOffset(AccessibilityObject*, const CharacterOffset&);
- CharacterOffset characterOffsetFromVisiblePosition(AccessibilityObject*, const VisiblePosition&);
</del><ins>+ VisiblePosition visiblePositionFromCharacterOffset(const CharacterOffset&);
+ CharacterOffset characterOffsetFromVisiblePosition(const VisiblePosition&);
</ins><span class="cx"> void setTextMarkerDataWithCharacterOffset(TextMarkerData&, const CharacterOffset&);
</span><ins>+ UChar32 characterAfter(const CharacterOffset&);
+ UChar32 characterBefore(const CharacterOffset&);
+ CharacterOffset startOrEndCharacterOffsetForRange(RefPtr<Range>, bool);
+ CharacterOffset characterOffsetForNodeAndOffset(Node&, int, bool toNodeEnd = false, bool ignoreStart = true);
+ CharacterOffset nextCharacterOffset(const CharacterOffset&);
+ CharacterOffset previousCharacterOffset(const CharacterOffset&);
+ CharacterOffset previousWordBoundary(CharacterOffset&, BoundarySearchFunction);
+ CharacterOffset nextWordBoundary(CharacterOffset&, BoundarySearchFunction);
</ins><span class="cx">
</span><span class="cx"> private:
</span><span class="cx"> AccessibilityObject* rootWebArea();
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilitymacWebAccessibilityObjectWrapperMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -858,12 +858,17 @@
</span><span class="cx"> return textMarker;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+- (id)textMarkerForNode:(Node&)node offset:(int)offset ignoreStart:(BOOL)ignoreStart
+{
+ return textMarkerForCharacterOffset(m_object->axObjectCache(), node, offset, false, ignoreStart);
+}
+
</ins><span class="cx"> - (id)textMarkerForNode:(Node&)node offset:(int)offset
</span><span class="cx"> {
</span><del>- return textMarkerForCharacterOffset(m_object->axObjectCache(), node, offset);
</del><ins>+ return [self textMarkerForNode:node offset:offset ignoreStart:YES];
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-static id textMarkerForCharacterOffset(AXObjectCache* cache, Node& node, int offset, bool toNodeEnd = false)
</del><ins>+static id textMarkerForCharacterOffset(AXObjectCache* cache, Node& node, int offset, bool toNodeEnd, bool ignoreStart)
</ins><span class="cx"> {
</span><span class="cx"> if (!cache)
</span><span class="cx"> return nil;
</span><span class="lines">@@ -873,7 +878,7 @@
</span><span class="cx"> return nil;
</span><span class="cx">
</span><span class="cx"> TextMarkerData textMarkerData;
</span><del>- cache->textMarkerDataForCharacterOffset(textMarkerData, node, offset, toNodeEnd);
</del><ins>+ cache->textMarkerDataForCharacterOffset(textMarkerData, node, offset, toNodeEnd, ignoreStart);
</ins><span class="cx"> if (!textMarkerData.axID && !textMarkerData.ignored)
</span><span class="cx"> return nil;
</span><span class="cx">
</span><span class="lines">@@ -4070,15 +4075,21 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"]) {
</span><del>- VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
- VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos);
- return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
</del><ins>+ AXObjectCache* cache = m_object->axObjectCache();
+ if (!cache)
+ return nil;
+ CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
+ RefPtr<Range> range = cache->leftWordRange(characterOffset);
+ return [self textMarkerRangeFromRange:range];
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if ([attribute isEqualToString:@"AXRightWordTextMarkerRangeForTextMarker"]) {
</span><del>- VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
- VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos);
- return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
</del><ins>+ AXObjectCache* cache = m_object->axObjectCache();
+ if (!cache)
+ return nil;
+ CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
+ RefPtr<Range> range = cache->rightWordRange(characterOffset);
+ return [self textMarkerRangeFromRange:range];
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if ([attribute isEqualToString:@"AXLeftLineTextMarkerRangeForTextMarker"]) {
</span><span class="lines">@@ -4106,13 +4117,21 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if ([attribute isEqualToString:@"AXNextWordEndTextMarkerForTextMarker"]) {
</span><del>- VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
- return [self textMarkerForVisiblePosition:m_object->nextWordEnd(visiblePos)];
</del><ins>+ AXObjectCache* cache = m_object->axObjectCache();
+ if (!cache)
+ return nil;
+ CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
+ CharacterOffset nextEnd = cache->nextWordEndCharacterOffset(characterOffset);
+ return [self textMarkerForNode:*nextEnd.node offset:nextEnd.offset];
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if ([attribute isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) {
</span><del>- VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
- return [self textMarkerForVisiblePosition:m_object->previousWordStart(visiblePos)];
</del><ins>+ AXObjectCache* cache = m_object->axObjectCache();
+ if (!cache)
+ return nil;
+ CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
+ CharacterOffset previousStart = cache->previousWordStartCharacterOffset(characterOffset);
+ return [self textMarkerForNode:*previousStart.node offset:previousStart.offset ignoreStart:NO];
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if ([attribute isEqualToString:@"AXNextLineEndTextMarkerForTextMarker"]) {
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingVisibleUnitscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/VisibleUnits.cpp (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/VisibleUnits.cpp        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Source/WebCore/editing/VisibleUnits.cpp        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -439,10 +439,6 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx">
</span><del>-enum BoundarySearchContextAvailability { DontHaveMoreContext, MayHaveMoreContext };
-
-typedef unsigned (*BoundarySearchFunction)(StringView, unsigned offset, BoundarySearchContextAvailability, bool& needMoreContext);
-
</del><span class="cx"> static void prepend(Vector<UChar, 1024>& buffer, StringView string)
</span><span class="cx"> {
</span><span class="cx"> unsigned oldSize = buffer.size();
</span><span class="lines">@@ -470,6 +466,99 @@
</span><span class="cx"> buffer[oldSize + i] = character;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+unsigned suffixLengthForRange(RefPtr<Range> forwardsScanRange, Vector<UChar, 1024>& string)
+{
+ unsigned suffixLength = 0;
+ TextIterator forwardsIterator(forwardsScanRange.get());
+ while (!forwardsIterator.atEnd()) {
+ StringView text = forwardsIterator.text();
+ unsigned i = endOfFirstWordBoundaryContext(text);
+ append(string, text.substring(0, i));
+ suffixLength += i;
+ if (i < text.length())
+ break;
+ forwardsIterator.advance();
+ }
+ return suffixLength;
+}
+
+unsigned prefixLengthForRange(RefPtr<Range> backwardsScanRange, Vector<UChar, 1024>& string)
+{
+ unsigned prefixLength = 0;
+ SimplifiedBackwardsTextIterator backwardsIterator(*backwardsScanRange);
+ while (!backwardsIterator.atEnd()) {
+ StringView text = backwardsIterator.text();
+ int i = startOfLastWordBoundaryContext(text);
+ prepend(string, text.substring(i));
+ prefixLength += text.length() - i;
+ if (i > 0)
+ break;
+ backwardsIterator.advance();
+ }
+ return prefixLength;
+}
+
+unsigned backwardSearchForBoundaryWithTextIterator(SimplifiedBackwardsTextIterator& it, Vector<UChar, 1024>& string, unsigned suffixLength, BoundarySearchFunction searchFunction)
+{
+ unsigned next = 0;
+ bool needMoreContext = false;
+ while (!it.atEnd()) {
+ bool inTextSecurityMode = it.node() && it.node()->renderer() && it.node()->renderer()->style().textSecurity() != TSNONE;
+ // iterate to get chunks until the searchFunction returns a non-zero value.
+ if (!inTextSecurityMode)
+ prepend(string, it.text());
+ else {
+ // Treat bullets used in the text security mode as regular characters when looking for boundaries
+ prependRepeatedCharacter(string, 'x', it.text().length());
+ }
+ if (string.size() > suffixLength) {
+ next = searchFunction(StringView(string.data(), string.size()), string.size() - suffixLength, MayHaveMoreContext, needMoreContext);
+ if (next > 1) // FIXME: This is a work around for https://webkit.org/b/115070. We need to provide more contexts in general case.
+ break;
+ }
+ it.advance();
+ }
+ if (needMoreContext && string.size() > suffixLength) {
+ // The last search returned the beginning of the buffer and asked for more context,
+ // but there is no earlier text. Force a search with what's available.
+ next = searchFunction(StringView(string.data(), string.size()), string.size() - suffixLength, DontHaveMoreContext, needMoreContext);
+ ASSERT(!needMoreContext);
+ }
+
+ return next;
+}
+
+unsigned forwardSearchForBoundaryWithTextIterator(TextIterator& it, Vector<UChar, 1024>& string, unsigned prefixLength, BoundarySearchFunction searchFunction)
+{
+ unsigned next = 0;
+ bool needMoreContext = false;
+ while (!it.atEnd()) {
+ bool inTextSecurityMode = it.node() && it.node()->renderer() && it.node()->renderer()->style().textSecurity() != TSNONE;
+ // Keep asking the iterator for chunks until the search function
+ // returns an end value not equal to the length of the string passed to it.
+ if (!inTextSecurityMode)
+ append(string, it.text());
+ else {
+ // Treat bullets used in the text security mode as regular characters when looking for boundaries
+ appendRepeatedCharacter(string, 'x', it.text().length());
+ }
+ if (string.size() > prefixLength) {
+ next = searchFunction(StringView(string.data(), string.size()), prefixLength, MayHaveMoreContext, needMoreContext);
+ if (next != string.size())
+ break;
+ }
+ it.advance();
+ }
+ if (needMoreContext && string.size() > prefixLength) {
+ // The last search returned the end of the buffer and asked for more context,
+ // but there is no further text. Force a search with what's available.
+ next = searchFunction(StringView(string.data(), string.size()), prefixLength, DontHaveMoreContext, needMoreContext);
+ ASSERT(!needMoreContext);
+ }
+
+ return next;
+}
+
</ins><span class="cx"> static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction)
</span><span class="cx"> {
</span><span class="cx"> Position pos = c.deepEquivalent();
</span><span class="lines">@@ -490,16 +579,7 @@
</span><span class="cx"> RefPtr<Range> forwardsScanRange(boundaryDocument.createRange());
</span><span class="cx"> forwardsScanRange->setEndAfter(boundary, ec);
</span><span class="cx"> forwardsScanRange->setStart(end.deprecatedNode(), end.deprecatedEditingOffset(), ec);
</span><del>- TextIterator forwardsIterator(forwardsScanRange.get());
- while (!forwardsIterator.atEnd()) {
- StringView text = forwardsIterator.text();
- unsigned i = endOfFirstWordBoundaryContext(text);
- append(string, text.substring(0, i));
- suffixLength += i;
- if (i < text.length())
- break;
- forwardsIterator.advance();
- }
</del><ins>+ suffixLength = suffixLengthForRange(forwardsScanRange, string);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), ec);
</span><span class="lines">@@ -510,30 +590,7 @@
</span><span class="cx"> return VisiblePosition();
</span><span class="cx">
</span><span class="cx"> SimplifiedBackwardsTextIterator it(*searchRange);
</span><del>- unsigned next = 0;
- bool needMoreContext = false;
- while (!it.atEnd()) {
- bool inTextSecurityMode = it.node() && it.node()->renderer() && it.node()->renderer()->style().textSecurity() != TSNONE;
- // iterate to get chunks until the searchFunction returns a non-zero value.
- if (!inTextSecurityMode)
- prepend(string, it.text());
- else {
- // Treat bullets used in the text security mode as regular characters when looking for boundaries
- prependRepeatedCharacter(string, 'x', it.text().length());
- }
- if (string.size() > suffixLength) {
- next = searchFunction(StringView(string.data(), string.size()), string.size() - suffixLength, MayHaveMoreContext, needMoreContext);
- if (next > 1) // FIXME: This is a work around for https://webkit.org/b/115070. We need to provide more contexts in general case.
- break;
- }
- it.advance();
- }
- if (needMoreContext && string.size() > suffixLength) {
- // The last search returned the beginning of the buffer and asked for more context,
- // but there is no earlier text. Force a search with what's available.
- next = searchFunction(StringView(string.data(), string.size()), string.size() - suffixLength, DontHaveMoreContext, needMoreContext);
- ASSERT(!needMoreContext);
- }
</del><ins>+ unsigned next = backwardSearchForBoundaryWithTextIterator(it, string, suffixLength, searchFunction);
</ins><span class="cx">
</span><span class="cx"> if (!next)
</span><span class="cx"> return VisiblePosition(it.atEnd() ? searchRange->startPosition() : pos, DOWNSTREAM);
</span><span class="lines">@@ -568,46 +625,13 @@
</span><span class="cx"> if (requiresContextForWordBoundary(c.characterAfter())) {
</span><span class="cx"> RefPtr<Range> backwardsScanRange(boundaryDocument.createRange());
</span><span class="cx"> backwardsScanRange->setEnd(start.deprecatedNode(), start.deprecatedEditingOffset(), IGNORE_EXCEPTION);
</span><del>- SimplifiedBackwardsTextIterator backwardsIterator(*backwardsScanRange);
- while (!backwardsIterator.atEnd()) {
- StringView text = backwardsIterator.text();
- int i = startOfLastWordBoundaryContext(text);
- prepend(string, text.substring(i));
- prefixLength += text.length() - i;
- if (i > 0)
- break;
- backwardsIterator.advance();
- }
</del><ins>+ prefixLength = prefixLengthForRange(backwardsScanRange, string);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> searchRange->selectNodeContents(boundary, IGNORE_EXCEPTION);
</span><span class="cx"> searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), IGNORE_EXCEPTION);
</span><span class="cx"> TextIterator it(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions);
</span><del>- unsigned next = 0;
- bool needMoreContext = false;
- while (!it.atEnd()) {
- bool inTextSecurityMode = it.node() && it.node()->renderer() && it.node()->renderer()->style().textSecurity() != TSNONE;
- // Keep asking the iterator for chunks until the search function
- // returns an end value not equal to the length of the string passed to it.
- if (!inTextSecurityMode)
- append(string, it.text());
- else {
- // Treat bullets used in the text security mode as regular characters when looking for boundaries
- appendRepeatedCharacter(string, 'x', it.text().length());
- }
- if (string.size() > prefixLength) {
- next = searchFunction(StringView(string.data(), string.size()), prefixLength, MayHaveMoreContext, needMoreContext);
- if (next != string.size())
- break;
- }
- it.advance();
- }
- if (needMoreContext && string.size() > prefixLength) {
- // The last search returned the end of the buffer and asked for more context,
- // but there is no further text. Force a search with what's available.
- next = searchFunction(StringView(string.data(), string.size()), prefixLength, DontHaveMoreContext, needMoreContext);
- ASSERT(!needMoreContext);
- }
</del><ins>+ unsigned next = forwardSearchForBoundaryWithTextIterator(it, string, prefixLength, searchFunction);
</ins><span class="cx">
</span><span class="cx"> if (it.atEnd() && next == string.size())
</span><span class="cx"> pos = searchRange->endPosition();
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingVisibleUnitsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/VisibleUnits.h (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/VisibleUnits.h        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Source/WebCore/editing/VisibleUnits.h        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -34,6 +34,8 @@
</span><span class="cx">
</span><span class="cx"> class Node;
</span><span class="cx"> class VisiblePosition;
</span><ins>+class SimplifiedBackwardsTextIterator;
+class TextIterator;
</ins><span class="cx">
</span><span class="cx"> enum EWordSide { RightWordIfOnBoundary = false, LeftWordIfOnBoundary = true };
</span><span class="cx">
</span><span class="lines">@@ -107,6 +109,14 @@
</span><span class="cx"> WEBCORE_EXPORT void charactersAroundPosition(const VisiblePosition&, UChar32& oneAfter, UChar32& oneBefore, UChar32& twoBefore);
</span><span class="cx"> WEBCORE_EXPORT PassRefPtr<Range> rangeExpandedAroundPositionByCharacters(const VisiblePosition&, int numberOfCharactersToExpand);
</span><span class="cx">
</span><ins>+// helper function
+enum BoundarySearchContextAvailability { DontHaveMoreContext, MayHaveMoreContext };
+typedef unsigned (*BoundarySearchFunction)(StringView, unsigned offset, BoundarySearchContextAvailability, bool& needMoreContext);
+unsigned suffixLengthForRange(RefPtr<Range>, Vector<UChar, 1024>&);
+unsigned prefixLengthForRange(RefPtr<Range>, Vector<UChar, 1024>&);
+unsigned backwardSearchForBoundaryWithTextIterator(SimplifiedBackwardsTextIterator&, Vector<UChar, 1024>&, unsigned, BoundarySearchFunction);
+unsigned forwardSearchForBoundaryWithTextIterator(TextIterator&, Vector<UChar, 1024>&, unsigned, BoundarySearchFunction);
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx">
</span><span class="cx"> #endif // VisibleUnits_h
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Tools/ChangeLog        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -1,3 +1,61 @@
</span><ins>+2016-02-09 Nan Wang <n_wang@apple.com>
+
+ AX: Implement word related text marker functions using TextIterator
+ https://bugs.webkit.org/show_bug.cgi?id=153939
+ <rdar://problem/24269605>
+
+ Reviewed by Chris Fleizach.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (endTextMarkerCallback):
+ (leftWordTextMarkerRangeForTextMarkerCallback):
+ (rightWordTextMarkerRangeForTextMarkerCallback):
+ (previousWordStartTextMarkerForTextMarkerCallback):
+ (nextWordEndTextMarkerForTextMarkerCallback):
+ (setSelectedVisibleTextRangeCallback):
+ (AccessibilityUIElement::setSelectedVisibleTextRange):
+ (AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
+ (AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
+ (AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
+ (AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/ios/AccessibilityUIElementIOS.mm:
+ (AccessibilityUIElement::setSelectedVisibleTextRange):
+ (AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
+ (AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
+ (AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
+ (AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::setSelectedVisibleTextRange):
+ (AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
+ (AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
+ (AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
+ (AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
+ (AccessibilityUIElement::supportedActions):
+ * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp:
+ (WTR::AccessibilityUIElement::setBoolAttributeValue):
+ (WTR::AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
+ (WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
+ (WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
+ (WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
+ * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
+ * WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl:
+ * WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm:
+ (WTR::AccessibilityUIElement::endTextMarker):
+ (WTR::AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
+ (WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
+ (WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
+ (WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
+ (WTR::AccessibilityUIElement::mathPostscriptsDescription):
+ * WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm:
+ (WTR::AccessibilityUIElement::endTextMarker):
+ (WTR::AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
+ (WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
+ (WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
+ (WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
+ (WTR::_convertMathMultiscriptPairsToString):
+
</ins><span class="cx"> 2016-02-09 Csaba Osztrogonác <ossy@webkit.org>
</span><span class="cx">
</span><span class="cx"> [EFL] Remove eail related cruft after r195725
</span></span></pre></div>
<a id="trunkToolsDumpRenderTreeAccessibilityUIElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/DumpRenderTree/AccessibilityUIElement.cpp (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/DumpRenderTree/AccessibilityUIElement.cpp        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Tools/DumpRenderTree/AccessibilityUIElement.cpp        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -974,6 +974,42 @@
</span><span class="cx"> return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->endTextMarker());
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+static JSValueRef leftWordTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->leftWordTextMarkerRangeForTextMarker(marker));
+}
+
+static JSValueRef rightWordTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->rightWordTextMarkerRangeForTextMarker(marker));
+}
+
+static JSValueRef previousWordStartTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->previousWordStartTextMarkerForTextMarker(marker));
+}
+
+static JSValueRef nextWordEndTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->nextWordEndTextMarkerForTextMarker(marker));
+}
+
</ins><span class="cx"> static JSValueRef setSelectedVisibleTextRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
</span><span class="cx"> {
</span><span class="cx"> AccessibilityUIElement* uiElement = toAXElement(thisObject);
</span><span class="lines">@@ -1564,6 +1600,26 @@
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+AccessibilityTextMarkerRange AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarkerRange AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
</ins><span class="cx"> #endif
</span><span class="cx">
</span><span class="cx"> // Destruction
</span><span class="lines">@@ -1744,6 +1800,10 @@
</span><span class="cx"> { "nextTextMarker", nextTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
</span><span class="cx"> { "previousTextMarker", previousTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
</span><span class="cx"> { "stringForTextMarkerRange", stringForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
</span><ins>+ { "leftWordTextMarkerRangeForTextMarker", leftWordTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "rightWordTextMarkerRangeForTextMarker", rightWordTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "previousWordStartTextMarkerForTextMarker", previousWordStartTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "nextWordEndTextMarkerForTextMarker", nextWordEndTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
</ins><span class="cx"> { "setSelectedChild", setSelectedChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
</span><span class="cx"> { "setSelectedChildAtIndex", setSelectedChildAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
</span><span class="cx"> { "removeSelectionAtIndex", removeSelectionAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
</span></span></pre></div>
<a id="trunkToolsDumpRenderTreeAccessibilityUIElementh"></a>
<div class="modfile"><h4>Modified: trunk/Tools/DumpRenderTree/AccessibilityUIElement.h (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/DumpRenderTree/AccessibilityUIElement.h        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Tools/DumpRenderTree/AccessibilityUIElement.h        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -260,6 +260,10 @@
</span><span class="cx"> AccessibilityUIElement accessibilityElementForTextMarker(AccessibilityTextMarker*);
</span><span class="cx"> AccessibilityTextMarker startTextMarker();
</span><span class="cx"> AccessibilityTextMarker endTextMarker();
</span><ins>+ AccessibilityTextMarkerRange leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*);
</ins><span class="cx"> AccessibilityTextMarkerRange selectedTextMarkerRange();
</span><span class="cx"> void resetSelectedTextMarkerRange();
</span><span class="cx"> bool setSelectedVisibleTextRange(AccessibilityTextMarkerRange*);
</span></span></pre></div>
<a id="trunkToolsDumpRenderTreeiosAccessibilityUIElementIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/DumpRenderTree/ios/AccessibilityUIElementIOS.mm (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/DumpRenderTree/ios/AccessibilityUIElementIOS.mm        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Tools/DumpRenderTree/ios/AccessibilityUIElementIOS.mm        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -550,6 +550,26 @@
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+AccessibilityTextMarkerRange AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarkerRange AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
</ins><span class="cx"> #endif // SUPPORTS_AX_TEXTMARKERS && PLATFORM(IOS)
</span><span class="cx">
</span><span class="cx"> #pragma mark Unused
</span></span></pre></div>
<a id="trunkToolsDumpRenderTreemacAccessibilityUIElementMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -1846,6 +1846,46 @@
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+AccessibilityTextMarkerRange AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id textMarkerRange = [m_element accessibilityAttributeValue:@"AXLeftWordTextMarkerRangeForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+ return AccessibilityTextMarkerRange(textMarkerRange);
+ END_AX_OBJC_EXCEPTIONS
+
+ return nullptr;
+}
+
+AccessibilityTextMarkerRange AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id textMarkerRange = [m_element accessibilityAttributeValue:@"AXRightWordTextMarkerRangeForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+ return AccessibilityTextMarkerRange(textMarkerRange);
+ END_AX_OBJC_EXCEPTIONS
+
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id previousTextMarker = [m_element accessibilityAttributeValue:@"AXPreviousWordStartTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+ return AccessibilityTextMarker(previousTextMarker);
+ END_AX_OBJC_EXCEPTIONS
+
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id nextTextMarker = [m_element accessibilityAttributeValue:@"AXNextWordEndTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+ return AccessibilityTextMarker(nextTextMarker);
+ END_AX_OBJC_EXCEPTIONS
+
+ return nullptr;
+}
+
</ins><span class="cx"> #endif // SUPPORTS_AX_TEXTMARKERS && PLATFORM(MAC)
</span><span class="cx">
</span><span class="cx"> JSStringRef AccessibilityUIElement::supportedActions()
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerInjectedBundleAccessibilityUIElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -244,5 +244,12 @@
</span><span class="cx"> void AccessibilityUIElement::setBoolAttributeValue(JSStringRef, bool) { }
</span><span class="cx"> #endif
</span><span class="cx">
</span><ins>+#if (!PLATFORM(MAC) && !PLATFORM(IOS)) || !HAVE(ACCESSIBILITY)
+PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+#endif
+
</ins><span class="cx"> } // namespace WTR
</span><span class="cx">
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerInjectedBundleAccessibilityUIElementh"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -251,6 +251,10 @@
</span><span class="cx"> PassRefPtr<AccessibilityTextMarker> startTextMarker();
</span><span class="cx"> PassRefPtr<AccessibilityTextMarker> endTextMarker();
</span><span class="cx"> bool setSelectedVisibleTextRange(AccessibilityTextMarkerRange*);
</span><ins>+ PassRefPtr<AccessibilityTextMarkerRange> leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ PassRefPtr<AccessibilityTextMarkerRange> rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ PassRefPtr<AccessibilityTextMarker> previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*);
+ PassRefPtr<AccessibilityTextMarker> nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*);
</ins><span class="cx">
</span><span class="cx"> // Returns an ordered list of supported actions for an element.
</span><span class="cx"> JSRetainPtr<JSStringRef> supportedActions() const;
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerInjectedBundleBindingsAccessibilityUIElementidl"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -201,6 +201,10 @@
</span><span class="cx"> readonly attribute AccessibilityTextMarker startTextMarker;
</span><span class="cx"> readonly attribute AccessibilityTextMarker endTextMarker;
</span><span class="cx"> boolean setSelectedVisibleTextRange(AccessibilityTextMarkerRange range);
</span><ins>+ AccessibilityTextMarkerRange leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
</ins><span class="cx">
</span><span class="cx"> // Returns an ordered list of supported actions for an element.
</span><span class="cx"> readonly attribute DOMString supportedActions;
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerInjectedBundleiosAccessibilityUIElementIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -1096,6 +1096,26 @@
</span><span class="cx"> return nullptr;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
+{
+ return nullptr;
+}
+
+PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
+{
+ return nullptr;
+}
+
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
+{
+ return nullptr;
+}
+
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
+{
+ return nullptr;
+}
+
</ins><span class="cx"> JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const
</span><span class="cx"> {
</span><span class="cx"> return 0;
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerInjectedBundlemacAccessibilityUIElementMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm (196351 => 196352)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm        2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm        2016-02-10 02:33:04 UTC (rev 196352)
</span><span class="lines">@@ -1873,6 +1873,46 @@
</span><span class="cx"> return nullptr;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id textMarkerRange = [m_element accessibilityAttributeValue:@"AXLeftWordTextMarkerRangeForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+ return AccessibilityTextMarkerRange::create(textMarkerRange);
+ END_AX_OBJC_EXCEPTIONS
+
+ return nullptr;
+}
+
+PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id textMarkerRange = [m_element accessibilityAttributeValue:@"AXRightWordTextMarkerRangeForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+ return AccessibilityTextMarkerRange::create(textMarkerRange);
+ END_AX_OBJC_EXCEPTIONS
+
+ return nullptr;
+}
+
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id previousWordStartMarker = [m_element accessibilityAttributeValue:@"AXPreviousWordStartTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+ return AccessibilityTextMarker::create(previousWordStartMarker);
+ END_AX_OBJC_EXCEPTIONS
+
+ return nullptr;
+}
+
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id nextWordEndMarker = [m_element accessibilityAttributeValue:@"AXNextWordEndTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+ return AccessibilityTextMarker::create(nextWordEndMarker);
+ END_AX_OBJC_EXCEPTIONS
+
+ return nullptr;
+}
+
</ins><span class="cx"> static NSString *_convertMathMultiscriptPairsToString(NSArray *pairs)
</span><span class="cx"> {
</span><span class="cx"> __block NSMutableString *result = [NSMutableString string];
</span></span></pre>
</div>
</div>
</body>
</html>