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