Simplify reference management in SkPDF
Prior to this change, SkPDFObject subclasses were required to track their resources separately from the document structure. (An object has a resource if it depends, via an indirect reference, on another object). This led to a lot of extra code to duplicate effort. I replace the getResources() function with the much simpler addResources() function. I only define a non-trivial addResources() method on arrays, dictionaries, and indirect object references. All other specialized classes simply rely on their parent class's implementation. SkPDFObject::addResources() works by recursively walking the directed graph of object (direct and indirect) references and adding resources to a set. It doesn't matter that there are closed loops in the graph, since we check the set before walking down a branch. - Add SkPDFObject::addResources() virtual function, with four implementations - Remove SkPDFObject::getResources() virtual function and all implementations. - Remove SkPDFObject::GetResourcesHelper() - Remove SkPDFObject::AddResourceHelper() - In SkPDFCatalog::findObjectIndex(), add an object to the catalog if it doesn't exist yet. - SkPDFCatalog::setSubstitute() no longer sets up resources - SkPDFDocument.cpp no longer needs the Streamer object - SkPDFDocument.cpp calls fDocCatalog->addResources to build the resource list. - SkPDFFont::addResource() removed - All SkPDF-::fResource sets removed (they are redundant). - removed SkPDFImage::addSMask() function - SkPDFResourceDict::getReferencedResources() removed. Motivation: this removes quite a bit of code and makes the objects slightly slimmer in memory. Most importantly, this will lead the way towards removing SkPDFObject's inheritance from SkRefCnt, which will greatly simplify everything. Testing: I usually test changes to the PDF backend by comparing checksums of PDF files rendered from GMs and SKPs before and after the change. This change both re-orders and re-numbers the indirect PDF objects. I used the qpdf program to normalize the PDFs and then compared the normalized outputs from before and after the change; they matched. Review URL: https://codereview.chromium.org/870333002
This commit is contained in:
parent
c8262ccbf9
commit
bf799cd228
@ -33,7 +33,7 @@ SkPDFObject* SkPDFCatalog::addObject(SkPDFObject* obj, bool onFirstPage) {
|
||||
fFirstPageCount++;
|
||||
}
|
||||
|
||||
struct Rec newEntry(obj, onFirstPage);
|
||||
Rec newEntry(obj, onFirstPage);
|
||||
fCatalog.append(1, &newEntry);
|
||||
return obj;
|
||||
}
|
||||
@ -45,18 +45,11 @@ void SkPDFCatalog::setFileOffset(SkPDFObject* obj, off_t offset) {
|
||||
fCatalog[objIndex].fFileOffset = offset;
|
||||
}
|
||||
|
||||
void SkPDFCatalog::emitObjectNumber(SkWStream* stream, SkPDFObject* obj) {
|
||||
stream->writeDecAsText(assignObjNum(obj));
|
||||
stream->writeText(" 0"); // Generation number is always 0.
|
||||
int32_t SkPDFCatalog::getObjectNumber(SkPDFObject* obj) {
|
||||
return (int32_t)assignObjNum(obj);
|
||||
}
|
||||
|
||||
size_t SkPDFCatalog::getObjectNumberSize(SkPDFObject* obj) {
|
||||
SkDynamicMemoryWStream buffer;
|
||||
emitObjectNumber(&buffer, obj);
|
||||
return buffer.getOffset();
|
||||
}
|
||||
|
||||
int SkPDFCatalog::findObjectIndex(SkPDFObject* obj) const {
|
||||
int SkPDFCatalog::findObjectIndex(SkPDFObject* obj) {
|
||||
for (int i = 0; i < fCatalog.count(); i++) {
|
||||
if (fCatalog[i].fObject == obj) {
|
||||
return i;
|
||||
@ -68,7 +61,9 @@ int SkPDFCatalog::findObjectIndex(SkPDFObject* obj) const {
|
||||
return findObjectIndex(fSubstituteMap[i].fOriginal);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
Rec newEntry(obj, false);
|
||||
fCatalog.append(1, &newEntry);
|
||||
return fCatalog.count() - 1;
|
||||
}
|
||||
|
||||
int SkPDFCatalog::assignObjNum(SkPDFObject* obj) {
|
||||
@ -150,35 +145,8 @@ void SkPDFCatalog::setSubstitute(SkPDFObject* original,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Check if the original is on first page.
|
||||
bool onFirstPage = false;
|
||||
for (int i = 0; i < fCatalog.count(); ++i) {
|
||||
if (fCatalog[i].fObject == original) {
|
||||
onFirstPage = fCatalog[i].fOnFirstPage;
|
||||
break;
|
||||
}
|
||||
#if defined(SK_DEBUG)
|
||||
if (i == fCatalog.count() - 1) {
|
||||
SkASSERT(false); // original not in catalog
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SubstituteMapping newMapping(original, substitute);
|
||||
fSubstituteMap.append(1, &newMapping);
|
||||
|
||||
// Add resource objects of substitute object to catalog.
|
||||
SkTSet<SkPDFObject*>* targetSet = getSubstituteList(onFirstPage);
|
||||
SkTSet<SkPDFObject*> newResourceObjects;
|
||||
newMapping.fSubstitute->getResources(*targetSet, &newResourceObjects);
|
||||
for (int i = 0; i < newResourceObjects.count(); ++i) {
|
||||
addObject(newResourceObjects[i], onFirstPage);
|
||||
}
|
||||
// mergeInto returns the number of duplicates.
|
||||
// If there are duplicates, there is a bug and we mess ref counting.
|
||||
SkDEBUGCODE(int duplicates =) targetSet->mergeInto(newResourceObjects);
|
||||
SkASSERT(duplicates == 0);
|
||||
}
|
||||
|
||||
SkPDFObject* SkPDFCatalog::getSubstituteObject(SkPDFObject* object) {
|
||||
@ -190,7 +158,3 @@ SkPDFObject* SkPDFCatalog::getSubstituteObject(SkPDFObject* object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
SkTSet<SkPDFObject*>* SkPDFCatalog::getSubstituteList(bool firstPage) {
|
||||
return firstPage ? &fSubstituteResourcesFirstPage :
|
||||
&fSubstituteResourcesRemaining;
|
||||
}
|
||||
|
@ -43,17 +43,10 @@ public:
|
||||
*/
|
||||
void setFileOffset(SkPDFObject* obj, off_t offset);
|
||||
|
||||
/** Output the object number for the passed object.
|
||||
/** Get the object number for the passed object.
|
||||
* @param obj The object of interest.
|
||||
* @param stream The writable output stream to send the output to.
|
||||
*/
|
||||
void emitObjectNumber(SkWStream* stream, SkPDFObject* obj);
|
||||
|
||||
/** Return the number of bytes that would be emitted for the passed
|
||||
* object's object number.
|
||||
* @param obj The object of interest
|
||||
*/
|
||||
size_t getObjectNumberSize(SkPDFObject* obj);
|
||||
int32_t getObjectNumber(SkPDFObject* obj);
|
||||
|
||||
/** Return the document flags in effect for this catalog/document.
|
||||
*/
|
||||
@ -76,10 +69,6 @@ public:
|
||||
*/
|
||||
SkPDFObject* getSubstituteObject(SkPDFObject* object);
|
||||
|
||||
/** get the resources of substitute objects.
|
||||
*/
|
||||
SkTSet<SkPDFObject*>* getSubstituteList(bool firstPage);
|
||||
|
||||
private:
|
||||
struct Rec {
|
||||
Rec(SkPDFObject* object, bool onFirstPage)
|
||||
@ -103,7 +92,7 @@ private:
|
||||
};
|
||||
|
||||
// TODO(vandebo): Make this a hash if it's a performance problem.
|
||||
SkTDArray<struct Rec> fCatalog;
|
||||
SkTDArray<Rec> fCatalog;
|
||||
|
||||
// TODO(arthurhsu): Make this a hash if it's a performance problem.
|
||||
SkTDArray<SubstituteMapping> fSubstituteMap;
|
||||
@ -119,7 +108,7 @@ private:
|
||||
|
||||
SkPDFDocument::Flags fDocumentFlags;
|
||||
|
||||
int findObjectIndex(SkPDFObject* obj) const;
|
||||
int findObjectIndex(SkPDFObject* obj);
|
||||
|
||||
int assignObjNum(SkPDFObject* obj);
|
||||
};
|
||||
|
@ -82,33 +82,6 @@ SkPDFDocument::~SkPDFDocument() {
|
||||
SkDELETE(fOtherPageResources);
|
||||
}
|
||||
|
||||
namespace {
|
||||
class Streamer {
|
||||
public:
|
||||
Streamer(SkPDFCatalog* cat, SkWStream* out)
|
||||
: fCat(cat), fOut(out), fBaseOffset(SkToOffT(out->bytesWritten())) {
|
||||
}
|
||||
|
||||
void stream(SkPDFObject* object) {
|
||||
fCat->setFileOffset(object, this->offset());
|
||||
SkPDFObject* realObject = fCat->getSubstituteObject(object);
|
||||
fCat->emitObjectNumber(fOut, realObject);
|
||||
fOut->writeText(" obj\n");
|
||||
realObject->emitObject(fOut, fCat);
|
||||
fOut->writeText("\nendobj\n");
|
||||
}
|
||||
|
||||
off_t offset() {
|
||||
return SkToOffT(fOut->bytesWritten()) - fBaseOffset;
|
||||
}
|
||||
|
||||
private:
|
||||
SkPDFCatalog* const fCat;
|
||||
SkWStream* const fOut;
|
||||
const off_t fBaseOffset;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
bool SkPDFDocument::emitPDF(SkWStream* stream) {
|
||||
if (fPages.isEmpty()) {
|
||||
return false;
|
||||
@ -187,52 +160,29 @@ bool SkPDFDocument::emitPDF(SkWStream* stream) {
|
||||
perform_font_subsetting(fCatalog.get(), fPages, &fSubstitutes);
|
||||
}
|
||||
|
||||
Streamer out(fCatalog, stream);
|
||||
SkTSet<SkPDFObject*> resourceSet;
|
||||
if (resourceSet.add(fDocCatalog)) {
|
||||
fDocCatalog->addResources(&resourceSet, fCatalog);
|
||||
}
|
||||
off_t baseOffset = SkToOffT(stream->bytesWritten());
|
||||
emitHeader(stream);
|
||||
|
||||
out.stream(fDocCatalog);
|
||||
out.stream(fPages[0]);
|
||||
out.stream(fPages[0]->getContentStream());
|
||||
|
||||
for (int i = 0; i < fFirstPageResources->count(); i++) {
|
||||
out.stream((*fFirstPageResources)[i]);
|
||||
for (int i = 0; i < resourceSet.count(); ++i) {
|
||||
SkPDFObject* object = resourceSet[i];
|
||||
fCatalog->setFileOffset(object,
|
||||
SkToOffT(stream->bytesWritten()) - baseOffset);
|
||||
SkASSERT(object == fCatalog->getSubstituteObject(object));
|
||||
stream->writeDecAsText(fCatalog->getObjectNumber(object));
|
||||
stream->writeText(" 0 obj\n"); // Generation number is always 0.
|
||||
object->emitObject(stream, fCatalog);
|
||||
stream->writeText("\nendobj\n");
|
||||
}
|
||||
|
||||
SkTSet<SkPDFObject*>* firstPageSubstituteResources =
|
||||
fCatalog->getSubstituteList(true);
|
||||
for (int i = 0; i < firstPageSubstituteResources->count(); ++i) {
|
||||
out.stream((*firstPageSubstituteResources)[i]);
|
||||
}
|
||||
// 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++) {
|
||||
out.stream(fPageTree[i]);
|
||||
}
|
||||
|
||||
for (int i = 1; i < fPages.count(); i++) {
|
||||
out.stream(fPages[i]->getContentStream());
|
||||
}
|
||||
|
||||
for (int i = 0; i < fOtherPageResources->count(); i++) {
|
||||
out.stream((*fOtherPageResources)[i]);
|
||||
}
|
||||
|
||||
SkTSet<SkPDFObject*>* otherSubstituteResources =
|
||||
fCatalog->getSubstituteList(false);
|
||||
for (int i = 0; i < otherSubstituteResources->count(); ++i) {
|
||||
out.stream((*otherSubstituteResources)[i]);
|
||||
}
|
||||
|
||||
fXRefFileOffset = out.offset();
|
||||
fXRefFileOffset = SkToOffT(stream->bytesWritten()) - baseOffset;
|
||||
int64_t objCount = fCatalog->emitXrefTable(stream, fPages.count() > 1);
|
||||
emitFooter(stream, objCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(halcanary): remove this method, since it is unused.
|
||||
bool SkPDFDocument::setPage(int pageNumber, SkPDFDevice* pdfDevice) {
|
||||
if (!fPageTree.isEmpty()) {
|
||||
return false;
|
||||
@ -266,6 +216,7 @@ bool SkPDFDocument::appendPage(SkPDFDevice* pdfDevice) {
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
// TODO(halcanary): remove
|
||||
void SkPDFDocument::getCountOfFontTypes(
|
||||
int counts[SkAdvancedTypefaceMetrics::kOther_Font + 2]) const {
|
||||
sk_bzero(counts, sizeof(int) *
|
||||
@ -290,6 +241,7 @@ void SkPDFDocument::getCountOfFontTypes(
|
||||
counts[SkAdvancedTypefaceMetrics::kOther_Font + 1] = notEmbeddable;
|
||||
}
|
||||
|
||||
// TODO(halcanary): expose notEmbeddableCount in SkDocument
|
||||
void SkPDFDocument::getCountOfFontTypes(
|
||||
int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1],
|
||||
int* notSubsettableCount,
|
||||
@ -334,6 +286,7 @@ void SkPDFDocument::emitHeader(SkWStream* stream) {
|
||||
stream->writeText("\n");
|
||||
}
|
||||
|
||||
//TODO(halcanary): remove this function
|
||||
size_t SkPDFDocument::headerSize() {
|
||||
SkDynamicMemoryWStream buffer;
|
||||
emitHeader(&buffer);
|
||||
|
@ -746,12 +746,6 @@ SkPDFFont::~SkPDFFont() {
|
||||
SkAutoMutexAcquire lock(SkPDFCanon::GetFontMutex());
|
||||
SkPDFCanon::GetCanon().removeFont(this);
|
||||
}
|
||||
fResources.unrefAll();
|
||||
}
|
||||
|
||||
void SkPDFFont::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects) {
|
||||
GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects);
|
||||
}
|
||||
|
||||
SkTypeface* SkPDFFont::typeface() {
|
||||
@ -940,12 +934,6 @@ void SkPDFFont::setLastGlyphID(uint16_t glyphID) {
|
||||
fLastGlyphID = glyphID;
|
||||
}
|
||||
|
||||
void SkPDFFont::addResource(SkPDFObject* object) {
|
||||
SkASSERT(object != NULL);
|
||||
fResources.push(object);
|
||||
object->ref();
|
||||
}
|
||||
|
||||
SkPDFDict* SkPDFFont::getFontDescriptor() {
|
||||
return fDescriptor.get();
|
||||
}
|
||||
@ -1000,7 +988,6 @@ void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) {
|
||||
generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset,
|
||||
multiByteGlyphs(), firstGlyphID(),
|
||||
lastGlyphID()));
|
||||
addResource(pdfCmap.get());
|
||||
insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref();
|
||||
}
|
||||
|
||||
@ -1042,7 +1029,6 @@ bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) {
|
||||
|
||||
SkAutoTUnref<SkPDFCIDFont> newCIDFont(
|
||||
new SkPDFCIDFont(fontInfo(), typeface(), subset));
|
||||
addResource(newCIDFont.get());
|
||||
SkAutoTUnref<SkPDFArray> descendantFonts(new SkPDFArray());
|
||||
descendantFonts->append(new SkPDFObjRef(newCIDFont.get()))->unref();
|
||||
insert("DescendantFonts", descendantFonts.get());
|
||||
@ -1069,7 +1055,6 @@ bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
|
||||
const SkTDArray<uint32_t>* subset) {
|
||||
SkAutoTUnref<SkPDFDict> descriptor(new SkPDFDict("FontDescriptor"));
|
||||
setFontDescriptor(descriptor.get());
|
||||
addResource(descriptor.get());
|
||||
insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
|
||||
if (!addCommonFontDescriptorEntries(defaultWidth)) {
|
||||
return false;
|
||||
@ -1098,7 +1083,6 @@ bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
|
||||
}
|
||||
SkASSERT(fontSize);
|
||||
SkASSERT(fontStream.get());
|
||||
addResource(fontStream.get());
|
||||
|
||||
fontStream->insertInt("Length1", fontSize);
|
||||
descriptor->insert("FontFile2",
|
||||
@ -1111,7 +1095,6 @@ bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
|
||||
SkAutoTDelete<SkStream> fontData(typeface()->openStream(&ttcIndex));
|
||||
SkAutoTUnref<SkPDFStream> fontStream(
|
||||
new SkPDFStream(fontData.get()));
|
||||
addResource(fontStream.get());
|
||||
|
||||
if (getType() == SkAdvancedTypefaceMetrics::kCFF_Font) {
|
||||
fontStream->insertName("Subtype", "Type1C");
|
||||
@ -1226,7 +1209,6 @@ SkPDFType1Font::~SkPDFType1Font() {}
|
||||
bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
|
||||
if (getFontDescriptor() != NULL) {
|
||||
SkPDFDict* descriptor = getFontDescriptor();
|
||||
addResource(descriptor);
|
||||
insert("FontDescriptor", new SkPDFObjRef(descriptor))->unref();
|
||||
return true;
|
||||
}
|
||||
@ -1246,7 +1228,6 @@ bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
|
||||
}
|
||||
if (canEmbed()) {
|
||||
SkAutoTUnref<SkPDFStream> fontStream(new SkPDFStream(fontData.get()));
|
||||
addResource(fontStream.get());
|
||||
fontStream->insertInt("Length1", header);
|
||||
fontStream->insertInt("Length2", data);
|
||||
fontStream->insertInt("Length3", trailer);
|
||||
@ -1254,7 +1235,6 @@ bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
|
||||
new SkPDFObjRef(fontStream.get()))->unref();
|
||||
}
|
||||
|
||||
addResource(descriptor.get());
|
||||
insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
|
||||
|
||||
return addCommonFontDescriptorEntries(defaultWidth);
|
||||
@ -1410,7 +1390,6 @@ bool SkPDFType3Font::populate(uint16_t glyphID) {
|
||||
|
||||
SkAutoTUnref<SkPDFStream> glyphDescription(
|
||||
new SkPDFStream(glyphStream.get()));
|
||||
addResource(glyphDescription.get());
|
||||
charProcs->insert(characterName.c_str(),
|
||||
new SkPDFObjRef(glyphDescription.get()))->unref();
|
||||
}
|
||||
|
@ -82,9 +82,6 @@ class SkPDFFont : public SkPDFDict {
|
||||
public:
|
||||
virtual ~SkPDFFont();
|
||||
|
||||
virtual void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects);
|
||||
|
||||
/** Returns the typeface represented by this class. Returns NULL for the
|
||||
* default typeface.
|
||||
*/
|
||||
@ -162,9 +159,6 @@ protected:
|
||||
uint16_t lastGlyphID() const;
|
||||
void setLastGlyphID(uint16_t glyphID);
|
||||
|
||||
// Add object to resource list.
|
||||
void addResource(SkPDFObject* object);
|
||||
|
||||
// Accessors for FontDescriptor associated with this object.
|
||||
SkPDFDict* getFontDescriptor();
|
||||
void setFontDescriptor(SkPDFDict* descriptor);
|
||||
@ -196,7 +190,6 @@ private:
|
||||
uint16_t fFirstGlyphID;
|
||||
uint16_t fLastGlyphID;
|
||||
SkAutoTUnref<const SkAdvancedTypefaceMetrics> fFontInfo;
|
||||
SkTDArray<SkPDFObject*> fResources;
|
||||
SkAutoTUnref<SkPDFDict> fDescriptor;
|
||||
|
||||
SkAdvancedTypefaceMetrics::FontType fFontType;
|
||||
|
@ -21,9 +21,7 @@ SkPDFFormXObject::SkPDFFormXObject(SkPDFDevice* device) {
|
||||
// We don't want to keep around device because we'd have two copies
|
||||
// of content, so reference or copy everything we need (content and
|
||||
// resources).
|
||||
SkTSet<SkPDFObject*> emptySet;
|
||||
SkPDFResourceDict* resourceDict = device->getResourceDict();
|
||||
resourceDict->getReferencedResources(emptySet, &fResources, false);
|
||||
|
||||
SkAutoTDelete<SkStream> content(device->content());
|
||||
setData(content.get());
|
||||
@ -50,9 +48,6 @@ SkPDFFormXObject::SkPDFFormXObject(SkPDFDevice* device) {
|
||||
*/
|
||||
SkPDFFormXObject::SkPDFFormXObject(SkStream* content, SkRect bbox,
|
||||
SkPDFResourceDict* resourceDict) {
|
||||
SkTSet<SkPDFObject*> emptySet;
|
||||
resourceDict->getReferencedResources(emptySet, &fResources, false);
|
||||
|
||||
setData(content);
|
||||
|
||||
SkAutoTUnref<SkPDFArray> bboxArray(SkPDFUtils::RectToArray(bbox));
|
||||
@ -82,14 +77,4 @@ void SkPDFFormXObject::init(const char* colorSpace,
|
||||
insert("Group", group.get());
|
||||
}
|
||||
|
||||
SkPDFFormXObject::~SkPDFFormXObject() {
|
||||
fResources.unrefAll();
|
||||
}
|
||||
|
||||
void SkPDFFormXObject::getResources(
|
||||
const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects) {
|
||||
GetResourcesHelper(&fResources.toArray(),
|
||||
knownResourceObjects,
|
||||
newResourceObjects);
|
||||
}
|
||||
SkPDFFormXObject::~SkPDFFormXObject() {}
|
||||
|
@ -47,15 +47,9 @@ public:
|
||||
SkPDFResourceDict* resourceDict);
|
||||
virtual ~SkPDFFormXObject();
|
||||
|
||||
// The SkPDFObject interface.
|
||||
virtual void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects);
|
||||
|
||||
private:
|
||||
void init(const char* colorSpace,
|
||||
SkPDFDict* resourceDict, SkPDFArray* bbox);
|
||||
|
||||
SkTSet<SkPDFObject*> fResources;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -117,13 +117,6 @@ SkPDFGraphicState::~SkPDFGraphicState() {
|
||||
if (!fSMask) {
|
||||
SkPDFCanon::GetCanon().removeGraphicState(this);
|
||||
}
|
||||
fResources.unrefAll();
|
||||
}
|
||||
|
||||
void SkPDFGraphicState::getResources(
|
||||
const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects) {
|
||||
GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects);
|
||||
}
|
||||
|
||||
void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
|
||||
@ -173,11 +166,6 @@ template <typename T> void unref(T* ptr) { ptr->unref(); }
|
||||
SK_DECLARE_STATIC_LAZY_PTR(SkPDFObject, invertFunction,
|
||||
create_invert_function, unref<SkPDFObject>);
|
||||
|
||||
// static
|
||||
SkPDFObject* SkPDFGraphicState::GetInvertFunction() {
|
||||
return invertFunction.get();
|
||||
}
|
||||
|
||||
// static
|
||||
SkPDFGraphicState* SkPDFGraphicState::GetSMaskGraphicState(
|
||||
SkPDFFormXObject* sMask, bool invert, SkPDFSMaskMode sMaskMode) {
|
||||
@ -196,14 +184,9 @@ SkPDFGraphicState* SkPDFGraphicState::GetSMaskGraphicState(
|
||||
result->fSMask = true;
|
||||
result->insertName("Type", "ExtGState");
|
||||
result->insert("SMask", sMaskDict.get());
|
||||
result->fResources.push(sMask);
|
||||
sMask->ref();
|
||||
|
||||
if (invert) {
|
||||
SkPDFObject* invertFunction = GetInvertFunction();
|
||||
result->fResources.push(invertFunction);
|
||||
invertFunction->ref();
|
||||
sMaskDict->insert("TR", new SkPDFObjRef(invertFunction))->unref();
|
||||
sMaskDict->insert("TR", new SkPDFObjRef(invertFunction.get()))->unref();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -36,9 +36,6 @@ public:
|
||||
|
||||
virtual ~SkPDFGraphicState();
|
||||
|
||||
virtual void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects);
|
||||
|
||||
// Override emitObject so that we can populate the dictionary on
|
||||
// demand.
|
||||
virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog);
|
||||
@ -78,7 +75,6 @@ public:
|
||||
|
||||
private:
|
||||
const SkPaint fPaint;
|
||||
SkTDArray<SkPDFObject*> fResources;
|
||||
bool fPopulated;
|
||||
bool fSMask;
|
||||
|
||||
@ -87,8 +83,6 @@ private:
|
||||
|
||||
void populateDict();
|
||||
|
||||
static SkPDFObject* GetInvertFunction();
|
||||
|
||||
typedef SkPDFDict INHERITED;
|
||||
};
|
||||
|
||||
|
@ -504,27 +504,12 @@ SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
|
||||
SkAutoTUnref<SkPDFImage> mask(
|
||||
SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap,
|
||||
true, srcRect, NULL)));
|
||||
image->addSMask(mask);
|
||||
image->insert("SMask", new SkPDFObjRef(mask))->unref();
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
SkPDFImage::~SkPDFImage() {
|
||||
fResources.unrefAll();
|
||||
}
|
||||
|
||||
SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) {
|
||||
fResources.push(mask);
|
||||
mask->ref();
|
||||
insert("SMask", new SkPDFObjRef(mask))->unref();
|
||||
return mask;
|
||||
}
|
||||
|
||||
void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects) {
|
||||
GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects);
|
||||
}
|
||||
SkPDFImage::~SkPDFImage() {}
|
||||
|
||||
SkPDFImage::SkPDFImage(SkStream* stream,
|
||||
const SkBitmap& bitmap,
|
||||
@ -673,8 +658,6 @@ class PDFJPEGImage : public SkPDFObject {
|
||||
public:
|
||||
PDFJPEGImage(SkData* data, int width, int height)
|
||||
: fData(SkRef(data)), fWidth(width), fHeight(height) {}
|
||||
virtual void getResources(const SkTSet<SkPDFObject*>&,
|
||||
SkTSet<SkPDFObject*>*) SK_OVERRIDE {}
|
||||
virtual void emitObject(
|
||||
SkWStream* stream,
|
||||
SkPDFCatalog* catalog, bool indirect) SK_OVERRIDE {
|
||||
|
@ -54,20 +54,10 @@ public:
|
||||
|
||||
virtual ~SkPDFImage();
|
||||
|
||||
/** Add a Soft Mask (alpha or shape channel) to the image. Refs mask.
|
||||
* @param mask A gray scale image representing the mask.
|
||||
* @return The mask argument is returned.
|
||||
*/
|
||||
SkPDFImage* addSMask(SkPDFImage* mask);
|
||||
|
||||
bool isEmpty() {
|
||||
return fSrcRect.isEmpty();
|
||||
}
|
||||
|
||||
// The SkPDFObject interface.
|
||||
virtual void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects);
|
||||
|
||||
private:
|
||||
SkBitmap fBitmap;
|
||||
bool fIsAlpha;
|
||||
@ -75,8 +65,6 @@ private:
|
||||
SkPicture::EncodeBitmap fEncoder;
|
||||
bool fStreamValid;
|
||||
|
||||
SkTDArray<SkPDFObject*> fResources;
|
||||
|
||||
/** Create a PDF image XObject. Entries for the image properties are
|
||||
* automatically added to the stream dictionary.
|
||||
* @param stream The image stream. May be NULL. Otherwise, this
|
||||
|
@ -24,9 +24,8 @@ SkPDFPage::~SkPDFPage() {}
|
||||
void SkPDFPage::finalizePage(SkPDFCatalog* catalog, bool firstPage,
|
||||
const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects) {
|
||||
SkPDFResourceDict* resourceDict = fDevice->getResourceDict();
|
||||
if (fContentStream.get() == NULL) {
|
||||
insert("Resources", resourceDict);
|
||||
this->insert("Resources", fDevice->getResourceDict());
|
||||
SkSafeUnref(this->insert("MediaBox", fDevice->copyMediaBox()));
|
||||
if (!SkToBool(catalog->getDocumentFlags() &
|
||||
SkPDFDocument::kNoLinks_Flags)) {
|
||||
@ -41,9 +40,6 @@ void SkPDFPage::finalizePage(SkPDFCatalog* catalog, bool firstPage,
|
||||
insert("Contents", new SkPDFObjRef(fContentStream.get()))->unref();
|
||||
}
|
||||
catalog->addObject(fContentStream.get(), firstPage);
|
||||
resourceDict->getReferencedResources(knownResourceObjects,
|
||||
newResourceObjects,
|
||||
true);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -77,27 +77,6 @@ SkPDFObject* SkPDFResourceDict::insertResourceAsReference(
|
||||
return value;
|
||||
}
|
||||
|
||||
void SkPDFResourceDict::getReferencedResources(
|
||||
const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects,
|
||||
bool recursive) const {
|
||||
// TODO: reserve not correct if we need to recursively explore.
|
||||
newResourceObjects->setReserve(newResourceObjects->count() +
|
||||
fResources.count());
|
||||
|
||||
for (int i = 0; i < fResources.count(); i++) {
|
||||
if (!knownResourceObjects.contains(fResources[i]) &&
|
||||
!newResourceObjects->contains(fResources[i])) {
|
||||
newResourceObjects->add(fResources[i]);
|
||||
fResources[i]->ref();
|
||||
if (recursive) {
|
||||
fResources[i]->getResources(knownResourceObjects,
|
||||
newResourceObjects);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SkString SkPDFResourceDict::getResourceName(
|
||||
SkPDFResourceType type, int key) {
|
||||
SkString keyString;
|
||||
|
@ -54,20 +54,6 @@ public:
|
||||
SkPDFObject* insertResourceAsReference(SkPDFResourceType type, int key,
|
||||
SkPDFObject* value);
|
||||
|
||||
/**
|
||||
* Gets resources inserted into this dictionary as a reference.
|
||||
*
|
||||
* @param knownResourceObjects Set containing currently known resources.
|
||||
* Resources in the dict and this set will not be added to the output.
|
||||
* @param newResourceObjects Output set to which non-preexisting resources
|
||||
* will be added.
|
||||
* @param recursive Whether or not to add resources of resources.
|
||||
*/
|
||||
void getReferencedResources(
|
||||
const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects,
|
||||
bool recursive) const;
|
||||
|
||||
/**
|
||||
* Returns the name for the resource that will be generated by the resource
|
||||
* dict.
|
||||
|
@ -510,11 +510,6 @@ private:
|
||||
SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
|
||||
: SkPDFDict("Pattern"), fShaderState(state) {}
|
||||
|
||||
void SkPDFFunctionShader::getResources(const SkTSet<SkPDFObject*>& known,
|
||||
SkTSet<SkPDFObject*>* newr) {
|
||||
GetResourcesHelper(&fResources, known, newr);
|
||||
}
|
||||
|
||||
SkPDFFunctionShader::~SkPDFFunctionShader() {
|
||||
SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex());
|
||||
SkPDFCanon::GetCanon().removeFunctionShader(this);
|
||||
@ -540,11 +535,6 @@ SkPDFAlphaFunctionShader::~SkPDFAlphaFunctionShader() {
|
||||
SkPDFCanon::GetCanon().removeAlphaShader(this);
|
||||
}
|
||||
|
||||
void SkPDFAlphaFunctionShader::getResources(const SkTSet<SkPDFObject*>& known,
|
||||
SkTSet<SkPDFObject*>* newr) {
|
||||
fResourceDict->getReferencedResources(known, newr, true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state)
|
||||
@ -561,11 +551,6 @@ SkPDFImageShader::~SkPDFImageShader() {
|
||||
fResources.unrefAll();
|
||||
}
|
||||
|
||||
void SkPDFImageShader::getResources(const SkTSet<SkPDFObject*>& known,
|
||||
SkTSet<SkPDFObject*>* newr) {
|
||||
GetResourcesHelper(&fResources.toArray(), known, newr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static SkPDFObject* get_pdf_shader_by_state(
|
||||
@ -1129,10 +1114,6 @@ SkPDFImageShader* SkPDFImageShader::Create(
|
||||
SkNEW_ARGS(SkPDFImageShader, (autoState->detach()));
|
||||
imageShader->setData(content.get());
|
||||
|
||||
SkPDFResourceDict* resourceDict = pattern.getResourceDict();
|
||||
resourceDict->getReferencedResources(imageShader->fResources,
|
||||
&imageShader->fResources, false);
|
||||
|
||||
populate_tiling_pattern_dict(imageShader, patternBBox,
|
||||
pattern.getResourceDict(), finalMatrix);
|
||||
|
||||
|
@ -55,8 +55,6 @@ public:
|
||||
static SkPDFFunctionShader* Create(SkAutoTDelete<SkPDFShader::State>*);
|
||||
virtual ~SkPDFFunctionShader();
|
||||
bool equals(const SkPDFShader::State&) const;
|
||||
void getResources(const SkTSet<SkPDFObject*>&,
|
||||
SkTSet<SkPDFObject*>*) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkAutoTDelete<const SkPDFShader::State> fShaderState;
|
||||
@ -74,8 +72,6 @@ class SkPDFAlphaFunctionShader : public SkPDFStream {
|
||||
public:
|
||||
static SkPDFAlphaFunctionShader* Create(SkAutoTDelete<SkPDFShader::State>*);
|
||||
virtual ~SkPDFAlphaFunctionShader();
|
||||
void getResources(const SkTSet<SkPDFObject*>&,
|
||||
SkTSet<SkPDFObject*>*) SK_OVERRIDE;
|
||||
bool equals(const SkPDFShader::State&) const;
|
||||
|
||||
private:
|
||||
@ -89,8 +85,6 @@ class SkPDFImageShader : public SkPDFStream {
|
||||
public:
|
||||
static SkPDFImageShader* Create(SkAutoTDelete<SkPDFShader::State>*);
|
||||
virtual ~SkPDFImageShader();
|
||||
void getResources(const SkTSet<SkPDFObject*>&,
|
||||
SkTSet<SkPDFObject*>*) SK_OVERRIDE;
|
||||
bool equals(const SkPDFShader::State&) const;
|
||||
|
||||
private:
|
||||
|
@ -17,36 +17,6 @@
|
||||
#define SNPRINTF snprintf
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkPDFObject::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects) {}
|
||||
|
||||
void SkPDFObject::AddResourceHelper(SkPDFObject* resource,
|
||||
SkTDArray<SkPDFObject*>* list) {
|
||||
list->push(resource);
|
||||
resource->ref();
|
||||
}
|
||||
|
||||
void SkPDFObject::GetResourcesHelper(
|
||||
const SkTDArray<SkPDFObject*>* resources,
|
||||
const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects) {
|
||||
if (resources->count()) {
|
||||
newResourceObjects->setReserve(
|
||||
newResourceObjects->count() + resources->count());
|
||||
for (int i = 0; i < resources->count(); i++) {
|
||||
if (!knownResourceObjects.contains((*resources)[i]) &&
|
||||
!newResourceObjects->contains((*resources)[i])) {
|
||||
newResourceObjects->add((*resources)[i]);
|
||||
(*resources)[i]->ref();
|
||||
(*resources)[i]->getResources(knownResourceObjects,
|
||||
newResourceObjects);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {
|
||||
@ -56,8 +26,17 @@ SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {
|
||||
SkPDFObjRef::~SkPDFObjRef() {}
|
||||
|
||||
void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
|
||||
catalog->emitObjectNumber(stream, fObj.get());
|
||||
stream->writeText(" R");
|
||||
stream->writeDecAsText(catalog->getObjectNumber(fObj.get()));
|
||||
stream->writeText(" 0 R"); // Generation number is always 0.
|
||||
}
|
||||
|
||||
void SkPDFObjRef::addResources(SkTSet<SkPDFObject*>* resourceSet,
|
||||
SkPDFCatalog* catalog) const {
|
||||
SkPDFObject* obj = catalog->getSubstituteObject(fObj);
|
||||
SkASSERT(obj);
|
||||
if (resourceSet->add(obj)) {
|
||||
obj->addResources(resourceSet, catalog);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -277,6 +256,14 @@ void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
|
||||
stream->writeText("]");
|
||||
}
|
||||
|
||||
void SkPDFArray::addResources(SkTSet<SkPDFObject*>* resourceSet,
|
||||
SkPDFCatalog* catalog) const {
|
||||
for (int i = 0; i < fValue.count(); i++) {
|
||||
catalog->getSubstituteObject(fValue[i])
|
||||
->addResources(resourceSet, catalog);
|
||||
}
|
||||
}
|
||||
|
||||
void SkPDFArray::reserve(int length) {
|
||||
SkASSERT(length <= kMaxLen);
|
||||
fValue.setReserve(length);
|
||||
@ -347,6 +334,17 @@ void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
|
||||
stream->writeText(">>");
|
||||
}
|
||||
|
||||
void SkPDFDict::addResources(SkTSet<SkPDFObject*>* resourceSet,
|
||||
SkPDFCatalog* catalog) const {
|
||||
for (int i = 0; i < fValue.count(); i++) {
|
||||
SkASSERT(fValue[i].key);
|
||||
SkASSERT(fValue[i].value);
|
||||
fValue[i].key->addResources(resourceSet, catalog);
|
||||
catalog->getSubstituteObject(fValue[i].value)
|
||||
->addResources(resourceSet, catalog);
|
||||
}
|
||||
}
|
||||
|
||||
SkPDFObject* SkPDFDict::append(SkPDFName* key, SkPDFObject* value) {
|
||||
SkASSERT(key);
|
||||
SkASSERT(value);
|
||||
|
@ -21,6 +21,8 @@
|
||||
class SkPDFCatalog;
|
||||
class SkWStream;
|
||||
|
||||
class SkPDFObject;
|
||||
|
||||
/** \class SkPDFObject
|
||||
|
||||
A PDF Object is the base class for primitive elements in a PDF file. A
|
||||
@ -36,41 +38,17 @@ public:
|
||||
* @param catalog The object catalog to use.
|
||||
* @param stream The writable output stream to send the output to.
|
||||
*/
|
||||
// TODO(halcanary): make this method const
|
||||
virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog) = 0;
|
||||
|
||||
/** For non-primitive objects (i.e. objects defined outside this file),
|
||||
* this method will add to newResourceObjects any objects that this method
|
||||
* depends on, but not already in knownResourceObjects. This operates
|
||||
* recursively so if this object depends on another object and that object
|
||||
* depends on two more, all three objects will be added.
|
||||
/**
|
||||
* Adds all transitive dependencies of this object to resourceSet.
|
||||
*
|
||||
* @param knownResourceObjects The set of resources to be ignored.
|
||||
* @param newResourceObjects The set to append dependant resources to.
|
||||
* @param catalog Implementations should respect the catalog's
|
||||
* object substitution map.
|
||||
*/
|
||||
virtual void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects);
|
||||
|
||||
/** Static helper function to add a resource to a list. The list takes
|
||||
* a reference.
|
||||
* @param resource The resource to add.
|
||||
* @param list The list to add the resource to.
|
||||
*/
|
||||
static void AddResourceHelper(SkPDFObject* resource,
|
||||
SkTDArray<SkPDFObject*>* list);
|
||||
|
||||
/** Static helper function to copy and reference the resources (and all
|
||||
* their subresources) into a new list.
|
||||
* @param resources The resource list.
|
||||
* @param newResourceObjects All the resource objects (recursively) used on
|
||||
* the page are added to this array. This gives
|
||||
* the caller a chance to deduplicate resources
|
||||
* across pages.
|
||||
* @param knownResourceObjects The set of resources to be ignored.
|
||||
*/
|
||||
static void GetResourcesHelper(
|
||||
const SkTDArray<SkPDFObject*>* resources,
|
||||
const SkTSet<SkPDFObject*>& knownResourceObjects,
|
||||
SkTSet<SkPDFObject*>* newResourceObjects);
|
||||
virtual void addResources(SkTSet<SkPDFObject*>* resourceSet,
|
||||
SkPDFCatalog* catalog) const {}
|
||||
|
||||
private:
|
||||
typedef SkRefCnt INHERITED;
|
||||
@ -92,6 +70,7 @@ public:
|
||||
|
||||
// The SkPDFObject interface.
|
||||
virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog) SK_OVERRIDE;
|
||||
virtual void addResources(SkTSet<SkPDFObject*>*, SkPDFCatalog*) const SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkAutoTUnref<SkPDFObject> fObj;
|
||||
@ -255,6 +234,7 @@ public:
|
||||
|
||||
// The SkPDFObject interface.
|
||||
virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog) SK_OVERRIDE;
|
||||
virtual void addResources(SkTSet<SkPDFObject*>*, SkPDFCatalog*) const SK_OVERRIDE;
|
||||
|
||||
/** The size of the array.
|
||||
*/
|
||||
@ -326,6 +306,7 @@ public:
|
||||
|
||||
// The SkPDFObject interface.
|
||||
virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog) SK_OVERRIDE;
|
||||
virtual void addResources(SkTSet<SkPDFObject*>*, SkPDFCatalog*) const SK_OVERRIDE;
|
||||
|
||||
/** The size of the dictionary.
|
||||
*/
|
||||
|
@ -75,8 +75,8 @@ static void emit_object(SkPDFObject* object,
|
||||
bool indirect) {
|
||||
SkPDFObject* realObject = catalog->getSubstituteObject(object);
|
||||
if (indirect) {
|
||||
catalog->emitObjectNumber(stream, realObject);
|
||||
stream->writeText(" obj\n");
|
||||
stream->writeDecAsText(catalog->getObjectNumber(object));
|
||||
stream->writeText(" 0 obj\n"); // Generation number is always 0.
|
||||
realObject->emitObject(stream, catalog);
|
||||
stream->writeText("\nendobj\n");
|
||||
} else {
|
||||
@ -201,18 +201,10 @@ static void TestCatalog(skiatest::Reporter* reporter) {
|
||||
catalog.addObject(int2.get(), false);
|
||||
catalog.addObject(int3.get(), false);
|
||||
|
||||
REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int1.get()) == 3);
|
||||
REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int2.get()) == 3);
|
||||
REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int3.get()) == 3);
|
||||
|
||||
SkDynamicMemoryWStream buffer;
|
||||
catalog.emitObjectNumber(&buffer, int1.get());
|
||||
catalog.emitObjectNumber(&buffer, int2.get());
|
||||
catalog.emitObjectNumber(&buffer, int3.get());
|
||||
catalog.emitObjectNumber(&buffer, int1Again.get());
|
||||
char expectedResult[] = "1 02 03 01 0";
|
||||
REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
|
||||
strlen(expectedResult)));
|
||||
REPORTER_ASSERT(reporter, catalog.getObjectNumber(int1.get()) == 1);
|
||||
REPORTER_ASSERT(reporter, catalog.getObjectNumber(int2.get()) == 2);
|
||||
REPORTER_ASSERT(reporter, catalog.getObjectNumber(int3.get()) == 3);
|
||||
REPORTER_ASSERT(reporter, catalog.getObjectNumber(int1Again.get()) == 1);
|
||||
}
|
||||
|
||||
static void TestObjectRef(skiatest::Reporter* reporter) {
|
||||
@ -223,8 +215,8 @@ static void TestObjectRef(skiatest::Reporter* reporter) {
|
||||
SkPDFCatalog catalog((SkPDFDocument::Flags)0);
|
||||
catalog.addObject(int1.get(), false);
|
||||
catalog.addObject(int2.get(), false);
|
||||
REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int1.get()) == 3);
|
||||
REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int2.get()) == 3);
|
||||
REPORTER_ASSERT(reporter, catalog.getObjectNumber(int1.get()) == 1);
|
||||
REPORTER_ASSERT(reporter, catalog.getObjectNumber(int2.get()) == 2);
|
||||
|
||||
char expectedResult[] = "2 0 R";
|
||||
SkDynamicMemoryWStream buffer;
|
||||
@ -237,38 +229,16 @@ static void TestObjectRef(skiatest::Reporter* reporter) {
|
||||
static void TestSubstitute(skiatest::Reporter* reporter) {
|
||||
SkAutoTUnref<SkPDFTestDict> proxy(new SkPDFTestDict());
|
||||
SkAutoTUnref<SkPDFTestDict> stub(new SkPDFTestDict());
|
||||
SkAutoTUnref<SkPDFInt> int33(new SkPDFInt(33));
|
||||
SkAutoTUnref<SkPDFDict> stubResource(new SkPDFDict());
|
||||
SkAutoTUnref<SkPDFInt> int44(new SkPDFInt(44));
|
||||
|
||||
stub->insert("Value", int33.get());
|
||||
stubResource->insert("InnerValue", int44.get());
|
||||
stub->addResource(stubResource.get());
|
||||
proxy->insert("Value", new SkPDFInt(33))->unref();
|
||||
stub->insert("Value", new SkPDFInt(44))->unref();
|
||||
|
||||
SkPDFCatalog catalog((SkPDFDocument::Flags)0);
|
||||
catalog.addObject(proxy.get(), false);
|
||||
catalog.setSubstitute(proxy.get(), stub.get());
|
||||
|
||||
SkDynamicMemoryWStream buffer;
|
||||
emit_object(proxy, &buffer, &catalog, false);
|
||||
SkTSet<SkPDFObject*>* substituteResources =
|
||||
catalog.getSubstituteList(false);
|
||||
for (int i = 0; i < substituteResources->count(); ++i) {
|
||||
emit_object((*substituteResources)[i], &buffer, &catalog, true);
|
||||
}
|
||||
|
||||
char objectResult[] = "2 0 obj\n<</Value 33\n>>\nendobj\n";
|
||||
catalog.setFileOffset(proxy.get(), 0);
|
||||
|
||||
size_t outputSize = get_output_size(
|
||||
catalog.getSubstituteObject(proxy.get()), &catalog, true);
|
||||
REPORTER_ASSERT(reporter, outputSize == strlen(objectResult));
|
||||
|
||||
char expectedResult[] =
|
||||
"<</Value 33\n>>1 0 obj\n<</InnerValue 44\n>>\nendobj\n";
|
||||
REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult));
|
||||
REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
|
||||
buffer.getOffset()));
|
||||
REPORTER_ASSERT(reporter, stub.get() == catalog.getSubstituteObject(proxy));
|
||||
REPORTER_ASSERT(reporter, proxy.get() != catalog.getSubstituteObject(stub));
|
||||
}
|
||||
|
||||
// Create a bitmap that would be very eficiently compressed in a ZIP.
|
||||
|
Loading…
Reference in New Issue
Block a user