add typeface flattening



git-svn-id: http://skia.googlecode.com/svn/trunk@1245 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pipe/SkGPipePriv.h b/src/pipe/SkGPipePriv.h
index 7ce7f10..b4c108e 100644
--- a/src/pipe/SkGPipePriv.h
+++ b/src/pipe/SkGPipePriv.h
@@ -58,6 +58,7 @@
 
     // these edit paints
     kPaintOp_DrawOp,
+    kDefineTypeface_DrawOp,
 
     // these are signals to playback, not drawing verbs
     kDone_DrawOp,
@@ -144,7 +145,8 @@
     kTextSize_PaintOp,  // arg scalar - text
     kTextScaleX_PaintOp,// arg scalar - text
     kTextSkewX_PaintOp, // arg scalar - text
-    
+    kTypeface_PaintOp,  // arg inline (index) - text
+
     kPathEffect_PaintOp,    // arg inline
     kShader_PaintOp,
     kXfermode_PaintOp,
diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp
index f022277..43abf89 100644
--- a/src/pipe/SkGPipeRead.cpp
+++ b/src/pipe/SkGPipeRead.cpp
@@ -20,6 +20,8 @@
 #include "SkGPipe.h"
 #include "SkGPipePriv.h"
 #include "SkReader32.h"
+#include "SkStream.h"
+#include "SkTypeface.h"
 
 class SkGPipeState {
 public:
@@ -32,9 +34,22 @@
     //  Returns the specified paint from our list, or creates a new paint if
     //  index == count. If index > count, return NULL
     SkPaint* editPaint(uint32_t drawOp32);
-    
+
+    SkTypeface* findTypeface(int id) const {
+        SkASSERT(id <= fTypefaces.count());
+        return id ? fTypefaces[id - 1] : NULL;
+    }
+    void addTypeface(SkReader32* reader) {
+        size_t size = reader->readU32();
+        const void* data = reader->skip(SkAlign4(size));
+        SkMemoryStream stream(data, size, false);
+        // fTypefaces takes over ownership of the typeface reference
+        *fTypefaces.append() = SkTypeface::Deserialize(&stream);
+    }
+
 private:
     SkTDArray<SkPaint*> fPaints;
+    SkTDArray<SkTypeface*> fTypefaces;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -389,6 +404,7 @@
             case kTextSize_PaintOp: p->setTextSize(reader->readScalar()); break;
             case kTextScaleX_PaintOp: p->setTextScaleX(reader->readScalar()); break;
             case kTextSkewX_PaintOp: p->setTextSkewX(reader->readScalar()); break;
+            case kTypeface_PaintOp: p->setTypeface(state->findTypeface(data)); break;
                 
             // flag to reference a cached index instead of inflating?
             case kPathEffect_PaintOp: inflate_patheffect(reader, p); break;
@@ -403,6 +419,11 @@
     } while (!done);
 }
 
+static void defTypeface_rp(SkCanvas*, SkReader32* reader, uint32_t,
+                           SkGPipeState* state) {
+    state->addTypeface(reader);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static void skip_rp(SkCanvas*, SkReader32* reader, uint32_t op32, SkGPipeState*) {
@@ -446,6 +467,7 @@
     skew_rp,
     translate_rp,
     paintOp_rp,
+    defTypeface_rp,
     done_rp
 };
 
@@ -457,6 +479,7 @@
 }
 
 SkGPipeState::~SkGPipeState() {
+    fTypefaces.unrefAll();
     fPaints.deleteAll();
 }
 
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index 03a0251..f0238ca 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -19,6 +19,8 @@
 #include "SkPaint.h"
 #include "SkGPipe.h"
 #include "SkGPipePriv.h"
+#include "SkStream.h"
+#include "SkTypeface.h"
 #include "SkWriter32.h"
 
 static size_t estimateFlattenSize(const SkPath& path) {
@@ -49,6 +51,18 @@
     matrix.flatten(writer->reserve(size));
 }
 
+static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
+    SkASSERT(typeface);
+    SkDynamicMemoryWStream stream;
+    typeface->serialize(&stream);
+    size_t size = stream.getOffset();
+    if (writer) {
+        writer->write32(size);
+        writer->write(stream.getStream(), size);
+    }
+    return 4 + size;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 class SkGPipeCanvas : public SkCanvas {
@@ -115,6 +129,10 @@
     size_t      fBytesNotified;
     bool        fDone;
 
+    SkRefCntSet fTypefaceSet;
+
+    uint32_t getTypefaceID(SkTypeface*);
+
     inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
         fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
     }
