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