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 "core/rendering/RenderView.h"
     30 #include "core/rendering/compositing/CompositedLayerMapping.h"
     31 #include "core/rendering/compositing/RenderLayerCompositor.h"
     32 #include "platform/graphics/GraphicsLayer.h"
     33 #include "public/platform/Platform.h"
     34 #include "public/platform/WebLayer.h"
     35 #include "public/platform/WebLayerPositionConstraint.h"
     36 #include "public/platform/WebLayerTreeView.h"
     37 #include "public/platform/WebUnitTestSupport.h"
     38 #include "public/web/WebSettings.h"
     39 #include "public/web/WebViewClient.h"
     40 #include "web/WebLocalFrameImpl.h"
     41 #include "web/WebViewImpl.h"
     42 #include "web/tests/FrameTestHelpers.h"
     43 #include "web/tests/URLTestHelpers.h"
     44 #include <gtest/gtest.h>
     45 
     46 using namespace WebCore;
     47 using namespace blink;
     48 
     49 namespace {
     50 
     51 class ScrollingCoordinatorChromiumTest : public testing::Test {
     52 public:
     53     ScrollingCoordinatorChromiumTest()
     54         : m_baseURL("http://www.test.com/")
     55     {
     56         m_helper.initialize(true, 0, &m_mockWebViewClient, &configureSettings);
     57         webViewImpl()->resize(IntSize(320, 240));
     58     }
     59 
     60     virtual ~ScrollingCoordinatorChromiumTest()
     61     {
     62         Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
     63     }
     64 
     65     void navigateTo(const std::string& url)
     66     {
     67         FrameTestHelpers::loadFrame(webViewImpl()->mainFrame(), url);
     68     }
     69 
     70     void forceFullCompositingUpdate()
     71     {
     72         webViewImpl()->layout();
     73     }
     74 
     75     void registerMockedHttpURLLoad(const std::string& fileName)
     76     {
     77         URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str()));
     78     }
     79 
     80     WebLayer* getRootScrollLayer()
     81     {
     82         RenderLayerCompositor* compositor = frame()->contentRenderer()->compositor();
     83         ASSERT(compositor);
     84         ASSERT(compositor->scrollLayer());
     85 
     86         WebLayer* webScrollLayer = compositor->scrollLayer()->platformLayer();
     87         return webScrollLayer;
     88     }
     89 
     90     WebViewImpl* webViewImpl() const { return m_helper.webViewImpl(); }
     91     LocalFrame* frame() const { return m_helper.webViewImpl()->mainFrameImpl()->frame(); }
     92 
     93 protected:
     94     std::string m_baseURL;
     95     FrameTestHelpers::TestWebViewClient m_mockWebViewClient;
     96 
     97 private:
     98     static void configureSettings(WebSettings* settings)
     99     {
    100         settings->setJavaScriptEnabled(true);
    101         settings->setAcceleratedCompositingEnabled(true);
    102         settings->setAcceleratedCompositingForFixedPositionEnabled(true);
    103         settings->setAcceleratedCompositingForOverflowScrollEnabled(true);
    104         settings->setCompositedScrollingForFramesEnabled(true);
    105     }
    106 
    107     FrameTestHelpers::WebViewHelper m_helper;
    108 };
    109 
    110 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingByDefault)
    111 {
    112     navigateTo("about:blank");
    113     forceFullCompositingUpdate();
    114 
    115     // Make sure the scrolling coordinator is active.
    116     FrameView* frameView = frame()->view();
    117     Page* page = frame()->page();
    118     ASSERT_TRUE(page->scrollingCoordinator());
    119     ASSERT_TRUE(page->scrollingCoordinator()->coordinatesScrollingForFrameView(frameView));
    120 
    121     // Fast scrolling should be enabled by default.
    122     WebLayer* rootScrollLayer = getRootScrollLayer();
    123     ASSERT_TRUE(rootScrollLayer->scrollable());
    124     ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
    125     ASSERT_FALSE(rootScrollLayer->haveWheelEventHandlers());
    126 }
    127 
    128 static WebLayer* webLayerFromElement(Element* element)
    129 {
    130     if (!element)
    131         return 0;
    132     RenderObject* renderer = element->renderer();
    133     if (!renderer || !renderer->isBoxModelObject())
    134         return 0;
    135     RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
    136     if (!layer)
    137         return 0;
    138     if (!layer->hasCompositedLayerMapping())
    139         return 0;
    140     CompositedLayerMappingPtr compositedLayerMapping = layer->compositedLayerMapping();
    141     GraphicsLayer* graphicsLayer = compositedLayerMapping->mainGraphicsLayer();
    142     if (!graphicsLayer)
    143         return 0;
    144     return graphicsLayer->platformLayer();
    145 }
    146 
    147 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingForFixedPosition)
    148 {
    149     registerMockedHttpURLLoad("fixed-position.html");
    150     navigateTo(m_baseURL + "fixed-position.html");
    151     forceFullCompositingUpdate();
    152 
    153     // Fixed position should not fall back to main thread scrolling.
    154     WebLayer* rootScrollLayer = getRootScrollLayer();
    155     ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
    156 
    157     Document* document = frame()->document();
    158     {
    159         Element* element = document->getElementById("div-tl");
    160         ASSERT_TRUE(element);
    161         WebLayer* layer = webLayerFromElement(element);
    162         ASSERT_TRUE(layer);
    163         WebLayerPositionConstraint constraint = layer->positionConstraint();
    164         ASSERT_TRUE(constraint.isFixedPosition);
    165         ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
    166     }
    167     {
    168         Element* element = document->getElementById("div-tr");
    169         ASSERT_TRUE(element);
    170         WebLayer* layer = webLayerFromElement(element);
    171         ASSERT_TRUE(layer);
    172         WebLayerPositionConstraint constraint = layer->positionConstraint();
    173         ASSERT_TRUE(constraint.isFixedPosition);
    174         ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
    175     }
    176     {
    177         Element* element = document->getElementById("div-bl");
    178         ASSERT_TRUE(element);
    179         WebLayer* layer = webLayerFromElement(element);
    180         ASSERT_TRUE(layer);
    181         WebLayerPositionConstraint constraint = layer->positionConstraint();
    182         ASSERT_TRUE(constraint.isFixedPosition);
    183         ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
    184     }
    185     {
    186         Element* element = document->getElementById("div-br");
    187         ASSERT_TRUE(element);
    188         WebLayer* layer = webLayerFromElement(element);
    189         ASSERT_TRUE(layer);
    190         WebLayerPositionConstraint constraint = layer->positionConstraint();
    191         ASSERT_TRUE(constraint.isFixedPosition);
    192         ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
    193     }
    194     {
    195         Element* element = document->getElementById("span-tl");
    196         ASSERT_TRUE(element);
    197         WebLayer* layer = webLayerFromElement(element);
    198         ASSERT_TRUE(layer);
    199         WebLayerPositionConstraint constraint = layer->positionConstraint();
    200         ASSERT_TRUE(constraint.isFixedPosition);
    201         ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
    202     }
    203     {
    204         Element* element = document->getElementById("span-tr");
    205         ASSERT_TRUE(element);
    206         WebLayer* layer = webLayerFromElement(element);
    207         ASSERT_TRUE(layer);
    208         WebLayerPositionConstraint constraint = layer->positionConstraint();
    209         ASSERT_TRUE(constraint.isFixedPosition);
    210         ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
    211     }
    212     {
    213         Element* element = document->getElementById("span-bl");
    214         ASSERT_TRUE(element);
    215         WebLayer* layer = webLayerFromElement(element);
    216         ASSERT_TRUE(layer);
    217         WebLayerPositionConstraint constraint = layer->positionConstraint();
    218         ASSERT_TRUE(constraint.isFixedPosition);
    219         ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
    220     }
    221     {
    222         Element* element = document->getElementById("span-br");
    223         ASSERT_TRUE(element);
    224         WebLayer* layer = webLayerFromElement(element);
    225         ASSERT_TRUE(layer);
    226         WebLayerPositionConstraint constraint = layer->positionConstraint();
    227         ASSERT_TRUE(constraint.isFixedPosition);
    228         ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
    229     }
    230 }
    231 
    232 TEST_F(ScrollingCoordinatorChromiumTest, wheelEventHandler)
    233 {
    234     registerMockedHttpURLLoad("wheel-event-handler.html");
    235     navigateTo(m_baseURL + "wheel-event-handler.html");
    236     forceFullCompositingUpdate();
    237 
    238     WebLayer* rootScrollLayer = getRootScrollLayer();
    239     ASSERT_TRUE(rootScrollLayer->haveWheelEventHandlers());
    240 }
    241 
    242 TEST_F(ScrollingCoordinatorChromiumTest, scrollEventHandler)
    243 {
    244     registerMockedHttpURLLoad("scroll-event-handler.html");
    245     navigateTo(m_baseURL + "scroll-event-handler.html");
    246     forceFullCompositingUpdate();
    247 
    248     WebLayer* rootScrollLayer = getRootScrollLayer();
    249     ASSERT_TRUE(rootScrollLayer->haveScrollEventHandlers());
    250 }
    251 
    252 TEST_F(ScrollingCoordinatorChromiumTest, updateEventHandlersDuringTeardown)
    253 {
    254     registerMockedHttpURLLoad("scroll-event-handler-window.html");
    255     navigateTo(m_baseURL + "scroll-event-handler-window.html");
    256     forceFullCompositingUpdate();
    257 
    258     // Simulate detaching the document from its DOM window. This should not
    259     // cause a crash when the WebViewImpl is closed by the test runner.
    260     frame()->document()->prepareForDestruction();
    261 }
    262 
    263 TEST_F(ScrollingCoordinatorChromiumTest, clippedBodyTest)
    264 {
    265     registerMockedHttpURLLoad("clipped-body.html");
    266     navigateTo(m_baseURL + "clipped-body.html");
    267     forceFullCompositingUpdate();
    268 
    269     WebLayer* rootScrollLayer = getRootScrollLayer();
    270     ASSERT_EQ(0u, rootScrollLayer->nonFastScrollableRegion().size());
    271 }
    272 
    273 TEST_F(ScrollingCoordinatorChromiumTest, overflowScrolling)
    274 {
    275     registerMockedHttpURLLoad("overflow-scrolling.html");
    276     navigateTo(m_baseURL + "overflow-scrolling.html");
    277     forceFullCompositingUpdate();
    278 
    279     // Verify the properties of the accelerated scrolling element starting from the RenderObject
    280     // all the way to the WebLayer.
    281     Element* scrollableElement = frame()->document()->getElementById("scrollable");
    282     ASSERT(scrollableElement);
    283 
    284     RenderObject* renderer = scrollableElement->renderer();
    285     ASSERT_TRUE(renderer->isBox());
    286     ASSERT_TRUE(renderer->hasLayer());
    287 
    288     RenderBox* box = toRenderBox(renderer);
    289     ASSERT_TRUE(box->usesCompositedScrolling());
    290     ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
    291 
    292     CompositedLayerMappingPtr compositedLayerMapping = box->layer()->compositedLayerMapping();
    293     ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
    294     ASSERT(compositedLayerMapping->scrollingContentsLayer());
    295 
    296     GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
    297     ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
    298 
    299     WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
    300     ASSERT_TRUE(webScrollLayer->scrollable());
    301     ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
    302     ASSERT_TRUE(webScrollLayer->userScrollableVertical());
    303 
    304 #if OS(ANDROID)
    305     // Now verify we've attached impl-side scrollbars onto the scrollbar layers
    306     ASSERT_TRUE(compositedLayerMapping->layerForHorizontalScrollbar());
    307     ASSERT_TRUE(compositedLayerMapping->layerForHorizontalScrollbar()->hasContentsLayer());
    308     ASSERT_TRUE(compositedLayerMapping->layerForVerticalScrollbar());
    309     ASSERT_TRUE(compositedLayerMapping->layerForVerticalScrollbar()->hasContentsLayer());
    310 #endif
    311 }
    312 
    313 TEST_F(ScrollingCoordinatorChromiumTest, overflowHidden)
    314 {
    315     registerMockedHttpURLLoad("overflow-hidden.html");
    316     navigateTo(m_baseURL + "overflow-hidden.html");
    317     forceFullCompositingUpdate();
    318 
    319     // Verify the properties of the accelerated scrolling element starting from the RenderObject
    320     // all the way to the WebLayer.
    321     Element* overflowElement = frame()->document()->getElementById("unscrollable-y");
    322     ASSERT(overflowElement);
    323 
    324     RenderObject* renderer = overflowElement->renderer();
    325     ASSERT_TRUE(renderer->isBox());
    326     ASSERT_TRUE(renderer->hasLayer());
    327 
    328     RenderBox* box = toRenderBox(renderer);
    329     ASSERT_TRUE(box->usesCompositedScrolling());
    330     ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
    331 
    332     CompositedLayerMappingPtr compositedLayerMapping = box->layer()->compositedLayerMapping();
    333     ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
    334     ASSERT(compositedLayerMapping->scrollingContentsLayer());
    335 
    336     GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
    337     ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
    338 
    339     WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
    340     ASSERT_TRUE(webScrollLayer->scrollable());
    341     ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
    342     ASSERT_FALSE(webScrollLayer->userScrollableVertical());
    343 
    344     overflowElement = frame()->document()->getElementById("unscrollable-x");
    345     ASSERT(overflowElement);
    346 
    347     renderer = overflowElement->renderer();
    348     ASSERT_TRUE(renderer->isBox());
    349     ASSERT_TRUE(renderer->hasLayer());
    350 
    351     box = toRenderBox(renderer);
    352     ASSERT_TRUE(box->scrollableArea()->usesCompositedScrolling());
    353     ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
    354 
    355     compositedLayerMapping = box->layer()->compositedLayerMapping();
    356     ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
    357     ASSERT(compositedLayerMapping->scrollingContentsLayer());
    358 
    359     graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
    360     ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
    361 
    362     webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
    363     ASSERT_TRUE(webScrollLayer->scrollable());
    364     ASSERT_FALSE(webScrollLayer->userScrollableHorizontal());
    365     ASSERT_TRUE(webScrollLayer->userScrollableVertical());
    366 }
    367 
    368 TEST_F(ScrollingCoordinatorChromiumTest, iframeScrolling)
    369 {
    370     registerMockedHttpURLLoad("iframe-scrolling.html");
    371     registerMockedHttpURLLoad("iframe-scrolling-inner.html");
    372     navigateTo(m_baseURL + "iframe-scrolling.html");
    373     forceFullCompositingUpdate();
    374 
    375     // Verify the properties of the accelerated scrolling element starting from the RenderObject
    376     // all the way to the WebLayer.
    377     Element* scrollableFrame = frame()->document()->getElementById("scrollable");
    378     ASSERT_TRUE(scrollableFrame);
    379 
    380     RenderObject* renderer = scrollableFrame->renderer();
    381     ASSERT_TRUE(renderer);
    382     ASSERT_TRUE(renderer->isWidget());
    383 
    384     RenderWidget* renderWidget = toRenderWidget(renderer);
    385     ASSERT_TRUE(renderWidget);
    386     ASSERT_TRUE(renderWidget->widget());
    387     ASSERT_TRUE(renderWidget->widget()->isFrameView());
    388 
    389     FrameView* innerFrameView = toFrameView(renderWidget->widget());
    390     RenderView* innerRenderView = innerFrameView->renderView();
    391     ASSERT_TRUE(innerRenderView);
    392 
    393     RenderLayerCompositor* innerCompositor = innerRenderView->compositor();
    394     ASSERT_TRUE(innerCompositor->inCompositingMode());
    395     ASSERT_TRUE(innerCompositor->scrollLayer());
    396 
    397     GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
    398     ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());
    399 
    400     WebLayer* webScrollLayer = scrollLayer->platformLayer();
    401     ASSERT_TRUE(webScrollLayer->scrollable());
    402 
    403 #if OS(ANDROID)
    404     // Now verify we've attached impl-side scrollbars onto the scrollbar layers
    405     ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar());
    406     ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar()->hasContentsLayer());
    407     ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar());
    408     ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar()->hasContentsLayer());
    409 #endif
    410 }
    411 
    412 TEST_F(ScrollingCoordinatorChromiumTest, rtlIframe)
    413 {
    414     registerMockedHttpURLLoad("rtl-iframe.html");
    415     registerMockedHttpURLLoad("rtl-iframe-inner.html");
    416     navigateTo(m_baseURL + "rtl-iframe.html");
    417     forceFullCompositingUpdate();
    418 
    419     // Verify the properties of the accelerated scrolling element starting from the RenderObject
    420     // all the way to the WebLayer.
    421     Element* scrollableFrame = frame()->document()->getElementById("scrollable");
    422     ASSERT_TRUE(scrollableFrame);
    423 
    424     RenderObject* renderer = scrollableFrame->renderer();
    425     ASSERT_TRUE(renderer);
    426     ASSERT_TRUE(renderer->isWidget());
    427 
    428     RenderWidget* renderWidget = toRenderWidget(renderer);
    429     ASSERT_TRUE(renderWidget);
    430     ASSERT_TRUE(renderWidget->widget());
    431     ASSERT_TRUE(renderWidget->widget()->isFrameView());
    432 
    433     FrameView* innerFrameView = toFrameView(renderWidget->widget());
    434     RenderView* innerRenderView = innerFrameView->renderView();
    435     ASSERT_TRUE(innerRenderView);
    436 
    437     RenderLayerCompositor* innerCompositor = innerRenderView->compositor();
    438     ASSERT_TRUE(innerCompositor->inCompositingMode());
    439     ASSERT_TRUE(innerCompositor->scrollLayer());
    440 
    441     GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
    442     ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());
    443 
    444     WebLayer* webScrollLayer = scrollLayer->platformLayer();
    445     ASSERT_TRUE(webScrollLayer->scrollable());
    446 
    447     int expectedScrollPosition = 958 + (innerFrameView->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
    448     ASSERT_EQ(expectedScrollPosition, webScrollLayer->scrollPosition().x);
    449 }
    450 
    451 TEST_F(ScrollingCoordinatorChromiumTest, setupScrollbarLayerShouldNotCrash)
    452 {
    453     registerMockedHttpURLLoad("setup_scrollbar_layer_crash.html");
    454     navigateTo(m_baseURL + "setup_scrollbar_layer_crash.html");
    455     forceFullCompositingUpdate();
    456     // This test document setup an iframe with scrollbars, then switch to
    457     // an empty document by javascript.
    458 }
    459 
    460 } // namespace
    461