aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-07-19 13:55:41 +0000
committerGravatar bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-07-19 13:55:41 +0000
commit88682b77d108a7413a166e3158e187f43211c46b (patch)
treecb94c9fd0429a6eae968bf0a8a1dc334136eb5d1
parenta79919883e275e7a5e00afc50be10cc721f6ba1d (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.cpp39
-rw-r--r--include/core/SkStream.h18
-rw-r--r--src/core/SkStream.cpp132
-rw-r--r--tests/StreamTest.cpp39
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;