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 |