Bug 1447131 - Handle backface-visibility:hidden in compositor hit testing. r=kats
MozReview-Commit-ID: EZhhSk3EZAL
--- a/gfx/layers/LayerMetricsWrapper.h
+++ b/gfx/layers/LayerMetricsWrapper.h
@@ -441,16 +441,23 @@ public:
FrameMetrics::ViewID GetFixedPositionScrollContainerId() const
{
MOZ_ASSERT(IsValid());
return mLayer->GetFixedPositionScrollContainerId();
}
+ bool IsBackfaceHidden() const
+ {
+ MOZ_ASSERT(IsValid());
+
+ return mLayer->IsBackfaceHidden();
+ }
+
// Expose an opaque pointer to the layer. Mostly used for printf
// purposes. This is not intended to be a general-purpose accessor
// for the underlying layer.
const void* GetLayer() const
{
MOZ_ASSERT(IsValid());
return (void*)mLayer;
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -838,17 +838,18 @@ APZCTreeManager::PrepareNodeForLayer(con
AttachNodeToTree(node, aParent, aNextSibling);
node->SetHitTestData(
GetEventRegions(aLayer),
aLayer.GetVisibleRegion(),
aLayer.GetTransformTyped(),
(!parentHasPerspective && aLayer.GetClipRect())
? Some(ParentLayerIntRegion(*aLayer.GetClipRect()))
: Nothing(),
- GetEventRegionsOverride(aParent, aLayer));
+ GetEventRegionsOverride(aParent, aLayer),
+ aLayer.IsBackfaceHidden());
node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(),
aLayer.GetScrollbarAnimationId(),
aLayer.GetScrollThumbData(),
aLayer.GetScrollbarContainerDirection());
node->SetFixedPosData(aLayer.GetFixedPositionScrollContainerId());
return node;
}
@@ -951,17 +952,18 @@ APZCTreeManager::PrepareNodeForLayer(con
Maybe<ParentLayerIntRegion> clipRegion = parentHasPerspective
? Nothing()
: Some(ComputeClipRegion(aLayer));
node->SetHitTestData(
GetEventRegions(aLayer),
aLayer.GetVisibleRegion(),
aLayer.GetTransformTyped(),
clipRegion,
- GetEventRegionsOverride(aParent, aLayer));
+ GetEventRegionsOverride(aParent, aLayer),
+ aLayer.IsBackfaceHidden());
apzc->SetAncestorTransform(aAncestorTransform);
PrintAPZCInfo(aLayer, apzc);
// Bind the APZC instance into the tree of APZCs
AttachNodeToTree(node, aParent, aNextSibling);
// For testing, log the parent scroll id of every APZC that has a
@@ -1050,17 +1052,18 @@ APZCTreeManager::PrepareNodeForLayer(con
Maybe<ParentLayerIntRegion> clipRegion = parentHasPerspective
? Nothing()
: Some(ComputeClipRegion(aLayer));
node->SetHitTestData(
GetEventRegions(aLayer),
aLayer.GetVisibleRegion(),
aLayer.GetTransformTyped(),
clipRegion,
- GetEventRegionsOverride(aParent, aLayer));
+ GetEventRegionsOverride(aParent, aLayer),
+ aLayer.IsBackfaceHidden());
}
// Note: if layer properties must be propagated to nodes, RecvUpdate in
// LayerTransactionParent.cpp must ensure that APZ will be notified
// when those properties change.
node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(),
aLayer.GetScrollbarAnimationId(),
aLayer.GetScrollThumbData(),
--- a/gfx/layers/apz/src/HitTestingTreeNode.cpp
+++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp
@@ -26,16 +26,17 @@ HitTestingTreeNode::HitTestingTreeNode(A
bool aIsPrimaryHolder,
LayersId aLayersId)
: mApzc(aApzc)
, mIsPrimaryApzcHolder(aIsPrimaryHolder)
, mLayersId(aLayersId)
, mScrollViewId(FrameMetrics::NULL_SCROLL_ID)
, mScrollbarAnimationId(0)
, mFixedPosTarget(FrameMetrics::NULL_SCROLL_ID)
+ , mIsBackfaceHidden(false)
, mOverride(EventRegionsOverride::NoOverride)
{
if (mIsPrimaryApzcHolder) {
MOZ_ASSERT(mApzc);
}
MOZ_ASSERT(!mApzc || mApzc->GetLayersId() == mLayersId);
}
@@ -258,23 +259,25 @@ HitTestingTreeNode::GetLayersId() const
return mLayersId;
}
void
HitTestingTreeNode::SetHitTestData(const EventRegions& aRegions,
const LayerIntRegion& aVisibleRegion,
const CSSTransformMatrix& aTransform,
const Maybe<ParentLayerIntRegion>& aClipRegion,
- const EventRegionsOverride& aOverride)
+ const EventRegionsOverride& aOverride,
+ bool aIsBackfaceHidden)
{
mEventRegions = aRegions;
mVisibleRegion = aVisibleRegion;
mTransform = aTransform;
mClipRegion = aClipRegion;
mOverride = aOverride;
+ mIsBackfaceHidden = aIsBackfaceHidden;
}
bool
HitTestingTreeNode::IsOutsideClip(const ParentLayerPoint& aPoint) const
{
// test against clip rect in ParentLayer coordinate space
return (mClipRegion.isSome() && !mClipRegion->Contains(aPoint.x, aPoint.y));
}
@@ -296,16 +299,23 @@ HitTestingTreeNode::HitTest(const LayerP
CompositorHitTestInfo result = CompositorHitTestInfo::eInvisibleToHitTest;
if (mOverride & EventRegionsOverride::ForceEmptyHitRegion) {
return result;
}
auto point = LayerIntPoint::Round(aPoint);
+ // If the layer's backface is showing and it's hidden, don't hit it.
+ // This matches the behavior of main-thread hit testing in
+ // nsDisplayTransform::HitTest().
+ if (mIsBackfaceHidden) {
+ return result;
+ }
+
// test against event regions in Layer coordinate space
if (!mEventRegions.mHitRegion.Contains(point.x, point.y)) {
return result;
}
result |= CompositorHitTestInfo::eVisibleToHitTest;
if ((mOverride & EventRegionsOverride::ForceDispatchToContent) ||
--- a/gfx/layers/apz/src/HitTestingTreeNode.h
+++ b/gfx/layers/apz/src/HitTestingTreeNode.h
@@ -84,17 +84,18 @@ public:
LayersId GetLayersId() const;
/* Hit test related methods */
void SetHitTestData(const EventRegions& aRegions,
const LayerIntRegion& aVisibleRegion,
const CSSTransformMatrix& aTransform,
const Maybe<ParentLayerIntRegion>& aClipRegion,
- const EventRegionsOverride& aOverride);
+ const EventRegionsOverride& aOverride,
+ bool aIsBackfaceHidden);
bool IsOutsideClip(const ParentLayerPoint& aPoint) const;
/* Scrollbar info */
void SetScrollbarData(FrameMetrics::ViewID aScrollViewId,
const uint64_t& aScrollbarAnimationId,
const ScrollThumbData& aThumbData,
const Maybe<ScrollDirection>& aScrollContainerDirection);
@@ -167,16 +168,24 @@ private:
EventRegions mEventRegions;
LayerIntRegion mVisibleRegion;
/* This is the transform from layer L. This does NOT include any async
* transforms. */
CSSTransformMatrix mTransform;
+ /* Whether layer L is backface-visibility:hidden, and its backface is
+ * currently visible. It's true that the latter depends on the layer's
+ * shadow transform, but the sorts of changes APZ makes to the shadow
+ * transform shouldn't change the backface from hidden to visible or
+ * vice versa, so it's sufficient to record this at hit test tree
+ * building time. */
+ bool mIsBackfaceHidden;
+
/* This is clip rect for L that we wish to use for hit-testing purposes. Note
* that this may not be exactly the same as the clip rect on layer L because
* of the touch-sensitive region provided by the GeckoContentController, or
* because we may use the composition bounds of the layer if the clip is not
* present. This value is in L's ParentLayerPixels. */
Maybe<ParentLayerIntRegion> mClipRegion;
/* Indicates whether or not the event regions on this node need to be
--- a/gfx/layers/wr/WebRenderScrollDataWrapper.h
+++ b/gfx/layers/wr/WebRenderScrollDataWrapper.h
@@ -310,16 +310,23 @@ public:
}
FrameMetrics::ViewID GetFixedPositionScrollContainerId() const
{
MOZ_ASSERT(IsValid());
return mLayer->GetFixedPositionScrollContainerId();
}
+ bool IsBackfaceHidden() const
+ {
+ // This is only used by APZCTM hit testing, and WR does its own
+ // hit testing, so no need to implement this.
+ return false;
+ }
+
const void* GetLayer() const
{
MOZ_ASSERT(IsValid());
return mLayer;
}
private:
bool AtBottomLayer() const