Bug 625425 - Don't re-share the plugin surfaces every time we flip front/back buffers on Windows. r=jimm,karlt, a=blocking
authorBenjamin Smedberg <benjamin@smedbergs.us>
Thu, 27 Jan 2011 16:37:00 -0600
changeset 61408 ecb1a0b69e0b
parent 61407 f3377ef65cd9
child 61409 5e0bba79c052
push id18349
push userjmathies@mozilla.com
push date2011-01-27 22:37 +0000
treeherdermozilla-central@ecb1a0b69e0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm, karlt, blocking
bugs625425
milestone2.0b11pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 625425 - Don't re-share the plugin surfaces every time we flip front/back buffers on Windows. r=jimm,karlt, a=blocking
dom/plugins/Makefile.in
dom/plugins/PPluginInstance.ipdl
dom/plugins/PPluginSurface.ipdl
dom/plugins/PluginInstanceChild.cpp
dom/plugins/PluginInstanceChild.h
dom/plugins/PluginInstanceParent.cpp
dom/plugins/PluginInstanceParent.h
dom/plugins/PluginSurfaceParent.cpp
dom/plugins/PluginSurfaceParent.h
dom/plugins/ipdl.mk
--- a/dom/plugins/Makefile.in
+++ b/dom/plugins/Makefile.in
@@ -121,17 +121,24 @@ CPPSRCS = \
   PluginScriptableObjectParent.cpp \
   BrowserStreamChild.cpp \
   BrowserStreamParent.cpp \
   PluginStreamChild.cpp \
   PluginStreamParent.cpp \
   $(NULL)
 
 ifeq (WINNT,$(OS_ARCH))
-CPPSRCS += COMMessageFilter.cpp
+CPPSRCS += \
+  COMMessageFilter.cpp \
+  PluginSurfaceParent.cpp \
+  $(NULL)
+
+EXPORTS_mozilla/plugins += \
+  PluginSurfaceParent.h \
+  $(NULL)
 endif
 
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 CMMSRCS   += \
     PluginUtilsOSX.mm \
     PluginInterposeOSX.mm \
     $(NULL)
 endif
--- a/dom/plugins/PPluginInstance.ipdl
+++ b/dom/plugins/PPluginInstance.ipdl
@@ -37,16 +37,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 include protocol PPluginModule;
 include protocol PPluginScriptableObject;
 include protocol PBrowserStream;
 include protocol PPluginStream;
 include protocol PStreamNotify;
+include protocol PPluginSurface;
 
 include "mozilla/plugins/PluginMessageUtils.h";
 
 using NPError;
 using NPRemoteWindow;
 using NPRemoteEvent;
 using NPRect;
 using NPNURLVariable;
