Chromium Code Reviews| Index: chrome/browser/resources/pdf/viewport.js |
| diff --git a/chrome/browser/resources/pdf/viewport.js b/chrome/browser/resources/pdf/viewport.js |
| index 18fb6c2ad403f4c8a49956f43a37bc776eaece6e..7c3ccca03bdb45b4422bcf5786234abee4fcb34c 100644 |
| --- a/chrome/browser/resources/pdf/viewport.js |
| +++ b/chrome/browser/resources/pdf/viewport.js |
| @@ -15,6 +15,36 @@ function getIntersectionHeight(rect1, rect2) { |
| } |
| /** |
| + * Makes sure that the scale level doesn't get out of the limits. |
| + * @param {number} scale The new scale level. |
| + * @return {number} The scale clamped within the limits. |
| + */ |
| +function clampScale(scale) { |
| + return Math.min(5, Math.max(0.25, scale)); |
| +} |
| + |
| +/** |
| + * Computes vector between two points. |
| + * @param {!Object} p1 The first point. |
| + * @param {!Object} p2 The second point. |
| + * @return {!Object} The vector. |
| + */ |
| +function vectorDelta(p1, p2) { |
| + return { |
| + x: p2.x - p1.x, |
| + y: p2.y - p1.y |
| + }; |
| +} |
| + |
| +function frameToPluginCoordinate(coordinateInFrame) { |
| + var container = $('plugin'); |
| + return { |
| + x: coordinateInFrame.x - container.getBoundingClientRect().left, |
| + y: coordinateInFrame.y - container.getBoundingClientRect().top |
| + }; |
| +} |
| + |
| +/** |
| * Create a new viewport. |
| * @constructor |
| * @param {Window} window the window |
| @@ -49,6 +79,11 @@ function Viewport(window, |
| this.fittingType_ = Viewport.FittingType.NONE; |
| this.defaultZoom_ = defaultZoom; |
| this.topToolbarHeight_ = topToolbarHeight; |
| + this.prevScale_ = 1; |
| + this.pinchPhase_ = Viewport.PinchPhase.PINCH_NONE; |
| + this.pinchPanVector_ = null; |
| + this.pinchCenter_ = null; |
| + this.firstPinchCenterInFrame_ = null; |
| window.addEventListener('scroll', this.updateViewport_.bind(this)); |
| window.addEventListener('resize', this.resize_.bind(this)); |
| @@ -65,6 +100,19 @@ Viewport.FittingType = { |
| }; |
| /** |
| + * Enumeration of pinch states. |
| + * This should match PinchPhase enum in pdf/out_of_process_instance.h |
| + * @enum {number} |
| + */ |
| +Viewport.PinchPhase = { |
| + PINCH_NONE: 0, |
| + PINCH_START: 1, |
| + PINCH_UPDATE_ZOOM_OUT: 2, |
| + PINCH_UPDATE_ZOOM_IN: 3, |
| + PINCH_END: 4 |
| +}; |
| + |
| +/** |
| * The increment to scroll a page by in pixels when up/down/left/right arrow |
| * keys are pressed. Usually we just let the browser handle scrolling on the |
| * window when these keys are pressed but in certain cases we need to simulate |
| @@ -227,6 +275,29 @@ Viewport.prototype = { |
| }, |
| /** |
| + * @type {Viewport.PinchPhase} The phase of the current pinch gesture for |
| + * the viewport. |
| + */ |
| + get pinchPhase() { |
| + return this.pinchPhase_; |
| + }, |
| + |
| + /** |
| + * @type {Object} The panning caused by the current pinch gesture (as |
| + * the deltas of the x and y coordinates). |
| + */ |
| + get pinchPanVector() { |
| + return this.pinchPanVector_; |
| + }, |
| + |
| + /** |
| + * @type {Object} The coordinates of the center of the current pinch gesture. |
| + */ |
| + get pinchCenter() { |
| + return this.pinchCenter_; |
| + }, |
| + |
| + /** |
| * @private |
| * Used to wrap a function that might perform zooming on the viewport. This is |
| * required so that we can notify the plugin that zooming is in progress |
| @@ -266,6 +337,52 @@ Viewport.prototype = { |
| }, |
| /** |
| + * @private |
| + * Sets the zoom of the viewport. |
| + * Same as setZoomInternal_ but for pinch zoom we have some more operations. |
| + * @param {number} scaleDelta The zoom delta. |
| + * @param {!Object} center The pinch center in content coordinates. |
| + */ |
| + setPinchZoomInternal_: function(scaleDelta, center) { |
| + assert(this.allowedToChangeZoom_, |
| + 'Called Viewport.setPinchZoomInternal_ without calling ' + |
| + 'Viewport.mightZoom_.'); |
| + this.zoom_ = clampScale(this.zoom_ * scaleDelta); |
| + |
| + var newCenterInContent = this.frameToContent(center); |
| + var delta = { |
| + x: (newCenterInContent.x - this.oldCenterInContent.x), |
| + y: (newCenterInContent.y - this.oldCenterInContent.y) |
| + }; |
| + |
| + // Record the scroll position (relative to the pinch center). |
| + var currentScrollPos = { |
| + x: this.position.x - delta.x * this.zoom_, |
| + y: this.position.y - delta.y * this.zoom_ |
| + }; |
| + |
| + this.contentSizeChanged_(); |
| + // Scroll to the scaled scroll position. |
| + this.position = { |
| + x: currentScrollPos.x, |
| + y: currentScrollPos.y |
| + }; |
| + }, |
| + |
| + /** |
| + * @private |
| + * Converts a point from frame to content coordinates. |
| + * @param {!Object} framePoint The frame coordinates. |
| + * @return {!Object} The content coordinates. |
| + */ |
| + frameToContent: function(framePoint) { |
| + return { |
|
dpapad
2016/11/09 01:12:27
For a future CL cleanup, I think this entire class
Kevin McNee - google account
2016/11/09 16:36:09
I've added a TODO about this.
Acknowledged.
|
| + x: (framePoint.x + this.position.x) / this.zoom_, |
| + y: (framePoint.y + this.position.y) / this.zoom_ |
| + }; |
| + }, |
| + |
| + /** |
| * Sets the zoom to the given zoom level. |
| * @param {number} newZoom the zoom level to zoom to. |
| */ |
| @@ -499,6 +616,79 @@ Viewport.prototype = { |
| }, |
| /** |
| + * Pinch zoom event handler. |
| + * @param {!Object} e The pinch event. |
| + */ |
| + pinchZoom: function(e) { |
| + this.mightZoom_(function() { |
| + this.pinchPhase_ = e.direction == 'out' ? |
| + Viewport.PinchPhase.PINCH_UPDATE_ZOOM_OUT : |
| + Viewport.PinchPhase.PINCH_UPDATE_ZOOM_IN; |
| + |
| + var scaleDelta = e.startScaleRatio / this.prevScale_; |
| + this.pinchPanVector_ = |
| + vectorDelta(e.center, this.firstPinchCenterInFrame_); |
| + |
| + var needsScrollbars = this.documentNeedsScrollbars_( |
| + clampScale(this.zoom_ * scaleDelta)); |
| + |
| + this.pinchCenter_ = e.center; |
| + |
| + // If there's no horizontal scrolling, keep the content centered so the |
| + // user can't zoom in on the non-content area. |
| + // TODO(mcnee) Investigate other ways of scaling when we don't have |
| + // horizontal scrolling. We want to keep the document centered, |
| + // but this causes a potentially awkward transition when we start |
| + // using the gesture center. |
| + if (!needsScrollbars.horizontal) { |
| + this.pinchCenter_ = { |
| + x: this.window_.innerWidth / 2, |
| + y: this.window_.innerHeight / 2 |
| + }; |
| + } else if (this.keepContentCentered_) { |
| + this.oldCenterInContent = |
| + this.frameToContent(frameToPluginCoordinate(e.center)); |
| + this.keepContentCentered_ = false; |
| + } |
| + |
| + this.setPinchZoomInternal_( |
| + scaleDelta, frameToPluginCoordinate(e.center)); |
| + this.updateViewport_(); |
| + this.prevScale_ = e.startScaleRatio; |
| + }.bind(this)); |
| + }, |
| + |
| + pinchZoomStart: function(e) { |
| + this.pinchPhase_ = Viewport.PinchPhase.PINCH_START; |
| + this.prevScale_ = 1; |
| + this.oldCenterInContent = |
| + this.frameToContent(frameToPluginCoordinate(e.center)); |
| + |
| + var needsScrollbars = this.documentNeedsScrollbars_(this.zoom_); |
| + this.keepContentCentered_ = !needsScrollbars.horizontal; |
| + // We keep track of begining of the pinch. |
| + // By doing so we will be able to compute the pan distance. |
| + this.firstPinchCenterInFrame_ = e.center; |
| + }, |
| + |
| + pinchZoomEnd: function(e) { |
| + this.mightZoom_(function() { |
| + this.pinchPhase_ = Viewport.PinchPhase.PINCH_END; |
| + var scaleDelta = e.startScaleRatio / this.prevScale_; |
| + this.pinchCenter_ = e.center; |
| + |
| + this.setPinchZoomInternal_( |
| + scaleDelta, frameToPluginCoordinate(e.center)); |
| + this.updateViewport_(); |
| + }.bind(this)); |
| + |
| + this.pinchPhase_ = Viewport.PinchPhase.PINCH_NONE; |
| + this.pinchPanVector_ = null; |
| + this.pinchCenter_ = null; |
| + this.firstPinchCenterInFrame_ = null; |
| + }, |
| + |
| + /** |
| * Go to the given page index. |
| * @param {number} page the index of the page to go to. zero-based. |
| */ |