| 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 */ |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 this.beforeZoomCallback_ = beforeZoomCallback; | 42 this.beforeZoomCallback_ = beforeZoomCallback; |
| 43 this.afterZoomCallback_ = afterZoomCallback; | 43 this.afterZoomCallback_ = afterZoomCallback; |
| 44 this.allowedToChangeZoom_ = false; | 44 this.allowedToChangeZoom_ = false; |
| 45 this.zoom_ = 1; | 45 this.zoom_ = 1; |
| 46 this.documentDimensions_ = null; | 46 this.documentDimensions_ = null; |
| 47 this.pageDimensions_ = []; | 47 this.pageDimensions_ = []; |
| 48 this.scrollbarWidth_ = scrollbarWidth; | 48 this.scrollbarWidth_ = scrollbarWidth; |
| 49 this.fittingType_ = Viewport.FittingType.NONE; | 49 this.fittingType_ = Viewport.FittingType.NONE; |
| 50 this.defaultZoom_ = defaultZoom; | 50 this.defaultZoom_ = defaultZoom; |
| 51 this.topToolbarHeight_ = topToolbarHeight; | 51 this.topToolbarHeight_ = topToolbarHeight; |
| 52 this.prevScale = 1; |
| 53 this.doRender_ = true; |
| 54 this.didPinch_ = false; |
| 55 this.didPinchEnd_ = false; |
| 52 | 56 |
| 53 window.addEventListener('scroll', this.updateViewport_.bind(this)); | 57 window.addEventListener('scroll', this.updateViewport_.bind(this)); |
| 54 window.addEventListener('resize', this.resize_.bind(this)); | 58 window.addEventListener('resize', this.resize_.bind(this)); |
| 55 } | 59 } |
| 56 | 60 |
| 57 /** | 61 /** |
| 58 * Enumeration of page fitting types. | 62 * Enumeration of page fitting types. |
| 59 * @enum {string} | 63 * @enum {string} |
| 60 */ | 64 */ |
| 61 Viewport.FittingType = { | 65 Viewport.FittingType = { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 this.sizer_.style.width = zoomedDimensions.width + 'px'; | 167 this.sizer_.style.width = zoomedDimensions.width + 'px'; |
| 164 this.sizer_.style.height = zoomedDimensions.height + | 168 this.sizer_.style.height = zoomedDimensions.height + |
| 165 this.topToolbarHeight_ + 'px'; | 169 this.topToolbarHeight_ + 'px'; |
| 166 } | 170 } |
| 167 }, | 171 }, |
| 168 | 172 |
| 169 /** | 173 /** |
| 170 * @private | 174 * @private |
| 171 * Called when the viewport should be updated. | 175 * Called when the viewport should be updated. |
| 172 */ | 176 */ |
| 173 updateViewport_: function() { | 177 updateViewport_: function() { this.viewportChangedCallback_(); }, |
| 174 this.viewportChangedCallback_(); | |
| 175 }, | |
| 176 | 178 |
| 177 /** | 179 /** |
| 178 * @private | 180 * @private |
| 179 * Called when the viewport size changes. | 181 * Called when the viewport size changes. |
| 180 */ | 182 */ |
| 181 resize_: function() { | 183 resize_: function() { |
| 182 if (this.fittingType_ == Viewport.FittingType.FIT_TO_PAGE) | 184 if (this.fittingType_ == Viewport.FittingType.FIT_TO_PAGE) |
| 183 this.fitToPageInternal_(false); | 185 this.fitToPageInternal_(false); |
| 184 else if (this.fittingType_ == Viewport.FittingType.FIT_TO_WIDTH) | 186 else if (this.fittingType_ == Viewport.FittingType.FIT_TO_WIDTH) |
| 185 this.fitToWidth(); | 187 this.fitToWidth(); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 214 var scrollbarHeight = needsScrollbars.horizontal ? this.scrollbarWidth_ : 0; | 216 var scrollbarHeight = needsScrollbars.horizontal ? this.scrollbarWidth_ : 0; |
| 215 return { | 217 return { |
| 216 width: this.window_.innerWidth - scrollbarWidth, | 218 width: this.window_.innerWidth - scrollbarWidth, |
| 217 height: this.window_.innerHeight - scrollbarHeight | 219 height: this.window_.innerHeight - scrollbarHeight |
| 218 }; | 220 }; |
| 219 }, | 221 }, |
| 220 | 222 |
| 221 /** | 223 /** |
| 222 * @type {number} the zoom level of the viewport. | 224 * @type {number} the zoom level of the viewport. |
| 223 */ | 225 */ |
| 224 get zoom() { | 226 get zoom() { return this.zoom_; }, |
| 225 return this.zoom_; | |
| 226 }, | |
| 227 | 227 |
| 228 /** | 228 /** |
| 229 * @private | 229 * @private |
| 230 * Used to wrap a function that might perform zooming on the viewport. This is | 230 * Used to wrap a function that might perform zooming on the viewport. This is |
| 231 * required so that we can notify the plugin that zooming is in progress | 231 * required so that we can notify the plugin that zooming is in progress |
| 232 * so that while zooming is taking place it can stop reacting to scroll events | 232 * so that while zooming is taking place it can stop reacting to scroll events |
| 233 * from the viewport. This is to avoid flickering. | 233 * from the viewport. This is to avoid flickering. |
| 234 */ | 234 */ |
| 235 mightZoom_: function(f) { | 235 mightZoom_: function(f) { |
| 236 this.beforeZoomCallback_(); | 236 this.beforeZoomCallback_(); |
| 237 this.allowedToChangeZoom_ = true; | 237 this.allowedToChangeZoom_ = true; |
| 238 f(); | 238 f(); |
| 239 var needsScrollbars = this.documentNeedsScrollbars_(this.zoom_); |
| 240 if (!needsScrollbars.horizontal) { |
| 241 this.pinchCenter_ = { |
| 242 x: this.window_.innerWidth / 2, |
| 243 y: this.window_.innerHeight / 2 |
| 244 }; |
| 245 } |
| 239 this.allowedToChangeZoom_ = false; | 246 this.allowedToChangeZoom_ = false; |
| 240 this.afterZoomCallback_(); | 247 this.afterZoomCallback_(); |
| 241 }, | 248 }, |
| 242 | 249 |
| 243 /** | 250 /** |
| 244 * @private | 251 * @private |
| 245 * Sets the zoom of the viewport. | 252 * Sets the zoom of the viewport. |
| 246 * @param {number} newZoom the zoom level to zoom to. | 253 * @param {number} newZoom the zoom level to zoom to. |
| 247 */ | 254 */ |
| 248 setZoomInternal_: function(newZoom) { | 255 setZoomInternal_: function(newZoom) { |
| 249 if (!this.allowedToChangeZoom_) { | 256 if (!this.allowedToChangeZoom_) { |
| 250 throw 'Called Viewport.setZoomInternal_ without calling ' + | 257 throw 'Called Viewport.setZoomInternal_ without calling ' + |
| 251 'Viewport.mightZoom_.'; | 258 'Viewport.mightZoom_.'; |
| 252 } | 259 } |
| 253 // Record the scroll position (relative to the top-left of the window). | 260 // Record the scroll position (relative to the top-left of the window). |
| 254 var currentScrollPos = { | 261 var currentScrollPos = { |
| 255 x: this.position.x / this.zoom_, | 262 x: this.position.x / this.zoom_, |
| 256 y: this.position.y / this.zoom_ | 263 y: this.position.y / this.zoom_ |
| 257 }; | 264 }; |
| 258 this.zoom_ = newZoom; | 265 this.zoom_ = newZoom; |
| 259 this.contentSizeChanged_(); | 266 this.contentSizeChanged_(); |
| 260 // Scroll to the scaled scroll position. | 267 // Scroll to the scaled scroll position. |
| 261 this.position = { | 268 this.position = { |
| 262 x: currentScrollPos.x * newZoom, | 269 x: currentScrollPos.x * newZoom, |
| 263 y: currentScrollPos.y * newZoom | 270 y: currentScrollPos.y * newZoom |
| 264 }; | 271 }; |
| 265 }, | 272 }, |
| 266 | 273 |
| 267 /** | 274 /** |
| 275 * @private |
| 276 * Sets the zoom of the viewport. |
| 277 * Same function as below but for pinch zoom we have some more operations. |
| 278 * @param {number} scaleDelta the zoom delta. |
| 279 * @param {Object} center the pinch center in content coordinates |
| 280 */ |
| 281 setPinchZoomInternal_: function(scaleDelta, center) { |
| 282 if (!this.allowedToChangeZoom_) { |
| 283 throw 'Called Viewport.setZoomInternal_ without calling ' + |
| 284 'Viewport.mightZoom_.'; |
| 285 } |
| 286 this.zoom_ = this.clampScale(this.zoom_ * scaleDelta); |
| 287 |
| 288 var newCenterInContent = this.frameToContent(center); |
| 289 var delta = { |
| 290 x: (newCenterInContent.x - this.oldCenterInContent.x), |
| 291 y: (newCenterInContent.y - this.oldCenterInContent.y) |
| 292 }; |
| 293 |
| 294 // Record the scroll position (relative to the pinch center). |
| 295 var currentScrollPos = { |
| 296 x: this.position.x - delta.x * this.zoom_, |
| 297 y: this.position.y - delta.y * this.zoom_ |
| 298 }; |
| 299 |
| 300 this.contentSizeChanged_(); |
| 301 // Scroll to the scaled scroll position. |
| 302 this.position = {x: currentScrollPos.x, y: currentScrollPos.y}; |
| 303 }, |
| 304 |
| 305 /** |
| 306 * @private |
| 307 * Makes sure that the scale level doesn't get out of the limits. |
| 308 * @param {number} scale the new scale level |
| 309 * @return {number} the scale clamped in the limit |
| 310 */ |
| 311 clampScale: function(scale) { return Math.min(5, Math.max(0.25, scale)); }, |
| 312 |
| 313 /** |
| 314 * @private |
| 315 * Gets the new center in content. |
| 316 * @param {Object} pinch center |
| 317 * @param {Object} zoom level |
| 318 * @return {Objet} the new center in content |
| 319 */ |
| 320 frameToContent: function(framePoint) { |
| 321 return { |
| 322 x: (framePoint.x + this.position.x) / this.zoom_, |
| 323 y: (framePoint.y + this.position.y) / this.zoom_ |
| 324 }; |
| 325 }, |
| 326 |
| 327 /** |
| 268 * Sets the zoom to the given zoom level. | 328 * Sets the zoom to the given zoom level. |
| 269 * @param {number} newZoom the zoom level to zoom to. | 329 * @param {number} newZoom the zoom level to zoom to. |
| 270 */ | 330 */ |
| 271 setZoom: function(newZoom) { | 331 setZoom: function(newZoom) { |
| 272 this.fittingType_ = Viewport.FittingType.NONE; | 332 this.fittingType_ = Viewport.FittingType.NONE; |
| 273 newZoom = Math.max(Viewport.ZOOM_FACTOR_RANGE.min, | 333 newZoom = Math.max(Viewport.ZOOM_FACTOR_RANGE.min, |
| 274 Math.min(newZoom, Viewport.ZOOM_FACTOR_RANGE.max)); | 334 Math.min(newZoom, Viewport.ZOOM_FACTOR_RANGE.max)); |
| 275 this.mightZoom_(function() { | 335 this.mightZoom_(function() { |
| 276 this.setZoomInternal_(newZoom); | 336 this.setZoomInternal_(newZoom); |
| 277 this.updateViewport_(); | 337 this.updateViewport_(); |
| 278 }.bind(this)); | 338 }.bind(this)); |
| 279 }, | 339 }, |
| 280 | 340 |
| 281 /** | 341 /** |
| 282 * @type {number} the width of scrollbars in the viewport in pixels. | 342 * @type {number} the width of scrollbars in the viewport in pixels. |
| 283 */ | 343 */ |
| 284 get scrollbarWidth() { | 344 get scrollbarWidth() { return this.scrollbarWidth_; }, |
| 285 return this.scrollbarWidth_; | |
| 286 }, | |
| 287 | 345 |
| 288 /** | 346 /** |
| 289 * @type {Viewport.FittingType} the fitting type the viewport is currently in. | 347 * @type {Viewport.FittingType} the fitting type the viewport is currently in. |
| 290 */ | 348 */ |
| 291 get fittingType() { | 349 get fittingType() { return this.fittingType_; }, |
| 292 return this.fittingType_; | |
| 293 }, | |
| 294 | 350 |
| 295 /** | 351 /** |
| 296 * @private | 352 * @private |
| 297 * @param {integer} y the y-coordinate to get the page at. | 353 * @param {integer} y the y-coordinate to get the page at. |
| 298 * @return {integer} the index of a page overlapping the given y-coordinate. | 354 * @return {integer} the index of a page overlapping the given y-coordinate. |
| 299 */ | 355 */ |
| 300 getPageAtY_: function(y) { | 356 getPageAtY_: function(y) { |
| 301 var min = 0; | 357 var min = 0; |
| 302 var max = this.pageDimensions_.length - 1; | 358 var max = this.pageDimensions_.length - 1; |
| 303 while (max >= min) { | 359 while (max >= min) { |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 449 this.setZoomInternal_(this.computeFittingZoom_(dimensions, false)); | 505 this.setZoomInternal_(this.computeFittingZoom_(dimensions, false)); |
| 450 if (scrollToTopOfPage) { | 506 if (scrollToTopOfPage) { |
| 451 this.position = { | 507 this.position = { |
| 452 x: 0, | 508 x: 0, |
| 453 y: this.pageDimensions_[page].y * this.zoom_ | 509 y: this.pageDimensions_[page].y * this.zoom_ |
| 454 }; | 510 }; |
| 455 } | 511 } |
| 456 this.updateViewport_(); | 512 this.updateViewport_(); |
| 457 }.bind(this)); | 513 }.bind(this)); |
| 458 }, | 514 }, |
| 515 /** |
| 516 * @private |
| 517 * Computes vector between two points. |
| 518 * @param {Object} First Point |
| 519 * @param {Object} Second Point |
| 520 * @return {Object} The vector |
| 521 */ |
| 522 vectorDelta: function(p1, p2) { |
| 523 var vector = { |
| 524 x: p2.x - p1.x, |
| 525 y: p2.y - p1.y |
| 526 }; |
| 527 return vector; |
| 528 }, |
| 459 | 529 |
| 460 /** | 530 /** |
| 461 * Zoom the viewport so that a page consumes the entire viewport. Also scrolls | 531 * Zoom the viewport so that a page consumes the entire viewport. Also scrolls |
| 462 * the viewport to the top of the current page. | 532 * the viewport to the top of the current page. |
| 463 */ | 533 */ |
| 464 fitToPage: function() { | 534 fitToPage: function() { this.fitToPageInternal_(true); }, |
| 465 this.fitToPageInternal_(true); | |
| 466 }, | |
| 467 | 535 |
| 468 /** | 536 /** |
| 469 * Zoom out to the next predefined zoom level. | 537 * Zoom out to the next predefined zoom level. |
| 470 */ | 538 */ |
| 471 zoomOut: function() { | 539 zoomOut: function() { |
| 472 this.mightZoom_(function() { | 540 this.mightZoom_(function() { |
| 473 this.fittingType_ = Viewport.FittingType.NONE; | 541 this.fittingType_ = Viewport.FittingType.NONE; |
| 474 var nextZoom = Viewport.ZOOM_FACTORS[0]; | 542 var nextZoom = Viewport.ZOOM_FACTORS[0]; |
| 475 for (var i = 0; i < Viewport.ZOOM_FACTORS.length; i++) { | 543 for (var i = 0; i < Viewport.ZOOM_FACTORS.length; i++) { |
| 476 if (Viewport.ZOOM_FACTORS[i] < this.zoom_) | 544 if (Viewport.ZOOM_FACTORS[i] < this.zoom_) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 491 for (var i = Viewport.ZOOM_FACTORS.length - 1; i >= 0; i--) { | 559 for (var i = Viewport.ZOOM_FACTORS.length - 1; i >= 0; i--) { |
| 492 if (Viewport.ZOOM_FACTORS[i] > this.zoom_) | 560 if (Viewport.ZOOM_FACTORS[i] > this.zoom_) |
| 493 nextZoom = Viewport.ZOOM_FACTORS[i]; | 561 nextZoom = Viewport.ZOOM_FACTORS[i]; |
| 494 } | 562 } |
| 495 this.setZoomInternal_(nextZoom); | 563 this.setZoomInternal_(nextZoom); |
| 496 this.updateViewport_(); | 564 this.updateViewport_(); |
| 497 }.bind(this)); | 565 }.bind(this)); |
| 498 }, | 566 }, |
| 499 | 567 |
| 500 /** | 568 /** |
| 569 * Pinch zoom event handler |
| 570 * @param {ev} the pinch event |
| 571 */ |
| 572 pinchZoom: function(ev) { |
| 573 this.mightZoom_(function() { |
| 574 // We render on pinchin in order to solve the invalid regions that appear |
| 575 // after zooming out. |
| 576 if (ev.additionalEvent == 'pinchin') |
| 577 this.doRender_ = true; |
| 578 else |
| 579 this.doRender_ = false; |
| 580 |
| 581 var scaleDelta = ev.scale / this.prevScale; |
| 582 this.pinchPanVector_ = this.vectorDelta(ev.center, this.first_pinch_center
_in_frame_); |
| 583 |
| 584 var needsScrollbars = this.documentNeedsScrollbars_( |
| 585 this.clampScale(this.zoom_ * scaleDelta)); |
| 586 // If there's no horizontal scrolling, keep the content centered so the |
| 587 // user can't zoom in on the non-content area. |
| 588 if (this.keepContentCentered_ && needsScrollbars.horizontal) { |
| 589 this.oldCenterInContent = |
| 590 this.frameToContent(this.frameToPluginCoordinate(ev.center)); |
| 591 this.keepContentCentered_ = false; |
| 592 } |
| 593 |
| 594 this.pinchCenter_ = ev.center; |
| 595 this.setPinchZoomInternal_(scaleDelta, this.frameToPluginCoordinate(ev.cen
ter)); |
| 596 this.updateViewport_(); |
| 597 this.prevScale = ev.scale; |
| 598 }.bind(this)); |
| 599 }, |
| 600 |
| 601 pinchZoomStart: function(ev) { |
| 602 this.prevScale = 1; |
| 603 this.oldCenterInContent = |
| 604 this.frameToContent(this.frameToPluginCoordinate(ev.center)); |
| 605 |
| 606 var needsScrollbars = this.documentNeedsScrollbars_(this.zoom_); |
| 607 if (!needsScrollbars.horizontal) |
| 608 this.keepContentCentered_ = true; |
| 609 else |
| 610 this.keepContentCentered_ = false; |
| 611 // We keep track of begining of the pinch. |
| 612 // By doing so we will be able to compute the pan distance. |
| 613 this.first_pinch_center_in_frame_ = ev.center; |
| 614 }, |
| 615 |
| 616 pinchZoomEnd: function(ev) { |
| 617 this.mightZoom_(function() { |
| 618 // We want to render the document on pinch end |
| 619 this.doRender_ = true; |
| 620 var scaleDelta = ev.scale / this.prevScale; |
| 621 this.pinchCenter_ = ev.center; |
| 622 |
| 623 this.setPinchZoomInternal_(scaleDelta, this.frameToPluginCoordinate(ev.cen
ter)); |
| 624 this.updateViewport_(); |
| 625 }.bind(this)); |
| 626 }, |
| 627 |
| 628 frameToPluginCoordinate: function(coordinateInFrame) { |
| 629 var container = $('plugin'); |
| 630 return { |
| 631 x: coordinateInFrame.x - container.getBoundingClientRect().left, |
| 632 y: coordinateInFrame.y - container.getBoundingClientRect().top |
| 633 }; |
| 634 }, |
| 635 |
| 636 /** |
| 501 * Go to the given page index. | 637 * Go to the given page index. |
| 502 * @param {number} page the index of the page to go to. zero-based. | 638 * @param {number} page the index of the page to go to. zero-based. |
| 503 */ | 639 */ |
| 504 goToPage: function(page) { | 640 goToPage: function(page) { |
| 505 this.mightZoom_(function() { | 641 this.mightZoom_(function() { |
| 506 if (this.pageDimensions_.length === 0) | 642 if (this.pageDimensions_.length === 0) |
| 507 return; | 643 return; |
| 508 if (page < 0) | 644 if (page < 0) |
| 509 page = 0; | 645 page = 0; |
| 510 if (page >= this.pageDimensions_.length) | 646 if (page >= this.pageDimensions_.length) |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 589 spaceOnLeft = Math.max(spaceOnLeft, 0); | 725 spaceOnLeft = Math.max(spaceOnLeft, 0); |
| 590 | 726 |
| 591 return { | 727 return { |
| 592 x: x * this.zoom_ + spaceOnLeft - this.window_.pageXOffset, | 728 x: x * this.zoom_ + spaceOnLeft - this.window_.pageXOffset, |
| 593 y: insetDimensions.y * this.zoom_ - this.window_.pageYOffset, | 729 y: insetDimensions.y * this.zoom_ - this.window_.pageYOffset, |
| 594 width: insetDimensions.width * this.zoom_, | 730 width: insetDimensions.width * this.zoom_, |
| 595 height: insetDimensions.height * this.zoom_ | 731 height: insetDimensions.height * this.zoom_ |
| 596 }; | 732 }; |
| 597 } | 733 } |
| 598 }; | 734 }; |
| OLD | NEW |