diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 05d3a273a4e5..c1847eecc5df 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -49,10 +49,24 @@ using mozilla::dom::ScreenOrientation from "mozilla/dom/ScreenOrientation.h"; using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h"; using mozilla::CSSPoint from "Units.h"; using mozilla::CSSToScreenScale from "Units.h"; +using mozilla::CommandInt from "mozilla/EventForwards.h"; namespace mozilla { namespace dom { +struct NativeKeyBinding +{ + CommandInt[] singleLineCommands; + CommandInt[] multiLineCommands; + CommandInt[] richTextCommands; +}; + +union MaybeNativeKeyBinding +{ + NativeKeyBinding; + void_t; +}; + intr protocol PBrowser { manager PContent; @@ -419,7 +433,7 @@ child: bool aIgnoreRootScrollFrame); RealMouseEvent(WidgetMouseEvent event); - RealKeyEvent(WidgetKeyboardEvent event); + RealKeyEvent(WidgetKeyboardEvent event, MaybeNativeKeyBinding keyBinding); MouseWheelEvent(WidgetWheelEvent event); RealTouchEvent(WidgetTouchEvent aEvent, ScrollableLayerGuid aGuid); // We use a separate message for touchmove events only to apply diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 8178e89ebf50..9b3ed3b8b0af 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -1917,8 +1917,20 @@ TabChild::RecvRealTouchMoveEvent(const WidgetTouchEvent& aEvent, } bool -TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event) -{ +TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event, + const MaybeNativeKeyBinding& aBindings) + { + if (event.message == NS_KEY_PRESS) { + PuppetWidget* widget = static_cast(mWidget.get()); + if (aBindings.type() == MaybeNativeKeyBinding::TNativeKeyBinding) { + const NativeKeyBinding& bindings = aBindings; + widget->CacheNativeKeyCommands(bindings.singleLineCommands(), + bindings.multiLineCommands(), + bindings.richTextCommands()); + } else { + widget->ClearNativeKeyCommands(); + } + } // If content code called preventDefault() on a keydown event, then we don't // want to process any following keypress events. if (event.message == NS_KEY_PRESS && mIgnoreKeyPressEvent) { diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 115abcebac53..f46e3d17ab66 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -238,7 +238,8 @@ public: const int32_t& aModifiers, const bool& aIgnoreRootScrollFrame) MOZ_OVERRIDE; virtual bool RecvRealMouseEvent(const mozilla::WidgetMouseEvent& event) MOZ_OVERRIDE; - virtual bool RecvRealKeyEvent(const mozilla::WidgetKeyboardEvent& event) MOZ_OVERRIDE; + virtual bool RecvRealKeyEvent(const mozilla::WidgetKeyboardEvent& event, + const MaybeNativeKeyBinding& aBindings) MOZ_OVERRIDE; virtual bool RecvMouseWheelEvent(const mozilla::WidgetWheelEvent& event) MOZ_OVERRIDE; virtual bool RecvRealTouchEvent(const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE; diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 48760c47523c..280b72831911 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -788,6 +788,12 @@ bool TabParent::SendMouseWheelEvent(WidgetWheelEvent& event) return PBrowserParent::SendMouseWheelEvent(event); } +static void +DoCommandCallback(mozilla::Command aCommand, void* aData) +{ + static_cast*>(aData)->AppendElement(aCommand); +} + bool TabParent::SendRealKeyEvent(WidgetKeyboardEvent& event) { if (mIsDestroyed) { @@ -797,7 +803,30 @@ bool TabParent::SendRealKeyEvent(WidgetKeyboardEvent& event) if (!MapEventCoordinatesForChildProcess(&event)) { return false; } - return PBrowserParent::SendRealKeyEvent(event); + + + MaybeNativeKeyBinding bindings; + bindings = void_t(); + if (event.message == NS_KEY_PRESS) { + nsCOMPtr widget = GetWidget(); + + AutoInfallibleTArray singleLine; + AutoInfallibleTArray multiLine; + AutoInfallibleTArray richText; + + widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForSingleLineEditor, + event, DoCommandCallback, &singleLine); + widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForMultiLineEditor, + event, DoCommandCallback, &multiLine); + widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForRichTextEditor, + event, DoCommandCallback, &richText); + + if (!singleLine.IsEmpty() || !multiLine.IsEmpty() || !richText.IsEmpty()) { + bindings = NativeKeyBinding(singleLine, multiLine, richText); + } + } + + return PBrowserParent::SendRealKeyEvent(event, bindings); } bool TabParent::SendRealTouchEvent(WidgetTouchEvent& event) diff --git a/widget/xpwidgets/PuppetWidget.cpp b/widget/xpwidgets/PuppetWidget.cpp index 7ddb4d5efb47..b26b7200c632 100644 --- a/widget/xpwidgets/PuppetWidget.cpp +++ b/widget/xpwidgets/PuppetWidget.cpp @@ -81,6 +81,10 @@ PuppetWidget::PuppetWidget(TabChild* aTabChild) , mDefaultScale(-1) { MOZ_COUNT_CTOR(PuppetWidget); + + mSingleLineCommands.SetCapacity(4); + mMultiLineCommands.SetCapacity(4); + mRichTextCommands.SetCapacity(4); } PuppetWidget::~PuppetWidget() @@ -308,6 +312,36 @@ PuppetWidget::DispatchEvent(WidgetGUIEvent* event, nsEventStatus& aStatus) return NS_OK; } + +NS_IMETHODIMP_(bool) +PuppetWidget::ExecuteNativeKeyBinding(NativeKeyBindingsType aType, + const mozilla::WidgetKeyboardEvent& aEvent, + DoCommandCallback aCallback, + void* aCallbackData) +{ + nsTArray& commands = mSingleLineCommands; + switch (aType) { + case nsIWidget::NativeKeyBindingsForSingleLineEditor: + commands = mSingleLineCommands; + break; + case nsIWidget::NativeKeyBindingsForMultiLineEditor: + commands = mMultiLineCommands; + break; + case nsIWidget::NativeKeyBindingsForRichTextEditor: + commands = mRichTextCommands; + break; + } + + if (commands.IsEmpty()) { + return false; + } + + for (uint32_t i = 0; i < commands.Length(); i++) { + aCallback(static_cast(commands[i]), aCallbackData); + } + return true; +} + LayerManager* PuppetWidget::GetLayerManager(PLayerTransactionChild* aShadowManager, LayersBackend aBackendHint, diff --git a/widget/xpwidgets/PuppetWidget.h b/widget/xpwidgets/PuppetWidget.h index fc31a54eac0e..2db6bc5f2425 100644 --- a/widget/xpwidgets/PuppetWidget.h +++ b/widget/xpwidgets/PuppetWidget.h @@ -21,6 +21,7 @@ #include "nsThreadUtils.h" #include "nsWeakReference.h" #include "mozilla/Attributes.h" +#include "mozilla/EventForwards.h" class gfxASurface; @@ -129,6 +130,28 @@ public: bool aDoCapture) { return NS_ERROR_UNEXPECTED; } + NS_IMETHOD_(bool) + ExecuteNativeKeyBinding(NativeKeyBindingsType aType, + const mozilla::WidgetKeyboardEvent& aEvent, + DoCommandCallback aCallback, + void* aCallbackData) MOZ_OVERRIDE; + + void CacheNativeKeyCommands(const InfallibleTArray& aSingleLineCommands, + const InfallibleTArray& aMultiLineCommands, + const InfallibleTArray& aRichTextCommands) + { + mSingleLineCommands = aSingleLineCommands; + mMultiLineCommands = aMultiLineCommands; + mRichTextCommands = aRichTextCommands; + } + + void ClearNativeKeyCommands() + { + mSingleLineCommands.Clear(); + mMultiLineCommands.Clear(); + mRichTextCommands.Clear(); + } + // // nsBaseWidget methods we override // @@ -225,6 +248,11 @@ private: // The DPI of the screen corresponding to this widget float mDPI; double mDefaultScale; + + // Precomputed answers for ExecuteNativeKeyBinding + InfallibleTArray mSingleLineCommands; + InfallibleTArray mMultiLineCommands; + InfallibleTArray mRichTextCommands; }; class PuppetScreen : public nsBaseScreen