Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (C) 2012 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1.  Redistributions of source code must retain the above copyright
      8  *     notice, this list of conditions and the following disclaimer.
      9  * 2.  Redistributions in binary form must reproduce the above copyright
     10  *     notice, this list of conditions and the following disclaimer in the
     11  *     documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23  */
     24 
     25 #include "config.h"
     26 
     27 #include "core/page/scrolling/ScrollingCoordinator.h"
     28 
     29 #include <gtest/gtest.h>
     30 #include "FrameTestHelpers.h"
     31 #include "URLTestHelpers.h"
     32 #include "WebFrameClient.h"
     33 #include "WebFrameImpl.h"
     34 #include "WebSettings.h"
     35 #include "WebViewClient.h"
     36 #include "WebViewImpl.h"
     37 #include "core/platform/graphics/GraphicsLayer.h"
     38 #include "core/rendering/RenderLayerBacking.h"
     39 #include "core/rendering/RenderLayerCompositor.h"
     40 #include "core/rendering/RenderView.h"
     41 #include "public/platform/Platform.h"
     42 #include "public/platform/WebLayer.h"
     43 #include "public/platform/WebLayerPositionConstraint.h"
     44 #include "public/platform/WebLayerTreeView.h"
     45 #include "public/platform/WebUnitTestSupport.h"
     46 
     47 using namespace WebCore;
     48 using namespace WebKit;
     49 
     50 namespace {
     51 
     52 class FakeWebViewClient : public WebViewClient {
     53 public:
     54     virtual void initializeLayerTreeView()
     55     {
     56         m_layerTreeView = adoptPtr(Platform::current()->unitTestSupport()->createLayerTreeViewForTesting(WebUnitTestSupport::TestViewTypeUnitTest));
     57         ASSERT(m_layerTreeView);
     58     }
     59 
     60     virtual WebLayerTreeView* layerTreeView()
     61     {
     62         return m_layerTreeView.get();
     63     }
     64 
     65 private:
     66     OwnPtr<WebLayerTreeView> m_layerTreeView;
     67 };
     68 
     69 class MockWebFrameClient : public WebFrameClient {
     70 };
     71 
     72 class ScrollingCoordinatorChromiumTest : public testing::Test {
     73 public:
     74     ScrollingCoordinatorChromiumTest()
     75         : m_baseURL("http://www.test.com/")
     76     {
     77         // We cannot reuse FrameTestHelpers::createWebViewAndLoad here because the compositing
     78         // settings need to be set before the page is loaded.
     79         m_webViewImpl = static_cast<WebViewImpl*>(WebView::create(&m_mockWebViewClient));
     80         m_webViewImpl->settings()->setJavaScriptEnabled(true);
     81         m_webViewImpl->settings()->setForceCompositingMode(true);
     82         m_webViewImpl->settings()->setAcceleratedCompositingEnabled(true);
     83         m_webViewImpl->settings()->setAcceleratedCompositingForFixedPositionEnabled(true);
     84         m_webViewImpl->settings()->setAcceleratedCompositingForOverflowScrollEnabled(true);
     85         m_webViewImpl->settings()->setAcceleratedCompositingForScrollableFramesEnabled(true);
     86         m_webViewImpl->settings()->setCompositedScrollingForFramesEnabled(true);
     87         m_webViewImpl->settings()->setFixedPositionCreatesStackingContext(true);
     88         m_webViewImpl->initializeMainFrame(&m_mockWebFrameClient);
     89         m_webViewImpl->resize(IntSize(320, 240));
     90     }
     91 
     92     virtual ~ScrollingCoordinatorChromiumTest()
     93     {
     94         Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
     95         m_webViewImpl->close();
     96     }
     97 
     98     void navigateTo(const std::string& url)
     99     {
    100         FrameTestHelpers::loadFrame(m_webViewImpl->mainFrame(), url);
    101         Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
    102     }
    103 
    104     void registerMockedHttpURLLoad(const std::string& fileName)
    105     {
    106         URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str()));
    107     }
    108 
    109     WebLayer* getRootScrollLayer()
    110     {
    111         RenderLayerCompositor* compositor = m_webViewImpl->mainFrameImpl()->frame()->contentRenderer()->compositor();
    112         ASSERT(compositor);
    113         ASSERT(compositor->scrollLayer());
    114 
    115         WebLayer* webScrollLayer = compositor->scrollLayer()->platformLayer();
    116         return webScrollLayer;
    117     }
    118 
    119 protected:
    120     std::string m_baseURL;
    121     MockWebFrameClient m_mockWebFrameClient;
    122     FakeWebViewClient m_mockWebViewClient;
    123     WebViewImpl* m_webViewImpl;
    124 };
    125 
    126 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingByDefault)
    127 {
    128     navigateTo("about:blank");
    129 
    130     // Make sure the scrolling coordinator is active.
    131     FrameView* frameView = m_webViewImpl->mainFrameImpl()->frameView();
    132     Page* page = m_webViewImpl->mainFrameImpl()->frame()->page();
    133     ASSERT_TRUE(page->scrollingCoordinator());
    134     ASSERT_TRUE(page->scrollingCoordinator()->coordinatesScrollingForFrameView(frameView));
    135 
    136     // Fast scrolling should be enabled by default.
    137     WebLayer* rootScrollLayer = getRootScrollLayer();
    138     ASSERT_TRUE(rootScrollLayer->scrollable());
    139     ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
    140     ASSERT_FALSE(rootScrollLayer->haveWheelEventHandlers());
    141 }
    142 
    143 static WebLayer* webLayerFromElement(Element* element)
    144 {
    145     if (!element)
    146         return 0;
    147     RenderObject* renderer = element->renderer();
    148     if (!renderer || !renderer->isBoxModelObject())
    149         return 0;
    150     RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
    151     if (!layer)
    152         return 0;
    153     RenderLayerBacking* backing = layer->backing();
    154     if (!backing)
    155         return 0;
    156     GraphicsLayer* graphicsLayer = backing->graphicsLayer();
    157     if (!graphicsLayer)
    158         return 0;
    159     return graphicsLayer->platformLayer();
    160 }
    161 
    162 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingForFixedPosition)
    163 {
    164     registerMockedHttpURLLoad("fixed-position.html");
    165     navigateTo(m_baseURL + "fixed-position.html");
    166 
    167     // Fixed position should not fall back to main thread scrolling.
    168     WebLayer* rootScrollLayer = getRootScrollLayer();
    169     ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
    170 
    171     Document* document = m_webViewImpl->mainFrameImpl()->frame()->document();
    172     {
    173         Element* element = document->getElementById("div-tl");
    174         ASSERT_TRUE(element);
    175         WebLayer* layer = webLayerFromElement(element);
    176         ASSERT_TRUE(layer);
    177         WebLayerPositionConstraint constraint = layer->positionConstraint();
    178         ASSERT_TRUE(constraint.isFixedPosition);
    179         ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
    180     }
    181     {
    182         Element* element = document->getElementById("div-tr");
    183         ASSERT_TRUE(element);
    184         WebLayer* layer = webLayerFromElement(element);
    185         ASSERT_TRUE(layer);
    186         WebLayerPositionConstraint constraint = layer->positionConstraint();
    187         ASSERT_TRUE(constraint.isFixedPosition);
    188         ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
    189     }
    190     {
    191         Element* element = document->getElementById("div-bl");
    192         ASSERT_TRUE(element);
    193         WebLayer* layer = webLayerFromElement(element);
    194         ASSERT_TRUE(layer);
    195         WebLayerPositionConstraint constraint = layer->positionConstraint();
    196         ASSERT_TRUE(constraint.isFixedPosition);
    197         ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
    198     }
    199     {
    200         Element* element = document->getElementById("div-br");
    201         ASSERT_TRUE(element);
    202         WebLayer* layer = webLayerFromElement(element);
    203         ASSERT_TRUE(layer);
    204         WebLayerPositionConstraint constraint = layer->positionConstraint();
    205         ASSERT_TRUE(constraint.isFixedPosition);
    206         ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
    207     }
    208     {
    209         Element* element = document->getElementById("span-tl");
    210         ASSERT_TRUE(element);
    211         WebLayer* layer = webLayerFromElement(element);
    212         ASSERT_TRUE(layer);
    213         WebLayerPositionConstraint constraint = layer->positionConstraint();
    214         ASSERT_TRUE(constraint.isFixedPosition);
    215         ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
    216     }
    217     {
    218         Element* element = document->getElementById("span-tr");
    219         ASSERT_TRUE(element);
    220         WebLayer* layer = webLayerFromElement(element);
    221         ASSERT_TRUE(layer);
    222         WebLayerPositionConstraint constraint = layer->positionConstraint();
    223         ASSERT_TRUE(constraint.isFixedPosition);
    224         ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
    225     }
    226     {
    227         Element* element = document->getElementById("span-bl");
    228         ASSERT_TRUE(element);
    229         WebLayer* layer = webLayerFromElement(element);
    230         ASSERT_TRUE(layer);
    231         WebLayerPositionConstraint constraint = layer->positionConstraint();
    232         ASSERT_TRUE(constraint.isFixedPosition);
    233         ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
    234     }
    235     {
    236         Element* element = document->getElementById("span-br");
    237         ASSERT_TRUE(element);
    238         WebLayer* layer = webLayerFromElement(element);
    239         ASSERT_TRUE(layer);
    240         WebLayerPositionConstraint constraint = layer->positionConstraint();
    241         ASSERT_TRUE(constraint.isFixedPosition);
    242         ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
    243     }
    244 }
    245 
    246 TEST_F(ScrollingCoordinatorChromiumTest, nonFastScrollableRegion)
    247 {
    248     registerMockedHttpURLLoad("non-fast-scrollable.html");
    249     navigateTo(m_baseURL + "non-fast-scrollable.html");
    250 
    251     WebLayer* rootScrollLayer = getRootScrollLayer();
    252     WebVector<WebRect> nonFastScrollableRegion = rootScrollLayer->nonFastScrollableRegion();
    253 
    254     ASSERT_EQ(1u, nonFastScrollableRegion.size());
    255     ASSERT_EQ(WebRect(8, 8, 10, 10), nonFastScrollableRegion[0]);
    256 }
    257 
    258 TEST_F(ScrollingCoordinatorChromiumTest, wheelEventHandler)
    259 {
    260     registerMockedHttpURLLoad("wheel-event-handler.html");
    261     navigateTo(m_baseURL + "wheel-event-handler.html");
    262 
    263     WebLayer* rootScrollLayer = getRootScrollLayer();
    264     ASSERT_TRUE(rootScrollLayer->haveWheelEventHandlers());
    265 }
    266 
    267 TEST_F(ScrollingCoordinatorChromiumTest, clippedBodyTest)
    268 {
    269     registerMockedHttpURLLoad("clipped-body.html");
    270     navigateTo(m_baseURL + "clipped-body.html");
    271 
    272     WebLayer* rootScrollLayer = getRootScrollLayer();
    273     ASSERT_EQ(0u, rootScrollLayer->nonFastScrollableRegion().size());
    274 }
    275 
    276 TEST_F(ScrollingCoordinatorChromiumTest, overflowScrolling)
    277 {
    278     registerMockedHttpURLLoad("overflow-scrolling.html");
    279     navigateTo(m_baseURL + "overflow-scrolling.html");
    280 
    281     // Verify the properties of the accelerated scrolling element starting from the RenderObject
    282     // all the way to the WebLayer.
    283     Element* scrollableElement = m_webViewImpl->mainFrameImpl()->frame()->document()->getElementById("scrollable");
    284     ASSERT(scrollableElement);
    285 
    286     RenderObject* renderer = scrollableElement->renderer();
    287     ASSERT_TRUE(renderer->isBoxModelObject());
    288     ASSERT_TRUE(renderer->hasLayer());
    289 
    290     RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
    291     ASSERT_TRUE(layer->usesCompositedScrolling());
    292     ASSERT_TRUE(layer->isComposited());
    293 
    294     RenderLayerBacking* layerBacking = layer->backing();
    295     ASSERT_TRUE(layerBacking->hasScrollingLayer());
    296     ASSERT(layerBacking->scrollingContentsLayer());
    297 
    298     GraphicsLayer* graphicsLayer = layerBacking->scrollingContentsLayer();
    299     ASSERT_EQ(layer, graphicsLayer->scrollableArea());
    300 
    301     WebLayer* webScrollLayer = layerBacking->scrollingContentsLayer()->platformLayer();
    302     ASSERT_TRUE(webScrollLayer->scrollable());
    303 
    304 #if OS(ANDROID)
    305     // Now verify we've attached impl-side scrollbars onto the scrollbar layers
    306     ASSERT_TRUE(layerBacking->layerForHorizontalScrollbar());
    307     ASSERT_TRUE(layerBacking->layerForHorizontalScrollbar()->hasContentsLayer());
    308     ASSERT_TRUE(layerBacking->layerForVerticalScrollbar());
    309     ASSERT_TRUE(layerBacking->layerForVerticalScrollbar()->hasContentsLayer());
    310 #endif
    311 }
    312 
    313 TEST_F(ScrollingCoordinatorChromiumTest, iframeScrolling)
    314 {
    315     registerMockedHttpURLLoad("iframe-scrolling.html");
    316     registerMockedHttpURLLoad("iframe-scrolling-inner.html");
    317     navigateTo(m_baseURL + "iframe-scrolling.html");
    318 
    319     // Verify the properties of the accelerated scrolling element starting from the RenderObject
    320     // all the way to the WebLayer.
    321     Element* scrollableFrame = m_webViewImpl->mainFrameImpl()->frame()->document()->getElementById("scrollable");
    322     ASSERT_TRUE(scrollableFrame);
    323 
    324     RenderObject* renderer = scrollableFrame->renderer();
    325     ASSERT_TRUE(renderer);
    326     ASSERT_TRUE(renderer->isWidget());
    327 
    328     RenderWidget* renderWidget = toRenderWidget(renderer);
    329     ASSERT_TRUE(renderWidget);
    330     ASSERT_TRUE(renderWidget->widget());
    331     ASSERT_TRUE(renderWidget->widget()->isFrameView());
    332 
    333     FrameView* innerFrameView = toFrameView(renderWidget->widget());
    334     RenderView* innerRenderView = innerFrameView->renderView();
    335     ASSERT_TRUE(innerRenderView);
    336 
    337     RenderLayerCompositor* innerCompositor = innerRenderView->compositor();
    338     ASSERT_TRUE(innerCompositor->inCompositingMode());
    339     ASSERT_TRUE(innerCompositor->scrollLayer());
    340 
    341     GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
    342     ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());
    343 
    344     WebLayer* webScrollLayer = scrollLayer->platformLayer();
    345     ASSERT_TRUE(webScrollLayer->scrollable());
    346 
    347 #if OS(ANDROID)
    348     // Now verify we've attached impl-side scrollbars onto the scrollbar layers
    349     ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar());
    350     ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar()->hasContentsLayer());
    351     ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar());
    352     ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar()->hasContentsLayer());
    353 #endif
    354 }
    355 
    356 TEST_F(ScrollingCoordinatorChromiumTest, rtlIframe)
    357 {
    358     registerMockedHttpURLLoad("rtl-iframe.html");
    359     registerMockedHttpURLLoad("rtl-iframe-inner.html");
    360     navigateTo(m_baseURL + "rtl-iframe.html");
    361 
    362     // Verify the properties of the accelerated scrolling element starting from the RenderObject
    363     // all the way to the WebLayer.
    364     Element* scrollableFrame = m_webViewImpl->mainFrameImpl()->frame()->document()->getElementById("scrollable");
    365     ASSERT_TRUE(scrollableFrame);
    366 
    367     RenderObject* renderer = scrollableFrame->renderer();
    368     ASSERT_TRUE(renderer);
    369     ASSERT_TRUE(renderer->isWidget());
    370 
    371     RenderWidget* renderWidget = toRenderWidget(renderer);
    372     ASSERT_TRUE(renderWidget);
    373     ASSERT_TRUE(renderWidget->widget());
    374     ASSERT_TRUE(renderWidget->widget()->isFrameView());
    375 
    376     FrameView* innerFrameView = static_cast<FrameView*>(renderWidget->widget());
    377     RenderView* innerRenderView = innerFrameView->renderView();
    378     ASSERT_TRUE(innerRenderView);
    379 
    380     RenderLayerCompositor* innerCompositor = innerRenderView->compositor();
    381     ASSERT_TRUE(innerCompositor->inCompositingMode());
    382     ASSERT_TRUE(innerCompositor->scrollLayer());
    383 
    384     GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
    385     ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());
    386 
    387     WebLayer* webScrollLayer = scrollLayer->platformLayer();
    388     ASSERT_TRUE(webScrollLayer->scrollable());
    389 
    390     int expectedScrollPosition = 958 + (innerFrameView->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
    391     ASSERT_EQ(expectedScrollPosition, webScrollLayer->scrollPosition().x);
    392     ASSERT_EQ(expectedScrollPosition, webScrollLayer->maxScrollPosition().width);
    393 }
    394 
    395 TEST_F(ScrollingCoordinatorChromiumTest, setupScrollbarLayerShouldNotCrash)
    396 {
    397     registerMockedHttpURLLoad("setup_scrollbar_layer_crash.html");
    398     navigateTo(m_baseURL + "setup_scrollbar_layer_crash.html");
    399     // This test document setup an iframe with scrollbars, then switch to
    400     // an empty document by javascript.
    401 }
    402 
    403 } // namespace
    404