Fix end of line announcements
- fix Cursor.deepEquivalent to account for end of line selection offset.
- add Cursor.deepEquivalent test coverage.
- add spoken feedback for end of line.
- add test coverage for end of line output.
BUG=719654
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:closure_compilation
Review-Url: https://codereview.chromium.org/2948173004
Cr-Commit-Position: refs/heads/master@{#482021}
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
index 7142a0e7..1f3f614f 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
@@ -445,9 +445,14 @@
var target = newNode.firstChild;
var length = 0;
while (target && length < newIndex) {
- if (length <= newIndex && newIndex < (length + target.name.length))
+ var newLength = length + target.name.length;
+
+ // Either |newIndex| falls between target's text or |newIndex| is the
+ // total length of all sibling text content.
+ if ((length <= newIndex && newIndex < newLength) ||
+ (newIndex == newLength && !target.nextSibling))
break;
- length += target.name.length;
+ length = newLength;
target = target.nextSibling;
}
if (target) {
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
index fd8243ce..f0b8a9e 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
@@ -462,3 +462,54 @@
assertFalse(inlineTextBoxRange.contentEquals(rootRange));
});
});
+
+TEST_F('CursorsTest', 'DeepEquivalency', function() {
+ this.runWithLoadedTree(function() {/*!
+ <p style="word-spacing:100000px">this is a test</p>
+ */}, function(root) {
+ var textNode = root.find({role: RoleType.STATIC_TEXT});
+
+ var text = new cursors.Cursor(textNode, 2);
+ deep = text.deepEquivalent;
+ assertEquals('this ', deep.node.name);
+ assertEquals(RoleType.INLINE_TEXT_BOX, deep.node.role);
+ assertEquals(2, deep.index);
+
+ text = new cursors.Cursor(textNode, 5);
+ deep = text.deepEquivalent;
+ assertEquals('is ', deep.node.name);
+ assertEquals(RoleType.INLINE_TEXT_BOX, deep.node.role);
+ assertEquals(0, deep.index);
+
+ text = new cursors.Cursor(textNode, 7);
+ deep = text.deepEquivalent;
+ assertEquals('is ', deep.node.name);
+ assertEquals(RoleType.INLINE_TEXT_BOX, deep.node.role);
+ assertEquals(2, deep.index);
+
+ text = new cursors.Cursor(textNode, 8);
+ deep = text.deepEquivalent;
+ assertEquals('a ', deep.node.name);
+ assertEquals(RoleType.INLINE_TEXT_BOX, deep.node.role);
+ assertEquals(0, deep.index);
+
+ text = new cursors.Cursor(textNode, 11);
+ deep = text.deepEquivalent;
+ assertEquals('test', deep.node.name);
+ assertEquals(RoleType.INLINE_TEXT_BOX, deep.node.role);
+ assertEquals(1, deep.index);
+
+ // This is the only selection that can be placed at the length of the node's
+ // text. This only happens at the end of a line.
+ text = new cursors.Cursor(textNode, 14);
+ deep = text.deepEquivalent;
+ assertEquals('test', deep.node.name);
+ assertEquals(RoleType.INLINE_TEXT_BOX, deep.node.role);
+ assertEquals(4, deep.index);
+
+ // However, any offset larger is invalid.
+ text = new cursors.Cursor(textNode, 15);
+ deep = text.deepEquivalent;
+ assertTrue(text.equals(deep));
+ });
+});
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
index 4a729cb..fdaae352 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
@@ -391,9 +391,13 @@
/** @override */
describeSelectionChanged: function(evt) {
- // Ignore end of text announcements.
- if ((this.start + 1) == evt.start && evt.start == this.value.length)
+ // Note that since Chrome allows for selection to be placed immediately at
+ // the end of a line (i.e. end == value.length) and since we try to describe
+ // the character to the right, just describe it as a new line.
+ if ((this.start + 1) == evt.start && evt.start == this.value.length) {
+ this.speak('\n', evt.triggeredByUser);
return;
+ }
cvox.ChromeVoxEditableTextBase.prototype.describeSelectionChanged.call(
this, evt);
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs
index d743aa2..23bc7d14 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs
@@ -373,6 +373,43 @@
});
});
+TEST_F('EditingTest', 'RichTextMoveByCharacterEndOfLine', function() {
+ editing.useRichText = true;
+ var mockFeedback = this.createMockFeedback();
+ this.runWithLoadedTree(function() {/*!
+ <div id="go" role="textbox" contenteditable>Test</div>
+
+ <script>
+ document.getElementById('go').addEventListener('click', function() {
+ var sel = getSelection();
+ sel.modify('move', 'forward', 'character');
+ }, true);
+ </script>
+ */}, function(root) {
+ var input = root.find({role: RoleType.TEXT_FIELD});
+ var moveByChar = input.doDefault.bind(input);
+ var lineText = 'Test';
+
+ this.listenOnce(input, 'focus', function() {
+ mockFeedback.call(moveByChar)
+ .expectSpeech('e')
+ .expectBraille(lineText, { startIndex: 1, endIndex: 1 })
+ .call(moveByChar)
+ .expectSpeech('s')
+ .expectBraille(lineText, { startIndex: 2, endIndex: 2 })
+ .call(moveByChar)
+ .expectSpeech('t')
+ .expectBraille(lineText, { startIndex: 3, endIndex: 3 })
+ .call(moveByChar)
+ .expectSpeech('\n')
+ .expectBraille(lineText, { startIndex: 4, endIndex: 4 })
+
+ .replay();
+ });
+ input.focus();
+ });
+});
+
TEST_F('EditingTest', 'EditableLineOneStaticText', function() {
this.runWithLoadedTree(function() {/*!
<p contenteditable style="word-spacing:100000px">this is a test</p>