AX: Implement bounds/position and index related text marker functions using TextIterator
authorn_wang@apple.com <n_wang@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Mar 2016 02:37:46 +0000 (02:37 +0000)
committern_wang@apple.com <n_wang@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Mar 2016 02:37:46 +0000 (02:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=154976

Reviewed by Chris Fleizach.

Source/WebCore:

Implemented position and index related text marker calls with TextIterator. Also fixed some
VoiceOver navigation issues.

Test: accessibility/mac/text-marker-for-index.html

* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::traverseToOffsetInRange):
(WebCore::AXObjectCache::startOrEndCharacterOffsetForRange):
(WebCore::AXObjectCache::textMarkerDataForCharacterOffset):
(WebCore::AXObjectCache::shouldSkipBoundary):
(WebCore::AXObjectCache::textMarkerDataForNextCharacterOffset):
(WebCore::AXObjectCache::startCharacterOffsetOfWord):
(WebCore::AXObjectCache::nextBoundary):
(WebCore::AXObjectCache::previousBoundary):
(WebCore::AXObjectCache::previousSentenceStartCharacterOffset):
(WebCore::AXObjectCache::localCaretRectForCharacterOffset):
(WebCore::AXObjectCache::absoluteCaretBoundsForCharacterOffset):
(WebCore::AXObjectCache::characterOffsetForPoint):
(WebCore::AXObjectCache::characterOffsetForBounds):
(WebCore::AXObjectCache::endCharacterOffsetOfLine):
(WebCore::AXObjectCache::startCharacterOffsetOfLine):
(WebCore::AXObjectCache::characterOffsetForIndex):
(WebCore::AXObjectCache::indexForCharacterOffset):
(WebCore::AXObjectCache::rootAXEditableElement):
* accessibility/AXObjectCache.h:
* accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::visiblePositionRangeForRange):
(WebCore::AccessibilityObject::rangeForPlainTextRange):
(WebCore::AccessibilityObject::lineRangeForPosition):
* accessibility/AccessibilityObject.h:
(WebCore::AccessibilityObject::boundsForVisiblePositionRange):
(WebCore::AccessibilityObject::boundsForRange):
(WebCore::AccessibilityObject::setSelectedVisiblePositionRange):
(WebCore::AccessibilityObject::doAXStringForRange):
(WebCore::AccessibilityObject::doAXBoundsForRange):
(WebCore::AccessibilityObject::doAXBoundsForRangeUsingCharacterOffset):
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::nodeIsTextControl):
(WebCore::AccessibilityRenderObject::boundsForRects):
(WebCore::AccessibilityRenderObject::boundsForVisiblePositionRange):
(WebCore::AccessibilityRenderObject::boundsForRange):
(WebCore::AccessibilityRenderObject::setSelectedVisiblePositionRange):
(WebCore::AccessibilityRenderObject::doAXBoundsForRange):
(WebCore::AccessibilityRenderObject::doAXBoundsForRangeUsingCharacterOffset):
(WebCore::AccessibilityRenderObject::accessibilityImageMapHitTest):
* accessibility/AccessibilityRenderObject.h:
* accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
(-[WebAccessibilityObjectWrapper positionForTextMarker:]):
(-[WebAccessibilityObjectWrapper textMarkerRange]):
(-[WebAccessibilityObjectWrapper textMarkerRangeForSelection]):
(-[WebAccessibilityObjectWrapper textMarkerForPosition:]):
(-[WebAccessibilityObjectWrapper _stringForRange:attributed:]):
(-[WebAccessibilityObjectWrapper frameForTextMarkers:]):
(-[WebAccessibilityObjectWrapper textMarkerForPoint:]):
(-[WebAccessibilityObjectWrapper nextMarkerForCharacterOffset:]):
* accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
(-[WebAccessibilityObjectWrapper doAXAttributedStringForRange:]):
(-[WebAccessibilityObjectWrapper _convertToNSRange:]):
(-[WebAccessibilityObjectWrapper _indexForTextMarker:]):
(-[WebAccessibilityObjectWrapper _textMarkerForIndex:]):
(-[WebAccessibilityObjectWrapper accessibilityAttributeValue:forParameter:]):
* editing/htmlediting.cpp:
(WebCore::localCaretRectInRendererForCaretPainting):
(WebCore::localCaretRectInRendererForRect):
* editing/htmlediting.h:

LayoutTests:

* accessibility/mac/text-marker-for-index-expected.txt: Added.
* accessibility/mac/text-marker-for-index.html: Added.
* accessibility/mac/text-marker-word-nav-expected.txt:
* accessibility/mac/text-marker-word-nav.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@197982 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
LayoutTests/ChangeLog
LayoutTests/accessibility/mac/text-marker-for-index-expected.txt [new file with mode: 0644]
LayoutTests/accessibility/mac/text-marker-for-index.html [new file with mode: 0644]
LayoutTests/accessibility/mac/text-marker-word-nav-expected.txt
LayoutTests/accessibility/mac/text-marker-word-nav.html
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AXObjectCache.cpp
Source/WebCore/accessibility/AXObjectCache.h
Source/WebCore/accessibility/AccessibilityObject.cpp
Source/WebCore/accessibility/AccessibilityObject.h
Source/WebCore/accessibility/AccessibilityRenderObject.cpp
Source/WebCore/accessibility/AccessibilityRenderObject.h
Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm
Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
Source/WebCore/editing/htmlediting.cpp
Source/WebCore/editing/htmlediting.h

index bc1593a2ad5abadb14ea3a8271eda5e4b6832360..97794c55620242715cf1daa0235c68e77b9bdf31 100644 (file)
@@ -1,3 +1,15 @@
+2016-03-10  Nan Wang  <n_wang@apple.com>
+
+        AX: Implement bounds/position and index related text marker functions using TextIterator
+        https://bugs.webkit.org/show_bug.cgi?id=154976
+
+        Reviewed by Chris Fleizach.
+
+        * accessibility/mac/text-marker-for-index-expected.txt: Added.
+        * accessibility/mac/text-marker-for-index.html: Added.
+        * accessibility/mac/text-marker-word-nav-expected.txt:
+        * accessibility/mac/text-marker-word-nav.html:
+
 2016-03-10  Myles C. Maxfield  <mmaxfield@apple.com>
 
         [Cocoa] Test gardening after r197933
