add SkSize for dimensions
add SkShape baseclass, in the hopes of having SkPicture inherit from that, and 
also using shapes as the extension mechanism for things like animated-gif



git-svn-id: http://skia.googlecode.com/svn/trunk@174 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index a19a5ae..77eb134 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -32,6 +32,7 @@
 class SkDraw;
 class SkDrawFilter;
 class SkPicture;
+class SkShape;
 
 /** \class SkCanvas
 
@@ -591,6 +592,10 @@
     */
     virtual void drawPicture(SkPicture& picture);
     
+    /** Draws the specified shape
+     */
+    virtual void drawShape(SkShape*);
+
     enum VertexMode {
         kTriangles_VertexMode,
         kTriangleStrip_VertexMode,
diff --git a/include/core/SkShape.h b/include/core/SkShape.h
new file mode 100644
index 0000000..78a140e
--- /dev/null
+++ b/include/core/SkShape.h
@@ -0,0 +1,47 @@
+#ifndef SkShape_DEFINED
+#define SkShape_DEFINED
+
+#include "SkFlattenable.h"
+#include "SkMatrix.h"
+
+class SkCanvas;
+class SkWStream;
+
+class SkShape : public SkFlattenable {
+public:
+            SkShape() : fMatrix(NULL) {}
+    virtual ~SkShape();
+
+    void getMatrix(SkMatrix*) const;
+    void setMatrix(const SkMatrix&);
+    void resetMatrix();
+
+    void draw(SkCanvas*);
+
+    /** Draw the shape translated by (dx,dy), which is applied before the
+        shape's matrix (if any).
+     */
+    void drawXY(SkCanvas*, SkScalar dx, SkScalar dy);
+    
+    /** Draw the shape with the specified matrix, applied before the shape's
+        matrix (if any).
+     */
+    void drawMatrix(SkCanvas*, const SkMatrix&);
+
+    // overrides
+    virtual void flatten(SkFlattenableWriteBuffer&);
+
+protected:
+    virtual void onDraw(SkCanvas*) = 0;
+
+    SkShape(SkFlattenableReadBuffer&);
+
+private:
+    SkMatrix* fMatrix;
+
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
+    typedef SkFlattenable INHERITED;
+};
+
+#endif
diff --git a/include/core/SkSize.h b/include/core/SkSize.h
index cb4c7b8..ac426d0 100644
--- a/include/core/SkSize.h
+++ b/include/core/SkSize.h
@@ -12,6 +12,12 @@
         fHeight = h;
     }
 
