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