Bug 651192 - Part 6: Implement the AsyncBitmapSurface drawing model support. r=roc
authorBas Schouten <bschouten@mozilla.com>
Thu, 16 Feb 2012 04:30:22 +0100
changeset 88077 ce22cc5a848b60d889757b558a81abdea2f0f1f2
parent 88076 cba4fa01e60f3ea65d8439a47c4cff9c91a1db35
child 88078 add138dc3cb03622b2fbb3004bbc30ed47b3c33c
push id22171
push usermak77@bonardo.net
push dateFri, 02 Mar 2012 13:56:30 +0000
treeherdermozilla-central@343ec916dfd5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs651192
milestone13.0a1
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 651192 - Part 6: Implement the AsyncBitmapSurface drawing model support. r=roc
dom/base/nsGlobalWindow.cpp
dom/plugins/base/nsIPluginInstanceOwner.idl
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsNPAPIPluginInstance.h
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/plugins/ipc/PPluginInstance.ipdl
dom/plugins/ipc/PluginInstanceChild.cpp
dom/plugins/ipc/PluginInstanceChild.h
dom/plugins/ipc/PluginInstanceParent.cpp
dom/plugins/ipc/PluginInstanceParent.h
dom/plugins/ipc/PluginMessageUtils.h
dom/plugins/ipc/PluginModuleChild.cpp
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -608,16 +608,22 @@ nsDummyJavaPluginOwner::InvalidateRect(N
 
 NS_IMETHODIMP
 nsDummyJavaPluginOwner::InvalidateRegion(NPRegion invalidRegion)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
+nsDummyJavaPluginOwner::RedrawPlugin()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 nsDummyJavaPluginOwner::GetNetscapeWindow(void *value)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsDummyJavaPluginOwner::SetEventModel(PRInt32 eventModel)
 {
--- a/dom/plugins/base/nsIPluginInstanceOwner.idl
+++ b/dom/plugins/base/nsIPluginInstanceOwner.idl
@@ -114,16 +114,21 @@ interface nsIPluginInstanceOwner : nsISu
   void invalidateRect(in NPRectPtr aRect);
 
   /**
    * Invalidate the region
    */
   void invalidateRegion(in NPRegion aRegion);
 
   /**
+   * Have the plugin recomposited.
+   */
+  void redrawPlugin();
+
+  /**
    * Get NetscapeWindow, corresponds to NPNVnetscapeWindow
    */
   void getNetscapeWindow(in voidPtr aValue);
 
   /**
    * Show native context menu
    */
 %{C++
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -698,16 +698,21 @@ nsNPAPIPluginInstance::UsesDOMForCursor(
   return mUsesDOMForCursor;
 }
 
 void nsNPAPIPluginInstance::SetDrawingModel(NPDrawingModel aModel)
 {
   mDrawingModel = aModel;
 }
 
+void nsNPAPIPluginInstance::RedrawPlugin()
+{
+  mOwner->RedrawPlugin();
+}
+
 #if defined(XP_MACOSX)
 void nsNPAPIPluginInstance::SetEventModel(NPEventModel aModel)
 {
   // the event model needs to be set for the object frame immediately
   nsCOMPtr<nsIPluginInstanceOwner> owner;
   GetOwner(getter_AddRefs(owner));
   if (!owner) {
     NS_WARNING("Trying to set event model without a plugin instance owner!");
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -149,16 +149,17 @@ public:
   NPError SetTransparent(bool aTransparent);
 
   NPError SetWantsAllNetworkStreams(bool aWantsAllNetworkStreams);
 
   NPError SetUsesDOMForCursor(bool aUsesDOMForCursor);
   bool UsesDOMForCursor();
 
   void SetDrawingModel(NPDrawingModel aModel);
+  void RedrawPlugin();
 #ifdef XP_MACOSX
   void SetEventModel(NPEventModel aModel);
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
   void NotifyForeground(bool aForeground);
   void NotifyOnScreen(bool aOnScreen);
   void MemoryPressure();
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -666,16 +666,25 @@ NS_IMETHODIMP nsPluginInstanceOwner::Inv
   mObjectFrame->InvalidateLayer(rect, nsDisplayItem::TYPE_PLUGIN);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
+ 
+NS_IMETHODIMP
+nsPluginInstanceOwner::RedrawPlugin()
+{
+  if (mObjectFrame) {
+    mObjectFrame->InvalidateLayer(mObjectFrame->GetContentRectRelativeToSelf(), nsDisplayItem::TYPE_PLUGIN);
+  }
+  return NS_OK;
+}
 
 NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
 {
   if (!mObjectFrame) {
     NS_WARNING("plugin owner has no owner in getting doc's window handle");
     return NS_ERROR_FAILURE;
   }
   
--- a/dom/plugins/ipc/PPluginInstance.ipdl
+++ b/dom/plugins/ipc/PPluginInstance.ipdl
@@ -56,16 +56,17 @@ using NPImageFormat;
 using NPNURLVariable;
 using NPCoordinateSpace;
 using mozilla::plugins::NativeWindowHandle;
 using mozilla::gfxSurfaceType;
 using gfxIntSize;
 using mozilla::null_t;
 using mozilla::plugins::WindowsSharedMemoryHandle;
 using mozilla::plugins::DXGISharedSurfaceHandle;
+using mozilla::CrossProcessMutexHandle;
 using SurfaceDescriptorX11;
 using nsIntRect;
 using nsTextEvent;
 using nsKeyEvent;
 
 namespace mozilla {
 namespace plugins {
 
@@ -81,28 +82,34 @@ union SurfaceDescriptor {
   // 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;
 };
 
+union OptionalShmem {
+  Shmem;
+  null_t;
+};
+
 union AsyncSurfaceDescriptor {
   Shmem;
   DXGISharedSurfaceHandle;
 };
 
 struct NPRemoteAsyncSurface
 {
   uint32_t version;
   gfxIntSize size;
   NPImageFormat format;
   uint32_t      stride;
   AsyncSurfaceDescriptor data;
+  uintptr_t hostPtr;
 };
 
 rpc protocol PPluginInstance
 {
   manager PPluginModule;
 
   manages PPluginBackgroundDestroyer;
   manages PPluginScriptableObject;
@@ -187,17 +194,17 @@ parent:
 
   rpc NPN_SetValue_NPPVpluginWindow(bool windowed)
     returns (NPError result);
   rpc NPN_SetValue_NPPVpluginTransparent(bool transparent)
     returns (NPError result);
   rpc NPN_SetValue_NPPVpluginUsesDOMForCursor(bool useDOMForCursor)
     returns (NPError result);
   rpc NPN_SetValue_NPPVpluginDrawingModel(int drawingModel)
-    returns (NPError result);
+    returns (OptionalShmem remoteImageData, CrossProcessMutexHandle mutex, NPError result);
   rpc NPN_SetValue_NPPVpluginEventModel(int eventModel)
     returns (NPError result);
 
   rpc NPN_GetURL(nsCString url, nsCString target)
     returns (NPError result);
   rpc NPN_PostURL(nsCString url, nsCString target, nsCString buffer, bool file)
     returns (NPError result);
 
@@ -243,16 +250,21 @@ parent:
                                 int32_t port, nsCString scheme,
                                 nsCString realm)
     returns (nsCString username, nsCString password, NPError result);
 
   rpc NPN_ConvertPoint(double sourceX, bool ignoreDestX, double sourceY, bool ignoreDestY, NPCoordinateSpace sourceSpace,
                        NPCoordinateSpace destSpace)
     returns (double destX, double destY, bool result);
 
+  async RedrawPlugin();
+
+  rpc NPN_InitAsyncSurface(gfxIntSize size, NPImageFormat format)
+    returns (NPRemoteAsyncSurface surfData, bool result);
+
   // Send notification that a plugin tried to negotiate Carbon NPAPI so that
   // users can be notified that restarting the browser in i386 mode may allow
   // them to use the plugin.
   sync NegotiatedCarbon();
 
 both:
   async PPluginScriptableObject();
 
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -70,16 +70,17 @@ using mozilla::gfx::SharedDIBSurface;
 
 #include "mozilla/Util.h"
 #include "mozilla/ipc/SyncChannel.h"
 #include "mozilla/AutoRestore.h"
 
 using namespace mozilla;
 using mozilla::ipc::ProcessChild;
 using namespace mozilla::plugins;
+using namespace std;
 
 #ifdef MOZ_WIDGET_GTK2
 
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
 #include <gdk/gdk.h>
 #include "gtk2xtbin.h"
 
@@ -128,16 +129,19 @@ struct RunnableMethodTraits<PluginInstan
 {
     static void RetainCallee(PluginInstanceChild* obj) { }
     static void ReleaseCallee(PluginInstanceChild* obj) { }
 };
 
 PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface)
     : mPluginIface(aPluginIface)
     , mDrawingModel(kDefaultDrawingModel)
+    , mCurrentAsyncSurface(0)
+    , mAsyncInvalidateMutex("PluginInstanceChild::mAsyncInvalidateMutex")
+    , mAsyncInvalidateTask(0)
     , mCachedWindowActor(nsnull)
     , mCachedElementActor(nsnull)
 #if defined(OS_WIN)
     , mPluginWindowHWND(0)
     , mPluginWndProc(0)
     , mPluginParentHWND(0)
     , mCachedWinlessPluginHWND(0)
     , mWinlessPopupSurrogateHWND(0)
@@ -170,16 +174,17 @@ PluginInstanceChild::PluginInstanceChild
     , mSurfaceDifferenceRect(0,0,0,0)
 #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
     , mMaemoImageRendering(true)
 #endif
 {
     memset(&mWindow, 0, sizeof(mWindow));
     mData.ndata = (void*) this;
     mData.pdata = nsnull;
+    mAsyncBitmaps.Init();
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
     mWindow.ws_info = &mWsInfo;
     memset(&mWsInfo, 0, sizeof(mWsInfo));
     mWsInfo.display = DefaultXDisplay();
 #endif // MOZ_X11 && XP_UNIX && !XP_MACOSX
 #if defined(OS_WIN)
     memset(&mAlphaExtract, 0, sizeof(mAlphaExtract));
 #endif // OS_WIN
@@ -529,26 +534,34 @@ PluginInstanceChild::NPN_SetValue(NPPVar
         }
         return rv;
     }
 
     case NPPVpluginDrawingModel: {
         NPError rv;
         int drawingModel = (int16) (intptr_t) aValue;
 
-        if (!PluginModuleChild::current()->AsyncDrawingAllowed()) {
-          if (drawingModel == NPDrawingModelAsyncBitmapSurface ||
-              drawingModel == NPDrawingModelAsyncWindowsDXGISurface ||
-              drawingModel == NPDrawingModelAsyncWindowsDX9ExSurface) {
+        if (!PluginModuleChild::current()->AsyncDrawingAllowed() &&
+            IsDrawingModelAsync(drawingModel)) {
+            return NPERR_GENERIC_ERROR;
+        }              
+
+        CrossProcessMutexHandle handle;
+        OptionalShmem optionalShmem;
+        if (!CallNPN_SetValue_NPPVpluginDrawingModel(drawingModel, &optionalShmem, &handle, &rv))
+            return NPERR_GENERIC_ERROR;
+
+        if (drawingModel == NPDrawingModelAsyncBitmapSurface) {
+            if (optionalShmem.type() != OptionalShmem::TShmem) {
                 return NPERR_GENERIC_ERROR;
-          }
-        }              
-
-        if (!CallNPN_SetValue_NPPVpluginDrawingModel(drawingModel, &rv))
-            return NPERR_GENERIC_ERROR;
+            }
+            mRemoteImageDataShmem = optionalShmem.get_Shmem();
+            mRemoteImageData = mRemoteImageDataShmem.get<RemoteImageData>();
+            mRemoteImageDataMutex = new CrossProcessMutex(handle);
+        }
         mDrawingModel = drawingModel;
 
 #ifdef XP_MACOSX
         if (drawingModel == NPDrawingModelCoreAnimation) {
             mCARefreshTimer = ScheduleTimer(DEFAULT_REFRESH_MS, true, CAUpdate);
         }
 #endif
 
@@ -2330,16 +2343,182 @@ PluginInstanceChild::NPN_URLRedirectResp
         if (sn->mClosure == notifyData) {
             sn->SendRedirectNotifyResponse(static_cast<bool>(allow));
             return;
         }
     }
     NS_ASSERTION(false, "Couldn't find stream for redirect response!");
 }
 
+NPError
+PluginInstanceChild::DeallocateAsyncBitmapSurface(NPAsyncSurface *aSurface)
+{
+    AsyncBitmapData* data;
+    
+    if (!mAsyncBitmaps.Get(aSurface, &data)) {
+        return NPERR_INVALID_PARAM;
+    }
+
+    DeallocShmem(data->mShmem);
+    aSurface->bitmap.data = nsnull;
+
+    mAsyncBitmaps.Remove(aSurface);
+    return NPERR_NO_ERROR;
+}
+
+bool
+PluginInstanceChild::IsAsyncDrawing()
+{
+    return IsDrawingModelAsync(mDrawingModel);
+}
+
+NPError
+PluginInstanceChild::NPN_InitAsyncSurface(NPSize *size, NPImageFormat format,
+                                          void *initData, NPAsyncSurface *surface)
+{
+    AssertPluginThread();
+
+    surface->bitmap.data = NULL;
+
+    if (!IsAsyncDrawing()) {
+        return NPERR_GENERIC_ERROR;
+    }
+
+    switch (mDrawingModel) {
+    case NPDrawingModelAsyncBitmapSurface: {
+            if (mAsyncBitmaps.Get(surface, nsnull)) {
+                return NPERR_INVALID_PARAM;
+            }
+
+            if (size->width < 0 || size->height < 0) {
+                return NPERR_INVALID_PARAM;
+            }
+
+
+            bool result;
+            NPRemoteAsyncSurface remote;
+
+            if (!CallNPN_InitAsyncSurface(gfxIntSize(size->width, size->height), format, &remote, &result) || !result) {
+                return NPERR_OUT_OF_MEMORY_ERROR;
+            }
+
+            NS_ABORT_IF_FALSE(remote.data().get_Shmem().IsWritable(),
+                "Failed to create writable shared memory.");
+            
+            AsyncBitmapData *data = new AsyncBitmapData;
+            mAsyncBitmaps.Put(surface, data);
+
+            data->mRemotePtr = (void*)remote.hostPtr();
+            data->mShmem = remote.data().get_Shmem();
+
+            surface->bitmap.data = data->mShmem.get<unsigned char>();
+            surface->bitmap.stride = remote.stride();
+            surface->format = remote.format();
+            surface->size.width = remote.size().width;
+            surface->size.height = remote.size().height;
+
+            return NPERR_NO_ERROR;
+        }
+    }
+
+    return NPERR_GENERIC_ERROR;
+}
+
+NPError
+PluginInstanceChild::NPN_FinalizeAsyncSurface(NPAsyncSurface *surface)
+{
+    AssertPluginThread();
+
+    if (!IsAsyncDrawing()) {
+        return NPERR_GENERIC_ERROR;
+    }
+
+    switch (mDrawingModel) {
+    case NPDrawingModelAsyncBitmapSurface: {
+            AsyncBitmapData *bitmapData;
+
+            if (!mAsyncBitmaps.Get(surface, &bitmapData)) {
+                return NPERR_GENERIC_ERROR;
+            }
+
+            {
+                CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
+                RemoteImageData *data = mRemoteImageData;
+                if (data->mBitmap.mData == bitmapData->mRemotePtr) {
+                    data->mBitmap.mData = NULL;
+                    data->mSize = gfxIntSize(0, 0);
+                    data->mWasUpdated = true;
+                }
+            }
+
+            return DeallocateAsyncBitmapSurface(surface);
+        }
+    }
+
+    return NPERR_GENERIC_ERROR;
+}
+
+void
+PluginInstanceChild::NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed)
+{
+    if (!IsAsyncDrawing()) {
+        return;
+    }
+
+    RemoteImageData *data = mRemoteImageData;
+
+    if (!surface) {
+        CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
+        data->mBitmap.mData = NULL;
+        data->mSize = gfxIntSize(0, 0);
+        data->mWasUpdated = true;
+    } else {
+        switch (mDrawingModel) {
+        case NPDrawingModelAsyncBitmapSurface:
+            {
+                AsyncBitmapData *bitmapData;
+        
+                if (!mAsyncBitmaps.Get(surface, &bitmapData)) {
+                    return;
+                }
+              
+                CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
+                data->mBitmap.mData = (unsigned char*)bitmapData->mRemotePtr;
+                data->mSize = gfxIntSize(surface->size.width, surface->size.height);
+                data->mFormat = surface->format == NPImageFormatBGRX32 ?
+                                RemoteImageData::BGRX32 : RemoteImageData::BGRA32;
+                data->mBitmap.mStride = surface->bitmap.stride;
+                data->mWasUpdated = true;
+                break;
+            }
+        }
+    }
+
+    {
+        MutexAutoLock autoLock(mAsyncInvalidateMutex);
+        if (!mAsyncInvalidateTask) {
+            mAsyncInvalidateTask = 
+                NewRunnableMethod<PluginInstanceChild, void (PluginInstanceChild::*)()>
+                    (this, &PluginInstanceChild::DoAsyncRedraw);
+            ProcessChild::message_loop()->PostTask(FROM_HERE, mAsyncInvalidateTask);
+        }
+    }
+}
+
+void
+PluginInstanceChild::DoAsyncRedraw()
+{
+    {
+        MutexAutoLock autoLock(mAsyncInvalidateMutex);
+        mAsyncInvalidateTask = NULL;
+    }
+
+    SendRedrawPlugin();
+}
+
 bool
 PluginInstanceChild::RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
                                         const NPRemoteWindow& aWindow)
 {
     AssertPluginThread();
 
     NS_ASSERTION(!aWindow.window, "Remote window should be null.");
 
@@ -3681,16 +3860,26 @@ PluginInstanceChild::ClearAllSurfaces()
         mCGLayer = nsnull;
     }
 
     mDoubleBufferCARenderer.ClearFrontSurface();
     mDoubleBufferCARenderer.ClearBackSurface();
 #endif
 }
 
+PLDHashOperator
+PluginInstanceChild::DeleteSurface(NPAsyncSurface* surf, nsAutoPtr<AsyncBitmapData> &data, void* userArg)
+{
+    PluginInstanceChild *inst = static_cast<PluginInstanceChild*>(userArg);
+
+    inst->DeallocShmem(data->mShmem);
+
+    return PL_DHASH_REMOVE;
+}
+
 bool
 PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
 {
     PLUGIN_LOG_DEBUG_METHOD;
     AssertPluginThread();
     *aResult = NPERR_NO_ERROR;
 
 #if defined(OS_WIN)
@@ -3721,16 +3910,23 @@ PluginInstanceChild::AnswerNPP_Destroy(N
     if (mCurrentInvalidateTask) {
         mCurrentInvalidateTask->Cancel();
         mCurrentInvalidateTask = nsnull;
     }
     if (mCurrentAsyncSetWindowTask) {
         mCurrentAsyncSetWindowTask->Cancel();
         mCurrentAsyncSetWindowTask = nsnull;
     }
+    {
+        MutexAutoLock autoLock(mAsyncInvalidateMutex);
+        if (mAsyncInvalidateTask) {
+            mAsyncInvalidateTask->Cancel();
+            mAsyncInvalidateTask = nsnull;
+        }
+    }
 
     ClearAllSurfaces();
 
     mDeletingHash = new nsTHashtable<DeletingObjectEntry>;
     mDeletingHash->Init();
     PluginModuleChild::current()->FindNPObjectsForInstance(this);
 
     mDeletingHash->EnumerateEntries(InvalidateObject, NULL);
@@ -3749,11 +3945,16 @@ PluginInstanceChild::AnswerNPP_Destroy(N
 #endif
 
     // Pending async calls are discarded, not delivered. This matches the
     // in-process behavior.
     for (PRUint32 i = 0; i < mPendingAsyncCalls.Length(); ++i)
         mPendingAsyncCalls[i]->Cancel();
 
     mPendingAsyncCalls.Clear();
+    
+    if (mAsyncBitmaps.Count()) {
+        NS_ERROR("Not all AsyncBitmaps were finalized by a plugin!");
+        mAsyncBitmaps.Enumerate(DeleteSurface, this);
+    }
 
     return true;
 }
--- a/dom/plugins/ipc/PluginInstanceChild.h
+++ b/dom/plugins/ipc/PluginInstanceChild.h
@@ -38,16 +38,18 @@
 
 #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"
+#include "mozilla/ipc/CrossProcessMutex.h"
+#include "nsClassHashtable.h"
 #if defined(OS_WIN)
 #include "mozilla/gfx/SharedDIBWin.h"
 #elif defined(MOZ_WIDGET_COCOA)
 #include "PluginUtilsOSX.h"
 #include "nsCoreAnimationSupport.h"
 #include "base/timer.h"
 
 using namespace mozilla::plugins::PluginUtilsOSX;
@@ -58,17 +60,24 @@ using namespace mozilla::plugins::Plugin
 #include "nsTArray.h"
 #include "ChildAsyncCall.h"
 #include "ChildTimer.h"
 #include "nsRect.h"
 #include "nsTHashtable.h"
 #include "mozilla/PaintTracker.h"
 #include "gfxASurface.h"
 
+#include <map>
+
 namespace mozilla {
+
+namespace layers {
+struct RemoteImageData;
+}
+
 namespace plugins {
 
 class PBrowserStreamChild;
 class BrowserStreamChild;
 class StreamNotifyChild;
 
 class PluginInstanceChild : public PPluginInstanceChild
 {
@@ -244,23 +253,34 @@ public:
     void UnscheduleTimer(uint32_t id);
 
     void AsyncCall(PluginThreadCallback aFunc, void* aUserData);
 
     int GetQuirks();
 
     void NPN_URLRedirectResponse(void* notifyData, NPBool allow);
 
+    NPError NPN_InitAsyncSurface(NPSize *size, NPImageFormat format,
+                                 void *initData, NPAsyncSurface *surface);
+    NPError NPN_FinalizeAsyncSurface(NPAsyncSurface *surface);
+
+    void NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed);
+
+    void DoAsyncRedraw();
 private:
     friend class PluginModuleChild;
 
     NPError
     InternalGetNPObjectForValue(NPNVariable aValue,
                                 NPObject** aObject);
 
+    bool IsAsyncDrawing();
+
+    NPError DeallocateAsyncBitmapSurface(NPAsyncSurface *aSurface);
+
     NS_OVERRIDE
     virtual bool RecvUpdateBackground(const SurfaceDescriptor& aBackground,
                                       const nsIntRect& aRect);
 
     NS_OVERRIDE
     virtual PPluginBackgroundDestroyerChild*
     AllocPPluginBackgroundDestroyer();
 
@@ -355,21 +375,33 @@ private:
         HWND                 mWnd;
         UINT                 mMsg;
         WPARAM               mWParam;
         LPARAM               mLParam;
         bool                 mWindowed;
     };
 
 #endif
-
     const NPPluginFuncs* mPluginIface;
     NPP_t mData;
     NPWindow mWindow;
     int16_t               mDrawingModel;
+    NPAsyncSurface* mCurrentAsyncSurface;
+    struct AsyncBitmapData {
+      void *mRemotePtr;
+      Shmem mShmem;
+    };
+
+    static PLDHashOperator DeleteSurface(NPAsyncSurface* surf, nsAutoPtr<AsyncBitmapData> &data, void* userArg);
+    nsClassHashtable<nsPtrHashKey<NPAsyncSurface>, AsyncBitmapData> mAsyncBitmaps;
+    Shmem mRemoteImageDataShmem;
+    mozilla::layers::RemoteImageData *mRemoteImageData;
+    nsAutoPtr<CrossProcessMutex> mRemoteImageDataMutex;
+    mozilla::Mutex mAsyncInvalidateMutex;
+    CancelableTask *mAsyncInvalidateTask;
 
     // Cached scriptable actors to avoid IPC churn
     PluginScriptableObjectChild* mCachedWindowActor;
     PluginScriptableObjectChild* mCachedElementActor;
 
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
     NPSetWindowCallbackStruct mWsInfo;
 #elif defined(OS_WIN)
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -117,16 +117,25 @@ PluginInstanceParent::~PluginInstancePar
 #endif
 #if defined(MOZ_WIDGET_COCOA)
     if (mShWidth != 0 && mShHeight != 0) {
         DeallocShmem(mShSurface);
     }
     if (mShColorSpace)
         ::CGColorSpaceRelease(mShColorSpace);
 #endif
+    if (mRemoteImageDataShmem.IsWritable()) {
+        ImageContainer *container =
+            GetImageContainer();
+
+        if (container) {
+            container->SetRemoteImageData(nsnull, nsnull);
+            DeallocShmem(mRemoteImageDataShmem);
+        }
+    }
 }
 
 bool
 PluginInstanceParent::Init()
 {
     return !!mScriptableObjects.Init();
 }
 
@@ -278,16 +287,22 @@ PluginInstanceParent::InternalGetValueFo
     }
 
     *aValue = nsnull;
     *aResult = result;
     return true;
 }
 
 bool
+PluginInstanceParent::IsAsyncDrawing()
+{
+  return IsDrawingModelAsync(mDrawingModel);
+}
+
+bool
 PluginInstanceParent::AnswerNPN_GetValue_NPNVWindowNPObject(
                                          PPluginScriptableObjectParent** aValue,
                                          NPError* aResult)
 {
     return InternalGetValueForNPObject(NPNVWindowNPObject, aValue, aResult);
 }
 
 bool
@@ -347,38 +362,81 @@ PluginInstanceParent::AnswerNPN_SetValue
 {
     *result = mNPNIface->setvalue(mNPP, NPPVpluginUsesDOMForCursorBool,
                                   (void*)(NPBool)useDOMForCursor);
     return true;
 }
 
 bool
 PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginDrawingModel(
-    const int& drawingModel, NPError* result)
+    const int& drawingModel, OptionalShmem *shmem, CrossProcessMutexHandle *mutex, NPError* result)
 {
 #ifdef XP_MACOSX
     if (drawingModel == NPDrawingModelCoreAnimation ||
         drawingModel == NPDrawingModelInvalidatingCoreAnimation) {
         // We need to request CoreGraphics otherwise
         // the nsObjectFrame will try to draw a CALayer
         // that can not be shared across process.
         mDrawingModel = drawingModel;
         *result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
                                   (void*)NPDrawingModelCoreGraphics);
     } else
 #endif
-    {
-        if (!GetImageContainer()) {
-          *result = NPERR_GENERIC_ERROR;
-          return true;
+    if (drawingModel == NPDrawingModelAsyncBitmapSurface) {
+        ImageContainer *container = GetImageContainer();
+        if (!container) {
+            *result = NPERR_GENERIC_ERROR;
+            return true;
+        }
+
+        mDrawingModel = drawingModel;
+        *result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
+                                        (void*)drawingModel);
+
+
+        if (*result != NPERR_NO_ERROR) {
+            return true;
+        }
+
+        AllocUnsafeShmem(sizeof(RemoteImageData), SharedMemory::TYPE_BASIC, &mRemoteImageDataShmem);
+
+        *shmem = mRemoteImageDataShmem;
+
+        mRemoteImageDataMutex = new CrossProcessMutex("PluginInstanceParent.mRemoteImageDataMutex");
+
+        *mutex = mRemoteImageDataMutex->ShareToProcess(OtherProcess());
+        container->SetRemoteImageData(mRemoteImageDataShmem.get<RemoteImageData>(), mRemoteImageDataMutex);
+    } else if (drawingModel == NPDrawingModelSyncWin ||
+#ifdef XP_MACOSX
+#ifndef NP_NO_QUICKDRAW
+               drawingModel == NPDrawingModelQuickDraw ||
+#endif
+               drawingModel == NPDrawingModelOpenGL ||
+               drawingModel == NPDrawingModelCoreGraphics ||
+#endif
+               drawingModel == NPDrawingModelSyncX) {
+        *shmem = null_t();
+
+        ImageContainer *container = GetImageContainer();
+        if (!container) {
+            *result = NPERR_GENERIC_ERROR;
+            return true;
         }
 
         mDrawingModel = drawingModel;
         *result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
                                       (void*)drawingModel);
+
+        if (mRemoteImageDataShmem.IsWritable()) {
+            container->SetRemoteImageData(nsnull, nsnull);
+            DeallocShmem(mRemoteImageDataShmem);
+            mRemoteImageDataMutex = NULL;
+        }
+    } else {
+        *result = NPERR_GENERIC_ERROR;
     }
     return true;
 }
 
 bool
 PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginEventModel(
     const int& eventModel, NPError* result)
 {
@@ -646,16 +704,22 @@ PluginInstanceParent::GetImageContainer(
 #endif
 
     ImageContainer *container = GetImageContainer();
 
     if (!container) {
         return NS_ERROR_FAILURE;
     }
 
+    if (IsAsyncDrawing()) {
+      NS_IF_ADDREF(container);
+      *aContainer = container;
+      return NS_OK;
+    }
+
     nsRefPtr<Image> image;
     image = container->CreateImage(&format, 1);
     if (!image) {
         return NS_ERROR_FAILURE;
     }
 
 #ifdef XP_MACOSX
     if (ioSurface) {
@@ -1100,16 +1164,22 @@ PluginInstanceParent::NPP_HandleEvent(vo
     NPEvent* npevent = reinterpret_cast<NPEvent*>(event);
 #endif
     NPRemoteEvent npremoteevent;
     npremoteevent.event = *npevent;
     int16_t handled = 0;
 
 #if defined(OS_WIN)
     if (mWindowType == NPWindowTypeDrawable) {
+        if (IsAsyncDrawing()) {
+            if (npevent->event == WM_PAINT || npevent->event == DoublePassRenderingEvent()) {
+                // This plugin maintains its own async drawing.
+                return handled;
+            }
+        }
         if (DoublePassRenderingEvent() == npevent->event) {
             CallPaint(npremoteevent, &handled);
             return handled;
         }
 
         switch (npevent->event) {
             case WM_PAINT:
             {
@@ -1602,24 +1672,67 @@ PluginInstanceParent::AnswerNPN_ConvertP
                                       ignoreDestX ? nsnull : destX,
                                       ignoreDestY ? nsnull : destY,
                                       destSpace);
 
     return true;
 }
 
 bool
+PluginInstanceParent::AnswerNPN_InitAsyncSurface(const gfxIntSize& size,
+                                                 const NPImageFormat& format,
+                                                 NPRemoteAsyncSurface* surfData,
+                                                 bool* result)
+{
+    if (!IsAsyncDrawing()) {
+        *result = false;
+        return true;
+    }
+
+    switch (mDrawingModel) {
+    case NPDrawingModelAsyncBitmapSurface: {
+            Shmem sharedMem;
+            if (!AllocUnsafeShmem(size.width * size.height * 4, SharedMemory::TYPE_BASIC, &sharedMem)) {
+                *result = false;
+                return true;
+            }
+
+            surfData->size() = size;
+            surfData->hostPtr() = (uintptr_t)sharedMem.get<unsigned char>();
+            surfData->stride() = size.width * 4;
+            surfData->format() = format;
+            surfData->data() = sharedMem;
+            *result = true;
+        }
+    }
+
+    return true;
+}
+
+bool
+PluginInstanceParent::RecvRedrawPlugin()
+{
+    nsNPAPIPluginInstance *inst = static_cast<nsNPAPIPluginInstance*>(mNPP->ndata);
+    if (!inst) {
+        return false;
+    }
+
+    inst->RedrawPlugin();
+    return true;
+}
+
+bool
 PluginInstanceParent::RecvNegotiatedCarbon()
 {
-  nsNPAPIPluginInstance *inst = static_cast<nsNPAPIPluginInstance*>(mNPP->ndata);
-  if (!inst) {
-    return false;
-  }
-  inst->CarbonNPAPIFailure();
-  return true;
+    nsNPAPIPluginInstance *inst = static_cast<nsNPAPIPluginInstance*>(mNPP->ndata);
+    if (!inst) {
+        return false;
+    }
+    inst->CarbonNPAPIFailure();
+    return true;
 }
 
 #if defined(OS_WIN)
 
 /*
   plugin focus changes between processes
 
   focus from dom -> child:
--- a/dom/plugins/ipc/PluginInstanceParent.h
+++ b/dom/plugins/ipc/PluginInstanceParent.h
@@ -139,17 +139,19 @@ public:
     virtual bool
     AnswerNPN_SetValue_NPPVpluginTransparent(const bool& transparent,
                                              NPError* result);
     virtual bool
     AnswerNPN_SetValue_NPPVpluginUsesDOMForCursor(const bool& useDOMForCursor,
                                                   NPError* result);
     virtual bool
     AnswerNPN_SetValue_NPPVpluginDrawingModel(const int& drawingModel,
-                                             NPError* result);
+                                              OptionalShmem *remoteImageData,
+                                              CrossProcessMutexHandle *mutex,
+                                              NPError* result);
     virtual bool
     AnswerNPN_SetValue_NPPVpluginEventModel(const int& eventModel,
                                              NPError* result);
 
     virtual bool
     AnswerNPN_GetURL(const nsCString& url, const nsCString& target,
                      NPError *result);
 
@@ -224,16 +226,25 @@ public:
                            const double& sourceY,
                            const bool&   ignoreDestY,
                            const NPCoordinateSpace& sourceSpace,
                            const NPCoordinateSpace& destSpace,
                            double *destX,
                            double *destY,
                            bool *result);
 
+    virtual bool
+    AnswerNPN_InitAsyncSurface(const gfxIntSize& size,
+                               const NPImageFormat& format,
+                               NPRemoteAsyncSurface* surfData,
+                               bool* result);
+
+    virtual bool
+    RecvRedrawPlugin();
+
     NS_OVERRIDE virtual bool
     RecvNegotiatedCarbon();
 
     NPError NPP_SetWindow(const NPWindow* aWindow);
 
     NPError NPP_GetValue(NPPVariable variable, void* retval);
     NPError NPP_SetValue(NPNVariable variable, void* value);
 
@@ -311,21 +322,25 @@ private:
     NS_OVERRIDE
     virtual bool
     DeallocPPluginBackgroundDestroyer(PPluginBackgroundDestroyerParent* aActor);
 
     bool InternalGetValueForNPObject(NPNVariable aVariable,
                                      PPluginScriptableObjectParent** aValue,
                                      NPError* aResult);
 
+    bool IsAsyncDrawing();
+
 private:
     PluginModuleParent* mParent;
     NPP mNPP;
     const NPNetscapeFuncs* mNPNIface;
     NPWindowType mWindowType;
+    Shmem mRemoteImageDataShmem;
+    nsAutoPtr<CrossProcessMutex> mRemoteImageDataMutex;
     int16_t            mDrawingModel;
 
     nsDataHashtable<nsVoidPtrHashKey, PluginScriptableObjectParent*> mScriptableObjects;
 
 #if defined(OS_WIN)
 private:
     // Used in rendering windowless plugins in other processes.
     bool SharedSurfaceSetWindow(const NPWindow* aWindow, NPRemoteWindow& aRemoteWindow);
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -38,16 +38,17 @@
 
 #ifndef DOM_PLUGINS_PLUGINMESSAGEUTILS_H
 #define DOM_PLUGINS_PLUGINMESSAGEUTILS_H
 
 #include "IPC/IPCMessageUtils.h"
 #include "base/message_loop.h"
 
 #include "mozilla/ipc/RPCChannel.h"
+#include "mozilla/ipc/CrossProcessMutex.h"
 #include "gfxipc/ShadowLayerUtils.h"
 
 #include "npapi.h"
 #include "npruntime.h"
 #include "npfunctions.h"
 #include "nsAutoPtr.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
@@ -83,16 +84,25 @@ std::string
 MungePluginDsoPath(const std::string& path);
 std::string
 UnmungePluginDsoPath(const std::string& munged);
 
 extern PRLogModuleInfo* gPluginLog;
 
 const uint32_t kAllowAsyncDrawing = 0x1;
 
+inline bool IsDrawingModelAsync(int16_t aModel) {
+  return aModel == NPDrawingModelAsyncBitmapSurface
+#ifdef XP_WIN
+         || aModel == NPDrawingModelAsyncWindowsDXGISurface
+         || aModel == NPDrawingModelAsyncWindowsDX9ExSurface
+#endif
+         ;
+}
+
 #if defined(_MSC_VER)
 #define FULLFUNCTION __FUNCSIG__
 #elif (__GNUC__ >= 4)
 #define FULLFUNCTION __PRETTY_FUNCTION__
 #else
 #define FULLFUNCTION __FUNCTION__
 #endif
 
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -970,16 +970,27 @@ static NPError NP_CALLBACK
 static NPBool NP_CALLBACK
 _convertpoint(NPP instance, 
               double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
               double *destX, double *destY, NPCoordinateSpace destSpace);
 
 static void NP_CALLBACK
 _urlredirectresponse(NPP instance, void* notifyData, NPBool allow);
 
+static NPError NP_CALLBACK
+_initasyncsurface(NPP instance, NPSize *size,
+                  NPImageFormat format, void *initData,
+                  NPAsyncSurface *surface);
+
+static NPError NP_CALLBACK
+_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface);
+
+static void NP_CALLBACK
+_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed);
+
 } /* namespace child */
 } /* namespace plugins */
 } /* namespace mozilla */
 
 const NPNetscapeFuncs PluginModuleChild::sBrowserFuncs = {
     sizeof(sBrowserFuncs),
     (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR,
     mozilla::plugins::child::_geturl,
@@ -1031,17 +1042,20 @@ const NPNetscapeFuncs PluginModuleChild:
     mozilla::plugins::child::_setvalueforurl,
     mozilla::plugins::child::_getauthenticationinfo,
     mozilla::plugins::child::_scheduletimer,
     mozilla::plugins::child::_unscheduletimer,
     mozilla::plugins::child::_popupcontextmenu,
     mozilla::plugins::child::_convertpoint,
     NULL, // handleevent, unimplemented
     NULL, // unfocusinstance, unimplemented
-    mozilla::plugins::child::_urlredirectresponse
+    mozilla::plugins::child::_urlredirectresponse,
+    mozilla::plugins::child::_initasyncsurface,
+    mozilla::plugins::child::_finalizeasyncsurface,
+    mozilla::plugins::child::_setcurrentasyncsurface
 };
 
 PluginInstanceChild*
 InstCast(NPP aNPP)
 {
     NS_ABORT_IF_FALSE(!!(aNPP->ndata), "nil instance");
     return static_cast<PluginInstanceChild*>(aNPP->ndata);
 }
@@ -1804,16 +1818,36 @@ NPBool NP_CALLBACK
 }
 
 void NP_CALLBACK
 _urlredirectresponse(NPP instance, void* notifyData, NPBool allow)
 {
     InstCast(instance)->NPN_URLRedirectResponse(notifyData, allow);
 }
 
+NPError NP_CALLBACK
+_initasyncsurface(NPP instance, NPSize *size,
+                  NPImageFormat format, void *initData,
+                  NPAsyncSurface *surface)
+{
+    return InstCast(instance)->NPN_InitAsyncSurface(size, format, initData, surface);
+}
+
+NPError NP_CALLBACK
+_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface)
+{
+    return InstCast(instance)->NPN_FinalizeAsyncSurface(surface);
+}
+
+void NP_CALLBACK
+_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
+{
+    InstCast(instance)->NPN_SetCurrentAsyncSurface(surface, changed);
+}
+
 } /* namespace child */
 } /* namespace plugins */
 } /* namespace mozilla */
 
 //-----------------------------------------------------------------------------
 
 bool
 PluginModuleChild::AnswerNP_GetEntryPoints(NPError* _retval)