blob: f50580a4c40a942514a5d1a7fbed19cecdc9f49d [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.org6504cfd2011-07-23 20:22:53 +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.org6504cfd2011-07-23 20:22:53 +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
37namespace {
38
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +000039///////////////////////////////////////////////////////////////////////////////
40// File-Local Functions
41///////////////////////////////////////////////////////////////////////////////
42
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000043bool parsePFBSection(const uint8_t** src, size_t* len, int sectionType,
44 size_t* size) {
45 // PFB sections have a two or six bytes header. 0x80 and a one byte
46 // section type followed by a four byte section length. Type one is
47 // an ASCII section (includes a length), type two is a binary section
48 // (includes a length) and type three is an EOF marker with no length.
49 const uint8_t* buf = *src;
50 if (*len < 2 || buf[0] != 0x80 || buf[1] != sectionType)
51 return false;
52 if (buf[1] == 3)
53 return true;
54 if (*len < 6)
55 return false;
56
vandebo@chromium.org73322072011-06-21 21:19:41 +000057 *size = (size_t)buf[2] | ((size_t)buf[3] << 8) | ((size_t)buf[4] << 16) |
58 ((size_t)buf[5] << 24);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000059 size_t consumed = *size + 6;
60 if (consumed > *len)
61 return false;
62 *src = *src + consumed;
63 *len = *len - consumed;
64 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000065}
66
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000067bool parsePFB(const uint8_t* src, size_t size, size_t* headerLen,
68 size_t* dataLen, size_t* trailerLen) {
69 const uint8_t* srcPtr = src;
70 size_t remaining = size;
71
72 return parsePFBSection(&srcPtr, &remaining, 1, headerLen) &&
73 parsePFBSection(&srcPtr, &remaining, 2, dataLen) &&
74 parsePFBSection(&srcPtr, &remaining, 1, trailerLen) &&
75 parsePFBSection(&srcPtr, &remaining, 3, NULL);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000076}
77
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000078/* The sections of a PFA file are implicitly defined. The body starts
79 * after the line containing "eexec," and the trailer starts with 512
80 * literal 0's followed by "cleartomark" (plus arbitrary white space).
81 *
82 * This function assumes that src is NUL terminated, but the NUL
83 * termination is not included in size.
84 *
85 */
86bool parsePFA(const char* src, size_t size, size_t* headerLen,
87 size_t* hexDataLen, size_t* dataLen, size_t* trailerLen) {
88 const char* end = src + size;
89
90 const char* dataPos = strstr(src, "eexec");
91 if (!dataPos)
92 return false;
93 dataPos += strlen("eexec");
94 while ((*dataPos == '\n' || *dataPos == '\r' || *dataPos == ' ') &&
95 dataPos < end)
96 dataPos++;
97 *headerLen = dataPos - src;
98
99 const char* trailerPos = strstr(dataPos, "cleartomark");
100 if (!trailerPos)
101 return false;
102 int zeroCount = 0;
103 for (trailerPos--; trailerPos > dataPos && zeroCount < 512; trailerPos--) {
104 if (*trailerPos == '\n' || *trailerPos == '\r' || *trailerPos == ' ') {
105 continue;
106 } else if (*trailerPos == '0') {
107 zeroCount++;
108 } else {
109 return false;
110 }
111 }
112 if (zeroCount != 512)
113 return false;
114
115 *hexDataLen = trailerPos - src - *headerLen;
116 *trailerLen = size - *headerLen - *hexDataLen;
117
118 // Verify that the data section is hex encoded and count the bytes.
119 int nibbles = 0;
120 for (; dataPos < trailerPos; dataPos++) {
121 if (isspace(*dataPos))
122 continue;
123 if (!isxdigit(*dataPos))
124 return false;
125 nibbles++;
126 }
127 *dataLen = (nibbles + 1) / 2;
128
129 return true;
130}
131
132int8_t hexToBin(uint8_t c) {
133 if (!isxdigit(c))
134 return -1;
135 if (c <= '9') return c - '0';
136 if (c <= 'F') return c - 'A' + 10;
137 if (c <= 'f') return c - 'a' + 10;
138 return -1;
139}
140
141SkStream* handleType1Stream(SkStream* srcStream, size_t* headerLen,
142 size_t* dataLen, size_t* trailerLen) {
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000143 // srcStream may be backed by a file or a unseekable fd, so we may not be
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000144 // able to use skip(), rewind(), or getMemoryBase(). read()ing through
145 // the input only once is doable, but very ugly. Furthermore, it'd be nice
146 // if the data was NUL terminated so that we can use strstr() to search it.
147 // Make as few copies as possible given these constraints.
148 SkDynamicMemoryWStream dynamicStream;
149 SkRefPtr<SkMemoryStream> staticStream;
reed@google.com8a85d0c2011-06-24 19:12:12 +0000150 SkData* data = NULL;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000151 const uint8_t* src;
152 size_t srcLen;
153 if ((srcLen = srcStream->getLength()) > 0) {
154 staticStream = new SkMemoryStream(srcLen + 1);
155 staticStream->unref(); // new and SkRefPtr both took a ref.
156 src = (const uint8_t*)staticStream->getMemoryBase();
157 if (srcStream->getMemoryBase() != NULL) {
158 memcpy((void *)src, srcStream->getMemoryBase(), srcLen);
159 } else {
160 size_t read = 0;
161 while (read < srcLen) {
162 size_t got = srcStream->read((void *)staticStream->getAtPos(),
163 srcLen - read);
164 if (got == 0)
165 return NULL;
166 read += got;
167 staticStream->seek(read);
168 }
169 }
170 ((uint8_t *)src)[srcLen] = 0;
171 } else {
172 static const size_t bufSize = 4096;
173 uint8_t buf[bufSize];
174 size_t amount;
175 while ((amount = srcStream->read(buf, bufSize)) > 0)
176 dynamicStream.write(buf, amount);
177 amount = 0;
178 dynamicStream.write(&amount, 1); // NULL terminator.
reed@google.com8a85d0c2011-06-24 19:12:12 +0000179 data = dynamicStream.copyToData();
180 src = data->bytes();
181 srcLen = data->size() - 1;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000182 }
183
reed@google.com8a85d0c2011-06-24 19:12:12 +0000184 // this handles releasing the data we may have gotten from dynamicStream.
185 // if data is null, it is a no-op
186 SkAutoDataUnref aud(data);
187
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000188 if (parsePFB(src, srcLen, headerLen, dataLen, trailerLen)) {
189 SkMemoryStream* result =
190 new SkMemoryStream(*headerLen + *dataLen + *trailerLen);
191 memcpy((char*)result->getAtPos(), src + 6, *headerLen);
192 result->seek(*headerLen);
193 memcpy((char*)result->getAtPos(), src + 6 + *headerLen + 6, *dataLen);
194 result->seek(*headerLen + *dataLen);
195 memcpy((char*)result->getAtPos(), src + 6 + *headerLen + 6 + *dataLen,
196 *trailerLen);
197 result->rewind();
198 return result;
199 }
200
201 // A PFA has to be converted for PDF.
202 size_t hexDataLen;
203 if (parsePFA((const char*)src, srcLen, headerLen, &hexDataLen, dataLen,
204 trailerLen)) {
205 SkMemoryStream* result =
206 new SkMemoryStream(*headerLen + *dataLen + *trailerLen);
207 memcpy((char*)result->getAtPos(), src, *headerLen);
208 result->seek(*headerLen);
209
210 const uint8_t* hexData = src + *headerLen;
211 const uint8_t* trailer = hexData + hexDataLen;
212 size_t outputOffset = 0;
vandebo@chromium.org5b073682011-03-08 18:33:31 +0000213 uint8_t dataByte = 0; // To hush compiler.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000214 bool highNibble = true;
215 for (; hexData < trailer; hexData++) {
216 char curNibble = hexToBin(*hexData);
217 if (curNibble < 0)
218 continue;
219 if (highNibble) {
220 dataByte = curNibble << 4;
221 highNibble = false;
222 } else {
223 dataByte |= curNibble;
224 highNibble = true;
225 ((char *)result->getAtPos())[outputOffset++] = dataByte;
226 }
227 }
228 if (!highNibble)
229 ((char *)result->getAtPos())[outputOffset++] = dataByte;
230 SkASSERT(outputOffset == *dataLen);
231 result->seek(*headerLen + outputOffset);
232
233 memcpy((char *)result->getAtPos(), src + *headerLen + hexDataLen,
234 *trailerLen);
235 result->rewind();
236 return result;
237 }
238
239 return NULL;
240}
241
reed@google.com3f0dcf92011-03-18 21:23:45 +0000242// scale from em-units to base-1000, returning as a SkScalar
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000243SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
reed@google.com3f0dcf92011-03-18 21:23:45 +0000244 SkScalar scaled = SkIntToScalar(val);
245 if (emSize == 1000) {
246 return scaled;
247 } else {
248 return SkScalarMulDiv(scaled, 1000, emSize);
249 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000250}
251
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000252void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000253 SkWStream* content) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000254 // Specify width and bounding box for the glyph.
255 SkPDFScalar::Append(width, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000256 content->writeText(" 0 ");
257 content->writeDecAsText(box.fLeft);
258 content->writeText(" ");
259 content->writeDecAsText(box.fTop);
260 content->writeText(" ");
261 content->writeDecAsText(box.fRight);
262 content->writeText(" ");
263 content->writeDecAsText(box.fBottom);
264 content->writeText(" d1\n");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000265}
266
vandebo@chromium.org75f97e42011-04-11 23:24:18 +0000267SkPDFArray* makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000268 SkPDFArray* bbox = new SkPDFArray;
269 bbox->reserve(4);
reed@google.comc789cf12011-07-20 12:14:33 +0000270 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fLeft, emSize));
271 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fBottom, emSize));
272 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fRight, emSize));
273 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fTop, emSize));
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000274 return bbox;
275}
276
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000277SkPDFArray* appendWidth(const int16_t& width, uint16_t emSize,
278 SkPDFArray* array) {
reed@google.comc789cf12011-07-20 12:14:33 +0000279 array->appendScalar(scaleFromFontUnits(width, emSize));
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000280 return array;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000281}
282
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000283SkPDFArray* appendVerticalAdvance(
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000284 const SkAdvancedTypefaceMetrics::VerticalMetric& advance,
285 uint16_t emSize, SkPDFArray* array) {
286 appendWidth(advance.fVerticalAdvance, emSize, array);
287 appendWidth(advance.fOriginXDisp, emSize, array);
288 appendWidth(advance.fOriginYDisp, emSize, array);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000289 return array;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000290}
291
292template <typename Data>
293SkPDFArray* composeAdvanceData(
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000294 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* advanceInfo,
295 uint16_t emSize,
296 SkPDFArray* (*appendAdvance)(const Data& advance, uint16_t emSize,
297 SkPDFArray* array),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000298 Data* defaultAdvance) {
299 SkPDFArray* result = new SkPDFArray();
300 for (; advanceInfo != NULL; advanceInfo = advanceInfo->fNext.get()) {
301 switch (advanceInfo->fType) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000302 case SkAdvancedTypefaceMetrics::WidthRange::kDefault: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000303 SkASSERT(advanceInfo->fAdvance.count() == 1);
304 *defaultAdvance = advanceInfo->fAdvance[0];
305 break;
306 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000307 case SkAdvancedTypefaceMetrics::WidthRange::kRange: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000308 SkRefPtr<SkPDFArray> advanceArray = new SkPDFArray();
309 advanceArray->unref(); // SkRefPtr and new both took a ref.
310 for (int j = 0; j < advanceInfo->fAdvance.count(); j++)
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000311 appendAdvance(advanceInfo->fAdvance[j], emSize,
312 advanceArray.get());
reed@google.comc789cf12011-07-20 12:14:33 +0000313 result->appendInt(advanceInfo->fStartId);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000314 result->append(advanceArray.get());
315 break;
316 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000317 case SkAdvancedTypefaceMetrics::WidthRange::kRun: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000318 SkASSERT(advanceInfo->fAdvance.count() == 1);
reed@google.comc789cf12011-07-20 12:14:33 +0000319 result->appendInt(advanceInfo->fStartId);
320 result->appendInt(advanceInfo->fEndId);
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000321 appendAdvance(advanceInfo->fAdvance[0], emSize, result);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000322 break;
323 }
324 }
325 }
326 return result;
327}
328
329} // namespace
330
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000331static void append_tounicode_header(SkDynamicMemoryWStream* cmap) {
332 // 12 dict begin: 12 is an Adobe-suggested value. Shall not change.
333 // It's there to prevent old version Adobe Readers from malfunctioning.
334 const char* kHeader =
335 "/CIDInit /ProcSet findresource begin\n"
336 "12 dict begin\n"
337 "begincmap\n";
338 cmap->writeText(kHeader);
339
340 // The /CIDSystemInfo must be consistent to the one in
341 // SkPDFFont::populateCIDFont().
342 // We can not pass over the system info object here because the format is
343 // different. This is not a reference object.
344 const char* kSysInfo =
345 "/CIDSystemInfo\n"
346 "<< /Registry (Adobe)\n"
347 "/Ordering (UCS)\n"
348 "/Supplement 0\n"
349 ">> def\n";
350 cmap->writeText(kSysInfo);
351
352 // The CMapName must be consistent to /CIDSystemInfo above.
353 // /CMapType 2 means ToUnicode.
354 // We specify codespacerange from 0x0000 to 0xFFFF because we convert our
355 // code table from unsigned short (16-bits). Codespace range just tells the
356 // PDF processor the valid range. It does not matter whether a complete
357 // mapping is provided or not.
358 const char* kTypeInfo =
359 "/CMapName /Adobe-Identity-UCS def\n"
360 "/CMapType 2 def\n"
361 "1 begincodespacerange\n"
362 "<0000> <FFFF>\n"
363 "endcodespacerange\n";
364 cmap->writeText(kTypeInfo);
365}
366
367static void append_cmap_bfchar_table(uint16_t* glyph_id, SkUnichar* unicode,
368 size_t count,
369 SkDynamicMemoryWStream* cmap) {
370 cmap->writeDecAsText(count);
371 cmap->writeText(" beginbfchar\n");
372 for (size_t i = 0; i < count; ++i) {
373 cmap->writeText("<");
374 cmap->writeHexAsText(glyph_id[i], 4);
375 cmap->writeText("> <");
376 cmap->writeHexAsText(unicode[i], 4);
377 cmap->writeText(">\n");
378 }
379 cmap->writeText("endbfchar\n");
380}
381
382static void append_cmap_footer(SkDynamicMemoryWStream* cmap) {
383 const char* kFooter =
384 "endcmap\n"
385 "CMapName currentdict /CMap defineresource pop\n"
386 "end\n"
387 "end";
388 cmap->writeText(kFooter);
389}
390
391// Generate <bfchar> table according to PDF spec 1.4 and Adobe Technote 5014.
392static void append_cmap_bfchar_sections(
393 const SkTDArray<SkUnichar>& glyphUnicode,
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000394 const SkPDFGlyphSet* subset, SkDynamicMemoryWStream* cmap) {
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000395 // PDF spec defines that every bf* list can have at most 100 entries.
396 const size_t kMaxEntries = 100;
397 uint16_t glyphId[kMaxEntries];
398 SkUnichar unicode[kMaxEntries];
399 size_t index = 0;
400 for (int i = 0; i < glyphUnicode.count(); i++) {
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000401 if (glyphUnicode[i] && (subset == NULL || subset->has(i))) {
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000402 glyphId[index] = i;
403 unicode[index] = glyphUnicode[i];
404 ++index;
405 }
406 if (index == kMaxEntries) {
407 append_cmap_bfchar_table(glyphId, unicode, index, cmap);
408 index = 0;
409 }
410 }
411
412 if (index) {
413 append_cmap_bfchar_table(glyphId, unicode, index, cmap);
414 }
415}
416
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000417static SkPDFStream* generate_tounicode_cmap(
418 const SkTDArray<SkUnichar>& glyphUnicode,
419 const SkPDFGlyphSet* subset) {
420 SkDynamicMemoryWStream cmap;
421 append_tounicode_header(&cmap);
422 append_cmap_bfchar_sections(glyphUnicode, subset, &cmap);
423 append_cmap_footer(&cmap);
424 SkRefPtr<SkMemoryStream> cmapStream = new SkMemoryStream();
425 cmapStream->unref(); // SkRefPtr and new took a reference.
426 cmapStream->setData(cmap.copyToData());
427 return new SkPDFStream(cmapStream.get());
428}
429
430///////////////////////////////////////////////////////////////////////////////
431// class SkPDFGlyphSet
432///////////////////////////////////////////////////////////////////////////////
433
434SkPDFGlyphSet::SkPDFGlyphSet() : fBitSet(SK_MaxU16 + 1) {
435}
436
437void SkPDFGlyphSet::set(const uint16_t* glyphIDs, int numGlyphs) {
438 for (int i = 0; i < numGlyphs; ++i) {
439 fBitSet.setBit(glyphIDs[i], true);
440 }
441}
442
443bool SkPDFGlyphSet::has(uint16_t glyphID) const {
444 return fBitSet.isBitSet(glyphID);
445}
446
447void SkPDFGlyphSet::merge(const SkPDFGlyphSet& usage) {
448 fBitSet.orBits(usage.fBitSet);
449}
450
451///////////////////////////////////////////////////////////////////////////////
452// class SkPDFGlyphSetMap
453///////////////////////////////////////////////////////////////////////////////
454SkPDFGlyphSetMap::FontGlyphSetPair::FontGlyphSetPair(SkPDFFont* font,
455 SkPDFGlyphSet* glyphSet)
456 : fFont(font),
457 fGlyphSet(glyphSet) {
458}
459
460SkPDFGlyphSetMap::F2BIter::F2BIter(const SkPDFGlyphSetMap& map) {
461 reset(map);
462}
463
464SkPDFGlyphSetMap::FontGlyphSetPair* SkPDFGlyphSetMap::F2BIter::next() const {
465 if (fIndex >= fMap->count()) {
466 return NULL;
467 }
468 return &((*fMap)[fIndex++]);
469}
470
471void SkPDFGlyphSetMap::F2BIter::reset(const SkPDFGlyphSetMap& map) {
472 fMap = &(map.fMap);
473 fIndex = 0;
474}
475
476SkPDFGlyphSetMap::SkPDFGlyphSetMap() {
477}
478
479SkPDFGlyphSetMap::~SkPDFGlyphSetMap() {
480 reset();
481}
482
483void SkPDFGlyphSetMap::merge(const SkPDFGlyphSetMap& usage) {
484 for (int i = 0; i < usage.fMap.count(); ++i) {
485 SkPDFGlyphSet* myUsage = getGlyphSetForFont(usage.fMap[i].fFont);
486 myUsage->merge(*(usage.fMap[i].fGlyphSet));
487 }
488}
489
490void SkPDFGlyphSetMap::reset() {
491 for (int i = 0; i < fMap.count(); ++i) {
492 delete fMap[i].fGlyphSet; // Should not be NULL.
493 }
494 fMap.reset();
495}
496
497void SkPDFGlyphSetMap::noteGlyphUsage(SkPDFFont* font, const uint16_t* glyphIDs,
498 int numGlyphs) {
499 SkPDFGlyphSet* subset = getGlyphSetForFont(font);
500 if (subset) {
501 subset->set(glyphIDs, numGlyphs);
502 }
503}
504
505SkPDFGlyphSet* SkPDFGlyphSetMap::getGlyphSetForFont(SkPDFFont* font) {
506 int index = fMap.count();
507 for (int i = 0; i < index; ++i) {
508 if (fMap[i].fFont == font) {
509 return fMap[i].fGlyphSet;
510 }
511 }
512 fMap.append();
513 index = fMap.count() - 1;
514 fMap[index].fFont = font;
515 fMap[index].fGlyphSet = new SkPDFGlyphSet();
516 return fMap[index].fGlyphSet;
517}
518
519///////////////////////////////////////////////////////////////////////////////
520// class SkPDFFont
521///////////////////////////////////////////////////////////////////////////////
522
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000523/* Font subset design: It would be nice to be able to subset fonts
524 * (particularly type 3 fonts), but it's a lot of work and not a priority.
525 *
526 * Resources are canonicalized and uniqueified by pointer so there has to be
527 * some additional state indicating which subset of the font is used. It
528 * must be maintained at the page granularity and then combined at the document
529 * granularity. a) change SkPDFFont to fill in its state on demand, kind of
530 * like SkPDFGraphicState. b) maintain a per font glyph usage class in each
531 * page/pdf device. c) in the document, retrieve the per font glyph usage
532 * from each page and combine it and ask for a resource with that subset.
533 */
534
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000535SkPDFFont::~SkPDFFont() {
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000536 SkAutoMutexAcquire lock(CanonicalFontsMutex());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000537 int index;
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000538 if (Find(SkTypeface::UniqueID(fTypeface.get()), fFirstGlyphID, &index)) {
539 CanonicalFonts().removeShuffle(index);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000540 }
541 fResources.unrefAll();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000542}
543
544void SkPDFFont::getResources(SkTDArray<SkPDFObject*>* resourceList) {
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000545 GetResourcesHelper(&fResources, resourceList);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000546}
547
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000548SkTypeface* SkPDFFont::typeface() {
549 return fTypeface.get();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000550}
551
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000552SkAdvancedTypefaceMetrics::FontType SkPDFFont::getType() {
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000553 return fFontType;
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000554}
555
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000556bool SkPDFFont::hasGlyph(uint16_t id) {
557 return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0;
558}
559
vandebo@chromium.org01294102011-02-28 19:52:18 +0000560size_t SkPDFFont::glyphsToPDFFontEncoding(uint16_t* glyphIDs,
561 size_t numGlyphs) {
562 // A font with multibyte glyphs will support all glyph IDs in a single font.
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000563 if (this->multiByteGlyphs()) {
vandebo@chromium.org01294102011-02-28 19:52:18 +0000564 return numGlyphs;
565 }
566
567 for (size_t i = 0; i < numGlyphs; i++) {
568 if (glyphIDs[i] == 0) {
569 continue;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000570 }
vandebo@chromium.org01294102011-02-28 19:52:18 +0000571 if (glyphIDs[i] < fFirstGlyphID || glyphIDs[i] > fLastGlyphID) {
572 return i;
573 }
574 glyphIDs[i] -= (fFirstGlyphID - 1);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000575 }
576
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000577 return numGlyphs;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000578}
579
580// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000581SkPDFFont* SkPDFFont::GetFontResource(SkTypeface* typeface, uint16_t glyphID) {
582 SkAutoMutexAcquire lock(CanonicalFontsMutex());
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000583 const uint32_t fontID = SkTypeface::UniqueID(typeface);
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000584 int relatedFontIndex;
585 if (Find(fontID, glyphID, &relatedFontIndex)) {
586 CanonicalFonts()[relatedFontIndex].fFont->ref();
587 return CanonicalFonts()[relatedFontIndex].fFont;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000588 }
589
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000590 SkRefPtr<SkAdvancedTypefaceMetrics> fontMetrics;
591 SkPDFDict* relatedFontDescriptor = NULL;
592 if (relatedFontIndex >= 0) {
593 SkPDFFont* relatedFont = CanonicalFonts()[relatedFontIndex].fFont;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000594 SkASSERT(relatedFont->fFontInfo.get());
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000595 fontMetrics = relatedFont->fontInfo();
596 relatedFontDescriptor = relatedFont->getFontDescriptor();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000597 } else {
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000598 SkAdvancedTypefaceMetrics::PerGlyphInfo info;
599 info = SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo;
600 info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>(
601 info, SkAdvancedTypefaceMetrics::kGlyphNames_PerGlyphInfo);
602 info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>(
603 info, SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo);
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000604 fontMetrics = SkFontHost::GetAdvancedTypefaceMetrics(fontID, info);
605 SkSafeUnref(fontMetrics.get()); // SkRefPtr and Get both took a ref.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000606 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000607
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000608 SkPDFFont* font = Create(fontMetrics.get(), typeface, glyphID,
609 relatedFontDescriptor);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000610 FontRec newEntry(font, fontID, font->fFirstGlyphID);
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000611 CanonicalFonts().push(newEntry);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000612 return font; // Return the reference new SkPDFFont() created.
613}
614
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000615SkPDFFont* SkPDFFont::getFontSubset(const SkPDFGlyphSet* usage) {
616 return NULL; // Default: no support.
617}
618
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000619// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000620SkTDArray<SkPDFFont::FontRec>& SkPDFFont::CanonicalFonts() {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000621 // This initialization is only thread safe with gcc.
622 static SkTDArray<FontRec> gCanonicalFonts;
623 return gCanonicalFonts;
624}
625
626// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000627SkMutex& SkPDFFont::CanonicalFontsMutex() {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000628 // This initialization is only thread safe with gcc.
629 static SkMutex gCanonicalFontsMutex;
630 return gCanonicalFontsMutex;
631}
632
633// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000634bool SkPDFFont::Find(uint32_t fontID, uint16_t glyphID, int* index) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000635 // TODO(vandebo) optimize this, do only one search?
636 FontRec search(NULL, fontID, glyphID);
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000637 *index = CanonicalFonts().find(search);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000638 if (*index >= 0)
639 return true;
640 search.fGlyphID = 0;
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000641 *index = CanonicalFonts().find(search);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000642 return false;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000643}
644
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000645SkPDFFont::SkPDFFont(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface,
646 uint16_t glyphID, bool descendantFont)
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000647 : SkPDFDict("Font"),
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000648 fTypeface(typeface),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000649 fFirstGlyphID(1),
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000650 fLastGlyphID(info ? info->fLastGlyphID : 0),
651 fFontInfo(info) {
652 if (info == NULL) {
653 fFontType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
654 } else if (info->fMultiMaster) {
655 fFontType = SkAdvancedTypefaceMetrics::kOther_Font;
656 } else {
657 fFontType = info->fType;
658 }
659}
660
661// static
662SkPDFFont* SkPDFFont::Create(SkAdvancedTypefaceMetrics* info,
663 SkTypeface* typeface, uint16_t glyphID,
664 SkPDFDict* relatedFontDescriptor) {
665 SkAdvancedTypefaceMetrics::FontType type =
666 info ? info->fType : SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
667
668 if (info && info->fMultiMaster) {
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000669 NOT_IMPLEMENTED(true, true);
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000670 return new SkPDFType3Font(info,
671 typeface,
672 glyphID,
673 relatedFontDescriptor);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000674 }
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000675 if (type == SkAdvancedTypefaceMetrics::kType1CID_Font ||
676 type == SkAdvancedTypefaceMetrics::kTrueType_Font) {
677 SkASSERT(relatedFontDescriptor == NULL);
678 return new SkPDFType0Font(info, typeface);
679 }
680 if (type == SkAdvancedTypefaceMetrics::kType1_Font) {
681 return new SkPDFType1Font(info,
682 typeface,
683 glyphID,
684 relatedFontDescriptor);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000685 }
686
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000687 SkASSERT(type == SkAdvancedTypefaceMetrics::kCFF_Font ||
688 type == SkAdvancedTypefaceMetrics::kOther_Font ||
689 type == SkAdvancedTypefaceMetrics::kNotEmbeddable_Font);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000690
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000691 return new SkPDFType3Font(info, typeface, glyphID, relatedFontDescriptor);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000692}
693
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000694SkAdvancedTypefaceMetrics* SkPDFFont::fontInfo() {
695 return fFontInfo.get();
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000696}
697
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000698uint16_t SkPDFFont::firstGlyphID() const {
699 return fFirstGlyphID;
700}
701
702uint16_t SkPDFFont::lastGlyphID() const {
703 return fLastGlyphID;
704}
705
706void SkPDFFont::setLastGlyphID(uint16_t glyphID) {
707 fLastGlyphID = glyphID;
708}
709
710void SkPDFFont::addResource(SkPDFObject* object) {
711 SkASSERT(object != NULL);
712 fResources.push(object);
713}
714
715SkPDFDict* SkPDFFont::getFontDescriptor() {
716 return fDescriptor.get();
717}
718
719void SkPDFFont::setFontDescriptor(SkPDFDict* descriptor) {
720 fDescriptor = descriptor;
721}
722
723bool SkPDFFont::addCommonFontDescriptorEntries(int16_t defaultWidth) {
724 if (fDescriptor.get() == NULL) {
725 return false;
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000726 }
727
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000728 const uint16_t emSize = fFontInfo->fEmSize;
729
730 fDescriptor->insertName("FontName", fFontInfo->fFontName);
731 fDescriptor->insertInt("Flags", fFontInfo->fStyle);
732 fDescriptor->insertScalar("Ascent",
733 scaleFromFontUnits(fFontInfo->fAscent, emSize));
734 fDescriptor->insertScalar("Descent",
735 scaleFromFontUnits(fFontInfo->fDescent, emSize));
736 fDescriptor->insertScalar("StemV",
737 scaleFromFontUnits(fFontInfo->fStemV, emSize));
738 fDescriptor->insertScalar("CapHeight",
739 scaleFromFontUnits(fFontInfo->fCapHeight, emSize));
740 fDescriptor->insertInt("ItalicAngle", fFontInfo->fItalicAngle);
741 fDescriptor->insert("FontBBox", makeFontBBox(fFontInfo->fBBox,
742 fFontInfo->fEmSize))->unref();
743
744 if (defaultWidth > 0) {
745 fDescriptor->insertScalar("MissingWidth",
746 scaleFromFontUnits(defaultWidth, emSize));
747 }
748 return true;
749}
750
751void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(int16_t glyphID) {
752 // Single byte glyph encoding supports a max of 255 glyphs.
753 fFirstGlyphID = glyphID - (glyphID - 1) % 255;
754 if (fLastGlyphID > fFirstGlyphID + 255 - 1) {
755 fLastGlyphID = fFirstGlyphID + 255 - 1;
756 }
757}
758
759bool SkPDFFont::FontRec::operator==(const SkPDFFont::FontRec& b) const {
760 if (fFontID != b.fFontID)
761 return false;
762 if (fFont != NULL && b.fFont != NULL) {
763 return fFont->fFirstGlyphID == b.fFont->fFirstGlyphID &&
764 fFont->fLastGlyphID == b.fFont->fLastGlyphID;
765 }
766 if (fGlyphID == 0 || b.fGlyphID == 0)
767 return true;
768
769 if (fFont != NULL) {
770 return fFont->fFirstGlyphID <= b.fGlyphID &&
771 b.fGlyphID <= fFont->fLastGlyphID;
772 } else if (b.fFont != NULL) {
773 return b.fFont->fFirstGlyphID <= fGlyphID &&
774 fGlyphID <= b.fFont->fLastGlyphID;
775 }
776 return fGlyphID == b.fGlyphID;
777}
778
779SkPDFFont::FontRec::FontRec(SkPDFFont* font, uint32_t fontID, uint16_t glyphID)
780 : fFont(font),
781 fFontID(fontID),
782 fGlyphID(glyphID) {
783}
784
785void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) {
786 if (fFontInfo == NULL || fFontInfo->fGlyphToUnicode.begin() == NULL) {
787 return;
788 }
789 SkRefPtr<SkPDFStream> pdfCmap =
790 generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset);
791 addResource(pdfCmap.get()); // Pass reference from new.
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000792 insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000793}
794
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000795///////////////////////////////////////////////////////////////////////////////
796// class SkPDFType0Font
797///////////////////////////////////////////////////////////////////////////////
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000798
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000799SkPDFType0Font::SkPDFType0Font(SkAdvancedTypefaceMetrics* info,
800 SkTypeface* typeface)
801 : SkPDFFont(info, typeface, 0, false) {
802 SkDEBUGCODE(fPopulated = false);
803}
804
805SkPDFType0Font::~SkPDFType0Font() {}
806
807SkPDFFont* SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) {
808 SkPDFType0Font* newSubset = new SkPDFType0Font(fontInfo(), typeface());
809 newSubset->populate(subset);
810 return newSubset;
811}
812
813#ifdef SK_DEBUG
814void SkPDFType0Font::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
815 bool indirect) {
816 SkASSERT(fPopulated);
817 return INHERITED::emitObject(stream, catalog, indirect);
818}
819#endif
820
821bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) {
822 insertName("Subtype", "Type0");
823 insertName("BaseFont", fontInfo()->fFontName);
824 insertName("Encoding", "Identity-H");
825
826 // Pass ref new created to fResources.
827 SkPDFCIDFont* newCIDFont =
828 new SkPDFCIDFont(fontInfo(), typeface(), subset);
829 addResource(newCIDFont);
830 SkRefPtr<SkPDFArray> descendantFonts = new SkPDFArray();
831 descendantFonts->unref(); // SkRefPtr and new took a reference.
832 descendantFonts->append(new SkPDFObjRef(newCIDFont))->unref();
833 insert("DescendantFonts", descendantFonts.get());
834
835 populateToUnicodeTable(subset);
836
837 SkDEBUGCODE(fPopulated = true);
838 return true;
839}
840
841///////////////////////////////////////////////////////////////////////////////
842// class SkPDFCIDFont
843///////////////////////////////////////////////////////////////////////////////
844
845SkPDFCIDFont::SkPDFCIDFont(SkAdvancedTypefaceMetrics* info,
846 SkTypeface* typeface, const SkPDFGlyphSet* subset)
847 : SkPDFFont(info, typeface, 0, true) {
848 populate(subset);
849}
850
851SkPDFCIDFont::~SkPDFCIDFont() {}
852
853bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
854 const SkPDFGlyphSet* subset) {
855 SkRefPtr<SkPDFDict> descriptor = new SkPDFDict("FontDescriptor");
856 descriptor->unref(); // SkRefPtr and new both took a ref.
857 setFontDescriptor(descriptor.get());
858
859 switch (getType()) {
860 case SkAdvancedTypefaceMetrics::kTrueType_Font: {
861 // TODO(arthurhsu): sfntly font subsetting
862 SkRefPtr<SkStream> fontData =
863 SkFontHost::OpenStream(SkTypeface::UniqueID(typeface()));
864 fontData->unref(); // SkRefPtr and OpenStream both took a ref.
865 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
866 // SkRefPtr and new both ref()'d fontStream, pass one.
867 addResource(fontStream.get());
868
869 fontStream->insertInt("Length1", fontData->getLength());
870 descriptor->insert("FontFile2",
871 new SkPDFObjRef(fontStream.get()))->unref();
872 break;
873 }
874 case SkAdvancedTypefaceMetrics::kCFF_Font:
875 case SkAdvancedTypefaceMetrics::kType1CID_Font: {
876 SkRefPtr<SkStream> fontData =
877 SkFontHost::OpenStream(SkTypeface::UniqueID(typeface()));
878 fontData->unref(); // SkRefPtr and OpenStream both took a ref.
879 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
880 // SkRefPtr and new both ref()'d fontStream, pass one.
881 addResource(fontStream.get());
882
883 if (getType() == SkAdvancedTypefaceMetrics::kCFF_Font) {
884 fontStream->insertName("Subtype", "Type1C");
885 } else {
886 fontStream->insertName("Subtype", "CIDFontType0c");
887 }
888 descriptor->insert("FontFile3",
889 new SkPDFObjRef(fontStream.get()))->unref();
890 break;
891 }
892 default:
893 SkASSERT(false);
894 }
895
896 addResource(descriptor.get());
897 descriptor->ref();
898
899 insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
900 return addCommonFontDescriptorEntries(defaultWidth);
901}
902
903bool SkPDFCIDFont::populate(const SkPDFGlyphSet* subset) {
904 insertName("BaseFont", fontInfo()->fFontName);
905
906 if (getType() == SkAdvancedTypefaceMetrics::kType1CID_Font) {
reed@google.comc789cf12011-07-20 12:14:33 +0000907 insertName("Subtype", "CIDFontType0");
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000908 } else if (getType() == SkAdvancedTypefaceMetrics::kTrueType_Font) {
reed@google.comc789cf12011-07-20 12:14:33 +0000909 insertName("Subtype", "CIDFontType2");
910 insertName("CIDToGIDMap", "Identity");
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000911 } else {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000912 SkASSERT(false);
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000913 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000914
915 SkRefPtr<SkPDFDict> sysInfo = new SkPDFDict;
916 sysInfo->unref(); // SkRefPtr and new both took a reference.
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000917 sysInfo->insert("Registry", new SkPDFString("Adobe"))->unref();
918 sysInfo->insert("Ordering", new SkPDFString("Identity"))->unref();
reed@google.comc789cf12011-07-20 12:14:33 +0000919 sysInfo->insertInt("Supplement", 0);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000920 insert("CIDSystemInfo", sysInfo.get());
921
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000922 addFontDescriptor(0, subset);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000923
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000924 if (fontInfo()->fGlyphWidths.get()) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000925 int16_t defaultWidth = 0;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000926 SkRefPtr<SkPDFArray> widths =
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000927 composeAdvanceData(fontInfo()->fGlyphWidths.get(),
928 fontInfo()->fEmSize, &appendWidth,
929 &defaultWidth);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000930 widths->unref(); // SkRefPtr and compose both took a reference.
931 if (widths->size())
932 insert("W", widths.get());
933 if (defaultWidth != 0) {
reed@google.comc789cf12011-07-20 12:14:33 +0000934 insertScalar("DW", scaleFromFontUnits(defaultWidth,
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000935 fontInfo()->fEmSize));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000936 }
937 }
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000938 if (fontInfo()->fVerticalMetrics.get()) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000939 struct SkAdvancedTypefaceMetrics::VerticalMetric defaultAdvance;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000940 defaultAdvance.fVerticalAdvance = 0;
941 defaultAdvance.fOriginXDisp = 0;
942 defaultAdvance.fOriginYDisp = 0;
943 SkRefPtr<SkPDFArray> advances =
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000944 composeAdvanceData(fontInfo()->fVerticalMetrics.get(),
945 fontInfo()->fEmSize, &appendVerticalAdvance,
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000946 &defaultAdvance);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000947 advances->unref(); // SkRefPtr and compose both took a ref.
948 if (advances->size())
949 insert("W2", advances.get());
950 if (defaultAdvance.fVerticalAdvance ||
951 defaultAdvance.fOriginXDisp ||
952 defaultAdvance.fOriginYDisp) {
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000953 insert("DW2", appendVerticalAdvance(defaultAdvance,
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000954 fontInfo()->fEmSize,
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000955 new SkPDFArray))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000956 }
957 }
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000958
959 return true;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000960}
961
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +0000962///////////////////////////////////////////////////////////////////////////////
963// class SkPDFType1Font
964///////////////////////////////////////////////////////////////////////////////
965
966SkPDFType1Font::SkPDFType1Font(SkAdvancedTypefaceMetrics* info,
967 SkTypeface* typeface,
968 uint16_t glyphID,
969 SkPDFDict* relatedFontDescriptor)
970 : SkPDFFont(info, typeface, glyphID, false) {
971 populate(glyphID);
972}
973
974SkPDFType1Font::~SkPDFType1Font() {}
975
976bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
977 SkRefPtr<SkPDFDict> descriptor = getFontDescriptor();
978 if (descriptor.get() != NULL) {
979 addResource(descriptor.get());
980 descriptor->ref();
981 insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
982 return true;
983 }
984
985 descriptor = new SkPDFDict("FontDescriptor");
986 descriptor->unref(); // SkRefPtr and new both took a ref.
987 setFontDescriptor(descriptor.get());
988
989 size_t header SK_INIT_TO_AVOID_WARNING;
990 size_t data SK_INIT_TO_AVOID_WARNING;
991 size_t trailer SK_INIT_TO_AVOID_WARNING;
992 SkRefPtr<SkStream> rawFontData =
993 SkFontHost::OpenStream(SkTypeface::UniqueID(typeface()));
994 rawFontData->unref(); // SkRefPtr and OpenStream both took a ref.
995 SkStream* fontData = handleType1Stream(rawFontData.get(), &header, &data,
996 &trailer);
997 if (fontData == NULL) {
998 return false;
999 }
1000 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData);
1001 // SkRefPtr and new both ref()'d fontStream, pass one.
1002 addResource(fontStream.get());
1003 fontStream->insertInt("Length1", header);
1004 fontStream->insertInt("Length2", data);
1005 fontStream->insertInt("Length3", trailer);
1006 descriptor->insert("FontFile", new SkPDFObjRef(fontStream.get()))->unref();
1007
1008 addResource(descriptor.get());
1009 descriptor->ref();
1010 insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
1011
1012 return addCommonFontDescriptorEntries(defaultWidth);
1013}
1014
1015bool SkPDFType1Font::populate(int16_t glyphID) {
1016 SkASSERT(!fontInfo()->fVerticalMetrics.get());
1017 SkASSERT(fontInfo()->fGlyphWidths.get());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001018
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001019 adjustGlyphRangeForSingleByteEncoding(glyphID);
1020
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001021 int16_t defaultWidth = 0;
1022 const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry = NULL;
1023 const SkAdvancedTypefaceMetrics::WidthRange* widthEntry;
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +00001024 for (widthEntry = fontInfo()->fGlyphWidths.get();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001025 widthEntry != NULL;
1026 widthEntry = widthEntry->fNext.get()) {
1027 switch (widthEntry->fType) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001028 case SkAdvancedTypefaceMetrics::WidthRange::kDefault:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001029 defaultWidth = widthEntry->fAdvance[0];
1030 break;
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001031 case SkAdvancedTypefaceMetrics::WidthRange::kRun:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001032 SkASSERT(false);
1033 break;
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +00001034 case SkAdvancedTypefaceMetrics::WidthRange::kRange:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001035 SkASSERT(widthRangeEntry == NULL);
1036 widthRangeEntry = widthEntry;
1037 break;
1038 }
1039 }
1040
1041 if (!addFontDescriptor(defaultWidth))
1042 return false;
1043
reed@google.comc789cf12011-07-20 12:14:33 +00001044 insertName("Subtype", "Type1");
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +00001045 insertName("BaseFont", fontInfo()->fFontName);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00001046
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001047 addWidthInfoFromRange(defaultWidth, widthRangeEntry);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001048
1049 SkRefPtr<SkPDFDict> encoding = new SkPDFDict("Encoding");
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00001050 encoding->unref(); // SkRefPtr and new both took a reference.
1051 insert("Encoding", encoding.get());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001052
1053 SkRefPtr<SkPDFArray> encDiffs = new SkPDFArray;
1054 encDiffs->unref(); // SkRefPtr and new both took a reference.
1055 encoding->insert("Differences", encDiffs.get());
1056
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +00001057 encDiffs->reserve(lastGlyphID() - firstGlyphID() + 2);
reed@google.comc789cf12011-07-20 12:14:33 +00001058 encDiffs->appendInt(1);
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +00001059 for (int gID = firstGlyphID(); gID <= lastGlyphID(); gID++) {
1060 encDiffs->appendName(fontInfo()->fGlyphNames->get()[gID].c_str());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001061 }
1062
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001063 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00001064}
1065
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +00001066void SkPDFType1Font::addWidthInfoFromRange(
1067 int16_t defaultWidth,
1068 const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry) {
1069 SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
1070 widthArray->unref(); // SkRefPtr and new both took a ref.
1071 int firstChar = 0;
1072 if (widthRangeEntry) {
1073 const uint16_t emSize = fontInfo()->fEmSize;
1074 int startIndex = firstGlyphID() - widthRangeEntry->fStartId;
1075 int endIndex = startIndex + lastGlyphID() - firstGlyphID() + 1;
1076 if (startIndex < 0)
1077 startIndex = 0;
1078 if (endIndex > widthRangeEntry->fAdvance.count())
1079 endIndex = widthRangeEntry->fAdvance.count();
1080 if (widthRangeEntry->fStartId == 0) {
1081 appendWidth(widthRangeEntry->fAdvance[0], emSize, widthArray.get());
1082 } else {
1083 firstChar = startIndex + widthRangeEntry->fStartId;
1084 }
1085 for (int i = startIndex; i < endIndex; i++)
1086 appendWidth(widthRangeEntry->fAdvance[i], emSize, widthArray.get());
1087 } else {
1088 appendWidth(defaultWidth, 1000, widthArray.get());
1089 }
1090 insertInt("FirstChar", firstChar);
1091 insertInt("LastChar", firstChar + widthArray->size() - 1);
1092 insert("Widths", widthArray.get());
1093}
1094
1095///////////////////////////////////////////////////////////////////////////////
1096// class SkPDFType3Font
1097///////////////////////////////////////////////////////////////////////////////
1098
1099SkPDFType3Font::SkPDFType3Font(SkAdvancedTypefaceMetrics* info,
1100 SkTypeface* typeface,
1101 uint16_t glyphID,
1102 SkPDFDict* relatedFontDescriptor)
1103 : SkPDFFont(info, typeface, glyphID, false) {
1104 populate(glyphID);
1105}
1106
1107SkPDFType3Font::~SkPDFType3Font() {}
1108
1109bool SkPDFType3Font::populate(int16_t glyphID) {
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001110 SkPaint paint;
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +00001111 paint.setTypeface(typeface());
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001112 paint.setTextSize(1000);
1113 SkAutoGlyphCache autoCache(paint, NULL);
1114 SkGlyphCache* cache = autoCache.getCache();
1115 // If fLastGlyphID isn't set (because there is not fFontInfo), look it up.
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +00001116 if (lastGlyphID() == 0) {
1117 setLastGlyphID(cache->getGlyphCount() - 1);
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001118 }
1119
1120 adjustGlyphRangeForSingleByteEncoding(glyphID);
1121
reed@google.comc789cf12011-07-20 12:14:33 +00001122 insertName("Subtype", "Type3");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001123 // Flip about the x-axis and scale by 1/1000.
1124 SkMatrix fontMatrix;
1125 fontMatrix.setScale(SkScalarInvert(1000), -SkScalarInvert(1000));
1126 insert("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix))->unref();
1127
1128 SkRefPtr<SkPDFDict> charProcs = new SkPDFDict;
1129 charProcs->unref(); // SkRefPtr and new both took a reference.
1130 insert("CharProcs", charProcs.get());
1131
1132 SkRefPtr<SkPDFDict> encoding = new SkPDFDict("Encoding");
1133 encoding->unref(); // SkRefPtr and new both took a reference.
1134 insert("Encoding", encoding.get());
1135
1136 SkRefPtr<SkPDFArray> encDiffs = new SkPDFArray;
1137 encDiffs->unref(); // SkRefPtr and new both took a reference.
1138 encoding->insert("Differences", encDiffs.get());
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +00001139 encDiffs->reserve(lastGlyphID() - firstGlyphID() + 2);
reed@google.comc789cf12011-07-20 12:14:33 +00001140 encDiffs->appendInt(1);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001141
1142 SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
1143 widthArray->unref(); // SkRefPtr and new both took a ref.
1144
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001145 SkIRect bbox = SkIRect::MakeEmpty();
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +00001146 for (int gID = firstGlyphID(); gID <= lastGlyphID(); gID++) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001147 SkString characterName;
1148 characterName.printf("gid%d", gID);
reed@google.comc789cf12011-07-20 12:14:33 +00001149 encDiffs->appendName(characterName.c_str());
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001150
reed@google.comce11b262011-03-21 21:25:35 +00001151 const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
reed@google.comc789cf12011-07-20 12:14:33 +00001152 widthArray->appendScalar(SkFixedToScalar(glyph.fAdvanceX));
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001153 SkIRect glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
1154 glyph.fWidth, glyph.fHeight);
1155 bbox.join(glyphBBox);
1156
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +00001157 SkDynamicMemoryWStream content;
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001158 setGlyphWidthAndBoundingBox(SkFixedToScalar(glyph.fAdvanceX), glyphBBox,
1159 &content);
1160 const SkPath* path = cache->findPath(glyph);
1161 if (path) {
1162 SkPDFUtils::EmitPath(*path, &content);
1163 SkPDFUtils::PaintPath(paint.getStyle(), path->getFillType(),
1164 &content);
1165 }
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +00001166 SkRefPtr<SkMemoryStream> glyphStream = new SkMemoryStream();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001167 glyphStream->unref(); // SkRefPtr and new both took a ref.
reed@google.com8a85d0c2011-06-24 19:12:12 +00001168 glyphStream->setData(content.copyToData())->unref();
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +00001169
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001170 SkRefPtr<SkPDFStream> glyphDescription =
1171 new SkPDFStream(glyphStream.get());
1172 // SkRefPtr and new both ref()'d charProcs, pass one.
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +00001173 addResource(glyphDescription.get());
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001174 charProcs->insert(characterName.c_str(),
1175 new SkPDFObjRef(glyphDescription.get()))->unref();
1176 }
1177
1178 insert("FontBBox", makeFontBBox(bbox, 1000))->unref();
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +00001179 insertInt("FirstChar", firstGlyphID());
1180 insertInt("LastChar", lastGlyphID());
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001181 insert("Widths", widthArray.get());
reed@google.comc789cf12011-07-20 12:14:33 +00001182 insertName("CIDToGIDMap", "Identity");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001183
vandebo@chromium.org6504cfd2011-07-23 20:22:53 +00001184 populateToUnicodeTable(NULL);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001185 return true;
1186}