From: vandebo Date: Thu, 19 Jun 2014 18:05:39 +0000 (-0700) Subject: [PDF] Fix font embedding restrictions. X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~7142 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0f9bad01b0e7ad592ffb342dcf1d238b15329be1;p=platform%2Fupstream%2FlibSkiaSharp.git [PDF] Fix font embedding restrictions. Stop using restricted font outlines and honor don't subset restriction. Resubmit of r12600. R=halcanary@google.com, bungeman@google.com, reed@google.com Author: vandebo@chromium.org Review URL: https://codereview.chromium.org/334443002 --- diff --git a/gyp/core.gyp b/gyp/core.gyp index b4f0579..64cc79b 100644 --- a/gyp/core.gyp +++ b/gyp/core.gyp @@ -21,6 +21,7 @@ '../include/utils', '../include/xml', '../src/core', + '../src/sfnt', '../src/image', '../src/opts', '../src/utils', diff --git a/include/core/SkAdvancedTypefaceMetrics.h b/include/core/SkAdvancedTypefaceMetrics.h index e75365b..1192688 100644 --- a/include/core/SkAdvancedTypefaceMetrics.h +++ b/include/core/SkAdvancedTypefaceMetrics.h @@ -35,15 +35,21 @@ public: kCFF_Font, kTrueType_Font, kOther_Font, - kNotEmbeddable_Font }; // The type of the underlying font program. This field determines which - // of the following fields are valid. If it is kOther_Font or - // kNotEmbeddable_Font, the per glyph information will never be populated. + // of the following fields are valid. If it is kOther_Font the per glyph + // information will never be populated. FontType fType; - // fMultiMaster may be true for Type1_Font or CFF_Font. - bool fMultiMaster; + enum FontFlags { + kEmpty_FontFlag = 0x0, //! fCatalog; diff --git a/src/core/SkTypeface.cpp b/src/core/SkTypeface.cpp index fd2803b..48be651 100644 --- a/src/core/SkTypeface.cpp +++ b/src/core/SkTypeface.cpp @@ -6,9 +6,11 @@ */ #include "SkAdvancedTypefaceMetrics.h" +#include "SkEndian.h" #include "SkFontDescriptor.h" #include "SkFontHost.h" #include "SkLazyPtr.h" +#include "SkOTTable_OS_2.h" #include "SkStream.h" #include "SkTypeface.h" @@ -269,7 +271,28 @@ SkAdvancedTypefaceMetrics* SkTypeface::getAdvancedTypefaceMetrics( SkAdvancedTypefaceMetrics::PerGlyphInfo info, const uint32_t* glyphIDs, uint32_t glyphIDsCount) const { - return this->onGetAdvancedTypefaceMetrics(info, glyphIDs, glyphIDsCount); + SkAdvancedTypefaceMetrics* result = + this->onGetAdvancedTypefaceMetrics(info, glyphIDs, glyphIDsCount); + if (result && result->fType == SkAdvancedTypefaceMetrics::kTrueType_Font) { + struct SkOTTableOS2 os2table; + if (this->getTableData(SkTEndian_SwapBE32(SkOTTableOS2::TAG), 0, + sizeof(os2table), &os2table) > 0) { + if (os2table.version.v2.fsType.field.Bitmap || + (os2table.version.v2.fsType.field.Restricted && + !(os2table.version.v2.fsType.field.PreviewPrint || + os2table.version.v2.fsType.field.Editable))) { + result->fFlags = SkTBitOr( + result->fFlags, + SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag); + } + if (os2table.version.v2.fsType.field.NoSubsetting) { + result->fFlags = SkTBitOr( + result->fFlags, + SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag); + } + } + } + return result; } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp index 0633d30..79699a0 100644 --- a/src/pdf/SkPDFDocument.cpp +++ b/src/pdf/SkPDFDocument.cpp @@ -258,11 +258,13 @@ bool SkPDFDocument::appendPage(SkPDFDevice* pdfDevice) { return true; } +// Deprecated. void SkPDFDocument::getCountOfFontTypes( - int counts[SkAdvancedTypefaceMetrics::kNotEmbeddable_Font + 1]) const { + int counts[SkAdvancedTypefaceMetrics::kOther_Font + 2]) const { sk_bzero(counts, sizeof(int) * - (SkAdvancedTypefaceMetrics::kNotEmbeddable_Font + 1)); + (SkAdvancedTypefaceMetrics::kOther_Font + 2)); SkTDArray seenFonts; + int notEmbeddable = 0; for (int pageNumber = 0; pageNumber < fPages.count(); pageNumber++) { const SkTDArray& fontResources = @@ -272,9 +274,49 @@ void SkPDFDocument::getCountOfFontTypes( if (seenFonts.find(fontID) == -1) { counts[fontResources[font]->getType()]++; seenFonts.push(fontID); + if (!fontResources[font]->canEmbed()) { + notEmbeddable++; + } } } } + counts[SkAdvancedTypefaceMetrics::kOther_Font + 1] = notEmbeddable; +} + +void SkPDFDocument::getCountOfFontTypes( + int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1], + int* notSubsettableCount, + int* notEmbeddableCount) const { + sk_bzero(counts, sizeof(int) * + (SkAdvancedTypefaceMetrics::kOther_Font + 1)); + SkTDArray seenFonts; + int notSubsettable = 0; + int notEmbeddable = 0; + + for (int pageNumber = 0; pageNumber < fPages.count(); pageNumber++) { + const SkTDArray& fontResources = + fPages[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; + } } void SkPDFDocument::emitHeader(SkWStream* stream) { diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp index 0d41176..49d383b 100644 --- a/src/pdf/SkPDFFont.cpp +++ b/src/pdf/SkPDFFont.cpp @@ -761,6 +761,24 @@ SkAdvancedTypefaceMetrics::FontType SkPDFFont::getType() { return fFontType; } +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; +} + bool SkPDFFont::hasGlyph(uint16_t id) { return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0; } @@ -808,7 +826,7 @@ SkPDFFont* SkPDFFont::GetFontResource(SkTypeface* typeface, uint16_t glyphID) { // This only is to catch callers who pass invalid glyph ids. // If glyph id is invalid, then we will create duplicate entries - // for True Type fonts. + // for TrueType fonts. SkAdvancedTypefaceMetrics::FontType fontType = fontMetrics.get() ? fontMetrics.get()->fType : SkAdvancedTypefaceMetrics::kOther_Font; @@ -888,9 +906,8 @@ SkPDFFont::SkPDFFont(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface, fLastGlyphID(info ? info->fLastGlyphID : 0), fFontInfo(SkSafeRef(info)), fDescriptor(SkSafeRef(relatedFontDescriptor)) { - if (info == NULL) { - fFontType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; - } else if (info->fMultiMaster) { + if (info == NULL || + info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag) { fFontType = SkAdvancedTypefaceMetrics::kOther_Font; } else { fFontType = info->fType; @@ -902,9 +919,10 @@ SkPDFFont* SkPDFFont::Create(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface, uint16_t glyphID, SkPDFDict* relatedFontDescriptor) { SkAdvancedTypefaceMetrics::FontType type = - info ? info->fType : SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; + info ? info->fType : SkAdvancedTypefaceMetrics::kOther_Font; - if (info && info->fMultiMaster) { + if (info && + (info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) { NOT_IMPLEMENTED(true, true); return new SkPDFType3Font(info, typeface, @@ -923,8 +941,7 @@ SkPDFFont* SkPDFFont::Create(SkAdvancedTypefaceMetrics* info, } SkASSERT(type == SkAdvancedTypefaceMetrics::kCFF_Font || - type == SkAdvancedTypefaceMetrics::kOther_Font || - type == SkAdvancedTypefaceMetrics::kNotEmbeddable_Font); + type == SkAdvancedTypefaceMetrics::kOther_Font); return new SkPDFType3Font(info, typeface, glyphID); } @@ -1052,11 +1069,17 @@ SkPDFType0Font::SkPDFType0Font(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface) : SkPDFFont(info, typeface, NULL) { SkDEBUGCODE(fPopulated = false); + if (!canSubset()) { + populate(NULL); + } } SkPDFType0Font::~SkPDFType0Font() {} SkPDFFont* SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) { + if (!canSubset()) { + return NULL; + } SkPDFType0Font* newSubset = new SkPDFType0Font(fontInfo(), typeface()); newSubset->populate(subset); return newSubset; @@ -1105,19 +1128,34 @@ bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth, SkAutoTUnref descriptor(new SkPDFDict("FontDescriptor")); setFontDescriptor(descriptor.get()); addResource(descriptor.get()); + insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref(); + if (!addCommonFontDescriptorEntries(defaultWidth)) { + return false; + } + if (!canEmbed()) { + return true; + } switch (getType()) { case SkAdvancedTypefaceMetrics::kTrueType_Font: { - SkASSERT(subset); - // Font subsetting - SkPDFStream* rawStream = NULL; - size_t fontSize = get_subset_font_stream(fontInfo()->fFontName.c_str(), - typeface(), - *subset, - &rawStream); + SkAutoTUnref fontStream; + size_t fontSize = 0; + if (canSubset()) { + SkPDFStream* rawStream = NULL; + fontSize = get_subset_font_stream(fontInfo()->fFontName.c_str(), + typeface(), + *subset, + &rawStream); + fontStream.reset(rawStream); + } else { + int ttcIndex; + SkAutoTUnref fontData( + typeface()->openStream(&ttcIndex)); + fontStream.reset(new SkPDFStream(fontData.get())); + fontSize = fontData->getLength(); + } SkASSERT(fontSize); - SkASSERT(rawStream); - SkAutoTUnref fontStream(rawStream); + SkASSERT(fontStream.get()); addResource(fontStream.get()); fontStream->insertInt("Length1", fontSize); @@ -1145,9 +1183,7 @@ bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth, default: SkASSERT(false); } - - insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref(); - return addCommonFontDescriptorEntries(defaultWidth); + return true; } bool SkPDFCIDFont::populate(const SkPDFGlyphSet* subset) { @@ -1266,12 +1302,15 @@ bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) { if (fontData == NULL) { return false; } - SkAutoTUnref fontStream(new SkPDFStream(fontData)); - addResource(fontStream.get()); - fontStream->insertInt("Length1", header); - fontStream->insertInt("Length2", data); - fontStream->insertInt("Length3", trailer); - descriptor->insert("FontFile", new SkPDFObjRef(fontStream.get()))->unref(); + if (canEmbed()) { + SkAutoTUnref fontStream(new SkPDFStream(fontData)); + addResource(fontStream.get()); + fontStream->insertInt("Length1", header); + fontStream->insertInt("Length2", data); + fontStream->insertInt("Length3", trailer); + descriptor->insert("FontFile", + new SkPDFObjRef(fontStream.get()))->unref(); + } addResource(descriptor.get()); insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref(); diff --git a/src/pdf/SkPDFFont.h b/src/pdf/SkPDFFont.h index 3a5234d..058a042 100644 --- a/src/pdf/SkPDFFont.h +++ b/src/pdf/SkPDFFont.h @@ -99,6 +99,14 @@ public: */ virtual bool multiByteGlyphs() const = 0; + /** Returns true if the machine readable licensing bits allow embedding. + */ + bool canEmbed() const; + + /** Returns true if the machine readable licensing bits allow subsetting. + */ + bool canSubset() const; + /** Return true if this font has an encoding for the passed glyph id. */ bool hasGlyph(uint16_t glyphID); @@ -121,8 +129,7 @@ public: * @param typeface The typeface to find. * @param glyphID Specify which section of a large font is of interest. */ - static SkPDFFont* GetFontResource(SkTypeface* typeface, - uint16_t glyphID); + static SkPDFFont* GetFontResource(SkTypeface* typeface, uint16_t glyphID); /** Subset the font based on usage set. Returns a SkPDFFont instance with * subset. @@ -188,8 +195,6 @@ private: // this will be a subset if the font has more than 255 glyphs. uint16_t fFirstGlyphID; uint16_t fLastGlyphID; - // The font info is only kept around after construction for large - // Type1 (non CID) fonts that need multiple "fonts" to access all glyphs. SkAutoTUnref fFontInfo; SkTDArray fResources; SkAutoTUnref fDescriptor; diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp index 4a0afbb..12edc49 100644 --- a/src/ports/SkFontHost_FreeType.cpp +++ b/src/ports/SkFontHost_FreeType.cpp @@ -440,6 +440,20 @@ static bool canEmbed(FT_Face face) { #endif } +static bool canSubset(FT_Face face) { +#ifdef FT_FSTYPE_NO_SUBSETTING + FT_UShort fsType = FT_Get_FSType_Flags(face); + return (fsType & FT_FSTYPE_NO_SUBSETTING) == 0; +#else + // No subset is 0x100. + TT_OS2* os2_table; + if ((os2_table = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2)) != NULL) { + return (os2_table->fsType & 0x100) == 0; + } + return false; // We tried, fail safe. +#endif +} + static bool GetLetterCBox(FT_Face face, char letter, FT_BBox* bbox) { const FT_UInt glyph_id = FT_Get_Char_Index(face, letter); if (!glyph_id) @@ -525,7 +539,21 @@ SkAdvancedTypefaceMetrics* SkTypeface_FreeType::onGetAdvancedTypefaceMetrics( SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics; info->fFontName.set(FT_Get_Postscript_Name(face)); - info->fMultiMaster = FT_HAS_MULTIPLE_MASTERS(face); + info->fFlags = SkAdvancedTypefaceMetrics::kEmpty_FontFlag; + if (FT_HAS_MULTIPLE_MASTERS(face)) { + info->fFlags = SkTBitOr( + info->fFlags, SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag); + } + if (!canEmbed(face)) { + info->fFlags = SkTBitOr( + info->fFlags, + SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag); + } + if (!canSubset(face)) { + info->fFlags = SkTBitOr( + info->fFlags, + SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag); + } info->fLastGlyphID = face->num_glyphs - 1; info->fEmSize = 1000; @@ -623,8 +651,7 @@ SkAdvancedTypefaceMetrics* SkTypeface_FreeType::onGetAdvancedTypefaceMetrics( info->fBBox = SkIRect::MakeLTRB(face->bbox.xMin, face->bbox.yMax, face->bbox.xMax, face->bbox.yMin); - if (!canEmbed(face) || !FT_IS_SCALABLE(face) || - info->fType == SkAdvancedTypefaceMetrics::kOther_Font) { + if (!FT_IS_SCALABLE(face)) { perGlyphInfo = SkAdvancedTypefaceMetrics::kNo_PerGlyphInfo; } @@ -687,9 +714,6 @@ SkAdvancedTypefaceMetrics* SkTypeface_FreeType::onGetAdvancedTypefaceMetrics( populate_glyph_to_unicode(face, &(info->fGlyphToUnicode)); } - if (!canEmbed(face)) - info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; - return info; #endif } diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp index 26d30d7..e00b87b 100755 --- a/src/ports/SkFontHost_mac.cpp +++ b/src/ports/SkFontHost_mac.cpp @@ -1544,17 +1544,16 @@ SkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics( CFStringToSkString(fontName, &info->fFontName); } - info->fMultiMaster = false; CFIndex glyphCount = CTFontGetGlyphCount(ctFont); info->fLastGlyphID = SkToU16(glyphCount - 1); info->fEmSize = CTFontGetUnitsPerEm(ctFont); + info->fFlags = SkAdvancedTypefaceMetrics::kEmpty_FontFlag; + info->fStyle = 0; if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) { populate_glyph_to_unicode(ctFont, glyphCount, &info->fGlyphToUnicode); } - info->fStyle = 0; - // If it's not a truetype font, mark it as 'other'. Assume that TrueType // fonts always have both glyf and loca tables. At the least, this is what // sfntly needs to subset the font. CTFontCopyAttribute() does not always @@ -1618,10 +1617,7 @@ SkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics( } } - if (false) { // TODO: haven't figured out how to know if font is embeddable - // (information is in the OS/2 table) - info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; - } else if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) { + if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) { if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) { skia_advanced_typeface_metrics_utils::appendRange(&info->fGlyphWidths, 0); info->fGlyphWidths->fAdvance.append(1, &min_width); diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp index 763fc35..5a90214 100755 --- a/src/ports/SkFontHost_win.cpp +++ b/src/ports/SkFontHost_win.cpp @@ -1867,10 +1867,18 @@ SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics( info = new SkAdvancedTypefaceMetrics; info->fEmSize = otm.otmEMSquare; - info->fMultiMaster = false; info->fLastGlyphID = SkToU16(glyphCount - 1); info->fStyle = 0; tchar_to_skstring(lf.lfFaceName, &info->fFontName); + info->fFlags = SkAdvancedTypefaceMetrics::kEmpty_FontFlag; + // If bit 1 is set, the font may not be embedded in a document. + // If bit 1 is clear, the font can be embedded. + // If bit 2 is set, the embedding is read-only. + if (otm.otmfsType & 0x1) { + info->fFlags = SkTBitOr( + info->fFlags, + SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag); + } if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) { populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode)); @@ -1931,13 +1939,7 @@ SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics( } } - // If bit 1 is set, the font may not be embedded in a document. - // If bit 1 is clear, the font can be embedded. - // If bit 2 is set, the embedding is read-only. - if (otm.otmfsType & 0x1) { - info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; - } else if (perGlyphInfo & - SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) { + if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) { if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) { appendRange(&info->fGlyphWidths, 0); info->fGlyphWidths->fAdvance.append(1, &min_width); diff --git a/src/ports/SkTypeface_win_dw.cpp b/src/ports/SkTypeface_win_dw.cpp index 9eace8b..6ff8412 100644 --- a/src/ports/SkTypeface_win_dw.cpp +++ b/src/ports/SkTypeface_win_dw.cpp @@ -361,9 +361,9 @@ SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics( info = new SkAdvancedTypefaceMetrics; info->fEmSize = dwfm.designUnitsPerEm; - info->fMultiMaster = false; info->fLastGlyphID = SkToU16(glyphCount - 1); info->fStyle = 0; + info->fFlags = SkAdvancedTypefaceMetrics::kEmpty_FontFlag; // SkAdvancedTypefaceMetrics::fFontName is in theory supposed to be // the PostScript name of the font. However, due to the way it is currently @@ -467,12 +467,7 @@ SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics( } */ - // If Restricted, the font may not be embedded in a document. - // If not Restricted, the font can be embedded. - // If PreviewPrint, the embedding is read-only. - if (os2Table->version.v0.fsType.field.Restricted) { - info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; - } else if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) { + if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) { if (fixedWidth) { appendRange(&info->fGlyphWidths, 0); int16_t advance;