1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/tests/gtest/TestLayers.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,326 @@ 1.4 +/* vim:set ts=2 sw=2 sts=2 et: */ 1.5 +/* Any copyright is dedicated to the Public Domain. 1.6 + * http://creativecommons.org/publicdomain/zero/1.0/ 1.7 + */ 1.8 + 1.9 +#include "TestLayers.h" 1.10 +#include "gtest/gtest.h" 1.11 +#include "gmock/gmock.h" 1.12 + 1.13 +using namespace mozilla; 1.14 +using namespace mozilla::gfx; 1.15 +using namespace mozilla::layers; 1.16 + 1.17 +class TestLayerManager: public LayerManager { 1.18 +public: 1.19 + TestLayerManager() 1.20 + : LayerManager() 1.21 + {} 1.22 + 1.23 + virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) { return false; } 1.24 + virtual already_AddRefed<ContainerLayer> CreateContainerLayer() { return nullptr; } 1.25 + virtual void GetBackendName(nsAString& aName) {} 1.26 + virtual LayersBackend GetBackendType() { return LayersBackend::LAYERS_BASIC; } 1.27 + virtual void BeginTransaction() {} 1.28 + virtual already_AddRefed<ImageLayer> CreateImageLayer() { return nullptr; } 1.29 + virtual void SetRoot(Layer* aLayer) {} 1.30 + virtual already_AddRefed<ColorLayer> CreateColorLayer() { return nullptr; } 1.31 + virtual void BeginTransactionWithTarget(gfxContext* aTarget) {} 1.32 + virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() { return nullptr; } 1.33 + virtual void EndTransaction(DrawThebesLayerCallback aCallback, 1.34 + void* aCallbackData, 1.35 + EndTransactionFlags aFlags = END_DEFAULT) {} 1.36 + virtual int32_t GetMaxTextureSize() const { return 0; } 1.37 + virtual already_AddRefed<ThebesLayer> CreateThebesLayer() { return nullptr; } 1.38 +}; 1.39 + 1.40 +class TestContainerLayer: public ContainerLayer { 1.41 +public: 1.42 + TestContainerLayer(LayerManager* aManager) 1.43 + : ContainerLayer(aManager, nullptr) 1.44 + {} 1.45 + 1.46 + virtual const char* Name() const { 1.47 + return "TestContainerLayer"; 1.48 + } 1.49 + 1.50 + virtual LayerType GetType() const { 1.51 + return TYPE_CONTAINER; 1.52 + } 1.53 + 1.54 + virtual void ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface) { 1.55 + DefaultComputeEffectiveTransforms(aTransformToSurface); 1.56 + } 1.57 +}; 1.58 + 1.59 +class TestThebesLayer: public ThebesLayer { 1.60 +public: 1.61 + TestThebesLayer(LayerManager* aManager) 1.62 + : ThebesLayer(aManager, nullptr) 1.63 + {} 1.64 + 1.65 + virtual const char* Name() const { 1.66 + return "TestThebesLayer"; 1.67 + } 1.68 + 1.69 + virtual LayerType GetType() const { 1.70 + return TYPE_THEBES; 1.71 + } 1.72 + 1.73 + virtual void InvalidateRegion(const nsIntRegion& aRegion) { 1.74 + MOZ_CRASH(); 1.75 + } 1.76 +}; 1.77 + 1.78 +class TestUserData: public LayerUserData { 1.79 +public: 1.80 + MOCK_METHOD0(Die, void()); 1.81 + virtual ~TestUserData() { Die(); } 1.82 +}; 1.83 + 1.84 + 1.85 +TEST(Layers, LayerConstructor) { 1.86 + TestContainerLayer layer(nullptr); 1.87 +} 1.88 + 1.89 +TEST(Layers, Defaults) { 1.90 + TestContainerLayer layer(nullptr); 1.91 + ASSERT_EQ(1.0, layer.GetOpacity()); 1.92 + ASSERT_EQ(1.0f, layer.GetPostXScale()); 1.93 + ASSERT_EQ(1.0f, layer.GetPostYScale()); 1.94 + 1.95 + ASSERT_EQ(nullptr, layer.GetNextSibling()); 1.96 + ASSERT_EQ(nullptr, layer.GetPrevSibling()); 1.97 + ASSERT_EQ(nullptr, layer.GetFirstChild()); 1.98 + ASSERT_EQ(nullptr, layer.GetLastChild()); 1.99 +} 1.100 + 1.101 +TEST(Layers, Transform) { 1.102 + TestContainerLayer layer(nullptr); 1.103 + 1.104 + Matrix4x4 identity; 1.105 + ASSERT_EQ(true, identity.IsIdentity()); 1.106 + 1.107 + ASSERT_EQ(identity, layer.GetTransform()); 1.108 +} 1.109 + 1.110 +TEST(Layers, Type) { 1.111 + TestContainerLayer layer(nullptr); 1.112 + ASSERT_EQ(nullptr, layer.AsThebesLayer()); 1.113 + ASSERT_EQ(nullptr, layer.AsRefLayer()); 1.114 + ASSERT_EQ(nullptr, layer.AsColorLayer()); 1.115 +} 1.116 + 1.117 +TEST(Layers, UserData) { 1.118 + TestContainerLayer* layerPtr = new TestContainerLayer(nullptr); 1.119 + TestContainerLayer& layer = *layerPtr; 1.120 + 1.121 + void* key1 = (void*)1; 1.122 + void* key2 = (void*)2; 1.123 + void* key3 = (void*)3; 1.124 + 1.125 + TestUserData* data1 = new TestUserData; 1.126 + TestUserData* data2 = new TestUserData; 1.127 + TestUserData* data3 = new TestUserData; 1.128 + 1.129 + ASSERT_EQ(nullptr, layer.GetUserData(key1)); 1.130 + ASSERT_EQ(nullptr, layer.GetUserData(key2)); 1.131 + ASSERT_EQ(nullptr, layer.GetUserData(key3)); 1.132 + 1.133 + layer.SetUserData(key1, data1); 1.134 + layer.SetUserData(key2, data2); 1.135 + layer.SetUserData(key3, data3); 1.136 + 1.137 + // Also checking that the user data is returned but not free'd 1.138 + ASSERT_EQ(data1, layer.RemoveUserData(key1).forget()); 1.139 + ASSERT_EQ(data2, layer.RemoveUserData(key2).forget()); 1.140 + ASSERT_EQ(data3, layer.RemoveUserData(key3).forget()); 1.141 + 1.142 + layer.SetUserData(key1, data1); 1.143 + layer.SetUserData(key2, data2); 1.144 + layer.SetUserData(key3, data3); 1.145 + 1.146 + // Layer has ownership of data1-3, check that they are destroyed 1.147 + EXPECT_CALL(*data1, Die()); 1.148 + EXPECT_CALL(*data2, Die()); 1.149 + EXPECT_CALL(*data3, Die()); 1.150 + delete layerPtr; 1.151 + 1.152 +} 1.153 + 1.154 +static 1.155 +already_AddRefed<Layer> CreateLayer(char aLayerType, LayerManager* aManager) { 1.156 + nsRefPtr<Layer> layer = nullptr; 1.157 + if (aLayerType == 'c') { 1.158 + layer = new TestContainerLayer(aManager); 1.159 + } else if (aLayerType == 't') { 1.160 + layer = new TestThebesLayer(aManager); 1.161 + } 1.162 + return layer.forget(); 1.163 +} 1.164 + 1.165 +already_AddRefed<Layer> CreateLayerTree( 1.166 + const char* aLayerTreeDescription, 1.167 + nsIntRegion* aVisibleRegions, 1.168 + const gfx3DMatrix* aTransforms, 1.169 + nsRefPtr<LayerManager>& manager, 1.170 + nsTArray<nsRefPtr<Layer> >& aLayersOut) { 1.171 + 1.172 + aLayersOut.Clear(); 1.173 + 1.174 + manager = new TestLayerManager(); 1.175 + 1.176 + nsRefPtr<Layer> rootLayer = nullptr; 1.177 + nsRefPtr<ContainerLayer> parentContainerLayer = nullptr; 1.178 + nsRefPtr<Layer> lastLayer = nullptr; 1.179 + int layerNumber = 0; 1.180 + for (size_t i = 0; i < strlen(aLayerTreeDescription); i++) { 1.181 + if (aLayerTreeDescription[i] == '(') { 1.182 + if (!lastLayer) { 1.183 + printf("Syntax error, likely '(' character isn't preceded by a container.\n"); 1.184 + MOZ_CRASH(); 1.185 + } 1.186 + parentContainerLayer = lastLayer->AsContainerLayer(); 1.187 + if (!parentContainerLayer) { 1.188 + printf("Layer before '(' must be a container.\n"); 1.189 + MOZ_CRASH(); 1.190 + } 1.191 + } else if (aLayerTreeDescription[i] == ')') { 1.192 + parentContainerLayer = parentContainerLayer->GetParent(); 1.193 + lastLayer = nullptr; 1.194 + } else { 1.195 + nsRefPtr<Layer> layer = CreateLayer(aLayerTreeDescription[i], manager.get()); 1.196 + if (aVisibleRegions) { 1.197 + layer->SetVisibleRegion(aVisibleRegions[layerNumber]); 1.198 + } 1.199 + if (aTransforms) { 1.200 + Matrix4x4 transform; 1.201 + ToMatrix4x4(aTransforms[layerNumber], transform); 1.202 + layer->SetBaseTransform(transform); 1.203 + } 1.204 + aLayersOut.AppendElement(layer); 1.205 + layerNumber++; 1.206 + if (rootLayer && !parentContainerLayer) { 1.207 + MOZ_CRASH(); 1.208 + } 1.209 + if (!rootLayer) { 1.210 + rootLayer = layer; 1.211 + } 1.212 + if (parentContainerLayer) { 1.213 + parentContainerLayer->InsertAfter(layer, parentContainerLayer->GetLastChild()); 1.214 + layer->SetParent(parentContainerLayer); 1.215 + } 1.216 + lastLayer = layer; 1.217 + } 1.218 + } 1.219 + if (rootLayer) { 1.220 + rootLayer->ComputeEffectiveTransforms(Matrix4x4()); 1.221 + } 1.222 + return rootLayer.forget(); 1.223 +} 1.224 + 1.225 +TEST(Layers, LayerTree) { 1.226 + const char* layerTreeSyntax = "c(c(tt))"; 1.227 + nsIntRegion layerVisibleRegion[] = { 1.228 + nsIntRegion(nsIntRect(0,0,100,100)), 1.229 + nsIntRegion(nsIntRect(0,0,100,100)), 1.230 + nsIntRegion(nsIntRect(0,0,100,100)), 1.231 + nsIntRegion(nsIntRect(10,10,20,20)), 1.232 + }; 1.233 + gfx3DMatrix transforms[] = { 1.234 + gfx3DMatrix(), 1.235 + gfx3DMatrix(), 1.236 + gfx3DMatrix(), 1.237 + gfx3DMatrix(), 1.238 + }; 1.239 + nsTArray<nsRefPtr<Layer> > layers; 1.240 + 1.241 + nsRefPtr<LayerManager> lm; 1.242 + nsRefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers); 1.243 + 1.244 + // B2G g++ doesn't like ASSERT_NE with nullptr directly. It thinks it's 1.245 + // an int. 1.246 + Layer* nullLayer = nullptr; 1.247 + ASSERT_NE(nullLayer, layers[0]->AsContainerLayer()); 1.248 + ASSERT_NE(nullLayer, layers[1]->AsContainerLayer()); 1.249 + ASSERT_NE(nullLayer, layers[2]->AsThebesLayer()); 1.250 + ASSERT_NE(nullLayer, layers[3]->AsThebesLayer()); 1.251 +} 1.252 + 1.253 +static void ValidateTreePointers(Layer* aLayer) { 1.254 + if (aLayer->GetNextSibling()) { 1.255 + ASSERT_EQ(aLayer, aLayer->GetNextSibling()->GetPrevSibling()); 1.256 + } else if (aLayer->GetParent()) { 1.257 + ASSERT_EQ(aLayer, aLayer->GetParent()->GetLastChild()); 1.258 + } 1.259 + if (aLayer->GetPrevSibling()) { 1.260 + ASSERT_EQ(aLayer, aLayer->GetPrevSibling()->GetNextSibling()); 1.261 + } else if (aLayer->GetParent()) { 1.262 + ASSERT_EQ(aLayer, aLayer->GetParent()->GetFirstChild()); 1.263 + } 1.264 + if (aLayer->GetFirstChild()) { 1.265 + ASSERT_EQ(aLayer, aLayer->GetFirstChild()->GetParent()); 1.266 + } 1.267 + if (aLayer->GetLastChild()) { 1.268 + ASSERT_EQ(aLayer, aLayer->GetLastChild()->GetParent()); 1.269 + } 1.270 +} 1.271 + 1.272 +static void ValidateTreePointers(nsTArray<nsRefPtr<Layer> >& aLayers) { 1.273 + for (uint32_t i = 0; i < aLayers.Length(); i++) { 1.274 + ValidateTreePointers(aLayers[i]); 1.275 + } 1.276 +} 1.277 + 1.278 +TEST(Layers, RepositionChild) { 1.279 + const char* layerTreeSyntax = "c(ttt)"; 1.280 + 1.281 + nsTArray<nsRefPtr<Layer> > layers; 1.282 + nsRefPtr<LayerManager> lm; 1.283 + nsRefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, nullptr, nullptr, lm, layers); 1.284 + ContainerLayer* parent = root->AsContainerLayer(); 1.285 + ValidateTreePointers(layers); 1.286 + 1.287 + // tree is currently like this (using indexes into layers): 1.288 + // 0 1.289 + // 1 2 3 1.290 + ASSERT_EQ(layers[2], layers[1]->GetNextSibling()); 1.291 + ASSERT_EQ(layers[3], layers[2]->GetNextSibling()); 1.292 + ASSERT_EQ(nullptr, layers[3]->GetNextSibling()); 1.293 + 1.294 + parent->RepositionChild(layers[1], layers[3]); 1.295 + ValidateTreePointers(layers); 1.296 + 1.297 + // now the tree is like this: 1.298 + // 0 1.299 + // 2 3 1 1.300 + ASSERT_EQ(layers[3], layers[2]->GetNextSibling()); 1.301 + ASSERT_EQ(layers[1], layers[3]->GetNextSibling()); 1.302 + ASSERT_EQ(nullptr, layers[1]->GetNextSibling()); 1.303 + 1.304 + parent->RepositionChild(layers[3], layers[2]); 1.305 + ValidateTreePointers(layers); 1.306 + 1.307 + // no change 1.308 + ASSERT_EQ(layers[3], layers[2]->GetNextSibling()); 1.309 + ASSERT_EQ(layers[1], layers[3]->GetNextSibling()); 1.310 + ASSERT_EQ(nullptr, layers[1]->GetNextSibling()); 1.311 + 1.312 + parent->RepositionChild(layers[3], layers[1]); 1.313 + ValidateTreePointers(layers); 1.314 + 1.315 + // 0 1.316 + // 2 1 3 1.317 + ASSERT_EQ(layers[1], layers[2]->GetNextSibling()); 1.318 + ASSERT_EQ(layers[3], layers[1]->GetNextSibling()); 1.319 + ASSERT_EQ(nullptr, layers[3]->GetNextSibling()); 1.320 + 1.321 + parent->RepositionChild(layers[3], nullptr); 1.322 + ValidateTreePointers(layers); 1.323 + 1.324 + // 0 1.325 + // 3 2 1 1.326 + ASSERT_EQ(layers[2], layers[3]->GetNextSibling()); 1.327 + ASSERT_EQ(layers[1], layers[2]->GetNextSibling()); 1.328 + ASSERT_EQ(nullptr, layers[1]->GetNextSibling()); 1.329 +}