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