SkPDF: Factor SkPDFCatalog into SkPDFObjNumMap and SkPDFSubstituteMap
Motivation: Keep separate features separate. Also, future
linearization work will need to have several objNumMap
objects share a substituteMap. Also "catalog" has a
specific meaning in PDF. This catalog did not map to that
catalog.
- Modify SkPDFObject::emitObject and SkPDFObject::addResources
interface to requiore SkPDFObjNumMap and SkPDFSubstituteMap.
- SkPDFObjNumMap const in SkPDFObject::emitObject.
- Remove SkPDFCatalog.cpp/.h
- Modify SkDocument_PDF.cpp to use new functions
- Fold in SkPDFStream::populate
- Fold in SkPDFBitmap::emitDict
- Move SkPDFObjNumMap and SkPDFSubstituteMap to SkPDFTypes.h
- Note (via assert) that SkPDFArray & SkPDFDict don't need to
check substitutes.
- Remove extra space from SkPDFDict serialization.
- SkPDFBitmap SkPDFType0Font SkPDFGraphicState SkPDFStream
updated to new interface.
- PDFPrimitivesTest updated for new interface.
BUG=skia:3585
Review URL: https://codereview.chromium.org/1049753002
diff --git a/gyp/pdf.gypi b/gyp/pdf.gypi
index 9de60a6..68c9897 100644
--- a/gyp/pdf.gypi
+++ b/gyp/pdf.gypi
@@ -16,8 +16,6 @@
'<(skia_src_path)/pdf/SkPDFBitmap.h',
'<(skia_src_path)/pdf/SkPDFCanon.cpp',
'<(skia_src_path)/pdf/SkPDFCanon.h',
- '<(skia_src_path)/pdf/SkPDFCatalog.cpp',
- '<(skia_src_path)/pdf/SkPDFCatalog.h',
'<(skia_src_path)/pdf/SkPDFDevice.cpp',
'<(skia_src_path)/pdf/SkPDFDevice.h',
'<(skia_src_path)/pdf/SkPDFFont.cpp',
diff --git a/src/doc/SkDocument_PDF.cpp b/src/doc/SkDocument_PDF.cpp
index 3b46fb6..0b62e2c 100644
--- a/src/doc/SkDocument_PDF.cpp
+++ b/src/doc/SkDocument_PDF.cpp
@@ -7,7 +7,6 @@
#include "SkDocument.h"
#include "SkPDFCanon.h"
-#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
#include "SkPDFFont.h"
#include "SkPDFResourceDict.h"
@@ -24,7 +23,8 @@
}
static void emit_pdf_footer(SkWStream* stream,
- SkPDFCatalog* catalog,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes,
SkPDFObject* docCatalog,
int64_t objCount,
int32_t xRefFileOffset) {
@@ -35,7 +35,7 @@
trailerDict.insert("Root", new SkPDFObjRef(docCatalog))->unref();
stream->writeText("trailer\n");
- trailerDict.emitObject(stream, catalog);
+ trailerDict.emitObject(stream, objNumMap, substitutes);
stream->writeText("\nstartxref\n");
stream->writeBigDecAsText(xRefFileOffset);
stream->writeText("\n%%EOF");
@@ -43,8 +43,8 @@
static void perform_font_subsetting(
const SkTDArray<const SkPDFDevice*>& pageDevices,
- SkPDFCatalog* catalog) {
- SkASSERT(catalog);
+ SkPDFSubstituteMap* substituteMap) {
+ SkASSERT(substituteMap);
SkPDFGlyphSetMap usage;
for (int i = 0; i < pageDevices.count(); ++i) {
@@ -56,7 +56,7 @@
SkAutoTUnref<SkPDFFont> subsetFont(
entry->fFont->getFontSubset(entry->fGlyphSet));
if (subsetFont) {
- catalog->setSubstitute(entry->fFont, subsetFont.get());
+ substituteMap->setSubstitute(entry->fFont, subsetFont.get());
}
entry = iterator.next();
}
@@ -183,7 +183,6 @@
pageDevices[i]->appendDestinations(dests, page.get());
pages.push(page.detach());
}
- SkPDFCatalog catalog;
SkTDArray<SkPDFDict*> pageTree;
SkAutoTUnref<SkPDFDict> docCatalog(SkNEW_ARGS(SkPDFDict, ("Catalog")));
@@ -209,22 +208,24 @@
}
// Build font subsetting info before proceeding.
- perform_font_subsetting(pageDevices, &catalog);
+ SkPDFSubstituteMap substitutes;
+ perform_font_subsetting(pageDevices, &substitutes);
- if (catalog.addObject(docCatalog.get())) {
- docCatalog->addResources(&catalog);
+ SkPDFObjNumMap objNumMap;
+ if (objNumMap.addObject(docCatalog.get())) {
+ docCatalog->addResources(&objNumMap, substitutes);
}
size_t baseOffset = SkToOffT(stream->bytesWritten());
emit_pdf_header(stream);
SkTDArray<int32_t> offsets;
- for (int i = 0; i < catalog.objects().count(); ++i) {
- SkPDFObject* object = catalog.objects()[i];
+ for (int i = 0; i < objNumMap.objects().count(); ++i) {
+ SkPDFObject* object = objNumMap.objects()[i];
offsets.push(SkToS32(stream->bytesWritten() - baseOffset));
- SkASSERT(object == catalog.getSubstituteObject(object));
- SkASSERT(catalog.getObjectNumber(object) == i + 1);
+ 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, &catalog);
+ object->emitObject(stream, objNumMap, substitutes);
stream->writeText("\nendobj\n");
}
int32_t xRefFileOffset = SkToS32(stream->bytesWritten() - baseOffset);
@@ -240,7 +241,7 @@
stream->writeBigDecAsText(offsets[i], 10);
stream->writeText(" 00000 n \n");
}
- emit_pdf_footer(stream, &catalog, docCatalog.get(), objCount,
+ emit_pdf_footer(stream, objNumMap, substitutes, docCatalog.get(), objCount,
xRefFileOffset);
// The page tree has both child and parent pointers, so it creates a
diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp
index e4580fc..2a9deb6 100644
--- a/src/pdf/SkPDFBitmap.cpp
+++ b/src/pdf/SkPDFBitmap.cpp
@@ -9,7 +9,6 @@
#include "SkFlate.h"
#include "SkPDFBitmap.h"
#include "SkPDFCanon.h"
-#include "SkPDFCatalog.h"
#include "SkStream.h"
#include "SkUnPreMultiply.h"
@@ -244,14 +243,17 @@
public:
PDFAlphaBitmap(const SkBitmap& bm) : fBitmap(bm) {}
~PDFAlphaBitmap() {}
- void emitObject(SkWStream*, SkPDFCatalog*) override;
+ void emitObject(SkWStream*,
+ const SkPDFObjNumMap&,
+ const SkPDFSubstituteMap&) override;
private:
const SkBitmap fBitmap;
- void emitDict(SkWStream*, SkPDFCatalog*, size_t) const;
};
-void PDFAlphaBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
+void PDFAlphaBitmap::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) {
SkAutoLockPixels autoLockPixels(fBitmap);
SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
fBitmap.getColorTable());
@@ -263,15 +265,6 @@
deflateWStream.finalize(); // call before detachAsStream().
SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
- this->emitDict(stream, catalog, asset->getLength());
- pdf_stream_begin(stream);
- stream->writeStream(asset.get(), asset->getLength());
- pdf_stream_end(stream);
-}
-
-void PDFAlphaBitmap::emitDict(SkWStream* stream,
- SkPDFCatalog* catalog,
- size_t length) const {
SkPDFDict pdfDict("XObject");
pdfDict.insertName("Subtype", "Image");
pdfDict.insertInt("Width", fBitmap.width());
@@ -279,39 +272,28 @@
pdfDict.insertName("ColorSpace", "DeviceGray");
pdfDict.insertInt("BitsPerComponent", 8);
pdfDict.insertName("Filter", "FlateDecode");
- pdfDict.insertInt("Length", length);
- pdfDict.emitObject(stream, catalog);
+ pdfDict.insertInt("Length", asset->getLength());
+ pdfDict.emitObject(stream, objNumMap, substitutes);
+
+ pdf_stream_begin(stream);
+ stream->writeStream(asset.get(), asset->getLength());
+ pdf_stream_end(stream);
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
-void SkPDFBitmap::addResources(SkPDFCatalog* catalog) const {
+void SkPDFBitmap::addResources(SkPDFObjNumMap* catalog,
+ const SkPDFSubstituteMap& substitutes) const {
if (fSMask.get()) {
- if (catalog->addObject(fSMask.get())) {
- fSMask->addResources(catalog);
+ SkPDFObject* obj = substitutes.getSubstitute(fSMask.get());
+ SkASSERT(obj);
+ if (catalog->addObject(obj)) {
+ obj->addResources(catalog, substitutes);
}
}
}
-void SkPDFBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
- SkAutoLockPixels autoLockPixels(fBitmap);
- SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
- fBitmap.getColorTable());
-
- // Write to a temporary buffer to get the compressed length.
- SkDynamicMemoryWStream buffer;
- SkDeflateWStream deflateWStream(&buffer);
- bitmap_to_pdf_pixels(fBitmap, &deflateWStream);
- deflateWStream.finalize(); // call before detachAsStream().
- SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
-
- this->emitDict(stream, catalog, asset->getLength());
- pdf_stream_begin(stream);
- stream->writeStream(asset.get(), asset->getLength());
- pdf_stream_end(stream);
-}
-
static SkPDFArray* make_indexed_color_space(const SkColorTable* table) {
SkPDFArray* result = SkNEW(SkPDFArray);
result->reserve(4);
@@ -342,9 +324,20 @@
return result;
}
-void SkPDFBitmap::emitDict(SkWStream* stream,
- SkPDFCatalog* catalog,
- size_t length) const {
+void SkPDFBitmap::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) {
+ SkAutoLockPixels autoLockPixels(fBitmap);
+ SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
+ fBitmap.getColorTable());
+
+ // Write to a temporary buffer to get the compressed length.
+ SkDynamicMemoryWStream buffer;
+ SkDeflateWStream deflateWStream(&buffer);
+ bitmap_to_pdf_pixels(fBitmap, &deflateWStream);
+ deflateWStream.finalize(); // call before detachAsStream().
+ SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
+
SkPDFDict pdfDict("XObject");
pdfDict.insertName("Subtype", "Image");
pdfDict.insertInt("Width", fBitmap.width());
@@ -363,8 +356,12 @@
pdfDict.insert("SMask", new SkPDFObjRef(fSMask))->unref();
}
pdfDict.insertName("Filter", "FlateDecode");
- pdfDict.insertInt("Length", length);
- pdfDict.emitObject(stream, catalog);
+ pdfDict.insertInt("Length", asset->getLength());
+ pdfDict.emitObject(stream, objNumMap,substitutes);
+
+ pdf_stream_begin(stream);
+ stream->writeStream(asset.get(), asset->getLength());
+ pdf_stream_end(stream);
}
SkPDFBitmap::SkPDFBitmap(const SkBitmap& bm,
diff --git a/src/pdf/SkPDFBitmap.h b/src/pdf/SkPDFBitmap.h
index 6816ed6..bf41f63 100644
--- a/src/pdf/SkPDFBitmap.h
+++ b/src/pdf/SkPDFBitmap.h
@@ -27,8 +27,11 @@
// Returns NULL on unsupported bitmap;
static SkPDFBitmap* Create(SkPDFCanon*, const SkBitmap&);
~SkPDFBitmap();
- void emitObject(SkWStream*, SkPDFCatalog*) override;
- void addResources(SkPDFCatalog*) const override;
+ void emitObject(SkWStream*,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) override;
+ void addResources(SkPDFObjNumMap*,
+ const SkPDFSubstituteMap&) const override;
bool equals(const SkBitmap& other) const {
return fBitmap.getGenerationID() == other.getGenerationID() &&
fBitmap.pixelRefOrigin() == other.pixelRefOrigin() &&
@@ -39,7 +42,6 @@
const SkBitmap fBitmap;
const SkAutoTUnref<SkPDFObject> fSMask;
SkPDFBitmap(const SkBitmap&, SkPDFObject*);
- void emitDict(SkWStream*, SkPDFCatalog*, size_t) const;
};
#endif // SkPDFBitmap_DEFINED
diff --git a/src/pdf/SkPDFCatalog.cpp b/src/pdf/SkPDFCatalog.cpp
deleted file mode 100644
index 4069cc9..0000000
--- a/src/pdf/SkPDFCatalog.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-
-/*
- * Copyright 2010 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#include "SkPDFCatalog.h"
-
-SkPDFCatalog::SkPDFCatalog() {}
-
-SkPDFCatalog::~SkPDFCatalog() {
- fSubstituteMap.foreach(
- [](SkPDFObject*, SkPDFObject** v) { (*v)->unref(); });
-}
-
-bool SkPDFCatalog::addObject(SkPDFObject* obj) {
- if (fObjectNumbers.find(obj)) {
- return false;
- }
- fObjectNumbers.set(obj, fObjectNumbers.count() + 1);
- fObjects.push(obj);
- return true;
-}
-
-int32_t SkPDFCatalog::getObjectNumber(SkPDFObject* obj) const {
- int32_t* objectNumberFound = fObjectNumbers.find(obj);
- SkASSERT(objectNumberFound);
- return *objectNumberFound;
-}
-
-void SkPDFCatalog::setSubstitute(SkPDFObject* original,
- SkPDFObject* substitute) {
- SkASSERT(original != substitute);
- SkASSERT(!fSubstituteMap.find(original));
- fSubstituteMap.set(original, SkRef(substitute));
-}
-
-SkPDFObject* SkPDFCatalog::getSubstituteObject(SkPDFObject* object) const {
- SkPDFObject** found = fSubstituteMap.find(object);
- return found ? *found : object;
-}
diff --git a/src/pdf/SkPDFCatalog.h b/src/pdf/SkPDFCatalog.h
deleted file mode 100644
index 3609f3c..0000000
--- a/src/pdf/SkPDFCatalog.h
+++ /dev/null
@@ -1,56 +0,0 @@
-
-/*
- * Copyright 2010 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#ifndef SkPDFCatalog_DEFINED
-#define SkPDFCatalog_DEFINED
-
-#include "SkPDFTypes.h"
-#include "SkTDArray.h"
-#include "SkTHash.h"
-
-/** \class SkPDFCatalog
-
- The PDF catalog manages object numbers. It is used
- to create the PDF cross reference table.
-*/
-class SkPDFCatalog {
-public:
- SkPDFCatalog();
- ~SkPDFCatalog();
-
- /** Add the passed object to the catalog.
- * @param obj The object to add.
- * @return True iff the object was not already added to the catalog.
- */
- bool addObject(SkPDFObject* obj);
-
- /** Get the object number for the passed object.
- * @param obj The object of interest.
- */
- int32_t getObjectNumber(SkPDFObject* obj) const;
-
- /** Set substitute object for the passed object.
- Refs substitute.
- */
- void setSubstitute(SkPDFObject* original, SkPDFObject* substitute);
-
- /** Find and return any substitute object set for the passed object. If
- * there is none, return the passed object.
- */
- SkPDFObject* getSubstituteObject(SkPDFObject* object) const;
-
- const SkTDArray<SkPDFObject*>& objects() const { return fObjects; }
-
-private:
- SkTDArray<SkPDFObject*> fObjects;
- SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers;
- SkTHashMap<SkPDFObject*, SkPDFObject*> fSubstituteMap;
-};
-
-#endif
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index d36a1d7..1a396c7 100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -10,7 +10,6 @@
#include "SkData.h"
#include "SkGlyphCache.h"
#include "SkPaint.h"
-#include "SkPDFCatalog.h"
#include "SkPDFCanon.h"
#include "SkPDFDevice.h"
#include "SkPDFFont.h"
@@ -1016,9 +1015,11 @@
}
#ifdef SK_DEBUG
-void SkPDFType0Font::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
+void SkPDFType0Font::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) {
SkASSERT(fPopulated);
- return INHERITED::emitObject(stream, catalog);
+ return INHERITED::emitObject(stream, objNumMap, substitutes);
}
#endif
diff --git a/src/pdf/SkPDFFont.h b/src/pdf/SkPDFFont.h
index c286fa4..6f8a923 100644
--- a/src/pdf/SkPDFFont.h
+++ b/src/pdf/SkPDFFont.h
@@ -18,7 +18,7 @@
class SkPaint;
class SkPDFCanon;
-class SkPDFCatalog;
+class SkPDFObjNumMap;
class SkPDFFont;
class SkPDFGlyphSet : SkNoncopyable {
diff --git a/src/pdf/SkPDFFontImpl.h b/src/pdf/SkPDFFontImpl.h
index a0689a3..cc7a4a1 100644
--- a/src/pdf/SkPDFFontImpl.h
+++ b/src/pdf/SkPDFFontImpl.h
@@ -18,7 +18,9 @@
virtual bool multiByteGlyphs() const { return true; }
virtual SkPDFFont* getFontSubset(const SkPDFGlyphSet* usage);
#ifdef SK_DEBUG
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog);
+ virtual void emitObject(SkWStream*,
+ const SkPDFObjNumMap&,
+ const SkPDFSubstituteMap&);
#endif
private:
diff --git a/src/pdf/SkPDFFormXObject.cpp b/src/pdf/SkPDFFormXObject.cpp
index 59e81f4..6797eac 100644
--- a/src/pdf/SkPDFFormXObject.cpp
+++ b/src/pdf/SkPDFFormXObject.cpp
@@ -10,7 +10,6 @@
#include "SkPDFFormXObject.h"
#include "SkMatrix.h"
-#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
#include "SkPDFResourceDict.h"
#include "SkPDFUtils.h"
diff --git a/src/pdf/SkPDFFormXObject.h b/src/pdf/SkPDFFormXObject.h
index 11fa2d5..337f64b 100644
--- a/src/pdf/SkPDFFormXObject.h
+++ b/src/pdf/SkPDFFormXObject.h
@@ -19,7 +19,7 @@
class SkMatrix;
class SkPDFDevice;
-class SkPDFCatalog;
+class SkPDFObjNumMap;
/** \class SkPDFFormXObject
diff --git a/src/pdf/SkPDFGraphicState.cpp b/src/pdf/SkPDFGraphicState.cpp
index 09545d1..6922b08 100644
--- a/src/pdf/SkPDFGraphicState.cpp
+++ b/src/pdf/SkPDFGraphicState.cpp
@@ -114,9 +114,11 @@
SkPDFGraphicState::~SkPDFGraphicState() {}
-void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
+void SkPDFGraphicState::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) {
populateDict();
- SkPDFDict::emitObject(stream, catalog);
+ SkPDFDict::emitObject(stream, objNumMap, substitutes);
}
// static
diff --git a/src/pdf/SkPDFGraphicState.h b/src/pdf/SkPDFGraphicState.h
index dc41fc6..85a324b 100644
--- a/src/pdf/SkPDFGraphicState.h
+++ b/src/pdf/SkPDFGraphicState.h
@@ -37,7 +37,9 @@
// Override emitObject so that we can populate the dictionary on
// demand.
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog);
+ virtual void emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes);
/** Get the graphic state for the passed SkPaint. The reference count of
* the object is incremented and it is the caller's responsibility to
diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp
index da55340..3032125 100644
--- a/src/pdf/SkPDFShader.cpp
+++ b/src/pdf/SkPDFShader.cpp
@@ -11,7 +11,6 @@
#include "SkData.h"
#include "SkPDFCanon.h"
-#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
#include "SkPDFFormXObject.h"
#include "SkPDFGraphicState.h"
diff --git a/src/pdf/SkPDFStream.cpp b/src/pdf/SkPDFStream.cpp
index 939cdd8..5665c59 100644
--- a/src/pdf/SkPDFStream.cpp
+++ b/src/pdf/SkPDFStream.cpp
@@ -9,7 +9,6 @@
#include "SkData.h"
#include "SkFlate.h"
-#include "SkPDFCatalog.h"
#include "SkPDFStream.h"
#include "SkStream.h"
#include "SkStreamPriv.h"
@@ -24,9 +23,26 @@
SkPDFStream::~SkPDFStream() {}
-void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
- SkAssertResult(this->populate(catalog));
- this->INHERITED::emitObject(stream, catalog);
+void SkPDFStream::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) {
+ if (fState == kUnused_State) {
+ fState = kNoCompression_State;
+ SkDynamicMemoryWStream compressedData;
+
+ SkAssertResult(
+ SkFlate::Deflate(fDataStream.get(), &compressedData));
+ SkAssertResult(fDataStream->rewind());
+ if (compressedData.getOffset() < this->dataSize()) {
+ SkAutoTDelete<SkStream> compressed(
+ compressedData.detachAsStream());
+ this->setData(compressed.get());
+ insertName("Filter", "FlateDecode");
+ }
+ fState = kCompressed_State;
+ insertInt("Length", this->dataSize());
+ }
+ this->INHERITED::emitObject(stream, objNumMap, substitutes);
stream->writeText(" stream\n");
stream->writeStream(fDataStream.get(), fDataStream->getLength());
SkAssertResult(fDataStream->rewind());
@@ -52,23 +68,3 @@
SkASSERT(fDataStream->hasLength());
return fDataStream->getLength();
}
-
-bool SkPDFStream::populate(SkPDFCatalog* catalog) {
- if (fState == kUnused_State) {
- fState = kNoCompression_State;
- SkDynamicMemoryWStream compressedData;
-
- SkAssertResult(
- SkFlate::Deflate(fDataStream.get(), &compressedData));
- SkAssertResult(fDataStream->rewind());
- if (compressedData.getOffset() < this->dataSize()) {
- SkAutoTDelete<SkStream> compressed(
- compressedData.detachAsStream());
- this->setData(compressed.get());
- insertName("Filter", "FlateDecode");
- }
- fState = kCompressed_State;
- insertInt("Length", this->dataSize());
- }
- return true;
-}
diff --git a/src/pdf/SkPDFStream.h b/src/pdf/SkPDFStream.h
index 9a43e3c..b43ead5 100644
--- a/src/pdf/SkPDFStream.h
+++ b/src/pdf/SkPDFStream.h
@@ -15,7 +15,7 @@
#include "SkStream.h"
#include "SkTemplates.h"
-class SkPDFCatalog;
+class SkPDFObjNumMap;
/** \class SkPDFStream
@@ -40,7 +40,9 @@
virtual ~SkPDFStream();
// The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog) override;
+ virtual void emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) override;
protected:
enum State {
@@ -55,10 +57,6 @@
*/
SkPDFStream();
- // Populate the stream dictionary. This method returns false if
- // fSubstitute should be used.
- virtual bool populate(SkPDFCatalog* catalog);
-
void setData(SkData* data);
void setData(SkStream* stream);
diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp
index 02c5573..e80d118 100644
--- a/src/pdf/SkPDFTypes.cpp
+++ b/src/pdf/SkPDFTypes.cpp
@@ -7,7 +7,6 @@
*/
-#include "SkPDFCatalog.h"
#include "SkPDFTypes.h"
#include "SkStream.h"
@@ -25,17 +24,20 @@
SkPDFObjRef::~SkPDFObjRef() {}
-void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
- SkPDFObject* obj = catalog->getSubstituteObject(fObj);
- stream->writeDecAsText(catalog->getObjectNumber(obj));
+void SkPDFObjRef::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) {
+ SkPDFObject* obj = substitutes.getSubstitute(fObj);
+ stream->writeDecAsText(objNumMap.getObjectNumber(obj));
stream->writeText(" 0 R"); // Generation number is always 0.
}
-void SkPDFObjRef::addResources(SkPDFCatalog* catalog) const {
- SkPDFObject* obj = catalog->getSubstituteObject(fObj);
+void SkPDFObjRef::addResources(SkPDFObjNumMap* catalog,
+ const SkPDFSubstituteMap& substitutes) const {
+ SkPDFObject* obj = substitutes.getSubstitute(fObj);
SkASSERT(obj);
if (catalog->addObject(obj)) {
- obj->addResources(catalog);
+ obj->addResources(catalog, substitutes);
}
}
@@ -44,7 +46,9 @@
SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {}
SkPDFInt::~SkPDFInt() {}
-void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
+void SkPDFInt::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap&,
+ const SkPDFSubstituteMap&) {
stream->writeDecAsText(fValue);
}
@@ -53,12 +57,10 @@
SkPDFBool::SkPDFBool(bool value) : fValue(value) {}
SkPDFBool::~SkPDFBool() {}
-void SkPDFBool::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
- if (fValue) {
- stream->writeText("true");
- } else {
- stream->writeText("false");
- }
+void SkPDFBool::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap&,
+ const SkPDFSubstituteMap&) {
+ stream->writeText(fValue ? "true" : "false");
}
////////////////////////////////////////////////////////////////////////////////
@@ -66,8 +68,10 @@
SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {}
SkPDFScalar::~SkPDFScalar() {}
-void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
- Append(fValue, stream);
+void SkPDFScalar::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap&,
+ const SkPDFSubstituteMap&) {
+ SkPDFScalar::Append(fValue, stream);
}
// static
@@ -135,7 +139,9 @@
SkPDFString::~SkPDFString() {}
-void SkPDFString::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
+void SkPDFString::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap&,
+ const SkPDFSubstituteMap&) {
stream->write(fValue.c_str(), fValue.size());
}
@@ -214,7 +220,9 @@
return fValue == b.fValue;
}
-void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
+void SkPDFName::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap&,
+ const SkPDFSubstituteMap&) {
stream->write(fValue.c_str(), fValue.size());
}
@@ -245,10 +253,13 @@
fValue.unrefAll();
}
-void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
+void SkPDFArray::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) {
stream->writeText("[");
for (int i = 0; i < fValue.count(); i++) {
- catalog->getSubstituteObject(fValue[i])->emitObject(stream, catalog);
+ SkASSERT(substitutes.getSubstitute(fValue[i]) == fValue[i]);
+ fValue[i]->emitObject(stream, objNumMap, substitutes);
if (i + 1 < fValue.count()) {
stream->writeText(" ");
}
@@ -256,9 +267,11 @@
stream->writeText("]");
}
-void SkPDFArray::addResources(SkPDFCatalog* catalog) const {
+void SkPDFArray::addResources(SkPDFObjNumMap* catalog,
+ const SkPDFSubstituteMap& substitutes) const {
for (int i = 0; i < fValue.count(); i++) {
- catalog->getSubstituteObject(fValue[i])->addResources(catalog);
+ SkASSERT(substitutes.getSubstitute(fValue[i]) == fValue[i]);
+ fValue[i]->addResources(catalog, substitutes);
}
}
@@ -313,26 +326,33 @@
return fValue.count();
}
-void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
+void SkPDFDict::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) {
stream->writeText("<<");
for (int i = 0; i < fValue.count(); i++) {
SkASSERT(fValue[i].key);
SkASSERT(fValue[i].value);
- fValue[i].key->emitObject(stream, catalog);
+ SkASSERT(substitutes.getSubstitute(fValue[i].key) == fValue[i].key);
+ SkASSERT(substitutes.getSubstitute(fValue[i].value) == fValue[i].value);
+ fValue[i].key->emitObject(stream, objNumMap, substitutes);
stream->writeText(" ");
- catalog->getSubstituteObject(fValue[i].value)
- ->emitObject(stream, catalog);
- stream->writeText("\n");
+ fValue[i].value->emitObject(stream, objNumMap, substitutes);
+ if (i + 1 < fValue.count()) {
+ stream->writeText("\n");
+ }
}
stream->writeText(">>");
}
-void SkPDFDict::addResources(SkPDFCatalog* catalog) const {
+void SkPDFDict::addResources(SkPDFObjNumMap* catalog,
+ const SkPDFSubstituteMap& substitutes) const {
for (int i = 0; i < fValue.count(); i++) {
SkASSERT(fValue[i].key);
SkASSERT(fValue[i].value);
- fValue[i].key->addResources(catalog);
- catalog->getSubstituteObject(fValue[i].value)->addResources(catalog);
+ fValue[i].key->addResources(catalog, substitutes);
+ SkASSERT(substitutes.getSubstitute(fValue[i].value) == fValue[i].value);
+ fValue[i].value->addResources(catalog, substitutes);
}
}
@@ -394,3 +414,40 @@
Rec(SkRef(other.fValue[i].key), SkRef(other.fValue[i].value));
}
}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SkPDFSubstituteMap::~SkPDFSubstituteMap() {
+ fSubstituteMap.foreach(
+ [](SkPDFObject*, SkPDFObject** v) { (*v)->unref(); });
+}
+
+void SkPDFSubstituteMap::setSubstitute(SkPDFObject* original,
+ SkPDFObject* substitute) {
+ SkASSERT(original != substitute);
+ SkASSERT(!fSubstituteMap.find(original));
+ fSubstituteMap.set(original, SkRef(substitute));
+}
+
+SkPDFObject* SkPDFSubstituteMap::getSubstitute(SkPDFObject* object) const {
+ SkPDFObject** found = fSubstituteMap.find(object);
+ return found ? *found : object;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool SkPDFObjNumMap::addObject(SkPDFObject* obj) {
+ if (fObjectNumbers.find(obj)) {
+ return false;
+ }
+ fObjectNumbers.set(obj, fObjectNumbers.count() + 1);
+ fObjects.push(obj);
+ return true;
+}
+
+int32_t SkPDFObjNumMap::getObjectNumber(SkPDFObject* obj) const {
+ int32_t* objectNumberFound = fObjectNumbers.find(obj);
+ SkASSERT(objectNumberFound);
+ return *objectNumberFound;
+}
+
diff --git a/src/pdf/SkPDFTypes.h b/src/pdf/SkPDFTypes.h
index 8eea7f8..0a16bf9 100644
--- a/src/pdf/SkPDFTypes.h
+++ b/src/pdf/SkPDFTypes.h
@@ -10,16 +10,18 @@
#ifndef SkPDFTypes_DEFINED
#define SkPDFTypes_DEFINED
+#include "SkPDFTypes.h"
#include "SkRefCnt.h"
#include "SkScalar.h"
#include "SkString.h"
#include "SkTDArray.h"
+#include "SkTHash.h"
#include "SkTypes.h"
-class SkPDFCatalog;
-class SkWStream;
-
+class SkPDFObjNumMap;
class SkPDFObject;
+class SkPDFSubstituteMap;
+class SkWStream;
/** \class SkPDFObject
@@ -37,14 +39,17 @@
* @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;
+ virtual void emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) = 0;
/**
* Adds all transitive dependencies of this object to the
* catalog. Implementations should respect the catalog's object
* substitution map.
*/
- virtual void addResources(SkPDFCatalog* catalog) const {}
+ virtual void addResources(SkPDFObjNumMap* catalog,
+ const SkPDFSubstituteMap& substitutes) const {}
private:
typedef SkRefCnt INHERITED;
@@ -65,8 +70,11 @@
virtual ~SkPDFObjRef();
// The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog) override;
- virtual void addResources(SkPDFCatalog*) const override;
+ virtual void emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) override;
+ virtual void addResources(SkPDFObjNumMap*,
+ const SkPDFSubstituteMap&) const override;
private:
SkAutoTUnref<SkPDFObject> fObj;
@@ -89,7 +97,9 @@
virtual ~SkPDFInt();
// The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog) override;
+ virtual void emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) override;
private:
int32_t fValue;
@@ -112,7 +122,9 @@
virtual ~SkPDFBool();
// The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog) override;
+ virtual void emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) override;
private:
bool fValue;
@@ -137,7 +149,9 @@
static void Append(SkScalar value, SkWStream* stream);
// The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog) override;
+ virtual void emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) override;
private:
SkScalar fValue;
@@ -169,7 +183,9 @@
virtual ~SkPDFString();
// The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog) override;
+ virtual void emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) override;
static SkString FormatString(const char* input, size_t len);
static SkString FormatString(const uint16_t* input, size_t len,
@@ -203,7 +219,9 @@
bool operator==(const SkPDFName& b) const;
// The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog) override;
+ virtual void emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) override;
private:
static const size_t kMaxLen = 127;
@@ -229,8 +247,11 @@
virtual ~SkPDFArray();
// The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog) override;
- virtual void addResources(SkPDFCatalog*) const override;
+ virtual void emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) override;
+ virtual void addResources(SkPDFObjNumMap*,
+ const SkPDFSubstituteMap&) const override;
/** The size of the array.
*/
@@ -301,8 +322,11 @@
virtual ~SkPDFDict();
// The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog) override;
- virtual void addResources(SkPDFCatalog*) const override;
+ virtual void emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) override;
+ virtual void addResources(SkPDFObjNumMap*,
+ const SkPDFSubstituteMap&) const override;
/** The size of the dictionary.
*/
@@ -387,4 +411,53 @@
typedef SkPDFObject INHERITED;
};
+////////////////////////////////////////////////////////////////////////////////
+
+/** \class SkPDFSubstituteMap
+
+ The PDF Substitute Map manages substitute objects and owns the
+ substitutes.
+*/
+class SkPDFSubstituteMap : SkNoncopyable {
+public:
+ ~SkPDFSubstituteMap();
+ /** Set substitute object for the passed object.
+ Refs substitute.
+ */
+ void setSubstitute(SkPDFObject* original, SkPDFObject* substitute);
+
+ /** Find and return any substitute object set for the passed object. If
+ * there is none, return the passed object.
+ */
+ SkPDFObject* getSubstitute(SkPDFObject* object) const;
+
+private:
+ SkTHashMap<SkPDFObject*, SkPDFObject*> fSubstituteMap;
+};
+
+/** \class SkPDFObjNumMap
+
+ The PDF Object Number Map manages object numbers. It is used to
+ create the PDF cross reference table.
+*/
+class SkPDFObjNumMap : SkNoncopyable {
+public:
+ /** Add the passed object to the catalog.
+ * @param obj The object to add.
+ * @return True iff the object was not already added to the catalog.
+ */
+ bool addObject(SkPDFObject* obj);
+
+ /** Get the object number for the passed object.
+ * @param obj The object of interest.
+ */
+ int32_t getObjectNumber(SkPDFObject* obj) const;
+
+ const SkTDArray<SkPDFObject*>& objects() const { return fObjects; }
+
+private:
+ SkTDArray<SkPDFObject*> fObjects;
+ SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers;
+};
+
#endif
diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp
index e361554..a98aacb 100644
--- a/tests/PDFPrimitivesTest.cpp
+++ b/tests/PDFPrimitivesTest.cpp
@@ -13,7 +13,6 @@
#include "SkImageEncoder.h"
#include "SkMatrix.h"
#include "SkPDFCanon.h"
-#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
#include "SkPDFStream.h"
#include "SkPDFTypes.h"
@@ -36,36 +35,39 @@
static void emit_object(SkPDFObject* object,
SkWStream* stream,
- SkPDFCatalog* catalog,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes,
bool indirect) {
- SkPDFObject* realObject = catalog->getSubstituteObject(object);
+ SkPDFObject* realObject = substitutes.getSubstitute(object);
if (indirect) {
- stream->writeDecAsText(catalog->getObjectNumber(object));
+ stream->writeDecAsText(objNumMap.getObjectNumber(realObject));
stream->writeText(" 0 obj\n"); // Generation number is always 0.
- realObject->emitObject(stream, catalog);
+ realObject->emitObject(stream, objNumMap, substitutes);
stream->writeText("\nendobj\n");
} else {
- realObject->emitObject(stream, catalog);
+ realObject->emitObject(stream, objNumMap, substitutes);
}
}
static size_t get_output_size(SkPDFObject* object,
- SkPDFCatalog* catalog,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes,
bool indirect) {
SkDynamicMemoryWStream buffer;
- emit_object(object, &buffer, catalog, indirect);
+ emit_object(object, &buffer, objNumMap, substitutes, indirect);
return buffer.getOffset();
}
static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj,
const char* expectedData, size_t expectedSize,
bool indirect) {
- SkPDFCatalog catalog;
- size_t directSize = get_output_size(obj, &catalog, false);
+ SkPDFSubstituteMap substituteMap;
+ SkPDFObjNumMap catalog;
+ size_t directSize = get_output_size(obj, catalog, substituteMap, false);
REPORTER_ASSERT(reporter, directSize == expectedSize);
SkDynamicMemoryWStream buffer;
- emit_object(obj, &buffer, &catalog, false);
+ emit_object(obj, &buffer, catalog, substituteMap, false);
REPORTER_ASSERT(reporter, directSize == buffer.getOffset());
REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedData,
directSize));
@@ -79,12 +81,13 @@
catalog.addObject(obj);
- size_t indirectSize = get_output_size(obj, &catalog, true);
+ size_t indirectSize =
+ get_output_size(obj, catalog, substituteMap, true);
REPORTER_ASSERT(reporter,
indirectSize == directSize + headerLen + footerLen);
buffer.reset();
- emit_object(obj, &buffer, &catalog, true);
+ emit_object(obj, &buffer, catalog, substituteMap, true);
REPORTER_ASSERT(reporter, indirectSize == buffer.getOffset());
REPORTER_ASSERT(reporter, stream_equals(buffer, 0, header, headerLen));
REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen, expectedData,
@@ -108,10 +111,10 @@
SkAutoTUnref<SkPDFStream> stream(new SkPDFStream(streamData.get()));
SimpleCheckObjectOutput(
reporter, stream.get(),
- "<</Length 12\n>> stream\nTest\nFoo\tBar\nendstream");
+ "<</Length 12>> stream\nTest\nFoo\tBar\nendstream");
stream->insert("Attribute", new SkPDFInt(42))->unref();
SimpleCheckObjectOutput(reporter, stream.get(),
- "<</Length 12\n/Attribute 42\n>> stream\n"
+ "<</Length 12\n/Attribute 42>> stream\n"
"Test\nFoo\tBar\nendstream");
{
@@ -128,8 +131,7 @@
SkAutoDataUnref compressedData(compressedByteStream.copyToData());
SkDynamicMemoryWStream expected;
- expected.writeText("<</Filter /FlateDecode\n/Length 116\n"
- ">> stream\n");
+ expected.writeText("<</Filter /FlateDecode\n/Length 116>> stream\n");
expected.write(compressedData->data(), compressedData->size());
expected.writeText("\nendstream");
SkAutoDataUnref expectedResultData2(expected.copyToData());
@@ -140,7 +142,8 @@
}
static void TestCatalog(skiatest::Reporter* reporter) {
- SkPDFCatalog catalog;
+ SkPDFSubstituteMap substituteMap;
+ SkPDFObjNumMap catalog;
SkAutoTUnref<SkPDFInt> int1(new SkPDFInt(1));
SkAutoTUnref<SkPDFInt> int2(new SkPDFInt(2));
SkAutoTUnref<SkPDFInt> int3(new SkPDFInt(3));
@@ -162,7 +165,8 @@
SkAutoTUnref<SkPDFInt> int2(new SkPDFInt(2));
SkAutoTUnref<SkPDFObjRef> int2ref(new SkPDFObjRef(int2.get()));
- SkPDFCatalog catalog;
+ SkPDFSubstituteMap substituteMap;
+ SkPDFObjNumMap catalog;
catalog.addObject(int1.get());
catalog.addObject(int2.get());
REPORTER_ASSERT(reporter, catalog.getObjectNumber(int1.get()) == 1);
@@ -170,7 +174,7 @@
char expectedResult[] = "2 0 R";
SkDynamicMemoryWStream buffer;
- int2ref->emitObject(&buffer, &catalog);
+ int2ref->emitObject(&buffer, catalog, substituteMap);
REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult));
REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
buffer.getOffset()));
@@ -183,12 +187,13 @@
proxy->insert("Value", new SkPDFInt(33))->unref();
stub->insert("Value", new SkPDFInt(44))->unref();
- SkPDFCatalog catalog;
+ SkPDFSubstituteMap substituteMap;
+ substituteMap.setSubstitute(proxy.get(), stub.get());
+ SkPDFObjNumMap catalog;
catalog.addObject(proxy.get());
- catalog.setSubstitute(proxy.get(), stub.get());
- REPORTER_ASSERT(reporter, stub.get() == catalog.getSubstituteObject(proxy));
- REPORTER_ASSERT(reporter, proxy.get() != catalog.getSubstituteObject(stub));
+ REPORTER_ASSERT(reporter, stub.get() == substituteMap.getSubstitute(proxy));
+ REPORTER_ASSERT(reporter, proxy.get() != substituteMap.getSubstitute(stub));
}
// This test used to assert without the fix submitted for
@@ -272,13 +277,13 @@
SimpleCheckObjectOutput(reporter, dict.get(), "<<>>");
SkAutoTUnref<SkPDFName> n1(new SkPDFName("n1"));
dict->insert(n1.get(), int42.get());
- SimpleCheckObjectOutput(reporter, dict.get(), "<</n1 42\n>>");
+ SimpleCheckObjectOutput(reporter, dict.get(), "<</n1 42>>");
SkAutoTUnref<SkPDFName> n2(new SkPDFName("n2"));
SkAutoTUnref<SkPDFName> n3(new SkPDFName("n3"));
dict->insert(n2.get(), realHalf.get());
dict->insert(n3.get(), array.get());
SimpleCheckObjectOutput(reporter, dict.get(),
- "<</n1 42\n/n2 0.5\n/n3 [1 0.5 0]\n>>");
+ "<</n1 42\n/n2 0.5\n/n3 [1 0.5 0]>>");
TestPDFStream(reporter);