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