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*/
22static 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
48static bool parsePFB(const uint8_t* src, size_t size, size_t* headerLen,
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 */
67static bool parsePFA(const char* src, size_t size, size_t* headerLen,
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
120static 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
133static sk_sp<SkData> convert_type1_font_stream(std::unique_ptr<SkStreamAsset> srcStream,
134 size_t* headerLen,
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 kPFBSectionHeaderLength = 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 srcHeader = 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 resultHeader = (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
219inline static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) {
220 return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
221}
222
223inline static SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
224 return emSize == 1000 ? scaled : scaled * 1000 / emSize;
225}
226
227static 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 header 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
257static 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
270static 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
283void 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