blob: 5c2c00ea0555c3343cd84da2459153f06563769f [file] [log] [blame]
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00001/*
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00002 * Copyright (C) 2011 Google Inc.
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000017#include <ctype.h>
18
reed@google.com8a85d0c2011-06-24 19:12:12 +000019#include "SkData.h"
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000020#include "SkFontHost.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000021#include "SkGlyphCache.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000022#include "SkPaint.h"
vandebo@chromium.org98594282011-07-25 22:34:12 +000023#include "SkPDFCatalog.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000024#include "SkPDFDevice.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000025#include "SkPDFFont.h"
vandebo@chromium.org98594282011-07-25 22:34:12 +000026#include "SkPDFFontImpl.h"
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000027#include "SkPDFStream.h"
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000028#include "SkPDFTypes.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000029#include "SkPDFUtils.h"
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +000030#include "SkRefCnt.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000031#include "SkScalar.h"
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000032#include "SkStream.h"
33#include "SkTypeface.h"
vandebo@chromium.org325cb9a2011-03-30 18:36:29 +000034#include "SkTypes.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000035#include "SkUtils.h"
36
vandebo@chromium.org1f165892011-07-26 02:11:41 +000037#if defined (SK_SFNTLY_SUBSETTER)
38#include SK_SFNTLY_SUBSETTER
39#endif
40
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000041namespace {
42
vandebo@chromium.org98594282011-07-25 22:34:12 +000043///////////////////////////////////////////////////////////////////////////////
44// File-Local Functions
45///////////////////////////////////////////////////////////////////////////////
46
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000047bool parsePFBSection(const uint8_t** src, size_t* len, int sectionType,
48 size_t* size) {
49 // PFB sections have a two or six bytes header. 0x80 and a one byte
50 // section type followed by a four byte section length. Type one is
51 // an ASCII section (includes a length), type two is a binary section
52 // (includes a length) and type three is an EOF marker with no length.
53 const uint8_t* buf = *src;
54 if (*len < 2 || buf[0] != 0x80 || buf[1] != sectionType)
55 return false;
56 if (buf[1] == 3)
57 return true;
58 if (*len < 6)
59 return false;
60
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;
64 if (consumed > *len)
65 return false;
66 *src = *src + consumed;
67 *len = *len - consumed;
68 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000069}
70
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000071bool parsePFB(const uint8_t* src, size_t size, size_t* headerLen,
72 size_t* dataLen, size_t* trailerLen) {
73 const uint8_t* srcPtr = src;
74 size_t remaining = size;
75
76 return parsePFBSection(&srcPtr, &remaining, 1, headerLen) &&
77 parsePFBSection(&srcPtr, &remaining, 2, dataLen) &&
78 parsePFBSection(&srcPtr, &remaining, 1, trailerLen) &&
79 parsePFBSection(&srcPtr, &remaining, 3, NULL);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000080}
81
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000082/* The sections of a PFA file are implicitly defined. The body starts
83 * after the line containing "eexec," and the trailer starts with 512
84 * literal 0's followed by "cleartomark" (plus arbitrary white space).
85 *
86 * This function assumes that src is NUL terminated, but the NUL
87 * termination is not included in size.
88 *
89 */
90bool parsePFA(const char* src, size_t size, size_t* headerLen,
91 size_t* hexDataLen, size_t* dataLen, size_t* trailerLen) {
92 const char* end = src + size;
93
94 const char* dataPos = strstr(src, "eexec");
95 if (!dataPos)
96 return false;
97 dataPos += strlen("eexec");
98 while ((*dataPos == '\n' || *dataPos == '\r' || *dataPos == ' ') &&
99 dataPos < end)
100 dataPos++;
101 *headerLen = dataPos - src;
102
103 const char* trailerPos = strstr(dataPos, "cleartomark");
104 if (!trailerPos)
105 return false;
106 int zeroCount = 0;
107 for (trailerPos--; trailerPos > dataPos && zeroCount < 512; trailerPos--) {
108 if (*trailerPos == '\n' || *trailerPos == '\r' || *trailerPos == ' ') {
109 continue;
110 } else if (*trailerPos == '0') {
111 zeroCount++;
112 } else {
113 return false;
114 }
115 }
116 if (zeroCount != 512)
117 return false;
118
119 *hexDataLen = trailerPos - src - *headerLen;
120 *trailerLen = size - *headerLen - *hexDataLen;
121
122 // Verify that the data section is hex encoded and count the bytes.
123 int nibbles = 0;
124 for (; dataPos < trailerPos; dataPos++) {
125 if (isspace(*dataPos))
126 continue;
127 if (!isxdigit(*dataPos))
128 return false;
129 nibbles++;
130 }
131 *dataLen = (nibbles + 1) / 2;
132
133 return true;
134}
135
136int8_t hexToBin(uint8_t c) {
137 if (!isxdigit(c))
138 return -1;
139 if (c <= '9') return c - '0';
140 if (c <= 'F') return c - 'A' + 10;
141 if (c <= 'f') return c - 'a' + 10;
142 return -1;
143}
144
145SkStream* handleType1Stream(SkStream* srcStream, size_t* headerLen,
146 size_t* dataLen, size_t* trailerLen) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000147 // srcStream may be backed by a file or a unseekable fd, so we may not be
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000148 // able to use skip(), rewind(), or getMemoryBase(). read()ing through
149 // the input only once is doable, but very ugly. Furthermore, it'd be nice
150 // if the data was NUL terminated so that we can use strstr() to search it.
151 // Make as few copies as possible given these constraints.
152 SkDynamicMemoryWStream dynamicStream;
153 SkRefPtr<SkMemoryStream> staticStream;
reed@google.com8a85d0c2011-06-24 19:12:12 +0000154 SkData* data = NULL;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000155 const uint8_t* src;
156 size_t srcLen;
157 if ((srcLen = srcStream->getLength()) > 0) {
158 staticStream = new SkMemoryStream(srcLen + 1);
159 staticStream->unref(); // new and SkRefPtr both took a ref.
160 src = (const uint8_t*)staticStream->getMemoryBase();
161 if (srcStream->getMemoryBase() != NULL) {
162 memcpy((void *)src, srcStream->getMemoryBase(), srcLen);
163 } else {
164 size_t read = 0;
165 while (read < srcLen) {
166 size_t got = srcStream->read((void *)staticStream->getAtPos(),
167 srcLen - read);
168 if (got == 0)
169 return NULL;
170 read += got;
171 staticStream->seek(read);
172 }
173 }
174 ((uint8_t *)src)[srcLen] = 0;
175 } else {
176 static const size_t bufSize = 4096;
177 uint8_t buf[bufSize];
178 size_t amount;
179 while ((amount = srcStream->read(buf, bufSize)) > 0)
180 dynamicStream.write(buf, amount);
181 amount = 0;
182 dynamicStream.write(&amount, 1); // NULL terminator.
reed@google.com8a85d0c2011-06-24 19:12:12 +0000183 data = dynamicStream.copyToData();
184 src = data->bytes();
185 srcLen = data->size() - 1;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000186 }
187
reed@google.com8a85d0c2011-06-24 19:12:12 +0000188 // this handles releasing the data we may have gotten from dynamicStream.
189 // if data is null, it is a no-op
190 SkAutoDataUnref aud(data);
191
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000192 if (parsePFB(src, srcLen, headerLen, dataLen, trailerLen)) {
193 SkMemoryStream* result =
194 new SkMemoryStream(*headerLen + *dataLen + *trailerLen);
195 memcpy((char*)result->getAtPos(), src + 6, *headerLen);
196 result->seek(*headerLen);
197 memcpy((char*)result->getAtPos(), src + 6 + *headerLen + 6, *dataLen);
198 result->seek(*headerLen + *dataLen);
199 memcpy((char*)result->getAtPos(), src + 6 + *headerLen + 6 + *dataLen,
200 *trailerLen);
201 result->rewind();
202 return result;
203 }
204
205 // A PFA has to be converted for PDF.
206 size_t hexDataLen;
207 if (parsePFA((const char*)src, srcLen, headerLen, &hexDataLen, dataLen,
208 trailerLen)) {
209 SkMemoryStream* result =
210 new SkMemoryStream(*headerLen + *dataLen + *trailerLen);
211 memcpy((char*)result->getAtPos(), src, *headerLen);
212 result->seek(*headerLen);
213
214 const uint8_t* hexData = src + *headerLen;
215 const uint8_t* trailer = hexData + hexDataLen;
216 size_t outputOffset = 0;
vandebo@chromium.org5b073682011-03-08 18:33:31 +0000217 uint8_t dataByte = 0; // To hush compiler.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000218 bool highNibble = true;
219 for (; hexData < trailer; hexData++) {
220 char curNibble = hexToBin(*hexData);
221 if (curNibble < 0)
222 continue;
223 if (highNibble) {
224 dataByte = curNibble << 4;
225 highNibble = false;
226 } else {
227 dataByte |= curNibble;
228 highNibble = true;
229 ((char *)result->getAtPos())[outputOffset++] = dataByte;
230 }
231 }
232 if (!highNibble)
233 ((char *)result->getAtPos())[outputOffset++] = dataByte;
234 SkASSERT(outputOffset == *dataLen);
235 result->seek(*headerLen + outputOffset);
236
237 memcpy((char *)result->getAtPos(), src + *headerLen + hexDataLen,
238 *trailerLen);
239 result->rewind();
240 return result;
241 }
242
243 return NULL;
244}
245
reed@google.com3f0dcf92011-03-18 21:23:45 +0000246// scale from em-units to base-1000, returning as a SkScalar
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000247SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
reed@google.com3f0dcf92011-03-18 21:23:45 +0000248 SkScalar scaled = SkIntToScalar(val);
249 if (emSize == 1000) {
250 return scaled;
251 } else {
252 return SkScalarMulDiv(scaled, 1000, emSize);
253 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000254}
255
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000256void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000257 SkWStream* content) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000258 // Specify width and bounding box for the glyph.
259 SkPDFScalar::Append(width, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000260 content->writeText(" 0 ");
261 content->writeDecAsText(box.fLeft);
262 content->writeText(" ");
263 content->writeDecAsText(box.fTop);
264 content->writeText(" ");
265 content->writeDecAsText(box.fRight);
266 content->writeText(" ");
267 content->writeDecAsText(box.fBottom);
268 content->writeText(" d1\n");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000269}
270
vandebo@chromium.org75f97e42011-04-11 23:24:18 +0000271SkPDFArray* makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000272 SkPDFArray* bbox = new SkPDFArray;
273 bbox->reserve(4);
reed@google.comc789cf12011-07-20 12:14:33 +0000274 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fLeft, emSize));
275 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fBottom, emSize));
276 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fRight, emSize));
277 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fTop, emSize));
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000278 return bbox;
279}
280
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000281SkPDFArray* appendWidth(const int16_t& width, uint16_t emSize,
282 SkPDFArray* array) {
reed@google.comc789cf12011-07-20 12:14:33 +0000283 array->appendScalar(scaleFromFontUnits(width, emSize));
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000284 return array;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000285}
286
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000287SkPDFArray* appendVerticalAdvance(
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000288 const SkAdvancedTypefaceMetrics::VerticalMetric& advance,
289 uint16_t emSize, SkPDFArray* array) {
290 appendWidth(advance.fVerticalAdvance, emSize, array);
291 appendWidth(advance.fOriginXDisp, emSize, array);
292 appendWidth(advance.fOriginYDisp, emSize, array);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000293 return array;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000294}
295
296template <typename Data>
297SkPDFArray* composeAdvanceData(
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000298 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* advanceInfo,
299 uint16_t emSize,
300 SkPDFArray* (*appendAdvance)(const Data& advance, uint16_t emSize,
301 SkPDFArray* array),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000302 Data* defaultAdvance) {
303 SkPDFArray* result = new SkPDFArray();
304 for (; advanceInfo != NULL; advanceInfo = advanceInfo->fNext.get()) {
305 switch (advanceInfo->fType) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000306 case SkAdvancedTypefaceMetrics::WidthRange::kDefault: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000307 SkASSERT(advanceInfo->fAdvance.count() == 1);
308 *defaultAdvance = advanceInfo->fAdvance[0];
309 break;
310 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000311 case SkAdvancedTypefaceMetrics::WidthRange::kRange: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000312 SkRefPtr<SkPDFArray> advanceArray = new SkPDFArray();
313 advanceArray->unref(); // SkRefPtr and new both took a ref.
314 for (int j = 0; j < advanceInfo->fAdvance.count(); j++)
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000315 appendAdvance(advanceInfo->fAdvance[j], emSize,
316 advanceArray.get());
reed@google.comc789cf12011-07-20 12:14:33 +0000317 result->appendInt(advanceInfo->fStartId);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000318 result->append(advanceArray.get());
319 break;
320 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000321 case SkAdvancedTypefaceMetrics::WidthRange::kRun: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000322 SkASSERT(advanceInfo->fAdvance.count() == 1);
reed@google.comc789cf12011-07-20 12:14:33 +0000323 result->appendInt(advanceInfo->fStartId);
324 result->appendInt(advanceInfo->fEndId);
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000325 appendAdvance(advanceInfo->fAdvance[0], emSize, result);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000326 break;
327 }
328 }
329 }
330 return result;
331}
332
333} // namespace
334
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000335static void append_tounicode_header(SkDynamicMemoryWStream* cmap) {
336 // 12 dict begin: 12 is an Adobe-suggested value. Shall not change.
337 // It's there to prevent old version Adobe Readers from malfunctioning.
338 const char* kHeader =
339 "/CIDInit /ProcSet findresource begin\n"
340 "12 dict begin\n"
341 "begincmap\n";
342 cmap->writeText(kHeader);
343
344 // The /CIDSystemInfo must be consistent to the one in
345 // SkPDFFont::populateCIDFont().
346 // We can not pass over the system info object here because the format is
347 // different. This is not a reference object.
348 const char* kSysInfo =
349 "/CIDSystemInfo\n"
350 "<< /Registry (Adobe)\n"
351 "/Ordering (UCS)\n"
352 "/Supplement 0\n"
353 ">> def\n";
354 cmap->writeText(kSysInfo);
355
356 // The CMapName must be consistent to /CIDSystemInfo above.
357 // /CMapType 2 means ToUnicode.
358 // We specify codespacerange from 0x0000 to 0xFFFF because we convert our
359 // code table from unsigned short (16-bits). Codespace range just tells the
360 // PDF processor the valid range. It does not matter whether a complete
361 // mapping is provided or not.
362 const char* kTypeInfo =
363 "/CMapName /Adobe-Identity-UCS def\n"
364 "/CMapType 2 def\n"
365 "1 begincodespacerange\n"
366 "<0000> <FFFF>\n"
367 "endcodespacerange\n";
368 cmap->writeText(kTypeInfo);
369}
370
371static void append_cmap_bfchar_table(uint16_t* glyph_id, SkUnichar* unicode,
372 size_t count,
373 SkDynamicMemoryWStream* cmap) {
374 cmap->writeDecAsText(count);
375 cmap->writeText(" beginbfchar\n");
376 for (size_t i = 0; i < count; ++i) {
377 cmap->writeText("<");
378 cmap->writeHexAsText(glyph_id[i], 4);
379 cmap->writeText("> <");
380 cmap->writeHexAsText(unicode[i], 4);
381 cmap->writeText(">\n");
382 }
383 cmap->writeText("endbfchar\n");
384}
385
386static void append_cmap_footer(SkDynamicMemoryWStream* cmap) {
387 const char* kFooter =
388 "endcmap\n"
389 "CMapName currentdict /CMap defineresource pop\n"
390 "end\n"
391 "end";
392 cmap->writeText(kFooter);
393}
394
395// Generate <bfchar> table according to PDF spec 1.4 and Adobe Technote 5014.
396static void append_cmap_bfchar_sections(
397 const SkTDArray<SkUnichar>& glyphUnicode,
vandebo@chromium.org98594282011-07-25 22:34:12 +0000398 const SkPDFGlyphSet* subset, SkDynamicMemoryWStream* cmap) {
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000399 // PDF spec defines that every bf* list can have at most 100 entries.
400 const size_t kMaxEntries = 100;
401 uint16_t glyphId[kMaxEntries];
402 SkUnichar unicode[kMaxEntries];
403 size_t index = 0;
404 for (int i = 0; i < glyphUnicode.count(); i++) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000405 if (glyphUnicode[i] && (subset == NULL || subset->has(i))) {
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000406 glyphId[index] = i;
407 unicode[index] = glyphUnicode[i];
408 ++index;
409 }
410 if (index == kMaxEntries) {
411 append_cmap_bfchar_table(glyphId, unicode, index, cmap);
412 index = 0;
413 }
414 }
415
416 if (index) {
417 append_cmap_bfchar_table(glyphId, unicode, index, cmap);
418 }
419}
420
vandebo@chromium.org98594282011-07-25 22:34:12 +0000421static SkPDFStream* generate_tounicode_cmap(
422 const SkTDArray<SkUnichar>& glyphUnicode,
423 const SkPDFGlyphSet* subset) {
424 SkDynamicMemoryWStream cmap;
425 append_tounicode_header(&cmap);
426 append_cmap_bfchar_sections(glyphUnicode, subset, &cmap);
427 append_cmap_footer(&cmap);
428 SkRefPtr<SkMemoryStream> cmapStream = new SkMemoryStream();
429 cmapStream->unref(); // SkRefPtr and new took a reference.
430 cmapStream->setData(cmap.copyToData());
431 return new SkPDFStream(cmapStream.get());
432}
433
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000434static void sk_delete_array(const void* ptr, size_t, void*) {
435 // Use C-style cast to cast away const and cast type simultaneously.
436 delete[] (unsigned char*)ptr;
437}
438
439static int get_subset_font_stream(const char* fontName,
440 const SkTypeface* typeface,
441 const SkPDFGlyphSet* subset,
442 SkPDFStream** fontStream) {
443 SkRefPtr<SkStream> fontData =
444 SkFontHost::OpenStream(SkTypeface::UniqueID(typeface));
445 fontData->unref(); // SkRefPtr and OpenStream both took a ref.
446
447 int fontSize = fontData->getLength();
448
449#if defined (SK_SFNTLY_SUBSETTER)
450 // Generate glyph id array.
vandebo@chromium.org17e66e22011-07-27 20:59:55 +0000451 SkTDArray<uint32_t> glyphIDs;
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000452 glyphIDs.push(0); // Always include glyph 0.
vandebo@chromium.org17e66e22011-07-27 20:59:55 +0000453 subset->exportTo(&glyphIDs);
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000454
455 // Read font into buffer.
456 SkPDFStream* subsetFontStream = NULL;
457 SkTDArray<unsigned char> originalFont;
458 originalFont.setCount(fontSize);
459 if (fontData->read(originalFont.begin(), fontSize) == (size_t)fontSize) {
460 unsigned char* subsetFont = NULL;
vandebo@chromium.org17e66e22011-07-27 20:59:55 +0000461 // sfntly requires unsigned int* to be passed in, as far as we know,
462 // unsigned int is equivalent to uint32_t on all platforms.
463 SK_COMPILE_ASSERT(sizeof(unsigned int) == sizeof(uint32_t),
464 unsigned_int_not_32_bits);
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000465 int subsetFontSize = SfntlyWrapper::SubsetFont(fontName,
466 originalFont.begin(),
467 fontSize,
468 glyphIDs.begin(),
469 glyphIDs.count(),
470 &subsetFont);
471 if (subsetFontSize > 0 && subsetFont != NULL) {
vandebo@chromium.org93225ff2011-07-27 18:38:11 +0000472 SkAutoDataUnref data(SkData::NewWithProc(subsetFont,
473 subsetFontSize,
474 sk_delete_array,
475 NULL));
476 subsetFontStream = new SkPDFStream(data.get());
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000477 fontSize = subsetFontSize;
478 }
479 }
480 if (subsetFontStream) {
481 *fontStream = subsetFontStream;
482 return fontSize;
483 }
484#endif
485
486 // Fail over: just embed the whole font.
487 *fontStream = new SkPDFStream(fontData.get());
488 return fontSize;
489}
490
vandebo@chromium.org98594282011-07-25 22:34:12 +0000491///////////////////////////////////////////////////////////////////////////////
492// class SkPDFGlyphSet
493///////////////////////////////////////////////////////////////////////////////
494
495SkPDFGlyphSet::SkPDFGlyphSet() : fBitSet(SK_MaxU16 + 1) {
496}
497
498void SkPDFGlyphSet::set(const uint16_t* glyphIDs, int numGlyphs) {
499 for (int i = 0; i < numGlyphs; ++i) {
500 fBitSet.setBit(glyphIDs[i], true);
501 }
502}
503
504bool SkPDFGlyphSet::has(uint16_t glyphID) const {
505 return fBitSet.isBitSet(glyphID);
506}
507
508void SkPDFGlyphSet::merge(const SkPDFGlyphSet& usage) {
509 fBitSet.orBits(usage.fBitSet);
510}
511
vandebo@chromium.org17e66e22011-07-27 20:59:55 +0000512void SkPDFGlyphSet::exportTo(SkTDArray<unsigned int>* glyphIDs) const {
513 fBitSet.exportTo(glyphIDs);
514}
515
vandebo@chromium.org98594282011-07-25 22:34:12 +0000516///////////////////////////////////////////////////////////////////////////////
517// class SkPDFGlyphSetMap
518///////////////////////////////////////////////////////////////////////////////
519SkPDFGlyphSetMap::FontGlyphSetPair::FontGlyphSetPair(SkPDFFont* font,
520 SkPDFGlyphSet* glyphSet)
521 : fFont(font),
522 fGlyphSet(glyphSet) {
523}
524
525SkPDFGlyphSetMap::F2BIter::F2BIter(const SkPDFGlyphSetMap& map) {
526 reset(map);
527}
528
529SkPDFGlyphSetMap::FontGlyphSetPair* SkPDFGlyphSetMap::F2BIter::next() const {
530 if (fIndex >= fMap->count()) {
531 return NULL;
532 }
533 return &((*fMap)[fIndex++]);
534}
535
536void SkPDFGlyphSetMap::F2BIter::reset(const SkPDFGlyphSetMap& map) {
537 fMap = &(map.fMap);
538 fIndex = 0;
539}
540
541SkPDFGlyphSetMap::SkPDFGlyphSetMap() {
542}
543
544SkPDFGlyphSetMap::~SkPDFGlyphSetMap() {
545 reset();
546}
547
548void SkPDFGlyphSetMap::merge(const SkPDFGlyphSetMap& usage) {
549 for (int i = 0; i < usage.fMap.count(); ++i) {
550 SkPDFGlyphSet* myUsage = getGlyphSetForFont(usage.fMap[i].fFont);
551 myUsage->merge(*(usage.fMap[i].fGlyphSet));
552 }
553}
554
555void SkPDFGlyphSetMap::reset() {
556 for (int i = 0; i < fMap.count(); ++i) {
557 delete fMap[i].fGlyphSet; // Should not be NULL.
558 }
559 fMap.reset();
560}
561
562void SkPDFGlyphSetMap::noteGlyphUsage(SkPDFFont* font, const uint16_t* glyphIDs,
563 int numGlyphs) {
564 SkPDFGlyphSet* subset = getGlyphSetForFont(font);
565 if (subset) {
566 subset->set(glyphIDs, numGlyphs);
567 }
568}
569
570SkPDFGlyphSet* SkPDFGlyphSetMap::getGlyphSetForFont(SkPDFFont* font) {
571 int index = fMap.count();
572 for (int i = 0; i < index; ++i) {
573 if (fMap[i].fFont == font) {
574 return fMap[i].fGlyphSet;
575 }
576 }
577 fMap.append();
578 index = fMap.count() - 1;
579 fMap[index].fFont = font;
580 fMap[index].fGlyphSet = new SkPDFGlyphSet();
581 return fMap[index].fGlyphSet;
582}
583
584///////////////////////////////////////////////////////////////////////////////
585// class SkPDFFont
586///////////////////////////////////////////////////////////////////////////////
587
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000588/* Font subset design: It would be nice to be able to subset fonts
589 * (particularly type 3 fonts), but it's a lot of work and not a priority.
590 *
591 * Resources are canonicalized and uniqueified by pointer so there has to be
592 * some additional state indicating which subset of the font is used. It
593 * must be maintained at the page granularity and then combined at the document
594 * granularity. a) change SkPDFFont to fill in its state on demand, kind of
595 * like SkPDFGraphicState. b) maintain a per font glyph usage class in each
596 * page/pdf device. c) in the document, retrieve the per font glyph usage
597 * from each page and combine it and ask for a resource with that subset.
598 */
599
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000600SkPDFFont::~SkPDFFont() {
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000601 SkAutoMutexAcquire lock(CanonicalFontsMutex());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000602 int index;
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000603 if (Find(SkTypeface::UniqueID(fTypeface.get()), fFirstGlyphID, &index)) {
604 CanonicalFonts().removeShuffle(index);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000605 }
606 fResources.unrefAll();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000607}
608
609void SkPDFFont::getResources(SkTDArray<SkPDFObject*>* resourceList) {
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000610 GetResourcesHelper(&fResources, resourceList);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000611}
612
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000613SkTypeface* SkPDFFont::typeface() {
614 return fTypeface.get();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000615}
616
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000617SkAdvancedTypefaceMetrics::FontType SkPDFFont::getType() {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000618 return fFontType;
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000619}
620
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000621bool SkPDFFont::hasGlyph(uint16_t id) {
622 return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0;
623}
624
vandebo@chromium.org01294102011-02-28 19:52:18 +0000625size_t SkPDFFont::glyphsToPDFFontEncoding(uint16_t* glyphIDs,
626 size_t numGlyphs) {
627 // A font with multibyte glyphs will support all glyph IDs in a single font.
vandebo@chromium.org98594282011-07-25 22:34:12 +0000628 if (this->multiByteGlyphs()) {
vandebo@chromium.org01294102011-02-28 19:52:18 +0000629 return numGlyphs;
630 }
631
632 for (size_t i = 0; i < numGlyphs; i++) {
633 if (glyphIDs[i] == 0) {
634 continue;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000635 }
vandebo@chromium.org01294102011-02-28 19:52:18 +0000636 if (glyphIDs[i] < fFirstGlyphID || glyphIDs[i] > fLastGlyphID) {
637 return i;
638 }
639 glyphIDs[i] -= (fFirstGlyphID - 1);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000640 }
641
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000642 return numGlyphs;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000643}
644
645// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000646SkPDFFont* SkPDFFont::GetFontResource(SkTypeface* typeface, uint16_t glyphID) {
647 SkAutoMutexAcquire lock(CanonicalFontsMutex());
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000648 const uint32_t fontID = SkTypeface::UniqueID(typeface);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000649 int relatedFontIndex;
650 if (Find(fontID, glyphID, &relatedFontIndex)) {
651 CanonicalFonts()[relatedFontIndex].fFont->ref();
652 return CanonicalFonts()[relatedFontIndex].fFont;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000653 }
654
vandebo@chromium.org98594282011-07-25 22:34:12 +0000655 SkRefPtr<SkAdvancedTypefaceMetrics> fontMetrics;
656 SkPDFDict* relatedFontDescriptor = NULL;
657 if (relatedFontIndex >= 0) {
658 SkPDFFont* relatedFont = CanonicalFonts()[relatedFontIndex].fFont;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000659 SkASSERT(relatedFont->fFontInfo.get());
vandebo@chromium.org98594282011-07-25 22:34:12 +0000660 fontMetrics = relatedFont->fontInfo();
661 relatedFontDescriptor = relatedFont->getFontDescriptor();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000662 } else {
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000663 SkAdvancedTypefaceMetrics::PerGlyphInfo info;
664 info = SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo;
665 info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>(
666 info, SkAdvancedTypefaceMetrics::kGlyphNames_PerGlyphInfo);
667 info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>(
668 info, SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000669 fontMetrics = SkFontHost::GetAdvancedTypefaceMetrics(fontID, info);
670 SkSafeUnref(fontMetrics.get()); // SkRefPtr and Get both took a ref.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000671 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000672
vandebo@chromium.org98594282011-07-25 22:34:12 +0000673 SkPDFFont* font = Create(fontMetrics.get(), typeface, glyphID,
674 relatedFontDescriptor);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000675 FontRec newEntry(font, fontID, font->fFirstGlyphID);
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000676 CanonicalFonts().push(newEntry);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000677 return font; // Return the reference new SkPDFFont() created.
678}
679
vandebo@chromium.org98594282011-07-25 22:34:12 +0000680SkPDFFont* SkPDFFont::getFontSubset(const SkPDFGlyphSet* usage) {
681 return NULL; // Default: no support.
682}
683
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000684// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000685SkTDArray<SkPDFFont::FontRec>& SkPDFFont::CanonicalFonts() {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000686 // This initialization is only thread safe with gcc.
687 static SkTDArray<FontRec> gCanonicalFonts;
688 return gCanonicalFonts;
689}
690
691// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000692SkMutex& SkPDFFont::CanonicalFontsMutex() {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000693 // This initialization is only thread safe with gcc.
694 static SkMutex gCanonicalFontsMutex;
695 return gCanonicalFontsMutex;
696}
697
698// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000699bool SkPDFFont::Find(uint32_t fontID, uint16_t glyphID, int* index) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000700 // TODO(vandebo) optimize this, do only one search?
701 FontRec search(NULL, fontID, glyphID);
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000702 *index = CanonicalFonts().find(search);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000703 if (*index >= 0)
704 return true;
705 search.fGlyphID = 0;
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000706 *index = CanonicalFonts().find(search);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000707 return false;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000708}
709
vandebo@chromium.org98594282011-07-25 22:34:12 +0000710SkPDFFont::SkPDFFont(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface,
711 uint16_t glyphID, bool descendantFont)
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000712 : SkPDFDict("Font"),
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000713 fTypeface(typeface),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000714 fFirstGlyphID(1),
vandebo@chromium.org98594282011-07-25 22:34:12 +0000715 fLastGlyphID(info ? info->fLastGlyphID : 0),
716 fFontInfo(info) {
717 if (info == NULL) {
718 fFontType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
719 } else if (info->fMultiMaster) {
720 fFontType = SkAdvancedTypefaceMetrics::kOther_Font;
721 } else {
722 fFontType = info->fType;
723 }
724}
725
726// static
727SkPDFFont* SkPDFFont::Create(SkAdvancedTypefaceMetrics* info,
728 SkTypeface* typeface, uint16_t glyphID,
729 SkPDFDict* relatedFontDescriptor) {
730 SkAdvancedTypefaceMetrics::FontType type =
731 info ? info->fType : SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
732
733 if (info && info->fMultiMaster) {
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000734 NOT_IMPLEMENTED(true, true);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000735 return new SkPDFType3Font(info,
736 typeface,
737 glyphID,
738 relatedFontDescriptor);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000739 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000740 if (type == SkAdvancedTypefaceMetrics::kType1CID_Font ||
741 type == SkAdvancedTypefaceMetrics::kTrueType_Font) {
742 SkASSERT(relatedFontDescriptor == NULL);
743 return new SkPDFType0Font(info, typeface);
744 }
745 if (type == SkAdvancedTypefaceMetrics::kType1_Font) {
746 return new SkPDFType1Font(info,
747 typeface,
748 glyphID,
749 relatedFontDescriptor);
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000750 }
vandebo@chromium.org31dcee72011-07-23 21:13:30 +0000751
vandebo@chromium.org98594282011-07-25 22:34:12 +0000752 SkASSERT(type == SkAdvancedTypefaceMetrics::kCFF_Font ||
753 type == SkAdvancedTypefaceMetrics::kOther_Font ||
754 type == SkAdvancedTypefaceMetrics::kNotEmbeddable_Font);
vandebo@chromium.org31dcee72011-07-23 21:13:30 +0000755
vandebo@chromium.org98594282011-07-25 22:34:12 +0000756 return new SkPDFType3Font(info, typeface, glyphID, relatedFontDescriptor);
vandebo@chromium.org31dcee72011-07-23 21:13:30 +0000757}
758
vandebo@chromium.org98594282011-07-25 22:34:12 +0000759SkAdvancedTypefaceMetrics* SkPDFFont::fontInfo() {
760 return fFontInfo.get();
vandebo@chromium.org31dcee72011-07-23 21:13:30 +0000761}
762
vandebo@chromium.org98594282011-07-25 22:34:12 +0000763uint16_t SkPDFFont::firstGlyphID() const {
764 return fFirstGlyphID;
765}
766
767uint16_t SkPDFFont::lastGlyphID() const {
768 return fLastGlyphID;
769}
770
771void SkPDFFont::setLastGlyphID(uint16_t glyphID) {
772 fLastGlyphID = glyphID;
773}
774
775void SkPDFFont::addResource(SkPDFObject* object) {
776 SkASSERT(object != NULL);
777 fResources.push(object);
778}
779
780SkPDFDict* SkPDFFont::getFontDescriptor() {
781 return fDescriptor.get();
782}
783
784void SkPDFFont::setFontDescriptor(SkPDFDict* descriptor) {
785 fDescriptor = descriptor;
786}
787
788bool SkPDFFont::addCommonFontDescriptorEntries(int16_t defaultWidth) {
789 if (fDescriptor.get() == NULL) {
790 return false;
vandebo@chromium.org31dcee72011-07-23 21:13:30 +0000791 }
792
vandebo@chromium.org98594282011-07-25 22:34:12 +0000793 const uint16_t emSize = fFontInfo->fEmSize;
794
795 fDescriptor->insertName("FontName", fFontInfo->fFontName);
796 fDescriptor->insertInt("Flags", fFontInfo->fStyle);
797 fDescriptor->insertScalar("Ascent",
798 scaleFromFontUnits(fFontInfo->fAscent, emSize));
799 fDescriptor->insertScalar("Descent",
800 scaleFromFontUnits(fFontInfo->fDescent, emSize));
801 fDescriptor->insertScalar("StemV",
802 scaleFromFontUnits(fFontInfo->fStemV, emSize));
803 fDescriptor->insertScalar("CapHeight",
804 scaleFromFontUnits(fFontInfo->fCapHeight, emSize));
805 fDescriptor->insertInt("ItalicAngle", fFontInfo->fItalicAngle);
806 fDescriptor->insert("FontBBox", makeFontBBox(fFontInfo->fBBox,
807 fFontInfo->fEmSize))->unref();
808
809 if (defaultWidth > 0) {
810 fDescriptor->insertScalar("MissingWidth",
811 scaleFromFontUnits(defaultWidth, emSize));
812 }
813 return true;
814}
815
816void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(int16_t glyphID) {
817 // Single byte glyph encoding supports a max of 255 glyphs.
818 fFirstGlyphID = glyphID - (glyphID - 1) % 255;
819 if (fLastGlyphID > fFirstGlyphID + 255 - 1) {
820 fLastGlyphID = fFirstGlyphID + 255 - 1;
821 }
822}
823
824bool SkPDFFont::FontRec::operator==(const SkPDFFont::FontRec& b) const {
825 if (fFontID != b.fFontID)
826 return false;
827 if (fFont != NULL && b.fFont != NULL) {
828 return fFont->fFirstGlyphID == b.fFont->fFirstGlyphID &&
829 fFont->fLastGlyphID == b.fFont->fLastGlyphID;
830 }
831 if (fGlyphID == 0 || b.fGlyphID == 0)
832 return true;
833
834 if (fFont != NULL) {
835 return fFont->fFirstGlyphID <= b.fGlyphID &&
836 b.fGlyphID <= fFont->fLastGlyphID;
837 } else if (b.fFont != NULL) {
838 return b.fFont->fFirstGlyphID <= fGlyphID &&
839 fGlyphID <= b.fFont->fLastGlyphID;
840 }
841 return fGlyphID == b.fGlyphID;
842}
843
844SkPDFFont::FontRec::FontRec(SkPDFFont* font, uint32_t fontID, uint16_t glyphID)
845 : fFont(font),
846 fFontID(fontID),
847 fGlyphID(glyphID) {
848}
849
850void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) {
851 if (fFontInfo == NULL || fFontInfo->fGlyphToUnicode.begin() == NULL) {
852 return;
853 }
854 SkRefPtr<SkPDFStream> pdfCmap =
855 generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset);
856 addResource(pdfCmap.get()); // Pass reference from new.
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000857 insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000858}
859
vandebo@chromium.org98594282011-07-25 22:34:12 +0000860///////////////////////////////////////////////////////////////////////////////
861// class SkPDFType0Font
862///////////////////////////////////////////////////////////////////////////////
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000863
vandebo@chromium.org98594282011-07-25 22:34:12 +0000864SkPDFType0Font::SkPDFType0Font(SkAdvancedTypefaceMetrics* info,
865 SkTypeface* typeface)
866 : SkPDFFont(info, typeface, 0, false) {
867 SkDEBUGCODE(fPopulated = false);
868}
869
870SkPDFType0Font::~SkPDFType0Font() {}
871
872SkPDFFont* SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) {
873 SkPDFType0Font* newSubset = new SkPDFType0Font(fontInfo(), typeface());
874 newSubset->populate(subset);
875 return newSubset;
876}
877
878#ifdef SK_DEBUG
879void SkPDFType0Font::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
880 bool indirect) {
881 SkASSERT(fPopulated);
882 return INHERITED::emitObject(stream, catalog, indirect);
883}
884#endif
885
886bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) {
887 insertName("Subtype", "Type0");
888 insertName("BaseFont", fontInfo()->fFontName);
889 insertName("Encoding", "Identity-H");
890
891 // Pass ref new created to fResources.
892 SkPDFCIDFont* newCIDFont =
893 new SkPDFCIDFont(fontInfo(), typeface(), subset);
894 addResource(newCIDFont);
895 SkRefPtr<SkPDFArray> descendantFonts = new SkPDFArray();
896 descendantFonts->unref(); // SkRefPtr and new took a reference.
897 descendantFonts->append(new SkPDFObjRef(newCIDFont))->unref();
898 insert("DescendantFonts", descendantFonts.get());
899
900 populateToUnicodeTable(subset);
901
902 SkDEBUGCODE(fPopulated = true);
903 return true;
904}
905
906///////////////////////////////////////////////////////////////////////////////
907// class SkPDFCIDFont
908///////////////////////////////////////////////////////////////////////////////
909
910SkPDFCIDFont::SkPDFCIDFont(SkAdvancedTypefaceMetrics* info,
911 SkTypeface* typeface, const SkPDFGlyphSet* subset)
912 : SkPDFFont(info, typeface, 0, true) {
913 populate(subset);
914}
915
916SkPDFCIDFont::~SkPDFCIDFont() {}
917
918bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
919 const SkPDFGlyphSet* subset) {
920 SkRefPtr<SkPDFDict> descriptor = new SkPDFDict("FontDescriptor");
921 descriptor->unref(); // SkRefPtr and new both took a ref.
922 setFontDescriptor(descriptor.get());
923
924 switch (getType()) {
925 case SkAdvancedTypefaceMetrics::kTrueType_Font: {
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000926 // Font subsetting
927 SkPDFStream* rawStream = NULL;
928 int fontSize = get_subset_font_stream(fontInfo()->fFontName.c_str(),
929 typeface(),
930 subset,
931 &rawStream);
932 SkASSERT(fontSize);
933 SkASSERT(rawStream);
934 SkRefPtr<SkPDFStream> fontStream = rawStream;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000935 // SkRefPtr and new both ref()'d fontStream, pass one.
936 addResource(fontStream.get());
937
vandebo@chromium.org1f165892011-07-26 02:11:41 +0000938 fontStream->insertInt("Length1", fontSize);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000939 descriptor->insert("FontFile2",
940 new SkPDFObjRef(fontStream.get()))->unref();
941 break;
942 }
943 case SkAdvancedTypefaceMetrics::kCFF_Font:
944 case SkAdvancedTypefaceMetrics::kType1CID_Font: {
945 SkRefPtr<SkStream> fontData =
946 SkFontHost::OpenStream(SkTypeface::UniqueID(typeface()));
947 fontData->unref(); // SkRefPtr and OpenStream both took a ref.
948 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
949 // SkRefPtr and new both ref()'d fontStream, pass one.
950 addResource(fontStream.get());
951
952 if (getType() == SkAdvancedTypefaceMetrics::kCFF_Font) {
953 fontStream->insertName("Subtype", "Type1C");
954 } else {
955 fontStream->insertName("Subtype", "CIDFontType0c");
956 }
957 descriptor->insert("FontFile3",
958 new SkPDFObjRef(fontStream.get()))->unref();
959 break;
960 }
961 default:
962 SkASSERT(false);
963 }
964
965 addResource(descriptor.get());
966 descriptor->ref();
967
968 insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
969 return addCommonFontDescriptorEntries(defaultWidth);
970}
971
972bool SkPDFCIDFont::populate(const SkPDFGlyphSet* subset) {
973 insertName("BaseFont", fontInfo()->fFontName);
974
975 if (getType() == SkAdvancedTypefaceMetrics::kType1CID_Font) {
reed@google.comc789cf12011-07-20 12:14:33 +0000976 insertName("Subtype", "CIDFontType0");
vandebo@chromium.org98594282011-07-25 22:34:12 +0000977 } else if (getType() == SkAdvancedTypefaceMetrics::kTrueType_Font) {
reed@google.comc789cf12011-07-20 12:14:33 +0000978 insertName("Subtype", "CIDFontType2");
979 insertName("CIDToGIDMap", "Identity");
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000980 } else {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000981 SkASSERT(false);
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000982 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000983
984 SkRefPtr<SkPDFDict> sysInfo = new SkPDFDict;
985 sysInfo->unref(); // SkRefPtr and new both took a reference.
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000986 sysInfo->insert("Registry", new SkPDFString("Adobe"))->unref();
987 sysInfo->insert("Ordering", new SkPDFString("Identity"))->unref();
reed@google.comc789cf12011-07-20 12:14:33 +0000988 sysInfo->insertInt("Supplement", 0);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000989 insert("CIDSystemInfo", sysInfo.get());
990
vandebo@chromium.org98594282011-07-25 22:34:12 +0000991 addFontDescriptor(0, subset);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000992
vandebo@chromium.org98594282011-07-25 22:34:12 +0000993 if (fontInfo()->fGlyphWidths.get()) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000994 int16_t defaultWidth = 0;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000995 SkRefPtr<SkPDFArray> widths =
vandebo@chromium.org98594282011-07-25 22:34:12 +0000996 composeAdvanceData(fontInfo()->fGlyphWidths.get(),
997 fontInfo()->fEmSize, &appendWidth,
998 &defaultWidth);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000999 widths->unref(); // SkRefPtr and compose both took a reference.
1000 if (widths->size())
1001 insert("W", widths.get());
1002 if (defaultWidth != 0) {
reed@google.comc789cf12011-07-20 12:14:33 +00001003 insertScalar("DW", scaleFromFontUnits(defaultWidth,
vandebo@chromium.org98594282011-07-25 22:34:12 +00001004 fontInfo()->fEmSize));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001005 }
1006 }
vandebo@chromium.org98594282011-07-25 22:34:12 +00001007 if (fontInfo()->fVerticalMetrics.get()) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001008 struct SkAdvancedTypefaceMetrics::VerticalMetric defaultAdvance;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001009 defaultAdvance.fVerticalAdvance = 0;
1010 defaultAdvance.fOriginXDisp = 0;
1011 defaultAdvance.fOriginYDisp = 0;
1012 SkRefPtr<SkPDFArray> advances =
vandebo@chromium.org98594282011-07-25 22:34:12 +00001013 composeAdvanceData(fontInfo()->fVerticalMetrics.get(),
1014 fontInfo()->fEmSize, &appendVerticalAdvance,
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001015 &defaultAdvance);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001016 advances->unref(); // SkRefPtr and compose both took a ref.
1017 if (advances->size())
1018 insert("W2", advances.get());
1019 if (defaultAdvance.fVerticalAdvance ||
1020 defaultAdvance.fOriginXDisp ||
1021 defaultAdvance.fOriginYDisp) {
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +00001022 insert("DW2", appendVerticalAdvance(defaultAdvance,
vandebo@chromium.org98594282011-07-25 22:34:12 +00001023 fontInfo()->fEmSize,
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +00001024 new SkPDFArray))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001025 }
1026 }
vandebo@chromium.org98594282011-07-25 22:34:12 +00001027
1028 return true;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001029}
1030
vandebo@chromium.org98594282011-07-25 22:34:12 +00001031///////////////////////////////////////////////////////////////////////////////
1032// class SkPDFType1Font
1033///////////////////////////////////////////////////////////////////////////////
1034
1035SkPDFType1Font::SkPDFType1Font(SkAdvancedTypefaceMetrics* info,
1036 SkTypeface* typeface,
1037 uint16_t glyphID,
1038 SkPDFDict* relatedFontDescriptor)
1039 : SkPDFFont(info, typeface, glyphID, false) {
1040 populate(glyphID);
1041}
1042
1043SkPDFType1Font::~SkPDFType1Font() {}
1044
1045bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
1046 SkRefPtr<SkPDFDict> descriptor = getFontDescriptor();
1047 if (descriptor.get() != NULL) {
1048 addResource(descriptor.get());
1049 descriptor->ref();
1050 insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
1051 return true;
1052 }
1053
1054 descriptor = new SkPDFDict("FontDescriptor");
1055 descriptor->unref(); // SkRefPtr and new both took a ref.
1056 setFontDescriptor(descriptor.get());
1057
1058 size_t header SK_INIT_TO_AVOID_WARNING;
1059 size_t data SK_INIT_TO_AVOID_WARNING;
1060 size_t trailer SK_INIT_TO_AVOID_WARNING;
1061 SkRefPtr<SkStream> rawFontData =
1062 SkFontHost::OpenStream(SkTypeface::UniqueID(typeface()));
1063 rawFontData->unref(); // SkRefPtr and OpenStream both took a ref.
1064 SkStream* fontData = handleType1Stream(rawFontData.get(), &header, &data,
1065 &trailer);
1066 if (fontData == NULL) {
1067 return false;
1068 }
1069 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData);
1070 // SkRefPtr and new both ref()'d fontStream, pass one.
1071 addResource(fontStream.get());
1072 fontStream->insertInt("Length1", header);
1073 fontStream->insertInt("Length2", data);
1074 fontStream->insertInt("Length3", trailer);
1075 descriptor->insert("FontFile", new SkPDFObjRef(fontStream.get()))->unref();
1076
1077 addResource(descriptor.get());
1078 descriptor->ref();
1079 insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
1080
1081 return addCommonFontDescriptorEntries(defaultWidth);
1082}
1083
1084bool SkPDFType1Font::populate(int16_t glyphID) {
1085 SkASSERT(!fontInfo()->fVerticalMetrics.get());
1086 SkASSERT(fontInfo()->fGlyphWidths.get());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001087
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001088 adjustGlyphRangeForSingleByteEncoding(glyphID);
1089
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001090 int16_t defaultWidth = 0;
1091 const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry = NULL;
1092 const SkAdvancedTypefaceMetrics::WidthRange* widthEntry;
vandebo@chromium.org98594282011-07-25 22:34:12 +00001093 for (widthEntry = fontInfo()->fGlyphWidths.get();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001094 widthEntry != NULL;
1095 widthEntry = widthEntry->fNext.get()) {
1096 switch (widthEntry->fType) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001097 case SkAdvancedTypefaceMetrics::WidthRange::kDefault:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001098 defaultWidth = widthEntry->fAdvance[0];
1099 break;
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001100 case SkAdvancedTypefaceMetrics::WidthRange::kRun:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001101 SkASSERT(false);
1102 break;
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001103 case SkAdvancedTypefaceMetrics::WidthRange::kRange:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001104 SkASSERT(widthRangeEntry == NULL);
1105 widthRangeEntry = widthEntry;
1106 break;
1107 }
1108 }
1109
1110 if (!addFontDescriptor(defaultWidth))
1111 return false;
1112
reed@google.comc789cf12011-07-20 12:14:33 +00001113 insertName("Subtype", "Type1");
vandebo@chromium.org98594282011-07-25 22:34:12 +00001114 insertName("BaseFont", fontInfo()->fFontName);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00001115
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001116 addWidthInfoFromRange(defaultWidth, widthRangeEntry);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001117
1118 SkRefPtr<SkPDFDict> encoding = new SkPDFDict("Encoding");
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00001119 encoding->unref(); // SkRefPtr and new both took a reference.
1120 insert("Encoding", encoding.get());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001121
1122 SkRefPtr<SkPDFArray> encDiffs = new SkPDFArray;
1123 encDiffs->unref(); // SkRefPtr and new both took a reference.
1124 encoding->insert("Differences", encDiffs.get());
1125
vandebo@chromium.org98594282011-07-25 22:34:12 +00001126 encDiffs->reserve(lastGlyphID() - firstGlyphID() + 2);
reed@google.comc789cf12011-07-20 12:14:33 +00001127 encDiffs->appendInt(1);
vandebo@chromium.org98594282011-07-25 22:34:12 +00001128 for (int gID = firstGlyphID(); gID <= lastGlyphID(); gID++) {
1129 encDiffs->appendName(fontInfo()->fGlyphNames->get()[gID].c_str());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001130 }
1131
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001132 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00001133}
1134
vandebo@chromium.org98594282011-07-25 22:34:12 +00001135void SkPDFType1Font::addWidthInfoFromRange(
1136 int16_t defaultWidth,
1137 const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry) {
1138 SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
1139 widthArray->unref(); // SkRefPtr and new both took a ref.
1140 int firstChar = 0;
1141 if (widthRangeEntry) {
1142 const uint16_t emSize = fontInfo()->fEmSize;
1143 int startIndex = firstGlyphID() - widthRangeEntry->fStartId;
1144 int endIndex = startIndex + lastGlyphID() - firstGlyphID() + 1;
1145 if (startIndex < 0)
1146 startIndex = 0;
1147 if (endIndex > widthRangeEntry->fAdvance.count())
1148 endIndex = widthRangeEntry->fAdvance.count();
1149 if (widthRangeEntry->fStartId == 0) {
1150 appendWidth(widthRangeEntry->fAdvance[0], emSize, widthArray.get());
1151 } else {
1152 firstChar = startIndex + widthRangeEntry->fStartId;
1153 }
1154 for (int i = startIndex; i < endIndex; i++)
1155 appendWidth(widthRangeEntry->fAdvance[i], emSize, widthArray.get());
1156 } else {
1157 appendWidth(defaultWidth, 1000, widthArray.get());
1158 }
1159 insertInt("FirstChar", firstChar);
1160 insertInt("LastChar", firstChar + widthArray->size() - 1);
1161 insert("Widths", widthArray.get());
1162}
1163
1164///////////////////////////////////////////////////////////////////////////////
1165// class SkPDFType3Font
1166///////////////////////////////////////////////////////////////////////////////
1167
1168SkPDFType3Font::SkPDFType3Font(SkAdvancedTypefaceMetrics* info,
1169 SkTypeface* typeface,
1170 uint16_t glyphID,
1171 SkPDFDict* relatedFontDescriptor)
1172 : SkPDFFont(info, typeface, glyphID, false) {
1173 populate(glyphID);
1174}
1175
1176SkPDFType3Font::~SkPDFType3Font() {}
1177
1178bool SkPDFType3Font::populate(int16_t glyphID) {
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001179 SkPaint paint;
vandebo@chromium.org98594282011-07-25 22:34:12 +00001180 paint.setTypeface(typeface());
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001181 paint.setTextSize(1000);
1182 SkAutoGlyphCache autoCache(paint, NULL);
1183 SkGlyphCache* cache = autoCache.getCache();
1184 // If fLastGlyphID isn't set (because there is not fFontInfo), look it up.
vandebo@chromium.org98594282011-07-25 22:34:12 +00001185 if (lastGlyphID() == 0) {
1186 setLastGlyphID(cache->getGlyphCount() - 1);
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001187 }
1188
1189 adjustGlyphRangeForSingleByteEncoding(glyphID);
1190
reed@google.comc789cf12011-07-20 12:14:33 +00001191 insertName("Subtype", "Type3");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001192 // Flip about the x-axis and scale by 1/1000.
1193 SkMatrix fontMatrix;
1194 fontMatrix.setScale(SkScalarInvert(1000), -SkScalarInvert(1000));
1195 insert("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix))->unref();
1196
1197 SkRefPtr<SkPDFDict> charProcs = new SkPDFDict;
1198 charProcs->unref(); // SkRefPtr and new both took a reference.
1199 insert("CharProcs", charProcs.get());
1200
1201 SkRefPtr<SkPDFDict> encoding = new SkPDFDict("Encoding");
1202 encoding->unref(); // SkRefPtr and new both took a reference.
1203 insert("Encoding", encoding.get());
1204
1205 SkRefPtr<SkPDFArray> encDiffs = new SkPDFArray;
1206 encDiffs->unref(); // SkRefPtr and new both took a reference.
1207 encoding->insert("Differences", encDiffs.get());
vandebo@chromium.org98594282011-07-25 22:34:12 +00001208 encDiffs->reserve(lastGlyphID() - firstGlyphID() + 2);
reed@google.comc789cf12011-07-20 12:14:33 +00001209 encDiffs->appendInt(1);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001210
1211 SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
1212 widthArray->unref(); // SkRefPtr and new both took a ref.
1213
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001214 SkIRect bbox = SkIRect::MakeEmpty();
vandebo@chromium.org98594282011-07-25 22:34:12 +00001215 for (int gID = firstGlyphID(); gID <= lastGlyphID(); gID++) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001216 SkString characterName;
1217 characterName.printf("gid%d", gID);
reed@google.comc789cf12011-07-20 12:14:33 +00001218 encDiffs->appendName(characterName.c_str());
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001219
reed@google.comce11b262011-03-21 21:25:35 +00001220 const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
reed@google.comc789cf12011-07-20 12:14:33 +00001221 widthArray->appendScalar(SkFixedToScalar(glyph.fAdvanceX));
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001222 SkIRect glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
1223 glyph.fWidth, glyph.fHeight);
1224 bbox.join(glyphBBox);
1225
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +00001226 SkDynamicMemoryWStream content;
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001227 setGlyphWidthAndBoundingBox(SkFixedToScalar(glyph.fAdvanceX), glyphBBox,
1228 &content);
1229 const SkPath* path = cache->findPath(glyph);
1230 if (path) {
1231 SkPDFUtils::EmitPath(*path, &content);
1232 SkPDFUtils::PaintPath(paint.getStyle(), path->getFillType(),
1233 &content);
1234 }
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +00001235 SkRefPtr<SkMemoryStream> glyphStream = new SkMemoryStream();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001236 glyphStream->unref(); // SkRefPtr and new both took a ref.
reed@google.com8a85d0c2011-06-24 19:12:12 +00001237 glyphStream->setData(content.copyToData())->unref();
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +00001238
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001239 SkRefPtr<SkPDFStream> glyphDescription =
1240 new SkPDFStream(glyphStream.get());
1241 // SkRefPtr and new both ref()'d charProcs, pass one.
vandebo@chromium.org98594282011-07-25 22:34:12 +00001242 addResource(glyphDescription.get());
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001243 charProcs->insert(characterName.c_str(),
1244 new SkPDFObjRef(glyphDescription.get()))->unref();
1245 }
1246
1247 insert("FontBBox", makeFontBBox(bbox, 1000))->unref();
vandebo@chromium.org98594282011-07-25 22:34:12 +00001248 insertInt("FirstChar", firstGlyphID());
1249 insertInt("LastChar", lastGlyphID());
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001250 insert("Widths", widthArray.get());
reed@google.comc789cf12011-07-20 12:14:33 +00001251 insertName("CIDToGIDMap", "Identity");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001252
vandebo@chromium.org98594282011-07-25 22:34:12 +00001253 populateToUnicodeTable(NULL);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001254 return true;
1255}