diff --git a/src/pdf/SkPDFCanon.cpp b/src/pdf/SkPDFCanon.cpp index 3dcf4e9f0f..a804d6b47b 100644 --- a/src/pdf/SkPDFCanon.cpp +++ b/src/pdf/SkPDFCanon.cpp @@ -12,52 +12,25 @@ //////////////////////////////////////////////////////////////////////////////// -void SkPDFCanon::reset() { - for (int i = 0; i < fFontRecords.count(); ++i) { - fFontRecords[i].fFont->unref(); - } - fFontRecords.reset(); - - fFunctionShaderRecords.reset(); - fAlphaShaderRecords.reset(); - fImageShaderRecords.reset(); +namespace { +template struct UnrefValue { + void operator()(K, V** v) { SkSafeUnref(*v); } +}; +} +SkPDFCanon::~SkPDFCanon() { // TODO(halcanary): make SkTHashSet work nicely with sk_sp<>, // or use std::unordered_set<> fGraphicStateRecords.foreach ([](WrapGS w) { w.fPtr->unref(); }); - fGraphicStateRecords.reset(); - - fPDFBitmapMap.foreach([](SkBitmapKey, SkPDFObject** p) { (*p)->unref(); }); - fPDFBitmapMap.reset(); + fPDFBitmapMap.foreach(UnrefValue()); + fTypefaceMetrics.foreach(UnrefValue()); + fFontDescriptors.foreach(UnrefValue()); + fFontMap.foreach(UnrefValue()); } -//////////////////////////////////////////////////////////////////////////////// - -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; +void SkPDFCanon::reset() { + this->~SkPDFCanon(); + new (this)SkPDFCanon; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/pdf/SkPDFCanon.h b/src/pdf/SkPDFCanon.h index a0241e308f..2da9e52f70 100644 --- a/src/pdf/SkPDFCanon.h +++ b/src/pdf/SkPDFCanon.h @@ -14,6 +14,7 @@ #include "SkTHash.h" #include "SkBitmapKey.h" +class SkAdvancedTypefaceMetrics; class SkPDFFont; /** @@ -35,19 +36,11 @@ class SkPDFFont; */ class SkPDFCanon : SkNoncopyable { public: - ~SkPDFCanon() { this->reset(); } + ~SkPDFCanon(); // 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); @@ -63,7 +56,9 @@ public: sk_sp findPDFBitmap(SkBitmapKey key) const; void addPDFBitmap(SkBitmapKey key, sk_sp); - SkTHashMap fCanEmbedTypeface; + SkTHashMap fTypefaceMetrics; + SkTHashMap fFontDescriptors; + SkTHashMap fFontMap; SkPixelSerializer* getPixelSerializer() const { return fPixelSerializer.get(); } void setPixelSerializer(sk_sp ps) { @@ -75,13 +70,6 @@ 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 4a577fcff3..4f044c8771 100644 --- a/src/pdf/SkPDFDocument.cpp +++ b/src/pdf/SkPDFDocument.cpp @@ -168,46 +168,6 @@ 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; } //////////////////////////////////////////////////////////////////////////////// @@ -484,7 +444,7 @@ bool SkPDFDocument::onClose(SkWStream* stream) { // Build font subsetting info before calling addObjectRecursively(). for (const auto& entry : fGlyphUsage) { sk_sp subsetFont = - entry.fFont->getFontSubset(&entry.fGlyphSet); + entry.fFont->getFontSubset(&fCanon, &entry.fGlyphSet); if (subsetFont) { fObjectSerializer.fSubstituteMap.setSubstitute( entry.fFont, subsetFont.get()); diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp index 4d114f0e1a..290061a491 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(sk_sp info, + SkPDFType0Font(const SkAdvancedTypefaceMetrics& info, sk_sp typeface, SkAdvancedTypefaceMetrics::FontType type); virtual ~SkPDFType0Font(); - sk_sp getFontSubset(const SkPDFGlyphSet* usage) override; + sk_sp getFontSubset(SkPDFCanon*, const SkPDFGlyphSet*) override; #ifdef SK_DEBUG void emitObject(SkWStream*, const SkPDFObjNumMap&, @@ -54,26 +54,23 @@ private: #ifdef SK_DEBUG bool fPopulated; #endif - bool populate(const SkPDFGlyphSet* subset); + bool populate(const SkPDFGlyphSet* subset, + const SkAdvancedTypefaceMetrics& metrics); typedef SkPDFDict INHERITED; }; class SkPDFType1Font final : public SkPDFFont { public: - SkPDFType1Font(sk_sp info, + SkPDFType1Font(const SkAdvancedTypefaceMetrics& info, sk_sp typeface, uint16_t glyphID, - sk_sp relatedFontDescriptor); - virtual ~SkPDFType1Font(); - -private: - bool populate(int16_t glyphID); - bool addFontDescriptor(int16_t defaultWidth); + SkPDFCanon* canon); + virtual ~SkPDFType1Font() {} }; class SkPDFType3Font final : public SkPDFFont { public: - SkPDFType3Font(sk_sp info, + SkPDFType3Font(const SkAdvancedTypefaceMetrics& info, sk_sp typeface, SkAdvancedTypefaceMetrics::FontType fontType, uint16_t glyphID); @@ -83,7 +80,7 @@ public: const SkPDFSubstituteMap&) const override { SkDEBUGFAIL("should call getFontSubset!"); } - sk_sp getFontSubset(const SkPDFGlyphSet* usage) override; + sk_sp getFontSubset(SkPDFCanon*, const SkPDFGlyphSet*) override; }; /////////////////////////////////////////////////////////////////////////////// @@ -99,7 +96,7 @@ static SkAutoGlyphCache vector_cache(SkTypeface* face, SkScalar size = 0) { tmpPaint.setTextSize((SkScalar)face->getUnitsPerEm()); } else { tmpPaint.setTextSize(size); - } + } const SkSurfaceProps props(0, kUnknown_SkPixelGeometry); SkAutoGlyphCache glyphCache(tmpPaint, &props, nullptr); SkASSERT(glyphCache.get()); @@ -216,26 +213,12 @@ SkPDFGlyphSet* SkPDFGlyphSetMap::getGlyphSetForFont(SkPDFFont* font) { SkPDFFont::~SkPDFFont() {} -bool SkPDFFont::canEmbed() const { - if (!fFontInfo.get()) { - SkASSERT(fFontType == SkAdvancedTypefaceMetrics::kOther_Font); - return true; - } - return (fFontInfo->fFlags & - SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag) == 0; +static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) { + return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_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; +static bool can_subset(const SkAdvancedTypefaceMetrics& metrics) { + return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag); } int SkPDFFont::glyphsToPDFFontEncoding(SkGlyphID* glyphIDs, int numGlyphs) const { @@ -271,125 +254,115 @@ int SkPDFFont::glyphsToPDFFontEncodingCount(const SkGlyphID* glyphIDs, return numGlyphs; } -// static + +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)); + if (!metrics) { + if (typeface->countGlyphs() > 0) { + metrics = sk_make_sp(); + } else { + SkDEBUGF(("SkPDF: SkTypeface:getAdvancedTypefaceMetrics() returned null.\n")); + } + } + // May cache null to skip this check. use SkSafeUnref. + return *canon->fTypefaceMetrics.set(id, metrics.release()); +} + +SkAdvancedTypefaceMetrics::FontType font_type(const SkAdvancedTypefaceMetrics& metrics) { + if (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; +} + SkPDFFont* SkPDFFont::GetFontResource(SkPDFCanon* canon, SkTypeface* face, - uint16_t glyphID) { + SkGlyphID glyphID) { SkASSERT(canon); - const uint32_t fontID = SkTypeface::UniqueID(face); - SkPDFFont* relatedFont; - if (SkPDFFont* pdfFont = canon->findFont(fontID, glyphID, &relatedFont)) { - return SkRef(pdfFont); + const SkAdvancedTypefaceMetrics* fontMetrics = SkPDFFont::GetMetrics(face, canon); + if (!fontMetrics) { + return nullptr; // bad font, return early. } + const SkAdvancedTypefaceMetrics& metrics = *fontMetrics; + SkAdvancedTypefaceMetrics::FontType type = font_type(metrics); + 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); + } + 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(relatedFontDescriptor == nullptr); - SkASSERT(fontMetrics != nullptr); - font = sk_make_sp(std::move(fontMetrics), + SkASSERT(multibyte); + font = sk_make_sp(metrics, std::move(typeface), type); break; case SkAdvancedTypefaceMetrics::kType1_Font: - SkASSERT(fontMetrics != nullptr); - font = sk_make_sp(std::move(fontMetrics), + SkASSERT(!multibyte); + font = sk_make_sp(metrics, std::move(typeface), glyphID, - std::move(relatedFontDescriptor)); + canon); break; - case SkAdvancedTypefaceMetrics::kCFF_Font: - SkASSERT(fontMetrics != nullptr); - // fallthrough - case SkAdvancedTypefaceMetrics::kOther_Font: - font = sk_make_sp(std::move(fontMetrics), + default: + SkASSERT(!multibyte); + // Type3 is our fallback font. + font = sk_make_sp(metrics, std::move(typeface), type, glyphID); break; - default: - SkDEBUGFAIL("invalid SkAdvancedTypefaceMetrics::FontType"); - return nullptr; } - // 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); + canon->fFontMap.set(fontID, SkRef(font.get())); return font.release(); // TODO(halcanary) return sk_sp. } -sk_sp SkPDFFont::getFontSubset(const SkPDFGlyphSet*) { +sk_sp SkPDFFont::getFontSubset(SkPDFCanon*, const SkPDFGlyphSet*) { return nullptr; // Default: no support. } -// TODO: take a sk_sp and sk_sp -SkPDFFont::SkPDFFont(sk_sp info, - sk_sp typeface, - sk_sp relatedFontDescriptor, - SkAdvancedTypefaceMetrics::FontType fontType, - bool multiByteGlyphs) +SkPDFFont::SkPDFFont(sk_sp typeface, + SkAdvancedTypefaceMetrics::FontType fontType) : SkPDFDict("Font") , fTypeface(std::move(typeface)) - , fFontInfo(std::move(info)) - , fDescriptor(std::move(relatedFontDescriptor)) , fFirstGlyphID(1) - , fFontType(fontType) - , fMultiByteGlyphs(multiByteGlyphs) { + , fFontType(fontType) { SkASSERT(fTypeface); - 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); + fLastGlyphID = SkToU16(fTypeface->countGlyphs() - 1); } static void add_common_font_descriptor_entries(SkPDFDict* descriptor, @@ -415,48 +388,41 @@ static void add_common_font_descriptor_entries(SkPDFDict* descriptor, } } -void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(uint16_t glyphID) { +void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(SkGlyphID glyphID) { // Single byte glyph encoding supports a max of 255 glyphs. - fFirstGlyphID = glyphID - (glyphID - 1) % 255; + fFirstGlyphID = first_glyph_for_single_byte_encoding(glyphID); 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(sk_sp info, +SkPDFType0Font::SkPDFType0Font(const SkAdvancedTypefaceMetrics& info, sk_sp typeface, SkAdvancedTypefaceMetrics::FontType fontType) - : SkPDFFont(std::move(info), std::move(typeface), nullptr, fontType, true) { + : SkPDFFont(std::move(typeface), fontType) { SkDEBUGCODE(fPopulated = false); - if (!canSubset()) { - this->populate(nullptr); + if (!can_subset(info)) { + this->populate(nullptr, info); } } SkPDFType0Font::~SkPDFType0Font() {} -sk_sp SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) { - if (!canSubset()) { +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(refFontInfo(), refTypeface(), getType()); - newSubset->populate(subset); + auto newSubset = sk_make_sp( + *metrics, this->refTypeface(), this->getType()); + newSubset->populate(subset, *metrics); return newSubset; } @@ -522,10 +488,9 @@ static sk_sp get_subset_font_stream( } #endif // SK_SFNTLY_SUBSETTER -bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) { - SkASSERT(this->canEmbed()); - SkASSERT(this->getFontInfo()); - const SkAdvancedTypefaceMetrics& metrics = *(this->getFontInfo()); +bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset, + const SkAdvancedTypefaceMetrics& metrics) { + SkASSERT(can_embed(metrics)); SkAdvancedTypefaceMetrics::FontType type = this->getType(); SkTypeface* face = this->typeface(); SkASSERT(face); @@ -548,7 +513,7 @@ bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) { } #ifdef SK_SFNTLY_SUBSETTER - if (this->canSubset() && subset) { + if (can_subset(metrics) && subset) { // Generate glyph id array. in format needed by sfntly SkTDArray glyphIDs; if (subset) { @@ -607,7 +572,7 @@ bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) { sysInfo->insertInt("Supplement", 0); newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo)); - uint16_t emSize = this->getFontInfo()->fEmSize; + uint16_t emSize = metrics.fEmSize; int16_t defaultWidth = 0; const SkBitSet* bitSet = subset ? &subset->bitSet() : nullptr; { @@ -629,102 +594,77 @@ bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) { auto descendantFonts = sk_make_sp(); descendantFonts->appendObjRef(std::move(newCIDFont)); this->insertObject("DescendantFonts", std::move(descendantFonts)); - this->populateToUnicodeTable(subset); + + if (metrics.fGlyphToUnicode.count() > 0) { + this->insertObjRef("ToUnicode", + SkPDFMakeToUnicodeCmap(metrics.fGlyphToUnicode, + subset, + multiByteGlyphs(), + firstGlyphID(), + lastGlyphID())); + } 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 /////////////////////////////////////////////////////////////////////////////// -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; - } - +static sk_sp make_type1_font_descriptor( + SkTypeface* typeface, + const SkAdvancedTypefaceMetrics& info) { auto descriptor = sk_make_sp("FontDescriptor"); - setFontDescriptor(descriptor); - + add_common_font_descriptor_entries(descriptor.get(), info, 0); + if (!can_embed(info)) { + return 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) { - return false; + if (fontData) { + 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->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; + return descriptor; } -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(); +static void populate_type_1_font(SkPDFDict* font, + const SkAdvancedTypefaceMetrics& info, + SkTypeface* typeface, + SkGlyphID firstGlyphID, + SkGlyphID lastGlyphID) { + font->insertName("Subtype", "Type1"); + font->insertName("BaseFont", info.fFontName); // glyphCount not including glyph 0 unsigned glyphCount = 1 + lastGlyphID - firstGlyphID; SkASSERT(glyphCount > 0 && glyphCount <= 255); - this->insertInt("FirstChar", (size_t)0); - this->insertInt("LastChar", (size_t)glyphCount); + font->insertInt("FirstChar", (size_t)0); + font->insertInt("LastChar", (size_t)glyphCount); { - SkAutoGlyphCache glyphCache = vector_cache(this->typeface()); + SkAutoGlyphCache glyphCache = vector_cache(typeface); auto widths = sk_make_sp(); SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX; - const uint16_t emSize = this->getFontInfo()->fEmSize; + const uint16_t emSize = info.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)); } - this->insertObject("Widths", std::move(widths)); - } - if (!addFontDescriptor(0)) { - return false; + font->insertObject("Widths", std::move(widths)); } auto encDiffs = sk_make_sp(); encDiffs->reserve(lastGlyphID - firstGlyphID + 3); encDiffs->appendInt(0); - const SkTArray& glyphNames = this->getFontInfo()->fGlyphNames; + const SkTArray& glyphNames = info.fGlyphNames; SkASSERT(glyphNames.count() > lastGlyphID); encDiffs->appendName(glyphNames[0].c_str()); const SkString unknown("UNKNOWN"); @@ -736,8 +676,28 @@ bool SkPDFType1Font::populate(int16_t glyphID) { auto encoding = sk_make_sp("Encoding"); encoding->insertObject("Differences", std::move(encDiffs)); - this->insertObject("Encoding", std::move(encoding)); - return true; + 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()); } /////////////////////////////////////////////////////////////////////////////// @@ -774,7 +734,8 @@ private: }; } -static void add_type3_font_info(SkPDFDict* font, +static void add_type3_font_info(SkPDFCanon* canon, + SkPDFDict* font, SkTypeface* typeface, SkScalar emSize, const SkPDFGlyphSet* subset, @@ -862,21 +823,8 @@ static void add_type3_font_info(SkPDFDict* font, fontBBox->appendInt(bbox.top()); font->insertObject("FontBBox", std::move(fontBBox)); font->insertName("CIDToGIDMap", "Identity"); - 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) { + const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon); + if (metrics /* && metrics->fGlyphToUnicode.count() > 0 */) { font->insertObjRef("ToUnicode", SkPDFMakeToUnicodeCmap(metrics->fGlyphToUnicode, subset, @@ -889,24 +837,24 @@ static void add_type3_font_info(SkPDFDict* font, font->insertObject("CharProcs", std::move(charProcs)); } -SkPDFType3Font::SkPDFType3Font(sk_sp info, +SkPDFType3Font::SkPDFType3Font(const SkAdvancedTypefaceMetrics& info, sk_sp typeface, SkAdvancedTypefaceMetrics::FontType fontType, uint16_t glyphID) - : 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)); + : SkPDFFont(std::move(typeface), fontType) { this->adjustGlyphRangeForSingleByteEncoding(glyphID); } -sk_sp SkPDFType3Font::getFontSubset(const SkPDFGlyphSet* usage) { +sk_sp SkPDFType3Font::getFontSubset(SkPDFCanon* canon, + 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); + SkASSERT(info); + uint16_t emSize = info->fEmSize > 0 ? info->fEmSize : 1000; auto font = sk_make_sp("Font"); - 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, + add_type3_font_info(canon, font.get(), this->typeface(), (SkScalar)emSize, usage, this->firstGlyphID(), this->lastGlyphID()); return font; } @@ -914,49 +862,12 @@ sk_sp SkPDFType3Font::getFontSubset(const SkPDFGlyphSet* usage) { //////////////////////////////////////////////////////////////////////////////// -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) { - 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); + const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon); + return metrics && can_embed(*metrics); } 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 36b93ecc35..f2f1df4c24 100644 --- a/src/pdf/SkPDFFont.h +++ b/src/pdf/SkPDFFont.h @@ -60,7 +60,6 @@ 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 @@ -76,28 +75,27 @@ public: /** Returns the typeface represented by this class. Returns nullptr for the * default typeface. */ - SkTypeface* typeface() { return fTypeface.get(); } + SkTypeface* typeface() const { return fTypeface.get(); } /** Returns the font type represented in this font. For Type0 fonts, * returns the type of the decendant font. */ - SkAdvancedTypefaceMetrics::FontType getType() { return fFontType; } + SkAdvancedTypefaceMetrics::FontType getType() const { return fFontType; } + + static bool IsMultiByte(SkAdvancedTypefaceMetrics::FontType type) { + return type == SkAdvancedTypefaceMetrics::kType1CID_Font || + type == SkAdvancedTypefaceMetrics::kTrueType_Font; + } /** Returns true if this font encoding supports glyph IDs above 255. */ - 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; + bool multiByteGlyphs() const { return SkPDFFont::IsMultiByte(this->getType()); } /** Return true if this font has an encoding for the passed glyph id. */ - bool hasGlyph(uint16_t glyphID); + bool hasGlyph(SkGlyphID gid) { + return (gid >= fFirstGlyphID && gid <= fLastGlyphID) || gid == 0; + } /** 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 @@ -124,10 +122,11 @@ public: */ static SkPDFFont* GetFontResource(SkPDFCanon* canon, SkTypeface* typeface, - uint16_t glyphID); + SkGlyphID glyphID); - static sk_sp GetFontMetricsWithToUnicode( - SkTypeface*, uint32_t* glyphs, uint32_t glyphsCount); + // Uses (kGlyphNames_PerGlyphInfo | kToUnicode_PerGlyphInfo). + static const SkAdvancedTypefaceMetrics* GetMetrics(SkTypeface* typeface, + SkPDFCanon* canon); /** Subset the font based on usage set. Returns a SkPDFFont instance with * subset. @@ -135,18 +134,8 @@ public: * @return nullptr if font does not support subsetting, a new instance * of SkPDFFont otherwise. */ - 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); + virtual sk_sp getFontSubset(SkPDFCanon* canon, + const SkPDFGlyphSet* usage); /** * Return false iff the typeface has its NotEmbeddable flag set. @@ -156,52 +145,29 @@ public: protected: // Common constructor to handle common members. - SkPDFFont(sk_sp fontInfo, - sk_sp typeface, - sk_sp relatedFontDescriptor, - SkAdvancedTypefaceMetrics::FontType fontType, - bool multiByteGlyphs); + SkPDFFont(sk_sp typeface, + SkAdvancedTypefaceMetrics::FontType fontType); - // 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(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 adjustGlyphRangeForSingleByteEncoding(SkGlyphID glyphID); 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; };