Pipe factory names independently from the flattenables using them.

Avoids an issue where a flattenable written twice might be written
differently (the first time the flat data may have a name, whereas
the second time it will have an index).

Also add a test which confirms that identical flattenables will have
the same SkFlatData representation.

BUG=https://code.google.com/p/skia/issues/detail?id=721
TEST=FlatDataTest.cpp

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

git-svn-id: http://skia.googlecode.com/svn/trunk@4896 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index 9efc0b5..75f1aff 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -28,6 +28,10 @@
 #include "SkOrderedWriteBuffer.h"
 #include "SkPictureFlat.h"
 
+static bool isCrossProcess(uint32_t flags) {
+    return SkToBool(flags & SkGPipeWriter::kCrossProcess_Flag);
+}
+
 static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
     SkASSERT(paintFlat < kCount_PaintFlats);
     switch (paintFlat) {
@@ -61,7 +65,9 @@
 
 class FlattenableHeap : public SkFlatController {
 public:
-    FlattenableHeap(int numFlatsToKeep) : fNumFlatsToKeep(numFlatsToKeep) {}
+    FlattenableHeap(int numFlatsToKeep)
+        : fNumFlatsToKeep(numFlatsToKeep) {
+    }
 
     ~FlattenableHeap() {
         fPointers.freeAll();
@@ -132,7 +138,7 @@
 
 class FlatDictionary : public SkFlatDictionary<SkFlattenable> {
 public:
-    FlatDictionary(FlattenableHeap* heap, SkFactorySet* factorySet)
+    FlatDictionary(FlattenableHeap* heap, SkNamedFactorySet* factorySet)
             : SkFlatDictionary<SkFlattenable>(heap, NULL, NULL, factorySet) {
         fFlattenProc = &flattenFlattenableProc;
         // No need to define fUnflattenProc since the writer will never
@@ -365,7 +371,7 @@
 
 class SkGPipeCanvas : public SkCanvas {
 public:
-    SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*, uint32_t flags);
+    SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags);
     virtual ~SkGPipeCanvas();
 
     void finish() {
@@ -439,16 +445,17 @@
     enum {
         kNoSaveLayer = -1,
     };
-    int         fFirstSaveLayerStackLevel;
-    SharedHeap  fSharedHeap;
+    SkNamedFactorySet* fFactorySet;
+    int                fFirstSaveLayerStackLevel;
+    SharedHeap         fSharedHeap;
     SkGPipeController* fController;
-    SkWriter32& fWriter;
-    size_t      fBlockSize; // amount allocated for writer
-    size_t      fBytesNotified;
-    bool        fDone;
-    uint32_t    fFlags;
+    SkWriter32&        fWriter;
+    size_t             fBlockSize; // amount allocated for writer
+    size_t             fBytesNotified;
+    bool               fDone;
+    uint32_t           fFlags;
 
-    SkRefCntSet fTypefaceSet;
+    SkRefCntSet        fTypefaceSet;
 
     uint32_t getTypefaceID(SkTypeface*);
 
@@ -472,6 +479,10 @@
         }
     }
 
+    // Should be called after any calls to an SkFlatDictionary::findAndReplace
+    // if a new SkFlatData was added when in cross process mode
+    void flattenFactoryNames();
+
     // These are only used when in cross process, but with no shared address
     // space, so bitmaps are flattened.
     FlattenableHeap    fBitmapHeap;
@@ -509,18 +520,32 @@
     typedef SkCanvas INHERITED;
 };
 
+void SkGPipeCanvas::flattenFactoryNames() {
+    const char* name;
+    while ((name = fFactorySet->getNextAddedFactoryName()) != NULL) {
+        size_t len = strlen(name);
+        if (this->needOpBytes(len)) {
+            this->writeOp(kDef_Factory_DrawOp);
+            fWriter.writeString(name, len);
+        }
+    }
+}
+
 int SkGPipeCanvas::flattenToIndex(const SkBitmap & bitmap) {
     SkASSERT(shouldFlattenBitmaps(fFlags));
-    uint32_t flags = SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
-        | SkFlattenableWriteBuffer::kCrossProcess_Flag;
+    uint32_t flags = SkFlattenableWriteBuffer::kCrossProcess_Flag;
     bool added, replaced;
     const SkFlatData* flat = fBitmapDictionary.findAndReplace(
         bitmap, flags, fBitmapHeap.flatToReplace(), &added, &replaced);
 
     int index = flat->index();
-    if (added && this->needOpBytes(flat->flatSize())) {
-        this->writeOp(kDef_Bitmap_DrawOp, 0, index);
-        fWriter.write(flat->data(), flat->flatSize());
+    if (added) {
+        this->flattenFactoryNames();
+        size_t flatSize = flat->flatSize();
+        if (this->needOpBytes(flatSize)) {
+            this->writeOp(kDef_Bitmap_DrawOp, 0, index);
+            fWriter.write(flat->data(), flatSize);
+        }
     }
     return index;
 }
@@ -533,9 +558,8 @@
     }
 
     uint32_t writeBufferFlags;
-    if (SkToBool(fFlags & SkGPipeWriter::kCrossProcess_Flag)) {
-        writeBufferFlags = (SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
-                            | SkFlattenableWriteBuffer::kCrossProcess_Flag);
+    if (isCrossProcess(fFlags)) {
+        writeBufferFlags =  SkFlattenableWriteBuffer::kCrossProcess_Flag;
     } else {
         // Needed for bitmap shaders.
         writeBufferFlags = SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag;
@@ -545,9 +569,15 @@
     const SkFlatData* flat = fFlatDictionary.findAndReplace(
             *obj, writeBufferFlags, fFlattenableHeap.flatToReplace(), &added, &replaced);
     int index = flat->index();
-    if (added && this->needOpBytes(flat->flatSize())) {
-        this->writeOp(kDef_Flattenable_DrawOp, paintflat, index);
-        fWriter.write(flat->data(), flat->flatSize());
+    if (added) {
+        if (isCrossProcess(fFlags)) {
+            this->flattenFactoryNames();
+        }
+        size_t flatSize = flat->flatSize();
+        if (this->needOpBytes(flatSize)) {
+            this->writeOp(kDef_Flattenable_DrawOp, paintflat, index);
+            fWriter.write(flat->data(), flatSize);
+        }
     }
     if (replaced) {
         index = ~index;
@@ -562,11 +592,15 @@
 #define FLATTENABLES_TO_KEEP 10
 
 SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
-                             SkWriter32* writer, SkFactorySet* fset, uint32_t flags)
-: fSharedHeap(!(flags & SkGPipeWriter::kCrossProcess_Flag), controller->numberOfReaders())
-, fWriter(*writer), fFlags(flags)
-, fBitmapHeap(BITMAPS_TO_KEEP), fBitmapDictionary(&fBitmapHeap, NULL, NULL, fset)
-, fFlattenableHeap(FLATTENABLES_TO_KEEP), fFlatDictionary(&fFlattenableHeap, fset) {
+                             SkWriter32* writer, uint32_t flags)
+: fFactorySet(isCrossProcess(flags) ? SkNEW(SkNamedFactorySet) : NULL)
+, fSharedHeap(!isCrossProcess(flags), controller->numberOfReaders())
+, fWriter(*writer)
+, fFlags(flags)
+, fBitmapHeap(BITMAPS_TO_KEEP)
+, fBitmapDictionary(&fBitmapHeap, NULL, NULL, fFactorySet)
+, fFlattenableHeap(FLATTENABLES_TO_KEEP)
+, fFlatDictionary(&fFlattenableHeap, fFactorySet) {
     fController = controller;
     fDone = false;
     fBlockSize = 0; // need first block from controller
@@ -589,6 +623,7 @@
 
 SkGPipeCanvas::~SkGPipeCanvas() {
     this->finish();
+    SkSafeUnref(fFactorySet);
 }
 
 bool SkGPipeCanvas::needOpBytes(size_t needed) {
@@ -1196,7 +1231,7 @@
     }
 
     if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
-        if (SkToBool(fFlags & SkGPipeWriter::kCrossProcess_Flag)) {
+        if (isCrossProcess(fFlags)) {
             uint32_t id = this->getTypefaceID(paint.getTypeface());
             *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
         } else if (this->needOpBytes(sizeof(void*))) {
@@ -1255,23 +1290,18 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 SkGPipeWriter::SkGPipeWriter()
-: fFactorySet(SkNEW(SkFactorySet))
-, fWriter(0) {
+: fWriter(0) {
     fCanvas = NULL;
 }
 
 SkGPipeWriter::~SkGPipeWriter() {
     this->endRecording();
-    fFactorySet->unref();
 }
 
 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, flags));
+        fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter, flags));
     }
     controller->setCanvas(fCanvas);
     return fCanvas;