PageRenderTime 116ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/source/src/Plugins/Pdf/dvipdfmx/pdfdev.c

http://itexmacs.googlecode.com/
C | 2019 lines | 1363 code | 297 blank | 359 comment | 210 complexity | 950c1f36fa8570ffb417f345410d8a6d MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /* $Header: /home/cvsroot/dvipdfmx/src/pdfdev.c,v 1.71 2009/03/16 22:26:40 matthias Exp $
  2. This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
  3. Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
  4. the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
  5. Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  17. */
  18. #if HAVE_CONFIG_H
  19. #include "config.h"
  20. #endif
  21. #include <string.h>
  22. #include <ctype.h>
  23. #include <math.h>
  24. #include "system.h"
  25. #include "mem.h"
  26. #include "error.h"
  27. #include "mfileio.h"
  28. #include "numbers.h"
  29. #include "pdfdoc.h"
  30. #include "pdfobj.h"
  31. #include "pdffont.h"
  32. #include "fontmap.h"
  33. #include "cmap.h"
  34. #include "pdfximage.h"
  35. #include "pdfdraw.h"
  36. #include "pdfcolor.h"
  37. #include "pdflimits.h"
  38. #include "pdfdev.h"
  39. static int verbose = 0;
  40. void
  41. pdf_dev_set_verbose (void)
  42. {
  43. verbose++;
  44. }
  45. /* Not working yet... */
  46. double
  47. pdf_dev_scale (void)
  48. {
  49. return 1.0;
  50. }
  51. /*
  52. * Unit conversion, formatting and others.
  53. */
  54. #define TEX_ONE_HUNDRED_BP 6578176
  55. static struct {
  56. double dvi2pts;
  57. long min_bp_val; /* Shortest resolvable distance in the output PDF. */
  58. int precision; /* Number of decimal digits (in fractional part) kept. */
  59. } dev_unit = {
  60. 0.0,
  61. 658,
  62. 2
  63. };
  64. double
  65. dev_unit_dviunit (void)
  66. {
  67. return (1.0/dev_unit.dvi2pts);
  68. }
  69. #define DEV_PRECISION_MAX 8
  70. static unsigned long ten_pow[10] = {
  71. 1ul, 10ul, 100ul, 1000ul, 10000ul, 100000ul, 1000000ul, 10000000ul, 100000000ul, 1000000000ul
  72. };
  73. static double ten_pow_inv[10] = {
  74. 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001, 0.000000001
  75. };
  76. #define bpt2spt(b) ( (spt_t) round( (b) / dev_unit.dvi2pts ) )
  77. #define spt2bpt(s) ( (s) * dev_unit.dvi2pts )
  78. #define dround_at(v,p) (ROUND( (v), ten_pow_inv[(p)] ))
  79. static int
  80. p_itoa (long value, char *buf)
  81. {
  82. int sign, ndigits;
  83. char *p = buf;
  84. if (value < 0) {
  85. *p++ = '-';
  86. value = -value;
  87. sign = 1;
  88. } else {
  89. sign = 0;
  90. }
  91. ndigits = 0;
  92. /* Generate at least one digit in reverse order */
  93. do {
  94. p[ndigits++] = (value % 10) + '0';
  95. value /= 10;
  96. } while (value != 0);
  97. /* Reverse the digits */
  98. {
  99. int i;
  100. for (i = 0; i < ndigits / 2 ; i++) {
  101. char tmp = p[i];
  102. p[i] = p[ndigits-i-1];
  103. p[ndigits-i-1] = tmp;
  104. }
  105. }
  106. p[ndigits] = '\0';
  107. return (sign ? ndigits + 1 : ndigits);
  108. }
  109. /* ... */
  110. static int
  111. p_dtoa (double value, int prec, char *buf)
  112. {
  113. const long p[10] = { 1, 10, 100, 1000, 10000,
  114. 100000, 1000000, 10000000, 100000000, 1000000000 };
  115. long i, f;
  116. char *c = buf;
  117. int n;
  118. if (value < 0) {
  119. value = -value;
  120. *c++ = '-';
  121. n = 1;
  122. } else
  123. n = 0;
  124. i = (long) value;
  125. f = (long) ((value-i)*p[prec] + 0.5);
  126. if (f == p[prec]) {
  127. f = 0;
  128. i++;
  129. }
  130. if (i) {
  131. int m = p_itoa(i, c);
  132. c += m;
  133. n += m;
  134. } else if (!f) {
  135. *(c = buf) = '0';
  136. n = 1;
  137. }
  138. if (f) {
  139. int j = prec;
  140. *c++ = '.';
  141. while (j--) {
  142. c[j] = (f % 10) + '0';
  143. f /= 10;
  144. }
  145. c += prec-1;
  146. n += 1+prec;
  147. while (*c == '0') {
  148. c--;
  149. n--;
  150. }
  151. }
  152. *(++c) = 0;
  153. return n;
  154. }
  155. static int
  156. dev_sprint_bp (char *buf, spt_t value, spt_t *error)
  157. {
  158. double value_in_bp;
  159. double error_in_bp;
  160. int prec = dev_unit.precision;
  161. value_in_bp = spt2bpt(value);
  162. if (error) {
  163. error_in_bp = value_in_bp - dround_at(value_in_bp, prec);
  164. *error = bpt2spt(error_in_bp);
  165. }
  166. return p_dtoa(value_in_bp, prec, buf);
  167. }
  168. /* They are affected by precision (set at device initialization). */
  169. int
  170. pdf_sprint_matrix (char *buf, const pdf_tmatrix *M)
  171. {
  172. int len;
  173. int prec2 = MIN(dev_unit.precision + 2, DEV_PRECISION_MAX);
  174. int prec0 = MAX(dev_unit.precision, 2);
  175. len = p_dtoa(M->a, prec2, buf);
  176. buf[len++] = ' ';
  177. len += p_dtoa(M->b, prec2, buf+len);
  178. buf[len++] = ' ';
  179. len += p_dtoa(M->c, prec2, buf+len);
  180. buf[len++] = ' ';
  181. len += p_dtoa(M->d, prec2, buf+len);
  182. buf[len++] = ' ';
  183. len += p_dtoa(M->e, prec0, buf+len);
  184. buf[len++] = ' ';
  185. len += p_dtoa(M->f, prec0, buf+len);
  186. buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
  187. return len;
  188. }
  189. int
  190. pdf_sprint_rect (char *buf, const pdf_rect *rect)
  191. {
  192. int len;
  193. len = p_dtoa(rect->llx, dev_unit.precision, buf);
  194. buf[len++] = ' ';
  195. len += p_dtoa(rect->lly, dev_unit.precision, buf+len);
  196. buf[len++] = ' ';
  197. len += p_dtoa(rect->urx, dev_unit.precision, buf+len);
  198. buf[len++] = ' ';
  199. len += p_dtoa(rect->ury, dev_unit.precision, buf+len);
  200. buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
  201. return len;
  202. }
  203. int
  204. pdf_sprint_coord (char *buf, const pdf_coord *p)
  205. {
  206. int len;
  207. len = p_dtoa(p->x, dev_unit.precision, buf);
  208. buf[len++] = ' ';
  209. len += p_dtoa(p->y, dev_unit.precision, buf+len);
  210. buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
  211. return len;
  212. }
  213. int
  214. pdf_sprint_length (char *buf, double value)
  215. {
  216. int len;
  217. len = p_dtoa(value, dev_unit.precision, buf);
  218. buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
  219. return len;
  220. }
  221. int
  222. pdf_sprint_number (char *buf, double value)
  223. {
  224. int len;
  225. len = p_dtoa(value, DEV_PRECISION_MAX, buf);
  226. buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
  227. return len;
  228. }
  229. static struct
  230. {
  231. /* Text composition (direction) mode is ignored (always same
  232. * as font's writing mode) if autorotate is unset (value zero).
  233. */
  234. int autorotate;
  235. /*
  236. * Ignore color migrated to here. This is device's capacity.
  237. * colormode 0 for ignore colors
  238. */
  239. int colormode;
  240. } dev_param = {
  241. 1, /* autorotate */
  242. 1, /* colormode */
  243. };
  244. /*
  245. * Text handling routines.
  246. */
  247. /* Motion state:
  248. * GRAPHICS_MODE Initial state (not within BT/ET block nor in string)
  249. * TEXT_MODE Text section is started via BT operator but not
  250. * in string.
  251. * STRING_MODE In string. A string or array of strings are currently
  252. * in process. May started '[', '<' or '('.
  253. */
  254. #define GRAPHICS_MODE 1
  255. #define TEXT_MODE 2
  256. #define STRING_MODE 3
  257. static int motion_state = GRAPHICS_MODE;
  258. #define FORMAT_BUF_SIZE 4096
  259. static char format_buffer[FORMAT_BUF_SIZE];
  260. /*
  261. * In PDF, vertical text positioning is always applied when current font
  262. * is vertical font. While ASCII pTeX manages current writing direction
  263. * and font's WMode separately.
  264. *
  265. * 00/11 WMODE_HH/VV h(v) font, h(v) direction.
  266. * 01 WMODE_HV -90 deg. rotated
  267. * 10 WMODE_VH +90 deg. rotated
  268. *
  269. * In MetaPost PostScript file processing (mp_mode = 1), only HH/VV mode
  270. * is applied.
  271. */
  272. #define TEXT_WMODE_HH 0
  273. #define TEXT_WMODE_HV 1
  274. #define TEXT_WMODE_VH 2
  275. #define TEXT_WMODE_VV 3
  276. #define ANGLE_CHANGES(m1,m2) ((abs((m1)-(m2)) % 3) == 0 ? 0 : 1)
  277. #define ROTATE_TEXT(m) ((m) != TEXT_WMODE_HH && (m) != TEXT_WMODE_VV)
  278. static struct {
  279. /* Current font.
  280. * This is index within dev_fonts.
  281. */
  282. int font_id;
  283. /* Dvipdfmx does compression of text by doing text positioning
  284. * in relative motion and uses string array [(foo) -250 (bar)]
  285. * with kerning (negative kern is used for white space as suited
  286. * for TeX). This is offset within current string.
  287. */
  288. spt_t offset;
  289. /* This is reference point of strings.
  290. * It may include error correction induced by rounding.
  291. */
  292. spt_t ref_x;
  293. spt_t ref_y;
  294. /* Using text raise and leading is highly recommended for
  295. * text extraction to work properly. But not implemented yet.
  296. * We can't do consice output for \TeX without this.
  297. */
  298. spt_t raise; /* unused */
  299. spt_t leading; /* unused */
  300. /* This is not always text matrix but rather font matrix.
  301. * We do not use horizontal scaling in PDF text state parameter
  302. * since they always apply scaling in fixed direction regardless
  303. * of writing mode.
  304. */
  305. struct {
  306. double slant;
  307. double extend;
  308. int rotate; /* TEXT_WMODE_XX */
  309. } matrix;
  310. /* Fake bold parameter:
  311. * If bold_param is positive, use text rendering mode
  312. * fill-then-stroke with stroking line width specified
  313. * by bold_param.
  314. */
  315. double bold_param;
  316. /* Text composition (direction) mode. */
  317. int dir_mode;
  318. /* internal */
  319. /* Flag indicating text matrix to be forcibly reset.
  320. * Enabled if synthetic font features (slant, extend, etc)
  321. * are used for current font or when text rotation mode
  322. * changes.
  323. */
  324. int force_reset;
  325. /* This information is duplicated from dev[font_id].format.
  326. * Set to 1 if font is composite (Type0) font.
  327. */
  328. int is_mb;
  329. } text_state = {
  330. -1, /* font */
  331. 0, /* offset */
  332. 0, 0, /* ref_x, ref_y */
  333. 0, 0, /* raise, leading */
  334. {0.0, 1.0, 0},
  335. 0.0, /* Experimental boldness param */
  336. 0, /* dir_mode */
  337. /* internal */
  338. 0, /* force_reset */
  339. 0 /* is_mb */
  340. };
  341. #define PDF_FONTTYPE_SIMPLE 1
  342. #define PDF_FONTTYPE_BITMAP 2
  343. #define PDF_FONTTYPE_COMPOSITE 3
  344. struct dev_font {
  345. /* Needs to be big enough to hold name "Fxxx"
  346. * where xxx is number of largest font
  347. */
  348. char short_name[7]; /* Resource name */
  349. int used_on_this_page;
  350. char *tex_name; /* String identifier of this font */
  351. spt_t sptsize; /* Point size */
  352. /* Returned values from font/encoding layer:
  353. *
  354. * The font_id and enc_id is font and encoding (CMap) identifier
  355. * used in pdf_font or encoding/cmap layer.
  356. * The PDF object "resource" is an indirect reference object
  357. * pointing font resource of this font. The used_chars is somewhat
  358. * misleading, this is actually used_glyphs in CIDFont for Type0
  359. * and is 65536/8 bytes binary data with each bits representing
  360. * whether the glyph is in-use or not. It is 256 char array for
  361. * simple font.
  362. */
  363. int font_id;
  364. int enc_id;
  365. pdf_obj *resource;
  366. char *used_chars;
  367. /* Font format:
  368. * simple, composite or bitmap.
  369. */
  370. int format;
  371. /* Writing mode:
  372. * Non-zero for vertical. Duplicated from CMap.
  373. */
  374. int wmode;
  375. /* Syntetic Font:
  376. *
  377. * We use text matrix for creating extended or slanted font,
  378. * but not with font's FontMatrix since TrueType and Type0
  379. * font don't support them.
  380. */
  381. double extend;
  382. double slant;
  383. double bold; /* Boldness prameter */
  384. /* Compatibility */
  385. int mapc; /* Nasty workaround for Omega */
  386. /* There are no font metric format supporting four-bytes
  387. * charcter code. So we should provide an option to specify
  388. * UCS group and plane.
  389. */
  390. int ucs_group;
  391. int ucs_plane;
  392. int is_unicode;
  393. int tfm_id;
  394. };
  395. static struct dev_font *dev_fonts = NULL;
  396. static int num_dev_fonts = 0;
  397. static int max_dev_fonts = 0;
  398. static int num_phys_fonts = 0;
  399. #define CURRENTFONT() ((text_state.font_id < 0) ? NULL : &(dev_fonts[text_state.font_id]))
  400. #define GET_FONT(n) (&(dev_fonts[(n)]))
  401. static void
  402. dev_set_text_matrix (spt_t xpos, spt_t ypos, double slant, double extend, int rotate)
  403. {
  404. pdf_tmatrix tm;
  405. int len = 0;
  406. /* slant is negated for vertical font so that right-side
  407. * is always lower. */
  408. switch (rotate) {
  409. case TEXT_WMODE_VH:
  410. /* Vertical font */
  411. tm.a = slant ; tm.b = 1.0;
  412. tm.c = -extend; tm.d = 0.0 ;
  413. break;
  414. case TEXT_WMODE_HV:
  415. /* Horizontal font */
  416. tm.a = 0.0; tm.b = -extend;
  417. tm.c = 1.0; tm.d = -slant ;
  418. break;
  419. case TEXT_WMODE_HH:
  420. /* Horizontal font */
  421. tm.a = extend; tm.b = 0.0;
  422. tm.c = slant ; tm.d = 1.0;
  423. break;
  424. case TEXT_WMODE_VV:
  425. /* Vertical font */
  426. tm.a = 1.0; tm.b = -slant;
  427. tm.c = 0.0; tm.d = extend;
  428. break;
  429. }
  430. tm.e = xpos * dev_unit.dvi2pts;
  431. tm.f = ypos * dev_unit.dvi2pts;
  432. format_buffer[len++] = ' ';
  433. len += pdf_sprint_matrix(format_buffer+len, &tm);
  434. format_buffer[len++] = ' ';
  435. format_buffer[len++] = 'T';
  436. format_buffer[len++] = 'm';
  437. pdf_doc_add_page_content(format_buffer, len); /* op: Tm */
  438. text_state.ref_x = xpos;
  439. text_state.ref_y = ypos;
  440. text_state.matrix.slant = slant;
  441. text_state.matrix.extend = extend;
  442. text_state.matrix.rotate = rotate;
  443. }
  444. /*
  445. * reset_text_state() outputs a BT and does any necessary coordinate
  446. * transformations to get ready to ship out text.
  447. */
  448. static void
  449. reset_text_state (void)
  450. {
  451. /*
  452. * We need to reset the line matrix to handle slanted fonts.
  453. */
  454. pdf_doc_add_page_content(" BT", 3); /* op: BT */
  455. /*
  456. * text_state.matrix is identity at top of page.
  457. * This sometimes write unnecessary "Tm"s when transition from
  458. * GRAPHICS_MODE to TEXT_MODE occurs.
  459. */
  460. if (text_state.force_reset ||
  461. text_state.matrix.slant != 0.0 ||
  462. text_state.matrix.extend != 1.0 ||
  463. ROTATE_TEXT(text_state.matrix.rotate)) {
  464. dev_set_text_matrix(0, 0,
  465. text_state.matrix.slant,
  466. text_state.matrix.extend,
  467. text_state.matrix.rotate);
  468. }
  469. text_state.ref_x = 0;
  470. text_state.ref_y = 0;
  471. text_state.offset = 0;
  472. text_state.force_reset = 0;
  473. }
  474. static void
  475. text_mode (void)
  476. {
  477. switch (motion_state) {
  478. case TEXT_MODE:
  479. break;
  480. case STRING_MODE:
  481. pdf_doc_add_page_content(text_state.is_mb ? ">]TJ" : ")]TJ", 4); /* op: TJ */
  482. break;
  483. case GRAPHICS_MODE:
  484. reset_text_state();
  485. break;
  486. }
  487. motion_state = TEXT_MODE;
  488. text_state.offset = 0;
  489. }
  490. void
  491. graphics_mode (void)
  492. {
  493. switch (motion_state) {
  494. case GRAPHICS_MODE:
  495. break;
  496. case STRING_MODE:
  497. pdf_doc_add_page_content(text_state.is_mb ? ">]TJ" : ")]TJ", 4); /* op: TJ */
  498. /* continue */
  499. case TEXT_MODE:
  500. pdf_doc_add_page_content(" ET", 3); /* op: ET */
  501. text_state.force_reset = 0;
  502. text_state.font_id = -1;
  503. break;
  504. }
  505. motion_state = GRAPHICS_MODE;
  506. }
  507. static void
  508. start_string (spt_t xpos, spt_t ypos, double slant, double extend, int rotate)
  509. {
  510. spt_t delx, dely, error_delx, error_dely;
  511. spt_t desired_delx, desired_dely;
  512. int len = 0;
  513. delx = xpos - text_state.ref_x;
  514. dely = ypos - text_state.ref_y;
  515. /*
  516. * Precompensating for line transformation matrix.
  517. *
  518. * Line transformation matrix L for horizontal font in horizontal
  519. * mode and it's inverse I is
  520. *
  521. * | e 0| | 1/e 0|
  522. * L_hh = | | , I_hh = | |
  523. * | s 1| |-s/e 1|
  524. *
  525. * For vertical font in vertical mode,
  526. *
  527. * | 1 -s| | 1 s/e|
  528. * L_vv = | | , I_vv = | |
  529. * | 0 e| | 0 1/e|
  530. *
  531. * For vertical font in horizontal mode,
  532. *
  533. * | s 1| | 0 1|
  534. * L_vh = | | = L_vv x | |
  535. * |-e 0| |-1 0|
  536. *
  537. * | 0 -1|
  538. * I_vh = | | x I_vv
  539. * | 1 0|
  540. *
  541. * For horizontal font in vertical mode,
  542. *
  543. * | 0 -e| | 0 -1|
  544. * L_hv = | | = L_hh x | |
  545. * | 1 -s| | 1 0|
  546. *
  547. * | 0 1|
  548. * I_hv = | | x I_hh
  549. * |-1 0|
  550. *
  551. */
  552. switch (rotate) {
  553. case TEXT_WMODE_VH:
  554. /* Vertical font in horizontal mode: rot = +90
  555. * | 0 -1/e|
  556. * d_user = d x I_vh = d x | |
  557. * | 1 s/e|
  558. */
  559. desired_delx = dely;
  560. desired_dely = (spt_t) (-(delx - dely*slant)/extend);
  561. /* error_del is in device space
  562. *
  563. * | 0 1|
  564. * e = e_user x | | = (-e_user_y, e_user_x)
  565. * |-1 0|
  566. *
  567. * We must care about rotation here but not extend/slant...
  568. * The extend and slant actually is font matrix.
  569. */
  570. format_buffer[len++] = ' ';
  571. len += dev_sprint_bp(format_buffer+len, desired_delx, &error_dely);
  572. format_buffer[len++] = ' ';
  573. len += dev_sprint_bp(format_buffer+len, desired_dely, &error_delx);
  574. error_delx = -error_delx;
  575. break;
  576. case TEXT_WMODE_HV:
  577. /* Horizontal font in vertical mode: rot = -90
  578. *
  579. * |-s/e 1|
  580. * d_user = d x I_hv = d x | |
  581. * |-1/e 0|
  582. */
  583. desired_delx = (spt_t)(-(dely + delx*slant)/extend);
  584. desired_dely = delx;
  585. /*
  586. * e = (e_user_y, -e_user_x)
  587. */
  588. format_buffer[len++] = ' ';
  589. len += dev_sprint_bp(format_buffer+len, desired_delx, &error_dely);
  590. format_buffer[len++] = ' ';
  591. len += dev_sprint_bp(format_buffer+len, desired_dely, &error_delx);
  592. error_dely = -error_dely;
  593. break;
  594. case TEXT_WMODE_HH:
  595. /* Horizontal font in horizontal mode:
  596. * | 1/e 0|
  597. * d_user = d x I_hh = d x | |
  598. * |-s/e 1|
  599. */
  600. desired_delx = (spt_t)((delx - dely*slant)/extend);
  601. desired_dely = dely;
  602. format_buffer[len++] = ' ';
  603. len += dev_sprint_bp(format_buffer+len, desired_delx, &error_delx);
  604. format_buffer[len++] = ' ';
  605. len += dev_sprint_bp(format_buffer+len, desired_dely, &error_dely);
  606. break;
  607. case TEXT_WMODE_VV:
  608. /* Vertical font in vertical mode:
  609. * | 1 s/e|
  610. * d_user = d x I_vv = d x | |
  611. * | 0 1/e|
  612. */
  613. desired_delx = delx;
  614. desired_dely = (spt_t)((dely + delx*slant)/extend);
  615. format_buffer[len++] = ' ';
  616. len += dev_sprint_bp(format_buffer+len, desired_delx, &error_delx);
  617. format_buffer[len++] = ' ';
  618. len += dev_sprint_bp(format_buffer+len, desired_dely, &error_dely);
  619. break;
  620. }
  621. pdf_doc_add_page_content(format_buffer, len); /* op: */
  622. /*
  623. * dvipdfm wrongly using "TD" in place of "Td".
  624. * The TD operator set leading, but we are not using T* etc.
  625. */
  626. pdf_doc_add_page_content(text_state.is_mb ? " Td[<" : " Td[(", 5); /* op: Td */
  627. /* Error correction */
  628. text_state.ref_x = xpos - error_delx;
  629. text_state.ref_y = ypos - error_dely;
  630. text_state.offset = 0;
  631. }
  632. static void
  633. string_mode (spt_t xpos, spt_t ypos, double slant, double extend, int rotate)
  634. {
  635. switch (motion_state) {
  636. case STRING_MODE:
  637. break;
  638. case GRAPHICS_MODE:
  639. reset_text_state();
  640. /* continue */
  641. case TEXT_MODE:
  642. if (text_state.force_reset) {
  643. dev_set_text_matrix(xpos, ypos, slant, extend, rotate);
  644. pdf_doc_add_page_content(text_state.is_mb ? "[<" : "[(", 2); /* op: */
  645. text_state.force_reset = 0;
  646. } else {
  647. start_string(xpos, ypos, slant, extend, rotate);
  648. }
  649. break;
  650. }
  651. motion_state = STRING_MODE;
  652. }
  653. /*
  654. * The purpose of the following routine is to force a Tf only
  655. * when it's actually necessary. This became a problem when the
  656. * VF code was added. The VF spec says to instantiate the
  657. * first font contained in the VF file before drawing a virtual
  658. * character. However, that font may not be used for
  659. * many characters (e.g. small caps fonts). For this reason,
  660. * dev_select_font() should not force a "physical" font selection.
  661. * This routine prevents a PDF Tf font selection until there's
  662. * really a character in that font.
  663. */
  664. static int
  665. dev_set_font (int font_id)
  666. {
  667. struct dev_font *font;
  668. int text_rotate;
  669. double font_scale;
  670. int len;
  671. int vert_dir, vert_font;
  672. /* text_mode() must come before text_state.is_mb is changed. */
  673. text_mode();
  674. font = GET_FONT(font_id);
  675. ASSERT(font); /* Caller should check font_id. */
  676. text_state.is_mb = (font->format == PDF_FONTTYPE_COMPOSITE) ? 1 : 0;
  677. vert_font = font->wmode ? 1 : 0;
  678. if (dev_param.autorotate) {
  679. vert_dir = text_state.dir_mode ? 1 : 0;
  680. } else {
  681. vert_dir = vert_font;
  682. }
  683. text_rotate = (vert_font << 1)|vert_dir;
  684. if (font->slant != text_state.matrix.slant ||
  685. font->extend != text_state.matrix.extend ||
  686. ANGLE_CHANGES(text_rotate, text_state.matrix.rotate)) {
  687. text_state.force_reset = 1;
  688. }
  689. text_state.matrix.slant = font->slant;
  690. text_state.matrix.extend = font->extend;
  691. text_state.matrix.rotate = text_rotate;
  692. if (!font->resource) {
  693. font->resource = pdf_get_font_reference(font->font_id);
  694. font->used_chars = pdf_get_font_usedchars(font->font_id);
  695. }
  696. if (!font->used_on_this_page) {
  697. pdf_doc_add_page_resource("Font",
  698. font->short_name,
  699. pdf_link_obj(font->resource));
  700. font->used_on_this_page = 1;
  701. }
  702. font_scale = (double) font->sptsize * dev_unit.dvi2pts;
  703. len = sprintf(format_buffer, " /%s", font->short_name); /* space not necessary. */
  704. format_buffer[len++] = ' ';
  705. len += p_dtoa(font_scale, MIN(dev_unit.precision+1, DEV_PRECISION_MAX), format_buffer+len);
  706. format_buffer[len++] = ' ';
  707. format_buffer[len++] = 'T';
  708. format_buffer[len++] = 'f';
  709. pdf_doc_add_page_content(format_buffer, len); /* op: Tf */
  710. if (font->bold > 0.0 || font->bold != text_state.bold_param) {
  711. if (font->bold <= 0.0)
  712. len = sprintf(format_buffer, " 0 Tr");
  713. else
  714. len = sprintf(format_buffer, " 2 Tr %.2f w", font->bold); /* _FIXME_ */
  715. pdf_doc_add_page_content(format_buffer, len); /* op: Tr w */
  716. }
  717. text_state.bold_param = font->bold;
  718. text_state.font_id = font_id;
  719. return 0;
  720. }
  721. /* Access text state parameters.
  722. */
  723. #if 0
  724. int
  725. pdf_dev_currentfont (void)
  726. {
  727. return text_state.font_id;
  728. }
  729. double
  730. pdf_dev_get_font_ptsize (int font_id)
  731. {
  732. struct dev_font *font;
  733. font = GET_FONT(font_id);
  734. if (font) {
  735. return font->sptsize * dev_unit.dvi2pts;
  736. }
  737. return 1.0;
  738. }
  739. #endif
  740. int
  741. pdf_dev_get_font_wmode (int font_id)
  742. {
  743. struct dev_font *font;
  744. font = GET_FONT(font_id);
  745. if (font) {
  746. return font->wmode;
  747. }
  748. return 0;
  749. }
  750. static unsigned char sbuf0[FORMAT_BUF_SIZE];
  751. static unsigned char sbuf1[FORMAT_BUF_SIZE];
  752. static int
  753. handle_multibyte_string (struct dev_font *font,
  754. unsigned char **str_ptr, int *str_len, int ctype)
  755. {
  756. unsigned char *p;
  757. int i, length;
  758. p = *str_ptr;
  759. length = *str_len;
  760. /* _FIXME_ */
  761. if (font->is_unicode) { /* UCS-4 */
  762. if (ctype == 1) {
  763. if (length * 4 >= FORMAT_BUF_SIZE) {
  764. WARN("Too long string...");
  765. return -1;
  766. }
  767. for (i = 0; i < length; i++) {
  768. sbuf1[i*4 ] = font->ucs_group;
  769. sbuf1[i*4+1] = font->ucs_plane;
  770. sbuf1[i*4+2] = '\0';
  771. sbuf1[i*4+3] = p[i];
  772. }
  773. length *= 4;
  774. } else if (ctype == 2) {
  775. if (length * 2 >= FORMAT_BUF_SIZE) {
  776. WARN("Too long string...");
  777. return -1;
  778. }
  779. for (i = 0; i < length; i += 2) {
  780. sbuf1[i*2 ] = font->ucs_group;
  781. sbuf1[i*2+1] = font->ucs_plane;
  782. sbuf1[i*2+2] = p[i];
  783. sbuf1[i*2+3] = p[i+1];
  784. }
  785. length *= 2;
  786. }
  787. p = sbuf1;
  788. } else if (ctype == 1 && font->mapc >= 0) {
  789. /* Omega workaround...
  790. * Translate single-byte chars to double byte code space.
  791. */
  792. if (length * 2 >= FORMAT_BUF_SIZE) {
  793. WARN("Too long string...");
  794. return -1;
  795. }
  796. for (i = 0; i < length; i++) {
  797. sbuf1[i*2 ] = (font->mapc & 0xff);
  798. sbuf1[i*2+1] = p[i];
  799. }
  800. length *= 2;
  801. p = sbuf1;
  802. }
  803. /*
  804. * Font is double-byte font. Output is assumed to be 16-bit fixed length
  805. * encoding.
  806. * TODO: A character decomposed to multiple characters.
  807. */
  808. if (font->enc_id >= 0) {
  809. unsigned char *inbuf, *outbuf;
  810. long inbytesleft, outbytesleft;
  811. CMap *cmap;
  812. cmap = CMap_cache_get(font->enc_id);
  813. inbuf = p;
  814. outbuf = sbuf0;
  815. inbytesleft = length;
  816. outbytesleft = FORMAT_BUF_SIZE;
  817. CMap_decode(cmap,
  818. (const unsigned char **) &inbuf, &inbytesleft, &outbuf, &outbytesleft);
  819. if (inbytesleft != 0) {
  820. WARN("CMap conversion failed. (%d bytes remains)", inbytesleft);
  821. return -1;
  822. }
  823. length = FORMAT_BUF_SIZE - outbytesleft;
  824. p = sbuf0;
  825. }
  826. *str_ptr = p;
  827. *str_len = length;
  828. return 0;
  829. }
  830. static pdf_coord *dev_coords = NULL;
  831. static int num_dev_coords = 0;
  832. static int max_dev_coords = 0;
  833. void pdf_dev_get_coord(double *xpos, double *ypos)
  834. {
  835. if (num_dev_coords > 0) {
  836. *xpos = dev_coords[num_dev_coords-1].x;
  837. *ypos = dev_coords[num_dev_coords-1].y;
  838. } else {
  839. *xpos = *ypos = 0.0;
  840. }
  841. }
  842. void pdf_dev_push_coord(double xpos, double ypos)
  843. {
  844. if (num_dev_coords >= max_dev_coords) {
  845. max_dev_coords += 4;
  846. dev_coords = RENEW(dev_coords, max_dev_coords, pdf_coord);
  847. }
  848. dev_coords[num_dev_coords].x = xpos;
  849. dev_coords[num_dev_coords].y = ypos;
  850. num_dev_coords++;
  851. }
  852. void pdf_dev_pop_coord(void)
  853. {
  854. if (num_dev_coords > 0) num_dev_coords--;
  855. }
  856. spt_t pdf_dev_string_width(int font_id, unsigned char *str, unsigned len)
  857. {
  858. if (font_id < 0 || font_id >= num_dev_fonts) {
  859. ERROR("Invalid font: %d (%d)", font_id, num_dev_fonts);
  860. return;
  861. }
  862. return tfm_string_width(GET_FONT(font_id)->tfm_id, str, len);
  863. }
  864. /*
  865. * ctype:
  866. * 0 byte-width of char can be variable and input string
  867. * is properly encoded.
  868. * n Single character cosumes n bytes in input string.
  869. *
  870. * _FIXME_
  871. * -->
  872. * selectfont(font_name, point_size) and show_string(pos, string)
  873. */
  874. void
  875. pdf_dev_set_string (spt_t xpos, spt_t ypos,
  876. const void *instr_ptr, int instr_len,
  877. spt_t width,
  878. int font_id, int ctype)
  879. {
  880. struct dev_font *font;
  881. unsigned char *str_ptr; /* Pointer to the reencoded string. */
  882. int length, i, len = 0;
  883. spt_t kern, delh, delv;
  884. spt_t text_xorigin;
  885. spt_t text_yorigin;
  886. if (font_id < 0 || font_id >= num_dev_fonts) {
  887. ERROR("Invalid font: %d (%d)", font_id, num_dev_fonts);
  888. return;
  889. }
  890. if (font_id != text_state.font_id) {
  891. dev_set_font(font_id);
  892. }
  893. font = CURRENTFONT();
  894. if (!font) {
  895. ERROR("Currentfont not set.");
  896. return;
  897. }
  898. text_xorigin = text_state.ref_x;
  899. text_yorigin = text_state.ref_y;
  900. str_ptr = (unsigned char *) instr_ptr;
  901. length = instr_len;
  902. if (font->format == PDF_FONTTYPE_COMPOSITE) {
  903. if (handle_multibyte_string(font, &str_ptr, &length, ctype) < 0) {
  904. ERROR("Error in converting input string...");
  905. return;
  906. }
  907. if (font->used_chars != NULL) {
  908. for (i = 0; i < length; i += 2)
  909. add_to_used_chars2(font->used_chars,
  910. (unsigned short) (str_ptr[i] << 8)|str_ptr[i+1]);
  911. }
  912. } else {
  913. if (font->used_chars != NULL) {
  914. for (i = 0; i < length; i++)
  915. font->used_chars[str_ptr[i]] = 1;
  916. }
  917. }
  918. if (num_dev_coords > 0) {
  919. xpos -= bpt2spt(dev_coords[num_dev_coords-1].x);
  920. ypos -= bpt2spt(dev_coords[num_dev_coords-1].y);
  921. }
  922. /*
  923. * Kern is in units of character units, i.e., 1000 = 1 em.
  924. *
  925. * Positive kern means kerning (reduce excess white space).
  926. *
  927. * The following formula is of the form a*x/b where a, x, and b are signed long
  928. * integers. Since in integer arithmetic (a*x) could overflow and a*(x/b) would
  929. * not be accurate, we use floating point arithmetic rather than trying to do
  930. * this all with integer arithmetic.
  931. *
  932. * 1000.0 / (font->extend * font->sptsize) is caluculated each times...
  933. * Is accuracy really a matter? Character widths are always rounded to integer
  934. * (in 1000 units per em) but dvipdfmx does not take into account of this...
  935. */
  936. if (text_state.dir_mode) {
  937. /* Top-to-bottom */
  938. delh = ypos - text_yorigin + text_state.offset;
  939. delv = xpos - text_xorigin;
  940. } else {
  941. /* Left-to-right */
  942. delh = text_xorigin + text_state.offset - xpos;
  943. delv = ypos - text_yorigin;
  944. }
  945. /* White-space more than 3em is not considered as a part of single text.
  946. * So we will break string mode in that case.
  947. * Dvipdfmx spend most of time processing strings with kern = 0 (but far
  948. * more times in font handling).
  949. * You may want to use pre-calculated value for WORD_SPACE_MAX.
  950. * More text compression may be possible by replacing kern with space char
  951. * when -kern is equal to space char width.
  952. */
  953. #define WORD_SPACE_MAX(f) (spt_t) (3.0 * (f)->extend * (f)->sptsize)
  954. if (text_state.force_reset ||
  955. labs(delv) > dev_unit.min_bp_val ||
  956. labs(delh) > WORD_SPACE_MAX(font)) {
  957. text_mode();
  958. kern = 0;
  959. } else {
  960. kern = (spt_t) (1000.0 / font->extend * delh / font->sptsize);
  961. }
  962. /* Inaccucary introduced by rounding of character width appears within
  963. * single text block. There are point_size/1000 rounding error per character.
  964. * If you really care about accuracy, you should compensate this here too.
  965. */
  966. if (motion_state != STRING_MODE)
  967. string_mode(xpos, ypos,
  968. font->slant, font->extend, text_state.matrix.rotate);
  969. else if (kern != 0) {
  970. /*
  971. * Same issues as earlier. Use floating point for simplicity.
  972. * This routine needs to be fast, so we don't call sprintf() or strcpy().
  973. */
  974. text_state.offset -=
  975. (spt_t) (kern * font->extend * (font->sptsize / 1000.0));
  976. format_buffer[len++] = text_state.is_mb ? '>' : ')';
  977. if (font->wmode)
  978. len += p_itoa(-kern, format_buffer + len);
  979. else {
  980. len += p_itoa( kern, format_buffer + len);
  981. }
  982. format_buffer[len++] = text_state.is_mb ? '<' : '(';
  983. pdf_doc_add_page_content(format_buffer, len); /* op: */
  984. len = 0;
  985. }
  986. if (text_state.is_mb) {
  987. if (FORMAT_BUF_SIZE - len < 2 * length)
  988. ERROR("Buffer overflow...");
  989. for (i = 0; i < length; i++) {
  990. int first, second;
  991. first = (str_ptr[i] >> 4) & 0x0f;
  992. second = str_ptr[i] & 0x0f;
  993. format_buffer[len++] = ((first >= 10) ? first + 'W' : first + '0');
  994. format_buffer[len++] = ((second >= 10) ? second + 'W' : second + '0');
  995. }
  996. } else {
  997. len += pdfobj_escape_str(format_buffer + len,
  998. FORMAT_BUF_SIZE - len, str_ptr, length);
  999. }
  1000. /* I think if you really care about speed, you should avoid memcopy here. */
  1001. pdf_doc_add_page_content(format_buffer, len); /* op: */
  1002. text_state.offset += width;
  1003. }
  1004. void
  1005. pdf_dev_set_raw_glyph (spt_t xpos, spt_t ypos, unsigned char glyph, int font_id)
  1006. {
  1007. struct dev_font *font;
  1008. int i, len = 0;
  1009. spt_t kern, delh, delv;
  1010. spt_t text_xorigin;
  1011. spt_t text_yorigin;
  1012. if (font_id < 0 || font_id >= num_dev_fonts) {
  1013. ERROR("Invalid font: %d (%d)", font_id, num_dev_fonts);
  1014. return;
  1015. }
  1016. if (font_id != text_state.font_id) {
  1017. dev_set_font(font_id);
  1018. }
  1019. font = CURRENTFONT();
  1020. if (!font) {
  1021. ERROR("Currentfont not set.");
  1022. return;
  1023. }
  1024. text_xorigin = text_state.ref_x;
  1025. text_yorigin = text_state.ref_y;
  1026. if (font->format == PDF_FONTTYPE_COMPOSITE) {
  1027. ERROR("This should not happen...");
  1028. return;
  1029. } else {
  1030. if (font->used_chars != NULL) {
  1031. font->used_chars[glyph] = 1;
  1032. }
  1033. }
  1034. if (num_dev_coords > 0) {
  1035. xpos -= bpt2spt(dev_coords[num_dev_coords-1].x);
  1036. ypos -= bpt2spt(dev_coords[num_dev_coords-1].y);
  1037. }
  1038. /*
  1039. * Kern is in units of character units, i.e., 1000 = 1 em.
  1040. *
  1041. * Positive kern means kerning (reduce excess white space).
  1042. *
  1043. * The following formula is of the form a*x/b where a, x, and b are signed long
  1044. * integers. Since in integer arithmetic (a*x) could overflow and a*(x/b) would
  1045. * not be accurate, we use floating point arithmetic rather than trying to do
  1046. * this all with integer arithmetic.
  1047. *
  1048. * 1000.0 / (font->extend * font->sptsize) is caluculated each times...
  1049. * Is accuracy really a matter? Character widths are always rounded to integer
  1050. * (in 1000 units per em) but dvipdfmx does not take into account of this...
  1051. */
  1052. if (text_state.dir_mode) {
  1053. /* Top-to-bottom */
  1054. delh = ypos - text_yorigin + text_state.offset;
  1055. delv = xpos - text_xorigin;
  1056. } else {
  1057. /* Left-to-right */
  1058. delh = text_xorigin + text_state.offset - xpos;
  1059. delv = ypos - text_yorigin;
  1060. }
  1061. /* White-space more than 3em is not considered as a part of single text.
  1062. * So we will break string mode in that case.
  1063. * Dvipdfmx spend most of time processing strings with kern = 0 (but far
  1064. * more times in font handling).
  1065. * You may want to use pre-calculated value for WORD_SPACE_MAX.
  1066. * More text compression may be possible by replacing kern with space char
  1067. * when -kern is equal to space char width.
  1068. */
  1069. #define WORD_SPACE_MAX(f) (spt_t) (3.0 * (f)->extend * (f)->sptsize)
  1070. text_mode();
  1071. kern = 0;
  1072. /* Inaccucary introduced by rounding of character width appears within
  1073. * single text block. There are point_size/1000 rounding error per character.
  1074. * If you really care about accuracy, you should compensate this here too.
  1075. */
  1076. if (motion_state != STRING_MODE)
  1077. string_mode(xpos, ypos,
  1078. font->slant, font->extend, text_state.matrix.rotate);
  1079. else if (kern != 0) {
  1080. /*
  1081. * Same issues as earlier. Use floating point for simplicity.
  1082. * This routine needs to be fast, so we don't call sprintf() or strcpy().
  1083. */
  1084. text_state.offset -=
  1085. (spt_t) (kern * font->extend * (font->sptsize / 1000.0));
  1086. format_buffer[len++] = text_state.is_mb ? '>' : ')';
  1087. if (font->wmode)
  1088. len += p_itoa(-kern, format_buffer + len);
  1089. else {
  1090. len += p_itoa( kern, format_buffer + len);
  1091. }
  1092. format_buffer[len++] = text_state.is_mb ? '<' : '(';
  1093. pdf_doc_add_page_content(format_buffer, len); /* op: */
  1094. len = 0;
  1095. }
  1096. if (text_state.is_mb) {
  1097. if (FORMAT_BUF_SIZE - len < 2)
  1098. ERROR("Buffer overflow...");
  1099. int first, second;
  1100. first = (glyph >> 4) & 0x0f;
  1101. second = glyph & 0x0f;
  1102. format_buffer[len++] = ((first >= 10) ? first + 'W' : first + '0');
  1103. format_buffer[len++] = ((second >= 10) ? second + 'W' : second + '0');
  1104. } else {
  1105. len += pdfobj_escape_str(format_buffer + len,
  1106. FORMAT_BUF_SIZE - len, &glyph, 1);
  1107. }
  1108. /* I think if you really care about speed, you should avoid memcopy here. */
  1109. pdf_doc_add_page_content(format_buffer, len); /* op: */
  1110. // text_state.offset += width;
  1111. }
  1112. void
  1113. pdf_init_device (double dvi2pts, int precision, int black_and_white)
  1114. {
  1115. if (precision < 0 ||
  1116. precision > DEV_PRECISION_MAX)
  1117. WARN("Number of decimal digits out of range [0-%d].",
  1118. DEV_PRECISION_MAX);
  1119. if (precision < 0) {
  1120. dev_unit.precision = 0;
  1121. } else if (precision > DEV_PRECISION_MAX) {
  1122. dev_unit.precision = DEV_PRECISION_MAX;
  1123. } else {
  1124. dev_unit.precision = precision;
  1125. }
  1126. dev_unit.dvi2pts = dvi2pts;
  1127. dev_unit.min_bp_val = (long) ROUND(1.0/(ten_pow[dev_unit.precision]*dvi2pts), 1);
  1128. if (dev_unit.min_bp_val < 0)
  1129. dev_unit.min_bp_val = -dev_unit.min_bp_val;
  1130. dev_param.colormode = (black_and_white ? 0 : 1);
  1131. graphics_mode();
  1132. pdf_color_clear_stack();
  1133. pdf_dev_init_gstates();
  1134. num_dev_fonts = max_dev_fonts = 0;
  1135. dev_fonts = NULL;
  1136. num_dev_coords = max_dev_coords = 0;
  1137. dev_coords = NULL;
  1138. }
  1139. void
  1140. pdf_close_device (void)
  1141. {
  1142. if (dev_fonts) {
  1143. int i;
  1144. for (i = 0; i < num_dev_fonts; i++) {
  1145. if (dev_fonts[i].tex_name)
  1146. RELEASE(dev_fonts[i].tex_name);
  1147. if (dev_fonts[i].resource)
  1148. pdf_release_obj(dev_fonts[i].resource);
  1149. dev_fonts[i].tex_name = NULL;
  1150. dev_fonts[i].resource = NULL;
  1151. }
  1152. RELEASE(dev_fonts);
  1153. }
  1154. if (dev_coords) RELEASE(dev_coords);
  1155. pdf_dev_clear_gstates();
  1156. }
  1157. /*
  1158. * BOP, EOP, and FONT section.
  1159. * BOP and EOP manipulate some of the same data structures
  1160. * as the font stuff.
  1161. */
  1162. void
  1163. pdf_dev_reset_fonts (void)
  1164. {
  1165. int i;
  1166. for (i = 0; i < num_dev_fonts; i++) {
  1167. dev_fonts[i].used_on_this_page = 0;
  1168. }
  1169. text_state.font_id = -1;
  1170. text_state.matrix.slant = 0.0;
  1171. text_state.matrix.extend = 1.0;
  1172. text_state.matrix.rotate = TEXT_WMODE_HH;
  1173. text_state.bold_param = 0.0;
  1174. text_state.is_mb = 0;
  1175. }
  1176. #if 0
  1177. /* Not working */
  1178. void
  1179. pdf_dev_set_origin (double phys_x, double phys_y)
  1180. {
  1181. pdf_tmatrix M0, M1;
  1182. pdf_dev_currentmatrix(&M0);
  1183. pdf_dev_currentmatrix(&M1);
  1184. pdf_invertmatrix(&M1);
  1185. M0.e = phys_x; M0.f = phys_y;
  1186. pdf_concatmatrix(&M1, &M0);
  1187. pdf_dev_concat(&M1);
  1188. }
  1189. #endif
  1190. void
  1191. pdf_dev_bop (const pdf_tmatrix *M)
  1192. {
  1193. graphics_mode();
  1194. text_state.force_reset = 0;
  1195. pdf_dev_gsave();
  1196. pdf_dev_concat(M);
  1197. pdf_dev_reset_fonts();
  1198. pdf_dev_reset_color(0);
  1199. }
  1200. void
  1201. pdf_dev_eop (void)
  1202. {
  1203. int depth;
  1204. graphics_mode();
  1205. depth = pdf_dev_current_depth();
  1206. if (depth != 1) {
  1207. WARN("Unbalenced q/Q nesting...: %d", depth);
  1208. pdf_dev_grestore_to(0);
  1209. } else {
  1210. pdf_dev_grestore();
  1211. }
  1212. }
  1213. static void
  1214. print_fontmap (const char *font_name, fontmap_rec *mrec)
  1215. {
  1216. if (!mrec)
  1217. return;
  1218. MESG("\n");
  1219. MESG("fontmap: %s -> %s", font_name, mrec->font_name);
  1220. if (mrec->enc_name)
  1221. MESG("(%s)", mrec->enc_name);
  1222. if (mrec->opt.extend != 1.0)
  1223. MESG("[extend:%g]", mrec->opt.extend);
  1224. if (mrec->opt.slant != 0.0)
  1225. MESG("[slant:%g]", mrec->opt.slant);
  1226. if (mrec->opt.bold != 0.0)
  1227. MESG("[bold:%g]", mrec->opt.bold);
  1228. if (mrec->opt.flags & FONTMAP_OPT_NOEMBED)
  1229. MESG("[noemb]");
  1230. if (mrec->opt.mapc >= 0)
  1231. MESG("[map:<%02x>]", mrec->opt.mapc);
  1232. if (mrec->opt.charcoll)
  1233. MESG("[csi:%s]", mrec->opt.charcoll);
  1234. if (mrec->opt.index)
  1235. MESG("[index:%d]", mrec->opt.index);
  1236. switch (mrec->opt.style) {
  1237. case FONTMAP_STYLE_BOLD:
  1238. MESG("[style:bold]");
  1239. break;
  1240. case FONTMAP_STYLE_ITALIC:
  1241. MESG("[style:italic]");
  1242. break;
  1243. case FONTMAP_STYLE_BOLDITALIC:
  1244. MESG("[style:bolditalic]");
  1245. break;
  1246. }
  1247. MESG("\n");
  1248. }
  1249. /* _FIXME_
  1250. * Font is identified with font_name and point_size as in DVI here.
  1251. * This may assign different resource name for same font at different
  1252. * point size even for scalable fonts.
  1253. */
  1254. int
  1255. pdf_dev_locate_font (const char *font_name, spt_t ptsize)
  1256. {
  1257. int i;
  1258. fontmap_rec *mrec;
  1259. struct dev_font *font;
  1260. if (!font_name)
  1261. return -1;
  1262. if (ptsize == 0) {
  1263. ERROR("pdf_dev_locate_font() called with the zero ptsize.");
  1264. return -1;
  1265. }
  1266. for (i = 0; i < num_dev_fonts; i++) {
  1267. if (!strcmp(font_name, dev_fonts[i].tex_name) && ptsize == dev_fonts[i].sptsize) {
  1268. return i;
  1269. }
  1270. }
  1271. /*
  1272. * Make sure we have room for a new one, even though we may not
  1273. * actually create one.
  1274. */
  1275. if (num_dev_fonts >= max_dev_fonts) {
  1276. max_dev_fonts += 16;
  1277. dev_fonts = RENEW(dev_fonts, max_dev_fonts, struct dev_font);
  1278. }
  1279. font = &dev_fonts[num_dev_fonts];
  1280. /* New font */
  1281. mrec = pdf_lookup_fontmap_record(font_name);
  1282. if (verbose > 1)
  1283. print_fontmap(font_name, mrec);
  1284. font->font_id = pdf_font_findresource(font_name, ptsize * dev_unit.dvi2pts, mrec);
  1285. if (font->font_id < 0)
  1286. return -1;
  1287. /* We found device font here. */
  1288. font->short_name[0] = 'F';
  1289. p_itoa(num_phys_fonts + 1, &font->short_name[1]); /* NULL terminated here */
  1290. num_phys_fonts++;
  1291. font->used_on_this_page = 0;
  1292. font->tex_name = NEW(strlen(font_name) + 1, char);
  1293. strcpy(font->tex_name, font_name);
  1294. font->sptsize = ptsize;
  1295. switch (pdf_get_font_subtype(font->font_id)) {
  1296. case PDF_FONT_FONTTYPE_TYPE3:
  1297. font->format = PDF_FONTTYPE_BITMAP;
  1298. break;
  1299. case PDF_FONT_FONTTYPE_TYPE0:
  1300. font->format = PDF_FONTTYPE_COMPOSITE;
  1301. break;
  1302. default:
  1303. font->format = PDF_FONTTYPE_SIMPLE;
  1304. break;
  1305. }
  1306. font->wmode = pdf_get_font_wmode (font->font_id);
  1307. font->enc_id = pdf_get_font_encoding(font->font_id);
  1308. font->resource = NULL; /* Don't ref obj until font is actually used. */
  1309. font->used_chars = NULL;
  1310. font->extend = 1.0;
  1311. font->slant = 0.0;
  1312. font->bold = 0.0;
  1313. font->mapc = -1;
  1314. font->is_unicode = 0;
  1315. font->ucs_group = 0;
  1316. font->ucs_plane = 0;
  1317. if (mrec) {
  1318. font->extend = mrec->opt.extend;
  1319. font->slant = mrec->opt.slant;
  1320. font->bold = mrec->opt.bold;
  1321. if (mrec->opt.mapc >= 0)
  1322. font->mapc = (mrec->opt.mapc >> 8) & 0xff;
  1323. else {
  1324. font->mapc = -1;
  1325. }
  1326. if (mrec->enc_name &&
  1327. !strcmp(mrec->enc_name, "unicode")) {
  1328. font->is_unicode = 1;
  1329. if (mrec->opt.mapc >= 0) {
  1330. font->ucs_group = (mrec->opt.mapc >> 24) & 0xff;
  1331. font->ucs_plane = (mrec->opt.mapc >> 16) & 0xff;
  1332. } else {
  1333. font->ucs_group = 0;
  1334. font->ucs_plane = 0;
  1335. }
  1336. } else {
  1337. font->is_unicode = 0;
  1338. }
  1339. }
  1340. return num_dev_fonts++;
  1341. }
  1342. int
  1343. pdf_dev_physical_font (const char *font_name, spt_t ptsize, const char *font_file, const char *tfm_file)
  1344. {
  1345. int i;
  1346. fontmap_rec *mrec = NULL;
  1347. struct dev_font *font;
  1348. if (!font_name)
  1349. return -1;
  1350. if (ptsize == 0) {
  1351. ERROR("pdf_dev_physical_font() called with the zero ptsize.");
  1352. return -1;
  1353. }
  1354. for (i = 0; i < num_dev_fonts; i++) {
  1355. if (!strcmp(font_name, dev_fonts[i].tex_name) && ptsize == dev_fonts[i].sptsize) {
  1356. return i;
  1357. }
  1358. }
  1359. /*
  1360. * Make sure we have room for a new one, even though we may not
  1361. * actually create one.
  1362. */
  1363. if (num_dev_fonts >= max_dev_fonts) {
  1364. max_dev_fonts += 16;
  1365. dev_fonts = RENEW(dev_fonts, max_dev_fonts, struct dev_font);
  1366. }
  1367. font = &dev_fonts[num_dev_fonts];
  1368. /* New font */
  1369. // mrec = pdf_lookup_fontmap_record(font_name);
  1370. if (verbose > 1)
  1371. print_fontmap(font_name, mrec);
  1372. font->font_id = pdf_font_physical(font_name, ptsize * dev_unit.dvi2pts, font_file, tfm_file);
  1373. if (font->font_id < 0)
  1374. return -1;
  1375. /* We found device font here. */
  1376. font->short_name[0] = 'F';
  1377. p_itoa(num_phys_fonts + 1, &font->short_name[1]); /* NULL terminated here */
  1378. num_phys_fonts++;
  1379. font->used_on_this_page = 0;
  1380. font->tex_name = NEW(strlen(font_name) + 1, char);
  1381. strcpy(font->tex_name, font_name);
  1382. font->sptsize = ptsize;
  1383. switch (pdf_get_font_subtype(font->font_id)) {
  1384. case PDF_FONT_FONTTYPE_TYPE3:
  1385. font->format = PDF_FONTTYPE_BITMAP;
  1386. break;
  1387. case PDF_FONT_FONTTYPE_TYPE0:
  1388. font->format = PDF_FONTTYPE_COMPOSITE;
  1389. break;
  1390. default:
  1391. font->format = PDF_FONTTYPE_SIMPLE;
  1392. break;
  1393. }
  1394. font->wmode = pdf_get_font_wmode (font->font_id);
  1395. font->enc_id = pdf_get_font_encoding(font->font_id);
  1396. font->resource = NULL; /* Don't ref obj until font is actually used. */
  1397. font->used_chars = NULL;
  1398. font->extend = 1.0;
  1399. font->slant = 0.0;
  1400. font->bold = 0.0;
  1401. font->mapc = -1;
  1402. font->is_unicode = 0;
  1403. font->ucs_group = 0;
  1404. font->ucs_plane = 0;
  1405. font->tfm_id = (tfm_file ? tfm_open(tfm_file, 1) : -1);
  1406. if (mrec) {
  1407. font->extend = mrec->opt.extend;
  1408. font->slant = mrec->opt.slant;
  1409. font->bold = mrec->opt.bold;
  1410. if (mrec->opt.mapc >= 0)
  1411. font->mapc = (mrec->opt.mapc >> 8) & 0xff;
  1412. else {
  1413. font->mapc = -1;
  1414. }
  1415. if (mrec->enc_name &&
  1416. !strcmp(mrec->enc_name, "unicode")) {
  1417. font->is_unicode = 1;
  1418. if (mrec->opt.mapc >= 0) {
  1419. font->ucs_group = (mrec->opt.mapc >> 24) & 0xff;
  1420. font->ucs_plane = (mrec->opt.mapc >> 16) & 0xff;
  1421. } else {
  1422. font->ucs_group = 0;
  1423. font->ucs_plane = 0;
  1424. }
  1425. } else {
  1426. font->is_unicode = 0;
  1427. }
  1428. }
  1429. return num_dev_fonts++;
  1430. }
  1431. /* This does not remember current stroking width. */
  1432. static int
  1433. dev_sprint_line (char *buf, spt_t width,
  1434. spt_t p0_x, spt_t p0_y, spt_t p1_x, spt_t p1_y)
  1435. {
  1436. int len = 0;
  1437. double w;
  1438. w = width * dev_unit.dvi2pts;
  1439. len += p_dtoa(w, MIN(dev_unit.precision+1, DEV_PRECISION_MAX), buf+len);
  1440. buf[len++] = ' ';
  1441. buf[len++] = 'w';
  1442. buf[len++] = ' ';
  1443. len += dev_sprint_bp(buf+len, p0_x, NULL);
  1444. buf[len++] = ' ';
  1445. len += dev_sprint_bp(buf+len, p0_y, NULL);
  1446. buf[len++] = ' ';
  1447. buf[len++] = 'm';
  1448. buf[len++] = ' ';
  1449. len += dev_sprint_bp(buf+len, p1_x, NULL);
  1450. buf[len++] = ' ';
  1451. len += dev_sprint_bp(buf+len, p1_y, NULL);
  1452. buf[len++] = ' ';
  1453. buf[len++] = 'l';
  1454. buf[len++] = ' ';
  1455. buf[len++] = 'S';
  1456. return len;
  1457. }
  1458. /* Not optimized. */
  1459. #define PDF_LINE_THICKNESS_MAX 5.0
  1460. void
  1461. pdf_dev_set_rule (spt_t xpos, spt_t ypos, spt_t width, spt_t height)
  1462. {
  1463. int len = 0;
  1464. double width_in_bp;
  1465. if (num_dev_coords > 0) {
  1466. xpos -= bpt2spt(dev_coords[num_dev_coords-1].x);
  1467. ypos -= bpt2spt(dev_coords[num_dev_coords-1].y);
  1468. }
  1469. graphics_mode();
  1470. format_buffer[len++] = ' ';
  1471. format_buffer[len++] = 'q';
  1472. format_buffer[len++] = ' ';
  1473. /* Don't use too thick line. */
  1474. width_in_bp = ((width < height) ? width : height) * dev_unit.dvi2pts;
  1475. if (width_in_bp < 0.0 || /* Shouldn't happen */
  1476. width_in_bp > PDF_LINE_THICKNESS_MAX) {
  1477. pdf_rect rect;
  1478. rect.llx = dev_unit.dvi2pts * xpos;
  1479. rect.lly = dev_unit.dvi2pts * ypos;
  1480. rect.urx = dev_unit.dvi2pts * width;
  1481. rect.ury = dev_unit.dvi2pts * height;
  1482. len += pdf_sprint_rect(format_buffer+len, &rect);
  1483. format_buffer[len++] = ' ';
  1484. format_buffer[len++] = 'r';
  1485. format_buffer[len++] = 'e';
  1486. format_buffer[len++] = ' ';
  1487. format_buffer[len++] = 'f';
  1488. } else {
  1489. if (width > height) {
  1490. /* NOTE:
  1491. * A line width of 0 denotes the thinnest line that can be rendered at
  1492. * device resolution. See, PDF Reference Manual 4th ed., sec. 4.3.2,
  1493. * "Details of Graphics State Parameters", p. 185.
  1494. */
  1495. if (height < dev_unit.min_bp_val) {
  1496. WARN("Too thin line: height=%ld (%g bp)", height, width_in_bp);
  1497. WARN("Please consider using \"-d\" option.");
  1498. }
  1499. len += dev_sprint_line(format_buffer+len,
  1500. height,
  1501. xpos,
  1502. ypos + height/2,
  1503. xpos + width,
  1504. ypos + height/2);
  1505. } else {
  1506. if (width < dev_unit.min_bp_val) {
  1507. WARN("Too thin line: width=%ld (%g bp)", width, width_in_bp);
  1508. WARN("Please consider using \"-d\" option.");
  1509. }
  1510. len += dev_sprint_line(format_buffer+len,
  1511. width,
  1512. xpos + width/2,
  1513. ypos,
  1514. xpos + width/2,
  1515. ypos + height);
  1516. }
  1517. }
  1518. format_buffer[len++] = ' ';
  1519. format_buffer[len++] = 'Q';
  1520. pdf_doc_add_page_content(format_buffer, len); /* op: q re f Q */
  1521. }
  1522. /* Rectangle in device space coordinate. */
  1523. void
  1524. pdf_dev_set_rect (pdf_rect *rect,
  1525. spt_t x_user, spt_t y_user,
  1526. spt_t width, spt_t height, spt_t depth)
  1527. {
  1528. double dev_x, dev_y;
  1529. pdf_coord p0, p1, p2, p3;
  1530. double min_x, min_y, max_x, max_y;
  1531. dev_x = x_user * dev_unit.dvi2pts;
  1532. dev_y = y_user * dev_unit.dvi2pts;
  1533. if (text_state.dir_mode) {
  1534. p0.x = dev_x - dev_unit.dvi2pts * depth;
  1535. p0.y = dev_y - dev_unit.dvi2pts * width;
  1536. p1.x = dev_x + dev_unit.dvi2pts * height;
  1537. p1.y = p0.y;
  1538. p2.x = p1.x;
  1539. p2.y = dev_y;
  1540. p3.x = p0.x;
  1541. p3.y = p2.y;
  1542. } else {
  1543. p0.x = dev_x;
  1544. p0.y = dev_y - dev_unit.dvi2pts * depth;
  1545. p1.x = dev_x + dev_unit.dvi2pts * width;
  1546. p1.y = p0.y;
  1547. p2.x = p1.x;
  1548. p2.y = dev_y + dev_unit.dvi2pts * height;
  1549. p3.x = p0.x;
  1550. p3.y = p2.y;
  1551. }
  1552. pdf_dev_transform(&p0, NULL); /* currentmatrix */
  1553. pdf_dev_transform(&p1, NULL);
  1554. pdf_dev_transform(&p2, NULL);
  1555. pdf_dev_transform(&p3, NULL);
  1556. min_x = MIN(p0.x , p1.x);
  1557. min_x = MIN(min_x, p2.x);
  1558. min_x = MIN(min_x, p3.x);
  1559. max_x = MAX(p0.x , p1.x);
  1560. max_x = MAX(max_x, p2.x);
  1561. max_x = MAX(max_x, p3.x);
  1562. min_y = MIN(p0.y , p1.y);
  1563. min_y = MIN(min_y, p2.y);
  1564. min_y = MIN(min_y, p3.y);
  1565. max_y = MAX(p0.y , p1.y);
  1566. max_y = MAX(max_y, p2.y);
  1567. max_y = MAX(max_y, p3.y);
  1568. rect->llx = min_x;
  1569. rect->lly = min_y;
  1570. rect->urx = max_x;
  1571. rect->ury = max_y;
  1572. return;
  1573. }
  1574. int
  1575. pdf_dev_get_dirmode (void)
  1576. {
  1577. return text_state.dir_mode;
  1578. }
  1579. void
  1580. pdf_dev_set_dirmode (int text_dir)
  1581. {
  1582. struct dev_font *font;
  1583. int text_rotate;
  1584. int vert_dir, vert_font;
  1585. font = CURRENTFONT();
  1586. vert_font = (font && font->wmode) ? 1 : 0;
  1587. if (dev_param.autorotate) {
  1588. vert_dir = text_dir ? 1 : 0;
  1589. } else {
  1590. vert_dir = vert_font;
  1591. }
  1592. text_rotate = (vert_font << 1)|vert_dir;
  1593. if (font &&
  1594. ANGLE_CHANGES(text_rotate, text_state.matrix.rotate)) {
  1595. text_state.force_reset = 1;
  1596. }
  1597. text_state.matrix.rotate = text_rotate;
  1598. text_state.dir_mode = text_dir;
  1599. }
  1600. static void
  1601. dev_set_param_autorotate (int auto_rotate)
  1602. {
  1603. struct dev_font *font;
  1604. int text_rotate, vert_font, vert_dir;
  1605. font = CURRENTFONT();
  1606. vert_font = (font && font->wmode) ? 1 : 0;
  1607. if (auto_rotate) {
  1608. vert_dir = text_state.dir_mode ? 1 : 0;
  1609. } else {
  1610. vert_dir = vert_font;
  1611. }
  1612. text_rotate = (vert_font << 1)|vert_dir;
  1613. if (ANGLE_CHANGES(text_rotate, text_state.matrix.rotate)) {
  1614. text_state.force_reset = 1;
  1615. }
  1616. text_state.matrix.rotate = text_rotate;
  1617. dev_param.autorotate = auto_rotate;
  1618. }
  1619. int
  1620. pdf_dev_get_param (int param_type)
  1621. {
  1622. int value = 0;
  1623. switch (param_type) {
  1624. case PDF_DEV_PARAM_AUTOROTATE:
  1625. value = dev_param.autorotate;
  1626. break;
  1627. case PDF_DEV_PARAM_COLORMODE:
  1628. value = dev_param.colormode;
  1629. break;
  1630. default:
  1631. ERROR("Unknown device parameter: %d", param_type);
  1632. }
  1633. return value;
  1634. }
  1635. void
  1636. pdf_dev_set_param (int param_type, int value)
  1637. {
  1638. switch (param_type) {
  1639. case PDF_DEV_PARAM_AUTOROTATE:
  1640. dev_set_param_autorotate(value);
  1641. break;
  1642. case PDF_DEV_PARAM_COLORMODE:
  1643. dev_param.colormode = value; /* 0 for B&W */
  1644. break;
  1645. default:
  1646. ERROR("Unknown device parameter: %d", param_type);
  1647. }
  1648. return;
  1649. }
  1650. int
  1651. pdf_dev_put_image (int id,

Large files files are truncated, but you can click here to view the full file