shapes checkpoint: move matrix into groupshape and out of shape



git-svn-id: http://skia.googlecode.com/svn/trunk@178 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkShape.h b/include/core/SkShape.h
index 78a140e..8978afa 100644
--- a/include/core/SkShape.h
+++ b/include/core/SkShape.h
@@ -2,19 +2,14 @@
 #define SkShape_DEFINED
 
 #include "SkFlattenable.h"
-#include "SkMatrix.h"
 
 class SkCanvas;
+class SkMatrix;
 class SkWStream;
 
 class SkShape : public SkFlattenable {
 public:
-            SkShape() : fMatrix(NULL) {}
-    virtual ~SkShape();
-
-    void getMatrix(SkMatrix*) const;
-    void setMatrix(const SkMatrix&);
-    void resetMatrix();
+    SkShape() {}
 
     void draw(SkCanvas*);
 
@@ -34,11 +29,9 @@
 protected:
     virtual void onDraw(SkCanvas*) = 0;
 
-    SkShape(SkFlattenableReadBuffer&);
+    SkShape(SkFlattenableReadBuffer&) {}
 
 private:
-    SkMatrix* fMatrix;
-
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
 
     typedef SkFlattenable INHERITED;
diff --git a/samplecode/SampleShapes.cpp b/samplecode/SampleShapes.cpp
index 131ba9e..77283fe 100644
--- a/samplecode/SampleShapes.cpp
+++ b/samplecode/SampleShapes.cpp
@@ -14,33 +14,26 @@
     return rect;
 }
 
