summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/codec/SkStreamBuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/skia/skia/src/codec/SkStreamBuffer.cpp')
-rw-r--r--gfx/skia/skia/src/codec/SkStreamBuffer.cpp88
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;
+}