Bug 1339543 part 4 Change nsIWidget::ExecuteNativeKeyBinding() to nsIWidget::GetEditCommands() which just retrieves edit commands for the type r?smaug draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 19 May 2017 17:49:41 +0900
changeset 581130 ae6b5c1e3c6c712c5532e3ba5095e0d4ae824cc6
parent 581129 e8fea9d1aac6bf840a19f772aacd93e9c5c7168f
child 581131 714cde97e14680ea2bb4b657b805b4ef7c58da96
push id59777
push usermasayuki@d-toybox.com
push dateFri, 19 May 2017 09:49:08 +0000
reviewerssmaug
bugs1339543
milestone55.0a1
Bug 1339543 part 4 Change nsIWidget::ExecuteNativeKeyBinding() to nsIWidget::GetEditCommands() which just retrieves edit commands for the type r?smaug Now, nsIWidget::ExecuteNativeKeyBinding() isn't used by anybody for executing edit commands. Instead, they need array of edit commands for the key combination. So, the method should be renamed to GetEditCommands() and just return edit commands as an array. MozReview-Commit-ID: 4G0B1lJ8Lbe
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
widget/PuppetWidget.cpp
widget/PuppetWidget.h
widget/TextEvents.h
widget/WidgetEventImpl.cpp
widget/cocoa/NativeKeyBindings.h
widget/cocoa/NativeKeyBindings.mm
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
widget/gtk/NativeKeyBindings.cpp
widget/gtk/NativeKeyBindings.h
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
widget/nsIWidget.h
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1873,31 +1873,47 @@ TabChild::RecvPluginEvent(const WidgetPl
   if (status != nsEventStatus_eConsumeNoDefault) {
     // If not consumed, we should call default action
     SendDefaultProcOfPluginEvent(aEvent);
   }
   return IPC_OK();
 }
 
 void