@@ -186,6 +204,22 @@
     return true;
 }
 
+uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
+    uint32_t id = 0; // 0 means default/null typeface
+    if (face) {
+        id = fTypefaceSet.find(face);
+        if (0 == id) {
+            id = fTypefaceSet.add(face);
+            size_t size = writeTypeface(NULL, face);
+            if (this->needOpBytes(size)) {
+                this->writeOp(kDefineTypeface_DrawOp);
+                writeTypeface(&fWriter, face);
+            }
+        }
+    }
+    return id;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 #define NOTIFY_SETUP(canvas)    \
@@ -567,7 +601,7 @@
 }
 
 unsigned SkGPipeCanvas::writePaint(const SkPaint& paint) {
-    const SkPaint& base = *fPaints[0];
+    SkPaint& base = *fPaints[0];
     uint32_t storage[32];
     uint32_t* ptr = storage;
     uint32_t* last = NULL;
@@ -575,66 +609,84 @@
     if (base.getFlags() != paint.getFlags()) {
         last = ptr;
         *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
+        base.setFlags(paint.getFlags());
     }
     if (base.getColor() != paint.getColor()) {
         last = ptr;
         *ptr++ = PaintOp_packOp(kColor_PaintOp);
         *ptr++ = paint.getColor();
+        base.setColor(paint.getColor());
     }
     if (base.getStyle() != paint.getStyle()) {
         last = ptr;
         *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
+        base.setStyle(paint.getStyle());
     }
     if (base.getStrokeJoin() != paint.getStrokeJoin()) {
         last = ptr;
         *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
+        base.setStrokeJoin(paint.getStrokeJoin());
     }
     if (base.getStrokeCap() != paint.getStrokeCap()) {
         last = ptr;
         *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
+        base.setStrokeCap(paint.getStrokeCap());
     }
     if (base.getStrokeWidth() != paint.getStrokeWidth()) {
         last = ptr;
         *ptr++ = PaintOp_packOp(kWidth_PaintOp);
         *ptr++ = castToU32(paint.getStrokeWidth());
+        base.setStrokeWidth(paint.getStrokeWidth());
     }
     if (base.getStrokeMiter() != paint.getStrokeMiter()) {
         last = ptr;
         *ptr++ = PaintOp_packOp(kMiter_PaintOp);
         *ptr++ = castToU32(paint.getStrokeMiter());
+        base.setStrokeMiter(paint.getStrokeMiter());
     }
     if (base.getTextEncoding() != paint.getTextEncoding()) {
         last = ptr;
         *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
+        base.setTextEncoding(paint.getTextEncoding());
     }
     if (base.getHinting() != paint.getHinting()) {
         last = ptr;
         *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
+        base.setHinting(paint.getHinting());
     }
     if (base.getTextAlign() != paint.getTextAlign()) {
         last = ptr;
         *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
+        base.setTextAlign(paint.getTextAlign());
     }
     if (base.getTextSize() != paint.getTextSize()) {
         last = ptr;
         *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
         *ptr++ = castToU32(paint.getTextSize());
+        base.setTextSize(paint.getTextSize());
     }
     if (base.getTextScaleX() != paint.getTextScaleX()) {
         last = ptr;
         *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
         *ptr++ = castToU32(paint.getTextScaleX());
+        base.setTextScaleX(paint.getTextScaleX());
     }
     if (base.getTextSkewX() != paint.getTextSkewX()) {
         last = ptr;
         *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
         *ptr++ = castToU32(paint.getTextSkewX());
+        base.setTextSkewX(paint.getTextSkewX());
+    }
+
+    if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
+        uint32_t id = this->getTypefaceID(paint.getTypeface());
+        last = ptr;
+        *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
+        base.setTypeface(paint.getTypeface());
     }
 
     size_t size = (char*)ptr - (char*)storage;
     if (size && this->needOpBytes(size)) {
-        *fPaints[0] = paint;
-
         this->writeOp(kPaintOp_DrawOp, 0, 0);
         size_t size = (char*)ptr - (char*)storage;
         *last |= kLastOp_PaintOpFlag << PAINTOPS_DATA_BITS;