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

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

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

Powered by Google App Engine
This is Rietveld 408576698