Bug 1340627. Properly push/pop skia saved layers during borrow/return cg context. r=lsalzman
authorMason Chang <mchang@mozilla.com>
Wed, 10 May 2017 16:21:13 -0400
changeset 576325 e06077091df1f2577a052b43e86135cc12e87a4c
parent 576324 0ebe08d1aa9297a703a15a0d0c2794a0bd1dda8b
child 576326 db4d4ed118a5f15dcf44ddd1cb7da17badf6f9c4
push id58318
push userdmitchell@mozilla.com
push dateThu, 11 May 2017 16:12:32 +0000
reviewerslsalzman
bugs1340627
milestone55.0a1
Bug 1340627. Properly push/pop skia saved layers during borrow/return cg context. r=lsalzman
gfx/2d/DrawTargetSkia.cpp
gfx/2d/DrawTargetSkia.h
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -263,16 +263,17 @@ GetSkImageForSurface(SourceSurface* aSur
 
 DrawTargetSkia::DrawTargetSkia()
   : mSnapshot(nullptr)
 #ifdef MOZ_WIDGET_COCOA
   , mCG(nullptr)
   , mColorSpace(nullptr)
   , mCanvasData(nullptr)
   , mCGSize(0, 0)
+  , mNeedLayer(false)
 #endif
 {
 }
 
 DrawTargetSkia::~DrawTargetSkia()
 {
 #ifdef MOZ_WIDGET_COCOA
   if (mCG) {
@@ -1088,35 +1089,38 @@ SetupCGGlyphs(CGContextRef aCGContext,
 
 // The context returned from this method will have the origin
 // in the top left and will have applied all the neccessary clips
 // and transforms to the CGContext. See the comment above
 // SetupCGContext.
 CGContextRef
 DrawTargetSkia::BorrowCGContext(const DrawOptions &aOptions)
 {
-  bool needLayer = !mCanvas->isClipEmpty() && !mCanvas->isClipRect();
-  if (needLayer) {
+  // Since we can't replay Skia clips, we have to use a layer if we have a complex clip.
+  // After saving a layer, the SkCanvas queries for needing a layer change so save if we
+  // pushed a layer.
+  mNeedLayer = !mCanvas->isClipEmpty() && !mCanvas->isClipRect();
+  if (mNeedLayer) {
     SkPaint paint;
     paint.setBlendMode(SkBlendMode::kSrc);
     SkCanvas::SaveLayerRec rec(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
     mCanvas->saveLayer(rec);
   }
 
   uint8_t* data = nullptr;
   int32_t stride;
   SurfaceFormat format;
   IntSize size;
   IntPoint origin;
   if (!LockBits(&data, &size, &stride, &format, &origin)) {
     NS_WARNING("Could not lock skia bits to wrap CG around");
     return nullptr;
   }
 
-  if (!needLayer && (data == mCanvasData) && mCG && (mCGSize == size)) {
+  if (!mNeedLayer && (data == mCanvasData) && mCG && (mCGSize == size)) {
     // If our canvas data still points to the same data,
     // we can reuse the CG Context
     CGContextSaveGState(mCG);
     CGContextSetAlpha(mCG, aOptions.mAlpha);
     SetupCGContext(this, mCG, mCanvas, origin, size);
     return mCG;
   }
 
@@ -1142,17 +1146,17 @@ DrawTargetSkia::BorrowCGContext(const Dr
                                       mCGSize.height,
                                       8, /* bits per component */
                                       stride,
                                       mColorSpace,
                                       bitmapInfo,
                                       NULL, /* Callback when released */
                                       NULL);
   if (!mCG) {
-    if (needLayer) {
+    if (mNeedLayer) {
       mCanvas->restore();
     }
     ReleaseBits(mCanvasData);
     NS_WARNING("Could not create bitmap around skia data\n");
     return nullptr;
   }
 
   CGContextSetAlpha(mCG, aOptions.mAlpha);
@@ -1166,18 +1170,17 @@ DrawTargetSkia::BorrowCGContext(const Dr
 
 void
 DrawTargetSkia::ReturnCGContext(CGContextRef aCGContext)
 {
   MOZ_ASSERT(aCGContext == mCG);
   ReleaseBits(mCanvasData);
   CGContextRestoreGState(aCGContext);
 
-  bool needLayer = !mCanvas->isClipEmpty() && !mCanvas->isClipRect();
-  if (needLayer) {
+  if (mNeedLayer) {
     // A layer was used for clipping and is about to be popped by the restore.
     // Make sure the CG context referencing it is released first so the popped
     // layer doesn't accidentally get used.
     if (mCG) {
       CGContextRelease(mCG);
       mCG = nullptr;
     }
     mCanvas->restore();
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -218,15 +218,16 @@ private:
                         const Pattern& aPattern,
                         const DrawOptions& aOptions = DrawOptions(),
                         const GlyphRenderingOptions* aRenderingOptions = nullptr);
 
   CGContextRef mCG;
   CGColorSpaceRef mColorSpace;
   uint8_t* mCanvasData;
   IntSize mCGSize;
+  bool mNeedLayer;
 #endif
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif // _MOZILLA_GFX_SOURCESURFACESKIA_H