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

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: Added LICENSE file 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;
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 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 this.sizer_.style.width = zoomedDimensions.width + 'px'; 167 this.sizer_.style.width = zoomedDimensions.width + 'px';
164 this.sizer_.style.height = zoomedDimensions.height + 168 this.sizer_.style.height = zoomedDimensions.height +
165 this.topToolbarHeight_ + 'px'; 169 this.topToolbarHeight_ + 'px';
166 } 170 }
167 }, 171 },
168 172
169 /** 173 /**
170 * @private 174 * @private
171 * Called when the viewport should be updated. 175 * Called when the viewport should be updated.
172 */ 176 */
173 updateViewport_: function() { 177 updateViewport_: function() { this.viewportChangedCallback_(); },
174 this.viewportChangedCallback_();
175 },
176 178
177 /** 179 /**
178 * @private 180 * @private
179 * Called when the viewport size changes. 181 * Called when the viewport size changes.
180 */ 182 */
181 resize_: function() { 183 resize_: function() {
182 if (this.fittingType_ == Viewport.FittingType.FIT_TO_PAGE) 184 if (this.fittingType_ == Viewport.FittingType.FIT_TO_PAGE)
183 this.fitToPageInternal_(false); 185 this.fitToPageInternal_(false);
184 else if (this.fittingType_ == Viewport.FittingType.FIT_TO_WIDTH) 186 else if (this.fittingType_ == Viewport.FittingType.FIT_TO_WIDTH)
185 this.fitToWidth(); 187 this.fitToWidth();
(...skipping 28 matching lines...) Expand all
214 var scrollbarHeight = needsScrollbars.horizontal ? this.scrollbarWidth_ : 0; 216 var scrollbarHeight = needsScrollbars.horizontal ? this.scrollbarWidth_ : 0;
215 return { 217 return {
216 width: this.window_.innerWidth - scrollbarWidth, 218 width: this.window_.innerWidth - scrollbarWidth,
217 height: this.window_.innerHeight - scrollbarHeight 219 height: this.window_.innerHeight - scrollbarHeight
218 }; 220 };
219 }, 221 },
220 222
221 /** 223 /**
222 * @type {number} the zoom level of the viewport. 224 * @type {number} the zoom level of the viewport.
223 */ 225 */
224 get zoom() { 226 get zoom() { return this.zoom_; },
225 return this.zoom_;
226 },
227 227
228 /** 228 /**
229 * @private 229 * @private
230 * Used to wrap a function that might perform zooming on the viewport. This is 230 * 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 231 * 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 232 * so that while zooming is taking place it can stop reacting to scroll events
233 * from the viewport. This is to avoid flickering. 233 * from the viewport. This is to avoid flickering.
234 */ 234 */
235 mightZoom_: function(f) { 235 mightZoom_: function(f) {
236 this.beforeZoomCallback_(); 236 this.beforeZoomCallback_();
237 this.allowedToChangeZoom_ = true; 237 this.allowedToChangeZoom_ = true;
238 f(); 238 f();
239 var needsScrollbars = this.documentNeedsScrollbars_(this.zoom_);
240 if (!needsScrollbars.horizontal) {
241 this.pinchCenter_ = {
242 x: this.window_.innerWidth / 2,
243 y: this.window_.innerHeight / 2
244 };
245 }
239 this.allowedToChangeZoom_ = false; 246 this.allowedToChangeZoom_ = false;
240 this.afterZoomCallback_(); 247 this.afterZoomCallback_();
241 }, 248 },
242 249
243 /** 250 /**
244 * @private 251 * @private
245 * Sets the zoom of the viewport. 252 * Sets the zoom of the viewport.
246 * @param {number} newZoom the zoom level to zoom to. 253 * @param {number} newZoom the zoom level to zoom to.
247 */ 254 */
248 setZoomInternal_: function(newZoom) { 255 setZoomInternal_: function(newZoom) {
249 if (!this.allowedToChangeZoom_) { 256 if (!this.allowedToChangeZoom_) {
250 throw 'Called Viewport.setZoomInternal_ without calling ' + 257 throw 'Called Viewport.setZoomInternal_ without calling ' +
251 'Viewport.mightZoom_.'; 258 'Viewport.mightZoom_.';
252 } 259 }
253 // Record the scroll position (relative to the top-left of the window). 260 // Record the scroll position (relative to the top-left of the window).
254 var currentScrollPos = { 261 var currentScrollPos = {
255 x: this.position.x / this.zoom_, 262 x: this.position.x / this.zoom_,
256 y: this.position.y / this.zoom_ 263 y: this.position.y / this.zoom_
257 }; 264 };
258 this.zoom_ = newZoom; 265 this.zoom_ = newZoom;
259 this.contentSizeChanged_(); 266 this.contentSizeChanged_();
260 // Scroll to the scaled scroll position. 267 // Scroll to the scaled scroll position.
261 this.position = { 268 this.position = {
262 x: currentScrollPos.x * newZoom, 269 x: currentScrollPos.x * newZoom,
263 y: currentScrollPos.y * newZoom 270 y: currentScrollPos.y * newZoom
264 }; 271 };
265 }, 272 },
266 273
267 /** 274 /**
275 * @private
276 * Sets the zoom of the viewport.
277 * Same function as below but for pinch zoom we have some more operations.
278 * @param {number} scaleDelta the zoom delta.
279 * @param {Object} center the pinch center in content coordinates
280 */
281 setPinchZoomInternal_: function(scaleDelta, center) {
282 if (!this.allowedToChangeZoom_) {
283 throw 'Called Viewport.setZoomInternal_ without calling ' +
284 'Viewport.mightZoom_.';
285 }
286 this.zoom_ = this.clampScale(this.zoom_ * scaleDelta);
287
288 var newCenterInContent = this.frameToContent(center);
289 var delta = {
290 x: (newCenterInContent.x - this.oldCenterInContent.x),
291 y: (newCenterInContent.y - this.oldCenterInContent.y)
292 };
293
294 // Record the scroll position (relative to the pinch center).
295 var currentScrollPos = {
296 x: this.position.x - delta.x * this.zoom_,
297 y: this.position.y - delta.y * this.zoom_
298 };
299
300 this.contentSizeChanged_();
301 // Scroll to the scaled scroll position.
302 this.position = {x: currentScrollPos.x, y: currentScrollPos.y};
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_; },
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 // We render on pinchin in order to solve the invalid regions that appear
575 // after zooming out.
576 if (ev.additionalEvent == 'pinchin')
577 this.doRender_ = true;
578 else
579 this.doRender_ = false;
580
581 var scaleDelta = ev.scale / this.prevScale;
582 this.pinchPanVector_ = this.vectorDelta(ev.center, this.first_pinch_center _in_frame_);
583
584 var needsScrollbars = this.documentNeedsScrollbars_(
585 this.clampScale(this.zoom_ * scaleDelta));
586 // If there's no horizontal scrolling, keep the content centered so the
587 // user can't zoom in on the non-content area.
588 if (this.keepContentCentered_ && needsScrollbars.horizontal) {
589 this.oldCenterInContent =
590 this.frameToContent(this.frameToPluginCoordinate(ev.center));
591 this.keepContentCentered_ = false;
592 }
593
594 this.pinchCenter_ = ev.center;
595 this.setPinchZoomInternal_(scaleDelta, this.frameToPluginCoordinate(ev.cen ter));
596 this.updateViewport_();
597 this.prevScale = ev.scale;
598 }.bind(this));
599 },
600
601 pinchZoomStart: function(ev) {
602 this.prevScale = 1;
603 this.oldCenterInContent =
604 this.frameToContent(this.frameToPluginCoordinate(ev.center));
605
606 var needsScrollbars = this.documentNeedsScrollbars_(this.zoom_);
607 if (!needsScrollbars.horizontal)
608 this.keepContentCentered_ = true;
609 else
610 this.keepContentCentered_ = false;
611 // We keep track of begining of the pinch.
612 // By doing so we will be able to compute the pan distance.
613 this.first_pinch_center_in_frame_ = ev.center;
614 },
615
616 pinchZoomEnd: function(ev) {
617 this.mightZoom_(function() {
618 // We want to render the document on pinch end
619 this.doRender_ = true;
620 var scaleDelta = ev.scale / this.prevScale;
621 this.pinchCenter_ = ev.center;
622
623 this.setPinchZoomInternal_(scaleDelta, this.frameToPluginCoordinate(ev.cen ter));
624 this.updateViewport_();
625 }.bind(this));
626 },
627
628 frameToPluginCoordinate: function(coordinateInFrame) {
629 var container = $('plugin');
630 return {
631 x: coordinateInFrame.x - container.getBoundingClientRect().left,
632 y: coordinateInFrame.y - container.getBoundingClientRect().top
633 };
634 },
635
636 /**
501 * Go to the given page index. 637 * Go to the given page index.
502 * @param {number} page the index of the page to go to. zero-based. 638 * @param {number} page the index of the page to go to. zero-based.
503 */ 639 */
504 goToPage: function(page) { 640 goToPage: function(page) {
505 this.mightZoom_(function() { 641 this.mightZoom_(function() {
506 if (this.pageDimensions_.length === 0) 642 if (this.pageDimensions_.length === 0)
507 return; 643 return;
508 if (page < 0) 644 if (page < 0)
509 page = 0; 645 page = 0;
510 if (page >= this.pageDimensions_.length) 646 if (page >= this.pageDimensions_.length)
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 spaceOnLeft = Math.max(spaceOnLeft, 0); 725 spaceOnLeft = Math.max(spaceOnLeft, 0);
590 726
591 return { 727 return {
592 x: x * this.zoom_ + spaceOnLeft - this.window_.pageXOffset, 728 x: x * this.zoom_ + spaceOnLeft - this.window_.pageXOffset,
593 y: insetDimensions.y * this.zoom_ - this.window_.pageYOffset, 729 y: insetDimensions.y * this.zoom_ - this.window_.pageYOffset,
594 width: insetDimensions.width * this.zoom_, 730 width: insetDimensions.width * this.zoom_,
595 height: insetDimensions.height * this.zoom_ 731 height: insetDimensions.height * this.zoom_
596 }; 732 };
597 } 733 }
598 }; 734 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698