1 /*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/pdf/SkPDFFont.h"
9
10 #include "include/codec/SkCodec.h"
11 #include "include/core/SkAlphaType.h"
12 #include "include/core/SkBitmap.h"
13 #include "include/core/SkCanvas.h"
14 #include "include/core/SkColorType.h"
15 #include "include/core/SkData.h"
16 #include "include/core/SkDrawable.h"
17 #include "include/core/SkFont.h"
18 #include "include/core/SkFontMetrics.h"
19 #include "include/core/SkFontStyle.h"
20 #include "include/core/SkFontTypes.h"
21 #include "include/core/SkImage.h"
22 #include "include/core/SkImageInfo.h"
23 #include "include/core/SkMaskFilter.h"
24 #include "include/core/SkMatrix.h"
25 #include "include/core/SkPaint.h"
26 #include "include/core/SkPath.h"
27 #include "include/core/SkPathTypes.h"
28 #include "include/core/SkPixmap.h"
29 #include "include/core/SkPoint.h"
30 #include "include/core/SkRect.h"
31 #include "include/core/SkRefCnt.h"
32 #include "include/core/SkScalar.h"
33 #include "include/core/SkSize.h"
34 #include "include/core/SkStream.h"
35 #include "include/core/SkString.h"
36 #include "include/core/SkTypeface.h"
37 #include "include/docs/SkPDFDocument.h"
38 #include "include/effects/SkDashPathEffect.h"
39 #include "include/private/base/SkDebug.h"
40 #include "include/private/base/SkTPin.h"
41 #include "include/private/base/SkTemplates.h"
42 #include "include/private/base/SkTo.h"
43 #include "src/base/SkBitmaskEnum.h"
44 #include "src/core/SkDescriptor.h"
45 #include "src/core/SkDevice.h"
46 #include "src/core/SkGlyph.h"
47 #include "src/core/SkMask.h"
48 #include "src/core/SkMaskFilterBase.h"
49 #include "src/core/SkPathEffectBase.h"
50 #include "src/core/SkStrike.h"
51 #include "src/core/SkStrikeSpec.h"
52 #include "src/core/SkTHash.h"
53 #include "src/pdf/SkPDFBitmap.h"
54 #include "src/pdf/SkPDFDevice.h"
55 #include "src/pdf/SkPDFDocumentPriv.h"
56 #include "src/pdf/SkPDFFormXObject.h"
57 #include "src/pdf/SkPDFGraphicState.h"
58 #include "src/pdf/SkPDFMakeCIDGlyphWidthsArray.h"
59 #include "src/pdf/SkPDFMakeToUnicodeCmap.h"
60 #include "src/pdf/SkPDFSubsetFont.h"
61 #include "src/pdf/SkPDFType1Font.h"
62 #include "src/pdf/SkPDFUtils.h"
63
64 #include <limits.h>
65 #include <algorithm>
66 #include <cstddef>
67 #include <initializer_list>
68 #include <memory>
69 #include <utility>
70
71 using namespace skia_private;
72
GetType1GlyphNames(const SkTypeface & face,SkString * dst)73 void SkPDFFont::GetType1GlyphNames(const SkTypeface& face, SkString* dst) {
74 face.getPostScriptGlyphNames(dst);
75 }
76
77 namespace {
78 // PDF's notion of symbolic vs non-symbolic is related to the character set, not
79 // symbols vs. characters. Rarely is a font the right character set to call it
80 // non-symbolic, so always call it symbolic. (PDF 1.4 spec, section 5.7.1)
81 static const int32_t kPdfSymbolic = 4;
82
83 // scale from em-units to base-1000, returning as a SkScalar
from_font_units(SkScalar scaled,uint16_t emSize)84 inline SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
85 return emSize == 1000 ? scaled : scaled * 1000 / emSize;
86 }
87
scaleFromFontUnits(int16_t val,uint16_t emSize)88 inline SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
89 return from_font_units(SkIntToScalar(val), emSize);
90 }
91
setGlyphWidthAndBoundingBox(SkScalar width,SkIRect box,SkDynamicMemoryWStream * content)92 void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
93 SkDynamicMemoryWStream* content) {
94 // Specify width and bounding box for the glyph.
95 SkPDFUtils::AppendScalar(width, content);
96 content->writeText(" 0 ");
97 content->writeDecAsText(box.fLeft);
98 content->writeText(" ");
99 content->writeDecAsText(box.fTop);
100 content->writeText(" ");
101 content->writeDecAsText(box.fRight);
102 content->writeText(" ");
103 content->writeDecAsText(box.fBottom);
104 content->writeText(" d1\n");
105 }
106
107 } // namespace
108
scale_paint(SkPaint & paint,SkScalar fontToEMScale)109 static bool scale_paint(SkPaint& paint, SkScalar fontToEMScale) {
110 // What we really want here is a way ask the path effect or mask filter for a scaled
111 // version of itself (if it is linearly scalable).
112
113 if (SkMaskFilterBase* mfb = as_MFB(paint.getMaskFilter())) {
114 SkMaskFilterBase::BlurRec blurRec;
115 if (mfb->asABlur(&blurRec)) {
116 // asABlur returns false if ignoring the CTM
117 blurRec.fSigma *= fontToEMScale;
118 paint.setMaskFilter(SkMaskFilter::MakeBlur(blurRec.fStyle, blurRec.fSigma, true));
119 } else {
120 return false;
121 }
122 }
123 if (SkPathEffectBase* peb = as_PEB(paint.getPathEffect())) {
124 AutoSTMalloc<4, SkScalar> intervals;
125 SkPathEffectBase::DashInfo dashInfo(intervals, 4, 0);
126 if (peb->asADash(&dashInfo) == SkPathEffectBase::DashType::kDash) {
127 if (dashInfo.fCount > 4) {
128 intervals.realloc(dashInfo.fCount);
129 peb->asADash(&dashInfo);
130 }
131 for (int32_t i = 0; i < dashInfo.fCount; ++i) {
132 dashInfo.fIntervals[i] *= fontToEMScale;
133 }
134 dashInfo.fPhase *= fontToEMScale;
135 paint.setPathEffect(
136 SkDashPathEffect::Make(dashInfo.fIntervals, dashInfo.fCount, dashInfo.fPhase));
137 } else {
138 return false;
139 }
140 }
141
142 if (paint.getStyle() != SkPaint::kFill_Style && paint.getStrokeWidth() > 0) {
143 paint.setStrokeWidth(paint.getStrokeWidth() * fontToEMScale);
144 }
145
146 return true;
147 }
148
149
SkPDFStrikeSpec(SkStrikeSpec strikeSpec,SkScalar em)150 SkPDFStrikeSpec::SkPDFStrikeSpec(SkStrikeSpec strikeSpec, SkScalar em)
151 : fStrikeSpec(std::move(strikeSpec))
152 , fUnitsPerEM(em)
153 {}
154
Make(SkPDFDocument * doc,const SkFont & font,const SkPaint & paint)155 sk_sp<SkPDFStrike> SkPDFStrike::Make(SkPDFDocument* doc, const SkFont& font, const SkPaint& paint) {
156 #ifdef SK_PDF_BITMAP_GLYPH_RASTER_SIZE
157 static constexpr float kBitmapFontSize = SK_PDF_BITMAP_GLYPH_RASTER_SIZE;
158 #else
159 static constexpr float kBitmapFontSize = 64;
160 #endif
161
162 SkScalar unitsPerEm = static_cast<SkScalar>(font.getTypeface()->getUnitsPerEm());
163 SkASSERT(0 < unitsPerEm);
164
165 SkFont canonFont(font);
166 canonFont.setBaselineSnap(false); // canonicalize
167 canonFont.setEdging(SkFont::Edging::kAntiAlias); // canonicalize
168 canonFont.setEmbeddedBitmaps(false); // canonicalize
169 //canonFont.setEmbolden(); // applied by scaler context, sets glyph path to modified
170 canonFont.setForceAutoHinting(false); // canonicalize
171 canonFont.setHinting(SkFontHinting::kNone); // canonicalize
172 canonFont.setLinearMetrics(true); // canonicalize
173 canonFont.setScaleX(1.0f); // original value applied by SkPDFDevice
174 //canonFont.setSize(unitsPerEm); // canonicalize below, adjusted by SkPDFDevice
175 canonFont.setSkewX(0.0f); // original value applied by SkPDFDevice
176 canonFont.setSubpixel(false); // canonicalize
177 //canonFont.setTypeface();
178
179 SkPaint pathPaint(paint);
180 if (scale_paint(pathPaint, unitsPerEm / font.getSize())) {
181 canonFont.setSize(unitsPerEm);
182 } else {
183 canonFont.setSize(font.getSize());
184 }
185 SkScalar pathStrikeEM = canonFont.getSize();
186 SkStrikeSpec pathStrikeSpec = SkStrikeSpec::MakeWithNoDevice(canonFont, &pathPaint);
187
188 if (sk_sp<SkPDFStrike>* strike = doc->fStrikes.find(pathStrikeSpec.descriptor())) {
189 return *strike;
190 }
191
192 if (kBitmapFontSize <= 0) {
193 // old code path compatibility
194 sk_sp<SkPDFStrike> strike(new SkPDFStrike(SkPDFStrikeSpec(pathStrikeSpec, pathStrikeEM),
195 SkPDFStrikeSpec(pathStrikeSpec, pathStrikeEM),
196 pathPaint.getMaskFilter(), doc));
197 doc->fStrikes.set(strike);
198 return strike;
199 }
200
201 SkPaint imagePaint(paint);
202 if (scale_paint(imagePaint, kBitmapFontSize / font.getSize())) {
203 canonFont.setSize(kBitmapFontSize);
204 } else {
205 canonFont.setSize(font.getSize());
206 }
207 SkScalar imageStrikeEM = canonFont.getSize();
208 SkStrikeSpec imageStrikeSpec = SkStrikeSpec::MakeWithNoDevice(canonFont, &imagePaint);
209
210 sk_sp<SkPDFStrike> strike(new SkPDFStrike(SkPDFStrikeSpec(pathStrikeSpec, pathStrikeEM),
211 SkPDFStrikeSpec(imageStrikeSpec, imageStrikeEM),
212 pathPaint.getMaskFilter(), doc));
213 doc->fStrikes.set(strike);
214 return strike;
215
216 }
217
SkPDFStrike(SkPDFStrikeSpec path,SkPDFStrikeSpec image,bool hasMaskFilter,SkPDFDocument * doc)218 SkPDFStrike::SkPDFStrike(SkPDFStrikeSpec path, SkPDFStrikeSpec image, bool hasMaskFilter,
219 SkPDFDocument* doc)
220 : fPath(std::move(path))
221 , fImage(std::move(image))
222 , fHasMaskFilter(hasMaskFilter)
223 , fDoc(doc)
224 {
225 SkASSERT(fDoc);
226 }
227
GetKey(const sk_sp<SkPDFStrike> & strike)228 const SkDescriptor& SkPDFStrike::Traits::GetKey(const sk_sp<SkPDFStrike>& strike) {
229 return strike->fPath.fStrikeSpec.descriptor();
230 }
Hash(const SkDescriptor & descriptor)231 uint32_t SkPDFStrike::Traits::Hash(const SkDescriptor& descriptor) {
232 return descriptor.getChecksum();
233 }
234
235 ///////////////////////////////////////////////////////////////////////////////
236 // class SkPDFFont
237 ///////////////////////////////////////////////////////////////////////////////
238
239 /* Resources are canonicalized and uniqueified by pointer so there has to be
240 * some additional state indicating which subset of the font is used. It
241 * must be maintained at the document granularity.
242 */
243
244 SkPDFFont::~SkPDFFont() = default;
245
246 SkPDFFont::SkPDFFont(SkPDFFont&&) = default;
247
can_embed(const SkAdvancedTypefaceMetrics & metrics)248 static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) {
249 return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
250 }
251
can_subset(const SkAdvancedTypefaceMetrics & metrics)252 static bool can_subset(const SkAdvancedTypefaceMetrics& metrics) {
253 return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag);
254 }
255
GetMetrics(const SkTypeface & typeface,SkPDFDocument * canon)256 const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(const SkTypeface& typeface,
257 SkPDFDocument* canon) {
258 SkTypefaceID id = typeface.uniqueID();
259 if (std::unique_ptr<SkAdvancedTypefaceMetrics>* ptr = canon->fTypefaceMetrics.find(id)) {
260 return ptr->get(); // canon retains ownership.
261 }
262
263 int count = typeface.countGlyphs();
264 if (count <= 0 || count > 1 + SkTo<int>(UINT16_MAX)) {
265 // Cache nullptr to skip this check. Use SkSafeUnref().
266 canon->fTypefaceMetrics.set(id, nullptr);
267 return nullptr;
268 }
269
270 std::unique_ptr<SkAdvancedTypefaceMetrics> metrics = typeface.getAdvancedMetrics();
271 if (!metrics) {
272 metrics = std::make_unique<SkAdvancedTypefaceMetrics>();
273 }
274 if (0 == metrics->fStemV || 0 == metrics->fCapHeight) {
275 SkFont font;
276 font.setHinting(SkFontHinting::kNone);
277 font.setTypeface(sk_ref_sp(&typeface));
278 font.setSize(1000); // glyph coordinate system
279 if (0 == metrics->fStemV) {
280 // Figure out a good guess for StemV - Min width of i, I, !, 1.
281 // This probably isn't very good with an italic font.
282 int16_t stemV = SHRT_MAX;
283 for (char c : {'i', 'I', '!', '1'}) {
284 SkGlyphID g = font.unicharToGlyph(c);
285 SkRect bounds;
286 font.getBounds(&g, 1, &bounds, nullptr);
287 stemV = std::min(stemV, SkToS16(SkScalarRoundToInt(bounds.width())));
288 }
289 metrics->fStemV = stemV;
290 }
291 if (0 == metrics->fCapHeight) {
292 // Figure out a good guess for CapHeight: average the height of M and X.
293 SkScalar capHeight = 0;
294 for (char c : {'M', 'X'}) {
295 SkGlyphID g = font.unicharToGlyph(c);
296 SkRect bounds;
297 font.getBounds(&g, 1, &bounds, nullptr);
298 capHeight += bounds.height();
299 }
300 metrics->fCapHeight = SkToS16(SkScalarRoundToInt(capHeight / 2));
301 }
302 }
303 // Fonts are always subset, so always prepend the subset tag.
304 metrics->fPostScriptName.prepend(canon->nextFontSubsetTag());
305 return canon->fTypefaceMetrics.set(id, std::move(metrics))->get();
306 }
307
GetUnicodeMap(const SkTypeface & typeface,SkPDFDocument * canon)308 const std::vector<SkUnichar>& SkPDFFont::GetUnicodeMap(const SkTypeface& typeface,
309 SkPDFDocument* canon) {
310 SkASSERT(canon);
311 SkTypefaceID id = typeface.uniqueID();
312 if (std::vector<SkUnichar>* ptr = canon->fToUnicodeMap.find(id)) {
313 return *ptr;
314 }
315 std::vector<SkUnichar> buffer(typeface.countGlyphs());
316 typeface.getGlyphToUnicodeMap(buffer.data());
317 return *canon->fToUnicodeMap.set(id, std::move(buffer));
318 }
319
GetUnicodeMapEx(const SkTypeface & typeface,SkPDFDocument * canon)320 THashMap<SkGlyphID, SkString>& SkPDFFont::GetUnicodeMapEx(const SkTypeface& typeface,
321 SkPDFDocument* canon) {
322 SkASSERT(canon);
323 SkTypefaceID id = typeface.uniqueID();
324 if (THashMap<SkGlyphID, SkString>* ptr = canon->fToUnicodeMapEx.find(id)) {
325 return *ptr;
326 }
327 return *canon->fToUnicodeMapEx.set(id, THashMap<SkGlyphID, SkString>());
328 }
329
FontType(const SkPDFStrike & pdfStrike,const SkAdvancedTypefaceMetrics & metrics)330 SkAdvancedTypefaceMetrics::FontType SkPDFFont::FontType(const SkPDFStrike& pdfStrike,
331 const SkAdvancedTypefaceMetrics& metrics) {
332 if (SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kVariable_FontFlag) ||
333 // PDF is actually interested in the encoding of the data, not just the logical format.
334 // If the TrueType is actually wOFF or wOF2 then it should not be directly embedded in PDF.
335 // For now export these as Type3 until the subsetter can handle table based fonts.
336 // See https://github.com/harfbuzz/harfbuzz/issues/3609 and
337 // https://skia-review.googlesource.com/c/skia/+/543485
338 SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kAltDataFormat_FontFlag) ||
339 SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag) ||
340 // Something like 45eeeddb00741493 and 7c86e7641b348ca7b0 to output OpenType should work,
341 // but requires PDF 1.6 which is still not supported by all printers. One could fix this by
342 // using bare CFF like 31a170226c22244cbd00497b67f6ae181f0f3e76 which is only PDF 1.3,
343 // but this only works when the CFF CIDs == CFF index == GlyphID as PDF bare CFF prefers
344 // CFF CIDs instead of GlyphIDs and Skia doesn't know the CIDs.
345 metrics.fType == SkAdvancedTypefaceMetrics::kCFF_Font ||
346 pdfStrike.fHasMaskFilter)
347 {
348 // force Type3 fallback.
349 return SkAdvancedTypefaceMetrics::kOther_Font;
350 }
351 return metrics.fType;
352 }
353
first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid)354 static SkGlyphID first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid) {
355 return gid != 0 ? gid - (gid - 1) % 255 : 1;
356 }
357
getFontResource(const SkGlyph * glyph)358 SkPDFFont* SkPDFStrike::getFontResource(const SkGlyph* glyph) {
359 const SkTypeface& typeface = fPath.fStrikeSpec.typeface();
360 const SkAdvancedTypefaceMetrics* fontMetrics = SkPDFFont::GetMetrics(typeface, fDoc);
361 SkASSERT(fontMetrics); // SkPDFDevice::internalDrawText ensures the typeface is good.
362 // GetMetrics only returns null to signify a bad typeface.
363 const SkAdvancedTypefaceMetrics& metrics = *fontMetrics;
364
365 // Determine the FontType.
366 // 1. Can the "original" font data be used directly
367 // (simple OpenType, no non-default variations, not WOFF, etc).
368 // 2. Is the glyph to be drawn unmodified from the font data
369 // (no path effect, stroking, fake bolding, extra matrix, mask filter).
370 // 3. Will PDF viewers draw this glyph the way we want
371 // (at the moment this means an unmodified glyph path).
372 SkAdvancedTypefaceMetrics::FontType type = SkPDFFont::FontType(*this, metrics);
373 // Keep the type (and original data) if the glyph is empty or the glyph has an unmodified path.
374 // Otherwise, fall back to Type3.
375 if (!(glyph->isEmpty() || (glyph->path() && !glyph->pathIsModified()))) {
376 type = SkAdvancedTypefaceMetrics::kOther_Font;
377 }
378
379 bool multibyte = SkPDFFont::IsMultiByte(type);
380 SkGlyphID subsetCode =
381 multibyte ? 0 : first_nonzero_glyph_for_single_byte_encoding(glyph->getGlyphID());
382 if (SkPDFFont* font = fFontMap.find(subsetCode)) {
383 SkASSERT(multibyte == font->multiByteGlyphs());
384 return font;
385 }
386
387 SkGlyphID lastGlyph = SkToU16(typeface.countGlyphs() - 1);
388 SkASSERT(glyph->getGlyphID() <= lastGlyph); // should be caught by SkPDFDevice::internalDrawText
389
390 SkGlyphID firstNonZeroGlyph;
391 if (multibyte) {
392 firstNonZeroGlyph = 1;
393 } else {
394 firstNonZeroGlyph = subsetCode;
395 lastGlyph = SkToU16(std::min<int>((int)lastGlyph, 254 + (int)subsetCode));
396 }
397 auto ref = fDoc->reserveRef();
398 return fFontMap.set(subsetCode, SkPDFFont(this, firstNonZeroGlyph, lastGlyph, type, ref));
399 }
400
SkPDFFont(const SkPDFStrike * strike,SkGlyphID firstGlyphID,SkGlyphID lastGlyphID,SkAdvancedTypefaceMetrics::FontType fontType,SkPDFIndirectReference indirectReference)401 SkPDFFont::SkPDFFont(const SkPDFStrike* strike,
402 SkGlyphID firstGlyphID,
403 SkGlyphID lastGlyphID,
404 SkAdvancedTypefaceMetrics::FontType fontType,
405 SkPDFIndirectReference indirectReference)
406 : fStrike(strike)
407 , fGlyphUsage(firstGlyphID, lastGlyphID)
408 , fIndirectReference(indirectReference)
409 , fFontType(fontType)
410 {
411 // Always include glyph 0
412 this->noteGlyphUsage(0);
413 }
414
PopulateCommonFontDescriptor(SkPDFDict * descriptor,const SkAdvancedTypefaceMetrics & metrics,uint16_t emSize,int16_t defaultWidth)415 void SkPDFFont::PopulateCommonFontDescriptor(SkPDFDict* descriptor,
416 const SkAdvancedTypefaceMetrics& metrics,
417 uint16_t emSize,
418 int16_t defaultWidth) {
419 descriptor->insertName("FontName", metrics.fPostScriptName);
420 descriptor->insertInt("Flags", (size_t)(metrics.fStyle | kPdfSymbolic));
421 descriptor->insertScalar("Ascent",
422 scaleFromFontUnits(metrics.fAscent, emSize));
423 descriptor->insertScalar("Descent",
424 scaleFromFontUnits(metrics.fDescent, emSize));
425 descriptor->insertScalar("StemV",
426 scaleFromFontUnits(metrics.fStemV, emSize));
427 descriptor->insertScalar("CapHeight",
428 scaleFromFontUnits(metrics.fCapHeight, emSize));
429 descriptor->insertInt("ItalicAngle", metrics.fItalicAngle);
430 descriptor->insertObject("FontBBox",
431 SkPDFMakeArray(scaleFromFontUnits(metrics.fBBox.left(), emSize),
432 scaleFromFontUnits(metrics.fBBox.bottom(), emSize),
433 scaleFromFontUnits(metrics.fBBox.right(), emSize),
434 scaleFromFontUnits(metrics.fBBox.top(), emSize)));
435 if (defaultWidth > 0) {
436 descriptor->insertScalar("MissingWidth",
437 scaleFromFontUnits(defaultWidth, emSize));
438 }
439 }
440
441 ///////////////////////////////////////////////////////////////////////////////
442 // Type0Font
443 ///////////////////////////////////////////////////////////////////////////////
444
emit_subset_type0(const SkPDFFont & font,SkPDFDocument * doc)445 static void emit_subset_type0(const SkPDFFont& font, SkPDFDocument* doc) {
446 const SkTypeface& typeface = font.strike().fPath.fStrikeSpec.typeface();
447 const SkAdvancedTypefaceMetrics* metricsPtr = SkPDFFont::GetMetrics(typeface, doc);
448 SkASSERT(metricsPtr);
449 if (!metricsPtr) {
450 return;
451 }
452 const SkAdvancedTypefaceMetrics& metrics = *metricsPtr;
453 SkASSERT(can_embed(metrics));
454 SkAdvancedTypefaceMetrics::FontType type = font.getType();
455
456 auto descriptor = SkPDFMakeDict("FontDescriptor");
457 uint16_t emSize = SkToU16(SkScalarRoundToInt(font.strike().fPath.fUnitsPerEM));
458 SkPDFFont::PopulateCommonFontDescriptor(descriptor.get(), metrics, emSize, 0);
459
460 int ttcIndex;
461 std::unique_ptr<SkStreamAsset> fontAsset = typeface.openStream(&ttcIndex);
462 size_t fontSize = fontAsset ? fontAsset->getLength() : 0;
463 if (0 == fontSize) {
464 SkDebugf("Error: (SkTypeface)(%p)::openStream() returned "
465 "empty stream (%p) when identified as kType1CID_Font "
466 "or kTrueType_Font.\n", &typeface, fontAsset.get());
467 } else if (type == SkAdvancedTypefaceMetrics::kTrueType_Font) {
468 sk_sp<SkData> subsetFontData;
469 if (can_subset(metrics)) {
470 SkASSERT(font.firstGlyphID() == 1);
471 subsetFontData = SkPDFSubsetFont(typeface, font.glyphUsage());
472 }
473 std::unique_ptr<SkStreamAsset> subsetFontAsset;
474 if (subsetFontData) {
475 subsetFontAsset = SkMemoryStream::Make(std::move(subsetFontData));
476 } else {
477 // If subsetting fails, fall back to original font data.
478 subsetFontAsset = std::move(fontAsset);
479 }
480 std::unique_ptr<SkPDFDict> streamDict = SkPDFMakeDict();
481 streamDict->insertInt("Length1", subsetFontAsset->getLength());
482 descriptor->insertRef("FontFile2",
483 SkPDFStreamOut(std::move(streamDict), std::move(subsetFontAsset),
484 doc, SkPDFSteamCompressionEnabled::Yes));
485 } else if (type == SkAdvancedTypefaceMetrics::kType1CID_Font) {
486 std::unique_ptr<SkPDFDict> streamDict = SkPDFMakeDict();
487 streamDict->insertName("Subtype", "CIDFontType0C");
488 descriptor->insertRef("FontFile3",
489 SkPDFStreamOut(std::move(streamDict), std::move(fontAsset),
490 doc, SkPDFSteamCompressionEnabled::Yes));
491 } else {
492 SkASSERT(false);
493 }
494
495 auto newCIDFont = SkPDFMakeDict("Font");
496 newCIDFont->insertRef("FontDescriptor", doc->emit(*descriptor));
497 newCIDFont->insertName("BaseFont", metrics.fPostScriptName);
498
499 switch (type) {
500 case SkAdvancedTypefaceMetrics::kType1CID_Font:
501 newCIDFont->insertName("Subtype", "CIDFontType0");
502 break;
503 case SkAdvancedTypefaceMetrics::kTrueType_Font:
504 newCIDFont->insertName("Subtype", "CIDFontType2");
505 newCIDFont->insertName("CIDToGIDMap", "Identity");
506 break;
507 default:
508 SkASSERT(false);
509 }
510 auto sysInfo = SkPDFMakeDict();
511 // These are actually ASCII strings.
512 sysInfo->insertByteString("Registry", "Adobe");
513 sysInfo->insertByteString("Ordering", "Identity");
514 sysInfo->insertInt("Supplement", 0);
515 newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo));
516
517 // Unfortunately, poppler enforces DW (default width) must be an integer.
518 int32_t defaultWidth = 0;
519 {
520 std::unique_ptr<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray(
521 font.strike().fPath, font.glyphUsage(), &defaultWidth);
522 if (widths && widths->size() > 0) {
523 newCIDFont->insertObject("W", std::move(widths));
524 }
525 newCIDFont->insertInt("DW", defaultWidth);
526 }
527
528 ////////////////////////////////////////////////////////////////////////////
529
530 SkPDFDict fontDict("Font");
531 fontDict.insertName("Subtype", "Type0");
532 fontDict.insertName("BaseFont", metrics.fPostScriptName);
533 fontDict.insertName("Encoding", "Identity-H");
534 auto descendantFonts = SkPDFMakeArray();
535 descendantFonts->appendRef(doc->emit(*newCIDFont));
536 fontDict.insertObject("DescendantFonts", std::move(descendantFonts));
537
538 const std::vector<SkUnichar>& glyphToUnicode =
539 SkPDFFont::GetUnicodeMap(typeface, doc);
540 SkASSERT(SkToSizeT(typeface.countGlyphs()) == glyphToUnicode.size());
541 std::unique_ptr<SkStreamAsset> toUnicode =
542 SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
543 SkPDFFont::GetUnicodeMapEx(typeface, doc),
544 &font.glyphUsage(),
545 font.multiByteGlyphs(),
546 font.firstGlyphID(),
547 font.lastGlyphID());
548 fontDict.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicode), doc));
549
550 doc->emit(fontDict, font.indirectReference());
551 }
552
553 ///////////////////////////////////////////////////////////////////////////////
554 // PDFType3Font
555 ///////////////////////////////////////////////////////////////////////////////
556
557 namespace {
558 // returns [0, first, first+1, ... last-1, last]
559 struct SingleByteGlyphIdIterator {
SingleByteGlyphIdIterator__anon7580bc5e0211::SingleByteGlyphIdIterator560 SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
561 : fFirst(first), fLast(last) {
562 SkASSERT(fFirst > 0);
563 SkASSERT(fLast >= first);
564 }
565 struct Iter {
operator ++__anon7580bc5e0211::SingleByteGlyphIdIterator::Iter566 void operator++() {
567 fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
568 }
569 // This is an input_iterator
operator *__anon7580bc5e0211::SingleByteGlyphIdIterator::Iter570 SkGlyphID operator*() const { return (SkGlyphID)fCurrent; }
operator !=__anon7580bc5e0211::SingleByteGlyphIdIterator::Iter571 bool operator!=(const Iter& rhs) const {
572 return fCurrent != rhs.fCurrent;
573 }
Iter__anon7580bc5e0211::SingleByteGlyphIdIterator::Iter574 Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {}
575 private:
576 const SkGlyphID fFirst;
577 int fCurrent; // must be int to make fLast+1 to fit
578 };
begin__anon7580bc5e0211::SingleByteGlyphIdIterator579 Iter begin() const { return Iter(fFirst, 0); }
end__anon7580bc5e0211::SingleByteGlyphIdIterator580 Iter end() const { return Iter(fFirst, (int)fLast + 1); }
581 private:
582 const SkGlyphID fFirst;
583 const SkGlyphID fLast;
584 };
585 } // namespace
586
587 struct ImageAndOffset {
588 sk_sp<SkImage> fImage;
589 SkIPoint fOffset;
590 };
to_image(SkGlyphID gid,SkBulkGlyphMetricsAndImages * smallGlyphs)591 static ImageAndOffset to_image(SkGlyphID gid, SkBulkGlyphMetricsAndImages* smallGlyphs) {
592 const SkGlyph* glyph = smallGlyphs->glyph(SkPackedGlyphID{gid});
593 SkMask mask = glyph->mask();
594 if (!mask.fImage) {
595 return {nullptr, {0, 0}};
596 }
597 SkIRect bounds = mask.fBounds;
598 SkBitmap bm;
599 switch (mask.fFormat) {
600 case SkMask::kBW_Format: {
601 // Make a gray image, used to smask a rectangle.
602 // TODO: emit as MaskImage?
603 const SkISize size = bounds.size();
604 bm.allocPixels(SkImageInfo::Make(size, kGray_8_SkColorType, kUnknown_SkAlphaType));
605 for (int y = 0; y < bm.height(); ++y) {
606 for (int x8 = 0; x8 < bm.width(); x8 += 8) {
607 uint8_t v = *mask.getAddr1(x8 + bounds.x(), y + bounds.y());
608 int e = std::min(x8 + 8, bm.width());
609 for (int x = x8; x < e; ++x) {
610 *bm.getAddr8(x, y) = (v >> (x & 0x7)) & 0x1 ? 0xFF : 0x00;
611 }
612 }
613 }
614 bm.setImmutable();
615 return {bm.asImage(), {bounds.x(), bounds.y()}};
616 }
617 case SkMask::kA8_Format:
618 case SkMask::k3D_Format: // just do the A8 part
619 // Make a gray image, used to smask a rectangle.
620 return {SkImages::RasterFromData(
621 SkImageInfo::Make(bounds.size(), kGray_8_SkColorType, kUnknown_SkAlphaType),
622 SkData::MakeWithCopy(mask.fImage, mask.computeImageSize()),
623 mask.fRowBytes),
624 {bounds.x(), bounds.y()}};
625 case SkMask::kARGB32_Format:
626 // These will be drawn as images directly.
627 return {SkImages::RasterFromData(
628 SkImageInfo::MakeN32Premul(bounds.size()),
629 SkData::MakeWithCopy(mask.fImage, mask.computeTotalImageSize()),
630 mask.fRowBytes),
631 {bounds.x(), bounds.y()}};
632 case SkMask::kLCD16_Format:
633 default:
634 SkASSERT(false);
635 return {nullptr, {0, 0}};
636 }
637 }
638
type3_descriptor(SkPDFDocument * doc,const SkTypeface & typeface,SkScalar xHeight)639 static SkPDFIndirectReference type3_descriptor(SkPDFDocument* doc,
640 const SkTypeface& typeface,
641 SkScalar xHeight) {
642 if (SkPDFIndirectReference* ptr = doc->fType3FontDescriptors.find(typeface.uniqueID())) {
643 return *ptr;
644 }
645
646 SkPDFDict descriptor("FontDescriptor");
647 int32_t fontDescriptorFlags = kPdfSymbolic;
648
649 /** PDF32000_2008: FontFamily should be used for Type3 fonts in Tagged PDF documents. */
650 SkString familyName;
651 typeface.getFamilyName(&familyName);
652 if (!familyName.isEmpty()) {
653 descriptor.insertByteString("FontFamily", familyName);
654 }
655
656 /** PDF32000_2008: FontStretch should be used for Type3 fonts in Tagged PDF documents. */
657 static constexpr const char* stretchNames[9] = {
658 "UltraCondensed",
659 "ExtraCondensed",
660 "Condensed",
661 "SemiCondensed",
662 "Normal",
663 "SemiExpanded",
664 "Expanded",
665 "ExtraExpanded",
666 "UltraExpanded",
667 };
668 const char* stretchName = stretchNames[typeface.fontStyle().width() - 1];
669 descriptor.insertName("FontStretch", stretchName);
670
671 /** PDF32000_2008: FontWeight should be used for Type3 fonts in Tagged PDF documents. */
672 int weight = (typeface.fontStyle().weight() + 50) / 100;
673 descriptor.insertInt("FontWeight", SkTPin(weight, 1, 9) * 100);
674
675 if (const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, doc)) {
676 // Type3 FontDescriptor does not require all the same fields.
677 descriptor.insertName("FontName", metrics->fPostScriptName);
678 descriptor.insertInt("ItalicAngle", metrics->fItalicAngle);
679 fontDescriptorFlags |= (int32_t)metrics->fStyle;
680 // Adobe requests CapHeight, XHeight, and StemV be added
681 // to "greatly help our workflow downstream".
682 if (metrics->fCapHeight != 0) { descriptor.insertInt("CapHeight", metrics->fCapHeight); }
683 if (metrics->fStemV != 0) { descriptor.insertInt("StemV", metrics->fStemV); }
684 if (xHeight != 0) {
685 descriptor.insertScalar("XHeight", xHeight);
686 }
687 }
688 descriptor.insertInt("Flags", fontDescriptorFlags);
689 SkPDFIndirectReference ref = doc->emit(descriptor);
690 doc->fType3FontDescriptors.set(typeface.uniqueID(), ref);
691 return ref;
692 }
693
emit_subset_type3(const SkPDFFont & pdfFont,SkPDFDocument * doc)694 static void emit_subset_type3(const SkPDFFont& pdfFont, SkPDFDocument* doc) {
695 const SkPDFStrike& pdfStrike = pdfFont.strike();
696 SkGlyphID firstGlyphID = pdfFont.firstGlyphID();
697 SkGlyphID lastGlyphID = pdfFont.lastGlyphID();
698 const SkPDFGlyphUse& subset = pdfFont.glyphUsage();
699 SkASSERT(lastGlyphID >= firstGlyphID);
700 // Remove unused glyphs at the end of the range.
701 // Keep the lastGlyphID >= firstGlyphID invariant true.
702 while (lastGlyphID > firstGlyphID && !subset.has(lastGlyphID)) {
703 --lastGlyphID;
704 }
705 SkScalar emSize = pdfStrike.fPath.fUnitsPerEM;
706 sk_sp<SkStrike> strike = pdfStrike.fPath.fStrikeSpec.findOrCreateStrike();
707 SkASSERT(strike);
708 SkScalar xHeight = strike->getFontMetrics().fXHeight;
709 SkBulkGlyphMetricsAndPaths metricsAndPaths((sk_sp<SkStrike>(strike)));
710 SkBulkGlyphMetricsAndDrawables metricsAndDrawables(std::move(strike));
711
712 SkBulkGlyphMetricsAndImages smallGlyphs(pdfFont.strike().fImage.fStrikeSpec);
713 float bitmapScale = emSize / pdfStrike.fImage.fUnitsPerEM;
714
715 SkPDFDict font("Font");
716 font.insertName("Subtype", "Type3");
717 // Flip about the x-axis and scale by 1/emSize.
718 SkMatrix fontMatrix;
719 fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
720 font.insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
721
722 auto charProcs = SkPDFMakeDict();
723 auto encoding = SkPDFMakeDict("Encoding");
724
725 auto encDiffs = SkPDFMakeArray();
726 // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
727 // plus 1 for glyph 0;
728 SkASSERT(firstGlyphID > 0);
729 SkASSERT(lastGlyphID >= firstGlyphID);
730 int glyphCount = lastGlyphID - firstGlyphID + 2;
731 // one other entry for the index of first glyph.
732 encDiffs->reserve(glyphCount + 1);
733 encDiffs->appendInt(0); // index of first glyph
734
735 auto widthArray = SkPDFMakeArray();
736 widthArray->reserve(glyphCount);
737
738 SkIRect bbox = SkIRect::MakeEmpty();
739
740 std::unique_ptr<SkPDFDict> xobjects = SkPDFMakeDict();
741 std::unique_ptr<SkPDFDict> graphicStates = SkPDFMakeDict();
742 for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
743 SkString characterName;
744 SkScalar advance = 0.0f;
745
746 if (gID != 0 && !subset.has(gID)) {
747 characterName.set("g0");
748 advance = 0.0f;
749 encDiffs->appendName(std::move(characterName));
750 widthArray->appendScalar(advance);
751 continue;
752 }
753
754 const SkGlyph* pathGlyph = metricsAndPaths.glyph(gID);
755 const SkGlyph* drawableGlyph = metricsAndDrawables.glyph(gID);
756
757 characterName.printf("g%X", gID);
758 advance = pathGlyph->advanceX();
759 encDiffs->appendName(characterName);
760 widthArray->appendScalar(advance);
761
762 SkIRect glyphBBox = pathGlyph->iRect();
763 bbox.join(glyphBBox);
764 const SkPath* path = pathGlyph->path();
765 SkDrawable* drawable = drawableGlyph->drawable();
766 SkDynamicMemoryWStream content;
767 if (drawable && !drawable->getBounds().isEmpty()) {
768 sk_sp<SkPDFDevice> glyphDevice = sk_make_sp<SkPDFDevice>(glyphBBox.size(), doc);
769 SkCanvas canvas(glyphDevice);
770 canvas.translate(-glyphBBox.fLeft, -glyphBBox.fTop);
771 canvas.drawDrawable(drawable);
772 SkPDFIndirectReference xobject = SkPDFMakeFormXObject(
773 doc, glyphDevice->content(),
774 SkPDFMakeArray(0, 0, glyphBBox.width(), glyphBBox.height()),
775 glyphDevice->makeResourceDict(),
776 SkMatrix::Translate(glyphBBox.fLeft, glyphBBox.fTop), nullptr);
777 xobjects->insertRef(SkStringPrintf("Xg%X", gID), xobject);
778 SkPDFUtils::AppendScalar(drawableGlyph->advanceX(), &content);
779 content.writeText(" 0 d0\n1 0 0 1 0 0 cm\n/X");
780 content.write(characterName.c_str(), characterName.size());
781 content.writeText(" Do\n");
782 } else if (path && !path->isEmpty() && !pdfStrike.fHasMaskFilter) {
783 setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), glyphBBox, &content);
784 SkPaint::Style style = pathGlyph->pathIsHairline() ? SkPaint::kStroke_Style
785 : SkPaint::kFill_Style;
786 SkPDFUtils::EmitPath(*path, style, &content);
787 SkPDFUtils::PaintPath(style, path->getFillType(), &content);
788 } else if (auto pimg = to_image(gID, &smallGlyphs); pimg.fImage) {
789 using SkPDFUtils::AppendScalar;
790 if (pimg.fImage->colorType() != kGray_8_SkColorType) {
791 AppendScalar(pathGlyph->advanceX(), &content);
792 content.writeText(" 0 d0\n");
793 AppendScalar(pimg.fImage->width() * bitmapScale, &content);
794 content.writeText(" 0 0 ");
795 AppendScalar(-pimg.fImage->height() * bitmapScale, &content);
796 content.writeText(" ");
797 AppendScalar(pimg.fOffset.x() * bitmapScale, &content);
798 content.writeText(" ");
799 AppendScalar((pimg.fImage->height() + pimg.fOffset.y()) * bitmapScale,&content);
800 content.writeText(" cm\n");
801 content.writeText("/X");
802 content.write(characterName.c_str(), characterName.size());
803 content.writeText(" Do\n");
804 SkPDFIndirectReference image = SkPDFSerializeImage(pimg.fImage.get(), doc);
805 xobjects->insertRef(SkStringPrintf("Xg%X", gID), image);
806 } else {
807 // TODO: For A1, put ImageMask on the PDF image and draw the image?
808 // The A8 mask has been converted to a Gray image
809
810 // This is a `d1` glyph (shaded with the current fill)
811 const SkGlyph* smallGlyph = smallGlyphs.glyph(SkPackedGlyphID{gID});
812 SkRect smallBBox = smallGlyph->rect();
813 SkIRect smallIBox;
814 SkMatrix::Scale(bitmapScale, bitmapScale).mapRect(smallBBox).roundOut(&smallIBox);
815 bbox.join(smallIBox);
816 setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), smallIBox, &content);
817
818 AppendScalar(bitmapScale, &content);
819 content.writeText(" 0 0 ");
820 AppendScalar(bitmapScale, &content);
821 content.writeText(" ");
822 AppendScalar(pimg.fOffset.x() * bitmapScale, &content);
823 content.writeText(" ");
824 AppendScalar(pimg.fOffset.y() * bitmapScale, &content);
825 content.writeText(" cm\n");
826
827 // Convert Grey image to deferred jpeg image to emit as jpeg
828 if (pdfStrike.fHasMaskFilter) {
829 SkPDF::EncodeJpegCallback encodeJPEG = doc->metadata().jpegEncoder;
830 SkPDF::DecodeJpegCallback decodeJPEG = doc->metadata().jpegDecoder;
831 if (encodeJPEG && decodeJPEG) {
832 SkImage* image = pimg.fImage.get();
833 SkPixmap pm;
834 SkAssertResult(image->peekPixels(&pm));
835 SkDynamicMemoryWStream buffer;
836 if (encodeJPEG(&buffer, pm, SK_PDF_MASK_QUALITY)) {
837 std::unique_ptr<SkCodec> codec =
838 decodeJPEG(buffer.detachAsData());
839 SkASSERT(codec);
840 sk_sp<SkImage> jpegImage = SkCodecs::DeferredImage(std::move(codec));
841 SkASSERT(jpegImage);
842 if (jpegImage) {
843 pimg.fImage = jpegImage;
844 }
845 }
846 }
847 }
848
849 // Draw image into a Form XObject
850 const SkISize imageSize = pimg.fImage->dimensions();
851 sk_sp<SkPDFDevice> glyphDevice = sk_sp(new SkPDFDevice(imageSize, doc));
852 SkCanvas canvas(glyphDevice);
853 canvas.drawImage(pimg.fImage, 0, 0);
854 SkPDFIndirectReference sMask = SkPDFMakeFormXObject(
855 doc, glyphDevice->content(),
856 SkPDFMakeArray(0, 0, pimg.fImage->width(), pimg.fImage->height()),
857 glyphDevice->makeResourceDict(),
858 SkMatrix(), "DeviceGray");
859
860 // Use Form XObject as SMask (luminosity) on the graphics state
861 SkPDFIndirectReference smaskGraphicState = SkPDFGraphicState::GetSMaskGraphicState(
862 sMask, false,
863 SkPDFGraphicState::kLuminosity_SMaskMode, doc);
864 SkPDFUtils::ApplyGraphicState(smaskGraphicState.fValue, &content);
865
866 // Draw a rectangle the size of the glyph (masked by SMask)
867 SkPDFUtils::AppendRectangle(SkRect::Make(pimg.fImage->bounds()), &content);
868 SkPDFUtils::PaintPath(SkPaint::kFill_Style, SkPathFillType::kWinding, &content);
869
870 // Add glyph resources to font resource dict
871 xobjects->insertRef(SkStringPrintf("Xg%X", gID), sMask);
872 // TODO: name must match ApplyGraphicState
873 graphicStates->insertRef(SkStringPrintf("G%d", smaskGraphicState.fValue),
874 smaskGraphicState);
875 }
876 } else {
877 setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), glyphBBox, &content);
878 }
879 charProcs->insertRef(std::move(characterName),
880 SkPDFStreamOut(nullptr, content.detachAsStream(), doc));
881 }
882
883 if (xobjects->size() || graphicStates->size()) {
884 auto resources = SkPDFMakeDict();
885 if (xobjects->size()) {
886 resources->insertObject("XObject", std::move(xobjects));
887 }
888 if (graphicStates->size()) {
889 resources->insertObject("ExtGState", std::move(graphicStates));
890 }
891 font.insertObject("Resources", std::move(resources));
892 }
893
894 encoding->insertObject("Differences", std::move(encDiffs));
895 font.insertInt("FirstChar", 0);
896 font.insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
897 /* FontBBox: "A rectangle expressed in the glyph coordinate
898 system, specifying the font bounding box. This is the smallest
899 rectangle enclosing the shape that would result if all of the
900 glyphs of the font were placed with their origins coincident and
901 then filled." */
902 font.insertObject("FontBBox", SkPDFMakeArray(bbox.left(),
903 bbox.bottom(),
904 bbox.right(),
905 bbox.top()));
906
907 font.insertName("CIDToGIDMap", "Identity");
908
909 const SkTypeface& pathTypeface = pdfStrike.fPath.fStrikeSpec.typeface();
910 const std::vector<SkUnichar>& glyphToUnicode = SkPDFFont::GetUnicodeMap(pathTypeface, doc);
911 SkASSERT(glyphToUnicode.size() == SkToSizeT(pathTypeface.countGlyphs()));
912 auto toUnicodeCmap = SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
913 SkPDFFont::GetUnicodeMapEx(pathTypeface, doc),
914 &subset,
915 false,
916 firstGlyphID,
917 lastGlyphID);
918 font.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicodeCmap), doc));
919 font.insertRef("FontDescriptor", type3_descriptor(doc, pathTypeface, xHeight));
920 font.insertObject("Widths", std::move(widthArray));
921 font.insertObject("Encoding", std::move(encoding));
922 font.insertObject("CharProcs", std::move(charProcs));
923
924 doc->emit(font, pdfFont.indirectReference());
925 }
926
emitSubset(SkPDFDocument * doc) const927 void SkPDFFont::emitSubset(SkPDFDocument* doc) const {
928 switch (fFontType) {
929 case SkAdvancedTypefaceMetrics::kType1CID_Font:
930 case SkAdvancedTypefaceMetrics::kTrueType_Font:
931 return emit_subset_type0(*this, doc);
932 #ifndef SK_PDF_DO_NOT_SUPPORT_TYPE_1_FONTS
933 case SkAdvancedTypefaceMetrics::kType1_Font:
934 return SkPDFEmitType1Font(*this, doc);
935 #endif
936 default:
937 return emit_subset_type3(*this, doc);
938 }
939 }
940
941 ////////////////////////////////////////////////////////////////////////////////
942
CanEmbedTypeface(const SkTypeface & typeface,SkPDFDocument * doc)943 bool SkPDFFont::CanEmbedTypeface(const SkTypeface& typeface, SkPDFDocument* doc) {
944 const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, doc);
945 return metrics && can_embed(*metrics);
946 }
947
948