Title: [196546] trunk
Revision
196546
Author
n_w...@apple.com
Date
2016-02-12 21:24:24 -0800 (Fri, 12 Feb 2016)

Log Message

AX: Implement paragraph related text marker functions using TextIterator
https://bugs.webkit.org/show_bug.cgi?id=154098
<rdar://problem/24269675>

Reviewed by Chris Fleizach.

Source/WebCore:

Using CharacterOffset to implement paragraph related text marker calls. Reused
logic from VisibleUnits class. And refactored textMarkerForCharacterOffset method
to get better performance. Also fixed an issue where we can't navigate through a text
node with line breaks in it using next/previousCharacterOffset call.

Test: accessibility/mac/text-marker-paragraph-nav.html

* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::traverseToOffsetInRange):
(WebCore::AXObjectCache::startOrEndTextMarkerDataForRange):
(WebCore::AXObjectCache::characterOffsetForNodeAndOffset):
(WebCore::AXObjectCache::textMarkerDataForCharacterOffset):
(WebCore::AXObjectCache::textMarkerDataForNextCharacterOffset):
(WebCore::AXObjectCache::textMarkerDataForPreviousCharacterOffset):
(WebCore::AXObjectCache::nextNode):
(WebCore::AXObjectCache::textMarkerDataForVisiblePosition):
(WebCore::AXObjectCache::nextCharacterOffset):
(WebCore::AXObjectCache::previousCharacterOffset):
(WebCore::startWordBoundary):
(WebCore::AXObjectCache::startCharacterOffsetOfWord):
(WebCore::AXObjectCache::endCharacterOffsetOfWord):
(WebCore::AXObjectCache::previousWordStartCharacterOffset):
(WebCore::AXObjectCache::previousWordBoundary):
(WebCore::AXObjectCache::startCharacterOffsetOfParagraph):
(WebCore::AXObjectCache::endCharacterOffsetOfParagraph):
(WebCore::AXObjectCache::paragraphForCharacterOffset):
(WebCore::AXObjectCache::nextParagraphEndCharacterOffset):
(WebCore::AXObjectCache::previousParagraphStartCharacterOffset):
(WebCore::AXObjectCache::rootAXEditableElement):
* accessibility/AXObjectCache.h:
(WebCore::CharacterOffset::remaining):
(WebCore::CharacterOffset::isNull):
(WebCore::CharacterOffset::isEqual):
(WebCore::AXObjectCache::isNodeInUse):
* accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
(+[WebAccessibilityTextMarker textMarkerWithCharacterOffset:cache:]):
(-[WebAccessibilityObjectWrapper nextMarkerForCharacterOffset:]):
(-[WebAccessibilityObjectWrapper previousMarkerForCharacterOffset:]):
(-[WebAccessibilityObjectWrapper rangeForTextMarkers:]):
* accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
(startOrEndTextmarkerForRange):
(nextTextMarkerForCharacterOffset):
(previousTextMarkerForCharacterOffset):
(-[WebAccessibilityObjectWrapper nextTextMarkerForCharacterOffset:]):
(-[WebAccessibilityObjectWrapper previousTextMarkerForCharacterOffset:]):
(-[WebAccessibilityObjectWrapper textMarkerForCharacterOffset:]):
(textMarkerForCharacterOffset):
(-[WebAccessibilityObjectWrapper accessibilityAttributeValue:forParameter:]):
(-[WebAccessibilityObjectWrapper nextTextMarkerForNode:offset:]): Deleted.
(-[WebAccessibilityObjectWrapper previousTextMarkerForNode:offset:]): Deleted.
(-[WebAccessibilityObjectWrapper textMarkerForNode:offset:ignoreStart:]): Deleted.
(-[WebAccessibilityObjectWrapper textMarkerForNode:offset:]): Deleted.
* editing/VisibleUnits.cpp:
(WebCore::nextSentencePosition):
(WebCore::findStartOfParagraph):
(WebCore::findEndOfParagraph):
(WebCore::startOfParagraph):
(WebCore::endOfParagraph):
* editing/VisibleUnits.h:

Tools:

* DumpRenderTree/AccessibilityUIElement.cpp:
(nextWordEndTextMarkerForTextMarkerCallback):
(paragraphTextMarkerRangeForTextMarkerCallback):
(previousParagraphStartTextMarkerForTextMarkerCallback):
(nextParagraphEndTextMarkerForTextMarkerCallback):
(setSelectedVisibleTextRangeCallback):
(AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker):
(AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker):
(AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker):
(AccessibilityUIElement::getJSClass):
* DumpRenderTree/AccessibilityUIElement.h:
* DumpRenderTree/ios/AccessibilityUIElementIOS.mm:
(AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker):
(AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker):
(AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker):
* DumpRenderTree/mac/AccessibilityUIElementMac.mm:
(AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker):
(AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker):
(AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker):
(AccessibilityUIElement::supportedActions):
* WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp:
(WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker):
* WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
* WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl:
* WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm:
(WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::mathPostscriptsDescription):
* WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm:
(WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker):
(WTR::_convertMathMultiscriptPairsToString):

LayoutTests:

* accessibility/mac/text-marker-paragraph-nav-expected.txt: Added.
* accessibility/mac/text-marker-paragraph-nav.html: Added.
* accessibility/text-marker/text-marker-previous-next-expected.txt:
* accessibility/text-marker/text-marker-previous-next.html:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (196545 => 196546)


--- trunk/LayoutTests/ChangeLog	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/LayoutTests/ChangeLog	2016-02-13 05:24:24 UTC (rev 196546)
@@ -1,3 +1,16 @@
+2016-02-12  Nan Wang  <n_w...@apple.com>
+
+        AX: Implement paragraph related text marker functions using TextIterator
+        https://bugs.webkit.org/show_bug.cgi?id=154098
+        <rdar://problem/24269675>
+
+        Reviewed by Chris Fleizach.
+
+        * accessibility/mac/text-marker-paragraph-nav-expected.txt: Added.
+        * accessibility/mac/text-marker-paragraph-nav.html: Added.
+        * accessibility/text-marker/text-marker-previous-next-expected.txt:
+        * accessibility/text-marker/text-marker-previous-next.html:
+
 2016-02-12  Saam barati  <sbar...@apple.com>
 
         [ES6] we have an incorrect syntax error when a callee of a function _expression_ has the same name as a top-level lexical declaration

Added: trunk/LayoutTests/accessibility/mac/text-marker-paragraph-nav-expected.txt (0 => 196546)


--- trunk/LayoutTests/accessibility/mac/text-marker-paragraph-nav-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/accessibility/mac/text-marker-paragraph-nav-expected.txt	2016-02-13 05:24:24 UTC (rev 196546)
@@ -0,0 +1,84 @@
+paragraph test
+Test Contenteditable is working.
+c d
+test audio file
+can't select
+巧克力 是食物吗?
+كيف حالك؟
+both   spaces
+line breaks
+some
+text
+this is my first paragraph. Of text. it has some text.
+this is my second paragraph. Of text. it has some text.
+this is my third paragraph. Of text. it has some text.
+
+This tests that paragraph navigation is working correctly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Current character is: p
+Current paragraph is: paragraph test
+Pre paragraph start to next paragraph end: paragraph test
+
+Current character is: T
+Current paragraph is: Test Content
+Pre paragraph start to next paragraph end: Test Content
+
+Current character is: c
+Current paragraph is: c [ATTACHMENT]d
+Pre paragraph start to next paragraph end: c [ATTACHMENT]d
+
+Current character is: d
+Current paragraph is: c [ATTACHMENT]d
+Pre paragraph start to next paragraph end: c [ATTACHMENT]d
+test audio file
+
+Current character is: t
+Current paragraph is: test audio [ATTACHMENT]file
+Pre paragraph start to next paragraph end: test audio [ATTACHMENT]file
+
+Current character is: c
+Current paragraph is: can't select
+Pre paragraph start to next paragraph end: can't select
+
+Current character is: 巧
+Current paragraph is: 巧克力 是食物吗?
+Pre paragraph start to next paragraph end: 巧克力 是食物吗?
+
+Current character is: ك
+Current paragraph is: كيف حالك؟
+Pre paragraph start to next paragraph end: كيف حالك؟
+
+Current character is: b
+Current paragraph is: both   spaces
+Pre paragraph start to next paragraph end: both   spaces
+
+Current character is: i
+Current paragraph is: line breaks
+Pre paragraph start to next paragraph end: line breaks
+
+Current character is: s
+Current paragraph is: some
+Pre paragraph start to next paragraph end: some
+
+Current character is: t
+Current paragraph is: text
+Pre paragraph start to next paragraph end: text
+
+Paragraph: this is my first paragraph. Of text. it has some text.
+Paragraph: this is my second paragraph. Of text. it has some text.
+Paragraph: this is my third paragraph. Of text. it has some text.
+Paragraph: this is my third paragraph. Of text. it has some text.
+Paragraph: this is my second paragraph. Of text. it has some text.
+Paragraph: this is my first paragraph. Of text. it has some text.
+Test going forward.
+End paragraph: text
+
+Test going backwards.
+Start paragraph: paragraph test
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/accessibility/mac/text-marker-paragraph-nav.html (0 => 196546)


