Bug 890280 - Apply proper transformations when sending inputs to the APZC and back to the DOM. r=BenWa

This commit is contained in:
Kartikaya Gupta 2013-08-14 10:15:54 -04:00
Родитель 571e6a0e9c
Коммит 9dd2faacc5
5 изменённых файлов: 221 добавлений и 117 удалений

Просмотреть файл

@ -87,9 +87,6 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
bool aIsFirstPaint, uint64_t aFirstPaintLayersId,
nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy)
{
// Accumulate the CSS transform between layers that have an APZC
aTransform = aTransform * aLayer->GetTransform();
ContainerLayer* container = aLayer->AsContainerLayer();
AsyncPanZoomController* controller = nullptr;
if (container) {
@ -121,9 +118,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
aIsFirstPaint && (aLayersId == aFirstPaintLayersId));
LayerRect visible = container->GetFrameMetrics().mViewport * container->GetFrameMetrics().LayersPixelsPerCSSPixel();
controller->SetLayerHitTestData(visible, aTransform);
// Reset the accumulated transform once we hit a layer with an APZC
aTransform = gfx3DMatrix();
controller->SetLayerHitTestData(visible, aTransform, aLayer->GetTransform());
APZC_LOG("Setting rect(%f %f %f %f) as visible region for APZC %p\n", visible.x, visible.y,
visible.width, visible.height,
controller);
@ -145,6 +140,15 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
container->SetAsyncPanZoomController(controller);
}
// Accumulate the CSS transform between layers that have an APZC, but exclude any
// any layers that do have an APZC, and reset the accumulation at those layers.
if (controller) {
aTransform = gfx3DMatrix();
} else {
// Multiply child layer transforms on the left so they get applied first
aTransform = aLayer->GetTransform() * aTransform;
}
uint64_t childLayersId = (aLayer->AsRefLayer() ? aLayer->AsRefLayer()->GetReferentId() : aLayersId);
AsyncPanZoomController* next = nullptr;
for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
@ -165,31 +169,69 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
return aNextSibling;
}
/*static*/ template<class T> void
ApplyTransform(gfx::PointTyped<T>* aPoint, const gfx3DMatrix& aMatrix)
{
gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
aPoint->x = result.x;
aPoint->y = result.y;
}
/*static*/ template<class T> void
ApplyTransform(gfx::IntPointTyped<T>* aPoint, const gfx3DMatrix& aMatrix)
{
gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
aPoint->x = NS_lround(result.x);
aPoint->y = NS_lround(result.y);
}
/*static*/ void
ApplyTransform(nsIntPoint* aPoint, const gfx3DMatrix& aMatrix)
{
gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
aPoint->x = NS_lround(result.x);
aPoint->y = NS_lround(result.y);
}
nsEventStatus
APZCTreeManager::ReceiveInputEvent(const InputData& aEvent)
{
nsRefPtr<AsyncPanZoomController> apzc;
gfx3DMatrix transformToApzc;
gfx3DMatrix transformToScreen;
switch (aEvent.mInputType) {
case MULTITOUCH_INPUT: {
const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput();
apzc = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint));
apzc = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint),
transformToApzc, transformToScreen);
if (apzc) {
MultiTouchInput inputForApzc(multiTouchInput);
for (int i = inputForApzc.mTouches.Length() - 1; i >= 0; i--) {
ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
}
apzc->ReceiveInputEvent(inputForApzc);
}
break;
} case PINCHGESTURE_INPUT: {
const PinchGestureInput& pinchInput = aEvent.AsPinchGestureInput();
apzc = GetTargetAPZC(pinchInput.mFocusPoint);
apzc = GetTargetAPZC(pinchInput.mFocusPoint, transformToApzc, transformToScreen);
if (apzc) {
PinchGestureInput inputForApzc(pinchInput);
ApplyTransform(&(inputForApzc.mFocusPoint), transformToApzc);
apzc->ReceiveInputEvent(inputForApzc);
}
break;
} case TAPGESTURE_INPUT: {
const TapGestureInput& tapInput = aEvent.AsTapGestureInput();
apzc = GetTargetAPZC(ScreenPoint(tapInput.mPoint));
break;
} default: {
// leave apzc as nullptr
apzc = GetTargetAPZC(ScreenPoint(tapInput.mPoint), transformToApzc, transformToScreen);
if (apzc) {
TapGestureInput inputForApzc(tapInput);
ApplyTransform(&(inputForApzc.mPoint), transformToApzc);
apzc->ReceiveInputEvent(inputForApzc);
}
break;
}
}
if (apzc) {
return apzc->ReceiveInputEvent(aEvent);
}
return nsEventStatus_eIgnore;
}
@ -200,27 +242,51 @@ APZCTreeManager::ReceiveInputEvent(const nsInputEvent& aEvent,
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<AsyncPanZoomController> apzc;
gfx3DMatrix transformToApzc;
gfx3DMatrix transformToScreen;
switch (aEvent.eventStructType) {
case NS_TOUCH_EVENT: {
const nsTouchEvent& touchEvent = static_cast<const nsTouchEvent&>(aEvent);
if (touchEvent.touches.Length() > 0) {
nsIntPoint point = touchEvent.touches[0]->mRefPoint;
apzc = GetTargetAPZC(ScreenPoint::FromUnknownPoint(gfx::Point(point.x, point.y)));
apzc = GetTargetAPZC(ScreenPoint::FromUnknownPoint(gfx::Point(point.x, point.y)),
transformToApzc, transformToScreen);
if (apzc) {
MultiTouchInput inputForApzc(touchEvent);
for (int i = inputForApzc.mTouches.Length() - 1; i >= 0; i--) {
ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
}
gfx3DMatrix outTransform = transformToApzc * transformToScreen;
nsTouchEvent* outEvent = static_cast<nsTouchEvent*>(aOutEvent);
for (int i = outEvent->touches.Length() - 1; i >= 0; i--) {
ApplyTransform(&(outEvent->touches[i]->mRefPoint), outTransform);
}
return apzc->ReceiveInputEvent(inputForApzc);
}
}
break;
} case NS_MOUSE_EVENT: {
const nsMouseEvent& mouseEvent = static_cast<const nsMouseEvent&>(aEvent);
apzc = GetTargetAPZC(ScreenPoint::FromUnknownPoint(gfx::Point(mouseEvent.refPoint.x,
mouseEvent.refPoint.y)));
mouseEvent.refPoint.y)),
transformToApzc, transformToScreen);
if (apzc) {
MultiTouchInput inputForApzc(mouseEvent);
ApplyTransform(&(inputForApzc.mTouches[0].mScreenPoint), transformToApzc);
gfx3DMatrix outTransform = transformToApzc * transformToScreen;
ApplyTransform(&(static_cast<nsMouseEvent*>(aOutEvent)->refPoint), outTransform);
return apzc->ReceiveInputEvent(inputForApzc);
}
break;
} default: {
// leave apzc as nullptr
// Ignore other event types
break;
}
}
if (apzc) {
return apzc->ReceiveInputEvent(aEvent, aOutEvent);
}
return nsEventStatus_eIgnore;
}
@ -334,15 +400,84 @@ APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid)
return target.forget();
}
/* This function returns the AsyncPanZoomController instance that hit testing determines
is under the given ScreenPoint.
In addition, the aTransformToApzcOut and aTransformToScreenOut out-parameters are filled
with some useful transformations that input events may need applied. This is best
illustrated with an example. Consider a chain of layers, L, M, N, O, P, Q, R. Layer L
is the layer that corresponds to the returned APZC instance, and layer R is the root
of the layer tree. Layer M is the parent of L, N is the parent of M, and so on.
When layer L is displayed to the screen by the compositor, the set of transforms that
are applied to L are (in order from top to bottom):
L's CSS transform (hereafter referred to as transform matrix LC)
L's async transform (hereafter referred to as transform matrix LA)
M's CSS transform (hereafter referred to as transform matrix MC)
M's async transform (hereafter referred to as transform matrix MA)
...
R's CSS transform (hereafter referred to as transform matrix RC)
R's async transform (hereafter referred to as transform matrix RA)
Therefore, if we want user input to modify L's async transform, we have to first convert
user input from screen space to the coordinate space of L's async transform. Doing this
involves applying the following transforms (in order from top to bottom):
RA.Inverse()
RC.Inverse()
...
MA.Inverse()
MC.Inverse()
This combined transformation is returned in the aTransformToApzcOut out-parameter.
Next, if we want user inputs sent to gecko for event-dispatching, we will need to strip
out all of the async transforms that are involved in this chain. This is because async
transforms are stored only in the compositor and gecko does not account for them when
doing display-list-based hit-testing for event dispatching. Therefore, given a user input
in screen space, the following transforms need to be applied (in order from top to bottom):
RA.Inverse()
RC.Inverse()
...
MA.Inverse()
MC.Inverse()
LA.Inverse()
LC.Inverse()
LC
MC
...
RC
This sequence can be simplified and refactored to the following:
aTransformToApzcOut
LA.Inverse()
MC
...
RC
Since aTransformToApzcOut is already one of the out-parameters, we set aTransformToScreenOut
to the remaining transforms (LA.Inverse() * MC * ... * RC), so that the caller code can
combine it with aTransformToApzcOut to get the final transform required in this case.
Note that for many of these layers, there will be no AsyncPanZoomController attached, and
so the async transform will be the identity transform. So, in the example above, if layers
L and P have APZC instances attached, MA, NA, OA, QA, and RA will be identity transforms.
Additionally, for space-saving purposes, each APZC instance stores its layers individual
CSS transform and the accumulation of CSS transforms to its parent APZC. So the APZC for
layer L would store LC and (MC * NC * OC), and the layer P would store PC and (QC * RC).
The APZCs also obviously have LA and PA, so all of the above transformation combinations
required can be generated.
Note that this function may return null, in which case the matrix out-parameters are
left unmodified.
*/
already_AddRefed<AsyncPanZoomController>
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint)
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint,
gfx3DMatrix& aTransformToApzcOut,
gfx3DMatrix& aTransformToScreenOut)
{
MonitorAutoLock lock(mTreeLock);
nsRefPtr<AsyncPanZoomController> target;
// The root may have siblings, so check those too
gfxPoint point(aPoint.x, aPoint.y);
for (AsyncPanZoomController* apzc = mRootApzc; apzc; apzc = apzc->GetPrevSibling()) {
target = GetAPZCAtPoint(apzc, point);
target = GetAPZCAtPoint(apzc, point, aTransformToApzcOut, aTransformToScreenOut);
if (target) {
break;
}
@ -368,23 +503,52 @@ APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableL
}
AsyncPanZoomController*
APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, gfxPoint aHitTestPoint)
APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint,
gfx3DMatrix& aTransformToApzcOut, gfx3DMatrix& aTransformToScreenOut)
{
gfx3DMatrix transform = gfx3DMatrix(aApzc->GetCurrentAsyncTransform()) * aApzc->GetCSSTransform();
gfx3DMatrix untransform = transform.Inverse();
gfxPoint untransformed = untransform.ProjectPoint(aHitTestPoint);
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
// explained in the comment on GetTargetAPZC. This function will recurse with aApzc at L and P, and the
// comments explain what values are stored in the variables at these two levels. All the comments
// use standard matrix notation where the leftmost matrix in a multiplication is applied first.
// ancestorUntransform is OC.Inverse() * NC.Inverse() * MC.Inverse() at recursion level for L,
// and RC.Inverse() * QC.Inverse() at recursion level for P.
gfx3DMatrix ancestorUntransform = aApzc->GetAncestorTransform().Inverse();
// asyncUntransform is LA.Inverse() at recursion level for L,
// and PA.Inverse() at recursion level for P.
gfx3DMatrix asyncUntransform = gfx3DMatrix(aApzc->GetCurrentAsyncTransform()).Inverse();
// untransformSinceLastApzc is OC.Inverse() * NC.Inverse() * MC.Inverse() * LA.Inverse() * LC.Inverse() at L,
// and RC.Inverse() * QC.Inverse() * PA.Inverse() * PC.Inverse() at P.
gfx3DMatrix untransformSinceLastApzc = ancestorUntransform * asyncUntransform * aApzc->GetCSSTransform().Inverse();
// untransformed is the user input in L's layer space at L,
// and in P's layer space at P.
gfxPoint untransformed = untransformSinceLastApzc.ProjectPoint(aHitTestPoint);
APZC_LOG("Untransformed %f %f to %f %f for APZC %p\n", aHitTestPoint.x, aHitTestPoint.y, untransformed.x, untransformed.y, aApzc);
// This walks the tree in depth-first, reverse order, so that it encounters
// APZCs front-to-back on the screen.
for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
AsyncPanZoomController* match = GetAPZCAtPoint(child, untransformed);
AsyncPanZoomController* match = GetAPZCAtPoint(child, untransformed, aTransformToApzcOut, aTransformToScreenOut);
if (match) {
// This code is not run in the recursion at layer L.
// aTransformToApzcOut is RC.Inverse() * QC.Inverse() * PA.Inverse() * PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
// at recursion level for P
aTransformToApzcOut = untransformSinceLastApzc * aTransformToApzcOut;
// aTransformToScreenOut is LA.Inverse() * MC * NC * OC * PC * QC * RC at recursion level for P
aTransformToScreenOut = aTransformToScreenOut * aApzc->GetCSSTransform() * aApzc->GetAncestorTransform();
// The above values for aTransformToApzcOut and aTransformToScreenOut at recursion level for P match
// the required output as explained in the comment above GetTargetAPZC. Note that any missing terms
// are async transforms that are guaranteed to be identity transforms.
return match;
}
}
if (aApzc->VisibleRegionContains(LayerPoint(untransformed.x, untransformed.y))) {
APZC_LOG("Successfully matched untransformed point %f %f to visible region for APZC %p\n", untransformed.x, untransformed.y, aApzc);
// This code is not run in the recursion at layer P.
// aTransformToApzcOut is OC.Inverse() * NC.Inverse() * MC.Inverse() at recursion level for L.
aTransformToApzcOut = ancestorUntransform;
// aTransformToScreenOut is LA.Inverse() * MC * NC * OC at recursion level for L.
aTransformToScreenOut = asyncUntransform * aApzc->GetAncestorTransform();
return aApzc;
}
return nullptr;