+    /** Returns true iff fWidth == 0 && fHeight == 0
+     */
+    bool isZero() const {
+        return 0 == fWidth && 0 == fHeight;
+    }
+
     /** Returns true if either widht or height are <= 0 */
     bool isEmpty() const {
         return fWidth <= 0 || fHeight <= 0;
diff --git a/include/effects/SkNWayCanvas.h b/include/effects/SkNWayCanvas.h
index 2394037..03bd6d1 100644
--- a/include/effects/SkNWayCanvas.h
+++ b/include/effects/SkNWayCanvas.h
@@ -56,7 +56,8 @@
     virtual void drawTextOnPath(const void* text, size_t byteLength,
                                 const SkPath& path, const SkMatrix* matrix,
                                 const SkPaint& paint);
-    virtual void drawPicture(SkPicture& picture);
+    virtual void drawPicture(SkPicture&);
+    virtual void drawShape(SkShape*);
     virtual void drawVertices(VertexMode vmode, int vertexCount,
                               const SkPoint vertices[], const SkPoint texs[],
                               const SkColor colors[], SkXfermode* xmode,
diff --git a/include/utils/SkDumpCanvas.h b/include/utils/SkDumpCanvas.h
index b919627..5347309 100644
--- a/include/utils/SkDumpCanvas.h
+++ b/include/utils/SkDumpCanvas.h
@@ -33,6 +33,7 @@
         kDrawBitmap_Verb,
         kDrawText_Verb,
         kDrawPicture_Verb,
+        kDrawShape_Verb,
         kDrawVertices_Verb
     };
     
@@ -92,7 +93,8 @@
     virtual void drawTextOnPath(const void* text, size_t byteLength,
                                 const SkPath& path, const SkMatrix* matrix,
                                 const SkPaint& paint);
-    virtual void drawPicture(SkPicture& picture);
+    virtual void drawPicture(SkPicture&);
+    virtual void drawShape(SkShape*);
     virtual void drawVertices(VertexMode vmode, int vertexCount,
                               const SkPoint vertices[], const SkPoint texs[],
                               const SkColor colors[], SkXfermode* xmode,
diff --git a/include/utils/SkProxyCanvas.h b/include/utils/SkProxyCanvas.h
index 1bc411a..f2e57ab 100644
--- a/include/utils/SkProxyCanvas.h
+++ b/include/utils/SkProxyCanvas.h
@@ -68,7 +68,8 @@
     virtual void drawTextOnPath(const void* text, size_t byteLength,
                                 const SkPath& path, const SkMatrix* matrix,
                                 const SkPaint& paint);
-    virtual void drawPicture(SkPicture& picture);
+    virtual void drawPicture(SkPicture&);
+    virtual void drawShape(SkShape*);
     virtual void drawVertices(VertexMode vmode, int vertexCount,
                               const SkPoint vertices[], const SkPoint texs[],
                               const SkColor colors[], SkXfermode* xmode,
diff --git a/samplecode/SampleRegion.cpp b/samplecode/SampleRegion.cpp
index fd20a81..5dc69cb 100644
--- a/samplecode/SampleRegion.cpp
+++ b/samplecode/SampleRegion.cpp
@@ -47,10 +47,32 @@
 }
 #endif
 
-static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn, const SkPaint& paint)
-{
-    SkRegion::Iterator  iter(rgn);
+static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
+    dst->fLeft = (int)::roundf(src.fLeft * scale);
+    dst->fTop = (int)::roundf(src.fTop * scale);
+    dst->fRight = (int)::roundf(src.fRight * scale);
+    dst->fBottom = (int)::roundf(src.fBottom * scale);
+}
+
+static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
+    SkRegion tmp;
+    SkRegion::Iterator iter(src);
+
+    for (; !iter.done(); iter.next()) {
+        SkIRect r;
+        scale_rect(&r, iter.rect(), scale);
+        tmp.op(r, SkRegion::kUnion_Op);
+    }
+    dst->swap(tmp);
+}
+
+static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
+                      const SkPaint& paint) {
+    SkRegion scaled;
+    scale_rgn(&scaled, rgn, 0.5f);
     
+    SkRegion::Iterator  iter(rgn);
+
     for (; !iter.done(); iter.next())
     {
         SkRect    r;
diff --git a/samplecode/SampleShapes.cpp b/samplecode/SampleShapes.cpp
new file mode 100644
index 0000000..131ba9e
--- /dev/null
+++ b/samplecode/SampleShapes.cpp
@@ -0,0 +1,100 @@
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkPorterDuff.h"
+#include "SkView.h"
+
+#include "SkRectShape.h"
+#include "SkGroupShape.h"
+
+static SkRect make_rect(int l, int t, int r, int b) {
+    SkRect rect;
+    rect.set(SkIntToScalar(l), SkIntToScalar(t),
+             SkIntToScalar(r), SkIntToScalar(b));
+    return rect;
+}
+
+static SkShape* make_shape0(const SkMatrix* matrix = NULL) {
+    SkRectShape* s = new SkRectShape;
+    s->setRect(make_rect(10, 10, 90, 90));
+    if (matrix) {
+        s->setMatrix(*matrix);
+        s->paint().setColor(SK_ColorRED);
+    }
+    return s;
+}
+
+static SkShape* make_shape1(const SkMatrix* matrix = NULL) {
+    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) {
+    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;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class ShapesView : public SkView {
+    SkGroupShape fGroup;
+public:
+	ShapesView() {
+        SkMatrix m;
+        fGroup.appendShape(make_shape0())->unref();
+        m.setRotate(SkIntToScalar(30), SkIntToScalar(50), SkIntToScalar(50));
+        m.postTranslate(0, SkIntToScalar(120));
+        fGroup.appendShape(make_shape0(&m))->unref();
+
+        m.setTranslate(SkIntToScalar(120), 0);
+        fGroup.appendShape(make_shape1(&m))->unref();
+        m.postTranslate(0, SkIntToScalar(120));
+        fGroup.appendShape(make_shape2(&m))->unref();
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "Shapes");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(0xFFDDDDDD);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        SkMatrix matrix;
+        matrix.setTranslate(SkIntToScalar(240), 0);
+        matrix.preScale(SK_Scalar1*2, SK_Scalar1*2);
+        
+        fGroup.draw(canvas);
+        fGroup.drawXY(canvas, 0, SkIntToScalar(240));
+        fGroup.drawMatrix(canvas, matrix);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ShapesView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 199c1b0..57b4f7b 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -22,6 +22,7 @@
 #include "SkDrawLooper.h"
 #include "SkPicture.h"
 #include "SkScalarCompare.h"
+#include "SkShape.h"
 #include "SkTemplates.h"
 #include "SkUtils.h"
 #include <new>
@@ -1357,12 +1358,19 @@
     this->drawTextOnPath(text, byteLength, path, &matrix, paint);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+
 void SkCanvas::drawPicture(SkPicture& picture) {
     int saveCount = save();
     picture.draw(this);
     restoreToCount(saveCount);
 }
 
+void SkCanvas::drawShape(SkShape* shape) {
+    // shape baseclass takes care of save/restore
+    shape->draw(this);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/src/core/SkShape.cpp b/src/core/SkShape.cpp
new file mode 100644
index 0000000..a6d19af
--- /dev/null
+++ b/src/core/SkShape.cpp
@@ -0,0 +1,85 @@
+#include "SkCanvas.h"
+#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);
+}
+
+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);
+}
+
+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));
+    }
+}
+
diff --git a/src/core/core_files.mk b/src/core/core_files.mk
index 27849e7..94e19d7 100644
--- a/src/core/core_files.mk
+++ b/src/core/core_files.mk
@@ -72,6 +72,7 @@
     SkScan_Hairline.cpp \
     SkScan_Path.cpp \
     SkShader.cpp \
