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/RenderPart.h"
31 #include "core/rendering/RenderView.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 class GraphicsLayerForScrollTesting : public GraphicsLayer {
111 virtual WebLayer* contentsLayer() const { return GraphicsLayer::contentsLayer(); }
114 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingByDefault)
116 navigateTo("about:blank");
117 forceFullCompositingUpdate();
119 // Make sure the scrolling coordinator is active.
120 FrameView* frameView = frame()->view();
121 Page* page = frame()->page();
122 ASSERT_TRUE(page->scrollingCoordinator());
123 ASSERT_TRUE(page->scrollingCoordinator()->coordinatesScrollingForFrameView(frameView));
125 // Fast scrolling should be enabled by default.
126 WebLayer* rootScrollLayer = getRootScrollLayer();
127 ASSERT_TRUE(rootScrollLayer->scrollable());
128 ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
129 ASSERT_FALSE(rootScrollLayer->haveWheelEventHandlers());
132 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingCanBeDisabledWithSetting)
134 navigateTo("about:blank");
135 webViewImpl()->settings()->setThreadedScrollingEnabled(false);
136 forceFullCompositingUpdate();
138 // Make sure the scrolling coordinator is active.
139 FrameView* frameView = frame()->view();
140 Page* page = frame()->page();
141 ASSERT_TRUE(page->scrollingCoordinator());
142 ASSERT_TRUE(page->scrollingCoordinator()->coordinatesScrollingForFrameView(frameView));
144 // Main scrolling should be enabled with the setting override.
145 WebLayer* rootScrollLayer = getRootScrollLayer();
146 ASSERT_TRUE(rootScrollLayer->scrollable());
147 ASSERT_TRUE(rootScrollLayer->shouldScrollOnMainThread());
150 static WebLayer* webLayerFromElement(Element* element)
154 RenderObject* renderer = element->renderer();
155 if (!renderer || !renderer->isBoxModelObject())
157 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
160 if (!layer->hasCompositedLayerMapping())
162 CompositedLayerMapping* compositedLayerMapping = layer->compositedLayerMapping();
163 GraphicsLayer* graphicsLayer = compositedLayerMapping->mainGraphicsLayer();
166 return graphicsLayer->platformLayer();
169 TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingForFixedPosition)
171 registerMockedHttpURLLoad("fixed-position.html");
172 navigateTo(m_baseURL + "fixed-position.html");
173 forceFullCompositingUpdate();
175 // Fixed position should not fall back to main thread scrolling.
176 WebLayer* rootScrollLayer = getRootScrollLayer();
177 ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
179 Document* document = frame()->document();
181 Element* element = document->getElementById("div-tl");
182 ASSERT_TRUE(element);
183 WebLayer* layer = webLayerFromElement(element);
185 WebLayerPositionConstraint constraint = layer->positionConstraint();
186 ASSERT_TRUE(constraint.isFixedPosition);
187 ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
190 Element* element = document->getElementById("div-tr");
191 ASSERT_TRUE(element);
192 WebLayer* layer = webLayerFromElement(element);
194 WebLayerPositionConstraint constraint = layer->positionConstraint();
195 ASSERT_TRUE(constraint.isFixedPosition);
196 ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
199 Element* element = document->getElementById("div-bl");
200 ASSERT_TRUE(element);
201 WebLayer* layer = webLayerFromElement(element);
203 WebLayerPositionConstraint constraint = layer->positionConstraint();
204 ASSERT_TRUE(constraint.isFixedPosition);
205 ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
208 Element* element = document->getElementById("div-br");
209 ASSERT_TRUE(element);
210 WebLayer* layer = webLayerFromElement(element);
212 WebLayerPositionConstraint constraint = layer->positionConstraint();
213 ASSERT_TRUE(constraint.isFixedPosition);
214 ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
217 Element* element = document->getElementById("span-tl");
218 ASSERT_TRUE(element);
219 WebLayer* layer = webLayerFromElement(element);
221 WebLayerPositionConstraint constraint = layer->positionConstraint();
222 ASSERT_TRUE(constraint.isFixedPosition);
223 ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
226 Element* element = document->getElementById("span-tr");
227 ASSERT_TRUE(element);
228 WebLayer* layer = webLayerFromElement(element);
230 WebLayerPositionConstraint constraint = layer->positionConstraint();
231 ASSERT_TRUE(constraint.isFixedPosition);
232 ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
235 Element* element = document->getElementById("span-bl");
236 ASSERT_TRUE(element);
237 WebLayer* layer = webLayerFromElement(element);
239 WebLayerPositionConstraint constraint = layer->positionConstraint();
240 ASSERT_TRUE(constraint.isFixedPosition);
241 ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
244 Element* element = document->getElementById("span-br");
245 ASSERT_TRUE(element);
246 WebLayer* layer = webLayerFromElement(element);
248 WebLayerPositionConstraint constraint = layer->positionConstraint();
249 ASSERT_TRUE(constraint.isFixedPosition);
250 ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
254 TEST_F(ScrollingCoordinatorChromiumTest, wheelEventHandler)
256 registerMockedHttpURLLoad("wheel-event-handler.html");
257 navigateTo(m_baseURL + "wheel-event-handler.html");
258 forceFullCompositingUpdate();
260 WebLayer* rootScrollLayer = getRootScrollLayer();
261 ASSERT_TRUE(rootScrollLayer->haveWheelEventHandlers());
264 TEST_F(ScrollingCoordinatorChromiumTest, scrollEventHandler)
266 registerMockedHttpURLLoad("scroll-event-handler.html");
267 navigateTo(m_baseURL + "scroll-event-handler.html");
268 forceFullCompositingUpdate();
270 WebLayer* rootScrollLayer = getRootScrollLayer();
271 ASSERT_TRUE(rootScrollLayer->haveScrollEventHandlers());
274 TEST_F(ScrollingCoordinatorChromiumTest, updateEventHandlersDuringTeardown)
276 registerMockedHttpURLLoad("scroll-event-handler-window.html");
277 navigateTo(m_baseURL + "scroll-event-handler-window.html");
278 forceFullCompositingUpdate();
280 // Simulate detaching the document from its DOM window. This should not
281 // cause a crash when the WebViewImpl is closed by the test runner.
282 frame()->document()->prepareForDestruction();
285 TEST_F(ScrollingCoordinatorChromiumTest, clippedBodyTest)
287 registerMockedHttpURLLoad("clipped-body.html");
288 navigateTo(m_baseURL + "clipped-body.html");
289 forceFullCompositingUpdate();
291 WebLayer* rootScrollLayer = getRootScrollLayer();
292 ASSERT_EQ(0u, rootScrollLayer->nonFastScrollableRegion().size());
295 TEST_F(ScrollingCoordinatorChromiumTest, overflowScrolling)
297 registerMockedHttpURLLoad("overflow-scrolling.html");
298 navigateTo(m_baseURL + "overflow-scrolling.html");
299 forceFullCompositingUpdate();
301 // Verify the properties of the accelerated scrolling element starting from the RenderObject
302 // all the way to the WebLayer.
303 Element* scrollableElement = frame()->document()->getElementById("scrollable");
304 ASSERT(scrollableElement);
306 RenderObject* renderer = scrollableElement->renderer();
307 ASSERT_TRUE(renderer->isBox());
308 ASSERT_TRUE(renderer->hasLayer());
310 RenderBox* box = toRenderBox(renderer);
311 ASSERT_TRUE(box->usesCompositedScrolling());
312 ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
314 CompositedLayerMapping* compositedLayerMapping = box->layer()->compositedLayerMapping();
315 ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
316 ASSERT(compositedLayerMapping->scrollingContentsLayer());
318 GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
319 ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
321 WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
322 ASSERT_TRUE(webScrollLayer->scrollable());
323 ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
324 ASSERT_TRUE(webScrollLayer->userScrollableVertical());
327 // Now verify we've attached impl-side scrollbars onto the scrollbar layers
328 ASSERT_TRUE(compositedLayerMapping->layerForHorizontalScrollbar());
329 ASSERT_TRUE(compositedLayerMapping->layerForHorizontalScrollbar()->hasContentsLayer());
330 ASSERT_TRUE(compositedLayerMapping->layerForVerticalScrollbar());
331 ASSERT_TRUE(compositedLayerMapping->layerForVerticalScrollbar()->hasContentsLayer());
335 TEST_F(ScrollingCoordinatorChromiumTest, overflowHidden)
337 registerMockedHttpURLLoad("overflow-hidden.html");
338 navigateTo(m_baseURL + "overflow-hidden.html");
339 forceFullCompositingUpdate();
341 // Verify the properties of the accelerated scrolling element starting from the RenderObject
342 // all the way to the WebLayer.
343 Element* overflowElement = frame()->document()->getElementById("unscrollable-y");
344 ASSERT(overflowElement);
346 RenderObject* renderer = overflowElement->renderer();
347 ASSERT_TRUE(renderer->isBox());
348 ASSERT_TRUE(renderer->hasLayer());
350 RenderBox* box = toRenderBox(renderer);
351 ASSERT_TRUE(box->usesCompositedScrolling());
352 ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
354 CompositedLayerMapping* compositedLayerMapping = box->layer()->compositedLayerMapping();
355 ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
356 ASSERT(compositedLayerMapping->scrollingContentsLayer());
358 GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
359 ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
361 WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
362 ASSERT_TRUE(webScrollLayer->scrollable());
363 ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
364 ASSERT_FALSE(webScrollLayer->userScrollableVertical());
366 overflowElement = frame()->document()->getElementById("unscrollable-x");
367 ASSERT(overflowElement);
369 renderer = overflowElement->renderer();
370 ASSERT_TRUE(renderer->isBox());
371 ASSERT_TRUE(renderer->hasLayer());
373 box = toRenderBox(renderer);
374 ASSERT_TRUE(box->scrollableArea()->usesCompositedScrolling());
375 ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());
377 compositedLayerMapping = box->layer()->compositedLayerMapping();
378 ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
379 ASSERT(compositedLayerMapping->scrollingContentsLayer());
381 graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
382 ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());
384 webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
385 ASSERT_TRUE(webScrollLayer->scrollable());
386 ASSERT_FALSE(webScrollLayer->userScrollableHorizontal());
387 ASSERT_TRUE(webScrollLayer->userScrollableVertical());
390 TEST_F(ScrollingCoordinatorChromiumTest, iframeScrolling)
392 registerMockedHttpURLLoad("iframe-scrolling.html");
393 registerMockedHttpURLLoad("iframe-scrolling-inner.html");
394 navigateTo(m_baseURL + "iframe-scrolling.html");
395 forceFullCompositingUpdate();
397 // Verify the properties of the accelerated scrolling element starting from the RenderObject
398 // all the way to the WebLayer.
399 Element* scrollableFrame = frame()->document()->getElementById("scrollable");
400 ASSERT_TRUE(scrollableFrame);
402 RenderObject* renderer = scrollableFrame->renderer();
403 ASSERT_TRUE(renderer);
404 ASSERT_TRUE(renderer->isRenderPart());
406 RenderPart* renderPart = toRenderPart(renderer);
407 ASSERT_TRUE(renderPart);
408 ASSERT_TRUE(renderPart->widget());
409 ASSERT_TRUE(renderPart->widget()->isFrameView());
411 FrameView* innerFrameView = toFrameView(renderPart->widget());
412 RenderView* innerRenderView = innerFrameView->renderView();
413 ASSERT_TRUE(innerRenderView);
415 RenderLayerCompositor* innerCompositor = innerRenderView->compositor();
416 ASSERT_TRUE(innerCompositor->inCompositingMode());
417 ASSERT_TRUE(innerCompositor->scrollLayer());
419 GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
420 ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());
422 WebLayer* webScrollLayer = scrollLayer->platformLayer();
423 ASSERT_TRUE(webScrollLayer->scrollable());
426 // Now verify we've attached impl-side scrollbars onto the scrollbar layers
427 ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar());
428 ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar()->hasContentsLayer());
429 ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar());
430 ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar()->hasContentsLayer());
434 TEST_F(ScrollingCoordinatorChromiumTest, rtlIframe)
436 registerMockedHttpURLLoad("rtl-iframe.html");
437 registerMockedHttpURLLoad("rtl-iframe-inner.html");
438 navigateTo(m_baseURL + "rtl-iframe.html");
439 forceFullCompositingUpdate();
441 // Verify the properties of the accelerated scrolling element starting from the RenderObject
442 // all the way to the WebLayer.
443 Element* scrollableFrame = frame()->document()->getElementById("scrollable");
444 ASSERT_TRUE(scrollableFrame);
446 RenderObject* renderer = scrollableFrame->renderer();
447 ASSERT_TRUE(renderer);
448 ASSERT_TRUE(renderer->isRenderPart());
450 RenderPart* renderPart = toRenderPart(renderer);
451 ASSERT_TRUE(renderPart);
452 ASSERT_TRUE(renderPart->widget());
453 ASSERT_TRUE(renderPart->widget()->isFrameView());
455 FrameView* innerFrameView = toFrameView(renderPart->widget());
456 RenderView* innerRenderView = innerFrameView->renderView();
457 ASSERT_TRUE(innerRenderView);
459 RenderLayerCompositor* innerCompositor = innerRenderView->compositor();
460 ASSERT_TRUE(innerCompositor->inCompositingMode());
461 ASSERT_TRUE(innerCompositor->scrollLayer());
463 GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
464 ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());
466 WebLayer* webScrollLayer = scrollLayer->platformLayer();
467 ASSERT_TRUE(webScrollLayer->scrollable());
469 int expectedScrollPosition = 958 + (innerFrameView->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
470 ASSERT_EQ(expectedScrollPosition, webScrollLayer->scrollPositionDouble().x);
473 TEST_F(ScrollingCoordinatorChromiumTest, setupScrollbarLayerShouldNotCrash)
475 registerMockedHttpURLLoad("setup_scrollbar_layer_crash.html");
476 navigateTo(m_baseURL + "setup_scrollbar_layer_crash.html");
477 forceFullCompositingUpdate();
478 // This test document setup an iframe with scrollbars, then switch to
479 // an empty document by javascript.
483 TEST_F(ScrollingCoordinatorChromiumTest, DISABLED_setupScrollbarLayerShouldSetScrollLayerOpaque)
485 TEST_F(ScrollingCoordinatorChromiumTest, setupScrollbarLayerShouldSetScrollLayerOpaque)
488 registerMockedHttpURLLoad("wide_document.html");
489 navigateTo(m_baseURL + "wide_document.html");
490 forceFullCompositingUpdate();
492 FrameView* frameView = frame()->view();
493 ASSERT_TRUE(frameView);
495 GraphicsLayerForScrollTesting* scrollbarGraphicsLayer = static_cast<GraphicsLayerForScrollTesting*>(frameView->layerForHorizontalScrollbar());
496 ASSERT_TRUE(scrollbarGraphicsLayer);
498 WebLayer* platformLayer = scrollbarGraphicsLayer->platformLayer();
499 ASSERT_TRUE(platformLayer);
501 WebLayer* contentsLayer = scrollbarGraphicsLayer->contentsLayer();
502 ASSERT_TRUE(contentsLayer);
504 // After scrollableAreaScrollbarLayerDidChange,
505 // if the main frame's scrollbarLayer is opaque,
506 // contentsLayer should be opaque too.
507 ASSERT_EQ(platformLayer->opaque(), contentsLayer->opaque());