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