| OLD | NEW |
| 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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 */ | 50 */ |
| 51 this.commandListener_ = function() {}; | 51 this.commandListener_ = function() {}; |
| 52 /** | 52 /** |
| 53 * Current display state to show in the Virtual Braille Captions display. | 53 * Current display state to show in the Virtual Braille Captions display. |
| 54 * This is different from realDisplayState_ if the braille captions feature | 54 * This is different from realDisplayState_ if the braille captions feature |
| 55 * is enabled and there is no hardware display connected. Otherwise, it is | 55 * is enabled and there is no hardware display connected. Otherwise, it is |
| 56 * the same object as realDisplayState_. | 56 * the same object as realDisplayState_. |
| 57 * @type {!cvox.BrailleDisplayState} | 57 * @type {!cvox.BrailleDisplayState} |
| 58 * @private | 58 * @private |
| 59 */ | 59 */ |
| 60 this.displayState_ = {available: false, textRowCount: undefined, | 60 this.displayState_ = {available: false, textRowCount: 0, |
| 61 textColumnCount: undefined}; | 61 textColumnCount: 0}; |
| 62 /** | 62 /** |
| 63 * State reported from the chrome api, reflecting a real hardware | 63 * State reported from the chrome api, reflecting a real hardware |
| 64 * display. | 64 * display. |
| 65 * @type {!cvox.BrailleDisplayState} | 65 * @type {!cvox.BrailleDisplayState} |
| 66 * @private | 66 * @private |
| 67 */ | 67 */ |
| 68 this.realDisplayState_ = this.displayState_; | 68 this.realDisplayState_ = this.displayState_; |
| 69 | 69 |
| 70 translatorManager.addChangeListener(function() { | 70 translatorManager.addChangeListener(function() { |
| 71 this.translateContent_(this.content_, this.expansionType_); | 71 this.translateContent_(this.content_, this.expansionType_); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 | 103 |
| 104 /** | 104 /** |
| 105 * Dots representing a cursor. | 105 * Dots representing a cursor. |
| 106 * @const | 106 * @const |
| 107 * @private | 107 * @private |
| 108 */ | 108 */ |
| 109 cvox.BrailleDisplayManager.CURSOR_DOTS_ = 1 << 6 | 1 << 7; | 109 cvox.BrailleDisplayManager.CURSOR_DOTS_ = 1 << 6 | 1 << 7; |
| 110 | 110 |
| 111 | 111 |
| 112 /** | 112 /** |
| 113 * Alpha threshold for a pixel to be possibly displayed as a raised dot when |
| 114 * converting an image to braille, where 255 means only fully-opaque |
| 115 * pixels can be raised (if their luminance passes the luminance threshold), |
| 116 * and 0 means that alpha is effectively ignored and only luminance matters. |
| 117 * @const |
| 118 * @private |
| 119 */ |
| 120 cvox.BrailleDisplayManager.ALPHA_THRESHOLD_ = 255; |
| 121 |
| 122 |
| 123 /** |
| 124 * Luminance threshold for a pixel to be displayed as a raised dot when |
| 125 * converting an image to braille, on a scale of 0 (black) to 255 (white). |
| 126 * A pixel whose luminance is less than the given threshold will be raised. |
| 127 * @const |
| 128 * @private |
| 129 */ |
| 130 cvox.BrailleDisplayManager.LUMINANCE_THRESHOLD_ = 128; |
| 131 |
| 132 |
| 133 /** |
| 134 * Array mapping an index in an 8-dot braille cell, in column-first order, |
| 135 * to its corresponding bit mask in the standard braille cell encoding. |
| 136 * @const |
| 137 * @private |
| 138 */ |
| 139 cvox.BrailleDisplayManager.COORDS_TO_BRAILLE_DOT_ = |
| 140 [0x1, 0x2, 0x4, 0x40, 0x8, 0x10, 0x20, 0x80]; |
| 141 |
| 142 |
| 143 /** |
| 113 * @param {!cvox.NavBraille} content Content to send to the braille display. | 144 * @param {!cvox.NavBraille} content Content to send to the braille display. |
| 114 * @param {!cvox.ExpandingBrailleTranslator.ExpansionType} expansionType | 145 * @param {!cvox.ExpandingBrailleTranslator.ExpansionType} expansionType |
| 115 * If the text has a {@code ValueSpan}, this indicates how that part | 146 * If the text has a {@code ValueSpan}, this indicates how that part |
| 116 * of the display content is expanded when translating to braille. | 147 * of the display content is expanded when translating to braille. |
| 117 * (See {@code cvox.ExpandingBrailleTranslator}). | 148 * (See {@code cvox.ExpandingBrailleTranslator}). |
| 118 */ | 149 */ |
| 119 cvox.BrailleDisplayManager.prototype.setContent = function( | 150 cvox.BrailleDisplayManager.prototype.setContent = function( |
| 120 content, expansionType) { | 151 content, expansionType) { |
| 121 this.translateContent_(content, expansionType); | 152 this.translateContent_(content, expansionType); |
| 122 }; | 153 }; |
| 123 | 154 |
| 124 | 155 |
| 125 /** | 156 /** |
| 157 * Takes an image, in the form of a data url, and displays it in braille |
| 158 * onto the physical braille display and the virtual braille captions display. |
| 159 * @param {!string} imageUrl The image, in the form of a data url. |
| 160 */ |
| 161 cvox.BrailleDisplayManager.prototype.setImageContent = function(imageUrl) { |
| 162 if (!this.displayState_.available) { |
| 163 return; |
| 164 } |
| 165 |
| 166 // The number of dots in a braille cell. |
| 167 // TODO(dmazzoni): Both multi-line braille displays we're testing with |
| 168 // are 6-dot (2 x 3), but we should have a way to detect that via brltty. |
| 169 var cellWidth = 2; |
| 170 var cellHeight = 3; |
| 171 var maxCellHeight = 4; |
| 172 |
| 173 var rows = this.displayState_.textRowCount; |
| 174 var columns = this.displayState_.textColumnCount; |
| 175 var imageDataUrl = imageUrl; |
| 176 var imgElement = document.createElement('img'); |
| 177 imgElement.src = imageDataUrl; |
| 178 imgElement.onload = (function() { |
| 179 var canvas = document.createElement('canvas'); |
| 180 var context = canvas.getContext('2d'); |
| 181 canvas.width = columns * cellWidth; |
| 182 canvas.height = rows * cellHeight; |
| 183 context.drawImage(imgElement, 0, 0, canvas.width, canvas.height); |
| 184 var imageData = context.getImageData(0, 0, canvas.width, canvas.height); |
| 185 var data = imageData.data; |
| 186 var outputData = []; |
| 187 |
| 188 // Convert image to black and white by thresholding the luminance for |
| 189 // all opaque (non-transparent) pixels. |
| 190 for (var i = 0; i < data.length; i += 4) { |
| 191 var red = data[i]; |
| 192 var green = data[i + 1]; |
| 193 var blue = data[i + 2]; |
| 194 var alpha = data[i + 3]; |
| 195 var luminance = |
| 196 0.2126 * red + |
| 197 0.7152 * green + |
| 198 0.0722 * blue; |
| 199 // Show braille pin if the alpha is greater than the threshold and |
| 200 // the luminance is less than the threshold. |
| 201 var show = (alpha >= cvox.BrailleDisplayManager.ALPHA_THRESHOLD_ && |
| 202 luminance < cvox.BrailleDisplayManager.LUMINANCE_THRESHOLD_); |
| 203 outputData.push(show); |
| 204 } |
| 205 |
| 206 // Convert black-and-white array to the proper encoding for Braille cells. |
| 207 var brailleBuf = new ArrayBuffer(rows * columns); |
| 208 var view = new Uint8Array(brailleBuf); |
| 209 for (var i = 0; i < rows; i++) { |
| 210 for (var j = 0; j < columns; j++) { |
| 211 // Index in braille array |
| 212 var brailleIndex = i * columns + j; |
| 213 for (var cellColumn = 0; cellColumn < cellWidth; cellColumn++) { |
| 214 for (var cellRow = 0; cellRow < cellHeight; cellRow++) { |
| 215 var bitmapIndex = |
| 216 (i * columns * cellHeight + j + cellRow * columns) * cellWidth |
| 217 + cellColumn; |
| 218 if (outputData[bitmapIndex]) { |
| 219 view[brailleIndex] += |
| 220 cvox.BrailleDisplayManager.COORDS_TO_BRAILLE_DOT_[ |
| 221 cellColumn * maxCellHeight + cellRow]; |
| 222 } |
| 223 } |
| 224 } |
| 225 } |
| 226 } |
| 227 |
| 228 if (this.realDisplayState_.available) { |
| 229 chrome.brailleDisplayPrivate.writeDots( |
| 230 brailleBuf, |
| 231 this.displayState_.textColumnCount, |
| 232 this.displayState_.textRowCount); |
| 233 } |
| 234 if (cvox.BrailleCaptionsBackground.isEnabled()) { |
| 235 cvox.BrailleCaptionsBackground.setImageContent( |
| 236 brailleBuf, rows, columns); |
| 237 } |
| 238 }).bind(this); |
| 239 }; |
| 240 |
| 241 |
| 242 /** |
| 126 * Sets the command listener. When a command is invoked, the listener will be | 243 * Sets the command listener. When a command is invoked, the listener will be |
| 127 * called with the BrailleKeyEvent corresponding to the command and the content | 244 * called with the BrailleKeyEvent corresponding to the command and the content |
| 128 * that was present on the display when the command was invoked. The content | 245 * that was present on the display when the command was invoked. The content |
| 129 * is guaranteed to be identical to an object previously used as the parameter | 246 * is guaranteed to be identical to an object previously used as the parameter |
| 130 * to cvox.BrailleDisplayManager.setContent, or null if no content was set. | 247 * to cvox.BrailleDisplayManager.setContent, or null if no content was set. |
| 131 * @param {function(!cvox.BrailleKeyEvent, !cvox.NavBraille)} func The listener. | 248 * @param {function(!cvox.BrailleKeyEvent, !cvox.NavBraille)} func The listener. |
| 132 */ | 249 */ |
| 133 cvox.BrailleDisplayManager.prototype.setCommandListener = function(func) { | 250 cvox.BrailleDisplayManager.prototype.setCommandListener = function(func) { |
| 134 this.commandListener_ = func; | 251 this.commandListener_ = func; |
| 135 }; | 252 }; |
| 136 | 253 |
| 137 | 254 |
| 138 /** | 255 /** |
| 139 * @param {!cvox.BrailleDisplayState} newState Display state reported | 256 * @return {!cvox.BrailleDisplayState} The current display state. |
| 140 * by the extension API. | 257 */ |
| 258 cvox.BrailleDisplayManager.prototype.getDisplayState = function() { |
| 259 return this.displayState_; |
| 260 }; |
| 261 |
| 262 |
| 263 /** |
| 264 * @param {{available: boolean, textRowCount: (number|undefined), |
| 265 * textColumnCount: (number|undefined)}} newState Display state reported |
| 266 * by the extension API. Note that the type is almost the same as |
| 267 * cvox.BrailleDisplayState except that the extension API allows |
| 268 * some fields to be undefined, while cvox.BrailleDisplayState does not. |
| 141 * @private | 269 * @private |
| 142 */ | 270 */ |
| 143 cvox.BrailleDisplayManager.prototype.refreshDisplayState_ = function( | 271 cvox.BrailleDisplayManager.prototype.refreshDisplayState_ = function( |
| 144 newState) { | 272 newState) { |
| 145 var oldColumnCount = this.displayState_.textColumnCount || 0; | 273 var oldColumnCount = this.displayState_.textColumnCount || 0; |
| 146 var oldRowCount = this.displayState_.textRowCount || 0; | 274 var oldRowCount = this.displayState_.textRowCount || 0; |
| 147 var processDisplayState = function(displayState) { | 275 var processDisplayState = function(displayState) { |
| 148 this.displayState_ = displayState; | 276 this.displayState_ = displayState; |
| 149 var newColumnCount = displayState.textColumnCount || 0; | 277 var newColumnCount = displayState.textColumnCount || 0; |
| 150 var newRowCount = displayState.textRowCount || 0; | 278 var newRowCount = displayState.textRowCount || 0; |
| 151 | 279 |
| 152 if (oldColumnCount != newColumnCount || oldRowCount != newRowCount) { | 280 if (oldColumnCount != newColumnCount || oldRowCount != newRowCount) { |
| 153 this.panStrategy_.setDisplaySize(newRowCount, newColumnCount); | 281 this.panStrategy_.setDisplaySize(newRowCount, newColumnCount); |
| 154 } | 282 } |
| 155 this.refresh_(); | 283 this.refresh_(); |
| 156 }.bind(this); | 284 }.bind(this); |
| 157 this.realDisplayState_ = newState; | 285 this.realDisplayState_ = { |
| 286 available: newState.available, |
| 287 textRowCount: newState.textRowCount || 0, |
| 288 textColumnCount: newState.textColumnCount || 0 |
| 289 }; |
| 158 if (newState.available) { | 290 if (newState.available) { |
| 159 processDisplayState(newState); | 291 processDisplayState(newState); |
| 160 // Update the dimensions of the virtual braille captions display to those | 292 // Update the dimensions of the virtual braille captions display to those |
| 161 // of a real physical display when one is plugged in. | 293 // of a real physical display when one is plugged in. |
| 162 } else { | 294 } else { |
| 163 cvox.BrailleCaptionsBackground.getVirtualDisplayState(processDisplayState); | 295 cvox.BrailleCaptionsBackground.getVirtualDisplayState(processDisplayState); |
| 164 } | 296 } |
| 165 }; | 297 }; |
| 166 | 298 |
| 167 | 299 |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 368 }; | 500 }; |
| 369 | 501 |
| 370 /** | 502 /** |
| 371 * @param {boolean} wordWrap | 503 * @param {boolean} wordWrap |
| 372 * @private | 504 * @private |
| 373 */ | 505 */ |
| 374 cvox.BrailleDisplayManager.prototype.updatePanStrategy_ = function(wordWrap) { | 506 cvox.BrailleDisplayManager.prototype.updatePanStrategy_ = function(wordWrap) { |
| 375 this.panStrategy_.setPanStrategy(wordWrap); | 507 this.panStrategy_.setPanStrategy(wordWrap); |
| 376 this.refresh_(); | 508 this.refresh_(); |
| 377 }; | 509 }; |
| OLD | NEW |