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