aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar halcanary <halcanary@google.com>2016-08-18 14:22:52 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-18 14:22:52 -0700
commit530032a18e373ee673ae96fdbfa1fae6292f8f08 (patch)
tree5edb6e14ca33bf75d3d7b1df73da47be56337b3a
parent9637ea91b88ff8f8e95325bfc41417ffc4d5ee0b (diff)
SkPDF: in-place font subsetting
Motivation: gross code simplification, also no bitset lookups at draw time. SkPDFFont owns its glyph useage bitset. SkPDFSubstituteMap goes away. SkPDFObject interface is simplified. SkPDFDocument tracks font usage (as hash set), not glyph usage. SkPDFFont gets a simpler constructor. SkPDFFont has first and last glyph set in constructor, not adjusted later. SkPDFFont implementations are simplified. SkPDFGlyphSet is replaced with simple SkBitSet. SkPDFFont sizes its SkBitSets based on glyph count. SkPDFGlyphSetMap goes away. SkBitSet is now non-copyable. SkBitSet now how utility methods to match old SkPDFGlyphSet. GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2253283004 CQ_INCLUDE_TRYBOTS=master.client.skia:Test-Win-MSVC-GCE-CPU-AVX2-x86_64-Release-GDI-Trybot,Test-Win-MSVC-GCE-CPU-AVX2-x86_64-Debug-GDI-Trybot Review-Url: https://codereview.chromium.org/2253283004
-rw-r--r--bench/PDFBench.cpp5
-rw-r--r--src/pdf/SkPDFBitmap.cpp34
-rw-r--r--src/pdf/SkPDFDevice.cpp11
-rw-r--r--src/pdf/SkPDFDevice.h4
-rw-r--r--src/pdf/SkPDFDocument.cpp33
-rw-r--r--src/pdf/SkPDFDocument.h9
-rw-r--r--src/pdf/SkPDFFont.cpp243
-rw-r--r--src/pdf/SkPDFFont.h73
-rw-r--r--src/pdf/SkPDFGraphicState.cpp5
-rw-r--r--src/pdf/SkPDFGraphicState.h3
-rw-r--r--src/pdf/SkPDFMakeToUnicodeCmap.cpp4
-rw-r--r--src/pdf/SkPDFMakeToUnicodeCmap.h4
-rw-r--r--src/pdf/SkPDFMetadata.cpp5
-rw-r--r--src/pdf/SkPDFTypes.cpp120
-rw-r--r--src/pdf/SkPDFTypes.h73
-rwxr-xr-xsrc/utils/SkBitSet.cpp21
-rw-r--r--src/utils/SkBitSet.h18
-rw-r--r--tests/BitSetTest.cpp3
-rw-r--r--tests/PDFGlyphsToUnicodeTest.cpp12
-rw-r--r--tests/PDFPrimitivesTest.cpp48
20 files changed, 222 insertions, 506 deletions
diff --git a/bench/PDFBench.cpp b/bench/PDFBench.cpp
index 5b33e8ca15..1010f74ab5 100644
--- a/bench/PDFBench.cpp
+++ b/bench/PDFBench.cpp
@@ -30,14 +30,13 @@ struct NullWStream : public SkWStream {
static void test_pdf_object_serialization(const sk_sp<SkPDFObject> object) {
// SkDebugWStream wStream;
NullWStream wStream;
- SkPDFSubstituteMap substitutes;
SkPDFObjNumMap objNumMap;
- objNumMap.addObjectRecursively(object.get(), substitutes);
+ objNumMap.addObjectRecursively(object.get());
for (int i = 0; i < objNumMap.objects().count(); ++i) {
SkPDFObject* object = objNumMap.objects()[i].get();
wStream.writeDecAsText(i + 1);
wStream.writeText(" 0 obj\n");
- object->emitObject(&wStream, objNumMap, substitutes);
+ object->emitObject(&wStream, objNumMap);
wStream.writeText("\nendobj\n");
}
}
diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp
index 772745ca50..2d789d04d8 100644
--- a/src/pdf/SkPDFBitmap.cpp
+++ b/src/pdf/SkPDFBitmap.cpp
@@ -346,8 +346,7 @@ static void emit_image_xobject(SkWStream* stream,
const SkImage* image,
bool alpha,
const sk_sp<SkPDFObject>& smask,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) {
+ const SkPDFObjNumMap& objNumMap) {
SkBitmap bitmap;
image_get_ro_pixels(image, &bitmap); // TODO(halcanary): test
SkAutoLockPixels autoLockPixels(bitmap); // with malformed images.
@@ -385,7 +384,7 @@ static void emit_image_xobject(SkWStream* stream,
pdfDict.insertInt("BitsPerComponent", 8);
pdfDict.insertName("Filter", "FlateDecode");
pdfDict.insertInt("Length", asset->getLength());
- pdfDict.emitObject(stream, objNumMap, substitutes);
+ pdfDict.emitObject(stream, objNumMap);
pdf_stream_begin(stream);
stream->writeStream(asset.get(), asset->getLength());
@@ -400,10 +399,9 @@ class PDFAlphaBitmap final : public SkPDFObject {
public:
PDFAlphaBitmap(sk_sp<SkImage> image) : fImage(std::move(image)) { SkASSERT(fImage); }
void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& subs) const override {
+ const SkPDFObjNumMap& objNumMap) const override {
SkASSERT(fImage);
- emit_image_xobject(stream, fImage.get(), true, nullptr, objNumMap, subs);
+ emit_image_xobject(stream, fImage.get(), true, nullptr, objNumMap);
}
void drop() override { fImage = nullptr; }
@@ -419,19 +417,12 @@ namespace {
class PDFDefaultBitmap final : public SkPDFObject {
public:
void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& subs) const override {
+ const SkPDFObjNumMap& objNumMap) const override {
SkASSERT(fImage);
- emit_image_xobject(stream, fImage.get(), false, fSMask, objNumMap, subs);
+ emit_image_xobject(stream, fImage.get(), false, fSMask, objNumMap);
}
- void addResources(SkPDFObjNumMap* catalog,
- const SkPDFSubstituteMap& subs) const override {
- SkASSERT(fImage);
- if (fSMask.get()) {
- SkPDFObject* obj = subs.getSubstitute(fSMask.get());
- SkASSERT(obj);
- catalog->addObjectRecursively(obj, subs);
- }
+ void addResources(SkPDFObjNumMap* catalog) const override {
+ catalog->addObjectRecursively(fSMask.get());
}
void drop() override { fImage = nullptr; fSMask = nullptr; }
PDFDefaultBitmap(sk_sp<SkImage> image, sk_sp<SkPDFObject> smask)
@@ -458,15 +449,12 @@ public:
bool fIsYUV;
PDFJpegBitmap(SkISize size, SkData* data, bool isYUV)
: fSize(size), fData(SkRef(data)), fIsYUV(isYUV) { SkASSERT(data); }
- void emitObject(SkWStream*,
- const SkPDFObjNumMap&,
- const SkPDFSubstituteMap&) const override;
+ void emitObject(SkWStream*, const SkPDFObjNumMap&) const override;
void drop() override { fData = nullptr; }
};
void PDFJpegBitmap::emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substituteMap) const {
+ const SkPDFObjNumMap& objNumMap) const {
SkASSERT(fData);
SkPDFDict pdfDict("XObject");
pdfDict.insertName("Subtype", "Image");
@@ -481,7 +469,7 @@ void PDFJpegBitmap::emitObject(SkWStream* stream,
pdfDict.insertName("Filter", "DCTDecode");
pdfDict.insertInt("ColorTransform", 0);
pdfDict.insertInt("Length", SkToInt(fData->size()));
- pdfDict.emitObject(stream, objNumMap, substituteMap);
+ pdfDict.emitObject(stream, objNumMap);
pdf_stream_begin(stream);
stream->write(fData->data(), fData->size());
pdf_stream_end(stream);
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 290c1c4f56..edf17280ef 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1153,7 +1153,6 @@ void SkPDFDevice::internalDrawText(
font->multiByteGlyphs(),
defaultPositioning,
offset);
- SkPDFGlyphSetMap* fontGlyphUsage = fDocument->getGlyphUsage();
const SkGlyphID* const glyphsEnd = glyphs + glyphCount;
while (glyphs < glyphsEnd) {
@@ -1184,7 +1183,7 @@ void SkPDFDevice::internalDrawText(
return;
}
}
- fontGlyphUsage->noteGlyphUsage(font, glyphs, stretch);
+ font->noteGlyphUsage(glyphs, stretch);
if (defaultPositioning) {
(void)font->glyphsToPDFFontEncoding(glyphs, SkToInt(glyphsEnd - glyphs));
while (stretch-- > 0) {
@@ -1318,10 +1317,6 @@ sk_sp<SkPDFDict> SkPDFDevice::makeResourceDict() const {
&fonts);
}
-const SkTDArray<SkPDFFont*>& SkPDFDevice::getFontResources() const {
- return fFontResources;
-}
-
sk_sp<SkPDFArray> SkPDFDevice::copyMediaBox() const {
auto mediaBox = sk_make_sp<SkPDFArray>();
mediaBox->reserve(4);
@@ -1948,9 +1943,9 @@ int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
}
int resourceIndex = fFontResources.find(newFont.get());
if (resourceIndex < 0) {
+ fDocument->registerFont(newFont.get());
resourceIndex = fFontResources.count();
- fFontResources.push(newFont.get());
- newFont.get()->ref();
+ fFontResources.push(newFont.release());
}
return resourceIndex;
}
diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h
index 364cc61688..4a860281e3 100644
--- a/src/pdf/SkPDFDevice.h
+++ b/src/pdf/SkPDFDevice.h
@@ -126,10 +126,6 @@ public:
/** Create the resource dictionary for this device. */
sk_sp<SkPDFDict> makeResourceDict() const;
- /** Get the fonts used on this device.
- */
- const SkTDArray<SkPDFFont*>& getFontResources() const;
-
/** Add our annotations (link to urls and destinations) to the supplied
* array.
* @param array Array to add annotations to.
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
index 4f044c8771..75c5de91e3 100644
--- a/src/pdf/SkPDFDocument.cpp
+++ b/src/pdf/SkPDFDocument.cpp
@@ -23,7 +23,7 @@ SkPDFObjectSerializer::~SkPDFObjectSerializer() {
}
void SkPDFObjectSerializer::addObjectRecursively(const sk_sp<SkPDFObject>& object) {
- fObjNumMap.addObjectRecursively(object.get(), fSubstituteMap);
+ fObjNumMap.addObjectRecursively(object.get());
}
#define SKPDF_MAGIC "\xD3\xEB\xE9\xE1"
@@ -58,10 +58,9 @@ void SkPDFObjectSerializer::serializeObjects(SkWStream* wStream) {
// the head of the linked list of free objects."
SkASSERT(fOffsets.count() == fNextToBeSerialized);
fOffsets.push(this->offset(wStream));
- SkASSERT(object == fSubstituteMap.getSubstitute(object));
wStream->writeDecAsText(index);
wStream->writeText(" 0 obj\n"); // Generation number is always 0.
- object->emitObject(wStream, fObjNumMap, fSubstituteMap);
+ object->emitObject(wStream, fObjNumMap);
wStream->writeText("\nendobj\n");
object->drop();
++fNextToBeSerialized;
@@ -93,7 +92,7 @@ void SkPDFObjectSerializer::serializeFooter(SkWStream* wStream,
trailerDict.insertObject("ID", std::move(id));
}
wStream->writeText("trailer\n");
- trailerDict.emitObject(wStream, fObjNumMap, fSubstituteMap);
+ trailerDict.emitObject(wStream, fObjNumMap);
wStream->writeText("\nstartxref\n");
wStream->writeBigDecAsText(xRefFileOffset);
wStream->writeText("\n%%EOF");
@@ -246,11 +245,15 @@ void SkPDFDocument::onEndPage() {
}
void SkPDFDocument::onAbort() {
+ this->reset();
+}
+
+void SkPDFDocument::reset() {
fCanvas.reset(nullptr);
fPages.reset();
fCanon.reset();
renew(&fObjectSerializer);
- renew(&fGlyphUsage);
+ fFonts.reset();
}
#ifdef SK_SUPPORT_LEGACY_DOCUMENT_API
@@ -419,10 +422,7 @@ static sk_sp<SkPDFArray> make_srgb_output_intents() {
bool SkPDFDocument::onClose(SkWStream* stream) {
SkASSERT(!fCanvas.get());
if (fPages.empty()) {
- fPages.reset();
- fCanon.reset();
- renew(&fObjectSerializer);
- renew(&fGlyphUsage);
+ this->reset();
return false;
}
auto docCatalog = sk_make_sp<SkPDFDict>("Catalog");
@@ -442,21 +442,12 @@ bool SkPDFDocument::onClose(SkWStream* stream) {
}
// Build font subsetting info before calling addObjectRecursively().
- for (const auto& entry : fGlyphUsage) {
- sk_sp<SkPDFObject> subsetFont =
- entry.fFont->getFontSubset(&fCanon, &entry.fGlyphSet);
- if (subsetFont) {
- fObjectSerializer.fSubstituteMap.setSubstitute(
- entry.fFont, subsetFont.get());
- }
- }
-
+ SkPDFCanon* canon = &fCanon;
+ fFonts.foreach([canon](SkPDFFont* p){ p->getFontSubset(canon); });
fObjectSerializer.addObjectRecursively(docCatalog);
fObjectSerializer.serializeObjects(this->getStream());
fObjectSerializer.serializeFooter(this->getStream(), docCatalog, fID);
- fCanon.reset();
- renew(&fObjectSerializer);
- renew(&fGlyphUsage);
+ this->reset();
return true;
}
diff --git a/src/pdf/SkPDFDocument.h b/src/pdf/SkPDFDocument.h
index 86562fe42e..5221dd2728 100644
--- a/src/pdf/SkPDFDocument.h
+++ b/src/pdf/SkPDFDocument.h
@@ -25,7 +25,6 @@ sk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream,
// keep similar functionality together.
struct SkPDFObjectSerializer : SkNoncopyable {
SkPDFObjNumMap fObjNumMap;
- SkPDFSubstituteMap fSubstituteMap;
SkTDArray<int32_t> fOffsets;
sk_sp<SkPDFObject> fInfoDict;
size_t fBaseOffset;
@@ -70,18 +69,16 @@ public:
It might go without saying that objects should not be changed
after calling serialize, since those changes will be too late.
- The same goes for changes to the SkPDFSubstituteMap that effect
- the object or its dependencies.
*/
void serialize(const sk_sp<SkPDFObject>&);
SkPDFCanon* canon() { return &fCanon; }
- SkPDFGlyphSetMap* getGlyphUsage() { return &fGlyphUsage; }
+ void registerFont(SkPDFFont* f) { fFonts.add(f); }
private:
SkPDFObjectSerializer fObjectSerializer;
SkPDFCanon fCanon;
- SkPDFGlyphSetMap fGlyphUsage;
SkTArray<sk_sp<SkPDFDict>> fPages;
+ SkTHashSet<SkPDFFont*> fFonts;
sk_sp<SkPDFDict> fDests;
sk_sp<SkPDFDevice> fPageDevice;
sk_sp<SkCanvas> fCanvas;
@@ -90,6 +87,8 @@ private:
SkScalar fRasterDpi;
SkDocument::PDFMetadata fMetadata;
bool fPDFA;
+
+ void reset();
};
#endif // SkPDFDocument_DEFINED
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index 290061a491..887f95001f 100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -37,50 +37,27 @@ namespace {
// non-symbolic, so always call it symbolic. (PDF 1.4 spec, section 5.7.1)
static const int kPdfSymbolic = 4;
-class SkPDFType0Font final : public SkPDFFont {
-public:
- SkPDFType0Font(const SkAdvancedTypefaceMetrics& info,
- sk_sp<SkTypeface> typeface,
- SkAdvancedTypefaceMetrics::FontType type);
+struct SkPDFType0Font final : public SkPDFFont {
+ SkPDFType0Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&);
virtual ~SkPDFType0Font();
- sk_sp<SkPDFObject> getFontSubset(SkPDFCanon*, const SkPDFGlyphSet*) override;
-#ifdef SK_DEBUG
- void emitObject(SkWStream*,
- const SkPDFObjNumMap&,
- const SkPDFSubstituteMap&) const override;
-#endif
-
-private:
+ void getFontSubset(SkPDFCanon*) override;
#ifdef SK_DEBUG
+ void emitObject(SkWStream*, const SkPDFObjNumMap&) const override;
bool fPopulated;
#endif
- bool populate(const SkPDFGlyphSet* subset,
- const SkAdvancedTypefaceMetrics& metrics);
typedef SkPDFDict INHERITED;
};
-class SkPDFType1Font final : public SkPDFFont {
-public:
- SkPDFType1Font(const SkAdvancedTypefaceMetrics& info,
- sk_sp<SkTypeface> typeface,
- uint16_t glyphID,
- SkPDFCanon* canon);
+struct SkPDFType1Font final : public SkPDFFont {
+ SkPDFType1Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&, SkPDFCanon*);
virtual ~SkPDFType1Font() {}
+ void getFontSubset(SkPDFCanon*) override {} // TODO(halcanary): implement
};
-class SkPDFType3Font final : public SkPDFFont {
-public:
- SkPDFType3Font(const SkAdvancedTypefaceMetrics& info,
- sk_sp<SkTypeface> typeface,
- SkAdvancedTypefaceMetrics::FontType fontType,
- uint16_t glyphID);
+struct SkPDFType3Font final : public SkPDFFont {
+ SkPDFType3Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&);
virtual ~SkPDFType3Font() {}
- void emitObject(SkWStream*,
- const SkPDFObjNumMap&,
- const SkPDFSubstituteMap&) const override {
- SkDEBUGFAIL("should call getFontSubset!");
- }
- sk_sp<SkPDFObject> getFontSubset(SkPDFCanon*, const SkPDFGlyphSet*) override;
+ void getFontSubset(SkPDFCanon*) override;
};
///////////////////////////////////////////////////////////////////////////////
@@ -143,58 +120,6 @@ static sk_sp<SkPDFArray> makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
}
} // namespace
-
-///////////////////////////////////////////////////////////////////////////////
-// class SkPDFGlyphSet
-///////////////////////////////////////////////////////////////////////////////
-
-SkPDFGlyphSet::SkPDFGlyphSet() : fBitSet(SK_MaxU16 + 1) {
-}
-
-void SkPDFGlyphSet::set(const uint16_t* glyphIDs, int numGlyphs) {
- for (int i = 0; i < numGlyphs; ++i) {
- fBitSet.setBit(glyphIDs[i], true);
- }
-}
-
-bool SkPDFGlyphSet::has(uint16_t glyphID) const {
- return fBitSet.isBitSet(glyphID);
-}
-
-void SkPDFGlyphSet::exportTo(SkTDArray<unsigned int>* glyphIDs) const {
- fBitSet.exportTo(glyphIDs);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// class SkPDFGlyphSetMap
-///////////////////////////////////////////////////////////////////////////////
-
-SkPDFGlyphSetMap::SkPDFGlyphSetMap() {}
-
-SkPDFGlyphSetMap::~SkPDFGlyphSetMap() {
- fMap.reset();
-}
-
-void SkPDFGlyphSetMap::noteGlyphUsage(SkPDFFont* font, const uint16_t* glyphIDs,
- int numGlyphs) {
- SkPDFGlyphSet* subset = getGlyphSetForFont(font);
- if (subset) {
- subset->set(glyphIDs, numGlyphs);
- }
-}
-
-SkPDFGlyphSet* SkPDFGlyphSetMap::getGlyphSetForFont(SkPDFFont* font) {
- int index = fMap.count();
- for (int i = 0; i < index; ++i) {
- if (fMap[i].fFont == font) {
- return &fMap[i].fGlyphSet;
- }
- }
- FontGlyphSetPair& pair = fMap.push_back();
- pair.fFont = font;
- return &pair.fGlyphSet;
-}
-
///////////////////////////////////////////////////////////////////////////////
// class SkPDFFont
///////////////////////////////////////////////////////////////////////////////
@@ -322,47 +247,46 @@ SkPDFFont* SkPDFFont::GetFontResource(SkPDFCanon* canon,
return nullptr;
}
+ SkGlyphID firstNonZeroGlyph;
+ SkGlyphID lastGlyph;
+ if (multibyte) {
+ firstNonZeroGlyph = 1;
+ lastGlyph = SkToU16(glyphCount - 1);
+ } else {
+ firstNonZeroGlyph = firstGlyph;
+ lastGlyph = SkToU16(SkTMin<int>(glyphCount - 1,
+ 254 + (int)firstGlyph));
+ }
+ SkPDFFont::Info info = {std::move(typeface), firstNonZeroGlyph, lastGlyph, type};
sk_sp<SkPDFFont> font;
switch (type) {
case SkAdvancedTypefaceMetrics::kType1CID_Font:
case SkAdvancedTypefaceMetrics::kTrueType_Font:
SkASSERT(multibyte);
- font = sk_make_sp<SkPDFType0Font>(metrics,
- std::move(typeface),
- type);
+ font = sk_make_sp<SkPDFType0Font>(std::move(info), metrics);
break;
case SkAdvancedTypefaceMetrics::kType1_Font:
SkASSERT(!multibyte);
- font = sk_make_sp<SkPDFType1Font>(metrics,
- std::move(typeface),
- glyphID,
- canon);
+ font = sk_make_sp<SkPDFType1Font>(std::move(info), metrics, canon);
break;
default:
SkASSERT(!multibyte);
// Type3 is our fallback font.
- font = sk_make_sp<SkPDFType3Font>(metrics,
- std::move(typeface),
- type,
- glyphID);
+ font = sk_make_sp<SkPDFType3Font>(std::move(info), metrics);
break;
}
canon->fFontMap.set(fontID, SkRef(font.get()));
return font.release(); // TODO(halcanary) return sk_sp<SkPDFFont>.
}
-sk_sp<SkPDFObject> SkPDFFont::getFontSubset(SkPDFCanon*, const SkPDFGlyphSet*) {
- return nullptr; // Default: no support.
-}
-
-SkPDFFont::SkPDFFont(sk_sp<SkTypeface> typeface,
- SkAdvancedTypefaceMetrics::FontType fontType)
+SkPDFFont::SkPDFFont(SkPDFFont::Info info)
: SkPDFDict("Font")
- , fTypeface(std::move(typeface))
- , fFirstGlyphID(1)
- , fFontType(fontType) {
+ , fTypeface(std::move(info.fTypeface))
+ , fGlyphUsage(info.fLastGlyphID + 1) // TODO(halcanary): Adjust mapping?
+ , fFirstGlyphID(info.fFirstGlyphID)
+ , fLastGlyphID(info.fLastGlyphID)
+ , fFontType(info.fFontType) {
SkASSERT(fTypeface);
- fLastGlyphID = SkToU16(fTypeface->countGlyphs() - 1);
}
static void add_common_font_descriptor_entries(SkPDFDict* descriptor,
@@ -388,50 +312,25 @@ static void add_common_font_descriptor_entries(SkPDFDict* descriptor,
}
}
-void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(SkGlyphID glyphID) {
- // Single byte glyph encoding supports a max of 255 glyphs.
- fFirstGlyphID = first_glyph_for_single_byte_encoding(glyphID);
- if (fLastGlyphID > fFirstGlyphID + 255 - 1) {
- fLastGlyphID = fFirstGlyphID + 255 - 1;
- }
-}
-
///////////////////////////////////////////////////////////////////////////////
// class SkPDFType0Font
///////////////////////////////////////////////////////////////////////////////
-SkPDFType0Font::SkPDFType0Font(const SkAdvancedTypefaceMetrics& info,
- sk_sp<SkTypeface> typeface,
- SkAdvancedTypefaceMetrics::FontType fontType)
- : SkPDFFont(std::move(typeface), fontType) {
+SkPDFType0Font::SkPDFType0Font(
+ SkPDFFont::Info info,
+ const SkAdvancedTypefaceMetrics& metrics)
+ : SkPDFFont(std::move(info)) {
SkDEBUGCODE(fPopulated = false);
- if (!can_subset(info)) {
- this->populate(nullptr, info);
- }
}
SkPDFType0Font::~SkPDFType0Font() {}
-sk_sp<SkPDFObject> SkPDFType0Font::getFontSubset(SkPDFCanon* canon,
- const SkPDFGlyphSet* subset) {
- const SkAdvancedTypefaceMetrics* metrics =
- SkPDFFont::GetMetrics(this->typeface(), canon);
- SkASSERT(metrics);
- if (!metrics || !can_subset(*metrics)) {
- return nullptr;
- }
- auto newSubset = sk_make_sp<SkPDFType0Font>(
- *metrics, this->refTypeface(), this->getType());
- newSubset->populate(subset, *metrics);
- return newSubset;
-}
#ifdef SK_DEBUG
void SkPDFType0Font::emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const {
+ const SkPDFObjNumMap& objNumMap) const {
SkASSERT(fPopulated);
- return INHERITED::emitObject(stream, objNumMap, substitutes);
+ return INHERITED::emitObject(stream, objNumMap);
}
#endif
@@ -488,8 +387,12 @@ static sk_sp<SkPDFObject> get_subset_font_stream(
}
#endif // SK_SFNTLY_SUBSETTER
-bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset,
- const SkAdvancedTypefaceMetrics& metrics) {
+void SkPDFType0Font::getFontSubset(SkPDFCanon* canon) {
+ const SkAdvancedTypefaceMetrics* metricsPtr =
+ SkPDFFont::GetMetrics(this->typeface(), canon);
+ SkASSERT(metricsPtr);
+ if (!metricsPtr) { return; }
+ const SkAdvancedTypefaceMetrics& metrics = *metricsPtr;
SkASSERT(can_embed(metrics));
SkAdvancedTypefaceMetrics::FontType type = this->getType();
SkTypeface* face = this->typeface();
@@ -504,24 +407,22 @@ bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset,
std::unique_ptr<SkStreamAsset> fontAsset(face->openStream(&ttcIndex));
SkASSERT(fontAsset);
if (!fontAsset) {
- return false;
+ return;
}
size_t fontSize = fontAsset->getLength();
SkASSERT(fontSize > 0);
if (fontSize == 0) {
- return false;
+ return;
}
#ifdef SK_SFNTLY_SUBSETTER
- if (can_subset(metrics) && subset) {
+ if (can_subset(metrics)) {
// Generate glyph id array. in format needed by sfntly
SkTDArray<uint32_t> glyphIDs;
- if (subset) {
- if (!subset->has(0)) {
- glyphIDs.push(0); // Always include glyph 0.
- }
- subset->exportTo(&glyphIDs);
+ if (!this->glyphUsage().has(0)) {
+ glyphIDs.push(0); // Always include glyph 0.
}
+ this->glyphUsage().exportTo(&glyphIDs);
sk_sp<SkPDFObject> subsetStream = get_subset_font_stream(
std::move(fontAsset), glyphIDs, name.c_str());
if (subsetStream) {
@@ -542,7 +443,7 @@ bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset,
SkASSERT(fontData);
SkASSERT(fontData->getLength() > 0);
if (!fontData || 0 == fontData->getLength()) {
- return false;
+ return;
}
auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontData));
fontStream->dict()->insertName("Subtype", "CIDFontType0c");
@@ -574,11 +475,10 @@ bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset,
uint16_t emSize = metrics.fEmSize;
int16_t defaultWidth = 0;
- const SkBitSet* bitSet = subset ? &subset->bitSet() : nullptr;
{
SkAutoGlyphCache glyphCache = vector_cache(face);
sk_sp<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray(
- glyphCache.get(), bitSet, emSize, &defaultWidth);
+ glyphCache.get(), &this->glyphUsage(), emSize, &defaultWidth);
if (widths && widths->size() > 0) {
newCIDFont->insertObject("W", std::move(widths));
}
@@ -598,13 +498,13 @@ bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset,
if (metrics.fGlyphToUnicode.count() > 0) {
this->insertObjRef("ToUnicode",
SkPDFMakeToUnicodeCmap(metrics.fGlyphToUnicode,
- subset,
+ &this->glyphUsage(),
multiByteGlyphs(),
firstGlyphID(),
lastGlyphID()));
}
SkDEBUGCODE(fPopulated = true);
- return true;
+ return;
}
///////////////////////////////////////////////////////////////////////////////
@@ -679,24 +579,22 @@ static void populate_type_1_font(SkPDFDict* font,
font->insertObject("Encoding", std::move(encoding));
}
-SkPDFType1Font::SkPDFType1Font(const SkAdvancedTypefaceMetrics& info,
- sk_sp<SkTypeface> typeface,
- uint16_t glyphID,
+SkPDFType1Font::SkPDFType1Font(SkPDFFont::Info info,
+ const SkAdvancedTypefaceMetrics& metrics,
SkPDFCanon* canon)
- : SkPDFFont(std::move(typeface), SkAdvancedTypefaceMetrics::kType1_Font)
+ : SkPDFFont(std::move(info))
{
SkFontID fontID = this->typeface()->uniqueID();
sk_sp<SkPDFDict> fontDescriptor;
if (SkPDFDict** ptr = canon->fFontDescriptors.find(fontID)) {
fontDescriptor = sk_ref_sp(*ptr);
} else {
- fontDescriptor = make_type1_font_descriptor(this->typeface(), info);
+ fontDescriptor = make_type1_font_descriptor(this->typeface(), metrics);
canon->fFontDescriptors.set(fontID, SkRef(fontDescriptor.get()));
}
this->insertObjRef("FontDescriptor", std::move(fontDescriptor));
- this->adjustGlyphRangeForSingleByteEncoding(glyphID);
// TODO(halcanary): subset this (advances and names).
- populate_type_1_font(this, info, this->typeface(),
+ populate_type_1_font(this, metrics, this->typeface(),
this->firstGlyphID(), this->lastGlyphID());
}
@@ -738,7 +636,7 @@ static void add_type3_font_info(SkPDFCanon* canon,
SkPDFDict* font,
SkTypeface* typeface,
SkScalar emSize,
- const SkPDFGlyphSet* subset,
+ const SkBitSet& subset,
SkGlyphID firstGlyphID,
SkGlyphID lastGlyphID) {
SkASSERT(lastGlyphID >= firstGlyphID);
@@ -770,7 +668,7 @@ static void add_type3_font_info(SkPDFCanon* canon,
sk_sp<SkPDFStream> emptyStream;
for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
- bool skipGlyph = subset && gID != 0 && !subset->has(gID);
+ bool skipGlyph = gID != 0 && !subset.has(gID);
SkString characterName;
SkScalar advance = 0.0f;
SkIRect glyphBBox;
@@ -827,7 +725,7 @@ static void add_type3_font_info(SkPDFCanon* canon,
if (metrics /* && metrics->fGlyphToUnicode.count() > 0 */) {
font->insertObjRef("ToUnicode",
SkPDFMakeToUnicodeCmap(metrics->fGlyphToUnicode,
- subset,
+ &subset,
false,
firstGlyphID,
lastGlyphID));
@@ -837,29 +735,20 @@ static void add_type3_font_info(SkPDFCanon* canon,
font->insertObject("CharProcs", std::move(charProcs));
}
-SkPDFType3Font::SkPDFType3Font(const SkAdvancedTypefaceMetrics& info,
- sk_sp<SkTypeface> typeface,
- SkAdvancedTypefaceMetrics::FontType fontType,
- uint16_t glyphID)
- : SkPDFFont(std::move(typeface), fontType) {
- this->adjustGlyphRangeForSingleByteEncoding(glyphID);
-}
+SkPDFType3Font::SkPDFType3Font(SkPDFFont::Info info,
+ const SkAdvancedTypefaceMetrics& metrics)
+ : SkPDFFont(std::move(info)) {}
-sk_sp<SkPDFObject> SkPDFType3Font::getFontSubset(SkPDFCanon* canon,
- const SkPDFGlyphSet* usage) {
- // All fonts are subset before serialization.
- // TODO(halcanary): all fonts should follow this pattern.
+void SkPDFType3Font::getFontSubset(SkPDFCanon* canon) {
const SkAdvancedTypefaceMetrics* info =
SkPDFFont::GetMetrics(this->typeface(), canon);
SkASSERT(info);
uint16_t emSize = info->fEmSize > 0 ? info->fEmSize : 1000;
- auto font = sk_make_sp<SkPDFDict>("Font");
- add_type3_font_info(canon, font.get(), this->typeface(), (SkScalar)emSize, usage,
+ add_type3_font_info(canon, this, this->typeface(), (SkScalar)emSize,
+ this->glyphUsage(),
this->firstGlyphID(), this->lastGlyphID());
- return font;
}
-
////////////////////////////////////////////////////////////////////////////////
bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFCanon* canon) {
diff --git a/src/pdf/SkPDFFont.h b/src/pdf/SkPDFFont.h
index f2f1df4c24..abf164c013 100644
--- a/src/pdf/SkPDFFont.h
+++ b/src/pdf/SkPDFFont.h
@@ -18,48 +18,6 @@
class SkPDFCanon;
class SkPDFFont;
-class SkPDFGlyphSet : SkNoncopyable {
-public:
- SkPDFGlyphSet();
- SkPDFGlyphSet(SkPDFGlyphSet&& o) : fBitSet(std::move(o.fBitSet)) {}
-
- void set(const uint16_t* glyphIDs, int numGlyphs);
- bool has(uint16_t glyphID) const;
- void exportTo(SkTDArray<uint32_t>* glyphIDs) const;
- const SkBitSet& bitSet() const { return fBitSet; }
-
-private:
- SkBitSet fBitSet;
-};
-
-class SkPDFGlyphSetMap : SkNoncopyable {
-public:
- struct FontGlyphSetPair : SkNoncopyable {
- FontGlyphSetPair() : fFont(nullptr) {}
- FontGlyphSetPair(FontGlyphSetPair&& o)
- : fFont(o.fFont)
- , fGlyphSet(std::move(o.fGlyphSet)) {
- o.fFont = nullptr;
- }
- SkPDFFont* fFont;
- SkPDFGlyphSet fGlyphSet;
- };
-
- SkPDFGlyphSetMap();
- ~SkPDFGlyphSetMap();
-
- const FontGlyphSetPair* begin() const { return fMap.begin(); }
- const FontGlyphSetPair* end() const { return fMap.end(); }
-
- void noteGlyphUsage(SkPDFFont* font, const uint16_t* glyphIDs,
- int numGlyphs);
-
-private:
- SkPDFGlyphSet* getGlyphSetForFont(SkPDFFont* font);
-
- SkTArray<FontGlyphSetPair> fMap;
-};
-
/** \class SkPDFFont
A PDF Object class representing a font. The font may have resources
attached to it in order to embed the font. SkPDFFonts are canonicalized
@@ -112,6 +70,10 @@ public:
int glyphsToPDFFontEncodingCount(const SkGlyphID* glyphIDs,
int numGlyphs) const;
+ void noteGlyphUsage(const SkGlyphID* glyphs, int count) {
+ fGlyphUsage.setAll(glyphs, count);
+ }
+
/** Get the font resource for the passed typeface and glyphID. The
* reference count of the object is incremented and it is the caller's
* responsibility to unreference it when done. This is needed to
@@ -128,14 +90,10 @@ public:
static const SkAdvancedTypefaceMetrics* GetMetrics(SkTypeface* typeface,
SkPDFCanon* canon);
- /** Subset the font based on usage set. Returns a SkPDFFont instance with
- * subset.
- * @param usage Glyph subset requested.
- * @return nullptr if font does not support subsetting, a new instance
- * of SkPDFFont otherwise.
+ /** Subset the font based on current usage.
+ * Must be called before emitObject().
*/
- virtual sk_sp<SkPDFObject> getFontSubset(SkPDFCanon* canon,
- const SkPDFGlyphSet* usage);
+ virtual void getFontSubset(SkPDFCanon*) = 0;
/**
* Return false iff the typeface has its NotEmbeddable flag set.
@@ -145,23 +103,24 @@ public:
protected:
// Common constructor to handle common members.
- SkPDFFont(sk_sp<SkTypeface> typeface,
- SkAdvancedTypefaceMetrics::FontType fontType);
+ struct Info {
+ sk_sp<SkTypeface> fTypeface;
+ SkGlyphID fFirstGlyphID;
+ SkGlyphID fLastGlyphID;
+ SkAdvancedTypefaceMetrics::FontType fFontType;
+ };
+ SkPDFFont(Info);
SkGlyphID firstGlyphID() const { return fFirstGlyphID; }
SkGlyphID lastGlyphID() const { return fLastGlyphID; }
-
+ const SkBitSet& glyphUsage() const { return fGlyphUsage; }
sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
- /** Set fFirstGlyphID and fLastGlyphID to span at most 255 glyphs,
- * including the passed glyphID.
- */
- void adjustGlyphRangeForSingleByteEncoding(SkGlyphID glyphID);
-
void drop() override;
private:
sk_sp<SkTypeface> fTypeface;
+ SkBitSet fGlyphUsage;
// The glyph IDs accessible with this font. For Type1 (non CID) fonts,
// this will be a subset if the font has more than 255 glyphs.
diff --git a/src/pdf/SkPDFGraphicState.cpp b/src/pdf/SkPDFGraphicState.cpp
index 5a603ce8da..a78c4c51b5 100644
--- a/src/pdf/SkPDFGraphicState.cpp
+++ b/src/pdf/SkPDFGraphicState.cpp
@@ -176,8 +176,7 @@ sk_sp<SkPDFDict> SkPDFGraphicState::MakeNoSmaskGraphicState() {
void SkPDFGraphicState::emitObject(
SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const {
+ const SkPDFObjNumMap& objNumMap) const {
auto dict = sk_make_sp<SkPDFDict>("ExtGState");
dict->insertName("Type", "ExtGState");
@@ -207,5 +206,5 @@ void SkPDFGraphicState::emitObject(
dict->insertScalar("ML", fStrokeMiter);
dict->insertBool("SA", true); // SA = Auto stroke adjustment.
dict->insertName("BM", as_blend_mode(xferMode));
- dict->emitObject(stream, objNumMap, substitutes);
+ dict->emitObject(stream, objNumMap);
}
diff --git a/src/pdf/SkPDFGraphicState.h b/src/pdf/SkPDFGraphicState.h
index 49723bd723..0c2e4a0f49 100644
--- a/src/pdf/SkPDFGraphicState.h
+++ b/src/pdf/SkPDFGraphicState.h
@@ -31,8 +31,7 @@ public:
// Override emitObject so that we can populate the dictionary on
// demand.
void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const override;
+ const SkPDFObjNumMap& objNumMap) const override;
/** 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/SkPDFMakeToUnicodeCmap.cpp b/src/pdf/SkPDFMakeToUnicodeCmap.cpp
index 6fd8b1ca16..5186cbbda1 100644
--- a/src/pdf/SkPDFMakeToUnicodeCmap.cpp
+++ b/src/pdf/SkPDFMakeToUnicodeCmap.cpp
@@ -149,7 +149,7 @@ static void append_bfrange_section(const SkTDArray<BFRange>& bfrange,
// one of them), the possible savings by aggressive optimization is 416KB
// pre-compressed and does not provide enough motivation for implementation.
void SkPDFAppendCmapSections(const SkTDArray<SkUnichar>& glyphToUnicode,
- const SkPDFGlyphSet* subset,
+ const SkBitSet* subset,
SkDynamicMemoryWStream* cmap,
bool multiByteGlyphs,
SkGlyphID firstGlyphID,
@@ -212,7 +212,7 @@ void SkPDFAppendCmapSections(const SkTDArray<SkUnichar>& glyphToUnicode,
sk_sp<SkPDFStream> SkPDFMakeToUnicodeCmap(
const SkTDArray<SkUnichar>& glyphToUnicode,
- const SkPDFGlyphSet* subset,
+ const SkBitSet* subset,
bool multiByteGlyphs,
SkGlyphID firstGlyphID,
SkGlyphID lastGlyphID) {
diff --git a/src/pdf/SkPDFMakeToUnicodeCmap.h b/src/pdf/SkPDFMakeToUnicodeCmap.h
index 1bd8930742..0c4d1c37dd 100644
--- a/src/pdf/SkPDFMakeToUnicodeCmap.h
+++ b/src/pdf/SkPDFMakeToUnicodeCmap.h
@@ -13,14 +13,14 @@
sk_sp<SkPDFStream> SkPDFMakeToUnicodeCmap(
const SkTDArray<SkUnichar>& glyphToUnicode,
- const SkPDFGlyphSet* subset,
+ const SkBitSet* subset,
bool multiByteGlyphs,
SkGlyphID firstGlyphID,
SkGlyphID lastGlyphID);
// Exposed for unit testing.
void SkPDFAppendCmapSections(const SkTDArray<SkUnichar>& glyphToUnicode,
- const SkPDFGlyphSet* subset,
+ const SkBitSet* subset,
SkDynamicMemoryWStream* cmap,
bool multiByteGlyphs,
SkGlyphID firstGlyphID,
diff --git a/src/pdf/SkPDFMetadata.cpp b/src/pdf/SkPDFMetadata.cpp
index 259249671f..46fe461be5 100644
--- a/src/pdf/SkPDFMetadata.cpp
+++ b/src/pdf/SkPDFMetadata.cpp
@@ -168,12 +168,11 @@ class PDFXMLObject final : public SkPDFObject {
public:
PDFXMLObject(SkString xml) : fXML(std::move(xml)) {}
void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& omap,
- const SkPDFSubstituteMap& smap) const override {
+ const SkPDFObjNumMap& omap) const override {
SkPDFDict dict("Metadata");
dict.insertName("Subtype", "XML");
dict.insertInt("Length", fXML.size());
- dict.emitObject(stream, omap, smap);
+ dict.emitObject(stream, omap);
static const char streamBegin[] = " stream\n";
stream->write(streamBegin, strlen(streamBegin));
// Do not compress this. The standard requires that a
diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp
index 6bf6afc611..838b5efeb9 100644
--- a/src/pdf/SkPDFTypes.cpp
+++ b/src/pdf/SkPDFTypes.cpp
@@ -113,8 +113,7 @@ static void write_name_escaped(SkWStream* o, const char* name) {
}
void SkPDFUnion::emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const {
+ const SkPDFObjNumMap& objNumMap) const {
switch (fType) {
case Type::kInt:
stream->writeDecAsText(fIntValue);
@@ -147,20 +146,18 @@ void SkPDFUnion::emitObject(SkWStream* stream,
pun(fSkString)->size());
return;
case Type::kObjRef:
- stream->writeDecAsText(objNumMap.getObjectNumber(
- substitutes.getSubstitute(fObject)));
+ stream->writeDecAsText(objNumMap.getObjectNumber(fObject));
stream->writeText(" 0 R"); // Generation number is always 0.
return;
case Type::kObject:
- fObject->emitObject(stream, objNumMap, substitutes);
+ fObject->emitObject(stream, objNumMap);
return;
default:
SkDEBUGFAIL("SkPDFUnion::emitObject with bad type");
}
}
-void SkPDFUnion::addResources(SkPDFObjNumMap* objNumMap,
- const SkPDFSubstituteMap& substituteMap) const {
+void SkPDFUnion::addResources(SkPDFObjNumMap* objNumMap) const {
switch (fType) {
case Type::kInt:
case Type::kColorComponent:
@@ -171,13 +168,11 @@ void SkPDFUnion::addResources(SkPDFObjNumMap* objNumMap,
case Type::kNameSkS:
case Type::kStringSkS:
return; // These have no resources.
- case Type::kObjRef: {
- SkPDFObject* obj = substituteMap.getSubstitute(fObject);
- objNumMap->addObjectRecursively(obj, substituteMap);
+ case Type::kObjRef:
+ objNumMap->addObjectRecursively(fObject);
return;
- }
case Type::kObject:
- fObject->addResources(objNumMap, substituteMap);
+ fObject->addResources(objNumMap);
return;
default:
SkDEBUGFAIL("SkPDFUnion::addResources with bad type");
@@ -253,13 +248,11 @@ SkPDFUnion SkPDFUnion::Object(sk_sp<SkPDFObject> objSp) {
#if 0 // Enable if needed.
void SkPDFAtom::emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const {
- fValue.emitObject(stream, objNumMap, substitutes);
+ const SkPDFObjNumMap& objNumMap) const {
+ fValue.emitObject(stream, objNumMap);
}
-void SkPDFAtom::addResources(SkPDFObjNumMap* map,
- const SkPDFSubstituteMap& substitutes) const {
- fValue.addResources(map, substitutes);
+void SkPDFAtom::addResources(SkPDFObjNumMap* map) const {
+ fValue.addResources(map);
}
#endif // 0
@@ -282,12 +275,11 @@ void SkPDFArray::reserve(int length) {
}
void SkPDFArray::emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const {
+ const SkPDFObjNumMap& objNumMap) const {
SkASSERT(!fDumped);
stream->writeText("[");
for (int i = 0; i < fValues.count(); i++) {
- fValues[i].emitObject(stream, objNumMap, substitutes);
+ fValues[i].emitObject(stream, objNumMap);
if (i + 1 < fValues.count()) {
stream->writeText(" ");
}
@@ -295,11 +287,10 @@ void SkPDFArray::emitObject(SkWStream* stream,
stream->writeText("]");
}
-void SkPDFArray::addResources(SkPDFObjNumMap* catalog,
- const SkPDFSubstituteMap& substitutes) const {
+void SkPDFArray::addResources(SkPDFObjNumMap* catalog) const {
SkASSERT(!fDumped);
for (const SkPDFUnion& value : fValues) {
- value.addResources(catalog, substitutes);
+ value.addResources(catalog);
}
}
@@ -364,33 +355,30 @@ SkPDFDict::SkPDFDict(const char type[]) {
}
void SkPDFDict::emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const {
+ const SkPDFObjNumMap& objNumMap) const {
stream->writeText("<<");
- this->emitAll(stream, objNumMap, substitutes);
+ this->emitAll(stream, objNumMap);
stream->writeText(">>");
}
void SkPDFDict::emitAll(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const {
+ const SkPDFObjNumMap& objNumMap) const {
SkASSERT(!fDumped);
for (int i = 0; i < fRecords.count(); i++) {
- fRecords[i].fKey.emitObject(stream, objNumMap, substitutes);
+ fRecords[i].fKey.emitObject(stream, objNumMap);
stream->writeText(" ");
- fRecords[i].fValue.emitObject(stream, objNumMap, substitutes);
+ fRecords[i].fValue.emitObject(stream, objNumMap);
if (i + 1 < fRecords.count()) {
stream->writeText("\n");
}
}
}
-void SkPDFDict::addResources(SkPDFObjNumMap* catalog,
- const SkPDFSubstituteMap& substitutes) const {
+void SkPDFDict::addResources(SkPDFObjNumMap* catalog) const {
SkASSERT(!fDumped);
for (int i = 0; i < fRecords.count(); i++) {
- fRecords[i].fKey.addResources(catalog, substitutes);
- fRecords[i].fValue.addResources(catalog, substitutes);
+ fRecords[i].fKey.addResources(catalog);
+ fRecords[i].fValue.addResources(catalog);
}
}
@@ -463,20 +451,17 @@ void SkPDFSharedStream::drop() {
#ifdef SK_PDF_LESS_COMPRESSION
void SkPDFSharedStream::emitObject(
SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const {
+ const SkPDFObjNumMap& objNumMap) const {
SkASSERT(fAsset);
std::unique_ptr<SkStreamAsset> dup(fAsset->duplicate());
SkASSERT(dup && dup->hasLength());
size_t length = dup->getLength();
stream->writeText("<<");
- fDict.emitAll(stream, objNumMap, substitutes);
+ fDict.emitAll(stream, objNumMap);
stream->writeText("\n");
- SkPDFUnion::Name("Length").emitObject(
- stream, objNumMap, substitutes);
+ SkPDFUnion::Name("Length").emitObject(stream, objNumMap);
stream->writeText(" ");
- SkPDFUnion::Int(length).emitObject(
- stream, objNumMap, substitutes);
+ SkPDFUnion::Int(length).emitObject(stream, objNumMap);
stream->writeText("\n>>stream\n");
SkStreamCopy(stream, dup.get());
stream->writeText("\nendstream");
@@ -484,8 +469,7 @@ void SkPDFSharedStream::emitObject(
#else
void SkPDFSharedStream::emitObject(
SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const {
+ const SkPDFObjNumMap& objNumMap) const {
SkASSERT(fAsset);
SkDynamicMemoryWStream buffer;
SkDeflateWStream deflateWStream(&buffer);
@@ -496,15 +480,15 @@ void SkPDFSharedStream::emitObject(
deflateWStream.finalize();
size_t length = buffer.bytesWritten();
stream->writeText("<<");
- fDict.emitAll(stream, objNumMap, substitutes);
+ fDict.emitAll(stream, objNumMap);
stream->writeText("\n");
- SkPDFUnion::Name("Length").emitObject(stream, objNumMap, substitutes);
+ SkPDFUnion::Name("Length").emitObject(stream, objNumMap);
stream->writeText(" ");
- SkPDFUnion::Int(length).emitObject(stream, objNumMap, substitutes);
+ SkPDFUnion::Int(length).emitObject(stream, objNumMap);
stream->writeText("\n");
- SkPDFUnion::Name("Filter").emitObject(stream, objNumMap, substitutes);
+ SkPDFUnion::Name("Filter").emitObject(stream, objNumMap);
stream->writeText(" ");
- SkPDFUnion::Name("FlateDecode").emitObject(stream, objNumMap, substitutes);
+ SkPDFUnion::Name("FlateDecode").emitObject(stream, objNumMap);
stream->writeText(">>");
stream->writeText(" stream\n");
buffer.writeToStream(stream);
@@ -513,9 +497,9 @@ void SkPDFSharedStream::emitObject(
#endif
void SkPDFSharedStream::addResources(
- SkPDFObjNumMap* catalog, const SkPDFSubstituteMap& substitutes) const {
+ SkPDFObjNumMap* catalog) const {
SkASSERT(fAsset);
- fDict.addResources(catalog, substitutes);
+ fDict.addResources(catalog);
}
@@ -534,10 +518,9 @@ SkPDFStream::SkPDFStream() {}
SkPDFStream::~SkPDFStream() {}
-void SkPDFStream::addResources(
- SkPDFObjNumMap* catalog, const SkPDFSubstituteMap& substitutes) const {
+void SkPDFStream::addResources(SkPDFObjNumMap* catalog) const {
SkASSERT(fCompressedData);
- fDict.addResources(catalog, substitutes);
+ fDict.addResources(catalog);
}
void SkPDFStream::drop() {
@@ -546,10 +529,9 @@ void SkPDFStream::drop() {
}
void SkPDFStream::emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const {
+ const SkPDFObjNumMap& objNumMap) const {
SkASSERT(fCompressedData);
- fDict.emitObject(stream, objNumMap, substitutes);
+ fDict.emitObject(stream, objNumMap);
// duplicate (a cheap operation) preserves const on fCompressedData.
std::unique_ptr<SkStreamAsset> dup(fCompressedData->duplicate());
SkASSERT(dup);
@@ -594,25 +576,6 @@ void SkPDFStream::setData(std::unique_ptr<SkStreamAsset> stream) {
////////////////////////////////////////////////////////////////////////////////
-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;
@@ -622,10 +585,9 @@ bool SkPDFObjNumMap::addObject(SkPDFObject* obj) {
return true;
}
-void SkPDFObjNumMap::addObjectRecursively(SkPDFObject* obj,
- const SkPDFSubstituteMap& subs) {
+void SkPDFObjNumMap::addObjectRecursively(SkPDFObject* obj) {
if (obj && this->addObject(obj)) {
- obj->addResources(this, subs);
+ obj->addResources(this);
}
}
diff --git a/src/pdf/SkPDFTypes.h b/src/pdf/SkPDFTypes.h
index cdfef6cb92..201d62b2ef 100644
--- a/src/pdf/SkPDFTypes.h
+++ b/src/pdf/SkPDFTypes.h
@@ -17,7 +17,6 @@
class SkData;
class SkPDFObjNumMap;
class SkPDFObject;
-class SkPDFSubstituteMap;
class SkStreamAsset;
class SkString;
class SkWStream;
@@ -41,16 +40,14 @@ public:
* @param stream The writable output stream to send the output to.
*/
virtual void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const = 0;
+ const SkPDFObjNumMap& objNumMap) const = 0;
/**
* Adds all transitive dependencies of this object to the
* catalog. Implementations should respect the catalog's object
* substitution map.
*/
- virtual void addResources(SkPDFObjNumMap* catalog,
- const SkPDFSubstituteMap& substitutes) const {}
+ virtual void addResources(SkPDFObjNumMap* catalog) const {}
/**
* Release all resources associated with this SkPDFObject. It is
@@ -121,10 +118,8 @@ public:
/** These two non-virtual methods mirror SkPDFObject's
corresponding virtuals. */
- void emitObject(SkWStream*,
- const SkPDFObjNumMap&,
- const SkPDFSubstituteMap&) const;
- void addResources(SkPDFObjNumMap*, const SkPDFSubstituteMap&) const;
+ void emitObject(SkWStream*, const SkPDFObjNumMap&) const;
+ void addResources(SkPDFObjNumMap*) const;
bool isName() const;
@@ -171,9 +166,8 @@ static_assert(sizeof(SkString) == sizeof(void*), "SkString_size");
class SkPDFAtom final : public SkPDFObject {
public:
void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) final;
- void addResources(SkPDFObjNumMap*, const SkPDFSubstituteMap&) const final;
+ const SkPDFObjNumMap& objNumMap) final;
+ void addResources(SkPDFObjNumMap* const final;
SkPDFAtom(SkPDFUnion&& v) : fValue(std::move(v) {}
private:
@@ -197,10 +191,8 @@ public:
// The SkPDFObject interface.
void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const override;
- void addResources(SkPDFObjNumMap*,
- const SkPDFSubstituteMap&) const override;
+ const SkPDFObjNumMap& objNumMap) const override;
+ void addResources(SkPDFObjNumMap*) const override;
void drop() override;
/** The size of the array.
@@ -247,10 +239,8 @@ public:
// The SkPDFObject interface.
void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const override;
- void addResources(SkPDFObjNumMap*,
- const SkPDFSubstituteMap&) const override;
+ const SkPDFObjNumMap& objNumMap) const override;
+ void addResources(SkPDFObjNumMap*) const override;
void drop() override;
/** The size of the dictionary.
@@ -282,8 +272,7 @@ public:
/** Emit the dictionary, without the "<<" and ">>".
*/
void emitAll(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const;
+ const SkPDFObjNumMap& objNumMap) const;
private:
struct Record {
@@ -312,10 +301,8 @@ public:
~SkPDFSharedStream();
SkPDFDict* dict() { return &fDict; }
void emitObject(SkWStream*,
- const SkPDFObjNumMap&,
- const SkPDFSubstituteMap&) const override;
- void addResources(SkPDFObjNumMap*,
- const SkPDFSubstituteMap&) const override;
+ const SkPDFObjNumMap&) const override;
+ void addResources(SkPDFObjNumMap*) const override;
void drop() override;
private:
@@ -346,9 +333,8 @@ public:
// The SkPDFObject interface.
void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) const override;
- void addResources(SkPDFObjNumMap*, const SkPDFSubstituteMap&) const final;
+ const SkPDFObjNumMap& objNumMap) const override;
+ void addResources(SkPDFObjNumMap*) const final;
void drop() override;
protected:
@@ -383,9 +369,8 @@ public:
/** Add the passed object to the catalog, as well as all its dependencies.
* @param obj The object to add. If nullptr, this is a noop.
- * @param subs Will be passed to obj->addResources().
*/
- void addObjectRecursively(SkPDFObject* obj, const SkPDFSubstituteMap& subs);
+ void addObjectRecursively(SkPDFObject* obj);
/** Get the object number for the passed object.
* @param obj The object of interest.
@@ -401,32 +386,6 @@ private:
////////////////////////////////////////////////////////////////////////////////
-/** \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;
-
- SkPDFObject* operator()(SkPDFObject* o) const {
- return this->getSubstitute(o);
- }
-
-private:
- SkTHashMap<SkPDFObject*, SkPDFObject*> fSubstituteMap;
-};
-
#ifdef SK_PDF_IMAGE_STATS
extern SkAtomic<int> gDrawImageCalls;
extern SkAtomic<int> gJpegImageObjects;
diff --git a/src/utils/SkBitSet.cpp b/src/utils/SkBitSet.cpp
index 0a1ecacf8a..4323ffb6d3 100755
--- a/src/utils/SkBitSet.cpp
+++ b/src/utils/SkBitSet.cpp
@@ -16,11 +16,6 @@ SkBitSet::SkBitSet(int numberOfBits)
fBitData.set(sk_calloc_throw(fDwordCount * sizeof(uint32_t)));
}
-SkBitSet::SkBitSet(const SkBitSet& source)
- : fBitData(nullptr), fDwordCount(0), fBitCount(0) {
- *this = source;
-}
-
SkBitSet::SkBitSet(SkBitSet&& source)
: fBitData(source.fBitData.release())
, fDwordCount(source.fDwordCount)
@@ -29,15 +24,15 @@ SkBitSet::SkBitSet(SkBitSet&& source)
source.fBitCount = 0;
}
-SkBitSet& SkBitSet::operator=(const SkBitSet& rhs) {
- if (this == &rhs) {
- return *this;
+SkBitSet& SkBitSet::operator=(SkBitSet&& rhs) {
+ if (this != &rhs) {
+ fBitCount = rhs.fBitCount;
+ fDwordCount = rhs.fDwordCount;
+ fBitData.reset(); // Free old pointer.
+ fBitData.set(rhs.fBitData.release());
+ rhs.fBitCount = 0;
+ rhs.fDwordCount = 0;
}
- fBitCount = rhs.fBitCount;
- fBitData.reset();
- fDwordCount = rhs.fDwordCount;
- fBitData.set(sk_malloc_throw(fDwordCount * sizeof(uint32_t)));
- memcpy(fBitData.get(), rhs.fBitData.get(), fDwordCount * sizeof(uint32_t));
return *this;
}
diff --git a/src/utils/SkBitSet.h b/src/utils/SkBitSet.h
index 6882752bc0..1e35c9120f 100644
--- a/src/utils/SkBitSet.h
+++ b/src/utils/SkBitSet.h
@@ -17,10 +17,11 @@ public:
/** NumberOfBits must be greater than zero.
*/
explicit SkBitSet(int numberOfBits);
- explicit SkBitSet(const SkBitSet& source);
- explicit SkBitSet(SkBitSet&&);
+ SkBitSet(const SkBitSet&) = delete;
+ SkBitSet(SkBitSet&&);
+ SkBitSet& operator=(const SkBitSet&) = delete;
+ SkBitSet& operator=(SkBitSet&& rhs);
- SkBitSet& operator=(const SkBitSet& rhs);
bool operator==(const SkBitSet& rhs);
bool operator!=(const SkBitSet& rhs);
@@ -39,6 +40,15 @@ public:
*chunk &= ~mask;
}
}
+ void set(int index) { this->setBit(index, true); }
+
+ template<typename T>
+ void setAll(T* array, int len) {
+ static_assert(std::is_integral<T>::value, "T is integral");
+ for (int i = 0; i < len; ++i) {
+ this->set(static_cast<int>(array[i]));
+ }
+ }
/** Test if bit index is set.
*/
@@ -46,6 +56,7 @@ public:
uint32_t mask = 1 << (index & 31);
return SkToBool(*this->internalGet(index) & mask);
}
+ bool has(int index) const { return this->isBitSet(index); }
/** Or bits from source. false is returned if this doesn't have the same
* bit count as source.
@@ -56,6 +67,7 @@ public:
*/
template<typename T>
void exportTo(SkTDArray<T>* array) const {
+ static_assert(std::is_integral<T>::value, "T is integral");
SkASSERT(array);
uint32_t* data = reinterpret_cast<uint32_t*>(fBitData.get());
for (unsigned int i = 0; i < fDwordCount; ++i) {
diff --git a/tests/BitSetTest.cpp b/tests/BitSetTest.cpp
index da023763ba..716f414670 100644
--- a/tests/BitSetTest.cpp
+++ b/tests/BitSetTest.cpp
@@ -70,7 +70,4 @@ DEF_TEST(BitSet, reporter) {
set3.setBit(0, true);
REPORTER_ASSERT(reporter, set2 == set3);
set3.clearAll();
- set3 = set2;
- set2 = set2;
- REPORTER_ASSERT(reporter, set2 == set3);
}
diff --git a/tests/PDFGlyphsToUnicodeTest.cpp b/tests/PDFGlyphsToUnicodeTest.cpp
index b8157caeea..d83ce664bc 100644
--- a/tests/PDFGlyphsToUnicodeTest.cpp
+++ b/tests/PDFGlyphsToUnicodeTest.cpp
@@ -5,12 +5,14 @@
* found in the LICENSE file.
*/
+#include "SkBitSet.h"
#include "SkData.h"
-#include "SkPDFFont.h"
#include "SkPDFMakeToUnicodeCmap.h"
#include "SkStream.h"
#include "Test.h"
+static const int kMaximumGlyphCount = SK_MaxU16 + 1;
+
static bool stream_equals(const SkDynamicMemoryWStream& stream, size_t offset,
const char* buffer, size_t len) {
sk_sp<SkData> data(stream.copyToData());
@@ -26,7 +28,7 @@ static bool stream_equals(const SkDynamicMemoryWStream& stream, size_t offset,
DEF_TEST(ToUnicode, reporter) {
SkTDArray<SkUnichar> glyphToUnicode;
SkTDArray<uint16_t> glyphsInSubset;
- SkPDFGlyphSet subset;
+ SkBitSet subset(kMaximumGlyphCount);
glyphToUnicode.push(0); // 0
glyphToUnicode.push(0); // 1
@@ -65,7 +67,7 @@ DEF_TEST(ToUnicode, reporter) {
glyphToUnicode.push(0x1013);
SkDynamicMemoryWStream buffer;
- subset.set(glyphsInSubset.begin(), glyphsInSubset.count());
+ subset.setAll(glyphsInSubset.begin(), glyphsInSubset.count());
SkPDFAppendCmapSections(glyphToUnicode, &subset, &buffer, true, 0, 0xFFFF);
char expectedResult[] =
@@ -136,7 +138,7 @@ endbfrange\n";
glyphToUnicode.reset();
glyphsInSubset.reset();
- SkPDFGlyphSet subset2;
+ SkBitSet subset2(kMaximumGlyphCount);
// Test mapping:
// I n s t a l
@@ -154,7 +156,7 @@ endbfrange\n";
glyphsInSubset.push(0x57);
SkDynamicMemoryWStream buffer2;
- subset2.set(glyphsInSubset.begin(), glyphsInSubset.count());
+ subset2.setAll(glyphsInSubset.begin(), glyphsInSubset.count());
SkPDFAppendCmapSections(glyphToUnicode, &subset2, &buffer2, true, 0, 0xffff);
char expectedResult2[] =
diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp
index 554f1ee720..1faecb516a 100644
--- a/tests/PDFPrimitivesTest.cpp
+++ b/tests/PDFPrimitivesTest.cpp
@@ -31,21 +31,14 @@
#define DUMMY_TEXT "DCT compessed stream."
-namespace {
-struct Catalog {
- SkPDFSubstituteMap substitutes;
- SkPDFObjNumMap numbers;
-};
-} // namespace
-
template <typename T>
-static SkString emit_to_string(T& obj, Catalog* catPtr = nullptr) {
- Catalog catalog;
+static SkString emit_to_string(T& obj, SkPDFObjNumMap* catPtr = nullptr) {
+ SkPDFObjNumMap catalog;
SkDynamicMemoryWStream buffer;
if (!catPtr) {
catPtr = &catalog;
}
- obj.emitObject(&buffer, catPtr->numbers, catPtr->substitutes);
+ obj.emitObject(&buffer, *catPtr);
SkString tmp(buffer.bytesWritten());
buffer.copyTo(tmp.writable_str());
return tmp;
@@ -148,9 +141,9 @@ static void TestObjectRef(skiatest::Reporter* reporter) {
sk_sp<SkPDFArray> a2(new SkPDFArray);
a2->appendObjRef(a1);
- Catalog catalog;
- catalog.numbers.addObject(a1.get());
- REPORTER_ASSERT(reporter, catalog.numbers.getObjectNumber(a1.get()) == 1);
+ SkPDFObjNumMap catalog;
+ catalog.addObject(a1.get());
+ REPORTER_ASSERT(reporter, catalog.getObjectNumber(a1.get()) == 1);
SkString result = emit_to_string(*a2, &catalog);
// If appendObjRef misbehaves, then the result would
@@ -158,22 +151,6 @@ static void TestObjectRef(skiatest::Reporter* reporter) {
assert_eq(reporter, result, "[1 0 R]");
}
-static void TestSubstitute(skiatest::Reporter* reporter) {
- sk_sp<SkPDFDict> proxy(new SkPDFDict());
- sk_sp<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.get()));
- REPORTER_ASSERT(reporter, proxy.get() != substituteMap.getSubstitute(stub.get()));
-}
-
// This test used to assert without the fix submitted for
// http://code.google.com/p/skia/issues/detail?id=1083.
// SKP files might have invalid glyph ids. This test ensures they are ignored,
@@ -283,9 +260,9 @@ static void TestPDFArray(skiatest::Reporter* reporter) {
"(Another String) [-1]]");
sk_sp<SkPDFArray> referencedArray(new SkPDFArray);
- Catalog catalog;
- catalog.numbers.addObject(referencedArray.get());
- REPORTER_ASSERT(reporter, catalog.numbers.getObjectNumber(
+ SkPDFObjNumMap catalog;
+ catalog.addObject(referencedArray.get());
+ REPORTER_ASSERT(reporter, catalog.getObjectNumber(
referencedArray.get()) == 1);
array->appendObjRef(std::move(referencedArray));
@@ -347,9 +324,9 @@ static void TestPDFDict(skiatest::Reporter* reporter) {
assert_emit_eq(reporter, *dict, "<</Type /DType>>");
sk_sp<SkPDFArray> referencedArray(new SkPDFArray);
- Catalog catalog;
- catalog.numbers.addObject(referencedArray.get());
- REPORTER_ASSERT(reporter, catalog.numbers.getObjectNumber(
+ SkPDFObjNumMap catalog;
+ catalog.addObject(referencedArray.get());
+ REPORTER_ASSERT(reporter, catalog.getObjectNumber(
referencedArray.get()) == 1);
dict->insertObjRef("n1", std::move(referencedArray));
SkString result = emit_to_string(*dict, &catalog);
@@ -363,7 +340,6 @@ DEF_TEST(PDFPrimitives, reporter) {
TestPDFStream(reporter);
TestObjectNumberMap(reporter);
TestObjectRef(reporter);
- TestSubstitute(reporter);
test_issue1083();
}