From 14da2adae7a66d901855563f2926dee1997297d6 Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Wed, 24 Feb 2010 16:13:48 -0800 Subject: [PATCH] Bug 547353 - [OOPP] Mouse pointer coordinates misaligned with winless Silverlight. r=bent. --- dom/plugins/PluginInstanceChild.cpp | 153 +++++++++++++++++++--------- dom/plugins/PluginInstanceChild.h | 10 +- dom/plugins/PluginModuleChild.cpp | 2 +- 3 files changed, 116 insertions(+), 49 deletions(-) diff --git a/dom/plugins/PluginInstanceChild.cpp b/dom/plugins/PluginInstanceChild.cpp index cc0a45d9f7a..2b53744d11f 100644 --- a/dom/plugins/PluginInstanceChild.cpp +++ b/dom/plugins/PluginInstanceChild.cpp @@ -61,6 +61,7 @@ using namespace mozilla::plugins; using mozilla::gfx::SharedDIB; #include +#include #define NS_OOPP_DOUBLEPASS_MSGID TEXT("MozDoublePassMsg") @@ -73,10 +74,12 @@ using mozilla::gfx::SharedDIB; #endif // defined(OS_WIN) -PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface) : - mPluginIface(aPluginIface), - mCachedWindowActor(nsnull), - mCachedElementActor(nsnull) +PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface, + const nsCString& aMimeType) : + mPluginIface(aPluginIface) + , mCachedWindowActor(nsnull) + , mCachedElementActor(nsnull) + , mQuirks(0) #if defined(OS_WIN) , mPluginWindowHWND(0) , mPluginWndProc(0) @@ -104,6 +107,7 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface) : memset(&mAlphaExtract, 0, sizeof(mAlphaExtract)); mAlphaExtract.doublePassEvent = ::RegisterWindowMessage(NS_OOPP_DOUBLEPASS_MSGID); #endif // OS_WIN + InitQuirksModes(aMimeType); } PluginInstanceChild::~PluginInstanceChild() @@ -113,6 +117,19 @@ PluginInstanceChild::~PluginInstanceChild() #endif } +void +PluginInstanceChild::InitQuirksModes(const nsCString& aMimeType) +{ +#ifdef OS_WIN + // application/x-silverlight + // application/x-silverlight-2 + NS_NAMED_LITERAL_CSTRING(silverlight, "application/x-silverlight"); + if (FindInReadable(silverlight, aMimeType)) { + mQuirks |= QUIRK_SILVERLIGHT_WINLESS_INPUT_TRANSLATION; + } +#endif +} + NPError PluginInstanceChild::InternalGetNPObjectForValue(NPNVariable aValue, NPObject** aObject) @@ -791,23 +808,6 @@ PluginInstanceChild::PluginWindowProc(HWND hWnd, /* winless modal ui loop logic */ -static bool -IsUserInputEvent(UINT msg) -{ - // Events we assume some sort of modal ui *might* be generated. - switch (msg) { - case WM_LBUTTONUP: - case WM_RBUTTONUP: - case WM_MBUTTONUP: - case WM_LBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_CONTEXTMENU: - return true; - } - return false; -} - VOID CALLBACK PluginInstanceChild::PumpTimerProc(HWND hwnd, UINT uMsg, @@ -923,42 +923,101 @@ PluginInstanceChild::InternalCallSetNestedEventState(bool aState) } } +/* windowless handle event helpers */ + +static bool +NeedsNestedEventCoverage(UINT msg) +{ + // Events we assume some sort of modal ui *might* be generated. + switch (msg) { + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_CONTEXTMENU: + return true; + } + return false; +} + +static bool +IsMouseInputEvent(UINT msg) +{ + switch (msg) { + case WM_MOUSEMOVE: + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + return true; + } + return false; +} + int16_t PluginInstanceChild::WinlessHandleEvent(NPEvent& event) { - if (!IsUserInputEvent(event.event)) { - return mPluginIface->event(&mData, reinterpret_cast(&event)); - } + // Winless Silverlight quirk: winposchanged events are not used in + // determining the position of the plugin within the parent window, + // NPP_SetWindow values are used instead. Due to shared memory dib + // rendering, the origin of NPP_SetWindow is 0x0, so we trap + // winposchanged events here and do the translation internally for + // mouse input events. + if (mQuirks & QUIRK_SILVERLIGHT_WINLESS_INPUT_TRANSLATION) { + if (event.event == WM_WINDOWPOSCHANGED && event.lParam) { + WINDOWPOS* pos = reinterpret_cast(event.lParam); + mPluginOffset.x = pos->x; + mPluginOffset.y = pos->y; + } + else if (IsMouseInputEvent(event.event)) { + event.lParam = + MAKELPARAM((GET_X_LPARAM(event.lParam) - mPluginOffset.x), + (GET_Y_LPARAM(event.lParam) - mPluginOffset.y)); + } + } - int16_t handled; + if (!NeedsNestedEventCoverage(event.event)) { + return mPluginIface->event(&mData, reinterpret_cast(&event)); + } - mNestedEventLevelDepth++; - PLUGIN_LOG_DEBUG(("WinlessHandleEvent start depth: %i", mNestedEventLevelDepth)); + // Events that might generate nested event dispatch loops need + // special handling during delivery. + int16_t handled; - // On the first, non-reentrant call, setup our modal ui detection hook. - if (mNestedEventLevelDepth == 1) { - NS_ASSERTION(!gTempChildPointer, "valid gTempChildPointer here?"); - gTempChildPointer = this; - SetNestedInputEventHook(); - } + mNestedEventLevelDepth++; + PLUGIN_LOG_DEBUG(("WinlessHandleEvent start depth: %i", mNestedEventLevelDepth)); - bool old_state = MessageLoop::current()->NestableTasksAllowed(); - MessageLoop::current()->SetNestableTasksAllowed(true); - handled = mPluginIface->event(&mData, reinterpret_cast(&event)); - MessageLoop::current()->SetNestableTasksAllowed(old_state); + // On the first, non-reentrant call, setup our modal ui detection hook. + if (mNestedEventLevelDepth == 1) { + NS_ASSERTION(!gTempChildPointer, "valid gTempChildPointer here?"); + gTempChildPointer = this; + SetNestedInputEventHook(); + } - gTempChildPointer = NULL; + bool old_state = MessageLoop::current()->NestableTasksAllowed(); + MessageLoop::current()->SetNestableTasksAllowed(true); + handled = mPluginIface->event(&mData, reinterpret_cast(&event)); + MessageLoop::current()->SetNestableTasksAllowed(old_state); - mNestedEventLevelDepth--; - PLUGIN_LOG_DEBUG(("WinlessHandleEvent end depth: %i", mNestedEventLevelDepth)); + gTempChildPointer = NULL; - NS_ASSERTION(!(mNestedEventLevelDepth < 0), "mNestedEventLevelDepth < 0?"); - if (mNestedEventLevelDepth <= 0) { - ResetNestedEventHook(); - ResetPumpHooks(); - InternalCallSetNestedEventState(false); - } - return handled; + mNestedEventLevelDepth--; + PLUGIN_LOG_DEBUG(("WinlessHandleEvent end depth: %i", mNestedEventLevelDepth)); + + NS_ASSERTION(!(mNestedEventLevelDepth < 0), "mNestedEventLevelDepth < 0?"); + if (mNestedEventLevelDepth <= 0) { + ResetNestedEventHook(); + ResetPumpHooks(); + InternalCallSetNestedEventState(false); + } + return handled; } /* windowless drawing helpers */ diff --git a/dom/plugins/PluginInstanceChild.h b/dom/plugins/PluginInstanceChild.h index c0d7711c1cb..bf06bba2d58 100644 --- a/dom/plugins/PluginInstanceChild.h +++ b/dom/plugins/PluginInstanceChild.h @@ -149,7 +149,7 @@ protected: AnswerUpdateWindow(); public: - PluginInstanceChild(const NPPluginFuncs* aPluginIface); + PluginInstanceChild(const NPPluginFuncs* aPluginIface, const nsCString& aMimeType); virtual ~PluginInstanceChild(); @@ -181,6 +181,12 @@ public: void UnscheduleTimer(uint32_t id); private: + // Quirks mode support for various plugin mime types + enum PluginQuirks { + QUIRK_SILVERLIGHT_WINLESS_INPUT_TRANSLATION = 1, // Win32 + }; + + void InitQuirksModes(const nsCString& aMimeType); NPError InternalGetNPObjectForValue(NPNVariable aValue, @@ -221,6 +227,7 @@ private: const NPPluginFuncs* mPluginIface; NPP_t mData; NPWindow mWindow; + int mQuirks; // Cached scriptable actors to avoid IPC churn PluginScriptableObjectChild* mCachedWindowActor; @@ -239,6 +246,7 @@ private: HWND mCachedWinlessPluginHWND; UINT_PTR mEventPumpTimer; nsIntPoint mPluginSize; + nsIntPoint mPluginOffset; #endif friend class ChildAsyncCall; diff --git a/dom/plugins/PluginModuleChild.cpp b/dom/plugins/PluginModuleChild.cpp index 3dc87c9b281..884e1a2568a 100644 --- a/dom/plugins/PluginModuleChild.cpp +++ b/dom/plugins/PluginModuleChild.cpp @@ -1448,7 +1448,7 @@ PluginModuleChild::AllocPPluginInstance(const nsCString& aMimeType, AssertPluginThread(); nsAutoPtr childInstance( - new PluginInstanceChild(&mFunctions)); + new PluginInstanceChild(&mFunctions, aMimeType)); if (!childInstance->Initialize()) { *rv = NPERR_GENERIC_ERROR; return 0;