Commit 171777f7 authored by hirono's avatar hirono Committed by Commit bot

Gallery: Takes into account target canvas size when calculating view port.

Gallery applies viewport both screen size cache, and full resolution image. To
handle the different size of two images, it used to set CSS 'width' and 'height'
style to the full resolution image so that the full resolution image can be
regarded as the same size of screen cache image.

But ImageView.Effect class, which is used for playing edit animation, does not
update the CSS properties. It causes wrong layout during the edit animation.

The CL removes the trick of CSS property, and let ImageView.Effect take into
account of the size of target canvas.

BUG=487129
TEST=Do and undo cropping and rotaiton.

Review URL: https://codereview.chromium.org/1138053003

Cr-Commit-Position: refs/heads/master@{#329793}
parent 5c23b37e
...@@ -701,11 +701,6 @@ ImageView.prototype.setTransform_ = function( ...@@ -701,11 +701,6 @@ ImageView.prototype.setTransform_ = function(
element.style.transitionDuration = opt_duration + 'ms'; element.style.transitionDuration = opt_duration + 'ms';
element.style.transitionTimingFunction = opt_effect.getTiming(); element.style.transitionTimingFunction = opt_effect.getTiming();
element.style.transform = opt_effect.transform(element, viewport); element.style.transform = opt_effect.transform(element, viewport);
var imageBounds = viewport.getImageElementBoundsOnScreen();
element.style.left = imageBounds.left + 'px';
element.style.top = imageBounds.top + 'px';
element.style.width = imageBounds.width + 'px';
element.style.height = imageBounds.height + 'px';
}; };
/** /**
...@@ -878,7 +873,7 @@ ImageView.Effect.None.prototype = { __proto__: ImageView.Effect.prototype }; ...@@ -878,7 +873,7 @@ ImageView.Effect.None.prototype = { __proto__: ImageView.Effect.prototype };
* @override * @override
*/ */
ImageView.Effect.None.prototype.transform = function(element, viewport) { ImageView.Effect.None.prototype.transform = function(element, viewport) {
return viewport.getTransformation(); return viewport.getTransformation(element.width, element.height);
}; };
/** /**
...@@ -912,7 +907,8 @@ ImageView.Effect.Slide.prototype.getReverse = function() { ...@@ -912,7 +907,8 @@ ImageView.Effect.Slide.prototype.getReverse = function() {
* @override * @override
*/ */
ImageView.Effect.Slide.prototype.transform = function(element, viewport) { ImageView.Effect.Slide.prototype.transform = function(element, viewport) {
return viewport.getShiftTransformation(this.shift_); return viewport.getTransformation(
element.width, element.height, this.shift_);
}; };
/** /**
...@@ -944,8 +940,12 @@ ImageView.Effect.Zoom.prototype = { __proto__: ImageView.Effect.prototype }; ...@@ -944,8 +940,12 @@ ImageView.Effect.Zoom.prototype = { __proto__: ImageView.Effect.prototype };
* @override * @override
*/ */
ImageView.Effect.Zoom.prototype.transform = function(element, viewport) { ImageView.Effect.Zoom.prototype.transform = function(element, viewport) {
return viewport.getInverseTransformForCroppedImage( return viewport.getCroppingTransformation(
this.previousImageWidth_, this.previousImageHeight_, this.imageCropRect_); element.width,
element.height,
this.previousImageWidth_,
this.previousImageHeight_,
this.imageCropRect_);
}; };
/** /**
...@@ -973,7 +973,10 @@ ImageView.Effect.ZoomToScreen.prototype = { ...@@ -973,7 +973,10 @@ ImageView.Effect.ZoomToScreen.prototype = {
*/ */
ImageView.Effect.ZoomToScreen.prototype.transform = function( ImageView.Effect.ZoomToScreen.prototype.transform = function(
element, viewport) { element, viewport) {
return viewport.getScreenRectTransformForImage(this.screenRect_); return viewport.getScreenRectTransformation(
element.width,
element.height,
this.screenRect_);
}; };
/** /**
...@@ -996,5 +999,6 @@ ImageView.Effect.Rotate.prototype = { __proto__: ImageView.Effect.prototype }; ...@@ -996,5 +999,6 @@ ImageView.Effect.Rotate.prototype = { __proto__: ImageView.Effect.prototype };
* @override * @override
*/ */
ImageView.Effect.Rotate.prototype.transform = function(element, viewport) { ImageView.Effect.Rotate.prototype.transform = function(element, viewport) {
return viewport.getInverseTransformForRotatedImage(this.orientation_); return viewport.getRotatingTransformation(
element.width, element.height, this.orientation_ ? -1 : 1);
}; };
...@@ -2,6 +2,19 @@ ...@@ -2,6 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
/**
* Formats string by replacing place holder with actual values.
* @param {string} str String includes placeholder '$n'. n starts from 1.
* @param {...*} var_args Values inserted into the place holders.
* @return {string}
*/
function formatString(str, var_args) {
var args = arguments;
return str.replace(/\$[1-9]/g, function(placeHolder) {
return args[placeHolder[1]];
});
}
/** /**
* Viewport class controls the way the image is displayed (scale, offset etc). * Viewport class controls the way the image is displayed (scale, offset etc).
* @constructor * @constructor
...@@ -192,18 +205,24 @@ Viewport.prototype.getRotation = function() { ...@@ -192,18 +205,24 @@ Viewport.prototype.getRotation = function() {
}; };
/** /**
* Obtains the scale for the specified image size. * Returns image scale so that it matches screen size as long as it does not
* exceed maximum size.
* *
* @param {number} width Width of the full resolution image. * @param {number} width Width of image.
* @param {number} height Height of the full resolution image. * @param {number} height Height of image.
* @param {number} maxWidth Max width of image.
* @param {number} maxHeight Max height of image.
* @return {number} The ratio of the full resotion image size and the calculated * @return {number} The ratio of the full resotion image size and the calculated
* displayed image size. * displayed image size.
* @private * @private
*/ */
Viewport.prototype.getFittingScaleForImageSize_ = function(width, height) { Viewport.prototype.getFittingScaleForImageSize_ = function(
var scaleX = this.screenBounds_.width / width; width, height, maxWidth, maxHeight) {
var scaleY = this.screenBounds_.height / height; return Math.min(
return Math.min(scaleX, scaleY, 1); maxWidth / width,
maxHeight / height,
this.screenBounds_.width / width,
this.screenBounds_.height / height);
}; };
/** /**
...@@ -248,10 +267,9 @@ Viewport.prototype.getScreenBounds = function() { return this.screenBounds_; }; ...@@ -248,10 +267,9 @@ Viewport.prototype.getScreenBounds = function() { return this.screenBounds_; };
* @return {!ImageRect} The size of screen cache canvas. * @return {!ImageRect} The size of screen cache canvas.
*/ */
Viewport.prototype.getDeviceBounds = function() { Viewport.prototype.getDeviceBounds = function() {
var size = this.getImageElementBoundsOnScreen();
return ImageRect.createFromWidthAndHeight( return ImageRect.createFromWidthAndHeight(
size.width * window.devicePixelRatio, this.imageElementBoundsOnScreen_.width * window.devicePixelRatio,
size.height * window.devicePixelRatio); this.imageElementBoundsOnScreen_.height * window.devicePixelRatio);
}; };
/** /**
...@@ -271,16 +289,6 @@ Viewport.prototype.getImageBoundsOnScreen = function() { ...@@ -271,16 +289,6 @@ Viewport.prototype.getImageBoundsOnScreen = function() {
return this.imageBoundsOnScreen_; return this.imageBoundsOnScreen_;
}; };
/**
* The image bounds in screen coordinates.
* This returns the bounds of element before applying zoom and offset.
* @return {!ImageRect}
*/
Viewport.prototype.getImageElementBoundsOnScreen = function() {
assert(this.imageElementBoundsOnScreen_);
return this.imageElementBoundsOnScreen_;
};
/** /**
* The image bounds on screen, which is clipped with the screen size. * The image bounds on screen, which is clipped with the screen size.
* @return {!ImageRect} * @return {!ImageRect}
...@@ -406,6 +414,7 @@ Viewport.prototype.resetView = function() { ...@@ -406,6 +414,7 @@ Viewport.prototype.resetView = function() {
Viewport.prototype.update_ = function() { Viewport.prototype.update_ = function() {
// Update scale. // Update scale.
this.scale_ = this.getFittingScaleForImageSize_( this.scale_ = this.getFittingScaleForImageSize_(
this.imageBounds_.width, this.imageBounds_.height,
this.imageBounds_.width, this.imageBounds_.height); this.imageBounds_.width, this.imageBounds_.height);
// Limit offset values. // Limit offset values.
...@@ -416,6 +425,7 @@ Viewport.prototype.update_ = function() { ...@@ -416,6 +425,7 @@ Viewport.prototype.update_ = function() {
zoomedHeight = ~~(this.imageBounds_.height * this.scale_ * this.zoom_); zoomedHeight = ~~(this.imageBounds_.height * this.scale_ * this.zoom_);
} else { } else {
var scale = this.getFittingScaleForImageSize_( var scale = this.getFittingScaleForImageSize_(
this.imageBounds_.height, this.imageBounds_.width,
this.imageBounds_.height, this.imageBounds_.width); this.imageBounds_.height, this.imageBounds_.width);
zoomedWidht = ~~(this.imageBounds_.height * scale * this.zoom_); zoomedWidht = ~~(this.imageBounds_.height * scale * this.zoom_);
zoomedHeight = ~~(this.imageBounds_.width * scale * this.zoom_); zoomedHeight = ~~(this.imageBounds_.width * scale * this.zoom_);
...@@ -472,104 +482,128 @@ Viewport.prototype.clone = function() { ...@@ -472,104 +482,128 @@ Viewport.prototype.clone = function() {
}; };
/** /**
* Obtains CSS transformation for the screen image. * Obtains CSS transformation string that matches the image dimension with
* @return {string} Transformation description. * |screenRect|.
* @param {number} width Width of image.
* @param {number} height Height of image.
* @param {!ImageRect} screenRect Rectangle in window coordinate system. The
* origin of the coordinate system at the left upper of the window.
*/ */
Viewport.prototype.getTransformation = function() { Viewport.prototype.getScreenRectTransformation = function(
var rotationScaleAdjustment; width, height, screenRect) {
if (this.rotation_ % 2) { var dx = screenRect.left + (screenRect.width - width) / 2;
rotationScaleAdjustment = this.getFittingScaleForImageSize_( var dy = screenRect.top + (screenRect.height - height) / 2;
this.imageBounds_.height, this.imageBounds_.width) / this.scale_;
} else { return formatString(
rotationScaleAdjustment = 1; 'translate($1px,$2px) scale($3,$4)',
} dx, dy, screenRect.width / width, screenRect.height / height);
return [
'translate(' + this.offsetX_ + 'px, ' + this.offsetY_ + 'px) ',
'rotate(' + (this.rotation_ * 90) + 'deg)',
'scale(' + (this.zoom_ * rotationScaleAdjustment) + ')'
].join(' ');
}; };
/** /**
* Obtains shift CSS transformation for the screen image. * Obtains CSS transformation string that places the cropped image at the
* @param {number} dx Amount of shift. * original position in the whole image.
* @return {string} Transformation description. * @param {number} width Width of cropped image.
* @param {number} height Width of cropped image.
* @param {number} wholeWidthMax Max width value that is used for layouting
* whole image.
* @param {number} wholeHeightMax Max height value that is used for layouting
* whole image.
* @param {!ImageRect} cropRect Crop rectangle in the whole image. The origin is
* left upper of the whole image.
*/ */
Viewport.prototype.getShiftTransformation = function(dx) { Viewport.prototype.getCroppingTransformation = function(
return 'translateX(' + dx + 'px) ' + this.getTransformation(); width,
height,
wholeWidthMax,
wholeHeightMax,
cropRect) {
var fittingScale = this.getFittingScaleForImageSize_(
wholeWidthMax, wholeHeightMax, wholeWidthMax, wholeHeightMax);
var wholeWidth = wholeWidthMax * fittingScale;
var wholeHeight = wholeHeightMax * fittingScale;
var wholeLeft = (this.screenBounds_.width - wholeWidth) / 2;
var wholeTop = (this.screenBounds_.height - wholeHeight) / 2;
return this.getScreenRectTransformation(
width,
height,
new ImageRect(
wholeLeft + cropRect.left * fittingScale,
wholeTop + cropRect.top * fittingScale,
cropRect.width * fittingScale,
cropRect.height * fittingScale));
}; };
/** /**
* Obtains CSS transformation that makes the rotated image fit the original * Obtains CSS transformation for the screen image.
* image. The new rotated image that the transformation is applied to looks the * @param {number} width Width of image.
* same with original image. * @param {number} height Height of image.
* * @param {number=} opt_dx Amount of horizontal shift.
* @param {boolean} orientation Orientation of the rotation from the original
* image to the rotated image. True is for clockwise and false is for
* counterclockwise.
* @return {string} Transformation description. * @return {string} Transformation description.
*/ */
Viewport.prototype.getInverseTransformForRotatedImage = function(orientation) { Viewport.prototype.getTransformation = function(width, height, opt_dx) {
var previousImageWidth = this.imageBounds_.height; return this.getTransformationInternal_(
var previousImageHeight = this.imageBounds_.width; width,
var oldScale = this.getFittingScaleForImageSize_( height,
previousImageWidth, previousImageHeight); this.rotation_,
var scaleRatio = oldScale / this.scale_; this.zoom_,
var degree = orientation ? '-90deg' : '90deg'; this.offsetX_ + (opt_dx || 0),
return [ this.offsetY_);
'scale(' + scaleRatio + ')',
'rotate(' + degree + ')',
this.getTransformation()
].join(' ');
}; };
/** /**
* Obtains CSS transformation that makes the cropped image fit the original * Obtains CSS transformation that makes the rotated image fit the original
* image. The new cropped image that the transformation is applied to fits to * image. The new rotated image that the transformation is applied to looks the
* the cropped rectangle in the original image. * same with original image.
* *
* @param {number} imageWidth Width of the original image. * @param {number} width Width of image.
* @param {number} imageHeight Height of the original image. * @param {number} height Height of image.
* @param {!ImageRect} imageCropRect Crop rectangle in the image's coordinate * @param {number} rotation Number of clockwise 90 degree rotation. The rotation
* system. * angle of the image is rotation * 90.
* @return {string} Transformation description. * @return {string} Transformation description.
*/ */
Viewport.prototype.getInverseTransformForCroppedImage = Viewport.prototype.getRotatingTransformation = function(
function(imageWidth, imageHeight, imageCropRect) { width, height, rotation) {
var wholeScale = this.getFittingScaleForImageSize_( return this.getTransformationInternal_(
imageWidth, imageHeight); width, height, rotation, 1, 0, 0);
var croppedScale = this.getFittingScaleForImageSize_(
imageCropRect.width, imageCropRect.height);
var dx =
(imageCropRect.left + imageCropRect.width / 2 - imageWidth / 2) *
wholeScale;
var dy =
(imageCropRect.top + imageCropRect.height / 2 - imageHeight / 2) *
wholeScale;
return [
'translate(' + dx + 'px,' + dy + 'px)',
'scale(' + wholeScale / croppedScale + ')',
this.getTransformation()
].join(' ');
}; };
/** /**
* Obtains CSS transformation that makes the image fit to the screen rectangle. * Obtains CSS transformation that placed the image in the application window.
* * @param {number} width Width of image.
* @param {!ImageRect} screenRect Screen rectangle. * @param {number} height Height of image.
* @return {string} Transformation description. * @param {number} rotation Number of clockwise 90 degree rotation. The rotation
* angle of the image is rotation * 90.
* @param {number} zoom Zoom rate.
* @param {number} offsetX Horizontal offset.
* @param {number} offsetY Vertical offset.
* @private
*/ */
Viewport.prototype.getScreenRectTransformForImage = function(screenRect) { Viewport.prototype.getTransformationInternal_ = function(
var imageBounds = this.getImageElementBoundsOnScreen(); width,
var scaleX = screenRect.width / imageBounds.width; height,
var scaleY = screenRect.height / imageBounds.height; rotation,
var screenWidth = this.screenBounds_.width; zoom,
var screenHeight = this.screenBounds_.height; offsetX,
var dx = screenRect.left + screenRect.width / 2 - screenWidth / 2; offsetY) {
var dy = screenRect.top + screenRect.height / 2 - screenHeight / 2; var rotatedWidth = rotation % 2 ? height : width;
return [ var rotatedHeight = rotation % 2 ? width : height;
'translate(' + dx + 'px,' + dy + 'px)', var rotatedMaxWidth = rotation % 2 ?
'scale(' + scaleX + ',' + scaleY + ')', this.imageBounds_.height : this.imageBounds_.width;
this.getTransformation() var rotatedMaxHeight = rotation % 2 ?
].join(' '); this.imageBounds_.width : this.imageBounds_.height;
// Scale.
var fittingScale = this.getFittingScaleForImageSize_(
rotatedWidth, rotatedHeight, rotatedMaxWidth, rotatedMaxHeight);
// Offset for centering.
var dx = (this.screenBounds_.width - width) / 2;
var dy = (this.screenBounds_.height - height) / 2;
return formatString(
'translate($1px,$2px) scale($3) rotate($4deg)',
dx + offsetX,
dy + offsetY,
fittingScale * zoom,
rotation * 90);
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment