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