Bug 1895742 - Return HandledByContent for touches prevented by touch-action. r=botond,geckoview-reviewers,tthibaud, a=dmeehan

Similar to what we did in bug 1785754, specifically in
hg.mozilla.org/integration/autoland/rev/e05ed4cedf9f , but not eager cases.

Differential Revision: https://phabricator.services.mozilla.com/D212487
This commit is contained in:
Hiroyuki Ikezoe 2024-06-20 21:10:31 +00:00
parent 8ff7f2494c
commit 7861db93b4
5 changed files with 66 additions and 20 deletions

View file

@ -876,7 +876,7 @@ AsyncPanZoomController::GetPinchLockMode() {
}
PointerEventsConsumableFlags AsyncPanZoomController::ArePointerEventsConsumable(
TouchBlockState* aBlock, const MultiTouchInput& aInput) {
TouchBlockState* aBlock, const MultiTouchInput& aInput) const {
uint32_t touchPoints = aInput.mTouches.Length();
if (touchPoints == 0) {
// Cant' do anything with zero touch points

View file

@ -1536,7 +1536,7 @@ class AsyncPanZoomController {
* govern dynamic toolbar and pull-to-refresh behaviour).
*/
PointerEventsConsumableFlags ArePointerEventsConsumable(
TouchBlockState* aBlock, const MultiTouchInput& aInput);
TouchBlockState* aBlock, const MultiTouchInput& aInput) const;
/**
* Clear internal state relating to touch input handling.

View file

@ -1007,10 +1007,11 @@ void InputQueue::SetBrowserGestureResponse(uint64_t aInputBlockId,
ProcessQueue();
}
static APZHandledResult GetHandledResultFor(
const AsyncPanZoomController* aApzc,
const InputBlockState& aCurrentInputBlock, nsEventStatus aEagerStatus) {
if (aCurrentInputBlock.ShouldDropEvents()) {
static APZHandledResult GetHandledResultFor(const AsyncPanZoomController* aApzc,
InputBlockState* aCurrentInputBlock,
nsEventStatus aEagerStatus,
const InputData& aEvent) {
if (aCurrentInputBlock->ShouldDropEvents()) {
return APZHandledResult{APZHandledPlace::HandledByContent, aApzc};
}
@ -1018,6 +1019,20 @@ static APZHandledResult GetHandledResultFor(
return APZHandledResult{APZHandledPlace::HandledByContent, aApzc};
}
if (aEvent.mInputType == MULTITOUCH_INPUT) {
// If the event is a multi touch event and is disallowed by touch-action,
// treat it as if a touch event listener had preventDefault()-ed it.
PointerEventsConsumableFlags consumableFlags =
aApzc->ArePointerEventsConsumable(aCurrentInputBlock->AsTouchBlock(),
aEvent.AsMultiTouchInput());
if (!consumableFlags.mAllowedByTouchAction) {
APZHandledResult result =
APZHandledResult{APZHandledPlace::HandledByContent, aApzc};
result.mOverscrollDirections = ScrollDirections();
return result;
}
}
if (aApzc->IsRootContent()) {
// If the eager status was eIgnore, we would have returned an eager result
// of Unhandled if there had been no event handler. Now that we know the
@ -1033,14 +1048,14 @@ static APZHandledResult GetHandledResultFor(
}
bool mayTriggerPullToRefresh =
aCurrentInputBlock.GetOverscrollHandoffChain()
aCurrentInputBlock->GetOverscrollHandoffChain()
->ScrollingUpWillTriggerPullToRefresh(aApzc);
if (mayTriggerPullToRefresh) {
return APZHandledResult{APZHandledPlace::Unhandled, aApzc, true};
}
auto [willMoveDynamicToolbar, rootApzc] =
aCurrentInputBlock.GetOverscrollHandoffChain()
aCurrentInputBlock->GetOverscrollHandoffChain()
->ScrollingDownWillMoveDynamicToolbar(aApzc);
if (!willMoveDynamicToolbar) {
return APZHandledResult{APZHandledPlace::HandledByContent, aApzc};
@ -1113,7 +1128,8 @@ bool InputQueue::ProcessQueue() {
"\n",
curBlock, curBlock->GetBlockId());
APZHandledResult handledResult =
GetHandledResultFor(target, *curBlock, it->second.mEagerStatus);
GetHandledResultFor(target, curBlock, it->second.mEagerStatus,
*(mQueuedInputs[0]->Input()));
it->second.mCallback(curBlock->GetBlockId(), handledResult);
// The callback is one-shot; discard it after calling it.
mInputBlockCallbacks.erase(it);

View file

@ -26,15 +26,43 @@
<script>
const searchParams = new URLSearchParams(location.search);
let div = document.querySelector("div");
if (searchParams.has("subframe")) {
const scrolledContents = document.createElement("div");
scrolledContents.style.height = "100%";
switch (searchParams.get("descendants")) {
case "subframe": {
const scrolledContents = document.createElement("div");
scrolledContents.style.height = "100%";
div.appendChild(scrolledContents);
div.style.overflow = "auto";
div.appendChild(scrolledContents);
div.style.overflow = "auto";
div = scrolledContents;
div = scrolledContents;
break;
}
case "svg": {
const svg = document.createElementNS(
"http://www.w3.org/2000/svg",
"svg"
);
svg.setAttribute("viewBox", "0 0 16 8");
svg.style.position = "absolute";
const path = document.createElementNS(
"http://www.w3.org/2000/svg",
"path"
);
path.setAttribute("width", "100");
path.setAttribute(
"d",
"M8 1a7 7 0 1 1-7 7 7 7 0 0 1 7-7zm0 3a1 1 0 1 1-1 1 1 1 0 0 1 1-1zm0 3a1 1 0 0 1 1 1v3a1 1 0 0 1-2 0V8a1 1 0 0 1 1-1z"
);
path.setAttribute("fill-rule", "evenodd");
path.setAttribute("fill", "green");
svg.appendChild(path);
div.appendChild(svg);
div.style.position = "absolute";
break;
}
}
if (searchParams.has("scrollable")) {
// Scrollable for dynamic toolbar purposes.
div.style.height = "100vh";

View file

@ -80,13 +80,15 @@ class InputResultDetailTest : BaseSessionTest() {
fun testTouchAction() {
sessionRule.display?.run { setDynamicToolbarMaxHeight(20) }
for (subframe in arrayOf(true, false)) {
for (descendants in arrayOf("subframe", "svg", "nothing")) {
for (scrollable in arrayOf(true, false)) {
for (event in arrayOf(true, false)) {
for (touchAction in arrayOf("auto", "none", "pan-x", "pan-y")) {
var url = TOUCH_ACTION_HTML_PATH + "?"
if (subframe) {
url += "subframe&"
when (descendants) {
"subframe" -> url += "descendants=subframe&"
"svg" -> url += "descendants=svg&"
"nothing" -> {}
}
if (scrollable) {
url += "scrollable&"
@ -103,7 +105,7 @@ class InputResultDetailTest : BaseSessionTest() {
// the pan-x and pan-y cases.
var expectedPlace = if (touchAction == "none") {
PanZoomController.INPUT_RESULT_HANDLED_CONTENT
} else if (scrollable && !subframe) {
} else if (scrollable && descendants != "subframe") {
PanZoomController.INPUT_RESULT_HANDLED
} else {
PanZoomController.INPUT_RESULT_UNHANDLED
@ -123,7 +125,7 @@ class InputResultDetailTest : BaseSessionTest() {
var value = sessionRule.waitForResult(sendDownEvent(50f, 20f))
assertResultDetail(
"`subframe=$subframe, scrollable=$scrollable, event=$event, touch-action=$touchAction`",
"`descendants=$descendants, scrollable=$scrollable, event=$event, touch-action=$touchAction`",
value,
expectedPlace,
expectedScrollableDirections,