+    SkShape.cpp \
     SkSpriteBlitter_ARGB32.cpp \
     SkSpriteBlitter_RGB16.cpp \
     SkStream.cpp \
diff --git a/src/effects/SkNWayCanvas.cpp b/src/effects/SkNWayCanvas.cpp
index d60f259..d3c84a1 100644
--- a/src/effects/SkNWayCanvas.cpp
+++ b/src/effects/SkNWayCanvas.cpp
@@ -248,6 +248,13 @@
     }
 }
 
+void SkNWayCanvas::drawShape(SkShape* shape) {
+    Iter iter(fList);
+    while (iter.next()) {
+        iter->drawShape(shape);
+    }
+}
+
 void SkNWayCanvas::drawVertices(VertexMode vmode, int vertexCount,
                           const SkPoint vertices[], const SkPoint texs[],
                           const SkColor colors[], SkXfermode* xmode,
diff --git a/src/shapes/SkGroupShape.cpp b/src/shapes/SkGroupShape.cpp
new file mode 100644
index 0000000..1322fe4
--- /dev/null
+++ b/src/shapes/SkGroupShape.cpp
@@ -0,0 +1,87 @@
+#include "SkGroupShape.h"
+
+SkGroupShape::SkGroupShape() {}
+
+SkGroupShape::~SkGroupShape() {
+    this->removeAllShapes();
+}
+
+int SkGroupShape::countShapes() const {
+    return fList.count();
+}
+
+SkShape* SkGroupShape::getShape(int index) const {
+    if ((unsigned)index < (unsigned)fList.count()) {
+        return fList[index];
+    }
+    return NULL;
+}
+
+SkShape* SkGroupShape::addShape(int index, SkShape* shape) {
+    int count = fList.count();
+    if (NULL == shape || index < 0 || index > count) {
+        return shape;
+    }
+
+    shape->ref();
+    SkShape** spot;
+    if (index == count) {
+        spot = fList.append();
+    } else {
+        spot = fList.insert(index);
+    }
+    *spot = shape;
+    return shape;
+}
+
+void SkGroupShape::removeShape(int index) {
+    if ((unsigned)index < (unsigned)fList.count()) {
+        fList[index]->unref();
+        fList.remove(index);
+    }
+}
+
+void SkGroupShape::removeAllShapes() {
+    fList.unrefAll();
+    fList.reset();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkGroupShape::onDraw(SkCanvas* canvas) {
+    SkShape** iter = fList.begin();
+    SkShape** stop = fList.end();
+    while (iter < stop) {
+        (*iter)->draw(canvas);
+        iter++;
+    }
+}
+
+SkFlattenable::Factory SkGroupShape::getFactory() {
+    return CreateProc;
+}
+
+void SkGroupShape::flatten(SkFlattenableWriteBuffer& buffer) {
+    this->INHERITED::flatten(buffer);
+
+    int count = fList.count();
+    buffer.write32(count);
+    for (int i = 0; i < count; i++) {
+        buffer.writeFunctionPtr((void*)fList[i]->getFactory());
+        fList[i]->flatten(buffer);
+    }
+}
+
+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();
+    }
+}
+
+SkFlattenable* SkGroupShape::CreateProc(SkFlattenableReadBuffer& buffer) {
+    return SkNEW_ARGS(SkGroupShape, (buffer));
+}
+
diff --git a/src/shapes/SkGroupShape.h b/src/shapes/SkGroupShape.h
new file mode 100644
index 0000000..de7574b
--- /dev/null
+++ b/src/shapes/SkGroupShape.h
@@ -0,0 +1,65 @@
+#ifndef SkGroupShape_DEFINED
+#define SkGroupShape_DEFINED
+
+#include "SkShape.h"
+#include "SkTDArray.h"
+
+class SkGroupShape : public SkShape {
+public:
+            SkGroupShape();
+    virtual ~SkGroupShape();
+
+    /** Return the number of child shapes in this group
+     */
+    int countShapes() const;
+
+    /** 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;
+
+    /** Ref the specified shape, and insert it into the child list at the
+        specified index. If index == countShapes(), then the shape will be
+        appended to the child list, otherwise if index is out of range, the
+        shape is not added. Either way, the shape parameter is returned.
+     
+        Child shapes are drawn in order, after the parent, so the shape at index
+        0 will be drawn first, and the shape at index countShapes() - 1 will be
+        drawn last.
+     */
+    SkShape* addShape(int index, SkShape*);
+
+    /** Helper method to append a shape, passing countShapes() for the index
+     */
+    SkShape* appendShape(SkShape* shape) {
+        return this->addShape(this->countShapes(), shape);
+    }
+
+    /** Unref the specified index, and remove it from the child list. If index
+        is out of range, does nothing.
+     */
+    void removeShape(int index);
+
+    /** Unrefs and removes all of the child shapes
+     */
+    void removeAllShapes();
+
+    // overrides
+    virtual Factory getFactory();
+    virtual void flatten(SkFlattenableWriteBuffer&);
+
+protected:
+    // overrides
+    virtual void onDraw(SkCanvas*);
+
+    SkGroupShape(SkFlattenableReadBuffer&);
+
+private:
+    SkTDArray<SkShape*> fList;
+
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
+    typedef SkShape INHERITED;
+};
+
+#endif
diff --git a/src/shapes/SkRectShape.cpp b/src/shapes/SkRectShape.cpp
new file mode 100644
index 0000000..16886d4
--- /dev/null
+++ b/src/shapes/SkRectShape.cpp
@@ -0,0 +1,85 @@
+#include "SkRectShape.h"
+#include "SkCanvas.h"
+
+SkPaintShape::SkPaintShape() {
+    fPaint.setAntiAlias(true);
+}
+
+SkRectShape::SkRectShape() {
+    fBounds.setEmpty();
+    fRadii.set(0, 0);
+}
+
+void SkRectShape::setRect(const SkRect& bounds) {
+    fBounds = bounds;
+    fRadii.set(0, 0);
+}
+
+void SkRectShape::setOval(const SkRect& bounds) {
+    fBounds = bounds;
+    fRadii.set(-SK_Scalar1, -SK_Scalar1);
+}
+
+void SkRectShape::setCircle(SkScalar cx, SkScalar cy, SkScalar radius) {
+    fBounds.set(cx - radius, cy - radius, cx + radius, cy + radius);
+    fRadii.set(-SK_Scalar1, -SK_Scalar1);
+}
+
+void SkRectShape::setRRect(const SkRect& bounds, SkScalar rx, SkScalar ry) {
+    if (rx < 0) {
+        rx = 0;
+    }
+    if (ry < 0) {
+        ry = 0;
+    }
+
+    fBounds = bounds;
+    fRadii.set(rx, ry);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkRectShape::onDraw(SkCanvas* canvas) {
+    const SkPaint& paint = this->paint();
+
+    if (fRadii.fWidth < 0) {
+        canvas->drawOval(fBounds, paint);
+    } else if (fRadii.isZero()) {
+        canvas->drawRect(fBounds, paint);
+    } else {
+        canvas->drawRoundRect(fBounds, fRadii.fWidth, fRadii.fHeight, paint);
+    }
+}
+
+SkFlattenable::Factory SkRectShape::getFactory() {
+    return CreateProc;
+}
+
+void SkRectShape::flatten(SkFlattenableWriteBuffer& buffer) {
+    this->INHERITED::flatten(buffer);
+
+    buffer.writeRect(fBounds);
+    *(SkSize*)buffer.reserve(sizeof(SkSize)) = fRadii;
+}
+
+SkRectShape::SkRectShape(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {    
+    buffer.read(&fBounds, sizeof(fBounds));
+    buffer.read(&fRadii, sizeof(fRadii));
+}
+
+SkFlattenable* SkRectShape::CreateProc(SkFlattenableReadBuffer& buffer) {
+    return SkNEW_ARGS(SkRectShape, (buffer));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkPaintShape::flatten(SkFlattenableWriteBuffer& buffer) {
+    this->INHERITED::flatten(buffer);
+    
+    fPaint.flatten(buffer);
+}
+
+SkPaintShape::SkPaintShape(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
+    fPaint.unflatten(buffer);
+}
+
diff --git a/src/shapes/SkRectShape.h b/src/shapes/SkRectShape.h
new file mode 100644
index 0000000..dfc07e9
--- /dev/null
+++ b/src/shapes/SkRectShape.h
@@ -0,0 +1,55 @@
+#ifndef SkRectShape_DEFINED
+#define SkRectShape_DEFINED
+
+#include "SkShape.h"
+#include "SkPaint.h"
+#include "SkSize.h"
+
+class SkPaintShape : public SkShape {
+public:
+    SkPaintShape();
+
+    SkPaint& paint() { return fPaint; }
+    const SkPaint& paint() const { return fPaint; }
+
+    // overrides
+    virtual void flatten(SkFlattenableWriteBuffer&);
+    
+protected:
+    SkPaintShape(SkFlattenableReadBuffer& buffer);
+    
+private:
+    SkPaint fPaint;
+    
+    typedef SkShape INHERITED;
+};
+
+class SkRectShape : public SkPaintShape {
+public:
+    SkRectShape();
+    
+    void setRect(const SkRect&);
+    void setOval(const SkRect&);
+    void setCircle(SkScalar x, SkScalar y, SkScalar radius);
+    void setRRect(const SkRect&, SkScalar rx, SkScalar ry);
+
+    // overrides
+    virtual Factory getFactory();
+    virtual void flatten(SkFlattenableWriteBuffer&);
+
+protected:
+    SkRectShape(SkFlattenableReadBuffer&);
+
+    // overrides
+    virtual void onDraw(SkCanvas*);
+
+private:
+    SkRect  fBounds;
+    SkSize  fRadii;
+
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
+    typedef SkPaintShape INHERITED;
+};
+
+#endif
diff --git a/src/utils/SkDumpCanvas.cpp b/src/utils/SkDumpCanvas.cpp
index 1ef444c..7a05f09 100644
--- a/src/utils/SkDumpCanvas.cpp
+++ b/src/utils/SkDumpCanvas.cpp
@@ -350,6 +350,10 @@
                str.c_str(), byteLength);
 }
 
+void SkDumpCanvas::drawShape(SkShape* shape) {
+    this->dump(kDrawShape_Verb, NULL, "drawShape(%p)", shape);
+}
+
 void SkDumpCanvas::drawPicture(SkPicture& picture) {
     this->dump(kDrawPicture_Verb, NULL, "drawPicture(%p)", &picture);
 }
diff --git a/src/utils/SkProxyCanvas.cpp b/src/utils/SkProxyCanvas.cpp
index 2a02b45..e38a0df 100644
--- a/src/utils/SkProxyCanvas.cpp
+++ b/src/utils/SkProxyCanvas.cpp
@@ -134,8 +134,8 @@
     fProxy->drawTextOnPath(text, byteLength, path, matrix, paint);
 }
 
