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

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

Issue 2400743002: Improved Pinch-Zoom for PDF. (Closed)
Patch Set: 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.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
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
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
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
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
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 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698