8adf47699d4870dd5497a8152a3d4eb0cceb3d5b
[WebKit-https.git] / Source / WebKit / chromium / tests / TreeSynchronizerTest.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26
27 #include "TreeSynchronizer.h"
28
29 #include "LayerChromium.h"
30 #include "cc/CCLayerImpl.h"
31 #include <gtest/gtest.h>
32
33 using namespace WebCore;
34
35 namespace {
36
37 class MockCCLayerImpl : public CCLayerImpl {
38 public:
39     static PassRefPtr<MockCCLayerImpl> create(int layerId)
40     {
41         return adoptRef(new MockCCLayerImpl(layerId));
42     }
43     virtual ~MockCCLayerImpl()
44     {
45         if (m_ccLayerDestructionList)
46             m_ccLayerDestructionList->append(id());
47     }
48
49     void setCCLayerDestructionList(Vector<int>* list) { m_ccLayerDestructionList = list; }
50
51 private:
52     MockCCLayerImpl(int layerId)
53         : CCLayerImpl(layerId)
54         , m_ccLayerDestructionList(0)
55     {
56     }
57
58     Vector<int>* m_ccLayerDestructionList;
59 };
60
61 class MockLayerChromium : public LayerChromium {
62 public:
63     static PassRefPtr<MockLayerChromium> create(Vector<int>* ccLayerDestructionList)
64     {
65         return adoptRef(new MockLayerChromium(ccLayerDestructionList));
66     }
67
68     virtual ~MockLayerChromium() { }
69
70     virtual PassRefPtr<CCLayerImpl> createCCLayerImpl()
71     {
72         return MockCCLayerImpl::create(m_layerId);
73     }
74
75     virtual void pushPropertiesTo(CCLayerImpl* ccLayer)
76     {
77         LayerChromium::pushPropertiesTo(ccLayer);
78
79         MockCCLayerImpl* mockCCLayer = static_cast<MockCCLayerImpl*>(ccLayer);
80         mockCCLayer->setCCLayerDestructionList(m_ccLayerDestructionList);
81     }
82 private:
83     MockLayerChromium(Vector<int>* ccLayerDestructionList)
84         : LayerChromium(0)
85         , m_ccLayerDestructionList(ccLayerDestructionList)
86     {
87     }
88
89     Vector<int>* m_ccLayerDestructionList;
90 };
91
92 void expectTreesAreIdentical(LayerChromium* layer, CCLayerImpl* ccLayer)
93 {
94     ASSERT_TRUE(layer);
95     ASSERT_TRUE(ccLayer);
96
97     EXPECT_EQ(layer->id(), ccLayer->id());
98
99     ASSERT_EQ(!!layer->maskLayer(), !!ccLayer->maskLayer());
100     if (layer->maskLayer())
101         expectTreesAreIdentical(layer->maskLayer(), ccLayer->maskLayer());
102
103     ASSERT_EQ(!!layer->replicaLayer(), !!ccLayer->replicaLayer());
104     if (layer->replicaLayer())
105         expectTreesAreIdentical(layer->replicaLayer(), ccLayer->replicaLayer());
106
107     const Vector<RefPtr<LayerChromium> >& layerChildren = layer->children();
108     const Vector<RefPtr<CCLayerImpl> >& ccLayerChildren = ccLayer->children();
109
110     ASSERT_EQ(layerChildren.size(), ccLayerChildren.size());
111
112     for (size_t i = 0; i < layerChildren.size(); ++i)
113         expectTreesAreIdentical(layerChildren[i].get(), ccLayerChildren[i].get());
114 }
115
116 // Constructs a very simple tree and synchronizes it without trying to reuse any preexisting layers.
117 TEST(TreeSynchronizerTest, syncSimpleTreeFromEmpty)
118 {
119     RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(0);
120     layerTreeRoot->addChild(LayerChromium::create(0));
121     layerTreeRoot->addChild(LayerChromium::create(0));
122
123     RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), 0);
124
125     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
126 }
127
128 // Constructs a very simple tree and synchronizes it attempting to reuse some layers
129 TEST(TreeSynchronizerTest, syncSimpleTreeReusingLayers)
130 {
131     Vector<int> ccLayerDestructionList;
132
133     RefPtr<LayerChromium> layerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
134     layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
135     layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
136
137     RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), 0);
138     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
139
140     // Add a new layer to the LayerChromium side
141     layerTreeRoot->children()[0]->addChild(MockLayerChromium::create(&ccLayerDestructionList));
142     // Remove one.
143     layerTreeRoot->children()[1]->removeFromParent();
144     int secondCCLayerId = ccLayerTreeRoot->children()[1]->id();
145
146     // Synchronize again. After the sync the trees should be equivalent and we should have created and destroyed one CCLayerImpl.
147     ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
148     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
149
150     ASSERT_EQ(1u, ccLayerDestructionList.size());
151     EXPECT_EQ(secondCCLayerId, ccLayerDestructionList[0]);
152 }
153
154 TEST(TreeSynchronizerTest, syncSimpleTreeAndProperties)
155 {
156     RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(0);
157     layerTreeRoot->addChild(LayerChromium::create(0));
158     layerTreeRoot->addChild(LayerChromium::create(0));
159
160     // Pick some random properties to set. The values are not important, we're just testing that at least some properties are making it through.
161     FloatPoint rootPosition = FloatPoint(2.3, 7.4);
162     layerTreeRoot->setPosition(rootPosition);
163
164     float firstChildOpacity = 0.25;
165     layerTreeRoot->children()[0]->setOpacity(firstChildOpacity);
166
167     IntSize secondChildBounds = IntSize(25, 53);
168     layerTreeRoot->children()[1]->setBounds(secondChildBounds);
169
170     RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), 0);
171     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
172
173     // Check that the property values we set on the LayerChromium tree are reflected in the CCLayerImpl tree.
174     FloatPoint rootCCLayerPosition = ccLayerTreeRoot->position();
175     EXPECT_EQ(rootPosition.x(), rootCCLayerPosition.x());
176     EXPECT_EQ(rootPosition.y(), rootCCLayerPosition.y());
177
178     EXPECT_EQ(firstChildOpacity, ccLayerTreeRoot->children()[0]->opacity());
179
180     IntSize secondCCLayerChildBounds = ccLayerTreeRoot->children()[1]->bounds();
181     EXPECT_EQ(secondChildBounds.width(), secondCCLayerChildBounds.width());
182     EXPECT_EQ(secondChildBounds.height(), secondCCLayerChildBounds.height());
183 }
184
185 TEST(TreeSynchronizerTest, reuseCCLayersAfterStructuralChange)
186 {
187     Vector<int> ccLayerDestructionList;
188
189     // Set up a tree with this sort of structure:
190     // root --- A --- B ---+--- C
191     //                     |
192     //                     +--- D
193     RefPtr<LayerChromium> layerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
194     layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
195
196     RefPtr<LayerChromium> layerA = layerTreeRoot->children()[0].get();
197     layerA->addChild(MockLayerChromium::create(&ccLayerDestructionList));
198
199     RefPtr<LayerChromium> layerB = layerA->children()[0].get();
200     layerB->addChild(MockLayerChromium::create(&ccLayerDestructionList));
201
202     RefPtr<LayerChromium> layerC = layerB->children()[0].get();
203     layerB->addChild(MockLayerChromium::create(&ccLayerDestructionList));
204     RefPtr<LayerChromium> layerD = layerB->children()[1].get();
205
206     RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), 0);
207     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
208
209     // Now restructure the tree to look like this:
210     // root --- D ---+--- A
211     //               |
212     //               +--- C --- B
213     layerTreeRoot->removeAllChildren();
214     layerD->removeAllChildren();
215     layerTreeRoot->addChild(layerD);
216     layerA->removeAllChildren();
217     layerD->addChild(layerA);
218     layerC->removeAllChildren();
219     layerD->addChild(layerC);
220     layerB->removeAllChildren();
221     layerC->addChild(layerB);
222
223     // After another synchronize our trees should match and we should not have destroyed any CCLayerImpls
224     ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
225     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
226
227     EXPECT_EQ(0u, ccLayerDestructionList.size());
228 }
229
230 // Constructs a very simple tree, synchronizes it, then synchronizes to a totally new tree. All layers from the old tree should be deleted.
231 TEST(TreeSynchronizerTest, syncSimpleTreeThenDestroy)
232 {
233     Vector<int> ccLayerDestructionList;
234
235     RefPtr<LayerChromium> oldLayerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
236     oldLayerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
237     oldLayerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
238
239     int oldTreeRootLayerId = oldLayerTreeRoot->id();
240     int oldTreeFirstChildLayerId = oldLayerTreeRoot->children()[0]->id();
241     int oldTreeSecondChildLayerId = oldLayerTreeRoot->children()[1]->id();
242
243     RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(oldLayerTreeRoot.get(), 0);
244     expectTreesAreIdentical(oldLayerTreeRoot.get(), ccLayerTreeRoot.get());
245
246     // Remove all children on the LayerChromium side.
247     oldLayerTreeRoot->removeAllChildren();
248
249     // Synchronize again. After the sync all CCLayerImpls from the old tree should be deleted.
250     RefPtr<LayerChromium> newLayerTreeRoot = LayerChromium::create(0);
251     ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(newLayerTreeRoot.get(), ccLayerTreeRoot.release());
252     expectTreesAreIdentical(newLayerTreeRoot.get(), ccLayerTreeRoot.get());
253
254     ASSERT_EQ(3u, ccLayerDestructionList.size());
255     EXPECT_TRUE(ccLayerDestructionList.contains(oldTreeRootLayerId));
256     EXPECT_TRUE(ccLayerDestructionList.contains(oldTreeFirstChildLayerId));
257     EXPECT_TRUE(ccLayerDestructionList.contains(oldTreeSecondChildLayerId));
258 }
259
260 // Constructs+syncs a tree with mask, replica, and replica mask layers.
261 TEST(TreeSynchronizerTest, syncMaskReplicaAndReplicaMaskLayers)
262 {
263     RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(0);
264     layerTreeRoot->addChild(LayerChromium::create(0));
265     layerTreeRoot->addChild(LayerChromium::create(0));
266     layerTreeRoot->addChild(LayerChromium::create(0));
267
268     // First child gets a mask layer.
269     RefPtr<LayerChromium> maskLayer = LayerChromium::create(0);
270     layerTreeRoot->children()[0]->setMaskLayer(maskLayer.get());
271
272     // Second child gets a replica layer.
273     RefPtr<LayerChromium> replicaLayer = LayerChromium::create(0);
274     layerTreeRoot->children()[1]->setReplicaLayer(replicaLayer.get());
275
276     // Third child gets a replica layer with a mask layer.
277     RefPtr<LayerChromium> replicaLayerWithMask = LayerChromium::create(0);
278     RefPtr<LayerChromium> replicaMaskLayer = LayerChromium::create(0);
279     replicaLayerWithMask->setMaskLayer(replicaMaskLayer.get());
280     layerTreeRoot->children()[2]->setReplicaLayer(replicaLayerWithMask.get());
281
282     RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), 0);
283
284     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
285
286     // Remove the mask layer.
287     layerTreeRoot->children()[0]->setMaskLayer(0);
288     ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.get());
289     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
290
291     // Remove the replica layer.
292     layerTreeRoot->children()[1]->setReplicaLayer(0);
293     ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.get());
294     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
295
296     // Remove the replica mask.
297     replicaLayerWithMask->setMaskLayer(0);
298     ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.get());
299     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
300 }
301
302
303 } // namespace