FoFiTrueType.cc 52.1 KB
Newer Older
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1
2
3
4
5
6
7
8
//========================================================================
//
// FoFiTrueType.cc
//
// Copyright 1999-2003 Glyph & Cog, LLC
//
//========================================================================

9
10
11
12
//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
13
14
15
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
16
17
18
// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
// Copyright (C) 2007 Koji Otani <sho@bbr.jp>
// 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>
suzuki toshiya's avatar
suzuki toshiya committed
21
// Copyright (C) 2012 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
22
// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
23
24
25
26
27
28
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================

Kristian Høgsberg's avatar
Kristian Høgsberg committed
29
30
31
32
33
34
35
#include <config.h>

#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif

#include <stdlib.h>
36
#include <string.h>
37
#include <algorithm>
Kristian Høgsberg's avatar
Kristian Høgsberg committed
38
39
40
41
#include "goo/gtypes.h"
#include "goo/gmem.h"
#include "goo/GooString.h"
#include "goo/GooHash.h"
42
#include "FoFiType1C.h"
Kristian Høgsberg's avatar
Kristian Høgsberg committed
43
#include "FoFiTrueType.h"
Albert Astals Cid's avatar
Albert Astals Cid committed
44
#include "poppler/Error.h"
Kristian Høgsberg's avatar
Kristian Høgsberg committed
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

//
// Terminology
// -----------
//
// character code = number used as an element of a text string
//
// character name = glyph name = name for a particular glyph within a
//                  font
//
// glyph index = GID = position (within some internal table in the font)
//               where the instructions to draw a particular glyph are
//               stored
//
// Type 1 fonts
// ------------
//
// Type 1 fonts contain:
//
// Encoding: array of glyph names, maps char codes to glyph names
//
//           Encoding[charCode] = charName
//
// CharStrings: dictionary of instructions, keyed by character names,
//              maps character name to glyph data
//
//              CharStrings[charName] = glyphData
//
// TrueType fonts
// --------------
//
// TrueType fonts contain:
//
// 'cmap' table: mapping from character code to glyph index; there may
//               be multiple cmaps in a TrueType font
//
//               cmap[charCode] = gid
//
// 'post' table: mapping from glyph index to glyph name
//
//               post[gid] = glyphName
//
// Type 42 fonts
// -------------
//
// Type 42 fonts contain:
//
// Encoding: array of glyph names, maps char codes to glyph names
//
//           Encoding[charCode] = charName
//
// CharStrings: dictionary of glyph indexes, keyed by character names,
//              maps character name to glyph index
//
//              CharStrings[charName] = gid
//

//------------------------------------------------------------------------

104
105
106
107
#define ttcfTag 0x74746366

//------------------------------------------------------------------------

Kristian Høgsberg's avatar
Kristian Høgsberg committed
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
struct TrueTypeTable {
  Guint tag;
  Guint checksum;
  int offset;
  int origOffset;
  int len;
};

struct TrueTypeCmap {
  int platform;
  int encoding;
  int offset;
  int len;
  int fmt;
};

struct TrueTypeLoca {
  int idx;
  int origOffset;
  int newOffset;
  int len;
};

#define cmapTag 0x636d6170
#define glyfTag 0x676c7966
133
#define headTag 0x68656164
134
135
#define hheaTag 0x68686561
#define hmtxTag 0x686d7478
Kristian Høgsberg's avatar
Kristian Høgsberg committed
136
137
#define locaTag 0x6c6f6361
#define nameTag 0x6e616d65
138
#define os2Tag  0x4f532f32
Kristian Høgsberg's avatar
Kristian Høgsberg committed
139
#define postTag 0x706f7374
Albert Astals Cid's avatar
Albert Astals Cid committed
140
141
#define vrt2Tag 0x76727432
#define vertTag 0x76657274
Kristian Høgsberg's avatar
Kristian Høgsberg committed
142

143
144
145
146
147
148
struct cmpTrueTypeLocaOffsetFunctor {
  bool operator()(const TrueTypeLoca &loca1, const TrueTypeLoca &loca2) {
    if (loca1.origOffset == loca2.origOffset) {
      return loca1.idx < loca2.idx;
    }
    return loca1.origOffset < loca2.origOffset;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
149
  }
150
};
Kristian Høgsberg's avatar
Kristian Høgsberg committed
151

152
153
154
155
156
struct cmpTrueTypeLocaIdxFunctor {
  bool operator()(const TrueTypeLoca &loca1, const TrueTypeLoca &loca2) {
    return loca1.idx < loca2.idx;
  }
};
Kristian Høgsberg's avatar
Kristian Høgsberg committed
157

158
159
160
161
162
struct cmpTrueTypeTableTagFunctor {
  bool operator()(const TrueTypeTable &tab1, const TrueTypeTable &tab2) {
    return tab1.tag < tab2.tag;
  }
};
Kristian Høgsberg's avatar
Kristian Høgsberg committed
163
164
165
166

//------------------------------------------------------------------------

struct T42Table {
167
  const char *tag;		// 4-byte tag
Kristian Høgsberg's avatar
Kristian Høgsberg committed
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  GBool required;		// required by the TrueType spec?
};

// TrueType tables to be embedded in Type 42 fonts.
// NB: the table names must be in alphabetical order here.
#define nT42Tables 11
static T42Table t42Tables[nT42Tables] = {
  { "cvt ", gTrue  },
  { "fpgm", gTrue  },
  { "glyf", gTrue  },
  { "head", gTrue  },
  { "hhea", gTrue  },
  { "hmtx", gTrue  },
  { "loca", gTrue  },
  { "maxp", gTrue  },
  { "prep", gTrue  },
  { "vhea", gFalse },
  { "vmtx", gFalse }
};
187
188
189
190
191
#define t42HeadTable  3
#define t42LocaTable  6
#define t42GlyfTable  2
#define t42VheaTable  9
#define t42VmtxTable 10
Kristian Høgsberg's avatar
Kristian Høgsberg committed
192
193
194
195
196

//------------------------------------------------------------------------

