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

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

Issue 1608143002: support animated GIF (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix a regression bug that the original image is not removed then the filter applied. Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * The overlay displaying the image. 6 * The overlay displaying the image.
7 * 7 *
8 * @param {!HTMLElement} container The container element. 8 * @param {!HTMLElement} container The container element.
9 * @param {!Viewport} viewport The viewport. 9 * @param {!Viewport} viewport The viewport.
10 * @param {!MetadataModel} metadataModel 10 * @param {!MetadataModel} metadataModel
(...skipping 20 matching lines...) Expand all
31 this.imageLoader_ = 31 this.imageLoader_ =
32 new ImageUtil.ImageLoader(this.document_, metadataModel); 32 new ImageUtil.ImageLoader(this.document_, metadataModel);
33 // We have a separate image loader for prefetch which does not get cancelled 33 // We have a separate image loader for prefetch which does not get cancelled
34 // when the selection changes. 34 // when the selection changes.
35 this.prefetchLoader_ = 35 this.prefetchLoader_ =
36 new ImageUtil.ImageLoader(this.document_, metadataModel); 36 new ImageUtil.ImageLoader(this.document_, metadataModel);
37 37
38 this.contentCallbacks_ = []; 38 this.contentCallbacks_ = [];
39 39
40 /** 40 /**
41 * The element displaying the current content. 41 * The content image or canvas element.
42 * @type {HTMLCanvasElement}
43 * @private
44 */
45 this.screenImage_ = null;
46
47 /**
48 * The content canvas element.
49 * @type {(HTMLCanvasElement|HTMLImageElement)} 42 * @type {(HTMLCanvasElement|HTMLImageElement)}
50 * @private 43 * @private
51 */ 44 */
52 this.contentCanvas_ = null; 45 this.contentImage_ = null;
53 46
54 /** 47 /**
55 * True if the image is a preview (not full res). 48 * True if the image is a preview (not full res).
56 * @type {boolean} 49 * @type {boolean}
57 * @private 50 * @private
58 */ 51 */
59 this.preview_ = false; 52 this.preview_ = false;
60 53
61 /** 54 /**
62 * Cached thumbnail image. 55 * Cached thumbnail image.
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 165
173 /** 166 /**
174 * @override 167 * @override
175 */ 168 */
176 ImageView.prototype.getZIndex = function() { return -1; }; 169 ImageView.prototype.getZIndex = function() { return -1; };
177 170
178 /** 171 /**
179 * @override 172 * @override
180 */ 173 */
181 ImageView.prototype.draw = function() { 174 ImageView.prototype.draw = function() {
182 if (!this.contentCanvas_) // Do nothing if the image content is not set. 175 if (!this.contentImage_) // Do nothing if the image content is not set.
183 return; 176 return;
184 this.setTransform_( 177 this.setTransform_(
185 this.contentCanvas_, 178 this.contentImage_,
186 this.viewport_, 179 this.viewport_,
187 new ImageView.Effect.None(), 180 new ImageView.Effect.None(),
188 ImageView.Effect.DEFAULT_DURATION); 181 0);
189 if ((this.screenImage_ && this.setupDeviceBuffer(this.screenImage_)) ||
190 this.displayedContentGeneration_ !== this.contentGeneration_) {
191 this.displayedContentGeneration_ = this.contentGeneration_;
192 ImageUtil.trace.resetTimer('paint');
193 this.paintDeviceRect(
194 this.contentCanvas_, ImageRect.createFromImage(this.contentCanvas_));
195 ImageUtil.trace.reportTimer('paint');
196 }
197 }; 182 };
198 183
199 /** 184 /**
200 * Applies the viewport change that does not affect the screen cache size (zoom 185 * Applies the viewport change that does not affect the screen cache size (zoom
201 * change or offset change) with animation. 186 * change or offset change) with animation.
202 */ 187 */
203 ImageView.prototype.applyViewportChange = function() { 188 ImageView.prototype.applyViewportChange = function() {
204 var zooming = this.viewport_.getZoom() > 1; 189 if (this.contentImage_) {
205 if (this.contentCanvas_) {
206 // Show full resolution image only for zooming.
207 this.contentCanvas_.style.opacity = zooming ? '1' : '0';
208 this.setTransform_( 190 this.setTransform_(
209 this.contentCanvas_, 191 this.contentImage_,
210 this.viewport_, 192 this.viewport_,
211 new ImageView.Effect.None(), 193 new ImageView.Effect.None(),
212 ImageView.Effect.DEFAULT_DURATION); 194 ImageView.Effect.DEFAULT_DURATION);
213 } 195 }
214 if (this.screenImage_) {
215 this.setTransform_(
216 this.screenImage_,
217 this.viewport_,
218 new ImageView.Effect.None(),
219 ImageView.Effect.DEFAULT_DURATION);
220 }
221 }; 196 };
222 197
223 /** 198 /**
224 * @return {number} The cache generation. 199 * @return {number} The cache generation.
225 */ 200 */
226 ImageView.prototype.getCacheGeneration = function() { 201 ImageView.prototype.getCacheGeneration = function() {
227 return this.contentGeneration_; 202 return this.contentGeneration_;
228 }; 203 };
229 204
230 /** 205 /**
231 * Invalidates the caches to force redrawing the screen canvas. 206 * Invalidates the caches to force redrawing the screen canvas.
232 */ 207 */
233 ImageView.prototype.invalidateCaches = function() { 208 ImageView.prototype.invalidateCaches = function() {
234 this.contentGeneration_++; 209 this.contentGeneration_++;
235 }; 210 };
236 211
237 /** 212 /**
238 * @return {HTMLCanvasElement} The content canvas element. 213 * @return {!HTMLCanvasElement|!HTMLImageElement} The content image(or canvas).
239 */ 214 */
240 ImageView.prototype.getCanvas = function() { return this.contentCanvas_; }; 215 ImageView.prototype.getImage = function() {
216 return assert(this.contentImage_);
217 };
241 218
242 /** 219 /**
243 * @return {boolean} True if the a valid image is currently loaded. 220 * @return {boolean} True if the a valid image is currently loaded.
244 */ 221 */
245 ImageView.prototype.hasValidImage = function() { 222 ImageView.prototype.hasValidImage = function() {
246 return !!(!this.preview_ && this.contentCanvas_ && this.contentCanvas_.width); 223 return !!(!this.preview_ && this.contentImage_ && this.contentImage_.width);
247 }; 224 };
248 225
249 /** 226 /**
250 * @return {!HTMLCanvasElement} The cached thumbnail image. 227 * @return {!HTMLCanvasElement} The cached thumbnail image.
251 */ 228 */
252 ImageView.prototype.getThumbnail = function() { 229 ImageView.prototype.getThumbnail = function() {
253 assert(this.thumbnailCanvas_); 230 assert(this.thumbnailCanvas_);
254 return this.thumbnailCanvas_; 231 return this.thumbnailCanvas_;
255 }; 232 };
256 233
257 /** 234 /**
258 * @return {number} The content revision number. 235 * @return {number} The content revision number.
259 */ 236 */
260 ImageView.prototype.getContentRevision = function() { 237 ImageView.prototype.getContentRevision = function() {
261 return this.contentRevision_; 238 return this.contentRevision_;
262 }; 239 };
263 240
264 /** 241 /**
265 * Copies an image fragment from a full resolution canvas to a device resolution 242 * Copies an image fragment to a content image.
266 * canvas.
267 * 243 *
268 * @param {!HTMLCanvasElement} canvas Canvas containing whole image. The canvas 244 * @param {!HTMLCanvasElement} canvas Canvas containing whole image. The canvas
269 * may not be full resolution (scaled). 245 * may not be full resolution (scaled).
270 * @param {!ImageRect} imageRect Rectangle region of the canvas to be rendered. 246 * @param {!ImageRect} imageRect Rectangle region of the canvas to be rendered.
271 */ 247 */
272 ImageView.prototype.paintDeviceRect = function(canvas, imageRect) { 248 ImageView.prototype.paintDeviceRect = function(canvas, imageRect) {
273 // Map the rectangle in full resolution image to the rectangle in the device 249 // Map the rectangle in full resolution image to the rectangle in the device
274 // canvas. 250 // canvas.
251 // TODO(ryoh): Shold we prepare a device-res canvas to show?
275 var deviceBounds = this.viewport_.getDeviceBounds(); 252 var deviceBounds = this.viewport_.getDeviceBounds();
276 var scaleX = deviceBounds.width / canvas.width; 253 var scaleX = deviceBounds.width / canvas.width;
277 var scaleY = deviceBounds.height / canvas.height; 254 var scaleY = deviceBounds.height / canvas.height;
278 var deviceRect = new ImageRect( 255 var deviceRect = new ImageRect(
279 imageRect.left * scaleX, 256 imageRect.left * scaleX,
280 imageRect.top * scaleY, 257 imageRect.top * scaleY,
281 imageRect.width * scaleX, 258 imageRect.width * scaleX,
282 imageRect.height * scaleY); 259 imageRect.height * scaleY);
283 260
261 var canvas = ImageUtil.ensureCanvas(this.contentImage_);
262 if (canvas !== this.contentImage_) {
263 this.replace(canvas);
hirono 2016/01/22 07:24:18 Maybe replaceContent is enough here since we don't
ryoh 2016/01/25 03:29:25 That's right, because we do not need any effect!
264 this.contentImage_ = canvas;
yawano 2016/01/22 07:02:49 nit: This line is unnecessary. replaceContent_() w
ryoh 2016/01/25 03:29:25 Done.
265 }
284 ImageRect.drawImage( 266 ImageRect.drawImage(
285 this.screenImage_.getContext('2d'), canvas, deviceRect, imageRect); 267 this.contentImage_.getContext('2d'), canvas, deviceRect, imageRect);
286 }; 268 };
287 269
288 /** 270 /**
289 * Creates an overlay canvas with properties similar to the screen canvas. 271 * Creates an overlay canvas with properties similar to the screen canvas.
290 * Useful for showing quick feedback when editing. 272 * Useful for showing quick feedback when editing.
291 * 273 *
292 * @return {!HTMLCanvasElement} Overlay canvas. 274 * @return {!HTMLCanvasElement} Overlay canvas.
293 */ 275 */
294 ImageView.prototype.createOverlayCanvas = function() { 276 ImageView.prototype.createOverlayCanvas = function() {
295 var canvas = assertInstanceof(this.document_.createElement('canvas'), 277 var canvas = assertInstanceof(this.document_.createElement('canvas'),
(...skipping 19 matching lines...) Expand all
315 } 297 }
316 if (canvas.height !== deviceRect.height) { 298 if (canvas.height !== deviceRect.height) {
317 canvas.height = deviceRect.height; 299 canvas.height = deviceRect.height;
318 needRepaint = true; 300 needRepaint = true;
319 } 301 }
320 this.setTransform_(canvas, this.viewport_); 302 this.setTransform_(canvas, this.viewport_);
321 return needRepaint; 303 return needRepaint;
322 }; 304 };
323 305
324 /** 306 /**
325 * Gets screen image data with specified size. 307 * Gets screen image canvas with specified size.
326 * @param {number} width 308 * @param {number} width
327 * @param {number} height 309 * @param {number} height
328 * @return {!ImageData} A new ImageData object. 310 * @return {!HTMLCanvasElement} A scaled canvas.
329 */ 311 */
330 ImageView.prototype.getScreenImageDataWith = function(width, height) { 312 ImageView.prototype.getImageCanvasWith = function(width, height) {
331 // If specified size is same with current screen image size, just return it.
332 if (width === this.screenImage_.width &&
333 height === this.screenImage_.height) {
334 return this.screenImage_.getContext('2d').getImageData(
335 0, 0, this.screenImage_.width, this.screenImage_.height);
336 }
337
338 // Resize if these sizes are different. 313 // Resize if these sizes are different.
339 var resizeCanvas = document.createElement('canvas'); 314 var resizeCanvas = assertInstanceof(document.createElement('canvas'),
315 HTMLCanvasElement);
340 resizeCanvas.width = width; 316 resizeCanvas.width = width;
341 resizeCanvas.height = height; 317 resizeCanvas.height = height;
342 318
343 var context = resizeCanvas.getContext('2d'); 319 var context = resizeCanvas.getContext('2d');
344 context.drawImage(this.screenImage_, 320 context.drawImage(this.contentImage_,
345 0, 0, this.screenImage_.width, this.screenImage_.height, 321 0, 0, this.contentImage_.width, this.contentImage_.height,
346 0, 0, resizeCanvas.width, resizeCanvas.height); 322 0, 0, resizeCanvas.width, resizeCanvas.height);
347 return context.getImageData(0, 0, resizeCanvas.width, resizeCanvas.height); 323 return resizeCanvas;
348 }; 324 };
349 325
350 /** 326 /**
351 * @return {boolean} True if the image is currently being loaded. 327 * @return {boolean} True if the image is currently being loaded.
352 */ 328 */
353 ImageView.prototype.isLoading = function() { 329 ImageView.prototype.isLoading = function() {
354 return this.imageLoader_.isBusy(); 330 return this.imageLoader_.isBusy();
355 }; 331 };
356 332
357 /** 333 /**
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 510
535 /** 511 /**
536 * Unloads content. 512 * Unloads content.
537 * @param {ImageRect=} opt_zoomToRect Target rectangle for zoom-out-effect. 513 * @param {ImageRect=} opt_zoomToRect Target rectangle for zoom-out-effect.
538 */ 514 */
539 ImageView.prototype.unload = function(opt_zoomToRect) { 515 ImageView.prototype.unload = function(opt_zoomToRect) {
540 if (this.unloadTimer_) { 516 if (this.unloadTimer_) {
541 clearTimeout(this.unloadTimer_); 517 clearTimeout(this.unloadTimer_);
542 this.unloadTimer_ = null; 518 this.unloadTimer_ = null;
543 } 519 }
544 if (opt_zoomToRect && this.screenImage_) { 520 if (opt_zoomToRect && this.contentImage_) {
545 var effect = this.createZoomEffect(opt_zoomToRect); 521 var effect = this.createZoomEffect(opt_zoomToRect);
546 this.setTransform_(this.screenImage_, this.viewport_, effect); 522 this.setTransform_(this.contentImage_, this.viewport_, effect);
547 this.screenImage_.setAttribute('fade', true); 523 this.contentImage_.setAttribute('fade', true);
548 this.unloadTimer_ = setTimeout(function() { 524 this.unloadTimer_ = setTimeout(function() {
549 this.unloadTimer_ = null; 525 this.unloadTimer_ = null;
550 this.unload(null /* force unload */); 526 this.unload(null /* force unload */);
551 }.bind(this), effect.getSafeInterval()); 527 }.bind(this), effect.getSafeInterval());
552 return; 528 return;
553 } 529 }
554 this.container_.textContent = ''; 530 this.container_.textContent = '';
555 this.contentCanvas_ = null; 531 this.contentImage_ = null;
556 this.screenImage_ = null;
557 }; 532 };
558 533
559 /** 534 /**
560 * @param {!(HTMLCanvasElement|HTMLImageElement)} content The image element. 535 * @param {!(HTMLCanvasElement|HTMLImageElement)} content The image element.
561 * @param {number=} opt_width Image width. 536 * @param {number=} opt_width Image width.
562 * @param {number=} opt_height Image height. 537 * @param {number=} opt_height Image height.
563 * @param {boolean=} opt_preview True if the image is a preview (not full res). 538 * @param {boolean=} opt_preview True if the image is a preview (not full res).
564 * @private 539 * @private
565 */ 540 */
566 ImageView.prototype.replaceContent_ = function( 541 ImageView.prototype.replaceContent_ = function(
567 content, opt_width, opt_height, opt_preview) { 542 content, opt_width, opt_height, opt_preview) {
568 543
569 if (this.contentCanvas_ && this.contentCanvas_.parentNode === this.container_) 544 if (this.contentImage_ && this.contentImage_.parentNode === this.container_)
570 this.container_.removeChild(this.contentCanvas_); 545 this.container_.removeChild(this.contentImage_);
571 546
572 this.screenImage_ = assertInstanceof(this.document_.createElement('canvas'), 547 this.contentImage_ = content;
573 HTMLCanvasElement); 548 this.container_.appendChild(content);
574 this.screenImage_.className = 'image'; 549 ImageUtil.setAttribute(this.contentImage_, 'fade', false);
575
576 this.contentCanvas_ = content;
577 this.invalidateCaches(); 550 this.invalidateCaches();
578 this.viewport_.setImageSize( 551 this.viewport_.setImageSize(
579 opt_width || this.contentCanvas_.width, 552 opt_width || this.contentImage_.width,
580 opt_height || this.contentCanvas_.height); 553 opt_height || this.contentImage_.height);
581 this.draw(); 554 this.draw();
582 555
583 this.container_.appendChild(this.screenImage_);
584
585 this.preview_ = opt_preview || false; 556 this.preview_ = opt_preview || false;
586 // If this is not a thumbnail, cache the content and the screen-scale image. 557 // If this is not a thumbnail, cache the content and the screen-scale image.
587 if (this.hasValidImage()) { 558 if (this.hasValidImage()) {
588 // Insert the full resolution canvas into DOM so that it can be printed. 559 // Insert the full resolution canvas into DOM so that it can be printed.
589 this.container_.appendChild(this.contentCanvas_); 560 this.contentImage_.classList.add('image');
590 this.contentCanvas_.classList.add('fullres'); 561 this.setTransform_(this.contentImage_, this.viewport_, null, 0);
591 this.setTransform_(
592 this.contentCanvas_, this.viewport_, null, 0);
593 562
594 this.contentItem_.contentImage = this.contentCanvas_; 563 this.contentItem_.contentImage = this.contentImage_;
595 this.contentItem_.screenImage = this.screenImage_;
596 564
597 // TODO(kaznacheev): It is better to pass screenImage_ as it is usually 565 this.updateThumbnail_(this.contentImage_);
598 // much smaller than contentCanvas_ and still contains the entire image.
599 // Once we implement zoom/pan we should pass contentCanvas_ instead.
600 this.updateThumbnail_(this.screenImage_);
601 566
602 this.contentRevision_++; 567 this.contentRevision_++;
603 for (var i = 0; i !== this.contentCallbacks_.length; i++) { 568 for (var i = 0; i !== this.contentCallbacks_.length; i++) {
604 try { 569 try {
605 this.contentCallbacks_[i](); 570 this.contentCallbacks_[i]();
606 } catch (e) { 571 } catch (e) {
607 console.error(e); 572 console.error(e);
608 } 573 }
609 } 574 }
610 } 575 }
611 }; 576 };
612 577
613 /** 578 /**
614 * Adds a listener for content changes. 579 * Adds a listener for content changes.
615 * @param {function()} callback Callback. 580 * @param {function()} callback Callback.
616 */ 581 */
617 ImageView.prototype.addContentCallback = function(callback) { 582 ImageView.prototype.addContentCallback = function(callback) {
618 this.contentCallbacks_.push(callback); 583 this.contentCallbacks_.push(callback);
619 }; 584 };
620 585
621 /** 586 /**
622 * Updates the cached thumbnail image. 587 * Updates the cached thumbnail image.
623 * 588 *
624 * @param {!HTMLCanvasElement} canvas The source canvas. 589 * @param {!HTMLCanvasElement|!HTMLImageElement} image The source image or
590 * canvas.
625 * @private 591 * @private
626 */ 592 */
627 ImageView.prototype.updateThumbnail_ = function(canvas) { 593 ImageView.prototype.updateThumbnail_ = function(image) {
628 ImageUtil.trace.resetTimer('thumb'); 594 ImageUtil.trace.resetTimer('thumb');
629 var pixelCount = 10000; 595 var pixelCount = 10000;
630 var downScale = 596 var downScale =
631 Math.max(1, Math.sqrt(canvas.width * canvas.height / pixelCount)); 597 Math.max(1, Math.sqrt(image.width * image.height / pixelCount));
632 598
633 this.thumbnailCanvas_ = canvas.ownerDocument.createElement('canvas'); 599 this.thumbnailCanvas_ = image.ownerDocument.createElement('canvas');
634 this.thumbnailCanvas_.width = Math.round(canvas.width / downScale); 600 this.thumbnailCanvas_.width = Math.round(image.width / downScale);
635 this.thumbnailCanvas_.height = Math.round(canvas.height / downScale); 601 this.thumbnailCanvas_.height = Math.round(image.height / downScale);
636 ImageRect.drawImage(this.thumbnailCanvas_.getContext('2d'), canvas); 602 ImageRect.drawImage(this.thumbnailCanvas_.getContext('2d'), image);
637 ImageUtil.trace.reportTimer('thumb'); 603 ImageUtil.trace.reportTimer('thumb');
638 }; 604 };
639 605
640 /** 606 /**
641 * Replaces the displayed image, possibly with slide-in animation. 607 * Replaces the displayed image, possibly with slide-in animation.
642 * 608 *
643 * @param {!(HTMLCanvasElement|HTMLImageElement)} content The image element. 609 * @param {!(HTMLCanvasElement|HTMLImageElement)} newContentImage
610 * The image element.
644 * @param {ImageView.Effect=} opt_effect Transition effect object. 611 * @param {ImageView.Effect=} opt_effect Transition effect object.
645 * @param {number=} opt_width Image width. 612 * @param {number=} opt_width Image width.
646 * @param {number=} opt_height Image height. 613 * @param {number=} opt_height Image height.
647 * @param {boolean=} opt_preview True if the image is a preview (not full res). 614 * @param {boolean=} opt_preview True if the image is a preview (not full res).
648 */ 615 */
649 ImageView.prototype.replace = function( 616 ImageView.prototype.replace = function(
650 content, opt_effect, opt_width, opt_height, opt_preview) { 617 newContentImage, opt_effect, opt_width, opt_height, opt_preview) {
651 var oldScreenImage = this.screenImage_; 618 var oldContentImage = this.contentImage_;
652 var oldViewport = this.viewport_.clone(); 619 var oldViewport = this.viewport_.clone();
653 this.replaceContent_(content, opt_width, opt_height, opt_preview); 620 this.replaceContent_(newContentImage, opt_width, opt_height, opt_preview);
654 if (!opt_effect) { 621 if (!opt_effect) {
655 if (oldScreenImage)
656 oldScreenImage.parentNode.removeChild(oldScreenImage);
657 return; 622 return;
658 } 623 }
659 624
660 assert(this.screenImage_); 625 assert(this.contentImage_);
661 var newScreenImage = this.screenImage_;
662 this.viewport_.resetView(); 626 this.viewport_.resetView();
663 627
664 if (oldScreenImage) 628 if (oldContentImage)
665 ImageUtil.setAttribute(newScreenImage, 'fade', true); 629 ImageUtil.setAttribute(newContentImage, 'fade', true);
hirono 2016/01/22 07:24:18 To show 'fade' animation here, we should not remov
ryoh 2016/01/25 03:29:25 Done.
666 this.setTransform_( 630 this.setTransform_(
667 newScreenImage, this.viewport_, opt_effect, 0 /* instant */); 631 newContentImage, this.viewport_, opt_effect, 0 /* instant */);
668 this.setTransform_(
669 content, this.viewport_, opt_effect, 0 /* instant */);
670 632
671 // We need to call requestAnimationFrame twice here. The first call is for 633 // We need to call requestAnimationFrame twice here. The first call is for
672 // commiting the styles of beggining of transition that are assigned above. 634 // commiting the styles of beggining of transition that are assigned above.
673 // The second call is for assigning and commiting the styles of end of 635 // The second call is for assigning and commiting the styles of end of
674 // transition, which triggers transition animation. 636 // transition, which triggers transition animation.
675 requestAnimationFrame(function() { 637 requestAnimationFrame(function() {
676 requestAnimationFrame(function() { 638 requestAnimationFrame(function() {
677 this.setTransform_( 639 this.setTransform_(
678 newScreenImage, 640 newContentImage,
679 this.viewport_, 641 this.viewport_,
680 null, 642 null,
681 opt_effect ? opt_effect.getDuration() : undefined); 643 opt_effect ? opt_effect.getDuration() : undefined);
682 this.setTransform_( 644 if (oldContentImage) {
683 content, 645 ImageUtil.setAttribute(newContentImage, 'fade', false);
684 this.viewport_, 646 ImageUtil.setAttribute(oldContentImage, 'fade', true);
685 null,
686 opt_effect ? opt_effect.getDuration() : undefined);
687 if (oldScreenImage) {
688 ImageUtil.setAttribute(newScreenImage, 'fade', false);
689 ImageUtil.setAttribute(oldScreenImage, 'fade', true);
690 var reverse = opt_effect.getReverse(); 647 var reverse = opt_effect.getReverse();
691 if (reverse) { 648 if (reverse) {
692 this.setTransform_(oldScreenImage, oldViewport, reverse); 649 this.setTransform_(oldContentImage, oldViewport, reverse);
693 setTimeout(function() { 650 setTimeout(function() {
694 if (oldScreenImage.parentNode) 651 if (oldContentImage.parentNode)
695 oldScreenImage.parentNode.removeChild(oldScreenImage); 652 oldContentImage.parentNode.removeChild(oldContentImage);
696 }, reverse.getSafeInterval()); 653 }, reverse.getSafeInterval());
697 } else { 654 } else {
698 if (oldScreenImage.parentNode) 655 if (oldContentImage.parentNode)
699 oldScreenImage.parentNode.removeChild(oldScreenImage); 656 oldContentImage.parentNode.removeChild(oldContentImage);
700 } 657 }
701 } 658 }
702 }.bind(this)); 659 }.bind(this));
703 }.bind(this)); 660 }.bind(this));
704 }; 661 };
705 662
706 /** 663 /**
707 * @param {!HTMLCanvasElement|!HTMLImageElement} element The element to 664 * @param {!HTMLCanvasElement|!HTMLImageElement} element The element to
708 * transform. 665 * transform.
709 * @param {!Viewport} viewport Viewport to be used for calculating 666 * @param {!Viewport} viewport Viewport to be used for calculating
(...skipping 29 matching lines...) Expand all
739 * the new image to visualize the operation. 696 * the new image to visualize the operation.
740 * 697 *
741 * @param {!HTMLCanvasElement} canvas New content canvas. 698 * @param {!HTMLCanvasElement} canvas New content canvas.
742 * @param {ImageRect} imageCropRect The crop rectangle in image coordinates. 699 * @param {ImageRect} imageCropRect The crop rectangle in image coordinates.
743 * Null for rotation operations. 700 * Null for rotation operations.
744 * @param {number} rotate90 Rotation angle in 90 degree increments. 701 * @param {number} rotate90 Rotation angle in 90 degree increments.
745 * @return {number} Animation duration. 702 * @return {number} Animation duration.
746 */ 703 */
747 ImageView.prototype.replaceAndAnimate = function( 704 ImageView.prototype.replaceAndAnimate = function(
748 canvas, imageCropRect, rotate90) { 705 canvas, imageCropRect, rotate90) {
749 assert(this.screenImage_); 706 assert(this.contentImage_);
750 707
751 var oldImageBounds = { 708 var oldImageBounds = {
752 width: this.viewport_.getImageBounds().width, 709 width: this.viewport_.getImageBounds().width,
753 height: this.viewport_.getImageBounds().height 710 height: this.viewport_.getImageBounds().height
754 }; 711 };
755 var oldScreenImage = this.screenImage_; 712 var oldScreenImage = this.contentImage_;
756 this.replaceContent_(canvas); 713 this.replaceContent_(canvas);
757 var newScreenImage = this.screenImage_; 714 var newScreenImage = this.contentImage_;
758 var effect = rotate90 ? 715 var effect = rotate90 ?
759 new ImageView.Effect.Rotate(rotate90 > 0) : 716 new ImageView.Effect.Rotate(rotate90 > 0) :
760 new ImageView.Effect.Zoom( 717 new ImageView.Effect.Zoom(
761 oldImageBounds.width, oldImageBounds.height, assert(imageCropRect)); 718 oldImageBounds.width, oldImageBounds.height, assert(imageCropRect));
762 719
763 this.setTransform_(newScreenImage, this.viewport_, effect, 0 /* instant */); 720 this.setTransform_(newScreenImage, this.viewport_, effect, 0 /* instant */);
764 721
765 oldScreenImage.parentNode.appendChild(newScreenImage);
766 oldScreenImage.parentNode.removeChild(oldScreenImage);
767
768 // Let the layout fire, then animate back to non-transformed state. 722 // Let the layout fire, then animate back to non-transformed state.
769 setTimeout( 723 setTimeout(
770 this.setTransform_.bind( 724 this.setTransform_.bind(
771 this, newScreenImage, this.viewport_, null, effect.getDuration()), 725 this, newScreenImage, this.viewport_, null, effect.getDuration()),
772 0); 726 0);
773 727
774 return effect.getSafeInterval(); 728 return effect.getSafeInterval();
775 }; 729 };
776 730
777 /** 731 /**
778 * Visualizes "undo crop". Shrink the current image to the given crop rectangle 732 * Visualizes "undo crop". Shrink the current image to the given crop rectangle
779 * while fading in the new image. 733 * while fading in the new image.
780 * 734 *
781 * @param {!HTMLCanvasElement} canvas New content canvas. 735 * @param {!HTMLCanvasElement} canvas New content canvas.
782 * @param {!ImageRect} imageCropRect The crop rectangle in image coordinates. 736 * @param {!ImageRect} imageCropRect The crop rectangle in image coordinates.
783 * @return {number} Animation duration. 737 * @return {number} Animation duration.
784 */ 738 */
785 ImageView.prototype.animateAndReplace = function(canvas, imageCropRect) { 739 ImageView.prototype.animateAndReplace = function(canvas, imageCropRect) {
786 var oldScreenImage = this.screenImage_; 740 var oldScreenImage = assert(this.contentImage_);
741 oldScreenImage.style.zIndex = 1000;
787 this.replaceContent_(canvas); 742 this.replaceContent_(canvas);
788 var newScreenImage = this.screenImage_; 743 this.container_.appendChild(oldScreenImage);
744 var newScreenImage = this.contentImage_;
789 var setFade = ImageUtil.setAttribute.bind(null, assert(newScreenImage), 745 var setFade = ImageUtil.setAttribute.bind(null, assert(newScreenImage),
790 'fade'); 746 'fade');
791 setFade(true); 747 setFade(true);
792 oldScreenImage.parentNode.insertBefore(newScreenImage, oldScreenImage);
793 var effect = new ImageView.Effect.Zoom( 748 var effect = new ImageView.Effect.Zoom(
794 this.viewport_.getImageBounds().width, 749 this.viewport_.getImageBounds().width,
795 this.viewport_.getImageBounds().height, 750 this.viewport_.getImageBounds().height,
796 imageCropRect); 751 imageCropRect);
752 // Animate to the transformed state.
753 setTimeout(function() {
hirono 2016/01/22 07:24:18 Actually setTimeout is not enough to ensure trigge
ryoh 2016/01/25 03:29:26 Done.
754 this.setTransform_(oldScreenImage, this.viewport_, effect);
hirono 2016/01/22 07:24:18 I think we can call setFade(false) here and remove
ryoh 2016/01/25 03:29:26 merged to the closure above.
755 }.bind(this), 0);
797 756
798 // Animate to the transformed state.
799 this.setTransform_(oldScreenImage, this.viewport_, effect);
800 setTimeout(setFade.bind(null, false), 0); 757 setTimeout(setFade.bind(null, false), 0);
758
801 setTimeout(function() { 759 setTimeout(function() {
802 if (oldScreenImage.parentNode) 760 if (oldScreenImage.parentNode)
hirono 2016/01/22 07:24:18 Please fix the indent.
ryoh 2016/01/25 03:29:25 Done.
803 oldScreenImage.parentNode.removeChild(oldScreenImage); 761 oldScreenImage.parentNode.removeChild(oldScreenImage);
hirono 2016/01/22 07:24:18 Could you clear zIndex here (or we can ensure oldS
ryoh 2016/01/25 03:29:25 We may reuse the images. I will clear the z-index
804 }, effect.getSafeInterval()); 762 }, effect.getSafeInterval());
805 763
806 return effect.getSafeInterval(); 764 return effect.getSafeInterval();
807 }; 765 };
808 766
809 /* Transition effects */ 767 /* Transition effects */
810 768
811 /** 769 /**
812 * Base class for effects. 770 * Base class for effects.
813 * 771 *
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
1015 973
1016 ImageView.Effect.Rotate.prototype = { __proto__: ImageView.Effect.prototype }; 974 ImageView.Effect.Rotate.prototype = { __proto__: ImageView.Effect.prototype };
1017 975
1018 /** 976 /**
1019 * @override 977 * @override
1020 */ 978 */
1021 ImageView.Effect.Rotate.prototype.transform = function(element, viewport) { 979 ImageView.Effect.Rotate.prototype.transform = function(element, viewport) {
1022 return viewport.getRotatingTransformation( 980 return viewport.getRotatingTransformation(
1023 element.width, element.height, this.orientation_ ? -1 : 1); 981 element.width, element.height, this.orientation_ ? -1 : 1);
1024 }; 982 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698