Bug 892966 - Implement CreateSourceSurfaceFromNativeSurface for DrawTargetCG and use it instead of copying pixel data. r=jrmuizel
authorMatt Woodrow <mwoodrow@mozilla.com>
Fri, 12 Jul 2013 17:19:28 -0400
changeset 138760 1bd8fb49312194a33d6654486de337fa00e38964
parent 138759 1dcbef737c1ed786e8693739b27456a948a56f3d
child 138761 9f2d53dd91fcf33f1c9aa834f70617c62e174445
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersjrmuizel
bugs892966
milestone25.0a1
Bug 892966 - Implement CreateSourceSurfaceFromNativeSurface for DrawTargetCG and use it instead of copying pixel data. r=jrmuizel
gfx/2d/DrawTargetCG.cpp
gfx/2d/DrawTargetCG.h
gfx/2d/SourceSurfaceCG.cpp
gfx/2d/SourceSurfaceCG.h
gfx/thebes/gfxPlatform.cpp
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -1067,16 +1067,31 @@ DrawTargetCG::GetNativeSurface(NativeSur
   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 nullptr;
   }
 }
 
+TemporaryRef<SourceSurface>
+DrawTargetCG::CreateSourceSurfaceFromNativeSurface(const NativeSurface& aNative) const
+{
+  if (aNative.mType != NATIVE_SURFACE_CGCONTEXT) {
+    return nullptr;
+  }
+
+  CGContextRef cg = (CGContextRef)aNative.mSurface;
+  if (GetContextType(cg) != CG_CONTEXT_TYPE_BITMAP) {
+    return nullptr;
+  }
+
+  return new SourceSurfaceCGBitmapContext(cg);
+}
+
 void
 DrawTargetCG::Mask(const Pattern &aSource,
                    const Pattern &aMask,
                    const DrawOptions &aDrawOptions)
 {
   MarkChanged();
 
   CGContextSaveGState(mCg);
--- a/gfx/2d/DrawTargetCG.h
+++ b/gfx/2d/DrawTargetCG.h
@@ -124,17 +124,17 @@ public:
   virtual void Fill(const Path *, const Pattern &, const DrawOptions &);
   virtual void FillGlyphs(ScaledFont *, const GlyphBuffer&, const Pattern &, const DrawOptions &, const GlyphRenderingOptions *);
   virtual void Mask(const Pattern &aSource,
                     const Pattern &aMask,
                     const DrawOptions &aOptions = DrawOptions());
   virtual void PushClip(const Path *);
   virtual void PushClipRect(const Rect &aRect);
   virtual void PopClip();
-  virtual TemporaryRef<SourceSurface> CreateSourceSurfaceFromNativeSurface(const NativeSurface&) const { return nullptr;}
+  virtual TemporaryRef<SourceSurface> CreateSourceSurfaceFromNativeSurface(const NativeSurface&) const;
   virtual TemporaryRef<DrawTarget> CreateSimilarDrawTarget(const IntSize &, SurfaceFormat) const;
   virtual TemporaryRef<PathBuilder> CreatePathBuilder(FillRule) const;
   virtual TemporaryRef<GradientStops> CreateGradientStops(GradientStop *, uint32_t,
                                                           ExtendMode aExtendMode = EXTEND_CLAMP) const;
 
   virtual void *GetNativeSurface(NativeSurfaceType);
 
   virtual IntSize GetSize() { return mSize; }
--- a/gfx/2d/SourceSurfaceCG.cpp
+++ b/gfx/2d/SourceSurfaceCG.cpp
@@ -236,19 +236,31 @@ DataSourceSurfaceCG::GetData()
   // unfortunately the the method above only works for read-only access and
   // 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();
+  Init((CGContextRef)aDrawTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT));
+}
+
+SourceSurfaceCGBitmapContext::SourceSurfaceCGBitmapContext(CGContextRef cg)
+{
+  Init(cg);
+}
+
+void
+SourceSurfaceCGBitmapContext::Init(CGContextRef cg)
+{
+  MOZ_ASSERT(cg);
+  MOZ_ASSERT(GetContextType(cg) == CG_CONTEXT_TYPE_BITMAP);
+
+  mCg = CGContextRetain(cg);
 
   mSize.width = CGBitmapContextGetWidth(mCg);
   mSize.height = CGBitmapContextGetHeight(mCg);
   mStride = CGBitmapContextGetBytesPerRow(mCg);
   mData = CGBitmapContextGetData(mCg);
 
   mImage = nullptr;
 }
