dom/plugins/base/nsPluginNativeWindowWin.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "mozilla/BasicEvents.h"
michael@0 7 #include "mozilla/DebugOnly.h"
michael@0 8
michael@0 9 #include "windows.h"
michael@0 10 #include "windowsx.h"
michael@0 11
michael@0 12 // XXXbz windowsx.h defines GetFirstChild, GetNextSibling,
michael@0 13 // GetPrevSibling are macros, apparently... Eeevil. We have functions
michael@0 14 // called that on some classes, so undef them.
michael@0 15 #undef GetFirstChild
michael@0 16 #undef GetNextSibling
michael@0 17 #undef GetPrevSibling
michael@0 18
michael@0 19 #include "nsDebug.h"
michael@0 20
michael@0 21 #include "nsWindowsDllInterceptor.h"
michael@0 22 #include "nsPluginNativeWindow.h"
michael@0 23 #include "nsThreadUtils.h"
michael@0 24 #include "nsAutoPtr.h"
michael@0 25 #include "nsTWeakRef.h"
michael@0 26 #include "nsCrashOnException.h"
michael@0 27
michael@0 28 using namespace mozilla;
michael@0 29
michael@0 30 #define NP_POPUP_API_VERSION 16
michael@0 31
michael@0 32 #define nsMajorVersion(v) (((int32_t)(v) >> 16) & 0xffff)
michael@0 33 #define nsMinorVersion(v) ((int32_t)(v) & 0xffff)
michael@0 34 #define versionOK(suppliedV, requiredV) \
michael@0 35 (nsMajorVersion(suppliedV) == nsMajorVersion(requiredV) \
michael@0 36 && nsMinorVersion(suppliedV) >= nsMinorVersion(requiredV))
michael@0 37
michael@0 38
michael@0 39 #define NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION TEXT("MozillaPluginWindowPropertyAssociation")
michael@0 40 #define NS_PLUGIN_CUSTOM_MSG_ID TEXT("MozFlashUserRelay")
michael@0 41 #define WM_USER_FLASH WM_USER+1
michael@0 42 static UINT sWM_FLASHBOUNCEMSG = 0;
michael@0 43
michael@0 44 typedef nsTWeakRef<class nsPluginNativeWindowWin> PluginWindowWeakRef;
michael@0 45
michael@0 46 /**
michael@0 47 * PLEvent handling code
michael@0 48 */
michael@0 49 class PluginWindowEvent : public nsRunnable {
michael@0 50 public:
michael@0 51 PluginWindowEvent();
michael@0 52 void Init(const PluginWindowWeakRef &ref, HWND hWnd, UINT msg, WPARAM wParam,
michael@0 53 LPARAM lParam);
michael@0 54 void Clear();
michael@0 55 HWND GetWnd() { return mWnd; };
michael@0 56 UINT GetMsg() { return mMsg; };
michael@0 57 WPARAM GetWParam() { return mWParam; };
michael@0 58 LPARAM GetLParam() { return mLParam; };
michael@0 59 bool InUse() { return mWnd != nullptr; };
michael@0 60
michael@0 61 NS_DECL_NSIRUNNABLE
michael@0 62
michael@0 63 protected:
michael@0 64 PluginWindowWeakRef mPluginWindowRef;
michael@0 65 HWND mWnd;
michael@0 66 UINT mMsg;
michael@0 67 WPARAM mWParam;
michael@0 68 LPARAM mLParam;
michael@0 69 };
michael@0 70
michael@0 71 PluginWindowEvent::PluginWindowEvent()
michael@0 72 {
michael@0 73 Clear();
michael@0 74 }
michael@0 75
michael@0 76 void PluginWindowEvent::Clear()
michael@0 77 {
michael@0 78 mWnd = nullptr;
michael@0 79 mMsg = 0;
michael@0 80 mWParam = 0;
michael@0 81 mLParam = 0;
michael@0 82 }
michael@0 83
michael@0 84 void PluginWindowEvent::Init(const PluginWindowWeakRef &ref, HWND aWnd,
michael@0 85 UINT aMsg, WPARAM aWParam, LPARAM aLParam)
michael@0 86 {
michael@0 87 NS_ASSERTION(aWnd != nullptr, "invalid plugin event value");
michael@0 88 NS_ASSERTION(mWnd == nullptr, "event already in use");
michael@0 89 mPluginWindowRef = ref;
michael@0 90 mWnd = aWnd;
michael@0 91 mMsg = aMsg;
michael@0 92 mWParam = aWParam;
michael@0 93 mLParam = aLParam;
michael@0 94 }
michael@0 95
michael@0 96 /**
michael@0 97 * nsPluginNativeWindow Windows specific class declaration
michael@0 98 */
michael@0 99
michael@0 100 typedef enum {
michael@0 101 nsPluginType_Unknown = 0,
michael@0 102 nsPluginType_Flash,
michael@0 103 nsPluginType_Real,
michael@0 104 nsPluginType_PDF,
michael@0 105 nsPluginType_Other
michael@0 106 } nsPluginType;
michael@0 107
michael@0 108 class nsPluginNativeWindowWin : public nsPluginNativeWindow {
michael@0 109 public:
michael@0 110 nsPluginNativeWindowWin();
michael@0 111 virtual ~nsPluginNativeWindowWin();
michael@0 112
michael@0 113 virtual nsresult CallSetWindow(nsRefPtr<nsNPAPIPluginInstance> &aPluginInstance);
michael@0 114
michael@0 115 private:
michael@0 116 nsresult SubclassAndAssociateWindow();
michael@0 117 nsresult UndoSubclassAndAssociateWindow();
michael@0 118
michael@0 119 public:
michael@0 120 // locals
michael@0 121 WNDPROC GetPrevWindowProc();
michael@0 122 void SetPrevWindowProc(WNDPROC proc) { mPluginWinProc = proc; }
michael@0 123 WNDPROC GetWindowProc();
michael@0 124 PluginWindowEvent * GetPluginWindowEvent(HWND aWnd,
michael@0 125 UINT aMsg,
michael@0 126 WPARAM aWParam,
michael@0 127 LPARAM aLParam);
michael@0 128
michael@0 129 private:
michael@0 130 WNDPROC mPluginWinProc;
michael@0 131 WNDPROC mPrevWinProc;
michael@0 132 PluginWindowWeakRef mWeakRef;
michael@0 133 nsRefPtr<PluginWindowEvent> mCachedPluginWindowEvent;
michael@0 134
michael@0 135 HWND mParentWnd;
michael@0 136 LONG_PTR mParentProc;
michael@0 137 public:
michael@0 138 nsPluginType mPluginType;
michael@0 139 };
michael@0 140
michael@0 141 static bool sInMessageDispatch = false;
michael@0 142 static bool sInPreviousMessageDispatch = false;
michael@0 143 static UINT sLastMsg = 0;
michael@0 144
michael@0 145 static bool ProcessFlashMessageDelayed(nsPluginNativeWindowWin * aWin, nsNPAPIPluginInstance * aInst,
michael@0 146 HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
michael@0 147 {
michael@0 148 NS_ENSURE_TRUE(aWin, false);
michael@0 149 NS_ENSURE_TRUE(aInst, false);
michael@0 150
michael@0 151 if (msg == sWM_FLASHBOUNCEMSG) {
michael@0 152 // See PluginWindowEvent::Run() below.
michael@0 153 NS_ASSERTION((sWM_FLASHBOUNCEMSG != 0), "RegisterWindowMessage failed in flash plugin WM_USER message handling!");
michael@0 154 ::CallWindowProc((WNDPROC)aWin->GetWindowProc(), hWnd, WM_USER_FLASH, wParam, lParam);
michael@0 155 return true;
michael@0 156 }
michael@0 157
michael@0 158 if (msg != WM_USER_FLASH)
michael@0 159 return false; // no need to delay
michael@0 160
michael@0 161 // do stuff
michael@0 162 nsCOMPtr<nsIRunnable> pwe = aWin->GetPluginWindowEvent(hWnd, msg, wParam, lParam);
michael@0 163 if (pwe) {
michael@0 164 NS_DispatchToCurrentThread(pwe);
michael@0 165 return true;
michael@0 166 }
michael@0 167 return false;
michael@0 168 }
michael@0 169
michael@0 170 class nsDelayedPopupsEnabledEvent : public nsRunnable
michael@0 171 {
michael@0 172 public:
michael@0 173 nsDelayedPopupsEnabledEvent(nsNPAPIPluginInstance *inst)
michael@0 174 : mInst(inst)
michael@0 175 {}
michael@0 176
michael@0 177 NS_DECL_NSIRUNNABLE
michael@0 178
michael@0 179 private:
michael@0 180 nsRefPtr<nsNPAPIPluginInstance> mInst;
michael@0 181 };
michael@0 182
michael@0 183 NS_IMETHODIMP nsDelayedPopupsEnabledEvent::Run()
michael@0 184 {
michael@0 185 mInst->PushPopupsEnabledState(false);
michael@0 186 return NS_OK;
michael@0 187 }
michael@0 188
michael@0 189 static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
michael@0 190
michael@0 191 /**
michael@0 192 * New plugin window procedure
michael@0 193 */
michael@0 194 static LRESULT CALLBACK PluginWndProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
michael@0 195 {
michael@0 196 nsPluginNativeWindowWin * win = (nsPluginNativeWindowWin *)::GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
michael@0 197 if (!win)
michael@0 198 return TRUE;
michael@0 199
michael@0 200 // The DispatchEvent(NS_PLUGIN_ACTIVATE) below can trigger a reentrant focus
michael@0 201 // event which might destroy us. Hold a strong ref on the plugin instance
michael@0 202 // to prevent that, bug 374229.
michael@0 203 nsRefPtr<nsNPAPIPluginInstance> inst;
michael@0 204 win->GetPluginInstance(inst);
michael@0 205
michael@0 206 // Real may go into a state where it recursivly dispatches the same event
michael@0 207 // when subclassed. If this is Real, lets examine the event and drop it
michael@0 208 // on the floor if we get into this recursive situation. See bug 192914.
michael@0 209 if (win->mPluginType == nsPluginType_Real) {
michael@0 210 if (sInMessageDispatch && msg == sLastMsg)
michael@0 211 return true;
michael@0 212 // Cache the last message sent
michael@0 213 sLastMsg = msg;
michael@0 214 }
michael@0 215
michael@0 216 bool enablePopups = false;
michael@0 217
michael@0 218 // Activate/deactivate mouse capture on the plugin widget
michael@0 219 // here, before we pass the Windows event to the plugin
michael@0 220 // because its possible our widget won't get paired events
michael@0 221 // (see bug 131007) and we'll look frozen. Note that this
michael@0 222 // is also done in ChildWindow::DispatchMouseEvent.
michael@0 223 switch (msg) {
michael@0 224 case WM_LBUTTONDOWN:
michael@0 225 case WM_MBUTTONDOWN:
michael@0 226 case WM_RBUTTONDOWN: {
michael@0 227 nsCOMPtr<nsIWidget> widget;
michael@0 228 win->GetPluginWidget(getter_AddRefs(widget));
michael@0 229 if (widget)
michael@0 230 widget->CaptureMouse(true);
michael@0 231 break;
michael@0 232 }
michael@0 233 case WM_LBUTTONUP:
michael@0 234 enablePopups = true;
michael@0 235
michael@0 236 // fall through
michael@0 237 case WM_MBUTTONUP:
michael@0 238 case WM_RBUTTONUP: {
michael@0 239 nsCOMPtr<nsIWidget> widget;
michael@0 240 win->GetPluginWidget(getter_AddRefs(widget));
michael@0 241 if (widget)
michael@0 242 widget->CaptureMouse(false);
michael@0 243 break;
michael@0 244 }
michael@0 245 case WM_KEYDOWN:
michael@0 246 // Ignore repeating keydown messages...
michael@0 247 if ((lParam & 0x40000000) != 0) {
michael@0 248 break;
michael@0 249 }
michael@0 250
michael@0 251 // fall through
michael@0 252 case WM_KEYUP:
michael@0 253 enablePopups = true;
michael@0 254
michael@0 255 break;
michael@0 256
michael@0 257 case WM_MOUSEACTIVATE: {
michael@0 258 // If a child window of this plug-in is already focused,
michael@0 259 // don't focus the parent to avoid focus dance. We'll
michael@0 260 // receive a follow up WM_SETFOCUS which will notify
michael@0 261 // the appropriate window anyway.
michael@0 262 HWND focusedWnd = ::GetFocus();
michael@0 263 if (!::IsChild((HWND)win->window, focusedWnd)) {
michael@0 264 // Notify the dom / focus manager the plugin has focus when one of
michael@0 265 // it's child windows receives it. OOPP specific - this code is
michael@0 266 // critical in notifying the dom of focus changes when the plugin
michael@0 267 // window in the child process receives focus via a mouse click.
michael@0 268 // WM_MOUSEACTIVATE is sent by nsWindow via a custom window event
michael@0 269 // sent from PluginInstanceParent in response to focus events sent
michael@0 270 // from the child. (bug 540052) Note, this gui event could also be
michael@0 271 // sent directly from widget.
michael@0 272 nsCOMPtr<nsIWidget> widget;
michael@0 273 win->GetPluginWidget(getter_AddRefs(widget));
michael@0 274 if (widget) {
michael@0 275 WidgetGUIEvent event(true, NS_PLUGIN_ACTIVATE, widget);
michael@0 276 nsEventStatus status;
michael@0 277 widget->DispatchEvent(&event, status);
michael@0 278 }
michael@0 279 }
michael@0 280 }
michael@0 281 break;
michael@0 282
michael@0 283 case WM_SETFOCUS:
michael@0 284 case WM_KILLFOCUS: {
michael@0 285 // RealPlayer can crash, don't process the message for those,
michael@0 286 // see bug 328675.
michael@0 287 if (win->mPluginType == nsPluginType_Real && msg == sLastMsg)
michael@0 288 return TRUE;
michael@0 289 // Make sure setfocus and killfocus get through to the widget procedure
michael@0 290 // even if they are eaten by the plugin. Also make sure we aren't calling
michael@0 291 // recursively.
michael@0 292 WNDPROC prevWndProc = win->GetPrevWindowProc();
michael@0 293 if (prevWndProc && !sInPreviousMessageDispatch) {
michael@0 294 sInPreviousMessageDispatch = true;
michael@0 295 ::CallWindowProc(prevWndProc, hWnd, msg, wParam, lParam);
michael@0 296 sInPreviousMessageDispatch = false;
michael@0 297 }
michael@0 298 break;
michael@0 299 }
michael@0 300 }
michael@0 301
michael@0 302 // Macromedia Flash plugin may flood the message queue with some special messages
michael@0 303 // (WM_USER+1) causing 100% CPU consumption and GUI freeze, see mozilla bug 132759;
michael@0 304 // we can prevent this from happening by delaying the processing such messages;
michael@0 305 if (win->mPluginType == nsPluginType_Flash) {
michael@0 306 if (ProcessFlashMessageDelayed(win, inst, hWnd, msg, wParam, lParam))
michael@0 307 return TRUE;
michael@0 308 }
michael@0 309
michael@0 310 if (enablePopups && inst) {
michael@0 311 uint16_t apiVersion;
michael@0 312 if (NS_SUCCEEDED(inst->GetPluginAPIVersion(&apiVersion)) &&
michael@0 313 !versionOK(apiVersion, NP_POPUP_API_VERSION)) {
michael@0 314 inst->PushPopupsEnabledState(true);
michael@0 315 }
michael@0 316 }
michael@0 317
michael@0 318 sInMessageDispatch = true;
michael@0 319 LRESULT res;
michael@0 320 WNDPROC proc = (WNDPROC)win->GetWindowProc();
michael@0 321 if (PluginWndProc == proc) {
michael@0 322 NS_WARNING("Previous plugin window procedure references PluginWndProc! "
michael@0 323 "Report this bug!");
michael@0 324 res = CallWindowProc(DefWindowProc, hWnd, msg, wParam, lParam);
michael@0 325 } else {
michael@0 326 res = CallWindowProc(proc, hWnd, msg, wParam, lParam);
michael@0 327 }
michael@0 328 sInMessageDispatch = false;
michael@0 329
michael@0 330 if (inst) {
michael@0 331 // Popups are enabled (were enabled before the call to
michael@0 332 // CallWindowProc()). Some plugins (at least the flash player)
michael@0 333 // post messages from their key handlers etc that delay the actual
michael@0 334 // processing, so we need to delay the disabling of popups so that
michael@0 335 // popups remain enabled when the flash player ends up processing
michael@0 336 // the actual key handlers. We do this by posting an event that
michael@0 337 // does the disabling, this way our disabling will happen after
michael@0 338 // the handlers in the plugin are done.
michael@0 339
michael@0 340 // Note that it's not fatal if any of this fails (which won't
michael@0 341 // happen unless we're out of memory anyways) since the plugin
michael@0 342 // code will pop any popup state pushed by this plugin on
michael@0 343 // destruction.
michael@0 344
michael@0 345 nsCOMPtr<nsIRunnable> event = new nsDelayedPopupsEnabledEvent(inst);
michael@0 346 if (event)
michael@0 347 NS_DispatchToCurrentThread(event);
michael@0 348 }
michael@0 349
michael@0 350 return res;
michael@0 351 }
michael@0 352
michael@0 353 static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
michael@0 354 {
michael@0 355 return mozilla::CallWindowProcCrashProtected(PluginWndProcInternal, hWnd, msg, wParam, lParam);
michael@0 356 }
michael@0 357
michael@0 358 /*
michael@0 359 * Flash will reset the subclass of our widget at various times.
michael@0 360 * (Notably when entering and exiting full screen mode.) This
michael@0 361 * occurs independent of the main plugin window event procedure.
michael@0 362 * We trap these subclass calls to prevent our subclass hook from
michael@0 363 * getting dropped.
michael@0 364 * Note, ascii versions can be nixed once flash versions < 10.1
michael@0 365 * are considered obsolete.
michael@0 366 */
michael@0 367 static WindowsDllInterceptor sUser32Intercept;
michael@0 368
michael@0 369 #ifdef _WIN64
michael@0 370 typedef LONG_PTR
michael@0 371 (WINAPI *User32SetWindowLongPtrA)(HWND hWnd,
michael@0 372 int nIndex,
michael@0 373 LONG_PTR dwNewLong);
michael@0 374 typedef LONG_PTR
michael@0 375 (WINAPI *User32SetWindowLongPtrW)(HWND hWnd,
michael@0 376 int nIndex,
michael@0 377 LONG_PTR dwNewLong);
michael@0 378 static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr;
michael@0 379 static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr;
michael@0 380 #else
michael@0 381 typedef LONG
michael@0 382 (WINAPI *User32SetWindowLongA)(HWND hWnd,
michael@0 383 int nIndex,
michael@0 384 LONG dwNewLong);
michael@0 385 typedef LONG
michael@0 386 (WINAPI *User32SetWindowLongW)(HWND hWnd,
michael@0 387 int nIndex,
michael@0 388 LONG dwNewLong);
michael@0 389 static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr;
michael@0 390 static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr;
michael@0 391 #endif
michael@0 392 static inline bool
michael@0 393 SetWindowLongHookCheck(HWND hWnd,
michael@0 394 int nIndex,
michael@0 395 LONG_PTR newLong)
michael@0 396 {
michael@0 397 nsPluginNativeWindowWin * win =
michael@0 398 (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
michael@0 399 if (!win || (win && win->mPluginType != nsPluginType_Flash) ||
michael@0 400 (nIndex == GWLP_WNDPROC &&
michael@0 401 newLong == reinterpret_cast<LONG_PTR>(PluginWndProc)))
michael@0 402 return true;
michael@0 403 return false;
michael@0 404 }
michael@0 405
michael@0 406 #ifdef _WIN64
michael@0 407 LONG_PTR WINAPI
michael@0 408 SetWindowLongPtrAHook(HWND hWnd,
michael@0 409 int nIndex,
michael@0 410 LONG_PTR newLong)
michael@0 411 #else
michael@0 412 LONG WINAPI
michael@0 413 SetWindowLongAHook(HWND hWnd,
michael@0 414 int nIndex,
michael@0 415 LONG newLong)
michael@0 416 #endif
michael@0 417 {
michael@0 418 if (SetWindowLongHookCheck(hWnd, nIndex, newLong))
michael@0 419 return sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong);
michael@0 420
michael@0 421 // Set flash's new subclass to get the result.
michael@0 422 LONG_PTR proc = sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong);
michael@0 423
michael@0 424 // We already checked this in SetWindowLongHookCheck
michael@0 425 nsPluginNativeWindowWin * win =
michael@0 426 (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
michael@0 427
michael@0 428 // Hook our subclass back up, just like we do on setwindow.
michael@0 429 win->SetPrevWindowProc(
michael@0 430 reinterpret_cast<WNDPROC>(sUser32SetWindowLongWHookStub(hWnd, nIndex,
michael@0 431 reinterpret_cast<LONG_PTR>(PluginWndProc))));
michael@0 432 return proc;
michael@0 433 }
michael@0 434
michael@0 435 #ifdef _WIN64
michael@0 436 LONG_PTR WINAPI
michael@0 437 SetWindowLongPtrWHook(HWND hWnd,
michael@0 438 int nIndex,
michael@0 439 LONG_PTR newLong)
michael@0 440 #else
michael@0 441 LONG WINAPI
michael@0 442 SetWindowLongWHook(HWND hWnd,
michael@0 443 int nIndex,
michael@0 444 LONG newLong)
michael@0 445 #endif
michael@0 446 {
michael@0 447 if (SetWindowLongHookCheck(hWnd, nIndex, newLong))
michael@0 448 return sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong);
michael@0 449
michael@0 450 // Set flash's new subclass to get the result.
michael@0 451 LONG_PTR proc = sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong);
michael@0 452
michael@0 453 // We already checked this in SetWindowLongHookCheck
michael@0 454 nsPluginNativeWindowWin * win =
michael@0 455 (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
michael@0 456
michael@0 457 // Hook our subclass back up, just like we do on setwindow.
michael@0 458 win->SetPrevWindowProc(
michael@0 459 reinterpret_cast<WNDPROC>(sUser32SetWindowLongWHookStub(hWnd, nIndex,
michael@0 460 reinterpret_cast<LONG_PTR>(PluginWndProc))));
michael@0 461 return proc;
michael@0 462 }
michael@0 463
michael@0 464 static void
michael@0 465 HookSetWindowLongPtr()
michael@0 466 {
michael@0 467 sUser32Intercept.Init("user32.dll");
michael@0 468 #ifdef _WIN64
michael@0 469 if (!sUser32SetWindowLongAHookStub)
michael@0 470 sUser32Intercept.AddHook("SetWindowLongPtrA",
michael@0 471 reinterpret_cast<intptr_t>(SetWindowLongPtrAHook),
michael@0 472 (void**) &sUser32SetWindowLongAHookStub);
michael@0 473 if (!sUser32SetWindowLongWHookStub)
michael@0 474 sUser32Intercept.AddHook("SetWindowLongPtrW",
michael@0 475 reinterpret_cast<intptr_t>(SetWindowLongPtrWHook),
michael@0 476 (void**) &sUser32SetWindowLongWHookStub);
michael@0 477 #else
michael@0 478 if (!sUser32SetWindowLongAHookStub)
michael@0 479 sUser32Intercept.AddHook("SetWindowLongA",
michael@0 480 reinterpret_cast<intptr_t>(SetWindowLongAHook),
michael@0 481 (void**) &sUser32SetWindowLongAHookStub);
michael@0 482 if (!sUser32SetWindowLongWHookStub)
michael@0 483 sUser32Intercept.AddHook("SetWindowLongW",
michael@0 484 reinterpret_cast<intptr_t>(SetWindowLongWHook),
michael@0 485 (void**) &sUser32SetWindowLongWHookStub);
michael@0 486 #endif
michael@0 487 }
michael@0 488
michael@0 489 /**
michael@0 490 * nsPluginNativeWindowWin implementation
michael@0 491 */
michael@0 492 nsPluginNativeWindowWin::nsPluginNativeWindowWin() : nsPluginNativeWindow()
michael@0 493 {
michael@0 494 // initialize the struct fields
michael@0 495 window = nullptr;
michael@0 496 x = 0;
michael@0 497 y = 0;
michael@0 498 width = 0;
michael@0 499 height = 0;
michael@0 500
michael@0 501 mPrevWinProc = nullptr;
michael@0 502 mPluginWinProc = nullptr;
michael@0 503 mPluginType = nsPluginType_Unknown;
michael@0 504
michael@0 505 mParentWnd = nullptr;
michael@0 506 mParentProc = 0;
michael@0 507
michael@0 508 if (!sWM_FLASHBOUNCEMSG) {
michael@0 509 sWM_FLASHBOUNCEMSG = ::RegisterWindowMessage(NS_PLUGIN_CUSTOM_MSG_ID);
michael@0 510 }
michael@0 511 }
michael@0 512
michael@0 513 nsPluginNativeWindowWin::~nsPluginNativeWindowWin()
michael@0 514 {
michael@0 515 // clear weak reference to self to prevent any pending events from
michael@0 516 // dereferencing this.
michael@0 517 mWeakRef.forget();
michael@0 518 }
michael@0 519
michael@0 520 WNDPROC nsPluginNativeWindowWin::GetPrevWindowProc()
michael@0 521 {
michael@0 522 return mPrevWinProc;
michael@0 523 }
michael@0 524
michael@0 525 WNDPROC nsPluginNativeWindowWin::GetWindowProc()
michael@0 526 {
michael@0 527 return mPluginWinProc;
michael@0 528 }
michael@0 529
michael@0 530 NS_IMETHODIMP PluginWindowEvent::Run()
michael@0 531 {
michael@0 532 nsPluginNativeWindowWin *win = mPluginWindowRef.get();
michael@0 533 if (!win)
michael@0 534 return NS_OK;
michael@0 535
michael@0 536 HWND hWnd = GetWnd();
michael@0 537 if (!hWnd)
michael@0 538 return NS_OK;
michael@0 539
michael@0 540 nsRefPtr<nsNPAPIPluginInstance> inst;
michael@0 541 win->GetPluginInstance(inst);
michael@0 542
michael@0 543 if (GetMsg() == WM_USER_FLASH) {
michael@0 544 // XXX Unwind issues related to runnable event callback depth for this
michael@0 545 // event and destruction of the plugin. (Bug 493601)
michael@0 546 ::PostMessage(hWnd, sWM_FLASHBOUNCEMSG, GetWParam(), GetLParam());
michael@0 547 }
michael@0 548 else {
michael@0 549 // Currently not used, but added so that processing events here
michael@0 550 // is more generic.
michael@0 551 ::CallWindowProc(win->GetWindowProc(),
michael@0 552 hWnd,
michael@0 553 GetMsg(),
michael@0 554 GetWParam(),
michael@0 555 GetLParam());
michael@0 556 }
michael@0 557
michael@0 558 Clear();
michael@0 559 return NS_OK;
michael@0 560 }
michael@0 561
michael@0 562 PluginWindowEvent *
michael@0 563 nsPluginNativeWindowWin::GetPluginWindowEvent(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam)
michael@0 564 {
michael@0 565 if (!mWeakRef) {
michael@0 566 mWeakRef = this;
michael@0 567 if (!mWeakRef)
michael@0 568 return nullptr;
michael@0 569 }
michael@0 570
michael@0 571 PluginWindowEvent *event;
michael@0 572
michael@0 573 // We have the ability to alloc if needed in case in the future some plugin
michael@0 574 // should post multiple PostMessages. However, this could lead to many
michael@0 575 // alloc's per second which could become a performance issue. See bug 169247.
michael@0 576 if (!mCachedPluginWindowEvent)
michael@0 577 {
michael@0 578 event = new PluginWindowEvent();
michael@0 579 if (!event) return nullptr;
michael@0 580 mCachedPluginWindowEvent = event;
michael@0 581 }
michael@0 582 else if (mCachedPluginWindowEvent->InUse())
michael@0 583 {
michael@0 584 event = new PluginWindowEvent();
michael@0 585 if (!event) return nullptr;
michael@0 586 }
michael@0 587 else
michael@0 588 {
michael@0 589 event = mCachedPluginWindowEvent;
michael@0 590 }
michael@0 591
michael@0 592 event->Init(mWeakRef, aWnd, aMsg, aWParam, aLParam);
michael@0 593 return event;
michael@0 594 }
michael@0 595
michael@0 596 nsresult nsPluginNativeWindowWin::CallSetWindow(nsRefPtr<nsNPAPIPluginInstance> &aPluginInstance)
michael@0 597 {
michael@0 598 // Note, 'window' can be null
michael@0 599
michael@0 600 // check the incoming instance, null indicates that window is going away and we are
michael@0 601 // not interested in subclassing business any more, undo and don't subclass
michael@0 602 if (!aPluginInstance) {
michael@0 603 UndoSubclassAndAssociateWindow();
michael@0 604 nsPluginNativeWindow::CallSetWindow(aPluginInstance);
michael@0 605 return NS_OK;
michael@0 606 }
michael@0 607
michael@0 608 // check plugin mime type and cache it if it will need special treatment later
michael@0 609 if (mPluginType == nsPluginType_Unknown) {
michael@0 610 const char* mimetype = nullptr;
michael@0 611 aPluginInstance->GetMIMEType(&mimetype);
michael@0 612 if (mimetype) {
michael@0 613 if (!strcmp(mimetype, "application/x-shockwave-flash"))
michael@0 614 mPluginType = nsPluginType_Flash;
michael@0 615 else if (!strcmp(mimetype, "audio/x-pn-realaudio-plugin"))
michael@0 616 mPluginType = nsPluginType_Real;
michael@0 617 else if (!strcmp(mimetype, "application/pdf"))
michael@0 618 mPluginType = nsPluginType_PDF;
michael@0 619 else
michael@0 620 mPluginType = nsPluginType_Other;
michael@0 621 }
michael@0 622 }
michael@0 623
michael@0 624 if (window) {
michael@0 625 // grab the widget procedure before the plug-in does a subclass in
michael@0 626 // setwindow. We'll use this in PluginWndProc for forwarding focus
michael@0 627 // events to the widget.
michael@0 628 WNDPROC currentWndProc =
michael@0 629 (WNDPROC)::GetWindowLongPtr((HWND)window, GWLP_WNDPROC);
michael@0 630 if (!mPrevWinProc && currentWndProc != PluginWndProc)
michael@0 631 mPrevWinProc = currentWndProc;
michael@0 632
michael@0 633 // PDF plugin v7.0.9, v8.1.3, and v9.0 subclass parent window, bug 531551
michael@0 634 // V8.2.2 and V9.1 don't have such problem.
michael@0 635 if (mPluginType == nsPluginType_PDF) {
michael@0 636 HWND parent = ::GetParent((HWND)window);
michael@0 637 if (mParentWnd != parent) {
michael@0 638 NS_ASSERTION(!mParentWnd, "Plugin's parent window changed");
michael@0 639 mParentWnd = parent;
michael@0 640 mParentProc = ::GetWindowLongPtr(mParentWnd, GWLP_WNDPROC);
michael@0 641 }
michael@0 642 }
michael@0 643 }
michael@0 644
michael@0 645 nsPluginNativeWindow::CallSetWindow(aPluginInstance);
michael@0 646
michael@0 647 SubclassAndAssociateWindow();
michael@0 648
michael@0 649 if (window && mPluginType == nsPluginType_Flash &&
michael@0 650 !GetPropW((HWND)window, L"PluginInstanceParentProperty")) {
michael@0 651 HookSetWindowLongPtr();
michael@0 652 }
michael@0 653
michael@0 654 return NS_OK;
michael@0 655 }
michael@0 656
michael@0 657 nsresult nsPluginNativeWindowWin::SubclassAndAssociateWindow()
michael@0 658 {
michael@0 659 if (type != NPWindowTypeWindow || !window)
michael@0 660 return NS_ERROR_FAILURE;
michael@0 661
michael@0 662 HWND hWnd = (HWND)window;
michael@0 663
michael@0 664 // check if we need to subclass
michael@0 665 WNDPROC currentWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC);
michael@0 666 if (currentWndProc == PluginWndProc)
michael@0 667 return NS_OK;
michael@0 668
michael@0 669 // If the plugin reset the subclass, set it back.
michael@0 670 if (mPluginWinProc) {
michael@0 671 #ifdef DEBUG
michael@0 672 NS_WARNING("A plugin cleared our subclass - resetting.");
michael@0 673 if (currentWndProc != mPluginWinProc) {
michael@0 674 NS_WARNING("Procedures do not match up, discarding old subclass value.");
michael@0 675 }
michael@0 676 if (mPrevWinProc && currentWndProc == mPrevWinProc) {
michael@0 677 NS_WARNING("The new procedure is our widget procedure?");
michael@0 678 }
michael@0 679 #endif
michael@0 680 SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc);
michael@0 681 return NS_OK;
michael@0 682 }
michael@0 683
michael@0 684 LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE);
michael@0 685 // Out of process plugins must not have the WS_CLIPCHILDREN style set on their
michael@0 686 // parent windows or else synchronous paints (via UpdateWindow() and others)
michael@0 687 // will cause deadlocks.
michael@0 688 if (::GetPropW(hWnd, L"PluginInstanceParentProperty"))
michael@0 689 style &= ~WS_CLIPCHILDREN;
michael@0 690 else
michael@0 691 style |= WS_CLIPCHILDREN;
michael@0 692 SetWindowLongPtr(hWnd, GWL_STYLE, style);
michael@0 693
michael@0 694 mPluginWinProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc);
michael@0 695 if (!mPluginWinProc)
michael@0 696 return NS_ERROR_FAILURE;
michael@0 697
michael@0 698 DebugOnly<nsPluginNativeWindowWin *> win = (nsPluginNativeWindowWin *)::GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
michael@0 699 NS_ASSERTION(!win || (win == this), "plugin window already has property and this is not us");
michael@0 700
michael@0 701 if (!::SetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION, (HANDLE)this))
michael@0 702 return NS_ERROR_FAILURE;
michael@0 703
michael@0 704 return NS_OK;
michael@0 705 }
michael@0 706
michael@0 707 nsresult nsPluginNativeWindowWin::UndoSubclassAndAssociateWindow()
michael@0 708 {
michael@0 709 // release plugin instance
michael@0 710 SetPluginInstance(nullptr);
michael@0 711
michael@0 712 // remove window property
michael@0 713 HWND hWnd = (HWND)window;
michael@0 714 if (IsWindow(hWnd))
michael@0 715 ::RemoveProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
michael@0 716
michael@0 717 // restore the original win proc
michael@0 718 // but only do this if this were us last time
michael@0 719 if (mPluginWinProc) {
michael@0 720 WNDPROC currentWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC);
michael@0 721 if (currentWndProc == PluginWndProc)
michael@0 722 SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)mPluginWinProc);
michael@0 723 mPluginWinProc = nullptr;
michael@0 724
michael@0 725 LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE);
michael@0 726 style &= ~WS_CLIPCHILDREN;
michael@0 727 SetWindowLongPtr(hWnd, GWL_STYLE, style);
michael@0 728 }
michael@0 729
michael@0 730 if (mPluginType == nsPluginType_PDF && mParentWnd) {
michael@0 731 ::SetWindowLongPtr(mParentWnd, GWLP_WNDPROC, mParentProc);
michael@0 732 mParentWnd = nullptr;
michael@0 733 mParentProc = 0;
michael@0 734 }
michael@0 735
michael@0 736 return NS_OK;
michael@0 737 }
michael@0 738
michael@0 739 nsresult PLUG_NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow)
michael@0 740 {
michael@0 741 NS_ENSURE_ARG_POINTER(aPluginNativeWindow);
michael@0 742
michael@0 743 *aPluginNativeWindow = new nsPluginNativeWindowWin();
michael@0 744
michael@0 745 return *aPluginNativeWindow ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
michael@0 746 }
michael@0 747
michael@0 748 nsresult PLUG_DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow)
michael@0 749 {
michael@0 750 NS_ENSURE_ARG_POINTER(aPluginNativeWindow);
michael@0 751 nsPluginNativeWindowWin *p = (nsPluginNativeWindowWin *)aPluginNativeWindow;
michael@0 752 delete p;
michael@0 753 return NS_OK;
michael@0 754 }

mercurial