Bug 1447131 - Handle backface-visibility:hidden in compositor hit testing. r=kats draft
authorBotond Ballo <botond@mozilla.com>
Wed, 28 Mar 2018 14:22:30 -0400
changeset 773958 be2e6a1e3fc651cb26bf90b77077ca0a5de8d80a
parent 772574 7b9da7139d94951431a148dcaf8a388640c91b27
child 773959 ad39696f8573e2e5119720c7495ce1b21cf62f82
push id104359
push userbballo@mozilla.com
push dateWed, 28 Mar 2018 18:25:07 +0000
reviewerskats
bugs1447131
milestone61.0a1
Bug 1447131 - Handle backface-visibility:hidden in compositor hit testing. r=kats MozReview-Commit-ID: EZhhSk3EZAL
gfx/layers/LayerMetricsWrapper.h
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/HitTestingTreeNode.cpp
gfx/layers/apz/src/HitTestingTreeNode.h
gfx/layers/wr/WebRenderScrollDataWrapper.h
--- 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