1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* 2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2015 Google Inc. 3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be 5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file. 6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRWBuffer.h" 9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkAtomics.h" 11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkMalloc.h" 12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkMakeUnique.h" 13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkStream.h" 14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <atomic> 16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Force small chunks to be a page's worth 18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic const size_t kMinAllocSize = 4096; 19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct SkBufferBlock { 21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkBufferBlock* fNext; // updated by the writer 22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t fUsed; // updated by the writer 23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const size_t fCapacity; 24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkBufferBlock(size_t capacity) : fNext(nullptr), fUsed(0), fCapacity(capacity) {} 26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const void* startData() const { return this + 1; } 28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t avail() const { return fCapacity - fUsed; } 30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void* availData() { return (char*)this->startData() + fUsed; } 31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static SkBufferBlock* Alloc(size_t length) { 33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t capacity = LengthToCapacity(length); 34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void* buffer = sk_malloc_throw(sizeof(SkBufferBlock) + capacity); 35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return new (buffer) SkBufferBlock(capacity); 36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Return number of bytes actually appended. Important that we always completely this block 39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // before spilling into the next, since the reader uses fCapacity to know how many it can read. 40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // 41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t append(const void* src, size_t length) { 42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->validate(); 43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t amount = SkTMin(this->avail(), length); 44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot memcpy(this->availData(), src, amount); 45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fUsed += amount; 46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->validate(); 47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return amount; 48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Do not call in the reader thread, since the writer may be updating fUsed. 51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // (The assertion is still true, but TSAN still may complain about its raciness.) 52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void validate() const { 53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG 54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fCapacity > 0); 55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fUsed <= fCapacity); 56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif 57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate: 60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static size_t LengthToCapacity(size_t length) { 61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const size_t minSize = kMinAllocSize - sizeof(SkBufferBlock); 62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return SkTMax(length, minSize); 63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct SkBufferHead { 67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot mutable std::atomic<int32_t> fRefCnt; 68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkBufferBlock fBlock; 69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkBufferHead(size_t capacity) : fRefCnt(1), fBlock(capacity) {} 71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static size_t LengthToCapacity(size_t length) { 73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const size_t minSize = kMinAllocSize - sizeof(SkBufferHead); 74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return SkTMax(length, minSize); 75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static SkBufferHead* Alloc(size_t length) { 78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t capacity = LengthToCapacity(length); 79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t size = sizeof(SkBufferHead) + capacity; 80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void* buffer = sk_malloc_throw(size); 81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return new (buffer) SkBufferHead(capacity); 82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void ref() const { 85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkAssertResult(fRefCnt.fetch_add(+1, std::memory_order_relaxed)); 86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void unref() const { 89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // A release here acts in place of all releases we "should" have been doing in ref(). 90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int32_t oldRefCnt = fRefCnt.fetch_add(-1, std::memory_order_acq_rel); 91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(oldRefCnt); 92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (1 == oldRefCnt) { 93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Like unique(), the acquire is only needed on success. 94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkBufferBlock* block = fBlock.fNext; 95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_free((void*)this); 96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot while (block) { 97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkBufferBlock* next = block->fNext; 98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_free(block); 99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot block = next; 100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void validate(size_t minUsed, const SkBufferBlock* tail = nullptr) const { 105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG 106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fRefCnt.load(std::memory_order_relaxed) > 0); 107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t totalUsed = 0; 108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkBufferBlock* block = &fBlock; 109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkBufferBlock* lastBlock = block; 110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot while (block) { 111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot block->validate(); 112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot totalUsed += block->fUsed; 113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot lastBlock = block; 114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot block = block->fNext; 115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(minUsed <= totalUsed); 117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (tail) { 118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(tail == lastBlock); 119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif 121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/////////////////////////////////////////////////////////////////////////////////////////////////// 125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// The reader can only access block.fCapacity (which never changes), and cannot access 126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// block.fUsed, which may be updated by the writer. 127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkROBuffer::SkROBuffer(const SkBufferHead* head, size_t available, const SkBufferBlock* tail) 129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot : fHead(head), fAvailable(available), fTail(tail) 130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot{ 131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (head) { 132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fHead->ref(); 133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(available > 0); 134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot head->validate(available, tail); 135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(0 == available); 137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(!tail); 138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkROBuffer::~SkROBuffer() { 142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (fHead) { 143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fHead->unref(); 144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkROBuffer::Iter::Iter(const SkROBuffer* buffer) { 148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->reset(buffer); 149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkROBuffer::Iter::Iter(const sk_sp<SkROBuffer>& buffer) { 152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->reset(buffer.get()); 153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkROBuffer::Iter::reset(const SkROBuffer* buffer) { 156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fBuffer = buffer; 157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (buffer && buffer->fHead) { 158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fBlock = &buffer->fHead->fBlock; 159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fRemaining = buffer->fAvailable; 160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fBlock = nullptr; 162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fRemaining = 0; 163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst void* SkROBuffer::Iter::data() const { 167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fRemaining ? fBlock->startData() : nullptr; 168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsize_t SkROBuffer::Iter::size() const { 171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!fBlock) { 172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return 0; 173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return SkTMin(fBlock->fCapacity, fRemaining); 175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkROBuffer::Iter::next() { 178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (fRemaining) { 179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fRemaining -= this->size(); 180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (fBuffer->fTail == fBlock) { 181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // There are more blocks, but fBuffer does not know about them. 182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(0 == fRemaining); 183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fBlock = nullptr; 184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fBlock = fBlock->fNext; 186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fRemaining != 0; 189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/////////////////////////////////////////////////////////////////////////////////////////////////// 192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkRWBuffer::SkRWBuffer(size_t initialCapacity) : fHead(nullptr), fTail(nullptr), fTotalUsed(0) { 194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (initialCapacity) { 195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fHead = SkBufferHead::Alloc(initialCapacity); 196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fTail = &fHead->fBlock; 197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkRWBuffer::~SkRWBuffer() { 201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->validate(); 202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (fHead) { 203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fHead->unref(); 204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// It is important that we always completely fill the current block before spilling over to the 208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// next, since our reader will be using fCapacity (min'd against its total available) to know how 209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// many bytes to read from a given block. 210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkRWBuffer::append(const void* src, size_t length, size_t reserve) { 212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->validate(); 213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (0 == length) { 214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fTotalUsed += length; 218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (nullptr == fHead) { 220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fHead = SkBufferHead::Alloc(length + reserve); 221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fTail = &fHead->fBlock; 222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t written = fTail->append(src, length); 225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(written <= length); 226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot src = (const char*)src + written; 227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot length -= written; 228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (length) { 230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkBufferBlock* block = SkBufferBlock::Alloc(length + reserve); 231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fTail->fNext = block; 232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fTail = block; 233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot written = fTail->append(src, length); 234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(written == length); 235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->validate(); 237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG 240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkRWBuffer::validate() const { 241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (fHead) { 242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fHead->validate(fTotalUsed, fTail); 243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(nullptr == fTail); 245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(0 == fTotalUsed); 246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif 249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/////////////////////////////////////////////////////////////////////////////////////////////////// 251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkROBufferStreamAsset : public SkStreamAsset { 253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void validate() const { 254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG 255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fGlobalOffset <= fBuffer->size()); 256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fLocalOffset <= fIter.size()); 257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fLocalOffset <= fGlobalOffset); 258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif 259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG 262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot class AutoValidate { 263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkROBufferStreamAsset* fStream; 264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot public: 265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot AutoValidate(SkROBufferStreamAsset* stream) : fStream(stream) { stream->validate(); } 266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ~AutoValidate() { fStream->validate(); } 267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot }; 268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot #define AUTO_VALIDATE AutoValidate av(this); 269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#else 270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot #define AUTO_VALIDATE 271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif 272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic: 274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkROBufferStreamAsset(sk_sp<SkROBuffer> buffer) : fBuffer(std::move(buffer)), fIter(fBuffer) { 275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fGlobalOffset = fLocalOffset = 0; 276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t getLength() const override { return fBuffer->size(); } 279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool rewind() override { 281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot AUTO_VALIDATE 282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fIter.reset(fBuffer.get()); 283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fGlobalOffset = fLocalOffset = 0; 284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return true; 285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t read(void* dst, size_t request) override { 288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot AUTO_VALIDATE 289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t bytesRead = 0; 290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (;;) { 291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t size = fIter.size(); 292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fLocalOffset <= size); 293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t avail = SkTMin(size - fLocalOffset, request - bytesRead); 294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (dst) { 295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot memcpy(dst, (const char*)fIter.data() + fLocalOffset, avail); 296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot dst = (char*)dst + avail; 297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bytesRead += avail; 299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fLocalOffset += avail; 300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(bytesRead <= request); 301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (bytesRead == request) { 302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // If we get here, we've exhausted the current iter 305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fLocalOffset == size); 306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fLocalOffset = 0; 307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!fIter.next()) { 308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; // ran out of data 309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fGlobalOffset += bytesRead; 312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fGlobalOffset <= fBuffer->size()); 313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return bytesRead; 314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool isAtEnd() const override { 317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fBuffer->size() == fGlobalOffset; 318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t getPosition() const override { 321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fGlobalOffset; 322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool seek(size_t position) override { 325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot AUTO_VALIDATE 326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (position < fGlobalOffset) { 327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->rewind(); 328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot (void)this->skip(position - fGlobalOffset); 330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return true; 331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool move(long offset) override{ 334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot AUTO_VALIDATE 335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot offset += fGlobalOffset; 336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (offset <= 0) { 337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->rewind(); 338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot (void)this->seek(SkToSizeT(offset)); 340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return true; 342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate: 345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkStreamAsset* onDuplicate() const override { 346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return new SkROBufferStreamAsset(fBuffer); 347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkStreamAsset* onFork() const override { 350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot auto clone = this->duplicate(); 351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot clone->seek(this->getPosition()); 352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return clone.release(); 353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_sp<SkROBuffer> fBuffer; 356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkROBuffer::Iter fIter; 357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t fLocalOffset; 358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t fGlobalOffset; 359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstd::unique_ptr<SkStreamAsset> SkRWBuffer::makeStreamSnapshot() const { 362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return skstd::make_unique<SkROBufferStreamAsset>(this->makeROBufferSnapshot()); 363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 364