blob: 1e635487aafa39e77a0dede8a04d98fc5a5bac6b [file] [log] [blame]
[email protected]3528d6302014-02-19 08:13:071// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/**
Henrique Nakashima585c7af02018-03-27 04:55:216 * @typedef {{
7 * x: number,
8 * y: number
9 * }}
10 */
11let Point;
12
13/**
14 * @typedef {{
15 * x: number | undefined,
16 * y: number | undefined
17 * }}
18 */
19let PartialPoint;
20
21/**
sammcd06823a962014-11-10 04:51:1522 * Returns the height of the intersection of two rectangles.
Henrique Nakashimad5de6d0d2018-04-13 18:02:4223 *
[email protected]3528d6302014-02-19 08:13:0724 * @param {Object} rect1 the first rect
25 * @param {Object} rect2 the second rect
sammcd06823a962014-11-10 04:51:1526 * @return {number} the height of the intersection of the rects
[email protected]3528d6302014-02-19 08:13:0727 */
sammcd06823a962014-11-10 04:51:1528function getIntersectionHeight(rect1, rect2) {
dbeam70db0fb2017-06-19 17:09:2729 return Math.max(
30 0,
[email protected]3528d6302014-02-19 08:13:0731 Math.min(rect1.y + rect1.height, rect2.y + rect2.height) -
dbeam70db0fb2017-06-19 17:09:2732 Math.max(rect1.y, rect2.y));
[email protected]3528d6302014-02-19 08:13:0733}
34
35/**
mcnee6e1abbf2016-11-09 18:05:3136 * Computes vector between two points.
Henrique Nakashimad5de6d0d2018-04-13 18:02:4237 *
mcnee6e1abbf2016-11-09 18:05:3138 * @param {!Object} p1 The first point.
39 * @param {!Object} p2 The second point.
40 * @return {!Object} The vector.
41 */
42function vectorDelta(p1, p2) {
dbeam70db0fb2017-06-19 17:09:2743 return {x: p2.x - p1.x, y: p2.y - p1.y};
mcnee6e1abbf2016-11-09 18:05:3144}
45
46function frameToPluginCoordinate(coordinateInFrame) {
47 var container = $('plugin');
48 return {
49 x: coordinateInFrame.x - container.getBoundingClientRect().left,
50 y: coordinateInFrame.y - container.getBoundingClientRect().top
51 };
52}
53
54/**
[email protected]3528d6302014-02-19 08:13:0755 * Create a new viewport.
Henrique Nakashimad5de6d0d2018-04-13 18:02:4256 *
[email protected]3528d6302014-02-19 08:13:0757 * @param {Window} window the window
58 * @param {Object} sizer is the element which represents the size of the
59 * document in the viewport
[email protected]3528d6302014-02-19 08:13:0760 * @param {Function} viewportChangedCallback is run when the viewport changes
[email protected]499e9562014-06-26 05:45:2761 * @param {Function} beforeZoomCallback is run before a change in zoom
62 * @param {Function} afterZoomCallback is run after a change in zoom
rbpottera82dacc2017-09-08 19:39:3963 * @param {Function} setUserInitiatedCallback is run to indicate whether a zoom
64 * event is user initiated.
[email protected]345e7c62014-05-02 09:52:5865 * @param {number} scrollbarWidth the width of scrollbars on the page
sammc43d4982f2015-04-22 07:46:5166 * @param {number} defaultZoom The default zoom level.
raymesbd82a942015-08-05 07:05:1867 * @param {number} topToolbarHeight The number of pixels that should initially
68 * be left blank above the document for the toolbar.
Henrique Nakashimad5de6d0d2018-04-13 18:02:4269 * @constructor
[email protected]3528d6302014-02-19 08:13:0770 */
dbeam70db0fb2017-06-19 17:09:2771function Viewport(
72 window, sizer, viewportChangedCallback, beforeZoomCallback,
rbpottera82dacc2017-09-08 19:39:3973 afterZoomCallback, setUserInitiatedCallback, scrollbarWidth, defaultZoom,
74 topToolbarHeight) {
[email protected]3528d6302014-02-19 08:13:0775 this.window_ = window;
76 this.sizer_ = sizer;
[email protected]3528d6302014-02-19 08:13:0777 this.viewportChangedCallback_ = viewportChangedCallback;
[email protected]499e9562014-06-26 05:45:2778 this.beforeZoomCallback_ = beforeZoomCallback;
79 this.afterZoomCallback_ = afterZoomCallback;
rbpottera82dacc2017-09-08 19:39:3980 this.setUserInitiatedCallback_ = setUserInitiatedCallback;
[email protected]499e9562014-06-26 05:45:2781 this.allowedToChangeZoom_ = false;
mcnee2999413a2016-12-06 20:29:2582 this.internalZoom_ = 1;
83 this.zoomManager_ = new InactiveZoomManager(this, 1);
[email protected]312112c72014-04-14 01:45:4384 this.documentDimensions_ = null;
[email protected]3528d6302014-02-19 08:13:0785 this.pageDimensions_ = [];
[email protected]345e7c62014-05-02 09:52:5886 this.scrollbarWidth_ = scrollbarWidth;
Henrique Nakashima50b18e02017-11-21 23:29:5787 this.fittingType_ = FittingType.NONE;
sammc43d4982f2015-04-22 07:46:5188 this.defaultZoom_ = defaultZoom;
raymesbd82a942015-08-05 07:05:1889 this.topToolbarHeight_ = topToolbarHeight;
mcnee6e1abbf2016-11-09 18:05:3190 this.prevScale_ = 1;
91 this.pinchPhase_ = Viewport.PinchPhase.PINCH_NONE;
92 this.pinchPanVector_ = null;
93 this.pinchCenter_ = null;
94 this.firstPinchCenterInFrame_ = null;
[email protected]3528d6302014-02-19 08:13:0795
96 window.addEventListener('scroll', this.updateViewport_.bind(this));
rbpottera82dacc2017-09-08 19:39:3997 window.addEventListener('resize', this.resizeWrapper_.bind(this));
[email protected]3528d6302014-02-19 08:13:0798}
99
[email protected]312112c72014-04-14 01:45:43100/**
mcnee6e1abbf2016-11-09 18:05:31101 * Enumeration of pinch states.
102 * This should match PinchPhase enum in pdf/out_of_process_instance.h
103 * @enum {number}
104 */
105Viewport.PinchPhase = {
106 PINCH_NONE: 0,
107 PINCH_START: 1,
108 PINCH_UPDATE_ZOOM_OUT: 2,
109 PINCH_UPDATE_ZOOM_IN: 3,
110 PINCH_END: 4
111};
112
113/**
[email protected]8dcaa262014-05-30 13:33:37114 * The increment to scroll a page by in pixels when up/down/left/right arrow
115 * keys are pressed. Usually we just let the browser handle scrolling on the
116 * window when these keys are pressed but in certain cases we need to simulate
117 * these events.
118 */
119Viewport.SCROLL_INCREMENT = 40;
120
121/**
[email protected]312112c72014-04-14 01:45:43122 * Predefined zoom factors to be used when zooming in/out. These are in
bsep24e7ec42016-08-25 02:11:20123 * ascending order. This should match the lists in
124 * components/ui/zoom/page_zoom_constants.h and
125 * chrome/browser/resources/settings/appearance_page/appearance_page.js
[email protected]312112c72014-04-14 01:45:43126 */
dbeam70db0fb2017-06-19 17:09:27127Viewport.ZOOM_FACTORS = [
128 0.25, 1 / 3, 0.5, 2 / 3, 0.75, 0.8, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2, 2.5, 3,
129 4, 5
130];
[email protected]312112c72014-04-14 01:45:43131
132/**
[email protected]4271e16b2014-08-22 12:18:59133 * The minimum and maximum range to be used to clip zoom factor.
134 */
135Viewport.ZOOM_FACTOR_RANGE = {
136 min: Viewport.ZOOM_FACTORS[0],
137 max: Viewport.ZOOM_FACTORS[Viewport.ZOOM_FACTORS.length - 1]
138};
139
140/**
Kevin McNee4e78edc2017-10-26 19:55:54141 * Clamps the zoom factor (or page scale factor) to be within the limits.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42142 *
Kevin McNee4e78edc2017-10-26 19:55:54143 * @param {number} factor The zoom/scale factor.
144 * @return {number} The factor clamped within the limits.
145 */
146Viewport.clampZoom = function(factor) {
147 return Math.max(
148 Viewport.ZOOM_FACTOR_RANGE.min,
149 Math.min(factor, Viewport.ZOOM_FACTOR_RANGE.max));
150};
151
152/**
[email protected]312112c72014-04-14 01:45:43153 * The width of the page shadow around pages in pixels.
154 */
dbeam70db0fb2017-06-19 17:09:27155Viewport.PAGE_SHADOW = {
156 top: 3,
157 bottom: 7,
158 left: 5,
159 right: 5
160};
[email protected]312112c72014-04-14 01:45:43161
[email protected]3528d6302014-02-19 08:13:07162Viewport.prototype = {
163 /**
raymese6e90c62015-08-10 06:21:40164 * Returns the zoomed and rounded document dimensions for the given zoom.
165 * Rounding is necessary when interacting with the renderer which tends to
166 * operate in integral values (for example for determining if scrollbars
167 * should be shown).
Henrique Nakashimad5de6d0d2018-04-13 18:02:42168 *
raymese6e90c62015-08-10 06:21:40169 * @param {number} zoom The zoom to use to compute the scaled dimensions.
170 * @return {Object} A dictionary with scaled 'width'/'height' of the document.
171 * @private
172 */
173 getZoomedDocumentDimensions_: function(zoom) {
174 if (!this.documentDimensions_)
175 return null;
176 return {
177 width: Math.round(this.documentDimensions_.width * zoom),
178 height: Math.round(this.documentDimensions_.height * zoom)
179 };
180 },
181
182 /**
[email protected]3528d6302014-02-19 08:13:07183 * Returns true if the document needs scrollbars at the given zoom level.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42184 *
[email protected]3528d6302014-02-19 08:13:07185 * @param {number} zoom compute whether scrollbars are needed at this zoom
[email protected]312112c72014-04-14 01:45:43186 * @return {Object} with 'horizontal' and 'vertical' keys which map to bool
187 * values indicating if the horizontal and vertical scrollbars are needed
[email protected]3528d6302014-02-19 08:13:07188 * respectively.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42189 * @private
[email protected]3528d6302014-02-19 08:13:07190 */
191 documentNeedsScrollbars_: function(zoom) {
raymese6e90c62015-08-10 06:21:40192 var zoomedDimensions = this.getZoomedDocumentDimensions_(zoom);
193 if (!zoomedDimensions) {
dbeam70db0fb2017-06-19 17:09:27194 return {horizontal: false, vertical: false};
[email protected]499e9562014-06-26 05:45:27195 }
sammc63334fed2014-11-10 03:07:35196
197 // If scrollbars are required for one direction, expand the document in the
198 // other direction to take the width of the scrollbars into account when
199 // deciding whether the other direction needs scrollbars.
raymese6e90c62015-08-10 06:21:40200 if (zoomedDimensions.width > this.window_.innerWidth)
201 zoomedDimensions.height += this.scrollbarWidth_;
202 else if (zoomedDimensions.height > this.window_.innerHeight)
203 zoomedDimensions.width += this.scrollbarWidth_;
[email protected]3528d6302014-02-19 08:13:07204 return {
raymese6e90c62015-08-10 06:21:40205 horizontal: zoomedDimensions.width > this.window_.innerWidth,
raymes051fb2c2015-09-21 04:56:41206 vertical: zoomedDimensions.height + this.topToolbarHeight_ >
207 this.window_.innerHeight
[email protected]3528d6302014-02-19 08:13:07208 };
209 },
210
211 /**
212 * Returns true if the document needs scrollbars at the current zoom level.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42213 *
[email protected]3528d6302014-02-19 08:13:07214 * @return {Object} with 'x' and 'y' keys which map to bool values
215 * indicating if the horizontal and vertical scrollbars are needed
216 * respectively.
217 */
218 documentHasScrollbars: function() {
mcnee2999413a2016-12-06 20:29:25219 return this.documentNeedsScrollbars_(this.zoom);
[email protected]3528d6302014-02-19 08:13:07220 },
221
222 /**
[email protected]3528d6302014-02-19 08:13:07223 * Helper function called when the zoomed document size changes.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42224 *
225 * @private
[email protected]3528d6302014-02-19 08:13:07226 */
227 contentSizeChanged_: function() {
mcnee2999413a2016-12-06 20:29:25228 var zoomedDimensions = this.getZoomedDocumentDimensions_(this.zoom);
raymese6e90c62015-08-10 06:21:40229 if (zoomedDimensions) {
230 this.sizer_.style.width = zoomedDimensions.width + 'px';
dbeam70db0fb2017-06-19 17:09:27231 this.sizer_.style.height =
232 zoomedDimensions.height + this.topToolbarHeight_ + 'px';
[email protected]345e7c62014-05-02 09:52:58233 }
[email protected]3528d6302014-02-19 08:13:07234 },
235
236 /**
[email protected]312112c72014-04-14 01:45:43237 * Called when the viewport should be updated.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42238 *
239 * @private
[email protected]3528d6302014-02-19 08:13:07240 */
[email protected]312112c72014-04-14 01:45:43241 updateViewport_: function() {
242 this.viewportChangedCallback_();
243 },
244
245 /**
rbpottera82dacc2017-09-08 19:39:39246 * Called when the browser window size changes.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42247 *
248 * @private
rbpottera82dacc2017-09-08 19:39:39249 */
250 resizeWrapper_: function() {
251 this.setUserInitiatedCallback_(false);
252 this.resize_();
253 this.setUserInitiatedCallback_(true);
254 },
255
256 /**
[email protected]312112c72014-04-14 01:45:43257 * Called when the viewport size changes.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42258 *
259 * @private
[email protected]312112c72014-04-14 01:45:43260 */
261 resize_: function() {
Henrique Nakashima50b18e02017-11-21 23:29:57262 if (this.fittingType_ == FittingType.FIT_TO_PAGE)
raymes161514f2015-02-17 05:09:51263 this.fitToPageInternal_(false);
Henrique Nakashima50b18e02017-11-21 23:29:57264 else if (this.fittingType_ == FittingType.FIT_TO_WIDTH)
[email protected]312112c72014-04-14 01:45:43265 this.fitToWidth();
Henrique Nakashima50b18e02017-11-21 23:29:57266 else if (this.fittingType_ == FittingType.FIT_TO_HEIGHT)
267 this.fitToHeightInternal_(false);
Henrique Nakashima4cf9ed42018-09-07 21:02:03268 else if (this.internalZoom_ == 0)
269 this.fitToNone();
[email protected]312112c72014-04-14 01:45:43270 else
271 this.updateViewport_();
272 },
273
274 /**
275 * @type {Object} the scroll position of the viewport.
276 */
277 get position() {
278 return {
279 x: this.window_.pageXOffset,
raymesbd82a942015-08-05 07:05:18280 y: this.window_.pageYOffset - this.topToolbarHeight_
[email protected]312112c72014-04-14 01:45:43281 };
282 },
283
284 /**
285 * Scroll the viewport to the specified position.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42286 *
Henrique Nakashima585c7af02018-03-27 04:55:21287 * @type {Object} position The position to scroll to.
[email protected]312112c72014-04-14 01:45:43288 */
289 set position(position) {
raymesbd82a942015-08-05 07:05:18290 this.window_.scrollTo(position.x, position.y + this.topToolbarHeight_);
[email protected]312112c72014-04-14 01:45:43291 },
292
293 /**
294 * @type {Object} the size of the viewport excluding scrollbars.
295 */
296 get size() {
mcnee2999413a2016-12-06 20:29:25297 var needsScrollbars = this.documentNeedsScrollbars_(this.zoom);
[email protected]312112c72014-04-14 01:45:43298 var scrollbarWidth = needsScrollbars.vertical ? this.scrollbarWidth_ : 0;
299 var scrollbarHeight = needsScrollbars.horizontal ? this.scrollbarWidth_ : 0;
300 return {
301 width: this.window_.innerWidth - scrollbarWidth,
302 height: this.window_.innerHeight - scrollbarHeight
303 };
304 },
305
306 /**
307 * @type {number} the zoom level of the viewport.
308 */
309 get zoom() {
mcnee2999413a2016-12-06 20:29:25310 return this.zoomManager_.applyBrowserZoom(this.internalZoom_);
311 },
312
313 /**
314 * Set the zoom manager.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42315 *
mcnee2999413a2016-12-06 20:29:25316 * @type {ZoomManager} manager the zoom manager to set.
317 */
318 set zoomManager(manager) {
319 this.zoomManager_ = manager;
[email protected]312112c72014-04-14 01:45:43320 },
321
322 /**
mcnee6e1abbf2016-11-09 18:05:31323 * @type {Viewport.PinchPhase} The phase of the current pinch gesture for
324 * the viewport.
325 */
326 get pinchPhase() {
327 return this.pinchPhase_;
328 },
329
330 /**
331 * @type {Object} The panning caused by the current pinch gesture (as
332 * the deltas of the x and y coordinates).
333 */
334 get pinchPanVector() {
335 return this.pinchPanVector_;
336 },
337
338 /**
339 * @type {Object} The coordinates of the center of the current pinch gesture.
340 */
341 get pinchCenter() {
342 return this.pinchCenter_;
343 },
344
345 /**
[email protected]499e9562014-06-26 05:45:27346 * Used to wrap a function that might perform zooming on the viewport. This is
347 * required so that we can notify the plugin that zooming is in progress
348 * so that while zooming is taking place it can stop reacting to scroll events
349 * from the viewport. This is to avoid flickering.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42350 *
351 * @param {function} f Function to wrap
352 * @private
[email protected]499e9562014-06-26 05:45:27353 */
354 mightZoom_: function(f) {
355 this.beforeZoomCallback_();
356 this.allowedToChangeZoom_ = true;
357 f();
358 this.allowedToChangeZoom_ = false;
359 this.afterZoomCallback_();
360 },
361
362 /**
[email protected]312112c72014-04-14 01:45:43363 * Sets the zoom of the viewport.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42364 *
[email protected]312112c72014-04-14 01:45:43365 * @param {number} newZoom the zoom level to zoom to.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42366 * @private
[email protected]312112c72014-04-14 01:45:43367 */
[email protected]fbad5bb2014-07-18 07:20:36368 setZoomInternal_: function(newZoom) {
369 if (!this.allowedToChangeZoom_) {
370 throw 'Called Viewport.setZoomInternal_ without calling ' +
dbeam70db0fb2017-06-19 17:09:27371 'Viewport.mightZoom_.';
[email protected]fbad5bb2014-07-18 07:20:36372 }
sammc5c33b7e2014-11-07 04:03:09373 // Record the scroll position (relative to the top-left of the window).
raymesbd82a942015-08-05 07:05:18374 var currentScrollPos = {
mcnee2999413a2016-12-06 20:29:25375 x: this.position.x / this.zoom,
376 y: this.position.y / this.zoom
raymesbd82a942015-08-05 07:05:18377 };
Henrique Nakashima4cf9ed42018-09-07 21:02:03378
mcnee2999413a2016-12-06 20:29:25379 this.internalZoom_ = newZoom;
[email protected]3528d6302014-02-19 08:13:07380 this.contentSizeChanged_();
381 // Scroll to the scaled scroll position.
raymesbd82a942015-08-05 07:05:18382 this.position = {
mcnee2999413a2016-12-06 20:29:25383 x: currentScrollPos.x * this.zoom,
384 y: currentScrollPos.y * this.zoom
raymesbd82a942015-08-05 07:05:18385 };
[email protected]3528d6302014-02-19 08:13:07386 },
387
388 /**
mcnee6e1abbf2016-11-09 18:05:31389 * Sets the zoom of the viewport.
390 * Same as setZoomInternal_ but for pinch zoom we have some more operations.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42391 *
mcnee6e1abbf2016-11-09 18:05:31392 * @param {number} scaleDelta The zoom delta.
393 * @param {!Object} center The pinch center in content coordinates.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42394 * @private
mcnee6e1abbf2016-11-09 18:05:31395 */
396 setPinchZoomInternal_: function(scaleDelta, center) {
dbeam70db0fb2017-06-19 17:09:27397 assert(
398 this.allowedToChangeZoom_,
mcnee6e1abbf2016-11-09 18:05:31399 'Called Viewport.setPinchZoomInternal_ without calling ' +
dbeam70db0fb2017-06-19 17:09:27400 'Viewport.mightZoom_.');
Kevin McNee4e78edc2017-10-26 19:55:54401 this.internalZoom_ = Viewport.clampZoom(this.internalZoom_ * scaleDelta);
mcnee6e1abbf2016-11-09 18:05:31402
403 var newCenterInContent = this.frameToContent(center);
404 var delta = {
405 x: (newCenterInContent.x - this.oldCenterInContent.x),
406 y: (newCenterInContent.y - this.oldCenterInContent.y)
407 };
408
409 // Record the scroll position (relative to the pinch center).
410 var currentScrollPos = {
mcnee2999413a2016-12-06 20:29:25411 x: this.position.x - delta.x * this.zoom,
412 y: this.position.y - delta.y * this.zoom
mcnee6e1abbf2016-11-09 18:05:31413 };
414
415 this.contentSizeChanged_();
416 // Scroll to the scaled scroll position.
dbeam70db0fb2017-06-19 17:09:27417 this.position = {x: currentScrollPos.x, y: currentScrollPos.y};
mcnee6e1abbf2016-11-09 18:05:31418 },
419
420 /**
mcnee6e1abbf2016-11-09 18:05:31421 * Converts a point from frame to content coordinates.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42422 *
mcnee6e1abbf2016-11-09 18:05:31423 * @param {!Object} framePoint The frame coordinates.
424 * @return {!Object} The content coordinates.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42425 * @private
mcnee6e1abbf2016-11-09 18:05:31426 */
427 frameToContent: function(framePoint) {
428 // TODO(mcnee) Add a helper Point class to avoid duplicating operations
429 // on plain {x,y} objects.
430 return {
mcnee2999413a2016-12-06 20:29:25431 x: (framePoint.x + this.position.x) / this.zoom,
432 y: (framePoint.y + this.position.y) / this.zoom
mcnee6e1abbf2016-11-09 18:05:31433 };
434 },
435
436 /**
[email protected]fbad5bb2014-07-18 07:20:36437 * Sets the zoom to the given zoom level.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42438 *
[email protected]fbad5bb2014-07-18 07:20:36439 * @param {number} newZoom the zoom level to zoom to.
[email protected]499e9562014-06-26 05:45:27440 */
[email protected]fbad5bb2014-07-18 07:20:36441 setZoom: function(newZoom) {
Henrique Nakashima50b18e02017-11-21 23:29:57442 this.fittingType_ = FittingType.NONE;
dpapad9afc2802017-08-09 22:01:43443 this.mightZoom_(() => {
Kevin McNee4e78edc2017-10-26 19:55:54444 this.setZoomInternal_(Viewport.clampZoom(newZoom));
[email protected]fbad5bb2014-07-18 07:20:36445 this.updateViewport_();
dpapad9afc2802017-08-09 22:01:43446 });
[email protected]499e9562014-06-26 05:45:27447 },
448
449 /**
mcnee2999413a2016-12-06 20:29:25450 * Gets notified of the browser zoom changing seperately from the
451 * internal zoom.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42452 *
mcnee2999413a2016-12-06 20:29:25453 * @param {number} oldBrowserZoom the previous value of the browser zoom.
454 */
455 updateZoomFromBrowserChange: function(oldBrowserZoom) {
dpapad9afc2802017-08-09 22:01:43456 this.mightZoom_(() => {
mcnee2999413a2016-12-06 20:29:25457 // Record the scroll position (relative to the top-left of the window).
458 var oldZoom = oldBrowserZoom * this.internalZoom_;
459 var currentScrollPos = {
460 x: this.position.x / oldZoom,
461 y: this.position.y / oldZoom
462 };
463 this.contentSizeChanged_();
464 // Scroll to the scaled scroll position.
465 this.position = {
466 x: currentScrollPos.x * this.zoom,
467 y: currentScrollPos.y * this.zoom
468 };
469 this.updateViewport_();
dpapad9afc2802017-08-09 22:01:43470 });
mcnee2999413a2016-12-06 20:29:25471 },
472
473 /**
[email protected]312112c72014-04-14 01:45:43474 * @type {number} the width of scrollbars in the viewport in pixels.
[email protected]3528d6302014-02-19 08:13:07475 */
[email protected]312112c72014-04-14 01:45:43476 get scrollbarWidth() {
477 return this.scrollbarWidth_;
[email protected]3528d6302014-02-19 08:13:07478 },
479
480 /**
Henrique Nakashima50b18e02017-11-21 23:29:57481 * @type {FittingType} the fitting type the viewport is currently in.
[email protected]3528d6302014-02-19 08:13:07482 */
[email protected]312112c72014-04-14 01:45:43483 get fittingType() {
484 return this.fittingType_;
[email protected]3528d6302014-02-19 08:13:07485 },
486
487 /**
Henrique Nakashimad5de6d0d2018-04-13 18:02:42488 * Get the which page is at a given y position.
489 *
dpapadd2d64772017-05-19 02:30:38490 * @param {number} y the y-coordinate to get the page at.
491 * @return {number} the index of a page overlapping the given y-coordinate.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42492 * @private
[email protected]56b7e3c2014-02-20 04:31:24493 */
494 getPageAtY_: function(y) {
495 var min = 0;
496 var max = this.pageDimensions_.length - 1;
497 while (max >= min) {
498 var page = Math.floor(min + ((max - min) / 2));
[email protected]13df2a42014-02-27 03:50:41499 // There might be a gap between the pages, in which case use the bottom
500 // of the previous page as the top for finding the page.
501 var top = 0;
502 if (page > 0) {
503 top = this.pageDimensions_[page - 1].y +
504 this.pageDimensions_[page - 1].height;
505 }
dbeam70db0fb2017-06-19 17:09:27506 var bottom =
507 this.pageDimensions_[page].y + this.pageDimensions_[page].height;
[email protected]13df2a42014-02-27 03:50:41508
[email protected]56b7e3c2014-02-20 04:31:24509 if (top <= y && bottom > y)
510 return page;
Lei Zhangddc0ef032017-11-22 02:14:24511
512 if (top > y)
[email protected]56b7e3c2014-02-20 04:31:24513 max = page - 1;
514 else
515 min = page + 1;
516 }
517 return 0;
518 },
519
520 /**
sammcd06823a962014-11-10 04:51:15521 * Returns the page with the greatest proportion of its height in the current
522 * viewport.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42523 *
dpapadd2d64772017-05-19 02:30:38524 * @return {number} the index of the most visible page.
[email protected]3528d6302014-02-19 08:13:07525 */
526 getMostVisiblePage: function() {
mcnee2999413a2016-12-06 20:29:25527 var firstVisiblePage = this.getPageAtY_(this.position.y / this.zoom);
sammcd06823a962014-11-10 04:51:15528 if (firstVisiblePage == this.pageDimensions_.length - 1)
529 return firstVisiblePage;
530
[email protected]345e7c62014-05-02 09:52:58531 var viewportRect = {
mcnee2999413a2016-12-06 20:29:25532 x: this.position.x / this.zoom,
533 y: this.position.y / this.zoom,
534 width: this.size.width / this.zoom,
535 height: this.size.height / this.zoom
[email protected]345e7c62014-05-02 09:52:58536 };
dbeam70db0fb2017-06-19 17:09:27537 var firstVisiblePageVisibility =
538 getIntersectionHeight(
539 this.pageDimensions_[firstVisiblePage], viewportRect) /
sammcd06823a962014-11-10 04:51:15540 this.pageDimensions_[firstVisiblePage].height;
dbeam70db0fb2017-06-19 17:09:27541 var nextPageVisibility =
542 getIntersectionHeight(
543 this.pageDimensions_[firstVisiblePage + 1], viewportRect) /
sammcd06823a962014-11-10 04:51:15544 this.pageDimensions_[firstVisiblePage + 1].height;
545 if (nextPageVisibility > firstVisiblePageVisibility)
546 return firstVisiblePage + 1;
547 return firstVisiblePage;
[email protected]3528d6302014-02-19 08:13:07548 },
549
550 /**
Henrique Nakashima50b18e02017-11-21 23:29:57551 * Compute the zoom level for fit-to-page, fit-to-width or fit-to-height.
552 *
553 * At least one of {fitWidth, fitHeight} must be true.
554 *
555 * @param {Object} pageDimensions the dimensions of a given page in px.
556 * @param {boolean} fitWidth a bool indicating whether the whole width of the
557 * page needs to be in the viewport.
558 * @param {boolean} fitHeight a bool indicating whether the whole height of
559 * the page needs to be in the viewport.
mcnee2999413a2016-12-06 20:29:25560 * @return {number} the internal zoom to set
Henrique Nakashimad5de6d0d2018-04-13 18:02:42561 * @private
[email protected]3528d6302014-02-19 08:13:07562 */
Henrique Nakashima50b18e02017-11-21 23:29:57563 computeFittingZoom_: function(pageDimensions, fitWidth, fitHeight) {
564 assert(
565 fitWidth || fitHeight,
566 'Invalid parameters. At least one of fitWidth and fitHeight must be ' +
567 'true.');
568
[email protected]3528d6302014-02-19 08:13:07569 // First compute the zoom without scrollbars.
Henrique Nakashima50b18e02017-11-21 23:29:57570 var zoom = this.computeFittingZoomGivenDimensions_(
571 fitWidth, fitHeight, this.window_.innerWidth, this.window_.innerHeight,
572 pageDimensions.width, pageDimensions.height);
573
[email protected]3528d6302014-02-19 08:13:07574 // Check if there needs to be any scrollbars.
575 var needsScrollbars = this.documentNeedsScrollbars_(zoom);
576
577 // If the document fits, just return the zoom.
[email protected]312112c72014-04-14 01:45:43578 if (!needsScrollbars.horizontal && !needsScrollbars.vertical)
[email protected]3528d6302014-02-19 08:13:07579 return zoom;
580
raymese6e90c62015-08-10 06:21:40581 var zoomedDimensions = this.getZoomedDocumentDimensions_(zoom);
[email protected]3528d6302014-02-19 08:13:07582
583 // Check if adding a scrollbar will result in needing the other scrollbar.
584 var scrollbarWidth = this.scrollbarWidth_;
[email protected]312112c72014-04-14 01:45:43585 if (needsScrollbars.horizontal &&
[email protected]3528d6302014-02-19 08:13:07586 zoomedDimensions.height > this.window_.innerHeight - scrollbarWidth) {
[email protected]312112c72014-04-14 01:45:43587 needsScrollbars.vertical = true;
[email protected]3528d6302014-02-19 08:13:07588 }
[email protected]312112c72014-04-14 01:45:43589 if (needsScrollbars.vertical &&
[email protected]3528d6302014-02-19 08:13:07590 zoomedDimensions.width > this.window_.innerWidth - scrollbarWidth) {
[email protected]312112c72014-04-14 01:45:43591 needsScrollbars.horizontal = true;
[email protected]3528d6302014-02-19 08:13:07592 }
593
594 // Compute available window space.
595 var windowWithScrollbars = {
596 width: this.window_.innerWidth,
597 height: this.window_.innerHeight
598 };
[email protected]312112c72014-04-14 01:45:43599 if (needsScrollbars.horizontal)
[email protected]3528d6302014-02-19 08:13:07600 windowWithScrollbars.height -= scrollbarWidth;
[email protected]312112c72014-04-14 01:45:43601 if (needsScrollbars.vertical)
[email protected]3528d6302014-02-19 08:13:07602 windowWithScrollbars.width -= scrollbarWidth;
603
604 // Recompute the zoom.
Henrique Nakashima50b18e02017-11-21 23:29:57605 zoom = this.computeFittingZoomGivenDimensions_(
606 fitWidth, fitHeight, windowWithScrollbars.width,
607 windowWithScrollbars.height, pageDimensions.width,
608 pageDimensions.height);
609
mcnee2999413a2016-12-06 20:29:25610 return this.zoomManager_.internalZoomComponent(zoom);
[email protected]3528d6302014-02-19 08:13:07611 },
612
613 /**
Henrique Nakashima50b18e02017-11-21 23:29:57614 * Compute a zoom level given the dimensions to fit and the actual numbers
615 * in those dimensions.
616 *
617 * @param {boolean} fitWidth make sure the page width is totally contained in
618 * the window.
619 * @param {boolean} fitHeight make sure the page height is totally contained
620 * in the window.
621 * @param {number} windowWidth the width of the window in px.
622 * @param {number} windowHeight the height of the window in px.
623 * @param {number} pageWidth the width of the page in px.
624 * @param {number} pageHeight the height of the page in px.
625 * @return {number} the internal zoom to set
Henrique Nakashimad5de6d0d2018-04-13 18:02:42626 * @private
Henrique Nakashima50b18e02017-11-21 23:29:57627 */
628 computeFittingZoomGivenDimensions_: function(
629 fitWidth, fitHeight, windowWidth, windowHeight, pageWidth, pageHeight) {
630 // Assumes at least one of {fitWidth, fitHeight} is set.
631 var zoomWidth;
632 var zoomHeight;
633
634 if (fitWidth)
635 zoomWidth = windowWidth / pageWidth;
636
637 if (fitHeight)
638 zoomHeight = windowHeight / pageHeight;
639
Henrique Nakashima4cf9ed42018-09-07 21:02:03640 var zoom;
641 if (!fitWidth && fitHeight) {
642 zoom = zoomHeight;
643 } else if (fitWidth && !fitHeight) {
644 zoom = zoomWidth;
645 } else {
646 // Assume fitWidth && fitHeight
647 zoom = Math.min(zoomWidth, zoomHeight);
648 }
Henrique Nakashima50b18e02017-11-21 23:29:57649
Henrique Nakashima4cf9ed42018-09-07 21:02:03650 return Math.max(zoom, 0);
Henrique Nakashima50b18e02017-11-21 23:29:57651 },
652
653 /**
654 * Zoom the viewport so that the page width consumes the entire viewport.
[email protected]3528d6302014-02-19 08:13:07655 */
656 fitToWidth: function() {
dpapad9afc2802017-08-09 22:01:43657 this.mightZoom_(() => {
Henrique Nakashima50b18e02017-11-21 23:29:57658 this.fittingType_ = FittingType.FIT_TO_WIDTH;
[email protected]499e9562014-06-26 05:45:27659 if (!this.documentDimensions_)
660 return;
[email protected]499e9562014-06-26 05:45:27661 // When computing fit-to-width, the maximum width of a page in the
662 // document is used, which is equal to the size of the document width.
dbeam70db0fb2017-06-19 17:09:27663 this.setZoomInternal_(
Henrique Nakashima50b18e02017-11-21 23:29:57664 this.computeFittingZoom_(this.documentDimensions_, true, false));
[email protected]499e9562014-06-26 05:45:27665 this.updateViewport_();
dpapad9afc2802017-08-09 22:01:43666 });
[email protected]3528d6302014-02-19 08:13:07667 },
668
669 /**
Henrique Nakashima50b18e02017-11-21 23:29:57670 * Zoom the viewport so that the page height consumes the entire viewport.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42671 *
Henrique Nakashima50b18e02017-11-21 23:29:57672 * @param {boolean} scrollToTopOfPage Set to true if the viewport should be
673 * scrolled to the top of the current page. Set to false if the viewport
674 * should remain at the current scroll position.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42675 * @private
Henrique Nakashima50b18e02017-11-21 23:29:57676 */
677 fitToHeightInternal_: function(scrollToTopOfPage) {
678 this.mightZoom_(() => {
679 this.fittingType_ = FittingType.FIT_TO_HEIGHT;
680 if (!this.documentDimensions_)
681 return;
682 var page = this.getMostVisiblePage();
683 // When computing fit-to-height, the maximum height of the current page
684 // is used.
685 var dimensions = {
686 width: 0,
687 height: this.pageDimensions_[page].height,
688 };
689 this.setZoomInternal_(this.computeFittingZoom_(dimensions, false, true));
690 if (scrollToTopOfPage) {
691 this.position = {x: 0, y: this.pageDimensions_[page].y * this.zoom};
692 }
693 this.updateViewport_();
694 });
695 },
696
697 /**
698 * Zoom the viewport so that the page height consumes the entire viewport.
699 */
700 fitToHeight: function() {
701 this.fitToHeightInternal_(true);
702 },
703
704 /**
Henrique Nakashima50b18e02017-11-21 23:29:57705 * Zoom the viewport so that a page consumes as much as possible of the it.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42706 *
raymes161514f2015-02-17 05:09:51707 * @param {boolean} scrollToTopOfPage Set to true if the viewport should be
708 * scrolled to the top of the current page. Set to false if the viewport
709 * should remain at the current scroll position.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42710 * @private
[email protected]3528d6302014-02-19 08:13:07711 */
raymes161514f2015-02-17 05:09:51712 fitToPageInternal_: function(scrollToTopOfPage) {
dpapad9afc2802017-08-09 22:01:43713 this.mightZoom_(() => {
Henrique Nakashima50b18e02017-11-21 23:29:57714 this.fittingType_ = FittingType.FIT_TO_PAGE;
[email protected]499e9562014-06-26 05:45:27715 if (!this.documentDimensions_)
716 return;
717 var page = this.getMostVisiblePage();
sammc07f53aa2014-11-06 06:57:46718 // Fit to the current page's height and the widest page's width.
719 var dimensions = {
720 width: this.documentDimensions_.width,
721 height: this.pageDimensions_[page].height,
722 };
Henrique Nakashima50b18e02017-11-21 23:29:57723 this.setZoomInternal_(this.computeFittingZoom_(dimensions, true, true));
raymesbd82a942015-08-05 07:05:18724 if (scrollToTopOfPage) {
dbeam70db0fb2017-06-19 17:09:27725 this.position = {x: 0, y: this.pageDimensions_[page].y * this.zoom};
raymesbd82a942015-08-05 07:05:18726 }
[email protected]499e9562014-06-26 05:45:27727 this.updateViewport_();
dpapad9afc2802017-08-09 22:01:43728 });
[email protected]3528d6302014-02-19 08:13:07729 },
730
731 /**
raymes161514f2015-02-17 05:09:51732 * Zoom the viewport so that a page consumes the entire viewport. Also scrolls
733 * the viewport to the top of the current page.
734 */
735 fitToPage: function() {
736 this.fitToPageInternal_(true);
737 },
738
739 /**
Henrique Nakashima4cf9ed42018-09-07 21:02:03740 * Zoom the viewport to the default zoom policy.
741 */
742 fitToNone: function() {
743 this.mightZoom_(() => {
744 this.fittingType_ = FittingType.NONE;
745 if (!this.documentDimensions_)
746 return;
747 this.setZoomInternal_(Math.min(
748 this.defaultZoom_,
749 this.computeFittingZoom_(this.documentDimensions_, true, false)));
750 this.updateViewport_();
751 });
752 },
753
754 /**
[email protected]3528d6302014-02-19 08:13:07755 * Zoom out to the next predefined zoom level.
756 */
757 zoomOut: function() {
dpapad9afc2802017-08-09 22:01:43758 this.mightZoom_(() => {
Henrique Nakashima50b18e02017-11-21 23:29:57759 this.fittingType_ = FittingType.NONE;
[email protected]499e9562014-06-26 05:45:27760 var nextZoom = Viewport.ZOOM_FACTORS[0];
761 for (var i = 0; i < Viewport.ZOOM_FACTORS.length; i++) {
mcnee2999413a2016-12-06 20:29:25762 if (Viewport.ZOOM_FACTORS[i] < this.internalZoom_)
[email protected]499e9562014-06-26 05:45:27763 nextZoom = Viewport.ZOOM_FACTORS[i];
764 }
[email protected]fbad5bb2014-07-18 07:20:36765 this.setZoomInternal_(nextZoom);
[email protected]499e9562014-06-26 05:45:27766 this.updateViewport_();
dpapad9afc2802017-08-09 22:01:43767 });
[email protected]3528d6302014-02-19 08:13:07768 },
769
770 /**
771 * Zoom in to the next predefined zoom level.
772 */
773 zoomIn: function() {
dpapad9afc2802017-08-09 22:01:43774 this.mightZoom_(() => {
Henrique Nakashima50b18e02017-11-21 23:29:57775 this.fittingType_ = FittingType.NONE;
[email protected]499e9562014-06-26 05:45:27776 var nextZoom = Viewport.ZOOM_FACTORS[Viewport.ZOOM_FACTORS.length - 1];
777 for (var i = Viewport.ZOOM_FACTORS.length - 1; i >= 0; i--) {
mcnee2999413a2016-12-06 20:29:25778 if (Viewport.ZOOM_FACTORS[i] > this.internalZoom_)
[email protected]499e9562014-06-26 05:45:27779 nextZoom = Viewport.ZOOM_FACTORS[i];
780 }
[email protected]fbad5bb2014-07-18 07:20:36781 this.setZoomInternal_(nextZoom);
[email protected]499e9562014-06-26 05:45:27782 this.updateViewport_();
dpapad9afc2802017-08-09 22:01:43783 });
[email protected]3528d6302014-02-19 08:13:07784 },
785
786 /**
mcnee6e1abbf2016-11-09 18:05:31787 * Pinch zoom event handler.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42788 *
mcnee6e1abbf2016-11-09 18:05:31789 * @param {!Object} e The pinch event.
790 */
791 pinchZoom: function(e) {
dpapad9afc2802017-08-09 22:01:43792 this.mightZoom_(() => {
mcnee6e1abbf2016-11-09 18:05:31793 this.pinchPhase_ = e.direction == 'out' ?
dbeam70db0fb2017-06-19 17:09:27794 Viewport.PinchPhase.PINCH_UPDATE_ZOOM_OUT :
795 Viewport.PinchPhase.PINCH_UPDATE_ZOOM_IN;
mcnee6e1abbf2016-11-09 18:05:31796
797 var scaleDelta = e.startScaleRatio / this.prevScale_;
798 this.pinchPanVector_ =
799 vectorDelta(e.center, this.firstPinchCenterInFrame_);
800
dbeam70db0fb2017-06-19 17:09:27801 var needsScrollbars =
802 this.documentNeedsScrollbars_(this.zoomManager_.applyBrowserZoom(
Kevin McNee4e78edc2017-10-26 19:55:54803 Viewport.clampZoom(this.internalZoom_ * scaleDelta)));
mcnee6e1abbf2016-11-09 18:05:31804
805 this.pinchCenter_ = e.center;
806
807 // If there's no horizontal scrolling, keep the content centered so the
808 // user can't zoom in on the non-content area.
809 // TODO(mcnee) Investigate other ways of scaling when we don't have
810 // horizontal scrolling. We want to keep the document centered,
811 // but this causes a potentially awkward transition when we start
812 // using the gesture center.
813 if (!needsScrollbars.horizontal) {
814 this.pinchCenter_ = {
815 x: this.window_.innerWidth / 2,
816 y: this.window_.innerHeight / 2
817 };
818 } else if (this.keepContentCentered_) {
819 this.oldCenterInContent =
820 this.frameToContent(frameToPluginCoordinate(e.center));
821 this.keepContentCentered_ = false;
822 }
823
dbeam70db0fb2017-06-19 17:09:27824 this.setPinchZoomInternal_(scaleDelta, frameToPluginCoordinate(e.center));
mcnee6e1abbf2016-11-09 18:05:31825 this.updateViewport_();
826 this.prevScale_ = e.startScaleRatio;
dpapad9afc2802017-08-09 22:01:43827 });
mcnee6e1abbf2016-11-09 18:05:31828 },
829
830 pinchZoomStart: function(e) {
831 this.pinchPhase_ = Viewport.PinchPhase.PINCH_START;
832 this.prevScale_ = 1;
833 this.oldCenterInContent =
834 this.frameToContent(frameToPluginCoordinate(e.center));
835
mcnee2999413a2016-12-06 20:29:25836 var needsScrollbars = this.documentNeedsScrollbars_(this.zoom);
mcnee6e1abbf2016-11-09 18:05:31837 this.keepContentCentered_ = !needsScrollbars.horizontal;
838 // We keep track of begining of the pinch.
839 // By doing so we will be able to compute the pan distance.
840 this.firstPinchCenterInFrame_ = e.center;
841 },
842
843 pinchZoomEnd: function(e) {
dpapad9afc2802017-08-09 22:01:43844 this.mightZoom_(() => {
mcnee6e1abbf2016-11-09 18:05:31845 this.pinchPhase_ = Viewport.PinchPhase.PINCH_END;
846 var scaleDelta = e.startScaleRatio / this.prevScale_;
847 this.pinchCenter_ = e.center;
848
dbeam70db0fb2017-06-19 17:09:27849 this.setPinchZoomInternal_(scaleDelta, frameToPluginCoordinate(e.center));
mcnee6e1abbf2016-11-09 18:05:31850 this.updateViewport_();
dpapad9afc2802017-08-09 22:01:43851 });
mcnee6e1abbf2016-11-09 18:05:31852
853 this.pinchPhase_ = Viewport.PinchPhase.PINCH_NONE;
854 this.pinchPanVector_ = null;
855 this.pinchCenter_ = null;
856 this.firstPinchCenterInFrame_ = null;
857 },
858
859 /**
[email protected]3528d6302014-02-19 08:13:07860 * Go to the given page index.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42861 *
[email protected]f90b9a42014-08-20 05:37:34862 * @param {number} page the index of the page to go to. zero-based.
[email protected]3528d6302014-02-19 08:13:07863 */
864 goToPage: function(page) {
Henrique Nakashima85fc58b32017-12-11 21:53:42865 this.goToPageAndXY(page, 0, 0);
Henrique Nakashima9d9e0632017-10-06 21:38:18866 },
867
868 /**
869 * Go to the given y position in the given page index.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42870 *
Henrique Nakashima9d9e0632017-10-06 21:38:18871 * @param {number} page the index of the page to go to. zero-based.
Henrique Nakashima85fc58b32017-12-11 21:53:42872 * @param {number} x the x position in the page to go to.
Henrique Nakashima9d9e0632017-10-06 21:38:18873 * @param {number} y the y position in the page to go to.
874 */
Henrique Nakashima85fc58b32017-12-11 21:53:42875 goToPageAndXY: function(page, x, y) {
dpapad9afc2802017-08-09 22:01:43876 this.mightZoom_(() => {
alexandrec9754b9e42015-01-19 03:41:19877 if (this.pageDimensions_.length === 0)
[email protected]499e9562014-06-26 05:45:27878 return;
879 if (page < 0)
880 page = 0;
881 if (page >= this.pageDimensions_.length)
882 page = this.pageDimensions_.length - 1;
883 var dimensions = this.pageDimensions_[page];
raymesbd82a942015-08-05 07:05:18884 var toolbarOffset = 0;
Henrique Nakashima50b18e02017-11-21 23:29:57885 // Unless we're in fit to page or fit to height mode, scroll above the
886 // page by |this.topToolbarHeight_| so that the toolbar isn't covering it
raymesbd82a942015-08-05 07:05:18887 // initially.
Henrique Nakashima50b18e02017-11-21 23:29:57888 if (!this.isPagedMode())
raymesbd82a942015-08-05 07:05:18889 toolbarOffset = this.topToolbarHeight_;
890 this.position = {
Henrique Nakashima85fc58b32017-12-11 21:53:42891 x: (dimensions.x + x) * this.zoom,
Henrique Nakashima9d9e0632017-10-06 21:38:18892 y: (dimensions.y + y) * this.zoom - toolbarOffset
raymesbd82a942015-08-05 07:05:18893 };
[email protected]499e9562014-06-26 05:45:27894 this.updateViewport_();
dpapad9afc2802017-08-09 22:01:43895 });
[email protected]3528d6302014-02-19 08:13:07896 },
897
898 /**
899 * Set the dimensions of the document.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42900 *
[email protected]3528d6302014-02-19 08:13:07901 * @param {Object} documentDimensions the dimensions of the document
902 */
903 setDocumentDimensions: function(documentDimensions) {
dpapad9afc2802017-08-09 22:01:43904 this.mightZoom_(() => {
[email protected]499e9562014-06-26 05:45:27905 var initialDimensions = !this.documentDimensions_;
906 this.documentDimensions_ = documentDimensions;
907 this.pageDimensions_ = this.documentDimensions_.pageDimensions;
908 if (initialDimensions) {
dbeam70db0fb2017-06-19 17:09:27909 this.setZoomInternal_(Math.min(
910 this.defaultZoom_,
Henrique Nakashima50b18e02017-11-21 23:29:57911 this.computeFittingZoom_(this.documentDimensions_, true, false)));
dbeam70db0fb2017-06-19 17:09:27912 this.position = {x: 0, y: -this.topToolbarHeight_};
[email protected]499e9562014-06-26 05:45:27913 }
914 this.contentSizeChanged_();
915 this.resize_();
dpapad9afc2802017-08-09 22:01:43916 });
[email protected]312112c72014-04-14 01:45:43917 },
918
919 /**
920 * Get the coordinates of the page contents (excluding the page shadow)
921 * relative to the screen.
Henrique Nakashimad5de6d0d2018-04-13 18:02:42922 *
[email protected]312112c72014-04-14 01:45:43923 * @param {number} page the index of the page to get the rect for.
924 * @return {Object} a rect representing the page in screen coordinates.
925 */
926 getPageScreenRect: function(page) {
[email protected]499e9562014-06-26 05:45:27927 if (!this.documentDimensions_) {
dbeam70db0fb2017-06-19 17:09:27928 return {x: 0, y: 0, width: 0, height: 0};
[email protected]499e9562014-06-26 05:45:27929 }
[email protected]312112c72014-04-14 01:45:43930 if (page >= this.pageDimensions_.length)
931 page = this.pageDimensions_.length - 1;
932
933 var pageDimensions = this.pageDimensions_[page];
934
935 // Compute the page dimensions minus the shadows.
936 var insetDimensions = {
937 x: pageDimensions.x + Viewport.PAGE_SHADOW.left,
938 y: pageDimensions.y + Viewport.PAGE_SHADOW.top,
939 width: pageDimensions.width - Viewport.PAGE_SHADOW.left -
940 Viewport.PAGE_SHADOW.right,
941 height: pageDimensions.height - Viewport.PAGE_SHADOW.top -
942 Viewport.PAGE_SHADOW.bottom
943 };
944
[email protected]345e7c62014-05-02 09:52:58945 // Compute the x-coordinate of the page within the document.
946 // TODO(raymes): This should really be set when the PDF plugin passes the
947 // page coordinates, but it isn't yet.
948 var x = (this.documentDimensions_.width - pageDimensions.width) / 2 +
949 Viewport.PAGE_SHADOW.left;
950 // Compute the space on the left of the document if the document fits
951 // completely in the screen.
dbeam70db0fb2017-06-19 17:09:27952 var spaceOnLeft =
953 (this.size.width - this.documentDimensions_.width * this.zoom) / 2;
[email protected]345e7c62014-05-02 09:52:58954 spaceOnLeft = Math.max(spaceOnLeft, 0);
[email protected]312112c72014-04-14 01:45:43955
956 return {
mcnee2999413a2016-12-06 20:29:25957 x: x * this.zoom + spaceOnLeft - this.window_.pageXOffset,
958 y: insetDimensions.y * this.zoom - this.window_.pageYOffset,
959 width: insetDimensions.width * this.zoom,
960 height: insetDimensions.height * this.zoom
[email protected]312112c72014-04-14 01:45:43961 };
Henrique Nakashima50b18e02017-11-21 23:29:57962 },
963
964 /**
965 * Check if the current fitting type is a paged mode.
966 *
967 * In a paged mode, page up and page down scroll to the top of the
968 * previous/next page and part of the page is under the toolbar.
969 *
970 * @return {boolean} Whether the current fitting type is a paged mode.
971 */
972 isPagedMode: function(page) {
973 return (
974 this.fittingType_ == FittingType.FIT_TO_PAGE ||
975 this.fittingType_ == FittingType.FIT_TO_HEIGHT);
Henrique Nakashima585c7af02018-03-27 04:55:21976 },
977
978 /**
979 * Scroll the viewport to the specified position.
980 *
981 * @param {!PartialPoint} point The position to which to move the viewport.
982 */
983 scrollTo: function(point) {
984 let changed = false;
985 const newPosition = this.position;
986 if (point.x !== undefined && point.x != newPosition.x) {
987 newPosition.x = point.x;
988 changed = true;
989 }
990 if (point.y !== undefined && point.y != newPosition.y) {
991 newPosition.y = point.y;
992 changed = true;
993 }
994
995 if (changed)
996 this.position = newPosition;
997 },
998
999 /**
1000 * Scroll the viewport by the specified delta.
1001 *
1002 * @param {!Point} delta The delta by which to move the viewport.
1003 */
1004 scrollBy: function(delta) {
1005 const newPosition = this.position;
1006 newPosition.x += delta.x;
1007 newPosition.y += delta.y;
1008 this.scrollTo(newPosition);
[email protected]3528d6302014-02-19 08:13:071009 }
1010};