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

Side by Side Diff: chrome/browser/resources/file_manager/js/media/media_util.js

Issue 12304013: Introduce Image loader extension. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Simplified. Created 7 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 * Loads a thumbnail using provided url. In CANVAS mode, loaded images 6 * Loads a thumbnail using provided url. In CANVAS mode, loaded images
7 * are attached as <canvas> element, while in IMAGE mode as <img>. 7 * are attached as <canvas> element, while in IMAGE mode as <img>.
8 * <canvas> renders faster than <img>, however has bigger memory overhead. 8 * <canvas> renders faster than <img>, however has bigger memory overhead.
9 * 9 *
10 * @param {string} url File URL. 10 * @param {string} url File URL.
(...skipping 20 matching lines...) Expand all
31 if (apps[i].docIcon && apps[i].isPrimary) { 31 if (apps[i].docIcon && apps[i].isPrimary) {
32 this.fallbackUrl_ = apps[i].docIcon; 32 this.fallbackUrl_ = apps[i].docIcon;
33 break; 33 break;
34 } 34 }
35 } 35 }
36 } 36 }
37 37
38 if (opt_metadata.thumbnail && opt_metadata.thumbnail.url) { 38 if (opt_metadata.thumbnail && opt_metadata.thumbnail.url) {
39 this.thumbnailUrl_ = opt_metadata.thumbnail.url; 39 this.thumbnailUrl_ = opt_metadata.thumbnail.url;
40 this.transform_ = opt_metadata.thumbnail.transform; 40 this.transform_ = opt_metadata.thumbnail.transform;
41 } else if (FileType.isImage(url) && 41 } else if (FileType.isImage(url)) {
42 ThumbnailLoader.canUseImageUrl_(opt_metadata)) {
43 this.thumbnailUrl_ = url; 42 this.thumbnailUrl_ = url;
44 this.transform_ = opt_metadata.media && opt_metadata.media.imageTransform; 43 this.transform_ = opt_metadata.media && opt_metadata.media.imageTransform;
45 } else if (this.fallbackUrl_) { 44 } else if (this.fallbackUrl_) {
46 // Use fallback as the primary thumbnail. 45 // Use fallback as the primary thumbnail.
47 this.thumbnailUrl_ = this.fallbackUrl_; 46 this.thumbnailUrl_ = this.fallbackUrl_;
48 this.fallbackUrl_ = null; 47 this.fallbackUrl_ = null;
49 } // else the generic thumbnail based on the media type will be used. 48 } // else the generic thumbnail based on the media type will be used.
50 } 49 }
51 50
52 /** 51 /**
53 * Files with more pixels won't have thumbnails.
54 */
55 ThumbnailLoader.MAX_PIXEL_COUNT = 1 << 21; // 2 MPix
56
57 /**
58 * Files of bigger size won't have thumbnails.
59 */
60 ThumbnailLoader.MAX_FILE_SIZE = 1 << 20; // 1 Mb
61
62 /**
63 * In percents (0.0 - 1.0), how much area can be cropped to fill an image 52 * In percents (0.0 - 1.0), how much area can be cropped to fill an image
64 * in a container, when loading a thumbnail in FillMode.AUTO mode. 53 * in a container, when loading a thumbnail in FillMode.AUTO mode.
65 * The specified 30% value allows to fill 16:9, 3:2 pictures in 4:3 element. 54 * The specified 30% value allows to fill 16:9, 3:2 pictures in 4:3 element.
66 * @type {number} 55 * @type {number}
67 */ 56 */
68 ThumbnailLoader.AUTO_FILL_THRESHOLD = 0.3; 57 ThumbnailLoader.AUTO_FILL_THRESHOLD = 0.3;
69 58
70 /** 59 /**
71 * Type of displaying a thumbnail within a box. 60 * Type of displaying a thumbnail within a box.
72 * @enum 61 * @enum
73 */ 62 */
74 ThumbnailLoader.FillMode = { 63 ThumbnailLoader.FillMode = {
75 FILL: 0, // Fill whole box. Image may be cropped. 64 FILL: 0, // Fill whole box. Image may be cropped.
76 FIT: 1, // Keep aspect ratio, do not crop. 65 FIT: 1, // Keep aspect ratio, do not crop.
77 AUTO: 2 // Try to fill, but if incompatible aspect ratio, then fit. 66 AUTO: 2 // Try to fill, but if incompatible aspect ratio, then fit.
78 }; 67 };
79 68
80 /** 69 /**
70 * Optimization mode for downloading thumbnails.
71 * @enum
72 */
73 ThumbnailLoader.OptimizationMode = {
74 NEVER_DISCARD: 0, // Never discards downloading. No optimization.
75 DISCARD_DETACHED: 1 // Canceled if the container is not attached anymore.
76 };
77
78 /**
81 * Type of element to store the image. 79 * Type of element to store the image.
82 * @enum 80 * @enum
83 */ 81 */
84 ThumbnailLoader.LoaderType = { 82 ThumbnailLoader.LoaderType = {
85 IMAGE: 0, 83 IMAGE: 0,
86 CANVAS: 1 84 CANVAS: 1
87 }; 85 };
88 86
89 /** 87 /**
90 * If an image file does not have an embedded thumbnail we might want to use 88 * Maximum thumbnail's width when generating from the full resolution image.
91 * the image itself as a thumbnail. If the image is too large it hurts 89 * @const
92 * the performance a lot so we allow it only for moderately sized files. 90 * @type {number}
93 *
94 * @param {Object} metadata Metadata object.
95 * @return {boolean} Whether it is OK to use the image url for a preview.
96 * @private
97 */ 91 */
98 ThumbnailLoader.canUseImageUrl_ = function(metadata) { 92 ThumbnailLoader.THUMBNAIL_MAX_WIDTH = 500;
99 return (metadata.filesystem && metadata.filesystem.size &&
100 metadata.filesystem.size <= ThumbnailLoader.MAX_FILE_SIZE) ||
101 (metadata.media && metadata.media.width && metadata.media.height &&
102 metadata.media.width * metadata.media.height <=
103 ThumbnailLoader.MAX_PIXEL_COUNT);
104 };
105 93
106 /** 94 /**
95 * Maximum thumbnail's height when generating from the full resolution image.
96 * @const
97 * @type {number}
98 */
99 ThumbnailLoader.THUMBNAIL_MAX_HEIGHT = 500;
100
101 /**
102 * Loads and attaches an image.
107 * 103 *
108 * @param {HTMLElement} box Container element. 104 * @param {HTMLElement} box Container element.
109 * @param {ThumbnailLoader.FillMode} fillMode Fill mode. 105 * @param {ThumbnailLoader.FillMode} fillMode Fill mode.
106 * @param {ThumbnailLoader.OptimizationMode=} opt_optimizationMode Optimization
107 * for downloading thumbnails. By default optimizations are disabled.
110 * @param {function(Image, object} opt_onSuccess Success callback, 108 * @param {function(Image, object} opt_onSuccess Success callback,
111 * accepts the image and the transform. 109 * accepts the image and the transform.
112 * @param {function} opt_onError Error callback. 110 * @param {function} opt_onError Error callback.
113 * @param {function} opt_onGeneric Callback for generic image used. 111 * @param {function} opt_onGeneric Callback for generic image used.
114 */ 112 */
115 ThumbnailLoader.prototype.load = function( 113 ThumbnailLoader.prototype.load = function(box, fillMode, opt_optimizationMode,
116 box, fillMode, opt_onSuccess, opt_onError, opt_onGeneric) { 114 opt_onSuccess, opt_onError, opt_onGeneric) {
115 opt_optimizationMode = opt_optimizationMode ||
116 ThumbnailLoader.OptimizationMode.NEVER_DISCARD;
117
117 if (!this.thumbnailUrl_) { 118 if (!this.thumbnailUrl_) {
118 // Relevant CSS rules are in file_types.css. 119 // Relevant CSS rules are in file_types.css.
119 box.setAttribute('generic-thumbnail', this.mediaType_); 120 box.setAttribute('generic-thumbnail', this.mediaType_);
120 if (opt_onGeneric) opt_onGeneric(); 121 if (opt_onGeneric) opt_onGeneric();
121 return; 122 return;
122 } 123 }
123 124
124 this.canvasUpToDate_ = false; 125 this.canvasUpToDate_ = false;
125 this.image_ = new Image(); 126 this.image_ = new Image();
126 this.image_.onload = function() { 127 this.image_.onload = function() {
127 this.attachImage(box, fillMode); 128 this.attachImage(box, fillMode);
128 if (opt_onSuccess) 129 if (opt_onSuccess)
129 opt_onSuccess(this.image_, this.transform_); 130 opt_onSuccess(this.image_, this.transform_);
130 }.bind(this); 131 }.bind(this);
131 this.image_.onerror = function() { 132 this.image_.onerror = function() {
132 if (opt_onError) 133 if (opt_onError)
133 opt_onError(); 134 opt_onError();
134 if (this.fallbackUrl_) { 135 if (this.fallbackUrl_) {
135 new ThumbnailLoader(this.fallbackUrl_, 136 new ThumbnailLoader(this.fallbackUrl_,
136 this.loaderType_, 137 this.loaderType_,
137 null, 138 null,
138 this.mediaType_). 139 this.mediaType_).
139 load(box, fillMode, opt_onSuccess); 140 load(box, fillMode, opt_onSuccess);
140 } else { 141 } else {
141 box.setAttribute('generic-thumbnail', this.mediaType_); 142 box.setAttribute('generic-thumbnail', this.mediaType_);
142 } 143 }
143 }.bind(this); 144 }.bind(this);
144 145
145 if (this.image_.src == this.thumbnailUrl_) { 146 if (this.image_.src) {
146 console.warn('Thumnbnail already loaded: ' + this.thumbnailUrl_); 147 console.warn('Thumbnail already loaded: ' + this.thumbnailUrl_);
147 return; 148 return;
148 } 149 }
149 150
150 util.loadImage(this.image_, this.thumbnailUrl_); 151 // TODO(mtomasz): Smarter calculation of the requested size.
152 var wasAttached = box.ownerDocument.contains(box);
153 var taskId = util.loadImage(
154 this.image_,
155 this.thumbnailUrl_,
156 { maxWidth: ThumbnailLoader.THUMBNAIL_MAX_WIDTH,
157 maxHeight: ThumbnailLoader.THUMBNAIL_MAX_HEIGHT,
158 cache: true },
159 function() {
160 if (opt_optimizationMode ==
161 ThumbnailLoader.OptimizationMode.DISCARD_DETACHED &&
162 !box.ownerDocument.contains(box)) {
163 // If the container is not attached, then invalidate the download.
164 return false;
165 }
166 return true;
167 });
168
169 if (!taskId)
170 this.image_.classList.add('cached');
151 }; 171 };
152 172
153 /** 173 /**
154 * @return {boolean} True if a valid image is loaded. 174 * @return {boolean} True if a valid image is loaded.
155 */ 175 */
156 ThumbnailLoader.prototype.hasValidImage = function() { 176 ThumbnailLoader.prototype.hasValidImage = function() {
157 return !!(this.image_ && this.image_.width && this.image_.height); 177 return !!(this.image_ && this.image_.width && this.image_.height);
158 }; 178 };
159 179
160 /** 180 /**
(...skipping 27 matching lines...) Expand all
188 ThumbnailLoader.prototype.loadDetachedImage = function(callback) { 208 ThumbnailLoader.prototype.loadDetachedImage = function(callback) {
189 if (!this.thumbnailUrl_) { 209 if (!this.thumbnailUrl_) {
190 callback(true); 210 callback(true);
191 return; 211 return;
192 } 212 }
193 213
194 this.canvasUpToDate_ = false; 214 this.canvasUpToDate_ = false;
195 this.image_ = new Image(); 215 this.image_ = new Image();
196 this.image_.onload = callback.bind(null, true); 216 this.image_.onload = callback.bind(null, true);
197 this.image_.onerror = callback.bind(null, false); 217 this.image_.onerror = callback.bind(null, false);
198 util.loadImage(this.image_, this.thumbnailUrl_); 218
219 // TODO(mtomasz): Smarter calculation of the requested size.
220 var taskId = util.loadImage(
221 this.image_,
222 this.thumbnailUrl_,
223 { maxWidth: ThumbnailLoader.THUMBNAIL_MAX_WIDTH,
224 maxHeight: ThumbnailLoader.THUMBNAIL_MAX_HEIGHT,
225 cache: true });
226
227 if (!taskId)
228 this.image_.classList.add('cached');
199 }; 229 };
200 230
201 /** 231 /**
202 * Attach the image to a given element. 232 * Attach the image to a given element.
203 * @param {Element} container Parent element. 233 * @param {Element} container Parent element.
204 * @param {ThumbnailLoader.FillMode} fillMode Fill mode. 234 * @param {ThumbnailLoader.FillMode} fillMode Fill mode.
205 */ 235 */
206 ThumbnailLoader.prototype.attachImage = function(container, fillMode) { 236 ThumbnailLoader.prototype.attachImage = function(container, fillMode) {
207 if (!this.hasValidImage()) { 237 if (!this.hasValidImage()) {
208 container.setAttribute('generic-thumbnail', this.mediaType_); 238 container.setAttribute('generic-thumbnail', this.mediaType_);
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 340
311 function percent(fraction) { 341 function percent(fraction) {
312 return (fraction * 100).toFixed(2) + '%'; 342 return (fraction * 100).toFixed(2) + '%';
313 } 343 }
314 344
315 img.style.width = percent(fractionX); 345 img.style.width = percent(fractionX);
316 img.style.height = percent(fractionY); 346 img.style.height = percent(fractionY);
317 img.style.left = percent((1 - fractionX) / 2); 347 img.style.left = percent((1 - fractionX) / 2);
318 img.style.top = percent((1 - fractionY) / 2); 348 img.style.top = percent((1 - fractionY) / 2);
319 }; 349 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698