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

Last change on this file since 515 was 515, checked in by Silvan Scherrer, 9 years ago

updated poppler to 0.20.3

File size: 75.0 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, 2012 Albert Astals Cid <aacid@kde.org>
20// Copyright (C) 2008 Tomas Are Haavet <tomasare@gmail.com>
21// Copyright (C) 2012 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
22// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
23//
24// To see a description of the changes please see the Changelog file that
25// came with your tarball or type make ChangeLog if you are building from git
26//
27//========================================================================
28
29#include <config.h>
30
31#ifdef USE_GCC_PRAGMAS
32#pragma implementation
33#endif
34
35#include <stdlib.h>
36#include <string.h>
37#include <algorithm>
38#include "goo/gtypes.h"
39#include "goo/gmem.h"
40#include "goo/GooString.h"
41#include "goo/GooHash.h"
42#include "FoFiType1C.h"
43#include "FoFiTrueType.h"
44#include "poppler/Error.h"
45
46//
47// Terminology
48// -----------
49//
50// character code = number used as an element of a text string
51//
52// character name = glyph name = name for a particular glyph within a
53//                  font
54//
55// glyph index = GID = position (within some internal table in the font)
56//               where the instructions to draw a particular glyph are
57//               stored
58//
59// Type 1 fonts
60// ------------
61//
62// Type 1 fonts contain:
63//
64// Encoding: array of glyph names, maps char codes to glyph names
65//
66//           Encoding[charCode] = charName
67//
68// CharStrings: dictionary of instructions, keyed by character names,
69//              maps character name to glyph data
70//
71//              CharStrings[charName] = glyphData
72//
73// TrueType fonts
74// --------------
75//
76// TrueType fonts contain:
77//
78// 'cmap' table: mapping from character code to glyph index; there may
79//               be multiple cmaps in a TrueType font
80//
81//               cmap[charCode] = gid
82//
83// 'post' table: mapping from glyph index to glyph name
84//
85//               post[gid] = glyphName
86//
87// Type 42 fonts
88// -------------
89//
90// Type 42 fonts contain:
91//
92// Encoding: array of glyph names, maps char codes to glyph names
93//
94//           Encoding[charCode] = charName
95//
96// CharStrings: dictionary of glyph indexes, keyed by character names,
97//              maps character name to glyph index
98//
99//              CharStrings[charName] = gid
100//
101
102//------------------------------------------------------------------------
103
104#define ttcfTag 0x74746366
105
106//------------------------------------------------------------------------
107
108struct TrueTypeTable {
109  Guint tag;
110  Guint checksum;
111  int offset;
112  int origOffset;
113  int len;
114};
115
116struct TrueTypeCmap {
117  int platform;
118  int encoding;
119  int offset;
120  int len;
121  int fmt;
122};
123
124struct TrueTypeLoca {
125  int idx;
126  int origOffset;
127  int newOffset;
128  int len;
129};
130
131#define cmapTag 0x636d6170
132#define glyfTag 0x676c7966
133#define headTag 0x68656164
134#define hheaTag 0x68686561
135#define hmtxTag 0x686d7478
136#define locaTag 0x6c6f6361
137#define nameTag 0x6e616d65
138#define os2Tag  0x4f532f32
139#define postTag 0x706f7374
140#define vrt2Tag 0x76727432
141#define vertTag 0x76657274
142
143struct cmpTrueTypeLocaOffsetFunctor {
144  bool operator()(const TrueTypeLoca &loca1, const TrueTypeLoca &loca2) {
145    if (loca1.origOffset == loca2.origOffset) {
146      return loca1.idx < loca2.idx;
147    }
148    return loca1.origOffset < loca2.origOffset;
149  }
150};
151
152struct cmpTrueTypeLocaIdxFunctor {
153  bool operator()(const TrueTypeLoca &loca1, const TrueTypeLoca &loca2) {
154    return loca1.idx < loca2.idx;
155  }
156};
157
158struct cmpTrueTypeTableTagFunctor {
159  bool operator()(const TrueTypeTable &tab1, const TrueTypeTable &tab2) {
160    return tab1.tag < tab2.tag;
161  }
162};
163
164//------------------------------------------------------------------------
165
166struct T42Table {
167  const 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 const 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",            "mu",
236  "partialdiff",    "summation",      "product",        "pi",
237  "integral",       "ordfeminine",    "ordmasculine",   "Omega",
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
343int FoFiTrueType::mapCodeToGID(int i, Guint c) {
344  int 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
447GBool FoFiTrueType::getCFFBlock(char **start, int *length) {
448  int i;
449
450  if (!openTypeCFF) {
451    return gFalse;
452  }
453  i = seekTable("CFF ");
454  if (!checkRegion(tables[i].offset, tables[i].len)) {
455    return gFalse;
456  }
457  *start = (char *)file + tables[i].offset;
458  *length = tables[i].len;
459  return gTrue;
460}
461
462int *FoFiTrueType::getCIDToGIDMap(int *nCIDs) {
463  char *start;
464  int length;
465  FoFiType1C *ff;
466  int *map;
467
468  *nCIDs = 0;
469  if (!getCFFBlock(&start, &length)) {
470    return NULL;
471  }
472  if (!(ff = FoFiType1C::make(start, length))) {
473    return NULL;
474  }
475  map = ff->getCIDToGIDMap(nCIDs);
476  delete ff;
477  return map;
478}
479
480int FoFiTrueType::getEmbeddingRights() {
481  int i, fsType;
482  GBool ok;
483
484  if ((i = seekTable("OS/2")) < 0) {
485    return 4;
486  }
487  ok = gTrue;
488  fsType = getU16BE(tables[i].offset + 8, &ok);
489  if (!ok) {
490    return 4;
491  }
492  if (fsType & 0x0008) {
493    return 2;
494  }
495  if (fsType & 0x0004) {
496    return 1;
497  }
498  if (fsType & 0x0002) {
499    return 0;
500  }
501  return 3;
502}
503
504void FoFiTrueType::getFontMatrix(double *mat) {
505  char *start;
506  int length;
507  FoFiType1C *ff;
508
509  if (!getCFFBlock(&start, &length)) {
510    return;
511  }
512  if (!(ff = FoFiType1C::make(start, length))) {
513    return;
514  }
515  ff->getFontMatrix(mat);
516  delete ff;
517}
518
519void FoFiTrueType::convertToType42(char *psName, char **encoding,
520                                   int *codeToGID,
521                                   FoFiOutputFunc outputFunc,
522                                   void *outputStream) {
523  GooString *buf;
524  int maxUsedGlyph;
525  GBool ok;
526
527  if (openTypeCFF) {
528    return;
529  }
530
531  // write the header
532  ok = gTrue;
533  buf = GooString::format("%!PS-TrueTypeFont-{0:2g}\n",
534                        (double)getS32BE(0, &ok) / 65536.0);
535  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
536  delete buf;
537
538  // begin the font dictionary
539  (*outputFunc)(outputStream, "10 dict begin\n", 14);
540  (*outputFunc)(outputStream, "/FontName /", 11);
541  (*outputFunc)(outputStream, psName, strlen(psName));
542  (*outputFunc)(outputStream, " def\n", 5);
543  (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
544  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
545  buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
546                        bbox[0], bbox[1], bbox[2], bbox[3]);
547  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
548  delete buf;
549  (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
550
551  // write the guts of the dictionary
552  cvtEncoding(encoding, outputFunc, outputStream);
553  cvtCharStrings(encoding, codeToGID, outputFunc, outputStream);
554  cvtSfnts(outputFunc, outputStream, NULL, gFalse, &maxUsedGlyph);
555
556  // end the dictionary and define the font
557  (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
558}
559
560void FoFiTrueType::convertToType1(char *psName, const char **newEncoding,
561                                  GBool ascii, FoFiOutputFunc outputFunc,
562                                  void *outputStream) {
563  char *start;
564  int length;
565  FoFiType1C *ff;
566
567  if (!getCFFBlock(&start, &length)) {
568    return;
569  }
570  if (!(ff = FoFiType1C::make(start, length))) {
571    return;
572  }
573  ff->convertToType1(psName, newEncoding, ascii, outputFunc, outputStream);
574  delete ff;
575}
576
577void FoFiTrueType::convertToCIDType2(char *psName,
578                                     int *cidMap, int nCIDs,
579                                     GBool needVerticalMetrics,
580                                     FoFiOutputFunc outputFunc,
581                                     void *outputStream) {
582  GooString *buf;
583  int cid, maxUsedGlyph;
584  GBool ok;
585  int i, j, k;
586
587  if (openTypeCFF) {
588    return;
589  }
590
591  // write the header
592  ok = gTrue;
593  buf = GooString::format("%!PS-TrueTypeFont-{0:2g}\n",
594                        (double)getS32BE(0, &ok) / 65536.0);
595  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
596  delete buf;
597
598  // begin the font dictionary
599  (*outputFunc)(outputStream, "20 dict begin\n", 14);
600  (*outputFunc)(outputStream, "/CIDFontName /", 14);
601  (*outputFunc)(outputStream, psName, strlen(psName));
602  (*outputFunc)(outputStream, " def\n", 5);
603  (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19);
604  (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
605  (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
606  (*outputFunc)(outputStream, "  /Registry (Adobe) def\n", 24);
607  (*outputFunc)(outputStream, "  /Ordering (Identity) def\n", 27);
608  (*outputFunc)(outputStream, "  /Supplement 0 def\n", 20);
609  (*outputFunc)(outputStream, "  end def\n", 10);
610  (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
611  if (cidMap) {
612    buf = GooString::format("/CIDCount {0:d} def\n", nCIDs);
613    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
614    delete buf;
615    if (nCIDs > 32767) {
616      (*outputFunc)(outputStream, "/CIDMap [", 9);
617      for (i = 0; i < nCIDs; i += 32768 - 16) {
618        (*outputFunc)(outputStream, "<\n", 2);
619        for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
620          (*outputFunc)(outputStream, "  ", 2);
621          for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
622            cid = cidMap[i+j+k];
623            buf = GooString::format("{0:02x}{1:02x}",
624                                  (cid >> 8) & 0xff, cid & 0xff);
625            (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
626            delete buf;
627          }
628          (*outputFunc)(outputStream, "\n", 1);
629        }
630        (*outputFunc)(outputStream, "  >", 3);
631      }
632      (*outputFunc)(outputStream, "\n", 1);
633      (*outputFunc)(outputStream, "] def\n", 6);
634    } else {
635      (*outputFunc)(outputStream, "/CIDMap <\n", 10);
636      for (i = 0; i < nCIDs; i += 16) {
637        (*outputFunc)(outputStream, "  ", 2);
638        for (j = 0; j < 16 && i+j < nCIDs; ++j) {
639          cid = cidMap[i+j];
640          buf = GooString::format("{0:02x}{1:02x}",
641                                (cid >> 8) & 0xff, cid & 0xff);
642          (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
643          delete buf;
644        }
645        (*outputFunc)(outputStream, "\n", 1);
646      }
647      (*outputFunc)(outputStream, "> def\n", 6);
648    }
649  } else {
650    // direct mapping - just fill the string(s) with s[i]=i
651    buf = GooString::format("/CIDCount {0:d} def\n", nGlyphs);
652    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
653    delete buf;
654    if (nGlyphs > 32767) {
655      (*outputFunc)(outputStream, "/CIDMap [\n", 10);
656      for (i = 0; i < nGlyphs; i += 32767) {
657        j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
658        buf = GooString::format("  {0:d} string 0 1 {1:d} {{\n", 2 * j, j - 1);
659        (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
660        delete buf;
661        buf = GooString::format("    2 copy dup 2 mul exch {0:d} add -8 bitshift put\n",
662                              i);
663        (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
664        delete buf;
665        buf = GooString::format("    1 index exch dup 2 mul 1 add exch {0:d} add"
666                              " 255 and put\n", i);
667        (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
668        delete buf;
669        (*outputFunc)(outputStream, "  } for\n", 8);
670      }
671      (*outputFunc)(outputStream, "] def\n", 6);
672    } else {
673      buf = GooString::format("/CIDMap {0:d} string\n", 2 * nGlyphs);
674      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
675      delete buf;
676      buf = GooString::format("  0 1 {0:d} {{\n", nGlyphs - 1);
677      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
678      delete buf;
679      (*outputFunc)(outputStream,
680                    "    2 copy dup 2 mul exch -8 bitshift put\n", 42);
681      (*outputFunc)(outputStream,
682                    "    1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
683      (*outputFunc)(outputStream, "  } for\n", 8);
684      (*outputFunc)(outputStream, "def\n", 4);
685    }
686  }
687  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
688  buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
689                        bbox[0], bbox[1], bbox[2], bbox[3]);
690  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
691  delete buf;
692  (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
693  (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
694  (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
695  (*outputFunc)(outputStream, "  /.notdef 0 def\n", 17);
696  (*outputFunc)(outputStream, "  end readonly def\n", 19);
697
698  // write the guts of the dictionary
699  cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics, &maxUsedGlyph);
700
701  // end the dictionary and define the font
702  (*outputFunc)(outputStream,
703                "CIDFontName currentdict end /CIDFont defineresource pop\n",
704                56);
705}
706
707void FoFiTrueType::convertToCIDType0(char *psName, int *cidMap, int nCIDs,
708                                     FoFiOutputFunc outputFunc,
709                                     void *outputStream) {
710  char *start;
711  int length;
712  FoFiType1C *ff;
713
714  if (!getCFFBlock(&start, &length)) {
715    return;
716  }
717  if (!(ff = FoFiType1C::make(start, length))) {
718    return;
719  }
720  ff->convertToCIDType0(psName, cidMap, nCIDs, outputFunc, outputStream);
721  delete ff;
722}
723
724void FoFiTrueType::convertToType0(char *psName, int *cidMap, int nCIDs,
725                                  GBool needVerticalMetrics,
726                                  FoFiOutputFunc outputFunc,
727                                  void *outputStream) {
728  GooString *buf;
729  GooString *sfntsName;
730  int maxUsedGlyph, n, i, j;
731
732  if (openTypeCFF) {
733    return;
734  }
735
736  // write the Type 42 sfnts array
737  sfntsName = (new GooString(psName))->append("_sfnts");
738  cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics,
739           &maxUsedGlyph);
740  delete sfntsName;
741
742  // write the descendant Type 42 fonts
743  // (The following is a kludge: nGlyphs is the glyph count from the
744  // maxp table; maxUsedGlyph is the max glyph number that has a
745  // non-zero-length description, from the loca table.  The problem is
746  // that some TrueType font subsets fail to change the glyph count,
747  // i.e., nGlyphs is much larger than maxUsedGlyph+1, which results
748  // in an unnecessarily huge Type 0 font.  But some other PDF files
749  // have fonts with only zero or one used glyph, and a content stream
750  // that refers to one of the unused glyphs -- this results in PS
751  // errors if we simply use maxUsedGlyph+1 for the Type 0 font.  So
752  // we compromise by always defining at least 256 glyphs.)
753  if (cidMap) {
754    n = nCIDs;
755  } else if (nGlyphs > maxUsedGlyph + 256) {
756    if (maxUsedGlyph <= 255) {
757      n = 256;
758    } else {
759      n = maxUsedGlyph + 1;
760    }
761  } else {
762    n = nGlyphs;
763  }
764  for (i = 0; i < n; i += 256) {
765    (*outputFunc)(outputStream, "10 dict begin\n", 14);
766    (*outputFunc)(outputStream, "/FontName /", 11);
767    (*outputFunc)(outputStream, psName, strlen(psName));
768    buf = GooString::format("_{0:02x} def\n", i >> 8);
769    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
770    delete buf;
771    (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
772    (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
773    buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
774                          bbox[0], bbox[1], bbox[2], bbox[3]);
775    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
776    delete buf;
777    (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
778    (*outputFunc)(outputStream, "/sfnts ", 7);
779    (*outputFunc)(outputStream, psName, strlen(psName));
780    (*outputFunc)(outputStream, "_sfnts def\n", 11);
781    (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
782    for (j = 0; j < 256 && i+j < n; ++j) {
783      buf = GooString::format("dup {0:d} /c{1:02x} put\n", j, j);
784      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
785      delete buf;
786    }
787    (*outputFunc)(outputStream, "readonly def\n", 13);
788    (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
789    (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
790    for (j = 0; j < 256 && i+j < n; ++j) {
791      buf = GooString::format("/c{0:02x} {1:d} def\n",
792                            j, cidMap ? cidMap[i+j] : i+j);
793      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
794      delete buf;
795    }
796    (*outputFunc)(outputStream, "end readonly def\n", 17);
797    (*outputFunc)(outputStream,
798                  "FontName currentdict end definefont pop\n", 40);
799  }
800
801  // write the Type 0 parent font
802  (*outputFunc)(outputStream, "16 dict begin\n", 14);
803  (*outputFunc)(outputStream, "/FontName /", 11);
804  (*outputFunc)(outputStream, psName, strlen(psName));
805  (*outputFunc)(outputStream, " def\n", 5);
806  (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
807  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
808  (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
809  (*outputFunc)(outputStream, "/Encoding [\n", 12);
810  for (i = 0; i < n; i += 256) {
811    buf = GooString::format("{0:d}\n", i >> 8);
812    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
813    delete buf;
814  }
815  (*outputFunc)(outputStream, "] def\n", 6);
816  (*outputFunc)(outputStream, "/FDepVector [\n", 14);
817  for (i = 0; i < n; i += 256) {
818    (*outputFunc)(outputStream, "/", 1);
819    (*outputFunc)(outputStream, psName, strlen(psName));
820    buf = GooString::format("_{0:02x} findfont\n", i >> 8);
821    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
822    delete buf;
823  }
824  (*outputFunc)(outputStream, "] def\n", 6);
825  (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
826}
827
828void FoFiTrueType::convertToType0(char *psName, int *cidMap, int nCIDs,
829                                  FoFiOutputFunc outputFunc,
830                                  void *outputStream) {
831  char *start;
832  int length;
833  FoFiType1C *ff;
834
835  if (!getCFFBlock(&start, &length)) {
836    return;
837  }
838  if (!(ff = FoFiType1C::make(start, length))) {
839    return;
840  }
841  ff->convertToType0(psName, cidMap, nCIDs, outputFunc, outputStream);
842  delete ff;
843}
844
845void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
846                            void *outputStream, char *name,
847                            int *codeToGID) {
848  // this substitute cmap table maps char code ffff to glyph 0,
849  // with tables for MacRoman and MS Unicode
850  static char cmapTab[44] = {
851    0, 0,                       // table version number
852    0, 2,                       // number of encoding tables
853    0, 1,                       // platform ID
854    0, 0,                       // encoding ID
855    0, 0, 0, 20,                // offset of subtable
856    0, 3,                       // platform ID
857    0, 1,                       // encoding ID
858    0, 0, 0, 20,                // offset of subtable
859    0, 4,                       // subtable format
860    0, 24,                      // subtable length
861    0, 0,                       // subtable version
862    0, 2,                       // segment count * 2
863    0, 2,                       // 2 * 2 ^ floor(log2(segCount))
864    0, 0,                       // floor(log2(segCount))
865    0, 0,                       // 2*segCount - 2*2^floor(log2(segCount))
866    (char)0xff, (char)0xff,     // endCount[0]
867    0, 0,                       // reserved
868    (char)0xff, (char)0xff,     // startCount[0]
869    0, 1,                       // idDelta[0]
870    0, 0                        // idRangeOffset[0]
871  };
872  static char nameTab[8] = {
873    0, 0,                       // format
874    0, 0,                       // number of name records
875    0, 6,                       // offset to start of string storage
876    0, 0                        // pad to multiple of four bytes
877  };
878  static char postTab[32] = {
879    0, 1, 0, 0,                 // format
880    0, 0, 0, 0,                 // italic angle
881    0, 0,                       // underline position
882    0, 0,                       // underline thickness
883    0, 0, 0, 0,                 // fixed pitch
884    0, 0, 0, 0,                 // min Type 42 memory
885    0, 0, 0, 0,                 // max Type 42 memory
886    0, 0, 0, 0,                 // min Type 1 memory
887    0, 0, 0, 0                  // max Type 1 memory
888  };
889  static char os2Tab[86] = {
890    0, 1,                       // version
891    0, 1,                       // xAvgCharWidth
892    0x01, (char)0x90,           // usWeightClass
893    0, 5,                       // usWidthClass
894    0, 0,                       // fsType
895    0, 0,                       // ySubscriptXSize
896    0, 0,                       // ySubscriptYSize
897    0, 0,                       // ySubscriptXOffset
898    0, 0,                       // ySubscriptYOffset
899    0, 0,                       // ySuperscriptXSize
900    0, 0,                       // ySuperscriptYSize
901    0, 0,                       // ySuperscriptXOffset
902    0, 0,                       // ySuperscriptYOffset
903    0, 0,                       // yStrikeoutSize
904    0, 0,                       // yStrikeoutPosition
905    0, 0,                       // sFamilyClass
906    0, 0, 0, 0, 0,              // panose
907    0, 0, 0, 0, 0,
908    0, 0, 0, 0,                 // ulUnicodeRange1
909    0, 0, 0, 0,                 // ulUnicodeRange2
910    0, 0, 0, 0,                 // ulUnicodeRange3
911    0, 0, 0, 0,                 // ulUnicodeRange4
912    0, 0, 0, 0,                 // achVendID
913    0, 0,                       // fsSelection
914    0, 0,                       // usFirstCharIndex
915    0, 0,                       // usLastCharIndex
916    0, 0,                       // sTypoAscender
917    0, 0,                       // sTypoDescender
918    0, 0,                       // sTypoLineGap
919    0x20, 0x00,                 // usWinAscent
920    0x20, 0x00,                 // usWinDescent
921    0, 0, 0, 1,                 // ulCodePageRange1
922    0, 0, 0, 0                  // ulCodePageRange2
923  };
924  GBool missingCmap, missingName, missingPost, missingOS2;
925  GBool unsortedLoca, emptyCmap, badCmapLen, abbrevHMTX;
926  int nZeroLengthTables, nBogusTables;
927  int nHMetrics, advWidth, lsb;
928  TrueTypeLoca *locaTable;
929  TrueTypeTable *newTables;
930  char *newNameTab, *newCmapTab, *newHHEATab, *newHMTXTab;
931  int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next;
932  int newHHEALen, newHMTXLen;
933  Guint locaChecksum, glyfChecksum, fileChecksum;
934  char *tableDir;
935  char locaBuf[4], checksumBuf[4];
936  GBool ok;
937  Guint t;
938  int pos, i, j, k, n;
939
940  if (openTypeCFF) {
941    return;
942  }
943
944  if (tables == NULL) {
945    return;
946  }
947
948  // check for missing tables
949  // (Note: if the OS/2 table is missing, the Microsoft PCL5 driver
950  // will embed a PCL TrueType font with the pitch field set to zero,
951  // which apparently causes divide-by-zero errors.  As far as I can
952  // tell, the only important field in the OS/2 table is
953  // xAvgCharWidth.)
954  missingCmap = (cmapIdx = seekTable("cmap")) < 0;
955  missingName = seekTable("name") < 0;
956  missingPost = seekTable("post") < 0;
957  missingOS2 = seekTable("OS/2") < 0;
958
959  // read the loca table, check to see if it's sorted
960  locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
961  unsortedLoca = gFalse;
962  i = seekTable("loca");
963  pos = tables[i].offset;
964  ok = gTrue;
965  for (i = 0; i <= nGlyphs; ++i) {
966    if (locaFmt) {
967      locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
968    } else {
969      locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
970    }
971    if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) {
972      unsortedLoca = gTrue;
973    }
974    // glyph descriptions must be at least 12 bytes long (nContours,
975    // xMin, yMin, xMax, yMax, instructionLength - two bytes each);
976    // invalid glyph descriptions (even if they're never used) make
977    // Windows choke, so we work around that problem here (ideally,
978    // this would parse the glyph descriptions in the glyf table and
979    // remove any that were invalid, but this quick test is a decent
980    // start)
981    if (i > 0 &&
982        locaTable[i].origOffset - locaTable[i-1].origOffset > 0 &&
983        locaTable[i].origOffset - locaTable[i-1].origOffset < 12) {
984      locaTable[i-1].origOffset = locaTable[i].origOffset;
985      unsortedLoca = gTrue;
986    }
987    locaTable[i].idx = i;
988  }
989
990  // check for zero-length tables and bogus tags
991  nZeroLengthTables = nBogusTables = 0;
992  for (i = 0; i < nTables; ++i) {
993    if (tables[i].len == 0) {
994      ++nZeroLengthTables;
995      if (tables[i].tag == cmapTag) {
996        missingCmap = gTrue;
997      } else if (tables[i].tag == nameTag) {
998        missingName = gTrue;
999      } else if (tables[i].tag == postTag) {
1000        missingPost = gTrue;
1001      } else if (tables[i].tag == os2Tag) {
1002        missingOS2 = gTrue;
1003      }
1004    } else if (!(tables[i].tag & 0xe0000000) ||
1005               !(tables[i].tag & 0x00e00000) ||
1006               !(tables[i].tag & 0x0000e000) ||
1007               !(tables[i].tag & 0x000000e0)) {
1008      // tags where any of the bytes are < 0x20 are probably bogus
1009      // (the TrueType spec uses ASCII sequences for tags) -- this
1010      // catches problems where the number of tables given in the
1011      // header is too large, and so gibberish data is read at the end
1012      // of the table directory
1013      ++nBogusTables;
1014    }
1015  }
1016
1017  // check for an empty cmap table or an incorrect cmap table length
1018  emptyCmap = badCmapLen = gFalse;
1019  cmapLen = 0; // make gcc happy
1020  if (!missingCmap) {
1021    if (nCmaps == 0) {
1022      emptyCmap = gTrue;
1023    } else {
1024      cmapLen = cmaps[0].offset + cmaps[0].len;
1025      for (i = 1; i < nCmaps; ++i) {
1026        if (cmaps[i].offset + cmaps[i].len > cmapLen) {
1027          cmapLen = cmaps[i].offset + cmaps[i].len;
1028        }
1029      }
1030      cmapLen -= tables[cmapIdx].offset;
1031      if (cmapLen > tables[cmapIdx].len) {
1032        badCmapLen = gTrue;
1033      }
1034    }
1035  }
1036
1037  // check for an abbreviated hmtx table (this is completely legal,
1038  // but confuses the Microsoft PCL5 printer driver, which generates
1039  // embedded fonts with the pitch field set to zero)
1040  i = seekTable("hhea");
1041  nHMetrics = getU16BE(tables[i].offset + 34, &ok);
1042  abbrevHMTX = nHMetrics < nGlyphs;
1043
1044  // if nothing is broken, just write the TTF file as is
1045  if (!missingCmap && !missingName && !missingPost && !missingOS2 &&
1046      !unsortedLoca && !emptyCmap && !badCmapLen && !abbrevHMTX &&
1047      nZeroLengthTables == 0 && nBogusTables == 0 &&
1048      !name && !codeToGID) {
1049    (*outputFunc)(outputStream, (char *)file, len);
1050    goto done1;
1051  }
1052
1053  // sort the 'loca' table: some (non-compliant) fonts have
1054  // out-of-order loca tables; in order to correctly handle the case
1055  // where (compliant) fonts have empty entries in the middle of the
1056  // table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
1057  // and idx as its secondary key (ensuring that adjacent entries with
1058  // the same pos value remain in the same order)
1059  glyfLen = 0; // make gcc happy
1060  if (unsortedLoca) {
1061    std::sort(locaTable, locaTable + nGlyphs + 1,
1062              cmpTrueTypeLocaOffsetFunctor());
1063    for (i = 0; i < nGlyphs; ++i) {
1064      locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
1065    }
1066    locaTable[nGlyphs].len = 0;
1067    std::sort(locaTable, locaTable + nGlyphs + 1, cmpTrueTypeLocaIdxFunctor());
1068    // if the last entry in the loca is not the max offset (size of
1069    // the glyf table), something is wrong -- work around the problem
1070    // by forcing the last sorted entry to have a zero length
1071    locaTable[nGlyphs].len = 0;
1072    pos = 0;
1073    for (i = 0; i <= nGlyphs; ++i) {
1074      locaTable[i].newOffset = pos;
1075      pos += locaTable[i].len;
1076      if (pos & 3) {
1077        pos += 4 - (pos & 3);
1078      }
1079    }
1080    glyfLen = pos;
1081  }
1082
1083  // compute checksums for the loca and glyf tables
1084  locaChecksum = glyfChecksum = 0;
1085  if (unsortedLoca) {
1086    if (locaFmt) {
1087      for (j = 0; j <= nGlyphs; ++j) {
1088        locaChecksum += locaTable[j].newOffset;
1089      }
1090    } else {
1091      for (j = 0; j <= nGlyphs; j += 2) {
1092        locaChecksum += locaTable[j].newOffset << 16;
1093        if (j + 1 <= nGlyphs) {
1094          locaChecksum += locaTable[j+1].newOffset;
1095        }
1096      }
1097    }
1098    pos = tables[seekTable("glyf")].offset;
1099    for (j = 0; j < nGlyphs; ++j) {
1100      n = locaTable[j].len;
1101      if (n > 0) {
1102        k = locaTable[j].origOffset;
1103        if (checkRegion(pos + k, n)) {
1104          glyfChecksum += computeTableChecksum(file + pos + k, n);
1105        }
1106      }
1107    }
1108  }
1109
1110  // construct the new name table
1111  if (name) {
1112    n = strlen(name);
1113    newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3;
1114    newNameTab = (char *)gmalloc(newNameLen);
1115    memset(newNameTab, 0, newNameLen);
1116    newNameTab[0] = 0;          // format selector
1117    newNameTab[1] = 0;
1118    newNameTab[2] = 0;          // number of name records
1119    newNameTab[3] = 4;
1120    newNameTab[4] = 0;          // offset to start of string storage
1121    newNameTab[5] = 6 + 4*12;
1122    next = 0;
1123    for (i = 0; i < 4; ++i) {
1124      newNameTab[6 + i*12 + 0] = 0;     // platform ID = Microsoft
1125      newNameTab[6 + i*12 + 1] = 3;
1126      newNameTab[6 + i*12 + 2] = 0;     // encoding ID = Unicode
1127      newNameTab[6 + i*12 + 3] = 1;
1128      newNameTab[6 + i*12 + 4] = 0x04;  // language ID = American English
1129      newNameTab[6 + i*12 + 5] = 0x09;
1130      newNameTab[6 + i*12 + 6] = 0;     // name ID
1131      newNameTab[6 + i*12 + 7] = i + 1;
1132      newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length
1133      newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff);
1134      newNameTab[6 + i*12 + 10] = next >> 8;                // string offset
1135      newNameTab[6 + i*12 + 11] = next & 0xff;
1136      if (i+1 == 2) {
1137        memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14);
1138        next += 14;
1139      } else {
1140        for (j = 0; j < n; ++j) {
1141          newNameTab[6 + 4*12 + next + 2*j] = 0;
1142          newNameTab[6 + 4*12 + next + 2*j + 1] = name[j];
1143        }
1144        next += 2*n;
1145      }
1146    }
1147  } else {
1148    newNameLen = 0;
1149    newNameTab = NULL;
1150  }
1151
1152  // construct the new cmap table
1153  if (codeToGID) {
1154    newCmapLen = 44 + 256 * 2;
1155    newCmapTab = (char *)gmalloc(newCmapLen);
1156    newCmapTab[0] = 0;          // table version number = 0
1157    newCmapTab[1] = 0;
1158    newCmapTab[2] = 0;          // number of encoding tables = 1
1159    newCmapTab[3] = 1;
1160    newCmapTab[4] = 0;          // platform ID = Microsoft
1161    newCmapTab[5] = 3;
1162    newCmapTab[6] = 0;          // encoding ID = Unicode
1163    newCmapTab[7] = 1;
1164    newCmapTab[8] = 0;          // offset of subtable
1165    newCmapTab[9] = 0;
1166    newCmapTab[10] = 0;
1167    newCmapTab[11] = 12;
1168    newCmapTab[12] = 0;         // subtable format = 4
1169    newCmapTab[13] = 4;
1170    newCmapTab[14] = 0x02;      // subtable length
1171    newCmapTab[15] = 0x20;
1172    newCmapTab[16] = 0;         // subtable version = 0
1173    newCmapTab[17] = 0;
1174    newCmapTab[18] = 0;         // segment count * 2
1175    newCmapTab[19] = 4;
1176    newCmapTab[20] = 0;         // 2 * 2 ^ floor(log2(segCount))
1177    newCmapTab[21] = 4;
1178    newCmapTab[22] = 0;         // floor(log2(segCount))
1179    newCmapTab[23] = 1;
1180    newCmapTab[24] = 0;         // 2*segCount - 2*2^floor(log2(segCount))
1181    newCmapTab[25] = 0;
1182    newCmapTab[26] = 0x00;      // endCount[0]
1183    newCmapTab[27] = (char)0xff;
1184    newCmapTab[28] = (char)0xff; // endCount[1]
1185    newCmapTab[29] = (char)0xff;
1186    newCmapTab[30] = 0;         // reserved
1187    newCmapTab[31] = 0;
1188    newCmapTab[32] = 0x00;      // startCount[0]
1189    newCmapTab[33] = 0x00;
1190    newCmapTab[34] = (char)0xff; // startCount[1]
1191    newCmapTab[35] = (char)0xff;
1192    newCmapTab[36] = 0;         // idDelta[0]
1193    newCmapTab[37] = 0;
1194    newCmapTab[38] = 0;         // idDelta[1]
1195    newCmapTab[39] = 1;
1196    newCmapTab[40] = 0;         // idRangeOffset[0]
1197    newCmapTab[41] = 4;
1198    newCmapTab[42] = 0;         // idRangeOffset[1]
1199    newCmapTab[43] = 0;
1200    for (i = 0; i < 256; ++i) {
1201      if (codeToGID[i] < 0) {
1202        //~ this may not be correct - we want this character to never be
1203        //~ displayed, but mapping it to the notdef glyph may result in
1204        //~ little boxes being displayed
1205        newCmapTab[44 + 2*i] = 0;
1206        newCmapTab[44 + 2*i + 1] = 0;
1207      } else {
1208        newCmapTab[44 + 2*i] = codeToGID[i] >> 8;
1209        newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff;
1210      }
1211    }
1212  } else {
1213    newCmapLen = 0;
1214    newCmapTab = NULL;
1215  }
1216
1217  // generate the new hmtx table and the updated hhea table
1218  if (abbrevHMTX) {
1219    i = seekTable("hhea");
1220    pos = tables[i].offset;
1221    newHHEALen = 36;
1222    newHHEATab = (char *)gmalloc(newHHEALen);
1223    for (i = 0; i < newHHEALen; ++i) {
1224      newHHEATab[i] = getU8(pos++, &ok);
1225    }
1226    newHHEATab[34] = nGlyphs >> 8;
1227    newHHEATab[35] = nGlyphs & 0xff;
1228    i = seekTable("hmtx");
1229    pos = tables[i].offset;
1230    newHMTXLen = 4 * nGlyphs;
1231    newHMTXTab = (char *)gmalloc(newHMTXLen);
1232    advWidth = 0;
1233    for (i = 0; i < nHMetrics; ++i) {
1234      advWidth = getU16BE(pos, &ok);
1235      lsb = getU16BE(pos + 2, &ok);
1236      pos += 4;
1237      newHMTXTab[4*i    ] = advWidth >> 8;
1238      newHMTXTab[4*i + 1] = advWidth & 0xff;
1239      newHMTXTab[4*i + 2] = lsb >> 8;
1240      newHMTXTab[4*i + 3] = lsb & 0xff;
1241    }
1242    for (; i < nGlyphs; ++i) {
1243      lsb = getU16BE(pos, &ok);
1244      pos += 2;
1245      newHMTXTab[4*i    ] = advWidth >> 8;
1246      newHMTXTab[4*i + 1] = advWidth & 0xff;
1247      newHMTXTab[4*i + 2] = lsb >> 8;
1248      newHMTXTab[4*i + 3] = lsb & 0xff;
1249    }
1250  } else {
1251    newHHEATab = newHMTXTab = NULL;
1252    newHHEALen = newHMTXLen = 0; // make gcc happy
1253  }
1254
1255  // construct the new table directory:
1256  // - keep all original tables with non-zero length
1257  // - fix the cmap table's length, if necessary
1258  // - add missing tables
1259  // - sort the table by tag
1260  // - compute new table positions, including 4-byte alignment
1261  // - (re)compute table checksums
1262  nNewTables = nTables - nZeroLengthTables - nBogusTables +
1263               (missingCmap ? 1 : 0) + (missingName ? 1 : 0) +
1264               (missingPost ? 1 : 0) + (missingOS2 ? 1 : 0);
1265  newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable));
1266  j = 0;
1267  for (i = 0; i < nTables; ++i) {
1268    if (tables[i].len > 0 &&
1269        (tables[i].tag & 0xe0000000) &&
1270        (tables[i].tag & 0x00e00000) &&
1271        (tables[i].tag & 0x0000e000) &&
1272        (tables[i].tag & 0x000000e0)) {
1273      newTables[j] = tables[i];
1274      newTables[j].origOffset = tables[i].offset;
1275      if (checkRegion(tables[i].offset, tables[i].len)) {
1276        newTables[j].checksum =
1277            computeTableChecksum(file + tables[i].offset, tables[i].len);
1278        if (tables[i].tag == headTag) {
1279          // don't include the file checksum
1280          newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok);
1281        }
1282      }
1283      if (newTables[j].tag == cmapTag && codeToGID) {
1284        newTables[j].len = newCmapLen;
1285        newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
1286                                                     newCmapLen);
1287      } else if (newTables[j].tag == cmapTag && emptyCmap) {
1288        newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab,
1289                                                     sizeof(cmapTab));
1290        newTables[j].len = sizeof(cmapTab);
1291      } else if (newTables[j].tag == cmapTag && badCmapLen) {
1292        newTables[j].len = cmapLen;
1293      } else if (newTables[j].tag == locaTag && unsortedLoca) {
1294        newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1295        newTables[j].checksum = locaChecksum;
1296      } else if (newTables[j].tag == glyfTag && unsortedLoca) {
1297        newTables[j].len = glyfLen;
1298        newTables[j].checksum = glyfChecksum;
1299      } else if (newTables[j].tag == nameTag && name) {
1300        newTables[j].len = newNameLen;
1301        newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
1302                                                     newNameLen);
1303      } else if (newTables[j].tag == hheaTag && abbrevHMTX) {
1304        newTables[j].len = newHHEALen;
1305        newTables[j].checksum = computeTableChecksum((Guchar *)newHHEATab,
1306                                                     newHHEALen);
1307      } else if (newTables[j].tag == hmtxTag && abbrevHMTX) {
1308        newTables[j].len = newHMTXLen;
1309        newTables[j].checksum = computeTableChecksum((Guchar *)newHMTXTab,
1310                                                     newHMTXLen);
1311      }
1312      ++j;
1313    }
1314  }
1315  if (missingCmap) {
1316    newTables[j].tag = cmapTag;
1317    if (codeToGID) {
1318      newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
1319                                                   newCmapLen);
1320      newTables[j].len = newCmapLen;
1321    } else {
1322      newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab,
1323                                                   sizeof(cmapTab));
1324      newTables[j].len = sizeof(cmapTab);
1325    }
1326    ++j;
1327  }
1328  if (missingName) {
1329    newTables[j].tag = nameTag;
1330    if (name) {
1331      newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
1332                                                   newNameLen);
1333      newTables[j].len = newNameLen;
1334    } else {
1335      newTables[j].checksum = computeTableChecksum((Guchar *)nameTab,
1336                                                   sizeof(nameTab));
1337      newTables[j].len = sizeof(nameTab);
1338    }
1339    ++j;
1340  }
1341  if (missingPost) {
1342    newTables[j].tag = postTag;
1343    newTables[j].checksum = computeTableChecksum((Guchar *)postTab,
1344                                                 sizeof(postTab));
1345    newTables[j].len = sizeof(postTab);
1346    ++j;
1347  }
1348  if (missingOS2) {
1349    newTables[j].tag = os2Tag;
1350    newTables[j].checksum = computeTableChecksum((Guchar *)os2Tab,
1351                                                 sizeof(os2Tab));
1352    newTables[j].len = sizeof(os2Tab);
1353    ++j;
1354  }
1355  std::sort(newTables, newTables + nNewTables, cmpTrueTypeTableTagFunctor());
1356  pos = 12 + nNewTables * 16;
1357  for (i = 0; i < nNewTables; ++i) {
1358    newTables[i].offset = pos;
1359    pos += newTables[i].len;
1360    if (pos & 3) {
1361      pos += 4 - (pos & 3);
1362    }
1363  }
1364
1365  // write the table directory
1366  tableDir = (char *)gmalloc(12 + nNewTables * 16);
1367  tableDir[0] = 0x00;                                   // sfnt version
1368  tableDir[1] = 0x01;
1369  tableDir[2] = 0x00;
1370  tableDir[3] = 0x00;
1371  tableDir[4] = (char)((nNewTables >> 8) & 0xff);       // numTables
1372  tableDir[5] = (char)(nNewTables & 0xff);
1373  for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ;
1374  t = 1 << (4 + i);
1375  tableDir[6] = (char)((t >> 8) & 0xff);                // searchRange
1376  tableDir[7] = (char)(t & 0xff);
1377  tableDir[8] = (char)((i >> 8) & 0xff);                // entrySelector
1378  tableDir[9] = (char)(i & 0xff);
1379  t = nNewTables * 16 - t;
1380  tableDir[10] = (char)((t >> 8) & 0xff);               // rangeShift
1381  tableDir[11] = (char)(t & 0xff);
1382  pos = 12;
1383  for (i = 0; i < nNewTables; ++i) {
1384    tableDir[pos   ] = (char)(newTables[i].tag >> 24);
1385    tableDir[pos+ 1] = (char)(newTables[i].tag >> 16);
1386    tableDir[pos+ 2] = (char)(newTables[i].tag >>  8);
1387    tableDir[pos+ 3] = (char) newTables[i].tag;
1388    tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24);
1389    tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16);
1390    tableDir[pos+ 6] = (char)(newTables[i].checksum >>  8);
1391    tableDir[pos+ 7] = (char) newTables[i].checksum;
1392    tableDir[pos+ 8] = (char)(newTables[i].offset >> 24);
1393    tableDir[pos+ 9] = (char)(newTables[i].offset >> 16);
1394    tableDir[pos+10] = (char)(newTables[i].offset >>  8);
1395    tableDir[pos+11] = (char) newTables[i].offset;
1396    tableDir[pos+12] = (char)(newTables[i].len >> 24);
1397    tableDir[pos+13] = (char)(newTables[i].len >> 16);
1398    tableDir[pos+14] = (char)(newTables[i].len >>  8);
1399    tableDir[pos+15] = (char) newTables[i].len;
1400    pos += 16;
1401  }
1402  (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16);
1403
1404  // compute the file checksum
1405  fileChecksum = computeTableChecksum((Guchar *)tableDir,
1406                                      12 + nNewTables * 16);
1407  for (i = 0; i < nNewTables; ++i) {
1408    fileChecksum += newTables[i].checksum;
1409  }
1410  fileChecksum = 0xb1b0afba - fileChecksum;
1411
1412  // write the tables
1413  for (i = 0; i < nNewTables; ++i) {
1414    if (newTables[i].tag == headTag) {
1415      if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
1416        (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8);
1417        checksumBuf[0] = fileChecksum >> 24;
1418        checksumBuf[1] = fileChecksum >> 16;
1419        checksumBuf[2] = fileChecksum >> 8;
1420        checksumBuf[3] = fileChecksum;
1421        (*outputFunc)(outputStream, checksumBuf, 4);
1422        (*outputFunc)(outputStream,
1423                      (char *)file + newTables[i].origOffset + 12,
1424                      newTables[i].len - 12);
1425      } else {
1426        for (j = 0; j < newTables[i].len; ++j) {
1427          (*outputFunc)(outputStream, "\0", 1);
1428        }
1429      }
1430    } else if (newTables[i].tag == cmapTag && codeToGID) {
1431      (*outputFunc)(outputStream, newCmapTab, newTables[i].len);
1432    } else if (newTables[i].tag == cmapTag && missingCmap) {
1433      (*outputFunc)(outputStream, cmapTab, newTables[i].len);
1434    } else if (newTables[i].tag == nameTag && name) {
1435      (*outputFunc)(outputStream, newNameTab, newTables[i].len);
1436    } else if (newTables[i].tag == nameTag && missingName) {
1437      (*outputFunc)(outputStream, nameTab, newTables[i].len);
1438    } else if (newTables[i].tag == postTag && missingPost) {
1439      (*outputFunc)(outputStream, postTab, newTables[i].len);
1440    } else if (newTables[i].tag == os2Tag && missingOS2) {
1441      (*outputFunc)(outputStream, os2Tab, newTables[i].len);
1442    } else if (newTables[i].tag == hheaTag && abbrevHMTX) {
1443      (*outputFunc)(outputStream, newHHEATab, newTables[i].len);
1444    } else if (newTables[i].tag == hmtxTag && abbrevHMTX) {
1445      (*outputFunc)(outputStream, newHMTXTab, newTables[i].len);
1446    } else if (newTables[i].tag == locaTag && unsortedLoca) {
1447      for (j = 0; j <= nGlyphs; ++j) {
1448        if (locaFmt) {
1449          locaBuf[0] = (char)(locaTable[j].newOffset >> 24);
1450          locaBuf[1] = (char)(locaTable[j].newOffset >> 16);
1451          locaBuf[2] = (char)(locaTable[j].newOffset >>  8);
1452          locaBuf[3] = (char) locaTable[j].newOffset;
1453          (*outputFunc)(outputStream, locaBuf, 4);
1454        } else {
1455          locaBuf[0] = (char)(locaTable[j].newOffset >> 9);
1456          locaBuf[1] = (char)(locaTable[j].newOffset >> 1);
1457          (*outputFunc)(outputStream, locaBuf, 2);
1458        }
1459      }
1460    } else if (newTables[i].tag == glyfTag && unsortedLoca) {
1461      pos = tables[seekTable("glyf")].offset;
1462      for (j = 0; j < nGlyphs; ++j) {
1463        n = locaTable[j].len;
1464        if (n > 0) {
1465          k = locaTable[j].origOffset;
1466          if (checkRegion(pos + k, n)) {
1467            (*outputFunc)(outputStream, (char *)file + pos + k, n);
1468          } else {
1469            for (k = 0; k < n; ++k) {
1470              (*outputFunc)(outputStream, "\0", 1);
1471            }
1472          }
1473          if ((k = locaTable[j].len & 3)) {
1474            (*outputFunc)(outputStream, "\0\0\0\0", 4 - k);
1475          }
1476        }
1477      }
1478    } else {
1479      if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
1480        (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset,
1481                      newTables[i].len);
1482      } else {
1483        for (j = 0; j < newTables[i].len; ++j) {
1484          (*outputFunc)(outputStream, "\0", 1);
1485        }
1486      }
1487    }
1488    if (newTables[i].len & 3) {
1489      (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3));
1490    }
1491  }
1492
1493  gfree(newHMTXTab);
1494  gfree(newHHEATab);
1495  gfree(newCmapTab);
1496  gfree(newNameTab);
1497  gfree(tableDir);
1498  gfree(newTables);
1499 done1:
1500  gfree(locaTable);
1501}
1502
1503void FoFiTrueType::cvtEncoding(char **encoding,
1504                               FoFiOutputFunc outputFunc,
1505                               void *outputStream) {
1506  const char *name;
1507  GooString *buf;
1508  int i;
1509
1510  (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
1511  if (encoding) {
1512    for (i = 0; i < 256; ++i) {
1513      if (!(name = encoding[i])) {
1514        name = ".notdef";
1515      }
1516      buf = GooString::format("dup {0:d} /", i);
1517      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
1518      delete buf;
1519      (*outputFunc)(outputStream, name, strlen(name));
1520      (*outputFunc)(outputStream, " put\n", 5);
1521    }
1522  } else {
1523    for (i = 0; i < 256; ++i) {
1524      buf = GooString::format("dup {0:d} /c{1:02x} put\n", i, i);
1525      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
1526      delete buf;
1527    }
1528  }
1529  (*outputFunc)(outputStream, "readonly def\n", 13);
1530}
1531
1532void FoFiTrueType::cvtCharStrings(char **encoding,
1533                                  int *codeToGID,
1534                                  FoFiOutputFunc outputFunc,
1535                                  void *outputStream) {
1536  char *name;
1537  GooString *buf;
1538  char buf2[16];
1539  int i, k;
1540
1541  // always define '.notdef'
1542  (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32);
1543  (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
1544
1545  // if there's no 'cmap' table, punt
1546  if (nCmaps == 0) {
1547    goto err;
1548  }
1549
1550  // map char name to glyph index:
1551  // 1. use encoding to map name to char code
1552  // 2. use codeToGID to map char code to glyph index
1553  // N.B. We do this in reverse order because font subsets can have
1554  //      weird encodings that use the same character name twice, and
1555  //      the first definition is probably the one we want.
1556  k = 0; // make gcc happy
1557  for (i = 255; i >= 0; --i) {
1558    if (encoding) {
1559      name = encoding[i];
1560    } else {
1561      sprintf(buf2, "c%02x", i);
1562      name = buf2;
1563    }
1564    if (name && strcmp(name, ".notdef")) {
1565      k = codeToGID[i];
1566      // note: Distiller (maybe Adobe's PS interpreter in general)
1567      // doesn't like TrueType fonts that have CharStrings entries
1568      // which point to nonexistent glyphs, hence the (k < nGlyphs)
1569      // test
1570      if (k > 0 && k < nGlyphs) {
1571        (*outputFunc)(outputStream, "/", 1);
1572        (*outputFunc)(outputStream, name, strlen(name));
1573        buf = GooString::format(" {0:d} def\n", k);
1574        (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
1575        delete buf;
1576      }
1577    }
1578  }
1579
1580 err:
1581  (*outputFunc)(outputStream, "end readonly def\n", 17);
1582}
1583
1584void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
1585                            void *outputStream, GooString *name,
1586                            GBool needVerticalMetrics,
1587                            int *maxUsedGlyph) {
1588  Guchar headData[54];
1589  TrueTypeLoca *locaTable;
1590  Guchar *locaData;
1591  TrueTypeTable newTables[nT42Tables];
1592  Guchar tableDir[12 + nT42Tables*16];
1593  GBool ok;
1594  Guint checksum;
1595  int nNewTables;
1596  int glyfTableLen, length, pos, glyfPos, i, j, k;
1597  Guchar vheaTab[36] = {
1598    0, 1, 0, 0,                 // table version number
1599    0, 0,                       // ascent
1600    0, 0,                       // descent
1601    0, 0,                       // reserved
1602    0, 0,                       // max advance height
1603    0, 0,                       // min top side bearing
1604    0, 0,                       // min bottom side bearing
1605    0, 0,                       // y max extent
1606    0, 0,                       // caret slope rise
1607    0, 1,                       // caret slope run
1608    0, 0,                       // caret offset
1609    0, 0,                       // reserved
1610    0, 0,                       // reserved
1611    0, 0,                       // reserved
1612    0, 0,                       // reserved
1613    0, 0,                       // metric data format
1614    0, 1                        // number of advance heights in vmtx table
1615  };
1616  Guchar *vmtxTab;
1617  GBool needVhea, needVmtx;
1618  int advance;
1619
1620  // construct the 'head' table, zero out the font checksum
1621  i = seekTable("head");
1622  if (i < 0 || i >= nTables) {
1623    return;
1624  }
1625  pos = tables[i].offset;
1626  if (!checkRegion(pos, 54)) {
1627    return;
1628  }
1629  memcpy(headData, file + pos, 54);
1630  headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0;
1631
1632  // check for a bogus loca format field in the 'head' table
1633  // (I've encountered fonts with loca format set to 0x0100 instead of 0x0001)
1634  if (locaFmt != 0 && locaFmt != 1) {
1635    headData[50] = 0;
1636    headData[51] = 1;
1637  }
1638
1639  // read the original 'loca' table, pad entries out to 4 bytes, and
1640  // sort it into proper order -- some (non-compliant) fonts have
1641  // out-of-order loca tables; in order to correctly handle the case
1642  // where (compliant) fonts have empty entries in the middle of the
1643  // table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
1644  // and idx as its secondary key (ensuring that adjacent entries with
1645  // the same pos value remain in the same order)
1646  locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
1647  i = seekTable("loca");
1648  pos = tables[i].offset;
1649  i = seekTable("glyf");
1650  glyfTableLen = tables[i].len;
1651  ok = gTrue;
1652  for (i = 0; i <= nGlyphs; ++i) {
1653    locaTable[i].idx = i;
1654    if (locaFmt) {
1655      locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
1656    } else {
1657      locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
1658    }
1659    if (locaTable[i].origOffset > glyfTableLen) {
1660      locaTable[i].origOffset = glyfTableLen;
1661    }
1662  }
1663  std::sort(locaTable, locaTable + nGlyphs + 1,
1664            cmpTrueTypeLocaOffsetFunctor());
1665  for (i = 0; i < nGlyphs; ++i) {
1666    locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
1667  }
1668  locaTable[nGlyphs].len = 0;
1669  std::sort(locaTable, locaTable + nGlyphs + 1, cmpTrueTypeLocaIdxFunctor());
1670  pos = 0;
1671  *maxUsedGlyph = -1;
1672  for (i = 0; i <= nGlyphs; ++i) {
1673    locaTable[i].newOffset = pos;
1674    pos += locaTable[i].len;
1675    if (pos & 3) {
1676      pos += 4 - (pos & 3);
1677    }
1678    if (locaTable[i].len > 0) {
1679      *maxUsedGlyph = i;
1680    }
1681  }
1682
1683  // construct the new 'loca' table
1684  locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2));
1685  for (i = 0; i <= nGlyphs; ++i) {
1686    pos = locaTable[i].newOffset;
1687    if (locaFmt) {
1688      locaData[4*] = (Guchar)(pos >> 24);
1689      locaData[4*i+1] = (Guchar)(pos >> 16);
1690      locaData[4*i+2] = (Guchar)(pos >>  8);
1691      locaData[4*i+3] = (Guchar) pos;
1692    } else {
1693      locaData[2*] = (Guchar)(pos >> 9);
1694      locaData[2*i+1] = (Guchar)(pos >> 1);
1695    }
1696  }
1697
1698  // count the number of tables
1699  nNewTables = 0;
1700  for (i = 0; i < nT42Tables; ++i) {
1701    if (t42Tables[i].required ||
1702        seekTable(t42Tables[i].tag) >= 0) {
1703      ++nNewTables;
1704    }
1705  }
1706  vmtxTab = NULL; // make gcc happy
1707  advance = 0; // make gcc happy
1708  if (needVerticalMetrics) {
1709    needVhea = seekTable("vhea") < 0;
1710    needVmtx = seekTable("vmtx") < 0;
1711    if (needVhea || needVmtx) {
1712      i = seekTable("head");
1713      advance = getU16BE(tables[i].offset + 18, &ok); // units per em
1714      if (needVhea) {
1715        ++nNewTables;
1716      }
1717      if (needVmtx) {
1718        ++nNewTables;
1719      }
1720    }
1721  }
1722
1723  // construct the new table headers, including table checksums
1724  // (pad each table out to a multiple of 4 bytes)
1725  pos = 12 + nNewTables*16;
1726  k = 0;
1727  for (i = 0; i < nT42Tables; ++i) {
1728    length = -1;
1729    checksum = 0; // make gcc happy
1730    if (i == t42HeadTable) {
1731      length = 54;
1732      checksum = computeTableChecksum(headData, 54);
1733    } else if (i == t42LocaTable) {
1734      length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1735      checksum = computeTableChecksum(locaData, length);
1736    } else if (i == t42GlyfTable) {
1737      length = 0;
1738      checksum = 0;
1739      glyfPos = tables[seekTable("glyf")].offset;
1740      for (j = 0; j < nGlyphs; ++j) {
1741        length += locaTable[j].len;
1742        if (length & 3) {
1743          length += 4 - (length & 3);
1744        }
1745        if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1746          checksum +=
1747              computeTableChecksum(file + glyfPos + locaTable[j].origOffset,
1748                                   locaTable[j].len);
1749        }
1750      }
1751    } else {
1752      if ((j = seekTable(t42Tables[i].tag)) >= 0) {
1753        length = tables[j].len;
1754        if (checkRegion(tables[j].offset, length)) {
1755          checksum = computeTableChecksum(file + tables[j].offset, length);
1756        }
1757      } else if (needVerticalMetrics && i == t42VheaTable) {
1758        vheaTab[10] = advance / 256;    // max advance height
1759        vheaTab[11] = advance % 256;
1760        length = sizeof(vheaTab);
1761        checksum = computeTableChecksum(vheaTab, length);
1762      } else if (needVerticalMetrics && i == t42VmtxTable) {
1763        length = 4 + (nGlyphs - 1) * 2;
1764        vmtxTab = (Guchar *)gmalloc(length);
1765        vmtxTab[0] = advance / 256;
1766        vmtxTab[1] = advance % 256;
1767        for (j = 2; j < length; j += 2) {
1768          vmtxTab[j] = 0;
1769          vmtxTab[j+1] = 0;
1770        }
1771        checksum = computeTableChecksum(vmtxTab, length);
1772      } else if (t42Tables[i].required) {
1773        //~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
1774        //~       t42Tables[i].tag);
1775        length = 0;
1776        checksum = 0;
1777      }
1778    }
1779    if (length >= 0) {
1780      newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) |
1781                         ((t42Tables[i].tag[1] & 0xff) << 16) |
1782                         ((t42Tables[i].tag[2] & 0xff) <<  8) |
1783                          (t42Tables[i].tag[3] & 0xff);
1784      newTables[k].checksum = checksum;
1785      newTables[k].offset = pos;
1786      newTables[k].len = length;
1787      pos += length;
1788      if (pos & 3) {
1789        pos += 4 - (length & 3);
1790      }
1791      ++k;
1792    }
1793  }
1794
1795  // construct the table directory
1796  tableDir[0] = 0x00;           // sfnt version
1797  tableDir[1] = 0x01;
1798  tableDir[2] = 0x00;
1799  tableDir[3] = 0x00;
1800  tableDir[4] = 0;              // numTables
1801  tableDir[5] = nNewTables;
1802  tableDir[6] = 0;              // searchRange
1803  tableDir[7] = (Guchar)128;
1804  tableDir[8] = 0;              // entrySelector
1805  tableDir[9] = 3;
1806  tableDir[10] = 0;             // rangeShift
1807  tableDir[11] = (Guchar)(16 * nNewTables - 128);
1808  pos = 12;
1809  for (i = 0; i < nNewTables; ++i) {
1810    tableDir[pos   ] = (Guchar)(newTables[i].tag >> 24);
1811    tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16);
1812    tableDir[pos+ 2] = (Guchar)(newTables[i].tag >>  8);
1813    tableDir[pos+ 3] = (Guchar) newTables[i].tag;
1814    tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24);
1815    tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16);
1816    tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >>  8);
1817    tableDir[pos+ 7] = (Guchar) newTables[i].checksum;
1818    tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24);
1819    tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16);
1820    tableDir[pos+10] = (Guchar)(newTables[i].offset >>  8);
1821    tableDir[pos+11] = (Guchar) newTables[i].offset;
1822    tableDir[pos+12] = (Guchar)(newTables[i].len >> 24);
1823    tableDir[pos+13] = (Guchar)(newTables[i].len >> 16);
1824    tableDir[pos+14] = (Guchar)(newTables[i].len >>  8);
1825    tableDir[pos+15] = (Guchar) newTables[i].len;
1826    pos += 16;
1827  }
1828
1829  // compute the font checksum and store it in the head table
1830  checksum = computeTableChecksum(tableDir, 12 + nNewTables*16);
1831  for (i = 0; i < nNewTables; ++i) {
1832    checksum += newTables[i].checksum;
1833  }
1834  checksum = 0xb1b0afba - checksum; // because the TrueType spec says so
1835  headData[ 8] = (Guchar)(checksum >> 24);
1836  headData[ 9] = (Guchar)(checksum >> 16);
1837  headData[10] = (Guchar)(checksum >>  8);
1838  headData[11] = (Guchar) checksum;
1839
1840  // start the sfnts array
1841  if (name) {
1842    (*outputFunc)(outputStream, "/", 1);
1843    (*outputFunc)(outputStream, name->getCString(), name->getLength());
1844    (*outputFunc)(outputStream, " [\n", 3);
1845  } else {
1846    (*outputFunc)(outputStream, "/sfnts [\n", 9);
1847  }
1848
1849  // write the table directory
1850  dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream);
1851
1852  // write the tables
1853  for (i = 0; i < nNewTables; ++i) {
1854    if (i == t42HeadTable) {
1855      dumpString(headData, 54, outputFunc, outputStream);
1856    } else if (i == t42LocaTable) {
1857      length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1858      dumpString(locaData, length, outputFunc, outputStream);
1859    } else if (i == t42GlyfTable) {
1860      glyfPos = tables[seekTable("glyf")].offset;
1861      for (j = 0; j < nGlyphs; ++j) {
1862        if (locaTable[j].len > 0 &&
1863            checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1864          dumpString(file + glyfPos + locaTable[j].origOffset,
1865                     locaTable[j].len, outputFunc, outputStream);
1866        }
1867      }
1868    } else {
1869      // length == 0 means the table is missing and the error was
1870      // already reported during the construction of the table
1871      // headers
1872      if ((length = newTables[i].len) > 0) {
1873        if ((j = seekTable(t42Tables[i].tag)) >= 0 &&
1874            checkRegion(tables[j].offset, tables[j].len)) {
1875          dumpString(file + tables[j].offset, tables[j].len,
1876                     outputFunc, outputStream);
1877        } else if (needVerticalMetrics && i == t42VheaTable) {
1878          dumpString(vheaTab, length, outputFunc, outputStream);
1879        } else if (needVerticalMetrics && i == t42VmtxTable) {
1880          dumpString(vmtxTab, length, outputFunc, outputStream);
1881        }
1882      }
1883    }
1884  }
1885
1886  // end the sfnts array
1887  (*outputFunc)(outputStream, "] def\n", 6);
1888
1889  gfree(locaData);
1890  gfree(locaTable);
1891  if (vmtxTab) {
1892    gfree(vmtxTab);
1893  }
1894}
1895
1896void FoFiTrueType::dumpString(Guchar *s, int length,
1897                              FoFiOutputFunc outputFunc,
1898                              void *outputStream) {
1899  GooString *buf;
1900  int pad, i, j;
1901
1902  (*outputFunc)(outputStream, "<", 1);
1903  for (i = 0; i < length; i += 32) {
1904    for (j = 0; j < 32 && i+j < length; ++j) {
1905      buf = GooString::format("{0:02x}", s[i+j] & 0xff);
1906      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
1907      delete buf;
1908    }
1909    if (i % (65536 - 32) == 65536 - 64) {
1910      (*outputFunc)(outputStream, ">\n<", 3);
1911    } else if (i+32 < length) {
1912      (*outputFunc)(outputStream, "\n", 1);
1913    }
1914  }
1915  if (length & 3) {
1916    pad = 4 - (length & 3);
1917    for (i = 0; i < pad; ++i) {
1918      (*outputFunc)(outputStream, "00", 2);
1919    }
1920  }
1921  // add an extra zero byte because the Adobe Type 42 spec says so
1922  (*outputFunc)(outputStream, "00>\n", 4);
1923}
1924
1925Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) {
1926  Guint checksum, word;
1927  int i;
1928
1929  checksum = 0;
1930  for (i = 0; i+3 < length; i += 4) {
1931    word = ((data[] & 0xff) << 24) +
1932           ((data[i+1] & 0xff) << 16) +
1933           ((data[i+2] & 0xff) <<  8) +
1934            (data[i+3] & 0xff);
1935    checksum += word;
1936  }
1937  if (length & 3) {
1938    word = 0;
1939    i = length & ~3;
1940    switch (length & 3) {
1941    case 3:
1942      word |= (data[i+2] & 0xff) <<  8;
1943    case 2:
1944      word |= (data[i+1] & 0xff) << 16;
1945    case 1:
1946      word |= (data[] & 0xff) << 24;
1947      break;
1948    }
1949    checksum += word;
1950  }
1951  return checksum;
1952}
1953
1954void FoFiTrueType::parse() {
1955  Guint topTag;
1956  int pos, ver, i, j;
1957
1958  parsedOk = gTrue;
1959
1960  // look for a collection (TTC)
1961  topTag = getU32BE(0, &parsedOk);
1962  if (!parsedOk) {
1963    return;
1964  }
1965  if (topTag == ttcfTag) {
1966    /* TTC font */
1967    int dircount;
1968
1969    dircount = getU32BE(8, &parsedOk);
1970    if (!parsedOk)
1971      return;
1972    if (! dircount) {
1973      parsedOk = gFalse;
1974      return;
1975    }
1976
1977    if (faceIndex >= dircount)
1978      faceIndex = 0;
1979    pos = getU32BE(12 + faceIndex * 4, &parsedOk);
1980    if (! parsedOk)
1981      return;
1982  } else {
1983    pos = 0;
1984  }
1985
1986  // check the sfnt version
1987  ver = getU32BE(pos, &parsedOk);
1988  if (!parsedOk) {
1989    return;
1990  }
1991  openTypeCFF = ver == 0x4f54544f; // 'OTTO'
1992
1993  // read the table directory
1994  nTables = getU16BE(pos + 4, &parsedOk);
1995  if (!parsedOk) {
1996    return;
1997  }
1998  tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable));
1999  pos += 12;
2000  j = 0;
2001  for (i = 0; i < nTables; ++i) {
2002    tables[j].tag = getU32BE(pos, &parsedOk);
2003    tables[j].checksum = getU32BE(pos + 4, &parsedOk);
2004    tables[j].offset = (int)getU32BE(pos + 8, &parsedOk);
2005    tables[j].len = (int)getU32BE(pos + 12, &parsedOk);
2006    if (tables[j].offset + tables[j].len >= tables[j].offset &&
2007        tables[j].offset + tables[j].len <= len) {
2008      // ignore any bogus entries in the table directory
2009      ++j;
2010    }
2011    pos += 16;
2012  }
2013  if (nTables != j) {
2014    nTables = j;
2015    tables = (TrueTypeTable *)greallocn_checkoverflow(tables, nTables, sizeof(TrueTypeTable));
2016  }
2017  if (!parsedOk || tables == NULL) {
2018    return;
2019  }
2020
2021  // check for tables that are required by both the TrueType spec and
2022  // the Type 42 spec
2023  if (seekTable("head") < 0 ||
2024      seekTable("hhea") < 0 ||
2025      seekTable("maxp") < 0 ||
2026      seekTable("hmtx") < 0 ||
2027      (!openTypeCFF && seekTable("loca") < 0) ||
2028      (!openTypeCFF && seekTable("glyf") < 0) ||
2029      (openTypeCFF && seekTable("CFF ") < 0)) {
2030    parsedOk = gFalse;
2031    return;
2032  }
2033
2034  // read the cmaps
2035  if ((i = seekTable("cmap")) >= 0) {
2036    pos = tables[i].offset + 2;
2037    nCmaps = getU16BE(pos, &parsedOk);
2038    pos += 2;
2039    if (!parsedOk) {
2040      return;
2041    }
2042    cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap));
2043    for (j = 0; j < nCmaps; ++j) {
2044      cmaps[j].platform = getU16BE(pos, &parsedOk);
2045      cmaps[j].encoding = getU16BE(pos + 2, &parsedOk);
2046      cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk);
2047      pos += 8;
2048      cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk);
2049      cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk);
2050    }
2051    if (!parsedOk) {
2052      return;
2053    }
2054  } else {
2055    nCmaps = 0;
2056  }
2057
2058  // get the number of glyphs from the maxp table
2059  i = seekTable("maxp");
2060  nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk);
2061  if (!parsedOk) {
2062    return;
2063  }
2064
2065  // get the bbox and loca table format from the head table
2066  i = seekTable("head");
2067  bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk);
2068  bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk);
2069  bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk);
2070  bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk);
2071  locaFmt = getS16BE(tables[i].offset + 50, &parsedOk);
2072  if (!parsedOk) {
2073    return;
2074  }
2075
2076  // make sure the loca table is sane (correct length and entries are
2077  // in bounds)
2078  if (!openTypeCFF) {
2079    i = seekTable("loca");
2080    if (tables[i].len < 0) {
2081      parsedOk = gFalse;
2082      return;
2083    }
2084    if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) {
2085      nGlyphs = tables[i].len / (locaFmt ? 4 : 2) - 1;
2086    }
2087    for (j = 0; j <= nGlyphs; ++j) {
2088      if (locaFmt) {
2089        pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk);
2090      } else {
2091        pos = getU16BE(tables[i].offset + j*2, &parsedOk);
2092      }
2093      if (pos < 0 || pos > len) {
2094        parsedOk = gFalse;
2095      }
2096    }
2097    if (!parsedOk) {
2098      return;
2099    }
2100  }
2101
2102  // read the post table
2103  readPostTable();
2104}
2105
2106void FoFiTrueType::readPostTable() {
2107  GooString *name;
2108  int tablePos, postFmt, stringIdx, stringPos;
2109  GBool ok;
2110  int i, j, n, m;
2111
2112  ok = gTrue;
2113  if ((i = seekTable("post")) < 0) {
2114    return;
2115  }
2116  tablePos = tables[i].offset;
2117  postFmt = getU32BE(tablePos, &ok);
2118  if (!ok) {
2119    goto err;
2120  }
2121  if (postFmt == 0x00010000) {
2122    nameToGID = new GooHash(gTrue);
2123    for (i = 0; i < 258; ++i) {
2124      nameToGID->add(new GooString(macGlyphNames[i]), i);
2125    }
2126  } else if (postFmt == 0x00020000) {
2127    nameToGID = new GooHash(gTrue);
2128    n = getU16BE(tablePos + 32, &ok);
2129    if (!ok) {
2130      goto err;
2131    }
2132    if (n > nGlyphs) {
2133      n = nGlyphs;
2134    }
2135    stringIdx = 0;
2136    stringPos = tablePos + 34 + 2*n;
2137    for (i = 0; i < n; ++i) {
2138      j = getU16BE(tablePos + 34 + 2*i, &ok);
2139      if (j < 258) {
2140        nameToGID->removeInt(macGlyphNames[j]);
2141        nameToGID->add(new GooString(macGlyphNames[j]), i);
2142      } else {
2143        j -= 258;
2144        if (j != stringIdx) {
2145          for (stringIdx = 0, stringPos = tablePos + 34 + 2*n;
2146               stringIdx < j;
2147               ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ;
2148          if (!ok) {
2149            goto err;
2150          }
2151        }
2152        m = getU8(stringPos, &ok);
2153        if (!ok || !checkRegion(stringPos + 1, m)) {
2154          goto err;
2155        }
2156        name = new GooString((char *)&file[stringPos + 1], m);
2157        nameToGID->removeInt(name);
2158        nameToGID->add(name, i);
2159        ++stringIdx;
2160        stringPos += 1 + m;
2161      }
2162    }
2163  } else if (postFmt == 0x00028000) {
2164    nameToGID = new GooHash(gTrue);
2165    for (i = 0; i < nGlyphs; ++i) {
2166      j = getU8(tablePos + 32 + i, &ok);
2167      if (!ok) {
2168        goto err;
2169      }
2170      if (j < 258) {
2171        nameToGID->removeInt(macGlyphNames[j]);
2172        nameToGID->add(new GooString(macGlyphNames[j]), i);
2173      }
2174    }
2175  }
2176
2177  return;
2178
2179 err:
2180  if (nameToGID) {
2181    delete nameToGID;
2182    nameToGID = NULL;
2183  }
2184}
2185
2186int FoFiTrueType::seekTable(const char *tag) {
2187  Guint tagI;
2188  int i;
2189
2190  tagI = ((tag[0] & 0xff) << 24) |
2191         ((tag[1] & 0xff) << 16) |
2192         ((tag[2] & 0xff) << 8) |
2193          (tag[3] & 0xff);
2194  for (i = 0; i < nTables; ++i) {
2195    if (tables[i].tag == tagI) {
2196      return i;
2197    }
2198  }
2199  return -1;
2200}
2201
2202Guint FoFiTrueType::charToTag(const char *tagName)
2203{
2204  int n = strlen(tagName);
2205  Guint tag = 0;
2206  int i;
2207
2208  if (n > 4) n = 4;
2209  for (i = 0;i < n;i++) {
2210    tag <<= 8;
2211    tag |= tagName[i] & 0xff;
2212  }
2213  for (;i < 4;i++) {
2214    tag <<= 8;
2215    tag |= ' ';
2216  }
2217  return tag;
2218}
2219
2220/*
2221  setup GSUB table data
2222  Only supporting vertical text substitution.
2223*/
2224int FoFiTrueType::setupGSUB(const char *scriptName)
2225{
2226  return setupGSUB(scriptName, NULL);
2227}
2228
2229/*
2230  setup GSUB table data
2231  Only supporting vertical text substitution.
2232*/
2233int FoFiTrueType::setupGSUB(const char *scriptName,
2234                            const char *languageName)
2235{
2236  Guint gsubTable;
2237  unsigned int i;
2238  Guint scriptList, featureList;
2239  Guint scriptCount;
2240  Guint tag;
2241  Guint scriptTable = 0;
2242  Guint langSys;
2243  Guint featureCount;
2244  Guint featureIndex;
2245  Guint ftable = 0;
2246  Guint llist;
2247  Guint scriptTag;
2248  int x;
2249  Guint pos;
2250
2251  if (scriptName == 0) {
2252    gsubFeatureTable = 0;
2253    return 0;
2254  }
2255  scriptTag = charToTag(scriptName);
2256  /* read GSUB Header */
2257  if ((x = seekTable("GSUB")) < 0) {
2258    return 0; /* GSUB table not found */
2259  }
2260  gsubTable = tables[x].offset;
2261  pos = gsubTable+4;
2262  scriptList = getU16BE(pos,&parsedOk);
2263  pos += 2;
2264  featureList = getU16BE(pos,&parsedOk);
2265  pos += 2;
2266  llist = getU16BE(pos,&parsedOk);
2267
2268  gsubLookupList = llist+gsubTable; /* change to offset from top of file */
2269  /* read script list table */
2270  pos = gsubTable+scriptList;
2271  scriptCount = getU16BE(pos,&parsedOk);
2272  pos += 2;
2273  /* find  script */
2274  for (i = 0;i < scriptCount;i++) {
2275    tag = getU32BE(pos,&parsedOk);
2276    pos += 4;
2277    scriptTable = getU16BE(pos,&parsedOk);
2278    pos += 2;
2279    if (tag == scriptTag) {
2280      /* found */
2281      break;
2282    }
2283  }
2284  if (i >= scriptCount) {
2285    /* not found */
2286    return 0;
2287  }
2288
2289  /* read script table */
2290  /* use default language system */
2291  pos = gsubTable+scriptList+scriptTable;
2292  langSys = 0;
2293  if (languageName) {
2294    Guint langTag = charToTag(languageName);
2295    Guint langCount = getU16BE(pos+2,&parsedOk);
2296    for (i = 0;i < langCount && langSys == 0;i++) {
2297      tag = getU32BE(pos+4+i*(4+2),&parsedOk);
2298      if (tag == langTag) {
2299        langSys = getU16BE(pos+4+i*(4+2)+4,&parsedOk);
2300      }
2301    }
2302  }
2303  if (langSys == 0) {
2304    /* default language system */
2305    langSys = getU16BE(pos,&parsedOk);
2306  }
2307
2308  /* read LangSys table */
2309  if (langSys == 0) {
2310    /* no default LangSys */
2311    return 0;
2312  }
2313
2314  pos = gsubTable+scriptList+scriptTable+langSys+2;
2315  featureIndex = getU16BE(pos,&parsedOk); /* ReqFeatureIndex */
2316  pos += 2;
2317
2318  if (featureIndex != 0xffff) {
2319    Guint tpos;
2320    /* read feature record */
2321    tpos = gsubTable+featureList;
2322    featureCount = getU16BE(tpos,&parsedOk);
2323    tpos = gsubTable+featureList+2+featureIndex*(4+2);
2324    tag = getU32BE(tpos,&parsedOk);
2325    tpos += 4;
2326    if (tag == vrt2Tag) {
2327      /* vrt2 is preferred, overwrite vert */
2328      ftable = getU16BE(tpos,&parsedOk);
2329      /* convert to offset from file top */
2330      gsubFeatureTable = ftable+gsubTable+featureList;
2331      return 0;
2332    } else if (tag == vertTag) {
2333      ftable = getU16BE(tpos,&parsedOk);
2334    }
2335  }
2336  featureCount = getU16BE(pos,&parsedOk);
2337  pos += 2;
2338  /* find 'vrt2' or 'vert' feature */
2339  for (i = 0;i < featureCount;i++) {
2340    Guint oldPos;
2341
2342    featureIndex = getU16BE(pos,&parsedOk);
2343    pos += 2;
2344    oldPos = pos; /* save position */
2345    /* read feature record */
2346    pos = gsubTable+featureList+2+featureIndex*(4+2);
2347    tag = getU32BE(pos,&parsedOk);
2348    pos += 4;
2349    if (tag == vrt2Tag) {
2350      /* vrt2 is preferred, overwrite vert */
2351      ftable = getU16BE(pos,&parsedOk);
2352      break;
2353    } else if (ftable == 0 && tag == vertTag) {
2354      ftable = getU16BE(pos,&parsedOk);
2355    }
2356    pos = oldPos; /* restore old position */
2357  }
2358  if (ftable == 0) {
2359    /* vert nor vrt2 are not found */
2360    return 0;
2361  }
2362  /* convert to offset from file top */
2363  gsubFeatureTable = ftable+gsubTable+featureList;
2364  return 0;
2365}
2366
2367Guint FoFiTrueType::doMapToVertGID(Guint orgGID)
2368{
2369  Guint lookupCount;
2370  Guint lookupListIndex;
2371  Guint i;
2372  Guint gid = 0;
2373  Guint pos;
2374
2375  pos = gsubFeatureTable+2;
2376  lookupCount = getU16BE(pos,&parsedOk);
2377  pos += 2;
2378  for (i = 0;i < lookupCount;i++) {
2379    lookupListIndex = getU16BE(pos,&parsedOk);
2380    pos += 2;
2381    if ((gid = scanLookupList(lookupListIndex,orgGID)) != 0) {
2382      break;
2383    }
2384  }
2385  return gid;
2386}
2387
2388Guint FoFiTrueType::mapToVertGID(Guint orgGID)
2389{
2390  Guint mapped;
2391
2392  if (gsubFeatureTable == 0) return orgGID;
2393  if ((mapped = doMapToVertGID(orgGID)) != 0) {
2394    return mapped;
2395  }
2396  return orgGID;
2397}
2398
2399Guint FoFiTrueType::scanLookupList(Guint listIndex, Guint orgGID)
2400{
2401  Guint lookupTable;
2402  Guint subTableCount;
2403  Guint subTable;
2404  Guint i;
2405  Guint gid = 0;
2406  Guint pos;
2407
2408  if (gsubLookupList == 0) return 0; /* no lookup list */
2409  pos = gsubLookupList+2+listIndex*2;
2410  lookupTable = getU16BE(pos,&parsedOk);
2411  /* read lookup table */
2412  pos = gsubLookupList+lookupTable+4;
2413  subTableCount = getU16BE(pos,&parsedOk);
2414  pos += 2;;
2415  for (i = 0;i < subTableCount;i++) {
2416    subTable = getU16BE(pos,&parsedOk);
2417    pos += 2;
2418    if ((gid = scanLookupSubTable(gsubLookupList+lookupTable+subTable,orgGID))
2419         != 0) break;
2420  }
2421  return gid;
2422}
2423
2424Guint FoFiTrueType::scanLookupSubTable(Guint subTable, Guint orgGID)
2425{
2426  Guint format;
2427  Guint coverage;
2428  int delta;
2429  int glyphCount;
2430  Guint substitute;
2431  Guint gid = 0;
2432  int coverageIndex;
2433  int pos;
2434
2435  pos = subTable;
2436  format = getU16BE(pos,&parsedOk);
2437  pos += 2;
2438  coverage = getU16BE(pos,&parsedOk);
2439  pos += 2;
2440  if ((coverageIndex =
2441     checkGIDInCoverage(subTable+coverage,orgGID)) >= 0) {
2442    switch (format) {
2443    case 1:
2444      /* format 1 */
2445      delta = getS16BE(pos,&parsedOk);
2446      pos += 2;
2447      gid = orgGID+delta;
2448      break;
2449    case 2:
2450      /* format 2 */
2451      glyphCount = getS16BE(pos,&parsedOk);
2452      pos += 2;
2453      if (glyphCount > coverageIndex) {
2454        pos += coverageIndex*2;
2455        substitute = getU16BE(pos,&parsedOk);
2456        gid = substitute;
2457      }
2458      break;
2459    default:
2460      /* unknown format */
2461      break;
2462    }
2463  }
2464  return gid;
2465}
2466
2467int FoFiTrueType::checkGIDInCoverage(Guint coverage, Guint orgGID)
2468{
2469  int index = -1;
2470  Guint format;
2471  Guint count;
2472  Guint i;
2473  Guint pos;
2474
2475  pos = coverage;
2476  format = getU16BE(pos,&parsedOk);
2477  pos += 2;
2478  switch (format) {
2479  case 1:
2480    count = getU16BE(pos,&parsedOk);
2481    pos += 2;
2482    // In some poor CJK fonts, key GIDs are not sorted,
2483    // thus we cannot finish checking even when the range
2484    // including orgGID seems to have already passed.
2485    for (i = 0;i < count;i++) {
2486      Guint gid;
2487
2488      gid = getU16BE(pos,&parsedOk);
2489      pos += 2;
2490      if (gid == orgGID) {
2491        /* found */
2492        index = i;
2493        break;
2494      }
2495    }
2496    break;
2497  case 2:
2498    count = getU16BE(pos,&parsedOk);
2499    pos += 2;
2500    for (i = 0;i < count;i++) {
2501      Guint startGID, endGID;
2502      Guint startIndex;
2503
2504      startGID = getU16BE(pos,&parsedOk);
2505      pos += 2;
2506      endGID = getU16BE(pos,&parsedOk);
2507      pos += 2;
2508      startIndex = getU16BE(pos,&parsedOk);
2509      pos += 2;
2510      // In some poor CJK fonts, key GIDs are not sorted,
2511      // thus we cannot finish checking even when the range
2512      // including orgGID seems to have already passed.
2513      if (startGID <= orgGID && orgGID <= endGID) {
2514        /* found */
2515        index = startIndex+orgGID-startGID;
2516        break;
2517      }
2518    }
2519    break;
2520  default:
2521    break;
2522  }
2523  return index;
2524}
2525
Note: See TracBrowser for help on using the repository browser.