@@ -61,42 +62,37 @@ namespace mozilla {
 namespace plugins {
 
 struct SurfaceDescriptorX11 {
   int XID;
   int xrenderPictID;
   gfxIntSize size;
 };
 
-struct SurfaceDescriptorWin {
-  WindowsSharedMemoryHandle handle;
-  gfxIntSize size;
-  bool transparent;
-};
-
 union SurfaceDescriptor {
   Shmem;
   SurfaceDescriptorX11;
-  SurfaceDescriptorWin;
+  PPluginSurface; // used on Windows
   // Descriptor can be null here in case
   // 1) of first Show call (prevSurface is null)
   // 2) when child is going to destroy
   //    and it just want to grab prevSurface
   //     back without giving new surface
   null_t;
 };
 
 rpc protocol PPluginInstance
 {
   manager PPluginModule;
 
   manages PPluginScriptableObject;
   manages PBrowserStream;
   manages PPluginStream;
   manages PStreamNotify;
+  manages PPluginSurface;
 
 child:
   rpc __delete__();
 
   rpc NPP_SetWindow(NPRemoteWindow window);
 
   // this message is not used on non-X platforms
   rpc NPP_GetValue_NPPVpluginNeedsXEmbed()
@@ -179,16 +175,20 @@ parent:
   // @param rect - actually updated rectangle, comparing to prevSurface content
   //               could be used for partial render of layer to topLevel context
   // @param newSurface - remotable surface
   // @param prevSurface - if the previous surface was shared-memory, returns
   //                      the shmem for reuse
   sync Show(NPRect updatedRect, SurfaceDescriptor newSurface)
     returns (SurfaceDescriptor prevSurface);
 
+  async PPluginSurface(WindowsSharedMemoryHandle handle,
+                       gfxIntSize size,
+                       bool transparent);
+
   rpc NPN_PushPopupsEnabledState(bool aState);
 
   rpc NPN_PopPopupsEnabledState();
 
   rpc NPN_GetValueForURL(NPNURLVariable variable, nsCString url)
     returns (nsCString value, NPError result);
 
   rpc NPN_SetValueForURL(NPNURLVariable variable, nsCString url,
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PPluginSurface.ipdl
@@ -0,0 +1,51 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Firefox.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation <http://www.mozilla.org/>.
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+include protocol PPluginInstance;
+
+namespace mozilla {
+namespace plugins {
+
+async protocol PPluginSurface {
+  manager PPluginInstance;
+
+parent:
+  async __delete__();
+};
+
+}
+}
--- a/dom/plugins/PluginInstanceChild.cpp
+++ b/dom/plugins/PluginInstanceChild.cpp
@@ -131,16 +131,20 @@ PluginInstanceChild::PluginInstanceChild
     , mEventModel(NPEventModelCarbon)
 #endif
     , mShColorSpace(nsnull)
     , mShContext(nsnull)
     , mDrawingModel(NPDrawingModelCoreGraphics)
     , mCurrentEvent(nsnull)
 #endif
     , mLayersRendering(false)
+#ifdef XP_WIN
+    , mCurrentSurfaceActor(NULL)
+    , mBackSurfaceActor(NULL)
+#endif
     , mAccumulatedInvalidRect(0,0,0,0)
     , mIsTransparent(false)
     , mSurfaceType(gfxASurface::SurfaceTypeMax)
     , mCurrentInvalidateTask(nsnull)
     , mCurrentAsyncSetWindowTask(nsnull)
     , mPendingPluginCall(false)
     , mDoAlphaExtraction(false)
     , mHasPainted(false)
@@ -2276,18 +2280,17 @@ PluginInstanceChild::DoAsyncSetWindow(co
         if (!mCurrentAsyncSetWindowTask) {
             return;
         }
         mCurrentAsyncSetWindowTask = nsnull;
     }
 
     mWindow.window = NULL;
     if (mWindow.width != aWindow.width || mWindow.height != aWindow.height) {
-        mCurrentSurface = nsnull;
-        mHelperSurface = nsnull;
+        ClearCurrentSurface();
         mAccumulatedInvalidRect = nsIntRect(0, 0, aWindow.width, aWindow.height);
     }
     if (mWindow.clipRect.top != aWindow.clipRect.top ||
         mWindow.clipRect.left != aWindow.clipRect.left ||
         mWindow.clipRect.bottom != aWindow.clipRect.bottom ||
         mWindow.clipRect.right != aWindow.clipRect.right)
         mAccumulatedInvalidRect = nsIntRect(0, 0, aWindow.width, aWindow.height);
 
@@ -2321,16 +2324,18 @@ static inline gfxRect
 GfxFromNsRect(const nsIntRect& aRect)
 {
     return gfxRect(aRect.x, aRect.y, aRect.width, aRect.height);
 }
 
 bool
 PluginInstanceChild::CreateOptSurface(void)
 {
+    NS_ASSERTION(!mCurrentSurface, "mCurrentSurfaceActor can get out of sync.");
+
     nsRefPtr<gfxASurface> retsurf;
     gfxASurface::gfxImageFormat format =
         mIsTransparent ? gfxASurface::ImageFormatARGB32 :
                          gfxASurface::ImageFormatRGB24;
 
 #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
     // On Maemo 5, we must send the Visibility event to activate the plugin
     if (mMaemoImageRendering) {
@@ -2831,20 +2836,27 @@ PluginInstanceChild::ShowPluginFrame()
                                         mCurrentSurface->GetSize());
         // Need to sync all pending x-paint requests
         // before giving drawable to another process
         XSync(mWsInfo.display, False);
     } else
 #endif
 #ifdef XP_WIN
     if (SharedDIBSurface::IsSharedDIBSurface(mCurrentSurface)) {
-        base::SharedMemoryHandle handle = NULL;
         SharedDIBSurface* s = static_cast<SharedDIBSurface*>(mCurrentSurface.get());
-        s->ShareToProcess(PluginModuleChild::current()->OtherProcess(), &handle);
-        currSurf = SurfaceDescriptorWin(handle, mCurrentSurface->GetSize(), mIsTransparent);
+        if (!mCurrentSurfaceActor) {
+            base::SharedMemoryHandle handle = NULL;
+            s->ShareToProcess(PluginModuleChild::current()->OtherProcess(), &handle);
+
+            mCurrentSurfaceActor =
+                SendPPluginSurfaceConstructor(handle,
+                                              mCurrentSurface->GetSize(),
+                                              mIsTransparent);
+        }
+        currSurf = mCurrentSurfaceActor;
         s->Flush();
     } else
 #endif
     if (gfxSharedImageSurface::IsSharedImage(mCurrentSurface)) {
         currSurf = static_cast<gfxSharedImageSurface*>(mCurrentSurface.get())->GetShmem();
     } else {
         NS_RUNTIMEABORT("Surface type is not remotable");
         return false;
@@ -2852,25 +2864,17 @@ PluginInstanceChild::ShowPluginFrame()
 
     // Unused, except to possibly return a shmem to us
     SurfaceDescriptor returnSurf;
 
     if (!SendShow(r, currSurf, &returnSurf)) {
         return false;
     }
 
-    nsRefPtr<gfxASurface> tmp = mCurrentSurface;
-    mCurrentSurface = mBackSurface;
-    mBackSurface = tmp;
-    // Outdated back surface... not usable anymore due to changed plugin size.
-    // Dropping obsolete surface
-    if (mCurrentSurface && mBackSurface &&
-        mCurrentSurface->GetSize() != mBackSurface->GetSize()) {
-        mCurrentSurface = nsnull;
-    }
+    SwapSurfaces();
     mSurfaceDifferenceRect = rect;
     return true;
 }
 
 bool
 PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect)
 {
     if (!mBackSurface)
@@ -3031,39 +3035,99 @@ DeleteObject(DeletingObjectEntry* e, voi
 #endif
 
         PluginModuleChild::DeallocNPObject(o);
     }
 
     return PL_DHASH_NEXT;
 }
 
-bool
-PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
+void
+PluginInstanceChild::SwapSurfaces()
 {
-    PLUGIN_LOG_DEBUG_METHOD;
-    AssertPluginThread();
-
-#if defined(OS_WIN)
-    SetProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty, (HANDLE)1);
+    nsRefPtr<gfxASurface> tmpsurf = mCurrentSurface;
+#ifdef XP_WIN
+    PPluginSurfaceChild* tmpactor = mCurrentSurfaceActor;
+#endif
+
+    mCurrentSurface = mBackSurface;
+#ifdef XP_WIN
+    mCurrentSurfaceActor = mBackSurfaceActor;
+#endif
+
+    mBackSurface = tmpsurf;
+#ifdef XP_WIN
+    mBackSurfaceActor = tmpactor;
 #endif
 
+    // Outdated back surface... not usable anymore due to changed plugin size.
+    // Dropping obsolete surface
+    if (mCurrentSurface && mBackSurface &&
+        mCurrentSurface->GetSize() != mBackSurface->GetSize()) {
+        mCurrentSurface = nsnull;
+#ifdef XP_WIN
+        if (mCurrentSurfaceActor) {
+            PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor);
+            mCurrentSurfaceActor = NULL;
+        }
+#endif
+    }
+}
+
+void
+PluginInstanceChild::ClearCurrentSurface()
+{
+    mCurrentSurface = nsnull;
+#ifdef XP_WIN
+    if (mCurrentSurfaceActor) {
+        PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor);
+        mCurrentSurfaceActor = NULL;
+    }
+#endif
+    mHelperSurface = nsnull;
+}
+
+void
+PluginInstanceChild::ClearAllSurfaces()
+{
     if (mBackSurface) {
         // Get last surface back, and drop it
         SurfaceDescriptor temp = null_t();
         NPRect r = { 0, 0, 1, 1 };
         SendShow(r, temp, &temp);
     }
     if (gfxSharedImageSurface::IsSharedImage(mCurrentSurface))
         DeallocShmem(static_cast<gfxSharedImageSurface*>(mCurrentSurface.get())->GetShmem());
     if (gfxSharedImageSurface::IsSharedImage(mBackSurface))
         DeallocShmem(static_cast<gfxSharedImageSurface*>(mBackSurface.get())->GetShmem());
     mCurrentSurface = nsnull;
     mBackSurface = nsnull;
 
+#ifdef XP_WIN
+    if (mCurrentSurfaceActor) {
+        PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor);
+        mCurrentSurfaceActor = NULL;
+    }
+    if (mBackSurfaceActor) {
+        PPluginSurfaceChild::Send__delete__(mBackSurfaceActor);
+        mBackSurfaceActor = NULL;
+    }
+#endif
+}
+
+bool
+PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
+{
+    PLUGIN_LOG_DEBUG_METHOD;
+    AssertPluginThread();
+
+#if defined(OS_WIN)
+    SetProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty, (HANDLE)1);
+#endif
+
     InfallibleTArray<PBrowserStreamChild*> streams;
     ManagedPBrowserStreamChild(streams);
 
     // First make sure none of these streams become deleted
     for (PRUint32 i = 0; i < streams.Length(); ) {
         if (static_cast<BrowserStreamChild*>(streams[i])->InstanceDying())
             ++i;
         else
@@ -3083,16 +3147,18 @@ PluginInstanceChild::AnswerNPP_Destroy(N
     }
 
     // NPP_Destroy() should be a synchronization point for plugin threads
     // calling NPN_AsyncCall: after this function returns, they are no longer
     // allowed to make async calls on this instance.
     PluginModuleChild::current()->NPP_Destroy(this);
     mData.ndata = 0;
 
+    ClearAllSurfaces();
+
     mDeletingHash = new nsTHashtable<DeletingObjectEntry>;
     mDeletingHash->Init();
     PluginModuleChild::current()->FindNPObjectsForInstance(this);
 
     mDeletingHash->EnumerateEntries(InvalidateObject, NULL);
     mDeletingHash->EnumerateEntries(DeleteObject, NULL);
 
     // Null out our cached actors as they should have been killed in the
--- a/dom/plugins/PluginInstanceChild.h
+++ b/dom/plugins/PluginInstanceChild.h
@@ -37,16 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef dom_plugins_PluginInstanceChild_h
 #define dom_plugins_PluginInstanceChild_h 1
 
 #include "mozilla/plugins/PPluginInstanceChild.h"
 #include "mozilla/plugins/PluginScriptableObjectChild.h"
 #include "mozilla/plugins/StreamNotifyChild.h"
+#include "mozilla/plugins/PPluginSurfaceChild.h"
 #if defined(OS_WIN)
 #include "mozilla/gfx/SharedDIBWin.h"
 #elif defined(OS_MACOSX)
 #include "nsCoreAnimationSupport.h"
 #include "base/timer.h"
 #endif
 
 #include "npfunctions.h"
@@ -103,16 +104,26 @@ protected:
     RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
                        const NPRemoteWindow& aWindow);
 
     virtual void
     DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
                      const NPRemoteWindow& aWindow,
                      bool aIsAsync);
 
