From 530032a18e373ee673ae96fdbfa1fae6292f8f08 Mon Sep 17 00:00:00 2001 From: halcanary Date: Thu, 18 Aug 2016 14:22:52 -0700 Subject: 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 --- src/pdf/SkPDFBitmap.cpp | 34 ++---- src/pdf/SkPDFDevice.cpp | 11 +- src/pdf/SkPDFDevice.h | 4 - src/pdf/SkPDFDocument.cpp | 33 ++--- src/pdf/SkPDFDocument.h | 9 +- src/pdf/SkPDFFont.cpp | 243 ++++++++++--------------------------- src/pdf/SkPDFFont.h | 73 +++-------- src/pdf/SkPDFGraphicState.cpp | 5 +- src/pdf/SkPDFGraphicState.h | 3 +- src/pdf/SkPDFMakeToUnicodeCmap.cpp | 4 +- src/pdf/SkPDFMakeToUnicodeCmap.h | 4 +- src/pdf/SkPDFMetadata.cpp | 5 +- src/pdf/SkPDFTypes.cpp | 120 +++++++----------- src/pdf/SkPDFTypes.h | 73 +++-------- src/utils/SkBitSet.cpp | 21 ++-- src/utils/SkBitSet.h | 18 ++- 16 files changed, 201 insertions(+), 459 deletions(-) (limited to 'src') 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& 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 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 image, sk_sp 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 SkPDFDevice::makeResourceDict() const { &fonts); } -const SkTDArray& SkPDFDevice::getFontResources() const { - return fFontResources; -} - sk_sp SkPDFDevice::copyMediaBox() const { auto mediaBox = sk_make_sp(); 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 makeResourceDict() const; - /** Get the fonts used on this device. - */ - const SkTDArray& 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& 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 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("Catalog"); @@ -442,21 +442,12 @@ bool SkPDFDocument::onClose(SkWStream* stream) { } // Build font subsetting info before calling addObjectRecursively(). - for (const auto& entry : fGlyphUsage) { - sk_sp 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 SkPDFMakeDocument(SkWStream* stream, // keep similar functionality together. struct SkPDFObjectSerializer : SkNoncopyable { SkPDFObjNumMap fObjNumMap; - SkPDFSubstituteMap fSubstituteMap; SkTDArray fOffsets; sk_sp 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&); SkPDFCanon* canon() { return &fCanon; } - SkPDFGlyphSetMap* getGlyphUsage() { return &fGlyphUsage; } + void registerFont(SkPDFFont* f) { fFonts.add(f); } private: SkPDFObjectSerializer fObjectSerializer; SkPDFCanon fCanon; - SkPDFGlyphSetMap fGlyphUsage; SkTArray> fPages; + SkTHashSet fFonts; sk_sp fDests; sk_sp fPageDevice; sk_sp 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 typeface, - SkAdvancedTypefaceMetrics::FontType type); +struct SkPDFType0Font final : public SkPDFFont { + SkPDFType0Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&); virtual ~SkPDFType0Font(); - sk_sp 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 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 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 getFontSubset(SkPDFCanon*, const SkPDFGlyphSet*) override; + void getFontSubset(SkPDFCanon*) override; }; /////////////////////////////////////////////////////////////////////////////// @@ -143,58 +120,6 @@ static sk_sp 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* 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(glyphCount - 1, + 254 + (int)firstGlyph)); + } + SkPDFFont::Info info = {std::move(typeface), firstNonZeroGlyph, lastGlyph, type}; sk_sp font; switch (type) { case SkAdvancedTypefaceMetrics::kType1CID_Font: case SkAdvancedTypefaceMetrics::kTrueType_Font: SkASSERT(multibyte); - font = sk_make_sp(metrics, - std::move(typeface), - type); + font = sk_make_sp(std::move(info), metrics); break; case SkAdvancedTypefaceMetrics::kType1_Font: SkASSERT(!multibyte); - font = sk_make_sp(metrics, - std::move(typeface), - glyphID, - canon); + font = sk_make_sp(std::move(info), metrics, canon); break; default: SkASSERT(!multibyte); // Type3 is our fallback font. - font = sk_make_sp(metrics, - std::move(typeface), - type, - glyphID); + font = sk_make_sp(std::move(info), metrics); break; } canon->fFontMap.set(fontID, SkRef(font.get())); return font.release(); // TODO(halcanary) return sk_sp. } -sk_sp SkPDFFont::getFontSubset(SkPDFCanon*, const SkPDFGlyphSet*) { - return nullptr; // Default: no support. -} - -SkPDFFont::SkPDFFont(sk_sp 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 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 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( - *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 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 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 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 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(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 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 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 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 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 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 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("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* 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 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 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 typeface, - SkAdvancedTypefaceMetrics::FontType fontType); + struct Info { + sk_sp 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 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 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 SkPDFGraphicState::MakeNoSmaskGraphicState() { void SkPDFGraphicState::emitObject( SkWStream* stream, - const SkPDFObjNumMap& objNumMap, - const SkPDFSubstituteMap& substitutes) const { + const SkPDFObjNumMap& objNumMap) const { auto dict = sk_make_sp("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, // 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& glyphToUnicode, - const SkPDFGlyphSet* subset, + const SkBitSet* subset, SkDynamicMemoryWStream* cmap, bool multiByteGlyphs, SkGlyphID firstGlyphID, @@ -212,7 +212,7 @@ void SkPDFAppendCmapSections(const SkTDArray& glyphToUnicode, sk_sp SkPDFMakeToUnicodeCmap( const SkTDArray& 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 SkPDFMakeToUnicodeCmap( const SkTDArray& glyphToUnicode, - const SkPDFGlyphSet* subset, + const SkBitSet* subset, bool multiByteGlyphs, SkGlyphID firstGlyphID, SkGlyphID lastGlyphID); // Exposed for unit testing. void SkPDFAppendCmapSections(const SkTDArray& 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 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 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 dup(fCompressedData->duplicate()); SkASSERT(dup); @@ -594,25 +576,6 @@ void SkPDFStream::setData(std::unique_ptr 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 fSubstituteMap; -}; - #ifdef SK_PDF_IMAGE_STATS extern SkAtomic gDrawImageCalls; extern SkAtomic 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 + void setAll(T* array, int len) { + static_assert(std::is_integral::value, "T is integral"); + for (int i = 0; i < len; ++i) { + this->set(static_cast(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 void exportTo(SkTDArray* array) const { + static_assert(std::is_integral::value, "T is integral"); SkASSERT(array); uint32_t* data = reinterpret_cast(fBitData.get()); for (unsigned int i = 0; i < fDwordCount; ++i) { -- cgit v1.2.3