// Glyph names in some arbitrary standard order that Apple uses for
// their TrueType fonts.
197
static const char *macGlyphNames[258] = {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
  ".notdef",        "null",           "CR",             "space",
  "exclam",         "quotedbl",       "numbersign",     "dollar",
  "percent",        "ampersand",      "quotesingle",    "parenleft",
  "parenright",     "asterisk",       "plus",           "comma",
  "hyphen",         "period",         "slash",          "zero",
  "one",            "two",            "three",          "four",
  "five",           "six",            "seven",          "eight",
  "nine",           "colon",          "semicolon",      "less",
  "equal",          "greater",        "question",       "at",
  "A",              "B",              "C",              "D",
  "E",              "F",              "G",              "H",
  "I",              "J",              "K",              "L",
  "M",              "N",              "O",              "P",
  "Q",              "R",              "S",              "T",
  "U",              "V",              "W",              "X",
  "Y",              "Z",              "bracketleft",    "backslash",
  "bracketright",   "asciicircum",    "underscore",     "grave",
  "a",              "b",              "c",              "d",
  "e",              "f",              "g",              "h",
  "i",              "j",              "k",              "l",
  "m",              "n",              "o",              "p",
  "q",              "r",              "s",              "t",
  "u",              "v",              "w",              "x",
  "y",              "z",              "braceleft",      "bar",
  "braceright",     "asciitilde",     "Adieresis",      "Aring",
  "Ccedilla",       "Eacute",         "Ntilde",         "Odieresis",
  "Udieresis",      "aacute",         "agrave",         "acircumflex",
  "adieresis",      "atilde",         "aring",          "ccedilla",
  "eacute",         "egrave",         "ecircumflex",    "edieresis",
  "iacute",         "igrave",         "icircumflex",    "idieresis",
  "ntilde",         "oacute",         "ograve",         "ocircumflex",
  "odieresis",      "otilde",         "uacute",         "ugrave",
  "ucircumflex",    "udieresis",      "dagger",         "degree",
  "cent",           "sterling",       "section",        "bullet",
  "paragraph",      "germandbls",     "registered",     "copyright",
  "trademark",      "acute",          "dieresis",       "notequal",
  "AE",             "Oslash",         "infinity",       "plusminus",
235
  "lessequal",      "greaterequal",   "yen",            "mu",
Kristian Høgsberg's avatar
Kristian Høgsberg committed
236
  "partialdiff",    "summation",      "product",        "pi",
237
  "integral",       "ordfeminine",    "ordmasculine",   "Omega",
Kristian Høgsberg's avatar
Kristian Høgsberg committed
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
  "ae",             "oslash",         "questiondown",   "exclamdown",
  "logicalnot",     "radical",        "florin",         "approxequal",
  "increment",      "guillemotleft",  "guillemotright", "ellipsis",
  "nbspace",        "Agrave",         "Atilde",         "Otilde",
  "OE",             "oe",             "endash",         "emdash",
  "quotedblleft",   "quotedblright",  "quoteleft",      "quoteright",
  "divide",         "lozenge",        "ydieresis",      "Ydieresis",
  "fraction",       "currency",       "guilsinglleft",  "guilsinglright",
  "fi",             "fl",             "daggerdbl",      "periodcentered",
  "quotesinglbase", "quotedblbase",   "perthousand",    "Acircumflex",
  "Ecircumflex",    "Aacute",         "Edieresis",      "Egrave",
  "Iacute",         "Icircumflex",    "Idieresis",      "Igrave",
  "Oacute",         "Ocircumflex",    "applelogo",      "Ograve",
  "Uacute",         "Ucircumflex",    "Ugrave",         "dotlessi",
  "circumflex",     "tilde",          "overscore",      "breve",
  "dotaccent",      "ring",           "cedilla",        "hungarumlaut",
  "ogonek",         "caron",          "Lslash",         "lslash",
  "Scaron",         "scaron",         "Zcaron",         "zcaron",
  "brokenbar",      "Eth",            "eth",            "Yacute",
  "yacute",         "Thorn",          "thorn",          "minus",
  "multiply",       "onesuperior",    "twosuperior",    "threesuperior",
  "onehalf",        "onequarter",     "threequarters",  "franc",
  "Gbreve",         "gbreve",         "Idot",           "Scedilla",
  "scedilla",       "Cacute",         "cacute",         "Ccaron",
  "ccaron",         "dmacron"
};

//------------------------------------------------------------------------
// FoFiTrueType
//------------------------------------------------------------------------

269
FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA, int faceIndexA) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
270
271
  FoFiTrueType *ff;

272
  ff = new FoFiTrueType(fileA, lenA, gFalse, faceIndexA);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
273
274
275
276
277
278
279
  if (!ff->parsedOk) {
    delete ff;
    return NULL;
  }
  return ff;
}

280
FoFiTrueType *FoFiTrueType::load(char *fileName, int faceIndexA) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
281
282
283
284
285
286
287
  FoFiTrueType *ff;
  char *fileA;
  int lenA;

  if (!(fileA = FoFiBase::readFile(fileName, &lenA))) {
    return NULL;
  }
288
  ff = new FoFiTrueType(fileA, lenA, gTrue, faceIndexA);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
289
290
291
292
293
294
295
  if (!ff->parsedOk) {
    delete ff;
    return NULL;
  }
  return ff;
}

296
FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA):
Kristian Høgsberg's avatar
Kristian Høgsberg committed
297
298
299
300
301
302
303
304
  FoFiBase(fileA, lenA, freeFileDataA)
{
  tables = NULL;
  nTables = 0;
  cmaps = NULL;
  nCmaps = 0;
  nameToGID = NULL;
  parsedOk = gFalse;
305
  faceIndex = faceIndexA;
Albert Astals Cid's avatar
Albert Astals Cid committed
306
307
  gsubFeatureTable = 0;
  gsubLookupList = 0;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
308
309
310
311
312
313
314

  parse();
}

FoFiTrueType::~FoFiTrueType() {
  gfree(tables);
  gfree(cmaps);
315
316
317
  if (nameToGID) {
    delete nameToGID;
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
}

int FoFiTrueType::getNumCmaps() {
  return nCmaps;
}

int FoFiTrueType::getCmapPlatform(int i) {
  return cmaps[i].platform;
}

int FoFiTrueType::getCmapEncoding(int i) {
  return cmaps[i].encoding;
}

int FoFiTrueType::findCmap(int platform, int encoding) {
  int i;

  for (i = 0; i < nCmaps; ++i) {
    if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) {
      return i;
    }
  }
  return -1;
}

343
344
int FoFiTrueType::mapCodeToGID(int i, Guint c) {
  int gid;
345
346
  Guint segCnt, segEnd, segStart, segDelta, segOffset;
  Guint cmapFirst, cmapLen;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
347
348
349
350
351
352
353
354
355
356
  int pos, a, b, m;
  GBool ok;

  if (i < 0 || i >= nCmaps) {
    return 0;
  }
  ok = gTrue;
  pos = cmaps[i].offset;
  switch (cmaps[i].fmt) {
  case 0:
357
    if (c + 6 >= (Guint)cmaps[i].len) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
      return 0;
    }
    gid = getU8(cmaps[i].offset + 6 + c, &ok);
    break;
  case 4:
    segCnt = getU16BE(pos + 6, &ok) / 2;
    a = -1;
    b = segCnt - 1;
    segEnd = getU16BE(pos + 14 + 2*b, &ok);
    if (c > segEnd) {
      // malformed font -- the TrueType spec requires the last segEnd
      // to be 0xffff
      return 0;
    }
    // invariant: seg[a].end < code <= seg[b].end
    while (b - a > 1 && ok) {
      m = (a + b) / 2;
      segEnd = getU16BE(pos + 14 + 2*m, &ok);
      if (segEnd < c) {
	a = m;
      } else {
	b = m;
      }
    }
    segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok);
    segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok);
    segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok);
    if (c < segStart) {
      return 0;
    }
    if (segOffset == 0) {
      gid = (c + segDelta) & 0xffff;
    } else {
      gid = getU16BE(pos + 16 + 6*segCnt + 2*b +
		       segOffset + 2 * (c - segStart), &ok);
      if (gid != 0) {
	gid = (gid + segDelta) & 0xffff;
      }
    }
    break;
  case 6:
    cmapFirst = getU16BE(pos + 6, &ok);
    cmapLen = getU16BE(pos + 8, &ok);
    if (c < cmapFirst || c >= cmapFirst + cmapLen) {
      return 0;
    }
    gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok);
    break;
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
  case 12:
    segCnt = getU32BE(pos + 12, &ok);
    a = -1;
    b = segCnt - 1;
    segEnd = getU32BE(pos + 16 + 12*b+4, &ok);
    if (c > segEnd) {
      return 0;
    }
    // invariant: seg[a].end < code <= seg[b].end
    while (b - a > 1 && ok) {
      m = (a + b) / 2;
      segEnd = getU32BE(pos + 16 + 12*m+4, &ok);
      if (segEnd < c) {
	a = m;
      } else {
	b = m;
      }
    }
    segStart = getU32BE(pos + 16 + 12*b, &ok);
    segDelta = getU32BE(pos + 16 + 12*b+8, &ok);
    if (c < segStart) {
      return 0;
    }
    gid = segDelta + (c-segStart);
    break;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
  default:
    return 0;
  }
  if (!ok) {
    return 0;
  }
  return gid;
}

int FoFiTrueType::mapNameToGID(char *name) {
  if (!nameToGID) {
    return 0;
  }
  return nameToGID->lookupInt(name);
}

447
GBool FoFiTrueType::getCFFBlock(char **start, int *length) {
448
449
450
  int i;

  if (!openTypeCFF) {
451
    return gFalse;
452
453
454
  }
  i = seekTable("CFF ");
  if (!checkRegion(tables[i].offset, tables[i].len)) {
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
    return gFalse;
  }
  *start = (char *)file + tables[i].offset;
  *length = tables[i].len;
  return gTrue;
}

int *FoFiTrueType::getCIDToGIDMap(int *nCIDs) {
  char *start;
  int length;
  FoFiType1C *ff;
  int *map;

  *nCIDs = 0;
  if (!getCFFBlock(&start, &length)) {
470
471
    return NULL;
  }
472
  if (!(ff = FoFiType1C::make(start, length))) {
473
474
475
476
477
478
479
    return NULL;
  }
  map = ff->getCIDToGIDMap(nCIDs);
  delete ff;
  return map;
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
int FoFiTrueType::getEmbeddingRights() {
  int i, fsType;
  GBool ok;

  if ((i = seekTable("OS/2")) < 0) {
    return 4;
  }
  ok = gTrue;
  fsType = getU16BE(tables[i].offset + 8, &ok);
  if (!ok) {
    return 4;
  }
  if (fsType & 0x0008) {
    return 2;
  }
  if (fsType & 0x0004) {
    return 1;
  }
  if (fsType & 0x0002) {
    return 0;
  }
  return 3;
}

504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
void FoFiTrueType::getFontMatrix(double *mat) {
  char *start;
  int length;
  FoFiType1C *ff;

  if (!getCFFBlock(&start, &length)) {
    return;
  }
  if (!(ff = FoFiType1C::make(start, length))) {
    return;
  }
  ff->getFontMatrix(mat);
  delete ff;
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
519
void FoFiTrueType::convertToType42(char *psName, char **encoding,
520
				   int *codeToGID,
Kristian Høgsberg's avatar
Kristian Høgsberg committed
521
522
				   FoFiOutputFunc outputFunc,
				   void *outputStream) {
523
  GooString *buf;
524
  int maxUsedGlyph;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
525
526
  GBool ok;

527
528
529
530
  if (openTypeCFF) {
    return;
  }

Kristian Høgsberg's avatar
Kristian Høgsberg committed
531
532
  // write the header
  ok = gTrue;
533
534
535
536
  buf = GooString::format("%!PS-TrueTypeFont-{0:2g}\n",
			(double)getS32BE(0, &ok) / 65536.0);
  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
  delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
537
538
539
540
541
542
543
544

  // begin the font dictionary
  (*outputFunc)(outputStream, "10 dict begin\n", 14);
  (*outputFunc)(outputStream, "/FontName /", 11);
  (*outputFunc)(outputStream, psName, strlen(psName));
  (*outputFunc)(outputStream, " def\n", 5);
  (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
545
546
547
548
  buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
			bbox[0], bbox[1], bbox[2], bbox[3]);
  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
  delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
549
550
551
552
553
  (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);

  // write the guts of the dictionary
  cvtEncoding(encoding, outputFunc, outputStream);
  cvtCharStrings(encoding, codeToGID, outputFunc, outputStream);
554
  cvtSfnts(outputFunc, outputStream, NULL, gFalse, &maxUsedGlyph);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
555
556
557
558
559

  // end the dictionary and define the font
  (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
}

560
void FoFiTrueType::convertToType1(char *psName, const char **newEncoding,
561
562
				  GBool ascii, FoFiOutputFunc outputFunc,
				  void *outputStream) {
563
564
  char *start;
  int length;
565
566
  FoFiType1C *ff;

567
  if (!getCFFBlock(&start, &length)) {
568
569
    return;
  }
570
  if (!(ff = FoFiType1C::make(start, length))) {
571
572
573
574
575
576
    return;
  }
  ff->convertToType1(psName, newEncoding, ascii, outputFunc, outputStream);
  delete ff;
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
577
void FoFiTrueType::convertToCIDType2(char *psName,
578
				     int *cidMap, int nCIDs,
579
				     GBool needVerticalMetrics,
Kristian Høgsberg's avatar
Kristian Høgsberg committed
580
581
				     FoFiOutputFunc outputFunc,
				     void *outputStream) {
582
  GooString *buf;
583
  int cid, maxUsedGlyph;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
584
585
586
  GBool ok;
  int i, j, k;

587
588
589
590
  if (openTypeCFF) {
    return;
  }

Kristian Høgsberg's avatar
Kristian Høgsberg committed
591
592
  // write the header
  ok = gTrue;
593
594
595
596
  buf = GooString::format("%!PS-TrueTypeFont-{0:2g}\n",
			(double)getS32BE(0, &ok) / 65536.0);
  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
  delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611

  // begin the font dictionary
  (*outputFunc)(outputStream, "20 dict begin\n", 14);
  (*outputFunc)(outputStream, "/CIDFontName /", 14);
  (*outputFunc)(outputStream, psName, strlen(psName));
  (*outputFunc)(outputStream, " def\n", 5);
  (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19);
  (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
  (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
  (*outputFunc)(outputStream, "  /Registry (Adobe) def\n", 24);
  (*outputFunc)(outputStream, "  /Ordering (Identity) def\n", 27);
  (*outputFunc)(outputStream, "  /Supplement 0 def\n", 20);
  (*outputFunc)(outputStream, "  end def\n", 10);
  (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
  if (cidMap) {
612
613
614
    buf = GooString::format("/CIDCount {0:d} def\n", nCIDs);
    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
    delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
615
616
617
618
619
620
621
622
    if (nCIDs > 32767) {
      (*outputFunc)(outputStream, "/CIDMap [", 9);
      for (i = 0; i < nCIDs; i += 32768 - 16) {
	(*outputFunc)(outputStream, "<\n", 2);
	for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
	  (*outputFunc)(outputStream, "  ", 2);
	  for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
	    cid = cidMap[i+j+k];
623
624
625
626
	    buf = GooString::format("{0:02x}{1:02x}",
				  (cid >> 8) & 0xff, cid & 0xff);
	    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
	    delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
627
628
629
630
631
632
633
634
635
636
637
638
639
	  }
	  (*outputFunc)(outputStream, "\n", 1);
	}
	(*outputFunc)(outputStream, "  >", 3);
      }
      (*outputFunc)(outputStream, "\n", 1);
      (*outputFunc)(outputStream, "] def\n", 6);
    } else {
      (*outputFunc)(outputStream, "/CIDMap <\n", 10);
      for (i = 0; i < nCIDs; i += 16) {
	(*outputFunc)(outputStream, "  ", 2);
	for (j = 0; j < 16 && i+j < nCIDs; ++j) {
	  cid = cidMap[i+j];
640
641
642
643
	  buf = GooString::format("{0:02x}{1:02x}",
				(cid >> 8) & 0xff, cid & 0xff);
	  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
	  delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
644
645
646
647
648
649
650
	}
	(*outputFunc)(outputStream, "\n", 1);
      }
      (*outputFunc)(outputStream, "> def\n", 6);
    }
  } else {
    // direct mapping - just fill the string(s) with s[i]=i
651
652
653
    buf = GooString::format("/CIDCount {0:d} def\n", nGlyphs);
    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
    delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
654
655
656
657
    if (nGlyphs > 32767) {
      (*outputFunc)(outputStream, "/CIDMap [\n", 10);
      for (i = 0; i < nGlyphs; i += 32767) {
	j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
658
659
660
661
662
663
664
665
666
667
668
	buf = GooString::format("  {0:d} string 0 1 {1:d} {{\n", 2 * j, j - 1);
	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
	delete buf;
	buf = GooString::format("    2 copy dup 2 mul exch {0:d} add -8 bitshift put\n",
			      i);
	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
	delete buf;
	buf = GooString::format("    1 index exch dup 2 mul 1 add exch {0:d} add"
			      " 255 and put\n", i);
	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
	delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
669
670
671
672
	(*outputFunc)(outputStream, "  } for\n", 8);
      }
      (*outputFunc)(outputStream, "] def\n", 6);
    } else {
673
674
675
676
677
678
      buf = GooString::format("/CIDMap {0:d} string\n", 2 * nGlyphs);
      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
      delete buf;
      buf = GooString::format("  0 1 {0:d} {{\n", nGlyphs - 1);
      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
      delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
679
680
681
682
683
684
685
686
687
      (*outputFunc)(outputStream,
		    "    2 copy dup 2 mul exch -8 bitshift put\n", 42);
      (*outputFunc)(outputStream,
		    "    1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
      (*outputFunc)(outputStream, "  } for\n", 8);
      (*outputFunc)(outputStream, "def\n", 4);
    }
  }
  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
688
689
690
691
  buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
			bbox[0], bbox[1], bbox[2], bbox[3]);
  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
  delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
692
693
694
695
696
697
698
  (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
  (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
  (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
  (*outputFunc)(outputStream, "  /.notdef 0 def\n", 17);
  (*outputFunc)(outputStream, "  end readonly def\n", 19);

  // write the guts of the dictionary
699
  cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics, &maxUsedGlyph);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
700
701
702
703
704
705
706

  // end the dictionary and define the font
  (*outputFunc)(outputStream,
		"CIDFontName currentdict end /CIDFont defineresource pop\n",
		56);
}

707
void FoFiTrueType::convertToCIDType0(char *psName, int *cidMap, int nCIDs,
708
709
				     FoFiOutputFunc outputFunc,
				     void *outputStream) {
710
711
  char *start;
  int length;
712
713
  FoFiType1C *ff;

714
  if (!getCFFBlock(&start, &length)) {
715
716
    return;
  }
717
  if (!(ff = FoFiType1C::make(start, length))) {
718
719
    return;
  }
720
  ff->convertToCIDType0(psName, cidMap, nCIDs, outputFunc, outputStream);
721
722
723
  delete ff;
}

724
void FoFiTrueType::convertToType0(char *psName, int *cidMap, int nCIDs,
725
				  GBool needVerticalMetrics,
Kristian Høgsberg's avatar
Kristian Høgsberg committed
726
727
				  FoFiOutputFunc outputFunc,
				  void *outputStream) {
728
  GooString *buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
729
  GooString *sfntsName;
730
  int maxUsedGlyph, n, i, j;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
731

732
733
734
735
  if (openTypeCFF) {
    return;
  }

Kristian Høgsberg's avatar
Kristian Høgsberg committed
736
737
  // write the Type 42 sfnts array
  sfntsName = (new GooString(psName))->append("_sfnts");
738
739
  cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics,
	   &maxUsedGlyph);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
740
741
742
  delete sfntsName;

  // write the descendant Type 42 fonts
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  // (The following is a kludge: nGlyphs is the glyph count from the
  // maxp table; maxUsedGlyph is the max glyph number that has a
  // non-zero-length description, from the loca table.  The problem is
  // that some TrueType font subsets fail to change the glyph count,
  // i.e., nGlyphs is much larger than maxUsedGlyph+1, which results
  // in an unnecessarily huge Type 0 font.  But some other PDF files
  // have fonts with only zero or one used glyph, and a content stream
  // that refers to one of the unused glyphs -- this results in PS
  // errors if we simply use maxUsedGlyph+1 for the Type 0 font.  So
  // we compromise by always defining at least 256 glyphs.)
  if (cidMap) {
    n = nCIDs;
  } else if (nGlyphs > maxUsedGlyph + 256) {
    if (maxUsedGlyph <= 255) {
      n = 256;
    } else {
      n = maxUsedGlyph + 1;
    }
  } else {
    n = nGlyphs;
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
764
765
766
767
  for (i = 0; i < n; i += 256) {
    (*outputFunc)(outputStream, "10 dict begin\n", 14);
    (*outputFunc)(outputStream, "/FontName /", 11);
    (*outputFunc)(outputStream, psName, strlen(psName));
768
769
770
    buf = GooString::format("_{0:02x} def\n", i >> 8);
    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
    delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
771
772
    (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
    (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
773
774
775
776
    buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
			  bbox[0], bbox[1], bbox[2], bbox[3]);
    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
    delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
777
778
779
780
781
782
    (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
    (*outputFunc)(outputStream, "/sfnts ", 7);
    (*outputFunc)(outputStream, psName, strlen(psName));
    (*outputFunc)(outputStream, "_sfnts def\n", 11);
    (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
    for (j = 0; j < 256 && i+j < n; ++j) {
783
784
785
      buf = GooString::format("dup {0:d} /c{1:02x} put\n", j, j);
      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
      delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
786
787
788
789
790
    }
    (*outputFunc)(outputStream, "readonly def\n", 13);
    (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
    (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
    for (j = 0; j < 256 && i+j < n; ++j) {
791
792
793
794
      buf = GooString::format("/c{0:02x} {1:d} def\n",
			    j, cidMap ? cidMap[i+j] : i+j);
      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
      delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
    }
    (*outputFunc)(outputStream, "end readonly def\n", 17);
    (*outputFunc)(outputStream,
		  "FontName currentdict end definefont pop\n", 40);
  }

  // write the Type 0 parent font
  (*outputFunc)(outputStream, "16 dict begin\n", 14);
  (*outputFunc)(outputStream, "/FontName /", 11);
  (*outputFunc)(outputStream, psName, strlen(psName));
  (*outputFunc)(outputStream, " def\n", 5);
  (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
  (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
  (*outputFunc)(outputStream, "/Encoding [\n", 12);
  for (i = 0; i < n; i += 256) {
811
812
813
    buf = GooString::format("{0:d}\n", i >> 8);
    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
    delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
814
815
816
817
818
819
  }
  (*outputFunc)(outputStream, "] def\n", 6);
  (*outputFunc)(outputStream, "/FDepVector [\n", 14);
  for (i = 0; i < n; i += 256) {
    (*outputFunc)(outputStream, "/", 1);
    (*outputFunc)(outputStream, psName, strlen(psName));
820
821
822
    buf = GooString::format("_{0:02x} findfont\n", i >> 8);
    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
    delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
823
824
825
826
827
  }
  (*outputFunc)(outputStream, "] def\n", 6);
  (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
}

828
void FoFiTrueType::convertToType0(char *psName, int *cidMap, int nCIDs,
829
830
				  FoFiOutputFunc outputFunc,
				  void *outputStream) {
831
832
  char *start;
  int length;
833
834
  FoFiType1C *ff;

835
  if (!getCFFBlock(&start, &length)) {
836
837
    return;
  }
838
  if (!(ff = FoFiType1C::make(start, length))) {
839
840
    return;
  }
841
  ff->convertToType0(psName, cidMap, nCIDs, outputFunc, outputStream);
842
843
844
  delete ff;
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
845
846
847
void FoFiTrueType::cvtEncoding(char **encoding,
			       FoFiOutputFunc outputFunc,
			       void *outputStream) {
848
  const char *name;
849
  GooString *buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
850
851
852
853
854
855
856
857
  int i;

  (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
  if (encoding) {
    for (i = 0; i < 256; ++i) {
      if (!(name = encoding[i])) {
	name = ".notdef";
      }
858
859
860
      buf = GooString::format("dup {0:d} /", i);
      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
      delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
861
862
863
864
865
      (*outputFunc)(outputStream, name, strlen(name));
      (*outputFunc)(outputStream, " put\n", 5);
    }
  } else {
    for (i = 0; i < 256; ++i) {
866
867
868
      buf = GooString::format("dup {0:d} /c{1:02x} put\n", i, i);
      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
      delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
869
870
871
872
873
874
    }
  }
  (*outputFunc)(outputStream, "readonly def\n", 13);
}

void FoFiTrueType::cvtCharStrings(char **encoding,
875
				  int *codeToGID,
Kristian Høgsberg's avatar
Kristian Høgsberg committed
876
877
878
				  FoFiOutputFunc outputFunc,
				  void *outputStream) {
  char *name;
879
880
  GooString *buf;
  char buf2[16];
Kristian Høgsberg's avatar
Kristian Høgsberg committed
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
  int i, k;

  // always define '.notdef'
  (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32);
  (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);

  // if there's no 'cmap' table, punt
  if (nCmaps == 0) {
    goto err;
  }

  // map char name to glyph index:
  // 1. use encoding to map name to char code
  // 2. use codeToGID to map char code to glyph index
  // N.B. We do this in reverse order because font subsets can have
  //      weird encodings that use the same character name twice, and
  //      the first definition is probably the one we want.
  k = 0; // make gcc happy
  for (i = 255; i >= 0; --i) {
    if (encoding) {
      name = encoding[i];
    } else {
      sprintf(buf2, "c%02x", i);
      name = buf2;
    }
    if (name && strcmp(name, ".notdef")) {
      k = codeToGID[i];
      // note: Distiller (maybe Adobe's PS interpreter in general)
      // doesn't like TrueType fonts that have CharStrings entries
      // which point to nonexistent glyphs, hence the (k < nGlyphs)
      // test
      if (k > 0 && k < nGlyphs) {
	(*outputFunc)(outputStream, "/", 1);
	(*outputFunc)(outputStream, name, strlen(name));
915
916
917
	buf = GooString::format(" {0:d} def\n", k);
	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
	delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
918
919
920
921
922
923
924
925
926
      }
    }
  }

 err:
  (*outputFunc)(outputStream, "end readonly def\n", 17);
}

void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
927
			    void *outputStream, GooString *name,
928
929
			    GBool needVerticalMetrics,
                            int *maxUsedGlyph) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
930
931
932
933
934
935
936
937
  Guchar headData[54];
  TrueTypeLoca *locaTable;
  Guchar *locaData;
  TrueTypeTable newTables[nT42Tables];
  Guchar tableDir[12 + nT42Tables*16];
  GBool ok;
  Guint checksum;
  int nNewTables;
938
  int glyfTableLen, length, pos, glyfPos, i, j, k;
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
  Guchar vheaTab[36] = {
    0, 1, 0, 0,			// table version number
    0, 0,			// ascent
    0, 0,			// descent
    0, 0,			// reserved
    0, 0,			// max advance height
    0, 0,			// min top side bearing
    0, 0,			// min bottom side bearing
    0, 0,			// y max extent
    0, 0,			// caret slope rise
    0, 1,			// caret slope run
    0, 0,			// caret offset
    0, 0,			// reserved
    0, 0,			// reserved
    0, 0,			// reserved
    0, 0,			// reserved
    0, 0,			// metric data format
    0, 1			// number of advance heights in vmtx table
  };
  Guchar *vmtxTab;
  GBool needVhea, needVmtx;
  int advance;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
961
962
963

  // construct the 'head' table, zero out the font checksum
  i = seekTable("head");
964
965
966
  if (i < 0 || i >= nTables) {
    return;
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
967
968
969
970
971
972
973
  pos = tables[i].offset;
  if (!checkRegion(pos, 54)) {
    return;
  }
  memcpy(headData, file + pos, 54);
  headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0;

974
975
976
977
978
979
980
  // check for a bogus loca format field in the 'head' table
  // (I've encountered fonts with loca format set to 0x0100 instead of 0x0001)
  if (locaFmt != 0 && locaFmt != 1) {
    headData[50] = 0;
    headData[51] = 1;
  }

Kristian Høgsberg's avatar
Kristian Høgsberg committed
981
982
983
984
  // read the original 'loca' table, pad entries out to 4 bytes, and
  // sort it into proper order -- some (non-compliant) fonts have
  // out-of-order loca tables; in order to correctly handle the case
  // where (compliant) fonts have empty entries in the middle of the
985
  // table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
Kristian Høgsberg's avatar
Kristian Høgsberg committed
986
987
  // and idx as its secondary key (ensuring that adjacent entries with
  // the same pos value remain in the same order)
988
  locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
989
990
  i = seekTable("loca");
  pos = tables[i].offset;
991
992
  i = seekTable("glyf");
  glyfTableLen = tables[i].len;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
993
994
995
996
997
998
999
1000
  ok = gTrue;
  for (i = 0; i <= nGlyphs; ++i) {
    locaTable[i].idx = i;
    if (locaFmt) {
      locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
    } else {
      locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
    }
1001
1002
1003
    if (locaTable[i].origOffset > glyfTableLen) {
      locaTable[i].origOffset = glyfTableLen;
    }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1004
  }
1005
1006
  std::sort(locaTable, locaTable + nGlyphs + 1,
	    cmpTrueTypeLocaOffsetFunctor());
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1007
1008
1009
1010
  for (i = 0; i < nGlyphs; ++i) {
    locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
  }
  locaTable[nGlyphs].len = 0;
1011
  std::sort(locaTable, locaTable + nGlyphs + 1, cmpTrueTypeLocaIdxFunctor());
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1012
  pos = 0;
1013
  *maxUsedGlyph = -1;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1014
1015
1016
1017
1018
1019
  for (i = 0; i <= nGlyphs; ++i) {
    locaTable[i].newOffset = pos;
    pos += locaTable[i].len;
    if (pos & 3) {
      pos += 4 - (pos & 3);
    }
1020
1021
1022
    if (locaTable[i].len > 0) {
      *maxUsedGlyph = i;
    }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1023
1024
1025
  }

  // construct the new 'loca' table
1026
  locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
  for (i = 0; i <= nGlyphs; ++i) {
    pos = locaTable[i].newOffset;
    if (locaFmt) {
      locaData[4*i  ] = (Guchar)(pos >> 24);
      locaData[4*i+1] = (Guchar)(pos >> 16);
      locaData[4*i+2] = (Guchar)(pos >>  8);
      locaData[4*i+3] = (Guchar) pos;
    } else {
      locaData[2*i  ] = (Guchar)(pos >> 9);
      locaData[2*i+1] = (Guchar)(pos >> 1);
    }
  }

  // count the number of tables
  nNewTables = 0;
  for (i = 0; i < nT42Tables; ++i) {
    if (t42Tables[i].required ||
	seekTable(t42Tables[i].tag) >= 0) {
      ++nNewTables;
    }
  }
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
  vmtxTab = NULL; // make gcc happy
  advance = 0; // make gcc happy
  if (needVerticalMetrics) {
    needVhea = seekTable("vhea") < 0;
    needVmtx = seekTable("vmtx") < 0;
    if (needVhea || needVmtx) {
      i = seekTable("head");
      advance = getU16BE(tables[i].offset + 18, &ok); // units per em
      if (needVhea) {
	++nNewTables;
      }
      if (needVmtx) {
	++nNewTables;
      }
    }
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098

  // construct the new table headers, including table checksums
  // (pad each table out to a multiple of 4 bytes)
  pos = 12 + nNewTables*16;
  k = 0;
  for (i = 0; i < nT42Tables; ++i) {
    length = -1;
    checksum = 0; // make gcc happy
    if (i == t42HeadTable) {
      length = 54;
      checksum = computeTableChecksum(headData, 54);
    } else if (i == t42LocaTable) {
      length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
      checksum = computeTableChecksum(locaData, length);
    } else if (i == t42GlyfTable) {
      length = 0;
      checksum = 0;
      glyfPos = tables[seekTable("glyf")].offset;
      for (j = 0; j < nGlyphs; ++j) {
	length += locaTable[j].len;
	if (length & 3) {
	  length += 4 - (length & 3);
	}
	if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
	  checksum +=
	      computeTableChecksum(file + glyfPos + locaTable[j].origOffset,
				   locaTable[j].len);
	}
      }
    } else {
      if ((j = seekTable(t42Tables[i].tag)) >= 0) {
	length = tables[j].len;
	if (checkRegion(tables[j].offset, length)) {
	  checksum = computeTableChecksum(file + tables[j].offset, length);
	}
1099
1100
1101
1102
1103
1104
      } else if (needVerticalMetrics && i == t42VheaTable) {
	vheaTab[10] = advance / 256;    // max advance height
	vheaTab[11] = advance % 256;
	length = sizeof(vheaTab);
	checksum = computeTableChecksum(vheaTab, length);
      } else if (needVerticalMetrics && i == t42VmtxTable) {
1105
	length = 4 + (nGlyphs - 1) * 2;
1106
1107
1108
1109
1110
1111
1112
1113
	vmtxTab = (Guchar *)gmalloc(length);
	vmtxTab[0] = advance / 256;
	vmtxTab[1] = advance % 256;
	for (j = 2; j < length; j += 2) {
	  vmtxTab[j] = 0;
	  vmtxTab[j+1] = 0;
	}
	checksum = computeTableChecksum(vmtxTab, length);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
      } else if (t42Tables[i].required) {
	//~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
	//~       t42Tables[i].tag);
	length = 0;
	checksum = 0;
      }
    }
    if (length >= 0) {
      newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) |
	                 ((t42Tables[i].tag[1] & 0xff) << 16) |
	                 ((t42Tables[i].tag[2] & 0xff) <<  8) |
	                  (t42Tables[i].tag[3] & 0xff);
      newTables[k].checksum = checksum;
      newTables[k].offset = pos;
      newTables[k].len = length;
      pos += length;
      if (pos & 3) {
	pos += 4 - (length & 3);
      }
      ++k;
    }
  }

  // construct the table directory
  tableDir[0] = 0x00;		// sfnt version
  tableDir[1] = 0x01;
  tableDir[2] = 0x00;
  tableDir[3] = 0x00;
  tableDir[4] = 0;		// numTables
  tableDir[5] = nNewTables;
  tableDir[6] = 0;		// searchRange
  tableDir[7] = (Guchar)128;
  tableDir[8] = 0;		// entrySelector
  tableDir[9] = 3;
  tableDir[10] = 0;		// rangeShift
  tableDir[11] = (Guchar)(16 * nNewTables - 128);
  pos = 12;
  for (i = 0; i < nNewTables; ++i) {
    tableDir[pos   ] = (Guchar)(newTables[i].tag >> 24);
    tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16);
    tableDir[pos+ 2] = (Guchar)(newTables[i].tag >>  8);
    tableDir[pos+ 3] = (Guchar) newTables[i].tag;
    tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24);
    tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16);
    tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >>  8);
    tableDir[pos+ 7] = (Guchar) newTables[i].checksum;
    tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24);
    tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16);
    tableDir[pos+10] = (Guchar)(newTables[i].offset >>  8);
    tableDir[pos+11] = (Guchar) newTables[i].offset;
    tableDir[pos+12] = (Guchar)(newTables[i].len >> 24);
    tableDir[pos+13] = (Guchar)(newTables[i].len >> 16);
    tableDir[pos+14] = (Guchar)(newTables[i].len >>  8);
    tableDir[pos+15] = (Guchar) newTables[i].len;
    pos += 16;
  }

  // compute the font checksum and store it in the head table
  checksum = computeTableChecksum(tableDir, 12 + nNewTables*16);
  for (i = 0; i < nNewTables; ++i) {
    checksum += newTables[i].checksum;
  }
  checksum = 0xb1b0afba - checksum; // because the TrueType spec says so
  headData[ 8] = (Guchar)(checksum >> 24);
  headData[ 9] = (Guchar)(checksum >> 16);
  headData[10] = (Guchar)(checksum >>  8);
  headData[11] = (Guchar) checksum;

  // start the sfnts array
  if (name) {
    (*outputFunc)(outputStream, "/", 1);
    (*outputFunc)(outputStream, name->getCString(), name->getLength());
    (*outputFunc)(outputStream, " [\n", 3);
  } else {
    (*outputFunc)(outputStream, "/sfnts [\n", 9);
  }

  // write the table directory
  dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream);

  // write the tables
  for (i = 0; i < nNewTables; ++i) {
    if (i == t42HeadTable) {
      dumpString(headData, 54, outputFunc, outputStream);
    } else if (i == t42LocaTable) {
      length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
      dumpString(locaData, length, outputFunc, outputStream);
    } else if (i == t42GlyfTable) {
      glyfPos = tables[seekTable("glyf")].offset;
      for (j = 0; j < nGlyphs; ++j) {
	if (locaTable[j].len > 0 &&
	    checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
	  dumpString(file + glyfPos + locaTable[j].origOffset,
		     locaTable[j].len, outputFunc, outputStream);
	}
      }
    } else {
      // length == 0 means the table is missing and the error was
      // already reported during the construction of the table
      // headers
      if ((length = newTables[i].len) > 0) {
	if ((j = seekTable(t42Tables[i].tag)) >= 0 &&
	    checkRegion(tables[j].offset, tables[j].len)) {
	  dumpString(file + tables[j].offset, tables[j].len,
		     outputFunc, outputStream);
1219
1220
1221
1222
	} else if (needVerticalMetrics && i == t42VheaTable) {
	  dumpString(vheaTab, length, outputFunc, outputStream);
	} else if (needVerticalMetrics && i == t42VmtxTable) {
	  dumpString(vmtxTab, length, outputFunc, outputStream);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
	}
      }
    }
  }

  // end the sfnts array
  (*outputFunc)(outputStream, "] def\n", 6);

  gfree(locaData);
  gfree(locaTable);
1233
1234
1235
  if (vmtxTab) {
    gfree(vmtxTab);
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1236
1237
1238
1239
1240
}

void FoFiTrueType::dumpString(Guchar *s, int length,
			      FoFiOutputFunc outputFunc,
			      void *outputStream) {
1241
  GooString *buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1242
1243
1244
1245
1246
  int pad, i, j;

  (*outputFunc)(outputStream, "<", 1);
  for (i = 0; i < length; i += 32) {
    for (j = 0; j < 32 && i+j < length; ++j) {
1247
1248
1249
      buf = GooString::format("{0:02x}", s[i+j] & 0xff);
      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
      delete buf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
    }
    if (i % (65536 - 32) == 65536 - 64) {
      (*outputFunc)(outputStream, ">\n<", 3);
    } else if (i+32 < length) {
      (*outputFunc)(outputStream, "\n", 1);
    }
  }
  if (length & 3) {
    pad = 4 - (length & 3);
    for (i = 0; i < pad; ++i) {
      (*outputFunc)(outputStream, "00", 2);
    }
  }
  // add an extra zero byte because the Adobe Type 42 spec says so
  (*outputFunc)(outputStream, "00>\n", 4);
}

Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) {
  Guint checksum, word;
  int i;

  checksum = 0;
  for (i = 0; i+3 < length; i += 4) {
    word = ((data[i  ] & 0xff) << 24) +
           ((data[i+1] & 0xff) << 16) +
           ((data[i+2] & 0xff) <<  8) +
            (data[i+3] & 0xff);
    checksum += word;
  }
  if (length & 3) {
    word = 0;
    i = length & ~3;
    switch (length & 3) {
    case 3:
      word |= (data[i+2] & 0xff) <<  8;
    case 2:
      word |= (data[i+1] & 0xff) << 16;
    case 1:
      word |= (data[i  ] & 0xff) << 24;
      break;
    }
    checksum += word;
  }
  return checksum;
}

void FoFiTrueType::parse() {
1297
  Guint topTag;
1298
  int pos, ver, i, j;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1299
1300
1301

  parsedOk = gTrue;

1302
1303
1304
1305
1306
1307
  // look for a collection (TTC)
  topTag = getU32BE(0, &parsedOk);
  if (!parsedOk) {
    return;
  }
  if (topTag == ttcfTag) {
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
    /* TTC font */
    int dircount;

    dircount = getU32BE(8, &parsedOk);
    if (!parsedOk)
      return;
    if (! dircount) {
      parsedOk = gFalse;
      return;
    }

    if (faceIndex >= dircount)
      faceIndex = 0;
    pos = getU32BE(12 + faceIndex * 4, &parsedOk);
    if (! parsedOk)
      return;
1324
1325
  } else {
    pos = 0;
1326
1327
  }

1328
1329
  // check the sfnt version
  ver = getU32BE(pos, &parsedOk);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1330
1331
1332
  if (!parsedOk) {
    return;
  }
1333
  openTypeCFF = ver == 0x4f54544f; // 'OTTO'
1334

1335
1336
1337
1338
1339
  // read the table directory
  nTables = getU16BE(pos + 4, &parsedOk);
  if (!parsedOk) {
    return;
  }
1340
  tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable));
1341
  pos += 12;
1342
  j = 0;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1343
  for (i = 0; i < nTables; ++i) {
1344
1345
1346
1347
1348
1349
1350
1351
    tables[j].tag = getU32BE(pos, &parsedOk);
    tables[j].checksum = getU32BE(pos + 4, &parsedOk);
    tables[j].offset = (int)getU32BE(pos + 8, &parsedOk);
    tables[j].len = (int)getU32BE(pos + 12, &parsedOk);
    if (tables[j].offset + tables[j].len >= tables[j].offset &&
	tables[j].offset + tables[j].len <= len) {
      // ignore any bogus entries in the table directory
      ++j;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1352
1353
1354
    }
    pos += 16;
  }
1355
1356
1357
1358
  if (nTables != j) {
    nTables = j;
    tables = (TrueTypeTable *)greallocn_checkoverflow(tables, nTables, sizeof(TrueTypeTable));
  }
1359
  if (!parsedOk || tables == NULL) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1360
1361
1362
1363
1364
1365
1366
1367
    return;
  }

  // check for tables that are required by both the TrueType spec and
  // the Type 42 spec
  if (seekTable("head") < 0 ||
      seekTable("hhea") < 0 ||
      seekTable("maxp") < 0 ||
1368
1369
1370
1371
      seekTable("hmtx") < 0 ||
      (!openTypeCFF && seekTable("loca") < 0) ||
      (!openTypeCFF && seekTable("glyf") < 0) ||
      (openTypeCFF && seekTable("CFF ") < 0)) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
    parsedOk = gFalse;
    return;
  }

  // read the cmaps
  if ((i = seekTable("cmap")) >= 0) {
    pos = tables[i].offset + 2;
    nCmaps = getU16BE(pos, &parsedOk);
    pos += 2;
    if (!parsedOk) {
      return;
    }
1384
    cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
    for (j = 0; j < nCmaps; ++j) {
      cmaps[j].platform = getU16BE(pos, &parsedOk);
      cmaps[j].encoding = getU16BE(pos + 2, &parsedOk);
      cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk);
      pos += 8;
      cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk);
      cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk);
    }
    if (!parsedOk) {
      return;
    }
  } else {
    nCmaps = 0;
  }

  // get the number of glyphs from the maxp table
  i = seekTable("maxp");
  nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk);
  if (!parsedOk) {
    return;
  }

  // get the bbox and loca table format from the head table
  i = seekTable("head");
  bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk);
  bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk);
  bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk);
  bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk);
  locaFmt = getS16BE(tables[i].offset + 50, &parsedOk);
  if (!parsedOk) {
    return;
  }