-void SkProxyCanvas::drawPicture(SkPicture& picture) {
-    fProxy->drawPicture(picture);
+void SkProxyCanvas::drawShape(SkShape* shape) {
+    fProxy->drawShape(shape);
 }
 
 void SkProxyCanvas::drawVertices(VertexMode vmode, int vertexCount,
diff --git a/xcode/maccore/maccore.xcodeproj/project.pbxproj b/xcode/maccore/maccore.xcodeproj/project.pbxproj
index 9f0ca7d..cf336dd 100644
--- a/xcode/maccore/maccore.xcodeproj/project.pbxproj
+++ b/xcode/maccore/maccore.xcodeproj/project.pbxproj
@@ -12,11 +12,11 @@
 		002884A60EFAB5DE0083E387 /* SkThread_pthread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 002884A30EFAB5DE0083E387 /* SkThread_pthread.cpp */; };
 		002884A70EFAB5DE0083E387 /* SkTime_Unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 002884A40EFAB5DE0083E387 /* SkTime_Unix.cpp */; };
 		002884E10EFABFFC0083E387 /* SkGlobals_global.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 002884E00EFABFFC0083E387 /* SkGlobals_global.cpp */; };
+		003144D50FB8491400B10956 /* SkImageDecoder_CG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27739F2E0F11409100F233EA /* SkImageDecoder_CG.cpp */; };
 		00488AF40F86532E00C08A57 /* SkDebug_stdio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00488AF30F86532E00C08A57 /* SkDebug_stdio.cpp */; };
 		007A7BEF0F01427100A2D6EE /* SkFontHost_mac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007A7BEE0F01427100A2D6EE /* SkFontHost_mac.cpp */; };
 		27739F2B0F11407000F233EA /* SkCreateCGImageRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27739F2A0F11407000F233EA /* SkCreateCGImageRef.cpp */; };
 		27739F2D0F11408100F233EA /* SkImageDecoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27739F2C0F11408100F233EA /* SkImageDecoder.cpp */; };
