mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
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 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
4669671e38
commit
937b89a55a
@ -35,14 +35,17 @@ 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 {
|
||||
|
@ -1627,7 +1627,10 @@ static TouchBehaviorFlags ConvertToTouchBehavior(
|
||||
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 |
|
||||
|
@ -115,8 +115,7 @@ struct TargetConfirmationFlags {
|
||||
const gfx::CompositorHitTestInfo& aHitTestInfo)
|
||||
: mTargetConfirmed(
|
||||
(aHitTestInfo != gfx::CompositorHitTestInvisibleToHit) &&
|
||||
!aHitTestInfo.contains(
|
||||
gfx::CompositorHitTestFlags::eDispatchToContent)),
|
||||
(aHitTestInfo & gfx::CompositorHitTestDispatchToContent).isEmpty()),
|
||||
mRequiresTargetConfirmation(aHitTestInfo.contains(
|
||||
gfx::CompositorHitTestFlags::eRequiresTargetConfirmation)) {}
|
||||
|
||||
|
@ -260,9 +260,16 @@ CompositorHitTestInfo HitTestingTreeNode::HitTest(
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -702,8 +702,20 @@ function hitTestScrollbar(params) {
|
||||
// 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;
|
||||
}
|
||||
|
@ -25,7 +25,9 @@ function* test(testDriver) {
|
||||
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");
|
||||
|
||||
@ -74,7 +76,9 @@ function* test(testDriver) {
|
||||
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");
|
||||
|
||||
|
@ -135,11 +135,11 @@ function* test(testDriver) {
|
||||
// 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 {
|
||||
@ -154,7 +154,7 @@ function* test(testDriver) {
|
||||
}
|
||||
|
||||
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}`);
|
||||
}
|
||||
|
@ -114,6 +114,12 @@ function* test(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 |
|
||||
@ -237,7 +243,7 @@ function* test(testDriver) {
|
||||
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");
|
||||
@ -245,13 +251,13 @@ function* test(testDriver) {
|
||||
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,
|
||||
|
@ -751,9 +751,10 @@ struct DIGroup {
|
||||
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.
|
||||
|
@ -22,33 +22,43 @@ namespace gfx {
|
||||
// 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>;
|
||||
@ -63,6 +73,13 @@ constexpr CompositorHitTestInfo CompositorHitTestTouchActionMask(
|
||||
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
|
||||
|
@ -10905,20 +10905,21 @@ CompositorHitTestInfo nsIFrame::GetCompositorHitTestInfo(
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -10985,7 +10986,7 @@ CompositorHitTestInfo nsIFrame::GetCompositorHitTestInfo(
|
||||
if (thumbGetsLayer) {
|
||||
result += CompositorHitTestFlags::eScrollbarThumb;
|
||||
} else {
|
||||
result += CompositorHitTestFlags::eDispatchToContent;
|
||||
result += CompositorHitTestFlags::eInactiveScrollframe;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3718,7 +3718,7 @@ void ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
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
|
||||
|
@ -3950,7 +3950,8 @@ void PaintedLayerData::AccumulateHitTestItem(ContainerState* aState,
|
||||
mHitRegion.OrWith(area);
|
||||
}
|
||||
|
||||
if (flags.contains(CompositorHitTestFlags::eDispatchToContent)) {
|
||||
const auto dtcFlags = flags & CompositorHitTestDispatchToContent;
|
||||
if (!dtcFlags.isEmpty()) {
|
||||
mDispatchToContentHitRegion.OrWith(area);
|
||||
|
||||
if (flags.contains(CompositorHitTestFlags::eRequiresTargetConfirmation)) {
|
||||
|
Loading…
Reference in New Issue
Block a user