• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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