Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / web / tests / VisualViewportTest.cpp
blob266c22839a45db6100f2e405e66b0101bdbf8260
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 #include "config.h"
7 #include "core/frame/VisualViewport.h"
9 #include "core/dom/Document.h"
10 #include "core/frame/FrameHost.h"
11 #include "core/frame/LocalFrame.h"
12 #include "core/html/HTMLBodyElement.h"
13 #include "core/html/HTMLElement.h"
14 #include "core/input/EventHandler.h"
15 #include "core/layout/LayoutObject.h"
16 #include "core/layout/LayoutView.h"
17 #include "core/layout/compositing/DeprecatedPaintLayerCompositor.h"
18 #include "core/page/Page.h"
19 #include "platform/PlatformGestureEvent.h"
20 #include "platform/geometry/DoublePoint.h"
21 #include "platform/geometry/DoubleRect.h"
22 #include "platform/testing/URLTestHelpers.h"
23 #include "public/platform/Platform.h"
24 #include "public/platform/WebLayerTreeView.h"
25 #include "public/platform/WebUnitTestSupport.h"
26 #include "public/web/WebContextMenuData.h"
27 #include "public/web/WebDocument.h"
28 #include "public/web/WebFrameClient.h"
29 #include "public/web/WebInputEvent.h"
30 #include "public/web/WebScriptSource.h"
31 #include "public/web/WebSettings.h"
32 #include "public/web/WebViewClient.h"
33 #include "web/WebLocalFrameImpl.h"
34 #include "web/tests/FrameTestHelpers.h"
35 #include <gmock/gmock.h>
36 #include <gtest/gtest.h>
38 #include <string>
40 #define ASSERT_POINT_EQ(expected, actual) \
41 do { \
42 ASSERT_EQ((expected).x(), (actual).x()); \
43 ASSERT_EQ((expected).y(), (actual).y()); \
44 } while (false)
46 #define EXPECT_POINT_EQ(expected, actual) \
47 do { \
48 EXPECT_EQ((expected).x(), (actual).x()); \
49 EXPECT_EQ((expected).y(), (actual).y()); \
50 } while (false)
52 #define EXPECT_FLOAT_POINT_EQ(expected, actual) \
53 do { \
54 EXPECT_FLOAT_EQ((expected).x(), (actual).x()); \
55 EXPECT_FLOAT_EQ((expected).y(), (actual).y()); \
56 } while (false)
58 #define EXPECT_POINT_EQ(expected, actual) \
59 do { \
60 EXPECT_EQ((expected).x(), (actual).x()); \
61 EXPECT_EQ((expected).y(), (actual).y()); \
62 } while (false)
64 #define EXPECT_SIZE_EQ(expected, actual) \
65 do { \
66 EXPECT_EQ((expected).width(), (actual).width()); \
67 EXPECT_EQ((expected).height(), (actual).height()); \
68 } while (false)
70 #define EXPECT_FLOAT_SIZE_EQ(expected, actual) \
71 do { \
72 EXPECT_FLOAT_EQ((expected).width(), (actual).width()); \
73 EXPECT_FLOAT_EQ((expected).height(), (actual).height()); \
74 } while (false)
76 #define EXPECT_FLOAT_RECT_EQ(expected, actual) \
77 do { \
78 EXPECT_FLOAT_EQ((expected).x(), (actual).x()); \
79 EXPECT_FLOAT_EQ((expected).y(), (actual).y()); \
80 EXPECT_FLOAT_EQ((expected).width(), (actual).width()); \
81 EXPECT_FLOAT_EQ((expected).height(), (actual).height()); \
82 } while (false)
85 using namespace blink;
87 using ::testing::_;
88 using ::testing::PrintToString;
89 using ::testing::Mock;
91 namespace blink {
92 ::std::ostream& operator<<(::std::ostream& os, const WebContextMenuData& data)
94 return os << "Context menu location: ["
95 << data.mousePosition.x << ", " << data.mousePosition.y << "]";
100 namespace {
102 class VisualViewportTest
103 : public testing::Test
104 , public FrameTestHelpers::SettingOverrider {
105 public:
106 VisualViewportTest()
107 : m_baseURL("http://www.test.com/")
108 , m_helper(this)
112 void overrideSettings(WebSettings *settings) override
116 void initializeWithDesktopSettings(void (*overrideSettingsFunc)(WebSettings*) = 0)
118 if (!overrideSettingsFunc)
119 overrideSettingsFunc = &configureSettings;
120 m_helper.initialize(true, 0, &m_mockWebViewClient, overrideSettingsFunc);
121 webViewImpl()->setDefaultPageScaleLimits(1, 4);
124 void initializeWithAndroidSettings(void (*overrideSettingsFunc)(WebSettings*) = 0)
126 if (!overrideSettingsFunc)
127 overrideSettingsFunc = &configureAndroidSettings;
128 m_helper.initialize(true, 0, &m_mockWebViewClient, overrideSettingsFunc);
129 webViewImpl()->setDefaultPageScaleLimits(0.25f, 5);
132 ~VisualViewportTest() override
134 Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
137 void navigateTo(const std::string& url)
139 FrameTestHelpers::loadFrame(webViewImpl()->mainFrame(), url);
142 void forceFullCompositingUpdate()
144 webViewImpl()->layout();
147 void registerMockedHttpURLLoad(const std::string& fileName)
149 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str()));
152 WebLayer* getRootScrollLayer()
154 DeprecatedPaintLayerCompositor* compositor = frame()->contentLayoutObject()->compositor();
155 ASSERT(compositor);
156 ASSERT(compositor->scrollLayer());
158 WebLayer* webScrollLayer = compositor->scrollLayer()->platformLayer();
159 return webScrollLayer;
162 WebViewImpl* webViewImpl() const { return m_helper.webViewImpl(); }
163 LocalFrame* frame() const { return m_helper.webViewImpl()->mainFrameImpl()->frame(); }
165 static void configureSettings(WebSettings* settings)
167 settings->setJavaScriptEnabled(true);
168 settings->setAcceleratedCompositingEnabled(true);
169 settings->setPreferCompositingToLCDTextEnabled(true);
172 static void configureAndroidSettings(WebSettings* settings)
174 configureSettings(settings);
175 settings->setViewportEnabled(true);
176 settings->setViewportMetaEnabled(true);
177 settings->setShrinksViewportContentToFit(true);
178 settings->setMainFrameResizesAreOrientationChanges(true);
181 protected:
182 std::string m_baseURL;
183 FrameTestHelpers::TestWebViewClient m_mockWebViewClient;
185 private:
186 FrameTestHelpers::WebViewHelper m_helper;
188 // To prevent platform differneces in content layout, use mock
189 // scrollbars. This is especially needed for Mac, where the presence
190 // or absence of a mouse will change frame sizes because of different
191 // scrollbar themes.
192 FrameTestHelpers::UseMockScrollbarSettings m_useMockScrollbars;
195 typedef void (*SettingOverrideFunction)(WebSettings*);
197 static void DefaultSettingOverride(WebSettings *)
201 class ParameterizedVisualViewportTest
202 : public VisualViewportTest
203 , public testing::WithParamInterface<SettingOverrideFunction> {
204 public:
205 void overrideSettings(WebSettings *settings) override
207 GetParam()(settings);
211 static void RootLayerScrollsSettingOverride(WebSettings *settings)
213 settings->setRootLayerScrolls(true);
215 INSTANTIATE_TEST_CASE_P(All, ParameterizedVisualViewportTest, ::testing::Values(
216 DefaultSettingOverride,
217 RootLayerScrollsSettingOverride));
219 // Test that resizing the VisualViewport works as expected and that resizing the
220 // WebView resizes the VisualViewport.
221 TEST_P(ParameterizedVisualViewportTest, TestResize)
223 initializeWithDesktopSettings();
224 webViewImpl()->resize(IntSize(320, 240));
226 navigateTo("about:blank");
227 forceFullCompositingUpdate();
229 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
231 IntSize webViewSize = webViewImpl()->size();
233 // Make sure the visual viewport was initialized.
234 EXPECT_SIZE_EQ(webViewSize, visualViewport.size());
236 // Resizing the WebView should change the VisualViewport.
237 webViewSize = IntSize(640, 480);
238 webViewImpl()->resize(webViewSize);
239 EXPECT_SIZE_EQ(webViewSize, IntSize(webViewImpl()->size()));
240 EXPECT_SIZE_EQ(webViewSize, visualViewport.size());
242 // Resizing the visual viewport shouldn't affect the WebView.
243 IntSize newViewportSize = IntSize(320, 200);
244 visualViewport.setSize(newViewportSize);
245 EXPECT_SIZE_EQ(webViewSize, IntSize(webViewImpl()->size()));
246 EXPECT_SIZE_EQ(newViewportSize, visualViewport.size());
249 // This tests that shrinking the WebView while the page is fully scrolled
250 // doesn't move the viewport up/left, it should keep the visible viewport
251 // unchanged from the user's perspective (shrinking the FrameView will clamp
252 // the VisualViewport so we need to counter scroll the FrameView to make it
253 // appear to stay still). This caused bugs like crbug.com/453859.
254 TEST_P(ParameterizedVisualViewportTest, TestResizeAtFullyScrolledPreservesViewportLocation)
256 initializeWithDesktopSettings();
257 webViewImpl()->resize(IntSize(800, 600));
259 registerMockedHttpURLLoad("content-width-1000.html");
260 navigateTo(m_baseURL + "content-width-1000.html");
262 FrameView& frameView = *webViewImpl()->mainFrameImpl()->frameView();
263 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
265 visualViewport.setScale(2);
267 // Fully scroll both viewports.
268 frameView.layoutViewportScrollableArea()->setScrollPosition(DoublePoint(10000, 10000), ProgrammaticScroll);
269 visualViewport.move(FloatSize(10000, 10000));
271 // Sanity check.
272 ASSERT_POINT_EQ(FloatPoint(400, 300), visualViewport.location());
273 ASSERT_POINT_EQ(DoublePoint(200, 1400), frameView.layoutViewportScrollableArea()->scrollPositionDouble());
275 DoublePoint expectedLocation = frameView.scrollableArea()->visibleContentRectDouble().location();
277 // Shrink the WebView, this should cause both viewports to shrink and
278 // WebView should do whatever it needs to do to preserve the visible
279 // location.
280 webViewImpl()->resize(IntSize(700, 550));
282 EXPECT_POINT_EQ(expectedLocation, frameView.scrollableArea()->visibleContentRectDouble().location());
284 webViewImpl()->resize(IntSize(800, 600));
286 EXPECT_POINT_EQ(expectedLocation, frameView.scrollableArea()->visibleContentRectDouble().location());
290 // Test that the VisualViewport works as expected in case of a scaled
291 // and scrolled viewport - scroll down.
292 TEST_P(ParameterizedVisualViewportTest, TestResizeAfterVerticalScroll)
295 200 200
296 | | | |
297 | | | |
298 | | 800 | | 800
299 |-------------------| | |
300 | | | |
301 | | | |
302 | | | |
303 | | --------> | |
304 | 300 | | |
305 | | | |
306 | 400 | | |
307 | | |-------------------|
308 | | | 75 |
309 | 50 | | 50 100|
310 o----- | o---- |
311 | | | | | 25 |
312 | |100 | |-------------------|
313 | | | | |
314 | | | | |
315 -------------------- --------------------
319 // Disable the test on Mac OSX until futher investigation.
320 // Local build on Mac is OK but thes bot fails.
321 #if OS(MACOSX)
322 return;
323 #endif
325 initializeWithAndroidSettings();
327 registerMockedHttpURLLoad("200-by-800-viewport.html");
328 navigateTo(m_baseURL + "200-by-800-viewport.html");
330 webViewImpl()->resize(IntSize(100, 200));
332 // Scroll main frame to the bottom of the document
333 webViewImpl()->mainFrame()->setScrollOffset(WebSize(0, 400));
334 EXPECT_POINT_EQ(IntPoint(0, 400), frame()->view()->layoutViewportScrollableArea()->scrollPosition());
336 webViewImpl()->setPageScaleFactor(2.0);
338 // Scroll visual viewport to the bottom of the main frame
339 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
340 visualViewport.setLocation(FloatPoint(0, 300));
341 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 300), visualViewport.location());
343 // Verify the initial size of the visual viewport in the CSS pixels
344 EXPECT_FLOAT_SIZE_EQ(FloatSize(50, 100), visualViewport.visibleRect().size());
346 // Perform the resizing
347 webViewImpl()->resize(IntSize(200, 100));
349 // After resizing the scale changes 2.0 -> 4.0
350 EXPECT_FLOAT_SIZE_EQ(FloatSize(50, 25), visualViewport.visibleRect().size());
352 EXPECT_POINT_EQ(IntPoint(0, 625), frame()->view()->layoutViewportScrollableArea()->scrollPosition());
353 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 75), visualViewport.location());
356 // Test that the VisualViewport works as expected in case if a scaled
357 // and scrolled viewport - scroll right.
358 TEST_P(ParameterizedVisualViewportTest, TestResizeAfterHorizontalScroll)
361 200 200
362 ---------------o----- ---------------o-----
363 | | | | 25| |
364 | | | | -----|
365 | 100| | |100 50 |
366 | | | | |
367 | ---- | |-------------------|
368 | | | |
369 | | | |
370 | | | |
371 | | | |
372 | | | |
373 |400 | ---------> | |
374 | | | |
375 | | | |
376 | | | |
377 | | | |
378 | | | |
379 | | | |
380 | | | |
381 | | | |
382 |-------------------| | |
383 | | | |
387 // Disable the test on Mac OSX until futher investigation.
388 // Local build on Mac is OK but thes bot fails.
389 #if OS(MACOSX)
390 return;
391 #endif
393 initializeWithAndroidSettings();
395 registerMockedHttpURLLoad("200-by-800-viewport.html");
396 navigateTo(m_baseURL + "200-by-800-viewport.html");
398 webViewImpl()->resize(IntSize(100, 200));
400 // Outer viewport takes the whole width of the document.
402 webViewImpl()->setPageScaleFactor(2.0);
404 // Scroll visual viewport to the right edge of the frame
405 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
406 visualViewport.setLocation(FloatPoint(150, 0));
407 EXPECT_FLOAT_POINT_EQ(FloatPoint(150, 0), visualViewport.location());
409 // Verify the initial size of the visual viewport in the CSS pixels
410 EXPECT_FLOAT_SIZE_EQ(FloatSize(50, 100), visualViewport.visibleRect().size());
412 webViewImpl()->resize(IntSize(200, 100));
414 // After resizing the scale changes 2.0 -> 4.0
415 EXPECT_FLOAT_SIZE_EQ(FloatSize(50, 25), visualViewport.visibleRect().size());
417 EXPECT_POINT_EQ(IntPoint(0, 0), frame()->view()->scrollPosition());
418 EXPECT_FLOAT_POINT_EQ(FloatPoint(150, 0), visualViewport.location());
421 static void disableAcceleratedCompositing(WebSettings* settings)
423 VisualViewportTest::configureSettings(settings);
424 // FIXME: This setting is being removed, so this test needs to be rewritten to
425 // do something else. crbug.com/173949
426 settings->setAcceleratedCompositingEnabled(false);
429 // Test that the container layer gets sized properly if the WebView is resized
430 // prior to the VisualViewport being attached to the layer tree.
431 TEST_P(ParameterizedVisualViewportTest, TestWebViewResizedBeforeAttachment)
433 initializeWithDesktopSettings(disableAcceleratedCompositing);
434 webViewImpl()->resize(IntSize(320, 240));
436 navigateTo("about:blank");
437 forceFullCompositingUpdate();
438 webViewImpl()->settings()->setAcceleratedCompositingEnabled(true);
439 webViewImpl()->layout();
441 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
442 EXPECT_FLOAT_SIZE_EQ(FloatSize(320, 240), visualViewport.containerLayer()->size());
445 // Make sure that the visibleRect method acurately reflects the scale and scroll location
446 // of the viewport.
447 TEST_P(ParameterizedVisualViewportTest, TestVisibleRect)
449 initializeWithDesktopSettings();
450 webViewImpl()->resize(IntSize(320, 240));
452 navigateTo("about:blank");
453 forceFullCompositingUpdate();
455 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
457 // Initial visible rect should be the whole frame.
458 EXPECT_SIZE_EQ(IntSize(webViewImpl()->size()), visualViewport.size());
460 // Viewport is whole frame.
461 IntSize size = IntSize(400, 200);
462 webViewImpl()->resize(size);
463 webViewImpl()->layout();
464 visualViewport.setSize(size);
466 // Scale the viewport to 2X; size should not change.
467 FloatRect expectedRect(FloatPoint(0, 0), size);
468 expectedRect.scale(0.5);
469 visualViewport.setScale(2);
470 EXPECT_EQ(2, visualViewport.scale());
471 EXPECT_SIZE_EQ(size, visualViewport.size());
472 EXPECT_FLOAT_RECT_EQ(expectedRect, visualViewport.visibleRect());
474 // Move the viewport.
475 expectedRect.setLocation(FloatPoint(5, 7));
476 visualViewport.setLocation(expectedRect.location());
477 EXPECT_FLOAT_RECT_EQ(expectedRect, visualViewport.visibleRect());
479 expectedRect.setLocation(FloatPoint(200, 100));
480 visualViewport.setLocation(expectedRect.location());
481 EXPECT_FLOAT_RECT_EQ(expectedRect, visualViewport.visibleRect());
483 // Scale the viewport to 3X to introduce some non-int values.
484 FloatPoint oldLocation = expectedRect.location();
485 expectedRect = FloatRect(FloatPoint(), size);
486 expectedRect.scale(1 / 3.0f);
487 expectedRect.setLocation(oldLocation);
488 visualViewport.setScale(3);
489 EXPECT_FLOAT_RECT_EQ(expectedRect, visualViewport.visibleRect());
491 expectedRect.setLocation(FloatPoint(0.25f, 0.333f));
492 visualViewport.setLocation(expectedRect.location());
493 EXPECT_FLOAT_RECT_EQ(expectedRect, visualViewport.visibleRect());
496 // Make sure that the visibleRectInDocument method acurately reflects the scale
497 // and scroll location of the viewport relative to the document.
498 TEST_P(ParameterizedVisualViewportTest, TestVisibleRectInDocument)
500 initializeWithDesktopSettings();
501 webViewImpl()->resize(IntSize(100, 400));
503 registerMockedHttpURLLoad("200-by-800-viewport.html");
504 navigateTo(m_baseURL + "200-by-800-viewport.html");
506 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
508 // Scale the viewport to 2X and move it.
509 visualViewport.setScale(2);
510 visualViewport.setLocation(FloatPoint(10, 15));
511 EXPECT_FLOAT_RECT_EQ(FloatRect(10, 15, 50, 200), visualViewport.visibleRectInDocument());
513 // Scroll the layout viewport. Ensure its offset is reflected in visibleRectInDocument().
514 FrameView& frameView = *webViewImpl()->mainFrameImpl()->frameView();
515 frameView.layoutViewportScrollableArea()->setScrollPosition(DoublePoint(40, 100), ProgrammaticScroll);
516 EXPECT_FLOAT_RECT_EQ(FloatRect(50, 115, 50, 200), visualViewport.visibleRectInDocument());
519 TEST_P(ParameterizedVisualViewportTest, TestFractionalScrollOffsetIsNotOverwritten)
521 initializeWithAndroidSettings();
522 webViewImpl()->resize(IntSize(200, 250));
524 registerMockedHttpURLLoad("200-by-800-viewport.html");
525 navigateTo(m_baseURL + "200-by-800-viewport.html");
527 FrameView& frameView = *webViewImpl()->mainFrameImpl()->frameView();
528 frameView.layoutViewportScrollableArea()->setScrollPosition(DoublePoint(0, 10.5), ProgrammaticScroll);
529 webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(10, 20), WebFloatSize(), 1, 0);
531 EXPECT_EQ(30.5, frameView.layoutViewportScrollableArea()->scrollPositionDouble().y());
534 // Test that the viewport's scroll offset is always appropriately bounded such that the
535 // visual viewport always stays within the bounds of the main frame.
536 TEST_P(ParameterizedVisualViewportTest, TestOffsetClamping)
538 initializeWithDesktopSettings();
539 webViewImpl()->resize(IntSize(320, 240));
541 navigateTo("about:blank");
542 forceFullCompositingUpdate();
544 // Visual viewport should be initialized to same size as frame so no scrolling possible.
545 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
546 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
548 visualViewport.setLocation(FloatPoint(-1, -2));
549 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
551 visualViewport.setLocation(FloatPoint(100, 200));
552 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
554 visualViewport.setLocation(FloatPoint(-5, 10));
555 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
557 // Scale by 2x. The viewport's visible rect should now have a size of 160x120.
558 visualViewport.setScale(2);
559 FloatPoint location(10, 50);
560 visualViewport.setLocation(location);
561 EXPECT_FLOAT_POINT_EQ(location, visualViewport.visibleRect().location());
563 visualViewport.setLocation(FloatPoint(1000, 2000));
564 EXPECT_FLOAT_POINT_EQ(FloatPoint(160, 120), visualViewport.visibleRect().location());
566 visualViewport.setLocation(FloatPoint(-1000, -2000));
567 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
569 // Make sure offset gets clamped on scale out. Scale to 1.25 so the viewport is 256x192.
570 visualViewport.setLocation(FloatPoint(160, 120));
571 visualViewport.setScale(1.25);
572 EXPECT_FLOAT_POINT_EQ(FloatPoint(64, 48), visualViewport.visibleRect().location());
574 // Scale out smaller than 1.
575 visualViewport.setScale(0.25);
576 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
579 // Test that the viewport can be scrolled around only within the main frame in the presence
580 // of viewport resizes, as would be the case if the on screen keyboard came up.
581 TEST_P(ParameterizedVisualViewportTest, TestOffsetClampingWithResize)
583 initializeWithDesktopSettings();
584 webViewImpl()->resize(IntSize(320, 240));
586 navigateTo("about:blank");
587 forceFullCompositingUpdate();
589 // Visual viewport should be initialized to same size as frame so no scrolling possible.
590 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
591 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
593 // Shrink the viewport vertically. The resize shouldn't affect the location, but it
594 // should allow vertical scrolling.
595 visualViewport.setSize(IntSize(320, 200));
596 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
597 visualViewport.setLocation(FloatPoint(10, 20));
598 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 20), visualViewport.visibleRect().location());
599 visualViewport.setLocation(FloatPoint(0, 100));
600 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 40), visualViewport.visibleRect().location());
601 visualViewport.setLocation(FloatPoint(0, 10));
602 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 10), visualViewport.visibleRect().location());
603 visualViewport.setLocation(FloatPoint(0, -100));
604 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
606 // Repeat the above but for horizontal dimension.
607 visualViewport.setSize(IntSize(280, 240));
608 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
609 visualViewport.setLocation(FloatPoint(10, 20));
610 EXPECT_FLOAT_POINT_EQ(FloatPoint(10, 0), visualViewport.visibleRect().location());
611 visualViewport.setLocation(FloatPoint(100, 0));
612 EXPECT_FLOAT_POINT_EQ(FloatPoint(40, 0), visualViewport.visibleRect().location());
613 visualViewport.setLocation(FloatPoint(10, 0));
614 EXPECT_FLOAT_POINT_EQ(FloatPoint(10, 0), visualViewport.visibleRect().location());
615 visualViewport.setLocation(FloatPoint(-100, 0));
616 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
618 // Now with both dimensions.
619 visualViewport.setSize(IntSize(280, 200));
620 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
621 visualViewport.setLocation(FloatPoint(10, 20));
622 EXPECT_FLOAT_POINT_EQ(FloatPoint(10, 20), visualViewport.visibleRect().location());
623 visualViewport.setLocation(FloatPoint(100, 100));
624 EXPECT_FLOAT_POINT_EQ(FloatPoint(40, 40), visualViewport.visibleRect().location());
625 visualViewport.setLocation(FloatPoint(10, 3));
626 EXPECT_FLOAT_POINT_EQ(FloatPoint(10, 3), visualViewport.visibleRect().location());
627 visualViewport.setLocation(FloatPoint(-10, -4));
628 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
631 // Test that the viewport is scrollable but bounded appropriately within the main frame
632 // when we apply both scaling and resizes.
633 TEST_P(ParameterizedVisualViewportTest, TestOffsetClampingWithResizeAndScale)
635 initializeWithDesktopSettings();
636 webViewImpl()->resize(IntSize(320, 240));
638 navigateTo("about:blank");
639 forceFullCompositingUpdate();
641 // Visual viewport should be initialized to same size as WebView so no scrolling possible.
642 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
643 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.visibleRect().location());
645 // Zoom in to 2X so we can scroll the viewport to 160x120.
646 visualViewport.setScale(2);
647 visualViewport.setLocation(FloatPoint(200, 200));
648 EXPECT_FLOAT_POINT_EQ(FloatPoint(160, 120), visualViewport.visibleRect().location());
650 // Now resize the viewport to make it 10px smaller. Since we're zoomed in by 2X it should
651 // allow us to scroll by 5px more.
652 visualViewport.setSize(IntSize(310, 230));
653 visualViewport.setLocation(FloatPoint(200, 200));
654 EXPECT_FLOAT_POINT_EQ(FloatPoint(165, 125), visualViewport.visibleRect().location());
656 // The viewport can be larger than the main frame (currently 320, 240) though typically
657 // the scale will be clamped to prevent it from actually being larger.
658 visualViewport.setSize(IntSize(330, 250));
659 EXPECT_SIZE_EQ(IntSize(330, 250), visualViewport.size());
661 // Resize both the viewport and the frame to be larger.
662 webViewImpl()->resize(IntSize(640, 480));
663 webViewImpl()->layout();
664 EXPECT_SIZE_EQ(IntSize(webViewImpl()->size()), visualViewport.size());
665 EXPECT_SIZE_EQ(IntSize(webViewImpl()->size()), frame()->view()->frameRect().size());
666 visualViewport.setLocation(FloatPoint(1000, 1000));
667 EXPECT_FLOAT_POINT_EQ(FloatPoint(320, 240), visualViewport.visibleRect().location());
669 // Make sure resizing the viewport doesn't change its offset if the resize doesn't make
670 // the viewport go out of bounds.
671 visualViewport.setLocation(FloatPoint(200, 200));
672 visualViewport.setSize(IntSize(880, 560));
673 EXPECT_FLOAT_POINT_EQ(FloatPoint(200, 200), visualViewport.visibleRect().location());
676 // The main FrameView's size should be set such that its the size of the visual viewport
677 // at minimum scale. If there's no explicit minimum scale set, the FrameView should be
678 // set to the content width and height derived by the aspect ratio.
679 TEST_P(ParameterizedVisualViewportTest, TestFrameViewSizedToContent)
681 initializeWithAndroidSettings();
682 webViewImpl()->resize(IntSize(320, 240));
684 registerMockedHttpURLLoad("200-by-300-viewport.html");
685 navigateTo(m_baseURL + "200-by-300-viewport.html");
687 webViewImpl()->resize(IntSize(600, 800));
688 webViewImpl()->layout();
690 // Note: the size is ceiled and should match the behavior in CC's LayerImpl::bounds().
691 EXPECT_SIZE_EQ(IntSize(200, 267),
692 webViewImpl()->mainFrameImpl()->frameView()->frameRect().size());
695 // The main FrameView's size should be set such that its the size of the visual viewport
696 // at minimum scale. On Desktop, the minimum scale is set at 1 so make sure the FrameView
697 // is sized to the viewport.
698 TEST_P(ParameterizedVisualViewportTest, TestFrameViewSizedToMinimumScale)
700 initializeWithDesktopSettings();
701 webViewImpl()->resize(IntSize(320, 240));
703 registerMockedHttpURLLoad("200-by-300.html");
704 navigateTo(m_baseURL + "200-by-300.html");
706 webViewImpl()->resize(IntSize(100, 160));
707 webViewImpl()->layout();
709 EXPECT_SIZE_EQ(IntSize(100, 160),
710 webViewImpl()->mainFrameImpl()->frameView()->frameRect().size());
713 // Test that attaching a new frame view resets the size of the inner viewport scroll
714 // layer. crbug.com/423189.
715 TEST_P(ParameterizedVisualViewportTest, TestAttachingNewFrameSetsInnerScrollLayerSize)
717 initializeWithAndroidSettings();
718 webViewImpl()->resize(IntSize(320, 240));
720 // Load a wider page first, the navigation should resize the scroll layer to
721 // the smaller size on the second navigation.
722 registerMockedHttpURLLoad("content-width-1000.html");
723 navigateTo(m_baseURL + "content-width-1000.html");
724 webViewImpl()->layout();
726 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
727 visualViewport.setScale(2);
728 visualViewport.move(FloatPoint(50, 60));
730 // Move and scale the viewport to make sure it gets reset in the navigation.
731 EXPECT_POINT_EQ(FloatPoint(50, 60), visualViewport.location());
732 EXPECT_EQ(2, visualViewport.scale());
734 // Navigate again, this time the FrameView should be smaller.
735 registerMockedHttpURLLoad("viewport-device-width.html");
736 navigateTo(m_baseURL + "viewport-device-width.html");
738 // Ensure the scroll layer matches the frame view's size.
739 EXPECT_SIZE_EQ(FloatSize(320, 240), visualViewport.scrollLayer()->size());
741 // Ensure the location and scale were reset.
742 EXPECT_POINT_EQ(FloatPoint(), visualViewport.location());
743 EXPECT_EQ(1, visualViewport.scale());
746 // The main FrameView's size should be set such that its the size of the visual viewport
747 // at minimum scale. Test that the FrameView is appropriately sized in the presence
748 // of a viewport <meta> tag.
749 TEST_P(ParameterizedVisualViewportTest, TestFrameViewSizedToViewportMetaMinimumScale)
751 initializeWithAndroidSettings();
752 webViewImpl()->resize(IntSize(320, 240));
754 registerMockedHttpURLLoad("200-by-300-min-scale-2.html");
755 navigateTo(m_baseURL + "200-by-300-min-scale-2.html");
757 webViewImpl()->resize(IntSize(100, 160));
758 webViewImpl()->layout();
760 EXPECT_SIZE_EQ(IntSize(50, 80),
761 webViewImpl()->mainFrameImpl()->frameView()->frameRect().size());
764 // Test that the visual viewport still gets sized in AutoSize/AutoResize mode.
765 TEST_P(ParameterizedVisualViewportTest, TestVisualViewportGetsSizeInAutoSizeMode)
767 initializeWithDesktopSettings();
769 EXPECT_SIZE_EQ(IntSize(0, 0), IntSize(webViewImpl()->size()));
770 EXPECT_SIZE_EQ(IntSize(0, 0), frame()->page()->frameHost().visualViewport().size());
772 webViewImpl()->enableAutoResizeMode(WebSize(10, 10), WebSize(1000, 1000));
774 registerMockedHttpURLLoad("200-by-300.html");
775 navigateTo(m_baseURL + "200-by-300.html");
777 EXPECT_SIZE_EQ(IntSize(200, 300), frame()->page()->frameHost().visualViewport().size());
780 // Test that the text selection handle's position accounts for the visual viewport.
781 TEST_P(ParameterizedVisualViewportTest, TestTextSelectionHandles)
783 initializeWithDesktopSettings();
784 webViewImpl()->resize(IntSize(500, 800));
786 registerMockedHttpURLLoad("pinch-viewport-input-field.html");
787 navigateTo(m_baseURL + "pinch-viewport-input-field.html");
789 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
790 webViewImpl()->setInitialFocus(false);
792 WebRect originalAnchor;
793 WebRect originalFocus;
794 webViewImpl()->selectionBounds(originalAnchor, originalFocus);
796 webViewImpl()->setPageScaleFactor(2);
797 visualViewport.setLocation(FloatPoint(100, 400));
799 WebRect anchor;
800 WebRect focus;
801 webViewImpl()->selectionBounds(anchor, focus);
803 IntPoint expected(IntRect(originalAnchor).location());
804 expected.moveBy(-flooredIntPoint(visualViewport.visibleRect().location()));
805 expected.scale(visualViewport.scale(), visualViewport.scale());
807 EXPECT_POINT_EQ(expected, IntRect(anchor).location());
808 EXPECT_POINT_EQ(expected, IntRect(focus).location());
810 // FIXME(bokan) - http://crbug.com/364154 - Figure out how to test text selection
811 // as well rather than just carret.
814 // Test that the HistoryItem for the page stores the visual viewport's offset and scale.
815 TEST_P(ParameterizedVisualViewportTest, TestSavedToHistoryItem)
817 initializeWithDesktopSettings();
818 webViewImpl()->resize(IntSize(200, 300));
819 webViewImpl()->layout();
821 registerMockedHttpURLLoad("200-by-300.html");
822 navigateTo(m_baseURL + "200-by-300.html");
824 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0),
825 toLocalFrame(webViewImpl()->page()->mainFrame())->loader().currentItem()->visualViewportScrollPoint());
827 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
828 visualViewport.setScale(2);
830 EXPECT_EQ(2, toLocalFrame(webViewImpl()->page()->mainFrame())->loader().currentItem()->pageScaleFactor());
832 visualViewport.setLocation(FloatPoint(10, 20));
834 EXPECT_FLOAT_POINT_EQ(FloatPoint(10, 20),
835 toLocalFrame(webViewImpl()->page()->mainFrame())->loader().currentItem()->visualViewportScrollPoint());
838 // Test restoring a HistoryItem properly restores the visual viewport's state.
839 TEST_P(ParameterizedVisualViewportTest, TestRestoredFromHistoryItem)
841 initializeWithDesktopSettings();
842 webViewImpl()->resize(IntSize(200, 300));
844 registerMockedHttpURLLoad("200-by-300.html");
846 WebHistoryItem item;
847 item.initialize();
848 WebURL destinationURL(URLTestHelpers::toKURL(m_baseURL + "200-by-300.html"));
849 item.setURLString(destinationURL.string());
850 item.setVisualViewportScrollOffset(WebFloatPoint(100, 120));
851 item.setPageScaleFactor(2);
853 FrameTestHelpers::loadHistoryItem(webViewImpl()->mainFrame(), item, WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
855 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
856 EXPECT_EQ(2, visualViewport.scale());
858 EXPECT_FLOAT_POINT_EQ(FloatPoint(100, 120), visualViewport.visibleRect().location());
861 // Test restoring a HistoryItem without the visual viewport offset falls back to distributing
862 // the scroll offset between the main frame and the visual viewport.
863 TEST_F(VisualViewportTest, TestRestoredFromLegacyHistoryItem)
865 initializeWithDesktopSettings();
866 webViewImpl()->resize(IntSize(100, 150));
868 registerMockedHttpURLLoad("200-by-300-viewport.html");
870 WebHistoryItem item;
871 item.initialize();
872 WebURL destinationURL(URLTestHelpers::toKURL(m_baseURL + "200-by-300-viewport.html"));
873 item.setURLString(destinationURL.string());
874 // (-1, -1) will be used if the HistoryItem is an older version prior to having
875 // visual viewport scroll offset.
876 item.setVisualViewportScrollOffset(WebFloatPoint(-1, -1));
877 item.setScrollOffset(WebPoint(120, 180));
878 item.setPageScaleFactor(2);
880 FrameTestHelpers::loadHistoryItem(webViewImpl()->mainFrame(), item, WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
882 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
883 EXPECT_EQ(2, visualViewport.scale());
884 EXPECT_POINT_EQ(IntPoint(100, 150), frame()->view()->scrollPosition());
885 EXPECT_FLOAT_POINT_EQ(FloatPoint(20, 30), visualViewport.visibleRect().location());
888 // Test that navigation to a new page with a different sized main frame doesn't
889 // clobber the history item's main frame scroll offset. crbug.com/371867
890 TEST_P(ParameterizedVisualViewportTest, TestNavigateToSmallerFrameViewHistoryItemClobberBug)
892 initializeWithAndroidSettings();
893 webViewImpl()->resize(IntSize(400, 400));
894 webViewImpl()->layout();
896 registerMockedHttpURLLoad("content-width-1000.html");
897 navigateTo(m_baseURL + "content-width-1000.html");
899 FrameView* frameView = webViewImpl()->mainFrameImpl()->frameView();
900 frameView->layoutViewportScrollableArea()->setScrollPosition(IntPoint(0, 1000), ProgrammaticScroll);
902 EXPECT_SIZE_EQ(IntSize(1000, 1000), frameView->frameRect().size());
904 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
905 visualViewport.setScale(2);
906 visualViewport.setLocation(FloatPoint(350, 350));
908 RefPtrWillBePersistent<HistoryItem> firstItem = webViewImpl()->mainFrameImpl()->frame()->loader().currentItem();
909 EXPECT_POINT_EQ(IntPoint(0, 1000), firstItem->scrollPoint());
911 // Now navigate to a page which causes a smaller frameView. Make sure that
912 // navigating doesn't cause the history item to set a new scroll offset
913 // before the item was replaced.
914 navigateTo("about:blank");
915 frameView = webViewImpl()->mainFrameImpl()->frameView();
917 EXPECT_NE(firstItem, webViewImpl()->mainFrameImpl()->frame()->loader().currentItem());
918 EXPECT_LT(frameView->frameRect().size().width(), 1000);
919 EXPECT_POINT_EQ(IntPoint(0, 1000), firstItem->scrollPoint());
922 // Test that the coordinates sent into moveRangeSelection are offset by the
923 // visual viewport's location.
924 TEST_P(ParameterizedVisualViewportTest, DISABLED_TestWebFrameRangeAccountsForVisualViewportScroll)
926 initializeWithDesktopSettings();
927 webViewImpl()->settings()->setDefaultFontSize(12);
928 webViewImpl()->resize(WebSize(640, 480));
929 registerMockedHttpURLLoad("move_range.html");
930 navigateTo(m_baseURL + "move_range.html");
932 WebRect baseRect;
933 WebRect extentRect;
935 webViewImpl()->setPageScaleFactor(2);
936 WebFrame* mainFrame = webViewImpl()->mainFrame();
938 // Select some text and get the base and extent rects (that's the start of
939 // the range and its end). Do a sanity check that the expected text is
940 // selected
941 mainFrame->executeScript(WebScriptSource("selectRange();"));
942 EXPECT_EQ("ir", mainFrame->selectionAsText().utf8());
944 webViewImpl()->selectionBounds(baseRect, extentRect);
945 WebPoint initialPoint(baseRect.x, baseRect.y);
946 WebPoint endPoint(extentRect.x, extentRect.y);
948 // Move the visual viewport over and make the selection in the same
949 // screen-space location. The selection should change to two characters to
950 // the right and down one line.
951 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
952 visualViewport.move(FloatPoint(60, 25));
953 mainFrame->moveRangeSelection(initialPoint, endPoint);
954 EXPECT_EQ("t ", mainFrame->selectionAsText().utf8());
957 // Test that the scrollFocusedNodeIntoRect method works with the visual viewport.
958 TEST_P(ParameterizedVisualViewportTest, DISABLED_TestScrollFocusedNodeIntoRect)
960 initializeWithDesktopSettings();
961 webViewImpl()->resize(IntSize(500, 300));
963 registerMockedHttpURLLoad("pinch-viewport-input-field.html");
964 navigateTo(m_baseURL + "pinch-viewport-input-field.html");
966 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
967 webViewImpl()->resizeVisualViewport(IntSize(200, 100));
968 webViewImpl()->setInitialFocus(false);
969 visualViewport.setLocation(FloatPoint());
970 webViewImpl()->scrollFocusedNodeIntoRect(IntRect(0, 0, 500, 200));
972 EXPECT_POINT_EQ(IntPoint(0, frame()->view()->maximumScrollPosition().y()),
973 frame()->view()->scrollPosition());
974 EXPECT_FLOAT_POINT_EQ(FloatPoint(150, 200), visualViewport.visibleRect().location());
976 // Try it again but with the page zoomed in
977 frame()->view()->setScrollPosition(IntPoint(0, 0), ProgrammaticScroll);
978 webViewImpl()->resizeVisualViewport(IntSize(500, 300));
979 visualViewport.setLocation(FloatPoint(0, 0));
981 webViewImpl()->setPageScaleFactor(2);
982 webViewImpl()->scrollFocusedNodeIntoRect(IntRect(0, 0, 500, 200));
983 EXPECT_POINT_EQ(IntPoint(0, frame()->view()->maximumScrollPosition().y()),
984 frame()->view()->scrollPosition());
985 EXPECT_FLOAT_POINT_EQ(FloatPoint(125, 150), visualViewport.visibleRect().location());
987 // Once more but make sure that we don't move the visual viewport unless necessary.
988 registerMockedHttpURLLoad("pinch-viewport-input-field-long-and-wide.html");
989 navigateTo(m_baseURL + "pinch-viewport-input-field-long-and-wide.html");
990 webViewImpl()->setInitialFocus(false);
991 visualViewport.setLocation(FloatPoint());
992 frame()->view()->setScrollPosition(IntPoint(0, 0), ProgrammaticScroll);
993 webViewImpl()->resizeVisualViewport(IntSize(500, 300));
994 visualViewport.setLocation(FloatPoint(30, 50));
996 webViewImpl()->setPageScaleFactor(2);
997 webViewImpl()->scrollFocusedNodeIntoRect(IntRect(0, 0, 500, 200));
998 EXPECT_POINT_EQ(IntPoint(200-30-75, 600-50-65), frame()->view()->scrollPosition());
999 EXPECT_FLOAT_POINT_EQ(FloatPoint(30, 50), visualViewport.visibleRect().location());
1002 // Test that resizing the WebView causes ViewportConstrained objects to relayout.
1003 TEST_P(ParameterizedVisualViewportTest, TestWebViewResizeCausesViewportConstrainedLayout)
1005 initializeWithDesktopSettings();
1006 webViewImpl()->resize(IntSize(500, 300));
1008 registerMockedHttpURLLoad("pinch-viewport-fixed-pos.html");
1009 navigateTo(m_baseURL + "pinch-viewport-fixed-pos.html");
1011 LayoutObject* navbar = frame()->document()->getElementById("navbar")->layoutObject();
1013 EXPECT_FALSE(navbar->needsLayout());
1015 frame()->view()->resize(IntSize(500, 200));
1017 EXPECT_TRUE(navbar->needsLayout());
1020 class MockWebFrameClient : public WebFrameClient {
1021 public:
1022 MOCK_METHOD1(showContextMenu, void(const WebContextMenuData&));
1023 MOCK_METHOD1(didChangeScrollOffset, void(WebLocalFrame*));
1026 MATCHER_P2(ContextMenuAtLocation, x, y,
1027 std::string(negation ? "is" : "isn't")
1028 + " at expected location ["
1029 + PrintToString(x) + ", " + PrintToString(y) + "]")
1031 return arg.mousePosition.x == x && arg.mousePosition.y == y;
1034 // Test that the context menu's location is correct in the presence of visual
1035 // viewport offset.
1036 TEST_P(ParameterizedVisualViewportTest, TestContextMenuShownInCorrectLocation)
1038 initializeWithDesktopSettings();
1039 webViewImpl()->resize(IntSize(200, 300));
1041 registerMockedHttpURLLoad("200-by-300.html");
1042 navigateTo(m_baseURL + "200-by-300.html");
1044 WebMouseEvent mouseDownEvent;
1045 mouseDownEvent.type = WebInputEvent::MouseDown;
1046 mouseDownEvent.x = 10;
1047 mouseDownEvent.y = 10;
1048 mouseDownEvent.windowX = 10;
1049 mouseDownEvent.windowY = 10;
1050 mouseDownEvent.globalX = 110;
1051 mouseDownEvent.globalY = 210;
1052 mouseDownEvent.clickCount = 1;
1053 mouseDownEvent.button = WebMouseEvent::ButtonRight;
1055 // Corresponding release event (Windows shows context menu on release).
1056 WebMouseEvent mouseUpEvent(mouseDownEvent);
1057 mouseUpEvent.type = WebInputEvent::MouseUp;
1059 WebFrameClient* oldClient = webViewImpl()->mainFrameImpl()->client();
1060 MockWebFrameClient mockWebFrameClient;
1061 EXPECT_CALL(mockWebFrameClient, showContextMenu(ContextMenuAtLocation(mouseDownEvent.x, mouseDownEvent.y)));
1063 // Do a sanity check with no scale applied.
1064 webViewImpl()->mainFrameImpl()->setClient(&mockWebFrameClient);
1065 webViewImpl()->handleInputEvent(mouseDownEvent);
1066 webViewImpl()->handleInputEvent(mouseUpEvent);
1068 Mock::VerifyAndClearExpectations(&mockWebFrameClient);
1069 mouseDownEvent.button = WebMouseEvent::ButtonLeft;
1070 webViewImpl()->handleInputEvent(mouseDownEvent);
1072 // Now pinch zoom into the page and move the visual viewport. The context
1073 // menu should still appear at the location of the event, relative to the
1074 // WebView.
1075 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
1076 webViewImpl()->setPageScaleFactor(2);
1077 visualViewport.setLocation(FloatPoint(60, 80));
1078 EXPECT_CALL(mockWebFrameClient, showContextMenu(ContextMenuAtLocation(mouseDownEvent.x, mouseDownEvent.y)));
1080 mouseDownEvent.button = WebMouseEvent::ButtonRight;
1081 webViewImpl()->handleInputEvent(mouseDownEvent);
1082 webViewImpl()->handleInputEvent(mouseUpEvent);
1084 // Reset the old client so destruction can occur naturally.
1085 webViewImpl()->mainFrameImpl()->setClient(oldClient);
1088 // Test that the client is notified if page scroll events.
1089 TEST_P(ParameterizedVisualViewportTest, TestClientNotifiedOfScrollEvents)
1091 initializeWithAndroidSettings();
1092 webViewImpl()->resize(IntSize(200, 300));
1094 registerMockedHttpURLLoad("200-by-300.html");
1095 navigateTo(m_baseURL + "200-by-300.html");
1097 WebFrameClient* oldClient = webViewImpl()->mainFrameImpl()->client();
1098 MockWebFrameClient mockWebFrameClient;
1099 webViewImpl()->mainFrameImpl()->setClient(&mockWebFrameClient);
1101 webViewImpl()->setPageScaleFactor(2);
1102 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
1104 EXPECT_CALL(mockWebFrameClient, didChangeScrollOffset(_));
1105 visualViewport.setLocation(FloatPoint(60, 80));
1106 Mock::VerifyAndClearExpectations(&mockWebFrameClient);
1108 // Scroll vertically.
1109 EXPECT_CALL(mockWebFrameClient, didChangeScrollOffset(_));
1110 visualViewport.setLocation(FloatPoint(60, 90));
1111 Mock::VerifyAndClearExpectations(&mockWebFrameClient);
1113 // Scroll horizontally.
1114 EXPECT_CALL(mockWebFrameClient, didChangeScrollOffset(_));
1115 visualViewport.setLocation(FloatPoint(70, 90));
1117 // Reset the old client so destruction can occur naturally.
1118 webViewImpl()->mainFrameImpl()->setClient(oldClient);
1121 // Tests that calling scroll into view on a visible element doesn cause
1122 // a scroll due to a fractional offset. Bug crbug.com/463356.
1123 TEST_P(ParameterizedVisualViewportTest, ScrollIntoViewFractionalOffset)
1125 initializeWithAndroidSettings();
1127 webViewImpl()->resize(IntSize(1000, 1000));
1129 registerMockedHttpURLLoad("scroll-into-view.html");
1130 navigateTo(m_baseURL + "scroll-into-view.html");
1132 FrameView& frameView = *webViewImpl()->mainFrameImpl()->frameView();
1133 ScrollableArea* layoutViewportScrollableArea = frameView.layoutViewportScrollableArea();
1134 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
1135 Element* inputBox = frame()->document()->getElementById("box");
1137 webViewImpl()->setPageScaleFactor(2);
1139 // The element is already in the view so the scrollIntoView shouldn't move
1140 // the viewport at all.
1141 webViewImpl()->setVisualViewportOffset(WebFloatPoint(250.25f, 100.25f));
1142 layoutViewportScrollableArea->setScrollPosition(DoublePoint(0, 900.75), ProgrammaticScroll);
1143 inputBox->scrollIntoViewIfNeeded(false);
1145 EXPECT_POINT_EQ(DoublePoint(0, 900.75), layoutViewportScrollableArea->scrollPositionDouble());
1146 EXPECT_POINT_EQ(FloatPoint(250.25f, 100.25f), visualViewport.location());
1148 // Change the fractional part of the frameview to one that would round down.
1149 layoutViewportScrollableArea->setScrollPosition(DoublePoint(0, 900.125), ProgrammaticScroll);
1150 inputBox->scrollIntoViewIfNeeded(false);
1152 EXPECT_POINT_EQ(DoublePoint(0, 900.125), layoutViewportScrollableArea->scrollPositionDouble());
1153 EXPECT_POINT_EQ(FloatPoint(250.25f, 100.25f), visualViewport.location());
1155 // Repeat both tests above with the visual viewport at a high fractional.
1156 webViewImpl()->setVisualViewportOffset(WebFloatPoint(250.875f, 100.875f));
1157 layoutViewportScrollableArea->setScrollPosition(DoublePoint(0, 900.75), ProgrammaticScroll);
1158 inputBox->scrollIntoViewIfNeeded(false);
1160 EXPECT_POINT_EQ(DoublePoint(0, 900.75), layoutViewportScrollableArea->scrollPositionDouble());
1161 EXPECT_POINT_EQ(FloatPoint(250.875f, 100.875f), visualViewport.location());
1163 // Change the fractional part of the frameview to one that would round down.
1164 layoutViewportScrollableArea->setScrollPosition(DoublePoint(0, 900.125), ProgrammaticScroll);
1165 inputBox->scrollIntoViewIfNeeded(false);
1167 EXPECT_POINT_EQ(DoublePoint(0, 900.125), layoutViewportScrollableArea->scrollPositionDouble());
1168 EXPECT_POINT_EQ(FloatPoint(250.875f, 100.875f), visualViewport.location());
1170 // Both viewports with a 0.5 fraction.
1171 webViewImpl()->setVisualViewportOffset(WebFloatPoint(250.5f, 100.5f));
1172 layoutViewportScrollableArea->setScrollPosition(DoublePoint(0, 900.5), ProgrammaticScroll);
1173 inputBox->scrollIntoViewIfNeeded(false);
1175 EXPECT_POINT_EQ(DoublePoint(0, 900.5), layoutViewportScrollableArea->scrollPositionDouble());
1176 EXPECT_POINT_EQ(FloatPoint(250.5f, 100.5f), visualViewport.location());
1179 // Top controls can make an unscrollable page temporarily scrollable, causing
1180 // a scroll clamp when the page is resized. Make sure this bug is fixed.
1181 // crbug.com/437620
1182 TEST_F(VisualViewportTest, TestResizeDoesntChangeScrollOffset)
1184 initializeWithAndroidSettings();
1185 webViewImpl()->resize(IntSize(980, 650));
1187 navigateTo("about:blank");
1189 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
1190 FrameView& frameView = *webViewImpl()->mainFrameImpl()->frameView();
1192 webViewImpl()->setTopControlsHeight(20, false);
1194 // Outer viewport isn't scrollable
1195 EXPECT_SIZE_EQ(IntSize(980, 650), frameView.visibleContentRect().size());
1197 visualViewport.setScale(2);
1198 visualViewport.move(FloatPoint(0, 40));
1200 // Simulate bringing down the top controls by 20px but counterscrolling the outer viewport.
1201 webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(0, 20), WebFloatSize(), 1, 1);
1203 EXPECT_EQ(20, frameView.layoutViewportScrollableArea()->scrollPosition().y());
1205 webViewImpl()->setTopControlsHeight(20, true);
1206 webViewImpl()->resize(WebSize(980, 630));
1208 EXPECT_EQ(0, frameView.layoutViewportScrollableArea()->scrollPosition().y());
1209 EXPECT_EQ(60, visualViewport.location().y());
1212 static IntPoint expectedMaxFrameViewScrollOffset(VisualViewport& visualViewport, FrameView& frameView)
1214 float aspectRatio = visualViewport.visibleRect().width() / visualViewport.visibleRect().height();
1215 float newHeight = frameView.frameRect().width() / aspectRatio;
1216 return IntPoint(
1217 frameView.contentsSize().width() - frameView.frameRect().width(),
1218 frameView.contentsSize().height() - newHeight);
1221 TEST_F(VisualViewportTest, TestTopControlsAdjustment)
1223 initializeWithAndroidSettings();
1224 webViewImpl()->resize(IntSize(500, 450));
1226 registerMockedHttpURLLoad("content-width-1000.html");
1227 navigateTo(m_baseURL + "content-width-1000.html");
1229 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
1230 FrameView& frameView = *webViewImpl()->mainFrameImpl()->frameView();
1232 webViewImpl()->setTopControlsHeight(20, false);
1234 visualViewport.setScale(1);
1235 EXPECT_SIZE_EQ(IntSize(500, 450), visualViewport.visibleRect().size());
1236 EXPECT_SIZE_EQ(IntSize(1000, 900), frameView.frameRect().size());
1238 // Simulate bringing down the top controls by 20px.
1239 webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1, 1);
1240 EXPECT_SIZE_EQ(IntSize(500, 430), visualViewport.visibleRect().size());
1242 // Test that the scroll bounds are adjusted appropriately: the visual viewport
1243 // should be shrunk by 20px to 430px. The outer viewport was shrunk to maintain the
1244 // aspect ratio so it's height is 860px.
1245 visualViewport.move(FloatPoint(10000, 10000));
1246 EXPECT_POINT_EQ(FloatPoint(500, 860 - 430), visualViewport.location());
1248 // The outer viewport (FrameView) should be affected as well.
1249 frameView.scrollBy(IntSize(10000, 10000), UserScroll);
1250 EXPECT_POINT_EQ(
1251 expectedMaxFrameViewScrollOffset(visualViewport, frameView),
1252 frameView.scrollPosition());
1254 // Simulate bringing up the top controls by 10.5px.
1255 webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1, -10.5f / 20);
1256 EXPECT_FLOAT_SIZE_EQ(FloatSize(500, 440.5f), visualViewport.visibleRect().size());
1258 // maximumScrollPosition floors the final values.
1259 visualViewport.move(FloatPoint(10000, 10000));
1260 EXPECT_FLOAT_POINT_EQ(FloatPoint(500, 881 - 440.5f), visualViewport.location());
1262 // The outer viewport (FrameView) should be affected as well.
1263 frameView.scrollBy(IntSize(10000, 10000), UserScroll);
1264 EXPECT_POINT_EQ(
1265 expectedMaxFrameViewScrollOffset(visualViewport, frameView),
1266 frameView.scrollPosition());
1269 TEST_F(VisualViewportTest, TestTopControlsAdjustmentWithScale)
1271 initializeWithAndroidSettings();
1272 webViewImpl()->resize(IntSize(500, 450));
1274 registerMockedHttpURLLoad("content-width-1000.html");
1275 navigateTo(m_baseURL + "content-width-1000.html");
1277 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
1278 FrameView& frameView = *webViewImpl()->mainFrameImpl()->frameView();
1280 webViewImpl()->setTopControlsHeight(20, false);
1282 visualViewport.setScale(2);
1283 EXPECT_SIZE_EQ(IntSize(250, 225), visualViewport.visibleRect().size());
1284 EXPECT_SIZE_EQ(IntSize(1000, 900), frameView.frameRect().size());
1286 // Simulate bringing down the top controls by 20px. Since we're zoomed in,
1287 // the top controls take up half as much space (in document-space) than
1288 // they do at an unzoomed level.
1289 webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1, 1);
1290 EXPECT_SIZE_EQ(IntSize(250, 215), visualViewport.visibleRect().size());
1292 // Test that the scroll bounds are adjusted appropriately.
1293 visualViewport.move(FloatPoint(10000, 10000));
1294 EXPECT_POINT_EQ(FloatPoint(750, 860 - 215), visualViewport.location());
1296 // The outer viewport (FrameView) should be affected as well.
1297 frameView.scrollBy(IntSize(10000, 10000), UserScroll);
1298 IntPoint expected = expectedMaxFrameViewScrollOffset(visualViewport, frameView);
1299 EXPECT_POINT_EQ(expected, frameView.scrollPosition());
1301 // Scale back out, FrameView max scroll shouldn't have changed. Visual
1302 // viewport should be moved up to accomodate larger view.
1303 webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 0.5f, 0);
1304 EXPECT_EQ(1, visualViewport.scale());
1305 EXPECT_POINT_EQ(expected, frameView.scrollPosition());
1306 frameView.scrollBy(IntSize(10000, 10000), UserScroll);
1307 EXPECT_POINT_EQ(expected, frameView.scrollPosition());
1309 EXPECT_POINT_EQ(FloatPoint(500, 860 - 430), visualViewport.location());
1310 visualViewport.move(FloatPoint(10000, 10000));
1311 EXPECT_POINT_EQ(FloatPoint(500, 860 - 430), visualViewport.location());
1313 // Scale out, use a scale that causes fractional rects.
1314 webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 0.8f, -1);
1315 EXPECT_SIZE_EQ(FloatSize(625, 562.5), visualViewport.visibleRect().size());
1317 // Bring out the top controls by 11
1318 webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1, 11 / 20.f);
1319 EXPECT_SIZE_EQ(FloatSize(625, 548.75), visualViewport.visibleRect().size());
1321 // Ensure max scroll offsets are updated properly.
1322 visualViewport.move(FloatPoint(10000, 10000));
1323 EXPECT_FLOAT_POINT_EQ(FloatPoint(375, 877.5 - 548.75), visualViewport.location());
1325 frameView.scrollBy(IntSize(10000, 10000), UserScroll);
1326 EXPECT_POINT_EQ(
1327 expectedMaxFrameViewScrollOffset(visualViewport, frameView),
1328 frameView.scrollPosition());
1332 TEST_F(VisualViewportTest, TestTopControlsAdjustmentAndResize)
1334 initializeWithAndroidSettings();
1335 webViewImpl()->resize(IntSize(500, 450));
1337 registerMockedHttpURLLoad("content-width-1000.html");
1338 navigateTo(m_baseURL + "content-width-1000.html");
1340 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
1341 FrameView& frameView = *webViewImpl()->mainFrameImpl()->frameView();
1343 visualViewport.setScale(2);
1344 EXPECT_SIZE_EQ(IntSize(250, 225), visualViewport.visibleRect().size());
1345 EXPECT_SIZE_EQ(IntSize(1000, 900), frameView.frameRect().size());
1347 webViewImpl()->setTopControlsHeight(20, false);
1349 webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1, 1);
1350 EXPECT_SIZE_EQ(IntSize(500, 450), visualViewport.size());
1351 EXPECT_SIZE_EQ(IntSize(250, 215), visualViewport.visibleRect().size());
1353 // Scroll all the way to the bottom.
1354 visualViewport.move(FloatPoint(10000, 10000));
1355 frameView.scrollBy(IntSize(10000, 10000), UserScroll);
1356 IntPoint frameViewExpected = expectedMaxFrameViewScrollOffset(visualViewport, frameView);
1357 FloatPoint visualViewportExpected = FloatPoint(750, 860 - 215);
1358 EXPECT_POINT_EQ(visualViewportExpected, visualViewport.location());
1359 EXPECT_POINT_EQ(frameViewExpected, frameView.scrollPosition());
1361 // Resize the widget to match the top controls adjustment. Ensure that scroll
1362 // offsets don't get clamped in the the process.
1363 webViewImpl()->setTopControlsHeight(20, true);
1364 webViewImpl()->resize(WebSize(500, 430));
1366 EXPECT_SIZE_EQ(IntSize(500, 430), visualViewport.size());
1367 EXPECT_SIZE_EQ(IntSize(250, 215), visualViewport.visibleRect().size());
1368 EXPECT_SIZE_EQ(IntSize(1000, 860), frameView.frameRect().size());
1370 EXPECT_POINT_EQ(frameViewExpected, frameView.scrollPosition());
1371 EXPECT_POINT_EQ(visualViewportExpected, visualViewport.location());
1374 // Tests that a resize due to top controls hiding doesn't incorrectly clamp the
1375 // main frame's scroll offset. crbug.com/428193.
1376 TEST_F(VisualViewportTest, TestTopControlHidingResizeDoesntClampMainFrame)
1378 initializeWithAndroidSettings();
1379 webViewImpl()->setTopControlsHeight(500, false);
1380 webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1, 1);
1381 webViewImpl()->setTopControlsHeight(500, true);
1382 webViewImpl()->resize(IntSize(1000, 1000));
1384 registerMockedHttpURLLoad("content-width-1000.html");
1385 navigateTo(m_baseURL + "content-width-1000.html");
1387 // Scroll the FrameView to the bottom of the page but "hide" the top
1388 // controls on the compositor side so the max scroll position should account
1389 // for the full viewport height.
1390 webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1, -1);
1391 FrameView& frameView = *webViewImpl()->mainFrameImpl()->frameView();
1392 frameView.setScrollPosition(IntPoint(0, 10000), ProgrammaticScroll);
1393 EXPECT_EQ(500, frameView.scrollPositionDouble().y());
1395 // Now send the resize, make sure the scroll offset doesn't change.
1396 webViewImpl()->setTopControlsHeight(500, false);
1397 webViewImpl()->resize(IntSize(1000, 1500));
1398 EXPECT_EQ(500, frameView.scrollPositionDouble().y());
1401 // Tests that the layout viewport's scroll layer bounds are updated in a compositing
1402 // change update. crbug.com/423188.
1403 TEST_P(ParameterizedVisualViewportTest, TestChangingContentSizeAffectsScrollBounds)
1405 initializeWithAndroidSettings();
1406 webViewImpl()->resize(IntSize(100, 150));
1408 registerMockedHttpURLLoad("content-width-1000.html");
1409 navigateTo(m_baseURL + "content-width-1000.html");
1411 FrameView& frameView = *webViewImpl()->mainFrameImpl()->frameView();
1412 WebLayer* scrollLayer = frameView.layerForScrolling()->platformLayer();
1414 webViewImpl()->mainFrame()->executeScript(WebScriptSource(
1415 "var content = document.getElementById(\"content\");"
1416 "content.style.width = \"1500px\";"
1417 "content.style.height = \"2400px\";"));
1418 frameView.updateAllLifecyclePhases();
1420 EXPECT_SIZE_EQ(IntSize(1500, 2400), IntSize(scrollLayer->bounds()));
1423 // Tests that resizing the visual viepwort keeps its bounds within the outer
1424 // viewport.
1425 TEST_P(ParameterizedVisualViewportTest, ResizeVisualViewportStaysWithinOuterViewport)
1427 initializeWithDesktopSettings();
1428 webViewImpl()->resize(IntSize(100, 200));
1430 navigateTo("about:blank");
1431 webViewImpl()->layout();
1433 webViewImpl()->resizeVisualViewport(IntSize(100, 100));
1435 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
1436 visualViewport.move(FloatPoint(0, 100));
1438 EXPECT_EQ(100, visualViewport.location().y());
1440 webViewImpl()->resizeVisualViewport(IntSize(100, 200));
1442 EXPECT_EQ(0, visualViewport.location().y());
1445 TEST_P(ParameterizedVisualViewportTest, ElementBoundsInViewportSpaceAccountsForViewport)
1447 initializeWithAndroidSettings();
1449 webViewImpl()->resize(IntSize(500, 800));
1451 registerMockedHttpURLLoad("pinch-viewport-input-field.html");
1452 navigateTo(m_baseURL + "pinch-viewport-input-field.html");
1454 webViewImpl()->setInitialFocus(false);
1455 Element* inputElement = webViewImpl()->focusedElement();
1457 IntRect bounds = inputElement->layoutObject()->absoluteBoundingBoxRect();
1459 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
1460 IntPoint scrollDelta(250, 400);
1461 visualViewport.setScale(2);
1462 visualViewport.setLocation(scrollDelta);
1464 IntRect boundsInViewport = inputElement->boundsInViewportSpace();
1466 EXPECT_POINT_EQ(IntPoint(bounds.location() - scrollDelta),
1467 boundsInViewport.location());
1468 EXPECT_SIZE_EQ(bounds.size(), boundsInViewport.size());
1471 // Test that the various window.scroll and document.body.scroll properties and
1472 // methods work unchanged from the pre-virtual viewport mode.
1473 TEST_P(ParameterizedVisualViewportTest, bodyAndWindowScrollPropertiesAccountForViewport)
1475 initializeWithAndroidSettings();
1477 webViewImpl()->resize(IntSize(200, 300));
1479 // Load page with no main frame scrolling.
1480 registerMockedHttpURLLoad("200-by-300-viewport.html");
1481 navigateTo(m_baseURL + "200-by-300-viewport.html");
1483 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
1484 visualViewport.setScale(2);
1486 // Chrome's quirky behavior regarding viewport scrolling means we treat the
1487 // body element as the viewport and don't apply scrolling to the HTML
1488 // element.
1489 RuntimeEnabledFeatures::setScrollTopLeftInteropEnabled(false);
1491 LocalDOMWindow* window = webViewImpl()->mainFrameImpl()->frame()->localDOMWindow();
1492 window->scrollTo(100, 150);
1493 EXPECT_EQ(100, window->scrollX());
1494 EXPECT_EQ(150, window->scrollY());
1495 EXPECT_FLOAT_POINT_EQ(FloatPoint(100, 150), visualViewport.location());
1497 HTMLElement* body = toHTMLBodyElement(window->document()->body());
1498 body->setScrollLeft(50);
1499 body->setScrollTop(130);
1500 EXPECT_EQ(50, body->scrollLeft());
1501 EXPECT_EQ(130, body->scrollTop());
1502 EXPECT_FLOAT_POINT_EQ(FloatPoint(50, 130), visualViewport.location());
1504 HTMLElement* documentElement = toHTMLElement(window->document()->documentElement());
1505 documentElement->setScrollLeft(40);
1506 documentElement->setScrollTop(50);
1507 EXPECT_EQ(0, documentElement->scrollLeft());
1508 EXPECT_EQ(0, documentElement->scrollTop());
1509 EXPECT_FLOAT_POINT_EQ(FloatPoint(50, 130), visualViewport.location());
1511 visualViewport.setLocation(FloatPoint(10, 20));
1512 EXPECT_EQ(10, body->scrollLeft());
1513 EXPECT_EQ(20, body->scrollTop());
1514 EXPECT_EQ(0, documentElement->scrollLeft());
1515 EXPECT_EQ(0, documentElement->scrollTop());
1516 EXPECT_EQ(10, window->scrollX());
1517 EXPECT_EQ(20, window->scrollY());
1519 // Turning on the standards-compliant viewport scrolling impl should make
1520 // the document element the viewport and not body.
1521 RuntimeEnabledFeatures::setScrollTopLeftInteropEnabled(true);
1523 window->scrollTo(100, 150);
1524 EXPECT_EQ(100, window->scrollX());
1525 EXPECT_EQ(150, window->scrollY());
1526 EXPECT_FLOAT_POINT_EQ(FloatPoint(100, 150), visualViewport.location());
1528 body->setScrollLeft(50);
1529 body->setScrollTop(130);
1530 EXPECT_EQ(0, body->scrollLeft());
1531 EXPECT_EQ(0, body->scrollTop());
1532 EXPECT_FLOAT_POINT_EQ(FloatPoint(100, 150), visualViewport.location());
1534 documentElement->setScrollLeft(40);
1535 documentElement->setScrollTop(50);
1536 EXPECT_EQ(40, documentElement->scrollLeft());
1537 EXPECT_EQ(50, documentElement->scrollTop());
1538 EXPECT_FLOAT_POINT_EQ(FloatPoint(40, 50), visualViewport.location());
1540 visualViewport.setLocation(FloatPoint(10, 20));
1541 EXPECT_EQ(0, body->scrollLeft());
1542 EXPECT_EQ(0, body->scrollTop());
1543 EXPECT_EQ(10, documentElement->scrollLeft());
1544 EXPECT_EQ(20, documentElement->scrollTop());
1545 EXPECT_EQ(10, window->scrollX());
1546 EXPECT_EQ(20, window->scrollY());
1549 // Tests that when a new frame is created, it is created with the intended
1550 // size (i.e. viewport at minimum scale, 100x200 / 0.5).
1551 TEST_P(ParameterizedVisualViewportTest, TestMainFrameInitializationSizing)
1553 initializeWithAndroidSettings();
1555 webViewImpl()->resize(IntSize(100, 200));
1557 registerMockedHttpURLLoad("content-width-1000-min-scale.html");
1558 navigateTo(m_baseURL + "content-width-1000-min-scale.html");
1560 WebLocalFrameImpl* localFrame = webViewImpl()->mainFrameImpl();
1561 // The detach() and dispose() calls are a hack to prevent this test
1562 // from violating invariants about frame state during navigation/detach.
1563 localFrame->frame()->document()->detach();
1564 localFrame->createFrameView();
1566 FrameView& frameView = *localFrame->frameView();
1567 EXPECT_SIZE_EQ(IntSize(200, 400), frameView.frameRect().size());
1568 frameView.dispose();
1571 // Tests that the maximum scroll offset of the viewport can be fractional.
1572 TEST_P(ParameterizedVisualViewportTest, FractionalMaxScrollOffset)
1574 initializeWithDesktopSettings();
1575 webViewImpl()->resize(IntSize(101, 201));
1576 navigateTo("about:blank");
1578 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
1579 ScrollableArea* scrollableArea = &visualViewport;
1581 webViewImpl()->setPageScaleFactor(1.0);
1582 EXPECT_FLOAT_POINT_EQ(DoublePoint(), scrollableArea->maximumScrollPositionDouble());
1584 webViewImpl()->setPageScaleFactor(2);
1585 EXPECT_FLOAT_POINT_EQ(DoublePoint(101. / 2., 201. / 2.), scrollableArea->maximumScrollPositionDouble());
1588 // Tests that the slow scrolling after an impl scroll on the visual viewport
1589 // is continuous. crbug.com/453460 was caused by the impl-path not updating the
1590 // ScrollAnimator class.
1591 TEST_P(ParameterizedVisualViewportTest, SlowScrollAfterImplScroll)
1593 initializeWithDesktopSettings();
1594 webViewImpl()->resize(IntSize(800, 600));
1595 navigateTo("about:blank");
1597 VisualViewport& visualViewport = frame()->page()->frameHost().visualViewport();
1599 // Apply some scroll and scale from the impl-side.
1600 webViewImpl()->applyViewportDeltas(
1601 WebFloatSize(300, 200),
1602 WebFloatSize(0, 0),
1603 WebFloatSize(0, 0),
1607 EXPECT_POINT_EQ(FloatPoint(300, 200), visualViewport.location());
1609 // Send a scroll event on the main thread path.
1610 PlatformGestureEvent gsu(
1611 PlatformEvent::GestureScrollUpdate,
1612 IntPoint(0, 0),
1613 IntPoint(0, 0),
1614 IntSize(5, 5),
1615 0, false, false, false, false);
1616 gsu.setScrollGestureData(-50, -60, 1, 1, false, false, -1 /* null plugin id */);
1618 frame()->eventHandler().handleGestureEvent(gsu);
1620 // The scroll sent from the impl-side must not be overwritten.
1621 EXPECT_POINT_EQ(FloatPoint(350, 260), visualViewport.location());
1624 static void accessibilitySettings(WebSettings* settings)
1626 VisualViewportTest::configureSettings(settings);
1627 settings->setAccessibilityEnabled(true);
1630 TEST_P(ParameterizedVisualViewportTest, AccessibilityHitTestWhileZoomedIn)
1632 initializeWithDesktopSettings(accessibilitySettings);
1634 registerMockedHttpURLLoad("hit-test.html");
1635 navigateTo(m_baseURL + "hit-test.html");
1637 webViewImpl()->resize(IntSize(500, 500));
1638 webViewImpl()->layout();
1640 WebDocument webDoc = webViewImpl()->mainFrame()->document();
1641 FrameView& frameView = *webViewImpl()->mainFrameImpl()->frameView();
1643 webViewImpl()->setPageScaleFactor(2);
1644 webViewImpl()->setVisualViewportOffset(WebFloatPoint(200, 230));
1645 frameView.layoutViewportScrollableArea()->setScrollPosition(DoublePoint(400, 1100), ProgrammaticScroll);
1647 // FIXME(504057): DeprecatedPaintLayerScrollableArea dirties the compositing state.
1648 forceFullCompositingUpdate();
1650 // Because of where the visual viewport is located, this should hit the bottom right
1651 // target (target 4).
1652 WebAXObject hitNode = webDoc.accessibilityObject().hitTest(WebPoint(154, 165));
1653 EXPECT_EQ(std::string("Target4"), hitNode.title().utf8());
1656 // Tests that the maximum scroll offset of the viewport can be fractional.
1657 TEST_P(ParameterizedVisualViewportTest, TestCoordinateTransforms)
1659 initializeWithAndroidSettings();
1660 webViewImpl()->resize(IntSize(800, 600));
1661 registerMockedHttpURLLoad("content-width-1000.html");
1662 navigateTo(m_baseURL + "content-width-1000.html");
1664 VisualViewport& visualViewport = webViewImpl()->page()->frameHost().visualViewport();
1665 FrameView& frameView = *webViewImpl()->mainFrameImpl()->frameView();
1667 // At scale = 1 the transform should be a no-op.
1668 visualViewport.setScale(1);
1669 EXPECT_FLOAT_POINT_EQ(FloatPoint(314, 273), visualViewport.viewportToRootFrame(FloatPoint(314, 273)));
1670 EXPECT_FLOAT_POINT_EQ(FloatPoint(314, 273), visualViewport.rootFrameToViewport(FloatPoint(314, 273)));
1672 // At scale = 2.
1673 visualViewport.setScale(2);
1674 EXPECT_FLOAT_POINT_EQ(FloatPoint(55, 75), visualViewport.viewportToRootFrame(FloatPoint(110, 150)));
1675 EXPECT_FLOAT_POINT_EQ(FloatPoint(110, 150), visualViewport.rootFrameToViewport(FloatPoint(55, 75)));
1677 // At scale = 2 and with the visual viewport offset.
1678 visualViewport.setLocation(FloatPoint(10, 12));
1679 EXPECT_FLOAT_POINT_EQ(FloatPoint(50, 62), visualViewport.viewportToRootFrame(FloatPoint(80, 100)));
1680 EXPECT_FLOAT_POINT_EQ(FloatPoint(80, 100), visualViewport.rootFrameToViewport(FloatPoint(50, 62)));
1682 // Test points that will cause non-integer values.
1683 EXPECT_FLOAT_POINT_EQ(FloatPoint(50.5, 62.4), visualViewport.viewportToRootFrame(FloatPoint(81, 100.8)));
1684 EXPECT_FLOAT_POINT_EQ(FloatPoint(81, 100.8), visualViewport.rootFrameToViewport(FloatPoint(50.5, 62.4)));
1687 // Scrolling the main frame should have no effect.
1688 frameView.layoutViewportScrollableArea()->setScrollPosition(DoublePoint(100, 120), ProgrammaticScroll);
1689 EXPECT_FLOAT_POINT_EQ(FloatPoint(50, 62), visualViewport.viewportToRootFrame(FloatPoint(80, 100)));
1690 EXPECT_FLOAT_POINT_EQ(FloatPoint(80, 100), visualViewport.rootFrameToViewport(FloatPoint(50, 62)));
1693 // Tests that the window dimensions are available before a full layout occurs.
1694 // More specifically, it checks that the innerWidth and innerHeight window
1695 // properties will trigger a layout which will cause an update to viewport
1696 // constraints and a refreshed initial scale. crbug.com/466718
1697 TEST_P(ParameterizedVisualViewportTest, WindowDimensionsOnLoad)
1699 initializeWithAndroidSettings();
1700 registerMockedHttpURLLoad("window_dimensions.html");
1701 webViewImpl()->resize(IntSize(800, 600));
1702 navigateTo(m_baseURL + "window_dimensions.html");
1704 Element* output = frame()->document()->getElementById("output");
1705 ASSERT(output);
1706 EXPECT_EQ(std::string("1600x1200"), std::string(output->innerHTML().ascii().data()));
1709 // Similar to above but make sure the initial scale is updated with the content
1710 // width for a very wide page. That is, make that innerWidth/Height actually
1711 // trigger a layout of the content, and not just an update of the viepwort.
1712 // crbug.com/466718
1713 TEST_P(ParameterizedVisualViewportTest, WindowDimensionsOnLoadWideContent)
1715 initializeWithAndroidSettings();
1716 registerMockedHttpURLLoad("window_dimensions_wide_div.html");
1717 webViewImpl()->resize(IntSize(800, 600));
1718 navigateTo(m_baseURL + "window_dimensions_wide_div.html");
1720 Element* output = frame()->document()->getElementById("output");
1721 ASSERT(output);
1722 EXPECT_EQ(std::string("2000x1500"), std::string(output->innerHTML().ascii().data()));
1725 static void turnOnInvertedScrollOrder(WebSettings* settings)
1727 VisualViewportTest::configureSettings(settings);
1728 settings->setInvertViewportScrollOrder(true);
1731 TEST_P(ParameterizedVisualViewportTest, PinchZoomGestureScrollsVisualViewportOnly)
1733 initializeWithDesktopSettings(turnOnInvertedScrollOrder);
1734 webViewImpl()->resize(IntSize(100, 100));
1736 registerMockedHttpURLLoad("200-by-800-viewport.html");
1737 navigateTo(m_baseURL + "200-by-800-viewport.html");
1739 WebGestureEvent pinchUpdate;
1740 pinchUpdate.type = WebInputEvent::GesturePinchUpdate;
1741 pinchUpdate.x = 100;
1742 pinchUpdate.y = 100;
1743 pinchUpdate.data.pinchUpdate.scale = 2;
1744 pinchUpdate.data.pinchUpdate.zoomDisabled = false;
1746 webViewImpl()->handleInputEvent(pinchUpdate);
1748 VisualViewport& visualViewport = webViewImpl()->page()->frameHost().visualViewport();
1749 FrameView& frameView = *webViewImpl()->mainFrameImpl()->frameView();
1751 EXPECT_FLOAT_POINT_EQ(FloatPoint(50, 50), visualViewport.location());
1752 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), frameView.scrollPositionDouble());
1755 } // namespace