--- trunk/LayoutTests/accessibility/mac/text-marker-paragraph-nav.html	                        (rev 0)
+++ trunk/LayoutTests/accessibility/mac/text-marker-paragraph-nav.html	2016-02-13 05:24:24 UTC (rev 196546)
@@ -0,0 +1,219 @@
+<!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="text1" tabindex="0">
+para<span>graph</span>
+test
+</div>
+
+<div id="text2">
+Test Content<span contenteditable="true">editable is working.</span>
+</div>
+
+<div id="text3">
+c <img src="" aria-label="blah" style="background-color: #aaaaaa; width: 100px; height: 100px;">d
+</div>
+
+<div id="text4">
+test audio <audio controls><source src="" type="audio/mpeg"></audio>file
+</div>
+
+<div class="" id="text5">can't select</div>
+
+<div id="text6">
+巧克力
+是食物吗?
+</div>
+
+<div id="text6a">
+كيف حالك؟
+</div>
+
+<pre id="text7">
+both   spaces
+line breaks
+</pre>
+
+<div id="text8">
+some<br>text
+</div>
+
+<div id="text9">this is my first paragraph. Of text. it has some text.<br>
+this is my second paragraph. Of text. it has some text.<br>
+this is my third paragraph. Of text. it has some text.<br><br>
+</div>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+
+    description("This tests that paragraph navigation is working correctly.");
+    
+    if (window.accessibilityController) {
+        
+        // Check that we can get the paragraph range with span tag.
+        var text = accessibilityController.accessibleElementById("text1");
+        var textMarkerRange = text.textMarkerRangeForElement(text);
+        var startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+        var currentMarker = advanceAndVerify(startMarker, 1, text);
+        
+        // Check with contenteditable.
+        text = accessibilityController.accessibleElementById("text2");
+        textMarkerRange = text.textMarkerRangeForElement(text);
+        startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+        currentMarker = advanceAndVerify(startMarker, 1, text);
+        
+        // Check with replaced elements.
+        text = accessibilityController.accessibleElementById("text3");
+        textMarkerRange = text.textMarkerRangeForElement(text);
+        startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+        currentMarker = advanceAndVerify(startMarker, 1, text);
+        currentMarker = advanceAndVerify(currentMarker, 3, text);
+        // Audio tag.
+        text = accessibilityController.accessibleElementById("text4");
+        textMarkerRange = text.textMarkerRangeForElement(text);
+        startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+        currentMarker = advanceAndVerify(startMarker, 1, text);
+        
+        // Check with user-select:none.
+        text = accessibilityController.accessibleElementById("text5");
+        textMarkerRange = text.textMarkerRangeForElement(text);
+        startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+        currentMarker = advanceAndVerify(startMarker, 1, text);
+        
+        // Multi-languages.
+        text = accessibilityController.accessibleElementById("text6");
+        textMarkerRange = text.textMarkerRangeForElement(text);
+        startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+        currentMarker = advanceAndVerify(startMarker, 1, text);
+        
+        text = accessibilityController.accessibleElementById("text6a");
+        textMarkerRange = text.textMarkerRangeForElement(text);
+        startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+        currentMarker = advanceAndVerify(startMarker, 1, text);
+        
+        // Check the case with pre tag.
+        text = accessibilityController.accessibleElementById("text7");
+        textMarkerRange = text.textMarkerRangeForElement(text);
+        startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+        currentMarker = advanceAndVerify(startMarker, 1, text);
+        currentMarker = advanceAndVerify(currentMarker, 15, text);
+        
+        // Check the case with br tag.
+        text = accessibilityController.accessibleElementById("text8");
+        textMarkerRange = text.textMarkerRangeForElement(text);
+        startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+        currentMarker = advanceAndVerify(startMarker, 1, text);
+        currentMarker = advanceAndVerify(currentMarker, 5, text);
+        
+        // Check getting the correct paragraphs
+        text = accessibilityController.accessibleElementById("text9");
+        textMarkerRange = text.textMarkerRangeForElement(text);
+        startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+        startMarker = text.nextTextMarker(startMarker);
+        var endMarker = text.endTextMarkerForTextMarkerRange(textMarkerRange);
+        verifyParagraphs(text, startMarker, 3);
+        
+        // Check the paragraph marker runs from start to end, and backwards.
+        // Make sure it won't hang.
+        verifyDocument(text);
+        
+        
+        function advanceAndVerify(currentMarker, offset, obj) {
+            var previousMarker = currentMarker;
+            for (var i = 0; i < offset; i++) {
+                previousMarker = currentMarker;
+                currentMarker = obj.nextTextMarker(previousMarker);
+            }
+            verifyParagraphRangeForTextMarker(previousMarker, currentMarker, obj);
+            return currentMarker;
+        }
+        
+        function replaceAttachmentInString(str) {
+            str =  str.replace(String.fromCharCode(65532), "[ATTACHMENT]");
+            return str;
+        }
+        
+        function verifyParagraphRangeForTextMarker(preMarker, textMarker, obj) {
+            var markerRange = obj.textMarkerRangeForMarkers(preMarker, textMarker);
+            var currentCharacter = replaceAttachmentInString(obj.stringForTextMarkerRange(markerRange));
+            debug("Current character is: " + currentCharacter);
+            
+            var paragraphRange = obj.paragraphTextMarkerRangeForTextMarker(textMarker);
+            var paragraph = replaceAttachmentInString(obj.stringForTextMarkerRange(paragraphRange));
+            debug("Current paragraph is: " + paragraph);
+            
+            var preStart = obj.previousParagraphStartTextMarkerForTextMarker(textMarker);
+            var nextEnd = obj.nextParagraphEndTextMarkerForTextMarker(textMarker);
+            var preAndNextParagraphRange = obj.textMarkerRangeForMarkers(preStart, nextEnd);
+            var preAndNextParagraph = replaceAttachmentInString(obj.stringForTextMarkerRange(preAndNextParagraphRange));
+            debug("Pre paragraph start to next paragraph end: " + preAndNextParagraph + "\n");
+        }
+        
+        function verifyParagraphs(obj, startMarker, paragraphCount) {
+            // Move to the end of first paragraph, so the first paragraph
+            // won't print twice.
+            var current = obj.nextParagraphEndTextMarkerForTextMarker(startMarker);
+            var i = 0;
+            while(i < paragraphCount) {
+                var currRange = obj.paragraphTextMarkerRangeForTextMarker(current);
+                var currParagraph = obj.stringForTextMarkerRange(currRange);
+                debug("Paragraph: " + currParagraph);
+                current = obj.nextParagraphEndTextMarkerForTextMarker(current);
+                i++;
+            }
+            
+            // Backwards.
+            current = obj.previousParagraphStartTextMarkerForTextMarker(current);
+            i = 0;
+            while(i < paragraphCount) {
+                var currRange = obj.paragraphTextMarkerRangeForTextMarker(current);
+                var currParagraph = obj.stringForTextMarkerRange(currRange);
+                debug("Paragraph: " + currParagraph);
+                current = obj.previousParagraphStartTextMarkerForTextMarker(current);
+                i++;
+            }
+        }
+        
+        function verifyDocument(obj) {
+            var start = obj.startTextMarker;
+            
+            // Going forward.
+            debug("Test going forward.");
+            var current = start;
+            var end = "text";
+            var currParagraph = "";
+            while(currParagraph != end) {
+                var currRange = obj.paragraphTextMarkerRangeForTextMarker(current);
+                currParagraph = obj.stringForTextMarkerRange(currRange);
+                current = obj.nextParagraphEndTextMarkerForTextMarker(current);
+            }
+            debug("End paragraph: " + replaceAttachmentInString(currParagraph));
+            
+            // Going backwards.
+            debug("\nTest going backwards.");
+            var start = "paragraph test";
+            currParagraph = ""; 
+            while(currParagraph != start) {
+                var currentRange = obj.paragraphTextMarkerRangeForTextMarker(current);
+                currParagraph = obj.stringForTextMarkerRange(currentRange);
+                current = obj.previousParagraphStartTextMarkerForTextMarker(current);
+            }
+            debug("Start paragraph: " + replaceAttachmentInString(currParagraph));
+        }
+    }
+
+</script>
+
+<script src=""
+</body>
+</html>
\ No newline at end of file