-TabChild::RequestNativeKeyBindings(AutoCacheNativeKeyCommands* aAutoCache,
-                                   const WidgetKeyboardEvent* aEvent)
+TabChild::RequestNativeKeyBindings(nsIWidget::NativeKeyBindingsType aType,
+                                   const WidgetKeyboardEvent& aEvent,
+                                   nsTArray<CommandInt>& aCommands)
 {
-  MaybeNativeKeyBinding maybeBindings;
-  if (!SendRequestNativeKeyBindings(*aEvent, &maybeBindings)) {
+  MOZ_ASSERT(aCommands.IsEmpty());
+
+  if (NS_WARN_IF(aEvent.IsEditCommandsInitialized(aType))) {
+    aCommands = aEvent.EditCommandsConstRef(aType);
     return;
   }
 
-  if (maybeBindings.type() == MaybeNativeKeyBinding::TNativeKeyBinding) {
-    const NativeKeyBinding& bindings = maybeBindings;
-    aAutoCache->Cache(bindings.singleLineCommands(),
-                      bindings.multiLineCommands(),
-                      bindings.richTextCommands());
-  } else {
-    aAutoCache->CacheNoCommands();
+  // TODO: Should retrieve edit commands only for specific type.
+  MaybeNativeKeyBinding maybeBindings;
+  if (!SendRequestNativeKeyBindings(aEvent, &maybeBindings) ||
+      maybeBindings.type() != MaybeNativeKeyBinding::TNativeKeyBinding) {
+    return;
+  }
+
+  const NativeKeyBinding& bindings = maybeBindings;
+  switch (aType) {
+    case nsIWidget::NativeKeyBindingsForSingleLineEditor:
+      aCommands = bindings.singleLineCommands();
+      break;
+    case nsIWidget::NativeKeyBindingsForMultiLineEditor:
+      aCommands = bindings.multiLineCommands();
+      break;
+    case nsIWidget::NativeKeyBindingsForRichTextEditor:
+      aCommands = bindings.richTextCommands();
+      break;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Invalid native key bindings type");
   }
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvNativeSynthesisResponse(const uint64_t& aObserverId,
                                       const nsCString& aResponse)
 {
   mozilla::widget::AutoObserverNotifier::NotifySavedObserver(aObserverId,
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -506,18 +506,19 @@ public:
   void GetMaxTouchPoints(uint32_t* aTouchPoints);
 
   ScreenOrientationInternal GetOrientation() const { return mOrientation; }
 
   void SetBackgroundColor(const nscolor& aColor);
 
   void NotifyPainted();
 
-  void RequestNativeKeyBindings(mozilla::widget::AutoCacheNativeKeyCommands* aAutoCache,
-                                const WidgetKeyboardEvent* aEvent);
+  void RequestNativeKeyBindings(nsIWidget::NativeKeyBindingsType aType,
+                                const WidgetKeyboardEvent& aEvent,
+                                nsTArray<CommandInt>& aCommands);
 
   /**
    * Signal to this TabChild that it should be made visible:
    * activated widget, retained layer tree, etc.  (Respectively,
    * made not visible.)
    */
   void MakeVisible();
   void MakeHidden();
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1209,54 +1209,45 @@ TabParent::RecvDispatchKeyboardEvent(con
   WidgetKeyboardEvent localEvent(aEvent);
   localEvent.mWidget = widget;
   localEvent.mRefPoint -= GetChildProcessOffset();
 
   widget->DispatchInputEvent(&localEvent);
   return IPC_OK();
 }
 
-static void
-DoCommandCallback(mozilla::Command aCommand, void* aData)
-{
-  static_cast<InfallibleTArray<mozilla::CommandInt>*>(aData)->
-    AppendElement(aCommand);
-}
-
 mozilla::ipc::IPCResult
 TabParent::RecvRequestNativeKeyBindings(const WidgetKeyboardEvent& aEvent,
                                         MaybeNativeKeyBinding* aBindings)
 {
-  AutoTArray<mozilla::CommandInt, 4> singleLine;
-  AutoTArray<mozilla::CommandInt, 4> multiLine;
-  AutoTArray<mozilla::CommandInt, 4> richText;
-
   *aBindings = mozilla::void_t();
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return IPC_OK();
   }
 
   WidgetKeyboardEvent localEvent(aEvent);
+  localEvent.mWidget = widget;
 
   if (NS_FAILED(widget->AttachNativeKeyEvent(localEvent))) {
     return IPC_OK();
   }
 
-  widget->ExecuteNativeKeyBinding(
-            nsIWidget::NativeKeyBindingsForSingleLineEditor,
-            localEvent, DoCommandCallback, &singleLine);
-  widget->ExecuteNativeKeyBinding(
-            nsIWidget::NativeKeyBindingsForMultiLineEditor,
-            localEvent, DoCommandCallback, &multiLine);
-  widget->ExecuteNativeKeyBinding(
-            nsIWidget::NativeKeyBindingsForRichTextEditor,
-            localEvent, DoCommandCallback, &richText);
-
+  localEvent.InitAllEditCommands();
+
+  const nsTArray<CommandInt>& multiLine =
+    localEvent.EditCommandsConstRef(
+                 nsIWidget::NativeKeyBindingsForSingleLineEditor);
+  const nsTArray<CommandInt>& singleLine =
+    localEvent.EditCommandsConstRef(
+                 nsIWidget::NativeKeyBindingsForMultiLineEditor);
+  const nsTArray<CommandInt>& richText =
+    localEvent.EditCommandsConstRef(
+                 nsIWidget::NativeKeyBindingsForRichTextEditor);
   if (!singleLine.IsEmpty() || !multiLine.IsEmpty() || !richText.IsEmpty()) {
     *aBindings = NativeKeyBinding(singleLine, multiLine, richText);
   }
 
   return IPC_OK();
 }
 
 class SynthesizedEventObserver : public nsIObserver
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -544,60 +544,25 @@ PuppetWidget::UpdateZoomConstraints(cons
 }
 
 bool
 PuppetWidget::AsyncPanZoomEnabled() const
 {
   return mTabChild && mTabChild->AsyncPanZoomEnabled();
 }
 
-bool
-PuppetWidget::ExecuteNativeKeyBinding(
-                NativeKeyBindingsType aType,
-                const mozilla::WidgetKeyboardEvent& aEvent,
-                DoCommandCallback aCallback,
-                void* aCallbackData)
+void
+PuppetWidget::GetEditCommands(NativeKeyBindingsType aType,
+                              const WidgetKeyboardEvent& aEvent,
+                              nsTArray<CommandInt>& aCommands)
 {
-  MOZ_ASSERT(!aEvent.IsEditCommandsInitialized(aType));
-
-  AutoCacheNativeKeyCommands autoCache(this);
-  if (!mNativeKeyCommandsValid) {
-    // Abort if untrusted to avoid leaking system settings
-    if (NS_WARN_IF(!aEvent.IsTrusted())) {
-      return false;
-    }
-    mTabChild->RequestNativeKeyBindings(&autoCache, &aEvent);
-  }
-
-  MOZ_ASSERT(mNativeKeyCommandsValid);
+  // Validate the arguments.
+  nsIWidget::GetEditCommands(aType, aEvent, aCommands);
 
-  const nsTArray<mozilla::CommandInt>* commands = nullptr;
-  switch (aType) {
-    case nsIWidget::NativeKeyBindingsForSingleLineEditor:
-      commands = &mSingleLineCommands;
-      break;
-    case nsIWidget::NativeKeyBindingsForMultiLineEditor:
-      commands = &mMultiLineCommands;
-      break;
-    case nsIWidget::NativeKeyBindingsForRichTextEditor:
-      commands = &mRichTextCommands;
-      break;
-    default:
-      MOZ_CRASH("Invalid type");
-      break;
-  }
-
-  if (commands->IsEmpty()) {
-    return false;
-  }
-
-  for (uint32_t i = 0; i < commands->Length(); i++) {
-    aCallback(static_cast<mozilla::Command>((*commands)[i]), aCallbackData);
-  }
-  return true;
+  mTabChild->RequestNativeKeyBindings(aType, aEvent, aCommands);
 }
 
 LayerManager*
 PuppetWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
                               LayersBackend aBackendHint,
                               LayerManagerPersistence aPersistence)
 {
   if (!mLayerManager) {
--- a/widget/PuppetWidget.h
+++ b/widget/PuppetWidget.h
@@ -152,21 +152,20 @@ public:
   nsEventStatus DispatchInputEvent(WidgetInputEvent* aEvent) override;
   void SetConfirmedTargetAPZC(uint64_t aInputBlockId,
                               const nsTArray<ScrollableLayerGuid>& aTargets) const override;
   void UpdateZoomConstraints(const uint32_t& aPresShellId,
                              const FrameMetrics::ViewID& aViewId,
                              const mozilla::Maybe<ZoomConstraints>& aConstraints) override;
   bool AsyncPanZoomEnabled() const override;
 
-  virtual bool
-  ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
-                          const mozilla::WidgetKeyboardEvent& aEvent,
-                          DoCommandCallback aCallback,
-                          void* aCallbackData) override;
+  virtual void GetEditCommands(
+                 NativeKeyBindingsType aType,
+                 const mozilla::WidgetKeyboardEvent& aEvent,
+                 nsTArray<mozilla::CommandInt>& aCommands) override;
 
   friend struct AutoCacheNativeKeyCommands;
 
   //
   // nsBaseWidget methods we override
   //
 
   // Documents loaded in child processes are always subdocuments of
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -304,28 +304,37 @@ public:
     mEditCommandsForSingleLineEditor.Clear();
     mEditCommandsForMultiLineEditor.Clear();
     mEditCommandsForRichTextEditor.Clear();
     mEditCommandsForSingleLineEditorInitialized = true;
     mEditCommandsForMultiLineEditorInitialized = true;
     mEditCommandsForRichTextEditorInitialized = true;
   }
 
-#ifdef DEBUG
+  /**
+   * EditCommandsConstRef() returns reference to edit commands for aType.
+   */
+  const nsTArray<CommandInt>&
+    EditCommandsConstRef(nsIWidget::NativeKeyBindingsType aType) const
+  {
+    return const_cast<WidgetKeyboardEvent*>(this)->EditCommandsRef(aType);
+  }
+
   /**
    * IsEditCommandsInitialized() returns true if edit commands for aType
    * was already initialized.  Otherwise, false.
    */
   bool IsEditCommandsInitialized(
          nsIWidget::NativeKeyBindingsType aType) const
   {
     return const_cast<WidgetKeyboardEvent*>(this)->
              IsEditCommandsInitializedRef(aType);
   }
 
+#ifdef DEBUG
   /**
    * AreAllEditCommandsInitialized() returns true if edit commands for all
    * types were already initialized.  Otherwise, false.
    */
   bool AreAllEditCommandsInitialized() const
   {
     return mEditCommandsForSingleLineEditorInitialized &&
            mEditCommandsForMultiLineEditorInitialized &&
@@ -334,18 +343,19 @@ public:
 #endif // #ifdef DEBUG
 
   /**
    * Execute edit commands for aType.
    *
    * @return        true if the caller should do nothing anymore.
    *                false, otherwise.
    */
+  typedef void (*DoCommandCallback)(Command, void*);
   bool ExecuteEditCommands(nsIWidget::NativeKeyBindingsType aType,
-                           nsIWidget::DoCommandCallback aCallback,
+                           DoCommandCallback aCallback,
                            void* aCallbackData);
 
   // If the key should cause keypress events, this returns true.
   // Otherwise, false.
   bool ShouldCauseKeypressEvents() const;
 
   // mCharCode value of non-eKeyPress events is always 0.  However, if
   // non-eKeyPress event has one or more alternative char code values,
--- a/widget/WidgetEventImpl.cpp
+++ b/widget/WidgetEventImpl.cpp
@@ -623,40 +623,34 @@ WidgetKeyboardEvent::InitAllEditCommands
   MOZ_ASSERT(!AreAllEditCommandsInitialized(),
     "Shouldn't be called two or more times");
 
   InitEditCommandsFor(nsIWidget::NativeKeyBindingsForSingleLineEditor);
   InitEditCommandsFor(nsIWidget::NativeKeyBindingsForMultiLineEditor);
   InitEditCommandsFor(nsIWidget::NativeKeyBindingsForRichTextEditor);
 }
 
-static void
-DoCommandCallback(Command aCommand, void* aData)
-{
-  static_cast<nsTArray<CommandInt>*>(aData)->AppendElement(aCommand);
-}
-
 void
 WidgetKeyboardEvent::InitEditCommandsFor(nsIWidget::NativeKeyBindingsType aType)
 {
   MOZ_ASSERT(mWidget);
   MOZ_RELEASE_ASSERT(IsTrusted());
 
   bool& initialized = IsEditCommandsInitializedRef(aType);
   if (initialized) {
     return;
   }
   nsTArray<CommandInt>& commands = EditCommandsRef(aType);
-  mWidget->ExecuteNativeKeyBinding(aType, *this, DoCommandCallback, &commands);
+  mWidget->GetEditCommands(aType, *this, commands);
   initialized = true;
 }
 
 bool
 WidgetKeyboardEvent::ExecuteEditCommands(nsIWidget::NativeKeyBindingsType aType,
-                                         nsIWidget::DoCommandCallback aCallback,
+                                         DoCommandCallback aCallback,
                                          void* aCallbackData)
 {
   // If the event was created without widget, e.g., created event in chrome
   // script, this shouldn't execute native key bindings.
   if (NS_WARN_IF(!mWidget)) {
     return false;
   }
 
--- a/widget/cocoa/NativeKeyBindings.h
+++ b/widget/cocoa/NativeKeyBindings.h
@@ -16,27 +16,25 @@ namespace mozilla {
 namespace widget {
 
 typedef nsDataHashtable<nsPtrHashKey<struct objc_selector>, CommandInt>
   SelectorCommandHashtable;
 
 class NativeKeyBindings final
 {
   typedef nsIWidget::NativeKeyBindingsType NativeKeyBindingsType;
-  typedef nsIWidget::DoCommandCallback DoCommandCallback;
 
 public:
   static NativeKeyBindings* GetInstance(NativeKeyBindingsType aType);
   static void Shutdown();
 
   void Init(NativeKeyBindingsType aType);
 
-  bool Execute(const WidgetKeyboardEvent& aEvent,
-               DoCommandCallback aCallback,
-               void* aCallbackData);
+  void GetEditCommands(const WidgetKeyboardEvent& aEvent,
+                       nsTArray<CommandInt>& aCommands);
 
 private:
   NativeKeyBindings();
 
   SelectorCommandHashtable mSelectorToCommand;
 
   static NativeKeyBindings* sInstanceForSingleLineEditor;
   static NativeKeyBindings* sInstanceForMultiLineEditor;
--- a/widget/cocoa/NativeKeyBindings.mm
+++ b/widget/cocoa/NativeKeyBindings.mm
@@ -190,100 +190,93 @@ NativeKeyBindings::Init(NativeKeyBinding
   // SEL_TO_COMMAND(transpose:, );
   // SEL_TO_COMMAND(transposeWords:, );
   // SEL_TO_COMMAND(uppercaseWord:, );
   // SEL_TO_COMMAND(yank:, );
 }
 
 #undef SEL_TO_COMMAND
 
-bool
-NativeKeyBindings::Execute(const WidgetKeyboardEvent& aEvent,
-                           DoCommandCallback aCallback,
-                           void* aCallbackData)
+void
+NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
+                                   nsTArray<CommandInt>& aCommands)
 {
+  MOZ_ASSERT(aCommands.IsEmpty());
+
   MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
-    ("%p NativeKeyBindings::KeyPress", this));
+    ("%p NativeKeyBindings::GetEditCommands", this));
 
   // Recover the current event, which should always be the key down we are
   // responding to.
 
   NSEvent* cocoaEvent = reinterpret_cast<NSEvent*>(aEvent.mNativeKeyEvent);
 
   if (!cocoaEvent || [cocoaEvent type] != NSKeyDown) {
     MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
-      ("%p NativeKeyBindings::KeyPress, no Cocoa key down event", this));
+      ("%p NativeKeyBindings::GetEditCommands, no Cocoa key down event", this));
 
-    return false;
+    return;
   }
 
   MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
-    ("%p NativeKeyBindings::KeyPress, interpreting", this));
+    ("%p NativeKeyBindings::GetEditCommands, interpreting", this));
 
   AutoTArray<KeyBindingsCommand, 2> bindingCommands;
   nsCocoaUtils::GetCommandsFromKeyEvent(cocoaEvent, bindingCommands);
 
   MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
-    ("%p NativeKeyBindings::KeyPress, bindingCommands=%" PRIuSIZE,
+    ("%p NativeKeyBindings::GetEditCommands, bindingCommands=%" PRIuSIZE,
      this, bindingCommands.Length()));
 
-  AutoTArray<Command, 4> geckoCommands;
-
   for (uint32_t i = 0; i < bindingCommands.Length(); i++) {
     SEL selector = bindingCommands[i].selector;
 
     if (MOZ_LOG_TEST(gNativeKeyBindingsLog, LogLevel::Info)) {
       NSString* selectorString = NSStringFromSelector(selector);
       nsAutoString nsSelectorString;
       nsCocoaUtils::GetStringForNSString(selectorString, nsSelectorString);
 
       MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
-        ("%p NativeKeyBindings::KeyPress, selector=%s",
+        ("%p NativeKeyBindings::GetEditCommands, selector=%s",
          this, NS_LossyConvertUTF16toASCII(nsSelectorString).get()));
     }
 
     // Try to find a simple mapping in the hashtable
-    Command geckoCommand = static_cast<Command>(mSelectorToCommand.Get(
-      reinterpret_cast<struct objc_selector*>(selector)));
+    CommandInt geckoCommand =
+      mSelectorToCommand.Get(reinterpret_cast<struct objc_selector*>(selector));
 
     if (geckoCommand) {
-      geckoCommands.AppendElement(geckoCommand);
+      aCommands.AppendElement(geckoCommand);
     } else if (selector == @selector(selectLine:)) {
       // This is functional, but Cocoa's version is direction-less in that
       // selection direction is not determined until some future directed action
       // is taken. See bug 282097, comment 79 for more details.
-      geckoCommands.AppendElement(CommandBeginLine);
-      geckoCommands.AppendElement(CommandSelectEndLine);
+      aCommands.AppendElement(CommandBeginLine);
+      aCommands.AppendElement(CommandSelectEndLine);
     } else if (selector == @selector(selectWord:)) {
       // This is functional, but Cocoa's version is direction-less in that
       // selection direction is not determined until some future directed action
       // is taken. See bug 282097, comment 79 for more details.
-      geckoCommands.AppendElement(CommandWordPrevious);
-      geckoCommands.AppendElement(CommandSelectWordNext);
+      aCommands.AppendElement(CommandWordPrevious);
+      aCommands.AppendElement(CommandSelectWordNext);
     }
   }
 
-  if (geckoCommands.IsEmpty()) {
-    MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
-      ("%p NativeKeyBindings::KeyPress, handled=false", this));
-
-    return false;
+  if (!MOZ_LOG_TEST(gNativeKeyBindingsLog, LogLevel::Info)) {
+    return;
   }
 
-  for (uint32_t i = 0; i < geckoCommands.Length(); i++) {
-    Command geckoCommand = geckoCommands[i];
-
+  if (aCommands.IsEmpty()) {
     MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
-      ("%p NativeKeyBindings::KeyPress, command=%s",
-       this, WidgetKeyboardEvent::GetCommandStr(geckoCommand)));
-
-    // Execute the Gecko command
-    aCallback(geckoCommand, aCallbackData);
+      ("%p NativeKeyBindings::GetEditCommands, handled=false", this));
+    return;
   }
 
