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

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

Issue 137663008: Implement viewporting for the out of process PDF plugin. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 10 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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 /**
6 * Predefined zoom factors to be used when zooming in/out. These are in
7 * ascending order.
8 */
9 var ZOOM_FACTORS = [0.25, 0.333, 0.5, 0.666, 0.75, 0.9, 1.0,
10 1.1, 1.25, 1.5, 1.75, 2.0, 2.5, 3.0, 4.0, 5.0];
11
12 /**
13 * Returns the area of the intersection of two rectangles.
14 * @param {dictionary} rect1 the first rect
arv (Not doing code reviews) 2014/02/13 23:47:41 Wrong type. Maybe {{x: number, y: number, width: n
raymes 2014/02/17 00:54:03 Done.
15 * @param {dictionary} rect2 the second rect
16 * @return {number} the area of the intersection of the rects
17 */
18 function getIntersectionArea(rect1, rect2) {
19 var xOverlap = Math.max(0,
20 Math.min(rect1.x + rect1.width, rect2.x + rect2.width) -
21 Math.max(rect1.x, rect2.x));
22 var yOverlap = Math.max(0,
23 Math.min(rect1.y + rect1.height, rect2.y + rect2.height) -
24 Math.max(rect1.y, rect2.y));
25 return xOverlap * yOverlap;
26 }
27
28 /**
29 * Return the width of a scrollbar in pixels.
arv (Not doing code reviews) 2014/02/13 23:47:41 Useless comment
raymes 2014/02/17 00:54:03 Done.
30 * @return {number} width of a scrollbar
31 */
32 function getScrollbarWidth() {
33 var parentDiv = document.createElement('div');
34 parentDiv.style.visibility = 'hidden';
35 parentDiv.style.width = '500px';
arv (Not doing code reviews) 2014/02/13 23:47:41 invalidates layout
raymes 2014/02/17 00:54:03 On 2014/02/13 23:47:41, arv wrote: > invalidates l
36 document.body.appendChild(parentDiv);
37 var parentDivWidth = parentDiv.offsetWidth;
arv (Not doing code reviews) 2014/02/13 23:47:41 forces layout
raymes 2014/02/17 00:54:03 On 2014/02/13 23:47:41, arv wrote: > forces layout
38 parentDiv.style.overflow = 'scroll';
arv (Not doing code reviews) 2014/02/13 23:47:41 invalidates layout again. Maybe restructure so th
raymes 2014/02/17 00:54:03 Could you explain a bit more how to improve the pe
39 var childDiv = document.createElement('div');
40 childDiv.style.width = '100%';
41 parentDiv.appendChild(childDiv);
42 var childDivWidth = childDiv.offsetWidth;
43 parentDiv.parentNode.removeChild(parentDiv);
44 return parentDivWidth - childDivWidth;
45 }
46
47 /**
48 * Create a new viewport.
49 * @param {object} window is the page window
arv (Not doing code reviews) 2014/02/13 23:47:41 invalid type
arv (Not doing code reviews) 2014/02/13 23:47:41 Badly formatted jsdoc @param {Object} window The
raymes 2014/02/17 00:54:03 Done.
raymes 2014/02/17 00:54:03 Done.
50 * @param {object} sizer is the element which represents the size of the
51 * document in the viewport
arv (Not doing code reviews) 2014/02/13 23:47:41 indent 4 spaces
raymes 2014/02/17 00:54:03 Done.
52 * @param {function} fitToPageEnabledFunction returns true if fit-to-page is
arv (Not doing code reviews) 2014/02/13 23:47:41 Function or function(T1, T2) : T3
raymes 2014/02/17 00:54:03 Done.
53 * enabled
54 * @param {function} viewportChangedCallback is run when the viewport changes
55 */
56 Viewport = function(window,
57 sizer,
58 fitToPageEnabledFunction,
59 viewportChangedCallback) {
60 this.window_ = window;
61 this.sizer_ = sizer;
62 this.fitToPageEnabledFunction_ = fitToPageEnabledFunction;
63 this.viewportChangedCallback_ = viewportChangedCallback;
64 this.zoom_ = 1;
65 this.documentDimensions_ = {};
66 this.pageDimensions_ = [];
67 this.scrollbarWidth_ = getScrollbarWidth();
68
69 window.addEventListener('scroll', this.updateViewport_.bind(this));
70 };
71
72 /**
73 * @private
74 * Returns true if the document needs scrollbars at the given zoom level.
75 * @param {number} zoom compute whether scrollbars are needed at this zoom
76 * @return {dictionary} with 'x' and 'y' keys which map to bool values
77 * indicating if the horizontal and vertical scrollbars are needed respectively.
78 */
79 Viewport.prototype.documentNeedsScrollbars_ = function(zoom) {
arv (Not doing code reviews) 2014/02/13 23:47:41 Viewport.prototype = { documentNeedsScrollbars_:
raymes 2014/02/17 00:54:03 Done.
80 return {
81 x: this.documentDimensions_.width * zoom > this.window_.innerWidth,
82 y: this.documentDimensions_.height * zoom > this.window_.innerHeight
83 };
84 };
85
86 /**
87 * Returns true if the document needs scrollbars at the current zoom level.
88 * @return {dictionary} with 'x' and 'y' keys which map to bool values
89 * indicating if the horizontal and vertical scrollbars are needed respectively.
90 */
91 Viewport.prototype.documentHasScrollbars = function() {
92 return this.documentNeedsScrollbars_(this.zoom_);
93 };
94
95 /**
96 * @private
97 * Helper function called when the zoomed document size changes.
98 */
99 Viewport.prototype.contentSizeChanged_ = function() {
100 this.sizer_.style.width = this.documentDimensions_.width * this.zoom_ + 'px';
101 this.sizer_.style.height =
102 this.documentDimensions_.height * this.zoom_ + 'px';
103 };
104
105 /**
106 * Sets the zoom of the viewport.
107 * @param {number} newZoom the zoom level to zoom to
108 */
109 Viewport.prototype.setZoom = function(newZoom) {
110 var oldZoom = this.zoom_;
111 this.zoom_ = newZoom;
112 // Record the scroll position (relative to the middle of the window).
113 var currentScrollPos =
arv (Not doing code reviews) 2014/02/13 23:47:41 var currentScrollPos = [ (this.window_.scrollX +
raymes 2014/02/17 00:54:03 Done.
114 [(this.window_.scrollX + this.window_.innerWidth / 2.0) / oldZoom,
arv (Not doing code reviews) 2014/02/13 23:47:41 2.0 -> 2
raymes 2014/02/17 00:54:03 Done.
115 (this.window_.scrollY + this.window_.innerHeight / 2.0) / oldZoom];
116 this.contentSizeChanged_();
117 // Scroll to the scaled scroll position.
118 this.window_.scrollTo(
119 (currentScrollPos[0] * newZoom) - this.window_.innerWidth / 2.0,
arv (Not doing code reviews) 2014/02/13 23:47:41 too many parens
raymes 2014/02/17 00:54:03 Done.
120 (currentScrollPos[1] * newZoom) - this.window_.innerHeight / 2.0);
121 };
122
123 /**
124 * @private
125 * Called when the viewport should be updated.
126 */
127 Viewport.prototype.updateViewport_ = function() {
128 // Shift the toolbar so that it doesn't move when the scrollbars display
129 var needsScrollbars = this.documentHasScrollbars();
130 this.viewportChangedCallback_(this.zoom_,
131 this.window_.pageXOffset,
132 this.window_.pageYOffset,
133 this.scrollbarWidth_,
134 needsScrollbars);
135 };
136
137 /**
138 * @private
139 * Returns a rect representing the current viewport.
140 * @return {dictionary} a rect representing the current viewport.
141 */
142 Viewport.prototype.getCurrentViewportRect_ = function() {
143 return {
144 'x': this.window_.pageXOffset / this.zoom_,
arv (Not doing code reviews) 2014/02/13 23:47:41 No need to quote the property names
raymes 2014/02/17 00:54:03 Done.
145 'y': this.window_.pageYOffset / this.zoom_,
146 'width': this.window_.innerWidth / this.zoom_,
147 'height': this.window_.innerHeight / this.zoom_,
148 };
149 };
150
151 /**
152 * Returns the page with the most pixels in the current viewport.
153 * @return {int} the index of the most visible page.
154 */
155 Viewport.prototype.getMostVisiblePage = function() {
156 // TODO(raymes): Do a binary search here.
157 var mostVisiblePage = {'number': 0, 'area': 0};
158 for (var i = 0; i < this.pageDimensions_.length; i++) {
159 var area = getIntersectionArea(this.pageDimensions_[i],
160 this.getCurrentViewportRect_());
161 if (area > mostVisiblePage.area) {
162 mostVisiblePage.area = area;
163 mostVisiblePage.number = i;
164 }
165 }
166 return mostVisiblePage.number;
167 };
168
169 /**
170 * @private
171 * Compute the zoom level for fit-to-page or fit-to-width. |pageDimensions| is
172 * the dimensions for a given page and if |widthOnly| is true, it indicates that
173 * fit-to-page zoom should be computed rather than fit-to-page.
174 * @param {dictionary} pageDimensions the dimensions of a given page
175 * @param {boolean} widthOnly a bool indicating whether fit-to-page or
176 * fit-to-width should be computed.
177 * @return {number} the zoom to use
178 */
179 Viewport.prototype.computeFittingZoom_ = function(pageDimensions, widthOnly) {
180 // First compute the zoom without scrollbars.
181 var zoomWidth = this.window_.innerWidth / pageDimensions.width;
182 var zoom;
183 if (widthOnly) {
184 zoom = zoomWidth;
185 } else {
186 var zoomHeight = this.window_.innerHeight / pageDimensions.height;
187 zoom = Math.min(zoomWidth, zoomHeight);
188 }
189 // Check if there needs to be any scrollbars.
190 var needsScrollbars = this.documentNeedsScrollbars_(zoom);
191
192 // If the document fits, just return the zoom.
193 if (!needsScrollbars.x && !needsScrollbars.y)
194 return zoom;
195
196 var zoomedDimensions = {
197 width: this.documentDimensions_.width * zoom,
198 height: this.documentDimensions_.height * zoom
199 };
200
201 // Check if adding a scrollbar will result in needing the other scrollbar.
202 var scrollbarWidth = this.scrollbarWidth_;
203 if (needsScrollbars.x &&
204 zoomedDimensions.height > this.window_.innerHeight - scrollbarWidth) {
205 needsScrollbars.y = true;
206 }
207 if (needsScrollbars.y &&
208 zoomedDimensions.width > this.window_.innerWidth - scrollbarWidth) {
209 needsScrollbars.x = true;
210 }
211
212 // Compute available window space.
213 var windowWithScrollbars = {
214 width: this.window_.innerWidth,
215 height: this.window_.innerHeight
216 };
217 if (needsScrollbars.x)
218 windowWithScrollbars.height -= scrollbarWidth;
219 if (needsScrollbars.y)
220 windowWithScrollbars.width -= scrollbarWidth;
221
222 // Recompute the zoom.
223 zoomWidth = windowWithScrollbars.width / pageDimensions.width;
224 if (widthOnly) {
225 zoom = zoomWidth;
226 } else {
227 var zoomHeight = windowWithScrollbars.height / pageDimensions.height;
228 zoom = Math.min(zoomWidth, zoomHeight);
229 }
230 return zoom;
231 };
232
233 /**
234 * Zoom the viewport so that the page-width consumes the entire viewport.
235 */
236 Viewport.prototype.fitToWidth = function() {
237 var page = this.getMostVisiblePage();
238 this.setZoom(this.computeFittingZoom_(this.pageDimensions_[page], true));
239 this.window_.scrollTo(this.pageDimensions_[page].x * this.zoom_,
240 this.window_.scrollY);
241 this.updateViewport_();
242 };
243
244 /**
245 * Zoom the viewport so that a page consumes the entire viewport. Also scrolls
246 * to the top of the most visible page.
247 */
248 Viewport.prototype.fitToPage = function() {
249 var page = this.getMostVisiblePage();
250 this.setZoom(this.computeFittingZoom_(this.pageDimensions_[page], false));
251 this.window_.scrollTo(this.pageDimensions_[page].x * this.zoom_,
252 this.pageDimensions_[page].y * this.zoom_);
253 this.updateViewport_();
254 };
255
256 /**
257 * Zoom out to the next predefined zoom level.
258 */
259 Viewport.prototype.zoomOut = function() {
260 var nextZoom = ZOOM_FACTORS[0];
261 for (var i = 0; i < ZOOM_FACTORS.length; i++) {
262 if (ZOOM_FACTORS[i] < this.zoom_)
263 nextZoom = ZOOM_FACTORS[i];
264 }
265 this.setZoom(nextZoom);
266 this.updateViewport_();
267 };
268
269 /**
270 * Zoom in to the next predefined zoom level.
271 */
272 Viewport.prototype.zoomIn = function() {
273 var nextZoom = ZOOM_FACTORS[ZOOM_FACTORS.length - 1];
274 for (var i = ZOOM_FACTORS.length - 1; i >= 0; i--) {
275 if (ZOOM_FACTORS[i] > this.zoom_)
276 nextZoom = ZOOM_FACTORS[i];
277 }
278 this.setZoom(nextZoom);
279 this.updateViewport_();
280 };
281
282 /**
283 * Go to the given page index.
284 * @param {number} page the index of the page to go to
285 */
286 Viewport.prototype.goToPage = function(page) {
287 if (page < 0)
288 page = 0;
289 var dimensions = this.pageDimensions_[page];
290 this.window_.scrollTo(dimensions.x * this.zoom_, dimensions.y * this.zoom_);
291 };
292
293 /**
294 * Set the dimensions of the document.
295 * @param {dictionary} documentDimensions the dimensions of the document
296 */
297 Viewport.prototype.setDocumentDimensions = function(documentDimensions) {
298 this.documentDimensions_ = documentDimensions;
299 this.pageDimensions_ = this.documentDimensions_.pageDimensions;
300 this.contentSizeChanged_();
301 this.updateViewport_();
302 };
OLDNEW
« chrome/browser/resources/pdf/pdf.js ('K') | « chrome/browser/resources/pdf/pdf.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698