static void TestObjectNumberMap(skiatest::Reporter* reporter) { SkPDFObjNumMap objNumMap; SkAutoTUnref<SkPDFArray> a1(new SkPDFArray); SkAutoTUnref<SkPDFArray> a2(new SkPDFArray); SkAutoTUnref<SkPDFArray> a3(new SkPDFArray); objNumMap.addObject(a1.get()); objNumMap.addObject(a2.get()); objNumMap.addObject(a3.get()); // The objects should be numbered in the order they are added, // starting with 1. REPORTER_ASSERT(reporter, objNumMap.getObjectNumber(a1.get()) == 1); REPORTER_ASSERT(reporter, objNumMap.getObjectNumber(a2.get()) == 2); REPORTER_ASSERT(reporter, objNumMap.getObjectNumber(a3.get()) == 3); // Assert that repeated calls to get the object number return // consistent result. REPORTER_ASSERT(reporter, objNumMap.getObjectNumber(a1.get()) == 1); }
static void TestSubstitute(skiatest::Reporter* reporter) { SkAutoTUnref<SkPDFDict> proxy(new SkPDFDict()); SkAutoTUnref<SkPDFDict> stub(new SkPDFDict()); proxy->insertInt("Value", 33); stub->insertInt("Value", 44); SkPDFSubstituteMap substituteMap; substituteMap.setSubstitute(proxy.get(), stub.get()); SkPDFObjNumMap catalog; catalog.addObject(proxy.get()); REPORTER_ASSERT(reporter, stub.get() == substituteMap.getSubstitute(proxy)); REPORTER_ASSERT(reporter, proxy.get() != substituteMap.getSubstitute(stub)); }
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; }