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 
12 #include "SkBitmapHeap.h"
13 #include "SkChecksum.h"
14 #include "SkChunkAlloc.h"
15 #include "SkReadBuffer.h"
16 #include "SkWriteBuffer.h"
17 #include "SkPaint.h"
18 #include "SkPicture.h"
19 #include "SkPtrRecorder.h"
20 #include "SkTDynamicHash.h"
21 
22 enum DrawType {
23     UNUSED,
24     CLIP_PATH,
25     CLIP_REGION,
26     CLIP_RECT,
27     CLIP_RRECT,
28     CONCAT,
29     DRAW_BITMAP,
30     DRAW_BITMAP_MATRIX, // deprecated, M41 was last Chromium version to write this to an .skp
31     DRAW_BITMAP_NINE,
32     DRAW_BITMAP_RECT_TO_RECT,
33     DRAW_CLEAR,
34     DRAW_DATA,
35     DRAW_OVAL,
36     DRAW_PAINT,
37     DRAW_PATH,
38     DRAW_PICTURE,
39     DRAW_POINTS,
40     DRAW_POS_TEXT,
41     DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
42     DRAW_POS_TEXT_H,
43     DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
44     DRAW_RECT,
45     DRAW_RRECT,
46     DRAW_SPRITE,
47     DRAW_TEXT,
48     DRAW_TEXT_ON_PATH,
49     DRAW_TEXT_TOP_BOTTOM,   // fast variant of DRAW_TEXT
50     DRAW_VERTICES,
51     RESTORE,
52     ROTATE,
53     SAVE,
54     SAVE_LAYER,
55     SCALE,
56     SET_MATRIX,
57     SKEW,
58     TRANSLATE,
59     NOOP,
60     BEGIN_COMMENT_GROUP,
61     COMMENT,
62     END_COMMENT_GROUP,
63 
64     // new ops -- feel free to re-alphabetize on next version bump
65     DRAW_DRRECT,
66     PUSH_CULL,  // deprecated, M41 was last Chromium version to write this to an .skp
67     POP_CULL,   // deprecated, M41 was last Chromium version to write this to an .skp
68 
69     DRAW_PATCH, // could not add in aphabetical order
70     DRAW_PICTURE_MATRIX_PAINT,
71     DRAW_TEXT_BLOB,
72 
73     LAST_DRAWTYPE_ENUM = DRAW_TEXT_BLOB
74 };
75 
76 // In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
77 static const int kDRAW_BITMAP_FLAVOR = LAST_DRAWTYPE_ENUM+1;
78 
79 enum DrawVertexFlags {
80     DRAW_VERTICES_HAS_TEXS    = 0x01,
81     DRAW_VERTICES_HAS_COLORS  = 0x02,
82     DRAW_VERTICES_HAS_INDICES = 0x04,
83     DRAW_VERTICES_HAS_XFER    = 0x08,
84 };
85 
86 ///////////////////////////////////////////////////////////////////////////////
87 // clipparams are packed in 5 bits
88 //  doAA:1 | regionOp:4
89 
ClipParams_pack(SkRegion::Op op,bool doAA)90 static inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) {
91     unsigned doAABit = doAA ? 1 : 0;
92     return (doAABit << 4) | op;
93 }
94 
ClipParams_unpackRegionOp(uint32_t packed)95 static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) {
96     return (SkRegion::Op)(packed & 0xF);
97 }
98 
ClipParams_unpackDoAA(uint32_t packed)99 static inline bool ClipParams_unpackDoAA(uint32_t packed) {
100     return SkToBool((packed >> 4) & 1);
101 }
102 
103 ///////////////////////////////////////////////////////////////////////////////
104 
105 class SkTypefacePlayback {
106 public:
107     SkTypefacePlayback();
108     virtual ~SkTypefacePlayback();
109 
count()110     int count() const { return fCount; }
111 
112     void reset(const SkRefCntSet*);
113 
114     void setCount(int count);
115     SkRefCnt* set(int index, SkRefCnt*);
116 
setupBuffer(SkReadBuffer & buffer)117     void setupBuffer(SkReadBuffer& buffer) const {
118         buffer.setTypefaceArray((SkTypeface**)fArray, fCount);
119     }
120 
121 protected:
122     int fCount;
123     SkRefCnt** fArray;
124 };
125 
126 class SkFactoryPlayback {
127 public:
SkFactoryPlayback(int count)128     SkFactoryPlayback(int count) : fCount(count) {
129         fArray = SkNEW_ARRAY(SkFlattenable::Factory, count);
130     }
131 
~SkFactoryPlayback()132     ~SkFactoryPlayback() {
133         SkDELETE_ARRAY(fArray);
134     }
135 
base()136     SkFlattenable::Factory* base() const { return fArray; }
137 
setupBuffer(SkReadBuffer & buffer)138     void setupBuffer(SkReadBuffer& buffer) const {
139         buffer.setFactoryPlayback(fArray, fCount);
140     }
141 
142 private:
143     int fCount;
144     SkFlattenable::Factory* fArray;
145 };
146 
147 ///////////////////////////////////////////////////////////////////////////////
148 //
149 //
150 // The following templated classes provide an efficient way to store and compare
151 // objects that have been flattened (i.e. serialized in an ordered binary
152 // format).
153 //
154 // SkFlatData:       is a simple indexable container for the flattened data
155 //                   which is agnostic to the type of data is is indexing. It is
156 //                   also responsible for flattening/unflattening objects but
157 //                   details of that operation are hidden in the provided traits
158 // SkFlatDictionary: is an abstract templated dictionary that maintains a
159 //                   searchable set of SkFlatData objects of type T.
160 // SkFlatController: is an interface provided to SkFlatDictionary which handles
161 //                   allocation (and unallocation in some cases). It also holds
162 //                   ref count recorders and the like.
163 //
164 // NOTE: any class that wishes to be used in conjunction with SkFlatDictionary must subclass the
165 // dictionary and provide the necessary flattening traits.  SkFlatController must also be
166 // implemented, or SkChunkFlatController can be used to use an SkChunkAllocator and never do
167 // replacements.
168 //
169 //
170 ///////////////////////////////////////////////////////////////////////////////
171 
172 class SkFlatData;
173 
174 class SkFlatController : public SkRefCnt {
175 public:
176     SK_DECLARE_INST_COUNT(SkFlatController)
177 
178     SkFlatController(uint32_t writeBufferFlags = 0);
179     virtual ~SkFlatController();
180     /**
181      * Return a new block of memory for the SkFlatDictionary to use.
182      * This memory is owned by the controller and has the same lifetime unless you
183      * call unalloc(), in which case it may be freed early.
184      */
185     virtual void* allocThrow(size_t bytes) = 0;
186 
187     /**
188      * Hint that this block, which was allocated with allocThrow, is no longer needed.
189      * The implementation may choose to free this memory any time beteween now and destruction.
190      */
191     virtual void unalloc(void* ptr) = 0;
192 
193     /**
194      * Used during creation and unflattening of SkFlatData objects. If the
195      * objects being flattened contain bitmaps they are stored in this heap
196      * and the flattenable stores the index to the bitmap on the heap.
197      * This should be set by the protected setBitmapHeap.
198      */
getBitmapHeap()199     SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; }
200 
201     /**
202      * Used during creation of SkFlatData objects. If a typeface recorder is
203      * required to flatten the objects being flattened (i.e. for SkPaints), this
204      * should be set by the protected setTypefaceSet.
205      */
getTypefaceSet()206     SkRefCntSet* getTypefaceSet() { return fTypefaceSet; }
207 
208     /**
209      * Used during unflattening of the SkFlatData objects in the
210      * SkFlatDictionary. Needs to be set by the protected setTypefacePlayback
211      * and needs to be reset to the SkRefCntSet passed to setTypefaceSet.
212      */
getTypefacePlayback()213     SkTypefacePlayback* getTypefacePlayback() { return fTypefacePlayback; }
214 
215     /**
216      * Optional factory recorder used during creation of SkFlatData objects. Set
217      * using the protected method setNamedFactorySet.
218      */
getNamedFactorySet()219     SkNamedFactorySet* getNamedFactorySet() { return fFactorySet; }
220 
221     /**
222      * Flags to use during creation of SkFlatData objects. Defaults to zero.
223      */
getWriteBufferFlags()224     uint32_t getWriteBufferFlags() { return fWriteBufferFlags; }
225 
226 protected:
227     /**
228      * Set an SkBitmapHeap to be used to store/read SkBitmaps. Ref counted.
229      */
230     void setBitmapHeap(SkBitmapHeap*);
231 
232     /**
233      * Set an SkRefCntSet to be used to store SkTypefaces during flattening. Ref
234      * counted.
235      */
236     void setTypefaceSet(SkRefCntSet*);
237 
238     /**
239      * Set an SkTypefacePlayback to be used to find references to SkTypefaces
240      * during unflattening. Should be reset to the set provided to
241      * setTypefaceSet.
242      */
243     void setTypefacePlayback(SkTypefacePlayback*);
244 
245     /**
246      * Set an SkNamedFactorySet to be used to store Factorys and their
247      * corresponding names during flattening. Ref counted. Returns the same
248      * set as a convenience.
249      */
250     SkNamedFactorySet* setNamedFactorySet(SkNamedFactorySet*);
251 
252 private:
253     SkBitmapHeap*       fBitmapHeap;
254     SkRefCntSet*        fTypefaceSet;
255     SkTypefacePlayback* fTypefacePlayback;
256     SkNamedFactorySet*  fFactorySet;
257     const uint32_t      fWriteBufferFlags;
258 
259     typedef SkRefCnt INHERITED;
260 };
261 
262 class SkFlatData {
263 public:
264     // Flatten obj into an SkFlatData with this index.  controller owns the SkFlatData*.
265     template <typename Traits, typename T>
Create(SkFlatController * controller,const T & obj,int index)266     static SkFlatData* Create(SkFlatController* controller, const T& obj, int index) {
267         // A buffer of 256 bytes should fit most paints, regions, and matrices.
268         uint32_t storage[64];
269         SkWriteBuffer buffer(storage, sizeof(storage), controller->getWriteBufferFlags());
270 
271         buffer.setBitmapHeap(controller->getBitmapHeap());
272         buffer.setTypefaceRecorder(controller->getTypefaceSet());
273         buffer.setNamedFactoryRecorder(controller->getNamedFactorySet());
274 
275         Traits::Flatten(buffer, obj);
276         size_t size = buffer.bytesWritten();
277         SkASSERT(SkIsAlign4(size));
278 
279         // Allocate enough memory to hold SkFlatData struct and the flat data itself.
280         size_t allocSize = sizeof(SkFlatData) + size;
281         SkFlatData* result = (SkFlatData*) controller->allocThrow(allocSize);
282 
283         // Put the serialized contents into the data section of the new allocation.
284         buffer.writeToMemory(result->data());
285         // Stamp the index, size and checksum in the header.
286         result->stampHeader(index, SkToS32(size));
287         return result;
288     }
289 
290     // Unflatten this into result, using bitmapHeap and facePlayback for bitmaps and fonts if given
291     template <typename Traits, typename T>
292     void unflatten(T* result,
293                    SkBitmapHeap* bitmapHeap = NULL,
294                    SkTypefacePlayback* facePlayback = NULL) const {
295         SkReadBuffer buffer(this->data(), fFlatSize);
296 
297         if (bitmapHeap) {
298             buffer.setBitmapStorage(bitmapHeap);
299         }
300         if (facePlayback) {
301             facePlayback->setupBuffer(buffer);
302         }
303 
304         Traits::Unflatten(buffer, result);
305         SkASSERT(fFlatSize == (int32_t)buffer.offset());
306     }
307 
308     // Do these contain the same data?  Ignores index() and topBot().
309     bool operator==(const SkFlatData& that) const {
310         if (this->checksum() != that.checksum() || this->flatSize() != that.flatSize()) {
311             return false;
312         }
313         return memcmp(this->data(), that.data(), this->flatSize()) == 0;
314     }
315 
index()316     int index() const { return fIndex; }
data()317     const uint8_t* data() const { return (const uint8_t*)this + sizeof(*this); }
flatSize()318     size_t flatSize() const { return fFlatSize; }
checksum()319     uint32_t checksum() const { return fChecksum; }
320 
321     // Returns true if fTopBot[] has been recorded.
isTopBotWritten()322     bool isTopBotWritten() const {
323         return !SkScalarIsNaN(fTopBot[0]);
324     }
325 
326     // Returns fTopBot array, so it can be passed to a routine to compute them.
327     // For efficiency, we assert that fTopBot have not been recorded yet.
writableTopBot()328     SkScalar* writableTopBot() const {
329         SkASSERT(!this->isTopBotWritten());
330         return fTopBot;
331     }
332 
333     // Return the topbot[] after it has been recorded.
topBot()334     const SkScalar* topBot() const {
335         SkASSERT(this->isTopBotWritten());
336         return fTopBot;
337     }
338 
339 private:
340     struct HashTraits {
GetKeyHashTraits341         static const SkFlatData& GetKey(const SkFlatData& flat) { return flat; }
HashHashTraits342         static uint32_t Hash(const SkFlatData& flat) { return flat.checksum(); }
343     };
344 
setIndex(int index)345     void setIndex(int index) { fIndex = index; }
data()346     uint8_t* data() { return (uint8_t*)this + sizeof(*this); }
347 
348     // This assumes the payload flat data has already been written and does not modify it.
stampHeader(int index,int32_t size)349     void stampHeader(int index, int32_t size) {
350         SkASSERT(SkIsAlign4(size));
351         fIndex     = index;
352         fFlatSize  = size;
353         fTopBot[0] = SK_ScalarNaN;  // Mark as unwritten.
354         fChecksum  = SkChecksum::Compute((uint32_t*)this->data(), size);
355     }
356 
357     int fIndex;
358     int32_t fFlatSize;
359     uint32_t fChecksum;
360     mutable SkScalar fTopBot[2];  // Cache of FontMetrics fTop, fBottom.  Starts as [NaN,?].
361     // uint32_t flattenedData[] implicitly hangs off the end.
362 
363     template <typename T, typename Traits> friend class SkFlatDictionary;
364 };
365 
366 template <typename T, typename Traits>
367 class SkFlatDictionary {
368 public:
SkFlatDictionary(SkFlatController * controller)369     explicit SkFlatDictionary(SkFlatController* controller)
370     : fController(SkRef(controller))
371     , fScratch(controller->getWriteBufferFlags())
372     , fReady(false) {
373         this->reset();
374     }
375 
376     /**
377      * Clears the dictionary of all entries. However, it does NOT free the
378      * memory that was allocated for each entry (that's owned by controller).
379      */
reset()380     void reset() {
381         fIndexedData.rewind();
382     }
383 
count()384     int count() const {
385         SkASSERT(fHash.count() == fIndexedData.count());
386         return fHash.count();
387     }
388 
389     // For testing only.  Index is zero-based.
390     const SkFlatData* operator[](int index) {
391         return fIndexedData[index];
392     }
393 
394     /**
395      * Given an element of type T return its 1-based index in the dictionary. If
396      * the element wasn't previously in the dictionary it is automatically
397      * added.
398      *
399      */
find(const T & element)400     int find(const T& element) {
401         return this->findAndReturnFlat(element)->index();
402     }
403 
404     /**
405      * Similar to find. Allows the caller to specify an SkFlatData to replace in
406      * the case of an add. Also tells the caller whether a new SkFlatData was
407      * added and whether the old one was replaced. The parameters added and
408      * replaced are required to be non-NULL. Rather than returning the index of
409      * the entry in the dictionary, it returns the actual SkFlatData.
410      */
findAndReplace(const T & element,const SkFlatData * toReplace,bool * added,bool * replaced)411     const SkFlatData* findAndReplace(const T& element,
412                                      const SkFlatData* toReplace,
413                                      bool* added,
414                                      bool* replaced) {
415         SkASSERT(added != NULL && replaced != NULL);
416 
417         const int oldCount = this->count();
418         SkFlatData* flat = this->findAndReturnMutableFlat(element);
419         *added = this->count() > oldCount;
420 
421         // If we don't want to replace anything, we're done.
422         if (!*added || toReplace == NULL) {
423             *replaced = false;
424             return flat;
425         }
426 
427         // If we don't have the thing to replace, we're done.
428         const SkFlatData* found = fHash.find(*toReplace);
429         if (found == NULL) {
430             *replaced = false;
431             return flat;
432         }
433 
434         // findAndReturnMutableFlat put flat at the back.  Swap it into found->index() instead.
435         // indices in SkFlatData are 1-based, while fIndexedData is 0-based.  Watch out!
436         SkASSERT(flat->index() == this->count());
437         flat->setIndex(found->index());
438         fIndexedData.removeShuffle(found->index()-1);
439         SkASSERT(flat == fIndexedData[found->index()-1]);
440 
441         // findAndReturnMutableFlat already called fHash.add(), so we just clean up the old entry.
442         fHash.remove(*found);
443         fController->unalloc((void*)found);
444         SkASSERT(this->count() == oldCount);
445 
446         *replaced = true;
447         return flat;
448     }
449 
450     /**
451      * Unflatten the specific object at the given index.
452      * Caller takes ownership of the result.
453      */
unflatten(int index)454     T* unflatten(int index) const {
455         // index is 1-based, while fIndexedData is 0-based.
456         const SkFlatData* element = fIndexedData[index-1];
457         SkASSERT(index == element->index());
458 
459         T* dst = new T;
460         this->unflatten(dst, element);
461         return dst;
462     }
463 
464     /**
465      * Find or insert a flattened version of element into the dictionary.
466      * Caller does not take ownership of the result.  This will not return NULL.
467      */
findAndReturnFlat(const T & element)468     const SkFlatData* findAndReturnFlat(const T& element) {
469         return this->findAndReturnMutableFlat(element);
470     }
471 
472 private:
473     // We have to delay fScratch's initialization until its first use; fController might not
474     // be fully set up by the time we get it in the constructor.
lazyInit()475     void lazyInit() {
476         if (fReady) {
477             return;
478         }
479 
480         // Without a bitmap heap, we'll flatten bitmaps into paints.  That's never what you want.
481         SkASSERT(fController->getBitmapHeap() != NULL);
482         fScratch.setBitmapHeap(fController->getBitmapHeap());
483         fScratch.setTypefaceRecorder(fController->getTypefaceSet());
484         fScratch.setNamedFactoryRecorder(fController->getNamedFactorySet());
485         fReady = true;
486     }
487 
488     // As findAndReturnFlat, but returns a mutable pointer for internal use.
findAndReturnMutableFlat(const T & element)489     SkFlatData* findAndReturnMutableFlat(const T& element) {
490         // Only valid until the next call to resetScratch().
491         const SkFlatData& scratch = this->resetScratch(element, this->count()+1);
492 
493         SkFlatData* candidate = fHash.find(scratch);
494         if (candidate != NULL) {
495             return candidate;
496         }
497 
498         SkFlatData* detached = this->detachScratch();
499         fHash.add(detached);
500         *fIndexedData.append() = detached;
501         SkASSERT(fIndexedData.top()->index() == this->count());
502         return detached;
503     }
504 
505     // This reference is valid only until the next call to resetScratch() or detachScratch().
resetScratch(const T & element,int index)506     const SkFlatData& resetScratch(const T& element, int index) {
507         this->lazyInit();
508 
509         // Layout of fScratch: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ]
510         fScratch.reset();
511         fScratch.reserve(sizeof(SkFlatData));
512         Traits::Flatten(fScratch, element);
513         const size_t dataSize = fScratch.bytesWritten() - sizeof(SkFlatData);
514 
515         // Reinterpret data in fScratch as an SkFlatData.
516         SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
517         SkASSERT(scratch != NULL);
518         scratch->stampHeader(index, SkToS32(dataSize));
519         return *scratch;
520     }
521 
522     // This result is owned by fController and lives as long as it does (unless unalloc'd).
detachScratch()523     SkFlatData* detachScratch() {
524         // Allocate a new SkFlatData exactly big enough to hold our current scratch.
525         // We use the controller for this allocation to extend the allocation's lifetime and allow
526         // the controller to do whatever memory management it wants.
527         SkFlatData* detached = (SkFlatData*)fController->allocThrow(fScratch.bytesWritten());
528 
529         // Copy scratch into the new SkFlatData.
530         SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
531         SkASSERT(scratch != NULL);
532         memcpy(detached, scratch, fScratch.bytesWritten());
533 
534         // We can now reuse fScratch, and detached will live until fController dies.
535         return detached;
536     }
537 
unflatten(T * dst,const SkFlatData * element)538     void unflatten(T* dst, const SkFlatData* element) const {
539         element->unflatten<Traits>(dst,
540                                    fController->getBitmapHeap(),
541                                    fController->getTypefacePlayback());
542     }
543 
544     // All SkFlatData* stored in fIndexedData and fHash are owned by the controller.
545     SkAutoTUnref<SkFlatController> fController;
546     SkWriteBuffer fScratch;
547     bool fReady;
548 
549     // For index -> SkFlatData.  0-based, while all indices in the API are 1-based.  Careful!
550     SkTDArray<const SkFlatData*> fIndexedData;
551 
552     // For SkFlatData -> cached SkFlatData, which has index().
553     SkTDynamicHash<SkFlatData, SkFlatData, SkFlatData::HashTraits> fHash;
554 };
555 
556 #endif
557