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