Modified: trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next-expected.txt (196545 => 196546)


--- trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next-expected.txt	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next-expected.txt	2016-02-13 05:24:24 UTC (rev 196546)
@@ -4,6 +4,7 @@
 c  d
 
 can't select
+abc de f
 This tests the next/previous text marker functions are implemented correctly.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
@@ -25,6 +26,8 @@
 PASS !psw.accessibilityElementForTextMarker(start) is true
 PASS text2.accessibilityElementForTextMarker(currentMarker).isEqual(text3) is true
 PASS text2.accessibilityElementForTextMarker(currentMarker).isEqual(text2.childAtIndex(2)) is true
+PASS text.stringForTextMarkerRange(markerRange) is 'f'
+PASS text.stringForTextMarkerRange(markerRange) is 'a'
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next.html (196545 => 196546)


--- trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next.html	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next.html	2016-02-13 05:24:24 UTC (rev 196546)
@@ -20,6 +20,12 @@
 
 <div class="userselect" id="text3">can't select</div>
 
+<div id="text4">
+abc
+de
+f
+</div>
+
 <p id="description"></p>
 <div id="console"></div>
 
@@ -135,6 +141,27 @@
         currentMarker = text2.previousTextMarker(currentMarker);
         shouldBeTrue("text2.accessibilityElementForTextMarker(currentMarker).isEqual(text2.childAtIndex(2))");
         
+        
+        // Make sure that text node with line breaks, we can go through it with next/previous call.
+        text = accessibilityController.accessibleElementById("text4");
+        textMarkerRange = text.textMarkerRangeForElement(text);
+        startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+        currentMarker = startMarker;
+        for (var i = 0; i < 8; i++) {
+            previousMarker = currentMarker;
+            currentMarker = text.nextTextMarker(currentMarker);
+        }
+        markerRange = text.textMarkerRangeForMarkers(previousMarker, currentMarker)
+        shouldBe("text.stringForTextMarkerRange(markerRange)", "'f'");
+        
+        endMarker = text.endTextMarkerForTextMarkerRange(textMarkerRange);
+        currentMarker = endMarker;
+        for (var i = 0; i < 7; i++) {
+            currentMarker = text.previousTextMarker(currentMarker);
+        }
+        markerRange = text.textMarkerRangeForMarkers(startMarker, currentMarker)
+        shouldBe("text.stringForTextMarkerRange(markerRange)", "'a'");
+        
     }
 
 </script>

Modified: trunk/Source/WebCore/ChangeLog (196545 => 196546)


--- trunk/Source/WebCore/ChangeLog	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Source/WebCore/ChangeLog	2016-02-13 05:24:24 UTC (rev 196546)
@@ -1,3 +1,71 @@
+2016-02-12  Nan Wang  <n_w...@apple.com>
+
+        AX: Implement paragraph related text marker functions using TextIterator
+        https://bugs.webkit.org/show_bug.cgi?id=154098
+        <rdar://problem/24269675>
+
+        Reviewed by Chris Fleizach.
+
+        Using CharacterOffset to implement paragraph related text marker calls. Reused
+        logic from VisibleUnits class. And refactored textMarkerForCharacterOffset method
+        to get better performance. Also fixed an issue where we can't navigate through a text
+        node with line breaks in it using next/previousCharacterOffset call.
+
+        Test: accessibility/mac/text-marker-paragraph-nav.html
+
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::AXObjectCache::traverseToOffsetInRange):
+        (WebCore::AXObjectCache::startOrEndTextMarkerDataForRange):
+        (WebCore::AXObjectCache::characterOffsetForNodeAndOffset):
+        (WebCore::AXObjectCache::textMarkerDataForCharacterOffset):
+        (WebCore::AXObjectCache::textMarkerDataForNextCharacterOffset):
+        (WebCore::AXObjectCache::textMarkerDataForPreviousCharacterOffset):
+        (WebCore::AXObjectCache::nextNode):
+        (WebCore::AXObjectCache::textMarkerDataForVisiblePosition):
+        (WebCore::AXObjectCache::nextCharacterOffset):
+        (WebCore::AXObjectCache::previousCharacterOffset):
+        (WebCore::startWordBoundary):
+        (WebCore::AXObjectCache::startCharacterOffsetOfWord):
+        (WebCore::AXObjectCache::endCharacterOffsetOfWord):
+        (WebCore::AXObjectCache::previousWordStartCharacterOffset):
+        (WebCore::AXObjectCache::previousWordBoundary):
+        (WebCore::AXObjectCache::startCharacterOffsetOfParagraph):
+        (WebCore::AXObjectCache::endCharacterOffsetOfParagraph):
+        (WebCore::AXObjectCache::paragraphForCharacterOffset):
+        (WebCore::AXObjectCache::nextParagraphEndCharacterOffset):
+        (WebCore::AXObjectCache::previousParagraphStartCharacterOffset):
+        (WebCore::AXObjectCache::rootAXEditableElement):
+        * accessibility/AXObjectCache.h:
+        (WebCore::CharacterOffset::remaining):
+        (WebCore::CharacterOffset::isNull):
+        (WebCore::CharacterOffset::isEqual):
+        (WebCore::AXObjectCache::isNodeInUse):
+        * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
+        (+[WebAccessibilityTextMarker textMarkerWithCharacterOffset:cache:]):
+        (-[WebAccessibilityObjectWrapper nextMarkerForCharacterOffset:]):
+        (-[WebAccessibilityObjectWrapper previousMarkerForCharacterOffset:]):
+        (-[WebAccessibilityObjectWrapper rangeForTextMarkers:]):
+        * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+        (startOrEndTextmarkerForRange):
+        (nextTextMarkerForCharacterOffset):
+        (previousTextMarkerForCharacterOffset):
+        (-[WebAccessibilityObjectWrapper nextTextMarkerForCharacterOffset:]):
+        (-[WebAccessibilityObjectWrapper previousTextMarkerForCharacterOffset:]):
+        (-[WebAccessibilityObjectWrapper textMarkerForCharacterOffset:]):
+        (textMarkerForCharacterOffset):
+        (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:forParameter:]):
+        (-[WebAccessibilityObjectWrapper nextTextMarkerForNode:offset:]): Deleted.
+        (-[WebAccessibilityObjectWrapper previousTextMarkerForNode:offset:]): Deleted.
+        (-[WebAccessibilityObjectWrapper textMarkerForNode:offset:ignoreStart:]): Deleted.
+        (-[WebAccessibilityObjectWrapper textMarkerForNode:offset:]): Deleted.
+        * editing/VisibleUnits.cpp:
+        (WebCore::nextSentencePosition):
+        (WebCore::findStartOfParagraph):
+        (WebCore::findEndOfParagraph):
+        (WebCore::startOfParagraph):
+        (WebCore::endOfParagraph):
+        * editing/VisibleUnits.h:
+
 2016-02-12  Ryan Haddad  <ryanhad...@apple.com>
 
         Reset results for bindings tests after r196520

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (196545 => 196546)


--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2016-02-13 05:24:24 UTC (rev 196546)
@@ -83,6 +83,7 @@
 #include "ScrollView.h"
 #include "TextBoundaries.h"
 #include "TextIterator.h"
