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/page/Page.h"
30 #include "core/rendering/RenderView.h"
31 #include "core/rendering/RenderWidget.h"
32 #include "core/rendering/compositing/CompositedLayerMapping.h"
33 #include "core/rendering/compositing/RenderLayerCompositor.h"
34 #include "core/testing/URLTestHelpers.h"
35 #include "platform/graphics/GraphicsLayer.h"
36 #include "public/platform/Platform.h"
37 #include "public/platform/WebLayer.h"
38 #include "public/platform/WebLayerPositionConstraint.h"
39 #include "public/platform/WebLayerTreeView.h"
40 #include "public/platform/WebUnitTestSupport.h"
41 #include "public/web/WebSettings.h"
42 #include "public/web/WebViewClient.h"
43 #include "web/WebLocalFrameImpl.h"
44 #include "web/WebViewImpl.h"
45 #include "web/tests/FrameTestHelpers.h"
46 #include <gtest/gtest.h>
48 using namespace blink;
52 class ScrollingCoordinatorChromiumTest : public testing::Test {
54 ScrollingCoordinatorChromiumTest()
55 : m_baseURL("http://www.test.com/")
57 m_helper.initialize(true, 0, &m_mockWebViewClient, &configureSettings);
58 webViewImpl()->resize(IntSize(320, 240));
61 virtual ~ScrollingCoordinatorChromiumTest()
63 Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
66 void navigateTo(const std::string& url)
68 FrameTestHelpers::loadFrame(webViewImpl()->mainFrame(), url);
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->setAcceleratedCompositingEnabled(true);
103 settings->setPreferCompositingToLCDTextEnabled(true);
106 FrameTestHelpers::WebViewHelper m_helper;
109 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingByDefault)
111 navigateTo("about:blank");
112 forceFullCompositingUpdate();
114 // Make sure the scrolling coordinator is active.
115 FrameView* frameView = frame()->view();
116 Page* page = frame()->page();
117 ASSERT_TRUE(page->scrollingCoordinator());
118 ASSERT_TRUE(page->scrollingCoordinator()->coordinatesScrollingForFrameView(frameView));
120 // Fast scrolling should be enabled by default.
121 WebLayer* rootScrollLayer = getRootScrollLayer();
122 ASSERT_TRUE(rootScrollLayer->scrollable());
123 ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
124 ASSERT_FALSE(rootScrollLayer->haveWheelEventHandlers());
127 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingCanBeDisabledWithSetting)
129 navigateTo("about:blank");
130 webViewImpl()->settings()->setThreadedScrollingEnabled(false);
131 forceFullCompositingUpdate();
133 // Make sure the scrolling coordinator is active.
134 FrameView* frameView = frame()->view();
135 Page* page = frame()->page();
136 ASSERT_TRUE(page->scrollingCoordinator());
137 ASSERT_TRUE(page->scrollingCoordinator()->coordinatesScrollingForFrameView(frameView));
139 // Main scrolling should be enabled with the setting override.
140 WebLayer* rootScrollLayer = getRootScrollLayer();
141 ASSERT_TRUE(rootScrollLayer->scrollable());
142 ASSERT_TRUE(rootScrollLayer->shouldScrollOnMainThread());
145 static WebLayer* webLayerFromElement(Element* element)
149 RenderObject* renderer = element->renderer();
150 if (!renderer || !renderer->isBoxModelObject())
152 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
155 if (!layer->hasCompositedLayerMapping())
157 CompositedLayerMapping* compositedLayerMapping = layer->compositedLayerMapping();
158 GraphicsLayer* graphicsLayer = compositedLayerMapping->mainGraphicsLayer();
161 return graphicsLayer->platformLayer();
164 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingForFixedPosition)
166 registerMockedHttpURLLoad("fixed-position.html");
167 navigateTo(m_baseURL + "fixed-position.html");
168 forceFullCompositingUpdate();
170 // Fixed position should not fall back to main thread scrolling.
171 WebLayer* rootScrollLayer = getRootScrollLayer();
172 ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
174 Document* document = frame()->document();
176 Element* element = document->getElementById("div-tl");
177 ASSERT_TRUE(element);
178 WebLayer* layer = webLayerFromElement(element);
180 WebLayerPositionConstraint constraint = layer->positionConstraint();
181 ASSERT_TRUE(constraint.isFixedPosition);
182 ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
185 Element* element = document->getElementById("div-tr");
186 ASSERT_TRUE(element);
187 WebLayer* layer = webLayerFromElement(element);
189 WebLayerPositionConstraint constraint = layer->positionConstraint();
190 ASSERT_TRUE(constraint.isFixedPosition);
191 ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
194 Element* element = document->getElementById("div-bl");
195 ASSERT_TRUE(element);
196 WebLayer* layer = webLayerFromElement(element);
198 WebLayerPositionConstraint constraint = layer->positionConstraint();
199 ASSERT_TRUE(constraint.isFixedPosition);
200 ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
203 Element* element = document->getElementById("div-br");
204 ASSERT_TRUE(element);
205 WebLayer* layer = webLayerFromElement(element);
207 WebLayerPositionConstraint constraint = layer->positionConstraint();
208 ASSERT_TRUE(constraint.isFixedPosition);
209 ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
212 Element* element = document->getElementById("span-tl");
213 ASSERT_TRUE(element);
214 WebLayer* layer = webLayerFromElement(element);
216 WebLayerPositionConstraint constraint = layer->positionConstraint();
217 ASSERT_TRUE(constraint.isFixedPosition);
218 ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
221 Element* element = document->getElementById("span-tr");
222 ASSERT_TRUE(element);
223 WebLayer* layer = webLayerFromElement(element);
225 WebLayerPositionConstraint constraint = layer->positionConstraint();
226 ASSERT_TRUE(constraint.isFixedPosition);
227 ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
230 Element* element = document->getElementById("span-bl");
231 ASSERT_TRUE(element);
232 WebLayer* layer = webLayerFromElement(element);
234 WebLayerPositionConstraint constraint = layer->positionConstraint();
235 ASSERT_TRUE(constraint.isFixedPosition);
236 ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
239 Element* element = document->getElementById("span-br");
240 ASSERT_TRUE(element);
241 WebLayer* layer = webLayerFromElement(element);
243 WebLayerPositionConstraint constraint = layer->positionConstraint();
244 ASSERT_TRUE(constraint.isFixedPosition);
245 ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
249 TEST_F(ScrollingCoordinatorChromiumTest, wheelEventHandler)
251 registerMockedHttpURLLoad("wheel-event-handler.html");
252 navigateTo(m_baseURL + "wheel-event-handler.html");
253 forceFullCompositingUpdate();
255 WebLayer* rootScrollLayer = getRootScrollLayer();
256 ASSERT_TRUE(rootScrollLayer->haveWheelEventHandlers());
259 TEST_F(ScrollingCoordinatorChromiumTest, scrollEventHandler)
261 registerMockedHttpURLLoad("scroll-event-handler.html");
262 navigateTo(m_baseURL + "scroll-event-handler.html");
263 forceFullCompositingUpdate();
265 WebLayer* rootScrollLayer = getRootScrollLayer();
266 ASSERT_TRUE(rootScrollLayer->haveScrollEventHandlers());
269 TEST_F(ScrollingCoordinatorChromiumTest, updateEventHandlersDuringTeardown)
271 registerMockedHttpURLLoad("scroll-event-handler-window.html");
272 navigateTo(m_baseURL + "scroll-event-handler-window.html");
273 forceFullCompositingUpdate();
275 // Simulate detaching the document from its DOM window. This should not
276 // cause a crash when the WebViewImpl is closed by the test runner.
277 frame()->document()->prepareForDestruction();
280 TEST_F(ScrollingCoordinatorChromiumTest, clippedBodyTest)
282 registerMockedHttpURLLoad("clipped-body.html");
283 navigateTo(m_baseURL + "clipped-body.html");
284 forceFullCompositingUpdate();
286 WebLayer* rootScrollLayer = getRootScrollLayer();
287 ASSERT_EQ(0u, rootScrollLayer->nonFastScrollableRegion().size());
290 TEST_F(ScrollingCoordinatorChromiumTest, overflowScrolling)
292 registerMockedHttpURLLoad("overflow-scrolling.html");
293 navigateTo(m_baseURL + "overflow-scrolling.html");
294 forceFullCompositingUpdate();
296 // Verify the properties of the accelerated scrolling element starting from the RenderObject
297 // all the way to the WebLayer.
298 Element* scrollableElement = frame()->document()->getElementById("scrollable");
299 ASSERT(scrollableElement);
301 RenderObject* renderer = scrollableElement->renderer();
302 ASSERT_TRUE(renderer->isBox());
303 ASSERT_TRUE(renderer->hasLayer());
305 RenderBox* box = toRenderBox(renderer);
306 ASSERT_TRUE(box->usesCompositedScrolling());
307 ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
309 CompositedLayerMapping* compositedLayerMapping = box->layer()->compositedLayerMapping();
310 ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
311 ASSERT(compositedLayerMapping->scrollingContentsLayer());
313 GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
314 ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
316 WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
317 ASSERT_TRUE(webScrollLayer->scrollable());
318 ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
319 ASSERT_TRUE(webScrollLayer->userScrollableVertical());
322 // Now verify we've attached impl-side scrollbars onto the scrollbar layers
323 ASSERT_TRUE(compositedLayerMapping->layerForHorizontalScrollbar());
324 ASSERT_TRUE(compositedLayerMapping->layerForHorizontalScrollbar()->hasContentsLayer());
325 ASSERT_TRUE(compositedLayerMapping->layerForVerticalScrollbar());
326 ASSERT_TRUE(compositedLayerMapping->layerForVerticalScrollbar()->hasContentsLayer());
330 TEST_F(ScrollingCoordinatorChromiumTest, overflowHidden)
332 registerMockedHttpURLLoad("overflow-hidden.html");
333 navigateTo(m_baseURL + "overflow-hidden.html");
334 forceFullCompositingUpdate();
336 // Verify the properties of the accelerated scrolling element starting from the RenderObject
337 // all the way to the WebLayer.
338 Element* overflowElement = frame()->document()->getElementById("unscrollable-y");
339 ASSERT(overflowElement);
341 RenderObject* renderer = overflowElement->renderer();
342 ASSERT_TRUE(renderer->isBox());
343 ASSERT_TRUE(renderer->hasLayer());
345 RenderBox* box = toRenderBox(renderer);
346 ASSERT_TRUE(box->usesCompositedScrolling());
347 ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
349 CompositedLayerMapping* compositedLayerMapping = box->layer()->compositedLayerMapping();
350 ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
351 ASSERT(compositedLayerMapping->scrollingContentsLayer());
353 GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
354 ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
356 WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
357 ASSERT_TRUE(webScrollLayer->scrollable());
358 ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
359 ASSERT_FALSE(webScrollLayer->userScrollableVertical());
361 overflowElement = frame()->document()->getElementById("unscrollable-x");
362 ASSERT(overflowElement);
364 renderer = overflowElement->renderer();
365 ASSERT_TRUE(renderer->isBox());
366 ASSERT_TRUE(renderer->hasLayer());
368 box = toRenderBox(renderer);
369 ASSERT_TRUE(box->scrollableArea()->usesCompositedScrolling());
370 ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
372 compositedLayerMapping = box->layer()->compositedLayerMapping();
373 ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
374 ASSERT(compositedLayerMapping->scrollingContentsLayer());
376 graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
377 ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
379 webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
380 ASSERT_TRUE(webScrollLayer->scrollable());
381 ASSERT_FALSE(webScrollLayer->userScrollableHorizontal());
382 ASSERT_TRUE(webScrollLayer->userScrollableVertical());
385 TEST_F(ScrollingCoordinatorChromiumTest, iframeScrolling)
387 registerMockedHttpURLLoad("iframe-scrolling.html");
388 registerMockedHttpURLLoad("iframe-scrolling-inner.html");
389 navigateTo(m_baseURL + "iframe-scrolling.html");
390 forceFullCompositingUpdate();
392 // Verify the properties of the accelerated scrolling element starting from the RenderObject
393 // all the way to the WebLayer.
394 Element* scrollableFrame = frame()->document()->getElementById("scrollable");
395 ASSERT_TRUE(scrollableFrame);
397 RenderObject* renderer = scrollableFrame->renderer();
398 ASSERT_TRUE(renderer);
399 ASSERT_TRUE(renderer->isWidget());
401 RenderWidget* renderWidget = toRenderWidget(renderer);
402 ASSERT_TRUE(renderWidget);
403 ASSERT_TRUE(renderWidget->widget());
404 ASSERT_TRUE(renderWidget->widget()->isFrameView());
406 FrameView* innerFrameView = toFrameView(renderWidget->widget());
407 RenderView* innerRenderView = innerFrameView->renderView();
408 ASSERT_TRUE(innerRenderView);
410 RenderLayerCompositor* innerCompositor = innerRenderView->compositor();
411 ASSERT_TRUE(innerCompositor->inCompositingMode());
412 ASSERT_TRUE(innerCompositor->scrollLayer());
414 GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
415 ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());
417 WebLayer* webScrollLayer = scrollLayer->platformLayer();
418 ASSERT_TRUE(webScrollLayer->scrollable());
421 // Now verify we've attached impl-side scrollbars onto the scrollbar layers
422 ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar());
423 ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar()->hasContentsLayer());
424 ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar());
425 ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar()->hasContentsLayer());
429 TEST_F(ScrollingCoordinatorChromiumTest, rtlIframe)
431 registerMockedHttpURLLoad("rtl-iframe.html");
432 registerMockedHttpURLLoad("rtl-iframe-inner.html");
433 navigateTo(m_baseURL + "rtl-iframe.html");
434 forceFullCompositingUpdate();
436 // Verify the properties of the accelerated scrolling element starting from the RenderObject
437 // all the way to the WebLayer.
438 Element* scrollableFrame = frame()->document()->getElementById("scrollable");
439 ASSERT_TRUE(scrollableFrame);
441 RenderObject* renderer = scrollableFrame->renderer();
442 ASSERT_TRUE(renderer);
443 ASSERT_TRUE(renderer->isWidget());
445 RenderWidget* renderWidget = toRenderWidget(renderer);
446 ASSERT_TRUE(renderWidget);
447 ASSERT_TRUE(renderWidget->widget());
448 ASSERT_TRUE(renderWidget->widget()->isFrameView());
450 FrameView* innerFrameView = toFrameView(renderWidget->widget());
451 RenderView* innerRenderView = innerFrameView->renderView();
452 ASSERT_TRUE(innerRenderView);
454 RenderLayerCompositor* innerCompositor = innerRenderView->compositor();
455 ASSERT_TRUE(innerCompositor->inCompositingMode());
456 ASSERT_TRUE(innerCompositor->scrollLayer());
458 GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
459 ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());
461 WebLayer* webScrollLayer = scrollLayer->platformLayer();
462 ASSERT_TRUE(webScrollLayer->scrollable());
464 int expectedScrollPosition = 958 + (innerFrameView->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
465 ASSERT_EQ(expectedScrollPosition, webScrollLayer->scrollPosition().x);
468 TEST_F(ScrollingCoordinatorChromiumTest, setupScrollbarLayerShouldNotCrash)
470 registerMockedHttpURLLoad("setup_scrollbar_layer_crash.html");
471 navigateTo(m_baseURL + "setup_scrollbar_layer_crash.html");
472 forceFullCompositingUpdate();
473 // This test document setup an iframe with scrollbars, then switch to
474 // an empty document by javascript.