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