+#include "htmlediting.h"
 #include <wtf/DataLog.h>
 
 #if ENABLE(VIDEO)
@@ -1469,6 +1470,9 @@
         }
     }
     
+    // Sometimes text contents in a node are splitted into several iterations, so that iterator.range()->startOffset()
+    // might not be the correct character count. Here we use a previousNode object to keep track of that.
+    Node* previousNode = nullptr;
     for (; !iterator.atEnd(); iterator.advance()) {
         int currentLength = iterator.text().length();
         bool hasReplacedNodeOrBR = false;
@@ -1497,22 +1501,27 @@
                     if (childNode && childNode->renderer() && childNode->renderer()->isBR()) {
                         currentNode = childNode;
                         hasReplacedNodeOrBR = true;
-                    } else
+                    } else if (currentNode != previousNode)
                         continue;
                 }
             }
             offsetSoFar += currentLength;
         }
 
-        lastLength = currentLength;
-        lastStartOffset = hasReplacedNodeOrBR ? 0 : iterator.range()->startOffset();
+        if (currentNode == previousNode)
+            lastLength += currentLength;
+        else {
+            lastLength = currentLength;
+            lastStartOffset = hasReplacedNodeOrBR ? 0 : iterator.range()->startOffset();
+        }
         
         // Break early if we have advanced enough characters.
         if (!toNodeEnd && offsetSoFar >= offset) {
-            offsetInCharacter = offset - (offsetSoFar - currentLength);
+            offsetInCharacter = offset - (offsetSoFar - lastLength);
             finished = true;
             break;
         }
+        previousNode = currentNode;
     }
     
     if (!finished) {
@@ -1707,15 +1716,18 @@
     setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
 }
 
-CharacterOffset AXObjectCache::characterOffsetForNodeAndOffset(Node& node, int offset, bool toNodeEnd, bool ignoreStart)
+CharacterOffset AXObjectCache::characterOffsetForNodeAndOffset(Node& node, int offset, TraverseOption option)
 {
     Node* domNode = &node;
     if (!domNode)
         return CharacterOffset();
     
+    bool toNodeEnd = option & TraverseOptionToNodeEnd;
+    bool includeStart = option & TraverseOptionIncludeStart;
+    
     // 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))) {
+    if (!toNodeEnd && (offset < 0 || (!offset && !includeStart))) {
         // Set the offset to the amount of characters we need to go backwards.
         offset = - offset;
         CharacterOffset charOffset = CharacterOffset();
@@ -1723,14 +1735,14 @@
             offset -= charOffset.offset;
             domNode = previousNode(domNode);
             if (domNode) {
-                charOffset = characterOffsetForNodeAndOffset(*domNode, 0, true);
+                charOffset = characterOffsetForNodeAndOffset(*domNode, 0, TraverseOptionToNodeEnd);
             } else
                 return CharacterOffset();
             if (!offset)
                 break;
         }
         if (offset > 0)
-            charOffset = characterOffsetForNodeAndOffset(*charOffset.node, charOffset.offset - offset, false);
+            charOffset = characterOffsetForNodeAndOffset(*charOffset.node, charOffset.offset - offset);
         return charOffset;
     }
     
@@ -1750,14 +1762,30 @@
     return characterOffset;
 }
 
-void AXObjectCache::textMarkerDataForCharacterOffset(TextMarkerData& textMarkerData, Node& node, int offset, bool toNodeEnd, bool ignoreStart)
+void AXObjectCache::textMarkerDataForCharacterOffset(TextMarkerData& textMarkerData, const CharacterOffset& characterOffset)
 {
     memset(&textMarkerData, 0, sizeof(TextMarkerData));
-    
-    CharacterOffset characterOffset = characterOffsetForNodeAndOffset(node, offset, toNodeEnd, ignoreStart);
     setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
 }
 
+void AXObjectCache::textMarkerDataForNextCharacterOffset(TextMarkerData& textMarkerData, const CharacterOffset& characterOffset)
+{
+    CharacterOffset next = characterOffset;
+    do {
+        next = nextCharacterOffset(next);
+        textMarkerDataForCharacterOffset(textMarkerData, next);
+    } while (textMarkerData.ignored);
+}
+
+void AXObjectCache::textMarkerDataForPreviousCharacterOffset(TextMarkerData& textMarkerData, const CharacterOffset& characterOffset)
+{
+    CharacterOffset previous = characterOffset;
+    do {
+        previous = previousCharacterOffset(previous);
+        textMarkerDataForCharacterOffset(textMarkerData, previous);
+    } while (textMarkerData.ignored);
+}
+
 Node* AXObjectCache::nextNode(Node* node) const
 {
     if (!node)
@@ -1875,20 +1903,20 @@
     cache->setNodeInUse(domNode);
 }
 
-CharacterOffset AXObjectCache::nextCharacterOffset(const CharacterOffset& characterOffset)
+CharacterOffset AXObjectCache::nextCharacterOffset(const CharacterOffset& characterOffset, bool ignoreStart)
 {
     if (characterOffset.isNull())
         return CharacterOffset();
     
-    return characterOffsetForNodeAndOffset(*characterOffset.node, characterOffset.offset + 1);
+    return characterOffsetForNodeAndOffset(*characterOffset.node, characterOffset.offset + 1, ignoreStart ? TraverseOptionDefault : TraverseOptionIncludeStart);
 }
 
-CharacterOffset AXObjectCache::previousCharacterOffset(const CharacterOffset& characterOffset)
+CharacterOffset AXObjectCache::previousCharacterOffset(const CharacterOffset& characterOffset, bool ignoreStart)
 {
     if (characterOffset.isNull())
         return CharacterOffset();
     
-    return characterOffsetForNodeAndOffset(*characterOffset.node, characterOffset.offset - 1, false, false);
+    return characterOffsetForNodeAndOffset(*characterOffset.node, characterOffset.offset - 1, ignoreStart ? TraverseOptionDefault : TraverseOptionIncludeStart);
 }
 
 static unsigned startWordBoundary(StringView text, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
@@ -1925,9 +1953,8 @@
     
     CharacterOffset c = characterOffset;
     if (side == RightWordIfOnBoundary) {
-        // FIXME: need to remove this when isEndOfParagraph is implemented for CharacterOffset.
-        VisiblePosition vp = visiblePositionFromCharacterOffset(c);
-        if (isEndOfParagraph(vp))
+        CharacterOffset endOfParagraph = endCharacterOffsetOfParagraph(c);
+        if (c.isEqual(endOfParagraph))
             return c;
         
         c = nextCharacterOffset(characterOffset);
@@ -1945,12 +1972,11 @@
     
     CharacterOffset c = characterOffset;
     if (side == LeftWordIfOnBoundary) {
-        // FIXME: need to remove this when isStartOfParagraph is implemented for CharacterOffset.
-        VisiblePosition vp = visiblePositionFromCharacterOffset(c);
-        if (isStartOfParagraph(vp))
+        CharacterOffset startOfParagraph = startCharacterOffsetOfParagraph(c);
+        if (c.isEqual(startOfParagraph))
             return c;
         
-        c = previousCharacterOffset(characterOffset);
+        c = previousCharacterOffset(characterOffset, false);
         if (c.isNull())
             return characterOffset;
     }
@@ -1963,7 +1989,7 @@
     if (characterOffset.isNull())
         return CharacterOffset();
     
-    CharacterOffset previousOffset = previousCharacterOffset(characterOffset);
+    CharacterOffset previousOffset = previousCharacterOffset(characterOffset, false);
     if (previousOffset.isNull())
         return CharacterOffset();
     
@@ -2111,13 +2137,84 @@
         // The next variable contains a usable index into a text node
         if (&node == characterOffset.node)
             next -= characterOffset.startIndex;
-        return characterOffsetForNodeAndOffset(node, next, false);
+        return characterOffsetForNodeAndOffset(node, next, TraverseOptionIncludeStart);
     }
     
     int characterCount = characterOffset.offset - (string.size() - suffixLength - next);
-    return characterOffsetForNodeAndOffset(*characterOffset.node, characterCount, false, false);
+    return characterOffsetForNodeAndOffset(*characterOffset.node, characterCount, TraverseOptionIncludeStart);
 }
 
