pprdrv_tt.cpp 47 KB

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