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 "SkData.h"
9 #include "SkGlyphCache.h"
10 #include "SkMakeUnique.h"
11 #include "SkPDFCanon.h"
12 #include "SkPDFConvertType1FontStream.h"
13 #include "SkPDFDevice.h"
14 #include "SkPDFFont.h"
15 #include "SkPDFMakeCIDGlyphWidthsArray.h"
16 #include "SkPDFMakeToUnicodeCmap.h"
17 #include "SkPDFUtils.h"
18 #include "SkPaint.h"
19 #include "SkRefCnt.h"
20 #include "SkScalar.h"
21 #include "SkStream.h"
22 #include "SkTypes.h"
23 #include "SkUtils.h"
24
25 #ifdef SK_PDF_USE_SFNTLY
26 #include "sample/chromium/font_subsetter.h"
27 #endif
28
MakeVectorCache(SkTypeface * face,int * size)29 SkAutoGlyphCache SkPDFFont::MakeVectorCache(SkTypeface* face, int* size) {
30 SkPaint tmpPaint;
31 tmpPaint.setHinting(SkPaint::kNo_Hinting);
32 tmpPaint.setTypeface(sk_ref_sp(face));
33 int unitsPerEm = face->getUnitsPerEm();
34 if (unitsPerEm <= 0) {
35 unitsPerEm = 1024;
36 }
37 if (size) {
38 *size = unitsPerEm;
39 }
40 tmpPaint.setTextSize((SkScalar)unitsPerEm);
41 const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
42 SkAutoGlyphCache glyphCache(tmpPaint, &props, nullptr);
43 SkASSERT(glyphCache.get());
44 return glyphCache;
45 }
46
47 namespace {
48 // PDF's notion of symbolic vs non-symbolic is related to the character set, not
49 // symbols vs. characters. Rarely is a font the right character set to call it
50 // non-symbolic, so always call it symbolic. (PDF 1.4 spec, section 5.7.1)
51 static const int32_t kPdfSymbolic = 4;
52
53 struct SkPDFType0Font final : public SkPDFFont {
54 SkPDFType0Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&);
55 ~SkPDFType0Font() override;
56 void getFontSubset(SkPDFCanon*) override;
57 #ifdef SK_DEBUG
58 void emitObject(SkWStream*, const SkPDFObjNumMap&) const override;
59 bool fPopulated;
60 #endif
61 typedef SkPDFDict INHERITED;
62 };
63
64 struct SkPDFType1Font final : public SkPDFFont {
65 SkPDFType1Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&, SkPDFCanon*);
~SkPDFType1Font__anondd58a2070111::SkPDFType1Font66 ~SkPDFType1Font() override {}
getFontSubset__anondd58a2070111::SkPDFType1Font67 void getFontSubset(SkPDFCanon*) override {} // TODO(halcanary): implement
68 };
69
70 struct SkPDFType3Font final : public SkPDFFont {
71 SkPDFType3Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&);
~SkPDFType3Font__anondd58a2070111::SkPDFType3Font72 ~SkPDFType3Font() override {}
73 void getFontSubset(SkPDFCanon*) override;
74 };
75
76 ///////////////////////////////////////////////////////////////////////////////
77 // File-Local Functions
78 ///////////////////////////////////////////////////////////////////////////////
79
80 // scale from em-units to base-1000, returning as a SkScalar
from_font_units(SkScalar scaled,uint16_t emSize)81 SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
82 if (emSize == 1000) {
83 return scaled;
84 } else {
85 return scaled * 1000 / emSize;
86 }
87 }
88
scaleFromFontUnits(int16_t val,uint16_t emSize)89 SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
90 return from_font_units(SkIntToScalar(val), emSize);
91 }
92
93
setGlyphWidthAndBoundingBox(SkScalar width,SkIRect box,SkDynamicMemoryWStream * content)94 void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
95 SkDynamicMemoryWStream* content) {
96 // Specify width and bounding box for the glyph.
97 SkPDFUtils::AppendScalar(width, content);
98 content->writeText(" 0 ");
99 content->writeDecAsText(box.fLeft);
100 content->writeText(" ");
101 content->writeDecAsText(box.fTop);
102 content->writeText(" ");
103 content->writeDecAsText(box.fRight);
104 content->writeText(" ");
105 content->writeDecAsText(box.fBottom);
106 content->writeText(" d1\n");
107 }
108
makeFontBBox(SkIRect glyphBBox,uint16_t emSize)109 static sk_sp<SkPDFArray> makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
110 auto bbox = sk_make_sp<SkPDFArray>();
111 bbox->reserve(4);
112 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fLeft, emSize));
113 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fBottom, emSize));
114 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fRight, emSize));
115 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fTop, emSize));
116 return bbox;
117 }
118 } // namespace
119
120 ///////////////////////////////////////////////////////////////////////////////
121 // class SkPDFFont
122 ///////////////////////////////////////////////////////////////////////////////
123
124 /* Font subset design: It would be nice to be able to subset fonts
125 * (particularly type 3 fonts), but it's a lot of work and not a priority.
126 *
127 * Resources are canonicalized and uniqueified by pointer so there has to be
128 * some additional state indicating which subset of the font is used. It
129 * must be maintained at the page granularity and then combined at the document
130 * granularity. a) change SkPDFFont to fill in its state on demand, kind of
131 * like SkPDFGraphicState. b) maintain a per font glyph usage class in each
132 * page/pdf device. c) in the document, retrieve the per font glyph usage
133 * from each page and combine it and ask for a resource with that subset.
134 */
135
~SkPDFFont()136 SkPDFFont::~SkPDFFont() {}
137
can_embed(const SkAdvancedTypefaceMetrics & metrics)138 static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) {
139 return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
140 }
141
GetMetrics(SkTypeface * typeface,SkPDFCanon * canon)142 const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(SkTypeface* typeface,
143 SkPDFCanon* canon) {
144 SkASSERT(typeface);
145 SkFontID id = typeface->uniqueID();
146 if (std::unique_ptr<SkAdvancedTypefaceMetrics>* ptr = canon->fTypefaceMetrics.find(id)) {
147 return ptr->get(); // canon retains ownership.
148 }
149 int count = typeface->countGlyphs();
150 if (count <= 0 || count > 1 + SK_MaxU16) {
151 // Cache nullptr to skip this check. Use SkSafeUnref().
152 canon->fTypefaceMetrics.set(id, nullptr);
153 return nullptr;
154 }
155 std::unique_ptr<SkAdvancedTypefaceMetrics> metrics = typeface->getAdvancedMetrics();
156 if (!metrics) {
157 metrics = skstd::make_unique<SkAdvancedTypefaceMetrics>();
158 }
159
160 if (0 == metrics->fStemV || 0 == metrics->fCapHeight) {
161 SkPaint tmpPaint;
162 tmpPaint.setHinting(SkPaint::kNo_Hinting);
163 tmpPaint.setTypeface(sk_ref_sp(typeface));
164 tmpPaint.setTextSize(1000); // glyph coordinate system
165 if (0 == metrics->fStemV) {
166 // Figure out a good guess for StemV - Min width of i, I, !, 1.
167 // This probably isn't very good with an italic font.
168 int16_t stemV = SHRT_MAX;
169 for (char c : {'i', 'I', '!', '1'}) {
170 SkRect bounds;
171 tmpPaint.measureText(&c, 1, &bounds);
172 stemV = SkTMin(stemV, SkToS16(SkScalarRoundToInt(bounds.width())));
173 }
174 metrics->fStemV = stemV;
175 }
176 if (0 == metrics->fCapHeight) {
177 // Figure out a good guess for CapHeight: average the height of M and X.
178 SkScalar capHeight = 0;
179 for (char c : {'M', 'X'}) {
180 SkRect bounds;
181 tmpPaint.measureText(&c, 1, &bounds);
182 capHeight += bounds.height();
183 }
184 metrics->fCapHeight = SkToS16(SkScalarRoundToInt(capHeight / 2));
185 }
186 }
187 return canon->fTypefaceMetrics.set(id, std::move(metrics))->get();
188 }
189
FontType(const SkAdvancedTypefaceMetrics & metrics)190 SkAdvancedTypefaceMetrics::FontType SkPDFFont::FontType(const SkAdvancedTypefaceMetrics& metrics) {
191 if (SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag) ||
192 SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag)) {
193 // force Type3 fallback.
194 return SkAdvancedTypefaceMetrics::kOther_Font;
195 }
196 return metrics.fType;
197 }
198
first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid)199 static SkGlyphID first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid) {
200 return gid != 0 ? gid - (gid - 1) % 255 : 1;
201 }
202
GetFontResource(SkPDFCanon * canon,SkTypeface * face,SkGlyphID glyphID)203 sk_sp<SkPDFFont> SkPDFFont::GetFontResource(SkPDFCanon* canon,
204 SkTypeface* face,
205 SkGlyphID glyphID) {
206 SkASSERT(canon);
207 SkASSERT(face); // All SkPDFDevice::internalDrawText ensures this.
208 const SkAdvancedTypefaceMetrics* fontMetrics = SkPDFFont::GetMetrics(face, canon);
209 SkASSERT(fontMetrics); // SkPDFDevice::internalDrawText ensures the typeface is good.
210 // GetMetrics only returns null to signify a bad typeface.
211 const SkAdvancedTypefaceMetrics& metrics = *fontMetrics;
212 SkAdvancedTypefaceMetrics::FontType type = SkPDFFont::FontType(metrics);
213 bool multibyte = SkPDFFont::IsMultiByte(type);
214 SkGlyphID subsetCode = multibyte ? 0 : first_nonzero_glyph_for_single_byte_encoding(glyphID);
215 uint64_t fontID = (SkTypeface::UniqueID(face) << 16) | subsetCode;
216
217 if (sk_sp<SkPDFFont>* found = canon->fFontMap.find(fontID)) {
218 SkDEBUGCODE(SkPDFFont* foundFont = found->get());
219 SkASSERT(foundFont && multibyte == foundFont->multiByteGlyphs());
220 return *found;
221 }
222
223 sk_sp<SkTypeface> typeface(sk_ref_sp(face));
224 SkASSERT(typeface);
225
226 SkGlyphID lastGlyph = SkToU16(typeface->countGlyphs() - 1);
227
228 // should be caught by SkPDFDevice::internalDrawText
229 SkASSERT(glyphID <= lastGlyph);
230
231 SkGlyphID firstNonZeroGlyph;
232 if (multibyte) {
233 firstNonZeroGlyph = 1;
234 } else {
235 firstNonZeroGlyph = subsetCode;
236 lastGlyph = SkToU16(SkTMin<int>((int)lastGlyph, 254 + (int)subsetCode));
237 }
238 SkPDFFont::Info info = {std::move(typeface), firstNonZeroGlyph, lastGlyph, type};
239 sk_sp<SkPDFFont> font;
240 switch (type) {
241 case SkAdvancedTypefaceMetrics::kType1CID_Font:
242 case SkAdvancedTypefaceMetrics::kTrueType_Font:
243 SkASSERT(multibyte);
244 font = sk_make_sp<SkPDFType0Font>(std::move(info), metrics);
245 break;
246 case SkAdvancedTypefaceMetrics::kType1_Font:
247 SkASSERT(!multibyte);
248 font = sk_make_sp<SkPDFType1Font>(std::move(info), metrics, canon);
249 break;
250 default:
251 SkASSERT(!multibyte);
252 // Type3 is our fallback font.
253 font = sk_make_sp<SkPDFType3Font>(std::move(info), metrics);
254 break;
255 }
256 canon->fFontMap.set(fontID, font);
257 return font;
258 }
259
SkPDFFont(SkPDFFont::Info info)260 SkPDFFont::SkPDFFont(SkPDFFont::Info info)
261 : SkPDFDict("Font")
262 , fTypeface(std::move(info.fTypeface))
263 , fGlyphUsage(info.fLastGlyphID + 1) // TODO(halcanary): Adjust mapping?
264 , fFirstGlyphID(info.fFirstGlyphID)
265 , fLastGlyphID(info.fLastGlyphID)
266 , fFontType(info.fFontType) {
267 SkASSERT(fTypeface);
268 }
269
add_common_font_descriptor_entries(SkPDFDict * descriptor,const SkAdvancedTypefaceMetrics & metrics,uint16_t emSize,int16_t defaultWidth)270 static void add_common_font_descriptor_entries(SkPDFDict* descriptor,
271 const SkAdvancedTypefaceMetrics& metrics,
272 uint16_t emSize,
273 int16_t defaultWidth) {
274 descriptor->insertName("FontName", metrics.fFontName);
275 descriptor->insertInt("Flags", (size_t)(metrics.fStyle | kPdfSymbolic));
276 descriptor->insertScalar("Ascent",
277 scaleFromFontUnits(metrics.fAscent, emSize));
278 descriptor->insertScalar("Descent",
279 scaleFromFontUnits(metrics.fDescent, emSize));
280 descriptor->insertScalar("StemV",
281 scaleFromFontUnits(metrics.fStemV, emSize));
282 descriptor->insertScalar("CapHeight",
283 scaleFromFontUnits(metrics.fCapHeight, emSize));
284 descriptor->insertInt("ItalicAngle", metrics.fItalicAngle);
285 descriptor->insertObject(
286 "FontBBox", makeFontBBox(metrics.fBBox, emSize));
287 if (defaultWidth > 0) {
288 descriptor->insertScalar("MissingWidth",
289 scaleFromFontUnits(defaultWidth, emSize));
290 }
291 }
292
293 ///////////////////////////////////////////////////////////////////////////////
294 // class SkPDFType0Font
295 ///////////////////////////////////////////////////////////////////////////////
296
SkPDFType0Font(SkPDFFont::Info info,const SkAdvancedTypefaceMetrics & metrics)297 SkPDFType0Font::SkPDFType0Font(
298 SkPDFFont::Info info,
299 const SkAdvancedTypefaceMetrics& metrics)
300 : SkPDFFont(std::move(info)) {
301 SkDEBUGCODE(fPopulated = false);
302 }
303
~SkPDFType0Font()304 SkPDFType0Font::~SkPDFType0Font() {}
305
306
307 #ifdef SK_DEBUG
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap) const308 void SkPDFType0Font::emitObject(SkWStream* stream,
309 const SkPDFObjNumMap& objNumMap) const {
310 SkASSERT(fPopulated);
311 return INHERITED::emitObject(stream, objNumMap);
312 }
313 #endif
314
315 #ifdef SK_PDF_USE_SFNTLY
316 // if possible, make no copy.
stream_to_data(std::unique_ptr<SkStreamAsset> stream)317 static sk_sp<SkData> stream_to_data(std::unique_ptr<SkStreamAsset> stream) {
318 SkASSERT(stream);
319 (void)stream->rewind();
320 SkASSERT(stream->hasLength());
321 size_t size = stream->getLength();
322 if (const void* base = stream->getMemoryBase()) {
323 SkData::ReleaseProc proc =
324 [](const void*, void* ctx) { delete (SkStreamAsset*)ctx; };
325 return SkData::MakeWithProc(base, size, proc, stream.release());
326 }
327 return SkData::MakeFromStream(stream.get(), size);
328 }
329
get_subset_font_stream(std::unique_ptr<SkStreamAsset> fontAsset,const SkBitSet & glyphUsage,const char * fontName,int ttcIndex)330 static sk_sp<SkPDFStream> get_subset_font_stream(
331 std::unique_ptr<SkStreamAsset> fontAsset,
332 const SkBitSet& glyphUsage,
333 const char* fontName,
334 int ttcIndex) {
335 // Generate glyph id array in format needed by sfntly.
336 // TODO(halcanary): sfntly should take a more compact format.
337 SkTDArray<unsigned> subset;
338 if (!glyphUsage.has(0)) {
339 subset.push(0); // Always include glyph 0.
340 }
341 glyphUsage.exportTo(&subset);
342
343 unsigned char* subsetFont{nullptr};
344 sk_sp<SkData> fontData(stream_to_data(std::move(fontAsset)));
345 #if defined(GOOGLE3)
346 // TODO(halcanary): update GOOGLE3 to newest version of Sfntly.
347 (void)ttcIndex;
348 int subsetFontSize = SfntlyWrapper::SubsetFont(fontName,
349 fontData->bytes(),
350 fontData->size(),
351 subset.begin(),
352 subset.count(),
353 &subsetFont);
354 #else
355 (void)fontName;
356 int subsetFontSize = SfntlyWrapper::SubsetFont(ttcIndex,
357 fontData->bytes(),
358 fontData->size(),
359 subset.begin(),
360 subset.count(),
361 &subsetFont);
362 #endif
363 fontData.reset();
364 subset.reset();
365 SkASSERT(subsetFontSize > 0 || subsetFont == nullptr);
366 if (subsetFontSize < 1) {
367 return nullptr;
368 }
369 SkASSERT(subsetFont != nullptr);
370 auto subsetStream = sk_make_sp<SkPDFStream>(
371 SkData::MakeWithProc(
372 subsetFont, subsetFontSize,
373 [](const void* p, void*) { delete[] (unsigned char*)p; },
374 nullptr));
375 subsetStream->dict()->insertInt("Length1", subsetFontSize);
376 return subsetStream;
377 }
378 #endif // SK_PDF_USE_SFNTLY
379
getFontSubset(SkPDFCanon * canon)380 void SkPDFType0Font::getFontSubset(SkPDFCanon* canon) {
381 const SkAdvancedTypefaceMetrics* metricsPtr =
382 SkPDFFont::GetMetrics(this->typeface(), canon);
383 SkASSERT(metricsPtr);
384 if (!metricsPtr) { return; }
385 const SkAdvancedTypefaceMetrics& metrics = *metricsPtr;
386 SkASSERT(can_embed(metrics));
387 SkAdvancedTypefaceMetrics::FontType type = this->getType();
388 SkTypeface* face = this->typeface();
389 SkASSERT(face);
390
391 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
392 uint16_t emSize = SkToU16(this->typeface()->getUnitsPerEm());
393 add_common_font_descriptor_entries(descriptor.get(), metrics, emSize , 0);
394
395 int ttcIndex;
396 std::unique_ptr<SkStreamAsset> fontAsset(face->openStream(&ttcIndex));
397 size_t fontSize = fontAsset ? fontAsset->getLength() : 0;
398 if (0 == fontSize) {
399 SkDebugf("Error: (SkTypeface)(%p)::openStream() returned "
400 "empty stream (%p) when identified as kType1CID_Font "
401 "or kTrueType_Font.\n", face, fontAsset.get());
402 } else {
403 switch (type) {
404 case SkAdvancedTypefaceMetrics::kTrueType_Font: {
405 #ifdef SK_PDF_USE_SFNTLY
406 if (!SkToBool(metrics.fFlags &
407 SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag)) {
408 sk_sp<SkPDFStream> subsetStream = get_subset_font_stream(
409 std::move(fontAsset), this->glyphUsage(),
410 metrics.fFontName.c_str(), ttcIndex);
411 if (subsetStream) {
412 descriptor->insertObjRef("FontFile2", std::move(subsetStream));
413 break;
414 }
415 // If subsetting fails, fall back to original font data.
416 fontAsset.reset(face->openStream(&ttcIndex));
417 SkASSERT(fontAsset);
418 SkASSERT(fontAsset->getLength() == fontSize);
419 if (!fontAsset || fontAsset->getLength() == 0) { break; }
420 }
421 #endif // SK_PDF_USE_SFNTLY
422 auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset));
423 fontStream->dict()->insertInt("Length1", fontSize);
424 descriptor->insertObjRef("FontFile2", std::move(fontStream));
425 break;
426 }
427 case SkAdvancedTypefaceMetrics::kType1CID_Font: {
428 auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset));
429 fontStream->dict()->insertName("Subtype", "CIDFontType0C");
430 descriptor->insertObjRef("FontFile3", std::move(fontStream));
431 break;
432 }
433 default:
434 SkASSERT(false);
435 }
436 }
437
438 auto newCIDFont = sk_make_sp<SkPDFDict>("Font");
439 newCIDFont->insertObjRef("FontDescriptor", std::move(descriptor));
440 newCIDFont->insertName("BaseFont", metrics.fFontName);
441
442 switch (type) {
443 case SkAdvancedTypefaceMetrics::kType1CID_Font:
444 newCIDFont->insertName("Subtype", "CIDFontType0");
445 break;
446 case SkAdvancedTypefaceMetrics::kTrueType_Font:
447 newCIDFont->insertName("Subtype", "CIDFontType2");
448 newCIDFont->insertName("CIDToGIDMap", "Identity");
449 break;
450 default:
451 SkASSERT(false);
452 }
453 auto sysInfo = sk_make_sp<SkPDFDict>();
454 sysInfo->insertString("Registry", "Adobe");
455 sysInfo->insertString("Ordering", "Identity");
456 sysInfo->insertInt("Supplement", 0);
457 newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo));
458
459 int16_t defaultWidth = 0;
460 {
461 int emSize;
462 SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(face, &emSize);
463 sk_sp<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray(
464 glyphCache.get(), &this->glyphUsage(), SkToS16(emSize), &defaultWidth);
465 if (widths && widths->size() > 0) {
466 newCIDFont->insertObject("W", std::move(widths));
467 }
468 newCIDFont->insertScalar(
469 "DW", scaleFromFontUnits(defaultWidth, SkToS16(emSize)));
470 }
471
472 ////////////////////////////////////////////////////////////////////////////
473
474 this->insertName("Subtype", "Type0");
475 this->insertName("BaseFont", metrics.fFontName);
476 this->insertName("Encoding", "Identity-H");
477 auto descendantFonts = sk_make_sp<SkPDFArray>();
478 descendantFonts->appendObjRef(std::move(newCIDFont));
479 this->insertObject("DescendantFonts", std::move(descendantFonts));
480
481 if (metrics.fGlyphToUnicode.count() > 0) {
482 this->insertObjRef("ToUnicode",
483 SkPDFMakeToUnicodeCmap(metrics.fGlyphToUnicode,
484 &this->glyphUsage(),
485 multiByteGlyphs(),
486 firstGlyphID(),
487 lastGlyphID()));
488 }
489 SkDEBUGCODE(fPopulated = true);
490 return;
491 }
492
493 ///////////////////////////////////////////////////////////////////////////////
494 // class SkPDFType1Font
495 ///////////////////////////////////////////////////////////////////////////////
496
make_type1_font_descriptor(SkTypeface * typeface,const SkAdvancedTypefaceMetrics & info)497 static sk_sp<SkPDFDict> make_type1_font_descriptor(
498 SkTypeface* typeface,
499 const SkAdvancedTypefaceMetrics& info) {
500 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
501 uint16_t emSize = SkToU16(typeface->getUnitsPerEm());
502 add_common_font_descriptor_entries(descriptor.get(), info, emSize, 0);
503 if (!can_embed(info)) {
504 return descriptor;
505 }
506 int ttcIndex;
507 size_t header SK_INIT_TO_AVOID_WARNING;
508 size_t data SK_INIT_TO_AVOID_WARNING;
509 size_t trailer SK_INIT_TO_AVOID_WARNING;
510 std::unique_ptr<SkStreamAsset> rawFontData(typeface->openStream(&ttcIndex));
511 sk_sp<SkData> fontData = SkPDFConvertType1FontStream(std::move(rawFontData),
512 &header, &data, &trailer);
513 if (fontData) {
514 auto fontStream = sk_make_sp<SkPDFStream>(std::move(fontData));
515 fontStream->dict()->insertInt("Length1", header);
516 fontStream->dict()->insertInt("Length2", data);
517 fontStream->dict()->insertInt("Length3", trailer);
518 descriptor->insertObjRef("FontFile", std::move(fontStream));
519 }
520 return descriptor;
521 }
522
populate_type_1_font(SkPDFDict * font,const SkAdvancedTypefaceMetrics & info,SkTypeface * typeface,SkGlyphID firstGlyphID,SkGlyphID lastGlyphID)523 static void populate_type_1_font(SkPDFDict* font,
524 const SkAdvancedTypefaceMetrics& info,
525 SkTypeface* typeface,
526 SkGlyphID firstGlyphID,
527 SkGlyphID lastGlyphID) {
528 font->insertName("Subtype", "Type1");
529 font->insertName("BaseFont", info.fFontName);
530
531 // glyphCount not including glyph 0
532 unsigned glyphCount = 1 + lastGlyphID - firstGlyphID;
533 SkASSERT(glyphCount > 0 && glyphCount <= 255);
534 font->insertInt("FirstChar", (size_t)0);
535 font->insertInt("LastChar", (size_t)glyphCount);
536 {
537 int emSize;
538 SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(typeface, &emSize);
539 auto widths = sk_make_sp<SkPDFArray>();
540 SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX;
541 widths->appendScalar(from_font_units(advance, SkToU16(emSize)));
542 for (unsigned gID = firstGlyphID; gID <= lastGlyphID; gID++) {
543 advance = glyphCache->getGlyphIDAdvance(gID).fAdvanceX;
544 widths->appendScalar(from_font_units(advance, SkToU16(emSize)));
545 }
546 font->insertObject("Widths", std::move(widths));
547 }
548 auto encDiffs = sk_make_sp<SkPDFArray>();
549 encDiffs->reserve(lastGlyphID - firstGlyphID + 3);
550 encDiffs->appendInt(0);
551 const SkTArray<SkString>& glyphNames = info.fGlyphNames;
552 SkASSERT(glyphNames.count() > lastGlyphID);
553 encDiffs->appendName(glyphNames[0].c_str());
554 const SkString unknown("UNKNOWN");
555 for (int gID = firstGlyphID; gID <= lastGlyphID; gID++) {
556 const bool valid = gID < glyphNames.count() && !glyphNames[gID].isEmpty();
557 const SkString& name = valid ? glyphNames[gID] : unknown;
558 encDiffs->appendName(name);
559 }
560
561 auto encoding = sk_make_sp<SkPDFDict>("Encoding");
562 encoding->insertObject("Differences", std::move(encDiffs));
563 font->insertObject("Encoding", std::move(encoding));
564 }
565
SkPDFType1Font(SkPDFFont::Info info,const SkAdvancedTypefaceMetrics & metrics,SkPDFCanon * canon)566 SkPDFType1Font::SkPDFType1Font(SkPDFFont::Info info,
567 const SkAdvancedTypefaceMetrics& metrics,
568 SkPDFCanon* canon)
569 : SkPDFFont(std::move(info))
570 {
571 SkFontID fontID = this->typeface()->uniqueID();
572 sk_sp<SkPDFDict> fontDescriptor;
573 if (sk_sp<SkPDFDict>* ptr = canon->fFontDescriptors.find(fontID)) {
574 fontDescriptor = *ptr;
575 } else {
576 fontDescriptor = make_type1_font_descriptor(this->typeface(), metrics);
577 canon->fFontDescriptors.set(fontID, fontDescriptor);
578 }
579 this->insertObjRef("FontDescriptor", std::move(fontDescriptor));
580 // TODO(halcanary): subset this (advances and names).
581 populate_type_1_font(this, metrics, this->typeface(),
582 this->firstGlyphID(), this->lastGlyphID());
583 }
584
585 ///////////////////////////////////////////////////////////////////////////////
586 // class SkPDFType3Font
587 ///////////////////////////////////////////////////////////////////////////////
588
589 namespace {
590 // returns [0, first, first+1, ... last-1, last]
591 struct SingleByteGlyphIdIterator {
SingleByteGlyphIdIterator__anondd58a2070411::SingleByteGlyphIdIterator592 SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
593 : fFirst(first), fLast(last) {
594 SkASSERT(fFirst > 0);
595 SkASSERT(fLast >= first);
596 }
597 struct Iter {
operator ++__anondd58a2070411::SingleByteGlyphIdIterator::Iter598 void operator++() {
599 fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
600 }
601 // This is an input_iterator
operator *__anondd58a2070411::SingleByteGlyphIdIterator::Iter602 SkGlyphID operator*() const { return (SkGlyphID)fCurrent; }
operator !=__anondd58a2070411::SingleByteGlyphIdIterator::Iter603 bool operator!=(const Iter& rhs) const {
604 return fCurrent != rhs.fCurrent;
605 }
Iter__anondd58a2070411::SingleByteGlyphIdIterator::Iter606 Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {}
607 private:
608 const SkGlyphID fFirst;
609 int fCurrent; // must be int to make fLast+1 to fit
610 };
begin__anondd58a2070411::SingleByteGlyphIdIterator611 Iter begin() const { return Iter(fFirst, 0); }
end__anondd58a2070411::SingleByteGlyphIdIterator612 Iter end() const { return Iter(fFirst, (int)fLast + 1); }
613 private:
614 const SkGlyphID fFirst;
615 const SkGlyphID fLast;
616 };
617 }
618
add_type3_font_info(SkPDFCanon * canon,SkPDFDict * font,SkTypeface * typeface,const SkBitSet & subset,SkGlyphID firstGlyphID,SkGlyphID lastGlyphID)619 static void add_type3_font_info(SkPDFCanon* canon,
620 SkPDFDict* font,
621 SkTypeface* typeface,
622 const SkBitSet& subset,
623 SkGlyphID firstGlyphID,
624 SkGlyphID lastGlyphID) {
625 const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon);
626 SkASSERT(lastGlyphID >= firstGlyphID);
627 // Remove unused glyphs at the end of the range.
628 // Keep the lastGlyphID >= firstGlyphID invariant true.
629 while (lastGlyphID > firstGlyphID && !subset.has(lastGlyphID)) {
630 --lastGlyphID;
631 }
632 int unitsPerEm;
633 SkAutoGlyphCache cache = SkPDFFont::MakeVectorCache(typeface, &unitsPerEm);
634 SkScalar emSize = (SkScalar)unitsPerEm;
635 font->insertName("Subtype", "Type3");
636 // Flip about the x-axis and scale by 1/emSize.
637 SkMatrix fontMatrix;
638 fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
639 font->insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
640
641 auto charProcs = sk_make_sp<SkPDFDict>();
642 auto encoding = sk_make_sp<SkPDFDict>("Encoding");
643
644 auto encDiffs = sk_make_sp<SkPDFArray>();
645 // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
646 // plus 1 for glyph 0;
647 SkASSERT(firstGlyphID > 0);
648 SkASSERT(lastGlyphID >= firstGlyphID);
649 int glyphCount = lastGlyphID - firstGlyphID + 2;
650 // one other entry for the index of first glyph.
651 encDiffs->reserve(glyphCount + 1);
652 encDiffs->appendInt(0); // index of first glyph
653
654 auto widthArray = sk_make_sp<SkPDFArray>();
655 widthArray->reserve(glyphCount);
656
657 SkIRect bbox = SkIRect::MakeEmpty();
658
659 sk_sp<SkPDFStream> emptyStream;
660 for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
661 bool skipGlyph = gID != 0 && !subset.has(gID);
662 SkString characterName;
663 SkScalar advance = 0.0f;
664 SkIRect glyphBBox;
665 if (skipGlyph) {
666 characterName.set("g0");
667 } else {
668 characterName.printf("g%X", gID);
669 const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
670 advance = SkFloatToScalar(glyph.fAdvanceX);
671 glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
672 glyph.fWidth, glyph.fHeight);
673 bbox.join(glyphBBox);
674 const SkPath* path = cache->findPath(glyph);
675 if (path && !path->isEmpty()) {
676 SkDynamicMemoryWStream content;
677 setGlyphWidthAndBoundingBox(SkFloatToScalar(glyph.fAdvanceX), glyphBBox,
678 &content);
679 SkPDFUtils::EmitPath(*path, SkPaint::kFill_Style, &content);
680 SkPDFUtils::PaintPath(SkPaint::kFill_Style, path->getFillType(),
681 &content);
682 charProcs->insertObjRef(
683 characterName, sk_make_sp<SkPDFStream>(
684 std::unique_ptr<SkStreamAsset>(content.detachAsStream())));
685 } else {
686 if (!emptyStream) {
687 emptyStream = sk_make_sp<SkPDFStream>(
688 std::unique_ptr<SkStreamAsset>(
689 new SkMemoryStream((size_t)0)));
690 }
691 charProcs->insertObjRef(characterName, emptyStream);
692 }
693 }
694 encDiffs->appendName(characterName.c_str());
695 widthArray->appendScalar(advance);
696 }
697
698 encoding->insertObject("Differences", std::move(encDiffs));
699 font->insertInt("FirstChar", 0);
700 font->insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
701 /* FontBBox: "A rectangle expressed in the glyph coordinate
702 system, specifying the font bounding box. This is the smallest
703 rectangle enclosing the shape that would result if all of the
704 glyphs of the font were placed with their origins coincident and
705 then filled." */
706 auto fontBBox = sk_make_sp<SkPDFArray>();
707 fontBBox->reserve(4);
708 fontBBox->appendInt(bbox.left());
709 fontBBox->appendInt(bbox.bottom());
710 fontBBox->appendInt(bbox.right());
711 fontBBox->appendInt(bbox.top());
712 font->insertObject("FontBBox", std::move(fontBBox));
713 font->insertName("CIDToGIDMap", "Identity");
714 if (metrics && metrics->fGlyphToUnicode.count() > 0) {
715 font->insertObjRef("ToUnicode",
716 SkPDFMakeToUnicodeCmap(metrics->fGlyphToUnicode,
717 &subset,
718 false,
719 firstGlyphID,
720 lastGlyphID));
721 }
722 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
723 int32_t fontDescriptorFlags = kPdfSymbolic;
724 if (metrics) {
725 // Type3 FontDescriptor does not require all the same fields.
726 descriptor->insertName("FontName", metrics->fFontName);
727 descriptor->insertInt("ItalicAngle", metrics->fItalicAngle);
728 fontDescriptorFlags |= (int32_t)metrics->fStyle;
729 }
730 descriptor->insertInt("Flags", fontDescriptorFlags);
731 font->insertObjRef("FontDescriptor", std::move(descriptor));
732 font->insertObject("Widths", std::move(widthArray));
733 font->insertObject("Encoding", std::move(encoding));
734 font->insertObject("CharProcs", std::move(charProcs));
735 }
736
SkPDFType3Font(SkPDFFont::Info info,const SkAdvancedTypefaceMetrics & metrics)737 SkPDFType3Font::SkPDFType3Font(SkPDFFont::Info info,
738 const SkAdvancedTypefaceMetrics& metrics)
739 : SkPDFFont(std::move(info)) {}
740
getFontSubset(SkPDFCanon * canon)741 void SkPDFType3Font::getFontSubset(SkPDFCanon* canon) {
742 add_type3_font_info(canon, this, this->typeface(), this->glyphUsage(),
743 this->firstGlyphID(), this->lastGlyphID());
744 }
745
746 ////////////////////////////////////////////////////////////////////////////////
747
CanEmbedTypeface(SkTypeface * typeface,SkPDFCanon * canon)748 bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFCanon* canon) {
749 const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon);
750 return metrics && can_embed(*metrics);
751 }
752
drop()753 void SkPDFFont::drop() {
754 fTypeface = nullptr;
755 fGlyphUsage.~SkBitSet();
756 new (&fGlyphUsage) SkBitSet(0);
757 this->SkPDFDict::drop();
758 }
759