Bug 1257759 part.5 PluginInstanceChild should post received native key event to chrome process if the key combination may be a shortcut key r=jimm

When PluginInstanceChild receives native key events, it should post the events to the chrome process first for checking if the key combination is reserved.  However, posting all key events to the chrome process may make damage to the performance of text input.  Therefore, this patch starts to post a key event whose key combination may be a shortcut key.  However, for avoiding to shuffle the event order, it posts following key events until all posted key events are handled by the chrome process.

For receiving response from widget, this patch defines nsIKeyEventInPluginCallback.  It's specified by nsIWidget::OnWindowedPluginKeyEvent() for ensuring the caller will receive the reply.  Basically, the caller of nsIWidget::OnWindowedPluginKeyEvent() should reply to the child process.  However, if the widget is a PuppetWidget, it cannot return the result synchronously.  Therefore, PuppetWidget::OnWindowedPluginKeyEvent() returns NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY and stores the callback to mKeyEventInPluginCallbacks.  Then, TabParent::HandledWindowedPluginKeyEvent() will call PuppetWidget::HandledWindowedPluginKeyEvent().

MozReview-Commit-ID: G6brOU26NwQ
This commit is contained in:
Masayuki Nakano
2016-04-19 20:09:37 +09:00
parent a42732a6b2
commit bbce223b06
31 changed files with 674 additions and 7 deletions

View File

@@ -67,6 +67,7 @@ using mozilla::EventMessage from "mozilla/EventForwards.h";
using nsEventStatus from "mozilla/EventForwards.h"; using nsEventStatus from "mozilla/EventForwards.h";
using nsSizeMode from "nsIWidgetListener.h"; using nsSizeMode from "nsIWidgetListener.h";
using mozilla::widget::CandidateWindowPosition from "ipc/nsGUIEventIPC.h"; using mozilla::widget::CandidateWindowPosition from "ipc/nsGUIEventIPC.h";
using class mozilla::NativeEventData from "ipc/nsGUIEventIPC.h";
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@@ -283,6 +284,16 @@ parent:
*/ */
async SetCandidateWindowForPlugin(CandidateWindowPosition aPosition); async SetCandidateWindowForPlugin(CandidateWindowPosition aPosition);
/**
* Notifies the parent process of native key event data received in a
* plugin process directly.
*
* aKeyEventData The native key event data. The actual type copied into
* NativeEventData depending on the caller. Please check
* PluginInstanceChild.
*/
prio(urgent) async OnWindowedPluginKeyEvent(NativeEventData aKeyEventData);
/** /**
* When plugin event isn't consumed, call this * When plugin event isn't consumed, call this
*/ */
@@ -732,6 +743,18 @@ child:
*/ */
async SetUseGlobalHistory(bool aUse); async SetUseGlobalHistory(bool aUse);
/**
* HandledWindowedPluginKeyEvent() is always called after posting a native
* key event with OnWindowedPluginKeyEvent().
*
* @param aKeyEventData The key event which was posted to the parent
* process.
* @param aIsConsumed true if aKeyEventData is consumed in the
* parent process. Otherwise, false.
*/
async HandledWindowedPluginKeyEvent(NativeEventData aKeyEventData,
bool aIsConsumed);
/* /*
* FIXME: write protocol! * FIXME: write protocol!

View File

@@ -2483,6 +2483,18 @@ TabChild::RecvNavigateByKey(const bool& aForward, const bool& aForDocumentNaviga
return true; return true;
} }
bool
TabChild::RecvHandledWindowedPluginKeyEvent(
const NativeEventData& aKeyEventData,
const bool& aIsConsumed)
{
if (NS_WARN_IF(!mPuppetWidget)) {
return true;
}
mPuppetWidget->HandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
return true;
}
PRenderFrameChild* PRenderFrameChild*
TabChild::AllocPRenderFrameChild() TabChild::AllocPRenderFrameChild()
{ {

View File

@@ -575,6 +575,10 @@ public:
virtual bool RecvSetUseGlobalHistory(const bool& aUse) override; virtual bool RecvSetUseGlobalHistory(const bool& aUse) override;
virtual bool RecvHandledWindowedPluginKeyEvent(
const mozilla::NativeEventData& aKeyEventData,
const bool& aIsConsumed) override;
/** /**
* Native widget remoting protocol for use with windowed plugins with e10s. * Native widget remoting protocol for use with windowed plugins with e10s.
*/ */

View File

