1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkStreamBuffer_DEFINED 9 #define SkStreamBuffer_DEFINED 10 11 #include "SkData.h" 12 #include "SkStream.h" 13 #include "SkTypes.h" 14 #include "../private/SkTHash.h" 15 16 /** 17 * Helper class for reading from a stream that may not have all its data 18 * available yet. 19 * 20 * Used by GIFImageReader, and currently set up for that use case. 21 * 22 * Buffers up to 256 * 3 bytes (256 colors, with 3 bytes each) to support GIF. 23 * FIXME (scroggo): Make this more general purpose? 24 */ 25 class SkStreamBuffer : SkNoncopyable { 26 public: 27 SkStreamBuffer(std::unique_ptr<SkStream>); 28 ~SkStreamBuffer(); 29 30 /** 31 * Return a pointer the buffered data. 32 * 33 * The number of bytes buffered is the number passed to buffer() 34 * after the last call to flush(). 35 */ 36 const char* get() const; 37 38 /** 39 * Buffer from the stream into our buffer. 40 * 41 * If this call returns true, get() can be used to access |bytes| bytes 42 * from the stream. In addition, markPosition() can be called to mark this 43 * position and enable calling getAtPosition() later to retrieve |bytes| 44 * bytes. 45 * 46 * @param bytes Total number of bytes desired. 47 * 48 * @return Whether all bytes were successfully buffered. 49 */ 50 bool buffer(size_t bytes); 51 52 /** 53 * Flush the buffer. 54 * 55 * After this call, no bytes are buffered. 56 */ 57 void flush() { 58 if (fHasLengthAndPosition) { 59 if (fTrulyBuffered < fBytesBuffered) { 60 fStream->move(fBytesBuffered - fTrulyBuffered); 61 } 62 fTrulyBuffered = 0; 63 } 64 fPosition += fBytesBuffered; 65 fBytesBuffered = 0; 66 } 67 68 /** 69 * Mark the current position in the stream to return to it later. 70 * 71 * This is the position of the start of the buffer. After this call, a 72 * a client can call getDataAtPosition to retrieve all the bytes currently 73 * buffered. 74 * 75 * @return size_t Position which can be passed to getDataAtPosition later 76 * to retrieve the data currently buffered. 77 */ 78 size_t markPosition(); 79 80 /** 81 * Retrieve data at position, as previously marked by markPosition(). 82 * 83 * @param position Position to retrieve data, as marked by markPosition(). 84 * @param length Amount of data required at position. 85 * @return SkData The data at position. 86 */ 87 sk_sp<SkData> getDataAtPosition(size_t position, size_t length); 88 89 private: 90 static constexpr size_t kMaxSize = 256 * 3; 91 92 std::unique_ptr<SkStream> fStream; 93 size_t fPosition; 94 char fBuffer[kMaxSize]; 95 size_t fBytesBuffered; 96 // If the stream has a length and position, we can make two optimizations: 97 // - We can skip buffering 98 // - During parsing, we can store the position and size of data that is 99 // needed later during decoding. 100 const bool fHasLengthAndPosition; 101 // When fHasLengthAndPosition is true, we do not need to actually buffer 102 // inside buffer(). We'll buffer inside get(). This keeps track of how many 103 // bytes we've buffered inside get(), for the (non-existent) case of: 104 // buffer(n) 105 // get() 106 // buffer(n + u) 107 // get() 108 // The second call to get() needs to only truly buffer the part that was 109 // not already buffered. 110 mutable size_t fTrulyBuffered; 111 // Only used if !fHasLengthAndPosition. In that case, markPosition will 112 // copy into an SkData, stored here. 113 SkTHashMap<size_t, SkData*> fMarkedData; 114 }; 115 #endif // SkStreamBuffer_DEFINED 116 117