add shape flatten so they work properly in pictures
add flatten/unflatten to matrix



git-svn-id: http://skia.googlecode.com/svn/trunk@242 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/shapes.cpp b/gm/shapes.cpp
index 2cf3f5e..b3d4863 100644
--- a/gm/shapes.cpp
+++ b/gm/shapes.cpp
@@ -57,8 +57,6 @@
         for (size_t i = 0; i < SK_ARRAY_COUNT(fMatrixRefs); i++) {
             SkSafeRef(fMatrixRefs[i] = fGroup.getShapeMatrixRef(i));
         }
-        
-        fAngle = 0;
     }
     
     virtual ~ShapesGM() {
@@ -80,15 +78,12 @@
         canvas->drawColor(0xFFDDDDDD);
     }
     
-    int fAngle;
-    
     virtual void onDraw(SkCanvas* canvas) {
         this->drawBG(canvas);
         
         SkMatrix saveM = *fMatrixRefs[3];
-        fAngle = (fAngle + 5) % 360;
         SkScalar c = SkIntToScalar(50);
-        fMatrixRefs[3]->preRotate(SkIntToScalar(fAngle), c, c);
+        fMatrixRefs[3]->preRotate(SkIntToScalar(30), c, c);
         
         SkMatrix matrix;
      
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h
index aa008cb..9dd4fc9 100644
--- a/include/core/SkMatrix.h
+++ b/include/core/SkMatrix.h
@@ -399,6 +399,11 @@
     friend bool operator!=(const SkMatrix& a, const SkMatrix& b) {
         return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) != 0;
     }
+
+    // return the number of bytes written, whether or not buffer is null
+    uint32_t flatten(void* buffer) const;
+    // return the number of bytes read
+    uint32_t unflatten(const void* buffer);
     
     void dump() const;
     void toDumpString(SkString*) const;
diff --git a/include/core/SkShape.h b/include/core/SkShape.h
index abe4e26..6cee70e 100644
--- a/include/core/SkShape.h
+++ b/include/core/SkShape.h
@@ -9,7 +9,8 @@
 
 class SkShape : public SkFlattenable {
 public:
-    SkShape() {}
+    SkShape();
+    virtual ~SkShape();
 
     void draw(SkCanvas*);
 
@@ -24,15 +25,18 @@
     void drawMatrix(SkCanvas*, const SkMatrix&);
 
     // overrides
+    virtual Factory getFactory();
     virtual void flatten(SkFlattenableWriteBuffer&);
 
-protected:
-    virtual void onDraw(SkCanvas*) = 0;
+    // public for Registrar
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
 
-    SkShape(SkFlattenableReadBuffer&) {}
+protected:
+    virtual void onDraw(SkCanvas*);
+
+    SkShape(SkFlattenableReadBuffer&);
 
 private:
-    static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
 
     typedef SkFlattenable INHERITED;
 };
diff --git a/include/effects/SkGroupShape.h b/include/effects/SkGroupShape.h
index 58ebecc..2c851fa 100644
--- a/include/effects/SkGroupShape.h
+++ b/include/effects/SkGroupShape.h
@@ -128,6 +128,9 @@
     virtual Factory getFactory();
     virtual void flatten(SkFlattenableWriteBuffer&);
 
+    // public for Registrar
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
 protected:
     // overrides
     virtual void onDraw(SkCanvas*);
@@ -141,8 +144,6 @@
     };
     SkTDArray<Rec> fList;
 
-    static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
-
     typedef SkShape INHERITED;
 };
 
diff --git a/include/effects/SkRectShape.h b/include/effects/SkRectShape.h
index dfc07e9..9b8cfc1 100644
--- a/include/effects/SkRectShape.h
+++ b/include/effects/SkRectShape.h
@@ -37,6 +37,9 @@
     virtual Factory getFactory();
     virtual void flatten(SkFlattenableWriteBuffer&);
 
+    // public for Registrar
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
 protected:
     SkRectShape(SkFlattenableReadBuffer&);
 
@@ -47,8 +50,6 @@
     SkRect  fBounds;
     SkSize  fRadii;
 
-    static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
-
     typedef SkPaintShape INHERITED;
 };
 
diff --git a/samplecode/SampleShapes.cpp b/samplecode/SampleShapes.cpp
index 81f6e4f..95efd0f 100644
--- a/samplecode/SampleShapes.cpp
+++ b/samplecode/SampleShapes.cpp
@@ -2,6 +2,7 @@
 #include "SkCanvas.h"
 #include "SkPaint.h"
 #include "SkPicture.h"
+#include "SkStream.h"
 #include "SkView.h"
 
 #include "SkRectShape.h"
@@ -83,6 +84,20 @@
         canvas->drawColor(0xFFDDDDDD);
     }
     
