Index: cc/CCLayerTreeHostImplTest.cpp |
diff --git a/cc/CCLayerTreeHostImplTest.cpp b/cc/CCLayerTreeHostImplTest.cpp |
deleted file mode 100644 |
index e2dda54c6c5b3aa99bf7e770731c93f6d4195ed5..0000000000000000000000000000000000000000 |
--- a/cc/CCLayerTreeHostImplTest.cpp |
+++ /dev/null |
@@ -1,4347 +0,0 @@ |
-// Copyright 2011 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "config.h" |
- |
-#include "CCLayerTreeHostImpl.h" |
- |
-#include "CCAnimationTestCommon.h" |
-#include "CCDelegatedRendererLayerImpl.h" |
-#include "CCGeometryTestUtils.h" |
-#include "CCHeadsUpDisplayLayerImpl.h" |
-#include "CCIOSurfaceLayerImpl.h" |
-#include "CCLayerImpl.h" |
-#include "CCLayerTestCommon.h" |
-#include "CCLayerTilingData.h" |
-#include "CCQuadSink.h" |
-#include "CCRenderPassDrawQuad.h" |
-#include "CCRenderPassTestCommon.h" |
-#include "CCRendererGL.h" |
-#include "CCScrollbarGeometryFixedThumb.h" |
-#include "CCScrollbarLayerImpl.h" |
-#include "CCSettings.h" |
-#include "CCSingleThreadProxy.h" |
-#include "CCSolidColorDrawQuad.h" |
-#include "CCTestCommon.h" |
-#include "CCTextureDrawQuad.h" |
-#include "CCTextureLayerImpl.h" |
-#include "CCTileDrawQuad.h" |
-#include "CCTiledLayerImpl.h" |
-#include "CCVideoLayerImpl.h" |
-#include "FakeWebCompositorOutputSurface.h" |
-#include "FakeWebGraphicsContext3D.h" |
-#include "FakeWebScrollbarThemeGeometry.h" |
-#include "base/hash_tables.h" |
-#include "testing/gmock/include/gmock/gmock.h" |
-#include "testing/gtest/include/gtest/gtest.h" |
-#include <public/WebVideoFrame.h> |
-#include <public/WebVideoFrameProvider.h> |
- |
-using namespace cc; |
-using namespace CCLayerTestCommon; |
-using namespace WebKit; |
-using namespace WebKitTests; |
- |
-using ::testing::Mock; |
-using ::testing::Return; |
-using ::testing::AnyNumber; |
-using ::testing::AtLeast; |
-using ::testing::_; |
- |
-namespace { |
- |
-// This test is parametrized to run all tests with the |
-// CCSettings::pageScalePinchZoomEnabled field enabled and disabled. |
-class CCLayerTreeHostImplTest : public testing::TestWithParam<bool>, |
- public CCLayerTreeHostImplClient { |
-public: |
- CCLayerTreeHostImplTest() |
- : m_onCanDrawStateChangedCalled(false) |
- , m_didRequestCommit(false) |
- , m_didRequestRedraw(false) |
- { |
- } |
- |
- virtual void SetUp() |
- { |
- CCSettings::setPageScalePinchZoomEnabled(GetParam()); |
- CCLayerTreeSettings settings; |
- settings.minimumOcclusionTrackingSize = IntSize(); |
- |
- m_hostImpl = CCLayerTreeHostImpl::create(settings, this); |
- m_hostImpl->initializeRenderer(createContext()); |
- m_hostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10)); |
- } |
- |
- virtual void TearDown() |
- { |
- CCSettings::reset(); |
- } |
- |
- virtual void didLoseContextOnImplThread() OVERRIDE { } |
- virtual void onSwapBuffersCompleteOnImplThread() OVERRIDE { } |
- virtual void onVSyncParametersChanged(double, double) OVERRIDE { } |
- virtual void onCanDrawStateChanged(bool canDraw) OVERRIDE { m_onCanDrawStateChangedCalled = true; } |
- virtual void setNeedsRedrawOnImplThread() OVERRIDE { m_didRequestRedraw = true; } |
- virtual void setNeedsCommitOnImplThread() OVERRIDE { m_didRequestCommit = true; } |
- virtual void postAnimationEventsToMainThreadOnImplThread(scoped_ptr<CCAnimationEventsVector>, double wallClockTime) OVERRIDE { } |
- virtual void releaseContentsTexturesOnImplThread() OVERRIDE { } |
- |
- scoped_ptr<CCLayerTreeHostImpl> createLayerTreeHost(bool partialSwap, scoped_ptr<CCGraphicsContext> graphicsContext, scoped_ptr<CCLayerImpl> root) |
- { |
- CCSettings::setPartialSwapEnabled(partialSwap); |
- |
- CCLayerTreeSettings settings; |
- settings.minimumOcclusionTrackingSize = IntSize(); |
- |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this); |
- |
- myHostImpl->initializeRenderer(graphicsContext.Pass()); |
- myHostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10)); |
- |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setPosition(FloatPoint(0, 0)); |
- root->setBounds(IntSize(10, 10)); |
- root->setContentBounds(IntSize(10, 10)); |
- root->setVisibleContentRect(IntRect(0, 0, 10, 10)); |
- root->setDrawsContent(true); |
- myHostImpl->setRootLayer(root.Pass()); |
- return myHostImpl.Pass(); |
- } |
- |
- static void expectClearedScrollDeltasRecursive(CCLayerImpl* layer) |
- { |
- ASSERT_EQ(layer->scrollDelta(), IntSize()); |
- for (size_t i = 0; i < layer->children().size(); ++i) |
- expectClearedScrollDeltasRecursive(layer->children()[i]); |
- } |
- |
- static void expectContains(const CCScrollAndScaleSet& scrollInfo, int id, const IntSize& scrollDelta) |
- { |
- int timesEncountered = 0; |
- |
- for (size_t i = 0; i < scrollInfo.scrolls.size(); ++i) { |
- if (scrollInfo.scrolls[i].layerId != id) |
- continue; |
- EXPECT_EQ(scrollDelta.width(), scrollInfo.scrolls[i].scrollDelta.width()); |
- EXPECT_EQ(scrollDelta.height(), scrollInfo.scrolls[i].scrollDelta.height()); |
- timesEncountered++; |
- } |
- |
- ASSERT_EQ(timesEncountered, 1); |
- } |
- |
- void setupScrollAndContentsLayers(const IntSize& contentSize) |
- { |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- root->setScrollable(true); |
- root->setScrollPosition(IntPoint(0, 0)); |
- root->setMaxScrollPosition(contentSize); |
- root->setBounds(contentSize); |
- root->setContentBounds(contentSize); |
- root->setPosition(FloatPoint(0, 0)); |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- |
- scoped_ptr<CCLayerImpl> contents = CCLayerImpl::create(2); |
- contents->setDrawsContent(true); |
- contents->setBounds(contentSize); |
- contents->setContentBounds(contentSize); |
- contents->setPosition(FloatPoint(0, 0)); |
- contents->setAnchorPoint(FloatPoint(0, 0)); |
- root->addChild(contents.Pass()); |
- m_hostImpl->setRootLayer(root.Pass()); |
- } |
- |
- static scoped_ptr<CCLayerImpl> createScrollableLayer(int id, const IntSize& size) |
- { |
- scoped_ptr<CCLayerImpl> layer = CCLayerImpl::create(id); |
- layer->setScrollable(true); |
- layer->setDrawsContent(true); |
- layer->setBounds(size); |
- layer->setContentBounds(size); |
- layer->setMaxScrollPosition(IntSize(size.width() * 2, size.height() * 2)); |
- return layer.Pass(); |
- } |
- |
- void initializeRendererAndDrawFrame() |
- { |
- m_hostImpl->initializeRenderer(createContext()); |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- } |
- |
-protected: |
- scoped_ptr<CCGraphicsContext> createContext() |
- { |
- return FakeWebCompositorOutputSurface::create(adoptPtr(new FakeWebGraphicsContext3D)).PassAs<CCGraphicsContext>(); |
- } |
- |
- DebugScopedSetImplThread m_alwaysImplThread; |
- DebugScopedSetMainThreadBlocked m_alwaysMainThreadBlocked; |
- |
- scoped_ptr<CCLayerTreeHostImpl> m_hostImpl; |
- bool m_onCanDrawStateChangedCalled; |
- bool m_didRequestCommit; |
- bool m_didRequestRedraw; |
- CCScopedSettings m_scopedSettings; |
-}; |
- |
-class FakeWebGraphicsContext3DMakeCurrentFails : public FakeWebGraphicsContext3D { |
-public: |
- virtual bool makeContextCurrent() { return false; } |
-}; |
- |
-TEST_P(CCLayerTreeHostImplTest, notifyIfCanDrawChanged) |
-{ |
- // Note: It is not possible to disable the renderer once it has been set, |
- // so we do not need to test that disabling the renderer notifies us |
- // that canDraw changed. |
- EXPECT_FALSE(m_hostImpl->canDraw()); |
- m_onCanDrawStateChangedCalled = false; |
- |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- EXPECT_TRUE(m_hostImpl->canDraw()); |
- EXPECT_TRUE(m_onCanDrawStateChangedCalled); |
- m_onCanDrawStateChangedCalled = false; |
- |
- // Toggle the root layer to make sure it toggles canDraw |
- m_hostImpl->setRootLayer(scoped_ptr<CCLayerImpl>()); |
- EXPECT_FALSE(m_hostImpl->canDraw()); |
- EXPECT_TRUE(m_onCanDrawStateChangedCalled); |
- m_onCanDrawStateChangedCalled = false; |
- |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- EXPECT_TRUE(m_hostImpl->canDraw()); |
- EXPECT_TRUE(m_onCanDrawStateChangedCalled); |
- m_onCanDrawStateChangedCalled = false; |
- |
- // Toggle the device viewport size to make sure it toggles canDraw. |
- m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(0, 0)); |
- EXPECT_FALSE(m_hostImpl->canDraw()); |
- EXPECT_TRUE(m_onCanDrawStateChangedCalled); |
- m_onCanDrawStateChangedCalled = false; |
- |
- m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100)); |
- EXPECT_TRUE(m_hostImpl->canDraw()); |
- EXPECT_TRUE(m_onCanDrawStateChangedCalled); |
- m_onCanDrawStateChangedCalled = false; |
- |
- // Toggle contents textures purged to make sure it toggles canDraw |
- m_hostImpl->releaseContentsTextures(); |
- EXPECT_FALSE(m_hostImpl->canDraw()); |
- EXPECT_TRUE(m_onCanDrawStateChangedCalled); |
- m_onCanDrawStateChangedCalled = false; |
- |
- m_hostImpl->resetContentsTexturesPurged(); |
- EXPECT_TRUE(m_hostImpl->canDraw()); |
- EXPECT_TRUE(m_onCanDrawStateChangedCalled); |
- m_onCanDrawStateChangedCalled = false; |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollDeltaNoLayers) |
-{ |
- ASSERT_FALSE(m_hostImpl->rootLayer()); |
- |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- ASSERT_EQ(scrollInfo->scrolls.size(), 0u); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollDeltaTreeButNoChanges) |
-{ |
- { |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- root->addChild(CCLayerImpl::create(2)); |
- root->addChild(CCLayerImpl::create(3)); |
- root->children()[1]->addChild(CCLayerImpl::create(4)); |
- root->children()[1]->addChild(CCLayerImpl::create(5)); |
- root->children()[1]->children()[0]->addChild(CCLayerImpl::create(6)); |
- m_hostImpl->setRootLayer(root.Pass()); |
- } |
- CCLayerImpl* root = m_hostImpl->rootLayer(); |
- |
- expectClearedScrollDeltasRecursive(root); |
- |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo; |
- |
- scrollInfo = m_hostImpl->processScrollDeltas(); |
- ASSERT_EQ(scrollInfo->scrolls.size(), 0u); |
- expectClearedScrollDeltasRecursive(root); |
- |
- scrollInfo = m_hostImpl->processScrollDeltas(); |
- ASSERT_EQ(scrollInfo->scrolls.size(), 0u); |
- expectClearedScrollDeltasRecursive(root); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollDeltaRepeatedScrolls) |
-{ |
- IntPoint scrollPosition(20, 30); |
- IntSize scrollDelta(11, -15); |
- { |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- root->setScrollPosition(scrollPosition); |
- root->setScrollable(true); |
- root->setMaxScrollPosition(IntSize(100, 100)); |
- root->scrollBy(scrollDelta); |
- m_hostImpl->setRootLayer(root.Pass()); |
- } |
- CCLayerImpl* root = m_hostImpl->rootLayer(); |
- |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo; |
- |
- scrollInfo = m_hostImpl->processScrollDeltas(); |
- ASSERT_EQ(scrollInfo->scrolls.size(), 1u); |
- EXPECT_EQ(root->sentScrollDelta(), scrollDelta); |
- expectContains(*scrollInfo, root->id(), scrollDelta); |
- |
- IntSize scrollDelta2(-5, 27); |
- root->scrollBy(scrollDelta2); |
- scrollInfo = m_hostImpl->processScrollDeltas(); |
- ASSERT_EQ(scrollInfo->scrolls.size(), 1u); |
- EXPECT_EQ(root->sentScrollDelta(), scrollDelta + scrollDelta2); |
- expectContains(*scrollInfo, root->id(), scrollDelta + scrollDelta2); |
- |
- root->scrollBy(IntSize()); |
- scrollInfo = m_hostImpl->processScrollDeltas(); |
- EXPECT_EQ(root->sentScrollDelta(), scrollDelta + scrollDelta2); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollRootCallsCommitAndRedraw) |
-{ |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); |
- initializeRendererAndDrawFrame(); |
- |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10)); |
- m_hostImpl->scrollEnd(); |
- EXPECT_TRUE(m_didRequestRedraw); |
- EXPECT_TRUE(m_didRequestCommit); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollWithoutRootLayer) |
-{ |
- // We should not crash when trying to scroll an empty layer tree. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollWithoutRenderer) |
-{ |
- CCLayerTreeSettings settings; |
- m_hostImpl = CCLayerTreeHostImpl::create(settings, this); |
- |
- // Initialization will fail here. |
- m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFails)).PassAs<CCGraphicsContext>()); |
- m_hostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10)); |
- |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- |
- // We should not crash when trying to scroll after the renderer initialization fails. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, replaceTreeWhileScrolling) |
-{ |
- const int scrollLayerId = 1; |
- |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); |
- initializeRendererAndDrawFrame(); |
- |
- // We should not crash if the tree is replaced while we are scrolling. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->detachLayerTree(); |
- |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- |
- // We should still be scrolling, because the scrolled layer also exists in the new tree. |
- IntSize scrollDelta(0, 10); |
- m_hostImpl->scrollBy(IntPoint(), scrollDelta); |
- m_hostImpl->scrollEnd(); |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- expectContains(*scrollInfo, scrollLayerId, scrollDelta); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, clearRootRenderSurfaceAndScroll) |
-{ |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); |
- initializeRendererAndDrawFrame(); |
- |
- // We should be able to scroll even if the root layer loses its render surface after the most |
- // recent render. |
- m_hostImpl->rootLayer()->clearRenderSurface(); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, wheelEventHandlers) |
-{ |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); |
- initializeRendererAndDrawFrame(); |
- CCLayerImpl* root = m_hostImpl->rootLayer(); |
- |
- root->setHaveWheelEventHandlers(true); |
- |
- // With registered event handlers, wheel scrolls have to go to the main thread. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread); |
- |
- // But gesture scrolls can still be handled. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, shouldScrollOnMainThread) |
-{ |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); |
- initializeRendererAndDrawFrame(); |
- CCLayerImpl* root = m_hostImpl->rootLayer(); |
- |
- root->setShouldScrollOnMainThread(true); |
- |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollOnMainThread); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, nonFastScrollableRegionBasic) |
-{ |
- setupScrollAndContentsLayers(IntSize(200, 200)); |
- m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100)); |
- initializeRendererAndDrawFrame(); |
- CCLayerImpl* root = m_hostImpl->rootLayer(); |
- |
- root->setNonFastScrollableRegion(IntRect(0, 0, 50, 50)); |
- |
- // All scroll types inside the non-fast scrollable region should fail. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollOnMainThread); |
- |
- // All scroll types outside this region should succeed. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(75, 75), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10)); |
- m_hostImpl->scrollEnd(); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(75, 75), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10)); |
- m_hostImpl->scrollEnd(); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, nonFastScrollableRegionWithOffset) |
-{ |
- setupScrollAndContentsLayers(IntSize(200, 200)); |
- m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100)); |
- CCLayerImpl* root = m_hostImpl->rootLayer(); |
- |
- root->setNonFastScrollableRegion(IntRect(0, 0, 50, 50)); |
- root->setPosition(FloatPoint(-25, 0)); |
- initializeRendererAndDrawFrame(); |
- |
- // This point would fall into the non-fast scrollable region except that we've moved the layer down by 25 pixels. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(40, 10), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), IntSize(0, 1)); |
- m_hostImpl->scrollEnd(); |
- |
- // This point is still inside the non-fast region. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(10, 10), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, maxScrollPositionChangedByDeviceScaleFactor) |
-{ |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- |
- float deviceScaleFactor = 2; |
- IntSize layoutViewport(25, 25); |
- IntSize deviceViewport(layoutViewport); |
- deviceViewport.scale(deviceScaleFactor); |
- m_hostImpl->setViewportSize(layoutViewport, deviceViewport); |
- m_hostImpl->setDeviceScaleFactor(deviceScaleFactor); |
- EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), IntSize(25, 25)); |
- |
- deviceScaleFactor = 1; |
- m_hostImpl->setViewportSize(layoutViewport, layoutViewport); |
- m_hostImpl->setDeviceScaleFactor(deviceScaleFactor); |
- EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), IntSize(75, 75)); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, implPinchZoom) |
-{ |
- // This test is specific to the page-scale based pinch zoom. |
- if (!CCSettings::pageScalePinchZoomEnabled()) |
- return; |
- |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); |
- initializeRendererAndDrawFrame(); |
- |
- CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer(); |
- ASSERT(scrollLayer); |
- |
- const float minPageScale = 1, maxPageScale = 4; |
- const WebTransformationMatrix identityScaleTransform; |
- |
- // The impl-based pinch zoome should not adjust the max scroll position. |
- { |
- m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); |
- scrollLayer->setImplTransform(identityScaleTransform); |
- scrollLayer->setScrollDelta(IntSize()); |
- |
- float pageScaleDelta = 2; |
- m_hostImpl->pinchGestureBegin(); |
- m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50)); |
- m_hostImpl->pinchGestureEnd(); |
- EXPECT_TRUE(m_didRequestRedraw); |
- EXPECT_TRUE(m_didRequestCommit); |
- |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta); |
- |
- EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), IntSize(50, 50)); |
- } |
- |
- // Scrolling after a pinch gesture should always be in local space. The scroll deltas do not |
- // have the page scale factor applied. |
- { |
- m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); |
- scrollLayer->setImplTransform(identityScaleTransform); |
- scrollLayer->setScrollDelta(IntSize()); |
- |
- float pageScaleDelta = 2; |
- m_hostImpl->pinchGestureBegin(); |
- m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(0, 0)); |
- m_hostImpl->pinchGestureEnd(); |
- |
- IntSize scrollDelta(0, 10); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), scrollDelta); |
- m_hostImpl->scrollEnd(); |
- |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), scrollDelta); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, pinchGesture) |
-{ |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); |
- initializeRendererAndDrawFrame(); |
- |
- CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer(); |
- ASSERT(scrollLayer); |
- |
- const float minPageScale = CCSettings::pageScalePinchZoomEnabled() ? 1 : 0.5; |
- const float maxPageScale = 4; |
- const WebTransformationMatrix identityScaleTransform; |
- |
- // Basic pinch zoom in gesture |
- { |
- m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); |
- scrollLayer->setImplTransform(identityScaleTransform); |
- scrollLayer->setScrollDelta(IntSize()); |
- |
- float pageScaleDelta = 2; |
- m_hostImpl->pinchGestureBegin(); |
- m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50)); |
- m_hostImpl->pinchGestureEnd(); |
- EXPECT_TRUE(m_didRequestRedraw); |
- EXPECT_TRUE(m_didRequestCommit); |
- |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta); |
- } |
- |
- // Zoom-in clamping |
- { |
- m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); |
- scrollLayer->setImplTransform(identityScaleTransform); |
- scrollLayer->setScrollDelta(IntSize()); |
- float pageScaleDelta = 10; |
- |
- m_hostImpl->pinchGestureBegin(); |
- m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50)); |
- m_hostImpl->pinchGestureEnd(); |
- |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- EXPECT_EQ(scrollInfo->pageScaleDelta, maxPageScale); |
- } |
- |
- // Zoom-out clamping |
- { |
- m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); |
- scrollLayer->setImplTransform(identityScaleTransform); |
- scrollLayer->setScrollDelta(IntSize()); |
- scrollLayer->setScrollPosition(IntPoint(50, 50)); |
- |
- float pageScaleDelta = 0.1f; |
- m_hostImpl->pinchGestureBegin(); |
- m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(0, 0)); |
- m_hostImpl->pinchGestureEnd(); |
- |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale); |
- |
- if (!CCSettings::pageScalePinchZoomEnabled()) { |
- // Pushed to (0,0) via clamping against contents layer size. |
- expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50)); |
- } else { |
- EXPECT_TRUE(scrollInfo->scrolls.isEmpty()); |
- } |
- } |
- |
- // Two-finger panning |
- { |
- m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); |
- scrollLayer->setImplTransform(identityScaleTransform); |
- scrollLayer->setScrollDelta(IntSize()); |
- scrollLayer->setScrollPosition(IntPoint(20, 20)); |
- |
- float pageScaleDelta = 1; |
- m_hostImpl->pinchGestureBegin(); |
- m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(10, 10)); |
- m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(20, 20)); |
- m_hostImpl->pinchGestureEnd(); |
- |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta); |
- expectContains(*scrollInfo, scrollLayer->id(), IntSize(-10, -10)); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, pageScaleAnimation) |
-{ |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); |
- initializeRendererAndDrawFrame(); |
- |
- CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer(); |
- ASSERT(scrollLayer); |
- |
- const float minPageScale = CCSettings::pageScalePinchZoomEnabled() ? 1 : 0.5; |
- const float maxPageScale = 4; |
- const double startTime = 1; |
- const double duration = 0.1; |
- const double halfwayThroughAnimation = startTime + duration / 2; |
- const double endTime = startTime + duration; |
- const WebTransformationMatrix identityScaleTransform; |
- |
- // Non-anchor zoom-in |
- { |
- m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); |
- scrollLayer->setImplTransform(identityScaleTransform); |
- scrollLayer->setScrollPosition(IntPoint(50, 50)); |
- |
- m_hostImpl->startPageScaleAnimation(IntSize(0, 0), false, 2, startTime, duration); |
- m_hostImpl->animate(halfwayThroughAnimation, halfwayThroughAnimation); |
- EXPECT_TRUE(m_didRequestRedraw); |
- m_hostImpl->animate(endTime, endTime); |
- EXPECT_TRUE(m_didRequestCommit); |
- |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- EXPECT_EQ(scrollInfo->pageScaleDelta, 2); |
- expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50)); |
- } |
- |
- // Anchor zoom-out |
- { |
- m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); |
- scrollLayer->setImplTransform(identityScaleTransform); |
- scrollLayer->setScrollPosition(IntPoint(50, 50)); |
- |
- m_hostImpl->startPageScaleAnimation(IntSize(25, 25), true, minPageScale, startTime, duration); |
- m_hostImpl->animate(endTime, endTime); |
- EXPECT_TRUE(m_didRequestRedraw); |
- EXPECT_TRUE(m_didRequestCommit); |
- |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale); |
- // Pushed to (0,0) via clamping against contents layer size. |
- expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50)); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, inhibitScrollAndPageScaleUpdatesWhilePinchZooming) |
-{ |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); |
- initializeRendererAndDrawFrame(); |
- |
- CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer(); |
- ASSERT(scrollLayer); |
- |
- const float minPageScale = CCSettings::pageScalePinchZoomEnabled() ? 1 : 0.5; |
- const float maxPageScale = 4; |
- |
- // Pinch zoom in. |
- { |
- // Start a pinch in gesture at the bottom right corner of the viewport. |
- const float zoomInDelta = 2; |
- m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); |
- m_hostImpl->pinchGestureBegin(); |
- m_hostImpl->pinchGestureUpdate(zoomInDelta, IntPoint(50, 50)); |
- |
- // Because we are pinch zooming in, we shouldn't get any scroll or page |
- // scale deltas. |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- EXPECT_EQ(scrollInfo->pageScaleDelta, 1); |
- EXPECT_EQ(scrollInfo->scrolls.size(), 0u); |
- |
- // Once the gesture ends, we get the final scroll and page scale values. |
- m_hostImpl->pinchGestureEnd(); |
- scrollInfo = m_hostImpl->processScrollDeltas(); |
- EXPECT_EQ(scrollInfo->pageScaleDelta, zoomInDelta); |
- if (!CCSettings::pageScalePinchZoomEnabled()) { |
- expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25)); |
- } else { |
- EXPECT_TRUE(scrollInfo->scrolls.isEmpty()); |
- } |
- } |
- |
- // Pinch zoom out. |
- { |
- // Start a pinch out gesture at the bottom right corner of the viewport. |
- const float zoomOutDelta = 0.75; |
- m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); |
- m_hostImpl->pinchGestureBegin(); |
- m_hostImpl->pinchGestureUpdate(zoomOutDelta, IntPoint(50, 50)); |
- |
- // Since we are pinch zooming out, we should get an update to zoom all |
- // the way out to the minimum page scale. |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- if (!CCSettings::pageScalePinchZoomEnabled()) { |
- EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale); |
- expectContains(*scrollInfo, scrollLayer->id(), IntSize(0, 0)); |
- } else { |
- EXPECT_EQ(scrollInfo->pageScaleDelta, 1); |
- EXPECT_TRUE(scrollInfo->scrolls.isEmpty()); |
- } |
- |
- // Once the gesture ends, we get the final scroll and page scale values. |
- m_hostImpl->pinchGestureEnd(); |
- scrollInfo = m_hostImpl->processScrollDeltas(); |
- if (CCSettings::pageScalePinchZoomEnabled()) { |
- EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale); |
- expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25)); |
- } else { |
- EXPECT_EQ(scrollInfo->pageScaleDelta, zoomOutDelta); |
- expectContains(*scrollInfo, scrollLayer->id(), IntSize(8, 8)); |
- } |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, inhibitScrollAndPageScaleUpdatesWhileAnimatingPageScale) |
-{ |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); |
- initializeRendererAndDrawFrame(); |
- |
- CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer(); |
- ASSERT(scrollLayer); |
- |
- const float minPageScale = CCSettings::pageScalePinchZoomEnabled() ? 1 : 0.5; |
- const float maxPageScale = 4; |
- const double startTime = 1; |
- const double duration = 0.1; |
- const double halfwayThroughAnimation = startTime + duration / 2; |
- const double endTime = startTime + duration; |
- |
- // Start a page scale animation. |
- const float pageScaleDelta = 2; |
- m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); |
- m_hostImpl->startPageScaleAnimation(IntSize(50, 50), false, pageScaleDelta, startTime, duration); |
- |
- // We should immediately get the final zoom and scroll values for the |
- // animation. |
- m_hostImpl->animate(halfwayThroughAnimation, halfwayThroughAnimation); |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- |
- if (!CCSettings::pageScalePinchZoomEnabled()) { |
- EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta); |
- expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25)); |
- } else { |
- EXPECT_EQ(scrollInfo->pageScaleDelta, 1); |
- EXPECT_TRUE(scrollInfo->scrolls.isEmpty()); |
- } |
- |
- // Scrolling during the animation is ignored. |
- const IntSize scrollDelta(0, 10); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), scrollDelta); |
- m_hostImpl->scrollEnd(); |
- |
- // The final page scale and scroll deltas should match what we got |
- // earlier. |
- m_hostImpl->animate(endTime, endTime); |
- scrollInfo = m_hostImpl->processScrollDeltas(); |
- EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta); |
- expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25)); |
-} |
- |
-class DidDrawCheckLayer : public CCTiledLayerImpl { |
-public: |
- static scoped_ptr<CCLayerImpl> create(int id) { return scoped_ptr<CCLayerImpl>(new DidDrawCheckLayer(id)); } |
- |
- virtual void didDraw(CCResourceProvider*) OVERRIDE |
- { |
- m_didDrawCalled = true; |
- } |
- |
- virtual void willDraw(CCResourceProvider*) OVERRIDE |
- { |
- m_willDrawCalled = true; |
- } |
- |
- bool didDrawCalled() const { return m_didDrawCalled; } |
- bool willDrawCalled() const { return m_willDrawCalled; } |
- |
- void clearDidDrawCheck() |
- { |
- m_didDrawCalled = false; |
- m_willDrawCalled = false; |
- } |
- |
-protected: |
- explicit DidDrawCheckLayer(int id) |
- : CCTiledLayerImpl(id) |
- , m_didDrawCalled(false) |
- , m_willDrawCalled(false) |
- { |
- setAnchorPoint(FloatPoint(0, 0)); |
- setBounds(IntSize(10, 10)); |
- setContentBounds(IntSize(10, 10)); |
- setDrawsContent(true); |
- setSkipsDraw(false); |
- setVisibleContentRect(IntRect(0, 0, 10, 10)); |
- |
- OwnPtr<CCLayerTilingData> tiler = CCLayerTilingData::create(IntSize(100, 100), CCLayerTilingData::HasBorderTexels); |
- tiler->setBounds(contentBounds()); |
- setTilingData(*tiler.get()); |
- } |
- |
-private: |
- bool m_didDrawCalled; |
- bool m_willDrawCalled; |
-}; |
- |
-TEST_P(CCLayerTreeHostImplTest, didDrawNotCalledOnHiddenLayer) |
-{ |
- // The root layer is always drawn, so run this test on a child layer that |
- // will be masked out by the root layer's bounds. |
- m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); |
- DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); |
- root->setMasksToBounds(true); |
- |
- root->addChild(DidDrawCheckLayer::create(2)); |
- DidDrawCheckLayer* layer = static_cast<DidDrawCheckLayer*>(root->children()[0]); |
- // Ensure visibleContentRect for layer is empty |
- layer->setPosition(FloatPoint(100, 100)); |
- layer->setBounds(IntSize(10, 10)); |
- layer->setContentBounds(IntSize(10, 10)); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- |
- EXPECT_FALSE(layer->willDrawCalled()); |
- EXPECT_FALSE(layer->didDrawCalled()); |
- |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- EXPECT_FALSE(layer->willDrawCalled()); |
- EXPECT_FALSE(layer->didDrawCalled()); |
- |
- EXPECT_TRUE(layer->visibleContentRect().isEmpty()); |
- |
- // Ensure visibleContentRect for layer layer is not empty |
- layer->setPosition(FloatPoint(0, 0)); |
- |
- EXPECT_FALSE(layer->willDrawCalled()); |
- EXPECT_FALSE(layer->didDrawCalled()); |
- |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- EXPECT_TRUE(layer->willDrawCalled()); |
- EXPECT_TRUE(layer->didDrawCalled()); |
- |
- EXPECT_FALSE(layer->visibleContentRect().isEmpty()); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, willDrawNotCalledOnOccludedLayer) |
-{ |
- IntSize bigSize(1000, 1000); |
- m_hostImpl->setViewportSize(bigSize, bigSize); |
- |
- m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); |
- DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); |
- |
- root->addChild(DidDrawCheckLayer::create(2)); |
- DidDrawCheckLayer* occludedLayer = static_cast<DidDrawCheckLayer*>(root->children()[0]); |
- |
- root->addChild(DidDrawCheckLayer::create(3)); |
- DidDrawCheckLayer* topLayer = static_cast<DidDrawCheckLayer*>(root->children()[1]); |
- // This layer covers the occludedLayer above. Make this layer large so it can occlude. |
- topLayer->setBounds(bigSize); |
- topLayer->setContentBounds(bigSize); |
- topLayer->setContentsOpaque(true); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- |
- EXPECT_FALSE(occludedLayer->willDrawCalled()); |
- EXPECT_FALSE(occludedLayer->didDrawCalled()); |
- EXPECT_FALSE(topLayer->willDrawCalled()); |
- EXPECT_FALSE(topLayer->didDrawCalled()); |
- |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- EXPECT_FALSE(occludedLayer->willDrawCalled()); |
- EXPECT_FALSE(occludedLayer->didDrawCalled()); |
- EXPECT_TRUE(topLayer->willDrawCalled()); |
- EXPECT_TRUE(topLayer->didDrawCalled()); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, didDrawCalledOnAllLayers) |
-{ |
- m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); |
- DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); |
- |
- root->addChild(DidDrawCheckLayer::create(2)); |
- DidDrawCheckLayer* layer1 = static_cast<DidDrawCheckLayer*>(root->children()[0]); |
- |
- layer1->addChild(DidDrawCheckLayer::create(3)); |
- DidDrawCheckLayer* layer2 = static_cast<DidDrawCheckLayer*>(layer1->children()[0]); |
- |
- layer1->setOpacity(0.3f); |
- layer1->setPreserves3D(false); |
- |
- EXPECT_FALSE(root->didDrawCalled()); |
- EXPECT_FALSE(layer1->didDrawCalled()); |
- EXPECT_FALSE(layer2->didDrawCalled()); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- EXPECT_TRUE(root->didDrawCalled()); |
- EXPECT_TRUE(layer1->didDrawCalled()); |
- EXPECT_TRUE(layer2->didDrawCalled()); |
- |
- EXPECT_NE(root->renderSurface(), layer1->renderSurface()); |
- EXPECT_TRUE(!!layer1->renderSurface()); |
-} |
- |
-class MissingTextureAnimatingLayer : public DidDrawCheckLayer { |
-public: |
- static scoped_ptr<CCLayerImpl> create(int id, bool tileMissing, bool skipsDraw, bool animating, CCResourceProvider* resourceProvider) |
- { |
- return scoped_ptr<CCLayerImpl>(new MissingTextureAnimatingLayer(id, tileMissing, skipsDraw, animating, resourceProvider)); |
- } |
- |
-private: |
- explicit MissingTextureAnimatingLayer(int id, bool tileMissing, bool skipsDraw, bool animating, CCResourceProvider* resourceProvider) |
- : DidDrawCheckLayer(id) |
- { |
- OwnPtr<CCLayerTilingData> tilingData = CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::NoBorderTexels); |
- tilingData->setBounds(bounds()); |
- setTilingData(*tilingData.get()); |
- setSkipsDraw(skipsDraw); |
- if (!tileMissing) { |
- CCResourceProvider::ResourceId resource = resourceProvider->createResource(CCRenderer::ContentPool, IntSize(), GraphicsContext3D::RGBA, CCResourceProvider::TextureUsageAny); |
- pushTileProperties(0, 0, resource, IntRect()); |
- } |
- if (animating) |
- addAnimatedTransformToLayer(*this, 10, 3, 0); |
- } |
-}; |
- |
-TEST_P(CCLayerTreeHostImplTest, prepareToDrawFailsWhenAnimationUsesCheckerboard) |
-{ |
- // When the texture is not missing, we draw as usual. |
- m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); |
- DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); |
- root->addChild(MissingTextureAnimatingLayer::create(2, false, false, true, m_hostImpl->resourceProvider())); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // When a texture is missing and we're not animating, we draw as usual with checkerboarding. |
- m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); |
- root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); |
- root->addChild(MissingTextureAnimatingLayer::create(2, true, false, false, m_hostImpl->resourceProvider())); |
- |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // When a texture is missing and we're animating, we don't want to draw anything. |
- m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); |
- root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); |
- root->addChild(MissingTextureAnimatingLayer::create(2, true, false, true, m_hostImpl->resourceProvider())); |
- |
- EXPECT_FALSE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // When the layer skips draw and we're animating, we still draw the frame. |
- m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); |
- root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); |
- root->addChild(MissingTextureAnimatingLayer::create(2, false, true, true, m_hostImpl->resourceProvider())); |
- |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollRootIgnored) |
-{ |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- root->setScrollable(false); |
- m_hostImpl->setRootLayer(root.Pass()); |
- initializeRendererAndDrawFrame(); |
- |
- // Scroll event is ignored because layer is not scrollable. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored); |
- EXPECT_FALSE(m_didRequestRedraw); |
- EXPECT_FALSE(m_didRequestCommit); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollNonCompositedRoot) |
-{ |
- // Test the configuration where a non-composited root layer is embedded in a |
- // scrollable outer layer. |
- IntSize surfaceSize(10, 10); |
- |
- scoped_ptr<CCLayerImpl> contentLayer = CCLayerImpl::create(1); |
- contentLayer->setUseLCDText(true); |
- contentLayer->setDrawsContent(true); |
- contentLayer->setPosition(FloatPoint(0, 0)); |
- contentLayer->setAnchorPoint(FloatPoint(0, 0)); |
- contentLayer->setBounds(surfaceSize); |
- contentLayer->setContentBounds(IntSize(surfaceSize.width() * 2, surfaceSize.height() * 2)); |
- |
- scoped_ptr<CCLayerImpl> scrollLayer = CCLayerImpl::create(2); |
- scrollLayer->setScrollable(true); |
- scrollLayer->setMaxScrollPosition(surfaceSize); |
- scrollLayer->setBounds(surfaceSize); |
- scrollLayer->setContentBounds(surfaceSize); |
- scrollLayer->setPosition(FloatPoint(0, 0)); |
- scrollLayer->setAnchorPoint(FloatPoint(0, 0)); |
- scrollLayer->addChild(contentLayer.Pass()); |
- |
- m_hostImpl->setRootLayer(scrollLayer.Pass()); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- initializeRendererAndDrawFrame(); |
- |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10)); |
- m_hostImpl->scrollEnd(); |
- EXPECT_TRUE(m_didRequestRedraw); |
- EXPECT_TRUE(m_didRequestCommit); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollChildCallsCommitAndRedraw) |
-{ |
- IntSize surfaceSize(10, 10); |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- root->setBounds(surfaceSize); |
- root->setContentBounds(surfaceSize); |
- root->addChild(createScrollableLayer(2, surfaceSize)); |
- m_hostImpl->setRootLayer(root.Pass()); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- initializeRendererAndDrawFrame(); |
- |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10)); |
- m_hostImpl->scrollEnd(); |
- EXPECT_TRUE(m_didRequestRedraw); |
- EXPECT_TRUE(m_didRequestCommit); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollMissesChild) |
-{ |
- IntSize surfaceSize(10, 10); |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- root->addChild(createScrollableLayer(2, surfaceSize)); |
- m_hostImpl->setRootLayer(root.Pass()); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- initializeRendererAndDrawFrame(); |
- |
- // Scroll event is ignored because the input coordinate is outside the layer boundaries. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(15, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored); |
- EXPECT_FALSE(m_didRequestRedraw); |
- EXPECT_FALSE(m_didRequestCommit); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollMissesBackfacingChild) |
-{ |
- IntSize surfaceSize(10, 10); |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- scoped_ptr<CCLayerImpl> child = createScrollableLayer(2, surfaceSize); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- |
- WebTransformationMatrix matrix; |
- matrix.rotate3d(180, 0, 0); |
- child->setTransform(matrix); |
- child->setDoubleSided(false); |
- |
- root->addChild(child.Pass()); |
- m_hostImpl->setRootLayer(root.Pass()); |
- initializeRendererAndDrawFrame(); |
- |
- // Scroll event is ignored because the scrollable layer is not facing the viewer and there is |
- // nothing scrollable behind it. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored); |
- EXPECT_FALSE(m_didRequestRedraw); |
- EXPECT_FALSE(m_didRequestCommit); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollBlockedByContentLayer) |
-{ |
- IntSize surfaceSize(10, 10); |
- scoped_ptr<CCLayerImpl> contentLayer = createScrollableLayer(1, surfaceSize); |
- contentLayer->setShouldScrollOnMainThread(true); |
- contentLayer->setScrollable(false); |
- |
- scoped_ptr<CCLayerImpl> scrollLayer = createScrollableLayer(2, surfaceSize); |
- scrollLayer->addChild(contentLayer.Pass()); |
- |
- m_hostImpl->setRootLayer(scrollLayer.Pass()); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- initializeRendererAndDrawFrame(); |
- |
- // Scrolling fails because the content layer is asking to be scrolled on the main thread. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollRootAndChangePageScaleOnMainThread) |
-{ |
- IntSize surfaceSize(10, 10); |
- float pageScale = 2; |
- scoped_ptr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize); |
- m_hostImpl->setRootLayer(root.Pass()); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- initializeRendererAndDrawFrame(); |
- |
- IntSize scrollDelta(0, 10); |
- IntSize expectedScrollDelta(scrollDelta); |
- IntSize expectedMaxScroll(m_hostImpl->rootLayer()->maxScrollPosition()); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), scrollDelta); |
- m_hostImpl->scrollEnd(); |
- |
- // Set new page scale from main thread. |
- m_hostImpl->setPageScaleFactorAndLimits(pageScale, pageScale, pageScale); |
- |
- if (!CCSettings::pageScalePinchZoomEnabled()) { |
- // The scale should apply to the scroll delta. |
- expectedScrollDelta.scale(pageScale); |
- } |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScrollDelta); |
- |
- // The scroll range should also have been updated. |
- EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), expectedMaxScroll); |
- |
- // The page scale delta remains constant because the impl thread did not scale. |
- EXPECT_EQ(m_hostImpl->rootLayer()->implTransform(), WebTransformationMatrix()); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollRootAndChangePageScaleOnImplThread) |
-{ |
- IntSize surfaceSize(10, 10); |
- float pageScale = 2; |
- scoped_ptr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize); |
- m_hostImpl->setRootLayer(root.Pass()); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- m_hostImpl->setPageScaleFactorAndLimits(1, 1, pageScale); |
- initializeRendererAndDrawFrame(); |
- |
- IntSize scrollDelta(0, 10); |
- IntSize expectedScrollDelta(scrollDelta); |
- IntSize expectedMaxScroll(m_hostImpl->rootLayer()->maxScrollPosition()); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), scrollDelta); |
- m_hostImpl->scrollEnd(); |
- |
- // Set new page scale on impl thread by pinching. |
- m_hostImpl->pinchGestureBegin(); |
- m_hostImpl->pinchGestureUpdate(pageScale, IntPoint()); |
- m_hostImpl->pinchGestureEnd(); |
- m_hostImpl->updateRootScrollLayerImplTransform(); |
- |
- // The scroll delta is not scaled because the main thread did not scale. |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScrollDelta); |
- |
- // The scroll range should also have been updated. |
- EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), expectedMaxScroll); |
- |
- // The page scale delta should match the new scale on the impl side. |
- WebTransformationMatrix expectedScale; |
- expectedScale.scale(pageScale); |
- EXPECT_EQ(m_hostImpl->rootLayer()->implTransform(), expectedScale); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, pageScaleDeltaAppliedToRootScrollLayerOnly) |
-{ |
- IntSize surfaceSize(10, 10); |
- float defaultPageScale = 1; |
- WebTransformationMatrix defaultPageScaleMatrix; |
- |
- float newPageScale = 2; |
- WebTransformationMatrix newPageScaleMatrix; |
- newPageScaleMatrix.scale(newPageScale); |
- |
- // Create a normal scrollable root layer and another scrollable child layer. |
- setupScrollAndContentsLayers(surfaceSize); |
- CCLayerImpl* root = m_hostImpl->rootLayer(); |
- CCLayerImpl* child = root->children()[0]; |
- |
- scoped_ptr<CCLayerImpl> scrollableChild = createScrollableLayer(3, surfaceSize); |
- child->addChild(scrollableChild.Pass()); |
- CCLayerImpl* grandChild = child->children()[0]; |
- |
- // Set new page scale on impl thread by pinching. |
- m_hostImpl->pinchGestureBegin(); |
- m_hostImpl->pinchGestureUpdate(newPageScale, IntPoint()); |
- m_hostImpl->pinchGestureEnd(); |
- m_hostImpl->updateRootScrollLayerImplTransform(); |
- |
- // The page scale delta should only be applied to the scrollable root layer. |
- EXPECT_EQ(root->implTransform(), newPageScaleMatrix); |
- EXPECT_EQ(child->implTransform(), defaultPageScaleMatrix); |
- EXPECT_EQ(grandChild->implTransform(), defaultPageScaleMatrix); |
- |
- // Make sure all the layers are drawn with the page scale delta applied, i.e., the page scale |
- // delta on the root layer is applied hierarchically. |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- EXPECT_EQ(root->drawTransform().m11(), newPageScale); |
- EXPECT_EQ(root->drawTransform().m22(), newPageScale); |
- EXPECT_EQ(child->drawTransform().m11(), newPageScale); |
- EXPECT_EQ(child->drawTransform().m22(), newPageScale); |
- EXPECT_EQ(grandChild->drawTransform().m11(), newPageScale); |
- EXPECT_EQ(grandChild->drawTransform().m22(), newPageScale); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollChildAndChangePageScaleOnMainThread) |
-{ |
- IntSize surfaceSize(10, 10); |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- root->setBounds(surfaceSize); |
- root->setContentBounds(surfaceSize); |
- // Also mark the root scrollable so it becomes the root scroll layer. |
- root->setScrollable(true); |
- int scrollLayerId = 2; |
- root->addChild(createScrollableLayer(scrollLayerId, surfaceSize)); |
- m_hostImpl->setRootLayer(root.Pass()); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- initializeRendererAndDrawFrame(); |
- |
- CCLayerImpl* child = m_hostImpl->rootLayer()->children()[0]; |
- |
- IntSize scrollDelta(0, 10); |
- IntSize expectedScrollDelta(scrollDelta); |
- IntSize expectedMaxScroll(child->maxScrollPosition()); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), scrollDelta); |
- m_hostImpl->scrollEnd(); |
- |
- float pageScale = 2; |
- m_hostImpl->setPageScaleFactorAndLimits(pageScale, 1, pageScale); |
- |
- m_hostImpl->updateRootScrollLayerImplTransform(); |
- |
- if (!CCSettings::pageScalePinchZoomEnabled()) { |
- // The scale should apply to the scroll delta. |
- expectedScrollDelta.scale(pageScale); |
- } |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- expectContains(*scrollInfo.get(), scrollLayerId, expectedScrollDelta); |
- |
- // The scroll range should not have changed. |
- EXPECT_EQ(child->maxScrollPosition(), expectedMaxScroll); |
- |
- // The page scale delta remains constant because the impl thread did not scale. |
- WebTransformationMatrix identityTransform; |
- EXPECT_EQ(child->implTransform(), WebTransformationMatrix()); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollChildBeyondLimit) |
-{ |
- // Scroll a child layer beyond its maximum scroll range and make sure the |
- // parent layer is scrolled on the axis on which the child was unable to |
- // scroll. |
- IntSize surfaceSize(10, 10); |
- scoped_ptr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize); |
- |
- scoped_ptr<CCLayerImpl> grandChild = createScrollableLayer(3, surfaceSize); |
- grandChild->setScrollPosition(IntPoint(0, 5)); |
- |
- scoped_ptr<CCLayerImpl> child = createScrollableLayer(2, surfaceSize); |
- child->setScrollPosition(IntPoint(3, 0)); |
- child->addChild(grandChild.Pass()); |
- |
- root->addChild(child.Pass()); |
- m_hostImpl->setRootLayer(root.Pass()); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- initializeRendererAndDrawFrame(); |
- { |
- IntSize scrollDelta(-8, -7); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), scrollDelta); |
- m_hostImpl->scrollEnd(); |
- |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- |
- // The grand child should have scrolled up to its limit. |
- CCLayerImpl* child = m_hostImpl->rootLayer()->children()[0]; |
- CCLayerImpl* grandChild = child->children()[0]; |
- expectContains(*scrollInfo.get(), grandChild->id(), IntSize(0, -5)); |
- |
- // The child should have only scrolled on the other axis. |
- expectContains(*scrollInfo.get(), child->id(), IntSize(-3, 0)); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollEventBubbling) |
-{ |
- // When we try to scroll a non-scrollable child layer, the scroll delta |
- // should be applied to one of its ancestors if possible. |
- IntSize surfaceSize(10, 10); |
- scoped_ptr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize); |
- scoped_ptr<CCLayerImpl> child = createScrollableLayer(2, surfaceSize); |
- |
- child->setScrollable(false); |
- root->addChild(child.Pass()); |
- |
- m_hostImpl->setRootLayer(root.Pass()); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- initializeRendererAndDrawFrame(); |
- { |
- IntSize scrollDelta(0, 4); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), scrollDelta); |
- m_hostImpl->scrollEnd(); |
- |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- |
- // Only the root should have scrolled. |
- ASSERT_EQ(scrollInfo->scrolls.size(), 1u); |
- expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), scrollDelta); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollBeforeRedraw) |
-{ |
- IntSize surfaceSize(10, 10); |
- m_hostImpl->setRootLayer(createScrollableLayer(1, surfaceSize)); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- |
- // Draw one frame and then immediately rebuild the layer tree to mimic a tree synchronization. |
- initializeRendererAndDrawFrame(); |
- m_hostImpl->detachLayerTree(); |
- m_hostImpl->setRootLayer(createScrollableLayer(2, surfaceSize)); |
- |
- // Scrolling should still work even though we did not draw yet. |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollAxisAlignedRotatedLayer) |
-{ |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- |
- // Rotate the root layer 90 degrees counter-clockwise about its center. |
- WebTransformationMatrix rotateTransform; |
- rotateTransform.rotate(-90); |
- m_hostImpl->rootLayer()->setTransform(rotateTransform); |
- |
- IntSize surfaceSize(50, 50); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- initializeRendererAndDrawFrame(); |
- |
- // Scroll to the right in screen coordinates with a gesture. |
- IntSize gestureScrollDelta(10, 0); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), gestureScrollDelta); |
- m_hostImpl->scrollEnd(); |
- |
- // The layer should have scrolled down in its local coordinates. |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), IntSize(0, gestureScrollDelta.width())); |
- |
- // Reset and scroll down with the wheel. |
- m_hostImpl->rootLayer()->setScrollDelta(FloatSize()); |
- IntSize wheelScrollDelta(0, 10); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), wheelScrollDelta); |
- m_hostImpl->scrollEnd(); |
- |
- // The layer should have scrolled down in its local coordinates. |
- scrollInfo = m_hostImpl->processScrollDeltas(); |
- expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), wheelScrollDelta); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollNonAxisAlignedRotatedLayer) |
-{ |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- int childLayerId = 3; |
- float childLayerAngle = -20; |
- |
- // Create a child layer that is rotated to a non-axis-aligned angle. |
- scoped_ptr<CCLayerImpl> child = createScrollableLayer(childLayerId, m_hostImpl->rootLayer()->contentBounds()); |
- WebTransformationMatrix rotateTransform; |
- rotateTransform.translate(-50, -50); |
- rotateTransform.rotate(childLayerAngle); |
- rotateTransform.translate(50, 50); |
- child->setTransform(rotateTransform); |
- |
- // Only allow vertical scrolling. |
- child->setMaxScrollPosition(IntSize(0, child->contentBounds().height())); |
- m_hostImpl->rootLayer()->addChild(child.Pass()); |
- |
- IntSize surfaceSize(50, 50); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- initializeRendererAndDrawFrame(); |
- |
- { |
- // Scroll down in screen coordinates with a gesture. |
- IntSize gestureScrollDelta(0, 10); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), gestureScrollDelta); |
- m_hostImpl->scrollEnd(); |
- |
- // The child layer should have scrolled down in its local coordinates an amount proportional to |
- // the angle between it and the input scroll delta. |
- IntSize expectedScrollDelta(0, gestureScrollDelta.height() * cosf(deg2rad(childLayerAngle))); |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- expectContains(*scrollInfo.get(), childLayerId, expectedScrollDelta); |
- |
- // The root layer should not have scrolled, because the input delta was close to the layer's |
- // axis of movement. |
- EXPECT_EQ(scrollInfo->scrolls.size(), 1u); |
- } |
- |
- { |
- // Now reset and scroll the same amount horizontally. |
- m_hostImpl->rootLayer()->children()[1]->setScrollDelta(FloatSize()); |
- IntSize gestureScrollDelta(10, 0); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), gestureScrollDelta); |
- m_hostImpl->scrollEnd(); |
- |
- // The child layer should have scrolled down in its local coordinates an amount proportional to |
- // the angle between it and the input scroll delta. |
- IntSize expectedScrollDelta(0, -gestureScrollDelta.width() * sinf(deg2rad(childLayerAngle))); |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- expectContains(*scrollInfo.get(), childLayerId, expectedScrollDelta); |
- |
- // The root layer should have scrolled more, since the input scroll delta was mostly |
- // orthogonal to the child layer's vertical scroll axis. |
- IntSize expectedRootScrollDelta(gestureScrollDelta.width() * pow(cosf(deg2rad(childLayerAngle)), 2), 0); |
- expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedRootScrollDelta); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, scrollScaledLayer) |
-{ |
- setupScrollAndContentsLayers(IntSize(100, 100)); |
- |
- // Scale the layer to twice its normal size. |
- int scale = 2; |
- WebTransformationMatrix scaleTransform; |
- scaleTransform.scale(scale); |
- m_hostImpl->rootLayer()->setTransform(scaleTransform); |
- |
- IntSize surfaceSize(50, 50); |
- m_hostImpl->setViewportSize(surfaceSize, surfaceSize); |
- initializeRendererAndDrawFrame(); |
- |
- // Scroll down in screen coordinates with a gesture. |
- IntSize scrollDelta(0, 10); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), scrollDelta); |
- m_hostImpl->scrollEnd(); |
- |
- // The layer should have scrolled down in its local coordinates, but half he amount. |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); |
- expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), IntSize(0, scrollDelta.height() / scale)); |
- |
- // Reset and scroll down with the wheel. |
- m_hostImpl->rootLayer()->setScrollDelta(FloatSize()); |
- IntSize wheelScrollDelta(0, 10); |
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); |
- m_hostImpl->scrollBy(IntPoint(), wheelScrollDelta); |
- m_hostImpl->scrollEnd(); |
- |
- // The scale should not have been applied to the scroll delta. |
- scrollInfo = m_hostImpl->processScrollDeltas(); |
- expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), wheelScrollDelta); |
-} |
- |
-class BlendStateTrackerContext: public FakeWebGraphicsContext3D { |
-public: |
- BlendStateTrackerContext() : m_blend(false) { } |
- |
- virtual void enable(WGC3Denum cap) |
- { |
- if (cap == GraphicsContext3D::BLEND) |
- m_blend = true; |
- } |
- |
- virtual void disable(WGC3Denum cap) |
- { |
- if (cap == GraphicsContext3D::BLEND) |
- m_blend = false; |
- } |
- |
- bool blend() const { return m_blend; } |
- |
-private: |
- bool m_blend; |
-}; |
- |
-class BlendStateCheckLayer : public CCLayerImpl { |
-public: |
- static scoped_ptr<CCLayerImpl> create(int id, CCResourceProvider* resourceProvider) { return scoped_ptr<CCLayerImpl>(new BlendStateCheckLayer(id, resourceProvider)); } |
- |
- virtual void appendQuads(CCQuadSink& quadSink, CCAppendQuadsData& appendQuadsData) OVERRIDE |
- { |
- m_quadsAppended = true; |
- |
- IntRect opaqueRect; |
- if (contentsOpaque()) |
- opaqueRect = m_quadRect; |
- else |
- opaqueRect = m_opaqueContentRect; |
- |
- CCSharedQuadState* sharedQuadState = quadSink.useSharedQuadState(createSharedQuadState()); |
- scoped_ptr<CCTileDrawQuad> testBlendingDrawQuad = CCTileDrawQuad::create(sharedQuadState, m_quadRect, opaqueRect, m_resourceId, IntPoint(), IntSize(1, 1), 0, false, false, false, false, false); |
- testBlendingDrawQuad->setQuadVisibleRect(m_quadVisibleRect); |
- EXPECT_EQ(m_blend, testBlendingDrawQuad->needsBlending()); |
- EXPECT_EQ(m_hasRenderSurface, !!renderSurface()); |
- quadSink.append(testBlendingDrawQuad.PassAs<CCDrawQuad>(), appendQuadsData); |
- } |
- |
- void setExpectation(bool blend, bool hasRenderSurface) |
- { |
- m_blend = blend; |
- m_hasRenderSurface = hasRenderSurface; |
- m_quadsAppended = false; |
- } |
- |
- bool quadsAppended() const { return m_quadsAppended; } |
- |
- void setQuadRect(const IntRect& rect) { m_quadRect = rect; } |
- void setQuadVisibleRect(const IntRect& rect) { m_quadVisibleRect = rect; } |
- void setOpaqueContentRect(const IntRect& rect) { m_opaqueContentRect = rect; } |
- |
-private: |
- explicit BlendStateCheckLayer(int id, CCResourceProvider* resourceProvider) |
- : CCLayerImpl(id) |
- , m_blend(false) |
- , m_hasRenderSurface(false) |
- , m_quadsAppended(false) |
- , m_quadRect(5, 5, 5, 5) |
- , m_quadVisibleRect(5, 5, 5, 5) |
- , m_resourceId(resourceProvider->createResource(CCRenderer::ContentPool, IntSize(1, 1), GraphicsContext3D::RGBA, CCResourceProvider::TextureUsageAny)) |
- { |
- setAnchorPoint(FloatPoint(0, 0)); |
- setBounds(IntSize(10, 10)); |
- setContentBounds(IntSize(10, 10)); |
- setDrawsContent(true); |
- } |
- |
- bool m_blend; |
- bool m_hasRenderSurface; |
- bool m_quadsAppended; |
- IntRect m_quadRect; |
- IntRect m_opaqueContentRect; |
- IntRect m_quadVisibleRect; |
- CCResourceProvider::ResourceId m_resourceId; |
-}; |
- |
-TEST_P(CCLayerTreeHostImplTest, blendingOffWhenDrawingOpaqueLayers) |
-{ |
- { |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setBounds(IntSize(10, 10)); |
- root->setContentBounds(root->bounds()); |
- root->setDrawsContent(false); |
- m_hostImpl->setRootLayer(root.Pass()); |
- } |
- CCLayerImpl* root = m_hostImpl->rootLayer(); |
- |
- root->addChild(BlendStateCheckLayer::create(2, m_hostImpl->resourceProvider())); |
- BlendStateCheckLayer* layer1 = static_cast<BlendStateCheckLayer*>(root->children()[0]); |
- layer1->setPosition(FloatPoint(2, 2)); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- |
- // Opaque layer, drawn without blending. |
- layer1->setContentsOpaque(true); |
- layer1->setExpectation(false, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // Layer with translucent content and painting, so drawn with blending. |
- layer1->setContentsOpaque(false); |
- layer1->setExpectation(true, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // Layer with translucent opacity, drawn with blending. |
- layer1->setContentsOpaque(true); |
- layer1->setOpacity(0.5); |
- layer1->setExpectation(true, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // Layer with translucent opacity and painting, drawn with blending. |
- layer1->setContentsOpaque(true); |
- layer1->setOpacity(0.5); |
- layer1->setExpectation(true, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- layer1->addChild(BlendStateCheckLayer::create(3, m_hostImpl->resourceProvider())); |
- BlendStateCheckLayer* layer2 = static_cast<BlendStateCheckLayer*>(layer1->children()[0]); |
- layer2->setPosition(FloatPoint(4, 4)); |
- |
- // 2 opaque layers, drawn without blending. |
- layer1->setContentsOpaque(true); |
- layer1->setOpacity(1); |
- layer1->setExpectation(false, false); |
- layer2->setContentsOpaque(true); |
- layer2->setOpacity(1); |
- layer2->setExpectation(false, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- EXPECT_TRUE(layer2->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // Parent layer with translucent content, drawn with blending. |
- // Child layer with opaque content, drawn without blending. |
- layer1->setContentsOpaque(false); |
- layer1->setExpectation(true, false); |
- layer2->setExpectation(false, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- EXPECT_TRUE(layer2->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // Parent layer with translucent content but opaque painting, drawn without blending. |
- // Child layer with opaque content, drawn without blending. |
- layer1->setContentsOpaque(true); |
- layer1->setExpectation(false, false); |
- layer2->setExpectation(false, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- EXPECT_TRUE(layer2->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // Parent layer with translucent opacity and opaque content. Since it has a |
- // drawing child, it's drawn to a render surface which carries the opacity, |
- // so it's itself drawn without blending. |
- // Child layer with opaque content, drawn without blending (parent surface |
- // carries the inherited opacity). |
- layer1->setContentsOpaque(true); |
- layer1->setOpacity(0.5); |
- layer1->setExpectation(false, true); |
- layer2->setExpectation(false, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- EXPECT_TRUE(layer2->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // Draw again, but with child non-opaque, to make sure |
- // layer1 not culled. |
- layer1->setContentsOpaque(true); |
- layer1->setOpacity(1); |
- layer1->setExpectation(false, false); |
- layer2->setContentsOpaque(true); |
- layer2->setOpacity(0.5); |
- layer2->setExpectation(true, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- EXPECT_TRUE(layer2->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // A second way of making the child non-opaque. |
- layer1->setContentsOpaque(true); |
- layer1->setOpacity(1); |
- layer1->setExpectation(false, false); |
- layer2->setContentsOpaque(false); |
- layer2->setOpacity(1); |
- layer2->setExpectation(true, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- EXPECT_TRUE(layer2->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // And when the layer says its not opaque but is painted opaque, it is not blended. |
- layer1->setContentsOpaque(true); |
- layer1->setOpacity(1); |
- layer1->setExpectation(false, false); |
- layer2->setContentsOpaque(true); |
- layer2->setOpacity(1); |
- layer2->setExpectation(false, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- EXPECT_TRUE(layer2->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // Layer with partially opaque contents, drawn with blending. |
- layer1->setContentsOpaque(false); |
- layer1->setQuadRect(IntRect(5, 5, 5, 5)); |
- layer1->setQuadVisibleRect(IntRect(5, 5, 5, 5)); |
- layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5)); |
- layer1->setExpectation(true, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // Layer with partially opaque contents partially culled, drawn with blending. |
- layer1->setContentsOpaque(false); |
- layer1->setQuadRect(IntRect(5, 5, 5, 5)); |
- layer1->setQuadVisibleRect(IntRect(5, 5, 5, 2)); |
- layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5)); |
- layer1->setExpectation(true, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // Layer with partially opaque contents culled, drawn with blending. |
- layer1->setContentsOpaque(false); |
- layer1->setQuadRect(IntRect(5, 5, 5, 5)); |
- layer1->setQuadVisibleRect(IntRect(7, 5, 3, 5)); |
- layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5)); |
- layer1->setExpectation(true, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- // Layer with partially opaque contents and translucent contents culled, drawn without blending. |
- layer1->setContentsOpaque(false); |
- layer1->setQuadRect(IntRect(5, 5, 5, 5)); |
- layer1->setQuadVisibleRect(IntRect(5, 5, 2, 5)); |
- layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5)); |
- layer1->setExpectation(false, false); |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(layer1->quadsAppended()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, viewportCovered) |
-{ |
- m_hostImpl->initializeRenderer(createContext()); |
- m_hostImpl->setBackgroundColor(SK_ColorGRAY); |
- |
- IntSize viewportSize(1000, 1000); |
- m_hostImpl->setViewportSize(viewportSize, viewportSize); |
- |
- m_hostImpl->setRootLayer(BlendStateCheckLayer::create(1, m_hostImpl->resourceProvider())); |
- BlendStateCheckLayer* root = static_cast<BlendStateCheckLayer*>(m_hostImpl->rootLayer()); |
- root->setExpectation(false, true); |
- root->setContentsOpaque(true); |
- |
- // No gutter rects |
- { |
- IntRect layerRect(0, 0, 1000, 1000); |
- root->setPosition(layerRect.location()); |
- root->setBounds(layerRect.size()); |
- root->setContentBounds(layerRect.size()); |
- root->setQuadRect(IntRect(IntPoint(), layerRect.size())); |
- root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size())); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- ASSERT_EQ(1u, frame.renderPasses.size()); |
- |
- size_t numGutterQuads = 0; |
- for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i) |
- numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0; |
- EXPECT_EQ(0u, numGutterQuads); |
- EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size()); |
- |
- verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize)); |
- m_hostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Empty visible content area (fullscreen gutter rect) |
- { |
- IntRect layerRect(0, 0, 0, 0); |
- root->setPosition(layerRect.location()); |
- root->setBounds(layerRect.size()); |
- root->setContentBounds(layerRect.size()); |
- root->setQuadRect(IntRect(IntPoint(), layerRect.size())); |
- root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size())); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- ASSERT_EQ(1u, frame.renderPasses.size()); |
- m_hostImpl->didDrawAllLayers(frame); |
- |
- size_t numGutterQuads = 0; |
- for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i) |
- numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0; |
- EXPECT_EQ(1u, numGutterQuads); |
- EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size()); |
- |
- verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize)); |
- m_hostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Content area in middle of clip rect (four surrounding gutter rects) |
- { |
- IntRect layerRect(500, 500, 200, 200); |
- root->setPosition(layerRect.location()); |
- root->setBounds(layerRect.size()); |
- root->setContentBounds(layerRect.size()); |
- root->setQuadRect(IntRect(IntPoint(), layerRect.size())); |
- root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size())); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- ASSERT_EQ(1u, frame.renderPasses.size()); |
- |
- size_t numGutterQuads = 0; |
- for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i) |
- numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0; |
- EXPECT_EQ(4u, numGutterQuads); |
- EXPECT_EQ(5u, frame.renderPasses[0]->quadList().size()); |
- |
- verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize)); |
- m_hostImpl->didDrawAllLayers(frame); |
- } |
- |
-} |
- |
- |
-class ReshapeTrackerContext: public FakeWebGraphicsContext3D { |
-public: |
- ReshapeTrackerContext() : m_reshapeCalled(false) { } |
- |
- virtual void reshape(int width, int height) |
- { |
- m_reshapeCalled = true; |
- } |
- |
- bool reshapeCalled() const { return m_reshapeCalled; } |
- |
-private: |
- bool m_reshapeCalled; |
-}; |
- |
-class FakeDrawableCCLayerImpl: public CCLayerImpl { |
-public: |
- static scoped_ptr<CCLayerImpl> create(int id) { return scoped_ptr<CCLayerImpl>(new FakeDrawableCCLayerImpl(id)); } |
-protected: |
- explicit FakeDrawableCCLayerImpl(int id) : CCLayerImpl(id) { } |
-}; |
- |
-// Only reshape when we know we are going to draw. Otherwise, the reshape |
-// can leave the window at the wrong size if we never draw and the proper |
-// viewport size is never set. |
-TEST_P(CCLayerTreeHostImplTest, reshapeNotCalledUntilDraw) |
-{ |
- scoped_ptr<CCGraphicsContext> ccContext = FakeWebCompositorOutputSurface::create(adoptPtr(new ReshapeTrackerContext)).PassAs<CCGraphicsContext>(); |
- ReshapeTrackerContext* reshapeTracker = static_cast<ReshapeTrackerContext*>(ccContext->context3D()); |
- m_hostImpl->initializeRenderer(ccContext.Pass()); |
- |
- scoped_ptr<CCLayerImpl> root = FakeDrawableCCLayerImpl::create(1); |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setBounds(IntSize(10, 10)); |
- root->setDrawsContent(true); |
- m_hostImpl->setRootLayer(root.Pass()); |
- EXPECT_FALSE(reshapeTracker->reshapeCalled()); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- EXPECT_TRUE(reshapeTracker->reshapeCalled()); |
- m_hostImpl->didDrawAllLayers(frame); |
-} |
- |
-class PartialSwapTrackerContext : public FakeWebGraphicsContext3D { |
-public: |
- virtual void postSubBufferCHROMIUM(int x, int y, int width, int height) |
- { |
- m_partialSwapRect = IntRect(x, y, width, height); |
- } |
- |
- virtual WebString getString(WGC3Denum name) |
- { |
- if (name == GraphicsContext3D::EXTENSIONS) |
- return WebString("GL_CHROMIUM_post_sub_buffer GL_CHROMIUM_set_visibility"); |
- |
- return WebString(); |
- } |
- |
- IntRect partialSwapRect() const { return m_partialSwapRect; } |
- |
-private: |
- IntRect m_partialSwapRect; |
-}; |
- |
-// Make sure damage tracking propagates all the way to the graphics context, |
-// where it should request to swap only the subBuffer that is damaged. |
-TEST_P(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect) |
-{ |
- scoped_ptr<CCGraphicsContext> ccContext = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapTrackerContext)).PassAs<CCGraphicsContext>(); |
- PartialSwapTrackerContext* partialSwapTracker = static_cast<PartialSwapTrackerContext*>(ccContext->context3D()); |
- |
- // This test creates its own CCLayerTreeHostImpl, so |
- // that we can force partial swap enabled. |
- CCLayerTreeSettings settings; |
- CCSettings::setPartialSwapEnabled(true); |
- scoped_ptr<CCLayerTreeHostImpl> layerTreeHostImpl = CCLayerTreeHostImpl::create(settings, this); |
- layerTreeHostImpl->initializeRenderer(ccContext.Pass()); |
- layerTreeHostImpl->setViewportSize(IntSize(500, 500), IntSize(500, 500)); |
- |
- scoped_ptr<CCLayerImpl> root = FakeDrawableCCLayerImpl::create(1); |
- scoped_ptr<CCLayerImpl> child = FakeDrawableCCLayerImpl::create(2); |
- child->setPosition(FloatPoint(12, 13)); |
- child->setAnchorPoint(FloatPoint(0, 0)); |
- child->setBounds(IntSize(14, 15)); |
- child->setContentBounds(IntSize(14, 15)); |
- child->setDrawsContent(true); |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setBounds(IntSize(500, 500)); |
- root->setContentBounds(IntSize(500, 500)); |
- root->setDrawsContent(true); |
- root->addChild(child.Pass()); |
- layerTreeHostImpl->setRootLayer(root.Pass()); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- |
- // First frame, the entire screen should get swapped. |
- EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame)); |
- layerTreeHostImpl->drawLayers(frame); |
- layerTreeHostImpl->didDrawAllLayers(frame); |
- layerTreeHostImpl->swapBuffers(); |
- IntRect actualSwapRect = partialSwapTracker->partialSwapRect(); |
- IntRect expectedSwapRect = IntRect(IntPoint::zero(), IntSize(500, 500)); |
- EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x()); |
- EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y()); |
- EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width()); |
- EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height()); |
- |
- // Second frame, only the damaged area should get swapped. Damage should be the union |
- // of old and new child rects. |
- // expected damage rect: IntRect(IntPoint::zero(), IntSize(26, 28)); |
- // expected swap rect: vertically flipped, with origin at bottom left corner. |
- layerTreeHostImpl->rootLayer()->children()[0]->setPosition(FloatPoint(0, 0)); |
- EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame)); |
- layerTreeHostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- layerTreeHostImpl->swapBuffers(); |
- actualSwapRect = partialSwapTracker->partialSwapRect(); |
- expectedSwapRect = IntRect(IntPoint(0, 500-28), IntSize(26, 28)); |
- EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x()); |
- EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y()); |
- EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width()); |
- EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height()); |
- |
- // Make sure that partial swap is constrained to the viewport dimensions |
- // expected damage rect: IntRect(IntPoint::zero(), IntSize(500, 500)); |
- // expected swap rect: flipped damage rect, but also clamped to viewport |
- layerTreeHostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10)); |
- layerTreeHostImpl->rootLayer()->setOpacity(0.7f); // this will damage everything |
- EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame)); |
- layerTreeHostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- layerTreeHostImpl->swapBuffers(); |
- actualSwapRect = partialSwapTracker->partialSwapRect(); |
- expectedSwapRect = IntRect(IntPoint::zero(), IntSize(10, 10)); |
- EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x()); |
- EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y()); |
- EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width()); |
- EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height()); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, rootLayerDoesntCreateExtraSurface) |
-{ |
- scoped_ptr<CCLayerImpl> root = FakeDrawableCCLayerImpl::create(1); |
- scoped_ptr<CCLayerImpl> child = FakeDrawableCCLayerImpl::create(2); |
- child->setAnchorPoint(FloatPoint(0, 0)); |
- child->setBounds(IntSize(10, 10)); |
- child->setContentBounds(IntSize(10, 10)); |
- child->setDrawsContent(true); |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setBounds(IntSize(10, 10)); |
- root->setContentBounds(IntSize(10, 10)); |
- root->setDrawsContent(true); |
- root->setOpacity(0.7f); |
- root->addChild(child.Pass()); |
- |
- m_hostImpl->setRootLayer(root.Pass()); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- EXPECT_EQ(1u, frame.renderSurfaceLayerList->size()); |
- EXPECT_EQ(1u, frame.renderPasses.size()); |
- m_hostImpl->didDrawAllLayers(frame); |
-} |
- |
-} // namespace |
- |
-class FakeLayerWithQuads : public CCLayerImpl { |
-public: |
- static scoped_ptr<CCLayerImpl> create(int id) { return scoped_ptr<CCLayerImpl>(new FakeLayerWithQuads(id)); } |
- |
- virtual void appendQuads(CCQuadSink& quadSink, CCAppendQuadsData& appendQuadsData) OVERRIDE |
- { |
- CCSharedQuadState* sharedQuadState = quadSink.useSharedQuadState(createSharedQuadState()); |
- |
- SkColor gray = SkColorSetRGB(100, 100, 100); |
- IntRect quadRect(IntPoint(0, 0), contentBounds()); |
- scoped_ptr<CCSolidColorDrawQuad> myQuad = CCSolidColorDrawQuad::create(sharedQuadState, quadRect, gray); |
- quadSink.append(myQuad.PassAs<CCDrawQuad>(), appendQuadsData); |
- } |
- |
-private: |
- FakeLayerWithQuads(int id) |
- : CCLayerImpl(id) |
- { |
- } |
-}; |
- |
-namespace { |
- |
-class MockContext : public FakeWebGraphicsContext3D { |
-public: |
- MOCK_METHOD1(useProgram, void(WebGLId program)); |
- MOCK_METHOD5(uniform4f, void(WGC3Dint location, WGC3Dfloat x, WGC3Dfloat y, WGC3Dfloat z, WGC3Dfloat w)); |
- MOCK_METHOD4(uniformMatrix4fv, void(WGC3Dint location, WGC3Dsizei count, WGC3Dboolean transpose, const WGC3Dfloat* value)); |
- MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum type, WGC3Dintptr offset)); |
- MOCK_METHOD1(getString, WebString(WGC3Denum name)); |
- MOCK_METHOD0(getRequestableExtensionsCHROMIUM, WebString()); |
- MOCK_METHOD1(enable, void(WGC3Denum cap)); |
- MOCK_METHOD1(disable, void(WGC3Denum cap)); |
- MOCK_METHOD4(scissor, void(WGC3Dint x, WGC3Dint y, WGC3Dsizei width, WGC3Dsizei height)); |
-}; |
- |
-class MockContextHarness { |
-private: |
- MockContext* m_context; |
-public: |
- MockContextHarness(MockContext* context) |
- : m_context(context) |
- { |
- // Catch "uninteresting" calls |
- EXPECT_CALL(*m_context, useProgram(_)) |
- .Times(0); |
- |
- EXPECT_CALL(*m_context, drawElements(_, _, _, _)) |
- .Times(0); |
- |
- // These are not asserted |
- EXPECT_CALL(*m_context, uniformMatrix4fv(_, _, _, _)) |
- .WillRepeatedly(Return()); |
- |
- EXPECT_CALL(*m_context, uniform4f(_, _, _, _, _)) |
- .WillRepeatedly(Return()); |
- |
- // Any other strings are empty |
- EXPECT_CALL(*m_context, getString(_)) |
- .WillRepeatedly(Return(WebString())); |
- |
- // Support for partial swap, if needed |
- EXPECT_CALL(*m_context, getString(GraphicsContext3D::EXTENSIONS)) |
- .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer"))); |
- |
- EXPECT_CALL(*m_context, getRequestableExtensionsCHROMIUM()) |
- .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer"))); |
- |
- // Any un-sanctioned calls to enable() are OK |
- EXPECT_CALL(*m_context, enable(_)) |
- .WillRepeatedly(Return()); |
- |
- // Any un-sanctioned calls to disable() are OK |
- EXPECT_CALL(*m_context, disable(_)) |
- .WillRepeatedly(Return()); |
- } |
- |
- void mustDrawSolidQuad() |
- { |
- EXPECT_CALL(*m_context, drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0)) |
- .WillOnce(Return()) |
- .RetiresOnSaturation(); |
- |
- // 1 is hardcoded return value of fake createProgram() |
- EXPECT_CALL(*m_context, useProgram(1)) |
- .WillOnce(Return()) |
- .RetiresOnSaturation(); |
- |
- } |
- |
- void mustSetScissor(int x, int y, int width, int height) |
- { |
- EXPECT_CALL(*m_context, enable(GraphicsContext3D::SCISSOR_TEST)) |
- .WillRepeatedly(Return()); |
- |
- EXPECT_CALL(*m_context, scissor(x, y, width, height)) |
- .Times(AtLeast(1)) |
- .WillRepeatedly(Return()); |
- } |
- |
- void mustSetNoScissor() |
- { |
- EXPECT_CALL(*m_context, disable(GraphicsContext3D::SCISSOR_TEST)) |
- .WillRepeatedly(Return()); |
- |
- EXPECT_CALL(*m_context, enable(GraphicsContext3D::SCISSOR_TEST)) |
- .Times(0); |
- |
- EXPECT_CALL(*m_context, scissor(_, _, _, _)) |
- .Times(0); |
- } |
-}; |
- |
-TEST_P(CCLayerTreeHostImplTest, noPartialSwap) |
-{ |
- scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new MockContext)).PassAs<CCGraphicsContext>(); |
- MockContext* mockContext = static_cast<MockContext*>(context->context3D()); |
- MockContextHarness harness(mockContext); |
- |
- harness.mustDrawSolidQuad(); |
- harness.mustSetScissor(0, 0, 10, 10); |
- |
- // Run test case |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(false, context.Pass(), FakeLayerWithQuads::create(1)); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- Mock::VerifyAndClearExpectations(&mockContext); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, partialSwap) |
-{ |
- scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new MockContext)).PassAs<CCGraphicsContext>(); |
- MockContext* mockContext = static_cast<MockContext*>(context->context3D()); |
- MockContextHarness harness(mockContext); |
- |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(true, context.Pass(), FakeLayerWithQuads::create(1)); |
- |
- // The first frame is not a partially-swapped one. |
- harness.mustSetScissor(0, 0, 10, 10); |
- harness.mustDrawSolidQuad(); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- Mock::VerifyAndClearExpectations(&mockContext); |
- |
- // Damage a portion of the frame. |
- myHostImpl->rootLayer()->setUpdateRect(IntRect(0, 0, 2, 3)); |
- |
- // The second frame will be partially-swapped (the y coordinates are flipped). |
- harness.mustSetScissor(0, 7, 2, 3); |
- harness.mustDrawSolidQuad(); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- Mock::VerifyAndClearExpectations(&mockContext); |
-} |
- |
-class PartialSwapContext : public FakeWebGraphicsContext3D { |
-public: |
- WebString getString(WGC3Denum name) |
- { |
- if (name == GraphicsContext3D::EXTENSIONS) |
- return WebString("GL_CHROMIUM_post_sub_buffer"); |
- return WebString(); |
- } |
- |
- WebString getRequestableExtensionsCHROMIUM() |
- { |
- return WebString("GL_CHROMIUM_post_sub_buffer"); |
- } |
- |
- // Unlimited texture size. |
- virtual void getIntegerv(WGC3Denum pname, WGC3Dint* value) |
- { |
- if (pname == cc::GraphicsContext3D::MAX_TEXTURE_SIZE) |
- *value = 8192; |
- } |
-}; |
- |
-static scoped_ptr<CCLayerTreeHostImpl> setupLayersForOpacity(bool partialSwap, CCLayerTreeHostImplClient* client) |
-{ |
- CCSettings::setPartialSwapEnabled(partialSwap); |
- |
- scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); |
- |
- CCLayerTreeSettings settings; |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, client); |
- myHostImpl->initializeRenderer(context.Pass()); |
- myHostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100)); |
- |
- /* |
- Layers are created as follows: |
- |
- +--------------------+ |
- | 1 | |
- | +-----------+ | |
- | | 2 | | |
- | | +-------------------+ |
- | | | 3 | |
- | | +-------------------+ |
- | | | | |
- | +-----------+ | |
- | | |
- | | |
- +--------------------+ |
- |
- Layers 1, 2 have render surfaces |
- */ |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- scoped_ptr<CCLayerImpl> child = CCLayerImpl::create(2); |
- scoped_ptr<CCLayerImpl> grandChild = FakeLayerWithQuads::create(3); |
- |
- IntRect rootRect(0, 0, 100, 100); |
- IntRect childRect(10, 10, 50, 50); |
- IntRect grandChildRect(5, 5, 150, 150); |
- |
- root->createRenderSurface(); |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setPosition(FloatPoint(rootRect.x(), rootRect.y())); |
- root->setBounds(IntSize(rootRect.width(), rootRect.height())); |
- root->setContentBounds(root->bounds()); |
- root->setVisibleContentRect(rootRect); |
- root->setDrawsContent(false); |
- root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.width(), rootRect.height()))); |
- |
- child->setAnchorPoint(FloatPoint(0, 0)); |
- child->setPosition(FloatPoint(childRect.x(), childRect.y())); |
- child->setOpacity(0.5f); |
- child->setBounds(IntSize(childRect.width(), childRect.height())); |
- child->setContentBounds(child->bounds()); |
- child->setVisibleContentRect(childRect); |
- child->setDrawsContent(false); |
- |
- grandChild->setAnchorPoint(FloatPoint(0, 0)); |
- grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y())); |
- grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height())); |
- grandChild->setContentBounds(grandChild->bounds()); |
- grandChild->setVisibleContentRect(grandChildRect); |
- grandChild->setDrawsContent(true); |
- |
- child->addChild(grandChild.Pass()); |
- root->addChild(child.Pass()); |
- |
- myHostImpl->setRootLayer(root.Pass()); |
- return myHostImpl.Pass(); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, contributingLayerEmptyScissorPartialSwap) |
-{ |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(true, this); |
- |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Just for consistency, the most interesting stuff already happened |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- |
- // Verify all quads have been computed |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size()); |
- EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material()); |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material()); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, contributingLayerEmptyScissorNoPartialSwap) |
-{ |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(false, this); |
- |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Just for consistency, the most interesting stuff already happened |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- |
- // Verify all quads have been computed |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size()); |
- EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material()); |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material()); |
- } |
-} |
- |
-// Make sure that context lost notifications are propagated through the tree. |
-class ContextLostNotificationCheckLayer : public CCLayerImpl { |
-public: |
- static scoped_ptr<CCLayerImpl> create(int id) { return scoped_ptr<CCLayerImpl>(new ContextLostNotificationCheckLayer(id)); } |
- |
- virtual void didLoseContext() OVERRIDE |
- { |
- m_didLoseContextCalled = true; |
- } |
- |
- bool didLoseContextCalled() const { return m_didLoseContextCalled; } |
- |
-private: |
- explicit ContextLostNotificationCheckLayer(int id) |
- : CCLayerImpl(id) |
- , m_didLoseContextCalled(false) |
- { |
- } |
- |
- bool m_didLoseContextCalled; |
-}; |
- |
-TEST_P(CCLayerTreeHostImplTest, contextLostAndRestoredNotificationSentToAllLayers) |
-{ |
- m_hostImpl->setRootLayer(ContextLostNotificationCheckLayer::create(1)); |
- ContextLostNotificationCheckLayer* root = static_cast<ContextLostNotificationCheckLayer*>(m_hostImpl->rootLayer()); |
- |
- root->addChild(ContextLostNotificationCheckLayer::create(1)); |
- ContextLostNotificationCheckLayer* layer1 = static_cast<ContextLostNotificationCheckLayer*>(root->children()[0]); |
- |
- layer1->addChild(ContextLostNotificationCheckLayer::create(2)); |
- ContextLostNotificationCheckLayer* layer2 = static_cast<ContextLostNotificationCheckLayer*>(layer1->children()[0]); |
- |
- EXPECT_FALSE(root->didLoseContextCalled()); |
- EXPECT_FALSE(layer1->didLoseContextCalled()); |
- EXPECT_FALSE(layer2->didLoseContextCalled()); |
- |
- m_hostImpl->initializeRenderer(createContext()); |
- |
- EXPECT_TRUE(root->didLoseContextCalled()); |
- EXPECT_TRUE(layer1->didLoseContextCalled()); |
- EXPECT_TRUE(layer2->didLoseContextCalled()); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, finishAllRenderingAfterContextLost) |
-{ |
- CCLayerTreeSettings settings; |
- m_hostImpl = CCLayerTreeHostImpl::create(settings, this); |
- |
- // The context initialization will fail, but we should still be able to call finishAllRendering() without any ill effects. |
- m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFails)).PassAs<CCGraphicsContext>()); |
- m_hostImpl->finishAllRendering(); |
-} |
- |
-class FakeWebGraphicsContext3DMakeCurrentFailsEventually : public FakeWebGraphicsContext3D { |
-public: |
- explicit FakeWebGraphicsContext3DMakeCurrentFailsEventually(unsigned succeedCount) : m_succeedCount(succeedCount) { } |
- virtual bool makeContextCurrent() { |
- if (!m_succeedCount) |
- return false; |
- --m_succeedCount; |
- return true; |
- } |
- |
-private: |
- unsigned m_succeedCount; |
-}; |
- |
-TEST_P(CCLayerTreeHostImplTest, contextLostDuringInitialize) |
-{ |
- CCLayerTreeSettings settings; |
- m_hostImpl = CCLayerTreeHostImpl::create(settings, this); |
- |
- // Initialize into a known successful state. |
- EXPECT_TRUE(m_hostImpl->initializeRenderer(createContext())); |
- EXPECT_TRUE(m_hostImpl->context()); |
- EXPECT_TRUE(m_hostImpl->renderer()); |
- EXPECT_TRUE(m_hostImpl->resourceProvider()); |
- |
- // We will make the context get lost after a numer of makeContextCurrent |
- // calls. The exact number of calls to make it succeed is dependent on the |
- // implementation and doesn't really matter (i.e. can be changed to make the |
- // tests pass after some refactoring). |
- const unsigned kMakeCurrentSuccessesNeededForSuccessfulInitialization = 3; |
- |
- for (unsigned i = 0; i < kMakeCurrentSuccessesNeededForSuccessfulInitialization; ++i) { |
- // The context will get lost during initialization, we shouldn't crash. We |
- // should also be in a consistent state. |
- EXPECT_FALSE(m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFailsEventually(i))).PassAs<CCGraphicsContext>())); |
- EXPECT_EQ(0, m_hostImpl->context()); |
- EXPECT_EQ(0, m_hostImpl->renderer()); |
- EXPECT_EQ(0, m_hostImpl->resourceProvider()); |
- EXPECT_TRUE(m_hostImpl->initializeRenderer(createContext())); |
- } |
- |
- EXPECT_TRUE(m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFailsEventually(kMakeCurrentSuccessesNeededForSuccessfulInitialization))).PassAs<CCGraphicsContext>())); |
- EXPECT_TRUE(m_hostImpl->context()); |
- EXPECT_TRUE(m_hostImpl->renderer()); |
- EXPECT_TRUE(m_hostImpl->resourceProvider()); |
-} |
- |
-// Fake WebGraphicsContext3D that will cause a failure if trying to use a |
-// resource that wasn't created by it (resources created by |
-// FakeWebGraphicsContext3D have an id of 1). |
-class StrictWebGraphicsContext3D : public FakeWebGraphicsContext3D { |
-public: |
- StrictWebGraphicsContext3D() |
- : FakeWebGraphicsContext3D() |
- { |
- m_nextTextureId = 7; // Start allocating texture ids larger than any other resource IDs so we can tell if someone's mixing up their resource types. |
- } |
- |
- virtual WebGLId createBuffer() { return 2; } |
- virtual WebGLId createFramebuffer() { return 3; } |
- virtual WebGLId createProgram() { return 4; } |
- virtual WebGLId createRenderbuffer() { return 5; } |
- virtual WebGLId createShader(WGC3Denum) { return 6; } |
- |
- virtual void deleteBuffer(WebGLId id) |
- { |
- if (id != 2) |
- ADD_FAILURE() << "Trying to delete buffer id " << id; |
- } |
- |
- virtual void deleteFramebuffer(WebGLId id) |
- { |
- if (id != 3) |
- ADD_FAILURE() << "Trying to delete framebuffer id " << id; |
- } |
- |
- virtual void deleteProgram(WebGLId id) |
- { |
- if (id != 4) |
- ADD_FAILURE() << "Trying to delete program id " << id; |
- } |
- |
- virtual void deleteRenderbuffer(WebGLId id) |
- { |
- if (id != 5) |
- ADD_FAILURE() << "Trying to delete renderbuffer id " << id; |
- } |
- |
- virtual void deleteShader(WebGLId id) |
- { |
- if (id != 6) |
- ADD_FAILURE() << "Trying to delete shader id " << id; |
- } |
- |
- virtual WebGLId createTexture() |
- { |
- unsigned textureId = FakeWebGraphicsContext3D::createTexture(); |
- m_allocatedTextureIds.insert(textureId); |
- return textureId; |
- } |
- virtual void deleteTexture(WebGLId id) |
- { |
- if (!ContainsKey(m_allocatedTextureIds, id)) |
- ADD_FAILURE() << "Trying to delete texture id " << id; |
- m_allocatedTextureIds.erase(id); |
- } |
- |
- virtual void bindBuffer(WGC3Denum, WebGLId id) |
- { |
- if (id != 2 && id) |
- ADD_FAILURE() << "Trying to bind buffer id " << id; |
- } |
- |
- virtual void bindFramebuffer(WGC3Denum, WebGLId id) |
- { |
- if (id != 3 && id) |
- ADD_FAILURE() << "Trying to bind framebuffer id " << id; |
- } |
- |
- virtual void useProgram(WebGLId id) |
- { |
- if (id != 4) |
- ADD_FAILURE() << "Trying to use program id " << id; |
- } |
- |
- virtual void bindRenderbuffer(WGC3Denum, WebGLId id) |
- { |
- if (id != 5 && id) |
- ADD_FAILURE() << "Trying to bind renderbuffer id " << id; |
- } |
- |
- virtual void attachShader(WebGLId program, WebGLId shader) |
- { |
- if ((program != 4) || (shader != 6)) |
- ADD_FAILURE() << "Trying to attach shader id " << shader << " to program id " << program; |
- } |
- |
- virtual void bindTexture(WGC3Denum, WebGLId id) |
- { |
- if (id && !ContainsKey(m_allocatedTextureIds, id)) |
- ADD_FAILURE() << "Trying to bind texture id " << id; |
- } |
- |
-private: |
- base::hash_set<unsigned> m_allocatedTextureIds; |
-}; |
- |
-// Fake video frame that represents a 4x4 YUV video frame. |
-class FakeVideoFrame: public WebVideoFrame { |
-public: |
- FakeVideoFrame() : m_textureId(0) { memset(m_data, 0x80, sizeof(m_data)); } |
- virtual ~FakeVideoFrame() { } |
- virtual Format format() const { return m_textureId ? FormatNativeTexture : FormatYV12; } |
- virtual unsigned width() const { return 4; } |
- virtual unsigned height() const { return 4; } |
- virtual unsigned planes() const { return 3; } |
- virtual int stride(unsigned plane) const { return 4; } |
- virtual const void* data(unsigned plane) const { return m_data; } |
- virtual unsigned textureId() const { return m_textureId; } |
- virtual unsigned textureTarget() const { return m_textureId ? GraphicsContext3D::TEXTURE_2D : 0; } |
- |
- void setTextureId(unsigned id) { m_textureId = id; } |
- |
-private: |
- char m_data[16]; |
- unsigned m_textureId; |
-}; |
- |
-// Fake video frame provider that always provides the same FakeVideoFrame. |
-class FakeVideoFrameProvider: public WebVideoFrameProvider { |
-public: |
- FakeVideoFrameProvider() : m_frame(0), m_client(0) { } |
- virtual ~FakeVideoFrameProvider() |
- { |
- if (m_client) |
- m_client->stopUsingProvider(); |
- } |
- |
- virtual void setVideoFrameProviderClient(Client* client) { m_client = client; } |
- virtual WebVideoFrame* getCurrentFrame() { return m_frame; } |
- virtual void putCurrentFrame(WebVideoFrame*) { } |
- |
- void setFrame(WebVideoFrame* frame) { m_frame = frame; } |
- |
-private: |
- WebVideoFrame* m_frame; |
- Client* m_client; |
-}; |
- |
-class StrictWebGraphicsContext3DWithIOSurface : public StrictWebGraphicsContext3D { |
-public: |
- virtual WebString getString(WGC3Denum name) OVERRIDE |
- { |
- if (name == cc::GraphicsContext3D::EXTENSIONS) |
- return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle"); |
- |
- return WebString(); |
- } |
-}; |
- |
-class FakeWebGraphicsContext3DWithIOSurface : public FakeWebGraphicsContext3D { |
-public: |
- virtual WebString getString(WGC3Denum name) OVERRIDE |
- { |
- if (name == cc::GraphicsContext3D::EXTENSIONS) |
- return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle"); |
- |
- return WebString(); |
- } |
-}; |
- |
-class FakeWebScrollbarThemeGeometryNonEmpty : public FakeWebScrollbarThemeGeometry { |
- virtual WebRect trackRect(WebScrollbar*) OVERRIDE { return WebRect(0, 0, 10, 10); } |
- virtual WebRect thumbRect(WebScrollbar*) OVERRIDE { return WebRect(0, 5, 5, 2); } |
- virtual void splitTrack(WebScrollbar*, const WebRect& track, WebRect& startTrack, WebRect& thumb, WebRect& endTrack) OVERRIDE |
- { |
- thumb = WebRect(0, 5, 5, 2); |
- startTrack = WebRect(0, 5, 0, 5); |
- endTrack = WebRect(0, 0, 0, 5); |
- } |
-}; |
- |
-class FakeScrollbarLayerImpl : public CCScrollbarLayerImpl { |
-public: |
- static scoped_ptr<FakeScrollbarLayerImpl> create(int id) |
- { |
- return make_scoped_ptr(new FakeScrollbarLayerImpl(id)); |
- } |
- |
- void createResources(CCResourceProvider* provider) |
- { |
- ASSERT(provider); |
- int pool = 0; |
- IntSize size(10, 10); |
- GC3Denum format = GraphicsContext3D::RGBA; |
- CCResourceProvider::TextureUsageHint hint = CCResourceProvider::TextureUsageAny; |
- setScrollbarGeometry(CCScrollbarGeometryFixedThumb::create(FakeWebScrollbarThemeGeometryNonEmpty::create())); |
- |
- setBackTrackResourceId(provider->createResource(pool, size, format, hint)); |
- setForeTrackResourceId(provider->createResource(pool, size, format, hint)); |
- setThumbResourceId(provider->createResource(pool, size, format, hint)); |
- } |
- |
-protected: |
- explicit FakeScrollbarLayerImpl(int id) |
- : CCScrollbarLayerImpl(id) |
- { |
- } |
-}; |
- |
-static inline scoped_ptr<CCRenderPass> createRenderPassWithResource(CCResourceProvider* provider) |
-{ |
- CCResourceProvider::ResourceId resourceId = provider->createResource(0, IntSize(1, 1), GraphicsContext3D::RGBA, CCResourceProvider::TextureUsageAny); |
- |
- scoped_ptr<CCRenderPass> pass = CCRenderPass::create(CCRenderPass::Id(1, 1), IntRect(0, 0, 1, 1), WebTransformationMatrix()); |
- scoped_ptr<CCSharedQuadState> sharedState = CCSharedQuadState::create(WebTransformationMatrix(), IntRect(0, 0, 1, 1), IntRect(0, 0, 1, 1), 1, false); |
- scoped_ptr<CCTextureDrawQuad> quad = CCTextureDrawQuad::create(sharedState.get(), IntRect(0, 0, 1, 1), resourceId, false, FloatRect(0, 0, 1, 1), false); |
- |
- static_cast<CCTestRenderPass*>(pass.get())->appendSharedQuadState(sharedState.Pass()); |
- static_cast<CCTestRenderPass*>(pass.get())->appendQuad(quad.PassAs<CCDrawQuad>()); |
- |
- return pass.Pass(); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, dontUseOldResourcesAfterLostContext) |
-{ |
- int layerId = 1; |
- |
- scoped_ptr<CCLayerImpl> rootLayer(CCLayerImpl::create(layerId++)); |
- rootLayer->setBounds(IntSize(10, 10)); |
- rootLayer->setAnchorPoint(FloatPoint(0, 0)); |
- |
- scoped_ptr<CCTiledLayerImpl> tileLayer = CCTiledLayerImpl::create(layerId++); |
- tileLayer->setBounds(IntSize(10, 10)); |
- tileLayer->setAnchorPoint(FloatPoint(0, 0)); |
- tileLayer->setContentBounds(IntSize(10, 10)); |
- tileLayer->setDrawsContent(true); |
- tileLayer->setSkipsDraw(false); |
- OwnPtr<CCLayerTilingData> tilingData(CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::NoBorderTexels)); |
- tilingData->setBounds(IntSize(10, 10)); |
- tileLayer->setTilingData(*tilingData); |
- tileLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10)); |
- rootLayer->addChild(tileLayer.PassAs<CCLayerImpl>()); |
- |
- scoped_ptr<CCTextureLayerImpl> textureLayer = CCTextureLayerImpl::create(layerId++); |
- textureLayer->setBounds(IntSize(10, 10)); |
- textureLayer->setAnchorPoint(FloatPoint(0, 0)); |
- textureLayer->setContentBounds(IntSize(10, 10)); |
- textureLayer->setDrawsContent(true); |
- textureLayer->setTextureId(1); |
- rootLayer->addChild(textureLayer.PassAs<CCLayerImpl>()); |
- |
- scoped_ptr<CCTiledLayerImpl> maskLayer = CCTiledLayerImpl::create(layerId++); |
- maskLayer->setBounds(IntSize(10, 10)); |
- maskLayer->setAnchorPoint(FloatPoint(0, 0)); |
- maskLayer->setContentBounds(IntSize(10, 10)); |
- maskLayer->setDrawsContent(true); |
- maskLayer->setSkipsDraw(false); |
- maskLayer->setTilingData(*tilingData); |
- maskLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10)); |
- |
- scoped_ptr<CCTextureLayerImpl> textureLayerWithMask = CCTextureLayerImpl::create(layerId++); |
- textureLayerWithMask->setBounds(IntSize(10, 10)); |
- textureLayerWithMask->setAnchorPoint(FloatPoint(0, 0)); |
- textureLayerWithMask->setContentBounds(IntSize(10, 10)); |
- textureLayerWithMask->setDrawsContent(true); |
- textureLayerWithMask->setTextureId(1); |
- textureLayerWithMask->setMaskLayer(maskLayer.PassAs<CCLayerImpl>()); |
- rootLayer->addChild(textureLayerWithMask.PassAs<CCLayerImpl>()); |
- |
- FakeVideoFrame videoFrame; |
- FakeVideoFrameProvider provider; |
- provider.setFrame(&videoFrame); |
- scoped_ptr<CCVideoLayerImpl> videoLayer = CCVideoLayerImpl::create(layerId++, &provider); |
- videoLayer->setBounds(IntSize(10, 10)); |
- videoLayer->setAnchorPoint(FloatPoint(0, 0)); |
- videoLayer->setContentBounds(IntSize(10, 10)); |
- videoLayer->setDrawsContent(true); |
- videoLayer->setLayerTreeHostImpl(m_hostImpl.get()); |
- rootLayer->addChild(videoLayer.PassAs<CCLayerImpl>()); |
- |
- FakeVideoFrame hwVideoFrame; |
- FakeVideoFrameProvider hwProvider; |
- hwProvider.setFrame(&hwVideoFrame); |
- scoped_ptr<CCVideoLayerImpl> hwVideoLayer = CCVideoLayerImpl::create(layerId++, &hwProvider); |
- hwVideoLayer->setBounds(IntSize(10, 10)); |
- hwVideoLayer->setAnchorPoint(FloatPoint(0, 0)); |
- hwVideoLayer->setContentBounds(IntSize(10, 10)); |
- hwVideoLayer->setDrawsContent(true); |
- hwVideoLayer->setLayerTreeHostImpl(m_hostImpl.get()); |
- rootLayer->addChild(hwVideoLayer.PassAs<CCLayerImpl>()); |
- |
- scoped_ptr<CCIOSurfaceLayerImpl> ioSurfaceLayer = CCIOSurfaceLayerImpl::create(layerId++); |
- ioSurfaceLayer->setBounds(IntSize(10, 10)); |
- ioSurfaceLayer->setAnchorPoint(FloatPoint(0, 0)); |
- ioSurfaceLayer->setContentBounds(IntSize(10, 10)); |
- ioSurfaceLayer->setDrawsContent(true); |
- ioSurfaceLayer->setIOSurfaceProperties(1, IntSize(10, 10)); |
- ioSurfaceLayer->setLayerTreeHostImpl(m_hostImpl.get()); |
- rootLayer->addChild(ioSurfaceLayer.PassAs<CCLayerImpl>()); |
- |
- scoped_ptr<CCHeadsUpDisplayLayerImpl> hudLayer = CCHeadsUpDisplayLayerImpl::create(layerId++); |
- hudLayer->setBounds(IntSize(10, 10)); |
- hudLayer->setAnchorPoint(FloatPoint(0, 0)); |
- hudLayer->setContentBounds(IntSize(10, 10)); |
- hudLayer->setDrawsContent(true); |
- hudLayer->setLayerTreeHostImpl(m_hostImpl.get()); |
- rootLayer->addChild(hudLayer.PassAs<CCLayerImpl>()); |
- |
- scoped_ptr<FakeScrollbarLayerImpl> scrollbarLayer(FakeScrollbarLayerImpl::create(layerId++)); |
- scrollbarLayer->setBounds(IntSize(10, 10)); |
- scrollbarLayer->setContentBounds(IntSize(10, 10)); |
- scrollbarLayer->setDrawsContent(true); |
- scrollbarLayer->setLayerTreeHostImpl(m_hostImpl.get()); |
- scrollbarLayer->createResources(m_hostImpl->resourceProvider()); |
- rootLayer->addChild(scrollbarLayer.PassAs<CCLayerImpl>()); |
- |
- scoped_ptr<CCDelegatedRendererLayerImpl> delegatedRendererLayer(CCDelegatedRendererLayerImpl::create(layerId++)); |
- delegatedRendererLayer->setBounds(IntSize(10, 10)); |
- delegatedRendererLayer->setContentBounds(IntSize(10, 10)); |
- delegatedRendererLayer->setDrawsContent(true); |
- delegatedRendererLayer->setLayerTreeHostImpl(m_hostImpl.get()); |
- ScopedPtrVector<CCRenderPass> passList; |
- passList.append(createRenderPassWithResource(m_hostImpl->resourceProvider())); |
- delegatedRendererLayer->setRenderPasses(passList); |
- EXPECT_TRUE(passList.isEmpty()); |
- rootLayer->addChild(delegatedRendererLayer.PassAs<CCLayerImpl>()); |
- |
- // Use a context that supports IOSurfaces |
- m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptPtr(new FakeWebGraphicsContext3DWithIOSurface)).PassAs<CCGraphicsContext>()); |
- |
- hwVideoFrame.setTextureId(m_hostImpl->resourceProvider()->graphicsContext3D()->createTexture()); |
- |
- m_hostImpl->setRootLayer(rootLayer.Pass()); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- m_hostImpl->swapBuffers(); |
- |
- unsigned numResources = m_hostImpl->resourceProvider()->numResources(); |
- |
- // Lose the context, replacing it with a StrictWebGraphicsContext3DWithIOSurface, |
- // that will warn if any resource from the previous context gets used. |
- m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptPtr(new StrictWebGraphicsContext3DWithIOSurface)).PassAs<CCGraphicsContext>()); |
- |
- // Create dummy resources so that looking up an old resource will get an |
- // invalid texture id mapping. |
- for (unsigned i = 0; i < numResources; ++i) |
- m_hostImpl->resourceProvider()->createResourceFromExternalTexture(1); |
- |
- // The WebVideoFrameProvider is expected to recreate its textures after a |
- // lost context (or not serve a frame). |
- hwProvider.setFrame(0); |
- |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- m_hostImpl->swapBuffers(); |
- |
- hwVideoFrame.setTextureId(m_hostImpl->resourceProvider()->graphicsContext3D()->createTexture()); |
- hwProvider.setFrame(&hwVideoFrame); |
- |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- m_hostImpl->swapBuffers(); |
-} |
- |
-// Fake WebGraphicsContext3D that tracks the number of textures in use. |
-class TrackingWebGraphicsContext3D : public FakeWebGraphicsContext3D { |
-public: |
- TrackingWebGraphicsContext3D() |
- : FakeWebGraphicsContext3D() |
- , m_numTextures(0) |
- { } |
- |
- virtual WebGLId createTexture() OVERRIDE |
- { |
- WebGLId id = FakeWebGraphicsContext3D::createTexture(); |
- |
- m_textures.set(id, true); |
- ++m_numTextures; |
- return id; |
- } |
- |
- virtual void deleteTexture(WebGLId id) OVERRIDE |
- { |
- if (!m_textures.get(id)) |
- return; |
- |
- m_textures.set(id, false); |
- --m_numTextures; |
- } |
- |
- virtual WebString getString(WGC3Denum name) OVERRIDE |
- { |
- if (name == cc::GraphicsContext3D::EXTENSIONS) |
- return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle"); |
- |
- return WebString(); |
- } |
- |
- unsigned numTextures() const { return m_numTextures; } |
- |
-private: |
- HashMap<WebGLId, bool> m_textures; |
- unsigned m_numTextures; |
-}; |
- |
-TEST_P(CCLayerTreeHostImplTest, layersFreeTextures) |
-{ |
- scoped_ptr<CCLayerImpl> rootLayer(CCLayerImpl::create(1)); |
- rootLayer->setBounds(IntSize(10, 10)); |
- rootLayer->setAnchorPoint(FloatPoint(0, 0)); |
- |
- scoped_ptr<CCTiledLayerImpl> tileLayer = CCTiledLayerImpl::create(2); |
- tileLayer->setBounds(IntSize(10, 10)); |
- tileLayer->setAnchorPoint(FloatPoint(0, 0)); |
- tileLayer->setContentBounds(IntSize(10, 10)); |
- tileLayer->setDrawsContent(true); |
- tileLayer->setSkipsDraw(false); |
- OwnPtr<CCLayerTilingData> tilingData(CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::NoBorderTexels)); |
- tilingData->setBounds(IntSize(10, 10)); |
- tileLayer->setTilingData(*tilingData); |
- tileLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10)); |
- rootLayer->addChild(tileLayer.PassAs<CCLayerImpl>()); |
- |
- scoped_ptr<CCTextureLayerImpl> textureLayer = CCTextureLayerImpl::create(3); |
- textureLayer->setBounds(IntSize(10, 10)); |
- textureLayer->setAnchorPoint(FloatPoint(0, 0)); |
- textureLayer->setContentBounds(IntSize(10, 10)); |
- textureLayer->setDrawsContent(true); |
- textureLayer->setTextureId(1); |
- rootLayer->addChild(textureLayer.PassAs<CCLayerImpl>()); |
- |
- FakeVideoFrameProvider provider; |
- scoped_ptr<CCVideoLayerImpl> videoLayer = CCVideoLayerImpl::create(4, &provider); |
- videoLayer->setBounds(IntSize(10, 10)); |
- videoLayer->setAnchorPoint(FloatPoint(0, 0)); |
- videoLayer->setContentBounds(IntSize(10, 10)); |
- videoLayer->setDrawsContent(true); |
- videoLayer->setLayerTreeHostImpl(m_hostImpl.get()); |
- rootLayer->addChild(videoLayer.PassAs<CCLayerImpl>()); |
- |
- scoped_ptr<CCIOSurfaceLayerImpl> ioSurfaceLayer = CCIOSurfaceLayerImpl::create(5); |
- ioSurfaceLayer->setBounds(IntSize(10, 10)); |
- ioSurfaceLayer->setAnchorPoint(FloatPoint(0, 0)); |
- ioSurfaceLayer->setContentBounds(IntSize(10, 10)); |
- ioSurfaceLayer->setDrawsContent(true); |
- ioSurfaceLayer->setIOSurfaceProperties(1, IntSize(10, 10)); |
- ioSurfaceLayer->setLayerTreeHostImpl(m_hostImpl.get()); |
- rootLayer->addChild(ioSurfaceLayer.PassAs<CCLayerImpl>()); |
- |
- // Lose the context, replacing it with a TrackingWebGraphicsContext3D (which the CCLayerTreeHostImpl takes ownership of). |
- scoped_ptr<CCGraphicsContext> ccContext(FakeWebCompositorOutputSurface::create(adoptPtr(new TrackingWebGraphicsContext3D))); |
- TrackingWebGraphicsContext3D* trackingWebGraphicsContext = static_cast<TrackingWebGraphicsContext3D*>(ccContext->context3D()); |
- m_hostImpl->initializeRenderer(ccContext.Pass()); |
- |
- m_hostImpl->setRootLayer(rootLayer.Pass()); |
- |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); |
- m_hostImpl->drawLayers(frame); |
- m_hostImpl->didDrawAllLayers(frame); |
- m_hostImpl->swapBuffers(); |
- |
- EXPECT_GT(trackingWebGraphicsContext->numTextures(), 0u); |
- |
- // Kill the layer tree. |
- m_hostImpl->setRootLayer(CCLayerImpl::create(100)); |
- // There should be no textures left in use after. |
- EXPECT_EQ(0u, trackingWebGraphicsContext->numTextures()); |
-} |
- |
-class MockDrawQuadsToFillScreenContext : public FakeWebGraphicsContext3D { |
-public: |
- MOCK_METHOD1(useProgram, void(WebGLId program)); |
- MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum type, WGC3Dintptr offset)); |
-}; |
- |
-TEST_P(CCLayerTreeHostImplTest, hasTransparentBackground) |
-{ |
- scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new MockDrawQuadsToFillScreenContext)).PassAs<CCGraphicsContext>(); |
- MockDrawQuadsToFillScreenContext* mockContext = static_cast<MockDrawQuadsToFillScreenContext*>(context->context3D()); |
- |
- // Run test case |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(false, context.Pass(), CCLayerImpl::create(1)); |
- myHostImpl->setBackgroundColor(SK_ColorWHITE); |
- |
- // Verify one quad is drawn when transparent background set is not set. |
- myHostImpl->setHasTransparentBackground(false); |
- EXPECT_CALL(*mockContext, useProgram(_)) |
- .Times(1); |
- EXPECT_CALL(*mockContext, drawElements(_, _, _, _)) |
- .Times(1); |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- Mock::VerifyAndClearExpectations(&mockContext); |
- |
- // Verify no quads are drawn when transparent background is set. |
- myHostImpl->setHasTransparentBackground(true); |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- Mock::VerifyAndClearExpectations(&mockContext); |
-} |
- |
-static void addDrawingLayerTo(CCLayerImpl* parent, int id, const IntRect& layerRect, CCLayerImpl** result) |
-{ |
- scoped_ptr<CCLayerImpl> layer = FakeLayerWithQuads::create(id); |
- CCLayerImpl* layerPtr = layer.get(); |
- layerPtr->setAnchorPoint(FloatPoint(0, 0)); |
- layerPtr->setPosition(FloatPoint(layerRect.location())); |
- layerPtr->setBounds(layerRect.size()); |
- layerPtr->setContentBounds(layerRect.size()); |
- layerPtr->setDrawsContent(true); // only children draw content |
- layerPtr->setContentsOpaque(true); |
- parent->addChild(layer.Pass()); |
- if (result) |
- *result = layerPtr; |
-} |
- |
-static void setupLayersForTextureCaching(CCLayerTreeHostImpl* layerTreeHostImpl, CCLayerImpl*& rootPtr, CCLayerImpl*& intermediateLayerPtr, CCLayerImpl*& surfaceLayerPtr, CCLayerImpl*& childPtr, const IntSize& rootSize) |
-{ |
- scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); |
- |
- layerTreeHostImpl->initializeRenderer(context.Pass()); |
- layerTreeHostImpl->setViewportSize(rootSize, rootSize); |
- |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- rootPtr = root.get(); |
- |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setPosition(FloatPoint(0, 0)); |
- root->setBounds(rootSize); |
- root->setContentBounds(rootSize); |
- root->setDrawsContent(true); |
- layerTreeHostImpl->setRootLayer(root.Pass()); |
- |
- addDrawingLayerTo(rootPtr, 2, IntRect(10, 10, rootSize.width(), rootSize.height()), &intermediateLayerPtr); |
- intermediateLayerPtr->setDrawsContent(false); // only children draw content |
- |
- // Surface layer is the layer that changes its opacity |
- // It will contain other layers that draw content. |
- addDrawingLayerTo(intermediateLayerPtr, 3, IntRect(10, 10, rootSize.width(), rootSize.height()), &surfaceLayerPtr); |
- surfaceLayerPtr->setDrawsContent(false); // only children draw content |
- surfaceLayerPtr->setOpacity(0.5f); // This will cause it to have a surface |
- |
- // Child of the surface layer will produce some quads |
- addDrawingLayerTo(surfaceLayerPtr, 4, IntRect(5, 5, rootSize.width() - 25, rootSize.height() - 25), &childPtr); |
-} |
- |
-class CCRendererGLWithReleaseTextures : public CCRendererGL { |
-public: |
- using CCRendererGL::releaseRenderPassTextures; |
-}; |
- |
-TEST_P(CCLayerTreeHostImplTest, textureCachingWithClipping) |
-{ |
- CCSettings::setPartialSwapEnabled(true); |
- |
- CCLayerTreeSettings settings; |
- settings.minimumOcclusionTrackingSize = IntSize(); |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this); |
- |
- CCLayerImpl* rootPtr; |
- CCLayerImpl* surfaceLayerPtr; |
- |
- scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); |
- |
- IntSize rootSize(100, 100); |
- |
- myHostImpl->initializeRenderer(context.Pass()); |
- myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), IntSize(rootSize.width(), rootSize.height())); |
- |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- rootPtr = root.get(); |
- |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setPosition(FloatPoint(0, 0)); |
- root->setBounds(rootSize); |
- root->setContentBounds(rootSize); |
- root->setDrawsContent(true); |
- root->setMasksToBounds(true); |
- myHostImpl->setRootLayer(root.Pass()); |
- |
- addDrawingLayerTo(rootPtr, 3, IntRect(0, 0, rootSize.width(), rootSize.height()), &surfaceLayerPtr); |
- surfaceLayerPtr->setDrawsContent(false); |
- |
- // Surface layer is the layer that changes its opacity |
- // It will contain other layers that draw content. |
- surfaceLayerPtr->setOpacity(0.5f); // This will cause it to have a surface |
- |
- addDrawingLayerTo(surfaceLayerPtr, 4, IntRect(0, 0, 100, 3), 0); |
- addDrawingLayerTo(surfaceLayerPtr, 5, IntRect(0, 97, 100, 3), 0); |
- |
- // Rotation will put part of the child ouside the bounds of the root layer. |
- // Nevertheless, the child layers should be drawn. |
- WebTransformationMatrix transform = surfaceLayerPtr->transform(); |
- transform.translate(50, 50); |
- transform.rotate(35); |
- transform.translate(-50, -50); |
- surfaceLayerPtr->setTransform(transform); |
- |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive two render passes, each with one quad |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); |
- ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size()); |
- |
- // Verify that the child layers are being clipped. |
- IntRect quadVisibleRect = frame.renderPasses[0]->quadList()[0]->quadVisibleRect(); |
- EXPECT_LT(quadVisibleRect.width(), 100); |
- |
- quadVisibleRect = frame.renderPasses[0]->quadList()[1]->quadVisibleRect(); |
- EXPECT_LT(quadVisibleRect.width(), 100); |
- |
- // Verify that the render surface texture is *not* clipped. |
- EXPECT_RECT_EQ(IntRect(0, 0, 100, 100), frame.renderPasses[0]->outputRect()); |
- |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material()); |
- CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0]); |
- EXPECT_FALSE(quad->contentsChangedSinceLastFrame().isEmpty()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- transform = surfaceLayerPtr->transform(); |
- transform.translate(50, 50); |
- transform.rotate(-35); |
- transform.translate(-50, -50); |
- surfaceLayerPtr->setTransform(transform); |
- |
- // The surface is now aligned again, and the clipped parts are exposed. |
- // Since the layers were clipped, even though the render surface size |
- // was not changed, the texture should not be saved. |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive two render passes, each with one quad |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); |
- ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusion) |
-{ |
- CCSettings::setPartialSwapEnabled(false); |
- |
- CCLayerTreeSettings settings; |
- settings.minimumOcclusionTrackingSize = IntSize(); |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this); |
- |
- // Layers are structure as follows: |
- // |
- // R +-- S1 +- L10 (owning) |
- // | +- L11 |
- // | +- L12 |
- // | |
- // +-- S2 +- L20 (owning) |
- // +- L21 |
- // |
- // Occlusion: |
- // L12 occludes L11 (internal) |
- // L20 occludes L10 (external) |
- // L21 occludes L20 (internal) |
- |
- CCLayerImpl* rootPtr; |
- CCLayerImpl* layerS1Ptr; |
- CCLayerImpl* layerS2Ptr; |
- |
- scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); |
- |
- IntSize rootSize(1000, 1000); |
- |
- myHostImpl->initializeRenderer(context.Pass()); |
- myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), IntSize(rootSize.width(), rootSize.height())); |
- |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- rootPtr = root.get(); |
- |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setPosition(FloatPoint(0, 0)); |
- root->setBounds(rootSize); |
- root->setContentBounds(rootSize); |
- root->setDrawsContent(true); |
- root->setMasksToBounds(true); |
- myHostImpl->setRootLayer(root.Pass()); |
- |
- addDrawingLayerTo(rootPtr, 2, IntRect(300, 300, 300, 300), &layerS1Ptr); |
- layerS1Ptr->setForceRenderSurface(true); |
- |
- addDrawingLayerTo(layerS1Ptr, 3, IntRect(10, 10, 10, 10), 0); // L11 |
- addDrawingLayerTo(layerS1Ptr, 4, IntRect(0, 0, 30, 30), 0); // L12 |
- |
- addDrawingLayerTo(rootPtr, 5, IntRect(550, 250, 300, 400), &layerS2Ptr); |
- layerS2Ptr->setForceRenderSurface(true); |
- |
- addDrawingLayerTo(layerS2Ptr, 6, IntRect(20, 20, 5, 5), 0); // L21 |
- |
- // Initial draw - must receive all quads |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive 3 render passes. |
- // For Root, there are 2 quads; for S1, there are 2 quads (1 is occluded); for S2, there is 2 quads. |
- ASSERT_EQ(3U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size()); |
- EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // "Unocclude" surface S1 and repeat draw. |
- // Must remove S2's render pass since it's cached; |
- // Must keep S1 quads because texture contained external occlusion. |
- WebTransformationMatrix transform = layerS2Ptr->transform(); |
- transform.translate(150, 150); |
- layerS2Ptr->setTransform(transform); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive 2 render passes. |
- // For Root, there are 2 quads |
- // For S1, the number of quads depends on what got unoccluded, so not asserted beyond being positive. |
- // For S2, there is no render pass |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- |
- EXPECT_GT(frame.renderPasses[0]->quadList().size(), 0U); |
- EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // "Re-occlude" surface S1 and repeat draw. |
- // Must remove S1's render pass since it is now available in full. |
- // S2 has no change so must also be removed. |
- transform = layerS2Ptr->transform(); |
- transform.translate(-15, -15); |
- layerS2Ptr->setTransform(transform); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive 1 render pass - for the root. |
- ASSERT_EQ(1U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusionEarlyOut) |
-{ |
- CCSettings::setPartialSwapEnabled(false); |
- |
- CCLayerTreeSettings settings; |
- settings.minimumOcclusionTrackingSize = IntSize(); |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this); |
- |
- // Layers are structure as follows: |
- // |
- // R +-- S1 +- L10 (owning, non drawing) |
- // | +- L11 (corner, unoccluded) |
- // | +- L12 (corner, unoccluded) |
- // | +- L13 (corner, unoccluded) |
- // | +- L14 (corner, entirely occluded) |
- // | |
- // +-- S2 +- L20 (owning, drawing) |
- // |
- |
- CCLayerImpl* rootPtr; |
- CCLayerImpl* layerS1Ptr; |
- CCLayerImpl* layerS2Ptr; |
- |
- scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); |
- |
- IntSize rootSize(1000, 1000); |
- |
- myHostImpl->initializeRenderer(context.Pass()); |
- myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), IntSize(rootSize.width(), rootSize.height())); |
- |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- rootPtr = root.get(); |
- |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setPosition(FloatPoint(0, 0)); |
- root->setBounds(rootSize); |
- root->setContentBounds(rootSize); |
- root->setDrawsContent(true); |
- root->setMasksToBounds(true); |
- myHostImpl->setRootLayer(root.Pass()); |
- |
- addDrawingLayerTo(rootPtr, 2, IntRect(0, 0, 800, 800), &layerS1Ptr); |
- layerS1Ptr->setForceRenderSurface(true); |
- layerS1Ptr->setDrawsContent(false); |
- |
- addDrawingLayerTo(layerS1Ptr, 3, IntRect(0, 0, 300, 300), 0); // L11 |
- addDrawingLayerTo(layerS1Ptr, 4, IntRect(0, 500, 300, 300), 0); // L12 |
- addDrawingLayerTo(layerS1Ptr, 5, IntRect(500, 0, 300, 300), 0); // L13 |
- addDrawingLayerTo(layerS1Ptr, 6, IntRect(500, 500, 300, 300), 0); // L14 |
- addDrawingLayerTo(layerS1Ptr, 9, IntRect(500, 500, 300, 300), 0); // L14 |
- |
- addDrawingLayerTo(rootPtr, 7, IntRect(450, 450, 450, 450), &layerS2Ptr); |
- layerS2Ptr->setForceRenderSurface(true); |
- |
- // Initial draw - must receive all quads |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive 3 render passes. |
- // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is 1 quad. |
- ASSERT_EQ(3U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- |
- // L14 is culled, so only 3 quads. |
- EXPECT_EQ(3U, frame.renderPasses[1]->quadList().size()); |
- EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // "Unocclude" surface S1 and repeat draw. |
- // Must remove S2's render pass since it's cached; |
- // Must keep S1 quads because texture contained external occlusion. |
- WebTransformationMatrix transform = layerS2Ptr->transform(); |
- transform.translate(100, 100); |
- layerS2Ptr->setTransform(transform); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive 2 render passes. |
- // For Root, there are 2 quads |
- // For S1, the number of quads depends on what got unoccluded, so not asserted beyond being positive. |
- // For S2, there is no render pass |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- |
- EXPECT_GT(frame.renderPasses[0]->quadList().size(), 0U); |
- EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // "Re-occlude" surface S1 and repeat draw. |
- // Must remove S1's render pass since it is now available in full. |
- // S2 has no change so must also be removed. |
- transform = layerS2Ptr->transform(); |
- transform.translate(-15, -15); |
- layerS2Ptr->setTransform(transform); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive 1 render pass - for the root. |
- ASSERT_EQ(1U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusionExternalOverInternal) |
-{ |
- CCSettings::setPartialSwapEnabled(false); |
- |
- CCLayerTreeSettings settings; |
- settings.minimumOcclusionTrackingSize = IntSize(); |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this); |
- |
- // Layers are structured as follows: |
- // |
- // R +-- S1 +- L10 (owning, drawing) |
- // | +- L11 (corner, occluded by L12) |
- // | +- L12 (opposite corner) |
- // | |
- // +-- S2 +- L20 (owning, drawing) |
- // |
- |
- CCLayerImpl* rootPtr; |
- CCLayerImpl* layerS1Ptr; |
- CCLayerImpl* layerS2Ptr; |
- |
- scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); |
- |
- IntSize rootSize(1000, 1000); |
- |
- myHostImpl->initializeRenderer(context.Pass()); |
- myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), IntSize(rootSize.width(), rootSize.height())); |
- |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- rootPtr = root.get(); |
- |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setPosition(FloatPoint(0, 0)); |
- root->setBounds(rootSize); |
- root->setContentBounds(rootSize); |
- root->setDrawsContent(true); |
- root->setMasksToBounds(true); |
- myHostImpl->setRootLayer(root.Pass()); |
- |
- addDrawingLayerTo(rootPtr, 2, IntRect(0, 0, 400, 400), &layerS1Ptr); |
- layerS1Ptr->setForceRenderSurface(true); |
- |
- addDrawingLayerTo(layerS1Ptr, 3, IntRect(0, 0, 300, 300), 0); // L11 |
- addDrawingLayerTo(layerS1Ptr, 4, IntRect(100, 0, 300, 300), 0); // L12 |
- |
- addDrawingLayerTo(rootPtr, 7, IntRect(200, 0, 300, 300), &layerS2Ptr); |
- layerS2Ptr->setForceRenderSurface(true); |
- |
- // Initial draw - must receive all quads |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive 3 render passes. |
- // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is 1 quad. |
- ASSERT_EQ(3U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(3U, frame.renderPasses[1]->quadList().size()); |
- EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // "Unocclude" surface S1 and repeat draw. |
- // Must remove S2's render pass since it's cached; |
- // Must keep S1 quads because texture contained external occlusion. |
- WebTransformationMatrix transform = layerS2Ptr->transform(); |
- transform.translate(300, 0); |
- layerS2Ptr->setTransform(transform); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive 2 render passes. |
- // For Root, there are 2 quads |
- // For S1, the number of quads depends on what got unoccluded, so not asserted beyond being positive. |
- // For S2, there is no render pass |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- |
- EXPECT_GT(frame.renderPasses[0]->quadList().size(), 0U); |
- EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusionExternalNotAligned) |
-{ |
- CCSettings::setPartialSwapEnabled(false); |
- |
- CCLayerTreeSettings settings; |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this); |
- |
- // Layers are structured as follows: |
- // |
- // R +-- S1 +- L10 (rotated, drawing) |
- // +- L11 (occupies half surface) |
- |
- CCLayerImpl* rootPtr; |
- CCLayerImpl* layerS1Ptr; |
- |
- scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); |
- |
- IntSize rootSize(1000, 1000); |
- |
- myHostImpl->initializeRenderer(context.Pass()); |
- myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), IntSize(rootSize.width(), rootSize.height())); |
- |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- rootPtr = root.get(); |
- |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setPosition(FloatPoint(0, 0)); |
- root->setBounds(rootSize); |
- root->setContentBounds(rootSize); |
- root->setDrawsContent(true); |
- root->setMasksToBounds(true); |
- myHostImpl->setRootLayer(root.Pass()); |
- |
- addDrawingLayerTo(rootPtr, 2, IntRect(0, 0, 400, 400), &layerS1Ptr); |
- layerS1Ptr->setForceRenderSurface(true); |
- WebTransformationMatrix transform = layerS1Ptr->transform(); |
- transform.translate(200, 200); |
- transform.rotate(45); |
- transform.translate(-200, -200); |
- layerS1Ptr->setTransform(transform); |
- |
- addDrawingLayerTo(layerS1Ptr, 3, IntRect(200, 0, 200, 400), 0); // L11 |
- |
- // Initial draw - must receive all quads |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive 2 render passes. |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Change opacity and draw. Verify we used cached texture. |
- layerS1Ptr->setOpacity(0.2f); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // One render pass must be gone due to cached texture. |
- ASSERT_EQ(1U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusionPartialSwap) |
-{ |
- CCSettings::setPartialSwapEnabled(true); |
- |
- CCLayerTreeSettings settings; |
- settings.minimumOcclusionTrackingSize = IntSize(); |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this); |
- |
- // Layers are structure as follows: |
- // |
- // R +-- S1 +- L10 (owning) |
- // | +- L11 |
- // | +- L12 |
- // | |
- // +-- S2 +- L20 (owning) |
- // +- L21 |
- // |
- // Occlusion: |
- // L12 occludes L11 (internal) |
- // L20 occludes L10 (external) |
- // L21 occludes L20 (internal) |
- |
- CCLayerImpl* rootPtr; |
- CCLayerImpl* layerS1Ptr; |
- CCLayerImpl* layerS2Ptr; |
- |
- scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); |
- |
- IntSize rootSize(1000, 1000); |
- |
- myHostImpl->initializeRenderer(context.Pass()); |
- myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), IntSize(rootSize.width(), rootSize.height())); |
- |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- rootPtr = root.get(); |
- |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setPosition(FloatPoint(0, 0)); |
- root->setBounds(rootSize); |
- root->setContentBounds(rootSize); |
- root->setDrawsContent(true); |
- root->setMasksToBounds(true); |
- myHostImpl->setRootLayer(root.Pass()); |
- |
- addDrawingLayerTo(rootPtr, 2, IntRect(300, 300, 300, 300), &layerS1Ptr); |
- layerS1Ptr->setForceRenderSurface(true); |
- |
- addDrawingLayerTo(layerS1Ptr, 3, IntRect(10, 10, 10, 10), 0); // L11 |
- addDrawingLayerTo(layerS1Ptr, 4, IntRect(0, 0, 30, 30), 0); // L12 |
- |
- addDrawingLayerTo(rootPtr, 5, IntRect(550, 250, 300, 400), &layerS2Ptr); |
- layerS2Ptr->setForceRenderSurface(true); |
- |
- addDrawingLayerTo(layerS2Ptr, 6, IntRect(20, 20, 5, 5), 0); // L21 |
- |
- // Initial draw - must receive all quads |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive 3 render passes. |
- // For Root, there are 2 quads; for S1, there are 2 quads (one is occluded); for S2, there is 2 quads. |
- ASSERT_EQ(3U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size()); |
- EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // "Unocclude" surface S1 and repeat draw. |
- // Must remove S2's render pass since it's cached; |
- // Must keep S1 quads because texture contained external occlusion. |
- WebTransformationMatrix transform = layerS2Ptr->transform(); |
- transform.translate(150, 150); |
- layerS2Ptr->setTransform(transform); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive 2 render passes. |
- // For Root, there are 2 quads. |
- // For S1, there are 2 quads. |
- // For S2, there is no render pass |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // "Re-occlude" surface S1 and repeat draw. |
- // Must remove S1's render pass since it is now available in full. |
- // S2 has no change so must also be removed. |
- transform = layerS2Ptr->transform(); |
- transform.translate(-15, -15); |
- layerS2Ptr->setTransform(transform); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Root render pass only. |
- ASSERT_EQ(1U, frame.renderPasses.size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, textureCachingWithScissor) |
-{ |
- CCSettings::setPartialSwapEnabled(false); |
- |
- CCLayerTreeSettings settings; |
- settings.minimumOcclusionTrackingSize = IntSize(); |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this); |
- |
- /* |
- Layers are created as follows: |
- |
- +--------------------+ |
- | 1 | |
- | +-----------+ | |
- | | 2 | | |
- | | +-------------------+ |
- | | | 3 | |
- | | +-------------------+ |
- | | | | |
- | +-----------+ | |
- | | |
- | | |
- +--------------------+ |
- |
- Layers 1, 2 have render surfaces |
- */ |
- scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); |
- scoped_ptr<CCTiledLayerImpl> child = CCTiledLayerImpl::create(2); |
- scoped_ptr<CCLayerImpl> grandChild = CCLayerImpl::create(3); |
- |
- IntRect rootRect(0, 0, 100, 100); |
- IntRect childRect(10, 10, 50, 50); |
- IntRect grandChildRect(5, 5, 150, 150); |
- |
- scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); |
- myHostImpl->initializeRenderer(context.Pass()); |
- |
- root->setAnchorPoint(FloatPoint(0, 0)); |
- root->setPosition(FloatPoint(rootRect.x(), rootRect.y())); |
- root->setBounds(IntSize(rootRect.width(), rootRect.height())); |
- root->setContentBounds(root->bounds()); |
- root->setDrawsContent(true); |
- root->setMasksToBounds(true); |
- |
- child->setAnchorPoint(FloatPoint(0, 0)); |
- child->setPosition(FloatPoint(childRect.x(), childRect.y())); |
- child->setOpacity(0.5); |
- child->setBounds(IntSize(childRect.width(), childRect.height())); |
- child->setContentBounds(child->bounds()); |
- child->setDrawsContent(true); |
- child->setSkipsDraw(false); |
- |
- // child layer has 10x10 tiles. |
- OwnPtr<CCLayerTilingData> tiler = CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::HasBorderTexels); |
- tiler->setBounds(child->contentBounds()); |
- child->setTilingData(*tiler.get()); |
- |
- grandChild->setAnchorPoint(FloatPoint(0, 0)); |
- grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y())); |
- grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height())); |
- grandChild->setContentBounds(grandChild->bounds()); |
- grandChild->setDrawsContent(true); |
- |
- CCTiledLayerImpl* childPtr = child.get(); |
- CCRenderPass::Id childPassId(childPtr->id(), 0); |
- |
- child->addChild(grandChild.Pass()); |
- root->addChild(child.PassAs<CCLayerImpl>()); |
- myHostImpl->setRootLayer(root.Pass()); |
- myHostImpl->setViewportSize(rootRect.size(), rootRect.size()); |
- |
- EXPECT_FALSE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(childPassId)); |
- |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // We should have cached textures for surface 2. |
- EXPECT_TRUE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(childPassId)); |
- |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // We should still have cached textures for surface 2 after drawing with no damage. |
- EXPECT_TRUE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(childPassId)); |
- |
- // Damage a single tile of surface 2. |
- childPtr->setUpdateRect(IntRect(10, 10, 10, 10)); |
- |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // We should have a cached texture for surface 2 again even though it was damaged. |
- EXPECT_TRUE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(childPassId)); |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, surfaceTextureCaching) |
-{ |
- CCSettings::setPartialSwapEnabled(true); |
- |
- CCLayerTreeSettings settings; |
- settings.minimumOcclusionTrackingSize = IntSize(); |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this); |
- |
- CCLayerImpl* rootPtr; |
- CCLayerImpl* intermediateLayerPtr; |
- CCLayerImpl* surfaceLayerPtr; |
- CCLayerImpl* childPtr; |
- |
- setupLayersForTextureCaching(myHostImpl.get(), rootPtr, intermediateLayerPtr, surfaceLayerPtr, childPtr, IntSize(100, 100)); |
- |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive two render passes, each with one quad |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size()); |
- |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material()); |
- CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0]); |
- CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId()); |
- EXPECT_FALSE(targetPass->damageRect().isEmpty()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Draw without any change |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive one render pass, as the other one should be culled |
- ASSERT_EQ(1U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material()); |
- CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0]); |
- CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId()); |
- EXPECT_TRUE(targetPass->damageRect().isEmpty()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Change opacity and draw |
- surfaceLayerPtr->setOpacity(0.6f); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive one render pass, as the other one should be culled |
- ASSERT_EQ(1U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material()); |
- CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0]); |
- CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId()); |
- EXPECT_TRUE(targetPass->damageRect().isEmpty()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Change less benign property and draw - should have contents changed flag |
- surfaceLayerPtr->setStackingOrderChanged(true); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive two render passes, each with one quad |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material()); |
- |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material()); |
- CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0]); |
- CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId()); |
- EXPECT_FALSE(targetPass->damageRect().isEmpty()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Change opacity again, and evict the cached surface texture. |
- surfaceLayerPtr->setOpacity(0.5f); |
- static_cast<CCRendererGLWithReleaseTextures*>(myHostImpl->renderer())->releaseRenderPassTextures(); |
- |
- // Change opacity and draw |
- surfaceLayerPtr->setOpacity(0.6f); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive two render passes |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- |
- // Even though not enough properties changed, the entire thing must be |
- // redrawn as we don't have cached textures |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size()); |
- |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material()); |
- CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0]); |
- CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId()); |
- EXPECT_TRUE(targetPass->damageRect().isEmpty()); |
- |
- // Was our surface evicted? |
- EXPECT_FALSE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(targetPass->id())); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Draw without any change, to make sure the state is clear |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive one render pass, as the other one should be culled |
- ASSERT_EQ(1U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material()); |
- CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0]); |
- CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId()); |
- EXPECT_TRUE(targetPass->damageRect().isEmpty()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Change opacity on the intermediate layer |
- WebTransformationMatrix transform = intermediateLayerPtr->transform(); |
- transform.setM11(1.0001); |
- intermediateLayerPtr->setTransform(transform); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive one render pass, as the other one should be culled. |
- ASSERT_EQ(1U, frame.renderPasses.size()); |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material()); |
- CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0]); |
- CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId()); |
- EXPECT_TRUE(targetPass->damageRect().isEmpty()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, surfaceTextureCachingNoPartialSwap) |
-{ |
- CCSettings::setPartialSwapEnabled(false); |
- |
- CCLayerTreeSettings settings; |
- settings.minimumOcclusionTrackingSize = IntSize(); |
- scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this); |
- |
- CCLayerImpl* rootPtr; |
- CCLayerImpl* intermediateLayerPtr; |
- CCLayerImpl* surfaceLayerPtr; |
- CCLayerImpl* childPtr; |
- |
- setupLayersForTextureCaching(myHostImpl.get(), rootPtr, intermediateLayerPtr, surfaceLayerPtr, childPtr, IntSize(100, 100)); |
- |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive two render passes, each with one quad |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size()); |
- |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material()); |
- CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0]); |
- CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId()); |
- EXPECT_FALSE(targetPass->damageRect().isEmpty()); |
- |
- EXPECT_FALSE(frame.renderPasses[0]->damageRect().isEmpty()); |
- EXPECT_FALSE(frame.renderPasses[1]->damageRect().isEmpty()); |
- |
- EXPECT_FALSE(frame.renderPasses[0]->hasOcclusionFromOutsideTargetSurface()); |
- EXPECT_FALSE(frame.renderPasses[1]->hasOcclusionFromOutsideTargetSurface()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Draw without any change |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Even though there was no change, we set the damage to entire viewport. |
- // One of the passes should be culled as a result, since contents didn't change |
- // and we have cached texture. |
- ASSERT_EQ(1U, frame.renderPasses.size()); |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- |
- EXPECT_TRUE(frame.renderPasses[0]->damageRect().isEmpty()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Change opacity and draw |
- surfaceLayerPtr->setOpacity(0.6f); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive one render pass, as the other one should be culled |
- ASSERT_EQ(1U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material()); |
- CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0]); |
- CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId()); |
- EXPECT_TRUE(targetPass->damageRect().isEmpty()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Change less benign property and draw - should have contents changed flag |
- surfaceLayerPtr->setStackingOrderChanged(true); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive two render passes, each with one quad |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material()); |
- |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material()); |
- CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0]); |
- CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId()); |
- EXPECT_FALSE(targetPass->damageRect().isEmpty()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Change opacity again, and evict the cached surface texture. |
- surfaceLayerPtr->setOpacity(0.5f); |
- static_cast<CCRendererGLWithReleaseTextures*>(myHostImpl->renderer())->releaseRenderPassTextures(); |
- |
- // Change opacity and draw |
- surfaceLayerPtr->setOpacity(0.6f); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive two render passes |
- ASSERT_EQ(2U, frame.renderPasses.size()); |
- |
- // Even though not enough properties changed, the entire thing must be |
- // redrawn as we don't have cached textures |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size()); |
- |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material()); |
- CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0]); |
- CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId()); |
- EXPECT_TRUE(targetPass->damageRect().isEmpty()); |
- |
- // Was our surface evicted? |
- EXPECT_FALSE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(targetPass->id())); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Draw without any change, to make sure the state is clear |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Even though there was no change, we set the damage to entire viewport. |
- // One of the passes should be culled as a result, since contents didn't change |
- // and we have cached texture. |
- ASSERT_EQ(1U, frame.renderPasses.size()); |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
- |
- // Change opacity on the intermediate layer |
- WebTransformationMatrix transform = intermediateLayerPtr->transform(); |
- transform.setM11(1.0001); |
- intermediateLayerPtr->setTransform(transform); |
- { |
- CCLayerTreeHostImpl::FrameData frame; |
- EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); |
- |
- // Must receive one render pass, as the other one should be culled. |
- ASSERT_EQ(1U, frame.renderPasses.size()); |
- EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); |
- |
- EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material()); |
- CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0]); |
- CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId()); |
- EXPECT_TRUE(targetPass->damageRect().isEmpty()); |
- |
- myHostImpl->drawLayers(frame); |
- myHostImpl->didDrawAllLayers(frame); |
- } |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, releaseContentsTextureShouldTriggerCommit) |
-{ |
- m_hostImpl->releaseContentsTextures(); |
- EXPECT_TRUE(m_didRequestCommit); |
-} |
- |
-struct RenderPassRemovalTestData : public CCLayerTreeHostImpl::FrameData { |
- ScopedPtrHashMap<CCRenderPass::Id, CCRenderPass> renderPassCache; |
- scoped_ptr<CCSharedQuadState> sharedQuadState; |
-}; |
- |
-class CCTestRenderer : public CCRendererGL, public CCRendererClient { |
-public: |
- static PassOwnPtr<CCTestRenderer> create(CCResourceProvider* resourceProvider) |
- { |
- OwnPtr<CCTestRenderer> renderer(adoptPtr(new CCTestRenderer(resourceProvider))); |
- if (!renderer->initialize()) |
- return nullptr; |
- |
- return renderer.release(); |
- } |
- |
- void clearCachedTextures() { m_textures.clear(); } |
- void setHaveCachedResourcesForRenderPassId(CCRenderPass::Id id) { m_textures.insert(id); } |
- |
- virtual bool haveCachedResourcesForRenderPassId(CCRenderPass::Id id) const OVERRIDE { return m_textures.count(id); } |
- |
- // CCRendererClient implementation. |
- virtual const IntSize& deviceViewportSize() const OVERRIDE { return m_viewportSize; } |
- virtual const CCLayerTreeSettings& settings() const OVERRIDE { return m_settings; } |
- virtual void didLoseContext() OVERRIDE { } |
- virtual void onSwapBuffersComplete() OVERRIDE { } |
- virtual void setFullRootLayerDamage() OVERRIDE { } |
- virtual void releaseContentsTextures() OVERRIDE { } |
- virtual void setMemoryAllocationLimitBytes(size_t) OVERRIDE { } |
- |
-protected: |
- CCTestRenderer(CCResourceProvider* resourceProvider) : CCRendererGL(this, resourceProvider) { } |
- |
-private: |
- CCLayerTreeSettings m_settings; |
- IntSize m_viewportSize; |
- base::hash_set<CCRenderPass::Id> m_textures; |
-}; |
- |
-static void configureRenderPassTestData(const char* testScript, RenderPassRemovalTestData& testData, CCTestRenderer* renderer) |
-{ |
- renderer->clearCachedTextures(); |
- |
- // One shared state for all quads - we don't need the correct details |
- testData.sharedQuadState = CCSharedQuadState::create(WebTransformationMatrix(), IntRect(), IntRect(), 1.0, true); |
- |
- const char* currentChar = testScript; |
- |
- // Pre-create root pass |
- CCRenderPass::Id rootRenderPassId = CCRenderPass::Id(testScript[0], testScript[1]); |
- testData.renderPassCache.add(rootRenderPassId, CCRenderPass::create(rootRenderPassId, IntRect(), WebTransformationMatrix())); |
- while (*currentChar) { |
- int layerId = *currentChar; |
- currentChar++; |
- ASSERT_TRUE(currentChar); |
- int index = *currentChar; |
- currentChar++; |
- |
- CCRenderPass::Id renderPassId = CCRenderPass::Id(layerId, index); |
- |
- bool isReplica = false; |
- if (!testData.renderPassCache.contains(renderPassId)) |
- isReplica = true; |
- |
- scoped_ptr<CCRenderPass> renderPass = testData.renderPassCache.take(renderPassId); |
- |
- // Cycle through quad data and create all quads |
- while (*currentChar && *currentChar != '\n') { |
- if (*currentChar == 's') { |
- // Solid color draw quad |
- scoped_ptr<CCSolidColorDrawQuad> quad = CCSolidColorDrawQuad::create(testData.sharedQuadState.get(), IntRect(0, 0, 10, 10), SK_ColorWHITE); |
- |
- static_cast<CCTestRenderPass*>(renderPass.get())->appendQuad(quad.PassAs<CCDrawQuad>()); |
- currentChar++; |
- } else if ((*currentChar >= 'A') && (*currentChar <= 'Z')) { |
- // RenderPass draw quad |
- int layerId = *currentChar; |
- currentChar++; |
- ASSERT_TRUE(currentChar); |
- int index = *currentChar; |
- currentChar++; |
- CCRenderPass::Id newRenderPassId = CCRenderPass::Id(layerId, index); |
- ASSERT_NE(rootRenderPassId, newRenderPassId); |
- bool hasTexture = false; |
- bool contentsChanged = true; |
- |
- if (*currentChar == '[') { |
- currentChar++; |
- while (*currentChar && *currentChar != ']') { |
- switch (*currentChar) { |
- case 'c': |
- contentsChanged = false; |
- break; |
- case 't': |
- hasTexture = true; |
- break; |
- } |
- currentChar++; |
- } |
- if (*currentChar == ']') |
- currentChar++; |
- } |
- |
- if (testData.renderPassCache.find(newRenderPassId) == testData.renderPassCache.end()) { |
- if (hasTexture) |
- renderer->setHaveCachedResourcesForRenderPassId(newRenderPassId); |
- |
- testData.renderPassCache.add(newRenderPassId, CCTestRenderPass::create(newRenderPassId, IntRect(), WebTransformationMatrix())); |
- } |
- |
- IntRect quadRect = IntRect(0, 0, 1, 1); |
- IntRect contentsChangedRect = contentsChanged ? quadRect : IntRect(); |
- scoped_ptr<CCRenderPassDrawQuad> quad = CCRenderPassDrawQuad::create(testData.sharedQuadState.get(), quadRect, newRenderPassId, isReplica, 1, contentsChangedRect, 1, 1, 0, 0); |
- static_cast<CCTestRenderPass*>(renderPass.get())->appendQuad(quad.PassAs<CCDrawQuad>()); |
- } |
- } |
- testData.renderPasses.insert(testData.renderPasses.begin(), renderPass.get()); |
- testData.renderPassesById.add(renderPassId, renderPass.Pass()); |
- if (*currentChar) |
- currentChar++; |
- } |
-} |
- |
-void dumpRenderPassTestData(const RenderPassRemovalTestData& testData, char* buffer) |
-{ |
- char* pos = buffer; |
- for (CCRenderPassList::const_reverse_iterator it = testData.renderPasses.rbegin(); it != testData.renderPasses.rend(); ++it) { |
- const CCRenderPass* currentPass = *it; |
- *pos = currentPass->id().layerId; |
- pos++; |
- *pos = currentPass->id().index; |
- pos++; |
- |
- CCQuadList::const_iterator quadListIterator = currentPass->quadList().begin(); |
- while (quadListIterator != currentPass->quadList().end()) { |
- CCDrawQuad* currentQuad = *quadListIterator; |
- switch (currentQuad->material()) { |
- case CCDrawQuad::SolidColor: |
- *pos = 's'; |
- pos++; |
- break; |
- case CCDrawQuad::RenderPass: |
- *pos = CCRenderPassDrawQuad::materialCast(currentQuad)->renderPassId().layerId; |
- pos++; |
- *pos = CCRenderPassDrawQuad::materialCast(currentQuad)->renderPassId().index; |
- pos++; |
- break; |
- default: |
- *pos = 'x'; |
- pos++; |
- break; |
- } |
- |
- quadListIterator++; |
- } |
- *pos = '\n'; |
- pos++; |
- } |
- *pos = '\0'; |
-} |
- |
-// Each CCRenderPassList is represented by a string which describes the configuration. |
-// The syntax of the string is as follows: |
-// |
-// RsssssX[c]ssYsssZ[t]ssW[ct] |
-// Identifies the render pass---------------------------^ ^^^ ^ ^ ^ ^ ^ |
-// These are solid color quads-----------------------------+ | | | | | |
-// Identifies RenderPassDrawQuad's RenderPass-----------------+ | | | | |
-// This quad's contents didn't change---------------------------+ | | | |
-// This quad's contents changed and it has no texture---------------+ | | |
-// This quad has texture but its contents changed-------------------------+ | |
-// This quad's contents didn't change and it has texture - will be removed------+ |
-// |
-// Expected results have exactly the same syntax, except they do not use square brackets, |
-// since we only check the structure, not attributes. |
-// |
-// Test case configuration consists of initialization script and expected results, |
-// all in the same format. |
-struct TestCase { |
- const char* name; |
- const char* initScript; |
- const char* expectedResult; |
-}; |
- |
-TestCase removeRenderPassesCases[] = |
- { |
- { |
- "Single root pass", |
- "R0ssss\n", |
- "R0ssss\n" |
- }, { |
- "Single pass - no quads", |
- "R0\n", |
- "R0\n" |
- }, { |
- "Two passes, no removal", |
- "R0ssssA0sss\n" |
- "A0ssss\n", |
- "R0ssssA0sss\n" |
- "A0ssss\n" |
- }, { |
- "Two passes, remove last", |
- "R0ssssA0[ct]sss\n" |
- "A0ssss\n", |
- "R0ssssA0sss\n" |
- }, { |
- "Have texture but contents changed - leave pass", |
- "R0ssssA0[t]sss\n" |
- "A0ssss\n", |
- "R0ssssA0sss\n" |
- "A0ssss\n" |
- }, { |
- "Contents didn't change but no texture - leave pass", |
- "R0ssssA0[c]sss\n" |
- "A0ssss\n", |
- "R0ssssA0sss\n" |
- "A0ssss\n" |
- }, { |
- "Replica: two quads reference the same pass; remove", |
- "R0ssssA0[ct]A0[ct]sss\n" |
- "A0ssss\n", |
- "R0ssssA0A0sss\n" |
- }, { |
- "Replica: two quads reference the same pass; leave", |
- "R0ssssA0[c]A0[c]sss\n" |
- "A0ssss\n", |
- "R0ssssA0A0sss\n" |
- "A0ssss\n", |
- }, { |
- "Many passes, remove all", |
- "R0ssssA0[ct]sss\n" |
- "A0sssB0[ct]C0[ct]s\n" |
- "B0sssD0[ct]ssE0[ct]F0[ct]\n" |
- "E0ssssss\n" |
- "C0G0[ct]\n" |
- "D0sssssss\n" |
- "F0sssssss\n" |
- "G0sss\n", |
- |
- "R0ssssA0sss\n" |
- }, { |
- "Deep recursion, remove all", |
- |
- "R0sssssA0[ct]ssss\n" |
- "A0ssssB0sss\n" |
- "B0C0\n" |
- "C0D0\n" |
- "D0E0\n" |
- "E0F0\n" |
- "F0G0\n" |
- "G0H0\n" |
- "H0sssI0sss\n" |
- "I0J0\n" |
- "J0ssss\n", |
- |
- "R0sssssA0ssss\n" |
- }, { |
- "Wide recursion, remove all", |
- "R0A0[ct]B0[ct]C0[ct]D0[ct]E0[ct]F0[ct]G0[ct]H0[ct]I0[ct]J0[ct]\n" |
- "A0s\n" |
- "B0s\n" |
- "C0ssss\n" |
- "D0ssss\n" |
- "E0s\n" |
- "F0\n" |
- "G0s\n" |
- "H0s\n" |
- "I0s\n" |
- "J0ssss\n", |
- |
- "R0A0B0C0D0E0F0G0H0I0J0\n" |
- }, { |
- "Remove passes regardless of cache state", |
- "R0ssssA0[ct]sss\n" |
- "A0sssB0C0s\n" |
- "B0sssD0[c]ssE0[t]F0\n" |
- "E0ssssss\n" |
- "C0G0\n" |
- "D0sssssss\n" |
- "F0sssssss\n" |
- "G0sss\n", |
- |
- "R0ssssA0sss\n" |
- }, { |
- "Leave some passes, remove others", |
- |
- "R0ssssA0[c]sss\n" |
- "A0sssB0[t]C0[ct]s\n" |
- "B0sssD0[c]ss\n" |
- "C0G0\n" |
- "D0sssssss\n" |
- "G0sss\n", |
- |
- "R0ssssA0sss\n" |
- "A0sssB0C0s\n" |
- "B0sssD0ss\n" |
- "D0sssssss\n" |
- }, { |
- 0, 0, 0 |
- } |
- }; |
- |
-static void verifyRenderPassTestData(TestCase& testCase, RenderPassRemovalTestData& testData) |
-{ |
- char actualResult[1024]; |
- dumpRenderPassTestData(testData, actualResult); |
- EXPECT_STREQ(testCase.expectedResult, actualResult) << "In test case: " << testCase.name; |
-} |
- |
-TEST_P(CCLayerTreeHostImplTest, testRemoveRenderPasses) |
-{ |
- scoped_ptr<CCGraphicsContext> context(createContext()); |
- ASSERT_TRUE(context->context3D()); |
- OwnPtr<CCResourceProvider> resourceProvider(CCResourceProvider::create(context.get())); |
- |
- OwnPtr<CCTestRenderer> renderer(CCTestRenderer::create(resourceProvider.get())); |
- |
- int testCaseIndex = 0; |
- while (removeRenderPassesCases[testCaseIndex].name) { |
- RenderPassRemovalTestData testData; |
- configureRenderPassTestData(removeRenderPassesCases[testCaseIndex].initScript, testData, renderer.get()); |
- CCLayerTreeHostImpl::removeRenderPasses(CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures(*renderer), testData); |
- verifyRenderPassTestData(removeRenderPassesCases[testCaseIndex], testData); |
- testCaseIndex++; |
- } |
-} |
- |
-INSTANTIATE_TEST_CASE_P(CCLayerTreeHostImplTests, |
- CCLayerTreeHostImplTest, |
- ::testing::Values(false, true)); |
- |
-} // namespace |