@@ -303,27 +315,31 @@ SourceSurfaceCGBitmapContext::DrawTarget
     // we transfer it to mImage
     memcpy(mData, CGBitmapContextGetData(mCg), stride*height);
 
     // drop the current image for the data associated with the CGBitmapContext
     if (mImage)
       CGImageRelease(mImage);
     mImage = nullptr;
 
+    CGContextRelease(mCg);
     mCg = nullptr;
     mDrawTarget = nullptr;
   }
 }
 
 SourceSurfaceCGBitmapContext::~SourceSurfaceCGBitmapContext()
 {
   if (!mImage && !mCg) {
     // neither mImage or mCg owns the data
     free(mData);
   }
+  if (mCg) {
+    CGContextRelease(mCg);
+  }
   if (mImage)
     CGImageRelease(mImage);
 }
 
 SourceSurfaceCGIOSurfaceContext::SourceSurfaceCGIOSurfaceContext(DrawTargetCG *aDrawTarget)
 {
   CGContextRef cg = (CGContextRef)aDrawTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT_ACCELERATED);
 
--- a/gfx/2d/SourceSurfaceCG.h
+++ b/gfx/2d/SourceSurfaceCG.h
@@ -83,37 +83,42 @@ public:
   virtual void DrawTargetWillChange() = 0;
   virtual CGImageRef GetImage() = 0;
 };
 
 class SourceSurfaceCGBitmapContext : public SourceSurfaceCGContext
 {
 public:
   SourceSurfaceCGBitmapContext(DrawTargetCG *);
+  SourceSurfaceCGBitmapContext(CGContextRef);
   ~SourceSurfaceCGBitmapContext();
 
+  void Init(CGContextRef);
+
   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() { return static_cast<unsigned char*>(mData); }
 
   virtual int32_t Stride() { return mStride; }
 
 private:
   //XXX: do the other backends friend their DrawTarget?
   friend class DrawTargetCG;
   virtual void DrawTargetWillChange();
   void EnsureImage() const;
 
-  // We hold a weak reference to these two objects.
+  // We hold a weak reference to this objects.
+  DrawTargetCG *mDrawTarget;
+
+  // We hold a strong reference to this.
   // The cycle is broken by DrawTargetWillChange
-  DrawTargetCG *mDrawTarget;
   CGContextRef mCg;
 
   mutable CGImageRef mImage;
 
   // mData can be owned by three different things:
   // mImage, mCg or SourceSurfaceCGBitmapContext
   void *mData;
 
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -634,16 +634,25 @@ gfxPlatform::GetSourceSurfaceForSurface(
     surf.mType = NATIVE_SURFACE_D3D10_TEXTURE;
     surf.mSurface = static_cast<gfxD2DSurface*>(aSurface)->GetTexture();
     mozilla::gfx::DrawTarget *dt = static_cast<mozilla::gfx::DrawTarget*>(aSurface->GetData(&kDrawTarget));
     if (dt) {
       dt->Flush();
     }
     srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
   } else
+#elif defined XP_MACOSX
+  if (aSurface->GetType() == gfxASurface::SurfaceTypeQuartz) {
+    NativeSurface surf;
+    surf.mFormat = format;
+    surf.mType = NATIVE_SURFACE_CGCONTEXT;
+    surf.mSurface = static_cast<gfxQuartzSurface*>(aSurface)->GetCGContext();
+
+    srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
+  } else
 #endif
   if (aSurface->CairoSurface() && aTarget->GetType() == BACKEND_CAIRO) {
     // If this is an xlib cairo surface we don't want to fetch it into memory
     // because this is a major slow down.
     NativeSurface surf;
     surf.mFormat = format;
     surf.mType = NATIVE_SURFACE_CAIRO_SURFACE;
     surf.mSurface = aSurface->CairoSurface();