+    void drawpicture(SkCanvas* canvas, SkPicture& pict) {
+#if 1
+        SkDynamicMemoryWStream ostream;
+        pict.serialize(&ostream);
+
+        SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
+        SkPicture newPict(&istream);
+        
+        canvas->drawPicture(newPict);
+#else
+        canvas->drawPicture(pict);
+#endif
+    }
+    
     int fAngle;
     
     virtual void onDraw(SkCanvas* canvas) {
@@ -105,7 +120,7 @@
         matrix.preScale(SK_Scalar1*2, SK_Scalar1*2);
         gs->appendShape(&fGroup, matrix);
         
-#if 0        
+#if 0
         canvas->drawShape(gs);
 #else
         SkPicture pict;
@@ -116,7 +131,8 @@
         cv->scale(-SK_Scalar1, SK_Scalar1);
         cv->drawShape(gs);
         pict.endRecording();
-        canvas->drawPicture(pict);
+        
+        drawpicture(canvas, pict);
 #endif
 
         *fMatrixRefs[3] = saveM;
diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp
index ac5ae92..48fa804 100644
--- a/src/core/SkMatrix.cpp
+++ b/src/core/SkMatrix.cpp
@@ -1582,6 +1582,20 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+uint32_t SkMatrix::flatten(void* buffer) const {
+    // TODO write less for simple matrices
+    if (buffer) {
+        memcpy(buffer, fMat, 9 * sizeof(SkScalar));
+    }
+    return 9 * sizeof(SkScalar);
+}
+
+uint32_t SkMatrix::unflatten(const void* buffer) {
+    memcpy(fMat, buffer, 9 * sizeof(SkScalar));
+    this->setTypeMask(kUnknown_Mask);
+    return 9 * sizeof(SkScalar);
+}
+
 void SkMatrix::dump() const {
     SkString str;
     this->toDumpString(&str);
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 24fcd8e..77ac912 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -246,7 +246,7 @@
     SkDELETE_ARRAY(fPictureRefs);
     
     for (int i = 0; i < fShapeCount; i++) {
-        fShapes[i]->unref();
+        SkSafeUnref(fShapes[i]);
     }
     SkDELETE_ARRAY(fShapes);
     
@@ -279,7 +279,7 @@
 #define PICT_PAINT_TAG      SkSetFourByteTag('p', 'n', 't', ' ')
 #define PICT_PATH_TAG       SkSetFourByteTag('p', 't', 'h', ' ')
 #define PICT_REGION_TAG     SkSetFourByteTag('r', 'g', 'n', ' ')
-
+#define PICT_SHAPE_TAG      SkSetFourByteTag('s', 'h', 'p', ' ')
 
 #include "SkStream.h"
 
@@ -376,6 +376,11 @@
         buffer.writePad(storage.get(), size);
     }
     
+    writeTagSize(buffer, PICT_SHAPE_TAG, fShapeCount);
+    for (i = 0; i < fShapeCount; i++) {
+        buffer.writeFlattenable(fShapes[i]);
+    }
+
     // now we can write to the stream again
 
     writeFactories(stream, factRecorder);
@@ -386,13 +391,6 @@
         fPictureRefs[i]->serialize(stream);
     }
     
-#if 0
-    writeTagSize(stream, PICT_SHAPE_TAG, fShapeCount);
-    for (i = 0; i < fShapeCount; i++) {
-        fShapes[i]->serialize(stream);
-    }
-#endif
-    
     writeTagSize(stream, PICT_ARRAYS_TAG, buffer.size());
     buffer.writeToStream(stream);
 }
@@ -491,6 +489,12 @@
         SkDEBUGCODE(uint32_t bytes =) fRegions[i].unflatten(buffer.skip(size));
         SkASSERT(size == bytes);
     }
+
+    fShapeCount = readTagSize(buffer, PICT_SHAPE_TAG);
+    fShapes = SkNEW_ARRAY(SkShape*, fShapeCount);
+    for (i = 0; i < fShapeCount; i++) {
+        fShapes[i] = reinterpret_cast<SkShape*>(buffer.readFlattenable());
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -633,9 +637,12 @@
                 const SkPaint& paint = *getPaint();
                 canvas.drawRect(*fReader.skipRect(), paint); 
             } break;
