[pdf] Fix OpenType CFF embedding
While OpenType is a singular format, PDF doesn't treat it that way. Most
viewers don't care how the PDF describes the font data, they just ship
it off to their font interpreter which figures out what the format is.
However, some viewers require strict adherence to the PDF specification
to recognize OpenType with CFF outlines.
This means setting the /Font's /Subtype to /CIDFontType0 (instead of
/CIDFontType2 for glyf outlines), using /FontFile3 instead of /FontFile2
in the /FontDescriptor, and setting /Subtype /OpenType on the font data
stream dictionary.
Bug: 342510496
Change-Id: Id4bedaea3e905f912c6120d1d2da8ee2d036e892
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/869037
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index a70ebf7..21e26ac 100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -111,6 +111,10 @@
return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
}
+static bool can_subset(const SkAdvancedTypefaceMetrics& metrics) {
+ return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag);
+}
+
const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(const SkTypeface* typeface,
SkPDFDocument* canon) {
SkASSERT(typeface);
@@ -289,10 +293,11 @@
///////////////////////////////////////////////////////////////////////////////
static void emit_subset_type0(const SkPDFFont& font, SkPDFDocument* doc) {
- const SkAdvancedTypefaceMetrics* metricsPtr =
- SkPDFFont::GetMetrics(font.typeface(), doc);
+ const SkAdvancedTypefaceMetrics* metricsPtr = SkPDFFont::GetMetrics(font.typeface(), doc);
SkASSERT(metricsPtr);
- if (!metricsPtr) { return; }
+ if (!metricsPtr) {
+ return;
+ }
const SkAdvancedTypefaceMetrics& metrics = *metricsPtr;
SkASSERT(can_embed(metrics));
SkAdvancedTypefaceMetrics::FontType type = font.getType();
@@ -310,44 +315,41 @@
SkDebugf("Error: (SkTypeface)(%p)::openStream() returned "
"empty stream (%p) when identified as kType1CID_Font "
"or kTrueType_Font.\n", face, fontAsset.get());
- } else {
- switch (type) {
- case SkAdvancedTypefaceMetrics::kTrueType_Font:
- case SkAdvancedTypefaceMetrics::kCFF_Font: {
- if (!SkToBool(metrics.fFlags &
- SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag)) {
- SkASSERT(font.firstGlyphID() == 1);
- sk_sp<SkData> subsetFontData = SkPDFSubsetFont(*face, font.glyphUsage());
- if (subsetFontData) {
- std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
- tmp->insertInt("Length1", SkToInt(subsetFontData->size()));
- descriptor->insertRef(
- "FontFile2",
- SkPDFStreamOut(std::move(tmp),
- SkMemoryStream::Make(std::move(subsetFontData)),
- doc, SkPDFSteamCompressionEnabled::Yes));
- break;
- }
- // If subsetting fails, fall back to original font data.
- }
- std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
- tmp->insertInt("Length1", fontSize);
- descriptor->insertRef("FontFile2",
- SkPDFStreamOut(std::move(tmp), std::move(fontAsset),
- doc, SkPDFSteamCompressionEnabled::Yes));
- break;
- }
- case SkAdvancedTypefaceMetrics::kType1CID_Font: {
- std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
- tmp->insertName("Subtype", "CIDFontType0C");
- descriptor->insertRef("FontFile3",
- SkPDFStreamOut(std::move(tmp), std::move(fontAsset),
- doc, SkPDFSteamCompressionEnabled::Yes));
- break;
- }
- default:
- SkASSERT(false);
+ } else if (type == SkAdvancedTypefaceMetrics::kTrueType_Font ||
+ type == SkAdvancedTypefaceMetrics::kCFF_Font)
+ {
+ sk_sp<SkData> subsetFontData;
+ if (can_subset(metrics)) {
+ SkASSERT(font.firstGlyphID() == 1);
+ subsetFontData = SkPDFSubsetFont(*face, font.glyphUsage());
}
+ std::unique_ptr<SkStreamAsset> subsetFontAsset;
+ if (subsetFontData) {
+ subsetFontAsset = SkMemoryStream::Make(std::move(subsetFontData));
+ } else {
+ // If subsetting fails, fall back to original font data.
+ subsetFontAsset = std::move(fontAsset);
+ }
+ std::unique_ptr<SkPDFDict> streamDict = SkPDFMakeDict();
+ streamDict->insertInt("Length1", subsetFontAsset->getLength());
+ const char* fontFileKey;
+ if (type == SkAdvancedTypefaceMetrics::kTrueType_Font) {
+ fontFileKey = "FontFile2";
+ } else {
+ streamDict->insertName("Subtype", "OpenType");
+ fontFileKey = "FontFile3";
+ }
+ descriptor->insertRef(fontFileKey,
+ SkPDFStreamOut(std::move(streamDict), std::move(subsetFontAsset),
+ doc, SkPDFSteamCompressionEnabled::Yes));
+ } else if (type == SkAdvancedTypefaceMetrics::kType1CID_Font) {
+ std::unique_ptr<SkPDFDict> streamDict = SkPDFMakeDict();
+ streamDict->insertName("Subtype", "CIDFontType0C");
+ descriptor->insertRef("FontFile3",
+ SkPDFStreamOut(std::move(streamDict), std::move(fontAsset),
+ doc, SkPDFSteamCompressionEnabled::Yes));
+ } else {
+ SkASSERT(false);
}
auto newCIDFont = SkPDFMakeDict("Font");
@@ -358,8 +360,11 @@
case SkAdvancedTypefaceMetrics::kType1CID_Font:
newCIDFont->insertName("Subtype", "CIDFontType0");
break;
- case SkAdvancedTypefaceMetrics::kTrueType_Font:
case SkAdvancedTypefaceMetrics::kCFF_Font:
+ newCIDFont->insertName("Subtype", "CIDFontType0");
+ newCIDFont->insertName("CIDToGIDMap", "Identity");
+ break;
+ case SkAdvancedTypefaceMetrics::kTrueType_Font:
newCIDFont->insertName("Subtype", "CIDFontType2");
newCIDFont->insertName("CIDToGIDMap", "Identity");
break;
diff --git a/src/ports/SkTypeface_mac_ct.cpp b/src/ports/SkTypeface_mac_ct.cpp
index f042c76..b81438f 100644
--- a/src/ports/SkTypeface_mac_ct.cpp
+++ b/src/ports/SkTypeface_mac_ct.cpp
@@ -537,13 +537,14 @@
constexpr SkFontTableTag glyf = SkSetFourByteTag('g','l','y','f');
constexpr SkFontTableTag loca = SkSetFourByteTag('l','o','c','a');
constexpr SkFontTableTag CFF = SkSetFourByteTag('C','F','F',' ');
- if (!((this->getTableSize(glyf) && this->getTableSize(loca)) ||
- this->getTableSize(CFF)))
- {
+ if (this->getTableSize(glyf) && this->getTableSize(loca)) {
+ info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
+ } else if (this->getTableSize(CFF)) {
+ info->fType = SkAdvancedTypefaceMetrics::kCFF_Font;
+ } else {
return info;
}
- info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont.get());
if (symbolicTraits & kCTFontMonoSpaceTrait) {
info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
diff --git a/src/ports/SkTypeface_win_dw.cpp b/src/ports/SkTypeface_win_dw.cpp
index 3164fb3..a3823ce 100644
--- a/src/ports/SkTypeface_win_dw.cpp
+++ b/src/ports/SkTypeface_win_dw.cpp
@@ -721,17 +721,21 @@
}
DWRITE_FONT_FACE_TYPE fontType = fDWriteFontFace->GetType();
- if (fontType != DWRITE_FONT_FACE_TYPE_TRUETYPE &&
- fontType != DWRITE_FONT_FACE_TYPE_CFF &&
- fontType != DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION &&
- fontType != DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION)
+ if (fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE ||
+ fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION)
{
+ info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
+ } else if (fontType == DWRITE_FONT_FACE_TYPE_CFF ||
+ fontType == DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION)
+ {
+ info->fType = SkAdvancedTypefaceMetrics::kCFF_Font;
+ } else {
return info;
}
- // Simulated fonts aren't really TrueType fonts.
- if (fDWriteFontFace->GetSimulations() == DWRITE_FONT_SIMULATIONS_NONE) {
- info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
+ // Simulated fonts aren't really OpenType fonts.
+ if (fDWriteFontFace->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
+ info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
}
AutoTDWriteTable<SkOTTableHead> headTable(fDWriteFontFace.get());