1 /*
2  * Copyright 2015 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 #include "SkRWBuffer.h"
9 #include "SkStream.h"
10 
11 // Force small chunks to be a page's worth
12 static const size_t kMinAllocSize = 4096;
13 
14 struct SkBufferBlock {
15     SkBufferBlock*  fNext;
16     size_t          fUsed;
17     size_t          fCapacity;
18 
startDataSkBufferBlock19     const void* startData() const { return this + 1; };
20 
availSkBufferBlock21     size_t avail() const { return fCapacity - fUsed; }
availDataSkBufferBlock22     void* availData() { return (char*)this->startData() + fUsed; }
23 
AllocSkBufferBlock24     static SkBufferBlock* Alloc(size_t length) {
25         size_t capacity = LengthToCapacity(length);
26         SkBufferBlock* block = (SkBufferBlock*)sk_malloc_throw(sizeof(SkBufferBlock) + capacity);
27         block->fNext = nullptr;
28         block->fUsed = 0;
29         block->fCapacity = capacity;
30         return block;
31     }
32 
33     // Return number of bytes actually appended
appendSkBufferBlock34     size_t append(const void* src, size_t length) {
35         this->validate();
36         size_t amount = SkTMin(this->avail(), length);
37         memcpy(this->availData(), src, amount);
38         fUsed += amount;
39         this->validate();
40         return amount;
41     }
42 
validateSkBufferBlock43     void validate() const {
44 #ifdef SK_DEBUG
45         SkASSERT(fCapacity > 0);
46         SkASSERT(fUsed <= fCapacity);
47 #endif
48     }
49 
50 private:
LengthToCapacitySkBufferBlock51     static size_t LengthToCapacity(size_t length) {
52         const size_t minSize = kMinAllocSize - sizeof(SkBufferBlock);
53         return SkTMax(length, minSize);
54     }
55 };
56 
57 struct SkBufferHead {
58     mutable int32_t fRefCnt;
59     SkBufferBlock   fBlock;
60 
LengthToCapacitySkBufferHead61     static size_t LengthToCapacity(size_t length) {
62         const size_t minSize = kMinAllocSize - sizeof(SkBufferHead);
63         return SkTMax(length, minSize);
64     }
65 
AllocSkBufferHead66     static SkBufferHead* Alloc(size_t length) {
67         size_t capacity = LengthToCapacity(length);
68         size_t size = sizeof(SkBufferHead) + capacity;
69         SkBufferHead* head = (SkBufferHead*)sk_malloc_throw(size);
70         head->fRefCnt = 1;
71         head->fBlock.fNext = nullptr;
72         head->fBlock.fUsed = 0;
73         head->fBlock.fCapacity = capacity;
74         return head;
75     }
76 
refSkBufferHead77     void ref() const {
78         SkASSERT(fRefCnt > 0);
79         sk_atomic_inc(&fRefCnt);
80     }
81 
unrefSkBufferHead82     void unref() const {
83         SkASSERT(fRefCnt > 0);
84         // A release here acts in place of all releases we "should" have been doing in ref().
85         if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) {
86             // Like unique(), the acquire is only needed on success.
87             SkBufferBlock* block = fBlock.fNext;
88             sk_free((void*)this);
89             while (block) {
90                 SkBufferBlock* next = block->fNext;
91                 sk_free(block);
92                 block = next;
93             }
94         }
95     }
96 
validateSkBufferHead97     void validate(size_t minUsed, SkBufferBlock* tail = nullptr) const {
98 #ifdef SK_DEBUG
99         SkASSERT(fRefCnt > 0);
100         size_t totalUsed = 0;
101         const SkBufferBlock* block = &fBlock;
102         const SkBufferBlock* lastBlock = block;
103         while (block) {
104             block->validate();
105             totalUsed += block->fUsed;
106             lastBlock = block;
107             block = block->fNext;
108         }
109         SkASSERT(minUsed <= totalUsed);
110         if (tail) {
111             SkASSERT(tail == lastBlock);
112         }
113 #endif
114     }
115 };
116 
SkROBuffer(const SkBufferHead * head,size_t used)117 SkROBuffer::SkROBuffer(const SkBufferHead* head, size_t used) : fHead(head), fUsed(used) {
118     if (head) {
119         fHead->ref();
120         SkASSERT(used > 0);
121         head->validate(used);
122     } else {
123         SkASSERT(0 == used);
124     }
125 }
126 
~SkROBuffer()127 SkROBuffer::~SkROBuffer() {
128     if (fHead) {
129         fHead->validate(fUsed);
130         fHead->unref();
131     }
132 }
133 
Iter(const SkROBuffer * buffer)134 SkROBuffer::Iter::Iter(const SkROBuffer* buffer) {
135     this->reset(buffer);
136 }
137 
reset(const SkROBuffer * buffer)138 void SkROBuffer::Iter::reset(const SkROBuffer* buffer) {
139     if (buffer) {
140         fBlock = &buffer->fHead->fBlock;
141         fRemaining = buffer->fUsed;
142     } else {
143         fBlock = nullptr;
144         fRemaining = 0;
145     }
146 }
147 
data() const148 const void* SkROBuffer::Iter::data() const {
149     return fRemaining ? fBlock->startData() : nullptr;
150 }
151 
size() const152 size_t SkROBuffer::Iter::size() const {
153     if (!fBlock) {
154         return 0;
155     }
156     return SkTMin(fBlock->fUsed, fRemaining);
157 }
158 
next()159 bool SkROBuffer::Iter::next() {
160     if (fRemaining) {
161         fRemaining -= this->size();
162         fBlock = fBlock->fNext;
163     }
164     return fRemaining != 0;
165 }
166 
SkRWBuffer(size_t initialCapacity)167 SkRWBuffer::SkRWBuffer(size_t initialCapacity) : fHead(nullptr), fTail(nullptr), fTotalUsed(0) {}
168 
~SkRWBuffer()169 SkRWBuffer::~SkRWBuffer() {
170     this->validate();
171     if (fHead) {
172         fHead->unref();
173     }
174 }
175 
append(const void * src,size_t length)176 void SkRWBuffer::append(const void* src, size_t length) {
177     this->validate();
178     if (0 == length) {
179         return;
180     }
181 
182     fTotalUsed += length;
183 
184     if (nullptr == fHead) {
185         fHead = SkBufferHead::Alloc(length);
186         fTail = &fHead->fBlock;
187     }
188 
189     size_t written = fTail->append(src, length);
190     SkASSERT(written <= length);
191     src = (const char*)src + written;
192     length -= written;
193 
194     if (length) {
195         SkBufferBlock* block = SkBufferBlock::Alloc(length);
196         fTail->fNext = block;
197         fTail = block;
198         written = fTail->append(src, length);
199         SkASSERT(written == length);
200     }
201     this->validate();
202 }
203 
append(size_t length)204 void* SkRWBuffer::append(size_t length) {
205     this->validate();
206     if (0 == length) {
207         return nullptr;
208     }
209 
210     fTotalUsed += length;
211 
212     if (nullptr == fHead) {
213         fHead = SkBufferHead::Alloc(length);
214         fTail = &fHead->fBlock;
215     } else if (fTail->avail() < length) {
216         SkBufferBlock* block = SkBufferBlock::Alloc(length);
217         fTail->fNext = block;
218         fTail = block;
219     }
220 
221     fTail->fUsed += length;
222     this->validate();
223     return (char*)fTail->availData() - length;
224 }
225 
226 #ifdef SK_DEBUG
validate() const227 void SkRWBuffer::validate() const {
228     if (fHead) {
229         fHead->validate(fTotalUsed, fTail);
230     } else {
231         SkASSERT(nullptr == fTail);
232         SkASSERT(0 == fTotalUsed);
233     }
234 }
235 #endif
236 
newRBufferSnapshot() const237 SkROBuffer* SkRWBuffer::newRBufferSnapshot() const { return new SkROBuffer(fHead, fTotalUsed); }
238 
239 ///////////////////////////////////////////////////////////////////////////////////////////////////
240 
241 class SkROBufferStreamAsset : public SkStreamAsset {
validate() const242     void validate() const {
243 #ifdef SK_DEBUG
244         SkASSERT(fGlobalOffset <= fBuffer->size());
245         SkASSERT(fLocalOffset <= fIter.size());
246         SkASSERT(fLocalOffset <= fGlobalOffset);
247 #endif
248     }
249 
250 #ifdef SK_DEBUG
251     class AutoValidate {
252         SkROBufferStreamAsset* fStream;
253     public:
AutoValidate(SkROBufferStreamAsset * stream)254         AutoValidate(SkROBufferStreamAsset* stream) : fStream(stream) { stream->validate(); }
~AutoValidate()255         ~AutoValidate() { fStream->validate(); }
256     };
257     #define AUTO_VALIDATE   AutoValidate av(this);
258 #else
259     #define AUTO_VALIDATE
260 #endif
261 
262 public:
SkROBufferStreamAsset(const SkROBuffer * buffer)263     SkROBufferStreamAsset(const SkROBuffer* buffer) : fBuffer(SkRef(buffer)), fIter(buffer) {
264         fGlobalOffset = fLocalOffset = 0;
265     }
266 
~SkROBufferStreamAsset()267     virtual ~SkROBufferStreamAsset() { fBuffer->unref(); }
268 
getLength() const269     size_t getLength() const override { return fBuffer->size(); }
270 
rewind()271     bool rewind() override {
272         AUTO_VALIDATE
273         fIter.reset(fBuffer);
274         fGlobalOffset = fLocalOffset = 0;
275         return true;
276     }
277 
read(void * dst,size_t request)278     size_t read(void* dst, size_t request) override {
279         AUTO_VALIDATE
280         size_t bytesRead = 0;
281         for (;;) {
282             size_t size = fIter.size();
283             SkASSERT(fLocalOffset <= size);
284             size_t avail = SkTMin(size - fLocalOffset, request - bytesRead);
285             if (dst) {
286                 memcpy(dst, (const char*)fIter.data() + fLocalOffset, avail);
287                 dst = (char*)dst + avail;
288             }
289             bytesRead += avail;
290             fLocalOffset += avail;
291             SkASSERT(bytesRead <= request);
292             if (bytesRead == request) {
293                 break;
294             }
295             // If we get here, we've exhausted the current iter
296             SkASSERT(fLocalOffset == size);
297             fLocalOffset = 0;
298             if (!fIter.next()) {
299                 break;   // ran out of data
300             }
301         }
302         fGlobalOffset += bytesRead;
303         SkASSERT(fGlobalOffset <= fBuffer->size());
304         return bytesRead;
305     }
306 
isAtEnd() const307     bool isAtEnd() const override {
308         return fBuffer->size() == fGlobalOffset;
309     }
310 
duplicate() const311     SkStreamAsset* duplicate() const override { return new SkROBufferStreamAsset(fBuffer); }
312 
getPosition() const313     size_t getPosition() const override {
314         return fGlobalOffset;
315     }
316 
seek(size_t position)317     bool seek(size_t position) override {
318         AUTO_VALIDATE
319         if (position < fGlobalOffset) {
320             this->rewind();
321         }
322         (void)this->skip(position - fGlobalOffset);
323         return true;
324     }
325 
move(long offset)326     bool move(long offset)  override{
327         AUTO_VALIDATE
328         offset += fGlobalOffset;
329         if (offset <= 0) {
330             this->rewind();
331         } else {
332             (void)this->seek(SkToSizeT(offset));
333         }
334         return true;
335     }
336 
fork() const337     SkStreamAsset* fork() const override {
338         SkStreamAsset* clone = this->duplicate();
339         clone->seek(this->getPosition());
340         return clone;
341     }
342 
343 
344 private:
345     const SkROBuffer*   fBuffer;
346     SkROBuffer::Iter    fIter;
347     size_t              fLocalOffset;
348     size_t              fGlobalOffset;
349 };
350 
newStreamSnapshot() const351 SkStreamAsset* SkRWBuffer::newStreamSnapshot() const {
352     SkAutoTUnref<SkROBuffer> buffer(this->newRBufferSnapshot());
353     return new SkROBufferStreamAsset(buffer);
354 }
355