Bug 724666 - Part 2: Add CGIOSurfaceContext to azure. r=jmuizelaar
authorBenoit Girard <b56girard@gmail.com>
Tue, 31 Jul 2012 11:17:43 -0400
changeset 100986 fd2d4f38c58a8c7be07c67194be1b18af4afb705
parent 100985 1471876c787af7207169b569638bac8384c3ef48
child 100987 2d7c387f47ecb6c57aedb6245a4c175f71b8d624
push id12780
push userb56girard@gmail.com
push dateTue, 31 Jul 2012 15:20:33 +0000
treeherdermozilla-inbound@fd2d4f38c58a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmuizelaar
bugs724666
milestone17.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 724666 - Part 2: Add CGIOSurfaceContext to azure. r=jmuizelaar
gfx/2d/DrawTargetCG.cpp
gfx/2d/DrawTargetCG.h
gfx/2d/Factory.cpp
gfx/2d/Makefile.in
gfx/2d/PathCG.h
gfx/2d/ScaledFontMac.cpp
gfx/2d/SourceSurfaceCG.cpp
gfx/2d/SourceSurfaceCG.h
gfx/2d/Types.h
gfx/layers/ImageLayers.cpp
gfx/layers/basic/BasicCanvasLayer.cpp
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/CanvasLayerOGL.h
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxPlatformMac.cpp
gfx/thebes/gfxPlatformMac.h
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "DrawTargetCG.h"
 #include "SourceSurfaceCG.h"
 #include "Rect.h"
 #include "ScaledFontMac.h"
 #include "Tools.h"
 #include <vector>
+#include "QuartzSupport.h"
 
 //CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode);
 
 // A private API that Cairo has been using for a long time
 CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
 
 namespace mozilla {
 namespace gfx {
@@ -87,33 +88,49 @@ DrawTargetCG::~DrawTargetCG()
   // We need to conditionally release these because Init can fail without initializing these.
   if (mColorSpace)
     CGColorSpaceRelease(mColorSpace);
   if (mCg)
     CGContextRelease(mCg);
   free(mData);
 }
 
+BackendType
+DrawTargetCG::GetType() const
+{
+  // It may be worth spliting Bitmap and IOSurface DrawTarget
+  // into seperate classes.
+  if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) {
+    return BACKEND_COREGRAPHICS_ACCELERATED;
+  } else {
+    return BACKEND_COREGRAPHICS;
+  }
+}
+
 TemporaryRef<SourceSurface>
 DrawTargetCG::Snapshot()
 {
   if (!mSnapshot) {
-    mSnapshot = new SourceSurfaceCGBitmapContext(this);
+    if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) {
+      return new SourceSurfaceCGIOSurfaceContext(this);
+    } else {
+      mSnapshot = new SourceSurfaceCGBitmapContext(this);
+    }
   }
 
   return mSnapshot;
 }
 
 TemporaryRef<DrawTarget>
 DrawTargetCG::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
 {
   // XXX: in thebes we use CGLayers to do this kind of thing. It probably makes sense
   // to add that in somehow, but at a higher level
   RefPtr<DrawTargetCG> newTarget = new DrawTargetCG();
-  if (newTarget->Init(aSize, aFormat)) {
+  if (newTarget->Init(GetType(), aSize, aFormat)) {
     return newTarget;
   } else {
     return NULL;
   }
 }
 
 TemporaryRef<SourceSurface>
 DrawTargetCG::CreateSourceSurfaceFromData(unsigned char *aData,
@@ -131,17 +148,17 @@ DrawTargetCG::CreateSourceSurfaceFromDat
 }
 
 static CGImageRef
 GetImageFromSourceSurface(SourceSurface *aSurface)
 {
   if (aSurface->GetType() == SURFACE_COREGRAPHICS_IMAGE)
     return static_cast<SourceSurfaceCG*>(aSurface)->GetImage();
   else if (aSurface->GetType() == SURFACE_COREGRAPHICS_CGCONTEXT)
-    return static_cast<SourceSurfaceCGBitmapContext*>(aSurface)->GetImage();
+    return static_cast<SourceSurfaceCGContext*>(aSurface)->GetImage();
   else if (aSurface->GetType() == SURFACE_DATA)
     return static_cast<DataSourceSurfaceCG*>(aSurface)->GetImage();
   abort();
 }
 
 TemporaryRef<SourceSurface>
 DrawTargetCG::OptimizeSourceSurface(SourceSurface *aSurface) const
 {
@@ -272,16 +289,18 @@ class GradientStopsCG : public GradientS
                                                     &colors.front(),
                                                     &offsets.front(),
                                                     aNumStops);
     CGColorSpaceRelease(colorSpace);
   }
   virtual ~GradientStopsCG() {
     CGGradientRelease(mGradient);
   }
