From a62d23f5c0f8f6e29bf4cb7e8c142f54bacd39e8 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Tue, 30 Jul 2013 14:03:41 -0400 Subject: [PATCH] Bug 866232 - Update and re-enable the test for hit detection in the APZC tree. r=BenWa --- gfx/layers/composite/APZCTreeManager.cpp | 8 +- gfx/layers/composite/APZCTreeManager.h | 16 +- gfx/layers/ipc/CompositorParent.cpp | 14 + gfx/layers/ipc/CompositorParent.h | 11 + .../gtest/TestAsyncPanZoomController.cpp | 263 +++++++++--------- gfx/tests/gtest/TestLayers.cpp | 8 +- 6 files changed, 174 insertions(+), 146 deletions(-) diff --git a/gfx/layers/composite/APZCTreeManager.cpp b/gfx/layers/composite/APZCTreeManager.cpp index 328455025809..6d18f0b5a449 100644 --- a/gfx/layers/composite/APZCTreeManager.cpp +++ b/gfx/layers/composite/APZCTreeManager.cpp @@ -21,6 +21,12 @@ APZCTreeManager::APZCTreeManager() AsyncPanZoomController::InitializeGlobalState(); } +void +APZCTreeManager::AssertOnCompositorThread() +{ + Compositor::AssertOnCompositorThread(); +} + /* Flatten the tree of APZC instances into the given nsTArray */ static void Collect(AsyncPanZoomController* aApzc, nsTArray< nsRefPtr >* aCollection) @@ -36,7 +42,7 @@ void APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor, Layer* aRoot, bool aIsFirstPaint, uint64_t aFirstPaintLayersId) { - Compositor::AssertOnCompositorThread(); + AssertOnCompositorThread(); MonitorAutoLock lock(mTreeLock); diff --git a/gfx/layers/composite/APZCTreeManager.h b/gfx/layers/composite/APZCTreeManager.h index 32540ee1b872..de8c55b4221d 100644 --- a/gfx/layers/composite/APZCTreeManager.h +++ b/gfx/layers/composite/APZCTreeManager.h @@ -96,11 +96,12 @@ struct ScrollableLayerGuid { * Note that the ClearTree function MUST be called when this class is no longer needed; * see the method documentation for details. */ -class APZCTreeManager MOZ_FINAL { +class APZCTreeManager { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(APZCTreeManager) public: APZCTreeManager(); + virtual ~APZCTreeManager() {} /** * Rebuild the APZC tree based on the layer update that just came up. Preserve @@ -220,14 +221,23 @@ public: */ void ClearTree(); -private: +protected: + /** + * Debug-build assertion that can be called to ensure code is running on the + * compositor thread. + */ + virtual void AssertOnCompositorThread(); + +public: /* Some helper functions to find an APZC given some identifying input. These functions lock the tree of APZCs while they find the right one, and then return an addref'd pointer to it. This allows caller code to just use the target APZC without worrying - about it going away. + about it going away. These are public for testing code and generally should not be + used by other production code. */ already_AddRefed GetTargetAPZC(const ScrollableLayerGuid& aGuid); already_AddRefed GetTargetAPZC(const ScreenPoint& aPoint); +private: /* Recursive helpers */ AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid); AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, gfxPoint aHitTestPoint); diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 04d5552f1503..05a7eb207c92 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -746,6 +746,20 @@ UpdateControllerForLayersId(uint64_t aLayersId, already_AddRefed(aController); } +ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(uint64_t aLayersId, + Layer* aRoot, + GeckoContentController* aController) + : mLayersId(aLayersId) +{ + sIndirectLayerTrees[aLayersId].mRoot = aRoot; + sIndirectLayerTrees[aLayersId].mController = aController; +} + +ScopedLayerTreeRegistration::~ScopedLayerTreeRegistration() +{ + sIndirectLayerTrees.erase(mLayersId); +} + /*static*/ void CompositorParent::SetControllerForLayerTree(uint64_t aLayersId, GeckoContentController* aController) diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index 4959f24dc5f3..0522fbe44146 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -38,6 +38,17 @@ class LayerManagerComposite; class AsyncCompositionManager; struct TextureFactoryIdentifier; +struct ScopedLayerTreeRegistration +{ + ScopedLayerTreeRegistration(uint64_t aLayersId, + Layer* aRoot, + GeckoContentController* aController); + ~ScopedLayerTreeRegistration(); + +private: + uint64_t mLayersId; +}; + class CompositorParent : public PCompositorParent, public ShadowLayersManager { diff --git a/gfx/tests/gtest/TestAsyncPanZoomController.cpp b/gfx/tests/gtest/TestAsyncPanZoomController.cpp index 0451682822a8..9fed66b0175d 100644 --- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp +++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp @@ -10,6 +10,8 @@ #include "mozilla/layers/AsyncPanZoomController.h" #include "mozilla/layers/LayerManagerComposite.h" #include "mozilla/layers/GeckoContentController.h" +#include "mozilla/layers/CompositorParent.h" +#include "mozilla/layers/APZCTreeManager.h" #include "Layers.h" #include "TestLayers.h" @@ -51,6 +53,11 @@ public: } }; +class TestAPZCTreeManager : public APZCTreeManager { +protected: + void AssertOnCompositorThread() MOZ_OVERRIDE { /* no-op */ } +}; + static FrameMetrics TestFrameMetrics() { FrameMetrics fm; @@ -339,143 +346,123 @@ CreateTestLayerTree(nsRefPtr& aLayerManager, 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); -// -// nsIntRect layerBound; -// 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; -// layerBound = root->GetVisibleRegion().GetBounds(); -// scrollable.mViewport = CSSRect(layerBound.x, layerBound.y, -// layerBound.width, layerBound.height); -// 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; -// layerBound = layers[3]->GetVisibleRegion().GetBounds(); -// scrollable.mViewport = CSSRect(layerBound.x, layerBound.y, -// layerBound.width, layerBound.height); -// 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++; -// layerBound = layers[4]->GetVisibleRegion().GetBounds(); -// scrollable.mViewport = CSSRect(layerBound.x, layerBound.y, -// layerBound.width, layerBound.height); -// 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++; -// layerBound = layers[7]->GetVisibleRegion().GetBounds(); -// scrollable.mViewport = CSSRect(layerBound.x, layerBound.y, -// layerBound.width, layerBound.height); -// 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); -//} +static void +SetScrollableFrameMetrics(Layer* aLayer, FrameMetrics::ViewID aScrollId, MockContentController* mcc) +{ + ContainerLayer* container = aLayer->AsContainerLayer(); + FrameMetrics metrics; + metrics.mScrollId = aScrollId; + nsIntRect layerBound = aLayer->GetVisibleRegion().GetBounds(); + metrics.mCompositionBounds = ScreenIntRect(layerBound.x, layerBound.y, + layerBound.width, layerBound.height); + metrics.mViewport = CSSRect(layerBound.x, layerBound.y, + layerBound.width, layerBound.height); + container->SetFrameMetrics(metrics); + + // when we do the next tree update, a new APZC will be created for this layer, + // and that will invoke these functions once. + EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_)).Times(1); + EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1); +} + +TEST(APZCTreeManager, GetAPZCAtPoint) { + nsTArray > layers; + nsRefPtr lm; + nsRefPtr root = CreateTestLayerTree(lm, layers); + + TimeStamp testStartTime = TimeStamp::Now(); + AsyncPanZoomController::SetFrameTime(testStartTime); + nsRefPtr mcc = new MockContentController(); + ScopedLayerTreeRegistration controller(CompositorParent::ROOT_LAYER_TREE_ID, root, mcc); + + nsRefPtr manager = new TestAPZCTreeManager(); + + // No APZC attached so hit testing will return no APZC at (20,20) + nsRefPtr hit = manager->GetTargetAPZC(ScreenPoint(20, 20)); + AsyncPanZoomController* nullAPZC = nullptr; + EXPECT_EQ(nullAPZC, hit.get()); + + // Now we have a root APZC that will match the page + SetScrollableFrameMetrics(root, FrameMetrics::ROOT_SCROLL_ID, mcc); + manager->UpdatePanZoomControllerTree(nullptr, root, CompositorParent::ROOT_LAYER_TREE_ID, false); + hit = manager->GetTargetAPZC(ScreenPoint(15, 15)); + EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get()); + // expect hit point at LayerIntPoint(15, 15) + + // Now we have a sub APZC with a better fit + SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID, mcc); + manager->UpdatePanZoomControllerTree(nullptr, root, CompositorParent::ROOT_LAYER_TREE_ID, false); + EXPECT_NE(root->AsContainerLayer()->GetAsyncPanZoomController(), layers[3]->AsContainerLayer()->GetAsyncPanZoomController()); + hit = manager->GetTargetAPZC(ScreenPoint(15, 15)); + EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get()); + // expect hit point at LayerIntPoint(15, 15) + + // Now test hit testing when we have two scrollable layers + hit = manager->GetTargetAPZC(ScreenPoint(15, 15)); + EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get()); + SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 1, mcc); + manager->UpdatePanZoomControllerTree(nullptr, root, CompositorParent::ROOT_LAYER_TREE_ID, false); + hit = manager->GetTargetAPZC(ScreenPoint(15, 15)); + EXPECT_EQ(layers[4]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get()); + // expect hit point at LayerIntPoint(15, 15) + + // Hit test ouside the reach of layer[3,4] but inside root + hit = manager->GetTargetAPZC(ScreenPoint(90, 90)); + EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get()); + // expect hit point at LayerIntPoint(90, 90) + + // Hit test ouside the reach of any layer + hit = manager->GetTargetAPZC(ScreenPoint(1000, 10)); + EXPECT_EQ(nullAPZC, hit.get()); + hit = manager->GetTargetAPZC(ScreenPoint(-1000, 10)); + EXPECT_EQ(nullAPZC, hit.get()); + + // Test layer transform + gfx3DMatrix transform; + transform.ScalePost(0.1, 0.1, 1); + root->SetBaseTransform(transform); + root->ComputeEffectiveTransforms(gfx3DMatrix()); + manager->UpdatePanZoomControllerTree(nullptr, root, CompositorParent::ROOT_LAYER_TREE_ID, false); + hit = manager->GetTargetAPZC(ScreenPoint(50, 50)); // This point is now outside the root layer + EXPECT_EQ(nullAPZC, hit.get()); + + hit = manager->GetTargetAPZC(ScreenPoint(2, 2)); + EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get()); + // expect hit point at LayerPoint(20, 20) + + // 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) + root->ComputeEffectiveTransforms(gfx3DMatrix()); + manager->UpdatePanZoomControllerTree(nullptr, root, CompositorParent::ROOT_LAYER_TREE_ID, false); + hit = manager->GetTargetAPZC(ScreenPoint(2, 2)); + EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get()); + // expect hit point at LayerPoint(20, 20) + + // Transformation chain to layer 7 + SetScrollableFrameMetrics(layers[7], FrameMetrics::START_SCROLL_ID + 2, mcc); + + 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); + + root->ComputeEffectiveTransforms(gfx3DMatrix()); + manager->UpdatePanZoomControllerTree(nullptr, root, CompositorParent::ROOT_LAYER_TREE_ID, false); + // layer 7 effective visible screenrect (0,16,4,60) but clipped by parent layers + hit = manager->GetTargetAPZC(ScreenPoint(1, 45)); + EXPECT_EQ(layers[7]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get()); + // expect hit point at LayerPoint(20, 29) + + manager->ClearTree(); +} diff --git a/gfx/tests/gtest/TestLayers.cpp b/gfx/tests/gtest/TestLayers.cpp index bd1c5cb327cc..c1364f069354 100644 --- a/gfx/tests/gtest/TestLayers.cpp +++ b/gfx/tests/gtest/TestLayers.cpp @@ -48,6 +48,7 @@ public: } virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) { + DefaultComputeEffectiveTransforms(aTransformToSurface); } virtual void RepositionChild(Layer* aChild, Layer* aAfter) { @@ -92,10 +93,6 @@ public: return TYPE_THEBES; } - virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) { - MOZ_CRASH(); - } - virtual void InvalidateRegion(const nsIntRegion& aRegion) { MOZ_CRASH(); } @@ -236,6 +233,9 @@ already_AddRefed CreateLayerTree( lastLayer = layer; } } + if (rootLayer) { + rootLayer->ComputeEffectiveTransforms(gfx3DMatrix()); + } return rootLayer.forget(); }