diff options
-rw-r--r-- | bench/PDFBench.cpp | 5 | ||||
-rw-r--r-- | src/pdf/SkPDFBitmap.cpp | 34 | ||||
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 11 | ||||
-rw-r--r-- | src/pdf/SkPDFDevice.h | 4 | ||||
-rw-r--r-- | src/pdf/SkPDFDocument.cpp | 33 | ||||
-rw-r--r-- | src/pdf/SkPDFDocument.h | 9 | ||||
-rw-r--r-- | src/pdf/SkPDFFont.cpp | 243 | ||||
-rw-r--r-- | src/pdf/SkPDFFont.h | 73 | ||||
-rw-r--r-- | src/pdf/SkPDFGraphicState.cpp | 5 | ||||
-rw-r--r-- | src/pdf/SkPDFGraphicState.h | 3 | ||||
-rw-r--r-- | src/pdf/SkPDFMakeToUnicodeCmap.cpp | 4 | ||||
-rw-r--r-- | src/pdf/SkPDFMakeToUnicodeCmap.h | 4 | ||||
-rw-r--r-- | src/pdf/SkPDFMetadata.cpp | 5 | ||||
-rw-r--r-- | src/pdf/SkPDFTypes.cpp | 120 | ||||
-rw-r--r-- | src/pdf/SkPDFTypes.h | 73 | ||||
-rwxr-xr-x | src/utils/SkBitSet.cpp | 21 | ||||
-rw-r--r-- | src/utils/SkBitSet.h | 18 | ||||
-rw-r--r-- | tests/BitSetTest.cpp | 3 | ||||
-rw-r--r-- | tests/PDFGlyphsToUnicodeTest.cpp | 12 | ||||
-rw-r--r-- | tests/PDFPrimitivesTest.cpp | 48 |
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(); } |