Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkPDFType1Font.cpp
Go to the documentation of this file.
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
5
8#include "src/core/SkStrike.h"
10
11#include <ctype.h>
12
13using 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*/
25static 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
51static 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 */
70static 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
123static 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
136static 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
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);
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
222inline static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) {
224}
225
226inline static SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
227 return emSize == 1000 ? scaled : scaled * 1000 / emSize;
228}
229
231 const SkTypeface* typeface,
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;
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),
254 }
255 }
256 }
257 return doc->emit(descriptor);
258}
259
260
261static 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
275 const SkTypeface* typeface) {
276 SkTypefaceID typefaceID = typeface->uniqueID();
277 if (SkPDFIndirectReference* ptr = doc->fFontDescriptors.find(typefaceID)) {
278 return *ptr;
279 }
281 auto fontDescriptor = make_type1_font_descriptor(doc, typeface, info);
282 doc->fFontDescriptors.set(typefaceID, fontDescriptor);
283 return fontDescriptor;
284}
285
286
287void 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}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
uint16_t glyphs[5]
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SK_INIT_TO_AVOID_WARNING
Definition SkMacros.h:58
static bool parsePFBSection(const uint8_t **src, size_t *len, int sectionType, size_t *size)
static const std::vector< SkString > & type_1_glyphnames(SkPDFDocument *canon, const SkTypeface *typeface)
static sk_sp< SkData > convert_type1_font_stream(std::unique_ptr< SkStreamAsset > srcStream, size_t *headerLen, size_t *dataLen, size_t *trailerLen)
void SkPDFEmitType1Font(const SkPDFFont &pdfFont, SkPDFDocument *doc)
static SkPDFIndirectReference make_type1_font_descriptor(SkPDFDocument *doc, const SkTypeface *typeface, const SkAdvancedTypefaceMetrics *info)
static bool parsePFB(const uint8_t *src, size_t size, size_t *headerLen, size_t *dataLen, size_t *trailerLen)
static SkScalar from_font_units(SkScalar scaled, uint16_t emSize)
static bool parsePFA(const char *src, size_t size, size_t *headerLen, size_t *hexDataLen, size_t *dataLen, size_t *trailerLen)
static bool can_embed(const SkAdvancedTypefaceMetrics &metrics)
static int8_t hexToBin(uint8_t c)
static SkPDFIndirectReference type1_font_descriptor(SkPDFDocument *doc, const SkTypeface *typeface)
SkPDFIndirectReference SkPDFStreamOut(std::unique_ptr< SkPDFDict > dict, std::unique_ptr< SkStreamAsset > content, SkPDFDocument *doc, SkPDFSteamCompressionEnabled compress)
static std::unique_ptr< SkPDFDict > SkPDFMakeDict(const char *type=nullptr)
Definition SkPDFTypes.h:195
static std::unique_ptr< SkPDFArray > SkPDFMakeArray(Args... args)
Definition SkPDFTypes.h:135
constexpr uint16_t SkToU16(S x)
Definition SkTo.h:24
constexpr int SkToInt(S x)
Definition SkTo.h:29
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
uint32_t SkTypefaceID
Definition SkTypeface.h:38
uint16_t SkGlyphID
Definition SkTypes.h:179
const SkScalar widths[]
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition SkData.cpp:116
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
Definition SkStream.cpp:314
void insertRef(const char key[], SkPDFIndirectReference)
SkPDFIndirectReference emit(const SkPDFObject &, SkPDFIndirectReference)
skia_private::THashMap< uint32_t, SkPDFIndirectReference > fFontDescriptors
skia_private::THashMap< uint32_t, std::vector< SkString > > fType1GlyphNames
static const SkAdvancedTypefaceMetrics * GetMetrics(const SkTypeface *typeface, SkPDFDocument *canon)
static void PopulateCommonFontDescriptor(SkPDFDict *descriptor, const SkAdvancedTypefaceMetrics &, uint16_t emSize, int16_t defaultWidth)
SkPDFIndirectReference indirectReference() const
Definition SkPDFFont.h:81
SkGlyphID lastGlyphID() const
Definition SkPDFFont.h:119
SkGlyphID firstGlyphID() const
Definition SkPDFFont.h:118
static void GetType1GlyphNames(const SkTypeface &, SkString *)
Definition SkPDFFont.cpp:53
SkTypeface * typeface() const
Definition SkPDFFont.h:39
static SkStrikeSpec MakePDFVector(const SkTypeface &typeface, int *size)
int countGlyphs() const
SkTypefaceID uniqueID() const
Definition SkTypeface.h:101
int getUnitsPerEm() const
std::unique_ptr< SkStreamAsset > openStream(int *ttcIndex) const
V * find(const K &key) const
Definition SkTHash.h:479
V * set(K key, V val)
Definition SkTHash.h:472
float SkScalar
Definition extension.cpp:12
glong glong end
static const uint8_t buffer[]
size_t length
static const char header[]
Definition skpbench.cpp:88
@ kNotEmbeddable_FontFlag
May not be embedded.