Index: chrome/browser/resources/file_manager/js/image_editor/image_transform.js |
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_transform.js b/chrome/browser/resources/file_manager/js/image_editor/image_transform.js |
index 0b39f20dafb1600399ecbc0893ed420d1ed84f79..68531560354bb97480202c8d8c00b294d9effd40 100644 |
--- a/chrome/browser/resources/file_manager/js/image_editor/image_transform.js |
+++ b/chrome/browser/resources/file_manager/js/image_editor/image_transform.js |
@@ -15,7 +15,7 @@ ImageEditor.Mode.Resize.prototype = {__proto__: ImageEditor.Mode.prototype}; |
ImageEditor.Mode.register(ImageEditor.Mode.Resize); |
ImageEditor.Mode.Resize.prototype.createTools = function(toolbar) { |
- var canvas = this.getBuffer().getImageCanvas(); |
+ var canvas = this.getContent().getCanvas(); |
this.widthRange_ = |
toolbar.addRange('width', 0, canvas.width, canvas.width * 2); |
this.heightRange_ = |
@@ -23,19 +23,12 @@ ImageEditor.Mode.Resize.prototype.createTools = function(toolbar) { |
}; |
ImageEditor.Mode.Resize.prototype.commit = function() { |
- var newCanvas = this.getBuffer().createBlankCanvas( |
- this.widthRange_.getValue(), this.heightRange_.getValue()); |
- |
- var srcCanvas = this.getBuffer().getImageCanvas(); |
- |
- var context = newCanvas.getContext("2d"); |
ImageUtil.trace.resetTimer('transform'); |
- Rect.drawImage( |
- context, srcCanvas, new Rect(newCanvas), new Rect(srcCanvas)); |
+ var newCanvas = this.getContent().copyCanvas( |
+ this.widthRange_.getValue(), this.heightRange_.getValue()); |
ImageUtil.trace.reportTimer('transform'); |
- |
- this.getBuffer().setImageCanvas(newCanvas); |
- this.getBuffer().fitImage(); |
+ this.getContent().setCanvas(newCanvas); |
+ this.getViewport().fitImage(); |
}; |
/** |
@@ -50,25 +43,23 @@ ImageEditor.Mode.Rotate.prototype = {__proto__: ImageEditor.Mode.prototype}; |
ImageEditor.Mode.register(ImageEditor.Mode.Rotate); |
-ImageEditor.Mode.Rotate.prototype.commit = function() { |
- this.getBuffer().fitImage(); |
-}; |
+ImageEditor.Mode.Rotate.prototype.commit = function() {}; |
ImageEditor.Mode.Rotate.prototype.rollback = function() { |
if (this.backup_) { |
- this.getBuffer().setImageCanvas(this.backup_); |
+ this.getContent().setCanvas(this.backup_); |
this.backup_ = null; |
- this.transform_ = null; |
} |
+ this.transform_ = null; |
}; |
ImageEditor.Mode.Rotate.prototype.createTools = function(toolbar) { |
- toolbar.addButton("Left", this.doTransform.bind(this, 1, 1, 3)); |
- toolbar.addButton("Right", this.doTransform.bind(this, 1, 1, 1)); |
- toolbar.addButton("Flip V", this.doTransform.bind(this, 1, -1, 0)); |
- toolbar.addButton("Flip H", this.doTransform.bind(this, -1, 1, 0)); |
+ toolbar.addButton("Left", this.modifyTransform.bind(this, 1, 1, 3)); |
+ toolbar.addButton("Right", this.modifyTransform.bind(this, 1, 1, 1)); |
+ toolbar.addButton("Flip V", this.modifyTransform.bind(this, 1, -1, 0)); |
+ toolbar.addButton("Flip H", this.modifyTransform.bind(this, -1, 1, 0)); |
- var srcCanvas = this.getBuffer().getImageCanvas(); |
+ var srcCanvas = this.getContent().getCanvas(); |
var width = srcCanvas.width; |
var height = srcCanvas.height; |
@@ -81,79 +72,165 @@ ImageEditor.Mode.Rotate.prototype.createTools = function(toolbar) { |
this.tiltRange_.addEventListener('mouseup', this.onTiltStop.bind(this)); |
}; |
+ImageEditor.Mode.Rotate.prototype.getOriginal = function() { |
+ if (!this.backup_) { |
+ this.backup_ = this.getContent().getCanvas(); |
+ } |
+ return this.backup_; |
+}; |
+ |
+ImageEditor.Mode.Rotate.prototype.getTransform = function() { |
+ if (!this.transform_) { |
+ this.transform_ = new ImageEditor.Mode.Rotate.Transform(); |
+ } |
+ return this.transform_; |
+}; |
+ |
ImageEditor.Mode.Rotate.prototype.onTiltStart = function() { |
this.tiltDrag_ = true; |
+ |
+ var original = this.getOriginal(); |
+ |
+ // Downscale the original image to the overview thumbnail size. |
+ var downScale = ImageBuffer.Overview.MAX_SIZE / |
+ Math.max(original.width, original.height); |
+ |
+ this.preScaledOriginal_ = this.getContent().createBlankCanvas( |
+ original.width * downScale, original.height * downScale); |
+ Rect.drawImage(this.preScaledOriginal_.getContext('2d'), original); |
+ |
+ // Translate the current offset into the original image coordinate space. |
+ var viewport = this.getViewport(); |
+ var originalOffset = this.getTransform().transformOffsetToBaseline( |
+ viewport.getOffsetX(), viewport.getOffsetY()); |
+ |
+ // Find the part of the original image that is sufficient to pre-render |
+ // the rotation results. |
+ var screenClipped = viewport.getScreenClipped(); |
+ var diagonal = viewport.screenToImageSize( |
+ Math.sqrt(screenClipped.width * screenClipped.width + |
+ screenClipped.height * screenClipped.height)); |
+ |
+ var originalBounds = new Rect(original); |
+ |
+ var originalPreclipped = new Rect( |
+ originalBounds.width / 2 - originalOffset.x - diagonal / 2, |
+ originalBounds.height / 2 - originalOffset.y - diagonal / 2, |
+ diagonal, |
+ diagonal).clamp(originalBounds); |
+ |
+ // We assume that the scale is not changing during the mouse drag. |
+ var scale = viewport.getScale(); |
+ this.preClippedOriginal_ = this.getContent().createBlankCanvas( |
+ originalPreclipped.width * scale, originalPreclipped.height * scale); |
+ |
+ Rect.drawImage(this.preClippedOriginal_.getContext('2d'), original, null, |
+ originalPreclipped); |
+ |
this.repaint(); |
}; |
ImageEditor.Mode.Rotate.prototype.onTiltStop = function() { |
this.tiltDrag_ = false; |
- this.repaint(); |
+ if (this.preScaledOriginal_) { |
+ this.preScaledOriginal_ = false; |
+ this.preClippedOriginal_ = false; |
+ this.applyTransform(); |
+ } else { |
+ this.repaint(); |
+ } |
}; |
ImageEditor.Mode.Rotate.prototype.draw = function(context) { |
if (!this.tiltDrag_) return; |
- var rect = this.getBuffer().getClippedScreen(); |
+ var screenClipped = this.getViewport().getScreenClipped(); |
+ |
+ if (this.preClippedOriginal_) { |
+ ImageUtil.trace.resetTimer('preview'); |
+ var transformed = this.getContent().createBlankCanvas( |
+ screenClipped.width, screenClipped.height); |
+ this.getTransform().apply( |
+ transformed.getContext('2d'), this.preClippedOriginal_); |
+ Rect.drawImage(context, transformed, screenClipped); |
+ ImageUtil.trace.reportTimer('preview'); |
+ } |
+ |
const STEP = 50; |
context.save(); |
context.globalAlpha = 0.4; |
context.strokeStyle = "#C0C0C0"; |
- for(var x = 0; x <= rect.width - STEP; x += STEP) { |
- context.strokeRect(rect.left + x, rect.top, STEP, rect.height); |
+ |
+ for(var x = Math.floor(screenClipped.left / STEP) * STEP; |
+ x < screenClipped.left + screenClipped.width; |
+ x += STEP) { |
+ var left = Math.max(screenClipped.left, x); |
+ var right = Math.min(screenClipped.left + screenClipped.width, x + STEP); |
+ context.strokeRect( |
+ left, screenClipped.top, right - left, screenClipped.height); |
} |
- for(var y = 0; y <= rect.height - STEP; y += STEP) { |
- context.strokeRect(rect.left, rect.top + y, rect.width, STEP); |
+ |
+ for(var y = Math.floor(screenClipped.top / STEP) * STEP; |
+ y < screenClipped.top + screenClipped.height; |
+ y += STEP) { |
+ var top = Math.max(screenClipped.top, y); |
+ var bottom = Math.min(screenClipped.top + screenClipped.height, y + STEP); |
+ context.strokeRect( |
+ screenClipped.left, top, screenClipped.width, bottom - top); |
} |
+ |
context.restore(); |
}; |
-ImageEditor.Mode.Rotate.prototype.doTransform = |
+ImageEditor.Mode.Rotate.prototype.modifyTransform = |
function(scaleX, scaleY, turn90) { |
- if (!this.backup_) { |
- this.backup_ = this.getBuffer().getImageCanvas(); |
- this.transform_ = new ImageEditor.Mode.Rotate.Transform(); |
- } |
- var baselineOffset = this.transform_.transformOffsetToBaseline( |
- this.getBuffer().getOffsetX(), this.getBuffer().getOffsetY()); |
+ var transform = this.getTransform(); |
+ var viewport = this.getViewport(); |
+ |
+ var baselineOffset = transform.transformOffsetToBaseline( |
+ viewport.getOffsetX(), viewport.getOffsetY()); |
- this.transform_.modify(scaleX, scaleY, turn90, this.tiltRange_.getValue()); |
+ transform.modify(scaleX, scaleY, turn90, this.tiltRange_.getValue()); |
+ |
+ var newOffset = transform.transformOffsetFromBaseline( |
+ baselineOffset.x, baselineOffset.y); |
+ |
+ // Ignoring offset clipping makes rotation behave more naturally. |
+ viewport.setOffset(newOffset.x, newOffset.y, true /*ignore clipping*/); |
if (scaleX * scaleY < 0) { |
- this.tiltRange_.setValue(this.transform_.tilt); |
+ this.tiltRange_.setValue(transform.tilt); |
} |
- var srcCanvas = this.backup_; |
+ this.applyTransform(); |
+}; |
+ |
+ImageEditor.Mode.Rotate.prototype.applyTransform = function() { |
+ var srcCanvas = this.getOriginal(); |
var newSize = this.transform_.getTiltedRectSize( |
srcCanvas.width, srcCanvas.height); |
- var dstCanvas = |
- this.getBuffer().createBlankCanvas(newSize.width, newSize.height); |
+ var scale = 1; |
- var context = dstCanvas.getContext("2d"); |
- context.save(); |
- context.translate(dstCanvas.width / 2, dstCanvas.height / 2); |
- context.rotate(this.transform_.getAngle()); |
- context.scale(this.transform_.scaleX, this.transform_.scaleY); |
+ if (this.preScaledOriginal_) { |
+ scale = this.preScaledOriginal_.width / srcCanvas.width; |
+ srcCanvas = this.preScaledOriginal_; |
+ } |
+ |
+ var dstCanvas = this.getContent().createBlankCanvas( |
+ newSize.width * scale, newSize.height * scale); |
ImageUtil.trace.resetTimer('transform'); |
- context.drawImage(srcCanvas, -srcCanvas.width / 2, -srcCanvas.height / 2); |
+ this.transform_.apply(dstCanvas.getContext('2d'), srcCanvas); |
ImageUtil.trace.reportTimer('transform'); |
- context.restore(); |
+ this.getContent().setCanvas(dstCanvas, newSize.width, newSize.height); |
- var newOffset = this.transform_.transformOffsetFromBaseline( |
- baselineOffset.x, baselineOffset.y); |
- |
- // Ignoring offset clipping make rotation behave more natural. |
- this.getBuffer().setOffset( |
- newOffset.x, newOffset.y, true /*ignore clipping*/); |
- this.getBuffer().setImageCanvas(dstCanvas); |
- this.getBuffer().repaint(); |
+ this.repaint(); |
}; |
ImageEditor.Mode.Rotate.prototype.update = function(values) { |
- this.doTransform(1, 1, 0); |
+ this.modifyTransform(1, 1, 0); |
}; |
ImageEditor.Mode.Rotate.Transform = function() { |
@@ -161,7 +238,7 @@ ImageEditor.Mode.Rotate.Transform = function() { |
this.scaleY = 1; |
this.turn90 = 0; |
this.tilt = 0; |
-} |
+}; |
ImageEditor.Mode.Rotate.Transform.prototype.modify = |
function(scaleX, scaleY, turn90, tilt) { |
@@ -224,6 +301,15 @@ ImageEditor.Mode.Rotate.Transform.prototype.getTiltedRectSize = |
} |
}; |
+ImageEditor.Mode.Rotate.Transform.prototype.apply = function( |
+ context, srcCanvas) { |
+ context.save(); |
+ context.translate(context.canvas.width / 2, context.canvas.height / 2); |
+ context.rotate(this.getAngle()); |
+ context.scale(this.scaleX, this.scaleY); |
+ context.drawImage(srcCanvas, -srcCanvas.width / 2, -srcCanvas.height / 2); |
+ context.restore(); |
+}; |
/** |
* Crop mode. |
@@ -246,17 +332,17 @@ ImageEditor.Mode.Crop.GRAB_RADIUS = 5; |
ImageEditor.Mode.Crop.prototype.commit = function() { |
var cropImageRect = this.cropRect_.getRect(); |
- var newCanvas = this.getBuffer(). |
+ var newCanvas = this.getContent(). |
createBlankCanvas(cropImageRect.width, cropImageRect.height); |
var newContext = newCanvas.getContext("2d"); |
ImageUtil.trace.resetTimer('transform'); |
- Rect.drawImage(newContext, this.getBuffer().getImageCanvas(), |
+ Rect.drawImage(newContext, this.getContent().getCanvas(), |
new Rect(newCanvas), cropImageRect); |
ImageUtil.trace.reportTimer('transform'); |
- this.getBuffer().setImageCanvas(newCanvas); |
- this.getBuffer().fitImage(); |
+ this.getContent().setCanvas(newCanvas); |
+ this.getViewport().fitImage(); |
}; |
ImageEditor.Mode.Crop.prototype.rollback = function() { |
@@ -264,17 +350,17 @@ ImageEditor.Mode.Crop.prototype.rollback = function() { |
}; |
ImageEditor.Mode.Crop.prototype.createDefaultCrop = function() { |
- var rect = new Rect(this.getBuffer().getClippedImage()); |
+ var rect = new Rect(this.getViewport().getImageClipped()); |
rect = rect.inflate (-rect.width / 6, -rect.height / 6); |
this.cropRect_ = new DraggableRect( |
- rect, this.getBuffer(), ImageEditor.Mode.Crop.GRAB_RADIUS); |
+ rect, this.getViewport(), ImageEditor.Mode.Crop.GRAB_RADIUS); |
}; |
ImageEditor.Mode.Crop.prototype.draw = function(context) { |
var R = ImageEditor.Mode.Crop.GRAB_RADIUS; |
- var inner = this.getBuffer().imageToScreenRect(this.cropRect_.getRect()); |
- var outer = this.getBuffer().getClippedScreen(); |
+ var inner = this.getViewport().imageToScreenRect(this.cropRect_.getRect()); |
+ var outer = this.getViewport().getScreenClipped(); |
var inner_bottom = inner.top + inner.height; |
var inner_right = inner.left + inner.width; |
@@ -324,7 +410,7 @@ ImageEditor.Mode.Crop.prototype.getDragHandler = function(x, y) { |
* A draggable rectangle over the image. |
*/ |
-function DraggableRect(rect, buffer, sensitivity) { |
+function DraggableRect(rect, viewport, sensitivity) { |
// The bounds are not held in a regular rectangle (with width/height). |
// left/top/right/bottom held instead for convenience. |
@@ -334,7 +420,7 @@ function DraggableRect(rect, buffer, sensitivity) { |
this.bounds_[DraggableRect.TOP] = rect.top; |
this.bounds_[DraggableRect.BOTTOM] = rect.top + rect.height; |
- this.buffer_ = buffer; |
+ this.viewport_ = viewport; |
this.sensitivity_ = sensitivity; |
this.oppositeSide_ = {}; |
@@ -350,10 +436,10 @@ function DraggableRect(rect, buffer, sensitivity) { |
this.cssSide_[DraggableRect.RIGHT] = 'e'; |
this.cssSide_[DraggableRect.BOTTOM] = 's'; |
this.cssSide_[DraggableRect.NONE] = ''; |
-}; |
+} |
// Static members to simplify reflective access to the bounds. |
-DraggableRect.LEFT = 'left' |
+DraggableRect.LEFT = 'left'; |
DraggableRect.RIGHT = 'right'; |
DraggableRect.TOP = 'top'; |
DraggableRect.BOTTOM = 'bottom'; |
@@ -368,7 +454,7 @@ DraggableRect.prototype.getDragMode = function(x, y) { |
}; |
var bounds = this.bounds_; |
- var R = this.buffer_.screenToImageSize(this.sensitivity_); |
+ var R = this.viewport_.screenToImageSize(this.sensitivity_); |
var circle = new Circle(x, y, R); |
@@ -410,7 +496,7 @@ DraggableRect.prototype.getCursorStyle = function(x, y, mouseDown) { |
mode = this.dragMode_; |
} else { |
mode = this.getDragMode( |
- this.buffer_.screenToImageX(x), this.buffer_.screenToImageY(y)); |
+ this.viewport_.screenToImageX(x), this.viewport_.screenToImageY(y)); |
} |
if (mode.whole) return 'hand'; |
if (mode.outside) return 'crosshair'; |
@@ -418,10 +504,10 @@ DraggableRect.prototype.getCursorStyle = function(x, y, mouseDown) { |
}; |
DraggableRect.prototype.getDragHandler = function(x, y) { |
- x = this.buffer_.screenToImageX(x); |
- y = this.buffer_.screenToImageY(y); |
+ x = this.viewport_.screenToImageX(x); |
+ y = this.viewport_.screenToImageY(y); |
- var clipRect = this.buffer_.getClippedImage(); |
+ var clipRect = this.viewport_.getImageClipped(); |
if (!clipRect.inside(x, y)) return null; |
this.dragMode_ = this.getDragMode(x, y); |
@@ -487,16 +573,16 @@ DraggableRect.prototype.getDragHandler = function(x, y) { |
} |
function convertX(x) { |
- return ImageUtil.clip( |
+ return ImageUtil.clamp( |
clipRect.left, |
- self.buffer_.screenToImageX(x) + mouseBiasX, |
+ self.viewport_.screenToImageX(x) + mouseBiasX, |
clipRect.left + clipRect.width - fixedWidth); |
} |
function convertY(y) { |
- return ImageUtil.clip( |
+ return ImageUtil.clamp( |
clipRect.top, |
- self.buffer_.screenToImageY(y) + mouseBiasY, |
+ self.viewport_.screenToImageY(y) + mouseBiasY, |
clipRect.top + clipRect.height - fixedHeight); |
} |