Commit 8c11a717 authored by Akihiro Ota's avatar Akihiro Ota Committed by Commit Bot

ChromeVox: Add output rule for the mark role.

This change adds an output rule for the mark role.
If needed, follow-up patches can build off of this change to support
associated aria-details elements. We also add tests to confirm
behavior, using sample code provided by the Docs team.

This change also adds a check for non-existent braille strings in
Msgs.getMsg(), since ChromeVox hits the following error without it:

"Invalid ChromeVox message id: role_content_insertion_brl"

'marked content'.

Fixed: 1126131
Change-Id: If588b3d018ddcab272a265bb63eb4c6119352781
AX-Relnotes: ChromeVox announces elements with role=mark as
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2422252
Commit-Queue: Akihiro Ota <akihiroota@chromium.org>
Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#819455}
parent ff94f947
......@@ -3255,3 +3255,56 @@ TEST_F('ChromeVoxBackgroundTest', 'AriaLeaves', function() {
.replay();
});
});
TEST_F('ChromeVoxBackgroundTest', 'MarkedContent', function() {
const mockFeedback = this.createMockFeedback();
const site = `
<p>Start</p>
<span>This is </span><span role="mark">my</span><span> text.</span>
<br>
<span>This is </span><span role="mark"
aria-roledescription="Comment">your</span><span> text.</span>
<br>
<span>This is </span><span role="suggestion"><span
role="insertion">their</span></span><span> text.</span>
<br>
<span>This is </span><span role="suggestion"><span
role="deletion">everyone's</span></span><span> text.</span>
`;
this.runWithLoadedTree(site, function(rootNode) {
mockFeedback.expectSpeech('Start')
.call(doCmd('nextObject'))
.expectSpeech('This is ')
.call(doCmd('nextObject'))
.expectSpeech('my', 'Marked content')
.expectBraille('my Marked content')
.call(doCmd('nextObject'))
.expectSpeech(' text.', 'Exited Marked content.')
.expectBraille(' text. Exited Marked content.')
.call(doCmd('nextObject'))
.expectSpeech('This is ')
.call(doCmd('nextObject'))
.expectSpeech('your', 'Comment')
.expectBraille('your Comment')
.call(doCmd('nextObject'))
.expectSpeech(' text.', 'Exited Comment.')
.expectBraille(' text. Exited Comment.')
.call(doCmd('nextObject'))
.expectSpeech('This is ')
.call(doCmd('nextObject'))
.expectSpeech('their', 'Insertion', 'Suggestion')
.expectBraille('their Insertion Suggestion')
.call(doCmd('nextObject'))
.expectSpeech(' text.', 'Exited Suggestion.', 'Exited Insertion.')
.expectBraille(' text. Exited Suggestion. Exited Insertion.')
.call(doCmd('nextObject'))
.expectSpeech('This is ')
.call(doCmd('nextObject'))
.expectSpeech(`everyone's`, 'Deletion', 'Suggestion')
.expectBraille(`everyone's Deletion Suggestion`)
.call(doCmd('nextObject'))
.expectSpeech(' text.', 'Exited Suggestion.', 'Exited Deletion.')
.expectBraille(' text. Exited Suggestion. Exited Deletion.')
.replay();
});
});
......@@ -1585,3 +1585,44 @@ TEST_F('ChromeVoxEditingTest', 'ContentEditableEvents', function() {
assertEquals('ab', contentEditable.value);
});
});
TEST_F('ChromeVoxEditingTest', 'MarkedContent', function() {
const mockFeedback = this.createMockFeedback();
const site = `
<div contenteditable role="textbox">
<p>Start</p>
<span>This is </span><span role="mark">my</span><span> text.</span>
<br>
<span>This is </span><span role="mark"
aria-roledescription="Comment">your</span><span> text.</span>
<br>
<span>This is </span><span role="suggestion"><span
role="insertion">their</span></span><span> text.</span>
<br>
<span>This is </span><span role="suggestion"><span
role="deletion">everyone's</span></span><span> text.</span>
</div>
`;
this.runWithLoadedTree(site, function(root) {
const input = root.find({role: RoleType.TEXT_FIELD});
this.listenOnce(input, 'focus', function() {
mockFeedback.call(this.press(KeyCode.DOWN))
.expectSpeech(
'This is ', 'my', 'Marked content', ' text.',
'Exited Marked content.')
.call(this.press(KeyCode.DOWN))
.expectSpeech(
'This is ', 'your', 'Comment', ' text.', 'Exited Comment.')
.call(this.press(KeyCode.DOWN))
.expectSpeech(
'This is ', 'their', 'Insertion', 'Suggestion', ' text.',
'Exited Suggestion.', 'Exited Insertion.')
.call(this.press(KeyCode.DOWN))
.expectSpeech(
'This is ', `everyone's`, 'Deletion', 'Suggestion', ' text.',
'Exited Suggestion.', 'Exited Deletion.')
.replay();
});
input.focus();
});
});
......@@ -2292,6 +2292,7 @@ Output.ROLE_INFO_ = {
{msgId: 'role_listitem', earconId: 'LIST_ITEM', inherits: 'abstractItem'},
log: {msgId: 'role_log', inherits: 'abstractNameFromContents'},
main: {msgId: 'role_main', inherits: 'abstractContainer'},
mark: {msgId: 'role_mark', inherits: 'abstractContainer'},
marquee: {msgId: 'role_marquee', inherits: 'abstractNameFromContents'},
math: {msgId: 'role_math', inherits: 'abstractContainer'},
menu: {msgId: 'role_menu', outputContextFirst: true, ignoreAncestry: true},
......@@ -2411,6 +2412,12 @@ Output.PRESSED_STATE_MAP = {
/**
* Rules specifying format of AutomationNodes for output.
* @type {!Object<Object<Object<string>>>}
* Please see below for more information on properties.
* speak: The speech rule for when ChromeVox range lands exactly on the node.
* braille: The braille rule for when ChromeVox range lands exactly on the node.
* enter: The rule for when ChromeVox range enters the node's subtree.
* Can contain speak and braille properties.
* leave: The rule for when ChromeVox range exits the node's subtree.
*/
Output.RULES = {
navigate: {
......
......@@ -36,6 +36,14 @@ Msgs = class {
return Msgs.applySubstitutions_(message, opt_subs);
}
message = chrome.i18n.getMessage(Msgs.NAMESPACE_ + messageId, opt_subs);
if ((message === undefined || message === '') &&
messageId.endsWith('_brl')) {
// Braille string entries are optional. If we couldn't find a braille-
// specific string, try again without the '_brl' suffix.
message = chrome.i18n.getMessage(
Msgs.NAMESPACE_ + messageId.replace('_brl', ''), opt_subs);
}
if (message == undefined || message == '') {
throw new Error('Invalid ChromeVox message id: ' + messageId);
}
......
......@@ -3032,11 +3032,14 @@
<message desc="Describes gesture that simulates pressing the enter key. No associated UI with this string which is spoken using text-to-speech." name="IDS_CHROMEVOX_ENTER_GESTURE_DESCRIPTION" is_accessibility_with_no_ui="true">
Enter
</message>
<message desc="Describes gesture that movees to the previous important section on the screen (e.g. the Launcher, Status Tray, etc). No associated UI with this string which is spoken using text-to-speech." name="IDS_CHROMEVOX_PREVIOUS_PANE_GESTURE_DESCRIPTION" is_accessibility_with_no_ui="true">
<message desc="Describes gesture that moves to the previous important section on the screen (e.g. the Launcher, Status Tray, etc). No associated UI with this string which is spoken using text-to-speech." name="IDS_CHROMEVOX_PREVIOUS_PANE_GESTURE_DESCRIPTION" is_accessibility_with_no_ui="true">
Move to previous section. Examples include the Status Tray and Launcher.
</message>
<message desc="Describes gesture that movees to the next important section on the screen (e.g. the Launcher, Status Tray, etc). No associated UI with this string which is spoken using text-to-speech." name="IDS_CHROMEVOX_NEXT_PANE_GESTURE_DESCRIPTION" is_accessibility_with_no_ui="true">
<message desc="Describes gesture that moves to the next important section on the screen (e.g. the Launcher, Status Tray, etc). No associated UI with this string which is spoken using text-to-speech." name="IDS_CHROMEVOX_NEXT_PANE_GESTURE_DESCRIPTION" is_accessibility_with_no_ui="true">
Move to next section. Examples include the Status Tray and Launcher.
</message>
<message desc="Describes an element with the ARIA role mark. We use 'marked content' since it's more descriptive than 'mark'." name="IDS_CHROMEVOX_ROLE_MARK" is_accessibility_with_no_ui="true">
Marked content
</message>
</grit-part>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment