Move SkPDFStream back to SkStream to save memory.

SkPDFStream stores data as a SkStreamRewindable to minimize
deep duplication and memory overhead.

SkStreamToStreamRewindable function to deal with fact that
SkTypeface returns a SkStream.

BUG=skia:2743
R=djsollen@google.com, mtklein@google.com, bungeman@google.com, reed@google.com

Author: halcanary@google.com

Review URL: https://codereview.chromium.org/387863005
diff --git a/src/core/SkStream.cpp b/src/core/SkStream.cpp
index 1022d18..5069bb0 100644
--- a/src/core/SkStream.cpp
+++ b/src/core/SkStream.cpp
@@ -907,3 +907,35 @@
     } while (!stream->isAtEnd());
     return tempStream.copyToData();
 }
+
+SkStreamRewindable* SkStreamRewindableFromSkStream(SkStream* stream) {
+    if (!stream) {
+        return NULL;
+    }
+    SkAutoTUnref<SkStreamRewindable> dupStream(stream->duplicate());
+    if (dupStream) {
+        return dupStream.detach();
+    }
+    stream->rewind();
+    if (stream->hasLength()) {
+        size_t length = stream->getLength();
+        if (stream->hasPosition()) {  // If stream has length, but can't rewind.
+            length -= stream->getPosition();
+        }
+        SkAutoMalloc allocMemory(length);
+        SkDEBUGCODE(size_t read =) stream->read(allocMemory.get(), length);
+        SkASSERT(length == read);
+        SkAutoTUnref<SkData> data(
+                SkData::NewFromMalloc(allocMemory.detach(), length));
+        return SkNEW_ARGS(SkMemoryStream, (data.get()));
+    }
+    SkDynamicMemoryWStream tempStream;
+    const size_t bufferSize = 4096;
+    char buffer[bufferSize];
+    do {
+        size_t bytesRead = stream->read(buffer, bufferSize);
+        tempStream.write(buffer, bytesRead);
+    } while (!stream->isAtEnd());
+    return tempStream.detachAsStream();  // returns a SkBlockMemoryStream,
+                                         // cheaper than copying to SkData
+}
diff --git a/src/core/SkStreamPriv.h b/src/core/SkStreamPriv.h
index 5b5a73a..718097d 100644
--- a/src/core/SkStreamPriv.h
+++ b/src/core/SkStreamPriv.h
@@ -10,6 +10,7 @@
 
 class SkAutoMalloc;
 class SkStream;
+class SkStreamRewindable;
 class SkData;
 
 /**
@@ -34,4 +35,12 @@
  */
 SkData *SkCopyStreamToData(SkStream* stream);
 
+/**
+ *  Attempt to convert this stream to a StreamRewindable in the
+ *  cheapest possible manner (calling duplicate() if possible, and
+ *  otherwise allocating memory for a copy).  The position of the
+ *  input stream is left in an indeterminate state.
+ */
+SkStreamRewindable* SkStreamRewindableFromSkStream(SkStream* stream);
+
 #endif  // SkStreamPriv_DEFINED