+    virtual PPluginSurfaceChild* AllocPPluginSurface(const WindowsSharedMemoryHandle&,
+                                                     const gfxIntSize&, const bool&) {
+        return new PPluginSurfaceChild();
+    }
+
+    virtual bool DeallocPPluginSurface(PPluginSurfaceChild* s) {
+        delete s;
+        return true;
+    }
+
     NS_OVERRIDE
     virtual bool
     AnswerPaint(const NPRemoteEvent& event, int16_t* handled)
     {
         PaintTracker pt;
         return AnswerNPP_HandleEvent(event, handled);
     }
 
@@ -452,27 +463,42 @@ private:
 
     // Make sure that we have surface for rendering
     bool EnsureCurrentBuffer(void);
 
     // Helper function for delayed InvalidateRect call
     // non null mCurrentInvalidateTask will call this function
     void InvalidateRectDelayed(void);
 
+    // Clear mCurrentSurface/mCurrentSurfaceActor/mHelperSurface
+    void ClearCurrentSurface();
+
+    // Swap mCurrentSurface/mBackSurface and their associated actors
+    void SwapSurfaces();
+
+    // Clear all surfaces in response to NPP_Destroy
+    void ClearAllSurfaces();
+
     // Set as true when SetupLayer called
     // and go with different path in InvalidateRect function
     bool mLayersRendering;
 
     // Current surface available for rendering
     nsRefPtr<gfxASurface> mCurrentSurface;
 
     // Back surface, just keeping reference to
     // surface which is on ParentProcess side
     nsRefPtr<gfxASurface> mBackSurface;
 
