diff options
author | halcanary <halcanary@google.com> | 2016-08-17 14:21:42 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-08-17 14:21:42 -0700 |
commit | 0a61270f4ba85d10659fb63a86817b435ec04c94 (patch) | |
tree | dcdc5d23af09dcdb2a85da2c49598c6412e26959 /src/pdf | |
parent | 69c166d2ce3f4d2099f35f8e88f1aa56ceeaf960 (diff) |
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
Review-Url: https://codereview.chromium.org/2253993002
Diffstat (limited to 'src/pdf')
-rw-r--r-- | src/pdf/SkPDFCanon.cpp | 53 | ||||
-rw-r--r-- | src/pdf/SkPDFCanon.h | 22 | ||||
-rw-r--r-- | src/pdf/SkPDFDocument.cpp | 42 | ||||
-rw-r--r-- | src/pdf/SkPDFFont.cpp | 429 | ||||
-rw-r--r-- | src/pdf/SkPDFFont.h | 74 |
5 files changed, 204 insertions, 416 deletions
diff --git a/src/pdf/SkPDFCanon.cpp b/src/pdf/SkPDFCanon.cpp index 3dcf4e9f0f..4e182aecfc 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 <typename K, typename V> struct UnrefValue { + void operator()(K, V** v) { (*v)->unref(); } +}; +} +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<SkBitmapKey, SkPDFObject>()); + fTypefaceMetrics.foreach(UnrefValue<uint32_t, SkAdvancedTypefaceMetrics>()); + fFontDescriptors.foreach(UnrefValue<uint32_t, SkPDFDict>()); + fFontMap.foreach(UnrefValue<uint64_t, SkPDFFont>()); } -//////////////////////////////////////////////////////////////////////////////// - -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<SkPDFObject> findFunctionShader(const SkPDFShader::State&) const; void addFunctionShader(sk_sp<SkPDFObject>, SkPDFShader::State); @@ -63,7 +56,9 @@ public: sk_sp<SkPDFObject> findPDFBitmap(SkBitmapKey key) const; void addPDFBitmap(SkBitmapKey key, sk_sp<SkPDFObject>); - SkTHashMap<uint32_t, bool> fCanEmbedTypeface; + SkTHashMap<uint32_t, SkAdvancedTypefaceMetrics*> fTypefaceMetrics; + SkTHashMap<uint32_t, SkPDFDict*> fFontDescriptors; + SkTHashMap<uint64_t, SkPDFFont*> fFontMap; SkPixelSerializer* getPixelSerializer() const { return fPixelSerializer.get(); } void setPixelSerializer(sk_sp<SkPixelSerializer> ps) { @@ -75,13 +70,6 @@ public: sk_sp<SkPDFArray> makeRangeObject(); private: - struct FontRec { - SkPDFFont* fFont; - uint32_t fFontID; - uint16_t fGlyphID; - }; - SkTDArray<FontRec> fFontRecords; - struct ShaderRec { SkPDFShader::State fShaderState; sk_sp<SkPDFObject> 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<SkPDFDict> generate_page_tree(SkTArray<sk_sp<SkPDFDict>>* pages) { return std::move(curNodes[0]); } -#if 0 -// TODO(halcanary): expose notEmbeddableCount in SkDocument -void GetCountOfFontTypes( - const SkTDArray<SkPDFDevice*>& pageDevices, - int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1], - int* notSubsettableCount, - int* notEmbeddableCount) { - sk_bzero(counts, sizeof(int) * - (SkAdvancedTypefaceMetrics::kOther_Font + 1)); - SkTDArray<SkFontID> seenFonts; - int notSubsettable = 0; - int notEmbeddable = 0; - - for (int pageNumber = 0; pageNumber < pageDevices.count(); pageNumber++) { - const SkTDArray<SkPDFFont*>& 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 <typename T> 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<SkPDFObject> 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..7afdff6aa8 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<const SkAdvancedTypefaceMetrics> info, + SkPDFType0Font(const SkAdvancedTypefaceMetrics* info, sk_sp<SkTypeface> typeface, SkAdvancedTypefaceMetrics::FontType type); virtual ~SkPDFType0Font(); - sk_sp<SkPDFObject> getFontSubset(const SkPDFGlyphSet* usage) override; + sk_sp<SkPDFObject> 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<const SkAdvancedTypefaceMetrics> info, + SkPDFType1Font(const SkAdvancedTypefaceMetrics* info, sk_sp<SkTypeface> typeface, uint16_t glyphID, - sk_sp<SkPDFDict> 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<const SkAdvancedTypefaceMetrics> info, + SkPDFType3Font(const SkAdvancedTypefaceMetrics* info, sk_sp<SkTypeface> typeface, SkAdvancedTypefaceMetrics::FontType fontType, uint16_t glyphID); @@ -83,7 +80,7 @@ public: const SkPDFSubstituteMap&) const override { SkDEBUGFAIL("should call getFontSubset!"); } - sk_sp<SkPDFObject> getFontSubset(const SkPDFGlyphSet* usage) override; + sk_sp<SkPDFObject> getFontSubset(SkPDFCanon*, const SkPDFGlyphSet*) override; }; /////////////////////////////////////////////////////////////////////////////// @@ -216,26 +213,14 @@ 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; -} - -bool SkPDFFont::canSubset() const { - if (!fFontInfo.get()) { - SkASSERT(fFontType == SkAdvancedTypefaceMetrics::kOther_Font); - return true; - } - return (fFontInfo->fFlags & - SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag) == 0; +static bool can_embed(const SkAdvancedTypefaceMetrics* metrics) { + return !metrics || + !SkToBool(metrics->fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag); } -bool SkPDFFont::hasGlyph(uint16_t id) { - return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0; +static bool can_subset(const SkAdvancedTypefaceMetrics* metrics) { + return !metrics || + !SkToBool(metrics->fFlags & SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag); } int SkPDFFont::glyphsToPDFFontEncoding(SkGlyphID* glyphIDs, int numGlyphs) const { @@ -271,125 +256,105 @@ 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<SkTypeface> defaultFace; + if (!typeface) { + defaultFace = SkTypeface::MakeDefault(); + typeface = defaultFace.get(); + } + sk_sp<SkAdvancedTypefaceMetrics> 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; +} + 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); + 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); } + sk_sp<SkTypeface> 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<const SkAdvancedTypefaceMetrics> fontMetrics; - sk_sp<SkPDFDict> 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<SkPDFFont> font; switch (type) { case SkAdvancedTypefaceMetrics::kType1CID_Font: case SkAdvancedTypefaceMetrics::kTrueType_Font: - SkASSERT(relatedFontDescriptor == nullptr); + SkASSERT(multibyte); SkASSERT(fontMetrics != nullptr); - font = sk_make_sp<SkPDFType0Font>(std::move(fontMetrics), + font = sk_make_sp<SkPDFType0Font>(fontMetrics, std::move(typeface), type); break; case SkAdvancedTypefaceMetrics::kType1_Font: + SkASSERT(!multibyte); SkASSERT(fontMetrics != nullptr); - font = sk_make_sp<SkPDFType1Font>(std::move(fontMetrics), + font = sk_make_sp<SkPDFType1Font>(fontMetrics, 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<SkPDFType3Font>(std::move(fontMetrics), + default: + SkASSERT(!multibyte); + font = sk_make_sp<SkPDFType3Font>(fontMetrics, 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<SkPDFFont>. - canon->addFont(font.get(), fontID, firstGlyphID); + canon->fFontMap.set(fontID, SkRef(font.get())); return font.release(); // TODO(halcanary) return sk_sp<SkPDFFont>. } -sk_sp<SkPDFObject> SkPDFFont::getFontSubset(const SkPDFGlyphSet*) { +sk_sp<SkPDFObject> SkPDFFont::getFontSubset(SkPDFCanon*, const SkPDFGlyphSet*) { return nullptr; // Default: no support. } -// TODO: take a sk_sp<SkAdvancedTypefaceMetrics> and sk_sp<SkTypeface> -SkPDFFont::SkPDFFont(sk_sp<const SkAdvancedTypefaceMetrics> info, - sk_sp<SkTypeface> typeface, - sk_sp<SkPDFDict> relatedFontDescriptor, - SkAdvancedTypefaceMetrics::FontType fontType, - bool multiByteGlyphs) +SkPDFFont::SkPDFFont(sk_sp<SkTypeface> 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<const SkAdvancedTypefaceMetrics> info) { - if (info) { - fFontInfo = std::move(info); - } -} - -void SkPDFFont::setLastGlyphID(uint16_t glyphID) { - fLastGlyphID = glyphID; -} - -void SkPDFFont::setFontDescriptor(sk_sp<SkPDFDict> descriptor) { - fDescriptor = std::move(descriptor); + fLastGlyphID = SkToU16(fTypeface->countGlyphs() - 1); } static void add_common_font_descriptor_entries(SkPDFDict* descriptor, @@ -415,48 +380,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<const SkAdvancedTypefaceMetrics> info, +SkPDFType0Font::SkPDFType0Font(const SkAdvancedTypefaceMetrics* info, sk_sp<SkTypeface> 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<SkPDFObject> SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) { - if (!canSubset()) { +sk_sp<SkPDFObject> SkPDFType0Font::getFontSubset(SkPDFCanon* canon, + const SkPDFGlyphSet* subset) { + const SkAdvancedTypefaceMetrics* metrics = + SkPDFFont::GetMetrics(this->typeface(), canon); + SkASSERT(metrics); + if (!can_subset(metrics)) { return nullptr; } - auto newSubset = sk_make_sp<SkPDFType0Font>(refFontInfo(), refTypeface(), getType()); - newSubset->populate(subset); + auto newSubset = sk_make_sp<SkPDFType0Font>( + metrics, this->refTypeface(), this->getType()); + newSubset->populate(subset, *metrics); return newSubset; } @@ -522,10 +480,9 @@ static sk_sp<SkPDFObject> 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 +505,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<uint32_t> glyphIDs; if (subset) { @@ -607,7 +564,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 +586,77 @@ bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) { auto descendantFonts = sk_make_sp<SkPDFArray>(); 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<const SkAdvancedTypefaceMetrics> SkPDFFont::GetFontMetricsWithToUnicode( - SkTypeface* typeface, uint32_t* glyphs, uint32_t glyphsCount) { - return sk_sp<const SkAdvancedTypefaceMetrics>( - typeface->getAdvancedTypefaceMetrics( - SkTypeface::kToUnicode_PerGlyphInfo, glyphs, glyphsCount)); -} - - /////////////////////////////////////////////////////////////////////////////// // class SkPDFType1Font /////////////////////////////////////////////////////////////////////////////// -SkPDFType1Font::SkPDFType1Font(sk_sp<const SkAdvancedTypefaceMetrics> info, - sk_sp<SkTypeface> typeface, - uint16_t glyphID, - sk_sp<SkPDFDict> 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<SkPDFDict> descriptor = this->refFontDescriptor()) { - this->insertObjRef("FontDescriptor", std::move(descriptor)); - return true; - } - +static sk_sp<SkPDFDict> make_type1_font_descriptor( + SkTypeface* typeface, + const SkAdvancedTypefaceMetrics* info) { auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor"); - setFontDescriptor(descriptor); + SkASSERT(info); + add_common_font_descriptor_entries(descriptor.get(), *info, 0); 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<SkStreamAsset> rawFontData(typeface()->openStream(&ttcIndex)); + std::unique_ptr<SkStreamAsset> rawFontData(typeface->openStream(&ttcIndex)); sk_sp<SkData> fontData = SkPDFConvertType1FontStream(std::move(rawFontData), &header, &data, &trailer); - if (!fontData) { - return false; - } - SkASSERT(this->canEmbed()); - auto fontStream = sk_make_sp<SkPDFStream>(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 && can_embed(info)) { + auto fontStream = sk_make_sp<SkPDFStream>(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) { + SkASSERT(info); + 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<SkPDFArray>(); 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<SkPDFArray>(); encDiffs->reserve(lastGlyphID - firstGlyphID + 3); encDiffs->appendInt(0); - const SkTArray<SkString>& glyphNames = this->getFontInfo()->fGlyphNames; + const SkTArray<SkString>& glyphNames = info->fGlyphNames; SkASSERT(glyphNames.count() > lastGlyphID); encDiffs->appendName(glyphNames[0].c_str()); const SkString unknown("UNKNOWN"); @@ -736,8 +668,28 @@ bool SkPDFType1Font::populate(int16_t glyphID) { auto encoding = sk_make_sp<SkPDFDict>("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<SkTypeface> typeface, + uint16_t glyphID, + SkPDFCanon* canon) + : SkPDFFont(std::move(typeface), SkAdvancedTypefaceMetrics::kType1_Font) +{ + SkFontID fontID = this->typeface()->uniqueID(); + sk_sp<SkPDFDict> fontDescriptor; + if (SkPDFDict** ptr = canon->fFontDescriptors.find(fontID)) { + fontDescriptor = sk_ref_sp(*ptr); + } else { + fontDescriptor = make_type1_font_descriptor(this->typeface(), info); + 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 +726,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 +815,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<const SkAdvancedTypefaceMetrics> metrics; - if (subset) { - SkTDArray<uint32_t> 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 +829,23 @@ static void add_type3_font_info(SkPDFDict* font, font->insertObject("CharProcs", std::move(charProcs)); } -SkPDFType3Font::SkPDFType3Font(sk_sp<const SkAdvancedTypefaceMetrics> info, +SkPDFType3Font::SkPDFType3Font(const SkAdvancedTypefaceMetrics* info, sk_sp<SkTypeface> 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<SkPDFObject> SkPDFType3Font::getFontSubset(const SkPDFGlyphSet* usage) { +sk_sp<SkPDFObject> SkPDFType3Font::getFontSubset(SkPDFCanon* canon, + const SkPDFGlyphSet* usage) { // All fonts are subset before serialization. // TODO(halcanary): all fonts should follow this pattern. - auto font = sk_make_sp<SkPDFDict>("Font"); - const SkAdvancedTypefaceMetrics* info = this->getFontInfo(); + const SkAdvancedTypefaceMetrics* info = + SkPDFFont::GetMetrics(this->typeface(), canon); uint16_t emSize = info && info->fEmSize > 0 ? info->fEmSize : 1000; - add_type3_font_info(font.get(), this->typeface(), (SkScalar)emSize, usage, + auto font = sk_make_sp<SkPDFDict>("Font"); + add_type3_font_info(canon, font.get(), this->typeface(), (SkScalar)emSize, usage, this->firstGlyphID(), this->lastGlyphID()); return font; } @@ -914,49 +853,11 @@ sk_sp<SkPDFObject> 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<const SkAdvancedTypefaceMetrics> fontMetrics( - face->getAdvancedTypefaceMetrics( - SkTypeface::kNo_PerGlyphInfo, nullptr, 0)); - if (fontMetrics) { - canEmbed = !SkToBool( - fontMetrics->fFlags & - SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag); - } - return *canon->fCanEmbedTypeface.set(id, canEmbed); + return can_embed(SkPDFFont::GetMetrics(typeface, canon)); } 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<FontGlyphSetPair> fMap; }; - /** \class SkPDFFont A PDF Object class representing a font. The font may have resources attached to it in order to embed the font. SkPDFFonts are canonicalized @@ -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<const SkAdvancedTypefaceMetrics> 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<SkPDFObject> 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<SkPDFObject> 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<const SkAdvancedTypefaceMetrics> fontInfo, - sk_sp<SkTypeface> typeface, - sk_sp<SkPDFDict> relatedFontDescriptor, - SkAdvancedTypefaceMetrics::FontType fontType, - bool multiByteGlyphs); - - // Accessors for subclass. - const SkAdvancedTypefaceMetrics* getFontInfo() const { return fFontInfo.get(); } - sk_sp<const SkAdvancedTypefaceMetrics> refFontInfo() const { return fFontInfo; } + SkPDFFont(sk_sp<SkTypeface> typeface, + SkAdvancedTypefaceMetrics::FontType fontType); - void setFontInfo(sk_sp<const SkAdvancedTypefaceMetrics> 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<SkPDFDict> refFontDescriptor() const { return fDescriptor; } - void setFontDescriptor(sk_sp<SkPDFDict> descriptor); sk_sp<SkTypeface> 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<SkTypeface> fTypeface; - sk_sp<const SkAdvancedTypefaceMetrics> fFontInfo; - sk_sp<SkPDFDict> 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; }; |