• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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