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