• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 Google LLC.
2 // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3 
4 #include "src/pdf/SkPDFType1Font.h"
5 
6 #include "include/private/base/SkTemplates.h"
7 #include "include/private/base/SkTo.h"
8 #include "src/core/SkStrike.h"
9 #include "src/core/SkStrikeSpec.h"
10 
11 #include <ctype.h>
12 
13 using namespace skia_private;
14 
15 /*
16   "A standard Type 1 font program, as described in the Adobe Type 1
17   Font Format specification, consists of three parts: a clear-text
18   portion (written using PostScript syntax), an encrypted portion, and
19   a fixed-content portion.  The fixed-content portion contains 512
20   ASCII zeros followed by a cleartomark operator, and perhaps followed
21   by additional data. Although the encrypted portion of a standard
22   Type 1 font may be in binary or ASCII hexadecimal format, PDF
23   supports only the binary format."
24 */
parsePFBSection(const uint8_t ** src,size_t * len,int sectionType,size_t * size)25 static bool parsePFBSection(const uint8_t** src, size_t* len, int sectionType,
26                             size_t* size) {
27     // PFB sections have a two or six bytes header. 0x80 and a one byte
28     // section type followed by a four byte section length.  Type one is
29     // an ASCII section (includes a length), type two is a binary section
30     // (includes a length) and type three is an EOF marker with no length.
31     const uint8_t* buf = *src;
32     if (*len < 2 || buf[0] != 0x80 || buf[1] != sectionType) {
33         return false;
34     } else if (buf[1] == 3) {
35         return true;
36     } else if (*len < 6) {
37         return false;
38     }
39 
40     *size = (size_t)buf[2] | ((size_t)buf[3] << 8) | ((size_t)buf[4] << 16) |
41             ((size_t)buf[5] << 24);
42     size_t consumed = *size + 6;
43     if (consumed > *len) {
44         return false;
45     }
46     *src = *src + consumed;
47     *len = *len - consumed;
48     return true;
49 }
50 
parsePFB(const uint8_t * src,size_t size,size_t * headerLen,size_t * dataLen,size_t * trailerLen)51 static bool parsePFB(const uint8_t* src, size_t size, size_t* headerLen,
52                      size_t* dataLen, size_t* trailerLen) {
53     const uint8_t* srcPtr = src;
54     size_t remaining = size;
55 
56     return parsePFBSection(&srcPtr, &remaining, 1, headerLen) &&
57            parsePFBSection(&srcPtr, &remaining, 2, dataLen) &&
58            parsePFBSection(&srcPtr, &remaining, 1, trailerLen) &&
59            parsePFBSection(&srcPtr, &remaining, 3, nullptr);
60 }
61 
62 /* The sections of a PFA file are implicitly defined.  The body starts
63  * after the line containing "eexec," and the trailer starts with 512
64  * literal 0's followed by "cleartomark" (plus arbitrary white space).
65  *
66  * This function assumes that src is NUL terminated, but the NUL
67  * termination is not included in size.
68  *
69  */
parsePFA(const char * src,size_t size,size_t * headerLen,size_t * hexDataLen,size_t * dataLen,size_t * trailerLen)70 static bool parsePFA(const char* src, size_t size, size_t* headerLen,
71                      size_t* hexDataLen, size_t* dataLen, size_t* trailerLen) {
72     const char* end = src + size;
73 
74     const char* dataPos = strstr(src, "eexec");
75     if (!dataPos) {
76         return false;
77     }
78     dataPos += strlen("eexec");
79     while ((*dataPos == '\n' || *dataPos == '\r' || *dataPos == ' ') &&
80             dataPos < end) {
81         dataPos++;
82     }
83     *headerLen = dataPos - src;
84 
85     const char* trailerPos = strstr(dataPos, "cleartomark");
86     if (!trailerPos) {
87         return false;
88     }
89     int zeroCount = 0;
90     for (trailerPos--; trailerPos > dataPos && zeroCount < 512; trailerPos--) {
91         if (*trailerPos == '\n' || *trailerPos == '\r' || *trailerPos == ' ') {
92             continue;
93         } else if (*trailerPos == '0') {
94             zeroCount++;
95         } else {
96             return false;
97         }
98     }
99     if (zeroCount != 512) {
100         return false;
101     }
102 
103     *hexDataLen = trailerPos - src - *headerLen;
104     *trailerLen = size - *headerLen - *hexDataLen;
105 
106     // Verify that the data section is hex encoded and count the bytes.
107     int nibbles = 0;
108     for (; dataPos < trailerPos; dataPos++) {
109         if (isspace(*dataPos)) {
110             continue;
111         }
112         // isxdigit() is locale-sensitive https://bugs.skia.org/8285
113         if (nullptr == strchr("0123456789abcdefABCDEF", *dataPos)) {
114             return false;
115         }
116         nibbles++;
117     }
118     *dataLen = (nibbles + 1) / 2;
119 
120     return true;
121 }
122 
hexToBin(uint8_t c)123 static int8_t hexToBin(uint8_t c) {
124     if (!isxdigit(c)) {
125         return -1;
126     } else if (c <= '9') {
127         return c - '0';
128     } else if (c <= 'F') {
129         return c - 'A' + 10;
130     } else if (c <= 'f') {
131         return c - 'a' + 10;
132     }
133     return -1;
134 }
135 
convert_type1_font_stream(std::unique_ptr<SkStreamAsset> srcStream,size_t * headerLen,size_t * dataLen,size_t * trailerLen)136 static sk_sp<SkData> convert_type1_font_stream(std::unique_ptr<SkStreamAsset> srcStream,
137                                                size_t* headerLen,
138                                                size_t* dataLen,
139                                                size_t* trailerLen) {
140     size_t srcLen = srcStream ? srcStream->getLength() : 0;
141     SkASSERT(srcLen);
142     if (!srcLen) {
143         return nullptr;
144     }
145     // Flatten and Nul-terminate the source stream so that we can use
146     // strstr() to search it.
147     AutoTMalloc<uint8_t> sourceBuffer(SkToInt(srcLen + 1));
148     (void)srcStream->read(sourceBuffer.get(), srcLen);
149     sourceBuffer[SkToInt(srcLen)] = 0;
150     const uint8_t* src = sourceBuffer.get();
151 
152     if (parsePFB(src, srcLen, headerLen, dataLen, trailerLen)) {
153         static const int kPFBSectionHeaderLength = 6;
154         const size_t length = *headerLen + *dataLen + *trailerLen;
155         SkASSERT(length > 0);
156         SkASSERT(length + (2 * kPFBSectionHeaderLength) <= srcLen);
157 
158         sk_sp<SkData> data(SkData::MakeUninitialized(length));
159 
160         const uint8_t* const srcHeader = src + kPFBSectionHeaderLength;
161         // There is a six-byte section header before header and data
162         // (but not trailer) that we're not going to copy.
163         const uint8_t* const srcData = srcHeader + *headerLen + kPFBSectionHeaderLength;
164         const uint8_t* const srcTrailer = srcData + *headerLen;
165 
166         uint8_t* const resultHeader = (uint8_t*)data->writable_data();
167         uint8_t* const resultData = resultHeader + *headerLen;
168         uint8_t* const resultTrailer = resultData + *dataLen;
169 
170         SkASSERT(resultTrailer + *trailerLen == resultHeader + length);
171 
172         memcpy(resultHeader,  srcHeader,  *headerLen);
173         memcpy(resultData,    srcData,    *dataLen);
174         memcpy(resultTrailer, srcTrailer, *trailerLen);
175 
176         return data;
177     }
178 
179     // A PFA has to be converted for PDF.
180     size_t hexDataLen;
181     if (!parsePFA((const char*)src, srcLen, headerLen, &hexDataLen, dataLen,
182                  trailerLen)) {
183         return nullptr;
184     }
185     const size_t length = *headerLen + *dataLen + *trailerLen;
186     SkASSERT(length > 0);
187     auto data = SkData::MakeUninitialized(length);
188     uint8_t* buffer = (uint8_t*)data->writable_data();
189 
190     memcpy(buffer, src, *headerLen);
191     uint8_t* const resultData = &(buffer[*headerLen]);
192 
193     const uint8_t* hexData = src + *headerLen;
194     const uint8_t* trailer = hexData + hexDataLen;
195     size_t outputOffset = 0;
196     uint8_t dataByte = 0;  // To hush compiler.
197     bool highNibble = true;
198     for (; hexData < trailer; hexData++) {
199         int8_t curNibble = hexToBin(*hexData);
200         if (curNibble < 0) {
201             continue;
202         }
203         if (highNibble) {
204             dataByte = curNibble << 4;
205             highNibble = false;
206         } else {
207             dataByte |= curNibble;
208             highNibble = true;
209             resultData[outputOffset++] = dataByte;
210         }
211     }
212     if (!highNibble) {
213         resultData[outputOffset++] = dataByte;
214     }
215     SkASSERT(outputOffset == *dataLen);
216 
217     uint8_t* const resultTrailer = &(buffer[SkToInt(*headerLen + outputOffset)]);
218     memcpy(resultTrailer, src + *headerLen + hexDataLen, *trailerLen);
219     return data;
220 }
221 
can_embed(const SkAdvancedTypefaceMetrics & metrics)222 inline static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) {
223     return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
224 }
225 
from_font_units(SkScalar scaled,uint16_t emSize)226 inline static SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
227     return emSize == 1000 ? scaled : scaled * 1000 / emSize;
228 }
229 
make_type1_font_descriptor(SkPDFDocument * doc,const SkTypeface * typeface,const SkAdvancedTypefaceMetrics * info)230 static SkPDFIndirectReference make_type1_font_descriptor(SkPDFDocument* doc,
231                                                          const SkTypeface* typeface,
232                                                          const SkAdvancedTypefaceMetrics* info) {
233     SkPDFDict descriptor("FontDescriptor");
234     uint16_t emSize = SkToU16(typeface->getUnitsPerEm());
235     if (info) {
236         SkPDFFont::PopulateCommonFontDescriptor(&descriptor, *info, emSize, 0);
237         if (can_embed(*info)) {
238             int ttcIndex;
239             size_t header SK_INIT_TO_AVOID_WARNING;
240             size_t data SK_INIT_TO_AVOID_WARNING;
241             size_t trailer SK_INIT_TO_AVOID_WARNING;
242             std::unique_ptr<SkStreamAsset> rawFontData = typeface->openStream(&ttcIndex);
243             sk_sp<SkData> fontData = convert_type1_font_stream(std::move(rawFontData),
244                                                                &header, &data, &trailer);
245             if (fontData) {
246                 std::unique_ptr<SkPDFDict> dict = SkPDFMakeDict();
247                 dict->insertInt("Length1", header);
248                 dict->insertInt("Length2", data);
249                 dict->insertInt("Length3", trailer);
250                 auto fontStream = SkMemoryStream::Make(std::move(fontData));
251                 descriptor.insertRef("FontFile",
252                                      SkPDFStreamOut(std::move(dict), std::move(fontStream),
253                                                     doc, SkPDFSteamCompressionEnabled::Yes));
254             }
255         }
256     }
257     return doc->emit(descriptor);
258 }
259 
260 
type_1_glyphnames(SkPDFDocument * canon,const SkTypeface * typeface)261 static const std::vector<SkString>& type_1_glyphnames(SkPDFDocument* canon,
262                                                       const SkTypeface* typeface) {
263     SkTypefaceID typefaceID = typeface->uniqueID();
264     const std::vector<SkString>* glyphNames = canon->fType1GlyphNames.find(typefaceID);
265     if (!glyphNames) {
266         std::vector<SkString> names(typeface->countGlyphs());
267         SkPDFFont::GetType1GlyphNames(*typeface, names.data());
268         glyphNames = canon->fType1GlyphNames.set(typefaceID, std::move(names));
269     }
270     SkASSERT(glyphNames);
271     return *glyphNames;
272 }
273 
type1_font_descriptor(SkPDFDocument * doc,const SkTypeface * typeface)274 static SkPDFIndirectReference type1_font_descriptor(SkPDFDocument* doc,
275                                                     const SkTypeface* typeface) {
276     SkTypefaceID typefaceID = typeface->uniqueID();
277     if (SkPDFIndirectReference* ptr = doc->fFontDescriptors.find(typefaceID)) {
278         return *ptr;
279     }
280     const SkAdvancedTypefaceMetrics* info = SkPDFFont::GetMetrics(typeface, doc);
281     auto fontDescriptor = make_type1_font_descriptor(doc, typeface, info);
282     doc->fFontDescriptors.set(typefaceID, fontDescriptor);
283     return fontDescriptor;
284 }
285 
286 
SkPDFEmitType1Font(const SkPDFFont & pdfFont,SkPDFDocument * doc)287 void SkPDFEmitType1Font(const SkPDFFont& pdfFont, SkPDFDocument* doc) {
288     SkTypeface* typeface = pdfFont.typeface();
289     const std::vector<SkString>& glyphNames = type_1_glyphnames(doc, typeface);
290     SkGlyphID firstGlyphID = pdfFont.firstGlyphID();
291     SkGlyphID lastGlyphID = pdfFont.lastGlyphID();
292 
293     SkPDFDict font("Font");
294     font.insertRef("FontDescriptor", type1_font_descriptor(doc, typeface));
295     font.insertName("Subtype", "Type1");
296     if (const SkAdvancedTypefaceMetrics* info = SkPDFFont::GetMetrics(typeface, doc)) {
297         font.insertName("BaseFont", info->fPostScriptName);
298     }
299 
300     // glyphCount not including glyph 0
301     unsigned glyphCount = 1 + lastGlyphID - firstGlyphID;
302     SkASSERT(glyphCount > 0 && glyphCount <= 255);
303     font.insertInt("FirstChar", (size_t)0);
304     font.insertInt("LastChar", (size_t)glyphCount);
305     {
306         int emSize;
307         auto widths = SkPDFMakeArray();
308 
309         int glyphRangeSize = lastGlyphID - firstGlyphID + 2;
310         AutoTArray<SkGlyphID> glyphIDs{glyphRangeSize};
311         glyphIDs[0] = 0;
312         for (unsigned gId = firstGlyphID; gId <= lastGlyphID; gId++) {
313             glyphIDs[gId - firstGlyphID + 1] = gId;
314         }
315         SkStrikeSpec strikeSpec = SkStrikeSpec::MakePDFVector(*typeface, &emSize);
316         SkBulkGlyphMetrics metrics{strikeSpec};
317         auto glyphs = metrics.glyphs(SkSpan(glyphIDs.get(), glyphRangeSize));
318         for (int i = 0; i < glyphRangeSize; ++i) {
319             widths->appendScalar(from_font_units(glyphs[i]->advanceX(), SkToU16(emSize)));
320         }
321         font.insertObject("Widths", std::move(widths));
322     }
323     auto encDiffs = SkPDFMakeArray();
324     encDiffs->reserve(lastGlyphID - firstGlyphID + 3);
325     encDiffs->appendInt(0);
326 
327     SkASSERT(glyphNames.size() > lastGlyphID);
328     const SkString unknown("UNKNOWN");
329     encDiffs->appendName(glyphNames[0].isEmpty() ? unknown : glyphNames[0]);
330     for (int gID = firstGlyphID; gID <= lastGlyphID; gID++) {
331         encDiffs->appendName(glyphNames[gID].isEmpty() ? unknown : glyphNames[gID]);
332     }
333 
334     auto encoding = SkPDFMakeDict("Encoding");
335     encoding->insertObject("Differences", std::move(encDiffs));
336     font.insertObject("Encoding", std::move(encoding));
337 
338     doc->emit(font, pdfFont.indirectReference());
339 }
340