Просмотреть файл

@ -236,11 +236,13 @@ public:
used by other production code.
*/
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint);
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint, gfx3DMatrix& aTransformToApzcOut,
gfx3DMatrix& aTransformToScreenOut);
private:
/* Recursive helpers */
AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, gfxPoint aHitTestPoint);
AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint,
gfx3DMatrix& aTransformToApzcOut, gfx3DMatrix& aTransformToScreenOut);
/**
* Recursive helper function to build the APZC tree. The tree of APZC instances has

Просмотреть файл

@ -247,64 +247,6 @@ WidgetSpaceToCompensatedViewportSpace(const ScreenPoint& aPoint,
return aPoint / aCurrentZoom;
}
nsEventStatus
AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent,
nsInputEvent* aOutEvent)
{
CSSToScreenScale currentResolution;
{
ReentrantMonitorAutoEnter lock(mMonitor);
currentResolution = mFrameMetrics.CalculateResolution();
}
nsEventStatus status;
switch (aEvent.eventStructType) {
case NS_TOUCH_EVENT: {
MultiTouchInput event(static_cast<const nsTouchEvent&>(aEvent));
status = ReceiveInputEvent(event);
break;
}
case NS_MOUSE_EVENT: {
MultiTouchInput event(static_cast<const nsMouseEvent&>(aEvent));
status = ReceiveInputEvent(event);
break;
}
default:
status = nsEventStatus_eIgnore;
break;
}
switch (aEvent.eventStructType) {
case NS_TOUCH_EVENT: {
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aOutEvent);
const nsTArray< nsRefPtr<dom::Touch> >& touches = touchEvent->touches;
for (uint32_t i = 0; i < touches.Length(); ++i) {
dom::Touch* touch = touches[i];
if (touch) {
CSSPoint refCSSPoint = WidgetSpaceToCompensatedViewportSpace(
ScreenPoint::FromUnknownPoint(gfx::Point(
touch->mRefPoint.x, touch->mRefPoint.y)),
currentResolution);
LayoutDevicePoint refPoint = refCSSPoint * mFrameMetrics.mDevPixelsPerCSSPixel;
touch->mRefPoint = nsIntPoint(refPoint.x, refPoint.y);
}
}
break;
}
default: {
CSSPoint refCSSPoint = WidgetSpaceToCompensatedViewportSpace(
ScreenPoint::FromUnknownPoint(gfx::Point(
aOutEvent->refPoint.x, aOutEvent->refPoint.y)),
currentResolution);
LayoutDevicePoint refPoint = refCSSPoint * mFrameMetrics.mDevPixelsPerCSSPixel;
aOutEvent->refPoint = LayoutDeviceIntPoint(refPoint.x, refPoint.y);
break;
}
}
return status;
}
nsEventStatus AsyncPanZoomController::ReceiveInputEvent(const InputData& aEvent) {
// If we may have touch listeners, we enable the machinery that allows touch
// listeners to preventDefault any touch inputs. This should not happen unless

Просмотреть файл

@ -100,19 +100,6 @@ public:
*/
nsEventStatus ReceiveInputEvent(const InputData& aEvent);
/**
* Special handler for nsInputEvents. Also sets |aOutEvent| (which is assumed
* to be an already-existing instance of an nsInputEvent which may be an
* nsTouchEvent) to have its touch points in DOM space. This is so that the
* touches can be passed through the DOM and content can handle them.
*
* NOTE: Be careful of invoking the nsInputEvent variant. This can only be
* called on the main thread. See widget/InputData.h for more information on
* why we have InputData and nsInputEvent separated.
*/
nsEventStatus ReceiveInputEvent(const nsInputEvent& aEvent,
nsInputEvent* aOutEvent);
/**
* Updates the composition bounds, i.e. the dimensions of the final size of
* the frame this is tied to during composition onto, in device pixels. In
@ -642,9 +629,15 @@ private:
* hit-testing to see which APZC instance should handle touch events.
*/
public:
void SetLayerHitTestData(const LayerRect& aRect, const gfx3DMatrix& aTransform) {
void SetLayerHitTestData(const LayerRect& aRect, const gfx3DMatrix& aTransformToLayer,
const gfx3DMatrix& aTransformForLayer) {
mVisibleRect = aRect;
mCSSTransform = aTransform;
mAncestorTransform = aTransformToLayer;
mCSSTransform = aTransformForLayer;
}
gfx3DMatrix GetAncestorTransform() const {
return mAncestorTransform;
}
gfx3DMatrix GetCSSTransform() const {
@ -661,8 +654,10 @@ private:
* applied to any layers, whether they are CSS transforms or async
* transforms. */
LayerRect mVisibleRect;
/* This is the cumulative layer transform from the parent APZC down to this
* one. */
/* This is the cumulative CSS transform for all the layers between the parent
* APZC and this one (not inclusive) */
gfx3DMatrix mAncestorTransform;
/* This is the CSS transform for this APZC's layer. */
gfx3DMatrix mCSSTransform;
};

Просмотреть файл

@ -376,16 +376,17 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
ScopedLayerTreeRegistration controller(0, root, mcc);
nsRefPtr<APZCTreeManager> manager = new TestAPZCTreeManager();
gfx3DMatrix matrix;
// No APZC attached so hit testing will return no APZC at (20,20)
nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(ScreenPoint(20, 20));
nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(ScreenPoint(20, 20), matrix, matrix);
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, 0, false);
hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
hit = manager->GetTargetAPZC(ScreenPoint(15, 15), matrix, matrix);
EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
// expect hit point at LayerIntPoint(15, 15)
@ -393,28 +394,28 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID, mcc);
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
EXPECT_NE(root->AsContainerLayer()->GetAsyncPanZoomController(), layers[3]->AsContainerLayer()->GetAsyncPanZoomController());
hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
hit = manager->GetTargetAPZC(ScreenPoint(15, 15), matrix, matrix);
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));
hit = manager->GetTargetAPZC(ScreenPoint(15, 15), matrix, matrix);
EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 1, mcc);
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
hit = manager->GetTargetAPZC(ScreenPoint(15, 15), matrix, matrix);
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));
hit = manager->GetTargetAPZC(ScreenPoint(90, 90), matrix, matrix);
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));
hit = manager->GetTargetAPZC(ScreenPoint(1000, 10), matrix, matrix);
EXPECT_EQ(nullAPZC, hit.get());
hit = manager->GetTargetAPZC(ScreenPoint(-1000, 10));
hit = manager->GetTargetAPZC(ScreenPoint(-1000, 10), matrix, matrix);
EXPECT_EQ(nullAPZC, hit.get());
// Test layer transform
@ -422,12 +423,12 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
transform.ScalePost(0.1, 0.1, 1);
root->SetBaseTransform(transform);
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
hit = manager->GetTargetAPZC(ScreenPoint(50, 50)); // This point is now outside the root layer
hit = manager->GetTargetAPZC(ScreenPoint(50, 50), matrix, matrix); // This point is now outside the root layer
EXPECT_EQ(nullAPZC, hit.get());
// This hit test will hit both layers[3] and layers[4]; layers[4] is later in the tree so
// it is a better match
hit = manager->GetTargetAPZC(ScreenPoint(2, 2));
hit = manager->GetTargetAPZC(ScreenPoint(2, 2), matrix, matrix);
EXPECT_EQ(layers[4]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
// expect hit point at LayerPoint(20, 20)
@ -436,7 +437,7 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
// layer 4 effective visible screenrect: (0.05, 0.05, 0.2, 0.2)
// Does not contain (2, 2)
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
hit = manager->GetTargetAPZC(ScreenPoint(2, 2));
hit = manager->GetTargetAPZC(ScreenPoint(2, 2), matrix, matrix);
EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
// expect hit point at LayerPoint(20, 20)
@ -457,7 +458,7 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
// layer 7 effective visible screenrect (0,16,4,60) but clipped by parent layers
hit = manager->GetTargetAPZC(ScreenPoint(1, 45));
hit = manager->GetTargetAPZC(ScreenPoint(1, 45), matrix, matrix);
EXPECT_EQ(layers[7]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
// expect hit point at LayerPoint(20, 29)