diff --git a/LayoutTests/accessibility/mac/text-marker-for-index-expected.txt b/LayoutTests/accessibility/mac/text-marker-for-index-expected.txt
new file mode 100644 (file)
index 0000000..6408b4a
--- /dev/null
@@ -0,0 +1,25 @@
+text
+
+text
+audio file.
+This verifies that textMarkerForIndex and indexForTextMarker are working correctly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Original marker string: x
+Index is: 3
+New marker string: x
+
+Original marker string: 'line break'
+Index is: 6
+New marker string: 'line break'
+
+Original marker string: f
+Index is: 18
+New marker string: f
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/accessibility/mac/text-marker-for-index.html b/LayoutTests/accessibility/mac/text-marker-for-index.html
new file mode 100644 (file)
index 0000000..919ae7b
--- /dev/null
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<script src="../../resources/js-test-pre.js"></script>
+<body id="body" tabindex="0">
+
+<div tabindex="0" id="text1">text</div>
+<br>
+text
+
+<div id="text2">
+audio <audio controls><source src="test.mp3" type="audio/mpeg"></audio>file.
+</div>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+
+    description("This verifies that textMarkerForIndex and indexForTextMarker are working correctly.");
+
+    if (window.accessibilityController) {
+        var text = accessibilityController.accessibleElementById("text1");
+        // Get the actual text node.
+        text = text.childAtIndex(0);
+        
+        var previous, current;
+        var textMarkerRange = text.textMarkerRangeForElement(text);
+        var startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+        var result = forward(3, previous, startMarker, text);
+        previous = result.previous;
+        current = result.current;
+        verifyMarkerIndex(previous, current, text); 
+        
+        // BR
+        result = forward(2, previous, current, text);
+        previous = result.previous;
+        current = result.current;
+        verifyMarkerIndex(previous, current, text); 
+        
+        // Attachment
+        text = accessibilityController.accessibleElementById("text2");
+        textMarkerRange = text.textMarkerRangeForElement(text);
+        startMarker = text.startTextMarkerForTextMarkerRange(textMarkerRange);
+        result = forward(8, previous, startMarker, text);
+        previous = result.previous;
+        current = result.current;
+        verifyMarkerIndex(previous, current, text);
+    }
+    
+    
+    function forward(count, previousMarker, currentMarker, obj) {
+        for (var i = 0; i < count; i++) {
+            previousMarker = currentMarker;
+            currentMarker = obj.nextTextMarker(currentMarker);
+        }
+        return {
+            previous: previousMarker,
+            current: currentMarker
+        };
+    }
+    
+    function replaceLinebreakInString(str) {
+        var newline = '\n';
+        str = str.replace(newline, "'line break'");
+        return str;
+    }
+    
+    function verifyMarkerIndex(previousMarker, textMarker, obj) {
+        var markerRange = obj.textMarkerRangeForMarkers(previousMarker, textMarker);
+        var originalString = replaceLinebreakInString(obj.stringForTextMarkerRange(markerRange));
+        debug("Original marker string: " + originalString);
+        
+        var index = obj.indexForTextMarker(textMarker);
+        var newMarker = obj.textMarkerForIndex(index);
+        markerRange = obj.textMarkerRangeForMarkers(previousMarker, newMarker);
+        var newString = replaceLinebreakInString(obj.stringForTextMarkerRange(markerRange));
+        debug("Index is: " + index + "\nNew marker string: " + newString + "\n");
+    }
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+
+</body>
+</html>
\ No newline at end of file
index b2edcd1f7c0cdc765f60d3d08693ec8eeb08f5ea..64cf91db26ce5576c5b0b7bc2e80fcc77d58e5ce 100644 (file)
@@ -9,6 +9,8 @@ line breaks
 some
 text
 test audio file
+Edit text
+
 This tests that word navigation is working correctly.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
@@ -59,6 +61,11 @@ 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: select'line break'巧克力
+
 Current character is: 克
 Left word is: 巧克力
 Right word is: 巧克力
@@ -119,6 +126,11 @@ Left word is: file
 Right word is: file
 Pre word start to next word end: file
 
+Current character is: t
+Left word is: Edit
+Right word is:  
+Pre word start to next word end: Edit text
+
 Test going forward.
 End word: file
 
index a376878f57e6fa97b47789f3e4499cdecbf6b5b3..8bceb8c45339e48709c0982c5ac94d8e46a5ae02 100644 (file)
@@ -39,6 +39,11 @@ some<br>text
 test audio <audio controls><source src="test.mp3" type="audio/mpeg"></audio>file
 </div>
 
+<p id="text8">
+<strong>Edit</strong>
+text
+</p>
+
 <p id="description"></p>
 <div id="console"></div>
 
@@ -64,13 +69,13 @@ test audio <audio controls><source src="test.mp3" type="audio/mpeg"></audio>file
         // At "T" in "Thisis", should return the word as "Thisislongword".
         currentMarker = advanceAndVerify(currentMarker, 2, text);
         // At " " before "I", the word should be "I'll".
-        currentMarker = advanceAndVerify(currentMarker, 15, text);
+        currentMarker = advanceAndVerify(currentMarker, 14, text);
         // At " " before "try", the word should excludes "."
-        currentMarker = advanceAndVerify(currentMarker, 6, text);
+        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, 19, text);
+        currentMarker = advanceAndVerify(currentMarker, 18, text);
         
         // Check the case with replaced node, the replaced node should be considered a word.
         var text2 = accessibilityController.accessibleElementById("text2");
@@ -89,6 +94,8 @@ test audio <audio controls><source src="test.mp3" type="audio/mpeg"></audio>file
         var text4 = accessibilityController.accessibleElementById("text4");
         textMarkerRange = text4.textMarkerRangeForElement(text4);
         currentMarker = text4.startTextMarkerForTextMarkerRange(textMarkerRange);
+        // Make sure when we are at the beginning of line, it won't go to previous node.
+        currentMarker = advanceAndVerify(currentMarker, 0, text4);
         currentMarker = advanceAndVerify(currentMarker, 2, text4);
         currentMarker = advanceAndVerify(currentMarker, 1, text4);
         currentMarker = advanceAndVerify(currentMarker, 1, text4);
@@ -123,12 +130,18 @@ test audio <audio controls><source src="test.mp3" type="audio/mpeg"></audio>file
         currentMarker = advanceAndVerify(currentMarker, 1, text7);
         currentMarker = advanceAndVerify(currentMarker, 1, text7);
         
+        // For node with text node children, we should treat the visual space as word boundary.
+        var text8 = accessibilityController.accessibleElementById("text8");
+        textMarkerRange = text8.textMarkerRangeForElement(text8);
+        currentMarker = text8.startTextMarkerForTextMarkerRange(textMarkerRange);
+        currentMarker = advanceAndVerify(currentMarker, 4, text8);
+        
         // 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;
