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