Bug 688342 - Make nsCanvasRenderingContext2D support Azure backends other than Direct2D. r=Bas
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 03 Nov 2011 08:55:03 +1300
changeset 79589 cf97283ed45fdc984c619583620c34fce906bfc7
parent 79588 50f566a3b44999ff53dea0c78779d249251ef33b
child 79590 58e6c346c72ab29a450bfddd7e85c1a11a96c071
push id3070
push usermwoodrow@mozilla.com
push dateWed, 02 Nov 2011 19:55:20 +0000
treeherdermozilla-inbound@a204fcf29e60 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas
bugs688342
milestone10.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 688342 - Make nsCanvasRenderingContext2D support Azure backends other than Direct2D. r=Bas
content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
gfx/layers/Layers.cpp
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/CanvasLayerOGL.h
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxPlatformMac.cpp
gfx/thebes/gfxPlatformMac.h
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
widget/src/cocoa/GfxInfo.mm
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -983,33 +983,32 @@ NS_INTERFACE_MAP_END
 // Initialize our static variables.
 PRUint32 nsCanvasRenderingContext2DAzure::sNumLivingContexts = 0;
 PRUint8 (*nsCanvasRenderingContext2DAzure::sUnpremultiplyTable)[256] = nsnull;
 PRUint8 (*nsCanvasRenderingContext2DAzure::sPremultiplyTable)[256] = nsnull;
 
 nsresult
 NS_NewCanvasRenderingContext2DAzure(nsIDOMCanvasRenderingContext2D** aResult)
 {
-#ifndef XP_WIN
-  return NS_ERROR_NOT_AVAILABLE;
-#else
-
+#ifdef XP_WIN
   if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() !=
       gfxWindowsPlatform::RENDER_DIRECT2D ||
       !gfxWindowsPlatform::GetPlatform()->DWriteEnabled()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
+#elif !defined XP_MACOSX
+  return NS_ERROR_NOT_AVAILABLE;
+#endif
 
   nsRefPtr<nsIDOMCanvasRenderingContext2D> ctx = new nsCanvasRenderingContext2DAzure();
   if (!ctx)
     return NS_ERROR_OUT_OF_MEMORY;
 
   *aResult = ctx.forget().get();
   return NS_OK;
-#endif
 }
 
 nsCanvasRenderingContext2DAzure::nsCanvasRenderingContext2DAzure()
   : mValid(false), mZero(false), mOpaque(false), mResetLayer(true)
   , mIPC(false)
   , mCanvasElement(nsnull)
   , mIsEntireFrameInvalid(false)
   , mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false)
@@ -1248,17 +1247,17 @@ nsCanvasRenderingContext2DAzure::SetDime
     if (ownerDoc) {
       layerManager =
         nsContentUtils::PersistentLayerManagerForDocument(ownerDoc);
     }
 
     if (layerManager) {
       target = layerManager->CreateDrawTarget(size, format);
     } else {
-      target = Factory::CreateDrawTarget(BACKEND_DIRECT2D, size, format);
+      target = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(size, format);
     }
   }
 
   if (target) {
     if (gCanvasAzureMemoryReporter == nsnull) {
         gCanvasAzureMemoryReporter = new NS_MEMORY_REPORTER_NAME(CanvasAzureMemory);
       NS_RegisterMemoryReporter(gCanvasAzureMemoryReporter);
     }
@@ -1288,17 +1287,17 @@ nsCanvasRenderingContext2DAzure::Initial
 
   mResetLayer = true;
 
   /* Create dummy surfaces here - target can be null when a canvas was created
    * that is too large to support.
    */
   if (!target)
   {
-    mTarget = Factory::CreateDrawTarget(BACKEND_DIRECT2D, IntSize(1, 1), FORMAT_B8G8R8A8);
+    mTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(IntSize(1, 1), FORMAT_B8G8R8A8);
   } else {
     mValid = true;
   }
 
   // set up the initial canvas defaults
   mStyleStack.Clear();
   mPathBuilder = nsnull;
   mPath = nsnull;
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -213,18 +213,18 @@ LayerManager::CreateOptimalSurface(const
   return gfxPlatform::GetPlatform()->
     CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFormat));
 }
 
 TemporaryRef<DrawTarget>
 LayerManager::CreateDrawTarget(const IntSize &aSize,
                                SurfaceFormat aFormat)
 {
-  // Right now this doesn't work on the general layer manager.
-  return NULL;
+  return gfxPlatform::GetPlatform()->
+    CreateOffscreenDrawTarget(aSize, aFormat);
 }
 
 #ifdef DEBUG
 void
 LayerManager::Mutated(Layer* aLayer)
 {
 }
 #endif  // DEBUG
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -40,16 +40,17 @@
 
 #include "gfxSharedImageSurface.h"
 
 #include "CanvasLayerOGL.h"
 
 #include "gfxImageSurface.h"
 #include "gfxContext.h"
 #include "GLContextProvider.h"
