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

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

Issue 2400743002: Improved Pinch-Zoom for PDF. (Closed)
Patch Set: Use our own touch gesture detection. Created 4 years, 1 month 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_UPDATE_ZOOM_OUT: 2,
78 PINCH_UPDATE_ZOOM_IN: 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
dpapad 2016/10/31 23:02:23 If Object can't be null, use !Object instead.
Kevin McNee - google account 2016/11/07 23:08:27 Done.
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 * Converts a point from frame to content coordinates.
352 * @param {Object} framePoint the frame coordinates
353 * @return {Object} the content coordinates
dpapad 2016/10/31 23:02:23 Is this code actually being compiled by Closure Co
raymes 2016/10/31 23:53:52 We just use it for documentation right now. They'r
354 */
355 frameToContent: function(framePoint) {
356 return {
357 x: (framePoint.x + this.position.x) / this.zoom_,
358 y: (framePoint.y + this.position.y) / this.zoom_
359 };
360 },
361
362 /**
269 * Sets the zoom to the given zoom level. 363 * Sets the zoom to the given zoom level.
270 * @param {number} newZoom the zoom level to zoom to. 364 * @param {number} newZoom the zoom level to zoom to.
271 */ 365 */
272 setZoom: function(newZoom) { 366 setZoom: function(newZoom) {
273 this.fittingType_ = Viewport.FittingType.NONE; 367 this.fittingType_ = Viewport.FittingType.NONE;
274 newZoom = Math.max(Viewport.ZOOM_FACTOR_RANGE.min, 368 newZoom = Math.max(Viewport.ZOOM_FACTOR_RANGE.min,
275 Math.min(newZoom, Viewport.ZOOM_FACTOR_RANGE.max)); 369 Math.min(newZoom, Viewport.ZOOM_FACTOR_RANGE.max));
276 this.mightZoom_(function() { 370 this.mightZoom_(function() {
277 this.setZoomInternal_(newZoom); 371 this.setZoomInternal_(newZoom);
278 this.updateViewport_(); 372 this.updateViewport_();
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 this.setZoomInternal_(this.computeFittingZoom_(dimensions, false)); 544 this.setZoomInternal_(this.computeFittingZoom_(dimensions, false));
451 if (scrollToTopOfPage) { 545 if (scrollToTopOfPage) {
452 this.position = { 546 this.position = {
453 x: 0, 547 x: 0,
454 y: this.pageDimensions_[page].y * this.zoom_ 548 y: this.pageDimensions_[page].y * this.zoom_
455 }; 549 };
456 } 550 }
457 this.updateViewport_(); 551 this.updateViewport_();
458 }.bind(this)); 552 }.bind(this));
459 }, 553 },
554 /**
555 * @private
556 * Computes vector between two points.
557 * @param {Object} First Point
dpapad 2016/10/31 23:02:23 !Object, here and elsewhere.
Kevin McNee - google account 2016/11/07 23:08:27 Done.
558 * @param {Object} Second Point
559 * @return {Object} The vector
560 */
561 vectorDelta: function(p1, p2) {
562 return {
563 x: p2.x - p1.x,
564 y: p2.y - p1.y
565 };
566 },
460 567
461 /** 568 /**
462 * Zoom the viewport so that a page consumes the entire viewport. Also scrolls 569 * Zoom the viewport so that a page consumes the entire viewport. Also scrolls
463 * the viewport to the top of the current page. 570 * the viewport to the top of the current page.
464 */ 571 */
465 fitToPage: function() { 572 fitToPage: function() {
466 this.fitToPageInternal_(true); 573 this.fitToPageInternal_(true);
467 }, 574 },
468 575
469 /** 576 /**
(...skipping 22 matching lines...) Expand all
492 for (var i = Viewport.ZOOM_FACTORS.length - 1; i >= 0; i--) { 599 for (var i = Viewport.ZOOM_FACTORS.length - 1; i >= 0; i--) {
493 if (Viewport.ZOOM_FACTORS[i] > this.zoom_) 600 if (Viewport.ZOOM_FACTORS[i] > this.zoom_)
494 nextZoom = Viewport.ZOOM_FACTORS[i]; 601 nextZoom = Viewport.ZOOM_FACTORS[i];
495 } 602 }
496 this.setZoomInternal_(nextZoom); 603 this.setZoomInternal_(nextZoom);
497 this.updateViewport_(); 604 this.updateViewport_();
498 }.bind(this)); 605 }.bind(this));
499 }, 606 },
500 607
501 /** 608 /**
609 * Pinch zoom event handler
610 * @param {ev} the pinch event
611 */
612 pinchZoom: function(ev) {
613 this.mightZoom_(function() {
614 this.pinchPhase_ = (ev.direction == 'out') ?
615 Viewport.PinchPhase.PINCH_UPDATE_ZOOM_OUT :
616 Viewport.PinchPhase.PINCH_UPDATE_ZOOM_IN;
617
618 var scaleDelta = ev.startScaleRatio / this.prevScale_;
619 this.pinchPanVector_ =
620 this.vectorDelta(ev.center, this.first_pinch_center_in_frame_);
621
622 var needsScrollbars = this.documentNeedsScrollbars_(
623 this.clampScale(this.zoom_ * scaleDelta));
624
625 this.pinchCenter_ = ev.center;
626
627 // If there's no horizontal scrolling, keep the content centered so the
628 // user can't zoom in on the non-content area.
629 // TODO(mcnee) Investigate other ways of scaling when we don't have
630 // horizontal scrolling. We want to keep the document centered,
631 // but this causes a potentially awkward transition when we start
632 // using the gesture center.
633 if (!needsScrollbars.horizontal) {
634 this.pinchCenter_ = {
635 x: this.window_.innerWidth / 2,
636 y: this.window_.innerHeight / 2
637 };
638 } else if (this.keepContentCentered_) {
639 this.oldCenterInContent =
640 this.frameToContent(this.frameToPluginCoordinate(ev.center));
641 this.keepContentCentered_ = false;
642 }
643
644 this.setPinchZoomInternal_(
645 scaleDelta, this.frameToPluginCoordinate(ev.center));
646 this.updateViewport_();
647 this.prevScale_ = ev.startScaleRatio;
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;
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.startScaleRatio / 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