+CharacterOffset AXObjectCache::startCharacterOffsetOfParagraph(const CharacterOffset& characterOffset, EditingBoundaryCrossingRule boundaryCrossingRule)
+{
+    if (characterOffset.isNull())
+        return CharacterOffset();
+    
+    Node* startNode = characterOffset.node;
+    
+    if (isRenderedAsNonInlineTableImageOrHR(startNode))
+        return startOrEndCharacterOffsetForRange(rangeForNodeContents(startNode), true);
+    
+    Node* startBlock = enclosingBlock(startNode);
+    int offset = characterOffset.startIndex + characterOffset.offset;
+    Position p(startNode, offset, Position::PositionIsOffsetInAnchor);
+    Node* highestRoot = highestEditableRoot(p);
+    Position::AnchorType type = Position::PositionIsOffsetInAnchor;
+    
+    Node* node = findStartOfParagraph(startNode, highestRoot, startBlock, offset, type, boundaryCrossingRule);
+    
+    if (type == Position::PositionIsOffsetInAnchor)
+        return characterOffsetForNodeAndOffset(*node, offset, TraverseOptionIncludeStart);
+    
+    return startOrEndCharacterOffsetForRange(rangeForNodeContents(node), true);
+}
+
+CharacterOffset AXObjectCache::endCharacterOffsetOfParagraph(const CharacterOffset& characterOffset, EditingBoundaryCrossingRule boundaryCrossingRule)
+{
+    if (characterOffset.isNull())
+        return CharacterOffset();
+    
+    Node* startNode = characterOffset.node;
+    if (isRenderedAsNonInlineTableImageOrHR(startNode))
+        return startOrEndCharacterOffsetForRange(rangeForNodeContents(startNode), false);
+    
+    Node* stayInsideBlock = enclosingBlock(startNode);
+    int offset = characterOffset.startIndex + characterOffset.offset;
+    Position p(startNode, offset, Position::PositionIsOffsetInAnchor);
+    Node* highestRoot = highestEditableRoot(p);
+    Position::AnchorType type = Position::PositionIsOffsetInAnchor;
+    
+    Node* node = findEndOfParagraph(startNode, highestRoot, stayInsideBlock, offset, type, boundaryCrossingRule);
+    if (type == Position::PositionIsOffsetInAnchor) {
+        if (node->isTextNode()) {
+            CharacterOffset startOffset = startOrEndCharacterOffsetForRange(rangeForNodeContents(node), true);
+            offset -= startOffset.startIndex;
+        }
+        return characterOffsetForNodeAndOffset(*node, offset, TraverseOptionIncludeStart);
+    }
+    
+    return startOrEndCharacterOffsetForRange(rangeForNodeContents(node), false);
+}
+
+RefPtr<Range> AXObjectCache::paragraphForCharacterOffset(const CharacterOffset& characterOffset)
+{
+    CharacterOffset start = startCharacterOffsetOfParagraph(characterOffset);
+    CharacterOffset end = endCharacterOffsetOfParagraph(characterOffset);
+    
+    return rangeForUnorderedCharacterOffsets(start, end);
+}
+
+CharacterOffset AXObjectCache::nextParagraphEndCharacterOffset(const CharacterOffset& characterOffset)
+{
+    // make sure we move off of a paragraph end
+    return endCharacterOffsetOfParagraph(nextCharacterOffset(characterOffset));
+}
+
+CharacterOffset AXObjectCache::previousParagraphStartCharacterOffset(const CharacterOffset& characterOffset)
+{
+    // make sure we move off of a paragraph start
+    return startCharacterOffsetOfParagraph(previousCharacterOffset(characterOffset, false));
+}
+
 const Element* AXObjectCache::rootAXEditableElement(const Node* node)
 {
     const Element* result = node->rootEditableElement();

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.h (196545 => 196546)


--- trunk/Source/WebCore/accessibility/AXObjectCache.h	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.h	2016-02-13 05:24:24 UTC (rev 196546)
@@ -74,6 +74,12 @@
     
     int remaining() const { return remainingOffset; }
     bool isNull() const { return !node; }
+    bool isEqual(CharacterOffset& other) const
+    {
+        if (isNull() || other.isNull())
+            return false;
+        return node == other.node && startIndex == other.startIndex && offset == other.offset;
+    }
 };
 
 class AXComputedObjectAttributeCache {
@@ -185,9 +191,13 @@
 
     // Text marker utilities.
     void textMarkerDataForVisiblePosition(TextMarkerData&, const VisiblePosition&);
+    void textMarkerDataForCharacterOffset(TextMarkerData&, const CharacterOffset&);
+    void textMarkerDataForNextCharacterOffset(TextMarkerData&, const CharacterOffset&);
+    void textMarkerDataForPreviousCharacterOffset(TextMarkerData&, const CharacterOffset&);
     VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&);
     CharacterOffset characterOffsetForTextMarkerData(TextMarkerData&);
-    void textMarkerDataForCharacterOffset(TextMarkerData&, Node&, int, bool toNodeEnd = false, bool ignoreStart = true);
+    CharacterOffset nextCharacterOffset(const CharacterOffset&, bool ignoreStart = true);
+    CharacterOffset previousCharacterOffset(const CharacterOffset&, bool ignoreStart = true);
     void startOrEndTextMarkerDataForRange(TextMarkerData&, RefPtr<Range>, bool);
     AccessibilityObject* accessibilityObjectForTextMarkerData(TextMarkerData&);
     RefPtr<Range> rangeForUnorderedCharacterOffsets(const CharacterOffset&, const CharacterOffset&);
@@ -195,12 +205,15 @@
     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&);
+    
+    // Paragraph
+    RefPtr<Range> paragraphForCharacterOffset(const CharacterOffset&);
+    CharacterOffset nextParagraphEndCharacterOffset(const CharacterOffset&);
+    CharacterOffset previousParagraphStartCharacterOffset(const CharacterOffset&);
 
     enum AXNotification {
         AXActiveDescendantChanged,
@@ -293,6 +306,7 @@
     bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); }
     
     // CharacterOffset functions.
+    enum TraverseOption { TraverseOptionDefault = 1 << 0, TraverseOptionToNodeEnd = 1 << 1, TraverseOptionIncludeStart = 1 << 2 };
     Node* nextNode(Node*) const;
     Node* previousNode(Node*) const;
     CharacterOffset traverseToOffsetInRange(RefPtr<Range>, int, bool, bool stayWithinRange = false);
@@ -302,11 +316,13 @@
     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 characterOffsetForNodeAndOffset(Node&, int, TraverseOption = TraverseOptionDefault);
     CharacterOffset previousWordBoundary(CharacterOffset&, BoundarySearchFunction);
     CharacterOffset nextWordBoundary(CharacterOffset&, BoundarySearchFunction);
+    CharacterOffset startCharacterOffsetOfWord(const CharacterOffset&, EWordSide = RightWordIfOnBoundary);
+    CharacterOffset endCharacterOffsetOfWord(const CharacterOffset&, EWordSide = RightWordIfOnBoundary);
+    CharacterOffset startCharacterOffsetOfParagraph(const CharacterOffset&, EditingBoundaryCrossingRule = CannotCrossEditingBoundary);
+    CharacterOffset endCharacterOffsetOfParagraph(const CharacterOffset&, EditingBoundaryCrossingRule = CannotCrossEditingBoundary);
 
 private:
     AccessibilityObject* rootWebArea();

Modified: trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm (196545 => 196546)


--- trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm	2016-02-13 05:24:24 UTC (rev 196546)
@@ -189,7 +189,7 @@
         return nil;
     
     TextMarkerData textMarkerData;
-    cache->textMarkerDataForCharacterOffset(textMarkerData, *characterOffset.node, characterOffset.offset, false);
+    cache->textMarkerDataForCharacterOffset(textMarkerData, characterOffset);
     if (!textMarkerData.axID && !textMarkerData.ignored)
         return nil;
     return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
