For SkGPipe, store bitmaps in a common location.

Also make a change to SkBitmap::copyTo() so that we do not
crash.
Review URL: https://codereview.appspot.com/6296066

git-svn-id: http://skia.googlecode.com/svn/trunk@4249 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index 6d5942f..a723113 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -925,7 +925,6 @@
         return false;
     }
     
-    SkAutoLockPixels dstlock(tmpDst);
     if (!tmpDst.readyToDraw()) {
         // allocator/lock failed
         return false;
diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp
index 85f46fd..7f05b31 100644
--- a/src/pipe/SkGPipeRead.cpp
+++ b/src/pipe/SkGPipeRead.cpp
@@ -347,8 +347,7 @@
 
 static void drawBitmap_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                           SkGPipeState* state) {
-    unsigned index = DrawOp_unpackData(op32);
-    SkBitmap* bm = state->getBitmap(index);
+    const SkBitmap* bm(static_cast<const SkBitmap*>(reader->readPtr()));
     bool hasPaint = reader->readBool();
     SkScalar left = reader->readScalar();
     SkScalar top = reader->readScalar();
@@ -362,8 +361,7 @@
 
 static void drawBitmapNine_rp(SkCanvas* canvas, SkReader32* reader,
                               uint32_t op32, SkGPipeState* state) {
-    unsigned index = DrawOp_unpackData(op32);
-    SkBitmap* bm = state->getBitmap(index);
+    const SkBitmap* bm(static_cast<const SkBitmap*>(reader->readPtr()));
     bool hasPaint = reader->readBool();
     const SkIRect* center = skip<SkIRect>(reader);
     const SkRect* dst = skip<SkRect>(reader);
@@ -373,8 +371,7 @@
 
 static void drawBitmapRect_rp(SkCanvas* canvas, SkReader32* reader,
                               uint32_t op32, SkGPipeState* state) {
-    unsigned index = DrawOp_unpackData(op32);
-    SkBitmap* bm = state->getBitmap(index);
+    const SkBitmap* bm(static_cast<const SkBitmap*>(reader->readPtr()));
     bool hasPaint = reader->readBool();
     bool hasSrc = reader->readBool();
     const SkIRect* src;
@@ -389,8 +386,7 @@
 
 static void drawSprite_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                           SkGPipeState* state) {
-    unsigned index = DrawOp_unpackData(op32);
-    SkBitmap* bm = state->getBitmap(index);
+    const SkBitmap* bm(static_cast<const SkBitmap*>(reader->readPtr()));
     bool hasPaint = reader->readBool();
     const SkIPoint* point = skip<SkIPoint>(reader);
     canvas->drawSprite(*bm, point->fX, point->fY, hasPaint ? &state->paint() : NULL);
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index 24ca0ea..b97b98d 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -58,6 +58,62 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+/*
+ * Shared heap for storing large things that can be shared, for a stream
+ * used by multiple readers.
+ * TODO: Make the allocations all come from cross process safe address space
+ * TODO: Store paths (others?)
+ * TODO: Allow reclaiming of memory. Will require us to know when all readers
+ *       have used the object.
+ */
+class Heap {
+public:
+    Heap() {}
+    ~Heap() {
+        for (int i = 0; i < fBitmaps.count(); i++) {
+            delete fBitmaps[i].fBitmap;
+        }
+    }
+
+    /*
+     * Add a copy of a bitmap to the heap.
+     * @param bm The SkBitmap to be copied and placed in the heap.
+     * @return void* Pointer to the heap's copy of the bitmap. If NULL,
+     *               the bitmap could not be copied.
+     */
+    const SkBitmap* addBitmap(const SkBitmap& bm) {
+        const uint32_t genID = bm.getGenerationID();
+        for (int i = fBitmaps.count() - 1; i >= 0; i--) {
+            if (genID == fBitmaps[i].fGenID) {
+                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;
+        }
+        delete copy;
+        return NULL;
+    }
+private:
+    struct BitmapInfo {
+        SkBitmap* fBitmap;
+        // Store the generation ID of the original bitmap, since copying does
+        // not copy this field, so fBitmap's generation ID will not be useful
+        // for comparing.
+        uint32_t fGenID;
+    };
+    SkTDArray<BitmapInfo>fBitmaps;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
 class SkGPipeCanvas : public SkCanvas {
 public:
     SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*);
@@ -124,6 +180,7 @@
     virtual void drawData(const void*, size_t) SK_OVERRIDE;
 
 private:
+    Heap fHeap;
     SkFactorySet* fFactorySet;  // optional, only used if cross-process
     SkGPipeController* fController;
     SkWriter32& fWriter;
@@ -539,17 +596,19 @@
 
 void SkGPipeCanvas::drawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top,
                                    const SkPaint* paint) {
-    // This is the brute-force solution
-    // TODO: add the notion of a shared, counted for large immutable resources
+    const void* ptr(fHeap.addBitmap(bm));
+    if (NULL == ptr) {
+        return;
+    }
+
     NOTIFY_SETUP(this);
     if (paint) {
         this->writePaint(*paint);
     }
 
-    int bitmapIndex = this->flattenToIndex(bm);
-    
-    if (this->needOpBytes(sizeof(SkScalar) * 2 + sizeof(bool))) {
-        this->writeOp(kDrawBitmap_DrawOp, 0, bitmapIndex);
+    if (this->needOpBytes(sizeof(SkScalar) * 2 + sizeof(bool) + sizeof(void*))) {
+        this->writeOp(kDrawBitmap_DrawOp, 0, 0);
+        fWriter.writePtr(const_cast<void*>(ptr));
         fWriter.writeBool(paint != NULL);
         fWriter.writeScalar(left);
         fWriter.writeScalar(top);
@@ -558,20 +617,24 @@
 
 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;
+    }
+
     NOTIFY_SETUP(this);
     if (paint) {
         this->writePaint(*paint);
     }
 
-    int bitmapIndex = this->flattenToIndex(bm);
-
-    size_t opBytesNeeded = sizeof(SkRect) + sizeof(bool) * 2;
+    size_t opBytesNeeded = sizeof(SkRect) + sizeof(bool) * 2 + sizeof(void*);
     bool hasSrc = src != NULL;
     if (hasSrc) {
         opBytesNeeded += sizeof(int32_t) * 4;
     }
     if (this->needOpBytes(opBytesNeeded)) {
-        this->writeOp(kDrawBitmapRect_DrawOp, 0, bitmapIndex);
+        this->writeOp(kDrawBitmapRect_DrawOp, 0, 0);
+        fWriter.writePtr(const_cast<void*>(ptr));
         fWriter.writeBool(paint != NULL);
         fWriter.writeBool(hasSrc);
         if (hasSrc) {
@@ -591,15 +654,20 @@
 
 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;
+    }
+
     NOTIFY_SETUP(this);
     if (paint) {
         this->writePaint(*paint);
     }
-    int bitmapIndex = this->flattenToIndex(bm);
 
     if (this->needOpBytes(sizeof(int32_t) * 4 + sizeof(bool)
-                          + sizeof(SkRect))) {
-        this->writeOp(kDrawBitmapNine_DrawOp, 0, bitmapIndex);
+                          + sizeof(SkRect) + sizeof(void*))) {
+        this->writeOp(kDrawBitmapNine_DrawOp, 0, 0);
+        fWriter.writePtr(const_cast<void*>(ptr));
         fWriter.writeBool(paint != NULL);
         fWriter.write32(center.fLeft);
         fWriter.write32(center.fTop);
@@ -611,14 +679,19 @@
 
 void SkGPipeCanvas::drawSprite(const SkBitmap& bm, int left, int top,
                                    const SkPaint* paint) {
+    const void* ptr(fHeap.addBitmap(bm));
+    if (NULL == ptr) {
+        return;
+    }
+
     NOTIFY_SETUP(this);
     if (paint) {
         this->writePaint(*paint);
     }
-    int bitmapIndex = this->flattenToIndex(bm);
 
-    if (this->needOpBytes(sizeof(int32_t) * 2 + sizeof(bool))) {
-        this->writeOp(kDrawSprite_DrawOp, 0, bitmapIndex);
+    if (this->needOpBytes(sizeof(int32_t) * 2 + sizeof(bool) + sizeof(void*))) {
+        this->writeOp(kDrawSprite_DrawOp, 0, 0);
+        fWriter.writePtr(const_cast<void*>(ptr));
         fWriter.writeBool(paint != NULL);
         fWriter.write32(left);
         fWriter.write32(top);