[chromium] Make CCThreadProxy draw
[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 "cc/CCProxy.h"
32 #include <gtest/gtest.h>
33
34 using namespace WebCore;
35
36 namespace {
37
38 class ScopedSetImplThread {
39 public:
40     ScopedSetImplThread()
41     {
42 #ifndef NDEBUG
43         CCProxy::setImplThread(true);
44 #endif
45     }
46     ~ScopedSetImplThread()
47     {
48 #ifndef NDEBUG
49         CCProxy::setImplThread(false);
50 #endif
51     }
52 };
53
54 class MockCCLayerImpl : public CCLayerImpl {
55 public:
56     static PassRefPtr<MockCCLayerImpl> create(int layerId)
57     {
58         return adoptRef(new MockCCLayerImpl(layerId));
59     }
60     virtual ~MockCCLayerImpl()
61     {
62         if (m_ccLayerDestructionList)
63             m_ccLayerDestructionList->append(id());
64     }
65
66     void setCCLayerDestructionList(Vector<int>* list) { m_ccLayerDestructionList = list; }
67
68 private:
69     MockCCLayerImpl(int layerId)
70         : CCLayerImpl(layerId)
71         , m_ccLayerDestructionList(0)
72     {
73     }
74
75     Vector<int>* m_ccLayerDestructionList;
76 };
77
78 class MockLayerChromium : public LayerChromium {
79 public:
80     static PassRefPtr<MockLayerChromium> create(Vector<int>* ccLayerDestructionList)
81     {
82         return adoptRef(new MockLayerChromium(ccLayerDestructionList));
83     }
84
85     virtual ~MockLayerChromium() { }
86
87     virtual PassRefPtr<CCLayerImpl> createCCLayerImpl()
88     {
89         return MockCCLayerImpl::create(m_layerId);
90     }
91
92     virtual void pushPropertiesTo(CCLayerImpl* ccLayer)
93     {
94         LayerChromium::pushPropertiesTo(ccLayer);
95
96         MockCCLayerImpl* mockCCLayer = static_cast<MockCCLayerImpl*>(ccLayer);
97         mockCCLayer->setCCLayerDestructionList(m_ccLayerDestructionList);
98     }
99 private:
100     MockLayerChromium(Vector<int>* ccLayerDestructionList)
101         : LayerChromium(0)
102         , m_ccLayerDestructionList(ccLayerDestructionList)
103     {
104     }
105
106     Vector<int>* m_ccLayerDestructionList;
107 };
108
109 void expectTreesAreIdentical(LayerChromium* layer, CCLayerImpl* ccLayer)
110 {
111     ASSERT_TRUE(layer);
112     ASSERT_TRUE(ccLayer);
113
114     EXPECT_EQ(layer->id(), ccLayer->id());
115
116     ASSERT_EQ(!!layer->maskLayer(), !!ccLayer->maskLayer());
117     if (layer->maskLayer())
118         expectTreesAreIdentical(layer->maskLayer(), ccLayer->maskLayer());
119
120     ASSERT_EQ(!!layer->replicaLayer(), !!ccLayer->replicaLayer());
121     if (layer->replicaLayer())
122         expectTreesAreIdentical(layer->replicaLayer(), ccLayer->replicaLayer());
123
124     const Vector<RefPtr<LayerChromium> >& layerChildren = layer->children();
125     const Vector<RefPtr<CCLayerImpl> >& ccLayerChildren = ccLayer->children();
126
127     ASSERT_EQ(layerChildren.size(), ccLayerChildren.size());
128
129     for (size_t i = 0; i < layerChildren.size(); ++i)
130         expectTreesAreIdentical(layerChildren[i].get(), ccLayerChildren[i].get());
131 }
132
133 // Constructs a very simple tree and synchronizes it without trying to reuse any preexisting layers.
134 TEST(TreeSynchronizerTest, syncSimpleTreeFromEmpty)
135 {
136     ScopedSetImplThread impl;
137     RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(0);
138     layerTreeRoot->addChild(LayerChromium::create(0));
139     layerTreeRoot->addChild(LayerChromium::create(0));
140
141     RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), 0);
142
143     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
144 }
145
146 // Constructs a very simple tree and synchronizes it attempting to reuse some layers
147 TEST(TreeSynchronizerTest, syncSimpleTreeReusingLayers)
148 {
149     ScopedSetImplThread impl;
150     Vector<int> ccLayerDestructionList;
151
152     RefPtr<LayerChromium> layerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
153     layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
154     layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
155
156     RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), 0);
157     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
158
159     // Add a new layer to the LayerChromium side
160     layerTreeRoot->children()[0]->addChild(MockLayerChromium::create(&ccLayerDestructionList));
161     // Remove one.
162     layerTreeRoot->children()[1]->removeFromParent();
163     int secondCCLayerId = ccLayerTreeRoot->children()[1]->id();
164
165     // Synchronize again. After the sync the trees should be equivalent and we should have created and destroyed one CCLayerImpl.
166     ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
167     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
168
169     ASSERT_EQ(1u, ccLayerDestructionList.size());
170     EXPECT_EQ(secondCCLayerId, ccLayerDestructionList[0]);
171 }
172
173 TEST(TreeSynchronizerTest, syncSimpleTreeAndProperties)
174 {
175     ScopedSetImplThread impl;
176     RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(0);
177     layerTreeRoot->addChild(LayerChromium::create(0));
178     layerTreeRoot->addChild(LayerChromium::create(0));
179
180     // Pick some random properties to set. The values are not important, we're just testing that at least some properties are making it through.
181     FloatPoint rootPosition = FloatPoint(2.3, 7.4);
182     layerTreeRoot->setPosition(rootPosition);
183
184     float firstChildOpacity = 0.25;
185     layerTreeRoot->children()[0]->setOpacity(firstChildOpacity);
186
187     IntSize secondChildBounds = IntSize(25, 53);
188     layerTreeRoot->children()[1]->setBounds(secondChildBounds);
189
190     RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), 0);
191     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
192
193     // Check that the property values we set on the LayerChromium tree are reflected in the CCLayerImpl tree.
194     FloatPoint rootCCLayerPosition = ccLayerTreeRoot->position();
195     EXPECT_EQ(rootPosition.x(), rootCCLayerPosition.x());
196     EXPECT_EQ(rootPosition.y(), rootCCLayerPosition.y());
197
198     EXPECT_EQ(firstChildOpacity, ccLayerTreeRoot->children()[0]->opacity());
199
200     IntSize secondCCLayerChildBounds = ccLayerTreeRoot->children()[1]->bounds();
201     EXPECT_EQ(secondChildBounds.width(), secondCCLayerChildBounds.width());
202     EXPECT_EQ(secondChildBounds.height(), secondCCLayerChildBounds.height());
203 }
204
205 TEST(TreeSynchronizerTest, reuseCCLayersAfterStructuralChange)
206 {
207     ScopedSetImplThread impl;
208     Vector<int> ccLayerDestructionList;
209
210     // Set up a tree with this sort of structure:
211     // root --- A --- B ---+--- C
212     //                     |
213     //                     +--- D
214     RefPtr<LayerChromium> layerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
215     layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
216
217     RefPtr<LayerChromium> layerA = layerTreeRoot->children()[0].get();
218     layerA->addChild(MockLayerChromium::create(&ccLayerDestructionList));
219
220     RefPtr<LayerChromium> layerB = layerA->children()[0].get();
221     layerB->addChild(MockLayerChromium::create(&ccLayerDestructionList));
222
223     RefPtr<LayerChromium> layerC = layerB->children()[0].get();
224     layerB->addChild(MockLayerChromium::create(&ccLayerDestructionList));
225     RefPtr<LayerChromium> layerD = layerB->children()[1].get();
226
227     RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), 0);
228     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
229
230     // Now restructure the tree to look like this:
231     // root --- D ---+--- A
232     //               |
233     //               +--- C --- B
234     layerTreeRoot->removeAllChildren();
235     layerD->removeAllChildren();
236     layerTreeRoot->addChild(layerD);
237     layerA->removeAllChildren();
238     layerD->addChild(layerA);
239     layerC->removeAllChildren();
240     layerD->addChild(layerC);
241     layerB->removeAllChildren();
242     layerC->addChild(layerB);
243
244     // After another synchronize our trees should match and we should not have destroyed any CCLayerImpls
245     ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
246     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
247
248     EXPECT_EQ(0u, ccLayerDestructionList.size());
249 }
250
251 // Constructs a very simple tree, synchronizes it, then synchronizes to a totally new tree. All layers from the old tree should be deleted.
252 TEST(TreeSynchronizerTest, syncSimpleTreeThenDestroy)
253 {
254     ScopedSetImplThread impl;
255     Vector<int> ccLayerDestructionList;
256
257     RefPtr<LayerChromium> oldLayerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
258     oldLayerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
259     oldLayerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
260
261     int oldTreeRootLayerId = oldLayerTreeRoot->id();
262     int oldTreeFirstChildLayerId = oldLayerTreeRoot->children()[0]->id();
263     int oldTreeSecondChildLayerId = oldLayerTreeRoot->children()[1]->id();
264
265     RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(oldLayerTreeRoot.get(), 0);
266     expectTreesAreIdentical(oldLayerTreeRoot.get(), ccLayerTreeRoot.get());
267
268     // Remove all children on the LayerChromium side.
269     oldLayerTreeRoot->removeAllChildren();
270
271     // Synchronize again. After the sync all CCLayerImpls from the old tree should be deleted.
272     RefPtr<LayerChromium> newLayerTreeRoot = LayerChromium::create(0);
273     ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(newLayerTreeRoot.get(), ccLayerTreeRoot.release());
274     expectTreesAreIdentical(newLayerTreeRoot.get(), ccLayerTreeRoot.get());
275
276     ASSERT_EQ(3u, ccLayerDestructionList.size());
277     EXPECT_TRUE(ccLayerDestructionList.contains(oldTreeRootLayerId));
278     EXPECT_TRUE(ccLayerDestructionList.contains(oldTreeFirstChildLayerId));
279     EXPECT_TRUE(ccLayerDestructionList.contains(oldTreeSecondChildLayerId));
280 }
281
282 // Constructs+syncs a tree with mask, replica, and replica mask layers.
283 TEST(TreeSynchronizerTest, syncMaskReplicaAndReplicaMaskLayers)
284 {
285     ScopedSetImplThread impl;
286     RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(0);
287     layerTreeRoot->addChild(LayerChromium::create(0));
288     layerTreeRoot->addChild(LayerChromium::create(0));
289     layerTreeRoot->addChild(LayerChromium::create(0));
290
291     // First child gets a mask layer.
292     RefPtr<LayerChromium> maskLayer = LayerChromium::create(0);
293     layerTreeRoot->children()[0]->setMaskLayer(maskLayer.get());
294
295     // Second child gets a replica layer.
296     RefPtr<LayerChromium> replicaLayer = LayerChromium::create(0);
297     layerTreeRoot->children()[1]->setReplicaLayer(replicaLayer.get());
298
299     // Third child gets a replica layer with a mask layer.
300     RefPtr<LayerChromium> replicaLayerWithMask = LayerChromium::create(0);
301     RefPtr<LayerChromium> replicaMaskLayer = LayerChromium::create(0);
302     replicaLayerWithMask->setMaskLayer(replicaMaskLayer.get());
303     layerTreeRoot->children()[2]->setReplicaLayer(replicaLayerWithMask.get());
304
305     RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), 0);
306
307     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
308
309     // Remove the mask layer.
310     layerTreeRoot->children()[0]->setMaskLayer(0);
311     ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.get());
312     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
313
314     // Remove the replica layer.
315     layerTreeRoot->children()[1]->setReplicaLayer(0);
316     ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.get());
317     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
318
319     // Remove the replica mask.
320     replicaLayerWithMask->setMaskLayer(0);
321     ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.get());
322     expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
323 }
324
325
326 } // namespace