diff options
author | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-07-19 13:55:41 +0000 |
---|---|---|
committer | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-07-19 13:55:41 +0000 |
commit | 88682b77d108a7413a166e3158e187f43211c46b (patch) | |
tree | cb94c9fd0429a6eae968bf0a8a1dc334136eb5d1 | |
parent | a79919883e275e7a5e00afc50be10cc721f6ba1d (diff) |
Add a detachAsStream to SkDynamicMemoryWStream.
R=reed@google.com
Committed: https://code.google.com/p/skia/source/detail?r=10171
Review URL: https://codereview.chromium.org/19677002
git-svn-id: http://skia.googlecode.com/svn/trunk@10178 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | gm/gmmain.cpp | 39 | ||||
-rw-r--r-- | include/core/SkStream.h | 18 | ||||
-rw-r--r-- | src/core/SkStream.cpp | 132 | ||||
-rw-r--r-- | tests/StreamTest.cpp | 39 |
4 files changed, 194 insertions, 34 deletions
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp index 98525a5394..3c01156653 100644 --- a/gm/gmmain.cpp +++ b/gm/gmmain.cpp @@ -410,11 +410,9 @@ public: gm_fprintf(stdout, "(results marked with [*] will cause nonzero return value)\n"); } - static bool write_document(const SkString& path, - const SkDynamicMemoryWStream& document) { + static bool write_document(const SkString& path, SkStreamAsset* asset) { SkFILEWStream stream(path.c_str()); - SkAutoDataUnref data(document.copyToData()); - return stream.write(data->data(), data->size()); + return stream.writeStream(asset, asset->getLength()); } /** @@ -665,7 +663,7 @@ public: const char renderModeDescriptor [], const char *shortName, const BitmapAndDigest* bitmapAndDigest, - SkDynamicMemoryWStream* document) { + SkStreamAsset* document) { SkString path; bool success = false; if (gRec.fBackend == kRaster_Backend || @@ -679,12 +677,12 @@ public: if (kPDF_Backend == gRec.fBackend) { path = make_filename(writePath, shortName, gRec.fName, renderModeDescriptor, "pdf"); - success = write_document(path, *document); + success = write_document(path, document); } if (kXPS_Backend == gRec.fBackend) { path = make_filename(writePath, shortName, gRec.fName, renderModeDescriptor, "xps"); - success = write_document(path, *document); + success = write_document(path, document); } if (success) { return kEmpty_ErrorCombination; @@ -911,7 +909,7 @@ public: */ ErrorCombination compare_test_results_to_stored_expectations( GM* gm, const ConfigData& gRec, const char writePath[], - const BitmapAndDigest* actualBitmapAndDigest, SkDynamicMemoryWStream* document) { + const BitmapAndDigest* actualBitmapAndDigest, SkStreamAsset* document) { SkString shortNamePlusConfig = make_shortname_plus_config(gm->shortName(), gRec.fName); SkString nameWithExtension(shortNamePlusConfig); @@ -1025,24 +1023,10 @@ public: } static SkPicture* stream_to_new_picture(const SkPicture& src) { - - // To do in-memory commiunications with a stream, we need to: - // * create a dynamic memory stream - // * copy it into a buffer - // * create a read stream from it - // ?!?! - SkDynamicMemoryWStream storage; src.serialize(&storage); - - size_t streamSize = storage.getOffset(); - SkAutoMalloc dstStorage(streamSize); - void* dst = dstStorage.get(); - //char* dst = new char [streamSize]; - //@todo thudson 22 April 2011 when can we safely delete [] dst? - storage.copyTo(dst); - SkMemoryStream pictReadback(dst, streamSize); - SkPicture* retval = SkPicture::CreateFromStream(&pictReadback); + SkAutoTUnref<SkStreamAsset> pictReadback(storage.detatchAsStream()); + SkPicture* retval = SkPicture::CreateFromStream(pictReadback); return retval; } @@ -1079,13 +1063,14 @@ public: bitmap = NULL; // we don't generate a bitmap rendering of the XPS file } + SkAutoTUnref<SkStreamAsset> documentStream(document.detatchAsStream()); if (NULL == bitmap) { return compare_test_results_to_stored_expectations( - gm, gRec, writePath, NULL, &document); + gm, gRec, writePath, NULL, documentStream); } else { BitmapAndDigest bitmapAndDigest(*bitmap); return compare_test_results_to_stored_expectations( - gm, gRec, writePath, &bitmapAndDigest, &document); + gm, gRec, writePath, &bitmapAndDigest, documentStream); } } @@ -1093,8 +1078,6 @@ public: const ConfigData& gRec, const SkBitmap& referenceBitmap, GrSurface* gpuTarget) { - SkDynamicMemoryWStream document; - if (gRec.fBackend == kRaster_Backend || gRec.fBackend == kGPU_Backend) { const char renderModeDescriptor[] = "-deferred"; diff --git a/include/core/SkStream.h b/include/core/SkStream.h index 31ed7bc6d4..8180a0a819 100644 --- a/include/core/SkStream.h +++ b/include/core/SkStream.h @@ -52,7 +52,7 @@ public: * If buffer != NULL, copy size bytes into buffer, return how many were copied. * @param buffer when NULL skip size bytes, otherwise copy size bytes into buffer * @param size the number of bytes to skip or copy - * @return bytes read on success + * @return the number of bytes actually read. */ virtual size_t read(void* buffer, size_t size) = 0; @@ -65,7 +65,10 @@ public: return 0 == size ? 0 : this->read(NULL, size); } - /** Returns true if there are no more bytes to be read. + /** Returns true when all the bytes in the stream have been read. + * This may return true early (when there are no more bytes to be read) + * or late (after the first unsuccessful read). + * * In Progress: do not use until all implementations are updated. * TODO: after this is implemented everywhere, make pure virtual. */ @@ -280,7 +283,7 @@ public: virtual size_t getLength() const SK_OVERRIDE; - const void* getMemoryBase() SK_OVERRIDE; + virtual const void* getMemoryBase() SK_OVERRIDE; private: SkFILE* fFILE; @@ -423,7 +426,10 @@ public: */ SkData* copyToData() const; - // reset the stream to its original state + /** Reset, returning a reader stream with the current content. */ + SkStreamAsset* detatchAsStream(); + + /** Reset the stream to its original, empty, state. */ void reset(); void padToAlign4(); private: @@ -435,6 +441,10 @@ private: void invalidateCopy(); + // For access to the Block type. + friend class SkBlockMemoryStream; + friend class SkBlockMemoryRefCnt; + typedef SkWStream INHERITED; }; diff --git a/src/core/SkStream.cpp b/src/core/SkStream.cpp index 91de88adac..b251905633 100644 --- a/src/core/SkStream.cpp +++ b/src/core/SkStream.cpp @@ -661,6 +661,138 @@ void SkDynamicMemoryWStream::invalidateCopy() { } } +class SkBlockMemoryRefCnt : public SkRefCnt { +public: + explicit SkBlockMemoryRefCnt(SkDynamicMemoryWStream::Block* head) : fHead(head) { } + + virtual ~SkBlockMemoryRefCnt() { + SkDynamicMemoryWStream::Block* block = fHead; + while (block != NULL) { + SkDynamicMemoryWStream::Block* next = block->fNext; + sk_free(block); + block = next; + } + } + + SkDynamicMemoryWStream::Block* const fHead; +}; + +class SkBlockMemoryStream : public SkStreamAsset { +public: + SkBlockMemoryStream(SkDynamicMemoryWStream::Block* head, size_t size) + : fBlockMemory(SkNEW_ARGS(SkBlockMemoryRefCnt, (head))), fCurrent(head) + , fSize(size) , fOffset(0), fCurrentOffset(0) { } + + SkBlockMemoryStream(SkBlockMemoryRefCnt* headRef, size_t size) + : fBlockMemory(SkRef(headRef)), fCurrent(fBlockMemory->fHead) + , fSize(size) , fOffset(0), fCurrentOffset(0) { } + + virtual size_t read(void* buffer, size_t rawCount) SK_OVERRIDE { + size_t count = rawCount; + if (fOffset + count > fSize) { + count = fSize - fOffset; + } + size_t bytesLeftToRead = count; + while (fCurrent != NULL) { + size_t bytesLeftInCurrent = fCurrent->written() - fCurrentOffset; + size_t bytesFromCurrent = bytesLeftToRead <= bytesLeftInCurrent + ? bytesLeftToRead : bytesLeftInCurrent; + if (buffer) { + memcpy(buffer, fCurrent->start() + fCurrentOffset, bytesFromCurrent); + } + if (bytesLeftToRead <= bytesFromCurrent) { + fCurrentOffset += bytesFromCurrent; + fOffset += count; + return count; + } + bytesLeftToRead -= bytesFromCurrent; + buffer = SkTAddOffset<void>(buffer, bytesFromCurrent); + fCurrent = fCurrent->fNext; + fCurrentOffset = 0; + } + SkASSERT(false); + return 0; + } + + virtual bool isAtEnd() const SK_OVERRIDE { + return fOffset == fSize; + } + + virtual bool rewind() SK_OVERRIDE { + fCurrent = fBlockMemory->fHead; + fOffset = 0; + fCurrentOffset = 0; + return true; + } + + virtual SkBlockMemoryStream* duplicate() const SK_OVERRIDE { + return SkNEW_ARGS(SkBlockMemoryStream, (fBlockMemory.get(), fSize)); + } + + virtual size_t getPosition() const SK_OVERRIDE { + return fOffset; + } + + virtual bool seek(size_t position) SK_OVERRIDE { + // If possible, skip forward. + if (position >= fOffset) { + size_t skipAmount = position - fOffset; + return this->skip(skipAmount) == skipAmount; + } + // If possible, move backward within the current block. + size_t moveBackAmount = fOffset - position; + if (moveBackAmount <= fCurrentOffset) { + fCurrentOffset -= moveBackAmount; + fOffset -= moveBackAmount; + return true; + } + // Otherwise rewind and move forward. + return this->rewind() && this->skip(position) == position; + } + + virtual bool move(long offset) SK_OVERRIDE { + return seek(fOffset + offset); + } + + virtual SkBlockMemoryStream* fork() const SK_OVERRIDE { + SkAutoTUnref<SkBlockMemoryStream> that(this->duplicate()); + that->fCurrent = this->fCurrent; + that->fOffset = this->fOffset; + that->fCurrentOffset = this->fCurrentOffset; + return that.detach(); + } + + virtual size_t getLength() const SK_OVERRIDE { + return fSize; + } + + virtual const void* getMemoryBase() SK_OVERRIDE { + if (NULL == fBlockMemory->fHead->fNext) { + return fBlockMemory->fHead->start(); + } + return NULL; + } + +private: + SkAutoTUnref<SkBlockMemoryRefCnt> const fBlockMemory; + SkDynamicMemoryWStream::Block const * fCurrent; + size_t const fSize; + size_t fOffset; + size_t fCurrentOffset; +}; + +SkStreamAsset* SkDynamicMemoryWStream::detatchAsStream() { + if (fCopy) { + SkMemoryStream* stream = SkNEW_ARGS(SkMemoryStream, (fCopy)); + this->reset(); + return stream; + } + SkBlockMemoryStream* stream = SkNEW_ARGS(SkBlockMemoryStream, (fHead, fBytesWritten)); + fHead = 0; + this->reset(); + return stream; +} + /////////////////////////////////////////////////////////////////////////////// void SkDebugWStream::newline() diff --git a/tests/StreamTest.cpp b/tests/StreamTest.cpp index cf828430a9..1eb1282ba7 100644 --- a/tests/StreamTest.cpp +++ b/tests/StreamTest.cpp @@ -32,6 +32,8 @@ static void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream, // expect EOF size_t bytes = stream->read(tmp, 1); REPORTER_ASSERT(reporter, 0 == bytes); + // isAtEnd might not return true until after the first failing read. + REPORTER_ASSERT(reporter, stream->isAtEnd()); } static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) { @@ -81,6 +83,7 @@ static void TestWStream(skiatest::Reporter* reporter) { REPORTER_ASSERT(reporter, ds.write(s, 26)); } REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26); + char* dst = new char[100 * 26 + 1]; dst[100*26] = '*'; ds.copyTo(dst); @@ -90,10 +93,42 @@ static void TestWStream(skiatest::Reporter* reporter) { } { - SkData* data = ds.copyToData(); + SkAutoTUnref<SkStreamAsset> stream(ds.detatchAsStream()); + REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength()); + REPORTER_ASSERT(reporter, ds.getOffset() == 0); + test_loop_stream(reporter, stream.get(), s, 26, 100); + + SkAutoTUnref<SkStreamAsset> stream2(stream->duplicate()); + test_loop_stream(reporter, stream2.get(), s, 26, 100); + + SkAutoTUnref<SkStreamAsset> stream3(stream->fork()); + REPORTER_ASSERT(reporter, stream3->isAtEnd()); + char tmp; + size_t bytes = stream->read(&tmp, 1); + REPORTER_ASSERT(reporter, 0 == bytes); + stream3->rewind(); + test_loop_stream(reporter, stream3.get(), s, 26, 100); + } + + for (i = 0; i < 100; i++) { + REPORTER_ASSERT(reporter, ds.write(s, 26)); + } + REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26); + + { + SkAutoTUnref<SkData> data(ds.copyToData()); REPORTER_ASSERT(reporter, 100 * 26 == data->size()); REPORTER_ASSERT(reporter, memcmp(dst, data->data(), data->size()) == 0); - data->unref(); + } + + { + // Test that this works after a copyToData. + SkAutoTUnref<SkStreamAsset> stream(ds.detatchAsStream()); + REPORTER_ASSERT(reporter, ds.getOffset() == 0); + test_loop_stream(reporter, stream.get(), s, 26, 100); + + SkAutoTUnref<SkStreamAsset> stream2(stream->duplicate()); + test_loop_stream(reporter, stream2.get(), s, 26, 100); } delete[] dst; |