Back to index

texmacs  1.0.7.15
pdfdev.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/pdfdev.c,v 1.71 2009/03/16 22:26:40 matthias Exp $
00002     
00003     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
00004 
00005     Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
00006     the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
00007     
00008     Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014     
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU General Public License for more details.
00019     
00020     You should have received a copy of the GNU General Public License
00021     along with this program; if not, write to the Free Software
00022     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00023 */
00024 
00025 #if HAVE_CONFIG_H
00026 #include "config.h"
00027 #endif
00028 
00029 #include <string.h>
00030 #include <ctype.h>
00031 #include <math.h>
00032 
00033 #include "system.h"
00034 #include "mem.h"
00035 #include "error.h"
00036 
00037 #include "mfileio.h"
00038 #include "numbers.h"
00039 
00040 #include "pdfdoc.h"
00041 #include "pdfobj.h"
00042 
00043 #include "pdffont.h"
00044 #include "fontmap.h"
00045 #include "cmap.h"
00046 #include "pdfximage.h"
00047 
00048 #include "pdfdraw.h"
00049 #include "pdfcolor.h"
00050 
00051 #include "pdflimits.h"
00052 
00053 #include "pdfdev.h"
00054 
00055 static int verbose = 0;
00056 
00057 void
00058 pdf_dev_set_verbose (void)
00059 {
00060   verbose++;
00061 }
00062 
00063 /* Not working yet... */
00064 double
00065 pdf_dev_scale (void)
00066 {
00067   return 1.0;
00068 }
00069 
00070 /*
00071  * Unit conversion, formatting and others.
00072  */
00073 
00074 #define TEX_ONE_HUNDRED_BP 6578176
00075 static struct {
00076   double dvi2pts;
00077   long   min_bp_val; /* Shortest resolvable distance in the output PDF.     */
00078   int    precision;  /* Number of decimal digits (in fractional part) kept. */
00079 } dev_unit = {
00080   0.0,
00081   658,
00082   2
00083 };
00084 
00085 
00086 double
00087 dev_unit_dviunit (void)
00088 {
00089   return (1.0/dev_unit.dvi2pts);
00090 }
00091 
00092 #define DEV_PRECISION_MAX  8
00093 static unsigned long ten_pow[10] = {
00094   1ul, 10ul, 100ul, 1000ul, 10000ul, 100000ul, 1000000ul, 10000000ul, 100000000ul, 1000000000ul
00095 };
00096 
00097 static double ten_pow_inv[10] = {
00098   1.0, 0.1,  0.01,  0.001,  0.0001,  0.00001,  0.000001,  0.0000001,  0.00000001,  0.000000001
00099 };
00100 
00101 #define bpt2spt(b) ( (spt_t) round( (b) / dev_unit.dvi2pts  ) )
00102 #define spt2bpt(s) ( (s) * dev_unit.dvi2pts )
00103 #define dround_at(v,p) (ROUND( (v), ten_pow_inv[(p)] ))
00104 
00105 static int
00106 p_itoa (long value, char *buf)
00107 {
00108   int   sign, ndigits;
00109   char *p = buf;
00110 
00111   if (value < 0) {
00112     *p++  = '-';
00113     value = -value;
00114     sign  = 1;
00115   } else {
00116     sign  = 0;
00117   }
00118 
00119   ndigits = 0;
00120   /* Generate at least one digit in reverse order */
00121   do {
00122     p[ndigits++] = (value % 10) + '0';
00123     value /= 10;
00124   } while (value != 0);
00125 
00126   /* Reverse the digits */
00127   {
00128     int i;
00129 
00130     for (i = 0; i < ndigits / 2 ; i++) {
00131       char tmp = p[i];
00132       p[i] = p[ndigits-i-1];
00133       p[ndigits-i-1] = tmp;
00134     }
00135   }
00136   p[ndigits] = '\0';
00137 
00138   return  (sign ? ndigits + 1 : ndigits);
00139 }
00140 
00141 /* ... */
00142 static int
00143 p_dtoa (double value, int prec, char *buf)
00144 {
00145   const long p[10] = { 1, 10, 100, 1000, 10000,
00146                      100000, 1000000, 10000000, 100000000, 1000000000 };
00147   long i, f;
00148   char *c = buf;
00149   int n;
00150 
00151   if (value < 0) {
00152     value = -value;
00153     *c++ = '-';
00154     n = 1;
00155   } else
00156     n = 0;
00157 
00158   i = (long) value;
00159   f = (long) ((value-i)*p[prec] + 0.5);
00160 
00161   if (f == p[prec]) {
00162     f = 0;
00163     i++;
00164   }
00165 
00166   if (i) {
00167     int m = p_itoa(i, c);
00168     c += m;
00169     n += m;
00170   } else if (!f) {
00171     *(c = buf) = '0';
00172     n = 1;
00173   }
00174 
00175   if (f) {
00176     int j = prec;
00177 
00178     *c++ = '.';
00179 
00180     while (j--) {
00181       c[j] = (f % 10) + '0';
00182       f /= 10;
00183     }
00184     c += prec-1;
00185     n += 1+prec;
00186 
00187     while (*c == '0') {
00188       c--;
00189       n--;
00190     }
00191   }
00192 
00193   *(++c) = 0;
00194 
00195   return n;
00196 }
00197 
00198 static int
00199 dev_sprint_bp (char *buf, spt_t value, spt_t *error)
00200 {
00201   double  value_in_bp;
00202   double  error_in_bp;
00203   int     prec = dev_unit.precision;
00204 
00205   value_in_bp = spt2bpt(value);
00206   if (error) {
00207     error_in_bp = value_in_bp - dround_at(value_in_bp, prec);
00208     *error = bpt2spt(error_in_bp);
00209   }
00210 
00211   return  p_dtoa(value_in_bp, prec, buf);
00212 }
00213 
00214 /* They are affected by precision (set at device initialization). */
00215 int
00216 pdf_sprint_matrix (char *buf, const pdf_tmatrix *M)
00217 {
00218   int  len;
00219   int  prec2 = MIN(dev_unit.precision + 2, DEV_PRECISION_MAX);
00220   int  prec0 = MAX(dev_unit.precision, 2);
00221 
00222   len  = p_dtoa(M->a, prec2, buf);
00223   buf[len++] = ' ';
00224   len += p_dtoa(M->b, prec2, buf+len);
00225   buf[len++] = ' ';
00226   len += p_dtoa(M->c, prec2, buf+len);
00227   buf[len++] = ' ';
00228   len += p_dtoa(M->d, prec2, buf+len);
00229   buf[len++] = ' ';
00230   len += p_dtoa(M->e, prec0, buf+len);
00231   buf[len++] = ' ';
00232   len += p_dtoa(M->f, prec0, buf+len);
00233   buf[len]   = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
00234 
00235   return  len;
00236 }
00237 
00238 int
00239 pdf_sprint_rect (char *buf, const pdf_rect *rect)
00240 {
00241   int  len;
00242 
00243   len  = p_dtoa(rect->llx, dev_unit.precision, buf);
00244   buf[len++] = ' ';
00245   len += p_dtoa(rect->lly, dev_unit.precision, buf+len);
00246   buf[len++] = ' ';
00247   len += p_dtoa(rect->urx, dev_unit.precision, buf+len);
00248   buf[len++] = ' ';
00249   len += p_dtoa(rect->ury, dev_unit.precision, buf+len);
00250   buf[len]   = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
00251 
00252   return  len;
00253 }
00254 
00255 int
00256 pdf_sprint_coord (char *buf, const pdf_coord *p)
00257 {
00258   int  len;
00259 
00260   len  = p_dtoa(p->x, dev_unit.precision, buf);
00261   buf[len++] = ' ';
00262   len += p_dtoa(p->y, dev_unit.precision, buf+len);
00263   buf[len]   = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
00264 
00265   return  len;
00266 }
00267 
00268 int
00269 pdf_sprint_length (char *buf, double value)
00270 {
00271   int  len;
00272 
00273   len = p_dtoa(value, dev_unit.precision, buf);
00274   buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
00275 
00276   return  len;
00277 }
00278 
00279 
00280 int
00281 pdf_sprint_number (char *buf, double value)
00282 {
00283   int  len;
00284 
00285   len = p_dtoa(value, DEV_PRECISION_MAX, buf);
00286   buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
00287 
00288   return  len;
00289 }
00290 
00291 
00292 static struct
00293 {
00294   /* Text composition (direction) mode is ignored (always same
00295    * as font's writing mode) if autorotate is unset (value zero).
00296    */
00297   int    autorotate;
00298 
00299   /*
00300    * Ignore color migrated to here. This is device's capacity.
00301    * colormode 0 for ignore colors
00302    */
00303   int    colormode;
00304 
00305 } dev_param = {
00306   1, /* autorotate */
00307   1, /* colormode  */
00308 };
00309 
00310 /*
00311  * Text handling routines.
00312  */
00313 
00314 /* Motion state:
00315  *  GRAPHICS_MODE  Initial state (not within BT/ET block nor in string)
00316  *  TEXT_MODE      Text section is started via BT operator but not
00317  *                 in string.
00318  *  STRING_MODE    In string. A string or array of strings are currently
00319  *                 in process. May started '[', '<' or '('.
00320  */
00321 #define GRAPHICS_MODE  1
00322 #define TEXT_MODE      2
00323 #define STRING_MODE    3
00324 
00325 static int motion_state = GRAPHICS_MODE;
00326 
00327 #define FORMAT_BUF_SIZE 4096
00328 static char format_buffer[FORMAT_BUF_SIZE];
00329 
00330 /*
00331  * In PDF, vertical text positioning is always applied when current font
00332  * is vertical font. While ASCII pTeX manages current writing direction
00333  * and font's WMode separately.
00334  *
00335  * 00/11 WMODE_HH/VV  h(v) font, h(v) direction.
00336  * 01    WMODE_HV    -90 deg. rotated
00337  * 10    WMODE_VH    +90 deg. rotated
00338  *
00339  * In MetaPost PostScript file processing (mp_mode = 1), only HH/VV mode
00340  * is applied.
00341  */
00342 #define TEXT_WMODE_HH 0
00343 #define TEXT_WMODE_HV 1
00344 #define TEXT_WMODE_VH 2
00345 #define TEXT_WMODE_VV 3
00346 
00347 #define ANGLE_CHANGES(m1,m2) ((abs((m1)-(m2)) % 3) == 0 ? 0 : 1)
00348 #define ROTATE_TEXT(m)       ((m) != TEXT_WMODE_HH && (m) != TEXT_WMODE_VV)
00349 
00350 static struct {
00351 
00352   /* Current font.
00353    * This is index within dev_fonts.
00354    */
00355   int       font_id;
00356 
00357   /* Dvipdfmx does compression of text by doing text positioning
00358    * in relative motion and uses string array [(foo) -250 (bar)]
00359    * with kerning (negative kern is used for white space as suited
00360    * for TeX). This is offset within current string.
00361    */
00362   spt_t     offset;
00363 
00364   /* This is reference point of strings.
00365    * It may include error correction induced by rounding.
00366    */
00367   spt_t     ref_x;
00368   spt_t     ref_y;
00369 
00370   /* Using text raise and leading is highly recommended for
00371    * text extraction to work properly. But not implemented yet.
00372    * We can't do consice output for \TeX without this.
00373    */
00374   spt_t     raise;    /* unused */
00375   spt_t     leading;  /* unused */
00376 
00377   /* This is not always text matrix but rather font matrix.
00378    * We do not use horizontal scaling in PDF text state parameter
00379    * since they always apply scaling in fixed direction regardless
00380    * of writing mode.
00381    */
00382   struct {
00383     double  slant;
00384     double  extend;
00385     int     rotate; /* TEXT_WMODE_XX */
00386   } matrix;
00387 
00388   /* Fake bold parameter:
00389    * If bold_param is positive, use text rendering mode
00390    * fill-then-stroke with stroking line width specified
00391    * by bold_param.
00392    */
00393   double    bold_param;
00394 
00395   /* Text composition (direction) mode. */
00396   int       dir_mode;
00397 
00398   /* internal */
00399 
00400   /* Flag indicating text matrix to be forcibly reset.
00401    * Enabled if synthetic font features (slant, extend, etc)
00402    * are used for current font or when text rotation mode
00403    * changes.
00404    */
00405   int       force_reset;
00406 
00407   /* This information is duplicated from dev[font_id].format.
00408    * Set to 1 if font is composite (Type0) font.
00409    */
00410   int       is_mb;
00411 } text_state = {
00412   -1,            /* font   */
00413   0,             /* offset */
00414   0, 0,          /* ref_x, ref_y   */
00415   0, 0,          /* raise, leading */
00416   {0.0, 1.0, 0},
00417 
00418   0.0,  /* Experimental boldness param */
00419 
00420   0,    /* dir_mode      */
00421 
00422   /* internal */
00423   0,    /* force_reset   */
00424   0     /* is_mb         */
00425 };
00426 
00427 #define PDF_FONTTYPE_SIMPLE    1
00428 #define PDF_FONTTYPE_BITMAP    2
00429 #define PDF_FONTTYPE_COMPOSITE 3
00430 
00431 struct dev_font {
00432   /* Needs to be big enough to hold name "Fxxx"
00433    * where xxx is number of largest font
00434    */
00435   char     short_name[7];      /* Resource name */
00436   int      used_on_this_page;
00437 
00438   char    *tex_name;  /* String identifier of this font */
00439   spt_t    sptsize;   /* Point size */
00440 
00441   /* Returned values from font/encoding layer:
00442    *
00443    * The font_id and enc_id is font and encoding (CMap) identifier
00444    * used in pdf_font or encoding/cmap layer.
00445    * The PDF object "resource" is an indirect reference object
00446    * pointing font resource of this font. The used_chars is somewhat
00447    * misleading, this is actually used_glyphs in CIDFont for Type0
00448    * and is 65536/8 bytes binary data with each bits representing
00449    * whether the glyph is in-use or not. It is 256 char array for
00450    * simple font.
00451    */
00452   int      font_id;
00453   int      enc_id;
00454 
00455   pdf_obj *resource;
00456   char    *used_chars;
00457 
00458   /* Font format:
00459    * simple, composite or bitmap.
00460    */
00461   int      format;
00462 
00463   /* Writing mode:
00464    * Non-zero for vertical. Duplicated from CMap.
00465    */
00466   int      wmode;
00467 
00468   /* Syntetic Font:
00469    *
00470    * We use text matrix for creating extended or slanted font,
00471    * but not with font's FontMatrix since TrueType and Type0
00472    * font don't support them.
00473    */
00474   double   extend;
00475   double   slant;
00476   double   bold;  /* Boldness prameter */
00477 
00478   /* Compatibility */
00479   int      mapc;  /* Nasty workaround for Omega */
00480 
00481   /* There are no font metric format supporting four-bytes
00482    * charcter code. So we should provide an option to specify
00483    * UCS group and plane.
00484    */
00485   int      ucs_group;
00486   int      ucs_plane;
00487 
00488   int      is_unicode;
00489   
00490   int   tfm_id;
00491 };
00492 static struct dev_font *dev_fonts = NULL;
00493 
00494 static int num_dev_fonts   = 0;
00495 static int max_dev_fonts   = 0;
00496 static int num_phys_fonts  = 0;
00497 
00498 #define CURRENTFONT() ((text_state.font_id < 0) ? NULL : &(dev_fonts[text_state.font_id]))
00499 #define GET_FONT(n)   (&(dev_fonts[(n)]))
00500 
00501 
00502 static void
00503 dev_set_text_matrix (spt_t xpos, spt_t ypos, double slant, double extend, int rotate)
00504 {
00505   pdf_tmatrix tm;
00506   int         len = 0;
00507 
00508   /* slant is negated for vertical font so that right-side
00509    * is always lower. */
00510   switch (rotate) {
00511   case TEXT_WMODE_VH:
00512     /* Vertical font */
00513     tm.a =  slant ;   tm.b =  1.0;
00514     tm.c = -extend;   tm.d =  0.0   ;
00515     break;
00516   case TEXT_WMODE_HV:
00517     /* Horizontal font */
00518     tm.a =  0.0;    tm.b = -extend;
00519     tm.c =  1.0;    tm.d = -slant ;
00520     break;
00521   case TEXT_WMODE_HH:
00522     /* Horizontal font */
00523     tm.a =  extend; tm.b =  0.0;
00524     tm.c =  slant ; tm.d =  1.0;
00525     break;
00526   case TEXT_WMODE_VV:
00527     /* Vertical font */
00528     tm.a =  1.0; tm.b =  -slant;
00529     tm.c =  0.0; tm.d =   extend;
00530     break;
00531   }
00532   tm.e = xpos * dev_unit.dvi2pts;
00533   tm.f = ypos * dev_unit.dvi2pts;
00534 
00535   format_buffer[len++] = ' ';
00536   len += pdf_sprint_matrix(format_buffer+len, &tm);
00537   format_buffer[len++] = ' ';
00538   format_buffer[len++] = 'T';
00539   format_buffer[len++] = 'm';
00540 
00541   pdf_doc_add_page_content(format_buffer, len);  /* op: Tm */
00542 
00543   text_state.ref_x = xpos;
00544   text_state.ref_y = ypos;
00545   text_state.matrix.slant  = slant;
00546   text_state.matrix.extend = extend;
00547   text_state.matrix.rotate = rotate;
00548 }
00549 
00550 /*
00551  * reset_text_state() outputs a BT and does any necessary coordinate
00552  * transformations to get ready to ship out text.
00553  */
00554 
00555 static void
00556 reset_text_state (void)
00557 {
00558   /*
00559    * We need to reset the line matrix to handle slanted fonts.
00560    */
00561   pdf_doc_add_page_content(" BT", 3);  /* op: BT */
00562   /*
00563    * text_state.matrix is identity at top of page.
00564    * This sometimes write unnecessary "Tm"s when transition from
00565    * GRAPHICS_MODE to TEXT_MODE occurs.
00566    */
00567   if (text_state.force_reset ||
00568       text_state.matrix.slant  != 0.0 ||
00569       text_state.matrix.extend != 1.0 ||
00570       ROTATE_TEXT(text_state.matrix.rotate)) {
00571     dev_set_text_matrix(0, 0,
00572                         text_state.matrix.slant,
00573                         text_state.matrix.extend,
00574                         text_state.matrix.rotate);
00575   }
00576   text_state.ref_x = 0;
00577   text_state.ref_y = 0;
00578   text_state.offset   = 0;
00579   text_state.force_reset = 0;
00580 }
00581 
00582 static void
00583 text_mode (void)
00584 {
00585   switch (motion_state) {
00586   case TEXT_MODE:
00587     break;
00588   case STRING_MODE:
00589     pdf_doc_add_page_content(text_state.is_mb ? ">]TJ" : ")]TJ", 4);  /* op: TJ */
00590     break;
00591   case GRAPHICS_MODE:
00592     reset_text_state();
00593     break;
00594   }
00595   motion_state      = TEXT_MODE;
00596   text_state.offset = 0;
00597 }
00598 
00599 void
00600 graphics_mode (void)
00601 {
00602   switch (motion_state) {
00603   case GRAPHICS_MODE:
00604     break;
00605   case STRING_MODE:
00606     pdf_doc_add_page_content(text_state.is_mb ? ">]TJ" : ")]TJ", 4);  /* op: TJ */
00607     /* continue */
00608   case TEXT_MODE:
00609     pdf_doc_add_page_content(" ET", 3);  /* op: ET */
00610     text_state.force_reset =  0;
00611     text_state.font_id     = -1;
00612     break;
00613   }
00614   motion_state = GRAPHICS_MODE;
00615 }
00616 
00617 static void
00618 start_string (spt_t xpos, spt_t ypos, double slant, double extend, int rotate)
00619 {
00620   spt_t delx, dely, error_delx, error_dely;
00621   spt_t desired_delx, desired_dely;
00622   int   len = 0;
00623 
00624   delx = xpos - text_state.ref_x;
00625   dely = ypos - text_state.ref_y;
00626   /*
00627    * Precompensating for line transformation matrix.
00628    *
00629    * Line transformation matrix L for horizontal font in horizontal
00630    * mode and it's inverse I is
00631    *
00632    *          | e  0|          | 1/e  0|
00633    *   L_hh = |     | , I_hh = |       |
00634    *          | s  1|          |-s/e  1|
00635    *
00636    * For vertical font in vertical mode,
00637    *
00638    *          | 1  -s|          | 1  s/e|
00639    *   L_vv = |      | , I_vv = |       |
00640    *          | 0   e|          | 0  1/e|
00641    *
00642    * For vertical font in horizontal mode,
00643    *
00644    *          | s   1|          | 0  1|
00645    *   L_vh = |      | = L_vv x |     |
00646    *          |-e   0|          |-1  0|
00647    *
00648    *          | 0  -1|
00649    *   I_vh = |      | x I_vv
00650    *          | 1   0|
00651    *
00652    * For horizontal font in vertical mode,
00653    *
00654    *          | 0  -e|          | 0  -1|
00655    *   L_hv = |      | = L_hh x |      |
00656    *          | 1  -s|          | 1   0|
00657    *
00658    *          | 0   1|
00659    *   I_hv = |      | x I_hh
00660    *          |-1   0|
00661    *
00662    */
00663   switch (rotate) {
00664   case TEXT_WMODE_VH:
00665     /* Vertical font in horizontal mode: rot = +90
00666      *                           | 0  -1/e|
00667      * d_user =  d x I_vh = d x  |        |
00668      *                           | 1   s/e|
00669      */
00670     desired_delx = dely;
00671     desired_dely = (spt_t) (-(delx - dely*slant)/extend);
00672 
00673     /* error_del is in device space
00674      *
00675      *               | 0  1|
00676      *  e = e_user x |     | = (-e_user_y, e_user_x)
00677      *               |-1  0|
00678      *
00679      * We must care about rotation here but not extend/slant...
00680      * The extend and slant actually is font matrix.
00681      */
00682     format_buffer[len++] = ' ';
00683     len += dev_sprint_bp(format_buffer+len, desired_delx, &error_dely);
00684     format_buffer[len++] = ' ';
00685     len += dev_sprint_bp(format_buffer+len, desired_dely, &error_delx);
00686     error_delx = -error_delx;
00687     break;
00688   case TEXT_WMODE_HV:
00689     /* Horizontal font in vertical mode: rot = -90
00690      *
00691      *                         |-s/e  1|
00692      * d_user = d x I_hv = d x |       |
00693      *                         |-1/e  0|
00694      */
00695     desired_delx = (spt_t)(-(dely + delx*slant)/extend);
00696     desired_dely = delx;
00697 
00698     /*
00699      * e = (e_user_y, -e_user_x)
00700      */
00701     format_buffer[len++] = ' ';
00702     len += dev_sprint_bp(format_buffer+len, desired_delx, &error_dely);
00703     format_buffer[len++] = ' ';
00704     len += dev_sprint_bp(format_buffer+len, desired_dely, &error_delx);
00705     error_dely = -error_dely;
00706     break;
00707   case TEXT_WMODE_HH:
00708     /* Horizontal font in horizontal mode:
00709      *                         | 1/e    0|
00710      * d_user = d x I_hh = d x |         |
00711      *                         |-s/e    1|
00712      */
00713     desired_delx = (spt_t)((delx - dely*slant)/extend);
00714     desired_dely = dely;
00715 
00716     format_buffer[len++] = ' ';
00717     len += dev_sprint_bp(format_buffer+len, desired_delx, &error_delx);
00718     format_buffer[len++] = ' ';
00719     len += dev_sprint_bp(format_buffer+len, desired_dely, &error_dely);
00720     break;
00721   case TEXT_WMODE_VV:
00722     /* Vertical font in vertical mode:
00723      *                         | 1  s/e|
00724      * d_user = d x I_vv = d x |       |
00725      *                         | 0  1/e|
00726      */
00727     desired_delx = delx;
00728     desired_dely = (spt_t)((dely + delx*slant)/extend);
00729 
00730     format_buffer[len++] = ' ';
00731     len += dev_sprint_bp(format_buffer+len, desired_delx, &error_delx);
00732     format_buffer[len++] = ' ';
00733     len += dev_sprint_bp(format_buffer+len, desired_dely, &error_dely);
00734     break;
00735   }
00736   pdf_doc_add_page_content(format_buffer, len);  /* op: */
00737   /*
00738    * dvipdfm wrongly using "TD" in place of "Td".
00739    * The TD operator set leading, but we are not using T* etc.
00740    */
00741   pdf_doc_add_page_content(text_state.is_mb ? " Td[<" : " Td[(", 5);  /* op: Td */
00742 
00743   /* Error correction */
00744   text_state.ref_x = xpos - error_delx;
00745   text_state.ref_y = ypos - error_dely;
00746 
00747   text_state.offset   = 0;
00748 }
00749 
00750 static void
00751 string_mode (spt_t xpos, spt_t ypos, double slant, double extend, int rotate)
00752 {
00753   switch (motion_state) {
00754   case STRING_MODE:
00755     break;
00756   case GRAPHICS_MODE:
00757     reset_text_state();
00758     /* continue */
00759   case TEXT_MODE:
00760     if (text_state.force_reset) {
00761       dev_set_text_matrix(xpos, ypos, slant, extend, rotate);
00762       pdf_doc_add_page_content(text_state.is_mb ? "[<" : "[(", 2);  /* op: */
00763       text_state.force_reset = 0;
00764     } else {
00765       start_string(xpos, ypos, slant, extend, rotate);
00766     }
00767     break;
00768   }
00769   motion_state = STRING_MODE;
00770 }
00771 
00772 /*
00773  * The purpose of the following routine is to force a Tf only
00774  * when it's actually necessary.  This became a problem when the
00775  * VF code was added.  The VF spec says to instantiate the
00776  * first font contained in the VF file before drawing a virtual
00777  * character.  However, that font may not be used for
00778  * many characters (e.g. small caps fonts).  For this reason, 
00779  * dev_select_font() should not force a "physical" font selection.
00780  * This routine prevents a PDF Tf font selection until there's
00781  * really a character in that font.
00782  */
00783 
00784 static int
00785 dev_set_font (int font_id)
00786 {
00787   struct dev_font *font;
00788   int    text_rotate;
00789   double font_scale;
00790   int    len;
00791   int    vert_dir, vert_font;
00792 
00793   /* text_mode() must come before text_state.is_mb is changed. */
00794   text_mode();
00795 
00796   font = GET_FONT(font_id);
00797   ASSERT(font); /* Caller should check font_id. */
00798 
00799   text_state.is_mb = (font->format == PDF_FONTTYPE_COMPOSITE) ? 1 : 0;
00800 
00801   vert_font  = font->wmode ? 1 : 0;
00802   if (dev_param.autorotate) {
00803     vert_dir = text_state.dir_mode ? 1 : 0;
00804   } else {
00805     vert_dir = vert_font;
00806   }
00807   text_rotate = (vert_font << 1)|vert_dir;
00808 
00809   if (font->slant  != text_state.matrix.slant  ||
00810       font->extend != text_state.matrix.extend ||
00811       ANGLE_CHANGES(text_rotate, text_state.matrix.rotate)) {
00812     text_state.force_reset = 1;
00813   }
00814   text_state.matrix.slant  = font->slant;
00815   text_state.matrix.extend = font->extend;
00816   text_state.matrix.rotate = text_rotate;
00817 
00818   if (!font->resource) {
00819     font->resource   = pdf_get_font_reference(font->font_id);
00820     font->used_chars = pdf_get_font_usedchars(font->font_id);
00821   }
00822 
00823   if (!font->used_on_this_page) { 
00824     pdf_doc_add_page_resource("Font",
00825                               font->short_name,
00826                               pdf_link_obj(font->resource));
00827     font->used_on_this_page = 1;
00828   }
00829 
00830   font_scale = (double) font->sptsize * dev_unit.dvi2pts;
00831   len  = sprintf(format_buffer, " /%s", font->short_name); /* space not necessary. */
00832   format_buffer[len++] = ' ';
00833   len += p_dtoa(font_scale, MIN(dev_unit.precision+1, DEV_PRECISION_MAX), format_buffer+len);
00834   format_buffer[len++] = ' ';
00835   format_buffer[len++] = 'T';
00836   format_buffer[len++] = 'f';
00837   pdf_doc_add_page_content(format_buffer, len);  /* op: Tf */
00838 
00839   if (font->bold > 0.0 || font->bold != text_state.bold_param) {
00840     if (font->bold <= 0.0)
00841       len = sprintf(format_buffer, " 0 Tr");
00842     else
00843       len = sprintf(format_buffer, " 2 Tr %.2f w", font->bold); /* _FIXME_ */
00844     pdf_doc_add_page_content(format_buffer, len);  /* op: Tr w */
00845   }
00846   text_state.bold_param = font->bold;
00847 
00848   text_state.font_id    = font_id;
00849 
00850   return  0;
00851 }
00852 
00853 
00854 /* Access text state parameters.
00855  */
00856 #if 0
00857 int
00858 pdf_dev_currentfont (void)
00859 {
00860   return text_state.font_id;
00861 }
00862 
00863 double
00864 pdf_dev_get_font_ptsize (int font_id)
00865 {
00866   struct dev_font *font;
00867 
00868   font = GET_FONT(font_id);
00869   if (font) {
00870     return font->sptsize * dev_unit.dvi2pts;
00871   }
00872 
00873   return 1.0;
00874 }
00875 #endif
00876 
00877 int
00878 pdf_dev_get_font_wmode (int font_id)
00879 {
00880   struct dev_font *font;
00881 
00882   font = GET_FONT(font_id);
00883   if (font) {
00884     return font->wmode;
00885   }
00886 
00887   return 0;
00888 }
00889 
00890 static unsigned char sbuf0[FORMAT_BUF_SIZE];
00891 static unsigned char sbuf1[FORMAT_BUF_SIZE];
00892 
00893 static int
00894 handle_multibyte_string (struct dev_font *font,
00895                          unsigned char **str_ptr, int *str_len, int ctype)
00896 {
00897   unsigned char *p;
00898   int            i, length;
00899 
00900   p      = *str_ptr;
00901   length = *str_len;
00902 
00903   /* _FIXME_ */
00904   if (font->is_unicode) { /* UCS-4 */
00905     if (ctype == 1) {
00906       if (length * 4 >= FORMAT_BUF_SIZE) {
00907         WARN("Too long string...");
00908         return -1;
00909       }
00910       for (i = 0; i < length; i++) {
00911         sbuf1[i*4  ] = font->ucs_group;
00912         sbuf1[i*4+1] = font->ucs_plane;
00913         sbuf1[i*4+2] = '\0';
00914         sbuf1[i*4+3] = p[i];
00915       }
00916       length *= 4;
00917     } else if (ctype == 2) {
00918       if (length * 2 >= FORMAT_BUF_SIZE) {
00919         WARN("Too long string...");
00920         return -1;
00921       }
00922       for (i = 0; i < length; i += 2) {
00923         sbuf1[i*2  ] = font->ucs_group;
00924         sbuf1[i*2+1] = font->ucs_plane;
00925         sbuf1[i*2+2] = p[i];
00926         sbuf1[i*2+3] = p[i+1];
00927       }
00928       length *= 2;
00929     }
00930     p = sbuf1;
00931   } else if (ctype == 1 && font->mapc >= 0) {
00932     /* Omega workaround...
00933      * Translate single-byte chars to double byte code space.
00934      */
00935     if (length * 2 >= FORMAT_BUF_SIZE) {
00936       WARN("Too long string...");
00937       return -1;
00938     }
00939     for (i = 0; i < length; i++) {
00940       sbuf1[i*2  ] = (font->mapc & 0xff);
00941       sbuf1[i*2+1] = p[i];
00942     }
00943     length *= 2;
00944     p       = sbuf1;
00945   }
00946 
00947   /*
00948    * Font is double-byte font. Output is assumed to be 16-bit fixed length
00949    * encoding.
00950    * TODO: A character decomposed to multiple characters.
00951    */
00952   if (font->enc_id >= 0) {
00953     unsigned char *inbuf, *outbuf;
00954     long           inbytesleft, outbytesleft;
00955     CMap          *cmap;
00956 
00957     cmap         = CMap_cache_get(font->enc_id);
00958     inbuf        = p;
00959     outbuf       = sbuf0;
00960     inbytesleft  = length;
00961     outbytesleft = FORMAT_BUF_SIZE;
00962 
00963     CMap_decode(cmap,
00964                 (const unsigned char **) &inbuf, &inbytesleft, &outbuf, &outbytesleft);
00965     if (inbytesleft != 0) {
00966       WARN("CMap conversion failed. (%d bytes remains)", inbytesleft);
00967       return -1;
00968     }
00969     length  = FORMAT_BUF_SIZE - outbytesleft;
00970     p       = sbuf0;
00971   }
00972 
00973   *str_ptr = p;
00974   *str_len = length;
00975   return 0;
00976 }
00977 
00978 
00979 static pdf_coord *dev_coords = NULL;
00980 static int num_dev_coords = 0;
00981 static int max_dev_coords = 0;
00982 
00983 void pdf_dev_get_coord(double *xpos, double *ypos)
00984 {
00985   if (num_dev_coords > 0) {
00986     *xpos = dev_coords[num_dev_coords-1].x;
00987     *ypos = dev_coords[num_dev_coords-1].y;
00988   } else {
00989     *xpos = *ypos = 0.0;
00990   }
00991 }
00992 
00993 void pdf_dev_push_coord(double xpos, double ypos)
00994 {
00995   if (num_dev_coords >= max_dev_coords) {
00996     max_dev_coords += 4;
00997     dev_coords = RENEW(dev_coords, max_dev_coords, pdf_coord);
00998   }
00999   dev_coords[num_dev_coords].x = xpos;
01000   dev_coords[num_dev_coords].y = ypos;
01001   num_dev_coords++;
01002 }
01003 
01004 void pdf_dev_pop_coord(void)
01005 {
01006   if (num_dev_coords > 0) num_dev_coords--;
01007 }
01008 
01009 
01010 spt_t pdf_dev_string_width(int   font_id, unsigned char *str, unsigned len)
01011 {
01012   if (font_id < 0 || font_id >= num_dev_fonts) {
01013     ERROR("Invalid font: %d (%d)", font_id, num_dev_fonts);
01014     return;
01015   }
01016   
01017   return tfm_string_width(GET_FONT(font_id)->tfm_id, str, len);
01018 }
01019 
01020 /*
01021  * ctype:
01022  *  0  byte-width of char can be variable and input string
01023  *     is properly encoded.
01024  *  n  Single character cosumes n bytes in input string.
01025  *
01026  * _FIXME_
01027  * -->
01028  * selectfont(font_name, point_size) and show_string(pos, string)
01029  */
01030 void
01031 pdf_dev_set_string (spt_t xpos, spt_t ypos,
01032                     const void *instr_ptr, int instr_len,
01033                     spt_t width,
01034                     int   font_id, int ctype)
01035 {
01036   struct dev_font *font;
01037   unsigned char   *str_ptr; /* Pointer to the reencoded string. */
01038   int              length, i, len = 0;
01039   spt_t            kern, delh, delv;
01040   spt_t            text_xorigin;
01041   spt_t            text_yorigin;
01042 
01043   if (font_id < 0 || font_id >= num_dev_fonts) {
01044     ERROR("Invalid font: %d (%d)", font_id, num_dev_fonts);
01045     return;
01046   }
01047   if (font_id != text_state.font_id) {
01048     dev_set_font(font_id);
01049   }
01050 
01051   font = CURRENTFONT();
01052   if (!font) {
01053     ERROR("Currentfont not set.");
01054     return;
01055   }
01056 
01057   text_xorigin = text_state.ref_x;
01058   text_yorigin = text_state.ref_y;
01059 
01060   str_ptr = (unsigned char *) instr_ptr;
01061   length  = instr_len;
01062 
01063   if (font->format == PDF_FONTTYPE_COMPOSITE) {
01064     if (handle_multibyte_string(font, &str_ptr, &length, ctype) < 0) {
01065       ERROR("Error in converting input string...");
01066       return;
01067     }
01068     if (font->used_chars != NULL) {
01069       for (i = 0; i < length; i += 2)
01070         add_to_used_chars2(font->used_chars,
01071                            (unsigned short) (str_ptr[i] << 8)|str_ptr[i+1]);
01072     }
01073   } else {
01074     if (font->used_chars != NULL) {
01075       for (i = 0; i < length; i++)
01076         font->used_chars[str_ptr[i]] = 1;
01077     }
01078   }
01079 
01080   if (num_dev_coords > 0) {
01081     xpos -= bpt2spt(dev_coords[num_dev_coords-1].x);
01082     ypos -= bpt2spt(dev_coords[num_dev_coords-1].y);
01083   }
01084 
01085   /*
01086    * Kern is in units of character units, i.e., 1000 = 1 em.
01087    *
01088    * Positive kern means kerning (reduce excess white space).
01089    *
01090    * The following formula is of the form a*x/b where a, x, and b are signed long
01091    * integers.  Since in integer arithmetic (a*x) could overflow and a*(x/b) would
01092    * not be accurate, we use floating point arithmetic rather than trying to do
01093    * this all with integer arithmetic.
01094    *
01095    * 1000.0 / (font->extend * font->sptsize) is caluculated each times...
01096    * Is accuracy really a matter? Character widths are always rounded to integer
01097    * (in 1000 units per em) but dvipdfmx does not take into account of this...
01098    */
01099 
01100   if (text_state.dir_mode) {
01101     /* Top-to-bottom */
01102     delh = ypos - text_yorigin + text_state.offset;
01103     delv = xpos - text_xorigin;
01104   } else {
01105     /* Left-to-right */
01106     delh = text_xorigin + text_state.offset - xpos;
01107     delv = ypos - text_yorigin;
01108   }
01109 
01110   /* White-space more than 3em is not considered as a part of single text.
01111    * So we will break string mode in that case.
01112    * Dvipdfmx spend most of time processing strings with kern = 0 (but far
01113    * more times in font handling).
01114    * You may want to use pre-calculated value for WORD_SPACE_MAX.
01115    * More text compression may be possible by replacing kern with space char
01116    * when -kern is equal to space char width.
01117    */
01118 #define WORD_SPACE_MAX(f) (spt_t) (3.0 * (f)->extend * (f)->sptsize)
01119 
01120   if (text_state.force_reset ||
01121       labs(delv) > dev_unit.min_bp_val ||
01122       labs(delh) > WORD_SPACE_MAX(font)) {
01123     text_mode();
01124     kern = 0;
01125   } else {
01126     kern = (spt_t) (1000.0 / font->extend * delh / font->sptsize);
01127   }
01128 
01129   /* Inaccucary introduced by rounding of character width appears within
01130    * single text block. There are point_size/1000 rounding error per character.
01131    * If you really care about accuracy, you should compensate this here too.
01132    */
01133   if (motion_state != STRING_MODE)
01134     string_mode(xpos, ypos,
01135                 font->slant, font->extend, text_state.matrix.rotate);
01136   else if (kern != 0) {
01137     /*
01138      * Same issues as earlier. Use floating point for simplicity.
01139      * This routine needs to be fast, so we don't call sprintf() or strcpy().
01140      */
01141     text_state.offset -= 
01142       (spt_t) (kern * font->extend * (font->sptsize / 1000.0));
01143     format_buffer[len++] = text_state.is_mb ? '>' : ')';
01144     if (font->wmode)
01145       len += p_itoa(-kern, format_buffer + len);
01146     else {
01147       len += p_itoa( kern, format_buffer + len);
01148     }
01149     format_buffer[len++] = text_state.is_mb ? '<' : '(';
01150     pdf_doc_add_page_content(format_buffer, len);  /* op: */
01151     len = 0;
01152   }
01153 
01154   if (text_state.is_mb) {
01155     if (FORMAT_BUF_SIZE - len < 2 * length)
01156       ERROR("Buffer overflow...");
01157     for (i = 0; i < length; i++) {
01158       int first, second;
01159 
01160       first  = (str_ptr[i] >> 4) & 0x0f;
01161       second = str_ptr[i] & 0x0f;
01162       format_buffer[len++] = ((first >= 10)  ? first  + 'W' : first  + '0');
01163       format_buffer[len++] = ((second >= 10) ? second + 'W' : second + '0');
01164     }
01165   } else {
01166     len += pdfobj_escape_str(format_buffer + len,
01167                              FORMAT_BUF_SIZE - len, str_ptr, length);
01168   }
01169   /* I think if you really care about speed, you should avoid memcopy here. */
01170   pdf_doc_add_page_content(format_buffer, len);  /* op: */
01171 
01172   text_state.offset += width;
01173 }
01174 
01175 
01176 void
01177 pdf_dev_set_raw_glyph (spt_t xpos, spt_t ypos, unsigned char glyph, int font_id)
01178 {
01179   struct dev_font *font;
01180   int              i, len = 0;
01181   spt_t            kern, delh, delv;
01182   spt_t            text_xorigin;
01183   spt_t            text_yorigin;
01184   
01185   if (font_id < 0 || font_id >= num_dev_fonts) {
01186     ERROR("Invalid font: %d (%d)", font_id, num_dev_fonts);
01187     return;
01188   }
01189   if (font_id != text_state.font_id) {
01190     dev_set_font(font_id);
01191   }
01192   
01193   font = CURRENTFONT();
01194   if (!font) {
01195     ERROR("Currentfont not set.");
01196     return;
01197   }
01198   
01199   text_xorigin = text_state.ref_x;
01200   text_yorigin = text_state.ref_y;
01201   
01202   if (font->format == PDF_FONTTYPE_COMPOSITE) {
01203     ERROR("This should not happen...");
01204     return;
01205   } else {
01206     if (font->used_chars != NULL) {
01207           font->used_chars[glyph] = 1;
01208     }
01209   }
01210   
01211   if (num_dev_coords > 0) {
01212     xpos -= bpt2spt(dev_coords[num_dev_coords-1].x);
01213     ypos -= bpt2spt(dev_coords[num_dev_coords-1].y);
01214   }
01215   
01216   /*
01217    * Kern is in units of character units, i.e., 1000 = 1 em.
01218    *
01219    * Positive kern means kerning (reduce excess white space).
01220    *
01221    * The following formula is of the form a*x/b where a, x, and b are signed long
01222    * integers.  Since in integer arithmetic (a*x) could overflow and a*(x/b) would
01223    * not be accurate, we use floating point arithmetic rather than trying to do
01224    * this all with integer arithmetic.
01225    *
01226    * 1000.0 / (font->extend * font->sptsize) is caluculated each times...
01227    * Is accuracy really a matter? Character widths are always rounded to integer
01228    * (in 1000 units per em) but dvipdfmx does not take into account of this...
01229    */
01230   
01231   if (text_state.dir_mode) {
01232     /* Top-to-bottom */
01233     delh = ypos - text_yorigin + text_state.offset;
01234     delv = xpos - text_xorigin;
01235   } else {
01236     /* Left-to-right */
01237     delh = text_xorigin + text_state.offset - xpos;
01238     delv = ypos - text_yorigin;
01239   }
01240   
01241   /* White-space more than 3em is not considered as a part of single text.
01242    * So we will break string mode in that case.
01243    * Dvipdfmx spend most of time processing strings with kern = 0 (but far
01244    * more times in font handling).
01245    * You may want to use pre-calculated value for WORD_SPACE_MAX.
01246    * More text compression may be possible by replacing kern with space char
01247    * when -kern is equal to space char width.
01248    */
01249 #define WORD_SPACE_MAX(f) (spt_t) (3.0 * (f)->extend * (f)->sptsize)
01250   
01251   text_mode();
01252   kern = 0;
01253 
01254   /* Inaccucary introduced by rounding of character width appears within
01255    * single text block. There are point_size/1000 rounding error per character.
01256    * If you really care about accuracy, you should compensate this here too.
01257    */
01258   if (motion_state != STRING_MODE)
01259     string_mode(xpos, ypos,
01260                 font->slant, font->extend, text_state.matrix.rotate);
01261   else if (kern != 0) {
01262     /*
01263      * Same issues as earlier. Use floating point for simplicity.
01264      * This routine needs to be fast, so we don't call sprintf() or strcpy().
01265      */
01266     text_state.offset -= 
01267     (spt_t) (kern * font->extend * (font->sptsize / 1000.0));
01268     format_buffer[len++] = text_state.is_mb ? '>' : ')';
01269     if (font->wmode)
01270       len += p_itoa(-kern, format_buffer + len);
01271     else {
01272       len += p_itoa( kern, format_buffer + len);
01273     }
01274     format_buffer[len++] = text_state.is_mb ? '<' : '(';
01275     pdf_doc_add_page_content(format_buffer, len);  /* op: */
01276     len = 0;
01277   }
01278   
01279   if (text_state.is_mb) {
01280     if (FORMAT_BUF_SIZE - len < 2)
01281       ERROR("Buffer overflow...");
01282       int first, second;
01283       
01284       first  = (glyph >> 4) & 0x0f;
01285       second = glyph & 0x0f;
01286       format_buffer[len++] = ((first >= 10)  ? first  + 'W' : first  + '0');
01287       format_buffer[len++] = ((second >= 10) ? second + 'W' : second + '0');
01288   } else {
01289     len += pdfobj_escape_str(format_buffer + len,
01290                              FORMAT_BUF_SIZE - len, &glyph, 1);
01291   }
01292   /* I think if you really care about speed, you should avoid memcopy here. */
01293   pdf_doc_add_page_content(format_buffer, len);  /* op: */
01294   
01295  // text_state.offset += width;
01296 }
01297 
01298 
01299 
01300 void
01301 pdf_init_device (double dvi2pts, int precision, int black_and_white)
01302 {
01303   if (precision < 0 ||
01304       precision > DEV_PRECISION_MAX)
01305     WARN("Number of decimal digits out of range [0-%d].",
01306          DEV_PRECISION_MAX);
01307 
01308   if (precision < 0) {
01309     dev_unit.precision  = 0;
01310   } else if (precision > DEV_PRECISION_MAX) {
01311     dev_unit.precision  = DEV_PRECISION_MAX;
01312   } else {
01313     dev_unit.precision  = precision;
01314   }
01315   dev_unit.dvi2pts      = dvi2pts;
01316   dev_unit.min_bp_val   = (long) ROUND(1.0/(ten_pow[dev_unit.precision]*dvi2pts), 1);
01317   if (dev_unit.min_bp_val < 0)
01318     dev_unit.min_bp_val = -dev_unit.min_bp_val;
01319 
01320   dev_param.colormode = (black_and_white ? 0 : 1);
01321 
01322   graphics_mode();
01323   pdf_color_clear_stack();
01324   pdf_dev_init_gstates();
01325 
01326   num_dev_fonts  = max_dev_fonts = 0;
01327   dev_fonts      = NULL;
01328   num_dev_coords = max_dev_coords = 0;
01329   dev_coords     = NULL;
01330 }
01331 
01332 void
01333 pdf_close_device (void)
01334 {
01335   if (dev_fonts) {
01336     int    i;
01337 
01338     for (i = 0; i < num_dev_fonts; i++) {
01339       if (dev_fonts[i].tex_name)
01340         RELEASE(dev_fonts[i].tex_name);
01341       if (dev_fonts[i].resource)
01342         pdf_release_obj(dev_fonts[i].resource);
01343       dev_fonts[i].tex_name = NULL;
01344       dev_fonts[i].resource = NULL;
01345     }
01346     RELEASE(dev_fonts);
01347   }
01348   if (dev_coords) RELEASE(dev_coords);
01349   pdf_dev_clear_gstates();
01350 }
01351 
01352 /*
01353  * BOP, EOP, and FONT section.
01354  * BOP and EOP manipulate some of the same data structures
01355  * as the font stuff.
01356  */
01357 void
01358 pdf_dev_reset_fonts (void)
01359 {
01360   int  i;
01361 
01362   for (i = 0; i < num_dev_fonts; i++) {
01363     dev_fonts[i].used_on_this_page = 0;
01364   }
01365 
01366   text_state.font_id       = -1;
01367 
01368   text_state.matrix.slant  = 0.0;
01369   text_state.matrix.extend = 1.0;
01370   text_state.matrix.rotate = TEXT_WMODE_HH;
01371 
01372   text_state.bold_param    = 0.0;
01373 
01374   text_state.is_mb         = 0;
01375 }
01376 
01377 #if 0
01378 /* Not working */
01379 void
01380 pdf_dev_set_origin (double phys_x, double phys_y)
01381 {
01382   pdf_tmatrix M0, M1;
01383 
01384   pdf_dev_currentmatrix(&M0);
01385   pdf_dev_currentmatrix(&M1);
01386   pdf_invertmatrix(&M1);
01387   M0.e = phys_x; M0.f = phys_y;
01388   pdf_concatmatrix(&M1, &M0);
01389 
01390   pdf_dev_concat(&M1);
01391 }
01392 #endif
01393 
01394 void
01395 pdf_dev_bop (const pdf_tmatrix *M)
01396 {
01397   graphics_mode();
01398 
01399   text_state.force_reset  = 0;
01400 
01401   pdf_dev_gsave();
01402   pdf_dev_concat(M);
01403 
01404   pdf_dev_reset_fonts();
01405   pdf_dev_reset_color(0);
01406 }
01407 
01408 void
01409 pdf_dev_eop (void)
01410 {
01411   int  depth;
01412 
01413   graphics_mode();
01414 
01415   depth = pdf_dev_current_depth();
01416   if (depth != 1) {
01417     WARN("Unbalenced q/Q nesting...: %d", depth);
01418     pdf_dev_grestore_to(0);
01419   } else {
01420     pdf_dev_grestore();
01421   }
01422 }
01423 
01424 static void
01425 print_fontmap (const char *font_name, fontmap_rec *mrec)
01426 {
01427   if (!mrec)
01428     return;
01429 
01430   MESG("\n");
01431 
01432   MESG("fontmap: %s -> %s", font_name, mrec->font_name);
01433   if (mrec->enc_name)
01434     MESG("(%s)",  mrec->enc_name);
01435   if (mrec->opt.extend != 1.0)
01436     MESG("[extend:%g]", mrec->opt.extend);
01437   if (mrec->opt.slant  != 0.0)
01438     MESG("[slant:%g]",  mrec->opt.slant);
01439   if (mrec->opt.bold   != 0.0) 
01440     MESG("[bold:%g]",   mrec->opt.bold);
01441   if (mrec->opt.flags & FONTMAP_OPT_NOEMBED)
01442     MESG("[noemb]");
01443   if (mrec->opt.mapc >= 0)
01444     MESG("[map:<%02x>]", mrec->opt.mapc);
01445   if (mrec->opt.charcoll)  
01446     MESG("[csi:%s]",     mrec->opt.charcoll);
01447   if (mrec->opt.index) 
01448     MESG("[index:%d]",   mrec->opt.index);
01449 
01450   switch (mrec->opt.style) {
01451   case FONTMAP_STYLE_BOLD:
01452     MESG("[style:bold]");
01453     break;
01454   case FONTMAP_STYLE_ITALIC:
01455     MESG("[style:italic]");
01456     break;
01457   case FONTMAP_STYLE_BOLDITALIC:
01458     MESG("[style:bolditalic]");
01459     break;
01460   }
01461   MESG("\n");
01462 
01463 }
01464 
01465 /* _FIXME_
01466  * Font is identified with font_name and point_size as in DVI here.
01467  * This may assign different resource name for same font at different
01468  * point size even for scalable fonts.
01469  */
01470 int
01471 pdf_dev_locate_font (const char *font_name, spt_t ptsize)
01472 {
01473   int              i;
01474   fontmap_rec     *mrec;
01475   struct dev_font *font;
01476 
01477   if (!font_name)
01478     return  -1;
01479 
01480   if (ptsize == 0) {
01481     ERROR("pdf_dev_locate_font() called with the zero ptsize.");
01482     return -1;
01483   }
01484 
01485   for (i = 0; i < num_dev_fonts; i++) {
01486     if (!strcmp(font_name, dev_fonts[i].tex_name) && ptsize == dev_fonts[i].sptsize) {
01487       return  i;
01488     }
01489   }
01490 
01491   /*
01492    * Make sure we have room for a new one, even though we may not
01493    * actually create one.
01494    */
01495   if (num_dev_fonts >= max_dev_fonts) {
01496     max_dev_fonts += 16;
01497     dev_fonts      = RENEW(dev_fonts, max_dev_fonts, struct dev_font);
01498   }
01499 
01500   font = &dev_fonts[num_dev_fonts];
01501 
01502   /* New font */
01503   mrec = pdf_lookup_fontmap_record(font_name);
01504 
01505   if (verbose > 1)
01506     print_fontmap(font_name, mrec);
01507 
01508   font->font_id = pdf_font_findresource(font_name, ptsize * dev_unit.dvi2pts, mrec);
01509   if (font->font_id < 0)
01510     return  -1;
01511 
01512   /* We found device font here. */
01513   font->short_name[0] = 'F';
01514   p_itoa(num_phys_fonts + 1, &font->short_name[1]); /* NULL terminated here */
01515   num_phys_fonts++;
01516 
01517   font->used_on_this_page = 0;
01518 
01519   font->tex_name = NEW(strlen(font_name) + 1, char);
01520   strcpy(font->tex_name, font_name);
01521   font->sptsize  = ptsize;
01522 
01523   switch (pdf_get_font_subtype(font->font_id)) {
01524   case PDF_FONT_FONTTYPE_TYPE3:
01525     font->format = PDF_FONTTYPE_BITMAP;
01526     break;
01527   case PDF_FONT_FONTTYPE_TYPE0:
01528     font->format = PDF_FONTTYPE_COMPOSITE;
01529     break;
01530   default:
01531     font->format = PDF_FONTTYPE_SIMPLE;
01532     break;
01533   }
01534 
01535   font->wmode      = pdf_get_font_wmode   (font->font_id);
01536   font->enc_id     = pdf_get_font_encoding(font->font_id);
01537 
01538   font->resource   = NULL; /* Don't ref obj until font is actually used. */  
01539   font->used_chars = NULL;
01540 
01541   font->extend     = 1.0;
01542   font->slant      = 0.0;
01543   font->bold       = 0.0;
01544   font->mapc       = -1;
01545   font->is_unicode = 0;
01546   font->ucs_group  = 0;
01547   font->ucs_plane  = 0;
01548 
01549   if (mrec) {
01550     font->extend = mrec->opt.extend;
01551     font->slant  = mrec->opt.slant;
01552     font->bold   = mrec->opt.bold;
01553     if (mrec->opt.mapc >= 0)
01554       font->mapc = (mrec->opt.mapc >> 8) & 0xff;
01555     else {
01556       font->mapc = -1;
01557     }
01558     if (mrec->enc_name &&
01559         !strcmp(mrec->enc_name, "unicode")) {
01560       font->is_unicode   = 1;
01561       if (mrec->opt.mapc >= 0) {
01562         font->ucs_group  = (mrec->opt.mapc >> 24) & 0xff;
01563         font->ucs_plane  = (mrec->opt.mapc >> 16) & 0xff;
01564       } else {
01565         font->ucs_group  = 0;
01566         font->ucs_plane  = 0;
01567       }
01568     } else {
01569       font->is_unicode   = 0;
01570     }
01571   }
01572 
01573   return  num_dev_fonts++;
01574 }
01575 
01576 int
01577 pdf_dev_physical_font (const char *font_name, spt_t ptsize, const char *font_file, const char *tfm_file)
01578 {
01579   int              i;
01580   fontmap_rec     *mrec = NULL;
01581   struct dev_font *font;
01582   
01583   if (!font_name)
01584     return  -1;
01585   
01586   if (ptsize == 0) {
01587     ERROR("pdf_dev_physical_font() called with the zero ptsize.");
01588     return -1;
01589   }
01590   
01591   for (i = 0; i < num_dev_fonts; i++) {
01592     if (!strcmp(font_name, dev_fonts[i].tex_name) && ptsize == dev_fonts[i].sptsize) {
01593       return  i;
01594     }
01595   }
01596   
01597   /*
01598    * Make sure we have room for a new one, even though we may not
01599    * actually create one.
01600    */
01601   if (num_dev_fonts >= max_dev_fonts) {
01602     max_dev_fonts += 16;
01603     dev_fonts      = RENEW(dev_fonts, max_dev_fonts, struct dev_font);
01604   }
01605   
01606   font = &dev_fonts[num_dev_fonts];
01607   
01608   /* New font */
01609 //  mrec = pdf_lookup_fontmap_record(font_name);
01610   
01611   if (verbose > 1)
01612     print_fontmap(font_name, mrec);
01613   
01614   font->font_id = pdf_font_physical(font_name, ptsize * dev_unit.dvi2pts, font_file, tfm_file);
01615   if (font->font_id < 0)
01616     return  -1;
01617   
01618   /* We found device font here. */
01619   font->short_name[0] = 'F';
01620   p_itoa(num_phys_fonts + 1, &font->short_name[1]); /* NULL terminated here */
01621   num_phys_fonts++;
01622   
01623   font->used_on_this_page = 0;
01624   
01625   font->tex_name = NEW(strlen(font_name) + 1, char);
01626   strcpy(font->tex_name, font_name);
01627   font->sptsize  = ptsize;
01628   
01629   switch (pdf_get_font_subtype(font->font_id)) {
01630     case PDF_FONT_FONTTYPE_TYPE3:
01631       font->format = PDF_FONTTYPE_BITMAP;
01632       break;
01633     case PDF_FONT_FONTTYPE_TYPE0:
01634       font->format = PDF_FONTTYPE_COMPOSITE;
01635       break;
01636     default:
01637       font->format = PDF_FONTTYPE_SIMPLE;
01638       break;
01639   }
01640   
01641   font->wmode      = pdf_get_font_wmode   (font->font_id);
01642   font->enc_id     = pdf_get_font_encoding(font->font_id);
01643   
01644   font->resource   = NULL; /* Don't ref obj until font is actually used. */  
01645   font->used_chars = NULL;
01646   
01647   font->extend     = 1.0;
01648   font->slant      = 0.0;
01649   font->bold       = 0.0;
01650   font->mapc       = -1;
01651   font->is_unicode = 0;
01652   font->ucs_group  = 0;
01653   font->ucs_plane  = 0;
01654   
01655   font->tfm_id = (tfm_file ? tfm_open(tfm_file, 1) : -1);
01656   
01657   if (mrec) {
01658     font->extend = mrec->opt.extend;
01659     font->slant  = mrec->opt.slant;
01660     font->bold   = mrec->opt.bold;
01661     if (mrec->opt.mapc >= 0)
01662       font->mapc = (mrec->opt.mapc >> 8) & 0xff;
01663     else {
01664       font->mapc = -1;
01665     }
01666     if (mrec->enc_name &&
01667         !strcmp(mrec->enc_name, "unicode")) {
01668       font->is_unicode   = 1;
01669       if (mrec->opt.mapc >= 0) {
01670         font->ucs_group  = (mrec->opt.mapc >> 24) & 0xff;
01671         font->ucs_plane  = (mrec->opt.mapc >> 16) & 0xff;
01672       } else {
01673         font->ucs_group  = 0;
01674         font->ucs_plane  = 0;
01675       }
01676     } else {
01677       font->is_unicode   = 0;
01678     }
01679   }
01680   
01681   return  num_dev_fonts++;
01682 }
01683 
01684 
01685 
01686 /* This does not remember current stroking width. */
01687 static int
01688 dev_sprint_line (char *buf, spt_t width,
01689                  spt_t p0_x, spt_t p0_y, spt_t p1_x, spt_t p1_y)
01690 {
01691   int    len = 0;
01692   double w;
01693 
01694   w = width * dev_unit.dvi2pts;
01695 
01696   len += p_dtoa(w, MIN(dev_unit.precision+1, DEV_PRECISION_MAX), buf+len);
01697   buf[len++] = ' ';
01698   buf[len++] = 'w';
01699   buf[len++] = ' ';
01700   len += dev_sprint_bp(buf+len, p0_x, NULL);
01701   buf[len++] = ' ';
01702   len += dev_sprint_bp(buf+len, p0_y, NULL);
01703   buf[len++] = ' ';
01704   buf[len++] = 'm';
01705   buf[len++] = ' ';
01706   len += dev_sprint_bp(buf+len, p1_x, NULL);
01707   buf[len++] = ' ';
01708   len += dev_sprint_bp(buf+len, p1_y, NULL);
01709   buf[len++] = ' ';
01710   buf[len++] = 'l';
01711   buf[len++] = ' ';
01712   buf[len++] = 'S';
01713 
01714   return len;
01715 }
01716 
01717 /* Not optimized. */
01718 #define PDF_LINE_THICKNESS_MAX 5.0
01719 void
01720 pdf_dev_set_rule (spt_t xpos, spt_t ypos, spt_t width, spt_t height)
01721 {
01722   int    len = 0;
01723   double width_in_bp;
01724 
01725   if (num_dev_coords > 0) {
01726     xpos -= bpt2spt(dev_coords[num_dev_coords-1].x);
01727     ypos -= bpt2spt(dev_coords[num_dev_coords-1].y);
01728   }
01729 
01730   graphics_mode();
01731 
01732   format_buffer[len++] = ' ';
01733   format_buffer[len++] = 'q';
01734   format_buffer[len++] = ' ';
01735   /* Don't use too thick line. */
01736   width_in_bp = ((width < height) ? width : height) * dev_unit.dvi2pts;
01737   if (width_in_bp < 0.0 || /* Shouldn't happen */
01738       width_in_bp > PDF_LINE_THICKNESS_MAX) {
01739     pdf_rect rect;
01740 
01741     rect.llx =  dev_unit.dvi2pts * xpos;
01742     rect.lly =  dev_unit.dvi2pts * ypos;
01743     rect.urx =  dev_unit.dvi2pts * width;
01744     rect.ury =  dev_unit.dvi2pts * height;
01745     len += pdf_sprint_rect(format_buffer+len, &rect);
01746     format_buffer[len++] = ' ';
01747     format_buffer[len++] = 'r';
01748     format_buffer[len++] = 'e';
01749     format_buffer[len++] = ' ';
01750     format_buffer[len++] = 'f';
01751   } else {
01752     if (width > height) {
01753       /* NOTE:
01754        *  A line width of 0 denotes the thinnest line that can be rendered at
01755        *  device resolution. See, PDF Reference Manual 4th ed., sec. 4.3.2,
01756        *  "Details of Graphics State Parameters", p. 185.
01757        */
01758       if (height < dev_unit.min_bp_val) {
01759         WARN("Too thin line: height=%ld (%g bp)", height, width_in_bp);
01760         WARN("Please consider using \"-d\" option.");
01761       }
01762       len += dev_sprint_line(format_buffer+len,
01763                              height,
01764                              xpos,
01765                              ypos + height/2,
01766                              xpos + width,
01767                              ypos + height/2);
01768     } else {
01769       if (width < dev_unit.min_bp_val) {
01770         WARN("Too thin line: width=%ld (%g bp)", width, width_in_bp);
01771         WARN("Please consider using \"-d\" option.");
01772       }
01773       len += dev_sprint_line(format_buffer+len,
01774                              width,
01775                              xpos + width/2,
01776                              ypos,
01777                              xpos + width/2,
01778                              ypos + height);
01779     }
01780   }
01781   format_buffer[len++] = ' ';
01782   format_buffer[len++] = 'Q';
01783   pdf_doc_add_page_content(format_buffer, len);  /* op: q re f Q */
01784 }
01785 
01786 /* Rectangle in device space coordinate. */
01787 void
01788 pdf_dev_set_rect (pdf_rect *rect,
01789                   spt_t x_user, spt_t y_user,
01790                   spt_t width,  spt_t height, spt_t depth)
01791 {
01792   double      dev_x, dev_y;
01793   pdf_coord   p0, p1, p2, p3;
01794   double      min_x, min_y, max_x, max_y;
01795 
01796   dev_x = x_user * dev_unit.dvi2pts;
01797   dev_y = y_user * dev_unit.dvi2pts;
01798   if (text_state.dir_mode) {
01799     p0.x = dev_x - dev_unit.dvi2pts * depth;
01800     p0.y = dev_y - dev_unit.dvi2pts * width;
01801     p1.x = dev_x + dev_unit.dvi2pts * height;
01802     p1.y = p0.y;
01803     p2.x = p1.x;
01804     p2.y = dev_y;
01805     p3.x = p0.x;
01806     p3.y = p2.y;
01807   } else {
01808     p0.x = dev_x;
01809     p0.y = dev_y - dev_unit.dvi2pts * depth;
01810     p1.x = dev_x + dev_unit.dvi2pts * width;
01811     p1.y = p0.y;
01812     p2.x = p1.x;
01813     p2.y = dev_y + dev_unit.dvi2pts * height;
01814     p3.x = p0.x;
01815     p3.y = p2.y;
01816   }
01817 
01818   pdf_dev_transform(&p0, NULL); /* currentmatrix */
01819   pdf_dev_transform(&p1, NULL);
01820   pdf_dev_transform(&p2, NULL);
01821   pdf_dev_transform(&p3, NULL);
01822 
01823   min_x = MIN(p0.x , p1.x);
01824   min_x = MIN(min_x, p2.x);
01825   min_x = MIN(min_x, p3.x);
01826 
01827   max_x = MAX(p0.x , p1.x);
01828   max_x = MAX(max_x, p2.x);
01829   max_x = MAX(max_x, p3.x);
01830 
01831   min_y = MIN(p0.y , p1.y);
01832   min_y = MIN(min_y, p2.y);
01833   min_y = MIN(min_y, p3.y);
01834 
01835   max_y = MAX(p0.y , p1.y);
01836   max_y = MAX(max_y, p2.y);
01837   max_y = MAX(max_y, p3.y);
01838 
01839   rect->llx = min_x;
01840   rect->lly = min_y;
01841   rect->urx = max_x;
01842   rect->ury = max_y;
01843 
01844   return;
01845 }
01846 
01847 int
01848 pdf_dev_get_dirmode (void)
01849 {
01850   return text_state.dir_mode;
01851 }
01852 
01853 void
01854 pdf_dev_set_dirmode (int text_dir)
01855 {
01856   struct dev_font *font;
01857   int text_rotate;
01858   int vert_dir, vert_font;
01859 
01860   font = CURRENTFONT();
01861 
01862   vert_font = (font && font->wmode) ? 1 : 0;
01863   if (dev_param.autorotate) {
01864     vert_dir = text_dir ? 1 : 0;
01865   } else {
01866     vert_dir = vert_font;
01867   }
01868   text_rotate = (vert_font << 1)|vert_dir;
01869 
01870   if (font &&
01871       ANGLE_CHANGES(text_rotate, text_state.matrix.rotate)) {
01872     text_state.force_reset = 1;
01873   }
01874 
01875   text_state.matrix.rotate = text_rotate;
01876   text_state.dir_mode      = text_dir;
01877 }
01878 
01879 static void
01880 dev_set_param_autorotate (int auto_rotate)
01881 {
01882   struct dev_font *font;
01883   int    text_rotate, vert_font, vert_dir;
01884 
01885   font = CURRENTFONT();
01886 
01887   vert_font = (font && font->wmode) ? 1 : 0;
01888   if (auto_rotate) {
01889     vert_dir = text_state.dir_mode ? 1 : 0;
01890   } else {
01891     vert_dir = vert_font;
01892   }
01893   text_rotate = (vert_font << 1)|vert_dir;
01894 
01895   if (ANGLE_CHANGES(text_rotate, text_state.matrix.rotate)) {
01896     text_state.force_reset = 1;
01897   }
01898   text_state.matrix.rotate = text_rotate;
01899   dev_param.autorotate     = auto_rotate;
01900 }
01901 
01902 int
01903 pdf_dev_get_param (int param_type)
01904 {
01905   int value = 0;
01906 
01907   switch (param_type) {
01908   case PDF_DEV_PARAM_AUTOROTATE:
01909     value = dev_param.autorotate;
01910     break;
01911   case PDF_DEV_PARAM_COLORMODE:
01912     value = dev_param.colormode;
01913     break;
01914   default:
01915     ERROR("Unknown device parameter: %d", param_type);
01916   }
01917 
01918   return value;
01919 }
01920 
01921 void
01922 pdf_dev_set_param (int param_type, int value)
01923 {
01924   switch (param_type) {
01925   case PDF_DEV_PARAM_AUTOROTATE:
01926     dev_set_param_autorotate(value);
01927     break;
01928   case PDF_DEV_PARAM_COLORMODE:
01929     dev_param.colormode = value; /* 0 for B&W */
01930     break;
01931   default:
01932     ERROR("Unknown device parameter: %d", param_type);
01933   }
01934 
01935   return;
01936 }
01937 
01938 
01939 int
01940 pdf_dev_put_image (int             id,
01941                    transform_info *p,
01942                    double          ref_x,
01943                    double          ref_y)
01944 {
01945   char        *res_name;
01946   pdf_tmatrix  M, M1;
01947   pdf_rect     r;
01948   int          len = 0;
01949 
01950   if (num_dev_coords > 0) {
01951     ref_x -= dev_coords[num_dev_coords-1].x;
01952     ref_y -= dev_coords[num_dev_coords-1].y;
01953   }
01954 
01955   pdf_copymatrix(&M, &(p->matrix));
01956   M.e += ref_x; M.f += ref_y;
01957   /* Just rotate by -90, but not tested yet. Any problem if M has scaling? */
01958   if (dev_param.autorotate &&
01959       text_state.dir_mode) {
01960     double tmp;
01961     tmp = -M.a; M.a = M.b; M.b = tmp;
01962     tmp = -M.c; M.c = M.d; M.d = tmp;
01963   }
01964 
01965   graphics_mode();
01966   pdf_dev_gsave();
01967 
01968   pdf_ximage_scale_image(id, &M1, &r, p);
01969   pdf_concatmatrix(&M, &M1);
01970   pdf_dev_concat(&M);
01971 
01972   /* Clip */
01973   if (p->flags & INFO_DO_CLIP) {
01974 #if  0
01975     pdf_dev_newpath();
01976     pdf_dev_moveto(r.llx, r.lly);
01977     pdf_dev_lineto(r.urx, r.lly);
01978     pdf_dev_lineto(r.urx, r.ury);
01979     pdf_dev_lineto(r.llx, r.ury);
01980     pdf_dev_closepath();
01981     pdf_dev_clip();
01982     pdf_dev_newpath();
01983 #else
01984     pdf_dev_rectclip(r.llx, r.lly, r.urx - r.llx, r.ury - r.lly);
01985 #endif
01986   }
01987 
01988   res_name = pdf_ximage_get_resname(id);
01989   len = sprintf(work_buffer, " /%s Do", res_name);
01990   pdf_doc_add_page_content(work_buffer, len);  /* op: Do */
01991 
01992   pdf_dev_grestore();
01993 
01994   pdf_doc_add_page_resource("XObject",
01995                             res_name,
01996                             pdf_ximage_get_reference(id));
01997 
01998   return 0;
01999 }
02000 
02001 
02002 void
02003 transform_info_clear (transform_info *info)
02004 {
02005   /* Physical dimensions */
02006   info->width    = 0.0;
02007   info->height   = 0.0;
02008   info->depth    = 0.0;
02009 
02010   info->bbox.llx = 0.0;
02011   info->bbox.lly = 0.0;
02012   info->bbox.urx = 0.0;
02013   info->bbox.ury = 0.0;
02014 
02015   /* Transformation matrix */
02016   pdf_setmatrix(&(info->matrix), 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
02017 
02018   info->flags    = 0;
02019 }