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

Side by Side Diff: chrome/browser/resources/chromeos/chromevox/braille/braille_display_manager.js

Issue 2496823002: Implement word wrapping and panning in multiline Braille. (Closed)
Patch Set: Wrote tests, fixed bugs :) Created 4 years 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview Puts text on a braille display. 6 * @fileoverview Puts text on a braille display.
7 * 7 *
8 */ 8 */
9 9
10 goog.provide('cvox.BrailleDisplayManager'); 10 goog.provide('cvox.BrailleDisplayManager');
(...skipping 22 matching lines...) Expand all
33 * @private 33 * @private
34 */ 34 */
35 this.content_ = new cvox.NavBraille({}); 35 this.content_ = new cvox.NavBraille({});
36 /** 36 /**
37 * @type {!cvox.ExpandingBrailleTranslator.ExpansionType} valueExpansion 37 * @type {!cvox.ExpandingBrailleTranslator.ExpansionType} valueExpansion
38 * @private 38 * @private
39 */ 39 */
40 this.expansionType_ = 40 this.expansionType_ =
41 cvox.ExpandingBrailleTranslator.ExpansionType.SELECTION; 41 cvox.ExpandingBrailleTranslator.ExpansionType.SELECTION;
42 /** 42 /**
43 * @type {!ArrayBuffer}
44 * @private
45 */
46 this.translatedContent_ = new ArrayBuffer(0);
47 /**
48 * @type {!ArrayBuffer}
49 * @private
50 */
51 this.displayedContent_ = this.translatedContent_;
52 /**
53 * @type {cvox.PanStrategy} 43 * @type {cvox.PanStrategy}
54 * @private 44 * @private
55 */ 45 */
56 this.panStrategy_ = new cvox.WrappingPanStrategy(); 46 this.panStrategy_ = new cvox.PanStrategy();
57 /** 47 /**
58 * @type {function(!cvox.BrailleKeyEvent, !cvox.NavBraille)} 48 * @type {function(!cvox.BrailleKeyEvent, !cvox.NavBraille)}
59 * @private 49 * @private
60 */ 50 */
61 this.commandListener_ = function() {}; 51 this.commandListener_ = function() {};
62 /** 52 /**
63 * Current display state used for width calculations. This is different from 53 * Current display state to show in the Virtual Braille Captions display.
64 * realDisplayState_ if the braille captions feature is enabled and there is 54 * This is different from realDisplayState_ if the braille captions feature
65 * no hardware display connected. Otherwise, it is the same object 55 * is enabled and there is no hardware display connected. Otherwise, it is
66 * as realDisplayState_. 56 * the same object as realDisplayState_.
67 * @type {!cvox.BrailleDisplayState} 57 * @type {!cvox.BrailleDisplayState}
68 * @private 58 * @private
69 */ 59 */
70 this.displayState_ = {available: false, textRowCount: undefined, 60 this.displayState_ = {available: false, textRowCount: undefined,
71 textColumnCount: undefined}; 61 textColumnCount: undefined};
72 /** 62 /**
73 * State reported from the chrome api, reflecting a real hardware 63 * State reported from the chrome api, reflecting a real hardware
74 * display. 64 * display.
75 * @type {!cvox.BrailleDisplayState} 65 * @type {!cvox.BrailleDisplayState}
76 * @private 66 * @private
77 */ 67 */
78 this.realDisplayState_ = this.displayState_; 68 this.realDisplayState_ = this.displayState_;
79 /**
80 * @type {!Array<number>}
81 * @private
82 */
83 this.textToBraille_ = [];
84 /**
85 * @type {!Array<number>}
86 * @private
87 */
88 this.brailleToText_ = [];
89 69
90 translatorManager.addChangeListener(function() { 70 translatorManager.addChangeListener(function() {
91 this.translateContent_(this.content_, this.expansionType_); 71 this.translateContent_(this.content_, this.expansionType_);
92 }.bind(this)); 72 }.bind(this));
93 73
94 chrome.storage.onChanged.addListener(function(changes, area) { 74 chrome.storage.onChanged.addListener(function(changes, area) {
95 if (area == 'local' && 'brailleWordWrap' in changes) { 75 if (area == 'local' && 'brailleWordWrap' in changes) {
96 this.updatePanStrategy_(changes.brailleWordWrap.newValue); 76 this.updatePanStrategy_(changes.brailleWordWrap.newValue);
97 } 77 }
98 }.bind(this)); 78 }.bind(this));
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 }; 131 };
152 132
153 133
154 /** 134 /**
155 * @param {!cvox.BrailleDisplayState} newState Display state reported 135 * @param {!cvox.BrailleDisplayState} newState Display state reported
156 * by the extension API. 136 * by the extension API.
157 * @private 137 * @private
158 */ 138 */
159 cvox.BrailleDisplayManager.prototype.refreshDisplayState_ = function( 139 cvox.BrailleDisplayManager.prototype.refreshDisplayState_ = function(
160 newState) { 140 newState) {
161 var oldSize = this.displayState_.textColumnCount * 141 var oldColumnCount = this.displayState_.textColumnCount || 0;
162 this.displayState_.textRowCount || 0; 142 var oldRowCount = this.displayState_.textRowCount || 0;
163 this.realDisplayState_ = newState; 143 this.realDisplayState_ = newState;
164 if (newState.available) { 144 if (newState.available) {
165 this.displayState_ = newState; 145 this.displayState_ = newState;
146 // Update the dimensions of the virtual braille captions display to those
147 // of a real physical display when one is plugged in.
166 } else { 148 } else {
167 this.displayState_ = 149 this.displayState_ =
168 cvox.BrailleCaptionsBackground.getVirtualDisplayState(); 150 cvox.BrailleCaptionsBackground.getVirtualDisplayState();
169 } 151 }
170 var newSize = this.displayState_.textColumnCount * 152 var newColumnCount = this.displayState_.textColumnCount || 0;
171 this.displayState_.textRowCount || 0; 153 var newRowCount = this.displayState_.textRowCount || 0;
172 if (oldSize != newSize) { 154
173 this.panStrategy_.setDisplaySize(newSize); 155 if (oldColumnCount != newColumnCount || oldRowCount != newRowCount) {
156 this.panStrategy_.setDisplaySize(newRowCount, newColumnCount);
174 } 157 }
175 this.refresh_(); 158 this.refresh_();
176 }; 159 };
177 160
178 161
179 /** 162 /**
180 * Called when the state of braille captions changes. 163 * Called when the state of braille captions changes.
181 * @private 164 * @private
182 */ 165 */
183 cvox.BrailleDisplayManager.prototype.onCaptionsStateChanged_ = function() { 166 cvox.BrailleDisplayManager.prototype.onCaptionsStateChanged_ = function() {
184 // Force reevaluation of the display state based on our stored real 167 // Force reevaluation of the display state based on our stored real
185 // hardware display state, meaning that if a real display is connected, 168 // hardware display state, meaning that if a real display is connected,
186 // that takes precedence over the state from the captions 'virtual' display. 169 // that takes precedence over the state from the captions 'virtual' display.
187 this.refreshDisplayState_(this.realDisplayState_); 170 this.refreshDisplayState_(this.realDisplayState_);
188 }; 171 };
189 172
190 173
191 /** @private */ 174 /**
175 * Refreshes what is shown on the physical braille display and the virtual
176 * braille captions display.
177 * @private */
David Tseng 2016/11/30 22:11:54 nit: move */ to a new line
ultimatedbz 2016/12/01 05:12:14 Done.
192 cvox.BrailleDisplayManager.prototype.refresh_ = function() { 178 cvox.BrailleDisplayManager.prototype.refresh_ = function() {
193 if (!this.displayState_.available) { 179 if (!this.displayState_.available) {
194 return; 180 return;
195 } 181 }
196 var viewPort = this.panStrategy_.viewPort; 182 var brailleBuf = this.panStrategy_.getCurrentBrailleViewportContents();
197 var buf = this.displayedContent_.slice(viewPort.start, viewPort.end); 183 var textBuf = this.panStrategy_.getCurrentTextSlice();
David Tseng 2016/11/30 22:11:54 Maybe make this getCurrentTextViewPortContents
ultimatedbz 2016/12/01 05:12:15 Done.
198 if (this.realDisplayState_.available) { 184 if (this.realDisplayState_.available) {
199 chrome.brailleDisplayPrivate.writeDots(buf, buf.byteLength, 1); 185 chrome.brailleDisplayPrivate.writeDots(brailleBuf,
186 brailleBuf.byteLength, 1);
200 } 187 }
201 if (cvox.BrailleCaptionsBackground.isEnabled()) { 188 if (cvox.BrailleCaptionsBackground.isEnabled()) {
202 var start = this.brailleToTextPosition_(viewPort.start); 189 cvox.BrailleCaptionsBackground.setContent(textBuf, brailleBuf,
203 var end = this.brailleToTextPosition_(viewPort.end); 190 this.panStrategy_.brailleToText, this.panStrategy_.offsetsForSlices,
204 cvox.BrailleCaptionsBackground.setContent( 191 this.displayState_.textRowCount, this.displayState_.textColumnCount);
205 this.content_.text.toString().substring(start, end), buf,
206 this.brailleToText_);
207 } 192 }
208 }; 193 };
209 194
210
211 /** 195 /**
212 * @param {!cvox.NavBraille} newContent New display content. 196 * @param {!cvox.NavBraille} newContent New display content.
213 * @param {cvox.ExpandingBrailleTranslator.ExpansionType} newExpansionType 197 * @param {cvox.ExpandingBrailleTranslator.ExpansionType} newExpansionType
214 * How the value part of of the new content should be expanded 198 * How the value part of of the new content should be expanded
215 * with regards to contractions. 199 * with regards to contractions.
216 * @private 200 * @private
217 */ 201 */
218 cvox.BrailleDisplayManager.prototype.translateContent_ = function( 202 cvox.BrailleDisplayManager.prototype.translateContent_ = function(
219 newContent, newExpansionType) { 203 newContent, newExpansionType) {
220 var writeTranslatedContent = function(cells, textToBraille, brailleToText) { 204 var writeTranslatedContent = function(cells, textToBraille, brailleToText) {
221 this.content_ = newContent; 205 this.content_ = newContent;
222 this.expansionType_ = newExpansionType; 206 this.expansionType_ = newExpansionType;
223 this.textToBraille_ = textToBraille;
224 this.brailleToText_ = brailleToText;
225 var startIndex = this.content_.startIndex; 207 var startIndex = this.content_.startIndex;
226 var endIndex = this.content_.endIndex; 208 var endIndex = this.content_.endIndex;
227 var targetPosition; 209 var targetPosition;
228 if (startIndex >= 0) { 210 if (startIndex >= 0) {
229 var translatedStartIndex; 211 var translatedStartIndex;
230 var translatedEndIndex; 212 var translatedEndIndex;
231 if (startIndex >= textToBraille.length) { 213 if (startIndex >= textToBraille.length) {
232 // Allow the cells to be extended with one extra cell for 214 // Allow the cells to be extended with one extra cell for
233 // a carret after the last character. 215 // a carret after the last character.
234 var extCells = new ArrayBuffer(cells.byteLength + 1); 216 var extCells = new ArrayBuffer(cells.byteLength + 1);
235 new Uint8Array(extCells).set(new Uint8Array(cells)); 217 new Uint8Array(extCells).set(new Uint8Array(cells));
236 // Last byte is initialized to 0. 218 // Last byte is initialized to 0.
237 cells = extCells; 219 cells = extCells;
238 translatedStartIndex = cells.byteLength - 1; 220 translatedStartIndex = cells.byteLength - 1;
239 } else { 221 } else {
240 translatedStartIndex = textToBraille[startIndex]; 222 translatedStartIndex = textToBraille[startIndex];
241 } 223 }
242 if (endIndex >= textToBraille.length) { 224 if (endIndex >= textToBraille.length) {
243 // endIndex can't be past-the-end of the last cell unless 225 // endIndex can't be past-the-end of the last cell unless
244 // startIndex is too, so we don't have to do another 226 // startIndex is too, so we don't have to do another
245 // extension here. 227 // extension here.
246 translatedEndIndex = cells.byteLength; 228 translatedEndIndex = cells.byteLength;
247 } else { 229 } else {
248 translatedEndIndex = textToBraille[endIndex]; 230 translatedEndIndex = textToBraille[endIndex];
249 } 231 }
250 this.translatedContent_ = cells; 232 // Add the cursor to cells.
251 // Copy the translated content to a separate buffer and add the cursor 233 this.writeCursor_(cells, translatedStartIndex, translatedEndIndex);
252 // to it.
253 this.displayedContent_ = new ArrayBuffer(cells.byteLength);
254 new Uint8Array(this.displayedContent_).set(new Uint8Array(cells));
255 this.writeCursor_(this.displayedContent_,
256 translatedStartIndex, translatedEndIndex);
257 targetPosition = translatedStartIndex; 234 targetPosition = translatedStartIndex;
258 } else { 235 } else {
259 this.translatedContent_ = this.displayedContent_ = cells;
260 targetPosition = 0; 236 targetPosition = 0;
261 } 237 }
262 this.panStrategy_.setContent(this.translatedContent_, targetPosition); 238 this.panStrategy_.setContent(this.content_.text.toString(),
239 cells, brailleToText, targetPosition);
David Tseng 2016/11/30 22:11:54 Optional: to help the reviewer and any future read
ultimatedbz 2016/12/01 05:12:15 Acknowledged.
240
263 this.refresh_(); 241 this.refresh_();
264 }.bind(this); 242 }.bind(this);
265 243
266 var translator = this.translatorManager_.getExpandingTranslator(); 244 var translator = this.translatorManager_.getExpandingTranslator();
267 if (!translator) { 245 if (!translator) {
268 writeTranslatedContent(new ArrayBuffer(0), [], []); 246 writeTranslatedContent(new ArrayBuffer(0), [], []);
269 } else { 247 } else {
270 translator.translate( 248 translator.translate(
271 newContent.text, 249 newContent.text,
272 newExpansionType, 250 newExpansionType,
273 writeTranslatedContent); 251 writeTranslatedContent);
274 } 252 }
275 }; 253 };
276 254
277 255
278 /** 256 /**
279 * @param {cvox.BrailleKeyEvent} event The key event. 257 * @param {cvox.BrailleKeyEvent} event The key event.
280 * @private 258 * @private
281 */ 259 */
282 cvox.BrailleDisplayManager.prototype.onKeyEvent_ = function(event) { 260 cvox.BrailleDisplayManager.prototype.onKeyEvent_ = function(event) {
283 switch (event.command) { 261 switch (event.command) {
284 case cvox.BrailleKeyCommand.PAN_LEFT: 262 case cvox.BrailleKeyCommand.PAN_LEFT:
285 this.panLeft_(); 263 this.panLeft_();
286 break; 264 break;
287 case cvox.BrailleKeyCommand.PAN_RIGHT: 265 case cvox.BrailleKeyCommand.PAN_RIGHT:
288 this.panRight_(); 266 this.panRight_();
289 break; 267 break;
290 case cvox.BrailleKeyCommand.ROUTING: 268 case cvox.BrailleKeyCommand.ROUTING:
291 event.displayPosition = this.brailleToTextPosition_( 269 event.displayPosition = this.brailleToTextPosition_(
292 event.displayPosition + this.panStrategy_.viewPort.start); 270 event.displayPosition + this.panStrategy_.viewPort.firstRow *
271 this.panStrategy_.displaySize.columns);
293 // fall through 272 // fall through
294 default: 273 default:
295 this.commandListener_(event, this.content_); 274 this.commandListener_(event, this.content_);
296 break; 275 break;
297 } 276 }
298 }; 277 };
299 278
300 279
301 /** 280 /**
302 * Shift the display by one full display size and refresh the content. 281 * Shift the display by one full display size and refresh the content.
(...skipping 21 matching lines...) Expand all
324 cvox.BrailleDisplayManager.prototype.panRight_ = function() { 303 cvox.BrailleDisplayManager.prototype.panRight_ = function() {
325 if (this.panStrategy_.next()) { 304 if (this.panStrategy_.next()) {
326 this.refresh_(); 305 this.refresh_();
327 } else { 306 } else {
328 this.commandListener_({ 307 this.commandListener_({
329 command: cvox.BrailleKeyCommand.PAN_RIGHT 308 command: cvox.BrailleKeyCommand.PAN_RIGHT
330 }, this.content_); 309 }, this.content_);
331 } 310 }
332 }; 311 };
333 312
334
335 /** 313 /**
336 * Writes a cursor in the specified range into translated content. 314 * Writes a cursor in the specified range into translated content.
337 * @param {ArrayBuffer} buffer Buffer to add cursor to. 315 * @param {ArrayBuffer} buffer Buffer to add cursor to.
338 * @param {number} startIndex The start index to place the cursor. 316 * @param {number} startIndex The start index to place the cursor.
339 * @param {number} endIndex The end index to place the cursor (exclusive). 317 * @param {number} endIndex The end index to place the cursor (exclusive).
340 * @private 318 * @private
341 */ 319 */
342 cvox.BrailleDisplayManager.prototype.writeCursor_ = function( 320 cvox.BrailleDisplayManager.prototype.writeCursor_ = function(
343 buffer, startIndex, endIndex) { 321 buffer, startIndex, endIndex) {
344 if (startIndex < 0 || startIndex >= buffer.byteLength || 322 if (startIndex < 0 || startIndex >= buffer.byteLength ||
345 endIndex < startIndex || endIndex > buffer.byteLength) { 323 endIndex < startIndex || endIndex > buffer.byteLength) {
346 return; 324 return;
347 } 325 }
348 if (startIndex == endIndex) { 326 if (startIndex == endIndex) {
349 endIndex = startIndex + 1; 327 endIndex = startIndex + 1;
350 } 328 }
351 var dataView = new DataView(buffer); 329 var dataView = new DataView(buffer);
352 while (startIndex < endIndex) { 330 while (startIndex < endIndex) {
353 var value = dataView.getUint8(startIndex); 331 var value = dataView.getUint8(startIndex);
354 value |= cvox.BrailleDisplayManager.CURSOR_DOTS_; 332 value |= cvox.BrailleDisplayManager.CURSOR_DOTS_;
355 dataView.setUint8(startIndex, value); 333 dataView.setUint8(startIndex, value);
356 startIndex++; 334 startIndex++;
357 } 335 }
358 }; 336 };
359 337
360
361 /** 338 /**
362 * Returns the text position corresponding to an absolute braille position, 339 * Returns the text position corresponding to an absolute braille position,
363 * that is not accounting for the current pan position. 340 * that is not accounting for the current pan position.
364 * @private 341 * @private
365 * @param {number} braillePosition Braille position relative to the startof 342 * @param {number} braillePosition Braille position relative to the startof
366 * the translated content. 343 * the translated content.
367 * @return {number} The mapped position in code units. 344 * @return {number} The mapped position in code units.
368 */ 345 */
369 cvox.BrailleDisplayManager.prototype.brailleToTextPosition_ = 346 cvox.BrailleDisplayManager.prototype.brailleToTextPosition_ =
370 function(braillePosition) { 347 function(braillePosition) {
371 var mapping = this.brailleToText_; 348 var mapping = this.panStrategy_.brailleToText;
372 if (braillePosition < 0) { 349 if (braillePosition < 0) {
373 // This shouldn't happen. 350 // This shouldn't happen.
374 console.error('WARNING: Braille position < 0: ' + braillePosition);
David Tseng 2016/11/30 22:11:54 Doesn't seem like this should be removed.
ultimatedbz 2016/12/01 05:12:15 Thanks for catching this!
375 return 0; 351 return 0;
376 } else if (braillePosition >= mapping.length) { 352 } else if (braillePosition >= mapping.length) {
377 // This happens when the user clicks on the right part of the display 353 // This happens when the user clicks on the right part of the display
378 // when it is not entirely filled with content. Allow addressing the 354 // when it is not entirely filled with content. Allow addressing the
379 // position after the last character. 355 // position after the last character.
380 return this.content_.text.length; 356 return this.content_.text.length;
381 } else { 357 } else {
382 return mapping[braillePosition]; 358 return mapping[braillePosition];
383 } 359 }
384 }; 360 };
385 361
386
387 /** 362 /**
388 * @param {boolean} wordWrap 363 * @param {boolean} wordWrap
389 * @private 364 * @private
390 */ 365 */
391 cvox.BrailleDisplayManager.prototype.updatePanStrategy_ = function(wordWrap) { 366 cvox.BrailleDisplayManager.prototype.updatePanStrategy_ = function(wordWrap) {
392 var newStrategy = wordWrap ? new cvox.WrappingPanStrategy() : 367 this.panStrategy_.setPanStrategy(wordWrap);
393 new cvox.FixedPanStrategy();
394 newStrategy.setDisplaySize(this.displayState_.textColumnCount || 0);
395 newStrategy.setContent(this.translatedContent_,
396 this.panStrategy_.viewPort.start);
397 this.panStrategy_ = newStrategy;
398 this.refresh_(); 368 this.refresh_();
399 }; 369 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698