15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)'use strict'; 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The overlay displaying the image. 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLElement} container The container element. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Viewport} viewport The viewport. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {MetadataCache} metadataCache The metadataCache. 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @constructor 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function ImageView(container, viewport, metadataCache) { 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.container_ = container; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.viewport_ = viewport; 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.document_ = container.ownerDocument; 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentGeneration_ = 0; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.displayedContentGeneration_ = 0; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.displayedViewportGeneration_ = 0; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) this.imageLoader_ = new ImageUtil.ImageLoader(this.document_, metadataCache); 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have a separate image loader for prefetch which does not get cancelled 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // when the selection changes. 267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) this.prefetchLoader_ = new ImageUtil.ImageLoader( 277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) this.document_, metadataCache); 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The content cache is used for prefetching the next image when going 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // through the images sequentially. The real life photos can be large 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (18Mpix = 72Mb pixel array) so we want only the minimum amount of caching. 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentCache_ = new ImageView.Cache(2); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We reuse previously generated screen-scale images so that going back to 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a recently loaded image looks instant even if the image is not in 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the content cache any more. Screen-scale images are small (~1Mpix) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so we can afford to cache more of them. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.screenCache_ = new ImageView.Cache(5); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentCallbacks_ = []; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The element displaying the current content. 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type {HTMLCanvasElement|HTMLVideoElement} 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.screenImage_ = null; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.localImageTransformFetcher_ = function(entry, callback) { 5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) metadataCache.getOne(entry, 'fetchedMedia', function(fetchedMedia) { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback(fetchedMedia.imageTransform); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Duration of transition between modes in ms. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.MODE_TRANSITION_DURATION = 350; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * If the user flips though images faster than this interval we do not apply 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the slide-in/slide-out transition. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.FAST_SCROLL_INTERVAL = 300; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Image load type: full resolution image loaded from cache. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.LOAD_TYPE_CACHED_FULL = 0; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Image load type: screen resolution preview loaded from cache. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.LOAD_TYPE_CACHED_SCREEN = 1; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Image load type: image read from file. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.LOAD_TYPE_IMAGE_FILE = 2; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Image load type: video loaded. 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.LOAD_TYPE_VIDEO_FILE = 3; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Image load type: error occurred. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.LOAD_TYPE_ERROR = 4; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Image load type: the file contents is not available offline. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.LOAD_TYPE_OFFLINE = 5; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The total number of load types. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.LOAD_TYPE_TOTAL = 6; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype = {__proto__: ImageBuffer.Overlay.prototype}; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Draws below overlays with the default zIndex. 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {number} Z-index. 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.getZIndex = function() { return -1 }; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Draws the image on screen. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.draw = function() { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.contentCanvas_) // Do nothing if the image content is not set. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var forceRepaint = false; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (this.displayedViewportGeneration_ !== 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.viewport_.getCacheGeneration()) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.displayedViewportGeneration_ = this.viewport_.getCacheGeneration(); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.setupDeviceBuffer(this.screenImage_); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) forceRepaint = true; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (forceRepaint || 129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.displayedContentGeneration_ !== this.contentGeneration_) { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.displayedContentGeneration_ = this.contentGeneration_; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageUtil.trace.resetTimer('paint'); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.paintDeviceRect(this.viewport_.getDeviceClipped(), 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentCanvas_, this.viewport_.getImageClipped()); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageUtil.trace.reportTimer('paint'); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} x X pointer position. 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} y Y pointer position. 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {boolean} mouseDown True if mouse is down. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {string} CSS cursor style. 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.getCursorStyle = function(x, y, mouseDown) { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Indicate that the image is draggable. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.viewport_.isClipped() && 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.viewport_.getScreenClipped().inside(x, y)) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 'move'; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return null; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} x X pointer position. 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} y Y pointer position. 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {function} The closure to call on drag. 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.getDragHandler = function(x, y) { 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var cursor = this.getCursorStyle(x, y); 161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (cursor === 'move') { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return the handler that drags the entire image. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this.viewport_.createOffsetSetter(x, y); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return null; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {number} The cache generation. 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.getCacheGeneration = function() { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this.contentGeneration_; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Invalidates the caches to force redrawing the screen canvas. 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.invalidateCaches = function() { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentGeneration_++; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {HTMLCanvasElement} The content canvas element. 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.getCanvas = function() { return this.contentCanvas_ }; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {boolean} True if the a valid image is currently loaded. 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.hasValidImage = function() { 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !this.preview_ && this.contentCanvas_ && this.contentCanvas_.width; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {HTMLVideoElement} The video element. 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.getVideo = function() { return this.videoElement_ }; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {HTMLCanvasElement} The cached thumbnail image. 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.getThumbnail = function() { return this.thumbnailCanvas_ }; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {number} The content revision number. 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.getContentRevision = function() { 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this.contentRevision_; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Copies an image fragment from a full resolution canvas to a device resolution 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * canvas. 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Rect} deviceRect Rectangle in the device coordinates. 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLCanvasElement} canvas Full resolution canvas. 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Rect} imageRect Rectangle in the full resolution canvas. 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.paintDeviceRect = function(deviceRect, canvas, imageRect) { 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Map screen canvas (0,0) to (deviceBounds.left, deviceBounds.top) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var deviceBounds = this.viewport_.getDeviceClipped(); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deviceRect = deviceRect.shift(-deviceBounds.left, -deviceBounds.top); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The source canvas may have different physical size than the image size 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // set at the viewport. Adjust imageRect accordingly. 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var bounds = this.viewport_.getImageBounds(); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var scaleX = canvas.width / bounds.width; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var scaleY = canvas.height / bounds.height; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) imageRect = new Rect(imageRect.left * scaleX, imageRect.top * scaleY, 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) imageRect.width * scaleX, imageRect.height * scaleY); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Rect.drawImage( 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.screenImage_.getContext('2d'), canvas, deviceRect, imageRect); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 237a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Creates an overlay canvas with properties similar to the screen canvas. 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Useful for showing quick feedback when editing. 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {HTMLCanvasElement} Overlay canvas. 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.createOverlayCanvas = function() { 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var canvas = this.document_.createElement('canvas'); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas.className = 'image'; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.container_.appendChild(canvas); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return canvas; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Sets up the canvas as a buffer in the device resolution. 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLCanvasElement} canvas The buffer canvas. 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.setupDeviceBuffer = function(canvas) { 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var deviceRect = this.viewport_.getDeviceClipped(); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the canvas position and size in device pixels. 258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (canvas.width !== deviceRect.width) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas.width = deviceRect.width; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 261a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (canvas.height !== deviceRect.height) 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas.height = deviceRect.height; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas.style.left = deviceRect.left + 'px'; 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas.style.top = deviceRect.top + 'px'; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Scale the canvas down to screen pixels. 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.setTransform(canvas); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {ImageData} A new ImageData object with a copy of the content. 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.copyScreenImageData = function() { 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this.screenImage_.getContext('2d').getImageData( 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, this.screenImage_.width, this.screenImage_.height); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {boolean} True if the image is currently being loaded. 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.isLoading = function() { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this.imageLoader_.isBusy(); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 287a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Cancels the current image loading operation. The callbacks will be ignored. 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.cancelLoad = function() { 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.imageLoader_.cancel(); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 294a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Loads and display a new image. 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Loads the thumbnail first, then replaces it with the main image. 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Takes into account the image orientation encoded in the metadata. 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 299a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {FileEntry} entry Image entry. 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} metadata Metadata. 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} effect Transition effect object. 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function(number} displayCallback Called when the image is displayed 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (possibly as a prevew). 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function(number} loadCallback Called when the image is fully loaded. 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The parameter is the load type. 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 307a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ImageView.prototype.load = function(entry, metadata, effect, 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) displayCallback, loadCallback) { 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (effect) { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip effects when reloading repeatedly very quickly. 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var time = Date.now(); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.lastLoadTime_ && 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (time - this.lastLoadTime_) < ImageView.FAST_SCROLL_INTERVAL) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) effect = null; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.lastLoadTime_ = time; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata = metadata || {}; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageUtil.metrics.startInterval(ImageUtil.getMetricName('DisplayTime')); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var self = this; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.contentEntry_ = entry; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentRevision_ = -1; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 328a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var loadingVideo = FileType.getMediaType(entry) === 'video'; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (loadingVideo) { 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var video = this.document_.createElement('video'); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var videoPreview = !!(metadata.thumbnail && metadata.thumbnail.url); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (videoPreview) { 3334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) var thumbnailLoader = new ThumbnailLoader( 3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) entry, 3354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ThumbnailLoader.LoaderType.CANVAS, 3364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) metadata); 3374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) thumbnailLoader.loadDetachedImage(function(success) { 3384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (success) { 3394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) var canvas = thumbnailLoader.getImage(); 3404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) video.setAttribute('poster', canvas.toDataURL('image/jpeg')); 3414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) this.replace(video, effect); // Show the poster immediately. 3424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (displayCallback) displayCallback(); 3434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) }.bind(this)); 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var onVideoLoad = function(error) { 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) video.removeEventListener('loadedmetadata', onVideoLoadSuccess); 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) video.removeEventListener('error', onVideoLoadError); 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) displayMainImage(ImageView.LOAD_TYPE_VIDEO_FILE, videoPreview, video, 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) error); 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }; 353a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var onVideoLoadError = onVideoLoad.bind(this, 'GALLERY_VIDEO_ERROR'); 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var onVideoLoadSuccess = onVideoLoad.bind(this, null); 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) video.addEventListener('loadedmetadata', onVideoLoadSuccess); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) video.addEventListener('error', onVideoLoadError); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 359a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) video.src = entry.toURL(); 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) video.load(); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Cache has to be evicted in advance, so the returned cached image is not 365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // evicted later by the prefetched image. 366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) this.contentCache_.evictLRU(); 367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 368a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var cached = this.contentCache_.getItem(this.contentEntry_); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cached) { 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) displayMainImage(ImageView.LOAD_TYPE_CACHED_FULL, 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false /* no preview */, cached); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 373a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var cachedScreen = this.screenCache_.getItem(this.contentEntry_); 3744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) var imageWidth = metadata.media && metadata.media.width || 3754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) metadata.drive && metadata.drive.imageWidth; 3764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) var imageHeight = metadata.media && metadata.media.height || 3774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) metadata.drive && metadata.drive.imageHeight; 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cachedScreen) { 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have a cached screen-scale canvas, use it instead of a thumbnail. 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) displayThumbnail(ImageView.LOAD_TYPE_CACHED_SCREEN, cachedScreen); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // As far as the user can tell the image is loaded. We still need to load 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the full res image to make editing possible, but we can report now. 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('DisplayTime')); 384f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else if ((effect && effect.constructor.name === 'Slide') && 385f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) (metadata.thumbnail && metadata.thumbnail.url)) { 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only show thumbnails if there is no effect or the effect is Slide. 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Also no thumbnail if the image is too large to be loaded. 3884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) var thumbnailLoader = new ThumbnailLoader( 3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) entry, 3904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ThumbnailLoader.LoaderType.CANVAS, 3914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) metadata); 3924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) thumbnailLoader.loadDetachedImage(function(success) { 3934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) displayThumbnail(ImageView.LOAD_TYPE_IMAGE_FILE, 3944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) success ? thumbnailLoader.getImage() : null); 3954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) }); 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 397a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) loadMainImage(ImageView.LOAD_TYPE_IMAGE_FILE, entry, 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false /* no preview*/, 0 /* delay */); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function displayThumbnail(loadType, canvas) { 4034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (canvas) { 40446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) var width = null; 40546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) var height = null; 40646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (metadata.media) { 40746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) width = metadata.media.width; 40846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) height = metadata.media.height; 40946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 41046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // If metadata.drive.present is true, the image data is loaded directly 41146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // from local cache, whose size may be out of sync with the drive 41246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // metadata. 41346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (metadata.drive && !metadata.drive.present) { 41446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) width = metadata.drive.imageWidth; 41546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) height = metadata.drive.imageHeight; 41646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 4174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self.replace( 4184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) canvas, 4194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) effect, 42046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) width, 42146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) height, 4224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) true /* preview */); 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (displayCallback) displayCallback(); 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 425a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) loadMainImage(loadType, entry, !!canvas, 4264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) (effect && canvas) ? effect.getSafeInterval() : 0); 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 429a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) function loadMainImage(loadType, contentEntry, previewShown, delay) { 430a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (self.prefetchLoader_.isLoading(contentEntry)) { 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The image we need is already being prefetched. Initiating another load 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // would be a waste. Hijack the load instead by overriding the callback. 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.prefetchLoader_.setCallback( 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) displayMainImage.bind(null, loadType, previewShown)); 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Swap the loaders so that the self.isLoading works correctly. 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var temp = self.prefetchLoader_; 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.prefetchLoader_ = self.imageLoader_; 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.imageLoader_ = temp; 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.prefetchLoader_.cancel(); // The prefetch was doing something useless. 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.imageLoader_.load( 445a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) contentEntry, 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.localImageTransformFetcher_, 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) displayMainImage.bind(null, loadType, previewShown), 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delay); 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function displayMainImage(loadType, previewShown, content, opt_error) { 452eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (opt_error) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loadType = ImageView.LOAD_TYPE_ERROR; 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we already displayed the preview we should not replace the content if: 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1. The full content failed to load. 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // or 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2. We are loading a video (because the full video is displayed in the 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // same HTML element as the preview). 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var animationDuration = 0; 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!(previewShown && 462a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) (loadType === ImageView.LOAD_TYPE_ERROR || 463a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) loadType === ImageView.LOAD_TYPE_VIDEO_FILE))) { 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var replaceEffect = previewShown ? null : effect; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animationDuration = replaceEffect ? replaceEffect.getSafeInterval() : 0; 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.replace(content, replaceEffect); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!previewShown && displayCallback) displayCallback(); 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 470a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (loadType !== ImageView.LOAD_TYPE_ERROR && 471a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) loadType !== ImageView.LOAD_TYPE_CACHED_SCREEN) { 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('DisplayTime')); 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('LoadMode'), 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loadType, ImageView.LOAD_TYPE_TOTAL); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 477a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (loadType === ImageView.LOAD_TYPE_ERROR && 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !navigator.onLine && metadata.streaming) { 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |streaming| is set only when the file is not locally cached. 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loadType = ImageView.LOAD_TYPE_OFFLINE; 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (loadCallback) loadCallback(loadType, animationDuration, opt_error); 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 487a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Prefetches an image. 488a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {FileEntry} entry The image entry. 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} delay Image load delay in ms. 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 491a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ImageView.prototype.prefetch = function(entry, delay) { 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var self = this; 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function prefetchDone(canvas) { 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (canvas.width) 495a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) self.contentCache_.putItem(entry, canvas); 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 498a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var cached = this.contentCache_.getItem(entry); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cached) { 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefetchDone(cached); 501a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } else if (FileType.getMediaType(entry) === 'image') { 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Evict the LRU item before we allocate the new canvas to avoid unneeded 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // strain on memory. 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentCache_.evictLRU(); 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.prefetchLoader_.load( 507a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) entry, 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.localImageTransformFetcher_, 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefetchDone, 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delay); 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 515a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Renames the current image. 516a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {FileEntry} newEntry The new image Entry. 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 518a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ImageView.prototype.changeEntry = function(newEntry) { 519a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.contentCache_.renameItem(this.contentEntry_, newEntry); 520a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.screenCache_.renameItem(this.contentEntry_, newEntry); 521a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.contentEntry_ = newEntry; 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 525a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Unloads content. 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Rect} zoomToRect Target rectangle for zoom-out-effect. 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.unload = function(zoomToRect) { 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.unloadTimer_) { 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clearTimeout(this.unloadTimer_); 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.unloadTimer_ = null; 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (zoomToRect && this.screenImage_) { 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var effect = this.createZoomEffect(zoomToRect); 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.setTransform(this.screenImage_, effect); 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.screenImage_.setAttribute('fade', true); 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.unloadTimer_ = setTimeout(function() { 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.unloadTimer_ = null; 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.unload(null /* force unload */); 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }.bind(this), 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) effect.getSafeInterval()); 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.container_.textContent = ''; 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentCanvas_ = null; 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.screenImage_ = null; 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.videoElement_ = null; 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLCanvasElement|HTMLVideoElement} content The image element. 5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_width Image width. 5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_height Image height. 5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {boolean=} opt_preview True if the image is a preview (not full res). 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.replaceContent_ = function( 55890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) content, opt_width, opt_height, opt_preview) { 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 560a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (this.contentCanvas_ && this.contentCanvas_.parentNode === this.container_) 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.container_.removeChild(this.contentCanvas_); 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 563a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (content.constructor.name === 'HTMLVideoElement') { 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentCanvas_ = null; 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.videoElement_ = content; 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.screenImage_ = content; 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.screenImage_.className = 'image'; 568eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch this.container_.appendChild(this.screenImage_); 569eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch this.videoElement_.play(); 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 57390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) this.screenImage_ = this.document_.createElement('canvas'); 57490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) this.screenImage_.className = 'image'; 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.videoElement_ = null; 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentCanvas_ = content; 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.invalidateCaches(); 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.viewport_.setImageSize( 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opt_width || this.contentCanvas_.width, 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opt_height || this.contentCanvas_.height); 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.viewport_.fitImage(); 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.viewport_.update(); 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.draw(); 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 58690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) this.container_.appendChild(this.screenImage_); 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.preview_ = opt_preview; 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If this is not a thumbnail, cache the content and the screen-scale image. 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.hasValidImage()) { 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Insert the full resolution canvas into DOM so that it can be printed. 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.container_.appendChild(this.contentCanvas_); 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentCanvas_.classList.add('fullres'); 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.contentCache_.putItem(this.contentEntry_, this.contentCanvas_, true); 596a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.screenCache_.putItem(this.contentEntry_, this.screenImage_); 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(kaznacheev): It is better to pass screenImage_ as it is usually 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // much smaller than contentCanvas_ and still contains the entire image. 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Once we implement zoom/pan we should pass contentCanvas_ instead. 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.updateThumbnail_(this.screenImage_); 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentRevision_++; 604a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (var i = 0; i !== this.contentCallbacks_.length; i++) { 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try { 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentCallbacks_[i](); 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } catch (e) { 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) console.error(e); 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 615a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Adds a listener for content changes. 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} callback Callback. 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.addContentCallback = function(callback) { 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.contentCallbacks_.push(callback); 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 623a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Updates the cached thumbnail image. 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLCanvasElement} canvas The source canvas. 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.updateThumbnail_ = function(canvas) { 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageUtil.trace.resetTimer('thumb'); 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var pixelCount = 10000; 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var downScale = 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Math.max(1, Math.sqrt(canvas.width * canvas.height / pixelCount)); 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.thumbnailCanvas_ = canvas.ownerDocument.createElement('canvas'); 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.thumbnailCanvas_.width = Math.round(canvas.width / downScale); 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.thumbnailCanvas_.height = Math.round(canvas.height / downScale); 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Rect.drawImage(this.thumbnailCanvas_.getContext('2d'), canvas); 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageUtil.trace.reportTimer('thumb'); 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 642a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Replaces the displayed image, possibly with slide-in animation. 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLCanvasElement|HTMLVideoElement} content The image element. 6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object=} opt_effect Transition effect object. 6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_width Image width. 6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_height Image height. 6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {boolean=} opt_preview True if the image is a preview (not full res). 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.replace = function( 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content, opt_effect, opt_width, opt_height, opt_preview) { 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var oldScreenImage = this.screenImage_; 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 65490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) this.replaceContent_(content, opt_width, opt_height, opt_preview); 65590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!opt_effect) { 65690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (oldScreenImage) 65790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) oldScreenImage.parentNode.removeChild(oldScreenImage); 65890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return; 65990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var newScreenImage = this.screenImage_; 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (oldScreenImage) 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageUtil.setAttribute(newScreenImage, 'fade', true); 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.setTransform(newScreenImage, opt_effect, 0 /* instant */); 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setTimeout(function() { 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.setTransform(newScreenImage, null, 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opt_effect && opt_effect.getDuration()); 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (oldScreenImage) { 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageUtil.setAttribute(newScreenImage, 'fade', false); 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageUtil.setAttribute(oldScreenImage, 'fade', true); 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) console.assert(opt_effect.getReverse, 'Cannot revert an effect.'); 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var reverse = opt_effect.getReverse(); 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.setTransform(oldScreenImage, reverse); 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setTimeout(function() { 6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (oldScreenImage.parentNode) 6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) oldScreenImage.parentNode.removeChild(oldScreenImage); 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, reverse.getSafeInterval()); 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }.bind(this), 0); 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLCanvasElement|HTMLVideoElement} element The element to transform. 6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {ImageView.Effect=} opt_effect The effect to apply. 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number=} opt_duration Transition duration. 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.setTransform = function(element, opt_effect, opt_duration) { 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!opt_effect) 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opt_effect = new ImageView.Effect.None(); 692a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (typeof opt_duration !== 'number') 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opt_duration = opt_effect.getDuration(); 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) element.style.webkitTransitionDuration = opt_duration + 'ms'; 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) element.style.webkitTransitionTimingFunction = opt_effect.getTiming(); 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) element.style.webkitTransform = opt_effect.transform(element, this.viewport_); 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Rect} screenRect Target rectangle in screen coordinates. 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {ImageView.Effect.Zoom} Zoom effect object. 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.createZoomEffect = function(screenRect) { 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new ImageView.Effect.Zoom( 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.viewport_.screenToDeviceRect(screenRect), 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) null /* use viewport */, 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageView.MODE_TRANSITION_DURATION); 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 711a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Visualizes crop or rotate operation. Hide the old image instantly, animate 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the new image to visualize the operation. 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLCanvasElement} canvas New content canvas. 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Rect} imageCropRect The crop rectangle in image coordinates. 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Null for rotation operations. 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} rotate90 Rotation angle in 90 degree increments. 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {number} Animation duration. 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.replaceAndAnimate = function( 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas, imageCropRect, rotate90) { 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var oldScale = this.viewport_.getScale(); 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var deviceCropRect = imageCropRect && this.viewport_.screenToDeviceRect( 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.viewport_.imageToScreenRect(imageCropRect)); 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var oldScreenImage = this.screenImage_; 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.replaceContent_(canvas); 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var newScreenImage = this.screenImage_; 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Display the new canvas, initially transformed. 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var deviceFullRect = this.viewport_.getDeviceClipped(); 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var effect = rotate90 ? 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new ImageView.Effect.Rotate( 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) oldScale / this.viewport_.getScale(), -rotate90) : 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new ImageView.Effect.Zoom(deviceCropRect, deviceFullRect); 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.setTransform(newScreenImage, effect, 0 /* instant */); 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) oldScreenImage.parentNode.appendChild(newScreenImage); 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) oldScreenImage.parentNode.removeChild(oldScreenImage); 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Let the layout fire, then animate back to non-transformed state. 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setTimeout( 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.setTransform.bind( 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, newScreenImage, null, effect.getDuration()), 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0); 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return effect.getSafeInterval(); 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 753a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Visualizes "undo crop". Shrink the current image to the given crop rectangle 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * while fading in the new image. 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLCanvasElement} canvas New content canvas. 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Rect} imageCropRect The crop rectangle in image coordinates. 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {number} Animation duration. 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.prototype.animateAndReplace = function(canvas, imageCropRect) { 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var deviceFullRect = this.viewport_.getDeviceClipped(); 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var oldScale = this.viewport_.getScale(); 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var oldScreenImage = this.screenImage_; 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.replaceContent_(canvas); 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var newScreenImage = this.screenImage_; 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var deviceCropRect = this.viewport_.screenToDeviceRect( 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.viewport_.imageToScreenRect(imageCropRect)); 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var setFade = ImageUtil.setAttribute.bind(null, newScreenImage, 'fade'); 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setFade(true); 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) oldScreenImage.parentNode.insertBefore(newScreenImage, oldScreenImage); 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var effect = new ImageView.Effect.Zoom(deviceCropRect, deviceFullRect); 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Animate to the transformed state. 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.setTransform(oldScreenImage, effect); 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setTimeout(setFade.bind(null, false), 0); 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setTimeout(function() { 7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (oldScreenImage.parentNode) 7832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) oldScreenImage.parentNode.removeChild(oldScreenImage); 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, effect.getSafeInterval()); 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return effect.getSafeInterval(); 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Generic cache with a limited capacity and LRU eviction. 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} capacity Maximum number of cached item. 7932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @constructor 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Cache = function(capacity) { 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.capacity_ = capacity; 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.map_ = {}; 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.order_ = []; 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 802a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Fetches the item from the cache. 803a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {FileEntry} entry The entry. 8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {Object} The cached item. 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 806a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ImageView.Cache.prototype.getItem = function(entry) { 807a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return this.map_[entry.toURL()]; 808a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}; 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 811a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Puts the item into the cache. 812a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * 813a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {FileEntry} entry The entry. 8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object} item The item object. 8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {boolean=} opt_keepLRU True if the LRU order should not be modified. 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 817a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ImageView.Cache.prototype.putItem = function(entry, item, opt_keepLRU) { 818a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var pos = this.order_.indexOf(entry.toURL()); 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 820a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if ((pos >= 0) !== (entry.toURL() in this.map_)) 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error('Inconsistent cache state'); 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 823a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (entry.toURL() in this.map_) { 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!opt_keepLRU) { 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Move to the end (most recently used). 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.order_.splice(pos, 1); 827a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.order_.push(entry.toURL()); 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.evictLRU(); 831a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.order_.push(entry.toURL()); 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 834a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if ((pos >= 0) && (item !== this.map_[entry.toURL()])) 835a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.deleteItem_(this.map_[entry.toURL()]); 836a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.map_[entry.toURL()] = item; 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.order_.length > this.capacity_) 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error('Exceeded cache capacity'); 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 843a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Evicts the least recently used items. 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Cache.prototype.evictLRU = function() { 846a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (this.order_.length === this.capacity_) { 847a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var url = this.order_.shift(); 848a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.deleteItem_(this.map_[url]); 849a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) delete this.map_[url]; 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 854a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Changes the Entry. 855a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {FileEntry} oldEntry The old Entry. 856a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {FileEntry} newEntry The new Entry. 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 858a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ImageView.Cache.prototype.renameItem = function(oldEntry, newEntry) { 859a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (util.isSameEntry(oldEntry, newEntry)) 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // No need to rename. 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 862a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var pos = this.order_.indexOf(oldEntry.toURL()); 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pos < 0) 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Not cached. 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 866a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.order_[pos] = newEntry.toURL(); 867a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this.map_[newEntry.toURL()] = this.map_[oldEntry.toURL()]; 868a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) delete this.map_[oldEntry.toURL()]; 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 8722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Disposes an object. 8732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 8742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object} item The item object. 8752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private 8762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 8772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ImageView.Cache.prototype.deleteItem_ = function(item) { 8782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Trick to reduce memory usage without waiting for gc. 8792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (item instanceof HTMLCanvasElement) { 8802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If the canvas is being used somewhere else (eg. displayed on the screen), 8812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // it will be cleared. 8822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) item.width = 0; 8832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) item.height = 0; 8842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 8852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 8862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Transition effects */ 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Base class for effects. 8912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} duration Duration in ms. 8932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {string=} opt_timing CSS transition timing function name. 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect = function(duration, opt_timing) { 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.duration_ = duration; 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.timing_ = opt_timing || 'linear'; 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.DEFAULT_DURATION = 180; 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.MARGIN = 100; 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {number} Effect duration in ms. 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.prototype.getDuration = function() { return this.duration_ }; 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {number} Delay in ms since the beginning of the animation after which 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * it is safe to perform CPU-heavy operations without disrupting the animation. 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.prototype.getSafeInterval = function() { 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this.getDuration() + ImageView.Effect.MARGIN; 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {string} CSS transition timing function name. 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.prototype.getTiming = function() { return this.timing_ }; 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLCanvasElement|HTMLVideoElement} element Element. 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {number} Preferred pixel ration to use with this element. 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.getPixelRatio_ = function(element) { 935a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (element.constructor.name === 'HTMLCanvasElement') 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Viewport.getDevicePixelRatio(); 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Default effect. It is not a no-op as it needs to adjust a canvas scale 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * for devicePixelRatio. 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.None = function() { 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageView.Effect.call(this, 0); 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Inherits from ImageView.Effect. 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.None.prototype = { __proto__: ImageView.Effect.prototype }; 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLCanvasElement|HTMLVideoElement} element Element. 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {string} Transform string. 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.None.prototype.transform = function(element) { 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var ratio = ImageView.Effect.getPixelRatio_(element); 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 'scale(' + (1 / ratio) + ')'; 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Slide effect. 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} direction -1 for left, 1 for right. 9692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {boolean=} opt_slow True if slow (as in slideshow). 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.Slide = function Slide(direction, opt_slow) { 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageView.Effect.call(this, 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opt_slow ? 800 : ImageView.Effect.DEFAULT_DURATION, 'ease-in-out'); 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.direction_ = direction; 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.slow_ = opt_slow; 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.shift_ = opt_slow ? 100 : 40; 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.direction_ < 0) this.shift_ = -this.shift_; 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Inherits from ImageView.Effect. 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.Slide.prototype = { __proto__: ImageView.Effect.prototype }; 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {ImageView.Effect.Slide} Reverse Slide effect. 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.Slide.prototype.getReverse = function() { 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new ImageView.Effect.Slide(-this.direction_, this.slow_); 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLCanvasElement|HTMLVideoElement} element Element. 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {string} Transform string. 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.Slide.prototype.transform = function(element) { 9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var ratio = ImageView.Effect.getPixelRatio_(element); 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 'scale(' + (1 / ratio) + ') translate(' + this.shift_ + 'px, 0px)'; 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Zoom effect. 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Animates the original rectangle to the target rectangle. Both parameters 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * should be given in device coordinates (accounting for devicePixelRatio). 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Rect} deviceTargetRect Target rectangle. 10092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Rect=} opt_deviceOriginalRect Original rectangle. If omitted, 10102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * the full viewport will be used at the time of |transform| call. 10112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_duration Duration in ms. 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.Zoom = function( 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deviceTargetRect, opt_deviceOriginalRect, opt_duration) { 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageView.Effect.call(this, 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opt_duration || ImageView.Effect.DEFAULT_DURATION); 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.target_ = deviceTargetRect; 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.original_ = opt_deviceOriginalRect; 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Inherits from ImageView.Effect. 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.Zoom.prototype = { __proto__: ImageView.Effect.prototype }; 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLCanvasElement|HTMLVideoElement} element Element. 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Viewport} viewport Viewport. 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {string} Transform string. 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.Zoom.prototype.transform = function(element, viewport) { 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.original_) 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.original_ = viewport.getDeviceClipped(); 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var ratio = ImageView.Effect.getPixelRatio_(element); 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var dx = (this.target_.left + this.target_.width / 2) - 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (this.original_.left + this.original_.width / 2); 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var dy = (this.target_.top + this.target_.height / 2) - 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (this.original_.top + this.original_.height / 2); 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var scaleX = this.target_.width / this.original_.width; 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var scaleY = this.target_.height / this.original_.height; 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 'translate(' + (dx / ratio) + 'px,' + (dy / ratio) + 'px) ' + 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'scaleX(' + (scaleX / ratio) + ') scaleY(' + (scaleY / ratio) + ')'; 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Rotate effect. 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} scale Scale. 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} rotate90 Rotation in 90 degrees increments. 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.Rotate = function(scale, rotate90) { 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageView.Effect.call(this, ImageView.Effect.DEFAULT_DURATION); 10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.scale_ = scale; 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.rotate90_ = rotate90; 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Inherits from ImageView.Effect. 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.Rotate.prototype = { __proto__: ImageView.Effect.prototype }; 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLCanvasElement|HTMLVideoElement} element Element. 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {string} Transform string. 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageView.Effect.Rotate.prototype.transform = function(element) { 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var ratio = ImageView.Effect.getPixelRatio_(element); 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 'rotate(' + (this.rotate90_ * 90) + 'deg) ' + 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'scale(' + (this.scale_ / ratio) + ')'; 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1077