Home | History | Annotate | Download | only in core
      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 
     24 enum 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*
     75 static const int kDRAW_BITMAP_FLAVOR = LAST_DRAWTYPE_ENUM+1;
     76 
     77 enum 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 
     88 static inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) {
     89     unsigned doAABit = doAA ? 1 : 0;
     90     return (doAABit << 4) | op;
     91 }
     92 
     93 static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) {
     94     return (SkRegion::Op)(packed & 0xF);
     95 }
     96 
     97 static inline bool ClipParams_unpackDoAA(uint32_t packed) {
     98     return SkToBool((packed >> 4) & 1);
     99 }
    100 
    101 ///////////////////////////////////////////////////////////////////////////////
    102 
    103 class SkTypefacePlayback {
    104 public:
    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 
    119 protected:
    120     int fCount;
    121     SkRefCnt** fArray;
    122 };
    123 
    124 class SkFactoryPlayback {
    125 public:
    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 
    140 private:
    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 
    170 class SkFlatData;
    171 
    172 class SkFlatController : public SkRefCnt {
    173 public:
    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 
    224 protected:
    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 
    250 private:
    251     SkBitmapHeap*       fBitmapHeap;
    252     SkRefCntSet*        fTypefaceSet;
    253     SkTypefacePlayback* fTypefacePlayback;
    254     SkNamedFactorySet*  fFactorySet;
    255     const uint32_t      fWriteBufferFlags;
    256 
    257     typedef SkRefCnt INHERITED;
    258 };
    259 
    260 class SkFlatData {
    261 public:
    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 
    337 private:
    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 
    364 template <typename T, typename Traits>
    365 class SkFlatDictionary {
    366 public:
    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 
    486 private:
    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 
    570 typedef SkFlatDictionary<SkPaint, SkPaint::FlatteningTraits> SkPaintDictionary;
    571 
    572 class SkChunkFlatController : public SkFlatController {
    573 public:
    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 
    601 private:
    602     SkChunkAlloc               fHeap;
    603     SkAutoTUnref<SkRefCntSet>  fTypefaceSet;
    604     void*                      fLastAllocated;
    605     mutable SkTypefacePlayback fTypefacePlayback;
    606 };
    607 
    608 #endif
    609