• 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 #ifndef SkPictureFlat_DEFINED
9 #define SkPictureFlat_DEFINED
10 
11 //#define SK_DEBUG_SIZE
12 
13 #include "SkBitmap.h"
14 #include "SkBitmapHeap.h"
15 #include "SkChecksum.h"
16 #include "SkChunkAlloc.h"
17 #include "SkMatrix.h"
18 #include "SkOrderedReadBuffer.h"
19 #include "SkOrderedWriteBuffer.h"
20 #include "SkPaint.h"
21 #include "SkPath.h"
22 #include "SkPicture.h"
23 #include "SkPtrRecorder.h"
24 #include "SkRegion.h"
25 #include "SkTDynamicHash.h"
26 #include "SkTRefArray.h"
27 #include "SkTSearch.h"
28 
29 enum DrawType {
30     UNUSED,
31     CLIP_PATH,
32     CLIP_REGION,
33     CLIP_RECT,
34     CLIP_RRECT,
35     CONCAT,
36     DRAW_BITMAP,
37     DRAW_BITMAP_MATRIX,
38     DRAW_BITMAP_NINE,
39     DRAW_BITMAP_RECT_TO_RECT,
40     DRAW_CLEAR,
41     DRAW_DATA,
42     DRAW_OVAL,
43     DRAW_PAINT,
44     DRAW_PATH,
45     DRAW_PICTURE,
46     DRAW_POINTS,
47     DRAW_POS_TEXT,
48     DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
49     DRAW_POS_TEXT_H,
50     DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
51     DRAW_RECT,
52     DRAW_RRECT,
53     DRAW_SPRITE,
54     DRAW_TEXT,
55     DRAW_TEXT_ON_PATH,
56     DRAW_TEXT_TOP_BOTTOM,   // fast variant of DRAW_TEXT
57     DRAW_VERTICES,
58     RESTORE,
59     ROTATE,
60     SAVE,
61     SAVE_LAYER,
62     SCALE,
63     SET_MATRIX,
64     SKEW,
65     TRANSLATE,
66     NOOP,
67     BEGIN_COMMENT_GROUP,
68     COMMENT,
69     END_COMMENT_GROUP,
70 
71     LAST_DRAWTYPE_ENUM = END_COMMENT_GROUP
72 };
73 
74 // In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
75 static const int kDRAW_BITMAP_FLAVOR = LAST_DRAWTYPE_ENUM+1;
76 
77 enum DrawVertexFlags {
78     DRAW_VERTICES_HAS_TEXS    = 0x01,
79     DRAW_VERTICES_HAS_COLORS  = 0x02,
80     DRAW_VERTICES_HAS_INDICES = 0x04
81 };
82 
83 ///////////////////////////////////////////////////////////////////////////////
84 // clipparams are packed in 5 bits
85 //  doAA:1 | regionOp:4
86 
ClipParams_pack(SkRegion::Op op,bool doAA)87 static inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) {
88     unsigned doAABit = doAA ? 1 : 0;
89     return (doAABit << 4) | op;
90 }
91 
ClipParams_unpackRegionOp(uint32_t packed)92 static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) {
93     return (SkRegion::Op)(packed & 0xF);
94 }
95 
ClipParams_unpackDoAA(uint32_t packed)96 static inline bool ClipParams_unpackDoAA(uint32_t packed) {
97     return SkToBool((packed >> 4) & 1);
98 }
99 
100 ///////////////////////////////////////////////////////////////////////////////
101 
102 class SkTypefacePlayback {
103 public:
104     SkTypefacePlayback();
105     virtual ~SkTypefacePlayback();
106 
count()107     int count() const { return fCount; }
108 
109     void reset(const SkRefCntSet*);
110 
111     void setCount(int count);
112     SkRefCnt* set(int index, SkRefCnt*);
113 
setupBuffer(SkOrderedReadBuffer & buffer)114     void setupBuffer(SkOrderedReadBuffer& buffer) const {
115         buffer.setTypefaceArray((SkTypeface**)fArray, fCount);
116     }
117 
118 protected:
119     int fCount;
120     SkRefCnt** fArray;
121 };
122 
123 class SkFactoryPlayback {
124 public:
SkFactoryPlayback(int count)125     SkFactoryPlayback(int count) : fCount(count) {
126         fArray = SkNEW_ARRAY(SkFlattenable::Factory, count);
127     }
128 
~SkFactoryPlayback()129     ~SkFactoryPlayback() {
130         SkDELETE_ARRAY(fArray);
131     }
132 
base()133     SkFlattenable::Factory* base() const { return fArray; }
134 
setupBuffer(SkOrderedReadBuffer & buffer)135     void setupBuffer(SkOrderedReadBuffer& buffer) const {
136         buffer.setFactoryPlayback(fArray, fCount);
137     }
138 
139 private:
140     int fCount;
141     SkFlattenable::Factory* fArray;
142 };
143 
144 ///////////////////////////////////////////////////////////////////////////////
145 //
146 //
147 // The following templated classes provide an efficient way to store and compare
148 // objects that have been flattened (i.e. serialized in an ordered binary
149 // format).
150 //
151 // SkFlatData:       is a simple indexable container for the flattened data
152 //                   which is agnostic to the type of data is is indexing. It is
153 //                   also responsible for flattening/unflattening objects but
154 //                   details of that operation are hidden in the provided procs
155 // SkFlatDictionary: is an abstract templated dictionary that maintains a
156 //                   searchable set of SkFlatData objects of type T.
157 // SkFlatController: is an interface provided to SkFlatDictionary which handles
158 //                   allocation (and unallocation in some cases). It also holds
159 //                   ref count recorders and the like.
160 //
161 // NOTE: any class that wishes to be used in conjunction with SkFlatDictionary
162 // must subclass the dictionary and provide the necessary flattening procs.
163 // The end of this header contains dictionary subclasses for some common classes
164 // like SkBitmap, SkMatrix, SkPaint, and SkRegion. SkFlatController must also
165 // be implemented, or SkChunkFlatController can be used to use an
166 // SkChunkAllocator and never do replacements.
167 //
168 //
169 ///////////////////////////////////////////////////////////////////////////////
170 
171 class SkFlatData;
172 
173 class SkFlatController : public SkRefCnt {
174 public:
175     SK_DECLARE_INST_COUNT(SkFlatController)
176 
177     SkFlatController();
178     virtual ~SkFlatController();
179     /**
180      * Return a new block of memory for the SkFlatDictionary to use.
181      * This memory is owned by the controller and has the same lifetime unless you
182      * call unalloc(), in which case it may be freed early.
183      */
184     virtual void* allocThrow(size_t bytes) = 0;
185 
186     /**
187      * Hint that this block, which was allocated with allocThrow, is no longer needed.
188      * The implementation may choose to free this memory any time beteween now and destruction.
189      */
190     virtual void unalloc(void* ptr) = 0;
191 
192     /**
193      * Used during creation and unflattening of SkFlatData objects. If the
194      * objects being flattened contain bitmaps they are stored in this heap
195      * and the flattenable stores the index to the bitmap on the heap.
196      * This should be set by the protected setBitmapHeap.
197      */
getBitmapHeap()198     SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; }
199 
200     /**
201      * Used during creation of SkFlatData objects. If a typeface recorder is
202      * required to flatten the objects being flattened (i.e. for SkPaints), this
203      * should be set by the protected setTypefaceSet.
204      */
getTypefaceSet()205     SkRefCntSet* getTypefaceSet() { return fTypefaceSet; }
206 
207     /**
208      * Used during unflattening of the SkFlatData objects in the
209      * SkFlatDictionary. Needs to be set by the protected setTypefacePlayback
210      * and needs to be reset to the SkRefCntSet passed to setTypefaceSet.
211      */
getTypefacePlayback()212     SkTypefacePlayback* getTypefacePlayback() { return fTypefacePlayback; }
213 
214     /**
215      * Optional factory recorder used during creation of SkFlatData objects. Set
216      * using the protected method setNamedFactorySet.
217      */
getNamedFactorySet()218     SkNamedFactorySet* getNamedFactorySet() { return fFactorySet; }
219 
220     /**
221      * Flags to use during creation of SkFlatData objects. Defaults to zero.
222      */
getWriteBufferFlags()223     uint32_t getWriteBufferFlags() { return fWriteBufferFlags; }
224 
225 protected:
226     /**
227      * Set an SkBitmapHeap to be used to store/read SkBitmaps. Ref counted.
228      */
229     void setBitmapHeap(SkBitmapHeap*);
230 
231     /**
232      * Set an SkRefCntSet to be used to store SkTypefaces during flattening. Ref
233      * counted.
234      */
235     void setTypefaceSet(SkRefCntSet*);
236 
237     /**
238      * Set an SkTypefacePlayback to be used to find references to SkTypefaces
239      * during unflattening. Should be reset to the set provided to
240      * setTypefaceSet.
241      */
242     void setTypefacePlayback(SkTypefacePlayback*);
243 
244     /**
245      * Set an SkNamedFactorySet to be used to store Factorys and their
246      * corresponding names during flattening. Ref counted. Returns the same
247      * set as a convenience.
248      */
249     SkNamedFactorySet* setNamedFactorySet(SkNamedFactorySet*);
250 
251     /**
252      * Set the flags to be used during flattening.
253      */
setWriteBufferFlags(uint32_t flags)254     void setWriteBufferFlags(uint32_t flags) { fWriteBufferFlags = flags; }
255 
256 private:
257     SkBitmapHeap*       fBitmapHeap;
258     SkRefCntSet*        fTypefaceSet;
259     SkTypefacePlayback* fTypefacePlayback;
260     SkNamedFactorySet*  fFactorySet;
261     uint32_t            fWriteBufferFlags;
262 
263     typedef SkRefCnt INHERITED;
264 };
265 
266 class SkFlatData {
267 public:
268     // Flatten obj into an SkFlatData with this index.  controller owns the SkFlatData*.
269     static SkFlatData* Create(SkFlatController* controller,
270                               const void* obj,
271                               int index,
272                               void (*flattenProc)(SkOrderedWriteBuffer&, const void*));
273 
274     // Unflatten this into result, using bitmapHeap and facePlayback for bitmaps and fonts if given.
275     void unflatten(void* result,
276                    void (*unflattenProc)(SkOrderedReadBuffer&, void*),
277                    SkBitmapHeap* bitmapHeap = NULL,
278                    SkTypefacePlayback* facePlayback = NULL) const;
279 
280     // Do these contain the same data?  Ignores index() and topBot().
281     bool operator==(const SkFlatData& that) const {
282         if (this->checksum() != that.checksum() || this->flatSize() != that.flatSize()) {
283             return false;
284         }
285         return memcmp(this->data(), that.data(), this->flatSize()) == 0;
286     }
287 
index()288     int index() const { return fIndex; }
data()289     const uint8_t* data() const { return (const uint8_t*)this + sizeof(*this); }
flatSize()290     size_t flatSize() const { return fFlatSize; }
checksum()291     uint32_t checksum() const { return fChecksum; }
292 
293     // Returns true if fTopBot[] has been recorded.
isTopBotWritten()294     bool isTopBotWritten() const {
295         return !SkScalarIsNaN(fTopBot[0]);
296     }
297 
298     // Returns fTopBot array, so it can be passed to a routine to compute them.
299     // For efficiency, we assert that fTopBot have not been recorded yet.
writableTopBot()300     SkScalar* writableTopBot() const {
301         SkASSERT(!this->isTopBotWritten());
302         return fTopBot;
303     }
304 
305     // Return the topbot[] after it has been recorded.
topBot()306     const SkScalar* topBot() const {
307         SkASSERT(this->isTopBotWritten());
308         return fTopBot;
309     }
310 
311 private:
312     // For SkTDynamicHash.
Identity(const SkFlatData & flat)313     static const SkFlatData& Identity(const SkFlatData& flat) { return flat; }
Hash(const SkFlatData & flat)314     static uint32_t Hash(const SkFlatData& flat) { return flat.checksum(); }
Equal(const SkFlatData & a,const SkFlatData & b)315     static bool Equal(const SkFlatData& a, const SkFlatData& b) { return a == b; }
316 
setIndex(int index)317     void setIndex(int index) { fIndex = index; }
data()318     uint8_t* data() { return (uint8_t*)this + sizeof(*this); }
319 
320     // This assumes the payload flat data has already been written and does not modify it.
stampHeader(int index,int32_t size)321     void stampHeader(int index, int32_t size) {
322         SkASSERT(SkIsAlign4(size));
323         fIndex     = index;
324         fFlatSize  = size;
325         fTopBot[0] = SK_ScalarNaN;  // Mark as unwritten.
326         fChecksum  = SkChecksum::Compute((uint32_t*)this->data(), size);
327     }
328 
329     int fIndex;
330     int32_t fFlatSize;
331     uint32_t fChecksum;
332     mutable SkScalar fTopBot[2];  // Cache of FontMetrics fTop, fBottom.  Starts as [NaN,?].
333     // uint32_t flattenedData[] implicitly hangs off the end.
334 
335     template <class T> friend class SkFlatDictionary;
336 };
337 
338 template <class T>
339 class SkFlatDictionary {
340     static const size_t kWriteBufferGrowthBytes = 1024;
341 
342 public:
343     SkFlatDictionary(SkFlatController* controller, size_t scratchSizeGuess = 0)
fFlattenProc(NULL)344     : fFlattenProc(NULL)
345     , fUnflattenProc(NULL)
346     , fController(SkRef(controller))
347     , fScratchSize(scratchSizeGuess)
348     , fScratch(AllocScratch(fScratchSize))
349     , fWriteBuffer(kWriteBufferGrowthBytes)
350     , fWriteBufferReady(false) {
351         this->reset();
352     }
353 
354     /**
355      * Clears the dictionary of all entries. However, it does NOT free the
356      * memory that was allocated for each entry (that's owned by controller).
357      */
reset()358     void reset() {
359         fIndexedData.rewind();
360         // TODO(mtklein): There's no reason to have the index start from 1.  Clean this up.
361         // index 0 is always empty since it is used as a signal that find failed
362         fIndexedData.push(NULL);
363         fNextIndex = 1;
364     }
365 
~SkFlatDictionary()366     ~SkFlatDictionary() {
367         sk_free(fScratch);
368     }
369 
count()370     int count() const {
371         SkASSERT(fIndexedData.count() == fNextIndex);
372         SkASSERT(fHash.count() == fNextIndex - 1);
373         return fNextIndex - 1;
374     }
375 
376     // For testing only.  Index is zero-based.
377     const SkFlatData* operator[](int index) {
378         return fIndexedData[index+1];
379     }
380 
381     /**
382      * Given an element of type T return its 1-based index in the dictionary. If
383      * the element wasn't previously in the dictionary it is automatically
384      * added.
385      *
386      */
find(const T & element)387     int find(const T& element) {
388         return this->findAndReturnFlat(element)->index();
389     }
390 
391     /**
392      * Similar to find. Allows the caller to specify an SkFlatData to replace in
393      * the case of an add. Also tells the caller whether a new SkFlatData was
394      * added and whether the old one was replaced. The parameters added and
395      * replaced are required to be non-NULL. Rather than returning the index of
396      * the entry in the dictionary, it returns the actual SkFlatData.
397      */
findAndReplace(const T & element,const SkFlatData * toReplace,bool * added,bool * replaced)398     const SkFlatData* findAndReplace(const T& element,
399                                      const SkFlatData* toReplace,
400                                      bool* added,
401                                      bool* replaced) {
402         SkASSERT(added != NULL && replaced != NULL);
403 
404         const int oldCount = this->count();
405         SkFlatData* flat = this->findAndReturnMutableFlat(element);
406         *added = this->count() > oldCount;
407 
408         // If we don't want to replace anything, we're done.
409         if (!*added || toReplace == NULL) {
410             *replaced = false;
411             return flat;
412         }
413 
414         // If we don't have the thing to replace, we're done.
415         const SkFlatData* found = fHash.find(*toReplace);
416         if (found == NULL) {
417             *replaced = false;
418             return flat;
419         }
420 
421         // findAndReturnMutableFlat gave us index (fNextIndex-1), but we'll use the old one.
422         fIndexedData.remove(flat->index());
423         fNextIndex--;
424         flat->setIndex(found->index());
425         fIndexedData[flat->index()] = flat;
426 
427         // findAndReturnMutableFlat already called fHash.add(), so we just clean up the old entry.
428         fHash.remove(*found);
429         fController->unalloc((void*)found);
430         SkASSERT(this->count() == oldCount);
431 
432         *replaced = true;
433         return flat;
434     }
435 
436     /**
437      *  Unflatten the objects and return them in SkTRefArray, or return NULL
438      *  if there no objects.  Caller takes ownership of result.
439      */
unflattenToArray()440     SkTRefArray<T>* unflattenToArray() const {
441         const int count = this->count();
442         if (count == 0) {
443             return NULL;
444         }
445         SkTRefArray<T>* array = SkTRefArray<T>::Create(count);
446         for (int i = 0; i < count; i++) {
447             this->unflatten(&array->writableAt(i), fIndexedData[i+1]);
448         }
449         return array;
450     }
451 
452     /**
453      * Unflatten the specific object at the given index.
454      * Caller takes ownership of the result.
455      */
unflatten(int index)456     T* unflatten(int index) const {
457         const SkFlatData* element = fIndexedData[index];
458         SkASSERT(index == element->index());
459 
460         T* dst = new T;
461         this->unflatten(dst, element);
462         return dst;
463     }
464 
465     /**
466      * Find or insert a flattened version of element into the dictionary.
467      * Caller does not take ownership of the result.  This will not return NULL.
468      */
findAndReturnFlat(const T & element)469     const SkFlatData* findAndReturnFlat(const T& element) {
470         return this->findAndReturnMutableFlat(element);
471     }
472 
473 protected:
474     void (*fFlattenProc)(SkOrderedWriteBuffer&, const void*);
475     void (*fUnflattenProc)(SkOrderedReadBuffer&, void*);
476 
477 private:
478     // Layout: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ]
SizeWithPadding(size_t flatDataSize)479     static size_t SizeWithPadding(size_t flatDataSize) {
480         SkASSERT(SkIsAlign4(flatDataSize));
481         return sizeof(SkFlatData) + flatDataSize;
482     }
483 
484     // Allocate a new scratch SkFlatData.  Must be sk_freed.
AllocScratch(size_t scratchSize)485     static SkFlatData* AllocScratch(size_t scratchSize) {
486         return (SkFlatData*) sk_malloc_throw(SizeWithPadding(scratchSize));
487     }
488 
489     // We have to delay fWriteBuffer's initialization until its first use; fController might not
490     // be fully set up by the time we get it in the constructor.
lazyWriteBufferInit()491     void lazyWriteBufferInit() {
492         if (fWriteBufferReady) {
493             return;
494         }
495         // Without a bitmap heap, we'll flatten bitmaps into paints.  That's never what you want.
496         SkASSERT(fController->getBitmapHeap() != NULL);
497         fWriteBuffer.setBitmapHeap(fController->getBitmapHeap());
498         fWriteBuffer.setTypefaceRecorder(fController->getTypefaceSet());
499         fWriteBuffer.setNamedFactoryRecorder(fController->getNamedFactorySet());
500         fWriteBuffer.setFlags(fController->getWriteBufferFlags());
501         fWriteBufferReady = true;
502     }
503 
504     // As findAndReturnFlat, but returns a mutable pointer for internal use.
findAndReturnMutableFlat(const T & element)505     SkFlatData* findAndReturnMutableFlat(const T& element) {
506         // Only valid until the next call to resetScratch().
507         const SkFlatData& scratch = this->resetScratch(element, fNextIndex);
508 
509         SkFlatData* candidate = fHash.find(scratch);
510         if (candidate != NULL) return candidate;
511 
512         SkFlatData* detached = this->detachScratch();
513         fHash.add(detached);
514         *fIndexedData.insert(fNextIndex) = detached;
515         fNextIndex++;
516         return detached;
517     }
518 
519     // This reference is valid only until the next call to resetScratch() or detachScratch().
resetScratch(const T & element,int index)520     const SkFlatData& resetScratch(const T& element, int index) {
521         this->lazyWriteBufferInit();
522 
523         // Flatten element into fWriteBuffer (using fScratch as storage).
524         fWriteBuffer.reset(fScratch->data(), fScratchSize);
525         fFlattenProc(fWriteBuffer, &element);
526         const size_t bytesWritten = fWriteBuffer.bytesWritten();
527 
528         // If all the flattened bytes fit into fScratch, we can skip a call to writeToMemory.
529         if (!fWriteBuffer.wroteOnlyToStorage()) {
530             SkASSERT(bytesWritten > fScratchSize);
531             // It didn't all fit.  Copy into a larger replacement SkFlatData.
532             // We can't just realloc because it might move the pointer and confuse writeToMemory.
533             SkFlatData* larger = AllocScratch(bytesWritten);
534             fWriteBuffer.writeToMemory(larger->data());
535 
536             // Carry on with this larger scratch to minimize the likelihood of future resizing.
537             sk_free(fScratch);
538             fScratchSize = bytesWritten;
539             fScratch = larger;
540         }
541 
542         // The data is in fScratch now but we need to stamp its header.
543         fScratch->stampHeader(index, bytesWritten);
544         return *fScratch;
545     }
546 
547     // This result is owned by fController and lives as long as it does (unless unalloc'd).
detachScratch()548     SkFlatData* detachScratch() {
549         // Allocate a new SkFlatData exactly big enough to hold our current scratch.
550         // We use the controller for this allocation to extend the allocation's lifetime and allow
551         // the controller to do whatever memory management it wants.
552         const size_t paddedSize = SizeWithPadding(fScratch->flatSize());
553         SkFlatData* detached = (SkFlatData*)fController->allocThrow(paddedSize);
554 
555         // Copy scratch into the new SkFlatData.
556         memcpy(detached, fScratch, paddedSize);
557 
558         // We can now reuse fScratch, and detached will live until fController dies.
559         return detached;
560     }
561 
unflatten(T * dst,const SkFlatData * element)562     void unflatten(T* dst, const SkFlatData* element) const {
563         element->unflatten(dst,
564                            fUnflattenProc,
565                            fController->getBitmapHeap(),
566                            fController->getTypefacePlayback());
567     }
568 
569     // All SkFlatData* stored in fIndexedData and fHash are owned by the controller.
570     SkAutoTUnref<SkFlatController> fController;
571     size_t fScratchSize;  // How many bytes fScratch has allocated for data itself.
572     SkFlatData* fScratch;  // Owned, must be freed with sk_free.
573     SkOrderedWriteBuffer fWriteBuffer;
574     bool fWriteBufferReady;
575 
576     // We map between SkFlatData and a 1-based integer index.
577     int fNextIndex;
578 
579     // For index -> SkFlatData.  fIndexedData[0] is always NULL.
580     SkTDArray<const SkFlatData*> fIndexedData;
581 
582     // For SkFlatData -> cached SkFlatData, which has index().
583     SkTDynamicHash<SkFlatData, SkFlatData,
584                    SkFlatData::Identity, SkFlatData::Hash, SkFlatData::Equal> fHash;
585 };
586 
587 ///////////////////////////////////////////////////////////////////////////////
588 // Some common dictionaries are defined here for both reference and convenience
589 ///////////////////////////////////////////////////////////////////////////////
590 
591 template <class T>
SkFlattenObjectProc(SkOrderedWriteBuffer & buffer,const void * obj)592 static void SkFlattenObjectProc(SkOrderedWriteBuffer& buffer, const void* obj) {
593     ((T*)obj)->flatten(buffer);
594 }
595 
596 template <class T>
SkUnflattenObjectProc(SkOrderedReadBuffer & buffer,void * obj)597 static void SkUnflattenObjectProc(SkOrderedReadBuffer& buffer, void* obj) {
598     ((T*)obj)->unflatten(buffer);
599 }
600 
601 class SkChunkFlatController : public SkFlatController {
602 public:
SkChunkFlatController(size_t minSize)603     SkChunkFlatController(size_t minSize)
604     : fHeap(minSize)
605     , fTypefaceSet(SkNEW(SkRefCntSet))
606     , fLastAllocated(NULL) {
607         this->setTypefaceSet(fTypefaceSet);
608         this->setTypefacePlayback(&fTypefacePlayback);
609     }
610 
allocThrow(size_t bytes)611     virtual void* allocThrow(size_t bytes) SK_OVERRIDE {
612         fLastAllocated = fHeap.allocThrow(bytes);
613         return fLastAllocated;
614     }
615 
unalloc(void * ptr)616     virtual void unalloc(void* ptr) SK_OVERRIDE {
617         // fHeap can only free a pointer if it was the last one allocated.  Otherwise, we'll just
618         // have to wait until fHeap is destroyed.
619         if (ptr == fLastAllocated) (void)fHeap.unalloc(ptr);
620     }
621 
setupPlaybacks()622     void setupPlaybacks() const {
623         fTypefacePlayback.reset(fTypefaceSet.get());
624     }
625 
setBitmapStorage(SkBitmapHeap * heap)626     void setBitmapStorage(SkBitmapHeap* heap) {
627         this->setBitmapHeap(heap);
628     }
629 
630 private:
631     SkChunkAlloc               fHeap;
632     SkAutoTUnref<SkRefCntSet>  fTypefaceSet;
633     void*                      fLastAllocated;
634     mutable SkTypefacePlayback fTypefacePlayback;
635 };
636 
637 class SkMatrixDictionary : public SkFlatDictionary<SkMatrix> {
638  public:
639     // All matrices fit in 36 bytes.
SkMatrixDictionary(SkFlatController * controller)640     SkMatrixDictionary(SkFlatController* controller)
641     : SkFlatDictionary<SkMatrix>(controller, 36) {
642         fFlattenProc = &flattenMatrix;
643         fUnflattenProc = &unflattenMatrix;
644     }
645 
flattenMatrix(SkOrderedWriteBuffer & buffer,const void * obj)646     static void flattenMatrix(SkOrderedWriteBuffer& buffer, const void* obj) {
647         buffer.getWriter32()->writeMatrix(*(SkMatrix*)obj);
648     }
649 
unflattenMatrix(SkOrderedReadBuffer & buffer,void * obj)650     static void unflattenMatrix(SkOrderedReadBuffer& buffer, void* obj) {
651         buffer.getReader32()->readMatrix((SkMatrix*)obj);
652     }
653 };
654 
655 class SkPaintDictionary : public SkFlatDictionary<SkPaint> {
656  public:
657     // The largest paint across ~60 .skps was 500 bytes.
SkPaintDictionary(SkFlatController * controller)658     SkPaintDictionary(SkFlatController* controller)
659     : SkFlatDictionary<SkPaint>(controller, 512) {
660         fFlattenProc = &SkFlattenObjectProc<SkPaint>;
661         fUnflattenProc = &SkUnflattenObjectProc<SkPaint>;
662     }
663 };
664 
665 class SkRegionDictionary : public SkFlatDictionary<SkRegion> {
666  public:
SkRegionDictionary(SkFlatController * controller)667     SkRegionDictionary(SkFlatController* controller)
668     : SkFlatDictionary<SkRegion>(controller) {
669         fFlattenProc = &flattenRegion;
670         fUnflattenProc = &unflattenRegion;
671     }
672 
flattenRegion(SkOrderedWriteBuffer & buffer,const void * obj)673     static void flattenRegion(SkOrderedWriteBuffer& buffer, const void* obj) {
674         buffer.getWriter32()->writeRegion(*(SkRegion*)obj);
675     }
676 
unflattenRegion(SkOrderedReadBuffer & buffer,void * obj)677     static void unflattenRegion(SkOrderedReadBuffer& buffer, void* obj) {
678         buffer.getReader32()->readRegion((SkRegion*)obj);
679     }
680 };
681 
682 #endif
683