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