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