Changeset 196352 in webkit


Ignore:
Timestamp:
Feb 9, 2016 6:33:04 PM (8 years ago)
Author:
n_wang@apple.com
Message:

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

Reviewed by Chris Fleizach.

Source/WebCore:

Using CharacterOffset to implement word related text marker calls. Reused
logic from previousBoundary and nextBoundary in VisibleUnits class.

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

  • accessibility/AXObjectCache.cpp:

(WebCore::AXObjectCache::traverseToOffsetInRange):
(WebCore::AXObjectCache::rangeForNodeContents):
(WebCore::isReplacedNodeOrBR):
(WebCore::characterOffsetsInOrder):
(WebCore::resetNodeAndOffsetForReplacedNode):
(WebCore::setRangeStartOrEndWithCharacterOffset):
(WebCore::AXObjectCache::rangeForUnorderedCharacterOffsets):
(WebCore::AXObjectCache::setTextMarkerDataWithCharacterOffset):
(WebCore::AXObjectCache::startOrEndCharacterOffsetForRange):
(WebCore::AXObjectCache::startOrEndTextMarkerDataForRange):
(WebCore::AXObjectCache::characterOffsetForNodeAndOffset):
(WebCore::AXObjectCache::textMarkerDataForCharacterOffset):
(WebCore::AXObjectCache::previousNode):
(WebCore::AXObjectCache::visiblePositionFromCharacterOffset):
(WebCore::AXObjectCache::characterOffsetFromVisiblePosition):
(WebCore::AXObjectCache::textMarkerDataForVisiblePosition):
(WebCore::AXObjectCache::nextCharacterOffset):
(WebCore::AXObjectCache::previousCharacterOffset):
(WebCore::startWordBoundary):
(WebCore::endWordBoundary):
(WebCore::AXObjectCache::startCharacterOffsetOfWord):
(WebCore::AXObjectCache::endCharacterOffsetOfWord):
(WebCore::AXObjectCache::previousWordStartCharacterOffset):
(WebCore::AXObjectCache::nextWordEndCharacterOffset):
(WebCore::AXObjectCache::leftWordRange):
(WebCore::AXObjectCache::rightWordRange):
(WebCore::characterForCharacterOffset):
(WebCore::AXObjectCache::characterAfter):
(WebCore::AXObjectCache::characterBefore):
(WebCore::parentEditingBoundary):
(WebCore::AXObjectCache::nextWordBoundary):
(WebCore::AXObjectCache::previousWordBoundary):
(WebCore::AXObjectCache::rootAXEditableElement):

  • accessibility/AXObjectCache.h:

(WebCore::AXObjectCache::removeNodeForUse):
(WebCore::AXObjectCache::isNodeInUse):

  • accessibility/mac/WebAccessibilityObjectWrapperMac.mm:

(-[WebAccessibilityObjectWrapper previousTextMarkerForNode:offset:]):
(-[WebAccessibilityObjectWrapper textMarkerForNode:offset:ignoreStart:]):
(-[WebAccessibilityObjectWrapper textMarkerForNode:offset:]):
(textMarkerForCharacterOffset):
(-[WebAccessibilityObjectWrapper accessibilityAttributeValue:forParameter:]):

  • editing/VisibleUnits.cpp:

(WebCore::rightWordPosition):
(WebCore::prepend):
(WebCore::appendRepeatedCharacter):
(WebCore::suffixLengthForRange):
(WebCore::prefixLengthForRange):
(WebCore::backwardSearchForBoundaryWithTextIterator):
(WebCore::forwardSearchForBoundaryWithTextIterator):
(WebCore::previousBoundary):
(WebCore::nextBoundary):

  • editing/VisibleUnits.h:

Tools:

  • DumpRenderTree/AccessibilityUIElement.cpp:

(endTextMarkerCallback):
(leftWordTextMarkerRangeForTextMarkerCallback):
(rightWordTextMarkerRangeForTextMarkerCallback):
(previousWordStartTextMarkerForTextMarkerCallback):
(nextWordEndTextMarkerForTextMarkerCallback):
(setSelectedVisibleTextRangeCallback):
(AccessibilityUIElement::setSelectedVisibleTextRange):
(AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
(AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
(AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
(AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(AccessibilityUIElement::getJSClass):

  • DumpRenderTree/AccessibilityUIElement.h:
  • DumpRenderTree/ios/AccessibilityUIElementIOS.mm:

(AccessibilityUIElement::setSelectedVisibleTextRange):
(AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
(AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
(AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
(AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):

  • DumpRenderTree/mac/AccessibilityUIElementMac.mm:

(AccessibilityUIElement::setSelectedVisibleTextRange):
(AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
(AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
(AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
(AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(AccessibilityUIElement::supportedActions):

  • WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp:

(WTR::AccessibilityUIElement::setBoolAttributeValue):
(WTR::AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):

  • WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
  • WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl:
  • WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm:

(WTR::AccessibilityUIElement::endTextMarker):
(WTR::AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::mathPostscriptsDescription):

  • WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm:

(WTR::AccessibilityUIElement::endTextMarker):
(WTR::AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
(WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
(WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
(WTR::_convertMathMultiscriptPairsToString):

LayoutTests:

  • accessibility/mac/text-marker-word-nav-expected.txt: Added.
  • accessibility/mac/text-marker-word-nav.html: Added.
  • accessibility/text-marker/text-marker-previous-next-expected.txt:
  • accessibility/text-marker/text-marker-previous-next.html:
Location:
trunk
Files:
2 added
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r196346 r196352  
     12016-02-09  Nan Wang  <n_wang@apple.com>
     2
     3        AX: Implement word related text marker functions using TextIterator
     4        https://bugs.webkit.org/show_bug.cgi?id=153939
     5        <rdar://problem/24269605>
     6
     7        Reviewed by Chris Fleizach.
     8
     9        * accessibility/mac/text-marker-word-nav-expected.txt: Added.
     10        * accessibility/mac/text-marker-word-nav.html: Added.
     11        * accessibility/text-marker/text-marker-previous-next-expected.txt:
     12        * accessibility/text-marker/text-marker-previous-next.html:
     13
    1142016-02-09  Ryan Haddad  <ryanhaddad@apple.com>
    215
  • trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next-expected.txt

    r195405 r196352  
    1313PASS text.accessibilityElementForTextMarker(startMarker).isEqual(text) is true
    1414PASS text.accessibilityElementForTextMarker(endMarker).isEqual(text) is true
    15 PASS text.stringForTextMarkerRange(markerRange) is ''
     15PASS text.stringForTextMarkerRange(markerRange) is newline
    1616PASS text.stringForTextMarkerRange(markerRange) is 't'
    17 PASS text.stringForTextMarkerRange(markerRange) is ''
     17PASS text.stringForTextMarkerRange(markerRange) is newline
    1818PASS text.stringForTextMarkerRange(markerRange) is 't'
    1919PASS text2.textMarkerRangeLength(textMarkerRange2) is 5
  • trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next.html

    r195405 r196352  
    5151        }
    5252        markerRange = text.textMarkerRangeForMarkers(previousMarker, currentMarker);
    53         shouldBe("text.stringForTextMarkerRange(markerRange)", "''");
     53        var newline = '\n';
     54        shouldBe("text.stringForTextMarkerRange(markerRange)", "newline");
    5455       
    5556        // Advance one more character, it will lande at "t" in "text1".
     
    6364        currentMarker = text.previousTextMarker(currentMarker);
    6465        markerRange = text.textMarkerRangeForMarkers(previousMarker, currentMarker);
    65         shouldBe("text.stringForTextMarkerRange(markerRange)", "''");
     66        shouldBe("text.stringForTextMarkerRange(markerRange)", "newline");
    6667       
    6768        // Traverse backwards one more character, it will land at the last character of "text".
  • trunk/Source/WebCore/ChangeLog

    r196350 r196352  
     12016-02-09  Nan Wang  <n_wang@apple.com>
     2
     3        AX: Implement word related text marker functions using TextIterator
     4        https://bugs.webkit.org/show_bug.cgi?id=153939
     5        <rdar://problem/24269605>
     6
     7        Reviewed by Chris Fleizach.
     8
     9        Using CharacterOffset to implement word related text marker calls. Reused
     10        logic from previousBoundary and nextBoundary in VisibleUnits class.
     11
     12        Test: accessibility/mac/text-marker-word-nav.html
     13
     14        * accessibility/AXObjectCache.cpp:
     15        (WebCore::AXObjectCache::traverseToOffsetInRange):
     16        (WebCore::AXObjectCache::rangeForNodeContents):
     17        (WebCore::isReplacedNodeOrBR):
     18        (WebCore::characterOffsetsInOrder):
     19        (WebCore::resetNodeAndOffsetForReplacedNode):
     20        (WebCore::setRangeStartOrEndWithCharacterOffset):
     21        (WebCore::AXObjectCache::rangeForUnorderedCharacterOffsets):
     22        (WebCore::AXObjectCache::setTextMarkerDataWithCharacterOffset):
     23        (WebCore::AXObjectCache::startOrEndCharacterOffsetForRange):
     24        (WebCore::AXObjectCache::startOrEndTextMarkerDataForRange):
     25        (WebCore::AXObjectCache::characterOffsetForNodeAndOffset):
     26        (WebCore::AXObjectCache::textMarkerDataForCharacterOffset):
     27        (WebCore::AXObjectCache::previousNode):
     28        (WebCore::AXObjectCache::visiblePositionFromCharacterOffset):
     29        (WebCore::AXObjectCache::characterOffsetFromVisiblePosition):
     30        (WebCore::AXObjectCache::textMarkerDataForVisiblePosition):
     31        (WebCore::AXObjectCache::nextCharacterOffset):
     32        (WebCore::AXObjectCache::previousCharacterOffset):
     33        (WebCore::startWordBoundary):
     34        (WebCore::endWordBoundary):
     35        (WebCore::AXObjectCache::startCharacterOffsetOfWord):
     36        (WebCore::AXObjectCache::endCharacterOffsetOfWord):
     37        (WebCore::AXObjectCache::previousWordStartCharacterOffset):
     38        (WebCore::AXObjectCache::nextWordEndCharacterOffset):
     39        (WebCore::AXObjectCache::leftWordRange):
     40        (WebCore::AXObjectCache::rightWordRange):
     41        (WebCore::characterForCharacterOffset):
     42        (WebCore::AXObjectCache::characterAfter):
     43        (WebCore::AXObjectCache::characterBefore):
     44        (WebCore::parentEditingBoundary):
     45        (WebCore::AXObjectCache::nextWordBoundary):
     46        (WebCore::AXObjectCache::previousWordBoundary):
     47        (WebCore::AXObjectCache::rootAXEditableElement):
     48        * accessibility/AXObjectCache.h:
     49        (WebCore::AXObjectCache::removeNodeForUse):
     50        (WebCore::AXObjectCache::isNodeInUse):
     51        * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
     52        (-[WebAccessibilityObjectWrapper previousTextMarkerForNode:offset:]):
     53        (-[WebAccessibilityObjectWrapper textMarkerForNode:offset:ignoreStart:]):
     54        (-[WebAccessibilityObjectWrapper textMarkerForNode:offset:]):
     55        (textMarkerForCharacterOffset):
     56        (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:forParameter:]):
     57        * editing/VisibleUnits.cpp:
     58        (WebCore::rightWordPosition):
     59        (WebCore::prepend):
     60        (WebCore::appendRepeatedCharacter):
     61        (WebCore::suffixLengthForRange):
     62        (WebCore::prefixLengthForRange):
     63        (WebCore::backwardSearchForBoundaryWithTextIterator):
     64        (WebCore::forwardSearchForBoundaryWithTextIterator):
     65        (WebCore::previousBoundary):
     66        (WebCore::nextBoundary):
     67        * editing/VisibleUnits.h:
     68
    1692016-02-09  Daniel Bates  <dabates@apple.com>
    270
  • trunk/Source/WebCore/accessibility/AXObjectCache.cpp

    r196287 r196352  
    8282#include "RenderView.h"
    8383#include "ScrollView.h"
     84#include "TextBoundaries.h"
    8485#include "TextIterator.h"
    8586#include <wtf/DataLog.h>
     
    14711472    for (; !iterator.atEnd(); iterator.advance()) {
    14721473        int currentLength = iterator.text().length();
     1474        bool hasReplacedNodeOrBR = false;
    14731475       
    14741476        Node& node = iterator.range()->startContainer();
     
    14831485                currentLength++;
    14841486                currentNode = childNode;
     1487                hasReplacedNodeOrBR = true;
    14851488            } else
    14861489                continue;
    14871490        } else {
    14881491            // Ignore space, new line, tag node.
    1489             if (currentLength == 1 && isSpaceOrNewline(iterator.text()[0]))
    1490                 continue;
     1492            if (currentLength == 1) {
     1493                if (isSpaceOrNewline(iterator.text()[0])) {
     1494                    // If the node has BR tag, we want to set the currentNode to it.
     1495                    int subOffset = iterator.range()->startOffset();
     1496                    Node* childNode = node.traverseToChildAt(subOffset);
     1497                    if (childNode && childNode->renderer() && childNode->renderer()->isBR()) {
     1498                        currentNode = childNode;
     1499                        hasReplacedNodeOrBR = true;
     1500                    } else
     1501                        continue;
     1502                }
     1503            }
    14911504            offsetSoFar += currentLength;
    14921505        }
    14931506
    14941507        lastLength = currentLength;
    1495         lastStartOffset = iterator.range()->startOffset();
     1508        lastStartOffset = hasReplacedNodeOrBR ? 0 : iterator.range()->startOffset();
    14961509       
    14971510        // Break early if we have advanced enough characters.
     
    15471560    return ec ? nullptr : range;
    15481561}
     1562   
     1563static bool isReplacedNodeOrBR(Node* node)
     1564{
     1565    return node && (AccessibilityObject::replacedNodeNeedsCharacter(node) || node->hasTagName(brTag));
     1566}
    15491567
    15501568static bool characterOffsetsInOrder(const CharacterOffset& characterOffset1, const CharacterOffset& characterOffset2)
     
    15561574        return characterOffset1.offset <= characterOffset2.offset;
    15571575   
    1558     RefPtr<Range> range1 = AXObjectCache::rangeForNodeContents(characterOffset1.node);
    1559     RefPtr<Range> range2 = AXObjectCache::rangeForNodeContents(characterOffset2.node);
     1576    Node* node1 = characterOffset1.node;
     1577    Node* node2 = characterOffset2.node;
     1578    if (!node1->offsetInCharacters() && !isReplacedNodeOrBR(node1))
     1579        node1 = node1->traverseToChildAt(characterOffset1.offset);
     1580    if (!node2->offsetInCharacters() && !isReplacedNodeOrBR(node2))
     1581        node2 = node2->traverseToChildAt(characterOffset2.offset);
     1582   
     1583    if (!node1 || !node2)
     1584        return false;
     1585   
     1586    RefPtr<Range> range1 = AXObjectCache::rangeForNodeContents(node1);
     1587    RefPtr<Range> range2 = AXObjectCache::rangeForNodeContents(node2);
    15601588    return range1->compareBoundaryPoints(Range::START_TO_START, range2.get(), IGNORE_EXCEPTION) <= 0;
    15611589}
     
    15731601}
    15741602
    1575 static bool isReplacedNodeOrBR(Node* node)
    1576 {
    1577     return AccessibilityObject::replacedNodeNeedsCharacter(node) || node->hasTagName(brTag);
     1603static void setRangeStartOrEndWithCharacterOffset(RefPtr<Range> range, CharacterOffset& characterOffset, bool isStart, ExceptionCode& ec)
     1604{
     1605    if (!range) {
     1606        ec = RangeError;
     1607        return;
     1608    }
     1609    if (characterOffset.isNull()) {
     1610        ec = TypeError;
     1611        return;
     1612    }
     1613   
     1614    int offset = characterOffset.startIndex + characterOffset.offset;
     1615    Node* node = characterOffset.node;
     1616    if (isReplacedNodeOrBR(node))
     1617        node = resetNodeAndOffsetForReplacedNode(node, offset, characterOffset.offset);
     1618   
     1619    if (isStart)
     1620        range->setStart(node, offset, ec);
     1621    else
     1622        range->setEnd(node, offset, ec);
    15781623}
    15791624
     
    15871632    CharacterOffset endCharacterOffset = alreadyInOrder ? characterOffset2 : characterOffset1;
    15881633   
    1589     int startOffset = startCharacterOffset.startIndex + startCharacterOffset.offset;
    1590     int endOffset = endCharacterOffset.startIndex + endCharacterOffset.offset;
    1591     Node* startNode = startCharacterOffset.node;
    1592     Node* endNode = endCharacterOffset.node;
    1593    
    1594     // Consider the case when the replaced node is at the start/end of the range.
    1595     bool startNodeIsReplacedOrBR = isReplacedNodeOrBR(startNode);
    1596     bool endNodeIsReplacedOrBR = isReplacedNodeOrBR(endNode);
    1597     if (startNodeIsReplacedOrBR || endNodeIsReplacedOrBR) {
    1598         // endOffset can be out of bounds sometimes if the node is a replaced node or has brTag and it has no children.
    1599         if (startNode == endNode && !startNode->hasChildNodes()) {
    1600             RefPtr<Range> nodeRange = AXObjectCache::rangeForNodeContents(startNode);
    1601             int nodeLength = TextIterator::rangeLength(nodeRange.get());
    1602             if (endCharacterOffset.offset > nodeLength)
    1603                 endOffset = endCharacterOffset.startIndex + nodeLength;
    1604         } else {
    1605             if (startNodeIsReplacedOrBR)
    1606                 startNode = resetNodeAndOffsetForReplacedNode(startNode, startOffset, startCharacterOffset.offset);
    1607             if (endNodeIsReplacedOrBR)
    1608                 endNode = resetNodeAndOffsetForReplacedNode(startNode, endOffset, startCharacterOffset.offset);
    1609         }
    1610     }
    1611    
    16121634    RefPtr<Range> result = Range::create(m_document);
    1613     ExceptionCode ecStart = 0, ecEnd = 0;
    1614     result->setStart(startNode, startOffset, ecStart);
    1615     result->setEnd(endNode, endOffset, ecEnd);
    1616     if (ecStart || ecEnd)
     1635    ExceptionCode ec = 0;
     1636    setRangeStartOrEndWithCharacterOffset(result, startCharacterOffset, true, ec);
     1637    setRangeStartOrEndWithCharacterOffset(result, endCharacterOffset, false, ec);
     1638    if (ec)
    16171639        return nullptr;
    16181640   
     
    16361658   
    16371659    // Convert to visible position.
    1638     VisiblePosition visiblePosition = visiblePositionFromCharacterOffset(obj.get(), characterOffset);
     1660    VisiblePosition visiblePosition = visiblePositionFromCharacterOffset(characterOffset);
    16391661    int vpOffset = 0;
    16401662    if (!visiblePosition.isNull()) {
     
    16531675}
    16541676
    1655 void AXObjectCache::startOrEndTextMarkerDataForRange(TextMarkerData& textMarkerData, RefPtr<Range> range, bool isStart)
    1656 {
    1657     memset(&textMarkerData, 0, sizeof(TextMarkerData));
    1658    
     1677CharacterOffset AXObjectCache::startOrEndCharacterOffsetForRange(RefPtr<Range> range, bool isStart)
     1678{
    16591679    if (!range)
    1660         return;
     1680        return CharacterOffset();
    16611681   
    16621682    // If it's end text marker, we want to go to the end of the range, and stay within the range.
    16631683    bool stayWithinRange = !isStart;
    16641684   
     1685    RefPtr<Range> copyRange = range;
    16651686    // Change the start of the range, so the character offset starts from node beginning.
    16661687    int offset = 0;
    1667     Node* node = &range->startContainer();
     1688    Node* node = &copyRange->startContainer();
    16681689    if (node->offsetInCharacters()) {
     1690        copyRange = Range::create(range->ownerDocument(), &range->startContainer(), range->startOffset(), &range->endContainer(), range->endOffset());
    16691691        CharacterOffset nodeStartOffset = traverseToOffsetInRange(rangeForNodeContents(node), 0, false);
    1670         offset = std::max(range->startOffset() - nodeStartOffset.startIndex, 0);
    1671         range->setStart(node, nodeStartOffset.startIndex);
    1672     }
    1673    
    1674     CharacterOffset characterOffset = traverseToOffsetInRange(range, offset, !isStart, stayWithinRange);
     1692        offset = std::max(copyRange->startOffset() - nodeStartOffset.startIndex, 0);
     1693        copyRange->setStart(node, nodeStartOffset.startIndex);
     1694    }
     1695   
     1696    return traverseToOffsetInRange(copyRange, offset, !isStart, stayWithinRange);
     1697}
     1698
     1699void AXObjectCache::startOrEndTextMarkerDataForRange(TextMarkerData& textMarkerData, RefPtr<Range> range, bool isStart)
     1700{
     1701    memset(&textMarkerData, 0, sizeof(TextMarkerData));
     1702   
     1703    CharacterOffset characterOffset = startOrEndCharacterOffsetForRange(range, isStart);
     1704    if (characterOffset.isNull())
     1705        return;
     1706   
    16751707    setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
    16761708}
    16771709
    1678 void AXObjectCache::textMarkerDataForCharacterOffset(TextMarkerData& textMarkerData, Node& node, int offset, bool toNodeEnd)
    1679 {
    1680     memset(&textMarkerData, 0, sizeof(TextMarkerData));
    1681    
     1710CharacterOffset AXObjectCache::characterOffsetForNodeAndOffset(Node& node, int offset, bool toNodeEnd, bool ignoreStart)
     1711{
    16821712    Node* domNode = &node;
    16831713    if (!domNode)
    1684         return;
    1685    
    1686     // If offset <= 0, means we want to go to the previous node.
    1687     if (offset <= 0 && !toNodeEnd) {
     1714        return CharacterOffset();
     1715   
     1716    // ignoreStart is used to determine if we should go to previous node or
     1717    // stay in current node when offset is 0.
     1718    if (!toNodeEnd && (offset < 0 || (!offset && ignoreStart))) {
    16881719        // Set the offset to the amount of characters we need to go backwards.
    1689         offset = - offset + 1;
    1690         while (offset > 0 && textMarkerData.characterOffset <= offset) {
    1691             offset -= textMarkerData.characterOffset;
     1720        offset = - offset;
     1721        CharacterOffset charOffset = CharacterOffset();
     1722        while (offset >= 0 && charOffset.offset <= offset) {
     1723            offset -= charOffset.offset;
    16921724            domNode = previousNode(domNode);
    16931725            if (domNode) {
    1694                 textMarkerDataForCharacterOffset(textMarkerData, *domNode, 0, true);
    1695                 offset--;
     1726                charOffset = characterOffsetForNodeAndOffset(*domNode, 0, true);
    16961727            } else
    1697                 return;
     1728                return CharacterOffset();
     1729            if (!offset)
     1730                break;
    16981731        }
    16991732        if (offset > 0)
    1700             textMarkerDataForCharacterOffset(textMarkerData, *domNode, offset, false);
    1701         return;
     1733            charOffset = characterOffsetForNodeAndOffset(*charOffset.node, charOffset.offset - offset, false);
     1734        return charOffset;
    17021735    }
    17031736   
     
    17101743        domNode = nextNode(domNode);
    17111744        if (!domNode)
    1712             return;
     1745            return CharacterOffset();
    17131746        range = rangeForNodeContents(domNode);
    17141747        characterOffset = traverseToOffsetInRange(range, characterOffset.remaining(), toNodeEnd);
    17151748    }
    17161749   
     1750    return characterOffset;
     1751}
     1752
     1753void AXObjectCache::textMarkerDataForCharacterOffset(TextMarkerData& textMarkerData, Node& node, int offset, bool toNodeEnd, bool ignoreStart)
     1754{
     1755    memset(&textMarkerData, 0, sizeof(TextMarkerData));
     1756   
     1757    CharacterOffset characterOffset = characterOffsetForNodeAndOffset(node, offset, toNodeEnd, ignoreStart);
    17171758    setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
    17181759}
     
    17381779}
    17391780
    1740 VisiblePosition AXObjectCache::visiblePositionFromCharacterOffset(AccessibilityObject* obj, const CharacterOffset& characterOffset)
    1741 {
     1781VisiblePosition AXObjectCache::visiblePositionFromCharacterOffset(const CharacterOffset& characterOffset)
     1782{
     1783    if (characterOffset.isNull())
     1784        return VisiblePosition();
     1785   
     1786    RefPtr<AccessibilityObject> obj = this->getOrCreate(characterOffset.node);
    17421787    if (!obj)
    17431788        return VisiblePosition();
     
    17531798}
    17541799
    1755 CharacterOffset AXObjectCache::characterOffsetFromVisiblePosition(AccessibilityObject* obj, const VisiblePosition& visiblePos)
    1756 {
     1800CharacterOffset AXObjectCache::characterOffsetFromVisiblePosition(const VisiblePosition& visiblePos)
     1801{
     1802    if (visiblePos.isNull())
     1803        return CharacterOffset();
     1804   
     1805    Position deepPos = visiblePos.deepEquivalent();
     1806    Node* domNode = deepPos.deprecatedNode();
     1807    ASSERT(domNode);
     1808   
     1809    RefPtr<AccessibilityObject> obj = this->getOrCreate(domNode);
    17571810    if (!obj)
    1758         return 0;
     1811        return CharacterOffset();
    17591812   
    17601813    // Use nextVisiblePosition to calculate how many characters we need to traverse to the current position.
    1761     Position deepPos = visiblePos.deepEquivalent();
    17621814    VisiblePositionRange vpRange = obj->visiblePositionRange();
    17631815    VisiblePosition vp = vpRange.start;
     
    18171869   
    18181870    // convert to character offset
    1819     CharacterOffset characterOffset = characterOffsetFromVisiblePosition(obj.get(), visiblePos);
     1871    CharacterOffset characterOffset = characterOffsetFromVisiblePosition(visiblePos);
    18201872    textMarkerData.characterOffset = characterOffset.offset;
    18211873    textMarkerData.characterStartIndex = characterOffset.startIndex;
    18221874   
    18231875    cache->setNodeInUse(domNode);
     1876}
     1877
     1878CharacterOffset AXObjectCache::nextCharacterOffset(const CharacterOffset& characterOffset)
     1879{
     1880    if (characterOffset.isNull())
     1881        return CharacterOffset();
     1882   
     1883    return characterOffsetForNodeAndOffset(*characterOffset.node, characterOffset.offset + 1);
     1884}
     1885
     1886CharacterOffset AXObjectCache::previousCharacterOffset(const CharacterOffset& characterOffset)
     1887{
     1888    if (characterOffset.isNull())
     1889        return CharacterOffset();
     1890   
     1891    return characterOffsetForNodeAndOffset(*characterOffset.node, characterOffset.offset - 1, false, false);
     1892}
     1893
     1894static unsigned startWordBoundary(StringView text, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
     1895{
     1896    ASSERT(offset);
     1897    if (mayHaveMoreContext && !startOfLastWordBoundaryContext(text.substring(0, offset))) {
     1898        needMoreContext = true;
     1899        return 0;
     1900    }
     1901    needMoreContext = false;
     1902    int start, end;
     1903    U16_BACK_1(text, 0, offset);
     1904    findWordBoundary(text, offset, &start, &end);
     1905    return start;
     1906}
     1907
     1908static unsigned endWordBoundary(StringView text, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
     1909{
     1910    ASSERT(offset <= text.length());
     1911    if (mayHaveMoreContext && endOfFirstWordBoundaryContext(text.substring(offset)) == text.length() - offset) {
     1912        needMoreContext = true;
     1913        return text.length();
     1914    }
     1915    needMoreContext = false;
     1916    int end;
     1917    findEndWordBoundary(text, offset, &end);
     1918    return end;
     1919}
     1920
     1921CharacterOffset AXObjectCache::startCharacterOffsetOfWord(const CharacterOffset& characterOffset, EWordSide side)
     1922{
     1923    if (characterOffset.isNull())
     1924        return CharacterOffset();
     1925   
     1926    CharacterOffset c = characterOffset;
     1927    if (side == RightWordIfOnBoundary) {
     1928        // FIXME: need to remove this when isEndOfParagraph is implemented for CharacterOffset.
     1929        VisiblePosition vp = visiblePositionFromCharacterOffset(c);
     1930        if (isEndOfParagraph(vp))
     1931            return c;
     1932       
     1933        c = nextCharacterOffset(characterOffset);
     1934        if (c.isNull())
     1935            return characterOffset;
     1936    }
     1937   
     1938    return previousWordBoundary(c, startWordBoundary);
     1939}
     1940
     1941CharacterOffset AXObjectCache::endCharacterOffsetOfWord(const CharacterOffset& characterOffset, EWordSide side)
     1942{
     1943    if (characterOffset.isNull())
     1944        return CharacterOffset();
     1945   
     1946    CharacterOffset c = characterOffset;
     1947    if (side == LeftWordIfOnBoundary) {
     1948        // FIXME: need to remove this when isStartOfParagraph is implemented for CharacterOffset.
     1949        VisiblePosition vp = visiblePositionFromCharacterOffset(c);
     1950        if (isStartOfParagraph(vp))
     1951            return c;
     1952       
     1953        c = previousCharacterOffset(characterOffset);
     1954        if (c.isNull())
     1955            return characterOffset;
     1956    }
     1957   
     1958    return nextWordBoundary(c, endWordBoundary);
     1959}
     1960
     1961CharacterOffset AXObjectCache::previousWordStartCharacterOffset(const CharacterOffset& characterOffset)
     1962{
     1963    if (characterOffset.isNull())
     1964        return CharacterOffset();
     1965   
     1966    CharacterOffset previousOffset = previousCharacterOffset(characterOffset);
     1967    if (previousOffset.isNull())
     1968        return CharacterOffset();
     1969   
     1970    return startCharacterOffsetOfWord(previousOffset, RightWordIfOnBoundary);
     1971}
     1972
     1973CharacterOffset AXObjectCache::nextWordEndCharacterOffset(const CharacterOffset& characterOffset)
     1974{
     1975    if (characterOffset.isNull())
     1976        return CharacterOffset();
     1977   
     1978    CharacterOffset nextOffset = nextCharacterOffset(characterOffset);
     1979    if (nextOffset.isNull())
     1980        return CharacterOffset();
     1981   
     1982    return endCharacterOffsetOfWord(nextOffset, LeftWordIfOnBoundary);
     1983}
     1984
     1985RefPtr<Range> AXObjectCache::leftWordRange(const CharacterOffset& characterOffset)
     1986{
     1987    CharacterOffset start = previousWordStartCharacterOffset(characterOffset);
     1988    CharacterOffset end = endCharacterOffsetOfWord(start);
     1989    return rangeForUnorderedCharacterOffsets(start, end);
     1990}
     1991
     1992RefPtr<Range> AXObjectCache::rightWordRange(const CharacterOffset& characterOffset)
     1993{
     1994    CharacterOffset start = startCharacterOffsetOfWord(characterOffset);
     1995    CharacterOffset end = nextWordEndCharacterOffset(start);
     1996    return rangeForUnorderedCharacterOffsets(start, end);
     1997}
     1998
     1999static UChar32 characterForCharacterOffset(const CharacterOffset& characterOffset)
     2000{
     2001    if (characterOffset.isNull() || !characterOffset.node->isTextNode())
     2002        return 0;
     2003   
     2004    UChar32 ch = 0;
     2005    unsigned offset = characterOffset.startIndex + characterOffset.offset;
     2006    if (offset < characterOffset.node->textContent().length())
     2007        U16_NEXT(characterOffset.node->textContent(), offset, characterOffset.node->textContent().length(), ch);
     2008    return ch;
     2009}
     2010
     2011UChar32 AXObjectCache::characterAfter(const CharacterOffset& characterOffset)
     2012{
     2013    return characterForCharacterOffset(nextCharacterOffset(characterOffset));
     2014}
     2015
     2016UChar32 AXObjectCache::characterBefore(const CharacterOffset& characterOffset)
     2017{
     2018    return characterForCharacterOffset(characterOffset);
     2019}
     2020   
     2021static Node* parentEditingBoundary(Node* node)
     2022{
     2023    if (!node)
     2024        return nullptr;
     2025   
     2026    Node* documentElement = node->document().documentElement();
     2027    if (!documentElement)
     2028        return nullptr;
     2029   
     2030    Node* boundary = node;
     2031    while (boundary != documentElement && boundary->nonShadowBoundaryParentNode() && node->hasEditableStyle() == boundary->parentNode()->hasEditableStyle())
     2032        boundary = boundary->nonShadowBoundaryParentNode();
     2033   
     2034    return boundary;
     2035}
     2036
     2037CharacterOffset AXObjectCache::nextWordBoundary(CharacterOffset& characterOffset, BoundarySearchFunction searchFunction)
     2038{
     2039    if (characterOffset.isNull())
     2040        return CharacterOffset();
     2041   
     2042    Node* boundary = parentEditingBoundary(characterOffset.node);
     2043    if (!boundary)
     2044        return CharacterOffset();
     2045   
     2046    RefPtr<Range> searchRange = rangeForNodeContents(boundary);
     2047    Vector<UChar, 1024> string;
     2048    unsigned prefixLength = 0;
     2049   
     2050    ExceptionCode ec = 0;
     2051    if (requiresContextForWordBoundary(characterAfter(characterOffset))) {
     2052        RefPtr<Range> backwardsScanRange(boundary->document().createRange());
     2053        setRangeStartOrEndWithCharacterOffset(backwardsScanRange, characterOffset, false, ec);
     2054        prefixLength = prefixLengthForRange(backwardsScanRange, string);
     2055    }
     2056   
     2057    setRangeStartOrEndWithCharacterOffset(searchRange, characterOffset, true, ec);
     2058    CharacterOffset end = startOrEndCharacterOffsetForRange(searchRange, false);
     2059   
     2060    ASSERT(!ec);
     2061    if (ec)
     2062        return CharacterOffset();
     2063   
     2064    TextIterator it(searchRange.get(), TextIteratorEmitsObjectReplacementCharacters);
     2065    unsigned next = forwardSearchForBoundaryWithTextIterator(it, string, prefixLength, searchFunction);
     2066   
     2067    if (it.atEnd() && next == string.size())
     2068        return end;
     2069    if (next > prefixLength)
     2070        return characterOffsetForNodeAndOffset(*characterOffset.node, characterOffset.offset + next - prefixLength);
     2071   
     2072    return characterOffset;
     2073}
     2074
     2075CharacterOffset AXObjectCache::previousWordBoundary(CharacterOffset& characterOffset, BoundarySearchFunction searchFunction)
     2076{
     2077    if (characterOffset.isNull())
     2078        return CharacterOffset();
     2079   
     2080    Node* boundary = parentEditingBoundary(characterOffset.node);
     2081    if (!boundary)
     2082        return CharacterOffset();
     2083   
     2084    RefPtr<Range> searchRange = rangeForNodeContents(boundary);
     2085    Vector<UChar, 1024> string;
     2086    unsigned suffixLength = 0;
     2087   
     2088    ExceptionCode ec = 0;
     2089    if (requiresContextForWordBoundary(characterBefore(characterOffset))) {
     2090        RefPtr<Range> forwardsScanRange(boundary->document().createRange());
     2091        forwardsScanRange->setEndAfter(boundary, ec);
     2092        setRangeStartOrEndWithCharacterOffset(forwardsScanRange, characterOffset, true, ec);
     2093        suffixLength = suffixLengthForRange(forwardsScanRange, string);
     2094    }
     2095   
     2096    setRangeStartOrEndWithCharacterOffset(searchRange, characterOffset, false, ec);
     2097    CharacterOffset start = startOrEndCharacterOffsetForRange(searchRange, true);
     2098   
     2099    ASSERT(!ec);
     2100    if (ec)
     2101        return CharacterOffset();
     2102   
     2103    SimplifiedBackwardsTextIterator it(*searchRange);
     2104    unsigned next = backwardSearchForBoundaryWithTextIterator(it, string, suffixLength, searchFunction);
     2105   
     2106    if (!next)
     2107        return it.atEnd() ? start : characterOffset;
     2108   
     2109    Node& node = it.atEnd() ? searchRange->startContainer() : it.range()->startContainer();
     2110    if ((node.isTextNode() && static_cast<int>(next) <= node.maxCharacterOffset()) || (node.renderer() && node.renderer()->isBR() && !next)) {
     2111        // The next variable contains a usable index into a text node
     2112        if (&node == characterOffset.node)
     2113            next -= characterOffset.startIndex;
     2114        return characterOffsetForNodeAndOffset(node, next, false);
     2115    }
     2116   
     2117    int characterCount = characterOffset.offset - (string.size() - suffixLength - next);
     2118    return characterOffsetForNodeAndOffset(*characterOffset.node, characterCount, false, false);
    18242119}
    18252120
  • trunk/Source/WebCore/accessibility/AXObjectCache.h

    r196287 r196352  
    3131#include "Range.h"
    3232#include "Timer.h"
     33#include "VisibleUnits.h"
    3334#include <limits.h>
    3435#include <wtf/Forward.h>
     
    187188    VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&);
    188189    CharacterOffset characterOffsetForTextMarkerData(TextMarkerData&);
    189     void textMarkerDataForCharacterOffset(TextMarkerData&, Node&, int, bool toNodeEnd = false);
     190    void textMarkerDataForCharacterOffset(TextMarkerData&, Node&, int, bool toNodeEnd = false, bool ignoreStart = true);
    190191    void startOrEndTextMarkerDataForRange(TextMarkerData&, RefPtr<Range>, bool);
    191192    AccessibilityObject* accessibilityObjectForTextMarkerData(TextMarkerData&);
     
    193194    static RefPtr<Range> rangeForNodeContents(Node*);
    194195    static int lengthForRange(Range*);
     196   
     197    // Word boundary
     198    CharacterOffset startCharacterOffsetOfWord(const CharacterOffset&, EWordSide = RightWordIfOnBoundary);
     199    CharacterOffset endCharacterOffsetOfWord(const CharacterOffset&, EWordSide = RightWordIfOnBoundary);
     200    CharacterOffset nextWordEndCharacterOffset(const CharacterOffset&);
     201    CharacterOffset previousWordStartCharacterOffset(const CharacterOffset&);
     202    RefPtr<Range> leftWordRange(const CharacterOffset&);
     203    RefPtr<Range> rightWordRange(const CharacterOffset&);
    195204
    196205    enum AXNotification {
     
    284293    bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); }
    285294   
     295    // CharacterOffset functions.
    286296    Node* nextNode(Node*) const;
    287297    Node* previousNode(Node*) const;
    288298    CharacterOffset traverseToOffsetInRange(RefPtr<Range>, int, bool, bool stayWithinRange = false);
    289     VisiblePosition visiblePositionFromCharacterOffset(AccessibilityObject*, const CharacterOffset&);
    290     CharacterOffset characterOffsetFromVisiblePosition(AccessibilityObject*, const VisiblePosition&);
     299    VisiblePosition visiblePositionFromCharacterOffset(const CharacterOffset&);
     300    CharacterOffset characterOffsetFromVisiblePosition(const VisiblePosition&);
    291301    void setTextMarkerDataWithCharacterOffset(TextMarkerData&, const CharacterOffset&);
     302    UChar32 characterAfter(const CharacterOffset&);
     303    UChar32 characterBefore(const CharacterOffset&);
     304    CharacterOffset startOrEndCharacterOffsetForRange(RefPtr<Range>, bool);
     305    CharacterOffset characterOffsetForNodeAndOffset(Node&, int, bool toNodeEnd = false, bool ignoreStart = true);
     306    CharacterOffset nextCharacterOffset(const CharacterOffset&);
     307    CharacterOffset previousCharacterOffset(const CharacterOffset&);
     308    CharacterOffset previousWordBoundary(CharacterOffset&, BoundarySearchFunction);
     309    CharacterOffset nextWordBoundary(CharacterOffset&, BoundarySearchFunction);
    292310
    293311private:
  • trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm

    r196287 r196352  
    859859}
    860860
     861- (id)textMarkerForNode:(Node&)node offset:(int)offset ignoreStart:(BOOL)ignoreStart
     862{
     863    return textMarkerForCharacterOffset(m_object->axObjectCache(), node, offset, false, ignoreStart);
     864}
     865
    861866- (id)textMarkerForNode:(Node&)node offset:(int)offset
    862867{
    863     return textMarkerForCharacterOffset(m_object->axObjectCache(), node, offset);
    864 }
    865 
    866 static id textMarkerForCharacterOffset(AXObjectCache* cache, Node& node, int offset, bool toNodeEnd = false)
     868    return [self textMarkerForNode:node offset:offset ignoreStart:YES];
     869}
     870
     871static id textMarkerForCharacterOffset(AXObjectCache* cache, Node& node, int offset, bool toNodeEnd, bool ignoreStart)
    867872{
    868873    if (!cache)
     
    874879   
    875880    TextMarkerData textMarkerData;
    876     cache->textMarkerDataForCharacterOffset(textMarkerData, node, offset, toNodeEnd);
     881    cache->textMarkerDataForCharacterOffset(textMarkerData, node, offset, toNodeEnd, ignoreStart);
    877882    if (!textMarkerData.axID && !textMarkerData.ignored)
    878883        return nil;
     
    40714076   
    40724077    if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"]) {
    4073         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
    4074         VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos);
    4075         return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
     4078        AXObjectCache* cache = m_object->axObjectCache();
     4079        if (!cache)
     4080            return nil;
     4081        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
     4082        RefPtr<Range> range = cache->leftWordRange(characterOffset);
     4083        return [self textMarkerRangeFromRange:range];
    40764084    }
    40774085   
    40784086    if ([attribute isEqualToString:@"AXRightWordTextMarkerRangeForTextMarker"]) {
    4079         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
    4080         VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos);
    4081         return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
     4087        AXObjectCache* cache = m_object->axObjectCache();
     4088        if (!cache)
     4089            return nil;
     4090        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
     4091        RefPtr<Range> range = cache->rightWordRange(characterOffset);
     4092        return [self textMarkerRangeFromRange:range];
    40824093    }
    40834094   
     
    41074118   
    41084119    if ([attribute isEqualToString:@"AXNextWordEndTextMarkerForTextMarker"]) {
    4109         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
    4110         return [self textMarkerForVisiblePosition:m_object->nextWordEnd(visiblePos)];
     4120        AXObjectCache* cache = m_object->axObjectCache();
     4121        if (!cache)
     4122            return nil;
     4123        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
     4124        CharacterOffset nextEnd = cache->nextWordEndCharacterOffset(characterOffset);
     4125        return [self textMarkerForNode:*nextEnd.node offset:nextEnd.offset];
    41114126    }
    41124127   
    41134128    if ([attribute isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) {
    4114         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
    4115         return [self textMarkerForVisiblePosition:m_object->previousWordStart(visiblePos)];
     4129        AXObjectCache* cache = m_object->axObjectCache();
     4130        if (!cache)
     4131            return nil;
     4132        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
     4133        CharacterOffset previousStart = cache->previousWordStartCharacterOffset(characterOffset);
     4134        return [self textMarkerForNode:*previousStart.node offset:previousStart.offset ignoreStart:NO];
    41164135    }
    41174136   
  • trunk/Source/WebCore/editing/VisibleUnits.cpp

    r195949 r196352  
    440440
    441441
    442 enum BoundarySearchContextAvailability { DontHaveMoreContext, MayHaveMoreContext };
    443 
    444 typedef unsigned (*BoundarySearchFunction)(StringView, unsigned offset, BoundarySearchContextAvailability, bool& needMoreContext);
    445 
    446442static void prepend(Vector<UChar, 1024>& buffer, StringView string)
    447443{
     
    471467}
    472468
    473 static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction)
    474 {
    475     Position pos = c.deepEquivalent();
    476     Node* boundary = pos.parentEditingBoundary();
    477     if (!boundary)
    478         return VisiblePosition();
    479 
    480     Document& boundaryDocument = boundary->document();
    481     Position start = createLegacyEditingPosition(boundary, 0).parentAnchoredEquivalent();
    482     Position end = pos.parentAnchoredEquivalent();
    483     RefPtr<Range> searchRange = Range::create(boundaryDocument);
    484    
    485     Vector<UChar, 1024> string;
     469unsigned suffixLengthForRange(RefPtr<Range> forwardsScanRange, Vector<UChar, 1024>& string)
     470{
    486471    unsigned suffixLength = 0;
    487 
    488     ExceptionCode ec = 0;
    489     if (requiresContextForWordBoundary(c.characterBefore())) {
    490         RefPtr<Range> forwardsScanRange(boundaryDocument.createRange());
    491         forwardsScanRange->setEndAfter(boundary, ec);
    492         forwardsScanRange->setStart(end.deprecatedNode(), end.deprecatedEditingOffset(), ec);
    493         TextIterator forwardsIterator(forwardsScanRange.get());
    494         while (!forwardsIterator.atEnd()) {
    495             StringView text = forwardsIterator.text();
    496             unsigned i = endOfFirstWordBoundaryContext(text);
    497             append(string, text.substring(0, i));
    498             suffixLength += i;
    499             if (i < text.length())
    500                 break;
    501             forwardsIterator.advance();
    502         }
    503     }
    504 
    505     searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), ec);
    506     searchRange->setEnd(end.deprecatedNode(), end.deprecatedEditingOffset(), ec);
    507 
    508     ASSERT(!ec);
    509     if (ec)
    510         return VisiblePosition();
    511 
    512     SimplifiedBackwardsTextIterator it(*searchRange);
     472    TextIterator forwardsIterator(forwardsScanRange.get());
     473    while (!forwardsIterator.atEnd()) {
     474        StringView text = forwardsIterator.text();
     475        unsigned i = endOfFirstWordBoundaryContext(text);
     476        append(string, text.substring(0, i));
     477        suffixLength += i;
     478        if (i < text.length())
     479            break;
     480        forwardsIterator.advance();
     481    }
     482    return suffixLength;
     483}
     484
     485unsigned prefixLengthForRange(RefPtr<Range> backwardsScanRange, Vector<UChar, 1024>& string)
     486{
     487    unsigned prefixLength = 0;
     488    SimplifiedBackwardsTextIterator backwardsIterator(*backwardsScanRange);
     489    while (!backwardsIterator.atEnd()) {
     490        StringView text = backwardsIterator.text();
     491        int i = startOfLastWordBoundaryContext(text);
     492        prepend(string, text.substring(i));
     493        prefixLength += text.length() - i;
     494        if (i > 0)
     495            break;
     496        backwardsIterator.advance();
     497    }
     498    return prefixLength;
     499}
     500
     501unsigned backwardSearchForBoundaryWithTextIterator(SimplifiedBackwardsTextIterator& it, Vector<UChar, 1024>& string, unsigned suffixLength, BoundarySearchFunction searchFunction)
     502{
    513503    unsigned next = 0;
    514504    bool needMoreContext = false;
     
    516506        bool inTextSecurityMode = it.node() && it.node()->renderer() && it.node()->renderer()->style().textSecurity() != TSNONE;
    517507        // iterate to get chunks until the searchFunction returns a non-zero value.
    518         if (!inTextSecurityMode) 
     508        if (!inTextSecurityMode)
    519509            prepend(string, it.text());
    520510        else {
     
    535525        ASSERT(!needMoreContext);
    536526    }
    537 
    538     if (!next)
    539         return VisiblePosition(it.atEnd() ? searchRange->startPosition() : pos, DOWNSTREAM);
    540 
    541     Node& node = it.atEnd() ? searchRange->startContainer() : it.range()->startContainer();
    542     if ((node.isTextNode() && static_cast<int>(next) <= node.maxCharacterOffset()) || (node.renderer() && node.renderer()->isBR() && !next)) {
    543         // The next variable contains a usable index into a text node
    544         return VisiblePosition(createLegacyEditingPosition(&node, next), DOWNSTREAM);
    545     }
    546 
    547     // Use the character iterator to translate the next value into a DOM position.
    548     BackwardsCharacterIterator charIt(*searchRange);
    549     charIt.advance(string.size() - suffixLength - next);
    550     // FIXME: charIt can get out of shadow host.
    551     return VisiblePosition(charIt.range()->endPosition(), DOWNSTREAM);
    552 }
    553 
    554 static VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction)
    555 {
    556     Position pos = c.deepEquivalent();
    557     Node* boundary = pos.parentEditingBoundary();
    558     if (!boundary)
    559         return VisiblePosition();
    560 
    561     Document& boundaryDocument = boundary->document();
    562     RefPtr<Range> searchRange(boundaryDocument.createRange());
    563     Position start(pos.parentAnchoredEquivalent());
    564 
    565     Vector<UChar, 1024> string;
    566     unsigned prefixLength = 0;
    567 
    568     if (requiresContextForWordBoundary(c.characterAfter())) {
    569         RefPtr<Range> backwardsScanRange(boundaryDocument.createRange());
    570         backwardsScanRange->setEnd(start.deprecatedNode(), start.deprecatedEditingOffset(), IGNORE_EXCEPTION);
    571         SimplifiedBackwardsTextIterator backwardsIterator(*backwardsScanRange);
    572         while (!backwardsIterator.atEnd()) {
    573             StringView text = backwardsIterator.text();
    574             int i = startOfLastWordBoundaryContext(text);
    575             prepend(string, text.substring(i));
    576             prefixLength += text.length() - i;
    577             if (i > 0)
    578                 break;
    579             backwardsIterator.advance();
    580         }
    581     }
    582 
    583     searchRange->selectNodeContents(boundary, IGNORE_EXCEPTION);
    584     searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), IGNORE_EXCEPTION);
    585     TextIterator it(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions);
     527   
     528    return next;
     529}
     530
     531unsigned forwardSearchForBoundaryWithTextIterator(TextIterator& it, Vector<UChar, 1024>& string, unsigned prefixLength, BoundarySearchFunction searchFunction)
     532{
    586533    unsigned next = 0;
    587534    bool needMoreContext = false;
     
    609556        ASSERT(!needMoreContext);
    610557    }
     558   
     559    return next;
     560}
     561
     562static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction)
     563{
     564    Position pos = c.deepEquivalent();
     565    Node* boundary = pos.parentEditingBoundary();
     566    if (!boundary)
     567        return VisiblePosition();
     568
     569    Document& boundaryDocument = boundary->document();
     570    Position start = createLegacyEditingPosition(boundary, 0).parentAnchoredEquivalent();
     571    Position end = pos.parentAnchoredEquivalent();
     572    RefPtr<Range> searchRange = Range::create(boundaryDocument);
     573   
     574    Vector<UChar, 1024> string;
     575    unsigned suffixLength = 0;
     576
     577    ExceptionCode ec = 0;
     578    if (requiresContextForWordBoundary(c.characterBefore())) {
     579        RefPtr<Range> forwardsScanRange(boundaryDocument.createRange());
     580        forwardsScanRange->setEndAfter(boundary, ec);
     581        forwardsScanRange->setStart(end.deprecatedNode(), end.deprecatedEditingOffset(), ec);
     582        suffixLength = suffixLengthForRange(forwardsScanRange, string);
     583    }
     584
     585    searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), ec);
     586    searchRange->setEnd(end.deprecatedNode(), end.deprecatedEditingOffset(), ec);
     587
     588    ASSERT(!ec);
     589    if (ec)
     590        return VisiblePosition();
     591
     592    SimplifiedBackwardsTextIterator it(*searchRange);
     593    unsigned next = backwardSearchForBoundaryWithTextIterator(it, string, suffixLength, searchFunction);
     594
     595    if (!next)
     596        return VisiblePosition(it.atEnd() ? searchRange->startPosition() : pos, DOWNSTREAM);
     597
     598    Node& node = it.atEnd() ? searchRange->startContainer() : it.range()->startContainer();
     599    if ((node.isTextNode() && static_cast<int>(next) <= node.maxCharacterOffset()) || (node.renderer() && node.renderer()->isBR() && !next)) {
     600        // The next variable contains a usable index into a text node
     601        return VisiblePosition(createLegacyEditingPosition(&node, next), DOWNSTREAM);
     602    }
     603
     604    // Use the character iterator to translate the next value into a DOM position.
     605    BackwardsCharacterIterator charIt(*searchRange);
     606    charIt.advance(string.size() - suffixLength - next);
     607    // FIXME: charIt can get out of shadow host.
     608    return VisiblePosition(charIt.range()->endPosition(), DOWNSTREAM);
     609}
     610
     611static VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction)
     612{
     613    Position pos = c.deepEquivalent();
     614    Node* boundary = pos.parentEditingBoundary();
     615    if (!boundary)
     616        return VisiblePosition();
     617
     618    Document& boundaryDocument = boundary->document();
     619    RefPtr<Range> searchRange(boundaryDocument.createRange());
     620    Position start(pos.parentAnchoredEquivalent());
     621
     622    Vector<UChar, 1024> string;
     623    unsigned prefixLength = 0;
     624
     625    if (requiresContextForWordBoundary(c.characterAfter())) {
     626        RefPtr<Range> backwardsScanRange(boundaryDocument.createRange());
     627        backwardsScanRange->setEnd(start.deprecatedNode(), start.deprecatedEditingOffset(), IGNORE_EXCEPTION);
     628        prefixLength = prefixLengthForRange(backwardsScanRange, string);
     629    }
     630
     631    searchRange->selectNodeContents(boundary, IGNORE_EXCEPTION);
     632    searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), IGNORE_EXCEPTION);
     633    TextIterator it(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions);
     634    unsigned next = forwardSearchForBoundaryWithTextIterator(it, string, prefixLength, searchFunction);
    611635   
    612636    if (it.atEnd() && next == string.size())
  • trunk/Source/WebCore/editing/VisibleUnits.h

    r195949 r196352  
    3535class Node;
    3636class VisiblePosition;
     37class SimplifiedBackwardsTextIterator;
     38class TextIterator;
    3739
    3840enum EWordSide { RightWordIfOnBoundary = false, LeftWordIfOnBoundary = true };
     
    108110WEBCORE_EXPORT PassRefPtr<Range> rangeExpandedAroundPositionByCharacters(const VisiblePosition&, int numberOfCharactersToExpand);
    109111
     112// helper function
     113enum BoundarySearchContextAvailability { DontHaveMoreContext, MayHaveMoreContext };
     114typedef unsigned (*BoundarySearchFunction)(StringView, unsigned offset, BoundarySearchContextAvailability, bool& needMoreContext);
     115unsigned suffixLengthForRange(RefPtr<Range>, Vector<UChar, 1024>&);
     116unsigned prefixLengthForRange(RefPtr<Range>, Vector<UChar, 1024>&);
     117unsigned backwardSearchForBoundaryWithTextIterator(SimplifiedBackwardsTextIterator&, Vector<UChar, 1024>&, unsigned, BoundarySearchFunction);
     118unsigned forwardSearchForBoundaryWithTextIterator(TextIterator&, Vector<UChar, 1024>&, unsigned, BoundarySearchFunction);
     119
    110120} // namespace WebCore
    111121
  • trunk/Tools/ChangeLog

    r196312 r196352  
     12016-02-09  Nan Wang  <n_wang@apple.com>
     2
     3        AX: Implement word related text marker functions using TextIterator
     4        https://bugs.webkit.org/show_bug.cgi?id=153939
     5        <rdar://problem/24269605>
     6
     7        Reviewed by Chris Fleizach.
     8
     9        * DumpRenderTree/AccessibilityUIElement.cpp:
     10        (endTextMarkerCallback):
     11        (leftWordTextMarkerRangeForTextMarkerCallback):
     12        (rightWordTextMarkerRangeForTextMarkerCallback):
     13        (previousWordStartTextMarkerForTextMarkerCallback):
     14        (nextWordEndTextMarkerForTextMarkerCallback):
     15        (setSelectedVisibleTextRangeCallback):
     16        (AccessibilityUIElement::setSelectedVisibleTextRange):
     17        (AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
     18        (AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
     19        (AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
     20        (AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
     21        (AccessibilityUIElement::getJSClass):
     22        * DumpRenderTree/AccessibilityUIElement.h:
     23        * DumpRenderTree/ios/AccessibilityUIElementIOS.mm:
     24        (AccessibilityUIElement::setSelectedVisibleTextRange):
     25        (AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
     26        (AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
     27        (AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
     28        (AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
     29        * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
     30        (AccessibilityUIElement::setSelectedVisibleTextRange):
     31        (AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
     32        (AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
     33        (AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
     34        (AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
     35        (AccessibilityUIElement::supportedActions):
     36        * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp:
     37        (WTR::AccessibilityUIElement::setBoolAttributeValue):
     38        (WTR::AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
     39        (WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
     40        (WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
     41        (WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
     42        * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
     43        * WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl:
     44        * WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm:
     45        (WTR::AccessibilityUIElement::endTextMarker):
     46        (WTR::AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
     47        (WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
     48        (WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
     49        (WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
     50        (WTR::AccessibilityUIElement::mathPostscriptsDescription):
     51        * WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm:
     52        (WTR::AccessibilityUIElement::endTextMarker):
     53        (WTR::AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker):
     54        (WTR::AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker):
     55        (WTR::AccessibilityUIElement::previousWordStartTextMarkerForTextMarker):
     56        (WTR::AccessibilityUIElement::nextWordEndTextMarkerForTextMarker):
     57        (WTR::_convertMathMultiscriptPairsToString):
     58
    1592016-02-09  Csaba Osztrogonác  <ossy@webkit.org>
    260
  • trunk/Tools/DumpRenderTree/AccessibilityUIElement.cpp

    r194054 r196352  
    975975}
    976976
     977static JSValueRef leftWordTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     978{
     979    AccessibilityTextMarker* marker = nullptr;
     980    if (argumentCount == 1)
     981        marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
     982   
     983    return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->leftWordTextMarkerRangeForTextMarker(marker));
     984}
     985
     986static JSValueRef rightWordTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     987{
     988    AccessibilityTextMarker* marker = nullptr;
     989    if (argumentCount == 1)
     990        marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
     991   
     992    return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->rightWordTextMarkerRangeForTextMarker(marker));
     993}
     994
     995static JSValueRef previousWordStartTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     996{
     997    AccessibilityTextMarker* marker = nullptr;
     998    if (argumentCount == 1)
     999        marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
     1000   
     1001    return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->previousWordStartTextMarkerForTextMarker(marker));
     1002}
     1003
     1004static JSValueRef nextWordEndTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     1005{
     1006    AccessibilityTextMarker* marker = nullptr;
     1007    if (argumentCount == 1)
     1008        marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
     1009   
     1010    return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->nextWordEndTextMarkerForTextMarker(marker));
     1011}
     1012
    9771013static JSValueRef setSelectedVisibleTextRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
    9781014{
     
    15631599{
    15641600    return false;
     1601}
     1602
     1603AccessibilityTextMarkerRange AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
     1604{
     1605    return nullptr;
     1606}
     1607
     1608AccessibilityTextMarkerRange AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
     1609{
     1610    return nullptr;
     1611}
     1612
     1613AccessibilityTextMarker AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*)
     1614{
     1615    return nullptr;
     1616}
     1617
     1618AccessibilityTextMarker AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*)
     1619{
     1620    return nullptr;
    15651621}
    15661622
     
    17451801        { "previousTextMarker", previousTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
    17461802        { "stringForTextMarkerRange", stringForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
     1803        { "leftWordTextMarkerRangeForTextMarker", leftWordTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
     1804        { "rightWordTextMarkerRangeForTextMarker", rightWordTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
     1805        { "previousWordStartTextMarkerForTextMarker", previousWordStartTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
     1806        { "nextWordEndTextMarkerForTextMarker", nextWordEndTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
    17471807        { "setSelectedChild", setSelectedChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
    17481808        { "setSelectedChildAtIndex", setSelectedChildAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  • trunk/Tools/DumpRenderTree/AccessibilityUIElement.h

    r194054 r196352  
    261261    AccessibilityTextMarker startTextMarker();
    262262    AccessibilityTextMarker endTextMarker();
     263    AccessibilityTextMarkerRange leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
     264    AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
     265    AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*);
     266    AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*);
    263267    AccessibilityTextMarkerRange selectedTextMarkerRange();
    264268    void resetSelectedTextMarkerRange();
  • trunk/Tools/DumpRenderTree/ios/AccessibilityUIElementIOS.mm

    r195405 r196352  
    551551}
    552552
     553AccessibilityTextMarkerRange AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
     554{
     555    return nullptr;
     556}
     557
     558AccessibilityTextMarkerRange AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
     559{
     560    return nullptr;
     561}
     562
     563AccessibilityTextMarker AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*)
     564{
     565    return nullptr;
     566}
     567
     568AccessibilityTextMarker AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*)
     569{
     570    return nullptr;
     571}
     572
    553573#endif // SUPPORTS_AX_TEXTMARKERS && PLATFORM(IOS)
    554574
  • trunk/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm

    r195405 r196352  
    18471847}
    18481848
     1849AccessibilityTextMarkerRange AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
     1850{
     1851    BEGIN_AX_OBJC_EXCEPTIONS
     1852    id textMarkerRange = [m_element accessibilityAttributeValue:@"AXLeftWordTextMarkerRangeForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
     1853    return AccessibilityTextMarkerRange(textMarkerRange);
     1854    END_AX_OBJC_EXCEPTIONS
     1855   
     1856    return nullptr;
     1857}
     1858
     1859AccessibilityTextMarkerRange AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
     1860{
     1861    BEGIN_AX_OBJC_EXCEPTIONS
     1862    id textMarkerRange = [m_element accessibilityAttributeValue:@"AXRightWordTextMarkerRangeForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
     1863    return AccessibilityTextMarkerRange(textMarkerRange);
     1864    END_AX_OBJC_EXCEPTIONS
     1865   
     1866    return nullptr;
     1867}
     1868
     1869AccessibilityTextMarker AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
     1870{
     1871    BEGIN_AX_OBJC_EXCEPTIONS
     1872    id previousTextMarker = [m_element accessibilityAttributeValue:@"AXPreviousWordStartTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
     1873    return AccessibilityTextMarker(previousTextMarker);
     1874    END_AX_OBJC_EXCEPTIONS
     1875   
     1876    return nullptr;
     1877}
     1878
     1879AccessibilityTextMarker AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
     1880{
     1881    BEGIN_AX_OBJC_EXCEPTIONS
     1882    id nextTextMarker = [m_element accessibilityAttributeValue:@"AXNextWordEndTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
     1883    return AccessibilityTextMarker(nextTextMarker);
     1884    END_AX_OBJC_EXCEPTIONS
     1885   
     1886    return nullptr;
     1887}
     1888
    18491889#endif // SUPPORTS_AX_TEXTMARKERS && PLATFORM(MAC)
    18501890
  • trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp

    r194054 r196352  
    245245#endif
    246246
     247#if (!PLATFORM(MAC) && !PLATFORM(IOS)) || !HAVE(ACCESSIBILITY)
     248PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; }
     249PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; }
     250PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
     251PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
     252#endif
     253
    247254} // namespace WTR
    248255
  • trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h

    r194054 r196352  
    252252    PassRefPtr<AccessibilityTextMarker> endTextMarker();
    253253    bool setSelectedVisibleTextRange(AccessibilityTextMarkerRange*);
     254    PassRefPtr<AccessibilityTextMarkerRange> leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
     255    PassRefPtr<AccessibilityTextMarkerRange> rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
     256    PassRefPtr<AccessibilityTextMarker> previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*);
     257    PassRefPtr<AccessibilityTextMarker> nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*);
    254258
    255259    // Returns an ordered list of supported actions for an element.
  • trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl

    r194054 r196352  
    202202    readonly attribute AccessibilityTextMarker endTextMarker;
    203203    boolean setSelectedVisibleTextRange(AccessibilityTextMarkerRange range);
     204    AccessibilityTextMarkerRange leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker);
     205    AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker);
     206    AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
     207    AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
    204208
    205209    // Returns an ordered list of supported actions for an element.
  • trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm

    r195405 r196352  
    10971097}
    10981098
     1099PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
     1100{
     1101    return nullptr;
     1102}
     1103
     1104PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
     1105{
     1106    return nullptr;
     1107}
     1108
     1109PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
     1110{
     1111    return nullptr;
     1112}
     1113
     1114PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
     1115{
     1116    return nullptr;
     1117}
     1118
    10991119JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const
    11001120{
  • trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm

    r195240 r196352  
    18741874}
    18751875
     1876PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
     1877{
     1878    BEGIN_AX_OBJC_EXCEPTIONS
     1879    id textMarkerRange = [m_element accessibilityAttributeValue:@"AXLeftWordTextMarkerRangeForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
     1880    return AccessibilityTextMarkerRange::create(textMarkerRange);
     1881    END_AX_OBJC_EXCEPTIONS
     1882   
     1883    return nullptr;
     1884}
     1885
     1886PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
     1887{
     1888    BEGIN_AX_OBJC_EXCEPTIONS
     1889    id textMarkerRange = [m_element accessibilityAttributeValue:@"AXRightWordTextMarkerRangeForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
     1890    return AccessibilityTextMarkerRange::create(textMarkerRange);
     1891    END_AX_OBJC_EXCEPTIONS
     1892   
     1893    return nullptr;
     1894}
     1895
     1896PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
     1897{
     1898    BEGIN_AX_OBJC_EXCEPTIONS
     1899    id previousWordStartMarker = [m_element accessibilityAttributeValue:@"AXPreviousWordStartTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
     1900    return AccessibilityTextMarker::create(previousWordStartMarker);
     1901    END_AX_OBJC_EXCEPTIONS
     1902   
     1903    return nullptr;
     1904}
     1905
     1906PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
     1907{
     1908    BEGIN_AX_OBJC_EXCEPTIONS
     1909    id nextWordEndMarker = [m_element accessibilityAttributeValue:@"AXNextWordEndTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
     1910    return AccessibilityTextMarker::create(nextWordEndMarker);
     1911    END_AX_OBJC_EXCEPTIONS
     1912   
     1913    return nullptr;
     1914}
     1915
    18761916static NSString *_convertMathMultiscriptPairsToString(NSArray *pairs)
    18771917{
Note: See TracChangeset for help on using the changeset viewer.