-		27739F2F0F11409100F233EA /* SkImageDecoder_CG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27739F2E0F11409100F233EA /* SkImageDecoder_CG.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -153,9 +153,9 @@
 				007A7BEF0F01427100A2D6EE /* SkFontHost_mac.cpp in Sources */,
 				27739F2B0F11407000F233EA /* SkCreateCGImageRef.cpp in Sources */,
 				27739F2D0F11408100F233EA /* SkImageDecoder.cpp in Sources */,
-				27739F2F0F11409100F233EA /* SkImageDecoder_CG.cpp in Sources */,
 				001EA8910F13F2CE00900BA9 /* SkImageEncoder.cpp in Sources */,
 				00488AF40F86532E00C08A57 /* SkDebug_stdio.cpp in Sources */,
+				003144D50FB8491400B10956 /* SkImageDecoder_CG.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
index bd18517..70732da 100644
--- a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
+++ b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
@@ -28,6 +28,10 @@
 		00003CA40EFC235F000FF73A /* SkXMLParser_empty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00003CA30EFC235F000FF73A /* SkXMLParser_empty.cpp */; };
 		0028847B0EFAB46A0083E387 /* libcore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 002884510EFAA35C0083E387 /* libcore.a */; };
 		002884BD0EFAB6A30083E387 /* libmaccore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 002884BC0EFAB69F0083E387 /* libmaccore.a */; };
