Diff
Modified: trunk/LayoutTests/ChangeLog (196351 => 196352)
--- trunk/LayoutTests/ChangeLog 2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/LayoutTests/ChangeLog 2016-02-10 02:33:04 UTC (rev 196352)
@@ -1,3 +1,16 @@
+2016-02-09 Nan Wang <n_w...@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:
+
2016-02-09 Ryan Haddad <ryanhad...@apple.com>
Mark perf/adding-radio-buttons.html as flaky on ios-simulator
Added: trunk/LayoutTests/accessibility/mac/text-marker-word-nav-expected.txt (0 => 196352)
--- 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)
@@ -0,0 +1,125 @@
+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
+
Added: trunk/LayoutTests/accessibility/mac/text-marker-word-nav.html (0 => 196352)
--- 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)
@@ -0,0 +1,195 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<meta charset="utf-8">
+<script src=""
+</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="" 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=""
+</body>
+</html>
\ No newline at end of file
Modified: trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next-expected.txt (196351 => 196352)
--- 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)
@@ -12,9 +12,9 @@
PASS text.textMarkerRangeLength(textMarkerRange) is 4
PASS text.accessibilityElementForTextMarker(startMarker).isEqual(text) is true
PASS text.accessibilityElementForTextMarker(endMarker).isEqual(text) is true
-PASS text.stringForTextMarkerRange(markerRange) is ''
+PASS text.stringForTextMarkerRange(markerRange) is newline
PASS text.stringForTextMarkerRange(markerRange) is 't'
-PASS text.stringForTextMarkerRange(markerRange) is ''
+PASS text.stringForTextMarkerRange(markerRange) is newline
PASS text.stringForTextMarkerRange(markerRange) is 't'
PASS text2.textMarkerRangeLength(textMarkerRange2) is 5
Object string for range: c [ATTACHMENT] d
Modified: trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next.html (196351 => 196352)
--- 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)
@@ -50,7 +50,8 @@
currentMarker = text.nextTextMarker(currentMarker);
}
markerRange = text.textMarkerRangeForMarkers(previousMarker, currentMarker);
- shouldBe("text.stringForTextMarkerRange(markerRange)", "''");
+ var newline = '\n';
+ shouldBe("text.stringForTextMarkerRange(markerRange)", "newline");
// Advance one more character, it will lande at "t" in "text1".
previousMarker = currentMarker;
@@ -62,7 +63,7 @@
previousMarker = text.previousTextMarker(previousMarker);
currentMarker = text.previousTextMarker(currentMarker);
markerRange = text.textMarkerRangeForMarkers(previousMarker, currentMarker);
- shouldBe("text.stringForTextMarkerRange(markerRange)", "''");
+ shouldBe("text.stringForTextMarkerRange(markerRange)", "newline");
// Traverse backwards one more character, it will land at the last character of "text".
previousMarker = text.previousTextMarker(previousMarker);
Modified: trunk/Source/WebCore/ChangeLog (196351 => 196352)
--- 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)
@@ -1,3 +1,71 @@
+2016-02-09 Nan Wang <n_w...@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:
+
2016-02-09 Daniel Bates <daba...@apple.com>
CSP: Extract helper classes into their own files
Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (196351 => 196352)
--- 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)
@@ -81,6 +81,7 @@
#include "RenderTableRow.h"
#include "RenderView.h"
#include "ScrollView.h"
+#include "TextBoundaries.h"
#include "TextIterator.h"
#include <wtf/DataLog.h>
@@ -1470,6 +1471,7 @@
for (; !iterator.atEnd(); iterator.advance()) {
int currentLength = iterator.text().length();
+ bool hasReplacedNodeOrBR = false;
Node& node = iterator.range()->startContainer();
currentNode = &node;
@@ -1482,17 +1484,28 @@
offsetSoFar++;
currentLength++;
currentNode = childNode;
+ hasReplacedNodeOrBR = true;
} else
continue;
} else {
// Ignore space, new line, tag node.
- if (currentLength == 1 && isSpaceOrNewline(iterator.text()[0]))
- continue;
+ 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;
+ }
+ }
offsetSoFar += currentLength;
}
lastLength = currentLength;
- lastStartOffset = iterator.range()->startOffset();
+ lastStartOffset = hasReplacedNodeOrBR ? 0 : iterator.range()->startOffset();
// Break early if we have advanced enough characters.
if (!toNodeEnd && offsetSoFar >= offset) {
@@ -1546,6 +1559,11 @@
range->selectNodeContents(node, ec);
return ec ? nullptr : range;
}
+
+static bool isReplacedNodeOrBR(Node* node)
+{
+ return node && (AccessibilityObject::replacedNodeNeedsCharacter(node) || node->hasTagName(brTag));
+}
static bool characterOffsetsInOrder(const CharacterOffset& characterOffset1, const CharacterOffset& characterOffset2)
{
@@ -1555,8 +1573,18 @@
if (characterOffset1.node == characterOffset2.node)
return characterOffset1.offset <= characterOffset2.offset;
- RefPtr<Range> range1 = AXObjectCache::rangeForNodeContents(characterOffset1.node);
- RefPtr<Range> range2 = AXObjectCache::rangeForNodeContents(characterOffset2.node);
+ 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);
return range1->compareBoundaryPoints(Range::START_TO_START, range2.get(), IGNORE_EXCEPTION) <= 0;
}
@@ -1572,9 +1600,26 @@
return replacedNode->parentNode();
}
-static bool isReplacedNodeOrBR(Node* node)
+static void setRangeStartOrEndWithCharacterOffset(RefPtr<Range> range, CharacterOffset& characterOffset, bool isStart, ExceptionCode& ec)
{
- return AccessibilityObject::replacedNodeNeedsCharacter(node) || node->hasTagName(brTag);
+ 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);
}
RefPtr<Range> AXObjectCache::rangeForUnorderedCharacterOffsets(const CharacterOffset& characterOffset1, const CharacterOffset& characterOffset2)
@@ -1586,34 +1631,11 @@
CharacterOffset startCharacterOffset = alreadyInOrder ? characterOffset1 : characterOffset2;
CharacterOffset endCharacterOffset = alreadyInOrder ? characterOffset2 : characterOffset1;
- 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);
- }
- }
-
RefPtr<Range> result = Range::create(m_document);
- ExceptionCode ecStart = 0, ecEnd = 0;
- result->setStart(startNode, startOffset, ecStart);
- result->setEnd(endNode, endOffset, ecEnd);
- if (ecStart || ecEnd)
+ ExceptionCode ec = 0;
+ setRangeStartOrEndWithCharacterOffset(result, startCharacterOffset, true, ec);
+ setRangeStartOrEndWithCharacterOffset(result, endCharacterOffset, false, ec);
+ if (ec)
return nullptr;
return result;
@@ -1635,7 +1657,7 @@
return;
// Convert to visible position.
- VisiblePosition visiblePosition = visiblePositionFromCharacterOffset(obj.get(), characterOffset);
+ VisiblePosition visiblePosition = visiblePositionFromCharacterOffset(characterOffset);
int vpOffset = 0;
if (!visiblePosition.isNull()) {
Position deepPos = visiblePosition.deepEquivalent();
@@ -1652,53 +1674,64 @@
this->setNodeInUse(domNode);
}
-void AXObjectCache::startOrEndTextMarkerDataForRange(TextMarkerData& textMarkerData, RefPtr<Range> range, bool isStart)
+CharacterOffset AXObjectCache::startOrEndCharacterOffsetForRange(RefPtr<Range> range, bool isStart)
{
- memset(&textMarkerData, 0, sizeof(TextMarkerData));
-
if (!range)
- return;
+ return CharacterOffset();
// If it's end text marker, we want to go to the end of the range, and stay within the range.
bool stayWithinRange = !isStart;
+ RefPtr<Range> copyRange = range;
// Change the start of the range, so the character offset starts from node beginning.
int offset = 0;
- Node* node = &range->startContainer();
+ Node* node = ©Range->startContainer();
if (node->offsetInCharacters()) {
+ copyRange = Range::create(range->ownerDocument(), &range->startContainer(), range->startOffset(), &range->endContainer(), range->endOffset());
CharacterOffset nodeStartOffset = traverseToOffsetInRange(rangeForNodeContents(node), 0, false);
- offset = std::max(range->startOffset() - nodeStartOffset.startIndex, 0);
- range->setStart(node, nodeStartOffset.startIndex);
+ offset = std::max(copyRange->startOffset() - nodeStartOffset.startIndex, 0);
+ copyRange->setStart(node, nodeStartOffset.startIndex);
}
- CharacterOffset characterOffset = traverseToOffsetInRange(range, offset, !isStart, stayWithinRange);
- setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
+ return traverseToOffsetInRange(copyRange, offset, !isStart, stayWithinRange);
}
-void AXObjectCache::textMarkerDataForCharacterOffset(TextMarkerData& textMarkerData, Node& node, int offset, bool toNodeEnd)
+void AXObjectCache::startOrEndTextMarkerDataForRange(TextMarkerData& textMarkerData, RefPtr<Range> range, bool isStart)
{
memset(&textMarkerData, 0, sizeof(TextMarkerData));
+ CharacterOffset characterOffset = startOrEndCharacterOffsetForRange(range, isStart);
+ if (characterOffset.isNull())
+ return;
+
+ setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
+}
+
+CharacterOffset AXObjectCache::characterOffsetForNodeAndOffset(Node& node, int offset, bool toNodeEnd, bool ignoreStart)
+{
Node* domNode = &node;
if (!domNode)
- return;
+ return CharacterOffset();
- // If offset <= 0, means we want to go to the previous node.
- if (offset <= 0 && !toNodeEnd) {
+ // 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))) {
// Set the offset to the amount of characters we need to go backwards.
- offset = - offset + 1;
- while (offset > 0 && textMarkerData.characterOffset <= offset) {
- offset -= textMarkerData.characterOffset;
+ offset = - offset;
+ CharacterOffset charOffset = CharacterOffset();
+ while (offset >= 0 && charOffset.offset <= offset) {
+ offset -= charOffset.offset;
domNode = previousNode(domNode);
if (domNode) {
- textMarkerDataForCharacterOffset(textMarkerData, *domNode, 0, true);
- offset--;
+ charOffset = characterOffsetForNodeAndOffset(*domNode, 0, true);
} else
- return;
+ return CharacterOffset();
+ if (!offset)
+ break;
}
if (offset > 0)
- textMarkerDataForCharacterOffset(textMarkerData, *domNode, offset, false);
- return;
+ charOffset = characterOffsetForNodeAndOffset(*charOffset.node, charOffset.offset - offset, false);
+ return charOffset;
}
RefPtr<Range> range = rangeForNodeContents(domNode);
@@ -1709,11 +1742,19 @@
while (!characterOffset.isNull() && characterOffset.remaining() && !toNodeEnd) {
domNode = nextNode(domNode);
if (!domNode)
- return;
+ return CharacterOffset();
range = rangeForNodeContents(domNode);
characterOffset = traverseToOffsetInRange(range, characterOffset.remaining(), toNodeEnd);
}
+ 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);
setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
}
@@ -1737,8 +1778,12 @@
return NodeTraversal::previousSkippingChildren(*node);
}
-VisiblePosition AXObjectCache::visiblePositionFromCharacterOffset(AccessibilityObject* obj, const CharacterOffset& characterOffset)
+VisiblePosition AXObjectCache::visiblePositionFromCharacterOffset(const CharacterOffset& characterOffset)
{
+ if (characterOffset.isNull())
+ return VisiblePosition();
+
+ RefPtr<AccessibilityObject> obj = this->getOrCreate(characterOffset.node);
if (!obj)
return VisiblePosition();
@@ -1752,13 +1797,20 @@
return result;
}
-CharacterOffset AXObjectCache::characterOffsetFromVisiblePosition(AccessibilityObject* obj, const VisiblePosition& visiblePos)
+CharacterOffset AXObjectCache::characterOffsetFromVisiblePosition(const VisiblePosition& visiblePos)
{
+ if (visiblePos.isNull())
+ return CharacterOffset();
+
+ Position deepPos = visiblePos.deepEquivalent();
+ Node* domNode = deepPos.deprecatedNode();
+ ASSERT(domNode);
+
+ RefPtr<AccessibilityObject> obj = this->getOrCreate(domNode);
if (!obj)
- return 0;
+ return CharacterOffset();
// Use nextVisiblePosition to calculate how many characters we need to traverse to the current position.
- Position deepPos = visiblePos.deepEquivalent();
VisiblePositionRange vpRange = obj->visiblePositionRange();
VisiblePosition vp = vpRange.start;
int characterOffset = 0;
@@ -1816,13 +1868,256 @@
textMarkerData.affinity = visiblePos.affinity();
// convert to character offset
- CharacterOffset characterOffset = characterOffsetFromVisiblePosition(obj.get(), visiblePos);
+ CharacterOffset characterOffset = characterOffsetFromVisiblePosition(visiblePos);
textMarkerData.characterOffset = characterOffset.offset;
textMarkerData.characterStartIndex = characterOffset.startIndex;
cache->setNodeInUse(domNode);
}
+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);
+}
+
const Element* AXObjectCache::rootAXEditableElement(const Node* node)
{
const Element* result = node->rootEditableElement();
Modified: trunk/Source/WebCore/accessibility/AXObjectCache.h (196351 => 196352)
--- 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)
@@ -30,6 +30,7 @@
#include "AccessibilityObject.h"
#include "Range.h"
#include "Timer.h"
+#include "VisibleUnits.h"
#include <limits.h>
#include <wtf/Forward.h>
#include <wtf/HashMap.h>
@@ -186,12 +187,20 @@
void textMarkerDataForVisiblePosition(TextMarkerData&, const VisiblePosition&);
VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&);
CharacterOffset characterOffsetForTextMarkerData(TextMarkerData&);
- void textMarkerDataForCharacterOffset(TextMarkerData&, Node&, int, bool toNodeEnd = false);
+ void textMarkerDataForCharacterOffset(TextMarkerData&, Node&, int, bool toNodeEnd = false, bool ignoreStart = true);
void startOrEndTextMarkerDataForRange(TextMarkerData&, RefPtr<Range>, bool);
AccessibilityObject* accessibilityObjectForTextMarkerData(TextMarkerData&);
RefPtr<Range> rangeForUnorderedCharacterOffsets(const CharacterOffset&, const CharacterOffset&);
static RefPtr<Range> rangeForNodeContents(Node*);
static int lengthForRange(Range*);
+
+ // 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&);
enum AXNotification {
AXActiveDescendantChanged,
@@ -283,12 +292,21 @@
void removeNodeForUse(Node* n) { m_textMarkerNodes.remove(n); }
bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); }
+ // CharacterOffset functions.
Node* nextNode(Node*) const;
Node* previousNode(Node*) const;
CharacterOffset traverseToOffsetInRange(RefPtr<Range>, int, bool, bool stayWithinRange = false);
- VisiblePosition visiblePositionFromCharacterOffset(AccessibilityObject*, const CharacterOffset&);
- CharacterOffset characterOffsetFromVisiblePosition(AccessibilityObject*, const VisiblePosition&);
+ VisiblePosition visiblePositionFromCharacterOffset(const CharacterOffset&);
+ CharacterOffset characterOffsetFromVisiblePosition(const VisiblePosition&);
void setTextMarkerDataWithCharacterOffset(TextMarkerData&, const CharacterOffset&);
+ 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);
private:
AccessibilityObject* rootWebArea();
Modified: trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm (196351 => 196352)
--- 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)
@@ -858,12 +858,17 @@
return textMarker;
}
+- (id)textMarkerForNode:(Node&)node offset:(int)offset ignoreStart:(BOOL)ignoreStart
+{
+ return textMarkerForCharacterOffset(m_object->axObjectCache(), node, offset, false, ignoreStart);
+}
+
- (id)textMarkerForNode:(Node&)node offset:(int)offset
{
- return textMarkerForCharacterOffset(m_object->axObjectCache(), node, offset);
+ return [self textMarkerForNode:node offset:offset ignoreStart:YES];
}
-static id textMarkerForCharacterOffset(AXObjectCache* cache, Node& node, int offset, bool toNodeEnd = false)
+static id textMarkerForCharacterOffset(AXObjectCache* cache, Node& node, int offset, bool toNodeEnd, bool ignoreStart)
{
if (!cache)
return nil;
@@ -873,7 +878,7 @@
return nil;
TextMarkerData textMarkerData;
- cache->textMarkerDataForCharacterOffset(textMarkerData, node, offset, toNodeEnd);
+ cache->textMarkerDataForCharacterOffset(textMarkerData, node, offset, toNodeEnd, ignoreStart);
if (!textMarkerData.axID && !textMarkerData.ignored)
return nil;
@@ -4070,15 +4075,21 @@
}
if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"]) {
- VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
- VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos);
- return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
+ AXObjectCache* cache = m_object->axObjectCache();
+ if (!cache)
+ return nil;
+ CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
+ RefPtr<Range> range = cache->leftWordRange(characterOffset);
+ return [self textMarkerRangeFromRange:range];
}
if ([attribute isEqualToString:@"AXRightWordTextMarkerRangeForTextMarker"]) {
- VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
- VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos);
- return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
+ AXObjectCache* cache = m_object->axObjectCache();
+ if (!cache)
+ return nil;
+ CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
+ RefPtr<Range> range = cache->rightWordRange(characterOffset);
+ return [self textMarkerRangeFromRange:range];
}
if ([attribute isEqualToString:@"AXLeftLineTextMarkerRangeForTextMarker"]) {
@@ -4106,13 +4117,21 @@
}
if ([attribute isEqualToString:@"AXNextWordEndTextMarkerForTextMarker"]) {
- VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
- return [self textMarkerForVisiblePosition:m_object->nextWordEnd(visiblePos)];
+ 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];
}
if ([attribute isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) {
- VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
- return [self textMarkerForVisiblePosition:m_object->previousWordStart(visiblePos)];
+ 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];
}
if ([attribute isEqualToString:@"AXNextLineEndTextMarkerForTextMarker"]) {
Modified: trunk/Source/WebCore/editing/VisibleUnits.cpp (196351 => 196352)
--- 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)
@@ -439,10 +439,6 @@
}
-enum BoundarySearchContextAvailability { DontHaveMoreContext, MayHaveMoreContext };
-
-typedef unsigned (*BoundarySearchFunction)(StringView, unsigned offset, BoundarySearchContextAvailability, bool& needMoreContext);
-
static void prepend(Vector<UChar, 1024>& buffer, StringView string)
{
unsigned oldSize = buffer.size();
@@ -470,6 +466,99 @@
buffer[oldSize + i] = character;
}
+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;
+}
+
static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction)
{
Position pos = c.deepEquivalent();
@@ -490,16 +579,7 @@
RefPtr<Range> forwardsScanRange(boundaryDocument.createRange());
forwardsScanRange->setEndAfter(boundary, ec);
forwardsScanRange->setStart(end.deprecatedNode(), end.deprecatedEditingOffset(), ec);
- 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();
- }
+ suffixLength = suffixLengthForRange(forwardsScanRange, string);
}
searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), ec);
@@ -510,30 +590,7 @@
return VisiblePosition();
SimplifiedBackwardsTextIterator it(*searchRange);
- 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);
- }
+ unsigned next = backwardSearchForBoundaryWithTextIterator(it, string, suffixLength, searchFunction);
if (!next)
return VisiblePosition(it.atEnd() ? searchRange->startPosition() : pos, DOWNSTREAM);
@@ -568,46 +625,13 @@
if (requiresContextForWordBoundary(c.characterAfter())) {
RefPtr<Range> backwardsScanRange(boundaryDocument.createRange());
backwardsScanRange->setEnd(start.deprecatedNode(), start.deprecatedEditingOffset(), IGNORE_EXCEPTION);
- 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();
- }
+ prefixLength = prefixLengthForRange(backwardsScanRange, string);
}
searchRange->selectNodeContents(boundary, IGNORE_EXCEPTION);
searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), IGNORE_EXCEPTION);
TextIterator it(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions);
- 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);
- }
+ unsigned next = forwardSearchForBoundaryWithTextIterator(it, string, prefixLength, searchFunction);
if (it.atEnd() && next == string.size())
pos = searchRange->endPosition();
Modified: trunk/Source/WebCore/editing/VisibleUnits.h (196351 => 196352)
--- 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)
@@ -34,6 +34,8 @@
class Node;
class VisiblePosition;
+class SimplifiedBackwardsTextIterator;
+class TextIterator;
enum EWordSide { RightWordIfOnBoundary = false, LeftWordIfOnBoundary = true };
@@ -107,6 +109,14 @@
WEBCORE_EXPORT void charactersAroundPosition(const VisiblePosition&, UChar32& oneAfter, UChar32& oneBefore, UChar32& twoBefore);
WEBCORE_EXPORT PassRefPtr<Range> rangeExpandedAroundPositionByCharacters(const VisiblePosition&, int numberOfCharactersToExpand);
+// 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);
+
} // namespace WebCore
#endif // VisibleUnits_h
Modified: trunk/Tools/ChangeLog (196351 => 196352)
--- trunk/Tools/ChangeLog 2016-02-10 02:29:38 UTC (rev 196351)
+++ trunk/Tools/ChangeLog 2016-02-10 02:33:04 UTC (rev 196352)
@@ -1,3 +1,61 @@
+2016-02-09 Nan Wang <n_w...@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):
+
2016-02-09 Csaba Osztrogonác <o...@webkit.org>
[EFL] Remove eail related cruft after r195725
Modified: trunk/Tools/DumpRenderTree/AccessibilityUIElement.cpp (196351 => 196352)
--- 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)
@@ -974,6 +974,42 @@
return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->endTextMarker());
}
+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));
+}
+
static JSValueRef setSelectedVisibleTextRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
AccessibilityUIElement* uiElement = toAXElement(thisObject);
@@ -1564,6 +1600,26 @@
return false;
}
+AccessibilityTextMarkerRange AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarkerRange AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
#endif
// Destruction
@@ -1744,6 +1800,10 @@
{ "nextTextMarker", nextTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "previousTextMarker", previousTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "stringForTextMarkerRange", stringForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "leftWordTextMarkerRangeForTextMarker", leftWordTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "rightWordTextMarkerRangeForTextMarker", rightWordTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "previousWordStartTextMarkerForTextMarker", previousWordStartTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "nextWordEndTextMarkerForTextMarker", nextWordEndTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setSelectedChild", setSelectedChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setSelectedChildAtIndex", setSelectedChildAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "removeSelectionAtIndex", removeSelectionAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
Modified: trunk/Tools/DumpRenderTree/AccessibilityUIElement.h (196351 => 196352)
--- 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)
@@ -260,6 +260,10 @@
AccessibilityUIElement accessibilityElementForTextMarker(AccessibilityTextMarker*);
AccessibilityTextMarker startTextMarker();
AccessibilityTextMarker endTextMarker();
+ AccessibilityTextMarkerRange leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*);
AccessibilityTextMarkerRange selectedTextMarkerRange();
void resetSelectedTextMarkerRange();
bool setSelectedVisibleTextRange(AccessibilityTextMarkerRange*);
Modified: trunk/Tools/DumpRenderTree/ios/AccessibilityUIElementIOS.mm (196351 => 196352)
--- 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)
@@ -550,6 +550,26 @@
return false;
}
+AccessibilityTextMarkerRange AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarkerRange AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
#endif // SUPPORTS_AX_TEXTMARKERS && PLATFORM(IOS)
#pragma mark Unused
Modified: trunk/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm (196351 => 196352)
--- 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)
@@ -1846,6 +1846,46 @@
return true;
}
+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;
+}
+
#endif // SUPPORTS_AX_TEXTMARKERS && PLATFORM(MAC)
JSStringRef AccessibilityUIElement::supportedActions()
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp (196351 => 196352)
--- 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)
@@ -244,5 +244,12 @@
void AccessibilityUIElement::setBoolAttributeValue(JSStringRef, bool) { }
#endif
+#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
+
} // namespace WTR
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h (196351 => 196352)
--- 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)
@@ -251,6 +251,10 @@
PassRefPtr<AccessibilityTextMarker> startTextMarker();
PassRefPtr<AccessibilityTextMarker> endTextMarker();
bool setSelectedVisibleTextRange(AccessibilityTextMarkerRange*);
+ PassRefPtr<AccessibilityTextMarkerRange> leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ PassRefPtr<AccessibilityTextMarkerRange> rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ PassRefPtr<AccessibilityTextMarker> previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*);
+ PassRefPtr<AccessibilityTextMarker> nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*);
// Returns an ordered list of supported actions for an element.
JSRetainPtr<JSStringRef> supportedActions() const;
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl (196351 => 196352)
--- 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)
@@ -201,6 +201,10 @@
readonly attribute AccessibilityTextMarker startTextMarker;
readonly attribute AccessibilityTextMarker endTextMarker;
boolean setSelectedVisibleTextRange(AccessibilityTextMarkerRange range);
+ AccessibilityTextMarkerRange leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
// Returns an ordered list of supported actions for an element.
readonly attribute DOMString supportedActions;
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm (196351 => 196352)
--- 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)
@@ -1096,6 +1096,26 @@
return nullptr;
}
+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;
+}
+
JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const
{
return 0;
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm (196351 => 196352)
--- 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)
@@ -1873,6 +1873,46 @@
return nullptr;
}
+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;
+}
+
static NSString *_convertMathMultiscriptPairsToString(NSArray *pairs)
{
__block NSMutableString *result = [NSMutableString string];