OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 * The overlay displaying the image. | 6 * The overlay displaying the image. |
7 */ | 7 */ |
8 function ImageView(container, viewport) { | 8 function ImageView(container, viewport) { |
9 this.container_ = container; | 9 this.container_ = container; |
10 this.viewport_ = viewport; | 10 this.viewport_ = viewport; |
(...skipping 17 matching lines...) Expand all Loading... | |
28 // the content cache any more. Screen-scale images are small (~1Mpix) | 28 // the content cache any more. Screen-scale images are small (~1Mpix) |
29 // so we can afford to cache more of them. | 29 // so we can afford to cache more of them. |
30 this.screenCache_ = new ImageView.Cache(5); | 30 this.screenCache_ = new ImageView.Cache(5); |
31 this.contentCallbacks_ = []; | 31 this.contentCallbacks_ = []; |
32 } | 32 } |
33 | 33 |
34 ImageView.ANIMATION_DURATION = 180; | 34 ImageView.ANIMATION_DURATION = 180; |
35 ImageView.ANIMATION_WAIT_INTERVAL = ImageView.ANIMATION_DURATION * 2; | 35 ImageView.ANIMATION_WAIT_INTERVAL = ImageView.ANIMATION_DURATION * 2; |
36 ImageView.FAST_SCROLL_INTERVAL = 300; | 36 ImageView.FAST_SCROLL_INTERVAL = 300; |
37 | 37 |
38 ImageView.LOAD_TYPE_CACHED_FULL = 0; | |
39 ImageView.LOAD_TYPE_CACHED_SCREEN = 1; | |
40 ImageView.LOAD_TYPE_FILE = 2; | |
41 ImageView.LOAD_TYPE_TOTAL = 3; | |
42 | |
38 ImageView.prototype = {__proto__: ImageBuffer.Overlay.prototype}; | 43 ImageView.prototype = {__proto__: ImageBuffer.Overlay.prototype}; |
39 | 44 |
40 // Draw below overlays with the default zIndex. | 45 // Draw below overlays with the default zIndex. |
41 ImageView.prototype.getZIndex = function() { return -1 }; | 46 ImageView.prototype.getZIndex = function() { return -1 }; |
42 | 47 |
43 ImageView.prototype.draw = function() { | 48 ImageView.prototype.draw = function() { |
44 var forceRepaint = false; | 49 var forceRepaint = false; |
45 | 50 |
46 var screenClipped = this.viewport_.getScreenClipped(); | 51 var screenClipped = this.viewport_.getScreenClipped(); |
47 | 52 |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
146 * @param {Object} metadata | 151 * @param {Object} metadata |
147 * @param {Object} slide Slide-in animation direction. | 152 * @param {Object} slide Slide-in animation direction. |
148 * @param {function(boolean} opt_callback The parameter is true if the image | 153 * @param {function(boolean} opt_callback The parameter is true if the image |
149 * was loaded instantly (from the cache of the canvas source). | 154 * was loaded instantly (from the cache of the canvas source). |
150 */ | 155 */ |
151 ImageView.prototype.load = function( | 156 ImageView.prototype.load = function( |
152 id, source, metadata, slide, opt_callback) { | 157 id, source, metadata, slide, opt_callback) { |
153 | 158 |
154 metadata = metadata|| {}; | 159 metadata = metadata|| {}; |
155 | 160 |
156 ImageUtil.trace.resetTimer('load'); | 161 if (ImageUtil.metrics) { |
162 ImageUtil.metrics.startInterval(ImageUtil.getMetricName('DisplayTime')); | |
163 } | |
157 | 164 |
158 var self = this; | 165 var self = this; |
159 | 166 |
160 this.contentID_ = id; | 167 this.contentID_ = id; |
161 | 168 |
162 var readyContent = this.getReadyContent(id, source); | 169 var readyContent = this.getReadyContent(id, source); |
163 if (readyContent) { | 170 if (readyContent) { |
164 displayMainImage(readyContent, true); | 171 displayMainImage(ImageView.LOAD_TYPE_CACHED_FULL, readyContent); |
165 } else { | 172 } else { |
166 var cachedScreen = this.screenCache_.getItem(id); | 173 var cachedScreen = this.screenCache_.getItem(id); |
167 if (cachedScreen) { | 174 if (cachedScreen) { |
168 // We have a cached screen-scale canvas, use it as a thumbnail. | 175 // We have a cached screen-scale canvas, use it instead of a thumbnail. |
169 displayThumbnail(cachedScreen); | 176 displayThumbnail(ImageView.LOAD_TYPE_CACHED_SCREEN, cachedScreen); |
177 // As far as the user can tell the image is loaded. We still need to load | |
178 // the full res image to make editing possible, but we can report now. | |
179 ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('DisplayTime')); | |
170 } else if (metadata.thumbnailURL) { | 180 } else if (metadata.thumbnailURL) { |
171 this.imageLoader_.load( | 181 this.imageLoader_.load( |
172 metadata.thumbnailURL, | 182 metadata.thumbnailURL, |
173 metadata.thumbnailTransform, | 183 metadata.thumbnailTransform, |
174 displayThumbnail); | 184 displayThumbnail.bind(null, ImageView.LOAD_TYPE_FILE)); |
175 } else { | 185 } else { |
176 loadMainImage(0); | 186 loadMainImage(ImageView.LOAD_TYPE_FILE, 0); |
177 } | 187 } |
178 } | 188 } |
179 | 189 |
180 function displayThumbnail(canvas) { | 190 function displayThumbnail(loadType, canvas) { |
181 // The thumbnail may have different aspect ratio than the main image. | 191 // The thumbnail may have different aspect ratio than the main image. |
182 // Force the main image proportions to avoid flicker. | 192 // Force the main image proportions to avoid flicker. |
183 var time = Date.now(); | 193 var time = Date.now(); |
184 | 194 |
185 var mainImageLoadDelay = ImageView.ANIMATION_WAIT_INTERVAL; | 195 var mainImageLoadDelay = ImageView.ANIMATION_WAIT_INTERVAL; |
186 | 196 |
187 // Do not do slide-in animation when scrolling very fast. | 197 // Do not do slide-in animation when scrolling very fast. |
188 if (self.lastLoadTime_ && | 198 if (self.lastLoadTime_ && |
189 (time - self.lastLoadTime_) < ImageView.FAST_SCROLL_INTERVAL) { | 199 (time - self.lastLoadTime_) < ImageView.FAST_SCROLL_INTERVAL) { |
190 slide = 0; | 200 slide = 0; |
191 } | 201 } |
192 self.lastLoadTime_ = time; | 202 self.lastLoadTime_ = time; |
193 | 203 |
194 self.replace(canvas, slide, metadata.width, metadata.height); | 204 self.replace(canvas, slide, metadata.width, metadata.height); |
195 if (!slide) mainImageLoadDelay = 0; | 205 if (!slide) mainImageLoadDelay = 0; |
196 slide = 0; | 206 slide = 0; |
197 loadMainImage(mainImageLoadDelay); | 207 loadMainImage(loadType, mainImageLoadDelay); |
198 } | 208 } |
199 | 209 |
200 function loadMainImage(delay) { | 210 function loadMainImage(loadType, delay) { |
201 if (self.prefetchLoader_.isLoading(source)) { | 211 if (self.prefetchLoader_.isLoading(source)) { |
202 // The image we need is already being prefetched. Initiating another load | 212 // The image we need is already being prefetched. Initiating another load |
203 // would be a waste. Hijack the load instead by overriding the callback. | 213 // would be a waste. Hijack the load instead by overriding the callback. |
204 self.prefetchLoader_.setCallback(displayMainImage); | 214 self.prefetchLoader_.setCallback(displayMainImage.bind(null, loadType)); |
205 | 215 |
206 // Swap the loaders so that the self.isLoading works correctly. | 216 // Swap the loaders so that the self.isLoading works correctly. |
207 var temp = self.prefetchLoader_; | 217 var temp = self.prefetchLoader_; |
208 self.prefetchLoader_ = self.imageLoader_; | 218 self.prefetchLoader_ = self.imageLoader_; |
209 self.imageLoader_ = temp; | 219 self.imageLoader_ = temp; |
210 return; | 220 return; |
211 } | 221 } |
212 self.prefetchLoader_.cancel(); // The prefetch was doing something useless. | 222 self.prefetchLoader_.cancel(); // The prefetch was doing something useless. |
213 | 223 |
214 self.imageLoader_.load( | 224 self.imageLoader_.load( |
215 source, | 225 source, |
216 metadata.imageTransform, | 226 metadata.imageTransform, |
217 displayMainImage, | 227 displayMainImage.bind(null, loadType), |
218 delay); | 228 delay); |
219 } | 229 } |
220 | 230 |
221 function displayMainImage(canvas, opt_fastLoad) { | 231 function displayMainImage(loadType, canvas) { |
222 self.replace(canvas, slide); | 232 self.replace(canvas, slide); |
223 ImageUtil.trace.reportTimer('load'); | 233 ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('DisplayMode'), |
224 ImageUtil.trace.report('load-type', opt_fastLoad ? 'cached' : 'file'); | 234 loadType, ImageView.LOAD_TYPE_TOTAL); |
225 if (opt_callback) opt_callback(opt_fastLoad); | 235 if (loadType != ImageView.LOAD_TYPE_CACHED_SCREEN) { |
236 ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('DisplayTime')); | |
237 } | |
238 if (opt_callback) opt_callback(loadType == ImageView.LOAD_TYPE_CACHED_FULL); | |
dgozman
2011/12/06 15:45:56
I believe that callback now accepts the loadType i
Vladislav Kaznacheev
2011/12/06 16:07:44
Good catch, thanks!
On 2011/12/06 15:45:56, dgozma
| |
226 } | 239 } |
227 }; | 240 }; |
228 | 241 |
229 /** | 242 /** |
230 * Try to get the canvas from the content cache or from the source. | 243 * Try to get the canvas from the content cache or from the source. |
231 * | 244 * |
232 * @param {number} id Unique image id for caching purposes | 245 * @param {number} id Unique image id for caching purposes |
233 * @param {string|HTMLCanvasElement} source | 246 * @param {string|HTMLCanvasElement} source |
234 */ | 247 */ |
235 ImageView.prototype.getReadyContent = function(id, source) { | 248 ImageView.prototype.getReadyContent = function(id, source) { |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
462 if (this.order_.length > this.capacity_) | 475 if (this.order_.length > this.capacity_) |
463 throw new Error('Exceeded cache capacity'); | 476 throw new Error('Exceeded cache capacity'); |
464 }; | 477 }; |
465 | 478 |
466 ImageView.Cache.prototype.evictLRU = function() { | 479 ImageView.Cache.prototype.evictLRU = function() { |
467 if (this.order_.length == this.capacity_) { | 480 if (this.order_.length == this.capacity_) { |
468 var id = this.order_.shift(); | 481 var id = this.order_.shift(); |
469 delete this.map_[id]; | 482 delete this.map_[id]; |
470 } | 483 } |
471 }; | 484 }; |
OLD | NEW |