| |
| /* |
| * Copyright 2011 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| #ifndef SkPictureFlat_DEFINED |
| #define SkPictureFlat_DEFINED |
| |
| #include "SkChunkAlloc.h" |
| #include "SkBitmap.h" |
| #include "SkOrderedReadBuffer.h" |
| #include "SkOrderedWriteBuffer.h" |
| #include "SkPicture.h" |
| #include "SkMatrix.h" |
| #include "SkPaint.h" |
| #include "SkPath.h" |
| #include "SkRegion.h" |
| #include "SkTSearch.h" |
| |
| enum DrawType { |
| UNUSED, |
| CLIP_PATH, |
| CLIP_REGION, |
| CLIP_RECT, |
| CONCAT, |
| DRAW_BITMAP, |
| DRAW_BITMAP_MATRIX, |
| DRAW_BITMAP_NINE, |
| DRAW_BITMAP_RECT, |
| DRAW_CLEAR, |
| DRAW_DATA, |
| DRAW_PAINT, |
| DRAW_PATH, |
| DRAW_PICTURE, |
| DRAW_POINTS, |
| DRAW_POS_TEXT, |
| DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT |
| DRAW_POS_TEXT_H, |
| DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H |
| DRAW_RECT, |
| DRAW_SPRITE, |
| DRAW_TEXT, |
| DRAW_TEXT_ON_PATH, |
| DRAW_TEXT_TOP_BOTTOM, // fast variant of DRAW_TEXT |
| DRAW_VERTICES, |
| RESTORE, |
| ROTATE, |
| SAVE, |
| SAVE_LAYER, |
| SCALE, |
| SET_MATRIX, |
| SKEW, |
| TRANSLATE |
| }; |
| |
| enum DrawVertexFlags { |
| DRAW_VERTICES_HAS_TEXS = 0x01, |
| DRAW_VERTICES_HAS_COLORS = 0x02, |
| DRAW_VERTICES_HAS_INDICES = 0x04 |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // clipparams are packed in 5 bits |
| // doAA:1 | regionOp:4 |
| |
| static inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) { |
| unsigned doAABit = doAA ? 1 : 0; |
| return (doAABit << 4) | op; |
| } |
| |
| static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) { |
| return (SkRegion::Op)(packed & 0xF); |
| } |
| |
| static inline bool ClipParams_unpackDoAA(uint32_t packed) { |
| return SkToBool((packed >> 4) & 1); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| class SkRefCntPlayback { |
| public: |
| SkRefCntPlayback(); |
| virtual ~SkRefCntPlayback(); |
| |
| int count() const { return fCount; } |
| |
| void reset(const SkRefCntSet*); |
| |
| void setCount(int count); |
| SkRefCnt* set(int index, SkRefCnt*); |
| |
| virtual void setupBuffer(SkFlattenableReadBuffer& buffer) const { |
| buffer.setRefCntArray(fArray, fCount); |
| } |
| |
| protected: |
| int fCount; |
| SkRefCnt** fArray; |
| }; |
| |
| class SkTypefacePlayback : public SkRefCntPlayback { |
| public: |
| virtual void setupBuffer(SkFlattenableReadBuffer& buffer) const { |
| buffer.setTypefaceArray((SkTypeface**)fArray, fCount); |
| } |
| }; |
| |
| class SkFactoryPlayback { |
| public: |
| SkFactoryPlayback(int count) : fCount(count) { |
| fArray = SkNEW_ARRAY(SkFlattenable::Factory, count); |
| } |
| |
| ~SkFactoryPlayback() { |
| SkDELETE_ARRAY(fArray); |
| } |
| |
| SkFlattenable::Factory* base() const { return fArray; } |
| |
| void setupBuffer(SkFlattenableReadBuffer& buffer) const { |
| buffer.setFactoryPlayback(fArray, fCount); |
| } |
| |
| private: |
| int fCount; |
| SkFlattenable::Factory* fArray; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // |
| // The following templated classes provide an efficient way to store and compare |
| // objects that have been flattened (i.e. serialized in an ordered binary |
| // format). |
| // |
| // SkFlatData: is a simple indexable container for the flattened data |
| // which is agnostic to the type of data is is indexing. It is |
| // also responsible for flattening/unflattening objects but |
| // details of that operation are hidden in the provided procs |
| // SkFlatDictionary: is a abstract templated dictionary that maintains a |
| // searchable set of SkFlataData objects of type T. |
| // |
| // NOTE: any class that wishes to be used in conjunction with SkFlatDictionary |
| // must subclass the dictionary and provide the necessary flattening procs. |
| // The end of this header contains dictionary subclasses for some common classes |
| // like SkBitmap, SkMatrix, SkPaint, and SkRegion. |
| // |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| class SkFlatData { |
| public: |
| |
| static int Compare(const SkFlatData* a, const SkFlatData* b) { |
| size_t bytesToCompare = sizeof(a->fChecksum) + a->fAllocSize; |
| #if SK_PREFER_32BIT_CHECKSUM |
| typedef uint32_t CompareType; |
| SkASSERT(SkIsAlign4(bytesToCompare)); |
| #else |
| typedef uint64_t CompareType; |
| SkASSERT(SkIsAlign8(bytesToCompare)); |
| #endif |
| const CompareType* a_ptr = &(a->fChecksum); |
| const CompareType* b_ptr = &(b->fChecksum); |
| const CompareType* stop = a_ptr + bytesToCompare / sizeof(CompareType); |
| while(a_ptr < stop) { |
| if (*a_ptr != *b_ptr) { |
| return (*a_ptr < *b_ptr) ? -1 : 1; |
| } |
| a_ptr++; |
| b_ptr++; |
| } |
| return 0; |
| } |
| |
| int index() const { return fIndex; } |
| void* data() const { return (char*)this + sizeof(*this); } |
| |
| #ifdef SK_DEBUG_SIZE |
| size_t size() const { return sizeof(SkFlatData) + fAllocSize; } |
| #endif |
| |
| static SkFlatData* Create(SkChunkAlloc* heap, const void* obj, int index, |
| void (*flattenProc)(SkOrderedWriteBuffer&, const void*), |
| SkRefCntSet* refCntRecorder = NULL, |
| SkRefCntSet* faceRecorder = NULL, |
| uint32_t writeBufferflags = 0); |
| void unflatten(void* result, |
| void (*unflattenProc)(SkOrderedReadBuffer&, void*), |
| SkRefCntPlayback* refCntPlayback = NULL, |
| SkTypefacePlayback* facePlayback = NULL) const; |
| |
| private: |
| // Data members add-up to 128 bits of storage, so data() is 128-bit |
| // aligned, which helps performance of memcpy in SkWriter32::flatten |
| int fIndex; |
| int32_t fAllocSize; |
| // fChecksum must be defined last in order to be contiguous with data() |
| #if SK_PREFER_32BIT_CHECKSUM |
| uint32_t fChecksum; |
| #else |
| uint64_t fChecksum; |
| #endif |
| }; |
| |
| template <class T> |
| class SkFlatDictionary { |
| public: |
| SkFlatDictionary(SkChunkAlloc* heap) { |
| fFlattenProc = NULL; |
| fUnflattenProc = NULL; |
| fHeap = heap; |
| // set to 1 since returning a zero from find() indicates failure |
| fNextIndex = 1; |
| } |
| |
| int count() const { return fData.count(); } |
| |
| const SkFlatData* operator[](int index) const { |
| SkASSERT(index >= 0 && index < fData.count()); |
| return fData[index]; |
| } |
| |
| /** |
| * Clears the dictionary of all entries. However, it does NOT free the |
| * memory that was allocated for each entry. |
| */ |
| void reset() { fData.reset(); fNextIndex = 1; } |
| |
| /** |
| * Given an element of type T it returns its index in the dictionary. If |
| * the element wasn't previously in the dictionary it is automatically added |
| */ |
| int find(const T* element, SkRefCntSet* refCntRecorder = NULL, |
| SkRefCntSet* faceRecorder = NULL, uint32_t writeBufferflags = 0) { |
| if (element == NULL) |
| return 0; |
| SkFlatData* flat = SkFlatData::Create(fHeap, element, fNextIndex, |
| fFlattenProc, refCntRecorder, faceRecorder, writeBufferflags); |
| int index = SkTSearch<SkFlatData>((const SkFlatData**) fData.begin(), |
| fData.count(), flat, sizeof(flat), &SkFlatData::Compare); |
| if (index >= 0) { |
| (void)fHeap->unalloc(flat); |
| return fData[index]->index(); |
| } |
| index = ~index; |
| *fData.insert(index) = flat; |
| SkASSERT(fData.count() == fNextIndex); |
| return fNextIndex++; |
| } |
| |
| /** |
| * Given a pointer to a array of type T we allocate the array and fill it |
| * with the unflattened dictionary contents. The return value is the size of |
| * the allocated array. |
| */ |
| int unflattenDictionary(T*& array, SkRefCntPlayback* refCntPlayback = NULL, |
| SkTypefacePlayback* facePlayback = NULL) const { |
| int elementCount = fData.count(); |
| if (elementCount > 0) { |
| array = SkNEW_ARRAY(T, elementCount); |
| for (const SkFlatData** elementPtr = fData.begin(); |
| elementPtr != fData.end(); elementPtr++) { |
| const SkFlatData* element = *elementPtr; |
| int index = element->index() - 1; |
| element->unflatten(&array[index], fUnflattenProc, |
| refCntPlayback, facePlayback); |
| } |
| } |
| return elementCount; |
| } |
| |
| protected: |
| void (*fFlattenProc)(SkOrderedWriteBuffer&, const void*); |
| void (*fUnflattenProc)(SkOrderedReadBuffer&, void*); |
| |
| private: |
| SkChunkAlloc* fHeap; |
| int fNextIndex; |
| SkTDArray<const SkFlatData*> fData; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Some common dictionaries are defined here for both reference and convenience |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| template <class T> |
| static void SkFlattenObjectProc(SkOrderedWriteBuffer& buffer, const void* obj) { |
| ((T*)obj)->flatten(buffer); |
| } |
| |
| template <class T> |
| static void SkUnflattenObjectProc(SkOrderedReadBuffer& buffer, void* obj) { |
| ((T*)obj)->unflatten(buffer); |
| } |
| |
| class SkBitmapDictionary : public SkFlatDictionary<SkBitmap> { |
| public: |
| SkBitmapDictionary(SkChunkAlloc* heap) : SkFlatDictionary<SkBitmap>(heap) { |
| fFlattenProc = &SkFlattenObjectProc<SkBitmap>; |
| fUnflattenProc = &SkUnflattenObjectProc<SkBitmap>; |
| } |
| }; |
| |
| class SkMatrixDictionary : public SkFlatDictionary<SkMatrix> { |
| public: |
| SkMatrixDictionary(SkChunkAlloc* heap) : SkFlatDictionary<SkMatrix>(heap) { |
| fFlattenProc = &flattenMatrix; |
| fUnflattenProc = &unflattenMatrix; |
| } |
| |
| static void flattenMatrix(SkOrderedWriteBuffer& buffer, const void* obj) { |
| buffer.getWriter32()->writeMatrix(*(SkMatrix*)obj); |
| } |
| |
| static void unflattenMatrix(SkOrderedReadBuffer& buffer, void* obj) { |
| buffer.getReader32()->readMatrix((SkMatrix*)obj); |
| } |
| }; |
| |
| class SkPaintDictionary : public SkFlatDictionary<SkPaint> { |
| public: |
| SkPaintDictionary(SkChunkAlloc* heap) : SkFlatDictionary<SkPaint>(heap) { |
| fFlattenProc = &SkFlattenObjectProc<SkPaint>; |
| fUnflattenProc = &SkUnflattenObjectProc<SkPaint>; |
| } |
| }; |
| |
| class SkRegionDictionary : public SkFlatDictionary<SkRegion> { |
| public: |
| SkRegionDictionary(SkChunkAlloc* heap) : SkFlatDictionary<SkRegion>(heap) { |
| fFlattenProc = &flattenRegion; |
| fUnflattenProc = &unflattenRegion; |
| } |
| |
| static void flattenRegion(SkOrderedWriteBuffer& buffer, const void* obj) { |
| buffer.getWriter32()->writeRegion(*(SkRegion*)obj); |
| } |
| |
| static void unflattenRegion(SkOrderedReadBuffer& buffer, void* obj) { |
| buffer.getReader32()->readRegion((SkRegion*)obj); |
| } |
| }; |
| |
| #endif |