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

     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 }

mercurial