Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2197)

Unified Diff: chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js

Issue 2007183002: Make ChromeVox cursor robust to deleted nodes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
index 35ebe6d51e6f4d4b780e740c7467e6789561f31a..b0ec3b35c1a9dd94a93708ab00fd0f71b364cdfa 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
@@ -71,10 +71,17 @@ var Unit = cursors.Unit;
* 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;
+ /** @type {Array<AutomationNode>} @private */
+ this.ancestry_ = [];
+ var nodeWalker = node;
+ while (nodeWalker) {
+ this.ancestry_.push(nodeWalker);
+ nodeWalker = nodeWalker.parent;
+ if (nodeWalker == node.root)
+ break;
+ }
};
/**
@@ -93,15 +100,24 @@ cursors.Cursor.prototype = {
* @return {boolean}
*/
equals: function(rhs) {
- return this.node_ === rhs.node &&
- this.index_ === rhs.index;
+ return this.node === rhs.node &&
+ this.index === rhs.index;
},
/**
- * @return {!AutomationNode}
+ * Returns the node. If the node is invalid since the last time it
+ * was accessed, moves the cursor to the nearest valid ancestor first.
+ * @return {?AutomationNode}
David Tseng 2016/05/25 20:58:10 You don't need the '?' (objects are nullable by de
dmazzoni 2016/06/01 16:36:50 Done.
*/
get node() {
- return this.node_;
+ for (var index = 0; index < this.ancestry_.length; index++) {
David Tseng 2016/05/25 20:58:10 The dual use of index here is confusing. Maybe use
dmazzoni 2016/06/01 16:36:50 Fixed, but the Closure compiler doesn't let us use
+ var foo = this.ancestry_[index];
David Tseng 2016/05/25 20:58:10 How about firstValidNode?
dmazzoni 2016/06/01 16:36:50 Acknowledged.
+ if (foo != null && foo.role !== undefined)
David Tseng 2016/05/25 20:58:10 This won't work. There are nodes that have a role
dmazzoni 2016/06/01 16:36:50 Done.
+ return foo;
David Tseng 2016/05/25 20:58:10 Do you need to do bookkeeping on the ancestry chai
dmazzoni 2016/06/01 16:36:50 I don't think so, because this object is basically
+ // If we have to walk up to an ancestor, reset the index to zero.
+ this.index_ = 0;
David Tseng 2016/05/25 20:58:10 Reset to cursors.NODE_INDEX
dmazzoni 2016/06/01 16:36:50 Thanks, that made it work better.
+ }
+ return null;
},
/**
@@ -141,7 +157,7 @@ cursors.Cursor.prototype = {
* @return {string}
*/
getText: function(opt_node) {
- var node = opt_node || this.node_;
+ var node = opt_node || this.node;
if (node.role === RoleType.textField)
return node.value;
return node.name || '';
@@ -156,7 +172,11 @@ cursors.Cursor.prototype = {
* @return {!cursors.Cursor} The moved cursor.
*/
move: function(unit, movement, dir) {
- var newNode = this.node_;
+ var originalNode = this.node;
+ if (!originalNode)
+ return this;
+
+ var newNode = originalNode;
var newIndex = this.index_;
if ((unit != Unit.NODE || unit != Unit.DOM_NODE) &&
@@ -257,7 +277,7 @@ cursors.Cursor.prototype = {
var pred = unit == Unit.NODE ?
AutomationPredicate.leaf : AutomationPredicate.element;
newNode = AutomationUtil.findNextNode(
- newNode, dir, pred) || this.node_;
+ newNode, dir, pred) || originalNode;
newIndex = cursors.NODE_INDEX;
break;
}
@@ -268,7 +288,7 @@ cursors.Cursor.prototype = {
case Movement.BOUND:
newNode = AutomationUtil.findNodeUntil(newNode, dir,
AutomationPredicate.linebreak, true);
- newNode = newNode || this.node_;
+ newNode = newNode || originalNode;
newIndex =
dir == Dir.FORWARD ? this.getText(newNode).length : 0;
break;
@@ -281,7 +301,7 @@ cursors.Cursor.prototype = {
default:
throw Error('Unrecognized unit: ' + unit);
}
- newNode = newNode || this.node_;
+ newNode = newNode || originalNode;
newIndex = goog.isDef(newIndex) ? newIndex : this.index_;
return new cursors.Cursor(newNode, newIndex);
},
@@ -324,6 +344,8 @@ cursors.WrappingCursor.prototype = {
/** @override */
move: function(unit, movement, dir) {
var result = this;
+ if (!result.node)
+ return this;
// Regular movement.
if (!AutomationUtil.isTraversalRoot(this.node) || dir == Dir.FORWARD)
@@ -339,6 +361,8 @@ cursors.WrappingCursor.prototype = {
var pred = unit == Unit.DOM_NODE ?
AutomationPredicate.element : AutomationPredicate.leaf;
var endpoint = this.node;
+ if (!endpoint)
+ return this;
// Case 1: forwards (find the root-like node).
while (!AutomationUtil.isTraversalRoot(endpoint) && endpoint.parent)
@@ -392,6 +416,10 @@ cursors.Range.getDirection = function(rangeA, rangeB) {
if (!rangeA || !rangeB)
return Dir.FORWARD;
+ if (!rangeA.start.node || !rangeA.end.node ||
+ !rangeB.start.node || !rangeB.end.node)
+ return Dir.FORWARD;
+
// They are the same range.
if (rangeA.start.node === rangeB.start.node &&
rangeB.end.node === rangeA.end.node)
@@ -471,6 +499,9 @@ cursors.Range.prototype = {
*/
move: function(unit, dir) {
var newStart = this.start_;
+ if (!newStart.node)
+ return this;
+
var newEnd;
switch (unit) {
case Unit.CHARACTER:
@@ -504,6 +535,9 @@ cursors.Range.prototype = {
var start = this.start.node;
var end = this.end.node;
+ if (!start || !end)
+ return;
+
// Find the most common root.
var uniqueAncestors = AutomationUtil.getUniqueAncestors(start, end);
var mcr = start.root;

Powered by Google App Engine
This is Rietveld 408576698