+  // Will always report BACKEND_COREGRAPHICS, but it is compatible
+  // with BACKEND_COREGRAPHICS_ACCELERATED
   BackendType GetBackendType() const { return BACKEND_COREGRAPHICS; }
   CGGradientRef mGradient;
 };
 
 TemporaryRef<GradientStops>
 DrawTargetCG::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops,
                                   ExtendMode aExtendMode) const
 {
@@ -794,17 +813,18 @@ DrawTargetCG::DrawSurfaceWithShadow(Sour
 
   CGContextDrawImage(mCg, flippedRect, image);
 
   CGContextRestoreGState(mCg);
 
 }
 
 bool
-DrawTargetCG::Init(unsigned char* aData,
+DrawTargetCG::Init(BackendType aType,
+                   unsigned char* aData,
                    const IntSize &aSize,
                    int32_t aStride,
                    SurfaceFormat aFormat)
 {
   // XXX: we should come up with some consistent semantics for dealing
   // with zero area drawtargets
   if (aSize.width <= 0 || aSize.height <= 0 ||
       // 32767 is the maximum size supported by cairo
@@ -816,43 +836,51 @@ DrawTargetCG::Init(unsigned char* aData,
     return false;
   }
 
   //XXX: handle SurfaceFormat
 
   //XXX: we'd be better off reusing the Colorspace across draw targets
   mColorSpace = CGColorSpaceCreateDeviceRGB();
 
-  if (aData == NULL) {
+  if (aData == NULL && aType != BACKEND_COREGRAPHICS_ACCELERATED) {
     // XXX: Currently, Init implicitly clears, that can often be a waste of time
     mData = calloc(aSize.height * aStride, 1);
     aData = static_cast<unsigned char*>(mData);  
   } else {
     // mData == NULL means DrawTargetCG doesn't own the image data and will not
     // delete it in the destructor
     mData = NULL;
   }
 
   mSize = aSize;
-  
-  int bitsPerComponent = 8;
 
-  CGBitmapInfo bitinfo;
+  if (aType == BACKEND_COREGRAPHICS_ACCELERATED) {
+    RefPtr<MacIOSurface> ioSurface = MacIOSurface::CreateIOSurface(aSize.width, aSize.height);
+    mCg = ioSurface->CreateIOSurfaceContext();
+    // If we don't have the symbol for 'CreateIOSurfaceContext' mCg will be null
+    // and we will fallback to software below
+    mData = NULL;
+  }
 
-  bitinfo = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst;
+  if (!mCg || aType == BACKEND_COREGRAPHICS) {
+    int bitsPerComponent = 8;
 
-  // XXX: what should we do if this fails?
-  mCg = CGBitmapContextCreate (aData,
-                               mSize.width,
-                               mSize.height,
-                               bitsPerComponent,
-                               aStride,
-                               mColorSpace,
-                               bitinfo);
+    CGBitmapInfo bitinfo;
+    bitinfo = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst;
 
+    // XXX: what should we do if this fails?
+    mCg = CGBitmapContextCreate (aData,
+                                 mSize.width,
+                                 mSize.height,
+                                 bitsPerComponent,
+                                 aStride,
+                                 mColorSpace,
+                                 bitinfo);
+  }
 
   assert(mCg);
   // CGContext's default to have the origin at the bottom left
   // so flip it to the top left
   CGContextTranslateCTM(mCg, 0, mSize.height);
   CGContextScaleCTM(mCg, 1, -1);
   // See Bug 722164 for performance details
   // Medium or higher quality lead to expensive interpolation
@@ -861,19 +889,32 @@ DrawTargetCG::Init(unsigned char* aData,
   // implementation.
   // XXX: Create input parameter to control interpolation and
   //      use the default for content.
   CGContextSetInterpolationQuality(mCg, kCGInterpolationLow);
 
   // XXX: set correct format
   mFormat = FORMAT_B8G8R8A8;
 
+  if (aType == BACKEND_COREGRAPHICS_ACCELERATED) {
+    // The bitmap backend uses callac to clear, we can't do that without
+    // reading back the surface. This should trigger something equivilent
+    // to glClear.
+    ClearRect(Rect(0, 0, mSize.width, mSize.height));
+  }
+
   return true;
 }
 
+void
+DrawTargetCG::Flush()
+{
+  CGContextFlush(mCg);
+}
+
 bool
 DrawTargetCG::Init(CGContextRef cgContext, const IntSize &aSize)
 {
   // XXX: we should come up with some consistent semantics for dealing
   // with zero area drawtargets
   if (aSize.width == 0 || aSize.height == 0) {
     mColorSpace = NULL;
     mCg = NULL;
@@ -900,35 +941,36 @@ DrawTargetCG::Init(CGContextRef cgContex
 
   //XXX: set correct format
   mFormat = FORMAT_B8G8R8A8;
 
   return true;
 }
 
 bool
-DrawTargetCG::Init(const IntSize &aSize, SurfaceFormat &aFormat)
+DrawTargetCG::Init(BackendType aType, const IntSize &aSize, SurfaceFormat &aFormat)
 {
   int stride = aSize.width*4;
   
   // Calling Init with aData == NULL will allocate.
-  return Init(NULL, aSize, stride, aFormat);
+  return Init(aType, NULL, aSize, stride, aFormat);
 }
 
 TemporaryRef<PathBuilder>
 DrawTargetCG::CreatePathBuilder(FillRule aFillRule) const
 {
   RefPtr<PathBuilderCG> pb = new PathBuilderCG(aFillRule);
   return pb;
 }
 
 void*
 DrawTargetCG::GetNativeSurface(NativeSurfaceType aType)
 {
-  if (aType == NATIVE_SURFACE_CGCONTEXT) {
+  if (aType == NATIVE_SURFACE_CGCONTEXT && GetContextType(mCg) == CG_CONTEXT_TYPE_BITMAP ||
+      aType == NATIVE_SURFACE_CGCONTEXT_ACCELERATED && GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) {
     return mCg;
   } else {
     return NULL;
   }
 }
 
 void
 DrawTargetCG::Mask(const Pattern &aSource,
--- a/gfx/2d/DrawTargetCG.h
+++ b/gfx/2d/DrawTargetCG.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <ApplicationServices/ApplicationServices.h>
 
 #include "2D.h"
 #include "Rect.h"
 #include "PathCG.h"
 #include "SourceSurfaceCG.h"
+#include "GLDefs.h"
 
 namespace mozilla {
 namespace gfx {
 
 static inline CGAffineTransform
 GfxMatrixToCGAffineTransform(Matrix m)
 {
   CGAffineTransform t;
@@ -82,37 +83,37 @@ SetStrokeOptions(CGContextRef cg, const 
 
 
 class DrawTargetCG : public DrawTarget
 {
 public:
   DrawTargetCG();
   virtual ~DrawTargetCG();
 
-  virtual BackendType GetType() const { return BACKEND_COREGRAPHICS; }
+  virtual BackendType GetType() const;
   virtual TemporaryRef<SourceSurface> Snapshot();
 
   virtual void DrawSurface(SourceSurface *aSurface,
                            const Rect &aDest,
                            const Rect &aSource,
                            const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(),
                            const DrawOptions &aOptions = DrawOptions());
 
   virtual void FillRect(const Rect &aRect,
                         const Pattern &aPattern,
                         const DrawOptions &aOptions = DrawOptions());
 
 
   //XXX: why do we take a reference to SurfaceFormat?
-  bool Init(const IntSize &aSize, SurfaceFormat&);
-  bool Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
+  bool Init(BackendType aType, const IntSize &aSize, SurfaceFormat&);
+  bool Init(BackendType aType, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
   bool Init(CGContextRef cgContext, const IntSize &aSize);
 
-
-  virtual void Flush() {}
+  // Flush if using IOSurface context
+  virtual void Flush();
 
   virtual void DrawSurfaceWithShadow(SourceSurface *, const Point &, const Color &, const Point &, Float, CompositionOp);
   virtual void ClearRect(const Rect &);
   virtual void CopySurface(SourceSurface *, const IntRect&, const IntPoint&);
   virtual void StrokeRect(const Rect &, const Pattern &, const StrokeOptions&, const DrawOptions&);
   virtual void StrokeLine(const Point &, const Point &, const Pattern &, const StrokeOptions &, const DrawOptions &);
   virtual void Stroke(const Path *, const Pattern &, const StrokeOptions &, const DrawOptions &);
   virtual void Fill(const Path *, const Pattern &, const DrawOptions &);
@@ -145,25 +146,27 @@ public:
   }
 private:
   void MarkChanged();
 
   IntSize mSize;
   CGColorSpaceRef mColorSpace;
   CGContextRef mCg;
 
+  GLuint mIOSurfaceTexture;
+
   /**
    * A pointer to the image buffer if the buffer is owned by this class (set to
    * NULL otherwise).
    * The data is not considered owned by DrawTargetCG if the DrawTarget was 
    * created for a pre-existing buffer or if the buffer's lifetime is managed
    * by CoreGraphics.
    * Data owned by DrawTargetCG will be deallocated in the destructor. 
    */
   void *mData;
 
   SurfaceFormat mFormat;
 
-  RefPtr<SourceSurfaceCGBitmapContext> mSnapshot;
+  RefPtr<SourceSurfaceCGContext> mSnapshot;
 };
 
 }
 }
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -168,20 +168,21 @@ Factory::CreateDrawTarget(BackendType aB
       newTarget = new DrawTargetD2D();
       if (newTarget->Init(aSize, aFormat)) {
         return newTarget;
       }
       break;
     }
 #elif defined XP_MACOSX
   case BACKEND_COREGRAPHICS:
+  case BACKEND_COREGRAPHICS_ACCELERATED:
     {
       RefPtr<DrawTargetCG> newTarget;
       newTarget = new DrawTargetCG();
-      if (newTarget->Init(aSize, aFormat)) {
+      if (newTarget->Init(aBackend, aSize, aFormat)) {
         return newTarget;
       }
       break;
     }
 #endif
 #ifdef USE_SKIA
   case BACKEND_SKIA:
     {
@@ -219,17 +220,17 @@ Factory::CreateDrawTargetForData(Backend
       newTarget->Init(aData, aSize, aStride, aFormat);
       return newTarget;
     }
 #endif
 #ifdef XP_MACOSX
   case BACKEND_COREGRAPHICS:
     {
       RefPtr<DrawTargetCG> newTarget = new DrawTargetCG();
-      if (newTarget->Init(aData, aSize, aStride, aFormat))
+      if (newTarget->Init(aBackend, aData, aSize, aStride, aFormat))
         return newTarget;
       break;
     }
 #endif
   default:
     gfxDebug() << "Invalid draw target type specified.";
     return NULL;
   }
--- a/gfx/2d/Makefile.in
+++ b/gfx/2d/Makefile.in
@@ -47,16 +47,25 @@ CPPSRCS	= \
         $(NULL)
 
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS	+= \
 	   SourceSurfaceCG.cpp \
 	   DrawTargetCG.cpp \
 	   PathCG.cpp \
 	   $(NULL)
+
+CMMSRCS = \
+	   QuartzSupport.mm \
+	   $(NULL)
+
+EXPORTS_mozilla/gfx	+= \
+	   QuartzSupport.h \
+	   MacIOSurface.h \
+	   $(NULL)
 endif
 
 DEFINES += -DMOZ_GFX -DUSE_CAIRO -DGFX2D_INTERNAL
 
 ifdef MOZ_ENABLE_SKIA
 CPPSRCS	+= \
         SourceSurfaceSkia.cpp \
         DrawTargetSkia.cpp \
--- a/gfx/2d/PathCG.h
+++ b/gfx/2d/PathCG.h
@@ -66,16 +66,18 @@ public:
   PathCG(CGMutablePathRef aPath, FillRule aFillRule)
     : mPath(aPath)
     , mFillRule(aFillRule)
   {
     CGPathRetain(mPath);
   }
   virtual ~PathCG() { CGPathRelease(mPath); }
 
+  // Paths will always return BACKEND_COREGRAPHICS, but note that they
+  // are compatible with BACKEND_COREGRAPHICS_ACCELERATED backend.
   virtual BackendType GetBackendType() const { return BACKEND_COREGRAPHICS; }
 
   virtual TemporaryRef<PathBuilder> CopyToBuilder(FillRule aFillRule = FILL_WINDING) const;
   virtual TemporaryRef<PathBuilder> TransformedCopyToBuilder(const Matrix &aTransform,
                                                              FillRule aFillRule = FILL_WINDING) const;
 
   virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const;
   virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const;
--- a/gfx/2d/ScaledFontMac.cpp
+++ b/gfx/2d/ScaledFontMac.cpp
@@ -51,17 +51,17 @@ SkTypeface* ScaledFontMac::GetSkTypeface
 // ATSUGlyphGetCubicPaths
 // we've used this in cairo sucessfully for some time.
 // Note: cairo dlsyms it. We could do that but maybe it's
 // safe just to use?
 
 TemporaryRef<Path>
 ScaledFontMac::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
 {
-  if (aTarget->GetType() == BACKEND_COREGRAPHICS) {
+  if (aTarget->GetType() == BACKEND_COREGRAPHICS || aTarget->GetType() == BACKEND_COREGRAPHICS_ACCELERATED) {
       CGMutablePathRef path = CGPathCreateMutable();
 
       for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
           // XXX: we could probably fold both of these transforms together to avoid extra work
           CGAffineTransform flip = CGAffineTransformMakeScale(1, -1);
           CGPathRef glyphPath = ::CGFontGetGlyphPath(mFont, &flip, 0, aBuffer.mGlyphs[i].mIndex);
 
           CGAffineTransform matrix = CGAffineTransformMake(mSize, 0, 0, mSize,
--- a/gfx/2d/SourceSurfaceCG.cpp
+++ b/gfx/2d/SourceSurfaceCG.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SourceSurfaceCG.h"
 #include "DrawTargetCG.h"
 
+#include "QuartzSupport.h"
+
 namespace mozilla {
 namespace gfx {
 
 
 SourceSurfaceCG::~SourceSurfaceCG()
 {
   CGImageRelease(mImage);
 }
@@ -280,28 +282,30 @@ DataSourceSurfaceCG::GetData()
   // we need read-write for DataSourceSurfaces
   return (unsigned char*)mData;
 }
 
 SourceSurfaceCGBitmapContext::SourceSurfaceCGBitmapContext(DrawTargetCG *aDrawTarget)
 {
   mDrawTarget = aDrawTarget;
   mCg = (CGContextRef)aDrawTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT);
+  if (!mCg)
+    abort();
 
   mSize.width = CGBitmapContextGetWidth(mCg);
   mSize.height = CGBitmapContextGetHeight(mCg);
   mStride = CGBitmapContextGetBytesPerRow(mCg);
   mData = CGBitmapContextGetData(mCg);
 
   mImage = NULL;
 }
 
 void SourceSurfaceCGBitmapContext::EnsureImage() const
 {
-  // Instaed of using CGBitmapContextCreateImage we create
+  // Instead of using CGBitmapContextCreateImage we create
   // a CGImage around the data associated with the CGBitmapContext
   // we do this to avoid the vm_copy that CGBitmapContextCreateImage.
   // vm_copy tends to cause all sorts of unexpected performance problems
   // because of the mm tricks that vm_copy does. Using a regular
   // memcpy when the bitmap context is modified gives us more predictable
   // performance characteristics.
   if (!mImage) {
       //XXX: we should avoid creating this colorspace everytime
@@ -321,16 +325,18 @@ void SourceSurfaceCGBitmapContext::Ensur
           // to the CGDataProviderCreateWithData
           info = NULL;
       } else {
           // otherwise we transfer ownership to
           // the dataProvider
           info = mData;
       }
 
+      if (!mData) abort();
+
       dataProvider = CGDataProviderCreateWithData (info,
                                                    mData,
                                                    mSize.height * mStride,
                                                    releaseCallback);
 
       mImage = CGImageCreate (mSize.width, mSize.height,
                               bitsPerComponent,
                               bitsPerPixel,
@@ -384,10 +390,107 @@ SourceSurfaceCGBitmapContext::~SourceSur
   if (!mImage && !mCg) {
     // neither mImage or mCg owns the data
     free(mData);
   }
   if (mImage)
     CGImageRelease(mImage);
 }
 
+SourceSurfaceCGIOSurfaceContext::SourceSurfaceCGIOSurfaceContext(DrawTargetCG *aDrawTarget)
+{
+  CGContextRef cg = (CGContextRef)aDrawTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT_ACCELERATED);
+
+  RefPtr<MacIOSurface> surf = MacIOSurface::IOSurfaceContextGetSurface(cg);
+
+  mSize.width = surf->GetWidth();
+  mSize.height = surf->GetHeight();
+
+  // TODO use CreateImageFromIOSurfaceContext instead of reading back the surface
+  //mImage = MacIOSurface::CreateImageFromIOSurfaceContext(cg);
+  mImage = NULL;
+
+  aDrawTarget->Flush();
+  surf->Lock();
+  size_t bytesPerRow = surf->GetBytesPerRow();
+  size_t ioHeight = surf->GetHeight();
+  void* ioData = surf->GetBaseAddress();
+  // XXX If the width is much less then the stride maybe
+  //     we should repack the image?
+  mData = malloc(ioHeight*bytesPerRow);
+  memcpy(mData, ioData, ioHeight*(bytesPerRow));
+  mStride = bytesPerRow;
+  surf->Unlock();
+}
+
+void SourceSurfaceCGIOSurfaceContext::EnsureImage() const
+{
+  // TODO Use CreateImageFromIOSurfaceContext and remove this
+
+  // Instead of using CGBitmapContextCreateImage we create
+  // a CGImage around the data associated with the CGBitmapContext
+  // we do this to avoid the vm_copy that CGBitmapContextCreateImage.
+  // vm_copy tends to cause all sorts of unexpected performance problems
+  // because of the mm tricks that vm_copy does. Using a regular
+  // memcpy when the bitmap context is modified gives us more predictable
+  // performance characteristics.
+  if (!mImage) {
+      //XXX: we should avoid creating this colorspace everytime
+      CGColorSpaceRef colorSpace = NULL;
+      CGBitmapInfo bitinfo = 0;
+      CGDataProviderRef dataProvider = NULL;
+      int bitsPerComponent = 8;
+      int bitsPerPixel = 32;
+
+      colorSpace = CGColorSpaceCreateDeviceRGB();
+      bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
+
+      void *info = mData;
+
+      dataProvider = CGDataProviderCreateWithData (info,
+                                                   mData,
+                                                   mSize.height * mStride,
+                                                   releaseCallback);
+
+      mImage = CGImageCreate (mSize.width, mSize.height,
+                              bitsPerComponent,
+                              bitsPerPixel,
+                              mStride,
+                              colorSpace,
+                              bitinfo,
+                              dataProvider,
+                              NULL,
+                              true,
+                              kCGRenderingIntentDefault);
+
+      CGDataProviderRelease(dataProvider);
+      CGColorSpaceRelease (colorSpace);
+  }
+
+}
+
+IntSize
+SourceSurfaceCGIOSurfaceContext::GetSize() const
+{
+  return mSize;
+}
+
+void
+SourceSurfaceCGIOSurfaceContext::DrawTargetWillChange()
+{
+}
+
+SourceSurfaceCGIOSurfaceContext::~SourceSurfaceCGIOSurfaceContext()
+{
+  if (mImage)
+    CGImageRelease(mImage);
+  else
+    free(mData);
+}
+
+unsigned char*
+SourceSurfaceCGIOSurfaceContext::GetData()
+{
+  return (unsigned char*)mData;
+}
+
 }
 }
--- a/gfx/2d/SourceSurfaceCG.h
+++ b/gfx/2d/SourceSurfaceCG.h
@@ -4,16 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #pragma once
 
 #include <ApplicationServices/ApplicationServices.h>
 
 #include "2D.h"
 
+class MacIOSurface;
+
 namespace mozilla {
 namespace gfx {
 
 class DrawTargetCG;
 
 class SourceSurfaceCG : public SourceSurface
 {
 public:
@@ -70,17 +72,24 @@ private:
   CGImageRef mImage;
   //XXX: we don't need to store mData we can just get it from the CGContext
   void *mData;
   /* It might be better to just use the bitmap info from the CGImageRef to
    * deduce the format to save space in SourceSurfaceCG,
    * for now we just store it in mFormat */
 };
 
-class SourceSurfaceCGBitmapContext : public DataSourceSurface
+class SourceSurfaceCGContext : public DataSourceSurface
+{
+public:
+  virtual void DrawTargetWillChange() = 0;
+  virtual CGImageRef GetImage() = 0;
+};
+
+class SourceSurfaceCGBitmapContext : public SourceSurfaceCGContext
 {
 public:
   SourceSurfaceCGBitmapContext(DrawTargetCG *);
   ~SourceSurfaceCGBitmapContext();
 
   virtual SurfaceType GetType() const { return SURFACE_COREGRAPHICS_CGCONTEXT; }
   virtual IntSize GetSize() const;
   virtual SurfaceFormat GetFormat() const { return FORMAT_B8G8R8A8; }
@@ -89,17 +98,17 @@ public:
 
   virtual unsigned char *GetData() { return static_cast<unsigned char*>(mData); }
 
   virtual int32_t Stride() { return mStride; }
 
 private:
   //XXX: do the other backends friend their DrawTarget?
   friend class DrawTargetCG;
-  void DrawTargetWillChange();
+  virtual void DrawTargetWillChange();
   void EnsureImage() const;
 
   // We hold a weak reference to these two objects.
   // The cycle is broken by DrawTargetWillChange
   DrawTargetCG *mDrawTarget;
   CGContextRef mCg;
 
   mutable CGImageRef mImage;
@@ -107,11 +116,42 @@ private:
   // mData can be owned by three different things:
   // mImage, mCg or SourceSurfaceCGBitmapContext
   void *mData;
 
   int32_t mStride;
   IntSize mSize;
 };
 
+class SourceSurfaceCGIOSurfaceContext : public SourceSurfaceCGContext
+{
+public:
+  SourceSurfaceCGIOSurfaceContext(DrawTargetCG *);
+  ~SourceSurfaceCGIOSurfaceContext();
+
+  virtual SurfaceType GetType() const { return SURFACE_COREGRAPHICS_CGCONTEXT; }
+  virtual IntSize GetSize() const;
+  virtual SurfaceFormat GetFormat() const { return FORMAT_B8G8R8A8; }
+
+  CGImageRef GetImage() { EnsureImage(); return mImage; }
+
+  virtual unsigned char *GetData();
+
+  virtual int32_t Stride() { return mStride; }
+
+private:
+  //XXX: do the other backends friend their DrawTarget?
+  friend class DrawTargetCG;
+  virtual void DrawTargetWillChange();
+  void EnsureImage() const;
+
+  mutable CGImageRef mImage;
+  MacIOSurface* mIOSurface;
+
+  void *mData;
+  int32_t mStride;
+
+  IntSize mSize;
+};
+
 
 }
 }
--- a/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -36,16 +36,17 @@ enum SurfaceFormat
   FORMAT_A8
 };
 
 enum BackendType
 {
   BACKEND_NONE = 0,
   BACKEND_DIRECT2D,
   BACKEND_COREGRAPHICS,
+  BACKEND_COREGRAPHICS_ACCELERATED,
   BACKEND_CAIRO,
   BACKEND_SKIA
 };
 
 enum FontType
 {
   FONT_DWRITE,
   FONT_GDI,
@@ -54,17 +55,18 @@ enum FontType
   FONT_CAIRO,
   FONT_COREGRAPHICS
 };
 
 enum NativeSurfaceType
 {
   NATIVE_SURFACE_D3D10_TEXTURE,
   NATIVE_SURFACE_CAIRO_SURFACE,
-  NATIVE_SURFACE_CGCONTEXT
+  NATIVE_SURFACE_CGCONTEXT,
+  NATIVE_SURFACE_CGCONTEXT_ACCELERATED
 };
 
 enum NativeFontType
 {
   NATIVE_FONT_DWRITE_FONT_FACE,
   NATIVE_FONT_GDI_FONT_FACE,
   NATIVE_FONT_MAC_FONT_FACE,
   NATIVE_FONT_SKIA_FONT_FACE,
--- a/gfx/layers/ImageLayers.cpp
+++ b/gfx/layers/ImageLayers.cpp
@@ -9,28 +9,30 @@
 #include "SharedTextureImage.h"
 #include "gfxImageSurface.h"
 #include "gfxSharedImageSurface.h"
 #include "yuv_convert.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/ImageContainerChild.h"
 
 #ifdef XP_MACOSX
-#include "nsCoreAnimationSupport.h"
+#include "mozilla/gfx/QuartzSupport.h"
 #endif
 
 #ifdef XP_WIN
 #include "gfxD2DSurface.h"
 #include "gfxWindowsPlatform.h"
 #include <d3d10_1.h>
 
 #include "d3d10/ImageLayerD3D10.h"
 #endif
 
 using namespace mozilla::ipc;
+using mozilla::gfx::DataSourceSurface;
+using mozilla::gfx::SourceSurface;
 
 namespace mozilla {
 namespace layers {
 
 already_AddRefed<Image>
 ImageFactory::CreateImage(const Image::Format *aFormats,
                           PRUint32 aNumFormats,
                           const gfxIntSize &,
@@ -489,24 +491,41 @@ PlanarYCbCrImage::GetAsSurface()
 
   return imageSurface.forget().get();
 }
 
 #ifdef XP_MACOSX
 void
 MacIOSurfaceImage::SetData(const Data& aData)
 {
-  mIOSurface = nsIOSurface::LookupSurface(aData.mIOSurface->GetIOSurfaceID());
+  mIOSurface = MacIOSurface::LookupSurface(aData.mIOSurface->GetIOSurfaceID());
   mSize = gfxIntSize(mIOSurface->GetWidth(), mIOSurface->GetHeight());
 }
 
 already_AddRefed<gfxASurface>
 MacIOSurfaceImage::GetAsSurface()
 {
-  return mIOSurface->GetAsSurface();
+  mIOSurface->Lock();
+  size_t bytesPerRow = mIOSurface->GetBytesPerRow();
+  size_t ioWidth = mIOSurface->GetWidth();
+  size_t ioHeight = mIOSurface->GetHeight();
+
+  unsigned char* ioData = (unsigned char*)mIOSurface->GetBaseAddress();
+
+  nsRefPtr<gfxImageSurface> imgSurface =
+    new gfxImageSurface(gfxIntSize(ioWidth, ioHeight), gfxASurface::ImageFormatARGB32);
+
+  for (int i = 0; i < ioHeight; i++) {
+    memcpy(imgSurface->Data() + i * imgSurface->Stride(),
+           ioData + i * bytesPerRow, ioWidth * 4);
+  }
+
+  mIOSurface->Unlock();
+
+  return imgSurface.forget();
 }
 
 void
 MacIOSurfaceImage::Update(ImageContainer* aContainer)
 {
   if (mUpdateCallback) {
     mUpdateCallback(aContainer, mPluginInstanceOwner);
   }
--- a/gfx/layers/basic/BasicCanvasLayer.cpp
+++ b/gfx/layers/basic/BasicCanvasLayer.cpp
@@ -112,16 +112,18 @@ BasicCanvasLayer::Initialize(const Data&
   mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
 }
 
 void
 BasicCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer)
 {
   if (mDrawTarget) {
     mDrawTarget->Flush();
+    // TODO Fix me before turning accelerated quartz canvas by default
+    //mSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget);
   }
 
   if (!mGLContext && aDestSurface) {
     nsRefPtr<gfxContext> tmpCtx = new gfxContext(aDestSurface);
     tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
     BasicCanvasLayer::PaintWithOpacity(tmpCtx, 1.0f, aMaskLayer);
     return;
   }
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -119,16 +119,53 @@ CanvasLayerOGL::Initialize(const Data& a
     MakeTextureIfNeeded(gl(), mTexture);
     // 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 || mDrawTarget, 
                       "Invalid texture size when WebGL surface already exists at that size?");
   }
 }
 
+#ifdef XP_MACOSX
+static GLuint
+MakeIOSurfaceTexture(void* aCGIOSurfaceContext, mozilla::gl::GLContext* aGL)
+{
+  GLuint ioSurfaceTexture;
+
+  aGL->fGenTextures(1, &ioSurfaceTexture);
+
+  aGL->fActiveTexture(LOCAL_GL_TEXTURE0);
+  aGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, ioSurfaceTexture);
+
+  aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
+  aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
+  aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+  aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+
+  RefPtr<MacIOSurface> ioSurface = MacIOSurface::IOSurfaceContextGetSurface((CGContextRef)aCGIOSurfaceContext);
+  void *nativeCtx = aGL->GetNativeData(GLContext::NativeGLContext);
+
+  ioSurface->CGLTexImageIOSurface2D(nativeCtx,
+                                    LOCAL_GL_RGBA, LOCAL_GL_BGRA,
+                                    LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV, 0);
+
+  aGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
+
+  return ioSurfaceTexture;
+}
+
+#else
+static GLuint
+MakeIOSurfaceTexture(void* aCGIOSurfaceContext, mozilla::gl::GLContext* aGL)
+{
+  NS_RUNTIMEABORT("Not implemented");
+  return 0;
+}
+#endif
+
 /**
  * Following UpdateSurface(), mTexture on context this->gl() should contain the data we want,
  * unless mDelayedUpdates is true because of a too-large surface.
  */
 void
 CanvasLayerOGL::UpdateSurface()
 {
   if (!mDirty)
@@ -198,17 +235,17 @@ CanvasLayerOGL::RenderLayer(int aPreviou
 
   // XXX We're going to need a different program depending on if
   // mGLBufferIsPremultiplied is TRUE or not.  The RGBLayerProgram
   // assumes that it's true.
 
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 
   if (mTexture) {
-    gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+    gl()->fBindTexture(mTextureTarget, mTexture);
   }
 
   ShaderProgramOGL *program = nullptr;
 
   bool useGLContext = mCanvasGLContext &&
     mCanvasGLContext->GetContextType() == gl()->GetContextType();
 
   nsIntRect drawRect = mBounds;
@@ -239,16 +276,20 @@ CanvasLayerOGL::RenderLayer(int aPreviou
   if (mPixmap && !mDelayedUpdates) {
     sGLXLibrary.BindTexImage(mPixmap);
   }
 #endif
 
   gl()->ApplyFilterToBoundTexture(mFilter);
 
   program->Activate();
+  if (mLayerProgram == gl::RGBARectLayerProgramType) {
+    // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
+    program->SetTexCoordMultiplier(mDrawTarget->GetSize().width, mDrawTarget->GetSize().height);
+  }
   program->SetLayerQuadRect(drawRect);
   program->SetLayerTransform(GetEffectiveTransform());
   program->SetLayerOpacity(GetEffectiveOpacity());
   program->SetRenderOffset(aOffset);
   program->SetTextureUnit(0);
   program->LoadMask(GetMaskLayer());
 
   if (gl()->CanUploadNonPowerOfTwo()) {
--- a/gfx/layers/opengl/CanvasLayerOGL.h
+++ b/gfx/layers/opengl/CanvasLayerOGL.h
@@ -21,16 +21,17 @@ class THEBES_API CanvasLayerOGL :
   public CanvasLayer,
   public LayerOGL
 {
 public:
   CanvasLayerOGL(LayerManagerOGL *aManager)
     : CanvasLayer(aManager, NULL),
       LayerOGL(aManager),
       mTexture(0),
+      mTextureTarget(LOCAL_GL_TEXTURE_2D),
       mDelayedUpdates(false)
 #if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
       ,mPixmap(0)
 #endif
   { 
       mImplData = static_cast<LayerOGL*>(this);
   }
   ~CanvasLayerOGL() { Destroy(); }
@@ -49,16 +50,17 @@ protected:
   void UpdateSurface();
 
   nsRefPtr<gfxASurface> mCanvasSurface;
   nsRefPtr<GLContext> mCanvasGLContext;
   gl::ShaderProgramType mLayerProgram;
   RefPtr<gfx::DrawTarget> mDrawTarget;
 
   GLuint mTexture;
+  GLenum mTextureTarget;
 
   bool mDelayedUpdates;
   bool mGLBufferIsPremultiplied;
   bool mNeedsYFlip;
 #if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
   GLXPixmap mPixmap;
 #endif
 
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -113,16 +113,18 @@ const PRUint32 kMaxLenPrefLangList = 32;
 typedef gfxASurface::gfxImageFormat gfxImageFormat;
 
 inline const char*
 GetBackendName(mozilla::gfx::BackendType aBackend)
 {
   switch (aBackend) {
       case mozilla::gfx::BACKEND_DIRECT2D:
         return "direct2d";
+      case mozilla::gfx::BACKEND_COREGRAPHICS_ACCELERATED:
+        return "quartz accelerated";
       case mozilla::gfx::BACKEND_COREGRAPHICS:
         return "quartz";
       case mozilla::gfx::BACKEND_CAIRO:
         return "cairo";
       case mozilla::gfx::BACKEND_SKIA:
         return "skia";
       case mozilla::gfx::BACKEND_NONE:
         return "none";
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -374,32 +374,48 @@ gfxPlatformMac::ReadAntiAliasingThreshol
     }
 
     return threshold;
 }
 
 already_AddRefed<gfxASurface>
 gfxPlatformMac::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
 {
-  if (aTarget->GetType() == BACKEND_COREGRAPHICS) {
+  if (aTarget->GetType() == BACKEND_COREGRAPHICS_ACCELERATED) {
+    RefPtr<SourceSurface> source = aTarget->Snapshot();
+    RefPtr<DataSourceSurface> sourceData = source->GetDataSurface();
+    unsigned char* data = sourceData->GetData();
+    nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(data, ThebesIntSize(sourceData->GetSize()), sourceData->Stride(),
+                                                         gfxImageSurface::ImageFormatARGB32);
+    // We could fix this by telling gfxImageSurface it owns data.
+    nsRefPtr<gfxImageSurface> cpy = new gfxImageSurface(ThebesIntSize(sourceData->GetSize()), gfxImageSurface::ImageFormatARGB32);
+    cpy->CopyFrom(surf);
+    return cpy.forget();
+  } else if (aTarget->GetType() == BACKEND_COREGRAPHICS) {
     CGContextRef cg = static_cast<CGContextRef>(aTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT));
 
     //XXX: it would be nice to have an implicit conversion from IntSize to gfxIntSize
     IntSize intSize = aTarget->GetSize();
     gfxIntSize size(intSize.width, intSize.height);
 
     nsRefPtr<gfxASurface> surf =
       new gfxQuartzSurface(cg, size);
 
     return surf.forget();
   }
 
   return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
 }
 
+bool
+gfxPlatformMac::UseAcceleratedCanvas()
+{
+  // Lion or later is required
+  return false && OSXVersion() >= 0x1070 && Preferences::GetBool("gfx.canvas.azure.accelerated", false);
+}
 
 qcms_profile *
 gfxPlatformMac::GetPlatformCMSOutputProfile()
 {
     qcms_profile *profile = nullptr;
     CMProfileRef cmProfile;
     CMProfileLocation *location;
     UInt32 locationSize;
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -67,19 +67,21 @@ public:
                          nsTArray<nsString>& aListOfFonts);
     nsresult UpdateFontList();
 
     virtual void GetCommonFallbackFonts(const PRUint32 aCh,
                                         PRInt32 aRunScript,
                                         nsTArray<const char*>& aFontList);
 
     // Returns the OS X version as returned from Gestalt(gestaltSystemVersion, ...)
-    // Ex: Mac OS X 10.4.x ==> 0x104x 
+    // Ex: Mac OS X 10.4.x ==> 0x104x
     PRInt32 OSXVersion();
 
+    bool UseAcceleratedCanvas();
+
     // lower threshold on font anti-aliasing
     PRUint32 GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }
 
     virtual already_AddRefed<gfxASurface>
     GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
 private:
     virtual qcms_profile* GetPlatformCMSOutputProfile();