blob: 382c93a2add9b4276a31555d2c488d3ada0fc61a [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.org28be72b2010-11-11 21:37:00 +000031#include "SkUtils.h"
32
33namespace {
34
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000035bool parsePFBSection(const uint8_t** src, size_t* len, int sectionType,
36 size_t* size) {
37 // PFB sections have a two or six bytes header. 0x80 and a one byte
38 // section type followed by a four byte section length. Type one is
39 // an ASCII section (includes a length), type two is a binary section
40 // (includes a length) and type three is an EOF marker with no length.
41 const uint8_t* buf = *src;
42 if (*len < 2 || buf[0] != 0x80 || buf[1] != sectionType)
43 return false;
44 if (buf[1] == 3)
45 return true;
46 if (*len < 6)
47 return false;
48
49 *size = buf[2] | (buf[3] << 8) | (buf[4] << 16) | (buf[5] << 24);
50 size_t consumed = *size + 6;
51 if (consumed > *len)
52 return false;
53 *src = *src + consumed;
54 *len = *len - consumed;
55 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000056}
57
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000058bool parsePFB(const uint8_t* src, size_t size, size_t* headerLen,
59 size_t* dataLen, size_t* trailerLen) {
60 const uint8_t* srcPtr = src;
61 size_t remaining = size;
62
63 return parsePFBSection(&srcPtr, &remaining, 1, headerLen) &&
64 parsePFBSection(&srcPtr, &remaining, 2, dataLen) &&
65 parsePFBSection(&srcPtr, &remaining, 1, trailerLen) &&
66 parsePFBSection(&srcPtr, &remaining, 3, NULL);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000067}
68
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000069/* The sections of a PFA file are implicitly defined. The body starts
70 * after the line containing "eexec," and the trailer starts with 512
71 * literal 0's followed by "cleartomark" (plus arbitrary white space).
72 *
73 * This function assumes that src is NUL terminated, but the NUL
74 * termination is not included in size.
75 *
76 */
77bool parsePFA(const char* src, size_t size, size_t* headerLen,
78 size_t* hexDataLen, size_t* dataLen, size_t* trailerLen) {
79 const char* end = src + size;
80
81 const char* dataPos = strstr(src, "eexec");
82 if (!dataPos)
83 return false;
84 dataPos += strlen("eexec");
85 while ((*dataPos == '\n' || *dataPos == '\r' || *dataPos == ' ') &&
86 dataPos < end)
87 dataPos++;
88 *headerLen = dataPos - src;
89
90 const char* trailerPos = strstr(dataPos, "cleartomark");
91 if (!trailerPos)
92 return false;
93 int zeroCount = 0;
94 for (trailerPos--; trailerPos > dataPos && zeroCount < 512; trailerPos--) {
95 if (*trailerPos == '\n' || *trailerPos == '\r' || *trailerPos == ' ') {
96 continue;
97 } else if (*trailerPos == '0') {
98 zeroCount++;
99 } else {
100 return false;
101 }
102 }
103 if (zeroCount != 512)
104 return false;
105
106 *hexDataLen = trailerPos - src - *headerLen;
107 *trailerLen = size - *headerLen - *hexDataLen;
108
109 // Verify that the data section is hex encoded and count the bytes.
110 int nibbles = 0;
111 for (; dataPos < trailerPos; dataPos++) {
112 if (isspace(*dataPos))
113 continue;
114 if (!isxdigit(*dataPos))
115 return false;
116 nibbles++;
117 }
118 *dataLen = (nibbles + 1) / 2;
119
120 return true;
121}
122
123int8_t hexToBin(uint8_t c) {
124 if (!isxdigit(c))
125 return -1;
126 if (c <= '9') return c - '0';
127 if (c <= 'F') return c - 'A' + 10;
128 if (c <= 'f') return c - 'a' + 10;
129 return -1;
130}
131
132SkStream* handleType1Stream(SkStream* srcStream, size_t* headerLen,
133 size_t* dataLen, size_t* trailerLen) {
134 // srcStream may be backed by a file or a unseekable fd, so we may not be
135 // able to use skip(), rewind(), or getMemoryBase(). read()ing through
136 // the input only once is doable, but very ugly. Furthermore, it'd be nice
137 // if the data was NUL terminated so that we can use strstr() to search it.
138 // Make as few copies as possible given these constraints.
139 SkDynamicMemoryWStream dynamicStream;
140 SkRefPtr<SkMemoryStream> staticStream;
141 const uint8_t* src;
142 size_t srcLen;
143 if ((srcLen = srcStream->getLength()) > 0) {
144 staticStream = new SkMemoryStream(srcLen + 1);
145 staticStream->unref(); // new and SkRefPtr both took a ref.
146 src = (const uint8_t*)staticStream->getMemoryBase();
147 if (srcStream->getMemoryBase() != NULL) {
148 memcpy((void *)src, srcStream->getMemoryBase(), srcLen);
149 } else {
150 size_t read = 0;
151 while (read < srcLen) {
152 size_t got = srcStream->read((void *)staticStream->getAtPos(),
153 srcLen - read);
154 if (got == 0)
155 return NULL;
156 read += got;
157 staticStream->seek(read);
158 }
159 }
160 ((uint8_t *)src)[srcLen] = 0;
161 } else {
162 static const size_t bufSize = 4096;
163 uint8_t buf[bufSize];
164 size_t amount;
165 while ((amount = srcStream->read(buf, bufSize)) > 0)
166 dynamicStream.write(buf, amount);
167 amount = 0;
168 dynamicStream.write(&amount, 1); // NULL terminator.
169 // getStream makes another copy, but we couldn't do any better.
170 src = (const uint8_t*)dynamicStream.getStream();
171 srcLen = dynamicStream.getOffset() - 1;
172 }
173
174 if (parsePFB(src, srcLen, headerLen, dataLen, trailerLen)) {
175 SkMemoryStream* result =
176 new SkMemoryStream(*headerLen + *dataLen + *trailerLen);
177 memcpy((char*)result->getAtPos(), src + 6, *headerLen);
178 result->seek(*headerLen);
179 memcpy((char*)result->getAtPos(), src + 6 + *headerLen + 6, *dataLen);
180 result->seek(*headerLen + *dataLen);
181 memcpy((char*)result->getAtPos(), src + 6 + *headerLen + 6 + *dataLen,
182 *trailerLen);
183 result->rewind();
184 return result;
185 }
186
187 // A PFA has to be converted for PDF.
188 size_t hexDataLen;
189 if (parsePFA((const char*)src, srcLen, headerLen, &hexDataLen, dataLen,
190 trailerLen)) {
191 SkMemoryStream* result =
192 new SkMemoryStream(*headerLen + *dataLen + *trailerLen);
193 memcpy((char*)result->getAtPos(), src, *headerLen);
194 result->seek(*headerLen);
195
196 const uint8_t* hexData = src + *headerLen;
197 const uint8_t* trailer = hexData + hexDataLen;
198 size_t outputOffset = 0;
vandebo@chromium.org5b073682011-03-08 18:33:31 +0000199 uint8_t dataByte = 0; // To hush compiler.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000200 bool highNibble = true;
201 for (; hexData < trailer; hexData++) {
202 char curNibble = hexToBin(*hexData);
203 if (curNibble < 0)
204 continue;
205 if (highNibble) {
206 dataByte = curNibble << 4;
207 highNibble = false;
208 } else {
209 dataByte |= curNibble;
210 highNibble = true;
211 ((char *)result->getAtPos())[outputOffset++] = dataByte;
212 }
213 }
214 if (!highNibble)
215 ((char *)result->getAtPos())[outputOffset++] = dataByte;
216 SkASSERT(outputOffset == *dataLen);
217 result->seek(*headerLen + outputOffset);
218
219 memcpy((char *)result->getAtPos(), src + *headerLen + hexDataLen,
220 *trailerLen);
221 result->rewind();
222 return result;
223 }
224
225 return NULL;
226}
227
reed@google.com3f0dcf92011-03-18 21:23:45 +0000228// scale from em-units to base-1000, returning as a SkScalar
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000229SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
reed@google.com3f0dcf92011-03-18 21:23:45 +0000230 SkScalar scaled = SkIntToScalar(val);
231 if (emSize == 1000) {
232 return scaled;
233 } else {
234 return SkScalarMulDiv(scaled, 1000, emSize);
235 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000236}
237
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000238void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
239 SkString* content) {
240 // Specify width and bounding box for the glyph.
241 SkPDFScalar::Append(width, content);
242 content->appendf(" 0 %d %d %d %d d1\n", box.fLeft, box.fTop,
243 box.fRight, box.fBottom);
244}
245
246SkPDFArray* makeFontBBox(
247 SkIRect glyphBBox, uint16_t emSize,
248 SkPDFDevice::OriginTransform flipOrigin =
249 SkPDFDevice::kNoFlip_OriginTransform) {
250 if (flipOrigin == SkPDFDevice::kFlip_OriginTransform) {
251 int32_t temp = -glyphBBox.fTop;
252 glyphBBox.fTop = -glyphBBox.fBottom;
253 glyphBBox.fBottom = temp;
254 }
255 SkPDFArray* bbox = new SkPDFArray;
256 bbox->reserve(4);
257 bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fLeft,
258 emSize)))->unref();
259 bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fBottom,
260 emSize)))->unref();
261 bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fRight,
262 emSize)))->unref();
263 bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fTop,
264 emSize)))->unref();
265 return bbox;
266}
267
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000268SkPDFArray* appendWidth(const int16_t& width, uint16_t emSize,
269 SkPDFArray* array) {
270 array->append(new SkPDFScalar(scaleFromFontUnits(width, emSize)))->unref();
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000271 return array;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000272}
273
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000274SkPDFArray* appendVerticalAdvance(
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000275 const SkAdvancedTypefaceMetrics::VerticalMetric& advance,
276 uint16_t emSize, SkPDFArray* array) {
277 appendWidth(advance.fVerticalAdvance, emSize, array);
278 appendWidth(advance.fOriginXDisp, emSize, array);
279 appendWidth(advance.fOriginYDisp, emSize, array);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000280 return array;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000281}
282
283template <typename Data>
284SkPDFArray* composeAdvanceData(
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000285 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* advanceInfo,
286 uint16_t emSize,
287 SkPDFArray* (*appendAdvance)(const Data& advance, uint16_t emSize,
288 SkPDFArray* array),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000289 Data* defaultAdvance) {
290 SkPDFArray* result = new SkPDFArray();
291 for (; advanceInfo != NULL; advanceInfo = advanceInfo->fNext.get()) {
292 switch (advanceInfo->fType) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000293 case SkAdvancedTypefaceMetrics::WidthRange::kDefault: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000294 SkASSERT(advanceInfo->fAdvance.count() == 1);
295 *defaultAdvance = advanceInfo->fAdvance[0];
296 break;
297 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000298 case SkAdvancedTypefaceMetrics::WidthRange::kRange: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000299 SkRefPtr<SkPDFArray> advanceArray = new SkPDFArray();
300 advanceArray->unref(); // SkRefPtr and new both took a ref.
301 for (int j = 0; j < advanceInfo->fAdvance.count(); j++)
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000302 appendAdvance(advanceInfo->fAdvance[j], emSize,
303 advanceArray.get());
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000304 result->append(new SkPDFInt(advanceInfo->fStartId))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000305 result->append(advanceArray.get());
306 break;
307 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000308 case SkAdvancedTypefaceMetrics::WidthRange::kRun: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000309 SkASSERT(advanceInfo->fAdvance.count() == 1);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000310 result->append(new SkPDFInt(advanceInfo->fStartId))->unref();
311 result->append(new SkPDFInt(advanceInfo->fEndId))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000312 appendAdvance(advanceInfo->fAdvance[0], emSize, result);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000313 break;
314 }
315 }
316 }
317 return result;
318}
319
320} // namespace
321
322/* Font subset design: It would be nice to be able to subset fonts
323 * (particularly type 3 fonts), but it's a lot of work and not a priority.
324 *
325 * Resources are canonicalized and uniqueified by pointer so there has to be
326 * some additional state indicating which subset of the font is used. It
327 * must be maintained at the page granularity and then combined at the document
328 * granularity. a) change SkPDFFont to fill in its state on demand, kind of
329 * like SkPDFGraphicState. b) maintain a per font glyph usage class in each
330 * page/pdf device. c) in the document, retrieve the per font glyph usage
331 * from each page and combine it and ask for a resource with that subset.
332 */
333
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000334SkPDFFont::~SkPDFFont() {
335 SkAutoMutexAcquire lock(canonicalFontsMutex());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000336 int index;
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000337 if (find(SkTypeface::UniqueID(fTypeface.get()), fFirstGlyphID, &index)) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000338 canonicalFonts().removeShuffle(index);
339#ifdef SK_DEBUG
340 SkASSERT(!fDescendant);
341 } else {
342 SkASSERT(fDescendant);
343#endif
344 }
345 fResources.unrefAll();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000346}
347
348void SkPDFFont::getResources(SkTDArray<SkPDFObject*>* resourceList) {
349 resourceList->setReserve(resourceList->count() + fResources.count());
350 for (int i = 0; i < fResources.count(); i++) {
351 resourceList->push(fResources[i]);
352 fResources[i]->ref();
353 fResources[i]->getResources(resourceList);
354 }
355}
356
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000357SkTypeface* SkPDFFont::typeface() {
358 return fTypeface.get();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000359}
360
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000361bool SkPDFFont::hasGlyph(uint16_t id) {
362 return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0;
363}
364
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000365bool SkPDFFont::multiByteGlyphs() {
366 return fMultiByteGlyphs;
367}
368
vandebo@chromium.org01294102011-02-28 19:52:18 +0000369size_t SkPDFFont::glyphsToPDFFontEncoding(uint16_t* glyphIDs,
370 size_t numGlyphs) {
371 // A font with multibyte glyphs will support all glyph IDs in a single font.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000372 if (fMultiByteGlyphs) {
vandebo@chromium.org01294102011-02-28 19:52:18 +0000373 return numGlyphs;
374 }
375
376 for (size_t i = 0; i < numGlyphs; i++) {
377 if (glyphIDs[i] == 0) {
378 continue;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000379 }
vandebo@chromium.org01294102011-02-28 19:52:18 +0000380 if (glyphIDs[i] < fFirstGlyphID || glyphIDs[i] > fLastGlyphID) {
381 return i;
382 }
383 glyphIDs[i] -= (fFirstGlyphID - 1);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000384 }
385
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000386 return numGlyphs;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000387}
388
389// static
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000390SkPDFFont* SkPDFFont::getFontResource(SkTypeface* typeface, uint16_t glyphID) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000391 SkAutoMutexAcquire lock(canonicalFontsMutex());
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000392 const uint32_t fontID = SkTypeface::UniqueID(typeface);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000393 int index;
394 if (find(fontID, glyphID, &index)) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000395 canonicalFonts()[index].fFont->ref();
396 return canonicalFonts()[index].fFont;
397 }
398
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000399 SkRefPtr<SkAdvancedTypefaceMetrics> fontInfo;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000400 SkPDFDict* fontDescriptor = NULL;
401 if (index >= 0) {
402 SkPDFFont* relatedFont = canonicalFonts()[index].fFont;
403 SkASSERT(relatedFont->fFontInfo.get());
404 fontInfo = relatedFont->fFontInfo;
405 fontDescriptor = relatedFont->fDescriptor.get();
406 } else {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000407 fontInfo = SkFontHost::GetAdvancedTypefaceMetrics(fontID, true);
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000408 SkSafeUnref(fontInfo.get()); // SkRefPtr and Get both took a reference.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000409 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000410
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000411 SkPDFFont* font = new SkPDFFont(fontInfo.get(), typeface, glyphID, false,
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000412 fontDescriptor);
413 FontRec newEntry(font, fontID, font->fFirstGlyphID);
414 index = canonicalFonts().count();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000415 canonicalFonts().push(newEntry);
416 return font; // Return the reference new SkPDFFont() created.
417}
418
419// static
420SkTDArray<SkPDFFont::FontRec>& SkPDFFont::canonicalFonts() {
421 // This initialization is only thread safe with gcc.
422 static SkTDArray<FontRec> gCanonicalFonts;
423 return gCanonicalFonts;
424}
425
426// static
427SkMutex& SkPDFFont::canonicalFontsMutex() {
428 // This initialization is only thread safe with gcc.
429 static SkMutex gCanonicalFontsMutex;
430 return gCanonicalFontsMutex;
431}
432
433// static
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000434bool SkPDFFont::find(uint32_t fontID, uint16_t glyphID, int* index) {
435 // TODO(vandebo) optimize this, do only one search?
436 FontRec search(NULL, fontID, glyphID);
437 *index = canonicalFonts().find(search);
438 if (*index >= 0)
439 return true;
440 search.fGlyphID = 0;
441 *index = canonicalFonts().find(search);
442 return false;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000443}
444
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000445SkPDFFont::SkPDFFont(class SkAdvancedTypefaceMetrics* fontInfo,
446 SkTypeface* typeface,
447 uint16_t glyphID,
448 bool descendantFont,
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000449 SkPDFDict* fontDescriptor)
450 : SkPDFDict("Font"),
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000451 fTypeface(typeface),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000452#ifdef SK_DEBUG
453 fDescendant(descendantFont),
454#endif
455 fMultiByteGlyphs(false),
456 fFirstGlyphID(1),
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000457 fLastGlyphID(fontInfo ? fontInfo->fLastGlyphID : 0),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000458 fFontInfo(fontInfo),
459 fDescriptor(fontDescriptor) {
460
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000461 SkAdvancedTypefaceMetrics::FontType type;
462 if (fontInfo) {
463 type = fontInfo->fType;
464 } else {
465 type = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
466 }
467
468 if (fontInfo && fontInfo->fMultiMaster) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000469 SkASSERT(false); // Not supported yet.
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000470 fontInfo->fType = SkAdvancedTypefaceMetrics::kOther_Font;
471 }
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000472 if (type == SkAdvancedTypefaceMetrics::kType1CID_Font ||
473 type == SkAdvancedTypefaceMetrics::kTrueType_Font) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000474 if (descendantFont) {
475 populateCIDFont();
476 } else {
477 populateType0Font();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000478 }
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000479 // No need to hold onto the font info for fonts types that
480 // support multibyte glyphs.
481 fFontInfo = NULL;
482 return;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000483 }
484
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000485 if (type == SkAdvancedTypefaceMetrics::kType1_Font &&
486 populateType1Font(glyphID)) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000487 return;
488 }
489
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000490 SkASSERT(type == SkAdvancedTypefaceMetrics::kType1_Font ||
491 type == SkAdvancedTypefaceMetrics::kCFF_Font ||
492 type == SkAdvancedTypefaceMetrics::kOther_Font ||
493 type == SkAdvancedTypefaceMetrics::kNotEmbeddable_Font);
494 populateType3Font(glyphID);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000495}
496
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000497void SkPDFFont::populateType0Font() {
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000498 // TODO(vandebo) add a ToUnicode mapping.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000499 fMultiByteGlyphs = true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000500
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000501 insert("Subtype", new SkPDFName("Type0"))->unref();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000502 insert("BaseFont", new SkPDFName(fFontInfo->fFontName))->unref();
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000503 insert("Encoding", new SkPDFName("Identity-H"))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000504
505 SkRefPtr<SkPDFArray> descendantFonts = new SkPDFArray();
506 descendantFonts->unref(); // SkRefPtr and new took a reference.
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000507
508 // Pass ref new created to fResources.
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000509 fResources.push(
510 new SkPDFFont(fFontInfo.get(), fTypeface.get(), 1, true, NULL));
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000511 descendantFonts->append(new SkPDFObjRef(fResources.top()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000512 insert("DescendantFonts", descendantFonts.get());
513}
514
515void SkPDFFont::populateCIDFont() {
516 fMultiByteGlyphs = true;
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000517 insert("BaseFont", new SkPDFName(fFontInfo->fFontName))->unref();
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000518
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000519 if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kType1CID_Font) {
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000520 insert("Subtype", new SkPDFName("CIDFontType0"))->unref();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000521 } else if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kTrueType_Font) {
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000522 insert("Subtype", new SkPDFName("CIDFontType2"))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000523 } else {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000524 SkASSERT(false);
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000525 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000526
527 SkRefPtr<SkPDFDict> sysInfo = new SkPDFDict;
528 sysInfo->unref(); // SkRefPtr and new both took a reference.
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000529 sysInfo->insert("Registry", new SkPDFString("Adobe"))->unref();
530 sysInfo->insert("Ordering", new SkPDFString("Identity"))->unref();
531 sysInfo->insert("Supplement", new SkPDFInt(0))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000532 insert("CIDSystemInfo", sysInfo.get());
533
534 addFontDescriptor(0);
535
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000536 if (fFontInfo->fGlyphWidths.get()) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000537 int16_t defaultWidth = 0;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000538 SkRefPtr<SkPDFArray> widths =
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000539 composeAdvanceData(fFontInfo->fGlyphWidths.get(),
540 fFontInfo->fEmSize, &appendWidth, &defaultWidth);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000541 widths->unref(); // SkRefPtr and compose both took a reference.
542 if (widths->size())
543 insert("W", widths.get());
544 if (defaultWidth != 0) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000545 insert("DW", new SkPDFScalar(scaleFromFontUnits(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000546 defaultWidth, fFontInfo->fEmSize)))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000547 }
548 }
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000549 if (fFontInfo->fVerticalMetrics.get()) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000550 struct SkAdvancedTypefaceMetrics::VerticalMetric defaultAdvance;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000551 defaultAdvance.fVerticalAdvance = 0;
552 defaultAdvance.fOriginXDisp = 0;
553 defaultAdvance.fOriginYDisp = 0;
554 SkRefPtr<SkPDFArray> advances =
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000555 composeAdvanceData(fFontInfo->fVerticalMetrics.get(),
556 fFontInfo->fEmSize, &appendVerticalAdvance,
557 &defaultAdvance);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000558 advances->unref(); // SkRefPtr and compose both took a ref.
559 if (advances->size())
560 insert("W2", advances.get());
561 if (defaultAdvance.fVerticalAdvance ||
562 defaultAdvance.fOriginXDisp ||
563 defaultAdvance.fOriginYDisp) {
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000564 insert("DW2", appendVerticalAdvance(defaultAdvance,
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000565 fFontInfo->fEmSize,
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000566 new SkPDFArray))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000567 }
568 }
569}
570
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000571bool SkPDFFont::populateType1Font(int16_t glyphID) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000572 SkASSERT(!fFontInfo->fVerticalMetrics.get());
573 SkASSERT(fFontInfo->fGlyphWidths.get());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000574
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000575 adjustGlyphRangeForSingleByteEncoding(glyphID);
576
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000577 int16_t defaultWidth = 0;
578 const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry = NULL;
579 const SkAdvancedTypefaceMetrics::WidthRange* widthEntry;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000580 for (widthEntry = fFontInfo.get()->fGlyphWidths.get();
581 widthEntry != NULL;
582 widthEntry = widthEntry->fNext.get()) {
583 switch (widthEntry->fType) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000584 case SkAdvancedTypefaceMetrics::WidthRange::kDefault:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000585 defaultWidth = widthEntry->fAdvance[0];
586 break;
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000587 case SkAdvancedTypefaceMetrics::WidthRange::kRun:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000588 SkASSERT(false);
589 break;
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000590 case SkAdvancedTypefaceMetrics::WidthRange::kRange:
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000591 SkASSERT(widthRangeEntry == NULL);
592 widthRangeEntry = widthEntry;
593 break;
594 }
595 }
596
597 if (!addFontDescriptor(defaultWidth))
598 return false;
599
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000600 insert("Subtype", new SkPDFName("Type1"))->unref();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000601 insert("BaseFont", new SkPDFName(fFontInfo->fFontName))->unref();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000602
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000603 addWidthInfoFromRange(defaultWidth, widthRangeEntry);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000604
605 SkRefPtr<SkPDFDict> encoding = new SkPDFDict("Encoding");
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000606 encoding->unref(); // SkRefPtr and new both took a reference.
607 insert("Encoding", encoding.get());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000608
609 SkRefPtr<SkPDFArray> encDiffs = new SkPDFArray;
610 encDiffs->unref(); // SkRefPtr and new both took a reference.
611 encoding->insert("Differences", encDiffs.get());
612
613 encDiffs->reserve(fLastGlyphID - fFirstGlyphID + 2);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000614 encDiffs->append(new SkPDFInt(1))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000615 for (int gID = fFirstGlyphID; gID <= fLastGlyphID; gID++) {
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000616 encDiffs->append(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000617 new SkPDFName(fFontInfo->fGlyphNames->get()[gID]))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000618 }
619
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000620 if (fFontInfo->fLastGlyphID <= 255)
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000621 fFontInfo = NULL;
622 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000623}
624
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000625void SkPDFFont::populateType3Font(int16_t glyphID) {
626 SkPaint paint;
627 paint.setTypeface(fTypeface.get());
628 paint.setTextSize(1000);
629 SkAutoGlyphCache autoCache(paint, NULL);
630 SkGlyphCache* cache = autoCache.getCache();
631 // If fLastGlyphID isn't set (because there is not fFontInfo), look it up.
632 if (fLastGlyphID == 0) {
633 fLastGlyphID = cache->getGlyphCount() - 1;
634 }
635
636 adjustGlyphRangeForSingleByteEncoding(glyphID);
637
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000638 insert("Subtype", new SkPDFName("Type3"))->unref();
639 // Flip about the x-axis and scale by 1/1000.
640 SkMatrix fontMatrix;
641 fontMatrix.setScale(SkScalarInvert(1000), -SkScalarInvert(1000));
642 insert("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix))->unref();
643
644 SkRefPtr<SkPDFDict> charProcs = new SkPDFDict;
645 charProcs->unref(); // SkRefPtr and new both took a reference.
646 insert("CharProcs", charProcs.get());
647
648 SkRefPtr<SkPDFDict> encoding = new SkPDFDict("Encoding");
649 encoding->unref(); // SkRefPtr and new both took a reference.
650 insert("Encoding", encoding.get());
651
652 SkRefPtr<SkPDFArray> encDiffs = new SkPDFArray;
653 encDiffs->unref(); // SkRefPtr and new both took a reference.
654 encoding->insert("Differences", encDiffs.get());
655 encDiffs->reserve(fLastGlyphID - fFirstGlyphID + 2);
656 encDiffs->append(new SkPDFInt(1))->unref();
657
658 SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
659 widthArray->unref(); // SkRefPtr and new both took a ref.
660
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000661 SkIRect bbox = SkIRect::MakeEmpty();
662 for (int gID = fFirstGlyphID; gID <= fLastGlyphID; gID++) {
663 SkString characterName;
664 characterName.printf("gid%d", gID);
665 encDiffs->append(new SkPDFName(characterName))->unref();
666
667 const SkGlyph glyph = cache->getGlyphIDMetrics(gID);
668 appendWidth(SkFixedToFloat(glyph.fAdvanceX), 1000, widthArray.get());
669 SkIRect glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
670 glyph.fWidth, glyph.fHeight);
671 bbox.join(glyphBBox);
672
673 SkString content;
674 setGlyphWidthAndBoundingBox(SkFixedToScalar(glyph.fAdvanceX), glyphBBox,
675 &content);
676 const SkPath* path = cache->findPath(glyph);
677 if (path) {
678 SkPDFUtils::EmitPath(*path, &content);
679 SkPDFUtils::PaintPath(paint.getStyle(), path->getFillType(),
680 &content);
681 }
682 SkRefPtr<SkStream> glyphStream =
683 new SkMemoryStream(content.c_str(), content.size(), true);
684 glyphStream->unref(); // SkRefPtr and new both took a ref.
685 SkRefPtr<SkPDFStream> glyphDescription =
686 new SkPDFStream(glyphStream.get());
687 // SkRefPtr and new both ref()'d charProcs, pass one.
688 fResources.push(glyphDescription.get());
689 charProcs->insert(characterName.c_str(),
690 new SkPDFObjRef(glyphDescription.get()))->unref();
691 }
692
693 insert("FontBBox", makeFontBBox(bbox, 1000))->unref();
694 insert("FirstChar", new SkPDFInt(fFirstGlyphID))->unref();
695 insert("LastChar", new SkPDFInt(fLastGlyphID))->unref();
696 insert("Widths", widthArray.get());
697
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000698 if (fFontInfo && fFontInfo->fLastGlyphID <= 255)
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000699 fFontInfo = NULL;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000700}
701
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000702bool SkPDFFont::addFontDescriptor(int16_t defaultWidth) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000703 if (fDescriptor.get() != NULL) {
704 fResources.push(fDescriptor.get());
705 fDescriptor->ref();
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000706 insert("FontDescriptor", new SkPDFObjRef(fDescriptor.get()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000707 return true;
708 }
709
710 fDescriptor = new SkPDFDict("FontDescriptor");
711 fDescriptor->unref(); // SkRefPtr and new both took a ref.
712
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000713 switch (fFontInfo->fType) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000714 case SkAdvancedTypefaceMetrics::kType1_Font: {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000715 size_t header, data, trailer;
716 SkRefPtr<SkStream> rawFontData =
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000717 SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get()));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000718 rawFontData->unref(); // SkRefPtr and OpenStream both took a ref.
719 SkStream* fontData = handleType1Stream(rawFontData.get(), &header,
720 &data, &trailer);
721 if (fontData == NULL)
722 return false;
723 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData);
724 // SkRefPtr and new both ref()'d fontStream, pass one.
725 fResources.push(fontStream.get());
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000726 fontStream->insert("Length1", new SkPDFInt(header))->unref();
727 fontStream->insert("Length2", new SkPDFInt(data))->unref();
728 fontStream->insert("Length3", new SkPDFInt(trailer))->unref();
729 fDescriptor->insert("FontFile",
730 new SkPDFObjRef(fontStream.get()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000731 break;
732 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000733 case SkAdvancedTypefaceMetrics::kTrueType_Font: {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000734 SkRefPtr<SkStream> fontData =
735 SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get()));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000736 fontData->unref(); // SkRefPtr and OpenStream both took a ref.
737 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
738 // SkRefPtr and new both ref()'d fontStream, pass one.
739 fResources.push(fontStream.get());
740
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000741 fontStream->insert("Length1",
742 new SkPDFInt(fontData->getLength()))->unref();
743 fDescriptor->insert("FontFile2",
744 new SkPDFObjRef(fontStream.get()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000745 break;
746 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000747 case SkAdvancedTypefaceMetrics::kCFF_Font:
748 case SkAdvancedTypefaceMetrics::kType1CID_Font: {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000749 SkRefPtr<SkStream> fontData =
750 SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get()));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000751 fontData->unref(); // SkRefPtr and OpenStream both took a ref.
752 SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
753 // SkRefPtr and new both ref()'d fontStream, pass one.
754 fResources.push(fontStream.get());
755
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000756 if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kCFF_Font) {
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000757 fontStream->insert("Subtype", new SkPDFName("Type1C"))->unref();
758 } else {
759 fontStream->insert("Subtype",
760 new SkPDFName("CIDFontType0c"))->unref();
761 }
762 fDescriptor->insert("FontFile3",
763 new SkPDFObjRef(fontStream.get()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000764 break;
765 }
766 default:
767 SkASSERT(false);
768 }
769
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000770 const uint16_t emSize = fFontInfo->fEmSize;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000771 fResources.push(fDescriptor.get());
772 fDescriptor->ref();
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000773 insert("FontDescriptor", new SkPDFObjRef(fDescriptor.get()))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000774
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000775 fDescriptor->insert("FontName", new SkPDFName(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000776 fFontInfo->fFontName))->unref();
777 fDescriptor->insert("Flags", new SkPDFInt(fFontInfo->fStyle))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000778 fDescriptor->insert("Ascent", new SkPDFScalar(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000779 scaleFromFontUnits(fFontInfo->fAscent, emSize)))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000780 fDescriptor->insert("Descent", new SkPDFScalar(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000781 scaleFromFontUnits(fFontInfo->fDescent, emSize)))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000782 fDescriptor->insert("StemV", new SkPDFScalar(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000783 scaleFromFontUnits(fFontInfo->fStemV, emSize)))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000784 fDescriptor->insert("CapHeight", new SkPDFScalar(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000785 scaleFromFontUnits(fFontInfo->fCapHeight, emSize)))->unref();
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000786 fDescriptor->insert("ItalicAngle", new SkPDFInt(
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000787 fFontInfo->fItalicAngle))->unref();
788 fDescriptor->insert("FontBBox", makeFontBBox(fFontInfo->fBBox,
789 fFontInfo->fEmSize))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000790
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000791 if (defaultWidth > 0) {
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000792 fDescriptor->insert("MissingWidth", new SkPDFScalar(
793 scaleFromFontUnits(defaultWidth, emSize)))->unref();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000794 }
795 return true;
796}
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000797void SkPDFFont::addWidthInfoFromRange(
798 int16_t defaultWidth,
799 const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry) {
800 SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
801 widthArray->unref(); // SkRefPtr and new both took a ref.
802 int firstChar = 0;
803 if (widthRangeEntry) {
804 const uint16_t emSize = fFontInfo->fEmSize;
805 int startIndex = fFirstGlyphID - widthRangeEntry->fStartId;
806 int endIndex = startIndex + fLastGlyphID - fFirstGlyphID + 1;
807 if (startIndex < 0)
808 startIndex = 0;
809 if (endIndex > widthRangeEntry->fAdvance.count())
810 endIndex = widthRangeEntry->fAdvance.count();
811 if (widthRangeEntry->fStartId == 0) {
812 appendWidth(widthRangeEntry->fAdvance[0], emSize, widthArray.get());
813 } else {
814 firstChar = startIndex + widthRangeEntry->fStartId;
815 }
816 for (int i = startIndex; i < endIndex; i++)
817 appendWidth(widthRangeEntry->fAdvance[i], emSize, widthArray.get());
818 } else {
819 appendWidth(defaultWidth, 1000, widthArray.get());
820 }
821 insert("FirstChar", new SkPDFInt(firstChar))->unref();
822 insert("LastChar",
823 new SkPDFInt(firstChar + widthArray->size() - 1))->unref();
824 insert("Widths", widthArray.get());
825}
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000826
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000827void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(int16_t glyphID) {
828 // Single byte glyph encoding supports a max of 255 glyphs.
829 fFirstGlyphID = glyphID - (glyphID - 1) % 255;
830 if (fLastGlyphID > fFirstGlyphID + 255 - 1) {
831 fLastGlyphID = fFirstGlyphID + 255 - 1;
832 }
833}
834
835
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000836bool SkPDFFont::FontRec::operator==(const SkPDFFont::FontRec& b) const {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000837 if (fFontID != b.fFontID)
838 return false;
839 if (fFont != NULL && b.fFont != NULL) {
840 return fFont->fFirstGlyphID == b.fFont->fFirstGlyphID &&
841 fFont->fLastGlyphID == b.fFont->fLastGlyphID;
842 }
843 if (fGlyphID == 0 || b.fGlyphID == 0)
844 return true;
845
846 if (fFont != NULL) {
847 return fFont->fFirstGlyphID <= b.fGlyphID &&
848 b.fGlyphID <= fFont->fLastGlyphID;
849 } else if (b.fFont != NULL) {
850 return b.fFont->fFirstGlyphID <= fGlyphID &&
851 fGlyphID <= b.fFont->fLastGlyphID;
852 }
853 return fGlyphID == b.fGlyphID;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000854}
855
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000856SkPDFFont::FontRec::FontRec(SkPDFFont* font, uint32_t fontID, uint16_t glyphID)
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000857 : fFont(font),
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000858 fFontID(fontID),
859 fGlyphID(glyphID) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000860}