+#ifdef XP_WIN
+    // These actors mirror mCurrentSurface/mBackSurface
+    PPluginSurfaceChild* mCurrentSurfaceActor;
+    PPluginSurfaceChild* mBackSurfaceActor;
+#endif
+
     // Accumulated invalidate rect, while back buffer is not accessible,
     // in plugin coordinates.
     nsIntRect mAccumulatedInvalidRect;
 
     // Plugin only call SetTransparent
     // and does not remember their transparent state
     // and p->getvalue return always false
     bool mIsTransparent;
--- a/dom/plugins/PluginInstanceParent.cpp
+++ b/dom/plugins/PluginInstanceParent.cpp
@@ -54,19 +54,17 @@
 #include "gfxXlibSurface.h"
 #endif
 #include "gfxContext.h"
 #include "gfxColor.h"
 #include "gfxUtils.h"
 
 #if defined(OS_WIN)
 #include <windowsx.h>
-#include "mozilla/gfx/SharedDIBSurface.h"
-
-using mozilla::gfx::SharedDIBSurface;
+#include "mozilla/plugins/PluginSurfaceParent.h"
 
 // Plugin focus event for widget.
 extern const PRUnichar* kOOPPPluginFocusEventId;
 UINT gOOPPPluginFocusEvent =
     RegisterWindowMessage(kOOPPPluginFocusEventId);
 extern const PRUnichar* kFlashFullscreenClass;
 UINT gOOPPSpinNativeLoopEvent =
     RegisterWindowMessage(L"SyncChannel Spin Inner Loop Message");