+		0031450E0FB8CDB100B10956 /* SkShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0031450D0FB8CDB100B10956 /* SkShape.cpp */; };
+		003145200FB99CCE00B10956 /* SkRectShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0031451F0FB99CCE00B10956 /* SkRectShape.cpp */; };
+		003145320FB9B48F00B10956 /* SampleShapes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 003145310FB9B48F00B10956 /* SampleShapes.cpp */; };
+		003145370FB9BA4000B10956 /* SkGroupShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 003145360FB9BA4000B10956 /* SkGroupShape.cpp */; };
 		0041CDDB0F00975E00695E8C /* SampleImageDir.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CDDA0F00975E00695E8C /* SampleImageDir.cpp */; };
 		0041CDF30F009ED100695E8C /* SkImageRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CDF20F009ED100695E8C /* SkImageRef.cpp */; };
 		0041CDF60F009EED00695E8C /* SkImageRef_GlobalPool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CDF50F009EED00695E8C /* SkImageRef_GlobalPool.cpp */; };
@@ -144,6 +148,12 @@
 		00003CA30EFC235F000FF73A /* SkXMLParser_empty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkXMLParser_empty.cpp; path = ../../src/ports/SkXMLParser_empty.cpp; sourceTree = SOURCE_ROOT; };
 		002884490EFAA35C0083E387 /* core.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = core.xcodeproj; path = ../core/core.xcodeproj; sourceTree = SOURCE_ROOT; };
 		002884B40EFAB69F0083E387 /* maccore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = maccore.xcodeproj; path = ../maccore/maccore.xcodeproj; sourceTree = SOURCE_ROOT; };
+		0031450D0FB8CDB100B10956 /* SkShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkShape.cpp; path = ../../src/core/SkShape.cpp; sourceTree = SOURCE_ROOT; };
+		0031451D0FB99C9700B10956 /* SkRectShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SkRectShape.h; path = ../../src/shapes/SkRectShape.h; sourceTree = SOURCE_ROOT; };
+		0031451F0FB99CCE00B10956 /* SkRectShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkRectShape.cpp; path = ../../src/shapes/SkRectShape.cpp; sourceTree = SOURCE_ROOT; };
+		003145310FB9B48F00B10956 /* SampleShapes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleShapes.cpp; path = ../../samplecode/SampleShapes.cpp; sourceTree = SOURCE_ROOT; };
+		003145340FB9B62D00B10956 /* SkGroupShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SkGroupShape.h; path = ../../src/shapes/SkGroupShape.h; sourceTree = SOURCE_ROOT; };
+		003145360FB9BA4000B10956 /* SkGroupShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkGroupShape.cpp; path = ../../src/shapes/SkGroupShape.cpp; sourceTree = SOURCE_ROOT; };
 		0041CDDA0F00975E00695E8C /* SampleImageDir.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleImageDir.cpp; path = ../../samplecode/SampleImageDir.cpp; sourceTree = SOURCE_ROOT; };
 		0041CDF20F009ED100695E8C /* SkImageRef.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkImageRef.cpp; path = ../../src/images/SkImageRef.cpp; sourceTree = SOURCE_ROOT; };
 		0041CDF50F009EED00695E8C /* SkImageRef_GlobalPool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkImageRef_GlobalPool.cpp; path = ../../src/images/SkImageRef_GlobalPool.cpp; sourceTree = SOURCE_ROOT; };
@@ -225,6 +235,7 @@
 				00D6B5CB0F72DC4300C466B9 /* SampleFuzz.cpp */,
 				00C55DA00F8552DC000CAC09 /* SampleGradients.cpp */,
 				009490310FB0A5B90063C792 /* SampleLayerMask.cpp */,
