SkPDF: Subset Type3 (fallback) font
Motivation: significant file-size reduction.
Also: SkPDFFont::subsetFont() returns a sk_sp<SkPDFObject>
rather than a SkPDFFont*.
SkPDFType3Font constructor no longer populates font info;
relies on subsetting.
SkPDFFont::Create is easier to read
Also: SkPDFType3Font are scaled by emSize rather than 1000.
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2231483002
Committed: https://skia.googlesource.com/skia/+/88b138da99328b04cae9a8ee19c3882b8847a550
Review-Url: https://codereview.chromium.org/2231483002
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index b9e1f3b..f3ede35 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1206,7 +1206,11 @@
SkPDFGlyphSetMap* fontGlyphUsage = fDocument->getGlyphUsage();
while (numGlyphs > consumedGlyphCount) {
- this->updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry());
+ if (!this->updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry())) {
+ SkDebugf("SkPDF: Font error.");
+ content.entry()->fContent.writeText("ET\n%SkPDF: Font error.\n");
+ return;
+ }
SkPDFFont* font = content.entry()->fState.fFont;
int availableGlyphs = font->glyphsToPDFFontEncoding(
@@ -1273,7 +1277,11 @@
SkAutoGlyphCache autoGlyphCache(textPaint, nullptr, nullptr);
content.entry()->fContent.writeText("BT\n");
- this->updateFont(textPaint, glyphIDs[0], content.entry());
+ if (!this->updateFont(textPaint, glyphIDs[0], content.entry())) {
+ SkDebugf("SkPDF: Font error.");
+ content.entry()->fContent.writeText("ET\n%SkPDF: Font error.\n");
+ return;
+ }
GlyphPositioner glyphPositioner(&content.entry()->fContent,
textPaint.getTextSkewX(),
content.entry()->fState.fFont->multiByteGlyphs());
@@ -1286,7 +1294,11 @@
// The current pdf font cannot encode the current glyph.
// Try to get a pdf font which can encode the current glyph.
glyphPositioner.flush();
- this->updateFont(textPaint, glyphIDs[i], content.entry());
+ if (!this->updateFont(textPaint, glyphIDs[i], content.entry())) {
+ SkDebugf("SkPDF: Font error.");
+ content.entry()->fContent.writeText("ET\n%SkPDF: Font error.\n");
+ return;
+ }
font = content.entry()->fState.fFont;
glyphPositioner.setWideChars(font->multiByteGlyphs());
if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) {
@@ -1997,13 +2009,16 @@
return result;
}
-void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID,
+bool SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID,
SkPDFDevice::ContentEntry* contentEntry) {
SkTypeface* typeface = paint.getTypeface();
if (contentEntry->fState.fFont == nullptr ||
contentEntry->fState.fTextSize != paint.getTextSize() ||
!contentEntry->fState.fFont->hasGlyph(glyphID)) {
int fontIndex = getFontResourceIndex(typeface, glyphID);
+ if (fontIndex < 0) {
+ return false;
+ }
contentEntry->fContent.writeText("/");
contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName(
SkPDFResourceDict::kFont_ResourceType,
@@ -2013,11 +2028,15 @@
contentEntry->fContent.writeText(" Tf\n");
contentEntry->fState.fFont = fFontResources[fontIndex];
}
+ return true;
}
int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
sk_sp<SkPDFFont> newFont(
SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID));
+ if (!newFont) {
+ return -1;
+ }
int resourceIndex = fFontResources.find(newFont.get());
if (resourceIndex < 0) {
resourceIndex = fFontResources.count();
diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h
index 7404752..f38dfcb 100644
--- a/src/pdf/SkPDFDevice.h
+++ b/src/pdf/SkPDFDevice.h
@@ -291,7 +291,8 @@
int addGraphicStateResource(SkPDFObject* gs);
int addXObjectResource(SkPDFObject* xObject);
- void updateFont(const SkPaint& paint, uint16_t glyphID, ContentEntry* contentEntry);
+ // returns false when a valid SkFont can not be produced
+ bool updateFont(const SkPaint& paint, uint16_t glyphID, ContentEntry* contentEntry);
int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
index 7723caf..4a577fc 100644
--- a/src/pdf/SkPDFDocument.cpp
+++ b/src/pdf/SkPDFDocument.cpp
@@ -483,8 +483,8 @@
// Build font subsetting info before calling addObjectRecursively().
for (const auto& entry : fGlyphUsage) {
- sk_sp<SkPDFFont> subsetFont(
- entry.fFont->getFontSubset(&entry.fGlyphSet));
+ sk_sp<SkPDFObject> subsetFont =
+ entry.fFont->getFontSubset(&entry.fGlyphSet);
if (subsetFont) {
fObjectSerializer.fSubstituteMap.setSubstitute(
entry.fFont, subsetFont.get());
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index ff1dd2d..769771a 100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -60,7 +60,7 @@
SkTypeface* typeface);
virtual ~SkPDFType0Font();
bool multiByteGlyphs() const override { return true; }
- SkPDFFont* getFontSubset(const SkPDFGlyphSet* usage) override;
+ sk_sp<SkPDFObject> getFontSubset(const SkPDFGlyphSet* usage) override;
#ifdef SK_DEBUG
void emitObject(SkWStream*,
const SkPDFObjNumMap&,
@@ -108,11 +108,14 @@
SkPDFType3Font(const SkAdvancedTypefaceMetrics* info,
SkTypeface* typeface,
uint16_t glyphID);
- virtual ~SkPDFType3Font();
+ virtual ~SkPDFType3Font() {}
+ void emitObject(SkWStream*,
+ const SkPDFObjNumMap&,
+ const SkPDFSubstituteMap&) const override {
+ SkDEBUGFAIL("should call getFontSubset!");
+ }
+ sk_sp<SkPDFObject> getFontSubset(const SkPDFGlyphSet* usage) override;
bool multiByteGlyphs() const override { return false; }
-
-private:
- bool populate(uint16_t glyphID);
};
///////////////////////////////////////////////////////////////////////////////
@@ -335,7 +338,7 @@
void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
- SkWStream* content) {
+ SkDynamicMemoryWStream* content) {
// Specify width and bounding box for the glyph.
SkPDFUtils::AppendScalar(width, content);
content->writeText(" 0 ");
@@ -519,15 +522,20 @@
SkTypeface* typeface,
uint16_t glyphID) {
SkASSERT(canon);
- SkAutoResolveDefaultTypeface autoResolve(typeface);
- typeface = autoResolve.get();
- const uint32_t fontID = typeface->uniqueID();
-
+ const uint32_t fontID = SkTypeface::UniqueID(typeface);
SkPDFFont* relatedFont;
if (SkPDFFont* pdfFont = canon->findFont(fontID, glyphID, &relatedFont)) {
return SkRef(pdfFont);
}
-
+ SkAutoResolveDefaultTypeface autoResolve(typeface);
+ typeface = autoResolve.get();
+ SkASSERT(typeface);
+ int glyphCount = typeface->countGlyphs();
+ 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;
SkPDFDict* relatedFontDescriptor = nullptr;
if (relatedFont) {
@@ -559,10 +567,11 @@
return font;
}
-SkPDFFont* SkPDFFont::getFontSubset(const SkPDFGlyphSet*) {
+sk_sp<SkPDFObject> SkPDFFont::getFontSubset(const SkPDFGlyphSet*) {
return nullptr; // Default: no support.
}
+// TODO: take a sk_sp<SkAdvancedTypefaceMetrics> and sk_sp<SkTypeface>
SkPDFFont::SkPDFFont(const SkAdvancedTypefaceMetrics* info,
SkTypeface* typeface,
SkPDFDict* relatedFontDescriptor)
@@ -571,12 +580,13 @@
, fFirstGlyphID(1)
, fLastGlyphID(info ? info->fLastGlyphID : 0)
, fFontInfo(SkSafeRef(info))
- , fDescriptor(SkSafeRef(relatedFontDescriptor)) {
- if (info == nullptr ||
- info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag) {
- fFontType = SkAdvancedTypefaceMetrics::kOther_Font;
- } else {
- fFontType = info->fType;
+ , fDescriptor(SkSafeRef(relatedFontDescriptor))
+ , fFontType((!info || info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)
+ ? SkAdvancedTypefaceMetrics::kOther_Font
+ : info->fType) {
+ SkASSERT(fTypeface);
+ if (0 == fLastGlyphID) {
+ fLastGlyphID = SkToU16(fTypeface->countGlyphs() - 1);
}
}
@@ -588,23 +598,28 @@
SkPDFDict* relatedFontDescriptor) {
SkAdvancedTypefaceMetrics::FontType type =
info ? info->fType : SkAdvancedTypefaceMetrics::kOther_Font;
-
- if (info && (info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) {
+ SkAdvancedTypefaceMetrics::FontFlags flags =
+ info ? info->fFlags : SkAdvancedTypefaceMetrics::kEmpty_FontFlag;
+ if (SkToBool(flags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) {
return new SkPDFType3Font(info, typeface, glyphID);
}
- if (type == SkAdvancedTypefaceMetrics::kType1CID_Font ||
- type == SkAdvancedTypefaceMetrics::kTrueType_Font) {
- SkASSERT(relatedFontDescriptor == nullptr);
- return new SkPDFType0Font(info, typeface);
+ switch (type) {
+ case SkAdvancedTypefaceMetrics::kType1CID_Font:
+ case SkAdvancedTypefaceMetrics::kTrueType_Font:
+ SkASSERT(relatedFontDescriptor == nullptr);
+ SkASSERT(info != nullptr);
+ return new SkPDFType0Font(info, typeface);
+ case SkAdvancedTypefaceMetrics::kType1_Font:
+ SkASSERT(info != nullptr);
+ return new SkPDFType1Font(info, typeface, glyphID, relatedFontDescriptor);
+ case SkAdvancedTypefaceMetrics::kCFF_Font:
+ SkASSERT(info != nullptr);
+ // fallthrough
+ case SkAdvancedTypefaceMetrics::kOther_Font:
+ return new SkPDFType3Font(info, typeface, glyphID);
}
- if (type == SkAdvancedTypefaceMetrics::kType1_Font) {
- return new SkPDFType1Font(info, typeface, glyphID, relatedFontDescriptor);
- }
-
- SkASSERT(type == SkAdvancedTypefaceMetrics::kCFF_Font ||
- type == SkAdvancedTypefaceMetrics::kOther_Font);
-
- return new SkPDFType3Font(info, typeface, glyphID);
+ SkDEBUGFAIL("invalid SkAdvancedTypefaceMetrics::FontType");
+ return nullptr;
}
const SkAdvancedTypefaceMetrics* SkPDFFont::fontInfo() {
@@ -703,11 +718,11 @@
SkPDFType0Font::~SkPDFType0Font() {}
-SkPDFFont* SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) {
+sk_sp<SkPDFObject> SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) {
if (!canSubset()) {
return nullptr;
}
- SkPDFType0Font* newSubset = new SkPDFType0Font(fontInfo(), typeface());
+ auto newSubset = sk_make_sp<SkPDFType0Font>(fontInfo(), typeface());
newSubset->populate(subset);
return newSubset;
}
@@ -878,7 +893,8 @@
tmpPaint.setHinting(SkPaint::kNo_Hinting);
tmpPaint.setTypeface(sk_ref_sp(tf));
tmpPaint.setTextSize((SkScalar)tf->getUnitsPerEm());
- SkAutoGlyphCache autoGlyphCache(tmpPaint, nullptr, nullptr);
+ const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
+ SkAutoGlyphCache autoGlyphCache(tmpPaint, &props, nullptr);
if (!glyphIDs || glyphIDs->isEmpty()) {
get_glyph_widths(dst, tf->countGlyphs(), nullptr, 0, autoGlyphCache.get());
} else {
@@ -1017,7 +1033,8 @@
tmpPaint.setHinting(SkPaint::kNo_Hinting);
tmpPaint.setTypeface(sk_ref_sp(this->typeface()));
tmpPaint.setTextSize((SkScalar)this->typeface()->getUnitsPerEm());
- SkAutoGlyphCache glyphCache(tmpPaint, nullptr, nullptr);
+ const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
+ SkAutoGlyphCache glyphCache(tmpPaint, &props, nullptr);
auto widths = sk_make_sp<SkPDFArray>();
SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX;
const uint16_t emSize = this->fontInfo()->fEmSize;
@@ -1054,85 +1071,179 @@
// class SkPDFType3Font
///////////////////////////////////////////////////////////////////////////////
-SkPDFType3Font::SkPDFType3Font(const SkAdvancedTypefaceMetrics* info,
- SkTypeface* typeface,
- uint16_t glyphID)
- : SkPDFFont(info, typeface, nullptr) {
- this->populate(glyphID);
+namespace {
+// returns [0, first, first+1, ... last-1, last]
+struct SingleByteGlyphIdIterator {
+ SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
+ : fFirst(first), fLast(last) {
+ SkASSERT(fFirst > 0);
+ SkASSERT(fLast >= first);
+ }
+ struct Iter {
+ void operator++() {
+ fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
+ }
+ // This is an input_iterator
+ SkGlyphID operator*() const { return (SkGlyphID)fCurrent; }
+ bool operator!=(const Iter& rhs) const {
+ return fCurrent != rhs.fCurrent;
+ }
+ Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {}
+ private:
+ const SkGlyphID fFirst;
+ int fCurrent; // must be int to make fLast+1 to fit
+ };
+ Iter begin() const { return Iter(fFirst, 0); }
+ Iter end() const { return Iter(fFirst, (int)fLast + 1); }
+private:
+ const SkGlyphID fFirst;
+ const SkGlyphID fLast;
+};
}
-SkPDFType3Font::~SkPDFType3Font() {}
-
-bool SkPDFType3Font::populate(uint16_t glyphID) {
+static void add_type3_font_info(SkPDFDict* font,
+ SkTypeface* typeface,
+ SkScalar emSize,
+ const SkPDFGlyphSet* subset,
+ SkGlyphID firstGlyphID,
+ SkGlyphID lastGlyphID) {
+ SkASSERT(lastGlyphID >= firstGlyphID);
SkPaint paint;
- paint.setTypeface(sk_ref_sp(this->typeface()));
- paint.setTextSize(1000);
+ paint.setHinting(SkPaint::kNo_Hinting);
+ paint.setTypeface(sk_ref_sp(typeface));
+ paint.setTextSize(emSize);
const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
- SkAutoGlyphCache autoCache(paint, &props, nullptr);
- SkGlyphCache* cache = autoCache.getCache();
- // If fLastGlyphID isn't set (because there is not fFontInfo), look it up.
- if (lastGlyphID() == 0) {
- setLastGlyphID(cache->getGlyphCount() - 1);
- }
+ SkAutoGlyphCache cache(paint, &props, nullptr);
- adjustGlyphRangeForSingleByteEncoding(glyphID);
-
- insertName("Subtype", "Type3");
- // Flip about the x-axis and scale by 1/1000.
+ font->insertName("Subtype", "Type3");
+ // Flip about the x-axis and scale by 1/emSize.
SkMatrix fontMatrix;
- fontMatrix.setScale(SkScalarInvert(1000), -SkScalarInvert(1000));
- this->insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
+ fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
+ font->insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
auto charProcs = sk_make_sp<SkPDFDict>();
auto encoding = sk_make_sp<SkPDFDict>("Encoding");
auto encDiffs = sk_make_sp<SkPDFArray>();
- encDiffs->reserve(lastGlyphID() - firstGlyphID() + 2);
- encDiffs->appendInt(1);
+ // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
+ // plus 1 for glyph 0;
+ SkASSERT(firstGlyphID > 0);
+ SkASSERT(lastGlyphID >= firstGlyphID);
+ int glyphCount = lastGlyphID - firstGlyphID + 2;
+ // one other entry for the index of first glyph.
+ encDiffs->reserve(glyphCount + 1);
+ encDiffs->appendInt(0); // index of first glyph
auto widthArray = sk_make_sp<SkPDFArray>();
+ widthArray->reserve(glyphCount);
SkIRect bbox = SkIRect::MakeEmpty();
- for (int gID = firstGlyphID(); gID <= lastGlyphID(); gID++) {
+
+ sk_sp<SkPDFStream> emptyStream;
+ for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
+ bool skipGlyph = subset && gID != 0 && !subset->has(gID);
SkString characterName;
- characterName.printf("gid%d", gID);
- encDiffs->appendName(characterName.c_str());
-
- const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
- widthArray->appendScalar(SkFloatToScalar(glyph.fAdvanceX));
- SkIRect glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
- glyph.fWidth, glyph.fHeight);
- bbox.join(glyphBBox);
-
- SkDynamicMemoryWStream content;
- setGlyphWidthAndBoundingBox(SkFloatToScalar(glyph.fAdvanceX), glyphBBox,
- &content);
- const SkPath* path = cache->findPath(glyph);
- if (path) {
- SkPDFUtils::EmitPath(*path, paint.getStyle(), &content);
- SkPDFUtils::PaintPath(paint.getStyle(), path->getFillType(),
- &content);
+ SkScalar advance = 0.0f;
+ SkIRect glyphBBox;
+ if (skipGlyph) {
+ characterName.set("g0");
+ } else {
+ characterName.printf("g%X", gID);
+ const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
+ advance = SkFloatToScalar(glyph.fAdvanceX);
+ glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
+ glyph.fWidth, glyph.fHeight);
+ bbox.join(glyphBBox);
+ const SkPath* path = cache->findPath(glyph);
+ if (path && !path->isEmpty()) {
+ SkDynamicMemoryWStream content;
+ setGlyphWidthAndBoundingBox(SkFloatToScalar(glyph.fAdvanceX), glyphBBox,
+ &content);
+ SkPDFUtils::EmitPath(*path, SkPaint::kFill_Style, &content);
+ SkPDFUtils::PaintPath(SkPaint::kFill_Style, path->getFillType(),
+ &content);
+ charProcs->insertObjRef(
+ characterName, sk_make_sp<SkPDFStream>(
+ std::unique_ptr<SkStreamAsset>(content.detachAsStream())));
+ } else {
+ if (!emptyStream) {
+ emptyStream = sk_make_sp<SkPDFStream>(
+ std::unique_ptr<SkStreamAsset>(
+ new SkMemoryStream((size_t)0)));
+ }
+ charProcs->insertObjRef(characterName, emptyStream);
+ }
}
- charProcs->insertObjRef(
- characterName, sk_make_sp<SkPDFStream>(
- std::unique_ptr<SkStreamAsset>(content.detachAsStream())));
+ encDiffs->appendName(characterName.c_str());
+ widthArray->appendScalar(advance);
}
encoding->insertObject("Differences", std::move(encDiffs));
-
- this->insertObject("CharProcs", std::move(charProcs));
- this->insertObject("Encoding", std::move(encoding));
-
- this->insertObject("FontBBox", makeFontBBox(bbox, 1000));
- this->insertInt("FirstChar", 1);
- this->insertInt("LastChar", lastGlyphID() - firstGlyphID() + 1);
- this->insertObject("Widths", std::move(widthArray));
- this->insertName("CIDToGIDMap", "Identity");
-
- this->populateToUnicodeTable(nullptr);
- return true;
+ font->insertInt("FirstChar", 0);
+ font->insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
+ /* FontBBox: "A rectangle expressed in the glyph coordinate
+ system, specifying the font bounding box. This is the smallest
+ rectangle enclosing the shape that would result if all of the
+ glyphs of the font were placed with their origins coincident and
+ then filled." */
+ auto fontBBox = sk_make_sp<SkPDFArray>();
+ fontBBox->reserve(4);
+ fontBBox->appendInt(bbox.left());
+ fontBBox->appendInt(bbox.bottom());
+ fontBBox->appendInt(bbox.right());
+ 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) {
+ font->insertObjRef("ToUnicode",
+ SkPDFMakeToUnicodeCmap(metrics->fGlyphToUnicode,
+ subset,
+ false,
+ firstGlyphID,
+ lastGlyphID));
+ }
+ font->insertObject("Widths", std::move(widthArray));
+ font->insertObject("Encoding", std::move(encoding));
+ font->insertObject("CharProcs", std::move(charProcs));
}
+SkPDFType3Font::SkPDFType3Font(const SkAdvancedTypefaceMetrics* info,
+ SkTypeface* typeface,
+ uint16_t glyphID)
+ : SkPDFFont(info, typeface, nullptr) {
+ // If fLastGlyphID isn't set (because there is not fFontInfo), look it up.
+ this->setLastGlyphID(SkToU16(typeface->countGlyphs() - 1));
+ this->adjustGlyphRangeForSingleByteEncoding(glyphID);
+}
+
+sk_sp<SkPDFObject> SkPDFType3Font::getFontSubset(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->fontInfo();
+ uint16_t emSize = info && info->fEmSize > 0 ? info->fEmSize : 1000;
+ add_type3_font_info(font.get(), this->typeface(), (SkScalar)emSize, usage,
+ this->firstGlyphID(), this->lastGlyphID());
+ return font;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
SkPDFFont::Match SkPDFFont::IsMatch(SkPDFFont* existingFont,
uint32_t existingFontID,
uint16_t existingGlyphID,
diff --git a/src/pdf/SkPDFFont.h b/src/pdf/SkPDFFont.h
index c55f650..acf9bf8 100644
--- a/src/pdf/SkPDFFont.h
+++ b/src/pdf/SkPDFFont.h
@@ -132,7 +132,7 @@
* @return nullptr if font does not support subsetting, a new instance
* of SkPDFFont otherwise.
*/
- virtual SkPDFFont* getFontSubset(const SkPDFGlyphSet* usage);
+ virtual sk_sp<SkPDFObject> getFontSubset(const SkPDFGlyphSet* usage);
enum Match {
kExact_Match,
diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp
index afb9b72..6bf6afc 100644
--- a/src/pdf/SkPDFTypes.cpp
+++ b/src/pdf/SkPDFTypes.cpp
@@ -573,7 +573,9 @@
SkASSERT(stream->hasLength());
SkDynamicMemoryWStream compressedData;
SkDeflateWStream deflateWStream(&compressedData);
- SkStreamCopy(&deflateWStream, stream.get());
+ if (stream->getLength() > 0) {
+ SkStreamCopy(&deflateWStream, stream.get());
+ }
deflateWStream.finalize();
size_t compressedLength = compressedData.bytesWritten();
size_t originalLength = stream->getLength();