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