Bug 1256589 part.4 Move the implementation of PreventDefault() and add PreventDefaultBeforeDispatch() from dom::Event to WidgetEvent r=smaug
mDefaultPreventedByChrome is hacky. When PresShell handles Escape key events in fullscreen mode, it prevents default of every Escape key events and dispatch it only into chrome. After that, it check mDefaultPreventedByChrome if at least one call of preventDefault() occurred in chrome. Therefore, if we shouldn't set both mDefaultPreventedByChrome and mDefaultPreventedByContent to true before dispatching an event. This the reason why we need a special method, PreventDefaultBeforeDispatch() is needed for setting only mDefaultPrevented to true.
MozReview-Commit-ID: BPSq68GnWw6
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7703,17 +7703,17 @@ nsContentUtils::SendKeyEvent(nsIWidget*
event.refPoint.x = event.refPoint.y = 0;
event.time = PR_IntervalNow();
if (!(aAdditionalFlags & nsIDOMWindowUtils::KEY_FLAG_NOT_SYNTHESIZED_FOR_TESTS)) {
event.mFlags.mIsSynthesizedForTests = true;
}
if (aAdditionalFlags & nsIDOMWindowUtils::KEY_FLAG_PREVENT_DEFAULT) {
- event.mFlags.mDefaultPrevented = true;
+ event.PreventDefaultBeforeDispatch();
}
nsEventStatus status;
nsresult rv = aWidget->DispatchEvent(&event, status);
NS_ENSURE_SUCCESS(rv, rv);
*aDefaultActionTaken = (status != nsEventStatus_eConsumeNoDefault);
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -514,27 +514,17 @@ Event::PreventDefault(JSContext* aCx)
void
Event::PreventDefaultInternal(bool aCalledByDefaultHandler)
{
if (!mEvent->mFlags.mCancelable) {
return;
}
- mEvent->mFlags.mDefaultPrevented = true;
-
- // Note that even if preventDefault() has already been called by chrome,
- // a call of preventDefault() by content needs to overwrite
- // mDefaultPreventedByContent to true because in such case, defaultPrevented
- // must be true when web apps check it after they call preventDefault().
- if (!aCalledByDefaultHandler) {
- mEvent->mFlags.mDefaultPreventedByContent = true;
- } else {
- mEvent->mFlags.mDefaultPreventedByChrome = true;
- }
+ mEvent->PreventDefault(aCalledByDefaultHandler);
if (!IsTrusted()) {
return;
}
WidgetDragEvent* dragEvent = mEvent->AsDragEvent();
if (!dragEvent) {
return;
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -1185,18 +1185,21 @@ EventListenerManager::GetDocShellForTarg
void
EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
WidgetEvent* aEvent,
nsIDOMEvent** aDOMEvent,
EventTarget* aCurrentTarget,
nsEventStatus* aEventStatus)
{
//Set the value of the internal PreventDefault flag properly based on aEventStatus
- if (*aEventStatus == nsEventStatus_eConsumeNoDefault) {
- aEvent->mFlags.mDefaultPrevented = true;
+ if (!aEvent->mFlags.mDefaultPrevented &&
+ *aEventStatus == nsEventStatus_eConsumeNoDefault) {
+ // Assume that if only aEventStatus claims that the event has already been
+ // consumed, the consumer is default event handler.
+ aEvent->PreventDefault();
}
Maybe<nsAutoPopupStatePusher> popupStatePusher;
if (mIsMainThreadELM) {
popupStatePusher.emplace(Event::GetEventPopupControlState(aEvent, *aDOMEvent));
}
bool hasListener = false;
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -2260,21 +2260,24 @@ EventStateManager::DispatchLegacyMouseSc
SendPixelScrollEvent(aTargetFrame, aEvent, stateX,
pixelDeltaX, DELTA_DIRECTION_X);
if (!targetFrame.IsAlive()) {
*aStatus = nsEventStatus_eConsumeNoDefault;
return;
}
}
- if (stateY.mDefaultPrevented || stateX.mDefaultPrevented) {
+ if (stateY.mDefaultPrevented) {
*aStatus = nsEventStatus_eConsumeNoDefault;
- aEvent->mFlags.mDefaultPrevented = true;
- aEvent->mFlags.mDefaultPreventedByContent |=
- stateY.mDefaultPreventedByContent || stateX.mDefaultPreventedByContent;
+ aEvent->PreventDefault(!stateY.mDefaultPreventedByContent);
+ }
+
+ if (stateX.mDefaultPrevented) {
+ *aStatus = nsEventStatus_eConsumeNoDefault;
+ aEvent->PreventDefault(!stateX.mDefaultPreventedByContent);
}
}
void
EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
WidgetWheelEvent* aEvent,
EventState& aState,
int32_t aDelta,
@@ -3173,17 +3176,17 @@ EventStateManager::PostHandleEvent(nsPre
// If the target has scroll-snapping points then we want to handle
// the wheel event on the main thread even if we have APZ enabled. Do
// so and let the APZ know that it should ignore this event. However,
// if the wheel event is synthesized from a Mac trackpad or other device
// that can generate additional momentum events, then we should allow
// APZ to handle it, because it will track the velocity and predicted
// destination from the momentum.
if (wheelEvent->mFlags.mHandledByAPZ) {
- wheelEvent->mFlags.mDefaultPrevented = true;
+ wheelEvent->PreventDefault();
}
action = WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
} else if (wheelEvent->mFlags.mHandledByAPZ) {
action = WheelPrefs::ACTION_NONE;
} else {
action = WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
}
switch (action) {
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -818,17 +818,19 @@ IMEContentObserver::OnMouseButtonEvent(n
notification.mMouseButtonEventData.mModifiers = aMouseEvent->modifiers;
nsresult rv = IMEStateManager::NotifyIME(notification, mWidget);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
bool consumed = (rv == NS_SUCCESS_EVENT_CONSUMED);
- aMouseEvent->mFlags.mDefaultPrevented = consumed;
+ if (consumed) {
+ aMouseEvent->PreventDefault();
+ }
return consumed;
}
void
IMEContentObserver::CharacterDataWillChange(nsIDocument* aDocument,
nsIContent* aContent,
CharacterDataChangeInfo* aInfo)
{
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -7928,33 +7928,42 @@ PresShell::HandleEventInternal(WidgetEve
auto keyCode = aEvent->AsKeyboardEvent()->keyCode;
if (keyCode == NS_VK_ESCAPE) {
nsIDocument* root = nsContentUtils::GetRootDocument(doc);
if (root && root->GetFullscreenElement()) {
// Prevent default action on ESC key press when exiting
// DOM fullscreen mode. This prevents the browser ESC key
// handler from stopping all loads in the document, which
// would cause <video> loads to stop.
- aEvent->mFlags.mDefaultPrevented = true;
+ // XXX We need to claim the Escape key event which will be
+ // dispatched only into chrome is already consumed by
+ // content because we need to prevent its default here
+ // for some reasons (not sure) but we need to detect
+ // if a chrome event handler will call PreventDefault()
+ // again and check it later.
+ aEvent->PreventDefaultBeforeDispatch();
aEvent->mFlags.mOnlyChromeDispatch = true;
// The event listeners in chrome can prevent this ESC behavior by
// calling prevent default on the preceding keydown/press events.
if (!mIsLastChromeOnlyEscapeKeyConsumed &&
aEvent->mMessage == eKeyUp) {
// ESC key released while in DOM fullscreen mode.
// Fully exit all browser windows and documents from
// fullscreen mode.
nsIDocument::AsyncExitFullscreen(nullptr);
}
}
nsCOMPtr<nsIDocument> pointerLockedDoc =
do_QueryReferent(EventStateManager::sPointerLockedDoc);
if (!mIsLastChromeOnlyEscapeKeyConsumed && pointerLockedDoc) {
- aEvent->mFlags.mDefaultPrevented = true;
+ // XXX See above comment to understand the reason why this needs
+ // to claim that the Escape key event is consumed by content
+ // even though it will be dispatched only into chrome.
+ aEvent->PreventDefaultBeforeDispatch();
aEvent->mFlags.mOnlyChromeDispatch = true;
if (aEvent->mMessage == eKeyUp) {
nsIDocument::UnlockPointer();
}
}
}
if (keyCode != NS_VK_ESCAPE && keyCode != NS_VK_SHIFT &&
keyCode != NS_VK_CONTROL && keyCode != NS_VK_ALT &&
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -141,16 +141,34 @@ public:
{
StopPropagation();
mImmediatePropagationStopped = true;
}
inline void StopCrossProcessForwarding()
{
mNoCrossProcessBoundaryForwarding = true;
}
+ inline void PreventDefault(bool aCalledByDefaultHandler = true)
+ {
+ mDefaultPrevented = true;
+ // Note that even if preventDefault() has already been called by chrome,
+ // a call of preventDefault() by content needs to overwrite
+ // mDefaultPreventedByContent to true because in such case, defaultPrevented
+ // must be true when web apps check it after they call preventDefault().
+ if (aCalledByDefaultHandler) {
+ mDefaultPreventedByChrome = true;
+ } else {
+ mDefaultPreventedByContent = true;
+ }
+ }
+ // This should be used only before dispatching events into the DOM tree.
+ inline void PreventDefaultBeforeDispatch()
+ {
+ mDefaultPrevented = true;
+ }
inline void Clear()
{
SetRawFlags(0);
}
// Get if either the instance's bit or the aOther's bit is true, the
// instance's bit becomes true. In other words, this works like:
// eventFlags |= aOther;
@@ -326,22 +344,21 @@ public:
}
/**
* Helper methods for methods of DOM Event.
*/
void StopPropagation() { mFlags.StopPropagation(); }
void StopImmediatePropagation() { mFlags.StopImmediatePropagation(); }
void StopCrossProcessForwarding() { mFlags.StopCrossProcessForwarding(); }
-
- void PreventDefault()
+ void PreventDefault(bool aCalledByDefaultHandler = true)
{
- mFlags.mDefaultPrevented = true;
- mFlags.mDefaultPreventedByChrome = true;
+ mFlags.PreventDefault(aCalledByDefaultHandler);
}
+ void PreventDefaultBeforeDispatch() { mFlags.PreventDefaultBeforeDispatch(); }
/**
* Utils for checking event types
*/
/**
* As*Event() returns the pointer of the instance only when the instance is
* the class or one of its derived class.
--- a/widget/TextEventDispatcher.cpp
+++ b/widget/TextEventDispatcher.cpp
@@ -427,17 +427,17 @@ TextEventDispatcher::DispatchKeyboardEve
WidgetKeyboardEvent keyEvent(true, aMessage, mWidget);
InitEvent(keyEvent);
keyEvent.AssignKeyEventData(aKeyboardEvent, false);
if (aStatus == nsEventStatus_eConsumeNoDefault) {
// If the key event should be dispatched as consumed event, marking it here.
// This is useful to prevent double action. E.g., when the key was already
// handled by system, our chrome shouldn't handle it.
- keyEvent.mFlags.mDefaultPrevented = true;
+ keyEvent.PreventDefaultBeforeDispatch();
}
// Corrects each member for the specific key event type.
if (keyEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING) {
MOZ_ASSERT(!aIndexOfKeypress,
"aIndexOfKeypress must be 0 for non-printable key");
// If the keyboard event isn't caused by printable key, its charCode should
// be 0.
--- a/widget/windows/KeyboardLayout.cpp
+++ b/widget/windows/KeyboardLayout.cpp
@@ -1170,18 +1170,19 @@ NativeKey::InitKeyEvent(WidgetKeyboardEv
break;
case eKeyUp:
aKeyEvent.keyCode = mDOMKeyCode;
// Set defaultPrevented of the key event if the VK_MENU is not a system
// key release, so that the menu bar does not trigger. This helps avoid
// triggering the menu bar for ALT key accelerators used in assistive
// technologies such as Window-Eyes and ZoomText or for switching open
// state of IME.
- aKeyEvent.mFlags.mDefaultPrevented =
- (mOriginalVirtualKeyCode == VK_MENU && mMsg.message != WM_SYSKEYUP);
+ if (mOriginalVirtualKeyCode == VK_MENU && mMsg.message != WM_SYSKEYUP) {
+ aKeyEvent.PreventDefaultBeforeDispatch();
+ }
break;
case eKeyPress:
aKeyEvent.mUniqueId = sUniqueKeyEventId;
break;
default:
MOZ_CRASH("Invalid event message");
}