@@ -515,21 +513,20 @@ PluginInstanceParent::RecvShow(const NPR
         XRenderPictFormat *incFormat =
             XRenderFindFormat(DefaultXDisplay(), PictFormatID, &pf, 0);
         surface =
             new gfxXlibSurface(DefaultScreenOfDisplay(DefaultXDisplay()),
                                xdesc.XID(), incFormat, xdesc.size());
     }
 #endif
 #ifdef XP_WIN
-    else if (newSurface.type() == SurfaceDescriptor::TSurfaceDescriptorWin) {
-        SurfaceDescriptorWin windesc = newSurface.get_SurfaceDescriptorWin();
-        SharedDIBSurface* dibsurf = new SharedDIBSurface();
-        if (dibsurf->Attach(windesc.handle(), windesc.size().width, windesc.size().height, windesc.transparent()))
-            surface = dibsurf;
+    else if (newSurface.type() == SurfaceDescriptor::TPPluginSurfaceParent) {
+        PluginSurfaceParent* s =
+            static_cast<PluginSurfaceParent*>(newSurface.get_PPluginSurfaceParent());
+        surface = s->Surface();
     }
 #endif
 
 #ifdef MOZ_X11
     if (mFrontSurface &&
         mFrontSurface->GetType() == gfxASurface::SurfaceTypeXlib)
         XSync(DefaultXDisplay(), False);
 #endif
@@ -1127,16 +1124,40 @@ PluginInstanceParent::GetActorForNPObjec
         NS_WARNING("Failed to send constructor message!");
         return nsnull;
     }
 
     actor->InitializeLocal(aObject);
     return actor;
 }
 
