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.
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>
40 #define ASSERT_POINT_EQ(expected, actual) \
42 ASSERT_EQ((expected).x(), (actual).x()); \
43 ASSERT_EQ((expected).y(), (actual).y()); \
46 #define EXPECT_POINT_EQ(expected, actual) \
48 EXPECT_EQ((expected).x(), (actual).x()); \
49 EXPECT_EQ((expected).y(), (actual).y()); \
52 #define EXPECT_FLOAT_POINT_EQ(expected, actual) \
54 EXPECT_FLOAT_EQ((expected).x(), (actual).x()); \
55 EXPECT_FLOAT_EQ((expected).y(), (actual).y()); \
58 #define EXPECT_POINT_EQ(expected, actual) \
60 EXPECT_EQ((expected).x(), (actual).x()); \
61 EXPECT_EQ((expected).y(), (actual).y()); \
64 #define EXPECT_SIZE_EQ(expected, actual) \
66 EXPECT_EQ((expected).width(), (actual).width()); \
67 EXPECT_EQ((expected).height(), (actual).height()); \
70 #define EXPECT_FLOAT_SIZE_EQ(expected, actual) \
72 EXPECT_FLOAT_EQ((expected).width(), (actual).width()); \
73 EXPECT_FLOAT_EQ((expected).height(), (actual).height()); \
76 #define EXPECT_FLOAT_RECT_EQ(expected, actual) \
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()); \
85 using namespace blink
;
88 using ::testing::PrintToString
;
89 using ::testing::Mock
;
92 ::std::ostream
& operator<<(::std::ostream
& os
, const WebContextMenuData
& data
)
94 return os
<< "Context menu location: ["
95 << data
.mousePosition
.x
<< ", " << data
.mousePosition
.y
<< "]";
102 class VisualViewportTest
103 : public testing::Test
104 , public FrameTestHelpers::SettingOverrider
{
107 : m_baseURL("http://www.test.com/")
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();
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);
182 std::string m_baseURL
;
183 FrameTestHelpers::TestWebViewClient m_mockWebViewClient
;
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
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
> {
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));
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
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
)
299 |-------------------| | |
307 | | |-------------------|
312 | |100 | |-------------------|
315 -------------------- --------------------
319 // Disable the test on Mac OSX until futher investigation.
320 // Local build on Mac is OK but thes bot fails.
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
)
362 ---------------o----- ---------------o-----
367 | ---- | |-------------------|
373 |400 | ---------> | |
382 |-------------------| | |
387 // Disable the test on Mac OSX until futher investigation.
388 // Local build on Mac is OK but thes bot fails.
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
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));
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");
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");
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");
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
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
{
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
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
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.
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
;
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
);
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
);
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
);
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
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
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),
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
,
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)));
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");
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.
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");
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());