dom/plugins/ipc/PluginInstanceChild.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: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: sw=4 ts=4 et :
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "PluginBackgroundDestroyer.h"
     8 #include "PluginInstanceChild.h"
     9 #include "PluginModuleChild.h"
    10 #include "BrowserStreamChild.h"
    11 #include "PluginStreamChild.h"
    12 #include "StreamNotifyChild.h"
    13 #include "PluginProcessChild.h"
    14 #include "gfxASurface.h"
    15 #include "gfxContext.h"
    16 #include "nsNPAPIPluginInstance.h"
    17 #ifdef MOZ_X11
    18 #include "gfxXlibSurface.h"
    19 #endif
    20 #ifdef XP_WIN
    21 #include "mozilla/gfx/SharedDIBSurface.h"
    22 #include "nsCrashOnException.h"
    23 extern const wchar_t* kFlashFullscreenClass;
    24 using mozilla::gfx::SharedDIBSurface;
    25 #endif
    26 #include "gfxSharedImageSurface.h"
    27 #include "gfxUtils.h"
    28 #include "gfxAlphaRecovery.h"
    30 #include "mozilla/ArrayUtils.h"
    31 #include "mozilla/ipc/MessageChannel.h"
    32 #include "mozilla/AutoRestore.h"
    33 #include "ImageContainer.h"
    35 using namespace mozilla;
    36 using mozilla::ipc::ProcessChild;
    37 using namespace mozilla::plugins;
    38 using namespace mozilla::layers;
    39 using namespace mozilla::gfx;
    40 using namespace std;
    42 #ifdef MOZ_WIDGET_GTK
    44 #include <gtk/gtk.h>
    45 #if (MOZ_WIDGET_GTK == 3)
    46 #include <gtk/gtkx.h>
    47 #endif
    48 #include <gdk/gdkx.h>
    49 #include <gdk/gdk.h>
    50 #if (MOZ_WIDGET_GTK == 2)
    51 #include "gtk2xtbin.h"
    52 #endif
    54 #elif defined(MOZ_WIDGET_QT)
    55 #undef KeyPress
    56 #undef KeyRelease
    57 #elif defined(OS_WIN)
    58 #ifndef WM_MOUSEHWHEEL
    59 #define WM_MOUSEHWHEEL     0x020E
    60 #endif
    62 #include "nsWindowsDllInterceptor.h"
    64 typedef BOOL (WINAPI *User32TrackPopupMenu)(HMENU hMenu,
    65                                             UINT uFlags,
    66                                             int x,
    67                                             int y,
    68                                             int nReserved,
    69                                             HWND hWnd,
    70                                             CONST RECT *prcRect);
    71 static WindowsDllInterceptor sUser32Intercept;
    72 static HWND sWinlessPopupSurrogateHWND = nullptr;
    73 static User32TrackPopupMenu sUser32TrackPopupMenuStub = nullptr;
    75 using mozilla::gfx::SharedDIB;
    77 #include <windows.h>
    78 #include <windowsx.h>
    80 // Flash WM_USER message delay time for PostDelayedTask. Borrowed
    81 // from Chromium's web plugin delegate src. See 'flash msg throttling
    82 // helpers' section for details.
    83 const int kFlashWMUSERMessageThrottleDelayMs = 5;
    85 static const TCHAR kPluginIgnoreSubclassProperty[] = TEXT("PluginIgnoreSubclassProperty");
    87 #elif defined(XP_MACOSX)
    88 #include <ApplicationServices/ApplicationServices.h>
    89 #include "nsCocoaFeatures.h"
    90 #include "PluginUtilsOSX.h"
    91 #endif // defined(XP_MACOSX)
    93 template<>
    94 struct RunnableMethodTraits<PluginInstanceChild>
    95 {
    96     static void RetainCallee(PluginInstanceChild* obj) { }
    97     static void ReleaseCallee(PluginInstanceChild* obj) { }
    98 };
   100 PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface)
   101     : mPluginIface(aPluginIface)
   102 #if defined(XP_MACOSX)
   103     , mContentsScaleFactor(1.0)
   104 #endif
   105     , mDrawingModel(kDefaultDrawingModel)
   106     , mCurrentAsyncSurface(0)
   107     , mAsyncInvalidateMutex("PluginInstanceChild::mAsyncInvalidateMutex")
   108     , mAsyncInvalidateTask(0)
   109     , mCachedWindowActor(nullptr)
   110     , mCachedElementActor(nullptr)
   111 #if (MOZ_WIDGET_GTK == 2)
   112     , mXEmbed(false)
   113 #endif // MOZ_WIDGET_GTK
   114 #if defined(OS_WIN)
   115     , mPluginWindowHWND(0)
   116     , mPluginWndProc(0)
   117     , mPluginParentHWND(0)
   118     , mCachedWinlessPluginHWND(0)
   119     , mWinlessPopupSurrogateHWND(0)
   120     , mWinlessThrottleOldWndProc(0)
   121     , mWinlessHiddenMsgHWND(0)
   122 #endif // OS_WIN
   123     , mAsyncCallMutex("PluginInstanceChild::mAsyncCallMutex")
   124 #if defined(MOZ_WIDGET_COCOA)
   125 #if defined(__i386__)
   126     , mEventModel(NPEventModelCarbon)
   127 #endif
   128     , mShColorSpace(nullptr)
   129     , mShContext(nullptr)
   130     , mCGLayer(nullptr)
   131     , mCurrentEvent(nullptr)
   132 #endif
   133     , mLayersRendering(false)
   134 #ifdef XP_WIN
   135     , mCurrentSurfaceActor(nullptr)
   136     , mBackSurfaceActor(nullptr)
   137 #endif
   138     , mAccumulatedInvalidRect(0,0,0,0)
   139     , mIsTransparent(false)
   140     , mSurfaceType(gfxSurfaceType::Max)
   141     , mCurrentInvalidateTask(nullptr)
   142     , mCurrentAsyncSetWindowTask(nullptr)
   143     , mPendingPluginCall(false)
   144     , mDoAlphaExtraction(false)
   145     , mHasPainted(false)
   146     , mSurfaceDifferenceRect(0,0,0,0)
   147 {
   148     memset(&mWindow, 0, sizeof(mWindow));
   149     mWindow.type = NPWindowTypeWindow;
   150     mData.ndata = (void*) this;
   151     mData.pdata = nullptr;
   152 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
   153     mWindow.ws_info = &mWsInfo;
   154     memset(&mWsInfo, 0, sizeof(mWsInfo));
   155 #if (MOZ_WIDGET_GTK == 2)
   156     mWsInfo.display = nullptr;
   157     mXtClient.top_widget = nullptr;
   158 #else
   159     mWsInfo.display = DefaultXDisplay();
   160 #endif
   161 #endif // MOZ_X11 && XP_UNIX && !XP_MACOSX
   162 #if defined(OS_WIN)
   163     memset(&mAlphaExtract, 0, sizeof(mAlphaExtract));
   164 #endif // OS_WIN
   165 #if defined(OS_WIN)
   166     InitPopupMenuHook();
   167 #endif // OS_WIN
   168 }
   170 PluginInstanceChild::~PluginInstanceChild()
   171 {
   172 #if defined(OS_WIN)
   173     NS_ASSERTION(!mPluginWindowHWND, "Destroying PluginInstanceChild without NPP_Destroy?");
   174 #endif
   175 #if defined(MOZ_WIDGET_COCOA)
   176     if (mShColorSpace) {
   177         ::CGColorSpaceRelease(mShColorSpace);
   178     }
   179     if (mShContext) {
   180         ::CGContextRelease(mShContext);
   181     }
   182     if (mCGLayer) {
   183         PluginUtilsOSX::ReleaseCGLayer(mCGLayer);
   184     }
   185     if (mDrawingModel == NPDrawingModelCoreAnimation) {
   186         UnscheduleTimer(mCARefreshTimer);
   187     }
   188 #endif
   189 }
   191 int
   192 PluginInstanceChild::GetQuirks()
   193 {
   194     return PluginModuleChild::current()->GetQuirks();
   195 }
   197 NPError
   198 PluginInstanceChild::InternalGetNPObjectForValue(NPNVariable aValue,
   199                                                  NPObject** aObject)
   200 {
   201     PluginScriptableObjectChild* actor = nullptr;
   202     NPError result = NPERR_NO_ERROR;
   204     switch (aValue) {
   205         case NPNVWindowNPObject:
   206             if (!(actor = mCachedWindowActor)) {
   207                 PPluginScriptableObjectChild* actorProtocol;
   208                 CallNPN_GetValue_NPNVWindowNPObject(&actorProtocol, &result);
   209                 if (result == NPERR_NO_ERROR) {
   210                     actor = mCachedWindowActor =
   211                         static_cast<PluginScriptableObjectChild*>(actorProtocol);
   212                     NS_ASSERTION(actor, "Null actor!");
   213                     PluginModuleChild::sBrowserFuncs.retainobject(
   214                         actor->GetObject(false));
   215                 }
   216             }
   217             break;
   219         case NPNVPluginElementNPObject:
   220             if (!(actor = mCachedElementActor)) {
   221                 PPluginScriptableObjectChild* actorProtocol;
   222                 CallNPN_GetValue_NPNVPluginElementNPObject(&actorProtocol,
   223                                                            &result);
   224                 if (result == NPERR_NO_ERROR) {
   225                     actor = mCachedElementActor =
   226                         static_cast<PluginScriptableObjectChild*>(actorProtocol);
   227                     NS_ASSERTION(actor, "Null actor!");
   228                     PluginModuleChild::sBrowserFuncs.retainobject(
   229                         actor->GetObject(false));
   230                 }
   231             }
   232             break;
   234         default:
   235             NS_NOTREACHED("Don't know what to do with this value type!");
   236     }
   238 #ifdef DEBUG
   239     {
   240         NPError currentResult;
   241         PPluginScriptableObjectChild* currentActor = nullptr;
   243         switch (aValue) {
   244             case NPNVWindowNPObject:
   245                 CallNPN_GetValue_NPNVWindowNPObject(&currentActor,
   246                                                     &currentResult);
   247                 break;
   248             case NPNVPluginElementNPObject:
   249                 CallNPN_GetValue_NPNVPluginElementNPObject(&currentActor,
   250                                                            &currentResult);
   251                 break;
   252             default:
   253                 MOZ_ASSERT(false);
   254         }
   256         // Make sure that the current actor returned by the parent matches our
   257         // cached actor!
   258         NS_ASSERTION(!currentActor ||
   259                      static_cast<PluginScriptableObjectChild*>(currentActor) ==
   260                      actor, "Cached actor is out of date!");
   261     }
   262 #endif
   264     if (result != NPERR_NO_ERROR) {
   265         return result;
   266     }
   268     NPObject* object = actor->GetObject(false);
   269     NS_ASSERTION(object, "Null object?!");
   271     *aObject = PluginModuleChild::sBrowserFuncs.retainobject(object);
   272     return NPERR_NO_ERROR;
   274 }
   276 NPError
   277 PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
   278                                   void* aValue)
   279 {
   280     PLUGIN_LOG_DEBUG(("%s (aVar=%i)", FULLFUNCTION, (int) aVar));
   281     AssertPluginThread();
   283     switch(aVar) {
   285 #if defined(MOZ_X11)
   286     case NPNVToolkit:
   287         *((NPNToolkitType*)aValue) = NPNVGtk2;
   288         return NPERR_NO_ERROR;
   290     case NPNVxDisplay:
   291         if (!mWsInfo.display) {
   292             // We are called before Initialize() so we have to call it now.
   293            Initialize();
   294            NS_ASSERTION(mWsInfo.display, "We should have a valid display!");
   295         }
   296         *(void **)aValue = mWsInfo.display;
   297         return NPERR_NO_ERROR;
   299 #elif defined(OS_WIN)
   300     case NPNVToolkit:
   301         return NPERR_GENERIC_ERROR;
   302 #endif
   303     case NPNVprivateModeBool: {
   304         bool v = false;
   305         NPError result;
   306         if (!CallNPN_GetValue_NPNVprivateModeBool(&v, &result)) {
   307             return NPERR_GENERIC_ERROR;
   308         }
   309         *static_cast<NPBool*>(aValue) = v;
   310         return result;
   311     }
   313     case NPNVdocumentOrigin: {
   314         nsCString v;
   315         NPError result;
   316         if (!CallNPN_GetValue_NPNVdocumentOrigin(&v, &result)) {
   317             return NPERR_GENERIC_ERROR;
   318         }
   319         if (result == NPERR_NO_ERROR) {
   320             *static_cast<char**>(aValue) = ToNewCString(v);
   321         }
   322         return result;
   323     }
   325     case NPNVWindowNPObject: // Intentional fall-through
   326     case NPNVPluginElementNPObject: {
   327         NPObject* object;
   328         NPError result = InternalGetNPObjectForValue(aVar, &object);
   329         if (result == NPERR_NO_ERROR) {
   330             *((NPObject**)aValue) = object;
   331         }
   332         return result;
   333     }
   335     case NPNVnetscapeWindow: {
   336 #ifdef XP_WIN
   337         if (mWindow.type == NPWindowTypeDrawable) {
   338             if (mCachedWinlessPluginHWND) {
   339               *static_cast<HWND*>(aValue) = mCachedWinlessPluginHWND;
   340               return NPERR_NO_ERROR;
   341             }
   342             NPError result;
   343             if (!CallNPN_GetValue_NPNVnetscapeWindow(&mCachedWinlessPluginHWND, &result)) {
   344                 return NPERR_GENERIC_ERROR;
   345             }
   346             *static_cast<HWND*>(aValue) = mCachedWinlessPluginHWND;
   347             return result;
   348         }
   349         else {
   350             *static_cast<HWND*>(aValue) = mPluginWindowHWND;
   351             return NPERR_NO_ERROR;
   352         }
   353 #elif defined(MOZ_X11)
   354         NPError result;
   355         CallNPN_GetValue_NPNVnetscapeWindow(static_cast<XID*>(aValue), &result);
   356         return result;
   357 #else
   358         return NPERR_GENERIC_ERROR;
   359 #endif
   360     }
   362     case NPNVsupportsAsyncBitmapSurfaceBool: {
   363 #ifdef XP_WIN
   364         *((NPBool*)aValue) = PluginModuleChild::current()->AsyncDrawingAllowed();
   365 #else
   366         // We do not support non-windows yet.
   367         *((NPBool*)aValue) = false;
   368 #endif
   369         return NPERR_NO_ERROR;
   370     }
   372 #ifdef XP_WIN
   373     case NPNVsupportsAsyncWindowsDXGISurfaceBool: {
   374         bool val;
   375         CallNPN_GetValue_DrawingModelSupport(NPNVsupportsAsyncWindowsDXGISurfaceBool, &val);
   376         *((NPBool*)aValue) = val;
   377         return NPERR_NO_ERROR;
   378     }
   379 #endif
   381 #ifdef XP_MACOSX
   382    case NPNVsupportsCoreGraphicsBool: {
   383         *((NPBool*)aValue) = true;
   384         return NPERR_NO_ERROR;
   385     }
   387     case NPNVsupportsCoreAnimationBool: {
   388         *((NPBool*)aValue) = nsCocoaFeatures::SupportCoreAnimationPlugins();
   389         return NPERR_NO_ERROR;
   390     }
   392     case NPNVsupportsInvalidatingCoreAnimationBool: {
   393         *((NPBool*)aValue) = nsCocoaFeatures::SupportCoreAnimationPlugins();
   394         return NPERR_NO_ERROR;
   395     }
   397     case NPNVsupportsCompositingCoreAnimationPluginsBool: {
   398         *((NPBool*)aValue) = true;
   399         return NPERR_NO_ERROR;
   400     }
   402     case NPNVsupportsCocoaBool: {
   403         *((NPBool*)aValue) = true;
   404         return NPERR_NO_ERROR;
   405     }
   407 #ifndef NP_NO_CARBON
   408     case NPNVsupportsCarbonBool: {
   409       *((NPBool*)aValue) = false;
   410       return NPERR_NO_ERROR;
   411     }
   412 #endif
   414     case NPNVsupportsUpdatedCocoaTextInputBool: {
   415       *static_cast<NPBool*>(aValue) = true;
   416       return NPERR_NO_ERROR;
   417     }
   419 #ifndef NP_NO_QUICKDRAW
   420     case NPNVsupportsQuickDrawBool: {
   421         *((NPBool*)aValue) = false;
   422         return NPERR_NO_ERROR;
   423     }
   424 #endif /* NP_NO_QUICKDRAW */
   426     case NPNVcontentsScaleFactor: {
   427         *static_cast<double*>(aValue) = mContentsScaleFactor;
   428         return NPERR_NO_ERROR;
   429     }
   430 #endif /* XP_MACOSX */
   432 #ifdef DEBUG
   433     case NPNVjavascriptEnabledBool:
   434     case NPNVasdEnabledBool:
   435     case NPNVisOfflineBool:
   436     case NPNVSupportsXEmbedBool:
   437     case NPNVSupportsWindowless:
   438         NS_NOTREACHED("NPNVariable should be handled in PluginModuleChild.");
   439 #endif
   441     default:
   442         PR_LOG(GetPluginLog(), PR_LOG_WARNING,
   443                ("In PluginInstanceChild::NPN_GetValue: Unhandled NPNVariable %i (%s)",
   444                 (int) aVar, NPNVariableToString(aVar)));
   445         return NPERR_GENERIC_ERROR;
   446     }
   448 }
   450 #ifdef MOZ_WIDGET_COCOA
   451 #define DEFAULT_REFRESH_MS 20 // CoreAnimation: 50 FPS
   453 void
   454 CAUpdate(NPP npp, uint32_t timerID) {
   455     static_cast<PluginInstanceChild*>(npp->ndata)->Invalidate();
   456 }
   458 void
   459 PluginInstanceChild::Invalidate()
   460 {
   461     NPRect windowRect = {0, 0, uint16_t(mWindow.height),
   462         uint16_t(mWindow.width)};
   464     InvalidateRect(&windowRect);
   465 }
   466 #endif
   468 NPError
   469 PluginInstanceChild::NPN_SetValue(NPPVariable aVar, void* aValue)
   470 {
   471     PR_LOG(GetPluginLog(), PR_LOG_DEBUG, ("%s (aVar=%i, aValue=%p)",
   472                                       FULLFUNCTION, (int) aVar, aValue));
   474     AssertPluginThread();
   476     switch (aVar) {
   477     case NPPVpluginWindowBool: {
   478         NPError rv;
   479         bool windowed = (NPBool) (intptr_t) aValue;
   481         if (!CallNPN_SetValue_NPPVpluginWindow(windowed, &rv))
   482             return NPERR_GENERIC_ERROR;
   484         NPWindowType newWindowType = windowed ? NPWindowTypeWindow : NPWindowTypeDrawable;
   485 #if (MOZ_WIDGET_GTK == 2)
   486         if (mWindow.type != newWindowType && mWsInfo.display) {
   487            // plugin type has been changed but we already have a valid display
   488            // so update it for the recent plugin mode
   489            if (mXEmbed || !windowed) {
   490                // Use default GTK display for XEmbed and windowless plugins
   491                mWsInfo.display = DefaultXDisplay();
   492            }
   493            else {
   494                mWsInfo.display = xt_client_get_display();
   495            }
   496         }
   497 #endif
   498         mWindow.type = newWindowType;
   499         return rv;
   500     }
   502     case NPPVpluginTransparentBool: {
   503         NPError rv;
   504         mIsTransparent = (!!aValue);
   506         if (!CallNPN_SetValue_NPPVpluginTransparent(mIsTransparent, &rv))
   507             return NPERR_GENERIC_ERROR;
   509         return rv;
   510     }
   512     case NPPVpluginUsesDOMForCursorBool: {
   513         NPError rv = NPERR_GENERIC_ERROR;
   514         if (!CallNPN_SetValue_NPPVpluginUsesDOMForCursor((NPBool)(intptr_t)aValue, &rv)) {
   515             return NPERR_GENERIC_ERROR;
   516         }
   517         return rv;
   518     }
   520     case NPPVpluginDrawingModel: {
   521         NPError rv;
   522         int drawingModel = (int16_t) (intptr_t) aValue;
   524         if (!PluginModuleChild::current()->AsyncDrawingAllowed() &&
   525             IsDrawingModelAsync(drawingModel)) {
   526             return NPERR_GENERIC_ERROR;
   527         }              
   529         CrossProcessMutexHandle handle;
   530         OptionalShmem optionalShmem;
   531         if (!CallNPN_SetValue_NPPVpluginDrawingModel(drawingModel, &optionalShmem, &handle, &rv))
   532             return NPERR_GENERIC_ERROR;
   534         if (IsDrawingModelAsync(drawingModel)) {
   535             if (optionalShmem.type() != OptionalShmem::TShmem) {
   536                 return NPERR_GENERIC_ERROR;
   537             }
   538             mRemoteImageDataShmem = optionalShmem.get_Shmem();
   539             mRemoteImageData = mRemoteImageDataShmem.get<RemoteImageData>();
   540             mRemoteImageDataMutex = new CrossProcessMutex(handle);
   541         }
   542         mDrawingModel = drawingModel;
   544 #ifdef XP_MACOSX
   545         if (drawingModel == NPDrawingModelCoreAnimation) {
   546             mCARefreshTimer = ScheduleTimer(DEFAULT_REFRESH_MS, true, CAUpdate);
   547         }
   548 #endif
   550         PLUGIN_LOG_DEBUG(("  Plugin requested drawing model id  #%i\n",
   551             mDrawingModel));
   553         return rv;
   554     }
   556 #ifdef XP_MACOSX
   557     case NPPVpluginEventModel: {
   558         NPError rv;
   559         int eventModel = (int16_t) (intptr_t) aValue;
   561         if (!CallNPN_SetValue_NPPVpluginEventModel(eventModel, &rv))
   562             return NPERR_GENERIC_ERROR;
   563 #if defined(__i386__)
   564         mEventModel = static_cast<NPEventModel>(eventModel);
   565 #endif
   567         PLUGIN_LOG_DEBUG(("  Plugin requested event model id # %i\n",
   568             eventModel));
   570         return rv;
   571     }
   572 #endif
   574     default:
   575         PR_LOG(GetPluginLog(), PR_LOG_WARNING,
   576                ("In PluginInstanceChild::NPN_SetValue: Unhandled NPPVariable %i (%s)",
   577                 (int) aVar, NPPVariableToString(aVar)));
   578         return NPERR_GENERIC_ERROR;
   579     }
   580 }
   582 bool
   583 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginWantsAllNetworkStreams(
   584     bool* wantsAllStreams, NPError* rv)
   585 {
   586     AssertPluginThread();
   588     uint32_t value = 0;
   589     if (!mPluginIface->getvalue) {
   590         *rv = NPERR_GENERIC_ERROR;
   591     }
   592     else {
   593         *rv = mPluginIface->getvalue(GetNPP(), NPPVpluginWantsAllNetworkStreams,
   594                                      &value);
   595     }
   596     *wantsAllStreams = value;
   597     return true;
   598 }
   600 bool
   601 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginNeedsXEmbed(
   602     bool* needs, NPError* rv)
   603 {
   604     AssertPluginThread();
   606 #ifdef MOZ_X11
   607     // The documentation on the types for many variables in NP(N|P)_GetValue
   608     // is vague.  Often boolean values are NPBool (1 byte), but
   609     // https://developer.mozilla.org/en/XEmbed_Extension_for_Mozilla_Plugins
   610     // treats NPPVpluginNeedsXEmbed as PRBool (int), and
   611     // on x86/32-bit, flash stores to this using |movl 0x1,&needsXEmbed|.
   612     // thus we can't use NPBool for needsXEmbed, or the three bytes above
   613     // it on the stack would get clobbered. so protect with the larger bool.
   614     int needsXEmbed = 0;
   615     if (!mPluginIface->getvalue) {
   616         *rv = NPERR_GENERIC_ERROR;
   617     }
   618     else {
   619         *rv = mPluginIface->getvalue(GetNPP(), NPPVpluginNeedsXEmbed,
   620                                      &needsXEmbed);
   621     }
   622     *needs = needsXEmbed;
   623     return true;
   625 #else
   627     NS_RUNTIMEABORT("shouldn't be called on non-X11 platforms");
   628     return false;               // not reached
   630 #endif
   631 }
   633 bool
   634 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginScriptableNPObject(
   635                                           PPluginScriptableObjectChild** aValue,
   636                                           NPError* aResult)
   637 {
   638     AssertPluginThread();
   640     NPObject* object = nullptr;
   641     NPError result = NPERR_GENERIC_ERROR;
   642     if (mPluginIface->getvalue) {
   643         result = mPluginIface->getvalue(GetNPP(), NPPVpluginScriptableNPObject,
   644                                         &object);
   645     }
   646     if (result == NPERR_NO_ERROR && object) {
   647         PluginScriptableObjectChild* actor = GetActorForNPObject(object);
   649         // If we get an actor then it has retained. Otherwise we don't need it
   650         // any longer.
   651         PluginModuleChild::sBrowserFuncs.releaseobject(object);
   652         if (actor) {
   653             *aValue = actor;
   654             *aResult = NPERR_NO_ERROR;
   655             return true;
   656         }
   658         NS_ERROR("Failed to get actor!");
   659         result = NPERR_GENERIC_ERROR;
   660     }
   661     else {
   662         result = NPERR_GENERIC_ERROR;
   663     }
   665     *aValue = nullptr;
   666     *aResult = result;
   667     return true;
   668 }
   670 bool
   671 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginNativeAccessibleAtkPlugId(
   672                                           nsCString* aPlugId,
   673                                           NPError* aResult)
   674 {
   675     AssertPluginThread();
   677 #if MOZ_ACCESSIBILITY_ATK
   679     char* plugId = nullptr;
   680     NPError result = NPERR_GENERIC_ERROR;
   681     if (mPluginIface->getvalue) {
   682         result = mPluginIface->getvalue(GetNPP(),
   683                                         NPPVpluginNativeAccessibleAtkPlugId,
   684                                         &plugId);
   685     }
   687     *aPlugId = nsCString(plugId);
   688     *aResult = result;
   689     return true;
   691 #else
   693     NS_RUNTIMEABORT("shouldn't be called on non-ATK platforms");
   694     return false;
   696 #endif
   697 }
   699 bool
   700 PluginInstanceChild::AnswerNPP_SetValue_NPNVprivateModeBool(const bool& value,
   701                                                             NPError* result)
   702 {
   703     if (!mPluginIface->setvalue) {
   704         *result = NPERR_GENERIC_ERROR;
   705         return true;
   706     }
   708     NPBool v = value;
   709     *result = mPluginIface->setvalue(GetNPP(), NPNVprivateModeBool, &v);
   710     return true;
   711 }
   713 bool
   714 PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event,
   715                                            int16_t* handled)
   716 {
   717     PLUGIN_LOG_DEBUG_FUNCTION;
   718     AssertPluginThread();
   720 #if defined(MOZ_X11) && defined(DEBUG)
   721     if (GraphicsExpose == event.event.type)
   722         PLUGIN_LOG_DEBUG(("  received drawable 0x%lx\n",
   723                           event.event.xgraphicsexpose.drawable));
   724 #endif
   726 #ifdef XP_MACOSX
   727     // Mac OS X does not define an NPEvent structure. It defines more specific types.
   728     NPCocoaEvent evcopy = event.event;
   729     // event.contentsScaleFactor <= 0 is a signal we shouldn't use it,
   730     // for example when AnswerNPP_HandleEvent() is called from elsewhere
   731     // in the child process (not via rpc code from the parent process).
   732     if (event.contentsScaleFactor > 0) {
   733       mContentsScaleFactor = event.contentsScaleFactor;
   734     }
   736     // Make sure we reset mCurrentEvent in case of an exception
   737     AutoRestore<const NPCocoaEvent*> savePreviousEvent(mCurrentEvent);
   739     // Track the current event for NPN_PopUpContextMenu.
   740     mCurrentEvent = &event.event;
   741 #else
   742     // Make a copy since we may modify values.
   743     NPEvent evcopy = event.event;
   744 #endif
   746 #ifdef OS_WIN
   747     // FIXME/bug 567645: temporarily drop the "dummy event" on the floor
   748     if (WM_NULL == evcopy.event)
   749         return true;
   751     // Painting for win32. SharedSurfacePaint handles everything.
   752     if (mWindow.type == NPWindowTypeDrawable) {
   753        if (evcopy.event == WM_PAINT) {
   754           *handled = SharedSurfacePaint(evcopy);
   755           return true;
   756        }
   757        else if (DoublePassRenderingEvent() == evcopy.event) {
   758             // We'll render to mSharedSurfaceDib first, then render to a cached bitmap
   759             // we store locally. The two passes are for alpha extraction, so the second
   760             // pass must be to a flat white surface in order for things to work.
   761             mAlphaExtract.doublePass = RENDER_BACK_ONE;
   762             *handled = true;
   763             return true;
   764        }
   765     }
   766     *handled = WinlessHandleEvent(evcopy);
   767     return true;
   768 #endif
   770     // XXX A previous call to mPluginIface->event might block, e.g. right click
   771     // for context menu. Still, we might get here again, calling into the plugin
   772     // a second time while it's in the previous call.
   773     if (!mPluginIface->event)
   774         *handled = false;
   775     else
   776         *handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
   778 #ifdef XP_MACOSX
   779     // Release any reference counted objects created in the child process.
   780     if (evcopy.type == NPCocoaEventKeyDown ||
   781         evcopy.type == NPCocoaEventKeyUp) {
   782       ::CFRelease((CFStringRef)evcopy.data.key.characters);
   783       ::CFRelease((CFStringRef)evcopy.data.key.charactersIgnoringModifiers);
   784     }
   785     else if (evcopy.type == NPCocoaEventTextInput) {
   786       ::CFRelease((CFStringRef)evcopy.data.text.text);
   787     }
   788 #endif
   790 #ifdef MOZ_X11
   791     if (GraphicsExpose == event.event.type) {
   792         // Make sure the X server completes the drawing before the parent
   793         // draws on top and destroys the Drawable.
   794         //
   795         // XSync() waits for the X server to complete.  Really this child
   796         // process does not need to wait; the parent is the process that needs
   797         // to wait.  A possibly-slightly-better alternative would be to send
   798         // an X event to the parent that the parent would wait for.
   799         XSync(mWsInfo.display, False);
   800     }
   801 #endif
   803     return true;
   804 }
   806 #ifdef XP_MACOSX
   808 bool
   809 PluginInstanceChild::AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event,
   810                                                  Shmem& mem,
   811                                                  int16_t* handled,
   812                                                  Shmem* rtnmem)
   813 {
   814     PLUGIN_LOG_DEBUG_FUNCTION;
   815     AssertPluginThread();
   817     PaintTracker pt;
   819     NPCocoaEvent evcopy = event.event;
   820     mContentsScaleFactor = event.contentsScaleFactor;
   822     if (evcopy.type == NPCocoaEventDrawRect) {
   823         int scaleFactor = ceil(mContentsScaleFactor);
   824         if (!mShColorSpace) {
   825             mShColorSpace = CreateSystemColorSpace();
   826             if (!mShColorSpace) {
   827                 PLUGIN_LOG_DEBUG(("Could not allocate ColorSpace."));
   828                 *handled = false;
   829                 *rtnmem = mem;
   830                 return true;
   831             } 
   832         }
   833         if (!mShContext) {
   834             void* cgContextByte = mem.get<char>();
   835             mShContext = ::CGBitmapContextCreate(cgContextByte, 
   836                               mWindow.width * scaleFactor,
   837                               mWindow.height * scaleFactor, 8, 
   838                               mWindow.width * 4 * scaleFactor, mShColorSpace, 
   839                               kCGImageAlphaPremultipliedFirst |
   840                               kCGBitmapByteOrder32Host);
   842             if (!mShContext) {
   843                 PLUGIN_LOG_DEBUG(("Could not allocate CGBitmapContext."));
   844                 *handled = false;
   845                 *rtnmem = mem;
   846                 return true;
   847             }
   848         }
   849         CGRect clearRect = ::CGRectMake(0, 0, mWindow.width, mWindow.height);
   850         ::CGContextClearRect(mShContext, clearRect);
   851         evcopy.data.draw.context = mShContext; 
   852     } else {
   853         PLUGIN_LOG_DEBUG(("Invalid event type for AnswerNNP_HandleEvent_Shmem."));
   854         *handled = false;
   855         *rtnmem = mem;
   856         return true;
   857     } 
   859     if (!mPluginIface->event) {
   860         *handled = false;
   861     } else {
   862         ::CGContextSaveGState(evcopy.data.draw.context);
   863         *handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
   864         ::CGContextRestoreGState(evcopy.data.draw.context);
   865     }
   867     *rtnmem = mem;
   868     return true;
   869 }
   871 #else
   872 bool
   873 PluginInstanceChild::AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event,
   874                                                  Shmem& mem,
   875                                                  int16_t* handled,
   876                                                  Shmem* rtnmem)
   877 {
   878     NS_RUNTIMEABORT("not reached.");
   879     *rtnmem = mem;
   880     return true;
   881 }
   882 #endif
   884 #ifdef XP_MACOSX
   886 void CallCGDraw(CGContextRef ref, void* aPluginInstance, nsIntRect aUpdateRect) {
   887   PluginInstanceChild* pluginInstance = (PluginInstanceChild*)aPluginInstance;
   889   pluginInstance->CGDraw(ref, aUpdateRect);
   890 }
   892 bool
   893 PluginInstanceChild::CGDraw(CGContextRef ref, nsIntRect aUpdateRect) {
   895   NPCocoaEvent drawEvent;
   896   drawEvent.type = NPCocoaEventDrawRect;
   897   drawEvent.version = 0;
   898   drawEvent.data.draw.x = aUpdateRect.x;
   899   drawEvent.data.draw.y = aUpdateRect.y;
   900   drawEvent.data.draw.width = aUpdateRect.width;
   901   drawEvent.data.draw.height = aUpdateRect.height;
   902   drawEvent.data.draw.context = ref;
   904   NPRemoteEvent remoteDrawEvent = {drawEvent};
   905   // Signal to AnswerNPP_HandleEvent() not to use this value
   906   remoteDrawEvent.contentsScaleFactor = -1.0;
   908   int16_t handled;
   909   AnswerNPP_HandleEvent(remoteDrawEvent, &handled);
   910   return handled == true;
   911 }
   913 bool
   914 PluginInstanceChild::AnswerNPP_HandleEvent_IOSurface(const NPRemoteEvent& event,
   915                                                      const uint32_t &surfaceid,
   916                                                      int16_t* handled)
   917 {
   918     PLUGIN_LOG_DEBUG_FUNCTION;
   919     AssertPluginThread();
   921     PaintTracker pt;
   923     NPCocoaEvent evcopy = event.event;
   924     mContentsScaleFactor = event.contentsScaleFactor;
   925     RefPtr<MacIOSurface> surf = MacIOSurface::LookupSurface(surfaceid,
   926                                                             mContentsScaleFactor);
   927     if (!surf) {
   928         NS_ERROR("Invalid IOSurface.");
   929         *handled = false;
   930         return false;
   931     }
   933     if (!mCARenderer) {
   934       mCARenderer = new nsCARenderer();
   935     }
   937     if (evcopy.type == NPCocoaEventDrawRect) {
   938         mCARenderer->AttachIOSurface(surf);
   939         if (!mCARenderer->isInit()) {
   940             void *caLayer = nullptr;
   941             NPError result = mPluginIface->getvalue(GetNPP(), 
   942                                      NPPVpluginCoreAnimationLayer,
   943                                      &caLayer);
   945             if (result != NPERR_NO_ERROR || !caLayer) {
   946                 PLUGIN_LOG_DEBUG(("Plugin requested CoreAnimation but did not "
   947                                   "provide CALayer."));
   948                 *handled = false;
   949                 return false;
   950             }
   952             mCARenderer->SetupRenderer(caLayer, mWindow.width, mWindow.height,
   953                             mContentsScaleFactor,
   954                             GetQuirks() & PluginModuleChild::QUIRK_ALLOW_OFFLINE_RENDERER ?
   955                             ALLOW_OFFLINE_RENDERER : DISALLOW_OFFLINE_RENDERER);
   957             // Flash needs to have the window set again after this step
   958             if (mPluginIface->setwindow)
   959                 (void) mPluginIface->setwindow(&mData, &mWindow);
   960         }
   961     } else {
   962         PLUGIN_LOG_DEBUG(("Invalid event type for "
   963                           "AnswerNNP_HandleEvent_IOSurface."));
   964         *handled = false;
   965         return false;
   966     } 
   968     mCARenderer->Render(mWindow.width, mWindow.height,
   969                         mContentsScaleFactor, nullptr);
   971     return true;
   973 }
   975 #else
   976 bool
   977 PluginInstanceChild::AnswerNPP_HandleEvent_IOSurface(const NPRemoteEvent& event,
   978                                                      const uint32_t &surfaceid,
   979                                                      int16_t* handled)
   980 {
   981     NS_RUNTIMEABORT("NPP_HandleEvent_IOSurface is a OSX-only message");
   982     return false;
   983 }
   984 #endif
   986 bool
   987 PluginInstanceChild::RecvWindowPosChanged(const NPRemoteEvent& event)
   988 {
   989     NS_ASSERTION(!mLayersRendering && !mPendingPluginCall,
   990                  "Shouldn't be receiving WindowPosChanged with layer rendering");
   992 #ifdef OS_WIN
   993     int16_t dontcare;
   994     return AnswerNPP_HandleEvent(event, &dontcare);
   995 #else
   996     NS_RUNTIMEABORT("WindowPosChanged is a windows-only message");
   997     return false;
   998 #endif
   999 }
  1001 bool
  1002 PluginInstanceChild::RecvContentsScaleFactorChanged(const double& aContentsScaleFactor)
  1004 #ifdef XP_MACOSX
  1005     mContentsScaleFactor = aContentsScaleFactor;
  1006     if (mShContext) {
  1007         // Release the shared context so that it is reallocated
  1008         // with the new size. 
  1009         ::CGContextRelease(mShContext);
  1010         mShContext = nullptr;
  1012     return true;
  1013 #else
  1014     NS_RUNTIMEABORT("ContentsScaleFactorChanged is an OSX-only message");
  1015     return false;
  1016 #endif
  1019 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
  1020 // Create a new window from NPWindow
  1021 bool PluginInstanceChild::CreateWindow(const NPRemoteWindow& aWindow)
  1023     PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
  1024                       FULLFUNCTION,
  1025                       aWindow.window,
  1026                       aWindow.x, aWindow.y,
  1027                       aWindow.width, aWindow.height));
  1029 #if (MOZ_WIDGET_GTK == 2)
  1030     if (mXEmbed) {
  1031         mWindow.window = reinterpret_cast<void*>(aWindow.window);
  1033     else {
  1034         Window browserSocket = (Window)(aWindow.window);
  1035         xt_client_init(&mXtClient, mWsInfo.visual, mWsInfo.colormap, mWsInfo.depth);
  1036         xt_client_create(&mXtClient, browserSocket, mWindow.width, mWindow.height); 
  1037         mWindow.window = (void *)XtWindow(mXtClient.child_widget);
  1039 #else
  1040     mWindow.window = reinterpret_cast<void*>(aWindow.window);
  1041 #endif
  1043     return true;
  1046 // Destroy window
  1047 void PluginInstanceChild::DeleteWindow()
  1049   PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
  1050                     FULLFUNCTION,
  1051                     mWindow.window,
  1052                     mWindow.x, mWindow.y,
  1053                     mWindow.width, mWindow.height));
  1055   if (!mWindow.window)
  1056       return;
  1058 #if (MOZ_WIDGET_GTK == 2)
  1059   if (mXtClient.top_widget) {     
  1060       xt_client_unrealize(&mXtClient);
  1061       xt_client_destroy(&mXtClient); 
  1062       mXtClient.top_widget = nullptr;
  1064 #endif
  1066   // We don't have to keep the plug-in window ID any longer.
  1067   mWindow.window = nullptr;
  1069 #endif
  1071 bool
  1072 PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
  1074     PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
  1075                       FULLFUNCTION,
  1076                       aWindow.window,
  1077                       aWindow.x, aWindow.y,
  1078                       aWindow.width, aWindow.height));
  1079     NS_ASSERTION(!mLayersRendering && !mPendingPluginCall,
  1080                  "Shouldn't be receiving NPP_SetWindow with layer rendering");
  1081     AssertPluginThread();
  1083 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
  1084     NS_ASSERTION(mWsInfo.display, "We should have a valid display!");
  1086     // The minimum info is sent over IPC to allow this
  1087     // code to determine the rest.
  1089     mWindow.x = aWindow.x;
  1090     mWindow.y = aWindow.y;
  1091     mWindow.width = aWindow.width;
  1092     mWindow.height = aWindow.height;
  1093     mWindow.clipRect = aWindow.clipRect;
  1094     mWindow.type = aWindow.type;
  1096     mWsInfo.colormap = aWindow.colormap;
  1097     int depth;
  1098     FindVisualAndDepth(mWsInfo.display, aWindow.visualID,
  1099                        &mWsInfo.visual, &depth);
  1100     mWsInfo.depth = depth;
  1102     if (!mWindow.window && mWindow.type == NPWindowTypeWindow) {
  1103         CreateWindow(aWindow);
  1106 #if (MOZ_WIDGET_GTK == 2)
  1107     if (mXEmbed && gtk_check_version(2,18,7) != nullptr) { // older
  1108         if (aWindow.type == NPWindowTypeWindow) {
  1109             GdkWindow* socket_window = gdk_window_lookup(static_cast<GdkNativeWindow>(aWindow.window));
  1110             if (socket_window) {
  1111                 // A GdkWindow for the socket already exists.  Need to
  1112                 // workaround https://bugzilla.gnome.org/show_bug.cgi?id=607061
  1113                 // See wrap_gtk_plug_embedded in PluginModuleChild.cpp.
  1114                 g_object_set_data(G_OBJECT(socket_window),
  1115                                   "moz-existed-before-set-window",
  1116                                   GUINT_TO_POINTER(1));
  1120         if (aWindow.visualID != None
  1121             && gtk_check_version(2, 12, 10) != nullptr) { // older
  1122             // Workaround for a bug in Gtk+ (prior to 2.12.10) where deleting
  1123             // a foreign GdkColormap will also free the XColormap.
  1124             // http://git.gnome.org/browse/gtk+/log/gdk/x11/gdkcolor-x11.c?id=GTK_2_12_10
  1125             GdkVisual *gdkvisual = gdkx_visual_get(aWindow.visualID);
  1126             GdkColormap *gdkcolor =
  1127                 gdk_x11_colormap_foreign_new(gdkvisual, aWindow.colormap);
  1129             if (g_object_get_data(G_OBJECT(gdkcolor), "moz-have-extra-ref")) {
  1130                 // We already have a ref to keep the object alive.
  1131                 g_object_unref(gdkcolor);
  1132             } else {
  1133                 // leak and mark as already leaked
  1134                 g_object_set_data(G_OBJECT(gdkcolor),
  1135                                   "moz-have-extra-ref", GUINT_TO_POINTER(1));
  1139 #endif
  1141     PLUGIN_LOG_DEBUG(
  1142         ("[InstanceChild][%p] Answer_SetWindow w=<x=%d,y=%d, w=%d,h=%d>, clip=<l=%d,t=%d,r=%d,b=%d>",
  1143          this, mWindow.x, mWindow.y, mWindow.width, mWindow.height,
  1144          mWindow.clipRect.left, mWindow.clipRect.top, mWindow.clipRect.right, mWindow.clipRect.bottom));
  1146     if (mPluginIface->setwindow)
  1147         (void) mPluginIface->setwindow(&mData, &mWindow);
  1149 #elif defined(OS_WIN)
  1150     switch (aWindow.type) {
  1151       case NPWindowTypeWindow:
  1153           if ((GetQuirks() & PluginModuleChild::QUIRK_QUICKTIME_AVOID_SETWINDOW) &&
  1154               aWindow.width == 0 &&
  1155               aWindow.height == 0) {
  1156             // Skip SetWindow call for hidden QuickTime plugins
  1157             return true;
  1160           if (!CreatePluginWindow())
  1161               return false;
  1163           ReparentPluginWindow(reinterpret_cast<HWND>(aWindow.window));
  1164           SizePluginWindow(aWindow.width, aWindow.height);
  1166           mWindow.window = (void*)mPluginWindowHWND;
  1167           mWindow.x = aWindow.x;
  1168           mWindow.y = aWindow.y;
  1169           mWindow.width = aWindow.width;
  1170           mWindow.height = aWindow.height;
  1171           mWindow.type = aWindow.type;
  1173           if (mPluginIface->setwindow) {
  1174               SetProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty, (HANDLE)1);
  1175               (void) mPluginIface->setwindow(&mData, &mWindow);
  1176               WNDPROC wndProc = reinterpret_cast<WNDPROC>(
  1177                   GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC));
  1178               if (wndProc != PluginWindowProc) {
  1179                   mPluginWndProc = reinterpret_cast<WNDPROC>(
  1180                       SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC,
  1181                                        reinterpret_cast<LONG_PTR>(PluginWindowProc)));
  1182                   NS_ASSERTION(mPluginWndProc != PluginWindowProc, "WTF?");
  1184               RemoveProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty);
  1185               HookSetWindowLongPtr();
  1188       break;
  1190       case NPWindowTypeDrawable:
  1191           mWindow.type = aWindow.type;
  1192           if (GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK)
  1193               CreateWinlessPopupSurrogate();
  1194           if (GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)
  1195               SetupFlashMsgThrottle();
  1196           return SharedSurfaceSetWindow(aWindow);
  1197       break;
  1199       default:
  1200           NS_NOTREACHED("Bad plugin window type.");
  1201           return false;
  1202       break;
  1205 #elif defined(XP_MACOSX)
  1207     mWindow.x = aWindow.x;
  1208     mWindow.y = aWindow.y;
  1209     mWindow.width = aWindow.width;
  1210     mWindow.height = aWindow.height;
  1211     mWindow.clipRect = aWindow.clipRect;
  1212     mWindow.type = aWindow.type;
  1213     mContentsScaleFactor = aWindow.contentsScaleFactor;
  1215     if (mShContext) {
  1216         // Release the shared context so that it is reallocated
  1217         // with the new size. 
  1218         ::CGContextRelease(mShContext);
  1219         mShContext = nullptr;
  1222     if (mPluginIface->setwindow)
  1223         (void) mPluginIface->setwindow(&mData, &mWindow);
  1225 #elif defined(ANDROID)
  1226     // TODO: Need Android impl
  1227 #elif defined(MOZ_WIDGET_QT)
  1228     // TODO: Need QT-nonX impl
  1229 #else
  1230 #  error Implement me for your OS
  1231 #endif
  1233     return true;
  1236 bool
  1237 PluginInstanceChild::Initialize()
  1239 #if (MOZ_WIDGET_GTK == 2)
  1240     NPError rv;
  1242     if (mWsInfo.display) {
  1243         // Already initialized
  1244         return false;
  1247     // Request for windowless plugins is set in newp(), before this call.
  1248     if (mWindow.type == NPWindowTypeWindow) {
  1249         AnswerNPP_GetValue_NPPVpluginNeedsXEmbed(&mXEmbed, &rv);
  1251         // Set up Xt loop for windowed plugins without XEmbed support
  1252         if (!mXEmbed) {
  1253            xt_client_xloop_create();
  1257     // Use default GTK display for XEmbed and windowless plugins
  1258     if (mXEmbed || mWindow.type != NPWindowTypeWindow) {
  1259         mWsInfo.display = DefaultXDisplay();
  1261     else {
  1262         mWsInfo.display = xt_client_get_display();
  1264 #endif 
  1266     return true;
  1269 #if defined(OS_WIN)
  1271 static const TCHAR kWindowClassName[] = TEXT("GeckoPluginWindow");
  1272 static const TCHAR kPluginInstanceChildProperty[] = TEXT("PluginInstanceChildProperty");
  1273 static const TCHAR kFlashThrottleProperty[] = TEXT("MozillaFlashThrottleProperty");
  1275 // static
  1276 bool
  1277 PluginInstanceChild::RegisterWindowClass()
  1279     static bool alreadyRegistered = false;
  1280     if (alreadyRegistered)
  1281         return true;
  1283     alreadyRegistered = true;
  1285     WNDCLASSEX wcex;
  1286     wcex.cbSize         = sizeof(WNDCLASSEX);
  1287     wcex.style          = CS_DBLCLKS;
  1288     wcex.lpfnWndProc    = DummyWindowProc;
  1289     wcex.cbClsExtra     = 0;
  1290     wcex.cbWndExtra     = 0;
  1291     wcex.hInstance      = GetModuleHandle(nullptr);
  1292     wcex.hIcon          = 0;
  1293     wcex.hCursor        = 0;
  1294     wcex.hbrBackground  = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
  1295     wcex.lpszMenuName   = 0;
  1296     wcex.lpszClassName  = kWindowClassName;
  1297     wcex.hIconSm        = 0;
  1299     return RegisterClassEx(&wcex) ? true : false;
  1302 bool
  1303 PluginInstanceChild::CreatePluginWindow()
  1305     // already initialized
  1306     if (mPluginWindowHWND)
  1307         return true;
  1309     if (!RegisterWindowClass())
  1310         return false;
  1312     mPluginWindowHWND =
  1313         CreateWindowEx(WS_EX_LEFT | WS_EX_LTRREADING |
  1314                        WS_EX_NOPARENTNOTIFY | // XXXbent Get rid of this!
  1315                        WS_EX_RIGHTSCROLLBAR,
  1316                        kWindowClassName, 0,
  1317                        WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0,
  1318                        0, 0, nullptr, 0, GetModuleHandle(nullptr), 0);
  1319     if (!mPluginWindowHWND)
  1320         return false;
  1321     if (!SetProp(mPluginWindowHWND, kPluginInstanceChildProperty, this))
  1322         return false;
  1324     // Apparently some plugins require an ASCII WndProc.
  1325     SetWindowLongPtrA(mPluginWindowHWND, GWLP_WNDPROC,
  1326                       reinterpret_cast<LONG_PTR>(DefWindowProcA));
  1328     return true;
  1331 void
  1332 PluginInstanceChild::DestroyPluginWindow()
  1334     if (mPluginWindowHWND) {
  1335         // Unsubclass the window.
  1336         WNDPROC wndProc = reinterpret_cast<WNDPROC>(
  1337             GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC));
  1338         // Removed prior to SetWindowLongPtr, see HookSetWindowLongPtr.
  1339         RemoveProp(mPluginWindowHWND, kPluginInstanceChildProperty);
  1340         if (wndProc == PluginWindowProc) {
  1341             NS_ASSERTION(mPluginWndProc, "Should have old proc here!");
  1342             SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC,
  1343                              reinterpret_cast<LONG_PTR>(mPluginWndProc));
  1344             mPluginWndProc = 0;
  1346         DestroyWindow(mPluginWindowHWND);
  1347         mPluginWindowHWND = 0;
  1351 void
  1352 PluginInstanceChild::ReparentPluginWindow(HWND hWndParent)
  1354     if (hWndParent != mPluginParentHWND && IsWindow(hWndParent)) {
  1355         // Fix the child window's style to be a child window.
  1356         LONG_PTR style = GetWindowLongPtr(mPluginWindowHWND, GWL_STYLE);
  1357         style |= WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
  1358         style &= ~WS_POPUP;
  1359         SetWindowLongPtr(mPluginWindowHWND, GWL_STYLE, style);
  1361         // Do the reparenting.
  1362         SetParent(mPluginWindowHWND, hWndParent);
  1364         // Make sure we're visible.
  1365         ShowWindow(mPluginWindowHWND, SW_SHOWNA);
  1367     mPluginParentHWND = hWndParent;
  1370 void
  1371 PluginInstanceChild::SizePluginWindow(int width,
  1372                                       int height)
  1374     if (mPluginWindowHWND) {
  1375         mPluginSize.x = width;
  1376         mPluginSize.y = height;
  1377         SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, width, height,
  1378                      SWP_NOZORDER | SWP_NOREPOSITION);
  1382 // See chromium's webplugin_delegate_impl.cc for explanation of this function.
  1383 // static
  1384 LRESULT CALLBACK
  1385 PluginInstanceChild::DummyWindowProc(HWND hWnd,
  1386                                      UINT message,
  1387                                      WPARAM wParam,
  1388                                      LPARAM lParam)
  1390     return CallWindowProc(DefWindowProc, hWnd, message, wParam, lParam);
  1393 // static
  1394 LRESULT CALLBACK
  1395 PluginInstanceChild::PluginWindowProc(HWND hWnd,
  1396                                       UINT message,
  1397                                       WPARAM wParam,
  1398                                       LPARAM lParam)
  1400   return mozilla::CallWindowProcCrashProtected(PluginWindowProcInternal, hWnd, message, wParam, lParam);
  1403 // static
  1404 LRESULT CALLBACK
  1405 PluginInstanceChild::PluginWindowProcInternal(HWND hWnd,
  1406                                               UINT message,
  1407                                               WPARAM wParam,
  1408                                               LPARAM lParam)
  1410     NS_ASSERTION(!mozilla::ipc::MessageChannel::IsPumpingMessages(),
  1411                  "Failed to prevent a nonqueued message from running!");
  1412     PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(
  1413         GetProp(hWnd, kPluginInstanceChildProperty));
  1414     if (!self) {
  1415         NS_NOTREACHED("Badness!");
  1416         return 0;
  1419     NS_ASSERTION(self->mPluginWindowHWND == hWnd, "Wrong window!");
  1420     NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, "Self-referential windowproc. Infinite recursion will happen soon.");
  1422     // Adobe's shockwave positions the plugin window relative to the browser
  1423     // frame when it initializes. With oopp disabled, this wouldn't have an
  1424     // effect. With oopp, GeckoPluginWindow is a child of the parent plugin
  1425     // window, so the move offsets the child within the parent. Generally
  1426     // we don't want plugins moving or sizing our window, so we prevent these
  1427     // changes here.
  1428     if (message == WM_WINDOWPOSCHANGING) {
  1429       WINDOWPOS* pos = reinterpret_cast<WINDOWPOS*>(lParam);
  1430       if (pos && (!(pos->flags & SWP_NOMOVE) || !(pos->flags & SWP_NOSIZE))) {
  1431         pos->x = pos->y = 0;
  1432         pos->cx = self->mPluginSize.x;
  1433         pos->cy = self->mPluginSize.y;
  1434         LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
  1435                                      lParam);
  1436         pos->x = pos->y = 0;
  1437         pos->cx = self->mPluginSize.x;
  1438         pos->cy = self->mPluginSize.y;
  1439         return res;
  1443     // The plugin received keyboard focus, let the parent know so the dom is up to date.
  1444     if (message == WM_MOUSEACTIVATE)
  1445       self->CallPluginFocusChange(true);
  1447     // Prevent lockups due to plugins making rpc calls when the parent
  1448     // is making a synchronous SendMessage call to the child window. Add
  1449     // more messages as needed.
  1450     if ((InSendMessageEx(nullptr)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
  1451         switch(message) {
  1452             case WM_KILLFOCUS:
  1453             ReplyMessage(0);
  1454             break;
  1458     if (message == WM_KILLFOCUS)
  1459       self->CallPluginFocusChange(false);
  1461     if (message == WM_USER+1 &&
  1462         (self->GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)) {
  1463         self->FlashThrottleMessage(hWnd, message, wParam, lParam, true);
  1464         return 0;
  1467     NS_ASSERTION(self->mPluginWndProc != PluginWindowProc,
  1468       "Self-referential windowproc happened inside our hook proc. "
  1469       "Infinite recursion will happen soon.");
  1471     LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
  1472                                  lParam);
  1474     // Make sure capture is released by the child on mouse events. Fixes a
  1475     // problem with flash full screen mode mouse input. Appears to be
  1476     // caused by a bug in flash, since we are not setting the capture
  1477     // on the window.
  1478     if (message == WM_LBUTTONDOWN &&
  1479         self->GetQuirks() & PluginModuleChild::QUIRK_FLASH_FIXUP_MOUSE_CAPTURE) {
  1480       wchar_t szClass[26];
  1481       HWND hwnd = GetForegroundWindow();
  1482       if (hwnd && GetClassNameW(hwnd, szClass,
  1483                                 sizeof(szClass)/sizeof(char16_t)) &&
  1484           !wcscmp(szClass, kFlashFullscreenClass)) {
  1485         ReleaseCapture();
  1486         SetFocus(hwnd);
  1490     if (message == WM_CLOSE)
  1491         self->DestroyPluginWindow();
  1493     if (message == WM_NCDESTROY)
  1494         RemoveProp(hWnd, kPluginInstanceChildProperty);
  1496     return res;
  1499 /* set window long ptr hook for flash */
  1501 /*
  1502  * Flash will reset the subclass of our widget at various times.
  1503  * (Notably when entering and exiting full screen mode.) This
  1504  * occurs independent of the main plugin window event procedure.
  1505  * We trap these subclass calls to prevent our subclass hook from
  1506  * getting dropped.
  1507  * Note, ascii versions can be nixed once flash versions < 10.1
  1508  * are considered obsolete.
  1509  */
  1511 #ifdef _WIN64
  1512 typedef LONG_PTR
  1513   (WINAPI *User32SetWindowLongPtrA)(HWND hWnd,
  1514                                     int nIndex,
  1515                                     LONG_PTR dwNewLong);
  1516 typedef LONG_PTR
  1517   (WINAPI *User32SetWindowLongPtrW)(HWND hWnd,
  1518                                     int nIndex,
  1519                                     LONG_PTR dwNewLong);
  1520 static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr;
  1521 static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr;
  1522 #else
  1523 typedef LONG
  1524 (WINAPI *User32SetWindowLongA)(HWND hWnd,
  1525                                int nIndex,
  1526                                LONG dwNewLong);
  1527 typedef LONG
  1528 (WINAPI *User32SetWindowLongW)(HWND hWnd,
  1529                                int nIndex,
  1530                                LONG dwNewLong);
  1531 static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr;
  1532 static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr;
  1533 #endif
  1535 extern LRESULT CALLBACK
  1536 NeuteredWindowProc(HWND hwnd,
  1537                    UINT uMsg,
  1538                    WPARAM wParam,
  1539                    LPARAM lParam);
  1541 const wchar_t kOldWndProcProp[] = L"MozillaIPCOldWndProc";
  1543 // static
  1544 bool
  1545 PluginInstanceChild::SetWindowLongHookCheck(HWND hWnd,
  1546                                             int nIndex,
  1547                                             LONG_PTR newLong)
  1549       // Let this go through if it's not a subclass
  1550   if (nIndex != GWLP_WNDPROC ||
  1551       // if it's not a subclassed plugin window
  1552       !GetProp(hWnd, kPluginInstanceChildProperty) ||
  1553       // if we're not disabled
  1554       GetProp(hWnd, kPluginIgnoreSubclassProperty) ||
  1555       // if the subclass is set to a known procedure
  1556       newLong == reinterpret_cast<LONG_PTR>(PluginWindowProc) ||
  1557       newLong == reinterpret_cast<LONG_PTR>(NeuteredWindowProc) ||
  1558       newLong == reinterpret_cast<LONG_PTR>(DefWindowProcA) ||
  1559       newLong == reinterpret_cast<LONG_PTR>(DefWindowProcW) ||
  1560       // if the subclass is a WindowsMessageLoop subclass restore
  1561       GetProp(hWnd, kOldWndProcProp))
  1562       return true;
  1563   // prevent the subclass
  1564   return false;
  1567 #ifdef _WIN64
  1568 LONG_PTR WINAPI
  1569 PluginInstanceChild::SetWindowLongPtrAHook(HWND hWnd,
  1570                                            int nIndex,
  1571                                            LONG_PTR newLong)
  1572 #else
  1573 LONG WINAPI
  1574 PluginInstanceChild::SetWindowLongAHook(HWND hWnd,
  1575                                         int nIndex,
  1576                                         LONG newLong)
  1577 #endif
  1579     if (SetWindowLongHookCheck(hWnd, nIndex, newLong))
  1580         return sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong);
  1582     // Set flash's new subclass to get the result. 
  1583     LONG_PTR proc = sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong);
  1585     // We already checked this in SetWindowLongHookCheck
  1586     PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(
  1587         GetProp(hWnd, kPluginInstanceChildProperty));
  1589     // Hook our subclass back up, just like we do on setwindow.   
  1590     WNDPROC currentProc =
  1591         reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWLP_WNDPROC));
  1592     if (currentProc != PluginWindowProc) {
  1593         self->mPluginWndProc =
  1594             reinterpret_cast<WNDPROC>(sUser32SetWindowLongWHookStub(hWnd, nIndex,
  1595                 reinterpret_cast<LONG_PTR>(PluginWindowProc)));
  1596         NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, "Infinite recursion coming up!");
  1598     return proc;
  1601 #ifdef _WIN64
  1602 LONG_PTR WINAPI
  1603 PluginInstanceChild::SetWindowLongPtrWHook(HWND hWnd,
  1604                                            int nIndex,
  1605                                            LONG_PTR newLong)
  1606 #else
  1607 LONG WINAPI
  1608 PluginInstanceChild::SetWindowLongWHook(HWND hWnd,
  1609                                         int nIndex,
  1610                                         LONG newLong)
  1611 #endif
  1613     if (SetWindowLongHookCheck(hWnd, nIndex, newLong))
  1614         return sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong);
  1616     // Set flash's new subclass to get the result. 
  1617     LONG_PTR proc = sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong);
  1619     // We already checked this in SetWindowLongHookCheck
  1620     PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(
  1621         GetProp(hWnd, kPluginInstanceChildProperty));
  1623     // Hook our subclass back up, just like we do on setwindow.   
  1624     WNDPROC currentProc =
  1625         reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWLP_WNDPROC));
  1626     if (currentProc != PluginWindowProc) {
  1627         self->mPluginWndProc =
  1628             reinterpret_cast<WNDPROC>(sUser32SetWindowLongWHookStub(hWnd, nIndex,
  1629                 reinterpret_cast<LONG_PTR>(PluginWindowProc)));
  1630         NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, "Infinite recursion coming up!");
  1632     return proc;
  1635 void
  1636 PluginInstanceChild::HookSetWindowLongPtr()
  1638     if (!(GetQuirks() & PluginModuleChild::QUIRK_FLASH_HOOK_SETLONGPTR))
  1639         return;
  1641     sUser32Intercept.Init("user32.dll");
  1642 #ifdef _WIN64
  1643     if (!sUser32SetWindowLongAHookStub)
  1644         sUser32Intercept.AddHook("SetWindowLongPtrA", reinterpret_cast<intptr_t>(SetWindowLongPtrAHook),
  1645                                  (void**) &sUser32SetWindowLongAHookStub);
  1646     if (!sUser32SetWindowLongWHookStub)
  1647         sUser32Intercept.AddHook("SetWindowLongPtrW", reinterpret_cast<intptr_t>(SetWindowLongPtrWHook),
  1648                                  (void**) &sUser32SetWindowLongWHookStub);
  1649 #else
  1650     if (!sUser32SetWindowLongAHookStub)
  1651         sUser32Intercept.AddHook("SetWindowLongA", reinterpret_cast<intptr_t>(SetWindowLongAHook),
  1652                                  (void**) &sUser32SetWindowLongAHookStub);
  1653     if (!sUser32SetWindowLongWHookStub)
  1654         sUser32Intercept.AddHook("SetWindowLongW", reinterpret_cast<intptr_t>(SetWindowLongWHook),
  1655                                  (void**) &sUser32SetWindowLongWHookStub);
  1656 #endif
  1659 /* windowless track popup menu helpers */
  1661 BOOL
  1662 WINAPI
  1663 PluginInstanceChild::TrackPopupHookProc(HMENU hMenu,
  1664                                         UINT uFlags,
  1665                                         int x,
  1666                                         int y,
  1667                                         int nReserved,
  1668                                         HWND hWnd,
  1669                                         CONST RECT *prcRect)
  1671   if (!sUser32TrackPopupMenuStub) {
  1672       NS_ERROR("TrackPopupMenu stub isn't set! Badness!");
  1673       return 0;
  1676   // Only change the parent when we know this is a context on the plugin
  1677   // surface within the browser. Prevents resetting the parent on child ui
  1678   // displayed by plugins that have working parent-child relationships.
  1679   wchar_t szClass[21];
  1680   bool haveClass = GetClassNameW(hWnd, szClass, ArrayLength(szClass));
  1681   if (!haveClass || 
  1682       (wcscmp(szClass, L"MozillaWindowClass") &&
  1683        wcscmp(szClass, L"SWFlash_Placeholder"))) {
  1684       // Unrecognized parent
  1685       return sUser32TrackPopupMenuStub(hMenu, uFlags, x, y, nReserved,
  1686                                        hWnd, prcRect);
  1689   // Called on an unexpected event, warn.
  1690   if (!sWinlessPopupSurrogateHWND) {
  1691       NS_WARNING(
  1692           "Untraced TrackPopupHookProc call! Menu might not work right!");
  1693       return sUser32TrackPopupMenuStub(hMenu, uFlags, x, y, nReserved,
  1694                                        hWnd, prcRect);
  1697   HWND surrogateHwnd = sWinlessPopupSurrogateHWND;
  1698   sWinlessPopupSurrogateHWND = nullptr;
  1700   // Popups that don't use TPM_RETURNCMD expect a final command message
  1701   // when an item is selected and the context closes. Since we replace
  1702   // the parent, we need to forward this back to the real parent so it
  1703   // can act on the menu item selected.
  1704   bool isRetCmdCall = (uFlags & TPM_RETURNCMD);
  1706   DWORD res = sUser32TrackPopupMenuStub(hMenu, uFlags|TPM_RETURNCMD, x, y,
  1707                                         nReserved, surrogateHwnd, prcRect);
  1709   if (!isRetCmdCall && res) {
  1710       SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(res, 0), 0);
  1713   return res;
  1716 void
  1717 PluginInstanceChild::InitPopupMenuHook()
  1719     if (!(GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) ||
  1720         sUser32TrackPopupMenuStub)
  1721         return;
  1723     // Note, once WindowsDllInterceptor is initialized for a module,
  1724     // it remains initialized for that particular module for it's
  1725     // lifetime. Additional instances are needed if other modules need
  1726     // to be hooked.
  1727     if (!sUser32TrackPopupMenuStub) {
  1728         sUser32Intercept.Init("user32.dll");
  1729         sUser32Intercept.AddHook("TrackPopupMenu", reinterpret_cast<intptr_t>(TrackPopupHookProc),
  1730                                  (void**) &sUser32TrackPopupMenuStub);
  1734 void
  1735 PluginInstanceChild::CreateWinlessPopupSurrogate()
  1737     // already initialized
  1738     if (mWinlessPopupSurrogateHWND)
  1739         return;
  1741     HWND hwnd = nullptr;
  1742     NPError result;
  1743     if (!CallNPN_GetValue_NPNVnetscapeWindow(&hwnd, &result)) {
  1744         NS_ERROR("CallNPN_GetValue_NPNVnetscapeWindow failed.");
  1745         return;
  1748     mWinlessPopupSurrogateHWND =
  1749         CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Static", nullptr, WS_CHILD,
  1750                        0, 0, 0, 0, hwnd, 0, GetModuleHandle(nullptr), 0);
  1751     if (!mWinlessPopupSurrogateHWND) {
  1752         NS_ERROR("CreateWindowEx failed for winless placeholder!");
  1753         return;
  1755     return;
  1758 void
  1759 PluginInstanceChild::DestroyWinlessPopupSurrogate()
  1761     if (mWinlessPopupSurrogateHWND)
  1762         DestroyWindow(mWinlessPopupSurrogateHWND);
  1763     mWinlessPopupSurrogateHWND = nullptr;
  1766 int16_t
  1767 PluginInstanceChild::WinlessHandleEvent(NPEvent& event)
  1769     if (!mPluginIface->event)
  1770         return false;
  1772     // Events that might generate nested event dispatch loops need
  1773     // special handling during delivery.
  1774     int16_t handled;
  1776     HWND focusHwnd = nullptr;
  1778     // TrackPopupMenu will fail if the parent window is not associated with
  1779     // our ui thread. So we hook TrackPopupMenu so we can hand in a surrogate
  1780     // parent created in the child process.
  1781     if ((GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) && // XXX turn on by default?
  1782           (event.event == WM_RBUTTONDOWN || // flash
  1783            event.event == WM_RBUTTONUP)) {  // silverlight
  1784       sWinlessPopupSurrogateHWND = mWinlessPopupSurrogateHWND;
  1786       // A little trick scrounged from chromium's code - set the focus
  1787       // to our surrogate parent so keyboard nav events go to the menu. 
  1788       focusHwnd = SetFocus(mWinlessPopupSurrogateHWND);
  1791     MessageLoop* loop = MessageLoop::current();
  1792     AutoRestore<bool> modalLoop(loop->os_modal_loop());
  1794     handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&event));
  1796     sWinlessPopupSurrogateHWND = nullptr;
  1798     if (IsWindow(focusHwnd)) {
  1799       SetFocus(focusHwnd);
  1802     return handled;
  1805 /* windowless drawing helpers */
  1807 bool
  1808 PluginInstanceChild::SharedSurfaceSetWindow(const NPRemoteWindow& aWindow)
  1810     // If the surfaceHandle is empty, parent is telling us we can reuse our cached
  1811     // memory surface and hdc. Otherwise, we need to reset, usually due to a
  1812     // expanding plugin port size.
  1813     if (!aWindow.surfaceHandle) {
  1814         if (!mSharedSurfaceDib.IsValid()) {
  1815             return false;
  1818     else {
  1819         // Attach to the new shared surface parent handed us.
  1820         if (NS_FAILED(mSharedSurfaceDib.Attach((SharedDIB::Handle)aWindow.surfaceHandle,
  1821                                                aWindow.width, aWindow.height, false)))
  1822           return false;
  1823         // Free any alpha extraction resources if needed. This will be reset
  1824         // the next time it's used.
  1825         AlphaExtractCacheRelease();
  1828     // NPRemoteWindow's origin is the origin of our shared dib.
  1829     mWindow.x      = aWindow.x;
  1830     mWindow.y      = aWindow.y;
  1831     mWindow.width  = aWindow.width;
  1832     mWindow.height = aWindow.height;
  1833     mWindow.type   = aWindow.type;
  1835     mWindow.window = reinterpret_cast<void*>(mSharedSurfaceDib.GetHDC());
  1836     ::SetViewportOrgEx(mSharedSurfaceDib.GetHDC(),
  1837                        -aWindow.x, -aWindow.y, nullptr);
  1839     if (mPluginIface->setwindow)
  1840         mPluginIface->setwindow(&mData, &mWindow);
  1842     return true;
  1845 void
  1846 PluginInstanceChild::SharedSurfaceRelease()
  1848     mSharedSurfaceDib.Close();
  1849     AlphaExtractCacheRelease();
  1852 /* double pass cache buffer - (rarely) used in cases where alpha extraction
  1853  * occurs for windowless plugins. */
  1855 bool
  1856 PluginInstanceChild::AlphaExtractCacheSetup()
  1858     AlphaExtractCacheRelease();
  1860     mAlphaExtract.hdc = ::CreateCompatibleDC(nullptr);
  1862     if (!mAlphaExtract.hdc)
  1863         return false;
  1865     BITMAPINFOHEADER bmih;
  1866     memset((void*)&bmih, 0, sizeof(BITMAPINFOHEADER));
  1867     bmih.biSize        = sizeof(BITMAPINFOHEADER);
  1868     bmih.biWidth       = mWindow.width;
  1869     bmih.biHeight      = mWindow.height;
  1870     bmih.biPlanes      = 1;
  1871     bmih.biBitCount    = 32;
  1872     bmih.biCompression = BI_RGB;
  1874     void* ppvBits = nullptr;
  1875     mAlphaExtract.bmp = ::CreateDIBSection(mAlphaExtract.hdc,
  1876                                            (BITMAPINFO*)&bmih,
  1877                                            DIB_RGB_COLORS,
  1878                                            (void**)&ppvBits,
  1879                                            nullptr,
  1880                                            (unsigned long)sizeof(BITMAPINFOHEADER));
  1881     if (!mAlphaExtract.bmp)
  1882       return false;
  1884     DeleteObject(::SelectObject(mAlphaExtract.hdc, mAlphaExtract.bmp));
  1885     return true;
  1888 void
  1889 PluginInstanceChild::AlphaExtractCacheRelease()
  1891     if (mAlphaExtract.bmp)
  1892         ::DeleteObject(mAlphaExtract.bmp);
  1894     if (mAlphaExtract.hdc)
  1895         ::DeleteObject(mAlphaExtract.hdc);
  1897     mAlphaExtract.bmp = nullptr;
  1898     mAlphaExtract.hdc = nullptr;
  1901 void
  1902 PluginInstanceChild::UpdatePaintClipRect(RECT* aRect)
  1904     if (aRect) {
  1905         // Update the clip rect on our internal hdc
  1906         HRGN clip = ::CreateRectRgnIndirect(aRect);
  1907         ::SelectClipRgn(mSharedSurfaceDib.GetHDC(), clip);
  1908         ::DeleteObject(clip);
  1912 int16_t
  1913 PluginInstanceChild::SharedSurfacePaint(NPEvent& evcopy)
  1915     if (!mPluginIface->event)
  1916         return false;
  1918     RECT* pRect = reinterpret_cast<RECT*>(evcopy.lParam);
  1920     switch(mAlphaExtract.doublePass) {
  1921         case RENDER_NATIVE:
  1922             // pass the internal hdc to the plugin
  1923             UpdatePaintClipRect(pRect);
  1924             evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC());
  1925             return mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
  1926         break;
  1927         case RENDER_BACK_ONE:
  1928               // Handle a double pass render used in alpha extraction for transparent
  1929               // plugins. (See nsObjectFrame and gfxWindowsNativeDrawing for details.)
  1930               // We render twice, once to the shared dib, and once to a cache which
  1931               // we copy back on a second paint. These paints can't be spread across
  1932               // multiple rpc messages as delays cause animation frame changes.
  1933               if (!mAlphaExtract.bmp && !AlphaExtractCacheSetup()) {
  1934                   mAlphaExtract.doublePass = RENDER_NATIVE;
  1935                   return false;
  1938               // See gfxWindowsNativeDrawing, color order doesn't have to match.
  1939               UpdatePaintClipRect(pRect);
  1940               ::FillRect(mSharedSurfaceDib.GetHDC(), pRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
  1941               evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC());
  1942               if (!mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy))) {
  1943                   mAlphaExtract.doublePass = RENDER_NATIVE;
  1944                   return false;
  1947               // Copy to cache. We render to shared dib so we don't have to call
  1948               // setwindow between calls (flash issue).  
  1949               ::BitBlt(mAlphaExtract.hdc,
  1950                        pRect->left,
  1951                        pRect->top,
  1952                        pRect->right - pRect->left,
  1953                        pRect->bottom - pRect->top,
  1954                        mSharedSurfaceDib.GetHDC(),
  1955                        pRect->left,
  1956                        pRect->top,
  1957                        SRCCOPY);
  1959               ::FillRect(mSharedSurfaceDib.GetHDC(), pRect, (HBRUSH)GetStockObject(BLACK_BRUSH));
  1960               if (!mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy))) {
  1961                   mAlphaExtract.doublePass = RENDER_NATIVE;
  1962                   return false;
  1964               mAlphaExtract.doublePass = RENDER_BACK_TWO;
  1965               return true;
  1966         break;
  1967         case RENDER_BACK_TWO:
  1968               // copy our cached surface back
  1969               UpdatePaintClipRect(pRect);
  1970               ::BitBlt(mSharedSurfaceDib.GetHDC(),
  1971                        pRect->left,
  1972                        pRect->top,
  1973                        pRect->right - pRect->left,
  1974                        pRect->bottom - pRect->top,
  1975                        mAlphaExtract.hdc,
  1976                        pRect->left,
  1977                        pRect->top,
  1978                        SRCCOPY);
  1979               mAlphaExtract.doublePass = RENDER_NATIVE;
  1980               return true;
  1981         break;
  1983     return false;
  1986 /* flash msg throttling helpers */
  1988 // Flash has the unfortunate habit of flooding dispatch loops with custom
  1989 // windowing events they use for timing. We throttle these by dropping the
  1990 // delivery priority below any other event, including pending ipc io
  1991 // notifications. We do this for both windowed and windowless controls.
  1992 // Note flash's windowless msg window can last longer than our instance,
  1993 // so we try to unhook when the window is destroyed and in NPP_Destroy.
  1995 void
  1996 PluginInstanceChild::UnhookWinlessFlashThrottle()
  1998   // We may have already unhooked
  1999   if (!mWinlessThrottleOldWndProc)
  2000       return;
  2002   WNDPROC tmpProc = mWinlessThrottleOldWndProc;
  2003   mWinlessThrottleOldWndProc = nullptr;
  2005   NS_ASSERTION(mWinlessHiddenMsgHWND,
  2006                "Missing mWinlessHiddenMsgHWND w/subclass set??");
  2008   // reset the subclass
  2009   SetWindowLongPtr(mWinlessHiddenMsgHWND, GWLP_WNDPROC,
  2010                    reinterpret_cast<LONG_PTR>(tmpProc));
  2012   // Remove our instance prop
  2013   RemoveProp(mWinlessHiddenMsgHWND, kFlashThrottleProperty);
  2014   mWinlessHiddenMsgHWND = nullptr;
  2017 // static
  2018 LRESULT CALLBACK
  2019 PluginInstanceChild::WinlessHiddenFlashWndProc(HWND hWnd,
  2020                                                UINT message,
  2021                                                WPARAM wParam,
  2022                                                LPARAM lParam)
  2024     PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(
  2025         GetProp(hWnd, kFlashThrottleProperty));
  2026     if (!self) {
  2027         NS_NOTREACHED("Badness!");
  2028         return 0;
  2031     NS_ASSERTION(self->mWinlessThrottleOldWndProc,
  2032                  "Missing subclass procedure!!");
  2034     // Throttle
  2035     if (message == WM_USER+1) {
  2036         self->FlashThrottleMessage(hWnd, message, wParam, lParam, false);
  2037         return 0;
  2040     // Unhook
  2041     if (message == WM_CLOSE || message == WM_NCDESTROY) {
  2042         WNDPROC tmpProc = self->mWinlessThrottleOldWndProc;
  2043         self->UnhookWinlessFlashThrottle();
  2044         LRESULT res = CallWindowProc(tmpProc, hWnd, message, wParam, lParam);
  2045         return res;
  2048     return CallWindowProc(self->mWinlessThrottleOldWndProc,
  2049                           hWnd, message, wParam, lParam);
  2052 // Enumerate all thread windows looking for flash's hidden message window.
  2053 // Once we find it, sub class it so we can throttle user msgs.  
  2054 // static
  2055 BOOL CALLBACK
  2056 PluginInstanceChild::EnumThreadWindowsCallback(HWND hWnd,
  2057                                                LPARAM aParam)
  2059     PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(aParam);
  2060     if (!self) {
  2061         NS_NOTREACHED("Enum befuddled!");
  2062         return FALSE;
  2065     wchar_t className[64];
  2066     if (!GetClassNameW(hWnd, className, sizeof(className)/sizeof(char16_t)))
  2067       return TRUE;
  2069     if (!wcscmp(className, L"SWFlash_PlaceholderX")) {
  2070         WNDPROC oldWndProc =
  2071             reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWLP_WNDPROC));
  2072         // Only set this if we haven't already.
  2073         if (oldWndProc != WinlessHiddenFlashWndProc) {
  2074             if (self->mWinlessThrottleOldWndProc) {
  2075                 NS_WARNING("mWinlessThrottleWndProc already set???");
  2076                 return FALSE;
  2078             // Subsclass and store self as a property
  2079             self->mWinlessHiddenMsgHWND = hWnd;
  2080             self->mWinlessThrottleOldWndProc =
  2081                 reinterpret_cast<WNDPROC>(SetWindowLongPtr(hWnd, GWLP_WNDPROC,
  2082                 reinterpret_cast<LONG_PTR>(WinlessHiddenFlashWndProc)));
  2083             SetProp(hWnd, kFlashThrottleProperty, self);
  2084             NS_ASSERTION(self->mWinlessThrottleOldWndProc,
  2085                          "SetWindowLongPtr failed?!");
  2087         // Return no matter what once we find the right window.
  2088         return FALSE;
  2091     return TRUE;
  2095 void
  2096 PluginInstanceChild::SetupFlashMsgThrottle()
  2098     if (mWindow.type == NPWindowTypeDrawable) {
  2099         // Search for the flash hidden message window and subclass it. Only
  2100         // search for flash windows belonging to our ui thread!
  2101         if (mWinlessThrottleOldWndProc)
  2102             return;
  2103         EnumThreadWindows(GetCurrentThreadId(), EnumThreadWindowsCallback,
  2104                           reinterpret_cast<LPARAM>(this));
  2106     else {
  2107         // Already setup through quirks and the subclass.
  2108         return;
  2112 WNDPROC
  2113 PluginInstanceChild::FlashThrottleAsyncMsg::GetProc()
  2115     if (mInstance) {
  2116         return mWindowed ? mInstance->mPluginWndProc :
  2117                            mInstance->mWinlessThrottleOldWndProc;
  2119     return nullptr;
  2122 void
  2123 PluginInstanceChild::FlashThrottleAsyncMsg::Run()
  2125     RemoveFromAsyncList();
  2127     // GetProc() checks mInstance, and pulls the procedure from
  2128     // PluginInstanceChild. We don't transport sub-class procedure
  2129     // ptrs around in FlashThrottleAsyncMsg msgs.
  2130     if (!GetProc())
  2131         return;
  2133     // deliver the event to flash 
  2134     CallWindowProc(GetProc(), GetWnd(), GetMsg(), GetWParam(), GetLParam());
  2137 void
  2138 PluginInstanceChild::FlashThrottleMessage(HWND aWnd,
  2139                                           UINT aMsg,
  2140                                           WPARAM aWParam,
  2141                                           LPARAM aLParam,
  2142                                           bool isWindowed)
  2144     // We reuse ChildAsyncCall so we get the cancelation work
  2145     // that's done in Destroy.
  2146     FlashThrottleAsyncMsg* task = new FlashThrottleAsyncMsg(this,
  2147         aWnd, aMsg, aWParam, aLParam, isWindowed);
  2148     if (!task)
  2149         return; 
  2152         MutexAutoLock lock(mAsyncCallMutex);
  2153         mPendingAsyncCalls.AppendElement(task);
  2155     MessageLoop::current()->PostDelayedTask(FROM_HERE,
  2156         task, kFlashWMUSERMessageThrottleDelayMs);
  2159 #endif // OS_WIN
  2161 bool
  2162 PluginInstanceChild::AnswerSetPluginFocus()
  2164     PR_LOG(GetPluginLog(), PR_LOG_DEBUG, ("%s", FULLFUNCTION));
  2166 #if defined(OS_WIN)
  2167     // Parent is letting us know the dom set focus to the plugin. Note,
  2168     // focus can change during transit in certain edge cases, for example
  2169     // when a button click brings up a full screen window. Since we send
  2170     // this in response to a WM_SETFOCUS event on our parent, the parent
  2171     // should have focus when we receive this. If not, ignore the call.
  2172     if (::GetFocus() == mPluginWindowHWND ||
  2173         ((GetQuirks() & PluginModuleChild::QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT) &&
  2174          (::GetFocus() != mPluginParentHWND)))
  2175         return true;
  2176     ::SetFocus(mPluginWindowHWND);
  2177     return true;
  2178 #else
  2179     NS_NOTREACHED("PluginInstanceChild::AnswerSetPluginFocus not implemented!");
  2180     return false;
  2181 #endif
  2184 bool
  2185 PluginInstanceChild::AnswerUpdateWindow()
  2187     PR_LOG(GetPluginLog(), PR_LOG_DEBUG, ("%s", FULLFUNCTION));
  2189 #if defined(OS_WIN)
  2190     if (mPluginWindowHWND) {
  2191         RECT rect;
  2192         if (GetUpdateRect(GetParent(mPluginWindowHWND), &rect, FALSE)) {
  2193             ::InvalidateRect(mPluginWindowHWND, &rect, FALSE); 
  2195         UpdateWindow(mPluginWindowHWND);
  2197     return true;
  2198 #else
  2199     NS_NOTREACHED("PluginInstanceChild::AnswerUpdateWindow not implemented!");
  2200     return false;
  2201 #endif
  2204 bool
  2205 PluginInstanceChild::RecvNPP_DidComposite()
  2207   if (mPluginIface->didComposite) {
  2208     mPluginIface->didComposite(GetNPP());
  2210   return true;
  2213 PPluginScriptableObjectChild*
  2214 PluginInstanceChild::AllocPPluginScriptableObjectChild()
  2216     AssertPluginThread();
  2217     return new PluginScriptableObjectChild(Proxy);
  2220 bool
  2221 PluginInstanceChild::DeallocPPluginScriptableObjectChild(
  2222     PPluginScriptableObjectChild* aObject)
  2224     AssertPluginThread();
  2225     delete aObject;
  2226     return true;
  2229 bool
  2230 PluginInstanceChild::RecvPPluginScriptableObjectConstructor(
  2231                                            PPluginScriptableObjectChild* aActor)
  2233     AssertPluginThread();
  2235     // This is only called in response to the parent process requesting the
  2236     // creation of an actor. This actor will represent an NPObject that is
  2237     // created by the browser and returned to the plugin.
  2238     PluginScriptableObjectChild* actor =
  2239         static_cast<PluginScriptableObjectChild*>(aActor);
  2240     NS_ASSERTION(!actor->GetObject(false), "Actor already has an object?!");
  2242     actor->InitializeProxy();
  2243     NS_ASSERTION(actor->GetObject(false), "Actor should have an object!");
  2245     return true;
  2248 bool
  2249 PluginInstanceChild::AnswerPBrowserStreamConstructor(
  2250     PBrowserStreamChild* aActor,
  2251     const nsCString& url,
  2252     const uint32_t& length,
  2253     const uint32_t& lastmodified,
  2254     PStreamNotifyChild* notifyData,
  2255     const nsCString& headers,
  2256     const nsCString& mimeType,
  2257     const bool& seekable,
  2258     NPError* rv,
  2259     uint16_t* stype)
  2261     AssertPluginThread();
  2262     *rv = static_cast<BrowserStreamChild*>(aActor)
  2263           ->StreamConstructed(mimeType, seekable, stype);
  2264     return true;
  2267 PBrowserStreamChild*
  2268 PluginInstanceChild::AllocPBrowserStreamChild(const nsCString& url,
  2269                                               const uint32_t& length,
  2270                                               const uint32_t& lastmodified,
  2271                                               PStreamNotifyChild* notifyData,
  2272                                               const nsCString& headers,
  2273                                               const nsCString& mimeType,
  2274                                               const bool& seekable,
  2275                                               NPError* rv,
  2276                                               uint16_t *stype)
  2278     AssertPluginThread();
  2279     return new BrowserStreamChild(this, url, length, lastmodified,
  2280                                   static_cast<StreamNotifyChild*>(notifyData),
  2281                                   headers, mimeType, seekable, rv, stype);
  2284 bool
  2285 PluginInstanceChild::DeallocPBrowserStreamChild(PBrowserStreamChild* stream)
  2287     AssertPluginThread();
  2288     delete stream;
  2289     return true;
  2292 PPluginStreamChild*
  2293 PluginInstanceChild::AllocPPluginStreamChild(const nsCString& mimeType,
  2294                                              const nsCString& target,
  2295                                              NPError* result)
  2297     NS_RUNTIMEABORT("not callable");
  2298     return nullptr;
  2301 bool
  2302 PluginInstanceChild::DeallocPPluginStreamChild(PPluginStreamChild* stream)
  2304     AssertPluginThread();
  2305     delete stream;
  2306     return true;
  2309 PStreamNotifyChild*
  2310 PluginInstanceChild::AllocPStreamNotifyChild(const nsCString& url,
  2311                                              const nsCString& target,
  2312                                              const bool& post,
  2313                                              const nsCString& buffer,
  2314                                              const bool& file,
  2315                                              NPError* result)
  2317     AssertPluginThread();
  2318     NS_RUNTIMEABORT("not reached");
  2319     return nullptr;
  2322 void
  2323 StreamNotifyChild::ActorDestroy(ActorDestroyReason why)
  2325     if (AncestorDeletion == why && mBrowserStream) {
  2326         NS_ERROR("Pending NPP_URLNotify not called when closing an instance.");
  2328         // reclaim responsibility for deleting ourself
  2329         mBrowserStream->mStreamNotify = nullptr;
  2330         mBrowserStream = nullptr;
  2335 void
  2336 StreamNotifyChild::SetAssociatedStream(BrowserStreamChild* bs)
  2338     NS_ASSERTION(bs, "Shouldn't be null");
  2339     NS_ASSERTION(!mBrowserStream, "Two streams for one streamnotify?");
  2341     mBrowserStream = bs;
  2344 bool
  2345 StreamNotifyChild::Recv__delete__(const NPReason& reason)
  2347     AssertPluginThread();
  2349     if (mBrowserStream)
  2350         mBrowserStream->NotifyPending();
  2351     else
  2352         NPP_URLNotify(reason);
  2354     return true;
  2357 bool
  2358 StreamNotifyChild::RecvRedirectNotify(const nsCString& url, const int32_t& status)
  2360     // NPP_URLRedirectNotify requires a non-null closure. Since core logic
  2361     // assumes that all out-of-process notify streams have non-null closure
  2362     // data it will assume that the plugin was notified at this point and
  2363     // expect a response otherwise the redirect will hang indefinitely.
  2364     if (!mClosure) {
  2365         SendRedirectNotifyResponse(false);
  2368     PluginInstanceChild* instance = static_cast<PluginInstanceChild*>(Manager());
  2369     if (instance->mPluginIface->urlredirectnotify)
  2370       instance->mPluginIface->urlredirectnotify(instance->GetNPP(), url.get(), status, mClosure);
  2372     return true;
  2375 void
  2376 StreamNotifyChild::NPP_URLNotify(NPReason reason)
  2378     PluginInstanceChild* instance = static_cast<PluginInstanceChild*>(Manager());
  2380     if (mClosure)
  2381         instance->mPluginIface->urlnotify(instance->GetNPP(), mURL.get(),
  2382                                           reason, mClosure);
  2385 bool
  2386 PluginInstanceChild::DeallocPStreamNotifyChild(PStreamNotifyChild* notifyData)
  2388     AssertPluginThread();
  2390     if (!static_cast<StreamNotifyChild*>(notifyData)->mBrowserStream)
  2391         delete notifyData;
  2392     return true;
  2395 PluginScriptableObjectChild*
  2396 PluginInstanceChild::GetActorForNPObject(NPObject* aObject)
  2398     AssertPluginThread();
  2399     NS_ASSERTION(aObject, "Null pointer!");
  2401     if (aObject->_class == PluginScriptableObjectChild::GetClass()) {
  2402         // One of ours! It's a browser-provided object.
  2403         ChildNPObject* object = static_cast<ChildNPObject*>(aObject);
  2404         NS_ASSERTION(object->parent, "Null actor!");
  2405         return object->parent;
  2408     PluginScriptableObjectChild* actor =
  2409         PluginModuleChild::current()->GetActorForNPObject(aObject);
  2410     if (actor) {
  2411         // Plugin-provided object that we've previously wrapped.
  2412         return actor;
  2415     actor = new PluginScriptableObjectChild(LocalObject);
  2416     if (!SendPPluginScriptableObjectConstructor(actor)) {
  2417         NS_ERROR("Failed to send constructor message!");
  2418         return nullptr;
  2421     actor->InitializeLocal(aObject);
  2422     return actor;
  2425 NPError
  2426 PluginInstanceChild::NPN_NewStream(NPMIMEType aMIMEType, const char* aWindow,
  2427                                    NPStream** aStream)
  2429     AssertPluginThread();
  2431     PluginStreamChild* ps = new PluginStreamChild();
  2433     NPError result;
  2434     CallPPluginStreamConstructor(ps, nsDependentCString(aMIMEType),
  2435                                  NullableString(aWindow), &result);
  2436     if (NPERR_NO_ERROR != result) {
  2437         *aStream = nullptr;
  2438         PPluginStreamChild::Call__delete__(ps, NPERR_GENERIC_ERROR, true);
  2439         return result;
  2442     *aStream = &ps->mStream;
  2443     return NPERR_NO_ERROR;
  2446 void
  2447 PluginInstanceChild::NPN_URLRedirectResponse(void* notifyData, NPBool allow)
  2449     if (!notifyData) {
  2450         return;
  2453     InfallibleTArray<PStreamNotifyChild*> notifyStreams;
  2454     ManagedPStreamNotifyChild(notifyStreams);
  2455     uint32_t notifyStreamCount = notifyStreams.Length();
  2456     for (uint32_t i = 0; i < notifyStreamCount; i++) {
  2457         StreamNotifyChild* sn = static_cast<StreamNotifyChild*>(notifyStreams[i]);
  2458         if (sn->mClosure == notifyData) {
  2459             sn->SendRedirectNotifyResponse(static_cast<bool>(allow));
  2460             return;
  2463     NS_ASSERTION(false, "Couldn't find stream for redirect response!");
  2466 NPError
  2467 PluginInstanceChild::DeallocateAsyncBitmapSurface(NPAsyncSurface *aSurface)
  2469     AsyncBitmapData* data;
  2471     if (!mAsyncBitmaps.Get(aSurface, &data)) {
  2472         return NPERR_INVALID_PARAM;
  2475     DeallocShmem(data->mShmem);
  2476     aSurface->bitmap.data = nullptr;
  2478     mAsyncBitmaps.Remove(aSurface);
  2479     return NPERR_NO_ERROR;
  2482 bool
  2483 PluginInstanceChild::IsAsyncDrawing()
  2485     return IsDrawingModelAsync(mDrawingModel);
  2488 NPError
  2489 PluginInstanceChild::NPN_InitAsyncSurface(NPSize *size, NPImageFormat format,
  2490                                           void *initData, NPAsyncSurface *surface)
  2492     AssertPluginThread();
  2494     surface->bitmap.data = nullptr;
  2496     if (!IsAsyncDrawing()) {
  2497         return NPERR_GENERIC_ERROR;
  2500     switch (mDrawingModel) {
  2501     case NPDrawingModelAsyncBitmapSurface: {
  2502             if (mAsyncBitmaps.Get(surface, nullptr)) {
  2503                 return NPERR_INVALID_PARAM;
  2506             if (size->width < 0 || size->height < 0) {
  2507                 return NPERR_INVALID_PARAM;
  2511             bool result;
  2512             NPRemoteAsyncSurface remote;
  2514             if (!CallNPN_InitAsyncSurface(gfxIntSize(size->width, size->height), format, &remote, &result) || !result) {
  2515                 return NPERR_OUT_OF_MEMORY_ERROR;
  2518             NS_ABORT_IF_FALSE(remote.data().get_Shmem().IsWritable(),
  2519                 "Failed to create writable shared memory.");
  2521             AsyncBitmapData *data = new AsyncBitmapData;
  2522             mAsyncBitmaps.Put(surface, data);
  2524             data->mRemotePtr = (void*)remote.hostPtr();
  2525             data->mShmem = remote.data().get_Shmem();
  2527             surface->bitmap.data = data->mShmem.get<unsigned char>();
  2528             surface->bitmap.stride = remote.stride();
  2529             surface->format = remote.format();
  2530             surface->size.width = remote.size().width;
  2531             surface->size.height = remote.size().height;
  2533             return NPERR_NO_ERROR;
  2535 #ifdef XP_WIN
  2536     case NPDrawingModelAsyncWindowsDXGISurface: {
  2537             if (size->width < 0 || size->height < 0) {
  2538                 return NPERR_INVALID_PARAM;
  2540             bool result;
  2541             NPRemoteAsyncSurface remote;
  2543             if (!CallNPN_InitAsyncSurface(gfxIntSize(size->width, size->height), format, &remote, &result) || !result) {
  2544                 return NPERR_OUT_OF_MEMORY_ERROR;
  2547             surface->format = remote.format();
  2548             surface->size.width = remote.size().width;
  2549             surface->size.height = remote.size().height;
  2550             surface->sharedHandle = remote.data().get_DXGISharedSurfaceHandle();
  2552             return NPERR_NO_ERROR;
  2554 #endif
  2557     return NPERR_GENERIC_ERROR;
  2560 NPError
  2561 PluginInstanceChild::NPN_FinalizeAsyncSurface(NPAsyncSurface *surface)
  2563     AssertPluginThread();
  2565     if (!IsAsyncDrawing()) {
  2566         return NPERR_GENERIC_ERROR;
  2569     switch (mDrawingModel) {
  2570     case NPDrawingModelAsyncBitmapSurface: {
  2571             AsyncBitmapData *bitmapData;
  2573             if (!mAsyncBitmaps.Get(surface, &bitmapData)) {
  2574                 return NPERR_GENERIC_ERROR;
  2578                 CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
  2579                 RemoteImageData *data = mRemoteImageData;
  2580                 if (data->mBitmap.mData == bitmapData->mRemotePtr) {
  2581                     data->mBitmap.mData = nullptr;
  2582                     data->mSize = IntSize(0, 0);
  2583                     data->mWasUpdated = true;
  2587             return DeallocateAsyncBitmapSurface(surface);
  2589 #ifdef XP_WIN
  2590     case NPDrawingModelAsyncWindowsDXGISurface: {
  2593                 CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
  2594                 RemoteImageData *data = mRemoteImageData;
  2595                 if (data->mTextureHandle == surface->sharedHandle) {
  2596                     data->mTextureHandle = nullptr;
  2597                     data->mSize = IntSize(0, 0);
  2598                     data->mWasUpdated = true;
  2602             SendReleaseDXGISharedSurface(surface->sharedHandle);
  2603             return NPERR_NO_ERROR;
  2605 #endif
  2608     return NPERR_GENERIC_ERROR;
  2611 void
  2612 PluginInstanceChild::NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed)
  2614     if (!IsAsyncDrawing()) {
  2615         return;
  2618     RemoteImageData *data = mRemoteImageData;
  2620     if (!surface) {
  2621         CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
  2622         data->mBitmap.mData = nullptr;
  2623         data->mSize = IntSize(0, 0);
  2624         data->mWasUpdated = true;
  2625     } else {
  2626         switch (mDrawingModel) {
  2627         case NPDrawingModelAsyncBitmapSurface:
  2629                 AsyncBitmapData *bitmapData;
  2631                 if (!mAsyncBitmaps.Get(surface, &bitmapData)) {
  2632                     return;
  2635                 CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
  2636                 data->mBitmap.mData = (unsigned char*)bitmapData->mRemotePtr;
  2637                 data->mSize = IntSize(surface->size.width, surface->size.height);
  2638                 data->mFormat = surface->format == NPImageFormatBGRX32 ?
  2639                                 RemoteImageData::BGRX32 : RemoteImageData::BGRA32;
  2640                 data->mBitmap.mStride = surface->bitmap.stride;
  2641                 data->mWasUpdated = true;
  2642                 break;
  2644 #ifdef XP_WIN
  2645         case NPDrawingModelAsyncWindowsDXGISurface:
  2647                 CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
  2648                 data->mType = RemoteImageData::DXGI_TEXTURE_HANDLE;
  2649                 data->mSize = IntSize(surface->size.width, surface->size.height);
  2650                 data->mFormat = surface->format == NPImageFormatBGRX32 ?
  2651                                 RemoteImageData::BGRX32 : RemoteImageData::BGRA32;
  2652                 data->mTextureHandle = surface->sharedHandle;
  2654                 data->mWasUpdated = true;
  2655                 break;
  2657 #endif
  2662         MutexAutoLock autoLock(mAsyncInvalidateMutex);
  2663         if (!mAsyncInvalidateTask) {
  2664             mAsyncInvalidateTask = 
  2665                 NewRunnableMethod<PluginInstanceChild, void (PluginInstanceChild::*)()>
  2666                     (this, &PluginInstanceChild::DoAsyncRedraw);
  2667             ProcessChild::message_loop()->PostTask(FROM_HERE, mAsyncInvalidateTask);
  2672 void
  2673 PluginInstanceChild::DoAsyncRedraw()
  2676         MutexAutoLock autoLock(mAsyncInvalidateMutex);
  2677         mAsyncInvalidateTask = nullptr;
  2680     SendRedrawPlugin();
  2683 bool
  2684 PluginInstanceChild::RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
  2685                                         const NPRemoteWindow& aWindow)
  2687     AssertPluginThread();
  2689     NS_ASSERTION(!aWindow.window, "Remote window should be null.");
  2691     if (mCurrentAsyncSetWindowTask) {
  2692         mCurrentAsyncSetWindowTask->Cancel();
  2693         mCurrentAsyncSetWindowTask = nullptr;
  2696     // We shouldn't process this now because it may be received within a nested
  2697     // RPC call, and both Flash and Java don't expect to receive setwindow calls
  2698     // at arbitrary times.
  2699     mCurrentAsyncSetWindowTask =
  2700         NewRunnableMethod<PluginInstanceChild,
  2701                           void (PluginInstanceChild::*)(const gfxSurfaceType&, const NPRemoteWindow&, bool),
  2702                           gfxSurfaceType, NPRemoteWindow, bool>
  2703         (this, &PluginInstanceChild::DoAsyncSetWindow,
  2704          aSurfaceType, aWindow, true);
  2705     MessageLoop::current()->PostTask(FROM_HERE, mCurrentAsyncSetWindowTask);
  2707     return true;
  2710 void
  2711 PluginInstanceChild::DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
  2712                                       const NPRemoteWindow& aWindow,
  2713                                       bool aIsAsync)
  2715     PLUGIN_LOG_DEBUG(
  2716         ("[InstanceChild][%p] AsyncSetWindow to <x=%d,y=%d, w=%d,h=%d>",
  2717          this, aWindow.x, aWindow.y, aWindow.width, aWindow.height));
  2719     AssertPluginThread();
  2720     NS_ASSERTION(!aWindow.window, "Remote window should be null.");
  2721     NS_ASSERTION(!mPendingPluginCall, "Can't do SetWindow during plugin call!");
  2723     if (aIsAsync) {
  2724         if (!mCurrentAsyncSetWindowTask) {
  2725             return;
  2727         mCurrentAsyncSetWindowTask = nullptr;
  2730     mWindow.window = nullptr;
  2731     if (mWindow.width != aWindow.width || mWindow.height != aWindow.height ||
  2732         mWindow.clipRect.top != aWindow.clipRect.top ||
  2733         mWindow.clipRect.left != aWindow.clipRect.left ||
  2734         mWindow.clipRect.bottom != aWindow.clipRect.bottom ||
  2735         mWindow.clipRect.right != aWindow.clipRect.right)
  2736         mAccumulatedInvalidRect = nsIntRect(0, 0, aWindow.width, aWindow.height);
  2738     mWindow.x = aWindow.x;
  2739     mWindow.y = aWindow.y;
  2740     mWindow.width = aWindow.width;
  2741     mWindow.height = aWindow.height;
  2742     mWindow.clipRect = aWindow.clipRect;
  2743     mWindow.type = aWindow.type;
  2744 #ifdef XP_MACOSX
  2745     mContentsScaleFactor = aWindow.contentsScaleFactor;
  2746 #endif
  2748     if (GetQuirks() & PluginModuleChild::QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT)
  2749         mIsTransparent = true;
  2751     mLayersRendering = true;
  2752     mSurfaceType = aSurfaceType;
  2753     UpdateWindowAttributes(true);
  2755 #ifdef XP_WIN
  2756     if (GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK)
  2757         CreateWinlessPopupSurrogate();
  2758     if (GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)
  2759         SetupFlashMsgThrottle();
  2760 #endif
  2762     if (!mAccumulatedInvalidRect.IsEmpty()) {
  2763         AsyncShowPluginFrame();
  2767 static inline gfxRect
  2768 GfxFromNsRect(const nsIntRect& aRect)
  2770     return gfxRect(aRect.x, aRect.y, aRect.width, aRect.height);
  2773 bool
  2774 PluginInstanceChild::CreateOptSurface(void)
  2776     NS_ABORT_IF_FALSE(mSurfaceType != gfxSurfaceType::Max,
  2777                       "Need a valid surface type here");
  2778     NS_ASSERTION(!mCurrentSurface, "mCurrentSurfaceActor can get out of sync.");
  2780     nsRefPtr<gfxASurface> retsurf;
  2781     // Use an opaque surface unless we're transparent and *don't* have
  2782     // a background to source from.
  2783     gfxImageFormat format =
  2784         (mIsTransparent && !mBackground) ? gfxImageFormat::ARGB32 :
  2785                                            gfxImageFormat::RGB24;
  2787 #ifdef MOZ_X11
  2788     Display* dpy = mWsInfo.display;
  2789     Screen* screen = DefaultScreenOfDisplay(dpy);
  2790     if (format == gfxImageFormat::RGB24 &&
  2791         DefaultDepth(dpy, DefaultScreen(dpy)) == 16) {
  2792         format = gfxImageFormat::RGB16_565;
  2795     if (mSurfaceType == gfxSurfaceType::Xlib) {
  2796         if (!mIsTransparent  || mBackground) {
  2797             Visual* defaultVisual = DefaultVisualOfScreen(screen);
  2798             mCurrentSurface =
  2799                 gfxXlibSurface::Create(screen, defaultVisual,
  2800                                        gfxIntSize(mWindow.width,
  2801                                                   mWindow.height));
  2802             return mCurrentSurface != nullptr;
  2805         XRenderPictFormat* xfmt = XRenderFindStandardFormat(dpy, PictStandardARGB32);
  2806         if (!xfmt) {
  2807             NS_ERROR("Need X falback surface, but FindRenderFormat failed");
  2808             return false;
  2810         mCurrentSurface =
  2811             gfxXlibSurface::Create(screen, xfmt,
  2812                                    gfxIntSize(mWindow.width,
  2813                                               mWindow.height));
  2814         return mCurrentSurface != nullptr;
  2816 #endif
  2818 #ifdef XP_WIN
  2819     if (mSurfaceType == gfxSurfaceType::Win32 ||
  2820         mSurfaceType == gfxSurfaceType::D2D) {
  2821         bool willHaveTransparentPixels = mIsTransparent && !mBackground;
  2823         SharedDIBSurface* s = new SharedDIBSurface();
  2824         if (!s->Create(reinterpret_cast<HDC>(mWindow.window),
  2825                        mWindow.width, mWindow.height,
  2826                        willHaveTransparentPixels))
  2827             return false;
  2829         mCurrentSurface = s;
  2830         return true;
  2833     NS_RUNTIMEABORT("Shared-memory drawing not expected on Windows.");
  2834 #endif
  2836     // Make common shmem implementation working for any platform
  2837     mCurrentSurface =
  2838         gfxSharedImageSurface::CreateUnsafe(this, gfxIntSize(mWindow.width, mWindow.height), format);
  2839     return !!mCurrentSurface;
  2842 bool
  2843 PluginInstanceChild::MaybeCreatePlatformHelperSurface(void)
  2845     if (!mCurrentSurface) {
  2846         NS_ERROR("Cannot create helper surface without mCurrentSurface");
  2847         return false;
  2850 #ifdef MOZ_X11
  2851     bool supportNonDefaultVisual = false;
  2852     Screen* screen = DefaultScreenOfDisplay(mWsInfo.display);
  2853     Visual* defaultVisual = DefaultVisualOfScreen(screen);
  2854     Visual* visual = nullptr;
  2855     Colormap colormap = 0;
  2856     mDoAlphaExtraction = false;
  2857     bool createHelperSurface = false;
  2859     if (mCurrentSurface->GetType() == gfxSurfaceType::Xlib) {
  2860         static_cast<gfxXlibSurface*>(mCurrentSurface.get())->
  2861             GetColormapAndVisual(&colormap, &visual);
  2862         // Create helper surface if layer surface visual not same as default
  2863         // and we don't support non-default visual rendering
  2864         if (!visual || (defaultVisual != visual && !supportNonDefaultVisual)) {
  2865             createHelperSurface = true;
  2866             visual = defaultVisual;
  2867             mDoAlphaExtraction = mIsTransparent;
  2869     } else if (mCurrentSurface->GetType() == gfxSurfaceType::Image) {
  2870         // For image layer surface we should always create helper surface
  2871         createHelperSurface = true;
  2872         // Check if we can create helper surface with non-default visual
  2873         visual = gfxXlibSurface::FindVisual(screen,
  2874             static_cast<gfxImageSurface*>(mCurrentSurface.get())->Format());
  2875         if (!visual || (defaultVisual != visual && !supportNonDefaultVisual)) {
  2876             visual = defaultVisual;
  2877             mDoAlphaExtraction = mIsTransparent;
  2881     if (createHelperSurface) {
  2882         if (!visual) {
  2883             NS_ERROR("Need X falback surface, but visual failed");
  2884             return false;
  2886         mHelperSurface =
  2887             gfxXlibSurface::Create(screen, visual,
  2888                                    mCurrentSurface->GetSize());
  2889         if (!mHelperSurface) {
  2890             NS_WARNING("Fail to create create helper surface");
  2891             return false;
  2894 #elif defined(XP_WIN)
  2895     mDoAlphaExtraction = mIsTransparent && !mBackground;
  2896 #endif
  2898     return true;
  2901 bool
  2902 PluginInstanceChild::EnsureCurrentBuffer(void)
  2904 #ifndef XP_MACOSX
  2905     nsIntRect toInvalidate(0, 0, 0, 0);
  2906     gfxIntSize winSize = gfxIntSize(mWindow.width, mWindow.height);
  2908     if (mBackground && mBackground->GetSize() != winSize) {
  2909         // It would be nice to keep the old background here, but doing
  2910         // so can lead to cases in which we permanently keep the old
  2911         // background size.
  2912         mBackground = nullptr;
  2913         toInvalidate.UnionRect(toInvalidate,
  2914                                nsIntRect(0, 0, winSize.width, winSize.height));
  2917     if (mCurrentSurface) {
  2918         gfxIntSize surfSize = mCurrentSurface->GetSize();
  2919         if (winSize != surfSize ||
  2920             (mBackground && !CanPaintOnBackground()) ||
  2921             (mBackground &&
  2922              gfxContentType::COLOR != mCurrentSurface->GetContentType()) ||
  2923             (!mBackground && mIsTransparent &&
  2924              gfxContentType::COLOR == mCurrentSurface->GetContentType())) {
  2925             // Don't try to use an old, invalid DC.
  2926             mWindow.window = nullptr;
  2927             ClearCurrentSurface();
  2928             toInvalidate.UnionRect(toInvalidate,
  2929                                    nsIntRect(0, 0, winSize.width, winSize.height));
  2933     mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, toInvalidate);
  2935     if (mCurrentSurface) {
  2936         return true;
  2939     if (!CreateOptSurface()) {
  2940         NS_ERROR("Cannot create optimized surface");
  2941         return false;
  2944     if (!MaybeCreatePlatformHelperSurface()) {
  2945         NS_ERROR("Cannot create helper surface");
  2946         return false;
  2949     return true;
  2950 #else // XP_MACOSX
  2952     if (!mDoubleBufferCARenderer.HasCALayer()) {
  2953         void *caLayer = nullptr;
  2954         if (mDrawingModel == NPDrawingModelCoreGraphics) {
  2955             if (!mCGLayer) {
  2956                 bool avoidCGCrashes = !nsCocoaFeatures::OnMountainLionOrLater() &&
  2957                   (GetQuirks() & PluginModuleChild::QUIRK_FLASH_AVOID_CGMODE_CRASHES);
  2958                 caLayer = mozilla::plugins::PluginUtilsOSX::GetCGLayer(CallCGDraw, this,
  2959                                                                        avoidCGCrashes,
  2960                                                                        mContentsScaleFactor);
  2962                 if (!caLayer) {
  2963                     PLUGIN_LOG_DEBUG(("GetCGLayer failed."));
  2964                     return false;
  2967             mCGLayer = caLayer;
  2968         } else {
  2969             NPError result = mPluginIface->getvalue(GetNPP(),
  2970                                      NPPVpluginCoreAnimationLayer,
  2971                                      &caLayer);
  2972             if (result != NPERR_NO_ERROR || !caLayer) {
  2973                 PLUGIN_LOG_DEBUG(("Plugin requested CoreAnimation but did not "
  2974                                   "provide CALayer."));
  2975                 return false;
  2978         mDoubleBufferCARenderer.SetCALayer(caLayer);
  2981     if (mDoubleBufferCARenderer.HasFrontSurface() &&
  2982         (mDoubleBufferCARenderer.GetFrontSurfaceWidth() != mWindow.width ||
  2983          mDoubleBufferCARenderer.GetFrontSurfaceHeight() != mWindow.height ||
  2984          mDoubleBufferCARenderer.GetContentsScaleFactor() != mContentsScaleFactor)) {
  2985         mDoubleBufferCARenderer.ClearFrontSurface();
  2988     if (!mDoubleBufferCARenderer.HasFrontSurface()) {
  2989         bool allocSurface = mDoubleBufferCARenderer.InitFrontSurface(
  2990                                 mWindow.width, mWindow.height, mContentsScaleFactor,
  2991                                 GetQuirks() & PluginModuleChild::QUIRK_ALLOW_OFFLINE_RENDERER ?
  2992                                 ALLOW_OFFLINE_RENDERER : DISALLOW_OFFLINE_RENDERER);
  2993         if (!allocSurface) {
  2994             PLUGIN_LOG_DEBUG(("Fail to allocate front IOSurface"));
  2995             return false;
  2998         if (mPluginIface->setwindow)
  2999             (void) mPluginIface->setwindow(&mData, &mWindow);
  3001         nsIntRect toInvalidate(0, 0, mWindow.width, mWindow.height);
  3002         mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, toInvalidate);
  3005     return true;
  3006 #endif
  3009 void
  3010 PluginInstanceChild::UpdateWindowAttributes(bool aForceSetWindow)
  3012     nsRefPtr<gfxASurface> curSurface = mHelperSurface ? mHelperSurface : mCurrentSurface;
  3013     bool needWindowUpdate = aForceSetWindow;
  3014 #ifdef MOZ_X11
  3015     Visual* visual = nullptr;
  3016     Colormap colormap = 0;
  3017     if (curSurface && curSurface->GetType() == gfxSurfaceType::Xlib) {
  3018         static_cast<gfxXlibSurface*>(curSurface.get())->
  3019             GetColormapAndVisual(&colormap, &visual);
  3020         if (visual != mWsInfo.visual || colormap != mWsInfo.colormap) {
  3021             mWsInfo.visual = visual;
  3022             mWsInfo.colormap = colormap;
  3023             needWindowUpdate = true;
  3026 #endif // MOZ_X11
  3027 #ifdef XP_WIN
  3028     HDC dc = nullptr;
  3030     if (curSurface) {
  3031         if (!SharedDIBSurface::IsSharedDIBSurface(curSurface))
  3032             NS_RUNTIMEABORT("Expected SharedDIBSurface!");
  3034         SharedDIBSurface* dibsurf = static_cast<SharedDIBSurface*>(curSurface.get());
  3035         dc = dibsurf->GetHDC();
  3037     if (mWindow.window != dc) {
  3038         mWindow.window = dc;
  3039         needWindowUpdate = true;
  3041 #endif // XP_WIN
  3043     if (!needWindowUpdate) {
  3044         return;
  3047 #ifndef XP_MACOSX
  3048     // Adjusting the window isn't needed for OSX
  3049 #ifndef XP_WIN
  3050     // On Windows, we translate the device context, in order for the window
  3051     // origin to be correct.
  3052     mWindow.x = mWindow.y = 0;
  3053 #endif
  3055     if (IsVisible()) {
  3056         // The clip rect is relative to drawable top-left.
  3057         nsIntRect clipRect;
  3059         // Don't ask the plugin to draw outside the drawable. The clip rect
  3060         // is in plugin coordinates, not window coordinates.
  3061         // This also ensures that the unsigned clip rectangle offsets won't be -ve.
  3062         clipRect.SetRect(0, 0, mWindow.width, mWindow.height);
  3064         mWindow.clipRect.left = 0;
  3065         mWindow.clipRect.top = 0;
  3066         mWindow.clipRect.right = clipRect.XMost();
  3067         mWindow.clipRect.bottom = clipRect.YMost();
  3069 #endif // XP_MACOSX
  3071 #ifdef XP_WIN
  3072     // Windowless plugins on Windows need a WM_WINDOWPOSCHANGED event to update
  3073     // their location... or at least Flash does: Silverlight uses the
  3074     // window.x/y passed to NPP_SetWindow
  3076     if (mPluginIface->event) {
  3077         WINDOWPOS winpos = {
  3078             0, 0,
  3079             mWindow.x, mWindow.y,
  3080             mWindow.width, mWindow.height,
  3082         };
  3083         NPEvent pluginEvent = {
  3084             WM_WINDOWPOSCHANGED, 0,
  3085             (LPARAM) &winpos
  3086         };
  3087         mPluginIface->event(&mData, &pluginEvent);
  3089 #endif
  3091     PLUGIN_LOG_DEBUG(
  3092         ("[InstanceChild][%p] UpdateWindow w=<x=%d,y=%d, w=%d,h=%d>, clip=<l=%d,t=%d,r=%d,b=%d>",
  3093          this, mWindow.x, mWindow.y, mWindow.width, mWindow.height,
  3094          mWindow.clipRect.left, mWindow.clipRect.top, mWindow.clipRect.right, mWindow.clipRect.bottom));
  3096     if (mPluginIface->setwindow) {
  3097         mPluginIface->setwindow(&mData, &mWindow);
  3101 void
  3102 PluginInstanceChild::PaintRectToPlatformSurface(const nsIntRect& aRect,
  3103                                                 gfxASurface* aSurface)
  3105     UpdateWindowAttributes();
  3107 #ifdef MOZ_X11
  3109         NS_ASSERTION(aSurface->GetType() == gfxSurfaceType::Xlib,
  3110                      "Non supported platform surface type");
  3112         NPEvent pluginEvent;
  3113         XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose;
  3114         exposeEvent.type = GraphicsExpose;
  3115         exposeEvent.display = mWsInfo.display;
  3116         exposeEvent.drawable = static_cast<gfxXlibSurface*>(aSurface)->XDrawable();
  3117         exposeEvent.x = aRect.x;
  3118         exposeEvent.y = aRect.y;
  3119         exposeEvent.width = aRect.width;
  3120         exposeEvent.height = aRect.height;
  3121         exposeEvent.count = 0;
  3122         // information not set:
  3123         exposeEvent.serial = 0;
  3124         exposeEvent.send_event = False;
  3125         exposeEvent.major_code = 0;
  3126         exposeEvent.minor_code = 0;
  3127         mPluginIface->event(&mData, reinterpret_cast<void*>(&exposeEvent));
  3129 #elif defined(XP_WIN)
  3130     NS_ASSERTION(SharedDIBSurface::IsSharedDIBSurface(aSurface),
  3131                  "Expected (SharedDIB) image surface.");
  3133     // This rect is in the window coordinate space. aRect is in the plugin
  3134     // coordinate space.
  3135     RECT rect = {
  3136         mWindow.x + aRect.x,
  3137         mWindow.y + aRect.y,
  3138         mWindow.x + aRect.XMost(),
  3139         mWindow.y + aRect.YMost()
  3140     };
  3141     NPEvent paintEvent = {
  3142         WM_PAINT,
  3143         uintptr_t(mWindow.window),
  3144         uintptr_t(&rect)
  3145     };
  3147     ::SetViewportOrgEx((HDC) mWindow.window, -mWindow.x, -mWindow.y, nullptr);
  3148     ::SelectClipRgn((HDC) mWindow.window, nullptr);
  3149     ::IntersectClipRect((HDC) mWindow.window, rect.left, rect.top, rect.right, rect.bottom);
  3150     mPluginIface->event(&mData, reinterpret_cast<void*>(&paintEvent));
  3151 #else
  3152     NS_RUNTIMEABORT("Surface type not implemented.");
  3153 #endif
  3156 void
  3157 PluginInstanceChild::PaintRectToSurface(const nsIntRect& aRect,
  3158                                         gfxASurface* aSurface,
  3159                                         const gfxRGBA& aColor)
  3161     // Render using temporary X surface, with copy to image surface
  3162     nsIntRect plPaintRect(aRect);
  3163     nsRefPtr<gfxASurface> renderSurface = aSurface;
  3164 #ifdef MOZ_X11
  3165     if (mIsTransparent && (GetQuirks() & PluginModuleChild::QUIRK_FLASH_EXPOSE_COORD_TRANSLATION)) {
  3166         // Work around a bug in Flash up to 10.1 d51 at least, where expose event
  3167         // top left coordinates within the plugin-rect and not at the drawable
  3168         // origin are misinterpreted.  (We can move the top left coordinate
  3169         // provided it is within the clipRect.), see bug 574583
  3170         plPaintRect.SetRect(0, 0, aRect.XMost(), aRect.YMost());
  3172     if (mHelperSurface) {
  3173         // On X11 we can paint to non Xlib surface only with HelperSurface
  3174         renderSurface = mHelperSurface;
  3176 #endif
  3178     if (mIsTransparent && !CanPaintOnBackground()) {
  3179        // Clear surface content for transparent rendering
  3180        nsRefPtr<gfxContext> ctx = new gfxContext(renderSurface);
  3181        ctx->SetDeviceColor(aColor);
  3182        ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
  3183        ctx->Rectangle(GfxFromNsRect(plPaintRect));
  3184        ctx->Fill();
  3187     PaintRectToPlatformSurface(plPaintRect, renderSurface);
  3189     if (renderSurface != aSurface) {
  3190         // Copy helper surface content to target
  3191         nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
  3192         ctx->SetSource(renderSurface);
  3193         ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
  3194         ctx->Rectangle(GfxFromNsRect(aRect));
  3195         ctx->Fill();
  3199 void
  3200 PluginInstanceChild::PaintRectWithAlphaExtraction(const nsIntRect& aRect,
  3201                                                   gfxASurface* aSurface)
  3203     NS_ABORT_IF_FALSE(aSurface->GetContentType() == gfxContentType::COLOR_ALPHA,
  3204                       "Refusing to pointlessly recover alpha");
  3206     nsIntRect rect(aRect);
  3207     // If |aSurface| can be used to paint and can have alpha values
  3208     // recovered directly to it, do that to save a tmp surface and
  3209     // copy.
  3210     bool useSurfaceSubimageForBlack = false;
  3211     if (gfxSurfaceType::Image == aSurface->GetType()) {
  3212         gfxImageSurface* surfaceAsImage =
  3213             static_cast<gfxImageSurface*>(aSurface);
  3214         useSurfaceSubimageForBlack =
  3215             (surfaceAsImage->Format() == gfxImageFormat::ARGB32);
  3216         // If we're going to use a subimage, nudge the rect so that we
  3217         // can use optimal alpha recovery.  If we're not using a
  3218         // subimage, the temporaries should automatically get
  3219         // fast-path alpha recovery so we don't need to do anything.
  3220         if (useSurfaceSubimageForBlack) {
  3221             rect =
  3222                 gfxAlphaRecovery::AlignRectForSubimageRecovery(aRect,
  3223                                                                surfaceAsImage);
  3227     nsRefPtr<gfxImageSurface> whiteImage;
  3228     nsRefPtr<gfxImageSurface> blackImage;
  3229     gfxRect targetRect(rect.x, rect.y, rect.width, rect.height);
  3230     gfxIntSize targetSize(rect.width, rect.height);
  3231     gfxPoint deviceOffset = -targetRect.TopLeft();
  3233     // We always use a temporary "white image"
  3234     whiteImage = new gfxImageSurface(targetSize, gfxImageFormat::RGB24);
  3235     if (whiteImage->CairoStatus()) {
  3236         return;
  3239 #ifdef XP_WIN
  3240     // On windows, we need an HDC and so can't paint directly to
  3241     // vanilla image surfaces.  Bifurcate this painting code so that
  3242     // we don't accidentally attempt that.
  3243     if (!SharedDIBSurface::IsSharedDIBSurface(aSurface))
  3244         NS_RUNTIMEABORT("Expected SharedDIBSurface!");
  3246     // Paint the plugin directly onto the target, with a white
  3247     // background and copy the result
  3248     PaintRectToSurface(rect, aSurface, gfxRGBA(1.0, 1.0, 1.0));
  3250         gfxRect copyRect(gfxPoint(0, 0), targetRect.Size());
  3251         nsRefPtr<gfxContext> ctx = new gfxContext(whiteImage);
  3252         ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
  3253         ctx->SetSource(aSurface, deviceOffset);
  3254         ctx->Rectangle(copyRect);
  3255         ctx->Fill();
  3258     // Paint the plugin directly onto the target, with a black
  3259     // background
  3260     PaintRectToSurface(rect, aSurface, gfxRGBA(0.0, 0.0, 0.0));
  3262     // Don't copy the result, just extract a subimage so that we can
  3263     // recover alpha directly into the target
  3264     gfxImageSurface *image = static_cast<gfxImageSurface*>(aSurface);
  3265     blackImage = image->GetSubimage(targetRect);
  3267 #else
  3268     // Paint onto white background
  3269     whiteImage->SetDeviceOffset(deviceOffset);
  3270     PaintRectToSurface(rect, whiteImage, gfxRGBA(1.0, 1.0, 1.0));
  3272     if (useSurfaceSubimageForBlack) {
  3273         gfxImageSurface *surface = static_cast<gfxImageSurface*>(aSurface);
  3274         blackImage = surface->GetSubimage(targetRect);
  3275     } else {
  3276         blackImage = new gfxImageSurface(targetSize,
  3277                                          gfxImageFormat::ARGB32);
  3280     // Paint onto black background
  3281     blackImage->SetDeviceOffset(deviceOffset);
  3282     PaintRectToSurface(rect, blackImage, gfxRGBA(0.0, 0.0, 0.0));
  3283 #endif
  3285     NS_ABORT_IF_FALSE(whiteImage && blackImage, "Didn't paint enough!");
  3287     // Extract alpha from black and white image and store to black
  3288     // image
  3289     if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage)) {
  3290         return;
  3293     // If we had to use a temporary black surface, copy the pixels
  3294     // with alpha back to the target
  3295     if (!useSurfaceSubimageForBlack) {
  3296         nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
  3297         ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
  3298         ctx->SetSource(blackImage);
  3299         ctx->Rectangle(targetRect);
  3300         ctx->Fill();
  3304 bool
  3305 PluginInstanceChild::CanPaintOnBackground()
  3307     return (mBackground &&
  3308             mCurrentSurface &&
  3309             mCurrentSurface->GetSize() == mBackground->GetSize());
  3312 bool
  3313 PluginInstanceChild::ShowPluginFrame()
  3315     // mLayersRendering can be false if we somehow get here without
  3316     // receiving AsyncSetWindow() first.  mPendingPluginCall is our
  3317     // re-entrancy guard; we can't paint while nested inside another
  3318     // paint.
  3319     if (!mLayersRendering || mPendingPluginCall) {
  3320         return false;
  3323     AutoRestore<bool> pending(mPendingPluginCall);
  3324     mPendingPluginCall = true;
  3326     bool temporarilyMakeVisible = !IsVisible() && !mHasPainted;
  3327     if (temporarilyMakeVisible && mWindow.width && mWindow.height) {
  3328         mWindow.clipRect.right = mWindow.width;
  3329         mWindow.clipRect.bottom = mWindow.height;
  3330     } else if (!IsVisible()) {
  3331         // If we're not visible, don't bother painting a <0,0,0,0>
  3332         // rect.  If we're eventually made visible, the visibility
  3333         // change will invalidate our window.
  3334         ClearCurrentSurface();
  3335         return true;
  3338     if (!EnsureCurrentBuffer()) {
  3339         return false;
  3342 #ifdef MOZ_WIDGET_COCOA
  3343     // We can't use the thebes code with CoreAnimation so we will
  3344     // take a different code path.
  3345     if (mDrawingModel == NPDrawingModelCoreAnimation ||
  3346         mDrawingModel == NPDrawingModelInvalidatingCoreAnimation ||
  3347         mDrawingModel == NPDrawingModelCoreGraphics) {
  3349         if (!IsVisible()) {
  3350             return true;
  3353         if (!mDoubleBufferCARenderer.HasFrontSurface()) {
  3354             NS_ERROR("CARenderer not initialized for rendering");
  3355             return false;
  3358         // Clear accRect here to be able to pass
  3359         // test_invalidate_during_plugin_paint  test
  3360         nsIntRect rect = mAccumulatedInvalidRect;
  3361         mAccumulatedInvalidRect.SetEmpty();
  3363         // Fix up old invalidations that might have been made when our
  3364         // surface was a different size
  3365         rect.IntersectRect(rect,
  3366                           nsIntRect(0, 0, 
  3367                           mDoubleBufferCARenderer.GetFrontSurfaceWidth(), 
  3368                           mDoubleBufferCARenderer.GetFrontSurfaceHeight()));
  3370         if (mDrawingModel == NPDrawingModelCoreGraphics) {
  3371             mozilla::plugins::PluginUtilsOSX::Repaint(mCGLayer, rect);
  3374         mDoubleBufferCARenderer.Render();
  3376         NPRect r = { (uint16_t)rect.y, (uint16_t)rect.x,
  3377                      (uint16_t)rect.YMost(), (uint16_t)rect.XMost() };
  3378         SurfaceDescriptor currSurf;
  3379         currSurf = IOSurfaceDescriptor(mDoubleBufferCARenderer.GetFrontSurfaceID(),
  3380                                        mDoubleBufferCARenderer.GetContentsScaleFactor());
  3382         mHasPainted = true;
  3384         SurfaceDescriptor returnSurf;
  3386         if (!SendShow(r, currSurf, &returnSurf)) {
  3387             return false;
  3390         SwapSurfaces();
  3391         return true;
  3392     } else {
  3393         NS_ERROR("Unsupported drawing model for async layer rendering");
  3394         return false;
  3396 #endif
  3398     NS_ASSERTION(mWindow.width == uint32_t(mWindow.clipRect.right - mWindow.clipRect.left) &&
  3399                  mWindow.height == uint32_t(mWindow.clipRect.bottom - mWindow.clipRect.top),
  3400                  "Clip rect should be same size as window when using layers");
  3402     // Clear accRect here to be able to pass
  3403     // test_invalidate_during_plugin_paint  test
  3404     nsIntRect rect = mAccumulatedInvalidRect;
  3405     mAccumulatedInvalidRect.SetEmpty();
  3407     // Fix up old invalidations that might have been made when our
  3408     // surface was a different size
  3409     gfxIntSize surfaceSize = mCurrentSurface->GetSize();
  3410     rect.IntersectRect(rect,
  3411                        nsIntRect(0, 0, surfaceSize.width, surfaceSize.height));
  3413     if (!ReadbackDifferenceRect(rect)) {
  3414         // We couldn't read back the pixels that differ between the
  3415         // current surface and last, so we have to invalidate the
  3416         // entire window.
  3417         rect.SetRect(0, 0, mWindow.width, mWindow.height);
  3420     bool haveTransparentPixels =
  3421         gfxContentType::COLOR_ALPHA == mCurrentSurface->GetContentType();
  3422     PLUGIN_LOG_DEBUG(
  3423         ("[InstanceChild][%p] Painting%s <x=%d,y=%d, w=%d,h=%d> on surface <w=%d,h=%d>",
  3424          this, haveTransparentPixels ? " with alpha" : "",
  3425          rect.x, rect.y, rect.width, rect.height,
  3426          mCurrentSurface->GetSize().width, mCurrentSurface->GetSize().height));
  3428     if (CanPaintOnBackground()) {
  3429         PLUGIN_LOG_DEBUG(("  (on background)"));
  3430         // Source the background pixels ...
  3432             nsRefPtr<gfxContext> ctx =
  3433                 new gfxContext(mHelperSurface ? mHelperSurface : mCurrentSurface);
  3434             ctx->SetSource(mBackground);
  3435             ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
  3436             ctx->Rectangle(gfxRect(rect.x, rect.y, rect.width, rect.height));
  3437             ctx->Fill();
  3439         // ... and hand off to the plugin
  3440         // BEWARE: mBackground may die during this call
  3441         PaintRectToSurface(rect, mCurrentSurface, gfxRGBA(0.0, 0.0, 0.0, 0.0));
  3442     } else if (!temporarilyMakeVisible && mDoAlphaExtraction) {
  3443         // We don't want to pay the expense of alpha extraction for
  3444         // phony paints.
  3445         PLUGIN_LOG_DEBUG(("  (with alpha recovery)"));
  3446         PaintRectWithAlphaExtraction(rect, mCurrentSurface);
  3447     } else {
  3448         PLUGIN_LOG_DEBUG(("  (onto opaque surface)"));
  3450         // If we're on a platform that needs helper surfaces for
  3451         // plugins, and we're forcing a throwaway paint of a
  3452         // wmode=transparent plugin, then make sure to use the helper
  3453         // surface here.
  3454         nsRefPtr<gfxASurface> target =
  3455             (temporarilyMakeVisible && mHelperSurface) ?
  3456             mHelperSurface : mCurrentSurface;
  3458         PaintRectToSurface(rect, target, gfxRGBA(0.0, 0.0, 0.0, 0.0));
  3460     mHasPainted = true;
  3462     if (temporarilyMakeVisible) {
  3463         mWindow.clipRect.right = mWindow.clipRect.bottom = 0;
  3465         PLUGIN_LOG_DEBUG(
  3466             ("[InstanceChild][%p] Undoing temporary clipping w=<x=%d,y=%d, w=%d,h=%d>, clip=<l=%d,t=%d,r=%d,b=%d>",
  3467              this, mWindow.x, mWindow.y, mWindow.width, mWindow.height,
  3468              mWindow.clipRect.left, mWindow.clipRect.top, mWindow.clipRect.right, mWindow.clipRect.bottom));
  3470         if (mPluginIface->setwindow) {
  3471             mPluginIface->setwindow(&mData, &mWindow);
  3474         // Skip forwarding the results of the phony paint to the
  3475         // browser.  We may have painted a transparent plugin using
  3476         // the opaque-plugin path, which can result in wrong pixels.
  3477         // We also don't want to pay the expense of forwarding the
  3478         // surface for plugins that might really be invisible.
  3479         mAccumulatedInvalidRect.SetRect(0, 0, mWindow.width, mWindow.height);
  3480         return true;
  3483     NPRect r = { (uint16_t)rect.y, (uint16_t)rect.x,
  3484                  (uint16_t)rect.YMost(), (uint16_t)rect.XMost() };
  3485     SurfaceDescriptor currSurf;
  3486 #ifdef MOZ_X11
  3487     if (mCurrentSurface->GetType() == gfxSurfaceType::Xlib) {
  3488         gfxXlibSurface *xsurf = static_cast<gfxXlibSurface*>(mCurrentSurface.get());
  3489         currSurf = SurfaceDescriptorX11(xsurf);
  3490         // Need to sync all pending x-paint requests
  3491         // before giving drawable to another process
  3492         XSync(mWsInfo.display, False);
  3493     } else
  3494 #endif
  3495 #ifdef XP_WIN
  3496     if (SharedDIBSurface::IsSharedDIBSurface(mCurrentSurface)) {
  3497         SharedDIBSurface* s = static_cast<SharedDIBSurface*>(mCurrentSurface.get());
  3498         if (!mCurrentSurfaceActor) {
  3499             base::SharedMemoryHandle handle = nullptr;
  3500             s->ShareToProcess(PluginModuleChild::current()->OtherProcess(), &handle);
  3502             mCurrentSurfaceActor =
  3503                 SendPPluginSurfaceConstructor(handle,
  3504                                               mCurrentSurface->GetSize(),
  3505                                               haveTransparentPixels);
  3507         currSurf = mCurrentSurfaceActor;
  3508         s->Flush();
  3509     } else
  3510 #endif
  3511     if (gfxSharedImageSurface::IsSharedImage(mCurrentSurface)) {
  3512         currSurf = static_cast<gfxSharedImageSurface*>(mCurrentSurface.get())->GetShmem();
  3513     } else {
  3514         NS_RUNTIMEABORT("Surface type is not remotable");
  3515         return false;
  3518     // Unused, except to possibly return a shmem to us
  3519     SurfaceDescriptor returnSurf;
  3521     if (!SendShow(r, currSurf, &returnSurf)) {
  3522         return false;
  3525     SwapSurfaces();
  3526     mSurfaceDifferenceRect = rect;
  3527     return true;
  3530 bool
  3531 PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect)
  3533     if (!mBackSurface)
  3534         return false;
  3536     // We can read safely from XSurface,SharedDIBSurface and Unsafe SharedMemory,
  3537     // because PluginHost is not able to modify that surface
  3538 #if defined(MOZ_X11)
  3539     if (mBackSurface->GetType() != gfxSurfaceType::Xlib &&
  3540         !gfxSharedImageSurface::IsSharedImage(mBackSurface))
  3541         return false;
  3542 #elif defined(XP_WIN)
  3543     if (!SharedDIBSurface::IsSharedDIBSurface(mBackSurface))
  3544         return false;
  3545 #else
  3546     return false;
  3547 #endif
  3549     if (mCurrentSurface->GetContentType() != mBackSurface->GetContentType())
  3550         return false;
  3552     if (mSurfaceDifferenceRect.IsEmpty())
  3553         return true;
  3555     PLUGIN_LOG_DEBUG(
  3556         ("[InstanceChild][%p] Reading back part of <x=%d,y=%d, w=%d,h=%d>",
  3557          this, mSurfaceDifferenceRect.x, mSurfaceDifferenceRect.y,
  3558          mSurfaceDifferenceRect.width, mSurfaceDifferenceRect.height));
  3560     // Read back previous content
  3561     nsRefPtr<gfxContext> ctx = new gfxContext(mCurrentSurface);
  3562     ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
  3563     ctx->SetSource(mBackSurface);
  3564     // Subtract from mSurfaceDifferenceRect area which is overlapping with rect
  3565     nsIntRegion result;
  3566     result.Sub(mSurfaceDifferenceRect, nsIntRegion(rect));
  3567     nsIntRegionRectIterator iter(result);
  3568     const nsIntRect* r;
  3569     while ((r = iter.Next()) != nullptr) {
  3570         ctx->Rectangle(GfxFromNsRect(*r));
  3572     ctx->Fill();
  3574     return true;
  3577 void
  3578 PluginInstanceChild::InvalidateRectDelayed(void)
  3580     if (!mCurrentInvalidateTask) {
  3581         return;
  3584     mCurrentInvalidateTask = nullptr;
  3585     if (mAccumulatedInvalidRect.IsEmpty()) {
  3586         return;
  3589     if (!ShowPluginFrame()) {
  3590         AsyncShowPluginFrame();
  3594 void
  3595 PluginInstanceChild::AsyncShowPluginFrame(void)
  3597     if (mCurrentInvalidateTask) {
  3598         return;
  3601     mCurrentInvalidateTask =
  3602         NewRunnableMethod(this, &PluginInstanceChild::InvalidateRectDelayed);
  3603     MessageLoop::current()->PostTask(FROM_HERE, mCurrentInvalidateTask);
  3606 void
  3607 PluginInstanceChild::InvalidateRect(NPRect* aInvalidRect)
  3609     NS_ASSERTION(aInvalidRect, "Null pointer!");
  3611 #ifdef OS_WIN
  3612     // Invalidate and draw locally for windowed plugins.
  3613     if (mWindow.type == NPWindowTypeWindow) {
  3614       NS_ASSERTION(IsWindow(mPluginWindowHWND), "Bad window?!");
  3615       RECT rect = { aInvalidRect->left, aInvalidRect->top,
  3616                     aInvalidRect->right, aInvalidRect->bottom };
  3617       ::InvalidateRect(mPluginWindowHWND, &rect, FALSE);
  3618       return;
  3620 #endif
  3622     if (mLayersRendering) {
  3623         nsIntRect r(aInvalidRect->left, aInvalidRect->top,
  3624                     aInvalidRect->right - aInvalidRect->left,
  3625                     aInvalidRect->bottom - aInvalidRect->top);
  3627         mAccumulatedInvalidRect.UnionRect(r, mAccumulatedInvalidRect);
  3628         // If we are able to paint and invalidate sent, then reset
  3629         // accumulated rectangle
  3630         AsyncShowPluginFrame();
  3631         return;
  3634     // If we were going to use layers rendering but it's not set up
  3635     // yet, and the plugin happens to call this first, we'll forward
  3636     // the invalidation to the browser.  It's unclear whether
  3637     // non-layers plugins need this rect forwarded when their window
  3638     // width or height is 0, which it would be for layers plugins
  3639     // before their first SetWindow().
  3640     SendNPN_InvalidateRect(*aInvalidRect);
  3643 bool
  3644 PluginInstanceChild::RecvUpdateBackground(const SurfaceDescriptor& aBackground,
  3645                                           const nsIntRect& aRect)
  3647     NS_ABORT_IF_FALSE(mIsTransparent, "Only transparent plugins use backgrounds");
  3649     if (!mBackground) {
  3650         // XXX refactor me
  3651         switch (aBackground.type()) {
  3652 #ifdef MOZ_X11
  3653         case SurfaceDescriptor::TSurfaceDescriptorX11: {
  3654             mBackground = aBackground.get_SurfaceDescriptorX11().OpenForeign();
  3655             break;
  3657 #endif
  3658         case SurfaceDescriptor::TShmem: {
  3659             mBackground = gfxSharedImageSurface::Open(aBackground.get_Shmem());
  3660             break;
  3662         default:
  3663             NS_RUNTIMEABORT("Unexpected background surface descriptor");
  3666         if (!mBackground) {
  3667             return false;
  3670         gfxIntSize bgSize = mBackground->GetSize();
  3671         mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect,
  3672                                           nsIntRect(0, 0, bgSize.width, bgSize.height));
  3673         AsyncShowPluginFrame();
  3674         return true;
  3677     // XXX refactor me
  3678     mAccumulatedInvalidRect.UnionRect(aRect, mAccumulatedInvalidRect);
  3680     // This must be asynchronous, because we may be nested within RPC messages
  3681     // which do not expect to receiving paint events.
  3682     AsyncShowPluginFrame();
  3684     return true;
  3687 PPluginBackgroundDestroyerChild*
  3688 PluginInstanceChild::AllocPPluginBackgroundDestroyerChild()
  3690     return new PluginBackgroundDestroyerChild();
  3693 bool
  3694 PluginInstanceChild::RecvPPluginBackgroundDestroyerConstructor(
  3695     PPluginBackgroundDestroyerChild* aActor)
  3697     // Our background changed, so we have to invalidate the area
  3698     // painted with the old background.  If the background was
  3699     // destroyed because we have a new background, then we expect to
  3700     // be notified of that "soon", before processing the asynchronous
  3701     // invalidation here.  If we're *not* getting a new background,
  3702     // our current front surface is stale and we want to repaint
  3703     // "soon" so that we can hand the browser back a surface with
  3704     // alpha values.  (We should be notified of that invalidation soon
  3705     // too, but we don't assume that here.)
  3706     if (mBackground) {
  3707         gfxIntSize bgsize = mBackground->GetSize();
  3708         mAccumulatedInvalidRect.UnionRect(
  3709             nsIntRect(0, 0, bgsize.width, bgsize.height), mAccumulatedInvalidRect);
  3711         // NB: we don't have to XSync here because only ShowPluginFrame()
  3712         // uses mBackground, and it always XSyncs after finishing.
  3713         mBackground = nullptr;
  3714         AsyncShowPluginFrame();
  3717     return PPluginBackgroundDestroyerChild::Send__delete__(aActor);
  3720 bool
  3721 PluginInstanceChild::DeallocPPluginBackgroundDestroyerChild(
  3722     PPluginBackgroundDestroyerChild* aActor)
  3724     delete aActor;
  3725     return true;
  3728 uint32_t
  3729 PluginInstanceChild::ScheduleTimer(uint32_t interval, bool repeat,
  3730                                    TimerFunc func)
  3732     ChildTimer* t = new ChildTimer(this, interval, repeat, func);
  3733     if (0 == t->ID()) {
  3734         delete t;
  3735         return 0;
  3738     mTimers.AppendElement(t);
  3739     return t->ID();
  3742 void
  3743 PluginInstanceChild::UnscheduleTimer(uint32_t id)
  3745     if (0 == id)
  3746         return;
  3748     mTimers.RemoveElement(id, ChildTimer::IDComparator());
  3751 void
  3752 PluginInstanceChild::AsyncCall(PluginThreadCallback aFunc, void* aUserData)
  3754     ChildAsyncCall* task = new ChildAsyncCall(this, aFunc, aUserData);
  3757         MutexAutoLock lock(mAsyncCallMutex);
  3758         mPendingAsyncCalls.AppendElement(task);
  3760     ProcessChild::message_loop()->PostTask(FROM_HERE, task);
  3763 static PLDHashOperator
  3764 InvalidateObject(DeletingObjectEntry* e, void* userArg)
  3766     NPObject* o = e->GetKey();
  3767     if (!e->mDeleted && o->_class && o->_class->invalidate)
  3768         o->_class->invalidate(o);
  3770     return PL_DHASH_NEXT;
  3773 static PLDHashOperator
  3774 DeleteObject(DeletingObjectEntry* e, void* userArg)
  3776     NPObject* o = e->GetKey();
  3777     if (!e->mDeleted) {
  3778         e->mDeleted = true;
  3780 #ifdef NS_BUILD_REFCNT_LOGGING
  3782             int32_t refcnt = o->referenceCount;
  3783             while (refcnt) {
  3784                 --refcnt;
  3785                 NS_LOG_RELEASE(o, refcnt, "NPObject");
  3788 #endif
  3790         PluginModuleChild::DeallocNPObject(o);
  3793     return PL_DHASH_NEXT;
  3796 void
  3797 PluginInstanceChild::SwapSurfaces()
  3799     nsRefPtr<gfxASurface> tmpsurf = mCurrentSurface;
  3800 #ifdef XP_WIN
  3801     PPluginSurfaceChild* tmpactor = mCurrentSurfaceActor;
  3802 #endif
  3804     mCurrentSurface = mBackSurface;
  3805 #ifdef XP_WIN
  3806     mCurrentSurfaceActor = mBackSurfaceActor;
  3807 #endif
  3809     mBackSurface = tmpsurf;
  3810 #ifdef XP_WIN
  3811     mBackSurfaceActor = tmpactor;
  3812 #endif
  3814 #ifdef MOZ_WIDGET_COCOA
  3815     mDoubleBufferCARenderer.SwapSurfaces();
  3817     // Outdated back surface... not usable anymore due to changed plugin size.
  3818     // Dropping obsolete surface
  3819     if (mDoubleBufferCARenderer.HasFrontSurface() && 
  3820         mDoubleBufferCARenderer.HasBackSurface() &&
  3821         (mDoubleBufferCARenderer.GetFrontSurfaceWidth() != 
  3822             mDoubleBufferCARenderer.GetBackSurfaceWidth() ||
  3823         mDoubleBufferCARenderer.GetFrontSurfaceHeight() != 
  3824             mDoubleBufferCARenderer.GetBackSurfaceHeight() ||
  3825         mDoubleBufferCARenderer.GetFrontSurfaceContentsScaleFactor() != 
  3826             mDoubleBufferCARenderer.GetBackSurfaceContentsScaleFactor())) {
  3828         mDoubleBufferCARenderer.ClearFrontSurface();
  3830 #else
  3831     if (mCurrentSurface && mBackSurface &&
  3832         (mCurrentSurface->GetSize() != mBackSurface->GetSize() ||
  3833          mCurrentSurface->GetContentType() != mBackSurface->GetContentType())) {
  3834         ClearCurrentSurface();
  3836 #endif
  3839 void
  3840 PluginInstanceChild::ClearCurrentSurface()
  3842     mCurrentSurface = nullptr;
  3843 #ifdef MOZ_WIDGET_COCOA
  3844     if (mDoubleBufferCARenderer.HasFrontSurface()) {
  3845         mDoubleBufferCARenderer.ClearFrontSurface();
  3847 #endif
  3848 #ifdef XP_WIN
  3849     if (mCurrentSurfaceActor) {
  3850         PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor);
  3851         mCurrentSurfaceActor = nullptr;
  3853 #endif
  3854     mHelperSurface = nullptr;
  3857 void
  3858 PluginInstanceChild::ClearAllSurfaces()
  3860     if (mBackSurface) {
  3861         // Get last surface back, and drop it
  3862         SurfaceDescriptor temp = null_t();
  3863         NPRect r = { 0, 0, 1, 1 };
  3864         SendShow(r, temp, &temp);
  3867     if (gfxSharedImageSurface::IsSharedImage(mCurrentSurface))
  3868         DeallocShmem(static_cast<gfxSharedImageSurface*>(mCurrentSurface.get())->GetShmem());
  3869     if (gfxSharedImageSurface::IsSharedImage(mBackSurface))
  3870         DeallocShmem(static_cast<gfxSharedImageSurface*>(mBackSurface.get())->GetShmem());
  3871     mCurrentSurface = nullptr;
  3872     mBackSurface = nullptr;
  3874 #ifdef XP_WIN
  3875     if (mCurrentSurfaceActor) {
  3876         PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor);
  3877         mCurrentSurfaceActor = nullptr;
  3879     if (mBackSurfaceActor) {
  3880         PPluginSurfaceChild::Send__delete__(mBackSurfaceActor);
  3881         mBackSurfaceActor = nullptr;
  3883 #endif
  3885 #ifdef MOZ_WIDGET_COCOA
  3886     if (mDoubleBufferCARenderer.HasBackSurface()) {
  3887         // Get last surface back, and drop it
  3888         SurfaceDescriptor temp = null_t();
  3889         NPRect r = { 0, 0, 1, 1 };
  3890         SendShow(r, temp, &temp);
  3893     if (mCGLayer) {
  3894         mozilla::plugins::PluginUtilsOSX::ReleaseCGLayer(mCGLayer);
  3895         mCGLayer = nullptr;
  3898     mDoubleBufferCARenderer.ClearFrontSurface();
  3899     mDoubleBufferCARenderer.ClearBackSurface();
  3900 #endif
  3903 PLDHashOperator
  3904 PluginInstanceChild::DeleteSurface(NPAsyncSurface* surf, nsAutoPtr<AsyncBitmapData> &data, void* userArg)
  3906     PluginInstanceChild *inst = static_cast<PluginInstanceChild*>(userArg);
  3908     inst->DeallocShmem(data->mShmem);
  3910     return PL_DHASH_REMOVE;
  3913 bool
  3914 PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
  3916     PLUGIN_LOG_DEBUG_METHOD;
  3917     AssertPluginThread();
  3918     *aResult = NPERR_NO_ERROR;
  3920 #if defined(OS_WIN)
  3921     SetProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty, (HANDLE)1);
  3922 #endif
  3924     InfallibleTArray<PBrowserStreamChild*> streams;
  3925     ManagedPBrowserStreamChild(streams);
  3927     // First make sure none of these streams become deleted
  3928     for (uint32_t i = 0; i < streams.Length(); ) {
  3929         if (static_cast<BrowserStreamChild*>(streams[i])->InstanceDying())
  3930             ++i;
  3931         else
  3932             streams.RemoveElementAt(i);
  3934     for (uint32_t i = 0; i < streams.Length(); ++i)
  3935         static_cast<BrowserStreamChild*>(streams[i])->FinishDelivery();
  3937     mTimers.Clear();
  3939     // NPP_Destroy() should be a synchronization point for plugin threads
  3940     // calling NPN_AsyncCall: after this function returns, they are no longer
  3941     // allowed to make async calls on this instance.
  3942     PluginModuleChild::current()->NPP_Destroy(this);
  3943     mData.ndata = 0;
  3945     if (mCurrentInvalidateTask) {
  3946         mCurrentInvalidateTask->Cancel();
  3947         mCurrentInvalidateTask = nullptr;
  3949     if (mCurrentAsyncSetWindowTask) {
  3950         mCurrentAsyncSetWindowTask->Cancel();
  3951         mCurrentAsyncSetWindowTask = nullptr;
  3954         MutexAutoLock autoLock(mAsyncInvalidateMutex);
  3955         if (mAsyncInvalidateTask) {
  3956             mAsyncInvalidateTask->Cancel();
  3957             mAsyncInvalidateTask = nullptr;
  3961     ClearAllSurfaces();
  3963     mDeletingHash = new nsTHashtable<DeletingObjectEntry>;
  3964     PluginModuleChild::current()->FindNPObjectsForInstance(this);
  3966     mDeletingHash->EnumerateEntries(InvalidateObject, nullptr);
  3967     mDeletingHash->EnumerateEntries(DeleteObject, nullptr);
  3969     // Null out our cached actors as they should have been killed in the
  3970     // PluginInstanceDestroyed call above.
  3971     mCachedWindowActor = nullptr;
  3972     mCachedElementActor = nullptr;
  3974 #if defined(OS_WIN)
  3975     SharedSurfaceRelease();
  3976     DestroyWinlessPopupSurrogate();
  3977     UnhookWinlessFlashThrottle();
  3978     DestroyPluginWindow();
  3979 #endif
  3981     // Pending async calls are discarded, not delivered. This matches the
  3982     // in-process behavior.
  3983     for (uint32_t i = 0; i < mPendingAsyncCalls.Length(); ++i)
  3984         mPendingAsyncCalls[i]->Cancel();
  3986     mPendingAsyncCalls.Clear();
  3988     if (mAsyncBitmaps.Count()) {
  3989         NS_ERROR("Not all AsyncBitmaps were finalized by a plugin!");
  3990         mAsyncBitmaps.Enumerate(DeleteSurface, this);
  3993 #if (MOZ_WIDGET_GTK == 2)
  3994     if (mWindow.type == NPWindowTypeWindow && !mXEmbed) {
  3995       xt_client_xloop_destroy();
  3997 #endif
  3998 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
  3999     DeleteWindow();
  4000 #endif
  4002     return true;

mercurial