@@ -2425,20 +2425,28 @@
 
 - (WebAccessibilityTextMarker *)nextMarkerForCharacterOffset:(CharacterOffset&)characterOffset
 {
-    characterOffset.offset = characterOffset.offset + 1;
-    WebAccessibilityTextMarker *textMarker = [WebAccessibilityTextMarker textMarkerWithCharacterOffset:characterOffset cache:m_object->axObjectCache()];
-    if (textMarker && textMarker.isIgnored)
-        textMarker = [self nextMarkerForCharacterOffset:characterOffset];
-    return textMarker;
+    AXObjectCache* cache = m_object->axObjectCache();
+    if (!cache)
+        return nil;
+    
+    TextMarkerData textMarkerData;
+    cache->textMarkerDataForNextCharacterOffset(textMarkerData, characterOffset);
+    if (!textMarkerData.axID)
+        return nil;
+    return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
 }
 
 - (WebAccessibilityTextMarker *)previousMarkerForCharacterOffset:(CharacterOffset&)characterOffset
 {
-    characterOffset.offset = characterOffset.offset - 1;
-    WebAccessibilityTextMarker *textMarker = [WebAccessibilityTextMarker textMarkerWithCharacterOffset:characterOffset cache:m_object->axObjectCache()];
-    if (textMarker && textMarker.isIgnored)
-        textMarker = [self previousMarkerForCharacterOffset:characterOffset];
-    return textMarker;
+    AXObjectCache* cache = m_object->axObjectCache();
+    if (!cache)
+        return nil;
+    
+    TextMarkerData textMarkerData;
+    cache->textMarkerDataForPreviousCharacterOffset(textMarkerData, characterOffset);
+    if (!textMarkerData.axID)
+        return nil;
+    return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
 }
 
 - (RefPtr<Range>)rangeForTextMarkers:(NSArray *)textMarkers

Modified: trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm (196545 => 196546)


--- trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm	2016-02-13 05:24:24 UTC (rev 196546)
@@ -840,45 +840,52 @@
     return CFBridgingRelease(wkCreateAXTextMarker(&textMarkerData, sizeof(textMarkerData)));
 }
 
-- (id)nextTextMarkerForNode:(Node&)node offset:(int)offset
+static id nextTextMarkerForCharacterOffset(AXObjectCache* cache, CharacterOffset& characterOffset)
 {
-    int nextOffset = offset + 1;
-    id textMarker = [self textMarkerForNode:node offset:nextOffset];
-    if (isTextMarkerIgnored(textMarker))
-        textMarker = [self nextTextMarkerForNode:node offset:nextOffset];
-    return textMarker;
+    if (!cache)
+        return nil;
+    
+    TextMarkerData textMarkerData;
+    cache->textMarkerDataForNextCharacterOffset(textMarkerData, characterOffset);
+    if (!textMarkerData.axID)
+        return nil;
+    return CFBridgingRelease(wkCreateAXTextMarker(&textMarkerData, sizeof(textMarkerData)));
 }
 
-- (id)previousTextMarkerForNode:(Node&)node offset:(int)offset
+static id previousTextMarkerForCharacterOffset(AXObjectCache* cache, CharacterOffset& characterOffset)
 {
-    int previousOffset = offset - 1;
-    id textMarker = [self textMarkerForNode:node offset:previousOffset];
-    if (isTextMarkerIgnored(textMarker))
-        textMarker = [self previousTextMarkerForNode:node offset:previousOffset];
-    return textMarker;
+    if (!cache)
+        return nil;
+    
+    TextMarkerData textMarkerData;
+    cache->textMarkerDataForPreviousCharacterOffset(textMarkerData, characterOffset);
+    if (!textMarkerData.axID)
+        return nil;
+    return CFBridgingRelease(wkCreateAXTextMarker(&textMarkerData, sizeof(textMarkerData)));
 }
 
-- (id)textMarkerForNode:(Node&)node offset:(int)offset ignoreStart:(BOOL)ignoreStart
+- (id)nextTextMarkerForCharacterOffset:(CharacterOffset&)characterOffset
 {
-    return textMarkerForCharacterOffset(m_object->axObjectCache(), node, offset, false, ignoreStart);
+    return nextTextMarkerForCharacterOffset(m_object->axObjectCache(), characterOffset);
 }
 
-- (id)textMarkerForNode:(Node&)node offset:(int)offset
+- (id)previousTextMarkerForCharacterOffset:(CharacterOffset&)characterOffset
 {
-    return [self textMarkerForNode:node offset:offset ignoreStart:YES];
+    return previousTextMarkerForCharacterOffset(m_object->axObjectCache(), characterOffset);
 }
 
-static id textMarkerForCharacterOffset(AXObjectCache* cache, Node& node, int offset, bool toNodeEnd, bool ignoreStart)
+- (id)textMarkerForCharacterOffset:(CharacterOffset&)characterOffset
 {
+    return textMarkerForCharacterOffset(m_object->axObjectCache(), characterOffset);
+}
+
+static id textMarkerForCharacterOffset(AXObjectCache* cache, const CharacterOffset& characterOffset)
+{
     if (!cache)
         return nil;
     
-    Node* domNode = &node;
-    if (!domNode)
-        return nil;
-    
     TextMarkerData textMarkerData;
-    cache->textMarkerDataForCharacterOffset(textMarkerData, node, offset, toNodeEnd, ignoreStart);
+    cache->textMarkerDataForCharacterOffset(textMarkerData, characterOffset);
     if (!textMarkerData.axID && !textMarkerData.ignored)
         return nil;
     
@@ -4066,12 +4073,12 @@
     
     if ([attribute isEqualToString:@"AXNextTextMarkerForTextMarker"]) {
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
-        return [self nextTextMarkerForNode:*characterOffset.node offset:characterOffset.offset];
+        return [self nextTextMarkerForCharacterOffset:characterOffset];
     }
     
     if ([attribute isEqualToString:@"AXPreviousTextMarkerForTextMarker"]) {
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
-        return [self previousTextMarkerForNode:*characterOffset.node offset:characterOffset.offset];
+        return [self previousTextMarkerForCharacterOffset:characterOffset];
     }
     
     if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"]) {
@@ -4111,9 +4118,12 @@
     }
     
     if ([attribute isEqualToString:@"AXParagraphTextMarkerRangeForTextMarker"]) {
-        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
-        VisiblePositionRange vpRange = m_object->paragraphForPosition(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->paragraphForCharacterOffset(characterOffset);
+        return [self textMarkerRangeFromRange:range];
     }
     
     if ([attribute isEqualToString:@"AXNextWordEndTextMarkerForTextMarker"]) {
@@ -4122,7 +4132,7 @@
             return nil;
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
         CharacterOffset nextEnd = cache->nextWordEndCharacterOffset(characterOffset);
-        return [self textMarkerForNode:*nextEnd.node offset:nextEnd.offset];
+        return [self textMarkerForCharacterOffset:nextEnd];
     }
     
     if ([attribute isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) {
@@ -4131,7 +4141,7 @@
             return nil;
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
         CharacterOffset previousStart = cache->previousWordStartCharacterOffset(characterOffset);
-        return [self textMarkerForNode:*previousStart.node offset:previousStart.offset ignoreStart:NO];
+        return [self textMarkerForCharacterOffset:previousStart];
     }
     
     if ([attribute isEqualToString:@"AXNextLineEndTextMarkerForTextMarker"]) {
@@ -4160,8 +4170,12 @@
     }
     
     if ([attribute isEqualToString:@"AXPreviousParagraphStartTextMarkerForTextMarker"]) {
-        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
-        return [self textMarkerForVisiblePosition:m_object->previousParagraphStartPosition(visiblePos)];
+        AXObjectCache* cache = m_object->axObjectCache();
+        if (!cache)
+            return nil;
+        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
+        CharacterOffset previousStart = cache->previousParagraphStartCharacterOffset(characterOffset);
+        return [self textMarkerForCharacterOffset:previousStart];
     }
     
     if ([attribute isEqualToString:@"AXStyleTextMarkerRangeForTextMarker"]) {

Modified: trunk/Source/WebCore/editing/VisibleUnits.cpp (196545 => 196546)


--- trunk/Source/WebCore/editing/VisibleUnits.cpp	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Source/WebCore/editing/VisibleUnits.cpp	2016-02-13 05:24:24 UTC (rev 196546)
@@ -1142,24 +1142,9 @@
     return position.honorEditingBoundaryAtOrAfter(nextBoundary(position, nextSentencePositionBoundary));
 }
 
-VisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossingRule boundaryCrossingRule)
+Node* findStartOfParagraph(Node* startNode, Node* highestRoot, Node* startBlock, int& offset, Position::AnchorType& type, EditingBoundaryCrossingRule boundaryCrossingRule)
 {
-    Position p = c.deepEquivalent();
-    Node* startNode = p.deprecatedNode();
-
-    if (!startNode)
-        return VisiblePosition();
-    
-    if (isRenderedAsNonInlineTableImageOrHR(startNode))
-        return positionBeforeNode(startNode);
-
-    Node* startBlock = enclosingBlock(startNode);
-
     Node* node = startNode;
-    Node* highestRoot = highestEditableRoot(p);
-    int offset = p.deprecatedEditingOffset();
-    Position::AnchorType type = p.anchorType();
-
     Node* n = startNode;
     while (n) {
 #if ENABLE(USERSELECT_ALL)
@@ -1198,8 +1183,10 @@
                 if (n == startNode && o < i)
                     i = std::max(0, o);
                 while (--i >= 0) {
-                    if (text[i] == '\n')
-                        return VisiblePosition(Position(downcast<Text>(n), i + 1), DOWNSTREAM);
+                    if (text[i] == '\n') {
+                        offset = i + 1;
+                        return n;
+                    }
                 }
             }
             node = n;
@@ -1213,33 +1200,12 @@
             n = NodeTraversal::previousPostOrder(*n, startBlock);
     }
 
-    if (type == Position::PositionIsOffsetInAnchor) {
-        ASSERT(type == Position::PositionIsOffsetInAnchor || !offset);
-        return VisiblePosition(Position(node, offset, type), DOWNSTREAM);
-    }
-
-    return VisiblePosition(Position(node, type), DOWNSTREAM);
+    return node;
 }
 
