1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/plugins/base/nsPluginNativeWindowWin.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,754 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/BasicEvents.h" 1.10 +#include "mozilla/DebugOnly.h" 1.11 + 1.12 +#include "windows.h" 1.13 +#include "windowsx.h" 1.14 + 1.15 +// XXXbz windowsx.h defines GetFirstChild, GetNextSibling, 1.16 +// GetPrevSibling are macros, apparently... Eeevil. We have functions 1.17 +// called that on some classes, so undef them. 1.18 +#undef GetFirstChild 1.19 +#undef GetNextSibling 1.20 +#undef GetPrevSibling 1.21 + 1.22 +#include "nsDebug.h" 1.23 + 1.24 +#include "nsWindowsDllInterceptor.h" 1.25 +#include "nsPluginNativeWindow.h" 1.26 +#include "nsThreadUtils.h" 1.27 +#include "nsAutoPtr.h" 1.28 +#include "nsTWeakRef.h" 1.29 +#include "nsCrashOnException.h" 1.30 + 1.31 +using namespace mozilla; 1.32 + 1.33 +#define NP_POPUP_API_VERSION 16 1.34 + 1.35 +#define nsMajorVersion(v) (((int32_t)(v) >> 16) & 0xffff) 1.36 +#define nsMinorVersion(v) ((int32_t)(v) & 0xffff) 1.37 +#define versionOK(suppliedV, requiredV) \ 1.38 + (nsMajorVersion(suppliedV) == nsMajorVersion(requiredV) \ 1.39 + && nsMinorVersion(suppliedV) >= nsMinorVersion(requiredV)) 1.40 + 1.41 + 1.42 +#define NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION TEXT("MozillaPluginWindowPropertyAssociation") 1.43 +#define NS_PLUGIN_CUSTOM_MSG_ID TEXT("MozFlashUserRelay") 1.44 +#define WM_USER_FLASH WM_USER+1 1.45 +static UINT sWM_FLASHBOUNCEMSG = 0; 1.46 + 1.47 +typedef nsTWeakRef<class nsPluginNativeWindowWin> PluginWindowWeakRef; 1.48 + 1.49 +/** 1.50 + * PLEvent handling code 1.51 + */ 1.52 +class PluginWindowEvent : public nsRunnable { 1.53 +public: 1.54 + PluginWindowEvent(); 1.55 + void Init(const PluginWindowWeakRef &ref, HWND hWnd, UINT msg, WPARAM wParam, 1.56 + LPARAM lParam); 1.57 + void Clear(); 1.58 + HWND GetWnd() { return mWnd; }; 1.59 + UINT GetMsg() { return mMsg; }; 1.60 + WPARAM GetWParam() { return mWParam; }; 1.61 + LPARAM GetLParam() { return mLParam; }; 1.62 + bool InUse() { return mWnd != nullptr; }; 1.63 + 1.64 + NS_DECL_NSIRUNNABLE 1.65 + 1.66 +protected: 1.67 + PluginWindowWeakRef mPluginWindowRef; 1.68 + HWND mWnd; 1.69 + UINT mMsg; 1.70 + WPARAM mWParam; 1.71 + LPARAM mLParam; 1.72 +}; 1.73 + 1.74 +PluginWindowEvent::PluginWindowEvent() 1.75 +{ 1.76 + Clear(); 1.77 +} 1.78 + 1.79 +void PluginWindowEvent::Clear() 1.80 +{ 1.81 + mWnd = nullptr; 1.82 + mMsg = 0; 1.83 + mWParam = 0; 1.84 + mLParam = 0; 1.85 +} 1.86 + 1.87 +void PluginWindowEvent::Init(const PluginWindowWeakRef &ref, HWND aWnd, 1.88 + UINT aMsg, WPARAM aWParam, LPARAM aLParam) 1.89 +{ 1.90 + NS_ASSERTION(aWnd != nullptr, "invalid plugin event value"); 1.91 + NS_ASSERTION(mWnd == nullptr, "event already in use"); 1.92 + mPluginWindowRef = ref; 1.93 + mWnd = aWnd; 1.94 + mMsg = aMsg; 1.95 + mWParam = aWParam; 1.96 + mLParam = aLParam; 1.97 +} 1.98 + 1.99 +/** 1.100 + * nsPluginNativeWindow Windows specific class declaration 1.101 + */ 1.102 + 1.103 +typedef enum { 1.104 + nsPluginType_Unknown = 0, 1.105 + nsPluginType_Flash, 1.106 + nsPluginType_Real, 1.107 + nsPluginType_PDF, 1.108 + nsPluginType_Other 1.109 +} nsPluginType; 1.110 + 1.111 +class nsPluginNativeWindowWin : public nsPluginNativeWindow { 1.112 +public: 1.113 + nsPluginNativeWindowWin(); 1.114 + virtual ~nsPluginNativeWindowWin(); 1.115 + 1.116 + virtual nsresult CallSetWindow(nsRefPtr<nsNPAPIPluginInstance> &aPluginInstance); 1.117 + 1.118 +private: 1.119 + nsresult SubclassAndAssociateWindow(); 1.120 + nsresult UndoSubclassAndAssociateWindow(); 1.121 + 1.122 +public: 1.123 + // locals 1.124 + WNDPROC GetPrevWindowProc(); 1.125 + void SetPrevWindowProc(WNDPROC proc) { mPluginWinProc = proc; } 1.126 + WNDPROC GetWindowProc(); 1.127 + PluginWindowEvent * GetPluginWindowEvent(HWND aWnd, 1.128 + UINT aMsg, 1.129 + WPARAM aWParam, 1.130 + LPARAM aLParam); 1.131 + 1.132 +private: 1.133 + WNDPROC mPluginWinProc; 1.134 + WNDPROC mPrevWinProc; 1.135 + PluginWindowWeakRef mWeakRef; 1.136 + nsRefPtr<PluginWindowEvent> mCachedPluginWindowEvent; 1.137 + 1.138 + HWND mParentWnd; 1.139 + LONG_PTR mParentProc; 1.140 +public: 1.141 + nsPluginType mPluginType; 1.142 +}; 1.143 + 1.144 +static bool sInMessageDispatch = false; 1.145 +static bool sInPreviousMessageDispatch = false; 1.146 +static UINT sLastMsg = 0; 1.147 + 1.148 +static bool ProcessFlashMessageDelayed(nsPluginNativeWindowWin * aWin, nsNPAPIPluginInstance * aInst, 1.149 + HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 1.150 +{ 1.151 + NS_ENSURE_TRUE(aWin, false); 1.152 + NS_ENSURE_TRUE(aInst, false); 1.153 + 1.154 + if (msg == sWM_FLASHBOUNCEMSG) { 1.155 + // See PluginWindowEvent::Run() below. 1.156 + NS_ASSERTION((sWM_FLASHBOUNCEMSG != 0), "RegisterWindowMessage failed in flash plugin WM_USER message handling!"); 1.157 + ::CallWindowProc((WNDPROC)aWin->GetWindowProc(), hWnd, WM_USER_FLASH, wParam, lParam); 1.158 + return true; 1.159 + } 1.160 + 1.161 + if (msg != WM_USER_FLASH) 1.162 + return false; // no need to delay 1.163 + 1.164 + // do stuff 1.165 + nsCOMPtr<nsIRunnable> pwe = aWin->GetPluginWindowEvent(hWnd, msg, wParam, lParam); 1.166 + if (pwe) { 1.167 + NS_DispatchToCurrentThread(pwe); 1.168 + return true; 1.169 + } 1.170 + return false; 1.171 +} 1.172 + 1.173 +class nsDelayedPopupsEnabledEvent : public nsRunnable 1.174 +{ 1.175 +public: 1.176 + nsDelayedPopupsEnabledEvent(nsNPAPIPluginInstance *inst) 1.177 + : mInst(inst) 1.178 + {} 1.179 + 1.180 + NS_DECL_NSIRUNNABLE 1.181 + 1.182 +private: 1.183 + nsRefPtr<nsNPAPIPluginInstance> mInst; 1.184 +}; 1.185 + 1.186 +NS_IMETHODIMP nsDelayedPopupsEnabledEvent::Run() 1.187 +{ 1.188 + mInst->PushPopupsEnabledState(false); 1.189 + return NS_OK; 1.190 +} 1.191 + 1.192 +static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 1.193 + 1.194 +/** 1.195 + * New plugin window procedure 1.196 + */ 1.197 +static LRESULT CALLBACK PluginWndProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 1.198 +{ 1.199 + nsPluginNativeWindowWin * win = (nsPluginNativeWindowWin *)::GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); 1.200 + if (!win) 1.201 + return TRUE; 1.202 + 1.203 + // The DispatchEvent(NS_PLUGIN_ACTIVATE) below can trigger a reentrant focus 1.204 + // event which might destroy us. Hold a strong ref on the plugin instance 1.205 + // to prevent that, bug 374229. 1.206 + nsRefPtr<nsNPAPIPluginInstance> inst; 1.207 + win->GetPluginInstance(inst); 1.208 + 1.209 + // Real may go into a state where it recursivly dispatches the same event 1.210 + // when subclassed. If this is Real, lets examine the event and drop it 1.211 + // on the floor if we get into this recursive situation. See bug 192914. 1.212 + if (win->mPluginType == nsPluginType_Real) { 1.213 + if (sInMessageDispatch && msg == sLastMsg) 1.214 + return true; 1.215 + // Cache the last message sent 1.216 + sLastMsg = msg; 1.217 + } 1.218 + 1.219 + bool enablePopups = false; 1.220 + 1.221 + // Activate/deactivate mouse capture on the plugin widget 1.222 + // here, before we pass the Windows event to the plugin 1.223 + // because its possible our widget won't get paired events 1.224 + // (see bug 131007) and we'll look frozen. Note that this 1.225 + // is also done in ChildWindow::DispatchMouseEvent. 1.226 + switch (msg) { 1.227 + case WM_LBUTTONDOWN: 1.228 + case WM_MBUTTONDOWN: 1.229 + case WM_RBUTTONDOWN: { 1.230 + nsCOMPtr<nsIWidget> widget; 1.231 + win->GetPluginWidget(getter_AddRefs(widget)); 1.232 + if (widget) 1.233 + widget->CaptureMouse(true); 1.234 + break; 1.235 + } 1.236 + case WM_LBUTTONUP: 1.237 + enablePopups = true; 1.238 + 1.239 + // fall through 1.240 + case WM_MBUTTONUP: 1.241 + case WM_RBUTTONUP: { 1.242 + nsCOMPtr<nsIWidget> widget; 1.243 + win->GetPluginWidget(getter_AddRefs(widget)); 1.244 + if (widget) 1.245 + widget->CaptureMouse(false); 1.246 + break; 1.247 + } 1.248 + case WM_KEYDOWN: 1.249 + // Ignore repeating keydown messages... 1.250 + if ((lParam & 0x40000000) != 0) { 1.251 + break; 1.252 + } 1.253 + 1.254 + // fall through 1.255 + case WM_KEYUP: 1.256 + enablePopups = true; 1.257 + 1.258 + break; 1.259 + 1.260 + case WM_MOUSEACTIVATE: { 1.261 + // If a child window of this plug-in is already focused, 1.262 + // don't focus the parent to avoid focus dance. We'll 1.263 + // receive a follow up WM_SETFOCUS which will notify 1.264 + // the appropriate window anyway. 1.265 + HWND focusedWnd = ::GetFocus(); 1.266 + if (!::IsChild((HWND)win->window, focusedWnd)) { 1.267 + // Notify the dom / focus manager the plugin has focus when one of 1.268 + // it's child windows receives it. OOPP specific - this code is 1.269 + // critical in notifying the dom of focus changes when the plugin 1.270 + // window in the child process receives focus via a mouse click. 1.271 + // WM_MOUSEACTIVATE is sent by nsWindow via a custom window event 1.272 + // sent from PluginInstanceParent in response to focus events sent 1.273 + // from the child. (bug 540052) Note, this gui event could also be 1.274 + // sent directly from widget. 1.275 + nsCOMPtr<nsIWidget> widget; 1.276 + win->GetPluginWidget(getter_AddRefs(widget)); 1.277 + if (widget) { 1.278 + WidgetGUIEvent event(true, NS_PLUGIN_ACTIVATE, widget); 1.279 + nsEventStatus status; 1.280 + widget->DispatchEvent(&event, status); 1.281 + } 1.282 + } 1.283 + } 1.284 + break; 1.285 + 1.286 + case WM_SETFOCUS: 1.287 + case WM_KILLFOCUS: { 1.288 + // RealPlayer can crash, don't process the message for those, 1.289 + // see bug 328675. 1.290 + if (win->mPluginType == nsPluginType_Real && msg == sLastMsg) 1.291 + return TRUE; 1.292 + // Make sure setfocus and killfocus get through to the widget procedure 1.293 + // even if they are eaten by the plugin. Also make sure we aren't calling 1.294 + // recursively. 1.295 + WNDPROC prevWndProc = win->GetPrevWindowProc(); 1.296 + if (prevWndProc && !sInPreviousMessageDispatch) { 1.297 + sInPreviousMessageDispatch = true; 1.298 + ::CallWindowProc(prevWndProc, hWnd, msg, wParam, lParam); 1.299 + sInPreviousMessageDispatch = false; 1.300 + } 1.301 + break; 1.302 + } 1.303 + } 1.304 + 1.305 + // Macromedia Flash plugin may flood the message queue with some special messages 1.306 + // (WM_USER+1) causing 100% CPU consumption and GUI freeze, see mozilla bug 132759; 1.307 + // we can prevent this from happening by delaying the processing such messages; 1.308 + if (win->mPluginType == nsPluginType_Flash) { 1.309 + if (ProcessFlashMessageDelayed(win, inst, hWnd, msg, wParam, lParam)) 1.310 + return TRUE; 1.311 + } 1.312 + 1.313 + if (enablePopups && inst) { 1.314 + uint16_t apiVersion; 1.315 + if (NS_SUCCEEDED(inst->GetPluginAPIVersion(&apiVersion)) && 1.316 + !versionOK(apiVersion, NP_POPUP_API_VERSION)) { 1.317 + inst->PushPopupsEnabledState(true); 1.318 + } 1.319 + } 1.320 + 1.321 + sInMessageDispatch = true; 1.322 + LRESULT res; 1.323 + WNDPROC proc = (WNDPROC)win->GetWindowProc(); 1.324 + if (PluginWndProc == proc) { 1.325 + NS_WARNING("Previous plugin window procedure references PluginWndProc! " 1.326 + "Report this bug!"); 1.327 + res = CallWindowProc(DefWindowProc, hWnd, msg, wParam, lParam); 1.328 + } else { 1.329 + res = CallWindowProc(proc, hWnd, msg, wParam, lParam); 1.330 + } 1.331 + sInMessageDispatch = false; 1.332 + 1.333 + if (inst) { 1.334 + // Popups are enabled (were enabled before the call to 1.335 + // CallWindowProc()). Some plugins (at least the flash player) 1.336 + // post messages from their key handlers etc that delay the actual 1.337 + // processing, so we need to delay the disabling of popups so that 1.338 + // popups remain enabled when the flash player ends up processing 1.339 + // the actual key handlers. We do this by posting an event that 1.340 + // does the disabling, this way our disabling will happen after 1.341 + // the handlers in the plugin are done. 1.342 + 1.343 + // Note that it's not fatal if any of this fails (which won't 1.344 + // happen unless we're out of memory anyways) since the plugin 1.345 + // code will pop any popup state pushed by this plugin on 1.346 + // destruction. 1.347 + 1.348 + nsCOMPtr<nsIRunnable> event = new nsDelayedPopupsEnabledEvent(inst); 1.349 + if (event) 1.350 + NS_DispatchToCurrentThread(event); 1.351 + } 1.352 + 1.353 + return res; 1.354 +} 1.355 + 1.356 +static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 1.357 +{ 1.358 + return mozilla::CallWindowProcCrashProtected(PluginWndProcInternal, hWnd, msg, wParam, lParam); 1.359 +} 1.360 + 1.361 +/* 1.362 + * Flash will reset the subclass of our widget at various times. 1.363 + * (Notably when entering and exiting full screen mode.) This 1.364 + * occurs independent of the main plugin window event procedure. 1.365 + * We trap these subclass calls to prevent our subclass hook from 1.366 + * getting dropped. 1.367 + * Note, ascii versions can be nixed once flash versions < 10.1 1.368 + * are considered obsolete. 1.369 + */ 1.370 +static WindowsDllInterceptor sUser32Intercept; 1.371 + 1.372 +#ifdef _WIN64 1.373 +typedef LONG_PTR 1.374 + (WINAPI *User32SetWindowLongPtrA)(HWND hWnd, 1.375 + int nIndex, 1.376 + LONG_PTR dwNewLong); 1.377 +typedef LONG_PTR 1.378 + (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, 1.379 + int nIndex, 1.380 + LONG_PTR dwNewLong); 1.381 +static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; 1.382 +static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; 1.383 +#else 1.384 +typedef LONG 1.385 +(WINAPI *User32SetWindowLongA)(HWND hWnd, 1.386 + int nIndex, 1.387 + LONG dwNewLong); 1.388 +typedef LONG 1.389 +(WINAPI *User32SetWindowLongW)(HWND hWnd, 1.390 + int nIndex, 1.391 + LONG dwNewLong); 1.392 +static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; 1.393 +static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; 1.394 +#endif 1.395 +static inline bool 1.396 +SetWindowLongHookCheck(HWND hWnd, 1.397 + int nIndex, 1.398 + LONG_PTR newLong) 1.399 +{ 1.400 + nsPluginNativeWindowWin * win = 1.401 + (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); 1.402 + if (!win || (win && win->mPluginType != nsPluginType_Flash) || 1.403 + (nIndex == GWLP_WNDPROC && 1.404 + newLong == reinterpret_cast<LONG_PTR>(PluginWndProc))) 1.405 + return true; 1.406 + return false; 1.407 +} 1.408 + 1.409 +#ifdef _WIN64 1.410 +LONG_PTR WINAPI 1.411 +SetWindowLongPtrAHook(HWND hWnd, 1.412 + int nIndex, 1.413 + LONG_PTR newLong) 1.414 +#else 1.415 +LONG WINAPI 1.416 +SetWindowLongAHook(HWND hWnd, 1.417 + int nIndex, 1.418 + LONG newLong) 1.419 +#endif 1.420 +{ 1.421 + if (SetWindowLongHookCheck(hWnd, nIndex, newLong)) 1.422 + return sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong); 1.423 + 1.424 + // Set flash's new subclass to get the result. 1.425 + LONG_PTR proc = sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong); 1.426 + 1.427 + // We already checked this in SetWindowLongHookCheck 1.428 + nsPluginNativeWindowWin * win = 1.429 + (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); 1.430 + 1.431 + // Hook our subclass back up, just like we do on setwindow. 1.432 + win->SetPrevWindowProc( 1.433 + reinterpret_cast<WNDPROC>(sUser32SetWindowLongWHookStub(hWnd, nIndex, 1.434 + reinterpret_cast<LONG_PTR>(PluginWndProc)))); 1.435 + return proc; 1.436 +} 1.437 + 1.438 +#ifdef _WIN64 1.439 +LONG_PTR WINAPI 1.440 +SetWindowLongPtrWHook(HWND hWnd, 1.441 + int nIndex, 1.442 + LONG_PTR newLong) 1.443 +#else 1.444 +LONG WINAPI 1.445 +SetWindowLongWHook(HWND hWnd, 1.446 + int nIndex, 1.447 + LONG newLong) 1.448 +#endif 1.449 +{ 1.450 + if (SetWindowLongHookCheck(hWnd, nIndex, newLong)) 1.451 + return sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong); 1.452 + 1.453 + // Set flash's new subclass to get the result. 1.454 + LONG_PTR proc = sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong); 1.455 + 1.456 + // We already checked this in SetWindowLongHookCheck 1.457 + nsPluginNativeWindowWin * win = 1.458 + (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); 1.459 + 1.460 + // Hook our subclass back up, just like we do on setwindow. 1.461 + win->SetPrevWindowProc( 1.462 + reinterpret_cast<WNDPROC>(sUser32SetWindowLongWHookStub(hWnd, nIndex, 1.463 + reinterpret_cast<LONG_PTR>(PluginWndProc)))); 1.464 + return proc; 1.465 +} 1.466 + 1.467 +static void 1.468 +HookSetWindowLongPtr() 1.469 +{ 1.470 + sUser32Intercept.Init("user32.dll"); 1.471 +#ifdef _WIN64 1.472 + if (!sUser32SetWindowLongAHookStub) 1.473 + sUser32Intercept.AddHook("SetWindowLongPtrA", 1.474 + reinterpret_cast<intptr_t>(SetWindowLongPtrAHook), 1.475 + (void**) &sUser32SetWindowLongAHookStub); 1.476 + if (!sUser32SetWindowLongWHookStub) 1.477 + sUser32Intercept.AddHook("SetWindowLongPtrW", 1.478 + reinterpret_cast<intptr_t>(SetWindowLongPtrWHook), 1.479 + (void**) &sUser32SetWindowLongWHookStub); 1.480 +#else 1.481 + if (!sUser32SetWindowLongAHookStub) 1.482 + sUser32Intercept.AddHook("SetWindowLongA", 1.483 + reinterpret_cast<intptr_t>(SetWindowLongAHook), 1.484 + (void**) &sUser32SetWindowLongAHookStub); 1.485 + if (!sUser32SetWindowLongWHookStub) 1.486 + sUser32Intercept.AddHook("SetWindowLongW", 1.487 + reinterpret_cast<intptr_t>(SetWindowLongWHook), 1.488 + (void**) &sUser32SetWindowLongWHookStub); 1.489 +#endif 1.490 +} 1.491 + 1.492 +/** 1.493 + * nsPluginNativeWindowWin implementation 1.494 + */ 1.495 +nsPluginNativeWindowWin::nsPluginNativeWindowWin() : nsPluginNativeWindow() 1.496 +{ 1.497 + // initialize the struct fields 1.498 + window = nullptr; 1.499 + x = 0; 1.500 + y = 0; 1.501 + width = 0; 1.502 + height = 0; 1.503 + 1.504 + mPrevWinProc = nullptr; 1.505 + mPluginWinProc = nullptr; 1.506 + mPluginType = nsPluginType_Unknown; 1.507 + 1.508 + mParentWnd = nullptr; 1.509 + mParentProc = 0; 1.510 + 1.511 + if (!sWM_FLASHBOUNCEMSG) { 1.512 + sWM_FLASHBOUNCEMSG = ::RegisterWindowMessage(NS_PLUGIN_CUSTOM_MSG_ID); 1.513 + } 1.514 +} 1.515 + 1.516 +nsPluginNativeWindowWin::~nsPluginNativeWindowWin() 1.517 +{ 1.518 + // clear weak reference to self to prevent any pending events from 1.519 + // dereferencing this. 1.520 + mWeakRef.forget(); 1.521 +} 1.522 + 1.523 +WNDPROC nsPluginNativeWindowWin::GetPrevWindowProc() 1.524 +{ 1.525 + return mPrevWinProc; 1.526 +} 1.527 + 1.528 +WNDPROC nsPluginNativeWindowWin::GetWindowProc() 1.529 +{ 1.530 + return mPluginWinProc; 1.531 +} 1.532 + 1.533 +NS_IMETHODIMP PluginWindowEvent::Run() 1.534 +{ 1.535 + nsPluginNativeWindowWin *win = mPluginWindowRef.get(); 1.536 + if (!win) 1.537 + return NS_OK; 1.538 + 1.539 + HWND hWnd = GetWnd(); 1.540 + if (!hWnd) 1.541 + return NS_OK; 1.542 + 1.543 + nsRefPtr<nsNPAPIPluginInstance> inst; 1.544 + win->GetPluginInstance(inst); 1.545 + 1.546 + if (GetMsg() == WM_USER_FLASH) { 1.547 + // XXX Unwind issues related to runnable event callback depth for this 1.548 + // event and destruction of the plugin. (Bug 493601) 1.549 + ::PostMessage(hWnd, sWM_FLASHBOUNCEMSG, GetWParam(), GetLParam()); 1.550 + } 1.551 + else { 1.552 + // Currently not used, but added so that processing events here 1.553 + // is more generic. 1.554 + ::CallWindowProc(win->GetWindowProc(), 1.555 + hWnd, 1.556 + GetMsg(), 1.557 + GetWParam(), 1.558 + GetLParam()); 1.559 + } 1.560 + 1.561 + Clear(); 1.562 + return NS_OK; 1.563 +} 1.564 + 1.565 +PluginWindowEvent * 1.566 +nsPluginNativeWindowWin::GetPluginWindowEvent(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam) 1.567 +{ 1.568 + if (!mWeakRef) { 1.569 + mWeakRef = this; 1.570 + if (!mWeakRef) 1.571 + return nullptr; 1.572 + } 1.573 + 1.574 + PluginWindowEvent *event; 1.575 + 1.576 + // We have the ability to alloc if needed in case in the future some plugin 1.577 + // should post multiple PostMessages. However, this could lead to many 1.578 + // alloc's per second which could become a performance issue. See bug 169247. 1.579 + if (!mCachedPluginWindowEvent) 1.580 + { 1.581 + event = new PluginWindowEvent(); 1.582 + if (!event) return nullptr; 1.583 + mCachedPluginWindowEvent = event; 1.584 + } 1.585 + else if (mCachedPluginWindowEvent->InUse()) 1.586 + { 1.587 + event = new PluginWindowEvent(); 1.588 + if (!event) return nullptr; 1.589 + } 1.590 + else 1.591 + { 1.592 + event = mCachedPluginWindowEvent; 1.593 + } 1.594 + 1.595 + event->Init(mWeakRef, aWnd, aMsg, aWParam, aLParam); 1.596 + return event; 1.597 +} 1.598 + 1.599 +nsresult nsPluginNativeWindowWin::CallSetWindow(nsRefPtr<nsNPAPIPluginInstance> &aPluginInstance) 1.600 +{ 1.601 + // Note, 'window' can be null 1.602 + 1.603 + // check the incoming instance, null indicates that window is going away and we are 1.604 + // not interested in subclassing business any more, undo and don't subclass 1.605 + if (!aPluginInstance) { 1.606 + UndoSubclassAndAssociateWindow(); 1.607 + nsPluginNativeWindow::CallSetWindow(aPluginInstance); 1.608 + return NS_OK; 1.609 + } 1.610 + 1.611 + // check plugin mime type and cache it if it will need special treatment later 1.612 + if (mPluginType == nsPluginType_Unknown) { 1.613 + const char* mimetype = nullptr; 1.614 + aPluginInstance->GetMIMEType(&mimetype); 1.615 + if (mimetype) { 1.616 + if (!strcmp(mimetype, "application/x-shockwave-flash")) 1.617 + mPluginType = nsPluginType_Flash; 1.618 + else if (!strcmp(mimetype, "audio/x-pn-realaudio-plugin")) 1.619 + mPluginType = nsPluginType_Real; 1.620 + else if (!strcmp(mimetype, "application/pdf")) 1.621 + mPluginType = nsPluginType_PDF; 1.622 + else 1.623 + mPluginType = nsPluginType_Other; 1.624 + } 1.625 + } 1.626 + 1.627 + if (window) { 1.628 + // grab the widget procedure before the plug-in does a subclass in 1.629 + // setwindow. We'll use this in PluginWndProc for forwarding focus 1.630 + // events to the widget. 1.631 + WNDPROC currentWndProc = 1.632 + (WNDPROC)::GetWindowLongPtr((HWND)window, GWLP_WNDPROC); 1.633 + if (!mPrevWinProc && currentWndProc != PluginWndProc) 1.634 + mPrevWinProc = currentWndProc; 1.635 + 1.636 + // PDF plugin v7.0.9, v8.1.3, and v9.0 subclass parent window, bug 531551 1.637 + // V8.2.2 and V9.1 don't have such problem. 1.638 + if (mPluginType == nsPluginType_PDF) { 1.639 + HWND parent = ::GetParent((HWND)window); 1.640 + if (mParentWnd != parent) { 1.641 + NS_ASSERTION(!mParentWnd, "Plugin's parent window changed"); 1.642 + mParentWnd = parent; 1.643 + mParentProc = ::GetWindowLongPtr(mParentWnd, GWLP_WNDPROC); 1.644 + } 1.645 + } 1.646 + } 1.647 + 1.648 + nsPluginNativeWindow::CallSetWindow(aPluginInstance); 1.649 + 1.650 + SubclassAndAssociateWindow(); 1.651 + 1.652 + if (window && mPluginType == nsPluginType_Flash && 1.653 + !GetPropW((HWND)window, L"PluginInstanceParentProperty")) { 1.654 + HookSetWindowLongPtr(); 1.655 + } 1.656 + 1.657 + return NS_OK; 1.658 +} 1.659 + 1.660 +nsresult nsPluginNativeWindowWin::SubclassAndAssociateWindow() 1.661 +{ 1.662 + if (type != NPWindowTypeWindow || !window) 1.663 + return NS_ERROR_FAILURE; 1.664 + 1.665 + HWND hWnd = (HWND)window; 1.666 + 1.667 + // check if we need to subclass 1.668 + WNDPROC currentWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC); 1.669 + if (currentWndProc == PluginWndProc) 1.670 + return NS_OK; 1.671 + 1.672 + // If the plugin reset the subclass, set it back. 1.673 + if (mPluginWinProc) { 1.674 +#ifdef DEBUG 1.675 + NS_WARNING("A plugin cleared our subclass - resetting."); 1.676 + if (currentWndProc != mPluginWinProc) { 1.677 + NS_WARNING("Procedures do not match up, discarding old subclass value."); 1.678 + } 1.679 + if (mPrevWinProc && currentWndProc == mPrevWinProc) { 1.680 + NS_WARNING("The new procedure is our widget procedure?"); 1.681 + } 1.682 +#endif 1.683 + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc); 1.684 + return NS_OK; 1.685 + } 1.686 + 1.687 + LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE); 1.688 + // Out of process plugins must not have the WS_CLIPCHILDREN style set on their 1.689 + // parent windows or else synchronous paints (via UpdateWindow() and others) 1.690 + // will cause deadlocks. 1.691 + if (::GetPropW(hWnd, L"PluginInstanceParentProperty")) 1.692 + style &= ~WS_CLIPCHILDREN; 1.693 + else 1.694 + style |= WS_CLIPCHILDREN; 1.695 + SetWindowLongPtr(hWnd, GWL_STYLE, style); 1.696 + 1.697 + mPluginWinProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc); 1.698 + if (!mPluginWinProc) 1.699 + return NS_ERROR_FAILURE; 1.700 + 1.701 + DebugOnly<nsPluginNativeWindowWin *> win = (nsPluginNativeWindowWin *)::GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); 1.702 + NS_ASSERTION(!win || (win == this), "plugin window already has property and this is not us"); 1.703 + 1.704 + if (!::SetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION, (HANDLE)this)) 1.705 + return NS_ERROR_FAILURE; 1.706 + 1.707 + return NS_OK; 1.708 +} 1.709 + 1.710 +nsresult nsPluginNativeWindowWin::UndoSubclassAndAssociateWindow() 1.711 +{ 1.712 + // release plugin instance 1.713 + SetPluginInstance(nullptr); 1.714 + 1.715 + // remove window property 1.716 + HWND hWnd = (HWND)window; 1.717 + if (IsWindow(hWnd)) 1.718 + ::RemoveProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); 1.719 + 1.720 + // restore the original win proc 1.721 + // but only do this if this were us last time 1.722 + if (mPluginWinProc) { 1.723 + WNDPROC currentWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC); 1.724 + if (currentWndProc == PluginWndProc) 1.725 + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)mPluginWinProc); 1.726 + mPluginWinProc = nullptr; 1.727 + 1.728 + LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE); 1.729 + style &= ~WS_CLIPCHILDREN; 1.730 + SetWindowLongPtr(hWnd, GWL_STYLE, style); 1.731 + } 1.732 + 1.733 + if (mPluginType == nsPluginType_PDF && mParentWnd) { 1.734 + ::SetWindowLongPtr(mParentWnd, GWLP_WNDPROC, mParentProc); 1.735 + mParentWnd = nullptr; 1.736 + mParentProc = 0; 1.737 + } 1.738 + 1.739 + return NS_OK; 1.740 +} 1.741 + 1.742 +nsresult PLUG_NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow) 1.743 +{ 1.744 + NS_ENSURE_ARG_POINTER(aPluginNativeWindow); 1.745 + 1.746 + *aPluginNativeWindow = new nsPluginNativeWindowWin(); 1.747 + 1.748 + return *aPluginNativeWindow ? NS_OK : NS_ERROR_OUT_OF_MEMORY; 1.749 +} 1.750 + 1.751 +nsresult PLUG_DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow) 1.752 +{ 1.753 + NS_ENSURE_ARG_POINTER(aPluginNativeWindow); 1.754 + nsPluginNativeWindowWin *p = (nsPluginNativeWindowWin *)aPluginNativeWindow; 1.755 + delete p; 1.756 + return NS_OK; 1.757 +}