gfx/skia/trunk/src/utils/SkFrontBufferedStream.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 * Copyright 2013 Google Inc.
michael@0 3 *
michael@0 4 * Use of this source code is governed by a BSD-style license that can be
michael@0 5 * found in the LICENSE file.
michael@0 6 */
michael@0 7
michael@0 8 #include "SkFrontBufferedStream.h"
michael@0 9 #include "SkStream.h"
michael@0 10 #include "SkTemplates.h"
michael@0 11
michael@0 12 class FrontBufferedStream : public SkStreamRewindable {
michael@0 13 public:
michael@0 14 // Called by Create.
michael@0 15 FrontBufferedStream(SkStream*, size_t bufferSize);
michael@0 16
michael@0 17 virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
michael@0 18
michael@0 19 virtual bool isAtEnd() const SK_OVERRIDE;
michael@0 20
michael@0 21 virtual bool rewind() SK_OVERRIDE;
michael@0 22
michael@0 23 virtual bool hasPosition() const SK_OVERRIDE { return true; }
michael@0 24
michael@0 25 virtual size_t getPosition() const SK_OVERRIDE { return fOffset; }
michael@0 26
michael@0 27 virtual bool hasLength() const SK_OVERRIDE { return fHasLength; }
michael@0 28
michael@0 29 virtual size_t getLength() const SK_OVERRIDE { return fLength; }
michael@0 30
michael@0 31 virtual SkStreamRewindable* duplicate() const SK_OVERRIDE { return NULL; }
michael@0 32
michael@0 33 private:
michael@0 34 SkAutoTUnref<SkStream> fStream;
michael@0 35 const bool fHasLength;
michael@0 36 const size_t fLength;
michael@0 37 // Current offset into the stream. Always >= 0.
michael@0 38 size_t fOffset;
michael@0 39 // Amount that has been buffered by calls to read. Will always be less than
michael@0 40 // fBufferSize.
michael@0 41 size_t fBufferedSoFar;
michael@0 42 // Total size of the buffer.
michael@0 43 const size_t fBufferSize;
michael@0 44 // FIXME: SkAutoTMalloc throws on failure. Instead, Create should return a
michael@0 45 // NULL stream.
michael@0 46 SkAutoTMalloc<char> fBuffer;
michael@0 47
michael@0 48 // Read up to size bytes from already buffered data, and copy to
michael@0 49 // dst, if non-NULL. Updates fOffset. Assumes that fOffset is less
michael@0 50 // than fBufferedSoFar.
michael@0 51 size_t readFromBuffer(char* dst, size_t size);
michael@0 52
michael@0 53 // Buffer up to size bytes from the stream, and copy to dst if non-
michael@0 54 // NULL. Updates fOffset and fBufferedSoFar. Assumes that fOffset is
michael@0 55 // less than fBufferedSoFar, and size is greater than 0.
michael@0 56 size_t bufferAndWriteTo(char* dst, size_t size);
michael@0 57
michael@0 58 // Read up to size bytes directly from the stream and into dst if non-
michael@0 59 // NULL. Updates fOffset. Assumes fOffset is at or beyond the buffered
michael@0 60 // data, and size is greater than 0.
michael@0 61 size_t readDirectlyFromStream(char* dst, size_t size);
michael@0 62
michael@0 63 typedef SkStream INHERITED;
michael@0 64 };
michael@0 65
michael@0 66 SkStreamRewindable* SkFrontBufferedStream::Create(SkStream* stream, size_t bufferSize) {
michael@0 67 if (NULL == stream) {
michael@0 68 return NULL;
michael@0 69 }
michael@0 70 return SkNEW_ARGS(FrontBufferedStream, (stream, bufferSize));
michael@0 71 }
michael@0 72
michael@0 73 FrontBufferedStream::FrontBufferedStream(SkStream* stream, size_t bufferSize)
michael@0 74 : fStream(SkRef(stream))
michael@0 75 , fHasLength(stream->hasPosition() && stream->hasLength())
michael@0 76 , fLength(stream->getLength() - stream->getPosition())
michael@0 77 , fOffset(0)
michael@0 78 , fBufferedSoFar(0)
michael@0 79 , fBufferSize(bufferSize)
michael@0 80 , fBuffer(bufferSize) {}
michael@0 81
michael@0 82 bool FrontBufferedStream::isAtEnd() const {
michael@0 83 if (fOffset < fBufferedSoFar) {
michael@0 84 // Even if the underlying stream is at the end, this stream has been
michael@0 85 // rewound after buffering, so it is not at the end.
michael@0 86 return false;
michael@0 87 }
michael@0 88
michael@0 89 return fStream->isAtEnd();
michael@0 90 }
michael@0 91
michael@0 92 bool FrontBufferedStream::rewind() {
michael@0 93 // Only allow a rewind if we have not exceeded the buffer.
michael@0 94 if (fOffset <= fBufferSize) {
michael@0 95 fOffset = 0;
michael@0 96 return true;
michael@0 97 }
michael@0 98 return false;
michael@0 99 }
michael@0 100
michael@0 101 size_t FrontBufferedStream::readFromBuffer(char* dst, size_t size) {
michael@0 102 SkASSERT(fOffset < fBufferedSoFar);
michael@0 103 // Some data has already been copied to fBuffer. Read up to the
michael@0 104 // lesser of the size requested and the remainder of the buffered
michael@0 105 // data.
michael@0 106 const size_t bytesToCopy = SkTMin(size, fBufferedSoFar - fOffset);
michael@0 107 if (dst != NULL) {
michael@0 108 memcpy(dst, fBuffer + fOffset, bytesToCopy);
michael@0 109 }
michael@0 110
michael@0 111 // Update fOffset to the new position. It is guaranteed to be
michael@0 112 // within the buffered data.
michael@0 113 fOffset += bytesToCopy;
michael@0 114 SkASSERT(fOffset <= fBufferedSoFar);
michael@0 115
michael@0 116 return bytesToCopy;
michael@0 117 }
michael@0 118
michael@0 119 size_t FrontBufferedStream::bufferAndWriteTo(char* dst, size_t size) {
michael@0 120 SkASSERT(size > 0);
michael@0 121 SkASSERT(fOffset >= fBufferedSoFar);
michael@0 122 // Data needs to be buffered. Buffer up to the lesser of the size requested
michael@0 123 // and the remainder of the max buffer size.
michael@0 124 const size_t bytesToBuffer = SkTMin(size, fBufferSize - fBufferedSoFar);
michael@0 125 char* buffer = fBuffer + fOffset;
michael@0 126 const size_t buffered = fStream->read(buffer, bytesToBuffer);
michael@0 127
michael@0 128 fBufferedSoFar += buffered;
michael@0 129 fOffset = fBufferedSoFar;
michael@0 130 SkASSERT(fBufferedSoFar <= fBufferSize);
michael@0 131
michael@0 132 // Copy the buffer to the destination buffer and update the amount read.
michael@0 133 if (dst != NULL) {
michael@0 134 memcpy(dst, buffer, buffered);
michael@0 135 }
michael@0 136
michael@0 137 return buffered;
michael@0 138 }
michael@0 139
michael@0 140 size_t FrontBufferedStream::readDirectlyFromStream(char* dst, size_t size) {
michael@0 141 SkASSERT(size > 0);
michael@0 142 // If we get here, we have buffered all that can be buffered.
michael@0 143 SkASSERT(fBufferSize == fBufferedSoFar && fOffset >= fBufferSize);
michael@0 144
michael@0 145 const size_t bytesReadDirectly = fStream->read(dst, size);
michael@0 146 fOffset += bytesReadDirectly;
michael@0 147
michael@0 148 // If we have read past the end of the buffer, rewinding is no longer
michael@0 149 // supported, so we can go ahead and free the memory.
michael@0 150 if (bytesReadDirectly > 0) {
michael@0 151 fBuffer.reset(0);
michael@0 152 }
michael@0 153
michael@0 154 return bytesReadDirectly;
michael@0 155 }
michael@0 156
michael@0 157 size_t FrontBufferedStream::read(void* voidDst, size_t size) {
michael@0 158 // Cast voidDst to a char* for easy addition.
michael@0 159 char* dst = reinterpret_cast<char*>(voidDst);
michael@0 160 SkDEBUGCODE(const size_t totalSize = size;)
michael@0 161 const size_t start = fOffset;
michael@0 162
michael@0 163 // First, read any data that was previously buffered.
michael@0 164 if (fOffset < fBufferedSoFar) {
michael@0 165 const size_t bytesCopied = this->readFromBuffer(dst, size);
michael@0 166
michael@0 167 // Update the remaining number of bytes needed to read
michael@0 168 // and the destination buffer.
michael@0 169 size -= bytesCopied;
michael@0 170 SkASSERT(size + (fOffset - start) == totalSize);
michael@0 171 if (dst != NULL) {
michael@0 172 dst += bytesCopied;
michael@0 173 }
michael@0 174 }
michael@0 175
michael@0 176 // Buffer any more data that should be buffered, and copy it to the
michael@0 177 // destination.
michael@0 178 if (size > 0 && fBufferedSoFar < fBufferSize) {
michael@0 179 const size_t buffered = this->bufferAndWriteTo(dst, size);
michael@0 180
michael@0 181 // Update the remaining number of bytes needed to read
michael@0 182 // and the destination buffer.
michael@0 183 size -= buffered;
michael@0 184 SkASSERT(size + (fOffset - start) == totalSize);
michael@0 185 if (dst != NULL) {
michael@0 186 dst += buffered;
michael@0 187 }
michael@0 188 }
michael@0 189
michael@0 190 if (size > 0 && !fStream->isAtEnd()) {
michael@0 191 SkDEBUGCODE(const size_t bytesReadDirectly =) this->readDirectlyFromStream(dst, size);
michael@0 192 SkDEBUGCODE(size -= bytesReadDirectly;)
michael@0 193 SkASSERT(size + (fOffset - start) == totalSize);
michael@0 194 }
michael@0 195
michael@0 196 return fOffset - start;
michael@0 197 }

mercurial