Change the translation of the "Help" menu item to "?", so that the menu can be displa...
[reactos.git] / rosapps / smartpdf / poppler / fofi / FoFiTrueType.cc
1 //========================================================================
2 //
3 // FoFiTrueType.cc
4 //
5 // Copyright 1999-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <config.h>
10
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14
15 #include <stdlib.h>
16 #include <string.h>
17 #include "goo/gtypes.h"
18 #include "goo/gmem.h"
19 #include "goo/GooString.h"
20 #include "goo/GooHash.h"
21 #include "FoFiTrueType.h"
22
23 //
24 // Terminology
25 // -----------
26 //
27 // character code = number used as an element of a text string
28 //
29 // character name = glyph name = name for a particular glyph within a
30 // font
31 //
32 // glyph index = GID = position (within some internal table in the font)
33 // where the instructions to draw a particular glyph are
34 // stored
35 //
36 // Type 1 fonts
37 // ------------
38 //
39 // Type 1 fonts contain:
40 //
41 // Encoding: array of glyph names, maps char codes to glyph names
42 //
43 // Encoding[charCode] = charName
44 //
45 // CharStrings: dictionary of instructions, keyed by character names,
46 // maps character name to glyph data
47 //
48 // CharStrings[charName] = glyphData
49 //
50 // TrueType fonts
51 // --------------
52 //
53 // TrueType fonts contain:
54 //
55 // 'cmap' table: mapping from character code to glyph index; there may
56 // be multiple cmaps in a TrueType font
57 //
58 // cmap[charCode] = gid
59 //
60 // 'post' table: mapping from glyph index to glyph name
61 //
62 // post[gid] = glyphName
63 //
64 // Type 42 fonts
65 // -------------
66 //
67 // Type 42 fonts contain:
68 //
69 // Encoding: array of glyph names, maps char codes to glyph names
70 //
71 // Encoding[charCode] = charName
72 //
73 // CharStrings: dictionary of glyph indexes, keyed by character names,
74 // maps character name to glyph index
75 //
76 // CharStrings[charName] = gid
77 //
78
79 //------------------------------------------------------------------------
80
81 #define ttcfTag 0x74746366
82
83 //------------------------------------------------------------------------
84
85 struct TrueTypeTable {
86 Guint tag;
87 Guint checksum;
88 int offset;
89 int origOffset;
90 int len;
91 };
92
93 struct TrueTypeCmap {
94 int platform;
95 int encoding;
96 int offset;
97 int len;
98 int fmt;
99 };
100
101 struct TrueTypeLoca {
102 int idx;
103 int origOffset;
104 int newOffset;
105 int len;
106 };
107
108 #define cmapTag 0x636d6170
109 #define glyfTag 0x676c7966
110 #define headTag 0x68656164
111 #define locaTag 0x6c6f6361
112 #define nameTag 0x6e616d65
113 #define postTag 0x706f7374
114
115 static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) {
116 TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
117 TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
118
119 if (loca1->origOffset == loca2->origOffset) {
120 return loca1->idx - loca2->idx;
121 }
122 return loca1->origOffset - loca2->origOffset;
123 }
124
125 static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) {
126 TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
127 TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
128
129 return loca1->idx - loca2->idx;
130 }
131
132 static int cmpTrueTypeTableTag(const void *p1, const void *p2) {
133 TrueTypeTable *tab1 = (TrueTypeTable *)p1;
134 TrueTypeTable *tab2 = (TrueTypeTable *)p2;
135
136 return (int)tab1->tag - (int)tab2->tag;
137 }
138
139 //------------------------------------------------------------------------
140
141 struct T42Table {
142 char *tag; // 4-byte tag
143 GBool required; // required by the TrueType spec?
144 };
145
146 // TrueType tables to be embedded in Type 42 fonts.
147 // NB: the table names must be in alphabetical order here.
148 #define nT42Tables 11
149 static T42Table t42Tables[nT42Tables] = {
150 { "cvt ", gTrue },
151 { "fpgm", gTrue },
152 { "glyf", gTrue },
153 { "head", gTrue },
154 { "hhea", gTrue },
155 { "hmtx", gTrue },
156 { "loca", gTrue },
157 { "maxp", gTrue },
158 { "prep", gTrue },
159 { "vhea", gFalse },
160 { "vmtx", gFalse }
161 };
162 #define t42HeadTable 3
163 #define t42LocaTable 6
164 #define t42GlyfTable 2
165 #define t42VheaTable 9
166 #define t42VmtxTable 10
167
168 //------------------------------------------------------------------------
169
170 // Glyph names in some arbitrary standard order that Apple uses for
171 // their TrueType fonts.
172 static char *macGlyphNames[258] = {
173 ".notdef", "null", "CR", "space",
174 "exclam", "quotedbl", "numbersign", "dollar",
175 "percent", "ampersand", "quotesingle", "parenleft",
176 "parenright", "asterisk", "plus", "comma",
177 "hyphen", "period", "slash", "zero",
178 "one", "two", "three", "four",
179 "five", "six", "seven", "eight",
180 "nine", "colon", "semicolon", "less",
181 "equal", "greater", "question", "at",
182 "A", "B", "C", "D",
183 "E", "F", "G", "H",
184 "I", "J", "K", "L",
185 "M", "N", "O", "P",
186 "Q", "R", "S", "T",
187 "U", "V", "W", "X",
188 "Y", "Z", "bracketleft", "backslash",
189 "bracketright", "asciicircum", "underscore", "grave",
190 "a", "b", "c", "d",
191 "e", "f", "g", "h",
192 "i", "j", "k", "l",
193 "m", "n", "o", "p",
194 "q", "r", "s", "t",
195 "u", "v", "w", "x",
196 "y", "z", "braceleft", "bar",
197 "braceright", "asciitilde", "Adieresis", "Aring",
198 "Ccedilla", "Eacute", "Ntilde", "Odieresis",
199 "Udieresis", "aacute", "agrave", "acircumflex",
200 "adieresis", "atilde", "aring", "ccedilla",
201 "eacute", "egrave", "ecircumflex", "edieresis",
202 "iacute", "igrave", "icircumflex", "idieresis",
203 "ntilde", "oacute", "ograve", "ocircumflex",
204 "odieresis", "otilde", "uacute", "ugrave",
205 "ucircumflex", "udieresis", "dagger", "degree",
206 "cent", "sterling", "section", "bullet",
207 "paragraph", "germandbls", "registered", "copyright",
208 "trademark", "acute", "dieresis", "notequal",
209 "AE", "Oslash", "infinity", "plusminus",
210 "lessequal", "greaterequal", "yen", "mu1",
211 "partialdiff", "summation", "product", "pi",
212 "integral", "ordfeminine", "ordmasculine", "Ohm",
213 "ae", "oslash", "questiondown", "exclamdown",
214 "logicalnot", "radical", "florin", "approxequal",
215 "increment", "guillemotleft", "guillemotright", "ellipsis",
216 "nbspace", "Agrave", "Atilde", "Otilde",
217 "OE", "oe", "endash", "emdash",
218 "quotedblleft", "quotedblright", "quoteleft", "quoteright",
219 "divide", "lozenge", "ydieresis", "Ydieresis",
220 "fraction", "currency", "guilsinglleft", "guilsinglright",
221 "fi", "fl", "daggerdbl", "periodcentered",
222 "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
223 "Ecircumflex", "Aacute", "Edieresis", "Egrave",
224 "Iacute", "Icircumflex", "Idieresis", "Igrave",
225 "Oacute", "Ocircumflex", "applelogo", "Ograve",
226 "Uacute", "Ucircumflex", "Ugrave", "dotlessi",
227 "circumflex", "tilde", "overscore", "breve",
228 "dotaccent", "ring", "cedilla", "hungarumlaut",
229 "ogonek", "caron", "Lslash", "lslash",
230 "Scaron", "scaron", "Zcaron", "zcaron",
231 "brokenbar", "Eth", "eth", "Yacute",
232 "yacute", "Thorn", "thorn", "minus",
233 "multiply", "onesuperior", "twosuperior", "threesuperior",
234 "onehalf", "onequarter", "threequarters", "franc",
235 "Gbreve", "gbreve", "Idot", "Scedilla",
236 "scedilla", "Cacute", "cacute", "Ccaron",
237 "ccaron", "dmacron"
238 };
239
240 //------------------------------------------------------------------------
241 // FoFiTrueType
242 //------------------------------------------------------------------------
243
244 FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA, int faceIndexA) {
245 FoFiTrueType *ff;
246
247 ff = new FoFiTrueType(fileA, lenA, gFalse, faceIndexA);
248 if (!ff->parsedOk) {
249 delete ff;
250 return NULL;
251 }
252 return ff;
253 }
254
255 FoFiTrueType *FoFiTrueType::load(char *fileName, int faceIndexA) {
256 FoFiTrueType *ff;
257 char *fileA;
258 int lenA;
259
260 if (!(fileA = FoFiBase::readFile(fileName, &lenA))) {
261 return NULL;
262 }
263 ff = new FoFiTrueType(fileA, lenA, gTrue, faceIndexA);
264 if (!ff->parsedOk) {
265 delete ff;
266 return NULL;
267 }
268 return ff;
269 }
270
271 FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA):
272 FoFiBase(fileA, lenA, freeFileDataA)
273 {
274 tables = NULL;
275 nTables = 0;
276 cmaps = NULL;
277 nCmaps = 0;
278 nameToGID = NULL;
279 parsedOk = gFalse;
280 faceIndex = faceIndexA;
281
282 parse();
283 }
284
285 FoFiTrueType::~FoFiTrueType() {
286 gfree(tables);
287 gfree(cmaps);
288 if (nameToGID) {
289 delete nameToGID;
290 }
291 }
292
293 int FoFiTrueType::getNumCmaps() {
294 return nCmaps;
295 }
296
297 int FoFiTrueType::getCmapPlatform(int i) {
298 return cmaps[i].platform;
299 }
300
301 int FoFiTrueType::getCmapEncoding(int i) {
302 return cmaps[i].encoding;
303 }
304
305 int FoFiTrueType::findCmap(int platform, int encoding) {
306 int i;
307
308 for (i = 0; i < nCmaps; ++i) {
309 if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) {
310 return i;
311 }
312 }
313 return -1;
314 }
315
316 Gushort FoFiTrueType::mapCodeToGID(int i, int c) {
317 Gushort gid;
318 int segCnt, segEnd, segStart, segDelta, segOffset;
319 int cmapFirst, cmapLen;
320 int pos, a, b, m;
321 GBool ok;
322
323 if (i < 0 || i >= nCmaps) {
324 return 0;
325 }
326 ok = gTrue;
327 pos = cmaps[i].offset;
328 switch (cmaps[i].fmt) {
329 case 0:
330 if (c < 0 || c >= cmaps[i].len - 6) {
331 return 0;
332 }
333 gid = getU8(cmaps[i].offset + 6 + c, &ok);
334 break;
335 case 4:
336 segCnt = getU16BE(pos + 6, &ok) / 2;
337 a = -1;
338 b = segCnt - 1;
339 segEnd = getU16BE(pos + 14 + 2*b, &ok);
340 if (c > segEnd) {
341 // malformed font -- the TrueType spec requires the last segEnd
342 // to be 0xffff
343 return 0;
344 }
345 // invariant: seg[a].end < code <= seg[b].end
346 while (b - a > 1 && ok) {
347 m = (a + b) / 2;
348 segEnd = getU16BE(pos + 14 + 2*m, &ok);
349 if (segEnd < c) {
350 a = m;
351 } else {
352 b = m;
353 }
354 }
355 segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok);
356 segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok);
357 segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok);
358 if (c < segStart) {
359 return 0;
360 }
361 if (segOffset == 0) {
362 gid = (c + segDelta) & 0xffff;
363 } else {
364 gid = getU16BE(pos + 16 + 6*segCnt + 2*b +
365 segOffset + 2 * (c - segStart), &ok);
366 if (gid != 0) {
367 gid = (gid + segDelta) & 0xffff;
368 }
369 }
370 break;
371 case 6:
372 cmapFirst = getU16BE(pos + 6, &ok);
373 cmapLen = getU16BE(pos + 8, &ok);
374 if (c < cmapFirst || c >= cmapFirst + cmapLen) {
375 return 0;
376 }
377 gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok);
378 break;
379 default:
380 return 0;
381 }
382 if (!ok) {
383 return 0;
384 }
385 return gid;
386 }
387
388 int FoFiTrueType::mapNameToGID(char *name) {
389 if (!nameToGID) {
390 return 0;
391 }
392 return nameToGID->lookupInt(name);
393 }
394
395 int FoFiTrueType::getEmbeddingRights() {
396 int i, fsType;
397 GBool ok;
398
399 if ((i = seekTable("OS/2")) < 0) {
400 return 4;
401 }
402 ok = gTrue;
403 fsType = getU16BE(tables[i].offset + 8, &ok);
404 if (!ok) {
405 return 4;
406 }
407 if (fsType & 0x0008) {
408 return 2;
409 }
410 if (fsType & 0x0004) {
411 return 1;
412 }
413 if (fsType & 0x0002) {
414 return 0;
415 }
416 return 3;
417 }
418
419 void FoFiTrueType::convertToType42(char *psName, char **encoding,
420 Gushort *codeToGID,
421 FoFiOutputFunc outputFunc,
422 void *outputStream) {
423 char buf[512];
424 GBool ok;
425
426 // write the header
427 ok = gTrue;
428 sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
429 (*outputFunc)(outputStream, buf, strlen(buf));
430
431 // begin the font dictionary
432 (*outputFunc)(outputStream, "10 dict begin\n", 14);
433 (*outputFunc)(outputStream, "/FontName /", 11);
434 (*outputFunc)(outputStream, psName, strlen(psName));
435 (*outputFunc)(outputStream, " def\n", 5);
436 (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
437 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
438 sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
439 bbox[0], bbox[1], bbox[2], bbox[3]);
440 (*outputFunc)(outputStream, buf, strlen(buf));
441 (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
442
443 // write the guts of the dictionary
444 cvtEncoding(encoding, outputFunc, outputStream);
445 cvtCharStrings(encoding, codeToGID, outputFunc, outputStream);
446 cvtSfnts(outputFunc, outputStream, NULL, gFalse);
447
448 // end the dictionary and define the font
449 (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
450 }
451
452 void FoFiTrueType::convertToCIDType2(char *psName,
453 Gushort *cidMap, int nCIDs,
454 GBool needVerticalMetrics,
455 FoFiOutputFunc outputFunc,
456 void *outputStream) {
457 char buf[512];
458 Gushort cid;
459 GBool ok;
460 int i, j, k;
461
462 // write the header
463 ok = gTrue;
464 sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
465 (*outputFunc)(outputStream, buf, strlen(buf));
466
467 // begin the font dictionary
468 (*outputFunc)(outputStream, "20 dict begin\n", 14);
469 (*outputFunc)(outputStream, "/CIDFontName /", 14);
470 (*outputFunc)(outputStream, psName, strlen(psName));
471 (*outputFunc)(outputStream, " def\n", 5);
472 (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19);
473 (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
474 (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
475 (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24);
476 (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27);
477 (*outputFunc)(outputStream, " /Supplement 0 def\n", 20);
478 (*outputFunc)(outputStream, " end def\n", 10);
479 (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
480 if (cidMap) {
481 sprintf(buf, "/CIDCount %d def\n", nCIDs);
482 (*outputFunc)(outputStream, buf, strlen(buf));
483 if (nCIDs > 32767) {
484 (*outputFunc)(outputStream, "/CIDMap [", 9);
485 for (i = 0; i < nCIDs; i += 32768 - 16) {
486 (*outputFunc)(outputStream, "<\n", 2);
487 for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
488 (*outputFunc)(outputStream, " ", 2);
489 for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
490 cid = cidMap[i+j+k];
491 sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
492 (*outputFunc)(outputStream, buf, strlen(buf));
493 }
494 (*outputFunc)(outputStream, "\n", 1);
495 }
496 (*outputFunc)(outputStream, " >", 3);
497 }
498 (*outputFunc)(outputStream, "\n", 1);
499 (*outputFunc)(outputStream, "] def\n", 6);
500 } else {
501 (*outputFunc)(outputStream, "/CIDMap <\n", 10);
502 for (i = 0; i < nCIDs; i += 16) {
503 (*outputFunc)(outputStream, " ", 2);
504 for (j = 0; j < 16 && i+j < nCIDs; ++j) {
505 cid = cidMap[i+j];
506 sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
507 (*outputFunc)(outputStream, buf, strlen(buf));
508 }
509 (*outputFunc)(outputStream, "\n", 1);
510 }
511 (*outputFunc)(outputStream, "> def\n", 6);
512 }
513 } else {
514 // direct mapping - just fill the string(s) with s[i]=i
515 sprintf(buf, "/CIDCount %d def\n", nGlyphs);
516 (*outputFunc)(outputStream, buf, strlen(buf));
517 if (nGlyphs > 32767) {
518 (*outputFunc)(outputStream, "/CIDMap [\n", 10);
519 for (i = 0; i < nGlyphs; i += 32767) {
520 j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
521 sprintf(buf, " %d string 0 1 %d {\n", 2 * j, j - 1);
522 (*outputFunc)(outputStream, buf, strlen(buf));
523 sprintf(buf, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
524 (*outputFunc)(outputStream, buf, strlen(buf));
525 sprintf(buf, " 1 index exch dup 2 mul 1 add exch %d add"
526 " 255 and put\n", i);
527 (*outputFunc)(outputStream, buf, strlen(buf));
528 (*outputFunc)(outputStream, " } for\n", 8);
529 }
530 (*outputFunc)(outputStream, "] def\n", 6);
531 } else {
532 sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs);
533 (*outputFunc)(outputStream, buf, strlen(buf));
534 sprintf(buf, " 0 1 %d {\n", nGlyphs - 1);
535 (*outputFunc)(outputStream, buf, strlen(buf));
536 (*outputFunc)(outputStream,
537 " 2 copy dup 2 mul exch -8 bitshift put\n", 42);
538 (*outputFunc)(outputStream,
539 " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
540 (*outputFunc)(outputStream, " } for\n", 8);
541 (*outputFunc)(outputStream, "def\n", 4);
542 }
543 }
544 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
545 sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
546 bbox[0], bbox[1], bbox[2], bbox[3]);
547 (*outputFunc)(outputStream, buf, strlen(buf));
548 (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
549 (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
550 (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
551 (*outputFunc)(outputStream, " /.notdef 0 def\n", 17);
552 (*outputFunc)(outputStream, " end readonly def\n", 19);
553
554 // write the guts of the dictionary
555 cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics);
556
557 // end the dictionary and define the font
558 (*outputFunc)(outputStream,
559 "CIDFontName currentdict end /CIDFont defineresource pop\n",
560 56);
561 }
562
563 void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
564 GBool needVerticalMetrics,
565 FoFiOutputFunc outputFunc,
566 void *outputStream) {
567 char buf[512];
568 GooString *sfntsName;
569 int n, i, j;
570
571 // write the Type 42 sfnts array
572 sfntsName = (new GooString(psName))->append("_sfnts");
573 cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics);
574 delete sfntsName;
575
576 // write the descendant Type 42 fonts
577 n = cidMap ? nCIDs : nGlyphs;
578 for (i = 0; i < n; i += 256) {
579 (*outputFunc)(outputStream, "10 dict begin\n", 14);
580 (*outputFunc)(outputStream, "/FontName /", 11);
581 (*outputFunc)(outputStream, psName, strlen(psName));
582 sprintf(buf, "_%02x def\n", i >> 8);
583 (*outputFunc)(outputStream, buf, strlen(buf));
584 (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
585 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
586 sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
587 bbox[0], bbox[1], bbox[2], bbox[3]);
588 (*outputFunc)(outputStream, buf, strlen(buf));
589 (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
590 (*outputFunc)(outputStream, "/sfnts ", 7);
591 (*outputFunc)(outputStream, psName, strlen(psName));
592 (*outputFunc)(outputStream, "_sfnts def\n", 11);
593 (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
594 for (j = 0; j < 256 && i+j < n; ++j) {
595 sprintf(buf, "dup %d /c%02x put\n", j, j);
596 (*outputFunc)(outputStream, buf, strlen(buf));
597 }
598 (*outputFunc)(outputStream, "readonly def\n", 13);
599 (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
600 (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
601 for (j = 0; j < 256 && i+j < n; ++j) {
602 sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
603 (*outputFunc)(outputStream, buf, strlen(buf));
604 }
605 (*outputFunc)(outputStream, "end readonly def\n", 17);
606 (*outputFunc)(outputStream,
607 "FontName currentdict end definefont pop\n", 40);
608 }
609
610 // write the Type 0 parent font
611 (*outputFunc)(outputStream, "16 dict begin\n", 14);
612 (*outputFunc)(outputStream, "/FontName /", 11);
613 (*outputFunc)(outputStream, psName, strlen(psName));
614 (*outputFunc)(outputStream, " def\n", 5);
615 (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
616 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
617 (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
618 (*outputFunc)(outputStream, "/Encoding [\n", 12);
619 for (i = 0; i < n; i += 256) {
620 sprintf(buf, "%d\n", i >> 8);
621 (*outputFunc)(outputStream, buf, strlen(buf));
622 }
623 (*outputFunc)(outputStream, "] def\n", 6);
624 (*outputFunc)(outputStream, "/FDepVector [\n", 14);
625 for (i = 0; i < n; i += 256) {
626 (*outputFunc)(outputStream, "/", 1);
627 (*outputFunc)(outputStream, psName, strlen(psName));
628 sprintf(buf, "_%02x findfont\n", i >> 8);
629 (*outputFunc)(outputStream, buf, strlen(buf));
630 }
631 (*outputFunc)(outputStream, "] def\n", 6);
632 (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
633 }
634
635 void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
636 void *outputStream, char *name,
637 Gushort *codeToGID) {
638 // this substitute cmap table maps char codes 0000-ffff directly to
639 // glyphs 0000-ffff
640 static char cmapTab[36] = {
641 0, 0, // table version number
642 0, 1, // number of encoding tables
643 0, 1, // platform ID
644 0, 0, // encoding ID
645 0, 0, 0, 12, // offset of subtable
646 0, 4, // subtable format
647 0, 24, // subtable length
648 0, 0, // subtable version
649 0, 2, // segment count * 2
650 0, 2, // 2 * 2 ^ floor(log2(segCount))
651 0, 0, // floor(log2(segCount))
652 0, 0, // 2*segCount - 2*2^floor(log2(segCount))
653 (char)0xff, (char)0xff, // endCount[0]
654 0, 0, // reserved
655 0, 0, // startCount[0]
656 0, 0, // idDelta[0]
657 0, 0 // pad to a mulitple of four bytes
658 };
659 static char nameTab[8] = {
660 0, 0, // format
661 0, 0, // number of name records
662 0, 6, // offset to start of string storage
663 0, 0 // pad to multiple of four bytes
664 };
665 static char postTab[32] = {
666 0, 1, 0, 0, // format
667 0, 0, 0, 0, // italic angle
668 0, 0, // underline position
669 0, 0, // underline thickness
670 0, 0, 0, 0, // fixed pitch
671 0, 0, 0, 0, // min Type 42 memory
672 0, 0, 0, 0, // max Type 42 memory
673 0, 0, 0, 0, // min Type 1 memory
674 0, 0, 0, 0 // max Type 1 memory
675 };
676 GBool missingCmap, missingName, missingPost, unsortedLoca, badCmapLen;
677 int nZeroLengthTables;
678 TrueTypeLoca *locaTable;
679 TrueTypeTable *newTables;
680 char *newNameTab, *newCmapTab;
681 int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next;
682 Guint locaChecksum, glyfChecksum, fileChecksum;
683 char *tableDir;
684 char locaBuf[4], checksumBuf[4];
685 GBool ok;
686 Guint t;
687 int pos, i, j, k, n;
688
689 // check for missing tables
690 missingCmap = (cmapIdx = seekTable("cmap")) < 0;
691 missingName = seekTable("name") < 0;
692 missingPost = seekTable("post") < 0;
693
694 // read the loca table, check to see if it's sorted
695 locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
696 unsortedLoca = gFalse;
697 i = seekTable("loca");
698 pos = tables[i].offset;
699 ok = gTrue;
700 for (i = 0; i <= nGlyphs; ++i) {
701 if (locaFmt) {
702 locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
703 } else {
704 locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
705 }
706 if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) {
707 unsortedLoca = gTrue;
708 }
709 locaTable[i].idx = i;
710 }
711
712 // check for zero-length tables
713 nZeroLengthTables = 0;
714 for (i = 0; i < nTables; ++i) {
715 if (tables[i].len == 0) {
716 ++nZeroLengthTables;
717 }
718 }
719
720 // check for an incorrect cmap table length
721 badCmapLen = gFalse;
722 cmapLen = 0; // make gcc happy
723 if (!missingCmap) {
724 cmapLen = cmaps[0].offset + cmaps[0].len;
725 for (i = 1; i < nCmaps; ++i) {
726 if (cmaps[i].offset + cmaps[i].len > cmapLen) {
727 cmapLen = cmaps[i].offset + cmaps[i].len;
728 }
729 }
730 cmapLen -= tables[cmapIdx].offset;
731 if (cmapLen > tables[cmapIdx].len) {
732 badCmapLen = gTrue;
733 }
734 }
735
736 // if nothing is broken, just write the TTF file as is
737 if (!missingCmap && !missingName && !missingPost && !unsortedLoca &&
738 !badCmapLen && nZeroLengthTables == 0 && !name && !codeToGID) {
739 (*outputFunc)(outputStream, (char *)file, len);
740 goto done1;
741 }
742
743 // sort the 'loca' table: some (non-compliant) fonts have
744 // out-of-order loca tables; in order to correctly handle the case
745 // where (compliant) fonts have empty entries in the middle of the
746 // table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
747 // and idx as its secondary key (ensuring that adjacent entries with
748 // the same pos value remain in the same order)
749 glyfLen = 0; // make gcc happy
750 if (unsortedLoca) {
751 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
752 &cmpTrueTypeLocaOffset);
753 for (i = 0; i < nGlyphs; ++i) {
754 locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
755 }
756 locaTable[nGlyphs].len = 0;
757 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
758 &cmpTrueTypeLocaIdx);
759 pos = 0;
760 for (i = 0; i <= nGlyphs; ++i) {
761 locaTable[i].newOffset = pos;
762 pos += locaTable[i].len;
763 if (pos & 3) {
764 pos += 4 - (pos & 3);
765 }
766 }
767 glyfLen = pos;
768 }
769
770 // compute checksums for the loca and glyf tables
771 locaChecksum = glyfChecksum = 0;
772 if (unsortedLoca) {
773 if (locaFmt) {
774 for (j = 0; j <= nGlyphs; ++j) {
775 locaChecksum += locaTable[j].newOffset;
776 }
777 } else {
778 for (j = 0; j <= nGlyphs; j += 2) {
779 locaChecksum += locaTable[j].newOffset << 16;
780 if (j + 1 <= nGlyphs) {
781 locaChecksum += locaTable[j+1].newOffset;
782 }
783 }
784 }
785 pos = tables[seekTable("glyf")].offset;
786 for (j = 0; j < nGlyphs; ++j) {
787 n = locaTable[j].len;
788 if (n > 0) {
789 k = locaTable[j].origOffset;
790 if (checkRegion(pos + k, n)) {
791 glyfChecksum += computeTableChecksum(file + pos + k, n);
792 }
793 }
794 }
795 }
796
797 // construct the new name table
798 if (name) {
799 n = strlen(name);
800 newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3;
801 newNameTab = (char *)gmalloc(newNameLen);
802 memset(newNameTab, 0, newNameLen);
803 newNameTab[0] = 0; // format selector
804 newNameTab[1] = 0;
805 newNameTab[2] = 0; // number of name records
806 newNameTab[3] = 4;
807 newNameTab[4] = 0; // offset to start of string storage
808 newNameTab[5] = 6 + 4*12;
809 next = 0;
810 for (i = 0; i < 4; ++i) {
811 newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft
812 newNameTab[6 + i*12 + 1] = 3;
813 newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode
814 newNameTab[6 + i*12 + 3] = 1;
815 newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English
816 newNameTab[6 + i*12 + 5] = 0x09;
817 newNameTab[6 + i*12 + 6] = 0; // name ID
818 newNameTab[6 + i*12 + 7] = i + 1;
819 newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length
820 newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff);
821 newNameTab[6 + i*12 + 10] = next >> 8; // string offset
822 newNameTab[6 + i*12 + 11] = next & 0xff;
823 if (i+1 == 2) {
824 memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14);
825 next += 14;
826 } else {
827 for (j = 0; j < n; ++j) {
828 newNameTab[6 + 4*12 + next + 2*j] = 0;
829 newNameTab[6 + 4*12 + next + 2*j + 1] = name[j];
830 }
831 next += 2*n;
832 }
833 }
834 } else {
835 newNameLen = 0;
836 newNameTab = NULL;
837 }
838
839 // construct the new cmap table
840 if (codeToGID) {
841 newCmapLen = 44 + 256 * 2;
842 newCmapTab = (char *)gmalloc(newCmapLen);
843 newCmapTab[0] = 0; // table version number = 0
844 newCmapTab[1] = 0;
845 newCmapTab[2] = 0; // number of encoding tables = 1
846 newCmapTab[3] = 1;
847 newCmapTab[4] = 0; // platform ID = Microsoft
848 newCmapTab[5] = 3;
849 newCmapTab[6] = 0; // encoding ID = Unicode
850 newCmapTab[7] = 1;
851 newCmapTab[8] = 0; // offset of subtable
852 newCmapTab[9] = 0;
853 newCmapTab[10] = 0;
854 newCmapTab[11] = 12;
855 newCmapTab[12] = 0; // subtable format = 4
856 newCmapTab[13] = 4;
857 newCmapTab[14] = 0x02; // subtable length
858 newCmapTab[15] = 0x20;
859 newCmapTab[16] = 0; // subtable version = 0
860 newCmapTab[17] = 0;
861 newCmapTab[18] = 0; // segment count * 2
862 newCmapTab[19] = 4;
863 newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount))
864 newCmapTab[21] = 4;
865 newCmapTab[22] = 0; // floor(log2(segCount))
866 newCmapTab[23] = 1;
867 newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount))
868 newCmapTab[25] = 0;
869 newCmapTab[26] = 0x00; // endCount[0]
870 newCmapTab[27] = (char)0xff;
871 newCmapTab[28] = (char)0xff; // endCount[1]
872 newCmapTab[29] = (char)0xff;
873 newCmapTab[30] = 0; // reserved
874 newCmapTab[31] = 0;
875 newCmapTab[32] = 0x00; // startCount[0]
876 newCmapTab[33] = 0x00;
877 newCmapTab[34] = (char)0xff; // startCount[1]
878 newCmapTab[35] = (char)0xff;
879 newCmapTab[36] = 0; // idDelta[0]
880 newCmapTab[37] = 0;
881 newCmapTab[38] = 0; // idDelta[1]
882 newCmapTab[39] = 1;
883 newCmapTab[40] = 0; // idRangeOffset[0]
884 newCmapTab[41] = 4;
885 newCmapTab[42] = 0; // idRangeOffset[1]
886 newCmapTab[43] = 0;
887 for (i = 0; i < 256; ++i) {
888 newCmapTab[44 + 2*i] = codeToGID[i] >> 8;
889 newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff;
890 }
891 } else {
892 newCmapLen = 0;
893 newCmapTab = NULL;
894 }
895
896 // construct the new table directory:
897 // - keep all original tables with non-zero length
898 // - fix the cmap table's length, if necessary
899 // - add missing tables
900 // - sort the table by tag
901 // - compute new table positions, including 4-byte alignment
902 // - (re)compute table checksums
903 nNewTables = nTables - nZeroLengthTables +
904 (missingCmap ? 1 : 0) + (missingName ? 1 : 0) +
905 (missingPost ? 1 : 0);
906 newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable));
907 j = 0;
908 for (i = 0; i < nTables; ++i) {
909 if (tables[i].len > 0) {
910 newTables[j] = tables[i];
911 newTables[j].origOffset = tables[i].offset;
912 if (checkRegion(tables[i].offset, newTables[i].len)) {
913 newTables[j].checksum =
914 computeTableChecksum(file + tables[i].offset, tables[i].len);
915 if (tables[i].tag == headTag) {
916 // don't include the file checksum
917 newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok);
918 }
919 }
920 if (newTables[j].tag == cmapTag && codeToGID) {
921 newTables[j].len = newCmapLen;
922 newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
923 newCmapLen);
924 } else if (newTables[j].tag == cmapTag && badCmapLen) {
925 newTables[j].len = cmapLen;
926 } else if (newTables[j].tag == locaTag && unsortedLoca) {
927 newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2);
928 newTables[j].checksum = locaChecksum;
929 } else if (newTables[j].tag == glyfTag && unsortedLoca) {
930 newTables[j].len = glyfLen;
931 newTables[j].checksum = glyfChecksum;
932 } else if (newTables[j].tag == nameTag && name) {
933 newTables[j].len = newNameLen;
934 newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
935 newNameLen);
936 }
937 ++j;
938 }
939 }
940 if (missingCmap) {
941 newTables[j].tag = cmapTag;
942 if (codeToGID) {
943 newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
944 newCmapLen);
945 newTables[j].len = newCmapLen;
946 } else {
947 newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab,
948 sizeof(cmapTab));
949 newTables[j].len = sizeof(cmapTab);
950 }
951 ++j;
952 }
953 if (missingName) {
954 newTables[j].tag = nameTag;
955 if (name) {
956 newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
957 newNameLen);
958 newTables[j].len = newNameLen;
959 } else {
960 newTables[j].checksum = computeTableChecksum((Guchar *)nameTab,
961 sizeof(nameTab));
962 newTables[j].len = sizeof(nameTab);
963 }
964 ++j;
965 }
966 if (missingPost) {
967 newTables[j].tag = postTag;
968 newTables[j].checksum = computeTableChecksum((Guchar *)postTab,
969 sizeof(postTab));
970 newTables[j].len = sizeof(postTab);
971 ++j;
972 }
973 qsort(newTables, nNewTables, sizeof(TrueTypeTable),
974 &cmpTrueTypeTableTag);
975 pos = 12 + nNewTables * 16;
976 for (i = 0; i < nNewTables; ++i) {
977 newTables[i].offset = pos;
978 pos += newTables[i].len;
979 if (pos & 3) {
980 pos += 4 - (pos & 3);
981 }
982 }
983
984 // write the table directory
985 tableDir = (char *)gmalloc(12 + nNewTables * 16);
986 tableDir[0] = 0x00; // sfnt version
987 tableDir[1] = 0x01;
988 tableDir[2] = 0x00;
989 tableDir[3] = 0x00;
990 tableDir[4] = (char)((nNewTables >> 8) & 0xff); // numTables
991 tableDir[5] = (char)(nNewTables & 0xff);
992 for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ;
993 t = 1 << (4 + i);
994 tableDir[6] = (char)((t >> 8) & 0xff); // searchRange
995 tableDir[7] = (char)(t & 0xff);
996 tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector
997 tableDir[9] = (char)(i & 0xff);
998 t = nNewTables * 16 - t;
999 tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift
1000 tableDir[11] = (char)(t & 0xff);
1001 pos = 12;
1002 for (i = 0; i < nNewTables; ++i) {
1003 tableDir[pos ] = (char)(newTables[i].tag >> 24);
1004 tableDir[pos+ 1] = (char)(newTables[i].tag >> 16);
1005 tableDir[pos+ 2] = (char)(newTables[i].tag >> 8);
1006 tableDir[pos+ 3] = (char) newTables[i].tag;
1007 tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24);
1008 tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16);
1009 tableDir[pos+ 6] = (char)(newTables[i].checksum >> 8);
1010 tableDir[pos+ 7] = (char) newTables[i].checksum;
1011 tableDir[pos+ 8] = (char)(newTables[i].offset >> 24);
1012 tableDir[pos+ 9] = (char)(newTables[i].offset >> 16);
1013 tableDir[pos+10] = (char)(newTables[i].offset >> 8);
1014 tableDir[pos+11] = (char) newTables[i].offset;
1015 tableDir[pos+12] = (char)(newTables[i].len >> 24);
1016 tableDir[pos+13] = (char)(newTables[i].len >> 16);
1017 tableDir[pos+14] = (char)(newTables[i].len >> 8);
1018 tableDir[pos+15] = (char) newTables[i].len;
1019 pos += 16;
1020 }
1021 (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16);
1022
1023 // compute the file checksum
1024 fileChecksum = computeTableChecksum((Guchar *)tableDir,
1025 12 + nNewTables * 16);
1026 for (i = 0; i < nNewTables; ++i) {
1027 fileChecksum += newTables[i].checksum;
1028 }
1029 fileChecksum = 0xb1b0afba - fileChecksum;
1030
1031 // write the tables
1032 for (i = 0; i < nNewTables; ++i) {
1033 if (newTables[i].tag == headTag) {
1034 if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
1035 (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8);
1036 checksumBuf[0] = fileChecksum >> 24;
1037 checksumBuf[1] = fileChecksum >> 16;
1038 checksumBuf[2] = fileChecksum >> 8;
1039 checksumBuf[3] = fileChecksum;
1040 (*outputFunc)(outputStream, checksumBuf, 4);
1041 (*outputFunc)(outputStream,
1042 (char *)file + newTables[i].origOffset + 12,
1043 newTables[i].len - 12);
1044 } else {
1045 for (j = 0; j < newTables[i].len; ++j) {
1046 (*outputFunc)(outputStream, "\0", 1);
1047 }
1048 }
1049 } else if (newTables[i].tag == cmapTag && codeToGID) {
1050 (*outputFunc)(outputStream, newCmapTab, newTables[i].len);
1051 } else if (newTables[i].tag == cmapTag && missingCmap) {
1052 (*outputFunc)(outputStream, cmapTab, newTables[i].len);
1053 } else if (newTables[i].tag == nameTag && name) {
1054 (*outputFunc)(outputStream, newNameTab, newTables[i].len);
1055 } else if (newTables[i].tag == nameTag && missingName) {
1056 (*outputFunc)(outputStream, nameTab, newTables[i].len);
1057 } else if (newTables[i].tag == postTag && missingPost) {
1058 (*outputFunc)(outputStream, postTab, newTables[i].len);
1059 } else if (newTables[i].tag == locaTag && unsortedLoca) {
1060 for (j = 0; j <= nGlyphs; ++j) {
1061 if (locaFmt) {
1062 locaBuf[0] = (char)(locaTable[j].newOffset >> 24);
1063 locaBuf[1] = (char)(locaTable[j].newOffset >> 16);
1064 locaBuf[2] = (char)(locaTable[j].newOffset >> 8);
1065 locaBuf[3] = (char) locaTable[j].newOffset;
1066 (*outputFunc)(outputStream, locaBuf, 4);
1067 } else {
1068 locaBuf[0] = (char)(locaTable[j].newOffset >> 9);
1069 locaBuf[1] = (char)(locaTable[j].newOffset >> 1);
1070 (*outputFunc)(outputStream, locaBuf, 2);
1071 }
1072 }
1073 } else if (newTables[i].tag == glyfTag && unsortedLoca) {
1074 pos = tables[seekTable("glyf")].offset;
1075 for (j = 0; j < nGlyphs; ++j) {
1076 n = locaTable[j].len;
1077 if (n > 0) {
1078 k = locaTable[j].origOffset;
1079 if (checkRegion(pos + k, n)) {
1080 (*outputFunc)(outputStream, (char *)file + pos + k, n);
1081 } else {
1082 for (k = 0; k < n; ++k) {
1083 (*outputFunc)(outputStream, "\0", 1);
1084 }
1085 }
1086 if ((k = locaTable[j].len & 3)) {
1087 (*outputFunc)(outputStream, "\0\0\0\0", 4 - k);
1088 }
1089 }
1090 }
1091 } else {
1092 if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
1093 (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset,
1094 newTables[i].len);
1095 } else {
1096 for (j = 0; j < newTables[i].len; ++j) {
1097 (*outputFunc)(outputStream, "\0", 1);
1098 }
1099 }
1100 }
1101 if (newTables[i].len & 3) {
1102 (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3));
1103 }
1104 }
1105
1106 gfree(newCmapTab);
1107 gfree(newNameTab);
1108 gfree(tableDir);
1109 gfree(newTables);
1110 done1:
1111 gfree(locaTable);
1112 }
1113
1114 void FoFiTrueType::cvtEncoding(char **encoding,
1115 FoFiOutputFunc outputFunc,
1116 void *outputStream) {
1117 char *name;
1118 char buf[64];
1119 int i;
1120
1121 (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
1122 if (encoding) {
1123 for (i = 0; i < 256; ++i) {
1124 if (!(name = encoding[i])) {
1125 name = ".notdef";
1126 }
1127 sprintf(buf, "dup %d /", i);
1128 (*outputFunc)(outputStream, buf, strlen(buf));
1129 (*outputFunc)(outputStream, name, strlen(name));
1130 (*outputFunc)(outputStream, " put\n", 5);
1131 }
1132 } else {
1133 for (i = 0; i < 256; ++i) {
1134 sprintf(buf, "dup %d /c%02x put\n", i, i);
1135 (*outputFunc)(outputStream, buf, strlen(buf));
1136 }
1137 }
1138 (*outputFunc)(outputStream, "readonly def\n", 13);
1139 }
1140
1141 void FoFiTrueType::cvtCharStrings(char **encoding,
1142 Gushort *codeToGID,
1143 FoFiOutputFunc outputFunc,
1144 void *outputStream) {
1145 char *name;
1146 char buf[64], buf2[16];
1147 int i, k;
1148
1149 // always define '.notdef'
1150 (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32);
1151 (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
1152
1153 // if there's no 'cmap' table, punt
1154 if (nCmaps == 0) {
1155 goto err;
1156 }
1157
1158 // map char name to glyph index:
1159 // 1. use encoding to map name to char code
1160 // 2. use codeToGID to map char code to glyph index
1161 // N.B. We do this in reverse order because font subsets can have
1162 // weird encodings that use the same character name twice, and
1163 // the first definition is probably the one we want.
1164 k = 0; // make gcc happy
1165 for (i = 255; i >= 0; --i) {
1166 if (encoding) {
1167 name = encoding[i];
1168 } else {
1169 sprintf(buf2, "c%02x", i);
1170 name = buf2;
1171 }
1172 if (name && strcmp(name, ".notdef")) {
1173 k = codeToGID[i];
1174 // note: Distiller (maybe Adobe's PS interpreter in general)
1175 // doesn't like TrueType fonts that have CharStrings entries
1176 // which point to nonexistent glyphs, hence the (k < nGlyphs)
1177 // test
1178 if (k > 0 && k < nGlyphs) {
1179 (*outputFunc)(outputStream, "/", 1);
1180 (*outputFunc)(outputStream, name, strlen(name));
1181 sprintf(buf, " %d def\n", k);
1182 (*outputFunc)(outputStream, buf, strlen(buf));
1183 }
1184 }
1185 }
1186
1187 err:
1188 (*outputFunc)(outputStream, "end readonly def\n", 17);
1189 }
1190
1191 void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
1192 void *outputStream, GooString *name,
1193 GBool needVerticalMetrics) {
1194 Guchar headData[54];
1195 TrueTypeLoca *locaTable;
1196 Guchar *locaData;
1197 TrueTypeTable newTables[nT42Tables];
1198 Guchar tableDir[12 + nT42Tables*16];
1199 GBool ok;
1200 Guint checksum;
1201 int nNewTables;
1202 int length, pos, glyfPos, i, j, k;
1203 Guchar vheaTab[36] = {
1204 0, 1, 0, 0, // table version number
1205 0, 0, // ascent
1206 0, 0, // descent
1207 0, 0, // reserved
1208 0, 0, // max advance height
1209 0, 0, // min top side bearing
1210 0, 0, // min bottom side bearing
1211 0, 0, // y max extent
1212 0, 0, // caret slope rise
1213 0, 1, // caret slope run
1214 0, 0, // caret offset
1215 0, 0, // reserved
1216 0, 0, // reserved
1217 0, 0, // reserved
1218 0, 0, // reserved
1219 0, 0, // metric data format
1220 0, 1 // number of advance heights in vmtx table
1221 };
1222 Guchar *vmtxTab;
1223 GBool needVhea, needVmtx;
1224 int advance;
1225
1226 // construct the 'head' table, zero out the font checksum
1227 i = seekTable("head");
1228 pos = tables[i].offset;
1229 if (!checkRegion(pos, 54)) {
1230 return;
1231 }
1232 memcpy(headData, file + pos, 54);
1233 headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0;
1234
1235 // read the original 'loca' table, pad entries out to 4 bytes, and
1236 // sort it into proper order -- some (non-compliant) fonts have
1237 // out-of-order loca tables; in order to correctly handle the case
1238 // where (compliant) fonts have empty entries in the middle of the
1239 // table, cmpTrueTypeLocaPos uses offset as its primary sort key,
1240 // and idx as its secondary key (ensuring that adjacent entries with
1241 // the same pos value remain in the same order)
1242 locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
1243 i = seekTable("loca");
1244 pos = tables[i].offset;
1245 ok = gTrue;
1246 for (i = 0; i <= nGlyphs; ++i) {
1247 locaTable[i].idx = i;
1248 if (locaFmt) {
1249 locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
1250 } else {
1251 locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
1252 }
1253 }
1254 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
1255 &cmpTrueTypeLocaOffset);
1256 for (i = 0; i < nGlyphs; ++i) {
1257 locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
1258 }
1259 locaTable[nGlyphs].len = 0;
1260 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
1261 &cmpTrueTypeLocaIdx);
1262 pos = 0;
1263 for (i = 0; i <= nGlyphs; ++i) {
1264 locaTable[i].newOffset = pos;
1265 pos += locaTable[i].len;
1266 if (pos & 3) {
1267 pos += 4 - (pos & 3);
1268 }
1269 }
1270
1271 // construct the new 'loca' table
1272 locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2));
1273 for (i = 0; i <= nGlyphs; ++i) {
1274 pos = locaTable[i].newOffset;
1275 if (locaFmt) {
1276 locaData[4*i ] = (Guchar)(pos >> 24);
1277 locaData[4*i+1] = (Guchar)(pos >> 16);
1278 locaData[4*i+2] = (Guchar)(pos >> 8);
1279 locaData[4*i+3] = (Guchar) pos;
1280 } else {
1281 locaData[2*i ] = (Guchar)(pos >> 9);
1282 locaData[2*i+1] = (Guchar)(pos >> 1);
1283 }
1284 }
1285
1286 // count the number of tables
1287 nNewTables = 0;
1288 for (i = 0; i < nT42Tables; ++i) {
1289 if (t42Tables[i].required ||
1290 seekTable(t42Tables[i].tag) >= 0) {
1291 ++nNewTables;
1292 }
1293 }
1294 vmtxTab = NULL; // make gcc happy
1295 advance = 0; // make gcc happy
1296 if (needVerticalMetrics) {
1297 needVhea = seekTable("vhea") < 0;
1298 needVmtx = seekTable("vmtx") < 0;
1299 if (needVhea || needVmtx) {
1300 i = seekTable("head");
1301 advance = getU16BE(tables[i].offset + 18, &ok); // units per em
1302 if (needVhea) {
1303 ++nNewTables;
1304 }
1305 if (needVmtx) {
1306 ++nNewTables;
1307 }
1308 }
1309 }
1310
1311 // construct the new table headers, including table checksums
1312 // (pad each table out to a multiple of 4 bytes)
1313 pos = 12 + nNewTables*16;
1314 k = 0;
1315 for (i = 0; i < nT42Tables; ++i) {
1316 length = -1;
1317 checksum = 0; // make gcc happy
1318 if (i == t42HeadTable) {
1319 length = 54;
1320 checksum = computeTableChecksum(headData, 54);
1321 } else if (i == t42LocaTable) {
1322 length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1323 checksum = computeTableChecksum(locaData, length);
1324 } else if (i == t42GlyfTable) {
1325 length = 0;
1326 checksum = 0;
1327 glyfPos = tables[seekTable("glyf")].offset;
1328 for (j = 0; j < nGlyphs; ++j) {
1329 length += locaTable[j].len;
1330 if (length & 3) {
1331 length += 4 - (length & 3);
1332 }
1333 if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1334 checksum +=
1335 computeTableChecksum(file + glyfPos + locaTable[j].origOffset,
1336 locaTable[j].len);
1337 }
1338 }
1339 } else {
1340 if ((j = seekTable(t42Tables[i].tag)) >= 0) {
1341 length = tables[j].len;
1342 if (checkRegion(tables[j].offset, length)) {
1343 checksum = computeTableChecksum(file + tables[j].offset, length);
1344 }
1345 } else if (needVerticalMetrics && i == t42VheaTable) {
1346 vheaTab[10] = advance / 256; // max advance height
1347 vheaTab[11] = advance % 256;
1348 length = sizeof(vheaTab);
1349 checksum = computeTableChecksum(vheaTab, length);
1350 } else if (needVerticalMetrics && i == t42VmtxTable) {
1351 length = 4 + (nGlyphs - 1) * 4;
1352 vmtxTab = (Guchar *)gmalloc(length);
1353 vmtxTab[0] = advance / 256;
1354 vmtxTab[1] = advance % 256;
1355 for (j = 2; j < length; j += 2) {
1356 vmtxTab[j] = 0;
1357 vmtxTab[j+1] = 0;
1358 }
1359 checksum = computeTableChecksum(vmtxTab, length);
1360 } else if (t42Tables[i].required) {
1361 //~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
1362 //~ t42Tables[i].tag);
1363 length = 0;
1364 checksum = 0;
1365 }
1366 }
1367 if (length >= 0) {
1368 newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) |
1369 ((t42Tables[i].tag[1] & 0xff) << 16) |
1370 ((t42Tables[i].tag[2] & 0xff) << 8) |
1371 (t42Tables[i].tag[3] & 0xff);
1372 newTables[k].checksum = checksum;
1373 newTables[k].offset = pos;
1374 newTables[k].len = length;
1375 pos += length;
1376 if (pos & 3) {
1377 pos += 4 - (length & 3);
1378 }
1379 ++k;
1380 }
1381 }
1382
1383 // construct the table directory
1384 tableDir[0] = 0x00; // sfnt version
1385 tableDir[1] = 0x01;
1386 tableDir[2] = 0x00;
1387 tableDir[3] = 0x00;
1388 tableDir[4] = 0; // numTables
1389 tableDir[5] = nNewTables;
1390 tableDir[6] = 0; // searchRange
1391 tableDir[7] = (Guchar)128;
1392 tableDir[8] = 0; // entrySelector
1393 tableDir[9] = 3;
1394 tableDir[10] = 0; // rangeShift
1395 tableDir[11] = (Guchar)(16 * nNewTables - 128);
1396 pos = 12;
1397 for (i = 0; i < nNewTables; ++i) {
1398 tableDir[pos ] = (Guchar)(newTables[i].tag >> 24);
1399 tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16);
1400 tableDir[pos+ 2] = (Guchar)(newTables[i].tag >> 8);
1401 tableDir[pos+ 3] = (Guchar) newTables[i].tag;
1402 tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24);
1403 tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16);
1404 tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >> 8);
1405 tableDir[pos+ 7] = (Guchar) newTables[i].checksum;
1406 tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24);
1407 tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16);
1408 tableDir[pos+10] = (Guchar)(newTables[i].offset >> 8);
1409 tableDir[pos+11] = (Guchar) newTables[i].offset;
1410 tableDir[pos+12] = (Guchar)(newTables[i].len >> 24);
1411 tableDir[pos+13] = (Guchar)(newTables[i].len >> 16);
1412 tableDir[pos+14] = (Guchar)(newTables[i].len >> 8);
1413 tableDir[pos+15] = (Guchar) newTables[i].len;
1414 pos += 16;
1415 }
1416
1417 // compute the font checksum and store it in the head table
1418 checksum = computeTableChecksum(tableDir, 12 + nNewTables*16);
1419 for (i = 0; i < nNewTables; ++i) {
1420 checksum += newTables[i].checksum;
1421 }
1422 checksum = 0xb1b0afba - checksum; // because the TrueType spec says so
1423 headData[ 8] = (Guchar)(checksum >> 24);
1424 headData[ 9] = (Guchar)(checksum >> 16);
1425 headData[10] = (Guchar)(checksum >> 8);
1426 headData[11] = (Guchar) checksum;
1427
1428 // start the sfnts array
1429 if (name) {
1430 (*outputFunc)(outputStream, "/", 1);
1431 (*outputFunc)(outputStream, name->getCString(), name->getLength());
1432 (*outputFunc)(outputStream, " [\n", 3);
1433 } else {
1434 (*outputFunc)(outputStream, "/sfnts [\n", 9);
1435 }
1436
1437 // write the table directory
1438 dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream);
1439
1440 // write the tables
1441 for (i = 0; i < nNewTables; ++i) {
1442 if (i == t42HeadTable) {
1443 dumpString(headData, 54, outputFunc, outputStream);
1444 } else if (i == t42LocaTable) {
1445 length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1446 dumpString(locaData, length, outputFunc, outputStream);
1447 } else if (i == t42GlyfTable) {
1448 glyfPos = tables[seekTable("glyf")].offset;
1449 for (j = 0; j < nGlyphs; ++j) {
1450 if (locaTable[j].len > 0 &&
1451 checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1452 dumpString(file + glyfPos + locaTable[j].origOffset,
1453 locaTable[j].len, outputFunc, outputStream);
1454 }
1455 }
1456 } else {
1457 // length == 0 means the table is missing and the error was
1458 // already reported during the construction of the table
1459 // headers
1460 if ((length = newTables[i].len) > 0) {
1461 if ((j = seekTable(t42Tables[i].tag)) >= 0 &&
1462 checkRegion(tables[j].offset, tables[j].len)) {
1463 dumpString(file + tables[j].offset, tables[j].len,
1464 outputFunc, outputStream);
1465 } else if (needVerticalMetrics && i == t42VheaTable) {
1466 dumpString(vheaTab, length, outputFunc, outputStream);
1467 } else if (needVerticalMetrics && i == t42VmtxTable) {
1468 dumpString(vmtxTab, length, outputFunc, outputStream);
1469 gfree(vmtxTab);
1470 }
1471 }
1472 }
1473 }
1474
1475 // end the sfnts array
1476 (*outputFunc)(outputStream, "] def\n", 6);
1477
1478 gfree(locaData);
1479 gfree(locaTable);
1480 }
1481
1482 void FoFiTrueType::dumpString(Guchar *s, int length,
1483 FoFiOutputFunc outputFunc,
1484 void *outputStream) {
1485 char buf[64];
1486 int pad, i, j;
1487
1488 (*outputFunc)(outputStream, "<", 1);
1489 for (i = 0; i < length; i += 32) {
1490 for (j = 0; j < 32 && i+j < length; ++j) {
1491 sprintf(buf, "%02X", s[i+j] & 0xff);
1492 (*outputFunc)(outputStream, buf, strlen(buf));
1493 }
1494 if (i % (65536 - 32) == 65536 - 64) {
1495 (*outputFunc)(outputStream, ">\n<", 3);
1496 } else if (i+32 < length) {
1497 (*outputFunc)(outputStream, "\n", 1);
1498 }
1499 }
1500 if (length & 3) {
1501 pad = 4 - (length & 3);
1502 for (i = 0; i < pad; ++i) {
1503 (*outputFunc)(outputStream, "00", 2);
1504 }
1505 }
1506 // add an extra zero byte because the Adobe Type 42 spec says so
1507 (*outputFunc)(outputStream, "00>\n", 4);
1508 }
1509
1510 Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) {
1511 Guint checksum, word;
1512 int i;
1513
1514 checksum = 0;
1515 for (i = 0; i+3 < length; i += 4) {
1516 word = ((data[i ] & 0xff) << 24) +
1517 ((data[i+1] & 0xff) << 16) +
1518 ((data[i+2] & 0xff) << 8) +
1519 (data[i+3] & 0xff);
1520 checksum += word;
1521 }
1522 if (length & 3) {
1523 word = 0;
1524 i = length & ~3;
1525 switch (length & 3) {
1526 case 3:
1527 word |= (data[i+2] & 0xff) << 8;
1528 case 2:
1529 word |= (data[i+1] & 0xff) << 16;
1530 case 1:
1531 word |= (data[i ] & 0xff) << 24;
1532 break;
1533 }
1534 checksum += word;
1535 }
1536 return checksum;
1537 }
1538
1539 #define toTag(a,b,c,d) (((unsigned int)(a)<<24) | ((unsigned int)(b)<<16) | ((unsigned int)(c)<<8) | (d))
1540
1541 void FoFiTrueType::parse() {
1542 Guint topTag;
1543 int pos, i, j;
1544 unsigned int head;
1545
1546 parsedOk = gTrue;
1547
1548 // look for a collection (TTC)
1549 topTag = getU32BE(0, &parsedOk);
1550 if (!parsedOk) {
1551 return;
1552 }
1553 if (topTag == ttcfTag) {
1554 pos = getU32BE(12, &parsedOk);
1555 if (!parsedOk) {
1556 return;
1557 }
1558 } else {
1559 pos = 0;
1560 }
1561
1562 // read the table directory
1563 head = getU32BE(pos, &parsedOk);
1564 if (! parsedOk)
1565 return;
1566 if (head == toTag('t','t','c','f')) {
1567 /* TTC font */
1568 int dircount;
1569
1570 dircount = getU32BE(8, &parsedOk);
1571 if (!parsedOk)
1572 return;
1573 if (! dircount) {
1574 parsedOk = gFalse;
1575 return;
1576 }
1577
1578 if (faceIndex >= dircount)
1579 faceIndex = 0;
1580 pos = getU32BE(12 + faceIndex * 4, &parsedOk);
1581 if (! parsedOk)
1582 return;
1583 }
1584
1585 pos += 4;
1586 nTables = getU16BE(pos, &parsedOk);
1587 if (!parsedOk) {
1588 return;
1589 }
1590
1591 pos += 8;
1592 tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable));
1593 for (i = 0; i < nTables; ++i) {
1594 tables[i].tag = getU32BE(pos, &parsedOk);
1595 tables[i].checksum = getU32BE(pos + 4, &parsedOk);
1596 tables[i].offset = (int)getU32BE(pos + 8, &parsedOk);
1597 tables[i].len = (int)getU32BE(pos + 12, &parsedOk);
1598 if (tables[i].offset + tables[i].len < tables[i].offset ||
1599 tables[i].offset + tables[i].len > len) {
1600 parsedOk = gFalse;
1601 }
1602 pos += 16;
1603 }
1604 if (!parsedOk) {
1605 return;
1606 }
1607
1608 // check for tables that are required by both the TrueType spec and
1609 // the Type 42 spec
1610 if (seekTable("head") < 0 ||
1611 seekTable("hhea") < 0 ||
1612 seekTable("loca") < 0 ||
1613 seekTable("maxp") < 0 ||
1614 seekTable("glyf") < 0 ||
1615 seekTable("hmtx") < 0) {
1616 parsedOk = gFalse;
1617 return;
1618 }
1619
1620 // read the cmaps
1621 if ((i = seekTable("cmap")) >= 0) {
1622 pos = tables[i].offset + 2;
1623 nCmaps = getU16BE(pos, &parsedOk);
1624 pos += 2;
1625 if (!parsedOk) {
1626 return;
1627 }
1628 cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap));
1629 for (j = 0; j < nCmaps; ++j) {
1630 cmaps[j].platform = getU16BE(pos, &parsedOk);
1631 cmaps[j].encoding = getU16BE(pos + 2, &parsedOk);
1632 cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk);
1633 pos += 8;
1634 cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk);
1635 cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk);
1636 }
1637 if (!parsedOk) {
1638 return;
1639 }
1640 } else {
1641 nCmaps = 0;
1642 }
1643
1644 // get the number of glyphs from the maxp table
1645 i = seekTable("maxp");
1646 nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk);
1647 if (!parsedOk) {
1648 return;
1649 }
1650
1651 // get the bbox and loca table format from the head table
1652 i = seekTable("head");
1653 bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk);
1654 bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk);
1655 bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk);
1656 bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk);
1657 locaFmt = getS16BE(tables[i].offset + 50, &parsedOk);
1658 if (!parsedOk) {
1659 return;
1660 }
1661
1662 // make sure the loca table is sane (correct length and entries are
1663 // in bounds)
1664 i = seekTable("loca");
1665 if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) {
1666 parsedOk = gFalse;
1667 return;
1668 }
1669 for (j = 0; j <= nGlyphs; ++j) {
1670 if (locaFmt) {
1671 pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk);
1672 } else {
1673 pos = getU16BE(tables[i].offset + j*2, &parsedOk);
1674 }
1675 if (pos < 0 || pos > len) {
1676 parsedOk = gFalse;
1677 }
1678 }
1679 if (!parsedOk) {
1680 return;
1681 }
1682
1683 // read the post table
1684 readPostTable();
1685 }
1686
1687 void FoFiTrueType::readPostTable() {
1688 GooString *name;
1689 int tablePos, postFmt, stringIdx, stringPos;
1690 GBool ok;
1691 int i, j, n, m;
1692
1693 ok = gTrue;
1694 if ((i = seekTable("post")) < 0) {
1695 return;
1696 }
1697 tablePos = tables[i].offset;
1698 postFmt = getU32BE(tablePos, &ok);
1699 if (!ok) {
1700 goto err;
1701 }
1702 if (postFmt == 0x00010000) {
1703 nameToGID = new GooHash(gTrue);
1704 for (i = 0; i < 258; ++i) {
1705 nameToGID->add(new GooString(macGlyphNames[i]), i);
1706 }
1707 } else if (postFmt == 0x00020000) {
1708 nameToGID = new GooHash(gTrue);
1709 n = getU16BE(tablePos + 32, &ok);
1710 if (!ok) {
1711 goto err;
1712 }
1713 if (n > nGlyphs) {
1714 n = nGlyphs;
1715 }
1716 stringIdx = 0;
1717 stringPos = tablePos + 34 + 2*n;
1718 for (i = 0; i < n; ++i) {
1719 j = getU16BE(tablePos + 34 + 2*i, &ok);
1720 if (j < 258) {
1721 nameToGID->removeInt(macGlyphNames[j]);
1722 nameToGID->add(new GooString(macGlyphNames[j]), i);
1723 } else {
1724 j -= 258;
1725 if (j != stringIdx) {
1726 for (stringIdx = 0, stringPos = tablePos + 34 + 2*n;
1727 stringIdx < j;
1728 ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ;
1729 if (!ok) {
1730 goto err;
1731 }
1732 }
1733 m = getU8(stringPos, &ok);
1734 if (!ok || !checkRegion(stringPos + 1, m)) {
1735 goto err;
1736 }
1737 name = new GooString((char *)&file[stringPos + 1], m);
1738 nameToGID->removeInt(name);
1739 nameToGID->add(name, i);
1740 ++stringIdx;
1741 stringPos += 1 + m;
1742 }
1743 }
1744 } else if (postFmt == 0x00028000) {
1745 nameToGID = new GooHash(gTrue);
1746 for (i = 0; i < nGlyphs; ++i) {
1747 j = getU8(tablePos + 32 + i, &ok);
1748 if (!ok) {
1749 goto err;
1750 }
1751 if (j < 258) {
1752 nameToGID->removeInt(macGlyphNames[j]);
1753 nameToGID->add(new GooString(macGlyphNames[j]), i);
1754 }
1755 }
1756 }
1757
1758 return;
1759
1760 err:
1761 if (nameToGID) {
1762 delete nameToGID;
1763 nameToGID = NULL;
1764 }
1765 }
1766
1767 int FoFiTrueType::seekTable(char *tag) {
1768 Guint tagI;
1769 int i;
1770
1771 tagI = ((tag[0] & 0xff) << 24) |
1772 ((tag[1] & 0xff) << 16) |
1773 ((tag[2] & 0xff) << 8) |
1774 (tag[3] & 0xff);
1775 for (i = 0; i < nTables; ++i) {
1776 if (tables[i].tag == tagI) {
1777 return i;
1778 }
1779 }
1780 return -1;
1781 }