Commit 79796fe5 authored by yawano's avatar yawano Committed by Commit bot

Change ListThumbnailLoader to use ThumbnailLoader.loadAsDataUrl.

BUG=438050
TEST=out/Release/browser_tests --gtest_filter=FileManagerJsTest.ListThumbnailLoader

Review URL: https://codereview.chromium.org/895093003

Cr-Commit-Position: refs/heads/master@{#314795}
parent a9bfa5b4
......@@ -17,7 +17,7 @@
* * Done: Implement cache size limitation.
* * Done: Modest queueing for low priority thumbnail fetches.
* * Handle other event types of FileListModel, e.g. sort.
* * Change ThumbnailLoader to directly return dataUrl.
* * Done: Change ThumbnailLoader to directly return dataUrl.
* * Handle file types for which generic images are used.
*
* @param {!FileListModel} dataModel A file list model.
......@@ -65,10 +65,8 @@ function ListThumbnailLoader(
this.active_ = {};
/**
* @type {LRUCache<!Object>}
* @type {LRUCache<!ListThumbnailLoader.ThumbnailData>}
* @private
*
* TODO(yawano): After ThumbnailData class is created, type this with it.
*/
this.cache_ = new LRUCache(ListThumbnailLoader.CACHE_SIZE);
......@@ -192,13 +190,17 @@ ListThumbnailLoader.prototype.enqueue_ = function(entry) {
entry, this.metadataCache_, this.document_,
this.thumbnailLoaderConstructor_);
this.active_[entry.toURL()] = task;
var url = entry.toURL();
this.active_[url] = task;
task.fetch().then(function(thumbnail) {
delete this.active_[thumbnail.fileUrl];
this.cache_.put(thumbnail.fileUrl, thumbnail);
delete this.active_[url];
this.cache_.put(url, thumbnail);
this.dispatchThumbnailLoaded_(thumbnail);
this.continue_();
}.bind(this), function() {
delete this.active_[url];
this.continue_();
}.bind(this));
}
......@@ -217,6 +219,37 @@ ListThumbnailLoader.prototype.dispatchThumbnailLoaded_ = function(thumbnail) {
this.dispatchEvent(event);
};
/**
* A class to represent thumbnail data.
* @param {string} fileUrl File url of an original image.
* @param {string} dataUrl Data url of thumbnail.
* @param {number} width Width of thumbnail.
* @param {number} height Height of thumbnail.
* @constructor
* @struct
*/
ListThumbnailLoader.ThumbnailData = function(fileUrl, dataUrl, width, height) {
/**
* @const {string}
*/
this.fileUrl = fileUrl;
/**
* @const {string}
*/
this.dataUrl = dataUrl;
/**
* @const {number}
*/
this.width = width;
/**
* @const {number}
*/
this.height = height;
}
/**
* A task to load thumbnail.
*
......@@ -238,43 +271,20 @@ ListThumbnailLoader.Task = function(
/**
* Fetches thumbnail.
* TODO(yawano): Add error handling.
*
* @return {!Promise} A promise which is resolved when thumbnail is fetched.
* @return {!Promise<!ListThumbnailLoader.ThumbnailData>} A promise which is
* resolved when thumbnail is fetched.
*/
ListThumbnailLoader.Task.prototype.fetch = function() {
return new Promise(function(resolve, reject) {
this.metadataCache_.getOne(this.entry_,
'thumbnail|filesystem|external|media',
function(metadata) {
// TODO(yawano): Change ThumbnailLoader to directly return data url of
// an image.
var box = this.document_.createElement('div');
var thumbnailLoader = new this.thumbnailLoaderConstructor_(
this.entry_,
ThumbnailLoader.LoaderType.IMAGE,
metadata);
thumbnailLoader.load(box,
ThumbnailLoader.FillMode.FIT,
ThumbnailLoader.OptimizationMode.DISCARD_DETACHED,
function(image, transform) {
// TODO(yawano): Transform an image if necessary.
var canvas = this.document_.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
// TODO(yawano): Create ThumbnailData class.
resolve({
fileUrl: this.entry_.toURL(),
dataUrl: canvas.toDataURL('image/jpeg', 0.5),
width: image.width,
height: image.height
});
}.bind(this));
}.bind(this));
this.metadataCache_.getOne(
this.entry_, 'thumbnail|filesystem|external|media', resolve);
}.bind(this)).then(function(metadata) {
return new this.thumbnailLoaderConstructor_(
this.entry_, ThumbnailLoader.LoaderType.IMAGE, metadata)
.loadAsDataUrl();
}.bind(this)).then(function(result) {
return new ListThumbnailLoader.ThumbnailData(
this.entry_.toURL(), result.data, result.width, result.height);
}.bind(this));
}
......@@ -58,7 +58,10 @@ function setUp() {
ListThumbnailLoader.NUM_OF_MAX_ACTIVE_TASKS = 2;
ListThumbnailLoader.NUM_OF_PREFETCH = 1;
ListThumbnailLoader.CACHE_SIZE = 5;
MockThumbnailLoader.setTestImageDataUrl(generateSampleImageDataUrl(document));
MockThumbnailLoader.errorUrls = [];
MockThumbnailLoader.testImageDataUrl = generateSampleImageDataUrl(document);
MockThumbnailLoader.testImageWidth = 160;
MockThumbnailLoader.testImageHeight = 160;
getOneCallbacks = {};
var metadataCache = {
......@@ -221,3 +224,21 @@ function testCache(callback) {
});
}), callback);
}
/**
* Test case for thumbnail fetch error. In this test case, thumbnail fetch for
* entry 2 is failed.
*/
function testErrorHandling(callback) {
MockThumbnailLoader.errorUrls = [entry2.toURL()];
listThumbnailLoader.setHighPriorityRange(0, 2);
fileListModel.push(entry1, entry2, entry3, entry4);
resolveGetOneCallback(entry2.toURL());
// Assert that new task is enqueued for entry3.
reportPromise(waitUntil(function() {
return !!getOneCallbacks[entry3.toURL()];
}), callback);
}
......@@ -14,43 +14,46 @@
*/
function MockThumbnailLoader(entry, opt_loaderType, opt_metadata, opt_mediaType,
opt_loadTargets, opt_priority) {
this.testImageDataUrl_ = null;
this.entry_ = entry;
}
/**
* @type {string} Data url of an image.
* Data url of test image.
* @private {string}
*/
MockThumbnailLoader.testImageDataUrl_ = null;
MockThumbnailLoader.testImageDataUrl = null;
/**
* Set data url of an image which is returned for testing.
*
* @param {string} dataUrl Data url of an image.
* Width of test image.
* @private {number}
*/
MockThumbnailLoader.setTestImageDataUrl = function(dataUrl) {
MockThumbnailLoader.testImageDataUrl_ = dataUrl;
};
MockThumbnailLoader.testImageWidth = 0;
/**
* Height of test image.
* @private {number}
*/
MockThumbnailLoader.testImageHeight = 0;
/**
* Load an image. (This mock implementation does not attach an image to the
* box).
* Error urls.
* @private {Array<string>}
*/
MockThumbnailLoader.errorUrls = [];
/**
* Loads thumbnail as data url.
*
* @param {Element} box Box.
* @param {ThumbnailLoader.FillMode} fillMode Fill mode.
* @param {ThumbnailLoader.OptimizationMode=} opt_optimizationMode Optimization.
* @param {function(Image, Object)=} opt_onSuccess Success callback.
* @param {function()=} opt_onError Error callback.
* @param {function()=} opt_onGeneric Callback which is called when generic
* image is used.
* @return {!Promise<{data:string, width:number, height:number}>} A promise
* which is resolved with data url.
*/
MockThumbnailLoader.prototype.load = function(
box, fillMode, opt_optimizationMode, opt_onSuccess, opt_onError,
opt_onGeneric) {
if (opt_onSuccess && MockThumbnailLoader.testImageDataUrl_) {
var image = new Image();
image.onload = function() {
opt_onSuccess(image, null);
};
image.src = MockThumbnailLoader.testImageDataUrl_;
}
MockThumbnailLoader.prototype.loadAsDataUrl = function() {
if (MockThumbnailLoader.errorUrls.indexOf(this.entry_.toURL()) !== -1)
throw new Error('Failed to load thumbnail.');
return Promise.resolve({
data: MockThumbnailLoader.testImageDataUrl,
width: MockThumbnailLoader.testImageWidth,
height: MockThumbnailLoader.testImageHeight
});
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment