TreeSynchronizerTest.cpp [plain text]
#include "config.h"
#include "TreeSynchronizer.h"
#include "CCAnimationTestCommon.h"
#include "LayerChromium.h"
#include "Region.h"
#include "cc/CCLayerAnimationController.h"
#include "cc/CCLayerImpl.h"
#include "cc/CCProxy.h"
#include "cc/CCSingleThreadProxy.h"
#include <gtest/gtest.h>
using namespace WebCore;
using namespace WebKitTests;
namespace {
class MockCCLayerImpl : public CCLayerImpl {
public:
static PassOwnPtr<MockCCLayerImpl> create(int layerId)
{
return adoptPtr(new MockCCLayerImpl(layerId));
}
virtual ~MockCCLayerImpl()
{
if (m_ccLayerDestructionList)
m_ccLayerDestructionList->append(id());
}
void setCCLayerDestructionList(Vector<int>* list) { m_ccLayerDestructionList = list; }
private:
MockCCLayerImpl(int layerId)
: CCLayerImpl(layerId)
, m_ccLayerDestructionList(0)
{
}
Vector<int>* m_ccLayerDestructionList;
};
class MockLayerChromium : public LayerChromium {
public:
static PassRefPtr<MockLayerChromium> create(Vector<int>* ccLayerDestructionList)
{
return adoptRef(new MockLayerChromium(ccLayerDestructionList));
}
virtual ~MockLayerChromium() { }
virtual PassOwnPtr<CCLayerImpl> createCCLayerImpl() OVERRIDE
{
return MockCCLayerImpl::create(m_layerId);
}
virtual void pushPropertiesTo(CCLayerImpl* ccLayer) OVERRIDE
{
LayerChromium::pushPropertiesTo(ccLayer);
MockCCLayerImpl* mockCCLayer = static_cast<MockCCLayerImpl*>(ccLayer);
mockCCLayer->setCCLayerDestructionList(m_ccLayerDestructionList);
}
private:
MockLayerChromium(Vector<int>* ccLayerDestructionList)
: LayerChromium()
, m_ccLayerDestructionList(ccLayerDestructionList)
{
}
Vector<int>* m_ccLayerDestructionList;
};
class FakeLayerAnimationController : public CCLayerAnimationController {
public:
static PassOwnPtr<FakeLayerAnimationController> create(CCLayerAnimationControllerClient* client)
{
return adoptPtr(new FakeLayerAnimationController(client));
}
bool synchronizedAnimations() const { return m_synchronizedAnimations; }
private:
explicit FakeLayerAnimationController(CCLayerAnimationControllerClient* client)
: CCLayerAnimationController(client)
, m_synchronizedAnimations(false)
{
}
virtual void pushAnimationUpdatesTo(CCLayerAnimationController* controllerImpl)
{
CCLayerAnimationController::pushAnimationUpdatesTo(controllerImpl);
m_synchronizedAnimations = true;
}
bool m_synchronizedAnimations;
};
void expectTreesAreIdentical(LayerChromium* layer, CCLayerImpl* ccLayer)
{
ASSERT_TRUE(layer);
ASSERT_TRUE(ccLayer);
EXPECT_EQ(layer->id(), ccLayer->id());
EXPECT_EQ(layer->nonFastScrollableRegion(), ccLayer->nonFastScrollableRegion());
ASSERT_EQ(!!layer->maskLayer(), !!ccLayer->maskLayer());
if (layer->maskLayer())
expectTreesAreIdentical(layer->maskLayer(), ccLayer->maskLayer());
ASSERT_EQ(!!layer->replicaLayer(), !!ccLayer->replicaLayer());
if (layer->replicaLayer())
expectTreesAreIdentical(layer->replicaLayer(), ccLayer->replicaLayer());
const Vector<RefPtr<LayerChromium> >& layerChildren = layer->children();
const Vector<OwnPtr<CCLayerImpl> >& ccLayerChildren = ccLayer->children();
ASSERT_EQ(layerChildren.size(), ccLayerChildren.size());
for (size_t i = 0; i < layerChildren.size(); ++i)
expectTreesAreIdentical(layerChildren[i].get(), ccLayerChildren[i].get());
}
TEST(TreeSynchronizerTest, syncNullTree)
{
DebugScopedSetImplThread impl;
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(0, nullptr);
EXPECT_TRUE(!ccLayerTreeRoot.get());
}
TEST(TreeSynchronizerTest, syncSimpleTreeFromEmpty)
{
DebugScopedSetImplThread impl;
RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create();
layerTreeRoot->addChild(LayerChromium::create());
layerTreeRoot->addChild(LayerChromium::create());
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
}
TEST(TreeSynchronizerTest, syncSimpleTreeReusingLayers)
{
DebugScopedSetImplThread impl;
Vector<int> ccLayerDestructionList;
RefPtr<LayerChromium> layerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
layerTreeRoot->children()[0]->addChild(MockLayerChromium::create(&ccLayerDestructionList));
layerTreeRoot->children()[1]->removeFromParent();
int secondCCLayerId = ccLayerTreeRoot->children()[1]->id();
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
ASSERT_EQ(1u, ccLayerDestructionList.size());
EXPECT_EQ(secondCCLayerId, ccLayerDestructionList[0]);
}
TEST(TreeSynchronizerTest, syncSimpleTreeAndTrackStackingOrderChange)
{
DebugScopedSetImplThread impl;
Vector<int> ccLayerDestructionList;
RefPtr<LayerChromium> layerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
RefPtr<LayerChromium> child2 = MockLayerChromium::create(&ccLayerDestructionList);
layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
layerTreeRoot->addChild(child2);
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
ccLayerTreeRoot->resetAllChangeTrackingForSubtree();
child2->removeFromParent();
layerTreeRoot->addChild(child2);
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
EXPECT_FALSE(ccLayerTreeRoot->layerPropertyChanged());
EXPECT_FALSE(ccLayerTreeRoot->children()[0]->layerPropertyChanged());
EXPECT_TRUE(ccLayerTreeRoot->children()[1]->layerPropertyChanged());
}
TEST(TreeSynchronizerTest, syncSimpleTreeAndProperties)
{
DebugScopedSetImplThread impl;
RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create();
layerTreeRoot->addChild(LayerChromium::create());
layerTreeRoot->addChild(LayerChromium::create());
FloatPoint rootPosition = FloatPoint(2.3f, 7.4f);
layerTreeRoot->setPosition(rootPosition);
float firstChildOpacity = 0.25f;
layerTreeRoot->children()[0]->setOpacity(firstChildOpacity);
IntSize secondChildBounds = IntSize(25, 53);
layerTreeRoot->children()[1]->setBounds(secondChildBounds);
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
FloatPoint rootCCLayerPosition = ccLayerTreeRoot->position();
EXPECT_EQ(rootPosition.x(), rootCCLayerPosition.x());
EXPECT_EQ(rootPosition.y(), rootCCLayerPosition.y());
EXPECT_EQ(firstChildOpacity, ccLayerTreeRoot->children()[0]->opacity());
IntSize secondCCLayerChildBounds = ccLayerTreeRoot->children()[1]->bounds();
EXPECT_EQ(secondChildBounds.width(), secondCCLayerChildBounds.width());
EXPECT_EQ(secondChildBounds.height(), secondCCLayerChildBounds.height());
}
TEST(TreeSynchronizerTest, reuseCCLayersAfterStructuralChange)
{
DebugScopedSetImplThread impl;
Vector<int> ccLayerDestructionList;
RefPtr<LayerChromium> layerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
RefPtr<LayerChromium> layerA = layerTreeRoot->children()[0].get();
layerA->addChild(MockLayerChromium::create(&ccLayerDestructionList));
RefPtr<LayerChromium> layerB = layerA->children()[0].get();
layerB->addChild(MockLayerChromium::create(&ccLayerDestructionList));
RefPtr<LayerChromium> layerC = layerB->children()[0].get();
layerB->addChild(MockLayerChromium::create(&ccLayerDestructionList));
RefPtr<LayerChromium> layerD = layerB->children()[1].get();
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
layerTreeRoot->removeAllChildren();
layerD->removeAllChildren();
layerTreeRoot->addChild(layerD);
layerA->removeAllChildren();
layerD->addChild(layerA);
layerC->removeAllChildren();
layerD->addChild(layerC);
layerB->removeAllChildren();
layerC->addChild(layerB);
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
EXPECT_EQ(0u, ccLayerDestructionList.size());
}
TEST(TreeSynchronizerTest, syncSimpleTreeThenDestroy)
{
DebugScopedSetImplThread impl;
Vector<int> ccLayerDestructionList;
RefPtr<LayerChromium> oldLayerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
oldLayerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
oldLayerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
int oldTreeRootLayerId = oldLayerTreeRoot->id();
int oldTreeFirstChildLayerId = oldLayerTreeRoot->children()[0]->id();
int oldTreeSecondChildLayerId = oldLayerTreeRoot->children()[1]->id();
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(oldLayerTreeRoot.get(), nullptr);
expectTreesAreIdentical(oldLayerTreeRoot.get(), ccLayerTreeRoot.get());
oldLayerTreeRoot->removeAllChildren();
RefPtr<LayerChromium> newLayerTreeRoot = LayerChromium::create();
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(newLayerTreeRoot.get(), ccLayerTreeRoot.release());
expectTreesAreIdentical(newLayerTreeRoot.get(), ccLayerTreeRoot.get());
ASSERT_EQ(3u, ccLayerDestructionList.size());
EXPECT_TRUE(ccLayerDestructionList.contains(oldTreeRootLayerId));
EXPECT_TRUE(ccLayerDestructionList.contains(oldTreeFirstChildLayerId));
EXPECT_TRUE(ccLayerDestructionList.contains(oldTreeSecondChildLayerId));
}
TEST(TreeSynchronizerTest, syncMaskReplicaAndReplicaMaskLayers)
{
DebugScopedSetImplThread impl;
RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create();
layerTreeRoot->addChild(LayerChromium::create());
layerTreeRoot->addChild(LayerChromium::create());
layerTreeRoot->addChild(LayerChromium::create());
RefPtr<LayerChromium> maskLayer = LayerChromium::create();
layerTreeRoot->children()[0]->setMaskLayer(maskLayer.get());
RefPtr<LayerChromium> replicaLayer = LayerChromium::create();
layerTreeRoot->children()[1]->setReplicaLayer(replicaLayer.get());
RefPtr<LayerChromium> replicaLayerWithMask = LayerChromium::create();
RefPtr<LayerChromium> replicaMaskLayer = LayerChromium::create();
replicaLayerWithMask->setMaskLayer(replicaMaskLayer.get());
layerTreeRoot->children()[2]->setReplicaLayer(replicaLayerWithMask.get());
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
layerTreeRoot->children()[0]->setMaskLayer(0);
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
layerTreeRoot->children()[1]->setReplicaLayer(0);
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
replicaLayerWithMask->setMaskLayer(0);
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
}
TEST(TreeSynchronizerTest, synchronizeAnimations)
{
DebugScopedSetImplThread impl;
RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create();
FakeLayerAnimationControllerClient dummy;
layerTreeRoot->setLayerAnimationController(FakeLayerAnimationController::create(&dummy));
EXPECT_FALSE(static_cast<FakeLayerAnimationController*>(layerTreeRoot->layerAnimationController())->synchronizedAnimations());
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
EXPECT_TRUE(static_cast<FakeLayerAnimationController*>(layerTreeRoot->layerAnimationController())->synchronizedAnimations());
}
}