-VisiblePosition endOfParagraph(const VisiblePosition& c, EditingBoundaryCrossingRule boundaryCrossingRule)
-{    
-    if (c.isNull())
-        return VisiblePosition();
-
-    Position p = c.deepEquivalent();
-    Node* startNode = p.deprecatedNode();
-
-    if (isRenderedAsNonInlineTableImageOrHR(startNode))
-        return positionAfterNode(startNode);
-    
-    Node* startBlock = enclosingBlock(startNode);
-    Node* stayInsideBlock = startBlock;
-    
+Node* findEndOfParagraph(Node* startNode, Node* highestRoot, Node* stayInsideBlock, int& offset, Position::AnchorType& type, EditingBoundaryCrossingRule boundaryCrossingRule)
+{
     Node* node = startNode;
-    Node* highestRoot = highestEditableRoot(p);
-    int offset = p.deprecatedEditingOffset();
-    Position::AnchorType type = p.anchorType();
-
     Node* n = startNode;
     while (n) {
 #if ENABLE(USERSELECT_ALL)
@@ -1279,8 +1245,10 @@
                 int o = n == startNode ? offset : 0;
                 int length = text.length();
                 for (int i = o; i < length; ++i) {
-                    if (text[i] == '\n')
-                        return VisiblePosition(Position(downcast<Text>(n), i), DOWNSTREAM);
+                    if (text[i] == '\n') {
+                        offset = i;
+                        return n;
+                    }
                 }
             }
             node = n;
@@ -1293,7 +1261,62 @@
         } else
             n = NodeTraversal::next(*n, stayInsideBlock);
     }
+    return node;
+}
 
+VisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossingRule boundaryCrossingRule)
+{
+    Position p = c.deepEquivalent();
+    Node* startNode = p.deprecatedNode();
+    
+    if (!startNode)
+        return VisiblePosition();
+    
+    if (isRenderedAsNonInlineTableImageOrHR(startNode))
+        return positionBeforeNode(startNode);
+    
+    Node* startBlock = enclosingBlock(startNode);
+    
+    Node* highestRoot = highestEditableRoot(p);
+    int offset = p.deprecatedEditingOffset();
+    Position::AnchorType type = p.anchorType();
+    
+    Node* node = findStartOfParagraph(startNode, highestRoot, startBlock, offset, type, boundaryCrossingRule);
+    
+    if (is<Text>(node))
+        return VisiblePosition(Position(downcast<Text>(node), offset), DOWNSTREAM);
+    
+    if (type == Position::PositionIsOffsetInAnchor) {
+        ASSERT(type == Position::PositionIsOffsetInAnchor || !offset);
+        return VisiblePosition(Position(node, offset, type), DOWNSTREAM);
+    }
+    
+    return VisiblePosition(Position(node, type), DOWNSTREAM);
+}
+
+VisiblePosition endOfParagraph(const VisiblePosition& c, EditingBoundaryCrossingRule boundaryCrossingRule)
+{    
+    if (c.isNull())
+        return VisiblePosition();
+    
+    Position p = c.deepEquivalent();
+    Node* startNode = p.deprecatedNode();
+    
+    if (isRenderedAsNonInlineTableImageOrHR(startNode))
+        return positionAfterNode(startNode);
+    
+    Node* startBlock = enclosingBlock(startNode);
+    Node* stayInsideBlock = startBlock;
+    
+    Node* highestRoot = highestEditableRoot(p);
+    int offset = p.deprecatedEditingOffset();
+    Position::AnchorType type = p.anchorType();
+    
+    Node* node = findEndOfParagraph(startNode, highestRoot, stayInsideBlock, offset, type, boundaryCrossingRule);
+    
+    if (is<Text>(node))
+        return VisiblePosition(Position(downcast<Text>(node), offset), DOWNSTREAM);
+    
     if (type == Position::PositionIsOffsetInAnchor)
         return VisiblePosition(Position(node, offset, type), DOWNSTREAM);
 

Modified: trunk/Source/WebCore/editing/VisibleUnits.h (196545 => 196546)


--- trunk/Source/WebCore/editing/VisibleUnits.h	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Source/WebCore/editing/VisibleUnits.h	2016-02-13 05:24:24 UTC (rev 196546)
@@ -116,6 +116,8 @@
 unsigned prefixLengthForRange(RefPtr<Range>, Vector<UChar, 1024>&);
 unsigned backwardSearchForBoundaryWithTextIterator(SimplifiedBackwardsTextIterator&, Vector<UChar, 1024>&, unsigned, BoundarySearchFunction);
 unsigned forwardSearchForBoundaryWithTextIterator(TextIterator&, Vector<UChar, 1024>&, unsigned, BoundarySearchFunction);
+Node* findStartOfParagraph(Node*, Node*, Node*, int&, Position::AnchorType&, EditingBoundaryCrossingRule);
+Node* findEndOfParagraph(Node*, Node*, Node*, int&, Position::AnchorType&, EditingBoundaryCrossingRule);
 
 } // namespace WebCore
 

Modified: trunk/Tools/ChangeLog (196545 => 196546)


