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 Review-Url: https://codereview.chromium.org/2231483002
This commit is contained in:
parent
86e7626f08
commit
88b138da99
@ -483,8 +483,8 @@ bool SkPDFDocument::onClose(SkWStream* stream) {
|
|||||||
|
|
||||||
// Build font subsetting info before calling addObjectRecursively().
|
// Build font subsetting info before calling addObjectRecursively().
|
||||||
for (const auto& entry : fGlyphUsage) {
|
for (const auto& entry : fGlyphUsage) {
|
||||||
sk_sp<SkPDFFont> subsetFont(
|
sk_sp<SkPDFObject> subsetFont =
|
||||||
entry.fFont->getFontSubset(&entry.fGlyphSet));
|
entry.fFont->getFontSubset(&entry.fGlyphSet);
|
||||||
if (subsetFont) {
|
if (subsetFont) {
|
||||||
fObjectSerializer.fSubstituteMap.setSubstitute(
|
fObjectSerializer.fSubstituteMap.setSubstitute(
|
||||||
entry.fFont, subsetFont.get());
|
entry.fFont, subsetFont.get());
|
||||||
|
@ -60,7 +60,7 @@ public:
|
|||||||
SkTypeface* typeface);
|
SkTypeface* typeface);
|
||||||
virtual ~SkPDFType0Font();
|
virtual ~SkPDFType0Font();
|
||||||
bool multiByteGlyphs() const override { return true; }
|
bool multiByteGlyphs() const override { return true; }
|
||||||
SkPDFFont* getFontSubset(const SkPDFGlyphSet* usage) override;
|
sk_sp<SkPDFObject> getFontSubset(const SkPDFGlyphSet* usage) override;
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
void emitObject(SkWStream*,
|
void emitObject(SkWStream*,
|
||||||
const SkPDFObjNumMap&,
|
const SkPDFObjNumMap&,
|
||||||
@ -108,11 +108,14 @@ public:
|
|||||||
SkPDFType3Font(const SkAdvancedTypefaceMetrics* info,
|
SkPDFType3Font(const SkAdvancedTypefaceMetrics* info,
|
||||||
SkTypeface* typeface,
|
SkTypeface* typeface,
|
||||||
uint16_t glyphID);
|
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; }
|
bool multiByteGlyphs() const override { return false; }
|
||||||
|
|
||||||
private:
|
|
||||||
bool populate(uint16_t glyphID);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -335,7 +338,7 @@ SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
|
|||||||
|
|
||||||
|
|
||||||
void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
|
void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
|
||||||
SkWStream* content) {
|
SkDynamicMemoryWStream* content) {
|
||||||
// Specify width and bounding box for the glyph.
|
// Specify width and bounding box for the glyph.
|
||||||
SkPDFUtils::AppendScalar(width, content);
|
SkPDFUtils::AppendScalar(width, content);
|
||||||
content->writeText(" 0 ");
|
content->writeText(" 0 ");
|
||||||
@ -559,7 +562,7 @@ SkPDFFont* SkPDFFont::GetFontResource(SkPDFCanon* canon,
|
|||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPDFFont* SkPDFFont::getFontSubset(const SkPDFGlyphSet*) {
|
sk_sp<SkPDFObject> SkPDFFont::getFontSubset(const SkPDFGlyphSet*) {
|
||||||
return nullptr; // Default: no support.
|
return nullptr; // Default: no support.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -571,12 +574,13 @@ SkPDFFont::SkPDFFont(const SkAdvancedTypefaceMetrics* info,
|
|||||||
, fFirstGlyphID(1)
|
, fFirstGlyphID(1)
|
||||||
, fLastGlyphID(info ? info->fLastGlyphID : 0)
|
, fLastGlyphID(info ? info->fLastGlyphID : 0)
|
||||||
, fFontInfo(SkSafeRef(info))
|
, fFontInfo(SkSafeRef(info))
|
||||||
, fDescriptor(SkSafeRef(relatedFontDescriptor)) {
|
, fDescriptor(SkSafeRef(relatedFontDescriptor))
|
||||||
if (info == nullptr ||
|
, fFontType((!info || info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)
|
||||||
info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag) {
|
? SkAdvancedTypefaceMetrics::kOther_Font
|
||||||
fFontType = SkAdvancedTypefaceMetrics::kOther_Font;
|
: info->fType) {
|
||||||
} else {
|
if (0 == fLastGlyphID) {
|
||||||
fFontType = info->fType;
|
SkAutoResolveDefaultTypeface face(typeface);
|
||||||
|
fLastGlyphID = SkToU16(face->countGlyphs() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,23 +592,28 @@ SkPDFFont* SkPDFFont::Create(SkPDFCanon* canon,
|
|||||||
SkPDFDict* relatedFontDescriptor) {
|
SkPDFDict* relatedFontDescriptor) {
|
||||||
SkAdvancedTypefaceMetrics::FontType type =
|
SkAdvancedTypefaceMetrics::FontType type =
|
||||||
info ? info->fType : SkAdvancedTypefaceMetrics::kOther_Font;
|
info ? info->fType : SkAdvancedTypefaceMetrics::kOther_Font;
|
||||||
|
SkAdvancedTypefaceMetrics::FontFlags flags =
|
||||||
if (info && (info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) {
|
info ? info->fFlags : SkAdvancedTypefaceMetrics::kEmpty_FontFlag;
|
||||||
|
if (SkToBool(flags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) {
|
||||||
return new SkPDFType3Font(info, typeface, glyphID);
|
return new SkPDFType3Font(info, typeface, glyphID);
|
||||||
}
|
}
|
||||||
if (type == SkAdvancedTypefaceMetrics::kType1CID_Font ||
|
switch (type) {
|
||||||
type == SkAdvancedTypefaceMetrics::kTrueType_Font) {
|
case SkAdvancedTypefaceMetrics::kType1CID_Font:
|
||||||
SkASSERT(relatedFontDescriptor == nullptr);
|
case SkAdvancedTypefaceMetrics::kTrueType_Font:
|
||||||
return new SkPDFType0Font(info, typeface);
|
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) {
|
SkDEBUGFAIL("invalid SkAdvancedTypefaceMetrics::FontType");
|
||||||
return new SkPDFType1Font(info, typeface, glyphID, relatedFontDescriptor);
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
SkASSERT(type == SkAdvancedTypefaceMetrics::kCFF_Font ||
|
|
||||||
type == SkAdvancedTypefaceMetrics::kOther_Font);
|
|
||||||
|
|
||||||
return new SkPDFType3Font(info, typeface, glyphID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SkAdvancedTypefaceMetrics* SkPDFFont::fontInfo() {
|
const SkAdvancedTypefaceMetrics* SkPDFFont::fontInfo() {
|
||||||
@ -703,11 +712,11 @@ SkPDFType0Font::SkPDFType0Font(const SkAdvancedTypefaceMetrics* info, SkTypeface
|
|||||||
|
|
||||||
SkPDFType0Font::~SkPDFType0Font() {}
|
SkPDFType0Font::~SkPDFType0Font() {}
|
||||||
|
|
||||||
SkPDFFont* SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) {
|
sk_sp<SkPDFObject> SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) {
|
||||||
if (!canSubset()) {
|
if (!canSubset()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
SkPDFType0Font* newSubset = new SkPDFType0Font(fontInfo(), typeface());
|
auto newSubset = sk_make_sp<SkPDFType0Font>(fontInfo(), typeface());
|
||||||
newSubset->populate(subset);
|
newSubset->populate(subset);
|
||||||
return newSubset;
|
return newSubset;
|
||||||
}
|
}
|
||||||
@ -878,7 +887,8 @@ void set_glyph_widths(SkTypeface* tf,
|
|||||||
tmpPaint.setHinting(SkPaint::kNo_Hinting);
|
tmpPaint.setHinting(SkPaint::kNo_Hinting);
|
||||||
tmpPaint.setTypeface(sk_ref_sp(tf));
|
tmpPaint.setTypeface(sk_ref_sp(tf));
|
||||||
tmpPaint.setTextSize((SkScalar)tf->getUnitsPerEm());
|
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()) {
|
if (!glyphIDs || glyphIDs->isEmpty()) {
|
||||||
get_glyph_widths(dst, tf->countGlyphs(), nullptr, 0, autoGlyphCache.get());
|
get_glyph_widths(dst, tf->countGlyphs(), nullptr, 0, autoGlyphCache.get());
|
||||||
} else {
|
} else {
|
||||||
@ -1017,7 +1027,8 @@ bool SkPDFType1Font::populate(int16_t glyphID) {
|
|||||||
tmpPaint.setHinting(SkPaint::kNo_Hinting);
|
tmpPaint.setHinting(SkPaint::kNo_Hinting);
|
||||||
tmpPaint.setTypeface(sk_ref_sp(this->typeface()));
|
tmpPaint.setTypeface(sk_ref_sp(this->typeface()));
|
||||||
tmpPaint.setTextSize((SkScalar)this->typeface()->getUnitsPerEm());
|
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>();
|
auto widths = sk_make_sp<SkPDFArray>();
|
||||||
SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX;
|
SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX;
|
||||||
const uint16_t emSize = this->fontInfo()->fEmSize;
|
const uint16_t emSize = this->fontInfo()->fEmSize;
|
||||||
@ -1054,85 +1065,177 @@ bool SkPDFType1Font::populate(int16_t glyphID) {
|
|||||||
// class SkPDFType3Font
|
// class SkPDFType3Font
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SkPDFType3Font::SkPDFType3Font(const SkAdvancedTypefaceMetrics* info,
|
namespace {
|
||||||
SkTypeface* typeface,
|
// returns [0, first, first+1, ... last-1, last]
|
||||||
uint16_t glyphID)
|
struct SingleByteGlyphIdIterator {
|
||||||
: SkPDFFont(info, typeface, nullptr) {
|
SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
|
||||||
this->populate(glyphID);
|
: 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() {}
|
static void add_type3_font_info(SkPDFDict* font,
|
||||||
|
SkTypeface* typeface,
|
||||||
bool SkPDFType3Font::populate(uint16_t glyphID) {
|
SkScalar emSize,
|
||||||
|
const SkPDFGlyphSet* subset,
|
||||||
|
SkGlyphID firstGlyphID,
|
||||||
|
SkGlyphID lastGlyphID) {
|
||||||
|
SkASSERT(lastGlyphID >= firstGlyphID);
|
||||||
SkPaint paint;
|
SkPaint paint;
|
||||||
paint.setTypeface(sk_ref_sp(this->typeface()));
|
paint.setHinting(SkPaint::kNo_Hinting);
|
||||||
paint.setTextSize(1000);
|
paint.setTypeface(sk_ref_sp(typeface));
|
||||||
|
paint.setTextSize(emSize);
|
||||||
const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
|
const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
|
||||||
SkAutoGlyphCache autoCache(paint, &props, nullptr);
|
SkAutoGlyphCache cache(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
adjustGlyphRangeForSingleByteEncoding(glyphID);
|
font->insertName("Subtype", "Type3");
|
||||||
|
// Flip about the x-axis and scale by 1/emSize.
|
||||||
insertName("Subtype", "Type3");
|
|
||||||
// Flip about the x-axis and scale by 1/1000.
|
|
||||||
SkMatrix fontMatrix;
|
SkMatrix fontMatrix;
|
||||||
fontMatrix.setScale(SkScalarInvert(1000), -SkScalarInvert(1000));
|
fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
|
||||||
this->insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
|
font->insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
|
||||||
|
|
||||||
auto charProcs = sk_make_sp<SkPDFDict>();
|
auto charProcs = sk_make_sp<SkPDFDict>();
|
||||||
auto encoding = sk_make_sp<SkPDFDict>("Encoding");
|
auto encoding = sk_make_sp<SkPDFDict>("Encoding");
|
||||||
|
|
||||||
auto encDiffs = sk_make_sp<SkPDFArray>();
|
auto encDiffs = sk_make_sp<SkPDFArray>();
|
||||||
encDiffs->reserve(lastGlyphID() - firstGlyphID() + 2);
|
// length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
|
||||||
encDiffs->appendInt(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>();
|
auto widthArray = sk_make_sp<SkPDFArray>();
|
||||||
|
widthArray->reserve(glyphCount);
|
||||||
|
|
||||||
SkIRect bbox = SkIRect::MakeEmpty();
|
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;
|
SkString characterName;
|
||||||
characterName.printf("gid%d", gID);
|
SkScalar advance = 0.0f;
|
||||||
encDiffs->appendName(characterName.c_str());
|
SkIRect glyphBBox;
|
||||||
|
if (skipGlyph) {
|
||||||
const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
|
characterName.set("g0");
|
||||||
widthArray->appendScalar(SkFloatToScalar(glyph.fAdvanceX));
|
} else {
|
||||||
SkIRect glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
|
characterName.printf("g%X", gID);
|
||||||
glyph.fWidth, glyph.fHeight);
|
const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
|
||||||
bbox.join(glyphBBox);
|
advance = SkFloatToScalar(glyph.fAdvanceX);
|
||||||
|
glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
|
||||||
SkDynamicMemoryWStream content;
|
glyph.fWidth, glyph.fHeight);
|
||||||
setGlyphWidthAndBoundingBox(SkFloatToScalar(glyph.fAdvanceX), glyphBBox,
|
bbox.join(glyphBBox);
|
||||||
&content);
|
const SkPath* path = cache->findPath(glyph);
|
||||||
const SkPath* path = cache->findPath(glyph);
|
if (path && !path->isEmpty()) {
|
||||||
if (path) {
|
SkDynamicMemoryWStream content;
|
||||||
SkPDFUtils::EmitPath(*path, paint.getStyle(), &content);
|
setGlyphWidthAndBoundingBox(SkFloatToScalar(glyph.fAdvanceX), glyphBBox,
|
||||||
SkPDFUtils::PaintPath(paint.getStyle(), path->getFillType(),
|
&content);
|
||||||
&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(
|
encDiffs->appendName(characterName.c_str());
|
||||||
characterName, sk_make_sp<SkPDFStream>(
|
widthArray->appendScalar(advance);
|
||||||
std::unique_ptr<SkStreamAsset>(content.detachAsStream())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
encoding->insertObject("Differences", std::move(encDiffs));
|
encoding->insertObject("Differences", std::move(encDiffs));
|
||||||
|
font->insertInt("FirstChar", 0);
|
||||||
this->insertObject("CharProcs", std::move(charProcs));
|
font->insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
|
||||||
this->insertObject("Encoding", std::move(encoding));
|
/* FontBBox: "A rectangle expressed in the glyph coordinate
|
||||||
|
system, specifying the font bounding box. This is the smallest
|
||||||
this->insertObject("FontBBox", makeFontBBox(bbox, 1000));
|
rectangle enclosing the shape that would result if all of the
|
||||||
this->insertInt("FirstChar", 1);
|
glyphs of the font were placed with their origins coincident and
|
||||||
this->insertInt("LastChar", lastGlyphID() - firstGlyphID() + 1);
|
then filled." */
|
||||||
this->insertObject("Widths", std::move(widthArray));
|
auto fontBBox = sk_make_sp<SkPDFArray>();
|
||||||
this->insertName("CIDToGIDMap", "Identity");
|
fontBBox->reserve(4);
|
||||||
|
fontBBox->appendInt(bbox.left());
|
||||||
this->populateToUnicodeTable(nullptr);
|
fontBBox->appendInt(bbox.bottom());
|
||||||
return true;
|
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);
|
||||||
|
}
|
||||||
|
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,
|
SkPDFFont::Match SkPDFFont::IsMatch(SkPDFFont* existingFont,
|
||||||
uint32_t existingFontID,
|
uint32_t existingFontID,
|
||||||
uint16_t existingGlyphID,
|
uint16_t existingGlyphID,
|
||||||
|
@ -132,7 +132,7 @@ public:
|
|||||||
* @return nullptr if font does not support subsetting, a new instance
|
* @return nullptr if font does not support subsetting, a new instance
|
||||||
* of SkPDFFont otherwise.
|
* of SkPDFFont otherwise.
|
||||||
*/
|
*/
|
||||||
virtual SkPDFFont* getFontSubset(const SkPDFGlyphSet* usage);
|
virtual sk_sp<SkPDFObject> getFontSubset(const SkPDFGlyphSet* usage);
|
||||||
|
|
||||||
enum Match {
|
enum Match {
|
||||||
kExact_Match,
|
kExact_Match,
|
||||||
|
@ -573,7 +573,9 @@ void SkPDFStream::setData(std::unique_ptr<SkStreamAsset> stream) {
|
|||||||
SkASSERT(stream->hasLength());
|
SkASSERT(stream->hasLength());
|
||||||
SkDynamicMemoryWStream compressedData;
|
SkDynamicMemoryWStream compressedData;
|
||||||
SkDeflateWStream deflateWStream(&compressedData);
|
SkDeflateWStream deflateWStream(&compressedData);
|
||||||
SkStreamCopy(&deflateWStream, stream.get());
|
if (stream->getLength() > 0) {
|
||||||
|
SkStreamCopy(&deflateWStream, stream.get());
|
||||||
|
}
|
||||||
deflateWStream.finalize();
|
deflateWStream.finalize();
|
||||||
size_t compressedLength = compressedData.bytesWritten();
|
size_t compressedLength = compressedData.bytesWritten();
|
||||||
size_t originalLength = stream->getLength();
|
size_t originalLength = stream->getLength();
|
||||||
|
Loading…
Reference in New Issue
Block a user