| 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 |