Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(117)

Side by Side Diff: ui/file_manager/gallery/js/image_editor/image_loader.js

Issue 2678723002: Compile several targets in Gallery in gyp v2. (Closed)
Patch Set: Rebased. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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.
4
5 /**
6 * ImageLoader loads an image from a given Entry into a canvas in two steps:
7 * 1. Loads the image into an HTMLImageElement.
8 * 2. Copies pixels from HTMLImageElement to HTMLCanvasElement. This is done
9 * stripe-by-stripe to avoid freezing up the UI. The transform is taken into
10 * account.
11 *
12 * @param {!HTMLDocument} document Owner document.
13 * @param {!MetadataModel} metadataModel
14 * @constructor
15 * @struct
16 */
17 ImageUtil.ImageLoader = function(document, metadataModel) {
18 this.document_ = document;
19
20 /**
21 * @private {!MetadataModel}
22 * @const
23 */
24 this.metadataModel_ = metadataModel;
25
26 this.generation_ = 0;
27
28 /**
29 * @type {number}
30 * @private
31 */
32 this.timeout_ = 0;
33
34 /**
35 * @type {?function(!HTMLCanvasElement, string=)}
36 * @private
37 */
38 this.callback_ = null;
39
40 /**
41 * @type {FileEntry}
42 * @private
43 */
44 this.entry_ = null;
45 };
46
47 /**
48 * Loads an image.
49 * TODO(mtomasz): Simplify, or even get rid of this class and merge with the
50 * ThumbnaiLoader class.
51 *
52 * @param {!GalleryItem} item Item representing the image to be loaded.
53 * @param {function(!HTMLCanvasElement, string=)} callback Callback to be
54 * called when loaded. The second optional argument is an error identifier.
55 * @param {number=} opt_delay Load delay in milliseconds, useful to let the
56 * animations play out before the computation heavy image loading starts.
57 */
58 ImageUtil.ImageLoader.prototype.load = function(item, callback, opt_delay) {
59 var entry = item.getEntry();
60
61 this.cancel();
62 this.entry_ = entry;
63 this.callback_ = callback;
64
65 var targetImage = assertInstanceof(this.document_.createElement('img'),
66 HTMLImageElement);
67 // The transform fetcher is not cancellable so we need a generation counter.
68 var generation = ++this.generation_;
69
70 /**
71 * @param {!HTMLImageElement} image Image to be transformed.
72 * @param {Object=} opt_transform Transformation.
73 */
74 var onTransform = function(image, opt_transform) {
75 if (generation === this.generation_) {
76 this.convertImage_(image, opt_transform);
77 }
78 };
79 onTransform = onTransform.bind(this);
80
81 /**
82 * @param {string=} opt_error Error.
83 */
84 var onError = function(opt_error) {
85 targetImage.onerror = null;
86 targetImage.onload = null;
87 var tmpCallback = this.callback_;
88 this.callback_ = null;
89 var emptyCanvas = assertInstanceof(this.document_.createElement('canvas'),
90 HTMLCanvasElement);
91 emptyCanvas.width = 0;
92 emptyCanvas.height = 0;
93 tmpCallback(emptyCanvas, opt_error);
94 };
95 onError = onError.bind(this);
96
97 var loadImage = function(url) {
98 if (generation !== this.generation_)
99 return;
100
101 metrics.startInterval(ImageUtil.getMetricName('LoadTime'));
102 this.timeout_ = 0;
103
104 targetImage.onload = function() {
105 targetImage.onerror = null;
106 targetImage.onload = null;
107 if (generation !== this.generation_)
108 return;
109 this.metadataModel_.get([entry], ['contentImageTransform']).then(
110 function(metadataItems) {
111 onTransform(targetImage, metadataItems[0].contentImageTransform);
112 }.bind(this));
113 }.bind(this);
114
115 // The error callback has an optional error argument, which in case of a
116 // general error should not be specified
117 targetImage.onerror = onError.bind(null, 'GALLERY_IMAGE_ERROR');
118
119 targetImage.src = url;
120 }.bind(this);
121
122 // Loads the image. If already loaded, then forces a reload.
123 var startLoad = function() {
124 if (generation !== this.generation_)
125 return;
126
127 // Obtain target URL.
128 if (FileType.isRaw(entry)) {
129 var timestamp =
130 item.getMetadataItem() &&
131 item.getMetadataItem().modificationTime &&
132 item.getMetadataItem().modificationTime.getTime();
133 ImageLoaderClient.getInstance().load(entry.toURL(), function(result) {
134 if (generation !== this.generation_)
135 return;
136 if (result.status === 'success')
137 loadImage(result.data);
138 else
139 onError('GALLERY_IMAGE_ERROR');
140 }.bind(this), {
141 cache: true,
142 timestamp: timestamp,
143 priority: 0 // Use highest priority to show main image.
144 });
145 return;
146 }
147
148 // Load the image directly. The query parameter is workaround for
149 // crbug.com/379678, which force to update the contents of the image.
150 loadImage(entry.toURL() + '?nocache=' + Date.now());
151 }.bind(this);
152
153 if (opt_delay) {
154 this.timeout_ = setTimeout(startLoad, opt_delay);
155 } else {
156 startLoad();
157 }
158 };
159
160 /**
161 * @return {boolean} True if an image is loading.
162 */
163 ImageUtil.ImageLoader.prototype.isBusy = function() {
164 return !!this.callback_;
165 };
166
167 /**
168 * @param {Entry} entry Image entry.
169 * @return {boolean} True if loader loads this image.
170 */
171 ImageUtil.ImageLoader.prototype.isLoading = function(entry) {
172 return this.isBusy() && util.isSameEntry(this.entry_, entry);
173 };
174
175 /**
176 * @param {function(!HTMLCanvasElement, string=)} callback To be called when the
177 * image loaded.
178 */
179 ImageUtil.ImageLoader.prototype.setCallback = function(callback) {
180 this.callback_ = callback;
181 };
182
183 /**
184 * Stops loading image.
185 */
186 ImageUtil.ImageLoader.prototype.cancel = function() {
187 if (!this.callback_)
188 return;
189 this.callback_ = null;
190 if (this.timeout_) {
191 clearTimeout(this.timeout_);
192 this.timeout_ = 0;
193 }
194 this.generation_++; // Silence the transform fetcher if it is in progress.
195 };
196
197 /**
198 * @param {!HTMLImageElement} image Image to be transformed.
199 * @param {!Object} transform transformation description to apply to the image.
200 * @private
201 */
202 ImageUtil.ImageLoader.prototype.convertImage_ = function(image, transform) {
203 if (!transform ||
204 (transform.rotate90 === 0 &&
205 transform.scaleX === 1 &&
206 transform.scaleY === 1)) {
207 setTimeout(this.callback_, 0, image);
208 this.callback_ = null;
209 return;
210 }
211 var canvas = this.document_.createElement('canvas');
212
213 if (transform.rotate90 & 1) { // Rotated +/-90deg, swap the dimensions.
214 canvas.width = image.height;
215 canvas.height = image.width;
216 } else {
217 canvas.width = image.width;
218 canvas.height = image.height;
219 }
220
221 var context = canvas.getContext('2d');
222 context.save();
223 context.translate(canvas.width / 2, canvas.height / 2);
224 context.rotate(transform.rotate90 * Math.PI / 2);
225 context.scale(transform.scaleX, transform.scaleY);
226
227 var stripCount = Math.ceil(image.width * image.height / (1 << 21));
228 var step = Math.max(16, Math.ceil(image.height / stripCount)) & 0xFFFFF0;
229
230 this.copyStrip_(context, image, 0, step);
231 };
232
233 /**
234 * @param {!CanvasRenderingContext2D} context Context to draw.
235 * @param {!HTMLImageElement} image Image to draw.
236 * @param {number} firstRow Number of the first pixel row to draw.
237 * @param {number} rowCount Count of pixel rows to draw.
238 * @private
239 */
240 ImageUtil.ImageLoader.prototype.copyStrip_ = function(
241 context, image, firstRow, rowCount) {
242 var lastRow = Math.min(firstRow + rowCount, image.height);
243
244 context.drawImage(
245 image, 0, firstRow, image.width, lastRow - firstRow,
246 -image.width / 2, firstRow - image.height / 2,
247 image.width, lastRow - firstRow);
248
249 if (lastRow === image.height) {
250 context.restore();
251 if (this.entry_.toURL().substr(0, 5) !== 'data:') { // Ignore data urls.
252 metrics.recordInterval(ImageUtil.getMetricName('LoadTime'));
253 }
254 setTimeout(this.callback_, 0, context.canvas);
255 this.callback_ = null;
256 } else {
257 var self = this;
258 this.timeout_ = setTimeout(
259 function() {
260 self.timeout_ = 0;
261 self.copyStrip_(context, image, lastRow, rowCount);
262 }, 0);
263 }
264 };
265
OLDNEW
« no previous file with comments | « ui/file_manager/gallery/js/image_editor/image_editor.js ('k') | ui/file_manager/gallery/js/image_editor/image_util.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698