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