+#include "gfxPlatform.h"
 
 #ifdef XP_WIN
 #include "gfxWindowsSurface.h"
 #include "WGLLibrary.h"
 #endif
 
 #ifdef XP_MACOSX
 #include <OpenGL/OpenGL.h>
@@ -86,17 +87,20 @@ CanvasLayerOGL::Initialize(const Data& a
       aData.mSurface != nsnull)
   {
     NS_WARNING("CanvasLayerOGL can't have both surface and GLContext");
     return;
   }
 
   mOGLManager->MakeCurrent();
 
-  if (aData.mSurface) {
+  if (aData.mDrawTarget) {
+    mDrawTarget = aData.mDrawTarget;
+    mNeedsYFlip = false;
+  } else if (aData.mSurface) {
     mCanvasSurface = aData.mSurface;
     mNeedsYFlip = false;
 #if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
     if (aData.mSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
         gfxXlibSurface *xsurf = static_cast<gfxXlibSurface*>(aData.mSurface);
         mPixmap = xsurf->GetGLXPixmap();
         if (mPixmap) {
             if (aData.mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
@@ -128,17 +132,17 @@ CanvasLayerOGL::Initialize(const Data& a
   // Check the maximum texture size supported by GL. glTexImage2D supports
   // images of up to 2 + GL_MAX_TEXTURE_SIZE
   GLint texSize = gl()->GetMaxTextureSize();
   if (mBounds.width > (2 + texSize) || mBounds.height > (2 + texSize)) {
     mDelayedUpdates = true;
     MakeTexture();
     // This should only ever occur with 2d canvas, WebGL can't already have a texture
     // of this size can it?
-    NS_ABORT_IF_FALSE(mCanvasSurface, 
+    NS_ABORT_IF_FALSE(mCanvasSurface || mDrawTarget, 
                       "Invalid texture size when WebGL surface already exists at that size?");
   }
 }
 
 void
 CanvasLayerOGL::MakeTexture()
 {
   if (mTexture != 0)
@@ -179,17 +183,21 @@ CanvasLayerOGL::UpdateSurface()
   {
     if (gl()->BindOffscreenNeedsTexture(mCanvasGLContext) &&
         mTexture == 0)
     {
       MakeTexture();
     }
   } else {
     nsRefPtr<gfxASurface> updatedAreaSurface;
-    if (mCanvasSurface) {
+    if (mDrawTarget) {
+      // TODO: This is suboptimal - We should have direct handling for the surface types instead of
+      // going via a gfxASurface.
+      updatedAreaSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget);
+    } else if (mCanvasSurface) {
       updatedAreaSurface = mCanvasSurface;
     } else if (mCanvasGLContext) {
       nsRefPtr<gfxImageSurface> updatedAreaImageSurface =
         new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
                             gfxASurface::ImageFormatARGB32);
       mCanvasGLContext->ReadPixelsIntoImageSurface(0, 0,
                                                    mBounds.width,
                                                    mBounds.height,
--- a/gfx/layers/opengl/CanvasLayerOGL.h
+++ b/gfx/layers/opengl/CanvasLayerOGL.h
@@ -77,16 +77,17 @@ public:
                            const nsIntPoint& aOffset);
 
 protected:
   void UpdateSurface();
 
   nsRefPtr<gfxASurface> mCanvasSurface;
   nsRefPtr<GLContext> mCanvasGLContext;
   gl::ShaderProgramType mLayerProgram;
+  RefPtr<gfx::DrawTarget> mDrawTarget;
 
   void MakeTexture();
   GLuint mTexture;
 
   bool mDelayedUpdates;
   bool mGLBufferIsPremultiplied;
   bool mNeedsYFlip;
 #if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -495,17 +495,35 @@ RefPtr<ScaledFont>
 gfxPlatform::GetScaledFontForFont(gfxFont *aFont)
 {
   return NULL;
 }
 
 already_AddRefed<gfxASurface>
 gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
 {
-  // Don't know how to do this outside of Windows with D2D yet.
+  RefPtr<SourceSurface> source = aTarget->Snapshot();
+  RefPtr<DataSourceSurface> data = source->GetDataSurface();
+
+  if (!data) {
+    return NULL;
+  }
+
+  IntSize size = data->GetSize();
+  gfxASurface::gfxImageFormat format = gfxASurface::FormatFromContent(ContentForFormat(data->GetFormat()));
+  
+  nsRefPtr<gfxImageSurface> image =
+    new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height),
+                        data->Stride(), format);
+  return image.forget();
+}
+
+RefPtr<DrawTarget>
+gfxPlatform::CreateOffscreenDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
+{
   return NULL;
 }
 
 nsresult
 gfxPlatform::GetFontList(nsIAtom *aLangGroup,
                          const nsACString& aGenericFamily,
                          nsTArray<nsString>& aListOfFonts)
 {
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -180,16 +180,19 @@ public:
       GetSourceSurfaceForSurface(mozilla::gfx::DrawTarget *aTarget, gfxASurface *aSurface);
 
     virtual mozilla::RefPtr<mozilla::gfx::ScaledFont>
       GetScaledFontForFont(gfxFont *aFont);
 
     virtual already_AddRefed<gfxASurface>
       GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
 
+    virtual mozilla::RefPtr<mozilla::gfx::DrawTarget>
+      CreateOffscreenDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
+
     /*
      * Font bits
      */
 
     virtual void SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString);
 
     /**
      * Fill aListOfFonts with the results of querying the list of font names
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -36,16 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxPlatformMac.h"
 
 #include "gfxImageSurface.h"
 #include "gfxQuartzSurface.h"
 #include "gfxQuartzImageSurface.h"
+#include "mozilla/gfx/2D.h"
 
 #include "gfxMacPlatformFontList.h"
 #include "gfxMacFont.h"
 #include "gfxCoreTextShaper.h"
 #include "gfxUserFontSet.h"
 
 #include "nsCRT.h"
 #include "nsTArray.h"
@@ -53,16 +54,17 @@
 
 #include "mozilla/Preferences.h"
 
 #include "qcms.h"
 
 #include <dlfcn.h>
 
 using namespace mozilla;
+using namespace mozilla::gfx;
 
 // cribbed from CTFontManager.h
 enum {
    kAutoActivationDisabled = 1
 };
 typedef uint32_t AutoActivationSetting;
 
 // bug 567552 - disable auto-activation of fonts
@@ -131,16 +133,22 @@ gfxPlatformMac::CreateOffscreenSurface(c
 {
     gfxASurface *newSurface = nsnull;
 
     newSurface = new gfxQuartzSurface(size, gfxASurface::FormatFromContent(contentType));
 
     NS_IF_ADDREF(newSurface);
     return newSurface;
 }
+    
+RefPtr<DrawTarget>
+gfxPlatformMac::CreateOffscreenDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
+{
+  return NULL;
+}
 
 already_AddRefed<gfxASurface>
 gfxPlatformMac::OptimizeImage(gfxImageSurface *aSurface,
                               gfxASurface::gfxImageFormat format)
 {
     const gfxIntSize& surfaceSize = aSurface->GetSize();
     nsRefPtr<gfxImageSurface> isurf = aSurface;
 
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -56,16 +56,19 @@ public:
     virtual ~gfxPlatformMac();
 
     static gfxPlatformMac *GetPlatform() {
         return (gfxPlatformMac*) gfxPlatform::GetPlatform();
     }
 
     already_AddRefed<gfxASurface> CreateOffscreenSurface(const gfxIntSize& size,
                                                          gfxASurface::gfxContentType contentType);
+    
+    virtual mozilla::RefPtr<mozilla::gfx::DrawTarget>
+      CreateOffscreenDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
 
     already_AddRefed<gfxASurface> OptimizeImage(gfxImageSurface *aSurface,
                                                 gfxASurface::gfxImageFormat format);
 
     nsresult ResolveFontName(const nsAString& aFontName,
                              FontResolverCallback aCallback,
                              void *aClosure, bool& aAborted);
 
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -469,16 +469,27 @@ gfxWindowsPlatform::CreateOffscreenSurfa
     if (surf == nsnull)
         surf = new gfxImageSurface(size, gfxASurface::FormatFromContent(contentType));
 
     NS_IF_ADDREF(surf);
 
     return surf;
 }
 
+RefPtr<DrawTarget>
+gfxWindowsPlatform::CreateOffscreenDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
+{
+#ifdef CAIRO_HAS_D2D_SURFACE
+  if (mRenderMode == RENDER_DIRECT2D) {
+      return Factory::CreateDrawTarget(BACKEND_DIRECT2D, aSize, aFormat); 
+  }
+#endif
+  return NULL;
+}
+
 RefPtr<ScaledFont>
 gfxWindowsPlatform::GetScaledFontForFont(gfxFont *aFont)
 {
   if(mUseDirectWrite) {
     gfxDWriteFont *font = static_cast<gfxDWriteFont*>(aFont);
 
     NativeFont nativeFont;
     nativeFont.mType = NATIVE_FONT_DWRITE_FONT_FACE;
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -126,16 +126,18 @@ public:
     virtual gfxPlatformFontList* CreatePlatformFontList();
 
     already_AddRefed<gfxASurface> CreateOffscreenSurface(const gfxIntSize& size,
                                                          gfxASurface::gfxContentType contentType);
     virtual mozilla::RefPtr<mozilla::gfx::ScaledFont>
       GetScaledFontForFont(gfxFont *aFont);
     virtual already_AddRefed<gfxASurface>
       GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
+    virtual mozilla::RefPtr<mozilla::gfx::DrawTarget>
+      CreateOffscreenDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
 
     enum RenderMode {
         /* Use GDI and windows surfaces */
         RENDER_GDI = 0,
 
         /* Use 32bpp image surfaces and call StretchDIBits */
         RENDER_IMAGE_STRETCH32,
 
--- a/widget/src/cocoa/GfxInfo.mm
+++ b/widget/src/cocoa/GfxInfo.mm
@@ -40,16 +40,17 @@
 #include <OpenGL/CGLRenderers.h>
 
 #include "mozilla/Util.h"
 
 #include "GfxInfo.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/FunctionTimer.h"
 #include "nsToolkit.h"
+#include "mozilla/Preferences.h"
 
 #import <Foundation/Foundation.h>
 #import <IOKit/IOKitLib.h>
 
 #if defined(MOZ_CRASHREPORTER)
 #include "nsExceptionHandler.h"
 #include "nsICrashReporter.h"
 #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
@@ -172,17 +173,25 @@ NS_IMETHODIMP
 GfxInfo::GetD2DEnabled(bool *aEnabled)
 {
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 GfxInfo::GetAzureEnabled(bool *aEnabled)
 {
-  return NS_ERROR_FAILURE;
+  bool azure = false;
+  nsresult rv = mozilla::Preferences::GetBool("gfx.canvas.azure.enabled", &azure);
+  
+  if (NS_SUCCEEDED(rv) && azure) {
+    *aEnabled = true;
+  } else {
+    *aEnabled = false;
+  }
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 GfxInfo::GetDWriteEnabled(bool *aEnabled)
 {
   return NS_ERROR_FAILURE;
 }