| 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 | |