• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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