-static SkShape* make_shape0(const SkMatrix* matrix = NULL) {
+static SkShape* make_shape0(bool red) {
     SkRectShape* s = new SkRectShape;
     s->setRect(make_rect(10, 10, 90, 90));
-    if (matrix) {
-        s->setMatrix(*matrix);
+    if (red) {
         s->paint().setColor(SK_ColorRED);
     }
     return s;
 }
 
-static SkShape* make_shape1(const SkMatrix* matrix = NULL) {
+static SkShape* make_shape1() {
     SkRectShape* s = new SkRectShape;
     s->setOval(make_rect(10, 10, 90, 90));
-    if (matrix) {
-        s->setMatrix(*matrix);
-    }
     s->paint().setColor(SK_ColorBLUE);
     return s;
 }
 
-static SkShape* make_shape2(const SkMatrix* matrix = NULL) {
+static SkShape* make_shape2() {
     SkRectShape* s = new SkRectShape;
     s->setRRect(make_rect(10, 10, 90, 90),
                 SkIntToScalar(20), SkIntToScalar(20));
-    if (matrix) {
-        s->setMatrix(*matrix);
-    }
     s->paint().setColor(SK_ColorGREEN);
     return s;
 }
@@ -52,15 +45,15 @@
 public:
 	ShapesView() {
         SkMatrix m;
-        fGroup.appendShape(make_shape0())->unref();
+        fGroup.appendShape(make_shape0(false))->unref();
         m.setRotate(SkIntToScalar(30), SkIntToScalar(50), SkIntToScalar(50));
         m.postTranslate(0, SkIntToScalar(120));
-        fGroup.appendShape(make_shape0(&m))->unref();
+        fGroup.appendShape(make_shape0(true), m)->unref();
 
         m.setTranslate(SkIntToScalar(120), 0);
-        fGroup.appendShape(make_shape1(&m))->unref();
+        fGroup.appendShape(make_shape1(), m)->unref();
         m.postTranslate(0, SkIntToScalar(120));
-        fGroup.appendShape(make_shape2(&m))->unref();
+        fGroup.appendShape(make_shape2(), m)->unref();
     }
     
 protected:
@@ -81,12 +74,20 @@
         this->drawBG(canvas);
         
         SkMatrix matrix;
+#if 1        
+        SkGroupShape gs;
+        gs.appendShape(&fGroup);
+        matrix.setTranslate(0, SkIntToScalar(240));
+        gs.appendShape(&fGroup, matrix);
         matrix.setTranslate(SkIntToScalar(240), 0);
         matrix.preScale(SK_Scalar1*2, SK_Scalar1*2);
-        
+        gs.appendShape(&fGroup, matrix);
+        canvas->drawShape(&gs);
+#else
         fGroup.draw(canvas);
         fGroup.drawXY(canvas, 0, SkIntToScalar(240));
         fGroup.drawMatrix(canvas, matrix);
+#endif
     }
     
 private:
diff --git a/src/core/SkShape.cpp b/src/core/SkShape.cpp
index a6d19af..e5fa8ff 100644
--- a/src/core/SkShape.cpp
+++ b/src/core/SkShape.cpp
@@ -2,46 +2,8 @@
 #include "SkShape.h"
 #include "SkMatrix.h"
 
-SkShape::~SkShape() {
-    if (fMatrix) {
-        SkDELETE(fMatrix);
-    }
-}
-
-void SkShape::getMatrix(SkMatrix* matrix) const {
-    if (matrix) {
-        if (fMatrix) {
-            *matrix = *fMatrix;
-        } else {
-            matrix->reset();
-        }
-    }
-}
-
-void SkShape::setMatrix(const SkMatrix& matrix) {
-    if (matrix.isIdentity()) {
-        this->resetMatrix();
-    } else {
-        if (NULL == fMatrix) {
-            fMatrix = SkNEW(SkMatrix);
-        }
-        *fMatrix = matrix;
-    }
-}
-
-void SkShape::resetMatrix() {
-    if (fMatrix) {
-        SkDELETE(fMatrix);
-        fMatrix = NULL;
-    }
-}
-
 void SkShape::draw(SkCanvas* canvas) {
     int saveCount = canvas->getSaveCount();
-    if (fMatrix) {
-        canvas->save(SkCanvas::kMatrix_SaveFlag);
-        canvas->concat(*fMatrix);
-    }
     this->onDraw(canvas);
     canvas->restoreToCount(saveCount);
 }
@@ -49,9 +11,6 @@
 void SkShape::drawXY(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
     int saveCount = canvas->save(SkCanvas::kMatrix_SaveFlag);
     canvas->translate(dx, dy);
-    if (fMatrix) {
-        canvas->concat(*fMatrix);
-    }
     this->onDraw(canvas);
     canvas->restoreToCount(saveCount);
 }
@@ -59,27 +18,11 @@
 void SkShape::drawMatrix(SkCanvas* canvas, const SkMatrix& matrix) {
     int saveCount = canvas->save(SkCanvas::kMatrix_SaveFlag);
     canvas->concat(matrix);
-    if (fMatrix) {
-        canvas->concat(*fMatrix);
-    }
     this->onDraw(canvas);
     canvas->restoreToCount(saveCount);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void SkShape::flatten(SkFlattenableWriteBuffer& buffer) {
-    buffer.writeBool(fMatrix != NULL);
-    if (fMatrix) {
-        *(SkMatrix*)buffer.reserve(sizeof(SkMatrix)) = *fMatrix;
-    }
-}
-
-SkShape::SkShape(SkFlattenableReadBuffer& buffer) {
-    fMatrix = NULL;
-    if (buffer.readBool()) {
-        fMatrix = SkNEW(SkMatrix);
-        buffer.read(fMatrix, sizeof(*fMatrix));
-    }
-}
+void SkShape::flatten(SkFlattenableWriteBuffer& buffer) {}
 
diff --git a/src/shapes/SkGroupShape.cpp b/src/shapes/SkGroupShape.cpp
index 1322fe4..3baa315 100644
--- a/src/shapes/SkGroupShape.cpp
+++ b/src/shapes/SkGroupShape.cpp
@@ -10,50 +10,69 @@
     return fList.count();
 }
 
-SkShape* SkGroupShape::getShape(int index) const {
+SkShape* SkGroupShape::getShape(int index, SkMatrixRef** mr) const {
     if ((unsigned)index < (unsigned)fList.count()) {
-        return fList[index];
+        const Rec& rec = fList[index];
+        if (mr) {
+            *mr = rec.fMatrixRef;
+        }
+        return rec.fShape;
     }
     return NULL;
 }
 
-SkShape* SkGroupShape::addShape(int index, SkShape* shape) {
+void SkGroupShape::addShape(int index, SkShape* shape, SkMatrixRef* mr) {
     int count = fList.count();
     if (NULL == shape || index < 0 || index > count) {
-        return shape;
+        return;
     }
 
     shape->ref();
-    SkShape** spot;
+    SkMatrixRef::SafeRef(mr);
+
+    Rec* rec;
     if (index == count) {
-        spot = fList.append();
+        rec = fList.append();
     } else {
-        spot = fList.insert(index);
+        rec = fList.insert(index);
     }
-    *spot = shape;
-    return shape;
+    rec->fShape = shape;
+    rec->fMatrixRef = mr;
 }
 
 void SkGroupShape::removeShape(int index) {
     if ((unsigned)index < (unsigned)fList.count()) {
-        fList[index]->unref();
+        Rec& rec = fList[index];
+        rec.fShape->unref();
+        SkMatrixRef::SafeUnref(rec.fMatrixRef);
         fList.remove(index);
     }
 }
 
 void SkGroupShape::removeAllShapes() {
-    fList.unrefAll();
+    Rec* rec = fList.begin();
+    Rec* stop = fList.end();
+    while (rec < stop) {
+        rec->fShape->unref();
+        SkMatrixRef::SafeUnref(rec->fMatrixRef);
+        rec++;
+    }
     fList.reset();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 void SkGroupShape::onDraw(SkCanvas* canvas) {
-    SkShape** iter = fList.begin();
-    SkShape** stop = fList.end();
-    while (iter < stop) {
-        (*iter)->draw(canvas);
-        iter++;
+    const Rec* rec = fList.begin();
+    const Rec* stop = fList.end();
+    while (rec < stop) {
+        SkShape* shape = rec->fShape;
+        if (rec->fMatrixRef) {
+            shape->drawMatrix(canvas, *rec->fMatrixRef);
+        } else {
+            shape->draw(canvas);
+        }
+        rec++;
     }
 }
 
@@ -66,9 +85,13 @@
 
     int count = fList.count();
     buffer.write32(count);
-    for (int i = 0; i < count; i++) {
-        buffer.writeFunctionPtr((void*)fList[i]->getFactory());
-        fList[i]->flatten(buffer);
+    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
     }
 }
 
@@ -78,6 +101,7 @@
         SkFlattenable::Factory fact =
                             (SkFlattenable::Factory)buffer.readFunctionPtr();
         this->appendShape((SkShape*)fact(buffer))->unref();
+        // todo: unflatten the matrixref if present
     }
 }
 
diff --git a/src/shapes/SkGroupShape.h b/src/shapes/SkGroupShape.h
index de7574b..708f306 100644
--- a/src/shapes/SkGroupShape.h
+++ b/src/shapes/SkGroupShape.h
@@ -1,8 +1,62 @@
 #ifndef SkGroupShape_DEFINED
 #define SkGroupShape_DEFINED
 
+#include "SkMatrix.h"
 #include "SkShape.h"
 #include "SkTDArray.h"
+#include "SkThread.h"
+
+template <typename T> class SkTRefCnt : public T {
+public:
+    SkTRefCnt() : fRefCnt(1) {}
+    ~SkTRefCnt() { SkASSERT(1 == fRefCnt); }
+
+    int32_t getRefCnt() const { return fRefCnt; }
+    
+    /** Increment the reference count. Must be balanced by a call to unref().
+     */
+    void ref() const {
+        SkASSERT(fRefCnt > 0);
+        sk_atomic_inc(&fRefCnt);
+    }
+    
+    /** Decrement the reference count. If the reference count is 1 before the
+        decrement, then call delete on the object. Note that if this is the
+        case, then the object needs to have been allocated via new, and not on
+        the stack.
+     */
+    void unref() const {
+        SkASSERT(fRefCnt > 0);
+        if (sk_atomic_dec(&fRefCnt) == 1) {
+            fRefCnt = 1;    // so our destructor won't complain
+            SkDELETE(this);
+        }
+    }
+    
+    static void SafeRef(const SkTRefCnt* obj) {
+        if (obj) {
+            obj->ref();
+        }
+    }
+    
+    static void SafeUnref(const SkTRefCnt* obj) {
+        if (obj) {
+            obj->unref();
+        }
+    }
+    
+private:
+    mutable int32_t fRefCnt;
+};
+
+class SkMatrixRef : public SkTRefCnt<SkMatrix> {
+public:
+    SkMatrixRef() { this->reset(); }
+    explicit SkMatrixRef(const SkMatrix& matrix) {
+        SkMatrix& m = *this;
+        m = matrix;
+    }
+};
 
 class SkGroupShape : public SkShape {
 public:
@@ -16,7 +70,7 @@
     /** Return the shape at the specified index. Note this does not affect the
         owner count of the index'd shape. If index is out of range, returns NULL
      */
-    SkShape* getShape(int index) const;
+    SkShape* getShape(int index, SkMatrixRef** = NULL) const;
 
     /** Ref the specified shape, and insert it into the child list at the
         specified index. If index == countShapes(), then the shape will be
@@ -27,14 +81,26 @@
         0 will be drawn first, and the shape at index countShapes() - 1 will be
         drawn last.
      */
-    SkShape* addShape(int index, SkShape*);
+    void addShape(int index, SkShape*, SkMatrixRef* = NULL);
+
+    void addShape(int index, SkShape* shape, const SkMatrix& matrix) {
+        SkMatrixRef* mr = SkNEW_ARGS(SkMatrixRef, (matrix));
+        this->addShape(index, shape, mr);
+        mr->unref();
+    }
 
     /** Helper method to append a shape, passing countShapes() for the index
      */
-    SkShape* appendShape(SkShape* shape) {
-        return this->addShape(this->countShapes(), shape);
+    SkShape* appendShape(SkShape* shape, SkMatrixRef* mr = NULL) {
+        this->addShape(this->countShapes(), shape, mr);
+        return shape;
     }
-
+    
+    SkShape* appendShape(SkShape* shape, const SkMatrix& matrix) {
+        this->addShape(this->countShapes(), shape, matrix);
+        return shape;
+    }
+    
     /** Unref the specified index, and remove it from the child list. If index
         is out of range, does nothing.
      */
@@ -55,7 +121,11 @@
     SkGroupShape(SkFlattenableReadBuffer&);
 
 private:
-    SkTDArray<SkShape*> fList;
+    struct Rec {
+        SkShape*     fShape;
+        SkMatrixRef* fMatrixRef;
+    };
+    SkTDArray<Rec> fList;
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);