diff --git a/gfx/2d/UserData.h b/gfx/2d/UserData.h index c9a22534b2d..e803dc04e1e 100644 --- a/gfx/2d/UserData.h +++ b/gfx/2d/UserData.h @@ -73,7 +73,7 @@ public: } /* Retrives the userData for the associated key */ - void *Get(UserDataKey *key) + void *Get(UserDataKey *key) const { for (int i=0; iGetPreXScale(), c->GetPreYScale(), 1.0f); } transform.ScalePost(mPostXScale, mPostYScale, 1.0f); diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 1379aa932c4..de24fe51e33 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -438,7 +438,7 @@ public: * This getter can be used anytime. Ownership is retained by the layer * manager. */ - LayerUserData* GetUserData(void* aKey) + LayerUserData* GetUserData(void* aKey) const { return static_cast(mUserData.Get(static_cast(aKey))); } @@ -895,17 +895,19 @@ public: const nsIntRegion& GetVisibleRegion() { return mVisibleRegion; } ContainerLayer* GetParent() { return mParent; } Layer* GetNextSibling() { return mNextSibling; } + const Layer* GetNextSibling() const { return mNextSibling; } Layer* GetPrevSibling() { return mPrevSibling; } - virtual Layer* GetFirstChild() { return nullptr; } - virtual Layer* GetLastChild() { return nullptr; } - const gfx3DMatrix GetTransform(); - const gfx3DMatrix& GetBaseTransform() { return mTransform; } - float GetPostXScale() { return mPostXScale; } - float GetPostYScale() { return mPostYScale; } + const Layer* GetPrevSibling() const { return mPrevSibling; } + virtual Layer* GetFirstChild() const { return nullptr; } + virtual Layer* GetLastChild() const { return nullptr; } + const gfx3DMatrix GetTransform() const; + const gfx3DMatrix& GetBaseTransform() const { return mTransform; } + float GetPostXScale() const { return mPostXScale; } + float GetPostYScale() const { return mPostYScale; } bool GetIsFixedPosition() { return mIsFixedPosition; } gfxPoint GetFixedPositionAnchor() { return mAnchor; } const gfx::Margin& GetFixedPositionMargins() { return mMargins; } - Layer* GetMaskLayer() { return mMaskLayer; } + Layer* GetMaskLayer() const { return mMaskLayer; } // Note that all lengths in animation data are either in CSS pixels or app // units and must be converted to device pixels by the compositor. @@ -991,7 +993,7 @@ public: * This getter can be used anytime. Ownership is retained by the layer * manager. */ - LayerUserData* GetUserData(void* aKey) + LayerUserData* GetUserData(void* aKey) const { return static_cast(mUserData.Get(static_cast(aKey))); } @@ -1018,6 +1020,7 @@ public: * a ContainerLayer. */ virtual ContainerLayer* AsContainerLayer() { return nullptr; } + virtual const ContainerLayer* AsContainerLayer() const { return nullptr; } /** * Dynamic cast to a RefLayer. Returns null if this is not a @@ -1420,7 +1423,7 @@ public: // and can be used anytime. // A container layer has an APZC only-if GetFrameMetrics().IsScrollable() void SetAsyncPanZoomController(AsyncPanZoomController *controller); - AsyncPanZoomController* GetAsyncPanZoomController(); + AsyncPanZoomController* GetAsyncPanZoomController() const; void SetPreScale(float aXScale, float aYScale) { @@ -1453,14 +1456,15 @@ public: // These getters can be used anytime. virtual ContainerLayer* AsContainerLayer() { return this; } + virtual const ContainerLayer* AsContainerLayer() const { return this; } - virtual Layer* GetFirstChild() { return mFirstChild; } - virtual Layer* GetLastChild() { return mLastChild; } - const FrameMetrics& GetFrameMetrics() { return mFrameMetrics; } - float GetPreXScale() { return mPreXScale; } - float GetPreYScale() { return mPreYScale; } - float GetInheritedXScale() { return mInheritedXScale; } - float GetInheritedYScale() { return mInheritedYScale; } + virtual Layer* GetFirstChild() const { return mFirstChild; } + virtual Layer* GetLastChild() const { return mLastChild; } + const FrameMetrics& GetFrameMetrics() const { return mFrameMetrics; } + float GetPreXScale() const { return mPreXScale; } + float GetPreYScale() const { return mPreYScale; } + float GetInheritedXScale() const { return mInheritedXScale; } + float GetInheritedYScale() const { return mInheritedYScale; } MOZ_LAYER_DECL_NAME("ContainerLayer", TYPE_CONTAINER) diff --git a/gfx/layers/ipc/AsyncPanZoomController.cpp b/gfx/layers/ipc/AsyncPanZoomController.cpp index 4d848cd23e1..1face09e824 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.cpp +++ b/gfx/layers/ipc/AsyncPanZoomController.cpp @@ -185,6 +185,7 @@ AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoCon mDelayPanning(false) { MOZ_ASSERT(NS_IsMainThread()); + MOZ_COUNT_CTOR(AsyncPanZoomController); InitAZPCPrefs(); @@ -206,7 +207,7 @@ AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoCon } AsyncPanZoomController::~AsyncPanZoomController() { - + MOZ_COUNT_DTOR(AsyncPanZoomController); } void @@ -1458,5 +1459,53 @@ void AsyncPanZoomController::SendAsyncScrollEvent() { mGeckoContentController->SendAsyncScrollDOMEvent(contentRect, scrollableSize); } + +static void GetAPZCAtPointOnSubtree(const ContainerLayer& aLayerIn, + const gfxPoint& aPoint, + AsyncPanZoomController** aApzcOut, + LayerIntPoint* aRelativePointOut) +{ + // Making layers const correct is very slow because it requires + // a near clobber of the tree. Once const correct is further along + // remove this cast. + ContainerLayer& aLayer = const_cast(aLayerIn); + gfx3DMatrix transform = aLayer.GetLocalTransform().Inverse(); + gfxPoint layerPoint = transform.Transform(aPoint); + + // iterate over the children first. They are better match then the parent + Layer* currLayer = aLayer.GetLastChild(); + while (currLayer) { + if (currLayer->AsContainerLayer()) { + GetAPZCAtPointOnSubtree(*currLayer->AsContainerLayer(), layerPoint, aApzcOut, aRelativePointOut); + } + if (*aApzcOut) { + return; + } + currLayer = currLayer->GetPrevSibling(); + } + + bool intersect = aLayer.GetVisibleRegion().Contains(nsIntRect(layerPoint.x, layerPoint.y, 1, 1)); + + if (intersect) { + if (aLayer.GetFrameMetrics().IsScrollable()) { + *aApzcOut = aLayer.GetAsyncPanZoomController(); + *aRelativePointOut = LayerIntPoint(NS_lround(layerPoint.x), NS_lround(layerPoint.y)); + } + } + +} + +void AsyncPanZoomController::GetAPZCAtPoint(const ContainerLayer& aLayerTree, + const ScreenIntPoint& aPoint, + AsyncPanZoomController** aApzcOut, + LayerIntPoint* aRelativePointOut) +{ + *aApzcOut = nullptr; + + gfxPoint point(aPoint.x, aPoint.y); + + GetAPZCAtPointOnSubtree(aLayerTree, point, aApzcOut, aRelativePointOut); +} + } } diff --git a/gfx/layers/ipc/AsyncPanZoomController.h b/gfx/layers/ipc/AsyncPanZoomController.h index 9be52bd3bbf..2480e453a5d 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.h +++ b/gfx/layers/ipc/AsyncPanZoomController.h @@ -242,6 +242,17 @@ public: */ static void SetFrameTime(const TimeStamp& aMilliseconds); + /** + * Transform and intersect aPoint with the layer tree returning the appropriate + * AsyncPanZoomController for this point. + * aRelativePointOut Return the point transformed into the layer coordinates + * relative to the scroll origin for this layer. + */ + static void GetAPZCAtPoint(const ContainerLayer& aLayerTree, + const ScreenIntPoint& aPoint, + AsyncPanZoomController** aApzcOut, + LayerIntPoint* aRelativePointOut); + protected: /** * Helper method for touches beginning. Sets everything up for panning and any diff --git a/gfx/tests/gtest/TestAsyncPanZoomController.cpp b/gfx/tests/gtest/TestAsyncPanZoomController.cpp index 89c130f29f3..7d440248cd4 100644 --- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp +++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp @@ -11,6 +11,7 @@ #include "mozilla/layers/LayerManagerComposite.h" #include "mozilla/layers/GeckoContentController.h" #include "Layers.h" +#include "TestLayers.h" using namespace mozilla; using namespace mozilla::gfx; @@ -27,9 +28,9 @@ public: MOCK_METHOD2(PostDelayedTask, void(Task* aTask, int aDelayMs)); }; -class TestContainerLayer : public ContainerLayer { +class TestAPZCContainerLayer : public ContainerLayer { public: - TestContainerLayer() + TestAPZCContainerLayer() : ContainerLayer(nullptr, nullptr) {} void RemoveChild(Layer* aChild) {} @@ -100,7 +101,7 @@ TEST(AsyncPanZoomController, SimpleTransform) { nsRefPtr apzc = new AsyncPanZoomController(mcc); apzc->NotifyLayersUpdated(TestFrameMetrics(), true); - TestContainerLayer layer; + TestAPZCContainerLayer layer; ScreenPoint pointOut; ViewTransform viewTransformOut; apzc->SampleContentTransformForFrame(testStartTime, &layer, &viewTransformOut, pointOut); @@ -123,7 +124,7 @@ TEST(AsyncPanZoomController, Pan) { int time = 0; int touchStart = 50; int touchEnd = 10; - TestContainerLayer layer; + TestAPZCContainerLayer layer; ScreenPoint pointOut; ViewTransform viewTransformOut; @@ -154,7 +155,7 @@ TEST(AsyncPanZoomController, Fling) { int time = 0; int touchStart = 50; int touchEnd = 10; - TestContainerLayer layer; + TestAPZCContainerLayer layer; ScreenPoint pointOut; ViewTransform viewTransformOut; @@ -163,7 +164,6 @@ TEST(AsyncPanZoomController, Fling) { ScreenPoint lastPoint; for (int i = 1; i < 50; i+=1) { apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(i), &layer, &viewTransformOut, pointOut); - printf("Time %f, y position %f\n", (float)i, pointOut.y); EXPECT_GT(pointOut.y, lastPoint.y); lastPoint = pointOut; } @@ -184,7 +184,7 @@ TEST(AsyncPanZoomController, OverScrollPanning) { int time = 0; int touchStart = 500; int touchEnd = 10; - TestContainerLayer layer; + TestAPZCContainerLayer layer; ScreenPoint pointOut; ViewTransform viewTransformOut; @@ -194,3 +194,157 @@ TEST(AsyncPanZoomController, OverScrollPanning) { EXPECT_EQ(pointOut, ScreenPoint(0, 90)); } +static already_AddRefed +CreateTestLayerTree(nsRefPtr& aLayerManager, nsTArray >& aLayers) { + const char* layerTreeSyntax = "c(ttccc(c(c)))"; + // LayerID 0 12345 6 7 + nsIntRegion layerVisibleRegion[] = { + nsIntRegion(nsIntRect(0,0,100,100)), + nsIntRegion(nsIntRect(0,0,100,100)), + nsIntRegion(nsIntRect(10,10,20,20)), + nsIntRegion(nsIntRect(10,10,20,20)), + nsIntRegion(nsIntRect(5,5,20,20)), + nsIntRegion(nsIntRect(10,10,40,40)), + nsIntRegion(nsIntRect(10,10,40,40)), + nsIntRegion(nsIntRect(10,10,40,40)), + }; + gfx3DMatrix transforms[] = { + gfx3DMatrix(), + gfx3DMatrix(), + gfx3DMatrix(), + gfx3DMatrix(), + gfx3DMatrix(), + gfx3DMatrix(), + gfx3DMatrix(), + gfx3DMatrix(), + }; + return CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, aLayerManager, aLayers); +} + +TEST(AsyncPanZoomController, GetAPZCAtPoint) { + nsTArray > layers; + nsRefPtr lm; + nsRefPtr root = CreateTestLayerTree(lm, layers); + + TimeStamp testStartTime = TimeStamp::Now(); + AsyncPanZoomController::SetFrameTime(testStartTime); + + nsRefPtr mcc = new MockContentController(); + nsRefPtr apzcMain = new AsyncPanZoomController(mcc); + nsRefPtr apzcSub3 = new AsyncPanZoomController(mcc); + nsRefPtr apzcSub4 = new AsyncPanZoomController(mcc); + nsRefPtr apzcSub7 = new AsyncPanZoomController(mcc); + apzcMain->NotifyLayersUpdated(TestFrameMetrics(), true); + + ScreenIntPoint touchPoint(20, 20); + AsyncPanZoomController* apzcOut; + LayerIntPoint relativePointOut; + + FrameMetrics scrollable; + + // No APZC attached so hit testing will return no APZC at (20,20) + AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint, + &apzcOut, &relativePointOut); + + AsyncPanZoomController* nullAPZC = nullptr; + EXPECT_EQ(apzcOut, nullAPZC); + + // Now we have a root APZC that will match the page + scrollable.mScrollId = FrameMetrics::ROOT_SCROLL_ID; + root->AsContainerLayer()->SetFrameMetrics(scrollable); + root->AsContainerLayer()->SetAsyncPanZoomController(apzcMain); + AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint, + &apzcOut, &relativePointOut); + EXPECT_EQ(apzcOut, apzcMain.get()); + EXPECT_EQ(LayerIntPoint(20, 20), relativePointOut); + + // Now we have a sub APZC with a better fit + scrollable.mScrollId = FrameMetrics::START_SCROLL_ID; + layers[3]->AsContainerLayer()->SetFrameMetrics(scrollable); + layers[3]->AsContainerLayer()->SetAsyncPanZoomController(apzcSub3); + AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint, + &apzcOut, &relativePointOut); + EXPECT_EQ(apzcOut, apzcSub3.get()); + EXPECT_EQ(LayerIntPoint(20, 20), relativePointOut); + + // Now test hit testing when we have two scrollable layers + touchPoint = ScreenIntPoint(15,15); + AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint, + &apzcOut, &relativePointOut); + EXPECT_EQ(apzcOut, apzcSub3.get()); // We haven't bound apzcSub4 yet + scrollable.mScrollId++; + layers[4]->AsContainerLayer()->SetFrameMetrics(scrollable); + layers[4]->AsContainerLayer()->SetAsyncPanZoomController(apzcSub4); + AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint, + &apzcOut, &relativePointOut); + EXPECT_EQ(apzcOut, apzcSub4.get()); + EXPECT_EQ(LayerIntPoint(15, 15), relativePointOut); + + // Hit test ouside the reach of apzc3/4 but inside apzcMain + touchPoint = ScreenIntPoint(90,90); + AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint, + &apzcOut, &relativePointOut); + EXPECT_EQ(apzcOut, apzcMain.get()); + EXPECT_EQ(LayerIntPoint(90, 90), relativePointOut); + + // Hit test ouside the reach of any layer + touchPoint = ScreenIntPoint(1000,10); + AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint, + &apzcOut, &relativePointOut); + EXPECT_EQ(apzcOut, nullAPZC); + touchPoint = ScreenIntPoint(-1000,10); + AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint, + &apzcOut, &relativePointOut); + EXPECT_EQ(apzcOut, nullAPZC); + + // Test layer transform + gfx3DMatrix transform; + transform.ScalePost(0.1, 0.1, 1); + root->SetBaseTransform(transform); + + touchPoint = ScreenIntPoint(50,50); // This point is now outside the root layer + AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint, + &apzcOut, &relativePointOut); + EXPECT_EQ(apzcOut, nullAPZC); + + touchPoint = ScreenIntPoint(2,2); + AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint, + &apzcOut, &relativePointOut); + EXPECT_EQ(apzcOut, apzcSub4.get()); + EXPECT_EQ(LayerIntPoint(20, 20), relativePointOut); + + // Scale layer[4] outside the range + layers[4]->SetBaseTransform(transform); + // layer 4 effective visible screenrect: (0.05, 0.05, 0.2, 0.2) + // Does not contain (2, 2) + AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint, + &apzcOut, &relativePointOut); + EXPECT_EQ(apzcOut, apzcSub3.get()); + EXPECT_EQ(LayerIntPoint(20, 20), relativePointOut); + + // Transformation chain to layer 7 + scrollable.mScrollId++; + layers[7]->AsContainerLayer()->SetFrameMetrics(scrollable); + layers[7]->AsContainerLayer()->SetAsyncPanZoomController(apzcSub7); + + gfx3DMatrix translateTransform; + translateTransform.Translate(gfxPoint3D(10, 10, 0)); + layers[5]->SetBaseTransform(translateTransform); + + gfx3DMatrix translateTransform2; + translateTransform2.Translate(gfxPoint3D(-20, 0, 0)); + layers[6]->SetBaseTransform(translateTransform2); + + gfx3DMatrix translateTransform3; + translateTransform3.ScalePost(1,15,1); + layers[7]->SetBaseTransform(translateTransform3); + + touchPoint = ScreenIntPoint(1,45); + // layer 7 effective visible screenrect (0,16,4,60) but clipped by parent layers + AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint, + &apzcOut, &relativePointOut); + EXPECT_EQ(apzcOut, apzcSub7.get()); + EXPECT_EQ(LayerIntPoint(20, 29), relativePointOut); +} + + diff --git a/gfx/tests/gtest/TestLayers.cpp b/gfx/tests/gtest/TestLayers.cpp index 24eabbb834f..bd1c5cb327c 100644 --- a/gfx/tests/gtest/TestLayers.cpp +++ b/gfx/tests/gtest/TestLayers.cpp @@ -3,21 +3,44 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +#include "TestLayers.h" #include "gtest/gtest.h" #include "gmock/gmock.h" -#include "Layers.h" using namespace mozilla; using namespace mozilla::layers; -class TestLayer: public Layer { +class TestLayerManager: public LayerManager { public: - TestLayer(LayerManager* aManager) - : Layer(aManager, nullptr) + TestLayerManager() + : LayerManager() + {} + + virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) { return false; } + virtual already_AddRefed CreateContainerLayer() { return nullptr; } + virtual void GetBackendName(nsAString& aName) {} + virtual LayersBackend GetBackendType() { return LAYERS_BASIC; } + virtual void BeginTransaction() {} + virtual already_AddRefed CreateImageLayer() { return nullptr; } + virtual void SetRoot(Layer* aLayer) {} + virtual already_AddRefed CreateColorLayer() { return nullptr; } + virtual void BeginTransactionWithTarget(gfxContext* aTarget) {} + virtual already_AddRefed CreateCanvasLayer() { return nullptr; } + virtual void EndTransaction(DrawThebesLayerCallback aCallback, + void* aCallbackData, + EndTransactionFlags aFlags = END_DEFAULT) {} + virtual int32_t GetMaxTextureSize() const { return 0; } + virtual already_AddRefed CreateThebesLayer() { return nullptr; } +}; + +class TestContainerLayer: public ContainerLayer { +public: + TestContainerLayer(LayerManager* aManager) + : ContainerLayer(aManager, nullptr) {} virtual const char* Name() const { - return "TestLayer"; + return "TestContainerLayer"; } virtual LayerType GetType() const { @@ -25,6 +48,55 @@ public: } virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) { + } + + virtual void RepositionChild(Layer* aChild, Layer* aAfter) { + MOZ_CRASH(); + } + + virtual void InsertAfter(Layer* aChild, Layer* aAfter) { + // Bad implementation but it should be fine for testing + if (this == aChild) { + MOZ_CRASH(); + } + if (aAfter != nullptr && aAfter != mLastChild) { + // Fix the implementation to support this if you need it + MOZ_CRASH(); + } + if (!mFirstChild) { + mFirstChild = aChild; + } + if (mLastChild) { + mLastChild->SetNextSibling(aChild); + } + aChild->SetPrevSibling(mLastChild); + mLastChild = aChild; + } + + virtual void RemoveChild(Layer* aChild) { + MOZ_CRASH(); + } +}; + +class TestThebesLayer: public ThebesLayer { +public: + TestThebesLayer(LayerManager* aManager) + : ThebesLayer(aManager, nullptr) + {} + + virtual const char* Name() const { + return "TestThebesLayer"; + } + + virtual LayerType GetType() const { + return TYPE_THEBES; + } + + virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) { + MOZ_CRASH(); + } + + virtual void InvalidateRegion(const nsIntRegion& aRegion) { MOZ_CRASH(); } }; @@ -37,11 +109,11 @@ public: TEST(Layers, LayerConstructor) { - TestLayer layer(nullptr); + TestContainerLayer layer(nullptr); } TEST(Layers, Defaults) { - TestLayer layer(nullptr); + TestContainerLayer layer(nullptr); ASSERT_EQ(1.0, layer.GetOpacity()); ASSERT_EQ(1.0f, layer.GetPostXScale()); ASSERT_EQ(1.0f, layer.GetPostYScale()); @@ -53,7 +125,7 @@ TEST(Layers, Defaults) { } TEST(Layers, Transform) { - TestLayer layer(nullptr); + TestContainerLayer layer(nullptr); gfx3DMatrix identity; ASSERT_EQ(true, identity.IsIdentity()); @@ -62,15 +134,15 @@ TEST(Layers, Transform) { } TEST(Layers, Type) { - TestLayer layer(nullptr); + TestContainerLayer layer(nullptr); ASSERT_EQ(nullptr, layer.AsThebesLayer()); ASSERT_EQ(nullptr, layer.AsRefLayer()); ASSERT_EQ(nullptr, layer.AsColorLayer()); } TEST(Layers, UserData) { - TestLayer* layerPtr = new TestLayer(nullptr); - TestLayer& layer = *layerPtr; + TestContainerLayer* layerPtr = new TestContainerLayer(nullptr); + TestContainerLayer& layer = *layerPtr; void* key1 = (void*)1; void* key2 = (void*)2; @@ -105,3 +177,93 @@ TEST(Layers, UserData) { } +static +already_AddRefed CreateLayer(char aLayerType, LayerManager* aManager) { + nsRefPtr layer = nullptr; + if (aLayerType == 'c') { + layer = new TestContainerLayer(aManager); + } else if (aLayerType == 't') { + layer = new TestThebesLayer(aManager); + } + return layer.forget(); +} + +already_AddRefed CreateLayerTree( + const char* aLayerTreeDescription, + nsIntRegion* aVisibleRegions, + const gfx3DMatrix* aTransforms, + nsRefPtr& manager, + nsTArray >& aLayersOut) { + + aLayersOut.Clear(); + + manager = new TestLayerManager(); + + nsRefPtr rootLayer = nullptr; + nsRefPtr parentContainerLayer = nullptr; + nsRefPtr 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 { + nsRefPtr layer = CreateLayer(aLayerTreeDescription[i], manager.get()); + layer->SetVisibleRegion(aVisibleRegions[layerNumber]); + layer->SetBaseTransform(aTransforms[layerNumber]); + aLayersOut.AppendElement(layer); + layerNumber++; + if (rootLayer && !parentContainerLayer) { + MOZ_CRASH(); + } + if (!rootLayer) { + rootLayer = layer; + } + if (parentContainerLayer) { + parentContainerLayer->InsertAfter(layer, nullptr); + layer->SetParent(parentContainerLayer); + } + lastLayer = layer; + } + } + return rootLayer.forget(); +} + +TEST(Layers, LayerTree) { + const char* layerTreeSyntax = "c(c(tt))"; + nsIntRegion layerVisibleRegion[] = { + nsIntRegion(nsIntRect(0,0,100,100)), + nsIntRegion(nsIntRect(0,0,100,100)), + nsIntRegion(nsIntRect(0,0,100,100)), + nsIntRegion(nsIntRect(10,10,20,20)), + }; + gfx3DMatrix transforms[] = { + gfx3DMatrix(), + gfx3DMatrix(), + gfx3DMatrix(), + gfx3DMatrix(), + }; + nsTArray > layers; + + nsRefPtr lm; + nsRefPtr 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]->AsThebesLayer()); + ASSERT_NE(nullLayer, layers[3]->AsThebesLayer()); +} + diff --git a/gfx/tests/gtest/TestLayers.h b/gfx/tests/gtest/TestLayers.h new file mode 100644 index 00000000000..18afea8c59a --- /dev/null +++ b/gfx/tests/gtest/TestLayers.h @@ -0,0 +1,35 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +#ifndef GFX_TEST_LAYERS_H +#define GFX_TEST_LAYERS_H + +#include "Layers.h" +#include "nsTArray.h" + +// Create layer tree from a simple layer tree description syntax. +// Each index is either the first letter of the layer type or +// a '(',')' to indicate the start/end of the child layers. +// The aim of this function is to remove hard to read +// layer tree creation code. +// +// Example "c(c(c(tt)t))" would yield: +// c +// | +// c +// / \ +// c t +// / \ +// t t +already_AddRefed CreateLayerTree( + const char* aLayerTreeDescription, + nsIntRegion* aVisibleRegions, + const gfx3DMatrix* aTransforms, + nsRefPtr& aLayerManager, + nsTArray >& aLayersOut); + + +#endif + diff --git a/testing/gtest/mozilla/GTestRunner.cpp b/testing/gtest/mozilla/GTestRunner.cpp index 6fd15d6d1be..ac9a77197f4 100644 --- a/testing/gtest/mozilla/GTestRunner.cpp +++ b/testing/gtest/mozilla/GTestRunner.cpp @@ -43,7 +43,7 @@ public: } virtual void OnTestPartResult(const TestPartResult& aTestPartResult) MOZ_OVERRIDE { printf("TEST-%s | %s.%s | %s @ %s:%i\n", - aTestPartResult.failed() ? "PASS" : "UNEXPECTED-FAIL", + !aTestPartResult.failed() ? "PASS" : "UNEXPECTED-FAIL", mTestInfo->test_case_name(), mTestInfo->name(), aTestPartResult.summary(), aTestPartResult.file_name(), aTestPartResult.line_number());