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