michael@0: michael@0: /* michael@0: * Copyright 2008 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #ifndef SkWriter32_DEFINED michael@0: #define SkWriter32_DEFINED michael@0: michael@0: #include "SkData.h" michael@0: #include "SkMatrix.h" michael@0: #include "SkPath.h" michael@0: #include "SkPoint.h" michael@0: #include "SkRRect.h" michael@0: #include "SkRect.h" michael@0: #include "SkRegion.h" michael@0: #include "SkScalar.h" michael@0: #include "SkStream.h" michael@0: #include "SkTemplates.h" michael@0: #include "SkTypes.h" michael@0: michael@0: class SkWriter32 : SkNoncopyable { michael@0: public: michael@0: /** michael@0: * The caller can specify an initial block of storage, which the caller manages. michael@0: * michael@0: * SkWriter32 will try to back reserve and write calls with this external storage until the michael@0: * first time an allocation doesn't fit. From then it will use dynamically allocated storage. michael@0: * This used to be optional behavior, but pipe now relies on it. michael@0: */ michael@0: SkWriter32(void* external = NULL, size_t externalBytes = 0) { michael@0: this->reset(external, externalBytes); michael@0: } michael@0: michael@0: // return the current offset (will always be a multiple of 4) michael@0: size_t bytesWritten() const { return fUsed; } michael@0: michael@0: SK_ATTR_DEPRECATED("use bytesWritten") michael@0: size_t size() const { return this->bytesWritten(); } michael@0: michael@0: void reset(void* external = NULL, size_t externalBytes = 0) { michael@0: SkASSERT(SkIsAlign4((uintptr_t)external)); michael@0: SkASSERT(SkIsAlign4(externalBytes)); michael@0: michael@0: fSnapshot.reset(NULL); michael@0: fData = (uint8_t*)external; michael@0: fCapacity = externalBytes; michael@0: fUsed = 0; michael@0: fExternal = external; michael@0: } michael@0: michael@0: // Returns the current buffer. michael@0: // The pointer may be invalidated by any future write calls. michael@0: const uint32_t* contiguousArray() const { michael@0: return (uint32_t*)fData; michael@0: } michael@0: michael@0: // size MUST be multiple of 4 michael@0: uint32_t* reserve(size_t size) { michael@0: SkASSERT(SkAlign4(size) == size); michael@0: size_t offset = fUsed; michael@0: size_t totalRequired = fUsed + size; michael@0: if (totalRequired > fCapacity) { michael@0: this->growToAtLeast(totalRequired); michael@0: } michael@0: fUsed = totalRequired; michael@0: return (uint32_t*)(fData + offset); michael@0: } michael@0: michael@0: /** michael@0: * Read a T record at offset, which must be a multiple of 4. Only legal if the record michael@0: * was written atomically using the write methods below. michael@0: */ michael@0: template michael@0: const T& readTAt(size_t offset) const { michael@0: SkASSERT(SkAlign4(offset) == offset); michael@0: SkASSERT(offset < fUsed); michael@0: return *(T*)(fData + offset); michael@0: } michael@0: michael@0: /** michael@0: * Overwrite a T record at offset, which must be a multiple of 4. Only legal if the record michael@0: * was written atomically using the write methods below. michael@0: */ michael@0: template michael@0: void overwriteTAt(size_t offset, const T& value) { michael@0: SkASSERT(SkAlign4(offset) == offset); michael@0: SkASSERT(offset < fUsed); michael@0: SkASSERT(fSnapshot.get() == NULL); michael@0: *(T*)(fData + offset) = value; michael@0: } michael@0: michael@0: bool writeBool(bool value) { michael@0: this->write32(value); michael@0: return value; michael@0: } michael@0: michael@0: void writeInt(int32_t value) { michael@0: this->write32(value); michael@0: } michael@0: michael@0: void write8(int32_t value) { michael@0: *(int32_t*)this->reserve(sizeof(value)) = value & 0xFF; michael@0: } michael@0: michael@0: void write16(int32_t value) { michael@0: *(int32_t*)this->reserve(sizeof(value)) = value & 0xFFFF; michael@0: } michael@0: michael@0: void write32(int32_t value) { michael@0: *(int32_t*)this->reserve(sizeof(value)) = value; michael@0: } michael@0: michael@0: void writePtr(void* value) { michael@0: *(void**)this->reserve(sizeof(value)) = value; michael@0: } michael@0: michael@0: void writeScalar(SkScalar value) { michael@0: *(SkScalar*)this->reserve(sizeof(value)) = value; michael@0: } michael@0: michael@0: void writePoint(const SkPoint& pt) { michael@0: *(SkPoint*)this->reserve(sizeof(pt)) = pt; michael@0: } michael@0: michael@0: void writeRect(const SkRect& rect) { michael@0: *(SkRect*)this->reserve(sizeof(rect)) = rect; michael@0: } michael@0: michael@0: void writeIRect(const SkIRect& rect) { michael@0: *(SkIRect*)this->reserve(sizeof(rect)) = rect; michael@0: } michael@0: michael@0: void writeRRect(const SkRRect& rrect) { michael@0: rrect.writeToMemory(this->reserve(SkRRect::kSizeInMemory)); michael@0: } michael@0: michael@0: void writePath(const SkPath& path) { michael@0: size_t size = path.writeToMemory(NULL); michael@0: SkASSERT(SkAlign4(size) == size); michael@0: path.writeToMemory(this->reserve(size)); michael@0: } michael@0: michael@0: void writeMatrix(const SkMatrix& matrix) { michael@0: size_t size = matrix.writeToMemory(NULL); michael@0: SkASSERT(SkAlign4(size) == size); michael@0: matrix.writeToMemory(this->reserve(size)); michael@0: } michael@0: michael@0: void writeRegion(const SkRegion& rgn) { michael@0: size_t size = rgn.writeToMemory(NULL); michael@0: SkASSERT(SkAlign4(size) == size); michael@0: rgn.writeToMemory(this->reserve(size)); michael@0: } michael@0: michael@0: // write count bytes (must be a multiple of 4) michael@0: void writeMul4(const void* values, size_t size) { michael@0: this->write(values, size); michael@0: } michael@0: michael@0: /** michael@0: * Write size bytes from values. size must be a multiple of 4, though michael@0: * values need not be 4-byte aligned. michael@0: */ michael@0: void write(const void* values, size_t size) { michael@0: SkASSERT(SkAlign4(size) == size); michael@0: memcpy(this->reserve(size), values, size); michael@0: } michael@0: michael@0: /** michael@0: * Reserve size bytes. Does not need to be 4 byte aligned. The remaining space (if any) will be michael@0: * filled in with zeroes. michael@0: */ michael@0: uint32_t* reservePad(size_t size) { michael@0: size_t alignedSize = SkAlign4(size); michael@0: uint32_t* p = this->reserve(alignedSize); michael@0: if (alignedSize != size) { michael@0: SkASSERT(alignedSize >= 4); michael@0: p[alignedSize / 4 - 1] = 0; michael@0: } michael@0: return p; michael@0: } michael@0: michael@0: /** michael@0: * Write size bytes from src, and pad to 4 byte alignment with zeroes. michael@0: */ michael@0: void writePad(const void* src, size_t size) { michael@0: memcpy(this->reservePad(size), src, size); michael@0: } michael@0: michael@0: /** michael@0: * Writes a string to the writer, which can be retrieved with michael@0: * SkReader32::readString(). michael@0: * The length can be specified, or if -1 is passed, it will be computed by michael@0: * calling strlen(). The length must be < max size_t. michael@0: * michael@0: * If you write NULL, it will be read as "". michael@0: */ michael@0: void writeString(const char* str, size_t len = (size_t)-1); michael@0: michael@0: /** michael@0: * Computes the size (aligned to multiple of 4) need to write the string michael@0: * in a call to writeString(). If the length is not specified, it will be michael@0: * computed by calling strlen(). michael@0: */ michael@0: static size_t WriteStringSize(const char* str, size_t len = (size_t)-1); michael@0: michael@0: /** michael@0: * Move the cursor back to offset bytes from the beginning. michael@0: * offset must be a multiple of 4 no greater than size(). michael@0: */ michael@0: void rewindToOffset(size_t offset) { michael@0: SkASSERT(SkAlign4(offset) == offset); michael@0: SkASSERT(offset <= bytesWritten()); michael@0: fUsed = offset; michael@0: } michael@0: michael@0: // copy into a single buffer (allocated by caller). Must be at least size() michael@0: void flatten(void* dst) const { michael@0: memcpy(dst, fData, fUsed); michael@0: } michael@0: michael@0: bool writeToStream(SkWStream* stream) const { michael@0: return stream->write(fData, fUsed); michael@0: } michael@0: michael@0: // read from the stream, and write up to length bytes. Return the actual michael@0: // number of bytes written. michael@0: size_t readFromStream(SkStream* stream, size_t length) { michael@0: return stream->read(this->reservePad(length), length); michael@0: } michael@0: michael@0: /** michael@0: * Captures a snapshot of the data as it is right now, and return it. michael@0: * Multiple calls without intervening writes may return the same SkData, michael@0: * but this is not guaranteed. michael@0: * Future appends will not affect the returned buffer. michael@0: * It is illegal to call overwriteTAt after this without an intervening michael@0: * append. It may cause the snapshot buffer to be corrupted. michael@0: * Callers must unref the returned SkData. michael@0: * This is not thread safe, it should only be called on the writing thread, michael@0: * the result however can be shared across threads. michael@0: */ michael@0: SkData* snapshotAsData() const; michael@0: private: michael@0: void growToAtLeast(size_t size); michael@0: michael@0: uint8_t* fData; // Points to either fInternal or fExternal. michael@0: size_t fCapacity; // Number of bytes we can write to fData. michael@0: size_t fUsed; // Number of bytes written. michael@0: void* fExternal; // Unmanaged memory block. michael@0: SkAutoTMalloc fInternal; // Managed memory block. michael@0: SkAutoTUnref fSnapshot; // Holds the result of last asData. michael@0: }; michael@0: michael@0: /** michael@0: * Helper class to allocated SIZE bytes as part of the writer, and to provide michael@0: * that storage to the constructor as its initial storage buffer. michael@0: * michael@0: * This wrapper ensures proper alignment rules are met for the storage. michael@0: */ michael@0: template class SkSWriter32 : public SkWriter32 { michael@0: public: michael@0: SkSWriter32() { this->reset(); } michael@0: michael@0: void reset() {this->INHERITED::reset(fData.fStorage, SIZE); } michael@0: michael@0: private: michael@0: union { michael@0: void* fPtrAlignment; michael@0: double fDoubleAlignment; michael@0: char fStorage[SIZE]; michael@0: } fData; michael@0: michael@0: typedef SkWriter32 INHERITED; michael@0: }; michael@0: michael@0: #endif