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