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);
70 void forceFullCompositingUpdate()
72 webViewImpl()->layout();
75 void registerMockedHttpURLLoad(const std::string& fileName)
77 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str()));
80 WebLayer* getRootScrollLayer()
82 RenderLayerCompositor* compositor = frame()->contentRenderer()->compositor();
84 ASSERT(compositor->scrollLayer());
86 WebLayer* webScrollLayer = compositor->scrollLayer()->platformLayer();
87 return webScrollLayer;
90 WebViewImpl* webViewImpl() const { return m_helper.webViewImpl(); }
91 LocalFrame* frame() const { return m_helper.webViewImpl()->mainFrameImpl()->frame(); }
94 std::string m_baseURL;
95 FrameTestHelpers::TestWebViewClient m_mockWebViewClient;
98 static void configureSettings(WebSettings* settings)
100 settings->setJavaScriptEnabled(true);
101 settings->setAcceleratedCompositingEnabled(true);
102 settings->setAcceleratedCompositingForFixedPositionEnabled(true);
103 settings->setAcceleratedCompositingForOverflowScrollEnabled(true);
104 settings->setCompositedScrollingForFramesEnabled(true);
107 FrameTestHelpers::WebViewHelper m_helper;
110 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingByDefault)
112 navigateTo("about:blank");
113 forceFullCompositingUpdate();
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));
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());
128 static WebLayer* webLayerFromElement(Element* element)
132 RenderObject* renderer = element->renderer();
133 if (!renderer || !renderer->isBoxModelObject())
135 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
138 if (!layer->hasCompositedLayerMapping())
140 CompositedLayerMappingPtr compositedLayerMapping = layer->compositedLayerMapping();
141 GraphicsLayer* graphicsLayer = compositedLayerMapping->mainGraphicsLayer();
144 return graphicsLayer->platformLayer();
147 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingForFixedPosition)
149 registerMockedHttpURLLoad("fixed-position.html");
150 navigateTo(m_baseURL + "fixed-position.html");
151 forceFullCompositingUpdate();
153 // Fixed position should not fall back to main thread scrolling.
154 WebLayer* rootScrollLayer = getRootScrollLayer();
155 ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
157 Document* document = frame()->document();
159 Element* element = document->getElementById("div-tl");
160 ASSERT_TRUE(element);
161 WebLayer* layer = webLayerFromElement(element);
163 WebLayerPositionConstraint constraint = layer->positionConstraint();
164 ASSERT_TRUE(constraint.isFixedPosition);
165 ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
168 Element* element = document->getElementById("div-tr");
169 ASSERT_TRUE(element);
170 WebLayer* layer = webLayerFromElement(element);
172 WebLayerPositionConstraint constraint = layer->positionConstraint();
173 ASSERT_TRUE(constraint.isFixedPosition);
174 ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
177 Element* element = document->getElementById("div-bl");
178 ASSERT_TRUE(element);
179 WebLayer* layer = webLayerFromElement(element);
181 WebLayerPositionConstraint constraint = layer->positionConstraint();
182 ASSERT_TRUE(constraint.isFixedPosition);
183 ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
186 Element* element = document->getElementById("div-br");
187 ASSERT_TRUE(element);
188 WebLayer* layer = webLayerFromElement(element);
190 WebLayerPositionConstraint constraint = layer->positionConstraint();
191 ASSERT_TRUE(constraint.isFixedPosition);
192 ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
195 Element* element = document->getElementById("span-tl");
196 ASSERT_TRUE(element);
197 WebLayer* layer = webLayerFromElement(element);
199 WebLayerPositionConstraint constraint = layer->positionConstraint();
200 ASSERT_TRUE(constraint.isFixedPosition);
201 ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
204 Element* element = document->getElementById("span-tr");
205 ASSERT_TRUE(element);
206 WebLayer* layer = webLayerFromElement(element);
208 WebLayerPositionConstraint constraint = layer->positionConstraint();
209 ASSERT_TRUE(constraint.isFixedPosition);
210 ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
213 Element* element = document->getElementById("span-bl");
214 ASSERT_TRUE(element);
215 WebLayer* layer = webLayerFromElement(element);
217 WebLayerPositionConstraint constraint = layer->positionConstraint();
218 ASSERT_TRUE(constraint.isFixedPosition);
219 ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
222 Element* element = document->getElementById("span-br");
223 ASSERT_TRUE(element);
224 WebLayer* layer = webLayerFromElement(element);
226 WebLayerPositionConstraint constraint = layer->positionConstraint();
227 ASSERT_TRUE(constraint.isFixedPosition);
228 ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
232 TEST_F(ScrollingCoordinatorChromiumTest, wheelEventHandler)
234 registerMockedHttpURLLoad("wheel-event-handler.html");
235 navigateTo(m_baseURL + "wheel-event-handler.html");
236 forceFullCompositingUpdate();
238 WebLayer* rootScrollLayer = getRootScrollLayer();
239 ASSERT_TRUE(rootScrollLayer->haveWheelEventHandlers());
242 TEST_F(ScrollingCoordinatorChromiumTest, scrollEventHandler)
244 registerMockedHttpURLLoad("scroll-event-handler.html");
245 navigateTo(m_baseURL + "scroll-event-handler.html");
246 forceFullCompositingUpdate();
248 WebLayer* rootScrollLayer = getRootScrollLayer();
249 ASSERT_TRUE(rootScrollLayer->haveScrollEventHandlers());
252 TEST_F(ScrollingCoordinatorChromiumTest, updateEventHandlersDuringTeardown)
254 registerMockedHttpURLLoad("scroll-event-handler-window.html");
255 navigateTo(m_baseURL + "scroll-event-handler-window.html");
256 forceFullCompositingUpdate();
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();
263 TEST_F(ScrollingCoordinatorChromiumTest, clippedBodyTest)
265 registerMockedHttpURLLoad("clipped-body.html");
266 navigateTo(m_baseURL + "clipped-body.html");
267 forceFullCompositingUpdate();
269 WebLayer* rootScrollLayer = getRootScrollLayer();
270 ASSERT_EQ(0u, rootScrollLayer->nonFastScrollableRegion().size());
273 TEST_F(ScrollingCoordinatorChromiumTest, overflowScrolling)
275 registerMockedHttpURLLoad("overflow-scrolling.html");
276 navigateTo(m_baseURL + "overflow-scrolling.html");
277 forceFullCompositingUpdate();
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);
284 RenderObject* renderer = scrollableElement->renderer();
285 ASSERT_TRUE(renderer->isBox());
286 ASSERT_TRUE(renderer->hasLayer());
288 RenderBox* box = toRenderBox(renderer);
289 ASSERT_TRUE(box->usesCompositedScrolling());
290 ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
292 CompositedLayerMappingPtr compositedLayerMapping = box->layer()->compositedLayerMapping();
293 ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
294 ASSERT(compositedLayerMapping->scrollingContentsLayer());
296 GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
297 ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
299 WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
300 ASSERT_TRUE(webScrollLayer->scrollable());
301 ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
302 ASSERT_TRUE(webScrollLayer->userScrollableVertical());
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());
313 TEST_F(ScrollingCoordinatorChromiumTest, overflowHidden)
315 registerMockedHttpURLLoad("overflow-hidden.html");
316 navigateTo(m_baseURL + "overflow-hidden.html");
317 forceFullCompositingUpdate();
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);
324 RenderObject* renderer = overflowElement->renderer();
325 ASSERT_TRUE(renderer->isBox());
326 ASSERT_TRUE(renderer->hasLayer());
328 RenderBox* box = toRenderBox(renderer);
329 ASSERT_TRUE(box->usesCompositedScrolling());
330 ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
332 CompositedLayerMappingPtr compositedLayerMapping = box->layer()->compositedLayerMapping();
333 ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
334 ASSERT(compositedLayerMapping->scrollingContentsLayer());
336 GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
337 ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
339 WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
340 ASSERT_TRUE(webScrollLayer->scrollable());
341 ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
342 ASSERT_FALSE(webScrollLayer->userScrollableVertical());
344 overflowElement = frame()->document()->getElementById("unscrollable-x");
345 ASSERT(overflowElement);
347 renderer = overflowElement->renderer();
348 ASSERT_TRUE(renderer->isBox());
349 ASSERT_TRUE(renderer->hasLayer());
351 box = toRenderBox(renderer);
352 ASSERT_TRUE(box->scrollableArea()->usesCompositedScrolling());
353 ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
355 compositedLayerMapping = box->layer()->compositedLayerMapping();
356 ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
357 ASSERT(compositedLayerMapping->scrollingContentsLayer());
359 graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
360 ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
362 webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
363 ASSERT_TRUE(webScrollLayer->scrollable());
364 ASSERT_FALSE(webScrollLayer->userScrollableHorizontal());
365 ASSERT_TRUE(webScrollLayer->userScrollableVertical());
368 TEST_F(ScrollingCoordinatorChromiumTest, iframeScrolling)
370 registerMockedHttpURLLoad("iframe-scrolling.html");
371 registerMockedHttpURLLoad("iframe-scrolling-inner.html");
372 navigateTo(m_baseURL + "iframe-scrolling.html");
373 forceFullCompositingUpdate();
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);
380 RenderObject* renderer = scrollableFrame->renderer();
381 ASSERT_TRUE(renderer);
382 ASSERT_TRUE(renderer->isWidget());
384 RenderWidget* renderWidget = toRenderWidget(renderer);
385 ASSERT_TRUE(renderWidget);
386 ASSERT_TRUE(renderWidget->widget());
387 ASSERT_TRUE(renderWidget->widget()->isFrameView());
389 FrameView* innerFrameView = toFrameView(renderWidget->widget());
390 RenderView* innerRenderView = innerFrameView->renderView();
391 ASSERT_TRUE(innerRenderView);
393 RenderLayerCompositor* innerCompositor = innerRenderView->compositor();
394 ASSERT_TRUE(innerCompositor->inCompositingMode());
395 ASSERT_TRUE(innerCompositor->scrollLayer());
397 GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
398 ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());
400 WebLayer* webScrollLayer = scrollLayer->platformLayer();
401 ASSERT_TRUE(webScrollLayer->scrollable());
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());
412 TEST_F(ScrollingCoordinatorChromiumTest, rtlIframe)
414 registerMockedHttpURLLoad("rtl-iframe.html");
415 registerMockedHttpURLLoad("rtl-iframe-inner.html");
416 navigateTo(m_baseURL + "rtl-iframe.html");
417 forceFullCompositingUpdate();
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);
424 RenderObject* renderer = scrollableFrame->renderer();
425 ASSERT_TRUE(renderer);
426 ASSERT_TRUE(renderer->isWidget());
428 RenderWidget* renderWidget = toRenderWidget(renderer);
429 ASSERT_TRUE(renderWidget);
430 ASSERT_TRUE(renderWidget->widget());
431 ASSERT_TRUE(renderWidget->widget()->isFrameView());
433 FrameView* innerFrameView = toFrameView(renderWidget->widget());
434 RenderView* innerRenderView = innerFrameView->renderView();
435 ASSERT_TRUE(innerRenderView);
437 RenderLayerCompositor* innerCompositor = innerRenderView->compositor();
438 ASSERT_TRUE(innerCompositor->inCompositingMode());
439 ASSERT_TRUE(innerCompositor->scrollLayer());
441 GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
442 ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());
444 WebLayer* webScrollLayer = scrollLayer->platformLayer();
445 ASSERT_TRUE(webScrollLayer->scrollable());
447 int expectedScrollPosition = 958 + (innerFrameView->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
448 ASSERT_EQ(expectedScrollPosition, webScrollLayer->scrollPosition().x);
451 TEST_F(ScrollingCoordinatorChromiumTest, setupScrollbarLayerShouldNotCrash)
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.