Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(712)

Side by Side Diff: chrome/browser/resources/pdf/viewport.js

Issue 2400743002: Improved Pinch-Zoom for PDF. (Closed)
Patch Set: Fix presubmit errors, code clean up, and refactor. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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.pinchPhase_ = Viewport.PinchPhase.PINCH_NONE;
52 54
53 window.addEventListener('scroll', this.updateViewport_.bind(this)); 55 window.addEventListener('scroll', this.updateViewport_.bind(this));
54 window.addEventListener('resize', this.resize_.bind(this)); 56 window.addEventListener('resize', this.resize_.bind(this));
55 } 57 }
56 58
57 /** 59 /**
58 * Enumeration of page fitting types. 60 * Enumeration of page fitting types.
59 * @enum {string} 61 * @enum {string}
60 */ 62 */
61 Viewport.FittingType = { 63 Viewport.FittingType = {
62 NONE: 'none', 64 NONE: 'none',
63 FIT_TO_PAGE: 'fit-to-page', 65 FIT_TO_PAGE: 'fit-to-page',
64 FIT_TO_WIDTH: 'fit-to-width' 66 FIT_TO_WIDTH: 'fit-to-width'
65 }; 67 };
66 68
67 /** 69 /**
70 * Enumeration of pinch states.
71 * This should match PinchPhase enum in pdf/out_of_process_instance.h
72 * @enum {number}
73 */
74 Viewport.PinchPhase = {
75 PINCH_NONE: 0,
76 PINCH_START: 1,
77 PINCH_IN_UPDATE: 2,
bokan 2016/10/17 22:20:16 There's some disagreement in terminology on which
Kevin McNee - google account 2016/10/24 21:11:47 Yeah, I was naming these to be consistent with Ham
78 PINCH_OUT_UPDATE: 3,
79 PINCH_END: 4
80 };
81
82 /**
68 * The increment to scroll a page by in pixels when up/down/left/right arrow 83 * 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 84 * 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 85 * window when these keys are pressed but in certain cases we need to simulate
71 * these events. 86 * these events.
72 */ 87 */
73 Viewport.SCROLL_INCREMENT = 40; 88 Viewport.SCROLL_INCREMENT = 40;
74 89
75 /** 90 /**
76 * Predefined zoom factors to be used when zooming in/out. These are in 91 * Predefined zoom factors to be used when zooming in/out. These are in
77 * ascending order. This should match the lists in 92 * ascending order. This should match the lists in
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 }, 235 },
221 236
222 /** 237 /**
223 * @type {number} the zoom level of the viewport. 238 * @type {number} the zoom level of the viewport.
224 */ 239 */
225 get zoom() { 240 get zoom() {
226 return this.zoom_; 241 return this.zoom_;
227 }, 242 },
228 243
229 /** 244 /**
245 * @type {Viewport.PinchPhase} the phase of the current pinch gesture for
246 * the viewport.
247 */
248 get pinchPhase() {
249 return this.pinchPhase_;
250 },
251
252 /**
253 * @type {Object} the panning caused by the current pinch gesture.
254 */
255 get pinchPanVector() {
256 return this.pinchPanVector_;
257 },
258
259 /**
260 * @type {Object} the center of the current pinch gesture.
261 */
262 get pinchCenter() {
263 return this.pinchCenter_;
264 },
265
266 /**
230 * @private 267 * @private
231 * Used to wrap a function that might perform zooming on the viewport. This is 268 * 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 269 * 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 270 * so that while zooming is taking place it can stop reacting to scroll events
234 * from the viewport. This is to avoid flickering. 271 * from the viewport. This is to avoid flickering.
235 */ 272 */
236 mightZoom_: function(f) { 273 mightZoom_: function(f) {
237 this.beforeZoomCallback_(); 274 this.beforeZoomCallback_();
238 this.allowedToChangeZoom_ = true; 275 this.allowedToChangeZoom_ = true;
239 f(); 276 f();
(...skipping 19 matching lines...) Expand all
259 this.zoom_ = newZoom; 296 this.zoom_ = newZoom;
260 this.contentSizeChanged_(); 297 this.contentSizeChanged_();
261 // Scroll to the scaled scroll position. 298 // Scroll to the scaled scroll position.
262 this.position = { 299 this.position = {
263 x: currentScrollPos.x * newZoom, 300 x: currentScrollPos.x * newZoom,
264 y: currentScrollPos.y * newZoom 301 y: currentScrollPos.y * newZoom
265 }; 302 };
266 }, 303 },
267 304
268 /** 305 /**
306 * @private
307 * Sets the zoom of the viewport.
308 * Same as setZoomInternal_ but for pinch zoom we have some more operations.
309 * @param {number} scaleDelta the zoom delta.
310 * @param {Object} center the pinch center in content coordinates
311 */
312 setPinchZoomInternal_: function(scaleDelta, center) {
313 if (!this.allowedToChangeZoom_) {
314 throw 'Called Viewport.setZoomInternal_ without calling ' +
315 'Viewport.mightZoom_.';
316 }
317 this.zoom_ = this.clampScale(this.zoom_ * scaleDelta);
318
319 var newCenterInContent = this.frameToContent(center);
320 var delta = {
321 x: (newCenterInContent.x - this.oldCenterInContent.x),
322 y: (newCenterInContent.y - this.oldCenterInContent.y)
323 };
324
325 // Record the scroll position (relative to the pinch center).
326 var currentScrollPos = {
327 x: this.position.x - delta.x * this.zoom_,
328 y: this.position.y - delta.y * this.zoom_
329 };
330
331 this.contentSizeChanged_();
332 // Scroll to the scaled scroll position.
333 this.position = {
334 x: currentScrollPos.x,
335 y: currentScrollPos.y
336 };
337 },
338
339 /**
340 * @private
341 * Makes sure that the scale level doesn't get out of the limits.
342 * @param {number} scale the new scale level
343 * @return {number} the scale clamped in the limit
344 */
345 clampScale: function(scale) {
346 return Math.min(5, Math.max(0.25, scale));
347 },
348
349 /**
350 * @private
351 * Gets the new center in content.
352 * @param {Object} pinch center
bokan 2016/10/17 22:20:15 This comment block is wrong, this converts a point
Kevin McNee - google account 2016/10/24 21:11:47 Done.
353 * @param {Object} zoom level
354 * @return {Objet} the new center in content
355 */
356 frameToContent: function(framePoint) {
357 return {
358 x: (framePoint.x + this.position.x) / this.zoom_,
359 y: (framePoint.y + this.position.y) / this.zoom_
360 };
361 },
362
363 /**
269 * Sets the zoom to the given zoom level. 364 * Sets the zoom to the given zoom level.
270 * @param {number} newZoom the zoom level to zoom to. 365 * @param {number} newZoom the zoom level to zoom to.
271 */ 366 */
272 setZoom: function(newZoom) { 367 setZoom: function(newZoom) {
273 this.fittingType_ = Viewport.FittingType.NONE; 368 this.fittingType_ = Viewport.FittingType.NONE;
274 newZoom = Math.max(Viewport.ZOOM_FACTOR_RANGE.min, 369 newZoom = Math.max(Viewport.ZOOM_FACTOR_RANGE.min,
275 Math.min(newZoom, Viewport.ZOOM_FACTOR_RANGE.max)); 370 Math.min(newZoom, Viewport.ZOOM_FACTOR_RANGE.max));
276 this.mightZoom_(function() { 371 this.mightZoom_(function() {
277 this.setZoomInternal_(newZoom); 372 this.setZoomInternal_(newZoom);
278 this.updateViewport_(); 373 this.updateViewport_();
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 this.setZoomInternal_(this.computeFittingZoom_(dimensions, false)); 545 this.setZoomInternal_(this.computeFittingZoom_(dimensions, false));
451 if (scrollToTopOfPage) { 546 if (scrollToTopOfPage) {
452 this.position = { 547 this.position = {
453 x: 0, 548 x: 0,
454 y: this.pageDimensions_[page].y * this.zoom_ 549 y: this.pageDimensions_[page].y * this.zoom_
455 }; 550 };
456 } 551 }
457 this.updateViewport_(); 552 this.updateViewport_();
458 }.bind(this)); 553 }.bind(this));
459 }, 554 },
555 /**
556 * @private
557 * Computes vector between two points.
558 * @param {Object} First Point
559 * @param {Object} Second Point
560 * @return {Object} The vector
561 */
562 vectorDelta: function(p1, p2) {
563 return {
564 x: p2.x - p1.x,
565 y: p2.y - p1.y
566 };
567 },
460 568
461 /** 569 /**
462 * Zoom the viewport so that a page consumes the entire viewport. Also scrolls 570 * Zoom the viewport so that a page consumes the entire viewport. Also scrolls
463 * the viewport to the top of the current page. 571 * the viewport to the top of the current page.
464 */ 572 */
465 fitToPage: function() { 573 fitToPage: function() {
466 this.fitToPageInternal_(true); 574 this.fitToPageInternal_(true);
467 }, 575 },
468 576
469 /** 577 /**
(...skipping 22 matching lines...) Expand all
492 for (var i = Viewport.ZOOM_FACTORS.length - 1; i >= 0; i--) { 600 for (var i = Viewport.ZOOM_FACTORS.length - 1; i >= 0; i--) {
493 if (Viewport.ZOOM_FACTORS[i] > this.zoom_) 601 if (Viewport.ZOOM_FACTORS[i] > this.zoom_)
494 nextZoom = Viewport.ZOOM_FACTORS[i]; 602 nextZoom = Viewport.ZOOM_FACTORS[i];
495 } 603 }
496 this.setZoomInternal_(nextZoom); 604 this.setZoomInternal_(nextZoom);
497 this.updateViewport_(); 605 this.updateViewport_();
498 }.bind(this)); 606 }.bind(this));
499 }, 607 },
500 608
501 /** 609 /**
610 * Pinch zoom event handler
611 * @param {ev} the pinch event
612 */
613 pinchZoom: function(ev) {
614 this.mightZoom_(function() {
615 this.pinchPhase_ = (ev.additionalEvent == 'pinchin') ?
616 Viewport.PinchPhase.PINCH_IN_UPDATE :
617 Viewport.PinchPhase.PINCH_OUT_UPDATE;
618
619 var scaleDelta = ev.scale / this.prevScale;
620 this.pinchPanVector_ =
621 this.vectorDelta(ev.center, this.first_pinch_center_in_frame_);
622
623 var needsScrollbars = this.documentNeedsScrollbars_(
624 this.clampScale(this.zoom_ * scaleDelta));
625 // If there's no horizontal scrolling, keep the content centered so the
626 // user can't zoom in on the non-content area.
bokan 2016/10/17 22:20:16 The if block attached to this comment is for the c
Kevin McNee - google account 2016/10/24 21:11:47 Done.
627 if (this.keepContentCentered_ && needsScrollbars.horizontal) {
628 this.oldCenterInContent =
629 this.frameToContent(this.frameToPluginCoordinate(ev.center));
630 this.keepContentCentered_ = false;
631 }
632
633 this.pinchCenter_ = ev.center;
634 // TODO(mcnee) Come up with a less jarring way of scaling
635 // when we don't have horizontal scrolling. We want to keep
636 // the document centered, but this causes an awkward transition
637 // when we start using the gesture center.
bokan 2016/10/17 22:20:16 IIRC this didn't actually feel that unnatural, but
Kevin McNee - google account 2016/10/24 21:11:47 Yeah, after playing with this a bit, I guess it's
638 if (!needsScrollbars.horizontal) {
639 this.pinchCenter_ = {
640 x: this.window_.innerWidth / 2,
641 y: this.window_.innerHeight / 2
642 };
643 }
644 this.setPinchZoomInternal_(
645 scaleDelta, this.frameToPluginCoordinate(ev.center));
646 this.updateViewport_();
647 this.prevScale = ev.scale;
648 }.bind(this));
649 },
650
651 pinchZoomStart: function(ev) {
652 this.pinchPhase_ = Viewport.PinchPhase.PINCH_START;
653 this.prevScale = 1;
654 this.oldCenterInContent =
655 this.frameToContent(this.frameToPluginCoordinate(ev.center));
656
657 var needsScrollbars = this.documentNeedsScrollbars_(this.zoom_);
658 this.keepContentCentered_ = (!needsScrollbars.horizontal);
bokan 2016/10/17 22:20:15 Nit: no need for parentheses.
Kevin McNee - google account 2016/10/24 21:11:47 Done.
659 // We keep track of begining of the pinch.
660 // By doing so we will be able to compute the pan distance.
661 this.first_pinch_center_in_frame_ = ev.center;
662 },
663
664 pinchZoomEnd: function(ev) {
665 this.mightZoom_(function() {
666 this.pinchPhase_ = Viewport.PinchPhase.PINCH_END;
667 var scaleDelta = ev.scale / this.prevScale;
668 this.pinchCenter_ = ev.center;
669
670 this.setPinchZoomInternal_(
671 scaleDelta, this.frameToPluginCoordinate(ev.center));
672 this.updateViewport_();
673 }.bind(this));
674 this.pinchPhase_ = Viewport.PinchPhase.PINCH_NONE;
675 },
676
677 frameToPluginCoordinate: function(coordinateInFrame) {
678 var container = $('plugin');
679 return {
680 x: coordinateInFrame.x - container.getBoundingClientRect().left,
681 y: coordinateInFrame.y - container.getBoundingClientRect().top
682 };
683 },
684
685 /**
502 * Go to the given page index. 686 * Go to the given page index.
503 * @param {number} page the index of the page to go to. zero-based. 687 * @param {number} page the index of the page to go to. zero-based.
504 */ 688 */
505 goToPage: function(page) { 689 goToPage: function(page) {
506 this.mightZoom_(function() { 690 this.mightZoom_(function() {
507 if (this.pageDimensions_.length === 0) 691 if (this.pageDimensions_.length === 0)
508 return; 692 return;
509 if (page < 0) 693 if (page < 0)
510 page = 0; 694 page = 0;
511 if (page >= this.pageDimensions_.length) 695 if (page >= this.pageDimensions_.length)
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 spaceOnLeft = Math.max(spaceOnLeft, 0); 774 spaceOnLeft = Math.max(spaceOnLeft, 0);
591 775
592 return { 776 return {
593 x: x * this.zoom_ + spaceOnLeft - this.window_.pageXOffset, 777 x: x * this.zoom_ + spaceOnLeft - this.window_.pageXOffset,
594 y: insetDimensions.y * this.zoom_ - this.window_.pageYOffset, 778 y: insetDimensions.y * this.zoom_ - this.window_.pageYOffset,
595 width: insetDimensions.width * this.zoom_, 779 width: insetDimensions.width * this.zoom_,
596 height: insetDimensions.height * this.zoom_ 780 height: insetDimensions.height * this.zoom_
597 }; 781 };
598 } 782 }
599 }; 783 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698