Back to index

texmacs  1.0.7.15
t1_char.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/t1_char.c,v 1.5 2005/07/17 09:53:38 hirata 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 <math.h>
00031 
00032 #include "system.h"
00033 #include "mem.h"
00034 #include "error.h"
00035 #include "numbers.h"
00036 
00037 #include "pdfobj.h"
00038 #include "pdffont.h"
00039 
00040 #include "pdfencoding.h"
00041 #include "unicode.h"
00042 
00043 #include "dpxutil.h"
00044 
00045 #include "pst_obj.h"
00046 #include "pst.h"
00047 
00048 #include "cff_limits.h"
00049 #include "cff_types.h"
00050 #include "cff_dict.h"
00051 #include "cff.h"
00052 
00053 #include "t1_char.h"
00054 
00055 /*
00056  * Type 1 -> Type 1C
00057  */
00058 
00059 /* Charstring decoder/encoder status codes */
00060 #define CS_OP_NOSUPPORT -4
00061 #define CS_BUFFER_ERROR -3
00062 #define CS_STACK_ERROR  -2
00063 #define CS_PARSE_ERROR  -1
00064 #define CS_PARSE_OK      0
00065 #define CS_PARSE_END     1
00066 #define CS_SUBR_RETURN   2
00067 #define CS_CHAR_END      3
00068 
00069 static int status = CS_PARSE_ERROR;
00070 
00071 #define DST_NEED(a,b) {if ((a) < (b)) { status = CS_BUFFER_ERROR ; return ; }}
00072 #define SRC_NEED(a,b) {if ((a) < (b)) { status = CS_PARSE_ERROR  ; return ; }}
00073 #define NEED(a,b)     {if ((a) < (b)) { status = CS_STACK_ERROR  ; return ; }}
00074 
00075 #define T1_CS_PHASE_INIT 0
00076 #define T1_CS_PHASE_HINT 1
00077 #define T1_CS_PHASE_PATH 2
00078 #define T1_CS_PHASE_FLEX 3
00079 
00080 static int phase = -1;
00081 static int nest  = -1;
00082 
00083 #ifndef CS_STEM_ZONE_MAX
00084 #define CS_STEM_ZONE_MAX 96
00085 #endif
00086 #ifndef CS_STEM_GROUP_MAX
00087 #define CS_STEM_GROUP_MAX CS_STEM_ZONE_MAX
00088 #endif
00089 #ifndef CS_ARG_STACK_MAX
00090 #define CS_ARG_STACK_MAX 48
00091 #endif
00092 #ifndef PS_ARG_STACK_MAX
00093 /*
00094  * Counter control may have CS_STEM_ZONE_MAX*2+2 arguments.
00095  */
00096 #define PS_ARG_STACK_MAX (CS_STEM_ZONE_MAX*2+2)
00097 #endif
00098 
00099 typedef struct t1_cpath {
00100   int     type;
00101   int     num_args;
00102   double  args[CS_ARG_STACK_MAX];
00103   struct t1_cpath *next;
00104 } t1_cpath;
00105 
00106 #define HSTEM 0
00107 #define VSTEM 1
00108 typedef struct {
00109   int id;
00110   int dir;
00111   double pos, del;
00112 } t1_stem;
00113 
00114 typedef struct {
00115   int    num_stems;
00116   double stems[CS_STEM_ZONE_MAX]; /* int */
00117 } t1_stemgroup;
00118 
00119 #define T1_CS_FLAG_NONE 0
00120 #define T1_CS_FLAG_USE_HINTMASK (1 << 0)
00121 #define T1_CS_FLAG_USE_CNTRMASK (1 << 1)
00122 #define T1_CS_FLAG_USE_SEAC     (1 << 2)
00123 
00124 typedef struct {
00125   int flags;
00126   struct {
00127     double sbx, sby, wx, wy;
00128   } sbw;
00129   struct {
00130     double llx, lly, urx, ury;
00131   } bbox;
00132   struct {
00133     double asb, adx, ady;
00134     card8 bchar, achar;
00135   } seac;
00136   int       num_stems;
00137   t1_stem   stems[CS_STEM_ZONE_MAX];
00138   t1_cpath *charpath;
00139   t1_cpath *lastpath;
00140 } t1_chardesc;
00141 
00142 static int cs_stack_top = 0;
00143 static int ps_stack_top = 0;
00144 
00145 /* [vh]stem support require one more stack size. */
00146 static double cs_arg_stack[CS_ARG_STACK_MAX+1];
00147 static double ps_arg_stack[PS_ARG_STACK_MAX];
00148 
00149 #define CS_HINT_DECL -1
00150 #define CS_FLEX_CTRL -2
00151 #define CS_CNTR_CTRL -3
00152 
00153 /*
00154  * Type 1/2 CharString encoding
00155  */
00156 
00157 /*
00158  * 1-byte CharString operaotrs:
00159  *  cs_escape is first byte of two-byte operator
00160  */
00161 
00162 /*      RESERVED      0 */
00163 #define cs_hstem      1
00164 /*      RESERVED      2 */
00165 #define cs_vstem      3
00166 #define cs_vmoveto    4
00167 #define cs_rlineto    5
00168 #define cs_hlineto    6
00169 #define cs_vlineto    7
00170 #define cs_rrcurveto  8
00171 #define cs_closepath  9
00172 #define cs_callsubr   10
00173 #define cs_return     11
00174 #define cs_escape     12
00175 #define cs_hsbw       13
00176 #define cs_endchar    14
00177 /*      RESERVED      15 */
00178 /*      RESERVED      16 */
00179 /*      RESERVED      17 */
00180 #define cs_hstemhm    18
00181 #define cs_hintmask   19
00182 #define cs_cntrmask   20
00183 #define cs_rmoveto    21
00184 #define cs_hmoveto    22
00185 #define cs_vstemhm    23
00186 #define cs_rcurveline 24
00187 #define cs_rlinecurve 25
00188 #define cs_vvcurveto  26
00189 #define cs_hhcurveto  27
00190 /*      SHORTINT      28 : first byte of shortint*/
00191 #define cs_callgsubr  29
00192 #define cs_vhcurveto  30
00193 #define cs_hvcurveto  31
00194 
00195 /* 2-byte op. flex 34-37 used. */
00196 
00197 /*
00198  * 2-byte CharString operaotrs:
00199  *  "dotsection" is obsoleted in Type 2 charstring.
00200  */
00201 
00202 #define cs_dotsection 0
00203 #define cs_vstem3     1
00204 #define cs_hstem3     2
00205 #define cs_and        3
00206 #define cs_or         4
00207 #define cs_not        5
00208 #define cs_seac       6
00209 #define cs_sbw        7
00210 /*      RESERVED      8  */
00211 #define cs_abs        9
00212 #define cs_add        10
00213 #define cs_sub        11
00214 #define cs_div        12
00215 /*      RESERVED      13 */
00216 #define cs_neg        14
00217 #define cs_eq         15
00218 #define cs_callothersubr 16
00219 #define cs_pop        17
00220 #define cs_drop       18
00221 /*      RESERVED      19 */
00222 #define cs_put        20
00223 #define cs_get        21
00224 #define cs_ifelse     22 
00225 #define cs_random     23
00226 #define cs_mul        24
00227 /*      RESERVED      25 */
00228 #define cs_sqrt       26
00229 #define cs_dup        27
00230 #define cs_exch       28
00231 #define cs_index      29
00232 #define cs_roll       30
00233 /*      RESERVED      31 */
00234 /*      RESERVED      32 */
00235 #define cs_setcurrentpoint 33
00236 #define cs_hflex      34
00237 #define cs_flex       35
00238 #define cs_hflex1     36
00239 #define cs_flex1      37
00240 
00241 #define IS_PATH_OPERATOR(o) (((o) >= cs_vmoveto && (o) <= cs_closepath) || \
00242                              ((o) >= cs_rmoveto && (o) <= cs_hvcurveto && \
00243                               (o) != cs_vstemhm && (o) != cs_callgsubr && (o) != 28)\
00244                             )
00245 
00246 /*
00247  * Stem:
00248  *
00249  *   1. Stems must be sorted in the increasing bottom/left edge order.
00250  *   2. The encoded values are all relative; The value x(y) of the first
00251  *      stem is relative to 0 for Type 2 charstring and is relative to
00252  *      the left(bottom) side-bearing for Type 1 charstring.
00253  *   3. A width of -20(-21) specifies the top/right(bottom/left) edge
00254  *      of an edge hint in Type 2 charstring. But the width of 'ghost'
00255  *      hint in Type 1 charstring is positive with value 20 or 21.
00256  *   4. The h(v)stemhm MUST be used instead of h(v)stem if charstring
00257  *      contains hintmask operator.
00258  *
00259  * TODO:
00260  *
00261  *  Convert ghost hint to edge hint, Counter control for hstem3/vstem3.
00262  */
00263 
00264 static int CDECL
00265 stem_compare (const void *v1, const void *v2)
00266 {
00267   int cmp = 0;
00268   t1_stem *s1, *s2;
00269 
00270   s1 = (t1_stem *) v1;
00271   s2 = (t1_stem *) v2;
00272   if (s1->dir == s2->dir) {
00273     if (s1->pos == s2->pos) {
00274       if (s1->del == s2->del)
00275        cmp = 0;
00276       else
00277        cmp = (s1->del < s2->del) ? -1 : 1;
00278     } else {
00279       cmp = (s1->pos < s2->pos) ? -1 : 1;
00280     }
00281   } else {
00282     cmp = (s1->dir == HSTEM) ? -1 : 1;
00283   }
00284 
00285   return cmp;
00286 }
00287 
00288 #define SORT_STEMS(cd) qsort((cd)->stems,(cd)->num_stems,sizeof(t1_stem),stem_compare)
00289 
00290 static int
00291 get_stem (t1_chardesc *cd, int stem_id)
00292 {
00293   int i;
00294 
00295   for (i = 0; i < cd->num_stems; i++) {
00296     if (cd->stems[i].id == stem_id)
00297       break;
00298   }
00299 
00300   return ((i < cd->num_stems) ? i : -1);
00301 }
00302 
00303 static int
00304 add_stem (t1_chardesc *cd, double pos, double del, int dir)
00305 {
00306   int i;
00307 
00308   ASSERT(cd);
00309 
00310   pos += (dir == HSTEM) ? cd->sbw.sby : cd->sbw.sbx;
00311   for (i = 0; i < cd->num_stems; i++) {
00312     if (cd->stems[i].dir == dir &&
00313        cd->stems[i].pos == pos &&
00314        cd->stems[i].del == del)
00315       break;
00316   }
00317   if (i == cd->num_stems) {
00318     if (cd->num_stems == CS_STEM_ZONE_MAX)
00319       return -1;
00320     cd->stems[i].dir = dir;
00321     cd->stems[i].pos = pos;
00322     cd->stems[i].del = del;
00323     cd->stems[i].id  = cd->num_stems;
00324     (cd->num_stems)++;
00325   }
00326 
00327   return cd->stems[i].id;
00328 }
00329 
00330 
00331 static void
00332 copy_args (double *args1, double *args2, int count)
00333 {
00334   while (count-- > 0) {
00335     *args1 = *args2;
00336     args1++; args2++;
00337   }
00338 }
00339 
00340 /*
00341  * Stack:
00342  */
00343 #define LIMITCHECK(n) do {\
00344                            if (cs_stack_top+(n) > CS_ARG_STACK_MAX) {\
00345                              status = CS_STACK_ERROR;\
00346                              return;\
00347                            }\
00348                       } while (0)
00349 #define CHECKSTACK(n) do {\
00350                            if (cs_stack_top < (n)) {\
00351                              status = CS_STACK_ERROR;\
00352                              return;\
00353                            }\
00354                       } while (0)
00355 #define CLEARSTACK()  do {\
00356                            cs_stack_top = 0;\
00357                       } while (0)
00358 
00359 /*
00360  * Path construction:
00361  */
00362 /* Get operands from cs_arg_stack[] */
00363 static void
00364 add_charpath (t1_chardesc *cd, int type, double *argv, int argn)
00365 {
00366   t1_cpath *p;
00367 
00368   ASSERT(cd);
00369   ASSERT(argn <= CS_ARG_STACK_MAX);
00370 
00371   p = NEW(1, t1_cpath);
00372   p->type     = type;
00373   p->num_args = argn;
00374   p->next     = NULL;
00375 
00376   while (argn-- > 0)
00377     p->args[argn] = argv[argn];
00378 
00379   if (!cd->charpath)
00380     cd->charpath = p;
00381   if (cd->lastpath)
00382     cd->lastpath->next = p;
00383   cd->lastpath = p;
00384 
00385   if (type >= 0 &&
00386       phase != T1_CS_PHASE_FLEX && IS_PATH_OPERATOR(type))
00387     phase = T1_CS_PHASE_PATH;
00388 }
00389 
00390 static void
00391 init_charpath (t1_chardesc *cd)
00392 {
00393   cd->flags = T1_CS_FLAG_NONE;
00394   cd->num_stems = 0;
00395   cd->sbw.wx  = cd->sbw.wy  = 0.0;
00396   cd->sbw.sbx = cd->sbw.sby = 0.0;
00397   cd->bbox.llx = cd->bbox.lly = cd->bbox.urx = cd->bbox.ury = 0.0;
00398   cd->charpath = cd->lastpath = NULL;
00399 }
00400 
00401 static void
00402 release_charpath (t1_chardesc *cd)
00403 {
00404   t1_cpath *curr, *next;
00405 
00406   ASSERT(cd);
00407 
00408   curr = cd->charpath;
00409   while (curr != NULL) {
00410     next = curr->next;
00411     RELEASE(curr);
00412     curr = next;
00413   }
00414 
00415   cd->charpath = cd->lastpath = NULL;
00416 }
00417 
00418 /*
00419  * Type 1 charstring operators:
00420  */
00421 #define ADD_PATH(p,t,n) add_charpath((p),(t),&(cs_arg_stack[cs_stack_top-(n)]),(n))
00422 
00423 /*
00424  * Single byte operators:
00425  */
00426 static void
00427 do_operator1 (t1_chardesc *cd, card8 **data, card8 *endptr)
00428 {
00429   card8 op = **data;
00430 
00431   *data += 1;
00432 
00433   switch (op) {
00434   case cs_closepath:
00435     /*
00436      * From T1 spec.:
00437      *  Note that, unlike the closepath command in the PostScript language,
00438      *  this command does not reposition the current point. Any subsequent
00439      *  rmoveto must be relative to the current point in force before the
00440      *  Type 1 font format closepath command was given.
00441      */
00442     /* noop */
00443     CLEARSTACK();
00444     break;
00445   case cs_hsbw:
00446     CHECKSTACK(2);
00447     cd->sbw.wx  = cs_arg_stack[--cs_stack_top];
00448     cd->sbw.wy  = 0;
00449     cd->sbw.sbx = cs_arg_stack[--cs_stack_top];
00450     cd->sbw.sby = 0;
00451     CLEARSTACK();
00452     /* hsbw does NOT set currentpoint. */
00453     break;
00454   case cs_hstem:
00455   case cs_vstem:
00456     CHECKSTACK(2);
00457     {
00458       int stem_id;
00459       stem_id = add_stem(cd,
00460                       cs_arg_stack[cs_stack_top-2],
00461                       cs_arg_stack[cs_stack_top-1],
00462                       ((op == cs_hstem) ? HSTEM : VSTEM));
00463       if (stem_id < 0) {
00464        WARN("Too many hints...");
00465        status = CS_PARSE_ERROR;
00466        return;
00467       }
00468       /* Put stem_id onto the stack... */
00469       cs_arg_stack[cs_stack_top++] = stem_id;
00470       ADD_PATH(cd, CS_HINT_DECL, 1);
00471     }
00472     CLEARSTACK();
00473     break;
00474   case cs_rmoveto:
00475     /*
00476      * Reference point is (0, 0) in Type 2 charstring.
00477      */
00478     CHECKSTACK(2);
00479     {
00480       if (phase < T1_CS_PHASE_PATH) {
00481        cs_arg_stack[cs_stack_top-2] += cd->sbw.sbx;
00482        cs_arg_stack[cs_stack_top-1] += cd->sbw.sby;
00483       }
00484       ADD_PATH(cd, op, 2);
00485     }
00486     CLEARSTACK();
00487     break;
00488   case cs_hmoveto:
00489   case cs_vmoveto:
00490     CHECKSTACK(1);
00491     {
00492       int argn = 1;
00493       if (phase < T1_CS_PHASE_PATH) {
00494        /*
00495         * The reference point for the first moveto operator is diferrent
00496         * between Type 1 charstring and Type 2 charstring. We compensate it.
00497         */
00498        if (op == cs_hmoveto) {
00499          cs_arg_stack[cs_stack_top-1] += cd->sbw.sbx;
00500          if (cd->sbw.sby != 0.0) {
00501            cs_arg_stack[cs_stack_top++] = cd->sbw.sby;
00502            argn = 2;
00503            op = cs_rmoveto;
00504          }
00505        } else {
00506          cs_arg_stack[cs_stack_top-1] += cd->sbw.sby;
00507          if (cd->sbw.sbx != 0.0) {
00508            cs_arg_stack[cs_stack_top]   = cs_arg_stack[cs_stack_top-1];
00509            cs_arg_stack[cs_stack_top-1] = cd->sbw.sbx;
00510            cs_stack_top++;
00511            argn = 2;
00512            op = cs_rmoveto;
00513          }
00514        }
00515       }
00516       ADD_PATH(cd, op, argn);
00517     }
00518     CLEARSTACK();
00519     break;
00520   case cs_endchar:
00521     status = CS_CHAR_END;
00522     CLEARSTACK();
00523     break;
00524   /* above oprators are candidate for first stack-clearing operator */
00525   case cs_rlineto:
00526     CHECKSTACK(2);
00527     ADD_PATH(cd, op, 2);
00528     CLEARSTACK();
00529     break;
00530   case cs_hlineto:
00531   case cs_vlineto:
00532     CHECKSTACK(1);
00533     ADD_PATH(cd, op, 1);
00534     CLEARSTACK();
00535     break;
00536   case cs_rrcurveto:
00537     CHECKSTACK(6);
00538     ADD_PATH(cd, op, 6);
00539     CLEARSTACK();
00540     break;
00541   case cs_vhcurveto:
00542   case cs_hvcurveto:
00543     CHECKSTACK(4);
00544     ADD_PATH(cd, op, 4);
00545     CLEARSTACK();
00546     break;
00547     /* all operotors above are stack-clearing operator */
00548     /* no output */
00549   case cs_return:
00550     break;
00551   case cs_callsubr:
00552     ERROR("Unexpected callsubr.");
00553     break;
00554   default:
00555     /* no-op ? */
00556     WARN("Unknown charstring operator: 0x%02x", op);
00557     status = CS_PARSE_ERROR;
00558     break;
00559   }
00560 
00561   return;
00562 }
00563 
00564 /*
00565  * OtherSubrs:
00566  *
00567  *  arg0 arg1 ... argn n othersubr# callothersubr
00568  *
00569  *   0: Build flex:
00570  *      fd x y 3 0 callothersubr
00571  *      Othersubr #0 pushes x and y to PostScript interpreter operand stack.
00572  *   1: Start flex
00573  *      0 1 callothersubr
00574  *   2: Mark flex control points
00575  *      0 2 callothersubr
00576  *   3: Discard hint
00577  *      subr# 1 3 callothersubr pop callsubr
00578  *      Subroutine subr# (only) contains stem declaration.
00579  *      Othersubr #3 pushes subr# to PostScript interpreter operand stack.
00580  *  12: Counter control
00581  *      A subr to avoid stack overflow.
00582  *  13: Counter control
00583  */
00584 
00585 /*
00586  * Convert six control points marked as CS_FLEX_CTRL to a flex path.
00587  */
00588 static void
00589 do_othersubr0 (t1_chardesc *cd)
00590 {
00591   t1_cpath *flex, *cur, *next;
00592 
00593   if (ps_stack_top < 1) {
00594     status = CS_PARSE_ERROR;
00595     return;
00596   }
00597 
00598   /* Seek first CS_FLEX_CTRL mark */
00599   for (cur = cd->charpath; cur != NULL && cur->type != CS_FLEX_CTRL; cur = cur->next);
00600   flex = cur;
00601   {
00602     int i;
00603     cur = cur->next;
00604     for (i = 1; i < 7; i++) {
00605       if (cur == NULL || cur->type != CS_FLEX_CTRL ||
00606          cur->num_args != 2) {
00607        status = CS_PARSE_ERROR;
00608        return;
00609       }
00610       if (i == 1) {
00611        flex->args[0] += cur->args[0];
00612        flex->args[1] += cur->args[1];
00613       } else {
00614        copy_args(&(flex->args[2*i-2]), cur->args, 2);
00615       }
00616       next = cur->next;
00617       RELEASE(cur);
00618       cur = next;
00619     }
00620   }
00621   if (cur != NULL) {
00622     status = CS_PARSE_ERROR;
00623     return;
00624   }
00625   /*
00626    * Now 'flex' have all six control points, the first pair is relative
00627    * from starting point.
00628    */
00629   flex->type = cs_flex;
00630   flex->args[12] = ps_arg_stack[--ps_stack_top]; /* flex depth */
00631   flex->num_args = 13;
00632   flex->next   = NULL;
00633   cd->lastpath = flex;
00634 
00635   phase = T1_CS_PHASE_PATH;
00636 }
00637 
00638 /* Start flex */
00639 static void
00640 do_othersubr1 (t1_chardesc *cd)
00641 {
00642   phase = T1_CS_PHASE_FLEX;
00643 }
00644 
00645 /* Mark flex control point */
00646 static void
00647 do_othersubr2 (t1_chardesc *cd)
00648 {
00649   if (phase != T1_CS_PHASE_FLEX || !cd->lastpath) {
00650     status = CS_PARSE_ERROR;
00651     return;
00652   }
00653 
00654   switch (cd->lastpath->type) {
00655   case cs_rmoveto:
00656     break;
00657   case cs_hmoveto:
00658     cd->lastpath->num_args = 2;
00659     cd->lastpath->args[1] = 0.0;
00660     break;
00661   case cs_vmoveto:
00662     cd->lastpath->num_args = 2;
00663     cd->lastpath->args[1] = cd->lastpath->args[0];
00664     cd->lastpath->args[0] = 0.0;
00665     break;
00666   default:
00667     status = CS_PARSE_ERROR;
00668     return;
00669   }
00670   cd->lastpath->type = CS_FLEX_CTRL;
00671 }
00672 
00673 /*
00674  * Hint Replacement:
00675  *  "Adobe Type 1 Font Format", Chapter 8.
00676  */
00677 static void
00678 do_othersubr3 (t1_chardesc *cd)
00679 {
00680   cd->flags |= T1_CS_FLAG_USE_HINTMASK;
00681 }
00682 
00683 static void
00684 do_othersubr12 (t1_chardesc *cd)
00685 {
00686   /* Othersubr12 call must immediately follow the hsbw or sbw. */
00687   if (phase != T1_CS_PHASE_INIT) {
00688     status = CS_PARSE_ERROR;
00689     return;
00690   }
00691   /* noop */
00692 }
00693 
00694 static void
00695 do_othersubr13 (t1_chardesc *cd)
00696 {
00697   t1_stemgroup stemgroups[CS_STEM_GROUP_MAX];
00698   int num_hgroups, num_vgroups, n, stem_id;
00699   double pos, del;
00700 
00701   /* After #12 callothersubr or hsbw or sbw. */
00702   if (phase != T1_CS_PHASE_INIT) {
00703     status = CS_PARSE_ERROR;
00704     return;
00705   }
00706   for (n = 0; n < CS_STEM_GROUP_MAX; n++) {
00707     stemgroups[n].num_stems = 0;
00708   }
00709 
00710   num_hgroups = (int) ps_arg_stack[--ps_stack_top];
00711   if (num_hgroups < 0 || num_hgroups > CS_STEM_GROUP_MAX) {
00712     status = CS_PARSE_ERROR;
00713     return;
00714   }
00715   n = 0; pos = 0.0;
00716   while (ps_stack_top >= 2 && n < num_hgroups) {
00717     /* add_stem() add sidebearing */
00718     pos += ps_arg_stack[--ps_stack_top];
00719     del  = ps_arg_stack[--ps_stack_top];
00720     stem_id = add_stem(cd,
00721                      (del < 0.0) ? pos + del : pos,
00722                      (del < 0.0) ? -del : del,
00723                      HSTEM);
00724     stemgroups[n].stems[stemgroups[n].num_stems] = stem_id;
00725     stemgroups[n].num_stems += 1;
00726     pos += del;
00727     if (del < 0.0) {
00728       pos = 0.0;
00729       n++;
00730     }
00731   }
00732   if (n != num_hgroups) {
00733     status = CS_STACK_ERROR;
00734     return;
00735   }
00736 
00737   num_vgroups = (int) ps_arg_stack[--ps_stack_top];
00738   if (num_vgroups < 0 || num_vgroups > CS_STEM_GROUP_MAX) {
00739     status = CS_PARSE_ERROR;
00740     return;
00741   }
00742   n = 0; pos = 0.0;
00743   while (ps_stack_top >= 2 && n < num_vgroups) {
00744     /* add_stem() add sidebearing */
00745     pos += ps_arg_stack[--ps_stack_top];
00746     del  = ps_arg_stack[--ps_stack_top];
00747     stem_id = add_stem(cd,
00748                      (del < 0.0) ? pos + del : pos,
00749                      (del < 0.0) ? -del : del,
00750                      VSTEM);
00751     stemgroups[n].stems[stemgroups[n].num_stems] = stem_id;
00752     stemgroups[n].num_stems += 1;
00753     pos += del;
00754     if (del < 0.0) {
00755       pos = 0.0;
00756       n++;
00757     }
00758   }
00759   if (n != num_vgroups) {
00760     status = CS_STACK_ERROR;
00761     return;
00762   }
00763 
00764   for (n = 0; n < MAX(num_hgroups, num_vgroups); n++) {
00765     add_charpath(cd, cs_cntrmask,
00766                stemgroups[n].stems, stemgroups[n].num_stems);
00767   }
00768 
00769   cd->flags |= T1_CS_FLAG_USE_CNTRMASK;
00770 }
00771 
00772 static void
00773 do_callothersubr (t1_chardesc *cd)
00774 {
00775   int argn, subrno;
00776 
00777   CHECKSTACK(2);
00778   subrno = (int) cs_arg_stack[--cs_stack_top];
00779   argn   = (int) cs_arg_stack[--cs_stack_top];
00780 
00781   CHECKSTACK(argn);
00782   if (ps_stack_top+argn > PS_ARG_STACK_MAX) {
00783     status = CS_PARSE_ERROR;
00784     return;
00785   }
00786   while (argn-- > 0)
00787     ps_arg_stack[ps_stack_top++] = cs_arg_stack[--cs_stack_top];
00788 
00789   switch (subrno) {
00790   case 0:  do_othersubr0(cd) ; break;
00791   case 1:  do_othersubr1(cd) ; break;
00792   case 2:  do_othersubr2(cd) ; break;
00793   case 3:  do_othersubr3(cd) ; break;
00794   case 12: do_othersubr12(cd); break;
00795   case 13: do_othersubr13(cd); break;
00796   default:
00797     ERROR("Unknown othersubr #%ld.", subrno);
00798     break;
00799   }
00800 }
00801 
00802 /*
00803  * Double byte operators:
00804  */
00805 static void
00806 do_operator2 (t1_chardesc *cd, card8 **data, card8 *endptr)
00807 {
00808   card8 op;
00809 
00810   *data += 1;
00811 
00812   SRC_NEED(endptr, *data + 1);
00813 
00814   op = **data;
00815   *data += 1;
00816 
00817   switch(op) {
00818   case cs_sbw:
00819     CHECKSTACK(4);
00820     cd->sbw.wy  = cs_arg_stack[--cs_stack_top];
00821     cd->sbw.wx  = cs_arg_stack[--cs_stack_top];
00822     cd->sbw.sby = cs_arg_stack[--cs_stack_top];
00823     cd->sbw.sbx = cs_arg_stack[--cs_stack_top];
00824     CLEARSTACK();
00825     break;
00826   case cs_hstem3:
00827   case cs_vstem3:
00828     /*
00829      * TODO:
00830      *  The counter control can be used for hstem3 and vstem3
00831      *  operator if LanguageGroup is not equal to 1.
00832      */
00833     CHECKSTACK(6);
00834     {
00835       int i;
00836       for (i = 2; i >= 0; i--) {
00837        int stem_id;
00838        stem_id = add_stem(cd,
00839                         cs_arg_stack[cs_stack_top-2*i-2],
00840                         cs_arg_stack[cs_stack_top-2*i-1],
00841                         ((op == cs_hstem3) ? HSTEM : VSTEM));
00842        if (stem_id < 0) {
00843          WARN("Too many hints...");
00844          status = CS_PARSE_ERROR;
00845          return;
00846        }
00847        /* Put stem_id onto the stack... */
00848        cs_arg_stack[cs_stack_top++] = stem_id;
00849        ADD_PATH(cd, CS_HINT_DECL, 1);
00850        cs_stack_top--;
00851       }
00852     }
00853     CLEARSTACK();
00854     break;
00855   case cs_setcurrentpoint:
00856     CHECKSTACK(2);
00857     /* noop */
00858     CLEARSTACK();
00859     break;
00860     /* all operator above are stack-clearing */
00861   case cs_pop:
00862     /*
00863      * Transfer a operand from PS interpreter operand stack to BuildChar
00864      * operand stack.
00865      */
00866     if (ps_stack_top < 1) {
00867       status = CS_PARSE_ERROR;
00868       return;
00869     }
00870     LIMITCHECK(1);
00871     cs_arg_stack[cs_stack_top++] = ps_arg_stack[--ps_stack_top];
00872     break;
00873   case cs_dotsection:
00874 #if 0
00875     /*
00876      * If the hint replacement feature is used in the font, the
00877      * "dotsection" operator exist only for compatibility to older
00878      * (more than 10 years old) Type 1 font rasterizer which can't
00879      * perform hint replacement. In this case, we silently ignore
00880      * the "dotsection" operator.
00881      *
00882      * The following code will wrongly warn about "dotsection" when
00883      * the charstring only contains dot (e.g., "bullet") where the
00884      * hint replacement is not necessary.
00885      *
00886      * Adobe ATM renderers always treat this operator as a no-op.
00887      * (See, Adobe Technical Note #5177, Appendix C)
00888      */
00889     if (!(cd->flags & T1_CS_FLAG_USE_HINTMASK)) {
00890       if (__verbose > 1)
00891        WARN("Obsolete Type 1 charstring operator \"dotsection\" not supported.");
00892     }
00893 #endif
00894     /* noop */
00895     break;
00896   case cs_div: /* TODO: check overflow */
00897     CHECKSTACK(2);
00898     cs_arg_stack[cs_stack_top-2] /= cs_arg_stack[cs_stack_top-1];
00899     cs_stack_top--;
00900     break;
00901   case cs_callothersubr:
00902     do_callothersubr(cd);
00903     break;
00904   case cs_seac:
00905     CHECKSTACK(5);
00906     cd->flags |= T1_CS_FLAG_USE_SEAC;
00907     cd->seac.achar = (card8) cs_arg_stack[--cs_stack_top];
00908     cd->seac.bchar = (card8) cs_arg_stack[--cs_stack_top];
00909     cd->seac.ady   = cs_arg_stack[--cs_stack_top];
00910     cd->seac.adx   = cs_arg_stack[--cs_stack_top];
00911     /* We must compensate the difference of the glyph origin. */
00912     cd->seac.ady += cd->sbw.sby;
00913     cd->seac.adx += cd->sbw.sbx - cs_arg_stack[--cs_stack_top];
00914     CLEARSTACK();
00915     break;
00916   default:
00917     /* no-op ? */
00918     WARN("Unknown charstring operator: 0x0c%02x", op);
00919     status = CS_PARSE_ERROR;
00920     break;
00921   }
00922 
00923   return;
00924 }
00925 
00926 /*
00927  * Charstring encoding:
00928  *  Copied from cs_type2.c
00929  *  Note:
00930  *   The Type 2 interpretation of a number encoded in five-bytes (those with
00931  *   an initial byte value of 255) differs from how it is interpreted in the
00932  *   Type 1 format.
00933  */
00934 
00935 /* Type 2 5-bytes encoding used. */
00936 static void
00937 put_numbers (double *argv, int argn, card8 **dest, card8 *limit)
00938 {
00939   int i;
00940 
00941   for (i = 0; i < argn; i++) {
00942     double value;
00943     long   ivalue;
00944     value  = argv[i];
00945     /* Nearest integer value */
00946     ivalue = (long) floor(value+0.5);
00947     if (value >= 0x8000L || value <= (-0x8000L - 1)) {
00948       /*
00949        * This number cannot be represented as a single operand.
00950        * We must use `a b mul ...' or `a c div' to represent large values.
00951        */
00952       ERROR("Argument value too large. (This is bug)");
00953     } else if (fabs(value - ivalue) > 3.0e-5) {
00954       /* 16.16-bit signed fixed value  */
00955       DST_NEED(limit, *dest + 5);
00956       *(*dest)++ = 255;
00957       ivalue = (long) floor(value); /* mantissa */
00958       *(*dest)++ = (ivalue >> 8) & 0xff;
00959       *(*dest)++ = ivalue & 0xff;
00960       ivalue = (long)((value - ivalue) * 0x10000l); /* fraction */
00961       *(*dest)++ = (ivalue >> 8) & 0xff;
00962       *(*dest)++ = ivalue & 0xff;
00963       /* Everything else are integers. */
00964     } else if (ivalue >= -107 && ivalue <= 107) {
00965       DST_NEED(limit, *dest + 1);
00966       *(*dest)++ = ivalue + 139;
00967     } else if (ivalue >= 108 && ivalue <= 1131) {
00968       DST_NEED(limit, *dest + 2);
00969       ivalue = 0xf700u + ivalue - 108;
00970       *(*dest)++ = (ivalue >> 8) & 0xff;
00971       *(*dest)++ = ivalue & 0xff;
00972     } else if (ivalue >= -1131 && ivalue <= -108) {
00973       DST_NEED(limit, *dest + 2);
00974       ivalue = 0xfb00u - ivalue - 108;
00975       *(*dest)++ = (ivalue >> 8) & 0xff;
00976       *(*dest)++ = ivalue & 0xff;
00977     } else if (ivalue >= -32768 && ivalue <= 32767) { /* shortint */
00978       DST_NEED(limit, *dest + 3);
00979       *(*dest)++ = 28;
00980       *(*dest)++ = (ivalue >> 8) & 0xff;
00981       *(*dest)++ = (ivalue) & 0xff;
00982     } else { /* Shouldn't come here */
00983       ERROR("Unexpected error.");
00984     }
00985   }
00986 
00987   return;
00988 }
00989 
00990 static void
00991 get_integer (card8 **data, card8 *endptr)
00992 {
00993   long result = 0;
00994   card8 b0 = **data, b1, b2;
00995 
00996   *data += 1;
00997 
00998   if (b0 == 28) { /* shortint */
00999     SRC_NEED(endptr, *data + 2);
01000     b1 = **data;
01001     b2 = *(*data+1);
01002     result = b1*256+b2;
01003     if (result > 0x7fff)
01004       result -= 0x10000L;
01005     *data += 2;
01006   } else if (b0 >= 32 && b0 <= 246) { /* int (1) */
01007     result = b0 - 139;
01008   } else if (b0 >= 247 && b0 <= 250) { /* int (2) */
01009     SRC_NEED(endptr, *data + 1);
01010     b1 = **data;
01011     result = (b0-247)*256+b1+108;
01012     *data += 1;
01013   } else if (b0 >= 251 && b0 <= 254) {
01014     SRC_NEED(endptr, *data + 1);
01015     b1 = **data;
01016     result = -(b0-251)*256-b1-108;
01017     *data += 1;
01018   } else {
01019     status = CS_PARSE_ERROR;
01020     return;
01021   }
01022 
01023   LIMITCHECK(1);
01024   cs_arg_stack[cs_stack_top++] = (double) result;
01025 
01026   return;
01027 }
01028 
01029 /* Type 1 */
01030 static void
01031 get_longint (card8 **data, card8 *endptr)
01032 {
01033   long result = 0;
01034   int  i;
01035 
01036   *data += 1;
01037   SRC_NEED(endptr, *data + 4);
01038   result = **data;
01039   if (result >= 0x80L)
01040     result -= 0x100L;
01041   *data += 1;
01042   for (i = 1; i < 4; i++) {
01043     result = result*256 + (**data);
01044     *data += 1;
01045   }
01046 
01047   LIMITCHECK(1);
01048   cs_arg_stack[cs_stack_top++] = (double) result;
01049 
01050   return;
01051 }
01052 
01053 /*
01054  * TODO:
01055  *  Check "seac"
01056  *   We cannot do backword parsing due to subroutine, div etc.
01057  */
01058 
01059 /* Parse charstring and build charpath. */
01060 static void
01061 t1char_build_charpath (t1_chardesc *cd,
01062                      card8 **data, card8 *endptr, cff_index *subrs)
01063 {
01064   card8 b0 = 0, *subr;
01065   long len;
01066 
01067   if (nest > CS_SUBR_NEST_MAX)
01068     ERROR("Subroutine nested too deeply.");
01069 
01070   nest++;
01071   while (*data < endptr && status == CS_PARSE_OK) {
01072     b0 = **data;
01073     if (b0 == 255) {
01074       get_longint(data, endptr); /* Type 1 */
01075     } else if (b0 == cs_return) {
01076       status = CS_SUBR_RETURN;
01077     } else if (b0 == cs_callsubr) {
01078       if (cs_stack_top < 1) {
01079        status = CS_STACK_ERROR;
01080       } else {
01081        int idx;
01082 
01083        idx = cs_arg_stack[--cs_stack_top];
01084        if (!subrs || idx >= subrs->count)
01085          ERROR("Invalid Subr#.");
01086        subr = subrs->data + subrs->offset[idx] - 1;
01087        len  = subrs->offset[idx+1] - subrs->offset[idx];
01088        t1char_build_charpath(cd, &subr, subr+len, subrs);
01089        *data += 1;
01090       }
01091     } else if (b0 == cs_escape) {
01092       do_operator2(cd, data, endptr);
01093     } else if (b0 < 32 && b0 != 28) { /* 19, 20 need mask */
01094       do_operator1(cd, data, endptr);
01095     } else if ((b0 <= 22 && b0 >= 27) || b0 == 31) { /* reserved */
01096       status = CS_PARSE_ERROR; /* not an error ? */
01097     } else { /* integer */
01098       get_integer(data, endptr);
01099     }
01100   }
01101 
01102   if (status == CS_SUBR_RETURN) {
01103     status = CS_PARSE_OK;
01104   } else if (status == CS_CHAR_END && *data < endptr) {
01105     if (!(*data == endptr - 1 && **data == cs_return))
01106       WARN("Garbage after endchar. (%ld bytes)", (long) (endptr - *data));
01107   } else if (status < CS_PARSE_OK) { /* error */
01108     ERROR("Parsing charstring failed: (status=%d, stack=%d)", status, cs_stack_top);
01109   }
01110 
01111   nest--;
01112 
01113   return;
01114 }
01115 
01116 /*
01117  * Calculate BoundingBox and compress path.
01118  *  The essentials of PDF size reduction is not Type 2 charstring compression
01119  *  but Type 1 charstring encryption. Encryption makes lossless compression
01120  *  useless. We will only do very simple charstring compression.
01121  */
01122 static void
01123 do_postproc (t1_chardesc *cd)
01124 {
01125   int i;
01126   t1_cpath *cur, *prev, *next;
01127   double x, y;
01128 
01129   if (!cd->charpath)
01130     return;
01131 
01132   /* Set dummy large value. */
01133   cd->bbox.llx = cd->bbox.lly =  100000.0;
01134   cd->bbox.urx = cd->bbox.ury = -100000.0;
01135 
01136   cur  = cd->charpath;
01137   prev = NULL;
01138   x = y = 0.0;
01139 
01140 #define UPDATE_BBOX(b,x,y) do {\
01141   if ((b).llx > (x)) (b).llx = (x);\
01142   if ((b).urx < (x)) (b).urx = (x);\
01143   if ((b).lly > (y)) (b).lly = (y);\
01144   if ((b).ury < (y)) (b).ury = (y);\
01145 } while (0)
01146 #define TRY_COMPACT (prev && cur && ((prev->num_args + cur->num_args) <= CS_ARG_STACK_MAX))
01147 
01148   while (cur != NULL) {
01149     next = cur->next;
01150     switch (cur->type) {
01151     case cs_rmoveto:
01152       x += cur->args[0]; y += cur->args[1];
01153       UPDATE_BBOX(cd->bbox, x, y);
01154       break;
01155     case cs_rlineto:
01156       x += cur->args[0]; y += cur->args[1];
01157       UPDATE_BBOX(cd->bbox, x, y);
01158       if (TRY_COMPACT) {
01159        if (prev->type == cs_rlineto) {
01160          copy_args(prev->args+prev->num_args, cur->args, cur->num_args);
01161          prev->num_args += cur->num_args;
01162          prev->next = next;
01163          RELEASE(cur); cur = NULL;
01164        } else if (prev->type == cs_rrcurveto) {
01165          copy_args(prev->args+prev->num_args, cur->args, cur->num_args);
01166          prev->num_args += cur->num_args;
01167          prev->type = cs_rcurveline;
01168          prev->next = next;
01169          RELEASE(cur); cur = NULL;
01170        }
01171       }
01172       break;
01173     case cs_hmoveto:
01174       x += cur->args[0];
01175       UPDATE_BBOX(cd->bbox, x, y);
01176       break;
01177     case cs_hlineto:
01178       x += cur->args[0];
01179       UPDATE_BBOX(cd->bbox, x, y);
01180       if (TRY_COMPACT) {
01181        if ((prev->type == cs_vlineto && (prev->num_args % 2) == 1) ||
01182            (prev->type == cs_hlineto && (prev->num_args % 2) == 0)) {
01183          copy_args(prev->args+prev->num_args, cur->args, cur->num_args);
01184          prev->num_args += cur->num_args;
01185          prev->next = next;
01186          RELEASE(cur); cur = NULL;
01187        }
01188       }
01189       break;
01190     case cs_vmoveto:
01191       y += cur->args[0];
01192       UPDATE_BBOX(cd->bbox, x, y);
01193       break;
01194     case cs_vlineto:
01195       y += cur->args[0];
01196       UPDATE_BBOX(cd->bbox, x, y);
01197       if (TRY_COMPACT) {
01198        if ((prev->type == cs_hlineto && (prev->num_args % 2) == 1) ||
01199            (prev->type == cs_vlineto && (prev->num_args % 2) == 0)) {
01200          copy_args(prev->args+prev->num_args, cur->args, cur->num_args);
01201          prev->num_args += cur->num_args;
01202          prev->next = next;
01203          RELEASE(cur); cur = NULL;
01204        }
01205       }
01206       break;
01207     case cs_rrcurveto:
01208       for (i = 0; i < 3; i++) {
01209        x += cur->args[2*i]; y += cur->args[2*i+1];
01210        UPDATE_BBOX(cd->bbox, x, y);
01211       }
01212       if (TRY_COMPACT) {
01213        if (prev->type == cs_rrcurveto) {
01214          copy_args(prev->args+prev->num_args, cur->args, cur->num_args);
01215          prev->num_args += cur->num_args;
01216          prev->next = next;
01217          RELEASE(cur); cur = NULL;
01218        } else if (prev->type == cs_rlineto) {
01219          copy_args(prev->args+prev->num_args, cur->args, cur->num_args);
01220          prev->num_args += cur->num_args;
01221          prev->type = cs_rlinecurve;
01222          prev->next = next;
01223          RELEASE(cur); cur = NULL;
01224        }
01225       }
01226       break;
01227     case cs_vhcurveto:
01228       y += cur->args[0];
01229       UPDATE_BBOX(cd->bbox, x, y);
01230       x += cur->args[1]; y += cur->args[2];
01231       UPDATE_BBOX(cd->bbox, x, y);
01232       x += cur->args[3];
01233       UPDATE_BBOX(cd->bbox, x, y);
01234       if (TRY_COMPACT) {
01235        if ((prev->type == cs_hvcurveto && ((prev->num_args / 4) % 2) == 1) ||
01236            (prev->type == cs_vhcurveto && ((prev->num_args / 4) % 2) == 0)) {
01237          copy_args(prev->args+prev->num_args, cur->args, cur->num_args);
01238          prev->num_args += cur->num_args;
01239          prev->next = next;
01240          RELEASE(cur); cur = NULL;
01241        }
01242       }
01243       break;
01244     case cs_hvcurveto:
01245       x += cur->args[0];
01246       UPDATE_BBOX(cd->bbox, x, y);
01247       x += cur->args[1]; y += cur->args[2];
01248       UPDATE_BBOX(cd->bbox, x, y);
01249       y += cur->args[3];
01250       UPDATE_BBOX(cd->bbox, x, y);
01251       if (TRY_COMPACT) {
01252        if ((prev->type == cs_vhcurveto && ((prev->num_args / 4) % 2) == 1) ||
01253            (prev->type == cs_hvcurveto && ((prev->num_args / 4) % 2) == 0)) {
01254          copy_args(prev->args+prev->num_args, cur->args, cur->num_args);
01255          prev->num_args += cur->num_args;
01256          prev->next = next;
01257          RELEASE(cur); cur = NULL;
01258        }
01259       }
01260       break;
01261     case cs_flex:
01262       for (i = 0; i < 6; i++) {
01263        x += cur->args[2*i]; y += cur->args[2*1+1];
01264        UPDATE_BBOX(cd->bbox, x, y);
01265       }
01266       if (cur->args[12] == 50.0) {
01267        if (cur->args[1] == 0.0 && cur->args[11] == 0.0 &&
01268            cur->args[5] == 0.0 && cur->args[7] == 0.0 &&
01269            cur->args[3] + cur->args[9] == 0.0) {
01270          /* cur->args[0] = cur->args[0];  dx1 */
01271          cur->args[1] = cur->args[2];  /* dx2 */
01272          cur->args[2] = cur->args[3];  /* dy2 */
01273          cur->args[3] = cur->args[4];  /* dx3 */
01274          cur->args[4] = cur->args[6];  /* dx4 */
01275          cur->args[5] = cur->args[8];  /* dx5 */
01276          cur->args[6] = cur->args[10]; /* dx6 */
01277          cur->num_args = 7;
01278          cur->type = cs_hflex;
01279        } else if (cur->args[5] == 0.0 && cur->args[7] == 0.0 &&
01280                  (cur->args[1] + cur->args[3] +
01281                   cur->args[9] + cur->args[11]) == 0) {
01282          /* cur->args[0] = cur->args[0];  dx1 */
01283          /* cur->args[1] = cur->args[1];  dy1 */
01284          /* cur->args[2] = cur->args[2];  dx2 */
01285          /* cur->args[3] = cur->args[3];  dy2 */
01286          /* cur->args[4] = cur->args[4];  dx3 */
01287          cur->args[5] = cur->args[6];  /* dx4 */
01288          cur->args[6] = cur->args[8];  /* dx5 */
01289          cur->args[7] = cur->args[9];  /* dy5 */
01290          cur->args[8] = cur->args[10]; /* dx6 */
01291          cur->num_args = 9;
01292          cur->type = cs_hflex1;
01293        }
01294       }
01295       break;
01296     case CS_HINT_DECL:
01297     case cs_cntrmask:
01298       /* noop */
01299       break;
01300     default:
01301       ERROR("Unexpected Type 2 charstring command %d.", cur->type);
01302       break;
01303     }
01304     if (cur != NULL)
01305       prev = cur;
01306     cur = next;
01307   }
01308 
01309   /* Had no path. Fix lower-left point. */
01310   if (cd->bbox.llx > cd->bbox.urx)
01311     cd->bbox.llx = cd->bbox.urx = cd->sbw.wx;
01312   if (cd->bbox.lly > cd->bbox.ury)
01313     cd->bbox.lly = cd->bbox.ury = cd->sbw.wy;
01314 
01315   return;
01316 }
01317 
01318 #define RESET_STATE() do {\
01319   status = CS_PARSE_OK;\
01320   phase  = T1_CS_PHASE_INIT;\
01321   nest   = 0;\
01322   ps_stack_top = 0;\
01323 } while (0)
01324 
01325 int
01326 t1char_get_metrics (card8 *src, long srclen, cff_index *subrs, t1_ginfo *ginfo)
01327 {
01328   t1_chardesc t1char, *cd;
01329 
01330   cd = &t1char;
01331   init_charpath(cd);
01332   RESET_STATE();
01333   CLEARSTACK();
01334   t1char_build_charpath(cd, &src, src+srclen, subrs);
01335   if (cs_stack_top != 0 || ps_stack_top != 0)
01336     WARN("Stack not empty. (%d, %d)", cs_stack_top, ps_stack_top);
01337   do_postproc(cd);
01338   if (ginfo) {
01339     ginfo->wx = cd->sbw.wx;
01340     ginfo->wy = cd->sbw.wy;
01341     ginfo->bbox.llx = cd->bbox.llx;
01342     ginfo->bbox.lly = cd->bbox.lly;
01343     ginfo->bbox.urx = cd->bbox.urx;
01344     ginfo->bbox.ury = cd->bbox.ury;
01345     if (cd->flags & T1_CS_FLAG_USE_SEAC) {
01346       ginfo->use_seac = 1;
01347       ginfo->seac.adx = cd->seac.adx;
01348       ginfo->seac.ady = cd->seac.ady;
01349       ginfo->seac.bchar = cd->seac.bchar;
01350       ginfo->seac.achar = cd->seac.achar;
01351     } else {
01352       ginfo->use_seac = 0;
01353     }
01354   }
01355   release_charpath(cd);
01356 
01357   return 0;
01358 }
01359 
01360 #define CHECK_BUFFER(n) if (dst+(n) >= endptr) {\
01361   ERROR("Buffer overflow.");\
01362 }
01363 #define CHECK_STATUS()  if (status != CS_PARSE_OK) {\
01364   ERROR("Charstring encoder error: %d", status);\
01365 }
01366 
01367 /*
01368  * Encode Charpath as a Type 2 Charstring
01369  */
01370 static long
01371 t1char_encode_charpath (t1_chardesc *cd,
01372                      double default_width, double nominal_width,
01373                      card8 *dst, card8 *endptr)
01374 {
01375   card8    *save;
01376   t1_cpath *curr;
01377 
01378   ASSERT(cd);
01379 
01380   save = dst;
01381   curr = cd->charpath;
01382 
01383   RESET_STATE();
01384   CLEARSTACK(); 
01385   /*
01386    * Advance Width
01387    */
01388   if (cd->sbw.wx != default_width) {
01389     double wx = cd->sbw.wx - nominal_width;
01390     put_numbers(&wx, 1, &dst, endptr);
01391     CHECK_STATUS();
01392   }
01393   /*
01394    * Hint Declaration
01395    */
01396   {
01397     int num_hstems = 0, num_vstems = 0;
01398     int i, reset = 1;
01399     double stem[2];
01400 
01401     for (i = 0; i < cd->num_stems && cd->stems[i].dir == HSTEM; i++) {
01402       num_hstems++;
01403       stem[0] = (reset ?
01404                (cd->stems[i].pos) :
01405                (cd->stems[i].pos - (cd->stems[i-1].pos + cd->stems[i-1].del)));
01406       stem[1] = cd->stems[i].del;
01407       put_numbers(stem, 2, &dst, endptr);
01408       CHECK_STATUS();
01409       reset = 0;
01410       if (2*num_hstems == CS_ARG_STACK_MAX) {
01411        CHECK_BUFFER(1);
01412        *dst++ = (card8) ((cd->flags & T1_CS_FLAG_USE_HINTMASK) ? cs_hstemhm : cs_hstem);
01413        reset = 1;
01414       }
01415     }
01416     if (reset == 0) {
01417       CHECK_BUFFER(1);
01418       *dst++ = (card8) ((cd->flags & T1_CS_FLAG_USE_HINTMASK) ? cs_hstemhm : cs_hstem);
01419     }
01420     reset = 1;
01421     if (cd->num_stems - num_hstems > 0) {
01422       for (i = num_hstems; i < cd->num_stems; i++) {
01423        num_vstems++;
01424        stem[0] = (reset ?
01425                  (cd->stems[i].pos) :
01426                  (cd->stems[i].pos - (cd->stems[i-1].pos + cd->stems[i-1].del)));
01427        stem[1] = cd->stems[i].del;
01428        put_numbers(stem, 2, &dst, endptr);
01429        CHECK_STATUS();
01430        reset = 0;
01431        if (2*num_vstems == CS_ARG_STACK_MAX) {
01432          CHECK_BUFFER(1);
01433          *dst++ = (card8) ((cd->flags & T1_CS_FLAG_USE_HINTMASK) ? cs_vstemhm : cs_vstem);
01434          reset = 1;
01435        }
01436       }
01437       if (reset == 0) {
01438        CHECK_BUFFER(1);
01439        if ((cd->flags & T1_CS_FLAG_USE_HINTMASK) ||
01440            (cd->flags & T1_CS_FLAG_USE_CNTRMASK)) {
01441          /*
01442           * The vstem hint operator can be ommited if hstem and vstem hints
01443           * are both declared at the beginning of a charstring, and is
01444           * followed directly by the hintmask or cntrmask operators.
01445           */
01446          if (curr->type != CS_HINT_DECL &&
01447              curr->type != cs_cntrmask) {
01448            *dst++ = (card8) cs_vstemhm;
01449          }
01450        } else {
01451          *dst++ = (card8) cs_vstem;
01452        }
01453       }
01454     }
01455   }
01456   /*
01457    * Path Construction and Hint Replacement
01458    */
01459   while (curr != NULL && curr->type != cs_endchar) {
01460     switch (curr->type) {
01461     case CS_HINT_DECL:
01462       {
01463        card8 hintmask[(CS_STEM_ZONE_MAX+7)/8];
01464 
01465        memset(hintmask, 0, (cd->num_stems+7)/8);
01466        while (curr != NULL && curr->type == CS_HINT_DECL) {
01467          int stem_idx;
01468 
01469          stem_idx = get_stem(cd, (int) curr->args[0]);
01470          ASSERT(stem_idx < cd->num_stems);
01471          hintmask[stem_idx/8] |= (1 << (7 - (stem_idx % 8)));
01472          curr = curr->next;
01473        }
01474        if (cd->flags & T1_CS_FLAG_USE_HINTMASK) {
01475          CHECK_BUFFER((cd->num_stems+7)/8 + 1);
01476          *dst++ = (card8) cs_hintmask;
01477          memcpy(dst, hintmask, (cd->num_stems+7)/8);
01478          dst += (cd->num_stems+7)/8;
01479        }
01480       }
01481       break;
01482     case cs_cntrmask:
01483       {
01484        card8 cntrmask[(CS_STEM_ZONE_MAX+7)/8];
01485        int   stem_idx, i;
01486 
01487        memset(cntrmask, 0, (cd->num_stems+7)/8);
01488        for (i = 0; i < curr->num_args; i++) {
01489          stem_idx = get_stem(cd, (int) curr->args[i]);
01490          ASSERT(stem_idx < cd->num_stems);
01491          cntrmask[stem_idx/8] |= (1 << (7 - (stem_idx % 8)));
01492        }
01493        CHECK_BUFFER((cd->num_stems+7)/8 + 1);
01494        *dst++ = (card8) cs_cntrmask;
01495        memcpy(dst, cntrmask, (cd->num_stems+7)/8);
01496        dst += (cd->num_stems+7)/8;
01497        curr = curr->next;
01498       }
01499       break;
01500     case cs_rmoveto: case cs_hmoveto: case cs_vmoveto:
01501     case cs_rlineto: case cs_hlineto: case cs_vlineto:
01502     case cs_rrcurveto:  case cs_hvcurveto: case cs_vhcurveto:
01503     case cs_rlinecurve: case cs_rcurveline:
01504       {
01505        put_numbers(curr->args, curr->num_args, &dst, endptr);
01506        CHECK_STATUS();
01507        CHECK_BUFFER(1);
01508        *dst++ = (card8) curr->type;
01509        curr = curr->next;
01510       }
01511       break;
01512     case cs_flex: case cs_hflex:
01513     case cs_hflex1:
01514       {
01515        put_numbers(curr->args, curr->num_args, &dst, endptr);
01516        CHECK_STATUS();
01517        CHECK_BUFFER(2);
01518        *dst++ = (card8) cs_escape;
01519        *dst++ = (card8) curr->type;
01520        curr = curr->next;
01521       }
01522       break;
01523     default:
01524       ERROR("Unknown Type 2 charstring command: %d", curr->type);
01525       break;
01526     }
01527   }
01528 
01529   /*
01530    * (adx ady bchar achar) endchar
01531    */
01532   if (cd->flags & T1_CS_FLAG_USE_SEAC) {
01533     double seac[4];
01534     seac[0] = cd->seac.adx;
01535     seac[1] = cd->seac.ady;
01536     seac[2] = cd->seac.bchar;
01537     seac[3] = cd->seac.achar;
01538     put_numbers(seac, 4, &dst, endptr);
01539     CHECK_STATUS();
01540     CHECK_BUFFER(2);
01541     WARN("Obsolete four arguments of \"endchar\" will be used for Type 1 \"seac\" operator.");
01542   }
01543   CHECK_BUFFER(1);
01544   *dst++ = (card8) cs_endchar;
01545 
01546   return (long) (dst - save);
01547 }
01548 
01549 long
01550 t1char_convert_charstring (card8 *dst, long dstlen,
01551                         card8 *src, long srclen, cff_index *subrs,
01552                         double default_width, double nominal_width,
01553                         t1_ginfo *ginfo)
01554 {
01555   long length;
01556   t1_chardesc t1char, *cd;
01557 
01558   cd = &t1char;
01559   init_charpath(cd);
01560   RESET_STATE();
01561   CLEARSTACK();
01562   t1char_build_charpath(cd, &src, src+srclen, subrs);
01563   if (cs_stack_top != 0 || ps_stack_top != 0)
01564     WARN("Stack not empty. (%d, %d)", cs_stack_top, ps_stack_top);
01565   do_postproc(cd);
01566   SORT_STEMS(cd);
01567 
01568   length = t1char_encode_charpath(cd, default_width, nominal_width, dst, dst+dstlen);
01569 
01570   if (ginfo) {
01571     ginfo->wx = cd->sbw.wx;
01572     ginfo->wy = cd->sbw.wy;
01573     ginfo->bbox.llx = cd->bbox.llx;
01574     ginfo->bbox.lly = cd->bbox.lly;
01575     ginfo->bbox.urx = cd->bbox.urx;
01576     ginfo->bbox.ury = cd->bbox.ury;
01577     if (cd->flags & T1_CS_FLAG_USE_SEAC) {
01578       ginfo->use_seac = 1;
01579       ginfo->seac.adx = cd->seac.adx;
01580       ginfo->seac.ady = cd->seac.ady;
01581       ginfo->seac.bchar = cd->seac.bchar;
01582       ginfo->seac.achar = cd->seac.achar;
01583     } else {
01584       ginfo->use_seac = 0;
01585     }
01586   }
01587   release_charpath(cd);
01588 
01589   return length;
01590 }