SkStream: DynamicMemoryWStream gets writeToAndReset
This is similar to copyToAndReset().
Also use this in SkPDF, for minor memory savings:
Single-threaded DM's peak RSS drops from 239MB
to 228MB.
Change-Id: I352a980e6dd54eb05d74cd057bd50e02312753b0
Reviewed-on: https://skia-review.googlesource.com/17714
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Hal Canary <halcanary@google.com>
diff --git a/include/core/SkStream.h b/include/core/SkStream.h
index b4875ad..01fd82a 100644
--- a/include/core/SkStream.h
+++ b/include/core/SkStream.h
@@ -384,11 +384,14 @@
/** More efficient version of read(dst, 0, bytesWritten()). */
void copyTo(void* dst) const;
- void writeToStream(SkWStream* dst) const;
+ bool writeToStream(SkWStream* dst) const;
/** Equivalent to copyTo() followed by reset(), but may save memory use. */
void copyToAndReset(void* dst);
+ /** Equivalent to writeToStream() followed by reset(), but may save memory use. */
+ bool writeToAndReset(SkWStream* dst);
+
/** Return the contents as SkData, and then reset the stream. */
sk_sp<SkData> detachAsData();
diff --git a/src/core/SkStream.cpp b/src/core/SkStream.cpp
index ef86bc9..7bb2079 100644
--- a/src/core/SkStream.cpp
+++ b/src/core/SkStream.cpp
@@ -545,10 +545,13 @@
}
}
-void SkDynamicMemoryWStream::writeToStream(SkWStream* dst) const {
+bool SkDynamicMemoryWStream::writeToStream(SkWStream* dst) const {
for (Block* block = fHead; block != nullptr; block = block->fNext) {
- dst->write(block->start(), block->written());
+ if (!dst->write(block->start(), block->written())) {
+ return false;
+ }
}
+ return true;
}
void SkDynamicMemoryWStream::padToAlign4() {
@@ -584,6 +587,23 @@
fBytesWrittenBeforeTail = 0;
}
+bool SkDynamicMemoryWStream::writeToAndReset(SkWStream* dst) {
+ // By looping through the source and freeing as we copy, we
+ // can reduce real memory use with large streams.
+ bool dstStreamGood = true;
+ for (Block* block = fHead; block != nullptr; ) {
+ if (dstStreamGood && !dst->write(block->start(), block->written())) {
+ dstStreamGood = false;
+ }
+ Block* next = block->fNext;
+ sk_free(block);
+ block = next;
+ }
+ fHead = fTail = nullptr;
+ fBytesWrittenBeforeTail = 0;
+ return dstStreamGood;
+}
+
sk_sp<SkData> SkDynamicMemoryWStream::detachAsData() {
const size_t size = this->bytesWritten();
if (0 == size) {
diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp
index b58aaf4..d5eb19e 100644
--- a/src/pdf/SkPDFBitmap.cpp
+++ b/src/pdf/SkPDFBitmap.cpp
@@ -356,8 +356,7 @@
} else {
bitmap_to_pdf_pixels(bitmap, &deflateWStream);
}
- deflateWStream.finalize(); // call before detachAsStream().
- std::unique_ptr<SkStreamAsset> asset(buffer.detachAsStream());
+ deflateWStream.finalize(); // call before buffer.bytesWritten().
SkPDFDict pdfDict("XObject");
pdfDict.insertName("Subtype", "Image");
@@ -380,11 +379,11 @@
}
pdfDict.insertInt("BitsPerComponent", 8);
pdfDict.insertName("Filter", "FlateDecode");
- pdfDict.insertInt("Length", asset->getLength());
+ pdfDict.insertInt("Length", buffer.bytesWritten());
pdfDict.emitObject(stream, objNumMap);
pdf_stream_begin(stream);
- stream->writeStream(asset.get(), asset->getLength());
+ buffer.writeToAndReset(stream);
pdf_stream_end(stream);
}
diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp
index c66c80a..2559f93 100644
--- a/src/pdf/SkPDFTypes.cpp
+++ b/src/pdf/SkPDFTypes.cpp
@@ -489,7 +489,7 @@
SkPDFUnion::Name("FlateDecode").emitObject(stream, objNumMap);
stream->writeText(">>");
stream->writeText(" stream\n");
- buffer.writeToStream(stream);
+ buffer.writeToAndReset(stream);
stream->writeText("\nendstream");
}
#endif