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 "include/core/SkBitmap.h"
9#include "include/core/SkData.h"
10#include "include/core/SkFont.h"
11#include "include/core/SkFontMetrics.h"
12#include "include/core/SkFontTypes.h"
13#include "include/core/SkImage.h"
14#include "include/core/SkImageInfo.h"
15#include "include/core/SkMatrix.h"
16#include "include/core/SkPaint.h"
17#include "include/core/SkPath.h"
18#include "include/core/SkPoint.h"
19#include "include/core/SkRect.h"
20#include "include/core/SkRefCnt.h"
21#include "include/core/SkScalar.h"
22#include "include/core/SkStream.h"
23#include "include/core/SkString.h"
24#include "include/core/SkSurfaceProps.h"
25#include "include/core/SkTypes.h"
26#include "include/docs/SkPDFDocument.h"
27#include "include/private/SkBitmaskEnum.h"
28#include "include/private/SkTHash.h"
29#include "include/private/SkTo.h"
30#include "src/core/SkGlyph.h"
31#include "src/core/SkImagePriv.h"
32#include "src/core/SkMask.h"
33#include "src/core/SkScalerCache.h"
34#include "src/core/SkScalerContext.h"
35#include "src/core/SkStrikeSpec.h"
36#include "src/pdf/SkPDFBitmap.h"
37#include "src/pdf/SkPDFDocumentPriv.h"
38#include "src/pdf/SkPDFFont.h"
39#include "src/pdf/SkPDFMakeCIDGlyphWidthsArray.h"
40#include "src/pdf/SkPDFMakeToUnicodeCmap.h"
41#include "src/pdf/SkPDFSubsetFont.h"
42#include "src/pdf/SkPDFType1Font.h"
43#include "src/pdf/SkPDFUtils.h"
44#include "src/utils/SkUTF.h"
45
46#include <limits.h>
47#include <initializer_list>
48#include <memory>
49#include <utility>
50
51void SkPDFFont::GetType1GlyphNames(const SkTypeface& face, SkString* dst) {
52 face.getPostScriptGlyphNames(dst);
53}
54
55namespace {
56// PDF's notion of symbolic vs non-symbolic is related to the character set, not
57// symbols vs. characters. Rarely is a font the right character set to call it
58// non-symbolic, so always call it symbolic. (PDF 1.4 spec, section 5.7.1)
59static const int32_t kPdfSymbolic = 4;
60
61
62// scale from em-units to base-1000, returning as a SkScalar
63inline SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
64 return emSize == 1000 ? scaled : scaled * 1000 / emSize;
65}
66
67inline SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
68 return from_font_units(SkIntToScalar(val), emSize);
69}
70
71void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
72 SkDynamicMemoryWStream* content) {
73 // Specify width and bounding box for the glyph.
74 SkPDFUtils::AppendScalar(width, content);
75 content->writeText(" 0 ");
76 content->writeDecAsText(box.fLeft);
77 content->writeText(" ");
78 content->writeDecAsText(box.fTop);
79 content->writeText(" ");
80 content->writeDecAsText(box.fRight);
81 content->writeText(" ");
82 content->writeDecAsText(box.fBottom);
83 content->writeText(" d1\n");
84}
85} // namespace
86
87///////////////////////////////////////////////////////////////////////////////
88// class SkPDFFont
89///////////////////////////////////////////////////////////////////////////////
90
91/* Resources are canonicalized and uniqueified by pointer so there has to be
92 * some additional state indicating which subset of the font is used. It
93 * must be maintained at the document granularity.
94 */
95
96SkPDFFont::~SkPDFFont() = default;
97
98SkPDFFont::SkPDFFont(SkPDFFont&&) = default;
99
100SkPDFFont& SkPDFFont::operator=(SkPDFFont&&) = default;
101
102static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) {
103 return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
104}
105
106const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(const SkTypeface* typeface,
107 SkPDFDocument* canon) {
108 SkASSERT(typeface);
109 SkFontID id = typeface->uniqueID();
110 if (std::unique_ptr<SkAdvancedTypefaceMetrics>* ptr = canon->fTypefaceMetrics.find(id)) {
111 return ptr->get(); // canon retains ownership.
112 }
113 int count = typeface->countGlyphs();
114 if (count <= 0 || count > 1 + SkTo<int>(UINT16_MAX)) {
115 // Cache nullptr to skip this check. Use SkSafeUnref().
116 canon->fTypefaceMetrics.set(id, nullptr);
117 return nullptr;
118 }
119 std::unique_ptr<SkAdvancedTypefaceMetrics> metrics = typeface->getAdvancedMetrics();
120 if (!metrics) {
121 metrics = std::make_unique<SkAdvancedTypefaceMetrics>();
122 }
123
124 if (0 == metrics->fStemV || 0 == metrics->fCapHeight) {
125 SkFont font;
126 font.setHinting(SkFontHinting::kNone);
127 font.setTypeface(sk_ref_sp(typeface));
128 font.setSize(1000); // glyph coordinate system
129 if (0 == metrics->fStemV) {
130 // Figure out a good guess for StemV - Min width of i, I, !, 1.
131 // This probably isn't very good with an italic font.
132 int16_t stemV = SHRT_MAX;
133 for (char c : {'i', 'I', '!', '1'}) {
134 uint16_t g = font.unicharToGlyph(c);
135 SkRect bounds;
136 font.getBounds(&g, 1, &bounds, nullptr);
137 stemV = std::min(stemV, SkToS16(SkScalarRoundToInt(bounds.width())));
138 }
139 metrics->fStemV = stemV;
140 }
141 if (0 == metrics->fCapHeight) {
142 // Figure out a good guess for CapHeight: average the height of M and X.
143 SkScalar capHeight = 0;
144 for (char c : {'M', 'X'}) {
145 uint16_t g = font.unicharToGlyph(c);
146 SkRect bounds;
147 font.getBounds(&g, 1, &bounds, nullptr);
148 capHeight += bounds.height();
149 }
150 metrics->fCapHeight = SkToS16(SkScalarRoundToInt(capHeight / 2));
151 }
152 }
153 return canon->fTypefaceMetrics.set(id, std::move(metrics))->get();
154}
155
156const std::vector<SkUnichar>& SkPDFFont::GetUnicodeMap(const SkTypeface* typeface,
157 SkPDFDocument* canon) {
158 SkASSERT(typeface);
159 SkASSERT(canon);
160 SkFontID id = typeface->uniqueID();
161 if (std::vector<SkUnichar>* ptr = canon->fToUnicodeMap.find(id)) {
162 return *ptr;
163 }
164 std::vector<SkUnichar> buffer(typeface->countGlyphs());
165 typeface->getGlyphToUnicodeMap(buffer.data());
166 return *canon->fToUnicodeMap.set(id, std::move(buffer));
167}
168
169SkAdvancedTypefaceMetrics::FontType SkPDFFont::FontType(const SkAdvancedTypefaceMetrics& metrics) {
170 if (SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag) ||
171 SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag)) {
172 // force Type3 fallback.
173 return SkAdvancedTypefaceMetrics::kOther_Font;
174 }
175 return metrics.fType;
176}
177
178static SkGlyphID first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid) {
179 return gid != 0 ? gid - (gid - 1) % 255 : 1;
180}
181
182SkPDFFont* SkPDFFont::GetFontResource(SkPDFDocument* doc,
183 const SkGlyph* glyph,
184 SkTypeface* face) {
185 SkASSERT(doc);
186 SkASSERT(face); // All SkPDFDevice::internalDrawText ensures this.
187 const SkAdvancedTypefaceMetrics* fontMetrics = SkPDFFont::GetMetrics(face, doc);
188 SkASSERT(fontMetrics); // SkPDFDevice::internalDrawText ensures the typeface is good.
189 // GetMetrics only returns null to signify a bad typeface.
190 const SkAdvancedTypefaceMetrics& metrics = *fontMetrics;
191 SkAdvancedTypefaceMetrics::FontType type = SkPDFFont::FontType(metrics);
192 if (!(glyph->isEmpty() || glyph->path())) {
193 type = SkAdvancedTypefaceMetrics::kOther_Font;
194 }
195 bool multibyte = SkPDFFont::IsMultiByte(type);
196 SkGlyphID subsetCode =
197 multibyte ? 0 : first_nonzero_glyph_for_single_byte_encoding(glyph->getGlyphID());
198 uint64_t fontID = (static_cast<uint64_t>(SkTypeface::UniqueID(face)) << 16) | subsetCode;
199
200 if (SkPDFFont* found = doc->fFontMap.find(fontID)) {
201 SkASSERT(multibyte == found->multiByteGlyphs());
202 return found;
203 }
204
205 sk_sp<SkTypeface> typeface(sk_ref_sp(face));
206 SkASSERT(typeface);
207
208 SkGlyphID lastGlyph = SkToU16(typeface->countGlyphs() - 1);
209
210 // should be caught by SkPDFDevice::internalDrawText
211 SkASSERT(glyph->getGlyphID() <= lastGlyph);
212
213 SkGlyphID firstNonZeroGlyph;
214 if (multibyte) {
215 firstNonZeroGlyph = 1;
216 } else {
217 firstNonZeroGlyph = subsetCode;
218 lastGlyph = SkToU16(std::min<int>((int)lastGlyph, 254 + (int)subsetCode));
219 }
220 auto ref = doc->reserveRef();
221 return doc->fFontMap.set(
222 fontID, SkPDFFont(std::move(typeface), firstNonZeroGlyph, lastGlyph, type, ref));
223}
224
225SkPDFFont::SkPDFFont(sk_sp<SkTypeface> typeface,
226 SkGlyphID firstGlyphID,
227 SkGlyphID lastGlyphID,
228 SkAdvancedTypefaceMetrics::FontType fontType,
229 SkPDFIndirectReference indirectReference)
230 : fTypeface(std::move(typeface))
231 , fGlyphUsage(firstGlyphID, lastGlyphID)
232 , fIndirectReference(indirectReference)
233 , fFontType(fontType)
234{
235 // Always include glyph 0
236 this->noteGlyphUsage(0);
237}
238
239void SkPDFFont::PopulateCommonFontDescriptor(SkPDFDict* descriptor,
240 const SkAdvancedTypefaceMetrics& metrics,
241 uint16_t emSize,
242 int16_t defaultWidth) {
243 descriptor->insertName("FontName", metrics.fPostScriptName);
244 descriptor->insertInt("Flags", (size_t)(metrics.fStyle | kPdfSymbolic));
245 descriptor->insertScalar("Ascent",
246 scaleFromFontUnits(metrics.fAscent, emSize));
247 descriptor->insertScalar("Descent",
248 scaleFromFontUnits(metrics.fDescent, emSize));
249 descriptor->insertScalar("StemV",
250 scaleFromFontUnits(metrics.fStemV, emSize));
251 descriptor->insertScalar("CapHeight",
252 scaleFromFontUnits(metrics.fCapHeight, emSize));
253 descriptor->insertInt("ItalicAngle", metrics.fItalicAngle);
254 descriptor->insertObject("FontBBox",
255 SkPDFMakeArray(scaleFromFontUnits(metrics.fBBox.left(), emSize),
256 scaleFromFontUnits(metrics.fBBox.bottom(), emSize),
257 scaleFromFontUnits(metrics.fBBox.right(), emSize),
258 scaleFromFontUnits(metrics.fBBox.top(), emSize)));
259 if (defaultWidth > 0) {
260 descriptor->insertScalar("MissingWidth",
261 scaleFromFontUnits(defaultWidth, emSize));
262 }
263}
264
265///////////////////////////////////////////////////////////////////////////////
266// Type0Font
267///////////////////////////////////////////////////////////////////////////////
268
269// if possible, make no copy.
270static sk_sp<SkData> stream_to_data(std::unique_ptr<SkStreamAsset> stream) {
271 SkASSERT(stream);
272 (void)stream->rewind();
273 SkASSERT(stream->hasLength());
274 size_t size = stream->getLength();
275 if (const void* base = stream->getMemoryBase()) {
276 SkData::ReleaseProc proc =
277 [](const void*, void* ctx) { delete (SkStreamAsset*)ctx; };
278 return SkData::MakeWithProc(base, size, proc, stream.release());
279 }
280 return SkData::MakeFromStream(stream.get(), size);
281}
282
283static void emit_subset_type0(const SkPDFFont& font, SkPDFDocument* doc) {
284 const SkAdvancedTypefaceMetrics* metricsPtr =
285 SkPDFFont::GetMetrics(font.typeface(), doc);
286 SkASSERT(metricsPtr);
287 if (!metricsPtr) { return; }
288 const SkAdvancedTypefaceMetrics& metrics = *metricsPtr;
289 SkASSERT(can_embed(metrics));
290 SkAdvancedTypefaceMetrics::FontType type = font.getType();
291 SkTypeface* face = font.typeface();
292 SkASSERT(face);
293
294 auto descriptor = SkPDFMakeDict("FontDescriptor");
295 uint16_t emSize = SkToU16(font.typeface()->getUnitsPerEm());
296 SkPDFFont::PopulateCommonFontDescriptor(descriptor.get(), metrics, emSize, 0);
297
298 int ttcIndex;
299 std::unique_ptr<SkStreamAsset> fontAsset = face->openStream(&ttcIndex);
300 size_t fontSize = fontAsset ? fontAsset->getLength() : 0;
301 if (0 == fontSize) {
302 SkDebugf("Error: (SkTypeface)(%p)::openStream() returned "
303 "empty stream (%p) when identified as kType1CID_Font "
304 "or kTrueType_Font.\n", face, fontAsset.get());
305 } else {
306 switch (type) {
307 case SkAdvancedTypefaceMetrics::kTrueType_Font: {
308 if (!SkToBool(metrics.fFlags &
309 SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag)) {
310 SkASSERT(font.firstGlyphID() == 1);
311 sk_sp<SkData> subsetFontData = SkPDFSubsetFont(
312 stream_to_data(std::move(fontAsset)), font.glyphUsage(),
313 doc->metadata().fSubsetter,
314 metrics.fFontName.c_str(), ttcIndex);
315 if (subsetFontData) {
316 std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
317 tmp->insertInt("Length1", SkToInt(subsetFontData->size()));
318 descriptor->insertRef(
319 "FontFile2",
320 SkPDFStreamOut(std::move(tmp),
321 SkMemoryStream::Make(std::move(subsetFontData)),
322 doc, true));
323 break;
324 }
325 // If subsetting fails, fall back to original font data.
326 fontAsset = face->openStream(&ttcIndex);
327 SkASSERT(fontAsset);
328 SkASSERT(fontAsset->getLength() == fontSize);
329 if (!fontAsset || fontAsset->getLength() == 0) { break; }
330 }
331 std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
332 tmp->insertInt("Length1", fontSize);
333 descriptor->insertRef("FontFile2",
334 SkPDFStreamOut(std::move(tmp), std::move(fontAsset),
335 doc, true));
336 break;
337 }
338 case SkAdvancedTypefaceMetrics::kType1CID_Font: {
339 std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
340 tmp->insertName("Subtype", "CIDFontType0C");
341 descriptor->insertRef("FontFile3",
342 SkPDFStreamOut(std::move(tmp), std::move(fontAsset),
343 doc, true));
344 break;
345 }
346 default:
347 SkASSERT(false);
348 }
349 }
350
351 auto newCIDFont = SkPDFMakeDict("Font");
352 newCIDFont->insertRef("FontDescriptor", doc->emit(*descriptor));
353 newCIDFont->insertName("BaseFont", metrics.fPostScriptName);
354
355 switch (type) {
356 case SkAdvancedTypefaceMetrics::kType1CID_Font:
357 newCIDFont->insertName("Subtype", "CIDFontType0");
358 break;
359 case SkAdvancedTypefaceMetrics::kTrueType_Font:
360 newCIDFont->insertName("Subtype", "CIDFontType2");
361 newCIDFont->insertName("CIDToGIDMap", "Identity");
362 break;
363 default:
364 SkASSERT(false);
365 }
366 auto sysInfo = SkPDFMakeDict();
367 sysInfo->insertString("Registry", "Adobe");
368 sysInfo->insertString("Ordering", "Identity");
369 sysInfo->insertInt("Supplement", 0);
370 newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo));
371
372 SkScalar defaultWidth = 0;
373 {
374 std::unique_ptr<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray(
375 *face, font.glyphUsage(), &defaultWidth);
376 if (widths && widths->size() > 0) {
377 newCIDFont->insertObject("W", std::move(widths));
378 }
379 newCIDFont->insertScalar("DW", defaultWidth);
380 }
381
382 ////////////////////////////////////////////////////////////////////////////
383
384 SkPDFDict fontDict("Font");
385 fontDict.insertName("Subtype", "Type0");
386 fontDict.insertName("BaseFont", metrics.fPostScriptName);
387 fontDict.insertName("Encoding", "Identity-H");
388 auto descendantFonts = SkPDFMakeArray();
389 descendantFonts->appendRef(doc->emit(*newCIDFont));
390 fontDict.insertObject("DescendantFonts", std::move(descendantFonts));
391
392 const std::vector<SkUnichar>& glyphToUnicode =
393 SkPDFFont::GetUnicodeMap(font.typeface(), doc);
394 SkASSERT(SkToSizeT(font.typeface()->countGlyphs()) == glyphToUnicode.size());
395 std::unique_ptr<SkStreamAsset> toUnicode =
396 SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
397 &font.glyphUsage(),
398 font.multiByteGlyphs(),
399 font.firstGlyphID(),
400 font.lastGlyphID());
401 fontDict.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicode), doc));
402
403 doc->emit(fontDict, font.indirectReference());
404}
405
406///////////////////////////////////////////////////////////////////////////////
407// PDFType3Font
408///////////////////////////////////////////////////////////////////////////////
409
410namespace {
411// returns [0, first, first+1, ... last-1, last]
412struct SingleByteGlyphIdIterator {
413 SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
414 : fFirst(first), fLast(last) {
415 SkASSERT(fFirst > 0);
416 SkASSERT(fLast >= first);
417 }
418 struct Iter {
419 void operator++() {
420 fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
421 }
422 // This is an input_iterator
423 SkGlyphID operator*() const { return (SkGlyphID)fCurrent; }
424 bool operator!=(const Iter& rhs) const {
425 return fCurrent != rhs.fCurrent;
426 }
427 Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {}
428 private:
429 const SkGlyphID fFirst;
430 int fCurrent; // must be int to make fLast+1 to fit
431 };
432 Iter begin() const { return Iter(fFirst, 0); }
433 Iter end() const { return Iter(fFirst, (int)fLast + 1); }
434private:
435 const SkGlyphID fFirst;
436 const SkGlyphID fLast;
437};
438}
439
440struct ImageAndOffset {
441 sk_sp<SkImage> fImage;
442 SkIPoint fOffset;
443};
444static ImageAndOffset to_image(SkGlyphID gid, SkBulkGlyphMetricsAndImages* smallGlyphs) {
445 const SkGlyph* glyph = smallGlyphs->glyph(SkPackedGlyphID{gid});
446 SkMask mask = glyph->mask();
447 if (!mask.fImage) {
448 return {nullptr, {0, 0}};
449 }
450 SkIRect bounds = mask.fBounds;
451 SkBitmap bm;
452 switch (mask.fFormat) {
453 case SkMask::kBW_Format:
454 bm.allocPixels(SkImageInfo::MakeA8(bounds.width(), bounds.height()));
455 for (int y = 0; y < bm.height(); ++y) {
456 for (int x8 = 0; x8 < bm.width(); x8 += 8) {
457 uint8_t v = *mask.getAddr1(x8 + bounds.x(), y + bounds.y());
458 int e = std::min(x8 + 8, bm.width());
459 for (int x = x8; x < e; ++x) {
460 *bm.getAddr8(x, y) = (v >> (x & 0x7)) & 0x1 ? 0xFF : 0x00;
461 }
462 }
463 }
464 bm.setImmutable();
465 return {SkImage::MakeFromBitmap(bm), {bounds.x(), bounds.y()}};
466 case SkMask::kA8_Format:
467 bm.installPixels(SkImageInfo::MakeA8(bounds.width(), bounds.height()),
468 mask.fImage, mask.fRowBytes);
469 return {SkMakeImageFromRasterBitmap(bm, kAlways_SkCopyPixelsMode),
470 {bounds.x(), bounds.y()}};
471 case SkMask::kARGB32_Format:
472 bm.installPixels(SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()),
473 mask.fImage, mask.fRowBytes);
474 return {SkMakeImageFromRasterBitmap(bm, kAlways_SkCopyPixelsMode),
475 {bounds.x(), bounds.y()}};
476 case SkMask::k3D_Format:
477 case SkMask::kLCD16_Format:
478 default:
479 SkASSERT(false);
480 return {nullptr, {0, 0}};
481 }
482}
483
484static SkPDFIndirectReference type3_descriptor(SkPDFDocument* doc,
485 const SkTypeface* typeface,
486 SkScalar xHeight) {
487 if (SkPDFIndirectReference* ptr = doc->fType3FontDescriptors.find(typeface->uniqueID())) {
488 return *ptr;
489 }
490
491 SkPDFDict descriptor("FontDescriptor");
492 int32_t fontDescriptorFlags = kPdfSymbolic;
493 if (const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, doc)) {
494 // Type3 FontDescriptor does not require all the same fields.
495 descriptor.insertName("FontName", metrics->fPostScriptName);
496 descriptor.insertInt("ItalicAngle", metrics->fItalicAngle);
497 fontDescriptorFlags |= (int32_t)metrics->fStyle;
498 // Adobe requests CapHeight, XHeight, and StemV be added
499 // to "greatly help our workflow downstream".
500 if (metrics->fCapHeight != 0) { descriptor.insertInt("CapHeight", metrics->fCapHeight); }
501 if (metrics->fStemV != 0) { descriptor.insertInt("StemV", metrics->fStemV); }
502 if (xHeight != 0) {
503 descriptor.insertScalar("XHeight", xHeight);
504 }
505 }
506 descriptor.insertInt("Flags", fontDescriptorFlags);
507 SkPDFIndirectReference ref = doc->emit(descriptor);
508 doc->fType3FontDescriptors.set(typeface->uniqueID(), ref);
509 return ref;
510}
511
512#ifdef SK_PDF_BITMAP_GLYPH_RASTER_SIZE
513static constexpr float kBitmapFontSize = SK_PDF_BITMAP_GLYPH_RASTER_SIZE;
514#else
515static constexpr float kBitmapFontSize = 64;
516#endif
517
518SkStrikeSpec make_small_strike(const SkTypeface& typeface) {
519 SkFont font(sk_ref_sp(&typeface), kBitmapFontSize);
520 font.setHinting(SkFontHinting::kNone);
521 font.setEdging(SkFont::Edging::kAlias);
522 return SkStrikeSpec::MakeMask(font,
523 SkPaint(),
524 SkSurfaceProps(0, kUnknown_SkPixelGeometry),
525 kFakeGammaAndBoostContrast,
526 SkMatrix::I());
527}
528
529static void emit_subset_type3(const SkPDFFont& pdfFont, SkPDFDocument* doc) {
530 SkTypeface* typeface = pdfFont.typeface();
531 SkGlyphID firstGlyphID = pdfFont.firstGlyphID();
532 SkGlyphID lastGlyphID = pdfFont.lastGlyphID();
533 const SkPDFGlyphUse& subset = pdfFont.glyphUsage();
534 SkASSERT(lastGlyphID >= firstGlyphID);
535 // Remove unused glyphs at the end of the range.
536 // Keep the lastGlyphID >= firstGlyphID invariant true.
537 while (lastGlyphID > firstGlyphID && !subset.has(lastGlyphID)) {
538 --lastGlyphID;
539 }
540 int unitsPerEm;
541 SkStrikeSpec strikeSpec = SkStrikeSpec::MakePDFVector(*typeface, &unitsPerEm);
542 auto strike = strikeSpec.findOrCreateStrike();
543 SkASSERT(strike);
544 SkScalar emSize = (SkScalar)unitsPerEm;
545 SkScalar xHeight = strike->getFontMetrics().fXHeight;
546 SkBulkGlyphMetricsAndPaths metricsAndPaths(std::move(strike));
547
548 SkStrikeSpec strikeSpecSmall = kBitmapFontSize > 0 ? make_small_strike(*typeface)
549 : strikeSpec;
550
551 SkBulkGlyphMetricsAndImages smallGlyphs(strikeSpecSmall);
552 float bitmapScale = kBitmapFontSize > 0 ? emSize / kBitmapFontSize : 1.0f;
553
554 SkPDFDict font("Font");
555 font.insertName("Subtype", "Type3");
556 // Flip about the x-axis and scale by 1/emSize.
557 SkMatrix fontMatrix;
558 fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
559 font.insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
560
561 auto charProcs = SkPDFMakeDict();
562 auto encoding = SkPDFMakeDict("Encoding");
563
564 auto encDiffs = SkPDFMakeArray();
565 // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
566 // plus 1 for glyph 0;
567 SkASSERT(firstGlyphID > 0);
568 SkASSERT(lastGlyphID >= firstGlyphID);
569 int glyphCount = lastGlyphID - firstGlyphID + 2;
570 // one other entry for the index of first glyph.
571 encDiffs->reserve(glyphCount + 1);
572 encDiffs->appendInt(0); // index of first glyph
573
574 auto widthArray = SkPDFMakeArray();
575 widthArray->reserve(glyphCount);
576
577 SkIRect bbox = SkIRect::MakeEmpty();
578
579 std::vector<std::pair<SkGlyphID, SkPDFIndirectReference>> imageGlyphs;
580 for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
581 bool skipGlyph = gID != 0 && !subset.has(gID);
582 SkString characterName;
583 SkScalar advance = 0.0f;
584 SkIRect glyphBBox;
585 if (skipGlyph) {
586 characterName.set("g0");
587 } else {
588 characterName.printf("g%X", gID);
589 const SkGlyph* glyph = metricsAndPaths.glyph(gID);
590 advance = glyph->advanceX();
591 glyphBBox = glyph->iRect();
592 bbox.join(glyphBBox);
593 const SkPath* path = glyph->path();
594 SkDynamicMemoryWStream content;
595 if (path && !path->isEmpty()) {
596 setGlyphWidthAndBoundingBox(glyph->advanceX(), glyphBBox, &content);
597 SkPDFUtils::EmitPath(*path, SkPaint::kFill_Style, &content);
598 SkPDFUtils::PaintPath(SkPaint::kFill_Style, path->getFillType(), &content);
599 } else {
600 auto pimg = to_image(gID, &smallGlyphs);
601 if (!pimg.fImage) {
602 setGlyphWidthAndBoundingBox(glyph->advanceX(), glyphBBox, &content);
603 } else {
604 using SkPDFUtils::AppendScalar;
605 imageGlyphs.emplace_back(gID, SkPDFSerializeImage(pimg.fImage.get(), doc));
606 AppendScalar(glyph->advanceX(), &content);
607 content.writeText(" 0 d0\n");
608 AppendScalar(pimg.fImage->width() * bitmapScale, &content);
609 content.writeText(" 0 0 ");
610 AppendScalar(-pimg.fImage->height() * bitmapScale, &content);
611 content.writeText(" ");
612 AppendScalar(pimg.fOffset.x() * bitmapScale, &content);
613 content.writeText(" ");
614 AppendScalar((pimg.fImage->height() + pimg.fOffset.y()) * bitmapScale,
615 &content);
616 content.writeText(" cm\n/X");
617 content.write(characterName.c_str(), characterName.size());
618 content.writeText(" Do\n");
619 }
620 }
621 charProcs->insertRef(characterName, SkPDFStreamOut(nullptr,
622 content.detachAsStream(), doc));
623 }
624 encDiffs->appendName(std::move(characterName));
625 widthArray->appendScalar(advance);
626 }
627
628 if (!imageGlyphs.empty()) {
629 auto d0 = SkPDFMakeDict();
630 for (const auto& pair : imageGlyphs) {
631 d0->insertRef(SkStringPrintf("Xg%X", pair.first), pair.second);
632 }
633 auto d1 = SkPDFMakeDict();
634 d1->insertObject("XObject", std::move(d0));
635 font.insertObject("Resources", std::move(d1));
636 }
637
638 encoding->insertObject("Differences", std::move(encDiffs));
639 font.insertInt("FirstChar", 0);
640 font.insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
641 /* FontBBox: "A rectangle expressed in the glyph coordinate
642 system, specifying the font bounding box. This is the smallest
643 rectangle enclosing the shape that would result if all of the
644 glyphs of the font were placed with their origins coincident and
645 then filled." */
646 font.insertObject("FontBBox", SkPDFMakeArray(bbox.left(),
647 bbox.bottom(),
648 bbox.right(),
649 bbox.top()));
650
651 font.insertName("CIDToGIDMap", "Identity");
652
653 const std::vector<SkUnichar>& glyphToUnicode = SkPDFFont::GetUnicodeMap(typeface, doc);
654 SkASSERT(glyphToUnicode.size() == SkToSizeT(typeface->countGlyphs()));
655 auto toUnicodeCmap = SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
656 &subset,
657 false,
658 firstGlyphID,
659 lastGlyphID);
660 font.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicodeCmap), doc));
661 font.insertRef("FontDescriptor", type3_descriptor(doc, typeface, xHeight));
662 font.insertObject("Widths", std::move(widthArray));
663 font.insertObject("Encoding", std::move(encoding));
664 font.insertObject("CharProcs", std::move(charProcs));
665
666 doc->emit(font, pdfFont.indirectReference());
667}
668
669void SkPDFFont::emitSubset(SkPDFDocument* doc) const {
670 SkASSERT(fFontType != SkPDFFont().fFontType); // not default value
671 switch (fFontType) {
672 case SkAdvancedTypefaceMetrics::kType1CID_Font:
673 case SkAdvancedTypefaceMetrics::kTrueType_Font:
674 return emit_subset_type0(*this, doc);
675#ifndef SK_PDF_DO_NOT_SUPPORT_TYPE_1_FONTS
676 case SkAdvancedTypefaceMetrics::kType1_Font:
677 return SkPDFEmitType1Font(*this, doc);
678#endif
679 default:
680 return emit_subset_type3(*this, doc);
681 }
682}
683
684////////////////////////////////////////////////////////////////////////////////
685
686bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFDocument* doc) {
687 const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, doc);
688 return metrics && can_embed(*metrics);
689}
690
691