@@ -1899,6 +1899,44 @@ TabParent::RecvOnEventNeedingAckHandled(const EventMessage& aMessage)
return true; return true;
} }
void
TabParent::HandledWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
bool aIsConsumed)
{
bool ok = SendHandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
NS_WARN_IF(!ok);
}
bool
TabParent::RecvOnWindowedPluginKeyEvent(const NativeEventData& aKeyEventData)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (NS_WARN_IF(!widget)) {
// Notifies the plugin process of the key event being not consumed by us.
HandledWindowedPluginKeyEvent(aKeyEventData, false);
return true;
}
nsresult rv = widget->OnWindowedPluginKeyEvent(aKeyEventData, this);
if (NS_WARN_IF(NS_FAILED(rv))) {
// Notifies the plugin process of the key event being not consumed by us.
HandledWindowedPluginKeyEvent(aKeyEventData, false);
return true;
}
// If the key event is posted to another process, we need to wait a call
// of HandledWindowedPluginKeyEvent(). So, nothing to do here in this case.
if (rv == NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY) {
return true;
}
// Otherwise, the key event is handled synchronously. Let's notify the
// plugin process of the key event's result.
bool consumed = (rv == NS_SUCCESS_EVENT_CONSUMED);
HandledWindowedPluginKeyEvent(aKeyEventData, consumed);
return true;
}
bool bool
TabParent::RecvRequestFocus(const bool& aCanRaise) TabParent::RecvRequestFocus(const bool& aCanRaise)
{ {

View File

@@ -22,6 +22,7 @@
#include "nsIAuthPromptProvider.h" #include "nsIAuthPromptProvider.h"
#include "nsIBrowserDOMWindow.h" #include "nsIBrowserDOMWindow.h"
#include "nsIDOMEventListener.h" #include "nsIDOMEventListener.h"
#include "nsIKeyEventInPluginCallback.h"
#include "nsISecureBrowserUI.h" #include "nsISecureBrowserUI.h"
#include "nsITabParent.h" #include "nsITabParent.h"
#include "nsIWebBrowserPersistable.h" #include "nsIWebBrowserPersistable.h"
@@ -82,6 +83,7 @@ class TabParent final : public PBrowserParent
, public nsITabParent , public nsITabParent
, public nsIAuthPromptProvider , public nsIAuthPromptProvider
, public nsISecureBrowserUI , public nsISecureBrowserUI
, public nsIKeyEventInPluginCallback
, public nsSupportsWeakReference , public nsSupportsWeakReference
, public TabContext , public TabContext
, public nsAPostRefreshObserver , public nsAPostRefreshObserver
@@ -255,6 +257,15 @@ public:
const int32_t& aCause, const int32_t& aCause,
const int32_t& aFocusChange) override; const int32_t& aFocusChange) override;
// See nsIKeyEventInPluginCallback
virtual void HandledWindowedPluginKeyEvent(
const NativeEventData& aKeyEventData,
bool aIsConsumed) override;
virtual bool RecvOnWindowedPluginKeyEvent(
const NativeEventData& aKeyEventData) override;
virtual bool RecvRequestFocus(const bool& aCanRaise) override; virtual bool RecvRequestFocus(const bool& aCanRaise) override;
virtual bool virtual bool

View File

@@ -334,4 +334,17 @@ PluginPRLibrary::UpdateScrollState(NPP aInstance, bool aIsScrolling)
} }
#endif #endif
nsresult
PluginPRLibrary::HandledWindowedPluginKeyEvent(
NPP aInstance,
const NativeEventData& aNativeKeyData,
bool aIsConsumed)
{
nsNPAPIPluginInstance* instance = (nsNPAPIPluginInstance*)aInstance->ndata;
if (NS_WARN_IF(!instance)) {
return NS_ERROR_NULL_POINTER;
}
return NS_OK;
}
} // namespace mozilla } // namespace mozilla

View File

@@ -129,6 +129,10 @@ public:
virtual nsresult GetScrollCaptureContainer(NPP aInstance, mozilla::layers::ImageContainer** aContainer) override; virtual nsresult GetScrollCaptureContainer(NPP aInstance, mozilla::layers::ImageContainer** aContainer) override;
virtual nsresult UpdateScrollState(NPP aInstance, bool aIsScrolling) override; virtual nsresult UpdateScrollState(NPP aInstance, bool aIsScrolling) override;
#endif #endif
virtual nsresult HandledWindowedPluginKeyEvent(
NPP aInstance,
const mozilla::NativeEventData& aNativeKeyData,
bool aIsCOnsumed) override;
private: private:
NP_InitializeFunc mNP_Initialize; NP_InitializeFunc mNP_Initialize;

View File

