blob: dd01458981a57fd38c113e0f64b84f431fe537ab [file] [log] [blame]
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2011 Google Inc.
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00006 */
7
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00008#include <ctype.h>
9
reed@google.com8a85d0c2011-06-24 19:12:12 +000010#include "SkData.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000011#include "SkGlyphCache.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000012#include "SkPaint.h"
halcanaryfb62b3d2015-01-21 09:59:14 -080013#include "SkPDFCanon.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000014#include "SkPDFDevice.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000015#include "SkPDFFont.h"
vandebo@chromium.org98594282011-07-25 22:34:12 +000016#include "SkPDFFontImpl.h"
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000017#include "SkPDFStream.h"
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000018#include "SkPDFTypes.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000019#include "SkPDFUtils.h"
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +000020#include "SkRefCnt.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000021#include "SkScalar.h"
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000022#include "SkStream.h"
reed@google.comfed86bd2013-03-14 15:04:57 +000023#include "SkTypefacePriv.h"
vandebo@chromium.org325cb9a2011-03-30 18:36:29 +000024#include "SkTypes.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000025#include "SkUtils.h"
26
mtkleind1371a62015-02-17 06:33:38 -080027#if defined (GOOGLE3)
28 // #including #defines doesn't work in with this build system.
29 #include "typography/font/sfntly/src/sample/chromium/font_subsetter.h"
30 #define SK_SFNTLY_SUBSETTER // For the benefit of #ifdefs below.
halcanary7be0ce02015-05-18 13:15:56 -070031#elif defined (SK_SFNTLY_SUBSETTER)
32 #include SK_SFNTLY_SUBSETTER
vandebo@chromium.org1f165892011-07-26 02:11:41 +000033#endif
34
vandebo@chromium.orgdcf9c192013-03-13 20:01:51 +000035// PDF's notion of symbolic vs non-symbolic is related to the character set, not
36// symbols vs. characters. Rarely is a font the right character set to call it
37// non-symbolic, so always call it symbolic. (PDF 1.4 spec, section 5.7.1)
38static const int kPdfSymbolic = 4;
39
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000040namespace {
41
vandebo@chromium.org98594282011-07-25 22:34:12 +000042///////////////////////////////////////////////////////////////////////////////
43// File-Local Functions
44///////////////////////////////////////////////////////////////////////////////
45
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000046bool parsePFBSection(const uint8_t** src, size_t* len, int sectionType,
47 size_t* size) {
48 // PFB sections have a two or six bytes header. 0x80 and a one byte
49 // section type followed by a four byte section length. Type one is
50 // an ASCII section (includes a length), type two is a binary section
51 // (includes a length) and type three is an EOF marker with no length.
52 const uint8_t* buf = *src;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000053 if (*len < 2 || buf[0] != 0x80 || buf[1] != sectionType) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000054 return false;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000055 } else if (buf[1] == 3) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000056 return true;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000057 } else if (*len < 6) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000058 return false;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000059 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000060
vandebo@chromium.org73322072011-06-21 21:19:41 +000061 *size = (size_t)buf[2] | ((size_t)buf[3] << 8) | ((size_t)buf[4] << 16) |
62 ((size_t)buf[5] << 24);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000063 size_t consumed = *size + 6;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000064 if (consumed > *len) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000065 return false;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000066 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000067 *src = *src + consumed;
68 *len = *len - consumed;
69 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000070}
71
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000072bool parsePFB(const uint8_t* src, size_t size, size_t* headerLen,
73 size_t* dataLen, size_t* trailerLen) {
74 const uint8_t* srcPtr = src;
75 size_t remaining = size;
76
77 return parsePFBSection(&srcPtr, &remaining, 1, headerLen) &&
78 parsePFBSection(&srcPtr, &remaining, 2, dataLen) &&
79 parsePFBSection(&srcPtr, &remaining, 1, trailerLen) &&
80 parsePFBSection(&srcPtr, &remaining, 3, NULL);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000081}
82
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000083/* The sections of a PFA file are implicitly defined. The body starts
84 * after the line containing "eexec," and the trailer starts with 512
85 * literal 0's followed by "cleartomark" (plus arbitrary white space).
86 *
87 * This function assumes that src is NUL terminated, but the NUL
88 * termination is not included in size.
89 *
90 */
91bool parsePFA(const char* src, size_t size, size_t* headerLen,
92 size_t* hexDataLen, size_t* dataLen, size_t* trailerLen) {
93 const char* end = src + size;
94
95 const char* dataPos = strstr(src, "eexec");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000096 if (!dataPos) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000097 return false;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000098 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000099 dataPos += strlen("eexec");
100 while ((*dataPos == '\n' || *dataPos == '\r' || *dataPos == ' ') &&
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000101 dataPos < end) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000102 dataPos++;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000103 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000104 *headerLen = dataPos - src;
105
106 const char* trailerPos = strstr(dataPos, "cleartomark");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000107 if (!trailerPos) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000108 return false;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000109 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000110 int zeroCount = 0;
111 for (trailerPos--; trailerPos > dataPos && zeroCount < 512; trailerPos--) {
112 if (*trailerPos == '\n' || *trailerPos == '\r' || *trailerPos == ' ') {
113 continue;
114 } else if (*trailerPos == '0') {
115 zeroCount++;
116 } else {
117 return false;
118 }
119 }
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000120 if (zeroCount != 512) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000121 return false;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000122 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000123
124 *hexDataLen = trailerPos - src - *headerLen;
125 *trailerLen = size - *headerLen - *hexDataLen;
126
127 // Verify that the data section is hex encoded and count the bytes.
128 int nibbles = 0;
129 for (; dataPos < trailerPos; dataPos++) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000130 if (isspace(*dataPos)) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000131 continue;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000132 }
133 if (!isxdigit(*dataPos)) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000134 return false;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000135 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000136 nibbles++;
137 }
138 *dataLen = (nibbles + 1) / 2;
139
140 return true;
141}
142
143int8_t hexToBin(uint8_t c) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000144 if (!isxdigit(c)) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000145 return -1;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000146 } 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 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000153 return -1;
154}
155
halcanary67ec1f82014-06-27 11:36:20 -0700156static SkData* handle_type1_stream(SkStream* srcStream, size_t* headerLen,
157 size_t* dataLen, size_t* trailerLen) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000158 // srcStream may be backed by a file or a unseekable fd, so we may not be
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000159 // able to use skip(), rewind(), or getMemoryBase(). read()ing through
160 // the input only once is doable, but very ugly. Furthermore, it'd be nice
161 // if the data was NUL terminated so that we can use strstr() to search it.
162 // Make as few copies as possible given these constraints.
163 SkDynamicMemoryWStream dynamicStream;
scroggoa1193e42015-01-21 12:09:53 -0800164 SkAutoTDelete<SkMemoryStream> staticStream;
reed@google.com8a85d0c2011-06-24 19:12:12 +0000165 SkData* data = NULL;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000166 const uint8_t* src;
167 size_t srcLen;
168 if ((srcLen = srcStream->getLength()) > 0) {
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000169 staticStream.reset(new SkMemoryStream(srcLen + 1));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000170 src = (const uint8_t*)staticStream->getMemoryBase();
171 if (srcStream->getMemoryBase() != NULL) {
172 memcpy((void *)src, srcStream->getMemoryBase(), srcLen);
173 } else {
174 size_t read = 0;
175 while (read < srcLen) {
176 size_t got = srcStream->read((void *)staticStream->getAtPos(),
177 srcLen - read);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000178 if (got == 0) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000179 return NULL;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000180 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000181 read += got;
182 staticStream->seek(read);
183 }
184 }
185 ((uint8_t *)src)[srcLen] = 0;
186 } else {
ctguil@chromium.orga5c72342011-08-15 23:55:03 +0000187 static const size_t kBufSize = 4096;
188 uint8_t buf[kBufSize];
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000189 size_t amount;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000190 while ((amount = srcStream->read(buf, kBufSize)) > 0) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000191 dynamicStream.write(buf, amount);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000192 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000193 amount = 0;
194 dynamicStream.write(&amount, 1); // NULL terminator.
reed@google.com8a85d0c2011-06-24 19:12:12 +0000195 data = dynamicStream.copyToData();
196 src = data->bytes();
197 srcLen = data->size() - 1;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000198 }
199
reed@google.com8a85d0c2011-06-24 19:12:12 +0000200 // this handles releasing the data we may have gotten from dynamicStream.
201 // if data is null, it is a no-op
202 SkAutoDataUnref aud(data);
203
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000204 if (parsePFB(src, srcLen, headerLen, dataLen, trailerLen)) {
halcanary67ec1f82014-06-27 11:36:20 -0700205 static const int kPFBSectionHeaderLength = 6;
206 const size_t length = *headerLen + *dataLen + *trailerLen;
207 SkASSERT(length > 0);
208 SkASSERT(length + (2 * kPFBSectionHeaderLength) <= srcLen);
209
reed33a30502014-09-11 08:42:36 -0700210 SkData* data = SkData::NewUninitialized(length);
halcanary67ec1f82014-06-27 11:36:20 -0700211
212 const uint8_t* const srcHeader = src + kPFBSectionHeaderLength;
213 // There is a six-byte section header before header and data
214 // (but not trailer) that we're not going to copy.
reed33a30502014-09-11 08:42:36 -0700215 const uint8_t* const srcData = srcHeader + *headerLen + kPFBSectionHeaderLength;
halcanary67ec1f82014-06-27 11:36:20 -0700216 const uint8_t* const srcTrailer = srcData + *headerLen;
217
reed33a30502014-09-11 08:42:36 -0700218 uint8_t* const resultHeader = (uint8_t*)data->writable_data();
halcanary67ec1f82014-06-27 11:36:20 -0700219 uint8_t* const resultData = resultHeader + *headerLen;
220 uint8_t* const resultTrailer = resultData + *dataLen;
221
222 SkASSERT(resultTrailer + *trailerLen == resultHeader + length);
223
224 memcpy(resultHeader, srcHeader, *headerLen);
225 memcpy(resultData, srcData, *dataLen);
226 memcpy(resultTrailer, srcTrailer, *trailerLen);
227
reed33a30502014-09-11 08:42:36 -0700228 return data;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000229 }
230
231 // A PFA has to be converted for PDF.
232 size_t hexDataLen;
233 if (parsePFA((const char*)src, srcLen, headerLen, &hexDataLen, dataLen,
234 trailerLen)) {
halcanary67ec1f82014-06-27 11:36:20 -0700235 const size_t length = *headerLen + *dataLen + *trailerLen;
236 SkASSERT(length > 0);
237 SkAutoTMalloc<uint8_t> buffer(length);
238
239 memcpy(buffer.get(), src, *headerLen);
bsalomon98806072014-12-12 15:11:17 -0800240 uint8_t* const resultData = &(buffer[SkToInt(*headerLen)]);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000241
242 const uint8_t* hexData = src + *headerLen;
243 const uint8_t* trailer = hexData + hexDataLen;
244 size_t outputOffset = 0;
vandebo@chromium.org5b073682011-03-08 18:33:31 +0000245 uint8_t dataByte = 0; // To hush compiler.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000246 bool highNibble = true;
247 for (; hexData < trailer; hexData++) {
commit-bot@chromium.org3720fda2013-07-10 15:03:52 +0000248 int8_t curNibble = hexToBin(*hexData);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000249 if (curNibble < 0) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000250 continue;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000251 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000252 if (highNibble) {
253 dataByte = curNibble << 4;
254 highNibble = false;
255 } else {
256 dataByte |= curNibble;
257 highNibble = true;
halcanary67ec1f82014-06-27 11:36:20 -0700258 resultData[outputOffset++] = dataByte;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000259 }
260 }
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000261 if (!highNibble) {
halcanary67ec1f82014-06-27 11:36:20 -0700262 resultData[outputOffset++] = dataByte;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000263 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000264 SkASSERT(outputOffset == *dataLen);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000265
bsalomon98806072014-12-12 15:11:17 -0800266 uint8_t* const resultTrailer = &(buffer[SkToInt(*headerLen + outputOffset)]);
halcanary67ec1f82014-06-27 11:36:20 -0700267 memcpy(resultTrailer, src + *headerLen + hexDataLen, *trailerLen);
268
269 return SkData::NewFromMalloc(buffer.detach(), length);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000270 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000271 return NULL;
272}
273
reed@google.com3f0dcf92011-03-18 21:23:45 +0000274// scale from em-units to base-1000, returning as a SkScalar
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000275SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
reed@google.com3f0dcf92011-03-18 21:23:45 +0000276 SkScalar scaled = SkIntToScalar(val);
277 if (emSize == 1000) {
278 return scaled;
279 } else {
280 return SkScalarMulDiv(scaled, 1000, emSize);
281 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000282}
283
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000284void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000285 SkWStream* content) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000286 // Specify width and bounding box for the glyph.
halcanarybc4696b2015-05-06 10:56:04 -0700287 SkPDFUtils::AppendScalar(width, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000288 content->writeText(" 0 ");
289 content->writeDecAsText(box.fLeft);
290 content->writeText(" ");
291 content->writeDecAsText(box.fTop);
292 content->writeText(" ");
293 content->writeDecAsText(box.fRight);
294 content->writeText(" ");
295 content->writeDecAsText(box.fBottom);
296 content->writeText(" d1\n");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000297}
298
vandebo@chromium.org75f97e42011-04-11 23:24:18 +0000299SkPDFArray* makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000300 SkPDFArray* bbox = new SkPDFArray;
301 bbox->reserve(4);
reed@google.comc789cf12011-07-20 12:14:33 +0000302 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fLeft, emSize));
303 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fBottom, emSize));
304 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fRight, emSize));
305 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fTop, emSize));
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000306 return bbox;
307}
308
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000309SkPDFArray* appendWidth(const int16_t& width, uint16_t emSize,
310 SkPDFArray* array) {
reed@google.comc789cf12011-07-20 12:14:33 +0000311 array->appendScalar(scaleFromFontUnits(width, emSize));
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000312 return array;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000313}
314
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000315SkPDFArray* appendVerticalAdvance(
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000316 const SkAdvancedTypefaceMetrics::VerticalMetric& advance,
317 uint16_t emSize, SkPDFArray* array) {
318 appendWidth(advance.fVerticalAdvance, emSize, array);
319 appendWidth(advance.fOriginXDisp, emSize, array);
320 appendWidth(advance.fOriginYDisp, emSize, array);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000321 return array;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000322}
323
324template <typename Data>
325SkPDFArray* composeAdvanceData(
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000326 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* advanceInfo,
327 uint16_t emSize,
328 SkPDFArray* (*appendAdvance)(const Data& advance, uint16_t emSize,
329 SkPDFArray* array),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000330 Data* defaultAdvance) {
331 SkPDFArray* result = new SkPDFArray();
332 for (; advanceInfo != NULL; advanceInfo = advanceInfo->fNext.get()) {
333 switch (advanceInfo->fType) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000334 case SkAdvancedTypefaceMetrics::WidthRange::kDefault: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000335 SkASSERT(advanceInfo->fAdvance.count() == 1);
336 *defaultAdvance = advanceInfo->fAdvance[0];
337 break;
338 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000339 case SkAdvancedTypefaceMetrics::WidthRange::kRange: {
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000340 SkAutoTUnref<SkPDFArray> advanceArray(new SkPDFArray());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000341 for (int j = 0; j < advanceInfo->fAdvance.count(); j++)
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000342 appendAdvance(advanceInfo->fAdvance[j], emSize,
343 advanceArray.get());
reed@google.comc789cf12011-07-20 12:14:33 +0000344 result->appendInt(advanceInfo->fStartId);
halcanarybf51cfd2015-05-05 10:24:09 -0700345 result->appendObject(advanceArray.detach());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000346 break;
347 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000348 case SkAdvancedTypefaceMetrics::WidthRange::kRun: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000349 SkASSERT(advanceInfo->fAdvance.count() == 1);
reed@google.comc789cf12011-07-20 12:14:33 +0000350 result->appendInt(advanceInfo->fStartId);
351 result->appendInt(advanceInfo->fEndId);
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000352 appendAdvance(advanceInfo->fAdvance[0], emSize, result);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000353 break;
354 }
355 }
356 }
357 return result;
358}
359
360} // namespace
361
edisonn@google.com26d2e042013-09-18 19:29:08 +0000362static void append_tounicode_header(SkDynamicMemoryWStream* cmap,
363 uint16_t firstGlyphID,
364 uint16_t lastGlyphID) {
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000365 // 12 dict begin: 12 is an Adobe-suggested value. Shall not change.
366 // It's there to prevent old version Adobe Readers from malfunctioning.
367 const char* kHeader =
368 "/CIDInit /ProcSet findresource begin\n"
369 "12 dict begin\n"
370 "begincmap\n";
371 cmap->writeText(kHeader);
372
373 // The /CIDSystemInfo must be consistent to the one in
374 // SkPDFFont::populateCIDFont().
375 // We can not pass over the system info object here because the format is
376 // different. This is not a reference object.
377 const char* kSysInfo =
378 "/CIDSystemInfo\n"
379 "<< /Registry (Adobe)\n"
380 "/Ordering (UCS)\n"
381 "/Supplement 0\n"
382 ">> def\n";
383 cmap->writeText(kSysInfo);
384
385 // The CMapName must be consistent to /CIDSystemInfo above.
386 // /CMapType 2 means ToUnicode.
edisonn@google.com26d2e042013-09-18 19:29:08 +0000387 // Codespace range just tells the PDF processor the valid range.
388 const char* kTypeInfoHeader =
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000389 "/CMapName /Adobe-Identity-UCS def\n"
390 "/CMapType 2 def\n"
edisonn@google.com26d2e042013-09-18 19:29:08 +0000391 "1 begincodespacerange\n";
392 cmap->writeText(kTypeInfoHeader);
skia.committer@gmail.com2262c582013-09-19 07:25:55 +0000393
edisonn@google.com26d2e042013-09-18 19:29:08 +0000394 // e.g. "<0000> <FFFF>\n"
395 SkString range;
396 range.appendf("<%04X> <%04X>\n", firstGlyphID, lastGlyphID);
397 cmap->writeText(range.c_str());
skia.committer@gmail.com2262c582013-09-19 07:25:55 +0000398
edisonn@google.com26d2e042013-09-18 19:29:08 +0000399 const char* kTypeInfoFooter = "endcodespacerange\n";
400 cmap->writeText(kTypeInfoFooter);
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000401}
402
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000403static void append_cmap_footer(SkDynamicMemoryWStream* cmap) {
404 const char* kFooter =
405 "endcmap\n"
406 "CMapName currentdict /CMap defineresource pop\n"
407 "end\n"
408 "end";
409 cmap->writeText(kFooter);
410}
411
vandebo@chromium.org04c643b2011-08-08 22:33:05 +0000412struct BFChar {
413 uint16_t fGlyphId;
414 SkUnichar fUnicode;
415};
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000416
vandebo@chromium.org04c643b2011-08-08 22:33:05 +0000417struct BFRange {
418 uint16_t fStart;
419 uint16_t fEnd;
420 SkUnichar fUnicode;
421};
422
423static void append_bfchar_section(const SkTDArray<BFChar>& bfchar,
424 SkDynamicMemoryWStream* cmap) {
425 // PDF spec defines that every bf* list can have at most 100 entries.
426 for (int i = 0; i < bfchar.count(); i += 100) {
427 int count = bfchar.count() - i;
428 count = SkMin32(count, 100);
429 cmap->writeDecAsText(count);
430 cmap->writeText(" beginbfchar\n");
431 for (int j = 0; j < count; ++j) {
432 cmap->writeText("<");
433 cmap->writeHexAsText(bfchar[i + j].fGlyphId, 4);
434 cmap->writeText("> <");
435 cmap->writeHexAsText(bfchar[i + j].fUnicode, 4);
436 cmap->writeText(">\n");
437 }
438 cmap->writeText("endbfchar\n");
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000439 }
440}
441
vandebo@chromium.org04c643b2011-08-08 22:33:05 +0000442static void append_bfrange_section(const SkTDArray<BFRange>& bfrange,
443 SkDynamicMemoryWStream* cmap) {
444 // PDF spec defines that every bf* list can have at most 100 entries.
445 for (int i = 0; i < bfrange.count(); i += 100) {
446 int count = bfrange.count() - i;
447 count = SkMin32(count, 100);
448 cmap->writeDecAsText(count);
449 cmap->writeText(" beginbfrange\n");
450 for (int j = 0; j < count; ++j) {
451 cmap->writeText("<");
452 cmap->writeHexAsText(bfrange[i + j].fStart, 4);
453 cmap->writeText("> <");
454 cmap->writeHexAsText(bfrange[i + j].fEnd, 4);
455 cmap->writeText("> <");
456 cmap->writeHexAsText(bfrange[i + j].fUnicode, 4);
457 cmap->writeText(">\n");
458 }
459 cmap->writeText("endbfrange\n");
460 }
461}
462
463// Generate <bfchar> and <bfrange> table according to PDF spec 1.4 and Adobe
464// Technote 5014.
465// The function is not static so we can test it in unit tests.
466//
467// Current implementation guarantees bfchar and bfrange entries do not overlap.
468//
469// Current implementation does not attempt aggresive optimizations against
470// following case because the specification is not clear.
471//
472// 4 beginbfchar 1 beginbfchar
473// <0003> <0013> <0020> <0014>
474// <0005> <0015> to endbfchar
475// <0007> <0017> 1 beginbfrange
476// <0020> <0014> <0003> <0007> <0013>
477// endbfchar endbfrange
478//
479// Adobe Technote 5014 said: "Code mappings (unlike codespace ranges) may
commit-bot@chromium.org1236d8e2013-12-11 18:47:11 +0000480// overlap, but succeeding maps supersede preceding maps."
vandebo@chromium.org04c643b2011-08-08 22:33:05 +0000481//
482// In case of searching text in PDF, bfrange will have higher precedence so
483// typing char id 0x0014 in search box will get glyph id 0x0004 first. However,
484// the spec does not mention how will this kind of conflict being resolved.
485//
486// For the worst case (having 65536 continuous unicode and we use every other
487// one of them), the possible savings by aggressive optimization is 416KB
488// pre-compressed and does not provide enough motivation for implementation.
caryclark@google.com1445a0d2012-06-06 12:04:24 +0000489
490// FIXME: this should be in a header so that it is separately testable
491// ( see caller in tests/ToUnicode.cpp )
492void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode,
493 const SkPDFGlyphSet* subset,
edisonn@google.com26d2e042013-09-18 19:29:08 +0000494 SkDynamicMemoryWStream* cmap,
commit-bot@chromium.org1236d8e2013-12-11 18:47:11 +0000495 bool multiByteGlyphs,
edisonn@google.com26d2e042013-09-18 19:29:08 +0000496 uint16_t firstGlyphID,
497 uint16_t lastGlyphID);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000498
vandebo@chromium.org04c643b2011-08-08 22:33:05 +0000499void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode,
500 const SkPDFGlyphSet* subset,
edisonn@google.com26d2e042013-09-18 19:29:08 +0000501 SkDynamicMemoryWStream* cmap,
commit-bot@chromium.org1236d8e2013-12-11 18:47:11 +0000502 bool multiByteGlyphs,
edisonn@google.com26d2e042013-09-18 19:29:08 +0000503 uint16_t firstGlyphID,
504 uint16_t lastGlyphID) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000505 if (glyphToUnicode.isEmpty()) {
506 return;
507 }
commit-bot@chromium.org1236d8e2013-12-11 18:47:11 +0000508 int glyphOffset = 0;
509 if (!multiByteGlyphs) {
510 glyphOffset = firstGlyphID - 1;
511 }
vandebo@chromium.org04c643b2011-08-08 22:33:05 +0000512
513 SkTDArray<BFChar> bfcharEntries;
514 SkTDArray<BFRange> bfrangeEntries;
515
bsalomon@google.comcadbcb82012-01-06 19:22:11 +0000516 BFRange currentRangeEntry = {0, 0, 0};
vandebo@chromium.org9ad35992012-01-03 18:35:39 +0000517 bool rangeEmpty = true;
commit-bot@chromium.org1236d8e2013-12-11 18:47:11 +0000518 const int limit =
519 SkMin32(lastGlyphID + 1, glyphToUnicode.count()) - glyphOffset;
vandebo@chromium.org04c643b2011-08-08 22:33:05 +0000520
commit-bot@chromium.org1236d8e2013-12-11 18:47:11 +0000521 for (int i = firstGlyphID - glyphOffset; i < limit + 1; ++i) {
edisonn@google.com26d2e042013-09-18 19:29:08 +0000522 bool inSubset = i < limit &&
commit-bot@chromium.org1236d8e2013-12-11 18:47:11 +0000523 (subset == NULL || subset->has(i + glyphOffset));
vandebo@chromium.org9ad35992012-01-03 18:35:39 +0000524 if (!rangeEmpty) {
vandebo@chromium.org04c643b2011-08-08 22:33:05 +0000525 // PDF spec requires bfrange not changing the higher byte,
526 // e.g. <1035> <10FF> <2222> is ok, but
527 // <1035> <1100> <2222> is no good
vandebo@chromium.org9ad35992012-01-03 18:35:39 +0000528 bool inRange =
529 i == currentRangeEntry.fEnd + 1 &&
530 i >> 8 == currentRangeEntry.fStart >> 8 &&
edisonn@google.com26d2e042013-09-18 19:29:08 +0000531 i < limit &&
commit-bot@chromium.org1236d8e2013-12-11 18:47:11 +0000532 glyphToUnicode[i + glyphOffset] ==
533 currentRangeEntry.fUnicode + i - currentRangeEntry.fStart;
vandebo@chromium.org9ad35992012-01-03 18:35:39 +0000534 if (!inSubset || !inRange) {
535 if (currentRangeEntry.fEnd > currentRangeEntry.fStart) {
vandebo@chromium.org04c643b2011-08-08 22:33:05 +0000536 bfrangeEntries.push(currentRangeEntry);
537 } else {
538 BFChar* entry = bfcharEntries.append();
539 entry->fGlyphId = currentRangeEntry.fStart;
540 entry->fUnicode = currentRangeEntry.fUnicode;
541 }
vandebo@chromium.org9ad35992012-01-03 18:35:39 +0000542 rangeEmpty = true;
vandebo@chromium.org04c643b2011-08-08 22:33:05 +0000543 }
vandebo@chromium.org9ad35992012-01-03 18:35:39 +0000544 }
545 if (inSubset) {
546 currentRangeEntry.fEnd = i;
547 if (rangeEmpty) {
548 currentRangeEntry.fStart = i;
commit-bot@chromium.org1236d8e2013-12-11 18:47:11 +0000549 currentRangeEntry.fUnicode = glyphToUnicode[i + glyphOffset];
vandebo@chromium.org9ad35992012-01-03 18:35:39 +0000550 rangeEmpty = false;
vandebo@chromium.org04c643b2011-08-08 22:33:05 +0000551 }
552 }
553 }
554
555 // The spec requires all bfchar entries for a font must come before bfrange
556 // entries.
557 append_bfchar_section(bfcharEntries, cmap);
558 append_bfrange_section(bfrangeEntries, cmap);
559}
560
vandebo@chromium.org98594282011-07-25 22:34:12 +0000561static SkPDFStream* generate_tounicode_cmap(
vandebo@chromium.org04c643b2011-08-08 22:33:05 +0000562 const SkTDArray<SkUnichar>& glyphToUnicode,
edisonn@google.com26d2e042013-09-18 19:29:08 +0000563 const SkPDFGlyphSet* subset,
commit-bot@chromium.org1236d8e2013-12-11 18:47:11 +0000564 bool multiByteGlyphs,
edisonn@google.com26d2e042013-09-18 19:29:08 +0000565 uint16_t firstGlyphID,
566 uint16_t lastGlyphID) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000567 SkDynamicMemoryWStream cmap;
commit-bot@chromium.org1236d8e2013-12-11 18:47:11 +0000568 if (multiByteGlyphs) {
569 append_tounicode_header(&cmap, firstGlyphID, lastGlyphID);
570 } else {
571 append_tounicode_header(&cmap, 1, lastGlyphID - firstGlyphID + 1);
572 }
573 append_cmap_sections(glyphToUnicode, subset, &cmap, multiByteGlyphs,
edisonn@google.com26d2e042013-09-18 19:29:08 +0000574 firstGlyphID, lastGlyphID);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000575 append_cmap_footer(&cmap);
halcanary67ec1f82014-06-27 11:36:20 -0700576 SkAutoTUnref<SkData> cmapData(cmap.copyToData());
577 return new SkPDFStream(cmapData.get());
vandebo@chromium.org98594282011-07-25 22:34:12 +0000578}
579
caryclark@google.com1445a0d2012-06-06 12:04:24 +0000580#if defined (SK_SFNTLY_SUBSETTER)
reed6b7f34e2015-06-17 09:58:24 -0700581static void sk_delete_array(const void* ptr, void*) {
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000582 // Use C-style cast to cast away const and cast type simultaneously.
583 delete[] (unsigned char*)ptr;
584}
caryclark@google.com1445a0d2012-06-06 12:04:24 +0000585#endif
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000586
reed@google.comaec40662014-04-18 19:29:07 +0000587static size_t get_subset_font_stream(const char* fontName,
588 const SkTypeface* typeface,
589 const SkTDArray<uint32_t>& subset,
590 SkPDFStream** fontStream) {
reed@google.comfed86bd2013-03-14 15:04:57 +0000591 int ttcIndex;
scroggoa1193e42015-01-21 12:09:53 -0800592 SkAutoTDelete<SkStream> fontData(typeface->openStream(&ttcIndex));
halcanary67ec1f82014-06-27 11:36:20 -0700593 SkASSERT(fontData.get());
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000594
reed@google.comaec40662014-04-18 19:29:07 +0000595 size_t fontSize = fontData->getLength();
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000596
597#if defined (SK_SFNTLY_SUBSETTER)
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000598 // Read font into buffer.
599 SkPDFStream* subsetFontStream = NULL;
600 SkTDArray<unsigned char> originalFont;
reed@google.comaec40662014-04-18 19:29:07 +0000601 originalFont.setCount(SkToInt(fontSize));
602 if (fontData->read(originalFont.begin(), fontSize) == fontSize) {
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000603 unsigned char* subsetFont = NULL;
vandebo@chromium.org17e66e22011-07-27 20:59:55 +0000604 // sfntly requires unsigned int* to be passed in, as far as we know,
605 // unsigned int is equivalent to uint32_t on all platforms.
606 SK_COMPILE_ASSERT(sizeof(unsigned int) == sizeof(uint32_t),
607 unsigned_int_not_32_bits);
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000608 int subsetFontSize = SfntlyWrapper::SubsetFont(fontName,
609 originalFont.begin(),
610 fontSize,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000611 subset.begin(),
612 subset.count(),
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000613 &subsetFont);
614 if (subsetFontSize > 0 && subsetFont != NULL) {
vandebo@chromium.org93225ff2011-07-27 18:38:11 +0000615 SkAutoDataUnref data(SkData::NewWithProc(subsetFont,
616 subsetFontSize,
617 sk_delete_array,
618 NULL));
619 subsetFontStream = new SkPDFStream(data.get());
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000620 fontSize = subsetFontSize;
621 }
622 }
623 if (subsetFontStream) {
624 *fontStream = subsetFontStream;
625 return fontSize;
626 }
vandebo@chromium.org938ea622013-09-05 19:44:44 +0000627 fontData->rewind();
sugoi@google.come2e81132013-03-05 18:35:55 +0000628#else
629 sk_ignore_unused_variable(fontName);
630 sk_ignore_unused_variable(subset);
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000631#endif
632
633 // Fail over: just embed the whole font.
634 *fontStream = new SkPDFStream(fontData.get());
635 return fontSize;
636}
637
vandebo@chromium.org98594282011-07-25 22:34:12 +0000638///////////////////////////////////////////////////////////////////////////////
639// class SkPDFGlyphSet
640///////////////////////////////////////////////////////////////////////////////
641
642SkPDFGlyphSet::SkPDFGlyphSet() : fBitSet(SK_MaxU16 + 1) {
643}
644
645void SkPDFGlyphSet::set(const uint16_t* glyphIDs, int numGlyphs) {
646 for (int i = 0; i < numGlyphs; ++i) {
647 fBitSet.setBit(glyphIDs[i], true);
648 }
649}
650
651bool SkPDFGlyphSet::has(uint16_t glyphID) const {
652 return fBitSet.isBitSet(glyphID);
653}
654
655void SkPDFGlyphSet::merge(const SkPDFGlyphSet& usage) {
656 fBitSet.orBits(usage.fBitSet);
657}
658
vandebo@chromium.org17e66e22011-07-27 20:59:55 +0000659void SkPDFGlyphSet::exportTo(SkTDArray<unsigned int>* glyphIDs) const {
660 fBitSet.exportTo(glyphIDs);
661}
662
vandebo@chromium.org98594282011-07-25 22:34:12 +0000663///////////////////////////////////////////////////////////////////////////////
664// class SkPDFGlyphSetMap
665///////////////////////////////////////////////////////////////////////////////
666SkPDFGlyphSetMap::FontGlyphSetPair::FontGlyphSetPair(SkPDFFont* font,
667 SkPDFGlyphSet* glyphSet)
668 : fFont(font),
669 fGlyphSet(glyphSet) {
670}
671
672SkPDFGlyphSetMap::F2BIter::F2BIter(const SkPDFGlyphSetMap& map) {
673 reset(map);
674}
675
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000676const SkPDFGlyphSetMap::FontGlyphSetPair* SkPDFGlyphSetMap::F2BIter::next() const {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000677 if (fIndex >= fMap->count()) {
678 return NULL;
679 }
680 return &((*fMap)[fIndex++]);
681}
682
683void SkPDFGlyphSetMap::F2BIter::reset(const SkPDFGlyphSetMap& map) {
684 fMap = &(map.fMap);
685 fIndex = 0;
686}
687
688SkPDFGlyphSetMap::SkPDFGlyphSetMap() {
689}
690
691SkPDFGlyphSetMap::~SkPDFGlyphSetMap() {
692 reset();
693}
694
695void SkPDFGlyphSetMap::merge(const SkPDFGlyphSetMap& usage) {
696 for (int i = 0; i < usage.fMap.count(); ++i) {
697 SkPDFGlyphSet* myUsage = getGlyphSetForFont(usage.fMap[i].fFont);
698 myUsage->merge(*(usage.fMap[i].fGlyphSet));
699 }
700}
701
702void SkPDFGlyphSetMap::reset() {
703 for (int i = 0; i < fMap.count(); ++i) {
704 delete fMap[i].fGlyphSet; // Should not be NULL.
705 }
706 fMap.reset();
707}
708
709void SkPDFGlyphSetMap::noteGlyphUsage(SkPDFFont* font, const uint16_t* glyphIDs,
710 int numGlyphs) {
711 SkPDFGlyphSet* subset = getGlyphSetForFont(font);
712 if (subset) {
713 subset->set(glyphIDs, numGlyphs);
714 }
715}
716
717SkPDFGlyphSet* SkPDFGlyphSetMap::getGlyphSetForFont(SkPDFFont* font) {
718 int index = fMap.count();
719 for (int i = 0; i < index; ++i) {
720 if (fMap[i].fFont == font) {
721 return fMap[i].fGlyphSet;
722 }
723 }
724 fMap.append();
725 index = fMap.count() - 1;
726 fMap[index].fFont = font;
727 fMap[index].fGlyphSet = new SkPDFGlyphSet();
728 return fMap[index].fGlyphSet;
729}
730
731///////////////////////////////////////////////////////////////////////////////
732// class SkPDFFont
733///////////////////////////////////////////////////////////////////////////////
734
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000735/* Font subset design: It would be nice to be able to subset fonts
736 * (particularly type 3 fonts), but it's a lot of work and not a priority.
737 *
738 * Resources are canonicalized and uniqueified by pointer so there has to be
739 * some additional state indicating which subset of the font is used. It
740 * must be maintained at the page granularity and then combined at the document
741 * granularity. a) change SkPDFFont to fill in its state on demand, kind of
742 * like SkPDFGraphicState. b) maintain a per font glyph usage class in each
743 * page/pdf device. c) in the document, retrieve the per font glyph usage
744 * from each page and combine it and ask for a resource with that subset.
745 */
746
halcanary2e3f9d82015-02-27 12:41:03 -0800747SkPDFFont::~SkPDFFont() {}
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000748
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000749SkTypeface* SkPDFFont::typeface() {
750 return fTypeface.get();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000751}
752
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000753SkAdvancedTypefaceMetrics::FontType SkPDFFont::getType() {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000754 return fFontType;
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000755}
756
vandebo0f9bad02014-06-19 11:05:39 -0700757bool SkPDFFont::canEmbed() const {
758 if (!fFontInfo.get()) {
759 SkASSERT(fFontType == SkAdvancedTypefaceMetrics::kOther_Font);
760 return true;
761 }
762 return (fFontInfo->fFlags &
763 SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag) == 0;
764}
765
766bool SkPDFFont::canSubset() const {
767 if (!fFontInfo.get()) {
768 SkASSERT(fFontType == SkAdvancedTypefaceMetrics::kOther_Font);
769 return true;
770 }
771 return (fFontInfo->fFlags &
772 SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag) == 0;
773}
774
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000775bool SkPDFFont::hasGlyph(uint16_t id) {
776 return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0;
777}
778
reed@google.comaec40662014-04-18 19:29:07 +0000779int SkPDFFont::glyphsToPDFFontEncoding(uint16_t* glyphIDs, int numGlyphs) {
vandebo@chromium.org01294102011-02-28 19:52:18 +0000780 // A font with multibyte glyphs will support all glyph IDs in a single font.
vandebo@chromium.org98594282011-07-25 22:34:12 +0000781 if (this->multiByteGlyphs()) {
vandebo@chromium.org01294102011-02-28 19:52:18 +0000782 return numGlyphs;
783 }
784
reed@google.comaec40662014-04-18 19:29:07 +0000785 for (int i = 0; i < numGlyphs; i++) {
vandebo@chromium.org01294102011-02-28 19:52:18 +0000786 if (glyphIDs[i] == 0) {
787 continue;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000788 }
vandebo@chromium.org01294102011-02-28 19:52:18 +0000789 if (glyphIDs[i] < fFirstGlyphID || glyphIDs[i] > fLastGlyphID) {
790 return i;
791 }
792 glyphIDs[i] -= (fFirstGlyphID - 1);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000793 }
794
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000795 return numGlyphs;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000796}
797
798// static
halcanary792c80f2015-02-20 07:21:05 -0800799SkPDFFont* SkPDFFont::GetFontResource(SkPDFCanon* canon,
800 SkTypeface* typeface,
801 uint16_t glyphID) {
802 SkASSERT(canon);
reed@google.comfed86bd2013-03-14 15:04:57 +0000803 SkAutoResolveDefaultTypeface autoResolve(typeface);
804 typeface = autoResolve.get();
reed@google.comfed86bd2013-03-14 15:04:57 +0000805 const uint32_t fontID = typeface->uniqueID();
halcanaryfb62b3d2015-01-21 09:59:14 -0800806
halcanaryfb62b3d2015-01-21 09:59:14 -0800807 SkPDFFont* relatedFont;
halcanary792c80f2015-02-20 07:21:05 -0800808 if (SkPDFFont* pdfFont = canon->findFont(fontID, glyphID, &relatedFont)) {
halcanaryfb62b3d2015-01-21 09:59:14 -0800809 return SkRef(pdfFont);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000810 }
811
halcanaryfb747e22014-07-11 19:45:23 -0700812 SkAutoTUnref<const SkAdvancedTypefaceMetrics> fontMetrics;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000813 SkPDFDict* relatedFontDescriptor = NULL;
halcanaryfb62b3d2015-01-21 09:59:14 -0800814 if (relatedFont) {
815 fontMetrics.reset(SkSafeRef(relatedFont->fontInfo()));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000816 relatedFontDescriptor = relatedFont->getFontDescriptor();
edisonn@google.com022e8572012-10-23 21:32:39 +0000817
818 // This only is to catch callers who pass invalid glyph ids.
819 // If glyph id is invalid, then we will create duplicate entries
vandebo0f9bad02014-06-19 11:05:39 -0700820 // for TrueType fonts.
skia.committer@gmail.com1e34ff72012-10-24 02:01:24 +0000821 SkAdvancedTypefaceMetrics::FontType fontType =
edisonn@google.com022e8572012-10-23 21:32:39 +0000822 fontMetrics.get() ? fontMetrics.get()->fType :
823 SkAdvancedTypefaceMetrics::kOther_Font;
824
825 if (fontType == SkAdvancedTypefaceMetrics::kType1CID_Font ||
826 fontType == SkAdvancedTypefaceMetrics::kTrueType_Font) {
halcanaryfb62b3d2015-01-21 09:59:14 -0800827 return SkRef(relatedFont);
skia.committer@gmail.com1e34ff72012-10-24 02:01:24 +0000828 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000829 } else {
reed39a9a502015-05-12 09:50:04 -0700830 SkTypeface::PerGlyphInfo info;
831 info = SkTypeface::kGlyphNames_PerGlyphInfo;
832 info = SkTBitOr<SkTypeface::PerGlyphInfo>(
833 info, SkTypeface::kToUnicode_PerGlyphInfo);
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000834#if !defined (SK_SFNTLY_SUBSETTER)
reed39a9a502015-05-12 09:50:04 -0700835 info = SkTBitOr<SkTypeface::PerGlyphInfo>(
836 info, SkTypeface::kHAdvance_PerGlyphInfo);
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000837#endif
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000838 fontMetrics.reset(
reed@google.comfed86bd2013-03-14 15:04:57 +0000839 typeface->getAdvancedTypefaceMetrics(info, NULL, 0));
vandebo@chromium.org610f7162012-03-14 18:34:15 +0000840#if defined (SK_SFNTLY_SUBSETTER)
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000841 if (fontMetrics.get() &&
vandebo@chromium.orgb3b46552011-10-17 23:22:49 +0000842 fontMetrics->fType != SkAdvancedTypefaceMetrics::kTrueType_Font) {
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000843 // Font does not support subsetting, get new info with advance.
reedd9950092015-05-12 10:49:15 -0700844 info = SkTBitOr<SkTypeface::PerGlyphInfo>(
845 info, SkTypeface::kHAdvance_PerGlyphInfo);
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000846 fontMetrics.reset(
reed@google.comfed86bd2013-03-14 15:04:57 +0000847 typeface->getAdvancedTypefaceMetrics(info, NULL, 0));
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000848 }
849#endif
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000850 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000851
halcanary792c80f2015-02-20 07:21:05 -0800852 SkPDFFont* font = SkPDFFont::Create(canon, fontMetrics.get(), typeface,
853 glyphID, relatedFontDescriptor);
854 canon->addFont(font, fontID, font->fFirstGlyphID);
855 return font;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000856}
857
sugoi@google.come2e81132013-03-05 18:35:55 +0000858SkPDFFont* SkPDFFont::getFontSubset(const SkPDFGlyphSet*) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000859 return NULL; // Default: no support.
860}
861
halcanary2e3f9d82015-02-27 12:41:03 -0800862SkPDFFont::SkPDFFont(const SkAdvancedTypefaceMetrics* info,
halcanaryfb747e22014-07-11 19:45:23 -0700863 SkTypeface* typeface,
sugoi@google.come2e81132013-03-05 18:35:55 +0000864 SkPDFDict* relatedFontDescriptor)
halcanary792c80f2015-02-20 07:21:05 -0800865 : SkPDFDict("Font")
halcanary792c80f2015-02-20 07:21:05 -0800866 , fTypeface(ref_or_default(typeface))
867 , fFirstGlyphID(1)
868 , fLastGlyphID(info ? info->fLastGlyphID : 0)
869 , fFontInfo(SkSafeRef(info))
870 , fDescriptor(SkSafeRef(relatedFontDescriptor)) {
vandebo0f9bad02014-06-19 11:05:39 -0700871 if (info == NULL ||
872 info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000873 fFontType = SkAdvancedTypefaceMetrics::kOther_Font;
874 } else {
875 fFontType = info->fType;
876 }
877}
878
879// static
halcanary792c80f2015-02-20 07:21:05 -0800880SkPDFFont* SkPDFFont::Create(SkPDFCanon* canon,
881 const SkAdvancedTypefaceMetrics* info,
882 SkTypeface* typeface,
883 uint16_t glyphID,
vandebo@chromium.org98594282011-07-25 22:34:12 +0000884 SkPDFDict* relatedFontDescriptor) {
885 SkAdvancedTypefaceMetrics::FontType type =
vandebo0f9bad02014-06-19 11:05:39 -0700886 info ? info->fType : SkAdvancedTypefaceMetrics::kOther_Font;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000887
bungeman41868fe2015-05-20 09:21:04 -0700888 if (info && (info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) {
halcanary2e3f9d82015-02-27 12:41:03 -0800889 return new SkPDFType3Font(info, typeface, glyphID);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000890 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000891 if (type == SkAdvancedTypefaceMetrics::kType1CID_Font ||
892 type == SkAdvancedTypefaceMetrics::kTrueType_Font) {
893 SkASSERT(relatedFontDescriptor == NULL);
halcanary2e3f9d82015-02-27 12:41:03 -0800894 return new SkPDFType0Font(info, typeface);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000895 }
896 if (type == SkAdvancedTypefaceMetrics::kType1_Font) {
halcanary2e3f9d82015-02-27 12:41:03 -0800897 return new SkPDFType1Font(info, typeface, glyphID,
vandebo@chromium.org98594282011-07-25 22:34:12 +0000898 relatedFontDescriptor);
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000899 }
vandebo@chromium.org31dcee72011-07-23 21:13:30 +0000900
vandebo@chromium.org98594282011-07-25 22:34:12 +0000901 SkASSERT(type == SkAdvancedTypefaceMetrics::kCFF_Font ||
vandebo0f9bad02014-06-19 11:05:39 -0700902 type == SkAdvancedTypefaceMetrics::kOther_Font);
vandebo@chromium.org31dcee72011-07-23 21:13:30 +0000903
halcanary2e3f9d82015-02-27 12:41:03 -0800904 return new SkPDFType3Font(info, typeface, glyphID);
vandebo@chromium.org31dcee72011-07-23 21:13:30 +0000905}
906
halcanaryfb747e22014-07-11 19:45:23 -0700907const SkAdvancedTypefaceMetrics* SkPDFFont::fontInfo() {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000908 return fFontInfo.get();
vandebo@chromium.org31dcee72011-07-23 21:13:30 +0000909}
910
halcanaryfb747e22014-07-11 19:45:23 -0700911void SkPDFFont::setFontInfo(const SkAdvancedTypefaceMetrics* info) {
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000912 if (info == NULL || info == fFontInfo.get()) {
913 return;
914 }
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000915 fFontInfo.reset(info);
916 SkSafeRef(info);
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000917}
918
vandebo@chromium.org98594282011-07-25 22:34:12 +0000919uint16_t SkPDFFont::firstGlyphID() const {
920 return fFirstGlyphID;
921}
922
923uint16_t SkPDFFont::lastGlyphID() const {
924 return fLastGlyphID;
925}
926
927void SkPDFFont::setLastGlyphID(uint16_t glyphID) {
928 fLastGlyphID = glyphID;
929}
930
vandebo@chromium.org98594282011-07-25 22:34:12 +0000931SkPDFDict* SkPDFFont::getFontDescriptor() {
932 return fDescriptor.get();
933}
934
935void SkPDFFont::setFontDescriptor(SkPDFDict* descriptor) {
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000936 fDescriptor.reset(descriptor);
937 SkSafeRef(descriptor);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000938}
939
940bool SkPDFFont::addCommonFontDescriptorEntries(int16_t defaultWidth) {
941 if (fDescriptor.get() == NULL) {
942 return false;
vandebo@chromium.org31dcee72011-07-23 21:13:30 +0000943 }
944
vandebo@chromium.org98594282011-07-25 22:34:12 +0000945 const uint16_t emSize = fFontInfo->fEmSize;
946
947 fDescriptor->insertName("FontName", fFontInfo->fFontName);
vandebo@chromium.orgdcf9c192013-03-13 20:01:51 +0000948 fDescriptor->insertInt("Flags", fFontInfo->fStyle | kPdfSymbolic);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000949 fDescriptor->insertScalar("Ascent",
950 scaleFromFontUnits(fFontInfo->fAscent, emSize));
951 fDescriptor->insertScalar("Descent",
952 scaleFromFontUnits(fFontInfo->fDescent, emSize));
953 fDescriptor->insertScalar("StemV",
954 scaleFromFontUnits(fFontInfo->fStemV, emSize));
halcanaryfb747e22014-07-11 19:45:23 -0700955
vandebo@chromium.org98594282011-07-25 22:34:12 +0000956 fDescriptor->insertScalar("CapHeight",
957 scaleFromFontUnits(fFontInfo->fCapHeight, emSize));
958 fDescriptor->insertInt("ItalicAngle", fFontInfo->fItalicAngle);
halcanarybf51cfd2015-05-05 10:24:09 -0700959 fDescriptor->insertObject(
960 "FontBBox", makeFontBBox(fFontInfo->fBBox, fFontInfo->fEmSize));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000961
962 if (defaultWidth > 0) {
963 fDescriptor->insertScalar("MissingWidth",
964 scaleFromFontUnits(defaultWidth, emSize));
965 }
966 return true;
967}
968
bungeman22edc832014-10-03 07:55:58 -0700969void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(uint16_t glyphID) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000970 // Single byte glyph encoding supports a max of 255 glyphs.
971 fFirstGlyphID = glyphID - (glyphID - 1) % 255;
972 if (fLastGlyphID > fFirstGlyphID + 255 - 1) {
973 fLastGlyphID = fFirstGlyphID + 255 - 1;
974 }
975}
976
vandebo@chromium.org98594282011-07-25 22:34:12 +0000977void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) {
978 if (fFontInfo == NULL || fFontInfo->fGlyphToUnicode.begin() == NULL) {
979 return;
980 }
halcanarybf51cfd2015-05-05 10:24:09 -0700981 this->insertObjRef("ToUnicode",
982 generate_tounicode_cmap(fFontInfo->fGlyphToUnicode,
983 subset,
984 multiByteGlyphs(),
985 firstGlyphID(),
986 lastGlyphID()));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000987}
988
vandebo@chromium.org98594282011-07-25 22:34:12 +0000989///////////////////////////////////////////////////////////////////////////////
990// class SkPDFType0Font
991///////////////////////////////////////////////////////////////////////////////
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000992
halcanary2e3f9d82015-02-27 12:41:03 -0800993SkPDFType0Font::SkPDFType0Font(const SkAdvancedTypefaceMetrics* info,
vandebo@chromium.org98594282011-07-25 22:34:12 +0000994 SkTypeface* typeface)
halcanary2e3f9d82015-02-27 12:41:03 -0800995 : SkPDFFont(info, typeface, NULL) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000996 SkDEBUGCODE(fPopulated = false);
vandebo0f9bad02014-06-19 11:05:39 -0700997 if (!canSubset()) {
998 populate(NULL);
999 }
vandebo@chromium.org98594282011-07-25 22:34:12 +00001000}
1001
1002SkPDFType0Font::~SkPDFType0Font() {}
1003
1004SkPDFFont* SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) {
vandebo0f9bad02014-06-19 11:05:39 -07001005 if (!canSubset()) {
1006 return NULL;
1007 }
halcanary792c80f2015-02-20 07:21:05 -08001008 SkPDFType0Font* newSubset =
halcanary2e3f9d82015-02-27 12:41:03 -08001009 new SkPDFType0Font(fontInfo(), typeface());
vandebo@chromium.org98594282011-07-25 22:34:12 +00001010 newSubset->populate(subset);
1011 return newSubset;
1012}
1013
1014#ifdef SK_DEBUG
halcanary37c46ca2015-03-31 12:30:20 -07001015void SkPDFType0Font::emitObject(SkWStream* stream,
1016 const SkPDFObjNumMap& objNumMap,
1017 const SkPDFSubstituteMap& substitutes) {
vandebo@chromium.org98594282011-07-25 22:34:12 +00001018 SkASSERT(fPopulated);
halcanary37c46ca2015-03-31 12:30:20 -07001019 return INHERITED::emitObject(stream, objNumMap, substitutes);
vandebo@chromium.org98594282011-07-25 22:34:12 +00001020}
1021#endif
1022
1023bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) {
1024 insertName("Subtype", "Type0");
1025 insertName("BaseFont", fontInfo()->fFontName);
1026 insertName("Encoding", "Identity-H");
1027
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001028 SkAutoTUnref<SkPDFCIDFont> newCIDFont(
halcanary2e3f9d82015-02-27 12:41:03 -08001029 new SkPDFCIDFont(fontInfo(), typeface(), subset));
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001030 SkAutoTUnref<SkPDFArray> descendantFonts(new SkPDFArray());
halcanarybf51cfd2015-05-05 10:24:09 -07001031 descendantFonts->appendObjRef(newCIDFont.detach());
1032 this->insertObject("DescendantFonts", descendantFonts.detach());
vandebo@chromium.org98594282011-07-25 22:34:12 +00001033
1034 populateToUnicodeTable(subset);
1035
1036 SkDEBUGCODE(fPopulated = true);
1037 return true;
1038}
1039
1040///////////////////////////////////////////////////////////////////////////////
1041// class SkPDFCIDFont
1042///////////////////////////////////////////////////////////////////////////////
1043
halcanary2e3f9d82015-02-27 12:41:03 -08001044SkPDFCIDFont::SkPDFCIDFont(const SkAdvancedTypefaceMetrics* info,
halcanary792c80f2015-02-20 07:21:05 -08001045 SkTypeface* typeface,
1046 const SkPDFGlyphSet* subset)
halcanary2e3f9d82015-02-27 12:41:03 -08001047 : SkPDFFont(info, typeface, NULL) {
vandebo@chromium.org98594282011-07-25 22:34:12 +00001048 populate(subset);
1049}
1050
1051SkPDFCIDFont::~SkPDFCIDFont() {}
1052
1053bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +00001054 const SkTDArray<uint32_t>* subset) {
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001055 SkAutoTUnref<SkPDFDict> descriptor(new SkPDFDict("FontDescriptor"));
vandebo@chromium.org98594282011-07-25 22:34:12 +00001056 setFontDescriptor(descriptor.get());
vandebo0f9bad02014-06-19 11:05:39 -07001057 if (!addCommonFontDescriptorEntries(defaultWidth)) {
halcanarybf51cfd2015-05-05 10:24:09 -07001058 this->insertObjRef("FontDescriptor", descriptor.detach());
vandebo0f9bad02014-06-19 11:05:39 -07001059 return false;
1060 }
1061 if (!canEmbed()) {
halcanarybf51cfd2015-05-05 10:24:09 -07001062 this->insertObjRef("FontDescriptor", descriptor.detach());
vandebo0f9bad02014-06-19 11:05:39 -07001063 return true;
1064 }
vandebo@chromium.org98594282011-07-25 22:34:12 +00001065
1066 switch (getType()) {
1067 case SkAdvancedTypefaceMetrics::kTrueType_Font: {
vandebo0f9bad02014-06-19 11:05:39 -07001068 SkAutoTUnref<SkPDFStream> fontStream;
1069 size_t fontSize = 0;
1070 if (canSubset()) {
1071 SkPDFStream* rawStream = NULL;
1072 fontSize = get_subset_font_stream(fontInfo()->fFontName.c_str(),
1073 typeface(),
1074 *subset,
1075 &rawStream);
1076 fontStream.reset(rawStream);
1077 } else {
1078 int ttcIndex;
scroggoa1193e42015-01-21 12:09:53 -08001079 SkAutoTDelete<SkStream> fontData(
vandebo0f9bad02014-06-19 11:05:39 -07001080 typeface()->openStream(&ttcIndex));
1081 fontStream.reset(new SkPDFStream(fontData.get()));
1082 fontSize = fontData->getLength();
1083 }
vandebo@chromium.org1f165892011-07-26 02:11:41 +00001084 SkASSERT(fontSize);
vandebo0f9bad02014-06-19 11:05:39 -07001085 SkASSERT(fontStream.get());
vandebo@chromium.org98594282011-07-25 22:34:12 +00001086
vandebo@chromium.org1f165892011-07-26 02:11:41 +00001087 fontStream->insertInt("Length1", fontSize);
halcanarybf51cfd2015-05-05 10:24:09 -07001088 descriptor->insertObjRef("FontFile2", fontStream.detach());
vandebo@chromium.org98594282011-07-25 22:34:12 +00001089 break;
1090 }
1091 case SkAdvancedTypefaceMetrics::kCFF_Font:
1092 case SkAdvancedTypefaceMetrics::kType1CID_Font: {
reed@google.comfed86bd2013-03-14 15:04:57 +00001093 int ttcIndex;
scroggoa1193e42015-01-21 12:09:53 -08001094 SkAutoTDelete<SkStream> fontData(typeface()->openStream(&ttcIndex));
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001095 SkAutoTUnref<SkPDFStream> fontStream(
1096 new SkPDFStream(fontData.get()));
vandebo@chromium.org98594282011-07-25 22:34:12 +00001097
1098 if (getType() == SkAdvancedTypefaceMetrics::kCFF_Font) {
1099 fontStream->insertName("Subtype", "Type1C");
1100 } else {
1101 fontStream->insertName("Subtype", "CIDFontType0c");
1102 }
halcanarybf51cfd2015-05-05 10:24:09 -07001103 descriptor->insertObjRef("FontFile3", fontStream.detach());
vandebo@chromium.org98594282011-07-25 22:34:12 +00001104 break;
1105 }
1106 default:
1107 SkASSERT(false);
1108 }
halcanarybf51cfd2015-05-05 10:24:09 -07001109 this->insertObjRef("FontDescriptor", descriptor.detach());
vandebo0f9bad02014-06-19 11:05:39 -07001110 return true;
vandebo@chromium.org98594282011-07-25 22:34:12 +00001111}
1112
1113bool SkPDFCIDFont::populate(const SkPDFGlyphSet* subset) {
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +00001114 // Generate new font metrics with advance info for true type fonts.
1115 if (fontInfo()->fType == SkAdvancedTypefaceMetrics::kTrueType_Font) {
1116 // Generate glyph id array.
1117 SkTDArray<uint32_t> glyphIDs;
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +00001118 if (subset) {
commit-bot@chromium.org4da3bfc2013-12-11 23:54:31 +00001119 // Always include glyph 0.
1120 if (!subset->has(0)) {
1121 glyphIDs.push(0);
1122 }
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +00001123 subset->exportTo(&glyphIDs);
1124 }
1125
reed39a9a502015-05-12 09:50:04 -07001126 SkTypeface::PerGlyphInfo info;
1127 info = SkTypeface::kGlyphNames_PerGlyphInfo;
1128 info = SkTBitOr<SkTypeface::PerGlyphInfo>(
1129 info, SkTypeface::kHAdvance_PerGlyphInfo);
commit-bot@chromium.org4da3bfc2013-12-11 23:54:31 +00001130 uint32_t* glyphs = (glyphIDs.count() == 0) ? NULL : glyphIDs.begin();
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +00001131 uint32_t glyphsCount = glyphs ? glyphIDs.count() : 0;
halcanaryfb747e22014-07-11 19:45:23 -07001132 SkAutoTUnref<const SkAdvancedTypefaceMetrics> fontMetrics(
reed@google.comfed86bd2013-03-14 15:04:57 +00001133 typeface()->getAdvancedTypefaceMetrics(info, glyphs, glyphsCount));
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +00001134 setFontInfo(fontMetrics.get());
1135 addFontDescriptor(0, &glyphIDs);
1136 } else {
1137 // Other CID fonts
1138 addFontDescriptor(0, NULL);
1139 }
1140
vandebo@chromium.org98594282011-07-25 22:34:12 +00001141 insertName("BaseFont", fontInfo()->fFontName);
1142
1143 if (getType() == SkAdvancedTypefaceMetrics::kType1CID_Font) {
reed@google.comc789cf12011-07-20 12:14:33 +00001144 insertName("Subtype", "CIDFontType0");
vandebo@chromium.org98594282011-07-25 22:34:12 +00001145 } else if (getType() == SkAdvancedTypefaceMetrics::kTrueType_Font) {
reed@google.comc789cf12011-07-20 12:14:33 +00001146 insertName("Subtype", "CIDFontType2");
1147 insertName("CIDToGIDMap", "Identity");
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001148 } else {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001149 SkASSERT(false);
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001150 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001151
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001152 SkAutoTUnref<SkPDFDict> sysInfo(new SkPDFDict);
halcanarybf51cfd2015-05-05 10:24:09 -07001153 sysInfo->insertString("Registry", "Adobe");
1154 sysInfo->insertString("Ordering", "Identity");
reed@google.comc789cf12011-07-20 12:14:33 +00001155 sysInfo->insertInt("Supplement", 0);
halcanarybf51cfd2015-05-05 10:24:09 -07001156 this->insertObject("CIDSystemInfo", sysInfo.detach());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001157
vandebo@chromium.org98594282011-07-25 22:34:12 +00001158 if (fontInfo()->fGlyphWidths.get()) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001159 int16_t defaultWidth = 0;
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001160 SkAutoTUnref<SkPDFArray> widths(
vandebo@chromium.org98594282011-07-25 22:34:12 +00001161 composeAdvanceData(fontInfo()->fGlyphWidths.get(),
1162 fontInfo()->fEmSize, &appendWidth,
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001163 &defaultWidth));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001164 if (widths->size())
halcanarybf51cfd2015-05-05 10:24:09 -07001165 this->insertObject("W", widths.detach());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001166 if (defaultWidth != 0) {
halcanarybf51cfd2015-05-05 10:24:09 -07001167 this->insertScalar(
1168 "DW",
1169 scaleFromFontUnits(defaultWidth, fontInfo()->fEmSize));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001170 }
1171 }
vandebo@chromium.org98594282011-07-25 22:34:12 +00001172 if (fontInfo()->fVerticalMetrics.get()) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001173 struct SkAdvancedTypefaceMetrics::VerticalMetric defaultAdvance;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001174 defaultAdvance.fVerticalAdvance = 0;
1175 defaultAdvance.fOriginXDisp = 0;
1176 defaultAdvance.fOriginYDisp = 0;
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001177 SkAutoTUnref<SkPDFArray> advances(
vandebo@chromium.org98594282011-07-25 22:34:12 +00001178 composeAdvanceData(fontInfo()->fVerticalMetrics.get(),
1179 fontInfo()->fEmSize, &appendVerticalAdvance,
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001180 &defaultAdvance));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001181 if (advances->size())
halcanarybf51cfd2015-05-05 10:24:09 -07001182 this->insertObject("W2", advances.detach());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001183 if (defaultAdvance.fVerticalAdvance ||
1184 defaultAdvance.fOriginXDisp ||
1185 defaultAdvance.fOriginYDisp) {
halcanarybf51cfd2015-05-05 10:24:09 -07001186 this->insertObject("DW2",
1187 appendVerticalAdvance(defaultAdvance,
1188 fontInfo()->fEmSize,
1189 new SkPDFArray));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001190 }
1191 }
vandebo@chromium.org98594282011-07-25 22:34:12 +00001192
1193 return true;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001194}
1195
vandebo@chromium.org98594282011-07-25 22:34:12 +00001196///////////////////////////////////////////////////////////////////////////////
1197// class SkPDFType1Font
1198///////////////////////////////////////////////////////////////////////////////
1199
halcanary2e3f9d82015-02-27 12:41:03 -08001200SkPDFType1Font::SkPDFType1Font(const SkAdvancedTypefaceMetrics* info,
vandebo@chromium.org98594282011-07-25 22:34:12 +00001201 SkTypeface* typeface,
1202 uint16_t glyphID,
1203 SkPDFDict* relatedFontDescriptor)
halcanary2e3f9d82015-02-27 12:41:03 -08001204 : SkPDFFont(info, typeface, relatedFontDescriptor) {
vandebo@chromium.org98594282011-07-25 22:34:12 +00001205 populate(glyphID);
1206}
1207
1208SkPDFType1Font::~SkPDFType1Font() {}
1209
1210bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
halcanarybf51cfd2015-05-05 10:24:09 -07001211 if (SkPDFDict* descriptor = getFontDescriptor()) {
1212 this->insertObjRef("FontDescriptor", SkRef(descriptor));
vandebo@chromium.org98594282011-07-25 22:34:12 +00001213 return true;
1214 }
1215
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001216 SkAutoTUnref<SkPDFDict> descriptor(new SkPDFDict("FontDescriptor"));
vandebo@chromium.org98594282011-07-25 22:34:12 +00001217 setFontDescriptor(descriptor.get());
1218
reed@google.comfed86bd2013-03-14 15:04:57 +00001219 int ttcIndex;
vandebo@chromium.org98594282011-07-25 22:34:12 +00001220 size_t header SK_INIT_TO_AVOID_WARNING;
1221 size_t data SK_INIT_TO_AVOID_WARNING;
1222 size_t trailer SK_INIT_TO_AVOID_WARNING;
scroggoa1193e42015-01-21 12:09:53 -08001223 SkAutoTDelete<SkStream> rawFontData(typeface()->openStream(&ttcIndex));
djsollen7ba28282014-08-28 12:34:41 -07001224 SkAutoTUnref<SkData> fontData(handle_type1_stream(rawFontData.get(), &header,
1225 &data, &trailer));
1226 if (fontData.get() == NULL) {
vandebo@chromium.org98594282011-07-25 22:34:12 +00001227 return false;
1228 }
vandebo0f9bad02014-06-19 11:05:39 -07001229 if (canEmbed()) {
djsollen7ba28282014-08-28 12:34:41 -07001230 SkAutoTUnref<SkPDFStream> fontStream(new SkPDFStream(fontData.get()));
vandebo0f9bad02014-06-19 11:05:39 -07001231 fontStream->insertInt("Length1", header);
1232 fontStream->insertInt("Length2", data);
1233 fontStream->insertInt("Length3", trailer);
halcanarybf51cfd2015-05-05 10:24:09 -07001234 descriptor->insertObjRef("FontFile", fontStream.detach());
vandebo0f9bad02014-06-19 11:05:39 -07001235 }
vandebo@chromium.org98594282011-07-25 22:34:12 +00001236
halcanarybf51cfd2015-05-05 10:24:09 -07001237 this->insertObjRef("FontDescriptor", descriptor.detach());
vandebo@chromium.org98594282011-07-25 22:34:12 +00001238
1239 return addCommonFontDescriptorEntries(defaultWidth);
1240}
1241
1242bool SkPDFType1Font::populate(int16_t glyphID) {
1243 SkASSERT(!fontInfo()->fVerticalMetrics.get());
1244 SkASSERT(fontInfo()->fGlyphWidths.get());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001245
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001246 adjustGlyphRangeForSingleByteEncoding(glyphID);
1247
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001248 int16_t defaultWidth = 0;
1249 const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry = NULL;
1250 const SkAdvancedTypefaceMetrics::WidthRange* widthEntry;
vandebo@chromium.org98594282011-07-25 22:34:12 +00001251 for (widthEntry = fontInfo()->fGlyphWidths.get();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001252 widthEntry != NULL;
1253 widthEntry = widthEntry->fNext.get()) {
1254 switch (widthEntry->fType) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001255 case SkAdvancedTypefaceMetrics::WidthRange::kDefault:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001256 defaultWidth = widthEntry->fAdvance[0];
1257 break;
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001258 case SkAdvancedTypefaceMetrics::WidthRange::kRun:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001259 SkASSERT(false);
1260 break;
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001261 case SkAdvancedTypefaceMetrics::WidthRange::kRange:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001262 SkASSERT(widthRangeEntry == NULL);
1263 widthRangeEntry = widthEntry;
1264 break;
1265 }
1266 }
1267
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +00001268 if (!addFontDescriptor(defaultWidth)) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001269 return false;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +00001270 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001271
reed@google.comc789cf12011-07-20 12:14:33 +00001272 insertName("Subtype", "Type1");
vandebo@chromium.org98594282011-07-25 22:34:12 +00001273 insertName("BaseFont", fontInfo()->fFontName);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00001274
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001275 addWidthInfoFromRange(defaultWidth, widthRangeEntry);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001276
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001277
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001278 SkAutoTUnref<SkPDFArray> encDiffs(new SkPDFArray);
vandebo@chromium.org98594282011-07-25 22:34:12 +00001279 encDiffs->reserve(lastGlyphID() - firstGlyphID() + 2);
reed@google.comc789cf12011-07-20 12:14:33 +00001280 encDiffs->appendInt(1);
vandebo@chromium.org98594282011-07-25 22:34:12 +00001281 for (int gID = firstGlyphID(); gID <= lastGlyphID(); gID++) {
1282 encDiffs->appendName(fontInfo()->fGlyphNames->get()[gID].c_str());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001283 }
1284
halcanarybf51cfd2015-05-05 10:24:09 -07001285 SkAutoTUnref<SkPDFDict> encoding(new SkPDFDict("Encoding"));
1286 encoding->insertObject("Differences", encDiffs.detach());
1287 this->insertObject("Encoding", encoding.detach());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001288 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00001289}
1290
vandebo@chromium.org98594282011-07-25 22:34:12 +00001291void SkPDFType1Font::addWidthInfoFromRange(
1292 int16_t defaultWidth,
1293 const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry) {
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001294 SkAutoTUnref<SkPDFArray> widthArray(new SkPDFArray());
vandebo@chromium.org98594282011-07-25 22:34:12 +00001295 int firstChar = 0;
1296 if (widthRangeEntry) {
1297 const uint16_t emSize = fontInfo()->fEmSize;
1298 int startIndex = firstGlyphID() - widthRangeEntry->fStartId;
1299 int endIndex = startIndex + lastGlyphID() - firstGlyphID() + 1;
1300 if (startIndex < 0)
1301 startIndex = 0;
1302 if (endIndex > widthRangeEntry->fAdvance.count())
1303 endIndex = widthRangeEntry->fAdvance.count();
1304 if (widthRangeEntry->fStartId == 0) {
1305 appendWidth(widthRangeEntry->fAdvance[0], emSize, widthArray.get());
1306 } else {
1307 firstChar = startIndex + widthRangeEntry->fStartId;
1308 }
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +00001309 for (int i = startIndex; i < endIndex; i++) {
vandebo@chromium.org98594282011-07-25 22:34:12 +00001310 appendWidth(widthRangeEntry->fAdvance[i], emSize, widthArray.get());
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +00001311 }
vandebo@chromium.org98594282011-07-25 22:34:12 +00001312 } else {
1313 appendWidth(defaultWidth, 1000, widthArray.get());
1314 }
halcanarybf51cfd2015-05-05 10:24:09 -07001315 this->insertInt("FirstChar", firstChar);
1316 this->insertInt("LastChar", firstChar + widthArray->size() - 1);
1317 this->insertObject("Widths", widthArray.detach());
vandebo@chromium.org98594282011-07-25 22:34:12 +00001318}
1319
1320///////////////////////////////////////////////////////////////////////////////
1321// class SkPDFType3Font
1322///////////////////////////////////////////////////////////////////////////////
1323
halcanary2e3f9d82015-02-27 12:41:03 -08001324SkPDFType3Font::SkPDFType3Font(const SkAdvancedTypefaceMetrics* info,
vandebo@chromium.org98594282011-07-25 22:34:12 +00001325 SkTypeface* typeface,
sugoi@google.come2e81132013-03-05 18:35:55 +00001326 uint16_t glyphID)
halcanary2e3f9d82015-02-27 12:41:03 -08001327 : SkPDFFont(info, typeface, NULL) {
vandebo@chromium.org98594282011-07-25 22:34:12 +00001328 populate(glyphID);
1329}
1330
1331SkPDFType3Font::~SkPDFType3Font() {}
1332
bungeman22edc832014-10-03 07:55:58 -07001333bool SkPDFType3Font::populate(uint16_t glyphID) {
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001334 SkPaint paint;
vandebo@chromium.org98594282011-07-25 22:34:12 +00001335 paint.setTypeface(typeface());
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001336 paint.setTextSize(1000);
bungeman@google.com532470f2013-01-22 19:25:14 +00001337 SkAutoGlyphCache autoCache(paint, NULL, NULL);
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001338 SkGlyphCache* cache = autoCache.getCache();
1339 // If fLastGlyphID isn't set (because there is not fFontInfo), look it up.
vandebo@chromium.org98594282011-07-25 22:34:12 +00001340 if (lastGlyphID() == 0) {
1341 setLastGlyphID(cache->getGlyphCount() - 1);
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001342 }
1343
1344 adjustGlyphRangeForSingleByteEncoding(glyphID);
1345
reed@google.comc789cf12011-07-20 12:14:33 +00001346 insertName("Subtype", "Type3");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001347 // Flip about the x-axis and scale by 1/1000.
1348 SkMatrix fontMatrix;
1349 fontMatrix.setScale(SkScalarInvert(1000), -SkScalarInvert(1000));
halcanarybf51cfd2015-05-05 10:24:09 -07001350 this->insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001351
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001352 SkAutoTUnref<SkPDFDict> charProcs(new SkPDFDict);
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001353 SkAutoTUnref<SkPDFDict> encoding(new SkPDFDict("Encoding"));
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001354
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001355 SkAutoTUnref<SkPDFArray> encDiffs(new SkPDFArray);
vandebo@chromium.org98594282011-07-25 22:34:12 +00001356 encDiffs->reserve(lastGlyphID() - firstGlyphID() + 2);
reed@google.comc789cf12011-07-20 12:14:33 +00001357 encDiffs->appendInt(1);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001358
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +00001359 SkAutoTUnref<SkPDFArray> widthArray(new SkPDFArray());
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001360
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001361 SkIRect bbox = SkIRect::MakeEmpty();
vandebo@chromium.org98594282011-07-25 22:34:12 +00001362 for (int gID = firstGlyphID(); gID <= lastGlyphID(); gID++) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001363 SkString characterName;
1364 characterName.printf("gid%d", gID);
reed@google.comc789cf12011-07-20 12:14:33 +00001365 encDiffs->appendName(characterName.c_str());
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001366
reed@google.comce11b262011-03-21 21:25:35 +00001367 const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
reed@google.comc789cf12011-07-20 12:14:33 +00001368 widthArray->appendScalar(SkFixedToScalar(glyph.fAdvanceX));
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001369 SkIRect glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
1370 glyph.fWidth, glyph.fHeight);
1371 bbox.join(glyphBBox);
1372
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +00001373 SkDynamicMemoryWStream content;
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001374 setGlyphWidthAndBoundingBox(SkFixedToScalar(glyph.fAdvanceX), glyphBBox,
1375 &content);
1376 const SkPath* path = cache->findPath(glyph);
1377 if (path) {
vandebo@chromium.org683001c2012-05-09 17:17:51 +00001378 SkPDFUtils::EmitPath(*path, paint.getStyle(), &content);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001379 SkPDFUtils::PaintPath(paint.getStyle(), path->getFillType(),
1380 &content);
1381 }
scroggoa1193e42015-01-21 12:09:53 -08001382 SkAutoTDelete<SkMemoryStream> glyphStream(new SkMemoryStream());
reed@google.com8a85d0c2011-06-24 19:12:12 +00001383 glyphStream->setData(content.copyToData())->unref();
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +00001384
halcanary130444f2015-04-25 06:45:07 -07001385 charProcs->insertObjRef(characterName,
1386 new SkPDFStream(glyphStream.get()));
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001387 }
1388
halcanarybf51cfd2015-05-05 10:24:09 -07001389 encoding->insertObject("Differences", encDiffs.detach());
1390
1391 this->insertObject("CharProcs", charProcs.detach());
1392 this->insertObject("Encoding", encoding.detach());
1393
1394 this->insertObject("FontBBox", makeFontBBox(bbox, 1000));
1395 this->insertInt("FirstChar", 1);
1396 this->insertInt("LastChar", lastGlyphID() - firstGlyphID() + 1);
1397 this->insertObject("Widths", widthArray.detach());
1398 this->insertName("CIDToGIDMap", "Identity");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001399
vandebo@chromium.org98594282011-07-25 22:34:12 +00001400 populateToUnicodeTable(NULL);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001401 return true;
1402}
halcanaryfb62b3d2015-01-21 09:59:14 -08001403
1404SkPDFFont::Match SkPDFFont::IsMatch(SkPDFFont* existingFont,
1405 uint32_t existingFontID,
1406 uint16_t existingGlyphID,
1407 uint32_t searchFontID,
1408 uint16_t searchGlyphID) {
1409 if (existingFontID != searchFontID) {
1410 return SkPDFFont::kNot_Match;
1411 }
1412 if (existingGlyphID == 0 || searchGlyphID == 0) {
1413 return SkPDFFont::kExact_Match;
1414 }
1415 if (existingFont != NULL) {
1416 return (existingFont->fFirstGlyphID <= searchGlyphID &&
1417 searchGlyphID <= existingFont->fLastGlyphID)
1418 ? SkPDFFont::kExact_Match
1419 : SkPDFFont::kRelated_Match;
1420 }
1421 return (existingGlyphID == searchGlyphID) ? SkPDFFont::kExact_Match
1422 : SkPDFFont::kRelated_Match;
1423}