summaryrefslogtreecommitdiffstats
path: root/gfx/tests/gtest/TestLayers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/tests/gtest/TestLayers.cpp')
-rw-r--r--gfx/tests/gtest/TestLayers.cpp505
1 files changed, 505 insertions, 0 deletions
diff --git a/gfx/tests/gtest/TestLayers.cpp b/gfx/tests/gtest/TestLayers.cpp
new file mode 100644
index 0000000000..cebd5a9622
--- /dev/null
+++ b/gfx/tests/gtest/TestLayers.cpp
@@ -0,0 +1,505 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+#include "TestLayers.h"
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+#include "LayerUserData.h"
+#include "mozilla/layers/LayerMetricsWrapper.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace mozilla::layers;
+
+class TestContainerLayer : public ContainerLayer {
+ public:
+ explicit TestContainerLayer(LayerManager* aManager)
+ : ContainerLayer(aManager, nullptr) {}
+
+ virtual const char* Name() const { return "TestContainerLayer"; }
+
+ virtual LayerType GetType() const { return TYPE_CONTAINER; }
+
+ virtual void ComputeEffectiveTransforms(
+ const Matrix4x4& aTransformToSurface) {
+ DefaultComputeEffectiveTransforms(aTransformToSurface);
+ }
+};
+
+class TestPaintedLayer : public PaintedLayer {
+ public:
+ explicit TestPaintedLayer(LayerManager* aManager)
+ : PaintedLayer(aManager, nullptr) {}
+
+ virtual const char* Name() const { return "TestPaintedLayer"; }
+
+ virtual LayerType GetType() const { return TYPE_PAINTED; }
+
+ virtual void InvalidateRegion(const nsIntRegion& aRegion) { MOZ_CRASH(); }
+};
+
+class TestLayerManager : public LayerManager {
+ public:
+ TestLayerManager() : LayerManager() {}
+
+ virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) {
+ return false;
+ }
+ virtual already_AddRefed<ContainerLayer> CreateContainerLayer() {
+ RefPtr<ContainerLayer> layer = new TestContainerLayer(this);
+ return layer.forget();
+ }
+ virtual void GetBackendName(nsAString& aName) {}
+ virtual LayersBackend GetBackendType() { return LayersBackend::LAYERS_BASIC; }
+ virtual bool BeginTransaction(const nsCString& = nsCString()) { return true; }
+ virtual already_AddRefed<ImageLayer> CreateImageLayer() {
+ MOZ_CRASH("Not implemented.");
+ }
+ virtual already_AddRefed<PaintedLayer> CreatePaintedLayer() {
+ RefPtr<PaintedLayer> layer = new TestPaintedLayer(this);
+ return layer.forget();
+ }
+ virtual already_AddRefed<ColorLayer> CreateColorLayer() {
+ MOZ_CRASH("Not implemented.");
+ }
+ virtual void SetRoot(Layer* aLayer) {}
+ virtual bool BeginTransactionWithTarget(gfxContext* aTarget,
+ const nsCString& = nsCString()) {
+ return true;
+ }
+ virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() {
+ MOZ_CRASH("Not implemented.");
+ }
+ virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
+ void* aCallbackData,
+ EndTransactionFlags aFlags = END_DEFAULT) {}
+ virtual int32_t GetMaxTextureSize() const { return 0; }
+};
+
+class TestUserData : public LayerUserData {
+ public:
+ MOCK_METHOD0(Die, void());
+ virtual ~TestUserData() { Die(); }
+};
+
+TEST(Layers, LayerConstructor)
+{ TestContainerLayer layer(nullptr); }
+
+TEST(Layers, Defaults)
+{
+ TestContainerLayer layer(nullptr);
+ ASSERT_EQ(1.0, layer.GetOpacity());
+ ASSERT_EQ(1.0f, layer.GetPostXScale());
+ ASSERT_EQ(1.0f, layer.GetPostYScale());
+
+ ASSERT_EQ(nullptr, layer.GetNextSibling());
+ ASSERT_EQ(nullptr, layer.GetPrevSibling());
+ ASSERT_EQ(nullptr, layer.GetFirstChild());
+ ASSERT_EQ(nullptr, layer.GetLastChild());
+}
+
+TEST(Layers, Transform)
+{
+ TestContainerLayer layer(nullptr);
+
+ Matrix4x4 identity;
+ ASSERT_EQ(true, identity.IsIdentity());
+
+ ASSERT_EQ(identity, layer.GetTransform());
+}
+
+TEST(Layers, Type)
+{
+ TestContainerLayer layer(nullptr);
+ ASSERT_EQ(nullptr, layer.AsPaintedLayer());
+ ASSERT_EQ(nullptr, layer.AsRefLayer());
+ ASSERT_EQ(nullptr, layer.AsColorLayer());
+}
+
+TEST(Layers, UserData)
+{
+ UniquePtr<TestContainerLayer> layerPtr(new TestContainerLayer(nullptr));
+ TestContainerLayer& layer = *layerPtr;
+
+ void* key1 = (void*)1;
+ void* key2 = (void*)2;
+ void* key3 = (void*)3;
+
+ ASSERT_EQ(nullptr, layer.GetUserData(key1));
+ ASSERT_EQ(nullptr, layer.GetUserData(key2));
+ ASSERT_EQ(nullptr, layer.GetUserData(key3));
+
+ TestUserData* data1 = new TestUserData;
+ TestUserData* data2 = new TestUserData;
+ TestUserData* data3 = new TestUserData;
+
+ layer.SetUserData(key1, data1);
+ layer.SetUserData(key2, data2);
+ layer.SetUserData(key3, data3);
+
+ // Also checking that the user data is returned but not free'd
+ UniquePtr<LayerUserData> d1(layer.RemoveUserData(key1));
+ UniquePtr<LayerUserData> d2(layer.RemoveUserData(key2));
+ UniquePtr<LayerUserData> d3(layer.RemoveUserData(key3));
+ ASSERT_EQ(data1, d1.get());
+ ASSERT_EQ(data2, d2.get());
+ ASSERT_EQ(data3, d3.get());
+
+ layer.SetUserData(key1, d1.release());
+ layer.SetUserData(key2, d2.release());
+ layer.SetUserData(key3, d3.release());
+
+ // Layer has ownership of data1-3, check that they are destroyed
+ EXPECT_CALL(*data1, Die());
+ EXPECT_CALL(*data2, Die());
+ EXPECT_CALL(*data3, Die());
+}
+
+static already_AddRefed<Layer> CreateLayer(char aLayerType,
+ LayerManager* aManager) {
+ RefPtr<Layer> layer = nullptr;
+ if (aLayerType == 'c') {
+ layer = aManager->CreateContainerLayer();
+ } else if (aLayerType == 't') {
+ layer = aManager->CreatePaintedLayer();
+ } else if (aLayerType == 'o') {
+ layer = aManager->CreateColorLayer();
+ }
+ return layer.forget();
+}
+
+already_AddRefed<Layer> CreateLayerTree(const char* aLayerTreeDescription,
+ nsIntRegion* aVisibleRegions,
+ const Matrix4x4* aTransforms,
+ RefPtr<LayerManager>& manager,
+ nsTArray<RefPtr<Layer> >& aLayersOut) {
+ aLayersOut.Clear();
+
+ if (!manager) {
+ manager = new TestLayerManager();
+ }
+
+ RefPtr<Layer> rootLayer = nullptr;
+ RefPtr<ContainerLayer> parentContainerLayer = nullptr;
+ RefPtr<Layer> lastLayer = nullptr;
+ int layerNumber = 0;
+ for (size_t i = 0; i < strlen(aLayerTreeDescription); i++) {
+ if (aLayerTreeDescription[i] == '(') {
+ if (!lastLayer) {
+ printf(
+ "Syntax error, likely '(' character isn't preceded by a "
+ "container.\n");
+ MOZ_CRASH();
+ }
+ parentContainerLayer = lastLayer->AsContainerLayer();
+ if (!parentContainerLayer) {
+ printf("Layer before '(' must be a container.\n");
+ MOZ_CRASH();
+ }
+ } else if (aLayerTreeDescription[i] == ')') {
+ parentContainerLayer = parentContainerLayer->GetParent();
+ lastLayer = nullptr;
+ } else {
+ RefPtr<Layer> layer =
+ CreateLayer(aLayerTreeDescription[i], manager.get());
+ if (aVisibleRegions) {
+ layer->SetVisibleRegion(
+ LayerIntRegion::FromUnknownRegion(aVisibleRegions[layerNumber]));
+ layer->SetEventRegions(EventRegions(aVisibleRegions[layerNumber]));
+ }
+ if (aTransforms) {
+ layer->SetBaseTransform(aTransforms[layerNumber]);
+ }
+ aLayersOut.AppendElement(layer);
+ layerNumber++;
+ if (rootLayer && !parentContainerLayer) {
+ MOZ_CRASH();
+ }
+ if (!rootLayer) {
+ rootLayer = layer;
+ }
+ if (parentContainerLayer) {
+ parentContainerLayer->InsertAfter(layer,
+ parentContainerLayer->GetLastChild());
+ layer->SetParent(parentContainerLayer);
+ }
+ lastLayer = layer;
+ }
+ }
+ if (rootLayer) {
+ rootLayer->ComputeEffectiveTransforms(Matrix4x4());
+ manager->SetRoot(rootLayer);
+ if (rootLayer->AsHostLayer()) {
+ // Only perform this for LayerManagerComposite
+ CompositorBridgeParent::SetShadowProperties(rootLayer);
+ }
+ }
+ return rootLayer.forget();
+}
+
+TEST(Layers, LayerTree)
+{
+ const char* layerTreeSyntax = "c(c(tt))";
+ nsIntRegion layerVisibleRegion[] = {
+ nsIntRegion(IntRect(0, 0, 100, 100)),
+ nsIntRegion(IntRect(0, 0, 100, 100)),
+ nsIntRegion(IntRect(0, 0, 100, 100)),
+ nsIntRegion(IntRect(10, 10, 20, 20)),
+ };
+ Matrix4x4 transforms[] = {
+ Matrix4x4(),
+ Matrix4x4(),
+ Matrix4x4(),
+ Matrix4x4(),
+ };
+ nsTArray<RefPtr<Layer> > layers;
+
+ RefPtr<LayerManager> lm;
+ RefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion,
+ transforms, lm, layers);
+
+ // B2G g++ doesn't like ASSERT_NE with nullptr directly. It thinks it's
+ // an int.
+ Layer* nullLayer = nullptr;
+ ASSERT_NE(nullLayer, layers[0]->AsContainerLayer());
+ ASSERT_NE(nullLayer, layers[1]->AsContainerLayer());
+ ASSERT_NE(nullLayer, layers[2]->AsPaintedLayer());
+ ASSERT_NE(nullLayer, layers[3]->AsPaintedLayer());
+}
+
+static void ValidateTreePointers(Layer* aLayer) {
+ if (aLayer->GetNextSibling()) {
+ ASSERT_EQ(aLayer, aLayer->GetNextSibling()->GetPrevSibling());
+ } else if (aLayer->GetParent()) {
+ ASSERT_EQ(aLayer, aLayer->GetParent()->GetLastChild());
+ }
+ if (aLayer->GetPrevSibling()) {
+ ASSERT_EQ(aLayer, aLayer->GetPrevSibling()->GetNextSibling());
+ } else if (aLayer->GetParent()) {
+ ASSERT_EQ(aLayer, aLayer->GetParent()->GetFirstChild());
+ }
+ if (aLayer->GetFirstChild()) {
+ ASSERT_EQ(aLayer, aLayer->GetFirstChild()->GetParent());
+ }
+ if (aLayer->GetLastChild()) {
+ ASSERT_EQ(aLayer, aLayer->GetLastChild()->GetParent());
+ }
+}
+
+static void ValidateTreePointers(nsTArray<RefPtr<Layer> >& aLayers) {
+ for (uint32_t i = 0; i < aLayers.Length(); i++) {
+ ValidateTreePointers(aLayers[i]);
+ }
+}
+
+TEST(Layers, RepositionChild)
+{
+ const char* layerTreeSyntax = "c(ttt)";
+
+ nsTArray<RefPtr<Layer> > layers;
+ RefPtr<LayerManager> lm;
+ RefPtr<Layer> root =
+ CreateLayerTree(layerTreeSyntax, nullptr, nullptr, lm, layers);
+ ContainerLayer* parent = root->AsContainerLayer();
+ ValidateTreePointers(layers);
+
+ // tree is currently like this (using indexes into layers):
+ // 0
+ // 1 2 3
+ ASSERT_EQ(layers[2], layers[1]->GetNextSibling());
+ ASSERT_EQ(layers[3], layers[2]->GetNextSibling());
+ ASSERT_EQ(nullptr, layers[3]->GetNextSibling());
+
+ parent->RepositionChild(layers[1], layers[3]);
+ ValidateTreePointers(layers);
+
+ // now the tree is like this:
+ // 0
+ // 2 3 1
+ ASSERT_EQ(layers[3], layers[2]->GetNextSibling());
+ ASSERT_EQ(layers[1], layers[3]->GetNextSibling());
+ ASSERT_EQ(nullptr, layers[1]->GetNextSibling());
+
+ parent->RepositionChild(layers[3], layers[2]);
+ ValidateTreePointers(layers);
+
+ // no change
+ ASSERT_EQ(layers[3], layers[2]->GetNextSibling());
+ ASSERT_EQ(layers[1], layers[3]->GetNextSibling());
+ ASSERT_EQ(nullptr, layers[1]->GetNextSibling());
+
+ parent->RepositionChild(layers[3], layers[1]);
+ ValidateTreePointers(layers);
+
+ // 0
+ // 2 1 3
+ ASSERT_EQ(layers[1], layers[2]->GetNextSibling());
+ ASSERT_EQ(layers[3], layers[1]->GetNextSibling());
+ ASSERT_EQ(nullptr, layers[3]->GetNextSibling());
+
+ parent->RepositionChild(layers[3], nullptr);
+ ValidateTreePointers(layers);
+
+ // 0
+ // 3 2 1
+ ASSERT_EQ(layers[2], layers[3]->GetNextSibling());
+ ASSERT_EQ(layers[1], layers[2]->GetNextSibling());
+ ASSERT_EQ(nullptr, layers[1]->GetNextSibling());
+}
+
+class LayerMetricsWrapperTester : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ // This ensures ScrollMetadata::sNullMetadata is initialized.
+ gfxPlatform::GetPlatform();
+ }
+};
+
+TEST_F(LayerMetricsWrapperTester, SimpleTree) {
+ nsTArray<RefPtr<Layer> > layers;
+ RefPtr<LayerManager> lm;
+ RefPtr<Layer> root =
+ CreateLayerTree("c(c(c(tt)c(t)))", nullptr, nullptr, lm, layers);
+ LayerMetricsWrapper wrapper(root);
+
+ ASSERT_EQ(root.get(), wrapper.GetLayer());
+ wrapper = wrapper.GetFirstChild();
+ ASSERT_EQ(layers[1].get(), wrapper.GetLayer());
+ ASSERT_FALSE(wrapper.GetNextSibling().IsValid());
+ wrapper = wrapper.GetFirstChild();
+ ASSERT_EQ(layers[2].get(), wrapper.GetLayer());
+ wrapper = wrapper.GetFirstChild();
+ ASSERT_EQ(layers[3].get(), wrapper.GetLayer());
+ ASSERT_FALSE(wrapper.GetFirstChild().IsValid());
+ wrapper = wrapper.GetNextSibling();
+ ASSERT_EQ(layers[4].get(), wrapper.GetLayer());
+ ASSERT_FALSE(wrapper.GetNextSibling().IsValid());
+ wrapper = wrapper.GetParent();
+ ASSERT_EQ(layers[2].get(), wrapper.GetLayer());
+ wrapper = wrapper.GetNextSibling();
+ ASSERT_EQ(layers[5].get(), wrapper.GetLayer());
+ ASSERT_FALSE(wrapper.GetNextSibling().IsValid());
+ wrapper = wrapper.GetLastChild();
+ ASSERT_EQ(layers[6].get(), wrapper.GetLayer());
+ wrapper = wrapper.GetParent();
+ ASSERT_EQ(layers[5].get(), wrapper.GetLayer());
+ LayerMetricsWrapper layer5 = wrapper;
+ wrapper = wrapper.GetPrevSibling();
+ ASSERT_EQ(layers[2].get(), wrapper.GetLayer());
+ wrapper = wrapper.GetParent();
+ ASSERT_EQ(layers[1].get(), wrapper.GetLayer());
+ ASSERT_TRUE(layer5 == wrapper.GetLastChild());
+ LayerMetricsWrapper rootWrapper(root);
+ ASSERT_TRUE(rootWrapper == wrapper.GetParent());
+}
+
+static ScrollMetadata MakeMetadata(ScrollableLayerGuid::ViewID aId) {
+ ScrollMetadata metadata;
+ metadata.GetMetrics().SetScrollId(aId);
+ return metadata;
+}
+
+TEST_F(LayerMetricsWrapperTester, MultiFramemetricsTree) {
+ nsTArray<RefPtr<Layer> > layers;
+ RefPtr<LayerManager> lm;
+ RefPtr<Layer> root =
+ CreateLayerTree("c(c(c(tt)c(t)))", nullptr, nullptr, lm, layers);
+
+ nsTArray<ScrollMetadata> metadata;
+ metadata.InsertElementAt(0,
+ MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID +
+ 0)); // topmost of root layer
+ metadata.InsertElementAt(0,
+ MakeMetadata(ScrollableLayerGuid::NULL_SCROLL_ID));
+ metadata.InsertElementAt(
+ 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 1));
+ metadata.InsertElementAt(
+ 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 2));
+ metadata.InsertElementAt(0,
+ MakeMetadata(ScrollableLayerGuid::NULL_SCROLL_ID));
+ metadata.InsertElementAt(
+ 0, MakeMetadata(
+ ScrollableLayerGuid::NULL_SCROLL_ID)); // bottom of root layer
+ root->SetScrollMetadata(metadata);
+
+ metadata.Clear();
+ metadata.InsertElementAt(
+ 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 3));
+ layers[1]->SetScrollMetadata(metadata);
+
+ metadata.Clear();
+ metadata.InsertElementAt(0,
+ MakeMetadata(ScrollableLayerGuid::NULL_SCROLL_ID));
+ metadata.InsertElementAt(
+ 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 4));
+ layers[2]->SetScrollMetadata(metadata);
+
+ metadata.Clear();
+ metadata.InsertElementAt(
+ 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 5));
+ layers[4]->SetScrollMetadata(metadata);
+
+ metadata.Clear();
+ metadata.InsertElementAt(
+ 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 6));
+ layers[5]->SetScrollMetadata(metadata);
+
+ LayerMetricsWrapper wrapper(root, LayerMetricsWrapper::StartAt::TOP);
+ nsTArray<Layer*> expectedLayers;
+ expectedLayers.AppendElement(layers[0].get());
+ expectedLayers.AppendElement(layers[0].get());
+ expectedLayers.AppendElement(layers[0].get());
+ expectedLayers.AppendElement(layers[0].get());
+ expectedLayers.AppendElement(layers[0].get());
+ expectedLayers.AppendElement(layers[0].get());
+ expectedLayers.AppendElement(layers[1].get());
+ expectedLayers.AppendElement(layers[2].get());
+ expectedLayers.AppendElement(layers[2].get());
+ expectedLayers.AppendElement(layers[3].get());
+ nsTArray<ScrollableLayerGuid::ViewID> expectedIds;
+ expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 0);
+ expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID);
+ expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 1);
+ expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 2);
+ expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID);
+ expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID);
+ expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 3);
+ expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID);
+ expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 4);
+ expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID);
+ for (int i = 0; i < 10; i++) {
+ ASSERT_EQ(expectedLayers[i], wrapper.GetLayer());
+ ASSERT_EQ(expectedIds[i], wrapper.Metrics().GetScrollId());
+ wrapper = wrapper.GetFirstChild();
+ }
+ ASSERT_FALSE(wrapper.IsValid());
+
+ wrapper = LayerMetricsWrapper(root, LayerMetricsWrapper::StartAt::BOTTOM);
+ for (int i = 5; i < 10; i++) {
+ ASSERT_EQ(expectedLayers[i], wrapper.GetLayer());
+ ASSERT_EQ(expectedIds[i], wrapper.Metrics().GetScrollId());
+ wrapper = wrapper.GetFirstChild();
+ }
+ ASSERT_FALSE(wrapper.IsValid());
+
+ wrapper =
+ LayerMetricsWrapper(layers[4], LayerMetricsWrapper::StartAt::BOTTOM);
+ ASSERT_EQ(ScrollableLayerGuid::START_SCROLL_ID + 5,
+ wrapper.Metrics().GetScrollId());
+ wrapper = wrapper.GetParent();
+ ASSERT_EQ(ScrollableLayerGuid::START_SCROLL_ID + 4,
+ wrapper.Metrics().GetScrollId());
+ ASSERT_EQ(layers[2].get(), wrapper.GetLayer());
+ ASSERT_FALSE(wrapper.GetNextSibling().IsValid());
+ wrapper = wrapper.GetParent();
+ ASSERT_EQ(ScrollableLayerGuid::NULL_SCROLL_ID,
+ wrapper.Metrics().GetScrollId());
+ ASSERT_EQ(layers[2].get(), wrapper.GetLayer());
+ wrapper = wrapper.GetNextSibling();
+ ASSERT_EQ(ScrollableLayerGuid::START_SCROLL_ID + 6,
+ wrapper.Metrics().GetScrollId());
+ ASSERT_EQ(layers[5].get(), wrapper.GetLayer());
+}