Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 * Returns the height of the intersection of two rectangles. | 6 * Returns the height of the intersection of two rectangles. |
| 7 * @param {Object} rect1 the first rect | 7 * @param {Object} rect1 the first rect |
| 8 * @param {Object} rect2 the second rect | 8 * @param {Object} rect2 the second rect |
| 9 * @return {number} the height of the intersection of the rects | 9 * @return {number} the height of the intersection of the rects |
| 10 */ | 10 */ |
| 11 function getIntersectionHeight(rect1, rect2) { | 11 function getIntersectionHeight(rect1, rect2) { |
| 12 return Math.max(0, | 12 return Math.max(0, |
| 13 Math.min(rect1.y + rect1.height, rect2.y + rect2.height) - | 13 Math.min(rect1.y + rect1.height, rect2.y + rect2.height) - |
| 14 Math.max(rect1.y, rect2.y)); | 14 Math.max(rect1.y, rect2.y)); |
| 15 } | 15 } |
| 16 | 16 |
| 17 /** | 17 /** |
| 18 * Makes sure that the scale level doesn't get out of the limits. | |
| 19 * @param {number} scale The new scale level. | |
| 20 * @return {number} The scale clamped within the limits. | |
| 21 */ | |
| 22 function clampScale(scale) { | |
| 23 return Math.min(5, Math.max(0.25, scale)); | |
| 24 } | |
| 25 | |
| 26 /** | |
| 27 * Computes vector between two points. | |
| 28 * @param {!Object} p1 The first point. | |
| 29 * @param {!Object} p2 The second point. | |
| 30 * @return {!Object} The vector. | |
| 31 */ | |
| 32 function vectorDelta(p1, p2) { | |
| 33 return { | |
| 34 x: p2.x - p1.x, | |
| 35 y: p2.y - p1.y | |
| 36 }; | |
| 37 } | |
| 38 | |
| 39 function frameToPluginCoordinate(coordinateInFrame) { | |
| 40 var container = $('plugin'); | |
| 41 return { | |
| 42 x: coordinateInFrame.x - container.getBoundingClientRect().left, | |
| 43 y: coordinateInFrame.y - container.getBoundingClientRect().top | |
| 44 }; | |
| 45 } | |
| 46 | |
| 47 /** | |
| 18 * Create a new viewport. | 48 * Create a new viewport. |
| 19 * @constructor | 49 * @constructor |
| 20 * @param {Window} window the window | 50 * @param {Window} window the window |
| 21 * @param {Object} sizer is the element which represents the size of the | 51 * @param {Object} sizer is the element which represents the size of the |
| 22 * document in the viewport | 52 * document in the viewport |
| 23 * @param {Function} viewportChangedCallback is run when the viewport changes | 53 * @param {Function} viewportChangedCallback is run when the viewport changes |
| 24 * @param {Function} beforeZoomCallback is run before a change in zoom | 54 * @param {Function} beforeZoomCallback is run before a change in zoom |
| 25 * @param {Function} afterZoomCallback is run after a change in zoom | 55 * @param {Function} afterZoomCallback is run after a change in zoom |
| 26 * @param {number} scrollbarWidth the width of scrollbars on the page | 56 * @param {number} scrollbarWidth the width of scrollbars on the page |
| 27 * @param {number} defaultZoom The default zoom level. | 57 * @param {number} defaultZoom The default zoom level. |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 42 this.beforeZoomCallback_ = beforeZoomCallback; | 72 this.beforeZoomCallback_ = beforeZoomCallback; |
| 43 this.afterZoomCallback_ = afterZoomCallback; | 73 this.afterZoomCallback_ = afterZoomCallback; |
| 44 this.allowedToChangeZoom_ = false; | 74 this.allowedToChangeZoom_ = false; |
| 45 this.zoom_ = 1; | 75 this.zoom_ = 1; |
| 46 this.documentDimensions_ = null; | 76 this.documentDimensions_ = null; |
| 47 this.pageDimensions_ = []; | 77 this.pageDimensions_ = []; |
| 48 this.scrollbarWidth_ = scrollbarWidth; | 78 this.scrollbarWidth_ = scrollbarWidth; |
| 49 this.fittingType_ = Viewport.FittingType.NONE; | 79 this.fittingType_ = Viewport.FittingType.NONE; |
| 50 this.defaultZoom_ = defaultZoom; | 80 this.defaultZoom_ = defaultZoom; |
| 51 this.topToolbarHeight_ = topToolbarHeight; | 81 this.topToolbarHeight_ = topToolbarHeight; |
| 82 this.prevScale_ = 1; | |
| 83 this.pinchPhase_ = Viewport.PinchPhase.PINCH_NONE; | |
| 84 this.pinchPanVector_ = null; | |
| 85 this.pinchCenter_ = null; | |
| 86 this.firstPinchCenterInFrame_ = null; | |
| 52 | 87 |
| 53 window.addEventListener('scroll', this.updateViewport_.bind(this)); | 88 window.addEventListener('scroll', this.updateViewport_.bind(this)); |
| 54 window.addEventListener('resize', this.resize_.bind(this)); | 89 window.addEventListener('resize', this.resize_.bind(this)); |
| 55 } | 90 } |
| 56 | 91 |
| 57 /** | 92 /** |
| 58 * Enumeration of page fitting types. | 93 * Enumeration of page fitting types. |
| 59 * @enum {string} | 94 * @enum {string} |
| 60 */ | 95 */ |
| 61 Viewport.FittingType = { | 96 Viewport.FittingType = { |
| 62 NONE: 'none', | 97 NONE: 'none', |
| 63 FIT_TO_PAGE: 'fit-to-page', | 98 FIT_TO_PAGE: 'fit-to-page', |
| 64 FIT_TO_WIDTH: 'fit-to-width' | 99 FIT_TO_WIDTH: 'fit-to-width' |
| 65 }; | 100 }; |
| 66 | 101 |
| 67 /** | 102 /** |
| 103 * Enumeration of pinch states. | |
| 104 * This should match PinchPhase enum in pdf/out_of_process_instance.h | |
| 105 * @enum {number} | |
| 106 */ | |
| 107 Viewport.PinchPhase = { | |
| 108 PINCH_NONE: 0, | |
| 109 PINCH_START: 1, | |
| 110 PINCH_UPDATE_ZOOM_OUT: 2, | |
| 111 PINCH_UPDATE_ZOOM_IN: 3, | |
| 112 PINCH_END: 4 | |
| 113 }; | |
| 114 | |
| 115 /** | |
| 68 * The increment to scroll a page by in pixels when up/down/left/right arrow | 116 * The increment to scroll a page by in pixels when up/down/left/right arrow |
| 69 * keys are pressed. Usually we just let the browser handle scrolling on the | 117 * keys are pressed. Usually we just let the browser handle scrolling on the |
| 70 * window when these keys are pressed but in certain cases we need to simulate | 118 * window when these keys are pressed but in certain cases we need to simulate |
| 71 * these events. | 119 * these events. |
| 72 */ | 120 */ |
| 73 Viewport.SCROLL_INCREMENT = 40; | 121 Viewport.SCROLL_INCREMENT = 40; |
| 74 | 122 |
| 75 /** | 123 /** |
| 76 * Predefined zoom factors to be used when zooming in/out. These are in | 124 * Predefined zoom factors to be used when zooming in/out. These are in |
| 77 * ascending order. This should match the lists in | 125 * ascending order. This should match the lists in |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 220 }, | 268 }, |
| 221 | 269 |
| 222 /** | 270 /** |
| 223 * @type {number} the zoom level of the viewport. | 271 * @type {number} the zoom level of the viewport. |
| 224 */ | 272 */ |
| 225 get zoom() { | 273 get zoom() { |
| 226 return this.zoom_; | 274 return this.zoom_; |
| 227 }, | 275 }, |
| 228 | 276 |
| 229 /** | 277 /** |
| 278 * @type {Viewport.PinchPhase} The phase of the current pinch gesture for | |
| 279 * the viewport. | |
| 280 */ | |
| 281 get pinchPhase() { | |
| 282 return this.pinchPhase_; | |
| 283 }, | |
| 284 | |
| 285 /** | |
| 286 * @type {Object} The panning caused by the current pinch gesture (as | |
| 287 * the deltas of the x and y coordinates). | |
| 288 */ | |
| 289 get pinchPanVector() { | |
| 290 return this.pinchPanVector_; | |
| 291 }, | |
| 292 | |
| 293 /** | |
| 294 * @type {Object} The coordinates of the center of the current pinch gesture. | |
| 295 */ | |
| 296 get pinchCenter() { | |
| 297 return this.pinchCenter_; | |
| 298 }, | |
| 299 | |
| 300 /** | |
| 230 * @private | 301 * @private |
| 231 * Used to wrap a function that might perform zooming on the viewport. This is | 302 * Used to wrap a function that might perform zooming on the viewport. This is |
| 232 * required so that we can notify the plugin that zooming is in progress | 303 * required so that we can notify the plugin that zooming is in progress |
| 233 * so that while zooming is taking place it can stop reacting to scroll events | 304 * so that while zooming is taking place it can stop reacting to scroll events |
| 234 * from the viewport. This is to avoid flickering. | 305 * from the viewport. This is to avoid flickering. |
| 235 */ | 306 */ |
| 236 mightZoom_: function(f) { | 307 mightZoom_: function(f) { |
| 237 this.beforeZoomCallback_(); | 308 this.beforeZoomCallback_(); |
| 238 this.allowedToChangeZoom_ = true; | 309 this.allowedToChangeZoom_ = true; |
| 239 f(); | 310 f(); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 259 this.zoom_ = newZoom; | 330 this.zoom_ = newZoom; |
| 260 this.contentSizeChanged_(); | 331 this.contentSizeChanged_(); |
| 261 // Scroll to the scaled scroll position. | 332 // Scroll to the scaled scroll position. |
| 262 this.position = { | 333 this.position = { |
| 263 x: currentScrollPos.x * newZoom, | 334 x: currentScrollPos.x * newZoom, |
| 264 y: currentScrollPos.y * newZoom | 335 y: currentScrollPos.y * newZoom |
| 265 }; | 336 }; |
| 266 }, | 337 }, |
| 267 | 338 |
| 268 /** | 339 /** |
| 340 * @private | |
| 341 * Sets the zoom of the viewport. | |
| 342 * Same as setZoomInternal_ but for pinch zoom we have some more operations. | |
| 343 * @param {number} scaleDelta The zoom delta. | |
| 344 * @param {!Object} center The pinch center in content coordinates. | |
| 345 */ | |
| 346 setPinchZoomInternal_: function(scaleDelta, center) { | |
| 347 assert(this.allowedToChangeZoom_, | |
| 348 'Called Viewport.setPinchZoomInternal_ without calling ' + | |
| 349 'Viewport.mightZoom_.'); | |
| 350 this.zoom_ = clampScale(this.zoom_ * scaleDelta); | |
| 351 | |
| 352 var newCenterInContent = this.frameToContent(center); | |
| 353 var delta = { | |
| 354 x: (newCenterInContent.x - this.oldCenterInContent.x), | |
| 355 y: (newCenterInContent.y - this.oldCenterInContent.y) | |
| 356 }; | |
| 357 | |
| 358 // Record the scroll position (relative to the pinch center). | |
| 359 var currentScrollPos = { | |
| 360 x: this.position.x - delta.x * this.zoom_, | |
| 361 y: this.position.y - delta.y * this.zoom_ | |
| 362 }; | |
| 363 | |
| 364 this.contentSizeChanged_(); | |
| 365 // Scroll to the scaled scroll position. | |
| 366 this.position = { | |
| 367 x: currentScrollPos.x, | |
| 368 y: currentScrollPos.y | |
| 369 }; | |
| 370 }, | |
| 371 | |
| 372 /** | |
| 373 * @private | |
| 374 * Converts a point from frame to content coordinates. | |
| 375 * @param {!Object} framePoint The frame coordinates. | |
| 376 * @return {!Object} The content coordinates. | |
| 377 */ | |
| 378 frameToContent: function(framePoint) { | |
| 379 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.
| |
| 380 x: (framePoint.x + this.position.x) / this.zoom_, | |
| 381 y: (framePoint.y + this.position.y) / this.zoom_ | |
| 382 }; | |
| 383 }, | |
| 384 | |
| 385 /** | |
| 269 * Sets the zoom to the given zoom level. | 386 * Sets the zoom to the given zoom level. |
| 270 * @param {number} newZoom the zoom level to zoom to. | 387 * @param {number} newZoom the zoom level to zoom to. |
| 271 */ | 388 */ |
| 272 setZoom: function(newZoom) { | 389 setZoom: function(newZoom) { |
| 273 this.fittingType_ = Viewport.FittingType.NONE; | 390 this.fittingType_ = Viewport.FittingType.NONE; |
| 274 newZoom = Math.max(Viewport.ZOOM_FACTOR_RANGE.min, | 391 newZoom = Math.max(Viewport.ZOOM_FACTOR_RANGE.min, |
| 275 Math.min(newZoom, Viewport.ZOOM_FACTOR_RANGE.max)); | 392 Math.min(newZoom, Viewport.ZOOM_FACTOR_RANGE.max)); |
| 276 this.mightZoom_(function() { | 393 this.mightZoom_(function() { |
| 277 this.setZoomInternal_(newZoom); | 394 this.setZoomInternal_(newZoom); |
| 278 this.updateViewport_(); | 395 this.updateViewport_(); |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 492 for (var i = Viewport.ZOOM_FACTORS.length - 1; i >= 0; i--) { | 609 for (var i = Viewport.ZOOM_FACTORS.length - 1; i >= 0; i--) { |
| 493 if (Viewport.ZOOM_FACTORS[i] > this.zoom_) | 610 if (Viewport.ZOOM_FACTORS[i] > this.zoom_) |
| 494 nextZoom = Viewport.ZOOM_FACTORS[i]; | 611 nextZoom = Viewport.ZOOM_FACTORS[i]; |
| 495 } | 612 } |
| 496 this.setZoomInternal_(nextZoom); | 613 this.setZoomInternal_(nextZoom); |
| 497 this.updateViewport_(); | 614 this.updateViewport_(); |
| 498 }.bind(this)); | 615 }.bind(this)); |
| 499 }, | 616 }, |
| 500 | 617 |
| 501 /** | 618 /** |
| 619 * Pinch zoom event handler. | |
| 620 * @param {!Object} e The pinch event. | |
| 621 */ | |
| 622 pinchZoom: function(e) { | |
| 623 this.mightZoom_(function() { | |
| 624 this.pinchPhase_ = e.direction == 'out' ? | |
| 625 Viewport.PinchPhase.PINCH_UPDATE_ZOOM_OUT : | |
| 626 Viewport.PinchPhase.PINCH_UPDATE_ZOOM_IN; | |
| 627 | |
| 628 var scaleDelta = e.startScaleRatio / this.prevScale_; | |
| 629 this.pinchPanVector_ = | |
| 630 vectorDelta(e.center, this.firstPinchCenterInFrame_); | |
| 631 | |
| 632 var needsScrollbars = this.documentNeedsScrollbars_( | |
| 633 clampScale(this.zoom_ * scaleDelta)); | |
| 634 | |
| 635 this.pinchCenter_ = e.center; | |
| 636 | |
| 637 // If there's no horizontal scrolling, keep the content centered so the | |
| 638 // user can't zoom in on the non-content area. | |
| 639 // TODO(mcnee) Investigate other ways of scaling when we don't have | |
| 640 // horizontal scrolling. We want to keep the document centered, | |
| 641 // but this causes a potentially awkward transition when we start | |
| 642 // using the gesture center. | |
| 643 if (!needsScrollbars.horizontal) { | |
| 644 this.pinchCenter_ = { | |
| 645 x: this.window_.innerWidth / 2, | |
| 646 y: this.window_.innerHeight / 2 | |
| 647 }; | |
| 648 } else if (this.keepContentCentered_) { | |
| 649 this.oldCenterInContent = | |
| 650 this.frameToContent(frameToPluginCoordinate(e.center)); | |
| 651 this.keepContentCentered_ = false; | |
| 652 } | |
| 653 | |
| 654 this.setPinchZoomInternal_( | |
| 655 scaleDelta, frameToPluginCoordinate(e.center)); | |
| 656 this.updateViewport_(); | |
| 657 this.prevScale_ = e.startScaleRatio; | |
| 658 }.bind(this)); | |
| 659 }, | |
| 660 | |
| 661 pinchZoomStart: function(e) { | |
| 662 this.pinchPhase_ = Viewport.PinchPhase.PINCH_START; | |
| 663 this.prevScale_ = 1; | |
| 664 this.oldCenterInContent = | |
| 665 this.frameToContent(frameToPluginCoordinate(e.center)); | |
| 666 | |
| 667 var needsScrollbars = this.documentNeedsScrollbars_(this.zoom_); | |
| 668 this.keepContentCentered_ = !needsScrollbars.horizontal; | |
| 669 // We keep track of begining of the pinch. | |
| 670 // By doing so we will be able to compute the pan distance. | |
| 671 this.firstPinchCenterInFrame_ = e.center; | |
| 672 }, | |
| 673 | |
| 674 pinchZoomEnd: function(e) { | |
| 675 this.mightZoom_(function() { | |
| 676 this.pinchPhase_ = Viewport.PinchPhase.PINCH_END; | |
| 677 var scaleDelta = e.startScaleRatio / this.prevScale_; | |
| 678 this.pinchCenter_ = e.center; | |
| 679 | |
| 680 this.setPinchZoomInternal_( | |
| 681 scaleDelta, frameToPluginCoordinate(e.center)); | |
| 682 this.updateViewport_(); | |
| 683 }.bind(this)); | |
| 684 | |
| 685 this.pinchPhase_ = Viewport.PinchPhase.PINCH_NONE; | |
| 686 this.pinchPanVector_ = null; | |
| 687 this.pinchCenter_ = null; | |
| 688 this.firstPinchCenterInFrame_ = null; | |
| 689 }, | |
| 690 | |
| 691 /** | |
| 502 * Go to the given page index. | 692 * Go to the given page index. |
| 503 * @param {number} page the index of the page to go to. zero-based. | 693 * @param {number} page the index of the page to go to. zero-based. |
| 504 */ | 694 */ |
| 505 goToPage: function(page) { | 695 goToPage: function(page) { |
| 506 this.mightZoom_(function() { | 696 this.mightZoom_(function() { |
| 507 if (this.pageDimensions_.length === 0) | 697 if (this.pageDimensions_.length === 0) |
| 508 return; | 698 return; |
| 509 if (page < 0) | 699 if (page < 0) |
| 510 page = 0; | 700 page = 0; |
| 511 if (page >= this.pageDimensions_.length) | 701 if (page >= this.pageDimensions_.length) |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 590 spaceOnLeft = Math.max(spaceOnLeft, 0); | 780 spaceOnLeft = Math.max(spaceOnLeft, 0); |
| 591 | 781 |
| 592 return { | 782 return { |
| 593 x: x * this.zoom_ + spaceOnLeft - this.window_.pageXOffset, | 783 x: x * this.zoom_ + spaceOnLeft - this.window_.pageXOffset, |
| 594 y: insetDimensions.y * this.zoom_ - this.window_.pageYOffset, | 784 y: insetDimensions.y * this.zoom_ - this.window_.pageYOffset, |
| 595 width: insetDimensions.width * this.zoom_, | 785 width: insetDimensions.width * this.zoom_, |
| 596 height: insetDimensions.height * this.zoom_ | 786 height: insetDimensions.height * this.zoom_ |
| 597 }; | 787 }; |
| 598 } | 788 } |
| 599 }; | 789 }; |
| OLD | NEW |