1 //========================================================================
5 // Copyright 1999-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
21 #include "FoFiType1C.h"
22 #include "FoFiTrueType.h"
28 // character code = number used as an element of a text string
30 // character name = glyph name = name for a particular glyph within a
33 // glyph index = GID = position (within some internal table in the font)
34 // where the instructions to draw a particular glyph are
40 // Type 1 fonts contain:
42 // Encoding: array of glyph names, maps char codes to glyph names
44 // Encoding[charCode] = charName
46 // CharStrings: dictionary of instructions, keyed by character names,
47 // maps character name to glyph data
49 // CharStrings[charName] = glyphData
54 // TrueType fonts contain:
56 // 'cmap' table: mapping from character code to glyph index; there may
57 // be multiple cmaps in a TrueType font
59 // cmap[charCode] = gid
61 // 'post' table: mapping from glyph index to glyph name
63 // post[gid] = glyphName
68 // Type 42 fonts contain:
70 // Encoding: array of glyph names, maps char codes to glyph names
72 // Encoding[charCode] = charName
74 // CharStrings: dictionary of glyph indexes, keyed by character names,
75 // maps character name to glyph index
77 // CharStrings[charName] = gid
80 //------------------------------------------------------------------------
82 #define ttcfTag 0x74746366
84 //------------------------------------------------------------------------
86 struct TrueTypeTable
{
102 struct TrueTypeLoca
{
109 #define cmapTag 0x636d6170
110 #define glyfTag 0x676c7966
111 #define headTag 0x68656164
112 #define hheaTag 0x68686561
113 #define hmtxTag 0x686d7478
114 #define locaTag 0x6c6f6361
115 #define nameTag 0x6e616d65
116 #define os2Tag 0x4f532f32
117 #define postTag 0x706f7374
119 static int cmpTrueTypeLocaOffset(const void *p1
, const void *p2
) {
120 TrueTypeLoca
*loca1
= (TrueTypeLoca
*)p1
;
121 TrueTypeLoca
*loca2
= (TrueTypeLoca
*)p2
;
123 if (loca1
->origOffset
== loca2
->origOffset
) {
124 return loca1
->idx
- loca2
->idx
;
126 return loca1
->origOffset
- loca2
->origOffset
;
129 static int cmpTrueTypeLocaIdx(const void *p1
, const void *p2
) {
130 TrueTypeLoca
*loca1
= (TrueTypeLoca
*)p1
;
131 TrueTypeLoca
*loca2
= (TrueTypeLoca
*)p2
;
133 return loca1
->idx
- loca2
->idx
;
136 static int cmpTrueTypeTableTag(const void *p1
, const void *p2
) {
137 TrueTypeTable
*tab1
= (TrueTypeTable
*)p1
;
138 TrueTypeTable
*tab2
= (TrueTypeTable
*)p2
;
140 return (int)tab1
->tag
- (int)tab2
->tag
;
143 //------------------------------------------------------------------------
146 char *tag
; // 4-byte tag
147 GBool required
; // required by the TrueType spec?
150 // TrueType tables to be embedded in Type 42 fonts.
151 // NB: the table names must be in alphabetical order here.
152 #define nT42Tables 11
153 static T42Table t42Tables
[nT42Tables
] = {
166 #define t42HeadTable 3
167 #define t42LocaTable 6
168 #define t42GlyfTable 2
169 #define t42VheaTable 9
170 #define t42VmtxTable 10
172 //------------------------------------------------------------------------
174 // Glyph names in some arbitrary standard order that Apple uses for
175 // their TrueType fonts.
176 static const char *macGlyphNames
[258] = {
177 ".notdef", "null", "CR", "space",
178 "exclam", "quotedbl", "numbersign", "dollar",
179 "percent", "ampersand", "quotesingle", "parenleft",
180 "parenright", "asterisk", "plus", "comma",
181 "hyphen", "period", "slash", "zero",
182 "one", "two", "three", "four",
183 "five", "six", "seven", "eight",
184 "nine", "colon", "semicolon", "less",
185 "equal", "greater", "question", "at",
192 "Y", "Z", "bracketleft", "backslash",
193 "bracketright", "asciicircum", "underscore", "grave",
200 "y", "z", "braceleft", "bar",
201 "braceright", "asciitilde", "Adieresis", "Aring",
202 "Ccedilla", "Eacute", "Ntilde", "Odieresis",
203 "Udieresis", "aacute", "agrave", "acircumflex",
204 "adieresis", "atilde", "aring", "ccedilla",
205 "eacute", "egrave", "ecircumflex", "edieresis",
206 "iacute", "igrave", "icircumflex", "idieresis",
207 "ntilde", "oacute", "ograve", "ocircumflex",
208 "odieresis", "otilde", "uacute", "ugrave",
209 "ucircumflex", "udieresis", "dagger", "degree",
210 "cent", "sterling", "section", "bullet",
211 "paragraph", "germandbls", "registered", "copyright",
212 "trademark", "acute", "dieresis", "notequal",
213 "AE", "Oslash", "infinity", "plusminus",
214 "lessequal", "greaterequal", "yen", "mu1",
215 "partialdiff", "summation", "product", "pi",
216 "integral", "ordfeminine", "ordmasculine", "Ohm",
217 "ae", "oslash", "questiondown", "exclamdown",
218 "logicalnot", "radical", "florin", "approxequal",
219 "increment", "guillemotleft", "guillemotright", "ellipsis",
220 "nbspace", "Agrave", "Atilde", "Otilde",
221 "OE", "oe", "endash", "emdash",
222 "quotedblleft", "quotedblright", "quoteleft", "quoteright",
223 "divide", "lozenge", "ydieresis", "Ydieresis",
224 "fraction", "currency", "guilsinglleft", "guilsinglright",
225 "fi", "fl", "daggerdbl", "periodcentered",
226 "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
227 "Ecircumflex", "Aacute", "Edieresis", "Egrave",
228 "Iacute", "Icircumflex", "Idieresis", "Igrave",
229 "Oacute", "Ocircumflex", "applelogo", "Ograve",
230 "Uacute", "Ucircumflex", "Ugrave", "dotlessi",
231 "circumflex", "tilde", "overscore", "breve",
232 "dotaccent", "ring", "cedilla", "hungarumlaut",
233 "ogonek", "caron", "Lslash", "lslash",
234 "Scaron", "scaron", "Zcaron", "zcaron",
235 "brokenbar", "Eth", "eth", "Yacute",
236 "yacute", "Thorn", "thorn", "minus",
237 "multiply", "onesuperior", "twosuperior", "threesuperior",
238 "onehalf", "onequarter", "threequarters", "franc",
239 "Gbreve", "gbreve", "Idot", "Scedilla",
240 "scedilla", "Cacute", "cacute", "Ccaron",
244 //------------------------------------------------------------------------
246 //------------------------------------------------------------------------
248 FoFiTrueType
*FoFiTrueType::make(char *fileA
, int lenA
) {
251 ff
= new FoFiTrueType(fileA
, lenA
, gFalse
);
259 FoFiTrueType
*FoFiTrueType::load(char *fileName
) {
264 if (!(fileA
= FoFiBase::readFile(fileName
, &lenA
))) {
267 ff
= new FoFiTrueType(fileA
, lenA
, gTrue
);
275 FoFiTrueType::FoFiTrueType(char *fileA
, int lenA
, GBool freeFileDataA
):
276 FoFiBase(fileA
, lenA
, freeFileDataA
)
288 FoFiTrueType::~FoFiTrueType() {
296 int FoFiTrueType::getNumCmaps() {
300 int FoFiTrueType::getCmapPlatform(int i
) {
301 return cmaps
[i
].platform
;
304 int FoFiTrueType::getCmapEncoding(int i
) {
305 return cmaps
[i
].encoding
;
308 int FoFiTrueType::findCmap(int platform
, int encoding
) {
311 for (i
= 0; i
< nCmaps
; ++i
) {
312 if (cmaps
[i
].platform
== platform
&& cmaps
[i
].encoding
== encoding
) {
319 Gushort
FoFiTrueType::mapCodeToGID(int i
, int c
) {
321 int segCnt
, segEnd
, segStart
, segDelta
, segOffset
;
322 int cmapFirst
, cmapLen
;
326 if (i
< 0 || i
>= nCmaps
) {
330 pos
= cmaps
[i
].offset
;
331 switch (cmaps
[i
].fmt
) {
333 if (c
< 0 || c
>= cmaps
[i
].len
- 6) {
336 gid
= getU8(cmaps
[i
].offset
+ 6 + c
, &ok
);
339 segCnt
= getU16BE(pos
+ 6, &ok
) / 2;
342 segEnd
= getU16BE(pos
+ 14 + 2*b
, &ok
);
344 // malformed font -- the TrueType spec requires the last segEnd
348 // invariant: seg[a].end < code <= seg[b].end
349 while (b
- a
> 1 && ok
) {
351 segEnd
= getU16BE(pos
+ 14 + 2*m
, &ok
);
358 segStart
= getU16BE(pos
+ 16 + 2*segCnt
+ 2*b
, &ok
);
359 segDelta
= getU16BE(pos
+ 16 + 4*segCnt
+ 2*b
, &ok
);
360 segOffset
= getU16BE(pos
+ 16 + 6*segCnt
+ 2*b
, &ok
);
364 if (segOffset
== 0) {
365 gid
= (c
+ segDelta
) & 0xffff;
367 gid
= getU16BE(pos
+ 16 + 6*segCnt
+ 2*b
+
368 segOffset
+ 2 * (c
- segStart
), &ok
);
370 gid
= (gid
+ segDelta
) & 0xffff;
375 cmapFirst
= getU16BE(pos
+ 6, &ok
);
376 cmapLen
= getU16BE(pos
+ 8, &ok
);
377 if (c
< cmapFirst
|| c
>= cmapFirst
+ cmapLen
) {
380 gid
= getU16BE(pos
+ 10 + 2 * (c
- cmapFirst
), &ok
);
391 int FoFiTrueType::mapNameToGID(char *name
) {
395 return nameToGID
->lookupInt((char *)name
);
398 Gushort
*FoFiTrueType::getCIDToGIDMap(int *nCIDs
) {
407 i
= seekTable("CFF ");
408 if (!checkRegion(tables
[i
].offset
, tables
[i
].len
)) {
411 if (!(ff
= FoFiType1C::make((char *)file
+ tables
[i
].offset
,
415 map
= ff
->getCIDToGIDMap(nCIDs
);
420 int FoFiTrueType::getEmbeddingRights() {
424 if ((i
= seekTable("OS/2")) < 0) {
428 fsType
= getU16BE(tables
[i
].offset
+ 8, &ok
);
432 if (fsType
& 0x0008) {
435 if (fsType
& 0x0004) {
438 if (fsType
& 0x0002) {
444 void FoFiTrueType::convertToType42(char *psName
, char **encoding
,
446 FoFiOutputFunc outputFunc
,
447 void *outputStream
) {
457 buf
= GString::format("%!PS-TrueTypeFont-{0:2g}\n",
458 (double)getS32BE(0, &ok
) / 65536.0);
459 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
462 // begin the font dictionary
463 (*outputFunc
)(outputStream
, "10 dict begin\n", 14);
464 (*outputFunc
)(outputStream
, "/FontName /", 11);
465 (*outputFunc
)(outputStream
, psName
, strlen(psName
));
466 (*outputFunc
)(outputStream
, " def\n", 5);
467 (*outputFunc
)(outputStream
, "/FontType 42 def\n", 17);
468 (*outputFunc
)(outputStream
, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
469 buf
= GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
470 bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
471 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
473 (*outputFunc
)(outputStream
, "/PaintType 0 def\n", 17);
475 // write the guts of the dictionary
476 cvtEncoding(encoding
, outputFunc
, outputStream
);
477 cvtCharStrings(encoding
, codeToGID
, outputFunc
, outputStream
);
478 cvtSfnts(outputFunc
, outputStream
, NULL
, gFalse
);
480 // end the dictionary and define the font
481 (*outputFunc
)(outputStream
, "FontName currentdict end definefont pop\n", 40);
484 void FoFiTrueType::convertToType1(char *psName
, char **newEncoding
,
485 GBool ascii
, FoFiOutputFunc outputFunc
,
486 void *outputStream
) {
493 i
= seekTable("CFF ");
494 if (!checkRegion(tables
[i
].offset
, tables
[i
].len
)) {
497 if (!(ff
= FoFiType1C::make((char *)file
+ tables
[i
].offset
,
501 ff
->convertToType1(psName
, newEncoding
, ascii
, outputFunc
, outputStream
);
505 void FoFiTrueType::convertToCIDType2(char *psName
,
506 Gushort
*cidMap
, int nCIDs
,
507 GBool needVerticalMetrics
,
508 FoFiOutputFunc outputFunc
,
509 void *outputStream
) {
521 buf
= GString::format("%!PS-TrueTypeFont-{0:2g}\n",
522 (double)getS32BE(0, &ok
) / 65536.0);
523 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
526 // begin the font dictionary
527 (*outputFunc
)(outputStream
, "20 dict begin\n", 14);
528 (*outputFunc
)(outputStream
, "/CIDFontName /", 14);
529 (*outputFunc
)(outputStream
, psName
, strlen(psName
));
530 (*outputFunc
)(outputStream
, " def\n", 5);
531 (*outputFunc
)(outputStream
, "/CIDFontType 2 def\n", 19);
532 (*outputFunc
)(outputStream
, "/FontType 42 def\n", 17);
533 (*outputFunc
)(outputStream
, "/CIDSystemInfo 3 dict dup begin\n", 32);
534 (*outputFunc
)(outputStream
, " /Registry (Adobe) def\n", 24);
535 (*outputFunc
)(outputStream
, " /Ordering (Identity) def\n", 27);
536 (*outputFunc
)(outputStream
, " /Supplement 0 def\n", 20);
537 (*outputFunc
)(outputStream
, " end def\n", 10);
538 (*outputFunc
)(outputStream
, "/GDBytes 2 def\n", 15);
540 buf
= GString::format("/CIDCount {0:d} def\n", nCIDs
);
541 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
544 (*outputFunc
)(outputStream
, "/CIDMap [", 9);
545 for (i
= 0; i
< nCIDs
; i
+= 32768 - 16) {
546 (*outputFunc
)(outputStream
, "<\n", 2);
547 for (j
= 0; j
< 32768 - 16 && i
+j
< nCIDs
; j
+= 16) {
548 (*outputFunc
)(outputStream
, " ", 2);
549 for (k
= 0; k
< 16 && i
+j
+k
< nCIDs
; ++k
) {
551 buf
= GString::format("{0:02x}{1:02x}",
552 (cid
>> 8) & 0xff, cid
& 0xff);
553 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
556 (*outputFunc
)(outputStream
, "\n", 1);
558 (*outputFunc
)(outputStream
, " >", 3);
560 (*outputFunc
)(outputStream
, "\n", 1);
561 (*outputFunc
)(outputStream
, "] def\n", 6);
563 (*outputFunc
)(outputStream
, "/CIDMap <\n", 10);
564 for (i
= 0; i
< nCIDs
; i
+= 16) {
565 (*outputFunc
)(outputStream
, " ", 2);
566 for (j
= 0; j
< 16 && i
+j
< nCIDs
; ++j
) {
568 buf
= GString::format("{0:02x}{1:02x}",
569 (cid
>> 8) & 0xff, cid
& 0xff);
570 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
573 (*outputFunc
)(outputStream
, "\n", 1);
575 (*outputFunc
)(outputStream
, "> def\n", 6);
578 // direct mapping - just fill the string(s) with s[i]=i
579 buf
= GString::format("/CIDCount {0:d} def\n", nGlyphs
);
580 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
582 if (nGlyphs
> 32767) {
583 (*outputFunc
)(outputStream
, "/CIDMap [\n", 10);
584 for (i
= 0; i
< nGlyphs
; i
+= 32767) {
585 j
= nGlyphs
- i
< 32767 ? nGlyphs
- i
: 32767;
586 buf
= GString::format(" {0:d} string 0 1 {1:d} {{\n", 2 * j
, j
- 1);
587 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
589 buf
= GString::format(" 2 copy dup 2 mul exch {0:d} add -8 bitshift put\n",
591 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
593 buf
= GString::format(" 1 index exch dup 2 mul 1 add exch {0:d} add"
594 " 255 and put\n", i
);
595 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
597 (*outputFunc
)(outputStream
, " } for\n", 8);
599 (*outputFunc
)(outputStream
, "] def\n", 6);
601 buf
= GString::format("/CIDMap {0:d} string\n", 2 * nGlyphs
);
602 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
604 buf
= GString::format(" 0 1 {0:d} {{\n", nGlyphs
- 1);
605 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
607 (*outputFunc
)(outputStream
,
608 " 2 copy dup 2 mul exch -8 bitshift put\n", 42);
609 (*outputFunc
)(outputStream
,
610 " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
611 (*outputFunc
)(outputStream
, " } for\n", 8);
612 (*outputFunc
)(outputStream
, "def\n", 4);
615 (*outputFunc
)(outputStream
, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
616 buf
= GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
617 bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
618 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
620 (*outputFunc
)(outputStream
, "/PaintType 0 def\n", 17);
621 (*outputFunc
)(outputStream
, "/Encoding [] readonly def\n", 26);
622 (*outputFunc
)(outputStream
, "/CharStrings 1 dict dup begin\n", 30);
623 (*outputFunc
)(outputStream
, " /.notdef 0 def\n", 17);
624 (*outputFunc
)(outputStream
, " end readonly def\n", 19);
626 // write the guts of the dictionary
627 cvtSfnts(outputFunc
, outputStream
, NULL
, needVerticalMetrics
);
629 // end the dictionary and define the font
630 (*outputFunc
)(outputStream
,
631 "CIDFontName currentdict end /CIDFont defineresource pop\n",
635 void FoFiTrueType::convertToCIDType0(char *psName
,
636 FoFiOutputFunc outputFunc
,
637 void *outputStream
) {
644 i
= seekTable("CFF ");
645 if (!checkRegion(tables
[i
].offset
, tables
[i
].len
)) {
648 if (!(ff
= FoFiType1C::make((char *)file
+ tables
[i
].offset
,
652 ff
->convertToCIDType0(psName
, outputFunc
, outputStream
);
656 void FoFiTrueType::convertToType0(char *psName
, Gushort
*cidMap
, int nCIDs
,
657 GBool needVerticalMetrics
,
658 FoFiOutputFunc outputFunc
,
659 void *outputStream
) {
668 // write the Type 42 sfnts array
669 sfntsName
= (new GString(psName
))->append("_sfnts");
670 cvtSfnts(outputFunc
, outputStream
, sfntsName
, needVerticalMetrics
);
673 // write the descendant Type 42 fonts
674 n
= cidMap
? nCIDs
: nGlyphs
;
675 for (i
= 0; i
< n
; i
+= 256) {
676 (*outputFunc
)(outputStream
, "10 dict begin\n", 14);
677 (*outputFunc
)(outputStream
, "/FontName /", 11);
678 (*outputFunc
)(outputStream
, psName
, strlen(psName
));
679 buf
= GString::format("_{0:02x} def\n", i
>> 8);
680 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
682 (*outputFunc
)(outputStream
, "/FontType 42 def\n", 17);
683 (*outputFunc
)(outputStream
, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
684 buf
= GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
685 bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
686 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
688 (*outputFunc
)(outputStream
, "/PaintType 0 def\n", 17);
689 (*outputFunc
)(outputStream
, "/sfnts ", 7);
690 (*outputFunc
)(outputStream
, psName
, strlen(psName
));
691 (*outputFunc
)(outputStream
, "_sfnts def\n", 11);
692 (*outputFunc
)(outputStream
, "/Encoding 256 array\n", 20);
693 for (j
= 0; j
< 256 && i
+j
< n
; ++j
) {
694 buf
= GString::format("dup {0:d} /c{1:02x} put\n", j
, j
);
695 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
698 (*outputFunc
)(outputStream
, "readonly def\n", 13);
699 (*outputFunc
)(outputStream
, "/CharStrings 257 dict dup begin\n", 32);
700 (*outputFunc
)(outputStream
, "/.notdef 0 def\n", 15);
701 for (j
= 0; j
< 256 && i
+j
< n
; ++j
) {
702 buf
= GString::format("/c{0:02x} {1:d} def\n",
703 j
, cidMap
? cidMap
[i
+j
] : i
+j
);
704 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
707 (*outputFunc
)(outputStream
, "end readonly def\n", 17);
708 (*outputFunc
)(outputStream
,
709 "FontName currentdict end definefont pop\n", 40);
712 // write the Type 0 parent font
713 (*outputFunc
)(outputStream
, "16 dict begin\n", 14);
714 (*outputFunc
)(outputStream
, "/FontName /", 11);
715 (*outputFunc
)(outputStream
, psName
, strlen(psName
));
716 (*outputFunc
)(outputStream
, " def\n", 5);
717 (*outputFunc
)(outputStream
, "/FontType 0 def\n", 16);
718 (*outputFunc
)(outputStream
, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
719 (*outputFunc
)(outputStream
, "/FMapType 2 def\n", 16);
720 (*outputFunc
)(outputStream
, "/Encoding [\n", 12);
721 for (i
= 0; i
< n
; i
+= 256) {
722 buf
= GString::format("{0:d}\n", i
>> 8);
723 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
726 (*outputFunc
)(outputStream
, "] def\n", 6);
727 (*outputFunc
)(outputStream
, "/FDepVector [\n", 14);
728 for (i
= 0; i
< n
; i
+= 256) {
729 (*outputFunc
)(outputStream
, "/", 1);
730 (*outputFunc
)(outputStream
, psName
, strlen(psName
));
731 buf
= GString::format("_{0:02x} findfont\n", i
>> 8);
732 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
735 (*outputFunc
)(outputStream
, "] def\n", 6);
736 (*outputFunc
)(outputStream
, "FontName currentdict end definefont pop\n", 40);
739 void FoFiTrueType::convertToType0(char *psName
,
740 FoFiOutputFunc outputFunc
,
741 void *outputStream
) {
748 i
= seekTable("CFF ");
749 if (!checkRegion(tables
[i
].offset
, tables
[i
].len
)) {
752 if (!(ff
= FoFiType1C::make((char *)file
+ tables
[i
].offset
,
756 ff
->convertToType0(psName
, outputFunc
, outputStream
);
760 void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc
,
761 void *outputStream
, char *name
,
762 Gushort
*codeToGID
) {
763 // this substitute cmap table maps char codes 0000-ffff directly to
765 static char cmapTab
[36] = {
766 0, 0, // table version number
767 0, 1, // number of encoding tables
770 0, 0, 0, 12, // offset of subtable
771 0, 4, // subtable format
772 0, 24, // subtable length
773 0, 0, // subtable version
774 0, 2, // segment count * 2
775 0, 2, // 2 * 2 ^ floor(log2(segCount))
776 0, 0, // floor(log2(segCount))
777 0, 0, // 2*segCount - 2*2^floor(log2(segCount))
778 (char)0xff, (char)0xff, // endCount[0]
780 0, 0, // startCount[0]
782 0, 0 // pad to a mulitple of four bytes
784 static char nameTab
[8] = {
786 0, 0, // number of name records
787 0, 6, // offset to start of string storage
788 0, 0 // pad to multiple of four bytes
790 static char postTab
[32] = {
791 0, 1, 0, 0, // format
792 0, 0, 0, 0, // italic angle
793 0, 0, // underline position
794 0, 0, // underline thickness
795 0, 0, 0, 0, // fixed pitch
796 0, 0, 0, 0, // min Type 42 memory
797 0, 0, 0, 0, // max Type 42 memory
798 0, 0, 0, 0, // min Type 1 memory
799 0, 0, 0, 0 // max Type 1 memory
801 static char os2Tab
[86] = {
803 0, 1, // xAvgCharWidth
804 0, 0, // usWeightClass
805 0, 0, // usWidthClass
807 0, 0, // ySubscriptXSize
808 0, 0, // ySubscriptYSize
809 0, 0, // ySubscriptXOffset
810 0, 0, // ySubscriptYOffset
811 0, 0, // ySuperscriptXSize
812 0, 0, // ySuperscriptYSize
813 0, 0, // ySuperscriptXOffset
814 0, 0, // ySuperscriptYOffset
815 0, 0, // yStrikeoutSize
816 0, 0, // yStrikeoutPosition
817 0, 0, // sFamilyClass
818 0, 0, 0, 0, 0, // panose
820 0, 0, 0, 0, // ulUnicodeRange1
821 0, 0, 0, 0, // ulUnicodeRange2
822 0, 0, 0, 0, // ulUnicodeRange3
823 0, 0, 0, 0, // ulUnicodeRange4
824 0, 0, 0, 0, // achVendID
826 0, 0, // usFirstCharIndex
827 0, 0, // usLastCharIndex
828 0, 0, // sTypoAscender
829 0, 0, // sTypoDescender
830 0, 0, // sTypoLineGap
832 0, 0, // usWinDescent
833 0, 0, 0, 0, // ulCodePageRange1
834 0, 0, 0, 0 // ulCodePageRange2
836 GBool missingCmap
, missingName
, missingPost
, missingOS2
;
837 GBool unsortedLoca
, badCmapLen
, abbrevHMTX
;
838 int nZeroLengthTables
;
839 int nHMetrics
, advWidth
, lsb
;
840 TrueTypeLoca
*locaTable
;
841 TrueTypeTable
*newTables
;
842 char *newNameTab
, *newCmapTab
, *newHHEATab
, *newHMTXTab
;
843 int nNewTables
, cmapIdx
, cmapLen
, glyfLen
, newNameLen
, newCmapLen
, next
;
844 int newHHEALen
, newHMTXLen
;
845 Guint locaChecksum
, glyfChecksum
, fileChecksum
;
847 char locaBuf
[4], checksumBuf
[4];
856 // check for missing tables
857 // (Note: if the OS/2 table is missing, the Microsoft PCL5 driver
858 // will embed a PCL TrueType font with the pitch field set to zero,
859 // which apparently causes divide-by-zero errors. As far as I can
860 // tell, the only important field in the OS/2 table is
862 missingCmap
= (cmapIdx
= seekTable("cmap")) < 0;
863 missingName
= seekTable("name") < 0;
864 missingPost
= seekTable("post") < 0;
865 missingOS2
= seekTable("OS/2") < 0;
867 // read the loca table, check to see if it's sorted
868 locaTable
= (TrueTypeLoca
*)gmallocn(nGlyphs
+ 1, sizeof(TrueTypeLoca
));
869 unsortedLoca
= gFalse
;
870 i
= seekTable("loca");
871 pos
= tables
[i
].offset
;
873 for (i
= 0; i
<= nGlyphs
; ++i
) {
875 locaTable
[i
].origOffset
= (int)getU32BE(pos
+ i
*4, &ok
);
877 locaTable
[i
].origOffset
= 2 * getU16BE(pos
+ i
*2, &ok
);
879 if (i
> 0 && locaTable
[i
].origOffset
< locaTable
[i
-1].origOffset
) {
880 unsortedLoca
= gTrue
;
882 // glyph descriptions must be at least 12 bytes long (nContours,
883 // xMin, yMin, xMax, yMax, instructionLength - two bytes each);
884 // invalid glyph descriptions (even if they're never used) make
885 // Windows choke, so we work around that problem here (ideally,
886 // this would parse the glyph descriptions in the glyf table and
887 // remove any that were invalid, but this quick test is a decent
890 locaTable
[i
].origOffset
- locaTable
[i
-1].origOffset
> 0 &&
891 locaTable
[i
].origOffset
- locaTable
[i
-1].origOffset
< 12) {
892 locaTable
[i
-1].origOffset
= locaTable
[i
].origOffset
;
893 unsortedLoca
= gTrue
;
895 locaTable
[i
].idx
= i
;
898 // check for zero-length tables
899 nZeroLengthTables
= 0;
900 for (i
= 0; i
< nTables
; ++i
) {
901 if (tables
[i
].len
== 0) {
906 // check for an incorrect cmap table length
908 cmapLen
= 0; // make gcc happy
910 cmapLen
= cmaps
[0].offset
+ cmaps
[0].len
;
911 for (i
= 1; i
< nCmaps
; ++i
) {
912 if (cmaps
[i
].offset
+ cmaps
[i
].len
> cmapLen
) {
913 cmapLen
= cmaps
[i
].offset
+ cmaps
[i
].len
;
916 cmapLen
-= tables
[cmapIdx
].offset
;
917 if (cmapLen
> tables
[cmapIdx
].len
) {
922 // check for an abbreviated hmtx table (this is completely legal,
923 // but confuses the Microsoft PCL5 printer driver, which generates
924 // embedded fonts with the pitch field set to zero)
925 i
= seekTable("hhea");
926 nHMetrics
= getU16BE(tables
[i
].offset
+ 34, &ok
);
927 abbrevHMTX
= nHMetrics
< nGlyphs
;
929 // if nothing is broken, just write the TTF file as is
930 if (!missingCmap
&& !missingName
&& !missingPost
&& !missingOS2
&&
931 !unsortedLoca
&& !badCmapLen
&& !abbrevHMTX
&& nZeroLengthTables
== 0 &&
932 !name
&& !codeToGID
) {
933 (*outputFunc
)(outputStream
, (char *)file
, len
);
937 // sort the 'loca' table: some (non-compliant) fonts have
938 // out-of-order loca tables; in order to correctly handle the case
939 // where (compliant) fonts have empty entries in the middle of the
940 // table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
941 // and idx as its secondary key (ensuring that adjacent entries with
942 // the same pos value remain in the same order)
943 glyfLen
= 0; // make gcc happy
945 qsort(locaTable
, nGlyphs
+ 1, sizeof(TrueTypeLoca
),
946 &cmpTrueTypeLocaOffset
);
947 for (i
= 0; i
< nGlyphs
; ++i
) {
948 locaTable
[i
].len
= locaTable
[i
+1].origOffset
- locaTable
[i
].origOffset
;
950 locaTable
[nGlyphs
].len
= 0;
951 qsort(locaTable
, nGlyphs
+ 1, sizeof(TrueTypeLoca
),
952 &cmpTrueTypeLocaIdx
);
954 for (i
= 0; i
<= nGlyphs
; ++i
) {
955 locaTable
[i
].newOffset
= pos
;
956 pos
+= locaTable
[i
].len
;
958 pos
+= 4 - (pos
& 3);
964 // compute checksums for the loca and glyf tables
965 locaChecksum
= glyfChecksum
= 0;
968 for (j
= 0; j
<= nGlyphs
; ++j
) {
969 locaChecksum
+= locaTable
[j
].newOffset
;
972 for (j
= 0; j
<= nGlyphs
; j
+= 2) {
973 locaChecksum
+= locaTable
[j
].newOffset
<< 16;
974 if (j
+ 1 <= nGlyphs
) {
975 locaChecksum
+= locaTable
[j
+1].newOffset
;
979 pos
= tables
[seekTable("glyf")].offset
;
980 for (j
= 0; j
< nGlyphs
; ++j
) {
981 n
= locaTable
[j
].len
;
983 k
= locaTable
[j
].origOffset
;
984 if (checkRegion(pos
+ k
, n
)) {
985 glyfChecksum
+= computeTableChecksum(file
+ pos
+ k
, n
);
991 // construct the new name table
994 newNameLen
= (6 + 4*12 + 2 * (3*n
+ 7) + 3) & ~3;
995 newNameTab
= (char *)gmalloc(newNameLen
);
996 memset(newNameTab
, 0, newNameLen
);
997 newNameTab
[0] = 0; // format selector
999 newNameTab
[2] = 0; // number of name records
1001 newNameTab
[4] = 0; // offset to start of string storage
1002 newNameTab
[5] = 6 + 4*12;
1004 for (i
= 0; i
< 4; ++i
) {
1005 newNameTab
[6 + i
*12 + 0] = 0; // platform ID = Microsoft
1006 newNameTab
[6 + i
*12 + 1] = 3;
1007 newNameTab
[6 + i
*12 + 2] = 0; // encoding ID = Unicode
1008 newNameTab
[6 + i
*12 + 3] = 1;
1009 newNameTab
[6 + i
*12 + 4] = 0x04; // language ID = American English
1010 newNameTab
[6 + i
*12 + 5] = 0x09;
1011 newNameTab
[6 + i
*12 + 6] = 0; // name ID
1012 newNameTab
[6 + i
*12 + 7] = i
+ 1;
1013 newNameTab
[6 + i
*12 + 8] = i
+1 == 2 ? 0 : ((2*n
) >> 8); // string length
1014 newNameTab
[6 + i
*12 + 9] = i
+1 == 2 ? 14 : ((2*n
) & 0xff);
1015 newNameTab
[6 + i
*12 + 10] = next
>> 8; // string offset
1016 newNameTab
[6 + i
*12 + 11] = next
& 0xff;
1018 memcpy(newNameTab
+ 6 + 4*12 + next
, "\0R\0e\0g\0u\0l\0a\0r", 14);
1021 for (j
= 0; j
< n
; ++j
) {
1022 newNameTab
[6 + 4*12 + next
+ 2*j
] = 0;
1023 newNameTab
[6 + 4*12 + next
+ 2*j
+ 1] = name
[j
];
1033 // construct the new cmap table
1035 newCmapLen
= 44 + 256 * 2;
1036 newCmapTab
= (char *)gmalloc(newCmapLen
);
1037 newCmapTab
[0] = 0; // table version number = 0
1039 newCmapTab
[2] = 0; // number of encoding tables = 1
1041 newCmapTab
[4] = 0; // platform ID = Microsoft
1043 newCmapTab
[6] = 0; // encoding ID = Unicode
1045 newCmapTab
[8] = 0; // offset of subtable
1048 newCmapTab
[11] = 12;
1049 newCmapTab
[12] = 0; // subtable format = 4
1051 newCmapTab
[14] = 0x02; // subtable length
1052 newCmapTab
[15] = 0x20;
1053 newCmapTab
[16] = 0; // subtable version = 0
1055 newCmapTab
[18] = 0; // segment count * 2
1057 newCmapTab
[20] = 0; // 2 * 2 ^ floor(log2(segCount))
1059 newCmapTab
[22] = 0; // floor(log2(segCount))
1061 newCmapTab
[24] = 0; // 2*segCount - 2*2^floor(log2(segCount))
1063 newCmapTab
[26] = 0x00; // endCount[0]
1064 newCmapTab
[27] = (char)0xff;
1065 newCmapTab
[28] = (char)0xff; // endCount[1]
1066 newCmapTab
[29] = (char)0xff;
1067 newCmapTab
[30] = 0; // reserved
1069 newCmapTab
[32] = 0x00; // startCount[0]
1070 newCmapTab
[33] = 0x00;
1071 newCmapTab
[34] = (char)0xff; // startCount[1]
1072 newCmapTab
[35] = (char)0xff;
1073 newCmapTab
[36] = 0; // idDelta[0]
1075 newCmapTab
[38] = 0; // idDelta[1]
1077 newCmapTab
[40] = 0; // idRangeOffset[0]
1079 newCmapTab
[42] = 0; // idRangeOffset[1]
1081 for (i
= 0; i
< 256; ++i
) {
1082 newCmapTab
[44 + 2*i
] = codeToGID
[i
] >> 8;
1083 newCmapTab
[44 + 2*i
+ 1] = codeToGID
[i
] & 0xff;
1090 // generate the new hmtx table and the updated hhea table
1092 i
= seekTable("hhea");
1093 pos
= tables
[i
].offset
;
1095 newHHEATab
= (char *)gmalloc(newHHEALen
);
1096 for (i
= 0; i
< newHHEALen
; ++i
) {
1097 newHHEATab
[i
] = getU8(pos
++, &ok
);
1099 newHHEATab
[34] = nGlyphs
>> 8;
1100 newHHEATab
[35] = nGlyphs
& 0xff;
1101 i
= seekTable("hmtx");
1102 pos
= tables
[i
].offset
;
1103 newHMTXLen
= 4 * nGlyphs
;
1104 newHMTXTab
= (char *)gmalloc(newHMTXLen
);
1106 for (i
= 0; i
< nHMetrics
; ++i
) {
1107 advWidth
= getU16BE(pos
, &ok
);
1108 lsb
= getU16BE(pos
+ 2, &ok
);
1110 newHMTXTab
[4*i
] = advWidth
>> 8;
1111 newHMTXTab
[4*i
+ 1] = advWidth
& 0xff;
1112 newHMTXTab
[4*i
+ 2] = lsb
>> 8;
1113 newHMTXTab
[4*i
+ 3] = lsb
& 0xff;
1115 for (; i
< nGlyphs
; ++i
) {
1116 lsb
= getU16BE(pos
, &ok
);
1118 newHMTXTab
[4*i
] = advWidth
>> 8;
1119 newHMTXTab
[4*i
+ 1] = advWidth
& 0xff;
1120 newHMTXTab
[4*i
+ 2] = lsb
>> 8;
1121 newHMTXTab
[4*i
+ 3] = lsb
& 0xff;
1124 newHHEATab
= newHMTXTab
= NULL
;
1125 newHHEALen
= newHMTXLen
= 0; // make gcc happy
1128 // construct the new table directory:
1129 // - keep all original tables with non-zero length
1130 // - fix the cmap table's length, if necessary
1131 // - add missing tables
1132 // - sort the table by tag
1133 // - compute new table positions, including 4-byte alignment
1134 // - (re)compute table checksums
1135 nNewTables
= nTables
- nZeroLengthTables
+
1136 (missingCmap
? 1 : 0) + (missingName
? 1 : 0) +
1137 (missingPost
? 1 : 0) + (missingOS2
? 1 : 0);
1138 newTables
= (TrueTypeTable
*)gmallocn(nNewTables
, sizeof(TrueTypeTable
));
1140 for (i
= 0; i
< nTables
; ++i
) {
1141 if (tables
[i
].len
> 0) {
1142 newTables
[j
] = tables
[i
];
1143 newTables
[j
].origOffset
= tables
[i
].offset
;
1144 if (checkRegion(tables
[i
].offset
, newTables
[i
].len
)) {
1145 newTables
[j
].checksum
=
1146 computeTableChecksum(file
+ tables
[i
].offset
, tables
[i
].len
);
1147 if (tables
[i
].tag
== headTag
) {
1148 // don't include the file checksum
1149 newTables
[j
].checksum
-= getU32BE(tables
[i
].offset
+ 8, &ok
);
1152 if (newTables
[j
].tag
== cmapTag
&& codeToGID
) {
1153 newTables
[j
].len
= newCmapLen
;
1154 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)newCmapTab
,
1156 } else if (newTables
[j
].tag
== cmapTag
&& badCmapLen
) {
1157 newTables
[j
].len
= cmapLen
;
1158 } else if (newTables
[j
].tag
== locaTag
&& unsortedLoca
) {
1159 newTables
[j
].len
= (nGlyphs
+ 1) * (locaFmt
? 4 : 2);
1160 newTables
[j
].checksum
= locaChecksum
;
1161 } else if (newTables
[j
].tag
== glyfTag
&& unsortedLoca
) {
1162 newTables
[j
].len
= glyfLen
;
1163 newTables
[j
].checksum
= glyfChecksum
;
1164 } else if (newTables
[j
].tag
== nameTag
&& name
) {
1165 newTables
[j
].len
= newNameLen
;
1166 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)newNameTab
,
1168 } else if (newTables
[j
].tag
== hheaTag
&& abbrevHMTX
) {
1169 newTables
[j
].len
= newHHEALen
;
1170 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)newHHEATab
,
1172 } else if (newTables
[j
].tag
== hmtxTag
&& abbrevHMTX
) {
1173 newTables
[j
].len
= newHMTXLen
;
1174 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)newHMTXTab
,
1181 newTables
[j
].tag
= cmapTag
;
1183 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)newCmapTab
,
1185 newTables
[j
].len
= newCmapLen
;
1187 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)cmapTab
,
1189 newTables
[j
].len
= sizeof(cmapTab
);
1194 newTables
[j
].tag
= nameTag
;
1196 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)newNameTab
,
1198 newTables
[j
].len
= newNameLen
;
1200 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)nameTab
,
1202 newTables
[j
].len
= sizeof(nameTab
);
1207 newTables
[j
].tag
= postTag
;
1208 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)postTab
,
1210 newTables
[j
].len
= sizeof(postTab
);
1214 newTables
[j
].tag
= os2Tag
;
1215 newTables
[j
].checksum
= computeTableChecksum((Guchar
*)os2Tab
,
1217 newTables
[j
].len
= sizeof(os2Tab
);
1220 qsort(newTables
, nNewTables
, sizeof(TrueTypeTable
),
1221 &cmpTrueTypeTableTag
);
1222 pos
= 12 + nNewTables
* 16;
1223 for (i
= 0; i
< nNewTables
; ++i
) {
1224 newTables
[i
].offset
= pos
;
1225 pos
+= newTables
[i
].len
;
1227 pos
+= 4 - (pos
& 3);
1231 // write the table directory
1232 tableDir
= (char *)gmalloc(12 + nNewTables
* 16);
1233 tableDir
[0] = 0x00; // sfnt version
1237 tableDir
[4] = (char)((nNewTables
>> 8) & 0xff); // numTables
1238 tableDir
[5] = (char)(nNewTables
& 0xff);
1239 for (i
= -1, t
= (Guint
)nNewTables
; t
; ++i
, t
>>= 1) ;
1241 tableDir
[6] = (char)((t
>> 8) & 0xff); // searchRange
1242 tableDir
[7] = (char)(t
& 0xff);
1243 tableDir
[8] = (char)((i
>> 8) & 0xff); // entrySelector
1244 tableDir
[9] = (char)(i
& 0xff);
1245 t
= nNewTables
* 16 - t
;
1246 tableDir
[10] = (char)((t
>> 8) & 0xff); // rangeShift
1247 tableDir
[11] = (char)(t
& 0xff);
1249 for (i
= 0; i
< nNewTables
; ++i
) {
1250 tableDir
[pos
] = (char)(newTables
[i
].tag
>> 24);
1251 tableDir
[pos
+ 1] = (char)(newTables
[i
].tag
>> 16);
1252 tableDir
[pos
+ 2] = (char)(newTables
[i
].tag
>> 8);
1253 tableDir
[pos
+ 3] = (char) newTables
[i
].tag
;
1254 tableDir
[pos
+ 4] = (char)(newTables
[i
].checksum
>> 24);
1255 tableDir
[pos
+ 5] = (char)(newTables
[i
].checksum
>> 16);
1256 tableDir
[pos
+ 6] = (char)(newTables
[i
].checksum
>> 8);
1257 tableDir
[pos
+ 7] = (char) newTables
[i
].checksum
;
1258 tableDir
[pos
+ 8] = (char)(newTables
[i
].offset
>> 24);
1259 tableDir
[pos
+ 9] = (char)(newTables
[i
].offset
>> 16);
1260 tableDir
[pos
+10] = (char)(newTables
[i
].offset
>> 8);
1261 tableDir
[pos
+11] = (char) newTables
[i
].offset
;
1262 tableDir
[pos
+12] = (char)(newTables
[i
].len
>> 24);
1263 tableDir
[pos
+13] = (char)(newTables
[i
].len
>> 16);
1264 tableDir
[pos
+14] = (char)(newTables
[i
].len
>> 8);
1265 tableDir
[pos
+15] = (char) newTables
[i
].len
;
1268 (*outputFunc
)(outputStream
, tableDir
, 12 + nNewTables
* 16);
1270 // compute the file checksum
1271 fileChecksum
= computeTableChecksum((Guchar
*)tableDir
,
1272 12 + nNewTables
* 16);
1273 for (i
= 0; i
< nNewTables
; ++i
) {
1274 fileChecksum
+= newTables
[i
].checksum
;
1276 fileChecksum
= 0xb1b0afba - fileChecksum
;
1279 for (i
= 0; i
< nNewTables
; ++i
) {
1280 if (newTables
[i
].tag
== headTag
) {
1281 if (checkRegion(newTables
[i
].origOffset
, newTables
[i
].len
)) {
1282 (*outputFunc
)(outputStream
, (char *)file
+ newTables
[i
].origOffset
, 8);
1283 checksumBuf
[0] = fileChecksum
>> 24;
1284 checksumBuf
[1] = fileChecksum
>> 16;
1285 checksumBuf
[2] = fileChecksum
>> 8;
1286 checksumBuf
[3] = fileChecksum
;
1287 (*outputFunc
)(outputStream
, checksumBuf
, 4);
1288 (*outputFunc
)(outputStream
,
1289 (char *)file
+ newTables
[i
].origOffset
+ 12,
1290 newTables
[i
].len
- 12);
1292 for (j
= 0; j
< newTables
[i
].len
; ++j
) {
1293 (*outputFunc
)(outputStream
, "\0", 1);
1296 } else if (newTables
[i
].tag
== cmapTag
&& codeToGID
) {
1297 (*outputFunc
)(outputStream
, newCmapTab
, newTables
[i
].len
);
1298 } else if (newTables
[i
].tag
== cmapTag
&& missingCmap
) {
1299 (*outputFunc
)(outputStream
, cmapTab
, newTables
[i
].len
);
1300 } else if (newTables
[i
].tag
== nameTag
&& name
) {
1301 (*outputFunc
)(outputStream
, newNameTab
, newTables
[i
].len
);
1302 } else if (newTables
[i
].tag
== nameTag
&& missingName
) {
1303 (*outputFunc
)(outputStream
, nameTab
, newTables
[i
].len
);
1304 } else if (newTables
[i
].tag
== postTag
&& missingPost
) {
1305 (*outputFunc
)(outputStream
, postTab
, newTables
[i
].len
);
1306 } else if (newTables
[i
].tag
== os2Tag
&& missingOS2
) {
1307 (*outputFunc
)(outputStream
, os2Tab
, newTables
[i
].len
);
1308 } else if (newTables
[i
].tag
== hheaTag
&& abbrevHMTX
) {
1309 (*outputFunc
)(outputStream
, newHHEATab
, newTables
[i
].len
);
1310 } else if (newTables
[i
].tag
== hmtxTag
&& abbrevHMTX
) {
1311 (*outputFunc
)(outputStream
, newHMTXTab
, newTables
[i
].len
);
1312 } else if (newTables
[i
].tag
== locaTag
&& unsortedLoca
) {
1313 for (j
= 0; j
<= nGlyphs
; ++j
) {
1315 locaBuf
[0] = (char)(locaTable
[j
].newOffset
>> 24);
1316 locaBuf
[1] = (char)(locaTable
[j
].newOffset
>> 16);
1317 locaBuf
[2] = (char)(locaTable
[j
].newOffset
>> 8);
1318 locaBuf
[3] = (char) locaTable
[j
].newOffset
;
1319 (*outputFunc
)(outputStream
, locaBuf
, 4);
1321 locaBuf
[0] = (char)(locaTable
[j
].newOffset
>> 9);
1322 locaBuf
[1] = (char)(locaTable
[j
].newOffset
>> 1);
1323 (*outputFunc
)(outputStream
, locaBuf
, 2);
1326 } else if (newTables
[i
].tag
== glyfTag
&& unsortedLoca
) {
1327 pos
= tables
[seekTable("glyf")].offset
;
1328 for (j
= 0; j
< nGlyphs
; ++j
) {
1329 n
= locaTable
[j
].len
;
1331 k
= locaTable
[j
].origOffset
;
1332 if (checkRegion(pos
+ k
, n
)) {
1333 (*outputFunc
)(outputStream
, (char *)file
+ pos
+ k
, n
);
1335 for (k
= 0; k
< n
; ++k
) {
1336 (*outputFunc
)(outputStream
, "\0", 1);
1339 if ((k
= locaTable
[j
].len
& 3)) {
1340 (*outputFunc
)(outputStream
, "\0\0\0\0", 4 - k
);
1345 if (checkRegion(newTables
[i
].origOffset
, newTables
[i
].len
)) {
1346 (*outputFunc
)(outputStream
, (char *)file
+ newTables
[i
].origOffset
,
1349 for (j
= 0; j
< newTables
[i
].len
; ++j
) {
1350 (*outputFunc
)(outputStream
, "\0", 1);
1354 if (newTables
[i
].len
& 3) {
1355 (*outputFunc
)(outputStream
, "\0\0\0", 4 - (newTables
[i
].len
& 3));
1369 void FoFiTrueType::cvtEncoding(char **encoding
,
1370 FoFiOutputFunc outputFunc
,
1371 void *outputStream
) {
1376 (*outputFunc
)(outputStream
, "/Encoding 256 array\n", 20);
1378 for (i
= 0; i
< 256; ++i
) {
1379 if (!(name
= encoding
[i
])) {
1382 buf
= GString::format("dup {0:d} /", i
);
1383 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
1385 (*outputFunc
)(outputStream
, name
, strlen(name
));
1386 (*outputFunc
)(outputStream
, " put\n", 5);
1389 for (i
= 0; i
< 256; ++i
) {
1390 buf
= GString::format("dup {0:d} /c{1:02x} put\n", i
, i
);
1391 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
1395 (*outputFunc
)(outputStream
, "readonly def\n", 13);
1398 void FoFiTrueType::cvtCharStrings(char **encoding
,
1400 FoFiOutputFunc outputFunc
,
1401 void *outputStream
) {
1407 // always define '.notdef'
1408 (*outputFunc
)(outputStream
, "/CharStrings 256 dict dup begin\n", 32);
1409 (*outputFunc
)(outputStream
, "/.notdef 0 def\n", 15);
1411 // if there's no 'cmap' table, punt
1416 // map char name to glyph index:
1417 // 1. use encoding to map name to char code
1418 // 2. use codeToGID to map char code to glyph index
1419 // N.B. We do this in reverse order because font subsets can have
1420 // weird encodings that use the same character name twice, and
1421 // the first definition is probably the one we want.
1422 k
= 0; // make gcc happy
1423 for (i
= 255; i
>= 0; --i
) {
1427 sprintf(buf2
, "c%02x", i
);
1430 if (name
&& strcmp(name
, ".notdef")) {
1432 // note: Distiller (maybe Adobe's PS interpreter in general)
1433 // doesn't like TrueType fonts that have CharStrings entries
1434 // which point to nonexistent glyphs, hence the (k < nGlyphs)
1436 if (k
> 0 && k
< nGlyphs
) {
1437 (*outputFunc
)(outputStream
, "/", 1);
1438 (*outputFunc
)(outputStream
, name
, strlen(name
));
1439 buf
= GString::format(" {0:d} def\n", k
);
1440 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
1447 (*outputFunc
)(outputStream
, "end readonly def\n", 17);
1450 void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc
,
1451 void *outputStream
, GString
*name
,
1452 GBool needVerticalMetrics
) {
1453 Guchar headData
[54];
1454 TrueTypeLoca
*locaTable
;
1456 TrueTypeTable newTables
[nT42Tables
];
1457 Guchar tableDir
[12 + nT42Tables
*16];
1461 int length
, pos
, glyfPos
, i
, j
, k
;
1462 Guchar vheaTab
[36] = {
1463 0, 1, 0, 0, // table version number
1467 0, 0, // max advance height
1468 0, 0, // min top side bearing
1469 0, 0, // min bottom side bearing
1470 0, 0, // y max extent
1471 0, 0, // caret slope rise
1472 0, 1, // caret slope run
1473 0, 0, // caret offset
1478 0, 0, // metric data format
1479 0, 1 // number of advance heights in vmtx table
1482 GBool needVhea
, needVmtx
;
1485 // construct the 'head' table, zero out the font checksum
1486 i
= seekTable("head");
1487 pos
= tables
[i
].offset
;
1488 if (!checkRegion(pos
, 54)) {
1491 memcpy(headData
, file
+ pos
, 54);
1492 headData
[8] = headData
[9] = headData
[10] = headData
[11] = (Guchar
)0;
1494 // read the original 'loca' table, pad entries out to 4 bytes, and
1495 // sort it into proper order -- some (non-compliant) fonts have
1496 // out-of-order loca tables; in order to correctly handle the case
1497 // where (compliant) fonts have empty entries in the middle of the
1498 // table, cmpTrueTypeLocaPos uses offset as its primary sort key,
1499 // and idx as its secondary key (ensuring that adjacent entries with
1500 // the same pos value remain in the same order)
1501 locaTable
= (TrueTypeLoca
*)gmallocn(nGlyphs
+ 1, sizeof(TrueTypeLoca
));
1502 i
= seekTable("loca");
1503 pos
= tables
[i
].offset
;
1505 for (i
= 0; i
<= nGlyphs
; ++i
) {
1506 locaTable
[i
].idx
= i
;
1508 locaTable
[i
].origOffset
= (int)getU32BE(pos
+ i
*4, &ok
);
1510 locaTable
[i
].origOffset
= 2 * getU16BE(pos
+ i
*2, &ok
);
1513 qsort(locaTable
, nGlyphs
+ 1, sizeof(TrueTypeLoca
),
1514 &cmpTrueTypeLocaOffset
);
1515 for (i
= 0; i
< nGlyphs
; ++i
) {
1516 locaTable
[i
].len
= locaTable
[i
+1].origOffset
- locaTable
[i
].origOffset
;
1518 locaTable
[nGlyphs
].len
= 0;
1519 qsort(locaTable
, nGlyphs
+ 1, sizeof(TrueTypeLoca
),
1520 &cmpTrueTypeLocaIdx
);
1522 for (i
= 0; i
<= nGlyphs
; ++i
) {
1523 locaTable
[i
].newOffset
= pos
;
1524 pos
+= locaTable
[i
].len
;
1526 pos
+= 4 - (pos
& 3);
1530 // construct the new 'loca' table
1531 locaData
= (Guchar
*)gmallocn(nGlyphs
+ 1, (locaFmt
? 4 : 2));
1532 for (i
= 0; i
<= nGlyphs
; ++i
) {
1533 pos
= locaTable
[i
].newOffset
;
1535 locaData
[4*i
] = (Guchar
)(pos
>> 24);
1536 locaData
[4*i
+1] = (Guchar
)(pos
>> 16);
1537 locaData
[4*i
+2] = (Guchar
)(pos
>> 8);
1538 locaData
[4*i
+3] = (Guchar
) pos
;
1540 locaData
[2*i
] = (Guchar
)(pos
>> 9);
1541 locaData
[2*i
+1] = (Guchar
)(pos
>> 1);
1545 // count the number of tables
1547 for (i
= 0; i
< nT42Tables
; ++i
) {
1548 if (t42Tables
[i
].required
||
1549 seekTable(t42Tables
[i
].tag
) >= 0) {
1553 vmtxTab
= NULL
; // make gcc happy
1554 advance
= 0; // make gcc happy
1555 if (needVerticalMetrics
) {
1556 needVhea
= seekTable("vhea") < 0;
1557 needVmtx
= seekTable("vmtx") < 0;
1558 if (needVhea
|| needVmtx
) {
1559 i
= seekTable("head");
1560 advance
= getU16BE(tables
[i
].offset
+ 18, &ok
); // units per em
1570 // construct the new table headers, including table checksums
1571 // (pad each table out to a multiple of 4 bytes)
1572 pos
= 12 + nNewTables
*16;
1574 for (i
= 0; i
< nT42Tables
; ++i
) {
1576 checksum
= 0; // make gcc happy
1577 if (i
== t42HeadTable
) {
1579 checksum
= computeTableChecksum(headData
, 54);
1580 } else if (i
== t42LocaTable
) {
1581 length
= (nGlyphs
+ 1) * (locaFmt
? 4 : 2);
1582 checksum
= computeTableChecksum(locaData
, length
);
1583 } else if (i
== t42GlyfTable
) {
1586 glyfPos
= tables
[seekTable("glyf")].offset
;
1587 for (j
= 0; j
< nGlyphs
; ++j
) {
1588 length
+= locaTable
[j
].len
;
1590 length
+= 4 - (length
& 3);
1592 if (checkRegion(glyfPos
+ locaTable
[j
].origOffset
, locaTable
[j
].len
)) {
1594 computeTableChecksum(file
+ glyfPos
+ locaTable
[j
].origOffset
,
1599 if ((j
= seekTable(t42Tables
[i
].tag
)) >= 0) {
1600 length
= tables
[j
].len
;
1601 if (checkRegion(tables
[j
].offset
, length
)) {
1602 checksum
= computeTableChecksum(file
+ tables
[j
].offset
, length
);
1604 } else if (needVerticalMetrics
&& i
== t42VheaTable
) {
1605 vheaTab
[10] = advance
/ 256; // max advance height
1606 vheaTab
[11] = advance
% 256;
1607 length
= sizeof(vheaTab
);
1608 checksum
= computeTableChecksum(vheaTab
, length
);
1609 } else if (needVerticalMetrics
&& i
== t42VmtxTable
) {
1610 length
= 4 + (nGlyphs
- 1) * 4;
1611 vmtxTab
= (Guchar
*)gmalloc(length
);
1612 vmtxTab
[0] = advance
/ 256;
1613 vmtxTab
[1] = advance
% 256;
1614 for (j
= 2; j
< length
; j
+= 2) {
1618 checksum
= computeTableChecksum(vmtxTab
, length
);
1619 } else if (t42Tables
[i
].required
) {
1620 //~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
1621 //~ t42Tables[i].tag);
1627 newTables
[k
].tag
= ((t42Tables
[i
].tag
[0] & 0xff) << 24) |
1628 ((t42Tables
[i
].tag
[1] & 0xff) << 16) |
1629 ((t42Tables
[i
].tag
[2] & 0xff) << 8) |
1630 (t42Tables
[i
].tag
[3] & 0xff);
1631 newTables
[k
].checksum
= checksum
;
1632 newTables
[k
].offset
= pos
;
1633 newTables
[k
].len
= length
;
1636 pos
+= 4 - (length
& 3);
1642 // construct the table directory
1643 tableDir
[0] = 0x00; // sfnt version
1647 tableDir
[4] = 0; // numTables
1648 tableDir
[5] = nNewTables
;
1649 tableDir
[6] = 0; // searchRange
1650 tableDir
[7] = (Guchar
)128;
1651 tableDir
[8] = 0; // entrySelector
1653 tableDir
[10] = 0; // rangeShift
1654 tableDir
[11] = (Guchar
)(16 * nNewTables
- 128);
1656 for (i
= 0; i
< nNewTables
; ++i
) {
1657 tableDir
[pos
] = (Guchar
)(newTables
[i
].tag
>> 24);
1658 tableDir
[pos
+ 1] = (Guchar
)(newTables
[i
].tag
>> 16);
1659 tableDir
[pos
+ 2] = (Guchar
)(newTables
[i
].tag
>> 8);
1660 tableDir
[pos
+ 3] = (Guchar
) newTables
[i
].tag
;
1661 tableDir
[pos
+ 4] = (Guchar
)(newTables
[i
].checksum
>> 24);
1662 tableDir
[pos
+ 5] = (Guchar
)(newTables
[i
].checksum
>> 16);
1663 tableDir
[pos
+ 6] = (Guchar
)(newTables
[i
].checksum
>> 8);
1664 tableDir
[pos
+ 7] = (Guchar
) newTables
[i
].checksum
;
1665 tableDir
[pos
+ 8] = (Guchar
)(newTables
[i
].offset
>> 24);
1666 tableDir
[pos
+ 9] = (Guchar
)(newTables
[i
].offset
>> 16);
1667 tableDir
[pos
+10] = (Guchar
)(newTables
[i
].offset
>> 8);
1668 tableDir
[pos
+11] = (Guchar
) newTables
[i
].offset
;
1669 tableDir
[pos
+12] = (Guchar
)(newTables
[i
].len
>> 24);
1670 tableDir
[pos
+13] = (Guchar
)(newTables
[i
].len
>> 16);
1671 tableDir
[pos
+14] = (Guchar
)(newTables
[i
].len
>> 8);
1672 tableDir
[pos
+15] = (Guchar
) newTables
[i
].len
;
1676 // compute the font checksum and store it in the head table
1677 checksum
= computeTableChecksum(tableDir
, 12 + nNewTables
*16);
1678 for (i
= 0; i
< nNewTables
; ++i
) {
1679 checksum
+= newTables
[i
].checksum
;
1681 checksum
= 0xb1b0afba - checksum
; // because the TrueType spec says so
1682 headData
[ 8] = (Guchar
)(checksum
>> 24);
1683 headData
[ 9] = (Guchar
)(checksum
>> 16);
1684 headData
[10] = (Guchar
)(checksum
>> 8);
1685 headData
[11] = (Guchar
) checksum
;
1687 // start the sfnts array
1689 (*outputFunc
)(outputStream
, "/", 1);
1690 (*outputFunc
)(outputStream
, name
->getCString(), name
->getLength());
1691 (*outputFunc
)(outputStream
, " [\n", 3);
1693 (*outputFunc
)(outputStream
, "/sfnts [\n", 9);
1696 // write the table directory
1697 dumpString(tableDir
, 12 + nNewTables
*16, outputFunc
, outputStream
);
1700 for (i
= 0; i
< nNewTables
; ++i
) {
1701 if (i
== t42HeadTable
) {
1702 dumpString(headData
, 54, outputFunc
, outputStream
);
1703 } else if (i
== t42LocaTable
) {
1704 length
= (nGlyphs
+ 1) * (locaFmt
? 4 : 2);
1705 dumpString(locaData
, length
, outputFunc
, outputStream
);
1706 } else if (i
== t42GlyfTable
) {
1707 glyfPos
= tables
[seekTable("glyf")].offset
;
1708 for (j
= 0; j
< nGlyphs
; ++j
) {
1709 if (locaTable
[j
].len
> 0 &&
1710 checkRegion(glyfPos
+ locaTable
[j
].origOffset
, locaTable
[j
].len
)) {
1711 dumpString(file
+ glyfPos
+ locaTable
[j
].origOffset
,
1712 locaTable
[j
].len
, outputFunc
, outputStream
);
1716 // length == 0 means the table is missing and the error was
1717 // already reported during the construction of the table
1719 if ((length
= newTables
[i
].len
) > 0) {
1720 if ((j
= seekTable(t42Tables
[i
].tag
)) >= 0 &&
1721 checkRegion(tables
[j
].offset
, tables
[j
].len
)) {
1722 dumpString(file
+ tables
[j
].offset
, tables
[j
].len
,
1723 outputFunc
, outputStream
);
1724 } else if (needVerticalMetrics
&& i
== t42VheaTable
) {
1725 dumpString(vheaTab
, length
, outputFunc
, outputStream
);
1726 } else if (needVerticalMetrics
&& i
== t42VmtxTable
) {
1727 dumpString(vmtxTab
, length
, outputFunc
, outputStream
);
1734 // end the sfnts array
1735 (*outputFunc
)(outputStream
, "] def\n", 6);
1741 void FoFiTrueType::dumpString(Guchar
*s
, int length
,
1742 FoFiOutputFunc outputFunc
,
1743 void *outputStream
) {
1747 (*outputFunc
)(outputStream
,"<", 1);
1748 for (i
= 0; i
< length
; i
+= 32) {
1749 for (j
= 0; j
< 32 && i
+j
< length
; ++j
) {
1750 buf
= GString::format("{0:02x}", s
[i
+j
] & 0xff);
1751 (*outputFunc
)(outputStream
, buf
->getCString(), buf
->getLength());
1754 if (i
% (65536 - 32) == 65536 - 64) {
1755 (*outputFunc
)(outputStream
, ">\n<", 3);
1756 } else if (i
+32 < length
) {
1757 (*outputFunc
)(outputStream
, "\n", 1);
1761 pad
= 4 - (length
& 3);
1762 for (i
= 0; i
< pad
; ++i
) {
1763 (*outputFunc
)(outputStream
, "00", 2);
1766 // add an extra zero byte because the Adobe Type 42 spec says so
1767 (*outputFunc
)(outputStream
, "00>\n", 4);
1770 Guint
FoFiTrueType::computeTableChecksum(Guchar
*data
, int length
) {
1771 Guint checksum
, word
;
1775 for (i
= 0; i
+3 < length
; i
+= 4) {
1776 word
= ((data
[i
] & 0xff) << 24) +
1777 ((data
[i
+1] & 0xff) << 16) +
1778 ((data
[i
+2] & 0xff) << 8) +
1785 switch (length
& 3) {
1787 word
|= (data
[i
+2] & 0xff) << 8;
1789 word
|= (data
[i
+1] & 0xff) << 16;
1791 word
|= (data
[i
] & 0xff) << 24;
1799 void FoFiTrueType::parse() {
1805 // look for a collection (TTC)
1806 topTag
= getU32BE(0, &parsedOk
);
1810 if (topTag
== ttcfTag
) {
1811 pos
= getU32BE(12, &parsedOk
);
1819 // check the sfnt version
1820 ver
= getU32BE(pos
, &parsedOk
);
1824 openTypeCFF
= ver
== 0x4f54544f; // 'OTTO'
1826 // read the table directory
1827 nTables
= getU16BE(pos
+ 4, &parsedOk
);
1831 tables
= (TrueTypeTable
*)gmallocn(nTables
, sizeof(TrueTypeTable
));
1833 for (i
= 0; i
< nTables
; ++i
) {
1834 tables
[i
].tag
= getU32BE(pos
, &parsedOk
);
1835 tables
[i
].checksum
= getU32BE(pos
+ 4, &parsedOk
);
1836 tables
[i
].offset
= (int)getU32BE(pos
+ 8, &parsedOk
);
1837 tables
[i
].len
= (int)getU32BE(pos
+ 12, &parsedOk
);
1838 if (tables
[i
].offset
+ tables
[i
].len
< tables
[i
].offset
||
1839 tables
[i
].offset
+ tables
[i
].len
> len
) {
1848 // check for tables that are required by both the TrueType spec and
1850 if (seekTable("head") < 0 ||
1851 seekTable("hhea") < 0 ||
1852 seekTable("maxp") < 0 ||
1853 seekTable("hmtx") < 0 ||
1854 (!openTypeCFF
&& seekTable("loca") < 0) ||
1855 (!openTypeCFF
&& seekTable("glyf") < 0) ||
1856 (openTypeCFF
&& seekTable("CFF ") < 0)) {
1862 if ((i
= seekTable("cmap")) >= 0) {
1863 pos
= tables
[i
].offset
+ 2;
1864 nCmaps
= getU16BE(pos
, &parsedOk
);
1869 cmaps
= (TrueTypeCmap
*)gmallocn(nCmaps
, sizeof(TrueTypeCmap
));
1870 for (j
= 0; j
< nCmaps
; ++j
) {
1871 cmaps
[j
].platform
= getU16BE(pos
, &parsedOk
);
1872 cmaps
[j
].encoding
= getU16BE(pos
+ 2, &parsedOk
);
1873 cmaps
[j
].offset
= tables
[i
].offset
+ getU32BE(pos
+ 4, &parsedOk
);
1875 cmaps
[j
].fmt
= getU16BE(cmaps
[j
].offset
, &parsedOk
);
1876 cmaps
[j
].len
= getU16BE(cmaps
[j
].offset
+ 2, &parsedOk
);
1885 // get the number of glyphs from the maxp table
1886 i
= seekTable("maxp");
1887 nGlyphs
= getU16BE(tables
[i
].offset
+ 4, &parsedOk
);
1892 // get the bbox and loca table format from the head table
1893 i
= seekTable("head");
1894 bbox
[0] = getS16BE(tables
[i
].offset
+ 36, &parsedOk
);
1895 bbox
[1] = getS16BE(tables
[i
].offset
+ 38, &parsedOk
);
1896 bbox
[2] = getS16BE(tables
[i
].offset
+ 40, &parsedOk
);
1897 bbox
[3] = getS16BE(tables
[i
].offset
+ 42, &parsedOk
);
1898 locaFmt
= getS16BE(tables
[i
].offset
+ 50, &parsedOk
);
1903 // make sure the loca table is sane (correct length and entries are
1906 i
= seekTable("loca");
1907 if (tables
[i
].len
< 0) {
1911 if (tables
[i
].len
< (nGlyphs
+ 1) * (locaFmt
? 4 : 2)) {
1912 nGlyphs
= tables
[i
].len
/ (locaFmt
? 4 : 2) - 1;
1914 for (j
= 0; j
<= nGlyphs
; ++j
) {
1916 pos
= (int)getU32BE(tables
[i
].offset
+ j
*4, &parsedOk
);
1918 pos
= getU16BE(tables
[i
].offset
+ j
*2, &parsedOk
);
1920 if (pos
< 0 || pos
> len
) {
1929 // read the post table
1933 void FoFiTrueType::readPostTable() {
1935 int tablePos
, postFmt
, stringIdx
, stringPos
;
1940 if ((i
= seekTable("post")) < 0) {
1943 tablePos
= tables
[i
].offset
;
1944 postFmt
= getU32BE(tablePos
, &ok
);
1948 if (postFmt
== 0x00010000) {
1949 nameToGID
= new GHash(gTrue
);
1950 for (i
= 0; i
< 258; ++i
) {
1951 nameToGID
->add(new GString(macGlyphNames
[i
]), i
);
1953 } else if (postFmt
== 0x00020000) {
1954 nameToGID
= new GHash(gTrue
);
1955 n
= getU16BE(tablePos
+ 32, &ok
);
1963 stringPos
= tablePos
+ 34 + 2*n
;
1964 for (i
= 0; i
< n
; ++i
) {
1965 j
= getU16BE(tablePos
+ 34 + 2*i
, &ok
);
1967 nameToGID
->removeInt((char *)macGlyphNames
[j
]);
1968 nameToGID
->add(new GString(macGlyphNames
[j
]), i
);
1971 if (j
!= stringIdx
) {
1972 for (stringIdx
= 0, stringPos
= tablePos
+ 34 + 2*n
;
1974 ++stringIdx
, stringPos
+= 1 + getU8(stringPos
, &ok
)) ;
1979 m
= getU8(stringPos
, &ok
);
1980 if (!ok
|| !checkRegion(stringPos
+ 1, m
)) {
1983 name
= new GString((char *)&file
[stringPos
+ 1], m
);
1984 nameToGID
->removeInt(name
);
1985 nameToGID
->add(name
, i
);
1990 } else if (postFmt
== 0x00028000) {
1991 nameToGID
= new GHash(gTrue
);
1992 for (i
= 0; i
< nGlyphs
; ++i
) {
1993 j
= getU8(tablePos
+ 32 + i
, &ok
);
1998 nameToGID
->removeInt((char *)macGlyphNames
[j
]);
1999 nameToGID
->add(new GString(macGlyphNames
[j
]), i
);
2013 int FoFiTrueType::seekTable(char *tag
) {
2017 tagI
= ((tag
[0] & 0xff) << 24) |
2018 ((tag
[1] & 0xff) << 16) |
2019 ((tag
[2] & 0xff) << 8) |
2021 for (i
= 0; i
< nTables
; ++i
) {
2022 if (tables
[i
].tag
== tagI
) {