source: trunk/poppler/mypoppler/fofi/FoFiTrueType.cc @ 250

Last change on this file since 250 was 250, checked in by Eugene Romanenko, 13 years ago

PDF plugin: poppler library updated to version 0.8.3

File size: 69.6 KB
Line 
1//========================================================================
2//
3// FoFiTrueType.cc
4//
5// Copyright 1999-2003 Glyph & Cog, LLC
6//
7//========================================================================
8
9#include <config.h>
10
11#ifdef USE_GCC_PRAGMAS
12#pragma implementation
13#endif
14
15#include <stdlib.h>
16#include <string.h>
17#include "goo/gtypes.h"
18#include "goo/gmem.h"
19#include "goo/GooString.h"
20#include "goo/GooHash.h"
21#include "FoFiType1C.h"
22#include "FoFiTrueType.h"
23
24//
25// Terminology
26// -----------
27//
28// character code = number used as an element of a text string
29//
30// character name = glyph name = name for a particular glyph within a
31//                  font
32//
33// glyph index = GID = position (within some internal table in the font)
34//               where the instructions to draw a particular glyph are
35//               stored
36//
37// Type 1 fonts
38// ------------
39//
40// Type 1 fonts contain:
41//
42// Encoding: array of glyph names, maps char codes to glyph names
43//
44//           Encoding[charCode] = charName
45//
46// CharStrings: dictionary of instructions, keyed by character names,
47//              maps character name to glyph data
48//
49//              CharStrings[charName] = glyphData
50//
51// TrueType fonts
52// --------------
53//
54// TrueType fonts contain:
55//
56// 'cmap' table: mapping from character code to glyph index; there may
57//               be multiple cmaps in a TrueType font
58//
59//               cmap[charCode] = gid
60//
61// 'post' table: mapping from glyph index to glyph name
62//
63//               post[gid] = glyphName
64//
65// Type 42 fonts
66// -------------
67//
68// Type 42 fonts contain:
69//
70// Encoding: array of glyph names, maps char codes to glyph names
71//
72//           Encoding[charCode] = charName
73//
74// CharStrings: dictionary of glyph indexes, keyed by character names,
75//              maps character name to glyph index
76//
77//              CharStrings[charName] = gid
78//
79
80//------------------------------------------------------------------------
81
82#define ttcfTag 0x74746366
83
84//------------------------------------------------------------------------
85
86struct TrueTypeTable {
87  Guint tag;
88  Guint checksum;
89  int offset;
90  int origOffset;
91  int len;
92};
93
94struct TrueTypeCmap {
95  int platform;
96  int encoding;
97  int offset;
98  int len;
99  int fmt;
100};
101
102struct TrueTypeLoca {
103  int idx;
104  int origOffset;
105  int newOffset;
106  int len;
107};
108
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
118#define vrt2Tag 0x76727432
119#define vertTag 0x76657274
120
121static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) {
122  TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
123  TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
124
125  if (loca1->origOffset == loca2->origOffset) {
126    return loca1->idx - loca2->idx;
127  }
128  return loca1->origOffset - loca2->origOffset;
129}
130
131static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) {
132  TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
133  TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
134
135  return loca1->idx - loca2->idx;
136}
137
138static int cmpTrueTypeTableTag(const void *p1, const void *p2) {
139  TrueTypeTable *tab1 = (TrueTypeTable *)p1;
140  TrueTypeTable *tab2 = (TrueTypeTable *)p2;
141
142  return (int)tab1->tag - (int)tab2->tag;
143}
144
145//------------------------------------------------------------------------
146
147struct T42Table {
148  char *tag;                    // 4-byte tag
149  GBool required;               // required by the TrueType spec?
150};
151
152// TrueType tables to be embedded in Type 42 fonts.
153// NB: the table names must be in alphabetical order here.
154#define nT42Tables 11
155static T42Table t42Tables[nT42Tables] = {
156  { "cvt ", gTrue  },
157  { "fpgm", gTrue  },
158  { "glyf", gTrue  },
159  { "head", gTrue  },
160  { "hhea", gTrue  },
161  { "hmtx", gTrue  },
162  { "loca", gTrue  },
163  { "maxp", gTrue  },
164  { "prep", gTrue  },
165  { "vhea", gFalse },
166  { "vmtx", gFalse }
167};
168#define t42HeadTable  3
169#define t42LocaTable  6
170#define t42GlyfTable  2
171#define t42VheaTable  9
172#define t42VmtxTable 10
173
174//------------------------------------------------------------------------
175
176// Glyph names in some arbitrary standard order that Apple uses for
177// their TrueType fonts.
178static char *macGlyphNames[258] = {
179  ".notdef",        "null",           "CR",             "space",
180  "exclam",         "quotedbl",       "numbersign",     "dollar",
181  "percent",        "ampersand",      "quotesingle",    "parenleft",
182  "parenright",     "asterisk",       "plus",           "comma",
183  "hyphen",         "period",         "slash",          "zero",
184  "one",            "two",            "three",          "four",
185  "five",           "six",            "seven",          "eight",
186  "nine",           "colon",          "semicolon",      "less",
187  "equal",          "greater",        "question",       "at",
188  "A",              "B",              "C",              "D",
189  "E",              "F",              "G",              "H",
190  "I",              "J",              "K",              "L",
191  "M",              "N",              "O",              "P",
192  "Q",              "R",              "S",              "T",
193  "U",              "V",              "W",              "X",
194  "Y",              "Z",              "bracketleft",    "backslash",
195  "bracketright",   "asciicircum",    "underscore",     "grave",
196  "a",              "b",              "c",              "d",
197  "e",              "f",              "g",              "h",
198  "i",              "j",              "k",              "l",
199  "m",              "n",              "o",              "p",
200  "q",              "r",              "s",              "t",
201  "u",              "v",              "w",              "x",
202  "y",              "z",              "braceleft",      "bar",
203  "braceright",     "asciitilde",     "Adieresis",      "Aring",
204  "Ccedilla",       "Eacute",         "Ntilde",         "Odieresis",
205  "Udieresis",      "aacute",         "agrave",         "acircumflex",
206  "adieresis",      "atilde",         "aring",          "ccedilla",
207  "eacute",         "egrave",         "ecircumflex",    "edieresis",
208  "iacute",         "igrave",         "icircumflex",    "idieresis",
209  "ntilde",         "oacute",         "ograve",         "ocircumflex",
210  "odieresis",      "otilde",         "uacute",         "ugrave",
211  "ucircumflex",    "udieresis",      "dagger",         "degree",
212  "cent",           "sterling",       "section",        "bullet",
213  "paragraph",      "germandbls",     "registered",     "copyright",
214  "trademark",      "acute",          "dieresis",       "notequal",
215  "AE",             "Oslash",         "infinity",       "plusminus",
216  "lessequal",      "greaterequal",   "yen",            "mu1",
217  "partialdiff",    "summation",      "product",        "pi",
218  "integral",       "ordfeminine",    "ordmasculine",   "Ohm",
219  "ae",             "oslash",         "questiondown",   "exclamdown",
220  "logicalnot",     "radical",        "florin",         "approxequal",
221  "increment",      "guillemotleft",  "guillemotright", "ellipsis",
222  "nbspace",        "Agrave",         "Atilde",         "Otilde",
223  "OE",             "oe",             "endash",         "emdash",
224  "quotedblleft",   "quotedblright",  "quoteleft",      "quoteright",
225  "divide",         "lozenge",        "ydieresis",      "Ydieresis",
226  "fraction",       "currency",       "guilsinglleft",  "guilsinglright",
227  "fi",             "fl",             "daggerdbl",      "periodcentered",
228  "quotesinglbase", "quotedblbase",   "perthousand",    "Acircumflex",
229  "Ecircumflex",    "Aacute",         "Edieresis",      "Egrave",
230  "Iacute",         "Icircumflex",    "Idieresis",      "Igrave",
231  "Oacute",         "Ocircumflex",    "applelogo",      "Ograve",
232  "Uacute",         "Ucircumflex",    "Ugrave",         "dotlessi",
233  "circumflex",     "tilde",          "overscore",      "breve",
234  "dotaccent",      "ring",           "cedilla",        "hungarumlaut",
235  "ogonek",         "caron",          "Lslash",         "lslash",
236  "Scaron",         "scaron",         "Zcaron",         "zcaron",
237  "brokenbar",      "Eth",            "eth",            "Yacute",
238  "yacute",         "Thorn",          "thorn",          "minus",
239  "multiply",       "onesuperior",    "twosuperior",    "threesuperior",
240  "onehalf",        "onequarter",     "threequarters",  "franc",
241  "Gbreve",         "gbreve",         "Idot",           "Scedilla",
242  "scedilla",       "Cacute",         "cacute",         "Ccaron",
243  "ccaron",         "dmacron"
244};
245
246//------------------------------------------------------------------------
247// FoFiTrueType
248//------------------------------------------------------------------------
249
250FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA, int faceIndexA) {
251  FoFiTrueType *ff;
252
253  ff = new FoFiTrueType(fileA, lenA, gFalse, faceIndexA);
254  if (!ff->parsedOk) {
255    delete ff;
256    return NULL;
257  }
258  return ff;
259}
260
261FoFiTrueType *FoFiTrueType::load(char *fileName, int faceIndexA) {
262  FoFiTrueType *ff;
263  char *fileA;
264  int lenA;
265
266  if (!(fileA = FoFiBase::readFile(fileName, &lenA))) {
267    return NULL;
268  }
269  ff = new FoFiTrueType(fileA, lenA, gTrue, faceIndexA);
270  if (!ff->parsedOk) {
271    delete ff;
272    return NULL;
273  }
274  return ff;
275}
276
277FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA):
278  FoFiBase(fileA, lenA, freeFileDataA)
279{
280  tables = NULL;
281  nTables = 0;
282  cmaps = NULL;
283  nCmaps = 0;
284  nameToGID = NULL;
285  parsedOk = gFalse;
286  faceIndex = faceIndexA;
287  gsubFeatureTable = 0;
288  gsubLookupList = 0;
289
290  parse();
291}
292
293FoFiTrueType::~FoFiTrueType() {
294  gfree(tables);
295  gfree(cmaps);
296  if (nameToGID) {
297    delete nameToGID;
298  }
299}
300
301int FoFiTrueType::getNumCmaps() {
302  return nCmaps;
303}
304
305int FoFiTrueType::getCmapPlatform(int i) {
306  return cmaps[i].platform;
307}
308
309int FoFiTrueType::getCmapEncoding(int i) {
310  return cmaps[i].encoding;
311}
312
313int FoFiTrueType::findCmap(int platform, int encoding) {
314  int i;
315
316  for (i = 0; i < nCmaps; ++i) {
317    if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) {
318      return i;
319    }
320  }
321  return -1;
322}
323
324Gushort FoFiTrueType::mapCodeToGID(int i, Guint c) {
325  Gushort gid;
326  Guint segCnt, segEnd, segStart, segDelta, segOffset;
327  Guint cmapFirst, cmapLen;
328  int pos, a, b, m;
329  GBool ok;
330
331  if (i < 0 || i >= nCmaps) {
332    return 0;
333  }
334  ok = gTrue;
335  pos = cmaps[i].offset;
336  switch (cmaps[i].fmt) {
337  case 0:
338    if (c >= cmaps[i].len - 6) {
339      return 0;
340    }
341    gid = getU8(cmaps[i].offset + 6 + c, &ok);
342    break;
343  case 4:
344    segCnt = getU16BE(pos + 6, &ok) / 2;
345    a = -1;
346    b = segCnt - 1;
347    segEnd = getU16BE(pos + 14 + 2*b, &ok);
348    if (c > segEnd) {
349      // malformed font -- the TrueType spec requires the last segEnd
350      // to be 0xffff
351      return 0;
352    }
353    // invariant: seg[a].end < code <= seg[b].end
354    while (b - a > 1 && ok) {
355      m = (a + b) / 2;
356      segEnd = getU16BE(pos + 14 + 2*m, &ok);
357      if (segEnd < c) {
358        a = m;
359      } else {
360        b = m;
361      }
362    }
363    segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok);
364    segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok);
365    segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok);
366    if (c < segStart) {
367      return 0;
368    }
369    if (segOffset == 0) {
370      gid = (c + segDelta) & 0xffff;
371    } else {
372      gid = getU16BE(pos + 16 + 6*segCnt + 2*b +
373                       segOffset + 2 * (c - segStart), &ok);
374      if (gid != 0) {
375        gid = (gid + segDelta) & 0xffff;
376      }
377    }
378    break;
379  case 6:
380    cmapFirst = getU16BE(pos + 6, &ok);
381    cmapLen = getU16BE(pos + 8, &ok);
382    if (c < cmapFirst || c >= cmapFirst + cmapLen) {
383      return 0;
384    }
385    gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok);
386    break;
387  case 12:
388    segCnt = getU32BE(pos + 12, &ok);
389    a = -1;
390    b = segCnt - 1;
391    segEnd = getU32BE(pos + 16 + 12*b+4, &ok);
392    if (c > segEnd) {
393      return 0;
394    }
395    // invariant: seg[a].end < code <= seg[b].end
396    while (b - a > 1 && ok) {
397      m = (a + b) / 2;
398      segEnd = getU32BE(pos + 16 + 12*m+4, &ok);
399      if (segEnd < c) {
400        a = m;
401      } else {
402        b = m;
403      }
404    }
405    segStart = getU32BE(pos + 16 + 12*b, &ok);
406    segDelta = getU32BE(pos + 16 + 12*b+8, &ok);
407    if (c < segStart) {
408      return 0;
409    }
410    gid = segDelta + (c-segStart);
411    break;
412  default:
413    return 0;
414  }
415  if (!ok) {
416    return 0;
417  }
418  return gid;
419}
420
421int FoFiTrueType::mapNameToGID(char *name) {
422  if (!nameToGID) {
423    return 0;
424  }
425  return nameToGID->lookupInt(name);
426}
427
428Gushort *FoFiTrueType::getCIDToGIDMap(int *nCIDs) {
429  FoFiType1C *ff;
430  Gushort *map;
431  int i;
432
433  *nCIDs = 0;
434  if (!openTypeCFF) {
435    return NULL;
436  }
437  i = seekTable("CFF ");
438  if (!checkRegion(tables[i].offset, tables[i].len)) {
439    return NULL;
440  }
441  if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
442                              tables[i].len))) {
443    return NULL;
444  }
445  map = ff->getCIDToGIDMap(nCIDs);
446  delete ff;
447  return map;
448}
449
450int FoFiTrueType::getEmbeddingRights() {
451  int i, fsType;
452  GBool ok;
453
454  if ((i = seekTable("OS/2")) < 0) {
455    return 4;
456  }
457  ok = gTrue;
458  fsType = getU16BE(tables[i].offset + 8, &ok);
459  if (!ok) {
460    return 4;
461  }
462  if (fsType & 0x0008) {
463    return 2;
464  }
465  if (fsType & 0x0004) {
466    return 1;
467  }
468  if (fsType & 0x0002) {
469    return 0;
470  }
471  return 3;
472}
473
474void FoFiTrueType::convertToType42(char *psName, char **encoding,
475                                   Gushort *codeToGID,
476                                   FoFiOutputFunc outputFunc,
477                                   void *outputStream) {
478  GooString *buf;
479  GBool ok;
480
481  if (openTypeCFF) {
482    return;
483  }
484
485  // write the header
486  ok = gTrue;
487  buf = GooString::format("%!PS-TrueTypeFont-{0:2g}\n",
488                        (double)getS32BE(0, &ok) / 65536.0);
489  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
490  delete buf;
491
492  // begin the font dictionary
493  (*outputFunc)(outputStream, "10 dict begin\n", 14);
494  (*outputFunc)(outputStream, "/FontName /", 11);
495  (*outputFunc)(outputStream, psName, strlen(psName));
496  (*outputFunc)(outputStream, " def\n", 5);
497  (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
498  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
499  buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
500                        bbox[0], bbox[1], bbox[2], bbox[3]);
501  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
502  delete buf;
503  (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
504
505  // write the guts of the dictionary
506  cvtEncoding(encoding, outputFunc, outputStream);
507  cvtCharStrings(encoding, codeToGID, outputFunc, outputStream);
508  cvtSfnts(outputFunc, outputStream, NULL, gFalse);
509
510  // end the dictionary and define the font
511  (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
512}
513
514void FoFiTrueType::convertToType1(char *psName, char **newEncoding,
515                                  GBool ascii, FoFiOutputFunc outputFunc,
516                                  void *outputStream) {
517  FoFiType1C *ff;
518  int i;
519
520  if (!openTypeCFF) {
521    return;
522  }
523  i = seekTable("CFF ");
524  if (!checkRegion(tables[i].offset, tables[i].len)) {
525    return;
526  }
527  if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
528                              tables[i].len))) {
529    return;
530  }
531  ff->convertToType1(psName, newEncoding, ascii, outputFunc, outputStream);
532  delete ff;
533}
534
535void FoFiTrueType::convertToCIDType2(char *psName,
536                                     Gushort *cidMap, int nCIDs,
537                                     GBool needVerticalMetrics,
538                                     FoFiOutputFunc outputFunc,
539                                     void *outputStream) {
540  GooString *buf;
541  Gushort cid;
542  GBool ok;
543  int i, j, k;
544
545  if (openTypeCFF) {
546    return;
547  }
548
549  // write the header
550  ok = gTrue;
551  buf = GooString::format("%!PS-TrueTypeFont-{0:2g}\n",
552                        (double)getS32BE(0, &ok) / 65536.0);
553  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
554  delete buf;
555
556  // begin the font dictionary
557  (*outputFunc)(outputStream, "20 dict begin\n", 14);
558  (*outputFunc)(outputStream, "/CIDFontName /", 14);
559  (*outputFunc)(outputStream, psName, strlen(psName));
560  (*outputFunc)(outputStream, " def\n", 5);
561  (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19);
562  (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
563  (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
564  (*outputFunc)(outputStream, "  /Registry (Adobe) def\n", 24);
565  (*outputFunc)(outputStream, "  /Ordering (Identity) def\n", 27);
566  (*outputFunc)(outputStream, "  /Supplement 0 def\n", 20);
567  (*outputFunc)(outputStream, "  end def\n", 10);
568  (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
569  if (cidMap) {
570    buf = GooString::format("/CIDCount {0:d} def\n", nCIDs);
571    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
572    delete buf;
573    if (nCIDs > 32767) {
574      (*outputFunc)(outputStream, "/CIDMap [", 9);
575      for (i = 0; i < nCIDs; i += 32768 - 16) {
576        (*outputFunc)(outputStream, "<\n", 2);
577        for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
578          (*outputFunc)(outputStream, "  ", 2);
579          for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
580            cid = cidMap[i+j+k];
581            buf = GooString::format("{0:02x}{1:02x}",
582                                  (cid >> 8) & 0xff, cid & 0xff);
583            (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
584            delete buf;
585          }
586          (*outputFunc)(outputStream, "\n", 1);
587        }
588        (*outputFunc)(outputStream, "  >", 3);
589      }
590      (*outputFunc)(outputStream, "\n", 1);
591      (*outputFunc)(outputStream, "] def\n", 6);
592    } else {
593      (*outputFunc)(outputStream, "/CIDMap <\n", 10);
594      for (i = 0; i < nCIDs; i += 16) {
595        (*outputFunc)(outputStream, "  ", 2);
596        for (j = 0; j < 16 && i+j < nCIDs; ++j) {
597          cid = cidMap[i+j];
598          buf = GooString::format("{0:02x}{1:02x}",
599                                (cid >> 8) & 0xff, cid & 0xff);
600          (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
601          delete buf;
602        }
603        (*outputFunc)(outputStream, "\n", 1);
604      }
605      (*outputFunc)(outputStream, "> def\n", 6);
606    }
607  } else {
608    // direct mapping - just fill the string(s) with s[i]=i
609    buf = GooString::format("/CIDCount {0:d} def\n", nGlyphs);
610    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
611    delete buf;
612    if (nGlyphs > 32767) {
613      (*outputFunc)(outputStream, "/CIDMap [\n", 10);
614      for (i = 0; i < nGlyphs; i += 32767) {
615        j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
616        buf = GooString::format("  {0:d} string 0 1 {1:d} {{\n", 2 * j, j - 1);
617        (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
618        delete buf;
619        buf = GooString::format("    2 copy dup 2 mul exch {0:d} add -8 bitshift put\n",
620                              i);
621        (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
622        delete buf;
623        buf = GooString::format("    1 index exch dup 2 mul 1 add exch {0:d} add"
624                              " 255 and put\n", i);
625        (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
626        delete buf;
627        (*outputFunc)(outputStream, "  } for\n", 8);
628      }
629      (*outputFunc)(outputStream, "] def\n", 6);
630    } else {
631      buf = GooString::format("/CIDMap {0:d} string\n", 2 * nGlyphs);
632      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
633      delete buf;
634      buf = GooString::format("  0 1 {0:d} {{\n", nGlyphs - 1);
635      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
636      delete buf;
637      (*outputFunc)(outputStream,
638                    "    2 copy dup 2 mul exch -8 bitshift put\n", 42);
639      (*outputFunc)(outputStream,
640                    "    1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
641      (*outputFunc)(outputStream, "  } for\n", 8);
642      (*outputFunc)(outputStream, "def\n", 4);
643    }
644  }
645  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
646  buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
647                        bbox[0], bbox[1], bbox[2], bbox[3]);
648  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
649  delete buf;
650  (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
651  (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
652  (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
653  (*outputFunc)(outputStream, "  /.notdef 0 def\n", 17);
654  (*outputFunc)(outputStream, "  end readonly def\n", 19);
655
656  // write the guts of the dictionary
657  cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics);
658
659  // end the dictionary and define the font
660  (*outputFunc)(outputStream,
661                "CIDFontName currentdict end /CIDFont defineresource pop\n",
662                56);
663}
664
665void FoFiTrueType::convertToCIDType0(char *psName,
666                                     FoFiOutputFunc outputFunc,
667                                     void *outputStream) {
668  FoFiType1C *ff;
669  int i;
670
671  if (!openTypeCFF) {
672    return;
673  }
674  i = seekTable("CFF ");
675  if (!checkRegion(tables[i].offset, tables[i].len)) {
676    return;
677  }
678  if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
679                              tables[i].len))) {
680    return;
681  }
682  ff->convertToCIDType0(psName, outputFunc, outputStream);
683  delete ff;
684}
685
686void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
687                                  GBool needVerticalMetrics,
688                                  FoFiOutputFunc outputFunc,
689                                  void *outputStream) {
690  GooString *buf;
691  GooString *sfntsName;
692  int n, i, j;
693
694  if (openTypeCFF) {
695    return;
696  }
697
698  // write the Type 42 sfnts array
699  sfntsName = (new GooString(psName))->append("_sfnts");
700  cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics);
701  delete sfntsName;
702
703  // write the descendant Type 42 fonts
704  n = cidMap ? nCIDs : nGlyphs;
705  for (i = 0; i < n; i += 256) {
706    (*outputFunc)(outputStream, "10 dict begin\n", 14);
707    (*outputFunc)(outputStream, "/FontName /", 11);
708    (*outputFunc)(outputStream, psName, strlen(psName));
709    buf = GooString::format("_{0:02x} def\n", i >> 8);
710    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
711    delete buf;
712    (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
713    (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
714    buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
715                          bbox[0], bbox[1], bbox[2], bbox[3]);
716    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
717    delete buf;
718    (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
719    (*outputFunc)(outputStream, "/sfnts ", 7);
720    (*outputFunc)(outputStream, psName, strlen(psName));
721    (*outputFunc)(outputStream, "_sfnts def\n", 11);
722    (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
723    for (j = 0; j < 256 && i+j < n; ++j) {
724      buf = GooString::format("dup {0:d} /c{1:02x} put\n", j, j);
725      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
726      delete buf;
727    }
728    (*outputFunc)(outputStream, "readonly def\n", 13);
729    (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
730    (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
731    for (j = 0; j < 256 && i+j < n; ++j) {
732      buf = GooString::format("/c{0:02x} {1:d} def\n",
733                            j, cidMap ? cidMap[i+j] : i+j);
734      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
735      delete buf;
736    }
737    (*outputFunc)(outputStream, "end readonly def\n", 17);
738    (*outputFunc)(outputStream,
739                  "FontName currentdict end definefont pop\n", 40);
740  }
741
742  // write the Type 0 parent font
743  (*outputFunc)(outputStream, "16 dict begin\n", 14);
744  (*outputFunc)(outputStream, "/FontName /", 11);
745  (*outputFunc)(outputStream, psName, strlen(psName));
746  (*outputFunc)(outputStream, " def\n", 5);
747  (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
748  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
749  (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
750  (*outputFunc)(outputStream, "/Encoding [\n", 12);
751  for (i = 0; i < n; i += 256) {
752    buf = GooString::format("{0:d}\n", i >> 8);
753    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
754    delete buf;
755  }
756  (*outputFunc)(outputStream, "] def\n", 6);
757  (*outputFunc)(outputStream, "/FDepVector [\n", 14);
758  for (i = 0; i < n; i += 256) {
759    (*outputFunc)(outputStream, "/", 1);
760    (*outputFunc)(outputStream, psName, strlen(psName));
761    buf = GooString::format("_{0:02x} findfont\n", i >> 8);
762    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
763    delete buf;
764  }
765  (*outputFunc)(outputStream, "] def\n", 6);
766  (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
767}
768
769void FoFiTrueType::convertToType0(char *psName,
770                                  FoFiOutputFunc outputFunc,
771                                  void *outputStream) {
772  FoFiType1C *ff;
773  int i;
774
775  if (!openTypeCFF) {
776    return;
777  }
778  i = seekTable("CFF ");
779  if (!checkRegion(tables[i].offset, tables[i].len)) {
780    return;
781  }
782  if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
783                              tables[i].len))) {
784    return;
785  }
786  ff->convertToType0(psName, outputFunc, outputStream);
787  delete ff;
788}
789
790void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
791                            void *outputStream, char *name,
792                            Gushort *codeToGID) {
793  // this substitute cmap table maps char codes 0000-ffff directly to
794  // glyphs 0000-ffff
795  static char cmapTab[36] = {
796    0, 0,                       // table version number
797    0, 1,                       // number of encoding tables
798    0, 1,                       // platform ID
799    0, 0,                       // encoding ID
800    0, 0, 0, 12,                // offset of subtable
801    0, 4,                       // subtable format
802    0, 24,                      // subtable length
803    0, 0,                       // subtable version
804    0, 2,                       // segment count * 2
805    0, 2,                       // 2 * 2 ^ floor(log2(segCount))
806    0, 0,                       // floor(log2(segCount))
807    0, 0,                       // 2*segCount - 2*2^floor(log2(segCount))
808    (char)0xff, (char)0xff,     // endCount[0]
809    0, 0,                       // reserved
810    0, 0,                       // startCount[0]
811    0, 0,                       // idDelta[0]
812    0, 0                        // pad to a mulitple of four bytes
813  };
814  static char nameTab[8] = {
815    0, 0,                       // format
816    0, 0,                       // number of name records
817    0, 6,                       // offset to start of string storage
818    0, 0                        // pad to multiple of four bytes
819  };
820  static char postTab[32] = {
821    0, 1, 0, 0,                 // format
822    0, 0, 0, 0,                 // italic angle
823    0, 0,                       // underline position
824    0, 0,                       // underline thickness
825    0, 0, 0, 0,                 // fixed pitch
826    0, 0, 0, 0,                 // min Type 42 memory
827    0, 0, 0, 0,                 // max Type 42 memory
828    0, 0, 0, 0,                 // min Type 1 memory
829    0, 0, 0, 0                  // max Type 1 memory
830  };
831  static char os2Tab[86] = {
832    0, 1,                       // version
833    0, 1,                       // xAvgCharWidth
834    0, 0,                       // usWeightClass
835    0, 0,                       // usWidthClass
836    0, 0,                       // fsType
837    0, 0,                       // ySubscriptXSize
838    0, 0,                       // ySubscriptYSize
839    0, 0,                       // ySubscriptXOffset
840    0, 0,                       // ySubscriptYOffset
841    0, 0,                       // ySuperscriptXSize
842    0, 0,                       // ySuperscriptYSize
843    0, 0,                       // ySuperscriptXOffset
844    0, 0,                       // ySuperscriptYOffset
845    0, 0,                       // yStrikeoutSize
846    0, 0,                       // yStrikeoutPosition
847    0, 0,                       // sFamilyClass
848    0, 0, 0, 0, 0,              // panose
849    0, 0, 0, 0, 0,
850    0, 0, 0, 0,                 // ulUnicodeRange1
851    0, 0, 0, 0,                 // ulUnicodeRange2
852    0, 0, 0, 0,                 // ulUnicodeRange3
853    0, 0, 0, 0,                 // ulUnicodeRange4
854    0, 0, 0, 0,                 // achVendID
855    0, 0,                       // fsSelection
856    0, 0,                       // usFirstCharIndex
857    0, 0,                       // usLastCharIndex
858    0, 0,                       // sTypoAscender
859    0, 0,                       // sTypoDescender
860    0, 0,                       // sTypoLineGap
861    0, 0,                       // usWinAscent
862    0, 0,                       // usWinDescent
863    0, 0, 0, 0,                 // ulCodePageRange1
864    0, 0, 0, 0                  // ulCodePageRange2
865  };
866  GBool missingCmap, missingName, missingPost, missingOS2;
867  GBool unsortedLoca, badCmapLen, abbrevHMTX;
868  int nZeroLengthTables;
869  int nHMetrics, advWidth, lsb;
870  TrueTypeLoca *locaTable;
871  TrueTypeTable *newTables;
872  char *newNameTab, *newCmapTab, *newHHEATab, *newHMTXTab;
873  int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next;
874  int newHHEALen, newHMTXLen;
875  Guint locaChecksum, glyfChecksum, fileChecksum;
876  char *tableDir;
877  char locaBuf[4], checksumBuf[4];
878  GBool ok;
879  Guint t;
880  int pos, i, j, k, n;
881
882  if (openTypeCFF) {
883    return;
884  }
885
886  // check for missing tables
887  // (Note: if the OS/2 table is missing, the Microsoft PCL5 driver
888  // will embed a PCL TrueType font with the pitch field set to zero,
889  // which apparently causes divide-by-zero errors.  As far as I can
890  // tell, the only important field in the OS/2 table is
891  // xAvgCharWidth.)
892  missingCmap = (cmapIdx = seekTable("cmap")) < 0;
893  missingName = seekTable("name") < 0;
894  missingPost = seekTable("post") < 0;
895  missingOS2 = seekTable("OS/2") < 0;
896
897  // read the loca table, check to see if it's sorted
898  locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
899  unsortedLoca = gFalse;
900  i = seekTable("loca");
901  pos = tables[i].offset;
902  ok = gTrue;
903  for (i = 0; i <= nGlyphs; ++i) {
904    if (locaFmt) {
905      locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
906    } else {
907      locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
908    }
909    if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) {
910      unsortedLoca = gTrue;
911    }
912    // glyph descriptions must be at least 12 bytes long (nContours,
913    // xMin, yMin, xMax, yMax, instructionLength - two bytes each);
914    // invalid glyph descriptions (even if they're never used) make
915    // Windows choke, so we work around that problem here (ideally,
916    // this would parse the glyph descriptions in the glyf table and
917    // remove any that were invalid, but this quick test is a decent
918    // start)
919    if (i > 0 &&
920        locaTable[i].origOffset - locaTable[i-1].origOffset > 0 &&
921        locaTable[i].origOffset - locaTable[i-1].origOffset < 12) {
922      locaTable[i-1].origOffset = locaTable[i].origOffset;
923      unsortedLoca = gTrue;
924    }
925    locaTable[i].idx = i;
926  }
927
928  // check for zero-length tables
929  nZeroLengthTables = 0;
930  for (i = 0; i < nTables; ++i) {
931    if (tables[i].len == 0) {
932      ++nZeroLengthTables;
933    }
934  }
935
936  // check for an incorrect cmap table length
937  badCmapLen = gFalse;
938  cmapLen = 0; // make gcc happy
939  if (!missingCmap) {
940    if (nCmaps > 0) {
941      cmapLen = cmaps[0].offset + cmaps[0].len;
942      for (i = 1; i < nCmaps; ++i) {
943        if (cmaps[i].offset + cmaps[i].len > cmapLen) {
944          cmapLen = cmaps[i].offset + cmaps[i].len;
945        }
946      }
947    }
948    cmapLen -= tables[cmapIdx].offset;
949    if (cmapLen > tables[cmapIdx].len) {
950      badCmapLen = gTrue;
951    }
952  }
953
954  // check for an abbreviated hmtx table (this is completely legal,
955  // but confuses the Microsoft PCL5 printer driver, which generates
956  // embedded fonts with the pitch field set to zero)
957  i = seekTable("hhea");
958  nHMetrics = getU16BE(tables[i].offset + 34, &ok);
959  abbrevHMTX = nHMetrics < nGlyphs;
960
961  // if nothing is broken, just write the TTF file as is
962  if (!missingCmap && !missingName && !missingPost && !missingOS2 &&
963      !unsortedLoca && !badCmapLen && !abbrevHMTX && nZeroLengthTables == 0 &&
964      !name && !codeToGID) {
965    (*outputFunc)(outputStream, (char *)file, len);
966    goto done1;
967  }
968
969  // sort the 'loca' table: some (non-compliant) fonts have
970  // out-of-order loca tables; in order to correctly handle the case
971  // where (compliant) fonts have empty entries in the middle of the
972  // table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
973  // and idx as its secondary key (ensuring that adjacent entries with
974  // the same pos value remain in the same order)
975  glyfLen = 0; // make gcc happy
976  if (unsortedLoca) {
977    qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
978          &cmpTrueTypeLocaOffset);
979    for (i = 0; i < nGlyphs; ++i) {
980      locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
981    }
982    locaTable[nGlyphs].len = 0;
983    qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
984          &cmpTrueTypeLocaIdx);
985    pos = 0;
986    for (i = 0; i <= nGlyphs; ++i) {
987      locaTable[i].newOffset = pos;
988      pos += locaTable[i].len;
989      if (pos & 3) {
990        pos += 4 - (pos & 3);
991      }
992    }
993    glyfLen = pos;
994  }
995
996  // compute checksums for the loca and glyf tables
997  locaChecksum = glyfChecksum = 0;
998  if (unsortedLoca) {
999    if (locaFmt) {
1000      for (j = 0; j <= nGlyphs; ++j) {
1001        locaChecksum += locaTable[j].newOffset;
1002      }
1003    } else {
1004      for (j = 0; j <= nGlyphs; j += 2) {
1005        locaChecksum += locaTable[j].newOffset << 16;
1006        if (j + 1 <= nGlyphs) {
1007          locaChecksum += locaTable[j+1].newOffset;
1008        }
1009      }
1010    }
1011    pos = tables[seekTable("glyf")].offset;
1012    for (j = 0; j < nGlyphs; ++j) {
1013      n = locaTable[j].len;
1014      if (n > 0) {
1015        k = locaTable[j].origOffset;
1016        if (checkRegion(pos + k, n)) {
1017          glyfChecksum += computeTableChecksum(file + pos + k, n);
1018        }
1019      }
1020    }
1021  }
1022
1023  // construct the new name table
1024  if (name) {
1025    n = strlen(name);
1026    newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3;
1027    newNameTab = (char *)gmalloc(newNameLen);
1028    memset(newNameTab, 0, newNameLen);
1029    newNameTab[0] = 0;          // format selector
1030    newNameTab[1] = 0;
1031    newNameTab[2] = 0;          // number of name records
1032    newNameTab[3] = 4;
1033    newNameTab[4] = 0;          // offset to start of string storage
1034    newNameTab[5] = 6 + 4*12;
1035    next = 0;
1036    for (i = 0; i < 4; ++i) {
1037      newNameTab[6 + i*12 + 0] = 0;     // platform ID = Microsoft
1038      newNameTab[6 + i*12 + 1] = 3;
1039      newNameTab[6 + i*12 + 2] = 0;     // encoding ID = Unicode
1040      newNameTab[6 + i*12 + 3] = 1;
1041      newNameTab[6 + i*12 + 4] = 0x04;  // language ID = American English
1042      newNameTab[6 + i*12 + 5] = 0x09;
1043      newNameTab[6 + i*12 + 6] = 0;     // name ID
1044      newNameTab[6 + i*12 + 7] = i + 1;
1045      newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length
1046      newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff);
1047      newNameTab[6 + i*12 + 10] = next >> 8;                // string offset
1048      newNameTab[6 + i*12 + 11] = next & 0xff;
1049      if (i+1 == 2) {
1050        memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14);
1051        next += 14;
1052      } else {
1053        for (j = 0; j < n; ++j) {
1054          newNameTab[6 + 4*12 + next + 2*j] = 0;
1055          newNameTab[6 + 4*12 + next + 2*j + 1] = name[j];
1056        }
1057        next += 2*n;
1058      }
1059    }
1060  } else {
1061    newNameLen = 0;
1062    newNameTab = NULL;
1063  }
1064
1065  // construct the new cmap table
1066  if (codeToGID) {
1067    newCmapLen = 44 + 256 * 2;
1068    newCmapTab = (char *)gmalloc(newCmapLen);
1069    newCmapTab[0] = 0;          // table version number = 0
1070    newCmapTab[1] = 0;
1071    newCmapTab[2] = 0;          // number of encoding tables = 1
1072    newCmapTab[3] = 1;
1073    newCmapTab[4] = 0;          // platform ID = Microsoft
1074    newCmapTab[5] = 3;
1075    newCmapTab[6] = 0;          // encoding ID = Unicode
1076    newCmapTab[7] = 1;
1077    newCmapTab[8] = 0;          // offset of subtable
1078    newCmapTab[9] = 0;
1079    newCmapTab[10] = 0;
1080    newCmapTab[11] = 12;
1081    newCmapTab[12] = 0;         // subtable format = 4
1082    newCmapTab[13] = 4;
1083    newCmapTab[14] = 0x02;      // subtable length
1084    newCmapTab[15] = 0x20;
1085    newCmapTab[16] = 0;         // subtable version = 0
1086    newCmapTab[17] = 0;
1087    newCmapTab[18] = 0;         // segment count * 2
1088    newCmapTab[19] = 4;
1089    newCmapTab[20] = 0;         // 2 * 2 ^ floor(log2(segCount))
1090    newCmapTab[21] = 4;
1091    newCmapTab[22] = 0;         // floor(log2(segCount))
1092    newCmapTab[23] = 1;
1093    newCmapTab[24] = 0;         // 2*segCount - 2*2^floor(log2(segCount))
1094    newCmapTab[25] = 0;
1095    newCmapTab[26] = 0x00;      // endCount[0]
1096    newCmapTab[27] = (char)0xff;
1097    newCmapTab[28] = (char)0xff; // endCount[1]
1098    newCmapTab[29] = (char)0xff;
1099    newCmapTab[30] = 0;         // reserved
1100    newCmapTab[31] = 0;
1101    newCmapTab[32] = 0x00;      // startCount[0]
1102    newCmapTab[33] = 0x00;
1103    newCmapTab[34] = (char)0xff; // startCount[1]
1104    newCmapTab[35] = (char)0xff;
1105    newCmapTab[36] = 0;         // idDelta[0]
1106    newCmapTab[37] = 0;
1107    newCmapTab[38] = 0;         // idDelta[1]
1108    newCmapTab[39] = 1;
1109    newCmapTab[40] = 0;         // idRangeOffset[0]
1110    newCmapTab[41] = 4;
1111    newCmapTab[42] = 0;         // idRangeOffset[1]
1112    newCmapTab[43] = 0;
1113    for (i = 0; i < 256; ++i) {
1114      newCmapTab[44 + 2*i] = codeToGID[i] >> 8;
1115      newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff;
1116    }
1117  } else {
1118    newCmapLen = 0;
1119    newCmapTab = NULL;
1120  }
1121
1122  // generate the new hmtx table and the updated hhea table
1123  if (abbrevHMTX) {
1124    i = seekTable("hhea");
1125    pos = tables[i].offset;
1126    newHHEALen = 36;
1127    newHHEATab = (char *)gmalloc(newHHEALen);
1128    for (i = 0; i < newHHEALen; ++i) {
1129      newHHEATab[i] = getU8(pos++, &ok);
1130    }
1131    newHHEATab[34] = nGlyphs >> 8;
1132    newHHEATab[35] = nGlyphs & 0xff;
1133    i = seekTable("hmtx");
1134    pos = tables[i].offset;
1135    newHMTXLen = 4 * nGlyphs;
1136    newHMTXTab = (char *)gmalloc(newHMTXLen);
1137    advWidth = 0;
1138    for (i = 0; i < nHMetrics; ++i) {
1139      advWidth = getU16BE(pos, &ok);
1140      lsb = getU16BE(pos + 2, &ok);
1141      pos += 4;
1142      newHMTXTab[4*i    ] = advWidth >> 8;
1143      newHMTXTab[4*i + 1] = advWidth & 0xff;
1144      newHMTXTab[4*i + 2] = lsb >> 8;
1145      newHMTXTab[4*i + 3] = lsb & 0xff;
1146    }
1147    for (; i < nGlyphs; ++i) {
1148      lsb = getU16BE(pos, &ok);
1149      pos += 2;
1150      newHMTXTab[4*i    ] = advWidth >> 8;
1151      newHMTXTab[4*i + 1] = advWidth & 0xff;
1152      newHMTXTab[4*i + 2] = lsb >> 8;
1153      newHMTXTab[4*i + 3] = lsb & 0xff;
1154    }
1155  } else {
1156    newHHEATab = newHMTXTab = NULL;
1157    newHHEALen = newHMTXLen = 0; // make gcc happy
1158  }
1159
1160  // construct the new table directory:
1161  // - keep all original tables with non-zero length
1162  // - fix the cmap table's length, if necessary
1163  // - add missing tables
1164  // - sort the table by tag
1165  // - compute new table positions, including 4-byte alignment
1166  // - (re)compute table checksums
1167  nNewTables = nTables - nZeroLengthTables +
1168               (missingCmap ? 1 : 0) + (missingName ? 1 : 0) +
1169               (missingPost ? 1 : 0) + (missingOS2 ? 1 : 0);
1170  newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable));
1171  j = 0;
1172  for (i = 0; i < nTables; ++i) {
1173    if (tables[i].len > 0) {
1174      newTables[j] = tables[i];
1175      newTables[j].origOffset = tables[i].offset;
1176      if (checkRegion(tables[i].offset, newTables[i].len)) {
1177        newTables[j].checksum =
1178            computeTableChecksum(file + tables[i].offset, tables[i].len);
1179        if (tables[i].tag == headTag) {
1180          // don't include the file checksum
1181          newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok);
1182        }
1183      }
1184      if (newTables[j].tag == cmapTag && codeToGID) {
1185        newTables[j].len = newCmapLen;
1186        newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
1187                                                     newCmapLen);
1188      } else if (newTables[j].tag == cmapTag && badCmapLen) {
1189        newTables[j].len = cmapLen;
1190      } else if (newTables[j].tag == locaTag && unsortedLoca) {
1191        newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1192        newTables[j].checksum = locaChecksum;
1193      } else if (newTables[j].tag == glyfTag && unsortedLoca) {
1194        newTables[j].len = glyfLen;
1195        newTables[j].checksum = glyfChecksum;
1196      } else if (newTables[j].tag == nameTag && name) {
1197        newTables[j].len = newNameLen;
1198        newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
1199                                                     newNameLen);
1200      } else if (newTables[j].tag == hheaTag && abbrevHMTX) {
1201        newTables[j].len = newHHEALen;
1202        newTables[j].checksum = computeTableChecksum((Guchar *)newHHEATab,
1203                                                     newHHEALen);
1204      } else if (newTables[j].tag == hmtxTag && abbrevHMTX) {
1205        newTables[j].len = newHMTXLen;
1206        newTables[j].checksum = computeTableChecksum((Guchar *)newHMTXTab,
1207                                                     newHMTXLen);
1208      }
1209      ++j;
1210    }
1211  }
1212  if (missingCmap) {
1213    newTables[j].tag = cmapTag;
1214    if (codeToGID) {
1215      newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
1216                                                   newCmapLen);
1217      newTables[j].len = newCmapLen;
1218    } else {
1219      newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab,
1220                                                   sizeof(cmapTab));
1221      newTables[j].len = sizeof(cmapTab);
1222    }
1223    ++j;
1224  }
1225  if (missingName) {
1226    newTables[j].tag = nameTag;
1227    if (name) {
1228      newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
1229                                                   newNameLen);
1230      newTables[j].len = newNameLen;
1231    } else {
1232      newTables[j].checksum = computeTableChecksum((Guchar *)nameTab,
1233                                                   sizeof(nameTab));
1234      newTables[j].len = sizeof(nameTab);
1235    }
1236    ++j;
1237  }
1238  if (missingPost) {
1239    newTables[j].tag = postTag;
1240    newTables[j].checksum = computeTableChecksum((Guchar *)postTab,
1241                                                 sizeof(postTab));
1242    newTables[j].len = sizeof(postTab);
1243    ++j;
1244  }
1245  if (missingOS2) {
1246    newTables[j].tag = os2Tag;
1247    newTables[j].checksum = computeTableChecksum((Guchar *)os2Tab,
1248                                                 sizeof(os2Tab));
1249    newTables[j].len = sizeof(os2Tab);
1250    ++j;
1251  }
1252  qsort(newTables, nNewTables, sizeof(TrueTypeTable),
1253        &cmpTrueTypeTableTag);
1254  pos = 12 + nNewTables * 16;
1255  for (i = 0; i < nNewTables; ++i) {
1256    newTables[i].offset = pos;
1257    pos += newTables[i].len;
1258    if (pos & 3) {
1259      pos += 4 - (pos & 3);
1260    }
1261  }
1262
1263  // write the table directory
1264  tableDir = (char *)gmalloc(12 + nNewTables * 16);
1265  tableDir[0] = 0x00;                                   // sfnt version
1266  tableDir[1] = 0x01;
1267  tableDir[2] = 0x00;
1268  tableDir[3] = 0x00;
1269  tableDir[4] = (char)((nNewTables >> 8) & 0xff);       // numTables
1270  tableDir[5] = (char)(nNewTables & 0xff);
1271  for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ;
1272  t = 1 << (4 + i);
1273  tableDir[6] = (char)((t >> 8) & 0xff);                // searchRange
1274  tableDir[7] = (char)(t & 0xff);
1275  tableDir[8] = (char)((i >> 8) & 0xff);                // entrySelector
1276  tableDir[9] = (char)(i & 0xff);
1277  t = nNewTables * 16 - t;
1278  tableDir[10] = (char)((t >> 8) & 0xff);               // rangeShift
1279  tableDir[11] = (char)(t & 0xff);
1280  pos = 12;
1281  for (i = 0; i < nNewTables; ++i) {
1282    tableDir[pos   ] = (char)(newTables[i].tag >> 24);
1283    tableDir[pos+ 1] = (char)(newTables[i].tag >> 16);
1284    tableDir[pos+ 2] = (char)(newTables[i].tag >>  8);
1285    tableDir[pos+ 3] = (char) newTables[i].tag;
1286    tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24);
1287    tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16);
1288    tableDir[pos+ 6] = (char)(newTables[i].checksum >>  8);
1289    tableDir[pos+ 7] = (char) newTables[i].checksum;
1290    tableDir[pos+ 8] = (char)(newTables[i].offset >> 24);
1291    tableDir[pos+ 9] = (char)(newTables[i].offset >> 16);
1292    tableDir[pos+10] = (char)(newTables[i].offset >>  8);
1293    tableDir[pos+11] = (char) newTables[i].offset;
1294    tableDir[pos+12] = (char)(newTables[i].len >> 24);
1295    tableDir[pos+13] = (char)(newTables[i].len >> 16);
1296    tableDir[pos+14] = (char)(newTables[i].len >>  8);
1297    tableDir[pos+15] = (char) newTables[i].len;
1298    pos += 16;
1299  }
1300  (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16);
1301
1302  // compute the file checksum
1303  fileChecksum = computeTableChecksum((Guchar *)tableDir,
1304                                      12 + nNewTables * 16);
1305  for (i = 0; i < nNewTables; ++i) {
1306    fileChecksum += newTables[i].checksum;
1307  }
1308  fileChecksum = 0xb1b0afba - fileChecksum;
1309
1310  // write the tables
1311  for (i = 0; i < nNewTables; ++i) {
1312    if (newTables[i].tag == headTag) {
1313      if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
1314        (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8);
1315        checksumBuf[0] = fileChecksum >> 24;
1316        checksumBuf[1] = fileChecksum >> 16;
1317        checksumBuf[2] = fileChecksum >> 8;
1318        checksumBuf[3] = fileChecksum;
1319        (*outputFunc)(outputStream, checksumBuf, 4);
1320        (*outputFunc)(outputStream,
1321                      (char *)file + newTables[i].origOffset + 12,
1322                      newTables[i].len - 12);
1323      } else {
1324        for (j = 0; j < newTables[i].len; ++j) {
1325          (*outputFunc)(outputStream, "\0", 1);
1326        }
1327      }
1328    } else if (newTables[i].tag == cmapTag && codeToGID) {
1329      (*outputFunc)(outputStream, newCmapTab, newTables[i].len);
1330    } else if (newTables[i].tag == cmapTag && missingCmap) {
1331      (*outputFunc)(outputStream, cmapTab, newTables[i].len);
1332    } else if (newTables[i].tag == nameTag && name) {
1333      (*outputFunc)(outputStream, newNameTab, newTables[i].len);
1334    } else if (newTables[i].tag == nameTag && missingName) {
1335      (*outputFunc)(outputStream, nameTab, newTables[i].len);
1336    } else if (newTables[i].tag == postTag && missingPost) {
1337      (*outputFunc)(outputStream, postTab, newTables[i].len);
1338    } else if (newTables[i].tag == os2Tag && missingOS2) {
1339      (*outputFunc)(outputStream, os2Tab, newTables[i].len);
1340    } else if (newTables[i].tag == hheaTag && abbrevHMTX) {
1341      (*outputFunc)(outputStream, newHHEATab, newTables[i].len);
1342    } else if (newTables[i].tag == hmtxTag && abbrevHMTX) {
1343      (*outputFunc)(outputStream, newHMTXTab, newTables[i].len);
1344    } else if (newTables[i].tag == locaTag && unsortedLoca) {
1345      for (j = 0; j <= nGlyphs; ++j) {
1346        if (locaFmt) {
1347          locaBuf[0] = (char)(locaTable[j].newOffset >> 24);
1348          locaBuf[1] = (char)(locaTable[j].newOffset >> 16);
1349          locaBuf[2] = (char)(locaTable[j].newOffset >>  8);
1350          locaBuf[3] = (char) locaTable[j].newOffset;
1351          (*outputFunc)(outputStream, locaBuf, 4);
1352        } else {
1353          locaBuf[0] = (char)(locaTable[j].newOffset >> 9);
1354          locaBuf[1] = (char)(locaTable[j].newOffset >> 1);
1355          (*outputFunc)(outputStream, locaBuf, 2);
1356        }
1357      }
1358    } else if (newTables[i].tag == glyfTag && unsortedLoca) {
1359      pos = tables[seekTable("glyf")].offset;
1360      for (j = 0; j < nGlyphs; ++j) {
1361        n = locaTable[j].len;
1362        if (n > 0) {
1363          k = locaTable[j].origOffset;
1364          if (checkRegion(pos + k, n)) {
1365            (*outputFunc)(outputStream, (char *)file + pos + k, n);
1366          } else {
1367            for (k = 0; k < n; ++k) {
1368              (*outputFunc)(outputStream, "\0", 1);
1369            }
1370          }
1371          if ((k = locaTable[j].len & 3)) {
1372            (*outputFunc)(outputStream, "\0\0\0\0", 4 - k);
1373          }
1374        }
1375      }
1376    } else {
1377      if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
1378        (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset,
1379                      newTables[i].len);
1380      } else {
1381        for (j = 0; j < newTables[i].len; ++j) {
1382          (*outputFunc)(outputStream, "\0", 1);
1383        }
1384      }
1385    }
1386    if (newTables[i].len & 3) {
1387      (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3));
1388    }
1389  }
1390
1391  gfree(newHMTXTab);
1392  gfree(newHHEATab);
1393  gfree(newCmapTab);
1394  gfree(newNameTab);
1395  gfree(tableDir);
1396  gfree(newTables);
1397 done1:
1398  gfree(locaTable);
1399}
1400
1401void FoFiTrueType::cvtEncoding(char **encoding,
1402                               FoFiOutputFunc outputFunc,
1403                               void *outputStream) {
1404  char *name;
1405  GooString *buf;
1406  int i;
1407
1408  (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
1409  if (encoding) {
1410    for (i = 0; i < 256; ++i) {
1411      if (!(name = encoding[i])) {
1412        name = ".notdef";
1413      }
1414      buf = GooString::format("dup {0:d} /", i);
1415      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
1416      delete buf;
1417      (*outputFunc)(outputStream, name, strlen(name));
1418      (*outputFunc)(outputStream, " put\n", 5);
1419    }
1420  } else {
1421    for (i = 0; i < 256; ++i) {
1422      buf = GooString::format("dup {0:d} /c{1:02x} put\n", i, i);
1423      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
1424      delete buf;
1425    }
1426  }
1427  (*outputFunc)(outputStream, "readonly def\n", 13);
1428}
1429
1430void FoFiTrueType::cvtCharStrings(char **encoding,
1431                                  Gushort *codeToGID,
1432                                  FoFiOutputFunc outputFunc,
1433                                  void *outputStream) {
1434  char *name;
1435  GooString *buf;
1436  char buf2[16];
1437  int i, k;
1438
1439  // always define '.notdef'
1440  (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32);
1441  (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
1442
1443  // if there's no 'cmap' table, punt
1444  if (nCmaps == 0) {
1445    goto err;
1446  }
1447
1448  // map char name to glyph index:
1449  // 1. use encoding to map name to char code
1450  // 2. use codeToGID to map char code to glyph index
1451  // N.B. We do this in reverse order because font subsets can have
1452  //      weird encodings that use the same character name twice, and
1453  //      the first definition is probably the one we want.
1454  k = 0; // make gcc happy
1455  for (i = 255; i >= 0; --i) {
1456    if (encoding) {
1457      name = encoding[i];
1458    } else {
1459      sprintf(buf2, "c%02x", i);
1460      name = buf2;
1461    }
1462    if (name && strcmp(name, ".notdef")) {
1463      k = codeToGID[i];
1464      // note: Distiller (maybe Adobe's PS interpreter in general)
1465      // doesn't like TrueType fonts that have CharStrings entries
1466      // which point to nonexistent glyphs, hence the (k < nGlyphs)
1467      // test
1468      if (k > 0 && k < nGlyphs) {
1469        (*outputFunc)(outputStream, "/", 1);
1470        (*outputFunc)(outputStream, name, strlen(name));
1471        buf = GooString::format(" {0:d} def\n", k);
1472        (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
1473        delete buf;
1474      }
1475    }
1476  }
1477
1478 err:
1479  (*outputFunc)(outputStream, "end readonly def\n", 17);
1480}
1481
1482void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
1483                            void *outputStream, GooString *name,
1484                            GBool needVerticalMetrics) {
1485  Guchar headData[54];
1486  TrueTypeLoca *locaTable;
1487  Guchar *locaData;
1488  TrueTypeTable newTables[nT42Tables];
1489  Guchar tableDir[12 + nT42Tables*16];
1490  GBool ok;
1491  Guint checksum;
1492  int nNewTables;
1493  int length, pos, glyfPos, i, j, k;
1494  Guchar vheaTab[36] = {
1495    0, 1, 0, 0,                 // table version number
1496    0, 0,                       // ascent
1497    0, 0,                       // descent
1498    0, 0,                       // reserved
1499    0, 0,                       // max advance height
1500    0, 0,                       // min top side bearing
1501    0, 0,                       // min bottom side bearing
1502    0, 0,                       // y max extent
1503    0, 0,                       // caret slope rise
1504    0, 1,                       // caret slope run
1505    0, 0,                       // caret offset
1506    0, 0,                       // reserved
1507    0, 0,                       // reserved
1508    0, 0,                       // reserved
1509    0, 0,                       // reserved
1510    0, 0,                       // metric data format
1511    0, 1                        // number of advance heights in vmtx table
1512  };
1513  Guchar *vmtxTab;
1514  GBool needVhea, needVmtx;
1515  int advance;
1516
1517  // construct the 'head' table, zero out the font checksum
1518  i = seekTable("head");
1519  pos = tables[i].offset;
1520  if (!checkRegion(pos, 54)) {
1521    return;
1522  }
1523  memcpy(headData, file + pos, 54);
1524  headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0;
1525
1526  // read the original 'loca' table, pad entries out to 4 bytes, and
1527  // sort it into proper order -- some (non-compliant) fonts have
1528  // out-of-order loca tables; in order to correctly handle the case
1529  // where (compliant) fonts have empty entries in the middle of the
1530  // table, cmpTrueTypeLocaPos uses offset as its primary sort key,
1531  // and idx as its secondary key (ensuring that adjacent entries with
1532  // the same pos value remain in the same order)
1533  locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
1534  i = seekTable("loca");
1535  pos = tables[i].offset;
1536  ok = gTrue;
1537  for (i = 0; i <= nGlyphs; ++i) {
1538    locaTable[i].idx = i;
1539    if (locaFmt) {
1540      locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
1541    } else {
1542      locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
1543    }
1544  }
1545  qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
1546        &cmpTrueTypeLocaOffset);
1547  for (i = 0; i < nGlyphs; ++i) {
1548    locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
1549  }
1550  locaTable[nGlyphs].len = 0;
1551  qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
1552        &cmpTrueTypeLocaIdx);
1553  pos = 0;
1554  for (i = 0; i <= nGlyphs; ++i) {
1555    locaTable[i].newOffset = pos;
1556    pos += locaTable[i].len;
1557    if (pos & 3) {
1558      pos += 4 - (pos & 3);
1559    }
1560  }
1561
1562  // construct the new 'loca' table
1563  locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2));
1564  for (i = 0; i <= nGlyphs; ++i) {
1565    pos = locaTable[i].newOffset;
1566    if (locaFmt) {
1567      locaData[4*] = (Guchar)(pos >> 24);
1568      locaData[4*i+1] = (Guchar)(pos >> 16);
1569      locaData[4*i+2] = (Guchar)(pos >>  8);
1570      locaData[4*i+3] = (Guchar) pos;
1571    } else {
1572      locaData[2*] = (Guchar)(pos >> 9);
1573      locaData[2*i+1] = (Guchar)(pos >> 1);
1574    }
1575  }
1576
1577  // count the number of tables
1578  nNewTables = 0;
1579  for (i = 0; i < nT42Tables; ++i) {
1580    if (t42Tables[i].required ||
1581        seekTable(t42Tables[i].tag) >= 0) {
1582      ++nNewTables;
1583    }
1584  }
1585  vmtxTab = NULL; // make gcc happy
1586  advance = 0; // make gcc happy
1587  if (needVerticalMetrics) {
1588    needVhea = seekTable("vhea") < 0;
1589    needVmtx = seekTable("vmtx") < 0;
1590    if (needVhea || needVmtx) {
1591      i = seekTable("head");
1592      advance = getU16BE(tables[i].offset + 18, &ok); // units per em
1593      if (needVhea) {
1594        ++nNewTables;
1595      }
1596      if (needVmtx) {
1597        ++nNewTables;
1598      }
1599    }
1600  }
1601
1602  // construct the new table headers, including table checksums
1603  // (pad each table out to a multiple of 4 bytes)
1604  pos = 12 + nNewTables*16;
1605  k = 0;
1606  for (i = 0; i < nT42Tables; ++i) {
1607    length = -1;
1608    checksum = 0; // make gcc happy
1609    if (i == t42HeadTable) {
1610      length = 54;
1611      checksum = computeTableChecksum(headData, 54);
1612    } else if (i == t42LocaTable) {
1613      length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1614      checksum = computeTableChecksum(locaData, length);
1615    } else if (i == t42GlyfTable) {
1616      length = 0;
1617      checksum = 0;
1618      glyfPos = tables[seekTable("glyf")].offset;
1619      for (j = 0; j < nGlyphs; ++j) {
1620        length += locaTable[j].len;
1621        if (length & 3) {
1622          length += 4 - (length & 3);
1623        }
1624        if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1625          checksum +=
1626              computeTableChecksum(file + glyfPos + locaTable[j].origOffset,
1627                                   locaTable[j].len);
1628        }
1629      }
1630    } else {
1631      if ((j = seekTable(t42Tables[i].tag)) >= 0) {
1632        length = tables[j].len;
1633        if (checkRegion(tables[j].offset, length)) {
1634          checksum = computeTableChecksum(file + tables[j].offset, length);
1635        }
1636      } else if (needVerticalMetrics && i == t42VheaTable) {
1637        vheaTab[10] = advance / 256;    // max advance height
1638        vheaTab[11] = advance % 256;
1639        length = sizeof(vheaTab);
1640        checksum = computeTableChecksum(vheaTab, length);
1641      } else if (needVerticalMetrics && i == t42VmtxTable) {
1642        length = 4 + (nGlyphs - 1) * 4;
1643        vmtxTab = (Guchar *)gmalloc(length);
1644        vmtxTab[0] = advance / 256;
1645        vmtxTab[1] = advance % 256;
1646        for (j = 2; j < length; j += 2) {
1647          vmtxTab[j] = 0;
1648          vmtxTab[j+1] = 0;
1649        }
1650        checksum = computeTableChecksum(vmtxTab, length);
1651      } else if (t42Tables[i].required) {
1652        //~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
1653        //~       t42Tables[i].tag);
1654        length = 0;
1655        checksum = 0;
1656      }
1657    }
1658    if (length >= 0) {
1659      newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) |
1660                         ((t42Tables[i].tag[1] & 0xff) << 16) |
1661                         ((t42Tables[i].tag[2] & 0xff) <<  8) |
1662                          (t42Tables[i].tag[3] & 0xff);
1663      newTables[k].checksum = checksum;
1664      newTables[k].offset = pos;
1665      newTables[k].len = length;
1666      pos += length;
1667      if (pos & 3) {
1668        pos += 4 - (length & 3);
1669      }
1670      ++k;
1671    }
1672  }
1673
1674  // construct the table directory
1675  tableDir[0] = 0x00;           // sfnt version
1676  tableDir[1] = 0x01;
1677  tableDir[2] = 0x00;
1678  tableDir[3] = 0x00;
1679  tableDir[4] = 0;              // numTables
1680  tableDir[5] = nNewTables;
1681  tableDir[6] = 0;              // searchRange
1682  tableDir[7] = (Guchar)128;
1683  tableDir[8] = 0;              // entrySelector
1684  tableDir[9] = 3;
1685  tableDir[10] = 0;             // rangeShift
1686  tableDir[11] = (Guchar)(16 * nNewTables - 128);
1687  pos = 12;
1688  for (i = 0; i < nNewTables; ++i) {
1689    tableDir[pos   ] = (Guchar)(newTables[i].tag >> 24);
1690    tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16);
1691    tableDir[pos+ 2] = (Guchar)(newTables[i].tag >>  8);
1692    tableDir[pos+ 3] = (Guchar) newTables[i].tag;
1693    tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24);
1694    tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16);
1695    tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >>  8);
1696    tableDir[pos+ 7] = (Guchar) newTables[i].checksum;
1697    tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24);
1698    tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16);
1699    tableDir[pos+10] = (Guchar)(newTables[i].offset >>  8);
1700    tableDir[pos+11] = (Guchar) newTables[i].offset;
1701    tableDir[pos+12] = (Guchar)(newTables[i].len >> 24);
1702    tableDir[pos+13] = (Guchar)(newTables[i].len >> 16);
1703    tableDir[pos+14] = (Guchar)(newTables[i].len >>  8);
1704    tableDir[pos+15] = (Guchar) newTables[i].len;
1705    pos += 16;
1706  }
1707
1708  // compute the font checksum and store it in the head table
1709  checksum = computeTableChecksum(tableDir, 12 + nNewTables*16);
1710  for (i = 0; i < nNewTables; ++i) {
1711    checksum += newTables[i].checksum;
1712  }
1713  checksum = 0xb1b0afba - checksum; // because the TrueType spec says so
1714  headData[ 8] = (Guchar)(checksum >> 24);
1715  headData[ 9] = (Guchar)(checksum >> 16);
1716  headData[10] = (Guchar)(checksum >>  8);
1717  headData[11] = (Guchar) checksum;
1718
1719  // start the sfnts array
1720  if (name) {
1721    (*outputFunc)(outputStream, "/", 1);
1722    (*outputFunc)(outputStream, name->getCString(), name->getLength());
1723    (*outputFunc)(outputStream, " [\n", 3);
1724  } else {
1725    (*outputFunc)(outputStream, "/sfnts [\n", 9);
1726  }
1727
1728  // write the table directory
1729  dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream);
1730
1731  // write the tables
1732  for (i = 0; i < nNewTables; ++i) {
1733    if (i == t42HeadTable) {
1734      dumpString(headData, 54, outputFunc, outputStream);
1735    } else if (i == t42LocaTable) {
1736      length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1737      dumpString(locaData, length, outputFunc, outputStream);
1738    } else if (i == t42GlyfTable) {
1739      glyfPos = tables[seekTable("glyf")].offset;
1740      for (j = 0; j < nGlyphs; ++j) {
1741        if (locaTable[j].len > 0 &&
1742            checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1743          dumpString(file + glyfPos + locaTable[j].origOffset,
1744                     locaTable[j].len, outputFunc, outputStream);
1745        }
1746      }
1747    } else {
1748      // length == 0 means the table is missing and the error was
1749      // already reported during the construction of the table
1750      // headers
1751      if ((length = newTables[i].len) > 0) {
1752        if ((j = seekTable(t42Tables[i].tag)) >= 0 &&
1753            checkRegion(tables[j].offset, tables[j].len)) {
1754          dumpString(file + tables[j].offset, tables[j].len,
1755                     outputFunc, outputStream);
1756        } else if (needVerticalMetrics && i == t42VheaTable) {
1757          dumpString(vheaTab, length, outputFunc, outputStream);
1758        } else if (needVerticalMetrics && i == t42VmtxTable) {
1759          dumpString(vmtxTab, length, outputFunc, outputStream);
1760          gfree(vmtxTab);
1761        }
1762      }
1763    }
1764  }
1765
1766  // end the sfnts array
1767  (*outputFunc)(outputStream, "] def\n", 6);
1768
1769  gfree(locaData);
1770  gfree(locaTable);
1771}
1772
1773void FoFiTrueType::dumpString(Guchar *s, int length,
1774                              FoFiOutputFunc outputFunc,
1775                              void *outputStream) {
1776  GooString *buf;
1777  int pad, i, j;
1778
1779  (*outputFunc)(outputStream, "<", 1);
1780  for (i = 0; i < length; i += 32) {
1781    for (j = 0; j < 32 && i+j < length; ++j) {
1782      buf = GooString::format("{0:02x}", s[i+j] & 0xff);
1783      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
1784      delete buf;
1785    }
1786    if (i % (65536 - 32) == 65536 - 64) {
1787      (*outputFunc)(outputStream, ">\n<", 3);
1788    } else if (i+32 < length) {
1789      (*outputFunc)(outputStream, "\n", 1);
1790    }
1791  }
1792  if (length & 3) {
1793    pad = 4 - (length & 3);
1794    for (i = 0; i < pad; ++i) {
1795      (*outputFunc)(outputStream, "00", 2);
1796    }
1797  }
1798  // add an extra zero byte because the Adobe Type 42 spec says so
1799  (*outputFunc)(outputStream, "00>\n", 4);
1800}
1801
1802Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) {
1803  Guint checksum, word;
1804  int i;
1805
1806  checksum = 0;
1807  for (i = 0; i+3 < length; i += 4) {
1808    word = ((data[] & 0xff) << 24) +
1809           ((data[i+1] & 0xff) << 16) +
1810           ((data[i+2] & 0xff) <<  8) +
1811            (data[i+3] & 0xff);
1812    checksum += word;
1813  }
1814  if (length & 3) {
1815    word = 0;
1816    i = length & ~3;
1817    switch (length & 3) {
1818    case 3:
1819      word |= (data[i+2] & 0xff) <<  8;
1820    case 2:
1821      word |= (data[i+1] & 0xff) << 16;
1822    case 1:
1823      word |= (data[] & 0xff) << 24;
1824      break;
1825    }
1826    checksum += word;
1827  }
1828  return checksum;
1829}
1830
1831void FoFiTrueType::parse() {
1832  Guint topTag;
1833  int pos, ver, i, j;
1834
1835  parsedOk = gTrue;
1836
1837  // look for a collection (TTC)
1838  topTag = getU32BE(0, &parsedOk);
1839  if (!parsedOk) {
1840    return;
1841  }
1842  if (topTag == ttcfTag) {
1843    /* TTC font */
1844    int dircount;
1845
1846    dircount = getU32BE(8, &parsedOk);
1847    if (!parsedOk)
1848      return;
1849    if (! dircount) {
1850      parsedOk = gFalse;
1851      return;
1852    }
1853
1854    if (faceIndex >= dircount)
1855      faceIndex = 0;
1856    pos = getU32BE(12 + faceIndex * 4, &parsedOk);
1857    if (! parsedOk)
1858      return;
1859  } else {
1860    pos = 0;
1861  }
1862
1863  // check the sfnt version
1864  ver = getU32BE(pos, &parsedOk);
1865  if (!parsedOk) {
1866    return;
1867  }
1868  openTypeCFF = ver == 0x4f54544f; // 'OTTO'
1869
1870  // read the table directory
1871  nTables = getU16BE(pos + 4, &parsedOk);
1872  if (!parsedOk) {
1873    return;
1874  }
1875  tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable));
1876  pos += 12;
1877  for (i = 0; i < nTables; ++i) {
1878    tables[i].tag = getU32BE(pos, &parsedOk);
1879    tables[i].checksum = getU32BE(pos + 4, &parsedOk);
1880    tables[i].offset = (int)getU32BE(pos + 8, &parsedOk);
1881    tables[i].len = (int)getU32BE(pos + 12, &parsedOk);
1882    if (tables[i].offset + tables[i].len < tables[i].offset ||
1883        tables[i].offset + tables[i].len > len) {
1884      parsedOk = gFalse;
1885    }
1886    pos += 16;
1887  }
1888  if (!parsedOk) {
1889    return;
1890  }
1891
1892  // check for tables that are required by both the TrueType spec and
1893  // the Type 42 spec
1894  if (seekTable("head") < 0 ||
1895      seekTable("hhea") < 0 ||
1896      seekTable("maxp") < 0 ||
1897      seekTable("hmtx") < 0 ||
1898      (!openTypeCFF && seekTable("loca") < 0) ||
1899      (!openTypeCFF && seekTable("glyf") < 0) ||
1900      (openTypeCFF && seekTable("CFF ") < 0)) {
1901    parsedOk = gFalse;
1902    return;
1903  }
1904
1905  // read the cmaps
1906  if ((i = seekTable("cmap")) >= 0) {
1907    pos = tables[i].offset + 2;
1908    nCmaps = getU16BE(pos, &parsedOk);
1909    pos += 2;
1910    if (!parsedOk) {
1911      return;
1912    }
1913    cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap));
1914    for (j = 0; j < nCmaps; ++j) {
1915      cmaps[j].platform = getU16BE(pos, &parsedOk);
1916      cmaps[j].encoding = getU16BE(pos + 2, &parsedOk);
1917      cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk);
1918      pos += 8;
1919      cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk);
1920      cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk);
1921    }
1922    if (!parsedOk) {
1923      return;
1924    }
1925  } else {
1926    nCmaps = 0;
1927  }
1928
1929  // get the number of glyphs from the maxp table
1930  i = seekTable("maxp");
1931  nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk);
1932  if (!parsedOk) {
1933    return;
1934  }
1935
1936  // get the bbox and loca table format from the head table
1937  i = seekTable("head");
1938  bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk);
1939  bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk);
1940  bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk);
1941  bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk);
1942  locaFmt = getS16BE(tables[i].offset + 50, &parsedOk);
1943  if (!parsedOk) {
1944    return;
1945  }
1946
1947  // make sure the loca table is sane (correct length and entries are
1948  // in bounds)
1949  if (!openTypeCFF) {
1950    i = seekTable("loca");
1951    if (tables[i].len < 0) {
1952      parsedOk = gFalse;
1953      return;
1954    }
1955    if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) {
1956      nGlyphs = tables[i].len / (locaFmt ? 4 : 2) - 1;
1957    }
1958    for (j = 0; j <= nGlyphs; ++j) {
1959      if (locaFmt) {
1960        pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk);
1961      } else {
1962        pos = getU16BE(tables[i].offset + j*2, &parsedOk);
1963      }
1964      if (pos < 0 || pos > len) {
1965        parsedOk = gFalse;
1966      }
1967    }
1968    if (!parsedOk) {
1969      return;
1970    }
1971  }
1972
1973  // read the post table
1974  readPostTable();
1975}
1976
1977void FoFiTrueType::readPostTable() {
1978  GooString *name;
1979  int tablePos, postFmt, stringIdx, stringPos;
1980  GBool ok;
1981  int i, j, n, m;
1982
1983  ok = gTrue;
1984  if ((i = seekTable("post")) < 0) {
1985    return;
1986  }
1987  tablePos = tables[i].offset;
1988  postFmt = getU32BE(tablePos, &ok);
1989  if (!ok) {
1990    goto err;
1991  }
1992  if (postFmt == 0x00010000) {
1993    nameToGID = new GooHash(gTrue);
1994    for (i = 0; i < 258; ++i) {
1995      nameToGID->add(new GooString(macGlyphNames[i]), i);
1996    }
1997  } else if (postFmt == 0x00020000) {
1998    nameToGID = new GooHash(gTrue);
1999    n = getU16BE(tablePos + 32, &ok);
2000    if (!ok) {
2001      goto err;
2002    }
2003    if (n > nGlyphs) {
2004      n = nGlyphs;
2005    }
2006    stringIdx = 0;
2007    stringPos = tablePos + 34 + 2*n;
2008    for (i = 0; i < n; ++i) {
2009      j = getU16BE(tablePos + 34 + 2*i, &ok);
2010      if (j < 258) {
2011        nameToGID->removeInt(macGlyphNames[j]);
2012        nameToGID->add(new GooString(macGlyphNames[j]), i);
2013      } else {
2014        j -= 258;
2015        if (j != stringIdx) {
2016          for (stringIdx = 0, stringPos = tablePos + 34 + 2*n;
2017               stringIdx < j;
2018               ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ;
2019          if (!ok) {
2020            goto err;
2021          }
2022        }
2023        m = getU8(stringPos, &ok);
2024        if (!ok || !checkRegion(stringPos + 1, m)) {
2025          goto err;
2026        }
2027        name = new GooString((char *)&file[stringPos + 1], m);
2028        nameToGID->removeInt(name);
2029        nameToGID->add(name, i);
2030        ++stringIdx;
2031        stringPos += 1 + m;
2032      }
2033    }
2034  } else if (postFmt == 0x00028000) {
2035    nameToGID = new GooHash(gTrue);
2036    for (i = 0; i < nGlyphs; ++i) {
2037      j = getU8(tablePos + 32 + i, &ok);
2038      if (!ok) {
2039        goto err;
2040      }
2041      if (j < 258) {
2042        nameToGID->removeInt(macGlyphNames[j]);
2043        nameToGID->add(new GooString(macGlyphNames[j]), i);
2044      }
2045    }
2046  }
2047
2048  return;
2049
2050 err:
2051  if (nameToGID) {
2052    delete nameToGID;
2053    nameToGID = NULL;
2054  }
2055}
2056
2057int FoFiTrueType::seekTable(char *tag) {
2058  Guint tagI;
2059  int i;
2060
2061  tagI = ((tag[0] & 0xff) << 24) |
2062         ((tag[1] & 0xff) << 16) |
2063         ((tag[2] & 0xff) << 8) |
2064          (tag[3] & 0xff);
2065  for (i = 0; i < nTables; ++i) {
2066    if (tables[i].tag == tagI) {
2067      return i;
2068    }
2069  }
2070  return -1;
2071}
2072
2073Guint FoFiTrueType::charToTag(const char *tagName)
2074{
2075  int n = strlen(tagName);
2076  Guint tag = 0;
2077  int i;
2078
2079  if (n > 4) n = 4;
2080  for (i = 0;i < n;i++) {
2081    tag <<= 8;
2082    tag |= tagName[i] & 0xff;
2083  }
2084  for (;i < 4;i++) {
2085    tag <<= 8;
2086    tag |= ' ';
2087  }
2088  return tag;
2089}
2090
2091/*
2092  setup GSUB table data
2093  Only supporting vertical text substitution.
2094*/
2095int FoFiTrueType::setupGSUB(const char *tagName)
2096{
2097  Guint gsubTable;
2098  unsigned int i;
2099  Guint scriptList, featureList;
2100  Guint scriptCount;
2101  Guint tag;
2102  Guint scriptTable = 0;
2103  Guint langSys;
2104  Guint featureCount;
2105  Guint featureIndex;
2106  Guint ftable = 0;
2107  Guint llist;
2108  Guint scriptTag;
2109  int x;
2110  Guint pos;
2111
2112  if (tagName == 0) {
2113    gsubFeatureTable = 0;
2114    return 0;
2115  }
2116  scriptTag = charToTag(tagName);
2117  /* read GSUB Header */
2118  if ((x = seekTable("GSUB")) < 0) {
2119    return 0; /* GSUB table not found */
2120  }
2121  gsubTable = tables[x].offset;
2122  pos = gsubTable+4;
2123  scriptList = getU16BE(pos,&parsedOk);
2124  pos += 2;
2125  featureList = getU16BE(pos,&parsedOk);
2126  pos += 2;
2127  llist = getU16BE(pos,&parsedOk);
2128
2129  gsubLookupList = llist+gsubTable; /* change to offset from top of file */
2130  /* read script list table */
2131  pos = gsubTable+scriptList;
2132  scriptCount = getU16BE(pos,&parsedOk);
2133  pos += 2;
2134  /* find  script */
2135  for (i = 0;i < scriptCount;i++) {
2136    tag = getU32BE(pos,&parsedOk);
2137    pos += 4;
2138    scriptTable = getU16BE(pos,&parsedOk);
2139    pos += 2;
2140    if (tag == scriptTag) {
2141      /* found */
2142      break;
2143    }
2144  }
2145  if (i >= scriptCount) {
2146    /* not found */
2147    return 0;
2148  }
2149
2150  /* read script table */
2151  /* use default language system */
2152  pos = gsubTable+scriptList+scriptTable;
2153  langSys = getU16BE(pos,&parsedOk);/* default language system */
2154
2155  /* read LangSys table */
2156  if (langSys == 0) {
2157    /* no ldefault LangSys */
2158    return 0;
2159  }
2160
2161  pos = gsubTable+scriptList+scriptTable+langSys+2;
2162  featureIndex = getU16BE(pos,&parsedOk); /* ReqFeatureIndex */
2163  pos += 2;
2164
2165  if (featureIndex != 0xffff) {
2166    Guint tpos;
2167    /* read feature record */
2168    tpos = gsubTable+featureList;
2169    featureCount = getU16BE(tpos,&parsedOk);
2170    tpos = gsubTable+featureList+2+featureIndex*(4+2);
2171    tag = getU32BE(tpos,&parsedOk);
2172    tpos += 4;
2173    if (tag == vrt2Tag) {
2174      /* vrt2 is preferred, overwrite vert */
2175      ftable = getU16BE(tpos,&parsedOk);
2176      /* convert to offset from file top */
2177      gsubFeatureTable = ftable+gsubTable+featureList;
2178      return 0;
2179    } else if (tag == vertTag) {
2180      ftable = getU16BE(tpos,&parsedOk);
2181    }
2182  }
2183  featureCount = getU16BE(pos,&parsedOk);
2184  pos += 2;
2185  /* find 'vrt2' or 'vert' feature */
2186  for (i = 0;i < featureCount;i++) {
2187    Guint oldPos;
2188
2189    featureIndex = getU16BE(pos,&parsedOk);
2190    pos += 2;
2191    oldPos = pos; /* save position */
2192    /* read feature record */
2193    pos = gsubTable+featureList+2+featureIndex*(4+2);
2194    tag = getU32BE(pos,&parsedOk);
2195    pos += 4;
2196    if (tag == vrt2Tag) {
2197      /* vrt2 is preferred, overwrite vert */
2198      ftable = getU16BE(pos,&parsedOk);
2199      break;
2200    } else if (ftable == 0 && tag == vertTag) {
2201      ftable = getU16BE(pos,&parsedOk);
2202    }
2203    pos = oldPos; /* restore old position */
2204  }
2205  if (ftable == 0) {
2206    /* vert nor vrt2 are not found */
2207    return 0;
2208  }
2209  /* convert to offset from file top */
2210  gsubFeatureTable = ftable+gsubTable+featureList;
2211  return 0;
2212}
2213
2214Guint FoFiTrueType::doMapToVertGID(Guint orgGID)
2215{
2216  Guint lookupCount;
2217  Guint lookupListIndex;
2218  Guint i;
2219  Guint gid = 0;
2220  Guint pos;
2221
2222  pos = gsubFeatureTable+2;
2223  lookupCount = getU16BE(pos,&parsedOk);
2224  pos += 2;
2225  for (i = 0;i < lookupCount;i++) {
2226    lookupListIndex = getU16BE(pos,&parsedOk);
2227    pos += 2;
2228    if ((gid = scanLookupList(lookupListIndex,orgGID)) != 0) {
2229      break;
2230    }
2231  }
2232  return gid;
2233}
2234
2235Guint FoFiTrueType::mapToVertGID(Guint orgGID)
2236{
2237  Guint mapped;
2238
2239  if (gsubFeatureTable == 0) return orgGID;
2240  if ((mapped = doMapToVertGID(orgGID)) != 0) {
2241    return mapped;
2242  }
2243  return orgGID;
2244}
2245
2246Guint FoFiTrueType::scanLookupList(Guint listIndex, Guint orgGID)
2247{
2248  Guint lookupTable;
2249  Guint subTableCount;
2250  Guint subTable;
2251  Guint i;
2252  Guint gid = 0;
2253  Guint pos;
2254
2255  if (gsubLookupList == 0) return 0; /* no lookup list */
2256  pos = gsubLookupList+2+listIndex*2;
2257  lookupTable = getU16BE(pos,&parsedOk);
2258  /* read lookup table */
2259  pos = gsubLookupList+lookupTable+4;
2260  subTableCount = getU16BE(pos,&parsedOk);
2261  pos += 2;;
2262  for (i = 0;i < subTableCount;i++) {
2263    subTable = getU16BE(pos,&parsedOk);
2264    pos += 2;
2265    if ((gid = scanLookupSubTable(gsubLookupList+lookupTable+subTable,orgGID))
2266         != 0) break;
2267  }
2268  return gid;
2269}
2270
2271Guint FoFiTrueType::scanLookupSubTable(Guint subTable, Guint orgGID)
2272{
2273  Guint format;
2274  Guint coverage;
2275  int delta;
2276  int glyphCount;
2277  Guint substitute;
2278  Guint gid = 0;
2279  int coverageIndex;
2280  int pos;
2281
2282  pos = subTable;
2283  format = getU16BE(pos,&parsedOk);
2284  pos += 2;
2285  coverage = getU16BE(pos,&parsedOk);
2286  pos += 2;
2287  if ((coverageIndex =
2288     checkGIDInCoverage(subTable+coverage,orgGID)) >= 0) {
2289    switch (format) {
2290    case 1:
2291      /* format 1 */
2292      delta = getS16BE(pos,&parsedOk);
2293      pos += 2;
2294      gid = orgGID+delta;
2295      break;
2296    case 2:
2297      /* format 2 */
2298      glyphCount = getS16BE(pos,&parsedOk);
2299      pos += 2;
2300      if (glyphCount > coverageIndex) {
2301        pos += coverageIndex*2;
2302        substitute = getU16BE(pos,&parsedOk);
2303        gid = substitute;
2304      }
2305      break;
2306    default:
2307      /* unknown format */
2308      break;
2309    }
2310  }
2311  return gid;
2312}
2313
2314int FoFiTrueType::checkGIDInCoverage(Guint coverage, Guint orgGID)
2315{
2316  int index = -1;
2317  Guint format;
2318  Guint count;
2319  Guint i;
2320  Guint pos;
2321
2322  pos = coverage;
2323  format = getU16BE(pos,&parsedOk);
2324  pos += 2;
2325  switch (format) {
2326  case 1:
2327    count = getU16BE(pos,&parsedOk);
2328    pos += 2;
2329    for (i = 0;i < count;i++) {
2330      Guint gid;
2331
2332      gid = getU16BE(pos,&parsedOk);
2333      pos += 2;
2334      if (gid == orgGID) {
2335        /* found */
2336        index = i;
2337        break;
2338      } else if (gid > orgGID) {
2339        /* not found */
2340        break;
2341      }
2342    }
2343    break;
2344  case 2:
2345    count = getU16BE(pos,&parsedOk);
2346    pos += 2;
2347    for (i = 0;i < count;i++) {
2348      Guint startGID, endGID;
2349      Guint startIndex;
2350
2351      startGID = getU16BE(pos,&parsedOk);
2352      pos += 2;
2353      endGID = getU16BE(pos,&parsedOk);
2354      pos += 2;
2355      startIndex = getU16BE(pos,&parsedOk);
2356      pos += 2;
2357      if (startGID <= orgGID && orgGID <= endGID) {
2358        /* found */
2359        index = startIndex+orgGID-startGID;
2360        break;
2361      } else if (orgGID <= endGID) {
2362        /* not found */
2363        break;
2364      }
2365    }
2366    break;
2367  default:
2368    break;
2369  }
2370  return index;
2371}
2372
Note: See TracBrowser for help on using the repository browser.