Bringing apdf from vendor into main branch.
[AROS-Contrib.git] / apdf / fofi / FoFiTrueType.cc
blob46b61ec39796ea68268d2529376a06eee1869d14
1 //========================================================================
2 //
3 // FoFiTrueType.cc
4 //
5 // Copyright 1999-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
9 #include <aconf.h>
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
15 #include <stdlib.h>
16 #include <string.h>
17 #include "gtypes.h"
18 #include "gmem.h"
19 #include "GString.h"
20 #include "GHash.h"
21 #include "FoFiTrueType.h"
24 // Terminology
25 // -----------
27 // character code = number used as an element of a text string
29 // character name = glyph name = name for a particular glyph within a
30 // font
32 // glyph index = GID = position (within some internal table in the font)
33 // where the instructions to draw a particular glyph are
34 // stored
36 // Type 1 fonts
37 // ------------
39 // Type 1 fonts contain:
41 // Encoding: array of glyph names, maps char codes to glyph names
43 // Encoding[charCode] = charName
45 // CharStrings: dictionary of instructions, keyed by character names,
46 // maps character name to glyph data
48 // CharStrings[charName] = glyphData
50 // TrueType fonts
51 // --------------
53 // TrueType fonts contain:
55 // 'cmap' table: mapping from character code to glyph index; there may
56 // be multiple cmaps in a TrueType font
58 // cmap[charCode] = gid
60 // 'post' table: mapping from glyph index to glyph name
62 // post[gid] = glyphName
64 // Type 42 fonts
65 // -------------
67 // Type 42 fonts contain:
69 // Encoding: array of glyph names, maps char codes to glyph names
71 // Encoding[charCode] = charName
73 // CharStrings: dictionary of glyph indexes, keyed by character names,
74 // maps character name to glyph index
76 // CharStrings[charName] = gid
79 //------------------------------------------------------------------------
81 #define ttcfTag 0x74746366
83 //------------------------------------------------------------------------
85 struct TrueTypeTable {
86 Guint tag;
87 Guint checksum;
88 int offset;
89 int origOffset;
90 int len;
93 struct TrueTypeCmap {
94 int platform;
95 int encoding;
96 int offset;
97 int len;
98 int fmt;
101 struct TrueTypeLoca {
102 int idx;
103 int origOffset;
104 int newOffset;
105 int len;
108 #define cmapTag 0x636d6170
109 #define glyfTag 0x676c7966
110 #define headTag 0x68656164
111 #define locaTag 0x6c6f6361
112 #define nameTag 0x6e616d65
113 #define postTag 0x706f7374
115 static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) {
116 TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
117 TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
119 if (loca1->origOffset == loca2->origOffset) {
120 return loca1->idx - loca2->idx;
122 return loca1->origOffset - loca2->origOffset;
125 static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) {
126 TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
127 TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
129 return loca1->idx - loca2->idx;
132 static int cmpTrueTypeTableTag(const void *p1, const void *p2) {
133 TrueTypeTable *tab1 = (TrueTypeTable *)p1;
134 TrueTypeTable *tab2 = (TrueTypeTable *)p2;
136 return (int)tab1->tag - (int)tab2->tag;
139 //------------------------------------------------------------------------
141 struct T42Table {
142 char *tag; // 4-byte tag
143 GBool required; // required by the TrueType spec?
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 }
162 #define t42HeadTable 3
163 #define t42LocaTable 6
164 #define t42GlyfTable 2
165 #define t42VheaTable 9
166 #define t42VmtxTable 10
168 //------------------------------------------------------------------------
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"
240 //------------------------------------------------------------------------
241 // FoFiTrueType
242 //------------------------------------------------------------------------
244 FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA) {
245 FoFiTrueType *ff;
247 ff = new FoFiTrueType(fileA, lenA, gFalse);
248 if (!ff->parsedOk) {
249 delete ff;
250 return NULL;
252 return ff;
255 FoFiTrueType *FoFiTrueType::load(char *fileName) {
256 FoFiTrueType *ff;
257 char *fileA;
258 int lenA;
260 if (!(fileA = FoFiBase::readFile(fileName, &lenA))) {
261 return NULL;
263 ff = new FoFiTrueType(fileA, lenA, gTrue);
264 if (!ff->parsedOk) {
265 delete ff;
266 return NULL;
268 return ff;
271 FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA):
272 FoFiBase(fileA, lenA, freeFileDataA)
274 tables = NULL;
275 nTables = 0;
276 cmaps = NULL;
277 nCmaps = 0;
278 nameToGID = NULL;
279 parsedOk = gFalse;
281 parse();
284 FoFiTrueType::~FoFiTrueType() {
285 gfree(tables);
286 gfree(cmaps);
287 if (nameToGID) {
288 delete nameToGID;
292 int FoFiTrueType::getNumCmaps() {
293 return nCmaps;
296 int FoFiTrueType::getCmapPlatform(int i) {
297 return cmaps[i].platform;
300 int FoFiTrueType::getCmapEncoding(int i) {
301 return cmaps[i].encoding;
304 int FoFiTrueType::findCmap(int platform, int encoding) {
305 int i;
307 for (i = 0; i < nCmaps; ++i) {
308 if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) {
309 return i;
312 return -1;
315 Gushort FoFiTrueType::mapCodeToGID(int i, int c) {
316 Gushort gid;
317 int segCnt, segEnd, segStart, segDelta, segOffset;
318 int cmapFirst, cmapLen;
319 int pos, a, b, m;
320 GBool ok;
322 if (i < 0 || i >= nCmaps) {
323 return 0;
325 ok = gTrue;
326 pos = cmaps[i].offset;
327 switch (cmaps[i].fmt) {
328 case 0:
329 if (c < 0 || c >= cmaps[i].len - 6) {
330 return 0;
332 gid = getU8(cmaps[i].offset + 6 + c, &ok);
333 break;
334 case 4:
335 segCnt = getU16BE(pos + 6, &ok) / 2;
336 a = -1;
337 b = segCnt - 1;
338 segEnd = getU16BE(pos + 14 + 2*b, &ok);
339 if (c > segEnd) {
340 // malformed font -- the TrueType spec requires the last segEnd
341 // to be 0xffff
342 return 0;
344 // invariant: seg[a].end < code <= seg[b].end
345 while (b - a > 1 && ok) {
346 m = (a + b) / 2;
347 segEnd = getU16BE(pos + 14 + 2*m, &ok);
348 if (segEnd < c) {
349 a = m;
350 } else {
351 b = m;
354 segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok);
355 segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok);
356 segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok);
357 if (c < segStart) {
358 return 0;
360 if (segOffset == 0) {
361 gid = (c + segDelta) & 0xffff;
362 } else {
363 gid = getU16BE(pos + 16 + 6*segCnt + 2*b +
364 segOffset + 2 * (c - segStart), &ok);
365 if (gid != 0) {
366 gid = (gid + segDelta) & 0xffff;
369 break;
370 case 6:
371 cmapFirst = getU16BE(pos + 6, &ok);
372 cmapLen = getU16BE(pos + 8, &ok);
373 if (c < cmapFirst || c >= cmapFirst + cmapLen) {
374 return 0;
376 gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok);
377 break;
378 default:
379 return 0;
381 if (!ok) {
382 return 0;
384 return gid;
387 int FoFiTrueType::mapNameToGID(char *name) {
388 if (!nameToGID) {
389 return 0;
391 return nameToGID->lookupInt(name);
394 int FoFiTrueType::getEmbeddingRights() {
395 int i, fsType;
396 GBool ok;
398 if ((i = seekTable("OS/2")) < 0) {
399 return 4;
401 ok = gTrue;
402 fsType = getU16BE(tables[i].offset + 8, &ok);
403 if (!ok) {
404 return 4;
406 if (fsType & 0x0008) {
407 return 2;
409 if (fsType & 0x0004) {
410 return 1;
412 if (fsType & 0x0002) {
413 return 0;
415 return 3;
418 void FoFiTrueType::convertToType42(char *psName, char **encoding,
419 Gushort *codeToGID,
420 FoFiOutputFunc outputFunc,
421 void *outputStream) {
422 char buf[512];
423 GBool ok;
425 // write the header
426 ok = gTrue;
427 sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
428 (*outputFunc)(outputStream, buf, strlen(buf));
430 // begin the font dictionary
431 (*outputFunc)(outputStream, "10 dict begin\n", 14);
432 (*outputFunc)(outputStream, "/FontName /", 11);
433 (*outputFunc)(outputStream, psName, strlen(psName));
434 (*outputFunc)(outputStream, " def\n", 5);
435 (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
436 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
437 sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
438 bbox[0], bbox[1], bbox[2], bbox[3]);
439 (*outputFunc)(outputStream, buf, strlen(buf));
440 (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
442 // write the guts of the dictionary
443 cvtEncoding(encoding, outputFunc, outputStream);
444 cvtCharStrings(encoding, codeToGID, outputFunc, outputStream);
445 cvtSfnts(outputFunc, outputStream, NULL, gFalse);
447 // end the dictionary and define the font
448 (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
451 void FoFiTrueType::convertToCIDType2(char *psName,
452 Gushort *cidMap, int nCIDs,
453 GBool needVerticalMetrics,
454 FoFiOutputFunc outputFunc,
455 void *outputStream) {
456 char buf[512];
457 Gushort cid;
458 GBool ok;
459 int i, j, k;
461 // write the header
462 ok = gTrue;
463 sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
464 (*outputFunc)(outputStream, buf, strlen(buf));
466 // begin the font dictionary
467 (*outputFunc)(outputStream, "20 dict begin\n", 14);
468 (*outputFunc)(outputStream, "/CIDFontName /", 14);
469 (*outputFunc)(outputStream, psName, strlen(psName));
470 (*outputFunc)(outputStream, " def\n", 5);
471 (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19);
472 (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
473 (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
474 (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24);
475 (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27);
476 (*outputFunc)(outputStream, " /Supplement 0 def\n", 20);
477 (*outputFunc)(outputStream, " end def\n", 10);
478 (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
479 if (cidMap) {
480 sprintf(buf, "/CIDCount %d def\n", nCIDs);
481 (*outputFunc)(outputStream, buf, strlen(buf));
482 if (nCIDs > 32767) {
483 (*outputFunc)(outputStream, "/CIDMap [", 9);
484 for (i = 0; i < nCIDs; i += 32768 - 16) {
485 (*outputFunc)(outputStream, "<\n", 2);
486 for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
487 (*outputFunc)(outputStream, " ", 2);
488 for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
489 cid = cidMap[i+j+k];
490 sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
491 (*outputFunc)(outputStream, buf, strlen(buf));
493 (*outputFunc)(outputStream, "\n", 1);
495 (*outputFunc)(outputStream, " >", 3);
497 (*outputFunc)(outputStream, "\n", 1);
498 (*outputFunc)(outputStream, "] def\n", 6);
499 } else {
500 (*outputFunc)(outputStream, "/CIDMap <\n", 10);
501 for (i = 0; i < nCIDs; i += 16) {
502 (*outputFunc)(outputStream, " ", 2);
503 for (j = 0; j < 16 && i+j < nCIDs; ++j) {
504 cid = cidMap[i+j];
505 sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
506 (*outputFunc)(outputStream, buf, strlen(buf));
508 (*outputFunc)(outputStream, "\n", 1);
510 (*outputFunc)(outputStream, "> def\n", 6);
512 } else {
513 // direct mapping - just fill the string(s) with s[i]=i
514 sprintf(buf, "/CIDCount %d def\n", nGlyphs);
515 (*outputFunc)(outputStream, buf, strlen(buf));
516 if (nGlyphs > 32767) {
517 (*outputFunc)(outputStream, "/CIDMap [\n", 10);
518 for (i = 0; i < nGlyphs; i += 32767) {
519 j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
520 sprintf(buf, " %d string 0 1 %d {\n", 2 * j, j - 1);
521 (*outputFunc)(outputStream, buf, strlen(buf));
522 sprintf(buf, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
523 (*outputFunc)(outputStream, buf, strlen(buf));
524 sprintf(buf, " 1 index exch dup 2 mul 1 add exch %d add"
525 " 255 and put\n", i);
526 (*outputFunc)(outputStream, buf, strlen(buf));
527 (*outputFunc)(outputStream, " } for\n", 8);
529 (*outputFunc)(outputStream, "] def\n", 6);
530 } else {
531 sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs);
532 (*outputFunc)(outputStream, buf, strlen(buf));
533 sprintf(buf, " 0 1 %d {\n", nGlyphs - 1);
534 (*outputFunc)(outputStream, buf, strlen(buf));
535 (*outputFunc)(outputStream,
536 " 2 copy dup 2 mul exch -8 bitshift put\n", 42);
537 (*outputFunc)(outputStream,
538 " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
539 (*outputFunc)(outputStream, " } for\n", 8);
540 (*outputFunc)(outputStream, "def\n", 4);
543 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
544 sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
545 bbox[0], bbox[1], bbox[2], bbox[3]);
546 (*outputFunc)(outputStream, buf, strlen(buf));
547 (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
548 (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
549 (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
550 (*outputFunc)(outputStream, " /.notdef 0 def\n", 17);
551 (*outputFunc)(outputStream, " end readonly def\n", 19);
553 // write the guts of the dictionary
554 cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics);
556 // end the dictionary and define the font
557 (*outputFunc)(outputStream,
558 "CIDFontName currentdict end /CIDFont defineresource pop\n",
559 56);
562 void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
563 GBool needVerticalMetrics,
564 FoFiOutputFunc outputFunc,
565 void *outputStream) {
566 char buf[512];
567 GString *sfntsName;
568 int n, i, j;
570 // write the Type 42 sfnts array
571 sfntsName = (new GString(psName))->append("_sfnts");
572 cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics);
573 delete sfntsName;
575 // write the descendant Type 42 fonts
576 n = cidMap ? nCIDs : nGlyphs;
577 for (i = 0; i < n; i += 256) {
578 (*outputFunc)(outputStream, "10 dict begin\n", 14);
579 (*outputFunc)(outputStream, "/FontName /", 11);
580 (*outputFunc)(outputStream, psName, strlen(psName));
581 sprintf(buf, "_%02x def\n", i >> 8);
582 (*outputFunc)(outputStream, buf, strlen(buf));
583 (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
584 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
585 sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
586 bbox[0], bbox[1], bbox[2], bbox[3]);
587 (*outputFunc)(outputStream, buf, strlen(buf));
588 (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
589 (*outputFunc)(outputStream, "/sfnts ", 7);
590 (*outputFunc)(outputStream, psName, strlen(psName));
591 (*outputFunc)(outputStream, "_sfnts def\n", 11);
592 (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
593 for (j = 0; j < 256 && i+j < n; ++j) {
594 sprintf(buf, "dup %d /c%02x put\n", j, j);
595 (*outputFunc)(outputStream, buf, strlen(buf));
597 (*outputFunc)(outputStream, "readonly def\n", 13);
598 (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
599 (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
600 for (j = 0; j < 256 && i+j < n; ++j) {
601 sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
602 (*outputFunc)(outputStream, buf, strlen(buf));
604 (*outputFunc)(outputStream, "end readonly def\n", 17);
605 (*outputFunc)(outputStream,
606 "FontName currentdict end definefont pop\n", 40);
609 // write the Type 0 parent font
610 (*outputFunc)(outputStream, "16 dict begin\n", 14);
611 (*outputFunc)(outputStream, "/FontName /", 11);
612 (*outputFunc)(outputStream, psName, strlen(psName));
613 (*outputFunc)(outputStream, " def\n", 5);
614 (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
615 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
616 (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
617 (*outputFunc)(outputStream, "/Encoding [\n", 12);
618 for (i = 0; i < n; i += 256) {
619 sprintf(buf, "%d\n", i >> 8);
620 (*outputFunc)(outputStream, buf, strlen(buf));
622 (*outputFunc)(outputStream, "] def\n", 6);
623 (*outputFunc)(outputStream, "/FDepVector [\n", 14);
624 for (i = 0; i < n; i += 256) {
625 (*outputFunc)(outputStream, "/", 1);
626 (*outputFunc)(outputStream, psName, strlen(psName));
627 sprintf(buf, "_%02x findfont\n", i >> 8);
628 (*outputFunc)(outputStream, buf, strlen(buf));
630 (*outputFunc)(outputStream, "] def\n", 6);
631 (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
634 void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
635 void *outputStream, char *name,
636 Gushort *codeToGID) {
637 // this substitute cmap table maps char codes 0000-ffff directly to
638 // glyphs 0000-ffff
639 static char cmapTab[36] = {
640 0, 0, // table version number
641 0, 1, // number of encoding tables
642 0, 1, // platform ID
643 0, 0, // encoding ID
644 0, 0, 0, 12, // offset of subtable
645 0, 4, // subtable format
646 0, 24, // subtable length
647 0, 0, // subtable version
648 0, 2, // segment count * 2
649 0, 2, // 2 * 2 ^ floor(log2(segCount))
650 0, 0, // floor(log2(segCount))
651 0, 0, // 2*segCount - 2*2^floor(log2(segCount))
652 (char)0xff, (char)0xff, // endCount[0]
653 0, 0, // reserved
654 0, 0, // startCount[0]
655 0, 0, // idDelta[0]
656 0, 0 // pad to a mulitple of four bytes
658 static char nameTab[8] = {
659 0, 0, // format
660 0, 0, // number of name records
661 0, 6, // offset to start of string storage
662 0, 0 // pad to multiple of four bytes
664 static char postTab[32] = {
665 0, 1, 0, 0, // format
666 0, 0, 0, 0, // italic angle
667 0, 0, // underline position
668 0, 0, // underline thickness
669 0, 0, 0, 0, // fixed pitch
670 0, 0, 0, 0, // min Type 42 memory
671 0, 0, 0, 0, // max Type 42 memory
672 0, 0, 0, 0, // min Type 1 memory
673 0, 0, 0, 0 // max Type 1 memory
675 GBool missingCmap, missingName, missingPost, unsortedLoca, badCmapLen;
676 int nZeroLengthTables;
677 TrueTypeLoca *locaTable;
678 TrueTypeTable *newTables;
679 char *newNameTab, *newCmapTab;
680 int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next;
681 Guint locaChecksum, glyfChecksum, fileChecksum;
682 char *tableDir;
683 char locaBuf[4], checksumBuf[4];
684 GBool ok;
685 Guint t;
686 int pos, i, j, k, n;
688 // check for missing tables
689 missingCmap = (cmapIdx = seekTable("cmap")) < 0;
690 missingName = seekTable("name") < 0;
691 missingPost = seekTable("post") < 0;
693 // read the loca table, check to see if it's sorted
694 locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
695 unsortedLoca = gFalse;
696 i = seekTable("loca");
697 pos = tables[i].offset;
698 ok = gTrue;
699 for (i = 0; i <= nGlyphs; ++i) {
700 if (locaFmt) {
701 locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
702 } else {
703 locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
705 if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) {
706 unsortedLoca = gTrue;
708 locaTable[i].idx = i;
711 // check for zero-length tables
712 nZeroLengthTables = 0;
713 for (i = 0; i < nTables; ++i) {
714 if (tables[i].len == 0) {
715 ++nZeroLengthTables;
719 // check for an incorrect cmap table length
720 badCmapLen = gFalse;
721 cmapLen = 0; // make gcc happy
722 if (!missingCmap) {
723 cmapLen = cmaps[0].offset + cmaps[0].len;
724 for (i = 1; i < nCmaps; ++i) {
725 if (cmaps[i].offset + cmaps[i].len > cmapLen) {
726 cmapLen = cmaps[i].offset + cmaps[i].len;
729 cmapLen -= tables[cmapIdx].offset;
730 if (cmapLen > tables[cmapIdx].len) {
731 badCmapLen = gTrue;
735 // if nothing is broken, just write the TTF file as is
736 if (!missingCmap && !missingName && !missingPost && !unsortedLoca &&
737 !badCmapLen && nZeroLengthTables == 0 && !name && !codeToGID) {
738 (*outputFunc)(outputStream, (char *)file, len);
739 goto done1;
742 // sort the 'loca' table: some (non-compliant) fonts have
743 // out-of-order loca tables; in order to correctly handle the case
744 // where (compliant) fonts have empty entries in the middle of the
745 // table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
746 // and idx as its secondary key (ensuring that adjacent entries with
747 // the same pos value remain in the same order)
748 glyfLen = 0; // make gcc happy
749 if (unsortedLoca) {
750 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
751 &cmpTrueTypeLocaOffset);
752 for (i = 0; i < nGlyphs; ++i) {
753 locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
755 locaTable[nGlyphs].len = 0;
756 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
757 &cmpTrueTypeLocaIdx);
758 pos = 0;
759 for (i = 0; i <= nGlyphs; ++i) {
760 locaTable[i].newOffset = pos;
761 pos += locaTable[i].len;
762 if (pos & 3) {
763 pos += 4 - (pos & 3);
766 glyfLen = pos;
769 // compute checksums for the loca and glyf tables
770 locaChecksum = glyfChecksum = 0;
771 if (unsortedLoca) {
772 if (locaFmt) {
773 for (j = 0; j <= nGlyphs; ++j) {
774 locaChecksum += locaTable[j].newOffset;
776 } else {
777 for (j = 0; j <= nGlyphs; j += 2) {
778 locaChecksum += locaTable[j].newOffset << 16;
779 if (j + 1 <= nGlyphs) {
780 locaChecksum += locaTable[j+1].newOffset;
784 pos = tables[seekTable("glyf")].offset;
785 for (j = 0; j < nGlyphs; ++j) {
786 n = locaTable[j].len;
787 if (n > 0) {
788 k = locaTable[j].origOffset;
789 if (checkRegion(pos + k, n)) {
790 glyfChecksum += computeTableChecksum(file + pos + k, n);
796 // construct the new name table
797 if (name) {
798 n = strlen(name);
799 newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3;
800 newNameTab = (char *)gmalloc(newNameLen);
801 memset(newNameTab, 0, newNameLen);
802 newNameTab[0] = 0; // format selector
803 newNameTab[1] = 0;
804 newNameTab[2] = 0; // number of name records
805 newNameTab[3] = 4;
806 newNameTab[4] = 0; // offset to start of string storage
807 newNameTab[5] = 6 + 4*12;
808 next = 0;
809 for (i = 0; i < 4; ++i) {
810 newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft
811 newNameTab[6 + i*12 + 1] = 3;
812 newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode
813 newNameTab[6 + i*12 + 3] = 1;
814 newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English
815 newNameTab[6 + i*12 + 5] = 0x09;
816 newNameTab[6 + i*12 + 6] = 0; // name ID
817 newNameTab[6 + i*12 + 7] = i + 1;
818 newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length
819 newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff);
820 newNameTab[6 + i*12 + 10] = next >> 8; // string offset
821 newNameTab[6 + i*12 + 11] = next & 0xff;
822 if (i+1 == 2) {
823 memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14);
824 next += 14;
825 } else {
826 for (j = 0; j < n; ++j) {
827 newNameTab[6 + 4*12 + next + 2*j] = 0;
828 newNameTab[6 + 4*12 + next + 2*j + 1] = name[j];
830 next += 2*n;
833 } else {
834 newNameLen = 0;
835 newNameTab = NULL;
838 // construct the new cmap table
839 if (codeToGID) {
840 newCmapLen = 44 + 256 * 2;
841 newCmapTab = (char *)gmalloc(newCmapLen);
842 newCmapTab[0] = 0; // table version number = 0
843 newCmapTab[1] = 0;
844 newCmapTab[2] = 0; // number of encoding tables = 1
845 newCmapTab[3] = 1;
846 newCmapTab[4] = 0; // platform ID = Microsoft
847 newCmapTab[5] = 3;
848 newCmapTab[6] = 0; // encoding ID = Unicode
849 newCmapTab[7] = 1;
850 newCmapTab[8] = 0; // offset of subtable
851 newCmapTab[9] = 0;
852 newCmapTab[10] = 0;
853 newCmapTab[11] = 12;
854 newCmapTab[12] = 0; // subtable format = 4
855 newCmapTab[13] = 4;
856 newCmapTab[14] = 0x02; // subtable length
857 newCmapTab[15] = 0x20;
858 newCmapTab[16] = 0; // subtable version = 0
859 newCmapTab[17] = 0;
860 newCmapTab[18] = 0; // segment count * 2
861 newCmapTab[19] = 4;
862 newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount))
863 newCmapTab[21] = 4;
864 newCmapTab[22] = 0; // floor(log2(segCount))
865 newCmapTab[23] = 1;
866 newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount))
867 newCmapTab[25] = 0;
868 newCmapTab[26] = 0x00; // endCount[0]
869 newCmapTab[27] = (char)0xff;
870 newCmapTab[28] = (char)0xff; // endCount[1]
871 newCmapTab[29] = (char)0xff;
872 newCmapTab[30] = 0; // reserved
873 newCmapTab[31] = 0;
874 newCmapTab[32] = 0x00; // startCount[0]
875 newCmapTab[33] = 0x00;
876 newCmapTab[34] = (char)0xff; // startCount[1]
877 newCmapTab[35] = (char)0xff;
878 newCmapTab[36] = 0; // idDelta[0]
879 newCmapTab[37] = 0;
880 newCmapTab[38] = 0; // idDelta[1]
881 newCmapTab[39] = 1;
882 newCmapTab[40] = 0; // idRangeOffset[0]
883 newCmapTab[41] = 4;
884 newCmapTab[42] = 0; // idRangeOffset[1]
885 newCmapTab[43] = 0;
886 for (i = 0; i < 256; ++i) {
887 newCmapTab[44 + 2*i] = codeToGID[i] >> 8;
888 newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff;
890 } else {
891 newCmapLen = 0;
892 newCmapTab = NULL;
895 // construct the new table directory:
896 // - keep all original tables with non-zero length
897 // - fix the cmap table's length, if necessary
898 // - add missing tables
899 // - sort the table by tag
900 // - compute new table positions, including 4-byte alignment
901 // - (re)compute table checksums
902 nNewTables = nTables - nZeroLengthTables +
903 (missingCmap ? 1 : 0) + (missingName ? 1 : 0) +
904 (missingPost ? 1 : 0);
905 newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable));
906 j = 0;
907 for (i = 0; i < nTables; ++i) {
908 if (tables[i].len > 0) {
909 newTables[j] = tables[i];
910 newTables[j].origOffset = tables[i].offset;
911 if (checkRegion(tables[i].offset, newTables[i].len)) {
912 newTables[j].checksum =
913 computeTableChecksum(file + tables[i].offset, tables[i].len);
914 if (tables[i].tag == headTag) {
915 // don't include the file checksum
916 newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok);
919 if (newTables[j].tag == cmapTag && codeToGID) {
920 newTables[j].len = newCmapLen;
921 newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
922 newCmapLen);
923 } else if (newTables[j].tag == cmapTag && badCmapLen) {
924 newTables[j].len = cmapLen;
925 } else if (newTables[j].tag == locaTag && unsortedLoca) {
926 newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2);
927 newTables[j].checksum = locaChecksum;
928 } else if (newTables[j].tag == glyfTag && unsortedLoca) {
929 newTables[j].len = glyfLen;
930 newTables[j].checksum = glyfChecksum;
931 } else if (newTables[j].tag == nameTag && name) {
932 newTables[j].len = newNameLen;
933 newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
934 newNameLen);
936 ++j;
939 if (missingCmap) {
940 newTables[j].tag = cmapTag;
941 if (codeToGID) {
942 newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
943 newCmapLen);
944 newTables[j].len = newCmapLen;
945 } else {
946 newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab,
947 sizeof(cmapTab));
948 newTables[j].len = sizeof(cmapTab);
950 ++j;
952 if (missingName) {
953 newTables[j].tag = nameTag;
954 if (name) {
955 newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
956 newNameLen);
957 newTables[j].len = newNameLen;
958 } else {
959 newTables[j].checksum = computeTableChecksum((Guchar *)nameTab,
960 sizeof(nameTab));
961 newTables[j].len = sizeof(nameTab);
963 ++j;
965 if (missingPost) {
966 newTables[j].tag = postTag;
967 newTables[j].checksum = computeTableChecksum((Guchar *)postTab,
968 sizeof(postTab));
969 newTables[j].len = sizeof(postTab);
970 ++j;
972 qsort(newTables, nNewTables, sizeof(TrueTypeTable),
973 &cmpTrueTypeTableTag);
974 pos = 12 + nNewTables * 16;
975 for (i = 0; i < nNewTables; ++i) {
976 newTables[i].offset = pos;
977 pos += newTables[i].len;
978 if (pos & 3) {
979 pos += 4 - (pos & 3);
983 // write the table directory
984 tableDir = (char *)gmalloc(12 + nNewTables * 16);
985 tableDir[0] = 0x00; // sfnt version
986 tableDir[1] = 0x01;
987 tableDir[2] = 0x00;
988 tableDir[3] = 0x00;
989 tableDir[4] = (char)((nNewTables >> 8) & 0xff); // numTables
990 tableDir[5] = (char)(nNewTables & 0xff);
991 for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ;
992 t = 1 << (4 + i);
993 tableDir[6] = (char)((t >> 8) & 0xff); // searchRange
994 tableDir[7] = (char)(t & 0xff);
995 tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector
996 tableDir[9] = (char)(i & 0xff);
997 t = nNewTables * 16 - t;
998 tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift
999 tableDir[11] = (char)(t & 0xff);
1000 pos = 12;
1001 for (i = 0; i < nNewTables; ++i) {
1002 tableDir[pos ] = (char)(newTables[i].tag >> 24);
1003 tableDir[pos+ 1] = (char)(newTables[i].tag >> 16);
1004 tableDir[pos+ 2] = (char)(newTables[i].tag >> 8);
1005 tableDir[pos+ 3] = (char) newTables[i].tag;
1006 tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24);
1007 tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16);
1008 tableDir[pos+ 6] = (char)(newTables[i].checksum >> 8);
1009 tableDir[pos+ 7] = (char) newTables[i].checksum;
1010 tableDir[pos+ 8] = (char)(newTables[i].offset >> 24);
1011 tableDir[pos+ 9] = (char)(newTables[i].offset >> 16);
1012 tableDir[pos+10] = (char)(newTables[i].offset >> 8);
1013 tableDir[pos+11] = (char) newTables[i].offset;
1014 tableDir[pos+12] = (char)(newTables[i].len >> 24);
1015 tableDir[pos+13] = (char)(newTables[i].len >> 16);
1016 tableDir[pos+14] = (char)(newTables[i].len >> 8);
1017 tableDir[pos+15] = (char) newTables[i].len;
1018 pos += 16;
1020 (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16);
1022 // compute the file checksum
1023 fileChecksum = computeTableChecksum((Guchar *)tableDir,
1024 12 + nNewTables * 16);
1025 for (i = 0; i < nNewTables; ++i) {
1026 fileChecksum += newTables[i].checksum;
1028 fileChecksum = 0xb1b0afba - fileChecksum;
1030 // write the tables
1031 for (i = 0; i < nNewTables; ++i) {
1032 if (newTables[i].tag == headTag) {
1033 if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
1034 (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8);
1035 checksumBuf[0] = fileChecksum >> 24;
1036 checksumBuf[1] = fileChecksum >> 16;
1037 checksumBuf[2] = fileChecksum >> 8;
1038 checksumBuf[3] = fileChecksum;
1039 (*outputFunc)(outputStream, checksumBuf, 4);
1040 (*outputFunc)(outputStream,
1041 (char *)file + newTables[i].origOffset + 12,
1042 newTables[i].len - 12);
1043 } else {
1044 for (j = 0; j < newTables[i].len; ++j) {
1045 (*outputFunc)(outputStream, "\0", 1);
1048 } else if (newTables[i].tag == cmapTag && codeToGID) {
1049 (*outputFunc)(outputStream, newCmapTab, newTables[i].len);
1050 } else if (newTables[i].tag == cmapTag && missingCmap) {
1051 (*outputFunc)(outputStream, cmapTab, newTables[i].len);
1052 } else if (newTables[i].tag == nameTag && name) {
1053 (*outputFunc)(outputStream, newNameTab, newTables[i].len);
1054 } else if (newTables[i].tag == nameTag && missingName) {
1055 (*outputFunc)(outputStream, nameTab, newTables[i].len);
1056 } else if (newTables[i].tag == postTag && missingPost) {
1057 (*outputFunc)(outputStream, postTab, newTables[i].len);
1058 } else if (newTables[i].tag == locaTag && unsortedLoca) {
1059 for (j = 0; j <= nGlyphs; ++j) {
1060 if (locaFmt) {
1061 locaBuf[0] = (char)(locaTable[j].newOffset >> 24);
1062 locaBuf[1] = (char)(locaTable[j].newOffset >> 16);
1063 locaBuf[2] = (char)(locaTable[j].newOffset >> 8);
1064 locaBuf[3] = (char) locaTable[j].newOffset;
1065 (*outputFunc)(outputStream, locaBuf, 4);
1066 } else {
1067 locaBuf[0] = (char)(locaTable[j].newOffset >> 9);
1068 locaBuf[1] = (char)(locaTable[j].newOffset >> 1);
1069 (*outputFunc)(outputStream, locaBuf, 2);
1072 } else if (newTables[i].tag == glyfTag && unsortedLoca) {
1073 pos = tables[seekTable("glyf")].offset;
1074 for (j = 0; j < nGlyphs; ++j) {
1075 n = locaTable[j].len;
1076 if (n > 0) {
1077 k = locaTable[j].origOffset;
1078 if (checkRegion(pos + k, n)) {
1079 (*outputFunc)(outputStream, (char *)file + pos + k, n);
1080 } else {
1081 for (k = 0; k < n; ++k) {
1082 (*outputFunc)(outputStream, "\0", 1);
1085 if ((k = locaTable[j].len & 3)) {
1086 (*outputFunc)(outputStream, "\0\0\0\0", 4 - k);
1090 } else {
1091 if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
1092 (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset,
1093 newTables[i].len);
1094 } else {
1095 for (j = 0; j < newTables[i].len; ++j) {
1096 (*outputFunc)(outputStream, "\0", 1);
1100 if (newTables[i].len & 3) {
1101 (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3));
1105 gfree(newCmapTab);
1106 gfree(newNameTab);
1107 gfree(tableDir);
1108 gfree(newTables);
1109 done1:
1110 gfree(locaTable);
1113 void FoFiTrueType::cvtEncoding(char **encoding,
1114 FoFiOutputFunc outputFunc,
1115 void *outputStream) {
1116 char *name;
1117 char buf[64];
1118 int i;
1120 (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
1121 if (encoding) {
1122 for (i = 0; i < 256; ++i) {
1123 if (!(name = encoding[i])) {
1124 name = ".notdef";
1126 sprintf(buf, "dup %d /", i);
1127 (*outputFunc)(outputStream, buf, strlen(buf));
1128 (*outputFunc)(outputStream, name, strlen(name));
1129 (*outputFunc)(outputStream, " put\n", 5);
1131 } else {
1132 for (i = 0; i < 256; ++i) {
1133 sprintf(buf, "dup %d /c%02x put\n", i, i);
1134 (*outputFunc)(outputStream, buf, strlen(buf));
1137 (*outputFunc)(outputStream, "readonly def\n", 13);
1140 void FoFiTrueType::cvtCharStrings(char **encoding,
1141 Gushort *codeToGID,
1142 FoFiOutputFunc outputFunc,
1143 void *outputStream) {
1144 char *name;
1145 char buf[64], buf2[16];
1146 int i, k;
1148 // always define '.notdef'
1149 (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32);
1150 (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
1152 // if there's no 'cmap' table, punt
1153 if (nCmaps == 0) {
1154 goto err;
1157 // map char name to glyph index:
1158 // 1. use encoding to map name to char code
1159 // 2. use codeToGID to map char code to glyph index
1160 // N.B. We do this in reverse order because font subsets can have
1161 // weird encodings that use the same character name twice, and
1162 // the first definition is probably the one we want.
1163 k = 0; // make gcc happy
1164 for (i = 255; i >= 0; --i) {
1165 if (encoding) {
1166 name = encoding[i];
1167 } else {
1168 sprintf(buf2, "c%02x", i);
1169 name = buf2;
1171 if (name && strcmp(name, ".notdef")) {
1172 k = codeToGID[i];
1173 // note: Distiller (maybe Adobe's PS interpreter in general)
1174 // doesn't like TrueType fonts that have CharStrings entries
1175 // which point to nonexistent glyphs, hence the (k < nGlyphs)
1176 // test
1177 if (k > 0 && k < nGlyphs) {
1178 (*outputFunc)(outputStream, "/", 1);
1179 (*outputFunc)(outputStream, name, strlen(name));
1180 sprintf(buf, " %d def\n", k);
1181 (*outputFunc)(outputStream, buf, strlen(buf));
1186 err:
1187 (*outputFunc)(outputStream, "end readonly def\n", 17);
1190 void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
1191 void *outputStream, GString *name,
1192 GBool needVerticalMetrics) {
1193 Guchar headData[54];
1194 TrueTypeLoca *locaTable;
1195 Guchar *locaData;
1196 TrueTypeTable newTables[nT42Tables];
1197 Guchar tableDir[12 + nT42Tables*16];
1198 GBool ok;
1199 Guint checksum;
1200 int nNewTables;
1201 int length, pos, glyfPos, i, j, k;
1202 Guchar vheaTab[36] = {
1203 0, 1, 0, 0, // table version number
1204 0, 0, // ascent
1205 0, 0, // descent
1206 0, 0, // reserved
1207 0, 0, // max advance height
1208 0, 0, // min top side bearing
1209 0, 0, // min bottom side bearing
1210 0, 0, // y max extent
1211 0, 0, // caret slope rise
1212 0, 1, // caret slope run
1213 0, 0, // caret offset
1214 0, 0, // reserved
1215 0, 0, // reserved
1216 0, 0, // reserved
1217 0, 0, // reserved
1218 0, 0, // metric data format
1219 0, 1 // number of advance heights in vmtx table
1221 Guchar *vmtxTab;
1222 GBool needVhea, needVmtx;
1223 int advance;
1225 // construct the 'head' table, zero out the font checksum
1226 i = seekTable("head");
1227 pos = tables[i].offset;
1228 if (!checkRegion(pos, 54)) {
1229 return;
1231 memcpy(headData, file + pos, 54);
1232 headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0;
1234 // read the original 'loca' table, pad entries out to 4 bytes, and
1235 // sort it into proper order -- some (non-compliant) fonts have
1236 // out-of-order loca tables; in order to correctly handle the case
1237 // where (compliant) fonts have empty entries in the middle of the
1238 // table, cmpTrueTypeLocaPos uses offset as its primary sort key,
1239 // and idx as its secondary key (ensuring that adjacent entries with
1240 // the same pos value remain in the same order)
1241 locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
1242 i = seekTable("loca");
1243 pos = tables[i].offset;
1244 ok = gTrue;
1245 for (i = 0; i <= nGlyphs; ++i) {
1246 locaTable[i].idx = i;
1247 if (locaFmt) {
1248 locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
1249 } else {
1250 locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
1253 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
1254 &cmpTrueTypeLocaOffset);
1255 for (i = 0; i < nGlyphs; ++i) {
1256 locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
1258 locaTable[nGlyphs].len = 0;
1259 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
1260 &cmpTrueTypeLocaIdx);
1261 pos = 0;
1262 for (i = 0; i <= nGlyphs; ++i) {
1263 locaTable[i].newOffset = pos;
1264 pos += locaTable[i].len;
1265 if (pos & 3) {
1266 pos += 4 - (pos & 3);
1270 // construct the new 'loca' table
1271 locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2));
1272 for (i = 0; i <= nGlyphs; ++i) {
1273 pos = locaTable[i].newOffset;
1274 if (locaFmt) {
1275 locaData[4*i ] = (Guchar)(pos >> 24);
1276 locaData[4*i+1] = (Guchar)(pos >> 16);
1277 locaData[4*i+2] = (Guchar)(pos >> 8);
1278 locaData[4*i+3] = (Guchar) pos;
1279 } else {
1280 locaData[2*i ] = (Guchar)(pos >> 9);
1281 locaData[2*i+1] = (Guchar)(pos >> 1);
1285 // count the number of tables
1286 nNewTables = 0;
1287 for (i = 0; i < nT42Tables; ++i) {
1288 if (t42Tables[i].required ||
1289 seekTable(t42Tables[i].tag) >= 0) {
1290 ++nNewTables;
1293 vmtxTab = NULL; // make gcc happy
1294 advance = 0; // make gcc happy
1295 if (needVerticalMetrics) {
1296 needVhea = seekTable("vhea") < 0;
1297 needVmtx = seekTable("vmtx") < 0;
1298 if (needVhea || needVmtx) {
1299 i = seekTable("head");
1300 advance = getU16BE(tables[i].offset + 18, &ok); // units per em
1301 if (needVhea) {
1302 ++nNewTables;
1304 if (needVmtx) {
1305 ++nNewTables;
1310 // construct the new table headers, including table checksums
1311 // (pad each table out to a multiple of 4 bytes)
1312 pos = 12 + nNewTables*16;
1313 k = 0;
1314 for (i = 0; i < nT42Tables; ++i) {
1315 length = -1;
1316 checksum = 0; // make gcc happy
1317 if (i == t42HeadTable) {
1318 length = 54;
1319 checksum = computeTableChecksum(headData, 54);
1320 } else if (i == t42LocaTable) {
1321 length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1322 checksum = computeTableChecksum(locaData, length);
1323 } else if (i == t42GlyfTable) {
1324 length = 0;
1325 checksum = 0;
1326 glyfPos = tables[seekTable("glyf")].offset;
1327 for (j = 0; j < nGlyphs; ++j) {
1328 length += locaTable[j].len;
1329 if (length & 3) {
1330 length += 4 - (length & 3);
1332 if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1333 checksum +=
1334 computeTableChecksum(file + glyfPos + locaTable[j].origOffset,
1335 locaTable[j].len);
1338 } else {
1339 if ((j = seekTable(t42Tables[i].tag)) >= 0) {
1340 length = tables[j].len;
1341 if (checkRegion(tables[j].offset, length)) {
1342 checksum = computeTableChecksum(file + tables[j].offset, length);
1344 } else if (needVerticalMetrics && i == t42VheaTable) {
1345 vheaTab[10] = advance / 256; // max advance height
1346 vheaTab[11] = advance % 256;
1347 length = sizeof(vheaTab);
1348 checksum = computeTableChecksum(vheaTab, length);
1349 } else if (needVerticalMetrics && i == t42VmtxTable) {
1350 length = 4 + (nGlyphs - 1) * 4;
1351 vmtxTab = (Guchar *)gmalloc(length);
1352 vmtxTab[0] = advance / 256;
1353 vmtxTab[1] = advance % 256;
1354 for (j = 2; j < length; j += 2) {
1355 vmtxTab[j] = 0;
1356 vmtxTab[j+1] = 0;
1358 checksum = computeTableChecksum(vmtxTab, length);
1359 } else if (t42Tables[i].required) {
1360 //~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
1361 //~ t42Tables[i].tag);
1362 length = 0;
1363 checksum = 0;
1366 if (length >= 0) {
1367 newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) |
1368 ((t42Tables[i].tag[1] & 0xff) << 16) |
1369 ((t42Tables[i].tag[2] & 0xff) << 8) |
1370 (t42Tables[i].tag[3] & 0xff);
1371 newTables[k].checksum = checksum;
1372 newTables[k].offset = pos;
1373 newTables[k].len = length;
1374 pos += length;
1375 if (pos & 3) {
1376 pos += 4 - (length & 3);
1378 ++k;
1382 // construct the table directory
1383 tableDir[0] = 0x00; // sfnt version
1384 tableDir[1] = 0x01;
1385 tableDir[2] = 0x00;
1386 tableDir[3] = 0x00;
1387 tableDir[4] = 0; // numTables
1388 tableDir[5] = nNewTables;
1389 tableDir[6] = 0; // searchRange
1390 tableDir[7] = (Guchar)128;
1391 tableDir[8] = 0; // entrySelector
1392 tableDir[9] = 3;
1393 tableDir[10] = 0; // rangeShift
1394 tableDir[11] = (Guchar)(16 * nNewTables - 128);
1395 pos = 12;
1396 for (i = 0; i < nNewTables; ++i) {
1397 tableDir[pos ] = (Guchar)(newTables[i].tag >> 24);
1398 tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16);
1399 tableDir[pos+ 2] = (Guchar)(newTables[i].tag >> 8);
1400 tableDir[pos+ 3] = (Guchar) newTables[i].tag;
1401 tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24);
1402 tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16);
1403 tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >> 8);
1404 tableDir[pos+ 7] = (Guchar) newTables[i].checksum;
1405 tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24);
1406 tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16);
1407 tableDir[pos+10] = (Guchar)(newTables[i].offset >> 8);
1408 tableDir[pos+11] = (Guchar) newTables[i].offset;
1409 tableDir[pos+12] = (Guchar)(newTables[i].len >> 24);
1410 tableDir[pos+13] = (Guchar)(newTables[i].len >> 16);
1411 tableDir[pos+14] = (Guchar)(newTables[i].len >> 8);
1412 tableDir[pos+15] = (Guchar) newTables[i].len;
1413 pos += 16;
1416 // compute the font checksum and store it in the head table
1417 checksum = computeTableChecksum(tableDir, 12 + nNewTables*16);
1418 for (i = 0; i < nNewTables; ++i) {
1419 checksum += newTables[i].checksum;
1421 checksum = 0xb1b0afba - checksum; // because the TrueType spec says so
1422 headData[ 8] = (Guchar)(checksum >> 24);
1423 headData[ 9] = (Guchar)(checksum >> 16);
1424 headData[10] = (Guchar)(checksum >> 8);
1425 headData[11] = (Guchar) checksum;
1427 // start the sfnts array
1428 if (name) {
1429 (*outputFunc)(outputStream, "/", 1);
1430 (*outputFunc)(outputStream, name->getCString(), name->getLength());
1431 (*outputFunc)(outputStream, " [\n", 3);
1432 } else {
1433 (*outputFunc)(outputStream, "/sfnts [\n", 9);
1436 // write the table directory
1437 dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream);
1439 // write the tables
1440 for (i = 0; i < nNewTables; ++i) {
1441 if (i == t42HeadTable) {
1442 dumpString(headData, 54, outputFunc, outputStream);
1443 } else if (i == t42LocaTable) {
1444 length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1445 dumpString(locaData, length, outputFunc, outputStream);
1446 } else if (i == t42GlyfTable) {
1447 glyfPos = tables[seekTable("glyf")].offset;
1448 for (j = 0; j < nGlyphs; ++j) {
1449 if (locaTable[j].len > 0 &&
1450 checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1451 dumpString(file + glyfPos + locaTable[j].origOffset,
1452 locaTable[j].len, outputFunc, outputStream);
1455 } else {
1456 // length == 0 means the table is missing and the error was
1457 // already reported during the construction of the table
1458 // headers
1459 if ((length = newTables[i].len) > 0) {
1460 if ((j = seekTable(t42Tables[i].tag)) >= 0 &&
1461 checkRegion(tables[j].offset, tables[j].len)) {
1462 dumpString(file + tables[j].offset, tables[j].len,
1463 outputFunc, outputStream);
1464 } else if (needVerticalMetrics && i == t42VheaTable) {
1465 dumpString(vheaTab, length, outputFunc, outputStream);
1466 } else if (needVerticalMetrics && i == t42VmtxTable) {
1467 dumpString(vmtxTab, length, outputFunc, outputStream);
1468 gfree(vmtxTab);
1474 // end the sfnts array
1475 (*outputFunc)(outputStream, "] def\n", 6);
1477 gfree(locaData);
1478 gfree(locaTable);
1481 void FoFiTrueType::dumpString(Guchar *s, int length,
1482 FoFiOutputFunc outputFunc,
1483 void *outputStream) {
1484 char buf[64];
1485 int pad, i, j;
1487 (*outputFunc)(outputStream, "<", 1);
1488 for (i = 0; i < length; i += 32) {
1489 for (j = 0; j < 32 && i+j < length; ++j) {
1490 sprintf(buf, "%02X", s[i+j] & 0xff);
1491 (*outputFunc)(outputStream, buf, strlen(buf));
1493 if (i % (65536 - 32) == 65536 - 64) {
1494 (*outputFunc)(outputStream, ">\n<", 3);
1495 } else if (i+32 < length) {
1496 (*outputFunc)(outputStream, "\n", 1);
1499 if (length & 3) {
1500 pad = 4 - (length & 3);
1501 for (i = 0; i < pad; ++i) {
1502 (*outputFunc)(outputStream, "00", 2);
1505 // add an extra zero byte because the Adobe Type 42 spec says so
1506 (*outputFunc)(outputStream, "00>\n", 4);
1509 Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) {
1510 Guint checksum, word;
1511 int i;
1513 checksum = 0;
1514 for (i = 0; i+3 < length; i += 4) {
1515 word = ((data[i ] & 0xff) << 24) +
1516 ((data[i+1] & 0xff) << 16) +
1517 ((data[i+2] & 0xff) << 8) +
1518 (data[i+3] & 0xff);
1519 checksum += word;
1521 if (length & 3) {
1522 word = 0;
1523 i = length & ~3;
1524 switch (length & 3) {
1525 case 3:
1526 word |= (data[i+2] & 0xff) << 8;
1527 case 2:
1528 word |= (data[i+1] & 0xff) << 16;
1529 case 1:
1530 word |= (data[i ] & 0xff) << 24;
1531 break;
1533 checksum += word;
1535 return checksum;
1538 void FoFiTrueType::parse() {
1539 Guint topTag;
1540 int pos, i, j;
1542 parsedOk = gTrue;
1544 // look for a collection (TTC)
1545 topTag = getU32BE(0, &parsedOk);
1546 if (!parsedOk) {
1547 return;
1549 if (topTag == ttcfTag) {
1550 pos = getU32BE(12, &parsedOk);
1551 if (!parsedOk) {
1552 return;
1554 } else {
1555 pos = 0;
1558 // read the table directory
1559 nTables = getU16BE(pos + 4, &parsedOk);
1560 if (!parsedOk) {
1561 return;
1563 tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable));
1564 pos += 12;
1565 for (i = 0; i < nTables; ++i) {
1566 tables[i].tag = getU32BE(pos, &parsedOk);
1567 tables[i].checksum = getU32BE(pos + 4, &parsedOk);
1568 tables[i].offset = (int)getU32BE(pos + 8, &parsedOk);
1569 tables[i].len = (int)getU32BE(pos + 12, &parsedOk);
1570 if (tables[i].offset + tables[i].len < tables[i].offset ||
1571 tables[i].offset + tables[i].len > len) {
1572 parsedOk = gFalse;
1574 pos += 16;
1576 if (!parsedOk) {
1577 return;
1580 // check for tables that are required by both the TrueType spec and
1581 // the Type 42 spec
1582 if (seekTable("head") < 0 ||
1583 seekTable("hhea") < 0 ||
1584 seekTable("loca") < 0 ||
1585 seekTable("maxp") < 0 ||
1586 seekTable("glyf") < 0 ||
1587 seekTable("hmtx") < 0) {
1588 parsedOk = gFalse;
1589 return;
1592 // read the cmaps
1593 if ((i = seekTable("cmap")) >= 0) {
1594 pos = tables[i].offset + 2;
1595 nCmaps = getU16BE(pos, &parsedOk);
1596 pos += 2;
1597 if (!parsedOk) {
1598 return;
1600 cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap));
1601 for (j = 0; j < nCmaps; ++j) {
1602 cmaps[j].platform = getU16BE(pos, &parsedOk);
1603 cmaps[j].encoding = getU16BE(pos + 2, &parsedOk);
1604 cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk);
1605 pos += 8;
1606 cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk);
1607 cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk);
1609 if (!parsedOk) {
1610 return;
1612 } else {
1613 nCmaps = 0;
1616 // get the number of glyphs from the maxp table
1617 i = seekTable("maxp");
1618 nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk);
1619 if (!parsedOk) {
1620 return;
1623 // get the bbox and loca table format from the head table
1624 i = seekTable("head");
1625 bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk);
1626 bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk);
1627 bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk);
1628 bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk);
1629 locaFmt = getS16BE(tables[i].offset + 50, &parsedOk);
1630 if (!parsedOk) {
1631 return;
1634 // make sure the loca table is sane (correct length and entries are
1635 // in bounds)
1636 i = seekTable("loca");
1637 if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) {
1638 parsedOk = gFalse;
1639 return;
1641 for (j = 0; j <= nGlyphs; ++j) {
1642 if (locaFmt) {
1643 pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk);
1644 } else {
1645 pos = getU16BE(tables[i].offset + j*2, &parsedOk);
1647 if (pos < 0 || pos > len) {
1648 parsedOk = gFalse;
1651 if (!parsedOk) {
1652 return;
1655 // read the post table
1656 readPostTable();
1659 void FoFiTrueType::readPostTable() {
1660 GString *name;
1661 int tablePos, postFmt, stringIdx, stringPos;
1662 GBool ok;
1663 int i, j, n, m;
1665 ok = gTrue;
1666 if ((i = seekTable("post")) < 0) {
1667 return;
1669 tablePos = tables[i].offset;
1670 postFmt = getU32BE(tablePos, &ok);
1671 if (!ok) {
1672 goto err;
1674 if (postFmt == 0x00010000) {
1675 nameToGID = new GHash(gTrue);
1676 for (i = 0; i < 258; ++i) {
1677 nameToGID->add(new GString(macGlyphNames[i]), i);
1679 } else if (postFmt == 0x00020000) {
1680 nameToGID = new GHash(gTrue);
1681 n = getU16BE(tablePos + 32, &ok);
1682 if (!ok) {
1683 goto err;
1685 if (n > nGlyphs) {
1686 n = nGlyphs;
1688 stringIdx = 0;
1689 stringPos = tablePos + 34 + 2*n;
1690 for (i = 0; i < n; ++i) {
1691 j = getU16BE(tablePos + 34 + 2*i, &ok);
1692 if (j < 258) {
1693 nameToGID->removeInt(macGlyphNames[j]);
1694 nameToGID->add(new GString(macGlyphNames[j]), i);
1695 } else {
1696 j -= 258;
1697 if (j != stringIdx) {
1698 for (stringIdx = 0, stringPos = tablePos + 34 + 2*n;
1699 stringIdx < j;
1700 ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ;
1701 if (!ok) {
1702 goto err;
1705 m = getU8(stringPos, &ok);
1706 if (!ok || !checkRegion(stringPos + 1, m)) {
1707 goto err;
1709 name = new GString((char *)&file[stringPos + 1], m);
1710 nameToGID->removeInt(name);
1711 nameToGID->add(name, i);
1712 ++stringIdx;
1713 stringPos += 1 + m;
1716 } else if (postFmt == 0x00028000) {
1717 nameToGID = new GHash(gTrue);
1718 for (i = 0; i < nGlyphs; ++i) {
1719 j = getU8(tablePos + 32 + i, &ok);
1720 if (!ok) {
1721 goto err;
1723 if (j < 258) {
1724 nameToGID->removeInt(macGlyphNames[j]);
1725 nameToGID->add(new GString(macGlyphNames[j]), i);
1730 return;
1732 err:
1733 if (nameToGID) {
1734 delete nameToGID;
1735 nameToGID = NULL;
1739 int FoFiTrueType::seekTable(char *tag) {
1740 Guint tagI;
1741 int i;
1743 tagI = ((tag[0] & 0xff) << 24) |
1744 ((tag[1] & 0xff) << 16) |
1745 ((tag[2] & 0xff) << 8) |
1746 (tag[3] & 0xff);
1747 for (i = 0; i < nTables; ++i) {
1748 if (tables[i].tag == tagI) {
1749 return i;
1752 return -1;