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 * Create a new viewport. | 18 * Create a new viewport. |
19 * @constructor | 19 * @constructor |
20 * @param {Window} window the window | 20 * @param {Window} window the window |
21 * @param {Object} sizer is the element which represents the size of the | 21 * @param {Object} sizer is the element which represents the size of the |
22 * document in the viewport | 22 * document in the viewport |
23 * @param {Function} viewportChangedCallback is run when the viewport changes | 23 * @param {Function} viewportChangedCallback is run when the viewport changes |
24 * @param {Function} beforeZoomCallback is run before a change in zoom | 24 * @param {Function} beforeZoomCallback is run before a change in zoom |
25 * @param {Function} afterZoomCallback is run after a change in zoom | 25 * @param {Function} afterZoomCallback is run after a change in zoom |
26 * @param {number} scrollbarWidth the width of scrollbars on the page | 26 * @param {number} scrollbarWidth the width of scrollbars on the page |
27 * @param {number} defaultZoom The default zoom level. | 27 * @param {number} defaultZoom The default zoom level. |
| 28 * @param {number} topToolbarHeight The number of pixels that should initially |
| 29 * be left blank above the document for the toolbar. |
28 */ | 30 */ |
29 function Viewport(window, | 31 function Viewport(window, |
30 sizer, | 32 sizer, |
31 viewportChangedCallback, | 33 viewportChangedCallback, |
32 beforeZoomCallback, | 34 beforeZoomCallback, |
33 afterZoomCallback, | 35 afterZoomCallback, |
34 scrollbarWidth, | 36 scrollbarWidth, |
35 defaultZoom) { | 37 defaultZoom, |
| 38 topToolbarHeight) { |
36 this.window_ = window; | 39 this.window_ = window; |
37 this.sizer_ = sizer; | 40 this.sizer_ = sizer; |
38 this.viewportChangedCallback_ = viewportChangedCallback; | 41 this.viewportChangedCallback_ = viewportChangedCallback; |
39 this.beforeZoomCallback_ = beforeZoomCallback; | 42 this.beforeZoomCallback_ = beforeZoomCallback; |
40 this.afterZoomCallback_ = afterZoomCallback; | 43 this.afterZoomCallback_ = afterZoomCallback; |
41 this.allowedToChangeZoom_ = false; | 44 this.allowedToChangeZoom_ = false; |
42 this.zoom_ = 1; | 45 this.zoom_ = 1; |
43 this.documentDimensions_ = null; | 46 this.documentDimensions_ = null; |
44 this.pageDimensions_ = []; | 47 this.pageDimensions_ = []; |
45 this.scrollbarWidth_ = scrollbarWidth; | 48 this.scrollbarWidth_ = scrollbarWidth; |
46 this.fittingType_ = Viewport.FittingType.NONE; | 49 this.fittingType_ = Viewport.FittingType.NONE; |
47 this.defaultZoom_ = defaultZoom; | 50 this.defaultZoom_ = defaultZoom; |
| 51 this.topToolbarHeight_ = topToolbarHeight; |
48 | 52 |
49 window.addEventListener('scroll', this.updateViewport_.bind(this)); | 53 window.addEventListener('scroll', this.updateViewport_.bind(this)); |
50 window.addEventListener('resize', this.resize_.bind(this)); | 54 window.addEventListener('resize', this.resize_.bind(this)); |
51 } | 55 } |
52 | 56 |
53 /** | 57 /** |
54 * Enumeration of page fitting types. | 58 * Enumeration of page fitting types. |
55 * @enum {string} | 59 * @enum {string} |
56 */ | 60 */ |
57 Viewport.FittingType = { | 61 Viewport.FittingType = { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 }, | 136 }, |
133 | 137 |
134 /** | 138 /** |
135 * @private | 139 * @private |
136 * Helper function called when the zoomed document size changes. | 140 * Helper function called when the zoomed document size changes. |
137 */ | 141 */ |
138 contentSizeChanged_: function() { | 142 contentSizeChanged_: function() { |
139 if (this.documentDimensions_) { | 143 if (this.documentDimensions_) { |
140 this.sizer_.style.width = | 144 this.sizer_.style.width = |
141 this.documentDimensions_.width * this.zoom_ + 'px'; | 145 this.documentDimensions_.width * this.zoom_ + 'px'; |
142 this.sizer_.style.height = | 146 this.sizer_.style.height = this.documentDimensions_.height * this.zoom_ + |
143 this.documentDimensions_.height * this.zoom_ + 'px'; | 147 this.topToolbarHeight_ + 'px'; |
144 } | 148 } |
145 }, | 149 }, |
146 | 150 |
147 /** | 151 /** |
148 * @private | 152 * @private |
149 * Called when the viewport should be updated. | 153 * Called when the viewport should be updated. |
150 */ | 154 */ |
151 updateViewport_: function() { | 155 updateViewport_: function() { |
152 this.viewportChangedCallback_(); | 156 this.viewportChangedCallback_(); |
153 }, | 157 }, |
(...skipping 10 matching lines...) Expand all Loading... |
164 else | 168 else |
165 this.updateViewport_(); | 169 this.updateViewport_(); |
166 }, | 170 }, |
167 | 171 |
168 /** | 172 /** |
169 * @type {Object} the scroll position of the viewport. | 173 * @type {Object} the scroll position of the viewport. |
170 */ | 174 */ |
171 get position() { | 175 get position() { |
172 return { | 176 return { |
173 x: this.window_.pageXOffset, | 177 x: this.window_.pageXOffset, |
174 y: this.window_.pageYOffset | 178 y: this.window_.pageYOffset - this.topToolbarHeight_ |
175 }; | 179 }; |
176 }, | 180 }, |
177 | 181 |
178 /** | 182 /** |
179 * Scroll the viewport to the specified position. | 183 * Scroll the viewport to the specified position. |
180 * @type {Object} position the position to scroll to. | 184 * @type {Object} position the position to scroll to. |
181 */ | 185 */ |
182 set position(position) { | 186 set position(position) { |
183 this.window_.scrollTo(position.x, position.y); | 187 this.window_.scrollTo(position.x, position.y + this.topToolbarHeight_); |
184 }, | 188 }, |
185 | 189 |
186 /** | 190 /** |
187 * @type {Object} the size of the viewport excluding scrollbars. | 191 * @type {Object} the size of the viewport excluding scrollbars. |
188 */ | 192 */ |
189 get size() { | 193 get size() { |
190 var needsScrollbars = this.documentNeedsScrollbars_(this.zoom_); | 194 var needsScrollbars = this.documentNeedsScrollbars_(this.zoom_); |
191 var scrollbarWidth = needsScrollbars.vertical ? this.scrollbarWidth_ : 0; | 195 var scrollbarWidth = needsScrollbars.vertical ? this.scrollbarWidth_ : 0; |
192 var scrollbarHeight = needsScrollbars.horizontal ? this.scrollbarWidth_ : 0; | 196 var scrollbarHeight = needsScrollbars.horizontal ? this.scrollbarWidth_ : 0; |
193 return { | 197 return { |
(...skipping 28 matching lines...) Expand all Loading... |
222 * @private | 226 * @private |
223 * Sets the zoom of the viewport. | 227 * Sets the zoom of the viewport. |
224 * @param {number} newZoom the zoom level to zoom to. | 228 * @param {number} newZoom the zoom level to zoom to. |
225 */ | 229 */ |
226 setZoomInternal_: function(newZoom) { | 230 setZoomInternal_: function(newZoom) { |
227 if (!this.allowedToChangeZoom_) { | 231 if (!this.allowedToChangeZoom_) { |
228 throw 'Called Viewport.setZoomInternal_ without calling ' + | 232 throw 'Called Viewport.setZoomInternal_ without calling ' + |
229 'Viewport.mightZoom_.'; | 233 'Viewport.mightZoom_.'; |
230 } | 234 } |
231 // Record the scroll position (relative to the top-left of the window). | 235 // Record the scroll position (relative to the top-left of the window). |
232 var currentScrollPos = [ | 236 var currentScrollPos = { |
233 this.window_.pageXOffset / this.zoom_, | 237 x: this.position.x / this.zoom_, |
234 this.window_.pageYOffset / this.zoom_ | 238 y: this.position.y / this.zoom_ |
235 ]; | 239 }; |
236 this.zoom_ = newZoom; | 240 this.zoom_ = newZoom; |
237 this.contentSizeChanged_(); | 241 this.contentSizeChanged_(); |
238 // Scroll to the scaled scroll position. | 242 // Scroll to the scaled scroll position. |
239 this.window_.scrollTo(currentScrollPos[0] * newZoom, | 243 this.position = { |
240 currentScrollPos[1] * newZoom); | 244 x: currentScrollPos.x * newZoom, |
| 245 y: currentScrollPos.y * newZoom |
| 246 }; |
241 }, | 247 }, |
242 | 248 |
243 /** | 249 /** |
244 * Sets the zoom to the given zoom level. | 250 * Sets the zoom to the given zoom level. |
245 * @param {number} newZoom the zoom level to zoom to. | 251 * @param {number} newZoom the zoom level to zoom to. |
246 */ | 252 */ |
247 setZoom: function(newZoom) { | 253 setZoom: function(newZoom) { |
248 this.fittingType_ = Viewport.FittingType.NONE; | 254 this.fittingType_ = Viewport.FittingType.NONE; |
249 newZoom = Math.max(Viewport.ZOOM_FACTOR_RANGE.min, | 255 newZoom = Math.max(Viewport.ZOOM_FACTOR_RANGE.min, |
250 Math.min(newZoom, Viewport.ZOOM_FACTOR_RANGE.max)); | 256 Math.min(newZoom, Viewport.ZOOM_FACTOR_RANGE.max)); |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
419 this.fittingType_ = Viewport.FittingType.FIT_TO_PAGE; | 425 this.fittingType_ = Viewport.FittingType.FIT_TO_PAGE; |
420 if (!this.documentDimensions_) | 426 if (!this.documentDimensions_) |
421 return; | 427 return; |
422 var page = this.getMostVisiblePage(); | 428 var page = this.getMostVisiblePage(); |
423 // Fit to the current page's height and the widest page's width. | 429 // Fit to the current page's height and the widest page's width. |
424 var dimensions = { | 430 var dimensions = { |
425 width: this.documentDimensions_.width, | 431 width: this.documentDimensions_.width, |
426 height: this.pageDimensions_[page].height, | 432 height: this.pageDimensions_[page].height, |
427 }; | 433 }; |
428 this.setZoomInternal_(this.computeFittingZoom_(dimensions, false)); | 434 this.setZoomInternal_(this.computeFittingZoom_(dimensions, false)); |
429 if (scrollToTopOfPage) | 435 if (scrollToTopOfPage) { |
430 this.window_.scrollTo(0, this.pageDimensions_[page].y * this.zoom_); | 436 this.position = { |
| 437 x: 0, |
| 438 y: this.pageDimensions_[page].y * this.zoom_ |
| 439 }; |
| 440 } |
431 this.updateViewport_(); | 441 this.updateViewport_(); |
432 }.bind(this)); | 442 }.bind(this)); |
433 }, | 443 }, |
434 | 444 |
435 /** | 445 /** |
436 * Zoom the viewport so that a page consumes the entire viewport. Also scrolls | 446 * Zoom the viewport so that a page consumes the entire viewport. Also scrolls |
437 * the viewport to the top of the current page. | 447 * the viewport to the top of the current page. |
438 */ | 448 */ |
439 fitToPage: function() { | 449 fitToPage: function() { |
440 this.fitToPageInternal_(true); | 450 this.fitToPageInternal_(true); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 */ | 488 */ |
479 goToPage: function(page) { | 489 goToPage: function(page) { |
480 this.mightZoom_(function() { | 490 this.mightZoom_(function() { |
481 if (this.pageDimensions_.length === 0) | 491 if (this.pageDimensions_.length === 0) |
482 return; | 492 return; |
483 if (page < 0) | 493 if (page < 0) |
484 page = 0; | 494 page = 0; |
485 if (page >= this.pageDimensions_.length) | 495 if (page >= this.pageDimensions_.length) |
486 page = this.pageDimensions_.length - 1; | 496 page = this.pageDimensions_.length - 1; |
487 var dimensions = this.pageDimensions_[page]; | 497 var dimensions = this.pageDimensions_[page]; |
488 this.window_.scrollTo(dimensions.x * this.zoom_, | 498 var toolbarOffset = 0; |
489 dimensions.y * this.zoom_); | 499 // Unless we're in fit to page mode, scroll above the page by |
| 500 // |this.topToolbarHeight_| so that the toolbar isn't covering it |
| 501 // initially. |
| 502 if (this.fittingType_ != Viewport.FittingType.FIT_TO_PAGE) |
| 503 toolbarOffset = this.topToolbarHeight_; |
| 504 this.position = { |
| 505 x: dimensions.x * this.zoom_, |
| 506 y: dimensions.y * this.zoom_ - toolbarOffset |
| 507 }; |
490 this.updateViewport_(); | 508 this.updateViewport_(); |
491 }.bind(this)); | 509 }.bind(this)); |
492 }, | 510 }, |
493 | 511 |
494 /** | 512 /** |
495 * Set the dimensions of the document. | 513 * Set the dimensions of the document. |
496 * @param {Object} documentDimensions the dimensions of the document | 514 * @param {Object} documentDimensions the dimensions of the document |
497 */ | 515 */ |
498 setDocumentDimensions: function(documentDimensions) { | 516 setDocumentDimensions: function(documentDimensions) { |
499 this.mightZoom_(function() { | 517 this.mightZoom_(function() { |
500 var initialDimensions = !this.documentDimensions_; | 518 var initialDimensions = !this.documentDimensions_; |
501 this.documentDimensions_ = documentDimensions; | 519 this.documentDimensions_ = documentDimensions; |
502 this.pageDimensions_ = this.documentDimensions_.pageDimensions; | 520 this.pageDimensions_ = this.documentDimensions_.pageDimensions; |
503 if (initialDimensions) { | 521 if (initialDimensions) { |
504 this.setZoomInternal_( | 522 this.setZoomInternal_( |
505 Math.min(this.defaultZoom_, | 523 Math.min(this.defaultZoom_, |
506 this.computeFittingZoom_(this.documentDimensions_, true))); | 524 this.computeFittingZoom_(this.documentDimensions_, true))); |
507 this.window_.scrollTo(0, 0); | 525 this.position = { |
| 526 x: 0, |
| 527 y: -this.topToolbarHeight_ |
| 528 }; |
508 } | 529 } |
509 this.contentSizeChanged_(); | 530 this.contentSizeChanged_(); |
510 this.resize_(); | 531 this.resize_(); |
511 }.bind(this)); | 532 }.bind(this)); |
512 }, | 533 }, |
513 | 534 |
514 /** | 535 /** |
515 * Get the coordinates of the page contents (excluding the page shadow) | 536 * Get the coordinates of the page contents (excluding the page shadow) |
516 * relative to the screen. | 537 * relative to the screen. |
517 * @param {number} page the index of the page to get the rect for. | 538 * @param {number} page the index of the page to get the rect for. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
553 spaceOnLeft = Math.max(spaceOnLeft, 0); | 574 spaceOnLeft = Math.max(spaceOnLeft, 0); |
554 | 575 |
555 return { | 576 return { |
556 x: x * this.zoom_ + spaceOnLeft - this.window_.pageXOffset, | 577 x: x * this.zoom_ + spaceOnLeft - this.window_.pageXOffset, |
557 y: insetDimensions.y * this.zoom_ - this.window_.pageYOffset, | 578 y: insetDimensions.y * this.zoom_ - this.window_.pageYOffset, |
558 width: insetDimensions.width * this.zoom_, | 579 width: insetDimensions.width * this.zoom_, |
559 height: insetDimensions.height * this.zoom_ | 580 height: insetDimensions.height * this.zoom_ |
560 }; | 581 }; |
561 } | 582 } |
562 }; | 583 }; |
OLD | NEW |