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