+				003145310FB9B48F00B10956 /* SampleShapes.cpp */,
 				009CC9180F65918A002185BE /* SampleFontScalerTest.cpp */,
 				007A7CA50F01658C00A2D6EE /* SamplePoints.cpp */,
 				007A7CA70F01658C00A2D6EE /* SampleRegion.cpp */,
@@ -339,6 +350,11 @@
 				002884B40EFAB69F0083E387 /* maccore.xcodeproj */,
 				00003C8C0EFC230E000FF73A /* effects.xcodeproj */,
 				0053528A0F8C4DFF00EE34B6 /* SkFontHost_tables.cpp */,
+				0031450D0FB8CDB100B10956 /* SkShape.cpp */,
+				0031451D0FB99C9700B10956 /* SkRectShape.h */,
+				0031451F0FB99CCE00B10956 /* SkRectShape.cpp */,
+				003145360FB9BA4000B10956 /* SkGroupShape.cpp */,
+				003145340FB9B62D00B10956 /* SkGroupShape.h */,
 			);
 			name = CICarbonSample;
 			sourceTree = "<group>";
@@ -521,7 +537,6 @@
 				007A7CC00F01658C00A2D6EE /* SampleVertices.cpp in Sources */,
 				007A7CC10F01658C00A2D6EE /* SampleXfermodes.cpp in Sources */,
 				0041CE3C0F00A12400695E8C /* SampleEncode.cpp in Sources */,
-				007A7CB60F01658C00A2D6EE /* SampleRegion.cpp in Sources */,
 				007C785E0F3B4C230004B142 /* SamplePathClip.cpp in Sources */,
 				009CC9190F65918A002185BE /* SampleFontScalerTest.cpp in Sources */,
 				007A7CB30F01658C00A2D6EE /* SamplePicture.cpp in Sources */,
@@ -529,6 +544,11 @@
 				008C4D980F77DAEE0056981C /* SampleHairline.cpp in Sources */,
 				00C55DA10F8552DC000CAC09 /* SampleGradients.cpp in Sources */,
 				009490320FB0A5B90063C792 /* SampleLayerMask.cpp in Sources */,
+				007A7CB60F01658C00A2D6EE /* SampleRegion.cpp in Sources */,
+				0031450E0FB8CDB100B10956 /* SkShape.cpp in Sources */,
+				003145200FB99CCE00B10956 /* SkRectShape.cpp in Sources */,
+				003145320FB9B48F00B10956 /* SampleShapes.cpp in Sources */,
+				003145370FB9BA4000B10956 /* SkGroupShape.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};