1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @fileoverview Translates text to braille, optionally with some parts
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * uncontracted.
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.provide('cvox.ExpandingBrailleTranslator');
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.BrailleUtil');
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.LibLouis');
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.Spannable');
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * A wrapper around one or two braille translators that uses contracted
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * braille or not based on the selection start- and end-points (if any) in the
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * translated text.  If only one translator is provided, then that translator
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * is used for all text regardless of selection.  If two translators
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * are provided, then the uncontracted translator is used for some text
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * around the selection end-points and the contracted translator is used
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * for all other text.  When determining what text to use uncontracted
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * translation for around a position, a region surrounding that position
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * containing either only whitespace characters or only non-whitespace
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * characters is used.
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {!cvox.LibLouis.Translator} defaultTranslator The translator for all
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *     text when the uncontracted translator is not used.
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {cvox.LibLouis.Translator=} opt_uncontractedTranslator
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *     Translator to use for uncontracted braille translation.
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @constructor
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ExpandingBrailleTranslator =
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    function(defaultTranslator, opt_uncontractedTranslator) {
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  /**
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * @type {!cvox.LibLouis.Translator}
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * @private
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   */
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.defaultTranslator_ = defaultTranslator;
41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  /**
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * @type {cvox.LibLouis.Translator}
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * @private
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   */
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.uncontractedTranslator_ = opt_uncontractedTranslator || null;
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * What expansion to apply to the part of the translated string marked by the
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * {@code cvox.BrailleUtil.ValueSpan} spannable.
5246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * @enum {number}
5346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) */
5446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)cvox.ExpandingBrailleTranslator.ExpansionType = {
5546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  /**
5646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   * Use the default translator all of the value, regardless of any selection.
5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   * This is typically used when the user is in the middle of typing and the
5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   * typing started outside of a word.
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   */
6046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  NONE: 0,
6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  /**
6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   * Expand text around the selection end-points if any.  If the selection is
6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   * a cursor, expand the text that occupies the positions right before and
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   * after the cursor.  This is typically used when the user hasn't started
6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   * typing contracted braille or when editing inside a word.
6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   */
6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  SELECTION: 1,
6846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  /**
6946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   * Expand all text covered by the value span.  this is typically used when
7046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   * the user is editing a text field where it doesn't make sense to use
7146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   * contracted braille (such as a url or email address).
7246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   */
7346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ALL: 2
7446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
7546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
7646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)/**
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Translates text to braille using the translator(s) provided to the
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * constructor.  See {@code cvox.LibLouis.Translator} for further details.
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {!cvox.Spannable} text Text to translate.
8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * @param {cvox.ExpandingBrailleTranslator.ExpansionType} expansionType
8246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) *     Indicates how the text marked by a value span, if any, is expanded.
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {function(!ArrayBuffer, !Array.<number>, !Array.<number>)}
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *     callback Called when the translation is done.  It takes resulting
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *         braille cells and positional mappings as parameters.
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ExpandingBrailleTranslator.prototype.translate =
8846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    function(text, expansionType, callback) {
8946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  var expandRanges = this.findExpandRanges_(text, expansionType);
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (expandRanges.length == 0) {
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    this.defaultTranslator_.translate(
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        text.toString(),
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        cvox.ExpandingBrailleTranslator.nullParamsToEmptyAdapter_(
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            text.getLength(), callback));
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var chunks = [];
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  function addChunk(translator, start, end) {
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    chunks.push({translator: translator, start: start, end: end});
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var lastEnd = 0;
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (var i = 0; i < expandRanges.length; ++i) {
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var range = expandRanges[i];
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (lastEnd < range.start) {
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      addChunk(this.defaultTranslator_, lastEnd, range.start);
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    addChunk(this.uncontractedTranslator_, range.start, range.end);
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    lastEnd = range.end;
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (lastEnd < text.getLength()) {
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    addChunk(this.defaultTranslator_, lastEnd, text.getLength());
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var numPendingCallbacks = chunks.length;
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  function chunkTranslated(chunk, cells, textToBraille, brailleToText) {
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    chunk.cells = cells;
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    chunk.textToBraille = textToBraille;
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    chunk.brailleToText = brailleToText;
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (--numPendingCallbacks <= 0) {
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      finish();
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  function finish() {
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var totalCells = chunks.reduce(
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        function(accum, chunk) { return accum + chunk.cells.byteLength}, 0);
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var cells = new Uint8Array(totalCells);
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var cellPos = 0;
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var textToBraille = [];
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var brailleToText = [];
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    function appendAdjusted(array, toAppend, adjustment) {
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      array.push.apply(array, toAppend.map(
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          function(elem) { return adjustment + elem; }
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          ));
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for (var i = 0, chunk; chunk = chunks[i]; ++i) {
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      cells.set(new Uint8Array(chunk.cells), cellPos);
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      appendAdjusted(textToBraille, chunk.textToBraille, cellPos);
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      appendAdjusted(brailleToText, chunk.brailleToText, chunk.start);
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      cellPos += chunk.cells.byteLength;
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    callback(cells.buffer, textToBraille, brailleToText);
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (var i = 0, chunk; chunk = chunks[i]; ++i) {
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    chunk.translator.translate(
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        text.toString().substring(chunk.start, chunk.end),
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        cvox.ExpandingBrailleTranslator.nullParamsToEmptyAdapter_(
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            chunk.end - chunk.start, goog.partial(chunkTranslated, chunk)));
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Expands a position to a range that covers the consecutive range of
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * either whitespace or non whitespace characters around it.
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {string} str Text to look in.
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {number} pos Position to start looking at.
16146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * @param {number} start Minimum value for the start position of the returned
16246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) *     range.
16346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * @param {number} end Maximum value for the end position of the returned
16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) *     range.
16546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * @return {!cvox.ExpandingBrailleTranslator.Range_} The claculated range.
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @private
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)cvox.ExpandingBrailleTranslator.rangeForPosition_ = function(
16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    str, pos, start, end) {
17046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (start < 0 || end > str.length) {
17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    throw RangeError(
17246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        'End-points out of range looking for braille expansion range');
17346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
17446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (pos < start || pos >= end) {
17546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    throw RangeError(
17646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        'Position out of range looking for braille expansion range');
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Find the last chunk of either whitespace or non-whitespace before and
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // including pos.
18046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  var start = str.substring(start, pos + 1).search(/(\s+|\S+)$/) + start;
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Find the characters to include after pos, starting at pos so that
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // they are the same kind (either whitespace or not) as the
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // characters starting at start.
18446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  var end = pos + /^(\s+|\S+)/.exec(str.substring(pos, end))[0].length;
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return {start: start, end: end};
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Finds the ranges in which contracted braille should not be used.
191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {!cvox.Spannable} text Text to find expansion ranges in.
19246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * @param {cvox.ExpandingBrailleTranslator.ExpansionType} expansionType
19346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) *     Indicates how the text marked up as the value is expanded.
19446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * @return {!Array.<cvox.ExpandingBrailleTranslator.Range_>} The calculated
19546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) *     ranges.
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @private
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
19846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)cvox.ExpandingBrailleTranslator.prototype.findExpandRanges_ = function(
19946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    text, expansionType) {
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var result = [];
20146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (this.uncontractedTranslator_ &&
20246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      expansionType != cvox.ExpandingBrailleTranslator.ExpansionType.NONE) {
20346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    var value = text.getSpanInstanceOf(cvox.BrailleUtil.ValueSpan);
20446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (value) {
20546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      // The below type casts are valid because the ranges must be valid when
20646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      // the span is known to exist.
20746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      var valueStart = /** @type {number} */ (text.getSpanStart(value));
20846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      var valueEnd = /** @type {number} */ (text.getSpanEnd(value));
20946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      switch (expansionType) {
21046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        case cvox.ExpandingBrailleTranslator.ExpansionType.SELECTION:
21146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          this.addRangesForSelection_(text, valueStart, valueEnd, result);
21246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          break;
21346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        case cvox.ExpandingBrailleTranslator.ExpansionType.ALL:
21446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          result.push({start: valueStart, end: valueEnd});
21546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          break;
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return result;
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
22546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * Finds ranges to expand around selection end points inside the value of
22646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * a string.  If any ranges are found, adds them to {@code outRanges}.
22746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * @param {cvox.Spannable} text Text to find ranges in.
22846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * @param {number} valueStart Start of the value in {@code text}.
22946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * @param {number} valueEnd End of the value in {@code text}.
23046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * @param {Array.<cvox.ExpandingBrailleTranslator.Range_>} outRanges
23146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) *     Destination for the expansion ranges.  Untouched if no ranges
23246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) *     are found.  Note that ranges may be coalesced.
23346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * @private
23446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) */
23546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)cvox.ExpandingBrailleTranslator.prototype.addRangesForSelection_ = function(
23646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    text, valueStart, valueEnd, outRanges) {
23746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  var selection = text.getSpanInstanceOf(
23846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      cvox.BrailleUtil.ValueSelectionSpan);
23946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!selection) {
24046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
24146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
24246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  var selectionStart = text.getSpanStart(selection);
24346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  var selectionEnd = text.getSpanEnd(selection);
24446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (selectionStart < valueStart || selectionEnd > valueEnd) {
24546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
24646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
24746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  var expandPositions = [];
24846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (selectionStart == valueEnd) {
24946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (selectionStart > valueStart) {
25046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      expandPositions.push(selectionStart - 1);
25146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
25246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  } else {
25346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (selectionStart == selectionEnd && selectionStart > valueStart) {
25446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      expandPositions.push(selectionStart - 1);
25546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
25646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    expandPositions.push(selectionStart);
25746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // Include the selection end if the length of the selection is
25846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // greater than one (otherwise this position would be redundant).
25946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (selectionEnd > selectionStart + 1) {
26046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      // Look at the last actual character of the selection, not the
26146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      // character at the (exclusive) end position.
26246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      expandPositions.push(selectionEnd - 1);
26346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
26446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
26546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
26646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  var lastRange = outRanges[outRanges.length - 1] || null;
26746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (var i = 0; i < expandPositions.length; ++i) {
26846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    var range = cvox.ExpandingBrailleTranslator.rangeForPosition_(
26946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        text.toString(), expandPositions[i], valueStart, valueEnd);
27046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (lastRange && lastRange.end >= range.start) {
27146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      lastRange.end = range.end;
27246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    } else {
27346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      outRanges.push(range);
27446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      lastRange = range;
27546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
27646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
27746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
27846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
27946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
28046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)/**
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Adapts {@code callback} to accept null arguments and treat them as if the
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * translation result is empty.
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {number} inputLength Length of the input to the translation.
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *     Used for populating {@code textToBraille} if null.
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {function(!ArrayBuffer, !Array.<number>, !Array.<number>)} callback
28646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) *     The callback to adapt.
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {function(ArrayBuffer, Array.<number>, Array.<number>)}
28846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) *     An adapted version of the callback.
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @private
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ExpandingBrailleTranslator.nullParamsToEmptyAdapter_ =
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    function(inputLength, callback) {
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return function(cells, textToBraille, brailleToText) {
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!textToBraille) {
295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      textToBraille = new Array(inputLength);
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      for (var i = 0; i < inputLength; ++i) {
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        textToBraille[i] = 0;
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    callback(cells || new ArrayBuffer(0),
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)             textToBraille,
302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)             brailleToText || []);
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  };
304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * A character range with inclusive start and exclusive end positions.
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @typedef {{start: number, end: number}}
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @private
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ExpandingBrailleTranslator.Range_;
313