Bug 1425573 - Require target confirmation for events that hit unlayerized scroll frames with non-default overscroll-behavior. r=kats draft
authorBotond Ballo <botond@mozilla.com>
Fri, 16 Feb 2018 20:16:41 -0500
changeset 758066 5edc6d20150feac46ce1dd70030c677520b41ace
parent 758065 9dd8c18183e6656e6f9459a92af4d9659cf421d6
child 759191 3af31c36520ca623bc5f93be58f9b2494f1529b5
child 759200 8ca1ac0744a2252f8e3e62afa99c74f89820a148
child 759219 a75aa57831ec65f6390b445a24481900195e0441
push id99941
push userbballo@mozilla.com
push dateWed, 21 Feb 2018 21:04:27 +0000
reviewerskats
bugs1425573
milestone60.0a1
Bug 1425573 - Require target confirmation for events that hit unlayerized scroll frames with non-default overscroll-behavior. r=kats MozReview-Commit-ID: K88tXahKg8H
gfx/layers/apz/src/APZUtils.h
gfx/layers/apz/src/InputBlockState.cpp
gfx/layers/apz/src/InputBlockState.h
gfx/src/CompositorHitTestInfo.h
layout/generic/nsGfxScrollFrame.cpp
--- a/gfx/layers/apz/src/APZUtils.h
+++ b/gfx/layers/apz/src/APZUtils.h
@@ -75,22 +75,25 @@ CompleteAsyncTransform(const AsyncTransf
 {
   return ViewAs<AsyncTransformMatrix>(aMatrix,
       PixelCastJustification::MultipleAsyncTransforms);
 }
 
 struct TargetConfirmationFlags {
   explicit TargetConfirmationFlags(bool aTargetConfirmed)
     : mTargetConfirmed(aTargetConfirmed)
+    , mRequiresTargetConfirmation(false)
   {}
 
   explicit TargetConfirmationFlags(gfx::CompositorHitTestInfo aHitTestInfo)
     : mTargetConfirmed(aHitTestInfo != gfx::CompositorHitTestInfo::eInvisibleToHitTest &&
                        !(aHitTestInfo & gfx::CompositorHitTestInfo::eDispatchToContent))
+    , mRequiresTargetConfirmation(aHitTestInfo & gfx::CompositorHitTestInfo::eRequiresTargetConfirmation)
   {}
 
   bool mTargetConfirmed : 1;
+  bool mRequiresTargetConfirmation : 1;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_APZUtils_h
--- a/gfx/layers/apz/src/InputBlockState.cpp
+++ b/gfx/layers/apz/src/InputBlockState.cpp
@@ -22,16 +22,17 @@ namespace layers {
 
 static uint64_t sBlockCounter = InputBlockState::NO_BLOCK_ID + 1;
 
 InputBlockState::InputBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc,
                                  TargetConfirmationFlags aFlags)
   : mTargetApzc(aTargetApzc)
   , mTargetConfirmed(aFlags.mTargetConfirmed ? TargetConfirmationState::eConfirmed
                                              : TargetConfirmationState::eUnconfirmed)
+  , mRequiresTargetConfirmation(aFlags.mRequiresTargetConfirmation)
   , mBlockId(sBlockCounter++)
   , mTransformToApzc(aTargetApzc->GetTransformToThis())
 {
   // We should never be constructed with a nullptr target.
   MOZ_ASSERT(mTargetApzc);
   mOverscrollHandoffChain = mTargetApzc->BuildOverscrollHandoffChain();
 }
 
@@ -106,17 +107,17 @@ InputBlockState::HasReceivedRealConfirme
 {
   return mTargetConfirmed == TargetConfirmationState::eConfirmed ||
          mTargetConfirmed == TargetConfirmationState::eTimedOutAndMainThreadResponded;
 }
 
 bool
 InputBlockState::ShouldDropEvents() const
 {
-  return false;
+  return mRequiresTargetConfirmation && (mTargetConfirmed != TargetConfirmationState::eConfirmed);
 }
 
 bool
 InputBlockState::IsDownchainOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB) const
 {
   if (aA == aB) {
     return true;
   }
--- a/gfx/layers/apz/src/InputBlockState.h
+++ b/gfx/layers/apz/src/InputBlockState.h
@@ -107,16 +107,17 @@ protected:
 private:
   // Checks whether |aA| is an ancestor of |aB| (or the same as |aB|) in
   // |mOverscrollHandoffChain|.
   bool IsDownchainOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB) const;
 
 private:
   RefPtr<AsyncPanZoomController> mTargetApzc;
   TargetConfirmationState mTargetConfirmed;
+  bool mRequiresTargetConfirmation;
   const uint64_t mBlockId;
 
   // The APZC that was actually scrolled by events in this input block.
   // This is used in configurations where a single input block is only
   // allowed to scroll a single APZC (configurations where gfxPrefs::
   // APZAllowImmediateHandoff() is false).
   // Set the first time an input event in this block scrolls an APZC.
   RefPtr<AsyncPanZoomController> mScrolledApzc;
--- a/gfx/src/CompositorHitTestInfo.h
+++ b/gfx/src/CompositorHitTestInfo.h
@@ -41,19 +41,25 @@ enum class CompositorHitTestInfo : uint1
   // The frame is a scrollthumb. If this is set then eScrollbar will also be
   // set, unless gecko somehow generates a scroll thumb without a containing
   // scrollbar.
   eScrollbarThumb = 1 << 7,
   // If eScrollbar is set, this flag indicates if the scrollbar is a vertical
   // one (if set) or a horizontal one (if not set)
   eScrollbarVertical = 1 << 8,
 
+  // Events targeting this frame should only be processed if a target
+  // confirmation is received from the main thread. If no such confirmation
+  // is received within a timeout period, the event may be dropped.
+  // Only meaningful in combination with eDispatchToContent.
+  eRequiresTargetConfirmation = 1 << 9,
+
   // Used for IPDL serialization. This bitmask should include all the bits
   // that are defined in the enum.
-  ALL_BITS = (1 << 9) - 1,
+  ALL_BITS = (1 << 10) - 1,
 };
 
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CompositorHitTestInfo)
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_COMPOSITORHITTESTINFO_H_ */
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3678,16 +3678,27 @@ ScrollFrameHelper::BuildDisplayList(nsDi
     // Make sure that APZ will dispatch events back to content so we can create
     // a displayport for this frame. We'll add the item later on.
     if (!mWillBuildScrollableLayer) {
       int32_t zIndex =
         MaxZIndexInListOfItemsContainedInFrame(scrolledContent.PositionedDescendants(), mOuter);
       if (aBuilder->BuildCompositorHitTestInfo()) {
         CompositorHitTestInfo info = CompositorHitTestInfo::eVisibleToHitTest
                                    | CompositorHitTestInfo::eDispatchToContent;
+        // If the scroll frame has non-default overscroll-behavior, instruct
+        // APZ to require a target confirmation before processing events that
+        // hit this scroll frame (that is, to drop the events if a confirmation
+        // does not arrive within the timeout period). Otherwise, APZ's
+        // fallback behaviour of scrolling the enclosing scroll frame would
+        // violate the specified overscroll-behavior.
+        ScrollbarStyles scrollbarStyles = GetScrollbarStylesFromFrame();
+        if (scrollbarStyles.mOverscrollBehaviorX != StyleOverscrollBehavior::Auto ||
+            scrollbarStyles.mOverscrollBehaviorY != StyleOverscrollBehavior::Auto) {
+          info |= CompositorHitTestInfo::eRequiresTargetConfirmation;
+        }
         nsDisplayCompositorHitTestInfo* hitInfo =
             MakeDisplayItem<nsDisplayCompositorHitTestInfo>(aBuilder, mScrolledFrame, info, 1,
                 Some(mScrollPort + aBuilder->ToReferenceFrame(mOuter)));
         AppendInternalItemToTop(scrolledContent, hitInfo, zIndex);
       }
       if (aBuilder->IsBuildingLayerEventRegions()) {
         nsDisplayLayerEventRegions* inactiveRegionItem =
             MakeDisplayItem<nsDisplayLayerEventRegions>(aBuilder, mScrolledFrame, 1);