Merge from Chromium at DEPS revision r207203
This commit was generated by merge_to_master.py.
Change-Id: I5fbb6854d092096c4d39edc2865a48be1b53c418
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_util.js b/chrome/browser/resources/file_manager/js/image_editor/image_util.js
index 33c527d..7ae773a 100644
--- a/chrome/browser/resources/file_manager/js/image_editor/image_util.js
+++ b/chrome/browser/resources/file_manager/js/image_editor/image_util.js
@@ -403,11 +403,15 @@
* 2. Copies pixels from HTMLImageElement to HTMLCanvasElement. This is done
* stripe-by-stripe to avoid freezing up the UI. The transform is taken into
* account.
+ *
* @param {HTMLDocument} document Owner document.
+ * @param {MetadataCache=} opt_metadataCache Metadata cache. Required for
+ * caching. If not passed, caching will be disabled.
* @constructor
*/
-ImageUtil.ImageLoader = function(document) {
+ImageUtil.ImageLoader = function(document, opt_metadataCache) {
this.document_ = document;
+ this.metadataCache_ = opt_metadataCache || null;
this.image_ = new Image();
this.generation_ = 0;
};
@@ -427,6 +431,10 @@
};
/**
+ * Loads an image.
+ * TODO(mtomasz): Simplify, or even get rid of this class and merge with the
+ * ThumbnaiLoader class.
+ *
* @param {string} url Image URL.
* @param {function(function(object))} transformFetcher function to get
* the image transform (which we need for the image orientation).
@@ -462,9 +470,10 @@
tmpCallback(emptyCanvas, opt_error);
}.bind(this);
- var loadImage = function() {
+ var loadImage = function(opt_metadata) {
ImageUtil.metrics.startInterval(ImageUtil.getMetricName('LoadTime'));
this.timeout_ = null;
+
this.image_.onload = function(e) {
this.image_.onerror = null;
this.image_.onload = null;
@@ -474,30 +483,32 @@
}
transformFetcher(url, onTransform.bind(this, e.target));
}.bind(this);
- // errorCallback has an optional error argument, which in case of general
- // error should not be specified
+
+ // The error callback has an optional error argument, which in case of a
+ // general error should not be specified
this.image_.onerror = onError.bind(this, 'IMAGE_ERROR');
- this.taskId_ = util.loadImage(this.image_, url, {priority: 1});
+
+ // Extract the last modification date to determine if the cached image
+ // is outdated.
+ var modificationTime = opt_metadata &&
+ opt_metadata.modificationTime &&
+ opt_metadata.modificationTime.getTime();
+
+ this.taskId_ = util.loadImage(this.image_, url, {
+ cache: true,
+ timestamp: modificationTime,
+ priority: 1
+ });
}.bind(this);
- // The clients of this class sometimes request the same url repeatedly.
- // The onload fires only if the src is different from the previous value.
- // To work around that we reset the src temporarily to an 1x1 pixel.
- // Load an empty 1x1 pixel image first.
- var resetImage = function(callback) {
- this.image_.onload = callback;
- this.image_.onerror = onError.bind(this, 'IMAGE_ERROR');
- this.image_.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAA' +
- 'AAABAAEAAAICTAEAOw==';
- }.bind(this);
-
- // Loads the image. If already loaded, then forces reloads.
- var startLoad = function() {
- if (this.image_.src == url)
- resetImage(loadImage);
+ // Loads the image. If already loaded, then forces a reload.
+ var startLoad = this.resetImage_.bind(this, function() {
+ // Fetch metadata to detect last modification time for the caching purpose.
+ if (this.metadataCache_)
+ this.metadataCache_.get(url, 'filesystem', loadImage);
else
loadImage();
- }.bind(this);
+ }.bind(this), onError);
if (opt_delay) {
this.timeout_ = setTimeout(startLoad, opt_delay);
@@ -507,6 +518,36 @@
};
/**
+ * Resets the image by forcing the garbage collection and clearing the src
+ * attribute.
+ *
+ * @param {function()} onSuccess Success callback.
+ * @param {function(opt_string)} onError Failure callback with an optional
+ * error identifier.
+ * @private
+ */
+ImageUtil.ImageLoader.prototype.resetImage_ = function(onSuccess, onError) {
+ var clearSrc = function() {
+ this.image_.onload = onSuccess;
+ this.image_.onerror = onSuccess;
+ this.image_.src = '';
+ }.bind(this);
+
+ var emptyImage = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAA' +
+ 'AAABAAEAAAICTAEAOw==';
+
+ if (this.image_.src != emptyImage) {
+ // Load an empty image, then clear src.
+ this.image_.onload = clearSrc;
+ this.image_.onerror = onError.bind(this, 'IMAGE_ERROR');
+ this.image_.src = emptyImage;
+ } else {
+ // Empty image already loaded, so clear src immediately.
+ clearSrc();
+ }
+};
+
+/**
* @return {boolean} True if an image is loading.
*/
ImageUtil.ImageLoader.prototype.isBusy = function() {