gdevpdft.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /* Copyright (C) 1996, 2000 Aladdin Enterprises. All rights reserved.
  2. This file is part of AFPL Ghostscript.
  3. AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
  4. distributor accepts any responsibility for the consequences of using it, or
  5. for whether it serves any particular purpose or works at all, unless he or
  6. she says so in writing. Refer to the Aladdin Free Public License (the
  7. "License") for full details.
  8. Every copy of AFPL Ghostscript must include a copy of the License, normally
  9. in a plain ASCII text file named PUBLIC. The License grants you the right
  10. to copy, modify and redistribute AFPL Ghostscript, but only under certain
  11. conditions described in the License. Among other things, the License
  12. requires that the copyright notice and this notice be preserved on all
  13. copies.
  14. */
  15. /*$Id: gdevpdft.c,v 1.36 2001/07/30 15:11:00 lpd Exp $ */
  16. /* Text handling for PDF-writing driver. */
  17. #include "math_.h"
  18. #include "memory_.h"
  19. #include "string_.h"
  20. #include "gx.h"
  21. #include "gserrors.h"
  22. #include "gxpath.h" /* for getting current point */
  23. #include "gdevpdfx.h"
  24. #include "gdevpdff.h"
  25. #include "gdevpdfg.h"
  26. #include "scommon.h"
  27. /* GC descriptors */
  28. private_st_pdf_text_enum();
  29. /* Define the auxiliary procedures for text processing. */
  30. private int
  31. pdf_text_resync(gs_text_enum_t *pte, const gs_text_enum_t *pfrom)
  32. {
  33. pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
  34. if ((pte->text.operation ^ pfrom->text.operation) & ~TEXT_FROM_ANY)
  35. return_error(gs_error_rangecheck);
  36. if (penum->pte_default) {
  37. int code = gs_text_resync(penum->pte_default, pfrom);
  38. if (code < 0)
  39. return code;
  40. }
  41. pte->text = pfrom->text;
  42. gs_text_enum_copy_dynamic(pte, pfrom, false);
  43. return 0;
  44. }
  45. private bool
  46. pdf_text_is_width_only(const gs_text_enum_t *pte)
  47. {
  48. const pdf_text_enum_t *const penum = (const pdf_text_enum_t *)pte;
  49. if (penum->pte_default)
  50. return gs_text_is_width_only(penum->pte_default);
  51. return false;
  52. }
  53. private int
  54. pdf_text_current_width(const gs_text_enum_t *pte, gs_point *pwidth)
  55. {
  56. const pdf_text_enum_t *const penum = (const pdf_text_enum_t *)pte;
  57. if (penum->pte_default)
  58. return gs_text_current_width(penum->pte_default, pwidth);
  59. return_error(gs_error_rangecheck); /* can't happen */
  60. }
  61. private int
  62. pdf_text_set_cache(gs_text_enum_t *pte, const double *pw,
  63. gs_text_cache_control_t control)
  64. {
  65. pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
  66. if (penum->pte_default)
  67. return gs_text_set_cache(penum->pte_default, pw, control);
  68. return_error(gs_error_rangecheck); /* can't happen */
  69. }
  70. private int
  71. pdf_text_retry(gs_text_enum_t *pte)
  72. {
  73. pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
  74. if (penum->pte_default)
  75. return gs_text_retry(penum->pte_default);
  76. return_error(gs_error_rangecheck); /* can't happen */
  77. }
  78. private void
  79. pdf_text_release(gs_text_enum_t *pte, client_name_t cname)
  80. {
  81. pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
  82. if (penum->pte_default) {
  83. gs_text_release(penum->pte_default, cname);
  84. penum->pte_default = 0;
  85. }
  86. gx_default_text_release(pte, cname);
  87. }
  88. /* Begin processing text. */
  89. extern text_enum_proc_process(pdf_text_process); /* in gdevpdfs.c */
  90. private const gs_text_enum_procs_t pdf_text_procs = {
  91. pdf_text_resync, pdf_text_process,
  92. pdf_text_is_width_only, pdf_text_current_width,
  93. pdf_text_set_cache, pdf_text_retry,
  94. pdf_text_release
  95. };
  96. int
  97. gdev_pdf_text_begin(gx_device * dev, gs_imager_state * pis,
  98. const gs_text_params_t *text, gs_font * font,
  99. gx_path * path, const gx_device_color * pdcolor,
  100. const gx_clip_path * pcpath,
  101. gs_memory_t * mem, gs_text_enum_t ** ppte)
  102. {
  103. gx_device_pdf *const pdev = (gx_device_pdf *)dev;
  104. pdf_text_enum_t *penum;
  105. gs_fixed_point cpt;
  106. int code;
  107. /* Track the dominant text rotation. */
  108. {
  109. gs_matrix tmat;
  110. int i;
  111. gs_matrix_multiply(&font->FontMatrix, &ctm_only(pis), &tmat);
  112. if (is_xxyy(&tmat))
  113. i = (tmat.xx >= 0 ? 0 : 2);
  114. else if (is_xyyx(&tmat))
  115. i = (tmat.xy >= 0 ? 1 : 3);
  116. else
  117. i = 4;
  118. pdf_current_page(pdev)->text_rotation.counts[i] += text->size;
  119. }
  120. if (!(text->operation & TEXT_DO_DRAW) || path == 0 ||
  121. gx_path_current_point(path, &cpt) < 0
  122. )
  123. return gx_default_text_begin(dev, pis, text, font, path, pdcolor,
  124. pcpath, mem, ppte);
  125. code = pdf_prepare_fill(pdev, pis);
  126. if (code < 0)
  127. return code;
  128. if (text->operation & TEXT_DO_DRAW) {
  129. /*
  130. * Set the clipping path and drawing color. We set both the fill
  131. * and stroke color, because we don't know whether the fonts will be
  132. * filled or stroked, and we can't set a color while we are in text
  133. * mode. (This is a consequence of the implementation, not a
  134. * limitation of PDF.)
  135. */
  136. if (pdf_must_put_clip_path(pdev, pcpath)) {
  137. int code = pdf_open_page(pdev, PDF_IN_STREAM);
  138. if (code < 0)
  139. return code;
  140. pdf_put_clip_path(pdev, pcpath);
  141. }
  142. if ((code =
  143. pdf_set_drawing_color(pdev, pdcolor, &pdev->stroke_color,
  144. &psdf_set_stroke_color_commands)) < 0 ||
  145. (code =
  146. pdf_set_drawing_color(pdev, pdcolor, &pdev->fill_color,
  147. &psdf_set_fill_color_commands)) < 0
  148. )
  149. return code;
  150. }
  151. /* Allocate and initialize the enumerator. */
  152. rc_alloc_struct_1(penum, pdf_text_enum_t, &st_pdf_text_enum, mem,
  153. return_error(gs_error_VMerror), "gdev_pdf_text_begin");
  154. penum->rc.free = rc_free_text_enum;
  155. penum->pte_default = 0;
  156. code = gs_text_enum_init((gs_text_enum_t *)penum, &pdf_text_procs,
  157. dev, pis, text, font, path, pdcolor, pcpath, mem);
  158. if (code < 0) {
  159. gs_free_object(mem, penum, "gdev_pdf_text_begin");
  160. return code;
  161. }
  162. *ppte = (gs_text_enum_t *)penum;
  163. return 0;
  164. }
  165. /* ---------------- Text and font utilities ---------------- */
  166. /* Forward declarations */
  167. private int assign_char_code(P1(gx_device_pdf * pdev));
  168. /*
  169. * Set the current font and size, writing a Tf command if needed.
  170. */
  171. int
  172. pdf_set_font_and_size(gx_device_pdf * pdev, pdf_font_t * font, floatp size)
  173. {
  174. if (font != pdev->text.font || size != pdev->text.size) {
  175. int code = pdf_open_page(pdev, PDF_IN_TEXT);
  176. stream *s = pdev->strm;
  177. if (code < 0)
  178. return code;
  179. pprints1(s, "/%s ", font->rname);
  180. pprintg1(s, "%g Tf\n", size);
  181. pdev->text.font = font;
  182. pdev->text.size = size;
  183. }
  184. font->where_used |= pdev->used_mask;
  185. return 0;
  186. }
  187. /*
  188. * Set the text matrix for writing text.
  189. * The translation component of the matrix is the text origin.
  190. * If the non-translation components of the matrix differ from the
  191. * current ones, write a Tm command; if there is only a Y translation
  192. * and it matches the leading, set use_leading so the next text string
  193. * will be written with ' rather than Tj; otherwise, write either a TL
  194. * command or a Tj command using space pseudo-characters.
  195. */
  196. private int
  197. set_text_distance(gs_point *pdist, const gs_point *ppt, const gs_matrix *pmat)
  198. {
  199. double rounded;
  200. gs_distance_transform_inverse(pmat->tx - ppt->x, pmat->ty - ppt->y,
  201. pmat, pdist);
  202. /* If the distance is very close to integers, round it. */
  203. if (fabs(pdist->x - (rounded = floor(pdist->x + 0.5))) < 0.0005)
  204. pdist->x = rounded;
  205. if (fabs(pdist->y - (rounded = floor(pdist->y + 0.5))) < 0.0005)
  206. pdist->y = rounded;
  207. return 0;
  208. }
  209. int
  210. pdf_set_text_matrix(gx_device_pdf * pdev, const gs_matrix * pmat)
  211. {
  212. stream *s = pdev->strm;
  213. double sx = 72.0 / pdev->HWResolution[0],
  214. sy = 72.0 / pdev->HWResolution[1];
  215. int code;
  216. if (pmat->xx == pdev->text.matrix.xx &&
  217. pmat->xy == pdev->text.matrix.xy &&
  218. pmat->yx == pdev->text.matrix.yx &&
  219. pmat->yy == pdev->text.matrix.yy &&
  220. /*
  221. * If we aren't already in text context, BT will reset
  222. * the text matrix.
  223. */
  224. (pdev->context == PDF_IN_TEXT || pdev->context == PDF_IN_STRING)
  225. ) {
  226. /* Use leading, Td or a pseudo-character. */
  227. gs_point dist;
  228. set_text_distance(&dist, &pdev->text.current, pmat);
  229. if (dist.y == 0 && dist.x >= X_SPACE_MIN &&
  230. dist.x <= X_SPACE_MAX &&
  231. pdev->text.font != 0 &&
  232. PDF_FONT_IS_SYNTHESIZED(pdev->text.font)
  233. ) { /* Use a pseudo-character. */
  234. int dx = (int)dist.x;
  235. int dx_i = dx - X_SPACE_MIN;
  236. byte space_char = pdev->text.font->spaces[dx_i];
  237. if (space_char == 0) {
  238. if (pdev->text.font != pdev->open_font)
  239. goto not_spaces;
  240. code = assign_char_code(pdev);
  241. if (code <= 0)
  242. goto not_spaces;
  243. space_char = pdev->open_font->spaces[dx_i] = (byte)code;
  244. if (pdev->space_char_ids[dx_i] == 0) {
  245. /* Create the space char_proc now. */
  246. char spstr[3 + 14 + 1];
  247. stream *s;
  248. sprintf(spstr, "%d 0 0 0 0 0 d1\n", dx);
  249. pdev->space_char_ids[dx_i] = pdf_begin_separate(pdev);
  250. s = pdev->strm;
  251. pprintd1(s, "<</Length %d>>\nstream\n", strlen(spstr));
  252. pprints1(s, "%sendstream\n", spstr);
  253. pdf_end_separate(pdev);
  254. }
  255. }
  256. pdf_append_chars(pdev, &space_char, 1);
  257. pdev->text.current.x += dx * pmat->xx;
  258. pdev->text.current.y += dx * pmat->xy;
  259. /* Don't change use_leading -- it only affects Y placement. */
  260. return 0;
  261. }
  262. not_spaces:
  263. code = pdf_open_page(pdev, PDF_IN_TEXT);
  264. if (code < 0)
  265. return code;
  266. set_text_distance(&dist, &pdev->text.line_start, pmat);
  267. if (pdev->text.use_leading) {
  268. /* Leading was deferred: take it into account now. */
  269. dist.y -= pdev->text.leading;
  270. }
  271. if (dist.x == 0 && dist.y < 0) {
  272. /* Use TL, if needed, + '. */
  273. float dist_y = (float)-dist.y;
  274. if (fabs(pdev->text.leading - dist_y) > 0.0005) {
  275. pprintg1(s, "%g TL\n", dist_y);
  276. pdev->text.leading = dist_y;
  277. }
  278. pdev->text.use_leading = true;
  279. } else {
  280. /* Use Td. */
  281. pprintg2(s, "%g %g Td\n", dist.x, dist.y);
  282. pdev->text.use_leading = false;
  283. }
  284. } else { /* Use Tm. */
  285. code = pdf_open_page(pdev, PDF_IN_TEXT);
  286. if (code < 0)
  287. return code;
  288. /*
  289. * See stream_to_text in gdevpdf.c for why we need the following
  290. * matrix adjustments.
  291. */
  292. pprintg6(pdev->strm, "%g %g %g %g %g %g Tm\n",
  293. pmat->xx * sx, pmat->xy * sy,
  294. pmat->yx * sx, pmat->yy * sy,
  295. pmat->tx * sx, pmat->ty * sy);
  296. pdev->text.matrix = *pmat;
  297. pdev->text.use_leading = false;
  298. }
  299. pdev->text.line_start.x = pmat->tx;
  300. pdev->text.line_start.y = pmat->ty;
  301. pdev->text.current.x = pmat->tx;
  302. pdev->text.current.y = pmat->ty;
  303. return 0;
  304. }
  305. /*
  306. * Append characters to a string being accumulated.
  307. */
  308. int
  309. pdf_append_chars(gx_device_pdf * pdev, const byte * str, uint size)
  310. {
  311. const byte *p = str;
  312. uint left = size;
  313. while (left)
  314. if (pdev->text.buffer_count == max_text_buffer) {
  315. int code = pdf_open_page(pdev, PDF_IN_TEXT);
  316. if (code < 0)
  317. return code;
  318. } else {
  319. int code = pdf_open_page(pdev, PDF_IN_STRING);
  320. uint copy;
  321. if (code < 0)
  322. return code;
  323. copy = min(max_text_buffer - pdev->text.buffer_count, left);
  324. memcpy(pdev->text.buffer + pdev->text.buffer_count, p, copy);
  325. pdev->text.buffer_count += copy;
  326. p += copy;
  327. left -= copy;
  328. }
  329. return 0;
  330. }
  331. /* ---------------- Synthesized fonts ---------------- */
  332. /* Assign a code for a char_proc. */
  333. private int
  334. assign_char_code(gx_device_pdf * pdev)
  335. {
  336. pdf_font_t *font = pdev->open_font;
  337. int c;
  338. if (pdev->embedded_encoding_id == 0)
  339. pdev->embedded_encoding_id = pdf_obj_ref(pdev);
  340. if (font == 0 || font->num_chars == 256 || !pdev->use_open_font) {
  341. /* Start a new synthesized font. */
  342. int code = pdf_alloc_font(pdev, gs_no_id, &font, NULL, NULL);
  343. char *pc;
  344. if (code < 0)
  345. return code;
  346. if (pdev->open_font == 0)
  347. font->rname[0] = 0;
  348. else
  349. strcpy(font->rname, pdev->open_font->rname);
  350. for (pc = font->rname; *pc == 'Z'; ++pc)
  351. *pc = '@';
  352. if ((*pc)++ == 0)
  353. *pc = 'A', pc[1] = 0;
  354. pdev->open_font = font;
  355. pdev->use_open_font = true;
  356. }
  357. c = font->num_chars++;
  358. if (c > pdev->max_embedded_code)
  359. pdev->max_embedded_code = c;
  360. return c;
  361. }
  362. /* Begin a CharProc for a synthesized (bitmap) font. */
  363. int
  364. pdf_begin_char_proc(gx_device_pdf * pdev, int w, int h, int x_width,
  365. int y_offset, gs_id id, pdf_char_proc_t ** ppcp, pdf_stream_position_t * ppos)
  366. {
  367. pdf_resource_t *pres;
  368. pdf_char_proc_t *pcp;
  369. int char_code = assign_char_code(pdev);
  370. pdf_font_t *font = pdev->open_font;
  371. int code;
  372. if (char_code < 0)
  373. return char_code;
  374. code = pdf_begin_resource(pdev, resourceCharProc, id, &pres);
  375. if (code < 0)
  376. return code;
  377. pcp = (pdf_char_proc_t *) pres;
  378. pcp->font = font;
  379. pcp->char_next = font->char_procs;
  380. font->char_procs = pcp;
  381. pcp->char_code = char_code;
  382. pcp->width = w;
  383. pcp->height = h;
  384. pcp->x_width = x_width;
  385. pcp->y_offset = y_offset;
  386. font->max_y_offset = max(font->max_y_offset, h + (h >> 2));
  387. *ppcp = pcp;
  388. {
  389. stream *s = pdev->strm;
  390. /*
  391. * The resource file is positionable, so rather than use an
  392. * object reference for the length, we'll go back and fill it in
  393. * at the end of the definition. Take 1M as the longest
  394. * definition we can handle. (This used to be 10K, but there was
  395. * a real file that exceeded this limit.)
  396. */
  397. stream_puts(s, "<</Length >>stream\n");
  398. ppos->start_pos = stell(s);
  399. }
  400. return 0;
  401. }
  402. /* End a CharProc. */
  403. int
  404. pdf_end_char_proc(gx_device_pdf * pdev, pdf_stream_position_t * ppos)
  405. {
  406. stream *s = pdev->strm;
  407. long start_pos = ppos->start_pos;
  408. long end_pos = stell(s);
  409. long length = end_pos - start_pos;
  410. if (length > 999999)
  411. return_error(gs_error_limitcheck);
  412. sseek(s, start_pos - 15);
  413. pprintd1(s, "%d", length);
  414. sseek(s, end_pos);
  415. stream_puts(s, "endstream\n");
  416. pdf_end_separate(pdev);
  417. return 0;
  418. }
  419. /* Put out a reference to an image as a character in a synthesized font. */
  420. int
  421. pdf_do_char_image(gx_device_pdf * pdev, const pdf_char_proc_t * pcp,
  422. const gs_matrix * pimat)
  423. {
  424. pdf_set_font_and_size(pdev, pcp->font, 1.0);
  425. {
  426. gs_matrix tmat;
  427. tmat = *pimat;
  428. tmat.ty -= pcp->y_offset;
  429. pdf_set_text_matrix(pdev, &tmat);
  430. }
  431. pdf_append_chars(pdev, &pcp->char_code, 1);
  432. pdev->text.current.x += pcp->x_width * pdev->text.matrix.xx;
  433. return 0;
  434. }