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 "SkWriteBuffer.h"
21#include "SkPaint.h"
22#include "SkPatchUtils.h"
23#include "SkPathEffect.h"
24#include "SkPictureFlat.h"
25#include "SkPtrRecorder.h"
26#include "SkRasterizer.h"
27#include "SkRRect.h"
28#include "SkShader.h"
29#include "SkStream.h"
30#include "SkTextBlob.h"
31#include "SkTSearch.h"
32#include "SkTypeface.h"
33#include "SkWriter32.h"
34
35enum {
36    kSizeOfFlatRRect = sizeof(SkRect) + 4 * sizeof(SkVector)
37};
38
39static bool is_cross_process(uint32_t flags) {
40    return SkToBool(flags & SkGPipeWriter::kCrossProcess_Flag);
41}
42
43static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
44    SkASSERT(paintFlat < kCount_PaintFlats);
45    switch (paintFlat) {
46        case kColorFilter_PaintFlat:    return paint.getColorFilter();
47        case kDrawLooper_PaintFlat:     return paint.getLooper();
48        case kMaskFilter_PaintFlat:     return paint.getMaskFilter();
49        case kPathEffect_PaintFlat:     return paint.getPathEffect();
50        case kRasterizer_PaintFlat:     return paint.getRasterizer();
51        case kShader_PaintFlat:         return paint.getShader();
52        case kImageFilter_PaintFlat:    return paint.getImageFilter();
53        case kXfermode_PaintFlat:       return paint.getXfermode();
54    }
55    SkDEBUGFAIL("never gets here");
56    return NULL;
57}
58
59static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
60    SkASSERT(typeface);
61    SkDynamicMemoryWStream stream;
62    typeface->serialize(&stream);
63    size_t size = stream.getOffset();
64    if (writer) {
65        writer->write32(SkToU32(size));
66        SkAutoDataUnref data(stream.copyToData());
67        writer->writePad(data->data(), size);
68    }
69    return 4 + SkAlign4(size);
70}
71
72///////////////////////////////////////////////////////////////////////////////
73
74class FlattenableHeap : public SkFlatController {
75public:
76    FlattenableHeap(int numFlatsToKeep, SkNamedFactorySet* fset, bool isCrossProcess)
77    : INHERITED(isCrossProcess ? SkWriteBuffer::kCrossProcess_Flag : 0)
78    , fNumFlatsToKeep(numFlatsToKeep) {
79        SkASSERT((isCrossProcess && fset != NULL) || (!isCrossProcess && NULL == fset));
80        if (isCrossProcess) {
81            this->setNamedFactorySet(fset);
82        }
83    }
84
85    ~FlattenableHeap() {
86        fPointers.freeAll();
87    }
88
89    void* allocThrow(size_t bytes) override;
90
91    void unalloc(void* ptr) override;
92
93    void setBitmapStorage(SkBitmapHeap* heap) {
94        this->setBitmapHeap(heap);
95    }
96
97    const SkFlatData* flatToReplace() const;
98
99    // Mark an SkFlatData as one that should not be returned by flatToReplace.
100    // Takes the result of SkFlatData::index() as its parameter.
101    void markFlatForKeeping(int index) {
102        *fFlatsThatMustBeKept.append() = index;
103    }
104
105    void markAllFlatsSafeToDelete() {
106        fFlatsThatMustBeKept.reset();
107    }
108
109private:
110    // Keep track of the indices (i.e. the result of SkFlatData::index()) of
111    // flats that must be kept, since they are on the current paint.
112    SkTDArray<int>   fFlatsThatMustBeKept;
113    SkTDArray<void*> fPointers;
114    const int        fNumFlatsToKeep;
115
116    typedef SkFlatController INHERITED;
117};
118
119void FlattenableHeap::unalloc(void* ptr) {
120    int indexToRemove = fPointers.rfind(ptr);
121    if (indexToRemove >= 0) {
122        sk_free(ptr);
123        fPointers.remove(indexToRemove);
124    }
125}
126
127void* FlattenableHeap::allocThrow(size_t bytes) {
128    void* ptr = sk_malloc_throw(bytes);
129    *fPointers.append() = ptr;
130    return ptr;
131}
132
133const SkFlatData* FlattenableHeap::flatToReplace() const {
134    // First, determine whether we should replace one.
135    if (fPointers.count() > fNumFlatsToKeep) {
136        // Look through the flattenable heap.
137        // TODO: Return the LRU flat.
138        for (int i = 0; i < fPointers.count(); i++) {
139            SkFlatData* potential = (SkFlatData*)fPointers[i];
140            // Make sure that it is not one that must be kept.
141            bool mustKeep = false;
142            for (int j = 0; j < fFlatsThatMustBeKept.count(); j++) {
143                if (potential->index() == fFlatsThatMustBeKept[j]) {
144                    mustKeep = true;
145                    break;
146                }
147            }
148            if (!mustKeep) {
149                return potential;
150            }
151        }
152    }
153    return NULL;
154}
155
156///////////////////////////////////////////////////////////////////////////////
157
158struct SkFlattenableTraits {
159    static void Flatten(SkWriteBuffer& buffer, const SkFlattenable& flattenable) {
160        buffer.writeFlattenable(&flattenable);
161    }
162    // No need to define unflatten if we never call it.
163};
164typedef SkFlatDictionary<SkFlattenable, SkFlattenableTraits> FlatDictionary;
165
166///////////////////////////////////////////////////////////////////////////////
167
168/**
169 * If SkBitmaps are to be flattened to send to the reader, this class is
170 * provided to the SkBitmapHeap to tell the SkGPipeCanvas to do so.
171 */
172class BitmapShuttle : public SkBitmapHeap::ExternalStorage {
173public:
174    BitmapShuttle(SkGPipeCanvas*);
175
176    ~BitmapShuttle();
177
178    bool insert(const SkBitmap& bitmap, int32_t slot) override;
179
180    /**
181     *  Remove the SkGPipeCanvas used for insertion. After this, calls to
182     *  insert will crash.
183     */
184    void removeCanvas();
185
186private:
187    SkGPipeCanvas*    fCanvas;
188};
189
190///////////////////////////////////////////////////////////////////////////////
191
192class SkGPipeCanvas : public SkCanvas {
193public:
194    SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags,
195                  uint32_t width, uint32_t height);
196    virtual ~SkGPipeCanvas();
197
198    /**
199     *  Called when nothing else is to be written to the stream. Any repeated
200     *  calls are ignored.
201     *
202     *  @param notifyReaders Whether to send a message to the reader(s) that
203     *      the writer is through sending commands. Should generally be true,
204     *      unless there is an error which prevents further messages from
205     *      being sent.
206     */
207    void finish(bool notifyReaders) {
208        if (fDone) {
209            return;
210        }
211        if (notifyReaders && this->needOpBytes()) {
212            this->writeOp(kDone_DrawOp);
213            this->doNotify();
214        }
215        if (shouldFlattenBitmaps(fFlags)) {
216            // The following circular references exist:
217            // fFlattenableHeap -> fWriteBuffer -> fBitmapStorage -> fExternalStorage -> fCanvas
218            // fBitmapHeap -> fExternalStorage -> fCanvas
219            // fFlattenableHeap -> fBitmapStorage -> fExternalStorage -> fCanvas
220
221            // Break them all by destroying the final link to this SkGPipeCanvas.
222            fBitmapShuttle->removeCanvas();
223        }
224        fDone = true;
225    }
226
227    void flushRecording(bool detachCurrentBlock);
228    size_t freeMemoryIfPossible(size_t bytesToFree);
229
230    size_t storageAllocatedForRecording() {
231        return (NULL == fBitmapHeap) ? 0 : fBitmapHeap->bytesAllocated();
232    }
233
234    void beginCommentGroup(const char* description) override;
235    void addComment(const char* kywd, const char* value) override;
236    void endCommentGroup() override;
237
238    /**
239     * Flatten an SkBitmap to send to the reader, where it will be referenced
240     * according to slot.
241     */
242    bool shuttleBitmap(const SkBitmap&, int32_t slot);
243
244protected:
245    void willSave() override;
246    SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) override;
247    void willRestore() override;
248
249    void didConcat(const SkMatrix&) override;
250    void didSetMatrix(const SkMatrix&) override;
251
252    void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
253    void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
254                    const SkPaint&) override;
255    void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
256                       const SkPaint&) override;
257    void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
258                        SkScalar constY, const SkPaint&) override;
259    void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
260                          const SkMatrix* matrix, const SkPaint&) override;
261    void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
262                        const SkPaint& paint) override;
263    void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
264                     const SkPoint texCoords[4], SkXfermode* xmode,
265                     const SkPaint& paint) override;
266    void onDrawPaint(const SkPaint&) override;
267    void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
268    void onDrawRect(const SkRect&, const SkPaint&) override;
269    void onDrawOval(const SkRect&, const SkPaint&) override;
270    void onDrawRRect(const SkRRect&, const SkPaint&) override;
271    void onDrawPath(const SkPath&, const SkPaint&) override;
272    void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override;
273    void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
274                          DrawBitmapRectFlags flags) override;
275    void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override;
276    void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
277                         const SkPaint*) override;
278    void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
279                          const SkPaint*) override;
280    void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override;
281    void onDrawVertices(VertexMode vmode, int vertexCount,
282                        const SkPoint vertices[], const SkPoint texs[],
283                        const SkColor colors[], SkXfermode* xmode,
284                        const uint16_t indices[], int indexCount,
285                        const SkPaint&) override;
286    void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
287    void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
288    void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override;
289    void onClipRegion(const SkRegion&, SkRegion::Op) override;
290
291    void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
292
293private:
294    void recordTranslate(const SkMatrix&);
295    void recordScale(const SkMatrix&);
296    void recordConcat(const SkMatrix&);
297
298    SkNamedFactorySet* fFactorySet;
299    SkBitmapHeap*      fBitmapHeap;
300    SkImageHeap*       fImageHeap;
301    SkGPipeController* fController;
302    SkWriter32&        fWriter;
303    size_t             fBlockSize; // amount allocated for writer
304    size_t             fBytesNotified;
305    bool               fDone;
306    const uint32_t     fFlags;
307
308    SkRefCntSet        fTypefaceSet;
309
310    uint32_t getTypefaceID(SkTypeface*);
311
312    inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
313        fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
314    }
315
316    inline void writeOp(DrawOps op) {
317        fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
318    }
319
320    bool needOpBytes(size_t size = 0);
321
322    inline void doNotify() {
323        if (!fDone) {
324            size_t bytes = fWriter.bytesWritten() - fBytesNotified;
325            if (bytes > 0) {
326                fController->notifyWritten(bytes);
327                fBytesNotified += bytes;
328            }
329        }
330    }
331
332    typedef SkAutoSTMalloc<128, uint8_t> TypefaceBuffer;
333    size_t getInProcessTypefaces(const SkRefCntSet& typefaceSet, TypefaceBuffer*);
334    size_t getCrossProcessTypefaces(const SkRefCntSet& typefaceSet, TypefaceBuffer*);
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&, DrawOps, unsigned flags, size_t bytes, const SkPaint*);
350    bool commonDrawImage(const SkImage*, DrawOps, unsigned flags, size_t bytes, const SkPaint*);
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
367void SkGPipeCanvas::flattenFactoryNames() {
368    const char* name;
369    while ((name = fFactorySet->getNextAddedFactoryName()) != NULL) {
370        size_t len = strlen(name);
371        if (this->needOpBytes(SkWriter32::WriteStringSize(name, len))) {
372            this->writeOp(kDef_Factory_DrawOp);
373            fWriter.writeString(name, len);
374        }
375    }
376}
377
378bool SkGPipeCanvas::shuttleBitmap(const SkBitmap& bm, int32_t slot) {
379    SkASSERT(shouldFlattenBitmaps(fFlags));
380    SkWriteBuffer buffer;
381    buffer.setNamedFactoryRecorder(fFactorySet);
382    buffer.writeBitmap(bm);
383    this->flattenFactoryNames();
384    size_t size = buffer.bytesWritten();
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
396int 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 (is_cross_process(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
430SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
431                             SkWriter32* writer, uint32_t flags,
432                             uint32_t width, uint32_t height)
433    : SkCanvas(width, height)
434    , fFactorySet(is_cross_process(flags) ? SkNEW(SkNamedFactorySet) : NULL)
435    , fWriter(*writer)
436    , fFlags(flags)
437    , fFlattenableHeap(FLATTENABLES_TO_KEEP, fFactorySet, is_cross_process(flags))
438    , fFlatDictionary(&fFlattenableHeap)
439{
440    fController = controller;
441    fDone = false;
442    fBlockSize = 0; // need first block from controller
443    fBytesNotified = 0;
444    sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
445
446    // Tell the reader the appropriate flags to use.
447    if (this->needOpBytes()) {
448        this->writeOp(kReportFlags_DrawOp, fFlags, 0);
449    }
450
451    if (shouldFlattenBitmaps(flags)) {
452        fBitmapShuttle.reset(SkNEW_ARGS(BitmapShuttle, (this)));
453        fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, (fBitmapShuttle.get(), BITMAPS_TO_KEEP));
454    } else {
455        fBitmapHeap = SkNEW_ARGS(SkBitmapHeap,
456                                 (BITMAPS_TO_KEEP, controller->numberOfReaders()));
457        if (this->needOpBytes(sizeof(void*))) {
458            this->writeOp(kShareBitmapHeap_DrawOp);
459            fWriter.writePtr(static_cast<void*>(fBitmapHeap));
460        }
461    }
462    fFlattenableHeap.setBitmapStorage(fBitmapHeap);
463
464    fImageHeap = SkNEW(SkImageHeap);
465    if (this->needOpBytes(sizeof(void*))) {
466        this->writeOp(kShareImageHeap_DrawOp);
467        fWriter.writePtr(static_cast<void*>(fImageHeap));
468    }
469
470    this->doNotify();
471}
472
473SkGPipeCanvas::~SkGPipeCanvas() {
474    this->finish(true);
475    SkSafeUnref(fFactorySet);
476    SkSafeUnref(fBitmapHeap);
477    SkSafeUnref(fImageHeap);
478}
479
480bool SkGPipeCanvas::needOpBytes(size_t needed) {
481    if (fDone) {
482        return false;
483    }
484
485    needed += 4;  // size of DrawOp atom
486    needed = SkAlign4(needed);
487    if (fWriter.bytesWritten() + needed > fBlockSize) {
488        // Before we wipe out any data that has already been written, read it out.
489        this->doNotify();
490
491        // If we're going to allocate a new block, allocate enough to make it worthwhile.
492        needed = SkTMax<size_t>(MIN_BLOCK_SIZE, needed);
493
494        void* block = fController->requestBlock(needed, &fBlockSize);
495        if (NULL == block) {
496            // Do not notify the readers, which would call this function again.
497            this->finish(false);
498            return false;
499        }
500        SkASSERT(SkIsAlign4(fBlockSize));
501        fWriter.reset(block, fBlockSize);
502        fBytesNotified = 0;
503    }
504    return true;
505}
506
507uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
508    uint32_t id = 0; // 0 means default/null typeface
509    if (face) {
510        id = fTypefaceSet.find(face);
511        if (0 == id) {
512            id = fTypefaceSet.add(face);
513            size_t size = writeTypeface(NULL, face);
514            if (this->needOpBytes(size)) {
515                this->writeOp(kDef_Typeface_DrawOp);
516                writeTypeface(&fWriter, face);
517            }
518        }
519    }
520    return id;
521}
522
523///////////////////////////////////////////////////////////////////////////////
524
525#define NOTIFY_SETUP(canvas)    \
526    AutoPipeNotify apn(canvas)
527
528void SkGPipeCanvas::willSave() {
529    NOTIFY_SETUP(this);
530    if (this->needOpBytes()) {
531        this->writeOp(kSave_DrawOp);
532    }
533
534    this->INHERITED::willSave();
535}
536
537SkCanvas::SaveLayerStrategy SkGPipeCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint,
538                                                         SaveFlags saveFlags) {
539    NOTIFY_SETUP(this);
540    size_t size = 0;
541    unsigned opFlags = 0;
542
543    if (bounds) {
544        opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
545        size += sizeof(SkRect);
546    }
547    if (paint) {
548        opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
549        this->writePaint(*paint);
550    }
551
552    if (this->needOpBytes(size)) {
553        this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
554        if (bounds) {
555            fWriter.writeRect(*bounds);
556        }
557    }
558
559    this->INHERITED::willSaveLayer(bounds, paint, saveFlags);
560    // we don't create a layer
561    return kNoLayer_SaveLayerStrategy;
562}
563
564void SkGPipeCanvas::willRestore() {
565    NOTIFY_SETUP(this);
566    if (this->needOpBytes()) {
567        this->writeOp(kRestore_DrawOp);
568    }
569
570    this->INHERITED::willRestore();
571}
572
573void SkGPipeCanvas::recordTranslate(const SkMatrix& m) {
574    if (this->needOpBytes(2 * sizeof(SkScalar))) {
575        this->writeOp(kTranslate_DrawOp);
576        fWriter.writeScalar(m.getTranslateX());
577        fWriter.writeScalar(m.getTranslateY());
578    }
579}
580
581void SkGPipeCanvas::recordScale(const SkMatrix& m) {
582    if (this->needOpBytes(2 * sizeof(SkScalar))) {
583        this->writeOp(kScale_DrawOp);
584        fWriter.writeScalar(m.getScaleX());
585        fWriter.writeScalar(m.getScaleY());
586    }
587}
588
589void SkGPipeCanvas::recordConcat(const SkMatrix& m) {
590    if (this->needOpBytes(m.writeToMemory(NULL))) {
591        this->writeOp(kConcat_DrawOp);
592        fWriter.writeMatrix(m);
593    }
594}
595
596void SkGPipeCanvas::didConcat(const SkMatrix& matrix) {
597    if (!matrix.isIdentity()) {
598        NOTIFY_SETUP(this);
599        switch (matrix.getType()) {
600            case SkMatrix::kTranslate_Mask:
601                this->recordTranslate(matrix);
602                break;
603            case SkMatrix::kScale_Mask:
604                this->recordScale(matrix);
605                break;
606            default:
607                this->recordConcat(matrix);
608                break;
609        }
610    }
611
612    this->INHERITED::didConcat(matrix);
613}
614
615void SkGPipeCanvas::didSetMatrix(const SkMatrix& matrix) {
616    NOTIFY_SETUP(this);
617    if (this->needOpBytes(matrix.writeToMemory(NULL))) {
618        this->writeOp(kSetMatrix_DrawOp);
619        fWriter.writeMatrix(matrix);
620    }
621    this->INHERITED::didSetMatrix(matrix);
622}
623
624void SkGPipeCanvas::onClipRect(const SkRect& rect, SkRegion::Op rgnOp,
625                               ClipEdgeStyle edgeStyle) {
626    NOTIFY_SETUP(this);
627    if (this->needOpBytes(sizeof(SkRect))) {
628        unsigned flags = 0;
629        if (kSoft_ClipEdgeStyle == edgeStyle) {
630            flags = kClip_HasAntiAlias_DrawOpFlag;
631        }
632        this->writeOp(kClipRect_DrawOp, flags, rgnOp);
633        fWriter.writeRect(rect);
634    }
635    this->INHERITED::onClipRect(rect, rgnOp, edgeStyle);
636}
637
638void SkGPipeCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op rgnOp,
639                                ClipEdgeStyle edgeStyle) {
640    NOTIFY_SETUP(this);
641    if (this->needOpBytes(kSizeOfFlatRRect)) {
642        unsigned flags = 0;
643        if (kSoft_ClipEdgeStyle == edgeStyle) {
644            flags = kClip_HasAntiAlias_DrawOpFlag;
645        }
646        this->writeOp(kClipRRect_DrawOp, flags, rgnOp);
647        fWriter.writeRRect(rrect);
648    }
649    this->INHERITED::onClipRRect(rrect, rgnOp, edgeStyle);
650}
651
652void SkGPipeCanvas::onClipPath(const SkPath& path, SkRegion::Op rgnOp,
653                               ClipEdgeStyle edgeStyle) {
654    NOTIFY_SETUP(this);
655    if (this->needOpBytes(path.writeToMemory(NULL))) {
656        unsigned flags = 0;
657        if (kSoft_ClipEdgeStyle == edgeStyle) {
658            flags = kClip_HasAntiAlias_DrawOpFlag;
659        }
660        this->writeOp(kClipPath_DrawOp, flags, rgnOp);
661        fWriter.writePath(path);
662    }
663    // we just pass on the bounds of the path
664    this->INHERITED::onClipRect(path.getBounds(), rgnOp, edgeStyle);
665}
666
667void SkGPipeCanvas::onClipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
668    NOTIFY_SETUP(this);
669    if (this->needOpBytes(region.writeToMemory(NULL))) {
670        this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
671        fWriter.writeRegion(region);
672    }
673    this->INHERITED::onClipRegion(region, rgnOp);
674}
675
676///////////////////////////////////////////////////////////////////////////////
677
678void SkGPipeCanvas::onDrawPaint(const SkPaint& paint) {
679    NOTIFY_SETUP(this);
680    this->writePaint(paint);
681    if (this->needOpBytes()) {
682        this->writeOp(kDrawPaint_DrawOp);
683    }
684}
685
686void SkGPipeCanvas::onDrawPoints(PointMode mode, size_t count,
687                                 const SkPoint pts[], const SkPaint& paint) {
688    if (count) {
689        NOTIFY_SETUP(this);
690        this->writePaint(paint);
691        if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
692            this->writeOp(kDrawPoints_DrawOp, mode, 0);
693            fWriter.write32(SkToU32(count));
694            fWriter.write(pts, count * sizeof(SkPoint));
695        }
696    }
697}
698
699void SkGPipeCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) {
700    NOTIFY_SETUP(this);
701    this->writePaint(paint);
702    if (this->needOpBytes(sizeof(SkRect))) {
703        this->writeOp(kDrawOval_DrawOp);
704        fWriter.writeRect(rect);
705    }
706}
707
708void SkGPipeCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
709    NOTIFY_SETUP(this);
710    this->writePaint(paint);
711    if (this->needOpBytes(sizeof(SkRect))) {
712        this->writeOp(kDrawRect_DrawOp);
713        fWriter.writeRect(rect);
714    }
715}
716
717void SkGPipeCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
718    NOTIFY_SETUP(this);
719    this->writePaint(paint);
720    if (this->needOpBytes(kSizeOfFlatRRect)) {
721        this->writeOp(kDrawRRect_DrawOp);
722        fWriter.writeRRect(rrect);
723    }
724}
725
726void SkGPipeCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
727                                 const SkPaint& paint) {
728    NOTIFY_SETUP(this);
729    this->writePaint(paint);
730    if (this->needOpBytes(kSizeOfFlatRRect * 2)) {
731        this->writeOp(kDrawDRRect_DrawOp);
732        fWriter.writeRRect(outer);
733        fWriter.writeRRect(inner);
734    }
735}
736
737void SkGPipeCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
738    NOTIFY_SETUP(this);
739    this->writePaint(paint);
740    if (this->needOpBytes(path.writeToMemory(NULL))) {
741        this->writeOp(kDrawPath_DrawOp);
742        fWriter.writePath(path);
743    }
744}
745
746bool SkGPipeCanvas::commonDrawBitmap(const SkBitmap& bm, DrawOps op,
747                                     unsigned flags,
748                                     size_t opBytesNeeded,
749                                     const SkPaint* paint) {
750    if (fDone) {
751        return false;
752    }
753
754    if (paint != NULL) {
755        flags |= kDrawBitmap_HasPaint_DrawOpFlag;
756        this->writePaint(*paint);
757    }
758    // This needs to run first so its calls to needOpBytes() and its writes
759    // don't interlace with the needOpBytes() and write below.
760    SkASSERT(fBitmapHeap != NULL);
761    int32_t bitmapIndex = fBitmapHeap->insert(bm);
762    if (SkBitmapHeap::INVALID_SLOT == bitmapIndex) {
763        return false;
764    }
765
766    if (this->needOpBytes(opBytesNeeded)) {
767        this->writeOp(op, flags, bitmapIndex);
768        return true;
769    }
770    return false;
771}
772
773void SkGPipeCanvas::onDrawBitmap(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::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst,
785                                     const SkPaint* paint, DrawBitmapRectFlags dbmrFlags) {
786    NOTIFY_SETUP(this);
787    size_t opBytesNeeded = sizeof(SkRect);
788    bool hasSrc = src != NULL;
789    unsigned flags;
790    if (hasSrc) {
791        flags = kDrawBitmap_HasSrcRect_DrawOpFlag;
792        opBytesNeeded += sizeof(int32_t) * 4;
793    } else {
794        flags = 0;
795    }
796    if (dbmrFlags & kBleed_DrawBitmapRectFlag) {
797        flags |= kDrawBitmap_Bleed_DrawOpFlag;
798    }
799
800    if (this->commonDrawBitmap(bm, kDrawBitmapRectToRect_DrawOp, flags, opBytesNeeded, paint)) {
801        if (hasSrc) {
802            fWriter.writeRect(*src);
803        }
804        fWriter.writeRect(dst);
805    }
806}
807
808void SkGPipeCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center,
809                                     const SkRect& dst, const SkPaint* paint) {
810    NOTIFY_SETUP(this);
811    size_t opBytesNeeded = sizeof(int32_t) * 4 + sizeof(SkRect);
812
813    if (this->commonDrawBitmap(bm, kDrawBitmapNine_DrawOp, 0, opBytesNeeded, paint)) {
814        fWriter.write32(center.fLeft);
815        fWriter.write32(center.fTop);
816        fWriter.write32(center.fRight);
817        fWriter.write32(center.fBottom);
818        fWriter.writeRect(dst);
819    }
820}
821
822void SkGPipeCanvas::onDrawSprite(const SkBitmap& bm, int left, int top, const SkPaint* paint) {
823    NOTIFY_SETUP(this);
824    size_t opBytesNeeded = sizeof(int32_t) * 2;
825
826    if (this->commonDrawBitmap(bm, kDrawSprite_DrawOp, 0, opBytesNeeded, paint)) {
827        fWriter.write32(left);
828        fWriter.write32(top);
829    }
830}
831
832bool SkGPipeCanvas::commonDrawImage(const SkImage* image, DrawOps op, unsigned flags,
833                                    size_t opBytesNeeded, const SkPaint* paint) {
834    if (fDone) {
835        return false;
836    }
837
838    if (paint != NULL) {
839        flags |= kDrawBitmap_HasPaint_DrawOpFlag;
840        this->writePaint(*paint);
841    }
842    // This needs to run first so its calls to needOpBytes() and its writes
843    // don't interlace with the needOpBytes() and write below.
844    int32_t slot = fImageHeap->insert(image);
845    SkASSERT(slot != 0);
846    if (this->needOpBytes(opBytesNeeded)) {
847        this->writeOp(op, flags, slot);
848        return true;
849    }
850    return false;
851}
852
853void SkGPipeCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
854                                const SkPaint* paint) {
855    NOTIFY_SETUP(this);
856    if (this->commonDrawImage(image, kDrawImage_DrawOp, 0, sizeof(SkScalar) * 2, paint)) {
857        fWriter.writeScalar(x);
858        fWriter.writeScalar(y);
859    }
860}
861
862void SkGPipeCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
863                                    const SkPaint* paint) {
864    NOTIFY_SETUP(this);
865    unsigned flags = 0;
866    size_t opBytesNeeded = sizeof(SkRect);  // dst
867    if (src) {
868        flags |= kDrawBitmap_HasSrcRect_DrawOpFlag;
869        opBytesNeeded += sizeof(SkRect);    // src
870    }
871    if (this->commonDrawImage(image, kDrawImageRect_DrawOp, flags, opBytesNeeded, paint)) {
872        if (src) {
873            fWriter.writeRect(*src);
874        }
875        fWriter.writeRect(dst);
876    }
877}
878
879void SkGPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
880                               const SkPaint& paint) {
881    if (byteLength) {
882        NOTIFY_SETUP(this);
883        this->writePaint(paint);
884        if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
885            this->writeOp(kDrawText_DrawOp);
886            fWriter.write32(SkToU32(byteLength));
887            fWriter.writePad(text, byteLength);
888            fWriter.writeScalar(x);
889            fWriter.writeScalar(y);
890        }
891    }
892}
893
894void SkGPipeCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
895                                  const SkPaint& paint) {
896    if (byteLength) {
897        NOTIFY_SETUP(this);
898        this->writePaint(paint);
899        int count = paint.textToGlyphs(text, byteLength, NULL);
900        if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
901            this->writeOp(kDrawPosText_DrawOp);
902            fWriter.write32(SkToU32(byteLength));
903            fWriter.writePad(text, byteLength);
904            fWriter.write32(count);
905            fWriter.write(pos, count * sizeof(SkPoint));
906        }
907    }
908}
909
910void SkGPipeCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
911                                   SkScalar constY, const SkPaint& paint) {
912    if (byteLength) {
913        NOTIFY_SETUP(this);
914        this->writePaint(paint);
915        int count = paint.textToGlyphs(text, byteLength, NULL);
916        if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
917            this->writeOp(kDrawPosTextH_DrawOp);
918            fWriter.write32(SkToU32(byteLength));
919            fWriter.writePad(text, byteLength);
920            fWriter.write32(count);
921            fWriter.write(xpos, count * sizeof(SkScalar));
922            fWriter.writeScalar(constY);
923        }
924    }
925}
926
927void SkGPipeCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
928                                     const SkMatrix* matrix, const SkPaint& paint) {
929    if (byteLength) {
930        NOTIFY_SETUP(this);
931        unsigned flags = 0;
932        size_t size = 4 + SkAlign4(byteLength) + path.writeToMemory(NULL);
933        if (matrix) {
934            flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
935            size += matrix->writeToMemory(NULL);
936        }
937        this->writePaint(paint);
938        if (this->needOpBytes(size)) {
939            this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
940
941            fWriter.write32(SkToU32(byteLength));
942            fWriter.writePad(text, byteLength);
943
944            fWriter.writePath(path);
945            if (matrix) {
946                fWriter.writeMatrix(*matrix);
947            }
948        }
949    }
950}
951
952size_t SkGPipeCanvas::getInProcessTypefaces(const SkRefCntSet& typefaceSet,
953                                            TypefaceBuffer* buffer) {
954    // When in-process, we simply write out the typeface pointers.
955    size_t size = typefaceSet.count() * sizeof(SkTypeface*);
956    buffer->reset(size);
957    typefaceSet.copyToArray(reinterpret_cast<SkRefCnt**>(buffer->get()));
958
959    return size;
960}
961
962size_t SkGPipeCanvas::getCrossProcessTypefaces(const SkRefCntSet& typefaceSet,
963                                               TypefaceBuffer* buffer) {
964    // For cross-process we use typeface IDs.
965    size_t size = typefaceSet.count() * sizeof(uint32_t);
966    buffer->reset(size);
967
968    uint32_t* idBuffer = reinterpret_cast<uint32_t*>(buffer->get());
969    SkRefCntSet::Iter iter(typefaceSet);
970    int i = 0;
971
972    for (void* setPtr = iter.next(); setPtr; setPtr = iter.next()) {
973        idBuffer[i++] = this->getTypefaceID(reinterpret_cast<SkTypeface*>(setPtr));
974    }
975
976    SkASSERT(i == typefaceSet.count());
977
978    return size;
979}
980
981void SkGPipeCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
982                                   const SkPaint& paint) {
983    NOTIFY_SETUP(this);
984    this->writePaint(paint);
985
986    // FIXME: this is inefficient but avoids duplicating the blob serialization logic.
987    SkRefCntSet typefaceSet;
988    SkWriteBuffer blobBuffer;
989    blobBuffer.setTypefaceRecorder(&typefaceSet);
990    blob->flatten(blobBuffer);
991
992    // Unlike most draw ops (which only use one paint/typeface), text blobs may reference
993    // an arbitrary number of typefaces. Since the one-paint-per-op model is not applicable,
994    // we need to serialize these explicitly.
995    TypefaceBuffer typefaceBuffer;
996    size_t typefaceSize = is_cross_process(fFlags)
997        ? this->getCrossProcessTypefaces(typefaceSet, &typefaceBuffer)
998        : this->getInProcessTypefaces(typefaceSet, &typefaceBuffer);
999
1000    // blob byte count + typeface count + x + y + blob data + an index (cross-process)
1001    // or pointer (in-process) for each typeface
1002    size_t size = 2 * sizeof(uint32_t)
1003                + 2 * sizeof(SkScalar)
1004                + blobBuffer.bytesWritten()
1005                + typefaceSize;
1006
1007    if (this->needOpBytes(size)) {
1008        this->writeOp(kDrawTextBlob_DrawOp);
1009        SkDEBUGCODE(size_t initialOffset = fWriter.bytesWritten();)
1010
1011        fWriter.writeScalar(x);
1012        fWriter.writeScalar(y);
1013
1014        fWriter.write32(typefaceSet.count());
1015        fWriter.write(typefaceBuffer.get(), typefaceSize);
1016
1017        fWriter.write32(SkToU32(blobBuffer.bytesWritten()));
1018        uint32_t* pad = fWriter.reservePad(blobBuffer.bytesWritten());
1019        blobBuffer.writeToMemory(pad);
1020
1021        SkASSERT(initialOffset + size == fWriter.bytesWritten());
1022    }
1023}
1024
1025void SkGPipeCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
1026                                  const SkPaint* paint) {
1027    // we want to playback the picture into individual draw calls
1028    //
1029    // todo: do we always have to unroll? If the pipe is not cross-process, seems like
1030    // we could just ref the picture and move on...? <reed, scroggo>
1031    //
1032    this->INHERITED::onDrawPicture(picture, matrix, paint);
1033}
1034
1035void SkGPipeCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
1036                                   const SkPoint vertices[], const SkPoint texs[],
1037                                   const SkColor colors[], SkXfermode* xfer,
1038                                   const uint16_t indices[], int indexCount,
1039                                   const SkPaint& paint) {
1040    if (0 == vertexCount) {
1041        return;
1042    }
1043
1044    NOTIFY_SETUP(this);
1045    this->writePaint(paint);
1046
1047    unsigned flags = 0;  // packs with the op, so needs no extra space
1048
1049    size_t size = 0;
1050    size += 4;                              // vmode
1051    size += 4;                              // vertex count
1052    size += vertexCount * sizeof(SkPoint);  // vertices
1053
1054    if (texs) {
1055        flags |= kDrawVertices_HasTexs_DrawOpFlag;
1056        size += vertexCount * sizeof(SkPoint);
1057    }
1058    if (colors) {
1059        flags |= kDrawVertices_HasColors_DrawOpFlag;
1060        size += vertexCount * sizeof(SkColor);
1061    }
1062    if (xfer && !SkXfermode::IsMode(xfer, SkXfermode::kModulate_Mode)) {
1063        flags |= kDrawVertices_HasXfermode_DrawOpFlag;
1064        size += sizeof(int32_t);    // SkXfermode::Mode
1065    }
1066    if (indices && indexCount > 0) {
1067        flags |= kDrawVertices_HasIndices_DrawOpFlag;
1068        size += 4;                                        // index count
1069        size += SkAlign4(indexCount * sizeof(uint16_t));  // indices
1070    }
1071
1072    if (this->needOpBytes(size)) {
1073        this->writeOp(kDrawVertices_DrawOp, flags, 0);
1074        fWriter.write32(vmode);
1075        fWriter.write32(vertexCount);
1076        fWriter.write(vertices, vertexCount * sizeof(SkPoint));
1077        if (flags & kDrawVertices_HasTexs_DrawOpFlag) {
1078            fWriter.write(texs, vertexCount * sizeof(SkPoint));
1079        }
1080        if (flags & kDrawVertices_HasColors_DrawOpFlag) {
1081            fWriter.write(colors, vertexCount * sizeof(SkColor));
1082        }
1083        if (flags & kDrawVertices_HasXfermode_DrawOpFlag) {
1084            SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1085            SkAssertResult(xfer->asMode(&mode));
1086            fWriter.write32(mode);
1087        }
1088        if (flags & kDrawVertices_HasIndices_DrawOpFlag) {
1089            fWriter.write32(indexCount);
1090            fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1091        }
1092    }
1093}
1094
1095void SkGPipeCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
1096                                const SkPoint texCoords[4], SkXfermode* xmode,
1097                                const SkPaint& paint) {
1098    NOTIFY_SETUP(this);
1099
1100    size_t size = SkPatchUtils::kNumCtrlPts * sizeof(SkPoint);
1101    unsigned flags = 0;
1102    if (colors) {
1103        flags |= kDrawVertices_HasColors_DrawOpFlag;
1104        size += SkPatchUtils::kNumCorners * sizeof(SkColor);
1105    }
1106    if (texCoords) {
1107        flags |= kDrawVertices_HasTexs_DrawOpFlag;
1108        size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
1109    }
1110    if (xmode) {
1111        SkXfermode::Mode mode;
1112        if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1113            flags |= kDrawVertices_HasXfermode_DrawOpFlag;
1114            size += sizeof(int32_t);
1115        }
1116    }
1117
1118    this->writePaint(paint);
1119    if (this->needOpBytes(size)) {
1120        this->writeOp(kDrawPatch_DrawOp, flags, 0);
1121
1122        fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
1123
1124        if (colors) {
1125            fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
1126        }
1127
1128        if (texCoords) {
1129            fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
1130        }
1131
1132        if (flags & kDrawVertices_HasXfermode_DrawOpFlag) {
1133            SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1134            SkAssertResult(xmode->asMode(&mode));
1135            fWriter.write32(mode);
1136        }
1137    }
1138}
1139
1140void SkGPipeCanvas::beginCommentGroup(const char* description) {
1141    // ignore for now
1142}
1143
1144void SkGPipeCanvas::addComment(const char* kywd, const char* value) {
1145    // ignore for now
1146}
1147
1148void SkGPipeCanvas::endCommentGroup() {
1149    // ignore for now
1150}
1151
1152void SkGPipeCanvas::flushRecording(bool detachCurrentBlock) {
1153    this->doNotify();
1154    if (detachCurrentBlock) {
1155        // force a new block to be requested for the next recorded command
1156        fBlockSize = 0;
1157    }
1158}
1159
1160size_t SkGPipeCanvas::freeMemoryIfPossible(size_t bytesToFree) {
1161    return (NULL == fBitmapHeap) ? 0 : fBitmapHeap->freeMemoryIfPossible(bytesToFree);
1162}
1163
1164///////////////////////////////////////////////////////////////////////////////
1165
1166template <typename T> uint32_t castToU32(T value) {
1167    union {
1168        T           fSrc;
1169        uint32_t    fDst;
1170    } data;
1171    data.fSrc = value;
1172    return data.fDst;
1173}
1174
1175void SkGPipeCanvas::writePaint(const SkPaint& paint) {
1176    if (fDone) {
1177        return;
1178    }
1179    SkPaint& base = fPaint;
1180    uint32_t storage[32];
1181    uint32_t* ptr = storage;
1182
1183    if (base.getFlags() != paint.getFlags()) {
1184        *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
1185        base.setFlags(paint.getFlags());
1186    }
1187    if (base.getColor() != paint.getColor()) {
1188        *ptr++ = PaintOp_packOp(kColor_PaintOp);
1189        *ptr++ = paint.getColor();
1190        base.setColor(paint.getColor());
1191    }
1192    if (base.getFilterQuality() != paint.getFilterQuality()) {
1193        *ptr++ = PaintOp_packOpData(kFilterLevel_PaintOp, paint.getFilterQuality());
1194        base.setFilterQuality(paint.getFilterQuality());
1195    }
1196    if (base.getStyle() != paint.getStyle()) {
1197        *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
1198        base.setStyle(paint.getStyle());
1199    }
1200    if (base.getStrokeJoin() != paint.getStrokeJoin()) {
1201        *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
1202        base.setStrokeJoin(paint.getStrokeJoin());
1203    }
1204    if (base.getStrokeCap() != paint.getStrokeCap()) {
1205        *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
1206        base.setStrokeCap(paint.getStrokeCap());
1207    }
1208    if (base.getStrokeWidth() != paint.getStrokeWidth()) {
1209        *ptr++ = PaintOp_packOp(kWidth_PaintOp);
1210        *ptr++ = castToU32(paint.getStrokeWidth());
1211        base.setStrokeWidth(paint.getStrokeWidth());
1212    }
1213    if (base.getStrokeMiter() != paint.getStrokeMiter()) {
1214        *ptr++ = PaintOp_packOp(kMiter_PaintOp);
1215        *ptr++ = castToU32(paint.getStrokeMiter());
1216        base.setStrokeMiter(paint.getStrokeMiter());
1217    }
1218    if (base.getTextEncoding() != paint.getTextEncoding()) {
1219        *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
1220        base.setTextEncoding(paint.getTextEncoding());
1221    }
1222    if (base.getHinting() != paint.getHinting()) {
1223        *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
1224        base.setHinting(paint.getHinting());
1225    }
1226    if (base.getTextAlign() != paint.getTextAlign()) {
1227        *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
1228        base.setTextAlign(paint.getTextAlign());
1229    }
1230    if (base.getTextSize() != paint.getTextSize()) {
1231        *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
1232        *ptr++ = castToU32(paint.getTextSize());
1233        base.setTextSize(paint.getTextSize());
1234    }
1235    if (base.getTextScaleX() != paint.getTextScaleX()) {
1236        *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
1237        *ptr++ = castToU32(paint.getTextScaleX());
1238        base.setTextScaleX(paint.getTextScaleX());
1239    }
1240    if (base.getTextSkewX() != paint.getTextSkewX()) {
1241        *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
1242        *ptr++ = castToU32(paint.getTextSkewX());
1243        base.setTextSkewX(paint.getTextSkewX());
1244    }
1245
1246    if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
1247        if (is_cross_process(fFlags)) {
1248            uint32_t id = this->getTypefaceID(paint.getTypeface());
1249            *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
1250        } else if (this->needOpBytes(sizeof(void*))) {
1251            // Add to the set for ref counting.
1252            fTypefaceSet.add(paint.getTypeface());
1253            // It is safe to write the typeface to the stream before the rest
1254            // of the paint unless we ever send a kReset_PaintOp, which we
1255            // currently never do.
1256            this->writeOp(kSetTypeface_DrawOp);
1257            fWriter.writePtr(paint.getTypeface());
1258        }
1259        base.setTypeface(paint.getTypeface());
1260    }
1261
1262    // This is a new paint, so all old flats can be safely purged, if necessary.
1263    fFlattenableHeap.markAllFlatsSafeToDelete();
1264    for (int i = 0; i < kCount_PaintFlats; i++) {
1265        int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
1266        bool replaced = index < 0;
1267        if (replaced) {
1268            index = ~index;
1269        }
1270        // Store the index of any flat that needs to be kept. 0 means no flat.
1271        if (index > 0) {
1272            fFlattenableHeap.markFlatForKeeping(index);
1273        }
1274        SkASSERT(index >= 0 && index <= fFlatDictionary.count());
1275        if (index != fCurrFlatIndex[i] || replaced) {
1276            *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
1277            fCurrFlatIndex[i] = index;
1278        }
1279    }
1280
1281    size_t size = (char*)ptr - (char*)storage;
1282    if (size && this->needOpBytes(size)) {
1283        this->writeOp(kPaintOp_DrawOp, 0, SkToU32(size));
1284        fWriter.write(storage, size);
1285        for (size_t i = 0; i < size/4; i++) {
1286//            SkDebugf("[%d] %08X\n", i, storage[i]);
1287        }
1288    }
1289
1290    //
1291    //  Do these after we've written kPaintOp_DrawOp
1292
1293    if (base.getAnnotation() != paint.getAnnotation()) {
1294        if (NULL == paint.getAnnotation()) {
1295            if (this->needOpBytes()) {
1296                this->writeOp(kSetAnnotation_DrawOp, 0, 0);
1297            }
1298        } else {
1299            SkWriteBuffer buffer;
1300            paint.getAnnotation()->writeToBuffer(buffer);
1301            const size_t size = buffer.bytesWritten();
1302            if (this->needOpBytes(size)) {
1303                this->writeOp(kSetAnnotation_DrawOp, 0, SkToU32(size));
1304                buffer.writeToMemory(fWriter.reserve(size));
1305            }
1306        }
1307        base.setAnnotation(paint.getAnnotation());
1308    }
1309}
1310
1311///////////////////////////////////////////////////////////////////////////////
1312
1313#include "SkGPipe.h"
1314
1315SkGPipeController::~SkGPipeController() {
1316    SkSafeUnref(fCanvas);
1317}
1318
1319void SkGPipeController::setCanvas(SkGPipeCanvas* canvas) {
1320    SkRefCnt_SafeAssign(fCanvas, canvas);
1321}
1322
1323///////////////////////////////////////////////////////////////////////////////
1324
1325SkGPipeWriter::SkGPipeWriter()
1326: fWriter(0) {
1327    fCanvas = NULL;
1328}
1329
1330SkGPipeWriter::~SkGPipeWriter() {
1331    this->endRecording();
1332}
1333
1334SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t flags,
1335                                        uint32_t width, uint32_t height) {
1336    if (NULL == fCanvas) {
1337        fWriter.reset(NULL, 0);
1338        fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter, flags, width, height));
1339    }
1340    controller->setCanvas(fCanvas);
1341    return fCanvas;
1342}
1343
1344void SkGPipeWriter::endRecording() {
1345    if (fCanvas) {
1346        fCanvas->finish(true);
1347        fCanvas->unref();
1348        fCanvas = NULL;
1349    }
1350}
1351
1352void SkGPipeWriter::flushRecording(bool detachCurrentBlock) {
1353    if (fCanvas) {
1354        fCanvas->flushRecording(detachCurrentBlock);
1355    }
1356}
1357
1358size_t SkGPipeWriter::freeMemoryIfPossible(size_t bytesToFree) {
1359    if (fCanvas) {
1360        return fCanvas->freeMemoryIfPossible(bytesToFree);
1361    }
1362    return 0;
1363}
1364
1365size_t SkGPipeWriter::storageAllocatedForRecording() const {
1366    return NULL == fCanvas ? 0 : fCanvas->storageAllocatedForRecording();
1367}
1368
1369///////////////////////////////////////////////////////////////////////////////
1370
1371BitmapShuttle::BitmapShuttle(SkGPipeCanvas* canvas) {
1372    SkASSERT(canvas != NULL);
1373    fCanvas = canvas;
1374    fCanvas->ref();
1375}
1376
1377BitmapShuttle::~BitmapShuttle() {
1378    this->removeCanvas();
1379}
1380
1381bool BitmapShuttle::insert(const SkBitmap& bitmap, int32_t slot) {
1382    SkASSERT(fCanvas != NULL);
1383    return fCanvas->shuttleBitmap(bitmap, slot);
1384}
1385
1386void BitmapShuttle::removeCanvas() {
1387    if (NULL == fCanvas) {
1388        return;
1389    }
1390    fCanvas->unref();
1391    fCanvas = NULL;
1392}
1393
1394///////////////////////////////////////////////////////////////////////////////////////////////////
1395
1396SkImageHeap::SkImageHeap() {}
1397
1398SkImageHeap::~SkImageHeap() {
1399    fArray.unrefAll();
1400}
1401
1402const SkImage* SkImageHeap::get(int32_t slot) const {
1403    SkASSERT(slot > 0);
1404    return fArray[slot - 1];
1405}
1406
1407int32_t SkImageHeap::find(const SkImage* img) const {
1408    int index = fArray.find(img);
1409    if (index >= 0) {
1410        return index + 1;   // found
1411    }
1412    return 0;   // not found
1413}
1414
1415int32_t SkImageHeap::insert(const SkImage* img) {
1416    int32_t slot = this->find(img);
1417    if (slot) {
1418        return slot;
1419    }
1420    *fArray.append() = SkRef(img);
1421    return fArray.count();  // slot is always index+1
1422}
1423
1424