From cee13425b5cd862189d1e5d7cf8f258bccae5f5d Mon Sep 17 00:00:00 2001 From: halcanary Date: Thu, 18 Aug 2016 09:52:48 -0700 Subject: [PATCH] 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 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/2253993002 --- src/pdf/SkPDFCanon.cpp | 53 ++---- src/pdf/SkPDFCanon.h | 22 +-- src/pdf/SkPDFDocument.cpp | 42 +---- src/pdf/SkPDFFont.cpp | 447 +++++++++++++++++++--------------------------- src/pdf/SkPDFFont.h | 74 +++----- 5 files changed, 218 insertions(+), 420 deletions(-) diff --git a/src/pdf/SkPDFCanon.cpp b/src/pdf/SkPDFCanon.cpp index 3dcf4e9..a804d6b 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 a0241e3..2da9e52 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 4a577fc..4f044c8 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 4d114f0..290061a 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; - } - 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; + 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)); + } + 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 36b93ec..f2f1df4 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; } - - /** Returns true if this font encoding supports glyph IDs above 255. - */ - bool multiByteGlyphs() const { return fMultiByteGlyphs; } + SkAdvancedTypefaceMetrics::FontType getType() const { return fFontType; } - /** Returns true if the machine readable licensing bits allow embedding. - */ - bool canEmbed() const; + static bool IsMultiByte(SkAdvancedTypefaceMetrics::FontType type) { + return type == SkAdvancedTypefaceMetrics::kType1CID_Font || + type == SkAdvancedTypefaceMetrics::kTrueType_Font; + } - /** Returns true if the machine readable licensing bits allow subsetting. + /** Returns true if this font encoding supports glyph IDs above 255. */ - 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); - - // Accessors for subclass. - const SkAdvancedTypefaceMetrics* getFontInfo() const { return fFontInfo.get(); } - sk_sp refFontInfo() const { return fFontInfo; } + SkPDFFont(sk_sp typeface, + SkAdvancedTypefaceMetrics::FontType fontType); - 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; }; -- 2.7.4