From 671fec43e51533b9969502c072cd29d88ebef6ea Mon Sep 17 00:00:00 2001 From: robertphillips Date: Wed, 17 Aug 2016 16:28:28 -0700 Subject: [PATCH] Revert of SkPDF: cache metrics once. (patchset #4 id:60001 of https://codereview.chromium.org/2253993002/ ) Reason for revert: because Original issue's description: > SkPDF: cache metrics once. > > Motivation: drawText can look up unicode mapping at draw time to see > if ActualText should be used after crrev.com/2084533004 lands. > > For each SkTypeface, only call getAdvancedTypefaceMetrics() once per > document. Cache the result in the SkPDFCanon, indexed by SkFontID. > Also cache PDF FontDescriptors in the canon, also indexed by SkFontID > (Type1 fonts only). > > Simplify PDF font lookup, map SkFontID+SkGlyphID into a uint64_t. Map > that uint64_t to SkPDFFonts. Remove SkPDFCanon::findFont(), > SkPDFCanon::addFont(), SkPDFFont::IsMatch(), and enum SkPDFFont::Match. > > SkPDFFont no longer holds on to ref of SkAdvancedTypefaceMetrics. > Instead, SkPDFFont::GetFontResource() and SkPDFFont::getFontSubset() > get metrics from canon. > > SkPDFFont multybite bool is now a function of type. > GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2253993002 > > Committed: https://skia.googlesource.com/skia/+/0a61270f4ba85d10659fb63a86817b435ec04c94 TBR=bungeman@google.com,halcanary@google.com # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true Review-Url: https://codereview.chromium.org/2251813006 --- src/pdf/SkPDFCanon.cpp | 53 +++-- src/pdf/SkPDFCanon.h | 22 +- src/pdf/SkPDFDocument.cpp | 42 +++- src/pdf/SkPDFFont.cpp | 427 +++++++++++++++++++++++--------------- src/pdf/SkPDFFont.h | 74 +++++-- 5 files changed, 415 insertions(+), 203 deletions(-) diff --git a/src/pdf/SkPDFCanon.cpp b/src/pdf/SkPDFCanon.cpp index 4e182aecfc..3dcf4e9f0f 100644 --- a/src/pdf/SkPDFCanon.cpp +++ b/src/pdf/SkPDFCanon.cpp @@ -12,25 +12,52 @@ //////////////////////////////////////////////////////////////////////////////// -namespace { -template struct UnrefValue { - void operator()(K, V** v) { (*v)->unref(); } -}; -} +void SkPDFCanon::reset() { + for (int i = 0; i < fFontRecords.count(); ++i) { + fFontRecords[i].fFont->unref(); + } + fFontRecords.reset(); + + fFunctionShaderRecords.reset(); + fAlphaShaderRecords.reset(); + fImageShaderRecords.reset(); -SkPDFCanon::~SkPDFCanon() { // TODO(halcanary): make SkTHashSet work nicely with sk_sp<>, // or use std::unordered_set<> fGraphicStateRecords.foreach ([](WrapGS w) { w.fPtr->unref(); }); - fPDFBitmapMap.foreach(UnrefValue()); - fTypefaceMetrics.foreach(UnrefValue()); - fFontDescriptors.foreach(UnrefValue()); - fFontMap.foreach(UnrefValue()); + fGraphicStateRecords.reset(); + + fPDFBitmapMap.foreach([](SkBitmapKey, SkPDFObject** p) { (*p)->unref(); }); + fPDFBitmapMap.reset(); } -void SkPDFCanon::reset() { - this->~SkPDFCanon(); - new (this)SkPDFCanon; +//////////////////////////////////////////////////////////////////////////////// + +SkPDFFont* SkPDFCanon::findFont(uint32_t fontID, + uint16_t glyphID, + SkPDFFont** relatedFontPtr) const { + SkASSERT(relatedFontPtr); + + SkPDFFont* relatedFont = nullptr; + for (int i = 0; i < fFontRecords.count(); ++i) { + SkPDFFont::Match match = SkPDFFont::IsMatch( + fFontRecords[i].fFont, fFontRecords[i].fFontID, + fFontRecords[i].fGlyphID, fontID, glyphID); + if (SkPDFFont::kExact_Match == match) { + return fFontRecords[i].fFont; + } else if (!relatedFont && SkPDFFont::kRelated_Match == match) { + relatedFont = fFontRecords[i].fFont; + } + } + *relatedFontPtr = relatedFont; // May still be nullptr. + return nullptr; +} + +void SkPDFCanon::addFont(SkPDFFont* font, uint32_t fontID, uint16_t fGlyphID) { + SkPDFCanon::FontRec* rec = fFontRecords.push(); + rec->fFont = SkRef(font); + rec->fFontID = fontID; + rec->fGlyphID = fGlyphID; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/pdf/SkPDFCanon.h b/src/pdf/SkPDFCanon.h index 2da9e52f70..a0241e308f 100644 --- a/src/pdf/SkPDFCanon.h +++ b/src/pdf/SkPDFCanon.h @@ -14,7 +14,6 @@ #include "SkTHash.h" #include "SkBitmapKey.h" -class SkAdvancedTypefaceMetrics; class SkPDFFont; /** @@ -36,11 +35,19 @@ class SkPDFFont; */ class SkPDFCanon : SkNoncopyable { public: - ~SkPDFCanon(); + ~SkPDFCanon() { this->reset(); } // reset to original setting, unrefs all objects. void reset(); + // Returns exact match if there is one. If not, it returns nullptr. + // If there is no exact match, but there is a related font, we + // still return nullptr, but also set *relatedFont. + SkPDFFont* findFont(uint32_t fontID, + uint16_t glyphID, + SkPDFFont** relatedFont) const; + void addFont(SkPDFFont* font, uint32_t fontID, uint16_t fGlyphID); + sk_sp findFunctionShader(const SkPDFShader::State&) const; void addFunctionShader(sk_sp, SkPDFShader::State); @@ -56,9 +63,7 @@ public: sk_sp findPDFBitmap(SkBitmapKey key) const; void addPDFBitmap(SkBitmapKey key, sk_sp); - SkTHashMap fTypefaceMetrics; - SkTHashMap fFontDescriptors; - SkTHashMap fFontMap; + SkTHashMap fCanEmbedTypeface; SkPixelSerializer* getPixelSerializer() const { return fPixelSerializer.get(); } void setPixelSerializer(sk_sp ps) { @@ -70,6 +75,13 @@ public: sk_sp makeRangeObject(); private: + struct FontRec { + SkPDFFont* fFont; + uint32_t fFontID; + uint16_t fGlyphID; + }; + SkTDArray fFontRecords; + struct ShaderRec { SkPDFShader::State fShaderState; sk_sp fShaderObject; diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp index 4f044c8771..4a577fcff3 100644 --- a/src/pdf/SkPDFDocument.cpp +++ b/src/pdf/SkPDFDocument.cpp @@ -168,6 +168,46 @@ static sk_sp generate_page_tree(SkTArray>* pages) { return std::move(curNodes[0]); } +#if 0 +// TODO(halcanary): expose notEmbeddableCount in SkDocument +void GetCountOfFontTypes( + const SkTDArray& pageDevices, + int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1], + int* notSubsettableCount, + int* notEmbeddableCount) { + sk_bzero(counts, sizeof(int) * + (SkAdvancedTypefaceMetrics::kOther_Font + 1)); + SkTDArray seenFonts; + int notSubsettable = 0; + int notEmbeddable = 0; + + for (int pageNumber = 0; pageNumber < pageDevices.count(); pageNumber++) { + const SkTDArray& fontResources = + pageDevices[pageNumber]->getFontResources(); + for (int font = 0; font < fontResources.count(); font++) { + SkFontID fontID = fontResources[font]->typeface()->uniqueID(); + if (seenFonts.find(fontID) == -1) { + counts[fontResources[font]->getType()]++; + seenFonts.push(fontID); + if (!fontResources[font]->canSubset()) { + notSubsettable++; + } + if (!fontResources[font]->canEmbed()) { + notEmbeddable++; + } + } + } + } + if (notSubsettableCount) { + *notSubsettableCount = notSubsettable; + + } + if (notEmbeddableCount) { + *notEmbeddableCount = notEmbeddable; + } +} +#endif + template static T* clone(const T* o) { return o ? new T(*o) : nullptr; } //////////////////////////////////////////////////////////////////////////////// @@ -444,7 +484,7 @@ 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); + entry.fFont->getFontSubset(&entry.fGlyphSet); if (subsetFont) { fObjectSerializer.fSubstituteMap.setSubstitute( entry.fFont, subsetFont.get()); diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp index 7afdff6aa8..4d114f0e1a 100644 --- a/src/pdf/SkPDFFont.cpp +++ b/src/pdf/SkPDFFont.cpp @@ -39,11 +39,11 @@ static const int kPdfSymbolic = 4; class SkPDFType0Font final : public SkPDFFont { public: - SkPDFType0Font(const SkAdvancedTypefaceMetrics* info, + SkPDFType0Font(sk_sp info, sk_sp typeface, SkAdvancedTypefaceMetrics::FontType type); virtual ~SkPDFType0Font(); - sk_sp getFontSubset(SkPDFCanon*, const SkPDFGlyphSet*) override; + sk_sp getFontSubset(const SkPDFGlyphSet* usage) override; #ifdef SK_DEBUG void emitObject(SkWStream*, const SkPDFObjNumMap&, @@ -54,23 +54,26 @@ private: #ifdef SK_DEBUG bool fPopulated; #endif - bool populate(const SkPDFGlyphSet* subset, - const SkAdvancedTypefaceMetrics& metrics); + bool populate(const SkPDFGlyphSet* subset); typedef SkPDFDict INHERITED; }; class SkPDFType1Font final : public SkPDFFont { public: - SkPDFType1Font(const SkAdvancedTypefaceMetrics* info, + SkPDFType1Font(sk_sp info, sk_sp typeface, uint16_t glyphID, - SkPDFCanon* canon); - virtual ~SkPDFType1Font() {} + sk_sp relatedFontDescriptor); + virtual ~SkPDFType1Font(); + +private: + bool populate(int16_t glyphID); + bool addFontDescriptor(int16_t defaultWidth); }; class SkPDFType3Font final : public SkPDFFont { public: - SkPDFType3Font(const SkAdvancedTypefaceMetrics* info, + SkPDFType3Font(sk_sp info, sk_sp typeface, SkAdvancedTypefaceMetrics::FontType fontType, uint16_t glyphID); @@ -80,7 +83,7 @@ public: const SkPDFSubstituteMap&) const override { SkDEBUGFAIL("should call getFontSubset!"); } - sk_sp getFontSubset(SkPDFCanon*, const SkPDFGlyphSet*) override; + sk_sp getFontSubset(const SkPDFGlyphSet* usage) override; }; /////////////////////////////////////////////////////////////////////////////// @@ -213,14 +216,26 @@ SkPDFGlyphSet* SkPDFGlyphSetMap::getGlyphSetForFont(SkPDFFont* font) { SkPDFFont::~SkPDFFont() {} -static bool can_embed(const SkAdvancedTypefaceMetrics* metrics) { - return !metrics || - !SkToBool(metrics->fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag); +bool SkPDFFont::canEmbed() const { + if (!fFontInfo.get()) { + SkASSERT(fFontType == SkAdvancedTypefaceMetrics::kOther_Font); + return true; + } + return (fFontInfo->fFlags & + SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag) == 0; } -static bool can_subset(const SkAdvancedTypefaceMetrics* metrics) { - return !metrics || - !SkToBool(metrics->fFlags & SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag); +bool SkPDFFont::canSubset() const { + if (!fFontInfo.get()) { + SkASSERT(fFontType == SkAdvancedTypefaceMetrics::kOther_Font); + return true; + } + return (fFontInfo->fFlags & + SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag) == 0; +} + +bool SkPDFFont::hasGlyph(uint16_t id) { + return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0; } int SkPDFFont::glyphsToPDFFontEncoding(SkGlyphID* glyphIDs, int numGlyphs) const { @@ -256,105 +271,125 @@ int SkPDFFont::glyphsToPDFFontEncodingCount(const SkGlyphID* glyphIDs, return numGlyphs; } - -const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(SkTypeface* typeface, - SkPDFCanon* canon) { - SkFontID id = SkTypeface::UniqueID(typeface); - if (SkAdvancedTypefaceMetrics** ptr = canon->fTypefaceMetrics.find(id)) { - return *ptr; - } - sk_sp defaultFace; - if (!typeface) { - defaultFace = SkTypeface::MakeDefault(); - typeface = defaultFace.get(); - } - sk_sp metrics( - typeface->getAdvancedTypefaceMetrics( - SkTypeface::kGlyphNames_PerGlyphInfo | SkTypeface::kToUnicode_PerGlyphInfo, - nullptr, 0)); - return *canon->fTypefaceMetrics.set(id, metrics.release()); -} - -SkAdvancedTypefaceMetrics::FontType font_type(const SkAdvancedTypefaceMetrics* metrics) { - if (!metrics || SkToBool(metrics->fFlags & - SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) { - // force Type3 fallback. - return SkAdvancedTypefaceMetrics::kOther_Font; - } - return metrics->fType; -} - -static SkGlyphID first_glyph_for_single_byte_encoding(SkGlyphID gid) { - return gid != 0 ? gid - (gid - 1) % 255 : 1; -} - +// static SkPDFFont* SkPDFFont::GetFontResource(SkPDFCanon* canon, SkTypeface* face, - SkGlyphID glyphID) { + uint16_t glyphID) { SkASSERT(canon); - const SkAdvancedTypefaceMetrics* fontMetrics = SkPDFFont::GetMetrics(face, canon); - SkAdvancedTypefaceMetrics::FontType type = font_type(fontMetrics); - bool multibyte = SkPDFFont::IsMultiByte(type); - SkGlyphID firstGlyph = multibyte ? 0 : first_glyph_for_single_byte_encoding(glyphID); - uint64_t fontID = (SkTypeface::UniqueID(face) << 16) | firstGlyph; - - if (SkPDFFont** found = canon->fFontMap.find(fontID)) { - SkASSERT(multibyte == (*found)->multiByteGlyphs()); - return SkRef(*found); + const uint32_t fontID = SkTypeface::UniqueID(face); + SkPDFFont* relatedFont; + if (SkPDFFont* pdfFont = canon->findFont(fontID, glyphID, &relatedFont)) { + return SkRef(pdfFont); } - sk_sp typeface(face ? sk_ref_sp(face) : SkTypeface::MakeDefault()); SkASSERT(typeface); int glyphCount = typeface->countGlyphs(); - // Validate typeface + glyph; if (glyphCount < 1 || // typeface lacks even a NOTDEF glyph. glyphCount > 1 + SK_MaxU16 || // invalid glyphCount glyphID >= glyphCount) { // invalid glyph return nullptr; } + sk_sp fontMetrics; + sk_sp relatedFontDescriptor; + if (relatedFont) { + fontMetrics = relatedFont->refFontInfo(); + relatedFontDescriptor = relatedFont->refFontDescriptor(); + + // This only is to catch callers who pass invalid glyph ids. + // If glyph id is invalid, then we will create duplicate entries + // for TrueType fonts. + SkDEBUGCODE(SkAdvancedTypefaceMetrics::FontType fontType = relatedFont->getType()); + SkASSERT(fontType != SkAdvancedTypefaceMetrics::kType1CID_Font); + SkASSERT(fontType != SkAdvancedTypefaceMetrics::kTrueType_Font); + } else { + SkTypeface::PerGlyphInfo info = SkTypeface::kGlyphNames_PerGlyphInfo | + SkTypeface::kToUnicode_PerGlyphInfo; + fontMetrics.reset( + typeface->getAdvancedTypefaceMetrics(info, nullptr, 0)); + } + + SkAdvancedTypefaceMetrics::FontType type = + fontMetrics ? fontMetrics->fType : SkAdvancedTypefaceMetrics::kOther_Font; + if (fontMetrics && + SkToBool(fontMetrics->fFlags & + SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) { + // force Type3 fallback. + type = SkAdvancedTypefaceMetrics::kOther_Font; + } sk_sp font; switch (type) { case SkAdvancedTypefaceMetrics::kType1CID_Font: case SkAdvancedTypefaceMetrics::kTrueType_Font: - SkASSERT(multibyte); + SkASSERT(relatedFontDescriptor == nullptr); SkASSERT(fontMetrics != nullptr); - font = sk_make_sp(fontMetrics, + font = sk_make_sp(std::move(fontMetrics), std::move(typeface), type); break; case SkAdvancedTypefaceMetrics::kType1_Font: - SkASSERT(!multibyte); SkASSERT(fontMetrics != nullptr); - font = sk_make_sp(fontMetrics, + font = sk_make_sp(std::move(fontMetrics), std::move(typeface), glyphID, - canon); + std::move(relatedFontDescriptor)); break; - default: - SkASSERT(!multibyte); - font = sk_make_sp(fontMetrics, + case SkAdvancedTypefaceMetrics::kCFF_Font: + SkASSERT(fontMetrics != nullptr); + // fallthrough + case SkAdvancedTypefaceMetrics::kOther_Font: + font = sk_make_sp(std::move(fontMetrics), std::move(typeface), type, glyphID); break; + default: + SkDEBUGFAIL("invalid SkAdvancedTypefaceMetrics::FontType"); + return nullptr; } - canon->fFontMap.set(fontID, SkRef(font.get())); + // When firstGlyphID==0, SkFont::IsMatch() matches all glyphs in font. + SkGlyphID firstGlyphID = font->multiByteGlyphs() ? 0 : font->fFirstGlyphID; + // TODO(halcanary) Make SkCanon::addFont take sk_sp. + canon->addFont(font.get(), fontID, firstGlyphID); return font.release(); // TODO(halcanary) return sk_sp. } -sk_sp SkPDFFont::getFontSubset(SkPDFCanon*, const SkPDFGlyphSet*) { +sk_sp SkPDFFont::getFontSubset(const SkPDFGlyphSet*) { return nullptr; // Default: no support. } -SkPDFFont::SkPDFFont(sk_sp typeface, - SkAdvancedTypefaceMetrics::FontType fontType) +// TODO: take a sk_sp and sk_sp +SkPDFFont::SkPDFFont(sk_sp info, + sk_sp typeface, + sk_sp relatedFontDescriptor, + SkAdvancedTypefaceMetrics::FontType fontType, + bool multiByteGlyphs) : SkPDFDict("Font") , fTypeface(std::move(typeface)) + , fFontInfo(std::move(info)) + , fDescriptor(std::move(relatedFontDescriptor)) , fFirstGlyphID(1) - , fFontType(fontType) { + , fFontType(fontType) + , fMultiByteGlyphs(multiByteGlyphs) { SkASSERT(fTypeface); - fLastGlyphID = SkToU16(fTypeface->countGlyphs() - 1); + fLastGlyphID = fFontInfo ? fFontInfo->fLastGlyphID : 0; + if (0 == fLastGlyphID) { + fLastGlyphID = SkToU16(fTypeface->countGlyphs() - 1); + } +} + +void SkPDFFont::setFontInfo(sk_sp info) { + if (info) { + fFontInfo = std::move(info); + } +} + +void SkPDFFont::setLastGlyphID(uint16_t glyphID) { + fLastGlyphID = glyphID; +} + +void SkPDFFont::setFontDescriptor(sk_sp descriptor) { + fDescriptor = std::move(descriptor); } static void add_common_font_descriptor_entries(SkPDFDict* descriptor, @@ -380,41 +415,48 @@ static void add_common_font_descriptor_entries(SkPDFDict* descriptor, } } -void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(SkGlyphID glyphID) { +void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(uint16_t glyphID) { // Single byte glyph encoding supports a max of 255 glyphs. - fFirstGlyphID = first_glyph_for_single_byte_encoding(glyphID); + fFirstGlyphID = glyphID - (glyphID - 1) % 255; if (fLastGlyphID > fFirstGlyphID + 255 - 1) { fLastGlyphID = fFirstGlyphID + 255 - 1; } } +void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) { + if (fFontInfo == nullptr || fFontInfo->fGlyphToUnicode.begin() == nullptr) { + return; + } + this->insertObjRef("ToUnicode", + SkPDFMakeToUnicodeCmap(fFontInfo->fGlyphToUnicode, + subset, + multiByteGlyphs(), + firstGlyphID(), + lastGlyphID())); +} + /////////////////////////////////////////////////////////////////////////////// // class SkPDFType0Font /////////////////////////////////////////////////////////////////////////////// -SkPDFType0Font::SkPDFType0Font(const SkAdvancedTypefaceMetrics* info, +SkPDFType0Font::SkPDFType0Font(sk_sp info, sk_sp typeface, SkAdvancedTypefaceMetrics::FontType fontType) - : SkPDFFont(std::move(typeface), fontType) { + : SkPDFFont(std::move(info), std::move(typeface), nullptr, fontType, true) { SkDEBUGCODE(fPopulated = false); - if (!can_subset(info)) { - this->populate(nullptr, *info); + if (!canSubset()) { + this->populate(nullptr); } } SkPDFType0Font::~SkPDFType0Font() {} -sk_sp SkPDFType0Font::getFontSubset(SkPDFCanon* canon, - const SkPDFGlyphSet* subset) { - const SkAdvancedTypefaceMetrics* metrics = - SkPDFFont::GetMetrics(this->typeface(), canon); - SkASSERT(metrics); - if (!can_subset(metrics)) { +sk_sp SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) { + if (!canSubset()) { return nullptr; } - auto newSubset = sk_make_sp( - metrics, this->refTypeface(), this->getType()); - newSubset->populate(subset, *metrics); + auto newSubset = sk_make_sp(refFontInfo(), refTypeface(), getType()); + newSubset->populate(subset); return newSubset; } @@ -480,9 +522,10 @@ static sk_sp get_subset_font_stream( } #endif // SK_SFNTLY_SUBSETTER -bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset, - const SkAdvancedTypefaceMetrics& metrics) { - SkASSERT(can_embed(&metrics)); +bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) { + SkASSERT(this->canEmbed()); + SkASSERT(this->getFontInfo()); + const SkAdvancedTypefaceMetrics& metrics = *(this->getFontInfo()); SkAdvancedTypefaceMetrics::FontType type = this->getType(); SkTypeface* face = this->typeface(); SkASSERT(face); @@ -505,7 +548,7 @@ bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset, } #ifdef SK_SFNTLY_SUBSETTER - if (can_subset(&metrics) && subset) { + if (this->canSubset() && subset) { // Generate glyph id array. in format needed by sfntly SkTDArray glyphIDs; if (subset) { @@ -564,7 +607,7 @@ bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset, sysInfo->insertInt("Supplement", 0); newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo)); - uint16_t emSize = metrics.fEmSize; + uint16_t emSize = this->getFontInfo()->fEmSize; int16_t defaultWidth = 0; const SkBitSet* bitSet = subset ? &subset->bitSet() : nullptr; { @@ -586,77 +629,102 @@ bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset, auto descendantFonts = sk_make_sp(); descendantFonts->appendObjRef(std::move(newCIDFont)); this->insertObject("DescendantFonts", std::move(descendantFonts)); - - if (metrics.fGlyphToUnicode.count() > 0) { - this->insertObjRef("ToUnicode", - SkPDFMakeToUnicodeCmap(metrics.fGlyphToUnicode, - subset, - multiByteGlyphs(), - firstGlyphID(), - lastGlyphID())); - } + this->populateToUnicodeTable(subset); SkDEBUGCODE(fPopulated = true); return true; } +sk_sp SkPDFFont::GetFontMetricsWithToUnicode( + SkTypeface* typeface, uint32_t* glyphs, uint32_t glyphsCount) { + return sk_sp( + typeface->getAdvancedTypefaceMetrics( + SkTypeface::kToUnicode_PerGlyphInfo, glyphs, glyphsCount)); +} + + /////////////////////////////////////////////////////////////////////////////// // class SkPDFType1Font /////////////////////////////////////////////////////////////////////////////// -static sk_sp make_type1_font_descriptor( - SkTypeface* typeface, - const SkAdvancedTypefaceMetrics* info) { +SkPDFType1Font::SkPDFType1Font(sk_sp info, + sk_sp typeface, + uint16_t glyphID, + sk_sp relatedFontDescriptor) + : SkPDFFont(std::move(info), + std::move(typeface), + std::move(relatedFontDescriptor), + SkAdvancedTypefaceMetrics::kType1_Font, + /* multiByteGlyphs = */ false) { + this->populate(glyphID); // TODO(halcanary): subset this. +} + +SkPDFType1Font::~SkPDFType1Font() {} + +bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) { + if (sk_sp descriptor = this->refFontDescriptor()) { + this->insertObjRef("FontDescriptor", std::move(descriptor)); + return true; + } + auto descriptor = sk_make_sp("FontDescriptor"); - SkASSERT(info); - add_common_font_descriptor_entries(descriptor.get(), *info, 0); + setFontDescriptor(descriptor); int ttcIndex; size_t header SK_INIT_TO_AVOID_WARNING; size_t data SK_INIT_TO_AVOID_WARNING; size_t trailer SK_INIT_TO_AVOID_WARNING; - std::unique_ptr rawFontData(typeface->openStream(&ttcIndex)); + std::unique_ptr rawFontData(typeface()->openStream(&ttcIndex)); sk_sp fontData = SkPDFConvertType1FontStream(std::move(rawFontData), &header, &data, &trailer); - if (fontData && can_embed(info)) { - auto fontStream = sk_make_sp(std::move(fontData)); - fontStream->dict()->insertInt("Length1", header); - fontStream->dict()->insertInt("Length2", data); - fontStream->dict()->insertInt("Length3", trailer); - descriptor->insertObjRef("FontFile", std::move(fontStream)); + if (!fontData) { + return false; } - return descriptor; + SkASSERT(this->canEmbed()); + auto fontStream = sk_make_sp(std::move(fontData)); + fontStream->dict()->insertInt("Length1", header); + fontStream->dict()->insertInt("Length2", data); + fontStream->dict()->insertInt("Length3", trailer); + descriptor->insertObjRef("FontFile", std::move(fontStream)); + + SkASSERT(this->getFontInfo()); + add_common_font_descriptor_entries(descriptor.get(), + *this->getFontInfo(), + defaultWidth); + this->insertObjRef("FontDescriptor", std::move(descriptor)); + return true; } -static void populate_type_1_font(SkPDFDict* font, - const SkAdvancedTypefaceMetrics* info, - SkTypeface* typeface, - SkGlyphID firstGlyphID, - SkGlyphID lastGlyphID) { - SkASSERT(info); - font->insertName("Subtype", "Type1"); - font->insertName("BaseFont", info->fFontName); +bool SkPDFType1Font::populate(int16_t glyphID) { + this->insertName("Subtype", "Type1"); + this->insertName("BaseFont", this->getFontInfo()->fFontName); + adjustGlyphRangeForSingleByteEncoding(glyphID); + SkGlyphID firstGlyphID = this->firstGlyphID(); + SkGlyphID lastGlyphID = this->lastGlyphID(); // glyphCount not including glyph 0 unsigned glyphCount = 1 + lastGlyphID - firstGlyphID; SkASSERT(glyphCount > 0 && glyphCount <= 255); - font->insertInt("FirstChar", (size_t)0); - font->insertInt("LastChar", (size_t)glyphCount); + this->insertInt("FirstChar", (size_t)0); + this->insertInt("LastChar", (size_t)glyphCount); { - SkAutoGlyphCache glyphCache = vector_cache(typeface); + SkAutoGlyphCache glyphCache = vector_cache(this->typeface()); auto widths = sk_make_sp(); SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX; - const uint16_t emSize = info->fEmSize; + const uint16_t emSize = this->getFontInfo()->fEmSize; widths->appendScalar(from_font_units(advance, emSize)); for (unsigned gID = firstGlyphID; gID <= lastGlyphID; gID++) { advance = glyphCache->getGlyphIDAdvance(gID).fAdvanceX; widths->appendScalar(from_font_units(advance, emSize)); } - font->insertObject("Widths", std::move(widths)); + this->insertObject("Widths", std::move(widths)); + } + if (!addFontDescriptor(0)) { + return false; } auto encDiffs = sk_make_sp(); encDiffs->reserve(lastGlyphID - firstGlyphID + 3); encDiffs->appendInt(0); - const SkTArray& glyphNames = info->fGlyphNames; + const SkTArray& glyphNames = this->getFontInfo()->fGlyphNames; SkASSERT(glyphNames.count() > lastGlyphID); encDiffs->appendName(glyphNames[0].c_str()); const SkString unknown("UNKNOWN"); @@ -668,28 +736,8 @@ static void populate_type_1_font(SkPDFDict* font, auto encoding = sk_make_sp("Encoding"); encoding->insertObject("Differences", std::move(encDiffs)); - font->insertObject("Encoding", std::move(encoding)); -} - -SkPDFType1Font::SkPDFType1Font(const SkAdvancedTypefaceMetrics* info, - sk_sp typeface, - uint16_t glyphID, - SkPDFCanon* canon) - : SkPDFFont(std::move(typeface), SkAdvancedTypefaceMetrics::kType1_Font) -{ - 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); - 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(), - this->firstGlyphID(), this->lastGlyphID()); + this->insertObject("Encoding", std::move(encoding)); + return true; } /////////////////////////////////////////////////////////////////////////////// @@ -726,8 +774,7 @@ private: }; } -static void add_type3_font_info(SkPDFCanon* canon, - SkPDFDict* font, +static void add_type3_font_info(SkPDFDict* font, SkTypeface* typeface, SkScalar emSize, const SkPDFGlyphSet* subset, @@ -815,8 +862,21 @@ static void add_type3_font_info(SkPDFCanon* canon, fontBBox->appendInt(bbox.top()); font->insertObject("FontBBox", std::move(fontBBox)); font->insertName("CIDToGIDMap", "Identity"); - const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon); - if (metrics /* && metrics->fGlyphToUnicode.count() > 0 */) { + sk_sp metrics; + if (subset) { + SkTDArray subsetList; + for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) { + if (gID == 0 || subset->has(gID)) { // Always include glyph 0. + subsetList.push(0); + } + } + subset->exportTo(&subsetList); + metrics = SkPDFFont::GetFontMetricsWithToUnicode(typeface, subsetList.begin(), + subsetList.count()); + } else { + metrics = SkPDFFont::GetFontMetricsWithToUnicode(typeface, nullptr, 0); + } + if (metrics) { font->insertObjRef("ToUnicode", SkPDFMakeToUnicodeCmap(metrics->fGlyphToUnicode, subset, @@ -829,23 +889,24 @@ static void add_type3_font_info(SkPDFCanon* canon, font->insertObject("CharProcs", std::move(charProcs)); } -SkPDFType3Font::SkPDFType3Font(const SkAdvancedTypefaceMetrics* info, +SkPDFType3Font::SkPDFType3Font(sk_sp info, sk_sp typeface, SkAdvancedTypefaceMetrics::FontType fontType, uint16_t glyphID) - : SkPDFFont(std::move(typeface), fontType) { + : SkPDFFont(std::move(info), std::move(typeface), nullptr, + fontType, /* multiByteGlyphs = */ false) { + // If fLastGlyphID isn't set (because there is not fFontInfo), look it up. + this->setLastGlyphID(SkToU16(this->typeface()->countGlyphs() - 1)); this->adjustGlyphRangeForSingleByteEncoding(glyphID); } -sk_sp SkPDFType3Font::getFontSubset(SkPDFCanon* canon, - const SkPDFGlyphSet* usage) { +sk_sp SkPDFType3Font::getFontSubset(const SkPDFGlyphSet* usage) { // All fonts are subset before serialization. // TODO(halcanary): all fonts should follow this pattern. - const SkAdvancedTypefaceMetrics* info = - SkPDFFont::GetMetrics(this->typeface(), canon); - uint16_t emSize = info && info->fEmSize > 0 ? info->fEmSize : 1000; auto font = sk_make_sp("Font"); - add_type3_font_info(canon, font.get(), this->typeface(), (SkScalar)emSize, usage, + const SkAdvancedTypefaceMetrics* info = this->getFontInfo(); + uint16_t emSize = info && info->fEmSize > 0 ? info->fEmSize : 1000; + add_type3_font_info(font.get(), this->typeface(), (SkScalar)emSize, usage, this->firstGlyphID(), this->lastGlyphID()); return font; } @@ -853,11 +914,49 @@ sk_sp SkPDFType3Font::getFontSubset(SkPDFCanon* canon, //////////////////////////////////////////////////////////////////////////////// +SkPDFFont::Match SkPDFFont::IsMatch(SkPDFFont* existingFont, + uint32_t existingFontID, + uint16_t existingGlyphID, + uint32_t searchFontID, + uint16_t searchGlyphID) { + if (existingFontID != searchFontID) { + return SkPDFFont::kNot_Match; + } + if (existingGlyphID == 0 || searchGlyphID == 0) { + return SkPDFFont::kExact_Match; + } + if (existingFont != nullptr) { + return (existingFont->fFirstGlyphID <= searchGlyphID && + searchGlyphID <= existingFont->fLastGlyphID) + ? SkPDFFont::kExact_Match + : SkPDFFont::kRelated_Match; + } + return (existingGlyphID == searchGlyphID) ? SkPDFFont::kExact_Match + : SkPDFFont::kRelated_Match; +} + +// Since getAdvancedTypefaceMetrics is expensive, cache the result. bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFCanon* canon) { - return can_embed(SkPDFFont::GetMetrics(typeface, canon)); + SkFontID id = SkTypeface::UniqueID(typeface); + if (bool* value = canon->fCanEmbedTypeface.find(id)) { + return *value; + } + SkAutoResolveDefaultTypeface face(typeface); + bool canEmbed = true; + sk_sp fontMetrics( + face->getAdvancedTypefaceMetrics( + SkTypeface::kNo_PerGlyphInfo, nullptr, 0)); + if (fontMetrics) { + canEmbed = !SkToBool( + fontMetrics->fFlags & + SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag); + } + return *canon->fCanEmbedTypeface.set(id, canEmbed); } void SkPDFFont::drop() { fTypeface = nullptr; + fFontInfo = nullptr; + fDescriptor = nullptr; this->SkPDFDict::drop(); } diff --git a/src/pdf/SkPDFFont.h b/src/pdf/SkPDFFont.h index f2f1df4c24..36b93ecc35 100644 --- a/src/pdf/SkPDFFont.h +++ b/src/pdf/SkPDFFont.h @@ -60,6 +60,7 @@ private: 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 @@ -75,27 +76,28 @@ public: /** Returns the typeface represented by this class. Returns nullptr for the * default typeface. */ - SkTypeface* typeface() const { return fTypeface.get(); } + SkTypeface* typeface() { return fTypeface.get(); } /** Returns the font type represented in this font. For Type0 fonts, * returns the type of the decendant font. */ - SkAdvancedTypefaceMetrics::FontType getType() const { return fFontType; } - - static bool IsMultiByte(SkAdvancedTypefaceMetrics::FontType type) { - return type == SkAdvancedTypefaceMetrics::kType1CID_Font || - type == SkAdvancedTypefaceMetrics::kTrueType_Font; - } + SkAdvancedTypefaceMetrics::FontType getType() { return fFontType; } /** Returns true if this font encoding supports glyph IDs above 255. */ - bool multiByteGlyphs() const { return SkPDFFont::IsMultiByte(this->getType()); } + bool multiByteGlyphs() const { return fMultiByteGlyphs; } + + /** Returns true if the machine readable licensing bits allow embedding. + */ + bool canEmbed() const; + + /** Returns true if the machine readable licensing bits allow subsetting. + */ + bool canSubset() const; /** Return true if this font has an encoding for the passed glyph id. */ - bool hasGlyph(SkGlyphID gid) { - return (gid >= fFirstGlyphID && gid <= fLastGlyphID) || gid == 0; - } + bool hasGlyph(uint16_t glyphID); /** Convert (in place) the input glyph IDs into the font encoding. If the * font has more glyphs than can be encoded (like a type 1 font with more @@ -122,11 +124,10 @@ public: */ static SkPDFFont* GetFontResource(SkPDFCanon* canon, SkTypeface* typeface, - SkGlyphID glyphID); + uint16_t glyphID); - // Uses (kGlyphNames_PerGlyphInfo | kToUnicode_PerGlyphInfo). - static const SkAdvancedTypefaceMetrics* GetMetrics(SkTypeface* typeface, - SkPDFCanon* canon); + static sk_sp GetFontMetricsWithToUnicode( + SkTypeface*, uint32_t* glyphs, uint32_t glyphsCount); /** Subset the font based on usage set. Returns a SkPDFFont instance with * subset. @@ -134,8 +135,18 @@ public: * @return nullptr if font does not support subsetting, a new instance * of SkPDFFont otherwise. */ - virtual sk_sp getFontSubset(SkPDFCanon* canon, - const SkPDFGlyphSet* usage); + virtual sk_sp getFontSubset(const SkPDFGlyphSet* usage); + + enum Match { + kExact_Match, + kRelated_Match, + kNot_Match, + }; + static Match IsMatch(SkPDFFont* existingFont, + uint32_t existingFontID, + uint16_t existingGlyphID, + uint32_t searchFontID, + uint16_t searchGlyphID); /** * Return false iff the typeface has its NotEmbeddable flag set. @@ -145,29 +156,52 @@ public: protected: // Common constructor to handle common members. - SkPDFFont(sk_sp typeface, - SkAdvancedTypefaceMetrics::FontType fontType); + SkPDFFont(sk_sp fontInfo, + sk_sp typeface, + sk_sp relatedFontDescriptor, + SkAdvancedTypefaceMetrics::FontType fontType, + bool multiByteGlyphs); + // Accessors for subclass. + const SkAdvancedTypefaceMetrics* getFontInfo() const { return fFontInfo.get(); } + sk_sp refFontInfo() const { return fFontInfo; } + + void setFontInfo(sk_sp info); SkGlyphID firstGlyphID() const { return fFirstGlyphID; } SkGlyphID lastGlyphID() const { return fLastGlyphID; } + void setLastGlyphID(uint16_t glyphID); + + // Accessors for FontDescriptor associated with this object. + SkPDFDict* getFontDescriptor() const { return fDescriptor.get(); } + sk_sp refFontDescriptor() const { return fDescriptor; } + void setFontDescriptor(sk_sp descriptor); 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 adjustGlyphRangeForSingleByteEncoding(uint16_t glyphID); + + // Generate ToUnicode table according to glyph usage subset. + // If subset is nullptr, all available glyph ids will be used. + void populateToUnicodeTable(const SkPDFGlyphSet* subset); + + static bool Find(uint32_t fontID, uint16_t glyphID, int* index); void drop() override; private: sk_sp fTypeface; + sk_sp fFontInfo; + sk_sp fDescriptor; // 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. SkGlyphID fFirstGlyphID; SkGlyphID fLastGlyphID; SkAdvancedTypefaceMetrics::FontType fFontType; + bool fMultiByteGlyphs; typedef SkPDFDict INHERITED; };