-  MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
-    ("%p NativeKeyBindings::KeyPress, handled=true", this));
-
-  return true;
+  for (CommandInt commandInt : aCommands) {
+    Command geckoCommand = static_cast<Command>(commandInt);
+    MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
+      ("%p NativeKeyBindings::GetEditCommands, command=%s",
+       this, WidgetKeyboardEvent::GetCommandStr(geckoCommand)));
+  }
 }
 
 } // namespace widget
 } // namespace mozilla
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -387,28 +387,25 @@ public:
                     GetSelectionAsPlaintext(nsAString& aResult) override;
 
   virtual void SetInputContext(const InputContext& aContext,
                                const InputContextAction& aAction) override;
   virtual InputContext GetInputContext() override;
   virtual TextEventDispatcherListener*
     GetNativeTextEventDispatcherListener() override;
   virtual MOZ_MUST_USE nsresult AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) override;
-  virtual bool ExecuteNativeKeyBinding(
-                      NativeKeyBindingsType aType,
-                      const mozilla::WidgetKeyboardEvent& aEvent,
-                      DoCommandCallback aCallback,
-                      void* aCallbackData) override;
-  bool ExecuteNativeKeyBindingRemapped(
-                      NativeKeyBindingsType aType,
-                      const mozilla::WidgetKeyboardEvent& aEvent,
-                      DoCommandCallback aCallback,
-                      void* aCallbackData,
-                      uint32_t aGeckoKeyCode,
-                      uint32_t aCocoaKeyCode);
+  virtual void GetEditCommands(
+                 NativeKeyBindingsType aType,
+                 const mozilla::WidgetKeyboardEvent& aEvent,
+                 nsTArray<mozilla::CommandInt>& aCommands) override;
+  void GetEditCommandsRemapped(NativeKeyBindingsType aType,
+                               const mozilla::WidgetKeyboardEvent& aEvent,
+                               nsTArray<mozilla::CommandInt>& aCommands,
+                               uint32_t aGeckoKeyCode,
+                               uint32_t aCocoaKeyCode);
 
   virtual nsTransparencyMode GetTransparencyMode() override;
   virtual void                SetTransparencyMode(nsTransparencyMode aMode) override;
 
   virtual nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
                                             int32_t aNativeKeyCode,
                                             uint32_t aModifierFlags,
                                             const nsAString& aCharacters,
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -1845,23 +1845,22 @@ nsChildView::GetNativeTextEventDispatche
 
 nsresult
 nsChildView::AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent)
 {
   NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
   return mTextInputHandler->AttachNativeKeyEvent(aEvent);
 }
 
