From aafeee24341b8f010db1226840b5b4dd88058658 Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Tue, 1 Jun 2021 05:47:29 +0000 Subject: [PATCH] Bug 1481923 - Make nsContentUtils::SendMouseEvent return the information where preventDefault() was called. r=masayuki On a long press touch event we fire a contextmenu event and if the contextmenu is opening, we fire a touchcancel event. Unfortunately we had been checking the return value, nsEventStatus, from nsIWidget::DispatchInputEvent via nsContentUtils::SendMouseEvent to tell whether the context menu is opening or not. So, we unintentionally fire the touchcancel event if the context menu is NOT going to be opened because of preventDefault() in a contextmenu event listener in the content itself. NOTE: The oparator<< for the new PreventDefaultResult enum will be used in APZ logging code. [1] https://searchfox.org/mozilla-central/rev/95c41d54c3fd65d51976d5188842a69b459a7589/mobile/android/actors/ContentDelegateChild.jsm#100 Differential Revision: https://phabricator.services.mozilla.com/D115963 --- dom/base/nsContentUtils.cpp | 30 ++++++++++++++++++++-- dom/base/nsContentUtils.h | 14 ++++++++-- dom/base/nsDOMWindowUtils.cpp | 11 ++++++-- gfx/layers/apz/util/APZCCallbackHelper.cpp | 7 ++--- 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 90284e2e8f4f..bed180fb3060 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -8196,7 +8196,7 @@ nsresult nsContentUtils::SendMouseEvent( int32_t aButton, int32_t aButtons, int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, - bool* aPreventDefault, bool aIsDOMEventSynthesized, + PreventDefaultResult* aPreventDefault, bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized) { nsPoint offset; nsCOMPtr widget = GetWidget(aPresShell, &offset); @@ -8278,7 +8278,15 @@ nsresult nsContentUtils::SendMouseEvent( NS_ENSURE_SUCCESS(rv, rv); } if (aPreventDefault) { - *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault); + if (status == nsEventStatus_eConsumeNoDefault) { + if (event.mFlags.mDefaultPreventedByContent) { + *aPreventDefault = PreventDefaultResult::ByContent; + } else { + *aPreventDefault = PreventDefaultResult::ByChrome; + } + } else { + *aPreventDefault = PreventDefaultResult::No; + } } return NS_OK; @@ -10602,3 +10610,21 @@ nsCString nsContentUtils::TruncatedURLForDisplay(nsIURI* aURL, } return spec; } + +namespace mozilla { +std::ostream& operator<<(std::ostream& aOut, + const PreventDefaultResult aPreventDefaultResult) { + switch (aPreventDefaultResult) { + case PreventDefaultResult::No: + aOut << "unhandled"; + break; + case PreventDefaultResult::ByContent: + aOut << "handled-by-content"; + break; + case PreventDefaultResult::ByChrome: + aOut << "handled-by-chrome"; + break; + } + return aOut; +} +} // namespace mozilla diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index e97347037c37..edbd0eedbebf 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -245,6 +245,10 @@ struct EventNameMapping { bool mMaybeSpecialSVGorSMILEvent; }; +namespace mozilla { +enum class PreventDefaultResult : uint8_t { No, ByContent, ByChrome }; +} + class nsContentUtils { friend class nsAutoScriptBlockerSuppressNodeRemoved; typedef mozilla::dom::Element Element; @@ -2916,8 +2920,8 @@ class nsContentUtils { float aY, int32_t aButton, int32_t aButtons, int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, - bool* aPreventDefault, bool aIsDOMEventSynthesized, - bool aIsWidgetEventSynthesized); + mozilla::PreventDefaultResult* aPreventDefault, + bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized); static void FirePageShowEventForFrameLoaderSwap( nsIDocShellTreeItem* aItem, @@ -3492,6 +3496,12 @@ nsContentUtils::InternalContentPolicyTypeToExternal(nsContentPolicyType aType) { } } +namespace mozilla { +std::ostream& operator<<( + std::ostream& aOut, + const mozilla::PreventDefaultResult aPreventDefaultResult); +} // namespace mozilla + class MOZ_RAII nsAutoScriptBlocker { public: explicit nsAutoScriptBlocker() { nsContentUtils::AddScriptBlocker(); } diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index ef7a48f631bc..b6cc4461ff96 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -725,10 +725,17 @@ nsDOMWindowUtils::SendMouseEventCommon( bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, int32_t aButtons) { RefPtr presShell = GetPresShell(); - return nsContentUtils::SendMouseEvent( + PreventDefaultResult preventDefaultResult; + nsresult rv = nsContentUtils::SendMouseEvent( presShell, aType, aX, aY, aButton, aButtons, aClickCount, aModifiers, aIgnoreRootScrollFrame, aPressure, aInputSourceArg, aPointerId, aToWindow, - aPreventDefault, aIsDOMEventSynthesized, aIsWidgetEventSynthesized); + &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized); + + if (aPreventDefault) { + *aPreventDefault = preventDefaultResult != PreventDefaultResult::No; + } + + return rv; } NS_IMETHODIMP diff --git a/gfx/layers/apz/util/APZCCallbackHelper.cpp b/gfx/layers/apz/util/APZCCallbackHelper.cpp index f42825f09ed7..838c82257969 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -551,13 +551,14 @@ bool APZCCallbackHelper::DispatchMouseEvent( unsigned short aInputSourceArg, uint32_t aPointerId) { NS_ENSURE_TRUE(aPresShell, true); - bool defaultPrevented = false; + PreventDefaultResult preventDefaultResult; nsContentUtils::SendMouseEvent( aPresShell, aType, aPoint.x, aPoint.y, aButton, nsIDOMWindowUtils::MOUSE_BUTTONS_NOT_SPECIFIED, aClickCount, aModifiers, /* aIgnoreRootScrollFrame = */ false, 0, aInputSourceArg, aPointerId, - false, &defaultPrevented, false, /* aIsWidgetEventSynthesized = */ false); - return defaultPrevented; + false, &preventDefaultResult, false, + /* aIsWidgetEventSynthesized = */ false); + return preventDefaultResult != PreventDefaultResult::No; } void APZCCallbackHelper::FireSingleTapEvent(const LayoutDevicePoint& aPoint,