Diff
Modified: trunk/LayoutTests/ChangeLog (214111 => 214112)
--- trunk/LayoutTests/ChangeLog 2017-03-17 19:30:43 UTC (rev 214111)
+++ trunk/LayoutTests/ChangeLog 2017-03-17 19:48:36 UTC (rev 214112)
@@ -1,3 +1,15 @@
+2017-03-17 Nan Wang <n_w...@apple.com>
+
+ AX: VoiceOver no longer works corectly with editable text in the web
+ https://bugs.webkit.org/show_bug.cgi?id=169801
+
+ Reviewed by Chris Fleizach.
+
+ * accessibility/ios-simulator/element-text-range-for-text-control-expected.txt: Added.
+ * accessibility/ios-simulator/element-text-range-for-text-control.html: Added.
+ * accessibility/mac/text-markers-for-input-with-placeholder-expected.txt: Added.
+ * accessibility/mac/text-markers-for-input-with-placeholder.html: Added.
+
2017-03-17 Dave Hyatt <hy...@apple.com>
Initial letter does not paginate properly.
Added: trunk/LayoutTests/accessibility/ios-simulator/element-text-range-for-text-control-expected.txt (0 => 214112)
--- trunk/LayoutTests/accessibility/ios-simulator/element-text-range-for-text-control-expected.txt (rev 0)
+++ trunk/LayoutTests/accessibility/ios-simulator/element-text-range-for-text-control-expected.txt 2017-03-17 19:48:36 UTC (rev 214112)
@@ -0,0 +1,11 @@
+
+This test ensures that elementTextRange is valid for text controls
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS input.elementTextPosition != -1 is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/accessibility/ios-simulator/element-text-range-for-text-control.html (0 => 214112)
--- trunk/LayoutTests/accessibility/ios-simulator/element-text-range-for-text-control.html (rev 0)
+++ trunk/LayoutTests/accessibility/ios-simulator/element-text-range-for-text-control.html 2017-03-17 19:48:36 UTC (rev 214112)
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script>
+var successfullyParsed = false;
+</script>
+<script src=""
+</head>
+<body id="body">
+
+<input id="input" type='text'>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+
+ description("This test ensures that elementTextRange is valid for text controls");
+
+ if (window.accessibilityController) {
+
+ var input = accessibilityController.accessibleElementById("input");
+ shouldBeTrue("input.elementTextPosition != -1");
+ }
+
+ successfullyParsed = true;
+</script>
+
+<script src=""
+</body>
+</html>
+
Added: trunk/LayoutTests/accessibility/mac/text-markers-for-input-with-placeholder-expected.txt (0 => 214112)
--- trunk/LayoutTests/accessibility/mac/text-markers-for-input-with-placeholder-expected.txt (rev 0)
+++ trunk/LayoutTests/accessibility/mac/text-markers-for-input-with-placeholder-expected.txt 2017-03-17 19:48:36 UTC (rev 214112)
@@ -0,0 +1,12 @@
+
+This tests that start and end text markers of an input element with placeholder are valid.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS input.isEqual(startObject) is true
+PASS input.isEqual(endObject) is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/accessibility/mac/text-markers-for-input-with-placeholder.html (0 => 214112)
--- trunk/LayoutTests/accessibility/mac/text-markers-for-input-with-placeholder.html (rev 0)
+++ trunk/LayoutTests/accessibility/mac/text-markers-for-input-with-placeholder.html 2017-03-17 19:48:36 UTC (rev 214112)
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body id="body">
+
+<input id="input" type='text' placeholder='text'>
+
+<div role="group" id="console"></div>
+
+<script>
+
+ description("This tests that start and end text markers of an input element with placeholder are valid.");
+
+ // Test contenteditable with newlines.
+ var input = accessibilityController.accessibleElementById("input");
+ var textMarkerRange = input.textMarkerRangeForElement(input);
+ var startMarker = input.endTextMarkerForTextMarkerRange(textMarkerRange);
+ var endMarker = input.endTextMarkerForTextMarkerRange(textMarkerRange);
+
+ // make sure the associated object of endMarker is the input object
+ var startObject = input.accessibilityElementForTextMarker(startMarker);
+ var endObject = input.accessibilityElementForTextMarker(endMarker);
+ shouldBeTrue("input.isEqual(startObject)");
+ shouldBeTrue("input.isEqual(endObject)");
+
+</script>
+
+<script src=""
+</body>
\ No newline at end of file
Modified: trunk/Source/WebCore/ChangeLog (214111 => 214112)
--- trunk/Source/WebCore/ChangeLog 2017-03-17 19:30:43 UTC (rev 214111)
+++ trunk/Source/WebCore/ChangeLog 2017-03-17 19:48:36 UTC (rev 214112)
@@ -1,3 +1,26 @@
+2017-03-17 Nan Wang <n_w...@apple.com>
+
+ AX: VoiceOver no longer works corectly with editable text in the web
+ https://bugs.webkit.org/show_bug.cgi?id=169801
+
+ Reviewed by Chris Fleizach.
+
+ The issue is that since we are entering text controls when getting the text marker,
+ the end text marker of the input tag might associate to the placeholder div instead of
+ the input tag itself.
+ Fixed the issue by checking the shadow elements using shadowHost() instead of isShadowRoot().
+ Also, only enter text controls when navigating by characters/indexes, so that both Mac and
+ iOS will get the correct text marker ranges for shadow host elements.
+
+ Tests: accessibility/ios-simulator/element-text-range-for-text-control.html
+ accessibility/mac/text-markers-for-input-with-placeholder.html
+
+ * accessibility/AXObjectCache.cpp:
+ (WebCore::AXObjectCache::traverseToOffsetInRange):
+ (WebCore::AXObjectCache::startOrEndCharacterOffsetForRange):
+ (WebCore::AXObjectCache::characterOffsetForIndex):
+ * accessibility/AXObjectCache.h:
+
2017-03-17 Wenson Hsieh <wenson_hs...@apple.com>
[WK1] Support animated transitions when performing a data interaction operation
Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (214111 => 214112)
--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp 2017-03-17 19:30:43 UTC (rev 214111)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp 2017-03-17 19:48:36 UTC (rev 214112)
@@ -1555,6 +1555,7 @@
bool toNodeEnd = option & TraverseOptionToNodeEnd;
bool validateOffset = option & TraverseOptionValidateOffset;
+ bool doNotEnterTextControls = option & TraverseOptionDoNotEnterTextControls;
int offsetInCharacter = 0;
int cumulativeOffset = 0;
@@ -1564,7 +1565,7 @@
bool finished = false;
int lastStartOffset = 0;
- TextIterator iterator(range.get(), TextIteratorEntersTextControls);
+ TextIterator iterator(range.get(), doNotEnterTextControls ? TextIteratorDefaultBehavior : TextIteratorEntersTextControls);
// When the range has zero length, there might be replaced node or brTag that we need to increment the characterOffset.
if (iterator.atEnd()) {
@@ -1617,11 +1618,13 @@
if (childNode && childNode->renderer() && childNode->renderer()->isBR()) {
currentNode = childNode;
hasReplacedNodeOrBR = true;
- } else if (currentNode->isShadowRoot()) {
+ } else if (Element *shadowHost = currentNode->shadowHost()) {
// Since we are entering text controls, we should set the currentNode
// to be the shadow host when there's no content.
- currentNode = currentNode->shadowHost();
- continue;
+ if (nodeIsTextControl(shadowHost)) {
+ currentNode = currentNode->shadowHost();
+ continue;
+ }
} else if (currentNode != previousNode) {
// We should set the start offset and length for the current node in case this is the last iteration.
lastStartOffset = 1;
@@ -1837,7 +1840,7 @@
this->setNodeInUse(domNode);
}
-CharacterOffset AXObjectCache::startOrEndCharacterOffsetForRange(RefPtr<Range> range, bool isStart)
+CharacterOffset AXObjectCache::startOrEndCharacterOffsetForRange(RefPtr<Range> range, bool isStart, bool enterTextControls)
{
if (!range)
return CharacterOffset();
@@ -1865,7 +1868,10 @@
offset += nodeStartOffset.offset;
}
- return traverseToOffsetInRange(WTFMove(copyRange), offset, isStart ? TraverseOptionDefault : TraverseOptionToNodeEnd, stayWithinRange);
+ TraverseOption options = isStart ? TraverseOptionDefault : TraverseOptionToNodeEnd;
+ if (!enterTextControls)
+ options = static_cast<TraverseOption>(options | TraverseOptionDoNotEnterTextControls);
+ return traverseToOffsetInRange(WTFMove(copyRange), offset, options, stayWithinRange);
}
void AXObjectCache::startOrEndTextMarkerDataForRange(TextMarkerData& textMarkerData, RefPtr<Range> range, bool isStart)
@@ -2616,8 +2622,8 @@
return CharacterOffset();
RefPtr<Range> range = obj->elementRange();
- CharacterOffset start = startOrEndCharacterOffsetForRange(range, true);
- CharacterOffset end = startOrEndCharacterOffsetForRange(range, false);
+ CharacterOffset start = startOrEndCharacterOffsetForRange(range, true, true);
+ CharacterOffset end = startOrEndCharacterOffsetForRange(range, false, true);
CharacterOffset result = start;
for (int i = 0; i < index; i++) {
result = nextCharacterOffset(result, false);
Modified: trunk/Source/WebCore/accessibility/AXObjectCache.h (214111 => 214112)
--- trunk/Source/WebCore/accessibility/AXObjectCache.h 2017-03-17 19:30:43 UTC (rev 214111)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.h 2017-03-17 19:48:36 UTC (rev 214112)
@@ -222,7 +222,7 @@
CharacterOffset nextCharacterOffset(const CharacterOffset&, bool ignoreNextNodeStart = true);
CharacterOffset previousCharacterOffset(const CharacterOffset&, bool ignorePreviousNodeEnd = true);
void startOrEndTextMarkerDataForRange(TextMarkerData&, RefPtr<Range>, bool);
- CharacterOffset startOrEndCharacterOffsetForRange(RefPtr<Range>, bool);
+ CharacterOffset startOrEndCharacterOffsetForRange(RefPtr<Range>, bool, bool enterTextControls = false);
AccessibilityObject* accessibilityObjectForTextMarkerData(TextMarkerData&);
RefPtr<Range> rangeForUnorderedCharacterOffsets(const CharacterOffset&, const CharacterOffset&);
static RefPtr<Range> rangeForNodeContents(Node*);
@@ -351,7 +351,7 @@
bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); }
// CharacterOffset functions.
- enum TraverseOption { TraverseOptionDefault = 1 << 0, TraverseOptionToNodeEnd = 1 << 1, TraverseOptionIncludeStart = 1 << 2, TraverseOptionValidateOffset = 1 << 3 };
+ enum TraverseOption { TraverseOptionDefault = 1 << 0, TraverseOptionToNodeEnd = 1 << 1, TraverseOptionIncludeStart = 1 << 2, TraverseOptionValidateOffset = 1 << 3, TraverseOptionDoNotEnterTextControls = 1 << 4 };
Node* nextNode(Node*) const;
Node* previousNode(Node*) const;
CharacterOffset traverseToOffsetInRange(RefPtr<Range>, int, TraverseOption = TraverseOptionDefault, bool stayWithinRange = false);