Home | History | Annotate | Download | only in pipe
      1 /*
      2     Copyright 2011 Google Inc.
      3 
      4     Licensed under the Apache License, Version 2.0 (the "License");
      5     you may not use this file except in compliance with the License.
      6     You may obtain a copy of the License at
      7 
      8     http://www.apache.org/licenses/LICENSE-2.0
      9 
     10     Unless required by applicable law or agreed to in writing, software
     11     distributed under the License is distributed on an "AS IS" BASIS,
     12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13     See the License for the specific language governing permissions and
     14     limitations under the License.
     15  */
     16 
     17 
     18 #include "SkCanvas.h"
     19 #include "SkDevice.h"
     20 #include "SkPaint.h"
     21 #include "SkGPipe.h"
     22 #include "SkGPipePriv.h"
     23 #include "SkStream.h"
     24 #include "SkTSearch.h"
     25 #include "SkTypeface.h"
     26 #include "SkWriter32.h"
     27 #include "SkColorFilter.h"
     28 #include "SkDrawLooper.h"
     29 #include "SkMaskFilter.h"
     30 #include "SkRasterizer.h"
     31 #include "SkShader.h"
     32 
     33 static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
     34     SkASSERT(paintFlat < kCount_PaintFlats);
     35     switch (paintFlat) {
     36         case kColorFilter_PaintFlat:    return paint.getColorFilter();
     37         case kDrawLooper_PaintFlat:     return paint.getLooper();
     38         case kMaskFilter_PaintFlat:     return paint.getMaskFilter();
     39         case kPathEffect_PaintFlat:     return paint.getPathEffect();
     40         case kRasterizer_PaintFlat:     return paint.getRasterizer();
     41         case kShader_PaintFlat:         return paint.getShader();
     42         case kXfermode_PaintFlat:       return paint.getXfermode();
     43     }
     44     SkASSERT(!"never gets here");
     45     return NULL;
     46 }
     47 
     48 static size_t estimateFlattenSize(const SkPath& path) {
     49     int n = path.countPoints();
     50     size_t bytes = 3 * sizeof(int32_t);
     51     bytes += n * sizeof(SkPoint);
     52     bytes += SkAlign4(n + 2);    // verbs: add 2 for move/close extras
     53 
     54 #ifdef SK_DEBUG
     55     {
     56         SkWriter32 writer(1024);
     57         path.flatten(writer);
     58         SkASSERT(writer.size() <= bytes);
     59     }
     60 #endif
     61     return bytes;
     62 }
     63 
     64 static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
     65     SkASSERT(typeface);
     66     SkDynamicMemoryWStream stream;
     67     typeface->serialize(&stream);
     68     size_t size = stream.getOffset();
     69     if (writer) {
     70         writer->write32(size);
     71         writer->write(stream.getStream(), size);
     72     }
     73     return 4 + size;
     74 }
     75 
     76 ///////////////////////////////////////////////////////////////////////////////
     77 
     78 class SkGPipeCanvas : public SkCanvas {
     79 public:
     80     SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*);
     81     virtual ~SkGPipeCanvas();
     82 
     83     void finish() {
     84         if (!fDone) {
     85             this->writeOp(kDone_DrawOp);
     86             this->doNotify();
     87             fDone = true;
     88         }
     89     }
     90 
     91     // overrides from SkCanvas
     92     virtual int save(SaveFlags);
     93     virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags);
     94     virtual void restore();
     95     virtual bool translate(SkScalar dx, SkScalar dy);
     96     virtual bool scale(SkScalar sx, SkScalar sy);
     97     virtual bool rotate(SkScalar degrees);
     98     virtual bool skew(SkScalar sx, SkScalar sy);
     99     virtual bool concat(const SkMatrix& matrix);
    100     virtual void setMatrix(const SkMatrix& matrix);
    101     virtual bool clipRect(const SkRect& rect, SkRegion::Op op);
    102     virtual bool clipPath(const SkPath& path, SkRegion::Op op);
    103     virtual bool clipRegion(const SkRegion& region, SkRegion::Op op);
    104     virtual void clear(SkColor);
    105     virtual void drawPaint(const SkPaint& paint);
    106     virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
    107                             const SkPaint&);
    108     virtual void drawRect(const SkRect& rect, const SkPaint&);
    109     virtual void drawPath(const SkPath& path, const SkPaint&);
    110     virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
    111                             const SkPaint*);
    112     virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src,
    113                                 const SkRect& dst, const SkPaint*);
    114     virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
    115                                   const SkPaint*);
    116     virtual void drawSprite(const SkBitmap&, int left, int top,
    117                             const SkPaint*);
    118     virtual void drawText(const void* text, size_t byteLength, SkScalar x,
    119                           SkScalar y, const SkPaint&);
    120     virtual void drawPosText(const void* text, size_t byteLength,
    121                              const SkPoint pos[], const SkPaint&);
    122     virtual void drawPosTextH(const void* text, size_t byteLength,
    123                       const SkScalar xpos[], SkScalar constY, const SkPaint&);
    124     virtual void drawTextOnPath(const void* text, size_t byteLength,
    125                             const SkPath& path, const SkMatrix* matrix,
    126                                 const SkPaint&);
    127     virtual void drawPicture(SkPicture& picture);
    128     virtual void drawShape(SkShape*);
    129     virtual void drawVertices(VertexMode, int vertexCount,
    130                           const SkPoint vertices[], const SkPoint texs[],
    131                           const SkColor colors[], SkXfermode*,
    132                           const uint16_t indices[], int indexCount,
    133                               const SkPaint&);
    134     virtual void drawData(const void*, size_t);
    135 
    136 private:
    137     SkFactorySet* fFactorySet;  // optional, only used if cross-process
    138     SkGPipeController* fController;
    139     SkWriter32& fWriter;
    140     size_t      fBlockSize; // amount allocated for writer
    141     size_t      fBytesNotified;
    142     bool        fDone;
    143 
    144     SkRefCntSet fTypefaceSet;
    145 
    146     uint32_t getTypefaceID(SkTypeface*);
    147 
    148     inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
    149         fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
    150     }
    151 
    152     inline void writeOp(DrawOps op) {
    153         fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
    154     }
    155 
    156     bool needOpBytes(size_t size = 0);
    157 
    158     inline void doNotify() {
    159         if (!fDone) {
    160             size_t bytes = fWriter.size() - fBytesNotified;
    161             fController->notifyWritten(bytes);
    162             fBytesNotified += bytes;
    163         }
    164     }
    165 
    166     struct FlatData {
    167         uint32_t    fIndex; // always > 0
    168         uint32_t    fSize;
    169 
    170         void*       data() { return (char*)this + sizeof(*this); }
    171 
    172         static int Compare(const FlatData* a, const FlatData* b) {
    173             return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
    174         }
    175     };
    176     SkTDArray<FlatData*> fFlatArray;
    177     int fCurrFlatIndex[kCount_PaintFlats];
    178     int flattenToIndex(SkFlattenable* obj, PaintFlats);
    179 
    180     SkPaint fPaint;
    181     void writePaint(const SkPaint&);
    182 
    183     class AutoPipeNotify {
    184     public:
    185         AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
    186         ~AutoPipeNotify() { fCanvas->doNotify(); }
    187     private:
    188         SkGPipeCanvas* fCanvas;
    189     };
    190     friend class AutoPipeNotify;
    191 
    192     typedef SkCanvas INHERITED;
    193 };
    194 
    195 // return 0 for NULL (or unflattenable obj), or index-base-1
    196 int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
    197     if (NULL == obj) {
    198         return 0;
    199     }
    200 
    201     SkFlattenable::Factory fact = obj->getFactory();
    202     if (NULL == fact) {
    203         return 0;
    204     }
    205 
    206     if (fFactorySet) {
    207         uint32_t id = fFactorySet->find((void*)fact);
    208         if (0 == id) {
    209             const char* name = SkFlattenable::FactoryToName(fact);
    210             if (NULL == name) {
    211                 return 0;
    212             }
    213             size_t len = strlen(name);
    214             size_t size = SkWriter32::WriteStringSize(name, len);
    215             if (!this->needOpBytes(size)) {
    216                 return 0;
    217             }
    218             unsigned id = fFactorySet->add(fact);
    219             this->writeOp(kName_Flattenable_DrawOp, paintflat, id);
    220             fWriter.writeString(name, len);
    221         }
    222     }
    223 
    224     SkFlattenableWriteBuffer tmpWriter(1024);
    225     tmpWriter.setFactoryRecorder(fFactorySet);
    226 
    227     tmpWriter.writeFlattenable(obj);
    228     size_t len = tmpWriter.size();
    229     size_t allocSize = len + sizeof(FlatData);
    230 
    231     SkAutoSMalloc<1024> storage(allocSize);
    232     FlatData* flat = (FlatData*)storage.get();
    233     flat->fSize = len;
    234     tmpWriter.flatten(flat->data());
    235 
    236     int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
    237                                     fFlatArray.count(), flat, sizeof(flat),
    238                                     &FlatData::Compare);
    239     if (index < 0) {
    240         index = ~index;
    241         FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
    242         memcpy(copy, flat, allocSize);
    243         *fFlatArray.insert(index) = copy;
    244         // call this after the insert, so that count() will have been grown
    245         copy->fIndex = fFlatArray.count();
    246 //        SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
    247 
    248         if (this->needOpBytes(len)) {
    249             this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex);
    250             fWriter.write(copy->data(), len);
    251         }
    252     }
    253     return fFlatArray[index]->fIndex;
    254 }
    255 
    256 ///////////////////////////////////////////////////////////////////////////////
    257 
    258 #define MIN_BLOCK_SIZE  (16 * 1024)
    259 
    260 SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
    261                              SkWriter32* writer, SkFactorySet* fset)
    262         : fWriter(*writer), fFactorySet(fset) {
    263     fController = controller;
    264     fDone = false;
    265     fBlockSize = 0; // need first block from controller
    266     sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
    267 
    268     // we need a device to limit our clip
    269     // should the caller give us the bounds?
    270     SkBitmap bitmap;
    271     bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
    272     SkDevice* device = SkNEW_ARGS(SkDevice, (this, bitmap, false));
    273     this->setDevice(device)->unref();
    274 }
    275 
    276 SkGPipeCanvas::~SkGPipeCanvas() {
    277     this->finish();
    278 
    279     fFlatArray.freeAll();
    280 }
    281 
    282 bool SkGPipeCanvas::needOpBytes(size_t needed) {
    283     if (fDone) {
    284         return false;
    285     }
    286 
    287     needed += 4;  // size of DrawOp atom
    288     if (fWriter.size() + needed > fBlockSize) {
    289         void* block = fController->requestBlock(MIN_BLOCK_SIZE, &fBlockSize);
    290         if (NULL == block) {
    291             fDone = true;
    292             return false;
    293         }
    294         fWriter.reset(block, fBlockSize);
    295         fBytesNotified = 0;
    296     }
    297     return true;
    298 }
    299 
    300 uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
    301     uint32_t id = 0; // 0 means default/null typeface
    302     if (face) {
    303         id = fTypefaceSet.find(face);
    304         if (0 == id) {
    305             id = fTypefaceSet.add(face);
    306             size_t size = writeTypeface(NULL, face);
    307             if (this->needOpBytes(size)) {
    308                 this->writeOp(kDef_Typeface_DrawOp);
    309                 writeTypeface(&fWriter, face);
    310             }
    311         }
    312     }
    313     return id;
    314 }
    315 
    316 ///////////////////////////////////////////////////////////////////////////////
    317 
    318 #define NOTIFY_SETUP(canvas)    \
    319     AutoPipeNotify apn(canvas)
    320 
    321 int SkGPipeCanvas::save(SaveFlags flags) {
    322     NOTIFY_SETUP(this);
    323     if (this->needOpBytes()) {
    324         this->writeOp(kSave_DrawOp, 0, flags);
    325     }
    326     return this->INHERITED::save(flags);
    327 }
    328 
    329 int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
    330                              SaveFlags saveFlags) {
    331     NOTIFY_SETUP(this);
    332     size_t size = 0;
    333     unsigned opFlags = 0;
    334 
    335     if (bounds) {
    336         opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
    337         size += sizeof(SkRect);
    338     }
    339     if (paint) {
    340         opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
    341         this->writePaint(*paint);
    342     }
    343 
    344     if (this->needOpBytes(size)) {
    345         this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
    346         if (bounds) {
    347             fWriter.writeRect(*bounds);
    348         }
    349     }
    350 
    351     // we just pass on the save, so we don't create a layer
    352     return this->INHERITED::save(saveFlags);
    353 }
    354 
    355 void SkGPipeCanvas::restore() {
    356     NOTIFY_SETUP(this);
    357     if (this->needOpBytes()) {
    358         this->writeOp(kRestore_DrawOp);
    359     }
    360     this->INHERITED::restore();
    361 }
    362 
    363 bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
    364     if (dx || dy) {
    365         NOTIFY_SETUP(this);
    366         if (this->needOpBytes(2 * sizeof(SkScalar))) {
    367             this->writeOp(kTranslate_DrawOp);
    368             fWriter.writeScalar(dx);
    369             fWriter.writeScalar(dy);
    370         }
    371     }
    372     return this->INHERITED::translate(dx, dy);
    373 }
    374 
    375 bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
    376     if (sx || sy) {
    377         NOTIFY_SETUP(this);
    378         if (this->needOpBytes(2 * sizeof(SkScalar))) {
    379             this->writeOp(kScale_DrawOp);
    380             fWriter.writeScalar(sx);
    381             fWriter.writeScalar(sy);
    382         }
    383     }
    384     return this->INHERITED::scale(sx, sy);
    385 }
    386 
    387 bool SkGPipeCanvas::rotate(SkScalar degrees) {
    388     if (degrees) {
    389         NOTIFY_SETUP(this);
    390         if (this->needOpBytes(sizeof(SkScalar))) {
    391             this->writeOp(kRotate_DrawOp);
    392             fWriter.writeScalar(degrees);
    393         }
    394     }
    395     return this->INHERITED::rotate(degrees);
    396 }
    397 
    398 bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
    399     if (sx || sy) {
    400         NOTIFY_SETUP(this);
    401         if (this->needOpBytes(2 * sizeof(SkScalar))) {
    402             this->writeOp(kSkew_DrawOp);
    403             fWriter.writeScalar(sx);
    404             fWriter.writeScalar(sy);
    405         }
    406     }
    407     return this->INHERITED::skew(sx, sy);
    408 }
    409 
    410 bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
    411     if (!matrix.isIdentity()) {
    412         NOTIFY_SETUP(this);
    413         if (this->needOpBytes(matrix.flatten(NULL))) {
    414             this->writeOp(kConcat_DrawOp);
    415             SkWriteMatrix(&fWriter, matrix);
    416         }
    417     }
    418     return this->INHERITED::concat(matrix);
    419 }
    420 
    421 void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
    422     NOTIFY_SETUP(this);
    423     if (this->needOpBytes(matrix.flatten(NULL))) {
    424         this->writeOp(kSetMatrix_DrawOp);
    425         SkWriteMatrix(&fWriter, matrix);
    426     }
    427     this->INHERITED::setMatrix(matrix);
    428 }
    429 
    430 bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) {
    431     NOTIFY_SETUP(this);
    432     if (this->needOpBytes(sizeof(SkRect))) {
    433         this->writeOp(kClipRect_DrawOp, 0, rgnOp);
    434         fWriter.writeRect(rect);
    435     }
    436     return this->INHERITED::clipRect(rect, rgnOp);
    437 }
    438 
    439 bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) {
    440     NOTIFY_SETUP(this);
    441     if (this->needOpBytes(estimateFlattenSize(path))) {
    442         this->writeOp(kClipPath_DrawOp, 0, rgnOp);
    443         path.flatten(fWriter);
    444     }
    445     // we just pass on the bounds of the path
    446     return this->INHERITED::clipRect(path.getBounds(), rgnOp);
    447 }
    448 
    449 bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
    450     NOTIFY_SETUP(this);
    451     if (this->needOpBytes(region.flatten(NULL))) {
    452         this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
    453         SkWriteRegion(&fWriter, region);
    454     }
    455     return this->INHERITED::clipRegion(region, rgnOp);
    456 }
    457 
    458 ///////////////////////////////////////////////////////////////////////////////
    459 
    460 void SkGPipeCanvas::clear(SkColor color) {
    461     NOTIFY_SETUP(this);
    462     unsigned flags = 0;
    463     if (color) {
    464         flags |= kClear_HasColor_DrawOpFlag;
    465     }
    466     if (this->needOpBytes(sizeof(SkColor))) {
    467         this->writeOp(kDrawClear_DrawOp, flags, 0);
    468         if (color) {
    469             fWriter.write32(color);
    470         }
    471     }
    472 }
    473 
    474 void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
    475     NOTIFY_SETUP(this);
    476     this->writePaint(paint);
    477     if (this->needOpBytes()) {
    478         this->writeOp(kDrawPaint_DrawOp);
    479     }
    480 }
    481 
    482 void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
    483                                    const SkPoint pts[], const SkPaint& paint) {
    484     if (count) {
    485         NOTIFY_SETUP(this);
    486         this->writePaint(paint);
    487         if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
    488             this->writeOp(kDrawPoints_DrawOp, mode, 0);
    489             fWriter.write32(count);
    490             fWriter.write(pts, count * sizeof(SkPoint));
    491         }
    492     }
    493 }
    494 
    495 void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
    496     NOTIFY_SETUP(this);
    497     this->writePaint(paint);
    498     if (this->needOpBytes(sizeof(SkRect))) {
    499         this->writeOp(kDrawRect_DrawOp);
    500         fWriter.writeRect(rect);
    501     }
    502 }
    503 
    504 void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
    505     NOTIFY_SETUP(this);
    506     this->writePaint(paint);
    507     if (this->needOpBytes(estimateFlattenSize(path))) {
    508         this->writeOp(kDrawPath_DrawOp);
    509         path.flatten(fWriter);
    510     }
    511 }
    512 
    513 void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
    514                                    const SkPaint*) {
    515     UNIMPLEMENTED
    516 }
    517 
    518 void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src,
    519                                        const SkRect& dst, const SkPaint*) {
    520     UNIMPLEMENTED
    521 }
    522 
    523 void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
    524                                          const SkPaint*) {
    525     UNIMPLEMENTED
    526 }
    527 
    528 void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top,
    529                                    const SkPaint*) {
    530     UNIMPLEMENTED
    531 }
    532 
    533 void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
    534                                  SkScalar y, const SkPaint& paint) {
    535     if (byteLength) {
    536         NOTIFY_SETUP(this);
    537         this->writePaint(paint);
    538         if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
    539             this->writeOp(kDrawText_DrawOp);
    540             fWriter.write32(byteLength);
    541             fWriter.writePad(text, byteLength);
    542             fWriter.writeScalar(x);
    543             fWriter.writeScalar(y);
    544         }
    545     }
    546 }
    547 
    548 void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
    549                                 const SkPoint pos[], const SkPaint& paint) {
    550     if (byteLength) {
    551         NOTIFY_SETUP(this);
    552         this->writePaint(paint);
    553         int count = paint.textToGlyphs(text, byteLength, NULL);
    554         if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
    555             this->writeOp(kDrawPosText_DrawOp);
    556             fWriter.write32(byteLength);
    557             fWriter.writePad(text, byteLength);
    558             fWriter.write32(count);
    559             fWriter.write(pos, count * sizeof(SkPoint));
    560         }
    561     }
    562 }
    563 
    564 void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
    565                                  const SkScalar xpos[], SkScalar constY,
    566                                  const SkPaint& paint) {
    567     if (byteLength) {
    568         NOTIFY_SETUP(this);
    569         this->writePaint(paint);
    570         int count = paint.textToGlyphs(text, byteLength, NULL);
    571         if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
    572             this->writeOp(kDrawPosTextH_DrawOp);
    573             fWriter.write32(byteLength);
    574             fWriter.writePad(text, byteLength);
    575             fWriter.write32(count);
    576             fWriter.write(xpos, count * sizeof(SkScalar));
    577             fWriter.writeScalar(constY);
    578         }
    579     }
    580 }
    581 
    582 void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
    583                                    const SkPath& path, const SkMatrix* matrix,
    584                                    const SkPaint& paint) {
    585     if (byteLength) {
    586         NOTIFY_SETUP(this);
    587         unsigned flags = 0;
    588         size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path);
    589         if (matrix) {
    590             flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
    591             size += matrix->flatten(NULL);
    592         }
    593         this->writePaint(paint);
    594         if (this->needOpBytes(size)) {
    595             this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
    596 
    597             fWriter.write32(byteLength);
    598             fWriter.writePad(text, byteLength);
    599 
    600             path.flatten(fWriter);
    601             if (matrix) {
    602                 SkWriteMatrix(&fWriter, *matrix);
    603             }
    604         }
    605     }
    606 }
    607 
    608 void SkGPipeCanvas::drawPicture(SkPicture& picture) {
    609     // we want to playback the picture into individual draw calls
    610     this->INHERITED::drawPicture(picture);
    611 }
    612 
    613 void SkGPipeCanvas::drawShape(SkShape* shape) {
    614     UNIMPLEMENTED
    615 }
    616 
    617 void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
    618                                  const SkPoint vertices[], const SkPoint texs[],
    619                                  const SkColor colors[], SkXfermode*,
    620                                  const uint16_t indices[], int indexCount,
    621                                  const SkPaint& paint) {
    622     if (0 == vertexCount) {
    623         return;
    624     }
    625 
    626     NOTIFY_SETUP(this);
    627     size_t size = 4 + vertexCount * sizeof(SkPoint);
    628     this->writePaint(paint);
    629     unsigned flags = 0;
    630     if (texs) {
    631         flags |= kDrawVertices_HasTexs_DrawOpFlag;
    632         size += vertexCount * sizeof(SkPoint);
    633     }
    634     if (colors) {
    635         flags |= kDrawVertices_HasColors_DrawOpFlag;
    636         size += vertexCount * sizeof(SkColor);
    637     }
    638     if (indices && indexCount > 0) {
    639         flags |= kDrawVertices_HasIndices_DrawOpFlag;
    640         size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
    641     }
    642 
    643     if (this->needOpBytes(size)) {
    644         this->writeOp(kDrawVertices_DrawOp, flags, 0);
    645         fWriter.write32(mode);
    646         fWriter.write32(vertexCount);
    647         fWriter.write(vertices, vertexCount * sizeof(SkPoint));
    648         if (texs) {
    649             fWriter.write(texs, vertexCount * sizeof(SkPoint));
    650         }
    651         if (colors) {
    652             fWriter.write(colors, vertexCount * sizeof(SkColor));
    653         }
    654 
    655         // TODO: flatten xfermode
    656 
    657         if (indices && indexCount > 0) {
    658             fWriter.write32(indexCount);
    659             fWriter.writePad(indices, indexCount * sizeof(uint16_t));
    660         }
    661     }
    662 }
    663 
    664 void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
    665     if (size && ptr) {
    666         NOTIFY_SETUP(this);
    667         unsigned data = 0;
    668         if (size < (1 << DRAWOPS_DATA_BITS)) {
    669             data = (unsigned)size;
    670         }
    671         if (this->needOpBytes(4 + SkAlign4(size))) {
    672             this->writeOp(kDrawData_DrawOp, 0, data);
    673             if (0 == data) {
    674                 fWriter.write32(size);
    675             }
    676             fWriter.writePad(ptr, size);
    677         }
    678     }
    679 }
    680 
    681 ///////////////////////////////////////////////////////////////////////////////
    682 
    683 template <typename T> uint32_t castToU32(T value) {
    684     union {
    685         T           fSrc;
    686         uint32_t    fDst;
    687     } data;
    688     data.fSrc = value;
    689     return data.fDst;
    690 }
    691 
    692 void SkGPipeCanvas::writePaint(const SkPaint& paint) {
    693     SkPaint& base = fPaint;
    694     uint32_t storage[32];
    695     uint32_t* ptr = storage;
    696 
    697     if (base.getFlags() != paint.getFlags()) {
    698         *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
    699         base.setFlags(paint.getFlags());
    700     }
    701     if (base.getColor() != paint.getColor()) {
    702         *ptr++ = PaintOp_packOp(kColor_PaintOp);
    703         *ptr++ = paint.getColor();
    704         base.setColor(paint.getColor());
    705     }
    706     if (base.getStyle() != paint.getStyle()) {
    707         *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
    708         base.setStyle(paint.getStyle());
    709     }
    710     if (base.getStrokeJoin() != paint.getStrokeJoin()) {
    711         *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
    712         base.setStrokeJoin(paint.getStrokeJoin());
    713     }
    714     if (base.getStrokeCap() != paint.getStrokeCap()) {
    715         *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
    716         base.setStrokeCap(paint.getStrokeCap());
    717     }
    718     if (base.getStrokeWidth() != paint.getStrokeWidth()) {
    719         *ptr++ = PaintOp_packOp(kWidth_PaintOp);
    720         *ptr++ = castToU32(paint.getStrokeWidth());
    721         base.setStrokeWidth(paint.getStrokeWidth());
    722     }
    723     if (base.getStrokeMiter() != paint.getStrokeMiter()) {
    724         *ptr++ = PaintOp_packOp(kMiter_PaintOp);
    725         *ptr++ = castToU32(paint.getStrokeMiter());
    726         base.setStrokeMiter(paint.getStrokeMiter());
    727     }
    728     if (base.getTextEncoding() != paint.getTextEncoding()) {
    729         *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
    730         base.setTextEncoding(paint.getTextEncoding());
    731     }
    732     if (base.getHinting() != paint.getHinting()) {
    733         *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
    734         base.setHinting(paint.getHinting());
    735     }
    736     if (base.getTextAlign() != paint.getTextAlign()) {
    737         *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
    738         base.setTextAlign(paint.getTextAlign());
    739     }
    740     if (base.getTextSize() != paint.getTextSize()) {
    741         *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
    742         *ptr++ = castToU32(paint.getTextSize());
    743         base.setTextSize(paint.getTextSize());
    744     }
    745     if (base.getTextScaleX() != paint.getTextScaleX()) {
    746         *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
    747         *ptr++ = castToU32(paint.getTextScaleX());
    748         base.setTextScaleX(paint.getTextScaleX());
    749     }
    750     if (base.getTextSkewX() != paint.getTextSkewX()) {
    751         *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
    752         *ptr++ = castToU32(paint.getTextSkewX());
    753         base.setTextSkewX(paint.getTextSkewX());
    754     }
    755 
    756     if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
    757         uint32_t id = this->getTypefaceID(paint.getTypeface());
    758         *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
    759         base.setTypeface(paint.getTypeface());
    760     }
    761 
    762     for (int i = 0; i < kCount_PaintFlats; i++) {
    763         int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
    764         SkASSERT(index >= 0 && index <= fFlatArray.count());
    765         if (index != fCurrFlatIndex[i]) {
    766             *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
    767             fCurrFlatIndex[i] = index;
    768         }
    769     }
    770 
    771     size_t size = (char*)ptr - (char*)storage;
    772     if (size && this->needOpBytes(size)) {
    773         this->writeOp(kPaintOp_DrawOp, 0, size);
    774         fWriter.write(storage, size);
    775         for (size_t i = 0; i < size/4; i++) {
    776 //            SkDebugf("[%d] %08X\n", i, storage[i]);
    777         }
    778     }
    779 }
    780 
    781 ///////////////////////////////////////////////////////////////////////////////
    782 
    783 #include "SkGPipe.h"
    784 
    785 SkGPipeWriter::SkGPipeWriter() : fWriter(0) {
    786     fCanvas = NULL;
    787 }
    788 
    789 SkGPipeWriter::~SkGPipeWriter() {
    790     this->endRecording();
    791     SkSafeUnref(fCanvas);
    792 }
    793 
    794 SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller,
    795                                         uint32_t flags) {
    796     if (NULL == fCanvas) {
    797         fWriter.reset(NULL, 0);
    798         fFactorySet.reset();
    799         fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
    800                                              (flags & kCrossProcess_Flag) ?
    801                                              &fFactorySet : NULL));
    802     }
    803     return fCanvas;
    804 }
    805 
    806 void SkGPipeWriter::endRecording() {
    807     if (fCanvas) {
    808         fCanvas->finish();
    809         fCanvas->unref();
    810         fCanvas = NULL;
    811     }
    812 }
    813 
    814