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
3 // found in the LICENSE file.
5 function MockWindow(width, height, sizer) {
6 this.innerWidth = width;
7 this.innerHeight = height;
8 this.addEventListener = function(e, f) {
10 this.scrollCallback = f;
12 this.resizeCallback = f;
14 this.scrollTo = function(x, y) {
16 x = Math.min(x, parseInt(sizer.style.width) - width);
17 y = Math.min(y, parseInt(sizer.style.height) - height);
19 this.pageXOffset = Math.max(0, x);
20 this.pageYOffset = Math.max(0, y);
21 this.scrollCallback();
24 sizer.resizeCallback_ = function() {
25 this.scrollTo(this.pageXOffset, this.pageYOffset);
30 this.scrollCallback = null;
31 this.resizeCallback = null;
34 function MockSizer() {
39 get height() { return this.height_; },
41 this.height_ = height;
42 if (sizer.resizeCallback_)
43 sizer.resizeCallback_();
45 get width() { return this.width_; },
48 if (sizer.resizeCallback_)
49 sizer.resizeCallback_();
54 function MockViewportChangedCallback() {
55 this.wasCalled = false;
56 this.callback = function() {
57 this.wasCalled = true;
59 this.reset = function() {
60 this.wasCalled = false;
64 function MockDocumentDimensions(width, height) {
65 this.width = width || 0;
66 this.height = height ? height : 0;
67 this.pageDimensions = [];
68 this.addPage = function(w, h) {
70 if (this.pageDimensions.length != 0) {
71 y = this.pageDimensions[this.pageDimensions.length - 1].y +
72 this.pageDimensions[this.pageDimensions.length - 1].height;
74 this.width = Math.max(this.width, w);
76 this.pageDimensions.push({
83 this.reset = function() {
86 this.pageDimensions = [];
91 function testDocumentNeedsScrollbars() {
92 var viewport = new Viewport(new MockWindow(100, 100), new MockSizer(),
93 function() {}, function() {}, function() {}, 0);
96 viewport.setDocumentDimensions(new MockDocumentDimensions(90, 90));
97 scrollbars = viewport.documentNeedsScrollbars_(1);
98 chrome.test.assertFalse(scrollbars.vertical);
99 chrome.test.assertFalse(scrollbars.horizontal);
101 viewport.setDocumentDimensions(new MockDocumentDimensions(100, 100));
102 scrollbars = viewport.documentNeedsScrollbars_(1);
103 chrome.test.assertFalse(scrollbars.vertical);
104 chrome.test.assertFalse(scrollbars.horizontal);
106 viewport.setDocumentDimensions(new MockDocumentDimensions(110, 110));
107 scrollbars = viewport.documentNeedsScrollbars_(1);
108 chrome.test.assertTrue(scrollbars.vertical);
109 chrome.test.assertTrue(scrollbars.horizontal);
111 viewport.setDocumentDimensions(new MockDocumentDimensions(100, 101));
112 scrollbars = viewport.documentNeedsScrollbars_(1);
113 chrome.test.assertTrue(scrollbars.vertical);
114 chrome.test.assertFalse(scrollbars.horizontal);
116 viewport.setDocumentDimensions(new MockDocumentDimensions(40, 51));
117 scrollbars = viewport.documentNeedsScrollbars_(2);
118 chrome.test.assertTrue(scrollbars.vertical);
119 chrome.test.assertFalse(scrollbars.horizontal);
121 viewport.setDocumentDimensions(new MockDocumentDimensions(101, 202));
122 scrollbars = viewport.documentNeedsScrollbars_(0.5);
123 chrome.test.assertTrue(scrollbars.vertical);
124 chrome.test.assertFalse(scrollbars.horizontal);
125 chrome.test.succeed();
128 function testSetZoom() {
129 var mockSizer = new MockSizer();
130 var mockWindow = new MockWindow(100, 100, mockSizer);
131 var mockCallback = new MockViewportChangedCallback();
132 var viewport = new Viewport(mockWindow, mockSizer, mockCallback.callback,
133 function() {}, function() {}, 0);
135 // Test setting the zoom without the document dimensions set. The sizer
136 // shouldn't change size.
137 mockCallback.reset();
138 viewport.setZoom(0.5);
139 chrome.test.assertEq(0.5, viewport.zoom);
140 chrome.test.assertTrue(mockCallback.wasCalled);
141 chrome.test.assertEq('0px', mockSizer.style.width);
142 chrome.test.assertEq('0px', mockSizer.style.height);
143 chrome.test.assertEq(0, mockWindow.pageXOffset);
144 chrome.test.assertEq(0, mockWindow.pageYOffset);
147 viewport.setDocumentDimensions(new MockDocumentDimensions(200, 200));
150 mockCallback.reset();
151 viewport.setZoom(0.5);
152 chrome.test.assertEq(0.5, viewport.zoom);
153 chrome.test.assertTrue(mockCallback.wasCalled);
154 chrome.test.assertEq('100px', mockSizer.style.width);
155 chrome.test.assertEq('100px', mockSizer.style.height);
158 mockCallback.reset();
160 chrome.test.assertEq(2, viewport.zoom);
161 chrome.test.assertTrue(mockCallback.wasCalled);
162 chrome.test.assertEq('400px', mockSizer.style.width);
163 chrome.test.assertEq('400px', mockSizer.style.height);
165 // Test that the scroll position scales correctly. It scales relative to the
166 // top-left of the page.
168 mockWindow.pageXOffset = 50;
169 mockWindow.pageYOffset = 50;
171 chrome.test.assertEq('400px', mockSizer.style.width);
172 chrome.test.assertEq('400px', mockSizer.style.height);
173 chrome.test.assertEq(100, mockWindow.pageXOffset);
174 chrome.test.assertEq(100, mockWindow.pageYOffset);
175 mockWindow.scrollTo(250, 250);
177 chrome.test.assertEq('200px', mockSizer.style.width);
178 chrome.test.assertEq('200px', mockSizer.style.height);
179 chrome.test.assertEq(100, mockWindow.pageXOffset);
180 chrome.test.assertEq(100, mockWindow.pageYOffset);
181 chrome.test.succeed();
184 function testGetMostVisiblePage() {
185 var mockWindow = new MockWindow(100, 100);
186 var viewport = new Viewport(mockWindow, new MockSizer(), function() {},
187 function() {}, function() {}, 0);
189 var documentDimensions = new MockDocumentDimensions(100, 100);
190 documentDimensions.addPage(100, 100);
191 documentDimensions.addPage(150, 100);
192 documentDimensions.addPage(100, 200);
193 viewport.setDocumentDimensions(documentDimensions);
196 // Scrolled to the start of the first page.
197 mockWindow.scrollTo(0, 0);
198 chrome.test.assertEq(0, viewport.getMostVisiblePage());
200 // Scrolled to the start of the second page.
201 mockWindow.scrollTo(0, 100);
202 chrome.test.assertEq(1, viewport.getMostVisiblePage());
204 // Scrolled half way through the first page.
205 mockWindow.scrollTo(0, 50);
206 chrome.test.assertEq(0, viewport.getMostVisiblePage());
208 // Scrolled just over half way through the first page.
209 mockWindow.scrollTo(0, 51);
210 chrome.test.assertEq(1, viewport.getMostVisiblePage());
212 // Scrolled most of the way through the second page.
213 mockWindow.scrollTo(0, 180);
214 chrome.test.assertEq(2, viewport.getMostVisiblePage());
216 // Scrolled just over half way through the first page with 2x zoom.
218 mockWindow.scrollTo(0, 151);
219 chrome.test.assertEq(1, viewport.getMostVisiblePage());
220 chrome.test.succeed();
223 function testFitToWidth() {
224 var mockWindow = new MockWindow(100, 100);
225 var mockSizer = new MockSizer();
226 var mockCallback = new MockViewportChangedCallback();
227 var viewport = new Viewport(mockWindow, mockSizer, mockCallback.callback,
228 function() {}, function() {}, 0);
229 var documentDimensions = new MockDocumentDimensions();
231 // Test with a document width which matches the window width.
232 documentDimensions.addPage(100, 100);
233 viewport.setDocumentDimensions(documentDimensions);
234 viewport.setZoom(0.1);
235 mockCallback.reset();
236 viewport.fitToWidth();
237 chrome.test.assertTrue(mockCallback.wasCalled);
238 chrome.test.assertEq('100px', mockSizer.style.width);
239 chrome.test.assertEq(1, viewport.zoom);
241 // Test with a document width which is twice the size of the window width.
242 documentDimensions.reset();
243 documentDimensions.addPage(200, 100);
244 viewport.setDocumentDimensions(documentDimensions);
245 mockCallback.reset();
246 viewport.fitToWidth();
247 chrome.test.assertTrue(mockCallback.wasCalled);
248 chrome.test.assertEq('100px', mockSizer.style.width);
249 chrome.test.assertEq(0.5, viewport.zoom);
251 // Test with a document width which is half the size of the window width.
252 documentDimensions.reset();
253 documentDimensions.addPage(50, 100);
254 viewport.setDocumentDimensions(documentDimensions);
255 mockCallback.reset();
256 viewport.fitToWidth();
257 chrome.test.assertTrue(mockCallback.wasCalled);
258 chrome.test.assertEq('100px', mockSizer.style.width);
259 chrome.test.assertEq(2, viewport.zoom);
261 // Test that the scroll position stays the same relative to the page after
262 // fit to page is called.
263 documentDimensions.reset();
264 documentDimensions.addPage(50, 400);
265 viewport.setDocumentDimensions(documentDimensions);
267 mockWindow.scrollTo(0, 100);
268 mockCallback.reset();
269 viewport.fitToWidth();
270 chrome.test.assertTrue(mockCallback.wasCalled);
271 chrome.test.assertEq(2, viewport.zoom);
272 chrome.test.assertEq(0, viewport.position.x);
273 chrome.test.assertEq(200, viewport.position.y);
275 // Test fitting works with scrollbars. The page will need to be zoomed to
276 // fit to width, which will cause the page height to span outside of the
277 // viewport, triggering 15px scrollbars to be shown.
278 viewport = new Viewport(mockWindow, mockSizer, mockCallback.callback,
279 function() {}, function() {}, 15);
280 documentDimensions.reset();
281 documentDimensions.addPage(50, 100);
282 viewport.setDocumentDimensions(documentDimensions);
283 mockCallback.reset();
284 viewport.fitToWidth();
285 chrome.test.assertTrue(mockCallback.wasCalled);
286 chrome.test.assertEq('85px', mockSizer.style.width);
287 chrome.test.assertEq(1.7, viewport.zoom);
288 chrome.test.succeed();
291 function testFitToPage() {
292 var mockWindow = new MockWindow(100, 100);
293 var mockSizer = new MockSizer();
294 var mockCallback = new MockViewportChangedCallback();
295 var viewport = new Viewport(mockWindow, mockSizer, mockCallback.callback,
296 function() {}, function() {}, 0);
297 var documentDimensions = new MockDocumentDimensions();
299 // Test with a page size which matches the window size.
300 documentDimensions.addPage(100, 100);
301 viewport.setDocumentDimensions(documentDimensions);
302 viewport.setZoom(0.1);
303 mockCallback.reset();
304 viewport.fitToPage();
305 chrome.test.assertTrue(mockCallback.wasCalled);
306 chrome.test.assertEq('100px', mockSizer.style.width);
307 chrome.test.assertEq('100px', mockSizer.style.height);
308 chrome.test.assertEq(1, viewport.zoom);
310 // Test with a page size whose width is larger than its height.
311 documentDimensions.reset();
312 documentDimensions.addPage(200, 100);
313 viewport.setDocumentDimensions(documentDimensions);
314 mockCallback.reset();
315 viewport.fitToPage();
316 chrome.test.assertTrue(mockCallback.wasCalled);
317 chrome.test.assertEq('100px', mockSizer.style.width);
318 chrome.test.assertEq('50px', mockSizer.style.height);
319 chrome.test.assertEq(0.5, viewport.zoom);
321 // Test with a page size whose height is larger than its width.
322 documentDimensions.reset();
323 documentDimensions.addPage(100, 200);
324 viewport.setDocumentDimensions(documentDimensions);
325 mockCallback.reset();
326 viewport.fitToPage();
327 chrome.test.assertTrue(mockCallback.wasCalled);
328 chrome.test.assertEq('50px', mockSizer.style.width);
329 chrome.test.assertEq('100px', mockSizer.style.height);
330 chrome.test.assertEq(0.5, viewport.zoom);
332 // Test that when there are multiple pages the height of the most visible
333 // page and the width of the widest page are sized to.
334 documentDimensions.reset();
335 documentDimensions.addPage(100, 100);
336 documentDimensions.addPage(200, 400);
337 viewport.setDocumentDimensions(documentDimensions);
339 mockWindow.scrollTo(0, 0);
340 mockCallback.reset();
341 viewport.fitToPage();
342 chrome.test.assertTrue(mockCallback.wasCalled);
343 chrome.test.assertEq('100px', mockSizer.style.width);
344 chrome.test.assertEq('250px', mockSizer.style.height);
345 chrome.test.assertEq(0.5, viewport.zoom);
347 mockWindow.scrollTo(0, 100);
348 mockCallback.reset();
349 viewport.fitToPage();
350 chrome.test.assertTrue(mockCallback.wasCalled);
351 chrome.test.assertEq('50px', mockSizer.style.width);
352 chrome.test.assertEq('125px', mockSizer.style.height);
353 chrome.test.assertEq(0.25, viewport.zoom);
355 // Test that the top of the most visible page is scrolled to.
356 documentDimensions.reset();
357 documentDimensions.addPage(200, 200);
358 documentDimensions.addPage(100, 400);
359 viewport.setDocumentDimensions(documentDimensions);
361 mockWindow.scrollTo(0, 0);
362 viewport.fitToPage();
363 chrome.test.assertEq(0.5, viewport.zoom);
364 chrome.test.assertEq(0, viewport.position.x);
365 chrome.test.assertEq(0, viewport.position.y);
367 mockWindow.scrollTo(0, 175);
368 viewport.fitToPage();
369 chrome.test.assertEq(0.25, viewport.zoom);
370 chrome.test.assertEq(0, viewport.position.x);
371 chrome.test.assertEq(50, viewport.position.y);
372 chrome.test.succeed();
375 function testGoToPage() {
376 var mockWindow = new MockWindow(100, 100);
377 var mockSizer = new MockSizer();
378 var mockCallback = new MockViewportChangedCallback();
379 var viewport = new Viewport(mockWindow, mockSizer, mockCallback.callback,
380 function() {}, function() {}, 0);
381 var documentDimensions = new MockDocumentDimensions();
383 documentDimensions.addPage(100, 100);
384 documentDimensions.addPage(200, 200);
385 documentDimensions.addPage(100, 400);
386 viewport.setDocumentDimensions(documentDimensions);
389 mockCallback.reset();
390 viewport.goToPage(0);
391 chrome.test.assertTrue(mockCallback.wasCalled);
392 chrome.test.assertEq(0, viewport.position.x);
393 chrome.test.assertEq(0, viewport.position.y);
395 mockCallback.reset();
396 viewport.goToPage(1);
397 chrome.test.assertTrue(mockCallback.wasCalled);
398 chrome.test.assertEq(0, viewport.position.x);
399 chrome.test.assertEq(100, viewport.position.y);
401 mockCallback.reset();
402 viewport.goToPage(2);
403 chrome.test.assertTrue(mockCallback.wasCalled);
404 chrome.test.assertEq(0, viewport.position.x);
405 chrome.test.assertEq(300, viewport.position.y);
407 viewport.setZoom(0.5);
408 mockCallback.reset();
409 viewport.goToPage(2);
410 chrome.test.assertTrue(mockCallback.wasCalled);
411 chrome.test.assertEq(0, viewport.position.x);
412 chrome.test.assertEq(150, viewport.position.y);
413 chrome.test.succeed();
416 function testGetPageScreenRect() {
417 var mockWindow = new MockWindow(100, 100);
418 var mockSizer = new MockSizer();
419 var mockCallback = new MockViewportChangedCallback();
420 var viewport = new Viewport(mockWindow, mockSizer, mockCallback.callback,
421 function() {}, function() {}, 0);
422 var documentDimensions = new MockDocumentDimensions();
423 documentDimensions.addPage(100, 100);
424 documentDimensions.addPage(200, 200);
425 viewport.setDocumentDimensions(documentDimensions);
428 // Test that the rect of the first page is positioned/sized correctly.
429 mockWindow.scrollTo(0, 0);
430 var rect1 = viewport.getPageScreenRect(0);
431 chrome.test.assertEq(Viewport.PAGE_SHADOW.left + 100 / 2, rect1.x);
432 chrome.test.assertEq(Viewport.PAGE_SHADOW.top, rect1.y);
433 chrome.test.assertEq(100 - Viewport.PAGE_SHADOW.right -
434 Viewport.PAGE_SHADOW.left, rect1.width);
435 chrome.test.assertEq(100 - Viewport.PAGE_SHADOW.bottom -
436 Viewport.PAGE_SHADOW.top, rect1.height);
438 // Check that when we scroll, the rect of the first page is updated
440 mockWindow.scrollTo(100, 10);
441 var rect2 = viewport.getPageScreenRect(0);
442 chrome.test.assertEq(rect1.x - 100, rect2.x);
443 chrome.test.assertEq(rect1.y - 10, rect2.y);
444 chrome.test.assertEq(rect1.width, rect2.width);
445 chrome.test.assertEq(rect1.height, rect2.height);
447 // Check the rect of the second page is positioned/sized correctly.
448 mockWindow.scrollTo(0, 100);
449 rect1 = viewport.getPageScreenRect(1);
450 chrome.test.assertEq(Viewport.PAGE_SHADOW.left, rect1.x);
451 chrome.test.assertEq(Viewport.PAGE_SHADOW.top, rect1.y);
452 chrome.test.assertEq(200 - Viewport.PAGE_SHADOW.right -
453 Viewport.PAGE_SHADOW.left, rect1.width);
454 chrome.test.assertEq(200 - Viewport.PAGE_SHADOW.bottom -
455 Viewport.PAGE_SHADOW.top, rect1.height);
456 chrome.test.succeed();
459 function testBeforeZoomAfterZoom() {
460 var mockWindow = new MockWindow(100, 100);
461 var mockSizer = new MockSizer();
463 var afterZoomCalled = false;
464 var beforeZoomCalled = false;
465 var afterZoom = function() {
466 afterZoomCalled = true;
467 chrome.test.assertTrue(beforeZoomCalled);
468 chrome.test.assertEq(0.5, viewport.zoom);
470 var beforeZoom = function() {
471 beforeZoomCalled = true;
472 chrome.test.assertFalse(afterZoomCalled);
473 chrome.test.assertEq(1, viewport.zoom);
475 viewport = new Viewport(mockWindow, mockSizer, function() {},
476 beforeZoom, afterZoom, 0);
477 viewport.setZoom(0.5);
478 chrome.test.succeed();
482 chrome.test.runTests(tests);