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 
     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 
     23 enum 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*
     78 static const int kDRAW_BITMAP_FLAVOR = LAST_DRAWTYPE_ENUM+1;
     79 
     80 enum 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 
     91 static inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) {
     92     unsigned doAABit = doAA ? 1 : 0;
     93     return (doAABit << 4) | op;
     94 }
     95 
     96 static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) {
     97     return (SkRegion::Op)(packed & 0xF);
     98 }
     99 
    100 static inline bool ClipParams_unpackDoAA(uint32_t packed) {
    101     return SkToBool((packed >> 4) & 1);
    102 }
    103 
    104 ///////////////////////////////////////////////////////////////////////////////
    105 
    106 class SkTypefacePlayback {
    107 public:
    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 
    122 protected:
    123     int fCount;
    124     SkRefCnt** fArray;
    125 };
    126 
    127 class SkFactoryPlayback {
    128 public:
    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 
    143 private:
    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 
    173 class SkFlatData;
    174 
    175 class SkFlatController : public SkRefCnt {
    176 public:
    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 
    227 protected:
    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 
    253 private:
    254     SkBitmapHeap*       fBitmapHeap;
    255     SkRefCntSet*        fTypefaceSet;
    256     SkTypefacePlayback* fTypefacePlayback;
    257     SkNamedFactorySet*  fFactorySet;
    258     const uint32_t      fWriteBufferFlags;
    259 
    260     typedef SkRefCnt INHERITED;
    261 };
    262 
    263 class SkFlatData {
    264 public:
    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 
    340 private:
    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 
    367 template <typename T, typename Traits>
    368 class SkFlatDictionary {
    369 public:
    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 
    489 private:
    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 
    573 typedef SkFlatDictionary<SkPaint, SkPaint::FlatteningTraits> SkPaintDictionary;
    574 
    575 class SkChunkFlatController : public SkFlatController {
    576 public:
    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 
    604 private:
    605     SkChunkAlloc               fHeap;
    606     SkAutoTUnref<SkRefCntSet>  fTypefaceSet;
    607     void*                      fLastAllocated;
    608     mutable SkTypefacePlayback fTypefacePlayback;
    609 };
    610 
    611 #endif
    612