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