| Index: src/core/SkPictureFlat.h
|
| diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
|
| index edfe24a4516dfe5e23d08be212e7c9bffad6ecee..d69b658efc834a1c3bd7619ab5a47aa997ade87d 100644
|
| --- a/src/core/SkPictureFlat.h
|
| +++ b/src/core/SkPictureFlat.h
|
| @@ -163,397 +163,4 @@ private:
|
| SkFlattenable::Factory* fArray;
|
| };
|
|
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -//
|
| -//
|
| -// The following templated classes provide an efficient way to store and compare
|
| -// objects that have been flattened (i.e. serialized in an ordered binary
|
| -// format).
|
| -//
|
| -// SkFlatData: is a simple indexable container for the flattened data
|
| -// which is agnostic to the type of data is is indexing. It is
|
| -// also responsible for flattening/unflattening objects but
|
| -// details of that operation are hidden in the provided traits
|
| -// SkFlatDictionary: is an abstract templated dictionary that maintains a
|
| -// searchable set of SkFlatData objects of type T.
|
| -// SkFlatController: is an interface provided to SkFlatDictionary which handles
|
| -// allocation (and unallocation in some cases). It also holds
|
| -// ref count recorders and the like.
|
| -//
|
| -// NOTE: any class that wishes to be used in conjunction with SkFlatDictionary must subclass the
|
| -// dictionary and provide the necessary flattening traits. SkFlatController must also be
|
| -// implemented, or SkChunkFlatController can be used to use an SkChunkAllocator and never do
|
| -// replacements.
|
| -//
|
| -//
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -class SkFlatData;
|
| -
|
| -class SkFlatController : public SkRefCnt {
|
| -public:
|
| -
|
| -
|
| - SkFlatController(uint32_t writeBufferFlags = 0);
|
| - virtual ~SkFlatController();
|
| - /**
|
| - * Return a new block of memory for the SkFlatDictionary to use.
|
| - * This memory is owned by the controller and has the same lifetime unless you
|
| - * call unalloc(), in which case it may be freed early.
|
| - */
|
| - virtual void* allocThrow(size_t bytes) = 0;
|
| -
|
| - /**
|
| - * Hint that this block, which was allocated with allocThrow, is no longer needed.
|
| - * The implementation may choose to free this memory any time beteween now and destruction.
|
| - */
|
| - virtual void unalloc(void* ptr) = 0;
|
| -
|
| - /**
|
| - * Used during creation and unflattening of SkFlatData objects. If the
|
| - * objects being flattened contain bitmaps they are stored in this heap
|
| - * and the flattenable stores the index to the bitmap on the heap.
|
| - * This should be set by the protected setBitmapHeap.
|
| - */
|
| - SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; }
|
| -
|
| - /**
|
| - * Used during creation of SkFlatData objects. If a typeface recorder is
|
| - * required to flatten the objects being flattened (i.e. for SkPaints), this
|
| - * should be set by the protected setTypefaceSet.
|
| - */
|
| - SkRefCntSet* getTypefaceSet() { return fTypefaceSet; }
|
| -
|
| - /**
|
| - * Used during unflattening of the SkFlatData objects in the
|
| - * SkFlatDictionary. Needs to be set by the protected setTypefacePlayback
|
| - * and needs to be reset to the SkRefCntSet passed to setTypefaceSet.
|
| - */
|
| - SkTypefacePlayback* getTypefacePlayback() { return fTypefacePlayback; }
|
| -
|
| - /**
|
| - * Flags to use during creation of SkFlatData objects. Defaults to zero.
|
| - */
|
| - uint32_t getWriteBufferFlags() { return fWriteBufferFlags; }
|
| -
|
| -protected:
|
| - /**
|
| - * Set an SkBitmapHeap to be used to store/read SkBitmaps. Ref counted.
|
| - */
|
| - void setBitmapHeap(SkBitmapHeap*);
|
| -
|
| - /**
|
| - * Set an SkRefCntSet to be used to store SkTypefaces during flattening. Ref
|
| - * counted.
|
| - */
|
| - void setTypefaceSet(SkRefCntSet*);
|
| -
|
| - /**
|
| - * Set an SkTypefacePlayback to be used to find references to SkTypefaces
|
| - * during unflattening. Should be reset to the set provided to
|
| - * setTypefaceSet.
|
| - */
|
| - void setTypefacePlayback(SkTypefacePlayback*);
|
| -
|
| -private:
|
| - SkBitmapHeap* fBitmapHeap;
|
| - SkRefCntSet* fTypefaceSet;
|
| - SkTypefacePlayback* fTypefacePlayback;
|
| - const uint32_t fWriteBufferFlags;
|
| -
|
| - typedef SkRefCnt INHERITED;
|
| -};
|
| -
|
| -class SkFlatData {
|
| -public:
|
| - // Flatten obj into an SkFlatData with this index. controller owns the SkFlatData*.
|
| - template <typename Traits, typename T>
|
| - static SkFlatData* Create(SkFlatController* controller, const T& obj, int index) {
|
| - // A buffer of 256 bytes should fit most paints, regions, and matrices.
|
| - uint32_t storage[64];
|
| - SkWriteBuffer buffer(storage, sizeof(storage), controller->getWriteBufferFlags());
|
| -
|
| - buffer.setBitmapHeap(controller->getBitmapHeap());
|
| - buffer.setTypefaceRecorder(controller->getTypefaceSet());
|
| -
|
| - Traits::Flatten(buffer, obj);
|
| - size_t size = buffer.bytesWritten();
|
| - SkASSERT(SkIsAlign4(size));
|
| -
|
| - // Allocate enough memory to hold SkFlatData struct and the flat data itself.
|
| - size_t allocSize = sizeof(SkFlatData) + size;
|
| - SkFlatData* result = (SkFlatData*) controller->allocThrow(allocSize);
|
| -
|
| - // Put the serialized contents into the data section of the new allocation.
|
| - buffer.writeToMemory(result->data());
|
| - // Stamp the index, size and checksum in the header.
|
| - result->stampHeader(index, SkToS32(size));
|
| - return result;
|
| - }
|
| -
|
| - // Unflatten this into result, using bitmapHeap and facePlayback for bitmaps and fonts if given
|
| - template <typename Traits, typename T>
|
| - void unflatten(T* result,
|
| - SkBitmapHeap* bitmapHeap = nullptr,
|
| - SkTypefacePlayback* facePlayback = nullptr) const {
|
| - SkReadBuffer buffer(this->data(), fFlatSize);
|
| -
|
| - if (bitmapHeap) {
|
| - buffer.setBitmapStorage(bitmapHeap);
|
| - }
|
| - if (facePlayback) {
|
| - facePlayback->setupBuffer(buffer);
|
| - }
|
| -
|
| - Traits::Unflatten(buffer, result);
|
| - SkASSERT(fFlatSize == (int32_t)buffer.offset());
|
| - }
|
| -
|
| - // Do these contain the same data? Ignores index() and topBot().
|
| - bool operator==(const SkFlatData& that) const {
|
| - if (this->checksum() != that.checksum() || this->flatSize() != that.flatSize()) {
|
| - return false;
|
| - }
|
| - return memcmp(this->data(), that.data(), this->flatSize()) == 0;
|
| - }
|
| -
|
| - int index() const { return fIndex; }
|
| - const uint8_t* data() const { return (const uint8_t*)this + sizeof(*this); }
|
| - size_t flatSize() const { return fFlatSize; }
|
| - uint32_t checksum() const { return fChecksum; }
|
| -
|
| - // Returns true if fTopBot[] has been recorded.
|
| - bool isTopBotWritten() const {
|
| - return !SkScalarIsNaN(fTopBot[0]);
|
| - }
|
| -
|
| - // Returns fTopBot array, so it can be passed to a routine to compute them.
|
| - // For efficiency, we assert that fTopBot have not been recorded yet.
|
| - SkScalar* writableTopBot() const {
|
| - SkASSERT(!this->isTopBotWritten());
|
| - return fTopBot;
|
| - }
|
| -
|
| - // Return the topbot[] after it has been recorded.
|
| - const SkScalar* topBot() const {
|
| - SkASSERT(this->isTopBotWritten());
|
| - return fTopBot;
|
| - }
|
| -
|
| -private:
|
| - struct HashTraits {
|
| - static const SkFlatData& GetKey(const SkFlatData& flat) { return flat; }
|
| - static uint32_t Hash(const SkFlatData& flat) { return flat.checksum(); }
|
| - };
|
| -
|
| - void setIndex(int index) { fIndex = index; }
|
| - uint8_t* data() { return (uint8_t*)this + sizeof(*this); }
|
| -
|
| - // This assumes the payload flat data has already been written and does not modify it.
|
| - void stampHeader(int index, int32_t size) {
|
| - SkASSERT(SkIsAlign4(size));
|
| - fIndex = index;
|
| - fFlatSize = size;
|
| - fTopBot[0] = SK_ScalarNaN; // Mark as unwritten.
|
| - fChecksum = SkChecksum::Murmur3(this->data(), size);
|
| - }
|
| -
|
| - int fIndex;
|
| - int32_t fFlatSize;
|
| - uint32_t fChecksum;
|
| - mutable SkScalar fTopBot[2]; // Cache of FontMetrics fTop, fBottom. Starts as [NaN,?].
|
| - // uint32_t flattenedData[] implicitly hangs off the end.
|
| -
|
| - template <typename T, typename Traits> friend class SkFlatDictionary;
|
| -};
|
| -
|
| -template <typename T, typename Traits>
|
| -class SkFlatDictionary {
|
| -public:
|
| - explicit SkFlatDictionary(SkFlatController* controller)
|
| - : fController(SkRef(controller))
|
| - , fScratch(controller->getWriteBufferFlags())
|
| - , fReady(false) {
|
| - this->reset();
|
| - }
|
| -
|
| - /**
|
| - * Clears the dictionary of all entries. However, it does NOT free the
|
| - * memory that was allocated for each entry (that's owned by controller).
|
| - */
|
| - void reset() {
|
| - fIndexedData.rewind();
|
| - }
|
| -
|
| - int count() const {
|
| - SkASSERT(fHash.count() == fIndexedData.count());
|
| - return fHash.count();
|
| - }
|
| -
|
| - // For testing only. Index is zero-based.
|
| - const SkFlatData* operator[](int index) {
|
| - return fIndexedData[index];
|
| - }
|
| -
|
| - /**
|
| - * Given an element of type T return its 1-based index in the dictionary. If
|
| - * the element wasn't previously in the dictionary it is automatically
|
| - * added.
|
| - *
|
| - */
|
| - int find(const T& element) {
|
| - return this->findAndReturnFlat(element)->index();
|
| - }
|
| -
|
| - /**
|
| - * Similar to find. Allows the caller to specify an SkFlatData to replace in
|
| - * the case of an add. Also tells the caller whether a new SkFlatData was
|
| - * added and whether the old one was replaced. The parameters added and
|
| - * replaced are required to be non-nullptr. Rather than returning the index of
|
| - * the entry in the dictionary, it returns the actual SkFlatData.
|
| - */
|
| - const SkFlatData* findAndReplace(const T& element,
|
| - const SkFlatData* toReplace,
|
| - bool* added,
|
| - bool* replaced) {
|
| - SkASSERT(added != nullptr && replaced != nullptr);
|
| -
|
| - const int oldCount = this->count();
|
| - SkFlatData* flat = this->findAndReturnMutableFlat(element);
|
| - *added = this->count() > oldCount;
|
| -
|
| - // If we don't want to replace anything, we're done.
|
| - if (!*added || toReplace == nullptr) {
|
| - *replaced = false;
|
| - return flat;
|
| - }
|
| -
|
| - // If we don't have the thing to replace, we're done.
|
| - const SkFlatData* found = fHash.find(*toReplace);
|
| - if (found == nullptr) {
|
| - *replaced = false;
|
| - return flat;
|
| - }
|
| -
|
| - // findAndReturnMutableFlat put flat at the back. Swap it into found->index() instead.
|
| - // indices in SkFlatData are 1-based, while fIndexedData is 0-based. Watch out!
|
| - SkASSERT(flat->index() == this->count());
|
| - flat->setIndex(found->index());
|
| - fIndexedData.removeShuffle(found->index()-1);
|
| - SkASSERT(flat == fIndexedData[found->index()-1]);
|
| -
|
| - // findAndReturnMutableFlat already called fHash.add(), so we just clean up the old entry.
|
| - fHash.remove(*found);
|
| - fController->unalloc((void*)found);
|
| - SkASSERT(this->count() == oldCount);
|
| -
|
| - *replaced = true;
|
| - return flat;
|
| - }
|
| -
|
| - /**
|
| - * Unflatten the specific object at the given index.
|
| - * Caller takes ownership of the result.
|
| - */
|
| - T* unflatten(int index) const {
|
| - // index is 1-based, while fIndexedData is 0-based.
|
| - const SkFlatData* element = fIndexedData[index-1];
|
| - SkASSERT(index == element->index());
|
| -
|
| - T* dst = new T;
|
| - this->unflatten(dst, element);
|
| - return dst;
|
| - }
|
| -
|
| - /**
|
| - * Find or insert a flattened version of element into the dictionary.
|
| - * Caller does not take ownership of the result. This will not return nullptr.
|
| - */
|
| - const SkFlatData* findAndReturnFlat(const T& element) {
|
| - return this->findAndReturnMutableFlat(element);
|
| - }
|
| -
|
| -private:
|
| - // We have to delay fScratch's initialization until its first use; fController might not
|
| - // be fully set up by the time we get it in the constructor.
|
| - void lazyInit() {
|
| - if (fReady) {
|
| - return;
|
| - }
|
| -
|
| - // Without a bitmap heap, we'll flatten bitmaps into paints. That's never what you want.
|
| - SkASSERT(fController->getBitmapHeap() != nullptr);
|
| - fScratch.setBitmapHeap(fController->getBitmapHeap());
|
| - fScratch.setTypefaceRecorder(fController->getTypefaceSet());
|
| - fReady = true;
|
| - }
|
| -
|
| - // As findAndReturnFlat, but returns a mutable pointer for internal use.
|
| - SkFlatData* findAndReturnMutableFlat(const T& element) {
|
| - // Only valid until the next call to resetScratch().
|
| - const SkFlatData& scratch = this->resetScratch(element, this->count()+1);
|
| -
|
| - SkFlatData* candidate = fHash.find(scratch);
|
| - if (candidate != nullptr) {
|
| - return candidate;
|
| - }
|
| -
|
| - SkFlatData* detached = this->detachScratch();
|
| - fHash.add(detached);
|
| - *fIndexedData.append() = detached;
|
| - SkASSERT(fIndexedData.top()->index() == this->count());
|
| - return detached;
|
| - }
|
| -
|
| - // This reference is valid only until the next call to resetScratch() or detachScratch().
|
| - const SkFlatData& resetScratch(const T& element, int index) {
|
| - this->lazyInit();
|
| -
|
| - // Layout of fScratch: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ]
|
| - fScratch.reset();
|
| - fScratch.reserve(sizeof(SkFlatData));
|
| - Traits::Flatten(fScratch, element);
|
| - const size_t dataSize = fScratch.bytesWritten() - sizeof(SkFlatData);
|
| -
|
| - // Reinterpret data in fScratch as an SkFlatData.
|
| - SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
|
| - SkASSERT(scratch != nullptr);
|
| - scratch->stampHeader(index, SkToS32(dataSize));
|
| - return *scratch;
|
| - }
|
| -
|
| - // This result is owned by fController and lives as long as it does (unless unalloc'd).
|
| - SkFlatData* detachScratch() {
|
| - // Allocate a new SkFlatData exactly big enough to hold our current scratch.
|
| - // We use the controller for this allocation to extend the allocation's lifetime and allow
|
| - // the controller to do whatever memory management it wants.
|
| - SkFlatData* detached = (SkFlatData*)fController->allocThrow(fScratch.bytesWritten());
|
| -
|
| - // Copy scratch into the new SkFlatData.
|
| - SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
|
| - SkASSERT(scratch != nullptr);
|
| - memcpy(detached, scratch, fScratch.bytesWritten());
|
| -
|
| - // We can now reuse fScratch, and detached will live until fController dies.
|
| - return detached;
|
| - }
|
| -
|
| - void unflatten(T* dst, const SkFlatData* element) const {
|
| - element->unflatten<Traits>(dst,
|
| - fController->getBitmapHeap(),
|
| - fController->getTypefacePlayback());
|
| - }
|
| -
|
| - // All SkFlatData* stored in fIndexedData and fHash are owned by the controller.
|
| - SkAutoTUnref<SkFlatController> fController;
|
| - SkWriteBuffer fScratch;
|
| - bool fReady;
|
| -
|
| - // For index -> SkFlatData. 0-based, while all indices in the API are 1-based. Careful!
|
| - SkTDArray<const SkFlatData*> fIndexedData;
|
| -
|
| - // For SkFlatData -> cached SkFlatData, which has index().
|
| - SkTDynamicHash<SkFlatData, SkFlatData, SkFlatData::HashTraits> fHash;
|
| -};
|
| -
|
| #endif
|
|
|