1418
1419
  // read the post table
  readPostTable();
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1420
1421
1422
1423
1424
}

void FoFiTrueType::readPostTable() {
  GooString *name;
  int tablePos, postFmt, stringIdx, stringPos;
1425
  GBool ok;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1426
1427
  int i, j, n, m;

1428
  ok = gTrue;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1429
1430
1431
1432
  if ((i = seekTable("post")) < 0) {
    return;
  }
  tablePos = tables[i].offset;
1433
1434
1435
  postFmt = getU32BE(tablePos, &ok);
  if (!ok) {
    goto err;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1436
1437
1438
1439
1440
1441
1442
1443
  }
  if (postFmt == 0x00010000) {
    nameToGID = new GooHash(gTrue);
    for (i = 0; i < 258; ++i) {
      nameToGID->add(new GooString(macGlyphNames[i]), i);
    }
  } else if (postFmt == 0x00020000) {
    nameToGID = new GooHash(gTrue);
1444
1445
1446
    n = getU16BE(tablePos + 32, &ok);
    if (!ok) {
      goto err;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1447
1448
1449
1450
1451
1452
1453
    }
    if (n > nGlyphs) {
      n = nGlyphs;
    }
    stringIdx = 0;
    stringPos = tablePos + 34 + 2*n;
    for (i = 0; i < n; ++i) {
1454
      j = getU16BE(tablePos + 34 + 2*i, &ok);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1455
1456
1457
1458
1459
1460
1461
1462
      if (j < 258) {
	nameToGID->removeInt(macGlyphNames[j]);
	nameToGID->add(new GooString(macGlyphNames[j]), i);
      } else {
	j -= 258;
	if (j != stringIdx) {
	  for (stringIdx = 0, stringPos = tablePos + 34 + 2*n;
	       stringIdx < j;
1463
1464
1465
	       ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ;
	  if (!ok) {
	    goto err;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1466
1467
	  }
	}
1468
1469
1470
	m = getU8(stringPos, &ok);
	if (!ok || !checkRegion(stringPos + 1, m)) {
	  goto err;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
	}
	name = new GooString((char *)&file[stringPos + 1], m);
	nameToGID->removeInt(name);
	nameToGID->add(name, i);
	++stringIdx;
	stringPos += 1 + m;
      }
    }
  } else if (postFmt == 0x00028000) {
    nameToGID = new GooHash(gTrue);
    for (i = 0; i < nGlyphs; ++i) {
1482
1483
1484
      j = getU8(tablePos + 32 + i, &ok);
      if (!ok) {
	goto err;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1485
1486
1487
1488
1489
1490
1491
      }
      if (j < 258) {
	nameToGID->removeInt(macGlyphNames[j]);
	nameToGID->add(new GooString(macGlyphNames[j]), i);
      }
    }
  }
1492
1493
1494
1495
1496
1497
1498
1499

  return;

 err:
  if (nameToGID) {
    delete nameToGID;
    nameToGID = NULL;
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1500
1501
}

1502
int FoFiTrueType::seekTable(const char *tag) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
  Guint tagI;
  int i;

  tagI = ((tag[0] & 0xff) << 24) |
         ((tag[1] & 0xff) << 16) |
         ((tag[2] & 0xff) << 8) |
          (tag[3] & 0xff);
  for (i = 0; i < nTables; ++i) {
    if (tables[i].tag == tagI) {
      return i;
    }
  }
  return -1;
}
Albert Astals Cid's avatar
Albert Astals Cid committed
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539

Guint FoFiTrueType::charToTag(const char *tagName)
{
  int n = strlen(tagName);
  Guint tag = 0;
  int i;

  if (n > 4) n = 4;
  for (i = 0;i < n;i++) {
    tag <<= 8;
    tag |= tagName[i] & 0xff;
  }
  for (;i < 4;i++) {
    tag <<= 8;
    tag |= ' ';
  }
  return tag;
}

/*
  setup GSUB table data
  Only supporting vertical text substitution.
*/
suzuki toshiya's avatar
suzuki toshiya committed
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
int FoFiTrueType::setupGSUB(const char *scriptName)
{
  return setupGSUB(scriptName, NULL);
}

/*
  setup GSUB table data
  Only supporting vertical text substitution.
*/
int FoFiTrueType::setupGSUB(const char *scriptName,
                            const char *languageName)
Albert Astals Cid's avatar
Albert Astals Cid committed
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
{
  Guint gsubTable;
  unsigned int i;
  Guint scriptList, featureList;
  Guint scriptCount;
  Guint tag;
  Guint scriptTable = 0;
  Guint langSys;
  Guint featureCount;
  Guint featureIndex;
  Guint ftable = 0;
  Guint llist;
  Guint scriptTag;
  int x;
  Guint pos;

suzuki toshiya's avatar
suzuki toshiya committed
1567
  if (scriptName == 0) {
Albert Astals Cid's avatar
Albert Astals Cid committed
1568
1569
1570
    gsubFeatureTable = 0;
    return 0;
  }
suzuki toshiya's avatar
suzuki toshiya committed
1571
  scriptTag = charToTag(scriptName);
Albert Astals Cid's avatar
Albert Astals Cid committed
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595