-bool
-nsChildView::ExecuteNativeKeyBindingRemapped(NativeKeyBindingsType aType,
-                                             const WidgetKeyboardEvent& aEvent,
-                                             DoCommandCallback aCallback,
-                                             void* aCallbackData,
-                                             uint32_t aGeckoKeyCode,
-                                             uint32_t aCocoaKeyCode)
+void
+nsChildView::GetEditCommandsRemapped(NativeKeyBindingsType aType,
+                                     const WidgetKeyboardEvent& aEvent,
+                                     nsTArray<CommandInt>& aCommands,
+                                     uint32_t aGeckoKeyCode,
+                                     uint32_t aCocoaKeyCode)
 {
   NSEvent *originalEvent = reinterpret_cast<NSEvent*>(aEvent.mNativeKeyEvent);
 
   WidgetKeyboardEvent modifiedEvent(aEvent);
   modifiedEvent.mKeyCode = aGeckoKeyCode;
 
   unichar ch = nsCocoaUtils::ConvertGeckoKeyCodeToMacCharCode(aGeckoKeyCode);
   NSString *chars =
@@ -1875,30 +1874,33 @@ nsChildView::ExecuteNativeKeyBindingRema
                  windowNumber:[originalEvent windowNumber]
                       context:[originalEvent context]
                    characters:chars
   charactersIgnoringModifiers:chars
                     isARepeat:[originalEvent isARepeat]
                       keyCode:aCocoaKeyCode];
 
   NativeKeyBindings* keyBindings = NativeKeyBindings::GetInstance(aType);
