summaryrefslogtreecommitdiff
path: root/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background')
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js202
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js277
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util_test.extjs102
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.html7
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js810
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs370
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/classic_compatibility.js181
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js397
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs294
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcon_engine.js711
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/control.wavbin14266 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/selection.wavbin13714 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/selection_reverse.wavbin9138 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/skim.wavbin24808 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/small_room_2.wavbin665344 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/static.wavbin304 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/loader.js10
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js1329
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs545
19 files changed, 0 insertions, 5235 deletions
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
deleted file mode 100644
index f0ce021c40b..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview ChromeVox predicates for the automation extension API.
- */
-
-goog.provide('AutomationPredicate');
-goog.provide('AutomationPredicate.Binary');
-goog.provide('AutomationPredicate.Unary');
-
-goog.scope(function() {
-var RoleType = chrome.automation.RoleType;
-
-/**
- * @constructor
- */
-AutomationPredicate = function() {};
-
-/**
- * @typedef {function(chrome.automation.AutomationNode) : boolean}
- */
-AutomationPredicate.Unary;
-
-/**
- * @typedef {function(chrome.automation.AutomationNode,
- * chrome.automation.AutomationNode) : boolean}
- */
-AutomationPredicate.Binary;
-
-/**
- * Constructs a predicate given a role.
- * @param {RoleType} role
- * @return {AutomationPredicate.Unary}
- */
-AutomationPredicate.withRole = function(role) {
- return function(node) {
- return node.role == role;
- };
-};
-
-/** @type {AutomationPredicate.Unary} */
-AutomationPredicate.checkBox = AutomationPredicate.withRole(RoleType.checkBox);
-/** @type {AutomationPredicate.Unary} */
-AutomationPredicate.comboBox = AutomationPredicate.withRole(RoleType.comboBox);
-/** @type {AutomationPredicate.Unary} */
-AutomationPredicate.editText = AutomationPredicate.withRole(RoleType.textField);
-/** @type {AutomationPredicate.Unary} */
-AutomationPredicate.heading = AutomationPredicate.withRole(RoleType.heading);
-/** @type {AutomationPredicate.Unary} */
-AutomationPredicate.inlineTextBox =
- AutomationPredicate.withRole(RoleType.inlineTextBox);
-/** @type {AutomationPredicate.Unary} */
-AutomationPredicate.link = AutomationPredicate.withRole(RoleType.link);
-/** @type {AutomationPredicate.Unary} */
-AutomationPredicate.table = AutomationPredicate.withRole(RoleType.table);
-
-/**
- * @param {chrome.automation.AutomationNode} node
- * @return {boolean}
- */
-AutomationPredicate.button = function(node) {
- return /button/i.test(node.role);
-};
-
-/**
- * @param {chrome.automation.AutomationNode} node
- * @return {boolean}
- */
-AutomationPredicate.formField = function(node) {
- switch (node.role) {
- case 'button':
- case 'buttonDropDown':
- case 'checkBox':
- case 'comboBox':
- case 'date':
- case 'dateTime':
- case 'details':
- case 'disclosureTriangle':
- case 'form':
- case 'menuButton':
- case 'menuListPopup':
- case 'popUpButton':
- case 'radioButton':
- case 'searchBox':
- case 'slider':
- case 'spinButton':
- case 'switch':
- case 'tab':
- case 'textField':
- case 'time':
- case 'toggleButton':
- case 'tree':
- return true;
- }
- return false;
-};
-
-/**
- * @param {chrome.automation.AutomationNode} node
- * @return {boolean}
- */
-AutomationPredicate.landmark = function(node) {
- switch (node.role) {
- case 'application':
- case 'banner':
- case 'complementary':
- case 'contentInfo':
- case 'form':
- case 'main':
- case 'navigation':
- case 'search':
- return true;
- }
- return false;
-};
-
-/**
- * @param {chrome.automation.AutomationNode} node
- * @return {boolean}
- */
-AutomationPredicate.visitedLink = function(node) {
- return node.state.visited;
-};
-
-/**
- * @param {chrome.automation.AutomationNode} node
- * @return {boolean}
- */
-AutomationPredicate.focused = function(node) {
- return node.state.focused;
-};
-
-/**
- * @param {chrome.automation.AutomationNode} node
- * @return {boolean}
- */
-AutomationPredicate.leaf = function(node) {
- return !node.firstChild ||
- node.role == RoleType.button ||
- node.role == RoleType.buttonDropDown ||
- node.role == RoleType.popUpButton ||
- node.role == RoleType.slider ||
- node.role == RoleType.textField ||
- node.children.every(function(n) {
- return n.state.invisible;
- });
-};
-
-/**
- * @param {chrome.automation.AutomationNode} node
- * @return {boolean}
- */
-AutomationPredicate.leafWithText = function(node) {
- return AutomationPredicate.leaf(node) &&
- !!(node.name || node.value);
-};
-
-/**
- * Matches against non-inline textbox 'nodes' which have an equivalent in the
- * DOM.
- * @param {chrome.automation.AutomationNode} node
- * @return {boolean}
- */
-AutomationPredicate.leafDomNode = function(node) {
- return AutomationPredicate.leaf(node) ||
- node.role == RoleType.staticText;
-};
-
-/**
- * @param {chrome.automation.AutomationNode} first
- * @param {chrome.automation.AutomationNode} second
- * @return {boolean}
- */
-AutomationPredicate.linebreak = function(first, second) {
- // TODO(dtseng): Use next/previousOnLin once available.
- var fl = first.location;
- var sl = second.location;
- return fl.top != sl.top ||
- (fl.top + fl.height != sl.top + sl.height);
-};
-
-/**
- * Leaf nodes that should be ignored while traversing the automation tree. For
- * example, apply this predicate when moving to the next element.
- * @param {chrome.automation.AutomationNode} node
- * @return {boolean}
- */
-AutomationPredicate.shouldIgnoreLeaf = function(node) {
- if (node.name || node.value)
- return false;
-
- return AutomationPredicate.leaf(node) &&
- (node.role == RoleType.client ||
- node.role == RoleType.div ||
- node.role == RoleType.group ||
- node.role == RoleType.image ||
- node.role == RoleType.staticText);
-};
-
-}); // goog.scope
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
deleted file mode 100644
index 17b52ffb4f6..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
+++ /dev/null
@@ -1,277 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview ChromeVox utilities for the automation extension API.
- */
-
-goog.provide('AutomationUtil');
-goog.provide('AutomationUtil.Dir');
-
-goog.require('AutomationPredicate');
-
-/**
- * @constructor
- */
-AutomationUtil = function() {};
-
-/**
- * Possible directions to perform tree traversals.
- * @enum {string}
- */
-AutomationUtil.Dir = {
- // Search from left to right.
- FORWARD: 'forward',
-
- // Search from right to left.
- BACKWARD: 'backward'
-};
-
-
-goog.scope(function() {
-var AutomationNode = chrome.automation.AutomationNode;
-var Dir = AutomationUtil.Dir;
-
-/**
- * Find a node in subtree of |cur| satisfying |pred| using pre-order traversal.
- * @param {AutomationNode} cur Node to begin the search from.
- * @param {Dir} dir
- * @param {AutomationPredicate.Unary} pred A predicate to apply
- * to a candidate node.
- * @return {AutomationNode}
- */
-AutomationUtil.findNodePre = function(cur, dir, pred) {
- if (pred(cur))
- return cur;
-
- var child = dir == Dir.BACKWARD ? cur.lastChild : cur.firstChild;
- while (child) {
- var ret = AutomationUtil.findNodePre(child, dir, pred);
- if (ret)
- return ret;
- child = dir == Dir.BACKWARD ?
- child.previousSibling : child.nextSibling;
- }
-};
-
-/**
- * Find a node in subtree of |cur| satisfying |pred| using post-order traversal.
- * @param {AutomationNode} cur Node to begin the search from.
- * @param {Dir} dir
- * @param {AutomationPredicate.Unary} pred A predicate to apply
- * to a candidate node.
- * @return {AutomationNode}
- */
-AutomationUtil.findNodePost = function(cur, dir, pred) {
- var child = dir == Dir.BACKWARD ? cur.lastChild : cur.firstChild;
- while (child) {
- var ret = AutomationUtil.findNodePost(child, dir, pred);
- if (ret)
- return ret;
- child = dir == Dir.BACKWARD ?
- child.previousSibling : child.nextSibling;
- }
-
- if (pred(cur))
- return cur;
-};
-
-/**
- * Find the next node in the given direction that is either an immediate sibling
- * or a sibling of an ancestor.
- * @param {AutomationNode} cur Node to start search from.
- * @param {Dir} dir
- * @return {AutomationNode}
- */
-AutomationUtil.findNextSubtree = function(cur, dir) {
- while (cur) {
- var next = dir == Dir.BACKWARD ?
- cur.previousSibling : cur.nextSibling;
- if (!AutomationUtil.isInSameTree(cur, next))
- return null;
- if (next)
- return next;
- if (!AutomationUtil.isInSameTree(cur, cur.parent))
- return null;
- cur = cur.parent;
- if (AutomationUtil.isTraversalRoot_(cur))
- return null;
- }
-};
-
-/**
- * Find the next node in the given direction in depth first order.
- * @param {AutomationNode} cur Node to begin the search from.
- * @param {Dir} dir
- * @param {AutomationPredicate.Unary} pred A predicate to apply
- * to a candidate node.
- * @return {AutomationNode}
- */
-AutomationUtil.findNextNode = function(cur, dir, pred) {
- var next = cur;
- do {
- if (!(next = AutomationUtil.findNextSubtree(cur, dir)))
- return null;
- cur = next;
- next = AutomationUtil.findNodePre(next, dir, pred);
- if (next && AutomationPredicate.shouldIgnoreLeaf(next)) {
- cur = next;
- next = null;
- }
- } while (!next);
- return next;
-};
-
-/**
- * Given nodes a_1, ..., a_n starting at |cur| in pre order traversal, apply
- * |pred| to a_i and a_(i - 1) until |pred| is satisfied. Returns a_(i - 1) or
- * a_i (depending on opt_options.before) or null if no match was found.
- * @param {AutomationNode} cur
- * @param {Dir} dir
- * @param {AutomationPredicate.Binary} pred
- * @param {{filter: (AutomationPredicate.Unary|undefined),
- * before: boolean?}=} opt_options
- * filter - Filters which candidate nodes to consider. Defaults to leaf
- * only.
- * before - True to return a_(i - 1); a_i otherwise. Defaults to false.
- * @return {AutomationNode}
- */
-AutomationUtil.findNodeUntil = function(cur, dir, pred, opt_options) {
- opt_options =
- opt_options || {filter: AutomationPredicate.leaf, before: false};
- if (!opt_options.filter)
- opt_options.filter = AutomationPredicate.leaf;
-
- var before = null;
- var after = null;
- var prev = cur;
- AutomationUtil.findNextNode(cur,
- dir,
- function(candidate) {
- if (!opt_options.filter(candidate))
- return false;
-
- var satisfied = pred(prev, candidate);
-
- prev = candidate;
- if (!satisfied)
- before = candidate;
- else
- after = candidate;
- return satisfied;
- });
- return opt_options.before ? before : after;
-};
-
-/**
- * Returns an array containing ancestors of node starting at root down to node.
- * @param {!AutomationNode} node
- * @return {!Array<AutomationNode>}
- */
-AutomationUtil.getAncestors = function(node) {
- var ret = [];
- var candidate = node;
- while (candidate) {
- ret.push(candidate);
-
- if (!AutomationUtil.isInSameTree(candidate, candidate.parent))
- break;
-
- candidate = candidate.parent;
- }
- return ret.reverse();
-};
-
-/**
- * Gets the first index where the two input arrays differ. Returns -1 if they
- * do not.
- * @param {!Array<AutomationNode>} ancestorsA
- * @param {!Array<AutomationNode>} ancestorsB
- * @return {number}
- */
-AutomationUtil.getDivergence = function(ancestorsA, ancestorsB) {
- for (var i = 0; i < ancestorsA.length; i++) {
- if (ancestorsA[i] !== ancestorsB[i])
- return i;
- }
- if (ancestorsA.length == ancestorsB.length)
- return -1;
- return ancestorsA.length;
-};
-
-/**
- * Returns ancestors of |node| that are not also ancestors of |prevNode|.
- * @param {!AutomationNode} prevNode
- * @param {!AutomationNode} node
- * @return {!Array<AutomationNode>}
- */
-AutomationUtil.getUniqueAncestors = function(prevNode, node) {
- var prevAncestors = AutomationUtil.getAncestors(prevNode);
- var ancestors = AutomationUtil.getAncestors(node);
- var divergence = AutomationUtil.getDivergence(prevAncestors, ancestors);
- return ancestors.slice(divergence);
-};
-
-/**
- * Given |nodeA| and |nodeB| in that order, determines their ordering in the
- * document.
- * @param {!AutomationNode} nodeA
- * @param {!AutomationNode} nodeB
- * @return {AutomationUtil.Dir}
- */
-AutomationUtil.getDirection = function(nodeA, nodeB) {
- var ancestorsA = AutomationUtil.getAncestors(nodeA);
- var ancestorsB = AutomationUtil.getAncestors(nodeB);
- var divergence = AutomationUtil.getDivergence(ancestorsA, ancestorsB);
-
- // Default to Dir.FORWARD.
- if (divergence == -1)
- return Dir.FORWARD;
-
- var divA = ancestorsA[divergence];
- var divB = ancestorsB[divergence];
-
- // One of the nodes is an ancestor of the other. Don't distinguish and just
- // consider it Dir.FORWARD.
- if (!divA || !divB || divA.parent === nodeB || divB.parent === nodeA)
- return Dir.FORWARD;
-
- return divA.indexInParent <= divB.indexInParent ? Dir.FORWARD : Dir.BACKWARD;
-};
-
-/**
- * Determines whether the two given nodes come from the same tree source.
- * @param {AutomationNode} a
- * @param {AutomationNode} b
- * @return {boolean}
- */
-AutomationUtil.isInSameTree = function(a, b) {
- if (!a || !b)
- return true;
-
- // Given two non-desktop roots, consider them in the "same" tree.
- return a.root === b.root ||
- (a.root.role == b.root.role && a.root.role == 'rootWebArea');
-};
-
-/**
- * Returns whether the given node should not be crossed when performing
- * traversals up the ancestry chain.
- * @param {AutomationNode} node
- * @return {boolean}
- * @private
- */
-AutomationUtil.isTraversalRoot_ = function(node) {
- switch (node.role) {
- case 'dialog':
- case 'window':
- return true;
- case 'toolbar':
- return node.root.role == 'desktop';
- default:
- return false;
- }
-};
-
-}); // goog.scope
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util_test.extjs b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util_test.extjs
deleted file mode 100644
index 2c75b9fc26b..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util_test.extjs
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Include test fixture.
-GEN_INCLUDE(['../../testing/chromevox_next_e2e_test_base.js']);
-
-/**
- * Test fixture for automation_util.js.
- * @constructor
- * @extends {ChromeVoxE2ETestBase}
- */
-function AutomationUtilE2ETest() {
- ChromeVoxNextE2ETest.call(this);
-}
-
-AutomationUtilE2ETest.prototype = {
- __proto__: ChromeVoxNextE2ETest.prototype,
-
- /** @override */
- setUp: function() {
- window.Dir = AutomationUtil.Dir;
- },
-
- basicDoc: function() {/*!
- <p><a href='#'></a>hello</p>
- <h1><ul><li>a</ul><button></h1>
- */}
-};
-
-TEST_F('AutomationUtilE2ETest', 'GetAncestors', function() {
- this.runWithLoadedTree(this.basicDoc, function(root) {
- var expectedLength = 1;
- while (root) {
- var ancestors = AutomationUtil.getAncestors(root);
- assertEquals(expectedLength++, ancestors.length);
- root = root.firstChild;
- }
- });
-});
-
-TEST_F('AutomationUtilE2ETest', 'GetUniqueAncestors', function() {
- this.runWithLoadedTree(this.basicDoc, function(root) {
- var leftmost = root, rightmost = root;
- while (leftmost.firstChild)
- leftmost = leftmost.firstChild;
- while (rightmost.lastChild)
- rightmost = rightmost.lastChild;
-
- var leftAncestors = AutomationUtil.getAncestors(leftmost);
- var rightAncestors = AutomationUtil.getAncestors(rightmost);
- assertEquals(chrome.automation.RoleType.link, leftmost.role);
- assertEquals(chrome.automation.RoleType.button, rightmost.role);
- assertEquals(
- 1, AutomationUtil.getDivergence(leftAncestors, rightAncestors));
- assertEquals(
- -1, AutomationUtil.getDivergence(leftAncestors, leftAncestors));
-
- var uniqueAncestorsLeft =
- AutomationUtil.getUniqueAncestors(rightmost, leftmost);
- var uniqueAncestorsRight =
- AutomationUtil.getUniqueAncestors(leftmost, rightmost);
-
- assertEquals(2, uniqueAncestorsLeft.length);
- assertEquals(chrome.automation.RoleType.paragraph,
- uniqueAncestorsLeft[0].role);
- assertEquals(chrome.automation.RoleType.link,
- uniqueAncestorsLeft[1].role);
-
- assertEquals(3, uniqueAncestorsRight.length);
- assertEquals(chrome.automation.RoleType.heading,
- uniqueAncestorsRight[0].role);
- assertEquals(chrome.automation.RoleType.group,
- uniqueAncestorsRight[1].role);
- assertEquals(chrome.automation.RoleType.button,
- uniqueAncestorsRight[2].role);
-
- assertEquals(
- 1, AutomationUtil.getUniqueAncestors(leftmost, leftmost).length);
-
- });
-});
-
-TEST_F('AutomationUtilE2ETest', 'GetDirection', function() {
- this.runWithLoadedTree(this.basicDoc, function(root) {
- var left = root, right = root;
-
- // Same node.
- assertEquals(Dir.FORWARD, AutomationUtil.getDirection(left, right));
-
- // Ancestor.
- left = left.firstChild;
- assertEquals(Dir.FORWARD, AutomationUtil.getDirection(left, right));
- assertEquals(Dir.FORWARD, AutomationUtil.getDirection(right, left));
-
- // Ordered.
- right = right.lastChild;
- assertEquals(Dir.BACKWARD, AutomationUtil.getDirection(right, left));
- assertEquals(Dir.FORWARD, AutomationUtil.getDirection(left, right));
-
- });
-});
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.html b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.html
deleted file mode 100644
index 84d67865599..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!-- Components to load uncompressed ChromeVox -->
-<script src="../../closure/base.js"></script>
-<script src="../../deps.js"></script>
-
-<!-- ChromeVox Next -->
-<script src="loader.js"></script>
-<script src="../../chromeVox2ChromeBackgroundScript.js"></script>
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
deleted file mode 100644
index aaf20bdd961..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
+++ /dev/null
@@ -1,810 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview The entry point for all ChromeVox2 related code for the
- * background page.
- */
-
-goog.provide('Background');
-goog.provide('global');
-
-goog.require('AutomationPredicate');
-goog.require('AutomationUtil');
-goog.require('ClassicCompatibility');
-goog.require('Output');
-goog.require('Output.EventType');
-goog.require('cursors.Cursor');
-goog.require('cvox.BrailleKeyCommand');
-goog.require('cvox.ChromeVoxEditableTextBase');
-goog.require('cvox.ExtensionBridge');
-goog.require('cvox.NavBraille');
-
-goog.scope(function() {
-var AutomationNode = chrome.automation.AutomationNode;
-var Dir = AutomationUtil.Dir;
-var EventType = chrome.automation.EventType;
-var RoleType = chrome.automation.RoleType;
-
-/**
- * All possible modes ChromeVox can run.
- * @enum {string}
- */
-var ChromeVoxMode = {
- CLASSIC: 'classic',
- COMPAT: 'compat',
- NEXT: 'next',
- FORCE_NEXT: 'force_next'
-};
-
-/**
- * ChromeVox2 background page.
- * @constructor
- */
-Background = function() {
- /**
- * A list of site substring patterns to use with ChromeVox next. Keep these
- * strings relatively specific.
- * @type {!Array<string>}
- * @private
- */
- this.whitelist_ = ['chromevox_next_test'];
-
- /**
- * @type {cursors.Range}
- * @private
- */
- this.currentRange_ = null;
-
- /**
- * Which variant of ChromeVox is active.
- * @type {ChromeVoxMode}
- * @private
- */
- this.mode_ = ChromeVoxMode.COMPAT;
-
- /** @type {!ClassicCompatibility} @private */
- this.compat_ = new ClassicCompatibility();
-
- // Manually bind all functions to |this|.
- for (var func in this) {
- if (typeof(this[func]) == 'function')
- this[func] = this[func].bind(this);
- }
-
- /**
- * Maps an automation event to its listener.
- * @type {!Object<EventType, function(Object) : void>}
- */
- this.listeners_ = {
- alert: this.onAlert,
- focus: this.onFocus,
- hover: this.onEventDefault,
- loadComplete: this.onLoadComplete,
- menuStart: this.onEventDefault,
- menuEnd: this.onEventDefault,
- textChanged: this.onTextOrTextSelectionChanged,
- textSelectionChanged: this.onTextOrTextSelectionChanged,
- valueChanged: this.onValueChanged
- };
-
- /**
- * The object that speaks changes to an editable text field.
- * @type {?cvox.ChromeVoxEditableTextBase}
- */
- this.editableTextHandler_ = null;
-
- chrome.automation.getDesktop(this.onGotDesktop);
-
- // Handle messages directed to the Next background page.
- cvox.ExtensionBridge.addMessageListener(function(msg, port) {
- var target = msg['target'];
- var action = msg['action'];
-
- switch (target) {
- case 'next':
- if (action == 'getIsClassicEnabled') {
- var url = msg['url'];
- var isClassicEnabled = this.shouldEnableClassicForUrl_(url);
- port.postMessage({
- target: 'next',
- isClassicEnabled: isClassicEnabled
- });
- }
- break;
- }
- }.bind(this));
-};
-
-Background.prototype = {
- /** Forces ChromeVox Next to be active for all tabs. */
- forceChromeVoxNextActive: function() {
- this.setChromeVoxMode(ChromeVoxMode.FORCE_NEXT);
- },
-
- /**
- * Handles all setup once a new automation tree appears.
- * @param {chrome.automation.AutomationNode} desktop
- */
- onGotDesktop: function(desktop) {
- // Register all automation event listeners.
- for (var eventType in this.listeners_)
- desktop.addEventListener(eventType, this.listeners_[eventType], true);
-
- // Register a tree change observer.
- chrome.automation.addTreeChangeObserver(this.onTreeChange);
-
- // The focused state gets set on the containing webView node.
- var webView = desktop.find({role: RoleType.webView,
- state: {focused: true}});
- if (webView) {
- var root = webView.find({role: RoleType.rootWebArea});
- if (root) {
- this.onLoadComplete(
- {target: root,
- type: chrome.automation.EventType.loadComplete});
- }
- }
- },
-
- /**
- * Handles chrome.commands.onCommand.
- * @param {string} command
- * @param {boolean=} opt_skipCompat Whether to skip compatibility checks.
- */
- onGotCommand: function(command, opt_skipCompat) {
- if (!this.currentRange_)
- return;
-
- if (!opt_skipCompat && this.mode_ === ChromeVoxMode.COMPAT) {
- if (this.compat_.onGotCommand(command))
- return;
- }
-
- var current = this.currentRange_;
- var dir = Dir.FORWARD;
- var pred = null;
- var predErrorMsg = undefined;
- switch (command) {
- case 'nextCharacter':
- current = current.move(cursors.Unit.CHARACTER, Dir.FORWARD);
- break;
- case 'previousCharacter':
- current = current.move(cursors.Unit.CHARACTER, Dir.BACKWARD);
- break;
- case 'nextWord':
- current = current.move(cursors.Unit.WORD, Dir.FORWARD);
- break;
- case 'previousWord':
- current = current.move(cursors.Unit.WORD, Dir.BACKWARD);
- break;
- case 'nextLine':
- current = current.move(cursors.Unit.LINE, Dir.FORWARD);
- break;
- case 'previousLine':
- current = current.move(cursors.Unit.LINE, Dir.BACKWARD);
- break;
- case 'nextButton':
- dir = Dir.FORWARD;
- pred = AutomationPredicate.button;
- predErrorMsg = 'no_next_button';
- break;
- case 'previousButton':
- dir = Dir.BACKWARD;
- pred = AutomationPredicate.button;
- predErrorMsg = 'no_previous_button';
- break;
- case 'nextCheckBox':
- dir = Dir.FORWARD;
- pred = AutomationPredicate.checkBox;
- predErrorMsg = 'no_next_checkbox';
- break;
- case 'previousCheckBox':
- dir = Dir.BACKWARD;
- pred = AutomationPredicate.checkBox;
- predErrorMsg = 'no_previous_checkbox';
- break;
- case 'nextComboBox':
- dir = Dir.FORWARD;
- pred = AutomationPredicate.comboBox;
- predErrorMsg = 'no_next_combo_box';
- break;
- case 'previousComboBox':
- dir = Dir.BACKWARD;
- pred = AutomationPredicate.comboBox;
- predErrorMsg = 'no_previous_combo_box';
- break;
- case 'nextEditText':
- dir = Dir.FORWARD;
- pred = AutomationPredicate.editText;
- predErrorMsg = 'no_next_edit_text';
- break;
- case 'previousEditText':
- dir = Dir.BACKWARD;
- pred = AutomationPredicate.editText;
- predErrorMsg = 'no_previous_edit_text';
- break;
- case 'nextFormField':
- dir = Dir.FORWARD;
- pred = AutomationPredicate.formField;
- predErrorMsg = 'no_next_form_field';
- break;
- case 'previousFormField':
- dir = Dir.BACKWARD;
- pred = AutomationPredicate.formField;
- predErrorMsg = 'no_previous_form_field';
- break;
- case 'nextHeading':
- dir = Dir.FORWARD;
- pred = AutomationPredicate.heading;
- predErrorMsg = 'no_next_heading';
- break;
- case 'previousHeading':
- dir = Dir.BACKWARD;
- pred = AutomationPredicate.heading;
- predErrorMsg = 'no_previous_heading';
- break;
- case 'nextLink':
- dir = Dir.FORWARD;
- pred = AutomationPredicate.link;
- predErrorMsg = 'no_next_link';
- break;
- case 'previousLink':
- dir = Dir.BACKWARD;
- pred = AutomationPredicate.link;
- predErrorMsg = 'no_previous_link';
- break;
- case 'nextTable':
- dir = Dir.FORWARD;
- pred = AutomationPredicate.table;
- predErrorMsg = 'no_next_table';
- break;
- case 'previousTable':
- dir = Dir.BACKWARD;
- pred = AutomationPredicate.table;
- predErrorMsg = 'no_previous_table';
- break;
- case 'nextVisitedLink':
- dir = Dir.FORWARD;
- pred = AutomationPredicate.visitedLink;
- predErrorMsg = 'no_next_visited_link';
- break;
- case 'previousVisitedLink':
- dir = Dir.BACKWARD;
- pred = AutomationPredicate.visitedLink;
- predErrorMsg = 'no_previous_visited_link';
- break;
- case 'nextElement':
- current = current.move(cursors.Unit.DOM_NODE, Dir.FORWARD);
- break;
- case 'previousElement':
- current = current.move(cursors.Unit.DOM_NODE, Dir.BACKWARD);
- break;
- case 'goToBeginning':
- var node =
- AutomationUtil.findNodePost(current.start.node.root,
- Dir.FORWARD,
- AutomationPredicate.leaf);
- if (node)
- current = cursors.Range.fromNode(node);
- break;
- case 'goToEnd':
- var node =
- AutomationUtil.findNodePost(current.start.node.root,
- Dir.BACKWARD,
- AutomationPredicate.leaf);
- if (node)
- current = cursors.Range.fromNode(node);
- break;
- case 'doDefault':
- if (this.currentRange_) {
- var actionNode = this.currentRange_.start.node;
- if (actionNode.role == RoleType.inlineTextBox)
- actionNode = actionNode.parent;
- actionNode.doDefault();
- }
- // Skip all other processing; if focus changes, we should get an event
- // for that.
- return;
- case 'continuousRead':
- global.isReadingContinuously = true;
- var continueReading = function(prevRange) {
- if (!global.isReadingContinuously || !this.currentRange_)
- return;
-
- new Output().withSpeechAndBraille(
- this.currentRange_, prevRange, Output.EventType.NAVIGATE)
- .onSpeechEnd(function() { continueReading(prevRange); })
- .go();
- prevRange = this.currentRange_;
- this.currentRange_ =
- this.currentRange_.move(cursors.Unit.NODE, Dir.FORWARD);
-
- if (!this.currentRange_ || this.currentRange_.equals(prevRange))
- global.isReadingContinuously = false;
- }.bind(this);
-
- continueReading(null);
- return;
- case 'showContextMenu':
- if (this.currentRange_) {
- var actionNode = this.currentRange_.start.node;
- if (actionNode.role == RoleType.inlineTextBox)
- actionNode = actionNode.parent;
- actionNode.showContextMenu();
- return;
- }
- break;
- case 'showOptionsPage':
- var optionsPage = {url: 'chromevox/background/options.html'};
- chrome.tabs.create(optionsPage);
- break;
- }
-
- if (pred) {
- var node = AutomationUtil.findNextNode(
- current.getBound(dir).node, dir, pred);
-
- if (node) {
- current = cursors.Range.fromNode(node);
- } else {
- if (predErrorMsg) {
- cvox.ChromeVox.tts.speak(Msgs.getMsg(predErrorMsg),
- cvox.QueueMode.FLUSH);
- }
- return;
- }
- }
-
- if (current) {
- // TODO(dtseng): Figure out what it means to focus a range.
- var actionNode = current.start.node;
- if (actionNode.role == RoleType.inlineTextBox)
- actionNode = actionNode.parent;
- actionNode.focus();
-
- var prevRange = this.currentRange_;
- this.currentRange_ = current;
-
- new Output().withSpeechAndBraille(
- this.currentRange_, prevRange, Output.EventType.NAVIGATE)
- .go();
- }
- },
-
- /**
- * Handles a braille command.
- * @param {!cvox.BrailleKeyEvent} evt
- * @param {!cvox.NavBraille} content
- * @return {boolean} True if evt was processed.
- */
- onBrailleKeyEvent: function(evt, content) {
- if (this.mode_ === ChromeVoxMode.CLASSIC)
- return false;
-
- switch (evt.command) {
- case cvox.BrailleKeyCommand.PAN_LEFT:
- this.onGotCommand('previousElement', true);
- break;
- case cvox.BrailleKeyCommand.PAN_RIGHT:
- this.onGotCommand('nextElement', true);
- break;
- case cvox.BrailleKeyCommand.LINE_UP:
- this.onGotCommand('previousLine', true);
- break;
- case cvox.BrailleKeyCommand.LINE_DOWN:
- this.onGotCommand('nextLine', true);
- break;
- case cvox.BrailleKeyCommand.TOP:
- this.onGotCommand('goToBeginning', true);
- break;
- case cvox.BrailleKeyCommand.BOTTOM:
- this.onGotCommand('goToEnd', true);
- break;
- case cvox.BrailleKeyCommand.ROUTING:
- this.brailleRoutingCommand_(
- content.text,
- // Cast ok since displayPosition is always defined in this case.
- /** @type {number} */ (evt.displayPosition));
- break;
- default:
- return false;
- }
- return true;
- },
-
- /**
- * Provides all feedback once ChromeVox's focus changes.
- * @param {Object} evt
- */
- onEventDefault: function(evt) {
- var node = evt.target;
-
- if (!node)
- return;
-
- var prevRange = this.currentRange_;
-
- this.currentRange_ = cursors.Range.fromNode(node);
-
- // Check to see if we've crossed roots. Continue if we've crossed roots or
- // are not within web content.
- if (node.root.role == 'desktop' ||
- !prevRange ||
- prevRange.start.node.root != node.root)
- this.setupChromeVoxVariants_(node.root.docUrl || '');
-
- // Don't process nodes inside of web content if ChromeVox Next is inactive.
- if (node.root.role != RoleType.desktop &&
- this.mode_ === ChromeVoxMode.CLASSIC) {
- chrome.accessibilityPrivate.setFocusRing([]);
- return;
- }
-
- // Don't output if focused node hasn't changed.
- if (prevRange &&
- evt.type == 'focus' &&
- this.currentRange_.equals(prevRange))
- return;
-
- new Output().withSpeechAndBraille(
- this.currentRange_, prevRange, evt.type)
- .go();
- },
-
- /**
- * Makes an announcement without changing focus.
- * @param {Object} evt
- */
- onAlert: function(evt) {
- var node = evt.target;
- if (!node)
- return;
-
- // Don't process nodes inside of web content if ChromeVox Next is inactive.
- if (node.root.role != RoleType.desktop &&
- this.mode_ === ChromeVoxMode.CLASSIC) {
- return;
- }
-
- var range = cursors.Range.fromNode(node);
-
- new Output().withSpeechAndBraille(range, null, evt.type).go();
- },
-
- /**
- * Provides all feedback once a focus event fires.
- * @param {Object} evt
- */
- onFocus: function(evt) {
- // Invalidate any previous editable text handler state.
- this.editableTextHandler_ = null;
-
- var node = evt.target;
-
-
- // Discard focus events on embeddedObject nodes.
- if (node.role == RoleType.embeddedObject)
- return;
-
- // It almost never makes sense to place focus directly on a rootWebArea.
- if (node.role == RoleType.rootWebArea) {
- // Discard focus events for root web areas when focus was previously
- // placed on a descendant.
- if (this.currentRange_.start.node.root == node)
- return;
-
- // Discard focused root nodes without focused state set.
- if (!node.state.focused)
- return;
-
- // Try to find a focusable descendant.
- node = node.find({state: {focused: true}}) || node;
- }
-
- if (evt.target.role == RoleType.textField)
- this.createEditableTextHandlerIfNeeded_(evt.target);
-
- this.onEventDefault({target: node, type: 'focus'});
- },
-
- /**
- * Provides all feedback once a load complete event fires.
- * @param {Object} evt
- */
- onLoadComplete: function(evt) {
- this.setupChromeVoxVariants_(evt.target.docUrl);
-
- // Don't process nodes inside of web content if ChromeVox Next is inactive.
- if (evt.target.root.role != RoleType.desktop &&
- this.mode_ === ChromeVoxMode.CLASSIC)
- return;
-
- // If initial focus was already placed on this page (e.g. if a user starts
- // tabbing before load complete), then don't move ChromeVox's position on
- // the page.
- if (this.currentRange_ &&
- this.currentRange_.start.node.role != RoleType.rootWebArea &&
- this.currentRange_.start.node.root.docUrl == evt.target.docUrl)
- return;
-
- var root = evt.target;
- var webView = root;
- while (webView && webView.role != RoleType.webView)
- webView = webView.parent;
-
- if (!webView || !webView.state.focused)
- return;
-
- var node = AutomationUtil.findNodePost(root,
- Dir.FORWARD,
- AutomationPredicate.leaf);
-
- if (node)
- this.currentRange_ = cursors.Range.fromNode(node);
-
- if (this.currentRange_)
- new Output().withSpeechAndBraille(
- this.currentRange_, null, evt.type)
- .go();
- },
-
- /**
- * Provides all feedback once a text selection change event fires.
- * @param {Object} evt
- */
- onTextOrTextSelectionChanged: function(evt) {
- // Don't process nodes inside of web content if ChromeVox Next is inactive.
- if (evt.target.root.role != RoleType.desktop &&
- this.mode_ === ChromeVoxMode.CLASSIC)
- return;
-
- if (!evt.target.state.focused)
- return;
-
- if (evt.target.role != RoleType.textField)
- return;
-
- if (!this.currentRange_) {
- this.onEventDefault(evt);
- this.currentRange_ = cursors.Range.fromNode(evt.target);
- }
-
- this.createEditableTextHandlerIfNeeded_(evt.target);
- var textChangeEvent = new cvox.TextChangeEvent(
- evt.target.value,
- evt.target.textSelStart,
- evt.target.textSelEnd,
- true); // triggered by user
-
- this.editableTextHandler_.changed(textChangeEvent);
-
- new Output().withBraille(
- this.currentRange_, null, evt.type)
- .go();
- },
-
- /**
- * Provides all feedback once a value changed event fires.
- * @param {Object} evt
- */
- onValueChanged: function(evt) {
- // Don't process nodes inside of web content if ChromeVox Next is inactive.
- if (evt.target.root.role != RoleType.desktop &&
- this.mode_ === ChromeVoxMode.CLASSIC)
- return;
-
- if (!evt.target.state.focused)
- return;
-
- // Value change events fire on web text fields and text areas when pressing
- // enter; suppress them.
- if (!this.currentRange_ ||
- evt.target.role != RoleType.textField) {
- this.onEventDefault(evt);
- this.currentRange_ = cursors.Range.fromNode(evt.target);
- }
- },
-
- /**
- * Called when the automation tree is changed.
- * @param {chrome.automation.TreeChange} treeChange
- */
- onTreeChange: function(treeChange) {
- if (this.mode_ === ChromeVoxMode.CLASSIC)
- return;
-
- var node = treeChange.target;
- if (!node.containerLiveStatus)
- return;
-
- if (node.containerLiveRelevant.indexOf('additions') >= 0 &&
- treeChange.type == 'nodeCreated')
- this.outputLiveRegionChange_(node, null);
- if (node.containerLiveRelevant.indexOf('text') >= 0 &&
- treeChange.type == 'nodeChanged')
- this.outputLiveRegionChange_(node, null);
- if (node.containerLiveRelevant.indexOf('removals') >= 0 &&
- treeChange.type == 'nodeRemoved')
- this.outputLiveRegionChange_(node, '@live_regions_removed');
- },
-
- /**
- * Given a node that needs to be spoken as part of a live region
- * change and an additional optional format string, output the
- * live region description.
- * @param {!chrome.automation.AutomationNode} node The changed node.
- * @param {?string} opt_prependFormatStr If set, a format string for
- * cvox2.Output to prepend to the output.
- * @private
- */
- outputLiveRegionChange_: function(node, opt_prependFormatStr) {
- var range = cursors.Range.fromNode(node);
- var output = new Output();
- if (opt_prependFormatStr) {
- output.format(opt_prependFormatStr);
- }
- output.withSpeech(range, null, Output.EventType.NAVIGATE);
- output.go();
- },
-
- /**
- * Returns true if the url should have Classic running.
- * @return {boolean}
- * @private
- */
- shouldEnableClassicForUrl_: function(url) {
- return this.mode_ != ChromeVoxMode.FORCE_NEXT &&
- !this.isWhitelistedForCompat_(url) &&
- !this.isWhitelistedForNext_(url);
- },
-
- /**
- * @return {boolean}
- * @private
- */
- isWhitelistedForCompat_: function(url) {
- return url.indexOf('chrome://md-settings') != -1 ||
- url.indexOf('chrome://downloads') != -1 ||
- url.indexOf('chrome://oobe/login') != -1 ||
- url.indexOf(
- 'https://accounts.google.com/embedded/setup/chromeos') === 0 ||
- url === '';
- },
-
- /**
- * @private
- * @param {string} url
- * @return {boolean} Whether the given |url| is whitelisted.
- */
- isWhitelistedForNext_: function(url) {
- return this.whitelist_.some(function(item) {
- return url.indexOf(item) != -1;
- }.bind(this));
- },
-
- /**
- * Setup ChromeVox variants.
- * @param {string} url
- * @private
- */
- setupChromeVoxVariants_: function(url) {
- var mode = this.mode_;
- if (mode != ChromeVoxMode.FORCE_NEXT) {
- if (this.isWhitelistedForCompat_(url))
- mode = ChromeVoxMode.COMPAT;
- else if (this.isWhitelistedForNext_(url))
- mode = ChromeVoxMode.NEXT;
- else
- mode = ChromeVoxMode.CLASSIC;
- }
-
- this.setChromeVoxMode(mode);
- },
-
- /**
- * Disables classic ChromeVox in current web content.
- */
- disableClassicChromeVox_: function() {
- cvox.ExtensionBridge.send({
- message: 'SYSTEM_COMMAND',
- command: 'killChromeVox'
- });
- },
-
- /**
- * Sets the current ChromeVox mode.
- * @param {ChromeVoxMode} mode
- */
- setChromeVoxMode: function(mode) {
- if (mode === ChromeVoxMode.NEXT ||
- mode === ChromeVoxMode.COMPAT ||
- mode === ChromeVoxMode.FORCE_NEXT) {
- if (chrome.commands &&
- !chrome.commands.onCommand.hasListener(this.onGotCommand))
- chrome.commands.onCommand.addListener(this.onGotCommand);
- } else {
- if (chrome.commands &&
- chrome.commands.onCommand.hasListener(this.onGotCommand))
- chrome.commands.onCommand.removeListener(this.onGotCommand);
- }
-
- chrome.tabs.query({active: true}, function(tabs) {
- if (mode === ChromeVoxMode.CLASSIC) {
- // This case should do nothing because Classic gets injected by the
- // extension system via our manifest. Once ChromeVox Next is enabled
- // for tabs, re-enable.
- // cvox.ChromeVox.injectChromeVoxIntoTabs(tabs);
- } else {
- // When in compat mode, if the focus is within the desktop tree proper,
- // then do not disable content scripts.
- if (this.currentRange_.start.node.root.role == 'desktop')
- return;
-
- this.disableClassicChromeVox_();
- }
- }.bind(this));
-
- this.mode_ = mode;
- },
-
- /**
- * @param {!cvox.Spannable} text
- * @param {number} position
- * @private
- */
- brailleRoutingCommand_: function(text, position) {
- var actionNode = null;
- var selectionSpan = null;
- text.getSpans(position).forEach(function(span) {
- if (span instanceof Output.SelectionSpan) {
- selectionSpan = span;
- } else if (span instanceof Output.NodeSpan) {
- if (!actionNode ||
- (text.getSpanEnd(actionNode) - text.getSpanStart(actionNode) >
- text.getSpanEnd(span) - text.getSpanStart(span))) {
- actionNode = span.node;
- }
- }
- });
- if (!actionNode)
- return;
- if (actionNode.role === RoleType.inlineTextBox)
- actionNode = actionNode.parent;
- actionNode.doDefault();
- if (selectionSpan) {
- var start = text.getSpanStart(selectionSpan);
- actionNode.setSelection(position - start, position - start);
- }
- },
-
- /**
- * Create an editable text handler for the given node if needed.
- * @param {Object} node
- */
- createEditableTextHandlerIfNeeded_: function(node) {
- if (!this.editableTextHandler_ || node != this.currentRange_.start.node) {
- var start = node.textSelStart;
- var end = node.textSelEnd;
- if (start > end) {
- var tempOffset = end;
- end = start;
- start = tempOffset;
- }
-
- this.editableTextHandler_ =
- new cvox.ChromeVoxEditableTextBase(
- node.value,
- start,
- end,
- node.state.protected,
- cvox.ChromeVox.tts);
- }
- }
-};
-
-/** @type {Background} */
-global.backgroundObj = new Background();
-
-}); // goog.scope
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
deleted file mode 100644
index 82810f95a0d..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
+++ /dev/null
@@ -1,370 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Include test fixture.
-GEN_INCLUDE(['../../testing/chromevox_next_e2e_test_base.js',
- '../../testing/assert_additions.js']);
-
-GEN_INCLUDE(['../../testing/mock_feedback.js']);
-
-/**
- * Test fixture for Background.
- * @constructor
- * @extends {ChromeVoxNextE2ETest}
- */
-function BackgroundTest() {
- ChromeVoxNextE2ETest.call(this);
-}
-
-BackgroundTest.prototype = {
- __proto__: ChromeVoxNextE2ETest.prototype,
-
- /** @override */
- setUp: function() {
- global.backgroundObj.forceChromeVoxNextActive();
- },
-
- /**
- * @return {!MockFeedback}
- */
- createMockFeedback: function() {
- var mockFeedback = new MockFeedback(this.newCallback(),
- this.newCallback.bind(this));
- mockFeedback.install();
- return mockFeedback;
- },
-
- /**
- * Create a function which perform the command |cmd|.
- * @param {string} cmd
- * @return {function() : void}
- */
- doCmd: function(cmd) {
- return function() {
- global.backgroundObj.onGotCommand(cmd);
- };
- },
-
- linksAndHeadingsDoc: function() {/*!
- <p>start</p>
- <a href='#a'>alpha</a>
- <a href='#b'>beta</a>
- <p>
- <h1>charlie</h1>
- <a href='foo'>delta</a>
- </p>
- <a href='#bar'>echo</a>
- <h2>foxtraut</h2>
- <p>end<span>of test</span></p>
- */},
-
- formsDoc: function() {/*!
- <select id="fruitSelect">
- <option>apple</option>
- <option>grape</option>
- <option> banana</option>
- </select>
- */}
-};
-
-/** Tests that ChromeVox classic is in this context. */
-SYNC_TEST_F('BackgroundTest', 'ClassicNamespaces', function() {
- assertEquals('object', typeof(cvox));
- assertEquals('function', typeof(cvox.ChromeVoxBackground));
-});
-
-/** Tests that ChromeVox next is in this context. */
-SYNC_TEST_F('BackgroundTest', 'NextNamespaces', function() {
- assertEquals('function', typeof(Background));
-});
-
-/** Tests consistency of navigating forward and backward. */
-TEST_F('BackgroundTest', 'ForwardBackwardNavigation', function() {
- var mockFeedback = this.createMockFeedback();
- this.runWithLoadedTree(this.linksAndHeadingsDoc, function() {
- var doCmd = this.doCmd.bind(this);
-
- mockFeedback.expectSpeech('start').expectBraille('start');
-
- mockFeedback.call(doCmd('nextLink'))
- .expectSpeech('alpha', 'Link')
- .expectBraille('alpha lnk');
- mockFeedback.call(doCmd('nextLink'))
- .expectSpeech('beta', 'Link')
- .expectBraille('beta lnk');
- mockFeedback.call(doCmd('nextLink'))
- .expectSpeech('delta', 'Link')
- .expectBraille('delta lnk');
- mockFeedback.call(doCmd('previousLink'))
- .expectSpeech('beta', 'Link')
- .expectBraille('beta lnk');
- mockFeedback.call(doCmd('nextHeading'))
- .expectSpeech('Heading 1', 'charlie')
- .expectBraille('h1 charlie');
- mockFeedback.call(doCmd('nextHeading'))
- .expectSpeech('Heading 2', 'foxtraut')
- .expectBraille('h2 foxtraut');
- mockFeedback.call(doCmd('previousHeading'))
- .expectSpeech('Heading 1', 'charlie')
- .expectBraille('h1 charlie');
-
- mockFeedback.call(doCmd('nextElement'))
- .expectSpeech('delta', 'Link')
- .expectBraille('delta lnk');
- mockFeedback.call(doCmd('nextElement'))
- .expectSpeech('echo', 'Link')
- .expectBraille('echo lnk');
- mockFeedback.call(doCmd('nextElement'))
- .expectSpeech('Heading 2', 'foxtraut')
- .expectBraille('h2 foxtraut');
- mockFeedback.call(doCmd('nextElement'))
- .expectSpeech('end')
- .expectBraille('end');
- mockFeedback.call(doCmd('previousElement'))
- .expectSpeech('Heading 2', 'foxtraut')
- .expectBraille('h2 foxtraut');
- mockFeedback.call(doCmd('nextLine'))
- .expectSpeech('end', 'of test')
- .expectBraille('end of test');
-
- mockFeedback.call(doCmd('goToBeginning'))
- .expectSpeech('start')
- .expectBraille('start');
- mockFeedback.call(doCmd('goToEnd'))
- .expectSpeech('of test')
- .expectBraille('of test');
-
- mockFeedback.replay();
- });
-});
-
-TEST_F('BackgroundTest', 'CaretNavigation', function() {
- // TODO(plundblad): Add braille expectaions when crbug.com/523285 is fixed.
- var mockFeedback = this.createMockFeedback();
- this.runWithLoadedTree(this.linksAndHeadingsDoc, function() {
- var doCmd = this.doCmd.bind(this);
-
- mockFeedback.expectSpeech('start');
- mockFeedback.call(doCmd('nextCharacter'))
- .expectSpeech('t');
- mockFeedback.call(doCmd('nextCharacter'))
- .expectSpeech('a');
- mockFeedback.call(doCmd('nextWord'))
- .expectSpeech('Link', 'alpha');
- mockFeedback.call(doCmd('nextWord'))
- .expectSpeech('Link', 'beta');
- mockFeedback.call(doCmd('nextWord'))
- .expectSpeech('Heading 1', 'charlie');
- mockFeedback.call(doCmd('nextLine'))
- .expectSpeech('Link', 'delta');
- mockFeedback.call(doCmd('nextLine'))
- .expectSpeech('Link', 'echo');
- mockFeedback.call(doCmd('nextLine'))
- .expectSpeech('Heading 2', 'foxtraut');
- mockFeedback.call(doCmd('nextLine'))
- .expectSpeech('end', 'of test');
- mockFeedback.call(doCmd('nextCharacter'))
- .expectSpeech('n');
- mockFeedback.call(doCmd('previousCharacter'))
- .expectSpeech('e');
- mockFeedback.call(doCmd('previousCharacter'))
- .expectSpeech('Heading 2', 't');
- mockFeedback.call(doCmd('previousWord'))
- .expectSpeech('foxtraut');
- mockFeedback.call(doCmd('previousWord'))
- .expectSpeech('Link', 'echo');
- mockFeedback.call(doCmd('previousCharacter'))
- .expectSpeech('Link', 'a');
- mockFeedback.call(doCmd('previousCharacter'))
- .expectSpeech('t');
- mockFeedback.call(doCmd('nextWord'))
- .expectSpeech('Link', 'echo');
- mockFeedback.replay();
- });
-});
-
-TEST_F('BackgroundTest', 'SelectSingleBasic', function() {
- var mockFeedback = this.createMockFeedback();
- this.runWithLoadedTree(this.formsDoc, function() {
- var sendDownToSelect =
- this.sendKeyToElement.bind(this, undefined, 'Down', '#fruitSelect');
- mockFeedback.expectSpeech('apple', 'Menu item', /1 of 3/)
- .expectBraille('apple mnuitm 1/3')
- .call(sendDownToSelect)
- .expectSpeech('grape', /2 of 3/)
- .expectBraille('grape mnuitm 2/3')
- .call(sendDownToSelect)
- .expectSpeech('banana', /3 of 3/)
- .expectBraille('banana mnuitm 3/3');
- mockFeedback.replay();
- });
-});
-
-TEST_F('BackgroundTest', 'ContinuousRead', function() {
- var mockFeedback = this.createMockFeedback();
- this.runWithLoadedTree(this.linksAndHeadingsDoc, function() {
- mockFeedback.expectSpeech('start')
- .call(this.doCmd('continuousRead'))
- .expectSpeech(
- 'start',
- 'alpha', 'Link',
- 'beta', 'Link',
- 'Heading 1', 'charlie');
- mockFeedback.replay();
- });
-});
-
-TEST_F('BackgroundTest', 'LiveRegionAddElement', function() {
- var mockFeedback = this.createMockFeedback();
- this.runWithLoadedTree(
- function() {/*!
- <h1>Document with live region</h1>
- <p id="live" aria-live="polite"></p>
- <button id="go">Go</button>
- <script>
- document.getElementById('go').addEventListener('click', function() {
- document.getElementById('live').innerHTML = 'Hello, world';
- }, false);
- </script>
- */},
- function(rootNode) {
- var go = rootNode.find({ role: chrome.automation.RoleType.button });
- mockFeedback.call(go.doDefault.bind(go))
- .expectSpeech('Hello, world');
- mockFeedback.replay();
- });
-});
-
-TEST_F('BackgroundTest', 'LiveRegionRemoveElement', function() {
- var mockFeedback = this.createMockFeedback();
- this.runWithLoadedTree(
- function() {/*!
- <h1>Document with live region</h1>
- <p id="live" aria-live="polite" aria-relevant="removals">Hello, world</p>
- <button id="go">Go</button>
- <script>
- document.getElementById('go').addEventListener('click', function() {
- document.getElementById('live').innerHTML = '';
- }, false);
- </script>
- */},
- function(rootNode) {
- var go = rootNode.find({ role: chrome.automation.RoleType.button });
- go.doDefault();
- mockFeedback.expectSpeech('removed:')
- .expectSpeech('Hello, world');
- mockFeedback.replay();
- });
-});
-
-TEST_F('BackgroundTest', 'InitialFocus', function() {
- var mockFeedback = this.createMockFeedback();
- this.runWithLoadedTree('<a href="a">a</a>',
- function(rootNode) {
- mockFeedback.expectSpeech('a')
- .expectSpeech('Link');
- mockFeedback.replay();
- });
-});
-
-TEST_F('BackgroundTest', 'AriaLabel', function() {
- var mockFeedback = this.createMockFeedback();
- this.runWithLoadedTree('<a aria-label="foo" href="a">a</a>',
- function(rootNode) {
- rootNode.find({role: 'link'}).focus();
- mockFeedback.expectSpeech('foo')
- .expectSpeech('Link')
- .expectBraille('foo lnk');
- mockFeedback.replay();
- }
- );
-});
-
-TEST_F('BackgroundTest', 'ShowContextMenu', function() {
- var mockFeedback = this.createMockFeedback();
- this.runWithLoadedTree('<a href="a">a</a>',
- function(rootNode) {
- mockFeedback.expectSpeech(/menu opened/)
- .call(function() {
- // When shown, the context menu pushes a new message loop so test
- // messages sent to the browser do not get processed. Ensure we
- // exit the context menu here.
- go.showContextMenu();
- });
- mockFeedback.replay();
-
- var go = rootNode.find({ role: chrome.automation.RoleType.link });
- this.listenOnce(go, 'focus', function(e) {
- this.doCmd('showContextMenu')();
- }.bind(this), true);
- go.focus();
- }.bind(this));
-});
-
-TEST_F('BackgroundTest', 'BrailleRouting', function() {
- var mockFeedback = this.createMockFeedback();
- var route = function(position) {
- assertTrue(global.backgroundObj.onBrailleKeyEvent(
- {command: cvox.BrailleKeyCommand.ROUTING,
- displayPosition: position},
- mockFeedback.lastMatchedBraille));
- };
- this.runWithLoadedTree(
- function() {/*!
- <p>start</p>
- <button id="btn1">Click me</button>
- <p>Some text</p>
- <button id="btn2">Focus me</button>
- <p>Some more text</p>
- <input type="text" id ="text" value="Edit me">
- <script>
- document.getElementById('btn1').addEventListener('click', function() {
- document.getElementById('btn2').focus();
- }, false);
- </script>
- */},
- function(rootNode) {
- var button1 = rootNode.find({role: chrome.automation.RoleType.button,
- name: 'Click me'});
- var textField = rootNode.find(
- {role: chrome.automation.RoleType.textField});
- mockFeedback.expectBraille('start')
- .call(button1.focus.bind(button1))
- .expectBraille(/^Click me btn/)
- .call(route.bind(null, 5))
- .expectBraille(/Focus me btn/)
- .call(textField.focus.bind(textField))
- .expectBraille('Edit me ed', {startIndex: 0})
- .call(route.bind(null, 3))
- .expectBraille('Edit me ed', {startIndex: 3})
- .call(function() {
- assertEquals(3, textField.textSelStart);
- });
- mockFeedback.replay();
- });
-});
-
-TEST_F('BackgroundTest', 'FocusInputElement', function() {
- var mockFeedback = this.createMockFeedback();
- this.runWithLoadedTree(
- function() {/*!
- <input id="name" value="Lancelot">
- <input id="quest" value="Grail">
- <input id="color" value="Blue">
- */},
- function(rootNode) {
- var name = rootNode.find({ attributes: { value: 'Lancelot' } });
- var quest = rootNode.find({ attributes: { value: 'Grail' } });
- var color = rootNode.find({ attributes: { value: 'Blue' } });
-
- mockFeedback.call(quest.focus.bind(quest))
- .expectSpeech('Grail', 'Edit text')
- .call(color.focus.bind(color))
- .expectSpeech('Blue', 'Edit text')
- .call(name.focus.bind(name))
- .expectNextSpeechUtteranceIsNot('Blue')
- .expectSpeech('Lancelot', 'Edit text');
- mockFeedback.replay();
- }.bind(this));
-});
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/classic_compatibility.js b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/classic_compatibility.js
deleted file mode 100644
index 35eb9ca3bad..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/classic_compatibility.js
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Provides a compatibility layer for ChromeVox Classic during the
- * transition to ChromeVox Next.
- */
-
-goog.provide('ClassicCompatibility');
-
-goog.require('cvox.ExtensionBridge');
-goog.require('cvox.KeyMap');
-goog.require('cvox.KeySequence');
-goog.require('cvox.KeyUtil');
-goog.require('cvox.SimpleKeyEvent');
-
-/**
- * @constructor
- */
-var ClassicCompatibility = function() {
- /**
- * @type {!Array<{description: string, name: string, shortcut: string}>}
- * @private
- */
- this.commands_ = [];
-
- // We grab the list of commands from the manifest because
- // chrome.commands.getAll is buggy.
- /** @type {!Object} */
- var commands = chrome.runtime.getManifest()['commands'];
- for (var key in commands) {
- /** @type {{suggested_key: {chromeos: string}}} */
- var command = commands[key];
- this.commands_.push({name: key, shortcut: command.suggested_key.chromeos});
- }
-};
-
-ClassicCompatibility.prototype = {
- /**
- * Processes a ChromeVox Next command.
- * @param {string} command
- * @return {boolean} Whether the command was successfully processed.
- */
- onGotCommand: function(command) {
- var evt = this.buildKeyEvent_(command);
- if (evt) {
- this.simulateKeyDownNext_(evt);
- return true;
- }
- cvox.KeyUtil.sequencing = false;
- },
-
- /**
- * Processes a ChromeVox Next command while in CLASSIC mode.
- * @param {string} command
- * @return {boolean} Whether the command was successfully processed.
- */
- onGotClassicCommand: function(command) {
- var evt = this.buildKeyEvent_(command);
- if (!evt)
- return false;
- this.simulateKeyDownClassic_(evt);
- return true;
- },
-
- /**
- * @param {string} command
- * @return {cvox.SimpleKeyEvent?}
- */
- buildKeyEvent_: function(command) {
- var commandInfo = this.commands_.filter(function(c) {
- return c.name == command;
- }.bind(this))[0];
- if (!commandInfo)
- return null;
- var shortcut = commandInfo.shortcut;
- return this.convertCommandShortcutToKeyEvent_(shortcut);
- },
-
- /**
- * @param {cvox.SimpleKeyEvent} evt
- * @private
- */
- simulateKeyDownNext_: function(evt) {
- var keySequence = cvox.KeyUtil.keyEventToKeySequence(evt);
- var classicCommand =
- cvox.KeyMap.fromCurrentKeyMap().commandForKey(keySequence);
- if (classicCommand) {
- var nextCommand = this.getNextCommand_(classicCommand);
- if (nextCommand)
- global.backgroundObj.onGotCommand(nextCommand, true);
- }
- },
-
- /**
- * @param {cvox.SimpleKeyEvent} evt
- * @private
- */
- simulateKeyDownClassic_: function(evt) {
- var keySequence = cvox.KeyUtil.keyEventToKeySequence(evt);
- var classicCommand =
- cvox.KeyMap.fromCurrentKeyMap().commandForKey(keySequence);
- if (classicCommand) {
- cvox.ExtensionBridge.send({
- 'message': 'USER_COMMAND',
- 'command': classicCommand
- });
- }
- },
-
- /**
- * @param {string} shortcut
- * @return {cvox.SimpleKeyEvent}
- * @private
- */
- convertCommandShortcutToKeyEvent_: function(shortcut) {
- var evt = {};
- shortcut.split('+').forEach(function(token) {
- // Known tokens.
- switch (token) {
- case 'Ctrl':
- evt.ctrlKey = true;
- break;
- case 'Shift':
- evt.shiftKey = true;
- break;
- case 'Alt':
- evt.altKey = true;
- break;
- case 'Search':
- evt.searchKeyHeld = true;
- break;
- case 'Space':
- evt.keyCode = 32;
- break;
- case 'Left':
- evt.keyCode = 37;
- break;
- case 'Up':
- evt.keyCode = 38;
- break;
- case 'Right':
- evt.keyCode = 39;
- break;
- case 'Down':
- evt.keyCode = 40;
- break;
- default:
- evt.keyCode = token.charCodeAt(0);
- }
- });
-
- return evt;
- },
-
- /**
- * Maps a Classic command to an approximate equivalent in Next.
- * @param {string} classicCommand
- * @return {string}
- * @private
- */
- getNextCommand_: function(classicCommand) {
- switch (classicCommand) {
- case 'right':
- return 'nextElement';
- case 'forward':
- return 'nextLine';
- case 'left':
- return 'previousElement';
- case 'backward':
- return 'previousLine';
- case 'forceClickOnCurrentItem':
- return 'doDefault';
- case 'readFromHere':
- return 'continuousRead';
- default:
- return classicCommand;
- }
- }
-};
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
deleted file mode 100644
index d92d55adcce..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
+++ /dev/null
@@ -1,397 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Classes related to cursors that point to and select parts of
- * the automation tree.
- */
-
-goog.provide('cursors.Cursor');
-goog.provide('cursors.Movement');
-goog.provide('cursors.Range');
-goog.provide('cursors.Unit');
-
-goog.require('AutomationUtil');
-
-/**
- * The special index that represents a cursor pointing to a node without
- * pointing to any part of its accessible text.
- */
-cursors.NODE_INDEX = -1;
-
-/**
- * Represents units of CursorMovement.
- * @enum {string}
- */
-cursors.Unit = {
- /** A single character within accessible name or value. */
- CHARACTER: 'character',
-
- /** A range of characters (given by attributes on automation nodes). */
- WORD: 'word',
-
- /** A leaf node. */
- NODE: 'node',
-
- /** A leaf DOM-node. */
- DOM_NODE: 'dom_node',
-
- /** Formed by a set of leaf nodes that are inline. */
- LINE: 'line'
-};
-
-/**
- * Represents the ways in which cursors can move given a cursor unit.
- * @enum {string}
- */
-cursors.Movement = {
- /** Move to the beginning or end of the current unit. */
- BOUND: 'bound',
-
- /** Move to the next unit in a particular direction. */
- DIRECTIONAL: 'directional'
-};
-
-goog.scope(function() {
-var AutomationNode = chrome.automation.AutomationNode;
-var Dir = AutomationUtil.Dir;
-var Movement = cursors.Movement;
-var Role = chrome.automation.RoleType;
-var Unit = cursors.Unit;
-
-/**
- * Represents a position within the automation tree.
- * @constructor
- * @param {!AutomationNode} node
- * @param {number} index A 0-based index into either this cursor's name or value
- * attribute. Relies on the fact that a node has either a name or a value but
- * not both. An index of |cursors.NODE_INDEX| means the node as a whole is
- * pointed to and covers the case where the accessible text is empty.
- */
-cursors.Cursor = function(node, index) {
- /** @type {!AutomationNode} @private */
- this.node_ = node;
- /** @type {number} @private */
- this.index_ = index;
-};
-
-/**
- * Convenience method to construct a Cursor from a node.
- * @param {!AutomationNode} node
- * @return {!cursors.Cursor}
- */
-cursors.Cursor.fromNode = function(node) {
- return new cursors.Cursor(node, cursors.NODE_INDEX);
-};
-
-cursors.Cursor.prototype = {
- /**
- * Returns true if |rhs| is equal to this cursor.
- * @param {!cursors.Cursor} rhs
- * @return {boolean}
- */
- equals: function(rhs) {
- return this.node_ === rhs.node &&
- this.index_ === rhs.getIndex();
- },
-
- /**
- * @return {!AutomationNode}
- */
- get node() {
- return this.node_;
- },
-
- /**
- * @return {number}
- */
- getIndex: function() {
- return this.index_;
- },
-
- /**
- * Gets the accessible text of the node associated with this cursor.
- *
- * Note that only one of |name| or |value| attribute is ever nonempty on an
- * automation node. If either contains whitespace, we still treat it as we do
- * for a nonempty string.
- * @param {!AutomationNode=} opt_node Use this node rather than this cursor's
- * node.
- * @return {string}
- */
- getText: function(opt_node) {
- var node = opt_node || this.node_;
- return node.name || node.value || '';
- },
-
- /**
- * Makes a Cursor which has been moved from this cursor by the unit in the
- * given direction using the given movement type.
- * @param {Unit} unit
- * @param {Movement} movement
- * @param {Dir} dir
- * @return {!cursors.Cursor} The moved cursor.
- */
- move: function(unit, movement, dir) {
- var newNode = this.node_;
- var newIndex = this.index_;
-
- if ((unit != Unit.NODE || unit != Unit.DOM_NODE) &&
- newIndex === cursors.NODE_INDEX)
- newIndex = 0;
-
- switch (unit) {
- case Unit.CHARACTER:
- // BOUND and DIRECTIONAL are the same for characters.
- newIndex = dir == Dir.FORWARD ? newIndex + 1 : newIndex - 1;
- if (newIndex < 0 || newIndex >= this.getText().length) {
- newNode = AutomationUtil.findNextNode(
- newNode, dir, AutomationPredicate.leafWithText);
- if (newNode) {
- newIndex =
- dir == Dir.FORWARD ? 0 : this.getText(newNode).length - 1;
- newIndex = newIndex == -1 ? 0 : newIndex;
- } else {
- newIndex = this.index_;
- }
- }
- break;
- case Unit.WORD:
- switch (movement) {
- case Movement.BOUND:
- if (newNode.role == Role.inlineTextBox) {
- var start, end;
- for (var i = 0; i < newNode.wordStarts.length; i++) {
- if (newIndex >= newNode.wordStarts[i] &&
- newIndex <= newNode.wordEnds[i]) {
- start = newNode.wordStarts[i];
- end = newNode.wordEnds[i];
- break;
- }
- }
- if (goog.isDef(start) && goog.isDef(end))
- newIndex = dir == Dir.FORWARD ? end : start;
- } else {
- // TODO(dtseng): Figure out what to do in this case.
- }
- break;
- case Movement.DIRECTIONAL:
- if (newNode.role == Role.inlineTextBox) {
- var start, end;
- for (var i = 0; i < newNode.wordStarts.length; i++) {
- if (newIndex >= newNode.wordStarts[i] &&
- newIndex <= newNode.wordEnds[i]) {
- var nextIndex = dir == Dir.FORWARD ? i + 1 : i - 1;
- start = newNode.wordStarts[nextIndex];
- end = newNode.wordEnds[nextIndex];
- break;
- }
- }
- if (goog.isDef(start)) {
- newIndex = start;
- } else {
- // The backward case is special at the beginning of nodes.
- if (dir == Dir.BACKWARD && newIndex != 0) {
- newIndex = 0;
- } else {
- newNode = AutomationUtil.findNextNode(newNode, dir,
- AutomationPredicate.leaf);
- if (newNode) {
- newIndex = 0;
- if (dir == Dir.BACKWARD &&
- newNode.role == Role.inlineTextBox) {
- var starts = newNode.wordStarts;
- newIndex = starts[starts.length - 1] || 0;
- } else {
- // TODO(dtseng): Figure out what to do for general nodes.
- }
- }
- }
- }
- } else {
- // TODO(dtseng): Figure out what to do in this case.
- }
- }
- break;
- case Unit.NODE:
- case Unit.DOM_NODE:
- switch (movement) {
- case Movement.BOUND:
- newIndex = dir == Dir.FORWARD ? this.getText().length - 1 : 0;
- break;
- case Movement.DIRECTIONAL:
- var pred = unit == Unit.NODE ?
- AutomationPredicate.leaf : AutomationPredicate.leafDomNode;
- newNode = AutomationUtil.findNextNode(
- newNode, dir, pred) || this.node_;
- newIndex = cursors.NODE_INDEX;
- break;
- }
- break;
- case Unit.LINE:
- newIndex = 0;
- switch (movement) {
- case Movement.BOUND:
- newNode = AutomationUtil.findNodeUntil(newNode, dir,
- AutomationPredicate.linebreak, {before: true});
- newNode = newNode || this.node_;
- newIndex =
- dir == Dir.FORWARD ? this.getText(newNode).length : 0;
- break;
- case Movement.DIRECTIONAL:
- newNode = AutomationUtil.findNodeUntil(
- newNode, dir, AutomationPredicate.linebreak);
- break;
- }
- break;
- default:
- throw 'Unrecognized unit: ' + unit;
- }
- newNode = newNode || this.node_;
- newIndex = goog.isDef(newIndex) ? newIndex : this.index_;
- return new cursors.Cursor(newNode, newIndex);
- }
-};
-
-/**
- * Represents a range in the automation tree. There is no visible selection on
- * the page caused by usage of this object.
- * It is assumed that the caller provides |start| and |end| in document order.
- * @param {!cursors.Cursor} start
- * @param {!cursors.Cursor} end
- * @constructor
- */
-cursors.Range = function(start, end) {
- /** @type {!cursors.Cursor} @private */
- this.start_ = start;
- /** @type {!cursors.Cursor} @private */
- this.end_ = end;
-};
-
-/**
- * Convenience method to construct a Range surrounding one node.
- * @param {!AutomationNode} node
- * @return {!cursors.Range}
- */
-cursors.Range.fromNode = function(node) {
- var cursor = cursors.Cursor.fromNode(node);
- return new cursors.Range(cursor, cursor);
-};
-
- /**
- * Given |rangeA| and |rangeB| in order, determine which |Dir|
- * relates them.
- * @param {!cursors.Range} rangeA
- * @param {!cursors.Range} rangeB
- * @return {Dir}
- */
-cursors.Range.getDirection = function(rangeA, rangeB) {
- if (!rangeA || !rangeB)
- return Dir.FORWARD;
-
- // They are the same range.
- if (rangeA.start.node === rangeB.start.node &&
- rangeB.end.node === rangeA.end.node)
- return Dir.FORWARD;
-
- var testDirA =
- AutomationUtil.getDirection(
- rangeA.start.node, rangeB.end.node);
- var testDirB =
- AutomationUtil.getDirection(
- rangeB.start.node, rangeA.end.node);
-
- // The two ranges are either partly overlapping or non overlapping.
- if (testDirA == Dir.FORWARD && testDirB == Dir.BACKWARD)
- return Dir.FORWARD;
- else if (testDirA == Dir.BACKWARD && testDirB == Dir.FORWARD)
- return Dir.BACKWARD;
- else
- return testDirA;
-};
-
-cursors.Range.prototype = {
- /**
- * Returns true if |rhs| is equal to this range.
- * @param {!cursors.Range} rhs
- * @return {boolean}
- */
- equals: function(rhs) {
- return this.start_.equals(rhs.start) &&
- this.end_.equals(rhs.end);
- },
-
- /**
- * Gets a cursor bounding this range.
- * @param {Dir} dir Which endpoint cursor to return; Dir.FORWARD for end,
- * Dir.BACKWARD for start.
- * @param {boolean=} opt_reverse Specify to have Dir.BACKWARD return end,
- * Dir.FORWARD return start.
- * @return {!cursors.Cursor}
- */
- getBound: function(dir, opt_reverse) {
- if (opt_reverse)
- return dir == Dir.BACKWARD ? this.end_ : this.start_;
- return dir == Dir.FORWARD ? this.end_ : this.start_;
- },
-
- /**
- * @return {!cursors.Cursor}
- */
- get start() {
- return this.start_;
- },
-
- /**
- * @return {!cursors.Cursor}
- */
- get end() {
- return this.end_;
- },
-
- /**
- * Returns true if this range covers less than a node.
- * @return {boolean}
- */
- isSubNode: function() {
- return this.start.node === this.end.node &&
- this.start.getIndex() > -1 &&
- this.end.getIndex() > -1;
- },
-
- /**
- * Makes a Range which has been moved from this range by the given unit and
- * direction.
- * @param {Unit} unit
- * @param {Dir} dir
- * @return {cursors.Range}
- */
- move: function(unit, dir) {
- var newStart = this.start_;
- var newEnd = newStart;
- switch (unit) {
- case Unit.CHARACTER:
- newStart = newStart.move(unit, Movement.BOUND, dir);
- newEnd = newStart.move(unit, Movement.BOUND, Dir.FORWARD);
- // Character crossed a node; collapses to the end of the node.
- if (newStart.node !== newEnd.node)
- newEnd = newStart;
- break;
- case Unit.WORD:
- case Unit.LINE:
- newStart = newStart.move(unit, Movement.DIRECTIONAL, dir);
- newStart = newStart.move(unit, Movement.BOUND, Dir.BACKWARD);
- newEnd = newStart.move(unit, Movement.BOUND, Dir.FORWARD);
- break;
- case Unit.NODE:
- case Unit.DOM_NODE:
- newStart = newStart.move(unit, Movement.DIRECTIONAL, dir);
- newEnd = newStart;
- break;
- }
- return new cursors.Range(newStart, newEnd);
- }
-};
-
-}); // goog.scope
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
deleted file mode 100644
index 346001d4d1b..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
+++ /dev/null
@@ -1,294 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Include test fixture.
-GEN_INCLUDE(['../../testing/chromevox_next_e2e_test_base.js']);
-
-/**
- * Test fixture for cvox2.cursors.
- * @constructor
- * @extends {ChromeVoxNextE2ETest}
- */
-function CursorsTest() {
- ChromeVoxNextE2ETest.call(this);
-}
-
-CursorsTest.prototype = {
- __proto__: ChromeVoxNextE2ETest.prototype,
-
- /** Test cursors.Cursor. @const {string} */
- CURSOR: 'cursor',
-
- /** Test cursors.Range. @const {string} */
- RANGE: 'range',
-
- /** @override */
- setUp: function() {
- // Various aliases.
- window.BACKWARD = AutomationUtil.Dir.BACKWARD;
- window.FORWARD = AutomationUtil.Dir.FORWARD;
- window.CHARACTER = cursors.Unit.CHARACTER;
- window.WORD = cursors.Unit.WORD;
- window.LINE = cursors.Unit.LINE;
- window.DOM_NODE = cursors.Unit.DOM_NODE;
- window.BOUND = cursors.Movement.BOUND;
- window.DIRECTIONAL = cursors.Movement.DIRECTIONAL;
- },
-
- /**
- * Performs a series of operations on a cursor and asserts the result.
- * @param {cursors.Cursor} cursor The starting cursor.
- * @param {!Array<Array<
- * cursors.Unit|
- * cursors.Movement|
- * automationUtil.Dir|
- * Object>>}
- * moves An array of arrays. Each inner array contains 4 items: unit,
- * movement, direction, and assertions object. See example below.
- */
- cursorMoveAndAssert: function(cursor, moves) {
- var move = null;
- while (move = moves.shift()) {
- cursor = cursor.move(move[0], move[1], move[2]);
- var expected = move[3];
- this.makeCursorAssertion(expected, cursor);
- }
- },
-
- /**
- * Performs a series of operations on a range and asserts the result.
- * @param {cursors.Range} range The starting range.
- * @param {!Array<Array<
- * cursors.Unit|
- * cursors.Movement|
- * automationUtil.Dir|
- * Object>>}
- * moves An array of arrays. Each inner array contains 4 items: unit,
- * direction, start and end assertions objects. See example below.
- */
- rangeMoveAndAssert: function(range, moves) {
- var move = null;
- while (move = moves.shift()) {
- range = range.move(move[0], move[1]);
- var expectedStart = move[2];
- var expectedEnd = move[3];
-
- this.makeCursorAssertion(expectedStart, range.start);
- this.makeCursorAssertion(expectedEnd, range.end);
- }
- },
-
- /**
- * Makes assertions about the given |cursor|.
- * @param {Object} expected
- * @param {Cursor} cursor
- */
- makeCursorAssertion: function(expected, cursor) {
- if (goog.isDef(expected.index))
- assertEquals(expected.index, cursor.getIndex());
- if (goog.isDef(expected.value))
- assertEquals(expected.value, cursor.node.value);
- },
-
- /**
- * Runs the specified moves on the |doc| and asserts expectations.
- * @param {function} doc
- * @param {string=} opt_testType Either CURSOR or RANGE.
- */
- runCursorMovesOnDocument: function(doc, moves, opt_testType) {
- this.runWithLoadedTree(doc,
- function(root) {
- var start = null;
-
- // This occurs as a result of a load complete.
- var start = AutomationUtil.findNodePost(root,
- FORWARD,
- AutomationPredicate.leaf);
-
- var cursor = new cursors.Cursor(start, 0);
- if (!opt_testType || opt_testType == this.CURSOR) {
- var cursor = new cursors.Cursor(start, 0);
- this.cursorMoveAndAssert(cursor, moves);
- } else if (opt_testType == this.RANGE) {
- var range = new cursors.Range(cursor, cursor);
- this.rangeMoveAndAssert(range, moves);
- }
- });
- },
-
-simpleDoc: function() {/*!
- <p>start <span>same line</span>
- <p>end
- */},
-
- multiInlineDoc: function() {/*!
- <p style='max-width: 5px'>start diff line</p>
- <p>end
- */}
-};
-
-TEST_F('CursorsTest', 'CharacterCursor', function() {
- this.runCursorMovesOnDocument(this.simpleDoc, [
- [CHARACTER, DIRECTIONAL, FORWARD, {index: 1, value: 'start '}],
- [CHARACTER, DIRECTIONAL, BACKWARD, {index: 0, value: 'start '}],
- [CHARACTER, DIRECTIONAL, BACKWARD, {index: 0, value: 'start '}],
-
- [CHARACTER, DIRECTIONAL, FORWARD, {index: 1, value: 'start '}],
- [CHARACTER, DIRECTIONAL, FORWARD, {index: 2, value: 'start '}],
- [CHARACTER, DIRECTIONAL, FORWARD, {index: 3, value: 'start '}],
- [CHARACTER, DIRECTIONAL, FORWARD, {index: 4, value: 'start '}],
- [CHARACTER, DIRECTIONAL, FORWARD, {index: 5, value: 'start '}],
-
- [CHARACTER, DIRECTIONAL, FORWARD, {index: 0, value: 'same line'}],
- [CHARACTER, DIRECTIONAL, FORWARD, {index: 1, value: 'same line'}],
- [CHARACTER, DIRECTIONAL, BACKWARD, {index: 0, value: 'same line'}],
-
- [CHARACTER, DIRECTIONAL, BACKWARD, {index: 5, value: 'start '}],]);
-});
-
-TEST_F('CursorsTest', 'WordCursor', function() {
- this.runCursorMovesOnDocument(this.simpleDoc, [
- // Word (BOUND).
- [WORD, BOUND, BACKWARD, {index: 0, value: 'start '}],
- [WORD, BOUND, BACKWARD, {index: 0, value: 'start '}],
- [WORD, BOUND, FORWARD, {index: 5, value: 'start '}],
- [WORD, BOUND, FORWARD, {index: 5, value: 'start '}],
-
- // Word (DIRECTIONAL).
- [WORD, DIRECTIONAL, FORWARD, {index: 0, value: 'same line'}],
- [WORD, DIRECTIONAL, FORWARD, {index: 5, value: 'same line'}],
-
- [WORD, DIRECTIONAL, FORWARD, {index: 0, value: 'end'}],
- [WORD, DIRECTIONAL, FORWARD, {index: 0, value: 'end'}],
-
- [WORD, DIRECTIONAL, BACKWARD, {index: 5, value: 'same line'}],
- [WORD, DIRECTIONAL, BACKWARD, {index: 0, value: 'same line'}],
-
- [WORD, DIRECTIONAL, BACKWARD, {index: 0, value: 'start '}],
- [WORD, DIRECTIONAL, BACKWARD, {index: 0, value: 'start '}]]);
-});
-
-TEST_F('CursorsTest', 'CharacterWordCursor', function() {
- this.runCursorMovesOnDocument(this.simpleDoc, [
- [CHARACTER, DIRECTIONAL, FORWARD, {index: 1, value: 'start '}],
-
- [WORD, DIRECTIONAL, FORWARD, {index: 0, value: 'same line'}],
- [CHARACTER, DIRECTIONAL, FORWARD, {index: 1, value: 'same line'}],
- [WORD, DIRECTIONAL, FORWARD, {index: 5, value: 'same line'}],
- [CHARACTER, DIRECTIONAL, BACKWARD, {index: 4, value: 'same line'}],
- [WORD, DIRECTIONAL, FORWARD, {index: 5, value: 'same line'}],
- [CHARACTER, DIRECTIONAL, FORWARD, {index: 6, value: 'same line'}],
- [WORD, DIRECTIONAL, BACKWARD, {index: 0, value: 'same line'}],
- [CHARACTER, DIRECTIONAL, BACKWARD, {index: 5, value: 'start '}],
- [CHARACTER, DIRECTIONAL, BACKWARD, {index: 4, value: 'start '}],
- [WORD, DIRECTIONAL, BACKWARD, {index: 0, value: 'start '}]]);
-});
-
-TEST_F('CursorsTest', 'LineCursor', function() {
- this.runCursorMovesOnDocument(this.simpleDoc, [
- // Line (BOUND).
- [LINE, BOUND, FORWARD, {value: 'same line'}],
- [LINE, BOUND, FORWARD, {value: 'same line'}],
- [LINE, BOUND, BACKWARD, {value: 'start '}],
- [LINE, BOUND, BACKWARD, {value: 'start '}],
-
- // Line (DIRECTIONAL).
- [LINE, DIRECTIONAL, FORWARD, {value: 'end'}],
- [LINE, DIRECTIONAL, FORWARD, {value: 'end'}],
- [LINE, DIRECTIONAL, BACKWARD, {value: 'same line'}],
- [LINE, DIRECTIONAL, BACKWARD, {value: 'same line'}],
- [LINE, BOUND, BACKWARD, {value: 'start '}],
- [LINE, DIRECTIONAL, FORWARD, {value: 'end'}]]);
-});
-
-TEST_F('CursorsTest', 'CharacterRange', function() {
- this.runCursorMovesOnDocument(this.simpleDoc, [
- [CHARACTER, FORWARD,
- {value: 'start ', index: 1}, {value: 'start ', index: 2}],
- [CHARACTER, FORWARD,
- {value: 'start ', index: 2}, {value: 'start ', index: 3}],
- [CHARACTER, FORWARD,
- {value: 'start ', index: 3}, {value: 'start ', index: 4}],
- [CHARACTER, FORWARD,
- {value: 'start ', index: 4}, {value: 'start ', index: 5}],
- [CHARACTER, FORWARD,
- {value: 'start ', index: 5}, {value: 'start ', index: 5}],
-
- [CHARACTER, FORWARD,
- {value: 'same line', index: 0}, {value: 'same line', index: 1}],
-
- [CHARACTER, BACKWARD,
- {value: 'start ', index: 5}, {value: 'start ', index: 5}],
- [CHARACTER, BACKWARD,
- {value: 'start ', index: 4}, {value: 'start ', index: 5}],
- [CHARACTER, BACKWARD,
- {value: 'start ', index: 3}, {value: 'start ', index: 4}],
- [CHARACTER, BACKWARD,
- {value: 'start ', index: 2}, {value: 'start ', index: 3}],
- [CHARACTER, BACKWARD,
- {value: 'start ', index: 1}, {value: 'start ', index: 2}],
- [CHARACTER, BACKWARD,
- {value: 'start ', index: 0}, {value: 'start ', index: 1}],
- [CHARACTER, BACKWARD,
- {value: 'start ', index: 0}, {value: 'start ', index: 1}],
- ], this.RANGE);
-});
-
-TEST_F('CursorsTest', 'WordRange', function() {
- this.runCursorMovesOnDocument(this.simpleDoc, [
- [WORD, FORWARD,
- {value: 'same line', index: 0}, {value: 'same line', index: 4}],
- [WORD, FORWARD,
- {value: 'same line', index: 5}, {value: 'same line', index: 9}],
-
- [WORD, FORWARD,
- {value: 'end', index: 0}, {value: 'end', index: 3}],
- [WORD, FORWARD,
- {value: 'end', index: 0}, {value: 'end', index: 3}],
-
- [WORD, BACKWARD,
- {value: 'same line', index: 5}, {value: 'same line', index: 9}],
- [WORD, BACKWARD,
- {value: 'same line', index: 0}, {value: 'same line', index: 4}],
-
- [WORD, BACKWARD,
- {value: 'start ', index: 0}, {value: 'start ', index: 5}],
- [WORD, BACKWARD,
- {value: 'start ', index: 0}, {value: 'start ', index: 5}],
- ], this.RANGE);
-});
-
-
-TEST_F('CursorsTest', 'LineRange', function() {
- this.runCursorMovesOnDocument(this.simpleDoc, [
- [LINE, FORWARD, {value: 'end', index: 0}, {value: 'end', index: 3}],
- [LINE, FORWARD, {value: 'end', index: 0}, {value: 'end', index: 3}],
-
- [LINE, BACKWARD,
- {value: 'start ', index: 0}, {value: 'same line', index: 9}],
-
- [LINE, BACKWARD,
- {value: 'start ', index: 0}, {value: 'same line', index: 9}],
- ], this.RANGE);
-});
-
-TEST_F('CursorsTest', 'DontSplitOnNodeNavigation', function() {
- this.runWithLoadedTree(this.multiInlineDoc, function(root) {
- var para = root.firstChild;
- assertEquals('paragraph', para.role);
- var cursor = new cursors.Cursor(para, 0);
- cursor = cursor.move(DOM_NODE, DIRECTIONAL, FORWARD);
- assertEquals('staticText', cursor.node.role);
- assertEquals('end', cursor.node.value);
-
- cursor = cursor.move(DOM_NODE, DIRECTIONAL, BACKWARD);
- assertEquals('staticText', cursor.node.role);
- assertEquals('start diff line', cursor.node.value);
-
- assertEquals('inlineTextBox', cursor.node.firstChild.role);
- assertEquals('start ', cursor.node.firstChild.value);
- assertEquals('diff ', cursor.node.firstChild.nextSibling.value);
- assertEquals('line', cursor.node.lastChild.value);
- });
-});
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcon_engine.js b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcon_engine.js
deleted file mode 100644
index fc428c54827..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcon_engine.js
+++ /dev/null
@@ -1,711 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview This is the low-level class that generates ChromeVox's
- * earcons. It's designed to be self-contained and not depend on the
- * rest of the code.
- */
-
-goog.provide('EarconEngine');
-
-/**
- * EarconEngine generates ChromeVox's earcons using the web audio API.
- * @constructor
- */
-EarconEngine = function() {
- // Public control parameters. All of these are meant to be adjustable.
-
- /** @type {number} The master volume, as an amplification factor. */
- this.masterVolume = 0.2;
-
- /** @type {number} The base relative pitch adjustment, in half-steps. */
- this.masterPitch = -4;
-
- /** @type {number} The click volume, as an amplification factor. */
- this.clickVolume = 0.4;
-
- /**
- * @type {number} The volume of the static sound, as an
- * amplification factor.
- */
- this.staticVolume = 0.2;
-
- /** @type {number} The base delay for repeated sounds, in seconds. */
- this.baseDelay = 0.045;
-
- /** @type {number} The master stereo panning, from -1 to 1. */
- this.masterPan = 0;
-
- /** @type {number} The master reverb level as an amplification factor. */
- this.masterReverb = 0.4;
-
- /**
- * @type {string} The choice of the reverb impulse response to use.
- * Must be one of the strings from EarconEngine.REVERBS.
- */
- this.reverbSound = 'small_room_2';
-
- /** @type {number} The base pitch for the 'wrap' sound in half-steps. */
- this.wrapPitch = 0;
-
- /** @type {number} The base pitch for the 'alert' sound in half-steps. */
- this.alertPitch = 0;
-
- /** @type {string} The choice of base sound for most controls. */
- this.controlSound = 'control';
-
- /**
- * @type {number} The delay between sounds in the on/off sweep effect,
- * in seconds.
- */
- this.sweepDelay = 0.045;
-
- /**
- * @type {number} The delay between echos in the on/off sweep, in seconds.
- */
- this.sweepEchoDelay = 0.15;
-
- /** @type {number} The number of echos in the on/off sweep. */
- this.sweepEchoCount = 3;
-
- /** @type {number} The pitch offset of the on/off sweep, in half-steps. */
- this.sweepPitch = -7;
-
- /**
- * @type {number} The final gain of the progress sound, as an
- * amplification factor.
- */
- this.progressFinalGain = 0.05;
-
- /** @type {number} The multiplicative decay rate of the progress ticks. */
- this.progressGain_Decay = 0.7;
-
- // Private variables.
-
- /** @type {AudioContext} @private The audio context. */
- this.context_ = new AudioContext();
-
- /** @type {?ConvolverNode} @private The reverb node, lazily initialized. */
- this.reverbConvolver_ = null;
-
- /**
- * @type {Object<string, AudioBuffer>} A map between the name of an
- * audio data file and its loaded AudioBuffer.
- * @private
- */
- this.buffers_ = {};
-
- /**
- * The source audio nodes for queued tick / tocks for progress.
- * Kept around so they can be canceled.
- *
- * @type {Array<AudioNode>}
- * @private
- */
- this.progressSources_ = [];
-
- /** @type {number} The current gain for progress sounds. @private */
- this.progressGain_ = 1.0;
-
- /** @type {?number} The current time for progress sounds. @private */
- this.progressTime_ = this.context_.currentTime;
-
- /**
- * @type {?number} The window.setInterval ID for progress sounds.
- * @private
- */
- this.progressIntervalID_ = null;
-
- // Initialization: load the base sound data files asynchronously.
- var allSoundFilesToLoad = EarconEngine.SOUNDS.concat(EarconEngine.REVERBS);
- allSoundFilesToLoad.forEach((function(sound) {
- var url = EarconEngine.BASE_URL + sound + '.wav';
- this.loadSound(sound, url);
- }).bind(this));
-};
-
-/**
- * @type {Array<string>} The list of sound data files to load.
- * @const
- */
-EarconEngine.SOUNDS = [
- 'control',
- 'selection',
- 'selection_reverse',
- 'skim',
- 'static'];
-
-/**
- * @type {Array<string>} The list of reverb data files to load.
- * @const
- */
-EarconEngine.REVERBS = [
- 'small_room_2'];
-
-/**
- * @type {number} The scale factor for one half-step.
- * @const
- */
-EarconEngine.HALF_STEP = Math.pow(2.0, 1.0 / 12.0);
-
-/**
- * @type {string} The base url for earcon sound resources.
- * @const
- */
-EarconEngine.BASE_URL = chrome.extension.getURL('cvox2/background/earcons/');
-
-/**
- * Fetches a sound asynchronously and loads its data into an AudioBuffer.
- *
- * @param {string} name The name of the sound to load.
- * @param {string} url The url where the sound should be fetched from.
- */
-EarconEngine.prototype.loadSound = function(name, url) {
- var request = new XMLHttpRequest();
- request.open('GET', url, true);
- request.responseType = 'arraybuffer';
-
- // Decode asynchronously.
- request.onload = (function() {
- this.context_.decodeAudioData(
- /** @type {ArrayBuffer} */ (request.response),
- (function(buffer) {
- this.buffers_[name] = buffer;
- }).bind(this));
- }).bind(this);
- request.send();
-};
-
-/**
- * Return an AudioNode containing the final processing that all
- * sounds go through: master volume / gain, panning, and reverb.
- * The chain is hooked up to the destination automatically, so you
- * just need to connect your source to the return value from this
- * method.
- *
- * @param {{gain: (number | undefined),
- * pan: (number | undefined),
- * reverb: (number | undefined)}} properties
- * An object where you can override the default
- * gain, pan, and reverb, otherwise these are taken from
- * masterVolume, masterPan, and masterReverb.
- * @return {AudioNode} The filters to be applied to all sounds, connected
- * to the destination node.
- */
-EarconEngine.prototype.createCommonFilters = function(properties) {
- var gain = this.masterVolume;
- if (properties.gain) {
- gain *= properties.gain;
- }
- var gainNode = this.context_.createGain();
- gainNode.gain.value = gain;
- var first = gainNode;
- var last = gainNode;
-
- var pan = this.masterPan;
- if (properties.pan !== undefined) {
- pan = properties.pan;
- }
- if (pan != 0) {
- var panNode = this.context_.createPanner();
- panNode.setPosition(pan, 0, -1);
- panNode.setOrientation(0, 0, 1);
- last.connect(panNode);
- last = panNode;
- }
-
- var reverb = this.masterReverb;
- if (properties.reverb !== undefined) {
- reverb = properties.reverb;
- }
- if (reverb) {
- if (!this.reverbConvolver_) {
- this.reverbConvolver_ = this.context_.createConvolver();
- this.reverbConvolver_.buffer = this.buffers_[this.reverbSound];
- this.reverbConvolver_.connect(this.context_.destination);
- }
-
- // Dry
- last.connect(this.context_.destination);
-
- // Wet
- var reverbGainNode = this.context_.createGain();
- reverbGainNode.gain.value = reverb;
- last.connect(reverbGainNode);
- reverbGainNode.connect(this.reverbConvolver_);
- } else {
- last.connect(this.context_.destination);
- }
-
- return first;
-};
-
-/**
- * High-level interface to play a sound from a buffer source by name,
- * with some simple adjustments like pitch change (in half-steps),
- * a start time (relative to the current time, in seconds),
- * gain, panning, and reverb.
- *
- * The only required parameter is the name of the sound. The time, pitch,
- * gain, panning, and reverb are all optional and are passed in an
- * object of optional properties.
- *
- * @param {string} sound The name of the sound to play. It must already
- * be loaded in a buffer.
- * @param {{pitch: (number | undefined),
- * time: (number | undefined),
- * gain: (number | undefined),
- * pan: (number | undefined),
- * reverb: (number | undefined)}=} opt_properties
- * An object where you can override the default pitch, gain, pan,
- * and reverb.
- * @return {AudioBufferSourceNode} The source node, so you can stop it
- * or set event handlers on it.
- */
-EarconEngine.prototype.play = function(sound, opt_properties) {
- var source = this.context_.createBufferSource();
- source.buffer = this.buffers_[sound];
-
- if (!opt_properties) {
- // This typecast looks silly, but the Closure compiler doesn't support
- // optional fields in record types very well so this is the shortest hack.
- opt_properties = /** @type {undefined} */({});
- }
-
- var pitch = this.masterPitch;
- if (opt_properties.pitch) {
- pitch += opt_properties.pitch;
- }
- if (pitch != 0) {
- source.playbackRate.value = Math.pow(EarconEngine.HALF_STEP, pitch);
- }
-
- var destination = this.createCommonFilters(opt_properties);
- source.connect(destination);
-
- if (opt_properties.time) {
- source.start(this.context_.currentTime + opt_properties.time);
- } else {
- source.start(this.context_.currentTime);
- }
-
- return source;
-};
-
-/**
- * Play the static sound.
- */
-EarconEngine.prototype.onStatic = function() {
- this.play('static', {gain: this.staticVolume});
-};
-
-/**
- * Play the link sound.
- */
-EarconEngine.prototype.onLink = function() {
- this.play('static', {gain: this.clickVolume});
- this.play(this.controlSound, {pitch: 12});
-};
-
-/**
- * Play the button sound.
- */
-EarconEngine.prototype.onButton = function() {
- this.play('static', {gain: this.clickVolume});
- this.play(this.controlSound);
-};
-
-/**
- * Play the text field sound.
- */
-EarconEngine.prototype.onTextField = function() {
- this.play('static', {gain: this.clickVolume});
- this.play('static', {time: this.baseDelay * 1.5,
- gain: this.clickVolume * 0.5});
- this.play(this.controlSound, {pitch: 4});
- this.play(this.controlSound,
- {pitch: 4,
- time: this.baseDelay * 1.5,
- gain: 0.5});
-};
-
-/**
- * Play the pop up button sound.
- */
-EarconEngine.prototype.onPopUpButton = function() {
- this.play('static', {gain: this.clickVolume});
-
- this.play(this.controlSound);
- this.play(this.controlSound,
- {time: this.baseDelay * 3,
- gain: 0.2,
- pitch: 12});
- this.play(this.controlSound,
- {time: this.baseDelay * 4.5,
- gain: 0.2,
- pitch: 12});
-};
-
-/**
- * Play the check on sound.
- */
-EarconEngine.prototype.onCheckOn = function() {
- this.play('static', {gain: this.clickVolume});
- this.play(this.controlSound, {pitch: -5});
- this.play(this.controlSound, {pitch: 7, time: this.baseDelay * 2});
-};
-
-/**
- * Play the check off sound.
- */
-EarconEngine.prototype.onCheckOff = function() {
- this.play('static', {gain: this.clickVolume});
- this.play(this.controlSound, {pitch: 7});
- this.play(this.controlSound, {pitch: -5, time: this.baseDelay * 2});
-};
-
-/**
- * Play the select control sound.
- */
-EarconEngine.prototype.onSelect = function() {
- this.play('static', {gain: this.clickVolume});
- this.play(this.controlSound);
- this.play(this.controlSound, {time: this.baseDelay});
- this.play(this.controlSound, {time: this.baseDelay * 2});
-};
-
-/**
- * Play the slider sound.
- */
-EarconEngine.prototype.onSlider = function() {
- this.play('static', {gain: this.clickVolume});
- this.play(this.controlSound);
- this.play(this.controlSound,
- {time: this.baseDelay,
- gain: 0.5,
- pitch: 2});
- this.play(this.controlSound,
- {time: this.baseDelay * 2,
- gain: 0.25,
- pitch: 4});
- this.play(this.controlSound,
- {time: this.baseDelay * 3,
- gain: 0.125,
- pitch: 6});
- this.play(this.controlSound,
- {time: this.baseDelay * 4,
- gain: 0.0625,
- pitch: 8});
-};
-
-/**
- * Play the skim sound.
- */
-EarconEngine.prototype.onSkim = function() {
- this.play('skim');
-};
-
-/**
- * Play the selection sound.
- */
-EarconEngine.prototype.onSelection = function() {
- this.play('selection');
-};
-
-/**
- * Play the selection reverse sound.
- */
-EarconEngine.prototype.onSelectionReverse = function() {
- this.play('selection_reverse');
-};
-
-/**
- * Generate a synthesized musical note based on a sum of sinusoidals shaped
- * by an envelope, controlled by a number of properties.
- *
- * The sound has a frequency of |freq|, or if |endFreq| is specified, does
- * an exponential ramp from |freq| to |endFreq|.
- *
- * If |overtones| is greater than 1, the sound will be mixed with additional
- * sinusoidals at multiples of |freq|, each one scaled by |overtoneFactor|.
- * This creates a rounder tone than a pure sine wave.
- *
- * The envelope is shaped by the duration |dur|, the attack time |attack|,
- * and the decay time |decay|, in seconds.
- *
- * As with other functions, |pan| and |reverb| can be used to override
- * masterPan and masterReverb.
- *
- * @param {{gain: number,
- * freq: number,
- * endFreq: (number | undefined),
- * time: (number | undefined),
- * overtones: (number | undefined),
- * overtoneFactor: (number | undefined),
- * dur: (number | undefined),
- * attack: (number | undefined),
- * decay: (number | undefined),
- * pan: (number | undefined),
- * reverb: (number | undefined)}} properties
- * An object containing the properties that can be used to
- * control the sound, as described above.
- */
-EarconEngine.prototype.generateSinusoidal = function(properties) {
- var envelopeNode = this.context_.createGain();
- envelopeNode.connect(this.context_.destination);
-
- var time = properties.time;
- if (time === undefined) {
- time = 0;
- }
-
- // Generate an oscillator for the frequency corresponding to the specified
- // frequency, and then additional overtones at multiples of that frequency
- // scaled by the overtoneFactor. Cue the oscillator to start and stop
- // based on the start time and specified duration.
- //
- // If an end frequency is specified, do an exponential ramp to that end
- // frequency.
- var gain = properties.gain;
- for (var i = 0; i < properties.overtones; i++) {
- var osc = this.context_.createOscillator();
- osc.frequency.value = properties.freq * (i + 1);
-
- if (properties.endFreq) {
- osc.frequency.setValueAtTime(
- properties.freq * (i + 1),
- this.context_.currentTime + time);
- osc.frequency.exponentialRampToValueAtTime(
- properties.endFreq * (i + 1),
- this.context_.currentTime + properties.dur);
- }
-
- osc.start(this.context_.currentTime + time);
- osc.stop(this.context_.currentTime + time + properties.dur);
-
- var gainNode = this.context_.createGain();
- gainNode.gain.value = gain;
- osc.connect(gainNode);
- gainNode.connect(envelopeNode);
-
- gain *= properties.overtoneFactor;
- }
-
- // Shape the overall sound by an envelope based on the attack and
- // decay times.
- envelopeNode.gain.setValueAtTime(0, this.context_.currentTime + time);
- envelopeNode.gain.linearRampToValueAtTime(
- 1, this.context_.currentTime + time + properties.attack);
- envelopeNode.gain.setValueAtTime(
- 1, this.context_.currentTime + time +
- properties.dur - properties.decay);
- envelopeNode.gain.linearRampToValueAtTime(
- 0, this.context_.currentTime + time + properties.dur);
-
- // Route everything through the common filters like reverb at the end.
- var destination = this.createCommonFilters({});
- envelopeNode.connect(destination);
-};
-
-/**
- * Play a sweep over a bunch of notes in a scale, with an echo,
- * for the ChromeVox on or off sounds.
- *
- * @param {boolean} reverse Whether to play in the reverse direction.
- */
-EarconEngine.prototype.onChromeVoxSweep = function(reverse) {
- var pitches = [-7, -5, 0, 5, 7, 12, 17, 19, 24];
-
- if (reverse) {
- pitches.reverse();
- }
-
- var attack = 0.015;
- var dur = pitches.length * this.sweepDelay;
-
- var destination = this.createCommonFilters({reverb: 2.0});
- for (var k = 0; k < this.sweepEchoCount; k++) {
- var envelopeNode = this.context_.createGain();
- var startTime = this.context_.currentTime + this.sweepEchoDelay * k;
- var sweepGain = Math.pow(0.3, k);
- var overtones = 2;
- var overtoneGain = sweepGain;
- for (var i = 0; i < overtones; i++) {
- var osc = this.context_.createOscillator();
- osc.start(startTime);
- osc.stop(startTime + dur);
-
- var gainNode = this.context_.createGain();
- osc.connect(gainNode);
- gainNode.connect(envelopeNode);
-
- for (var j = 0; j < pitches.length; j++) {
- var freqDecay;
- if (reverse) {
- freqDecay = Math.pow(0.75, pitches.length - j);
- } else {
- freqDecay = Math.pow(0.75, j);
- }
- var gain = overtoneGain * freqDecay;
- var freq = (i + 1) * 220 *
- Math.pow(EarconEngine.HALF_STEP, pitches[j] + this.sweepPitch);
- if (j == 0) {
- osc.frequency.setValueAtTime(freq, startTime);
- gainNode.gain.setValueAtTime(gain, startTime);
- } else {
- osc.frequency.exponentialRampToValueAtTime(
- freq, startTime + j * this.sweepDelay);
- gainNode.gain.linearRampToValueAtTime(
- gain, startTime + j * this.sweepDelay);
- }
- osc.frequency.setValueAtTime(
- freq, startTime + j * this.sweepDelay + this.sweepDelay - attack);
- }
-
- overtoneGain *= 0.1 + 0.2 * k;
- }
-
- envelopeNode.gain.setValueAtTime(0, startTime);
- envelopeNode.gain.linearRampToValueAtTime(1, startTime + this.sweepDelay);
- envelopeNode.gain.setValueAtTime(1, startTime + dur - attack * 2);
- envelopeNode.gain.linearRampToValueAtTime(0, startTime + dur);
- envelopeNode.connect(destination);
- }
-};
-
-/**
- * Play the "ChromeVox On" sound.
- */
-EarconEngine.prototype.onChromeVoxOn = function() {
- this.onChromeVoxSweep(false);
-};
-
-/**
- * Play the "ChromeVox Off" sound.
- */
-EarconEngine.prototype.onChromeVoxOff = function() {
- this.onChromeVoxSweep(true);
-};
-
-/**
- * Play an alert sound.
- */
-EarconEngine.prototype.onAlert = function() {
- var freq1 = 220 * Math.pow(EarconEngine.HALF_STEP, this.alertPitch - 2);
- var freq2 = 220 * Math.pow(EarconEngine.HALF_STEP, this.alertPitch - 3);
- this.generateSinusoidal({attack: 0.02,
- decay: 0.07,
- dur: 0.15,
- gain: 0.3,
- freq: freq1,
- overtones: 3,
- overtoneFactor: 0.1});
- this.generateSinusoidal({attack: 0.02,
- decay: 0.07,
- dur: 0.15,
- gain: 0.3,
- freq: freq2,
- overtones: 3,
- overtoneFactor: 0.1});
-};
-
-/**
- * Play a wrap sound.
- */
-EarconEngine.prototype.onWrap = function() {
- this.play('static', {gain: this.clickVolume * 0.3});
- var freq1 = 220 * Math.pow(EarconEngine.HALF_STEP, this.wrapPitch - 8);
- var freq2 = 220 * Math.pow(EarconEngine.HALF_STEP, this.wrapPitch + 8);
- this.generateSinusoidal({attack: 0.01,
- decay: 0.1,
- dur: 0.15,
- gain: 0.3,
- freq: freq1,
- endFreq: freq2,
- overtones: 1,
- overtoneFactor: 0.1});
-};
-
-/**
- * Queue up a few tick/tock sounds for a progress bar. This is called
- * repeatedly by setInterval to keep the sounds going continuously.
- * @private
- */
-EarconEngine.prototype.generateProgressTickTocks_ = function() {
- while (this.progressTime_ < this.context_.currentTime + 3.0) {
- var t = this.progressTime_ - this.context_.currentTime;
- this.progressSources_.push(
- [this.progressTime_,
- this.play('static',
- {gain: 0.5 * this.progressGain_,
- time: t})]);
- this.progressSources_.push(
- [this.progressTime_,
- this.play(this.controlSound,
- {pitch: 20,
- time: t,
- gain: this.progressGain_})]);
-
- if (this.progressGain_ > this.progressFinalGain) {
- this.progressGain_ *= this.progressGain_Decay;
- }
- t += 0.5;
-
- this.progressSources_.push(
- [this.progressTime_,
- this.play('static',
- {gain: 0.5 * this.progressGain_,
- time: t})]);
- this.progressSources_.push(
- [this.progressTime_,
- this.play(this.controlSound,
- {pitch: 8,
- time: t,
- gain: this.progressGain_})]);
-
- if (this.progressGain_ > this.progressFinalGain) {
- this.progressGain_ *= this.progressGain_Decay;
- }
-
- this.progressTime_ += 1.0;
- }
-
- var removeCount = 0;
- while (removeCount < this.progressSources_.length &&
- this.progressSources_[removeCount][0] < this.context_.currentTime - 0.2) {
- removeCount++;
- }
- this.progressSources_.splice(0, removeCount);
-};
-
-/**
- * Start playing tick / tock progress sounds continuously until
- * explicitly canceled.
- */
-EarconEngine.prototype.startProgress = function() {
- this.progressSources_ = [];
- this.progressGain_ = 0.5;
- this.progressTime_ = this.context_.currentTime;
- this.generateProgressTickTocks_();
- this.progressIntervalID_ = window.setInterval(
- this.generateProgressTickTocks_.bind(this), 1000);
-};
-
-/**
- * Stop playing any tick / tock progress sounds.
- */
-EarconEngine.prototype.cancelProgress = function() {
- if (!this.progressIntervalID_) {
- return;
- }
-
- for (var i = 0; i < this.progressSources_.length; i++) {
- this.progressSources_[i][1].stop();
- }
- this.progressSources_ = [];
-
- window.clearInterval(this.progressIntervalID_);
- this.progressIntervalID_ = null;
-};
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/control.wav b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/control.wav
deleted file mode 100644
index 4a37991111a..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/control.wav
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/selection.wav b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/selection.wav
deleted file mode 100644
index 7be8224dbd3..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/selection.wav
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/selection_reverse.wav b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/selection_reverse.wav
deleted file mode 100644
index a42b0d9afb3..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/selection_reverse.wav
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/skim.wav b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/skim.wav
deleted file mode 100644
index b74c196c18b..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/skim.wav
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/small_room_2.wav b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/small_room_2.wav
deleted file mode 100644
index 7ef10db6c87..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/small_room_2.wav
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/static.wav b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/static.wav
deleted file mode 100644
index d43fae18449..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcons/static.wav
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/loader.js b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/loader.js
deleted file mode 100644
index 7f2602dc9f3..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/loader.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Loader for the background page.
- */
-
-goog.require('Background');
-goog.require('cvox.ChromeVoxBackground');
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
deleted file mode 100644
index 677030882ea..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
+++ /dev/null
@@ -1,1329 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Provides output services for ChromeVox.
- */
-
-goog.provide('Output');
-goog.provide('Output.EventType');
-
-goog.require('AutomationUtil.Dir');
-goog.require('EarconEngine');
-goog.require('cursors.Cursor');
-goog.require('cursors.Range');
-goog.require('cursors.Unit');
-goog.require('cvox.AbstractEarcons');
-goog.require('cvox.NavBraille');
-goog.require('cvox.Spannable');
-goog.require('cvox.ValueSelectionSpan');
-goog.require('cvox.ValueSpan');
-goog.require('goog.i18n.MessageFormat');
-
-goog.scope(function() {
-var Dir = AutomationUtil.Dir;
-
-/**
- * An Output object formats a cursors.Range into speech, braille, or both
- * representations. This is typically a cvox.Spannable.
- *
- * The translation from Range to these output representations rely upon format
- * rules which specify how to convert AutomationNode objects into annotated
- * strings.
- * The format of these rules is as follows.
- *
- * $ prefix: used to substitute either an attribute or a specialized value from
- * an AutomationNode. Specialized values include role and state.
- * For example, $value $role $enabled
- * @ prefix: used to substitute a message. Note the ability to specify params to
- * the message. For example, '@tag_html' '@selected_index($text_sel_start,
- * $text_sel_end').
- * @@ prefix: similar to @, used to substitute a message, but also pulls the
- * localized string through goog.i18n.MessageFormat to support locale
- * aware plural handling. The first argument should be a number which will
- * be passed as a COUNT named parameter to MessageFormat.
- * TODO(plundblad): Make subsequent arguments normal placeholder arguments
- * when needed.
- * = suffix: used to specify substitution only if not previously appended.
- * For example, $name= would insert the name attribute only if no name
- * attribute had been inserted previously.
- * @constructor
- */
-Output = function() {
- // TODO(dtseng): Include braille specific rules.
- /** @type {!Array<!cvox.Spannable>} */
- this.speechBuffer_ = [];
- /** @type {!Array<!cvox.Spannable>} */
- this.brailleBuffer_ = [];
- /** @type {!Array<!Object>} */
- this.locations_ = [];
- /** @type {function(?)} */
- this.speechEndCallback_;
-
- /**
- * Current global options.
- * @type {{speech: boolean, braille: boolean, location: boolean}}
- */
- this.formatOptions_ = {speech: true, braille: false, location: true};
-
- /**
- * Speech properties to apply to the entire output.
- * @type {!Object<*>}
- */
- this.speechProperties_ = {};
-};
-
-/**
- * Delimiter to use between output values.
- * @type {string}
- */
-Output.SPACE = ' ';
-
-/**
- * Metadata about supported automation roles.
- * @const {Object<{msgId: string,
- * earconId: (string|undefined),
- * inherits: (string|undefined)}>}
- * msgId: the message id of the role.
- * earconId: an optional earcon to play when encountering the role.
- * inherits: inherits rules from this role.
- * @private
- */
-Output.ROLE_INFO_ = {
- alert: {
- msgId: 'role_alert',
- earconId: 'ALERT_NONMODAL',
- },
- alertDialog: {
- msgId: 'role_alertdialog'
- },
- article: {
- msgId: 'role_article',
- inherits: 'abstractContainer'
- },
- application: {
- msgId: 'role_application',
- inherits: 'abstractContainer'
- },
- banner: {
- msgId: 'role_banner',
- inherits: 'abstractContainer'
- },
- button: {
- msgId: 'role_button',
- earconId: 'BUTTON'
- },
- buttonDropDown: {
- msgId: 'role_button',
- earconId: 'BUTTON'
- },
- cell: {
- msgId: 'role_gridcell'
- },
- checkBox: {
- msgId: 'role_checkbox'
- },
- columnHeader: {
- msgId: 'role_columnheader',
- inherits: 'abstractContainer'
- },
- comboBox: {
- msgId: 'role_combobox'
- },
- complementary: {
- msgId: 'role_complementary',
- inherits: 'abstractContainer'
- },
- contentInfo: {
- msgId: 'role_contentinfo',
- inherits: 'abstractContainer'
- },
- date: {
- msgId: 'input_type_date',
- inherits: 'abstractContainer'
- },
- definition: {
- msgId: 'role_definition',
- inherits: 'abstractContainer'
- },
- dialog: {
- msgId: 'role_dialog'
- },
- directory: {
- msgId: 'role_directory',
- inherits: 'abstractContainer'
- },
- document: {
- msgId: 'role_document',
- inherits: 'abstractContainer'
- },
- form: {
- msgId: 'role_form',
- inherits: 'abstractContainer'
- },
- grid: {
- msgId: 'role_grid'
- },
- group: {
- msgId: 'role_group'
- },
- heading: {
- msgId: 'role_heading',
- },
- image: {
- msgId: 'role_img',
- },
- inputTime: {
- msgId: 'input_type_time',
- inherits: 'abstractContainer'
- },
- link: {
- msgId: 'role_link',
- earconId: 'LINK'
- },
- listBox: {
- msgId: 'role_listbox',
- earconId: 'LISTBOX'
- },
- listBoxOption: {
- msgId: 'role_listitem',
- earconId: 'LIST_ITEM'
- },
- listItem: {
- msgId: 'role_listitem',
- earconId: 'LIST_ITEM'
- },
- log: {
- msgId: 'role_log',
- },
- main: {
- msgId: 'role_main',
- inherits: 'abstractContainer'
- },
- marquee: {
- msgId: 'role_marquee',
- },
- math: {
- msgId: 'role_math',
- inherits: 'abstractContainer'
- },
- menu: {
- msgId: 'role_menu'
- },
- menuBar: {
- msgId: 'role_menubar',
- },
- menuItem: {
- msgId: 'role_menuitem'
- },
- menuItemCheckBox: {
- msgId: 'role_menuitemcheckbox'
- },
- menuItemRadio: {
- msgId: 'role_menuitemradio'
- },
- menuListOption: {
- msgId: 'role_menuitem'
- },
- menuListPopup: {
- msgId: 'role_menu'
- },
- navigation: {
- msgId: 'role_navigation',
- inherits: 'abstractContainer'
- },
- note: {
- msgId: 'role_note',
- inherits: 'abstractContainer'
- },
- popUpButton: {
- msgId: 'role_button',
- earcon: 'LISTBOX'
- },
- radioButton: {
- msgId: 'role_radio'
- },
- radioGroup: {
- msgId: 'role_radiogroup',
- },
- region: {
- msgId: 'role_region',
- inherits: 'abstractContainer'
- },
- rowHeader: {
- msgId: 'role_rowheader',
- inherits: 'abstractContainer'
- },
- scrollBar: {
- msgId: 'role_scrollbar',
- },
- search: {
- msgId: 'role_search',
- inherits: 'abstractContainer'
- },
- separator: {
- msgId: 'role_separator',
- inherits: 'abstractContainer'
- },
- spinButton: {
- msgId: 'role_spinbutton',
- earconId: 'LISTBOX'
- },
- status: {
- msgId: 'role_status'
- },
- tab: {
- msgId: 'role_tab'
- },
- tabList: {
- msgId: 'role_tablist'
- },
- tabPanel: {
- msgId: 'role_tabpanel'
- },
- textBox: {
- msgId: 'input_type_text',
- earconId: 'EDITABLE_TEXT'
- },
- textField: {
- msgId: 'input_type_text',
- earconId: 'EDITABLE_TEXT'
- },
- time: {
- msgId: 'tag_time',
- inherits: 'abstractContainer'
- },
- timer: {
- msgId: 'role_timer'
- },
- toolbar: {
- msgId: 'role_toolbar'
- },
- tree: {
- msgId: 'role_tree'
- },
- treeItem: {
- msgId: 'role_treeitem'
- }
-};
-
-/**
- * Metadata about supported automation states.
- * @const {!Object<{on: {msgId: string, earconId: string},
- * off: {msgId: string, earconId: string},
- * omitted: {msgId: string, earconId: string}}>}
- * on: info used to describe a state that is set to true.
- * off: info used to describe a state that is set to false.
- * omitted: info used to describe a state that is undefined.
- * @private
- */
-Output.STATE_INFO_ = {
- checked: {
- on: {
- earconId: 'CHECK_ON',
- msgId: 'checkbox_checked_state'
- },
- off: {
- earconId: 'CHECK_OFF',
- msgId: 'checkbox_unchecked_state'
- },
- omitted: {
- earconId: 'CHECK_OFF',
- msgId: 'checkbox_unchecked_state'
- }
- },
- collapsed: {
- on: {
- msgId: 'aria_expanded_false'
- },
- off: {
- msgId: 'aria_expanded_true'
- }
- },
- expanded: {
- on: {
- msgId: 'aria_expanded_true'
- },
- off: {
- msgId: 'aria_expanded_false'
- }
- },
- visited: {
- on: {
- msgId: 'visited_state'
- }
- }
-};
-
-/**
- * Maps input types to message IDs.
- * @const {Object<string>}
- * @private
- */
-Output.INPUT_TYPE_MESSAGE_IDS_ = {
- 'email': 'input_type_email',
- 'number': 'input_type_number',
- 'password': 'input_type_password',
- 'search': 'input_type_search',
- 'tel': 'input_type_number',
- 'text': 'input_type_text',
- 'url': 'input_type_url',
-};
-
-/**
- * Rules specifying format of AutomationNodes for output.
- * @type {!Object<Object<Object<string>>>}
- */
-Output.RULES = {
- navigate: {
- 'default': {
- speak: '$name $value $help $role',
- braille: ''
- },
- abstractContainer: {
- enter: '$name $role',
- leave: '@exited_container($role)'
- },
- alert: {
- speak: '!doNotInterrupt $role $descendants'
- },
- alertDialog: {
- enter: '$name $role $descendants'
- },
- cell: {
- enter: '@column_granularity $tableCellColumnIndex'
- },
- checkBox: {
- speak: '$name $role $checked'
- },
- dialog: {
- enter: '$name $role'
- },
- div: {
- enter: '$name',
- speak: '$name'
- },
- grid: {
- enter: '$name $role'
- },
- heading: {
- enter: '@tag_h+$hierarchicalLevel',
- speak: '@tag_h+$hierarchicalLevel $nameOrDescendants='
- },
- inlineTextBox: {
- speak: '$value='
- },
- link: {
- enter: '$name $if($visited, @visited_link, $role)',
- stay: '$name= $if($visited, @visited_link, $role)',
- speak: '$name= $if($visited, @visited_link, $role)'
- },
- list: {
- enter: '$role @@list_with_items($countChildren(listItem))'
- },
- listBox: {
- enter: '$name $role @@list_with_items($countChildren(listBoxOption))'
- },
- listBoxOption: {
- speak: '$name $role @describe_index($indexInParent, $parentChildCount)'
- },
- listItem: {
- enter: '$role'
- },
- menu: {
- enter: '$name $role @@list_with_items($countChildren(menuItem))'
- },
- menuItem: {
- speak: '$name $role $if($haspopup, @has_submenu) ' +
- '@describe_index($indexInParent, $parentChildCount)'
- },
- menuListOption: {
- speak: '$name $value @role_menuitem ' +
- '@describe_index($indexInParent, $parentChildCount)'
- },
- paragraph: {
- speak: '$descendants'
- },
- popUpButton: {
- speak: '$value $name $role @aria_has_popup ' +
- '$if($collapsed, @aria_expanded_false, @aria_expanded_true)'
- },
- radioButton: {
- speak: '$if($checked, @describe_radio_selected($name), ' +
- '@describe_radio_unselected($name))'
- },
- radioGroup: {
- enter: '$name $role'
- },
- rootWebArea: {
- enter: '$name'
- },
- row: {
- enter: '@row_granularity $tableRowIndex'
- },
- slider: {
- speak: '@describe_slider($value, $name) $help'
- },
- staticText: {
- speak: '$value='
- },
- tab: {
- speak: '@describe_tab($name)'
- },
- textField: {
- speak: '$name $value $if(' +
- '$inputType, $inputType, $role)',
- braille: ''
- },
- toolbar: {
- enter: '$name $role'
- },
- tree: {
- enter: '$name $role @@list_with_items($countChildren(treeItem))'
- },
- treeItem: {
- enter: '$role $expanded $collapsed ' +
- '@describe_index($indexInParent, $parentChildCount) ' +
- '@describe_depth($hierarchicalLevel)'
- },
- window: {
- enter: '$name',
- speak: '@describe_window($name) $earcon(OBJECT_OPEN)'
- }
- },
- menuStart: {
- 'default': {
- speak: '@chrome_menu_opened($name) $earcon(OBJECT_OPEN)'
- }
- },
- menuEnd: {
- 'default': {
- speak: '@chrome_menu_closed $earcon(OBJECT_CLOSE)'
- }
- },
- menuListValueChanged: {
- 'default': {
- speak: '$value $name ' +
- '$find({"state": {"selected": true, "invisible": false}}, ' +
- '@describe_index($indexInParent, $parentChildCount)) '
- }
- },
- alert: {
- default: {
- speak: '!doNotInterrupt ' +
- '@role_alert $name $earcon(ALERT_NONMODAL) $descendants'
- }
- }
-};
-
-/**
- * Custom actions performed while rendering an output string.
- * @constructor
- */
-Output.Action = function() {
-};
-
-Output.Action.prototype = {
- run: function() {
- }
-};
-
-/**
- * Action to play an earcon.
- * @param {string} earconId
- * @constructor
- * @extends {Output.Action}
- */
-Output.EarconAction = function(earconId) {
- Output.Action.call(this);
- /** @type {string} */
- this.earconId = earconId;
-};
-
-Output.EarconAction.prototype = {
- __proto__: Output.Action.prototype,
-
- /** @override */
- run: function() {
- cvox.ChromeVox.earcons.playEarcon(cvox.Earcon[this.earconId]);
- }
-};
-
-/**
- * Annotation for selection.
- * @param {number} startIndex
- * @param {number} endIndex
- * @constructor
- */
-Output.SelectionSpan = function(startIndex, endIndex) {
- // TODO(dtseng): Direction lost below; should preserve for braille panning.
- this.startIndex = startIndex < endIndex ? startIndex : endIndex;
- this.endIndex = endIndex > startIndex ? endIndex : startIndex;
-};
-
-/**
- * Wrapper for automation nodes as annotations. Since the
- * {@code chrome.automation.AutomationNode} constructor isn't exposed in
- * the API, this class is used to allow isntanceof checks on these
- * annotations.
- @ @param {chrome.automation.AutomationNode} node
- * @constructor
- */
-Output.NodeSpan = function(node) {
- this.node = node;
-};
-
-/**
- * Possible events handled by ChromeVox internally.
- * @enum {string}
- */
-Output.EventType = {
- NAVIGATE: 'navigate'
-};
-
-Output.prototype = {
- /**
- * Gets the spoken output with separator '|'.
- * @return {!cvox.Spannable}
- */
- get speechOutputForTest() {
- return this.speechBuffer_.reduce(function(prev, cur) {
- if (prev === null)
- return cur;
- prev.append('|');
- prev.append(cur);
- return prev;
- }, null);
- },
-
- /**
- * Gets the output buffer for braille.
- * @return {!cvox.Spannable}
- */
- get brailleOutputForTest() {
- return this.createBrailleOutput_();
- },
-
- /**
- * Specify ranges for speech.
- * @param {!cursors.Range} range
- * @param {cursors.Range} prevRange
- * @param {chrome.automation.EventType|Output.EventType} type
- * @return {!Output}
- */
- withSpeech: function(range, prevRange, type) {
- this.formatOptions_ = {speech: true, braille: false, location: true};
- this.render_(range, prevRange, type, this.speechBuffer_);
- return this;
- },
-
- /**
- * Specify ranges for braille.
- * @param {!cursors.Range} range
- * @param {cursors.Range} prevRange
- * @param {chrome.automation.EventType|Output.EventType} type
- * @return {!Output}
- */
- withBraille: function(range, prevRange, type) {
- this.formatOptions_ = {speech: false, braille: true, location: false};
- this.render_(range, prevRange, type, this.brailleBuffer_);
- return this;
- },
-
- /**
- * Specify the same ranges for speech and braille.
- * @param {!cursors.Range} range
- * @param {cursors.Range} prevRange
- * @param {chrome.automation.EventType|Output.EventType} type
- * @return {!Output}
- */
- withSpeechAndBraille: function(range, prevRange, type) {
- this.withSpeech(range, prevRange, type);
- this.withBraille(range, prevRange, type);
- return this;
- },
-
- /**
- * Apply a format string directly to the output buffer. This lets you
- * output a message directly to the buffer using the format syntax.
- * @param {string} formatStr
- * @return {!Output}
- */
- format: function(formatStr) {
- this.formatOptions_ = {speech: true, braille: false, location: true};
- this.format_(null, formatStr, this.speechBuffer_);
-
- this.formatOptions_ = {speech: false, braille: true, location: false};
- this.format_(null, formatStr, this.brailleBuffer_);
-
- return this;
- },
-
- /**
- * Triggers callback for a speech event.
- * @param {function()} callback
- */
- onSpeechEnd: function(callback) {
- this.speechEndCallback_ = function(opt_cleanupOnly) {
- if (!opt_cleanupOnly)
- callback();
- }.bind(this);
- return this;
- },
-
- /**
- * Executes all specified output.
- */
- go: function() {
- // Speech.
- var queueMode = cvox.QueueMode.FLUSH;
- this.speechBuffer_.forEach(function(buff, i, a) {
- if (buff.toString()) {
- (function() {
- var scopedBuff = buff;
- this.speechProperties_['startCallback'] = function() {
- var actions = scopedBuff.getSpansInstanceOf(Output.Action);
- if (actions) {
- actions.forEach(function(a) {
- a.run();
- });
- }
- };
- }.bind(this)());
-
- if (this.speechEndCallback_ && i == a.length - 1)
- this.speechProperties_['endCallback'] = this.speechEndCallback_;
- else
- this.speechProperties_['endCallback'] = null;
- cvox.ChromeVox.tts.speak(
- buff.toString(), queueMode, this.speechProperties_);
- queueMode = cvox.QueueMode.QUEUE;
- }
- }.bind(this));
-
- // Braille.
- if (this.brailleBuffer_.length) {
- var buff = this.createBrailleOutput_();
- var selSpan =
- buff.getSpanInstanceOf(Output.SelectionSpan);
- var startIndex = -1, endIndex = -1;
- if (selSpan) {
- // Casts ok, since the span is known to be in the spannable.
- var valueStart =
- /** @type {number} */ (buff.getSpanStart(selSpan));
- var valueEnd =
- /** @type {number} */ (buff.getSpanEnd(selSpan));
- startIndex = valueStart + selSpan.startIndex;
- endIndex = valueStart + selSpan.endIndex;
- buff.setSpan(new cvox.ValueSpan(0), valueStart, valueEnd);
- buff.setSpan(new cvox.ValueSelectionSpan(), startIndex, endIndex);
- }
-
- var output = new cvox.NavBraille({
- text: buff,
- startIndex: startIndex,
- endIndex: endIndex
- });
-
- cvox.ChromeVox.braille.write(output);
- }
-
- // Display.
- chrome.accessibilityPrivate.setFocusRing(this.locations_);
- },
-
- /**
- * Renders the given range using optional context previous range and event
- * type.
- * @param {!cursors.Range} range
- * @param {cursors.Range} prevRange
- * @param {chrome.automation.EventType|string} type
- * @param {!Array<cvox.Spannable>} buff Buffer to receive rendered output.
- * @private
- */
- render_: function(range, prevRange, type, buff) {
- if (range.isSubNode())
- this.subNode_(range, prevRange, type, buff);
- else
- this.range_(range, prevRange, type, buff);
- },
-
- /**
- * Format the node given the format specifier.
- * @param {chrome.automation.AutomationNode} node
- * @param {string|!Object} format The output format either specified as an
- * output template string or a parsed output format tree.
- * @param {!Array<cvox.Spannable>} buff Buffer to receive rendered output.
- * @param {!Object=} opt_exclude A set of attributes to exclude.
- * @private
- */
- format_: function(node, format, buff, opt_exclude) {
- opt_exclude = opt_exclude || {};
- var tokens = [];
- var args = null;
-
- // Hacky way to support args.
- if (typeof(format) == 'string') {
- format = format.replace(/([,:])\W/g, '$1');
- tokens = format.split(' ');
- } else {
- tokens = [format];
- }
-
- tokens.forEach(function(token) {
- // Ignore empty tokens.
- if (!token)
- return;
-
- // Parse the token.
- var tree;
- if (typeof(token) == 'string')
- tree = this.createParseTree_(token);
- else
- tree = token;
-
- // Obtain the operator token.
- token = tree.value;
-
- // Set suffix options.
- var options = {};
- options.annotation = [];
- options.isUnique = token[token.length - 1] == '=';
- if (options.isUnique)
- token = token.substring(0, token.length - 1);
-
- // Annotate braille output with the corresponding automation nodes
- // to support acting on nodes based on location in the output.
- if (this.formatOptions_.braille)
- options.annotation.push(new Output.NodeSpan(node));
-
- // Process token based on prefix.
- var prefix = token[0];
- token = token.slice(1);
-
- if (opt_exclude[token])
- return;
-
- // All possible tokens based on prefix.
- if (prefix == '$') {
- if (token == 'value') {
- var text = node.value;
- if (text !== undefined) {
- if (node.textSelStart !== undefined) {
- options.annotation.push(new Output.SelectionSpan(
- node.textSelStart,
- node.textSelEnd));
- }
- }
- // Annotate this as a name so we don't duplicate names from ancestors.
- if (node.role == chrome.automation.RoleType.inlineTextBox ||
- node.role == chrome.automation.RoleType.staticText)
- token = 'name';
- options.annotation.push(token);
- this.append_(buff, text, options);
- } else if (token == 'name') {
- options.annotation.push(token);
- if (this.formatOptions_.speech) {
- var earconFinder = node;
- while (earconFinder) {
- var info = Output.ROLE_INFO_[earconFinder.role];
- if (info && info.earconId) {
- options.annotation.push(
- new Output.EarconAction(info.earconId));
- break;
- }
- earconFinder = earconFinder.parent;
- }
- }
-
- // Pending finalization of name calculation; we must use the
- // description property to access aria-label. See crbug.com/473220.
- var resolvedName = node.description || node.name;
- this.append_(buff, resolvedName, options);
- } else if (token == 'nameOrDescendants') {
- options.annotation.push(token);
- if (node.name)
- this.append_(buff, node.name, options);
- else
- this.format_(node, '$descendants', buff);
- } else if (token == 'indexInParent') {
- options.annotation.push(token);
- this.append_(buff, String(node.indexInParent + 1));
- } else if (token == 'parentChildCount') {
- options.annotation.push(token);
- if (node.parent)
- this.append_(buff, String(node.parent.children.length));
- } else if (token == 'state') {
- options.annotation.push(token);
- Object.getOwnPropertyNames(node.state).forEach(function(s) {
- this.append_(buff, s, options);
- }.bind(this));
- } else if (token == 'find') {
- // Find takes two arguments: JSON query string and format string.
- if (tree.firstChild) {
- var jsonQuery = tree.firstChild.value;
- node = node.find(
- /** @type {Object}*/(JSON.parse(jsonQuery)));
- var formatString = tree.firstChild.nextSibling;
- if (node)
- this.format_(node, formatString, buff);
- }
- } else if (token == 'descendants') {
- if (AutomationPredicate.leaf(node))
- return;
-
- // Construct a range to the leftmost and rightmost leaves.
- var leftmost = AutomationUtil.findNodePre(
- node, Dir.FORWARD, AutomationPredicate.leaf);
- var rightmost = AutomationUtil.findNodePre(
- node, Dir.BACKWARD, AutomationPredicate.leaf);
- if (!leftmost || !rightmost)
- return;
-
- var subrange = new cursors.Range(
- new cursors.Cursor(leftmost, 0),
- new cursors.Cursor(rightmost, 0));
- var prev = null;
- if (node)
- prev = cursors.Range.fromNode(node);
- this.range_(subrange, prev, 'navigate', buff);
- } else if (token == 'role') {
- options.annotation.push(token);
- var msg = node.role;
- var info = Output.ROLE_INFO_[node.role];
- if (info) {
- if (this.formatOptions_.braille)
- msg = Msgs.getMsg(info.msgId + '_brl');
- else
- msg = Msgs.getMsg(info.msgId);
- } else {
- console.error('Missing role info for ' + node.role);
- }
- this.append_(buff, msg, options);
- } else if (token == 'inputType') {
- if (!node.inputType)
- return;
- options.annotation.push(token);
- var msgId = Output.INPUT_TYPE_MESSAGE_IDS_[node.inputType] ||
- 'input_type_text';
- if (this.formatOptions_.braille)
- msgId = msgId + '_brl';
- this.append_(buff, Msgs.getMsg(msgId), options);
- } else if (token == 'tableRowIndex' ||
- token == 'tableCellColumnIndex') {
- var value = node[token];
- if (!value)
- return;
- value = String(value + 1);
- options.annotation.push(token);
- this.append_(buff, value, options);
- } else if (node[token] !== undefined) {
- options.annotation.push(token);
- var value = node[token];
- if (typeof value == 'number')
- value = String(value);
- this.append_(buff, value, options);
- } else if (Output.STATE_INFO_[token]) {
- options.annotation.push('state');
- var stateInfo = Output.STATE_INFO_[token];
- var resolvedInfo = {};
- if (node.state[token] === undefined)
- resolvedInfo = stateInfo.omitted;
- else
- resolvedInfo = node.state[token] ? stateInfo.on : stateInfo.off;
- if (!resolvedInfo)
- return;
- if (this.formatOptions_.speech && resolvedInfo.earconId) {
- options.annotation.push(
- new Output.EarconAction(resolvedInfo.earconId));
- }
- var msgId =
- this.formatOptions_.braille ? resolvedInfo.msgId + '_brl' :
- resolvedInfo.msgId;
- var msg = Msgs.getMsg(msgId);
- this.append_(buff, msg, options);
- } else if (tree.firstChild) {
- // Custom functions.
- if (token == 'if') {
- var cond = tree.firstChild;
- var attrib = cond.value.slice(1);
- if (node[attrib] || node.state[attrib])
- this.format_(node, cond.nextSibling, buff);
- else
- this.format_(node, cond.nextSibling.nextSibling, buff);
- } else if (token == 'earcon') {
- // Ignore unless we're generating speech output.
- if (!this.formatOptions_.speech)
- return;
- // Assumes there's existing output in our buffer.
- var lastBuff = buff[buff.length - 1];
- if (!lastBuff)
- return;
-
- lastBuff.setSpan(
- new Output.EarconAction(tree.firstChild.value), 0, 0);
- } else if (token == 'countChildren') {
- var role = tree.firstChild.value;
- var count = node.children.filter(function(e) {
- return e.role == role;
- }).length;
- this.append_(buff, String(count));
- }
- }
- } else if (prefix == '@') {
- var isPluralized = (token[0] == '@');
- if (isPluralized)
- token = token.slice(1);
- // Tokens can have substitutions.
- var pieces = token.split('+');
- token = pieces.reduce(function(prev, cur) {
- var lookup = cur;
- if (cur[0] == '$')
- lookup = node[cur.slice(1)];
- return prev + lookup;
- }.bind(this), '');
- var msgId = token;
- var msgArgs = [];
- if (!isPluralized) {
- var curArg = tree.firstChild;
- while (curArg) {
- if (curArg.value[0] != '$') {
- console.error('Unexpected value: ' + curArg.value);
- return;
- }
- var msgBuff = [];
- this.format_(node, curArg, msgBuff);
- msgArgs = msgArgs.concat(msgBuff);
- curArg = curArg.nextSibling;
- }
- }
- var msg = Msgs.getMsg(msgId, msgArgs);
- try {
- if (this.formatOptions_.braille)
- msg = Msgs.getMsg(msgId + '_brl', msgArgs) || msg;
- } catch(e) {}
-
- if (!msg) {
- console.error('Could not get message ' + msgId);
- return;
- }
-
- if (isPluralized) {
- var arg = tree.firstChild;
- if (!arg || arg.nextSibling) {
- console.error('Pluralized messages take exactly one argument');
- return;
- }
- if (arg.value[0] != '$') {
- console.error('Unexpected value: ' + arg.value);
- return;
- }
- var argBuff = [];
- this.format_(node, arg, argBuff);
- var namedArgs = {COUNT: Number(argBuff[0])};
- msg = new goog.i18n.MessageFormat(msg).format(namedArgs);
- }
-
- this.append_(buff, msg, options);
- } else if (prefix == '!') {
- this.speechProperties_[token] = true;
- }
- }.bind(this));
- },
-
- /**
- * @param {!cursors.Range} range
- * @param {cursors.Range} prevRange
- * @param {chrome.automation.EventType|string} type
- * @param {!Array<cvox.Spannable>} rangeBuff
- * @private
- */
- range_: function(range, prevRange, type, rangeBuff) {
- if (!prevRange)
- prevRange = cursors.Range.fromNode(range.start.node.root);
-
- var cursor = range.start;
- var prevNode = prevRange.start.node;
-
- var formatNodeAndAncestors = function(node, prevNode) {
- var buff = [];
- this.ancestry_(node, prevNode, type, buff);
- this.node_(node, prevNode, type, buff);
- if (this.formatOptions_.location)
- this.locations_.push(node.location);
- return buff;
- }.bind(this);
-
- while (cursor.node != range.end.node) {
- var node = cursor.node;
- rangeBuff.push.apply(rangeBuff, formatNodeAndAncestors(node, prevNode));
- prevNode = node;
- cursor = cursor.move(cursors.Unit.NODE,
- cursors.Movement.DIRECTIONAL,
- Dir.FORWARD);
-
- // Reached a boundary.
- if (cursor.node == prevNode)
- break;
- }
- var lastNode = range.end.node;
- rangeBuff.push.apply(rangeBuff, formatNodeAndAncestors(lastNode, prevNode));
- },
-
- /**
- * @param {!chrome.automation.AutomationNode} node
- * @param {!chrome.automation.AutomationNode} prevNode
- * @param {chrome.automation.EventType|string} type
- * @param {!Array<cvox.Spannable>} buff
- * @param {!Object=} opt_exclude A list of attributes to exclude from
- * processing.
- * @private
- */
- ancestry_: function(node, prevNode, type, buff, opt_exclude) {
- opt_exclude = opt_exclude || {};
- var prevUniqueAncestors =
- AutomationUtil.getUniqueAncestors(node, prevNode);
- var uniqueAncestors = AutomationUtil.getUniqueAncestors(prevNode, node);
-
- // First, look up the event type's format block.
- // Navigate is the default event.
- var eventBlock = Output.RULES[type] || Output.RULES['navigate'];
-
- var getMergedRoleBlock = function(role) {
- var parentRole = (Output.ROLE_INFO_[role] || {}).inherits;
- var roleBlock = eventBlock[role] || eventBlock['default'];
- var parentRoleBlock = parentRole ? eventBlock[parentRole] : {};
- var mergedRoleBlock = {};
- for (var key in parentRoleBlock)
- mergedRoleBlock[key] = parentRoleBlock[key];
- for (var key in roleBlock)
- mergedRoleBlock[key] = roleBlock[key];
- return mergedRoleBlock;
- };
-
- for (var i = 0, formatPrevNode;
- (formatPrevNode = prevUniqueAncestors[i]);
- i++) {
- var roleBlock = getMergedRoleBlock(formatPrevNode.role);
- if (roleBlock.leave)
- this.format_(formatPrevNode, roleBlock.leave, buff, opt_exclude);
- }
-
- var enterOutputs = [];
- var enterRole = {};
- for (var j = uniqueAncestors.length - 2, formatNode;
- (formatNode = uniqueAncestors[j]);
- j--) {
- var roleBlock = getMergedRoleBlock(formatNode.role);
- if (roleBlock.enter) {
- if (enterRole[formatNode.role])
- continue;
- enterRole[formatNode.role] = true;
- var tempBuff = [];
- this.format_(formatNode, roleBlock.enter, tempBuff, opt_exclude);
- enterOutputs.unshift(tempBuff);
- }
- if (formatNode.role == 'window')
- break;
- }
- enterOutputs.forEach(function(b) {
- buff.push.apply(buff, b);
- });
-
- if (!opt_exclude.stay) {
- var commonFormatNode = uniqueAncestors[0];
- while (commonFormatNode && commonFormatNode.parent) {
- commonFormatNode = commonFormatNode.parent;
- var roleBlock =
- eventBlock[commonFormatNode.role] || eventBlock['default'];
- if (roleBlock.stay)
- this.format_(commonFormatNode, roleBlock.stay, buff, opt_exclude);
- }
- }
- },
-
- /**
- * @param {!chrome.automation.AutomationNode} node
- * @param {!chrome.automation.AutomationNode} prevNode
- * @param {chrome.automation.EventType|string} type
- * @param {!Array<cvox.Spannable>} buff
- * @private
- */
- node_: function(node, prevNode, type, buff) {
- // Navigate is the default event.
- var eventBlock = Output.RULES[type] || Output.RULES['navigate'];
- var roleBlock = eventBlock[node.role] || eventBlock['default'];
- var speakFormat = roleBlock.speak || eventBlock['default'].speak;
- this.format_(node, speakFormat, buff);
- },
-
- /**
- * @param {!cursors.Range} range
- * @param {cursors.Range} prevRange
- * @param {chrome.automation.EventType|string} type
- * @param {!Array<cvox.Spannable>} buff
- * @private
- */
- subNode_: function(range, prevRange, type, buff) {
- if (!prevRange)
- prevRange = range;
- var dir = cursors.Range.getDirection(prevRange, range);
- var prevNode = prevRange.getBound(dir).node;
- this.ancestry_(
- range.start.node, prevNode, type, buff,
- {stay: true, name: true, value: true});
- var startIndex = range.start.getIndex();
- var endIndex = range.end.getIndex();
- if (startIndex === endIndex)
- endIndex++;
- this.append_(
- buff, range.start.getText().substring(startIndex, endIndex));
- },
-
- /**
- * Appends output to the |buff|.
- * @param {!Array<cvox.Spannable>} buff
- * @param {string|!cvox.Spannable} value
- * @param {{isUnique: (boolean|undefined),
- * annotation: !Array<*>}=} opt_options
- */
- append_: function(buff, value, opt_options) {
- opt_options = opt_options || {isUnique: false, annotation: []};
-
- // Reject empty values without annotations.
- if ((!value || value.length == 0) && opt_options.annotation.length == 0)
- return;
-
- var spannableToAdd = new cvox.Spannable(value);
- opt_options.annotation.forEach(function(a) {
- spannableToAdd.setSpan(a, 0, spannableToAdd.getLength());
- });
-
- // |isUnique| specifies an annotation that cannot be duplicated.
- if (opt_options.isUnique) {
- var annotationSansNodes = opt_options.annotation.filter(
- function(annotation) {
- return !(annotation instanceof Output.NodeSpan);
- });
- var alreadyAnnotated = buff.some(function(s) {
- return annotationSansNodes.some(function(annotation) {
- var start = s.getSpanStart(annotation);
- var end = s.getSpanEnd(annotation);
- if (start === undefined)
- return false;
- return s.substring(start, end).toString() == value.toString();
- });
- });
- if (alreadyAnnotated)
- return;
- }
-
- buff.push(spannableToAdd);
- },
-
- /**
- * Parses the token containing a custom function and returns a tree.
- * @param {string} inputStr
- * @return {Object}
- * @private
- */
- createParseTree_: function(inputStr) {
- var root = {value: ''};
- var currentNode = root;
- var index = 0;
- var braceNesting = 0;
- while (index < inputStr.length) {
- if (inputStr[index] == '(') {
- currentNode.firstChild = {value: ''};
- currentNode.firstChild.parent = currentNode;
- currentNode = currentNode.firstChild;
- } else if (inputStr[index] == ')') {
- currentNode = currentNode.parent;
- } else if (inputStr[index] == '{') {
- braceNesting++;
- currentNode.value += inputStr[index];
- } else if (inputStr[index] == '}') {
- braceNesting--;
- currentNode.value += inputStr[index];
- } else if (inputStr[index] == ',' && braceNesting === 0) {
- currentNode.nextSibling = {value: ''};
- currentNode.nextSibling.parent = currentNode.parent;
- currentNode = currentNode.nextSibling;
- } else {
- currentNode.value += inputStr[index];
- }
- index++;
- }
-
- if (currentNode != root)
- throw 'Unbalanced parenthesis.';
-
- return root;
- },
-
- /**
- * Converts the currently rendered braille buffers to a single spannable.
- * @return {!cvox.Spannable}
- * @private
- */
- createBrailleOutput_: function() {
- var result = new cvox.Spannable();
- var separator = ''; // Changes to space as appropriate.
- this.brailleBuffer_.forEach(function(cur) {
- // If this chunk is empty, don't add it since it won't result
- // in any output on the braille display, but node spans would
- // start before the separator in that case, which is not desired.
- // The exception is if this chunk contains a selectionm, in which
- // case it will result in a cursor which has to be preserved.
- // In this case, having separators, potentially both before and after
- // the empty string is correct.
- if (cur.getLength() == 0 && !cur.getSpanInstanceOf(Output.SelectionSpan))
- return;
- var spansToExtend = [];
- var spansToRemove = [];
- // Nodes that have node spans both on the character to the left
- // of the separator and to the right should also cover the separator.
- // We extend the left span to cover both the separator and what the
- // right span used to cover, removing the right span, mostly for
- // ease of writing tests and debug.
- // Note that getSpan(position) never returns zero length spans
- // (because they don't cover any position). Still, we want to include
- // these because they can be included (the selection span in an empty
- // text field is an example), which is why we write the below code
- // using getSpansInstanceOf and check the endpoints (isntead of doing
- // the opposite).
- result.getSpansInstanceOf(Output.NodeSpan).forEach(function(leftSpan) {
- if (result.getSpanEnd(leftSpan) < result.getLength())
- return;
- var newEnd = result.getLength();
- cur.getSpansInstanceOf(Output.NodeSpan).forEach(function(rightSpan) {
- if (cur.getSpanStart(rightSpan) == 0 &&
- leftSpan.node === rightSpan.node) {
- newEnd = Math.max(
- newEnd,
- result.getLength() + separator.length +
- cur.getSpanEnd(rightSpan));
- spansToRemove.push(rightSpan);
- }
- });
- if (newEnd > result.getLength())
- spansToExtend.push({span: leftSpan, end: newEnd});
- });
- result.append(separator);
- result.append(cur);
- spansToExtend.forEach(function(elem) {
- result.setSpan(
- elem.span,
- // Cast ok, since span is known to exist.
- /** @type {number} */ (result.getSpanStart(elem.span)),
- elem.end);
- });
- spansToRemove.forEach(result.removeSpan.bind(result));
- separator = Output.SPACE;
- });
- return result;
- }
-};
-
-}); // goog.scope
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs b/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
deleted file mode 100644
index ad642ed0e50..00000000000
--- a/chromium/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
+++ /dev/null
@@ -1,545 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-GEN_INCLUDE(['../../testing/assert_additions.js']);
-GEN_INCLUDE(['../../testing/chromevox_next_e2e_test_base.js']);
-
-/**
- * Gets the braille output and asserts that it matches expected values.
- * Annotations in the output that are primitive strings are ignored.
- */
-function checkBrailleOutput(expectedText, expectedSpans, output) {
- var actualOutput = output.brailleOutputForTest;
- // Remove string annotations. These are tested in the speech output and
- // there's no need to clutter the tests with the corresponding braille
- // annotations.
- var actualSpans = actualOutput.spans_.filter(function(span) {
- return (typeof span.value !== 'string');
- });
- assertEquals(expectedText, actualOutput.toString());
-
- function describeSpan(span) {
- var obj = {value: span.value, start: span.start, end: span.end};
- if (obj.value instanceof Output.NodeSpan) {
- obj.value.node = (obj.value.node.name || '') + ' ' +
- obj.value.node.toString();
- }
- return JSON.stringify(obj);
- }
-
- function describeActualSpans() {
- return '\nAll actual spans:\n' + actualSpans.map(describeSpan).join('\n');
- }
-
- for (var i = 0, max = Math.max(expectedSpans.length, actualSpans.length);
- i < max; ++i) {
- var expectedSpan = expectedSpans[i];
- var actualSpan = actualSpans[i];
- if (!expectedSpan)
- throw Error('Unexpected span in ' + expectedText + ': ' +
- describeSpan(actualSpan) + describeActualSpans());
- if (!actualSpan)
- throw Error('Missing expected span in ' + expectedText + ': ' +
- describeSpan(expectedSpan) + describeActualSpans());
- var equal = true;
- if (expectedSpan.start !== actualSpan.start ||
- expectedSpan.end !== actualSpan.end) {
- equal = false;
- } else if (expectedSpan.value instanceof Output.NodeSpan &&
- (!(actualSpan.value instanceof Output.NodeSpan) ||
- expectedSpan.value.node !== actualSpan.value.node)) {
- equal = false;
- } else {
- equal = (JSON.stringify(expectedSpan.value) ===
- JSON.stringify(actualSpan.value));
- }
- if (!equal) {
- throw Error('Spans differ in ' + expectedText + ':\n' +
- 'Expected: ' + describeSpan(expectedSpan) + '\n' +
- 'Got : ' + describeSpan(actualSpan) + describeActualSpans());
- }
- }
-}
-
-/**
- * Test fixture for output.js.
- * @constructor
- * @extends {ChromeVoxNextE2ETestBase}
- */
-function OutputE2ETest() {
- ChromeVoxNextE2ETest.call(this);
-}
-
-OutputE2ETest.prototype = {
- __proto__: ChromeVoxNextE2ETest.prototype,
-
- /** @override */
- setUp: function() {
- window.Dir = AutomationUtil.Dir;
- }
-};
-
-TEST_F('OutputE2ETest', 'Links', function() {
- this.runWithLoadedTree('<a href="#">Click here</a>',
- function(root) {
- var el = root.firstChild.firstChild;
- var range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, null, 'navigate');
- assertEqualsJSON({string_: 'Click here|Link', 'spans_': [
- // Attributes.
- {value: 'name', start: 0, end: 10},
-
- // Link earcon (based on the name).
- {value: {earconId: 'LINK'}, start: 0, end: 10},
-
- {value: 'role', start: 11, end: 15}
- ]}, o.speechOutputForTest);
- checkBrailleOutput(
- 'Click here lnk',
- [{value: new Output.NodeSpan(el), start: 0, end: 14}],
- o);
- });
-});
-
-TEST_F('OutputE2ETest', 'Checkbox', function() {
- this.runWithLoadedTree('<input type="checkbox">',
- function(root) {
- var el = root.firstChild.firstChild;
- var range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, null, 'navigate');
- assertEqualsJSON({string_: '|Check box|not checked', 'spans_': [
- // Attributes.
- {value: 'name', start: 0, end: 0},
- {value: 'role', start: 1, end: 10},
- {value: 'state', start: 11, end: 22},
-
- // Checkbox earcon (based on the state).
- {value: {earconId: 'CHECK_OFF'}, start: 11, end: 22}
- ]}, o.speechOutputForTest);
- checkBrailleOutput(
- 'chk ( )',
- [{value: new Output.NodeSpan(el), start: 0, end: 7}],
- o);
- });
-});
-
-TEST_F('OutputE2ETest', 'InLineTextBoxValueGetsIgnored', function() {
- this.runWithLoadedTree('<p>OK',
- function(root) {
- var el = root.firstChild.firstChild.firstChild;
- assertEquals('inlineTextBox', el.role);
- var range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, null, 'navigate');
- assertEqualsJSON({string_: 'OK', 'spans_': [
- // Attributes.
- {value: 'name', start: 0, end: 2}
- ]}, o.speechOutputForTest);
- checkBrailleOutput(
- 'OK',
- [{value: new Output.NodeSpan(el), start: 0, end: 2}],
- o);
-
- el = root.firstChild.firstChild;
- assertEquals('staticText', el.role);
- range = cursors.Range.fromNode(el);
- o = new Output().withSpeechAndBraille(range, null, 'navigate');
- assertEqualsJSON({string_: 'OK', 'spans_': [
- // Attributes.
- {value: 'name', start: 0, end: 2}
- ]}, o.speechOutputForTest);
- checkBrailleOutput(
- 'OK',
- [{value: new Output.NodeSpan(el), start: 0, end: 2}],
- o);
- });
-});
-
-TEST_F('OutputE2ETest', 'Headings', function() {
- this.runWithLoadedTree(function() {/*!
- <h1>a</h1><h2>b</h2><h3>c</h3><h4>d</h4><h5>e</h5><h6>f</h6>
- <h1><a href="a.com">b</a></h1> */},
- function(root) {
- var el = root.firstChild;
- for (var i = 1; i <= 6; ++i) {
- var range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, null, 'navigate');
- var letter = String.fromCharCode('a'.charCodeAt(0) + i -1);
- assertEqualsJSON({string_: 'Heading ' + i + '|' + letter, 'spans_': [
- // Attributes.
- {value: 'nameOrDescendants', start: 10, end: 11}
- ]}, o.speechOutputForTest);
- checkBrailleOutput(
- 'h' + i + ' ' + letter,
- [{value: new Output.NodeSpan(el), start: 0, end: 4}],
- o);
- el = el.nextSibling;
- }
-
- range = cursors.Range.fromNode(el);
- o = new Output().withSpeechAndBraille(range, null, 'navigate');
- assertEqualsJSON({string_: 'Heading 1|b|Link', 'spans_': [
- // Link.
- {value: 'name', start: 10, end: 11},
- {value: {earconId: "LINK"}, start: 10, end: 11},
- {value: 'role', start: 12, end: 16}
- ]}, o.speechOutputForTest);
- checkBrailleOutput(
- 'h1 b lnk',
- [{value: new Output.NodeSpan(el), start: 0, end: 2},
- {value: new Output.NodeSpan(el.firstChild), start: 3, end: 8}],
- o);
- });
-});
-
-TEST_F('OutputE2ETest', 'Audio', function() {
- this.runWithLoadedTree('<audio src="foo.mp3" controls></audio>',
- function(root) {
- var el = root.firstChild.firstChild.firstChild.firstChild;
- var range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, null, 'navigate');
- assertEqualsJSON(
- {string_: 'audio|Tool bar|play||begin playback|Button',
- spans_:
- // Entered container toolbar.
-
- // Button.
- [{value: 'name', start: 15, end: 19},
-
- // Button earcon.
- {value: {earconId: "BUTTON"}, start: 15, end: 19},
-
- {value: 'value', start: 20, end: 20},
- {value: 'help', start: 21, end: 35},
- {value: 'role', start: 36, end: 42}]
- }, o.speechOutputForTest);
- checkBrailleOutput(
- 'audio tlbar play begin playback btn',
- [{value: new Output.NodeSpan(el.parent), start: 0, end: 11},
- {value: new Output.NodeSpan(el), start: 12, end: 35}],
- o);
-
- el = el.nextSibling;
- var prevRange = range;
- range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, prevRange, 'navigate');
- assertEqualsJSON({string_: '0, , slider|audio time scrubber',
- spans_:
- [{value: 'help', start: 12, end: 31}]
- }, o.speechOutputForTest);
- // TODO(plundblad): Investigate this.
- checkBrailleOutput(
- '0, , slider audio time scrubber',
- [{value: new Output.NodeSpan(el), start: 0, end: 31}],
- o);
- });
-});
-
-TEST_F('OutputE2ETest', 'Input', function() {
- this.runWithLoadedTree(
- '<input type="text"></input>' +
- '<input type="email"></input>' +
- '<input type="password"></input>' +
- '<input type="tel"></input>' +
- '<input type="number"></input>' +
- '<input type="time"></input>' +
- '<input type="date"></input>' +
- '<input type="file"</input>' +
- '<input type="search"</input>' +
- '<input type="invalidType"</input>',
- function(root) {
- var expected = {string_: '', 'spans_': [
- {value: 'name', start: 0, end: 0},
-
- // Earcon
- {value: {earconId: 'EDITABLE_TEXT'}, start: 0, end: 0},
-
- // Selection span.
- {value: {startIndex: 0, endIndex: 0}, start: 1, end: 1},
-
- {value: 'value', start: 1, end: 1},
- {value: 'inputType', start: 2}
- ]};
-
- var expectedSpeechValues = [
- '||Edit text',
- '||Edit text, email entry',
- '||Password edit text',
- '||Edit text numeric only',
- {string_: '||Spin button', spans_: [{value: 'name', start: 0, end: 0},
- {value: {earconId:'LISTBOX'}, start: 0, end: 0},
- {value: {startIndex: 0, endIndex: 0}, start: 1, end: 1},
- {value: 'value', start: 1, end: 1},
- {value: 'role', start: 2, end: 13}]},
- {string_: '||Time control', spans_: [{value: 'name', start: 0, end: 0},
- {value: 'value', start: 1, end: 1},
- {value: 'role', start: 2, end: 14}]},
- {string_: '||Date control', spans_: [{value: 'name', start: 0, end: 0},
- {value: 'value', start: 1, end: 1},
- {value: 'role', start: 2, end: 14}]},
- {string_: 'Choose File|No file chosen|Button',
- spans_: [{value: 'name', start: 0, end: 11},
- {value: {earconId: "BUTTON"}, start: 0, end: 11},
- {value: 'value', start: 12, end: 26},
- {value: 'role', start: 27, end: 33}]},
- '||Edit text, search entry',
- '||Edit text'
- ];
- // TODO(plundblad): Some of these are wrong, there should be an initial
- // space for the cursor in edit fields.
- var expectedBrailleValues = [
- ' ed',
- ' @ed',
- ' pwded',
- ' #ed',
- ' spnbtn',
- {string_: 'time'},
- {string_: 'date'},
- {string_: 'Choose File No file chosen btn'},
- ' srched',
- ' ed'
- ];
- assertEquals(expectedSpeechValues.length, expectedBrailleValues.length);
-
- var el = root.firstChild.firstChild;
- expectedSpeechValues.forEach(function(expectedValue) {
- var range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, null, 'navigate');
- if (typeof expectedValue == 'object') {
- assertEqualsJSON(expectedValue, o.speechOutputForTest);
- } else {
- expected.string_ = expectedValue;
- expected.spans_[4].end = expectedValue.length;
- assertEqualsJSON(expected, o.speechOutputForTest);
- }
- el = el.nextSibling;
- });
-
- el = root.firstChild.firstChild;
- expectedBrailleValues.forEach(function(expectedValue) {
- var range = cursors.Range.fromNode(el);
- var o = new Output().withBraille(range, null, 'navigate');
- if (typeof expectedValue === 'string') {
- checkBrailleOutput(
- expectedValue,
- [{value: {startIndex: 0, endIndex: 0}, start: 0, end: 0},
- {value: new Output.NodeSpan(el), start: 0,
- end: expectedValue.length}],
- o);
- } else {
- checkBrailleOutput(
- expectedValue.string_,
- [{value: new Output.NodeSpan(el), start: 0,
- end: expectedValue.string_.length}],
- o);
- }
- el = el.nextSibling;
- });
- });
-});
-
-TEST_F('OutputE2ETest', 'List', function() {
- this.runWithLoadedTree(
- '<ul><li>a<li>b<li>c</ul>',
- function(root) {
- var el = root.firstChild.firstChild;
- var range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, null, 'navigate');
- assertEqualsJSON({string_: 'list|with 3 items|a||List item', spans_: [
- {value: 'name', start: 18, end: 19},
- {value: {earconId:'LIST_ITEM'}, start: 18, end: 19},
- {value: 'value', start:20, end: 20},
- {value: 'role', start: 21, end: 30}
- ]}, o.speechOutputForTest);
- // TODO(plundblad): This output is wrong. Add special handling for
- // braille here.
- checkBrailleOutput(
- 'list +3 a lstitm',
- [{value: new Output.NodeSpan(el.parent), start: 0, end: 7},
- {value: new Output.NodeSpan(el), start: 8, end: 16}],
- o);
- });
-});
-
-TEST_F('OutputE2ETest', 'Tree', function() {
- this.runWithLoadedTree(function() {/*!
- <ul role="tree">
- <li aria-expanded="true" role="treeitem">a
- <li role="treeitem">b
- <li aria-expanded="false" role="treeitem">c
- </ul>
- */},
- function(root) {
- var el = root.firstChild.children[0].firstChild;
- var range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, null, 'navigate');
- assertEqualsJSON(
- {string_: '|Tree|with 3 items|Tree item|Expanded| 1 of 3 | level 1 |a',
- spans_: [
- // Enter rule.
-
- // TreeItem.
- {value: 'role','start': 19, end: 28},
- {value: 'state', start: 29, end: 37},
-
- // InLineTextBox.
- {value: 'name', start: 57, end: 58}
- ]}, o.speechOutputForTest);
- // TODO(plundblad): Braille output is wrong.
- checkBrailleOutput(
- 'tree +3 tritm - 1/3 level 1 a',
- [{value: new Output.NodeSpan(el.parent.parent), start: 0, end: 7},
- {value: new Output.NodeSpan(el.parent), start: 8, end: 29},
- {value: new Output.NodeSpan(el), start: 30, end: 31}],
- o);
-
- el = root.firstChild.children[1].firstChild;
- var range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, null, 'navigate');
- assertEqualsJSON(
- {string_: '|Tree|with 3 items|Tree item| 2 of 3 | level 1 |b',
- spans_: [
- // Enter rule.
-
- // TreeItem.
- {value: 'role','start': 19, end: 28},
-
- // InLineTextBox.
- {value: 'name', start: 48, end: 49}
- ]}, o.speechOutputForTest);
- // TODO(plundblad): Braille output is wrong.
- checkBrailleOutput(
- 'tree +3 tritm 2/3 level 1 b',
- [{value: new Output.NodeSpan(el.parent.parent), start: 0, end: 7},
- {value: new Output.NodeSpan(el.parent), start: 8, end: 27},
- {value: new Output.NodeSpan(el), start: 28, end: 29}],
- o);
-
- el = root.firstChild.children[2].firstChild;
- var range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, null, 'navigate');
- assertEqualsJSON(
- {string_: '|Tree|with 3 items|Tree item|Collapsed| 3 of 3 | level 1 |c',
- spans_: [
- // Enter rule.
-
- // TreeItem.
- {value: 'role','start': 19, end: 28},
- {value: 'state', start: 29, end: 38},
-
- // InLineTextBox.
- {value: 'name', start: 58, end: 59}
- ]}, o.speechOutputForTest);
- // TODO(plundblad): Braille output is wrong.
- checkBrailleOutput(
- 'tree +3 tritm + 3/3 level 1 c',
- [{value: new Output.NodeSpan(el.parent.parent), start: 0, end: 7},
- {value: new Output.NodeSpan(el.parent), start: 8, end: 29},
- {value: new Output.NodeSpan(el), start: 30, end: 31}],
- o);
- });
-});
-
-TEST_F('OutputE2ETest', 'Menu', function() {
- this.runWithLoadedTree(function() {/*!
- <div role="menu">
- <div role="menuitem">a</div>
- </div>
- */},
- function(root) {
- var el = root.firstChild.firstChild;
- var range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, null, 'navigate');
- assertEqualsJSON({string_:
- '|Menu|with 1 item|a|Menu item| 1 of 1 ', spans_: [
- {value: 'name', start: 18, end: 19},
- {value: 'role', start:20, end: 29}
- ]}, o.speechOutputForTest);
- checkBrailleOutput(
- 'mnu +1 a mnuitm 1/1',
- [{value: new Output.NodeSpan(el.parent), start: 0, end: 6},
- {value: new Output.NodeSpan(el), start: 7, end: 19}],
- o);
- });
-});
-
-TEST_F('OutputE2ETest', 'ListBox', function() {
- this.runWithLoadedTree(function() {/*!
- <select multiple>
- <option>1</option>
- <option>2</option>
- </select>
- */},
- function(root) {
- var el = root.firstChild.firstChild.firstChild;
- var range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, null, 'navigate');
- assertEqualsJSON({string_: '|List box|with 2 items||List item| 1 of 2 ',
- spans_: [
- // ListBox.
- // Earcon.
- {value: {earconId:'LISTBOX'}, start: 0, end: 0},
-
- {value: 'name', start: 23, end: 23},
-
- // Earcon.
- {value: {earconId: 'LIST_ITEM'}, start: 23, end: 23},
-
- {value: 'role', start:24, end: 33}
- ]}, o.speechOutputForTest);
- checkBrailleOutput(
- 'lstbx +2 lstitm 1/2',
- [{value: new Output.NodeSpan(el.parent), start: 0, end: 8},
- {value: new Output.NodeSpan(el), start: 9, end: 19}],
- o);
- });
-});
-
-SYNC_TEST_F('OutputE2ETest', 'MessageIdAndEarconValidity', function() {
- for (var key in Output.ROLE_INFO_) {
- var value = Output.ROLE_INFO_[key];
- Msgs.getMsg(value.msgId);
- Msgs.getMsg(value.msgId + '_brl');
- assertFalse(/[A-Z]+/.test(value.msgId));
- if (value.earconId)
- assertNotNullNorUndefined(cvox.Earcon[value.earconId]);
- }
- for (var key in Output.STATE_INFO_) {
- var value = Output.STATE_INFO_[key];
- for (innerKey in value) {
- var innerValue = value[innerKey];
- Msgs.getMsg(innerValue.msgId);
- Msgs.getMsg(innerValue.msgId + '_brl');
- assertFalse(/[A-Z]+/.test(innerValue.msgId));
- if (innerValue.earconId)
- assertNotNullNorUndefined(cvox.Earcon[innerValue.earconId]);
- }
- }
- for (var key in Output.INPUT_TYPE_MESSAGE_IDS_) {
- var msgId = Output.INPUT_TYPE_MESSAGE_IDS_[key];
- assertFalse(/[A-Z]+/.test(msgId));
- Msgs.getMsg(msgId);
- Msgs.getMsg(msgId + '_brl');
- }
-});
-
-TEST_F('OutputE2ETest', 'DivOmitsRole', function() {
- this.runWithLoadedTree(function() {/*!
- <div>that has content</div>
- <div></div>
- <div role='group'><div>nested content</div></div>
- */},
- function(root) {
- var el = root.firstChild.firstChild;
- var range = cursors.Range.fromNode(el);
- var o = new Output().withSpeechAndBraille(range, null, 'navigate');
- assertEqualsJSON({string_: '|that has content',
- spans_: [
- {value: 'name', start: 1, end: 17}
- ]}, o.speechOutputForTest);
- checkBrailleOutput(
- 'that has content',
- [{value: new Output.NodeSpan(el), start: 0, end: 16}],
- o);
- });
-});