gfx/tests/gtest/TestLayers.cpp

changeset 0
6474c204b198
     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 +}

mercurial