15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright 2010 The Android Open Source Project
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * found in the LICENSE file.
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFCatalog.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "SkPDFTypes.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkStream.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "SkTypes.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkPDFCatalog::SkPDFCatalog(SkPDFDocument::Flags flags)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : fFirstPageCount(0),
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fNextObjNum(1),
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fNextFirstPageObjNum(0),
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fDocumentFlags(flags) {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkPDFCatalog::~SkPDFCatalog() {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fSubstituteResourcesRemaining.safeUnrefAll();
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fSubstituteResourcesFirstPage.safeUnrefAll();
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkPDFObject* SkPDFCatalog::addObject(SkPDFObject* obj, bool onFirstPage) {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (findObjectIndex(obj) != -1) {  // object already added
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return obj;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkASSERT(fNextFirstPageObjNum == 0);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (onFirstPage) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fFirstPageCount++;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct Rec newEntry(obj, onFirstPage);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fCatalog.append(1, &newEntry);
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return obj;
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)size_t SkPDFCatalog::setFileOffset(SkPDFObject* obj, off_t offset) {
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int objIndex = assignObjNum(obj) - 1;
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SkASSERT(fCatalog[objIndex].fObjNumAssigned);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkASSERT(fCatalog[objIndex].fFileOffset == 0);
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fCatalog[objIndex].fFileOffset = offset;
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return getSubstituteObject(obj)->getOutputSize(this, true);
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SkPDFCatalog::emitObjectNumber(SkWStream* stream, SkPDFObject* obj) {
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    stream->writeDecAsText(assignObjNum(obj));
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    stream->writeText(" 0");  // Generation number is always 0.
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)size_t SkPDFCatalog::getObjectNumberSize(SkPDFObject* obj) {
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SkDynamicMemoryWStream buffer;
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    emitObjectNumber(&buffer, obj);
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return buffer.getOffset();
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int SkPDFCatalog::findObjectIndex(SkPDFObject* obj) const {
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (int i = 0; i < fCatalog.count(); i++) {
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (fCatalog[i].fObject == obj) {
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            return i;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If it's not in the main array, check if it's a substitute object.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < fSubstituteMap.count(); ++i) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (fSubstituteMap[i].fSubstitute == obj) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return findObjectIndex(fSubstituteMap[i].fOriginal);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SkPDFCatalog::assignObjNum(SkPDFObject* obj) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int pos = findObjectIndex(obj);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If this assert fails, it means you probably forgot to add an object
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to the resource list.
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SkASSERT(pos >= 0);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t currentIndex = pos;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (fCatalog[currentIndex].fObjNumAssigned) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return currentIndex + 1;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // First assignment.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (fNextFirstPageObjNum == 0) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fNextFirstPageObjNum = fCatalog.count() - fFirstPageCount + 1;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t objNum;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (fCatalog[currentIndex].fOnFirstPage) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        objNum = fNextFirstPageObjNum;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        fNextFirstPageObjNum++;
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        objNum = fNextObjNum;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fNextObjNum++;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When we assign an object an object number, we put it in that array
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // offset (minus 1 because object number 0 is reserved).
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SkASSERT(!fCatalog[objNum - 1].fObjNumAssigned);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (objNum - 1 != currentIndex) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkTSwap(fCatalog[objNum - 1], fCatalog[currentIndex]);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fCatalog[objNum - 1].fObjNumAssigned = true;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return objNum;
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int32_t SkPDFCatalog::emitXrefTable(SkWStream* stream, bool firstPage) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int first = -1;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int last = fCatalog.count() - 1;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(vandebo): Support linearized format.
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // int last = fCatalog.count() - fFirstPageCount - 1;
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // if (firstPage) {
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    //     first = fCatalog.count() - fFirstPageCount;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //     last = fCatalog.count() - 1;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream->writeText("xref\n");
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream->writeDecAsText(first + 1);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream->writeText(" ");
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream->writeDecAsText(last - first + 1);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream->writeText("\n");
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (first == -1) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stream->writeText("0000000000 65535 f \n");
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        first++;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = first; i <= last; i++) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // For 32 bits platforms, the maximum offset has to fit within off_t
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // which is a 32 bits signed integer on these platforms.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkDEBUGCODE(static const off_t kMaxOff = SK_MaxS32;)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkASSERT(fCatalog[i].fFileOffset > 0);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkASSERT(fCatalog[i].fFileOffset < kMaxOff);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stream->writeBigDecAsText(fCatalog[i].fFileOffset, 10);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stream->writeText(" 00000 n \n");
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return fCatalog.count() + 1;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SkPDFCatalog::setSubstitute(SkPDFObject* original,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SkPDFObject* substitute) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(SK_DEBUG)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sanity check: is the original already in substitute list?
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < fSubstituteMap.count(); ++i) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (original == fSubstituteMap[i].fSubstitute ||
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            original == fSubstituteMap[i].fOriginal) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SkASSERT(false);
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return;
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check if the original is on first page.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool onFirstPage = false;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < fCatalog.count(); ++i) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (fCatalog[i].fObject == original) {
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            onFirstPage = fCatalog[i].fOnFirstPage;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            break;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#if defined(SK_DEBUG)
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (i == fCatalog.count() - 1) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SkASSERT(false);  // original not in catalog
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SubstituteMapping newMapping(original, substitute);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fSubstituteMap.append(1, &newMapping);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add resource objects of substitute object to catalog.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkTSet<SkPDFObject*>* targetSet = getSubstituteList(onFirstPage);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkTSet<SkPDFObject*> newResourceObjects;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    newMapping.fSubstitute->getResources(*targetSet, &newResourceObjects);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < newResourceObjects.count(); ++i) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        addObject(newResourceObjects[i], onFirstPage);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // mergeInto returns the number of duplicates.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If there are duplicates, there is a bug and we mess ref counting.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkDEBUGCODE(int duplicates =) targetSet->mergeInto(newResourceObjects);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkASSERT(duplicates == 0);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkPDFObject* SkPDFCatalog::getSubstituteObject(SkPDFObject* object) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < fSubstituteMap.count(); ++i) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (object == fSubstituteMap[i].fOriginal) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return fSubstituteMap[i].fSubstitute;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return object;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)off_t SkPDFCatalog::setSubstituteResourcesOffsets(off_t fileOffset,
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                  bool firstPage) {
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SkTSet<SkPDFObject*>* targetSet = getSubstituteList(firstPage);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    off_t offsetSum = fileOffset;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < targetSet->count(); ++i) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        offsetSum += setFileOffset((*targetSet)[i], offsetSum);
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return offsetSum - fileOffset;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SkPDFCatalog::emitSubstituteResources(SkWStream *stream, bool firstPage) {
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SkTSet<SkPDFObject*>* targetSet = getSubstituteList(firstPage);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < targetSet->count(); ++i) {
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (*targetSet)[i]->emit(stream, this, true);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkTSet<SkPDFObject*>* SkPDFCatalog::getSubstituteList(bool firstPage) {
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return firstPage ? &fSubstituteResourcesFirstPage :
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       &fSubstituteResourcesRemaining;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)