Fix SkGPipe drawing, and turn it on by default.

A recent change broke SkGPipe. Fix it, and turn on pipe drawing
in GM by default so we will catch these in the future.

We already had a bug where SkGPipeWriter had to use its Cross Process
flag to work, so for a quick fix, force the reader to use the Cross
Process flag as well. The bug to allow both cross and non cross process
is http://code.google.com/p/skia/issues/detail?id=663

Review URL: https://codereview.appspot.com/6333071

git-svn-id: http://skia.googlecode.com/svn/trunk@4384 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index b97b98d..15adea8 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -68,7 +68,7 @@
  */
 class Heap {
 public:
-    Heap() {}
+    Heap(bool shallow) : fCanDoShallowCopies(shallow) {}
     ~Heap() {
         for (int i = 0; i < fBitmaps.count(); i++) {
             delete fBitmaps[i].fBitmap;
@@ -88,18 +88,23 @@
                 return fBitmaps[i].fBitmap;
             }
         }
-        // TODO: Use a flag to determine whether we need the bitmap to be
-        // in shared cross process address space. If not, we can do a shallow
-        // copy.
-        SkBitmap* copy = new SkBitmap();
-        if (bm.copyTo(copy, bm.getConfig())) {
-            BitmapInfo* info = fBitmaps.append();
-            info->fBitmap = copy;
-            info->fGenID = genID;
-            return copy;
+        SkBitmap* copy;
+        // If the bitmap is mutable, we still need to do a deep copy, since the
+        // caller may modify it afterwards. That said, if the bitmap is mutable,
+        // but has no pixelRef, the copy constructor actually does a deep copy.
+        if (fCanDoShallowCopies && (bm.isImmutable() || !bm.pixelRef())) {
+            copy = new SkBitmap(bm);
+        } else {
+            copy = new SkBitmap();
+            if (!bm.copyTo(copy, bm.getConfig())) {
+                delete copy;
+                return NULL;
+            }
         }
-        delete copy;
-        return NULL;
+        BitmapInfo* info = fBitmaps.append();
+        info->fBitmap = copy;
+        info->fGenID = genID;
+        return copy;
     }
 private:
     struct BitmapInfo {
@@ -109,14 +114,15 @@
         // for comparing.
         uint32_t fGenID;
     };
-    SkTDArray<BitmapInfo>fBitmaps;
+    SkTDArray<BitmapInfo>   fBitmaps;
+    const bool              fCanDoShallowCopies;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 
 class SkGPipeCanvas : public SkCanvas {
 public:
-    SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*);
+    SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*, uint32_t flags);
     virtual ~SkGPipeCanvas();
 
     void finish() {
@@ -187,6 +193,7 @@
     size_t      fBlockSize; // amount allocated for writer
     size_t      fBytesNotified;
     bool        fDone;
+    uint32_t    fFlags;
 
     SkRefCntSet fTypefaceSet;
 
@@ -246,10 +253,12 @@
 };
 
 int SkGPipeCanvas::flattenToIndex(const SkBitmap & bitmap) {
+    SkASSERT(shouldFlattenBitmaps(fFlags));
     SkOrderedWriteBuffer tmpWriter(1024);
-    // FIXME: Rather than forcing CrossProcess, we should create an SkRefCntSet
-    // so that we can store a pointer to a bitmap's pixels during flattening.
-    tmpWriter.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag);
+    tmpWriter.setFlags((SkFlattenableWriteBuffer::Flags)
+                       (SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
+                        | SkFlattenableWriteBuffer::kCrossProcess_Flag));
+    tmpWriter.setFactoryRecorder(fFactorySet);
     bitmap.flatten(tmpWriter);
 
     size_t len = tmpWriter.size();
@@ -271,9 +280,8 @@
         // for a NULL bitmap (unlike with paint flattenables).
         copy->fIndex = fBitmapArray.count();
         *fBitmapArray.insert(index) = copy;
-        if (this->needOpBytes(len + sizeof(uint32_t))) {
+        if (this->needOpBytes(len)) {
             this->writeOp(kDef_Bitmap_DrawOp, 0, copy->fIndex);
-            fWriter.write32(len);
             fWriter.write(copy->data(), len);
         }
     }
@@ -288,13 +296,15 @@
 
     SkOrderedWriteBuffer tmpWriter(1024);
     
