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

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

Issue 2945703002: add support for rich text selections (Closed)
Patch Set: Address comments. Created 3 years, 6 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
« no previous file with comments | « no previous file | chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
index c18ebb4fc4d148cf2ac9e7dacb6c445495e47f46..4a729cbc796c57e6e57fc24d73607204c2235fb2 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
@@ -215,11 +215,15 @@ function AutomationRichEditableText(node) {
AutomationEditableText.call(this, node);
var root = this.node_.root;
- if (!root || !root.anchorObject || !root.focusObject)
+ if (!root || !root.anchorObject || !root.focusObject ||
+ root.anchorOffset === undefined || root.focusOffset === undefined)
return;
- this.line_ = new editing.EditableLine(
- root.anchorObject, root.anchorOffset, root.focusObject, root.focusOffset);
+ this.anchorLine_ = new editing.EditableLine(
+ root.anchorObject, root.anchorOffset, root.anchorObject,
+ root.anchorOffset);
+ this.focusLine_ = new editing.EditableLine(
+ root.focusObject, root.focusOffset, root.focusObject, root.focusOffset);
}
AutomationRichEditableText.prototype = {
@@ -228,19 +232,38 @@ AutomationRichEditableText.prototype = {
/** @override */
onUpdate: function() {
var root = this.node_.root;
- if (!root.anchorObject || !root.focusObject)
+ if (!root.anchorObject || !root.focusObject ||
+ root.anchorOffset === undefined || root.focusOffset === undefined)
return;
+ var anchorLine = new editing.EditableLine(
+ root.anchorObject, root.anchorOffset, root.anchorObject,
+ root.anchorOffset);
+ var focusLine = new editing.EditableLine(
+ root.focusObject, root.focusOffset, root.focusObject, root.focusOffset);
+
+ var prevAnchorLine = this.anchorLine_;
+ var prevFocusLine = this.focusLine_;
+ this.anchorLine_ = anchorLine;
+ this.focusLine_ = focusLine;
+
+ // Compute the current line based upon whether the current selection was
+ // extended from anchor or focus. The default behavior is to compute lines
+ // via focus.
+ var baseLineOnStart = prevFocusLine.isSameLineAndSelection(focusLine);
+
var cur = new editing.EditableLine(
- root.anchorObject, root.anchorOffset || 0, root.focusObject,
- root.focusOffset || 0);
+ root.anchorObject, root.anchorOffset, root.focusObject,
+ root.focusOffset, baseLineOnStart);
var prev = this.line_;
this.line_ = cur;
- if (prev.equals(cur)) {
- // Collapsed cursor.
+ // Selection stayed within the same line(s) and didn't cross into new lines.
+ if (anchorLine.isSameLine(prevAnchorLine) &&
+ focusLine.isSameLine(prevFocusLine)) {
+ // Intra-line changes.
this.changed(new cvox.TextChangeEvent(
- cur.text || '', cur.startOffset || 0, cur.endOffset || 0, true));
+ cur.text || '', cur.startOffset, cur.endOffset, true));
this.brailleCurrentRichLine_();
// Finally, queue up any text markers/styles at bounds.
@@ -283,9 +306,20 @@ AutomationRichEditableText.prototype = {
return;
}
- // Just output the current line.
- cvox.ChromeVox.tts.speak(cur.text, cvox.QueueMode.CATEGORY_FLUSH);
- this.brailleCurrentRichLine_();
+ if (cur.text == '') {
+ // This line has no text content. Describe the DOM selection.
+ new Output()
+ .withRichSpeechAndBraille(
+ new Range(cur.start_, cur.end_),
+ new Range(prev.start_, prev.end_), Output.EventType.NAVIGATE)
+ .go();
+ } else {
+ // Describe the current line. This accounts for previous/current
+ // selections and picking the line edge boundary that changed (as computed
+ // above). This is also the code path for describing paste.
+ cvox.ChromeVox.tts.speak(cur.text, cvox.QueueMode.CATEGORY_FLUSH);
+ this.brailleCurrentRichLine_();
+ }
// The state in EditableTextBase needs to get updated with the new line
// contents, so that subsequent intra-line changes get the right state
@@ -441,9 +475,19 @@ editing.observer_ = new editing.EditingChromeVoxStateObserver();
/**
* An EditableLine encapsulates all data concerning a line in the automation
* tree necessary to provide output.
+ * Editable: an editable selection (e.g. start/end offsets) get saved.
+ * Line: nodes/offsets at the beginning/end of a line get saved.
+ * @param {!AutomationNode} startNode
+ * @param {number} startIndex
+ * @param {!AutomationNode} endNode
+ * @param {number} endIndex
+ * @param {boolean=} opt_baseLineOnStart Controls whether to use anchor or
+ * focus for Line computations as described above. Selections are automatically
+ * truncated up to either the line start or end.
* @constructor
*/
-editing.EditableLine = function(startNode, startIndex, endNode, endIndex) {
+editing.EditableLine = function(
+ startNode, startIndex, endNode, endIndex, opt_baseLineOnStart) {
/** @private {!Cursor} */
this.start_ = new Cursor(startNode, startIndex);
this.start_ = this.start_.deepEquivalent || this.start_;
@@ -467,29 +511,41 @@ editing.EditableLine = function(startNode, startIndex, endNode, endIndex) {
this.lineStartContainer_;
/** @private {number} */
this.localLineStartContainerOffset_ = 0;
+ /** @private {AutomationNode|undefined} */
+ this.lineEndContainer_;
+ /** @private {number} */
+ this.localLineEndContainerOffset_ = 0;
- this.computeLineData_();
+ this.computeLineData_(opt_baseLineOnStart);
};
editing.EditableLine.prototype = {
/** @private */
- computeLineData_: function() {
+ computeLineData_: function(opt_baseLineOnStart) {
+ // Note that we calculate the line based only upon anchor or focus even if
+ // they do not fall on the same line. It is up to the caller to specify
+ // which end to base this line upon since it requires reasoning about two
+ // lines.
var nameLen = 0;
- if (this.start_.node.name)
- nameLen = this.start_.node.name.length;
+ var lineBase = opt_baseLineOnStart ? this.start_ : this.end_;
+ var lineExtend = opt_baseLineOnStart ? this.end_ : this.start_;
- this.value_ = new Spannable(this.start_.node.name || '', this.start_);
- if (this.start_.node == this.end_.node)
- this.value_.setSpan(this.end_, 0, nameLen);
+ if (lineBase.node.name)
+ nameLen = lineBase.node.name.length;
+
+ this.value_ = new Spannable(lineBase.node.name || '', lineBase);
+ if (lineBase.node == lineExtend.node)
+ this.value_.setSpan(lineExtend, 0, nameLen);
// Initialize defaults.
- this.lineStart_ = this.start_.node;
+ this.lineStart_ = lineBase.node;
this.lineEnd_ = this.lineStart_;
this.startContainer_ = this.lineStart_.parent;
this.lineStartContainer_ = this.lineStart_.parent;
+ this.lineEndContainer_ = this.lineStart_.parent;
// Annotate each chunk with its associated inline text box node.
- this.value_.setSpan(this.lineStart_, 0, this.lineStart_.name.length);
+ this.value_.setSpan(this.lineStart_, 0, nameLen);
// If the current selection is not on an inline text box (e.g. an image),
// return early here so that the line contents are just the node. This is
@@ -533,6 +589,7 @@ editing.EditableLine.prototype = {
this.value_.append(new Spannable(lineEnd.name, annotation));
}
+ this.lineEndContainer_ = this.lineEnd_.parent;
// Finally, annotate with all parent static texts as NodeSpan's so that
// braille routing can key properly into the node with an offset.
@@ -552,6 +609,11 @@ editing.EditableLine.prototype = {
textCountAfterLineEnd += finder.name.length;
}
+ if (this.lineEndContainer_.name) {
+ this.localLineEndContainerOffset_ =
+ this.lineEndContainer_.name.length - textCountAfterLineEnd;
+ }
+
var len = 0;
for (var i = 0; i < parents.length; i++) {
var parent = parents[i];
@@ -592,7 +654,14 @@ editing.EditableLine.prototype = {
* @return {number}
*/
get startOffset() {
- return this.value_.getSpanStart(this.start_) + this.start_.index;
+ // It is possible that the start cursor points to content before this line
+ // (e.g. in a multi-line selection).
+ try {
+ return this.value_.getSpanStart(this.start_) + this.start_.index;
+ } catch (e) {
+ // When that happens, fall back to the start of this line.
+ return 0;
+ }
},
/**
@@ -600,7 +669,11 @@ editing.EditableLine.prototype = {
* @return {number}
*/
get endOffset() {
- return this.value_.getSpanStart(this.end_) + this.end_.index;
+ try {
+ return this.value_.getSpanStart(this.end_) + this.end_.index;
+ } catch (e) {
+ return this.value_.length;
+ }
},
/**
@@ -650,15 +723,31 @@ editing.EditableLine.prototype = {
/**
* Returns true if |otherLine| surrounds the same line as |this|. Note that
* the contents of the line might be different.
+ * @param {editing.EditableLine} otherLine
* @return {boolean}
*/
- equals: function(otherLine) {
+ isSameLine: function(otherLine) {
// Equality is intentionally loose here as any of the state nodes can be
// invalidated at any time. We rely upon the start/anchor of the line
// staying the same.
- return otherLine.lineStartContainer_ == this.lineStartContainer_ &&
- otherLine.localLineStartContainerOffset_ ==
- this.localLineStartContainerOffset_;
+ return (otherLine.lineStartContainer_ == this.lineStartContainer_ &&
+ otherLine.localLineStartContainerOffset_ ==
+ this.localLineStartContainerOffset_) ||
+ (otherLine.lineEndContainer_ == this.lineEndContainer_ &&
+ otherLine.localLineEndContainerOffset_ ==
+ this.localLineEndContainerOffset_);
+ },
+
+ /**
+ * Returns true if |otherLine| surrounds the same line as |this| and has the
+ * same selection.
+ * @param {editing.EditableLine} otherLine
+ * @return {boolean}
+ */
+ isSameLineAndSelection: function(otherLine) {
+ return this.isSameLine(otherLine) &&
+ this.startOffset == otherLine.startOffset &&
+ this.endOffset == otherLine.endOffset;
}
};
« no previous file with comments | « no previous file | chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698