Bug 663259 - Enable Mac Async plugin by default. r=cjones,mattwoodrow
authorBenoit Girard <b56girard@gmail.com>
Tue, 12 Jul 2011 10:31:18 -0400
changeset 72713 5cea57e451ddfac20958edf83d6b15748ae12c3f
parent 72712 2d5bc18fdf9c40ee4d86411fb2713c8094814092
child 72714 ce95693001bc4038a9420f71d6df1f4b96b04130
push id20761
push usereakhgari@mozilla.com
push dateWed, 13 Jul 2011 15:40:29 +0000
treeherdermozilla-central@40a1936f6a2d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones, mattwoodrow
bugs663259
milestone8.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 663259 - Enable Mac Async plugin by default. r=cjones,mattwoodrow
browser/app/profile/firefox.js
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/plugins/base/nsPluginInstanceOwner.h
dom/plugins/ipc/Makefile.in
dom/plugins/ipc/PluginInstanceChild.cpp
dom/plugins/ipc/PluginInstanceChild.h
dom/plugins/ipc/PluginInstanceParent.cpp
dom/plugins/ipc/PluginInstanceParent.h
dom/plugins/ipc/PluginUtilsOSX.h
dom/plugins/ipc/PluginUtilsOSX.mm
dom/plugins/test/mochitest/utils.js
gfx/layers/opengl/MacIOSurfaceImageOGL.h
gfx/thebes/nsCoreAnimationSupport.h
gfx/thebes/nsCoreAnimationSupport.mm
layout/generic/nsObjectFrame.cpp
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -562,17 +562,17 @@ pref("accessibility.typeaheadfind.flashB
 // plugin finder service url
 pref("pfs.datasource.url", "https://pfs.mozilla.org/plugins/PluginFinderService.php?mimetype=%PLUGIN_MIMETYPE%&appID=%APP_ID%&appVersion=%APP_VERSION%&clientOS=%CLIENT_OS%&chromeLocale=%CHROME_LOCALE%&appRelease=%APP_RELEASE%");
 
 // by default we show an infobar message when pages require plugins the user has not installed, or are outdated
 pref("plugins.hide_infobar_for_missing_plugin", false);
 pref("plugins.hide_infobar_for_outdated_plugin", false);
 
 #ifdef XP_MACOSX
-pref("plugins.use_layers", false);
+pref("plugins.use_layers", true);
 pref("plugins.hide_infobar_for_carbon_failure_plugin", false);
 #endif
 
 pref("plugins.update.url", "https://www.mozilla.com/%LOCALE%/plugincheck/");
 pref("plugins.update.notifyUser", false);
 
 #ifdef XP_WIN
 pref("browser.preferences.instantApply", false);
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -82,17 +82,17 @@ nsNPAPIPluginInstance::nsNPAPIPluginInst
     mWindowlessLocal(PR_FALSE),
     mTransparent(PR_FALSE),
     mUsesDOMForCursor(PR_FALSE),
     mInPluginInitCall(PR_FALSE),
     mPlugin(plugin),
     mMIMEType(nsnull),
     mOwner(nsnull),
     mCurrentPluginEvent(nsnull),
-#if defined(MOZ_X11) || defined(XP_WIN)
+#if defined(MOZ_X11) || defined(XP_WIN) || defined(XP_MACOSX)
     mUsePluginLayersPref(PR_TRUE)
 #else
     mUsePluginLayersPref(PR_FALSE)
 #endif
 {
   NS_ASSERTION(mPlugin != NULL, "Plugin is required when creating an instance.");
 
   // Initialize the NPP structure.
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1472,18 +1472,18 @@ void nsPluginInstanceOwner::RenderCoreAn
   if (!mIOSurface || 
       (mIOSurface->GetWidth() != (size_t)aWidth || 
        mIOSurface->GetHeight() != (size_t)aHeight)) {
     delete mIOSurface;
 
     // If the renderer is backed by an IOSurface, resize it as required.
     mIOSurface = nsIOSurface::CreateIOSurface(aWidth, aHeight);
     if (mIOSurface) {
-      nsIOSurface *attachSurface = nsIOSurface::LookupSurface(
-                                      mIOSurface->GetIOSurfaceID());
+      nsRefPtr<nsIOSurface> attachSurface = nsIOSurface::LookupSurface(
+                                              mIOSurface->GetIOSurfaceID());
       if (attachSurface) {
         mCARenderer.AttachIOSurface(attachSurface);
       } else {
         NS_ERROR("IOSurface attachment failed");
         delete attachSurface;
         delete mIOSurface;
         mIOSurface = NULL;
       }
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -319,17 +319,17 @@ private:
   nsRefPtr<nsPluginHost>      mPluginHost;
   
 #ifdef XP_MACOSX
   NP_CGContext                              mCGPluginPortCopy;
 #ifndef NP_NO_QUICKDRAW
   NP_Port                                   mQDPluginPortCopy;
 #endif
   PRInt32                                   mInCGPaintLevel;
-  nsIOSurface                              *mIOSurface;
+  nsRefPtr<nsIOSurface>                     mIOSurface;
   nsCARenderer                              mCARenderer;
   CGColorSpaceRef                           mColorProfile;
   static nsCOMPtr<nsITimer>                *sCATimer;
   static nsTArray<nsPluginInstanceOwner*>  *sCARefreshListeners;
   PRBool                                    mSentInitialTopLevelWindowEvent;
 #endif
   // We need to know if async hide window is required since we
   // can not check UseAsyncRendering when executing StopPlugin
--- a/dom/plugins/ipc/Makefile.in
+++ b/dom/plugins/ipc/Makefile.in
@@ -70,16 +70,17 @@ EXPORTS_mozilla/plugins = \
   PluginModuleParent.h \
   PluginProcessParent.h \
   PluginScriptableObjectChild.h \
   PluginScriptableObjectParent.h \
   PluginScriptableObjectUtils.h \
   PluginScriptableObjectUtils-inl.h \
   PluginInstanceChild.h \
   PluginInstanceParent.h \
+  PluginUtilsOSX.h \
   AStream.h \
   BrowserStreamChild.h \
   BrowserStreamParent.h \
   PluginStreamChild.h \
   PluginStreamParent.h \
   PluginMessageUtils.h \
   PluginProcessParent.h \
   PluginProcessChild.h \
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -181,17 +181,17 @@ PluginInstanceChild::~PluginInstanceChil
 #if defined(MOZ_WIDGET_COCOA)
     if (mShColorSpace) {
         ::CGColorSpaceRelease(mShColorSpace);
     }
     if (mShContext) {
         ::CGContextRelease(mShContext);
     }
     if (mCGLayer) {
-        mozilla::plugins::PluginUtilsOSX::ReleaseCGLayer(mCGLayer);
+        PluginUtilsOSX::ReleaseCGLayer(mCGLayer);
     }
 #endif
 }
 
 int
 PluginInstanceChild::GetQuirks()
 {
     return PluginModuleChild::current()->GetQuirks();
@@ -839,17 +839,17 @@ PluginInstanceChild::AnswerNPP_HandleEve
                                                      int16_t* handled)
 {
     PLUGIN_LOG_DEBUG_FUNCTION;
     AssertPluginThread();
 
     PaintTracker pt;
 
     NPCocoaEvent evcopy = event.event;
-    nsIOSurface* surf = nsIOSurface::LookupSurface(surfaceid);
+    nsRefPtr<nsIOSurface> surf = nsIOSurface::LookupSurface(surfaceid);
     if (!surf) {
         NS_ERROR("Invalid IOSurface.");
         *handled = false;
         return false;
     }
 
     if (evcopy.type == NPCocoaEventDrawRect) {
         mCARenderer.AttachIOSurface(surf);
@@ -2572,72 +2572,63 @@ PluginInstanceChild::EnsureCurrentBuffer
 
     if (!MaybeCreatePlatformHelperSurface()) {
         NS_ERROR("Cannot create helper surface");
         return false;
     }
 
     return true;
 #else // XP_MACOSX
-    if (mCurrentIOSurface && 
-        (mCurrentIOSurface->GetWidth() != mWindow.width ||
-         mCurrentIOSurface->GetHeight() != mWindow.height) ) {
-        mCurrentIOSurface = nsnull;
-    }
-
-    if (!mCARenderer.isInit() || !mCurrentIOSurface) {
-        if (!mCurrentIOSurface) {
-            mCurrentIOSurface = nsIOSurface::CreateIOSurface(mWindow.width, mWindow.height);
-
-            nsIntRect toInvalidate(0, 0, mWindow.width, mWindow.height);
-            mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, toInvalidate);
-        }
-
-        if (!mCurrentIOSurface) {
-            NS_WARNING("Failed to allocate IOSurface");
-            return false;
-        }
-
-        nsIOSurface *rendererSurface = nsIOSurface::LookupSurface(mCurrentIOSurface->GetIOSurfaceID()); 
-        if (!rendererSurface) {
-            NS_WARNING("Failed to lookup IOSurface");
-            return false;
-        }
-        mCARenderer.AttachIOSurface(rendererSurface);
-
+
+    if (!mDoubleBufferCARenderer.HasCALayer()) {
         void *caLayer = nsnull;
         if (mDrawingModel == NPDrawingModelCoreGraphics) {
-            if (mCGLayer) {
-                mozilla::plugins::PluginUtilsOSX::ReleaseCGLayer(mCGLayer);
-                mCGLayer = nsnull;
+            if (!mCGLayer) {
+                caLayer = mozilla::plugins::PluginUtilsOSX::GetCGLayer(CallCGDraw, this);
+
+                if (!caLayer) {
+                    PLUGIN_LOG_DEBUG(("GetCGLayer failed."));
+                    return false;
+                }
             }
-
-            caLayer = mozilla::plugins::PluginUtilsOSX::GetCGLayer(CallCGDraw, this);
-            if (!caLayer) {
-                return false;
-            }
-
             mCGLayer = caLayer;
         } else {
             NPError result = mPluginIface->getvalue(GetNPP(),
                                      NPPVpluginCoreAnimationLayer,
                                      &caLayer);
             if (result != NPERR_NO_ERROR || !caLayer) {
                 PLUGIN_LOG_DEBUG(("Plugin requested CoreAnimation but did not "
                                   "provide CALayer."));
                 return false;
             }
         }
-
-        mCARenderer.SetupRenderer(caLayer, mWindow.width, mWindow.height);
-        // Flash needs to have the window set again after this step
+        mDoubleBufferCARenderer.SetCALayer(caLayer);
+    }
+
+    if (mDoubleBufferCARenderer.HasFrontSurface() &&
+        (mDoubleBufferCARenderer.GetFrontSurfaceWidth() != mWindow.width ||
+         mDoubleBufferCARenderer.GetFrontSurfaceHeight() != mWindow.height) ) {
+        mDoubleBufferCARenderer.ClearFrontSurface();
+    }
+
+    if (!mDoubleBufferCARenderer.HasFrontSurface()) {
+        bool allocSurface = mDoubleBufferCARenderer.InitFrontSurface(mWindow.width, 
+                                                           mWindow.height);
+        if (!allocSurface) {
+            PLUGIN_LOG_DEBUG(("Fail to allocate front IOSurface"));
+            return false;
+        }
+
         if (mPluginIface->setwindow)
             (void) mPluginIface->setwindow(&mData, &mWindow);
+
+        nsIntRect toInvalidate(0, 0, mWindow.width, mWindow.height);
+        mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, toInvalidate);
     }
-
+  
     return true;
 #endif
 }
 
 void
 PluginInstanceChild::UpdateWindowAttributes(bool aForceSetWindow)
 {
     nsRefPtr<gfxASurface> curSurface = mHelperSurface ? mHelperSurface : mCurrentSurface;
@@ -3025,62 +3016,64 @@ PluginInstanceChild::ShowPluginFrame()
         ClearCurrentSurface();
         return true;
     }
 
     if (!EnsureCurrentBuffer()) {
         return false;
     }
 
-#ifdef XP_MACOSX
+#ifdef MOZ_WIDGET_COCOA
     // We can't use the thebes code with CoreAnimation so we will
     // take a different code path.
     if (mDrawingModel == NPDrawingModelCoreAnimation ||
         mDrawingModel == NPDrawingModelInvalidatingCoreAnimation ||
         mDrawingModel == NPDrawingModelCoreGraphics) {
 
         if (!IsVisible()) {
             return true;
         }
 
+        if (!mDoubleBufferCARenderer.HasFrontSurface()) {
+            NS_ERROR("CARenderer not initialized for rendering");
+            return false;
+        }
+
         // Clear accRect here to be able to pass
         // test_invalidate_during_plugin_paint  test
         nsIntRect rect = mAccumulatedInvalidRect;
         mAccumulatedInvalidRect.SetEmpty();
 
         // Fix up old invalidations that might have been made when our
         // surface was a different size
         rect.IntersectRect(rect,
-                         nsIntRect(0, 0, mCurrentIOSurface->GetWidth(), mCurrentIOSurface->GetHeight()));
-      
-        if (!mCARenderer.isInit()) {
-            NS_ERROR("CARenderer not initialized");
-            return false;
-        }
+                          nsIntRect(0, 0, 
+                          mDoubleBufferCARenderer.GetFrontSurfaceWidth(), 
+                          mDoubleBufferCARenderer.GetFrontSurfaceHeight()));
 
         if (mDrawingModel == NPDrawingModelCoreGraphics) {
             mozilla::plugins::PluginUtilsOSX::Repaint(mCGLayer, rect);
         }
 
-        mCARenderer.Render(mWindow.width, mWindow.height, nsnull);
+        mDoubleBufferCARenderer.Render();
 
         NPRect r = { (uint16_t)rect.y, (uint16_t)rect.x,
                      (uint16_t)rect.YMost(), (uint16_t)rect.XMost() };
         SurfaceDescriptor currSurf;
-        currSurf = IOSurfaceDescriptor(mCurrentIOSurface->GetIOSurfaceID());
+        currSurf = IOSurfaceDescriptor(mDoubleBufferCARenderer.GetFrontSurfaceID());
 
         mHasPainted = true;
 
-        // Unused
         SurfaceDescriptor returnSurf;
 
         if (!SendShow(r, currSurf, &returnSurf)) {
             return false;
         }
 
+        SwapSurfaces();
         return true;
     } else {
         NS_ERROR("Unsupported drawing model for async layer rendering");
         return false;
     }
 #endif
 
     NS_ASSERTION(mWindow.width == (mWindow.clipRect.right - mWindow.clipRect.left) &&
@@ -3506,29 +3499,42 @@ PluginInstanceChild::SwapSurfaces()
     mCurrentSurfaceActor = mBackSurfaceActor;
 #endif
 
     mBackSurface = tmpsurf;
 #ifdef XP_WIN
     mBackSurfaceActor = tmpactor;
 #endif
 
+#ifdef MOZ_WIDGET_COCOA
+    mDoubleBufferCARenderer.SwapSurfaces();
+
     // Outdated back surface... not usable anymore due to changed plugin size.
     // Dropping obsolete surface
-    if (mCurrentSurface && mBackSurface &&
-        (mCurrentSurface->GetSize() != mBackSurface->GetSize() ||
-         mCurrentSurface->GetContentType() != mBackSurface->GetContentType())) {
-        ClearCurrentSurface();
+    if (mDoubleBufferCARenderer.HasFrontSurface() && 
+        mDoubleBufferCARenderer.HasBackSurface() &&
+        (mDoubleBufferCARenderer.GetFrontSurfaceWidth() != 
+            mDoubleBufferCARenderer.GetBackSurfaceWidth() ||
+        mDoubleBufferCARenderer.GetFrontSurfaceHeight() != 
+            mDoubleBufferCARenderer.GetBackSurfaceHeight())) {
+
+        mDoubleBufferCARenderer.ClearFrontSurface();
     }
+#endif //MOZ_WIDGET_COCOA
 }
 
 void
 PluginInstanceChild::ClearCurrentSurface()
 {
     mCurrentSurface = nsnull;
+#ifdef MOZ_WIDGET_COCOA
+    if (mDoubleBufferCARenderer.HasFrontSurface()) {
+        mDoubleBufferCARenderer.ClearFrontSurface();
+    }
+#endif
 #ifdef XP_WIN
     if (mCurrentSurfaceActor) {
         PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor);
         mCurrentSurfaceActor = NULL;
     }
 #endif
     mHelperSurface = nsnull;
 }
@@ -3537,16 +3543,17 @@ 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
@@ -3555,30 +3562,31 @@ PluginInstanceChild::ClearAllSurfaces()
         mCurrentSurfaceActor = NULL;
     }
     if (mBackSurfaceActor) {
         PPluginSurfaceChild::Send__delete__(mBackSurfaceActor);
         mBackSurfaceActor = NULL;
     }
 #endif
 
-#ifdef XP_MACOSX
-    if (mCurrentIOSurface) {
+#ifdef MOZ_WIDGET_COCOA
+    if (mDoubleBufferCARenderer.HasBackSurface()) {
         // Get last surface back, and drop it
         SurfaceDescriptor temp = null_t();
         NPRect r = { 0, 0, 1, 1 };
         SendShow(r, temp, &temp);
     }
 
     if (mCGLayer) {
         mozilla::plugins::PluginUtilsOSX::ReleaseCGLayer(mCGLayer);
         mCGLayer = nsnull;
     }
 
-    mCurrentIOSurface = nsnull;
+    mDoubleBufferCARenderer.ClearFrontSurface();
+    mDoubleBufferCARenderer.ClearBackSurface();
 #endif
 }
 
 bool
 PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
 {
     PLUGIN_LOG_DEBUG_METHOD;
     AssertPluginThread();
--- a/dom/plugins/ipc/PluginInstanceChild.h
+++ b/dom/plugins/ipc/PluginInstanceChild.h
@@ -41,18 +41,21 @@
 
 #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(MOZ_WIDGET_COCOA)
+#include "PluginUtilsOSX.h"
 #include "nsCoreAnimationSupport.h"
 #include "base/timer.h"
+
+using namespace mozilla::plugins::PluginUtilsOSX;
 #endif
 
 #include "npfunctions.h"
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
 #include "ChildAsyncCall.h"
 #include "ChildTimer.h"
 #include "nsRect.h"
@@ -519,17 +522,17 @@ private:
 
     // Back surface, just keeping reference to
     // surface which is on ParentProcess side
     nsRefPtr<gfxASurface> mBackSurface;
 
 #ifdef XP_MACOSX
     // Current IOSurface available for rendering
     // We can't use thebes gfxASurface like other platforms.
-    nsAutoPtr<nsIOSurface> mCurrentIOSurface; 
+    nsDoubleBufferCARenderer mDoubleBufferCARenderer; 
 #endif
 
     // (Not to be confused with mBackSurface).  This is a recent copy
     // of the opaque pixels under our object frame, if
     // |mIsTransparent|.  We ask the plugin render directly onto a
     // copy of the background pixels if available, and fall back on
     // alpha recovery otherwise.
     nsRefPtr<gfxASurface> mBackground;
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -514,29 +514,32 @@ PluginInstanceParent::RecvShow(const NPR
             return false;
         }
         surface = gfxSharedImageSurface::Open(newSurface.get_Shmem());
     }
 #ifdef XP_MACOSX
     else if (newSurface.type() == SurfaceDescriptor::TIOSurfaceDescriptor) {
         IOSurfaceDescriptor iodesc = newSurface.get_IOSurfaceDescriptor();
     
-        nsIOSurface *newIOSurface = nsIOSurface::LookupSurface(iodesc.surfaceId());
+        nsRefPtr<nsIOSurface> newIOSurface = nsIOSurface::LookupSurface(iodesc.surfaceId());
 
         if (!newIOSurface) {
             NS_WARNING("Got bad IOSurfaceDescriptor in RecvShow");
             return false;
         }
       
+        if (mFrontIOSurface)
+            *prevSurface = IOSurfaceDescriptor(mFrontIOSurface->GetIOSurfaceID());
+        else
+            *prevSurface = null_t();
+
         mFrontIOSurface = newIOSurface;
 
         RecvNPN_InvalidateRect(updatedRect);
 
-        *prevSurface = null_t();
-
         PLUGIN_LOG_DEBUG(("   (RecvShow invalidated for surface %p)",
                           mFrontSurface.get()));
 
         return true;
     }
 #endif
 #ifdef MOZ_X11
     else if (newSurface.type() == SurfaceDescriptor::TSurfaceDescriptorX11) {
--- a/dom/plugins/ipc/PluginInstanceParent.h
+++ b/dom/plugins/ipc/PluginInstanceParent.h
@@ -352,18 +352,18 @@ private:
 #endif // defined(XP_WIN)
 #if defined(MOZ_WIDGET_COCOA)
 private:
     Shmem                  mShSurface; 
     size_t                 mShWidth;
     size_t                 mShHeight;
     CGColorSpaceRef        mShColorSpace;
     int16_t                mDrawingModel;
-    nsAutoPtr<nsIOSurface> mIOSurface;
-    nsAutoPtr<nsIOSurface> mFrontIOSurface;
+    nsRefPtr<nsIOSurface> mIOSurface;
+    nsRefPtr<nsIOSurface> mFrontIOSurface;
 #endif // definied(MOZ_WIDGET_COCOA)
 
     // ObjectFrame layer wrapper
     nsRefPtr<gfxASurface>    mFrontSurface;
     // For windowless+transparent instances, this surface contains a
     // "pretty recent" copy of the pixels under its <object> frame.
     // On the plugin side, we use this surface to avoid doing alpha
     // recovery when possible.  This surface is created and owned by
--- a/dom/plugins/ipc/PluginUtilsOSX.h
+++ b/dom/plugins/ipc/PluginUtilsOSX.h
@@ -32,18 +32,22 @@
   * 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_PluginUtilsOSX_h
+#define dom_plugins_PluginUtilsOSX_h 1
+
 #include "npapi.h"
 #include "nsRect.h"
+#include "nsCoreAnimationSupport.h"
 
 namespace mozilla {
 namespace plugins {
 namespace PluginUtilsOSX {
 
 // Need to call back into the browser's message loop to process event.
 typedef void (*RemoteProcessEvents) (void*);
 
@@ -55,11 +59,49 @@ void InvokeNativeEventLoop();
 typedef void (*DrawPluginFunc) (CGContextRef, void*, nsIntRect aUpdateRect);
 
 void* GetCGLayer(DrawPluginFunc aFunc, void* aPluginInstance);
 void ReleaseCGLayer(void* cgLayer);
 void Repaint(void* cgLayer, nsIntRect aRect);
 
 bool SetProcessName(const char* aProcessName);
 
+/*
+ * Provides a wrapper around nsCARenderer to manage double buffering
+ * without having to unbind nsCARenderer on every surface swaps.
+ *
+ * The double buffer renderer begins with no initialize surfaces.
+ * The buffers can be initialized and cleared individually.
+ * Swapping still occurs regardless if the buffers are initialized.
+ */
+class THEBES_API nsDoubleBufferCARenderer {
+public:
+  nsDoubleBufferCARenderer() : mCALayer(nsnull) {}
+  size_t GetFrontSurfaceWidth();
+  size_t GetFrontSurfaceHeight();
+  size_t GetBackSurfaceWidth();
+  size_t GetBackSurfaceHeight();
+  IOSurfaceID GetFrontSurfaceID();
+
+  bool HasBackSurface();
+  bool HasFrontSurface();
+  bool HasCALayer();
+
+  void SetCALayer(void *aCALayer);
+  bool InitFrontSurface(size_t aWidth, size_t aHeight);
+  void Render();
+  void SwapSurfaces();
+  void ClearFrontSurface();
+  void ClearBackSurface();
+
+private:
+  void *mCALayer;
+  nsRefPtr<nsCARenderer> mFrontRenderer;
+  nsRefPtr<nsCARenderer> mBackRenderer;
+  nsRefPtr<nsIOSurface> mFrontSurface;
+  nsRefPtr<nsIOSurface> mBackSurface;
+};
+
 } // namespace PluginUtilsOSX
 } // namespace plugins
 } // namespace mozilla
+
+#endif //dom_plugins_PluginUtilsOSX_h
--- a/dom/plugins/ipc/PluginUtilsOSX.mm
+++ b/dom/plugins/ipc/PluginUtilsOSX.mm
@@ -271,8 +271,142 @@ bool mozilla::plugins::PluginUtilsOSX::S
   if (err != noErr) {
     NS_WARNING("Failed to set process name: LSSetInformationItemType err");
     return false;
   }
 
   return true;
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
 }
+
+namespace mozilla {
+namespace plugins {
+namespace PluginUtilsOSX {
+
+size_t nsDoubleBufferCARenderer::GetFrontSurfaceWidth() {
+  if (!HasFrontSurface()) {
+    return 0;
+  }
+
+  return mFrontSurface->GetWidth();
+}
+
+size_t nsDoubleBufferCARenderer::GetFrontSurfaceHeight() {
+  if (!HasFrontSurface()) {
+    return 0;
+  }
+
+  return mFrontSurface->GetHeight();
+}
+
+size_t nsDoubleBufferCARenderer::GetBackSurfaceWidth() {
+  if (!HasBackSurface()) {
+    return 0;
+  }
+
+  return mBackSurface->GetWidth();
+}
+
+size_t nsDoubleBufferCARenderer::GetBackSurfaceHeight() {
+  if (!HasBackSurface()) {
+    return 0;
+  }
+
+  return mBackSurface->GetHeight();
+}
+
+IOSurfaceID nsDoubleBufferCARenderer::GetFrontSurfaceID() {
+  if (!HasFrontSurface()) {
+    return 0;
+  }
+
+  return mFrontSurface->GetIOSurfaceID();
+}
+
+bool nsDoubleBufferCARenderer::HasBackSurface() {
+  return !!mBackSurface;
+}
+
+bool nsDoubleBufferCARenderer::HasFrontSurface() {
+  return !!mFrontSurface;
+}
+
+bool nsDoubleBufferCARenderer::HasCALayer() {
+  return !!mCALayer;
+}
+
+void nsDoubleBufferCARenderer::SetCALayer(void *aCALayer) {
+  mCALayer = aCALayer;
+}
+
+bool nsDoubleBufferCARenderer::InitFrontSurface(size_t aWidth, size_t aHeight) {
+  if (!mCALayer) {
+    return false;
+  }
+
+  mFrontSurface = nsIOSurface::CreateIOSurface(aWidth, aHeight);
+  if (!mFrontSurface) {
+    return false;
+  }
+
+  mFrontRenderer = new nsCARenderer();
+  if (!mFrontRenderer) {
+    mFrontSurface = nsnull;
+    return false;
+  }
+
+  nsRefPtr<nsIOSurface> ioSurface = nsIOSurface::LookupSurface(mFrontSurface->GetIOSurfaceID());
+  if (!ioSurface) {
+    mFrontRenderer = nsnull;
+    mFrontSurface = nsnull;
+    return false;
+  }
+
+  mFrontRenderer->AttachIOSurface(ioSurface);
+
+  nsresult result = mFrontRenderer->SetupRenderer(mCALayer, 
+                        ioSurface->GetWidth(), 
+                        ioSurface->GetHeight());
+
+  return result == NS_OK;
+}
+
+void nsDoubleBufferCARenderer::Render() {
+  if (!HasFrontSurface()) {
+    return;
+  }
+
+  mFrontRenderer->Render(GetFrontSurfaceWidth(), GetFrontSurfaceHeight(), nsnull);
+}
+
+void nsDoubleBufferCARenderer::SwapSurfaces() {
+  if (mFrontRenderer) {
+    mFrontRenderer->DettachCALayer();
+  }
+
+  nsRefPtr<nsCARenderer> prevFrontRenderer = mFrontRenderer;
+  nsRefPtr<nsIOSurface> prevFrontSurface = mFrontSurface;
+
+  mFrontRenderer = mBackRenderer;
+  mFrontSurface = mBackSurface;
+
+  mBackRenderer = prevFrontRenderer;
+  mBackSurface = prevFrontSurface;
+
+  if (mFrontRenderer) {
+    mFrontRenderer->AttachCALayer(mCALayer);
+  }
+}
+
+void nsDoubleBufferCARenderer::ClearFrontSurface() {
+  mFrontRenderer = nsnull;
+  mFrontSurface = nsnull;
+}
+
+void nsDoubleBufferCARenderer::ClearBackSurface() {
+  mBackRenderer = nsnull;
+  mBackSurface = nsnull;
+}
+
+} //PluginUtilsOSX
+} //plugins
+} //mozilla
+
--- a/dom/plugins/test/mochitest/utils.js
+++ b/dom/plugins/test/mochitest/utils.js
@@ -1,13 +1,12 @@
 function paintCountIs(plugin, expected, msg) {
   var count = plugin.getPaintCount();
   var realExpected = expected;
-  var isAsync = SimpleTest.testPluginIsOOP() &&
-    navigator.platform.indexOf("Mac") < 0;
+  var isAsync = SimpleTest.testPluginIsOOP();
   if (isAsync) {
     ++realExpected; // extra paint at startup for all async-rendering plugins
   } else {
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
     try {
       if (Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).D2DEnabled) {
         realExpected *= 2;
       }
--- a/gfx/layers/opengl/MacIOSurfaceImageOGL.h
+++ b/gfx/layers/opengl/MacIOSurfaceImageOGL.h
@@ -55,17 +55,17 @@ public:
   void SetUpdateCallback(UpdateSurfaceCallback aCallback, void* aPluginInstanceOwner);
   void SetDestroyCallback(DestroyCallback aCallback);
   void Update(ImageContainer* aContainer);
 
   void SetData(const Data &aData);
 
   GLTexture mTexture;
   gfxIntSize mSize;
-  nsAutoPtr<nsIOSurface> mIOSurface;
+  nsRefPtr<nsIOSurface> mIOSurface;
   void* mPluginInstanceOwner;
   UpdateSurfaceCallback mUpdateCallback;
   DestroyCallback mDestroyCallback;
 };
 
 } /* layers */
 } /* mozilla */
 #endif /* XP_MACOSX */
--- a/gfx/thebes/nsCoreAnimationSupport.h
+++ b/gfx/thebes/nsCoreAnimationSupport.h
@@ -36,76 +36,84 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsCoreAnimationSupport_h__
 #define nsCoreAnimationSupport_h__
 #ifdef XP_MACOSX
 
+#import <QuartzCore/QuartzCore.h>
 #import "ApplicationServices/ApplicationServices.h"
 #include "nscore.h"
 #include "gfxTypes.h"
-#import <QuartzCore/QuartzCore.h>
+#include "nsAutoPtr.h"
 
 // Get the system color space.
 CGColorSpaceRef THEBES_API CreateSystemColorSpace();
 
 // Manages a CARenderer
 struct _CGLPBufferObject;
 struct _CGLContextObject;
 class nsIOSurface;
 
+typedef uint32_t IOSurfaceID;
+
 class THEBES_API nsCARenderer {
+  NS_INLINE_DECL_REFCOUNTING(nsCARenderer)
 public:
   nsCARenderer() : mCARenderer(nsnull), mPixelBuffer(nsnull), mOpenGLContext(nsnull),
                    mCGImage(nsnull), mCGData(nsnull), mIOSurface(nsnull), mFBO(nsnull),
                    mIOTexture(nsnull), 
                    mUnsupportedWidth(UINT32_MAX), mUnsupportedHeight(UINT32_MAX) {}
   ~nsCARenderer();
   nsresult SetupRenderer(void* aCALayer, int aWidth, int aHeight);
   nsresult Render(int aWidth, int aHeight, CGImageRef *aOutCAImage);
   bool isInit() { return mCARenderer != nsnull; }
   /*
    * Render the CALayer to an IOSurface. If no IOSurface
    * is attached then an internal pixel buffer will be
    * used.
    */ 
-  void AttachIOSurface(nsIOSurface *aSurface);
+  void AttachIOSurface(nsRefPtr<nsIOSurface> aSurface);
+  IOSurfaceID GetIOSurfaceID();
   static nsresult DrawSurfaceToCGContext(CGContextRef aContext, 
                                          nsIOSurface *surf, 
                                          CGColorSpaceRef aColorSpace, 
                                          int aX, int aY,
                                          size_t aWidth, size_t aHeight);
-
+  
+  // Remove & Add the layer without destroying
+  // the renderer for fast back buffer swapping.
+  void DettachCALayer();
+  void AttachCALayer(void *aCALayer);
 #ifdef DEBUG
   static void SaveToDisk(nsIOSurface *surf);
 #endif
 private:
   void Destroy();
 
   void *mCARenderer;
-  _CGLPBufferObject *mPixelBuffer;
-  _CGLContextObject *mOpenGLContext;
-  CGImageRef         mCGImage;
-  void              *mCGData;
-  nsIOSurface       *mIOSurface;
-  uint32_t           mFBO;
-  uint32_t           mIOTexture;
-  uint32_t           mUnsupportedWidth;
-  uint32_t           mUnsupportedHeight;
+  _CGLPBufferObject     *mPixelBuffer;
+  _CGLContextObject     *mOpenGLContext;
+  CGImageRef             mCGImage;
+  void                  *mCGData;
+  nsRefPtr<nsIOSurface>  mIOSurface;
+  uint32_t               mFBO;
+  uint32_t               mIOTexture;
+  uint32_t               mUnsupportedWidth;
+  uint32_t               mUnsupportedHeight;
 };
 
-typedef uint32_t IOSurfaceID;
-
 class THEBES_API nsIOSurface {
+    NS_INLINE_DECL_REFCOUNTING(nsIOSurface)
 public:
-  static nsIOSurface *CreateIOSurface(int aWidth, int aHeight); 
+  static already_AddRefed<nsIOSurface> CreateIOSurface(int aWidth, int aHeight);
   static void ReleaseIOSurface(nsIOSurface *aIOSurface); 
-  static nsIOSurface *LookupSurface(IOSurfaceID aSurfaceID);
+  static already_AddRefed<nsIOSurface> LookupSurface(IOSurfaceID aSurfaceID);
 
   nsIOSurface(CFTypeRef aIOSurfacePtr) : mIOSurfacePtr(aIOSurfacePtr) {}
   ~nsIOSurface() { CFRelease(mIOSurfacePtr); }
   IOSurfaceID GetIOSurfaceID();
   void *GetBaseAddress();
   size_t GetWidth();
   size_t GetHeight();
   size_t GetBytesPerRow();
--- a/gfx/thebes/nsCoreAnimationSupport.mm
+++ b/gfx/thebes/nsCoreAnimationSupport.mm
@@ -262,17 +262,17 @@ void nsIOSurfaceLib::CloseLibrary() {
   }
   if (sOpenGLFramework) {
     dlclose(sOpenGLFramework);
   }
   sIOSurfaceFramework = nsnull;
   sOpenGLFramework = nsnull;
 }
 
-nsIOSurface* nsIOSurface::CreateIOSurface(int aWidth, int aHeight) { 
+already_AddRefed<nsIOSurface> nsIOSurface::CreateIOSurface(int aWidth, int aHeight) { 
   if (!nsIOSurfaceLib::isInit())
     return nsnull;
 
   CFMutableDictionaryRef props = ::CFDictionaryCreateMutable(
                       kCFAllocatorDefault, 4,
                       &kCFTypeDictionaryKeyCallBacks,
                       &kCFTypeDictionaryValueCallBacks);
   if (!props)
@@ -295,39 +295,39 @@ nsIOSurface* nsIOSurface::CreateIOSurfac
                                 kCFBooleanTrue);
 
   IOSurfacePtr surfaceRef = nsIOSurfaceLib::IOSurfaceCreate(props);
   ::CFRelease(props);
 
   if (!surfaceRef)
     return nsnull;
 
-  nsIOSurface* ioSurface = new nsIOSurface(surfaceRef);
+  nsRefPtr<nsIOSurface> ioSurface = new nsIOSurface(surfaceRef);
   if (!ioSurface) {
     ::CFRelease(surfaceRef);
     return nsnull;
   }
 
-  return ioSurface;
+  return ioSurface.forget();
 }
 
-nsIOSurface* nsIOSurface::LookupSurface(IOSurfaceID aIOSurfaceID) { 
+already_AddRefed<nsIOSurface> nsIOSurface::LookupSurface(IOSurfaceID aIOSurfaceID) { 
   if (!nsIOSurfaceLib::isInit())
     return nsnull;
 
   IOSurfacePtr surfaceRef = nsIOSurfaceLib::IOSurfaceLookup(aIOSurfaceID);
   if (!surfaceRef)
     return nsnull;
 
-  nsIOSurface* ioSurface = new nsIOSurface(surfaceRef);
+  nsRefPtr<nsIOSurface> ioSurface = new nsIOSurface(surfaceRef);
   if (!ioSurface) {
     ::CFRelease(surfaceRef);
     return nsnull;
   }
-  return ioSurface;
+  return ioSurface.forget();
 }
 
 IOSurfaceID nsIOSurface::GetIOSurfaceID() { 
   return nsIOSurfaceLib::IOSurfaceGetID(mIOSurfacePtr);
 }
 
 void* nsIOSurface::GetBaseAddress() { 
   return nsIOSurfaceLib::IOSurfaceGetBaseAddress(mIOSurfacePtr);
@@ -422,19 +422,16 @@ void nsCARenderer::Destroy() {
       if (oldContext)
         ::CGLSetCurrentContext(oldContext);
     }
     ::CGLDestroyContext((CGLContextObj)mOpenGLContext);
   }
   if (mCGImage) {
     ::CGImageRelease(mCGImage);
   }
-  if (mIOSurface) {
-    delete mIOSurface;
-  }
   // mCGData is deallocated by cgdata_release_callback
 
   mCARenderer = nil;
   mPixelBuffer = nsnull;
   mOpenGLContext = nsnull;
   mCGImage = nsnull;
   mIOSurface = nsnull;
   mFBO = nsnull;
@@ -507,17 +504,16 @@ nsresult nsCARenderer::SetupRenderer(voi
                                    [NSNull null], @"sublayers",
                                    [NSNull null], @"contents",
                                    [NSNull null], @"position",
                                    [NSNull null], @"bounds",
                                    nil];
   layer.actions = newActions;
   [newActions release];
 
-  double time = 0;
   [CATransaction setValue: [NSNumber numberWithFloat:0.0f] forKey: kCATransactionAnimationDuration];
   [CATransaction setValue: (id) kCFBooleanTrue forKey: kCATransactionDisableActions];
   [layer setBounds:CGRectMake(0, 0, aWidth, aHeight)];
   [layer setPosition:CGPointMake(aWidth/2.0, aHeight/2.0)];
   caRenderer.layer = layer;
   caRenderer.bounds = CGRectMake(0, 0, aWidth, aHeight);
   [CATransaction commit];
 
@@ -621,33 +617,41 @@ nsresult nsCARenderer::SetupRenderer(voi
   }
 
   if (oldContext)
     ::CGLSetCurrentContext(oldContext);
 
   return NS_OK;
 }
 
-void nsCARenderer::AttachIOSurface(nsIOSurface *aSurface) {
+void nsCARenderer::AttachIOSurface(nsRefPtr<nsIOSurface> aSurface) {
   if (mIOSurface && 
       aSurface->GetIOSurfaceID() == mIOSurface->GetIOSurfaceID()) {
-    delete aSurface; 
+    // This object isn't needed since we already have a
+    // handle to the same io surface.
+    aSurface = nsnull;
     return;
   }
   if (mCARenderer) {
     // We are attaching a larger IOSurface, we need to
     // resize our elements.
     Destroy(); 
   }
-  if (mIOSurface)
-    delete mIOSurface;
 
   mIOSurface = aSurface;
 }
 
+IOSurfaceID nsCARenderer::GetIOSurfaceID() {
+  if (!mIOSurface) {
+    return 0;
+  }
+
+  return mIOSurface->GetIOSurfaceID();
+}
+
 nsresult nsCARenderer::Render(int aWidth, int aHeight, 
                               CGImageRef *aOutCGImage) {
   if (!aOutCGImage && !mIOSurface) {
     NS_ERROR("No target destination for rendering");
   } else if (aOutCGImage) {
     // We are expected to return a CGImageRef, we will set
     // it to NULL in case we fail before the image is ready.
     *aOutCGImage = NULL;
@@ -777,16 +781,29 @@ nsresult nsCARenderer::DrawSurfaceToCGCo
                        subImage);
 
   ::CGImageRelease(subImage);
   ::CGImageRelease(cgImage);
   surf->Unlock();
   return NS_OK;
 }
 
+void nsCARenderer::DettachCALayer() {
+  CARenderer* caRenderer = (CARenderer*)mCARenderer;
+
+  caRenderer.layer = nil;
+}
+
+void nsCARenderer::AttachCALayer(void *aCALayer) {
+  CARenderer* caRenderer = (CARenderer*)mCARenderer;
+
+  CALayer* caLayer = (CALayer*)aCALayer;
+  caRenderer.layer = caLayer;
+}
+
 #ifdef DEBUG
 
 int sSaveToDiskSequence = 0;
 void nsCARenderer::SaveToDisk(nsIOSurface *surf) {
   surf->Lock();
   size_t bytesPerRow = surf->GetBytesPerRow();
   size_t ioWidth = surf->GetWidth();
   size_t ioHeight = surf->GetHeight();
@@ -829,8 +846,9 @@ void nsCARenderer::SaveToDisk(nsIOSurfac
 
   surf->Unlock();
 
   return;
 
 }
 
 #endif
+
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -1554,19 +1554,24 @@ nsObjectFrame::UpdateImageLayer(ImageCon
 LayerState
 nsObjectFrame::GetLayerState(nsDisplayListBuilder* aBuilder,
                              LayerManager* aManager)
 {
   if (!mInstanceOwner)
     return LAYER_NONE;
 
 #ifdef XP_MACOSX
-  if (aManager && aManager->GetBackendType() ==
-      LayerManager::LAYERS_OPENGL && 
-      !mInstanceOwner->UseAsyncRendering() &&
+  // Layer painting not supported without OpenGL
+  if (aManager && aManager->GetBackendType() !=
+      LayerManager::LAYERS_OPENGL) {
+    return LAYER_NONE;
+  }
+
+  // Synchronous painting, but with (gecko) layers.
+  if (!mInstanceOwner->UseAsyncRendering() &&
       mInstanceOwner->IsRemoteDrawingCoreAnimation() &&
       mInstanceOwner->GetEventModel() == NPEventModelCocoa) {
     return LAYER_ACTIVE;
   }
 #endif
 
   if (!mInstanceOwner->UseAsyncRendering()) {
     return LAYER_NONE;