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
10
11#include "SkCanvas.h"
12#include "SkData.h"
13#include "SkDevice.h"
14#include "SkPaint.h"
15#include "SkGPipe.h"
16#include "SkGPipePriv.h"
17#include "SkStream.h"
18#include "SkTSearch.h"
19#include "SkTypeface.h"
20#include "SkWriter32.h"
21#include "SkColorFilter.h"
22#include "SkDrawLooper.h"
23#include "SkMaskFilter.h"
24#include "SkRasterizer.h"
25#include "SkShader.h"
26
27static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
28    SkASSERT(paintFlat < kCount_PaintFlats);
29    switch (paintFlat) {
30        case kColorFilter_PaintFlat:    return paint.getColorFilter();
31        case kDrawLooper_PaintFlat:     return paint.getLooper();
32        case kMaskFilter_PaintFlat:     return paint.getMaskFilter();
33        case kPathEffect_PaintFlat:     return paint.getPathEffect();
34        case kRasterizer_PaintFlat:     return paint.getRasterizer();
35        case kShader_PaintFlat:         return paint.getShader();
36        case kXfermode_PaintFlat:       return paint.getXfermode();
37    }
38    SkDEBUGFAIL("never gets here");
39    return NULL;
40}
41
42static size_t estimateFlattenSize(const SkPath& path) {
43    int n = path.countPoints();
44    size_t bytes = 3 * sizeof(int32_t);
45    bytes += n * sizeof(SkPoint);
46    bytes += SkAlign4(n + 2);    // verbs: add 2 for move/close extras
47
48#ifdef SK_DEBUG
49    {
50        SkWriter32 writer(1024);
51        path.flatten(writer);
52        SkASSERT(writer.size() <= bytes);
53    }
54#endif
55    return bytes;
56}
57
58static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
59    SkASSERT(typeface);
60    SkDynamicMemoryWStream stream;
61    typeface->serialize(&stream);
62    size_t size = stream.getOffset();
63    if (writer) {
64        writer->write32(size);
65        SkAutoDataUnref data(stream.copyToData());
66        writer->write(data.data(), size);
67    }
68    return 4 + size;
69}
70
71///////////////////////////////////////////////////////////////////////////////
72
73class SkGPipeCanvas : public SkCanvas {
74public:
75    SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*);
76    virtual ~SkGPipeCanvas();
77
78    void finish() {
79        if (!fDone) {
80            if (this->needOpBytes()) {
81                this->writeOp(kDone_DrawOp);
82                this->doNotify();
83            }
84            fDone = true;
85        }
86    }
87
88    // overrides from SkCanvas
89    virtual int save(SaveFlags);
90    virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags);
91    virtual void restore();
92    virtual bool translate(SkScalar dx, SkScalar dy);
93    virtual bool scale(SkScalar sx, SkScalar sy);
94    virtual bool rotate(SkScalar degrees);
95    virtual bool skew(SkScalar sx, SkScalar sy);
96    virtual bool concat(const SkMatrix& matrix);
97    virtual void setMatrix(const SkMatrix& matrix);
98    virtual bool clipRect(const SkRect& rect, SkRegion::Op op);
99    virtual bool clipPath(const SkPath& path, SkRegion::Op op);
100    virtual bool clipRegion(const SkRegion& region, SkRegion::Op op);
101    virtual void clear(SkColor);
102    virtual void drawPaint(const SkPaint& paint);
103    virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
104                            const SkPaint&);
105    virtual void drawRect(const SkRect& rect, const SkPaint&);
106    virtual void drawPath(const SkPath& path, const SkPaint&);
107    virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
108                            const SkPaint*);
109    virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src,
110                                const SkRect& dst, const SkPaint*);
111    virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
112                                  const SkPaint*);
113    virtual void drawSprite(const SkBitmap&, int left, int top,
114                            const SkPaint*);
115    virtual void drawText(const void* text, size_t byteLength, SkScalar x,
116                          SkScalar y, const SkPaint&);
117    virtual void drawPosText(const void* text, size_t byteLength,
118                             const SkPoint pos[], const SkPaint&);
119    virtual void drawPosTextH(const void* text, size_t byteLength,
120                      const SkScalar xpos[], SkScalar constY, const SkPaint&);
121    virtual void drawTextOnPath(const void* text, size_t byteLength,
122                            const SkPath& path, const SkMatrix* matrix,
123                                const SkPaint&);
124    virtual void drawPicture(SkPicture& picture);
125    virtual void drawVertices(VertexMode, int vertexCount,
126                          const SkPoint vertices[], const SkPoint texs[],
127                          const SkColor colors[], SkXfermode*,
128                          const uint16_t indices[], int indexCount,
129                              const SkPaint&);
130    virtual void drawData(const void*, size_t);
131
132private:
133    SkFactorySet* fFactorySet;  // optional, only used if cross-process
134    SkGPipeController* fController;
135    SkWriter32& fWriter;
136    size_t      fBlockSize; // amount allocated for writer
137    size_t      fBytesNotified;
138    bool        fDone;
139
140    SkRefCntSet fTypefaceSet;
141
142    uint32_t getTypefaceID(SkTypeface*);
143
144    inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
145        fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
146    }
147
148    inline void writeOp(DrawOps op) {
149        fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
150    }
151
152    bool needOpBytes(size_t size = 0);
153
154    inline void doNotify() {
155        if (!fDone) {
156            size_t bytes = fWriter.size() - fBytesNotified;
157            fController->notifyWritten(bytes);
158            fBytesNotified += bytes;
159        }
160    }
161
162    struct FlatData {
163        uint32_t    fIndex; // always > 0
164        uint32_t    fSize;
165
166        void*       data() { return (char*)this + sizeof(*this); }
167
168        static int Compare(const FlatData* a, const FlatData* b) {
169            return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
170        }
171    };
172    SkTDArray<FlatData*> fFlatArray;
173    int fCurrFlatIndex[kCount_PaintFlats];
174    int flattenToIndex(SkFlattenable* obj, PaintFlats);
175
176    SkPaint fPaint;
177    void writePaint(const SkPaint&);
178
179    class AutoPipeNotify {
180    public:
181        AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
182        ~AutoPipeNotify() { fCanvas->doNotify(); }
183    private:
184        SkGPipeCanvas* fCanvas;
185    };
186    friend class AutoPipeNotify;
187
188    typedef SkCanvas INHERITED;
189};
190
191// return 0 for NULL (or unflattenable obj), or index-base-1
192int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
193    if (NULL == obj) {
194        return 0;
195    }
196
197    SkFlattenableWriteBuffer tmpWriter(1024);
198    tmpWriter.setFlags(SkFlattenableWriteBuffer::kInlineFactoryNames_Flag);
199    tmpWriter.setFactoryRecorder(fFactorySet);
200
201    tmpWriter.writeFlattenable(obj);
202    size_t len = tmpWriter.size();
203    size_t allocSize = len + sizeof(FlatData);
204
205    SkAutoSMalloc<1024> storage(allocSize);
206    FlatData* flat = (FlatData*)storage.get();
207    flat->fSize = len;
208    tmpWriter.flatten(flat->data());
209
210    int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
211                                    fFlatArray.count(), flat, sizeof(flat),
212                                    &FlatData::Compare);
213    if (index < 0) {
214        index = ~index;
215        FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
216        memcpy(copy, flat, allocSize);
217        *fFlatArray.insert(index) = copy;
218        // call this after the insert, so that count() will have been grown
219        copy->fIndex = fFlatArray.count();
220//        SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
221
222        if (this->needOpBytes(len)) {
223            this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex);
224            fWriter.write(copy->data(), len);
225        }
226    }
227    return fFlatArray[index]->fIndex;
228}
229
230///////////////////////////////////////////////////////////////////////////////
231
232#define MIN_BLOCK_SIZE  (16 * 1024)
233
234SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
235                             SkWriter32* writer, SkFactorySet* fset)
236        : fWriter(*writer) {
237    fFactorySet = fset;
238    fController = controller;
239    fDone = false;
240    fBlockSize = 0; // need first block from controller
241    sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
242
243    // we need a device to limit our clip
244    // should the caller give us the bounds?
245    // We don't allocate pixels for the bitmap
246    SkBitmap bitmap;
247    bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
248    SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
249    this->setDevice(device)->unref();
250}
251
252SkGPipeCanvas::~SkGPipeCanvas() {
253    this->finish();
254
255    fFlatArray.freeAll();
256}
257
258bool SkGPipeCanvas::needOpBytes(size_t needed) {
259    if (fDone) {
260        return false;
261    }
262
263    needed += 4;  // size of DrawOp atom
264    if (fWriter.size() + needed > fBlockSize) {
265        void* block = fController->requestBlock(MIN_BLOCK_SIZE, &fBlockSize);
266        if (NULL == block) {
267            fDone = true;
268            return false;
269        }
270        fWriter.reset(block, fBlockSize);
271        fBytesNotified = 0;
272    }
273    return true;
274}
275
276uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
277    uint32_t id = 0; // 0 means default/null typeface
278    if (face) {
279        id = fTypefaceSet.find(face);
280        if (0 == id) {
281            id = fTypefaceSet.add(face);
282            size_t size = writeTypeface(NULL, face);
283            if (this->needOpBytes(size)) {
284                this->writeOp(kDef_Typeface_DrawOp);
285                writeTypeface(&fWriter, face);
286            }
287        }
288    }
289    return id;
290}
291
292///////////////////////////////////////////////////////////////////////////////
293
294#define NOTIFY_SETUP(canvas)    \
295    AutoPipeNotify apn(canvas)
296
297int SkGPipeCanvas::save(SaveFlags flags) {
298    NOTIFY_SETUP(this);
299    if (this->needOpBytes()) {
300        this->writeOp(kSave_DrawOp, 0, flags);
301    }
302    return this->INHERITED::save(flags);
303}
304
305int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
306                             SaveFlags saveFlags) {
307    NOTIFY_SETUP(this);
308    size_t size = 0;
309    unsigned opFlags = 0;
310
311    if (bounds) {
312        opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
313        size += sizeof(SkRect);
314    }
315    if (paint) {
316        opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
317        this->writePaint(*paint);
318    }
319
320    if (this->needOpBytes(size)) {
321        this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
322        if (bounds) {
323            fWriter.writeRect(*bounds);
324        }
325    }
326
327    // we just pass on the save, so we don't create a layer
328    return this->INHERITED::save(saveFlags);
329}
330
331void SkGPipeCanvas::restore() {
332    NOTIFY_SETUP(this);
333    if (this->needOpBytes()) {
334        this->writeOp(kRestore_DrawOp);
335    }
336    this->INHERITED::restore();
337}
338
339bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
340    if (dx || dy) {
341        NOTIFY_SETUP(this);
342        if (this->needOpBytes(2 * sizeof(SkScalar))) {
343            this->writeOp(kTranslate_DrawOp);
344            fWriter.writeScalar(dx);
345            fWriter.writeScalar(dy);
346        }
347    }
348    return this->INHERITED::translate(dx, dy);
349}
350
351bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
352    if (sx || sy) {
353        NOTIFY_SETUP(this);
354        if (this->needOpBytes(2 * sizeof(SkScalar))) {
355            this->writeOp(kScale_DrawOp);
356            fWriter.writeScalar(sx);
357            fWriter.writeScalar(sy);
358        }
359    }
360    return this->INHERITED::scale(sx, sy);
361}
362
363bool SkGPipeCanvas::rotate(SkScalar degrees) {
364    if (degrees) {
365        NOTIFY_SETUP(this);
366        if (this->needOpBytes(sizeof(SkScalar))) {
367            this->writeOp(kRotate_DrawOp);
368            fWriter.writeScalar(degrees);
369        }
370    }
371    return this->INHERITED::rotate(degrees);
372}
373
374bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
375    if (sx || sy) {
376        NOTIFY_SETUP(this);
377        if (this->needOpBytes(2 * sizeof(SkScalar))) {
378            this->writeOp(kSkew_DrawOp);
379            fWriter.writeScalar(sx);
380            fWriter.writeScalar(sy);
381        }
382    }
383    return this->INHERITED::skew(sx, sy);
384}
385
386bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
387    if (!matrix.isIdentity()) {
388        NOTIFY_SETUP(this);
389        if (this->needOpBytes(matrix.flatten(NULL))) {
390            this->writeOp(kConcat_DrawOp);
391            SkWriteMatrix(&fWriter, matrix);
392        }
393    }
394    return this->INHERITED::concat(matrix);
395}
396
397void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
398    NOTIFY_SETUP(this);
399    if (this->needOpBytes(matrix.flatten(NULL))) {
400        this->writeOp(kSetMatrix_DrawOp);
401        SkWriteMatrix(&fWriter, matrix);
402    }
403    this->INHERITED::setMatrix(matrix);
404}
405
406bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) {
407    NOTIFY_SETUP(this);
408    if (this->needOpBytes(sizeof(SkRect))) {
409        this->writeOp(kClipRect_DrawOp, 0, rgnOp);
410        fWriter.writeRect(rect);
411    }
412    return this->INHERITED::clipRect(rect, rgnOp);
413}
414
415bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) {
416    NOTIFY_SETUP(this);
417    if (this->needOpBytes(estimateFlattenSize(path))) {
418        this->writeOp(kClipPath_DrawOp, 0, rgnOp);
419        path.flatten(fWriter);
420    }
421    // we just pass on the bounds of the path
422    return this->INHERITED::clipRect(path.getBounds(), rgnOp);
423}
424
425bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
426    NOTIFY_SETUP(this);
427    if (this->needOpBytes(region.flatten(NULL))) {
428        this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
429        SkWriteRegion(&fWriter, region);
430    }
431    return this->INHERITED::clipRegion(region, rgnOp);
432}
433
434///////////////////////////////////////////////////////////////////////////////
435
436void SkGPipeCanvas::clear(SkColor color) {
437    NOTIFY_SETUP(this);
438    unsigned flags = 0;
439    if (color) {
440        flags |= kClear_HasColor_DrawOpFlag;
441    }
442    if (this->needOpBytes(sizeof(SkColor))) {
443        this->writeOp(kDrawClear_DrawOp, flags, 0);
444        if (color) {
445            fWriter.write32(color);
446        }
447    }
448}
449
450void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
451    NOTIFY_SETUP(this);
452    this->writePaint(paint);
453    if (this->needOpBytes()) {
454        this->writeOp(kDrawPaint_DrawOp);
455    }
456}
457
458void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
459                                   const SkPoint pts[], const SkPaint& paint) {
460    if (count) {
461        NOTIFY_SETUP(this);
462        this->writePaint(paint);
463        if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
464            this->writeOp(kDrawPoints_DrawOp, mode, 0);
465            fWriter.write32(count);
466            fWriter.write(pts, count * sizeof(SkPoint));
467        }
468    }
469}
470
471void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
472    NOTIFY_SETUP(this);
473    this->writePaint(paint);
474    if (this->needOpBytes(sizeof(SkRect))) {
475        this->writeOp(kDrawRect_DrawOp);
476        fWriter.writeRect(rect);
477    }
478}
479
480void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
481    NOTIFY_SETUP(this);
482    this->writePaint(paint);
483    if (this->needOpBytes(estimateFlattenSize(path))) {
484        this->writeOp(kDrawPath_DrawOp);
485        path.flatten(fWriter);
486    }
487}
488
489void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
490                                   const SkPaint*) {
491    UNIMPLEMENTED
492}
493
494void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src,
495                                       const SkRect& dst, const SkPaint*) {
496    UNIMPLEMENTED
497}
498
499void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
500                                         const SkPaint*) {
501    UNIMPLEMENTED
502}
503
504void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top,
505                                   const SkPaint*) {
506    UNIMPLEMENTED
507}
508
509void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
510                                 SkScalar y, const SkPaint& paint) {
511    if (byteLength) {
512        NOTIFY_SETUP(this);
513        this->writePaint(paint);
514        if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
515            this->writeOp(kDrawText_DrawOp);
516            fWriter.write32(byteLength);
517            fWriter.writePad(text, byteLength);
518            fWriter.writeScalar(x);
519            fWriter.writeScalar(y);
520        }
521    }
522}
523
524void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
525                                const SkPoint pos[], const SkPaint& paint) {
526    if (byteLength) {
527        NOTIFY_SETUP(this);
528        this->writePaint(paint);
529        int count = paint.textToGlyphs(text, byteLength, NULL);
530        if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
531            this->writeOp(kDrawPosText_DrawOp);
532            fWriter.write32(byteLength);
533            fWriter.writePad(text, byteLength);
534            fWriter.write32(count);
535            fWriter.write(pos, count * sizeof(SkPoint));
536        }
537    }
538}
539
540void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
541                                 const SkScalar xpos[], SkScalar constY,
542                                 const SkPaint& paint) {
543    if (byteLength) {
544        NOTIFY_SETUP(this);
545        this->writePaint(paint);
546        int count = paint.textToGlyphs(text, byteLength, NULL);
547        if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
548            this->writeOp(kDrawPosTextH_DrawOp);
549            fWriter.write32(byteLength);
550            fWriter.writePad(text, byteLength);
551            fWriter.write32(count);
552            fWriter.write(xpos, count * sizeof(SkScalar));
553            fWriter.writeScalar(constY);
554        }
555    }
556}
557
558void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
559                                   const SkPath& path, const SkMatrix* matrix,
560                                   const SkPaint& paint) {
561    if (byteLength) {
562        NOTIFY_SETUP(this);
563        unsigned flags = 0;
564        size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path);
565        if (matrix) {
566            flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
567            size += matrix->flatten(NULL);
568        }
569        this->writePaint(paint);
570        if (this->needOpBytes(size)) {
571            this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
572
573            fWriter.write32(byteLength);
574            fWriter.writePad(text, byteLength);
575
576            path.flatten(fWriter);
577            if (matrix) {
578                SkWriteMatrix(&fWriter, *matrix);
579            }
580        }
581    }
582}
583
584void SkGPipeCanvas::drawPicture(SkPicture& picture) {
585    // we want to playback the picture into individual draw calls
586    this->INHERITED::drawPicture(picture);
587}
588
589void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
590                                 const SkPoint vertices[], const SkPoint texs[],
591                                 const SkColor colors[], SkXfermode*,
592                                 const uint16_t indices[], int indexCount,
593                                 const SkPaint& paint) {
594    if (0 == vertexCount) {
595        return;
596    }
597
598    NOTIFY_SETUP(this);
599    size_t size = 4 + vertexCount * sizeof(SkPoint);
600    this->writePaint(paint);
601    unsigned flags = 0;
602    if (texs) {
603        flags |= kDrawVertices_HasTexs_DrawOpFlag;
604        size += vertexCount * sizeof(SkPoint);
605    }
606    if (colors) {
607        flags |= kDrawVertices_HasColors_DrawOpFlag;
608        size += vertexCount * sizeof(SkColor);
609    }
610    if (indices && indexCount > 0) {
611        flags |= kDrawVertices_HasIndices_DrawOpFlag;
612        size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
613    }
614
615    if (this->needOpBytes(size)) {
616        this->writeOp(kDrawVertices_DrawOp, flags, 0);
617        fWriter.write32(mode);
618        fWriter.write32(vertexCount);
619        fWriter.write(vertices, vertexCount * sizeof(SkPoint));
620        if (texs) {
621            fWriter.write(texs, vertexCount * sizeof(SkPoint));
622        }
623        if (colors) {
624            fWriter.write(colors, vertexCount * sizeof(SkColor));
625        }
626
627        // TODO: flatten xfermode
628
629        if (indices && indexCount > 0) {
630            fWriter.write32(indexCount);
631            fWriter.writePad(indices, indexCount * sizeof(uint16_t));
632        }
633    }
634}
635
636void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
637    if (size && ptr) {
638        NOTIFY_SETUP(this);
639        unsigned data = 0;
640        if (size < (1 << DRAWOPS_DATA_BITS)) {
641            data = (unsigned)size;
642        }
643        if (this->needOpBytes(4 + SkAlign4(size))) {
644            this->writeOp(kDrawData_DrawOp, 0, data);
645            if (0 == data) {
646                fWriter.write32(size);
647            }
648            fWriter.writePad(ptr, size);
649        }
650    }
651}
652
653///////////////////////////////////////////////////////////////////////////////
654
655template <typename T> uint32_t castToU32(T value) {
656    union {
657        T           fSrc;
658        uint32_t    fDst;
659    } data;
660    data.fSrc = value;
661    return data.fDst;
662}
663
664void SkGPipeCanvas::writePaint(const SkPaint& paint) {
665    SkPaint& base = fPaint;
666    uint32_t storage[32];
667    uint32_t* ptr = storage;
668
669    if (base.getFlags() != paint.getFlags()) {
670        *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
671        base.setFlags(paint.getFlags());
672    }
673    if (base.getColor() != paint.getColor()) {
674        *ptr++ = PaintOp_packOp(kColor_PaintOp);
675        *ptr++ = paint.getColor();
676        base.setColor(paint.getColor());
677    }
678    if (base.getStyle() != paint.getStyle()) {
679        *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
680        base.setStyle(paint.getStyle());
681    }
682    if (base.getStrokeJoin() != paint.getStrokeJoin()) {
683        *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
684        base.setStrokeJoin(paint.getStrokeJoin());
685    }
686    if (base.getStrokeCap() != paint.getStrokeCap()) {
687        *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
688        base.setStrokeCap(paint.getStrokeCap());
689    }
690    if (base.getStrokeWidth() != paint.getStrokeWidth()) {
691        *ptr++ = PaintOp_packOp(kWidth_PaintOp);
692        *ptr++ = castToU32(paint.getStrokeWidth());
693        base.setStrokeWidth(paint.getStrokeWidth());
694    }
695    if (base.getStrokeMiter() != paint.getStrokeMiter()) {
696        *ptr++ = PaintOp_packOp(kMiter_PaintOp);
697        *ptr++ = castToU32(paint.getStrokeMiter());
698        base.setStrokeMiter(paint.getStrokeMiter());
699    }
700    if (base.getTextEncoding() != paint.getTextEncoding()) {
701        *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
702        base.setTextEncoding(paint.getTextEncoding());
703    }
704    if (base.getHinting() != paint.getHinting()) {
705        *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
706        base.setHinting(paint.getHinting());
707    }
708    if (base.getTextAlign() != paint.getTextAlign()) {
709        *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
710        base.setTextAlign(paint.getTextAlign());
711    }
712    if (base.getTextSize() != paint.getTextSize()) {
713        *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
714        *ptr++ = castToU32(paint.getTextSize());
715        base.setTextSize(paint.getTextSize());
716    }
717    if (base.getTextScaleX() != paint.getTextScaleX()) {
718        *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
719        *ptr++ = castToU32(paint.getTextScaleX());
720        base.setTextScaleX(paint.getTextScaleX());
721    }
722    if (base.getTextSkewX() != paint.getTextSkewX()) {
723        *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
724        *ptr++ = castToU32(paint.getTextSkewX());
725        base.setTextSkewX(paint.getTextSkewX());
726    }
727
728    if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
729        uint32_t id = this->getTypefaceID(paint.getTypeface());
730        *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
731        base.setTypeface(paint.getTypeface());
732    }
733
734    for (int i = 0; i < kCount_PaintFlats; i++) {
735        int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
736        SkASSERT(index >= 0 && index <= fFlatArray.count());
737        if (index != fCurrFlatIndex[i]) {
738            *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
739            fCurrFlatIndex[i] = index;
740        }
741    }
742
743    size_t size = (char*)ptr - (char*)storage;
744    if (size && this->needOpBytes(size)) {
745        this->writeOp(kPaintOp_DrawOp, 0, size);
746        fWriter.write(storage, size);
747        for (size_t i = 0; i < size/4; i++) {
748//            SkDebugf("[%d] %08X\n", i, storage[i]);
749        }
750    }
751}
752
753///////////////////////////////////////////////////////////////////////////////
754
755#include "SkGPipe.h"
756
757SkGPipeWriter::SkGPipeWriter() : fWriter(0) {
758    fCanvas = NULL;
759}
760
761SkGPipeWriter::~SkGPipeWriter() {
762    this->endRecording();
763    SkSafeUnref(fCanvas);
764}
765
766SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller,
767                                        uint32_t flags) {
768    if (NULL == fCanvas) {
769        fWriter.reset(NULL, 0);
770        fFactorySet.reset();
771        fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
772                                             (flags & kCrossProcess_Flag) ?
773                                             &fFactorySet : NULL));
774    }
775    return fCanvas;
776}
777
778void SkGPipeWriter::endRecording() {
779    if (fCanvas) {
780        fCanvas->finish();
781        fCanvas->unref();
782        fCanvas = NULL;
783    }
784}
785
786