blob: f570a1f51aa3e762701e0c6b2e2519eecb6eb243 [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"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000020#include "SkGlyphCache.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000021#include "SkPaint.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000022#include "SkPDFDevice.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000023#include "SkPDFFont.h"
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000024#include "SkPDFStream.h"
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000025#include "SkPDFTypes.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000026#include "SkPDFUtils.h"
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +000027#include "SkRefCnt.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000028#include "SkScalar.h"
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000029#include "SkStream.h"
30#include "SkTypeface.h"
vandebo@chromium.org325cb9a2011-03-30 18:36:29 +000031#include "SkTypes.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000032#include "SkUtils.h"
33
34namespace {
35
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000036bool parsePFBSection(const uint8_t** src, size_t* len, int sectionType,
37 size_t* size) {
38 // PFB sections have a two or six bytes header. 0x80 and a one byte
39 // section type followed by a four byte section length. Type one is
40 // an ASCII section (includes a length), type two is a binary section
41 // (includes a length) and type three is an EOF marker with no length.
42 const uint8_t* buf = *src;
43 if (*len < 2 || buf[0] != 0x80 || buf[1] != sectionType)
44 return false;
45 if (buf[1] == 3)
46 return true;
47 if (*len < 6)
48 return false;
49
vandebo@chromium.org73322072011-06-21 21:19:41 +000050 *size = (size_t)buf[2] | ((size_t)buf[3] << 8) | ((size_t)buf[4] << 16) |
51 ((size_t)buf[5] << 24);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000052 size_t consumed = *size + 6;
53 if (consumed > *len)
54 return false;
55 *src = *src + consumed;
56 *len = *len - consumed;
57 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000058}
59
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000060bool parsePFB(const uint8_t* src, size_t size, size_t* headerLen,
61 size_t* dataLen, size_t* trailerLen) {
62 const uint8_t* srcPtr = src;
63 size_t remaining = size;
64
65 return parsePFBSection(&srcPtr, &remaining, 1, headerLen) &&
66 parsePFBSection(&srcPtr, &remaining, 2, dataLen) &&
67 parsePFBSection(&srcPtr, &remaining, 1, trailerLen) &&
68 parsePFBSection(&srcPtr, &remaining, 3, NULL);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000069}
70
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000071/* The sections of a PFA file are implicitly defined. The body starts
72 * after the line containing "eexec," and the trailer starts with 512
73 * literal 0's followed by "cleartomark" (plus arbitrary white space).
74 *
75 * This function assumes that src is NUL terminated, but the NUL
76 * termination is not included in size.
77 *
78 */
79bool parsePFA(const char* src, size_t size, size_t* headerLen,
80 size_t* hexDataLen, size_t* dataLen, size_t* trailerLen) {
81 const char* end = src + size;
82
83 const char* dataPos = strstr(src, "eexec");
84 if (!dataPos)
85 return false;
86 dataPos += strlen("eexec");
87 while ((*dataPos == '\n' || *dataPos == '\r' || *dataPos == ' ') &&
88 dataPos < end)
89 dataPos++;
90 *headerLen = dataPos - src;
91
92 const char* trailerPos = strstr(dataPos, "cleartomark");
93 if (!trailerPos)
94 return false;
95 int zeroCount = 0;
96 for (trailerPos--; trailerPos > dataPos && zeroCount < 512; trailerPos--) {
97 if (*trailerPos == '\n' || *trailerPos == '\r' || *trailerPos == ' ') {
98 continue;
99 } else if (*trailerPos == '0') {
100 zeroCount++;
101 } else {
102 return false;
103 }
104 }
105 if (zeroCount != 512)
106 return false;
107
108 *hexDataLen = trailerPos - src - *headerLen;
109 *trailerLen = size - *headerLen - *hexDataLen;
110
111 // Verify that the data section is hex encoded and count the bytes.
112 int nibbles = 0;
113 for (; dataPos < trailerPos; dataPos++) {
114 if (isspace(*dataPos))
115 continue;
116 if (!isxdigit(*dataPos))
117 return false;
118 nibbles++;
119 }
120 *dataLen = (nibbles + 1) / 2;
121
122 return true;
123}
124
125int8_t hexToBin(uint8_t c) {
126 if (!isxdigit(c))
127 return -1;
128 if (c <= '9') return c - '0';
129 if (c <= 'F') return c - 'A' + 10;
130 if (c <= 'f') return c - 'a' + 10;
131 return -1;
132}
133
134SkStream* handleType1Stream(SkStream* srcStream, size_t* headerLen,
135 size_t* dataLen, size_t* trailerLen) {
136 // srcStream may be backed by a file or a unseekable fd, so we may not be
137 // able to use skip(), rewind(), or getMemoryBase(). read()ing through
138 // the input only once is doable, but very ugly. Furthermore, it'd be nice
139 // if the data was NUL terminated so that we can use strstr() to search it.
140 // Make as few copies as possible given these constraints.
141 SkDynamicMemoryWStream dynamicStream;
142 SkRefPtr<SkMemoryStream> staticStream;
143 const uint8_t* src;
144 size_t srcLen;
145 if ((srcLen = srcStream->getLength()) > 0) {
146 staticStream = new SkMemoryStream(srcLen + 1);
147 staticStream->unref(); // new and SkRefPtr both took a ref.
148 src = (const uint8_t*)staticStream->getMemoryBase();
149 if (srcStream->getMemoryBase() != NULL) {
150 memcpy((void *)src, srcStream->getMemoryBase(), srcLen);
151 } else {
152 size_t read = 0;
153 while (read < srcLen) {
154 size_t got = srcStream->read((void *)staticStream->getAtPos(),
155 srcLen - read);
156 if (got == 0)
157 return NULL;
158 read += got;
159 staticStream->seek(read);
160 }
161 }
162 ((uint8_t *)src)[srcLen] = 0;
163 } else {
164 static const size_t bufSize = 4096;
165 uint8_t buf[bufSize];
166 size_t amount;
167 while ((amount = srcStream->read(buf, bufSize)) > 0)
168 dynamicStream.write(buf, amount);
169 amount = 0;
170 dynamicStream.write(&amount, 1); // NULL terminator.
171 // getStream makes another copy, but we couldn't do any better.
172 src = (const uint8_t*)dynamicStream.getStream();
173 srcLen = dynamicStream.getOffset() - 1;
174 }
175
176 if (parsePFB(src, srcLen, headerLen, dataLen, trailerLen)) {
177 SkMemoryStream* result =
178 new SkMemoryStream(*headerLen + *dataLen + *trailerLen);
179 memcpy((char*)result->getAtPos(), src + 6, *headerLen);
180 result->seek(*headerLen);
181 memcpy((char*)result->getAtPos(), src + 6 + *headerLen + 6, *dataLen);
182 result->seek(*headerLen + *dataLen);
183 memcpy((char*)result->getAtPos(), src + 6 + *headerLen + 6 + *dataLen,
184 *trailerLen);
185 result->rewind();
186 return result;
187 }
188
189 // A PFA has to be converted for PDF.
190 size_t hexDataLen;
191 if (parsePFA((const char*)src, srcLen, headerLen, &hexDataLen, dataLen,
192 trailerLen)) {
193 SkMemoryStream* result =
194 new SkMemoryStream(*headerLen + *dataLen + *trailerLen);
195 memcpy((char*)result->getAtPos(), src, *headerLen);
196 result->seek(*headerLen);
197
198 const uint8_t* hexData = src + *headerLen;
199 const uint8_t* trailer = hexData + hexDataLen;
200 size_t outputOffset = 0;
vandebo@chromium.org5b073682011-03-08 18:33:31 +0000201 uint8_t dataByte = 0; // To hush compiler.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000202 bool highNibble = true;
203 for (; hexData < trailer; hexData++) {
204 char curNibble = hexToBin(*hexData);
205 if (curNibble < 0)
206 continue;
207 if (highNibble) {
208 dataByte = curNibble << 4;
209 highNibble = false;
210 } else {
211 dataByte |= curNibble;
212 highNibble = true;
213 ((char *)result->getAtPos())[outputOffset++] = dataByte;
214 }
215 }
216 if (!highNibble)
217 ((char *)result->getAtPos())[outputOffset++] = dataByte;
218 SkASSERT(outputOffset == *dataLen);
219 result->seek(*headerLen + outputOffset);
220
221 memcpy((char *)result->getAtPos(), src + *headerLen + hexDataLen,
222 *trailerLen);
223 result->rewind();
224 return result;
225 }
226
227 return NULL;
228}
229
reed@google.com3f0dcf92011-03-18 21:23:45 +0000230// scale from em-units to base-1000, returning as a SkScalar
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000231SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
reed@google.com3f0dcf92011-03-18 21:23:45 +0000232 SkScalar scaled = SkIntToScalar(val);
233 if (emSize == 1000) {
234 return scaled;
235 } else {
236 return SkScalarMulDiv(scaled, 1000, emSize);
237 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000238}
239
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000240void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000241 SkWStream* content) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000242 // Specify width and bounding box for the glyph.
243 SkPDFScalar::Append(width, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000244 content->writeText(" 0 ");
245 content->writeDecAsText(box.fLeft);
246 content->writeText(" ");
247 content->writeDecAsText(box.fTop);
248 content->writeText(" ");
249 content->writeDecAsText(box.fRight);
250 content->writeText(" ");
251 content->writeDecAsText(box.fBottom);
252 content->writeText(" d1\n");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000253}
254
vandebo@chromium.org75f97e42011-04-11 23:24:18 +0000255SkPDFArray* makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000256 SkPDFArray* bbox = new SkPDFArray;
257 bbox->reserve(4);
258 bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fLeft,
259 emSize)))->unref();
260 bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fBottom,
261 emSize)))->unref();
262 bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fRight,
263 emSize)))->unref();
264 bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fTop,
265 emSize)))->unref();
266 return bbox;
267}
268
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000269SkPDFArray* appendWidth(const int16_t& width, uint16_t emSize,
270 SkPDFArray* array) {
271 array->append(new SkPDFScalar(scaleFromFontUnits(width, emSize)))->unref();
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000272 return array;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000273}
274
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000275SkPDFArray* appendVerticalAdvance(
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000276 const SkAdvancedTypefaceMetrics::VerticalMetric& advance,
277 uint16_t emSize, SkPDFArray* array) {
278 appendWidth(advance.fVerticalAdvance, emSize, array);
279 appendWidth(advance.fOriginXDisp, emSize, array);
280 appendWidth(advance.fOriginYDisp, emSize, array);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000281 return array;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000282}
283
284template <typename Data>
285SkPDFArray* composeAdvanceData(
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000286 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* advanceInfo,
287 uint16_t emSize,
288 SkPDFArray* (*appendAdvance)(const Data& advance, uint16_t emSize,
289 SkPDFArray* array),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000290 Data* defaultAdvance) {
291 SkPDFArray* result = new SkPDFArray();
292 for (; advanceInfo != NULL; advanceInfo = advanceInfo->fNext.get()) {
293 switch (advanceInfo->fType) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000294 case SkAdvancedTypefaceMetrics::WidthRange::kDefault: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000295 SkASSERT(advanceInfo->fAdvance.count() == 1);
296 *defaultAdvance = advanceInfo->fAdvance[0];
297 break;
298 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000299 case SkAdvancedTypefaceMetrics::WidthRange::kRange: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000300 SkRefPtr<SkPDFArray> advanceArray = new SkPDFArray();
301 advanceArray->unref(); // SkRefPtr and new both took a ref.
302 for (int j = 0; j < advanceInfo->fAdvance.count(); j++)
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000303 appendAdvance(advanceInfo->fAdvance[j], emSize,
304 advanceArray.get());
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000305 result->append(new SkPDFInt(advanceInfo->fStartId))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000306 result->append(advanceArray.get());
307 break;
308 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000309 case SkAdvancedTypefaceMetrics::WidthRange::kRun: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000310 SkASSERT(advanceInfo->fAdvance.count() == 1);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000311 result->append(new SkPDFInt(advanceInfo->fStartId))->unref();
312 result->append(new SkPDFInt(advanceInfo->fEndId))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000313 appendAdvance(advanceInfo->fAdvance[0], emSize, result);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000314 break;
315 }
316 }
317 }
318 return result;
319}
320
321} // namespace
322
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000323static void append_tounicode_header(SkDynamicMemoryWStream* cmap) {
324 // 12 dict begin: 12 is an Adobe-suggested value. Shall not change.
325 // It's there to prevent old version Adobe Readers from malfunctioning.
326 const char* kHeader =
327 "/CIDInit /ProcSet findresource begin\n"
328 "12 dict begin\n"
329 "begincmap\n";
330 cmap->writeText(kHeader);
331
332 // The /CIDSystemInfo must be consistent to the one in
333 // SkPDFFont::populateCIDFont().
334 // We can not pass over the system info object here because the format is
335 // different. This is not a reference object.
336 const char* kSysInfo =
337 "/CIDSystemInfo\n"
338 "<< /Registry (Adobe)\n"
339 "/Ordering (UCS)\n"
340 "/Supplement 0\n"
341 ">> def\n";
342 cmap->writeText(kSysInfo);
343
344 // The CMapName must be consistent to /CIDSystemInfo above.
345 // /CMapType 2 means ToUnicode.
346 // We specify codespacerange from 0x0000 to 0xFFFF because we convert our
347 // code table from unsigned short (16-bits). Codespace range just tells the
348 // PDF processor the valid range. It does not matter whether a complete
349 // mapping is provided or not.
350 const char* kTypeInfo =
351 "/CMapName /Adobe-Identity-UCS def\n"
352 "/CMapType 2 def\n"
353 "1 begincodespacerange\n"
354 "<0000> <FFFF>\n"
355 "endcodespacerange\n";
356 cmap->writeText(kTypeInfo);
357}
358
359static void append_cmap_bfchar_table(uint16_t* glyph_id, SkUnichar* unicode,
360 size_t count,
361 SkDynamicMemoryWStream* cmap) {
362 cmap->writeDecAsText(count);
363 cmap->writeText(" beginbfchar\n");
364 for (size_t i = 0; i < count; ++i) {
365 cmap->writeText("<");
366 cmap->writeHexAsText(glyph_id[i], 4);
367 cmap->writeText("> <");
368 cmap->writeHexAsText(unicode[i], 4);
369 cmap->writeText(">\n");
370 }
371 cmap->writeText("endbfchar\n");
372}
373
374static void append_cmap_footer(SkDynamicMemoryWStream* cmap) {
375 const char* kFooter =
376 "endcmap\n"
377 "CMapName currentdict /CMap defineresource pop\n"
378 "end\n"
379 "end";
380 cmap->writeText(kFooter);
381}
382
383// Generate <bfchar> table according to PDF spec 1.4 and Adobe Technote 5014.
384static void append_cmap_bfchar_sections(
385 const SkTDArray<SkUnichar>& glyphUnicode,
386 SkDynamicMemoryWStream* cmap) {
387 // PDF spec defines that every bf* list can have at most 100 entries.
388 const size_t kMaxEntries = 100;
389 uint16_t glyphId[kMaxEntries];
390 SkUnichar unicode[kMaxEntries];
391 size_t index = 0;
392 for (int i = 0; i < glyphUnicode.count(); i++) {
393 if (glyphUnicode[i]) {
394 glyphId[index] = i;
395 unicode[index] = glyphUnicode[i];
396 ++index;
397 }
398 if (index == kMaxEntries) {
399 append_cmap_bfchar_table(glyphId, unicode, index, cmap);
400 index = 0;
401 }
402 }
403
404 if (index) {
405 append_cmap_bfchar_table(glyphId, unicode, index, cmap);
406 }
407}
408
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000409/* Font subset design: It would be nice to be able to subset fonts
410 * (particularly type 3 fonts), but it's a lot of work and not a priority.
411 *
412 * Resources are canonicalized and uniqueified by pointer so there has to be
413 * some additional state indicating which subset of the font is used. It
414 * must be maintained at the page granularity and then combined at the document
415 * granularity. a) change SkPDFFont to fill in its state on demand, kind of
416 * like SkPDFGraphicState. b) maintain a per font glyph usage class in each
417 * page/pdf device. c) in the document, retrieve the per font glyph usage
418 * from each page and combine it and ask for a resource with that subset.
419 */
420
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000421SkPDFFont::~SkPDFFont() {
422 SkAutoMutexAcquire lock(canonicalFontsMutex());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000423 int index;
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000424 if (find(SkTypeface::UniqueID(fTypeface.get()), fFirstGlyphID, &index)) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000425 canonicalFonts().removeShuffle(index);
426#ifdef SK_DEBUG
427 SkASSERT(!fDescendant);
428 } else {
429 SkASSERT(fDescendant);
430#endif
431 }
432 fResources.unrefAll();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000433}
434
435void SkPDFFont::getResources(SkTDArray<SkPDFObject*>* resourceList) {
436 resourceList->setReserve(resourceList->count() + fResources.count());
437 for (int i = 0; i < fResources.count(); i++) {
438 resourceList->push(fResources[i]);
439 fResources[i]->ref();
440 fResources[i]->getResources(resourceList);
441 }
442}
443
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000444SkTypeface* SkPDFFont::typeface() {
445 return fTypeface.get();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000446}
447
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000448SkAdvancedTypefaceMetrics::FontType SkPDFFont::getType() {
449 return fType;
450}
451
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000452bool SkPDFFont::hasGlyph(uint16_t id) {
453 return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0;
454}
455
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000456bool SkPDFFont::multiByteGlyphs() {
457 return fMultiByteGlyphs;
458}
459
vandebo@chromium.org01294102011-02-28 19:52:18 +0000460size_t SkPDFFont::glyphsToPDFFontEncoding(uint16_t* glyphIDs,
461 size_t numGlyphs) {
462 // A font with multibyte glyphs will support all glyph IDs in a single font.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000463 if (fMultiByteGlyphs) {
vandebo@chromium.org01294102011-02-28 19:52:18 +0000464 return numGlyphs;
465 }
466
467 for (size_t i = 0; i < numGlyphs; i++) {
468 if (glyphIDs[i] == 0) {
469 continue;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000470 }
vandebo@chromium.org01294102011-02-28 19:52:18 +0000471 if (glyphIDs[i] < fFirstGlyphID || glyphIDs[i] > fLastGlyphID) {
472 return i;
473 }
474 glyphIDs[i] -= (fFirstGlyphID - 1);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000475 }
476
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000477 return numGlyphs;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000478}
479
480// static
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000481SkPDFFont* SkPDFFont::getFontResource(SkTypeface* typeface, uint16_t glyphID) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000482 SkAutoMutexAcquire lock(canonicalFontsMutex());
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000483 const uint32_t fontID = SkTypeface::UniqueID(typeface);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000484 int index;
485 if (find(fontID, glyphID, &index)) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000486 canonicalFonts()[index].fFont->ref();
487 return canonicalFonts()[index].fFont;
488 }
489
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000490 SkRefPtr<SkAdvancedTypefaceMetrics> fontInfo;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000491 SkPDFDict* fontDescriptor = NULL;
492 if (index >= 0) {
493 SkPDFFont* relatedFont = canonicalFonts()[index].fFont;
494 SkASSERT(relatedFont->fFontInfo.get());
495 fontInfo = relatedFont->fFontInfo;
496 fontDescriptor = relatedFont->fDescriptor.get();
497 } else {
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000498 SkAdvancedTypefaceMetrics::PerGlyphInfo info;
499 info = SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo;
500 info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>(
501 info, SkAdvancedTypefaceMetrics::kGlyphNames_PerGlyphInfo);
502 info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>(
503 info, SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo);
504 fontInfo = SkFontHost::GetAdvancedTypefaceMetrics(fontID, info);
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000505 SkSafeUnref(fontInfo.get()); // SkRefPtr and Get both took a reference.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000506 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000507
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000508 SkPDFFont* font = new SkPDFFont(fontInfo.get(), typeface, glyphID, false,
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000509 fontDescriptor);
510 FontRec newEntry(font, fontID, font->fFirstGlyphID);
511 index = canonicalFonts().count();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000512 canonicalFonts().push(newEntry);
513 return font; // Return the reference new SkPDFFont() created.
514}
515
516// static
517SkTDArray<SkPDFFont::FontRec>& SkPDFFont::canonicalFonts() {
518 // This initialization is only thread safe with gcc.
519 static SkTDArray<FontRec> gCanonicalFonts;
520 return gCanonicalFonts;
521}
522
523// static
524SkMutex& SkPDFFont::canonicalFontsMutex() {
525 // This initialization is only thread safe with gcc.
526 static SkMutex gCanonicalFontsMutex;
527 return gCanonicalFontsMutex;
528}
529
530// static
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000531bool SkPDFFont::find(uint32_t fontID, uint16_t glyphID, int* index) {
532 // TODO(vandebo) optimize this, do only one search?
533 FontRec search(NULL, fontID, glyphID);
534 *index = canonicalFonts().find(search);
535 if (*index >= 0)
536 return true;
537 search.fGlyphID = 0;
538 *index = canonicalFonts().find(search);
539 return false;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000540}
541
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000542SkPDFFont::SkPDFFont(class SkAdvancedTypefaceMetrics* fontInfo,
543 SkTypeface* typeface,
544 uint16_t glyphID,
545 bool descendantFont,
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000546 SkPDFDict* fontDescriptor)
547 : SkPDFDict("Font"),
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000548 fTypeface(typeface),
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000549 fType(fontInfo ? fontInfo->fType :
550 SkAdvancedTypefaceMetrics::kNotEmbeddable_Font),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000551#ifdef SK_DEBUG
552 fDescendant(descendantFont),
553#endif
554 fMultiByteGlyphs(false),
555 fFirstGlyphID(1),
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000556 fLastGlyphID(fontInfo ? fontInfo->fLastGlyphID : 0),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000557 fFontInfo(fontInfo),
558 fDescriptor(fontDescriptor) {
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000559 if (fontInfo && fontInfo->fMultiMaster) {
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000560 NOT_IMPLEMENTED(true, true);
561 fType = SkAdvancedTypefaceMetrics::kOther_Font;
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000562 }
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000563 if (fType == SkAdvancedTypefaceMetrics::kType1CID_Font ||
564 fType == SkAdvancedTypefaceMetrics::kTrueType_Font) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000565 if (descendantFont) {
566 populateCIDFont();
567 } else {
568 populateType0Font();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000569 }
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000570 // No need to hold onto the font info for fonts types that
571 // support multibyte glyphs.
572 fFontInfo = NULL;
573 return;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000574 }
575
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000576 if (fType == SkAdvancedTypefaceMetrics::kType1_Font &&
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000577 populateType1Font(glyphID)) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000578 return;
579 }
580
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000581 SkASSERT(fType == SkAdvancedTypefaceMetrics::kType1_Font ||
582 fType == SkAdvancedTypefaceMetrics::kCFF_Font ||
583 fType == SkAdvancedTypefaceMetrics::kOther_Font ||
584 fType == SkAdvancedTypefaceMetrics::kNotEmbeddable_Font);
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000585 populateType3Font(glyphID);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000586}
587
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000588void SkPDFFont::populateType0Font() {
589 fMultiByteGlyphs = true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000590
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000591 insert("Subtype", new SkPDFName("Type0"))->unref();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000592 insert("BaseFont", new SkPDFName(fFontInfo->fFontName))->unref();
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000593 insert("Encoding", new SkPDFName("Identity-H"))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000594
595 SkRefPtr<SkPDFArray> descendantFonts = new SkPDFArray();
596 descendantFonts->unref(); // SkRefPtr and new took a reference.
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000597
598 // Pass ref new created to fResources.
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000599 fResources.push(
600 new SkPDFFont(fFontInfo.get(), fTypeface.get(), 1, true, NULL));
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000601 descendantFonts->append(new SkPDFObjRef(fResources.top()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000602 insert("DescendantFonts", descendantFonts.get());
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000603
604 populateToUnicodeTable();
605}
606
607void SkPDFFont::populateToUnicodeTable() {
608 if (fFontInfo.get() == NULL ||
609 fFontInfo->fGlyphToUnicode.begin() == NULL) {
610 return;
611 }
612
613 SkDynamicMemoryWStream cmap;
614 append_tounicode_header(&cmap);
615 append_cmap_bfchar_sections(fFontInfo->fGlyphToUnicode, &cmap);
616 append_cmap_footer(&cmap);
617 SkRefPtr<SkMemoryStream> cmapStream = new SkMemoryStream();
618 cmapStream->unref(); // SkRefPtr and new took a reference.
619 cmapStream->setMemoryOwned(cmap.detach(), cmap.getOffset());
620 SkRefPtr<SkPDFStream> pdfCmap = new SkPDFStream(cmapStream.get());
621 fResources.push(pdfCmap.get()); // Pass reference from new.
622 insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000623}
624
625void SkPDFFont::populateCIDFont() {
626 fMultiByteGlyphs = true;
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000627 insert("BaseFont", new SkPDFName(fFontInfo->fFontName))->unref();
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000628
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000629 if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kType1CID_Font) {
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000630 insert("Subtype", new SkPDFName("CIDFontType0"))->unref();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000631 } else if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kTrueType_Font) {
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000632 insert("Subtype", new SkPDFName("CIDFontType2"))->unref();
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000633 insert("CIDToGIDMap", new SkPDFName("Identity"))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000634 } else {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000635 SkASSERT(false);
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000636 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000637
638 SkRefPtr<SkPDFDict> sysInfo = new SkPDFDict;
639 sysInfo->unref(); // SkRefPtr and new both took a reference.
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000640 sysInfo->insert("Registry", new SkPDFString("Adobe"))->unref();
641 sysInfo->insert("Ordering", new SkPDFString("Identity"))->unref();
642 sysInfo->insert("Supplement", new SkPDFInt(0))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000643 insert("CIDSystemInfo", sysInfo.get());
644
645 addFontDescriptor(0);
646
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000647 if (fFontInfo->fGlyphWidths.get()) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000648 int16_t defaultWidth = 0;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000649 SkRefPtr<SkPDFArray> widths =
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000650 composeAdvanceData(fFontInfo->fGlyphWidths.get(),
651 fFontInfo->fEmSize, &appendWidth, &defaultWidth);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000652 widths->unref(); // SkRefPtr and compose both took a reference.
653 if (widths->size())
654 insert("W", widths.get());
655 if (defaultWidth != 0) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000656 insert("DW", new SkPDFScalar(scaleFromFontUnits(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000657 defaultWidth, fFontInfo->fEmSize)))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000658 }
659 }
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000660 if (fFontInfo->fVerticalMetrics.get()) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000661 struct SkAdvancedTypefaceMetrics::VerticalMetric defaultAdvance;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000662 defaultAdvance.fVerticalAdvance = 0;
663 defaultAdvance.fOriginXDisp = 0;
664 defaultAdvance.fOriginYDisp = 0;
665 SkRefPtr<SkPDFArray> advances =
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000666 composeAdvanceData(fFontInfo->fVerticalMetrics.get(),
667 fFontInfo->fEmSize, &appendVerticalAdvance,
668 &defaultAdvance);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000669 advances->unref(); // SkRefPtr and compose both took a ref.
670 if (advances->size())
671 insert("W2", advances.get());
672 if (defaultAdvance.fVerticalAdvance ||
673 defaultAdvance.fOriginXDisp ||
674 defaultAdvance.fOriginYDisp) {
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000675 insert("DW2", appendVerticalAdvance(defaultAdvance,
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000676 fFontInfo->fEmSize,
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000677 new SkPDFArray))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000678 }
679 }
680}
681
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000682bool SkPDFFont::populateType1Font(int16_t glyphID) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000683 SkASSERT(!fFontInfo->fVerticalMetrics.get());
684 SkASSERT(fFontInfo->fGlyphWidths.get());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000685
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000686 adjustGlyphRangeForSingleByteEncoding(glyphID);
687
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000688 int16_t defaultWidth = 0;
689 const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry = NULL;
690 const SkAdvancedTypefaceMetrics::WidthRange* widthEntry;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000691 for (widthEntry = fFontInfo.get()->fGlyphWidths.get();
692 widthEntry != NULL;
693 widthEntry = widthEntry->fNext.get()) {
694 switch (widthEntry->fType) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000695 case SkAdvancedTypefaceMetrics::WidthRange::kDefault:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000696 defaultWidth = widthEntry->fAdvance[0];
697 break;
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000698 case SkAdvancedTypefaceMetrics::WidthRange::kRun:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000699 SkASSERT(false);
700 break;
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000701 case SkAdvancedTypefaceMetrics::WidthRange::kRange:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000702 SkASSERT(widthRangeEntry == NULL);
703 widthRangeEntry = widthEntry;
704 break;
705 }
706 }
707
708 if (!addFontDescriptor(defaultWidth))
709 return false;
710
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000711 insert("Subtype", new SkPDFName("Type1"))->unref();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000712 insert("BaseFont", new SkPDFName(fFontInfo->fFontName))->unref();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000713
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000714 addWidthInfoFromRange(defaultWidth, widthRangeEntry);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000715
716 SkRefPtr<SkPDFDict> encoding = new SkPDFDict("Encoding");
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000717 encoding->unref(); // SkRefPtr and new both took a reference.
718 insert("Encoding", encoding.get());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000719
720 SkRefPtr<SkPDFArray> encDiffs = new SkPDFArray;
721 encDiffs->unref(); // SkRefPtr and new both took a reference.
722 encoding->insert("Differences", encDiffs.get());
723
724 encDiffs->reserve(fLastGlyphID - fFirstGlyphID + 2);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000725 encDiffs->append(new SkPDFInt(1))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000726 for (int gID = fFirstGlyphID; gID <= fLastGlyphID; gID++) {
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000727 encDiffs->append(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000728 new SkPDFName(fFontInfo->fGlyphNames->get()[gID]))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000729 }
730
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000731 if (fFontInfo->fLastGlyphID <= 255)
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000732 fFontInfo = NULL;
733 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000734}
735
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000736void SkPDFFont::populateType3Font(int16_t glyphID) {
737 SkPaint paint;
738 paint.setTypeface(fTypeface.get());
739 paint.setTextSize(1000);
740 SkAutoGlyphCache autoCache(paint, NULL);
741 SkGlyphCache* cache = autoCache.getCache();
742 // If fLastGlyphID isn't set (because there is not fFontInfo), look it up.
743 if (fLastGlyphID == 0) {
744 fLastGlyphID = cache->getGlyphCount() - 1;
745 }
746
747 adjustGlyphRangeForSingleByteEncoding(glyphID);
748
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000749 insert("Subtype", new SkPDFName("Type3"))->unref();
750 // Flip about the x-axis and scale by 1/1000.
751 SkMatrix fontMatrix;
752 fontMatrix.setScale(SkScalarInvert(1000), -SkScalarInvert(1000));
753 insert("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix))->unref();
754
755 SkRefPtr<SkPDFDict> charProcs = new SkPDFDict;
756 charProcs->unref(); // SkRefPtr and new both took a reference.
757 insert("CharProcs", charProcs.get());
758
759 SkRefPtr<SkPDFDict> encoding = new SkPDFDict("Encoding");
760 encoding->unref(); // SkRefPtr and new both took a reference.
761 insert("Encoding", encoding.get());
762
763 SkRefPtr<SkPDFArray> encDiffs = new SkPDFArray;
764 encDiffs->unref(); // SkRefPtr and new both took a reference.
765 encoding->insert("Differences", encDiffs.get());
766 encDiffs->reserve(fLastGlyphID - fFirstGlyphID + 2);
767 encDiffs->append(new SkPDFInt(1))->unref();
768
769 SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
770 widthArray->unref(); // SkRefPtr and new both took a ref.
771
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000772 SkIRect bbox = SkIRect::MakeEmpty();
773 for (int gID = fFirstGlyphID; gID <= fLastGlyphID; gID++) {
774 SkString characterName;
775 characterName.printf("gid%d", gID);
776 encDiffs->append(new SkPDFName(characterName))->unref();
777
reed@google.comce11b262011-03-21 21:25:35 +0000778 const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
779 widthArray->append(new SkPDFScalar(SkFixedToScalar(glyph.fAdvanceX)))->unref();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000780 SkIRect glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
781 glyph.fWidth, glyph.fHeight);
782 bbox.join(glyphBBox);
783
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000784 SkDynamicMemoryWStream content;
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000785 setGlyphWidthAndBoundingBox(SkFixedToScalar(glyph.fAdvanceX), glyphBBox,
786 &content);
787 const SkPath* path = cache->findPath(glyph);
788 if (path) {
789 SkPDFUtils::EmitPath(*path, &content);
790 SkPDFUtils::PaintPath(paint.getStyle(), path->getFillType(),
791 &content);
792 }
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000793 SkRefPtr<SkMemoryStream> glyphStream = new SkMemoryStream();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000794 glyphStream->unref(); // SkRefPtr and new both took a ref.
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000795 glyphStream->setMemoryOwned(content.detach(), content.getOffset());
796
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000797 SkRefPtr<SkPDFStream> glyphDescription =
798 new SkPDFStream(glyphStream.get());
799 // SkRefPtr and new both ref()'d charProcs, pass one.
800 fResources.push(glyphDescription.get());
801 charProcs->insert(characterName.c_str(),
802 new SkPDFObjRef(glyphDescription.get()))->unref();
803 }
804
805 insert("FontBBox", makeFontBBox(bbox, 1000))->unref();
806 insert("FirstChar", new SkPDFInt(fFirstGlyphID))->unref();
807 insert("LastChar", new SkPDFInt(fLastGlyphID))->unref();
808 insert("Widths", widthArray.get());
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000809 insert("CIDToGIDMap", new SkPDFName("Identity"))->unref();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000810
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000811 if (fFontInfo && fFontInfo->fLastGlyphID <= 255)
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000812 fFontInfo = NULL;
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000813
814 populateToUnicodeTable();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000815}
816
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000817bool SkPDFFont::addFontDescriptor(int16_t defaultWidth) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000818 if (fDescriptor.get() != NULL) {
819 fResources.push(fDescriptor.get());
820 fDescriptor->ref();
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000821 insert("FontDescriptor", new SkPDFObjRef(fDescriptor.get()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000822 return true;
823 }
824
825 fDescriptor = new SkPDFDict("FontDescriptor");
826 fDescriptor->unref(); // SkRefPtr and new both took a ref.
827
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000828 switch (fFontInfo->fType) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000829 case SkAdvancedTypefaceMetrics::kType1_Font: {
reed@google.comee5ee582011-04-28 14:12:48 +0000830 size_t header SK_INIT_TO_AVOID_WARNING;
831 size_t data SK_INIT_TO_AVOID_WARNING;
832 size_t trailer SK_INIT_TO_AVOID_WARNING;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000833 SkRefPtr<SkStream> rawFontData =
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000834 SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get()));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000835 rawFontData->unref(); // SkRefPtr and OpenStream both took a ref.
836 SkStream* fontData = handleType1Stream(rawFontData.get(), &header,
837 &data, &trailer);
838 if (fontData == NULL)
839 return false;
840 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData);
841 // SkRefPtr and new both ref()'d fontStream, pass one.
842 fResources.push(fontStream.get());
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000843 fontStream->insert("Length1", new SkPDFInt(header))->unref();
844 fontStream->insert("Length2", new SkPDFInt(data))->unref();
845 fontStream->insert("Length3", new SkPDFInt(trailer))->unref();
846 fDescriptor->insert("FontFile",
847 new SkPDFObjRef(fontStream.get()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000848 break;
849 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000850 case SkAdvancedTypefaceMetrics::kTrueType_Font: {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000851 SkRefPtr<SkStream> fontData =
852 SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get()));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000853 fontData->unref(); // SkRefPtr and OpenStream both took a ref.
854 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
855 // SkRefPtr and new both ref()'d fontStream, pass one.
856 fResources.push(fontStream.get());
857
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000858 fontStream->insert("Length1",
859 new SkPDFInt(fontData->getLength()))->unref();
860 fDescriptor->insert("FontFile2",
861 new SkPDFObjRef(fontStream.get()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000862 break;
863 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000864 case SkAdvancedTypefaceMetrics::kCFF_Font:
865 case SkAdvancedTypefaceMetrics::kType1CID_Font: {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000866 SkRefPtr<SkStream> fontData =
867 SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get()));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000868 fontData->unref(); // SkRefPtr and OpenStream both took a ref.
869 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
870 // SkRefPtr and new both ref()'d fontStream, pass one.
871 fResources.push(fontStream.get());
872
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000873 if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kCFF_Font) {
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000874 fontStream->insert("Subtype", new SkPDFName("Type1C"))->unref();
875 } else {
876 fontStream->insert("Subtype",
877 new SkPDFName("CIDFontType0c"))->unref();
878 }
879 fDescriptor->insert("FontFile3",
880 new SkPDFObjRef(fontStream.get()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000881 break;
882 }
883 default:
884 SkASSERT(false);
885 }
886
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000887 const uint16_t emSize = fFontInfo->fEmSize;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000888 fResources.push(fDescriptor.get());
889 fDescriptor->ref();
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000890 insert("FontDescriptor", new SkPDFObjRef(fDescriptor.get()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000891
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000892 fDescriptor->insert("FontName", new SkPDFName(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000893 fFontInfo->fFontName))->unref();
894 fDescriptor->insert("Flags", new SkPDFInt(fFontInfo->fStyle))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000895 fDescriptor->insert("Ascent", new SkPDFScalar(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000896 scaleFromFontUnits(fFontInfo->fAscent, emSize)))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000897 fDescriptor->insert("Descent", new SkPDFScalar(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000898 scaleFromFontUnits(fFontInfo->fDescent, emSize)))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000899 fDescriptor->insert("StemV", new SkPDFScalar(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000900 scaleFromFontUnits(fFontInfo->fStemV, emSize)))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000901 fDescriptor->insert("CapHeight", new SkPDFScalar(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000902 scaleFromFontUnits(fFontInfo->fCapHeight, emSize)))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000903 fDescriptor->insert("ItalicAngle", new SkPDFInt(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000904 fFontInfo->fItalicAngle))->unref();
905 fDescriptor->insert("FontBBox", makeFontBBox(fFontInfo->fBBox,
906 fFontInfo->fEmSize))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000907
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000908 if (defaultWidth > 0) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000909 fDescriptor->insert("MissingWidth", new SkPDFScalar(
910 scaleFromFontUnits(defaultWidth, emSize)))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000911 }
912 return true;
913}
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000914void SkPDFFont::addWidthInfoFromRange(
915 int16_t defaultWidth,
916 const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry) {
917 SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
918 widthArray->unref(); // SkRefPtr and new both took a ref.
919 int firstChar = 0;
920 if (widthRangeEntry) {
921 const uint16_t emSize = fFontInfo->fEmSize;
922 int startIndex = fFirstGlyphID - widthRangeEntry->fStartId;
923 int endIndex = startIndex + fLastGlyphID - fFirstGlyphID + 1;
924 if (startIndex < 0)
925 startIndex = 0;
926 if (endIndex > widthRangeEntry->fAdvance.count())
927 endIndex = widthRangeEntry->fAdvance.count();
928 if (widthRangeEntry->fStartId == 0) {
929 appendWidth(widthRangeEntry->fAdvance[0], emSize, widthArray.get());
930 } else {
931 firstChar = startIndex + widthRangeEntry->fStartId;
932 }
933 for (int i = startIndex; i < endIndex; i++)
934 appendWidth(widthRangeEntry->fAdvance[i], emSize, widthArray.get());
935 } else {
936 appendWidth(defaultWidth, 1000, widthArray.get());
937 }
938 insert("FirstChar", new SkPDFInt(firstChar))->unref();
939 insert("LastChar",
940 new SkPDFInt(firstChar + widthArray->size() - 1))->unref();
941 insert("Widths", widthArray.get());
942}
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000943
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000944void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(int16_t glyphID) {
945 // Single byte glyph encoding supports a max of 255 glyphs.
946 fFirstGlyphID = glyphID - (glyphID - 1) % 255;
947 if (fLastGlyphID > fFirstGlyphID + 255 - 1) {
948 fLastGlyphID = fFirstGlyphID + 255 - 1;
949 }
950}
951
952
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000953bool SkPDFFont::FontRec::operator==(const SkPDFFont::FontRec& b) const {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000954 if (fFontID != b.fFontID)
955 return false;
956 if (fFont != NULL && b.fFont != NULL) {
957 return fFont->fFirstGlyphID == b.fFont->fFirstGlyphID &&
958 fFont->fLastGlyphID == b.fFont->fLastGlyphID;
959 }
960 if (fGlyphID == 0 || b.fGlyphID == 0)
961 return true;
962
963 if (fFont != NULL) {
964 return fFont->fFirstGlyphID <= b.fGlyphID &&
965 b.fGlyphID <= fFont->fLastGlyphID;
966 } else if (b.fFont != NULL) {
967 return b.fFont->fFirstGlyphID <= fGlyphID &&
968 fGlyphID <= b.fFont->fLastGlyphID;
969 }
970 return fGlyphID == b.fGlyphID;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000971}
972
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000973SkPDFFont::FontRec::FontRec(SkPDFFont* font, uint32_t fontID, uint16_t glyphID)
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000974 : fFont(font),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000975 fFontID(fontID),
976 fGlyphID(glyphID) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000977}