blob: e39530c685d448704e5887a63c151866d18ed77e [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
19#include "SkFontHost.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000020#include "SkPaint.h"
21#include "SkPDFFont.h"
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000022#include "SkPDFStream.h"
23#include "SkPDFTypefaceInfo.h"
24#include "SkPDFTypes.h"
25#include "SkStream.h"
26#include "SkTypeface.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000027#include "SkUtils.h"
28
29namespace {
30
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000031bool parsePFBSection(const uint8_t** src, size_t* len, int sectionType,
32 size_t* size) {
33 // PFB sections have a two or six bytes header. 0x80 and a one byte
34 // section type followed by a four byte section length. Type one is
35 // an ASCII section (includes a length), type two is a binary section
36 // (includes a length) and type three is an EOF marker with no length.
37 const uint8_t* buf = *src;
38 if (*len < 2 || buf[0] != 0x80 || buf[1] != sectionType)
39 return false;
40 if (buf[1] == 3)
41 return true;
42 if (*len < 6)
43 return false;
44
45 *size = buf[2] | (buf[3] << 8) | (buf[4] << 16) | (buf[5] << 24);
46 size_t consumed = *size + 6;
47 if (consumed > *len)
48 return false;
49 *src = *src + consumed;
50 *len = *len - consumed;
51 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000052}
53
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000054bool parsePFB(const uint8_t* src, size_t size, size_t* headerLen,
55 size_t* dataLen, size_t* trailerLen) {
56 const uint8_t* srcPtr = src;
57 size_t remaining = size;
58
59 return parsePFBSection(&srcPtr, &remaining, 1, headerLen) &&
60 parsePFBSection(&srcPtr, &remaining, 2, dataLen) &&
61 parsePFBSection(&srcPtr, &remaining, 1, trailerLen) &&
62 parsePFBSection(&srcPtr, &remaining, 3, NULL);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000063}
64
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000065/* The sections of a PFA file are implicitly defined. The body starts
66 * after the line containing "eexec," and the trailer starts with 512
67 * literal 0's followed by "cleartomark" (plus arbitrary white space).
68 *
69 * This function assumes that src is NUL terminated, but the NUL
70 * termination is not included in size.
71 *
72 */
73bool parsePFA(const char* src, size_t size, size_t* headerLen,
74 size_t* hexDataLen, size_t* dataLen, size_t* trailerLen) {
75 const char* end = src + size;
76
77 const char* dataPos = strstr(src, "eexec");
78 if (!dataPos)
79 return false;
80 dataPos += strlen("eexec");
81 while ((*dataPos == '\n' || *dataPos == '\r' || *dataPos == ' ') &&
82 dataPos < end)
83 dataPos++;
84 *headerLen = dataPos - src;
85
86 const char* trailerPos = strstr(dataPos, "cleartomark");
87 if (!trailerPos)
88 return false;
89 int zeroCount = 0;
90 for (trailerPos--; trailerPos > dataPos && zeroCount < 512; trailerPos--) {
91 if (*trailerPos == '\n' || *trailerPos == '\r' || *trailerPos == ' ') {
92 continue;
93 } else if (*trailerPos == '0') {
94 zeroCount++;
95 } else {
96 return false;
97 }
98 }
99 if (zeroCount != 512)
100 return false;
101
102 *hexDataLen = trailerPos - src - *headerLen;
103 *trailerLen = size - *headerLen - *hexDataLen;
104
105 // Verify that the data section is hex encoded and count the bytes.
106 int nibbles = 0;
107 for (; dataPos < trailerPos; dataPos++) {
108 if (isspace(*dataPos))
109 continue;
110 if (!isxdigit(*dataPos))
111 return false;
112 nibbles++;
113 }
114 *dataLen = (nibbles + 1) / 2;
115
116 return true;
117}
118
119int8_t hexToBin(uint8_t c) {
120 if (!isxdigit(c))
121 return -1;
122 if (c <= '9') return c - '0';
123 if (c <= 'F') return c - 'A' + 10;
124 if (c <= 'f') return c - 'a' + 10;
125 return -1;
126}
127
128SkStream* handleType1Stream(SkStream* srcStream, size_t* headerLen,
129 size_t* dataLen, size_t* trailerLen) {
130 // srcStream may be backed by a file or a unseekable fd, so we may not be
131 // able to use skip(), rewind(), or getMemoryBase(). read()ing through
132 // the input only once is doable, but very ugly. Furthermore, it'd be nice
133 // if the data was NUL terminated so that we can use strstr() to search it.
134 // Make as few copies as possible given these constraints.
135 SkDynamicMemoryWStream dynamicStream;
136 SkRefPtr<SkMemoryStream> staticStream;
137 const uint8_t* src;
138 size_t srcLen;
139 if ((srcLen = srcStream->getLength()) > 0) {
140 staticStream = new SkMemoryStream(srcLen + 1);
141 staticStream->unref(); // new and SkRefPtr both took a ref.
142 src = (const uint8_t*)staticStream->getMemoryBase();
143 if (srcStream->getMemoryBase() != NULL) {
144 memcpy((void *)src, srcStream->getMemoryBase(), srcLen);
145 } else {
146 size_t read = 0;
147 while (read < srcLen) {
148 size_t got = srcStream->read((void *)staticStream->getAtPos(),
149 srcLen - read);
150 if (got == 0)
151 return NULL;
152 read += got;
153 staticStream->seek(read);
154 }
155 }
156 ((uint8_t *)src)[srcLen] = 0;
157 } else {
158 static const size_t bufSize = 4096;
159 uint8_t buf[bufSize];
160 size_t amount;
161 while ((amount = srcStream->read(buf, bufSize)) > 0)
162 dynamicStream.write(buf, amount);
163 amount = 0;
164 dynamicStream.write(&amount, 1); // NULL terminator.
165 // getStream makes another copy, but we couldn't do any better.
166 src = (const uint8_t*)dynamicStream.getStream();
167 srcLen = dynamicStream.getOffset() - 1;
168 }
169
170 if (parsePFB(src, srcLen, headerLen, dataLen, trailerLen)) {
171 SkMemoryStream* result =
172 new SkMemoryStream(*headerLen + *dataLen + *trailerLen);
173 memcpy((char*)result->getAtPos(), src + 6, *headerLen);
174 result->seek(*headerLen);
175 memcpy((char*)result->getAtPos(), src + 6 + *headerLen + 6, *dataLen);
176 result->seek(*headerLen + *dataLen);
177 memcpy((char*)result->getAtPos(), src + 6 + *headerLen + 6 + *dataLen,
178 *trailerLen);
179 result->rewind();
180 return result;
181 }
182
183 // A PFA has to be converted for PDF.
184 size_t hexDataLen;
185 if (parsePFA((const char*)src, srcLen, headerLen, &hexDataLen, dataLen,
186 trailerLen)) {
187 SkMemoryStream* result =
188 new SkMemoryStream(*headerLen + *dataLen + *trailerLen);
189 memcpy((char*)result->getAtPos(), src, *headerLen);
190 result->seek(*headerLen);
191
192 const uint8_t* hexData = src + *headerLen;
193 const uint8_t* trailer = hexData + hexDataLen;
194 size_t outputOffset = 0;
195 uint8_t dataByte;
196 bool highNibble = true;
197 for (; hexData < trailer; hexData++) {
198 char curNibble = hexToBin(*hexData);
199 if (curNibble < 0)
200 continue;
201 if (highNibble) {
202 dataByte = curNibble << 4;
203 highNibble = false;
204 } else {
205 dataByte |= curNibble;
206 highNibble = true;
207 ((char *)result->getAtPos())[outputOffset++] = dataByte;
208 }
209 }
210 if (!highNibble)
211 ((char *)result->getAtPos())[outputOffset++] = dataByte;
212 SkASSERT(outputOffset == *dataLen);
213 result->seek(*headerLen + outputOffset);
214
215 memcpy((char *)result->getAtPos(), src + *headerLen + hexDataLen,
216 *trailerLen);
217 result->rewind();
218 return result;
219 }
220
221 return NULL;
222}
223
224void appendWidth(const int& width, SkPDFArray* array) {
225 SkRefPtr<SkPDFInt> widthInt = new SkPDFInt(width);
226 widthInt->unref(); // SkRefPtr and new both took a reference.
227 array->append(widthInt.get());
228}
229
230void appendVerticalAdvance(const SkPDFTypefaceInfo::VerticalMetric& advance,
231 SkPDFArray* array) {
232 appendWidth(advance.fVerticalAdvance, array);
233 appendWidth(advance.fOriginXDisp, array);
234 appendWidth(advance.fOriginYDisp, array);
235}
236
237template <typename Data>
238SkPDFArray* composeAdvanceData(
239 SkPDFTypefaceInfo::AdvanceMetric<Data>* advanceInfo,
240 void (*appendAdvance)(const Data& advance, SkPDFArray* array),
241 Data* defaultAdvance) {
242 SkPDFArray* result = new SkPDFArray();
243 for (; advanceInfo != NULL; advanceInfo = advanceInfo->fNext.get()) {
244 switch (advanceInfo->fType) {
245 case SkPDFTypefaceInfo::WidthRange::kDefault: {
246 SkASSERT(advanceInfo->fAdvance.count() == 1);
247 *defaultAdvance = advanceInfo->fAdvance[0];
248 break;
249 }
250 case SkPDFTypefaceInfo::WidthRange::kRange: {
251 SkRefPtr<SkPDFArray> advanceArray = new SkPDFArray();
252 advanceArray->unref(); // SkRefPtr and new both took a ref.
253 for (int j = 0; j < advanceInfo->fAdvance.count(); j++)
254 appendAdvance(advanceInfo->fAdvance[j], advanceArray.get());
255 SkRefPtr<SkPDFInt> rangeStart =
256 new SkPDFInt(advanceInfo->fStartId);
257 rangeStart->unref(); // SkRefPtr and new both took a reference.
258 result->append(rangeStart.get());
259 result->append(advanceArray.get());
260 break;
261 }
262 case SkPDFTypefaceInfo::WidthRange::kRun: {
263 SkASSERT(advanceInfo->fAdvance.count() == 1);
264 SkRefPtr<SkPDFInt> rangeStart =
265 new SkPDFInt(advanceInfo->fStartId);
266 rangeStart->unref(); // SkRefPtr and new both took a reference.
267 result->append(rangeStart.get());
268
269 SkRefPtr<SkPDFInt> rangeEnd = new SkPDFInt(advanceInfo->fEndId);
270 rangeEnd->unref(); // SkRefPtr and new both took a reference.
271 result->append(rangeEnd.get());
272
273 appendAdvance(advanceInfo->fAdvance[0], result);
274 break;
275 }
276 }
277 }
278 return result;
279}
280
281} // namespace
282
283/* Font subset design: It would be nice to be able to subset fonts
284 * (particularly type 3 fonts), but it's a lot of work and not a priority.
285 *
286 * Resources are canonicalized and uniqueified by pointer so there has to be
287 * some additional state indicating which subset of the font is used. It
288 * must be maintained at the page granularity and then combined at the document
289 * granularity. a) change SkPDFFont to fill in its state on demand, kind of
290 * like SkPDFGraphicState. b) maintain a per font glyph usage class in each
291 * page/pdf device. c) in the document, retrieve the per font glyph usage
292 * from each page and combine it and ask for a resource with that subset.
293 */
294
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000295SkPDFFont::~SkPDFFont() {
296 SkAutoMutexAcquire lock(canonicalFontsMutex());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000297 int index;
298 if (find(fFontID, fFirstGlyphID, &index)) {
299 canonicalFonts().removeShuffle(index);
300#ifdef SK_DEBUG
301 SkASSERT(!fDescendant);
302 } else {
303 SkASSERT(fDescendant);
304#endif
305 }
306 fResources.unrefAll();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000307}
308
309void SkPDFFont::getResources(SkTDArray<SkPDFObject*>* resourceList) {
310 resourceList->setReserve(resourceList->count() + fResources.count());
311 for (int i = 0; i < fResources.count(); i++) {
312 resourceList->push(fResources[i]);
313 fResources[i]->ref();
314 fResources[i]->getResources(resourceList);
315 }
316}
317
318uint32_t SkPDFFont::fontID() {
319 return fFontID;
320}
321
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000322bool SkPDFFont::hasGlyph(uint16_t id) {
323 return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0;
324}
325
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000326bool SkPDFFont::multiByteGlyphs() {
327 return fMultiByteGlyphs;
328}
329
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000330size_t SkPDFFont::glyphsToPDFFontEncoding(const uint16_t* glyphIDs,
331 size_t numGlyphs, void* encodedValues,
332 size_t* encodedLength) {
333 if (numGlyphs * 2 > *encodedLength)
334 numGlyphs = *encodedLength / 2;
335
336 // A font with multibyte glyphs will support all glyph IDs in a single font,
337 // shortcut if we can.
338 if (fMultiByteGlyphs) {
339 *encodedLength = numGlyphs * 2;
340 memcpy(encodedValues, glyphIDs, *encodedLength);
341 } else {
342 char* output = (char*) encodedValues;
343 for (size_t i = 0; i < numGlyphs; i++) {
344 if (glyphIDs[i] == 0) {
345 output[i] = 0;
346 continue;
347 }
348 if (glyphIDs[i] < fFirstGlyphID || glyphIDs[i] > fLastGlyphID) {
349 numGlyphs = i;
350 break;
351 }
352 output[i] = glyphIDs[i] - fFirstGlyphID + 1;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000353 }
354 }
355
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000356 return numGlyphs;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000357}
358
359// static
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000360SkPDFFont* SkPDFFont::getFontResource(uint32_t fontID, uint16_t glyphID) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000361 SkAutoMutexAcquire lock(canonicalFontsMutex());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000362 int index;
363 if (find(fontID, glyphID, &index)) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000364 canonicalFonts()[index].fFont->ref();
365 return canonicalFonts()[index].fFont;
366 }
367
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000368 SkRefPtr<SkPDFTypefaceInfo> fontInfo;
369 SkPDFDict* fontDescriptor = NULL;
370 if (index >= 0) {
371 SkPDFFont* relatedFont = canonicalFonts()[index].fFont;
372 SkASSERT(relatedFont->fFontInfo.get());
373 fontInfo = relatedFont->fFontInfo;
374 fontDescriptor = relatedFont->fDescriptor.get();
375 } else {
376 fontInfo = SkFontHost::GetPDFTypefaceInfo(fontID);
377 fontInfo->unref(); // SkRefPtr and get info both took a reference.
378 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000379
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000380 SkPDFFont* font = new SkPDFFont(fontInfo.get(), fontID, glyphID, false,
381 fontDescriptor);
382 FontRec newEntry(font, fontID, font->fFirstGlyphID);
383 index = canonicalFonts().count();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000384 canonicalFonts().push(newEntry);
385 return font; // Return the reference new SkPDFFont() created.
386}
387
388// static
389SkTDArray<SkPDFFont::FontRec>& SkPDFFont::canonicalFonts() {
390 // This initialization is only thread safe with gcc.
391 static SkTDArray<FontRec> gCanonicalFonts;
392 return gCanonicalFonts;
393}
394
395// static
396SkMutex& SkPDFFont::canonicalFontsMutex() {
397 // This initialization is only thread safe with gcc.
398 static SkMutex gCanonicalFontsMutex;
399 return gCanonicalFontsMutex;
400}
401
402// static
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000403bool SkPDFFont::find(uint32_t fontID, uint16_t glyphID, int* index) {
404 // TODO(vandebo) optimize this, do only one search?
405 FontRec search(NULL, fontID, glyphID);
406 *index = canonicalFonts().find(search);
407 if (*index >= 0)
408 return true;
409 search.fGlyphID = 0;
410 *index = canonicalFonts().find(search);
411 return false;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000412}
413
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000414SkPDFFont::SkPDFFont(class SkPDFTypefaceInfo* fontInfo, uint32_t fontID,
415 uint16_t glyphID, bool descendantFont,
416 SkPDFDict* fontDescriptor)
417 : SkPDFDict("Font"),
418 fFontID(fontID),
419#ifdef SK_DEBUG
420 fDescendant(descendantFont),
421#endif
422 fMultiByteGlyphs(false),
423 fFirstGlyphID(1),
424 fLastGlyphID(fontInfo->fLastGlyphID),
425 fFontInfo(fontInfo),
426 fDescriptor(fontDescriptor) {
427
428 if (fontInfo->fMultiMaster) {
429 populateType3Font();
430 } else {
431 switch (fontInfo->fType) {
432 case SkPDFTypefaceInfo::kType1CID_Font:
433 case SkPDFTypefaceInfo::kTrueType_Font:
434 if (descendantFont)
435 populateCIDFont();
436 else
437 populateType0Font();
438 break;
439 case SkPDFTypefaceInfo::kType1_Font: {
440 uint16_t firstGlyphID = glyphID - (glyphID - 1) % 255;
441 uint16_t lastGlyphID = firstGlyphID + 255 - 1;
442 if (lastGlyphID > fLastGlyphID)
443 lastGlyphID = fLastGlyphID;
444 if (populateType1Font(firstGlyphID, lastGlyphID))
445 break;
446 // else, fall through.
447 }
448 case SkPDFTypefaceInfo::kOther_Font:
449 case SkPDFTypefaceInfo::kNotEmbeddable_Font:
450 populateType3Font();
451 break;
452 case SkPDFTypefaceInfo::kCFF_Font:
453 SkASSERT(false); // Not supported yet.
454 }
455 }
456
457 // Type1 fonts may hold on to the font info, otherwise we are done with it.
458 if (fontInfo->fType != SkPDFTypefaceInfo::kType1_Font)
459 fFontInfo = NULL;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000460}
461
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000462void SkPDFFont::populateType0Font() {
463 fMultiByteGlyphs = true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000464
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000465 SkRefPtr<SkPDFName> subType = new SkPDFName("Type0");
466 subType->unref(); // SkRefPtr and new both took a reference.
467 insert("Subtype", subType.get());
468
469 SkRefPtr<SkPDFName> baseFont = new SkPDFName(fFontInfo.get()->fFontName);
470 baseFont->unref(); // SkRefPtr and new both took a reference.
471 insert("BaseFont", baseFont.get());
472
473 SkRefPtr<SkPDFName> encoding = new SkPDFName("Identity-H");
474 encoding->unref(); // SkRefPtr and new both took a reference.
475 insert("Encoding", encoding.get());
476
477 // TODO(vandebo) add a ToUnicode mapping.
478
479 SkRefPtr<SkPDFFont> cidFont = new SkPDFFont(fFontInfo.get(),
480 fFontID, 1, true, NULL);
481 fResources.push(cidFont.get()); // 2 refs: SkRefPtr, new. Pass one.
482
483 SkRefPtr<SkPDFArray> descendantFonts = new SkPDFArray();
484 descendantFonts->unref(); // SkRefPtr and new took a reference.
485 SkRefPtr<SkPDFObjRef> cidFontRef = new SkPDFObjRef(cidFont.get());
486 cidFontRef->unref(); // SkRefPtr and new both took a reference.
487 descendantFonts->append(cidFontRef.get());
488 insert("DescendantFonts", descendantFonts.get());
489}
490
491void SkPDFFont::populateCIDFont() {
492 fMultiByteGlyphs = true;
493
494 SkRefPtr<SkPDFName> subType;
495 if (fFontInfo.get()->fType == SkPDFTypefaceInfo::kType1CID_Font)
496 subType = new SkPDFName("CIDFontType0");
497 else if (fFontInfo.get()->fType == SkPDFTypefaceInfo::kTrueType_Font)
498 subType = new SkPDFName("CIDFontType2");
499 else
500 SkASSERT(false);
501 subType->unref(); // SkRefPtr and new both took a reference.
502 insert("Subtype", subType.get());
503
504 SkRefPtr<SkPDFName> baseFont = new SkPDFName(fFontInfo.get()->fFontName);
505 baseFont->unref(); // SkRefPtr and new both took a reference.
506 insert("BaseFont", baseFont.get());
507
508 SkRefPtr<SkPDFDict> sysInfo = new SkPDFDict;
509 sysInfo->unref(); // SkRefPtr and new both took a reference.
510
511 SkRefPtr<SkPDFString> adobeString = new SkPDFString("Adobe");
512 adobeString->unref(); // SkRefPtr and new both took a reference.
513 sysInfo->insert("Registry", adobeString.get());
514
515 SkRefPtr<SkPDFString> identityString = new SkPDFString("Identity");
516 identityString->unref(); // SkRefPtr and new both took a reference.
517 sysInfo->insert("Ordering", identityString.get());
518
519 SkRefPtr<SkPDFInt> supplement = new SkPDFInt(0);
520 supplement->unref(); // SkRefPtr and new both took a reference.
521 sysInfo->insert("Supplement", supplement.get());
522
523 insert("CIDSystemInfo", sysInfo.get());
524
525 addFontDescriptor(0);
526
527 if (fFontInfo.get()->fGlyphWidths.get()) {
528 int defaultWidth = 0;
529 SkRefPtr<SkPDFArray> widths =
530 composeAdvanceData(fFontInfo.get()->fGlyphWidths.get(),
531 &appendWidth, &defaultWidth);
532 widths->unref(); // SkRefPtr and compose both took a reference.
533 if (widths->size())
534 insert("W", widths.get());
535 if (defaultWidth != 0) {
536 SkRefPtr<SkPDFInt> defaultWidthInt =
537 new SkPDFInt(defaultWidth);
538 // SkRefPtr and compose both took a reference.
539 defaultWidthInt->unref();
540 insert("DW", defaultWidthInt.get());
541 }
542 }
543 if (fFontInfo.get()->fVerticalMetrics.get()) {
544 struct SkPDFTypefaceInfo::VerticalMetric defaultAdvance;
545 defaultAdvance.fVerticalAdvance = 0;
546 defaultAdvance.fOriginXDisp = 0;
547 defaultAdvance.fOriginYDisp = 0;
548 SkRefPtr<SkPDFArray> advances =
549 composeAdvanceData(fFontInfo.get()->fVerticalMetrics.get(),
550 &appendVerticalAdvance, &defaultAdvance);
551 advances->unref(); // SkRefPtr and compose both took a ref.
552 if (advances->size())
553 insert("W2", advances.get());
554 if (defaultAdvance.fVerticalAdvance ||
555 defaultAdvance.fOriginXDisp ||
556 defaultAdvance.fOriginYDisp) {
557 SkRefPtr<SkPDFArray> defaultAdvanceArray = new SkPDFArray;
558 // SkRefPtr and compose both took a reference.
559 defaultAdvanceArray->unref();
560 appendVerticalAdvance(defaultAdvance,
561 defaultAdvanceArray.get());
562 insert("DW2", defaultAdvanceArray.get());
563 }
564 }
565}
566
567bool SkPDFFont::populateType1Font(uint16_t firstGlyphID, uint16_t lastGlyphID) {
568 SkASSERT(!fFontInfo.get()->fVerticalMetrics.get());
569 SkASSERT(fFontInfo.get()->fGlyphWidths.get());
570
571 int defaultWidth = 0;
572 const SkPDFTypefaceInfo::WidthRange* widthRangeEntry = NULL;
573 const SkPDFTypefaceInfo::WidthRange* widthEntry;
574 for (widthEntry = fFontInfo.get()->fGlyphWidths.get();
575 widthEntry != NULL;
576 widthEntry = widthEntry->fNext.get()) {
577 switch (widthEntry->fType) {
578 case SkPDFTypefaceInfo::WidthRange::kDefault:
579 defaultWidth = widthEntry->fAdvance[0];
580 break;
581 case SkPDFTypefaceInfo::WidthRange::kRun:
582 SkASSERT(false);
583 break;
584 case SkPDFTypefaceInfo::WidthRange::kRange:
585 SkASSERT(widthRangeEntry == NULL);
586 widthRangeEntry = widthEntry;
587 break;
588 }
589 }
590
591 if (!addFontDescriptor(defaultWidth))
592 return false;
593
594 fFirstGlyphID = firstGlyphID;
595 fLastGlyphID = lastGlyphID;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000596
597 SkRefPtr<SkPDFName> subType = new SkPDFName("Type1");
598 subType->unref(); // SkRefPtr and new both took a reference.
599 insert("Subtype", subType.get());
600
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000601 SkRefPtr<SkPDFName> baseFont = new SkPDFName(fFontInfo.get()->fFontName);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000602 baseFont->unref(); // SkRefPtr and new both took a reference.
603 insert("BaseFont", baseFont.get());
604
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000605 SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
606 widthArray->unref(); // SkRefPtr and new both took a ref.
607 int firstChar = 0;
608 if (widthRangeEntry) {
609 int startIndex = firstGlyphID - widthRangeEntry->fStartId;
610 int endIndex = startIndex + lastGlyphID - firstGlyphID + 1;
611 if (startIndex < 0)
612 startIndex = 0;
613 if (endIndex > widthRangeEntry->fAdvance.count())
614 endIndex = widthRangeEntry->fAdvance.count();
615 if (widthRangeEntry->fStartId == 0) {
616 appendWidth(widthRangeEntry->fAdvance[0], widthArray.get());
617 } else {
618 firstChar = startIndex + widthRangeEntry->fStartId;
619 }
620 for (int i = startIndex; i < endIndex; i++)
621 appendWidth(widthRangeEntry->fAdvance[i], widthArray.get());
622 } else {
623 appendWidth(defaultWidth, widthArray.get());
624 }
625 insert("Widths", widthArray.get());
626
627 SkRefPtr<SkPDFInt> firstCharInt = new SkPDFInt(firstChar);
628 firstCharInt->unref(); // SkRefPtr and new both took a reference.
629 insert("FirstChar", firstCharInt.get());
630
631 SkRefPtr<SkPDFInt> lastChar =
632 new SkPDFInt(firstChar + widthArray->size() - 1);
633 lastChar->unref(); // SkRefPtr and new both took a reference.
634 insert("LastChar", lastChar.get());
635
636 SkRefPtr<SkPDFDict> encoding = new SkPDFDict("Encoding");
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000637 encoding->unref(); // SkRefPtr and new both took a reference.
638 insert("Encoding", encoding.get());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000639
640 SkRefPtr<SkPDFArray> encDiffs = new SkPDFArray;
641 encDiffs->unref(); // SkRefPtr and new both took a reference.
642 encoding->insert("Differences", encDiffs.get());
643
644 encDiffs->reserve(fLastGlyphID - fFirstGlyphID + 2);
645 SkRefPtr<SkPDFInt> startID = new SkPDFInt(1);
646 startID->unref(); // SkRefPtr and new both took a reference.
647 encDiffs->append(startID.get());
648 for (int gID = fFirstGlyphID; gID <= fLastGlyphID; gID++) {
649 SkRefPtr<SkPDFName> glyphName =
650 new SkPDFName(fFontInfo.get()->fGlyphNames->get()[gID]);
651 glyphName->unref(); // SkRefPtr and new both took a reference.
652 encDiffs->append(glyphName.get());
653 }
654
655 if (fFontInfo.get()->fLastGlyphID <= 255)
656 fFontInfo = NULL;
657 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000658}
659
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000660void SkPDFFont::populateType3Font() {
661 // TODO(vandebo)
662 SkASSERT(false);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000663}
664
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000665bool SkPDFFont::addFontDescriptor(int defaultWidth) {
666 if (fDescriptor.get() != NULL) {
667 fResources.push(fDescriptor.get());
668 fDescriptor->ref();
669 SkRefPtr<SkPDFObjRef> descRef = new SkPDFObjRef(fDescriptor.get());
670 descRef->unref(); // SkRefPtr and new both took a reference.
671 insert("FontDescriptor", descRef.get());
672 return true;
673 }
674
675 fDescriptor = new SkPDFDict("FontDescriptor");
676 fDescriptor->unref(); // SkRefPtr and new both took a ref.
677
678 switch (fFontInfo.get()->fType) {
679 case SkPDFTypefaceInfo::kType1_Font: {
680 size_t header, data, trailer;
681 SkRefPtr<SkStream> rawFontData =
682 SkFontHost::OpenStream(fFontID);
683 rawFontData->unref(); // SkRefPtr and OpenStream both took a ref.
684 SkStream* fontData = handleType1Stream(rawFontData.get(), &header,
685 &data, &trailer);
686 if (fontData == NULL)
687 return false;
688 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData);
689 // SkRefPtr and new both ref()'d fontStream, pass one.
690 fResources.push(fontStream.get());
691
692 SkRefPtr<SkPDFInt> headerLen = new SkPDFInt(header);
693 headerLen->unref(); // SkRefPtr and new both took a reference.
694 fontStream->insert("Length1", headerLen.get());
695 SkRefPtr<SkPDFInt> dataLen = new SkPDFInt(data);
696 dataLen->unref(); // SkRefPtr and new both took a reference.
697 fontStream->insert("Length2", dataLen.get());
698 SkRefPtr<SkPDFInt> trailerLen = new SkPDFInt(trailer);
699 trailerLen->unref(); // SkRefPtr and new both took a reference.
700 fontStream->insert("Length3", trailerLen.get());
701
702 SkRefPtr<SkPDFObjRef> streamRef = new SkPDFObjRef(fontStream.get());
703 streamRef->unref(); // SkRefPtr and new both took a reference.
704 fDescriptor->insert("FontFile", streamRef.get());
705 break;
706 }
707 case SkPDFTypefaceInfo::kTrueType_Font: {
708 SkRefPtr<SkStream> fontData = SkFontHost::OpenStream(fFontID);
709 fontData->unref(); // SkRefPtr and OpenStream both took a ref.
710 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
711 // SkRefPtr and new both ref()'d fontStream, pass one.
712 fResources.push(fontStream.get());
713
714 SkRefPtr<SkPDFInt> length = new SkPDFInt(fontData->getLength());
715 length->unref(); // SkRefPtr and new both took a reference.
716 fontStream->insert("Length1", length.get());
717
718 SkRefPtr<SkPDFObjRef> streamRef = new SkPDFObjRef(fontStream.get());
719 streamRef->unref(); // SkRefPtr and new both took a reference.
720 fDescriptor->insert("FontFile2", streamRef.get());
721 break;
722 }
723 case SkPDFTypefaceInfo::kCFF_Font:
724 case SkPDFTypefaceInfo::kType1CID_Font: {
725 SkRefPtr<SkStream> fontData = SkFontHost::OpenStream(fFontID);
726 fontData->unref(); // SkRefPtr and OpenStream both took a ref.
727 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
728 // SkRefPtr and new both ref()'d fontStream, pass one.
729 fResources.push(fontStream.get());
730
731 SkRefPtr<SkPDFName> subtype;
732 if (fFontInfo.get()->fType == SkPDFTypefaceInfo::kCFF_Font)
733 subtype = new SkPDFName("Type1C");
734 else
735 subtype = new SkPDFName("CIDFontType0c");
736 subtype->unref(); // SkRefPtr and new both took a reference.
737 fontStream->insert("Subtype", subtype.get());
738
739 SkRefPtr<SkPDFObjRef> streamRef = new SkPDFObjRef(fontStream.get());
740 streamRef->unref(); // SkRefPtr and new both took a reference.
741 fDescriptor->insert("FontFile3", streamRef.get());
742 break;
743 }
744 default:
745 SkASSERT(false);
746 }
747
748 fResources.push(fDescriptor.get());
749 fDescriptor->ref();
750 SkRefPtr<SkPDFObjRef> descRef = new SkPDFObjRef(fDescriptor.get());
751 descRef->unref(); // SkRefPtr and new both took a reference.
752 insert("FontDescriptor", descRef.get());
753
754 SkRefPtr<SkPDFName> fontName =
755 new SkPDFName(fFontInfo.get()->fFontName);
756 fontName->unref(); // SkRefPtr and new both took a reference.
757 fDescriptor->insert("FontName", fontName.get());
758
759 SkRefPtr<SkPDFInt> flags = new SkPDFInt(fFontInfo.get()->fStyle);
760 flags->unref(); // SkRefPtr and new both took a reference.
761 fDescriptor->insert("Flags", flags.get());
762
763 SkIRect glyphBBox = fFontInfo.get()->fBBox;
764 SkRefPtr<SkPDFArray> bbox = new SkPDFArray;
765 bbox->unref(); // SkRefPtr and new both took a reference.
766 bbox->reserve(4);
767 SkRefPtr<SkPDFInt> bboxXMin = new SkPDFInt(glyphBBox.fLeft);
768 bboxXMin->unref(); // SkRefPtr and new both took a reference.
769 bbox->append(bboxXMin.get());
770 SkRefPtr<SkPDFInt> bboxYMin = new SkPDFInt(glyphBBox.fBottom);
771 bboxYMin->unref(); // SkRefPtr and new both took a reference.
772 bbox->append(bboxYMin.get());
773 SkRefPtr<SkPDFInt> bboxXMax = new SkPDFInt(glyphBBox.fRight);
774 bboxXMax->unref(); // SkRefPtr and new both took a reference.
775 bbox->append(bboxXMax.get());
776 SkRefPtr<SkPDFInt> bboxYMax = new SkPDFInt(glyphBBox.fTop);
777 bboxYMax->unref(); // SkRefPtr and new both took a reference.
778 bbox->append(bboxYMax.get());
779 fDescriptor->insert("FontBBox", bbox.get());
780
781 SkRefPtr<SkPDFInt> italicAngle =
782 new SkPDFInt(fFontInfo.get()->fItalicAngle);
783 italicAngle->unref(); // SkRefPtr and new both took a reference.
784 fDescriptor->insert("ItalicAngle", italicAngle.get());
785
786 SkRefPtr<SkPDFScalar> ascent = new SkPDFScalar(fFontInfo.get()->fAscent);
787 ascent->unref(); // SkRefPtr and new both took a reference.
788 fDescriptor->insert("Ascent", ascent.get());
789
790 SkRefPtr<SkPDFScalar> descent = new SkPDFScalar(fFontInfo.get()->fDescent);
791 descent->unref(); // SkRefPtr and new both took a reference.
792 fDescriptor->insert("Descent", descent.get());
793
794 SkRefPtr<SkPDFScalar> capHeight =
795 new SkPDFScalar(fFontInfo.get()->fCapHeight);
796 capHeight->unref(); // SkRefPtr and new both took a reference.
797 fDescriptor->insert("CapHeight", capHeight.get());
798
799 SkRefPtr<SkPDFScalar> stemV = new SkPDFScalar(fFontInfo.get()->fStemV);
800 stemV->unref(); // SkRefPtr and new both took a reference.
801 fDescriptor->insert("StemV", stemV.get());
802
803 if (defaultWidth > 0) {
804 SkRefPtr<SkPDFInt> defaultWidthInt = new SkPDFInt(defaultWidth);
805 defaultWidthInt->unref(); // SkRefPtr and new both took a reference.
806 fDescriptor->insert("MissingWidth", defaultWidthInt.get());
807 }
808 return true;
809}
810
811
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000812bool SkPDFFont::FontRec::operator==(const SkPDFFont::FontRec& b) const {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000813 if (fFontID != b.fFontID)
814 return false;
815 if (fFont != NULL && b.fFont != NULL) {
816 return fFont->fFirstGlyphID == b.fFont->fFirstGlyphID &&
817 fFont->fLastGlyphID == b.fFont->fLastGlyphID;
818 }
819 if (fGlyphID == 0 || b.fGlyphID == 0)
820 return true;
821
822 if (fFont != NULL) {
823 return fFont->fFirstGlyphID <= b.fGlyphID &&
824 b.fGlyphID <= fFont->fLastGlyphID;
825 } else if (b.fFont != NULL) {
826 return b.fFont->fFirstGlyphID <= fGlyphID &&
827 fGlyphID <= b.fFont->fLastGlyphID;
828 }
829 return fGlyphID == b.fGlyphID;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000830}
831
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000832SkPDFFont::FontRec::FontRec(SkPDFFont* font, uint32_t fontID, uint16_t glyphID)
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000833 : fFont(font),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000834 fFontID(fontID),
835 fGlyphID(glyphID) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000836}