-  return keyBindings->Execute(modifiedEvent, aCallback, aCallbackData);
-}
-
-bool
-nsChildView::ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
-                                     const WidgetKeyboardEvent& aEvent,
-                                     DoCommandCallback aCallback,
-                                     void* aCallbackData)
-{
+  keyBindings->GetEditCommands(modifiedEvent, aCommands);
+}
+
+void
+nsChildView::GetEditCommands(NativeKeyBindingsType aType,
+                             const WidgetKeyboardEvent& aEvent,
+                             nsTArray<CommandInt>& aCommands)
+{
+  // Validate the arguments.
+  nsIWidget::GetEditCommands(aType, aEvent, aCommands);
+
   // If the key is a cursor-movement arrow, and the current selection has
   // vertical writing-mode, we'll remap so that the movement command
   // generated (in terms of characters/lines) will be appropriate for
   // the physical direction of the arrow.
   if (aEvent.mKeyCode >= NS_VK_LEFT && aEvent.mKeyCode <= NS_VK_DOWN) {
+    // XXX This may be expensive. Should use the cache in TextInputHandler.
     WidgetQueryContentEvent query(true, eQuerySelectedText, this);
     DispatchWindowEvent(query);
 
     if (query.mSucceeded && query.mReply.mWritingMode.IsVertical()) {
       uint32_t geckoKey = 0;
       uint32_t cocoaKey = 0;
 
       switch (aEvent.mKeyCode) {
@@ -1928,24 +1930,23 @@ nsChildView::ExecuteNativeKeyBinding(Nat
         break;
 
       case NS_VK_DOWN:
         geckoKey = NS_VK_RIGHT;
         cocoaKey = kVK_RightArrow;
         break;
       }
 
-      return ExecuteNativeKeyBindingRemapped(aType, aEvent, aCallback,
-                                             aCallbackData,
-                                             geckoKey, cocoaKey);
+      GetEditCommandsRemapped(aType, aEvent, aCommands, geckoKey, cocoaKey);
+      return;
     }
   }
 
   NativeKeyBindings* keyBindings = NativeKeyBindings::GetInstance(aType);
-  return keyBindings->Execute(aEvent, aCallback, aCallbackData);
+  keyBindings->GetEditCommands(aEvent, aCommands);
 }
 
 NSView<mozView>* nsChildView::GetEditorView()
 {
   NSView<mozView>* editorView = mView;
   // We need to get editor's view. E.g., when the focus is in the bookmark
   // dialog, the view is <panel> element of the dialog.  At this time, the key
   // events are processed the parent window's view that has native focus.
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -341,21 +341,20 @@ public:
     nsMenuBarX *GetMenuBar();
 
     virtual void SetInputContext(const InputContext& aContext,
                                  const InputContextAction& aAction) override;
     virtual InputContext GetInputContext() override
     {
       return mInputContext;
     }
-    virtual bool ExecuteNativeKeyBinding(
-                        NativeKeyBindingsType aType,
-                        const mozilla::WidgetKeyboardEvent& aEvent,
-                        DoCommandCallback aCallback,
-                        void* aCallbackData) override;
+    virtual void GetEditCommands(
+                   NativeKeyBindingsType aType,
+                   const mozilla::WidgetKeyboardEvent& aEvent,
+                   nsTArray<mozilla::CommandInt>& aCommands) override;
 
     void SetPopupWindowLevel();
 
 protected:
   virtual ~nsCocoaWindow();
 
   nsresult             CreateNativeWindow(const NSRect &aRect,
                                           nsBorderStyle aBorderStyle,
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -2340,24 +2340,26 @@ nsCocoaWindow::SetInputContext(const Inp
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   mInputContext = aContext;
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
-bool
-nsCocoaWindow::ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
-                                       const WidgetKeyboardEvent& aEvent,
-                                       DoCommandCallback aCallback,
-                                       void* aCallbackData)
+void
+nsCocoaWindow::GetEditCommands(NativeKeyBindingsType aType,
+                               const WidgetKeyboardEvent& aEvent,
+                               nsTArray<CommandInt>& aCommands)
 {
+  // Validate the arguments.
+  nsIWidget::GetEditCommands(aType, aEvent, aCommands);
+
   NativeKeyBindings* keyBindings = NativeKeyBindings::GetInstance(aType);
-  return keyBindings->Execute(aEvent, aCallback, aCallbackData);
+  keyBindings->GetEditCommands(aEvent, aCommands);
 }
 
 @implementation WindowDelegate
 
 // We try to find a gecko menu bar to paint. If one does not exist, just paint
 // the application menu by itself so that a window doesn't have some other
 // window's menu bar.
 + (void)paintMenubarForWindow:(NSWindow*)aWindow
--- a/widget/gtk/NativeKeyBindings.cpp
+++ b/widget/gtk/NativeKeyBindings.cpp
@@ -14,33 +14,32 @@
 
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 #include <gdk/gdk.h>
 
 namespace mozilla {
 namespace widget {
 
-static nsIWidget::DoCommandCallback gCurrentCallback;
-static void *gCurrentCallbackData;
-static bool gHandled;
+static nsTArray<CommandInt>* gCurrentCommands = nullptr;
+static bool gHandled = false;
 
 // Common GtkEntry and GtkTextView signals
 static void
 copy_clipboard_cb(GtkWidget *w, gpointer user_data)
 {
-  gCurrentCallback(CommandCopy, gCurrentCallbackData);
+  gCurrentCommands->AppendElement(CommandCopy);
   g_signal_stop_emission_by_name(w, "copy_clipboard");
   gHandled = true;
 }
 
 static void
 cut_clipboard_cb(GtkWidget *w, gpointer user_data)
 {
-  gCurrentCallback(CommandCut, gCurrentCallbackData);
+  gCurrentCommands->AppendElement(CommandCut);
   g_signal_stop_emission_by_name(w, "cut_clipboard");
   gHandled = true;
 }
 
 // GTK distinguishes between display lines (wrapped, as they appear on the
 // screen) and paragraphs, which are runs of text terminated by a newline.
 // We don't have this distinction, so we always use editor's notion of
 // lines, which are newline-terminated.
@@ -88,42 +87,42 @@ delete_from_cursor_cb(GtkWidget *w, GtkD
     // unsupported deletion type
     return;
   }
 
   if (del_type == GTK_DELETE_WORDS) {
     // This works like word_ends, except we first move the caret to the
     // beginning/end of the current word.
     if (forward) {
-      gCurrentCallback(CommandWordNext, gCurrentCallbackData);
-      gCurrentCallback(CommandWordPrevious, gCurrentCallbackData);
+      gCurrentCommands->AppendElement(CommandWordNext);
+      gCurrentCommands->AppendElement(CommandWordPrevious);
     } else {
-      gCurrentCallback(CommandWordPrevious, gCurrentCallbackData);
-      gCurrentCallback(CommandWordNext, gCurrentCallbackData);
+      gCurrentCommands->AppendElement(CommandWordPrevious);
+      gCurrentCommands->AppendElement(CommandWordNext);
     }
   } else if (del_type == GTK_DELETE_DISPLAY_LINES ||
              del_type == GTK_DELETE_PARAGRAPHS) {
 
     // This works like display_line_ends, except we first move the caret to the
     // beginning/end of the current line.
     if (forward) {
-      gCurrentCallback(CommandBeginLine, gCurrentCallbackData);
+      gCurrentCommands->AppendElement(CommandBeginLine);
     } else {
-      gCurrentCallback(CommandEndLine, gCurrentCallbackData);
+      gCurrentCommands->AppendElement(CommandEndLine);
     }
   }
 
   Command command = sDeleteCommands[del_type][forward];
   if (!command) {
     return; // unsupported command
   }
 
   unsigned int absCount = Abs(count);
   for (unsigned int i = 0; i < absCount; ++i) {
-    gCurrentCallback(command, gCurrentCallbackData);
+    gCurrentCommands->AppendElement(command);
   }
 }
 
 static const Command sMoveCommands[][2][2] = {
   // non-extend { backward, forward }, extend { backward, forward }
   // GTK differentiates between logical position, which is prev/next,
   // and visual position, which is always left/right.
   // We should fix this to work the same way for RTL text input.
@@ -183,33 +182,33 @@ move_cursor_cb(GtkWidget *w, GtkMovement
 
   Command command = sMoveCommands[step][extend_selection][forward];
   if (!command) {
     return; // unsupported command
   }
 
   unsigned int absCount = Abs(count);
   for (unsigned int i = 0; i < absCount; ++i) {
-    gCurrentCallback(command, gCurrentCallbackData);
+    gCurrentCommands->AppendElement(command);
   }
 }
 
 static void
 paste_clipboard_cb(GtkWidget *w, gpointer user_data)
 {
-  gCurrentCallback(CommandPaste, gCurrentCallbackData);
+  gCurrentCommands->AppendElement(CommandPaste);
   g_signal_stop_emission_by_name(w, "paste_clipboard");
   gHandled = true;
 }
 
 // GtkTextView-only signals
 static void
 select_all_cb(GtkWidget *w, gboolean select, gpointer user_data)
 {
-  gCurrentCallback(CommandSelectAll, gCurrentCallbackData);
+  gCurrentCommands->AppendElement(CommandSelectAll);
   g_signal_stop_emission_by_name(w, "select_all");
   gHandled = true;
 }
 
 NativeKeyBindings* NativeKeyBindings::sInstanceForSingleLineEditor = nullptr;
 NativeKeyBindings* NativeKeyBindings::sInstanceForMultiLineEditor = nullptr;
 
 // static
@@ -283,50 +282,49 @@ NativeKeyBindings::Init(NativeKeyBinding
 }
 
 NativeKeyBindings::~NativeKeyBindings()
 {
   gtk_widget_destroy(mNativeTarget);
   g_object_unref(mNativeTarget);
 }
 
-bool
-NativeKeyBindings::Execute(const WidgetKeyboardEvent& aEvent,
-                           DoCommandCallback aCallback,
-                           void* aCallbackData)
+void
+NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
+                                   nsTArray<CommandInt>& aCommands)
 {
   // If the native key event is set, it must be synthesized for tests.
   // We just ignore such events because this behavior depends on system
   // settings.
   if (!aEvent.mNativeKeyEvent) {
     // It must be synthesized event or dispatched DOM event from chrome.
-    return false;
+    return;
   }
 
   guint keyval;
 
   if (aEvent.mCharCode) {
     keyval = gdk_unicode_to_keyval(aEvent.mCharCode);
   } else {
     keyval =
       static_cast<GdkEventKey*>(aEvent.mNativeKeyEvent)->keyval;
   }
 
-  if (ExecuteInternal(aEvent, aCallback, aCallbackData, keyval)) {
-    return true;
+  if (GetEditCommandsInternal(aEvent, aCommands, keyval)) {
+    return;
   }
 
   for (uint32_t i = 0; i < aEvent.mAlternativeCharCodes.Length(); ++i) {
     uint32_t ch = aEvent.IsShift() ?
       aEvent.mAlternativeCharCodes[i].mShiftedCharCode :
       aEvent.mAlternativeCharCodes[i].mUnshiftedCharCode;
     if (ch && ch != aEvent.mCharCode) {
       keyval = gdk_unicode_to_keyval(ch);
-      if (ExecuteInternal(aEvent, aCallback, aCallbackData, keyval)) {
-        return true;
+      if (GetEditCommandsInternal(aEvent, aCommands, keyval)) {
+        return;
       }
     }
   }
 
 /*
 gtk_bindings_activate_event is preferable, but it has unresolved bug:
 http://bugzilla.gnome.org/show_bug.cgi?id=162726
 The bug was already marked as FIXED.  However, somebody reports that the
@@ -334,41 +332,38 @@ bug still exists.
 Also gtk_bindings_activate may work with some non-shortcuts operations
 (todo: check it). See bug 411005 and bug 406407.
 
 Code, which should be used after fixing GNOME bug 162726:
 
   gtk_bindings_activate_event(GTK_OBJECT(mNativeTarget),
     static_cast<GdkEventKey*>(aEvent.mNativeKeyEvent));
 */
-
-  return false;
 }
 
 bool
-NativeKeyBindings::ExecuteInternal(const WidgetKeyboardEvent& aEvent,
-                                   DoCommandCallback aCallback,
-                                   void* aCallbackData,
-                                   guint aKeyval)
+NativeKeyBindings::GetEditCommandsInternal(const WidgetKeyboardEvent& aEvent,
+                                           nsTArray<CommandInt>& aCommands,
+                                           guint aKeyval)
 {
   guint modifiers =
     static_cast<GdkEventKey*>(aEvent.mNativeKeyEvent)->state;
 
-  gCurrentCallback = aCallback;
-  gCurrentCallbackData = aCallbackData;
+  gCurrentCommands = &aCommands;
 
   gHandled = false;
 #if (MOZ_WIDGET_GTK == 2)
   gtk_bindings_activate(GTK_OBJECT(mNativeTarget),
                         aKeyval, GdkModifierType(modifiers));
 #else
   gtk_bindings_activate(G_OBJECT(mNativeTarget),
                         aKeyval, GdkModifierType(modifiers));
 #endif
 
-  gCurrentCallback = nullptr;
-  gCurrentCallbackData = nullptr;
+  gCurrentCommands = nullptr;
+
+  MOZ_ASSERT(!gHandled || !aCommands.IsEmpty());
 
   return gHandled;
 }
 
 } // namespace widget
 } // namespace mozilla
--- a/widget/gtk/NativeKeyBindings.h
+++ b/widget/gtk/NativeKeyBindings.h
@@ -12,35 +12,32 @@
 #include "nsIWidget.h"
 
 namespace mozilla {
 namespace widget {
 
 class NativeKeyBindings final
 {
   typedef nsIWidget::NativeKeyBindingsType NativeKeyBindingsType;
-  typedef nsIWidget::DoCommandCallback DoCommandCallback;
 
 public:
   static NativeKeyBindings* GetInstance(NativeKeyBindingsType aType);
   static void Shutdown();
 
   void Init(NativeKeyBindingsType aType);
 
-  bool Execute(const WidgetKeyboardEvent& aEvent,
-               DoCommandCallback aCallback,
-               void* aCallbackData);
+  void GetEditCommands(const WidgetKeyboardEvent& aEvent,
+                       nsTArray<CommandInt>& aCommands);
 
 private:
   ~NativeKeyBindings();
 
-  bool ExecuteInternal(const WidgetKeyboardEvent& aEvent,
-                       DoCommandCallback aCallback,
-                       void* aCallbackData,
-                       guint aKeyval);
+  bool GetEditCommandsInternal(const WidgetKeyboardEvent& aEvent,
+                               nsTArray<CommandInt>& aCommands,
+                               guint aKeyval);
 
   GtkWidget* mNativeTarget;
 
   static NativeKeyBindings* sInstanceForSingleLineEditor;
   static NativeKeyBindings* sInstanceForMultiLineEditor;
 };
 
 } // namespace widget
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -6160,43 +6160,44 @@ TextEventDispatcherListener*
 nsWindow::GetNativeTextEventDispatcherListener()
 {
     if (NS_WARN_IF(!mIMContext)) {
         return nullptr;
     }
     return mIMContext;
 }
 
-bool
-nsWindow::ExecuteNativeKeyBindingRemapped(NativeKeyBindingsType aType,
-                                          const WidgetKeyboardEvent& aEvent,
-                                          DoCommandCallback aCallback,
-                                          void* aCallbackData,
-                                          uint32_t aGeckoKeyCode,
-                                          uint32_t aNativeKeyCode)
+void
+nsWindow::GetEditCommandsRemapped(NativeKeyBindingsType aType,
+                                  const WidgetKeyboardEvent& aEvent,
+                                  nsTArray<CommandInt>& aCommands,
+                                  uint32_t aGeckoKeyCode,
+                                  uint32_t aNativeKeyCode)
 {
     WidgetKeyboardEvent modifiedEvent(aEvent);
     modifiedEvent.mKeyCode = aGeckoKeyCode;
     static_cast<GdkEventKey*>(modifiedEvent.mNativeKeyEvent)->keyval =
         aNativeKeyCode;
 
     NativeKeyBindings* keyBindings = NativeKeyBindings::GetInstance(aType);
-    return keyBindings->Execute(modifiedEvent, aCallback, aCallbackData);
-}
-
-bool
-nsWindow::ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
-                                  const WidgetKeyboardEvent& aEvent,
-                                  DoCommandCallback aCallback,
-                                  void* aCallbackData)
-{
+    return keyBindings->GetEditCommands(modifiedEvent, aCommands);
+}
+
+void
+nsWindow::GetEditCommands(NativeKeyBindingsType aType,
+                          const WidgetKeyboardEvent& aEvent,
+                          nsTArray<CommandInt>& aCommands)
+{
+    // Validate the arguments.
+    nsIWidget::GetEditCommands(aType, aEvent, aCommands);
+
     if (aEvent.mKeyCode >= NS_VK_LEFT && aEvent.mKeyCode <= NS_VK_DOWN) {
-
         // Check if we're targeting content with vertical writing mode,
         // and if so remap the arrow keys.
+        // XXX This may be expensive.
         WidgetQueryContentEvent query(true, eQuerySelectedText, this);
         nsEventStatus status;
         DispatchEvent(&query, status);
 
         if (query.mSucceeded && query.mReply.mWritingMode.IsVertical()) {
             uint32_t geckoCode = 0;
             uint32_t gdkCode = 0;
             switch (aEvent.mKeyCode) {
@@ -6226,24 +6227,24 @@ nsWindow::ExecuteNativeKeyBinding(Native
                 break;
 
             case NS_VK_DOWN:
                 geckoCode = NS_VK_RIGHT;
                 gdkCode = GDK_Right;
                 break;
             }
 
-            return ExecuteNativeKeyBindingRemapped(aType, aEvent, aCallback,
-                                                   aCallbackData,
-                                                   geckoCode, gdkCode);
+            GetEditCommandsRemapped(aType, aEvent, aCommands,
+                                    geckoCode, gdkCode);
+            return;
         }
     }
 
     NativeKeyBindings* keyBindings = NativeKeyBindings::GetInstance(aType);
-    return keyBindings->Execute(aEvent, aCallback, aCallbackData);
+    keyBindings->GetEditCommands(aEvent, aCommands);
 }
 
 #if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
 /* static */ already_AddRefed<DrawTarget>
 nsWindow::GetDrawTargetForGdkDrawable(GdkDrawable* aDrawable,
                                       const IntSize& aSize)
 {
     GdkVisual* visual = gdk_drawable_get_visual(aDrawable);
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -285,28 +285,25 @@ public:
     mozilla::TimeStamp GetEventTimeStamp(guint32 aEventTime);
     mozilla::CurrentX11TimeGetter* GetCurrentTimeGetter();
 
     virtual void SetInputContext(const InputContext& aContext,
                                  const InputContextAction& aAction) override;
     virtual InputContext GetInputContext() override;
     virtual TextEventDispatcherListener*
         GetNativeTextEventDispatcherListener() override;
-    bool ExecuteNativeKeyBindingRemapped(
-                        NativeKeyBindingsType aType,
-                        const mozilla::WidgetKeyboardEvent& aEvent,
-                        DoCommandCallback aCallback,
-                        void* aCallbackData,
-                        uint32_t aGeckoKeyCode,
-                        uint32_t aNativeKeyCode);
-    virtual bool ExecuteNativeKeyBinding(
-                        NativeKeyBindingsType aType,
-                        const mozilla::WidgetKeyboardEvent& aEvent,
-                        DoCommandCallback aCallback,
-                        void* aCallbackData) override;
+    void GetEditCommandsRemapped(NativeKeyBindingsType aType,
+                                 const mozilla::WidgetKeyboardEvent& aEvent,
+                                 nsTArray<mozilla::CommandInt>& aCommands,
+                                 uint32_t aGeckoKeyCode,
+                                 uint32_t aNativeKeyCode);
+    virtual void GetEditCommands(
+                     NativeKeyBindingsType aType,
+                     const mozilla::WidgetKeyboardEvent& aEvent,
+                     nsTArray<mozilla::CommandInt>& aCommands) override;
 
     // These methods are for toplevel windows only.
     void               ResizeTransparencyBitmap();
     void               ApplyTransparencyBitmap();
     void               ClearTransparencyBitmap();
 
    virtual void        SetTransparencyMode(nsTransparencyMode aMode) override;
    virtual nsTransparencyMode GetTransparencyMode() override;
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -2282,16 +2282,25 @@ nsIWidget::OnWindowedPluginKeyEvent(cons
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 void
 nsIWidget::PostHandleKeyEvent(mozilla::WidgetKeyboardEvent* aEvent)
 {
 }
 
+void
+nsIWidget::GetEditCommands(nsIWidget::NativeKeyBindingsType aType,
+                           const WidgetKeyboardEvent& aEvent,
+                           nsTArray<CommandInt>& aCommands)
+{
+  MOZ_ASSERT(aEvent.IsTrusted());
+  MOZ_ASSERT(aCommands.IsEmpty());
+}
+
 namespace mozilla {
 namespace widget {
 
 const char*
 ToChar(IMEMessage aIMEMessage)
 {
   switch (aIMEMessage) {
     case NOTIFY_IME_OF_NOTHING:
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -274,21 +274,16 @@ public:
   virtual void            SetCandidateWindowForPlugin(
                             const mozilla::widget::CandidateWindowPosition&
                               aPosition) override
                           { }
   virtual void            DefaultProcOfPluginEvent(
                             const mozilla::WidgetPluginEvent& aEvent) override
                           { }
   virtual MOZ_MUST_USE nsresult AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) override { return NS_ERROR_NOT_IMPLEMENTED; }
-  virtual bool            ExecuteNativeKeyBinding(
-                            NativeKeyBindingsType aType,
-                            const mozilla::WidgetKeyboardEvent& aEvent,
-                            DoCommandCallback aCallback,
-                            void* aCallbackData) override { return false; }
   bool                    ComputeShouldAccelerate();
   virtual bool            WidgetTypeSupportsAcceleration() { return true; }
   virtual MOZ_MUST_USE nsresult OnDefaultButtonLoaded(const LayoutDeviceIntRect& aButtonRect) override { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual already_AddRefed<nsIWidget>
   CreateChild(const LayoutDeviceIntRect& aRect,
               nsWidgetInitData* aInitData = nullptr,
               bool aForceUseIWidgetParent = false) override;
   virtual void            AttachViewToTopLevel(bool aUseAttachedEvents) override;
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -1812,31 +1812,29 @@ public:
      * Given a WidgetKeyboardEvent, this method synthesizes a corresponding
      * native (OS-level) event for it. This method allows tests to simulate
      * keystrokes that trigger native key bindings (which require a native
      * event).
      */
     virtual MOZ_MUST_USE nsresult
     AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) = 0;
 
-    /*
-     * Execute native key bindings for aType.
+    /**
+     * Retrieve edit commands when the key combination of aEvent is used
+     * in platform native applications.
      */
-    typedef void (*DoCommandCallback)(mozilla::Command, void*);
     enum NativeKeyBindingsType
     {
       NativeKeyBindingsForSingleLineEditor,
       NativeKeyBindingsForMultiLineEditor,
       NativeKeyBindingsForRichTextEditor
     };
-    virtual bool ExecuteNativeKeyBinding(
-                        NativeKeyBindingsType aType,
-                        const mozilla::WidgetKeyboardEvent& aEvent,
-                        DoCommandCallback aCallback,
-                        void* aCallbackData) = 0;
+    virtual void GetEditCommands(NativeKeyBindingsType aType,
+                                 const mozilla::WidgetKeyboardEvent& aEvent,
+                                 nsTArray<mozilla::CommandInt>& aCommands);
 
     /*
      * Retrieves a reference to notification requests of IME.  Note that the
      * reference is valid while the nsIWidget instance is alive.  So, if you
      * need to store the reference for a long time, you need to grab the widget
      * instance too.
      */
     const IMENotificationRequests& IMENotificationRequestsRef();