diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkStream.cpp | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/core/SkStream.cpp b/src/core/SkStream.cpp index 91de88adac..b251905633 100644 --- a/src/core/SkStream.cpp +++ b/src/core/SkStream.cpp @@ -661,6 +661,138 @@ void SkDynamicMemoryWStream::invalidateCopy() { } } +class SkBlockMemoryRefCnt : public SkRefCnt { +public: + explicit SkBlockMemoryRefCnt(SkDynamicMemoryWStream::Block* head) : fHead(head) { } + + virtual ~SkBlockMemoryRefCnt() { + SkDynamicMemoryWStream::Block* block = fHead; + while (block != NULL) { + SkDynamicMemoryWStream::Block* next = block->fNext; + sk_free(block); + block = next; + } + } + + SkDynamicMemoryWStream::Block* const fHead; +}; + +class SkBlockMemoryStream : public SkStreamAsset { +public: + SkBlockMemoryStream(SkDynamicMemoryWStream::Block* head, size_t size) + : fBlockMemory(SkNEW_ARGS(SkBlockMemoryRefCnt, (head))), fCurrent(head) + , fSize(size) , fOffset(0), fCurrentOffset(0) { } + + SkBlockMemoryStream(SkBlockMemoryRefCnt* headRef, size_t size) + : fBlockMemory(SkRef(headRef)), fCurrent(fBlockMemory->fHead) + , fSize(size) , fOffset(0), fCurrentOffset(0) { } + + virtual size_t read(void* buffer, size_t rawCount) SK_OVERRIDE { + size_t count = rawCount; + if (fOffset + count > fSize) { + count = fSize - fOffset; + } + size_t bytesLeftToRead = count; + while (fCurrent != NULL) { + size_t bytesLeftInCurrent = fCurrent->written() - fCurrentOffset; + size_t bytesFromCurrent = bytesLeftToRead <= bytesLeftInCurrent + ? bytesLeftToRead : bytesLeftInCurrent; + if (buffer) { + memcpy(buffer, fCurrent->start() + fCurrentOffset, bytesFromCurrent); + } + if (bytesLeftToRead <= bytesFromCurrent) { + fCurrentOffset += bytesFromCurrent; + fOffset += count; + return count; + } + bytesLeftToRead -= bytesFromCurrent; + buffer = SkTAddOffset<void>(buffer, bytesFromCurrent); + fCurrent = fCurrent->fNext; + fCurrentOffset = 0; + } + SkASSERT(false); + return 0; + } + + virtual bool isAtEnd() const SK_OVERRIDE { + return fOffset == fSize; + } + + virtual bool rewind() SK_OVERRIDE { + fCurrent = fBlockMemory->fHead; + fOffset = 0; + fCurrentOffset = 0; + return true; + } + + virtual SkBlockMemoryStream* duplicate() const SK_OVERRIDE { + return SkNEW_ARGS(SkBlockMemoryStream, (fBlockMemory.get(), fSize)); + } + + virtual size_t getPosition() const SK_OVERRIDE { + return fOffset; + } + + virtual bool seek(size_t position) SK_OVERRIDE { + // If possible, skip forward. + if (position >= fOffset) { + size_t skipAmount = position - fOffset; + return this->skip(skipAmount) == skipAmount; + } + // If possible, move backward within the current block. + size_t moveBackAmount = fOffset - position; + if (moveBackAmount <= fCurrentOffset) { + fCurrentOffset -= moveBackAmount; + fOffset -= moveBackAmount; + return true; + } + // Otherwise rewind and move forward. + return this->rewind() && this->skip(position) == position; + } + + virtual bool move(long offset) SK_OVERRIDE { + return seek(fOffset + offset); + } + + virtual SkBlockMemoryStream* fork() const SK_OVERRIDE { + SkAutoTUnref<SkBlockMemoryStream> that(this->duplicate()); + that->fCurrent = this->fCurrent; + that->fOffset = this->fOffset; + that->fCurrentOffset = this->fCurrentOffset; + return that.detach(); + } + + virtual size_t getLength() const SK_OVERRIDE { + return fSize; + } + + virtual const void* getMemoryBase() SK_OVERRIDE { + if (NULL == fBlockMemory->fHead->fNext) { + return fBlockMemory->fHead->start(); + } + return NULL; + } + +private: + SkAutoTUnref<SkBlockMemoryRefCnt> const fBlockMemory; + SkDynamicMemoryWStream::Block const * fCurrent; + size_t const fSize; + size_t fOffset; + size_t fCurrentOffset; +}; + +SkStreamAsset* SkDynamicMemoryWStream::detatchAsStream() { + if (fCopy) { + SkMemoryStream* stream = SkNEW_ARGS(SkMemoryStream, (fCopy)); + this->reset(); + return stream; + } + SkBlockMemoryStream* stream = SkNEW_ARGS(SkBlockMemoryStream, (fHead, fBytesWritten)); + fHead = 0; + this->reset(); + return stream; +} + /////////////////////////////////////////////////////////////////////////////// void SkDebugWStream::newline() |