2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "core/page/scrolling/ScrollingCoordinator.h"
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>
46 using namespace WebCore;
47 using namespace blink;
51 class ScrollingCoordinatorChromiumTest : public testing::Test {
53 ScrollingCoordinatorChromiumTest()
54 : m_baseURL("http://www.test.com/")
56 m_helper.initialize(true, 0, &m_mockWebViewClient, &configureSettings);
57 webViewImpl()->resize(IntSize(320, 240));
60 virtual ~ScrollingCoordinatorChromiumTest()
62 Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
65 void navigateTo(const std::string& url)
67 FrameTestHelpers::loadFrame(webViewImpl()->mainFrame(), url);
68 Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
71 void forceFullCompositingUpdate()
73 webViewImpl()->layout();
76 void registerMockedHttpURLLoad(const std::string& fileName)
78 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str()));
81 WebLayer* getRootScrollLayer()
83 RenderLayerCompositor* compositor = frame()->contentRenderer()->compositor();
85 ASSERT(compositor->scrollLayer());
87 WebLayer* webScrollLayer = compositor->scrollLayer()->platformLayer();
88 return webScrollLayer;
91 WebViewImpl* webViewImpl() const { return m_helper.webViewImpl(); }
92 LocalFrame* frame() const { return m_helper.webViewImpl()->mainFrameImpl()->frame(); }
95 std::string m_baseURL;
96 FrameTestHelpers::TestWebViewClient m_mockWebViewClient;
99 static void configureSettings(WebSettings* settings)
101 settings->setJavaScriptEnabled(true);
102 settings->setForceCompositingMode(true);
103 settings->setAcceleratedCompositingEnabled(true);
104 settings->setAcceleratedCompositingForFixedPositionEnabled(true);
105 settings->setAcceleratedCompositingForOverflowScrollEnabled(true);
106 settings->setCompositedScrollingForFramesEnabled(true);
109 FrameTestHelpers::WebViewHelper m_helper;
112 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingByDefault)
114 navigateTo("about:blank");
115 forceFullCompositingUpdate();
117 // Make sure the scrolling coordinator is active.
118 FrameView* frameView = frame()->view();
119 Page* page = frame()->page();
120 ASSERT_TRUE(page->scrollingCoordinator());
121 ASSERT_TRUE(page->scrollingCoordinator()->coordinatesScrollingForFrameView(frameView));
123 // Fast scrolling should be enabled by default.
124 WebLayer* rootScrollLayer = getRootScrollLayer();
125 ASSERT_TRUE(rootScrollLayer->scrollable());
126 ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
127 ASSERT_FALSE(rootScrollLayer->haveWheelEventHandlers());
130 static WebLayer* webLayerFromElement(Element* element)
134 RenderObject* renderer = element->renderer();
135 if (!renderer || !renderer->isBoxModelObject())
137 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
140 if (!layer->hasCompositedLayerMapping())
142 CompositedLayerMappingPtr compositedLayerMapping = layer->compositedLayerMapping();
143 GraphicsLayer* graphicsLayer = compositedLayerMapping->mainGraphicsLayer();
146 return graphicsLayer->platformLayer();
149 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingForFixedPosition)
151 registerMockedHttpURLLoad("fixed-position.html");
152 navigateTo(m_baseURL + "fixed-position.html");
153 forceFullCompositingUpdate();
155 // Fixed position should not fall back to main thread scrolling.
156 WebLayer* rootScrollLayer = getRootScrollLayer();
157 ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
159 Document* document = frame()->document();
161 Element* element = document->getElementById("div-tl");
162 ASSERT_TRUE(element);
163 WebLayer* layer = webLayerFromElement(element);
165 WebLayerPositionConstraint constraint = layer->positionConstraint();
166 ASSERT_TRUE(constraint.isFixedPosition);
167 ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
170 Element* element = document->getElementById("div-tr");
171 ASSERT_TRUE(element);
172 WebLayer* layer = webLayerFromElement(element);
174 WebLayerPositionConstraint constraint = layer->positionConstraint();
175 ASSERT_TRUE(constraint.isFixedPosition);
176 ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
179 Element* element = document->getElementById("div-bl");
180 ASSERT_TRUE(element);
181 WebLayer* layer = webLayerFromElement(element);
183 WebLayerPositionConstraint constraint = layer->positionConstraint();
184 ASSERT_TRUE(constraint.isFixedPosition);
185 ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
188 Element* element = document->getElementById("div-br");
189 ASSERT_TRUE(element);
190 WebLayer* layer = webLayerFromElement(element);
192 WebLayerPositionConstraint constraint = layer->positionConstraint();
193 ASSERT_TRUE(constraint.isFixedPosition);
194 ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
197 Element* element = document->getElementById("span-tl");
198 ASSERT_TRUE(element);
199 WebLayer* layer = webLayerFromElement(element);
201 WebLayerPositionConstraint constraint = layer->positionConstraint();
202 ASSERT_TRUE(constraint.isFixedPosition);
203 ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
206 Element* element = document->getElementById("span-tr");
207 ASSERT_TRUE(element);
208 WebLayer* layer = webLayerFromElement(element);
210 WebLayerPositionConstraint constraint = layer->positionConstraint();
211 ASSERT_TRUE(constraint.isFixedPosition);
212 ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
215 Element* element = document->getElementById("span-bl");
216 ASSERT_TRUE(element);
217 WebLayer* layer = webLayerFromElement(element);
219 WebLayerPositionConstraint constraint = layer->positionConstraint();
220 ASSERT_TRUE(constraint.isFixedPosition);
221 ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
224 Element* element = document->getElementById("span-br");
225 ASSERT_TRUE(element);
226 WebLayer* layer = webLayerFromElement(element);
228 WebLayerPositionConstraint constraint = layer->positionConstraint();
229 ASSERT_TRUE(constraint.isFixedPosition);
230 ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
234 TEST_F(ScrollingCoordinatorChromiumTest, wheelEventHandler)
236 registerMockedHttpURLLoad("wheel-event-handler.html");
237 navigateTo(m_baseURL + "wheel-event-handler.html");
238 forceFullCompositingUpdate();
240 WebLayer* rootScrollLayer = getRootScrollLayer();
241 ASSERT_TRUE(rootScrollLayer->haveWheelEventHandlers());
244 TEST_F(ScrollingCoordinatorChromiumTest, scrollEventHandler)
246 registerMockedHttpURLLoad("scroll-event-handler.html");
247 navigateTo(m_baseURL + "scroll-event-handler.html");
248 forceFullCompositingUpdate();
250 WebLayer* rootScrollLayer = getRootScrollLayer();
251 ASSERT_TRUE(rootScrollLayer->haveScrollEventHandlers());
254 TEST_F(ScrollingCoordinatorChromiumTest, clippedBodyTest)
256 registerMockedHttpURLLoad("clipped-body.html");
257 navigateTo(m_baseURL + "clipped-body.html");
258 forceFullCompositingUpdate();
260 WebLayer* rootScrollLayer = getRootScrollLayer();
261 ASSERT_EQ(0u, rootScrollLayer->nonFastScrollableRegion().size());
264 TEST_F(ScrollingCoordinatorChromiumTest, overflowScrolling)
266 registerMockedHttpURLLoad("overflow-scrolling.html");
267 navigateTo(m_baseURL + "overflow-scrolling.html");
268 forceFullCompositingUpdate();
270 // Verify the properties of the accelerated scrolling element starting from the RenderObject
271 // all the way to the WebLayer.
272 Element* scrollableElement = frame()->document()->getElementById("scrollable");
273 ASSERT(scrollableElement);
275 RenderObject* renderer = scrollableElement->renderer();
276 ASSERT_TRUE(renderer->isBox());
277 ASSERT_TRUE(renderer->hasLayer());
279 RenderBox* box = toRenderBox(renderer);
280 ASSERT_TRUE(box->usesCompositedScrolling());
281 ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
283 CompositedLayerMappingPtr compositedLayerMapping = box->layer()->compositedLayerMapping();
284 ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
285 ASSERT(compositedLayerMapping->scrollingContentsLayer());
287 GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
288 ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
290 WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
291 ASSERT_TRUE(webScrollLayer->scrollable());
292 ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
293 ASSERT_TRUE(webScrollLayer->userScrollableVertical());
296 // Now verify we've attached impl-side scrollbars onto the scrollbar layers
297 ASSERT_TRUE(compositedLayerMapping->layerForHorizontalScrollbar());
298 ASSERT_TRUE(compositedLayerMapping->layerForHorizontalScrollbar()->hasContentsLayer());
299 ASSERT_TRUE(compositedLayerMapping->layerForVerticalScrollbar());
300 ASSERT_TRUE(compositedLayerMapping->layerForVerticalScrollbar()->hasContentsLayer());
304 TEST_F(ScrollingCoordinatorChromiumTest, overflowHidden)
306 registerMockedHttpURLLoad("overflow-hidden.html");
307 navigateTo(m_baseURL + "overflow-hidden.html");
308 forceFullCompositingUpdate();
310 // Verify the properties of the accelerated scrolling element starting from the RenderObject
311 // all the way to the WebLayer.
312 Element* overflowElement = frame()->document()->getElementById("unscrollable-y");
313 ASSERT(overflowElement);
315 RenderObject* renderer = overflowElement->renderer();
316 ASSERT_TRUE(renderer->isBox());
317 ASSERT_TRUE(renderer->hasLayer());
319 RenderBox* box = toRenderBox(renderer);
320 ASSERT_TRUE(box->usesCompositedScrolling());
321 ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
323 CompositedLayerMappingPtr compositedLayerMapping = box->layer()->compositedLayerMapping();
324 ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
325 ASSERT(compositedLayerMapping->scrollingContentsLayer());
327 GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
328 ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
330 WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
331 ASSERT_TRUE(webScrollLayer->scrollable());
332 ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
333 ASSERT_FALSE(webScrollLayer->userScrollableVertical());
335 overflowElement = frame()->document()->getElementById("unscrollable-x");
336 ASSERT(overflowElement);
338 renderer = overflowElement->renderer();
339 ASSERT_TRUE(renderer->isBox());
340 ASSERT_TRUE(renderer->hasLayer());
342 box = toRenderBox(renderer);
343 ASSERT_TRUE(box->scrollableArea()->usesCompositedScrolling());
344 ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
346 compositedLayerMapping = box->layer()->compositedLayerMapping();
347 ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
348 ASSERT(compositedLayerMapping->scrollingContentsLayer());
350 graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
351 ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
353 webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
354 ASSERT_TRUE(webScrollLayer->scrollable());
355 ASSERT_FALSE(webScrollLayer->userScrollableHorizontal());
356 ASSERT_TRUE(webScrollLayer->userScrollableVertical());
359 TEST_F(ScrollingCoordinatorChromiumTest, iframeScrolling)
361 registerMockedHttpURLLoad("iframe-scrolling.html");
362 registerMockedHttpURLLoad("iframe-scrolling-inner.html");
363 navigateTo(m_baseURL + "iframe-scrolling.html");
364 forceFullCompositingUpdate();
366 // Verify the properties of the accelerated scrolling element starting from the RenderObject
367 // all the way to the WebLayer.
368 Element* scrollableFrame = frame()->document()->getElementById("scrollable");
369 ASSERT_TRUE(scrollableFrame);
371 RenderObject* renderer = scrollableFrame->renderer();
372 ASSERT_TRUE(renderer);
373 ASSERT_TRUE(renderer->isWidget());
375 RenderWidget* renderWidget = toRenderWidget(renderer);
376 ASSERT_TRUE(renderWidget);
377 ASSERT_TRUE(renderWidget->widget());
378 ASSERT_TRUE(renderWidget->widget()->isFrameView());
380 FrameView* innerFrameView = toFrameView(renderWidget->widget());
381 RenderView* innerRenderView = innerFrameView->renderView();
382 ASSERT_TRUE(innerRenderView);
384 RenderLayerCompositor* innerCompositor = innerRenderView->compositor();
385 ASSERT_TRUE(innerCompositor->inCompositingMode());
386 ASSERT_TRUE(innerCompositor->scrollLayer());
388 GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
389 ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());
391 WebLayer* webScrollLayer = scrollLayer->platformLayer();
392 ASSERT_TRUE(webScrollLayer->scrollable());
395 // Now verify we've attached impl-side scrollbars onto the scrollbar layers
396 ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar());
397 ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar()->hasContentsLayer());
398 ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar());
399 ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar()->hasContentsLayer());
403 TEST_F(ScrollingCoordinatorChromiumTest, rtlIframe)
405 registerMockedHttpURLLoad("rtl-iframe.html");
406 registerMockedHttpURLLoad("rtl-iframe-inner.html");
407 navigateTo(m_baseURL + "rtl-iframe.html");
408 forceFullCompositingUpdate();
410 // Verify the properties of the accelerated scrolling element starting from the RenderObject
411 // all the way to the WebLayer.
412 Element* scrollableFrame = frame()->document()->getElementById("scrollable");
413 ASSERT_TRUE(scrollableFrame);
415 RenderObject* renderer = scrollableFrame->renderer();
416 ASSERT_TRUE(renderer);
417 ASSERT_TRUE(renderer->isWidget());
419 RenderWidget* renderWidget = toRenderWidget(renderer);
420 ASSERT_TRUE(renderWidget);
421 ASSERT_TRUE(renderWidget->widget());
422 ASSERT_TRUE(renderWidget->widget()->isFrameView());
424 FrameView* innerFrameView = toFrameView(renderWidget->widget());
425 RenderView* innerRenderView = innerFrameView->renderView();
426 ASSERT_TRUE(innerRenderView);
428 RenderLayerCompositor* innerCompositor = innerRenderView->compositor();
429 ASSERT_TRUE(innerCompositor->inCompositingMode());
430 ASSERT_TRUE(innerCompositor->scrollLayer());
432 GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
433 ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());
435 WebLayer* webScrollLayer = scrollLayer->platformLayer();
436 ASSERT_TRUE(webScrollLayer->scrollable());
438 int expectedScrollPosition = 958 + (innerFrameView->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
439 ASSERT_EQ(expectedScrollPosition, webScrollLayer->scrollPosition().x);
442 TEST_F(ScrollingCoordinatorChromiumTest, setupScrollbarLayerShouldNotCrash)
444 registerMockedHttpURLLoad("setup_scrollbar_layer_crash.html");
445 navigateTo(m_baseURL + "setup_scrollbar_layer_crash.html");
446 forceFullCompositingUpdate();
447 // This test document setup an iframe with scrollbars, then switch to
448 // an empty document by javascript.