pprdrv_tt.cpp 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401
  1. /* -*- mode: c++; c-basic-offset: 4 -*- */
  2. /*
  3. * Modified for use within matplotlib
  4. * 5 July 2007
  5. * Michael Droettboom
  6. */
  7. /*
  8. ** ~ppr/src/pprdrv/pprdrv_tt.c
  9. ** Copyright 1995, Trinity College Computing Center.
  10. ** Written by David Chappell.
  11. **
  12. ** Permission to use, copy, modify, and distribute this software and its
  13. ** documentation for any purpose and without fee is hereby granted, provided
  14. ** that the above copyright notice appear in all copies and that both that
  15. ** copyright notice and this permission notice appear in supporting
  16. ** documentation. This software is provided "as is" without express or
  17. ** implied warranty.
  18. **
  19. ** TrueType font support. These functions allow PPR to generate
  20. ** PostScript fonts from Microsoft compatible TrueType font files.
  21. **
  22. ** Last revised 19 December 1995.
  23. */
  24. #include <cstdio>
  25. #include <cstdlib>
  26. #include <cstring>
  27. #include "pprdrv.h"
  28. #include "truetype.h"
  29. #include <sstream>
  30. #ifdef _POSIX_C_SOURCE
  31. # undef _POSIX_C_SOURCE
  32. #endif
  33. #ifndef _AIX
  34. #ifdef _XOPEN_SOURCE
  35. # undef _XOPEN_SOURCE
  36. #endif
  37. #endif
  38. #include <Python.h>
  39. /*==========================================================================
  40. ** Convert the indicated Truetype font file to a type 42 or type 3
  41. ** PostScript font and insert it in the output stream.
  42. **
  43. ** All the routines from here to the end of file file are involved
  44. ** in this process.
  45. ==========================================================================*/
  46. /*---------------------------------------
  47. ** Endian conversion routines.
  48. ** These routines take a BYTE pointer
  49. ** and return a value formed by reading
  50. ** bytes starting at that point.
  51. **
  52. ** These routines read the big-endian
  53. ** values which are used in TrueType
  54. ** font files.
  55. ---------------------------------------*/
  56. /*
  57. ** Get an Unsigned 32 bit number.
  58. */
  59. ULONG getULONG(BYTE *p)
  60. {
  61. int x;
  62. ULONG val=0;
  63. for (x=0; x<4; x++)
  64. {
  65. val *= 0x100;
  66. val += p[x];
  67. }
  68. return val;
  69. } /* end of ftohULONG() */
  70. /*
  71. ** Get an unsigned 16 bit number.
  72. */
  73. USHORT getUSHORT(BYTE *p)
  74. {
  75. int x;
  76. USHORT val=0;
  77. for (x=0; x<2; x++)
  78. {
  79. val *= 0x100;
  80. val += p[x];
  81. }
  82. return val;
  83. } /* end of getUSHORT() */
  84. /*
  85. ** Get a 32 bit fixed point (16.16) number.
  86. ** A special structure is used to return the value.
  87. */
  88. Fixed getFixed(BYTE *s)
  89. {
  90. Fixed val={0,0};
  91. val.whole = ((s[0] * 256) + s[1]);
  92. val.fraction = ((s[2] * 256) + s[3]);
  93. return val;
  94. } /* end of getFixed() */
  95. /*-----------------------------------------------------------------------
  96. ** Load a TrueType font table into memory and return a pointer to it.
  97. ** The font's "file" and "offset_table" fields must be set before this
  98. ** routine is called.
  99. **
  100. ** This first argument is a TrueType font structure, the second
  101. ** argument is the name of the table to retrieve. A table name
  102. ** is always 4 characters, though the last characters may be
  103. ** padding spaces.
  104. -----------------------------------------------------------------------*/
  105. BYTE *GetTable(struct TTFONT *font, const char *name)
  106. {
  107. BYTE *ptr;
  108. ULONG x;
  109. debug("GetTable(file,font,\"%s\")",name);
  110. /* We must search the table directory. */
  111. ptr = font->offset_table + 12;
  112. x=0;
  113. while (true)
  114. {
  115. if ( strncmp((const char*)ptr,name,4) == 0 )
  116. {
  117. ULONG offset,length;
  118. BYTE *table;
  119. offset = getULONG( ptr + 8 );
  120. length = getULONG( ptr + 12 );
  121. table = (BYTE*)calloc( sizeof(BYTE), length + 2 );
  122. try
  123. {
  124. debug("Loading table \"%s\" from offset %d, %d bytes",name,offset,length);
  125. if ( fseek( font->file, (long)offset, SEEK_SET ) )
  126. {
  127. throw TTException("TrueType font may be corrupt (reason 3)");
  128. }
  129. if ( fread(table,sizeof(BYTE),length,font->file) != (sizeof(BYTE) * length))
  130. {
  131. throw TTException("TrueType font may be corrupt (reason 4)");
  132. }
  133. }
  134. catch (TTException& )
  135. {
  136. free(table);
  137. throw;
  138. }
  139. /* Always NUL-terminate; add two in case of UTF16 strings. */
  140. table[length] = '\0';
  141. table[length + 1] = '\0';
  142. return table;
  143. }
  144. x++;
  145. ptr += 16;
  146. if (x == font->numTables)
  147. {
  148. throw TTException("TrueType font is missing table");
  149. }
  150. }
  151. } /* end of GetTable() */
  152. static void utf16be_to_ascii(char *dst, char *src, size_t length) {
  153. ++src;
  154. for (; *src != 0 && length; dst++, src += 2, --length) {
  155. *dst = *src;
  156. }
  157. }
  158. /*--------------------------------------------------------------------
  159. ** Load the 'name' table, get information from it,
  160. ** and store that information in the font structure.
  161. **
  162. ** The 'name' table contains information such as the name of
  163. ** the font, and it's PostScript name.
  164. --------------------------------------------------------------------*/
  165. void Read_name(struct TTFONT *font)
  166. {
  167. BYTE *table_ptr,*ptr2;
  168. int numrecords; /* Number of strings in this table */
  169. BYTE *strings; /* pointer to start of string storage */
  170. int x;
  171. int platform; /* Current platform id */
  172. int nameid; /* name id, */
  173. int offset,length; /* offset and length of string. */
  174. debug("Read_name()");
  175. table_ptr = NULL;
  176. /* Set default values to avoid future references to undefined
  177. * pointers. Allocate each of PostName, FullName, FamilyName,
  178. * Version, and Style separately so they can be freed safely. */
  179. for (char **ptr = &(font->PostName); ptr != NULL; )
  180. {
  181. *ptr = (char*) calloc(sizeof(char), strlen("unknown")+1);
  182. strcpy(*ptr, "unknown");
  183. if (ptr == &(font->PostName)) ptr = &(font->FullName);
  184. else if (ptr == &(font->FullName)) ptr = &(font->FamilyName);
  185. else if (ptr == &(font->FamilyName)) ptr = &(font->Version);
  186. else if (ptr == &(font->Version)) ptr = &(font->Style);
  187. else ptr = NULL;
  188. }
  189. font->Copyright = font->Trademark = (char*)NULL;
  190. table_ptr = GetTable(font, "name"); /* pointer to table */
  191. try
  192. {
  193. numrecords = getUSHORT( table_ptr + 2 ); /* number of names */
  194. strings = table_ptr + getUSHORT( table_ptr + 4 ); /* start of string storage */
  195. ptr2 = table_ptr + 6;
  196. for (x=0; x < numrecords; x++,ptr2+=12)
  197. {
  198. platform = getUSHORT(ptr2);
  199. nameid = getUSHORT(ptr2+6);
  200. length = getUSHORT(ptr2+8);
  201. offset = getUSHORT(ptr2+10);
  202. debug("platform %d, encoding %d, language 0x%x, name %d, offset %d, length %d",
  203. platform,encoding,language,nameid,offset,length);
  204. /* Copyright notice */
  205. if ( platform == 1 && nameid == 0 )
  206. {
  207. font->Copyright = (char*)calloc(sizeof(char),length+1);
  208. strncpy(font->Copyright,(const char*)strings+offset,length);
  209. font->Copyright[length]='\0';
  210. replace_newlines_with_spaces(font->Copyright);
  211. debug("font->Copyright=\"%s\"",font->Copyright);
  212. continue;
  213. }
  214. /* Font Family name */
  215. if ( platform == 1 && nameid == 1 )
  216. {
  217. free(font->FamilyName);
  218. font->FamilyName = (char*)calloc(sizeof(char),length+1);
  219. strncpy(font->FamilyName,(const char*)strings+offset,length);
  220. font->FamilyName[length]='\0';
  221. replace_newlines_with_spaces(font->FamilyName);
  222. debug("font->FamilyName=\"%s\"",font->FamilyName);
  223. continue;
  224. }
  225. /* Font Family name */
  226. if ( platform == 1 && nameid == 2 )
  227. {
  228. free(font->Style);
  229. font->Style = (char*)calloc(sizeof(char),length+1);
  230. strncpy(font->Style,(const char*)strings+offset,length);
  231. font->Style[length]='\0';
  232. replace_newlines_with_spaces(font->Style);
  233. debug("font->Style=\"%s\"",font->Style);
  234. continue;
  235. }
  236. /* Full Font name */
  237. if ( platform == 1 && nameid == 4 )
  238. {
  239. free(font->FullName);
  240. font->FullName = (char*)calloc(sizeof(char),length+1);
  241. strncpy(font->FullName,(const char*)strings+offset,length);
  242. font->FullName[length]='\0';
  243. replace_newlines_with_spaces(font->FullName);
  244. debug("font->FullName=\"%s\"",font->FullName);
  245. continue;
  246. }
  247. /* Version string */
  248. if ( platform == 1 && nameid == 5 )
  249. {
  250. free(font->Version);
  251. font->Version = (char*)calloc(sizeof(char),length+1);
  252. strncpy(font->Version,(const char*)strings+offset,length);
  253. font->Version[length]='\0';
  254. replace_newlines_with_spaces(font->Version);
  255. debug("font->Version=\"%s\"",font->Version);
  256. continue;
  257. }
  258. /* PostScript name */
  259. if ( platform == 1 && nameid == 6 )
  260. {
  261. free(font->PostName);
  262. font->PostName = (char*)calloc(sizeof(char),length+1);
  263. strncpy(font->PostName,(const char*)strings+offset,length);
  264. font->PostName[length]='\0';
  265. replace_newlines_with_spaces(font->PostName);
  266. debug("font->PostName=\"%s\"",font->PostName);
  267. continue;
  268. }
  269. /* Microsoft-format PostScript name */
  270. if ( platform == 3 && nameid == 6 )
  271. {
  272. free(font->PostName);
  273. font->PostName = (char*)calloc(sizeof(char),length+1);
  274. utf16be_to_ascii(font->PostName, (char *)strings+offset, length);
  275. font->PostName[length/2]='\0';
  276. replace_newlines_with_spaces(font->PostName);
  277. debug("font->PostName=\"%s\"",font->PostName);
  278. continue;
  279. }
  280. /* Trademark string */
  281. if ( platform == 1 && nameid == 7 )
  282. {
  283. font->Trademark = (char*)calloc(sizeof(char),length+1);
  284. strncpy(font->Trademark,(const char*)strings+offset,length);
  285. font->Trademark[length]='\0';
  286. replace_newlines_with_spaces(font->Trademark);
  287. debug("font->Trademark=\"%s\"",font->Trademark);
  288. continue;
  289. }
  290. }
  291. }
  292. catch (TTException& )
  293. {
  294. free(table_ptr);
  295. throw;
  296. }
  297. free(table_ptr);
  298. } /* end of Read_name() */
  299. /*---------------------------------------------------------------------
  300. ** Write the header for a PostScript font.
  301. ---------------------------------------------------------------------*/
  302. void ttfont_header(TTStreamWriter& stream, struct TTFONT *font)
  303. {
  304. int VMMin;
  305. int VMMax;
  306. /*
  307. ** To show that it is a TrueType font in PostScript format,
  308. ** we will begin the file with a specific string.
  309. ** This string also indicates the version of the TrueType
  310. ** specification on which the font is based and the
  311. ** font manufacturer's revision number for the font.
  312. */
  313. if ( font->target_type == PS_TYPE_42 ||
  314. font->target_type == PS_TYPE_42_3_HYBRID)
  315. {
  316. stream.printf("%%!PS-TrueTypeFont-%d.%d-%d.%d\n",
  317. font->TTVersion.whole, font->TTVersion.fraction,
  318. font->MfrRevision.whole, font->MfrRevision.fraction);
  319. }
  320. /* If it is not a Type 42 font, we will use a different format. */
  321. else
  322. {
  323. stream.putline("%!PS-Adobe-3.0 Resource-Font");
  324. } /* See RBIIp 641 */
  325. /* We will make the title the name of the font. */
  326. stream.printf("%%%%Title: %s\n",font->FullName);
  327. /* If there is a Copyright notice, put it here too. */
  328. if ( font->Copyright != (char*)NULL )
  329. {
  330. stream.printf("%%%%Copyright: %s\n",font->Copyright);
  331. }
  332. /* We created this file. */
  333. if ( font->target_type == PS_TYPE_42 )
  334. {
  335. stream.putline("%%Creator: Converted from TrueType to type 42 by PPR");
  336. }
  337. else if (font->target_type == PS_TYPE_42_3_HYBRID)
  338. {
  339. stream.putline("%%Creator: Converted from TypeType to type 42/type 3 hybrid by PPR");
  340. }
  341. else
  342. {
  343. stream.putline("%%Creator: Converted from TrueType to type 3 by PPR");
  344. }
  345. /* If VM usage information is available, print it. */
  346. if ( font->target_type == PS_TYPE_42 || font->target_type == PS_TYPE_42_3_HYBRID)
  347. {
  348. VMMin = (int)getULONG( font->post_table + 16 );
  349. VMMax = (int)getULONG( font->post_table + 20 );
  350. if ( VMMin > 0 && VMMax > 0 )
  351. stream.printf("%%%%VMUsage: %d %d\n",VMMin,VMMax);
  352. }
  353. /* Start the dictionary which will eventually */
  354. /* become the font. */
  355. if (font->target_type == PS_TYPE_42)
  356. {
  357. stream.putline("15 dict begin");
  358. }
  359. else
  360. {
  361. stream.putline("25 dict begin");
  362. /* Type 3 fonts will need some subroutines here. */
  363. stream.putline("/_d{bind def}bind def");
  364. stream.putline("/_m{moveto}_d");
  365. stream.putline("/_l{lineto}_d");
  366. stream.putline("/_cl{closepath eofill}_d");
  367. stream.putline("/_c{curveto}_d");
  368. stream.putline("/_sc{7 -1 roll{setcachedevice}{pop pop pop pop pop pop}ifelse}_d");
  369. stream.putline("/_e{exec}_d");
  370. }
  371. stream.printf("/FontName /%s def\n",font->PostName);
  372. stream.putline("/PaintType 0 def");
  373. if (font->target_type == PS_TYPE_42 || font->target_type == PS_TYPE_42_3_HYBRID)
  374. {
  375. stream.putline("/FontMatrix[1 0 0 1 0 0]def");
  376. }
  377. else
  378. {
  379. stream.putline("/FontMatrix[.001 0 0 .001 0 0]def");
  380. }
  381. stream.printf("/FontBBox[%d %d %d %d]def\n",font->llx-1,font->lly-1,font->urx,font->ury);
  382. if (font->target_type == PS_TYPE_42 || font->target_type == PS_TYPE_42_3_HYBRID)
  383. {
  384. stream.printf("/FontType 42 def\n", font->target_type );
  385. }
  386. else
  387. {
  388. stream.printf("/FontType 3 def\n", font->target_type );
  389. }
  390. } /* end of ttfont_header() */
  391. /*-------------------------------------------------------------
  392. ** Define the encoding array for this font.
  393. ** Since we don't really want to deal with converting all of
  394. ** the possible font encodings in the wild to a standard PS
  395. ** one, we just explicitly create one for each font.
  396. -------------------------------------------------------------*/
  397. void ttfont_encoding(TTStreamWriter& stream, struct TTFONT *font, std::vector<int>& glyph_ids, font_type_enum target_type)
  398. {
  399. if (target_type == PS_TYPE_3 || target_type == PS_TYPE_42_3_HYBRID)
  400. {
  401. stream.printf("/Encoding [ ");
  402. for (std::vector<int>::const_iterator i = glyph_ids.begin();
  403. i != glyph_ids.end(); ++i)
  404. {
  405. const char* name = ttfont_CharStrings_getname(font, *i);
  406. stream.printf("/%s ", name);
  407. }
  408. stream.printf("] def\n");
  409. }
  410. else
  411. {
  412. stream.putline("/Encoding StandardEncoding def");
  413. }
  414. } /* end of ttfont_encoding() */
  415. /*-----------------------------------------------------------
  416. ** Create the optional "FontInfo" sub-dictionary.
  417. -----------------------------------------------------------*/
  418. void ttfont_FontInfo(TTStreamWriter& stream, struct TTFONT *font)
  419. {
  420. Fixed ItalicAngle;
  421. /* We create a sub dictionary named "FontInfo" where we */
  422. /* store information which though it is not used by the */
  423. /* interpreter, is useful to some programs which will */
  424. /* be printing with the font. */
  425. stream.putline("/FontInfo 10 dict dup begin");
  426. /* These names come from the TrueType font's "name" table. */
  427. stream.printf("/FamilyName (%s) def\n",font->FamilyName);
  428. stream.printf("/FullName (%s) def\n",font->FullName);
  429. if ( font->Copyright != (char*)NULL || font->Trademark != (char*)NULL )
  430. {
  431. stream.printf("/Notice (%s",
  432. font->Copyright != (char*)NULL ? font->Copyright : "");
  433. stream.printf("%s%s) def\n",
  434. font->Trademark != (char*)NULL ? " " : "",
  435. font->Trademark != (char*)NULL ? font->Trademark : "");
  436. }
  437. /* This information is not quite correct. */
  438. stream.printf("/Weight (%s) def\n",font->Style);
  439. /* Some fonts have this as "version". */
  440. stream.printf("/Version (%s) def\n",font->Version);
  441. /* Some information from the "post" table. */
  442. ItalicAngle = getFixed( font->post_table + 4 );
  443. stream.printf("/ItalicAngle %d.%d def\n",ItalicAngle.whole,ItalicAngle.fraction);
  444. stream.printf("/isFixedPitch %s def\n", getULONG( font->post_table + 12 ) ? "true" : "false" );
  445. stream.printf("/UnderlinePosition %d def\n", (int)getFWord( font->post_table + 8 ) );
  446. stream.printf("/UnderlineThickness %d def\n", (int)getFWord( font->post_table + 10 ) );
  447. stream.putline("end readonly def");
  448. } /* end of ttfont_FontInfo() */
  449. /*-------------------------------------------------------------------
  450. ** sfnts routines
  451. ** These routines generate the PostScript "sfnts" array which
  452. ** contains one or more strings which contain a reduced version
  453. ** of the TrueType font.
  454. **
  455. ** A number of functions are required to accomplish this rather
  456. ** complicated task.
  457. -------------------------------------------------------------------*/
  458. int string_len;
  459. int line_len;
  460. bool in_string;
  461. /*
  462. ** This is called once at the start.
  463. */
  464. void sfnts_start(TTStreamWriter& stream)
  465. {
  466. stream.puts("/sfnts[<");
  467. in_string=true;
  468. string_len=0;
  469. line_len=8;
  470. } /* end of sfnts_start() */
  471. /*
  472. ** Write a BYTE as a hexadecimal value as part of the sfnts array.
  473. */
  474. void sfnts_pputBYTE(TTStreamWriter& stream, BYTE n)
  475. {
  476. static const char hexdigits[]="0123456789ABCDEF";
  477. if (!in_string)
  478. {
  479. stream.put_char('<');
  480. string_len=0;
  481. line_len++;
  482. in_string=true;
  483. }
  484. stream.put_char( hexdigits[ n / 16 ] );
  485. stream.put_char( hexdigits[ n % 16 ] );
  486. string_len++;
  487. line_len+=2;
  488. if (line_len > 70)
  489. {
  490. stream.put_char('\n');
  491. line_len=0;
  492. }
  493. } /* end of sfnts_pputBYTE() */
  494. /*
  495. ** Write a USHORT as a hexadecimal value as part of the sfnts array.
  496. */
  497. void sfnts_pputUSHORT(TTStreamWriter& stream, USHORT n)
  498. {
  499. sfnts_pputBYTE(stream, n / 256);
  500. sfnts_pputBYTE(stream, n % 256);
  501. } /* end of sfnts_pputUSHORT() */
  502. /*
  503. ** Write a ULONG as part of the sfnts array.
  504. */
  505. void sfnts_pputULONG(TTStreamWriter& stream, ULONG n)
  506. {
  507. int x1,x2,x3;
  508. x1 = n % 256;
  509. n /= 256;
  510. x2 = n % 256;
  511. n /= 256;
  512. x3 = n % 256;
  513. n /= 256;
  514. sfnts_pputBYTE(stream, n);
  515. sfnts_pputBYTE(stream, x3);
  516. sfnts_pputBYTE(stream, x2);
  517. sfnts_pputBYTE(stream, x1);
  518. } /* end of sfnts_pputULONG() */
  519. /*
  520. ** This is called whenever it is
  521. ** necessary to end a string in the sfnts array.
  522. **
  523. ** (The array must be broken into strings which are
  524. ** no longer than 64K characters.)
  525. */
  526. void sfnts_end_string(TTStreamWriter& stream)
  527. {
  528. if (in_string)
  529. {
  530. string_len=0; /* fool sfnts_pputBYTE() */
  531. #ifdef DEBUG_TRUETYPE_INLINE
  532. puts("\n% dummy byte:\n");
  533. #endif
  534. sfnts_pputBYTE(stream, 0); /* extra byte for pre-2013 compatibility */
  535. stream.put_char('>');
  536. line_len++;
  537. }
  538. in_string=false;
  539. } /* end of sfnts_end_string() */
  540. /*
  541. ** This is called at the start of each new table.
  542. ** The argement is the length in bytes of the table
  543. ** which will follow. If the new table will not fit
  544. ** in the current string, a new one is started.
  545. */
  546. void sfnts_new_table(TTStreamWriter& stream, ULONG length)
  547. {
  548. if ( (string_len + length) > 65528 )
  549. sfnts_end_string(stream);
  550. } /* end of sfnts_new_table() */
  551. /*
  552. ** We may have to break up the 'glyf' table. That is the reason
  553. ** why we provide this special routine to copy it into the sfnts
  554. ** array.
  555. */
  556. void sfnts_glyf_table(TTStreamWriter& stream, struct TTFONT *font, ULONG oldoffset, ULONG correct_total_length)
  557. {
  558. ULONG off;
  559. ULONG length;
  560. int c;
  561. ULONG total=0; /* running total of bytes written to table */
  562. int x;
  563. bool loca_is_local=false;
  564. debug("sfnts_glyf_table(font,%d)", (int)correct_total_length);
  565. if (font->loca_table == NULL)
  566. {
  567. font->loca_table = GetTable(font,"loca");
  568. loca_is_local = true;
  569. }
  570. /* Seek to proper position in the file. */
  571. fseek( font->file, oldoffset, SEEK_SET );
  572. /* Copy the glyphs one by one */
  573. for (x=0; x < font->numGlyphs; x++)
  574. {
  575. /* Read the glyph offset from the index-to-location table. */
  576. if (font->indexToLocFormat == 0)
  577. {
  578. off = getUSHORT( font->loca_table + (x * 2) );
  579. off *= 2;
  580. length = getUSHORT( font->loca_table + ((x+1) * 2) );
  581. length *= 2;
  582. length -= off;
  583. }
  584. else
  585. {
  586. off = getULONG( font->loca_table + (x * 4) );
  587. length = getULONG( font->loca_table + ((x+1) * 4) );
  588. length -= off;
  589. }
  590. debug("glyph length=%d",(int)length);
  591. /* Start new string if necessary. */
  592. sfnts_new_table( stream, (int)length );
  593. /*
  594. ** Make sure the glyph is padded out to a
  595. ** two byte boundary.
  596. */
  597. if ( length % 2 ) {
  598. throw TTException("TrueType font contains a 'glyf' table without 2 byte padding");
  599. }
  600. /* Copy the bytes of the glyph. */
  601. while ( length-- )
  602. {
  603. if ( (c = fgetc(font->file)) == EOF ) {
  604. throw TTException("TrueType font may be corrupt (reason 6)");
  605. }
  606. sfnts_pputBYTE(stream, c);
  607. total++; /* add to running total */
  608. }
  609. }
  610. if (loca_is_local)
  611. {
  612. free(font->loca_table);
  613. font->loca_table = NULL;
  614. }
  615. /* Pad out to full length from table directory */
  616. while ( total < correct_total_length )
  617. {
  618. sfnts_pputBYTE(stream, 0);
  619. total++;
  620. }
  621. } /* end of sfnts_glyf_table() */
  622. /*
  623. ** Here is the routine which ties it all together.
  624. **
  625. ** Create the array called "sfnts" which
  626. ** holds the actual TrueType data.
  627. */
  628. void ttfont_sfnts(TTStreamWriter& stream, struct TTFONT *font)
  629. {
  630. static const char *table_names[] = /* The names of all tables */
  631. {
  632. /* which it is worth while */
  633. "cvt ", /* to include in a Type 42 */
  634. "fpgm", /* PostScript font. */
  635. "glyf",
  636. "head",
  637. "hhea",
  638. "hmtx",
  639. "loca",
  640. "maxp",
  641. "prep"
  642. } ;
  643. struct /* The location of each of */
  644. {
  645. ULONG oldoffset; /* the above tables. */
  646. ULONG newoffset;
  647. ULONG length;
  648. ULONG checksum;
  649. } tables[9];
  650. BYTE *ptr; /* A pointer into the origional table directory. */
  651. ULONG x,y; /* General use loop countes. */
  652. int c; /* Input character. */
  653. int diff;
  654. ULONG nextoffset;
  655. int count; /* How many `important' tables did we find? */
  656. ptr = font->offset_table + 12;
  657. nextoffset=0;
  658. count=0;
  659. /*
  660. ** Find the tables we want and store there vital
  661. ** statistics in tables[].
  662. */
  663. ULONG num_tables_read = 0; /* Number of tables read from the directory */
  664. for (x = 0; x < 9; x++) {
  665. do {
  666. if (num_tables_read < font->numTables) {
  667. /* There are still tables to read from ptr */
  668. diff = strncmp((char*)ptr, table_names[x], 4);
  669. if (diff > 0) { /* If we are past it. */
  670. tables[x].length = 0;
  671. diff = 0;
  672. } else if (diff < 0) { /* If we haven't hit it yet. */
  673. ptr += 16;
  674. num_tables_read++;
  675. } else if (diff == 0) { /* Here it is! */
  676. tables[x].newoffset = nextoffset;
  677. tables[x].checksum = getULONG( ptr + 4 );
  678. tables[x].oldoffset = getULONG( ptr + 8 );
  679. tables[x].length = getULONG( ptr + 12 );
  680. nextoffset += ( ((tables[x].length + 3) / 4) * 4 );
  681. count++;
  682. ptr += 16;
  683. num_tables_read++;
  684. }
  685. } else {
  686. /* We've read the whole table directory already */
  687. /* Some tables couldn't be found */
  688. tables[x].length = 0;
  689. break; /* Proceed to next tables[x] */
  690. }
  691. } while (diff != 0);
  692. } /* end of for loop which passes over the table directory */
  693. /* Begin the sfnts array. */
  694. sfnts_start(stream);
  695. /* Generate the offset table header */
  696. /* Start by copying the TrueType version number. */
  697. ptr = font->offset_table;
  698. for (x=0; x < 4; x++)
  699. {
  700. sfnts_pputBYTE( stream, *(ptr++) );
  701. }
  702. /* Now, generate those silly numTables numbers. */
  703. sfnts_pputUSHORT(stream, count); /* number of tables */
  704. int search_range = 1;
  705. int entry_sel = 0;
  706. while (search_range <= count) {
  707. search_range <<= 1;
  708. entry_sel++;
  709. }
  710. entry_sel = entry_sel > 0 ? entry_sel - 1 : 0;
  711. search_range = (search_range >> 1) * 16;
  712. int range_shift = count * 16 - search_range;
  713. sfnts_pputUSHORT(stream, search_range); /* searchRange */
  714. sfnts_pputUSHORT(stream, entry_sel); /* entrySelector */
  715. sfnts_pputUSHORT(stream, range_shift); /* rangeShift */
  716. debug("only %d tables selected",count);
  717. /* Now, emmit the table directory. */
  718. for (x=0; x < 9; x++)
  719. {
  720. if ( tables[x].length == 0 ) /* Skip missing tables */
  721. {
  722. continue;
  723. }
  724. /* Name */
  725. sfnts_pputBYTE( stream, table_names[x][0] );
  726. sfnts_pputBYTE( stream, table_names[x][1] );
  727. sfnts_pputBYTE( stream, table_names[x][2] );
  728. sfnts_pputBYTE( stream, table_names[x][3] );
  729. /* Checksum */
  730. sfnts_pputULONG( stream, tables[x].checksum );
  731. /* Offset */
  732. sfnts_pputULONG( stream, tables[x].newoffset + 12 + (count * 16) );
  733. /* Length */
  734. sfnts_pputULONG( stream, tables[x].length );
  735. }
  736. /* Now, send the tables */
  737. for (x=0; x < 9; x++)
  738. {
  739. if ( tables[x].length == 0 ) /* skip tables that aren't there */
  740. {
  741. continue;
  742. }
  743. debug("emmiting table '%s'",table_names[x]);
  744. /* 'glyf' table gets special treatment */
  745. if ( strcmp(table_names[x],"glyf")==0 )
  746. {
  747. sfnts_glyf_table(stream,font,tables[x].oldoffset,tables[x].length);
  748. }
  749. else /* Other tables may not exceed */
  750. {
  751. /* 65535 bytes in length. */
  752. if ( tables[x].length > 65535 )
  753. {
  754. throw TTException("TrueType font has a table which is too long");
  755. }
  756. /* Start new string if necessary. */
  757. sfnts_new_table(stream, tables[x].length);
  758. /* Seek to proper position in the file. */
  759. fseek( font->file, tables[x].oldoffset, SEEK_SET );
  760. /* Copy the bytes of the table. */
  761. for ( y=0; y < tables[x].length; y++ )
  762. {
  763. if ( (c = fgetc(font->file)) == EOF )
  764. {
  765. throw TTException("TrueType font may be corrupt (reason 7)");
  766. }
  767. sfnts_pputBYTE(stream, c);
  768. }
  769. }
  770. /* Padd it out to a four byte boundary. */
  771. y=tables[x].length;
  772. while ( (y % 4) != 0 )
  773. {
  774. sfnts_pputBYTE(stream, 0);
  775. y++;
  776. #ifdef DEBUG_TRUETYPE_INLINE
  777. puts("\n% pad byte:\n");
  778. #endif
  779. }
  780. } /* End of loop for all tables */
  781. /* Close the array. */
  782. sfnts_end_string(stream);
  783. stream.putline("]def");
  784. } /* end of ttfont_sfnts() */
  785. /*--------------------------------------------------------------
  786. ** Create the CharStrings dictionary which will translate
  787. ** PostScript character names to TrueType font character
  788. ** indexes.
  789. **
  790. ** If we are creating a type 3 instead of a type 42 font,
  791. ** this array will instead convert PostScript character names
  792. ** to executable proceedures.
  793. --------------------------------------------------------------*/
  794. const char *Apple_CharStrings[]=
  795. {
  796. ".notdef",".null","nonmarkingreturn","space","exclam","quotedbl","numbersign",
  797. "dollar","percent","ampersand","quotesingle","parenleft","parenright",
  798. "asterisk","plus", "comma","hyphen","period","slash","zero","one","two",
  799. "three","four","five","six","seven","eight","nine","colon","semicolon",
  800. "less","equal","greater","question","at","A","B","C","D","E","F","G","H","I",
  801. "J","K", "L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
  802. "bracketleft","backslash","bracketright","asciicircum","underscore","grave",
  803. "a","b","c","d","e","f","g","h","i","j","k", "l","m","n","o","p","q","r","s",
  804. "t","u","v","w","x","y","z","braceleft","bar","braceright","asciitilde",
  805. "Adieresis","Aring","Ccedilla","Eacute","Ntilde","Odieresis","Udieresis",
  806. "aacute","agrave","acircumflex","adieresis","atilde","aring","ccedilla",
  807. "eacute","egrave","ecircumflex","edieresis","iacute","igrave","icircumflex",
  808. "idieresis","ntilde","oacute","ograve","ocircumflex","odieresis","otilde",
  809. "uacute","ugrave","ucircumflex","udieresis","dagger","degree","cent",
  810. "sterling","section","bullet","paragraph","germandbls","registered",
  811. "copyright","trademark","acute","dieresis","notequal","AE","Oslash",
  812. "infinity","plusminus","lessequal","greaterequal","yen","mu","partialdiff",
  813. "summation","product","pi","integral","ordfeminine","ordmasculine","Omega",
  814. "ae","oslash","questiondown","exclamdown","logicalnot","radical","florin",
  815. "approxequal","Delta","guillemotleft","guillemotright","ellipsis",
  816. "nobreakspace","Agrave","Atilde","Otilde","OE","oe","endash","emdash",
  817. "quotedblleft","quotedblright","quoteleft","quoteright","divide","lozenge",
  818. "ydieresis","Ydieresis","fraction","currency","guilsinglleft","guilsinglright",
  819. "fi","fl","daggerdbl","periodcentered","quotesinglbase","quotedblbase",
  820. "perthousand","Acircumflex","Ecircumflex","Aacute","Edieresis","Egrave",
  821. "Iacute","Icircumflex","Idieresis","Igrave","Oacute","Ocircumflex","apple",
  822. "Ograve","Uacute","Ucircumflex","Ugrave","dotlessi","circumflex","tilde",
  823. "macron","breve","dotaccent","ring","cedilla","hungarumlaut","ogonek","caron",
  824. "Lslash","lslash","Scaron","scaron","Zcaron","zcaron","brokenbar","Eth","eth",
  825. "Yacute","yacute","Thorn","thorn","minus","multiply","onesuperior",
  826. "twosuperior","threesuperior","onehalf","onequarter","threequarters","franc",
  827. "Gbreve","gbreve","Idot","Scedilla","scedilla","Cacute","cacute","Ccaron",
  828. "ccaron","dmacron","markingspace","capslock","shift","propeller","enter",
  829. "markingtabrtol","markingtabltor","control","markingdeleteltor",
  830. "markingdeletertol","option","escape","parbreakltor","parbreakrtol",
  831. "newpage","checkmark","linebreakltor","linebreakrtol","markingnobreakspace",
  832. "diamond","appleoutline"
  833. };
  834. /*
  835. ** This routine is called by the one below.
  836. ** It is also called from pprdrv_tt2.c
  837. */
  838. const char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex)
  839. {
  840. int GlyphIndex;
  841. static char temp[80];
  842. char *ptr;
  843. ULONG len;
  844. Fixed post_format;
  845. /* The 'post' table format number. */
  846. post_format = getFixed( font->post_table );
  847. if ( post_format.whole != 2 || post_format.fraction != 0 )
  848. {
  849. /* We don't have a glyph name table, so generate a name.
  850. This generated name must match exactly the name that is
  851. generated by FT2Font in get_glyph_name */
  852. PyOS_snprintf(temp, 80, "uni%08x", charindex);
  853. return temp;
  854. }
  855. GlyphIndex = (int)getUSHORT( font->post_table + 34 + (charindex * 2) );
  856. if ( GlyphIndex <= 257 ) /* If a standard Apple name, */
  857. {
  858. return Apple_CharStrings[GlyphIndex];
  859. }
  860. else /* Otherwise, use one */
  861. {
  862. /* of the pascal strings. */
  863. GlyphIndex -= 258;
  864. /* Set pointer to start of Pascal strings. */
  865. ptr = (char*)(font->post_table + 34 + (font->numGlyphs * 2));
  866. len = (ULONG)*(ptr++); /* Step thru the strings */
  867. while (GlyphIndex--) /* until we get to the one */
  868. {
  869. /* that we want. */
  870. ptr += len;
  871. len = (ULONG)*(ptr++);
  872. }
  873. if ( len >= sizeof(temp) )
  874. {
  875. throw TTException("TrueType font file contains a very long PostScript name");
  876. }
  877. strncpy(temp,ptr,len); /* Copy the pascal string into */
  878. temp[len]='\0'; /* a buffer and make it ASCIIz. */
  879. return temp;
  880. }
  881. } /* end of ttfont_CharStrings_getname() */
  882. /*
  883. ** This is the central routine of this section.
  884. */
  885. void ttfont_CharStrings(TTStreamWriter& stream, struct TTFONT *font, std::vector<int>& glyph_ids)
  886. {
  887. Fixed post_format;
  888. /* The 'post' table format number. */
  889. post_format = getFixed( font->post_table );
  890. /* Emmit the start of the PostScript code to define the dictionary. */
  891. stream.printf("/CharStrings %d dict dup begin\n", glyph_ids.size()+1);
  892. /* Section 5.8.2 table 5.7 of the PS Language Ref says a CharStrings dictionary must contain an entry for .notdef */
  893. stream.printf("/.notdef 0 def\n");
  894. /* Emmit one key-value pair for each glyph. */
  895. for (std::vector<int>::const_iterator i = glyph_ids.begin();
  896. i != glyph_ids.end(); ++i)
  897. {
  898. if ((font->target_type == PS_TYPE_42 ||
  899. font->target_type == PS_TYPE_42_3_HYBRID)
  900. && *i < 256) /* type 42 */
  901. {
  902. stream.printf("/%s %d def\n",ttfont_CharStrings_getname(font, *i), *i);
  903. }
  904. else /* type 3 */
  905. {
  906. stream.printf("/%s{",ttfont_CharStrings_getname(font, *i));
  907. tt_type3_charproc(stream, font, *i);
  908. stream.putline("}_d"); /* "} bind def" */
  909. }
  910. }
  911. stream.putline("end readonly def");
  912. } /* end of ttfont_CharStrings() */
  913. /*----------------------------------------------------------------
  914. ** Emmit the code to finish up the dictionary and turn
  915. ** it into a font.
  916. ----------------------------------------------------------------*/
  917. void ttfont_trailer(TTStreamWriter& stream, struct TTFONT *font)
  918. {
  919. /* If we are generating a type 3 font, we need to provide */
  920. /* a BuildGlyph and BuildChar proceedures. */
  921. if (font->target_type == PS_TYPE_3 ||
  922. font->target_type == PS_TYPE_42_3_HYBRID)
  923. {
  924. stream.put_char('\n');
  925. stream.putline("/BuildGlyph");
  926. stream.putline(" {exch begin"); /* start font dictionary */
  927. stream.putline(" CharStrings exch");
  928. stream.putline(" 2 copy known not{pop /.notdef}if");
  929. stream.putline(" true 3 1 roll get exec");
  930. stream.putline(" end}_d");
  931. stream.put_char('\n');
  932. /* This proceedure is for compatibility with */
  933. /* level 1 interpreters. */
  934. stream.putline("/BuildChar {");
  935. stream.putline(" 1 index /Encoding get exch get");
  936. stream.putline(" 1 index /BuildGlyph get exec");
  937. stream.putline("}_d");
  938. stream.put_char('\n');
  939. }
  940. /* If we are generating a type 42 font, we need to check to see */
  941. /* if this PostScript interpreter understands type 42 fonts. If */
  942. /* it doesn't, we will hope that the Apple TrueType rasterizer */
  943. /* has been loaded and we will adjust the font accordingly. */
  944. /* I found out how to do this by examining a TrueType font */
  945. /* generated by a Macintosh. That is where the TrueType interpreter */
  946. /* setup instructions and part of BuildGlyph came from. */
  947. if (font->target_type == PS_TYPE_42 ||
  948. font->target_type == PS_TYPE_42_3_HYBRID)
  949. {
  950. stream.put_char('\n');
  951. /* If we have no "resourcestatus" command, or FontType 42 */
  952. /* is unknown, leave "true" on the stack. */
  953. stream.putline("systemdict/resourcestatus known");
  954. stream.putline(" {42 /FontType resourcestatus");
  955. stream.putline(" {pop pop false}{true}ifelse}");
  956. stream.putline(" {true}ifelse");
  957. /* If true, execute code to produce an error message if */
  958. /* we can't find Apple's TrueDict in VM. */
  959. stream.putline("{/TrueDict where{pop}{(%%[ Error: no TrueType rasterizer ]%%)= flush}ifelse");
  960. /* Since we are expected to use Apple's TrueDict TrueType */
  961. /* reasterizer, change the font type to 3. */
  962. stream.putline("/FontType 3 def");
  963. /* Define a string to hold the state of the Apple */
  964. /* TrueType interpreter. */
  965. stream.putline(" /TrueState 271 string def");
  966. /* It looks like we get information about the resolution */
  967. /* of the printer and store it in the TrueState string. */
  968. stream.putline(" TrueDict begin sfnts save");
  969. stream.putline(" 72 0 matrix defaultmatrix dtransform dup");
  970. stream.putline(" mul exch dup mul add sqrt cvi 0 72 matrix");
  971. stream.putline(" defaultmatrix dtransform dup mul exch dup");
  972. stream.putline(" mul add sqrt cvi 3 -1 roll restore");
  973. stream.putline(" TrueState initer end");
  974. /* This BuildGlyph procedure will look the name up in the */
  975. /* CharStrings array, and then check to see if what it gets */
  976. /* is a procedure. If it is, it executes it, otherwise, it */
  977. /* lets the TrueType rasterizer loose on it. */
  978. /* When this proceedure is executed the stack contains */
  979. /* the font dictionary and the character name. We */
  980. /* exchange arguments and move the dictionary to the */
  981. /* dictionary stack. */
  982. stream.putline(" /BuildGlyph{exch begin");
  983. /* stack: charname */
  984. /* Put two copies of CharStrings on the stack and consume */
  985. /* one testing to see if the charname is defined in it, */
  986. /* leave the answer on the stack. */
  987. stream.putline(" CharStrings dup 2 index known");
  988. /* stack: charname CharStrings bool */
  989. /* Exchange the CharStrings dictionary and the charname, */
  990. /* but if the answer was false, replace the character name */
  991. /* with ".notdef". */
  992. stream.putline(" {exch}{exch pop /.notdef}ifelse");
  993. /* stack: CharStrings charname */
  994. /* Get the value from the CharStrings dictionary and see */
  995. /* if it is executable. */
  996. stream.putline(" get dup xcheck");
  997. /* stack: CharStrings_entry */
  998. /* If is a proceedure. Execute according to RBIIp 277-278. */
  999. stream.putline(" {currentdict systemdict begin begin exec end end}");
  1000. /* Is a TrueType character index, let the rasterizer at it. */
  1001. stream.putline(" {TrueDict begin /bander load cvlit exch TrueState render end}");
  1002. stream.putline(" ifelse");
  1003. /* Pop the font's dictionary off the stack. */
  1004. stream.putline(" end}bind def");
  1005. /* This is the level 1 compatibility BuildChar procedure. */
  1006. /* See RBIIp 281. */
  1007. stream.putline(" /BuildChar{");
  1008. stream.putline(" 1 index /Encoding get exch get");
  1009. stream.putline(" 1 index /BuildGlyph get exec");
  1010. stream.putline(" }bind def");
  1011. /* Here we close the condition which is true */
  1012. /* if the printer has no built-in TrueType */
  1013. /* rasterizer. */
  1014. stream.putline("}if");
  1015. stream.put_char('\n');
  1016. } /* end of if Type 42 not understood. */
  1017. stream.putline("FontName currentdict end definefont pop");
  1018. /* stream.putline("%%EOF"); */
  1019. } /* end of ttfont_trailer() */
  1020. /*------------------------------------------------------------------
  1021. ** This is the externally callable routine which inserts the font.
  1022. ------------------------------------------------------------------*/
  1023. void read_font(const char *filename, font_type_enum target_type, std::vector<int>& glyph_ids, TTFONT& font)
  1024. {
  1025. BYTE *ptr;
  1026. /* Decide what type of PostScript font we will be generating. */
  1027. font.target_type = target_type;
  1028. if (font.target_type == PS_TYPE_42)
  1029. {
  1030. bool has_low = false;
  1031. bool has_high = false;
  1032. for (std::vector<int>::const_iterator i = glyph_ids.begin();
  1033. i != glyph_ids.end(); ++i)
  1034. {
  1035. if (*i > 255)
  1036. {
  1037. has_high = true;
  1038. if (has_low) break;
  1039. }
  1040. else
  1041. {
  1042. has_low = true;
  1043. if (has_high) break;
  1044. }
  1045. }
  1046. if (has_high && has_low)
  1047. {
  1048. font.target_type = PS_TYPE_42_3_HYBRID;
  1049. }
  1050. else if (has_high && !has_low)
  1051. {
  1052. font.target_type = PS_TYPE_3;
  1053. }
  1054. }
  1055. /* Save the file name for error messages. */
  1056. font.filename=filename;
  1057. /* Open the font file */
  1058. if ( (font.file = fopen(filename,"rb")) == (FILE*)NULL )
  1059. {
  1060. throw TTException("Failed to open TrueType font");
  1061. }
  1062. /* Allocate space for the unvarying part of the offset table. */
  1063. assert(font.offset_table == NULL);
  1064. font.offset_table = (BYTE*)calloc( 12, sizeof(BYTE) );
  1065. /* Read the first part of the offset table. */
  1066. if ( fread( font.offset_table, sizeof(BYTE), 12, font.file ) != 12 )
  1067. {
  1068. throw TTException("TrueType font may be corrupt (reason 1)");
  1069. }
  1070. /* Determine how many directory entries there are. */
  1071. font.numTables = getUSHORT( font.offset_table + 4 );
  1072. debug("numTables=%d",(int)font.numTables);
  1073. /* Expand the memory block to hold the whole thing. */
  1074. font.offset_table = (BYTE*)realloc( font.offset_table, sizeof(BYTE) * (12 + font.numTables * 16) );
  1075. /* Read the rest of the table directory. */
  1076. if ( fread( font.offset_table + 12, sizeof(BYTE), (font.numTables*16), font.file ) != (font.numTables*16) )
  1077. {
  1078. throw TTException("TrueType font may be corrupt (reason 2)");
  1079. }
  1080. /* Extract information from the "Offset" table. */
  1081. font.TTVersion = getFixed( font.offset_table );
  1082. /* Load the "head" table and extract information from it. */
  1083. ptr = GetTable(&font, "head");
  1084. try
  1085. {
  1086. font.MfrRevision = getFixed( ptr + 4 ); /* font revision number */
  1087. font.unitsPerEm = getUSHORT( ptr + 18 );
  1088. font.HUPM = font.unitsPerEm / 2;
  1089. debug("unitsPerEm=%d",(int)font.unitsPerEm);
  1090. font.llx = topost2( getFWord( ptr + 36 ) ); /* bounding box info */
  1091. font.lly = topost2( getFWord( ptr + 38 ) );
  1092. font.urx = topost2( getFWord( ptr + 40 ) );
  1093. font.ury = topost2( getFWord( ptr + 42 ) );
  1094. font.indexToLocFormat = getSHORT( ptr + 50 ); /* size of 'loca' data */
  1095. if (font.indexToLocFormat != 0 && font.indexToLocFormat != 1)
  1096. {
  1097. throw TTException("TrueType font is unusable because indexToLocFormat != 0");
  1098. }
  1099. if ( getSHORT(ptr+52) != 0 )
  1100. {
  1101. throw TTException("TrueType font is unusable because glyphDataFormat != 0");
  1102. }
  1103. }
  1104. catch (TTException& )
  1105. {
  1106. free(ptr);
  1107. throw;
  1108. }
  1109. free(ptr);
  1110. /* Load information from the "name" table. */
  1111. Read_name(&font);
  1112. /* We need to have the PostScript table around. */
  1113. assert(font.post_table == NULL);
  1114. font.post_table = GetTable(&font, "post");
  1115. font.numGlyphs = getUSHORT( font.post_table + 32 );
  1116. /* If we are generating a Type 3 font, we will need to */
  1117. /* have the 'loca' and 'glyf' tables arround while */
  1118. /* we are generating the CharStrings. */
  1119. if (font.target_type == PS_TYPE_3 || font.target_type == PS_TYPE_42_3_HYBRID)
  1120. {
  1121. BYTE *ptr; /* We need only one value */
  1122. ptr = GetTable(&font, "hhea");
  1123. font.numberOfHMetrics = getUSHORT(ptr + 34);
  1124. free(ptr);
  1125. assert(font.loca_table == NULL);
  1126. font.loca_table = GetTable(&font,"loca");
  1127. assert(font.glyf_table == NULL);
  1128. font.glyf_table = GetTable(&font,"glyf");
  1129. assert(font.hmtx_table == NULL);
  1130. font.hmtx_table = GetTable(&font,"hmtx");
  1131. }
  1132. if (glyph_ids.size() == 0)
  1133. {
  1134. glyph_ids.clear();
  1135. glyph_ids.reserve(font.numGlyphs);
  1136. for (int x = 0; x < font.numGlyphs; ++x)
  1137. {
  1138. glyph_ids.push_back(x);
  1139. }
  1140. }
  1141. else if (font.target_type == PS_TYPE_3 ||
  1142. font.target_type == PS_TYPE_42_3_HYBRID)
  1143. {
  1144. ttfont_add_glyph_dependencies(&font, glyph_ids);
  1145. }
  1146. } /* end of insert_ttfont() */
  1147. void insert_ttfont(const char *filename, TTStreamWriter& stream,
  1148. font_type_enum target_type, std::vector<int>& glyph_ids)
  1149. {
  1150. struct TTFONT font;
  1151. read_font(filename, target_type, glyph_ids, font);
  1152. /* Write the header for the PostScript font. */
  1153. ttfont_header(stream, &font);
  1154. /* Define the encoding. */
  1155. ttfont_encoding(stream, &font, glyph_ids, target_type);
  1156. /* Insert FontInfo dictionary. */
  1157. ttfont_FontInfo(stream, &font);
  1158. /* If we are generating a type 42 font, */
  1159. /* emmit the sfnts array. */
  1160. if (font.target_type == PS_TYPE_42 ||
  1161. font.target_type == PS_TYPE_42_3_HYBRID)
  1162. {
  1163. ttfont_sfnts(stream, &font);
  1164. }
  1165. /* Emmit the CharStrings array. */
  1166. ttfont_CharStrings(stream, &font, glyph_ids);
  1167. /* Send the font trailer. */
  1168. ttfont_trailer(stream, &font);
  1169. } /* end of insert_ttfont() */
  1170. TTFONT::TTFONT() :
  1171. file(NULL),
  1172. PostName(NULL),
  1173. FullName(NULL),
  1174. FamilyName(NULL),
  1175. Style(NULL),
  1176. Copyright(NULL),
  1177. Version(NULL),
  1178. Trademark(NULL),
  1179. offset_table(NULL),
  1180. post_table(NULL),
  1181. loca_table(NULL),
  1182. glyf_table(NULL),
  1183. hmtx_table(NULL)
  1184. {
  1185. }
  1186. TTFONT::~TTFONT()
  1187. {
  1188. if (file)
  1189. {
  1190. fclose(file);
  1191. }
  1192. free(PostName);
  1193. free(FullName);
  1194. free(FamilyName);
  1195. free(Style);
  1196. free(Copyright);
  1197. free(Version);
  1198. free(Trademark);
  1199. free(offset_table);
  1200. free(post_table);
  1201. free(loca_table);
  1202. free(glyf_table);
  1203. free(hmtx_table);
  1204. }
  1205. /* end of file */