gfx/tests/gtest/TestLayers.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:e4296eef9a69
1 /* vim:set ts=2 sw=2 sts=2 et: */
2 /* Any copyright is dedicated to the Public Domain.
3 * http://creativecommons.org/publicdomain/zero/1.0/
4 */
5
6 #include "TestLayers.h"
7 #include "gtest/gtest.h"
8 #include "gmock/gmock.h"
9
10 using namespace mozilla;
11 using namespace mozilla::gfx;
12 using namespace mozilla::layers;
13
14 class TestLayerManager: public LayerManager {
15 public:
16 TestLayerManager()
17 : LayerManager()
18 {}
19
20 virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) { return false; }
21 virtual already_AddRefed<ContainerLayer> CreateContainerLayer() { return nullptr; }
22 virtual void GetBackendName(nsAString& aName) {}
23 virtual LayersBackend GetBackendType() { return LayersBackend::LAYERS_BASIC; }
24 virtual void BeginTransaction() {}
25 virtual already_AddRefed<ImageLayer> CreateImageLayer() { return nullptr; }
26 virtual void SetRoot(Layer* aLayer) {}
27 virtual already_AddRefed<ColorLayer> CreateColorLayer() { return nullptr; }
28 virtual void BeginTransactionWithTarget(gfxContext* aTarget) {}
29 virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() { return nullptr; }
30 virtual void EndTransaction(DrawThebesLayerCallback aCallback,
31 void* aCallbackData,
32 EndTransactionFlags aFlags = END_DEFAULT) {}
33 virtual int32_t GetMaxTextureSize() const { return 0; }
34 virtual already_AddRefed<ThebesLayer> CreateThebesLayer() { return nullptr; }
35 };
36
37 class TestContainerLayer: public ContainerLayer {
38 public:
39 TestContainerLayer(LayerManager* aManager)
40 : ContainerLayer(aManager, nullptr)
41 {}
42
43 virtual const char* Name() const {
44 return "TestContainerLayer";
45 }
46
47 virtual LayerType GetType() const {
48 return TYPE_CONTAINER;
49 }
50
51 virtual void ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface) {
52 DefaultComputeEffectiveTransforms(aTransformToSurface);
53 }
54 };
55
56 class TestThebesLayer: public ThebesLayer {
57 public:
58 TestThebesLayer(LayerManager* aManager)
59 : ThebesLayer(aManager, nullptr)
60 {}
61
62 virtual const char* Name() const {
63 return "TestThebesLayer";
64 }
65
66 virtual LayerType GetType() const {
67 return TYPE_THEBES;
68 }
69
70 virtual void InvalidateRegion(const nsIntRegion& aRegion) {
71 MOZ_CRASH();
72 }
73 };
74
75 class TestUserData: public LayerUserData {
76 public:
77 MOCK_METHOD0(Die, void());
78 virtual ~TestUserData() { Die(); }
79 };
80
81
82 TEST(Layers, LayerConstructor) {
83 TestContainerLayer layer(nullptr);
84 }
85
86 TEST(Layers, Defaults) {
87 TestContainerLayer layer(nullptr);
88 ASSERT_EQ(1.0, layer.GetOpacity());
89 ASSERT_EQ(1.0f, layer.GetPostXScale());
90 ASSERT_EQ(1.0f, layer.GetPostYScale());
91
92 ASSERT_EQ(nullptr, layer.GetNextSibling());
93 ASSERT_EQ(nullptr, layer.GetPrevSibling());
94 ASSERT_EQ(nullptr, layer.GetFirstChild());
95 ASSERT_EQ(nullptr, layer.GetLastChild());
96 }
97
98 TEST(Layers, Transform) {
99 TestContainerLayer layer(nullptr);
100
101 Matrix4x4 identity;
102 ASSERT_EQ(true, identity.IsIdentity());
103
104 ASSERT_EQ(identity, layer.GetTransform());
105 }
106
107 TEST(Layers, Type) {
108 TestContainerLayer layer(nullptr);
109 ASSERT_EQ(nullptr, layer.AsThebesLayer());
110 ASSERT_EQ(nullptr, layer.AsRefLayer());
111 ASSERT_EQ(nullptr, layer.AsColorLayer());
112 }
113
114 TEST(Layers, UserData) {
115 TestContainerLayer* layerPtr = new TestContainerLayer(nullptr);
116 TestContainerLayer& layer = *layerPtr;
117
118 void* key1 = (void*)1;
119 void* key2 = (void*)2;
120 void* key3 = (void*)3;
121
122 TestUserData* data1 = new TestUserData;
123 TestUserData* data2 = new TestUserData;
124 TestUserData* data3 = new TestUserData;
125
126 ASSERT_EQ(nullptr, layer.GetUserData(key1));
127 ASSERT_EQ(nullptr, layer.GetUserData(key2));
128 ASSERT_EQ(nullptr, layer.GetUserData(key3));
129
130 layer.SetUserData(key1, data1);
131 layer.SetUserData(key2, data2);
132 layer.SetUserData(key3, data3);
133
134 // Also checking that the user data is returned but not free'd
135 ASSERT_EQ(data1, layer.RemoveUserData(key1).forget());
136 ASSERT_EQ(data2, layer.RemoveUserData(key2).forget());
137 ASSERT_EQ(data3, layer.RemoveUserData(key3).forget());
138
139 layer.SetUserData(key1, data1);
140 layer.SetUserData(key2, data2);
141 layer.SetUserData(key3, data3);
142
143 // Layer has ownership of data1-3, check that they are destroyed
144 EXPECT_CALL(*data1, Die());
145 EXPECT_CALL(*data2, Die());
146 EXPECT_CALL(*data3, Die());
147 delete layerPtr;
148
149 }
150
151 static
152 already_AddRefed<Layer> CreateLayer(char aLayerType, LayerManager* aManager) {
153 nsRefPtr<Layer> layer = nullptr;
154 if (aLayerType == 'c') {
155 layer = new TestContainerLayer(aManager);
156 } else if (aLayerType == 't') {
157 layer = new TestThebesLayer(aManager);
158 }
159 return layer.forget();
160 }
161
162 already_AddRefed<Layer> CreateLayerTree(
163 const char* aLayerTreeDescription,
164 nsIntRegion* aVisibleRegions,
165 const gfx3DMatrix* aTransforms,
166 nsRefPtr<LayerManager>& manager,
167 nsTArray<nsRefPtr<Layer> >& aLayersOut) {
168
169 aLayersOut.Clear();
170
171 manager = new TestLayerManager();
172
173 nsRefPtr<Layer> rootLayer = nullptr;
174 nsRefPtr<ContainerLayer> parentContainerLayer = nullptr;
175 nsRefPtr<Layer> lastLayer = nullptr;
176 int layerNumber = 0;
177 for (size_t i = 0; i < strlen(aLayerTreeDescription); i++) {
178 if (aLayerTreeDescription[i] == '(') {
179 if (!lastLayer) {
180 printf("Syntax error, likely '(' character isn't preceded by a container.\n");
181 MOZ_CRASH();
182 }
183 parentContainerLayer = lastLayer->AsContainerLayer();
184 if (!parentContainerLayer) {
185 printf("Layer before '(' must be a container.\n");
186 MOZ_CRASH();
187 }
188 } else if (aLayerTreeDescription[i] == ')') {
189 parentContainerLayer = parentContainerLayer->GetParent();
190 lastLayer = nullptr;
191 } else {
192 nsRefPtr<Layer> layer = CreateLayer(aLayerTreeDescription[i], manager.get());
193 if (aVisibleRegions) {
194 layer->SetVisibleRegion(aVisibleRegions[layerNumber]);
195 }
196 if (aTransforms) {
197 Matrix4x4 transform;
198 ToMatrix4x4(aTransforms[layerNumber], transform);
199 layer->SetBaseTransform(transform);
200 }
201 aLayersOut.AppendElement(layer);
202 layerNumber++;
203 if (rootLayer && !parentContainerLayer) {
204 MOZ_CRASH();
205 }
206 if (!rootLayer) {
207 rootLayer = layer;
208 }
209 if (parentContainerLayer) {
210 parentContainerLayer->InsertAfter(layer, parentContainerLayer->GetLastChild());
211 layer->SetParent(parentContainerLayer);
212 }
213 lastLayer = layer;
214 }
215 }
216 if (rootLayer) {
217 rootLayer->ComputeEffectiveTransforms(Matrix4x4());
218 }
219 return rootLayer.forget();
220 }
221
222 TEST(Layers, LayerTree) {
223 const char* layerTreeSyntax = "c(c(tt))";
224 nsIntRegion layerVisibleRegion[] = {
225 nsIntRegion(nsIntRect(0,0,100,100)),
226 nsIntRegion(nsIntRect(0,0,100,100)),
227 nsIntRegion(nsIntRect(0,0,100,100)),
228 nsIntRegion(nsIntRect(10,10,20,20)),
229 };
230 gfx3DMatrix transforms[] = {
231 gfx3DMatrix(),
232 gfx3DMatrix(),
233 gfx3DMatrix(),
234 gfx3DMatrix(),
235 };
236 nsTArray<nsRefPtr<Layer> > layers;
237
238 nsRefPtr<LayerManager> lm;
239 nsRefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
240
241 // B2G g++ doesn't like ASSERT_NE with nullptr directly. It thinks it's
242 // an int.
243 Layer* nullLayer = nullptr;
244 ASSERT_NE(nullLayer, layers[0]->AsContainerLayer());
245 ASSERT_NE(nullLayer, layers[1]->AsContainerLayer());
246 ASSERT_NE(nullLayer, layers[2]->AsThebesLayer());
247 ASSERT_NE(nullLayer, layers[3]->AsThebesLayer());
248 }
249
250 static void ValidateTreePointers(Layer* aLayer) {
251 if (aLayer->GetNextSibling()) {
252 ASSERT_EQ(aLayer, aLayer->GetNextSibling()->GetPrevSibling());
253 } else if (aLayer->GetParent()) {
254 ASSERT_EQ(aLayer, aLayer->GetParent()->GetLastChild());
255 }
256 if (aLayer->GetPrevSibling()) {
257 ASSERT_EQ(aLayer, aLayer->GetPrevSibling()->GetNextSibling());
258 } else if (aLayer->GetParent()) {
259 ASSERT_EQ(aLayer, aLayer->GetParent()->GetFirstChild());
260 }
261 if (aLayer->GetFirstChild()) {
262 ASSERT_EQ(aLayer, aLayer->GetFirstChild()->GetParent());
263 }
264 if (aLayer->GetLastChild()) {
265 ASSERT_EQ(aLayer, aLayer->GetLastChild()->GetParent());
266 }
267 }
268
269 static void ValidateTreePointers(nsTArray<nsRefPtr<Layer> >& aLayers) {
270 for (uint32_t i = 0; i < aLayers.Length(); i++) {
271 ValidateTreePointers(aLayers[i]);
272 }
273 }
274
275 TEST(Layers, RepositionChild) {
276 const char* layerTreeSyntax = "c(ttt)";
277
278 nsTArray<nsRefPtr<Layer> > layers;
279 nsRefPtr<LayerManager> lm;
280 nsRefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, nullptr, nullptr, lm, layers);
281 ContainerLayer* parent = root->AsContainerLayer();
282 ValidateTreePointers(layers);
283
284 // tree is currently like this (using indexes into layers):
285 // 0
286 // 1 2 3
287 ASSERT_EQ(layers[2], layers[1]->GetNextSibling());
288 ASSERT_EQ(layers[3], layers[2]->GetNextSibling());
289 ASSERT_EQ(nullptr, layers[3]->GetNextSibling());
290
291 parent->RepositionChild(layers[1], layers[3]);
292 ValidateTreePointers(layers);
293
294 // now the tree is like this:
295 // 0
296 // 2 3 1
297 ASSERT_EQ(layers[3], layers[2]->GetNextSibling());
298 ASSERT_EQ(layers[1], layers[3]->GetNextSibling());
299 ASSERT_EQ(nullptr, layers[1]->GetNextSibling());
300
301 parent->RepositionChild(layers[3], layers[2]);
302 ValidateTreePointers(layers);
303
304 // no change
305 ASSERT_EQ(layers[3], layers[2]->GetNextSibling());
306 ASSERT_EQ(layers[1], layers[3]->GetNextSibling());
307 ASSERT_EQ(nullptr, layers[1]->GetNextSibling());
308
309 parent->RepositionChild(layers[3], layers[1]);
310 ValidateTreePointers(layers);
311
312 // 0
313 // 2 1 3
314 ASSERT_EQ(layers[1], layers[2]->GetNextSibling());
315 ASSERT_EQ(layers[3], layers[1]->GetNextSibling());
316 ASSERT_EQ(nullptr, layers[3]->GetNextSibling());
317
318 parent->RepositionChild(layers[3], nullptr);
319 ValidateTreePointers(layers);
320
321 // 0
322 // 3 2 1
323 ASSERT_EQ(layers[2], layers[3]->GetNextSibling());
324 ASSERT_EQ(layers[1], layers[2]->GetNextSibling());
325 ASSERT_EQ(nullptr, layers[1]->GetNextSibling());
326 }

mercurial