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