Bug 1542019 - Split the dispatch-to-content flag into three. r=botond,hsivonen
authorKartikaya Gupta <kgupta@mozilla.com>
Thu, 11 Apr 2019 13:31:53 +0000
changeset 469001 a5fe792348ed187dd06b3047d18e731f4dd4b227
parent 469000 a7adb4cb7f66a2b98f8a674458b43f10a4d7bf14
child 469002 5207719835cc7619e481be3ddf85f2fe0b763917
push id35856
push usercsabou@mozilla.com
push dateFri, 12 Apr 2019 03:19:48 +0000
treeherdermozilla-central@940684cd1065 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond, hsivonen
bugs1542019
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1542019 - Split the dispatch-to-content flag into three. r=botond,hsivonen This patch extracts two additional CompositorHitTestInfo flags from the eDispatchToContent flag; eApzAwareListeners for elements that have APZ-aware listeners, and eInactiveScrollframe for inactive scrollframe or unlayerized scrollthumbs. The eDispatchToContent is then renamed to eIrregularArea to reflect the fact that it is used for irregular-shaped areas that require main-thread hit-testing. Additionally, it is important to note that when using the non-WebRender codepath, all three of these flags still end up gettings squashed into the "dispatch to content" region on the EventRegions; when APZ reconstructs a CompositorHitTestInfo it will turn anything in this region back into an eIrregularArea. So this is a lossy round-trip conversion for the non-WebRender case. However it should still result in correct behaviour because the semantics of eIrregularArea result in APZ relying on the main-thread to do hit-testing and so any APZ-aware listeners and inactive scrollframes are also handled by the main-thread. Differential Revision: https://phabricator.services.mozilla.com/D26440
dom/webidl/APZTestData.webidl
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/APZUtils.h
gfx/layers/apz/src/HitTestingTreeNode.cpp
gfx/layers/apz/test/mochitest/apz_test_utils.js
gfx/layers/apz/test/mochitest/helper_hittest_basic.html
gfx/layers/apz/test/mochitest/helper_hittest_pointerevents_svg.html
gfx/layers/apz/test/mochitest/helper_hittest_touchaction.html
gfx/layers/wr/WebRenderCommandBuilder.cpp
gfx/src/CompositorHitTestInfo.h
layout/generic/nsFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/painting/FrameLayerBuilder.cpp
--- a/dom/webidl/APZTestData.webidl
+++ b/dom/webidl/APZTestData.webidl
@@ -30,24 +30,27 @@ dictionary APZBucket {
   sequence<ScrollFrameData> scrollFrames;
 };
 
 [Pref="apz.test.logging_enabled"]
 namespace APZHitResultFlags {
   // These constants should be kept in sync with mozilla::gfx::CompositorHitTestInfo
   const unsigned short INVISIBLE = 0;
   const unsigned short VISIBLE = 0x0001;
-  const unsigned short DISPATCH_TO_CONTENT = 0x0002;
-  const unsigned short PAN_X_DISABLED = 0x0004;
-  const unsigned short PAN_Y_DISABLED = 0x0008;
-  const unsigned short PINCH_ZOOM_DISABLED = 0x0010;
-  const unsigned short DOUBLE_TAP_ZOOM_DISABLED = 0x0020;
-  const unsigned short SCROLLBAR = 0x0040;
-  const unsigned short SCROLLBAR_THUMB = 0x0080;
-  const unsigned short SCROLLBAR_VERTICAL = 0x0100;
+  const unsigned short IRREGULAR_AREA = 0x0002;
+  const unsigned short APZ_AWARE_LISTENERS = 0x0004;
+  const unsigned short INACTIVE_SCROLLFRAME = 0x0008;
+  const unsigned short PAN_X_DISABLED = 0x0010;
+  const unsigned short PAN_Y_DISABLED = 0x0020;
+  const unsigned short PINCH_ZOOM_DISABLED = 0x0040;
+  const unsigned short DOUBLE_TAP_ZOOM_DISABLED = 0x0080;
+  const unsigned short SCROLLBAR = 0x0100;
+  const unsigned short SCROLLBAR_THUMB = 0x0200;
+  const unsigned short SCROLLBAR_VERTICAL = 0x0400;
+  const unsigned short REQUIRES_TARGET_CONFIRMATION = 0x0800;
 };
 
 dictionary APZHitResult {
   float screenX;
   float screenY;
   unsigned short hitResult; // combination of the APZHitResultFlags.* flags
   unsigned long long scrollId;
 };
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -1622,17 +1622,20 @@ nsEventStatus APZCTreeManager::ReceiveIn
   return result;
 }
 
 static TouchBehaviorFlags ConvertToTouchBehavior(
     const CompositorHitTestInfo& info) {
   TouchBehaviorFlags result = AllowedTouchBehavior::UNKNOWN;
   if (info == CompositorHitTestInvisibleToHit) {
     result = AllowedTouchBehavior::NONE;
-  } else if (info.contains(CompositorHitTestFlags::eDispatchToContent)) {
+  } else if (info.contains(CompositorHitTestFlags::eIrregularArea)) {
+    // Note that eApzAwareListeners and eInactiveScrollframe are similar
+    // to eIrregularArea in some respects, but are not relevant for the
+    // purposes of this function, which deals specifically with touch-action.
     result = AllowedTouchBehavior::UNKNOWN;
   } else {
     result = AllowedTouchBehavior::VERTICAL_PAN |
              AllowedTouchBehavior::HORIZONTAL_PAN |
              AllowedTouchBehavior::PINCH_ZOOM |
              AllowedTouchBehavior::DOUBLE_TAP_ZOOM;
     if (info.contains(CompositorHitTestFlags::eTouchActionPanXDisabled)) {
       result &= ~AllowedTouchBehavior::HORIZONTAL_PAN;
--- a/gfx/layers/apz/src/APZUtils.h
+++ b/gfx/layers/apz/src/APZUtils.h
@@ -110,18 +110,17 @@ struct TargetConfirmationFlags {
   explicit TargetConfirmationFlags(bool aTargetConfirmed)
       : mTargetConfirmed(aTargetConfirmed),
         mRequiresTargetConfirmation(false) {}
 
   explicit TargetConfirmationFlags(
       const gfx::CompositorHitTestInfo& aHitTestInfo)
       : mTargetConfirmed(
             (aHitTestInfo != gfx::CompositorHitTestInvisibleToHit) &&
-            !aHitTestInfo.contains(
-                gfx::CompositorHitTestFlags::eDispatchToContent)),
+            (aHitTestInfo & gfx::CompositorHitTestDispatchToContent).isEmpty()),
         mRequiresTargetConfirmation(aHitTestInfo.contains(
             gfx::CompositorHitTestFlags::eRequiresTargetConfirmation)) {}
 
   bool mTargetConfirmed : 1;
   bool mRequiresTargetConfirmation : 1;
 };
 
 enum class AsyncTransformComponent { eLayout, eVisual };
--- a/gfx/layers/apz/src/HitTestingTreeNode.cpp
+++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp
@@ -255,19 +255,26 @@ CompositorHitTestInfo HitTestingTreeNode
 
   // test against event regions in Layer coordinate space
   if (!mEventRegions.mHitRegion.Contains(point.x, point.y)) {
     return result;
   }
 
   result = CompositorHitTestFlags::eVisibleToHitTest;
 
-  if ((mOverride & EventRegionsOverride::ForceDispatchToContent) ||
-      mEventRegions.mDispatchToContentHitRegion.Contains(point.x, point.y)) {
-    result += CompositorHitTestFlags::eDispatchToContent;
+  if (mOverride & EventRegionsOverride::ForceDispatchToContent) {
+    result += CompositorHitTestFlags::eApzAwareListeners;
+  }
+  if (mEventRegions.mDispatchToContentHitRegion.Contains(point.x, point.y)) {
+    // Technically this might be some combination of eInactiveScrollframe,
+    // eApzAwareListeners, and eIrregularArea, because the round-trip through
+    // mEventRegions is lossy. We just convert it back to eIrregularArea
+    // because that's the most conservative option (i.e. eIrregularArea makes
+    // APZ rely on the main thread for everything).
+    result += CompositorHitTestFlags::eIrregularArea;
     if (mEventRegions.mDTCRequiresTargetConfirmation) {
       result += CompositorHitTestFlags::eRequiresTargetConfirmation;
     }
   } else if (gfxPrefs::TouchActionEnabled()) {
     if (mEventRegions.mNoActionRegion.Contains(point.x, point.y)) {
       // set all the touch-action flags as disabled
       result += CompositorHitTestTouchActionMask;
     } else {
--- a/gfx/layers/apz/test/mochitest/apz_test_utils.js
+++ b/gfx/layers/apz/test/mochitest/apz_test_utils.js
@@ -697,18 +697,30 @@ function hitTestScrollbar(params) {
   // The direction flag (APZHitResultFlags.SCROLLBAR_VERTICAL) is added in
   // later, for the vertical test only.
   // The APZHitResultFlags.SCROLLBAR flag will be present regardless of whether
   // the layer is active or inactive because we force layerization of scrollbar
   // tracks. Unfortunately not forcing the layerization results in different
   // behaviour on different platforms which makes testing harder.
   var expectedHitInfo = APZHitResultFlags.VISIBLE | APZHitResultFlags.SCROLLBAR;
   if (params.expectThumb) {
+    // The thumb has listeners which are APZ-aware. With WebRender we are able
+    // to losslessly propagate this flag to APZ, but with non-WebRender the area
+    // ends up in the mDispatchToContentRegion which we then convert back to
+    // a IRREGULAR_AREA flag. This still works correctly since IRREGULAR_AREA
+    // will fall back to the main thread for everything.
+    if (config.isWebRender) {
+      expectedHitInfo |= APZHitResultFlags.APZ_AWARE_LISTENERS;
+      if (params.layerState == LayerState.INACTIVE) {
+        expectedHitInfo |= APZHitResultFlags.INACTIVE_SCROLLFRAME;
+      }
+    } else {
+      expectedHitInfo |= APZHitResultFlags.IRREGULAR_AREA;
+    }
     // We do not generate the layers for thumbs on inactive scrollframes.
-    expectedHitInfo |= APZHitResultFlags.DISPATCH_TO_CONTENT;
     if (params.layerState == LayerState.ACTIVE) {
       expectedHitInfo |= APZHitResultFlags.SCROLLBAR_THUMB;
     }
   }
 
   var scrollframeMsg = (params.layerState == LayerState.ACTIVE)
     ? "active scrollframe" : "inactive scrollframe";
 
--- a/gfx/layers/apz/test/mochitest/helper_hittest_basic.html
+++ b/gfx/layers/apz/test/mochitest/helper_hittest_basic.html
@@ -20,17 +20,19 @@
 function* test(testDriver) {
   var config = getHitTestConfig();
   var utils = config.utils;
 
   var scroller = document.getElementById("scroller");
   var apzaware = document.getElementById("apzaware");
 
   checkHitResult(hitTest(centerOf(scroller)),
-                 APZHitResultFlags.VISIBLE | APZHitResultFlags.DISPATCH_TO_CONTENT,
+                 APZHitResultFlags.VISIBLE |
+                 (config.isWebRender ? APZHitResultFlags.INACTIVE_SCROLLFRAME
+                                     : APZHitResultFlags.IRREGULAR_AREA),
                  utils.getViewId(document.scrollingElement),
                  "inactive scrollframe");
 
   // The apz-aware div (which has a non-passive wheel listener) is not visible
   // and so the hit-test should just return the root scrollframe area that's
   // covering it
   checkHitResult(hitTest(centerOf(apzaware)),
                  APZHitResultFlags.VISIBLE,
@@ -69,17 +71,19 @@ function* test(testDriver) {
                  APZHitResultFlags.VISIBLE,
                  scrollerViewId,
                  "active scrollframe");
 
   // Test the apz-aware block
   var apzawarePosition = centerOf(apzaware); // main thread position
   apzawarePosition.y -= scrollY; // APZ position
   checkHitResult(hitTest(apzawarePosition),
-                 APZHitResultFlags.VISIBLE | APZHitResultFlags.DISPATCH_TO_CONTENT,
+                 APZHitResultFlags.VISIBLE |
+                 (config.isWebRender ? APZHitResultFlags.APZ_AWARE_LISTENERS
+                                     : APZHitResultFlags.IRREGULAR_AREA),
                  scrollerViewId,
                  "active scrollframe - apzaware block");
 
   // Test the scrollbars. Note that this time the vertical scrollthumb is
   // going to be at the bottom of the track. We'll test both the top and the
   // bottom.
 
   // top of scrollbar track
--- a/gfx/layers/apz/test/mochitest/helper_hittest_pointerevents_svg.html
+++ b/gfx/layers/apz/test/mochitest/helper_hittest_pointerevents_svg.html
@@ -130,36 +130,36 @@ function* test(testDriver) {
     // With the first two cases (circle masks) both WebRender and non-WebRender
     // emit dispatch-to-content regions for the right side, so for now we just
     // test for that. Eventually WebRender should be able to stop emitting DTC
     // and we can update this test to be more precise in that case.
     // For the two rectangular test cases we get precise results rather than
     // dispatch-to-content.
     if (testId == 1 || testId == 2) {
       checkHitResult(hitTest({x: bounds.right - verticalScrollbarWidth - 1, y: bounds.y + 1}),
-                     APZHitResultFlags.VISIBLE | APZHitResultFlags.DISPATCH_TO_CONTENT,
+                     APZHitResultFlags.VISIBLE | APZHitResultFlags.IRREGULAR_AREA,
                      rootViewId,
                      `top right of scroller in testcase ${testId}`);
       checkHitResult(hitTest({x: bounds.right - verticalScrollbarWidth - 1, y: bounds.bottom - horizontalScrollbarHeight - 1}),
-                     APZHitResultFlags.VISIBLE | APZHitResultFlags.DISPATCH_TO_CONTENT,
+                     APZHitResultFlags.VISIBLE | APZHitResultFlags.IRREGULAR_AREA,
                      rootViewId,
                      `bottom right of scroller in testcase ${testId}`);
     } else {
       checkHitResult(hitTest({x: bounds.right - verticalScrollbarWidth - 1, y: bounds.y + 1}),
                      APZHitResultFlags.VISIBLE,
                      scrollerViewId,
                      `top right of scroller in testcase ${testId}`);
       checkHitResult(hitTest({x: bounds.right - verticalScrollbarWidth - 1, y: bounds.bottom - horizontalScrollbarHeight - 1}),
                      APZHitResultFlags.VISIBLE,
                      scrollerViewId,
                      `bottom right of scroller in testcase ${testId}`);
     }
 
     checkHitResult(hitTest({x: bounds.right - 1, y: bounds.y + (bounds.height / 2)}),
-                   APZHitResultFlags.VISIBLE | APZHitResultFlags.DISPATCH_TO_CONTENT,
+                   APZHitResultFlags.VISIBLE | APZHitResultFlags.IRREGULAR_AREA,
                    rootViewId,
                    `middle right of scroller in testcase ${testId}`);
   }
 }
 
 waitUntilApzStable()
     .then(runContinuation(test))
     .then(subtestDone);
--- a/gfx/layers/apz/test/mochitest/helper_hittest_touchaction.html
+++ b/gfx/layers/apz/test/mochitest/helper_hittest_touchaction.html
@@ -109,16 +109,22 @@ function* test(testDriver) {
   for (var scroller of document.querySelectorAll(".taBigBox > div")) {
     // layerize all the scrollable divs
     config.utils.setDisplayPortForElement(0, 0, 100, 100, scroller, 1);
   }
   yield waitForApzFlushedRepaints(testDriver);
 
   var scrollId = config.utils.getViewId(document.scrollingElement);
 
+  // Elements with APZ aware listeners round-trip through the dispatch-to-content
+  // region and end up as IRREGULAR_AREA when WebRender is disabled.
+  var touchListenerFlag = config.isWebRender
+        ? APZHitResultFlags.APZ_AWARE_LISTENERS
+        : APZHitResultFlags.IRREGULAR_AREA;
+
   checkHitResult(
       hitTest(centerOf("taNone")),
       APZHitResultFlags.VISIBLE |
       APZHitResultFlags.PAN_X_DISABLED |
       APZHitResultFlags.PAN_Y_DISABLED |
       APZHitResultFlags.PINCH_ZOOM_DISABLED |
       APZHitResultFlags.DOUBLE_TAP_ZOOM_DISABLED,
       scrollId,
@@ -232,31 +238,31 @@ function* test(testDriver) {
       APZHitResultFlags.PAN_Y_DISABLED |
       APZHitResultFlags.PINCH_ZOOM_DISABLED |
       APZHitResultFlags.DOUBLE_TAP_ZOOM_DISABLED,
       scrollId,
       "touch-action: none inside touch-action: manipulation");
   checkHitResult(
       hitTest(centerOf("taInnerManipListener")),
       APZHitResultFlags.VISIBLE |
-      APZHitResultFlags.DISPATCH_TO_CONTENT |
+      touchListenerFlag |
       APZHitResultFlags.DOUBLE_TAP_ZOOM_DISABLED,
       scrollId,
       "div with touch listener inside touch-action: manipulation");
 
   checkHitResult(
       hitTest(centerOf("taListener")),
       APZHitResultFlags.VISIBLE |
-      APZHitResultFlags.DISPATCH_TO_CONTENT,
+      touchListenerFlag,
       scrollId,
       "div with touch listener");
   checkHitResult(
       hitTest(centerOf("taInnerListenerPanX")),
       APZHitResultFlags.VISIBLE |
-      APZHitResultFlags.DISPATCH_TO_CONTENT |
+      touchListenerFlag |
       APZHitResultFlags.PAN_Y_DISABLED |
       APZHitResultFlags.PINCH_ZOOM_DISABLED |
       APZHitResultFlags.DOUBLE_TAP_ZOOM_DISABLED,
       scrollId,
       "touch-action: pan-x inside div with touch listener");
 
   checkHitResult(
       hitTest(centerOf("taScrollerPanY")),
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -746,19 +746,20 @@ struct DIGroup {
                  const LayoutDeviceRect& bounds) {
     wr::LayoutRect dest = wr::ToLayoutRect(bounds);
     GP("PushImage: %f %f %f %f\n", dest.origin.x, dest.origin.y,
        dest.size.width, dest.size.height);
     gfx::SamplingFilter sampleFilter = gfx::SamplingFilter::
         LINEAR;  // nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
     bool backfaceHidden = false;
 
-    // Emit a dispatch-to-content hit test region covering this area
+    // We don't really know the exact shape of this blob because it may contain
+    // SVG shapes so generate an irregular-area hit-test region for it.
     CompositorHitTestInfo hitInfo(CompositorHitTestFlags::eVisibleToHitTest,
-                                  CompositorHitTestFlags::eDispatchToContent);
+                                  CompositorHitTestFlags::eIrregularArea);
 
     // XXX - clipping the item against the paint rect breaks some content.
     // cf. Bug 1455422.
     // wr::LayoutRect clip = wr::ToLayoutRect(bounds.Intersect(mPaintRect));
 
     aBuilder.SetHitTestInfo(mScrollId, hitInfo);
     aBuilder.PushImage(dest, dest, !backfaceHidden,
                        wr::ToImageRendering(sampleFilter),
--- a/gfx/src/CompositorHitTestInfo.h
+++ b/gfx/src/CompositorHitTestInfo.h
@@ -17,57 +17,74 @@ namespace gfx {
 // that is relevant to hit-testing in the compositor. The flags are
 // intentionally set up so that if all of them are 0 the item is effectively
 // invisible to hit-testing, and no information for this frame needs to be
 // sent to the compositor.
 // Each enumerator is annotated with the value it contributes to an
 // EnumSet (2 ^ <value of enumerator>), in hexadecimal.
 enum class CompositorHitTestFlags : uint8_t {
   // The frame participates in hit-testing
-  eVisibleToHitTest = 0,  // 0x001
-  // The frame requires main-thread handling for events
-  eDispatchToContent,  // 0x002
+  eVisibleToHitTest = 0,  // 0x0001
+
+  // The frame may have odd shapes that requires the main thread to do accurate
+  // hit-testing.
+  eIrregularArea,  // 0x0002
+  // The frame has APZ-aware listeners and so inputs targeted at this area
+  // need to be handled by the main thread before APZ can use them, as they
+  // might be prevent-defaulted.
+  eApzAwareListeners,  // 0x0004
+  // This is an inactive scrollframe or unlayerized scrollthumb. In this state
+  // it cannot be used by APZ for async scrolling, so APZ will defer to the main
+  // thread.
+  eInactiveScrollframe,  // 0x0008
 
   // The touch action flags are set up so that the default of
   // touch-action:auto on an element leaves all the flags as 0.
-  eTouchActionPanXDisabled,           // 0x004
-  eTouchActionPanYDisabled,           // 0x008
-  eTouchActionPinchZoomDisabled,      // 0x010
-  eTouchActionDoubleTapZoomDisabled,  // 0x020
+  eTouchActionPanXDisabled,           // 0x0010
+  eTouchActionPanYDisabled,           // 0x0020
+  eTouchActionPinchZoomDisabled,      // 0x0040
+  eTouchActionDoubleTapZoomDisabled,  // 0x0080
 
   // The frame is a scrollbar or a subframe inside a scrollbar (including
   // scroll thumbs)
-  eScrollbar,  // 0x040
+  eScrollbar,  // 0x0100
   // 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,  // 0x080
+  eScrollbarThumb,  // 0x0200
   // If eScrollbar is set, this flag indicates if the scrollbar is a vertical
   // one (if set) or a horizontal one (if not set)
-  eScrollbarVertical,  // 0x100
+  eScrollbarVertical,  // 0x0400
 
   // 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,  // 0x200
+  eRequiresTargetConfirmation,  // 0x0800
 };
 
 using CompositorHitTestInfo = EnumSet<CompositorHitTestFlags, uint32_t>;
 
 // A CompositorHitTestInfo with none of the flags set
 constexpr CompositorHitTestInfo CompositorHitTestInvisibleToHit;
 
 // Mask to check for all the touch-action flags at once
 constexpr CompositorHitTestInfo CompositorHitTestTouchActionMask(
     CompositorHitTestFlags::eTouchActionPanXDisabled,
     CompositorHitTestFlags::eTouchActionPanYDisabled,
     CompositorHitTestFlags::eTouchActionPinchZoomDisabled,
     CompositorHitTestFlags::eTouchActionDoubleTapZoomDisabled);
 
+// Mask to check all the flags that involve APZ waiting for results from the
+// main thread
+constexpr CompositorHitTestInfo CompositorHitTestDispatchToContent(
+    CompositorHitTestFlags::eIrregularArea,
+    CompositorHitTestFlags::eApzAwareListeners,
+    CompositorHitTestFlags::eInactiveScrollframe);
+
 }  // namespace gfx
 
 // Used for IPDL serialization. The 'value' have to be the biggest enum from
 // CompositorHitTestFlags.
 template <>
 struct MaxEnumValue<::mozilla::gfx::CompositorHitTestFlags> {
   static constexpr unsigned int value = static_cast<unsigned int>(
       gfx::CompositorHitTestFlags::eRequiresTargetConfirmation);
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -10900,30 +10900,31 @@ CompositorHitTestInfo nsIFrame::GetCompo
   }
   if (!StyleVisibility()->IsVisible()) {
     return result;
   }
 
   // Anything that didn't match the above conditions is visible to hit-testing.
   result = CompositorHitTestFlags::eVisibleToHitTest;
 
-  if (aBuilder->IsBuildingNonLayerizedScrollbar() ||
-      aBuilder->GetAncestorHasApzAwareEventHandler()) {
+  if (aBuilder->IsBuildingNonLayerizedScrollbar()) {
     // Scrollbars may be painted into a layer below the actual layer they will
     // scroll, and therefore wheel events may be dispatched to the outer frame
     // instead of the intended scrollframe. To address this, we force a d-t-c
     // region on scrollbar frames that won't be placed in their own layer. See
     // bug 1213324 for details.
-    result += CompositorHitTestFlags::eDispatchToContent;
+    result += CompositorHitTestFlags::eInactiveScrollframe;
+  } else if (aBuilder->GetAncestorHasApzAwareEventHandler()) {
+    result += CompositorHitTestFlags::eApzAwareListeners;
   } else if (IsObjectFrame()) {
     // If the frame is a plugin frame and wants to handle wheel events as
     // default action, we should add the frame to dispatch-to-content region.
     nsPluginFrame* pluginFrame = do_QueryFrame(this);
     if (pluginFrame && pluginFrame->WantsToHandleWheelEventAsDefaultAction()) {
-      result += CompositorHitTestFlags::eDispatchToContent;
+      result += CompositorHitTestFlags::eApzAwareListeners;
     }
   }
 
   if (aBuilder->IsTouchEventPrefEnabledDoc()) {
     // Inherit the touch-action flags from the parent, if there is one. We do
     // this because of how the touch-action on a frame combines the touch-action
     // from ancestor DOM elements. Refer to the documentation in
     // TouchActionHelper.cpp for details; this code is meant to be equivalent to
@@ -10980,17 +10981,17 @@ CompositorHitTestInfo nsIFrame::GetCompo
       aBuilder->GetCurrentScrollbarDirection();
   if (scrollDirection.isSome()) {
     if (GetContent()->IsXULElement(nsGkAtoms::thumb)) {
       const bool thumbGetsLayer = aBuilder->GetCurrentScrollbarTarget() !=
                                   layers::ScrollableLayerGuid::NULL_SCROLL_ID;
       if (thumbGetsLayer) {
         result += CompositorHitTestFlags::eScrollbarThumb;
       } else {
-        result += CompositorHitTestFlags::eDispatchToContent;
+        result += CompositorHitTestFlags::eInactiveScrollframe;
       }
     }
 
     if (*scrollDirection == ScrollDirection::eVertical) {
       result += CompositorHitTestFlags::eScrollbarVertical;
     }
 
     // includes the ScrollbarFrame, SliderFrame, anything else that
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3713,17 +3713,17 @@ void ScrollFrameHelper::BuildDisplayList
   }
 
   if (couldBuildLayer) {
     // 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) {
       if (aBuilder->BuildCompositorHitTestInfo()) {
         CompositorHitTestInfo info(CompositorHitTestFlags::eVisibleToHitTest,
-                                   CompositorHitTestFlags::eDispatchToContent);
+                                   CompositorHitTestFlags::eInactiveScrollframe);
         // 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.
         ScrollStyles scrollStyles = GetScrollStylesFromFrame();
         if (scrollStyles.mOverscrollBehaviorX !=
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -3945,17 +3945,18 @@ void PaintedLayerData::AccumulateHitTest
   }
 
   if (hasRoundedCorners || (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
     mMaybeHitRegion.OrWith(area);
   } else {
     mHitRegion.OrWith(area);
   }
 
-  if (flags.contains(CompositorHitTestFlags::eDispatchToContent)) {
+  const auto dtcFlags = flags & CompositorHitTestDispatchToContent;
+  if (!dtcFlags.isEmpty()) {
     mDispatchToContentHitRegion.OrWith(area);
 
     if (flags.contains(CompositorHitTestFlags::eRequiresTargetConfirmation)) {
       mDTCRequiresTargetConfirmation = true;
     }
   }
 
   const auto touchFlags = flags & CompositorHitTestTouchActionMask;