+            var previousMarker = currentMarker;
             for (var i = 0; i < offset; i++) {
                 previousMarker = currentMarker;
                 currentMarker = obj.nextTextMarker(previousMarker);
index 66aa3235de0ee429ce939f89c7361d8919eb7879..7ce629539182ca9bf481472115c0621c1c8d9cfb 100644 (file)
@@ -1,3 +1,76 @@
+2016-03-10  Nan Wang  <n_wang@apple.com>
+
+        AX: Implement bounds/position and index related text marker functions using TextIterator
+        https://bugs.webkit.org/show_bug.cgi?id=154976
+
+        Reviewed by Chris Fleizach.
+
+        Implemented position and index related text marker calls with TextIterator. Also fixed some
+        VoiceOver navigation issues.
+
+        Test: accessibility/mac/text-marker-for-index.html
+
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::AXObjectCache::traverseToOffsetInRange):
+        (WebCore::AXObjectCache::startOrEndCharacterOffsetForRange):
+        (WebCore::AXObjectCache::textMarkerDataForCharacterOffset):
+        (WebCore::AXObjectCache::shouldSkipBoundary):
+        (WebCore::AXObjectCache::textMarkerDataForNextCharacterOffset):
+        (WebCore::AXObjectCache::startCharacterOffsetOfWord):
+        (WebCore::AXObjectCache::nextBoundary):
+        (WebCore::AXObjectCache::previousBoundary):
+        (WebCore::AXObjectCache::previousSentenceStartCharacterOffset):
+        (WebCore::AXObjectCache::localCaretRectForCharacterOffset):
+        (WebCore::AXObjectCache::absoluteCaretBoundsForCharacterOffset):
+        (WebCore::AXObjectCache::characterOffsetForPoint):
+        (WebCore::AXObjectCache::characterOffsetForBounds):
+        (WebCore::AXObjectCache::endCharacterOffsetOfLine):
+        (WebCore::AXObjectCache::startCharacterOffsetOfLine):
+        (WebCore::AXObjectCache::characterOffsetForIndex):
+        (WebCore::AXObjectCache::indexForCharacterOffset):
+        (WebCore::AXObjectCache::rootAXEditableElement):
+        * accessibility/AXObjectCache.h:
+        * accessibility/AccessibilityObject.cpp:
+        (WebCore::AccessibilityObject::visiblePositionRangeForRange):
+        (WebCore::AccessibilityObject::rangeForPlainTextRange):
+        (WebCore::AccessibilityObject::lineRangeForPosition):
+        * accessibility/AccessibilityObject.h:
+        (WebCore::AccessibilityObject::boundsForVisiblePositionRange):
+        (WebCore::AccessibilityObject::boundsForRange):
+        (WebCore::AccessibilityObject::setSelectedVisiblePositionRange):
+        (WebCore::AccessibilityObject::doAXStringForRange):
+        (WebCore::AccessibilityObject::doAXBoundsForRange):
+        (WebCore::AccessibilityObject::doAXBoundsForRangeUsingCharacterOffset):
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::AccessibilityRenderObject::nodeIsTextControl):
+        (WebCore::AccessibilityRenderObject::boundsForRects):
+        (WebCore::AccessibilityRenderObject::boundsForVisiblePositionRange):
+        (WebCore::AccessibilityRenderObject::boundsForRange):
+        (WebCore::AccessibilityRenderObject::setSelectedVisiblePositionRange):
+        (WebCore::AccessibilityRenderObject::doAXBoundsForRange):
+        (WebCore::AccessibilityRenderObject::doAXBoundsForRangeUsingCharacterOffset):
+        (WebCore::AccessibilityRenderObject::accessibilityImageMapHitTest):
+        * accessibility/AccessibilityRenderObject.h:
+        * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
+        (-[WebAccessibilityObjectWrapper positionForTextMarker:]):
+        (-[WebAccessibilityObjectWrapper textMarkerRange]):
+        (-[WebAccessibilityObjectWrapper textMarkerRangeForSelection]):
+        (-[WebAccessibilityObjectWrapper textMarkerForPosition:]):
+        (-[WebAccessibilityObjectWrapper _stringForRange:attributed:]):
+        (-[WebAccessibilityObjectWrapper frameForTextMarkers:]):
+        (-[WebAccessibilityObjectWrapper textMarkerForPoint:]):
+        (-[WebAccessibilityObjectWrapper nextMarkerForCharacterOffset:]):
+        * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+        (-[WebAccessibilityObjectWrapper doAXAttributedStringForRange:]):
+        (-[WebAccessibilityObjectWrapper _convertToNSRange:]):
+        (-[WebAccessibilityObjectWrapper _indexForTextMarker:]):
+        (-[WebAccessibilityObjectWrapper _textMarkerForIndex:]):
+        (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:forParameter:]):
+        * editing/htmlediting.cpp:
+        (WebCore::localCaretRectInRendererForCaretPainting):
+        (WebCore::localCaretRectInRendererForRect):
+        * editing/htmlediting.h:
+
 2016-03-10  Simon Fraser  <simon.fraser@apple.com>
 
         Font antialiasing (smoothing) changes when elements are rendered into compositing layers
index 9d64a61e776a04273e312409890442285bd83470..151e9e75e6e916b03f761526aea9b5835510433c 100644 (file)
@@ -1506,8 +1506,9 @@ CharacterOffset AXObjectCache::traverseToOffsetInRange(RefPtr<Range>range, int o
                         currentNode = childNode;
                         hasReplacedNodeOrBR = true;
                     } else if (currentNode != previousNode) {
-                        // We should set the currentNode to previous one in case this is the last iteration.
-                        currentNode = previousNode;
+                        // We should set the start offset and length for the current node in case this is the last iteration.
+                        lastStartOffset = 1;
+                        lastLength = 0;
                         continue;
                     }
                 }
