Changeset 196352 in webkit
- Timestamp:
- Feb 9, 2016 6:33:04 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 19 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r196346 r196352 1 2016-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 1 14 2016-02-09 Ryan Haddad <ryanhaddad@apple.com> 2 15 -
trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next-expected.txt
r195405 r196352 13 13 PASS text.accessibilityElementForTextMarker(startMarker).isEqual(text) is true 14 14 PASS text.accessibilityElementForTextMarker(endMarker).isEqual(text) is true 15 PASS text.stringForTextMarkerRange(markerRange) is ''15 PASS text.stringForTextMarkerRange(markerRange) is newline 16 16 PASS text.stringForTextMarkerRange(markerRange) is 't' 17 PASS text.stringForTextMarkerRange(markerRange) is ''17 PASS text.stringForTextMarkerRange(markerRange) is newline 18 18 PASS text.stringForTextMarkerRange(markerRange) is 't' 19 19 PASS text2.textMarkerRangeLength(textMarkerRange2) is 5 -
trunk/LayoutTests/accessibility/text-marker/text-marker-previous-next.html
r195405 r196352 51 51 } 52 52 markerRange = text.textMarkerRangeForMarkers(previousMarker, currentMarker); 53 shouldBe("text.stringForTextMarkerRange(markerRange)", "''"); 53 var newline = '\n'; 54 shouldBe("text.stringForTextMarkerRange(markerRange)", "newline"); 54 55 55 56 // Advance one more character, it will lande at "t" in "text1". … … 63 64 currentMarker = text.previousTextMarker(currentMarker); 64 65 markerRange = text.textMarkerRangeForMarkers(previousMarker, currentMarker); 65 shouldBe("text.stringForTextMarkerRange(markerRange)", " ''");66 shouldBe("text.stringForTextMarkerRange(markerRange)", "newline"); 66 67 67 68 // Traverse backwards one more character, it will land at the last character of "text". -
trunk/Source/WebCore/ChangeLog
r196350 r196352 1 2016-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 1 69 2016-02-09 Daniel Bates <dabates@apple.com> 2 70 -
trunk/Source/WebCore/accessibility/AXObjectCache.cpp
r196287 r196352 82 82 #include "RenderView.h" 83 83 #include "ScrollView.h" 84 #include "TextBoundaries.h" 84 85 #include "TextIterator.h" 85 86 #include <wtf/DataLog.h> … … 1471 1472 for (; !iterator.atEnd(); iterator.advance()) { 1472 1473 int currentLength = iterator.text().length(); 1474 bool hasReplacedNodeOrBR = false; 1473 1475 1474 1476 Node& node = iterator.range()->startContainer(); … … 1483 1485 currentLength++; 1484 1486 currentNode = childNode; 1487 hasReplacedNodeOrBR = true; 1485 1488 } else 1486 1489 continue; 1487 1490 } else { 1488 1491 // 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 } 1491 1504 offsetSoFar += currentLength; 1492 1505 } 1493 1506 1494 1507 lastLength = currentLength; 1495 lastStartOffset = iterator.range()->startOffset();1508 lastStartOffset = hasReplacedNodeOrBR ? 0 : iterator.range()->startOffset(); 1496 1509 1497 1510 // Break early if we have advanced enough characters. … … 1547 1560 return ec ? nullptr : range; 1548 1561 } 1562 1563 static bool isReplacedNodeOrBR(Node* node) 1564 { 1565 return node && (AccessibilityObject::replacedNodeNeedsCharacter(node) || node->hasTagName(brTag)); 1566 } 1549 1567 1550 1568 static bool characterOffsetsInOrder(const CharacterOffset& characterOffset1, const CharacterOffset& characterOffset2) … … 1556 1574 return characterOffset1.offset <= characterOffset2.offset; 1557 1575 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); 1560 1588 return range1->compareBoundaryPoints(Range::START_TO_START, range2.get(), IGNORE_EXCEPTION) <= 0; 1561 1589 } … … 1573 1601 } 1574 1602 1575 static bool isReplacedNodeOrBR(Node* node) 1576 { 1577 return AccessibilityObject::replacedNodeNeedsCharacter(node) || node->hasTagName(brTag); 1603 static 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); 1578 1623 } 1579 1624 … … 1587 1632 CharacterOffset endCharacterOffset = alreadyInOrder ? characterOffset2 : characterOffset1; 1588 1633 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 1612 1634 RefPtr<Range> result = Range::create(m_document); 1613 ExceptionCode ec Start = 0, ecEnd= 0;1614 result->setStart(startNode, startOffset, ecStart);1615 result->setEnd(endNode, endOffset, ecEnd);1616 if (ec Start || ecEnd)1635 ExceptionCode ec = 0; 1636 setRangeStartOrEndWithCharacterOffset(result, startCharacterOffset, true, ec); 1637 setRangeStartOrEndWithCharacterOffset(result, endCharacterOffset, false, ec); 1638 if (ec) 1617 1639 return nullptr; 1618 1640 … … 1636 1658 1637 1659 // Convert to visible position. 1638 VisiblePosition visiblePosition = visiblePositionFromCharacterOffset( obj.get(),characterOffset);1660 VisiblePosition visiblePosition = visiblePositionFromCharacterOffset(characterOffset); 1639 1661 int vpOffset = 0; 1640 1662 if (!visiblePosition.isNull()) { … … 1653 1675 } 1654 1676 1655 void AXObjectCache::startOrEndTextMarkerDataForRange(TextMarkerData& textMarkerData, RefPtr<Range> range, bool isStart) 1656 { 1657 memset(&textMarkerData, 0, sizeof(TextMarkerData)); 1658 1677 CharacterOffset AXObjectCache::startOrEndCharacterOffsetForRange(RefPtr<Range> range, bool isStart) 1678 { 1659 1679 if (!range) 1660 return ;1680 return CharacterOffset(); 1661 1681 1662 1682 // If it's end text marker, we want to go to the end of the range, and stay within the range. 1663 1683 bool stayWithinRange = !isStart; 1664 1684 1685 RefPtr<Range> copyRange = range; 1665 1686 // Change the start of the range, so the character offset starts from node beginning. 1666 1687 int offset = 0; 1667 Node* node = & range->startContainer();1688 Node* node = ©Range->startContainer(); 1668 1689 if (node->offsetInCharacters()) { 1690 copyRange = Range::create(range->ownerDocument(), &range->startContainer(), range->startOffset(), &range->endContainer(), range->endOffset()); 1669 1691 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 1699 void 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 1675 1707 setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset); 1676 1708 } 1677 1709 1678 void AXObjectCache::textMarkerDataForCharacterOffset(TextMarkerData& textMarkerData, Node& node, int offset, bool toNodeEnd) 1679 { 1680 memset(&textMarkerData, 0, sizeof(TextMarkerData)); 1681 1710 CharacterOffset AXObjectCache::characterOffsetForNodeAndOffset(Node& node, int offset, bool toNodeEnd, bool ignoreStart) 1711 { 1682 1712 Node* domNode = &node; 1683 1713 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))) { 1688 1719 // 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; 1692 1724 domNode = previousNode(domNode); 1693 1725 if (domNode) { 1694 textMarkerDataForCharacterOffset(textMarkerData, *domNode, 0, true); 1695 offset--; 1726 charOffset = characterOffsetForNodeAndOffset(*domNode, 0, true); 1696 1727 } else 1697 return; 1728 return CharacterOffset(); 1729 if (!offset) 1730 break; 1698 1731 } 1699 1732 if (offset > 0) 1700 textMarkerDataForCharacterOffset(textMarkerData, *domNode,offset, false);1701 return ;1733 charOffset = characterOffsetForNodeAndOffset(*charOffset.node, charOffset.offset - offset, false); 1734 return charOffset; 1702 1735 } 1703 1736 … … 1710 1743 domNode = nextNode(domNode); 1711 1744 if (!domNode) 1712 return ;1745 return CharacterOffset(); 1713 1746 range = rangeForNodeContents(domNode); 1714 1747 characterOffset = traverseToOffsetInRange(range, characterOffset.remaining(), toNodeEnd); 1715 1748 } 1716 1749 1750 return characterOffset; 1751 } 1752 1753 void 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); 1717 1758 setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset); 1718 1759 } … … 1738 1779 } 1739 1780 1740 VisiblePosition AXObjectCache::visiblePositionFromCharacterOffset(AccessibilityObject* obj, const CharacterOffset& characterOffset) 1741 { 1781 VisiblePosition AXObjectCache::visiblePositionFromCharacterOffset(const CharacterOffset& characterOffset) 1782 { 1783 if (characterOffset.isNull()) 1784 return VisiblePosition(); 1785 1786 RefPtr<AccessibilityObject> obj = this->getOrCreate(characterOffset.node); 1742 1787 if (!obj) 1743 1788 return VisiblePosition(); … … 1753 1798 } 1754 1799 1755 CharacterOffset AXObjectCache::characterOffsetFromVisiblePosition(AccessibilityObject* obj, const VisiblePosition& visiblePos) 1756 { 1800 CharacterOffset 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); 1757 1810 if (!obj) 1758 return 0;1811 return CharacterOffset(); 1759 1812 1760 1813 // Use nextVisiblePosition to calculate how many characters we need to traverse to the current position. 1761 Position deepPos = visiblePos.deepEquivalent();1762 1814 VisiblePositionRange vpRange = obj->visiblePositionRange(); 1763 1815 VisiblePosition vp = vpRange.start; … … 1817 1869 1818 1870 // convert to character offset 1819 CharacterOffset characterOffset = characterOffsetFromVisiblePosition( obj.get(),visiblePos);1871 CharacterOffset characterOffset = characterOffsetFromVisiblePosition(visiblePos); 1820 1872 textMarkerData.characterOffset = characterOffset.offset; 1821 1873 textMarkerData.characterStartIndex = characterOffset.startIndex; 1822 1874 1823 1875 cache->setNodeInUse(domNode); 1876 } 1877 1878 CharacterOffset AXObjectCache::nextCharacterOffset(const CharacterOffset& characterOffset) 1879 { 1880 if (characterOffset.isNull()) 1881 return CharacterOffset(); 1882 1883 return characterOffsetForNodeAndOffset(*characterOffset.node, characterOffset.offset + 1); 1884 } 1885 1886 CharacterOffset 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 1894 static 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 1908 static 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 1921 CharacterOffset 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 1941 CharacterOffset 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 1961 CharacterOffset 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 1973 CharacterOffset 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 1985 RefPtr<Range> AXObjectCache::leftWordRange(const CharacterOffset& characterOffset) 1986 { 1987 CharacterOffset start = previousWordStartCharacterOffset(characterOffset); 1988 CharacterOffset end = endCharacterOffsetOfWord(start); 1989 return rangeForUnorderedCharacterOffsets(start, end); 1990 } 1991 1992 RefPtr<Range> AXObjectCache::rightWordRange(const CharacterOffset& characterOffset) 1993 { 1994 CharacterOffset start = startCharacterOffsetOfWord(characterOffset); 1995 CharacterOffset end = nextWordEndCharacterOffset(start); 1996 return rangeForUnorderedCharacterOffsets(start, end); 1997 } 1998 1999 static 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 2011 UChar32 AXObjectCache::characterAfter(const CharacterOffset& characterOffset) 2012 { 2013 return characterForCharacterOffset(nextCharacterOffset(characterOffset)); 2014 } 2015 2016 UChar32 AXObjectCache::characterBefore(const CharacterOffset& characterOffset) 2017 { 2018 return characterForCharacterOffset(characterOffset); 2019 } 2020 2021 static 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 2037 CharacterOffset 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 2075 CharacterOffset 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); 1824 2119 } 1825 2120 -
trunk/Source/WebCore/accessibility/AXObjectCache.h
r196287 r196352 31 31 #include "Range.h" 32 32 #include "Timer.h" 33 #include "VisibleUnits.h" 33 34 #include <limits.h> 34 35 #include <wtf/Forward.h> … … 187 188 VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&); 188 189 CharacterOffset characterOffsetForTextMarkerData(TextMarkerData&); 189 void textMarkerDataForCharacterOffset(TextMarkerData&, Node&, int, bool toNodeEnd = false );190 void textMarkerDataForCharacterOffset(TextMarkerData&, Node&, int, bool toNodeEnd = false, bool ignoreStart = true); 190 191 void startOrEndTextMarkerDataForRange(TextMarkerData&, RefPtr<Range>, bool); 191 192 AccessibilityObject* accessibilityObjectForTextMarkerData(TextMarkerData&); … … 193 194 static RefPtr<Range> rangeForNodeContents(Node*); 194 195 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&); 195 204 196 205 enum AXNotification { … … 284 293 bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); } 285 294 295 // CharacterOffset functions. 286 296 Node* nextNode(Node*) const; 287 297 Node* previousNode(Node*) const; 288 298 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&); 291 301 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); 292 310 293 311 private: -
trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
r196287 r196352 859 859 } 860 860 861 - (id)textMarkerForNode:(Node&)node offset:(int)offset ignoreStart:(BOOL)ignoreStart 862 { 863 return textMarkerForCharacterOffset(m_object->axObjectCache(), node, offset, false, ignoreStart); 864 } 865 861 866 - (id)textMarkerForNode:(Node&)node offset:(int)offset 862 867 { 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 871 static id textMarkerForCharacterOffset(AXObjectCache* cache, Node& node, int offset, bool toNodeEnd, bool ignoreStart) 867 872 { 868 873 if (!cache) … … 874 879 875 880 TextMarkerData textMarkerData; 876 cache->textMarkerDataForCharacterOffset(textMarkerData, node, offset, toNodeEnd );881 cache->textMarkerDataForCharacterOffset(textMarkerData, node, offset, toNodeEnd, ignoreStart); 877 882 if (!textMarkerData.axID && !textMarkerData.ignored) 878 883 return nil; … … 4071 4076 4072 4077 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]; 4076 4084 } 4077 4085 4078 4086 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]; 4082 4093 } 4083 4094 … … 4107 4118 4108 4119 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]; 4111 4126 } 4112 4127 4113 4128 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]; 4116 4135 } 4117 4136 -
trunk/Source/WebCore/editing/VisibleUnits.cpp
r195949 r196352 440 440 441 441 442 enum BoundarySearchContextAvailability { DontHaveMoreContext, MayHaveMoreContext };443 444 typedef unsigned (*BoundarySearchFunction)(StringView, unsigned offset, BoundarySearchContextAvailability, bool& needMoreContext);445 446 442 static void prepend(Vector<UChar, 1024>& buffer, StringView string) 447 443 { … … 471 467 } 472 468 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; 469 unsigned suffixLengthForRange(RefPtr<Range> forwardsScanRange, Vector<UChar, 1024>& string) 470 { 486 471 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 485 unsigned 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 501 unsigned backwardSearchForBoundaryWithTextIterator(SimplifiedBackwardsTextIterator& it, Vector<UChar, 1024>& string, unsigned suffixLength, BoundarySearchFunction searchFunction) 502 { 513 503 unsigned next = 0; 514 504 bool needMoreContext = false; … … 516 506 bool inTextSecurityMode = it.node() && it.node()->renderer() && it.node()->renderer()->style().textSecurity() != TSNONE; 517 507 // iterate to get chunks until the searchFunction returns a non-zero value. 518 if (!inTextSecurityMode) 508 if (!inTextSecurityMode) 519 509 prepend(string, it.text()); 520 510 else { … … 535 525 ASSERT(!needMoreContext); 536 526 } 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 531 unsigned forwardSearchForBoundaryWithTextIterator(TextIterator& it, Vector<UChar, 1024>& string, unsigned prefixLength, BoundarySearchFunction searchFunction) 532 { 586 533 unsigned next = 0; 587 534 bool needMoreContext = false; … … 609 556 ASSERT(!needMoreContext); 610 557 } 558 559 return next; 560 } 561 562 static 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 611 static 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); 611 635 612 636 if (it.atEnd() && next == string.size()) -
trunk/Source/WebCore/editing/VisibleUnits.h
r195949 r196352 35 35 class Node; 36 36 class VisiblePosition; 37 class SimplifiedBackwardsTextIterator; 38 class TextIterator; 37 39 38 40 enum EWordSide { RightWordIfOnBoundary = false, LeftWordIfOnBoundary = true }; … … 108 110 WEBCORE_EXPORT PassRefPtr<Range> rangeExpandedAroundPositionByCharacters(const VisiblePosition&, int numberOfCharactersToExpand); 109 111 112 // helper function 113 enum BoundarySearchContextAvailability { DontHaveMoreContext, MayHaveMoreContext }; 114 typedef unsigned (*BoundarySearchFunction)(StringView, unsigned offset, BoundarySearchContextAvailability, bool& needMoreContext); 115 unsigned suffixLengthForRange(RefPtr<Range>, Vector<UChar, 1024>&); 116 unsigned prefixLengthForRange(RefPtr<Range>, Vector<UChar, 1024>&); 117 unsigned backwardSearchForBoundaryWithTextIterator(SimplifiedBackwardsTextIterator&, Vector<UChar, 1024>&, unsigned, BoundarySearchFunction); 118 unsigned forwardSearchForBoundaryWithTextIterator(TextIterator&, Vector<UChar, 1024>&, unsigned, BoundarySearchFunction); 119 110 120 } // namespace WebCore 111 121 -
trunk/Tools/ChangeLog
r196312 r196352 1 2016-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 1 59 2016-02-09 Csaba Osztrogonác <ossy@webkit.org> 2 60 -
trunk/Tools/DumpRenderTree/AccessibilityUIElement.cpp
r194054 r196352 975 975 } 976 976 977 static 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 986 static 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 995 static 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 1004 static 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 977 1013 static JSValueRef setSelectedVisibleTextRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 978 1014 { … … 1563 1599 { 1564 1600 return false; 1601 } 1602 1603 AccessibilityTextMarkerRange AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) 1604 { 1605 return nullptr; 1606 } 1607 1608 AccessibilityTextMarkerRange AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) 1609 { 1610 return nullptr; 1611 } 1612 1613 AccessibilityTextMarker AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*) 1614 { 1615 return nullptr; 1616 } 1617 1618 AccessibilityTextMarker AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*) 1619 { 1620 return nullptr; 1565 1621 } 1566 1622 … … 1745 1801 { "previousTextMarker", previousTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, 1746 1802 { "stringForTextMarkerRange", stringForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, 1803 { "leftWordTextMarkerRangeForTextMarker", leftWordTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, 1804 { "rightWordTextMarkerRangeForTextMarker", rightWordTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, 1805 { "previousWordStartTextMarkerForTextMarker", previousWordStartTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, 1806 { "nextWordEndTextMarkerForTextMarker", nextWordEndTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, 1747 1807 { "setSelectedChild", setSelectedChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, 1748 1808 { "setSelectedChildAtIndex", setSelectedChildAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, -
trunk/Tools/DumpRenderTree/AccessibilityUIElement.h
r194054 r196352 261 261 AccessibilityTextMarker startTextMarker(); 262 262 AccessibilityTextMarker endTextMarker(); 263 AccessibilityTextMarkerRange leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*); 264 AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*); 265 AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*); 266 AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*); 263 267 AccessibilityTextMarkerRange selectedTextMarkerRange(); 264 268 void resetSelectedTextMarkerRange(); -
trunk/Tools/DumpRenderTree/ios/AccessibilityUIElementIOS.mm
r195405 r196352 551 551 } 552 552 553 AccessibilityTextMarkerRange AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) 554 { 555 return nullptr; 556 } 557 558 AccessibilityTextMarkerRange AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) 559 { 560 return nullptr; 561 } 562 563 AccessibilityTextMarker AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*) 564 { 565 return nullptr; 566 } 567 568 AccessibilityTextMarker AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*) 569 { 570 return nullptr; 571 } 572 553 573 #endif // SUPPORTS_AX_TEXTMARKERS && PLATFORM(IOS) 554 574 -
trunk/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
r195405 r196352 1847 1847 } 1848 1848 1849 AccessibilityTextMarkerRange 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 1859 AccessibilityTextMarkerRange 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 1869 AccessibilityTextMarker 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 1879 AccessibilityTextMarker 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 1849 1889 #endif // SUPPORTS_AX_TEXTMARKERS && PLATFORM(MAC) 1850 1890 -
trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp
r194054 r196352 245 245 #endif 246 246 247 #if (!PLATFORM(MAC) && !PLATFORM(IOS)) || !HAVE(ACCESSIBILITY) 248 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; } 249 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; } 250 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; } 251 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; } 252 #endif 253 247 254 } // namespace WTR 248 255 -
trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h
r194054 r196352 252 252 PassRefPtr<AccessibilityTextMarker> endTextMarker(); 253 253 bool setSelectedVisibleTextRange(AccessibilityTextMarkerRange*); 254 PassRefPtr<AccessibilityTextMarkerRange> leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*); 255 PassRefPtr<AccessibilityTextMarkerRange> rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*); 256 PassRefPtr<AccessibilityTextMarker> previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*); 257 PassRefPtr<AccessibilityTextMarker> nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*); 254 258 255 259 // Returns an ordered list of supported actions for an element. -
trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl
r194054 r196352 202 202 readonly attribute AccessibilityTextMarker endTextMarker; 203 203 boolean setSelectedVisibleTextRange(AccessibilityTextMarkerRange range); 204 AccessibilityTextMarkerRange leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker); 205 AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker); 206 AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker textMarker); 207 AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker textMarker); 204 208 205 209 // Returns an ordered list of supported actions for an element. -
trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm
r195405 r196352 1097 1097 } 1098 1098 1099 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker) 1100 { 1101 return nullptr; 1102 } 1103 1104 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker) 1105 { 1106 return nullptr; 1107 } 1108 1109 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker) 1110 { 1111 return nullptr; 1112 } 1113 1114 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker) 1115 { 1116 return nullptr; 1117 } 1118 1099 1119 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const 1100 1120 { -
trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm
r195240 r196352 1874 1874 } 1875 1875 1876 PassRefPtr<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 1886 PassRefPtr<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 1896 PassRefPtr<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 1906 PassRefPtr<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 1876 1916 static NSString *_convertMathMultiscriptPairsToString(NSArray *pairs) 1877 1917 {
Note: See TracChangeset
for help on using the changeset viewer.