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 {
// // Client::Write // void Client::Write() { // Get the message text const char *message = stream.str(); // Get the filename const char *fileName = Utils::Strrchr(file, '\\') + 1; // Get the time U32 time = Clock::Time::Ms() - startTime; /* // Is this an warning or error ? if (level == WARN || level == ERR) { // Compose buffer into exception information U32 arguments[4]; arguments[0] = (U32) message; arguments[1] = (U32) file; arguments[2] = (U32) line; arguments[3] = level == WARN ? 1 : 0; RaiseException(1, level == ERR ? EXCEPTION_NONCONTINUABLE_EXCEPTION : 0, 4, arguments); } else */ { // Write to the destinations NList<Destination>::Iterator dests(&destinations); for (!dests; dests.IsValid(); ++dests) { (*dests)->Write(level, name, fileName, line, time, message); } } stream.freeze(0); stream.seekp(0); }
static bool emit_pdf_document(const SkTDArray<const SkPDFDevice*>& pageDevices, SkWStream* stream) { if (pageDevices.isEmpty()) { return false; } SkTDArray<SkPDFDict*> pages; SkAutoTUnref<SkPDFDict> dests(SkNEW(SkPDFDict)); for (int i = 0; i < pageDevices.count(); i++) { SkASSERT(pageDevices[i]); SkASSERT(i == 0 || pageDevices[i - 1]->getCanon() == pageDevices[i]->getCanon()); SkAutoTUnref<SkPDFDict> page(create_pdf_page(pageDevices[i])); pageDevices[i]->appendDestinations(dests, page.get()); pages.push(page.detach()); } SkTDArray<SkPDFDict*> pageTree; SkAutoTUnref<SkPDFDict> docCatalog(SkNEW_ARGS(SkPDFDict, ("Catalog"))); SkPDFDict* pageTreeRoot; generate_page_tree(pages, &pageTree, &pageTreeRoot); docCatalog->insertObjRef("Pages", SkRef(pageTreeRoot)); if (dests->size() > 0) { docCatalog->insertObjRef("Dests", dests.detach()); } /* TODO(vandebo): output intent SkAutoTUnref<SkPDFDict> outputIntent = new SkPDFDict("OutputIntent"); outputIntent->insertName("S", "GTS_PDFA1"); outputIntent->insertString("OutputConditionIdentifier", "sRGB"); SkAutoTUnref<SkPDFArray> intentArray(new SkPDFArray); intentArray->appendObject(SkRef(outputIntent.get())); docCatalog->insertObject("OutputIntent", intentArray.detach()); */ // Build font subsetting info before proceeding. SkPDFSubstituteMap substitutes; perform_font_subsetting(pageDevices, &substitutes); SkPDFObjNumMap objNumMap; if (objNumMap.addObject(docCatalog.get())) { docCatalog->addResources(&objNumMap, substitutes); } size_t baseOffset = stream->bytesWritten(); emit_pdf_header(stream); SkTDArray<int32_t> offsets; for (int i = 0; i < objNumMap.objects().count(); ++i) { SkPDFObject* object = objNumMap.objects()[i]; size_t offset = stream->bytesWritten(); // This assert checks that size(pdf_header) > 0 and that // the output stream correctly reports bytesWritten(). SkASSERT(offset > baseOffset); offsets.push(SkToS32(offset - baseOffset)); SkASSERT(object == substitutes.getSubstitute(object)); SkASSERT(objNumMap.getObjectNumber(object) == i + 1); stream->writeDecAsText(i + 1); stream->writeText(" 0 obj\n"); // Generation number is always 0. object->emitObject(stream, objNumMap, substitutes); stream->writeText("\nendobj\n"); } int32_t xRefFileOffset = SkToS32(stream->bytesWritten() - baseOffset); // Include the zeroth object in the count. int32_t objCount = SkToS32(offsets.count() + 1); stream->writeText("xref\n0 "); stream->writeDecAsText(objCount); stream->writeText("\n0000000000 65535 f \n"); for (int i = 0; i < offsets.count(); i++) { SkASSERT(offsets[i] > 0); stream->writeBigDecAsText(offsets[i], 10); stream->writeText(" 00000 n \n"); } emit_pdf_footer(stream, objNumMap, substitutes, docCatalog.get(), objCount, xRefFileOffset); // The page tree has both child and parent pointers, so it creates a // reference cycle. We must clear that cycle to properly reclaim memory. for (int i = 0; i < pageTree.count(); i++) { pageTree[i]->clear(); } pageTree.safeUnrefAll(); pages.unrefAll(); return true; }