diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:09:42 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:09:42 +0000 |
commit | ae2c20f398933a9e86c387dcc465ec0f71065ffc (patch) | |
tree | de668b1411e2ee0b4e49b6d8f8b68183134ac990 /skia/images/SkStream.cpp | |
parent | 09911bf300f1a419907a9412154760efd0b7abc3 (diff) | |
download | chromium_src-ae2c20f398933a9e86c387dcc465ec0f71065ffc.zip chromium_src-ae2c20f398933a9e86c387dcc465ec0f71065ffc.tar.gz chromium_src-ae2c20f398933a9e86c387dcc465ec0f71065ffc.tar.bz2 |
Add skia to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia/images/SkStream.cpp')
-rw-r--r-- | skia/images/SkStream.cpp | 792 |
1 files changed, 792 insertions, 0 deletions
diff --git a/skia/images/SkStream.cpp b/skia/images/SkStream.cpp new file mode 100644 index 0000000..5c1eebe --- /dev/null +++ b/skia/images/SkStream.cpp @@ -0,0 +1,792 @@ +/* libs/graphics/images/SkStream.cpp +** +** Copyright 2006, Google Inc. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include "SkStream.h" +#include "SkFixed.h" +#include "SkString.h" +#include "SkOSFile.h" + +SkStream::~SkStream() {} + +const char* SkStream::getFileName() +{ + // override in subclass if you represent a file + return NULL; +} + +const void* SkStream::getMemoryBase() +{ + // override in subclass if you represent a memory block + return NULL; +} + +size_t SkStream::skip(size_t size) +{ + /* Check for size == 0, and just return 0. If we passed that + to read(), it would interpret it as a request for the entire + size of the stream. + */ + return size ? this->read(NULL, size) : 0; +} + +int8_t SkStream::readS8() { + int8_t value; + size_t len = this->read(&value, 1); + SkASSERT(1 == len); + return value; +} + +int16_t SkStream::readS16() { + int16_t value; + size_t len = this->read(&value, 2); + SkASSERT(2 == len); + return value; +} + +int32_t SkStream::readS32() { + int32_t value; + size_t len = this->read(&value, 4); + SkASSERT(4 == len); + return value; +} + +SkScalar SkStream::readScalar() { + SkScalar value; + size_t len = this->read(&value, sizeof(SkScalar)); + SkASSERT(sizeof(SkScalar) == len); + return value; +} + +size_t SkStream::readPackedUInt() { + uint8_t byte; + if (!this->read(&byte, 1)) { + return 0; + } + if (byte != 0xFF) { + return byte; + } + + uint16_t word; + if (!this->read(&word, 2)) { + return 0; + } + if (word != 0xFFFF) { + return word; + } + + uint32_t quad; + if (!this->read(&quad, 4)) { + return 0; + } + return quad; +} + +////////////////////////////////////////////////////////////////////////////////////// + +SkWStream::~SkWStream() +{ +} + +void SkWStream::newline() +{ + this->write("\n", 1); +} + +void SkWStream::flush() +{ +} + +bool SkWStream::writeText(const char text[]) +{ + SkASSERT(text); + return this->write(text, strlen(text)); +} + +bool SkWStream::writeDecAsText(int32_t dec) +{ + SkString tmp; + tmp.appendS32(dec); + return this->write(tmp.c_str(), tmp.size()); +} + +bool SkWStream::writeHexAsText(uint32_t hex, int digits) +{ + SkString tmp; + tmp.appendHex(hex, digits); + return this->write(tmp.c_str(), tmp.size()); +} + +bool SkWStream::writeScalarAsText(SkScalar value) +{ + SkString tmp; + tmp.appendScalar(value); + return this->write(tmp.c_str(), tmp.size()); +} + +bool SkWStream::write8(U8CPU value) { + uint8_t v = SkToU8(value); + return this->write(&v, 1); +} + +bool SkWStream::write16(U16CPU value) { + uint16_t v = SkToU16(value); + return this->write(&v, 2); +} + +bool SkWStream::write32(uint32_t value) { + return this->write(&value, 4); +} + +bool SkWStream::writeScalar(SkScalar value) { + return this->write(&value, sizeof(value)); +} + +bool SkWStream::writePackedUInt(size_t value) { + if (value < 0xFF) { + return this->write8(value); + } else if (value < 0xFFFF) { + return this->write8(0xFF) && this->write16(value); + } else { + return this->write16(0xFFFF) && this->write32(value); + } +} + +bool SkWStream::writeStream(SkStream* stream, size_t length) { + char scratch[1024]; + const size_t MAX = sizeof(scratch); + + while (length != 0) { + size_t n = length; + if (n > MAX) { + n = MAX; + } + stream->read(scratch, n); + if (!this->write(scratch, n)) { + return false; + } + length -= n; + } + return true; +} + +//////////////////////////////////////////////////////////////////////////// + +SkFILEStream::SkFILEStream(const char file[]) : fName(file) +{ +#ifdef SK_BUILD_FOR_BREW + if (SkStrEndsWith(fName.c_str(), ".xml")) + fName.writable_str()[fName.size()-3] = 'b'; +#endif + + fFILE = file ? sk_fopen(fName.c_str(), kRead_SkFILE_Flag) : NULL; +} + +SkFILEStream::~SkFILEStream() +{ + if (fFILE) + sk_fclose(fFILE); +} + +void SkFILEStream::setPath(const char path[]) +{ + fName.set(path); +#ifdef SK_BUILD_FOR_BREW + if (SkStrEndsWith(fName.c_str(), ".xml")) + fName.writable_str()[fName.size()-3] = 'b'; +#endif + + if (fFILE) + { + sk_fclose(fFILE); + fFILE = NULL; + } + if (path) + fFILE = sk_fopen(fName.c_str(), kRead_SkFILE_Flag); +} + +const char* SkFILEStream::getFileName() +{ + return fName.c_str(); +} + +bool SkFILEStream::rewind() +{ + if (fFILE) + { + if (sk_frewind(fFILE)) + return true; + // we hit an error + sk_fclose(fFILE); + fFILE = NULL; + } + return false; +} + +size_t SkFILEStream::read(void* buffer, size_t size) +{ + if (fFILE) + { + if (buffer == NULL && size == 0) // special signature, they want the total size + return sk_fgetsize(fFILE); + else + return sk_fread(buffer, size, fFILE); + } + return 0; +} + +//////////////////////////////////////////////////////////////////////// + +SkMemoryStream::SkMemoryStream() +{ + fWeOwnTheData = false; + this->setMemory(NULL, 0); +} + +SkMemoryStream::SkMemoryStream(size_t size) { + fWeOwnTheData = true; + fOffset = 0; + fSize = size; + fSrc = sk_malloc_throw(size); +} + +SkMemoryStream::SkMemoryStream(const void* src, size_t size, bool copyData) +{ + fWeOwnTheData = false; + this->setMemory(src, size, copyData); +} + +SkMemoryStream::~SkMemoryStream() +{ + if (fWeOwnTheData) + sk_free((void*)fSrc); +} + +void SkMemoryStream::setMemory(const void* src, size_t size, bool copyData) +{ + if (fWeOwnTheData) + sk_free((void*)fSrc); + + fSize = size; + fOffset = 0; + fWeOwnTheData = copyData; + + if (copyData) + { + void* copy = sk_malloc_throw(size); + memcpy(copy, src, size); + src = copy; + } + fSrc = src; +} + +void SkMemoryStream::skipToAlign4() +{ + // cast to remove unary-minus warning + fOffset += -(int)fOffset & 0x03; +} + +bool SkMemoryStream::rewind() +{ + fOffset = 0; + return true; +} + +size_t SkMemoryStream::read(void* buffer, size_t size) +{ + if (buffer == NULL && size == 0) // special signature, they want the total size + return fSize; + + // if buffer is NULL, seek ahead by size + + if (size == 0) + return 0; + if (size > fSize - fOffset) + size = fSize - fOffset; + if (buffer) { + memcpy(buffer, (const char*)fSrc + fOffset, size); + } + fOffset += size; + return size; +} + +const void* SkMemoryStream::getMemoryBase() +{ + return fSrc; +} + +const void* SkMemoryStream::getAtPos() +{ + return (const char*)fSrc + fOffset; +} + +size_t SkMemoryStream::seek(size_t offset) +{ + if (offset > fSize) + offset = fSize; + fOffset = offset; + return offset; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +SkBufferStream::SkBufferStream(SkStream& proxy, size_t bufferSize) + : fProxy(proxy) +{ + SkASSERT(&proxy != NULL); + this->init(NULL, bufferSize); +} + +SkBufferStream::SkBufferStream(SkStream& proxy, void* buffer, size_t bufferSize) + : fProxy(proxy) +{ + SkASSERT(&proxy != NULL); + SkASSERT(buffer == NULL || bufferSize != 0); // init(addr, 0) makes no sense, we must know how big their buffer is + + this->init(buffer, bufferSize); +} + +void SkBufferStream::init(void* buffer, size_t bufferSize) +{ + if (bufferSize == 0) + bufferSize = kDefaultBufferSize; + + fOrigBufferSize = bufferSize; + fBufferSize = bufferSize; + fBufferOffset = bufferSize; // to trigger a reload on the first read() + + if (buffer == NULL) + { + fBuffer = (char*)sk_malloc_throw(fBufferSize); + fWeOwnTheBuffer = true; + } + else + { + fBuffer = (char*)buffer; + fWeOwnTheBuffer = false; + } +} + +SkBufferStream::~SkBufferStream() +{ + if (fWeOwnTheBuffer) + sk_free(fBuffer); +} + +bool SkBufferStream::rewind() +{ + fBufferOffset = fBufferSize = fOrigBufferSize; + return fProxy.rewind(); +} + +const char* SkBufferStream::getFileName() +{ + return fProxy.getFileName(); +} + +#ifdef SK_DEBUG +// #define SK_TRACE_BUFFERSTREAM +#endif + +size_t SkBufferStream::read(void* buffer, size_t size) +{ +#ifdef SK_TRACE_BUFFERSTREAM + SkDebugf("Request %d", size); +#endif + + if (buffer == NULL && size == 0) + return fProxy.read(buffer, size); // requesting total size + + if (buffer == NULL || size == 0) + { + fBufferOffset += size; + return fProxy.read(buffer, size); + } + + size_t s = size; + size_t actuallyRead = 0; + + // flush what we can from our fBuffer + if (fBufferOffset < fBufferSize) + { + if (s > fBufferSize - fBufferOffset) + s = fBufferSize - fBufferOffset; + memcpy(buffer, fBuffer + fBufferOffset, s); +#ifdef SK_TRACE_BUFFERSTREAM + SkDebugf(" flush %d", s); +#endif + size -= s; + fBufferOffset += s; + buffer = (char*)buffer + s; + actuallyRead = s; + } + + // check if there is more to read + if (size) + { + SkASSERT(fBufferOffset >= fBufferSize); // need to refill our fBuffer + + if (size < fBufferSize) // lets try to read more than the request + { + s = fProxy.read(fBuffer, fBufferSize); +#ifdef SK_TRACE_BUFFERSTREAM + SkDebugf(" read %d into fBuffer", s); +#endif + if (size > s) // they asked for too much + size = s; + if (size) + { + memcpy(buffer, fBuffer, size); + actuallyRead += size; +#ifdef SK_TRACE_BUFFERSTREAM + SkDebugf(" memcpy %d into dst", size); +#endif + } + + fBufferOffset = size; + fBufferSize = s; // record the (possibly smaller) size for the buffer + } + else // just do a direct read + { + actuallyRead += fProxy.read(buffer, size); +#ifdef SK_TRACE_BUFFERSTREAM + SkDebugf(" direct read %d", size); +#endif + } + } +#ifdef SK_TRACE_BUFFERSTREAM + SkDebugf("\n"); +#endif + return actuallyRead; +} + +const void* SkBufferStream::getMemoryBase() +{ + return fProxy.getMemoryBase(); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +SkFILEWStream::SkFILEWStream(const char path[]) +{ + fFILE = sk_fopen(path, kWrite_SkFILE_Flag); +} + +SkFILEWStream::~SkFILEWStream() +{ + if (fFILE) + sk_fclose(fFILE); +} + +bool SkFILEWStream::write(const void* buffer, size_t size) +{ + if (fFILE == NULL) + return false; + + if (sk_fwrite(buffer, size, fFILE) != size) + { + SkDEBUGCODE(SkDebugf("SkFILEWStream failed writing %d bytes\n", size);) + sk_fclose(fFILE); + fFILE = NULL; + return false; + } + return true; +} + +void SkFILEWStream::flush() +{ + if (fFILE) + sk_fflush(fFILE); +} + +//////////////////////////////////////////////////////////////////////// + +SkMemoryWStream::SkMemoryWStream(void* buffer, size_t size) + : fBuffer((char*)buffer), fMaxLength(size), fBytesWritten(0) +{ +} + +bool SkMemoryWStream::write(const void* buffer, size_t size) +{ + size = SkMin32(size, fMaxLength - fBytesWritten); + if (size > 0) + { + memcpy(fBuffer + fBytesWritten, buffer, size); + fBytesWritten += size; + return true; + } + return false; +} + +//////////////////////////////////////////////////////////////////////// + +#define SkDynamicMemoryWStream_MinBlockSize 256 + +struct SkDynamicMemoryWStream::Block { + Block* fNext; + char* fCurr; + char* fStop; + + const char* start() const { return (const char*)(this + 1); } + char* start() { return (char*)(this + 1); } + size_t avail() const { return fStop - fCurr; } + size_t written() const { return fCurr - this->start(); } + + void init(size_t size) + { + fNext = NULL; + fCurr = this->start(); + fStop = this->start() + size; + } + + const void* append(const void* data, size_t size) + { + SkASSERT((size_t)(fStop - fCurr) >= size); + memcpy(fCurr, data, size); + fCurr += size; + return (const void*)((const char*)data + size); + } +}; + +SkDynamicMemoryWStream::SkDynamicMemoryWStream() : fHead(NULL), fTail(NULL), fBytesWritten(0), fCopyToCache(NULL) +{ +} + +SkDynamicMemoryWStream::~SkDynamicMemoryWStream() +{ + reset(); +} + +const char* SkDynamicMemoryWStream::detach() +{ + const char* result = getStream(); + fCopyToCache = NULL; + return result; +} + +void SkDynamicMemoryWStream::reset() +{ + sk_free(fCopyToCache); + Block* block = fHead; + + while (block != NULL) { + Block* next = block->fNext; + sk_free(block); + block = next; + } + fHead = fTail = NULL; + fBytesWritten = 0; + fCopyToCache = NULL; +} + +bool SkDynamicMemoryWStream::write(const void* buffer, size_t count) +{ + if (count > 0) { + + if (fCopyToCache) { + sk_free(fCopyToCache); + fCopyToCache = NULL; + } + fBytesWritten += count; + + size_t size; + + if (fTail != NULL && fTail->avail() > 0) { + size = SkMin32(fTail->avail(), count); + buffer = fTail->append(buffer, size); + SkASSERT(count >= size); + count -= size; + if (count == 0) + return true; + } + + size = SkMax32(count, SkDynamicMemoryWStream_MinBlockSize); + Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size); + block->init(size); + block->append(buffer, count); + + if (fTail != NULL) + fTail->fNext = block; + else + fHead = fTail = block; + fTail = block; + } + return true; +} + +bool SkDynamicMemoryWStream::write(const void* buffer, size_t offset, size_t count) +{ + if (offset + count > fBytesWritten) + return false; // test does not partially modify + Block* block = fHead; + while (block != NULL) { + size_t size = block->written(); + if (offset < size) { + size_t part = offset + count > size ? size - offset : count; + memcpy(block->start() + offset, buffer, part); + if (count <= part) + return true; + count -= part; + buffer = (const void*) ((char* ) buffer + part); + } + offset = offset > size ? offset - size : 0; + block = block->fNext; + } + return false; +} + +bool SkDynamicMemoryWStream::read(void* buffer, size_t offset, size_t count) +{ + if (offset + count > fBytesWritten) + return false; // test does not partially modify + Block* block = fHead; + while (block != NULL) { + size_t size = block->written(); + if (offset < size) { + size_t part = offset + count > size ? size - offset : count; + memcpy(buffer, block->start() + offset, part); + if (count <= part) + return true; + count -= part; + buffer = (void*) ((char* ) buffer + part); + } + offset = offset > size ? offset - size : 0; + block = block->fNext; + } + return false; +} + +void SkDynamicMemoryWStream::copyTo(void* dst) const +{ + Block* block = fHead; + + while (block != NULL) { + size_t size = block->written(); + memcpy(dst, block->start(), size); + dst = (void*)((char*)dst + size); + block = block->fNext; + } +} + +const char* SkDynamicMemoryWStream::getStream() const +{ + if (fCopyToCache == NULL) { + fCopyToCache = (char*)sk_malloc_throw(fBytesWritten); + this->copyTo(fCopyToCache); + } + return fCopyToCache; +} + +void SkDynamicMemoryWStream::padToAlign4() +{ + // cast to remove unary-minus warning + int padBytes = -(int)fBytesWritten & 0x03; + if (padBytes == 0) + return; + int zero = 0; + write(&zero, padBytes); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +void SkDebugWStream::newline() +{ +#ifdef SK_DEBUG + SkDebugf("\n"); +#endif +} + +bool SkDebugWStream::write(const void* buffer, size_t size) +{ +#ifdef SK_DEBUG + char* s = new char[size+1]; + memcpy(s, buffer, size); + s[size] = 0; + SkDebugf("%s", s); + delete[] s; +#endif + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef SK_DEBUG + +#include "SkRandom.h" + +void SkWStream::UnitTest() +{ +#ifdef SK_SUPPORT_UNITTEST + { + static const char s[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + char copy[sizeof(s)]; + SkRandom rand; + + for (int i = 0; i < 65; i++) + { + char* copyPtr = copy; + SkMemoryStream mem(s, sizeof(s)); + SkBufferStream buff(mem, i); + + do { + copyPtr += buff.read(copyPtr, rand.nextU() & 15); + } while (copyPtr < copy + sizeof(s)); + SkASSERT(copyPtr == copy + sizeof(s)); + SkASSERT(memcmp(s, copy, sizeof(s)) == 0); + } + } + { + SkDebugWStream s; + + s.writeText("testing wstream helpers\n"); + s.writeText("compare: 0 "); s.writeDecAsText(0); s.newline(); + s.writeText("compare: 591 "); s.writeDecAsText(591); s.newline(); + s.writeText("compare: -9125 "); s.writeDecAsText(-9125); s.newline(); + s.writeText("compare: 0 "); s.writeHexAsText(0, 0); s.newline(); + s.writeText("compare: 03FA "); s.writeHexAsText(0x3FA, 4); s.newline(); + s.writeText("compare: DEADBEEF "); s.writeHexAsText(0xDEADBEEF, 4); s.newline(); + s.writeText("compare: 0 "); s.writeScalarAsText(SkIntToScalar(0)); s.newline(); + s.writeText("compare: 27 "); s.writeScalarAsText(SkIntToScalar(27)); s.newline(); + s.writeText("compare: -119 "); s.writeScalarAsText(SkIntToScalar(-119)); s.newline(); + s.writeText("compare: 851.3333 "); s.writeScalarAsText(SkIntToScalar(851) + SK_Scalar1/3); s.newline(); + s.writeText("compare: -0.08 "); s.writeScalarAsText(-SK_Scalar1*8/100); s.newline(); + } + + { + SkDynamicMemoryWStream ds; + const char s[] = "abcdefghijklmnopqrstuvwxyz"; + int i; + for (i = 0; i < 100; i++) { + bool result = ds.write(s, 26); + SkASSERT(result); + } + SkASSERT(ds.getOffset() == 100 * 26); + char* dst = new char[100 * 26 + 1]; + dst[100*26] = '*'; + ds.copyTo(dst); + SkASSERT(dst[100*26] == '*'); + // char* p = dst; + for (i = 0; i < 100; i++) + SkASSERT(memcmp(&dst[i * 26], s, 26) == 0); + SkASSERT(memcmp(dst, ds.getStream(), 100*26) == 0); + delete[] dst; + } +#endif +} + +#endif |