bool SkPDFDocument::emitPDF(SkWStream* stream) { if (fPages.isEmpty()) { return false; } for (int i = 0; i < fPages.count(); i++) { if (fPages[i] == NULL) { return false; } } fFirstPageResources = SkNEW(SkTSet<SkPDFObject*>); fOtherPageResources = SkNEW(SkTSet<SkPDFObject*>); // We haven't emitted the document before if fPageTree is empty. if (fPageTree.isEmpty()) { SkPDFDict* pageTreeRoot; SkPDFPage::GeneratePageTree(fPages, fCatalog.get(), &fPageTree, &pageTreeRoot); fDocCatalog->insert("Pages", new SkPDFObjRef(pageTreeRoot))->unref(); /* TODO(vandebo): output intent SkAutoTUnref<SkPDFDict> outputIntent = new SkPDFDict("OutputIntent"); outputIntent->insert("S", new SkPDFName("GTS_PDFA1"))->unref(); outputIntent->insert("OutputConditionIdentifier", new SkPDFString("sRGB"))->unref(); SkAutoTUnref<SkPDFArray> intentArray = new SkPDFArray; intentArray->append(outputIntent.get()); fDocCatalog->insert("OutputIntent", intentArray.get()); */ SkAutoTUnref<SkPDFDict> dests(SkNEW(SkPDFDict)); bool firstPage = true; /* The references returned in newResources are transfered to * fFirstPageResources or fOtherPageResources depending on firstPage and * knownResources doesn't have a reference but just relies on the other * two sets to maintain a reference. */ SkTSet<SkPDFObject*> knownResources; // mergeInto returns the number of duplicates. // If there are duplicates, there is a bug and we mess ref counting. SkDEBUGCODE(int duplicates =) knownResources.mergeInto(*fFirstPageResources); SkASSERT(duplicates == 0); for (int i = 0; i < fPages.count(); i++) { if (i == 1) { firstPage = false; SkDEBUGCODE(duplicates =) knownResources.mergeInto(*fOtherPageResources); } SkTSet<SkPDFObject*> newResources; fPages[i]->finalizePage( fCatalog.get(), firstPage, knownResources, &newResources); addResourcesToCatalog(firstPage, &newResources, fCatalog.get()); if (firstPage) { SkDEBUGCODE(duplicates =) fFirstPageResources->mergeInto(newResources); } else {
bool SkPDFDocument::emitPDF(SkWStream* stream) { if (fPages.isEmpty()) { return false; } for (int i = 0; i < fPages.count(); i++) { if (fPages[i] == NULL) { return false; } } // We haven't emitted the document before if fPageTree is empty. if (fPageTree.isEmpty()) { SkPDFDict* pageTreeRoot; SkPDFPage::GeneratePageTree(fPages, fCatalog.get(), &fPageTree, &pageTreeRoot); fDocCatalog->insert("Pages", new SkPDFObjRef(pageTreeRoot))->unref(); /* TODO(vandebo): output intent SkRefPtr<SkPDFDict> outputIntent = new SkPDFDict("OutputIntent"); outputIntent->unref(); // SkRefPtr and new both took a reference. outputIntent->insert("S", new SkPDFName("GTS_PDFA1"))->unref(); outputIntent->insert("OutputConditionIdentifier", new SkPDFString("sRGB"))->unref(); SkRefPtr<SkPDFArray> intentArray = new SkPDFArray; intentArray->unref(); // SkRefPtr and new both took a reference. intentArray->append(outputIntent.get()); fDocCatalog->insert("OutputIntent", intentArray.get()); */ bool firstPage = true; for (int i = 0; i < fPages.count(); i++) { int resourceCount = fPageResources.count(); fPages[i]->finalizePage(fCatalog.get(), firstPage, &fPageResources); addResourcesToCatalog(resourceCount, firstPage, &fPageResources, fCatalog.get()); if (i == 0) { firstPage = false; fSecondPageFirstResourceIndex = fPageResources.count(); } } // 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 = headerSize(); fileOffset += fCatalog->setFileOffset(fDocCatalog.get(), (size_t) fileOffset); fileOffset += fCatalog->setFileOffset(fPages[0], (size_t) fileOffset); fileOffset += fPages[0]->getPageSize(fCatalog.get(), (size_t) fileOffset); for (int i = 0; i < fSecondPageFirstResourceIndex; i++) { fileOffset += fCatalog->setFileOffset(fPageResources[i], (size_t) 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 += fCatalog->setFileOffset(fPageTree[i], (size_t) fileOffset); } for (int i = 1; i < fPages.count(); i++) { fileOffset += fPages[i]->getPageSize(fCatalog.get(), (size_t) fileOffset); } for (int i = fSecondPageFirstResourceIndex; i < fPageResources.count(); i++) { fileOffset += fCatalog->setFileOffset(fPageResources[i], (size_t) fileOffset); } fileOffset += fCatalog->setSubstituteResourcesOffsets(fileOffset, false); fXRefFileOffset = fileOffset; } emitHeader(stream); fDocCatalog->emitObject(stream, fCatalog.get(), true); fPages[0]->emitObject(stream, fCatalog.get(), true); fPages[0]->emitPage(stream, fCatalog.get()); for (int i = 0; i < fSecondPageFirstResourceIndex; i++) { fPageResources[i]->emit(stream, fCatalog.get(), true); } 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. // fCatalog->emitXrefTable(stream, true); // } for (int i = 0; i < fPageTree.count(); i++) { fPageTree[i]->emitObject(stream, fCatalog.get(), true); } for (int i = 1; i < fPages.count(); i++) { fPages[i]->emitPage(stream, fCatalog.get()); } for (int i = fSecondPageFirstResourceIndex; i < fPageResources.count(); i++) { fPageResources[i]->emit(stream, fCatalog.get(), true); } fCatalog->emitSubstituteResources(stream, false); int64_t objCount = fCatalog->emitXrefTable(stream, fPages.count() > 1); emitFooter(stream, objCount); return true; }