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 // Takes ownership of the SkStream. 28 SkStreamBuffer(SkStream*); 29 30 ~SkStreamBuffer(); 31 32 /** 33 * Return a pointer the buffered data. 34 * 35 * The number of bytes buffered is the number passed to buffer() 36 * after the last call to flush(). 37 */ 38 const char* get() const; 39 40 /** 41 * Buffer from the stream into our buffer. 42 * 43 * If this call returns true, get() can be used to access |bytes| bytes 44 * from the stream. In addition, markPosition() can be called to mark this 45 * position and enable calling getAtPosition() later to retrieve |bytes| 46 * bytes. 47 * 48 * @param bytes Total number of bytes desired. 49 * 50 * @return Whether all bytes were successfully buffered. 51 */ 52 bool buffer(size_t bytes); 53 54 /** 55 * Flush the buffer. 56 * 57 * After this call, no bytes are buffered. 58 */ flush()59 void flush() { 60 if (fHasLengthAndPosition) { 61 if (fTrulyBuffered < fBytesBuffered) { 62 fStream->move(fBytesBuffered - fTrulyBuffered); 63 } 64 fTrulyBuffered = 0; 65 } 66 fPosition += fBytesBuffered; 67 fBytesBuffered = 0; 68 } 69 70 /** 71 * Mark the current position in the stream to return to it later. 72 * 73 * This is the position of the start of the buffer. After this call, a 74 * a client can call getDataAtPosition to retrieve all the bytes currently 75 * buffered. 76 * 77 * @return size_t Position which can be passed to getDataAtPosition later 78 * to retrieve the data currently buffered. 79 */ 80 size_t markPosition(); 81 82 /** 83 * Retrieve data at position, as previously marked by markPosition(). 84 * 85 * @param position Position to retrieve data, as marked by markPosition(). 86 * @param length Amount of data required at position. 87 * @return SkData The data at position. 88 */ 89 sk_sp<SkData> getDataAtPosition(size_t position, size_t length); 90 91 private: 92 static constexpr size_t kMaxSize = 256 * 3; 93 94 std::unique_ptr<SkStream> fStream; 95 size_t fPosition; 96 char fBuffer[kMaxSize]; 97 size_t fBytesBuffered; 98 // If the stream has a length and position, we can make two optimizations: 99 // - We can skip buffering 100 // - During parsing, we can store the position and size of data that is 101 // needed later during decoding. 102 const bool fHasLengthAndPosition; 103 // When fHasLengthAndPosition is true, we do not need to actually buffer 104 // inside buffer(). We'll buffer inside get(). This keeps track of how many 105 // bytes we've buffered inside get(), for the (non-existent) case of: 106 // buffer(n) 107 // get() 108 // buffer(n + u) 109 // get() 110 // The second call to get() needs to only truly buffer the part that was 111 // not already buffered. 112 mutable size_t fTrulyBuffered; 113 // Only used if !fHasLengthAndPosition. In that case, markPosition will 114 // copy into an SkData, stored here. 115 SkTHashMap<size_t, SkData*> fMarkedData; 116 }; 117 #endif // SkStreamBuffer_DEFINED 118 119