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 * Persistent cache storing images in an indexed database on the hard disk. | 6 * Persistent cache storing images in an indexed database on the hard disk. |
7 * @constructor | 7 * @constructor |
8 */ | 8 */ |
9 function Cache() { | 9 function Cache() { |
10 /** | 10 /** |
11 * IndexedDB database handle. | 11 * IndexedDB database handle. |
12 * @type {IDBDatabase} | 12 * @type {IDBDatabase} |
13 * @private | 13 * @private |
14 */ | 14 */ |
15 this.db_ = null; | 15 this.db_ = null; |
16 } | 16 } |
17 | 17 |
18 /** | 18 /** |
19 * Cache database name. | 19 * Cache database name. |
20 * @type {string} | 20 * @type {string} |
21 * @const | 21 * @const |
22 */ | 22 */ |
23 Cache.DB_NAME = 'image-loader'; | 23 Cache.DB_NAME = 'image-loader'; |
24 | 24 |
25 /** | 25 /** |
26 * Cache database version. | 26 * Cache database version. |
27 * @type {number} | 27 * @type {number} |
28 * @const | 28 * @const |
29 */ | 29 */ |
30 Cache.DB_VERSION = 11; | 30 Cache.DB_VERSION = 12; |
31 | 31 |
32 /** | 32 /** |
33 * Memory limit for images data in bytes. | 33 * Memory limit for images data in bytes. |
34 * | 34 * |
35 * @const | 35 * @const |
36 * @type {number} | 36 * @type {number} |
37 */ | 37 */ |
38 Cache.MEMORY_LIMIT = 250 * 1024 * 1024; // 250 MB. | 38 Cache.MEMORY_LIMIT = 250 * 1024 * 1024; // 250 MB. |
39 | 39 |
40 /** | 40 /** |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 }.bind(this); | 208 }.bind(this); |
209 | 209 |
210 this.fetchCacheSize_(onCacheSize, onFailure, transaction); | 210 this.fetchCacheSize_(onCacheSize, onFailure, transaction); |
211 }; | 211 }; |
212 | 212 |
213 /** | 213 /** |
214 * Saves an image in the cache. | 214 * Saves an image in the cache. |
215 * | 215 * |
216 * @param {string} key Cache key. | 216 * @param {string} key Cache key. |
217 * @param {string} data Image data. | 217 * @param {string} data Image data. |
| 218 * @param {number} width Image width. |
| 219 * @param {number} height Image height. |
218 * @param {number} timestamp Last modification timestamp. Used to detect | 220 * @param {number} timestamp Last modification timestamp. Used to detect |
219 * if the cache entry becomes out of date. | 221 * if the cache entry becomes out of date. |
220 */ | 222 */ |
221 Cache.prototype.saveImage = function(key, data, timestamp) { | 223 Cache.prototype.saveImage = function(key, data, width, height, timestamp) { |
222 if (!this.db_) { | 224 if (!this.db_) { |
223 console.warn('Cache database not available.'); | 225 console.warn('Cache database not available.'); |
224 return; | 226 return; |
225 } | 227 } |
226 | 228 |
227 var onNotFoundInCache = function() { | 229 var onNotFoundInCache = function() { |
228 var metadataEntry = { | 230 var metadataEntry = { |
229 key: key, | 231 key: key, |
230 timestamp: timestamp, | 232 timestamp: timestamp, |
| 233 width: width, |
| 234 height: height, |
231 size: data.length, | 235 size: data.length, |
232 lastLoadTimestamp: Date.now()}; | 236 lastLoadTimestamp: Date.now()}; |
233 var dataEntry = {key: key, data: data}; | 237 var dataEntry = {key: key, data: data}; |
234 | 238 |
235 var transaction = this.db_.transaction(['settings', 'metadata', 'data'], | 239 var transaction = this.db_.transaction(['settings', 'metadata', 'data'], |
236 'readwrite'); | 240 'readwrite'); |
237 var metadataStore = transaction.objectStore('metadata'); | 241 var metadataStore = transaction.objectStore('metadata'); |
238 var dataStore = transaction.objectStore('data'); | 242 var dataStore = transaction.objectStore('data'); |
239 | 243 |
240 var onCacheEvicted = function() { | 244 var onCacheEvicted = function() { |
241 metadataStore.put(metadataEntry); // Add asynchronously. | 245 metadataStore.put(metadataEntry); // Add asynchronously. |
242 dataStore.put(dataEntry); // Add asynchronously. | 246 dataStore.put(dataEntry); // Add asynchronously. |
243 }; | 247 }; |
244 | 248 |
245 // Make sure there is enough space in the cache. | 249 // Make sure there is enough space in the cache. |
246 this.evictCache_(data.length, onCacheEvicted, function() {}, transaction); | 250 this.evictCache_(data.length, onCacheEvicted, function() {}, transaction); |
247 }.bind(this); | 251 }.bind(this); |
248 | 252 |
249 // Check if the image is already in cache. If not, then save it to cache. | 253 // Check if the image is already in cache. If not, then save it to cache. |
250 this.loadImage(key, timestamp, function() {}, onNotFoundInCache); | 254 this.loadImage(key, timestamp, function() {}, onNotFoundInCache); |
251 }; | 255 }; |
252 | 256 |
253 /** | 257 /** |
254 * Loads an image from the cache (if available) or returns null. | 258 * Loads an image from the cache (if available) or returns null. |
255 * | 259 * |
256 * @param {string} key Cache key. | 260 * @param {string} key Cache key. |
257 * @param {number} timestamp Last modification timestamp. If different | 261 * @param {number} timestamp Last modification timestamp. If different |
258 * that the one in cache, then the entry will be invalidated. | 262 * that the one in cache, then the entry will be invalidated. |
259 * @param {function(string)} onSuccess Success callback with the image's data. | 263 * @param {function(string, number, number)} onSuccess Success callback with |
| 264 * the image's data, width, height. |
260 * @param {function()} onFailure Failure callback. | 265 * @param {function()} onFailure Failure callback. |
261 */ | 266 */ |
262 Cache.prototype.loadImage = function(key, timestamp, onSuccess, onFailure) { | 267 Cache.prototype.loadImage = function(key, timestamp, onSuccess, onFailure) { |
263 if (!this.db_) { | 268 if (!this.db_) { |
264 console.warn('Cache database not available.'); | 269 console.warn('Cache database not available.'); |
265 onFailure(); | 270 onFailure(); |
266 return; | 271 return; |
267 } | 272 } |
268 | 273 |
269 var transaction = this.db_.transaction(['settings', 'metadata', 'data'], | 274 var transaction = this.db_.transaction(['settings', 'metadata', 'data'], |
(...skipping 26 matching lines...) Expand all Loading... |
296 onFailure(); | 301 onFailure(); |
297 } else if (metadataEntry.timestamp != timestamp) { | 302 } else if (metadataEntry.timestamp != timestamp) { |
298 // The image is not up to date, so remove it. | 303 // The image is not up to date, so remove it. |
299 this.removeImage(key, function() {}, function() {}, transaction); | 304 this.removeImage(key, function() {}, function() {}, transaction); |
300 onFailure(); | 305 onFailure(); |
301 } else { | 306 } else { |
302 // The image is available. Update the last load time and return the | 307 // The image is available. Update the last load time and return the |
303 // image data. | 308 // image data. |
304 metadataEntry.lastLoadTimestamp = Date.now(); | 309 metadataEntry.lastLoadTimestamp = Date.now(); |
305 metadataStore.put(metadataEntry); // Added asynchronously. | 310 metadataStore.put(metadataEntry); // Added asynchronously. |
306 onSuccess(dataEntry.data); | 311 onSuccess(dataEntry.data, metadataEntry.width, metadataEntry.height); |
307 } | 312 } |
308 }.bind(this); | 313 }.bind(this); |
309 | 314 |
310 metadataRequest.onsuccess = function(e) { | 315 metadataRequest.onsuccess = function(e) { |
311 if (e.target.result) | 316 if (e.target.result) |
312 metadataEntry = e.target.result; | 317 metadataEntry = e.target.result; |
313 metadataReceived = true; | 318 metadataReceived = true; |
314 onPartialSuccess(); | 319 onPartialSuccess(); |
315 }; | 320 }; |
316 | 321 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 metadataReceived = true; | 407 metadataReceived = true; |
403 onPartialSuccess(); | 408 onPartialSuccess(); |
404 }; | 409 }; |
405 | 410 |
406 metadataRequest.onerror = function() { | 411 metadataRequest.onerror = function() { |
407 console.error('Failed to remove an image.'); | 412 console.error('Failed to remove an image.'); |
408 metadataReceived = true; | 413 metadataReceived = true; |
409 onPartialSuccess(); | 414 onPartialSuccess(); |
410 }; | 415 }; |
411 }; | 416 }; |
OLD | NEW |