+PPluginSurfaceParent*
+PluginInstanceParent::AllocPPluginSurface(const WindowsSharedMemoryHandle& handle,
+                                          const gfxIntSize& size,
+                                          const bool& transparent)
+{
+#ifdef XP_WIN
+    return new PluginSurfaceParent(handle, size, transparent);
+#else
+    NS_ERROR("This shouldn't be called!");
+    return NULL;
+#endif
+}
+
+bool
+PluginInstanceParent::DeallocPPluginSurface(PPluginSurfaceParent* s)
+{
+#ifdef XP_WIN
+    delete s;
+    return true;
+#else
+    return false;
+#endif
+}
+
 bool
 PluginInstanceParent::AnswerNPN_PushPopupsEnabledState(const bool& aState)
 {
     mNPNIface->pushpopupsenabledstate(mNPP, aState ? 1 : 0);
     return true;
 }
 
 bool
--- a/dom/plugins/PluginInstanceParent.h
+++ b/dom/plugins/PluginInstanceParent.h
@@ -171,16 +171,24 @@ public:
     RecvNPN_InvalidateRect(const NPRect& rect);
 
     // Async rendering
     virtual bool
     RecvShow(const NPRect& updatedRect,
              const SurfaceDescriptor& newSurface,
              SurfaceDescriptor* prevSurface);
 
+    virtual PPluginSurfaceParent*
+    AllocPPluginSurface(const WindowsSharedMemoryHandle& handle,
+                        const gfxIntSize& size,
+                        const bool& transparent);
+
+    virtual bool
+    DeallocPPluginSurface(PPluginSurfaceParent* s);
+
     virtual bool
     AnswerNPN_PushPopupsEnabledState(const bool& aState);
 
     virtual bool
     AnswerNPN_PopPopupsEnabledState();
 
     NS_OVERRIDE virtual bool
     AnswerNPN_GetValueForURL(const NPNURLVariable& variable,
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PluginSurfaceParent.cpp
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Firefox.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation <http://www.mozilla.org/>.
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mozilla/plugins/PluginSurfaceParent.h"
+#include "mozilla/gfx/SharedDIBSurface.h"
+
+using mozilla::gfx::SharedDIBSurface;
+
+namespace mozilla {
+namespace plugins {
+
+PluginSurfaceParent::PluginSurfaceParent(const WindowsSharedMemoryHandle& handle,
+                                         const gfxIntSize& size,
+                                         bool transparent)
+{
+  SharedDIBSurface* dibsurf = new SharedDIBSurface();
+  if (dibsurf->Attach(handle, size.width, size.height, transparent))
+    mSurface = dibsurf;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PluginSurfaceParent.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Firefox.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation <http://www.mozilla.org/>.
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef dom_plugins_PluginSurfaceParent_h
+#define dom_plugins_PluginSurfaceParent_h
+
+#include "mozilla/plugins/PPluginSurfaceParent.h"
+#include "gfxASurface.h"
+#include "nsAutoPtr.h"
+#include "mozilla/plugins/PluginMessageUtils.h"
+
+#ifndef XP_WIN
+#error "This header is for Windows only."
+#endif
+
+namespace mozilla {
+namespace plugins {
+
+class PluginSurfaceParent : public PPluginSurfaceParent
+{
+public:
+  PluginSurfaceParent(const WindowsSharedMemoryHandle& handle,
+                      const gfxIntSize& size,
+                      const bool transparent);
+  ~PluginSurfaceParent() { }
+
+  gfxASurface* Surface() { return mSurface; }
+
+private:
+  nsRefPtr<gfxASurface> mSurface;
+};
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif // dom_plugin_PluginSurfaceParent_h
--- a/dom/plugins/ipdl.mk
+++ b/dom/plugins/ipdl.mk
@@ -37,9 +37,10 @@
 IPDLSRCS = \
   PPluginModule.ipdl \
   PPluginIdentifier.ipdl \
   PPluginInstance.ipdl \
   PPluginScriptableObject.ipdl \
   PBrowserStream.ipdl \
   PPluginStream.ipdl \
   PStreamNotify.ipdl \
+  PPluginSurface.ipdl \
   $(NULL)