Bug 1257759 part.7 Add new internal events which represent key events on plugin r=smaug draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Sat, 23 Apr 2016 01:22:49 +0900
changeset 355641 c6852423e47c40e9953b72061262730f7cce35d7
parent 355640 42e304c45cd980f339b29526ab65854d196198ad
child 355642 361be61bc6ff0213e3386427878d2f81321ca0df
push id16345
push usermasayuki@d-toybox.com
push dateSat, 23 Apr 2016 09:42:11 +0000
reviewerssmaug
bugs1257759
milestone48.0a1
Bug 1257759 part.7 Add new internal events which represent key events on plugin r=smaug If a plugin process posts native key events to the widget, it needs to check if the key combination is reserved by chrome because if it's reserved by chrome, the reserved shortcut key handler should be executed and the event shouldn't be handled by the focused plugin. This patches add eKeyDownOnPlugin and eKeyUpOnPlugin. nsXBLWindowKeyHandler will listen to them and handle them as normal keydown and keypress or keyup event. Note that these events won't be fired on content in the default event group and won't be sent to the remote process. MozReview-Commit-ID: H5OKPLtVdr6
dom/base/nsGkAtomList.h
dom/events/EventNameList.h
dom/events/KeyboardEvent.cpp
dom/xbl/nsXBLWindowKeyHandler.cpp
layout/base/nsPresShell.cpp
widget/EventMessageList.h
widget/TextEventDispatcher.cpp
widget/TextEvents.h
widget/WidgetEventImpl.cpp
widget/nsGUIEventIPC.h
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -831,16 +831,18 @@ GK_ATOM(onMozMouseHittest, "onMozMouseHi
 GK_ATOM(onmouseup, "onmouseup")
 GK_ATOM(onMozAfterPaint, "onMozAfterPaint")
 GK_ATOM(onmozbrowserafterkeydown, "onmozbrowserafterkeydown")
 GK_ATOM(onmozbrowserafterkeyup, "onmozbrowserafterkeyup")
 GK_ATOM(onmozbrowserbeforekeydown, "onmozbrowserbeforekeydown")
 GK_ATOM(onmozbrowserbeforekeyup, "onmozbrowserbeforekeyup")
 GK_ATOM(onmozfullscreenchange, "onmozfullscreenchange")
 GK_ATOM(onmozfullscreenerror, "onmozfullscreenerror")
+GK_ATOM(onmozkeydownonplugin, "onmozkeydownonplugin")
+GK_ATOM(onmozkeyuponplugin, "onmozkeyuponplugin")
 GK_ATOM(onmozpointerlockchange, "onmozpointerlockchange")
 GK_ATOM(onmozpointerlockerror, "onmozpointerlockerror")
 GK_ATOM(onmoztimechange, "onmoztimechange")
 GK_ATOM(onMozMousePixelScroll, "onMozMousePixelScroll")
 GK_ATOM(onMozScrolledAreaChanged, "onMozScrolledAreaChanged")
 GK_ATOM(onmoznetworkupload, "onmoznetworkupload")
 GK_ATOM(onmoznetworkdownload, "onmoznetworkdownload")
 GK_ATOM(onmapfolderlistingreq, "onmapfolderlistingreq")
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -241,16 +241,24 @@ EVENT(keydown,
 EVENT(keypress,
       eKeyPress,
       EventNameType_HTMLXUL,
       eKeyboardEventClass)
 EVENT(keyup,
       eKeyUp,
       EventNameType_HTMLXUL,
       eKeyboardEventClass)
+EVENT(mozkeydownonplugin,
+      eKeyDownOnPlugin,
+      EventNameType_None,
+      eKeyboardEventClass)
+EVENT(mozkeyuponplugin,
+      eKeyUpOnPlugin,
+      EventNameType_None,
+      eKeyboardEventClass)
 NON_IDL_EVENT(mozbrowserbeforekeydown,
               eBeforeKeyDown,
               EventNameType_None,
               eBeforeAfterKeyboardEventClass)
 NON_IDL_EVENT(mozbrowserafterkeydown,
               eAfterKeyDown,
               EventNameType_None,
               eBeforeAfterKeyboardEventClass)
--- a/dom/events/KeyboardEvent.cpp
+++ b/dom/events/KeyboardEvent.cpp
@@ -185,19 +185,21 @@ KeyboardEvent::CharCode()
   // If this event is initialized with ctor, we shouldn't check event type.
   if (mInitializedByCtor) {
     return mEvent->AsKeyboardEvent()->charCode;
   }
 
   switch (mEvent->mMessage) {
   case eBeforeKeyDown:
   case eKeyDown:
+  case eKeyDownOnPlugin:
   case eAfterKeyDown:
   case eBeforeKeyUp:
   case eKeyUp:
+  case eKeyUpOnPlugin:
   case eAfterKeyUp:
     return 0;
   case eKeyPress:
     return mEvent->AsKeyboardEvent()->charCode;
   default:
     break;
   }
   return 0;
@@ -231,19 +233,21 @@ KeyboardEvent::Which()
   // If this event is initialized with ctor, which can have independent value.
   if (mInitializedByCtor) {
     return mInitializedWhichValue;
   }
 
   switch (mEvent->mMessage) {
     case eBeforeKeyDown:
     case eKeyDown:
+    case eKeyDownOnPlugin:
     case eAfterKeyDown:
     case eBeforeKeyUp:
     case eKeyUp:
+    case eKeyUpOnPlugin:
     case eAfterKeyUp:
       return KeyCode();
     case eKeyPress:
       //Special case for 4xp bug 62878.  Try to make value of which
       //more closely mirror the values that 4.x gave for RETURN and BACKSPACE
       {
         uint32_t keyCode = mEvent->AsKeyboardEvent()->keyCode;
         if (keyCode == NS_VK_RETURN || keyCode == NS_VK_BACK) {
--- a/dom/xbl/nsXBLWindowKeyHandler.cpp
+++ b/dom/xbl/nsXBLWindowKeyHandler.cpp
@@ -401,24 +401,27 @@ nsXBLWindowKeyHandler::HandleEvent(nsIDO
 
 void
 nsXBLWindowKeyHandler::HandleEventOnCaptureInDefaultEventGroup(
                          nsIDOMKeyEvent* aEvent)
 {
   WidgetKeyboardEvent* widgetKeyboardEvent =
     aEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
 
-  if (widgetKeyboardEvent->mFlags.mOnlySystemGroupDispatchInContent) {
+  if (widgetKeyboardEvent->mIsReserved) {
+    MOZ_RELEASE_ASSERT(
+      widgetKeyboardEvent->mFlags.mOnlySystemGroupDispatchInContent);
     MOZ_RELEASE_ASSERT(
       widgetKeyboardEvent->mFlags.mNoCrossProcessBoundaryForwarding);
     return;
   }
 
   bool isReserved = false;
   if (HasHandlerForEvent(aEvent, &isReserved) && isReserved) {
+    widgetKeyboardEvent->mIsReserved = true;
     // For reserved commands (such as Open New Tab), we don't to wait for
     // the content to answer (so mWantReplyFromContentProcess remains false),
     // neither to give a chance for content to override its behavior.
     widgetKeyboardEvent->StopCrossProcessForwarding();
     // If the key combination is reserved by chrome, we shouldn't expose the
     // keyboard event to web contents because such keyboard events shouldn't be
     // cancelable.  So, it's not good behavior to fire keyboard events but
     // to ignore the defaultPrevented attribute value in chrome.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -7154,20 +7154,20 @@ PresShell::HandleKeyboardEvent(nsINode* 
                                nsEventStatus* aStatus,
                                EventDispatchingCallback* aEventCB)
 {
   MOZ_ASSERT(aTarget);
   
   // return true if the event target is in its child process
   bool targetIsIframe = IsTargetIframe(aTarget);
 
-  // Dispatch event directly if the event is synthesized from
-  // nsITextInputProcessor, or there is no need to fire
-  // beforeKey* and afterKey* events.
+  // Dispatch event directly if the event is a keypress event, a key event on
+  // plugin, or there is no need to fire beforeKey* and afterKey* events.
   if (aEvent.mMessage == eKeyPress ||
+      aEvent.IsKeyEventOnPlugin() ||
       !BeforeAfterKeyboardEventEnabled()) {
     ForwardKeyToInputMethodAppOrDispatch(targetIsIframe, aTarget, aEvent,
                                          aStatus, aEventCB);
     return;
   }
 
   MOZ_ASSERT(aEvent.mMessage == eKeyDown || aEvent.mMessage == eKeyUp);
 
@@ -7224,17 +7224,18 @@ PresShell::HandleKeyboardEvent(nsINode* 
 }
 
 #ifdef MOZ_B2G
 bool
 PresShell::ForwardKeyToInputMethodApp(nsINode* aTarget,
                                       WidgetKeyboardEvent& aEvent,
                                       nsEventStatus* aStatus)
 {
-  if (!XRE_IsParentProcess() || aEvent.mIsSynthesizedByTIP) {
+  if (!XRE_IsParentProcess() || aEvent.mIsSynthesizedByTIP ||
+      aEvent.IsKeyEventOnPlugin()) {
     return false;
   }
 
   if (!mHardwareKeyHandler) {
     nsresult rv;
     mHardwareKeyHandler =
       do_GetService("@mozilla.org/HardwareKeyHandler;1", &rv);
     if (!NS_SUCCEEDED(rv) || !mHardwareKeyHandler) {
--- a/widget/EventMessageList.h
+++ b/widget/EventMessageList.h
@@ -35,16 +35,23 @@ NS_EVENT_MESSAGE(eAllEvents)
 
 // Widget may be destroyed
 NS_EVENT_MESSAGE(eWindowClose)
 
 NS_EVENT_MESSAGE(eKeyPress)
 NS_EVENT_MESSAGE(eKeyUp)
 NS_EVENT_MESSAGE(eKeyDown)
 
+// These messages are dispatched when PluginInstaceChild receives native
+// keyboard events directly and it posts the information to the widget.
+// These messages shouldn't be handled by content and non-reserved chrome
+// event handlers.
+NS_EVENT_MESSAGE(eKeyDownOnPlugin)
+NS_EVENT_MESSAGE(eKeyUpOnPlugin)
+
 NS_EVENT_MESSAGE(eBeforeKeyDown)
 NS_EVENT_MESSAGE(eAfterKeyDown)
 NS_EVENT_MESSAGE(eBeforeKeyUp)
 NS_EVENT_MESSAGE(eAfterKeyUp)
 
 NS_EVENT_MESSAGE(eResize)
 NS_EVENT_MESSAGE(eScroll)
 
--- a/widget/TextEventDispatcher.cpp
+++ b/widget/TextEventDispatcher.cpp
@@ -394,30 +394,39 @@ TextEventDispatcher::DispatchKeyboardEve
 bool
 TextEventDispatcher::DispatchKeyboardEventInternal(
                        EventMessage aMessage,
                        const WidgetKeyboardEvent& aKeyboardEvent,
                        nsEventStatus& aStatus,
                        void* aData,
                        uint32_t aIndexOfKeypress)
 {
-  MOZ_ASSERT(aMessage == eKeyDown || aMessage == eKeyUp ||
+  // Note that this method is also used for dispatching key events on a plugin
+  // because key events on a plugin should be dispatched same as normal key
+  // events.  Then, only some handlers which need to intercept key events
+  // before the focused plugin (e.g., reserved shortcut key handlers) can
+  // consume the events.
+  MOZ_ASSERT(WidgetKeyboardEvent::IsKeyDownOrKeyDownOnPlugin(aMessage) ||
+             WidgetKeyboardEvent::IsKeyUpOrKeyUpOnPlugin(aMessage) ||
              aMessage == eKeyPress, "Invalid aMessage value");
   nsresult rv = GetState();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
   // If the key shouldn't cause keypress events, don't this patch them.
   if (aMessage == eKeyPress && !aKeyboardEvent.ShouldCauseKeypressEvents()) {
     return false;
   }
 
   // Basically, key events shouldn't be dispatched during composition.
-  if (IsComposing()) {
+  // Note that plugin process has different IME context.  Therefore, we don't
+  // need to check our composition state when the key event is fired on a
+  // plugin.
+  if (IsComposing() && !WidgetKeyboardEvent::IsKeyEventOnPlugin(aMessage)) {
     // However, if we need to behave like other browsers, we need the keydown
     // and keyup events.  Note that this behavior is also allowed by D3E spec.
     // FYI: keypress events must not be fired during composition.
     if (!sDispatchKeyEventsDuringComposition || aMessage == eKeyPress) {
       return false;
     }
     // XXX If there was mOnlyContentDispatch for this case, it might be useful
     //     because our chrome doesn't assume that key events are fired during
@@ -438,17 +447,18 @@ TextEventDispatcher::DispatchKeyboardEve
   // 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.
     keyEvent.SetCharCode(0);
   } else {
-    if (aMessage == eKeyDown || aMessage == eKeyUp) {
+    if (WidgetKeyboardEvent::IsKeyDownOrKeyDownOnPlugin(aMessage) ||
+        WidgetKeyboardEvent::IsKeyUpOrKeyUpOnPlugin(aMessage)) {
       MOZ_RELEASE_ASSERT(!aIndexOfKeypress,
         "aIndexOfKeypress must be 0 for either eKeyDown or eKeyUp");
     } else {
       MOZ_RELEASE_ASSERT(
         !aIndexOfKeypress || aIndexOfKeypress < keyEvent.mKeyValue.Length(),
         "aIndexOfKeypress must be 0 - mKeyValue.Length() - 1");
     }
     wchar_t ch =
@@ -461,17 +471,17 @@ TextEventDispatcher::DispatchKeyboardEve
       // So, each key value of eKeyPress events should be a character.
       if (ch) {
         keyEvent.mKeyValue.Assign(ch);
       } else {
         keyEvent.mKeyValue.Truncate();
       }
     }
   }
-  if (aMessage == eKeyUp) {
+  if (WidgetKeyboardEvent::IsKeyUpOrKeyUpOnPlugin(aMessage)) {
     // mIsRepeat of keyup event must be false.
     keyEvent.mIsRepeat = false;
   }
   // mIsComposing should be initialized later.
   keyEvent.mIsComposing = false;
   if (mInputTransactionType == eNativeInputTransaction) {
     // Copy mNativeKeyEvent here because for safety for other users of
     // AssignKeyEventData(), it doesn't copy this.
@@ -484,17 +494,18 @@ TextEventDispatcher::DispatchKeyboardEve
   }
   // TODO: Manage mUniqueId here.
 
   // Request the alternative char codes for the key event.
   // eKeyDown also needs alternative char codes because nsXBLWindowKeyHandler
   // needs to check if a following keypress event is reserved by chrome for
   // stopping propagation of its preceding keydown event.
   keyEvent.alternativeCharCodes.Clear();
-  if ((aMessage == eKeyDown || aMessage == eKeyPress) &&
+  if ((WidgetKeyboardEvent::IsKeyDownOrKeyDownOnPlugin(aMessage) ||
+       aMessage == eKeyPress) &&
       (keyEvent.IsControl() || keyEvent.IsAlt() ||
        keyEvent.IsMeta() || keyEvent.IsOS())) {
     nsCOMPtr<TextEventDispatcherListener> listener =
       do_QueryReferent(mListener);
     if (listener) {
       DebugOnly<WidgetKeyboardEvent> original(keyEvent);
       listener->WillDispatchKeyboardEvent(this, keyEvent, aIndexOfKeypress,
                                           aData);
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -104,16 +104,17 @@ protected:
   WidgetKeyboardEvent()
     : keyCode(0)
     , charCode(0)
     , mPseudoCharCode(0)
     , location(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD)
     , isChar(false)
     , mIsRepeat(false)
     , mIsComposing(false)
+    , mIsReserved(false)
     , mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified)
     , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN)
     , mNativeKeyEvent(nullptr)
     , mUniqueId(0)
 #ifdef XP_MACOSX
     , mNativeKeyCode(0)
     , mNativeModifierFlags(0)
 #endif
@@ -131,27 +132,56 @@ public:
     : WidgetInputEvent(aIsTrusted, aMessage, aWidget, aEventClassID)
     , keyCode(0)
     , charCode(0)
     , mPseudoCharCode(0)
     , location(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD)
     , isChar(false)
     , mIsRepeat(false)
     , mIsComposing(false)
+    , mIsReserved(false)
     , mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified)
     , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN)
     , mNativeKeyEvent(nullptr)
     , mUniqueId(0)
 #ifdef XP_MACOSX
     , mNativeKeyCode(0)
     , mNativeModifierFlags(0)
 #endif
     , mInputMethodAppState(eNotHandled)
     , mIsSynthesizedByTIP(false)
   {
+    // If this is a keyboard event on a plugin, it shouldn't fired on content.
+    mFlags.mOnlySystemGroupDispatchInContent =
+      mFlags.mNoCrossProcessBoundaryForwarding = IsKeyEventOnPlugin();
+  }
+
+  static bool IsKeyDownOrKeyDownOnPlugin(EventMessage aMessage)
+  {
+    return aMessage == eKeyDown || aMessage == eKeyDownOnPlugin;
+  }
+  bool IsKeyDownOrKeyDownOnPlugin() const
+  {
+    return IsKeyDownOrKeyDownOnPlugin(mMessage);
+  }
+  static bool IsKeyUpOrKeyUpOnPlugin(EventMessage aMessage)
+  {
+    return aMessage == eKeyUp || aMessage == eKeyUpOnPlugin;
+  }
+  bool IsKeyUpOrKeyUpOnPlugin() const
+  {
+    return IsKeyUpOrKeyUpOnPlugin(mMessage);
+  }
+  static bool IsKeyEventOnPlugin(EventMessage aMessage)
+  {
+    return aMessage == eKeyDownOnPlugin || aMessage == eKeyUpOnPlugin;
+  }
+  bool IsKeyEventOnPlugin() const
+  {
+    return IsKeyEventOnPlugin(mMessage);
   }
 
   virtual WidgetEvent* Duplicate() const override
   {
     MOZ_ASSERT(mClass == eKeyboardEventClass,
                "Duplicate() must be overridden by sub class");
     // Not copying widget, it is a weak reference.
     WidgetKeyboardEvent* result =
@@ -182,16 +212,19 @@ public:
   bool isChar;
   // Indicates whether the event is generated by auto repeat or not.
   // if this is keyup event, always false.
   bool mIsRepeat;
   // Indicates whether the event is generated during IME (or deadkey)
   // composition.  This is initialized by EventStateManager.  So, key event
   // dispatchers don't need to initialize this.
   bool mIsComposing;
+  // Indicates if the key combination is reserved by chrome.  This is set by
+  // nsXBLWindowKeyHandler at capturing phase of the default event group.
+  bool mIsReserved;
   // DOM KeyboardEvent.key
   KeyNameIndex mKeyNameIndex;
   // DOM KeyboardEvent.code
   CodeNameIndex mCodeNameIndex;
   // DOM KeyboardEvent.key only when mKeyNameIndex is KEY_NAME_INDEX_USE_STRING.
   nsString mKeyValue;
   // DOM KeyboardEvent.code only when mCodeNameIndex is
   // CODE_NAME_INDEX_USE_STRING.
@@ -335,16 +368,17 @@ public:
     keyCode = aEvent.keyCode;
     charCode = aEvent.charCode;
     mPseudoCharCode = aEvent.mPseudoCharCode;
     location = aEvent.location;
     alternativeCharCodes = aEvent.alternativeCharCodes;
     isChar = aEvent.isChar;
     mIsRepeat = aEvent.mIsRepeat;
     mIsComposing = aEvent.mIsComposing;
+    mIsReserved = aEvent.mIsReserved;
     mKeyNameIndex = aEvent.mKeyNameIndex;
     mCodeNameIndex = aEvent.mCodeNameIndex;
     mKeyValue = aEvent.mKeyValue;
     mCodeValue = aEvent.mCodeValue;
     // Don't copy mNativeKeyEvent because it may be referred after its instance
     // is destroyed.
     mNativeKeyEvent = nullptr;
     mUniqueId = aEvent.mUniqueId;
--- a/widget/WidgetEventImpl.cpp
+++ b/widget/WidgetEventImpl.cpp
@@ -160,16 +160,18 @@ WidgetEvent::HasDragEventMessage() const
 
 bool
 WidgetEvent::HasKeyEventMessage() const
 {
   switch (mMessage) {
     case eKeyDown:
     case eKeyPress:
     case eKeyUp:
+    case eKeyDownOnPlugin:
+    case eKeyUpOnPlugin:
     case eBeforeKeyDown:
     case eBeforeKeyUp:
     case eAfterKeyDown:
     case eAfterKeyUp:
       return true;
     default:
       return false;
   }
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -393,16 +393,17 @@ struct ParamTraits<mozilla::WidgetKeyboa
     WriteParam(aMsg, aParam.mKeyValue);
     WriteParam(aMsg, aParam.mCodeValue);
     WriteParam(aMsg, aParam.keyCode);
     WriteParam(aMsg, aParam.charCode);
     WriteParam(aMsg, aParam.mPseudoCharCode);
     WriteParam(aMsg, aParam.alternativeCharCodes);
     WriteParam(aMsg, aParam.isChar);
     WriteParam(aMsg, aParam.mIsRepeat);
+    WriteParam(aMsg, aParam.mIsReserved);
     WriteParam(aMsg, aParam.location);
     WriteParam(aMsg, aParam.mUniqueId);
     WriteParam(aMsg, aParam.mIsSynthesizedByTIP);
     WriteParam(aMsg,
                static_cast<mozilla::WidgetKeyboardEvent::InputMethodAppStateType>
                  (aParam.mInputMethodAppState));
 #ifdef XP_MACOSX
     WriteParam(aMsg, aParam.mNativeKeyCode);
@@ -427,16 +428,17 @@ struct ParamTraits<mozilla::WidgetKeyboa
         ReadParam(aMsg, aIter, &aResult->mKeyValue) &&
         ReadParam(aMsg, aIter, &aResult->mCodeValue) &&
         ReadParam(aMsg, aIter, &aResult->keyCode) &&
         ReadParam(aMsg, aIter, &aResult->charCode) &&
         ReadParam(aMsg, aIter, &aResult->mPseudoCharCode) &&
         ReadParam(aMsg, aIter, &aResult->alternativeCharCodes) &&
         ReadParam(aMsg, aIter, &aResult->isChar) &&
         ReadParam(aMsg, aIter, &aResult->mIsRepeat) &&
+        ReadParam(aMsg, aIter, &aResult->mIsReserved) &&
         ReadParam(aMsg, aIter, &aResult->location) &&
         ReadParam(aMsg, aIter, &aResult->mUniqueId) &&
         ReadParam(aMsg, aIter, &aResult->mIsSynthesizedByTIP) &&
         ReadParam(aMsg, aIter, &inputMethodAppState)
 #ifdef XP_MACOSX
         && ReadParam(aMsg, aIter, &aResult->mNativeKeyCode)
         && ReadParam(aMsg, aIter, &aResult->mNativeModifierFlags)
         && ReadParam(aMsg, aIter, &aResult->mNativeCharacters)