More cleanup: streamline paths and bitmaps.

SkBitmapHeap is still used---now exclusively---by pipe.

BUG=skia:

Review URL: https://codereview.chromium.org/715413002
diff --git a/src/core/SkPathHeap.cpp b/src/core/SkPathHeap.cpp
deleted file mode 100644
index 84ffb04..0000000
--- a/src/core/SkPathHeap.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include "SkPathHeap.h"
-#include "SkPath.h"
-#include "SkStream.h"
-#include "SkReadBuffer.h"
-#include "SkTSearch.h"
-#include "SkWriteBuffer.h"
-#include <new>
-
-#define kPathCount  64
-
-SkPathHeap::SkPathHeap() : fHeap(kPathCount * sizeof(SkPath)) {
-}
-
-SkPathHeap::SkPathHeap(SkReadBuffer& buffer)
-            : fHeap(kPathCount * sizeof(SkPath)) {
-    const int count = buffer.readInt();
-
-    fPaths.setCount(count);
-    SkPath** ptr = fPaths.begin();
-    SkPath* p = (SkPath*)fHeap.allocThrow(count * sizeof(SkPath));
-
-    for (int i = 0; i < count; i++) {
-        new (p) SkPath;
-        buffer.readPath(p);
-        *ptr++ = p; // record the pointer
-        p++;        // move to the next storage location
-    }
-}
-
-SkPathHeap::~SkPathHeap() {
-    SkPath** iter = fPaths.begin();
-    SkPath** stop = fPaths.end();
-    while (iter < stop) {
-        (*iter)->~SkPath();
-        iter++;
-    }
-}
-
-int SkPathHeap::append(const SkPath& path) {
-    SkPath* p = (SkPath*)fHeap.allocThrow(sizeof(SkPath));
-    new (p) SkPath(path);
-    *fPaths.append() = p;
-    return fPaths.count();
-}
-
-SkPathHeap::LookupEntry::LookupEntry(const SkPath& path)
-    : fGenerationID(path.getGenerationID()), fStorageSlot(0) {
-}
-
-SkPathHeap::LookupEntry* SkPathHeap::addIfNotPresent(const SkPath& path) {
-    LookupEntry searchKey(path);
-    int index = SkTSearch<const LookupEntry, LookupEntry::Less>(
-                                    fLookupTable.begin(),
-                                    fLookupTable.count(),
-                                    searchKey,
-                                    sizeof(LookupEntry));
-    if (index < 0) {
-        index = ~index;
-        *fLookupTable.insert(index) = LookupEntry(path);
-    }
-
-    return &fLookupTable[index];;
-}
-
-int SkPathHeap::insert(const SkPath& path) {
-    SkPathHeap::LookupEntry* entry = this->addIfNotPresent(path);
-
-    if (entry->storageSlot() > 0) {
-        return entry->storageSlot();
-    }
-
-    int newSlot = this->append(path);
-    SkASSERT(newSlot > 0);
-    entry->setStorageSlot(newSlot);
-    return newSlot;
-}
-
-void SkPathHeap::flatten(SkWriteBuffer& buffer) const {
-    int count = fPaths.count();
-
-    buffer.writeInt(count);
-    SkPath* const* iter = fPaths.begin();
-    SkPath* const* stop = fPaths.end();
-    while (iter < stop) {
-        buffer.writePath(**iter);
-        iter++;
-    }
-}
diff --git a/src/core/SkPathHeap.h b/src/core/SkPathHeap.h
deleted file mode 100644
index 377d8d9..0000000
--- a/src/core/SkPathHeap.h
+++ /dev/null
@@ -1,76 +0,0 @@
-
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef SkPathHeap_DEFINED
-#define SkPathHeap_DEFINED
-
-#include "SkRefCnt.h"
-#include "SkChunkAlloc.h"
-#include "SkTDArray.h"
-
-class SkPath;
-class SkReadBuffer;
-class SkWriteBuffer;
-
-class SkPathHeap : public SkRefCnt {
-public:
-    SK_DECLARE_INST_COUNT(SkPathHeap)
-
-    SkPathHeap();
-    SkPathHeap(SkReadBuffer&);
-    virtual ~SkPathHeap();
-
-    /** Copy the path into the heap, and return the new total number of paths.
-        Thus, the returned value will be index+1, where index is the index of
-        this newly added (copied) path.
-     */
-    int append(const SkPath&);
-
-    /** Add the specified path to the heap using its gen ID to de-duplicate.
-        Returns the path's index in the heap + 1.
-     */
-    int insert(const SkPath&);
-
-    // called during picture-playback
-    int count() const { return fPaths.count(); }
-    const SkPath& operator[](int index) const {
-        return *fPaths[index];
-    }
-
-    void flatten(SkWriteBuffer&) const;
-
-private:
-    // we store the paths in the heap (placement new)
-    SkChunkAlloc        fHeap;
-    // we just store ptrs into fHeap here
-    SkTDArray<SkPath*>  fPaths;
-
-    class LookupEntry {
-    public:
-        LookupEntry(const SkPath& path);
-
-        int storageSlot() const { return fStorageSlot; }
-        void setStorageSlot(int storageSlot) { fStorageSlot = storageSlot; }
-
-        static bool Less(const LookupEntry& a, const LookupEntry& b) {
-            return a.fGenerationID < b.fGenerationID;
-        }
-
-    private:
-        uint32_t fGenerationID;     // the SkPath's generation ID
-        // the path's index in the heap + 1. It is 0 if the path is not yet in the heap.
-        int      fStorageSlot;
-    };
-
-    SkTDArray<LookupEntry> fLookupTable;
-
-    SkPathHeap::LookupEntry* addIfNotPresent(const SkPath& path);
-
-    typedef SkRefCnt INHERITED;
-};
-
-#endif
diff --git a/src/core/SkPictureData.cpp b/src/core/SkPictureData.cpp
index 556e2a5..29e4415 100644
--- a/src/core/SkPictureData.cpp
+++ b/src/core/SkPictureData.cpp
@@ -30,10 +30,8 @@
 
 void SkPictureData::initForPlayback() const {
     // ensure that the paths bounds are pre-computed
-    if (fPathHeap.get()) {
-        for (int i = 0; i < fPathHeap->count(); i++) {
-            (*fPathHeap.get())[i].updateBoundsCache();
-        }
+    for (int i = 0; i < fPaths->count(); i++) {
+        (*fPaths)[i].updateBoundsCache();
     }
 }
 
@@ -48,11 +46,9 @@
 
     fContentInfo.set(record.fContentInfo);
 
-    fBitmaps = record.fBitmapHeap->extractBitmaps();
-    fPaints = SkTRefArray<SkPaint>::Create(record.fPaints.begin(), record.fPaints.count());
-
-    fBitmapHeap.reset(SkSafeRef(record.fBitmapHeap));
-    fPathHeap.reset(SkSafeRef(record.pathHeap()));
+    fBitmaps = SkTRefArray<SkBitmap>::Create(record.fBitmaps.begin(), record.fBitmaps.count());
+    fPaints  = SkTRefArray<SkPaint> ::Create(record.fPaints .begin(), record.fPaints .count());
+    fPaths   = SkTRefArray<SkPath>  ::Create(record.fPaths  .begin(), record.fPaths  .count());
 
     this->initForPlayback();
 
@@ -80,6 +76,7 @@
 void SkPictureData::init() {
     fBitmaps = NULL;
     fPaints = NULL;
+    fPaths = NULL;
     fPictureRefs = NULL;
     fPictureCount = 0;
     fTextBlobRefs = NULL;
@@ -93,6 +90,7 @@
 
     SkSafeUnref(fBitmaps);
     SkSafeUnref(fPaints);
+    SkSafeUnref(fPaths);
 
     for (int i = 0; i < fPictureCount; i++) {
         fPictureRefs[i]->unref();
@@ -210,9 +208,12 @@
         }
     }
 
-    if ((n = SafeCount(fPathHeap.get())) > 0) {
+    if ((n = SafeCount(fPaths)) > 0) {
         write_tag_size(buffer, SK_PICT_PATH_BUFFER_TAG, n);
-        fPathHeap->flatten(buffer);
+        buffer.writeInt(n);
+        for (int i = 0; i < n; i++) {
+            buffer.writePath((*fPaths)[i]);
+        }
     }
 
     if (fTextBlobCount > 0) {
@@ -441,9 +442,12 @@
         } break;
         case SK_PICT_PATH_BUFFER_TAG:
             if (size > 0) {
-                fPathHeap.reset(SkNEW_ARGS(SkPathHeap, (buffer)));
-            }
-            break;
+                const int count = buffer.readInt();
+                fPaths = SkTRefArray<SkPath>::Create(count);
+                for (int i = 0; i < count; i++) {
+                    buffer.readPath(&fPaths->writableAt(i));
+                }
+            } break;
         case SK_PICT_TEXTBLOB_BUFFER_TAG: {
             if (!buffer.validate((0 == fTextBlobCount) && (NULL == fTextBlobRefs))) {
                 return false;
diff --git a/src/core/SkPictureData.h b/src/core/SkPictureData.h
index 0252993..9a5a4ca 100644
--- a/src/core/SkPictureData.h
+++ b/src/core/SkPictureData.h
@@ -9,7 +9,6 @@
 #define SkPictureData_DEFINED
 
 #include "SkBitmap.h"
-#include "SkPathHeap.h"
 #include "SkPicture.h"
 #include "SkPictureContentInfo.h"
 #include "SkPictureFlat.h"
@@ -85,18 +84,12 @@
 public:
     const SkBitmap& getBitmap(SkReader32* reader) const {
         const int index = reader->readInt();
-        if (SkBitmapHeap::INVALID_SLOT == index) {
-#ifdef SK_DEBUG
-            SkDebugf("An invalid bitmap was recorded!\n");
-#endif
-            return fBadBitmap;
-        }
         return (*fBitmaps)[index];
     }
 
     const SkPath& getPath(SkReader32* reader) const {
         int index = reader->readInt() - 1;
-        return (*fPathHeap.get())[index];
+        return (*fPaths)[index];
     }
 
     const SkPicture* getPicture(SkReader32* reader) const {
@@ -149,15 +142,12 @@
     // bitmap allows playback to draw nothing and move on.
     SkBitmap fBadBitmap;
 
-    SkAutoTUnref<SkBitmapHeap> fBitmapHeap;
-
     SkTRefArray<SkBitmap>* fBitmaps;
-    SkTRefArray<SkPaint>* fPaints;
+    SkTRefArray<SkPaint>*  fPaints;
+    SkTRefArray<SkPath>*   fPaths;
 
     SkData* fOpData;    // opcodes and parameters
 
-    SkAutoTUnref<const SkPathHeap> fPathHeap;  // reference counted
-
     const SkPicture** fPictureRefs;
     int fPictureCount;
     const SkTextBlob** fTextBlobRefs;
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 00c51ac..af1b8ff 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -31,16 +31,12 @@
 
 SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
     : INHERITED(dimensions.width(), dimensions.height())
-    , fRecordFlags(flags) {
-
-    fBitmapHeap = SkNEW(SkBitmapHeap);
-
-    fFirstSavedLayerIndex = kNoSavedLayerIndex;
-    fInitialSaveCount = kNoInitialSave;
+    , fFirstSavedLayerIndex(kNoSavedLayerIndex)
+    , fRecordFlags(flags)
+    , fInitialSaveCount(kNoInitialSave) {
 }
 
 SkPictureRecord::~SkPictureRecord() {
-    SkSafeUnref(fBitmapHeap);
     fPictureRefs.unrefAll();
     fTextBlobRefs.unrefAll();
 }
@@ -905,13 +901,16 @@
 }
 
 int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
-    const int index = fBitmapHeap->insert(bitmap);
-    // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
-    // release builds, the invalid value will be recorded so that the reader will know that there
-    // was a problem.
-    SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
-    this->addInt(index);
-    return index;
+    if (bitmap.isImmutable()) {
+        fBitmaps.push_back(bitmap);
+    } else {
+        SkBitmap copy;
+        bitmap.copyTo(&copy);
+        copy.setImmutable();
+        fBitmaps.push_back(copy);
+    }
+    this->addInt(fBitmaps.count()-1);  // Unlike the rest, bitmap indicies are 0-based.
+    return fBitmaps.count();
 }
 
 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
@@ -930,14 +929,8 @@
 }
 
 int SkPictureRecord::addPathToHeap(const SkPath& path) {
-    if (NULL == fPathHeap) {
-        fPathHeap.reset(SkNEW(SkPathHeap));
-    }
-#ifdef SK_DEDUP_PICTURE_PATHS
-    return fPathHeap->insert(path);
-#else
-    return fPathHeap->append(path);
-#endif
+    fPaths.push_back(path);
+    return fPaths.count();
 }
 
 void SkPictureRecord::addPath(const SkPath& path) {
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index bac5586..6a577ca 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -10,7 +10,6 @@
 
 #include "SkCanvas.h"
 #include "SkFlattenable.h"
-#include "SkPathHeap.h"
 #include "SkPicture.h"
 #include "SkPictureData.h"
 #include "SkTemplates.h"
@@ -82,10 +81,6 @@
         return fWriter.snapshotAsData();
     }
 
-    const SkPathHeap* pathHeap() const {
-        return fPathHeap.get();
-    }
-
     const SkPictureContentInfo& contentInfo() const {
         return fContentInfo;
     }
@@ -236,14 +231,12 @@
     void recordSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags);
     void recordRestore(bool fillInSkips = true);
 
-    // Allocated in the constructor and managed by this class.
-    SkBitmapHeap* fBitmapHeap;
-
 private:
     SkPictureContentInfo fContentInfo;
-    SkAutoTUnref<SkPathHeap> fPathHeap;
 
-    SkTArray<SkPaint> fPaints;
+    SkTArray<SkBitmap> fBitmaps;
+    SkTArray<SkPaint>  fPaints;
+    SkTArray<SkPath>   fPaths;
 
     SkWriter32 fWriter;