1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
28459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2010 The Android Open Source Project
48459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
78459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org */
88459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
108459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org#include "SkPDFCatalog.h"
118459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org#include "SkPDFTypes.h"
128459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org#include "SkStream.h"
13d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org#include "SkTypes.h"
148459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
15421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFCatalog::SkPDFCatalog(SkPDFDocument::Flags flags)
16d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    : fFirstPageCount(0),
17d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org      fNextObjNum(1),
18421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org      fNextFirstPageObjNum(0),
19421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org      fDocumentFlags(flags) {
20f66025d59ab4c8c4439fabf6ad89ddf35a19d1fdvandebo@chromium.org}
21f66025d59ab4c8c4439fabf6ad89ddf35a19d1fdvandebo@chromium.org
222ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.orgSkPDFCatalog::~SkPDFCatalog() {
232ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    fSubstituteResourcesRemaining.safeUnrefAll();
242ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    fSubstituteResourcesFirstPage.safeUnrefAll();
252ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org}
26f66025d59ab4c8c4439fabf6ad89ddf35a19d1fdvandebo@chromium.org
27f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.orgSkPDFObject* SkPDFCatalog::addObject(SkPDFObject* obj, bool onFirstPage) {
282ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    if (findObjectIndex(obj) != -1) {  // object already added
292ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org        return obj;
302ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    }
31d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    SkASSERT(fNextFirstPageObjNum == 0);
32769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    if (onFirstPage) {
33d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org        fFirstPageCount++;
34769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    }
358459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
368459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    struct Rec newEntry(obj, onFirstPage);
378459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    fCatalog.append(1, &newEntry);
38f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.org    return obj;
398459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org}
408459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
4130580f69493fd8aa86c223736b4f7564ce458760vandebo@chromium.orgsize_t SkPDFCatalog::setFileOffset(SkPDFObject* obj, off_t offset) {
42d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    int objIndex = assignObjNum(obj) - 1;
43d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    SkASSERT(fCatalog[objIndex].fObjNumAssigned);
44d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    SkASSERT(fCatalog[objIndex].fFileOffset == 0);
45d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    fCatalog[objIndex].fFileOffset = offset;
46d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
47d3a094ca346bee7631eb522a2bf46b72f755ef40vandebo@chromium.org    return getSubstituteObject(obj)->getOutputSize(this, true);
48d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org}
49d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
508459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.orgvoid SkPDFCatalog::emitObjectNumber(SkWStream* stream, SkPDFObject* obj) {
518459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    stream->writeDecAsText(assignObjNum(obj));
528459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    stream->writeText(" 0");  // Generation number is always 0.
538459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org}
548459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
558459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.orgsize_t SkPDFCatalog::getObjectNumberSize(SkPDFObject* obj) {
568459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    SkDynamicMemoryWStream buffer;
578459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    emitObjectNumber(&buffer, obj);
588459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    return buffer.getOffset();
598459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org}
608459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
618459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.orgint SkPDFCatalog::findObjectIndex(SkPDFObject* obj) const {
628459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    for (int i = 0; i < fCatalog.count(); i++) {
63769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org        if (fCatalog[i].fObject == obj) {
648459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org            return i;
65769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org        }
668459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    }
672ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    // If it's not in the main array, check if it's a substitute object.
682ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    for (int i = 0; i < fSubstituteMap.count(); ++i) {
692ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org        if (fSubstituteMap[i].fSubstitute == obj) {
702ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org            return findObjectIndex(fSubstituteMap[i].fOriginal);
712ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org        }
722ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    }
738459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    return -1;
748459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org}
758459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
768459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.orgint SkPDFCatalog::assignObjNum(SkPDFObject* obj) {
778459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    int pos = findObjectIndex(obj);
78da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org    // If this assert fails, it means you probably forgot to add an object
79da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org    // to the resource list.
808459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    SkASSERT(pos >= 0);
818459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    uint32_t currentIndex = pos;
82769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    if (fCatalog[currentIndex].fObjNumAssigned) {
838459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org        return currentIndex + 1;
84769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    }
858459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
86d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    // First assignment.
87769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    if (fNextFirstPageObjNum == 0) {
88d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org        fNextFirstPageObjNum = fCatalog.count() - fFirstPageCount + 1;
89769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    }
90d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
91d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    uint32_t objNum;
928459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    if (fCatalog[currentIndex].fOnFirstPage) {
93d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org        objNum = fNextFirstPageObjNum;
94d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org        fNextFirstPageObjNum++;
958459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    } else {
96d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org        objNum = fNextObjNum;
97d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org        fNextObjNum++;
988459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    }
998459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
1008459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    // When we assign an object an object number, we put it in that array
1018459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    // offset (minus 1 because object number 0 is reserved).
102d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    SkASSERT(!fCatalog[objNum - 1].fObjNumAssigned);
103769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    if (objNum - 1 != currentIndex) {
104d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org        SkTSwap(fCatalog[objNum - 1], fCatalog[currentIndex]);
105769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    }
106d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    fCatalog[objNum - 1].fObjNumAssigned = true;
107d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    return objNum;
108d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org}
109d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
110d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.orgint32_t SkPDFCatalog::emitXrefTable(SkWStream* stream, bool firstPage) {
111d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    int first = -1;
112d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    int last = fCatalog.count() - 1;
113769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    // TODO(vandebo): Support linearized format.
114a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org    // int last = fCatalog.count() - fFirstPageCount - 1;
115a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org    // if (firstPage) {
116a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org    //     first = fCatalog.count() - fFirstPageCount;
117a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org    //     last = fCatalog.count() - 1;
118a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org    // }
119d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
120d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    stream->writeText("xref\n");
121d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    stream->writeDecAsText(first + 1);
122d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    stream->writeText(" ");
123d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    stream->writeDecAsText(last - first + 1);
124d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    stream->writeText("\n");
125d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
126d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    if (first == -1) {
127d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org        stream->writeText("0000000000 65535 f \n");
128d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org        first++;
1298459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    }
130d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    for (int i = first; i <= last; i++) {
13146ee9c6a92716e73c078dac63e4bf7f10205ea4creed@google.com        // For 32 bits platforms, the maximum offset has to fit within off_t
13246ee9c6a92716e73c078dac63e4bf7f10205ea4creed@google.com        // which is a 32 bits signed integer on these platforms.
13346ee9c6a92716e73c078dac63e4bf7f10205ea4creed@google.com        SkDEBUGCODE(static const off_t kMaxOff = SK_MaxS32;)
134d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org        SkASSERT(fCatalog[i].fFileOffset > 0);
135dfc867bab24e184f5093d4eabbac7d9c58cc6320sugoi@google.com        SkASSERT(fCatalog[i].fFileOffset < kMaxOff);
136d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org        stream->writeBigDecAsText(fCatalog[i].fFileOffset, 10);
137d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org        stream->writeText(" 00000 n \n");
138d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    }
139d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
140d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org    return fCatalog.count() + 1;
1418459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org}
1422ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org
1432ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.orgvoid SkPDFCatalog::setSubstitute(SkPDFObject* original,
1442ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org                                 SkPDFObject* substitute) {
1452ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org#if defined(SK_DEBUG)
1462ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    // Sanity check: is the original already in substitute list?
1472ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    for (int i = 0; i < fSubstituteMap.count(); ++i) {
1482ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org        if (original == fSubstituteMap[i].fSubstitute ||
1492ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org            original == fSubstituteMap[i].fOriginal) {
1502ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org            SkASSERT(false);
1512ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org            return;
1522ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org        }
1532ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    }
1542ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org#endif
1552ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    // Check if the original is on first page.
1562ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    bool onFirstPage = false;
1572ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    for (int i = 0; i < fCatalog.count(); ++i) {
1582ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org        if (fCatalog[i].fObject == original) {
1592ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org            onFirstPage = fCatalog[i].fOnFirstPage;
1602ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org            break;
1612ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org        }
1622ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org#if defined(SK_DEBUG)
1632ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org        if (i == fCatalog.count() - 1) {
1642ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org            SkASSERT(false);  // original not in catalog
1652ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org            return;
1662ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org        }
1672ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org#endif
1682ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    }
1692ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org
1702ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    SubstituteMapping newMapping(original, substitute);
1712ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    fSubstituteMap.append(1, &newMapping);
1722ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org
1732ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    // Add resource objects of substitute object to catalog.
1746addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    SkTSet<SkPDFObject*>* targetSet = getSubstituteList(onFirstPage);
1756addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    SkTSet<SkPDFObject*> newResourceObjects;
1766addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    newMapping.fSubstitute->getResources(*targetSet, &newResourceObjects);
1776addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    for (int i = 0; i < newResourceObjects.count(); ++i) {
1786addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com        addObject(newResourceObjects[i], onFirstPage);
1796addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    }
1806addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    // mergeInto returns the number of duplicates.
1816addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    // If there are duplicates, there is a bug and we mess ref counting.
1826addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    SkDEBUGCODE(int duplicates =) targetSet->mergeInto(newResourceObjects);
1836addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    SkASSERT(duplicates == 0);
1842ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org}
1852ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org
1862ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.orgSkPDFObject* SkPDFCatalog::getSubstituteObject(SkPDFObject* object) {
1872ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    for (int i = 0; i < fSubstituteMap.count(); ++i) {
1882ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org        if (object == fSubstituteMap[i].fOriginal) {
1892ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org            return fSubstituteMap[i].fSubstitute;
1902ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org        }
1912ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    }
1922ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    return object;
1932ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org}
1942ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org
1952ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.orgoff_t SkPDFCatalog::setSubstituteResourcesOffsets(off_t fileOffset,
1962ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org                                                  bool firstPage) {
1976addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    SkTSet<SkPDFObject*>* targetSet = getSubstituteList(firstPage);
1982ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    off_t offsetSum = fileOffset;
1996addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    for (int i = 0; i < targetSet->count(); ++i) {
2006addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com        offsetSum += setFileOffset((*targetSet)[i], offsetSum);
2012ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    }
202f5181a496d79b0dbe4d96195157b25308437cf93vandebo@chromium.org    return offsetSum - fileOffset;
2032ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org}
2042ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org
2052ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.orgvoid SkPDFCatalog::emitSubstituteResources(SkWStream *stream, bool firstPage) {
2066addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    SkTSet<SkPDFObject*>* targetSet = getSubstituteList(firstPage);
2076addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    for (int i = 0; i < targetSet->count(); ++i) {
2086addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com        (*targetSet)[i]->emit(stream, this, true);
2092ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    }
2102ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org}
2112ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org
2126addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.comSkTSet<SkPDFObject*>* SkPDFCatalog::getSubstituteList(bool firstPage) {
2132ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org    return firstPage ? &fSubstituteResourcesFirstPage :
2142ef12d4bb54312091d644f0ada3639c51c9f6e5avandebo@chromium.org                       &fSubstituteResourcesRemaining;
215f5181a496d79b0dbe4d96195157b25308437cf93vandebo@chromium.org}
216