Bug 1090398 - Add support for using the layer event regions for hit testing. r=botond

When the event-regions are provided by layout, use them to populate the APZ-side
hit testing regions. The existing code is still used when event-regions are not
provided by layout.
This commit is contained in:
Kartikaya Gupta 2014-11-14 07:40:14 -05:00
parent 9dac319884
commit ce01ad7c02
6 changed files with 152 additions and 10 deletions

View File

@ -299,6 +299,16 @@ public:
return gfx::Matrix4x4();
}
EventRegions GetEventRegions() const
{
MOZ_ASSERT(IsValid());
if (AtBottomLayer()) {
return mLayer->GetEventRegions();
}
return EventRegions();
}
RefLayer* AsRefLayer() const
{
MOZ_ASSERT(IsValid());

View File

@ -1476,11 +1476,8 @@ Layer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
} else {
aStream << " [not visible]";
}
if (!mEventRegions.mHitRegion.IsEmpty()) {
AppendToString(aStream, mEventRegions.mHitRegion, " [hitregion=", "]");
}
if (!mEventRegions.mDispatchToContentHitRegion.IsEmpty()) {
AppendToString(aStream, mEventRegions.mDispatchToContentHitRegion, " [dispatchtocontentregion=", "]");
if (!mEventRegions.IsEmpty()) {
AppendToString(aStream, mEventRegions, " ", "");
}
if (1.0 != mOpacity) {
aStream << nsPrintfCString(" [opacity=%g]", mOpacity).get();

View File

@ -124,6 +124,20 @@ AppendToString(std::stringstream& aStream, const nsIntRegion& r,
aStream << sfx;
}
void
AppendToString(std::stringstream& aStream, const EventRegions& e,
const char* pfx, const char* sfx)
{
aStream << pfx << "{";
if (!e.mHitRegion.IsEmpty()) {
AppendToString(aStream, e.mHitRegion, " hitregion=", "");
}
if (!e.mDispatchToContentHitRegion.IsEmpty()) {
AppendToString(aStream, e.mDispatchToContentHitRegion, " dispatchtocontentregion=", "");
}
aStream << "}" << sfx;
}
void
AppendToString(std::stringstream& aStream, const nsIntSize& sz,
const char* pfx, const char* sfx)

View File

@ -97,6 +97,10 @@ void
AppendToString(std::stringstream& aStream, const nsIntRegion& r,
const char* pfx="", const char* sfx="");
void
AppendToString(std::stringstream& aStream, const EventRegions& e,
const char* pfx="", const char* sfx="");
void
AppendToString(std::stringstream& aStream, const nsIntSize& sz,
const char* pfx="", const char* sfx="");

View File

@ -187,6 +187,30 @@ struct EventRegions {
mDispatchToContentHitRegion.OrWith(aOther.mDispatchToContentHitRegion);
}
void AndWith(const nsIntRegion& aRegion)
{
mHitRegion.AndWith(aRegion);
mDispatchToContentHitRegion.AndWith(aRegion);
}
void Sub(const EventRegions& aMinuend, const nsIntRegion& aSubtrahend)
{
mHitRegion.Sub(aMinuend.mHitRegion, aSubtrahend);
mDispatchToContentHitRegion.Sub(aMinuend.mDispatchToContentHitRegion, aSubtrahend);
}
void Transform(const gfx3DMatrix& aTransform)
{
mHitRegion.Transform(aTransform);
mDispatchToContentHitRegion.Transform(aTransform);
}
bool IsEmpty() const
{
return mHitRegion.IsEmpty()
&& mDispatchToContentHitRegion.IsEmpty();
}
nsCString ToString() const
{
nsCString result = mHitRegion.ToString();

View File

@ -59,6 +59,7 @@ struct APZCTreeManager::TreeBuildingState {
// State that is updated as we perform the tree build
nsTArray< nsRefPtr<AsyncPanZoomController> > mApzcsToDestroy;
std::map<ScrollableLayerGuid, AsyncPanZoomController*> mApzcMap;
nsTArray<EventRegions> mEventRegions;
};
/*static*/ const ScreenMargin
@ -178,6 +179,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
Matrix4x4(), nullptr, nullptr, nsIntRegion());
mApzcTreeLog << "[end]\n";
}
MOZ_ASSERT(state.mEventRegions.Length() == 0);
for (size_t i = 0; i < state.mApzcsToDestroy.Length(); i++) {
APZCTM_LOG("Destroying APZC at %p\n", state.mApzcsToDestroy[i].get());
@ -326,7 +328,10 @@ APZCTreeManager::PrepareAPZCForLayer(const LayerMetricsWrapper& aLayer,
apzc->NotifyLayersUpdated(aMetrics,
aState.mIsFirstPaint && (aLayersId == aState.mOriginatingLayersId));
nsIntRegion unobscured = ComputeTouchSensitiveRegion(state->mController, aMetrics, aObscured);
nsIntRegion unobscured;
if (!gfxPrefs::LayoutEventRegionsEnabled()) {
unobscured = ComputeTouchSensitiveRegion(state->mController, aMetrics, aObscured);
}
apzc->SetLayerHitTestData(EventRegions(unobscured), aAncestorTransform);
APZCTM_LOG("Setting region %s as visible region for APZC %p\n",
Stringify(unobscured).c_str(), apzc);
@ -390,9 +395,11 @@ APZCTreeManager::PrepareAPZCForLayer(const LayerMetricsWrapper& aLayer,
// async transform and so we basically assume the same amount of C is always visible
// on top of B. Fixing this doesn't appear to be very easy so I'm leaving it for
// now in the hopes that we won't run into this problem a lot.
nsIntRegion unobscured = ComputeTouchSensitiveRegion(state->mController, aMetrics, aObscured);
apzc->AddHitTestRegions(EventRegions(unobscured));
APZCTM_LOG("Adding region %s to visible region of APZC %p\n", Stringify(unobscured).c_str(), apzc);
if (!gfxPrefs::LayoutEventRegionsEnabled()) {
nsIntRegion unobscured = ComputeTouchSensitiveRegion(state->mController, aMetrics, aObscured);
apzc->AddHitTestRegions(EventRegions(unobscured));
APZCTM_LOG("Adding region %s to visible region of APZC %p\n", Stringify(unobscured).c_str(), apzc);
}
}
return apzc;
@ -460,6 +467,16 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState,
next = apzc->GetFirstChild();
}
// In our recursive downward traversal, track event regions for layers once
// we encounter an APZC. Push a new empty region on the mEventRegions stack
// which will accumulate the hit area of descendants of aLayer. In general,
// the mEventRegions stack is used to accumulate event regions from descendant
// layers because the event regions for a layer don't include those of its
// children.
if (gfxPrefs::LayoutEventRegionsEnabled() && (apzc || aState.mEventRegions.Length() > 0)) {
aState.mEventRegions.AppendElement(EventRegions());
}
for (LayerMetricsWrapper child = aLayer.GetLastChild(); child; child = child.GetPrevSibling()) {
gfx::TreeAutoIndent indent(mApzcTreeLog);
next = UpdatePanZoomControllerTree(aState, child, childLayersId,
@ -468,7 +485,12 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState,
// Each layer obscures its previous siblings, so we augment the obscured
// region as we loop backwards through the children.
nsIntRegion childRegion = child.GetVisibleRegion();
nsIntRegion childRegion;
if (gfxPrefs::LayoutEventRegionsEnabled()) {
childRegion = child.GetEventRegions().mHitRegion;
} else {
childRegion = child.GetVisibleRegion();
}
childRegion.Transform(gfx::To3DMatrix(child.GetTransform()));
if (child.GetClipRect()) {
childRegion.AndWith(*child.GetClipRect());
@ -477,6 +499,77 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState,
obscured.OrWith(childRegion);
}
if (gfxPrefs::LayoutEventRegionsEnabled() && aState.mEventRegions.Length() > 0) {
// At this point in the code, aState.mEventRegions.LastElement() contains
// the accumulated regions of the non-APZC descendants of |aLayer|. This
// happened in the loop above while we iterated through the descendants of
// |aLayer|. Note that it only includes the non-APZC descendants, because
// if a layer has an APZC, we simply store the regions from that subtree on
// that APZC and don't propagate them upwards in the tree. Because of the
// way we do hit-testing (where the deepest matching APZC is used) it should
// still be ok if we did propagate those regions upwards and included them
// in all the ancestor APZCs.
//
// Also at this point in the code the |obscured| region includes the hit
// regions of children of |aLayer| as well as the hit regions of |aLayer|'s
// younger uncles (i.e. the next-sibling chain of |aLayer|'s parent).
// When we compute the unobscured regions below, we subtract off the
// |obscured| region, but it would also be ok to do this before the above
// loop. At that point |obscured| would only have the uncles' hit regions
// and not the children. The reason this is ok is again because of the way
// we do hit-testing (where the deepest APZC is used) it doesn't matter if
// we count the children as obscuring the parent or not.
EventRegions unobscured;
unobscured.Sub(aLayer.GetEventRegions(), obscured);
APZCTM_LOG("Picking up unobscured hit region %s from layer %p\n", Stringify(unobscured).c_str(), aLayer.GetLayer());
// Take the hit region of the |aLayer|'s subtree (which has already been
// transformed into the coordinate space of |aLayer|) and...
EventRegions subtreeEventRegions = aState.mEventRegions.LastElement();
aState.mEventRegions.RemoveElementAt(aState.mEventRegions.Length() - 1);
// ... combine it with the hit region for this layer, and then ...
subtreeEventRegions.OrWith(unobscured);
// ... transform it up to the parent layer's coordinate space.
subtreeEventRegions.Transform(To3DMatrix(aLayer.GetTransform()));
if (aLayer.GetClipRect()) {
subtreeEventRegions.AndWith(*aLayer.GetClipRect());
}
APZCTM_LOG("After processing layer %p the subtree hit region is %s\n", aLayer.GetLayer(), Stringify(subtreeEventRegions).c_str());
// If we have an APZC at this level, intersect the subtree hit region with
// the touch-sensitive region and add it to the APZ's hit test regions.
if (apzc) {
APZCTM_LOG("Adding region %s to visible region of APZC %p\n", Stringify(subtreeEventRegions).c_str(), apzc);
const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId);
MOZ_ASSERT(state);
MOZ_ASSERT(state->mController.get());
CSSRect touchSensitiveRegion;
if (state->mController->GetTouchSensitiveRegion(&touchSensitiveRegion)) {
// Here we assume 'touchSensitiveRegion' is in the CSS pixels of the
// parent frame. To convert it to ParentLayer pixels, we therefore need
// the cumulative resolution of the parent frame. We approximate this as
// the quotient of our cumulative resolution and our pres shell
// resolution; this approximation may not be accurate in the presence of
// a css-driven resolution.
LayoutDeviceToParentLayerScale parentCumulativeResolution =
aLayer.Metrics().mCumulativeResolution
/ ParentLayerToLayerScale(aLayer.Metrics().mPresShellResolution);
subtreeEventRegions.AndWith(ParentLayerIntRect::ToUntyped(
RoundedIn(touchSensitiveRegion
* aLayer.Metrics().mDevPixelsPerCSSPixel
* parentCumulativeResolution)));
}
apzc->AddHitTestRegions(subtreeEventRegions);
} else {
// If we don't have an APZC at this level, carry the subtree hit region
// up to the parent.
MOZ_ASSERT(aState.mEventRegions.Length() > 0);
aState.mEventRegions.LastElement().OrWith(subtreeEventRegions);
}
}
// Return the APZC that should be the sibling of other APZCs as we continue
// moving towards the first child at this depth in the layer tree.
// If this layer doesn't have an APZC, we promote any APZCs in the subtree