1 //========================================================================
5 // Copyright 1999-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
17 #include "goo/gtypes.h"
19 #include "goo/GooString.h"
20 #include "goo/GooHash.h"
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
, int faceIndexA
) {
247 ff
= new FoFiTrueType(fileA
, lenA
, gFalse
, faceIndexA
);
255 FoFiTrueType
*FoFiTrueType::load(char *fileName
, int faceIndexA
) {
260 if (!(fileA
= FoFiBase::readFile(fileName
, &lenA
))) {
263 ff
= new FoFiTrueType(fileA
, lenA
, gTrue
, faceIndexA
);
271 FoFiTrueType::FoFiTrueType(char *fileA
, int lenA
, GBool freeFileDataA
, int faceIndexA
):
272 FoFiBase(fileA
, lenA
, freeFileDataA
)
280 faceIndex
= faceIndexA
;
285 FoFiTrueType::~FoFiTrueType() {
293 int FoFiTrueType::getNumCmaps() {
297 int FoFiTrueType::getCmapPlatform(int i
) {
298 return cmaps
[i
].platform
;
301 int FoFiTrueType::getCmapEncoding(int i
) {
302 return cmaps
[i
].encoding
;
305 int FoFiTrueType::findCmap(int platform
, int encoding
) {
308 for (i
= 0; i
< nCmaps
; ++i
) {
309 if (cmaps
[i
].platform
== platform
&& cmaps
[i
].encoding
== encoding
) {
316 Gushort
FoFiTrueType::mapCodeToGID(int i
, int c
) {
318 int segCnt
, segEnd
, segStart
, segDelta
, segOffset
;
319 int cmapFirst
, cmapLen
;
323 if (i
< 0 || i
>= nCmaps
) {
327 pos
= cmaps
[i
].offset
;
328 switch (cmaps
[i
].fmt
) {
330 if (c
< 0 || c
>= cmaps
[i
].len
- 6) {
333 gid
= getU8(cmaps
[i
].offset
+ 6 + c
, &ok
);
336 segCnt
= getU16BE(pos
+ 6, &ok
) / 2;
339 segEnd
= getU16BE(pos
+ 14 + 2*b
, &ok
);
341 // malformed font -- the TrueType spec requires the last segEnd
345 // invariant: seg[a].end < code <= seg[b].end
346 while (b
- a
> 1 && ok
) {
348 segEnd
= getU16BE(pos
+ 14 + 2*m
, &ok
);
355 segStart
= getU16BE(pos
+ 16 + 2*segCnt
+ 2*b
, &ok
);
356 segDelta
= getU16BE(pos
+ 16 + 4*segCnt
+ 2*b
, &ok
);
357 segOffset
= getU16BE(pos
+ 16 + 6*segCnt
+ 2*b
, &ok
);
361 if (segOffset
== 0) {
362 gid
= (c
+ segDelta
) & 0xffff;
364 gid
= getU16BE(pos
+ 16 + 6*segCnt
+ 2*b
+
365 segOffset
+ 2 * (c
- segStart
), &ok
);
367 gid
= (gid
+ segDelta
) & 0xffff;
372 cmapFirst
= getU16BE(pos
+ 6, &ok
);
373 cmapLen
= getU16BE(pos
+ 8, &ok
);
374 if (c
< cmapFirst
|| c
>= cmapFirst
+ cmapLen
) {
377 gid
= getU16BE(pos
+ 10 + 2 * (c
- cmapFirst
), &ok
);
388 int FoFiTrueType::mapNameToGID(char *name
) {
392 return nameToGID
->lookupInt(name
);
395 int FoFiTrueType::getEmbeddingRights() {
399 if ((i
= seekTable("OS/2")) < 0) {
403 fsType
= getU16BE(tables
[i
].offset
+ 8, &ok
);
407 if (fsType
& 0x0008) {
410 if (fsType
& 0x0004) {
413 if (fsType
& 0x0002) {
419 void FoFiTrueType::convertToType42(char *psName
, char **encoding
,
421 FoFiOutputFunc outputFunc
,
422 void *outputStream
) {
428 sprintf(buf
, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok
) / 65536.0);
429 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
431 // begin the font dictionary
432 (*outputFunc
)(outputStream
, "10 dict begin\n", 14);
433 (*outputFunc
)(outputStream
, "/FontName /", 11);
434 (*outputFunc
)(outputStream
, psName
, strlen(psName
));
435 (*outputFunc
)(outputStream
, " def\n", 5);
436 (*outputFunc
)(outputStream
, "/FontType 42 def\n", 17);
437 (*outputFunc
)(outputStream
, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
438 sprintf(buf
, "/FontBBox [%d %d %d %d] def\n",
439 bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
440 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
441 (*outputFunc
)(outputStream
, "/PaintType 0 def\n", 17);
443 // write the guts of the dictionary
444 cvtEncoding(encoding
, outputFunc
, outputStream
);
445 cvtCharStrings(encoding
, codeToGID
, outputFunc
, outputStream
);
446 cvtSfnts(outputFunc
, outputStream
, NULL
, gFalse
);
448 // end the dictionary and define the font
449 (*outputFunc
)(outputStream
, "FontName currentdict end definefont pop\n", 40);
452 void FoFiTrueType::convertToCIDType2(char *psName
,
453 Gushort
*cidMap
, int nCIDs
,
454 GBool needVerticalMetrics
,
455 FoFiOutputFunc outputFunc
,
456 void *outputStream
) {
464 sprintf(buf
, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok
) / 65536.0);
465 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
467 // begin the font dictionary
468 (*outputFunc
)(outputStream
, "20 dict begin\n", 14);
469 (*outputFunc
)(outputStream
, "/CIDFontName /", 14);
470 (*outputFunc
)(outputStream
, psName
, strlen(psName
));
471 (*outputFunc
)(outputStream
, " def\n", 5);
472 (*outputFunc
)(outputStream
, "/CIDFontType 2 def\n", 19);
473 (*outputFunc
)(outputStream
, "/FontType 42 def\n", 17);
474 (*outputFunc
)(outputStream
, "/CIDSystemInfo 3 dict dup begin\n", 32);
475 (*outputFunc
)(outputStream
, " /Registry (Adobe) def\n", 24);
476 (*outputFunc
)(outputStream
, " /Ordering (Identity) def\n", 27);
477 (*outputFunc
)(outputStream
, " /Supplement 0 def\n", 20);
478 (*outputFunc
)(outputStream
, " end def\n", 10);
479 (*outputFunc
)(outputStream
, "/GDBytes 2 def\n", 15);
481 sprintf(buf
, "/CIDCount %d def\n", nCIDs
);
482 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
484 (*outputFunc
)(outputStream
, "/CIDMap [", 9);
485 for (i
= 0; i
< nCIDs
; i
+= 32768 - 16) {
486 (*outputFunc
)(outputStream
, "<\n", 2);
487 for (j
= 0; j
< 32768 - 16 && i
+j
< nCIDs
; j
+= 16) {
488 (*outputFunc
)(outputStream
, " ", 2);
489 for (k
= 0; k
< 16 && i
+j
+k
< nCIDs
; ++k
) {
491 sprintf(buf
, "%02x%02x", (cid
>> 8) & 0xff, cid
& 0xff);
492 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
494 (*outputFunc
)(outputStream
, "\n", 1);
496 (*outputFunc
)(outputStream
, " >", 3);
498 (*outputFunc
)(outputStream
, "\n", 1);
499 (*outputFunc
)(outputStream
, "] def\n", 6);
501 (*outputFunc
)(outputStream
, "/CIDMap <\n", 10);
502 for (i
= 0; i
< nCIDs
; i
+= 16) {
503 (*outputFunc
)(outputStream
, " ", 2);
504 for (j
= 0; j
< 16 && i
+j
< nCIDs
; ++j
) {
506 sprintf(buf
, "%02x%02x", (cid
>> 8) & 0xff, cid
& 0xff);
507 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
509 (*outputFunc
)(outputStream
, "\n", 1);
511 (*outputFunc
)(outputStream
, "> def\n", 6);
514 // direct mapping - just fill the string(s) with s[i]=i
515 sprintf(buf
, "/CIDCount %d def\n", nGlyphs
);
516 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
517 if (nGlyphs
> 32767) {
518 (*outputFunc
)(outputStream
, "/CIDMap [\n", 10);
519 for (i
= 0; i
< nGlyphs
; i
+= 32767) {
520 j
= nGlyphs
- i
< 32767 ? nGlyphs
- i
: 32767;
521 sprintf(buf
, " %d string 0 1 %d {\n", 2 * j
, j
- 1);
522 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
523 sprintf(buf
, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i
);
524 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
525 sprintf(buf
, " 1 index exch dup 2 mul 1 add exch %d add"
526 " 255 and put\n", i
);
527 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
528 (*outputFunc
)(outputStream
, " } for\n", 8);
530 (*outputFunc
)(outputStream
, "] def\n", 6);
532 sprintf(buf
, "/CIDMap %d string\n", 2 * nGlyphs
);
533 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
534 sprintf(buf
, " 0 1 %d {\n", nGlyphs
- 1);
535 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
536 (*outputFunc
)(outputStream
,
537 " 2 copy dup 2 mul exch -8 bitshift put\n", 42);
538 (*outputFunc
)(outputStream
,
539 " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
540 (*outputFunc
)(outputStream
, " } for\n", 8);
541 (*outputFunc
)(outputStream
, "def\n", 4);
544 (*outputFunc
)(outputStream
, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
545 sprintf(buf
, "/FontBBox [%d %d %d %d] def\n",
546 bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
547 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
548 (*outputFunc
)(outputStream
, "/PaintType 0 def\n", 17);
549 (*outputFunc
)(outputStream
, "/Encoding [] readonly def\n", 26);
550 (*outputFunc
)(outputStream
, "/CharStrings 1 dict dup begin\n", 30);
551 (*outputFunc
)(outputStream
, " /.notdef 0 def\n", 17);
552 (*outputFunc
)(outputStream
, " end readonly def\n", 19);
554 // write the guts of the dictionary
555 cvtSfnts(outputFunc
, outputStream
, NULL
, needVerticalMetrics
);
557 // end the dictionary and define the font
558 (*outputFunc
)(outputStream
,
559 "CIDFontName currentdict end /CIDFont defineresource pop\n",
563 void FoFiTrueType::convertToType0(char *psName
, Gushort
*cidMap
, int nCIDs
,
564 GBool needVerticalMetrics
,
565 FoFiOutputFunc outputFunc
,
566 void *outputStream
) {
568 GooString
*sfntsName
;
571 // write the Type 42 sfnts array
572 sfntsName
= (new GooString(psName
))->append("_sfnts");
573 cvtSfnts(outputFunc
, outputStream
, sfntsName
, needVerticalMetrics
);
576 // write the descendant Type 42 fonts
577 n
= cidMap
? nCIDs
: nGlyphs
;
578 for (i
= 0; i
< n
; i
+= 256) {
579 (*outputFunc
)(outputStream
, "10 dict begin\n", 14);
580 (*outputFunc
)(outputStream
, "/FontName /", 11);
581 (*outputFunc
)(outputStream
, psName
, strlen(psName
));
582 sprintf(buf
, "_%02x def\n", i
>> 8);
583 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
584 (*outputFunc
)(outputStream
, "/FontType 42 def\n", 17);
585 (*outputFunc
)(outputStream
, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
586 sprintf(buf
, "/FontBBox [%d %d %d %d] def\n",
587 bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
588 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
589 (*outputFunc
)(outputStream
, "/PaintType 0 def\n", 17);
590 (*outputFunc
)(outputStream
, "/sfnts ", 7);
591 (*outputFunc
)(outputStream
, psName
, strlen(psName
));
592 (*outputFunc
)(outputStream
, "_sfnts def\n", 11);
593 (*outputFunc
)(outputStream
, "/Encoding 256 array\n", 20);
594 for (j
= 0; j
< 256 && i
+j
< n
; ++j
) {
595 sprintf(buf
, "dup %d /c%02x put\n", j
, j
);
596 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
598 (*outputFunc
)(outputStream
, "readonly def\n", 13);
599 (*outputFunc
)(outputStream
, "/CharStrings 257 dict dup begin\n", 32);
600 (*outputFunc
)(outputStream
, "/.notdef 0 def\n", 15);
601 for (j
= 0; j
< 256 && i
+j
< n
; ++j
) {
602 sprintf(buf
, "/c%02x %d def\n", j
, cidMap
? cidMap
[i
+j
] : i
+j
);
603 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
605 (*outputFunc
)(outputStream
, "end readonly def\n", 17);
606 (*outputFunc
)(outputStream
,
607 "FontName currentdict end definefont pop\n", 40);
610 // write the Type 0 parent font
611 (*outputFunc
)(outputStream
, "16 dict begin\n", 14);
612 (*outputFunc
)(outputStream
, "/FontName /", 11);
613 (*outputFunc
)(outputStream
, psName
, strlen(psName
));
614 (*outputFunc
)(outputStream
, " def\n", 5);
615 (*outputFunc
)(outputStream
, "/FontType 0 def\n", 16);
616 (*outputFunc
)(outputStream
, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
617 (*outputFunc
)(outputStream
, "/FMapType 2 def\n", 16);
618 (*outputFunc
)(outputStream
, "/Encoding [\n", 12);
619 for (i
= 0; i
< n
; i
+= 256) {
620 sprintf(buf
, "%d\n", i
>> 8);
621 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
623 (*outputFunc
)(outputStream
, "] def\n", 6);
624 (*outputFunc
)(outputStream
, "/FDepVector [\n", 14);
625 for (i
= 0; i
< n
; i
+= 256) {
626 (*outputFunc
)(outputStream
, "/", 1);
627 (*outputFunc
)(outputStream
, psName
, strlen(psName
));
628 sprintf(buf
, "_%02x findfont\n", i
>> 8);
629 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
631 (*outputFunc
)(outputStream
, "] def\n", 6);
632 (*outputFunc
)(outputStream
, "FontName currentdict end definefont pop\n", 40);
635 void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc
,
636 void *outputStream
, char *name
,
637 Gushort
*codeToGID
) {
638 // this substitute cmap table maps char codes 0000-ffff directly to
640 static char cmapTab
[36] = {
641 0, 0, // table version number
642 0, 1, // number of encoding tables
645 0, 0, 0, 12, // offset of subtable
646 0, 4, // subtable format
647 0, 24, // subtable length
648 0, 0, // subtable version
649 0, 2, // segment count * 2
650 0, 2, // 2 * 2 ^ floor(log2(segCount))
651 0, 0, // floor(log2(segCount))
652 0, 0, // 2*segCount - 2*2^floor(log2(segCount))
653 (char)0xff, (char)0xff, // endCount[0]
655 0, 0, // startCount[0]
657 0, 0 // pad to a mulitple of four bytes
659 static char nameTab
[8] = {
661 0, 0, // number of name records
662 0, 6, // offset to start of string storage
663 0, 0 // pad to multiple of four bytes
665 static char postTab
[32] = {
666 0, 1, 0, 0, // format
667 0, 0, 0, 0, // italic angle
668 0, 0, // underline position
669 0, 0, // underline thickness
670 0, 0, 0, 0, // fixed pitch
671 0, 0, 0, 0, // min Type 42 memory
672 0, 0, 0, 0, // max Type 42 memory
673 0, 0, 0, 0, // min Type 1 memory
674 0, 0, 0, 0 // max Type 1 memory
676 GBool missingCmap
, missingName
, missingPost
, unsortedLoca
, badCmapLen
;
677 int nZeroLengthTables
;
678 TrueTypeLoca
*locaTable
;
679 TrueTypeTable
*newTables
;
680 char *newNameTab
, *newCmapTab
;
681 int nNewTables
, cmapIdx
, cmapLen
, glyfLen
, newNameLen
, newCmapLen
, next
;
682 Guint locaChecksum
, glyfChecksum
, fileChecksum
;
684 char locaBuf
[4], checksumBuf
[4];
689 // check for missing tables
690 missingCmap
= (cmapIdx
= seekTable("cmap")) < 0;
691 missingName
= seekTable("name") < 0;
692 missingPost
= seekTable("post") < 0;
694 // read the loca table, check to see if it's sorted
695 locaTable
= (TrueTypeLoca
*)gmallocn(nGlyphs
+ 1, sizeof(TrueTypeLoca
));
696 unsortedLoca
= gFalse
;
697 i
= seekTable("loca");
698 pos
= tables
[i
].offset
;
700 for (i
= 0; i
<= nGlyphs
; ++i
) {
702 locaTable
[i
].origOffset
= (int)getU32BE(pos
+ i
*4, &ok
);
704 locaTable
[i
].origOffset
= 2 * getU16BE(pos
+ i
*2, &ok
);
706 if (i
> 0 && locaTable
[i
].origOffset
< locaTable
[i
-1].origOffset
) {
707 unsortedLoca
= gTrue
;
709 locaTable
[i
].idx
= i
;
712 // check for zero-length tables
713 nZeroLengthTables
= 0;
714 for (i
= 0; i
< nTables
; ++i
) {
715 if (tables
[i
].len
== 0) {
720 // check for an incorrect cmap table length
722 cmapLen
= 0; // make gcc happy
724 cmapLen
= cmaps
[0].offset
+ cmaps
[0].len
;
725 for (i
= 1; i
< nCmaps
; ++i
) {
726 if (cmaps
[i
].offset
+ cmaps
[i
].len
> cmapLen
) {
727 cmapLen
= cmaps
[i
].offset
+ cmaps
[i
].len
;
730 cmapLen
-= tables
[cmapIdx
].offset
;
731 if (cmapLen
> tables
[cmapIdx
].len
) {
736 // if nothing is broken, just write the TTF file as is
737 if (!missingCmap
&& !missingName
&& !missingPost
&& !unsortedLoca
&&
738 !badCmapLen
&& nZeroLengthTables
== 0 && !name
&& !codeToGID
) {
739 (*outputFunc
)(outputStream
, (char *)file
, len
);
743 // sort the 'loca' table: some (non-compliant) fonts have
744 // out-of-order loca tables; in order to correctly handle the case
745 // where (compliant) fonts have empty entries in the middle of the
746 // table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
747 // and idx as its secondary key (ensuring that adjacent entries with
748 // the same pos value remain in the same order)
749 glyfLen
= 0; // make gcc happy
751 qsort(locaTable
, nGlyphs
+ 1, sizeof(TrueTypeLoca
),
752 &cmpTrueTypeLocaOffset
);
753 for (i
= 0; i
< nGlyphs
; ++i
) {
754 locaTable
[i
].len
= locaTable
[i
+1].origOffset
- locaTable
[i
].origOffset
;
756 locaTable
[nGlyphs
].len
= 0;
757 qsort(locaTable
, nGlyphs
+ 1, sizeof(TrueTypeLoca
),
758 &cmpTrueTypeLocaIdx
);
760 for (i
= 0; i
<= nGlyphs
; ++i
) {
761 locaTable
[i
].newOffset
= pos
;
762 pos
+= locaTable
[i
].len
;
764 pos
+= 4 - (pos
& 3);
770 // compute checksums for the loca and glyf tables
771 locaChecksum
= glyfChecksum
= 0;
774 for (j
= 0; j
<= nGlyphs
; ++j
) {
775 locaChecksum
+= locaTable
[j
].newOffset
;
778 for (j
= 0; j
<= nGlyphs
; j
+= 2) {
779 locaChecksum
+= locaTable
[j
].newOffset
<< 16;
780 if (j
+ 1 <= nGlyphs
) {
781 locaChecksum
+= locaTable
[j
+1].newOffset
;
785 pos
= tables
[seekTable("glyf")].offset
;
786 for (j
= 0; j
< nGlyphs
; ++j
) {
787 n
= locaTable
[j
].len
;
789 k
= locaTable
[j
].origOffset
;
790 if (checkRegion(pos
+ k
, n
)) {
791 glyfChecksum
+= computeTableChecksum(file
+ pos
+ k
, n
);
797 // construct the new name table
800 newNameLen
= (6 + 4*12 + 2 * (3*n
+ 7) + 3) & ~3;
801 newNameTab
= (char *)gmalloc(newNameLen
);
802 memset(newNameTab
, 0, newNameLen
);
803 newNameTab
[0] = 0; // format selector
805 newNameTab
[2] = 0; // number of name records
807 newNameTab
[4] = 0; // offset to start of string storage
808 newNameTab
[5] = 6 + 4*12;
810 for (i
= 0; i
< 4; ++i
) {
811 newNameTab
[6 + i
*12 + 0] = 0; // platform ID = Microsoft
812 newNameTab
[6 + i
*12 + 1] = 3;
813 newNameTab
[6 + i
*12 + 2] = 0; // encoding ID = Unicode
814 newNameTab
[6 + i
*12 + 3] = 1;
815 newNameTab
[6 + i
*12 + 4] = 0x04; // language ID = American English
816 newNameTab
[6 + i
*12 + 5] = 0x09;
817 newNameTab
[6 + i
*12 + 6] = 0; // name ID
818 newNameTab
[6 + i
*12 + 7] = i
+ 1;
819 newNameTab
[6 + i
*12 + 8] = i
+1 == 2 ? 0 : ((2*n
) >> 8); // string length
820 newNameTab
[6 + i
*12 + 9] = i
+1 == 2 ? 14 : ((2*n
) & 0xff);
821 newNameTab
[6 + i
*12 + 10] = next
>> 8; // string offset
822 newNameTab
[6 + i
*12 + 11] = next
& 0xff;
824 memcpy(newNameTab
+ 6 + 4*12 + next
, "\0R\0e\0g\0u\0l\0a\0r", 14);
827 for (j
= 0; j
< n
; ++j
) {
828 newNameTab
[6 + 4*12 + next
+ 2*j
] = 0;
829 newNameTab
[6 + 4*12 + next
+ 2*j
+ 1] = name
[j
];
839 // construct the new cmap table
841 newCmapLen
= 44 + 256 * 2;
842 newCmapTab
= (char *)gmalloc(newCmapLen
);
843 newCmapTab
[0] = 0; // table version number = 0
845 newCmapTab
[2] = 0; // number of encoding tables = 1
847 newCmapTab
[4] = 0; // platform ID = Microsoft
849 newCmapTab
[6] = 0; // encoding ID = Unicode
851 newCmapTab
[8] = 0; // offset of subtable
855 newCmapTab
[12] = 0; // subtable format = 4
857 newCmapTab
[14] = 0x02; // subtable length
858 newCmapTab
[15] = 0x20;
859 newCmapTab
[16] = 0; // subtable version = 0
861 newCmapTab
[18] = 0; // segment count * 2
863 newCmapTab
[20] = 0; // 2 * 2 ^ floor(log2(segCount))
865 newCmapTab
[22] = 0; // floor(log2(segCount))
867 newCmapTab
[24] = 0; // 2*segCount - 2*2^floor(log2(segCount))
869 newCmapTab
[26] = 0x00; // endCount[0]
870 newCmapTab
[27] = (char)0xff;
871 newCmapTab
[28] = (char)0xff; // endCount[1]
872 newCmapTab
[29] = (char)0xff;
873 newCmapTab
[30] = 0; // reserved
875 newCmapTab
[32] = 0x00; // startCount[0]
876 newCmapTab
[33] = 0x00;
877 newCmapTab
[34] = (char)0xff; // startCount[1]
878 newCmapTab
[35] = (char)0xff;
879 newCmapTab
[36] = 0; // idDelta[0]
881 newCmapTab
[38] = 0; // idDelta[1]
883 newCmapTab
[40] = 0; // idRangeOffset[0]
885 newCmapTab
[42] = 0; // idRangeOffset[1]
887 for (i
= 0; i
< 256; ++i
) {
888 newCmapTab
[44 + 2*i
] = codeToGID
[i
] >> 8;
889 newCmapTab
[44 + 2*i
+ 1] = codeToGID
[i
] & 0xff;
896 // construct the new table directory:
897 // - keep all original tables with non-zero length
898 // - fix the cmap table's length, if necessary
899 // - add missing tables
900 // - sort the table by tag
901 // - compute new table positions, including 4-byte alignment
902 // - (re)compute table checksums
903 nNewTables
= nTables
- nZeroLengthTables
+
904 (missingCmap
? 1 : 0) + (missingName
? 1 : 0) +
905 (missingPost
? 1 : 0);
906 newTables
= (TrueTypeTable
*)gmallocn(nNewTables
, sizeof(TrueTypeTable
));
908 for (i
= 0; i
< nTables
; ++i
) {
909 if (tables
[i
].len
> 0) {
910 newTables
[j
] = tables
[i
];
911 newTables
[j
].origOffset
= tables
[i
].offset
;
912 if (checkRegion(tables
[i
].offset
, newTables
[i
].len
)) {
913 newTables
[j
].checksum
=
914 computeTableChecksum(file
+ tables
[i
].offset
, tables
[i
].len
);
915 if (tables
[i
].tag
== headTag
) {
916 // don't include the file checksum
917 newTables
[j
].checksum
-= getU32BE(tables
[i
].offset
+ 8, &ok
);
920 if (newTables
[j
].tag
== cmapTag
&& codeToGID
) {
921 newTables
[j
].len
= newCmapLen
;
922 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)newCmapTab
,
924 } else if (newTables
[j
].tag
== cmapTag
&& badCmapLen
) {
925 newTables
[j
].len
= cmapLen
;
926 } else if (newTables
[j
].tag
== locaTag
&& unsortedLoca
) {
927 newTables
[j
].len
= (nGlyphs
+ 1) * (locaFmt
? 4 : 2);
928 newTables
[j
].checksum
= locaChecksum
;
929 } else if (newTables
[j
].tag
== glyfTag
&& unsortedLoca
) {
930 newTables
[j
].len
= glyfLen
;
931 newTables
[j
].checksum
= glyfChecksum
;
932 } else if (newTables
[j
].tag
== nameTag
&& name
) {
933 newTables
[j
].len
= newNameLen
;
934 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)newNameTab
,
941 newTables
[j
].tag
= cmapTag
;
943 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)newCmapTab
,
945 newTables
[j
].len
= newCmapLen
;
947 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)cmapTab
,
949 newTables
[j
].len
= sizeof(cmapTab
);
954 newTables
[j
].tag
= nameTag
;
956 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)newNameTab
,
958 newTables
[j
].len
= newNameLen
;
960 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)nameTab
,
962 newTables
[j
].len
= sizeof(nameTab
);
967 newTables
[j
].tag
= postTag
;
968 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)postTab
,
970 newTables
[j
].len
= sizeof(postTab
);
973 qsort(newTables
, nNewTables
, sizeof(TrueTypeTable
),
974 &cmpTrueTypeTableTag
);
975 pos
= 12 + nNewTables
* 16;
976 for (i
= 0; i
< nNewTables
; ++i
) {
977 newTables
[i
].offset
= pos
;
978 pos
+= newTables
[i
].len
;
980 pos
+= 4 - (pos
& 3);
984 // write the table directory
985 tableDir
= (char *)gmalloc(12 + nNewTables
* 16);
986 tableDir
[0] = 0x00; // sfnt version
990 tableDir
[4] = (char)((nNewTables
>> 8) & 0xff); // numTables
991 tableDir
[5] = (char)(nNewTables
& 0xff);
992 for (i
= -1, t
= (Guint
)nNewTables
; t
; ++i
, t
>>= 1) ;
994 tableDir
[6] = (char)((t
>> 8) & 0xff); // searchRange
995 tableDir
[7] = (char)(t
& 0xff);
996 tableDir
[8] = (char)((i
>> 8) & 0xff); // entrySelector
997 tableDir
[9] = (char)(i
& 0xff);
998 t
= nNewTables
* 16 - t
;
999 tableDir
[10] = (char)((t
>> 8) & 0xff); // rangeShift
1000 tableDir
[11] = (char)(t
& 0xff);
1002 for (i
= 0; i
< nNewTables
; ++i
) {
1003 tableDir
[pos
] = (char)(newTables
[i
].tag
>> 24);
1004 tableDir
[pos
+ 1] = (char)(newTables
[i
].tag
>> 16);
1005 tableDir
[pos
+ 2] = (char)(newTables
[i
].tag
>> 8);
1006 tableDir
[pos
+ 3] = (char) newTables
[i
].tag
;
1007 tableDir
[pos
+ 4] = (char)(newTables
[i
].checksum
>> 24);
1008 tableDir
[pos
+ 5] = (char)(newTables
[i
].checksum
>> 16);
1009 tableDir
[pos
+ 6] = (char)(newTables
[i
].checksum
>> 8);
1010 tableDir
[pos
+ 7] = (char) newTables
[i
].checksum
;
1011 tableDir
[pos
+ 8] = (char)(newTables
[i
].offset
>> 24);
1012 tableDir
[pos
+ 9] = (char)(newTables
[i
].offset
>> 16);
1013 tableDir
[pos
+10] = (char)(newTables
[i
].offset
>> 8);
1014 tableDir
[pos
+11] = (char) newTables
[i
].offset
;
1015 tableDir
[pos
+12] = (char)(newTables
[i
].len
>> 24);
1016 tableDir
[pos
+13] = (char)(newTables
[i
].len
>> 16);
1017 tableDir
[pos
+14] = (char)(newTables
[i
].len
>> 8);
1018 tableDir
[pos
+15] = (char) newTables
[i
].len
;
1021 (*outputFunc
)(outputStream
, tableDir
, 12 + nNewTables
* 16);
1023 // compute the file checksum
1024 fileChecksum
= computeTableChecksum((Guchar
*)tableDir
,
1025 12 + nNewTables
* 16);
1026 for (i
= 0; i
< nNewTables
; ++i
) {
1027 fileChecksum
+= newTables
[i
].checksum
;
1029 fileChecksum
= 0xb1b0afba - fileChecksum
;
1032 for (i
= 0; i
< nNewTables
; ++i
) {
1033 if (newTables
[i
].tag
== headTag
) {
1034 if (checkRegion(newTables
[i
].origOffset
, newTables
[i
].len
)) {
1035 (*outputFunc
)(outputStream
, (char *)file
+ newTables
[i
].origOffset
, 8);
1036 checksumBuf
[0] = fileChecksum
>> 24;
1037 checksumBuf
[1] = fileChecksum
>> 16;
1038 checksumBuf
[2] = fileChecksum
>> 8;
1039 checksumBuf
[3] = fileChecksum
;
1040 (*outputFunc
)(outputStream
, checksumBuf
, 4);
1041 (*outputFunc
)(outputStream
,
1042 (char *)file
+ newTables
[i
].origOffset
+ 12,
1043 newTables
[i
].len
- 12);
1045 for (j
= 0; j
< newTables
[i
].len
; ++j
) {
1046 (*outputFunc
)(outputStream
, "\0", 1);
1049 } else if (newTables
[i
].tag
== cmapTag
&& codeToGID
) {
1050 (*outputFunc
)(outputStream
, newCmapTab
, newTables
[i
].len
);
1051 } else if (newTables
[i
].tag
== cmapTag
&& missingCmap
) {
1052 (*outputFunc
)(outputStream
, cmapTab
, newTables
[i
].len
);
1053 } else if (newTables
[i
].tag
== nameTag
&& name
) {
1054 (*outputFunc
)(outputStream
, newNameTab
, newTables
[i
].len
);
1055 } else if (newTables
[i
].tag
== nameTag
&& missingName
) {
1056 (*outputFunc
)(outputStream
, nameTab
, newTables
[i
].len
);
1057 } else if (newTables
[i
].tag
== postTag
&& missingPost
) {
1058 (*outputFunc
)(outputStream
, postTab
, newTables
[i
].len
);
1059 } else if (newTables
[i
].tag
== locaTag
&& unsortedLoca
) {
1060 for (j
= 0; j
<= nGlyphs
; ++j
) {
1062 locaBuf
[0] = (char)(locaTable
[j
].newOffset
>> 24);
1063 locaBuf
[1] = (char)(locaTable
[j
].newOffset
>> 16);
1064 locaBuf
[2] = (char)(locaTable
[j
].newOffset
>> 8);
1065 locaBuf
[3] = (char) locaTable
[j
].newOffset
;
1066 (*outputFunc
)(outputStream
, locaBuf
, 4);
1068 locaBuf
[0] = (char)(locaTable
[j
].newOffset
>> 9);
1069 locaBuf
[1] = (char)(locaTable
[j
].newOffset
>> 1);
1070 (*outputFunc
)(outputStream
, locaBuf
, 2);
1073 } else if (newTables
[i
].tag
== glyfTag
&& unsortedLoca
) {
1074 pos
= tables
[seekTable("glyf")].offset
;
1075 for (j
= 0; j
< nGlyphs
; ++j
) {
1076 n
= locaTable
[j
].len
;
1078 k
= locaTable
[j
].origOffset
;
1079 if (checkRegion(pos
+ k
, n
)) {
1080 (*outputFunc
)(outputStream
, (char *)file
+ pos
+ k
, n
);
1082 for (k
= 0; k
< n
; ++k
) {
1083 (*outputFunc
)(outputStream
, "\0", 1);
1086 if ((k
= locaTable
[j
].len
& 3)) {
1087 (*outputFunc
)(outputStream
, "\0\0\0\0", 4 - k
);
1092 if (checkRegion(newTables
[i
].origOffset
, newTables
[i
].len
)) {
1093 (*outputFunc
)(outputStream
, (char *)file
+ newTables
[i
].origOffset
,
1096 for (j
= 0; j
< newTables
[i
].len
; ++j
) {
1097 (*outputFunc
)(outputStream
, "\0", 1);
1101 if (newTables
[i
].len
& 3) {
1102 (*outputFunc
)(outputStream
, "\0\0\0", 4 - (newTables
[i
].len
& 3));
1114 void FoFiTrueType::cvtEncoding(char **encoding
,
1115 FoFiOutputFunc outputFunc
,
1116 void *outputStream
) {
1121 (*outputFunc
)(outputStream
, "/Encoding 256 array\n", 20);
1123 for (i
= 0; i
< 256; ++i
) {
1124 if (!(name
= encoding
[i
])) {
1127 sprintf(buf
, "dup %d /", i
);
1128 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
1129 (*outputFunc
)(outputStream
, name
, strlen(name
));
1130 (*outputFunc
)(outputStream
, " put\n", 5);
1133 for (i
= 0; i
< 256; ++i
) {
1134 sprintf(buf
, "dup %d /c%02x put\n", i
, i
);
1135 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
1138 (*outputFunc
)(outputStream
, "readonly def\n", 13);
1141 void FoFiTrueType::cvtCharStrings(char **encoding
,
1143 FoFiOutputFunc outputFunc
,
1144 void *outputStream
) {
1146 char buf
[64], buf2
[16];
1149 // always define '.notdef'
1150 (*outputFunc
)(outputStream
, "/CharStrings 256 dict dup begin\n", 32);
1151 (*outputFunc
)(outputStream
, "/.notdef 0 def\n", 15);
1153 // if there's no 'cmap' table, punt
1158 // map char name to glyph index:
1159 // 1. use encoding to map name to char code
1160 // 2. use codeToGID to map char code to glyph index
1161 // N.B. We do this in reverse order because font subsets can have
1162 // weird encodings that use the same character name twice, and
1163 // the first definition is probably the one we want.
1164 k
= 0; // make gcc happy
1165 for (i
= 255; i
>= 0; --i
) {
1169 sprintf(buf2
, "c%02x", i
);
1172 if (name
&& strcmp(name
, ".notdef")) {
1174 // note: Distiller (maybe Adobe's PS interpreter in general)
1175 // doesn't like TrueType fonts that have CharStrings entries
1176 // which point to nonexistent glyphs, hence the (k < nGlyphs)
1178 if (k
> 0 && k
< nGlyphs
) {
1179 (*outputFunc
)(outputStream
, "/", 1);
1180 (*outputFunc
)(outputStream
, name
, strlen(name
));
1181 sprintf(buf
, " %d def\n", k
);
1182 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
1188 (*outputFunc
)(outputStream
, "end readonly def\n", 17);
1191 void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc
,
1192 void *outputStream
, GooString
*name
,
1193 GBool needVerticalMetrics
) {
1194 Guchar headData
[54];
1195 TrueTypeLoca
*locaTable
;
1197 TrueTypeTable newTables
[nT42Tables
];
1198 Guchar tableDir
[12 + nT42Tables
*16];
1202 int length
, pos
, glyfPos
, i
, j
, k
;
1203 Guchar vheaTab
[36] = {
1204 0, 1, 0, 0, // table version number
1208 0, 0, // max advance height
1209 0, 0, // min top side bearing
1210 0, 0, // min bottom side bearing
1211 0, 0, // y max extent
1212 0, 0, // caret slope rise
1213 0, 1, // caret slope run
1214 0, 0, // caret offset
1219 0, 0, // metric data format
1220 0, 1 // number of advance heights in vmtx table
1223 GBool needVhea
, needVmtx
;
1226 // construct the 'head' table, zero out the font checksum
1227 i
= seekTable("head");
1228 pos
= tables
[i
].offset
;
1229 if (!checkRegion(pos
, 54)) {
1232 memcpy(headData
, file
+ pos
, 54);
1233 headData
[8] = headData
[9] = headData
[10] = headData
[11] = (Guchar
)0;
1235 // read the original 'loca' table, pad entries out to 4 bytes, and
1236 // sort it into proper order -- some (non-compliant) fonts have
1237 // out-of-order loca tables; in order to correctly handle the case
1238 // where (compliant) fonts have empty entries in the middle of the
1239 // table, cmpTrueTypeLocaPos uses offset as its primary sort key,
1240 // and idx as its secondary key (ensuring that adjacent entries with
1241 // the same pos value remain in the same order)
1242 locaTable
= (TrueTypeLoca
*)gmallocn(nGlyphs
+ 1, sizeof(TrueTypeLoca
));
1243 i
= seekTable("loca");
1244 pos
= tables
[i
].offset
;
1246 for (i
= 0; i
<= nGlyphs
; ++i
) {
1247 locaTable
[i
].idx
= i
;
1249 locaTable
[i
].origOffset
= (int)getU32BE(pos
+ i
*4, &ok
);
1251 locaTable
[i
].origOffset
= 2 * getU16BE(pos
+ i
*2, &ok
);
1254 qsort(locaTable
, nGlyphs
+ 1, sizeof(TrueTypeLoca
),
1255 &cmpTrueTypeLocaOffset
);
1256 for (i
= 0; i
< nGlyphs
; ++i
) {
1257 locaTable
[i
].len
= locaTable
[i
+1].origOffset
- locaTable
[i
].origOffset
;
1259 locaTable
[nGlyphs
].len
= 0;
1260 qsort(locaTable
, nGlyphs
+ 1, sizeof(TrueTypeLoca
),
1261 &cmpTrueTypeLocaIdx
);
1263 for (i
= 0; i
<= nGlyphs
; ++i
) {
1264 locaTable
[i
].newOffset
= pos
;
1265 pos
+= locaTable
[i
].len
;
1267 pos
+= 4 - (pos
& 3);
1271 // construct the new 'loca' table
1272 locaData
= (Guchar
*)gmallocn(nGlyphs
+ 1, (locaFmt
? 4 : 2));
1273 for (i
= 0; i
<= nGlyphs
; ++i
) {
1274 pos
= locaTable
[i
].newOffset
;
1276 locaData
[4*i
] = (Guchar
)(pos
>> 24);
1277 locaData
[4*i
+1] = (Guchar
)(pos
>> 16);
1278 locaData
[4*i
+2] = (Guchar
)(pos
>> 8);
1279 locaData
[4*i
+3] = (Guchar
) pos
;
1281 locaData
[2*i
] = (Guchar
)(pos
>> 9);
1282 locaData
[2*i
+1] = (Guchar
)(pos
>> 1);
1286 // count the number of tables
1288 for (i
= 0; i
< nT42Tables
; ++i
) {
1289 if (t42Tables
[i
].required
||
1290 seekTable(t42Tables
[i
].tag
) >= 0) {
1294 vmtxTab
= NULL
; // make gcc happy
1295 advance
= 0; // make gcc happy
1296 if (needVerticalMetrics
) {
1297 needVhea
= seekTable("vhea") < 0;
1298 needVmtx
= seekTable("vmtx") < 0;
1299 if (needVhea
|| needVmtx
) {
1300 i
= seekTable("head");
1301 advance
= getU16BE(tables
[i
].offset
+ 18, &ok
); // units per em
1311 // construct the new table headers, including table checksums
1312 // (pad each table out to a multiple of 4 bytes)
1313 pos
= 12 + nNewTables
*16;
1315 for (i
= 0; i
< nT42Tables
; ++i
) {
1317 checksum
= 0; // make gcc happy
1318 if (i
== t42HeadTable
) {
1320 checksum
= computeTableChecksum(headData
, 54);
1321 } else if (i
== t42LocaTable
) {
1322 length
= (nGlyphs
+ 1) * (locaFmt
? 4 : 2);
1323 checksum
= computeTableChecksum(locaData
, length
);
1324 } else if (i
== t42GlyfTable
) {
1327 glyfPos
= tables
[seekTable("glyf")].offset
;
1328 for (j
= 0; j
< nGlyphs
; ++j
) {
1329 length
+= locaTable
[j
].len
;
1331 length
+= 4 - (length
& 3);
1333 if (checkRegion(glyfPos
+ locaTable
[j
].origOffset
, locaTable
[j
].len
)) {
1335 computeTableChecksum(file
+ glyfPos
+ locaTable
[j
].origOffset
,
1340 if ((j
= seekTable(t42Tables
[i
].tag
)) >= 0) {
1341 length
= tables
[j
].len
;
1342 if (checkRegion(tables
[j
].offset
, length
)) {
1343 checksum
= computeTableChecksum(file
+ tables
[j
].offset
, length
);
1345 } else if (needVerticalMetrics
&& i
== t42VheaTable
) {
1346 vheaTab
[10] = advance
/ 256; // max advance height
1347 vheaTab
[11] = advance
% 256;
1348 length
= sizeof(vheaTab
);
1349 checksum
= computeTableChecksum(vheaTab
, length
);
1350 } else if (needVerticalMetrics
&& i
== t42VmtxTable
) {
1351 length
= 4 + (nGlyphs
- 1) * 4;
1352 vmtxTab
= (Guchar
*)gmalloc(length
);
1353 vmtxTab
[0] = advance
/ 256;
1354 vmtxTab
[1] = advance
% 256;
1355 for (j
= 2; j
< length
; j
+= 2) {
1359 checksum
= computeTableChecksum(vmtxTab
, length
);
1360 } else if (t42Tables
[i
].required
) {
1361 //~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
1362 //~ t42Tables[i].tag);
1368 newTables
[k
].tag
= ((t42Tables
[i
].tag
[0] & 0xff) << 24) |
1369 ((t42Tables
[i
].tag
[1] & 0xff) << 16) |
1370 ((t42Tables
[i
].tag
[2] & 0xff) << 8) |
1371 (t42Tables
[i
].tag
[3] & 0xff);
1372 newTables
[k
].checksum
= checksum
;
1373 newTables
[k
].offset
= pos
;
1374 newTables
[k
].len
= length
;
1377 pos
+= 4 - (length
& 3);
1383 // construct the table directory
1384 tableDir
[0] = 0x00; // sfnt version
1388 tableDir
[4] = 0; // numTables
1389 tableDir
[5] = nNewTables
;
1390 tableDir
[6] = 0; // searchRange
1391 tableDir
[7] = (Guchar
)128;
1392 tableDir
[8] = 0; // entrySelector
1394 tableDir
[10] = 0; // rangeShift
1395 tableDir
[11] = (Guchar
)(16 * nNewTables
- 128);
1397 for (i
= 0; i
< nNewTables
; ++i
) {
1398 tableDir
[pos
] = (Guchar
)(newTables
[i
].tag
>> 24);
1399 tableDir
[pos
+ 1] = (Guchar
)(newTables
[i
].tag
>> 16);
1400 tableDir
[pos
+ 2] = (Guchar
)(newTables
[i
].tag
>> 8);
1401 tableDir
[pos
+ 3] = (Guchar
) newTables
[i
].tag
;
1402 tableDir
[pos
+ 4] = (Guchar
)(newTables
[i
].checksum
>> 24);
1403 tableDir
[pos
+ 5] = (Guchar
)(newTables
[i
].checksum
>> 16);
1404 tableDir
[pos
+ 6] = (Guchar
)(newTables
[i
].checksum
>> 8);
1405 tableDir
[pos
+ 7] = (Guchar
) newTables
[i
].checksum
;
1406 tableDir
[pos
+ 8] = (Guchar
)(newTables
[i
].offset
>> 24);
1407 tableDir
[pos
+ 9] = (Guchar
)(newTables
[i
].offset
>> 16);
1408 tableDir
[pos
+10] = (Guchar
)(newTables
[i
].offset
>> 8);
1409 tableDir
[pos
+11] = (Guchar
) newTables
[i
].offset
;
1410 tableDir
[pos
+12] = (Guchar
)(newTables
[i
].len
>> 24);
1411 tableDir
[pos
+13] = (Guchar
)(newTables
[i
].len
>> 16);
1412 tableDir
[pos
+14] = (Guchar
)(newTables
[i
].len
>> 8);
1413 tableDir
[pos
+15] = (Guchar
) newTables
[i
].len
;
1417 // compute the font checksum and store it in the head table
1418 checksum
= computeTableChecksum(tableDir
, 12 + nNewTables
*16);
1419 for (i
= 0; i
< nNewTables
; ++i
) {
1420 checksum
+= newTables
[i
].checksum
;
1422 checksum
= 0xb1b0afba - checksum
; // because the TrueType spec says so
1423 headData
[ 8] = (Guchar
)(checksum
>> 24);
1424 headData
[ 9] = (Guchar
)(checksum
>> 16);
1425 headData
[10] = (Guchar
)(checksum
>> 8);
1426 headData
[11] = (Guchar
) checksum
;
1428 // start the sfnts array
1430 (*outputFunc
)(outputStream
, "/", 1);
1431 (*outputFunc
)(outputStream
, name
->getCString(), name
->getLength());
1432 (*outputFunc
)(outputStream
, " [\n", 3);
1434 (*outputFunc
)(outputStream
, "/sfnts [\n", 9);
1437 // write the table directory
1438 dumpString(tableDir
, 12 + nNewTables
*16, outputFunc
, outputStream
);
1441 for (i
= 0; i
< nNewTables
; ++i
) {
1442 if (i
== t42HeadTable
) {
1443 dumpString(headData
, 54, outputFunc
, outputStream
);
1444 } else if (i
== t42LocaTable
) {
1445 length
= (nGlyphs
+ 1) * (locaFmt
? 4 : 2);
1446 dumpString(locaData
, length
, outputFunc
, outputStream
);
1447 } else if (i
== t42GlyfTable
) {
1448 glyfPos
= tables
[seekTable("glyf")].offset
;
1449 for (j
= 0; j
< nGlyphs
; ++j
) {
1450 if (locaTable
[j
].len
> 0 &&
1451 checkRegion(glyfPos
+ locaTable
[j
].origOffset
, locaTable
[j
].len
)) {
1452 dumpString(file
+ glyfPos
+ locaTable
[j
].origOffset
,
1453 locaTable
[j
].len
, outputFunc
, outputStream
);
1457 // length == 0 means the table is missing and the error was
1458 // already reported during the construction of the table
1460 if ((length
= newTables
[i
].len
) > 0) {
1461 if ((j
= seekTable(t42Tables
[i
].tag
)) >= 0 &&
1462 checkRegion(tables
[j
].offset
, tables
[j
].len
)) {
1463 dumpString(file
+ tables
[j
].offset
, tables
[j
].len
,
1464 outputFunc
, outputStream
);
1465 } else if (needVerticalMetrics
&& i
== t42VheaTable
) {
1466 dumpString(vheaTab
, length
, outputFunc
, outputStream
);
1467 } else if (needVerticalMetrics
&& i
== t42VmtxTable
) {
1468 dumpString(vmtxTab
, length
, outputFunc
, outputStream
);
1475 // end the sfnts array
1476 (*outputFunc
)(outputStream
, "] def\n", 6);
1482 void FoFiTrueType::dumpString(Guchar
*s
, int length
,
1483 FoFiOutputFunc outputFunc
,
1484 void *outputStream
) {
1488 (*outputFunc
)(outputStream
, "<", 1);
1489 for (i
= 0; i
< length
; i
+= 32) {
1490 for (j
= 0; j
< 32 && i
+j
< length
; ++j
) {
1491 sprintf(buf
, "%02X", s
[i
+j
] & 0xff);
1492 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
1494 if (i
% (65536 - 32) == 65536 - 64) {
1495 (*outputFunc
)(outputStream
, ">\n<", 3);
1496 } else if (i
+32 < length
) {
1497 (*outputFunc
)(outputStream
, "\n", 1);
1501 pad
= 4 - (length
& 3);
1502 for (i
= 0; i
< pad
; ++i
) {
1503 (*outputFunc
)(outputStream
, "00", 2);
1506 // add an extra zero byte because the Adobe Type 42 spec says so
1507 (*outputFunc
)(outputStream
, "00>\n", 4);
1510 Guint
FoFiTrueType::computeTableChecksum(Guchar
*data
, int length
) {
1511 Guint checksum
, word
;
1515 for (i
= 0; i
+3 < length
; i
+= 4) {
1516 word
= ((data
[i
] & 0xff) << 24) +
1517 ((data
[i
+1] & 0xff) << 16) +
1518 ((data
[i
+2] & 0xff) << 8) +
1525 switch (length
& 3) {
1527 word
|= (data
[i
+2] & 0xff) << 8;
1529 word
|= (data
[i
+1] & 0xff) << 16;
1531 word
|= (data
[i
] & 0xff) << 24;
1539 #define toTag(a,b,c,d) (((unsigned int)(a)<<24) | ((unsigned int)(b)<<16) | ((unsigned int)(c)<<8) | (d))
1541 void FoFiTrueType::parse() {
1548 // look for a collection (TTC)
1549 topTag
= getU32BE(0, &parsedOk
);
1553 if (topTag
== ttcfTag
) {
1554 pos
= getU32BE(12, &parsedOk
);
1562 // read the table directory
1563 head
= getU32BE(pos
, &parsedOk
);
1566 if (head
== toTag('t','t','c','f')) {
1570 dircount
= getU32BE(8, &parsedOk
);
1578 if (faceIndex
>= dircount
)
1580 pos
= getU32BE(12 + faceIndex
* 4, &parsedOk
);
1586 nTables
= getU16BE(pos
, &parsedOk
);
1592 tables
= (TrueTypeTable
*)gmallocn(nTables
, sizeof(TrueTypeTable
));
1593 for (i
= 0; i
< nTables
; ++i
) {
1594 tables
[i
].tag
= getU32BE(pos
, &parsedOk
);
1595 tables
[i
].checksum
= getU32BE(pos
+ 4, &parsedOk
);
1596 tables
[i
].offset
= (int)getU32BE(pos
+ 8, &parsedOk
);
1597 tables
[i
].len
= (int)getU32BE(pos
+ 12, &parsedOk
);
1598 if (tables
[i
].offset
+ tables
[i
].len
< tables
[i
].offset
||
1599 tables
[i
].offset
+ tables
[i
].len
> len
) {
1608 // check for tables that are required by both the TrueType spec and
1610 if (seekTable("head") < 0 ||
1611 seekTable("hhea") < 0 ||
1612 seekTable("loca") < 0 ||
1613 seekTable("maxp") < 0 ||
1614 seekTable("glyf") < 0 ||
1615 seekTable("hmtx") < 0) {
1621 if ((i
= seekTable("cmap")) >= 0) {
1622 pos
= tables
[i
].offset
+ 2;
1623 nCmaps
= getU16BE(pos
, &parsedOk
);
1628 cmaps
= (TrueTypeCmap
*)gmallocn(nCmaps
, sizeof(TrueTypeCmap
));
1629 for (j
= 0; j
< nCmaps
; ++j
) {
1630 cmaps
[j
].platform
= getU16BE(pos
, &parsedOk
);
1631 cmaps
[j
].encoding
= getU16BE(pos
+ 2, &parsedOk
);
1632 cmaps
[j
].offset
= tables
[i
].offset
+ getU32BE(pos
+ 4, &parsedOk
);
1634 cmaps
[j
].fmt
= getU16BE(cmaps
[j
].offset
, &parsedOk
);
1635 cmaps
[j
].len
= getU16BE(cmaps
[j
].offset
+ 2, &parsedOk
);
1644 // get the number of glyphs from the maxp table
1645 i
= seekTable("maxp");
1646 nGlyphs
= getU16BE(tables
[i
].offset
+ 4, &parsedOk
);
1651 // get the bbox and loca table format from the head table
1652 i
= seekTable("head");
1653 bbox
[0] = getS16BE(tables
[i
].offset
+ 36, &parsedOk
);
1654 bbox
[1] = getS16BE(tables
[i
].offset
+ 38, &parsedOk
);
1655 bbox
[2] = getS16BE(tables
[i
].offset
+ 40, &parsedOk
);
1656 bbox
[3] = getS16BE(tables
[i
].offset
+ 42, &parsedOk
);
1657 locaFmt
= getS16BE(tables
[i
].offset
+ 50, &parsedOk
);
1662 // make sure the loca table is sane (correct length and entries are
1664 i
= seekTable("loca");
1665 if (tables
[i
].len
< (nGlyphs
+ 1) * (locaFmt
? 4 : 2)) {
1669 for (j
= 0; j
<= nGlyphs
; ++j
) {
1671 pos
= (int)getU32BE(tables
[i
].offset
+ j
*4, &parsedOk
);
1673 pos
= getU16BE(tables
[i
].offset
+ j
*2, &parsedOk
);
1675 if (pos
< 0 || pos
> len
) {
1683 // read the post table
1687 void FoFiTrueType::readPostTable() {
1689 int tablePos
, postFmt
, stringIdx
, stringPos
;
1694 if ((i
= seekTable("post")) < 0) {
1697 tablePos
= tables
[i
].offset
;
1698 postFmt
= getU32BE(tablePos
, &ok
);
1702 if (postFmt
== 0x00010000) {
1703 nameToGID
= new GooHash(gTrue
);
1704 for (i
= 0; i
< 258; ++i
) {
1705 nameToGID
->add(new GooString(macGlyphNames
[i
]), i
);
1707 } else if (postFmt
== 0x00020000) {
1708 nameToGID
= new GooHash(gTrue
);
1709 n
= getU16BE(tablePos
+ 32, &ok
);
1717 stringPos
= tablePos
+ 34 + 2*n
;
1718 for (i
= 0; i
< n
; ++i
) {
1719 j
= getU16BE(tablePos
+ 34 + 2*i
, &ok
);
1721 nameToGID
->removeInt(macGlyphNames
[j
]);
1722 nameToGID
->add(new GooString(macGlyphNames
[j
]), i
);
1725 if (j
!= stringIdx
) {
1726 for (stringIdx
= 0, stringPos
= tablePos
+ 34 + 2*n
;
1728 ++stringIdx
, stringPos
+= 1 + getU8(stringPos
, &ok
)) ;
1733 m
= getU8(stringPos
, &ok
);
1734 if (!ok
|| !checkRegion(stringPos
+ 1, m
)) {
1737 name
= new GooString((char *)&file
[stringPos
+ 1], m
);
1738 nameToGID
->removeInt(name
);
1739 nameToGID
->add(name
, i
);
1744 } else if (postFmt
== 0x00028000) {
1745 nameToGID
= new GooHash(gTrue
);
1746 for (i
= 0; i
< nGlyphs
; ++i
) {
1747 j
= getU8(tablePos
+ 32 + i
, &ok
);
1752 nameToGID
->removeInt(macGlyphNames
[j
]);
1753 nameToGID
->add(new GooString(macGlyphNames
[j
]), i
);
1767 int FoFiTrueType::seekTable(char *tag
) {
1771 tagI
= ((tag
[0] & 0xff) << 24) |
1772 ((tag
[1] & 0xff) << 16) |
1773 ((tag
[2] & 0xff) << 8) |
1775 for (i
= 0; i
< nTables
; ++i
) {
1776 if (tables
[i
].tag
== tagI
) {