-            case DRAW_SHAPE:
-                canvas.drawShape(getShape());
-                break;
+            case DRAW_SHAPE: {
+                SkShape* shape = getShape();
+                if (shape) {
+                    canvas.drawShape(shape);
+                }
+            } break;
             case DRAW_SPRITE: {
                 const SkPaint* paint = getPaint();
                 const SkBitmap& bitmap = getBitmap(); 
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index f0f3402..4778726 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -413,6 +413,7 @@
     fPaints.reset();
     fPictureRefs.unrefAll();
     fRegions.reset();
+    fShapes.unrefAll();
     fWriter.reset();
     fHeap.reset();
     
diff --git a/src/core/SkShape.cpp b/src/core/SkShape.cpp
index e5fa8ff..cd405db 100644
--- a/src/core/SkShape.cpp
+++ b/src/core/SkShape.cpp
@@ -2,6 +2,23 @@
 #include "SkShape.h"
 #include "SkMatrix.h"
 
+#if 0
+static int gShapeCounter;
+static void inc_shape(const SkShape* s) {
+    SkDebugf("inc %d\n", gShapeCounter);
+    gShapeCounter += 1;
+}
+static void dec_shape(const SkShape* s) {
+    --gShapeCounter;
+    SkDebugf("dec %d\n", gShapeCounter);
+}
+#else
+#define inc_shape(s)
+#define dec_shape(s)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
 void SkShape::draw(SkCanvas* canvas) {
     int saveCount = canvas->getSaveCount();
     this->onDraw(canvas);
@@ -24,5 +41,30 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void SkShape::flatten(SkFlattenableWriteBuffer& buffer) {}
+SkShape::SkShape() {
+    inc_shape(this);
+}
 
+SkShape::~SkShape() {
+    dec_shape(this);
+}
+
+SkShape::SkShape(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
+    inc_shape(this);
+}
+
+SkFlattenable* SkShape::CreateProc(SkFlattenableReadBuffer& buffer) {
+    return SkNEW_ARGS(SkShape, (buffer));
+}
+
+SkFlattenable::Factory SkShape::getFactory() {
+    return CreateProc;
+}
+
+void SkShape::flatten(SkFlattenableWriteBuffer& buffer) {
+    this->INHERITED::flatten(buffer);
+}
+
+void SkShape::onDraw(SkCanvas*) {}
+
+static SkFlattenable::Registrar gReg("SkShape", SkShape::CreateProc);
diff --git a/src/effects/SkGroupShape.cpp b/src/effects/SkGroupShape.cpp
index 3baa315..0e7640f 100644
--- a/src/effects/SkGroupShape.cpp
+++ b/src/effects/SkGroupShape.cpp
@@ -80,6 +80,8 @@
     return CreateProc;
 }
 
+#define SAFE_MATRIX_STORAGE_SIZE    (sizeof(SkMatrix)*2)
+
 void SkGroupShape::flatten(SkFlattenableWriteBuffer& buffer) {
     this->INHERITED::flatten(buffer);
 
@@ -88,20 +90,36 @@
     const Rec* rec = fList.begin();
     const Rec* stop = fList.end();
     while (rec < stop) {
-        SkShape* shape = rec->fShape;
-        buffer.writeFunctionPtr((void*)shape->getFactory());
-        shape->flatten(buffer);
-        // todo: flatten the matrixref if present
+        buffer.writeFlattenable(rec->fShape);
+        if (rec->fMatrixRef) {
+            char storage[SAFE_MATRIX_STORAGE_SIZE];
+            uint32_t size = rec->fMatrixRef->flatten(storage);
+            buffer.write32(size);
+            buffer.writePad(storage, size);
+        } else {
+            buffer.write32(0);
+        }
+        rec += 1;
     }
 }
 
 SkGroupShape::SkGroupShape(SkFlattenableReadBuffer& buffer) : INHERITED(buffer){
     int count = buffer.readS32();
     for (int i = 0; i < count; i++) {
-        SkFlattenable::Factory fact =
-                            (SkFlattenable::Factory)buffer.readFunctionPtr();
-        this->appendShape((SkShape*)fact(buffer))->unref();
-        // todo: unflatten the matrixref if present
+        SkShape* shape = reinterpret_cast<SkShape*>(buffer.readFlattenable());
+        SkMatrixRef* mr = NULL;
+        uint32_t size = buffer.readS32();
+        if (size) {
+            char storage[SAFE_MATRIX_STORAGE_SIZE];
+            SkASSERT(size <= SAFE_MATRIX_STORAGE_SIZE);
+            buffer.read(storage, SkAlign4(size));
+            mr = SkNEW(SkMatrixRef);
+            mr->unflatten(storage);
+        }
+        if (shape) {
+            this->appendShape(shape, mr)->unref();
+        }
+        SkSafeUnref(mr);
     }
 }
 
@@ -109,3 +127,5 @@
     return SkNEW_ARGS(SkGroupShape, (buffer));
 }
 
+static SkFlattenable::Registrar gReg("SkGroupShape", SkGroupShape::CreateProc);
+
diff --git a/src/effects/SkRectShape.cpp b/src/effects/SkRectShape.cpp
index 16886d4..8a38a1e 100644
--- a/src/effects/SkRectShape.cpp
+++ b/src/effects/SkRectShape.cpp
@@ -83,3 +83,5 @@
     fPaint.unflatten(buffer);
 }
 
+static SkFlattenable::Registrar gReg("SkRectShape", SkRectShape::CreateProc);
+