Home | History | Annotate | Download | only in pipe
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "SkAnnotation.h"
     10 #include "SkBitmapHeap.h"
     11 #include "SkCanvas.h"
     12 #include "SkColorFilter.h"
     13 #include "SkData.h"
     14 #include "SkDrawLooper.h"
     15 #include "SkDevice.h"
     16 #include "SkGPipe.h"
     17 #include "SkGPipePriv.h"
     18 #include "SkImageFilter.h"
     19 #include "SkMaskFilter.h"
     20 #include "SkOrderedWriteBuffer.h"
     21 #include "SkPaint.h"
     22 #include "SkPathEffect.h"
     23 #include "SkPictureFlat.h"
     24 #include "SkRasterizer.h"
     25 #include "SkRRect.h"
     26 #include "SkShader.h"
     27 #include "SkStream.h"
     28 #include "SkTSearch.h"
     29 #include "SkTypeface.h"
     30 #include "SkWriter32.h"
     31 
     32 enum {
     33     kSizeOfFlatRRect = sizeof(SkRect) + 4 * sizeof(SkVector)
     34 };
     35 
     36 static bool isCrossProcess(uint32_t flags) {
     37     return SkToBool(flags & SkGPipeWriter::kCrossProcess_Flag);
     38 }
     39 
     40 static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
     41     SkASSERT(paintFlat < kCount_PaintFlats);
     42     switch (paintFlat) {
     43         case kColorFilter_PaintFlat:    return paint.getColorFilter();
     44         case kDrawLooper_PaintFlat:     return paint.getLooper();
     45         case kMaskFilter_PaintFlat:     return paint.getMaskFilter();
     46         case kPathEffect_PaintFlat:     return paint.getPathEffect();
     47         case kRasterizer_PaintFlat:     return paint.getRasterizer();
     48         case kShader_PaintFlat:         return paint.getShader();
     49         case kImageFilter_PaintFlat:    return paint.getImageFilter();
     50         case kXfermode_PaintFlat:       return paint.getXfermode();
     51         case kAnnotation_PaintFlat:     return paint.getAnnotation();
     52     }
     53     SkDEBUGFAIL("never gets here");
     54     return NULL;
     55 }
     56 
     57 static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
     58     SkASSERT(typeface);
     59     SkDynamicMemoryWStream stream;
     60     typeface->serialize(&stream);
     61     size_t size = stream.getOffset();
     62     if (writer) {
     63         writer->write32(size);
     64         SkAutoDataUnref data(stream.copyToData());
     65         writer->writePad(data->data(), size);
     66     }
     67     return 4 + SkAlign4(size);
     68 }
     69 
     70 ///////////////////////////////////////////////////////////////////////////////
     71 
     72 class FlattenableHeap : public SkFlatController {
     73 public:
     74     FlattenableHeap(int numFlatsToKeep, SkNamedFactorySet* fset, bool isCrossProcess)
     75     : fNumFlatsToKeep(numFlatsToKeep) {
     76         SkASSERT((isCrossProcess && fset != NULL) || (!isCrossProcess && NULL == fset));
     77         if (isCrossProcess) {
     78             this->setNamedFactorySet(fset);
     79             this->setWriteBufferFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag);
     80         }
     81     }
     82 
     83     ~FlattenableHeap() {
     84         fPointers.freeAll();
     85     }
     86 
     87     virtual void* allocThrow(size_t bytes) SK_OVERRIDE;
     88 
     89     virtual void unalloc(void* ptr) SK_OVERRIDE;
     90 
     91     void setBitmapStorage(SkBitmapHeap* heap) {
     92         this->setBitmapHeap(heap);
     93     }
     94 
     95     const SkFlatData* flatToReplace() const;
     96 
     97     // Mark an SkFlatData as one that should not be returned by flatToReplace.
     98     // Takes the result of SkFlatData::index() as its parameter.
     99     void markFlatForKeeping(int index) {
    100         *fFlatsThatMustBeKept.append() = index;
    101     }
    102 
    103     void markAllFlatsSafeToDelete() {
    104         fFlatsThatMustBeKept.reset();
    105     }
    106 
    107 private:
    108     // Keep track of the indices (i.e. the result of SkFlatData::index()) of
    109     // flats that must be kept, since they are on the current paint.
    110     SkTDArray<int>   fFlatsThatMustBeKept;
    111     SkTDArray<void*> fPointers;
    112     const int        fNumFlatsToKeep;
    113 };
    114 
    115 void FlattenableHeap::unalloc(void* ptr) {
    116     int indexToRemove = fPointers.rfind(ptr);
    117     if (indexToRemove >= 0) {
    118         sk_free(ptr);
    119         fPointers.remove(indexToRemove);
    120     }
    121 }
    122 
    123 void* FlattenableHeap::allocThrow(size_t bytes) {
    124     void* ptr = sk_malloc_throw(bytes);
    125     *fPointers.append() = ptr;
    126     return ptr;
    127 }
    128 
    129 const SkFlatData* FlattenableHeap::flatToReplace() const {
    130     // First, determine whether we should replace one.
    131     if (fPointers.count() > fNumFlatsToKeep) {
    132         // Look through the flattenable heap.
    133         // TODO: Return the LRU flat.
    134         for (int i = 0; i < fPointers.count(); i++) {
    135             SkFlatData* potential = (SkFlatData*)fPointers[i];
    136             // Make sure that it is not one that must be kept.
    137             bool mustKeep = false;
    138             for (int j = 0; j < fFlatsThatMustBeKept.count(); j++) {
    139                 if (potential->index() == fFlatsThatMustBeKept[j]) {
    140                     mustKeep = true;
    141                     break;
    142                 }
    143             }
    144             if (!mustKeep) {
    145                 return potential;
    146             }
    147         }
    148     }
    149     return NULL;
    150 }
    151 
    152 ///////////////////////////////////////////////////////////////////////////////
    153 
    154 class FlatDictionary : public SkFlatDictionary<SkFlattenable> {
    155 public:
    156     FlatDictionary(FlattenableHeap* heap)
    157             : SkFlatDictionary<SkFlattenable>(heap) {
    158         fFlattenProc = &flattenFlattenableProc;
    159         // No need to define fUnflattenProc since the writer will never
    160         // unflatten the data.
    161     }
    162     static void flattenFlattenableProc(SkOrderedWriteBuffer& buffer,
    163                                        const void* obj) {
    164         buffer.writeFlattenable((SkFlattenable*)obj);
    165     }
    166 
    167 };
    168 
    169 ///////////////////////////////////////////////////////////////////////////////
    170 
    171 class SkGPipeCanvas : public SkCanvas {
    172 public:
    173     SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags,
    174                   uint32_t width, uint32_t height);
    175     virtual ~SkGPipeCanvas();
    176 
    177     void finish() {
    178         if (!fDone) {
    179             if (this->needOpBytes()) {
    180                 this->writeOp(kDone_DrawOp);
    181                 this->doNotify();
    182                 if (shouldFlattenBitmaps(fFlags)) {
    183                     // In this case, a BitmapShuttle is reffed by the SkBitmapHeap
    184                     // and refs this canvas. Unref the SkBitmapHeap to end the
    185                     // circular reference. When shouldFlattenBitmaps is false,
    186                     // there is no circular reference, so the SkBitmapHeap can be
    187                     // safely unreffed in the destructor.
    188                     fBitmapHeap->unref();
    189                     // This eliminates a similar circular reference (Canvas owns
    190                     // the FlattenableHeap which holds a ref to the SkBitmapHeap).
    191                     fFlattenableHeap.setBitmapStorage(NULL);
    192                     fBitmapHeap = NULL;
    193                 }
    194             }
    195             fDone = true;
    196         }
    197     }
    198 
    199     void flushRecording(bool detachCurrentBlock);
    200     size_t freeMemoryIfPossible(size_t bytesToFree);
    201 
    202     size_t storageAllocatedForRecording() {
    203         return (NULL == fBitmapHeap) ? 0 : fBitmapHeap->bytesAllocated();
    204     }
    205 
    206     // overrides from SkCanvas
    207     virtual int save(SaveFlags) SK_OVERRIDE;
    208     virtual int saveLayer(const SkRect* bounds, const SkPaint*,
    209                           SaveFlags) SK_OVERRIDE;
    210     virtual void restore() SK_OVERRIDE;
    211     virtual bool isDrawingToLayer() const SK_OVERRIDE;
    212     virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE;
    213     virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE;
    214     virtual bool rotate(SkScalar degrees) SK_OVERRIDE;
    215     virtual bool skew(SkScalar sx, SkScalar sy) SK_OVERRIDE;
    216     virtual bool concat(const SkMatrix& matrix) SK_OVERRIDE;
    217     virtual void setMatrix(const SkMatrix& matrix) SK_OVERRIDE;
    218     virtual bool clipRect(const SkRect&, SkRegion::Op op, bool doAntiAlias = false) SK_OVERRIDE;
    219     virtual bool clipRRect(const SkRRect&, SkRegion::Op op, bool doAntiAlias = false) SK_OVERRIDE;
    220     virtual bool clipPath(const SkPath& path, SkRegion::Op op,
    221                           bool doAntiAlias = false) SK_OVERRIDE;
    222     virtual bool clipRegion(const SkRegion& region, SkRegion::Op op) SK_OVERRIDE;
    223     virtual void clear(SkColor) SK_OVERRIDE;
    224     virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE;
    225     virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
    226                             const SkPaint&) SK_OVERRIDE;
    227     virtual void drawOval(const SkRect&, const SkPaint&) SK_OVERRIDE;
    228     virtual void drawRect(const SkRect& rect, const SkPaint&) SK_OVERRIDE;
    229     virtual void drawRRect(const SkRRect&, const SkPaint&) SK_OVERRIDE;
    230     virtual void drawPath(const SkPath& path, const SkPaint&) SK_OVERRIDE;
    231     virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
    232                             const SkPaint*) SK_OVERRIDE;
    233     virtual void drawBitmapRectToRect(const SkBitmap&, const SkRect* src,
    234                                 const SkRect& dst, const SkPaint*) SK_OVERRIDE;
    235     virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
    236                                   const SkPaint*) SK_OVERRIDE;
    237     virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
    238                                 const SkRect& dst, const SkPaint* paint = NULL) SK_OVERRIDE;
    239     virtual void drawSprite(const SkBitmap&, int left, int top,
    240                             const SkPaint*) SK_OVERRIDE;
    241     virtual void drawText(const void* text, size_t byteLength, SkScalar x,
    242                           SkScalar y, const SkPaint&) SK_OVERRIDE;
    243     virtual void drawPosText(const void* text, size_t byteLength,
    244                              const SkPoint pos[], const SkPaint&) SK_OVERRIDE;
    245     virtual void drawPosTextH(const void* text, size_t byteLength,
    246                               const SkScalar xpos[], SkScalar constY,
    247                               const SkPaint&) SK_OVERRIDE;
    248     virtual void drawTextOnPath(const void* text, size_t byteLength,
    249                             const SkPath& path, const SkMatrix* matrix,
    250                                 const SkPaint&) SK_OVERRIDE;
    251     virtual void drawPicture(SkPicture& picture) SK_OVERRIDE;
    252     virtual void drawVertices(VertexMode, int vertexCount,
    253                           const SkPoint vertices[], const SkPoint texs[],
    254                           const SkColor colors[], SkXfermode*,
    255                           const uint16_t indices[], int indexCount,
    256                               const SkPaint&) SK_OVERRIDE;
    257     virtual void drawData(const void*, size_t) SK_OVERRIDE;
    258     virtual void beginCommentGroup(const char* description) SK_OVERRIDE;
    259     virtual void addComment(const char* kywd, const char* value) SK_OVERRIDE;
    260     virtual void endCommentGroup() SK_OVERRIDE;
    261 
    262     /**
    263      * Flatten an SkBitmap to send to the reader, where it will be referenced
    264      * according to slot.
    265      */
    266     bool shuttleBitmap(const SkBitmap&, int32_t slot);
    267 private:
    268     enum {
    269         kNoSaveLayer = -1,
    270     };
    271     SkNamedFactorySet* fFactorySet;
    272     int                fFirstSaveLayerStackLevel;
    273     SkBitmapHeap*      fBitmapHeap;
    274     SkGPipeController* fController;
    275     SkWriter32&        fWriter;
    276     size_t             fBlockSize; // amount allocated for writer
    277     size_t             fBytesNotified;
    278     bool               fDone;
    279     const uint32_t     fFlags;
    280 
    281     SkRefCntSet        fTypefaceSet;
    282 
    283     uint32_t getTypefaceID(SkTypeface*);
    284 
    285     inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
    286         fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
    287     }
    288 
    289     inline void writeOp(DrawOps op) {
    290         fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
    291     }
    292 
    293     bool needOpBytes(size_t size = 0);
    294 
    295     inline void doNotify() {
    296         if (!fDone) {
    297             size_t bytes = fWriter.size() - fBytesNotified;
    298             if (bytes > 0) {
    299                 fController->notifyWritten(bytes);
    300                 fBytesNotified += bytes;
    301             }
    302         }
    303     }
    304 
    305     // Should be called after any calls to an SkFlatDictionary::findAndReplace
    306     // if a new SkFlatData was added when in cross process mode
    307     void flattenFactoryNames();
    308 
    309     FlattenableHeap fFlattenableHeap;
    310     FlatDictionary  fFlatDictionary;
    311     int fCurrFlatIndex[kCount_PaintFlats];
    312     int flattenToIndex(SkFlattenable* obj, PaintFlats);
    313 
    314     // Common code used by drawBitmap*. Behaves differently depending on the
    315     // type of SkBitmapHeap being used, which is determined by the flags used.
    316     bool commonDrawBitmap(const SkBitmap& bm, DrawOps op, unsigned flags,
    317                           size_t opBytesNeeded, const SkPaint* paint);
    318 
    319     SkPaint fPaint;
    320     void writePaint(const SkPaint&);
    321 
    322     class AutoPipeNotify {
    323     public:
    324         AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
    325         ~AutoPipeNotify() { fCanvas->doNotify(); }
    326     private:
    327         SkGPipeCanvas* fCanvas;
    328     };
    329     friend class AutoPipeNotify;
    330 
    331     typedef SkCanvas INHERITED;
    332 };
    333 
    334 void SkGPipeCanvas::flattenFactoryNames() {
    335     const char* name;
    336     while ((name = fFactorySet->getNextAddedFactoryName()) != NULL) {
    337         size_t len = strlen(name);
    338         if (this->needOpBytes(len)) {
    339             this->writeOp(kDef_Factory_DrawOp);
    340             fWriter.writeString(name, len);
    341         }
    342     }
    343 }
    344 
    345 bool SkGPipeCanvas::shuttleBitmap(const SkBitmap& bm, int32_t slot) {
    346     SkASSERT(shouldFlattenBitmaps(fFlags));
    347     SkOrderedWriteBuffer buffer(1024);
    348     buffer.setNamedFactoryRecorder(fFactorySet);
    349     buffer.writeBitmap(bm);
    350     this->flattenFactoryNames();
    351     uint32_t size = buffer.size();
    352     if (this->needOpBytes(size)) {
    353         this->writeOp(kDef_Bitmap_DrawOp, 0, slot);
    354         void* dst = static_cast<void*>(fWriter.reserve(size));
    355         buffer.writeToMemory(dst);
    356         return true;
    357     }
    358     return false;
    359 }
    360 
    361 // return 0 for NULL (or unflattenable obj), or index-base-1
    362 // return ~(index-base-1) if an old flattenable was replaced
    363 int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
    364     SkASSERT(!fDone && fBitmapHeap != NULL);
    365     if (NULL == obj) {
    366         return 0;
    367     }
    368 
    369     fBitmapHeap->deferAddingOwners();
    370     bool added, replaced;
    371     const SkFlatData* flat = fFlatDictionary.findAndReplace(*obj, fFlattenableHeap.flatToReplace(),
    372                                                             &added, &replaced);
    373     fBitmapHeap->endAddingOwnersDeferral(added);
    374     int index = flat->index();
    375     if (added) {
    376         if (isCrossProcess(fFlags)) {
    377             this->flattenFactoryNames();
    378         }
    379         size_t flatSize = flat->flatSize();
    380         if (this->needOpBytes(flatSize)) {
    381             this->writeOp(kDef_Flattenable_DrawOp, paintflat, index);
    382             fWriter.write(flat->data(), flatSize);
    383         }
    384     }
    385     if (replaced) {
    386         index = ~index;
    387     }
    388     return index;
    389 }
    390 
    391 ///////////////////////////////////////////////////////////////////////////////
    392 
    393 /**
    394  * If SkBitmaps are to be flattened to send to the reader, this class is
    395  * provided to the SkBitmapHeap to tell the SkGPipeCanvas to do so.
    396  */
    397 class BitmapShuttle : public SkBitmapHeap::ExternalStorage {
    398 public:
    399     BitmapShuttle(SkGPipeCanvas*);
    400 
    401     ~BitmapShuttle();
    402 
    403     virtual bool insert(const SkBitmap& bitmap, int32_t slot) SK_OVERRIDE;
    404 
    405 private:
    406     SkGPipeCanvas*    fCanvas;
    407 };
    408 
    409 ///////////////////////////////////////////////////////////////////////////////
    410 
    411 #define MIN_BLOCK_SIZE  (16 * 1024)
    412 #define BITMAPS_TO_KEEP 5
    413 #define FLATTENABLES_TO_KEEP 10
    414 
    415 SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
    416                              SkWriter32* writer, uint32_t flags,
    417                              uint32_t width, uint32_t height)
    418 : fFactorySet(isCrossProcess(flags) ? SkNEW(SkNamedFactorySet) : NULL)
    419 , fWriter(*writer)
    420 , fFlags(flags)
    421 , fFlattenableHeap(FLATTENABLES_TO_KEEP, fFactorySet, isCrossProcess(flags))
    422 , fFlatDictionary(&fFlattenableHeap) {
    423     fController = controller;
    424     fDone = false;
    425     fBlockSize = 0; // need first block from controller
    426     fBytesNotified = 0;
    427     fFirstSaveLayerStackLevel = kNoSaveLayer;
    428     sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
    429 
    430     // we need a device to limit our clip
    431     // We don't allocate pixels for the bitmap
    432     SkBitmap bitmap;
    433     bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
    434     SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
    435     this->setDevice(device)->unref();
    436 
    437     // Tell the reader the appropriate flags to use.
    438     if (this->needOpBytes()) {
    439         this->writeOp(kReportFlags_DrawOp, fFlags, 0);
    440     }
    441 
    442     if (shouldFlattenBitmaps(flags)) {
    443         BitmapShuttle* shuttle = SkNEW_ARGS(BitmapShuttle, (this));
    444         fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, (shuttle, BITMAPS_TO_KEEP));
    445         shuttle->unref();
    446     } else {
    447         fBitmapHeap = SkNEW_ARGS(SkBitmapHeap,
    448                                  (BITMAPS_TO_KEEP, controller->numberOfReaders()));
    449         if (this->needOpBytes(sizeof(void*))) {
    450             this->writeOp(kShareBitmapHeap_DrawOp);
    451             fWriter.writePtr(static_cast<void*>(fBitmapHeap));
    452         }
    453     }
    454     fFlattenableHeap.setBitmapStorage(fBitmapHeap);
    455     this->doNotify();
    456 }
    457 
    458 SkGPipeCanvas::~SkGPipeCanvas() {
    459     this->finish();
    460     SkSafeUnref(fFactorySet);
    461     SkSafeUnref(fBitmapHeap);
    462 }
    463 
    464 bool SkGPipeCanvas::needOpBytes(size_t needed) {
    465     if (fDone) {
    466         return false;
    467     }
    468 
    469     needed += 4;  // size of DrawOp atom
    470     if (fWriter.size() + needed > fBlockSize) {
    471         // Before we wipe out any data that has already been written, read it
    472         // out.
    473         this->doNotify();
    474         size_t blockSize = SkMax32(MIN_BLOCK_SIZE, needed);
    475         void* block = fController->requestBlock(blockSize, &fBlockSize);
    476         if (NULL == block) {
    477             fDone = true;
    478             return false;
    479         }
    480         SkASSERT(SkIsAlign4(fBlockSize));
    481         fWriter.reset(block, fBlockSize);
    482         fBytesNotified = 0;
    483     }
    484     return true;
    485 }
    486 
    487 uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
    488     uint32_t id = 0; // 0 means default/null typeface
    489     if (face) {
    490         id = fTypefaceSet.find(face);
    491         if (0 == id) {
    492             id = fTypefaceSet.add(face);
    493             size_t size = writeTypeface(NULL, face);
    494             if (this->needOpBytes(size)) {
    495                 this->writeOp(kDef_Typeface_DrawOp);
    496                 writeTypeface(&fWriter, face);
    497             }
    498         }
    499     }
    500     return id;
    501 }
    502 
    503 ///////////////////////////////////////////////////////////////////////////////
    504 
    505 #define NOTIFY_SETUP(canvas)    \
    506     AutoPipeNotify apn(canvas)
    507 
    508 int SkGPipeCanvas::save(SaveFlags flags) {
    509     NOTIFY_SETUP(this);
    510     if (this->needOpBytes()) {
    511         this->writeOp(kSave_DrawOp, 0, flags);
    512     }
    513     return this->INHERITED::save(flags);
    514 }
    515 
    516 int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
    517                              SaveFlags saveFlags) {
    518     NOTIFY_SETUP(this);
    519     size_t size = 0;
    520     unsigned opFlags = 0;
    521 
    522     if (bounds) {
    523         opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
    524         size += sizeof(SkRect);
    525     }
    526     if (paint) {
    527         opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
    528         this->writePaint(*paint);
    529     }
    530 
    531     if (this->needOpBytes(size)) {
    532         this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
    533         if (bounds) {
    534             fWriter.writeRect(*bounds);
    535         }
    536     }
    537 
    538     if (kNoSaveLayer == fFirstSaveLayerStackLevel){
    539         fFirstSaveLayerStackLevel = this->getSaveCount();
    540     }
    541     // we just pass on the save, so we don't create a layer
    542     return this->INHERITED::save(saveFlags);
    543 }
    544 
    545 void SkGPipeCanvas::restore() {
    546     NOTIFY_SETUP(this);
    547     if (this->needOpBytes()) {
    548         this->writeOp(kRestore_DrawOp);
    549     }
    550 
    551     this->INHERITED::restore();
    552 
    553     if (this->getSaveCount() == fFirstSaveLayerStackLevel){
    554         fFirstSaveLayerStackLevel = kNoSaveLayer;
    555     }
    556 }
    557 
    558 bool SkGPipeCanvas::isDrawingToLayer() const {
    559     return kNoSaveLayer != fFirstSaveLayerStackLevel;
    560 }
    561 
    562 bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
    563     if (dx || dy) {
    564         NOTIFY_SETUP(this);
    565         if (this->needOpBytes(2 * sizeof(SkScalar))) {
    566             this->writeOp(kTranslate_DrawOp);
    567             fWriter.writeScalar(dx);
    568             fWriter.writeScalar(dy);
    569         }
    570     }
    571     return this->INHERITED::translate(dx, dy);
    572 }
    573 
    574 bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
    575     if (sx || sy) {
    576         NOTIFY_SETUP(this);
    577         if (this->needOpBytes(2 * sizeof(SkScalar))) {
    578             this->writeOp(kScale_DrawOp);
    579             fWriter.writeScalar(sx);
    580             fWriter.writeScalar(sy);
    581         }
    582     }
    583     return this->INHERITED::scale(sx, sy);
    584 }
    585 
    586 bool SkGPipeCanvas::rotate(SkScalar degrees) {
    587     if (degrees) {
    588         NOTIFY_SETUP(this);
    589         if (this->needOpBytes(sizeof(SkScalar))) {
    590             this->writeOp(kRotate_DrawOp);
    591             fWriter.writeScalar(degrees);
    592         }
    593     }
    594     return this->INHERITED::rotate(degrees);
    595 }
    596 
    597 bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
    598     if (sx || sy) {
    599         NOTIFY_SETUP(this);
    600         if (this->needOpBytes(2 * sizeof(SkScalar))) {
    601             this->writeOp(kSkew_DrawOp);
    602             fWriter.writeScalar(sx);
    603             fWriter.writeScalar(sy);
    604         }
    605     }
    606     return this->INHERITED::skew(sx, sy);
    607 }
    608 
    609 bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
    610     if (!matrix.isIdentity()) {
    611         NOTIFY_SETUP(this);
    612         if (this->needOpBytes(matrix.writeToMemory(NULL))) {
    613             this->writeOp(kConcat_DrawOp);
    614             fWriter.writeMatrix(matrix);
    615         }
    616     }
    617     return this->INHERITED::concat(matrix);
    618 }
    619 
    620 void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
    621     NOTIFY_SETUP(this);
    622     if (this->needOpBytes(matrix.writeToMemory(NULL))) {
    623         this->writeOp(kSetMatrix_DrawOp);
    624         fWriter.writeMatrix(matrix);
    625     }
    626     this->INHERITED::setMatrix(matrix);
    627 }
    628 
    629 bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp,
    630                              bool doAntiAlias) {
    631     NOTIFY_SETUP(this);
    632     if (this->needOpBytes(sizeof(SkRect))) {
    633         unsigned flags = doAntiAlias & kClip_HasAntiAlias_DrawOpFlag;
    634         this->writeOp(kClipRect_DrawOp, flags, rgnOp);
    635         fWriter.writeRect(rect);
    636     }
    637     return this->INHERITED::clipRect(rect, rgnOp, doAntiAlias);
    638 }
    639 
    640 bool SkGPipeCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op rgnOp,
    641                               bool doAntiAlias) {
    642     NOTIFY_SETUP(this);
    643     if (this->needOpBytes(kSizeOfFlatRRect)) {
    644         unsigned flags = doAntiAlias & kClip_HasAntiAlias_DrawOpFlag;
    645         this->writeOp(kClipRRect_DrawOp, flags, rgnOp);
    646         fWriter.writeRRect(rrect);
    647     }
    648     return this->INHERITED::clipRRect(rrect, rgnOp, doAntiAlias);
    649 }
    650 
    651 bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp,
    652                              bool doAntiAlias) {
    653     NOTIFY_SETUP(this);
    654     if (this->needOpBytes(path.writeToMemory(NULL))) {
    655         unsigned flags = doAntiAlias & kClip_HasAntiAlias_DrawOpFlag;
    656         this->writeOp(kClipPath_DrawOp, flags, rgnOp);
    657         fWriter.writePath(path);
    658     }
    659     // we just pass on the bounds of the path
    660     return this->INHERITED::clipRect(path.getBounds(), rgnOp, doAntiAlias);
    661 }
    662 
    663 bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
    664     NOTIFY_SETUP(this);
    665     if (this->needOpBytes(region.writeToMemory(NULL))) {
    666         this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
    667         fWriter.writeRegion(region);
    668     }
    669     return this->INHERITED::clipRegion(region, rgnOp);
    670 }
    671 
    672 ///////////////////////////////////////////////////////////////////////////////
    673 
    674 void SkGPipeCanvas::clear(SkColor color) {
    675     NOTIFY_SETUP(this);
    676     unsigned flags = 0;
    677     if (color) {
    678         flags |= kClear_HasColor_DrawOpFlag;
    679     }
    680     if (this->needOpBytes(sizeof(SkColor))) {
    681         this->writeOp(kDrawClear_DrawOp, flags, 0);
    682         if (color) {
    683             fWriter.write32(color);
    684         }
    685     }
    686 }
    687 
    688 void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
    689     NOTIFY_SETUP(this);
    690     this->writePaint(paint);
    691     if (this->needOpBytes()) {
    692         this->writeOp(kDrawPaint_DrawOp);
    693     }
    694 }
    695 
    696 void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
    697                                    const SkPoint pts[], const SkPaint& paint) {
    698     if (count) {
    699         NOTIFY_SETUP(this);
    700         this->writePaint(paint);
    701         if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
    702             this->writeOp(kDrawPoints_DrawOp, mode, 0);
    703             fWriter.write32(count);
    704             fWriter.write(pts, count * sizeof(SkPoint));
    705         }
    706     }
    707 }
    708 
    709 void SkGPipeCanvas::drawOval(const SkRect& rect, const SkPaint& paint) {
    710     NOTIFY_SETUP(this);
    711     this->writePaint(paint);
    712     if (this->needOpBytes(sizeof(SkRect))) {
    713         this->writeOp(kDrawOval_DrawOp);
    714         fWriter.writeRect(rect);
    715     }
    716 }
    717 
    718 void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
    719     NOTIFY_SETUP(this);
    720     this->writePaint(paint);
    721     if (this->needOpBytes(sizeof(SkRect))) {
    722         this->writeOp(kDrawRect_DrawOp);
    723         fWriter.writeRect(rect);
    724     }
    725 }
    726 
    727 void SkGPipeCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
    728     NOTIFY_SETUP(this);
    729     this->writePaint(paint);
    730     if (this->needOpBytes(kSizeOfFlatRRect)) {
    731         this->writeOp(kDrawRRect_DrawOp);
    732         fWriter.writeRRect(rrect);
    733     }
    734 }
    735 
    736 void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
    737     NOTIFY_SETUP(this);
    738     this->writePaint(paint);
    739     if (this->needOpBytes(path.writeToMemory(NULL))) {
    740         this->writeOp(kDrawPath_DrawOp);
    741         fWriter.writePath(path);
    742     }
    743 }
    744 
    745 bool SkGPipeCanvas::commonDrawBitmap(const SkBitmap& bm, DrawOps op,
    746                                      unsigned flags,
    747                                      size_t opBytesNeeded,
    748                                      const SkPaint* paint) {
    749     if (paint != NULL) {
    750         flags |= kDrawBitmap_HasPaint_DrawOpFlag;
    751         this->writePaint(*paint);
    752     }
    753     if (this->needOpBytes(opBytesNeeded)) {
    754         SkASSERT(fBitmapHeap != NULL);
    755         int32_t bitmapIndex = fBitmapHeap->insert(bm);
    756         if (SkBitmapHeap::INVALID_SLOT == bitmapIndex) {
    757             return false;
    758         }
    759         this->writeOp(op, flags, bitmapIndex);
    760         return true;
    761     }
    762     return false;
    763 }
    764 
    765 void SkGPipeCanvas::drawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top,
    766                                const SkPaint* paint) {
    767     NOTIFY_SETUP(this);
    768     size_t opBytesNeeded = sizeof(SkScalar) * 2;
    769 
    770     if (this->commonDrawBitmap(bm, kDrawBitmap_DrawOp, 0, opBytesNeeded, paint)) {
    771         fWriter.writeScalar(left);
    772         fWriter.writeScalar(top);
    773     }
    774 }
    775 
    776 void SkGPipeCanvas::drawBitmapRectToRect(const SkBitmap& bm, const SkRect* src,
    777                                    const SkRect& dst, const SkPaint* paint) {
    778     NOTIFY_SETUP(this);
    779     size_t opBytesNeeded = sizeof(SkRect);
    780     bool hasSrc = src != NULL;
    781     unsigned flags;
    782     if (hasSrc) {
    783         flags = kDrawBitmap_HasSrcRect_DrawOpFlag;
    784         opBytesNeeded += sizeof(int32_t) * 4;
    785     } else {
    786         flags = 0;
    787     }
    788 
    789     if (this->commonDrawBitmap(bm, kDrawBitmapRectToRect_DrawOp, flags, opBytesNeeded, paint)) {
    790         if (hasSrc) {
    791             fWriter.writeRect(*src);
    792         }
    793         fWriter.writeRect(dst);
    794     }
    795 }
    796 
    797 void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap& bm, const SkMatrix& matrix,
    798                                      const SkPaint* paint) {
    799     NOTIFY_SETUP(this);
    800     size_t opBytesNeeded = matrix.writeToMemory(NULL);
    801 
    802     if (this->commonDrawBitmap(bm, kDrawBitmapMatrix_DrawOp, 0, opBytesNeeded, paint)) {
    803         fWriter.writeMatrix(matrix);
    804     }
    805 }
    806 
    807 void SkGPipeCanvas::drawBitmapNine(const SkBitmap& bm, const SkIRect& center,
    808                                    const SkRect& dst, const SkPaint* paint) {
    809     NOTIFY_SETUP(this);
    810     size_t opBytesNeeded = sizeof(int32_t) * 4 + sizeof(SkRect);
    811 
    812     if (this->commonDrawBitmap(bm, kDrawBitmapNine_DrawOp, 0, opBytesNeeded, paint)) {
    813         fWriter.write32(center.fLeft);
    814         fWriter.write32(center.fTop);
    815         fWriter.write32(center.fRight);
    816         fWriter.write32(center.fBottom);
    817         fWriter.writeRect(dst);
    818     }
    819 }
    820 
    821 void SkGPipeCanvas::drawSprite(const SkBitmap& bm, int left, int top,
    822                                    const SkPaint* paint) {
    823     NOTIFY_SETUP(this);
    824     size_t opBytesNeeded = sizeof(int32_t) * 2;
    825 
    826     if (this->commonDrawBitmap(bm, kDrawSprite_DrawOp, 0, opBytesNeeded, paint)) {
    827         fWriter.write32(left);
    828         fWriter.write32(top);
    829     }
    830 }
    831 
    832 void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
    833                                  SkScalar y, const SkPaint& paint) {
    834     if (byteLength) {
    835         NOTIFY_SETUP(this);
    836         this->writePaint(paint);
    837         if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
    838             this->writeOp(kDrawText_DrawOp);
    839             fWriter.write32(byteLength);
    840             fWriter.writePad(text, byteLength);
    841             fWriter.writeScalar(x);
    842             fWriter.writeScalar(y);
    843         }
    844     }
    845 }
    846 
    847 void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
    848                                 const SkPoint pos[], const SkPaint& paint) {
    849     if (byteLength) {
    850         NOTIFY_SETUP(this);
    851         this->writePaint(paint);
    852         int count = paint.textToGlyphs(text, byteLength, NULL);
    853         if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
    854             this->writeOp(kDrawPosText_DrawOp);
    855             fWriter.write32(byteLength);
    856             fWriter.writePad(text, byteLength);
    857             fWriter.write32(count);
    858             fWriter.write(pos, count * sizeof(SkPoint));
    859         }
    860     }
    861 }
    862 
    863 void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
    864                                  const SkScalar xpos[], SkScalar constY,
    865                                  const SkPaint& paint) {
    866     if (byteLength) {
    867         NOTIFY_SETUP(this);
    868         this->writePaint(paint);
    869         int count = paint.textToGlyphs(text, byteLength, NULL);
    870         if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
    871             this->writeOp(kDrawPosTextH_DrawOp);
    872             fWriter.write32(byteLength);
    873             fWriter.writePad(text, byteLength);
    874             fWriter.write32(count);
    875             fWriter.write(xpos, count * sizeof(SkScalar));
    876             fWriter.writeScalar(constY);
    877         }
    878     }
    879 }
    880 
    881 void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
    882                                    const SkPath& path, const SkMatrix* matrix,
    883                                    const SkPaint& paint) {
    884     if (byteLength) {
    885         NOTIFY_SETUP(this);
    886         unsigned flags = 0;
    887         size_t size = 4 + SkAlign4(byteLength) + path.writeToMemory(NULL);
    888         if (matrix) {
    889             flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
    890             size += matrix->writeToMemory(NULL);
    891         }
    892         this->writePaint(paint);
    893         if (this->needOpBytes(size)) {
    894             this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
    895 
    896             fWriter.write32(byteLength);
    897             fWriter.writePad(text, byteLength);
    898 
    899             fWriter.writePath(path);
    900             if (matrix) {
    901                 fWriter.writeMatrix(*matrix);
    902             }
    903         }
    904     }
    905 }
    906 
    907 void SkGPipeCanvas::drawPicture(SkPicture& picture) {
    908     // we want to playback the picture into individual draw calls
    909     this->INHERITED::drawPicture(picture);
    910 }
    911 
    912 void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
    913                                  const SkPoint vertices[], const SkPoint texs[],
    914                                  const SkColor colors[], SkXfermode*,
    915                                  const uint16_t indices[], int indexCount,
    916                                  const SkPaint& paint) {
    917     if (0 == vertexCount) {
    918         return;
    919     }
    920 
    921     NOTIFY_SETUP(this);
    922     size_t size = 4 + vertexCount * sizeof(SkPoint);
    923     this->writePaint(paint);
    924     unsigned flags = 0;
    925     if (texs) {
    926         flags |= kDrawVertices_HasTexs_DrawOpFlag;
    927         size += vertexCount * sizeof(SkPoint);
    928     }
    929     if (colors) {
    930         flags |= kDrawVertices_HasColors_DrawOpFlag;
    931         size += vertexCount * sizeof(SkColor);
    932     }
    933     if (indices && indexCount > 0) {
    934         flags |= kDrawVertices_HasIndices_DrawOpFlag;
    935         size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
    936     }
    937 
    938     if (this->needOpBytes(size)) {
    939         this->writeOp(kDrawVertices_DrawOp, flags, 0);
    940         fWriter.write32(mode);
    941         fWriter.write32(vertexCount);
    942         fWriter.write(vertices, vertexCount * sizeof(SkPoint));
    943         if (texs) {
    944             fWriter.write(texs, vertexCount * sizeof(SkPoint));
    945         }
    946         if (colors) {
    947             fWriter.write(colors, vertexCount * sizeof(SkColor));
    948         }
    949 
    950         // TODO: flatten xfermode
    951 
    952         if (indices && indexCount > 0) {
    953             fWriter.write32(indexCount);
    954             fWriter.writePad(indices, indexCount * sizeof(uint16_t));
    955         }
    956     }
    957 }
    958 
    959 void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
    960     if (size && ptr) {
    961         NOTIFY_SETUP(this);
    962         unsigned data = 0;
    963         if (size < (1 << DRAWOPS_DATA_BITS)) {
    964             data = (unsigned)size;
    965         }
    966         if (this->needOpBytes(4 + SkAlign4(size))) {
    967             this->writeOp(kDrawData_DrawOp, 0, data);
    968             if (0 == data) {
    969                 fWriter.write32(size);
    970             }
    971             fWriter.writePad(ptr, size);
    972         }
    973     }
    974 }
    975 
    976 void SkGPipeCanvas::beginCommentGroup(const char* description) {
    977     // ignore for now
    978 }
    979 
    980 void SkGPipeCanvas::addComment(const char* kywd, const char* value) {
    981     // ignore for now
    982 }
    983 
    984 void SkGPipeCanvas::endCommentGroup() {
    985     // ignore for now
    986 }
    987 
    988 void SkGPipeCanvas::flushRecording(bool detachCurrentBlock) {
    989     doNotify();
    990     if (detachCurrentBlock) {
    991         // force a new block to be requested for the next recorded command
    992         fBlockSize = 0;
    993     }
    994 }
    995 
    996 size_t SkGPipeCanvas::freeMemoryIfPossible(size_t bytesToFree) {
    997     return (NULL == fBitmapHeap) ? 0 : fBitmapHeap->freeMemoryIfPossible(bytesToFree);
    998 }
    999 
   1000 ///////////////////////////////////////////////////////////////////////////////
   1001 
   1002 template <typename T> uint32_t castToU32(T value) {
   1003     union {
   1004         T           fSrc;
   1005         uint32_t    fDst;
   1006     } data;
   1007     data.fSrc = value;
   1008     return data.fDst;
   1009 }
   1010 
   1011 void SkGPipeCanvas::writePaint(const SkPaint& paint) {
   1012     if (fDone) {
   1013         return;
   1014     }
   1015     SkPaint& base = fPaint;
   1016     uint32_t storage[32];
   1017     uint32_t* ptr = storage;
   1018 
   1019     if (base.getFlags() != paint.getFlags()) {
   1020         *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
   1021         base.setFlags(paint.getFlags());
   1022     }
   1023     if (base.getColor() != paint.getColor()) {
   1024         *ptr++ = PaintOp_packOp(kColor_PaintOp);
   1025         *ptr++ = paint.getColor();
   1026         base.setColor(paint.getColor());
   1027     }
   1028     if (base.getStyle() != paint.getStyle()) {
   1029         *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
   1030         base.setStyle(paint.getStyle());
   1031     }
   1032     if (base.getStrokeJoin() != paint.getStrokeJoin()) {
   1033         *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
   1034         base.setStrokeJoin(paint.getStrokeJoin());
   1035     }
   1036     if (base.getStrokeCap() != paint.getStrokeCap()) {
   1037         *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
   1038         base.setStrokeCap(paint.getStrokeCap());
   1039     }
   1040     if (base.getStrokeWidth() != paint.getStrokeWidth()) {
   1041         *ptr++ = PaintOp_packOp(kWidth_PaintOp);
   1042         *ptr++ = castToU32(paint.getStrokeWidth());
   1043         base.setStrokeWidth(paint.getStrokeWidth());
   1044     }
   1045     if (base.getStrokeMiter() != paint.getStrokeMiter()) {
   1046         *ptr++ = PaintOp_packOp(kMiter_PaintOp);
   1047         *ptr++ = castToU32(paint.getStrokeMiter());
   1048         base.setStrokeMiter(paint.getStrokeMiter());
   1049     }
   1050     if (base.getTextEncoding() != paint.getTextEncoding()) {
   1051         *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
   1052         base.setTextEncoding(paint.getTextEncoding());
   1053     }
   1054     if (base.getHinting() != paint.getHinting()) {
   1055         *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
   1056         base.setHinting(paint.getHinting());
   1057     }
   1058     if (base.getTextAlign() != paint.getTextAlign()) {
   1059         *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
   1060         base.setTextAlign(paint.getTextAlign());
   1061     }
   1062     if (base.getTextSize() != paint.getTextSize()) {
   1063         *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
   1064         *ptr++ = castToU32(paint.getTextSize());
   1065         base.setTextSize(paint.getTextSize());
   1066     }
   1067     if (base.getTextScaleX() != paint.getTextScaleX()) {
   1068         *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
   1069         *ptr++ = castToU32(paint.getTextScaleX());
   1070         base.setTextScaleX(paint.getTextScaleX());
   1071     }
   1072     if (base.getTextSkewX() != paint.getTextSkewX()) {
   1073         *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
   1074         *ptr++ = castToU32(paint.getTextSkewX());
   1075         base.setTextSkewX(paint.getTextSkewX());
   1076     }
   1077 
   1078     if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
   1079         if (isCrossProcess(fFlags)) {
   1080             uint32_t id = this->getTypefaceID(paint.getTypeface());
   1081             *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
   1082         } else if (this->needOpBytes(sizeof(void*))) {
   1083             // Add to the set for ref counting.
   1084             fTypefaceSet.add(paint.getTypeface());
   1085             // It is safe to write the typeface to the stream before the rest
   1086             // of the paint unless we ever send a kReset_PaintOp, which we
   1087             // currently never do.
   1088             this->writeOp(kSetTypeface_DrawOp);
   1089             fWriter.writePtr(paint.getTypeface());
   1090         }
   1091         base.setTypeface(paint.getTypeface());
   1092     }
   1093 
   1094     // This is a new paint, so all old flats can be safely purged, if necessary.
   1095     fFlattenableHeap.markAllFlatsSafeToDelete();
   1096     for (int i = 0; i < kCount_PaintFlats; i++) {
   1097         int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
   1098         bool replaced = index < 0;
   1099         if (replaced) {
   1100             index = ~index;
   1101         }
   1102         // Store the index of any flat that needs to be kept. 0 means no flat.
   1103         if (index > 0) {
   1104             fFlattenableHeap.markFlatForKeeping(index);
   1105         }
   1106         SkASSERT(index >= 0 && index <= fFlatDictionary.count());
   1107         if (index != fCurrFlatIndex[i] || replaced) {
   1108             *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
   1109             fCurrFlatIndex[i] = index;
   1110         }
   1111     }
   1112 
   1113     size_t size = (char*)ptr - (char*)storage;
   1114     if (size && this->needOpBytes(size)) {
   1115         this->writeOp(kPaintOp_DrawOp, 0, size);
   1116         fWriter.write(storage, size);
   1117         for (size_t i = 0; i < size/4; i++) {
   1118 //            SkDebugf("[%d] %08X\n", i, storage[i]);
   1119         }
   1120     }
   1121 }
   1122 
   1123 ///////////////////////////////////////////////////////////////////////////////
   1124 
   1125 #include "SkGPipe.h"
   1126 
   1127 SkGPipeController::~SkGPipeController() {
   1128     SkSafeUnref(fCanvas);
   1129 }
   1130 
   1131 void SkGPipeController::setCanvas(SkGPipeCanvas* canvas) {
   1132     SkRefCnt_SafeAssign(fCanvas, canvas);
   1133 }
   1134 
   1135 ///////////////////////////////////////////////////////////////////////////////
   1136 
   1137 SkGPipeWriter::SkGPipeWriter()
   1138 : fWriter(0) {
   1139     fCanvas = NULL;
   1140 }
   1141 
   1142 SkGPipeWriter::~SkGPipeWriter() {
   1143     this->endRecording();
   1144 }
   1145 
   1146 SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t flags,
   1147                                         uint32_t width, uint32_t height) {
   1148     if (NULL == fCanvas) {
   1149         fWriter.reset(NULL, 0);
   1150         fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter, flags, width, height));
   1151     }
   1152     controller->setCanvas(fCanvas);
   1153     return fCanvas;
   1154 }
   1155 
   1156 void SkGPipeWriter::endRecording() {
   1157     if (fCanvas) {
   1158         fCanvas->finish();
   1159         fCanvas->unref();
   1160         fCanvas = NULL;
   1161     }
   1162 }
   1163 
   1164 void SkGPipeWriter::flushRecording(bool detachCurrentBlock) {
   1165     if (fCanvas) {
   1166         fCanvas->flushRecording(detachCurrentBlock);
   1167     }
   1168 }
   1169 
   1170 size_t SkGPipeWriter::freeMemoryIfPossible(size_t bytesToFree) {
   1171     if (fCanvas) {
   1172         return fCanvas->freeMemoryIfPossible(bytesToFree);
   1173     }
   1174     return 0;
   1175 }
   1176 
   1177 size_t SkGPipeWriter::storageAllocatedForRecording() const {
   1178     return NULL == fCanvas ? 0 : fCanvas->storageAllocatedForRecording();
   1179 }
   1180 
   1181 ///////////////////////////////////////////////////////////////////////////////
   1182 
   1183 BitmapShuttle::BitmapShuttle(SkGPipeCanvas* canvas) {
   1184     SkASSERT(canvas != NULL);
   1185     fCanvas = canvas;
   1186     fCanvas->ref();
   1187 }
   1188 
   1189 BitmapShuttle::~BitmapShuttle() {
   1190     fCanvas->unref();
   1191 }
   1192 
   1193 bool BitmapShuttle::insert(const SkBitmap& bitmap, int32_t slot) {
   1194     return fCanvas->shuttleBitmap(bitmap, slot);
   1195 }
   1196