OLD | NEW |
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 * The overlay displaying the image. | 6 * The overlay displaying the image. |
7 * @param {HTMLElement} container The container element. | 7 * @param {HTMLElement} container The container element. |
8 * @param {Viewport} viewport The viewport. | 8 * @param {Viewport} viewport The viewport. |
9 * @param {MetadataCache} metadataCache The metadataCache. | 9 * @param {MetadataCache} metadataCache The metadataCache. |
10 */ | 10 */ |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 ImageView.prototype.cancelLoad = function() { | 288 ImageView.prototype.cancelLoad = function() { |
289 this.imageLoader_.cancel(); | 289 this.imageLoader_.cancel(); |
290 }; | 290 }; |
291 | 291 |
292 /** | 292 /** |
293 * Load and display a new image. | 293 * Load and display a new image. |
294 * | 294 * |
295 * Loads the thumbnail first, then replaces it with the main image. | 295 * Loads the thumbnail first, then replaces it with the main image. |
296 * Takes into account the image orientation encoded in the metadata. | 296 * Takes into account the image orientation encoded in the metadata. |
297 * | 297 * |
298 * @param {number} id Unique image id for caching purposes. | |
299 * @param {string} url Image url. | 298 * @param {string} url Image url. |
300 * @param {Object} metadata Metadata. | 299 * @param {Object} metadata Metadata. |
301 * @param {Object} slide Slide-in animation direction. | 300 * @param {Object} slide Slide-in animation direction. |
302 * @param {function(number} opt_callback The parameter is the load type. | 301 * @param {function(number} opt_callback The parameter is the load type. |
303 */ | 302 */ |
304 ImageView.prototype.load = function( | 303 ImageView.prototype.load = function(url, metadata, slide, opt_callback) { |
305 id, url, metadata, slide, opt_callback) { | |
306 | 304 |
307 metadata = metadata || {}; | 305 metadata = metadata || {}; |
308 | 306 |
309 ImageUtil.metrics.startInterval(ImageUtil.getMetricName('DisplayTime')); | 307 ImageUtil.metrics.startInterval(ImageUtil.getMetricName('DisplayTime')); |
310 | 308 |
311 var self = this; | 309 var self = this; |
312 | 310 |
313 this.contentID_ = id; | 311 this.contentID_ = url; |
314 this.contentRevision_ = -1; | 312 this.contentRevision_ = -1; |
315 | 313 |
316 var loadingVideo = FileType.getMediaType(url) == 'video'; | 314 var loadingVideo = FileType.getMediaType(url) == 'video'; |
317 if (loadingVideo) { | 315 if (loadingVideo) { |
318 var video = this.document_.createElement('video'); | 316 var video = this.document_.createElement('video'); |
319 if (metadata.thumbnail && metadata.thumbnail.url) { | 317 if (metadata.thumbnail && metadata.thumbnail.url) { |
320 video.setAttribute('poster', metadata.thumbnail.url); | 318 video.setAttribute('poster', metadata.thumbnail.url); |
321 this.replace(video, slide); // Show the poster immediately. | 319 this.replace(video, slide); // Show the poster immediately. |
322 } | 320 } |
323 video.addEventListener('loadedmetadata', onVideoLoad); | 321 video.addEventListener('loadedmetadata', onVideoLoad); |
324 video.addEventListener('error', onVideoLoad); | 322 video.addEventListener('error', onVideoLoad); |
325 | 323 |
326 // Do not try no stream when offline. | 324 // Do not try no stream when offline. |
327 video.src = (navigator.onLine && metadata.streaming && | 325 video.src = (navigator.onLine && metadata.streaming && |
328 metadata.streaming.url) || url; | 326 metadata.streaming.url) || url; |
329 video.load(); | 327 video.load(); |
330 | 328 |
331 function onVideoLoad() { | 329 function onVideoLoad() { |
332 video.removeEventListener('loadedmetadata', onVideoLoad); | 330 video.removeEventListener('loadedmetadata', onVideoLoad); |
333 video.removeEventListener('error', onVideoLoad); | 331 video.removeEventListener('error', onVideoLoad); |
334 displayMainImage(ImageView.LOAD_TYPE_VIDEO_FILE, slide, | 332 displayMainImage(ImageView.LOAD_TYPE_VIDEO_FILE, slide, |
335 !!(metadata.thumbnail && metadata.thumbnail.url) /* preview shown */, | 333 !!(metadata.thumbnail && metadata.thumbnail.url) /* preview shown */, |
336 video); | 334 video); |
337 } | 335 } |
338 return; | 336 return; |
339 } | 337 } |
340 var cached = this.contentCache_.getItem(id); | 338 var cached = this.contentCache_.getItem(this.contentID_); |
341 if (cached) { | 339 if (cached) { |
342 displayMainImage(ImageView.LOAD_TYPE_CACHED_FULL, slide, | 340 displayMainImage(ImageView.LOAD_TYPE_CACHED_FULL, slide, |
343 false /* no preview */, cached); | 341 false /* no preview */, cached); |
344 } else { | 342 } else { |
345 var cachedScreen = this.screenCache_.getItem(id); | 343 var cachedScreen = this.screenCache_.getItem(this.contentID_); |
346 if (cachedScreen) { | 344 if (cachedScreen) { |
347 // We have a cached screen-scale canvas, use it instead of a thumbnail. | 345 // We have a cached screen-scale canvas, use it instead of a thumbnail. |
348 displayThumbnail(ImageView.LOAD_TYPE_CACHED_SCREEN, slide, cachedScreen); | 346 displayThumbnail(ImageView.LOAD_TYPE_CACHED_SCREEN, slide, cachedScreen); |
349 // As far as the user can tell the image is loaded. We still need to load | 347 // As far as the user can tell the image is loaded. We still need to load |
350 // the full res image to make editing possible, but we can report now. | 348 // the full res image to make editing possible, but we can report now. |
351 ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('DisplayTime')); | 349 ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('DisplayTime')); |
352 } else if (metadata.thumbnail && metadata.thumbnail.url) { | 350 } else if (metadata.thumbnail && metadata.thumbnail.url) { |
353 this.imageLoader_.load( | 351 this.imageLoader_.load( |
354 metadata.thumbnail.url, | 352 metadata.thumbnail.url, |
355 function(url, callback) { callback(metadata.thumbnail.transform); }, | 353 function(url, callback) { callback(metadata.thumbnail.transform); }, |
(...skipping 13 matching lines...) Expand all Loading... |
369 var mainImageSlide = slide; | 367 var mainImageSlide = slide; |
370 | 368 |
371 // Do not do slide-in animation when scrolling very fast. | 369 // Do not do slide-in animation when scrolling very fast. |
372 if (self.lastLoadTime_ && | 370 if (self.lastLoadTime_ && |
373 (time - self.lastLoadTime_) < ImageView.FAST_SCROLL_INTERVAL) { | 371 (time - self.lastLoadTime_) < ImageView.FAST_SCROLL_INTERVAL) { |
374 mainImageSlide = 0; | 372 mainImageSlide = 0; |
375 } | 373 } |
376 self.lastLoadTime_ = time; | 374 self.lastLoadTime_ = time; |
377 | 375 |
378 if (canvas.width) { | 376 if (canvas.width) { |
379 if (!!metadata.media.width) { | 377 if (!metadata.media.width) { |
380 // We do not know the main image size, but chances are that it is large | 378 // We do not know the main image size, but chances are that it is large |
381 // enough. Show the thumbnail at the maximum possible scale. | 379 // enough. Show the thumbnail at the maximum possible scale. |
382 var bounds = self.viewport_.getScreenBounds(); | 380 var bounds = self.viewport_.getScreenBounds(); |
383 var scale = Math.min(bounds.width / canvas.width, | 381 var scale = Math.min(bounds.width / canvas.width, |
384 bounds.height / canvas.height); | 382 bounds.height / canvas.height); |
385 self.replace(canvas, slide, | 383 self.replace(canvas, slide, |
386 canvas.width * scale, canvas.height * scale, true /* preview */); | 384 canvas.width * scale, canvas.height * scale, true /* preview */); |
387 } else { | 385 } else { |
388 self.replace(canvas, slide, | 386 self.replace(canvas, slide, |
389 metadata.media.width, metadata.media.height, true /* preview */); | 387 metadata.media.width, metadata.media.height, true /* preview */); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 // |streaming| is set only when the file is not locally cached. | 447 // |streaming| is set only when the file is not locally cached. |
450 loadType = ImageView.LOAD_TYPE_OFFLINE; | 448 loadType = ImageView.LOAD_TYPE_OFFLINE; |
451 } | 449 } |
452 if (opt_callback) opt_callback(loadType); | 450 if (opt_callback) opt_callback(loadType); |
453 } | 451 } |
454 }; | 452 }; |
455 | 453 |
456 /** | 454 /** |
457 * Prefetch an image. | 455 * Prefetch an image. |
458 * | 456 * |
459 * @param {number} id Unique image id for caching purposes. | |
460 * @param {string} url The image url. | 457 * @param {string} url The image url. |
461 */ | 458 */ |
462 ImageView.prototype.prefetch = function(id, url) { | 459 ImageView.prototype.prefetch = function(url) { |
463 var self = this; | 460 var self = this; |
464 function prefetchDone(canvas) { | 461 function prefetchDone(canvas) { |
465 if (canvas.width) | 462 if (canvas.width) |
466 self.contentCache_.putItem(id, canvas); | 463 self.contentCache_.putItem(url, canvas); |
467 } | 464 } |
468 | 465 |
469 var cached = this.contentCache_.getItem(id); | 466 var cached = this.contentCache_.getItem(url); |
470 if (cached) { | 467 if (cached) { |
471 prefetchDone(cached); | 468 prefetchDone(cached); |
472 } else if (FileType.getMediaType(url) == 'image') { | 469 } else if (FileType.getMediaType(url) == 'image') { |
473 // Evict the LRU item before we allocate the new canvas to avoid unneeded | 470 // Evict the LRU item before we allocate the new canvas to avoid unneeded |
474 // strain on memory. | 471 // strain on memory. |
475 this.contentCache_.evictLRU(); | 472 this.contentCache_.evictLRU(); |
476 | 473 |
477 this.prefetchLoader_.load( | 474 this.prefetchLoader_.load( |
478 url, | 475 url, |
479 this.localImageTransformFetcher_, | 476 this.localImageTransformFetcher_, |
480 prefetchDone, | 477 prefetchDone, |
481 ImageView.ANIMATION_WAIT_INTERVAL); | 478 ImageView.ANIMATION_WAIT_INTERVAL); |
482 } | 479 } |
483 }; | 480 }; |
484 | 481 |
485 /** | 482 /** |
| 483 * Rename the current image. |
| 484 * |
| 485 * @param {string} newUrl The new image url. |
| 486 */ |
| 487 ImageView.prototype.changeUrl = function(newUrl) { |
| 488 this.contentCache_.renameItem(this.contentID_, newUrl); |
| 489 this.screenCache_.renameItem(this.contentID_, newUrl); |
| 490 this.contentID_ = newUrl; |
| 491 }; |
| 492 |
| 493 /** |
| 494 * Unload content. |
| 495 */ |
| 496 ImageView.prototype.unload = function() { |
| 497 this.container_.textContent = ''; |
| 498 this.screenImage_ = null; |
| 499 this.videoElement_ = null; |
| 500 }; |
| 501 |
| 502 /** |
486 * | 503 * |
487 * @param {HTMLCanvasElement|HTMLVideoElement} content The image element. | 504 * @param {HTMLCanvasElement|HTMLVideoElement} content The image element. |
488 * @param {boolean} opt_reuseScreenCanvas True if it is OK to reuse the screen | 505 * @param {boolean} opt_reuseScreenCanvas True if it is OK to reuse the screen |
489 * resolution canvas. | 506 * resolution canvas. |
490 * @param {number} opt_width Image width. | 507 * @param {number} opt_width Image width. |
491 * @param {number} opt_height Image height. | 508 * @param {number} opt_height Image height. |
492 * @param {boolean} opt_preview True if the image is a preview (not full res). | 509 * @param {boolean} opt_preview True if the image is a preview (not full res). |
493 * @private | 510 * @private |
494 */ | 511 */ |
495 ImageView.prototype.replaceContent_ = function( | 512 ImageView.prototype.replaceContent_ = function( |
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
797 | 814 |
798 /** | 815 /** |
799 * Evict the least recently used items. | 816 * Evict the least recently used items. |
800 */ | 817 */ |
801 ImageView.Cache.prototype.evictLRU = function() { | 818 ImageView.Cache.prototype.evictLRU = function() { |
802 if (this.order_.length == this.capacity_) { | 819 if (this.order_.length == this.capacity_) { |
803 var id = this.order_.shift(); | 820 var id = this.order_.shift(); |
804 delete this.map_[id]; | 821 delete this.map_[id]; |
805 } | 822 } |
806 }; | 823 }; |
| 824 |
| 825 /** |
| 826 * Change the id of an entry. |
| 827 * @param {string} oldId The old ID. |
| 828 * @param {string} newId The new ID. |
| 829 */ |
| 830 ImageView.Cache.prototype.renameItem = function(oldId, newId) { |
| 831 if (oldId == newId) |
| 832 return; // No need to rename. |
| 833 |
| 834 var pos = this.order_.indexOf(oldId); |
| 835 if (pos < 0) |
| 836 return; // Not cached. |
| 837 |
| 838 this.order_[pos] = newId; |
| 839 this.map_[newId] = this.map_[oldId]; |
| 840 delete this.map_[oldId]; |
| 841 }; |
OLD | NEW |