Bug 973096 - When computing the hit test area for an APZC, remove the visible regions of layers obscuring it. r=botond

This commit is contained in:
Kartikaya Gupta 2014-07-25 08:27:43 -04:00
parent 5f98bf8180
commit 716eeb59c8
4 changed files with 62 additions and 17 deletions

View File

@ -141,7 +141,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
aCompositor ? aCompositor->RootLayerTreeId() : 0,
gfx3DMatrix(), nullptr, nullptr,
aIsFirstPaint, aOriginatingLayersId,
paintLogger, &apzcsToDestroy);
paintLogger, &apzcsToDestroy, nsIntRegion());
mApzcTreeLog << "[end]\n";
}
@ -160,10 +160,13 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
bool aIsFirstPaint,
uint64_t aOriginatingLayersId,
const APZPaintLogHelper& aPaintLogger,
nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy)
nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy,
const nsIntRegion& aObscured)
{
mTreeLock.AssertCurrentThreadOwns();
gfx3DMatrix transform = gfx::To3DMatrix(aLayer->GetTransform());
ContainerLayer* container = aLayer->AsContainerLayer();
AsyncPanZoomController* apzc = nullptr;
mApzcTreeLog << aLayer->Name() << '\t';
@ -244,9 +247,17 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
* metrics.mDevPixelsPerCSSPixel
* metrics.GetParentResolution());
}
gfx3DMatrix transform = gfx::To3DMatrix(aLayer->GetTransform());
apzc->SetLayerHitTestData(visible, aTransform, transform);
// Not sure what rounding option is the most correct here, but if we ever
// figure it out we can change this. For now I'm rounding in to minimize
// the chances of getting a complex region.
ParentLayerIntRect roundedVisible = RoundedIn(visible);
nsIntRegion unobscured;
unobscured.Sub(nsIntRect(roundedVisible.x, roundedVisible.y,
roundedVisible.width, roundedVisible.height),
aObscured);
apzc->SetLayerHitTestData(unobscured, aTransform, transform);
APZCTM_LOG("Setting rect(%f %f %f %f) as visible region for APZC %p\n", visible.x, visible.y,
visible.width, visible.height,
apzc);
@ -311,10 +322,28 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
aTransform = gfx3DMatrix();
} else {
// Multiply child layer transforms on the left so they get applied first
aTransform = gfx::To3DMatrix(aLayer->GetTransform()) * aTransform;
aTransform = transform * aTransform;
}
uint64_t childLayersId = (aLayer->AsRefLayer() ? aLayer->AsRefLayer()->GetReferentId() : aLayersId);
nsIntRegion obscured;
if (aLayersId == childLayersId) {
// If the child layer is in the same process, transform
// aObscured from aLayer's ParentLayerPixels to aLayer's LayerPixels,
// which are the children layers' ParentLayerPixels.
// If we cross a process boundary, we assume that we can start with
// an empty obscured region because nothing in the parent process will
// obscure the child process. This may be false. However, not doing this
// definitely runs into a problematic case where the B2G notification
// bar and the keyboard get merged into a single layer that obscures
// all child processes, even though visually they do not. We'd probably
// have to check for mask layers and so on in order to properly handle
// that case.
obscured = aObscured;
obscured.Transform(transform.Inverse());
}
// If there's no APZC at this level, any APZCs for our child layers will
// have our siblings as siblings.
AsyncPanZoomController* next = apzc ? nullptr : aNextSibling;
@ -322,7 +351,17 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
gfx::TreeAutoIndent indent(mApzcTreeLog);
next = UpdatePanZoomControllerTree(aCompositor, child, childLayersId, aTransform, aParent, next,
aIsFirstPaint, aOriginatingLayersId,
aPaintLogger, aApzcsToDestroy);
aPaintLogger, aApzcsToDestroy, obscured);
// Each layer obscures its previous siblings, so we augment the obscured
// region as we loop backwards through the children.
nsIntRegion childRegion = child->GetVisibleRegion();
childRegion.Transform(gfx::To3DMatrix(child->GetTransform()));
if (child->GetClipRect()) {
childRegion.AndWith(*child->GetClipRect());
}
obscured.OrWith(childRegion);
}
// Return the APZC that should be the sibling of other APZCs as we continue

View File

@ -363,7 +363,8 @@ private:
bool aIsFirstPaint,
uint64_t aOriginatingLayersId,
const APZPaintLogHelper& aPaintLogger,
nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy);
nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy,
const nsIntRegion& aObscured);
private:
/* Whenever walking or mutating the tree rooted at mRootApzc, mTreeLock must be held.

View File

@ -21,6 +21,7 @@
#include "Axis.h"
#include "TaskThrottler.h"
#include "gfx3DMatrix.h"
#include "nsRegion.h"
#include "base/message_loop.h"
@ -941,9 +942,9 @@ private:
* hit-testing to see which APZC instance should handle touch events.
*/
public:
void SetLayerHitTestData(const ParentLayerRect& aRect, const gfx3DMatrix& aTransformToLayer,
void SetLayerHitTestData(const nsIntRegion& aRegion, const gfx3DMatrix& aTransformToLayer,
const gfx3DMatrix& aTransformForLayer) {
mVisibleRect = aRect;
mVisibleRegion = aRegion;
mAncestorTransform = aTransformToLayer;
mCSSTransform = aTransformForLayer;
UpdateTransformScale();
@ -958,7 +959,8 @@ public:
}
bool VisibleRegionContains(const ParentLayerPoint& aPoint) const {
return mVisibleRect.Contains(aPoint);
ParentLayerIntPoint point = RoundedToInt(aPoint);
return mVisibleRegion.Contains(point.x, point.y);
}
bool IsOverscrolled() const {
@ -969,7 +971,7 @@ private:
/* This is the visible region of the layer that this APZC corresponds to, in
* that layer's screen pixels (the same coordinate system in which this APZC
* receives events in ReceiveInputEvent()). */
ParentLayerRect mVisibleRect;
nsIntRegion mVisibleRegion;
/* This is the cumulative CSS transform for all the layers between the parent
* APZC and this one (not inclusive) */
gfx3DMatrix mAncestorTransform;

View File

@ -1545,15 +1545,18 @@ TEST_F(APZCTreeManagerTester, HitTesting1) {
SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 1);
manager->UpdatePanZoomControllerTree(nullptr, root, false, 0, paintSequenceNumber++);
EXPECT_NE(root->AsContainerLayer()->GetAsyncPanZoomController(), layers[3]->AsContainerLayer()->GetAsyncPanZoomController());
hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);
hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko);
EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
// expect hit point at LayerIntPoint(15, 15)
EXPECT_EQ(gfxPoint(15, 15), transformToApzc.Transform(gfxPoint(15, 15)));
EXPECT_EQ(gfxPoint(15, 15), transformToGecko.Transform(gfxPoint(15, 15)));
// expect hit point at LayerIntPoint(25, 25)
EXPECT_EQ(gfxPoint(25, 25), transformToApzc.Transform(gfxPoint(25, 25)));
EXPECT_EQ(gfxPoint(25, 25), transformToGecko.Transform(gfxPoint(25, 25)));
// At this point, layers[4] obscures layers[3] at the point (15, 15) so
// hitting there should hit the root APZC
hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);
EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
// Now test hit testing when we have two scrollable layers
hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);
EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 2);
manager->UpdatePanZoomControllerTree(nullptr, root, false, 0, paintSequenceNumber++);
hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);