Bug 866232 - Update and re-enable the test for hit detection in the APZC tree. r=BenWa

This commit is contained in:
Kartikaya Gupta 2013-07-30 14:03:41 -04:00
parent c40b9b29dd
commit a62d23f5c0
6 changed files with 174 additions and 146 deletions

View File

@ -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<AsyncPanZoomController> >* aCollection)
@ -36,7 +42,7 @@ void
APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor, Layer* aRoot,
bool aIsFirstPaint, uint64_t aFirstPaintLayersId)
{
Compositor::AssertOnCompositorThread();
AssertOnCompositorThread();
MonitorAutoLock lock(mTreeLock);

View File

@ -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<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint);
private:
/* Recursive helpers */
AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, gfxPoint aHitTestPoint);

View File

@ -746,6 +746,20 @@ UpdateControllerForLayersId(uint64_t aLayersId,
already_AddRefed<GeckoContentController>(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)

View File

@ -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
{

View File

@ -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<LayerManager>& aLayerManager, nsTArray<nsRefPtr<Lay
return CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, aLayerManager, aLayers);
}
//TEST(AsyncPanZoomController, GetAPZCAtPoint) {
// nsTArray<nsRefPtr<Layer> > layers;
// nsRefPtr<LayerManager> lm;
// nsRefPtr<Layer> root = CreateTestLayerTree(lm, layers);
//
// TimeStamp testStartTime = TimeStamp::Now();
// AsyncPanZoomController::SetFrameTime(testStartTime);
//
// nsRefPtr<MockContentController> mcc = new MockContentController();
// nsRefPtr<AsyncPanZoomController> apzcMain = new AsyncPanZoomController(mcc);
// nsRefPtr<AsyncPanZoomController> apzcSub3 = new AsyncPanZoomController(mcc);
// nsRefPtr<AsyncPanZoomController> apzcSub4 = new AsyncPanZoomController(mcc);
// nsRefPtr<AsyncPanZoomController> 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<nsRefPtr<Layer> > layers;
nsRefPtr<LayerManager> lm;
nsRefPtr<Layer> root = CreateTestLayerTree(lm, layers);
TimeStamp testStartTime = TimeStamp::Now();
AsyncPanZoomController::SetFrameTime(testStartTime);
nsRefPtr<MockContentController> mcc = new MockContentController();
ScopedLayerTreeRegistration controller(CompositorParent::ROOT_LAYER_TREE_ID, root, mcc);
nsRefPtr<APZCTreeManager> manager = new TestAPZCTreeManager();
// No APZC attached so hit testing will return no APZC at (20,20)
nsRefPtr<AsyncPanZoomController> 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();
}

View File

@ -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<Layer> CreateLayerTree(
lastLayer = layer;
}
}
if (rootLayer) {
rootLayer->ComputeEffectiveTransforms(gfx3DMatrix());
}
return rootLayer.forget();
}