diff --git a/src/pdf/SkPDFStream.cpp b/src/pdf/SkPDFStream.cpp
index 8715d93..60fce0d 100644
--- a/src/pdf/SkPDFStream.cpp
+++ b/src/pdf/SkPDFStream.cpp
@@ -30,7 +30,7 @@
 SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream)
         : SkPDFDict(),
           fState(kUnused_State) {
-    this->setData(pdfStream.fData.get());
+    this->setData(pdfStream.fDataStream.get());
     bool removeLength = true;
     // Don't uncompress an already compressed stream, but we could.
     if (pdfStream.fState == kCompressed_State) {
@@ -57,9 +57,8 @@
 
     this->INHERITED::emitObject(stream, catalog, false);
     stream->writeText(" stream\n");
-    if (fData.get()) {
-        stream->write(fData->data(), fData->size());
-    }
+    stream->writeStream(fDataStream.get(), fDataStream->getLength());
+    SkAssertResult(fDataStream->rewind());
     stream->writeText("\nendstream");
 }
 
@@ -79,22 +78,31 @@
 SkPDFStream::SkPDFStream() : fState(kUnused_State) {}
 
 void SkPDFStream::setData(SkData* data) {
-    fData.reset(SkSafeRef(data));
+    fMemoryStream.setData(data);
+    if (&fMemoryStream != fDataStream.get()) {
+        fDataStream.reset(SkRef(&fMemoryStream));
+    }
 }
 
 void SkPDFStream::setData(SkStream* stream) {
     // Code assumes that the stream starts at the beginning and is rewindable.
+    if (&fMemoryStream == fDataStream.get()) {
+        SkASSERT(&fMemoryStream != stream);
+        fMemoryStream.setData(NULL);
+    }
+    SkASSERT(0 == fMemoryStream.getLength());
     if (stream) {
-        SkASSERT(stream->getPosition() == 0);
-        fData.reset(SkCopyStreamToData(stream));
-        SkAssertResult(stream->rewind());
+        // SkStreamRewindableFromSkStream will try stream->duplicate().
+        fDataStream.reset(SkStreamRewindableFromSkStream(stream));
+        SkASSERT(fDataStream.get());
     } else {
-        fData.reset(NULL);
+        fDataStream.reset(SkRef(&fMemoryStream));
     }
 }
 
 size_t SkPDFStream::dataSize() const {
-    return fData.get() ? fData->size() : 0;
+    SkASSERT(fDataStream->hasLength());
+    return fDataStream->getLength();
 }
 
 bool SkPDFStream::populate(SkPDFCatalog* catalog) {
@@ -102,9 +110,11 @@
         if (!skip_compression(catalog) && SkFlate::HaveFlate()) {
             SkDynamicMemoryWStream compressedData;
 
-            SkAssertResult(SkFlate::Deflate(fData.get(), &compressedData));
+            SkAssertResult(
+                    SkFlate::Deflate(fDataStream.get(), &compressedData));
+            SkAssertResult(fDataStream->rewind());
             if (compressedData.getOffset() < this->dataSize()) {
-                fData.reset(compressedData.copyToData());
+                this->setData(compressedData.detachAsStream());
                 insertName("Filter", "FlateDecode");
             }
             fState = kCompressed_State;
diff --git a/src/pdf/SkPDFStream.h b/src/pdf/SkPDFStream.h
index 3a84068..f908fbf 100644
--- a/src/pdf/SkPDFStream.h
+++ b/src/pdf/SkPDFStream.h
@@ -21,19 +21,20 @@
 
     A stream object in a PDF.  Note, all streams must be indirect objects (via
     SkObjRef).
-    TODO(vandebo): SkStream should be replaced by SkStreamRewindable when that
-    is feasible.
 */
 class SkPDFStream : public SkPDFDict {
     SK_DECLARE_INST_COUNT(SkPDFStream)
 public:
     /** Create a PDF stream. A Length entry is automatically added to the
-     *  stream dictionary. The stream may be retained (stream->ref() may be
-     *  called) so its contents must not be changed after calling this.
-     *  @param data  The data part of the stream.
+     *  stream dictionary.
+     *  @param data   The data part of the stream.  Will be ref()ed.
      */
     explicit SkPDFStream(SkData* data);
-    /** Deprecated constructor. */
+
+    /** Create a PDF stream. A Length entry is automatically added to the
+     *  stream dictionary.
+     *  @param stream The data part of the stream.  Will be duplicate()d.
+     */
     explicit SkPDFStream(SkStream* stream);
 
     virtual ~SkPDFStream();
@@ -79,8 +80,6 @@
 
     size_t dataSize() const;
 
-    SkData* getData() const { return fData.get(); }
-
     void setState(State state) {
         fState = state;
     }
@@ -93,10 +92,13 @@
     // Indicates what form (or if) the stream has been requested.
     State fState;
 
-    // Mutex guards fState, fData, and fSubstitute in public interface.
+    // Mutex guards fState, fDataStream, and fSubstitute in public interface.
     SkMutex fMutex;
 
-    SkAutoTUnref<SkData> fData;
+    SkMemoryStream fMemoryStream;  // Used by fDataStream when
+                                   // fDataStream needs to be backed
+                                   // by SkData.
+    SkAutoTUnref<SkStreamRewindable> fDataStream;
     SkAutoTUnref<SkPDFStream> fSubstitute;
 
     typedef SkPDFDict INHERITED;