OSDN Git Service

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