Bug 1256589 part.4 Move the implementation of PreventDefault() and add PreventDefaultBeforeDispatch() from dom::Event to WidgetEvent r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 22 Mar 2016 16:26:27 +0900
changeset 290043 bfc36cc31ae93c801d600d1010692a4769d3eaff
parent 290042 93b3ea492ea730775bd5c8023195a3e0a1504019
child 290044 0881a3d1697aed1c4878f761652d3da79bad624b
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1256589
milestone48.0a1
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
dom/base/nsContentUtils.cpp
dom/events/Event.cpp
dom/events/EventListenerManager.cpp
dom/events/EventStateManager.cpp
dom/events/IMEContentObserver.cpp
layout/base/nsPresShell.cpp
widget/BasicEvents.h
widget/TextEventDispatcher.cpp
widget/windows/KeyboardLayout.cpp
--- 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");
   }