--- trunk/Tools/ChangeLog	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Tools/ChangeLog	2016-02-13 05:24:24 UTC (rev 196546)
@@ -1,3 +1,56 @@
+2016-02-12  Nan Wang  <n_w...@apple.com>
+
+        AX: Implement paragraph related text marker functions using TextIterator
+        https://bugs.webkit.org/show_bug.cgi?id=154098
+        <rdar://problem/24269675>
+
+        Reviewed by Chris Fleizach.
+
+        * DumpRenderTree/AccessibilityUIElement.cpp:
+        (nextWordEndTextMarkerForTextMarkerCallback):
+        (paragraphTextMarkerRangeForTextMarkerCallback):
+        (previousParagraphStartTextMarkerForTextMarkerCallback):
+        (nextParagraphEndTextMarkerForTextMarkerCallback):
+        (setSelectedVisibleTextRangeCallback):
+        (AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
+        (AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker):
+        (AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker):
+        (AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker):
+        (AccessibilityUIElement::getJSClass):
+        * DumpRenderTree/AccessibilityUIElement.h:
+        * DumpRenderTree/ios/AccessibilityUIElementIOS.mm:
+        (AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
+        (AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker):
+        (AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker):
+        (AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker):
+        * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+        (AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
+        (AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker):
+        (AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker):
+        (AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker):
+        (AccessibilityUIElement::supportedActions):
+        * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp:
+        (WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
+        (WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
+        (WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
+        (WTR::AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker):
+        (WTR::AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker):
+        (WTR::AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker):
+        * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
+        * WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl:
+        * WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm:
+        (WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
+        (WTR::AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker):
+        (WTR::AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker):
+        (WTR::AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker):
+        (WTR::AccessibilityUIElement::mathPostscriptsDescription):
+        * WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm:
+        (WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
+        (WTR::AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker):
+        (WTR::AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker):
+        (WTR::AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker):
+        (WTR::_convertMathMultiscriptPairsToString):
+
 2016-02-12  Jason Marcell  <jmarc...@apple.com>
 
         Open source bot watcher's dashboard fails assertion in BuildbotQueue.prototype.compareIterationsByRevisions

Modified: trunk/Tools/DumpRenderTree/AccessibilityUIElement.cpp (196545 => 196546)


--- trunk/Tools/DumpRenderTree/AccessibilityUIElement.cpp	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Tools/DumpRenderTree/AccessibilityUIElement.cpp	2016-02-13 05:24:24 UTC (rev 196546)
@@ -1010,6 +1010,33 @@
     return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->nextWordEndTextMarkerForTextMarker(marker));
 }
 
+static JSValueRef paragraphTextMarkerRangeForTextMarkerCallback(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)->paragraphTextMarkerRangeForTextMarker(marker));
+}
+
+static JSValueRef previousParagraphStartTextMarkerForTextMarkerCallback(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)->previousParagraphStartTextMarkerForTextMarker(marker));
+}
+
+static JSValueRef nextParagraphEndTextMarkerForTextMarkerCallback(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)->nextParagraphEndTextMarkerForTextMarker(marker));
+}
+
 static JSValueRef setSelectedVisibleTextRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 {
     AccessibilityUIElement* uiElement = toAXElement(thisObject);
@@ -1620,6 +1647,21 @@
     return nullptr;
 }
 
+AccessibilityTextMarkerRange AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+    return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+    return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+    return nullptr;
+}
+
 #endif
 
 // Destruction
@@ -1804,6 +1846,9 @@
         { "rightWordTextMarkerRangeForTextMarker", rightWordTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "previousWordStartTextMarkerForTextMarker", previousWordStartTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "nextWordEndTextMarkerForTextMarker", nextWordEndTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+        { "paragraphTextMarkerRangeForTextMarker", paragraphTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+        { "previousParagraphStartTextMarkerForTextMarker", previousParagraphStartTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+        { "nextParagraphEndTextMarkerForTextMarker", nextParagraphEndTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "setSelectedChild", setSelectedChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "setSelectedChildAtIndex", setSelectedChildAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "removeSelectionAtIndex", removeSelectionAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },

Modified: trunk/Tools/DumpRenderTree/AccessibilityUIElement.h (196545 => 196546)


--- trunk/Tools/DumpRenderTree/AccessibilityUIElement.h	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Tools/DumpRenderTree/AccessibilityUIElement.h	2016-02-13 05:24:24 UTC (rev 196546)
@@ -264,6 +264,9 @@
     AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
     AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*);
     AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*);
+    AccessibilityTextMarkerRange paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+    AccessibilityTextMarker previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*);
+    AccessibilityTextMarker nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*);
     AccessibilityTextMarkerRange selectedTextMarkerRange();
     void resetSelectedTextMarkerRange();
     bool setSelectedVisibleTextRange(AccessibilityTextMarkerRange*);

Modified: trunk/Tools/DumpRenderTree/ios/AccessibilityUIElementIOS.mm (196545 => 196546)


--- trunk/Tools/DumpRenderTree/ios/AccessibilityUIElementIOS.mm	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Tools/DumpRenderTree/ios/AccessibilityUIElementIOS.mm	2016-02-13 05:24:24 UTC (rev 196546)
@@ -570,6 +570,21 @@
     return nullptr;
 }
 
+AccessibilityTextMarkerRange AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+    return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+    return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+    return nullptr;
+}
+
 #endif // SUPPORTS_AX_TEXTMARKERS && PLATFORM(IOS)
 
 #pragma mark Unused

Modified: trunk/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm (196545 => 196546)


--- trunk/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm	2016-02-13 05:24:24 UTC (rev 196546)
@@ -1886,6 +1886,36 @@
     return nullptr;
 }
 
+AccessibilityTextMarkerRange AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
+{
+    BEGIN_AX_OBJC_EXCEPTIONS
+    id textMarkerRange = [m_element accessibilityAttributeValue:@"AXParagraphTextMarkerRangeForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+    return AccessibilityTextMarkerRange(textMarkerRange);
+    END_AX_OBJC_EXCEPTIONS
+    
+    return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
+{
+    BEGIN_AX_OBJC_EXCEPTIONS
+    id previousTextMarker = [m_element accessibilityAttributeValue:@"AXPreviousParagraphStartTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+    return AccessibilityTextMarker(previousTextMarker);
+    END_AX_OBJC_EXCEPTIONS
+    
+    return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
+{
+    BEGIN_AX_OBJC_EXCEPTIONS
+    id nextTextMarker = [m_element accessibilityAttributeValue:@"AXNextParagraphEndTextMarkerForTextMarker" 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 (196545 => 196546)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp	2016-02-13 05:24:24 UTC (rev 196546)
@@ -249,6 +249,9 @@
 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; }
 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
 #endif
 
 } // namespace WTR

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h (196545 => 196546)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h	2016-02-13 05:24:24 UTC (rev 196546)
@@ -255,6 +255,9 @@
     PassRefPtr<AccessibilityTextMarkerRange> rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
     PassRefPtr<AccessibilityTextMarker> previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*);
     PassRefPtr<AccessibilityTextMarker> nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*);
+    PassRefPtr<AccessibilityTextMarkerRange> paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+    PassRefPtr<AccessibilityTextMarker> nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*);
+    PassRefPtr<AccessibilityTextMarker> previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*);
 
     // Returns an ordered list of supported actions for an element.
     JSRetainPtr<JSStringRef> supportedActions() const;

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl (196545 => 196546)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl	2016-02-13 05:24:24 UTC (rev 196546)
@@ -205,6 +205,9 @@
     AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker);
     AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
     AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
+    AccessibilityTextMarkerRange paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker);
+    AccessibilityTextMarker previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
+    AccessibilityTextMarker nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
 
     // Returns an ordered list of supported actions for an element.
     readonly attribute DOMString supportedActions;

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm (196545 => 196546)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm	2016-02-13 05:24:24 UTC (rev 196546)
@@ -1116,6 +1116,21 @@
     return nullptr;
 }
 
+PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
+{
+    return nullptr;
+}
+
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
+{
+    return nullptr;
+}
+
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
+{
+    return nullptr;
+}
+
 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const
 {
     return 0;

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm (196545 => 196546)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm	2016-02-13 04:52:01 UTC (rev 196545)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm	2016-02-13 05:24:24 UTC (rev 196546)
@@ -1913,6 +1913,36 @@
     return nullptr;
 }
 
+PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
+{
+    BEGIN_AX_OBJC_EXCEPTIONS
+    id textMarkerRange = [m_element accessibilityAttributeValue:@"AXParagraphTextMarkerRangeForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+    return AccessibilityTextMarkerRange::create(textMarkerRange);
+    END_AX_OBJC_EXCEPTIONS
+    
+    return nullptr;
+}
+
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
+{
+    BEGIN_AX_OBJC_EXCEPTIONS
+    id previousParagraphStartMarker = [m_element accessibilityAttributeValue:@"AXPreviousParagraphStartTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+    return AccessibilityTextMarker::create(previousParagraphStartMarker);
+    END_AX_OBJC_EXCEPTIONS
+    
+    return nullptr;
+}
+
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
+{
+    BEGIN_AX_OBJC_EXCEPTIONS
+    id nextParagraphEndMarker = [m_element accessibilityAttributeValue:@"AXNextParagraphEndTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+    return AccessibilityTextMarker::create(nextParagraphEndMarker);
+    END_AX_OBJC_EXCEPTIONS
+    
+    return nullptr;
+}
+
 static NSString *_convertMathMultiscriptPairsToString(NSArray *pairs)
 {
     __block NSMutableString *result = [NSMutableString string];
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to