-    // Needs to be cross process so a bitmap shader will be preserved
-    // FIXME: Rather than forcing CrossProcess, we should create an SkRefCntSet
-    // so that we can store a pointer to a bitmap's pixels during flattening.
-    tmpWriter.setFlags((SkFlattenableWriteBuffer::Flags)
-                       (SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
-                       | SkFlattenableWriteBuffer::kCrossProcess_Flag));
-    tmpWriter.setFactoryRecorder(fFactorySet);
+    if (fFlags & SkGPipeWriter::kCrossProcess_Flag) {
+        tmpWriter.setFlags((SkFlattenableWriteBuffer::Flags)
+                           (SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
+                           | SkFlattenableWriteBuffer::kCrossProcess_Flag));
+        tmpWriter.setFactoryRecorder(fFactorySet);
+    } else {
+        // Needed for bitmap shaders.
+        tmpWriter.setFlags(SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag);
+    }
 
     tmpWriter.writeFlattenable(obj);
     size_t len = tmpWriter.size();
@@ -330,8 +340,8 @@
 #define MIN_BLOCK_SIZE  (16 * 1024)
 
 SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
-                             SkWriter32* writer, SkFactorySet* fset)
-        : fWriter(*writer) {
+                             SkWriter32* writer, SkFactorySet* fset, uint32_t flags)
+: fWriter(*writer), fFlags(flags), fHeap(!(flags & SkGPipeWriter::kCrossProcess_Flag)) {
     fFactorySet = fset;
     fController = controller;
     fDone = false;
@@ -346,6 +356,10 @@
     bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
     SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
     this->setDevice(device)->unref();
+    // Tell the reader the appropriate flags to use.
+    if (this->needOpBytes()) {
+        this->writeOp(kReportFlags_DrawOp, fFlags, 0);
+    }
 }
 
 SkGPipeCanvas::~SkGPipeCanvas() {
@@ -596,9 +610,16 @@
 
 void SkGPipeCanvas::drawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top,
                                    const SkPaint* paint) {
-    const void* ptr(fHeap.addBitmap(bm));
-    if (NULL == ptr) {
-        return;
+    bool flatten = shouldFlattenBitmaps(fFlags);
+    const void* ptr = 0;
+    int bitmapIndex = 0;
+    if (flatten) {
+        bitmapIndex = this->flattenToIndex(bm);
+    } else {
+        ptr = fHeap.addBitmap(bm);
+        if (NULL == ptr) {
+            return;
+        }
     }
 
     NOTIFY_SETUP(this);
@@ -606,9 +627,15 @@
         this->writePaint(*paint);
     }
 
-    if (this->needOpBytes(sizeof(SkScalar) * 2 + sizeof(bool) + sizeof(void*))) {
-        this->writeOp(kDrawBitmap_DrawOp, 0, 0);
-        fWriter.writePtr(const_cast<void*>(ptr));
+    size_t opBytesNeeded = sizeof(SkScalar) * 2 + sizeof(bool);
+    if (!flatten) {
+        opBytesNeeded += sizeof(void*);
+    }
+    if (this->needOpBytes(opBytesNeeded)) {
+        this->writeOp(kDrawBitmap_DrawOp, 0, bitmapIndex);
+        if (!flatten) {
+            fWriter.writePtr(const_cast<void*>(ptr));
+        }
         fWriter.writeBool(paint != NULL);
         fWriter.writeScalar(left);
         fWriter.writeScalar(top);
@@ -617,9 +644,16 @@
 
 void SkGPipeCanvas::drawBitmapRect(const SkBitmap& bm, const SkIRect* src,
                                        const SkRect& dst, const SkPaint* paint) {
-    const void* ptr(fHeap.addBitmap(bm));
-    if (NULL == ptr) {
-        return;
+    bool flatten = shouldFlattenBitmaps(fFlags);
+    const void* ptr = 0;
+    int bitmapIndex = 0;
+    if (flatten) {
+        bitmapIndex = this->flattenToIndex(bm);
+    } else {
+        ptr = fHeap.addBitmap(bm);
+        if (NULL == ptr) {
+            return;
+        }
     }
 
     NOTIFY_SETUP(this);
@@ -627,14 +661,19 @@
         this->writePaint(*paint);
     }
 
-    size_t opBytesNeeded = sizeof(SkRect) + sizeof(bool) * 2 + sizeof(void*);
+    size_t opBytesNeeded = sizeof(SkRect) + sizeof(bool) * 2;
     bool hasSrc = src != NULL;
     if (hasSrc) {
         opBytesNeeded += sizeof(int32_t) * 4;
     }
+    if (!flatten) {
+        opBytesNeeded += sizeof(void*);
+    }
     if (this->needOpBytes(opBytesNeeded)) {
-        this->writeOp(kDrawBitmapRect_DrawOp, 0, 0);
-        fWriter.writePtr(const_cast<void*>(ptr));
+        this->writeOp(kDrawBitmapRect_DrawOp, 0, bitmapIndex);
+        if (!flatten) {
+            fWriter.writePtr(const_cast<void*>(ptr));
+        }
         fWriter.writeBool(paint != NULL);
         fWriter.writeBool(hasSrc);
         if (hasSrc) {
@@ -654,9 +693,16 @@
 
 void SkGPipeCanvas::drawBitmapNine(const SkBitmap& bm, const SkIRect& center,
                                    const SkRect& dst, const SkPaint* paint) {
-    const void* ptr(fHeap.addBitmap(bm));
-    if (NULL == ptr) {
-        return;
+    bool flatten = shouldFlattenBitmaps(fFlags);
+    const void* ptr = 0;
+    int bitmapIndex = 0;
+    if (flatten) {
+        bitmapIndex = this->flattenToIndex(bm);
+    } else {
+        ptr = fHeap.addBitmap(bm);
+        if (NULL == ptr) {
+            return;
+        }
     }
 
     NOTIFY_SETUP(this);
@@ -664,10 +710,15 @@
         this->writePaint(*paint);
     }
 
-    if (this->needOpBytes(sizeof(int32_t) * 4 + sizeof(bool)
-                          + sizeof(SkRect) + sizeof(void*))) {
-        this->writeOp(kDrawBitmapNine_DrawOp, 0, 0);
-        fWriter.writePtr(const_cast<void*>(ptr));
+    size_t opBytesNeeded = sizeof(int32_t) * 4 + sizeof(bool) + sizeof(SkRect);
+    if (!flatten) {
+        opBytesNeeded += sizeof(void*);
+    }
+    if (this->needOpBytes(opBytesNeeded)) {
+        this->writeOp(kDrawBitmapNine_DrawOp, 0, bitmapIndex);
+        if (!flatten) {
+            fWriter.writePtr(const_cast<void*>(ptr));
+        }
         fWriter.writeBool(paint != NULL);
         fWriter.write32(center.fLeft);
         fWriter.write32(center.fTop);
@@ -679,9 +730,16 @@
 
 void SkGPipeCanvas::drawSprite(const SkBitmap& bm, int left, int top,
                                    const SkPaint* paint) {
-    const void* ptr(fHeap.addBitmap(bm));
-    if (NULL == ptr) {
-        return;
+    bool flatten = shouldFlattenBitmaps(fFlags);
+    const void* ptr = 0;
+    int bitmapIndex = 0;
+    if (flatten) {
+        bitmapIndex = this->flattenToIndex(bm);
+    } else {
+        ptr = fHeap.addBitmap(bm);
+        if (NULL == ptr) {
+            return;
+        }
     }
 
     NOTIFY_SETUP(this);
@@ -689,9 +747,15 @@
         this->writePaint(*paint);
     }
 
-    if (this->needOpBytes(sizeof(int32_t) * 2 + sizeof(bool) + sizeof(void*))) {
-        this->writeOp(kDrawSprite_DrawOp, 0, 0);
-        fWriter.writePtr(const_cast<void*>(ptr));
+    size_t opBytesNeeded = sizeof(int32_t) * 2 + sizeof(bool);
+    if (!flatten) {
+        opBytesNeeded += sizeof(void*);
+    }
+    if (this->needOpBytes(opBytesNeeded)) {
+        this->writeOp(kDrawSprite_DrawOp, 0, bitmapIndex);
+        if (!flatten) {
+            fWriter.writePtr(const_cast<void*>(ptr));
+        }
         fWriter.writeBool(paint != NULL);
         fWriter.write32(left);
         fWriter.write32(top);
@@ -955,14 +1019,13 @@
     SkSafeUnref(fCanvas);
 }
 
-SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller,
-                                        uint32_t flags) {
+SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t flags) {
     if (NULL == fCanvas) {
         fWriter.reset(NULL, 0);
         fFactorySet.reset();
         fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
                                              (flags & kCrossProcess_Flag) ?
-                                             &fFactorySet : NULL));
+                                             &fFactorySet : NULL, flags));
     }
     return fCanvas;
 }