| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 * @typedef {{ | 6 * @typedef {{ |
| 7 * cache: (boolean|undefined), | 7 * cache: (boolean|undefined), |
| 8 * priority: (number|undefined), | 8 * priority: (number|undefined), |
| 9 * taskId: number, | 9 * taskId: number, |
| 10 * timestamp: (number|undefined), | 10 * timestamp: (number|undefined), |
| 11 * url: string, | 11 * url: string, |
| 12 * orientation: ImageOrientation, | 12 * orientation: ImageOrientation, |
| 13 * colorSpace: ?ColorSpace | 13 * colorSpace: ?ColorSpace |
| 14 * }} | 14 * }} |
| 15 */ | 15 */ |
| 16 var LoadImageRequest; | 16 var LoadImageRequest; |
| 17 | 17 |
| 18 /** | 18 /** |
| 19 * Creates and starts downloading and then resizing of the image. Finally, | 19 * Creates and starts downloading and then resizing of the image. Finally, |
| 20 * returns the image using the callback. | 20 * returns the image using the callback. |
| 21 * | 21 * |
| 22 * @param {string} id Request ID. | 22 * @param {string} id Request ID. |
| 23 * @param {Cache} cache Cache object. | 23 * @param {ImageCache} cache Cache object. |
| 24 * @param {!PiexLoader} piexLoader Piex loader for RAW file. | 24 * @param {!PiexLoader} piexLoader Piex loader for RAW file. |
| 25 * @param {LoadImageRequest} request Request message as a hash array. | 25 * @param {LoadImageRequest} request Request message as a hash array. |
| 26 * @param {function(Object)} callback Callback used to send the response. | 26 * @param {function(Object)} callback Callback used to send the response. |
| 27 * @constructor | 27 * @constructor |
| 28 */ | 28 */ |
| 29 function Request(id, cache, piexLoader, request, callback) { | 29 function ImageRequest(id, cache, piexLoader, request, callback) { |
| 30 /** | 30 /** |
| 31 * @type {string} | 31 * @type {string} |
| 32 * @private | 32 * @private |
| 33 */ | 33 */ |
| 34 this.id_ = id; | 34 this.id_ = id; |
| 35 | 35 |
| 36 /** | 36 /** |
| 37 * @type {Cache} | 37 * @type {ImageCache} |
| 38 * @private | 38 * @private |
| 39 */ | 39 */ |
| 40 this.cache_ = cache; | 40 this.cache_ = cache; |
| 41 | 41 |
| 42 /** | 42 /** |
| 43 * @type {!PiexLoader} | 43 * @type {!PiexLoader} |
| 44 * @private | 44 * @private |
| 45 */ | 45 */ |
| 46 this.piexLoader_ = piexLoader; | 46 this.piexLoader_ = piexLoader; |
| 47 | 47 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 * @type {?function()} | 98 * @type {?function()} |
| 99 * @private | 99 * @private |
| 100 */ | 100 */ |
| 101 this.downloadCallback_ = null; | 101 this.downloadCallback_ = null; |
| 102 } | 102 } |
| 103 | 103 |
| 104 /** | 104 /** |
| 105 * Returns ID of the request. | 105 * Returns ID of the request. |
| 106 * @return {string} Request ID. | 106 * @return {string} Request ID. |
| 107 */ | 107 */ |
| 108 Request.prototype.getId = function() { | 108 ImageRequest.prototype.getId = function() { |
| 109 return this.id_; | 109 return this.id_; |
| 110 }; | 110 }; |
| 111 | 111 |
| 112 /** | 112 /** |
| 113 * Returns priority of the request. The higher priority, the faster it will | 113 * Returns priority of the request. The higher priority, the faster it will |
| 114 * be handled. The highest priority is 0. The default one is 2. | 114 * be handled. The highest priority is 0. The default one is 2. |
| 115 * | 115 * |
| 116 * @return {number} Priority. | 116 * @return {number} Priority. |
| 117 */ | 117 */ |
| 118 Request.prototype.getPriority = function() { | 118 ImageRequest.prototype.getPriority = function() { |
| 119 return (this.request_.priority !== undefined) ? this.request_.priority : 2; | 119 return (this.request_.priority !== undefined) ? this.request_.priority : 2; |
| 120 }; | 120 }; |
| 121 | 121 |
| 122 /** | 122 /** |
| 123 * Tries to load the image from cache if exists and sends the response. | 123 * Tries to load the image from cache if exists and sends the response. |
| 124 * | 124 * |
| 125 * @param {function()} onSuccess Success callback. | 125 * @param {function()} onSuccess Success callback. |
| 126 * @param {function()} onFailure Failure callback. | 126 * @param {function()} onFailure Failure callback. |
| 127 */ | 127 */ |
| 128 Request.prototype.loadFromCacheAndProcess = function(onSuccess, onFailure) { | 128 ImageRequest.prototype.loadFromCacheAndProcess = function( |
| 129 onSuccess, onFailure) { |
| 129 this.loadFromCache_( | 130 this.loadFromCache_( |
| 130 function(data, width, height) { // Found in cache. | 131 function(data, width, height) { // Found in cache. |
| 131 this.sendImageData_(data, width, height); | 132 this.sendImageData_(data, width, height); |
| 132 onSuccess(); | 133 onSuccess(); |
| 133 }.bind(this), | 134 }.bind(this), |
| 134 onFailure); // Not found in cache. | 135 onFailure); // Not found in cache. |
| 135 }; | 136 }; |
| 136 | 137 |
| 137 /** | 138 /** |
| 138 * Tries to download the image, resizes and sends the response. | 139 * Tries to download the image, resizes and sends the response. |
| 139 * @param {function()} callback Completion callback. | 140 * @param {function()} callback Completion callback. |
| 140 */ | 141 */ |
| 141 Request.prototype.downloadAndProcess = function(callback) { | 142 ImageRequest.prototype.downloadAndProcess = function(callback) { |
| 142 if (this.downloadCallback_) | 143 if (this.downloadCallback_) |
| 143 throw new Error('Downloading already started.'); | 144 throw new Error('Downloading already started.'); |
| 144 | 145 |
| 145 this.downloadCallback_ = callback; | 146 this.downloadCallback_ = callback; |
| 146 this.downloadOriginal_(this.onImageLoad_.bind(this), | 147 this.downloadOriginal_(this.onImageLoad_.bind(this), |
| 147 this.onImageError_.bind(this)); | 148 this.onImageError_.bind(this)); |
| 148 }; | 149 }; |
| 149 | 150 |
| 150 /** | 151 /** |
| 151 * Fetches the image from the persistent cache. | 152 * Fetches the image from the persistent cache. |
| 152 * | 153 * |
| 153 * @param {function(string, number, number)} onSuccess Success callback. | 154 * @param {function(string, number, number)} onSuccess Success callback. |
| 154 * @param {function()} onFailure Failure callback. | 155 * @param {function()} onFailure Failure callback. |
| 155 * @private | 156 * @private |
| 156 */ | 157 */ |
| 157 Request.prototype.loadFromCache_ = function(onSuccess, onFailure) { | 158 ImageRequest.prototype.loadFromCache_ = function(onSuccess, onFailure) { |
| 158 var cacheKey = Cache.createKey(this.request_); | 159 var cacheKey = ImageCache.createKey(this.request_); |
| 159 | 160 |
| 160 if (!cacheKey) { | 161 if (!cacheKey) { |
| 161 // Cache key is not provided for the request. | 162 // Cache key is not provided for the request. |
| 162 onFailure(); | 163 onFailure(); |
| 163 return; | 164 return; |
| 164 } | 165 } |
| 165 | 166 |
| 166 if (!this.request_.cache) { | 167 if (!this.request_.cache) { |
| 167 // Cache is disabled for this request; therefore, remove it from cache | 168 // Cache is disabled for this request; therefore, remove it from cache |
| 168 // if existed. | 169 // if existed. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 184 }; | 185 }; |
| 185 | 186 |
| 186 /** | 187 /** |
| 187 * Saves the image to the persistent cache. | 188 * Saves the image to the persistent cache. |
| 188 * | 189 * |
| 189 * @param {string} data The image's data. | 190 * @param {string} data The image's data. |
| 190 * @param {number} width Image width. | 191 * @param {number} width Image width. |
| 191 * @param {number} height Image height. | 192 * @param {number} height Image height. |
| 192 * @private | 193 * @private |
| 193 */ | 194 */ |
| 194 Request.prototype.saveToCache_ = function(data, width, height) { | 195 ImageRequest.prototype.saveToCache_ = function(data, width, height) { |
| 195 if (!this.request_.cache || !this.request_.timestamp) { | 196 if (!this.request_.cache || !this.request_.timestamp) { |
| 196 // Persistent cache is available only when a timestamp is provided. | 197 // Persistent cache is available only when a timestamp is provided. |
| 197 return; | 198 return; |
| 198 } | 199 } |
| 199 | 200 |
| 200 var cacheKey = Cache.createKey(this.request_); | 201 var cacheKey = ImageCache.createKey(this.request_); |
| 201 if (!cacheKey) { | 202 if (!cacheKey) { |
| 202 // Cache key is not provided for the request. | 203 // Cache key is not provided for the request. |
| 203 return; | 204 return; |
| 204 } | 205 } |
| 205 | 206 |
| 206 this.cache_.saveImage(cacheKey, | 207 this.cache_.saveImage(cacheKey, |
| 207 data, | 208 data, |
| 208 width, | 209 width, |
| 209 height, | 210 height, |
| 210 this.request_.timestamp); | 211 this.request_.timestamp); |
| 211 }; | 212 }; |
| 212 | 213 |
| 213 /** | 214 /** |
| 214 * Downloads an image directly or for remote resources using the XmlHttpRequest. | 215 * Downloads an image directly or for remote resources using the XmlHttpRequest. |
| 215 * | 216 * |
| 216 * @param {function()} onSuccess Success callback. | 217 * @param {function()} onSuccess Success callback. |
| 217 * @param {function()} onFailure Failure callback. | 218 * @param {function()} onFailure Failure callback. |
| 218 * @private | 219 * @private |
| 219 */ | 220 */ |
| 220 Request.prototype.downloadOriginal_ = function(onSuccess, onFailure) { | 221 ImageRequest.prototype.downloadOriginal_ = function(onSuccess, onFailure) { |
| 221 this.image_.onload = function() { | 222 this.image_.onload = function() { |
| 222 URL.revokeObjectURL(this.image_.src); | 223 URL.revokeObjectURL(this.image_.src); |
| 223 onSuccess(); | 224 onSuccess(); |
| 224 }.bind(this); | 225 }.bind(this); |
| 225 this.image_.onerror = function() { | 226 this.image_.onerror = function() { |
| 226 URL.revokeObjectURL(this.image_.src); | 227 URL.revokeObjectURL(this.image_.src); |
| 227 onFailure(); | 228 onFailure(); |
| 228 }.bind(this); | 229 }.bind(this); |
| 229 | 230 |
| 230 // Download data urls directly since they are not supported by XmlHttpRequest. | 231 // Download data urls directly since they are not supported by XmlHttpRequest. |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 return xhr; | 421 return xhr; |
| 421 }; | 422 }; |
| 422 | 423 |
| 423 /** | 424 /** |
| 424 * Sends the resized image via the callback. If the image has been changed, | 425 * Sends the resized image via the callback. If the image has been changed, |
| 425 * then packs the canvas contents, otherwise sends the raw image data. | 426 * then packs the canvas contents, otherwise sends the raw image data. |
| 426 * | 427 * |
| 427 * @param {boolean} imageChanged Whether the image has been changed. | 428 * @param {boolean} imageChanged Whether the image has been changed. |
| 428 * @private | 429 * @private |
| 429 */ | 430 */ |
| 430 Request.prototype.sendImage_ = function(imageChanged) { | 431 ImageRequest.prototype.sendImage_ = function(imageChanged) { |
| 431 var imageData; | 432 var imageData; |
| 432 var width; | 433 var width; |
| 433 var height; | 434 var height; |
| 434 if (!imageChanged) { | 435 if (!imageChanged) { |
| 435 // The image hasn't been processed, so the raw data can be directly | 436 // The image hasn't been processed, so the raw data can be directly |
| 436 // forwarded for speed (no need to encode the image again). | 437 // forwarded for speed (no need to encode the image again). |
| 437 imageData = this.image_.src; | 438 imageData = this.image_.src; |
| 438 width = this.image_.width; | 439 width = this.image_.width; |
| 439 height = this.image_.height; | 440 height = this.image_.height; |
| 440 } else { | 441 } else { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 461 this.saveToCache_(imageData, width, height); | 462 this.saveToCache_(imageData, width, height); |
| 462 }; | 463 }; |
| 463 | 464 |
| 464 /** | 465 /** |
| 465 * Sends the resized image via the callback. | 466 * Sends the resized image via the callback. |
| 466 * @param {string} data Compressed image data. | 467 * @param {string} data Compressed image data. |
| 467 * @param {number} width Width. | 468 * @param {number} width Width. |
| 468 * @param {number} height Height. | 469 * @param {number} height Height. |
| 469 * @private | 470 * @private |
| 470 */ | 471 */ |
| 471 Request.prototype.sendImageData_ = function(data, width, height) { | 472 ImageRequest.prototype.sendImageData_ = function(data, width, height) { |
| 472 this.sendResponse_({ | 473 this.sendResponse_({ |
| 473 status: 'success', data: data, width: width, height: height, | 474 status: 'success', data: data, width: width, height: height, |
| 474 taskId: this.request_.taskId | 475 taskId: this.request_.taskId |
| 475 }); | 476 }); |
| 476 }; | 477 }; |
| 477 | 478 |
| 478 /** | 479 /** |
| 479 * Handler, when contents are loaded into the image element. Performs resizing | 480 * Handler, when contents are loaded into the image element. Performs resizing |
| 480 * and finalizes the request process. | 481 * and finalizes the request process. |
| 481 * @private | 482 * @private |
| 482 */ | 483 */ |
| 483 Request.prototype.onImageLoad_ = function() { | 484 ImageRequest.prototype.onImageLoad_ = function() { |
| 484 // Perform processing if the url is not a data url, or if there are some | 485 // Perform processing if the url is not a data url, or if there are some |
| 485 // operations requested. | 486 // operations requested. |
| 486 if (!this.request_.url.match(/^data/) || | 487 if (!this.request_.url.match(/^data/) || |
| 487 ImageLoader.shouldProcess(this.image_.width, | 488 ImageLoader.shouldProcess(this.image_.width, |
| 488 this.image_.height, | 489 this.image_.height, |
| 489 this.request_)) { | 490 this.request_)) { |
| 490 ImageLoader.resizeAndCrop(this.image_, this.canvas_, this.request_); | 491 ImageLoader.resizeAndCrop(this.image_, this.canvas_, this.request_); |
| 491 ImageLoader.convertColorSpace( | 492 ImageLoader.convertColorSpace( |
| 492 this.canvas_, this.request_.colorSpace || ColorSpace.SRGB); | 493 this.canvas_, this.request_.colorSpace || ColorSpace.SRGB); |
| 493 this.sendImage_(true); // Image changed. | 494 this.sendImage_(true); // Image changed. |
| 494 } else { | 495 } else { |
| 495 this.sendImage_(false); // Image not changed. | 496 this.sendImage_(false); // Image not changed. |
| 496 } | 497 } |
| 497 this.cleanup_(); | 498 this.cleanup_(); |
| 498 this.downloadCallback_(); | 499 this.downloadCallback_(); |
| 499 }; | 500 }; |
| 500 | 501 |
| 501 /** | 502 /** |
| 502 * Handler, when loading of the image fails. Sends a failure response and | 503 * Handler, when loading of the image fails. Sends a failure response and |
| 503 * finalizes the request process. | 504 * finalizes the request process. |
| 504 * @private | 505 * @private |
| 505 */ | 506 */ |
| 506 Request.prototype.onImageError_ = function() { | 507 ImageRequest.prototype.onImageError_ = function() { |
| 507 this.sendResponse_( | 508 this.sendResponse_( |
| 508 {status: 'error', taskId: this.request_.taskId}); | 509 {status: 'error', taskId: this.request_.taskId}); |
| 509 this.cleanup_(); | 510 this.cleanup_(); |
| 510 this.downloadCallback_(); | 511 this.downloadCallback_(); |
| 511 }; | 512 }; |
| 512 | 513 |
| 513 /** | 514 /** |
| 514 * Cancels the request. | 515 * Cancels the request. |
| 515 */ | 516 */ |
| 516 Request.prototype.cancel = function() { | 517 ImageRequest.prototype.cancel = function() { |
| 517 this.cleanup_(); | 518 this.cleanup_(); |
| 518 | 519 |
| 519 // If downloading has started, then call the callback. | 520 // If downloading has started, then call the callback. |
| 520 if (this.downloadCallback_) | 521 if (this.downloadCallback_) |
| 521 this.downloadCallback_(); | 522 this.downloadCallback_(); |
| 522 }; | 523 }; |
| 523 | 524 |
| 524 /** | 525 /** |
| 525 * Cleans up memory used by this request. | 526 * Cleans up memory used by this request. |
| 526 * @private | 527 * @private |
| 527 */ | 528 */ |
| 528 Request.prototype.cleanup_ = function() { | 529 ImageRequest.prototype.cleanup_ = function() { |
| 529 this.image_.onerror = function() {}; | 530 this.image_.onerror = function() {}; |
| 530 this.image_.onload = function() {}; | 531 this.image_.onload = function() {}; |
| 531 | 532 |
| 532 // Transparent 1x1 pixel gif, to force garbage collecting. | 533 // Transparent 1x1 pixel gif, to force garbage collecting. |
| 533 this.image_.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAA' + | 534 this.image_.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAA' + |
| 534 'ABAAEAAAICTAEAOw=='; | 535 'ABAAEAAAICTAEAOw=='; |
| 535 | 536 |
| 536 this.xhr_.onload = function() {}; | 537 this.xhr_.onload = function() {}; |
| 537 this.xhr_.abort(); | 538 this.xhr_.abort(); |
| 538 | 539 |
| 539 // Dispose memory allocated by Canvas. | 540 // Dispose memory allocated by Canvas. |
| 540 this.canvas_.width = 0; | 541 this.canvas_.width = 0; |
| 541 this.canvas_.height = 0; | 542 this.canvas_.height = 0; |
| 542 }; | 543 }; |
| OLD | NEW |