| Index: src/pdf/SkPDFDocument.cpp
 | 
| diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
 | 
| index 632cbcfe3ee5f3c706ce84cae5c1e90f15f20b14..c4a5d448a54cc1ca6dd873a4a7737b3095aee7ac 100644
 | 
| --- a/src/pdf/SkPDFDocument.cpp
 | 
| +++ b/src/pdf/SkPDFDocument.cpp
 | 
| @@ -82,6 +82,29 @@ SkPDFDocument::~SkPDFDocument() {
 | 
|      SkDELETE(fOtherPageResources);
 | 
|  }
 | 
|  
 | 
| +namespace {
 | 
| +class Streamer {
 | 
| +public:
 | 
| +    Streamer(SkPDFCatalog* cat, SkWStream* out)
 | 
| +        : fCat(cat), fOut(out), fBaseOffset(SkToOffT(out->bytesWritten())) {
 | 
| +    }
 | 
| +
 | 
| +    void stream(SkPDFObject* obj) {
 | 
| +        fCat->setFileOffset(obj, this->offset());
 | 
| +        obj->emit(fOut, fCat, true);
 | 
| +    }
 | 
| +
 | 
| +    off_t offset() {
 | 
| +        return SkToOffT(fOut->bytesWritten()) - fBaseOffset;
 | 
| +    }
 | 
| +
 | 
| +private:
 | 
| +    SkPDFCatalog* const fCat;
 | 
| +    SkWStream* const fOut;
 | 
| +    const off_t fBaseOffset;
 | 
| +};
 | 
| +}  // namespace
 | 
| +
 | 
|  bool SkPDFDocument::emitPDF(SkWStream* stream) {
 | 
|      if (fPages.isEmpty()) {
 | 
|          return false;
 | 
| @@ -158,46 +181,24 @@ bool SkPDFDocument::emitPDF(SkWStream* stream) {
 | 
|  
 | 
|          // Build font subsetting info before proceeding.
 | 
|          perform_font_subsetting(fCatalog.get(), fPages, &fSubstitutes);
 | 
| +    }
 | 
|  
 | 
| -        // Figure out the size of things and inform the catalog of file offsets.
 | 
| -        off_t fileOffset = SkToOffT(this->headerSize());
 | 
| -        fileOffset += SkToOffT(fCatalog->setFileOffset(fDocCatalog, fileOffset));
 | 
| -        fileOffset += SkToOffT(fCatalog->setFileOffset(fPages[0], fileOffset));
 | 
| -        fileOffset += fPages[0]->getPageSize(fCatalog.get(), fileOffset);
 | 
| -        for (int i = 0; i < fFirstPageResources->count(); i++) {
 | 
| -            fileOffset += SkToOffT(fCatalog->setFileOffset((*fFirstPageResources)[i], fileOffset));
 | 
| -        }
 | 
| -        // Add the size of resources of substitute objects used on page 1.
 | 
| -        fileOffset += fCatalog->setSubstituteResourcesOffsets(fileOffset, true);
 | 
| -        if (fPages.count() > 1) {
 | 
| -            // TODO(vandebo): For linearized format, save the start of the
 | 
| -            // first page xref table and calculate the size.
 | 
| -        }
 | 
| -
 | 
| -        for (int i = 0; i < fPageTree.count(); i++) {
 | 
| -            fileOffset += SkToOffT(fCatalog->setFileOffset(fPageTree[i], fileOffset));
 | 
| -        }
 | 
| -
 | 
| -        for (int i = 1; i < fPages.count(); i++) {
 | 
| -            fileOffset += fPages[i]->getPageSize(fCatalog.get(), fileOffset);
 | 
| -        }
 | 
| +    Streamer out(fCatalog, stream);
 | 
| +    emitHeader(stream);
 | 
|  
 | 
| -        for (int i = 0; i < fOtherPageResources->count(); i++) {
 | 
| -            fileOffset += SkToOffT(fCatalog->setFileOffset((*fOtherPageResources)[i], fileOffset));
 | 
| -        }
 | 
| +    out.stream(fDocCatalog);
 | 
| +    out.stream(fPages[0]);
 | 
| +    out.stream(fPages[0]->getContentStream());
 | 
|  
 | 
| -        fileOffset += fCatalog->setSubstituteResourcesOffsets(fileOffset, false);
 | 
| -        fXRefFileOffset = fileOffset;
 | 
| +    for (int i = 0; i < fFirstPageResources->count(); i++) {
 | 
| +        out.stream((*fFirstPageResources)[i]);
 | 
|      }
 | 
|  
 | 
| -    emitHeader(stream);
 | 
| -    fDocCatalog->emitIndirectObject(stream, fCatalog.get());
 | 
| -    fPages[0]->emitIndirectObject(stream, fCatalog.get());
 | 
| -    fPages[0]->emitPage(stream, fCatalog.get());
 | 
| -    for (int i = 0; i < fFirstPageResources->count(); i++) {
 | 
| -        (*fFirstPageResources)[i]->emit(stream, fCatalog.get(), true);
 | 
| +    SkTSet<SkPDFObject*>* firstPageSubstituteResources =
 | 
| +            fCatalog->getSubstituteList(true);
 | 
| +    for (int i = 0; i < firstPageSubstituteResources->count(); ++i) {
 | 
| +        out.stream((*firstPageSubstituteResources)[i]);
 | 
|      }
 | 
| -    fCatalog->emitSubstituteResources(stream, true);
 | 
|      // TODO(vandebo): Support linearized format
 | 
|      // if (fPages.size() > 1) {
 | 
|      //     // TODO(vandebo): Save the file offset for the first page xref table.
 | 
| @@ -205,18 +206,24 @@ bool SkPDFDocument::emitPDF(SkWStream* stream) {
 | 
|      // }
 | 
|  
 | 
|      for (int i = 0; i < fPageTree.count(); i++) {
 | 
| -        fPageTree[i]->emitIndirectObject(stream, fCatalog.get());
 | 
| +        out.stream(fPageTree[i]);
 | 
|      }
 | 
|  
 | 
|      for (int i = 1; i < fPages.count(); i++) {
 | 
| -        fPages[i]->emitPage(stream, fCatalog.get());
 | 
| +        out.stream(fPages[i]->getContentStream());
 | 
|      }
 | 
|  
 | 
|      for (int i = 0; i < fOtherPageResources->count(); i++) {
 | 
| -        (*fOtherPageResources)[i]->emit(stream, fCatalog.get(), true);
 | 
| +        out.stream((*fOtherPageResources)[i]);
 | 
| +    }
 | 
| +
 | 
| +    SkTSet<SkPDFObject*>* otherSubstituteResources =
 | 
| +            fCatalog->getSubstituteList(false);
 | 
| +    for (int i = 0; i < otherSubstituteResources->count(); ++i) {
 | 
| +        out.stream((*otherSubstituteResources)[i]);
 | 
|      }
 | 
|  
 | 
| -    fCatalog->emitSubstituteResources(stream, false);
 | 
| +    fXRefFileOffset = out.offset();
 | 
|      int64_t objCount = fCatalog->emitXrefTable(stream, fPages.count() > 1);
 | 
|      emitFooter(stream, objCount);
 | 
|      return true;
 | 
| 
 |