@@ -1170,6 +1170,23 @@ nsNPAPIPluginInstance::UpdateScrollState(bool aIsScrolling)
} }
#endif #endif
nsresult
nsNPAPIPluginInstance::HandledWindowedPluginKeyEvent(
const NativeEventData& aKeyEventData,
bool aIsConsumed)
{
if (NS_WARN_IF(!mPlugin)) {
return NS_ERROR_FAILURE;
}
PluginLibrary* library = mPlugin->GetLibrary();
if (NS_WARN_IF(!library)) {
return NS_ERROR_FAILURE;
}
return library->HandledWindowedPluginKeyEvent(&mNPP, aKeyEventData,
aIsConsumed);
}
void void
nsNPAPIPluginInstance::DidComposite() nsNPAPIPluginInstance::DidComposite()
{ {

View File

@@ -28,6 +28,7 @@
class PluginEventRunnable; class PluginEventRunnable;
#endif #endif
#include "mozilla/EventForwards.h"
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "mozilla/PluginLibrary.h" #include "mozilla/PluginLibrary.h"
#include "mozilla/WeakPtr.h" #include "mozilla/WeakPtr.h"
@@ -125,6 +126,9 @@ public:
nsresult GetScrollCaptureContainer(mozilla::layers::ImageContainer **aContainer); nsresult GetScrollCaptureContainer(mozilla::layers::ImageContainer **aContainer);
nsresult UpdateScrollState(bool aIsScrolling); nsresult UpdateScrollState(bool aIsScrolling);
#endif #endif
nsresult HandledWindowedPluginKeyEvent(
const mozilla::NativeEventData& aKeyEventData,
bool aIsConsumed);
nsPluginInstanceOwner* GetOwner(); nsPluginInstanceOwner* GetOwner();
void SetOwner(nsPluginInstanceOwner *aOwner); void SetOwner(nsPluginInstanceOwner *aOwner);
void DidComposite(); void DidComposite();

View File

@@ -418,6 +418,7 @@ NS_IMPL_ISUPPORTS(nsPluginInstanceOwner,
nsIPluginInstanceOwner, nsIPluginInstanceOwner,
nsIDOMEventListener, nsIDOMEventListener,
nsIPrivacyTransitionObserver, nsIPrivacyTransitionObserver,
nsIKeyEventInPluginCallback,
nsISupportsWeakReference) nsISupportsWeakReference)
nsresult nsresult
@@ -993,8 +994,58 @@ nsPluginInstanceOwner::RequestCommitOrCancel(bool aCommitted)
} }
return true; return true;
} }
#endif // #ifdef XP_WIN #endif // #ifdef XP_WIN
void
nsPluginInstanceOwner::HandledWindowedPluginKeyEvent(
const NativeEventData& aKeyEventData,
bool aIsConsumed)
{
if (NS_WARN_IF(!mInstance)) {
return;
}
nsresult rv =
mInstance->HandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
NS_WARN_IF(NS_FAILED(rv));
}
void
nsPluginInstanceOwner::OnWindowedPluginKeyEvent(
const NativeEventData& aKeyEventData)
{
if (NS_WARN_IF(!mPluginFrame)) {
// Notifies the plugin process of the key event being not consumed by us.
HandledWindowedPluginKeyEvent(aKeyEventData, false);
return;
}
nsCOMPtr<nsIWidget> widget = mPluginFrame->PresContext()->GetRootWidget();
if (NS_WARN_IF(!widget)) {
// Notifies the plugin process of the key event being not consumed by us.
HandledWindowedPluginKeyEvent(aKeyEventData, false);
return;
}
nsresult rv = widget->OnWindowedPluginKeyEvent(aKeyEventData, this);
if (NS_WARN_IF(NS_FAILED(rv))) {
// Notifies the plugin process of the key event being not consumed by us.
HandledWindowedPluginKeyEvent(aKeyEventData, false);
return;
}
// If the key event is posted to another process, we need to wait a call
// of HandledWindowedPluginKeyEvent(). So, nothing to do here in this case.
if (rv == NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY) {
return;
}
// Otherwise, the key event is handled synchronously. Let's notify the
// plugin process of the key event's result.
bool consumed = (rv == NS_SUCCESS_EVENT_CONSUMED);
HandledWindowedPluginKeyEvent(aKeyEventData, consumed);
}
NS_IMETHODIMP nsPluginInstanceOwner::SetEventModel(int32_t eventModel) NS_IMETHODIMP nsPluginInstanceOwner::SetEventModel(int32_t eventModel)
{ {
#ifdef XP_MACOSX #ifdef XP_MACOSX

View File

@@ -10,6 +10,7 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "npapi.h" #include "npapi.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsIKeyEventInPluginCallback.h"
#include "nsIPluginInstanceOwner.h" #include "nsIPluginInstanceOwner.h"
#include "nsIPrivacyTransitionObserver.h" #include "nsIPrivacyTransitionObserver.h"
#include "nsIDOMEventListener.h" #include "nsIDOMEventListener.h"
@@ -52,10 +53,11 @@ using mozilla::widget::PuppetWidget;
#endif #endif
#endif #endif
class nsPluginInstanceOwner final : public nsIPluginInstanceOwner, class nsPluginInstanceOwner final : public nsIPluginInstanceOwner
public nsIDOMEventListener, , public nsIDOMEventListener
public nsIPrivacyTransitionObserver, , public nsIPrivacyTransitionObserver
public nsSupportsWeakReference , public nsIKeyEventInPluginCallback
, public nsSupportsWeakReference
{ {
public: public:
typedef mozilla::gfx::DrawTarget DrawTarget; typedef mozilla::gfx::DrawTarget DrawTarget;
@@ -278,6 +280,21 @@ public:
const mozilla::widget::CandidateWindowPosition& aPosition); const mozilla::widget::CandidateWindowPosition& aPosition);
bool RequestCommitOrCancel(bool aCommitted); bool RequestCommitOrCancel(bool aCommitted);
// See nsIKeyEventInPluginCallback
virtual void HandledWindowedPluginKeyEvent(
const mozilla::NativeEventData& aKeyEventData,
bool aIsConsumed) override;
/**
* OnWindowedPluginKeyEvent() is called when the plugin process receives
* native key event directly.
*
* @param aNativeKeyData The key event which was received by the
* plugin process directly.
*/
void OnWindowedPluginKeyEvent(
const mozilla::NativeEventData& aNativeKeyData);
void GetCSSZoomFactor(float *result); void GetCSSZoomFactor(float *result);
private: private:
virtual ~nsPluginInstanceOwner(); virtual ~nsPluginInstanceOwner();

View File

@@ -32,6 +32,7 @@ using nsIntRect from "nsRect.h";
using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h"; using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
using struct DxgiAdapterDesc from "mozilla/D3DMessageUtils.h"; using struct DxgiAdapterDesc from "mozilla/D3DMessageUtils.h";
using struct mozilla::widget::CandidateWindowPosition from "ipc/nsGUIEventIPC.h"; using struct mozilla::widget::CandidateWindowPosition from "ipc/nsGUIEventIPC.h";
using class mozilla::NativeEventData from "ipc/nsGUIEventIPC.h";
namespace mozilla { namespace mozilla {
namespace plugins { namespace plugins {
@@ -140,6 +141,16 @@ child:
intr NPP_Destroy() intr NPP_Destroy()
returns (NPError rv); returns (NPError rv);
// HandledWindowedPluginKeyEvent() is always called after posting a native
// key event with OnWindowedPluginKeyEvent().
//
// @param aKeyEventData The key event which was posted to the parent
// process.
// @param aIsConsumed true if aKeyEventData is consumed in the
// parent process. Otherwise, false.
async HandledWindowedPluginKeyEvent(NativeEventData aKeyEventData,
bool aIsConsumed);
parent: parent:
intr NPN_GetValue_NPNVWindowNPObject() intr NPN_GetValue_NPNVWindowNPObject()
returns (nullable PPluginScriptableObject value, NPError result); returns (nullable PPluginScriptableObject value, NPError result);
@@ -271,6 +282,13 @@ parent:
async SetCandidateWindow(CandidateWindowPosition aPosition); async SetCandidateWindow(CandidateWindowPosition aPosition);
async RequestCommitOrCancel(bool aCommitted); async RequestCommitOrCancel(bool aCommitted);
// Notifies the parent process of a plugin instance receiving key event
// directly.
//
// @param aKeyEventData The native key event which will be sent to
// plugin from native event handler.
async OnWindowedPluginKeyEvent(NativeEventData aKeyEventData);
both: both:
async PPluginScriptableObject(); async PPluginScriptableObject();

View File

@@ -32,6 +32,7 @@ using mozilla::gfx::SharedDIBSurface;
#include "gfxAlphaRecovery.h" #include "gfxAlphaRecovery.h"
#include "mozilla/ArrayUtils.h" #include "mozilla/ArrayUtils.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/ipc/MessageChannel.h" #include "mozilla/ipc/MessageChannel.h"
#include "mozilla/AutoRestore.h" #include "mozilla/AutoRestore.h"
#include "mozilla/StaticPtr.h" #include "mozilla/StaticPtr.h"
@@ -43,6 +44,7 @@ using mozilla::ipc::ProcessChild;
using namespace mozilla::plugins; using namespace mozilla::plugins;
using namespace mozilla::layers; using namespace mozilla::layers;
using namespace mozilla::gfx; using namespace mozilla::gfx;
using namespace mozilla::widget;
using namespace std; using namespace std;
#ifdef MOZ_WIDGET_GTK #ifdef MOZ_WIDGET_GTK
@@ -61,6 +63,8 @@ using namespace std;
#include <windowsx.h> #include <windowsx.h>
#include "mozilla/widget/WinMessages.h" #include "mozilla/widget/WinMessages.h"
#include "mozilla/widget/WinModifierKeyState.h"
#include "mozilla/widget/WinNativeEventData.h"
#include "nsWindowsDllInterceptor.h" #include "nsWindowsDllInterceptor.h"
typedef BOOL (WINAPI *User32TrackPopupMenu)(HMENU hMenu, typedef BOOL (WINAPI *User32TrackPopupMenu)(HMENU hMenu,
@@ -149,6 +153,7 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface,
#if defined(XP_DARWIN) #if defined(XP_DARWIN)
, mContentsScaleFactor(1.0) , mContentsScaleFactor(1.0)
#endif #endif
, mPostingKeyEvents(0)
, mDrawingModel(kDefaultDrawingModel) , mDrawingModel(kDefaultDrawingModel)
, mCurrentDirectSurface(nullptr) , mCurrentDirectSurface(nullptr)
, mAsyncInvalidateMutex("PluginInstanceChild::mAsyncInvalidateMutex") , mAsyncInvalidateMutex("PluginInstanceChild::mAsyncInvalidateMutex")
@@ -1430,6 +1435,61 @@ PluginInstanceChild::Initialize()
return true; return true;
} }
bool
PluginInstanceChild::RecvHandledWindowedPluginKeyEvent(
const NativeEventData& aKeyEventData,
const bool& aIsConsumed)
{
// Unknown key input shouldn't be sent to plugin for security.
// XXX Is this possible if a plugin process which posted the message
// already crashed and this plugin process is recreated?
if (NS_WARN_IF(!mPostingKeyEvents)) {
return true;
}
mPostingKeyEvents--;
if (aIsConsumed) {
return true;
}
#if defined(OS_WIN)
const WinNativeKeyEventData* eventData =
static_cast<const WinNativeKeyEventData*>(aKeyEventData);
UINT message = 0;
switch (eventData->mMessage) {
case WM_KEYDOWN:
message = MOZ_WM_KEYDOWN;
break;
case WM_SYSKEYDOWN:
message = MOZ_WM_SYSKEYDOWN;
break;
case WM_KEYUP:
message = MOZ_WM_KEYUP;
break;
case WM_SYSKEYUP:
message = MOZ_WM_SYSKEYUP;
break;
case WM_CHAR:
message = MOZ_WM_CHAR;
break;
case WM_SYSCHAR:
message = MOZ_WM_SYSCHAR;
break;
case WM_DEADCHAR:
message = MOZ_WM_DEADCHAR;
break;
case WM_SYSDEADCHAR:
message = MOZ_WM_SYSDEADCHAR;
break;
default:
MOZ_CRASH("Needs to handle all messages posted to the parent");
}
PluginWindowProcInternal(mPluginWindowHWND, message,
eventData->mWParam, eventData->mLParam);
#endif
return true;
}
#if defined(OS_WIN) #if defined(OS_WIN)
static const TCHAR kWindowClassName[] = TEXT("GeckoPluginWindow"); static const TCHAR kWindowClassName[] = TEXT("GeckoPluginWindow");
@@ -1588,6 +1648,51 @@ PluginInstanceChild::PluginWindowProcInternal(HWND hWnd,
break; break;
} }
case WM_SETFOCUS:
// If this gets focus, ensure that there is no pending key events.
// Even if there were, we should ignore them for performance reason.
// Although, such case shouldn't occur.
NS_WARN_IF(self->mPostingKeyEvents > 0);
self->mPostingKeyEvents = 0;
break;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
if (self->MaybePostKeyMessage(message, wParam, lParam)) {
// If PreHandleKeyMessage() posts the message to the parent
// process, we need to wait RecvOnKeyEventHandledBeforePlugin()
// to be called.
return 0; // Consume current message temporarily.
}
break;
case MOZ_WM_KEYDOWN:
message = WM_KEYDOWN;
break;
case MOZ_WM_SYSKEYDOWN:
message = WM_SYSKEYDOWN;
break;
case MOZ_WM_KEYUP:
message = WM_KEYUP;
break;
case MOZ_WM_SYSKEYUP:
message = WM_SYSKEYUP;
break;
case MOZ_WM_CHAR:
message = WM_CHAR;
break;
case MOZ_WM_SYSCHAR:
message = WM_SYSCHAR;
break;
case MOZ_WM_DEADCHAR:
message = WM_DEADCHAR;
break;
case MOZ_WM_SYSDEADCHAR:
message = WM_SYSDEADCHAR;
break;
// The plugin received keyboard focus, let the parent know so the dom // The plugin received keyboard focus, let the parent know so the dom
// is up to date. // is up to date.
case WM_MOUSEACTIVATE: case WM_MOUSEACTIVATE:
@@ -1651,6 +1756,87 @@ PluginInstanceChild::PluginWindowProcInternal(HWND hWnd,
return res; return res;
} }
bool
PluginInstanceChild::ShouldPostKeyMessage(UINT message,
WPARAM wParam,
LPARAM lParam)
{
// If there are some pending keyboard events which are not handled in
// the parent process, we should post the message for avoiding to shuffle
// the key event order.
if (mPostingKeyEvents) {
return true;
}
// If we are not waiting calls of RecvOnKeyEventHandledBeforePlugin(),
// we don't need to post WM_*CHAR messages.
switch (message) {
case WM_CHAR:
case WM_SYSCHAR:
case WM_DEADCHAR:
case WM_SYSDEADCHAR:
return false;
}
// Otherwise, we should post key message which might match with a
// shortcut key.
ModifierKeyState modifierState;
if (!modifierState.MaybeMatchShortcutKey()) {
// For better UX, we shouldn't use IPC when user tries to
// input character(s).
return false;
}
// Ignore modifier key events and keys already handled by IME.
switch (wParam) {
case VK_SHIFT:
case VK_CONTROL:
case VK_MENU:
case VK_LWIN:
case VK_RWIN:
case VK_CAPITAL:
case VK_NUMLOCK:
case VK_SCROLL:
// Following virtual keycodes shouldn't come with WM_(SYS)KEY* message
// but check it for avoiding unnecessary cross process communication.
case VK_LSHIFT:
case VK_RSHIFT:
case VK_LCONTROL:
case VK_RCONTROL:
case VK_LMENU:
case VK_RMENU:
case VK_PROCESSKEY:
case VK_PACKET:
case 0xFF: // 0xFF could be sent with unidentified key by the layout.
return false;
default:
break;
}
return true;
}
bool
PluginInstanceChild::MaybePostKeyMessage(UINT message,
WPARAM wParam,
LPARAM lParam)
{
if (!ShouldPostKeyMessage(message, wParam, lParam)) {
return false;
}
ModifierKeyState modifierState;
WinNativeKeyEventData winNativeKeyData(message, wParam, lParam,
modifierState);
NativeEventData nativeKeyData;
nativeKeyData.Copy(winNativeKeyData);
if (NS_WARN_IF(!SendOnWindowedPluginKeyEvent(nativeKeyData))) {
return false;
}
mPostingKeyEvents++;
return true;
}
/* set window long ptr hook for flash */ /* set window long ptr hook for flash */
/* /*

View File

@@ -7,6 +7,7 @@
#ifndef dom_plugins_PluginInstanceChild_h #ifndef dom_plugins_PluginInstanceChild_h
#define dom_plugins_PluginInstanceChild_h 1 #define dom_plugins_PluginInstanceChild_h 1
#include "mozilla/EventForwards.h"
#include "mozilla/plugins/PPluginInstanceChild.h" #include "mozilla/plugins/PPluginInstanceChild.h"
#include "mozilla/plugins/PluginScriptableObjectChild.h" #include "mozilla/plugins/PluginScriptableObjectChild.h"
#include "mozilla/plugins/StreamNotifyChild.h" #include "mozilla/plugins/StreamNotifyChild.h"
@@ -272,6 +273,11 @@ public:
void NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed); void NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed);
void DoAsyncRedraw(); void DoAsyncRedraw();
virtual bool RecvHandledWindowedPluginKeyEvent(
const NativeEventData& aKeyEventData,
const bool& aIsConsumed) override;
private: private:
friend class PluginModuleChild; friend class PluginModuleChild;
@@ -394,7 +400,9 @@ private:
bool mWindowed; bool mWindowed;
}; };
#endif bool ShouldPostKeyMessage(UINT message, WPARAM wParam, LPARAM lParam);
bool MaybePostKeyMessage(UINT message, WPARAM wParam, LPARAM lParam);
#endif // #if defined(OS_WIN)
const NPPluginFuncs* mPluginIface; const NPPluginFuncs* mPluginIface;
nsCString mMimeType; nsCString mMimeType;
uint16_t mMode; uint16_t mMode;
@@ -406,6 +414,7 @@ private:
double mContentsScaleFactor; double mContentsScaleFactor;
#endif #endif
double mCSSZoomFactor; double mCSSZoomFactor;
uint32_t mPostingKeyEvents;
int16_t mDrawingModel; int16_t mDrawingModel;
NPAsyncSurface* mCurrentDirectSurface; NPAsyncSurface* mCurrentDirectSurface;

View File

@@ -7,6 +7,7 @@
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include <stdint.h> // for intptr_t #include <stdint.h> // for intptr_t
#include "mozilla/BasicEvents.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h" #include "mozilla/Telemetry.h"
#include "PluginInstanceParent.h" #include "PluginInstanceParent.h"
@@ -2662,6 +2663,33 @@ PluginInstanceParent::RecvRequestCommitOrCancel(const bool& aCommitted)
return true; return true;
} }
nsresult
PluginInstanceParent::HandledWindowedPluginKeyEvent(
const NativeEventData& aKeyEventData,
bool aIsConsumed)
{
if (NS_WARN_IF(!SendHandledWindowedPluginKeyEvent(aKeyEventData,
aIsConsumed))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
bool
PluginInstanceParent::RecvOnWindowedPluginKeyEvent(
const NativeEventData& aKeyEventData)
{
nsPluginInstanceOwner* owner = GetOwner();
if (NS_WARN_IF(!owner)) {
// Notifies the plugin process of the key event being not consumed
// by us.
HandledWindowedPluginKeyEvent(aKeyEventData, false);
return true;
}
owner->OnWindowedPluginKeyEvent(aKeyEventData);
return true;
}
void void
PluginInstanceParent::RecordDrawingModel() PluginInstanceParent::RecordDrawingModel()
{ {

View File

@@ -25,6 +25,7 @@
#include "PluginDataResolver.h" #include "PluginDataResolver.h"
#include "mozilla/unused.h" #include "mozilla/unused.h"
#include "mozilla/EventForwards.h"
class gfxASurface; class gfxASurface;
class gfxContext; class gfxContext;
@@ -356,6 +357,14 @@ public:
virtual bool virtual bool
RecvRequestCommitOrCancel(const bool& aCommitted) override; RecvRequestCommitOrCancel(const bool& aCommitted) override;
// for reserved shortcut key handling with windowed plugin on Windows
nsresult HandledWindowedPluginKeyEvent(
const mozilla::NativeEventData& aKeyEventData,
bool aIsConsumed);
virtual bool
RecvOnWindowedPluginKeyEvent(
const mozilla::NativeEventData& aKeyEventData) override;
private: private:
// Create an appropriate platform surface for a background of size // Create an appropriate platform surface for a background of size
// |aSize|. Return true if successful. // |aSize|. Return true if successful.

View File

@@ -91,6 +91,10 @@ public:
virtual nsresult GetScrollCaptureContainer(NPP aInstance, mozilla::layers::ImageContainer** aContainer) = 0; virtual nsresult GetScrollCaptureContainer(NPP aInstance, mozilla::layers::ImageContainer** aContainer) = 0;
virtual nsresult UpdateScrollState(NPP aInstance, bool aIsScrolling) = 0; virtual nsresult UpdateScrollState(NPP aInstance, bool aIsScrolling) = 0;
#endif #endif
virtual nsresult HandledWindowedPluginKeyEvent(
NPP aInstance,
const mozilla::NativeEventData& aNativeKeyData,
bool aIsCOnsumed) = 0;
/** /**
* The next three methods are the third leg in the trip to * The next three methods are the third leg in the trip to

View File

@@ -2014,6 +2014,19 @@ PluginModuleParent::UpdateScrollState(NPP aInstance, bool aIsScrolling)
} }
#endif #endif
nsresult
PluginModuleParent::HandledWindowedPluginKeyEvent(
NPP aInstance,
const NativeEventData& aNativeKeyData,
bool aIsConsumed)
{
PluginInstanceParent* parent = PluginInstanceParent::Cast(aInstance);
if (NS_WARN_IF(!parent)) {
return NS_ERROR_FAILURE;
}
return parent->HandledWindowedPluginKeyEvent(aNativeKeyData, aIsConsumed);
}
void void
PluginModuleParent::OnInitFailure() PluginModuleParent::OnInitFailure()
{ {

View File

@@ -266,6 +266,11 @@ protected:
virtual nsresult UpdateScrollState(NPP aInstance, bool aIsScrolling); virtual nsresult UpdateScrollState(NPP aInstance, bool aIsScrolling);
#endif #endif
virtual nsresult HandledWindowedPluginKeyEvent(
NPP aInstance,
const mozilla::NativeEventData& aNativeKeyData,
bool aIsConsumed) override;
#if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK) #if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK)
virtual nsresult NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error) override; virtual nsresult NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error) override;
#else #else

View File

@@ -1459,5 +1459,34 @@ PuppetWidget::HasPendingInputEvent()
return ret; return ret;
} }
void
PuppetWidget::HandledWindowedPluginKeyEvent(
const NativeEventData& aKeyEventData,
bool aIsConsumed)
{
if (NS_WARN_IF(mKeyEventInPluginCallbacks.IsEmpty())) {
return;
}
nsCOMPtr<nsIKeyEventInPluginCallback> callback =
mKeyEventInPluginCallbacks[0];
MOZ_ASSERT(callback);
mKeyEventInPluginCallbacks.RemoveElementAt(0);
callback->HandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
}
nsresult
PuppetWidget::OnWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
nsIKeyEventInPluginCallback* aCallback)
{
if (NS_WARN_IF(!mTabChild)) {
return NS_ERROR_NOT_AVAILABLE;
}
if (NS_WARN_IF(!mTabChild->SendOnWindowedPluginKeyEvent(aKeyEventData))) {
return NS_ERROR_FAILURE;
}
mKeyEventInPluginCallbacks.AppendElement(aCallback);
return NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY;
}
} // namespace widget } // namespace widget
} // namespace mozilla } // namespace mozilla

View File

@@ -19,6 +19,8 @@
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "nsBaseScreen.h" #include "nsBaseScreen.h"
#include "nsBaseWidget.h" #include "nsBaseWidget.h"
#include "nsCOMArray.h"
#include "nsIKeyEventInPluginCallback.h"
#include "nsIScreenManager.h" #include "nsIScreenManager.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
@@ -262,6 +264,12 @@ public:
virtual bool HasPendingInputEvent() override; virtual bool HasPendingInputEvent() override;
void HandledWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
bool aIsConsumed);
virtual nsresult OnWindowedPluginKeyEvent(
const NativeEventData& aKeyEventData,
nsIKeyEventInPluginCallback* aCallback) override;
protected: protected:
virtual nsresult NotifyIMEInternal( virtual nsresult NotifyIMEInternal(
const IMENotification& aIMENotification) override; const IMENotification& aIMENotification) override;
@@ -348,6 +356,8 @@ private:
nsCOMPtr<imgIContainer> mCustomCursor; nsCOMPtr<imgIContainer> mCustomCursor;
uint32_t mCursorHotspotX, mCursorHotspotY; uint32_t mCursorHotspotX, mCursorHotspotY;
nsCOMArray<nsIKeyEventInPluginCallback> mKeyEventInPluginCallbacks;
protected: protected:
bool mEnabled; bool mEnabled;
bool mVisible; bool mVisible;

View File

@@ -96,6 +96,7 @@ EXPORTS += [
'nsBaseWidget.h', 'nsBaseWidget.h',
'nsDeviceContextSpecProxy.h', 'nsDeviceContextSpecProxy.h',
'nsIDeviceContextSpec.h', 'nsIDeviceContextSpec.h',
'nsIKeyEventInPluginCallback.h',
'nsIPluginWidget.h', 'nsIPluginWidget.h',
'nsIRollupListener.h', 'nsIRollupListener.h',
'nsIWidget.h', 'nsIWidget.h',

View File

@@ -18,6 +18,7 @@
#include "nsGfxCIID.h" #include "nsGfxCIID.h"
#include "nsWidgetsCID.h" #include "nsWidgetsCID.h"
#include "nsServiceManagerUtils.h" #include "nsServiceManagerUtils.h"
#include "nsIKeyEventInPluginCallback.h"
#include "nsIScreenManager.h" #include "nsIScreenManager.h"
#include "nsAppDirectoryServiceDefs.h" #include "nsAppDirectoryServiceDefs.h"
#include "nsISimpleEnumerator.h" #include "nsISimpleEnumerator.h"
@@ -2140,6 +2141,13 @@ nsIWidget::GetNativeIMEContext()
return NativeIMEContext(this); return NativeIMEContext(this);
} }
nsresult
nsIWidget::OnWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
nsIKeyEventInPluginCallback* aCallback)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
namespace mozilla { namespace mozilla {
namespace widget { namespace widget {

View File

@@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsIKeyEventInPluginCallback_h_
#define nsIKeyEventInPluginCallback_h_
#include "mozilla/EventForwards.h"
#include "nsISupports.h"
#define NS_IKEYEVENTINPLUGINCALLBACK_IID \
{ 0x543c5a8a, 0xc50e, 0x4cf9, \
{ 0xa6, 0xba, 0x29, 0xa1, 0xc5, 0xa5, 0x47, 0x07 } }
class nsIKeyEventInPluginCallback : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IKEYEVENTINPLUGINCALLBACK_IID)
/**
* HandledWindowedPluginKeyEvent() is a callback method of
* nsIWidget::OnWindowedPluginKeyEvent(). When it returns
* NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY, it should call this method
* when the key event is handled.
*
* @param aKeyEventData The key event which was posted to the parent
* process from a plugin process.
* @param aIsConsumed true if aKeyEventData is consumed in the
* parent process. Otherwise, false.
*/
virtual void HandledWindowedPluginKeyEvent(
const mozilla::NativeEventData& aKeyEventData,
bool aIsConsumed) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIKeyEventInPluginCallback,
NS_IKEYEVENTINPLUGINCALLBACK_IID)
#endif // #ifndef nsIKeyEventInPluginCallback_h_

View File

@@ -39,6 +39,7 @@ class nsIContent;
class ViewWrapper; class ViewWrapper;
class nsIScreen; class nsIScreen;
class nsIRunnable; class nsIRunnable;
class nsIKeyEventInPluginCallback;
namespace mozilla { namespace mozilla {
class CompositorVsyncDispatcher; class CompositorVsyncDispatcher;
@@ -2054,6 +2055,28 @@ public:
const CSSRect& aRect, const CSSRect& aRect,
const uint32_t& aFlags) = 0; const uint32_t& aFlags) = 0;
/**
* OnWindowedPluginKeyEvent() is called when native key event is
* received in the focused plugin process directly in PluginInstanceChild.
*
* @param aKeyEventData The native key event data. The actual type
* copied into NativeEventData depends on the
* caller. Please check PluginInstanceChild.
* @param aCallback Callback interface. When this returns
* NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY,
* the event handler has to call this callback.
* Otherwise, the caller should do that instead.
* @return NS_ERROR_* if this fails to handle the event.
* NS_SUCCESS_EVENT_CONSUMED if the key event is
* consumed.
* NS_OK if the key event isn't consumed.
* NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY if the
* key event will be handled asynchronously.
*/
virtual nsresult OnWindowedPluginKeyEvent(
const mozilla::NativeEventData& aKeyEventData,
nsIKeyEventInPluginCallback* aCallback);
protected: protected:
/** /**
* Like GetDefaultScale, but taking into account only the system settings * Like GetDefaultScale, but taking into account only the system settings

View File

@@ -34,6 +34,17 @@
// Internal message used for hiding the on-screen keyboard // Internal message used for hiding the on-screen keyboard
#define MOZ_WM_DISMISS_ONSCREEN_KEYBOARD (WM_APP+0x0317) #define MOZ_WM_DISMISS_ONSCREEN_KEYBOARD (WM_APP+0x0317)
// Following MOZ_WM_*KEY* messages are used by PluginInstanceChild internally.
// (never posted to the queue)
#define MOZ_WM_KEYDOWN (WM_APP+0x0318)
#define MOZ_WM_KEYUP (WM_APP+0x0319)
#define MOZ_WM_SYSKEYDOWN (WM_APP+0x031A)
#define MOZ_WM_SYSKEYUP (WM_APP+0x031B)
#define MOZ_WM_CHAR (WM_APP+0x031C)
#define MOZ_WM_SYSCHAR (WM_APP+0x031D)
#define MOZ_WM_DEADCHAR (WM_APP+0x031E)
#define MOZ_WM_SYSDEADCHAR (WM_APP+0x031F)
// Internal message for ensuring the file picker is visible on multi monitor // Internal message for ensuring the file picker is visible on multi monitor
// systems, and when the screen resolution changes. // systems, and when the screen resolution changes.
#define MOZ_WM_ENSUREVISIBLE (WM_APP+0x374F) #define MOZ_WM_ENSUREVISIBLE (WM_APP+0x374F)

View File

@@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_widget_WinNativeEventData_h_
#define mozilla_widget_WinNativeEventData_h_
#include <windows.h>
#include "mozilla/EventForwards.h"
#include "mozilla/widget/WinModifierKeyState.h"
namespace mozilla {
namespace widget {
/**
* WinNativeKeyEventData is used by nsIWidget::OnWindowedPluginKeyEvent() and
* related IPC methods. This class cannot hold any pointers and references
* since which are not available in different process.
*/
class WinNativeKeyEventData final
{
public:
UINT mMessage;
WPARAM mWParam;
LPARAM mLParam;
Modifiers mModifiers;
private:
uintptr_t mKeyboardLayout;
public:
WinNativeKeyEventData(UINT aMessage,
WPARAM aWParam,
LPARAM aLParam,
const ModifierKeyState& aModifierKeyState)
: mMessage(aMessage)
, mWParam(aWParam)
, mLParam(aLParam)
, mModifiers(aModifierKeyState.GetModifiers())
, mKeyboardLayout(reinterpret_cast<uintptr_t>(::GetKeyboardLayout(0)))
{
}
HKL GetKeyboardLayout() const
{
return reinterpret_cast<HKL>(mKeyboardLayout);
}
};
} // namespace widget
} // namespace mozilla
#endif // #ifndef mozilla_widget_WinNativeEventData_h_

View File

@@ -16,6 +16,7 @@ EXPORTS.mozilla.widget += [
'AudioSession.h', 'AudioSession.h',
'WinMessages.h', 'WinMessages.h',
'WinModifierKeyState.h', 'WinModifierKeyState.h',
'WinNativeEventData.h',
] ]
UNIFIED_SOURCES += [ UNIFIED_SOURCES += [

View File

@@ -86,6 +86,7 @@
#include "nsIAppShell.h" #include "nsIAppShell.h"
#include "nsISupportsPrimitives.h" #include "nsISupportsPrimitives.h"
#include "nsIDOMMouseEvent.h" #include "nsIDOMMouseEvent.h"
#include "nsIKeyEventInPluginCallback.h"
#include "nsITheme.h" #include "nsITheme.h"
#include "nsIObserverService.h" #include "nsIObserverService.h"
#include "nsIScreenManager.h" #include "nsIScreenManager.h"
@@ -7869,6 +7870,14 @@ nsWindow::DefaultProcOfPluginEvent(const WidgetPluginEvent& aEvent)
pPluginEvent->wParam, pPluginEvent->lParam); pPluginEvent->wParam, pPluginEvent->lParam);
} }
nsresult
nsWindow::OnWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
nsIKeyEventInPluginCallback* aCallback)
{
// TODO: Implement in the following patch.
return NS_ERROR_NOT_IMPLEMENTED;
}
/************************************************************** /**************************************************************
************************************************************** **************************************************************
** **

View File

@@ -311,6 +311,9 @@ public:
aPosition) override; aPosition) override;
virtual void DefaultProcOfPluginEvent( virtual void DefaultProcOfPluginEvent(
const mozilla::WidgetPluginEvent& aEvent) override; const mozilla::WidgetPluginEvent& aEvent) override;
virtual nsresult OnWindowedPluginKeyEvent(
const mozilla::NativeEventData& aKeyEventData,
nsIKeyEventInPluginCallback* aCallback) override;
protected: protected:
virtual ~nsWindow(); virtual ~nsWindow();

View File

@@ -118,9 +118,17 @@
/* 4: NS_ERROR_MODULE_WIDGET */ /* 4: NS_ERROR_MODULE_WIDGET */
/* ======================================================================= */ /* ======================================================================= */
#define MODULE NS_ERROR_MODULE_WIDGET #define MODULE NS_ERROR_MODULE_WIDGET
/* Used by nsIWidget::NotifyIME(). Returned when the notification is handled /* Used by:
* and the notified event is consumed by IME. */ * - nsIWidget::NotifyIME()
* - nsIWidget::OnWindowedPluginKeyEvent()
* Returned when the notification or the event is handled and it's consumed
* by somebody. */
ERROR(NS_SUCCESS_EVENT_CONSUMED, SUCCESS(1)), ERROR(NS_SUCCESS_EVENT_CONSUMED, SUCCESS(1)),
/* Used by:
* - nsIWidget::OnWindowedPluginKeyEvent()
* Returned when the event is handled correctly but the result will be
* notified asynchronously. */
ERROR(NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY, SUCCESS(2)),
#undef MODULE #undef MODULE