diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /dom/plugins/base/nsPluginNativeWindowWin.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/plugins/base/nsPluginNativeWindowWin.cpp')
-rw-r--r-- | dom/plugins/base/nsPluginNativeWindowWin.cpp | 748 |
1 files changed, 748 insertions, 0 deletions
diff --git a/dom/plugins/base/nsPluginNativeWindowWin.cpp b/dom/plugins/base/nsPluginNativeWindowWin.cpp new file mode 100644 index 000000000..106dcaf77 --- /dev/null +++ b/dom/plugins/base/nsPluginNativeWindowWin.cpp @@ -0,0 +1,748 @@ +/* -*- 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/. */ + +#include "mozilla/BasicEvents.h" +#include "mozilla/DebugOnly.h" + +#include "windows.h" +#include "windowsx.h" + +// XXXbz windowsx.h defines GetFirstChild, GetNextSibling, +// GetPrevSibling are macros, apparently... Eeevil. We have functions +// called that on some classes, so undef them. +#undef GetFirstChild +#undef GetNextSibling +#undef GetPrevSibling + +#include "nsDebug.h" + +#include "nsWindowsDllInterceptor.h" +#include "nsPluginNativeWindow.h" +#include "nsThreadUtils.h" +#include "nsTWeakRef.h" +#include "nsCrashOnException.h" + +using namespace mozilla; + +#define NP_POPUP_API_VERSION 16 + +#define nsMajorVersion(v) (((int32_t)(v) >> 16) & 0xffff) +#define nsMinorVersion(v) ((int32_t)(v) & 0xffff) +#define versionOK(suppliedV, requiredV) \ + (nsMajorVersion(suppliedV) == nsMajorVersion(requiredV) \ + && nsMinorVersion(suppliedV) >= nsMinorVersion(requiredV)) + + +#define NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION TEXT("MozillaPluginWindowPropertyAssociation") +#define NS_PLUGIN_CUSTOM_MSG_ID TEXT("MozFlashUserRelay") +#define WM_USER_FLASH WM_USER+1 +static UINT sWM_FLASHBOUNCEMSG = 0; + +typedef nsTWeakRef<class nsPluginNativeWindowWin> PluginWindowWeakRef; + +/** + * PLEvent handling code + */ +class PluginWindowEvent : public Runnable { +public: + PluginWindowEvent(); + void Init(const PluginWindowWeakRef &ref, HWND hWnd, UINT msg, WPARAM wParam, + LPARAM lParam); + void Clear(); + HWND GetWnd() { return mWnd; }; + UINT GetMsg() { return mMsg; }; + WPARAM GetWParam() { return mWParam; }; + LPARAM GetLParam() { return mLParam; }; + bool InUse() { return mWnd != nullptr; }; + + NS_DECL_NSIRUNNABLE + +protected: + PluginWindowWeakRef mPluginWindowRef; + HWND mWnd; + UINT mMsg; + WPARAM mWParam; + LPARAM mLParam; +}; + +PluginWindowEvent::PluginWindowEvent() +{ + Clear(); +} + +void PluginWindowEvent::Clear() +{ + mWnd = nullptr; + mMsg = 0; + mWParam = 0; + mLParam = 0; +} + +void PluginWindowEvent::Init(const PluginWindowWeakRef &ref, HWND aWnd, + UINT aMsg, WPARAM aWParam, LPARAM aLParam) +{ + NS_ASSERTION(aWnd != nullptr, "invalid plugin event value"); + NS_ASSERTION(mWnd == nullptr, "event already in use"); + mPluginWindowRef = ref; + mWnd = aWnd; + mMsg = aMsg; + mWParam = aWParam; + mLParam = aLParam; +} + +/** + * nsPluginNativeWindow Windows specific class declaration + */ + +class nsPluginNativeWindowWin : public nsPluginNativeWindow { +public: + nsPluginNativeWindowWin(); + virtual ~nsPluginNativeWindowWin(); + + virtual nsresult CallSetWindow(RefPtr<nsNPAPIPluginInstance> &aPluginInstance); + +private: + nsresult SubclassAndAssociateWindow(); + nsresult UndoSubclassAndAssociateWindow(); + +public: + // locals + WNDPROC GetPrevWindowProc(); + void SetPrevWindowProc(WNDPROC proc) { mPluginWinProc = proc; } + WNDPROC GetWindowProc(); + PluginWindowEvent * GetPluginWindowEvent(HWND aWnd, + UINT aMsg, + WPARAM aWParam, + LPARAM aLParam); + +private: + WNDPROC mPluginWinProc; + WNDPROC mPrevWinProc; + PluginWindowWeakRef mWeakRef; + RefPtr<PluginWindowEvent> mCachedPluginWindowEvent; + + HWND mParentWnd; + LONG_PTR mParentProc; +public: + nsPluginHost::SpecialType mPluginType; +}; + +static bool sInMessageDispatch = false; +static bool sInPreviousMessageDispatch = false; +static UINT sLastMsg = 0; + +static bool ProcessFlashMessageDelayed(nsPluginNativeWindowWin * aWin, nsNPAPIPluginInstance * aInst, + HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + NS_ENSURE_TRUE(aWin, false); + NS_ENSURE_TRUE(aInst, false); + + if (msg == sWM_FLASHBOUNCEMSG) { + // See PluginWindowEvent::Run() below. + NS_ASSERTION((sWM_FLASHBOUNCEMSG != 0), "RegisterWindowMessage failed in flash plugin WM_USER message handling!"); + ::CallWindowProc((WNDPROC)aWin->GetWindowProc(), hWnd, WM_USER_FLASH, wParam, lParam); + return true; + } + + if (msg != WM_USER_FLASH) + return false; // no need to delay + + // do stuff + nsCOMPtr<nsIRunnable> pwe = aWin->GetPluginWindowEvent(hWnd, msg, wParam, lParam); + if (pwe) { + NS_DispatchToCurrentThread(pwe); + return true; + } + return false; +} + +class nsDelayedPopupsEnabledEvent : public Runnable +{ +public: + nsDelayedPopupsEnabledEvent(nsNPAPIPluginInstance *inst) + : mInst(inst) + {} + + NS_DECL_NSIRUNNABLE + +private: + RefPtr<nsNPAPIPluginInstance> mInst; +}; + +NS_IMETHODIMP nsDelayedPopupsEnabledEvent::Run() +{ + mInst->PushPopupsEnabledState(false); + return NS_OK; +} + +static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +/** + * New plugin window procedure + * + * e10s note - this subclass, and the hooks we set below using WindowsDllInterceptor + * are currently not in use when running with e10s. (Utility calls like CallSetWindow + * are still in use in the content process.) We would like to keep things this away, + * essentially making all the hacks here obsolete. Some of the mitigation work here has + * already been supplanted by code in PluginInstanceChild. The rest we eventually want + * to rip out. + */ +static LRESULT CALLBACK PluginWndProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + nsPluginNativeWindowWin * win = (nsPluginNativeWindowWin *)::GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); + if (!win) + return TRUE; + + // The DispatchEvent(ePluginActivate) below can trigger a reentrant focus + // event which might destroy us. Hold a strong ref on the plugin instance + // to prevent that, bug 374229. + RefPtr<nsNPAPIPluginInstance> inst; + win->GetPluginInstance(inst); + + // Real may go into a state where it recursivly dispatches the same event + // when subclassed. If this is Real, lets examine the event and drop it + // on the floor if we get into this recursive situation. See bug 192914. + if (win->mPluginType == nsPluginHost::eSpecialType_RealPlayer) { + if (sInMessageDispatch && msg == sLastMsg) + return true; + // Cache the last message sent + sLastMsg = msg; + } + + bool enablePopups = false; + + // Activate/deactivate mouse capture on the plugin widget + // here, before we pass the Windows event to the plugin + // because its possible our widget won't get paired events + // (see bug 131007) and we'll look frozen. Note that this + // is also done in ChildWindow::DispatchMouseEvent. + switch (msg) { + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: { + nsCOMPtr<nsIWidget> widget; + win->GetPluginWidget(getter_AddRefs(widget)); + if (widget) + widget->CaptureMouse(true); + break; + } + case WM_LBUTTONUP: + enablePopups = true; + + // fall through + case WM_MBUTTONUP: + case WM_RBUTTONUP: { + nsCOMPtr<nsIWidget> widget; + win->GetPluginWidget(getter_AddRefs(widget)); + if (widget) + widget->CaptureMouse(false); + break; + } + case WM_KEYDOWN: + // Ignore repeating keydown messages... + if ((lParam & 0x40000000) != 0) { + break; + } + + // fall through + case WM_KEYUP: + enablePopups = true; + + break; + + case WM_MOUSEACTIVATE: { + // If a child window of this plug-in is already focused, + // don't focus the parent to avoid focus dance. We'll + // receive a follow up WM_SETFOCUS which will notify + // the appropriate window anyway. + HWND focusedWnd = ::GetFocus(); + if (!::IsChild((HWND)win->window, focusedWnd)) { + // Notify the dom / focus manager the plugin has focus when one of + // it's child windows receives it. OOPP specific - this code is + // critical in notifying the dom of focus changes when the plugin + // window in the child process receives focus via a mouse click. + // WM_MOUSEACTIVATE is sent by nsWindow via a custom window event + // sent from PluginInstanceParent in response to focus events sent + // from the child. (bug 540052) Note, this gui event could also be + // sent directly from widget. + nsCOMPtr<nsIWidget> widget; + win->GetPluginWidget(getter_AddRefs(widget)); + if (widget) { + WidgetGUIEvent event(true, ePluginActivate, widget); + nsEventStatus status; + widget->DispatchEvent(&event, status); + } + } + } + break; + + case WM_SETFOCUS: + case WM_KILLFOCUS: { + // RealPlayer can crash, don't process the message for those, + // see bug 328675. + if (win->mPluginType == nsPluginHost::eSpecialType_RealPlayer && msg == sLastMsg) + return TRUE; + // Make sure setfocus and killfocus get through to the widget procedure + // even if they are eaten by the plugin. Also make sure we aren't calling + // recursively. + WNDPROC prevWndProc = win->GetPrevWindowProc(); + if (prevWndProc && !sInPreviousMessageDispatch) { + sInPreviousMessageDispatch = true; + ::CallWindowProc(prevWndProc, hWnd, msg, wParam, lParam); + sInPreviousMessageDispatch = false; + } + break; + } + } + + // Macromedia Flash plugin may flood the message queue with some special messages + // (WM_USER+1) causing 100% CPU consumption and GUI freeze, see mozilla bug 132759; + // we can prevent this from happening by delaying the processing such messages; + if (win->mPluginType == nsPluginHost::eSpecialType_Flash) { + if (ProcessFlashMessageDelayed(win, inst, hWnd, msg, wParam, lParam)) + return TRUE; + } + + if (enablePopups && inst) { + uint16_t apiVersion; + if (NS_SUCCEEDED(inst->GetPluginAPIVersion(&apiVersion)) && + !versionOK(apiVersion, NP_POPUP_API_VERSION)) { + inst->PushPopupsEnabledState(true); + } + } + + sInMessageDispatch = true; + LRESULT res; + WNDPROC proc = (WNDPROC)win->GetWindowProc(); + if (PluginWndProc == proc) { + NS_WARNING("Previous plugin window procedure references PluginWndProc! " + "Report this bug!"); + res = CallWindowProc(DefWindowProc, hWnd, msg, wParam, lParam); + } else { + res = CallWindowProc(proc, hWnd, msg, wParam, lParam); + } + sInMessageDispatch = false; + + if (inst) { + // Popups are enabled (were enabled before the call to + // CallWindowProc()). Some plugins (at least the flash player) + // post messages from their key handlers etc that delay the actual + // processing, so we need to delay the disabling of popups so that + // popups remain enabled when the flash player ends up processing + // the actual key handlers. We do this by posting an event that + // does the disabling, this way our disabling will happen after + // the handlers in the plugin are done. + + // Note that it's not fatal if any of this fails (which won't + // happen unless we're out of memory anyways) since the plugin + // code will pop any popup state pushed by this plugin on + // destruction. + + nsCOMPtr<nsIRunnable> event = new nsDelayedPopupsEnabledEvent(inst); + if (event) + NS_DispatchToCurrentThread(event); + } + + return res; +} + +static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + return mozilla::CallWindowProcCrashProtected(PluginWndProcInternal, hWnd, msg, wParam, lParam); +} + +/* + * Flash will reset the subclass of our widget at various times. + * (Notably when entering and exiting full screen mode.) This + * occurs independent of the main plugin window event procedure. + * We trap these subclass calls to prevent our subclass hook from + * getting dropped. + * Note, ascii versions can be nixed once flash versions < 10.1 + * are considered obsolete. + */ +static WindowsDllInterceptor sUser32Intercept; + +#ifdef _WIN64 +typedef LONG_PTR + (WINAPI *User32SetWindowLongPtrA)(HWND hWnd, + int nIndex, + LONG_PTR dwNewLong); +typedef LONG_PTR + (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, + int nIndex, + LONG_PTR dwNewLong); +static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; +static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; +#else +typedef LONG +(WINAPI *User32SetWindowLongA)(HWND hWnd, + int nIndex, + LONG dwNewLong); +typedef LONG +(WINAPI *User32SetWindowLongW)(HWND hWnd, + int nIndex, + LONG dwNewLong); +static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; +static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; +#endif +static inline bool +SetWindowLongHookCheck(HWND hWnd, + int nIndex, + LONG_PTR newLong) +{ + nsPluginNativeWindowWin * win = + (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); + if (!win || (win && win->mPluginType != nsPluginHost::eSpecialType_Flash) || + (nIndex == GWLP_WNDPROC && + newLong == reinterpret_cast<LONG_PTR>(PluginWndProc))) + return true; + return false; +} + +#ifdef _WIN64 +LONG_PTR WINAPI +SetWindowLongPtrAHook(HWND hWnd, + int nIndex, + LONG_PTR newLong) +#else +LONG WINAPI +SetWindowLongAHook(HWND hWnd, + int nIndex, + LONG newLong) +#endif +{ + if (SetWindowLongHookCheck(hWnd, nIndex, newLong)) + return sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong); + + // Set flash's new subclass to get the result. + LONG_PTR proc = sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong); + + // We already checked this in SetWindowLongHookCheck + nsPluginNativeWindowWin * win = + (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); + + // Hook our subclass back up, just like we do on setwindow. + win->SetPrevWindowProc( + reinterpret_cast<WNDPROC>(sUser32SetWindowLongWHookStub(hWnd, nIndex, + reinterpret_cast<LONG_PTR>(PluginWndProc)))); + return proc; +} + +#ifdef _WIN64 +LONG_PTR WINAPI +SetWindowLongPtrWHook(HWND hWnd, + int nIndex, + LONG_PTR newLong) +#else +LONG WINAPI +SetWindowLongWHook(HWND hWnd, + int nIndex, + LONG newLong) +#endif +{ + if (SetWindowLongHookCheck(hWnd, nIndex, newLong)) + return sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong); + + // Set flash's new subclass to get the result. + LONG_PTR proc = sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong); + + // We already checked this in SetWindowLongHookCheck + nsPluginNativeWindowWin * win = + (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); + + // Hook our subclass back up, just like we do on setwindow. + win->SetPrevWindowProc( + reinterpret_cast<WNDPROC>(sUser32SetWindowLongWHookStub(hWnd, nIndex, + reinterpret_cast<LONG_PTR>(PluginWndProc)))); + return proc; +} + +static void +HookSetWindowLongPtr() +{ + sUser32Intercept.Init("user32.dll"); +#ifdef _WIN64 + if (!sUser32SetWindowLongAHookStub) + sUser32Intercept.AddHook("SetWindowLongPtrA", + reinterpret_cast<intptr_t>(SetWindowLongPtrAHook), + (void**) &sUser32SetWindowLongAHookStub); + if (!sUser32SetWindowLongWHookStub) + sUser32Intercept.AddHook("SetWindowLongPtrW", + reinterpret_cast<intptr_t>(SetWindowLongPtrWHook), + (void**) &sUser32SetWindowLongWHookStub); +#else + if (!sUser32SetWindowLongAHookStub) + sUser32Intercept.AddHook("SetWindowLongA", + reinterpret_cast<intptr_t>(SetWindowLongAHook), + (void**) &sUser32SetWindowLongAHookStub); + if (!sUser32SetWindowLongWHookStub) + sUser32Intercept.AddHook("SetWindowLongW", + reinterpret_cast<intptr_t>(SetWindowLongWHook), + (void**) &sUser32SetWindowLongWHookStub); +#endif +} + +/** + * nsPluginNativeWindowWin implementation + */ +nsPluginNativeWindowWin::nsPluginNativeWindowWin() : nsPluginNativeWindow() +{ + // initialize the struct fields + window = nullptr; + x = 0; + y = 0; + width = 0; + height = 0; + + mPrevWinProc = nullptr; + mPluginWinProc = nullptr; + mPluginType = nsPluginHost::eSpecialType_None; + + mParentWnd = nullptr; + mParentProc = 0; + + if (!sWM_FLASHBOUNCEMSG) { + sWM_FLASHBOUNCEMSG = ::RegisterWindowMessage(NS_PLUGIN_CUSTOM_MSG_ID); + } +} + +nsPluginNativeWindowWin::~nsPluginNativeWindowWin() +{ + // clear weak reference to self to prevent any pending events from + // dereferencing this. + mWeakRef.forget(); +} + +WNDPROC nsPluginNativeWindowWin::GetPrevWindowProc() +{ + return mPrevWinProc; +} + +WNDPROC nsPluginNativeWindowWin::GetWindowProc() +{ + return mPluginWinProc; +} + +NS_IMETHODIMP PluginWindowEvent::Run() +{ + nsPluginNativeWindowWin *win = mPluginWindowRef.get(); + if (!win) + return NS_OK; + + HWND hWnd = GetWnd(); + if (!hWnd) + return NS_OK; + + RefPtr<nsNPAPIPluginInstance> inst; + win->GetPluginInstance(inst); + + if (GetMsg() == WM_USER_FLASH) { + // XXX Unwind issues related to runnable event callback depth for this + // event and destruction of the plugin. (Bug 493601) + ::PostMessage(hWnd, sWM_FLASHBOUNCEMSG, GetWParam(), GetLParam()); + } + else { + // Currently not used, but added so that processing events here + // is more generic. + ::CallWindowProc(win->GetWindowProc(), + hWnd, + GetMsg(), + GetWParam(), + GetLParam()); + } + + Clear(); + return NS_OK; +} + +PluginWindowEvent * +nsPluginNativeWindowWin::GetPluginWindowEvent(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam) +{ + if (!mWeakRef) { + mWeakRef = this; + if (!mWeakRef) + return nullptr; + } + + PluginWindowEvent *event; + + // We have the ability to alloc if needed in case in the future some plugin + // should post multiple PostMessages. However, this could lead to many + // alloc's per second which could become a performance issue. See bug 169247. + if (!mCachedPluginWindowEvent) + { + event = new PluginWindowEvent(); + mCachedPluginWindowEvent = event; + } + else if (mCachedPluginWindowEvent->InUse()) + { + event = new PluginWindowEvent(); + } + else + { + event = mCachedPluginWindowEvent; + } + + event->Init(mWeakRef, aWnd, aMsg, aWParam, aLParam); + return event; +} + +nsresult nsPluginNativeWindowWin::CallSetWindow(RefPtr<nsNPAPIPluginInstance> &aPluginInstance) +{ + // Note, 'window' can be null + + // check the incoming instance, null indicates that window is going away and we are + // not interested in subclassing business any more, undo and don't subclass + if (!aPluginInstance) { + UndoSubclassAndAssociateWindow(); + // release plugin instance + SetPluginInstance(nullptr); + nsPluginNativeWindow::CallSetWindow(aPluginInstance); + return NS_OK; + } + + // check plugin mime type and cache it if it will need special treatment later + if (mPluginType == nsPluginHost::eSpecialType_None) { + const char* mimetype = nullptr; + if (NS_SUCCEEDED(aPluginInstance->GetMIMEType(&mimetype)) && mimetype) { + mPluginType = nsPluginHost::GetSpecialType(nsDependentCString(mimetype)); + } + } + + // With e10s we execute in the content process and as such we don't + // have access to native widgets. CallSetWindow and skip native widget + // subclassing. + if (!XRE_IsParentProcess()) { + nsPluginNativeWindow::CallSetWindow(aPluginInstance); + return NS_OK; + } + + if (window) { + // grab the widget procedure before the plug-in does a subclass in + // setwindow. We'll use this in PluginWndProc for forwarding focus + // events to the widget. + WNDPROC currentWndProc = + (WNDPROC)::GetWindowLongPtr((HWND)window, GWLP_WNDPROC); + if (!mPrevWinProc && currentWndProc != PluginWndProc) + mPrevWinProc = currentWndProc; + + // PDF plugin v7.0.9, v8.1.3, and v9.0 subclass parent window, bug 531551 + // V8.2.2 and V9.1 don't have such problem. + if (mPluginType == nsPluginHost::eSpecialType_PDF) { + HWND parent = ::GetParent((HWND)window); + if (mParentWnd != parent) { + NS_ASSERTION(!mParentWnd, "Plugin's parent window changed"); + mParentWnd = parent; + mParentProc = ::GetWindowLongPtr(mParentWnd, GWLP_WNDPROC); + } + } + } + + nsPluginNativeWindow::CallSetWindow(aPluginInstance); + + SubclassAndAssociateWindow(); + + if (window && mPluginType == nsPluginHost::eSpecialType_Flash && + !GetPropW((HWND)window, L"PluginInstanceParentProperty")) { + HookSetWindowLongPtr(); + } + + return NS_OK; +} + +nsresult nsPluginNativeWindowWin::SubclassAndAssociateWindow() +{ + if (type != NPWindowTypeWindow || !window) + return NS_ERROR_FAILURE; + + HWND hWnd = (HWND)window; + + // check if we need to subclass + WNDPROC currentWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC); + if (currentWndProc == PluginWndProc) + return NS_OK; + + // If the plugin reset the subclass, set it back. + if (mPluginWinProc) { +#ifdef DEBUG + NS_WARNING("A plugin cleared our subclass - resetting."); + if (currentWndProc != mPluginWinProc) { + NS_WARNING("Procedures do not match up, discarding old subclass value."); + } + if (mPrevWinProc && currentWndProc == mPrevWinProc) { + NS_WARNING("The new procedure is our widget procedure?"); + } +#endif + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc); + return NS_OK; + } + + LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE); + // Out of process plugins must not have the WS_CLIPCHILDREN style set on their + // parent windows or else synchronous paints (via UpdateWindow() and others) + // will cause deadlocks. + if (::GetPropW(hWnd, L"PluginInstanceParentProperty")) + style &= ~WS_CLIPCHILDREN; + else + style |= WS_CLIPCHILDREN; + SetWindowLongPtr(hWnd, GWL_STYLE, style); + + mPluginWinProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc); + if (!mPluginWinProc) + return NS_ERROR_FAILURE; + + DebugOnly<nsPluginNativeWindowWin *> win = (nsPluginNativeWindowWin *)::GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); + NS_ASSERTION(!win || (win == this), "plugin window already has property and this is not us"); + + if (!::SetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION, (HANDLE)this)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +nsresult nsPluginNativeWindowWin::UndoSubclassAndAssociateWindow() +{ + // remove window property + HWND hWnd = (HWND)window; + if (IsWindow(hWnd)) + ::RemoveProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); + + // restore the original win proc + // but only do this if this were us last time + if (mPluginWinProc) { + WNDPROC currentWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC); + if (currentWndProc == PluginWndProc) + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)mPluginWinProc); + mPluginWinProc = nullptr; + + LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE); + style &= ~WS_CLIPCHILDREN; + SetWindowLongPtr(hWnd, GWL_STYLE, style); + } + + if (mPluginType == nsPluginHost::eSpecialType_Flash && mParentWnd) { + ::SetWindowLongPtr(mParentWnd, GWLP_WNDPROC, mParentProc); + mParentWnd = nullptr; + mParentProc = 0; + } + + return NS_OK; +} + +nsresult PLUG_NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow) +{ + NS_ENSURE_ARG_POINTER(aPluginNativeWindow); + + *aPluginNativeWindow = new nsPluginNativeWindowWin(); + return NS_OK; +} + +nsresult PLUG_DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow) +{ + NS_ENSURE_ARG_POINTER(aPluginNativeWindow); + nsPluginNativeWindowWin *p = (nsPluginNativeWindowWin *)aPluginNativeWindow; + delete p; + return NS_OK; +} |