pprdrv_tt2.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  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_tt2.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. ** The functions in this file do most of the work to convert a
  23. ** TrueType font to a type 3 PostScript font.
  24. **
  25. ** Most of the material in this file is derived from a program called
  26. ** "ttf2ps" which L. S. Ng posted to the usenet news group
  27. ** "comp.sources.postscript". The author did not provide a copyright
  28. ** notice or indicate any restrictions on use.
  29. **
  30. ** Last revised 11 July 1995.
  31. */
  32. #include <cstdlib>
  33. #include <cmath>
  34. #include <cstring>
  35. #include <memory>
  36. #include "pprdrv.h"
  37. #include "truetype.h"
  38. #include <algorithm>
  39. #include <stack>
  40. #include <list>
  41. class GlyphToType3
  42. {
  43. private:
  44. GlyphToType3& operator=(const GlyphToType3& other);
  45. GlyphToType3(const GlyphToType3& other);
  46. /* The PostScript bounding box. */
  47. int llx,lly,urx,ury;
  48. int advance_width;
  49. /* Variables to hold the character data. */
  50. int *epts_ctr; /* array of contour endpoints */
  51. int num_pts, num_ctr; /* number of points, number of coutours */
  52. FWord *xcoor, *ycoor; /* arrays of x and y coordinates */
  53. BYTE *tt_flags; /* array of TrueType flags */
  54. int stack_depth; /* A book-keeping variable for keeping track of the depth of the PS stack */
  55. void load_char(TTFONT* font, BYTE *glyph);
  56. void stack(TTStreamWriter& stream, int new_elem);
  57. void stack_end(TTStreamWriter& stream);
  58. void PSConvert(TTStreamWriter& stream);
  59. void PSCurveto(TTStreamWriter& stream,
  60. FWord x0, FWord y0,
  61. FWord x1, FWord y1,
  62. FWord x2, FWord y2);
  63. void PSMoveto(TTStreamWriter& stream, int x, int y);
  64. void PSLineto(TTStreamWriter& stream, int x, int y);
  65. void do_composite(TTStreamWriter& stream, struct TTFONT *font, BYTE *glyph);
  66. public:
  67. GlyphToType3(TTStreamWriter& stream, struct TTFONT *font, int charindex, bool embedded = false);
  68. ~GlyphToType3();
  69. };
  70. // Each point on a TrueType contour is either on the path or off it (a
  71. // control point); here's a simple representation for building such
  72. // contours. Added by Jouni Seppänen 2012-05-27.
  73. enum Flag { ON_PATH, OFF_PATH };
  74. struct FlaggedPoint
  75. {
  76. enum Flag flag;
  77. FWord x;
  78. FWord y;
  79. FlaggedPoint(Flag flag_, FWord x_, FWord y_): flag(flag_), x(x_), y(y_) {};
  80. };
  81. /*
  82. ** This routine is used to break the character
  83. ** procedure up into a number of smaller
  84. ** procedures. This is necessary so as not to
  85. ** overflow the stack on certain level 1 interpreters.
  86. **
  87. ** Prepare to push another item onto the stack,
  88. ** starting a new proceedure if necessary.
  89. **
  90. ** Not all the stack depth calculations in this routine
  91. ** are perfectly accurate, but they do the job.
  92. */
  93. void GlyphToType3::stack(TTStreamWriter& stream, int new_elem)
  94. {
  95. if ( num_pts > 25 ) /* Only do something of we will have a log of points. */
  96. {
  97. if (stack_depth == 0)
  98. {
  99. stream.put_char('{');
  100. stack_depth=1;
  101. }
  102. stack_depth += new_elem; /* Account for what we propose to add */
  103. if (stack_depth > 100)
  104. {
  105. stream.puts("}_e{");
  106. stack_depth = 3 + new_elem; /* A rough estimate */
  107. }
  108. }
  109. } /* end of stack() */
  110. void GlyphToType3::stack_end(TTStreamWriter& stream) /* called at end */
  111. {
  112. if ( stack_depth )
  113. {
  114. stream.puts("}_e");
  115. stack_depth=0;
  116. }
  117. } /* end of stack_end() */
  118. /*
  119. ** We call this routine to emmit the PostScript code
  120. ** for the character we have loaded with load_char().
  121. */
  122. void GlyphToType3::PSConvert(TTStreamWriter& stream)
  123. {
  124. int j, k;
  125. /* Step thru the contours.
  126. * j = index to xcoor, ycoor, tt_flags (point data)
  127. * k = index to epts_ctr (which points belong to the same contour) */
  128. for(j = k = 0; k < num_ctr; k++)
  129. {
  130. // A TrueType contour consists of on-path and off-path points.
  131. // Two consecutive on-path points are to be joined with a
  132. // line; off-path points between on-path points indicate a
  133. // quadratic spline, where the off-path point is the control
  134. // point. Two consecutive off-path points have an implicit
  135. // on-path point midway between them.
  136. std::list<FlaggedPoint> points;
  137. // Represent flags and x/y coordinates as a C++ list
  138. for (; j <= epts_ctr[k]; j++)
  139. {
  140. if (!(tt_flags[j] & 1)) {
  141. points.push_back(FlaggedPoint(OFF_PATH, xcoor[j], ycoor[j]));
  142. } else {
  143. points.push_back(FlaggedPoint(ON_PATH, xcoor[j], ycoor[j]));
  144. }
  145. }
  146. if (points.size() == 0) {
  147. // Don't try to access the last element of an empty list
  148. continue;
  149. }
  150. // For any two consecutive off-path points, insert the implied
  151. // on-path point.
  152. FlaggedPoint prev = points.back();
  153. for (std::list<FlaggedPoint>::iterator it = points.begin();
  154. it != points.end();
  155. it++)
  156. {
  157. if (prev.flag == OFF_PATH && it->flag == OFF_PATH)
  158. {
  159. points.insert(it,
  160. FlaggedPoint(ON_PATH,
  161. (prev.x + it->x) / 2,
  162. (prev.y + it->y) / 2));
  163. }
  164. prev = *it;
  165. }
  166. // Handle the wrap-around: insert a point either at the beginning
  167. // or at the end that has the same coordinates as the opposite point.
  168. // This also ensures that the initial point is ON_PATH.
  169. if (points.front().flag == OFF_PATH)
  170. {
  171. assert(points.back().flag == ON_PATH);
  172. points.insert(points.begin(), points.back());
  173. }
  174. else
  175. {
  176. assert(points.front().flag == ON_PATH);
  177. points.push_back(points.front());
  178. }
  179. // The first point
  180. stack(stream, 3);
  181. PSMoveto(stream, points.front().x, points.front().y);
  182. // Step through the remaining points
  183. std::list<FlaggedPoint>::const_iterator it = points.begin();
  184. for (it++; it != points.end(); /* incremented inside */)
  185. {
  186. const FlaggedPoint& point = *it;
  187. if (point.flag == ON_PATH)
  188. {
  189. stack(stream, 3);
  190. PSLineto(stream, point.x, point.y);
  191. it++;
  192. } else {
  193. std::list<FlaggedPoint>::const_iterator prev = it, next = it;
  194. prev--;
  195. next++;
  196. assert(prev->flag == ON_PATH);
  197. assert(next->flag == ON_PATH);
  198. stack(stream, 7);
  199. PSCurveto(stream,
  200. prev->x, prev->y,
  201. point.x, point.y,
  202. next->x, next->y);
  203. it++;
  204. it++;
  205. }
  206. }
  207. }
  208. /* Now, we can fill the whole thing. */
  209. stack(stream, 1);
  210. stream.puts("_cl");
  211. } /* end of PSConvert() */
  212. void GlyphToType3::PSMoveto(TTStreamWriter& stream, int x, int y)
  213. {
  214. stream.printf("%d %d _m\n", x, y);
  215. }
  216. void GlyphToType3::PSLineto(TTStreamWriter& stream, int x, int y)
  217. {
  218. stream.printf("%d %d _l\n", x, y);
  219. }
  220. /*
  221. ** Emit a PostScript "curveto" command, assuming the current point
  222. ** is (x0, y0), the control point of a quadratic spline is (x1, y1),
  223. ** and the endpoint is (x2, y2). Note that this requires a conversion,
  224. ** since PostScript splines are cubic.
  225. */
  226. void GlyphToType3::PSCurveto(TTStreamWriter& stream,
  227. FWord x0, FWord y0,
  228. FWord x1, FWord y1,
  229. FWord x2, FWord y2)
  230. {
  231. double sx[3], sy[3], cx[3], cy[3];
  232. sx[0] = x0;
  233. sy[0] = y0;
  234. sx[1] = x1;
  235. sy[1] = y1;
  236. sx[2] = x2;
  237. sy[2] = y2;
  238. cx[0] = (2*sx[1]+sx[0])/3;
  239. cy[0] = (2*sy[1]+sy[0])/3;
  240. cx[1] = (sx[2]+2*sx[1])/3;
  241. cy[1] = (sy[2]+2*sy[1])/3;
  242. cx[2] = sx[2];
  243. cy[2] = sy[2];
  244. stream.printf("%d %d %d %d %d %d _c\n",
  245. (int)cx[0], (int)cy[0], (int)cx[1], (int)cy[1],
  246. (int)cx[2], (int)cy[2]);
  247. }
  248. /*
  249. ** Deallocate the structures which stored
  250. ** the data for the last simple glyph.
  251. */
  252. GlyphToType3::~GlyphToType3()
  253. {
  254. free(tt_flags); /* The flags array */
  255. free(xcoor); /* The X coordinates */
  256. free(ycoor); /* The Y coordinates */
  257. free(epts_ctr); /* The array of contour endpoints */
  258. }
  259. /*
  260. ** Load the simple glyph data pointed to by glyph.
  261. ** The pointer "glyph" should point 10 bytes into
  262. ** the glyph data.
  263. */
  264. void GlyphToType3::load_char(TTFONT* font, BYTE *glyph)
  265. {
  266. int x;
  267. BYTE c, ct;
  268. /* Read the contour endpoints list. */
  269. epts_ctr = (int *)calloc(num_ctr,sizeof(int));
  270. for (x = 0; x < num_ctr; x++)
  271. {
  272. epts_ctr[x] = getUSHORT(glyph);
  273. glyph += 2;
  274. }
  275. /* From the endpoint of the last contour, we can */
  276. /* determine the number of points. */
  277. num_pts = epts_ctr[num_ctr-1]+1;
  278. #ifdef DEBUG_TRUETYPE
  279. debug("num_pts=%d",num_pts);
  280. stream.printf("%% num_pts=%d\n",num_pts);
  281. #endif
  282. /* Skip the instructions. */
  283. x = getUSHORT(glyph);
  284. glyph += 2;
  285. glyph += x;
  286. /* Allocate space to hold the data. */
  287. tt_flags = (BYTE *)calloc(num_pts,sizeof(BYTE));
  288. xcoor = (FWord *)calloc(num_pts,sizeof(FWord));
  289. ycoor = (FWord *)calloc(num_pts,sizeof(FWord));
  290. /* Read the flags array, uncompressing it as we go. */
  291. /* There is danger of overflow here. */
  292. for (x = 0; x < num_pts; )
  293. {
  294. tt_flags[x++] = c = *(glyph++);
  295. if (c&8) /* If next byte is repeat count, */
  296. {
  297. ct = *(glyph++);
  298. if ( (x + ct) > num_pts )
  299. {
  300. throw TTException("Error in TT flags");
  301. }
  302. while (ct--)
  303. {
  304. tt_flags[x++] = c;
  305. }
  306. }
  307. }
  308. /* Read the x coordinates */
  309. for (x = 0; x < num_pts; x++)
  310. {
  311. if (tt_flags[x] & 2) /* one byte value with */
  312. {
  313. /* external sign */
  314. c = *(glyph++);
  315. xcoor[x] = (tt_flags[x] & 0x10) ? c : (-1 * (int)c);
  316. }
  317. else if (tt_flags[x] & 0x10) /* repeat last */
  318. {
  319. xcoor[x] = 0;
  320. }
  321. else /* two byte signed value */
  322. {
  323. xcoor[x] = getFWord(glyph);
  324. glyph+=2;
  325. }
  326. }
  327. /* Read the y coordinates */
  328. for (x = 0; x < num_pts; x++)
  329. {
  330. if (tt_flags[x] & 4) /* one byte value with */
  331. {
  332. /* external sign */
  333. c = *(glyph++);
  334. ycoor[x] = (tt_flags[x] & 0x20) ? c : (-1 * (int)c);
  335. }
  336. else if (tt_flags[x] & 0x20) /* repeat last value */
  337. {
  338. ycoor[x] = 0;
  339. }
  340. else /* two byte signed value */
  341. {
  342. ycoor[x] = getUSHORT(glyph);
  343. glyph+=2;
  344. }
  345. }
  346. /* Convert delta values to absolute values. */
  347. for (x = 1; x < num_pts; x++)
  348. {
  349. xcoor[x] += xcoor[x-1];
  350. ycoor[x] += ycoor[x-1];
  351. }
  352. for (x=0; x < num_pts; x++)
  353. {
  354. xcoor[x] = topost(xcoor[x]);
  355. ycoor[x] = topost(ycoor[x]);
  356. }
  357. } /* end of load_char() */
  358. /*
  359. ** Emmit PostScript code for a composite character.
  360. */
  361. void GlyphToType3::do_composite(TTStreamWriter& stream, struct TTFONT *font, BYTE *glyph)
  362. {
  363. USHORT flags;
  364. USHORT glyphIndex;
  365. int arg1;
  366. int arg2;
  367. /* Once around this loop for each component. */
  368. do
  369. {
  370. flags = getUSHORT(glyph); /* read the flags word */
  371. glyph += 2;
  372. glyphIndex = getUSHORT(glyph); /* read the glyphindex word */
  373. glyph += 2;
  374. if (flags & ARG_1_AND_2_ARE_WORDS)
  375. {
  376. /* The tt spec. seems to say these are signed. */
  377. arg1 = getSHORT(glyph);
  378. glyph += 2;
  379. arg2 = getSHORT(glyph);
  380. glyph += 2;
  381. }
  382. else /* The tt spec. does not clearly indicate */
  383. {
  384. /* whether these values are signed or not. */
  385. arg1 = *(signed char *)(glyph++);
  386. arg2 = *(signed char *)(glyph++);
  387. }
  388. if (flags & WE_HAVE_A_SCALE)
  389. {
  390. glyph += 2;
  391. }
  392. else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
  393. {
  394. glyph += 4;
  395. }
  396. else if (flags & WE_HAVE_A_TWO_BY_TWO)
  397. {
  398. glyph += 8;
  399. }
  400. else
  401. {
  402. }
  403. /* Debugging */
  404. #ifdef DEBUG_TRUETYPE
  405. stream.printf("%% flags=%d, arg1=%d, arg2=%d\n",
  406. (int)flags,arg1,arg2);
  407. #endif
  408. /* If we have an (X,Y) shift and it is non-zero, */
  409. /* translate the coordinate system. */
  410. if ( flags & ARGS_ARE_XY_VALUES )
  411. {
  412. if ( arg1 != 0 || arg2 != 0 )
  413. stream.printf("gsave %d %d translate\n", topost(arg1), topost(arg2) );
  414. }
  415. else
  416. {
  417. stream.printf("%% unimplemented shift, arg1=%d, arg2=%d\n",arg1,arg2);
  418. }
  419. /* Invoke the CharStrings procedure to print the component. */
  420. stream.printf("false CharStrings /%s get exec\n",
  421. ttfont_CharStrings_getname(font, glyphIndex));
  422. /* If we translated the coordinate system, */
  423. /* put it back the way it was. */
  424. if ( flags & ARGS_ARE_XY_VALUES && (arg1 != 0 || arg2 != 0) )
  425. {
  426. stream.puts("grestore ");
  427. }
  428. }
  429. while (flags & MORE_COMPONENTS);
  430. } /* end of do_composite() */
  431. /*
  432. ** Return a pointer to a specific glyph's data.
  433. */
  434. BYTE *find_glyph_data(struct TTFONT *font, int charindex)
  435. {
  436. ULONG off;
  437. ULONG length;
  438. /* Read the glyph offset from the index to location table. */
  439. if (font->indexToLocFormat == 0)
  440. {
  441. off = getUSHORT( font->loca_table + (charindex * 2) );
  442. off *= 2;
  443. length = getUSHORT( font->loca_table + ((charindex+1) * 2) );
  444. length *= 2;
  445. length -= off;
  446. }
  447. else
  448. {
  449. off = getULONG( font->loca_table + (charindex * 4) );
  450. length = getULONG( font->loca_table + ((charindex+1) * 4) );
  451. length -= off;
  452. }
  453. if (length > 0)
  454. {
  455. return font->glyf_table + off;
  456. }
  457. else
  458. {
  459. return (BYTE*)NULL;
  460. }
  461. } /* end of find_glyph_data() */
  462. GlyphToType3::GlyphToType3(TTStreamWriter& stream, struct TTFONT *font, int charindex, bool embedded /* = false */)
  463. {
  464. BYTE *glyph;
  465. tt_flags = NULL;
  466. xcoor = NULL;
  467. ycoor = NULL;
  468. epts_ctr = NULL;
  469. stack_depth = 0;
  470. /* Get a pointer to the data. */
  471. glyph = find_glyph_data( font, charindex );
  472. /* If the character is blank, it has no bounding box, */
  473. /* otherwise read the bounding box. */
  474. if ( glyph == (BYTE*)NULL )
  475. {
  476. llx=lly=urx=ury=0; /* A blank char has an all zero BoundingBox */
  477. num_ctr=0; /* Set this for later if()s */
  478. }
  479. else
  480. {
  481. /* Read the number of contours. */
  482. num_ctr = getSHORT(glyph);
  483. /* Read PostScript bounding box. */
  484. llx = getFWord(glyph + 2);
  485. lly = getFWord(glyph + 4);
  486. urx = getFWord(glyph + 6);
  487. ury = getFWord(glyph + 8);
  488. /* Advance the pointer. */
  489. glyph += 10;
  490. }
  491. /* If it is a simple character, load its data. */
  492. if (num_ctr > 0)
  493. {
  494. load_char(font, glyph);
  495. }
  496. else
  497. {
  498. num_pts=0;
  499. }
  500. /* Consult the horizontal metrics table to determine */
  501. /* the character width. */
  502. if ( charindex < font->numberOfHMetrics )
  503. {
  504. advance_width = getuFWord( font->hmtx_table + (charindex * 4) );
  505. }
  506. else
  507. {
  508. advance_width = getuFWord( font->hmtx_table + ((font->numberOfHMetrics-1) * 4) );
  509. }
  510. /* Execute setcachedevice in order to inform the font machinery */
  511. /* of the character bounding box and advance width. */
  512. stack(stream, 7);
  513. if (font->target_type == PS_TYPE_42_3_HYBRID)
  514. {
  515. stream.printf("pop gsave .001 .001 scale %d 0 %d %d %d %d setcachedevice\n",
  516. topost(advance_width),
  517. topost(llx), topost(lly), topost(urx), topost(ury) );
  518. }
  519. else
  520. {
  521. stream.printf("%d 0 %d %d %d %d _sc\n",
  522. topost(advance_width),
  523. topost(llx), topost(lly), topost(urx), topost(ury) );
  524. }
  525. /* If it is a simple glyph, convert it, */
  526. /* otherwise, close the stack business. */
  527. if ( num_ctr > 0 ) /* simple */
  528. {
  529. PSConvert(stream);
  530. }
  531. else if ( num_ctr < 0 ) /* composite */
  532. {
  533. do_composite(stream, font, glyph);
  534. }
  535. if (font->target_type == PS_TYPE_42_3_HYBRID)
  536. {
  537. stream.printf("\ngrestore\n");
  538. }
  539. stack_end(stream);
  540. }
  541. /*
  542. ** This is the routine which is called from pprdrv_tt.c.
  543. */
  544. void tt_type3_charproc(TTStreamWriter& stream, struct TTFONT *font, int charindex)
  545. {
  546. GlyphToType3 glyph(stream, font, charindex);
  547. } /* end of tt_type3_charproc() */
  548. /*
  549. ** Some of the given glyph ids may refer to composite glyphs.
  550. ** This function adds all of the dependencies of those composite
  551. ** glyphs to the glyph id vector. Michael Droettboom [06-07-07]
  552. */
  553. void ttfont_add_glyph_dependencies(struct TTFONT *font, std::vector<int>& glyph_ids)
  554. {
  555. std::sort(glyph_ids.begin(), glyph_ids.end());
  556. std::stack<int> glyph_stack;
  557. for (std::vector<int>::iterator i = glyph_ids.begin();
  558. i != glyph_ids.end(); ++i)
  559. {
  560. glyph_stack.push(*i);
  561. }
  562. while (glyph_stack.size())
  563. {
  564. int gind = glyph_stack.top();
  565. glyph_stack.pop();
  566. BYTE* glyph = find_glyph_data( font, gind );
  567. if (glyph != (BYTE*)NULL)
  568. {
  569. int num_ctr = getSHORT(glyph);
  570. if (num_ctr <= 0) // This is a composite glyph
  571. {
  572. glyph += 10;
  573. USHORT flags = 0;
  574. do
  575. {
  576. flags = getUSHORT(glyph);
  577. glyph += 2;
  578. gind = (int)getUSHORT(glyph);
  579. glyph += 2;
  580. std::vector<int>::iterator insertion =
  581. std::lower_bound(glyph_ids.begin(), glyph_ids.end(), gind);
  582. if (insertion == glyph_ids.end() || *insertion != gind)
  583. {
  584. glyph_ids.insert(insertion, gind);
  585. glyph_stack.push(gind);
  586. }
  587. if (flags & ARG_1_AND_2_ARE_WORDS)
  588. {
  589. glyph += 4;
  590. }
  591. else
  592. {
  593. glyph += 2;
  594. }
  595. if (flags & WE_HAVE_A_SCALE)
  596. {
  597. glyph += 2;
  598. }
  599. else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
  600. {
  601. glyph += 4;
  602. }
  603. else if (flags & WE_HAVE_A_TWO_BY_TWO)
  604. {
  605. glyph += 8;
  606. }
  607. }
  608. while (flags & MORE_COMPONENTS);
  609. }
  610. }
  611. }
  612. }
  613. /* end of file */