Title: [214112] trunk
Revision
214112
Author
n_w...@apple.com
Date
2017-03-17 12:48:36 -0700 (Fri, 17 Mar 2017)

Log Message

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.

Source/WebCore:

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:

LayoutTests:

* 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.

Modified Paths

Added Paths

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);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to