Back to index

tetex-bin  3.0
fontfcn.c
Go to the documentation of this file.
00001 /* $XConsortium: fontfcn.c,v 1.8 92/03/27 18:15:45 eswu Exp $ */
00002 /* Copyright International Business Machines,Corp. 1991
00003  * All Rights Reserved
00004  *
00005  * License to use, copy, modify, and distribute this software
00006  * and its documentation for any purpose and without fee is
00007  * hereby granted, provided that the above copyright notice
00008  * appear in all copies and that both that copyright notice and
00009  * this permission notice appear in supporting documentation,
00010  * and that the name of IBM not be used in advertising or
00011  * publicity pertaining to distribution of the software without
00012  * specific, written prior permission.
00013  *
00014  * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
00015  * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
00016  * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
00017  * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
00018  * THIRD PARTY RIGHTS.  THE ENTIRE RISK AS TO THE QUALITY AND
00019  * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
00020  * OR MAINTAIN, BELONGS TO THE LICENSEE.  SHOULD ANY PORTION OF
00021  * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
00022  * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION.  IN
00023  * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
00024  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
00025  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
00026  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00027  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00028  * SOFTWARE.
00029  */
00030 /* Author: Katherine A. Hitchcock    IBM Almaden Research Laboratory */
00031  
00032 #include <stdio.h>
00033 #include <string.h>
00034 #include <stdlib.h>
00035 
00036 #include "t1imager.h" 
00037 #include "util.h"
00038 #include "fontfcn.h"
00039 #include "fontmisc.h"
00040 #include "paths_rmz.h" 
00041 
00042 #include "../t1lib/parseAFM.h" 
00043 #include "../t1lib/t1types.h"
00044 #include "../t1lib/t1extern.h"
00045 #include "../t1lib/t1misc.h"
00046 #include "../t1lib/t1base.h"
00047 #include "../t1lib/t1finfo.h"
00048 
00049 extern xobject Type1Char(psfont *env, struct XYspace *S,
00050                       psobj *charstrP, psobj *subrsP,
00051                       psobj *osubrsP,
00052                       struct blues_struct *bluesP,
00053                       int *modeP, char *name,
00054                       float strokewidth );
00055 extern xobject Type1Line(psfont *env, struct XYspace *S,
00056                       float line_position,
00057                       float line_thickness,
00058                       float line_length,
00059                       float strokewidth);
00060 void objFormatName(psobj *objP, int length, char *valueP);
00061   
00062 extern void T1io_reset( void);
00063 
00064 #define BEZIERTYPE 0x10+0x02
00065 #define LINETYPE   0x10+0x00
00066 #define MOVETYPE   0x10+0x05
00067 
00068 #if 1
00069 struct region {
00070   XOBJ_COMMON           /* xobject common data define 3-26-91 PNM    */
00071   /* type = REGIONTYPE                         */
00072   struct fractpoint origin;    /* beginning handle:  X,Y origin of region      */
00073   struct fractpoint ending;    /* ending handle:  X,Y change after painting region */
00074   pel xmin,ymin;        /* minimum X,Y of region                        */
00075   pel xmax,ymax;        /* mat1_mum X,Y of region                        */
00076   struct edgelist *anchor;  /* list of edges that bound the region      */
00077   struct picture *thresholded;  /* region defined by thresholded picture*/
00078   /*
00079     Note that the ending handle and the bounding box values are stored
00080     relative to 'origin'.
00081     
00082     The above elements describe a region.  The following elements are
00083     scratchpad areas used while the region is being built:
00084   */
00085   fractpel lastdy;      /* direction of last segment                    */
00086   fractpel firstx,firsty;    /* starting point of current edge          */
00087   fractpel edgexmin,edgexmax;  /* x extent of current edge              */
00088   struct edgelist *lastedge,*firstedge;  /* last and first edges in subpath */
00089   pel *edge;            /* pointer to array of X values for edge        */
00090   fractpel edgeYstop;   /* Y value where 'edges' array ends             */
00091   int (*newedgefcn)();  /* function to use when building a new edge     */
00092   struct strokeinfo *strokeinfo;  /* scratchpad info during stroking only */
00093 } ;
00094 struct edgelist {
00095   XOBJ_COMMON          /* xobject common data define 3-26-91 PNM        */
00096   /* type = EDGETYPE                               */
00097   struct edgelist *link;  /* pointer to next in linked list             */
00098   struct edgelist *subpath;  /* informational link for "same subpath"   */
00099   pel xmin,xmax;        /* range of edge in X                           */
00100   pel ymin,ymax;        /* range of edge in Y                           */
00101   pel *xvalues;         /* pointer to ymax-ymin X values                */
00102 };
00103 #endif
00104 
00105 /***================================================================***/
00106 /*   GLOBALS                                                          */
00107 /***================================================================***/
00108 static char CurCharName[257]="";
00109 static char BaseCharName[257]="";
00110 char CurFontName[MAXPATHLEN];
00111 char *CurFontEnv;
00112 char *vm_base = NULL;
00113 
00114 static char notdef[]=".notdef";
00115 
00116 
00117 /* the following is inserted by RMz for VM checking and reallocating: */
00118 char *vm_used = NULL;
00119 extern int vm_init_count;
00120 extern int vm_init_amount;
00121 
00122 static psfont *FontP = NULL;
00123 psfont TheCurrentFont;
00124  
00125  
00126 /***================================================================***/
00127 /*   SearchDict - look for  name                                      */
00128 /*              - compare for match on len and string                 */
00129 /*                return 0 - not found.                               */
00130 /*                return n - nth element in dictionary.               */
00131 /***================================================================***/
00132 int SearchDictName(dictP,keyP)
00133  psdict *dictP;
00134  psobj  *keyP;
00135 {
00136   int i,n;
00137  
00138  
00139   n =  dictP[0].key.len;
00140   for (i=1;i<=n;i++) {          /* scan the intire dictionary */
00141     if (
00142         (dictP[i].key.len  == keyP->len )
00143         &&
00144         (strncmp(dictP[i].key.data.valueP,
00145                  keyP->data.valueP,
00146                  keyP->len) == 0
00147         )
00148        ) return(i);
00149   }
00150   return(0);
00151 }
00152 /***================================================================***/
00153 /* assignment of &TheCurrentFont removed by RMz:
00154  */
00155 boolean initFont()
00156 {
00157   if (!(vm_init())) return(FALSE);
00158   vm_base = vm_next_byte();
00159   strcpy(CurFontName, "");    /* iniitialize to none */
00160   FontP->vm_start = vm_next_byte();
00161   FontP->FontFileName.len = 0;
00162   FontP->FontFileName.data.valueP = CurFontName;
00163   return(TRUE);
00164 }
00165 /***================================================================***/
00166 int resetFont(env)
00167 char *env;
00168 {
00169  
00170   vm_next =  FontP->vm_start;
00171   vm_free = vm_size - ( vm_next - vm_base);
00172   FontP->Subrs.len = 0;
00173   FontP->Subrs.data.stringP = NULL;
00174   FontP->CharStringsP = NULL;
00175   FontP->Private = NULL;
00176   FontP->fontInfoP = NULL;
00177   FontP->BluesP = NULL;
00178   /* This will load the font into the FontP */
00179   strncpy(CurFontName,env, MAXPATHLEN);
00180   CurFontName[MAXPATHLEN-1] = '\0';
00181   FontP->FontFileName.len = strlen(CurFontName);
00182   FontP->FontFileName.data.nameP = CurFontName;
00183   T1io_reset();
00184 
00185   return(0);
00186   
00187 }
00188 /***================================================================***/
00189 /* Read font used to attempt to load the font and, upon failure, 
00190    try a second time with twice as much memory.  Unfortunately, if
00191    it's a really complex font, simply using 2*vm_size may be insufficient.
00192    I've modified it so that the program will try progressively larger
00193    amounts of memory until it really runs out or the font loads
00194    successfully. (ndw)
00195 */
00196 int readFont(env)
00197 char *env;
00198 {
00199   int rcode;
00200   /* int memscale = 2; */ /* initially, try twice just like we used to ... */
00201  
00202   /* restore the virtual memory and eliminate old font */
00203   
00204   resetFont(env);
00205   /* This will load the font into the FontP */
00206  
00207   rcode = scan_font(FontP);
00208   return(rcode);
00209 }
00210 
00211 
00212 static int isCompositeChar( int FontID,
00213                          char *charname) 
00214 {
00215   int i;
00216   FontInfo *pAFMData;
00217   
00218   if (pFontBase->pFontArray[FontID].pAFMData==NULL) {
00219     /* No AFM data present */
00220     return( -1);
00221   }
00222 
00223   pAFMData=pFontBase->pFontArray[FontID].pAFMData;
00224   for ( i=0; i<pAFMData->numOfComps; i++) {
00225     if (strcmp( pAFMData->ccd[i].ccName, charname)==0)
00226       return( i);
00227   }
00228   
00229   return( -1);
00230   
00231 }
00232 
00233 
00234 
00235 /* dump a description of path elements to stdout */
00236 static T1_PATHPOINT getDisplacement( struct segment *path)
00237 {
00238 
00239   register struct segment *ipath;
00240   register struct beziersegment *ibpath;
00241   T1_PATHPOINT point={0,0};
00242   
00243   /* Step through the path list */
00244   ipath=(struct segment *)path;
00245   
00246   do {
00247     if (ipath->type==LINETYPE) {
00248       point.x+=ipath->dest.x;
00249       point.y+=ipath->dest.y;
00250     }
00251     else if (ipath->type==MOVETYPE) {
00252       point.x+=ipath->dest.x;
00253       point.y+=ipath->dest.y;
00254     }
00255     else if (ipath->type==BEZIERTYPE) {
00256       ibpath=(struct beziersegment *)ipath;
00257       point.x+=ibpath->dest.x;
00258       point.y+=ibpath->dest.y;
00259     }
00260     ipath=ipath->link;
00261   } while (ipath!=NULL);
00262   return( point);
00263   
00264 }
00265 
00266 
00267 
00268 /***================================================================***/
00269 /* RMz: instead of code, which is a character pointer to the name
00270         of the character, we use "ev" which is a pointer to a desired
00271        encoding vector (or NULL if font-internal encoding should be
00272        used) and "index" as an index into the desired encoding vector!
00273        The user thus has the opportunity of supplying whatever encoding
00274        he wants. Font_Ptr is the pointer to the local psfont-structure. 
00275        */
00276 
00277 xobject fontfcnB(int FontID, int modflag,
00278                struct XYspace *S, char **ev,
00279                unsigned char index, int *mode,
00280                psfont *Font_Ptr,
00281                int do_raster,
00282                float strokewidth)
00283 {
00284  
00285   psobj *charnameP; /* points to psobj that is name of character*/
00286   FontInfo *pAFMData=NULL;
00287   int i=-1;
00288   int j=0;
00289   int numPieces=1;
00290   int N;
00291   T1_PATHPOINT currdisp;
00292   int basechar;
00293   
00294   psdict *CharStringsDictP; /* dictionary with char strings     */
00295   psobj   CodeName;   /* used to store the translation of the name*/
00296   psobj  *SubrsArrayP;
00297   psobj  *theStringP;
00298   int localmode=0;
00299   
00300   struct segment *charpath=NULL;   /* the path for this character   */           
00301   struct segment *tmppath1=NULL;
00302   struct segment *tmppath2=NULL;
00303   struct segment *tmppath3=NULL;
00304   struct segment *tmppath4=NULL;
00305   
00306    
00307   /* set the global font pointer to the address of already allocated
00308      structure and setup pointers*/
00309   FontP=Font_Ptr;
00310   CharStringsDictP =  FontP->CharStringsP;
00311   SubrsArrayP = &(FontP->Subrs);
00312   charnameP = &CodeName;
00313 
00314   if (ev==NULL){  /* font-internal encoding should be used */
00315     charnameP->len = FontP->fontInfoP[ENCODING].value.data.arrayP[index].len;
00316     charnameP->data.stringP = (unsigned char *) FontP->fontInfoP[ENCODING].value.data.arrayP[index].data.arrayP;
00317   }
00318   else{           /* some user-supplied encoding is to be used */
00319     charnameP->len = strlen(ev[index]);
00320     charnameP->data.stringP = (unsigned char *) ev[index];
00321   }
00322   strncpy( (char *)CurCharName, (char *)charnameP->data.stringP, charnameP->len);
00323   CurCharName[charnameP->len]='\0';
00324   
00325  
00326   /* search the chars string for this charname as key */
00327   basechar = SearchDictName(CharStringsDictP,charnameP);
00328   if (basechar<=0) {
00329     /* Check first, whether a char in question is a composite char */
00330     if ((i=isCompositeChar( FontID, CurCharName))>-1) {
00331       /* i is now the index of the composite char definitions
00332         (starting at 0). At this point it is clear that AFM-info
00333         must be present -> fetch first component of composite char. */
00334       pAFMData=pFontBase->pFontArray[FontID].pAFMData;
00335       charnameP->len=strlen( pAFMData->ccd[i].pieces[0].pccName);
00336       charnameP->data.stringP=(unsigned char*)pAFMData->ccd[i].pieces[0].pccName;
00337       numPieces=pAFMData->ccd[i].numOfPieces;
00338       
00339       if ((basechar=SearchDictName(CharStringsDictP,charnameP))<=0) {
00340        /* this is bad, AFM-file and font file do not match. This 
00341           will most probably lead to errors or inconsistencies later.
00342           However, we substitute .notdef and inform the user via
00343           logfile and T1_errno. */
00344        sprintf( err_warn_msg_buf,
00345                "Charstring \"%s\" needed to construct composite char \"%s\" not defined (FontID=%d)",
00346                pAFMData->ccd[i].pieces[0].pccName,
00347                pAFMData->ccd[i].ccName, FontID);
00348        T1_PrintLog( "fontfcnB():", err_warn_msg_buf, T1LOG_WARNING);
00349        T1_errno=T1ERR_COMPOSITE_CHAR;
00350       }
00351     }
00352   }
00353   
00354   if (basechar<=0) { /* This  means the requested char is unknown or the
00355                      base char of a composite is not found ->
00356                      we substitute .notdef */
00357     charnameP = &CodeName;
00358     charnameP->len = 7;
00359     charnameP->data.stringP = (unsigned char *) notdef;
00360     basechar = SearchDictName(CharStringsDictP,charnameP);
00361     localmode=FF_NOTDEF_SUBST;
00362     /* Font must be completely damaged if it doesn't define a .notdef */
00363     if (basechar<=0) {
00364       *mode=FF_PARSE_ERROR;
00365       return(NULL);
00366     }
00367   } /* if (basechar<=0) */
00368   /* basechar is now the index of the base character in the CharStrings
00369      dictionary */
00370 
00371   /* we provide the Type1Char() procedure with the name of the character
00372      to rasterize for debugging purposes */
00373   strncpy( (char *)CurCharName, (char *)charnameP->data.stringP, charnameP->len);
00374   CurCharName[charnameP->len]='\0';
00375   /* get CharString and character path */
00376   theStringP = &(CharStringsDictP[basechar].value);
00377   tmppath2 = (struct segment *) Type1Char(FontP,S,theStringP,SubrsArrayP,NULL,
00378                                      FontP->BluesP,mode,CurCharName,strokewidth);
00379   /* if Type1Char reported an error, then return */
00380   if ( *mode == FF_PARSE_ERROR || *mode==FF_PATH_ERROR)
00381     return(NULL);
00382   
00383   /* Defer rastering to later, we first have to handle the composite
00384      symbols */
00385   for (j=1; j<numPieces; j++) {
00386     /* get composite symbol name */
00387     charnameP->len=strlen( pAFMData->ccd[i].pieces[j].pccName);
00388     charnameP->data.stringP=(unsigned char*)pAFMData->ccd[i].pieces[j].pccName;
00389     /* get CharString definition */
00390     if ((N=SearchDictName(CharStringsDictP,charnameP))<=0) {
00391       /* handling of errors, see comments above ... */
00392       sprintf( err_warn_msg_buf,
00393               "Charstring \"%s\" needed to construct composite char \"%s\" not defined (FontID=%d)",
00394               pAFMData->ccd[i].pieces[j].pccName,
00395               pAFMData->ccd[i].ccName, FontID);
00396       T1_PrintLog( "fontfcnB():", err_warn_msg_buf, T1LOG_WARNING);
00397       charnameP = &CodeName;
00398       charnameP->len = 7;
00399       charnameP->data.stringP = (unsigned char *) notdef;
00400       N = SearchDictName(CharStringsDictP,charnameP);
00401       localmode=FF_NOTDEF_SUBST;
00402       /* damaged Font */
00403       if (N<=0) {
00404        *mode=FF_PARSE_ERROR;
00405        if (charpath!=NULL) {
00406          KillPath( charpath);
00407        }
00408        return(NULL);
00409       }
00410     }
00411     theStringP = &(CharStringsDictP[N].value);
00412     tmppath1=(struct segment *)ILoc(S,
00413                                 pAFMData->ccd[i].pieces[j].deltax,
00414                                 pAFMData->ccd[i].pieces[j].deltay);
00415     
00416     strncpy( (char *)CurCharName, (char *)charnameP->data.stringP, charnameP->len);
00417     CurCharName[charnameP->len]='\0';
00418     charpath=(struct segment *)Type1Char(FontP,S,theStringP,SubrsArrayP,NULL,
00419                                     FontP->BluesP,mode,CurCharName,strokewidth);
00420     /* return if Type1Char reports an error */
00421     if ( *mode == FF_PARSE_ERROR || *mode==FF_PATH_ERROR)
00422       return(NULL);
00423     /* get escapement of current symbol */
00424     currdisp=getDisplacement( charpath);
00425     /* concat displacement and symbol path */
00426     charpath=(struct segment *)Join(tmppath1,charpath);
00427     /* for composite symbols we have to step back the char escapement.
00428        this is, in order to be able to use accents that cause a
00429        non zero displacement of the current point! We further have to
00430        step back the displacement from composite char data. */
00431     tmppath1=(struct segment *)t1_PathSegment( MOVETYPE, -currdisp.x, -currdisp.y);
00432     tmppath3=(struct segment *)ILoc(S,
00433                                 -pAFMData->ccd[i].pieces[j].deltax,
00434                                 -pAFMData->ccd[i].pieces[j].deltay);
00435     tmppath3=(struct segment *)Join(tmppath1,tmppath3);
00436     /* create path, or, respectively, append to existing path */
00437     if (tmppath4==NULL) {
00438       tmppath4=(struct segment *)Join(charpath,tmppath3);
00439     }
00440     else {
00441       charpath=(struct segment *)Join(charpath,tmppath3);
00442       tmppath4=(struct segment *)Join(tmppath4,charpath);
00443     }
00444   }
00445 
00446   /* concat composite symbols and base char */
00447   if (tmppath4==NULL) { /* no previous composite symbols */
00448     charpath=tmppath2; /* a simple char */
00449   }
00450   else { 
00451     charpath=(struct segment *)Join(tmppath4,tmppath2);
00452   }
00453   
00454   
00455   if (do_raster) { 
00456     /* fill with winding rule unless path was requested */
00457     if (*mode != FF_PATH) {
00458       charpath =  (struct segment *)Interior(charpath,WINDINGRULE+CONTINUITY);
00459     }
00460   }
00461 
00462   if (*mode==0)
00463     *mode=localmode;
00464   
00465   return((xobject) charpath);
00466 }
00467 
00468 
00469 
00470 
00471 /***================================================================***/
00472 /*   fontfcnA(env, mode)                                              */
00473 /*                                                                    */
00474 /*          env is a pointer to a string that contains the fontname.  */
00475 /*                                                                    */
00476 /*     1) initialize the font     - global indicates it has been done */
00477 /*     2) load the font                                               */
00478 /*                                                                    */
00479 /* This function has been modified by RMz. It now takes a pointer which
00480    already contains the address of a valid type1 font structure as the
00481    third argument. The value of this pointer is first handed to FontP
00482    so that most other routines may be used without changes */
00483 
00484 #define MAXTRIAL              4
00485 
00486 /***================================================================***/
00487 Bool fontfcnA(env,mode,Font_Ptr)
00488 char *env;
00489 int  *mode;
00490 psfont *Font_Ptr;
00491 
00492 {
00493   int i, result;
00494   
00495   /* set the global font pointer to the address of already allocated
00496      structure */
00497   FontP=Font_Ptr;
00498 
00499   InitImager();
00500 
00501   /* Read the font program. */
00502   for (i=1; i<MAXTRIAL; i++){
00503     vm_init_count=0;
00504     /* We allocate larger chunks (4*65536 Bytes) in order to reduce load
00505        time for large fonts by initially requesting somewhat more
00506        memory. */
00507     vm_init_amount=MAX_STRING_LEN * 4 * i;
00508     if (!(initFont())) {
00509       /* we are really out of memory, not simulated! */
00510       *mode = SCAN_OUT_OF_MEMORY;
00511       return(FALSE);
00512     }
00513     /* Try to read font into memory */
00514     if ((result=readFont(env))==0){
00515       /* In order to get the amount of memory that was really used */      
00516       vm_used=vm_next_byte();
00517       return(TRUE);
00518     }
00519     else{
00520       /* VM did not suffice, free it and try again with larger
00521         value: */
00522       free(vm_base);
00523     }
00524   }
00525   /* Font could not be loaded: */
00526   *mode = result;
00527   return(FALSE);
00528 
00529 }
00530 
00531 
00532 /***================================================================***/
00533 /*   QueryFontLib(env, infoName,infoValue,rcodeP)                     */
00534 /*                                                                    */
00535 /*          env is a pointer to a string that contains the fontname.  */
00536 /*                                                                    */
00537 /*     1) initialize the font     - global indicates it has been done */
00538 /*     2) load the font                                               */
00539 /*     3) use the font to call getInfo for that value.                */
00540 /***================================================================***/
00541 
00542 void QueryFontLib(env,infoName,infoValue,rcodeP)
00543 char *env;
00544 char *infoName;
00545 pointer infoValue;    /* parameter returned here    */
00546 int  *rcodeP;
00547 {
00548 
00549   int rc,N,i;
00550   psdict *dictP;
00551   psobj  nameObj;
00552   psobj  *valueP;
00553  
00554   /* Has the FontP initialized?  If not, then   */
00555   /* Initialize  */
00556   if (FontP == NULL) {
00557     InitImager();
00558     if (!(initFont())) {
00559       *rcodeP = 1;
00560       return;
00561     }
00562   }
00563   /* if the env is null, then use font already loaded */
00564   /* if the not same font name, reset and load next font */
00565   if ( (env) && (strcmp(env,CurFontName) != 0 ) ) {
00566     /* restore the virtual memory and eliminate old font */
00567     rc = readFont(env);
00568     if (rc != 0 ) {
00569       strcpy(CurFontName, "");    /* no font loaded */
00570       *rcodeP = 1;
00571       return;
00572     }
00573   }
00574   dictP = FontP->fontInfoP;
00575   objFormatName(&nameObj,strlen(infoName),infoName);
00576   N = SearchDictName(dictP,&nameObj);
00577   /* if found */
00578   if ( N > 0 ) {
00579     *rcodeP = 0;
00580     switch (dictP[N].value.type) {
00581        case OBJ_ARRAY:
00582          valueP = dictP[N].value.data.arrayP;
00583          if (strcmp(infoName,"FontMatrix") == 0) {
00584            /* 6 elments, return them as floats      */
00585            for (i=0;i<6;i++) {
00586              if (valueP->type == OBJ_INTEGER )
00587                ((float *)infoValue)[i] = valueP->data.integer;
00588              else
00589                ((float *)infoValue)[i] = valueP->data.real;
00590             valueP++;
00591            }
00592          }
00593          if (strcmp(infoName,"FontBBox") == 0) {
00594            /* 4 elments for Bounding Box.  all integers   */
00595            for (i=0;i<4;i++) {
00596              ((int *)infoValue)[i] = valueP->data.integer;
00597              valueP++;
00598            }
00599          break;
00600        case OBJ_INTEGER:
00601        case OBJ_BOOLEAN:
00602          *((int *)infoValue) = dictP[N].value.data.integer;
00603          break;
00604        case OBJ_REAL:
00605          *((float *)infoValue) = dictP[N].value.data.real;
00606          break;
00607        case OBJ_NAME:
00608        case OBJ_STRING:
00609          *((char **)infoValue) =  dictP[N].value.data.valueP;
00610          break;
00611        default:
00612          *rcodeP = 1;
00613          break;
00614      }
00615    }
00616   }
00617   else *rcodeP = 1;
00618 }
00619 
00620 
00621 /***================================================================***/
00622 /* RMz: instead of code, which is a character pointer to the name
00623         of the character, we use "ev" which is a pointer to a desired
00624        encoding vector (or NULL if font-internal encoding should be
00625        used) and "index" as an index into the desired encoding vector!
00626        The user thus has the opportunity of supplying whatever encoding
00627        he wants. Font_Ptr is the pointer to the local psfont-structure. 
00628        */
00629 xobject fontfcnB_string( int FontID, int modflag,
00630                       struct XYspace *S, char **ev,
00631                       unsigned char *string, int no_chars,
00632                       int *mode, psfont *Font_Ptr,
00633                       int *kern_pairs, long spacewidth,
00634                       int do_raster,
00635                       float strokewidth)
00636 {
00637  
00638   psobj *charnameP; /* points to psobj that is name of character*/
00639   FontInfo *pAFMData=NULL;
00640   int i=-1;
00641   int j=0;
00642   int k=0;
00643   long acc_width=0;
00644   int numPieces=1;
00645   int N;
00646   T1_PATHPOINT currdisp;
00647   int basechar;
00648   
00649   psdict *CharStringsDictP; /* dictionary with char strings     */
00650   psobj   CodeName;   /* used to store the translation of the name*/
00651   psobj  *SubrsArrayP;
00652   psobj  *theStringP;
00653   int localmode=0;
00654   
00655   struct segment *charpath=NULL;   /* the path for this character   */           
00656   struct segment *tmppath1=NULL;
00657   struct segment *tmppath2=NULL;
00658   struct segment *tmppath3=NULL;
00659   struct segment *tmppath4=NULL;
00660   struct segment *tmppath5=NULL;
00661   
00662    
00663   /* set the global font pointer to the address of already allocated
00664      structure and setup pointers*/
00665   FontP=Font_Ptr;
00666   CharStringsDictP =  FontP->CharStringsP;
00667   SubrsArrayP = &(FontP->Subrs);
00668   charnameP = &CodeName;
00669 
00670   
00671   /* In the following for-loop, all characters are processed, one after
00672      the other. Between them, the amount of kerning is inserted.
00673      The number of path variables used is somewhat numerous. We use the
00674      follwing conventions:
00675 
00676      charpath:  the overall path of the string.
00677      tmppath5:  the overall path of one component (possibly a composite symbol)
00678      tmppath2:  the path of a simple char or base char of a composite
00679      tmppath4:  the path of all "accents" of a composite symbol
00680   */
00681   for (k=0; k<no_chars;k++) {
00682     if (ev==NULL){  /* font-internal encoding should be used */
00683       charnameP = &CodeName;
00684       charnameP->len = FontP->fontInfoP[ENCODING].value.data.arrayP[string[k]].len;
00685       charnameP->data.stringP = (unsigned char *) FontP->fontInfoP[ENCODING].value.data.arrayP[string[k]].data.arrayP;
00686     }
00687     else {           /* some user-supplied encoding is to be used */
00688       charnameP = &CodeName;
00689       charnameP->len = strlen(ev[string[k]]);
00690       charnameP->data.stringP = (unsigned char*) ev[string[k]];
00691     }
00692     
00693     /* Spacing is to be under users control: => if space is the charname, don't
00694        raster it. Rather, generate a horizontal movement of spacewidth: */
00695     if (strcmp((char *)charnameP->data.stringP, "space")==0){
00696       tmppath5=(struct segment *)ILoc(S, spacewidth,0);
00697       acc_width += spacewidth;
00698     }
00699     else {
00700       /* here a character or composite character is to be constructed */
00701       strncpy( (char *)CurCharName, (char *)charnameP->data.stringP, charnameP->len);
00702       CurCharName[charnameP->len]='\0';
00703       
00704       /* search the CharString for this charname as key */
00705       basechar = SearchDictName(CharStringsDictP,charnameP);
00706       if (basechar<=0) {
00707        /* Check first, whether a char in question is a composite char */
00708        if ((i=isCompositeChar( FontID, CurCharName))>-1) {
00709          /* i is now the index of the composite char definitions
00710             (starting at 0). At this point it is clear that AFM-info
00711             must be present -> fetch first component of composite char. */
00712          pAFMData=pFontBase->pFontArray[FontID].pAFMData;
00713          charnameP->len=strlen( pAFMData->ccd[i].pieces[0].pccName);
00714          charnameP->data.stringP=(unsigned char*)pAFMData->ccd[i].pieces[0].pccName;
00715          numPieces=pAFMData->ccd[i].numOfPieces;
00716          
00717          if ((basechar=SearchDictName(CharStringsDictP,charnameP))<=0) {
00718            /* this is bad, AFM-file and font file do not match. This 
00719               will most probably lead to errors or inconsistencies later.
00720               However, we substitute .notdef and inform the user via
00721               logfile and T1_errno. */
00722            sprintf( err_warn_msg_buf,
00723                    "Charstring \"%s\" needed to construct composite char \"%s\" not defined (FontID=%d)",
00724                    pAFMData->ccd[i].pieces[0].pccName,
00725                    pAFMData->ccd[i].ccName, FontID);
00726            T1_PrintLog( "fontfcnB():", err_warn_msg_buf, T1LOG_WARNING);
00727            T1_errno=T1ERR_COMPOSITE_CHAR;
00728          }
00729        }
00730       }
00731       
00732       if (basechar<=0) { /* This  means the requested char is unknown or the
00733                          base char of a composite is not found ->
00734                          we substitute .notdef */
00735        charnameP = &CodeName;
00736        charnameP->len = 7;
00737        charnameP->data.stringP = (unsigned char *) notdef;
00738        basechar = SearchDictName(CharStringsDictP,charnameP);
00739        localmode=FF_NOTDEF_SUBST;
00740        /* Font must be completely damaged if it doesn't define a .notdef */
00741        if (basechar<=0) {
00742          *mode=FF_PARSE_ERROR;
00743          return(NULL);
00744        }
00745       } /* if (basechar<=0) */
00746       /* basechar is now the index of the base character in the CharStrings
00747         dictionary */
00748       
00749       /* we provide the Type1Char() procedure with the name of the character
00750         to rasterize for debugging purposes */
00751       strncpy( (char *)CurCharName, (char *)charnameP->data.stringP, charnameP->len);
00752       CurCharName[charnameP->len]='\0';
00753       /* get CharString and character path */
00754       theStringP = &(CharStringsDictP[basechar].value);
00755       tmppath2 = (struct segment *) Type1Char(FontP,S,theStringP,SubrsArrayP,NULL,
00756                                          FontP->BluesP,mode,CurCharName,strokewidth);
00757       strcpy( BaseCharName, CurCharName);
00758       /* if Type1Char reports an error, clean up and return */
00759       if ( *mode == FF_PARSE_ERROR || *mode==FF_PATH_ERROR) {
00760        if (charpath!=NULL) {
00761          KillPath( charpath);
00762        }
00763        if (tmppath1!=NULL) {
00764          KillPath( tmppath1);
00765        }
00766        if (tmppath2!=NULL) {
00767          KillPath( tmppath2);
00768        }
00769        if (tmppath3!=NULL) {
00770          KillPath( tmppath3);
00771        }
00772        if (tmppath4!=NULL) {
00773          KillPath( tmppath4);
00774        }
00775        if (tmppath5!=NULL) {
00776          KillPath( tmppath5);
00777        }
00778        return(NULL);
00779       }
00780        
00781       /* Defer rastering to later, we first have to handle the composite
00782         symbols */
00783       for (j=1; j<numPieces; j++) {
00784        /* get composite symbol name */
00785        charnameP->len=strlen( pAFMData->ccd[i].pieces[j].pccName);
00786        charnameP->data.stringP=(unsigned char*)pAFMData->ccd[i].pieces[j].pccName;
00787        /* get CharString definition */
00788        if ((N=SearchDictName(CharStringsDictP,charnameP))<=0) {
00789          /* handling of errors, see comments above ... */
00790          sprintf( err_warn_msg_buf,
00791                  "Charstring \"%s\" needed to construct composite char \"%s\" not defined (FontID=%d)",
00792                  pAFMData->ccd[i].pieces[j].pccName,
00793                  pAFMData->ccd[i].ccName, FontID);
00794          T1_PrintLog( "fontfcnB():", err_warn_msg_buf, T1LOG_WARNING);
00795          charnameP = &CodeName;
00796          charnameP->len = 7;
00797          charnameP->data.stringP = (unsigned char *) notdef;
00798          N = SearchDictName(CharStringsDictP,charnameP);
00799          localmode=FF_NOTDEF_SUBST;
00800          /* an undefined .notdef is fatal -> clean up and return */
00801          if (N<=0) {
00802            *mode=FF_PARSE_ERROR;
00803            if (charpath!=NULL) {
00804              KillPath( charpath);
00805            }
00806            if (tmppath1!=NULL) {
00807              KillPath( tmppath1);
00808            }
00809            if (tmppath2!=NULL) {
00810              KillPath( tmppath2);
00811            }
00812            if (tmppath3!=NULL) {
00813              KillPath( tmppath3);
00814            }
00815            if (tmppath4!=NULL) {
00816              KillPath( tmppath4);
00817            }
00818            if (tmppath5!=NULL) {
00819              KillPath( tmppath5);
00820            }
00821            return(NULL);
00822          }
00823        }
00824        theStringP = &(CharStringsDictP[N].value);
00825        tmppath1=(struct segment *)ILoc(S,
00826                                    pAFMData->ccd[i].pieces[j].deltax,
00827                                    pAFMData->ccd[i].pieces[j].deltay);
00828     
00829        strncpy( (char *)CurCharName, (char *)charnameP->data.stringP, charnameP->len);
00830        CurCharName[charnameP->len]='\0';
00831        tmppath5=(struct segment *)Type1Char(FontP,S,theStringP,SubrsArrayP,NULL,
00832                                         FontP->BluesP,mode,CurCharName,strokewidth);
00833        /* return if Type1Char reports an error */
00834        if ( *mode == FF_PARSE_ERROR || *mode==FF_PATH_ERROR)
00835          return(NULL);
00836        /* get escapement of current symbol */
00837        currdisp=getDisplacement( tmppath5);
00838        /* concat displacement and symbol path */
00839        tmppath5=(struct segment *)Join(tmppath1,tmppath5);
00840        /* for composite symbols we have to step back the char escapement.
00841           this is, in order to be able to use accents that cause a
00842           non zero displacement of the current point! We further have to
00843           step back the displacement from composite char data. */
00844        tmppath1=(struct segment *)t1_PathSegment( MOVETYPE, -currdisp.x, -currdisp.y);
00845        tmppath3=(struct segment *)ILoc(S,
00846                                    -pAFMData->ccd[i].pieces[j].deltax,
00847                                    -pAFMData->ccd[i].pieces[j].deltay);
00848        tmppath3=(struct segment *)Join(tmppath1,tmppath3);
00849        /* create path, or, respectively, append to existing path */
00850        if (tmppath4==NULL) {
00851          tmppath4=(struct segment *)Join(tmppath5,tmppath3);
00852        }
00853        else {
00854          tmppath5=(struct segment *)Join(tmppath5,tmppath3);
00855          tmppath4=(struct segment *)Join(tmppath4,tmppath5);
00856        }
00857       }
00858       
00859       /* concat composite symbols and base char. We use tmppath5 to store
00860         the path of the resulting (possibly composite) character. */
00861       if (tmppath4==NULL) { /* no previous composite symbols */
00862        tmppath5=tmppath2; /* a simple char */
00863       }
00864       else { 
00865        tmppath5=(struct segment *)Join(tmppath4,tmppath2);
00866       }
00867       
00868 
00869       /* Accumulate displacement, but be careful: In case of composite
00870         characters, we have to take the escapement of the base char only
00871         into account, because accents do not cause spacing. The path is
00872         constructed in a way that this automatically matches.
00873       */
00874       if (numPieces>1) { /* composite character */
00875        acc_width +=pFontBase->pFontArray[FontID].pAFMData->ccd[-(pFontBase->pFontArray[FontID].pEncMap[string[k]]+1)].wx;
00876       }
00877       else { /* ordinary character */
00878        acc_width +=pFontBase->pFontArray[FontID].pAFMData->cmi[pFontBase->pFontArray[FontID].pEncMap[string[k]]-1].wx;
00879       }
00880       
00881     } /* else (if (char==space) */
00882 
00883     /* character path is now stored in tmppath5. It may be a composite character.
00884        Insert kerning amount, if it is not the last character of the string. */
00885     if (k<no_chars-1){
00886       tmppath2=(struct segment *)ILoc(S,kern_pairs[k],0); 
00887       tmppath5=(struct segment *)Join(tmppath5,tmppath2);
00888       acc_width += kern_pairs[k];
00889     }
00890     if (charpath!=NULL){
00891       charpath=(struct segment *)Join(charpath,tmppath5);
00892     }
00893     else{
00894       charpath=(struct segment *)tmppath5;
00895     }
00896     /* reset the temporary paths so that constructing composite
00897        characters wiil continue to work properly in the next interation. */
00898     tmppath1=NULL;
00899     tmppath2=NULL;
00900     tmppath3=NULL;
00901     tmppath4=NULL;
00902     tmppath5=NULL;
00903     /* reset composition parameters */
00904     i=-1;
00905     numPieces=1;
00906     
00907   } /* for (k<no_chars) */
00908   
00909   
00910   /* Take care for underlining and such */
00911   if (modflag & T1_UNDERLINE){
00912     tmppath2=(struct segment *)Type1Line(FontP,S,
00913                                     pFontBase->pFontArray[FontID].UndrLnPos,
00914                                     pFontBase->pFontArray[FontID].UndrLnThick,
00915                                     (float) acc_width,strokewidth);
00916     charpath=(struct segment *)Join(charpath,tmppath2);
00917   }
00918   if (modflag & T1_OVERLINE){
00919     tmppath2=(struct segment *)Type1Line(FontP,S,
00920                                     pFontBase->pFontArray[FontID].OvrLnPos,
00921                                     pFontBase->pFontArray[FontID].OvrLnThick,
00922                                     (float) acc_width,strokewidth);
00923     charpath=(struct segment *)Join(charpath,tmppath2);
00924   }
00925   if (modflag & T1_OVERSTRIKE){
00926     tmppath2=(struct segment *)Type1Line(FontP,S,
00927                                     pFontBase->pFontArray[FontID].OvrStrkPos,
00928                                     pFontBase->pFontArray[FontID].OvrStrkThick,
00929                                     (float) acc_width,strokewidth);
00930     charpath=(struct segment *)Join(charpath,tmppath2);
00931   }
00932   
00933   /*
00934   printf("charpath->type: %x\n",charpath->type);
00935   printf("path1->type: %x\n",path1->type);
00936   printf("path2->type: %x\n",path2->type);
00937   */
00938 
00939   /* if Type1Char reported an error, then return */
00940 
00941   if ( *mode == FF_PARSE_ERROR)  return(NULL);
00942   if ( *mode == FF_PATH_ERROR)  return(NULL);
00943   if (do_raster) { 
00944     /* fill with winding rule unless path was requested */
00945     if (*mode != FF_PATH) {
00946       charpath = (struct segment *) Interior((path) charpath,WINDINGRULE+CONTINUITY);
00947     }
00948   }
00949   
00950   if (*mode==0)
00951     *mode=localmode;
00952 
00953   return((path)charpath);
00954 }
00955 
00956 
00957 /* This special variant is for generating character bitmaps from
00958    charactername */
00959 xobject fontfcnB_ByName( int FontID, int modflag,
00960                       struct XYspace *S,
00961                       unsigned char *charname,
00962                       int *mode, psfont *Font_Ptr,
00963                       int do_raster)
00964 {
00965  
00966   psobj *charnameP; /* points to psobj that is name of character*/
00967   FontInfo *pAFMData=NULL;
00968   int i=-1;
00969   int j=0;
00970   int numPieces=1;
00971   int N;
00972   T1_PATHPOINT currdisp;
00973   int basechar;
00974   
00975   psdict *CharStringsDictP; /* dictionary with char strings     */
00976   psobj   CodeName;   /* used to store the translation of the name*/
00977   psobj  *SubrsArrayP;
00978   psobj  *theStringP;
00979   int localmode=0;
00980   
00981   struct segment *charpath=NULL;   /* the path for this character   */           
00982   struct segment *tmppath1=NULL;
00983   struct segment *tmppath2=NULL;
00984   struct segment *tmppath3=NULL;
00985   struct segment *tmppath4=NULL;
00986   
00987    
00988   /* set the global font pointer to the address of already allocated
00989      structure and setup pointers*/
00990   FontP=Font_Ptr;
00991   CharStringsDictP =  FontP->CharStringsP;
00992   SubrsArrayP = &(FontP->Subrs);
00993   charnameP = &CodeName;
00994 
00995   charnameP->len = strlen((char*)charname);
00996   charnameP->data.stringP = charname;
00997 
00998   strncpy( (char *)CurCharName, (char *)charnameP->data.stringP, charnameP->len);
00999   CurCharName[charnameP->len]='\0';
01000   
01001  
01002   /* search the chars string for this charname as key */
01003   basechar = SearchDictName(CharStringsDictP,charnameP);
01004   if (basechar<=0) {
01005     /* Check first, whether a char in question is a composite char */
01006     if ((i=isCompositeChar( FontID, CurCharName))>-1) {
01007       /* i is now the index of the composite char definitions
01008         (starting at 0). At this point it is clear that AFM-info
01009         must be present -> fetch first component of composite char. */
01010       pAFMData=pFontBase->pFontArray[FontID].pAFMData;
01011       charnameP->len=strlen( pAFMData->ccd[i].pieces[0].pccName);
01012       charnameP->data.stringP=(unsigned char*)pAFMData->ccd[i].pieces[0].pccName;
01013       numPieces=pAFMData->ccd[i].numOfPieces;
01014       
01015       if ((basechar=SearchDictName(CharStringsDictP,charnameP))<=0) {
01016        /* this is bad, AFM-file and font file do not match. This 
01017           will most probably lead to errors or inconsistencies later.
01018           However, we substitute .notdef and inform the user via
01019           logfile and T1_errno. */
01020        sprintf( err_warn_msg_buf,
01021                "Charstring \"%s\" needed to construct composite char \"%s\" not defined (FontID=%d)",
01022                pAFMData->ccd[i].pieces[0].pccName,
01023                pAFMData->ccd[i].ccName, FontID);
01024        T1_PrintLog( "fontfcnB():", err_warn_msg_buf, T1LOG_WARNING);
01025        T1_errno=T1ERR_COMPOSITE_CHAR;
01026       }
01027     }
01028   }
01029   
01030   if (basechar<=0) { /* This  means the requested char is unknown or the
01031                      base char of a composite is not found ->
01032                      we substitute .notdef */
01033     charnameP = &CodeName;
01034     charnameP->len = 7;
01035     charnameP->data.stringP = (unsigned char *) notdef;
01036     basechar = SearchDictName(CharStringsDictP,charnameP);
01037     localmode=FF_NOTDEF_SUBST;
01038     /* Font must be completely damaged if it doesn't define a .notdef */
01039     if (basechar<=0) {
01040       *mode=FF_PARSE_ERROR;
01041       return(NULL);
01042     }
01043   } /* if (basechar<=0) */
01044   /* basechar is now the index of the base character in the CharStrings
01045      dictionary */
01046 
01047   /* we provide the Type1Char() procedure with the name of the character
01048      to rasterize for debugging purposes */
01049   strncpy( (char *)CurCharName, (char *)charnameP->data.stringP, charnameP->len);
01050   CurCharName[charnameP->len]='\0';
01051   /* get CharString and character path */
01052   theStringP = &(CharStringsDictP[basechar].value);
01053   tmppath2 = (struct segment *) Type1Char(FontP,S,theStringP,SubrsArrayP,NULL,
01054                                      FontP->BluesP,mode,CurCharName, 0.0f);
01055   /* if Type1Char reported an error, then return */
01056   if ( *mode == FF_PARSE_ERROR || *mode==FF_PATH_ERROR)
01057     return(NULL);
01058   
01059   /* Defer rastering to later, we first have to handle the composite
01060      symbols */
01061   for (j=1; j<numPieces; j++) {
01062     /* get composite symbol name */
01063     charnameP->len=strlen( pAFMData->ccd[i].pieces[j].pccName);
01064     charnameP->data.stringP=(unsigned char*)pAFMData->ccd[i].pieces[j].pccName;
01065     /* get CharString definition */
01066     if ((N=SearchDictName(CharStringsDictP,charnameP))<=0) {
01067       /* handling of errors, see comments above ... */
01068       sprintf( err_warn_msg_buf,
01069               "Charstring \"%s\" needed to construct composite char \"%s\" not defined (FontID=%d)",
01070               pAFMData->ccd[i].pieces[j].pccName,
01071               pAFMData->ccd[i].ccName, FontID);
01072       T1_PrintLog( "fontfcnB():", err_warn_msg_buf, T1LOG_WARNING);
01073       charnameP = &CodeName;
01074       charnameP->len = 7;
01075       charnameP->data.stringP = (unsigned char *) notdef;
01076       N = SearchDictName(CharStringsDictP,charnameP);
01077       localmode=FF_NOTDEF_SUBST;
01078       /* damaged Font */
01079       if (N<=0) {
01080        *mode=FF_PARSE_ERROR;
01081        if (charpath!=NULL) {
01082          KillPath( charpath);
01083        }
01084        return(NULL);
01085       }
01086     }
01087     theStringP = &(CharStringsDictP[N].value);
01088     tmppath1=(struct segment *)ILoc(S,
01089                                 pAFMData->ccd[i].pieces[j].deltax,
01090                                 pAFMData->ccd[i].pieces[j].deltay);
01091     
01092     strncpy( (char *)CurCharName, (char *)charnameP->data.stringP, charnameP->len);
01093     CurCharName[charnameP->len]='\0';
01094     charpath=(struct segment *)Type1Char(FontP,S,theStringP,SubrsArrayP,NULL,
01095                                     FontP->BluesP,mode,CurCharName,0.0f);
01096     /* return if Type1Char reports an error */
01097     if ( *mode == FF_PARSE_ERROR || *mode==FF_PATH_ERROR)
01098       return(NULL);
01099     /* get escapement of current symbol */
01100     currdisp=getDisplacement( charpath);
01101     /* concat displacement and symbol path */
01102     charpath=(struct segment *)Join(tmppath1,charpath);
01103     /* for composite symbols we have to step back the char escapement.
01104        this is, in order to be able to use accents that cause a
01105        non zero displacement of the current point! We further have to
01106        step back the displacement from composite char data. */
01107     tmppath1=(struct segment *)t1_PathSegment( MOVETYPE, -currdisp.x, -currdisp.y);
01108     tmppath3=(struct segment *)ILoc(S,
01109                                 -pAFMData->ccd[i].pieces[j].deltax,
01110                                 -pAFMData->ccd[i].pieces[j].deltay);
01111     tmppath3=(struct segment *)Join(tmppath1,tmppath3);
01112     /* create path, or, respectively, append to existing path */
01113     if (tmppath4==NULL) {
01114       tmppath4=(struct segment *)Join(charpath,tmppath3);
01115     }
01116     else {
01117       charpath=(struct segment *)Join(charpath,tmppath3);
01118       tmppath4=(struct segment *)Join(tmppath4,charpath);
01119     }
01120   }
01121 
01122   /* concat composite symbols and base char */
01123   if (tmppath4==NULL) { /* no previous composite symbols */
01124     charpath=tmppath2; /* a simple char */
01125   }
01126   else { 
01127     charpath=(struct segment *)Join(tmppath4,tmppath2);
01128   }
01129   
01130   
01131   if (do_raster) { 
01132     /* fill with winding rule unless path was requested */
01133     if (*mode != FF_PATH) {
01134       charpath =  (struct segment *)Interior(charpath,WINDINGRULE+CONTINUITY);
01135     }
01136   }
01137 
01138   if (*mode==0)
01139     *mode=localmode;
01140   
01141   return((xobject) charpath);
01142 
01143 }
01144 
01145 
01146 xobject fontfcnRect( float width,
01147                    float height,
01148                    struct XYspace* S,
01149                    int *mode,
01150                    int do_raster,
01151                    float strokewidth)
01152 {
01153   struct segment *charpath = NULL;   /* the path for this character (rectangle)  */           
01154   
01155   charpath = (struct segment *) Type1Line( NULL, S,
01156                                       0.5f * height,    /* position */
01157                                       height,           /* thickness */
01158                                       -width,            /* width */
01159                                       strokewidth       /* strokewidth */
01160                                       );
01161   
01162   if (do_raster) { 
01163     /* fill with winding rule unless path was requested */
01164     if (*mode != FF_PATH) {
01165       charpath =  (struct segment *)Interior(charpath,WINDINGRULE+CONTINUITY);
01166     }
01167   }
01168 
01169   return((xobject) charpath);
01170   
01171 }