Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / resources / image_loader / image_loader.js
bloba353627151aa4297b0968d2eaddad3da91100f48
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
3 // found in the LICENSE file.
5 'use strict';
7 /**
8  * Loads and resizes an image.
9  * @constructor
10  */
11 function ImageLoader() {
12   /**
13    * Persistent cache object.
14    * @type {Cache}
15    * @private
16    */
17   this.cache_ = new Cache();
19   /**
20    * Manages pending requests and runs them in order of priorities.
21    * @type {Worker}
22    * @private
23    */
24   this.worker_ = new Worker();
26   // Grant permissions to the local file system and initialize the cache.
27   chrome.fileBrowserPrivate.requestFileSystem(
28     'compatible',
29     function(filesystem) {
30       this.cache_.initialize(function() {
31         this.worker_.start();
32       }.bind(this));
33     }.bind(this));
35   chrome.extension.onMessageExternal.addListener(function(request,
36                                                           sender,
37                                                           sendResponse) {
38     if (ImageLoader.ALLOWED_CLIENTS.indexOf(sender.id) !== -1) {
39       // Sending a response may fail if the receiver already went offline.
40       // This is not an error, but a normal and quite common situation.
41       var failSafeSendResponse = function(response) {
42         try {
43           sendResponse(response);
44         }
45         catch (e) {
46           // Ignore the error.
47         }
48       };
49       return this.onMessage_(sender.id, request, failSafeSendResponse);
50     }
51   }.bind(this));
54 /**
55  * List of extensions allowed to perform image requests.
56  *
57  * @const
58  * @type {Array.<string>}
59  */
60 ImageLoader.ALLOWED_CLIENTS =
61     ['hhaomjibdihmijegdhdafkllkbggdgoj'];  // File Manager's extension id.
63 /**
64  * Handles a request. Depending on type of the request, starts or stops
65  * an image task.
66  *
67  * @param {string} senderId Sender's extension id.
68  * @param {Object} request Request message as a hash array.
69  * @param {function} callback Callback to be called to return response.
70  * @return {boolean} True if the message channel should stay alive until the
71  *     callback is called.
72  * @private
73  */
74 ImageLoader.prototype.onMessage_ = function(senderId, request, callback) {
75   var requestId = senderId + ':' + request.taskId;
76   if (request.cancel) {
77     // Cancel a task.
78     this.worker_.remove(requestId);
79     return false;  // No callback calls.
80   } else {
81     // Create a request task and add it to the worker (queue).
82     var requestTask = new Request(requestId, this.cache_, request, callback);
83     this.worker_.add(requestTask);
84     return true;  // Request will call the callback.
85   }
88 /**
89  * Returns the singleton instance.
90  * @return {ImageLoader} ImageLoader object.
91  */
92 ImageLoader.getInstance = function() {
93   if (!ImageLoader.instance_)
94     ImageLoader.instance_ = new ImageLoader();
95   return ImageLoader.instance_;
98 /**
99  * Checks if the options contain any image processing.
101  * @param {number} width Source width.
102  * @param {number} height Source height.
103  * @param {Object} options Resizing options as a hash array.
104  * @return {boolean} True if yes, false if not.
105  */
106 ImageLoader.shouldProcess = function(width, height, options) {
107   var targetDimensions = ImageLoader.resizeDimensions(width, height, options);
109   // Dimensions has to be adjusted.
110   if (targetDimensions.width != width || targetDimensions.height != height)
111     return true;
113   // Orientation has to be adjusted.
114   if (options.orientation)
115     return true;
117   // No changes required.
118   return false;
122  * Calculates dimensions taking into account resize options, such as:
123  * - scale: for scaling,
124  * - maxWidth, maxHeight: for maximum dimensions,
125  * - width, height: for exact requested size.
126  * Returns the target size as hash array with width, height properties.
128  * @param {number} width Source width.
129  * @param {number} height Source height.
130  * @param {Object} options Resizing options as a hash array.
131  * @return {Object} Dimensions, eg. {width: 100, height: 50}.
132  */
133 ImageLoader.resizeDimensions = function(width, height, options) {
134   var sourceWidth = width;
135   var sourceHeight = height;
137   // Flip dimensions for odd orientation values: 1 (90deg) and 3 (270deg).
138   if (options.orientation && options.orientation % 2) {
139     sourceWidth = height;
140     sourceHeight = width;
141   }
143   var targetWidth = sourceWidth;
144   var targetHeight = sourceHeight;
146   if ('scale' in options) {
147     targetWidth = sourceWidth * options.scale;
148     targetHeight = sourceHeight * options.scale;
149   }
151   if (options.maxWidth &&
152       targetWidth > options.maxWidth) {
153       var scale = options.maxWidth / targetWidth;
154       targetWidth *= scale;
155       targetHeight *= scale;
156   }
158   if (options.maxHeight &&
159       targetHeight > options.maxHeight) {
160       var scale = options.maxHeight / targetHeight;
161       targetWidth *= scale;
162       targetHeight *= scale;
163   }
165   if (options.width)
166     targetWidth = options.width;
168   if (options.height)
169     targetHeight = options.height;
171   targetWidth = Math.round(targetWidth);
172   targetHeight = Math.round(targetHeight);
174   return {width: targetWidth, height: targetHeight};
178  * Performs resizing of the source image into the target canvas.
180  * @param {HTMLCanvasElement|Image} source Source image or canvas.
181  * @param {HTMLCanvasElement} target Target canvas.
182  * @param {Object} options Resizing options as a hash array.
183  */
184 ImageLoader.resize = function(source, target, options) {
185   var targetDimensions = ImageLoader.resizeDimensions(
186       source.width, source.height, options);
188   target.width = targetDimensions.width;
189   target.height = targetDimensions.height;
191   // Default orientation is 0deg.
192   var orientation = options.orientation || 0;
194   // For odd orientation values: 1 (90deg) and 3 (270deg) flip dimensions.
195   var drawImageWidth;
196   var drawImageHeight;
197   if (orientation % 2) {
198     drawImageWidth = target.height;
199     drawImageHeight = target.width;
200   } else {
201     drawImageWidth = target.width;
202     drawImageHeight = target.height;
203   }
205   var targetContext = target.getContext('2d');
206   targetContext.save();
207   targetContext.translate(target.width / 2, target.height / 2);
208   targetContext.rotate(orientation * Math.PI / 2);
209   targetContext.drawImage(
210       source,
211       0, 0,
212       source.width, source.height,
213       -drawImageWidth / 2, -drawImageHeight / 2,
214       drawImageWidth, drawImageHeight);
215   targetContext.restore();