|
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/. */ |
|
5 |
|
6 #include "mozilla/BasicEvents.h" |
|
7 #include "mozilla/DebugOnly.h" |
|
8 |
|
9 #include "windows.h" |
|
10 #include "windowsx.h" |
|
11 |
|
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 |
|
18 |
|
19 #include "nsDebug.h" |
|
20 |
|
21 #include "nsWindowsDllInterceptor.h" |
|
22 #include "nsPluginNativeWindow.h" |
|
23 #include "nsThreadUtils.h" |
|
24 #include "nsAutoPtr.h" |
|
25 #include "nsTWeakRef.h" |
|
26 #include "nsCrashOnException.h" |
|
27 |
|
28 using namespace mozilla; |
|
29 |
|
30 #define NP_POPUP_API_VERSION 16 |
|
31 |
|
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)) |
|
37 |
|
38 |
|
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; |
|
43 |
|
44 typedef nsTWeakRef<class nsPluginNativeWindowWin> PluginWindowWeakRef; |
|
45 |
|
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; }; |
|
60 |
|
61 NS_DECL_NSIRUNNABLE |
|
62 |
|
63 protected: |
|
64 PluginWindowWeakRef mPluginWindowRef; |
|
65 HWND mWnd; |
|
66 UINT mMsg; |
|
67 WPARAM mWParam; |
|
68 LPARAM mLParam; |
|
69 }; |
|
70 |
|
71 PluginWindowEvent::PluginWindowEvent() |
|
72 { |
|
73 Clear(); |
|
74 } |
|
75 |
|
76 void PluginWindowEvent::Clear() |
|
77 { |
|
78 mWnd = nullptr; |
|
79 mMsg = 0; |
|
80 mWParam = 0; |
|
81 mLParam = 0; |
|
82 } |
|
83 |
|
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 } |
|
95 |
|
96 /** |
|
97 * nsPluginNativeWindow Windows specific class declaration |
|
98 */ |
|
99 |
|
100 typedef enum { |
|
101 nsPluginType_Unknown = 0, |
|
102 nsPluginType_Flash, |
|
103 nsPluginType_Real, |
|
104 nsPluginType_PDF, |
|
105 nsPluginType_Other |
|
106 } nsPluginType; |
|
107 |
|
108 class nsPluginNativeWindowWin : public nsPluginNativeWindow { |
|
109 public: |
|
110 nsPluginNativeWindowWin(); |
|
111 virtual ~nsPluginNativeWindowWin(); |
|
112 |
|
113 virtual nsresult CallSetWindow(nsRefPtr<nsNPAPIPluginInstance> &aPluginInstance); |
|
114 |
|
115 private: |
|
116 nsresult SubclassAndAssociateWindow(); |
|
117 nsresult UndoSubclassAndAssociateWindow(); |
|
118 |
|
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); |
|
128 |
|
129 private: |
|
130 WNDPROC mPluginWinProc; |
|
131 WNDPROC mPrevWinProc; |
|
132 PluginWindowWeakRef mWeakRef; |
|
133 nsRefPtr<PluginWindowEvent> mCachedPluginWindowEvent; |
|
134 |
|
135 HWND mParentWnd; |
|
136 LONG_PTR mParentProc; |
|
137 public: |
|
138 nsPluginType mPluginType; |
|
139 }; |
|
140 |
|
141 static bool sInMessageDispatch = false; |
|
142 static bool sInPreviousMessageDispatch = false; |
|
143 static UINT sLastMsg = 0; |
|
144 |
|
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); |
|
150 |
|
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 } |
|
157 |
|
158 if (msg != WM_USER_FLASH) |
|
159 return false; // no need to delay |
|
160 |
|
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 } |
|
169 |
|
170 class nsDelayedPopupsEnabledEvent : public nsRunnable |
|
171 { |
|
172 public: |
|
173 nsDelayedPopupsEnabledEvent(nsNPAPIPluginInstance *inst) |
|
174 : mInst(inst) |
|
175 {} |
|
176 |
|
177 NS_DECL_NSIRUNNABLE |
|
178 |
|
179 private: |
|
180 nsRefPtr<nsNPAPIPluginInstance> mInst; |
|
181 }; |
|
182 |
|
183 NS_IMETHODIMP nsDelayedPopupsEnabledEvent::Run() |
|
184 { |
|
185 mInst->PushPopupsEnabledState(false); |
|
186 return NS_OK; |
|
187 } |
|
188 |
|
189 static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); |
|
190 |
|
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; |
|
199 |
|
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); |
|
205 |
|
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 } |
|
215 |
|
216 bool enablePopups = false; |
|
217 |
|
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; |
|
235 |
|
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 } |
|
250 |
|
251 // fall through |
|
252 case WM_KEYUP: |
|
253 enablePopups = true; |
|
254 |
|
255 break; |
|
256 |
|
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; |
|
282 |
|
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 } |
|
301 |
|
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 } |
|
309 |
|
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 } |
|
317 |
|
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; |
|
329 |
|
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. |
|
339 |
|
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. |
|
344 |
|
345 nsCOMPtr<nsIRunnable> event = new nsDelayedPopupsEnabledEvent(inst); |
|
346 if (event) |
|
347 NS_DispatchToCurrentThread(event); |
|
348 } |
|
349 |
|
350 return res; |
|
351 } |
|
352 |
|
353 static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) |
|
354 { |
|
355 return mozilla::CallWindowProcCrashProtected(PluginWndProcInternal, hWnd, msg, wParam, lParam); |
|
356 } |
|
357 |
|
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; |
|
368 |
|
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 } |
|
405 |
|
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); |
|
420 |
|
421 // Set flash's new subclass to get the result. |
|
422 LONG_PTR proc = sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong); |
|
423 |
|
424 // We already checked this in SetWindowLongHookCheck |
|
425 nsPluginNativeWindowWin * win = |
|
426 (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); |
|
427 |
|
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 } |
|
434 |
|
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); |
|
449 |
|
450 // Set flash's new subclass to get the result. |
|
451 LONG_PTR proc = sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong); |
|
452 |
|
453 // We already checked this in SetWindowLongHookCheck |
|
454 nsPluginNativeWindowWin * win = |
|
455 (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); |
|
456 |
|
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 } |
|
463 |
|
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 } |
|
488 |
|
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; |
|
500 |
|
501 mPrevWinProc = nullptr; |
|
502 mPluginWinProc = nullptr; |
|
503 mPluginType = nsPluginType_Unknown; |
|
504 |
|
505 mParentWnd = nullptr; |
|
506 mParentProc = 0; |
|
507 |
|
508 if (!sWM_FLASHBOUNCEMSG) { |
|
509 sWM_FLASHBOUNCEMSG = ::RegisterWindowMessage(NS_PLUGIN_CUSTOM_MSG_ID); |
|
510 } |
|
511 } |
|
512 |
|
513 nsPluginNativeWindowWin::~nsPluginNativeWindowWin() |
|
514 { |
|
515 // clear weak reference to self to prevent any pending events from |
|
516 // dereferencing this. |
|
517 mWeakRef.forget(); |
|
518 } |
|
519 |
|
520 WNDPROC nsPluginNativeWindowWin::GetPrevWindowProc() |
|
521 { |
|
522 return mPrevWinProc; |
|
523 } |
|
524 |
|
525 WNDPROC nsPluginNativeWindowWin::GetWindowProc() |
|
526 { |
|
527 return mPluginWinProc; |
|
528 } |
|
529 |
|
530 NS_IMETHODIMP PluginWindowEvent::Run() |
|
531 { |
|
532 nsPluginNativeWindowWin *win = mPluginWindowRef.get(); |
|
533 if (!win) |
|
534 return NS_OK; |
|
535 |
|
536 HWND hWnd = GetWnd(); |
|
537 if (!hWnd) |
|
538 return NS_OK; |
|
539 |
|
540 nsRefPtr<nsNPAPIPluginInstance> inst; |
|
541 win->GetPluginInstance(inst); |
|
542 |
|
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 } |
|
557 |
|
558 Clear(); |
|
559 return NS_OK; |
|
560 } |
|
561 |
|
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 } |
|
570 |
|
571 PluginWindowEvent *event; |
|
572 |
|
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 } |
|
591 |
|
592 event->Init(mWeakRef, aWnd, aMsg, aWParam, aLParam); |
|
593 return event; |
|
594 } |
|
595 |
|
596 nsresult nsPluginNativeWindowWin::CallSetWindow(nsRefPtr<nsNPAPIPluginInstance> &aPluginInstance) |
|
597 { |
|
598 // Note, 'window' can be null |
|
599 |
|
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 } |
|
607 |
|
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 } |
|
623 |
|
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; |
|
632 |
|
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 } |
|
644 |
|
645 nsPluginNativeWindow::CallSetWindow(aPluginInstance); |
|
646 |
|
647 SubclassAndAssociateWindow(); |
|
648 |
|
649 if (window && mPluginType == nsPluginType_Flash && |
|
650 !GetPropW((HWND)window, L"PluginInstanceParentProperty")) { |
|
651 HookSetWindowLongPtr(); |
|
652 } |
|
653 |
|
654 return NS_OK; |
|
655 } |
|
656 |
|
657 nsresult nsPluginNativeWindowWin::SubclassAndAssociateWindow() |
|
658 { |
|
659 if (type != NPWindowTypeWindow || !window) |
|
660 return NS_ERROR_FAILURE; |
|
661 |
|
662 HWND hWnd = (HWND)window; |
|
663 |
|
664 // check if we need to subclass |
|
665 WNDPROC currentWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC); |
|
666 if (currentWndProc == PluginWndProc) |
|
667 return NS_OK; |
|
668 |
|
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 } |
|
683 |
|
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); |
|
693 |
|
694 mPluginWinProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc); |
|
695 if (!mPluginWinProc) |
|
696 return NS_ERROR_FAILURE; |
|
697 |
|
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"); |
|
700 |
|
701 if (!::SetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION, (HANDLE)this)) |
|
702 return NS_ERROR_FAILURE; |
|
703 |
|
704 return NS_OK; |
|
705 } |
|
706 |
|
707 nsresult nsPluginNativeWindowWin::UndoSubclassAndAssociateWindow() |
|
708 { |
|
709 // release plugin instance |
|
710 SetPluginInstance(nullptr); |
|
711 |
|
712 // remove window property |
|
713 HWND hWnd = (HWND)window; |
|
714 if (IsWindow(hWnd)) |
|
715 ::RemoveProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); |
|
716 |
|
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; |
|
724 |
|
725 LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE); |
|
726 style &= ~WS_CLIPCHILDREN; |
|
727 SetWindowLongPtr(hWnd, GWL_STYLE, style); |
|
728 } |
|
729 |
|
730 if (mPluginType == nsPluginType_PDF && mParentWnd) { |
|
731 ::SetWindowLongPtr(mParentWnd, GWLP_WNDPROC, mParentProc); |
|
732 mParentWnd = nullptr; |
|
733 mParentProc = 0; |
|
734 } |
|
735 |
|
736 return NS_OK; |
|
737 } |
|
738 |
|
739 nsresult PLUG_NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow) |
|
740 { |
|
741 NS_ENSURE_ARG_POINTER(aPluginNativeWindow); |
|
742 |
|
743 *aPluginNativeWindow = new nsPluginNativeWindowWin(); |
|
744 |
|
745 return *aPluginNativeWindow ? NS_OK : NS_ERROR_OUT_OF_MEMORY; |
|
746 } |
|
747 |
|
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 } |