Home | History | Annotate | Download | only in tests
      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.
      4 
      5 #include "config.h"
      6 
      7 #include "core/frame/PinchViewport.h"
      8 
      9 #include "core/frame/FrameHost.h"
     10 #include "core/frame/LocalFrame.h"
     11 #include "core/page/Page.h"
     12 #include "core/rendering/RenderObject.h"
     13 #include "core/rendering/RenderView.h"
     14 #include "core/rendering/compositing/CompositedLayerMapping.h"
     15 #include "core/rendering/compositing/RenderLayerCompositor.h"
     16 #include "core/testing/URLTestHelpers.h"
     17 #include "public/platform/Platform.h"
     18 #include "public/platform/WebLayerTreeView.h"
     19 #include "public/platform/WebUnitTestSupport.h"
     20 #include "public/web/WebContextMenuData.h"
     21 #include "public/web/WebFrameClient.h"
     22 #include "public/web/WebInputEvent.h"
     23 #include "public/web/WebScriptSource.h"
     24 #include "public/web/WebSettings.h"
     25 #include "public/web/WebViewClient.h"
     26 #include "web/WebLocalFrameImpl.h"
     27 #include "web/tests/FrameTestHelpers.h"
     28 #include <gmock/gmock.h>
     29 #include <gtest/gtest.h>
     30 
     31 #define EXPECT_POINT_EQ(expected, actual) \
     32     do { \
     33         EXPECT_EQ((expected).x(), (actual).x()); \
     34         EXPECT_EQ((expected).y(), (actual).y()); \
     35     } while (false)
     36 
     37 #define EXPECT_FLOAT_POINT_EQ(expected, actual) \
     38     do { \
     39         EXPECT_FLOAT_EQ((expected).x(), (actual).x()); \
     40         EXPECT_FLOAT_EQ((expected).y(), (actual).y()); \
     41     } while (false)
     42 
     43 #define EXPECT_POINT_EQ(expected, actual) \
     44     do { \
     45         EXPECT_EQ((expected).x(), (actual).x()); \
     46         EXPECT_EQ((expected).y(), (actual).y()); \
     47     } while (false)
     48 
     49 #define EXPECT_SIZE_EQ(expected, actual) \
     50     do { \
     51         EXPECT_EQ((expected).width(), (actual).width()); \
     52         EXPECT_EQ((expected).height(), (actual).height()); \
     53     } while (false)
     54 
     55 #define EXPECT_FLOAT_SIZE_EQ(expected, actual) \
     56     do { \
     57         EXPECT_FLOAT_EQ((expected).width(), (actual).width()); \
     58         EXPECT_FLOAT_EQ((expected).height(), (actual).height()); \
     59     } while (false)
     60 
     61 #define EXPECT_FLOAT_RECT_EQ(expected, actual) \
     62     do { \
     63         EXPECT_FLOAT_EQ((expected).x(), (actual).x()); \
     64         EXPECT_FLOAT_EQ((expected).y(), (actual).y()); \
     65         EXPECT_FLOAT_EQ((expected).width(), (actual).width()); \
     66         EXPECT_FLOAT_EQ((expected).height(), (actual).height()); \
     67     } while (false)
     68 
     69 
     70 using namespace blink;
     71 
     72 using ::testing::_;
     73 using ::testing::PrintToString;
     74 using ::testing::Mock;
     75 
     76 namespace blink {
     77 ::std::ostream& operator<<(::std::ostream& os, const WebContextMenuData& data)
     78 {
     79     return os << "Context menu location: ["
     80         << data.mousePosition.x << ", " << data.mousePosition.y << "]";
     81 }
     82 }
     83 
     84 
     85 namespace {
     86 
     87 class PinchViewportTest : public testing::Test {
     88 public:
     89     PinchViewportTest()
     90         : m_baseURL("http://www.test.com/")
     91     {
     92     }
     93 
     94     void initializeWithDesktopSettings(void (*overrideSettingsFunc)(WebSettings*) = 0)
     95     {
     96         if (!overrideSettingsFunc)
     97             overrideSettingsFunc = &configureSettings;
     98         m_helper.initialize(true, 0, &m_mockWebViewClient, overrideSettingsFunc);
     99         webViewImpl()->setPageScaleFactorLimits(1, 4);
    100     }
    101 
    102     void initializeWithAndroidSettings(void (*overrideSettingsFunc)(WebSettings*) = 0)
    103     {
    104         if (!overrideSettingsFunc)
    105             overrideSettingsFunc = &configureAndroidSettings;
    106         m_helper.initialize(true, 0, &m_mockWebViewClient, overrideSettingsFunc);
    107     }
    108 
    109     virtual ~PinchViewportTest()
    110     {
    111         Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
    112     }
    113 
    114     void navigateTo(const std::string& url)
    115     {
    116         FrameTestHelpers::loadFrame(webViewImpl()->mainFrame(), url);
    117     }
    118 
    119     void forceFullCompositingUpdate()
    120     {
    121         webViewImpl()->layout();
    122     }
    123 
    124     void registerMockedHttpURLLoad(const std::string& fileName)
    125     {
    126         URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str()));
    127     }
    128 
    129     WebLayer* getRootScrollLayer()
    130     {
    131         RenderLayerCompositor* compositor = frame()->contentRenderer()->compositor();
    132         ASSERT(compositor);
    133         ASSERT(compositor->scrollLayer());
    134 
    135         WebLayer* webScrollLayer = compositor->scrollLayer()->platformLayer();
    136         return webScrollLayer;
    137     }
    138 
    139     WebViewImpl* webViewImpl() const { return m_helper.webViewImpl(); }
    140     LocalFrame* frame() const { return m_helper.webViewImpl()->mainFrameImpl()->frame(); }
    141 
    142     static void configureSettings(WebSettings* settings)
    143     {
    144         settings->setJavaScriptEnabled(true);
    145         settings->setAcceleratedCompositingEnabled(true);
    146         settings->setPreferCompositingToLCDTextEnabled(true);
    147         settings->setPinchVirtualViewportEnabled(true);
    148     }
    149 
    150     static void configureAndroidSettings(WebSettings* settings)
    151     {
    152         configureSettings(settings);
    153         settings->setViewportEnabled(true);
    154         settings->setViewportMetaEnabled(true);
    155         settings->setShrinksViewportContentToFit(true);
    156         settings->setMainFrameResizesAreOrientationChanges(true);
    157     }
    158 
    159 protected:
    160     std::string m_baseURL;
    161     FrameTestHelpers::TestWebViewClient m_mockWebViewClient;
    162 
    163 private:
    164     FrameTestHelpers::WebViewHelper m_helper;
    165 };
    166 
    167 // Test that resizing the PinchViewport works as expected and that resizing the
    168 // WebView resizes the PinchViewport.
    169 TEST_F(PinchViewportTest, TestResize)
    170 {
    171     initializeWithDesktopSettings();
    172     webViewImpl()->resize(IntSize(320, 240));
    173 
    174     navigateTo("about:blank");
    175     forceFullCompositingUpdate();
    176 
    177     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    178 
    179     IntSize webViewSize = webViewImpl()->size();
    180 
    181     // Make sure the pinch viewport was initialized.
    182     EXPECT_SIZE_EQ(webViewSize, pinchViewport.size());
    183 
    184     // Resizing the WebView should change the PinchViewport.
    185     webViewSize = IntSize(640, 480);
    186     webViewImpl()->resize(webViewSize);
    187     EXPECT_SIZE_EQ(webViewSize, IntSize(webViewImpl()->size()));
    188     EXPECT_SIZE_EQ(webViewSize, pinchViewport.size());
    189 
    190     // Resizing the pinch viewport shouldn't affect the WebView.
    191     IntSize newViewportSize = IntSize(320, 200);
    192     pinchViewport.setSize(newViewportSize);
    193     EXPECT_SIZE_EQ(webViewSize, IntSize(webViewImpl()->size()));
    194     EXPECT_SIZE_EQ(newViewportSize, pinchViewport.size());
    195 }
    196 
    197 // Test that the PinchViewport works as expected in case of a scaled
    198 // and scrolled viewport - scroll down.
    199 TEST_F(PinchViewportTest, TestResizeAfterVerticalScroll)
    200 {
    201     /*
    202                  200                                 200
    203         |                   |               |                   |
    204         |                   |               |                   |
    205         |                   | 800           |                   | 800
    206         |-------------------|               |                   |
    207         |                   |               |                   |
    208         |                   |               |                   |
    209         |                   |               |                   |
    210         |                   |   -------->   |                   |
    211         | 300               |               |                   |
    212         |                   |               |                   |
    213         |               400 |               |                   |
    214         |                   |               |-------------------|
    215         |                   |               |      75           |
    216         | 50                |               | 50             100|
    217         o-----              |               o----               |
    218         |    |              |               |   |  25           |
    219         |    |100           |               |-------------------|
    220         |    |              |               |                   |
    221         |    |              |               |                   |
    222         --------------------                --------------------
    223 
    224      */
    225 
    226     initializeWithAndroidSettings();
    227 
    228     registerMockedHttpURLLoad("200-by-800-viewport.html");
    229     navigateTo(m_baseURL + "200-by-800-viewport.html");
    230 
    231     webViewImpl()->resize(IntSize(100, 200));
    232 
    233     // Scroll main frame to the bottom of the document
    234     webViewImpl()->setMainFrameScrollOffset(WebPoint(0, 400));
    235     EXPECT_POINT_EQ(IntPoint(0, 400), frame()->view()->scrollPosition());
    236 
    237     webViewImpl()->setPageScaleFactor(2.0);
    238 
    239     // Scroll pinch viewport to the bottom of the main frame
    240     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    241     pinchViewport.setLocation(FloatPoint(0, 300));
    242     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 300), pinchViewport.location());
    243 
    244     // Verify the initial size of the pinch viewport in the CSS pixels
    245     EXPECT_FLOAT_SIZE_EQ(FloatSize(50, 100), pinchViewport.visibleRect().size());
    246 
    247     // Perform the resizing
    248     webViewImpl()->resize(IntSize(200, 100));
    249 
    250     // After resizing the scale changes 2.0 -> 4.0
    251     EXPECT_FLOAT_SIZE_EQ(FloatSize(50, 25), pinchViewport.visibleRect().size());
    252 
    253     EXPECT_POINT_EQ(IntPoint(0, 625), frame()->view()->scrollPosition());
    254     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 75), pinchViewport.location());
    255 }
    256 
    257 // Test that the PinchViewport works as expected in case if a scaled
    258 // and scrolled viewport - scroll right.
    259 TEST_F(PinchViewportTest, TestResizeAfterHorizontalScroll)
    260 {
    261     /*
    262                  200                                 200
    263         ---------------o-----               ---------------o-----
    264         |              |    |               |            25|    |
    265         |              |    |               |              -----|
    266         |           100|    |               |100             50 |
    267         |              |    |               |                   |
    268         |              ---- |               |-------------------|
    269         |                   |               |                   |
    270         |                   |               |                   |
    271         |                   |               |                   |
    272         |                   |               |                   |
    273         |                   |               |                   |
    274         |400                |   --------->  |                   |
    275         |                   |               |                   |
    276         |                   |               |                   |
    277         |                   |               |                   |
    278         |                   |               |                   |
    279         |                   |               |                   |
    280         |                   |               |                   |
    281         |                   |               |                   |
    282         |                   |               |                   |
    283         |-------------------|               |                   |
    284         |                   |               |                   |
    285 
    286      */
    287 
    288     initializeWithAndroidSettings();
    289 
    290     registerMockedHttpURLLoad("200-by-800-viewport.html");
    291     navigateTo(m_baseURL + "200-by-800-viewport.html");
    292 
    293     webViewImpl()->resize(IntSize(100, 200));
    294 
    295     // Outer viewport takes the whole width of the document.
    296 
    297     webViewImpl()->setPageScaleFactor(2.0);
    298 
    299     // Scroll pinch viewport to the right edge of the frame
    300     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    301     pinchViewport.setLocation(FloatPoint(150, 0));
    302     EXPECT_FLOAT_POINT_EQ(FloatPoint(150, 0), pinchViewport.location());
    303 
    304     // Verify the initial size of the pinch viewport in the CSS pixels
    305     EXPECT_FLOAT_SIZE_EQ(FloatSize(50, 100), pinchViewport.visibleRect().size());
    306 
    307     webViewImpl()->resize(IntSize(200, 100));
    308 
    309     // After resizing the scale changes 2.0 -> 4.0
    310     EXPECT_FLOAT_SIZE_EQ(FloatSize(50, 25), pinchViewport.visibleRect().size());
    311 
    312     EXPECT_POINT_EQ(IntPoint(0, 0), frame()->view()->scrollPosition());
    313     EXPECT_FLOAT_POINT_EQ(FloatPoint(150, 0), pinchViewport.location());
    314 }
    315 
    316 static void disableAcceleratedCompositing(WebSettings* settings)
    317 {
    318     PinchViewportTest::configureSettings(settings);
    319     // FIXME: This setting is being removed, so this test needs to be rewritten to
    320     // do something else. crbug.com/173949
    321     settings->setAcceleratedCompositingEnabled(false);
    322 }
    323 
    324 // Test that the container layer gets sized properly if the WebView is resized
    325 // prior to the PinchViewport being attached to the layer tree.
    326 TEST_F(PinchViewportTest, TestWebViewResizedBeforeAttachment)
    327 {
    328     initializeWithDesktopSettings(disableAcceleratedCompositing);
    329     webViewImpl()->resize(IntSize(320, 240));
    330 
    331     navigateTo("about:blank");
    332     forceFullCompositingUpdate();
    333     webViewImpl()->settings()->setAcceleratedCompositingEnabled(true);
    334     webViewImpl()->layout();
    335 
    336     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    337     EXPECT_FLOAT_SIZE_EQ(FloatSize(320, 240), pinchViewport.containerLayer()->size());
    338 }
    339 // Make sure that the visibleRect method acurately reflects the scale and scroll location
    340 // of the viewport.
    341 TEST_F(PinchViewportTest, TestVisibleRect)
    342 {
    343     initializeWithDesktopSettings();
    344     webViewImpl()->resize(IntSize(320, 240));
    345 
    346     navigateTo("about:blank");
    347     forceFullCompositingUpdate();
    348 
    349     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    350 
    351     // Initial visible rect should be the whole frame.
    352     EXPECT_SIZE_EQ(IntSize(webViewImpl()->size()), pinchViewport.size());
    353 
    354     // Viewport is whole frame.
    355     IntSize size = IntSize(400, 200);
    356     webViewImpl()->resize(size);
    357     webViewImpl()->layout();
    358     pinchViewport.setSize(size);
    359 
    360     // Scale the viewport to 2X; size should not change.
    361     FloatRect expectedRect(FloatPoint(0, 0), size);
    362     expectedRect.scale(0.5);
    363     pinchViewport.setScale(2);
    364     EXPECT_EQ(2, pinchViewport.scale());
    365     EXPECT_SIZE_EQ(size, pinchViewport.size());
    366     EXPECT_FLOAT_RECT_EQ(expectedRect, pinchViewport.visibleRect());
    367 
    368     // Move the viewport.
    369     expectedRect.setLocation(FloatPoint(5, 7));
    370     pinchViewport.setLocation(expectedRect.location());
    371     EXPECT_FLOAT_RECT_EQ(expectedRect, pinchViewport.visibleRect());
    372 
    373     expectedRect.setLocation(FloatPoint(200, 100));
    374     pinchViewport.setLocation(expectedRect.location());
    375     EXPECT_FLOAT_RECT_EQ(expectedRect, pinchViewport.visibleRect());
    376 
    377     // Scale the viewport to 3X to introduce some non-int values.
    378     FloatPoint oldLocation = expectedRect.location();
    379     expectedRect = FloatRect(FloatPoint(), size);
    380     expectedRect.scale(1 / 3.0f);
    381     expectedRect.setLocation(oldLocation);
    382     pinchViewport.setScale(3);
    383     EXPECT_FLOAT_RECT_EQ(expectedRect, pinchViewport.visibleRect());
    384 
    385     expectedRect.setLocation(FloatPoint(0.25f, 0.333f));
    386     pinchViewport.setLocation(expectedRect.location());
    387     EXPECT_FLOAT_RECT_EQ(expectedRect, pinchViewport.visibleRect());
    388 }
    389 
    390 // Test that the viewport's scroll offset is always appropriately bounded such that the
    391 // pinch viewport always stays within the bounds of the main frame.
    392 TEST_F(PinchViewportTest, TestOffsetClamping)
    393 {
    394     initializeWithDesktopSettings();
    395     webViewImpl()->resize(IntSize(320, 240));
    396 
    397     navigateTo("about:blank");
    398     forceFullCompositingUpdate();
    399 
    400     // Pinch viewport should be initialized to same size as frame so no scrolling possible.
    401     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    402     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    403 
    404     pinchViewport.setLocation(FloatPoint(-1, -2));
    405     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    406 
    407     pinchViewport.setLocation(FloatPoint(100, 200));
    408     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    409 
    410     pinchViewport.setLocation(FloatPoint(-5, 10));
    411     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    412 
    413     // Scale by 2x. The viewport's visible rect should now have a size of 160x120.
    414     pinchViewport.setScale(2);
    415     FloatPoint location(10, 50);
    416     pinchViewport.setLocation(location);
    417     EXPECT_FLOAT_POINT_EQ(location, pinchViewport.visibleRect().location());
    418 
    419     pinchViewport.setLocation(FloatPoint(1000, 2000));
    420     EXPECT_FLOAT_POINT_EQ(FloatPoint(160, 120), pinchViewport.visibleRect().location());
    421 
    422     pinchViewport.setLocation(FloatPoint(-1000, -2000));
    423     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    424 
    425     // Make sure offset gets clamped on scale out. Scale to 1.25 so the viewport is 256x192.
    426     pinchViewport.setLocation(FloatPoint(160, 120));
    427     pinchViewport.setScale(1.25);
    428     EXPECT_FLOAT_POINT_EQ(FloatPoint(64, 48), pinchViewport.visibleRect().location());
    429 
    430     // Scale out smaller than 1.
    431     pinchViewport.setScale(0.25);
    432     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    433 }
    434 
    435 // Test that the viewport can be scrolled around only within the main frame in the presence
    436 // of viewport resizes, as would be the case if the on screen keyboard came up.
    437 TEST_F(PinchViewportTest, TestOffsetClampingWithResize)
    438 {
    439     initializeWithDesktopSettings();
    440     webViewImpl()->resize(IntSize(320, 240));
    441 
    442     navigateTo("about:blank");
    443     forceFullCompositingUpdate();
    444 
    445     // Pinch viewport should be initialized to same size as frame so no scrolling possible.
    446     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    447     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    448 
    449     // Shrink the viewport vertically. The resize shouldn't affect the location, but it
    450     // should allow vertical scrolling.
    451     pinchViewport.setSize(IntSize(320, 200));
    452     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    453     pinchViewport.setLocation(FloatPoint(10, 20));
    454     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 20), pinchViewport.visibleRect().location());
    455     pinchViewport.setLocation(FloatPoint(0, 100));
    456     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 40), pinchViewport.visibleRect().location());
    457     pinchViewport.setLocation(FloatPoint(0, 10));
    458     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 10), pinchViewport.visibleRect().location());
    459     pinchViewport.setLocation(FloatPoint(0, -100));
    460     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    461 
    462     // Repeat the above but for horizontal dimension.
    463     pinchViewport.setSize(IntSize(280, 240));
    464     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    465     pinchViewport.setLocation(FloatPoint(10, 20));
    466     EXPECT_FLOAT_POINT_EQ(FloatPoint(10, 0), pinchViewport.visibleRect().location());
    467     pinchViewport.setLocation(FloatPoint(100, 0));
    468     EXPECT_FLOAT_POINT_EQ(FloatPoint(40, 0), pinchViewport.visibleRect().location());
    469     pinchViewport.setLocation(FloatPoint(10, 0));
    470     EXPECT_FLOAT_POINT_EQ(FloatPoint(10, 0), pinchViewport.visibleRect().location());
    471     pinchViewport.setLocation(FloatPoint(-100, 0));
    472     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    473 
    474     // Now with both dimensions.
    475     pinchViewport.setSize(IntSize(280, 200));
    476     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    477     pinchViewport.setLocation(FloatPoint(10, 20));
    478     EXPECT_FLOAT_POINT_EQ(FloatPoint(10, 20), pinchViewport.visibleRect().location());
    479     pinchViewport.setLocation(FloatPoint(100, 100));
    480     EXPECT_FLOAT_POINT_EQ(FloatPoint(40, 40), pinchViewport.visibleRect().location());
    481     pinchViewport.setLocation(FloatPoint(10, 3));
    482     EXPECT_FLOAT_POINT_EQ(FloatPoint(10, 3), pinchViewport.visibleRect().location());
    483     pinchViewport.setLocation(FloatPoint(-10, -4));
    484     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    485 }
    486 
    487 // Test that the viewport is scrollable but bounded appropriately within the main frame
    488 // when we apply both scaling and resizes.
    489 TEST_F(PinchViewportTest, TestOffsetClampingWithResizeAndScale)
    490 {
    491     initializeWithDesktopSettings();
    492     webViewImpl()->resize(IntSize(320, 240));
    493 
    494     navigateTo("about:blank");
    495     forceFullCompositingUpdate();
    496 
    497     // Pinch viewport should be initialized to same size as WebView so no scrolling possible.
    498     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    499     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.visibleRect().location());
    500 
    501     // Zoom in to 2X so we can scroll the viewport to 160x120.
    502     pinchViewport.setScale(2);
    503     pinchViewport.setLocation(FloatPoint(200, 200));
    504     EXPECT_FLOAT_POINT_EQ(FloatPoint(160, 120), pinchViewport.visibleRect().location());
    505 
    506     // Now resize the viewport to make it 10px smaller. Since we're zoomed in by 2X it should
    507     // allow us to scroll by 5px more.
    508     pinchViewport.setSize(IntSize(310, 230));
    509     pinchViewport.setLocation(FloatPoint(200, 200));
    510     EXPECT_FLOAT_POINT_EQ(FloatPoint(165, 125), pinchViewport.visibleRect().location());
    511 
    512     // The viewport can be larger than the main frame (currently 320, 240) though typically
    513     // the scale will be clamped to prevent it from actually being larger. Make sure size
    514     // changes clamp the offset so the inner remains within the outer.
    515     pinchViewport.setSize(IntSize(330, 250));
    516     EXPECT_SIZE_EQ(IntSize(330, 250), pinchViewport.size());
    517     EXPECT_FLOAT_POINT_EQ(FloatPoint(155, 115), pinchViewport.visibleRect().location());
    518     pinchViewport.setLocation(FloatPoint(200, 200));
    519     EXPECT_FLOAT_POINT_EQ(FloatPoint(155, 115), pinchViewport.visibleRect().location());
    520 
    521     // Resize both the viewport and the frame to be larger.
    522     webViewImpl()->resize(IntSize(640, 480));
    523     webViewImpl()->layout();
    524     EXPECT_SIZE_EQ(IntSize(webViewImpl()->size()), pinchViewport.size());
    525     EXPECT_SIZE_EQ(IntSize(webViewImpl()->size()), frame()->view()->frameRect().size());
    526     pinchViewport.setLocation(FloatPoint(1000, 1000));
    527     EXPECT_FLOAT_POINT_EQ(FloatPoint(320, 240), pinchViewport.visibleRect().location());
    528 
    529     // Make sure resizing the viewport doesn't change its offset if the resize doesn't make
    530     // the viewport go out of bounds.
    531     pinchViewport.setLocation(FloatPoint(200, 200));
    532     pinchViewport.setSize(IntSize(880, 560));
    533     EXPECT_FLOAT_POINT_EQ(FloatPoint(200, 200), pinchViewport.visibleRect().location());
    534 
    535     // Resizing the viewport such that the viewport is out of bounds should move the
    536     // viewport.
    537     pinchViewport.setSize(IntSize(920, 640));
    538     EXPECT_FLOAT_POINT_EQ(FloatPoint(180, 160), pinchViewport.visibleRect().location());
    539 }
    540 
    541 // The main FrameView's size should be set such that its the size of the pinch viewport
    542 // at minimum scale. If there's no explicit minimum scale set, the FrameView should be
    543 // set to the content width and height derived by the aspect ratio.
    544 TEST_F(PinchViewportTest, TestFrameViewSizedToContent)
    545 {
    546     initializeWithAndroidSettings();
    547     webViewImpl()->resize(IntSize(320, 240));
    548 
    549     registerMockedHttpURLLoad("200-by-300-viewport.html");
    550     navigateTo(m_baseURL + "200-by-300-viewport.html");
    551 
    552     webViewImpl()->resize(IntSize(600, 800));
    553     webViewImpl()->layout();
    554 
    555     EXPECT_SIZE_EQ(IntSize(200, 266),
    556         webViewImpl()->mainFrameImpl()->frameView()->frameRect().size());
    557 }
    558 
    559 // The main FrameView's size should be set such that its the size of the pinch viewport
    560 // at minimum scale. On Desktop, the minimum scale is set at 1 so make sure the FrameView
    561 // is sized to the viewport.
    562 TEST_F(PinchViewportTest, TestFrameViewSizedToMinimumScale)
    563 {
    564     initializeWithDesktopSettings();
    565     webViewImpl()->resize(IntSize(320, 240));
    566 
    567     registerMockedHttpURLLoad("200-by-300.html");
    568     navigateTo(m_baseURL + "200-by-300.html");
    569 
    570     webViewImpl()->resize(IntSize(100, 160));
    571     webViewImpl()->layout();
    572 
    573     EXPECT_SIZE_EQ(IntSize(100, 160),
    574         webViewImpl()->mainFrameImpl()->frameView()->frameRect().size());
    575 }
    576 
    577 // The main FrameView's size should be set such that its the size of the pinch viewport
    578 // at minimum scale. Test that the FrameView is appropriately sized in the presence
    579 // of a viewport <meta> tag.
    580 TEST_F(PinchViewportTest, TestFrameViewSizedToViewportMetaMinimumScale)
    581 {
    582     initializeWithAndroidSettings();
    583     webViewImpl()->resize(IntSize(320, 240));
    584 
    585     registerMockedHttpURLLoad("200-by-300-min-scale-2.html");
    586     navigateTo(m_baseURL + "200-by-300-min-scale-2.html");
    587 
    588     webViewImpl()->resize(IntSize(100, 160));
    589     webViewImpl()->layout();
    590 
    591     EXPECT_SIZE_EQ(IntSize(50, 80),
    592         webViewImpl()->mainFrameImpl()->frameView()->frameRect().size());
    593 }
    594 
    595 // Test that the pinch viewport still gets sized in AutoSize/AutoResize mode.
    596 TEST_F(PinchViewportTest, TestPinchViewportGetsSizeInAutoSizeMode)
    597 {
    598     initializeWithDesktopSettings();
    599 
    600     EXPECT_SIZE_EQ(IntSize(0, 0), IntSize(webViewImpl()->size()));
    601     EXPECT_SIZE_EQ(IntSize(0, 0), frame()->page()->frameHost().pinchViewport().size());
    602 
    603     webViewImpl()->enableAutoResizeMode(WebSize(10, 10), WebSize(1000, 1000));
    604 
    605     registerMockedHttpURLLoad("200-by-300.html");
    606     navigateTo(m_baseURL + "200-by-300.html");
    607 
    608     EXPECT_SIZE_EQ(IntSize(200, 300), frame()->page()->frameHost().pinchViewport().size());
    609 }
    610 
    611 // Test that the text selection handle's position accounts for the pinch viewport.
    612 TEST_F(PinchViewportTest, TestTextSelectionHandles)
    613 {
    614     initializeWithDesktopSettings();
    615     webViewImpl()->resize(IntSize(500, 800));
    616 
    617     registerMockedHttpURLLoad("pinch-viewport-input-field.html");
    618     navigateTo(m_baseURL + "pinch-viewport-input-field.html");
    619 
    620     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    621     webViewImpl()->setInitialFocus(false);
    622 
    623     WebRect originalAnchor;
    624     WebRect originalFocus;
    625     webViewImpl()->selectionBounds(originalAnchor, originalFocus);
    626 
    627     webViewImpl()->setPageScaleFactor(2);
    628     pinchViewport.setLocation(FloatPoint(100, 400));
    629 
    630     WebRect anchor;
    631     WebRect focus;
    632     webViewImpl()->selectionBounds(anchor, focus);
    633 
    634     IntPoint expected(IntRect(originalAnchor).location());
    635     expected.moveBy(-flooredIntPoint(pinchViewport.visibleRect().location()));
    636     expected.scale(pinchViewport.scale(), pinchViewport.scale());
    637 
    638     EXPECT_POINT_EQ(expected, IntRect(anchor).location());
    639     EXPECT_POINT_EQ(expected, IntRect(focus).location());
    640 
    641     // FIXME(bokan) - http://crbug.com/364154 - Figure out how to test text selection
    642     // as well rather than just carret.
    643 }
    644 
    645 // Test that the HistoryItem for the page stores the pinch viewport's offset and scale.
    646 TEST_F(PinchViewportTest, TestSavedToHistoryItem)
    647 {
    648     initializeWithDesktopSettings();
    649     webViewImpl()->resize(IntSize(200, 300));
    650     webViewImpl()->layout();
    651 
    652     registerMockedHttpURLLoad("200-by-300.html");
    653     navigateTo(m_baseURL + "200-by-300.html");
    654 
    655     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0),
    656         toLocalFrame(webViewImpl()->page()->mainFrame())->loader().currentItem()->pinchViewportScrollPoint());
    657 
    658     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    659     pinchViewport.setScale(2);
    660 
    661     EXPECT_EQ(2, toLocalFrame(webViewImpl()->page()->mainFrame())->loader().currentItem()->pageScaleFactor());
    662 
    663     pinchViewport.setLocation(FloatPoint(10, 20));
    664 
    665     EXPECT_FLOAT_POINT_EQ(FloatPoint(10, 20),
    666         toLocalFrame(webViewImpl()->page()->mainFrame())->loader().currentItem()->pinchViewportScrollPoint());
    667 }
    668 
    669 // Test restoring a HistoryItem properly restores the pinch viewport's state.
    670 TEST_F(PinchViewportTest, TestRestoredFromHistoryItem)
    671 {
    672     initializeWithDesktopSettings();
    673     webViewImpl()->resize(IntSize(200, 300));
    674 
    675     registerMockedHttpURLLoad("200-by-300.html");
    676 
    677     WebHistoryItem item;
    678     item.initialize();
    679     WebURL destinationURL(URLTestHelpers::toKURL(m_baseURL + "200-by-300.html"));
    680     item.setURLString(destinationURL.string());
    681     item.setPinchViewportScrollOffset(WebFloatPoint(100, 120));
    682     item.setPageScaleFactor(2);
    683 
    684     FrameTestHelpers::loadHistoryItem(webViewImpl()->mainFrame(), item, WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
    685 
    686     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    687     EXPECT_EQ(2, pinchViewport.scale());
    688 
    689     EXPECT_FLOAT_POINT_EQ(FloatPoint(100, 120), pinchViewport.visibleRect().location());
    690 }
    691 
    692 // Test restoring a HistoryItem without the pinch viewport offset falls back to distributing
    693 // the scroll offset between the main frame and the pinch viewport.
    694 TEST_F(PinchViewportTest, TestRestoredFromLegacyHistoryItem)
    695 {
    696     initializeWithDesktopSettings();
    697     webViewImpl()->resize(IntSize(100, 150));
    698 
    699     registerMockedHttpURLLoad("200-by-300-viewport.html");
    700 
    701     WebHistoryItem item;
    702     item.initialize();
    703     WebURL destinationURL(URLTestHelpers::toKURL(m_baseURL + "200-by-300-viewport.html"));
    704     item.setURLString(destinationURL.string());
    705     // (-1, -1) will be used if the HistoryItem is an older version prior to having
    706     // pinch viewport scroll offset.
    707     item.setPinchViewportScrollOffset(WebFloatPoint(-1, -1));
    708     item.setScrollOffset(WebPoint(120, 180));
    709     item.setPageScaleFactor(2);
    710 
    711     FrameTestHelpers::loadHistoryItem(webViewImpl()->mainFrame(), item, WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
    712 
    713     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    714     EXPECT_EQ(2, pinchViewport.scale());
    715     EXPECT_POINT_EQ(IntPoint(100, 150), frame()->view()->scrollPosition());
    716     EXPECT_FLOAT_POINT_EQ(FloatPoint(20, 30), pinchViewport.visibleRect().location());
    717 }
    718 
    719 // Test that the coordinates sent into moveRangeSelection are offset by the
    720 // pinch viewport's location.
    721 TEST_F(PinchViewportTest, TestWebFrameRangeAccountsForPinchViewportScroll)
    722 {
    723     initializeWithDesktopSettings();
    724     webViewImpl()->settings()->setDefaultFontSize(12);
    725     webViewImpl()->resize(WebSize(640, 480));
    726     registerMockedHttpURLLoad("move_range.html");
    727     navigateTo(m_baseURL + "move_range.html");
    728 
    729     WebRect baseRect;
    730     WebRect extentRect;
    731 
    732     webViewImpl()->setPageScaleFactor(2);
    733     WebFrame* mainFrame = webViewImpl()->mainFrame();
    734 
    735     // Select some text and get the base and extent rects (that's the start of
    736     // the range and its end). Do a sanity check that the expected text is
    737     // selected
    738     mainFrame->executeScript(WebScriptSource("selectRange();"));
    739     EXPECT_EQ("ir", mainFrame->selectionAsText().utf8());
    740 
    741     webViewImpl()->selectionBounds(baseRect, extentRect);
    742     WebPoint initialPoint(baseRect.x, baseRect.y);
    743     WebPoint endPoint(extentRect.x, extentRect.y);
    744 
    745     // Move the pinch viewport over and make the selection in the same
    746     // screen-space location. The selection should change to two characters to
    747     // the right and down one line.
    748     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    749     pinchViewport.move(FloatPoint(60, 25));
    750     mainFrame->moveRangeSelection(initialPoint, endPoint);
    751     EXPECT_EQ("t ", mainFrame->selectionAsText().utf8());
    752 }
    753 
    754 // Test that the scrollFocusedNodeIntoRect method works with the pinch viewport.
    755 TEST_F(PinchViewportTest, DISABLED_TestScrollFocusedNodeIntoRect)
    756 {
    757     initializeWithDesktopSettings();
    758     webViewImpl()->resize(IntSize(500, 300));
    759 
    760     registerMockedHttpURLLoad("pinch-viewport-input-field.html");
    761     navigateTo(m_baseURL + "pinch-viewport-input-field.html");
    762 
    763     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    764     webViewImpl()->resizePinchViewport(IntSize(200, 100));
    765     webViewImpl()->setInitialFocus(false);
    766     pinchViewport.setLocation(FloatPoint());
    767     webViewImpl()->scrollFocusedNodeIntoRect(IntRect(0, 0, 500, 200));
    768 
    769     EXPECT_POINT_EQ(IntPoint(0, frame()->view()->maximumScrollPosition().y()),
    770         frame()->view()->scrollPosition());
    771     EXPECT_FLOAT_POINT_EQ(FloatPoint(150, 200), pinchViewport.visibleRect().location());
    772 
    773     // Try it again but with the page zoomed in
    774     frame()->view()->notifyScrollPositionChanged(IntPoint(0, 0));
    775     webViewImpl()->resizePinchViewport(IntSize(500, 300));
    776     pinchViewport.setLocation(FloatPoint(0, 0));
    777 
    778     webViewImpl()->setPageScaleFactor(2);
    779     webViewImpl()->scrollFocusedNodeIntoRect(IntRect(0, 0, 500, 200));
    780     EXPECT_POINT_EQ(IntPoint(0, frame()->view()->maximumScrollPosition().y()),
    781         frame()->view()->scrollPosition());
    782     EXPECT_FLOAT_POINT_EQ(FloatPoint(125, 150), pinchViewport.visibleRect().location());
    783 
    784     // Once more but make sure that we don't move the pinch viewport unless necessary.
    785     registerMockedHttpURLLoad("pinch-viewport-input-field-long-and-wide.html");
    786     navigateTo(m_baseURL + "pinch-viewport-input-field-long-and-wide.html");
    787     webViewImpl()->setInitialFocus(false);
    788     pinchViewport.setLocation(FloatPoint());
    789     frame()->view()->notifyScrollPositionChanged(IntPoint(0, 0));
    790     webViewImpl()->resizePinchViewport(IntSize(500, 300));
    791     pinchViewport.setLocation(FloatPoint(30, 50));
    792 
    793     webViewImpl()->setPageScaleFactor(2);
    794     webViewImpl()->scrollFocusedNodeIntoRect(IntRect(0, 0, 500, 200));
    795     EXPECT_POINT_EQ(IntPoint(200-30-75, 600-50-65), frame()->view()->scrollPosition());
    796     EXPECT_FLOAT_POINT_EQ(FloatPoint(30, 50), pinchViewport.visibleRect().location());
    797 }
    798 
    799 // Test that resizing the WebView causes ViewportConstrained objects to relayout.
    800 TEST_F(PinchViewportTest, TestWebViewResizeCausesViewportConstrainedLayout)
    801 {
    802     initializeWithDesktopSettings();
    803     webViewImpl()->resize(IntSize(500, 300));
    804 
    805     registerMockedHttpURLLoad("pinch-viewport-fixed-pos.html");
    806     navigateTo(m_baseURL + "pinch-viewport-fixed-pos.html");
    807 
    808     RenderObject* navbar = frame()->document()->getElementById("navbar")->renderer();
    809 
    810     EXPECT_FALSE(navbar->needsLayout());
    811 
    812     frame()->view()->resize(IntSize(500, 200));
    813 
    814     EXPECT_TRUE(navbar->needsLayout());
    815 }
    816 
    817 class MockWebFrameClient : public WebFrameClient {
    818 public:
    819     MOCK_METHOD1(showContextMenu, void(const WebContextMenuData&));
    820 };
    821 
    822 MATCHER_P2(ContextMenuAtLocation, x, y,
    823     std::string(negation ? "is" : "isn't")
    824     + " at expected location ["
    825     + PrintToString(x) + ", " + PrintToString(y) + "]")
    826 {
    827     return arg.mousePosition.x == x && arg.mousePosition.y == y;
    828 }
    829 
    830 // Test that the context menu's location is correct in the presence of pinch
    831 // viewport offset.
    832 TEST_F(PinchViewportTest, TestContextMenuShownInCorrectLocation)
    833 {
    834     initializeWithDesktopSettings();
    835     webViewImpl()->resize(IntSize(200, 300));
    836 
    837     registerMockedHttpURLLoad("200-by-300.html");
    838     navigateTo(m_baseURL + "200-by-300.html");
    839 
    840     WebMouseEvent mouseDownEvent;
    841     mouseDownEvent.type = WebInputEvent::MouseDown;
    842     mouseDownEvent.x = 10;
    843     mouseDownEvent.y = 10;
    844     mouseDownEvent.windowX = 10;
    845     mouseDownEvent.windowY = 10;
    846     mouseDownEvent.globalX = 110;
    847     mouseDownEvent.globalY = 210;
    848     mouseDownEvent.clickCount = 1;
    849     mouseDownEvent.button = WebMouseEvent::ButtonRight;
    850 
    851     // Corresponding release event (Windows shows context menu on release).
    852     WebMouseEvent mouseUpEvent(mouseDownEvent);
    853     mouseUpEvent.type = WebInputEvent::MouseUp;
    854 
    855     WebFrameClient* oldClient = webViewImpl()->mainFrameImpl()->client();
    856     MockWebFrameClient mockWebFrameClient;
    857     EXPECT_CALL(mockWebFrameClient, showContextMenu(ContextMenuAtLocation(mouseDownEvent.x, mouseDownEvent.y)));
    858 
    859     // Do a sanity check with no scale applied.
    860     webViewImpl()->mainFrameImpl()->setClient(&mockWebFrameClient);
    861     webViewImpl()->handleInputEvent(mouseDownEvent);
    862     webViewImpl()->handleInputEvent(mouseUpEvent);
    863 
    864     Mock::VerifyAndClearExpectations(&mockWebFrameClient);
    865     mouseDownEvent.button = WebMouseEvent::ButtonLeft;
    866     webViewImpl()->handleInputEvent(mouseDownEvent);
    867 
    868     // Now pinch zoom into the page and move the pinch viewport. The context
    869     // menu should still appear at the location of the event, relative to the
    870     // WebView.
    871     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    872     webViewImpl()->setPageScaleFactor(2);
    873     pinchViewport.setLocation(FloatPoint(60, 80));
    874     EXPECT_CALL(mockWebFrameClient, showContextMenu(ContextMenuAtLocation(mouseDownEvent.x, mouseDownEvent.y)));
    875 
    876     mouseDownEvent.button = WebMouseEvent::ButtonRight;
    877     webViewImpl()->handleInputEvent(mouseDownEvent);
    878     webViewImpl()->handleInputEvent(mouseUpEvent);
    879 
    880     // Reset the old client so destruction can occur naturally.
    881     webViewImpl()->mainFrameImpl()->setClient(oldClient);
    882 }
    883 
    884 // Test that the scrollIntoView correctly scrolls the main frame
    885 // and pinch viewports such that the given rect is centered in the viewport.
    886 TEST_F(PinchViewportTest, DISABLED_TestScrollingDocumentRegionIntoView)
    887 {
    888     initializeWithDesktopSettings();
    889     webViewImpl()->resize(IntSize(100, 150));
    890 
    891     registerMockedHttpURLLoad("200-by-300-viewport.html");
    892     navigateTo(m_baseURL + "200-by-300-viewport.html");
    893 
    894     PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
    895 
    896     // Test that the pinch viewport is scrolled if the viewport has been
    897     // resized (as is the case when the ChromeOS keyboard comes up) but not
    898     // scaled.
    899     webViewImpl()->resizePinchViewport(WebSize(100, 100));
    900     pinchViewport.scrollIntoView(FloatRect(100, 250, 50, 50));
    901     EXPECT_POINT_EQ(IntPoint(75, 150), frame()->view()->scrollPosition());
    902     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 50), pinchViewport.visibleRect().location());
    903 
    904     pinchViewport.scrollIntoView(FloatRect(25, 75, 50, 50));
    905     EXPECT_POINT_EQ(IntPoint(0, 0), frame()->view()->scrollPosition());
    906     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 50), pinchViewport.visibleRect().location());
    907 
    908     // Reset the pinch viewport's size, scale the page and repeat the test
    909     webViewImpl()->resizePinchViewport(IntSize(100, 150));
    910     webViewImpl()->setPageScaleFactor(2);
    911     pinchViewport.setLocation(FloatPoint());
    912 
    913     pinchViewport.scrollIntoView(FloatRect(50, 75, 50, 75));
    914     EXPECT_POINT_EQ(IntPoint(50, 75), frame()->view()->scrollPosition());
    915     EXPECT_FLOAT_POINT_EQ(FloatPoint(), pinchViewport.visibleRect().location());
    916 
    917     pinchViewport.scrollIntoView(FloatRect(190, 290, 10, 10));
    918     EXPECT_POINT_EQ(IntPoint(100, 150), frame()->view()->scrollPosition());
    919     EXPECT_FLOAT_POINT_EQ(FloatPoint(50, 75), pinchViewport.visibleRect().location());
    920 }
    921 
    922 } // namespace
    923