1 //========================================================================
5 // Copyright 1999-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
21 #include "FoFiTrueType.h"
27 // character code = number used as an element of a text string
29 // character name = glyph name = name for a particular glyph within a
32 // glyph index = GID = position (within some internal table in the font)
33 // where the instructions to draw a particular glyph are
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
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
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
{
101 struct TrueTypeLoca
{
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 //------------------------------------------------------------------------
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
] = {
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",
188 "Y", "Z", "bracketleft", "backslash",
189 "bracketright", "asciicircum", "underscore", "grave",
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",
240 //------------------------------------------------------------------------
242 //------------------------------------------------------------------------
244 FoFiTrueType
*FoFiTrueType::make(char *fileA
, int lenA
) {
247 ff
= new FoFiTrueType(fileA
, lenA
, gFalse
);
255 FoFiTrueType
*FoFiTrueType::load(char *fileName
) {
260 if (!(fileA
= FoFiBase::readFile(fileName
, &lenA
))) {
263 ff
= new FoFiTrueType(fileA
, lenA
, gTrue
);
271 FoFiTrueType::FoFiTrueType(char *fileA
, int lenA
, GBool freeFileDataA
):
272 FoFiBase(fileA
, lenA
, freeFileDataA
)
284 FoFiTrueType::~FoFiTrueType() {
292 int FoFiTrueType::getNumCmaps() {
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
) {
307 for (i
= 0; i
< nCmaps
; ++i
) {
308 if (cmaps
[i
].platform
== platform
&& cmaps
[i
].encoding
== encoding
) {
315 Gushort
FoFiTrueType::mapCodeToGID(int i
, int c
) {
317 int segCnt
, segEnd
, segStart
, segDelta
, segOffset
;
318 int cmapFirst
, cmapLen
;
322 if (i
< 0 || i
>= nCmaps
) {
326 pos
= cmaps
[i
].offset
;
327 switch (cmaps
[i
].fmt
) {
329 if (c
< 0 || c
>= cmaps
[i
].len
- 6) {
332 gid
= getU8(cmaps
[i
].offset
+ 6 + c
, &ok
);
335 segCnt
= getU16BE(pos
+ 6, &ok
) / 2;
338 segEnd
= getU16BE(pos
+ 14 + 2*b
, &ok
);
340 // malformed font -- the TrueType spec requires the last segEnd
344 // invariant: seg[a].end < code <= seg[b].end
345 while (b
- a
> 1 && ok
) {
347 segEnd
= getU16BE(pos
+ 14 + 2*m
, &ok
);
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
);
360 if (segOffset
== 0) {
361 gid
= (c
+ segDelta
) & 0xffff;
363 gid
= getU16BE(pos
+ 16 + 6*segCnt
+ 2*b
+
364 segOffset
+ 2 * (c
- segStart
), &ok
);
366 gid
= (gid
+ segDelta
) & 0xffff;
371 cmapFirst
= getU16BE(pos
+ 6, &ok
);
372 cmapLen
= getU16BE(pos
+ 8, &ok
);
373 if (c
< cmapFirst
|| c
>= cmapFirst
+ cmapLen
) {
376 gid
= getU16BE(pos
+ 10 + 2 * (c
- cmapFirst
), &ok
);
387 int FoFiTrueType::mapNameToGID(char *name
) {
391 return nameToGID
->lookupInt(name
);
394 int FoFiTrueType::getEmbeddingRights() {
398 if ((i
= seekTable("OS/2")) < 0) {
402 fsType
= getU16BE(tables
[i
].offset
+ 8, &ok
);
406 if (fsType
& 0x0008) {
409 if (fsType
& 0x0004) {
412 if (fsType
& 0x0002) {
418 void FoFiTrueType::convertToType42(char *psName
, char **encoding
,
420 FoFiOutputFunc outputFunc
,
421 void *outputStream
) {
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
) {
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);
480 sprintf(buf
, "/CIDCount %d def\n", nCIDs
);
481 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
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
) {
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);
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
) {
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);
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);
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",
562 void FoFiTrueType::convertToType0(char *psName
, Gushort
*cidMap
, int nCIDs
,
563 GBool needVerticalMetrics
,
564 FoFiOutputFunc outputFunc
,
565 void *outputStream
) {
570 // write the Type 42 sfnts array
571 sfntsName
= (new GString(psName
))->append("_sfnts");
572 cvtSfnts(outputFunc
, outputStream
, sfntsName
, needVerticalMetrics
);
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
639 static char cmapTab
[36] = {
640 0, 0, // table version number
641 0, 1, // number of encoding tables
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]
654 0, 0, // startCount[0]
656 0, 0 // pad to a mulitple of four bytes
658 static char nameTab
[8] = {
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
;
683 char locaBuf
[4], checksumBuf
[4];
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
;
699 for (i
= 0; i
<= nGlyphs
; ++i
) {
701 locaTable
[i
].origOffset
= (int)getU32BE(pos
+ i
*4, &ok
);
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) {
719 // check for an incorrect cmap table length
721 cmapLen
= 0; // make gcc happy
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
) {
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
);
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
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
);
759 for (i
= 0; i
<= nGlyphs
; ++i
) {
760 locaTable
[i
].newOffset
= pos
;
761 pos
+= locaTable
[i
].len
;
763 pos
+= 4 - (pos
& 3);
769 // compute checksums for the loca and glyf tables
770 locaChecksum
= glyfChecksum
= 0;
773 for (j
= 0; j
<= nGlyphs
; ++j
) {
774 locaChecksum
+= locaTable
[j
].newOffset
;
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
;
788 k
= locaTable
[j
].origOffset
;
789 if (checkRegion(pos
+ k
, n
)) {
790 glyfChecksum
+= computeTableChecksum(file
+ pos
+ k
, n
);
796 // construct the new name table
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
804 newNameTab
[2] = 0; // number of name records
806 newNameTab
[4] = 0; // offset to start of string storage
807 newNameTab
[5] = 6 + 4*12;
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;
823 memcpy(newNameTab
+ 6 + 4*12 + next
, "\0R\0e\0g\0u\0l\0a\0r", 14);
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
];
838 // construct the new cmap table
840 newCmapLen
= 44 + 256 * 2;
841 newCmapTab
= (char *)gmalloc(newCmapLen
);
842 newCmapTab
[0] = 0; // table version number = 0
844 newCmapTab
[2] = 0; // number of encoding tables = 1
846 newCmapTab
[4] = 0; // platform ID = Microsoft
848 newCmapTab
[6] = 0; // encoding ID = Unicode
850 newCmapTab
[8] = 0; // offset of subtable
854 newCmapTab
[12] = 0; // subtable format = 4
856 newCmapTab
[14] = 0x02; // subtable length
857 newCmapTab
[15] = 0x20;
858 newCmapTab
[16] = 0; // subtable version = 0
860 newCmapTab
[18] = 0; // segment count * 2
862 newCmapTab
[20] = 0; // 2 * 2 ^ floor(log2(segCount))
864 newCmapTab
[22] = 0; // floor(log2(segCount))
866 newCmapTab
[24] = 0; // 2*segCount - 2*2^floor(log2(segCount))
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
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]
880 newCmapTab
[38] = 0; // idDelta[1]
882 newCmapTab
[40] = 0; // idRangeOffset[0]
884 newCmapTab
[42] = 0; // idRangeOffset[1]
886 for (i
= 0; i
< 256; ++i
) {
887 newCmapTab
[44 + 2*i
] = codeToGID
[i
] >> 8;
888 newCmapTab
[44 + 2*i
+ 1] = codeToGID
[i
] & 0xff;
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
));
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
,
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
,
940 newTables
[j
].tag
= cmapTag
;
942 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)newCmapTab
,
944 newTables
[j
].len
= newCmapLen
;
946 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)cmapTab
,
948 newTables
[j
].len
= sizeof(cmapTab
);
953 newTables
[j
].tag
= nameTag
;
955 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)newNameTab
,
957 newTables
[j
].len
= newNameLen
;
959 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)nameTab
,
961 newTables
[j
].len
= sizeof(nameTab
);
966 newTables
[j
].tag
= postTag
;
967 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)postTab
,
969 newTables
[j
].len
= sizeof(postTab
);
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
;
979 pos
+= 4 - (pos
& 3);
983 // write the table directory
984 tableDir
= (char *)gmalloc(12 + nNewTables
* 16);
985 tableDir
[0] = 0x00; // sfnt version
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) ;
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);
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
;
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
;
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);
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
) {
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);
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
;
1077 k
= locaTable
[j
].origOffset
;
1078 if (checkRegion(pos
+ k
, n
)) {
1079 (*outputFunc
)(outputStream
, (char *)file
+ pos
+ k
, n
);
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
);
1091 if (checkRegion(newTables
[i
].origOffset
, newTables
[i
].len
)) {
1092 (*outputFunc
)(outputStream
, (char *)file
+ newTables
[i
].origOffset
,
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));
1113 void FoFiTrueType::cvtEncoding(char **encoding
,
1114 FoFiOutputFunc outputFunc
,
1115 void *outputStream
) {
1120 (*outputFunc
)(outputStream
, "/Encoding 256 array\n", 20);
1122 for (i
= 0; i
< 256; ++i
) {
1123 if (!(name
= encoding
[i
])) {
1126 sprintf(buf
, "dup %d /", i
);
1127 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
1128 (*outputFunc
)(outputStream
, name
, strlen(name
));
1129 (*outputFunc
)(outputStream
, " put\n", 5);
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
,
1142 FoFiOutputFunc outputFunc
,
1143 void *outputStream
) {
1145 char buf
[64], buf2
[16];
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
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
) {
1168 sprintf(buf2
, "c%02x", i
);
1171 if (name
&& strcmp(name
, ".notdef")) {
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)
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
));
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
;
1196 TrueTypeTable newTables
[nT42Tables
];
1197 Guchar tableDir
[12 + nT42Tables
*16];
1201 int length
, pos
, glyfPos
, i
, j
, k
;
1202 Guchar vheaTab
[36] = {
1203 0, 1, 0, 0, // table version number
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
1218 0, 0, // metric data format
1219 0, 1 // number of advance heights in vmtx table
1222 GBool needVhea
, needVmtx
;
1225 // construct the 'head' table, zero out the font checksum
1226 i
= seekTable("head");
1227 pos
= tables
[i
].offset
;
1228 if (!checkRegion(pos
, 54)) {
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
;
1245 for (i
= 0; i
<= nGlyphs
; ++i
) {
1246 locaTable
[i
].idx
= i
;
1248 locaTable
[i
].origOffset
= (int)getU32BE(pos
+ i
*4, &ok
);
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
);
1262 for (i
= 0; i
<= nGlyphs
; ++i
) {
1263 locaTable
[i
].newOffset
= pos
;
1264 pos
+= locaTable
[i
].len
;
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
;
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
;
1280 locaData
[2*i
] = (Guchar
)(pos
>> 9);
1281 locaData
[2*i
+1] = (Guchar
)(pos
>> 1);
1285 // count the number of tables
1287 for (i
= 0; i
< nT42Tables
; ++i
) {
1288 if (t42Tables
[i
].required
||
1289 seekTable(t42Tables
[i
].tag
) >= 0) {
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
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;
1314 for (i
= 0; i
< nT42Tables
; ++i
) {
1316 checksum
= 0; // make gcc happy
1317 if (i
== t42HeadTable
) {
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
) {
1326 glyfPos
= tables
[seekTable("glyf")].offset
;
1327 for (j
= 0; j
< nGlyphs
; ++j
) {
1328 length
+= locaTable
[j
].len
;
1330 length
+= 4 - (length
& 3);
1332 if (checkRegion(glyfPos
+ locaTable
[j
].origOffset
, locaTable
[j
].len
)) {
1334 computeTableChecksum(file
+ glyfPos
+ locaTable
[j
].origOffset
,
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) {
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);
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
;
1376 pos
+= 4 - (length
& 3);
1382 // construct the table directory
1383 tableDir
[0] = 0x00; // sfnt version
1387 tableDir
[4] = 0; // numTables
1388 tableDir
[5] = nNewTables
;
1389 tableDir
[6] = 0; // searchRange
1390 tableDir
[7] = (Guchar
)128;
1391 tableDir
[8] = 0; // entrySelector
1393 tableDir
[10] = 0; // rangeShift
1394 tableDir
[11] = (Guchar
)(16 * nNewTables
- 128);
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
;
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
1429 (*outputFunc
)(outputStream
, "/", 1);
1430 (*outputFunc
)(outputStream
, name
->getCString(), name
->getLength());
1431 (*outputFunc
)(outputStream
, " [\n", 3);
1433 (*outputFunc
)(outputStream
, "/sfnts [\n", 9);
1436 // write the table directory
1437 dumpString(tableDir
, 12 + nNewTables
*16, outputFunc
, outputStream
);
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
);
1456 // length == 0 means the table is missing and the error was
1457 // already reported during the construction of the table
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
);
1474 // end the sfnts array
1475 (*outputFunc
)(outputStream
, "] def\n", 6);
1481 void FoFiTrueType::dumpString(Guchar
*s
, int length
,
1482 FoFiOutputFunc outputFunc
,
1483 void *outputStream
) {
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);
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
;
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) +
1524 switch (length
& 3) {
1526 word
|= (data
[i
+2] & 0xff) << 8;
1528 word
|= (data
[i
+1] & 0xff) << 16;
1530 word
|= (data
[i
] & 0xff) << 24;
1538 void FoFiTrueType::parse() {
1544 // look for a collection (TTC)
1545 topTag
= getU32BE(0, &parsedOk
);
1549 if (topTag
== ttcfTag
) {
1550 pos
= getU32BE(12, &parsedOk
);
1558 // read the table directory
1559 nTables
= getU16BE(pos
+ 4, &parsedOk
);
1563 tables
= (TrueTypeTable
*)gmallocn(nTables
, sizeof(TrueTypeTable
));
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
) {
1580 // check for tables that are required by both the TrueType spec and
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) {
1593 if ((i
= seekTable("cmap")) >= 0) {
1594 pos
= tables
[i
].offset
+ 2;
1595 nCmaps
= getU16BE(pos
, &parsedOk
);
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
);
1606 cmaps
[j
].fmt
= getU16BE(cmaps
[j
].offset
, &parsedOk
);
1607 cmaps
[j
].len
= getU16BE(cmaps
[j
].offset
+ 2, &parsedOk
);
1616 // get the number of glyphs from the maxp table
1617 i
= seekTable("maxp");
1618 nGlyphs
= getU16BE(tables
[i
].offset
+ 4, &parsedOk
);
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
);
1634 // make sure the loca table is sane (correct length and entries are
1636 i
= seekTable("loca");
1637 if (tables
[i
].len
< (nGlyphs
+ 1) * (locaFmt
? 4 : 2)) {
1641 for (j
= 0; j
<= nGlyphs
; ++j
) {
1643 pos
= (int)getU32BE(tables
[i
].offset
+ j
*4, &parsedOk
);
1645 pos
= getU16BE(tables
[i
].offset
+ j
*2, &parsedOk
);
1647 if (pos
< 0 || pos
> len
) {
1655 // read the post table
1659 void FoFiTrueType::readPostTable() {
1661 int tablePos
, postFmt
, stringIdx
, stringPos
;
1666 if ((i
= seekTable("post")) < 0) {
1669 tablePos
= tables
[i
].offset
;
1670 postFmt
= getU32BE(tablePos
, &ok
);
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
);
1689 stringPos
= tablePos
+ 34 + 2*n
;
1690 for (i
= 0; i
< n
; ++i
) {
1691 j
= getU16BE(tablePos
+ 34 + 2*i
, &ok
);
1693 nameToGID
->removeInt(macGlyphNames
[j
]);
1694 nameToGID
->add(new GString(macGlyphNames
[j
]), i
);
1697 if (j
!= stringIdx
) {
1698 for (stringIdx
= 0, stringPos
= tablePos
+ 34 + 2*n
;
1700 ++stringIdx
, stringPos
+= 1 + getU8(stringPos
, &ok
)) ;
1705 m
= getU8(stringPos
, &ok
);
1706 if (!ok
|| !checkRegion(stringPos
+ 1, m
)) {
1709 name
= new GString((char *)&file
[stringPos
+ 1], m
);
1710 nameToGID
->removeInt(name
);
1711 nameToGID
->add(name
, i
);
1716 } else if (postFmt
== 0x00028000) {
1717 nameToGID
= new GHash(gTrue
);
1718 for (i
= 0; i
< nGlyphs
; ++i
) {
1719 j
= getU8(tablePos
+ 32 + i
, &ok
);
1724 nameToGID
->removeInt(macGlyphNames
[j
]);
1725 nameToGID
->add(new GString(macGlyphNames
[j
]), i
);
1739 int FoFiTrueType::seekTable(char *tag
) {
1743 tagI
= ((tag
[0] & 0xff) << 24) |
1744 ((tag
[1] & 0xff) << 16) |
1745 ((tag
[2] & 0xff) << 8) |
1747 for (i
= 0; i
< nTables
; ++i
) {
1748 if (tables
[i
].tag
== tagI
) {