@@ -1695,6 +1696,10 @@ CharacterOffset AXObjectCache::startOrEndCharacterOffsetForRange(RefPtr<Range> r
     if (!range)
         return CharacterOffset();
     
+    // When getting the end CharacterOffset at node boundary, we don't want to collapse to the previous node.
+    if (!isStart && !range->endOffset())
+        return characterOffsetForNodeAndOffset(range->endContainer(), 0, TraverseOptionIncludeStart);
+    
     // If it's end text marker, we want to go to the end of the range, and stay within the range.
     bool stayWithinRange = !isStart;
     
@@ -1775,12 +1780,35 @@ void AXObjectCache::textMarkerDataForCharacterOffset(TextMarkerData& textMarkerD
     setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
 }
 
+bool AXObjectCache::shouldSkipBoundary(const CharacterOffset& previous, const CharacterOffset& next)
+{
+    // Match the behavior of VisiblePosition, we should skip the node boundary when there's no visual space or new line character.
+    if (previous.isNull() || next.isNull())
+        return false;
+    
+    if (previous.node == next.node)
+        return false;
+    
+    if (next.startIndex > 0 || next.offset > 0)
+        return false;
+    
+    CharacterOffset newLine = startCharacterOffsetOfLine(next);
+    if (next.isEqual(newLine))
+        return false;
+    
+    return true;
+}
+    
 void AXObjectCache::textMarkerDataForNextCharacterOffset(TextMarkerData& textMarkerData, const CharacterOffset& characterOffset)
 {
     CharacterOffset next = characterOffset;
+    CharacterOffset previous = characterOffset;
     do {
         next = nextCharacterOffset(next, false);
+        if (shouldSkipBoundary(previous, next))
+            next = nextCharacterOffset(next, false);
         textMarkerDataForCharacterOffset(textMarkerData, next);
+        previous = next;
     } while (textMarkerData.ignored);
 }
 
@@ -1958,7 +1986,10 @@ CharacterOffset AXObjectCache::startCharacterOffsetOfWord(const CharacterOffset&
         if (c.isEqual(endOfParagraph))
             return c;
         
-        c = nextCharacterOffset(characterOffset);
+        // We should consider the node boundary that splits words. Otherwise VoiceOver won't see it as space.
+        c = nextCharacterOffset(characterOffset, false);
+        if (shouldSkipBoundary(characterOffset, c))
+            c = nextCharacterOffset(c, false);
         if (c.isNull())
             return characterOffset;
     }
@@ -2106,6 +2137,10 @@ CharacterOffset AXObjectCache::nextBoundary(const CharacterOffset& characterOffs
     if (it.atEnd() && next == string.size())
         return end;
     
+    // We should consider the node boundary that splits words.
+    if (searchFunction == endWordBoundary && next - prefixLength == 1)
+        return nextCharacterOffset(characterOffset, false);
+    
     // The endSentenceBoundary function will include a line break at the end of the sentence.
     if (searchFunction == endSentenceBoundary && string[next - 1] == '\n')
         next--;
@@ -2160,7 +2195,7 @@ CharacterOffset AXObjectCache::previousBoundary(const CharacterOffset& character
     
     int characterCount = characterOffset.offset - (string.size() - suffixLength - next);
     // We don't want to go to the previous node if the node is at the start of a new line.
-    if (characterCount < 0 && (characterOffsetNodeIsBR(characterOffset) || string[string.size() - 1] == '\n'))
+    if (characterCount < 0 && (characterOffsetNodeIsBR(characterOffset) || string[string.size() - suffixLength - 1] == '\n'))
         characterCount = 0;
     return characterOffsetForNodeAndOffset(*characterOffset.node, characterCount, TraverseOptionIncludeStart);
 }
@@ -2283,6 +2318,133 @@ CharacterOffset AXObjectCache::previousSentenceStartCharacterOffset(const Charac
     return startCharacterOffsetOfSentence(previous);
 }
 
+LayoutRect AXObjectCache::localCaretRectForCharacterOffset(RenderObject*& renderer, const CharacterOffset& characterOffset)
+{
+    if (characterOffset.isNull()) {
+        renderer = nullptr;
+        return IntRect();
+    }
+    
+    Node* node = characterOffset.node;
+    
+    renderer = node->renderer();
+    if (!renderer)
+        return LayoutRect();
+    
+    InlineBox* inlineBox = nullptr;
+    int caretOffset;
+    // Use a collapsed range to get the position.
+    RefPtr<Range> range = rangeForUnorderedCharacterOffsets(characterOffset, characterOffset);
+    Position startPosition = range->startPosition();
+    startPosition.getInlineBoxAndOffset(DOWNSTREAM, inlineBox, caretOffset);
+    
+    if (inlineBox)
+        renderer = &inlineBox->renderer();
+    
+    return renderer->localCaretRect(inlineBox, caretOffset);
+}
+
+IntRect AXObjectCache::absoluteCaretBoundsForCharacterOffset(const CharacterOffset& characterOffset)
+{
+    RenderBlock* caretPainter = nullptr;
+    
+    // First compute a rect local to the renderer at the selection start.
+    RenderObject* renderer = nullptr;
+    LayoutRect localRect = localCaretRectForCharacterOffset(renderer, characterOffset);
+    
+    localRect = localCaretRectInRendererForRect(localRect, characterOffset.node, renderer, caretPainter);
+    return absoluteBoundsForLocalCaretRect(caretPainter, localRect);
+}
+
+CharacterOffset AXObjectCache::characterOffsetForPoint(const IntPoint &point, AccessibilityObject* obj)
+{
+    if (!obj)
+        return CharacterOffset();
+    
+    VisiblePosition vp = obj->visiblePositionForPoint(point);
+    RefPtr<Range> range = makeRange(vp, vp);
+    return startOrEndCharacterOffsetForRange(range, true);
+}
+
+CharacterOffset AXObjectCache::characterOffsetForPoint(const IntPoint &point)
+{
+    RefPtr<Range> caretRange = m_document.caretRangeFromPoint(LayoutPoint(point));
+    return startOrEndCharacterOffsetForRange(caretRange, true);
+}
+
+CharacterOffset AXObjectCache::characterOffsetForBounds(const IntRect& rect, bool first)
+{
+    if (rect.isEmpty())
+        return CharacterOffset();
+    
+    IntPoint corner = first ? rect.minXMinYCorner() : rect.maxXMaxYCorner();
+    CharacterOffset characterOffset = characterOffsetForPoint(corner);
+    
+    if (rect.contains(absoluteCaretBoundsForCharacterOffset(characterOffset).center()))
+        return characterOffset;
+    
+    // If the initial position is located outside the bounds adjust it incrementally as needed.
+    CharacterOffset nextCharOffset = nextCharacterOffset(characterOffset, false);
+    CharacterOffset previousCharOffset = previousCharacterOffset(characterOffset, false);
+    while (!nextCharOffset.isNull() || !previousCharOffset.isNull()) {
+        if (rect.contains(absoluteCaretBoundsForCharacterOffset(nextCharOffset).center()))
+            return nextCharOffset;
+        if (rect.contains(absoluteCaretBoundsForCharacterOffset(previousCharOffset).center()))
+            return previousCharOffset;
+        
+        nextCharOffset = nextCharacterOffset(nextCharOffset, false);
+        previousCharOffset = previousCharacterOffset(previousCharOffset, false);
+    }
+    
+    return CharacterOffset();
+}
+
+// FIXME: Remove VisiblePosition code after implementing this using CharacterOffset.
+CharacterOffset AXObjectCache::endCharacterOffsetOfLine(const CharacterOffset& characterOffset)
+{
+    if (characterOffset.isNull())
+        return CharacterOffset();
+    
+    VisiblePosition vp = visiblePositionFromCharacterOffset(characterOffset);
+    VisiblePosition endLine = endOfLine(vp);
+    
+    return characterOffsetFromVisiblePosition(endLine);
+}
+
+CharacterOffset AXObjectCache::startCharacterOffsetOfLine(const CharacterOffset& characterOffset)
+{
+    if (characterOffset.isNull())
+        return CharacterOffset();
+    
+    VisiblePosition vp = visiblePositionFromCharacterOffset(characterOffset);
+    VisiblePosition startLine = startOfLine(vp);
+    
+    return characterOffsetFromVisiblePosition(startLine);
+}
+
+CharacterOffset AXObjectCache::characterOffsetForIndex(int index, const AccessibilityObject* obj)
+{
+    if (!obj)
+        return CharacterOffset();
+    
+    // Since this would only work on rendered nodes, using VisiblePosition to create a collapsed
+    // range should be fine.
+    VisiblePosition vp = obj->visiblePositionForIndex(index);
+    RefPtr<Range> range = makeRange(vp, vp);
+    
+    return startOrEndCharacterOffsetForRange(range, true);
+}
+
+int AXObjectCache::indexForCharacterOffset(const CharacterOffset& characterOffset, AccessibilityObject* obj)
+{
+    // Create a collapsed range so that we can get the VisiblePosition from it.
+    RefPtr<Range> range = rangeForUnorderedCharacterOffsets(characterOffset, characterOffset);
+    if (!range)
+        return 0;
+    VisiblePosition vp = range->startPosition();
+    return obj->indexForVisiblePosition(vp);
+}
+
 const Element* AXObjectCache::rootAXEditableElement(const Node* node)
 {
     const Element* result = node->rootEditableElement();
index c1dd2962eabe3285cc445e330ff949918e5d13f2..9b56d5db33bd107c1960ced6db9a2b8f9e063ad1 100644 (file)
@@ -200,6 +200,7 @@ public:
     CharacterOffset nextCharacterOffset(const CharacterOffset&, bool ignoreNextNodeStart = true);
     CharacterOffset previousCharacterOffset(const CharacterOffset&, bool ignorePreviousNodeEnd = true);
     void startOrEndTextMarkerDataForRange(TextMarkerData&, RefPtr<Range>, bool);
+    CharacterOffset startOrEndCharacterOffsetForRange(RefPtr<Range>, bool);
     AccessibilityObject* accessibilityObjectForTextMarkerData(TextMarkerData&);
     RefPtr<Range> rangeForUnorderedCharacterOffsets(const CharacterOffset&, const CharacterOffset&);
     static RefPtr<Range> rangeForNodeContents(Node*);
@@ -220,6 +221,19 @@ public:
     RefPtr<Range> sentenceForCharacterOffset(const CharacterOffset&);
     CharacterOffset nextSentenceEndCharacterOffset(const CharacterOffset&);
     CharacterOffset previousSentenceStartCharacterOffset(const CharacterOffset&);
+    
+    // Bounds
+    CharacterOffset characterOffsetForPoint(const IntPoint&, AccessibilityObject*);
+    IntRect absoluteCaretBoundsForCharacterOffset(const CharacterOffset&);
+    CharacterOffset characterOffsetForBounds(const IntRect&, bool);
+    
+    // Lines
+    CharacterOffset endCharacterOffsetOfLine(const CharacterOffset&);
+    CharacterOffset startCharacterOffsetOfLine(const CharacterOffset&);
+    
+    // Index
+    CharacterOffset characterOffsetForIndex(int, const AccessibilityObject*);
+    int indexForCharacterOffset(const CharacterOffset&, AccessibilityObject*);
 
     enum AXNotification {
         AXActiveDescendantChanged,
@@ -321,7 +335,6 @@ protected:
     void setTextMarkerDataWithCharacterOffset(TextMarkerData&, const CharacterOffset&);
     UChar32 characterAfter(const CharacterOffset&);
     UChar32 characterBefore(const CharacterOffset&);
-    CharacterOffset startOrEndCharacterOffsetForRange(RefPtr<Range>, bool);
     CharacterOffset characterOffsetForNodeAndOffset(Node&, int, TraverseOption = TraverseOptionDefault);
     CharacterOffset previousBoundary(const CharacterOffset&, BoundarySearchFunction);
     CharacterOffset nextBoundary(const CharacterOffset&, BoundarySearchFunction);
@@ -331,6 +344,9 @@ protected:
     CharacterOffset endCharacterOffsetOfParagraph(const CharacterOffset&, EditingBoundaryCrossingRule = CannotCrossEditingBoundary);
     CharacterOffset startCharacterOffsetOfSentence(const CharacterOffset&);
     CharacterOffset endCharacterOffsetOfSentence(const CharacterOffset&);
+    CharacterOffset characterOffsetForPoint(const IntPoint&);
+    LayoutRect localCaretRectForCharacterOffset(RenderObject*&, const CharacterOffset&);
+    bool shouldSkipBoundary(const CharacterOffset&, const CharacterOffset&);
 
 private:
     AccessibilityObject* rootWebArea();
index 06a432aac29de7954a274a64acf2d135fd7db8f2..29297306788f873c4c444c0a75e6e3ad42a4729b 100644 (file)
@@ -1198,6 +1198,20 @@ VisiblePositionRange AccessibilityObject::visiblePositionRangeForRange(const Pla
     return VisiblePositionRange(startPosition, endPosition);
 }
 
+RefPtr<Range> AccessibilityObject::rangeForPlainTextRange(const PlainTextRange& range) const
+{
+    unsigned textLength = getLengthForTextRange();
+    if (range.start + range.length > textLength)
+        return nullptr;
+    
+    if (AXObjectCache* cache = axObjectCache()) {
+        CharacterOffset start = cache->characterOffsetForIndex(range.start, this);
+        CharacterOffset end = cache->characterOffsetForIndex(range.start + range.length, this);
+        return cache->rangeForUnorderedCharacterOffsets(start, end);
+    }
+    return nullptr;
+}
+
 VisiblePositionRange AccessibilityObject::lineRangeForPosition(const VisiblePosition& visiblePosition) const
 {
     VisiblePosition startPosition = startOfLine(visiblePosition);
index b89160477efdefc1c4e8cae3288947ced216c0db..75c08db5b82d501face0b517fe400d9c3c09b919 100644 (file)
@@ -835,10 +835,13 @@ public:
     VisiblePositionRange styleRangeForPosition(const VisiblePosition&) const;
     VisiblePositionRange visiblePositionRangeForRange(const PlainTextRange&) const;
     VisiblePositionRange lineRangeForPosition(const VisiblePosition&) const;
+    
+    RefPtr<Range> rangeForPlainTextRange(const PlainTextRange&) const;
 
     String stringForVisiblePositionRange(const VisiblePositionRange&) const;
     String stringForRange(RefPtr<Range>) const;
     virtual IntRect boundsForVisiblePositionRange(const VisiblePositionRange&) const { return IntRect(); }
+    virtual IntRect boundsForRange(const RefPtr<Range>) const { return IntRect(); }
     int lengthForVisiblePositionRange(const VisiblePositionRange&) const;
     virtual void setSelectedVisiblePositionRange(const VisiblePositionRange&) const { }
 
@@ -872,6 +875,7 @@ public:
 
     virtual String doAXStringForRange(const PlainTextRange&) const { return String(); }
     virtual IntRect doAXBoundsForRange(const PlainTextRange&) const { return IntRect(); }
+    virtual IntRect doAXBoundsForRangeUsingCharacterOffset(const PlainTextRange&) const { return IntRect(); }
     String listMarkerTextForNodeAndPosition(Node*, const VisiblePosition&) const;
 
     unsigned doAXLineForIndex(unsigned);
index d2f4c1abfca28bb47cd7be028063e57889861075..1bfc966e082b3f924cff5ab7273d521c426b61fb 100644 (file)
@@ -1962,6 +1962,26 @@ bool AccessibilityRenderObject::nodeIsTextControl(const Node* node) const
     return false;
 }
 
+IntRect AccessibilityRenderObject::boundsForRects(LayoutRect& rect1, LayoutRect& rect2, RefPtr<Range> dataRange) const
+{
+    LayoutRect ourRect = rect1;
+    ourRect.unite(rect2);
+    
+    // if the rectangle spans lines and contains multiple text chars, use the range's bounding box intead
+    if (rect1.maxY() != rect2.maxY()) {
+        LayoutRect boundingBox = dataRange->absoluteBoundingBox();
+        String rangeString = plainText(dataRange.get());
+        if (rangeString.length() > 1 && !boundingBox.isEmpty())
+            ourRect = boundingBox;
+    }
+    
+#if PLATFORM(MAC)
+    return m_renderer->view().frameView().contentsToScreen(snappedIntRect(ourRect));
+#else
+    return snappedIntRect(ourRect);
+#endif
+}
+
 IntRect AccessibilityRenderObject::boundsForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
 {
     if (visiblePositionRange.isNull())
@@ -1985,23 +2005,39 @@ IntRect AccessibilityRenderObject::boundsForVisiblePositionRange(const VisiblePo
         }
     }
     
-    LayoutRect ourrect = rect1;
-    ourrect.unite(rect2);
+    RefPtr<Range> dataRange = makeRange(range.start, range.end);
+    return boundsForRects(rect1, rect2, dataRange);
+}
+
+IntRect AccessibilityRenderObject::boundsForRange(const RefPtr<Range> range) const
+{
+    if (!range)
+        return IntRect();
     
-    // if the rectangle spans lines and contains multiple text chars, use the range's bounding box intead
-    if (rect1.maxY() != rect2.maxY()) {
-        RefPtr<Range> dataRange = makeRange(range.start, range.end);
-        LayoutRect boundingBox = dataRange->absoluteBoundingBox();
-        String rangeString = plainText(dataRange.get());
-        if (rangeString.length() > 1 && !boundingBox.isEmpty())
-            ourrect = boundingBox;
+    AXObjectCache* cache = this->axObjectCache();
+    if (!cache)
+        return IntRect();
+    
+    CharacterOffset start = cache->startOrEndCharacterOffsetForRange(range, true);
+    CharacterOffset end = cache->startOrEndCharacterOffsetForRange(range, false);
+    
+    LayoutRect rect1 = cache->absoluteCaretBoundsForCharacterOffset(start);
+    LayoutRect rect2 = cache->absoluteCaretBoundsForCharacterOffset(end);
+    
+    // readjust for position at the edge of a line. This is to exclude line rect that doesn't need to be accounted in the range bounds.
+    if (rect2.y() != rect1.y()) {
+        CharacterOffset endOfFirstLine = cache->endCharacterOffsetOfLine(start);
+        if (start.isEqual(endOfFirstLine)) {
+            start = cache->nextCharacterOffset(start, false);
+            rect1 = cache->absoluteCaretBoundsForCharacterOffset(start);
+        }
+        if (end.isEqual(endOfFirstLine)) {
+            end = cache->previousCharacterOffset(end, false);
+            rect2 = cache->absoluteCaretBoundsForCharacterOffset(end);
+        }
     }
     
-#if PLATFORM(MAC)
-    return m_renderer->view().frameView().contentsToScreen(snappedIntRect(ourrect));
-#else
-    return snappedIntRect(ourrect);
-#endif
+    return boundsForRects(rect1, rect2, range);
 }
     
 void AccessibilityRenderObject::setSelectedVisiblePositionRange(const VisiblePositionRange& range) const
@@ -2196,6 +2232,13 @@ IntRect AccessibilityRenderObject::doAXBoundsForRange(const PlainTextRange& rang
     return IntRect();
 }
 
+IntRect AccessibilityRenderObject::doAXBoundsForRangeUsingCharacterOffset(const PlainTextRange& range) const
+{
+    if (allowsTextRanges())
+        return boundsForRange(rangeForPlainTextRange(range));
+    return IntRect();
+}
+
 AccessibilityObject* AccessibilityRenderObject::accessibilityImageMapHitTest(HTMLAreaElement* area, const IntPoint& point) const
 {
     if (!area)
index 8f432f0c606081e70498581c01df1380d6619be8..1c5faae08de6a514785c4cb3d7eb6d2c5a29e088 100644 (file)
@@ -173,6 +173,8 @@ public:
     VisiblePositionRange visiblePositionRange() const override;
     VisiblePositionRange visiblePositionRangeForLine(unsigned) const override;
     IntRect boundsForVisiblePositionRange(const VisiblePositionRange&) const override;
+    IntRect boundsForRange(const RefPtr<Range>) const override;
+    IntRect boundsForRects(LayoutRect&, LayoutRect&, RefPtr<Range>) const;
     void setSelectedVisiblePositionRange(const VisiblePositionRange&) const override;
     bool supportsARIAFlowTo() const override;
     void ariaFlowToElements(AccessibilityChildrenVector&) const override;
@@ -200,6 +202,7 @@ public:
     
     String doAXStringForRange(const PlainTextRange&) const override;
     IntRect doAXBoundsForRange(const PlainTextRange&) const override;
+    IntRect doAXBoundsForRangeUsingCharacterOffset(const PlainTextRange&) const override;
     
     String stringValueForMSAA() const override;
     String stringRoleForMSAA() const override;
index 4d76cb0bd6b84a3d09c0bfd700b1b154cfea5a79..5d1c3296047275f8c1bb9f8a5a99bdf48d242d65 100644 (file)
@@ -2148,10 +2148,14 @@ static void AXAttributedStringAppendText(NSMutableAttributedString* attrString,
     if (!marker)
         return NSNotFound;    
 
-    VisibleSelection selection([marker visiblePosition]);
-    RefPtr<Range> range = selection.toNormalizedRange();
-    NSRange nsRange = [self _convertToNSRange:range.get()];
-    return nsRange.location;
+    if (AXObjectCache* cache = m_object->axObjectCache()) {
+        CharacterOffset characterOffset = [marker characterOffset];
+        // Create a collapsed range from the CharacterOffset object.
+        RefPtr<Range> range = cache->rangeForUnorderedCharacterOffsets(characterOffset, characterOffset);
+        NSRange nsRange = [self _convertToNSRange:range.get()];
+        return nsRange.location;
+    }
+    return NSNotFound;
 }
 
 - (NSArray *)textMarkerRange
@@ -2205,11 +2209,17 @@ static void AXAttributedStringAppendText(NSMutableAttributedString* attrString,
     VisibleSelection selection = m_object->selection();
     if (selection.isNone())
         return nil;
-    VisiblePosition startPosition = selection.visibleStart();
-    VisiblePosition endPosition = selection.visibleEnd();
+    
+    AXObjectCache* cache = m_object->axObjectCache();
+    if (!cache)
+        return nil;
+    
+    RefPtr<Range> range = selection.toNormalizedRange();
+    CharacterOffset start = cache->startOrEndCharacterOffsetForRange(range, true);
+    CharacterOffset end = cache->startOrEndCharacterOffsetForRange(range, false);
 
-    WebAccessibilityTextMarker* startMarker = [WebAccessibilityTextMarker textMarkerWithVisiblePosition:startPosition cache:m_object->axObjectCache()];
-    WebAccessibilityTextMarker* endMarker = [WebAccessibilityTextMarker textMarkerWithVisiblePosition:endPosition cache:m_object->axObjectCache()];
+    WebAccessibilityTextMarker* startMarker = [WebAccessibilityTextMarker textMarkerWithCharacterOffset:start cache:cache];
+    WebAccessibilityTextMarker* endMarker = [WebAccessibilityTextMarker textMarkerWithCharacterOffset:end cache:cache];
     if (!startMarker || !endMarker)
         return nil;
     
@@ -2224,11 +2234,13 @@ static void AXAttributedStringAppendText(NSMutableAttributedString* attrString,
     RefPtr<Range> range = [self _convertToDOMRange:NSMakeRange(position, 0)];
     if (!range)
         return nil;
-    
-    VisibleSelection selection = VisibleSelection(*range, DOWNSTREAM);
 
-    VisiblePosition visiblePosition = selection.visibleStart();
-    return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:visiblePosition cache:m_object->axObjectCache()];
+    AXObjectCache* cache = m_object->axObjectCache();
+    if (!cache)
+        return nil;
+    
+    CharacterOffset characterOffset = cache->startOrEndCharacterOffsetForRange(range, true);
+    return [WebAccessibilityTextMarker textMarkerWithCharacterOffset:characterOffset cache:cache];
 }
 
 - (id)_stringForRange:(NSRange)range attributed:(BOOL)attributed
@@ -2405,15 +2417,14 @@ static void AXAttributedStringAppendText(NSMutableAttributedString* attrString,
     if (![self _prepareAccessibilityCall])
         return CGRectZero;
 
-    if ([array count] != 2)
+    AXObjectCache* cache = m_object->axObjectCache();
+    if (!cache)
         return CGRectZero;
-    
-    WebAccessibilityTextMarker* startMarker = [array objectAtIndex:0];
-    WebAccessibilityTextMarker* endMarker = [array objectAtIndex:1];
-    if (![startMarker isKindOfClass:[WebAccessibilityTextMarker class]] || ![endMarker isKindOfClass:[WebAccessibilityTextMarker class]])
+    RefPtr<Range> range = [self rangeForTextMarkers:array];
+    if (!range)
         return CGRectZero;
-
-    IntRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange([startMarker visiblePosition], [endMarker visiblePosition]));
+    
+    IntRect rect = m_object->boundsForRange(range);
     return [self convertRectToScreenSpace:rect];
 }
 
@@ -2422,8 +2433,11 @@ static void AXAttributedStringAppendText(NSMutableAttributedString* attrString,
     if (![self _prepareAccessibilityCall])
         return nil;
     
-    VisiblePosition pos = m_object->visiblePositionForPoint(IntPoint(point));
-    return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:pos cache:m_object->axObjectCache()];
+    AXObjectCache* cache = m_object->axObjectCache();
+    if (!cache)
+        return nil;
+    CharacterOffset characterOffset = cache->characterOffsetForPoint(IntPoint(point), m_object);
+    return [WebAccessibilityTextMarker textMarkerWithCharacterOffset:characterOffset cache:cache];
 }
 
 - (WebAccessibilityTextMarker *)nextMarkerForCharacterOffset:(CharacterOffset&)characterOffset
index 248d398d886b77a1445909129415cc5c1408aed8..2ca69bc952d71c3eb8125c0fc559fff63e9c4092 100644 (file)
@@ -3776,8 +3776,8 @@ static RenderObject* rendererForView(NSView* view)
 - (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range
 {
     PlainTextRange textRange = PlainTextRange(range.location, range.length);
-    VisiblePositionRange visiblePosRange = m_object->visiblePositionRangeForRange(textRange);
-    return [self doAXAttributedStringForTextMarkerRange:[self textMarkerRangeFromVisiblePositions:visiblePosRange.start endPosition:visiblePosRange.end]];
+    RefPtr<Range> webRange = m_object->rangeForPlainTextRange(textRange);
+    return [self doAXAttributedStringForTextMarkerRange:[self textMarkerRangeFromRange:webRange]];
 }
 
 - (NSRange)_convertToNSRange:(Range*)range
@@ -3804,8 +3804,13 @@ static RenderObject* rendererForView(NSView* view)
     if (!marker)
         return NSNotFound;
     
-    VisibleSelection selection([self visiblePositionForTextMarker:marker]);
-    return [self _convertToNSRange:selection.toNormalizedRange().get()].location;
+    if (AXObjectCache* cache = m_object->axObjectCache()) {
+        CharacterOffset characterOffset = [self characterOffsetForTextMarker:marker];
+        // Create a collapsed range from the CharacterOffset object.
+        RefPtr<Range> range = cache->rangeForUnorderedCharacterOffsets(characterOffset, characterOffset);
+        return [self _convertToNSRange:range.get()].location;
+    }
+    return NSNotFound;
 }
 
 - (id)_textMarkerForIndex:(NSInteger)textIndex
@@ -3818,8 +3823,11 @@ static RenderObject* rendererForView(NSView* view)
     if (!textRange || !textRange->boundaryPointsValid())
         return nil;
     
-    VisiblePosition position(textRange->startPosition());
-    return [self textMarkerForVisiblePosition:position];
+    if (AXObjectCache* cache = m_object->axObjectCache()) {
+        CharacterOffset characterOffset = cache->startOrEndCharacterOffsetForRange(textRange, true);
+        return [self textMarkerForCharacterOffset:characterOffset];
+    }
+    return nil;
 }
 
 // The RTF representation of the text associated with this accessibility object that is
@@ -3907,6 +3915,10 @@ static void formatForDebugger(const VisiblePositionRange& range, char* buffer, u
     if (![self updateObjectBackingStore])
         return nil;
     
+    AXObjectCache* cache = m_object->axObjectCache();
+    if (!cache)
+        return nil;
+    
     // common parameter type check/casting.  Nil checks in handlers catch wrong type case.
     // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
     // a parameter of the wrong type.
@@ -3964,11 +3976,13 @@ static void formatForDebugger(const VisiblePositionRange& range, char* buffer, u
     
     if ([attribute isEqualToString:NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute]) {
         IntRect webCoreRect = [self screenToContents:enclosingIntRect(rect)];
-        return [self textMarkerForVisiblePosition:m_object->visiblePositionForBounds(webCoreRect, LastVisiblePositionForBounds)];
+        CharacterOffset characterOffset = cache->characterOffsetForBounds(webCoreRect, false);
+        return [self textMarkerForCharacterOffset:characterOffset];
     }
     if ([attribute isEqualToString:NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute]) {
         IntRect webCoreRect = [self screenToContents:enclosingIntRect(rect)];
-        return [self textMarkerForVisiblePosition:m_object->visiblePositionForBounds(webCoreRect, FirstVisiblePositionForBounds)];
+        CharacterOffset characterOffset = cache->characterOffsetForBounds(webCoreRect, true);
+        return [self textMarkerForCharacterOffset:characterOffset];
     }
     
     if ([attribute isEqualToString:NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute]) {
@@ -4017,30 +4031,35 @@ static void formatForDebugger(const VisiblePositionRange& range, char* buffer, u
     
     if ([attribute isEqualToString:@"AXTextMarkerForPosition"]) {
         IntPoint webCorePoint = IntPoint(point);
-        return pointSet ? [self textMarkerForVisiblePosition:m_object->visiblePositionForPoint(webCorePoint)] : nil;
+        if (!pointSet)
+            return nil;
+        CharacterOffset characterOffset = cache->characterOffsetForPoint(webCorePoint, m_object);
+        return [self textMarkerForCharacterOffset:characterOffset];
     }
     
     if ([attribute isEqualToString:@"AXBoundsForTextMarkerRange"]) {
-        VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
-        NSRect rect = m_object->boundsForVisiblePositionRange(visiblePosRange);
+        RefPtr<Range> range = [self rangeForTextMarkerRange:textMarkerRange];
+        NSRect rect = m_object->boundsForRange(range);
         return [NSValue valueWithRect:rect];
     }
     
     if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) {
-        VisiblePosition start = m_object->visiblePositionForIndex(range.location);
-        VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
+        CharacterOffset start = cache->characterOffsetForIndex(range.location, m_object);
+        CharacterOffset end = cache->characterOffsetForIndex(range.location+range.length, m_object);
         if (start.isNull() || end.isNull())
             return nil;
-        NSRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange(start, end));
+        RefPtr<Range> range = cache->rangeForUnorderedCharacterOffsets(start, end);
+        NSRect rect = m_object->boundsForRange(range);
         return [NSValue valueWithRect:rect];
     }
     
     if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
-        VisiblePosition start = m_object->visiblePositionForIndex(range.location);
-        VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
+        CharacterOffset start = cache->characterOffsetForIndex(range.location, m_object);
+        CharacterOffset end = cache->characterOffsetForIndex(range.location + range.length, m_object);
         if (start.isNull() || end.isNull())
             return nil;
-        return m_object->stringForVisiblePositionRange(VisiblePositionRange(start, end));
+        RefPtr<Range> range = cache->rangeForUnorderedCharacterOffsets(start, end);
+        return m_object->stringForRange(range);
     }
     
     if ([attribute isEqualToString:@"AXAttributedStringForTextMarkerRange"])
@@ -4055,9 +4074,6 @@ static void formatForDebugger(const VisiblePositionRange& range, char* buffer, u
         if (!AXObjectIsTextMarker(textMarker1) || !AXObjectIsTextMarker(textMarker2))
             return nil;
         
-        AXObjectCache* cache = m_object->axObjectCache();
-        if (!cache)
-            return nil;
         CharacterOffset characterOffset1 = [self characterOffsetForTextMarker:textMarker1];
         CharacterOffset characterOffset2 = [self characterOffsetForTextMarker:textMarker2];
         RefPtr<Range> range = cache->rangeForUnorderedCharacterOffsets(characterOffset1, characterOffset2);
@@ -4075,18 +4091,12 @@ static void formatForDebugger(const VisiblePositionRange& range, char* buffer, u
     }
     
     if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"]) {
-        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"]) {
-        AXObjectCache* cache = m_object->axObjectCache();
-        if (!cache)
-            return nil;
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
         RefPtr<Range> range = cache->rightWordRange(characterOffset);
         return [self textMarkerRangeFromRange:range];
@@ -4105,36 +4115,24 @@ static void formatForDebugger(const VisiblePositionRange& range, char* buffer, u
     }
     
     if ([attribute isEqualToString:@"AXSentenceTextMarkerRangeForTextMarker"]) {
-        AXObjectCache* cache = m_object->axObjectCache();
-        if (!cache)
-            return nil;
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
         RefPtr<Range> range = cache->sentenceForCharacterOffset(characterOffset);
         return [self textMarkerRangeFromRange:range];
     }
     
     if ([attribute isEqualToString:@"AXParagraphTextMarkerRangeForTextMarker"]) {
-        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"]) {
-        AXObjectCache* cache = m_object->axObjectCache();
-        if (!cache)
-            return nil;
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
         CharacterOffset nextEnd = cache->nextWordEndCharacterOffset(characterOffset);
         return [self textMarkerForCharacterOffset:nextEnd];
     }
     
     if ([attribute isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) {
-        AXObjectCache* cache = m_object->axObjectCache();
-        if (!cache)
-            return nil;
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
         CharacterOffset previousStart = cache->previousWordStartCharacterOffset(characterOffset);
         return [self textMarkerForCharacterOffset:previousStart];
@@ -4151,36 +4149,24 @@ static void formatForDebugger(const VisiblePositionRange& range, char* buffer, u
     }
     
     if ([attribute isEqualToString:@"AXNextSentenceEndTextMarkerForTextMarker"]) {
-        AXObjectCache* cache = m_object->axObjectCache();
-        if (!cache)
-            return nil;
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
         CharacterOffset nextEnd = cache->nextSentenceEndCharacterOffset(characterOffset);
         return [self textMarkerForCharacterOffset:nextEnd];
     }
     
     if ([attribute isEqualToString:@"AXPreviousSentenceStartTextMarkerForTextMarker"]) {
-        AXObjectCache* cache = m_object->axObjectCache();
-        if (!cache)
-            return nil;
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
         CharacterOffset previousStart = cache->previousSentenceStartCharacterOffset(characterOffset);
         return [self textMarkerForCharacterOffset:previousStart];
     }
     
     if ([attribute isEqualToString:@"AXNextParagraphEndTextMarkerForTextMarker"]) {
-        AXObjectCache* cache = m_object->axObjectCache();
-        if (!cache)
-            return nil;
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
         CharacterOffset nextEnd = cache->nextParagraphEndCharacterOffset(characterOffset);
         return [self textMarkerForCharacterOffset:nextEnd];
     }
     
     if ([attribute isEqualToString:@"AXPreviousParagraphStartTextMarkerForTextMarker"]) {
-        AXObjectCache* cache = m_object->axObjectCache();
-        if (!cache)
-            return nil;
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
         CharacterOffset previousStart = cache->previousParagraphStartCharacterOffset(characterOffset);
         return [self textMarkerForCharacterOffset:previousStart];
@@ -4276,7 +4262,7 @@ static void formatForDebugger(const VisiblePositionRange& range, char* buffer, u
             if (!rangeSet)
                 return nil;
             PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
-            NSRect rect = m_object->doAXBoundsForRange(plainTextRange);
+            NSRect rect = m_object->doAXBoundsForRangeUsingCharacterOffset(plainTextRange);
             return [NSValue valueWithRect:rect];
         }
         
index a24e5024dd29a6cc096b0e0c7e93e1c4417021a8..607dc7acd516b20759228b275d922a9d29c681f3 100644 (file)
@@ -1320,9 +1320,14 @@ LayoutRect localCaretRectInRendererForCaretPainting(const VisiblePosition& caret
     RenderObject* renderer;
     LayoutRect localRect = caretPosition.localCaretRect(renderer);
 
+    return localCaretRectInRendererForRect(localRect, caretPosition.deepEquivalent().deprecatedNode(), renderer, caretPainter);
+}
+
+LayoutRect localCaretRectInRendererForRect(LayoutRect& localRect, Node* node, RenderObject* renderer, RenderBlock*& caretPainter)
+{
     // Get the renderer that will be responsible for painting the caret
     // (which is either the renderer we just found, or one of its containers).
-    caretPainter = rendererForCaretPainting(caretPosition.deepEquivalent().deprecatedNode());
+    caretPainter = rendererForCaretPainting(node);
 
     // Compute an offset between the renderer and the caretPainter.
     while (renderer != caretPainter) {
index e408468a6dc797ed98179e45fb3ad71ef2a8780f..6349efc2ed8e28f56058b6023266e1fc757d08f5 100644 (file)
@@ -269,6 +269,7 @@ const String& nonBreakingSpaceString();
 
 RenderBlock* rendererForCaretPainting(Node*);
 LayoutRect localCaretRectInRendererForCaretPainting(const VisiblePosition&, RenderBlock*&);
+LayoutRect localCaretRectInRendererForRect(LayoutRect&, Node*, RenderObject*, RenderBlock*&);
 IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, const LayoutRect&);
 
 }