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