diff options
Diffstat (limited to 'gfx/skia/skia/src/codec/SkStreamBuffer.cpp')
-rw-r--r-- | gfx/skia/skia/src/codec/SkStreamBuffer.cpp | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/codec/SkStreamBuffer.cpp b/gfx/skia/skia/src/codec/SkStreamBuffer.cpp new file mode 100644 index 0000000000..cdac862fdd --- /dev/null +++ b/gfx/skia/skia/src/codec/SkStreamBuffer.cpp @@ -0,0 +1,88 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/codec/SkStreamBuffer.h" + +SkStreamBuffer::SkStreamBuffer(std::unique_ptr<SkStream> stream) + : fStream(std::move(stream)) + , fPosition(0) + , fBytesBuffered(0) + , fHasLengthAndPosition(fStream->hasLength() && fStream->hasPosition()) + , fTrulyBuffered(0) +{} + +SkStreamBuffer::~SkStreamBuffer() { + fMarkedData.foreach([](size_t, SkData** data) { (*data)->unref(); }); +} + +const char* SkStreamBuffer::get() const { + SkASSERT(fBytesBuffered >= 1); + if (fHasLengthAndPosition && fTrulyBuffered < fBytesBuffered) { + const size_t bytesToBuffer = fBytesBuffered - fTrulyBuffered; + char* dst = SkTAddOffset<char>(const_cast<char*>(fBuffer), fTrulyBuffered); + SkDEBUGCODE(const size_t bytesRead =) + // This stream is rewindable, so it should be safe to call the non-const + // read() + const_cast<SkStream*>(fStream.get())->read(dst, bytesToBuffer); + SkASSERT(bytesRead == bytesToBuffer); + fTrulyBuffered = fBytesBuffered; + } + return fBuffer; +} + +bool SkStreamBuffer::buffer(size_t totalBytesToBuffer) { + // FIXME (scroggo): What should we do if the client tries to read too much? + // Should not be a problem in GIF. + SkASSERT(totalBytesToBuffer <= kMaxSize); + + if (totalBytesToBuffer <= fBytesBuffered) { + return true; + } + + if (fHasLengthAndPosition) { + const size_t remaining = fStream->getLength() - fStream->getPosition() + fTrulyBuffered; + fBytesBuffered = SkTMin(remaining, totalBytesToBuffer); + } else { + const size_t extraBytes = totalBytesToBuffer - fBytesBuffered; + const size_t bytesBuffered = fStream->read(fBuffer + fBytesBuffered, extraBytes); + fBytesBuffered += bytesBuffered; + } + return fBytesBuffered == totalBytesToBuffer; +} + +size_t SkStreamBuffer::markPosition() { + SkASSERT(fBytesBuffered >= 1); + if (!fHasLengthAndPosition) { + sk_sp<SkData> data(SkData::MakeWithCopy(fBuffer, fBytesBuffered)); + SkASSERT(nullptr == fMarkedData.find(fPosition)); + fMarkedData.set(fPosition, data.release()); + } + return fPosition; +} + +sk_sp<SkData> SkStreamBuffer::getDataAtPosition(size_t position, size_t length) { + if (!fHasLengthAndPosition) { + SkData** data = fMarkedData.find(position); + SkASSERT(data); + SkASSERT((*data)->size() == length); + return sk_ref_sp<SkData>(*data); + } + + SkASSERT(length <= fStream->getLength() && + position <= fStream->getLength() - length); + + const size_t oldPosition = fStream->getPosition(); + if (!fStream->seek(position)) { + return nullptr; + } + + sk_sp<SkData> data(SkData::MakeUninitialized(length)); + void* dst = data->writable_data(); + const bool success = fStream->read(dst, length) == length; + fStream->seek(oldPosition); + return success ? data : nullptr; +} |