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

Last change on this file since 277 was 277, checked in by rbri, 12 years ago

PDF plugin: Poppler library updated to version 0.12.3

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