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