Back to index

tetex-bin  3.0
t1load.c
Go to the documentation of this file.
00001 /*--------------------------------------------------------------------------
00002   ----- File:        t1load.c 
00003   ----- Author:      Rainer Menzner (Rainer.Menzner@web.de)
00004   ----- Date:        2002-11-27
00005   ----- Description: This file is part of the t1-library. It contains
00006                      functions for loading fonts  and for managing size
00007                    dependent data.
00008   ----- Copyright:   t1lib is copyrighted (c) Rainer Menzner, 1996-2002. 
00009                      As of version 0.5, t1lib is distributed under the
00010                    GNU General Public Library Lincense. The
00011                    conditions can be found in the files LICENSE and
00012                    LGPL, which should reside in the toplevel
00013                    directory of the distribution.  Please note that 
00014                    there are parts of t1lib that are subject to
00015                    other licenses:
00016                    The parseAFM-package is copyrighted by Adobe Systems
00017                    Inc.
00018                    The type1 rasterizer is copyrighted by IBM and the
00019                    X11-consortium.
00020   ----- Warranties:  Of course, there's NO WARRANTY OF ANY KIND :-)
00021   ----- Credits:     I want to thank IBM and the X11-consortium for making
00022                      their rasterizer freely available.
00023                    Also thanks to Piet Tutelaers for his ps2pk, from
00024                    which I took the rasterizer sources in a format
00025                    independent from X11.
00026                      Thanks to all people who make free software living!
00027 --------------------------------------------------------------------------*/
00028   
00029 #define T1LOAD_C
00030 
00031 /*
00032   SU: Enabling this causes a segfault on  OSF1/V5.1 alpha. Since it
00033   appears to be an optimization only, I've disabled it until Rainer
00034   has a fix.
00035  */
00036 /* #define ANSI_REALLOC_VM   */
00037 
00038 #include <stdio.h>
00039 #include <sys/types.h>
00040 #include <sys/stat.h>
00041 #include <fcntl.h>
00042 #if defined(_MSC_VER)
00043 # include <io.h>
00044 # include <sys/types.h>
00045 # include <sys/stat.h>
00046 #else
00047 # include <unistd.h>
00048 #endif
00049 #include <stdlib.h>
00050 #include <math.h>
00051 #include <string.h>
00052 
00053 #include "../type1/ffilest.h"
00054 #include "../type1/types.h"
00055 #include "parseAFM.h" 
00056 #include "../type1/objects.h"
00057 #include "../type1/spaces.h"
00058 #include "../type1/util.h"
00059 #include "../type1/fontfcn.h"
00060 #include "../type1/blues.h"
00061 #include "../type1/regions.h"
00062 
00063 
00064 #include "t1types.h"
00065 #include "t1extern.h"
00066 #include "t1load.h"
00067 #include "t1env.h"
00068 #include "t1set.h"
00069 #include "t1base.h"
00070 #include "t1finfo.h"
00071 #include "t1afmtool.h"
00072 
00073 
00074 
00075 extern psobj *StdEncArrayP;       /* For checking of a fonts encoding */
00076 extern char not_def[];            /* for checking the ".notdef"-string */
00077 
00078 
00079 
00080 /* T1_LoadFont(FontID): Loads a Type1 font into memory and allocates all
00081    memory, necessary for this. */
00082 
00083 int T1_LoadFont( int FontID)
00084 {
00085   int i, j, k, l, m;
00086   char *FileName, *FileNamePath;
00087   int mode;  /* This is used by the type1-library for error reporting */   
00088   char *charname;
00089   
00090   /* The following vars are used for reallocation of VM */
00091   long tmp_size;
00092   float ascender;
00093 #ifdef ANSI_REALLOC_VM
00094   unsigned long shift;
00095   unsigned long ldummy;
00096   char *tmp_ptr;
00097 #endif
00098 
00099   struct region *area;
00100   struct XYspace *S;    
00101 
00102   /* These are for constructing the kerning lookup table: */
00103   PairKernData *pkd;
00104   METRICS_ENTRY *kern_tbl;
00105   int char1, char2;
00106   
00107   
00108   if (T1_CheckForInit()){
00109     T1_errno=T1ERR_OP_NOT_PERMITTED;
00110     return(-1);
00111   }
00112   
00113 
00114   i=T1_CheckForFontID(FontID);
00115   if (i==1)
00116     return(0);      /* Font already loaded */
00117   if (i==-1){
00118     T1_errno=T1ERR_INVALID_FONTID;
00119     return(-1);     /* illegal FontID */
00120   }
00121   
00122   /* Allocate memory for ps_font structure: */
00123   if ((pFontBase->pFontArray[FontID].pType1Data=(psfont *)malloc(sizeof(psfont)))==NULL){
00124     T1_PrintLog( "T1_LoadFont()", "Failed to allocate memory for psfont-struct (FontID=%d)",
00125                T1LOG_ERROR, FontID);
00126     T1_errno=T1ERR_ALLOC_MEM;
00127     return(-1);
00128   }
00129 
00130   /* Check for valid filename */
00131   if ((FileName=T1_GetFontFileName(FontID))==NULL){
00132     T1_PrintLog( "T1_LoadFont()", "No font file name for font %d", T1LOG_ERROR, FontID);
00133     return(-1);
00134   }
00135   
00136   /* Fetch the full path of type1 font file */
00137   if ((FileNamePath=intT1_Env_GetCompletePath( FileName,
00138                                     T1_PFAB_ptr))==NULL){
00139     T1_PrintLog( "T1_LoadFont()", "Couldn't locate font file for font %d in %s",
00140                T1LOG_ERROR, FontID, T1_GetFileSearchPath(T1_PFAB_PATH));
00141     T1_errno=T1ERR_FILE_OPEN_ERR;
00142     return(-1);
00143   }
00144   
00145   /* And load all PostScript information into memory */
00146   if (fontfcnA( FileNamePath, &mode,
00147               pFontBase->pFontArray[FontID].pType1Data) == FALSE){
00148     T1_PrintLog( "T1_LoadFont()", "Loading font with ID = %d failed! (mode = %d)",
00149                T1LOG_ERROR, FontID, mode);
00150     free(FileNamePath);
00151     pFontBase->pFontArray[FontID].pType1Data=NULL;
00152     T1_errno=mode;
00153     return(-1);
00154   }
00155   free(FileNamePath);
00156 
00157   
00158   /* Store the base address of virtual memory and realloc in order not
00159      to waste too much memory: */
00160   pFontBase->pFontArray[FontID].vm_base=vm_base; 
00161 #ifdef ANSI_REALLOC_VM
00162   /* We first get the size of pointers on the current system */
00163   /* Get size of VM, ... */
00164   tmp_size=((unsigned long)vm_used - (unsigned long)vm_base); 
00165   /* ... realloc to that size ... */
00166   tmp_ptr=(char *)realloc(vm_base,  tmp_size); 
00167   /* ... and shift all pointers refering to that area */
00168   if (tmp_ptr > vm_base){
00169     shift= (unsigned long)tmp_ptr - (unsigned long)vm_base;
00170     sprintf( err_warn_msg_buf,
00171             "Old VM at 0x%lX, new VM at 0x%lX, shifting up by %lu",
00172             (unsigned long)vm_base, (unsigned long)tmp_ptr, tmp_size);
00173     T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
00174     
00175     /* We start by shifting the topmost pointers: */
00176     pFontBase->pFontArray[FontID].vm_base=tmp_ptr;
00177     
00178     ldummy=(long)(pFontBase->pFontArray[FontID].pType1Data->vm_start);
00179     ldummy +=shift;
00180     pFontBase->pFontArray[FontID].pType1Data->vm_start=(char *)ldummy;
00181     
00182     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP;
00183     ldummy +=shift;
00184     pFontBase->pFontArray[FontID].pType1Data->CharStringsP=(psdict *)ldummy;
00185     
00186     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Private;
00187     ldummy +=shift;
00188     pFontBase->pFontArray[FontID].pType1Data->Private=(psdict *)ldummy;
00189     
00190     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP;
00191     ldummy +=shift;
00192     pFontBase->pFontArray[FontID].pType1Data->fontInfoP=(psdict *)ldummy;
00193     
00194     ldummy=(long)(pFontBase->pFontArray[FontID].pType1Data->BluesP);
00195     ldummy +=shift;
00196     pFontBase->pFontArray[FontID].pType1Data->BluesP=(struct blues_struct *)ldummy;
00197     
00198     /* We now have to care for correcting all pointers which are in the VM
00199        and refer to some place in the VM! Note: Instead of selecting the
00200        appropriate pointer-elements of the union we simply shift the
00201        unspecified pointer "valueP".
00202        Note: The filename entry does not need to be modified since it does not
00203        need to be shifted since it points to memory managed by t1lib.
00204        */
00205     /* FontInfo-dictionary: All name-pointers and the pointers to all array
00206        types have to be shifted: */
00207     i=pFontBase->pFontArray[FontID].pType1Data->fontInfoP[0].key.len;
00208     for (j=1; j<=i; j++){
00209       if ((pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_ARRAY) ||
00210          (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_STRING) ||
00211          (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_NAME) ||
00212          (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_FILE)){
00213        ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP;
00214        ldummy +=shift;
00215        pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP=(char *)ldummy;
00216       }
00217       /* The encoding needs special treatment: */
00218       if (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_ENCODING){
00219        /* If a builtin encoding is used, it is sufficient to shift the pointer
00220           to the Encoding since the character-namestrings of builtin encodings
00221           are static and thus located on the heap.
00222           For font-specific encoding, character-namestrings reside in VM and
00223           thus each entry has to be shifted. 
00224           Caution: We still have to shift the builtin encoding-pointer, since
00225           they also point to are located in VM: */
00226        ldummy=(long)StdEncArrayP;
00227        ldummy +=shift;
00228        StdEncArrayP=(psobj *)ldummy;
00229        ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP;
00230        ldummy +=shift;
00231        pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP=(char *)ldummy;
00232        if (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.arrayP
00233            == StdEncArrayP){ /* Font uses builtin standard encoding */
00234          ;
00235        } 
00236        else{ /* Font-specific encoding */ 
00237          for (k=0; k<256; k++){
00238            ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.arrayP[k].data.arrayP;
00239            /* The ".notdef" is also static and may not be shifted (Thanks, Derek ;) */
00240            if (ldummy != (unsigned long)not_def) {
00241              ldummy +=shift;
00242              pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.arrayP[k].data.arrayP=(struct ps_obj *)ldummy;
00243            }
00244          }
00245        }
00246       } /* end of encoding-handling */
00247       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].key.data.valueP;
00248       ldummy +=shift;
00249       pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].key.data.valueP=(char *)ldummy;
00250     } /* fontinfo-dict done */
00251     
00252     /* Private-dictionary: All name-pointers and the pointers to all array
00253        types have to be shifted: */
00254     i=pFontBase->pFontArray[FontID].pType1Data->Private[0].key.len;
00255     for (j=1; j<=i; j++){
00256       if ((pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_ARRAY) ||
00257          (pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_STRING) ||
00258          (pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_NAME) ||
00259          (pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_FILE)){
00260        ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Private[j].value.data.valueP;
00261        ldummy +=shift;
00262        pFontBase->pFontArray[FontID].pType1Data->Private[j].value.data.valueP=(char *)ldummy;
00263       }
00264       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Private[j].key.data.valueP;
00265       ldummy +=shift;
00266       pFontBase->pFontArray[FontID].pType1Data->Private[j].key.data.valueP=(char *)ldummy;
00267     }
00268     
00269     /* BluesP: The entry "next" is the only pointer in blues_struct. Although it is
00270        not used anywhere we should shift it for correctness reasons (in case its not
00271        NULL)! */
00272     if (pFontBase->pFontArray[FontID].pType1Data->BluesP->next != NULL){
00273       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->BluesP->next;
00274       ldummy +=shift;
00275       pFontBase->pFontArray[FontID].pType1Data->BluesP->next=(struct blues_struct *)ldummy;
00276     }
00277     
00278     /* The CharStrings-dictionary: Every namepointer and its corresponding
00279        charstring has to be shifted: */
00280     i=pFontBase->pFontArray[FontID].pType1Data->CharStringsP[0].key.len;
00281     for (j=1; j<=i; j++){
00282       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].value.data.valueP;
00283       ldummy +=shift;
00284       pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].value.data.valueP=(char *)ldummy;
00285       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].key.data.valueP;
00286       ldummy +=shift;
00287       pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].key.data.valueP=(char *)ldummy;
00288     }
00289     
00290     /* The Subroutines have also to be reorganized: */
00291     i=pFontBase->pFontArray[FontID].pType1Data->Subrs.len;
00292     /* First, shift pointer to array-start and after that the pointers to
00293        each command string: */
00294     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP;
00295     ldummy +=shift;
00296     pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP=(struct ps_obj *)ldummy;
00297     for (j=0; j<i; j++) {
00298       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP[j].data.valueP;
00299       ldummy +=shift;
00300       pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP[j].data.valueP=(char *)ldummy;
00301     }
00302   } /* end of if( tmp_ptr > vm_base ) */
00303   else if ( vm_base > tmp_ptr){
00304     shift= (unsigned long)vm_base - (unsigned long)tmp_ptr;
00305     sprintf( err_warn_msg_buf,
00306             "Old VM at 0x%lX, new VM at 0x%lX, shifting down by %lu",
00307             (unsigned long)vm_base, (unsigned long)tmp_ptr, tmp_size);
00308     T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
00309     
00310     /* We start by shifting the topmost pointers: */
00311     pFontBase->pFontArray[FontID].vm_base=tmp_ptr;
00312     
00313     ldummy=(long)(pFontBase->pFontArray[FontID].pType1Data->vm_start);
00314     ldummy -=shift;
00315     pFontBase->pFontArray[FontID].pType1Data->vm_start=(char *)ldummy;
00316     
00317     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP;
00318     ldummy -=shift;
00319     pFontBase->pFontArray[FontID].pType1Data->CharStringsP=(psdict *)ldummy;
00320     
00321     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Private;
00322     ldummy -=shift;
00323     pFontBase->pFontArray[FontID].pType1Data->Private=(psdict *)ldummy;
00324     
00325     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP;
00326     ldummy -=shift;
00327     pFontBase->pFontArray[FontID].pType1Data->fontInfoP=(psdict *)ldummy;
00328     
00329     ldummy=(long)(pFontBase->pFontArray[FontID].pType1Data->BluesP);
00330     ldummy -=shift;
00331     pFontBase->pFontArray[FontID].pType1Data->BluesP=(struct blues_struct *)ldummy;
00332     
00333     /* We now have to care for correcting all pointers which are in the VM
00334        and refer to some place in the VM! Note: Instead of selecting the
00335        appropriate pointer-elements of the union we simply shift the
00336        unspecified pointer "valueP".
00337        Note: The filename entry does not need to be modified since it does not
00338        need to be shifted since it points to memory managed by t1lib.
00339        */
00340     /* FontInfo-dictionary: All name-pointers and the pointers to all array
00341        types have to be shifted: */
00342     i=pFontBase->pFontArray[FontID].pType1Data->fontInfoP[0].key.len;
00343     for (j=1; j<=i; j++){
00344       if ((pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_ARRAY) ||
00345          (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_STRING) ||
00346          (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_NAME) ||
00347          (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_FILE)){
00348        ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP;
00349        ldummy -=shift;
00350        pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP=(char *)ldummy;
00351       }
00352       /* The encoding needs special treatment: */
00353       if (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_ENCODING){
00354        /* If a builtin encoding is used, it is sufficient to shift the pointer
00355           to the Encoding since the character-namestrings of builtin encodings
00356           are static and thus located on the heap.
00357           For font-specific encoding, character-namestrings reside in VM and
00358           thus each entry has to be shifted. 
00359           Caution: We still have to shift the builtin encoding-pointer, since
00360           they also point to are located in VM: */
00361        ldummy=(long)StdEncArrayP;
00362        ldummy -=shift;
00363        StdEncArrayP=(psobj *)ldummy;
00364        ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP;
00365        ldummy -=shift;
00366        pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP=(char *)ldummy;
00367        if (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.arrayP
00368             == StdEncArrayP){ /* Font uses builtin encoding */
00369          ;
00370        } 
00371        else{ /* Font-specific encoding */ 
00372          for (k=0; k<256; k++){
00373            ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.arrayP[k].data.arrayP;
00374            /* The ".notdef" is also static and may not be shifted (Thanks, Derek ;) */
00375            if (ldummy != (unsigned long)not_def) {
00376              ldummy -=shift;
00377              pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.arrayP[k].data.arrayP=(struct ps_obj *)ldummy;
00378            }
00379          }
00380        }
00381       } /* end of encoding-handling */
00382       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].key.data.valueP;
00383       ldummy -=shift;
00384       pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].key.data.valueP=(char *)ldummy;
00385     } /* fontinfo-dict done */
00386     
00387     /* Private-dictionary: All name-pointers and the pointers to all array
00388        types have to be shifted: */
00389     i=pFontBase->pFontArray[FontID].pType1Data->Private[0].key.len;
00390     for (j=1; j<=i; j++){
00391       if ((pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_ARRAY) ||
00392          (pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_STRING) ||
00393          (pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_NAME) ||
00394          (pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_FILE)){
00395        ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Private[j].value.data.valueP;
00396        ldummy -=shift;
00397        pFontBase->pFontArray[FontID].pType1Data->Private[j].value.data.valueP=(char *)ldummy;
00398       }
00399       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Private[j].key.data.valueP;
00400       ldummy -=shift;
00401       pFontBase->pFontArray[FontID].pType1Data->Private[j].key.data.valueP=(char *)ldummy;
00402     }
00403     
00404     /* BluesP: The entry "next" is the only pointer in blues_struct. Although it is
00405        not used anywhere we should shift it for correctness reasons (in case its not
00406        NULL)! */
00407     if (pFontBase->pFontArray[FontID].pType1Data->BluesP->next != NULL){
00408       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->BluesP->next;
00409       ldummy -=shift;
00410       pFontBase->pFontArray[FontID].pType1Data->BluesP->next=(struct blues_struct *)ldummy;
00411     }
00412     
00413     /* The CharStrings-dictionary: Every namepointer and its corresponding
00414        charstring has to be shifted: */
00415     i=pFontBase->pFontArray[FontID].pType1Data->CharStringsP[0].key.len;
00416     for (j=1; j<=i; j++){
00417       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].value.data.valueP;
00418       ldummy -=shift;
00419       pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].value.data.valueP=(char *)ldummy;
00420       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].key.data.valueP;
00421       ldummy -=shift;
00422       pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].key.data.valueP=(char *)ldummy;
00423     }
00424     
00425     /* The Subroutines have also to be reorganized: */
00426     i=pFontBase->pFontArray[FontID].pType1Data->Subrs.len;
00427     /* First, shift pointer to array-start and after that the pointers to
00428        each command string: */
00429     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP;
00430     ldummy -=shift;
00431     pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP=(struct ps_obj *)ldummy;
00432     for (j=0; j<i; j++) {
00433       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP[j].data.valueP;
00434       ldummy -=shift;
00435       pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP[j].data.valueP=(char *)ldummy;
00436     }
00437   } /* end of if( vm_base > tmp_ptr ) */
00438   else{ /* VM addess has not changed during reallocation */
00439     sprintf( err_warn_msg_buf,
00440             "Old VM and new VM at 0x%lX, no pointer-shifting",
00441             (unsigned long)vm_base);
00442     T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
00443   }
00444 #endif
00445     
00446   /* Generate a message how much VM the current font consumes */
00447   sprintf( err_warn_msg_buf,
00448           "VM for Font %d: %d bytes", FontID, (int) tmp_size);
00449   T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_STATISTIC);
00450 
00451   
00452   /* Set the matrix for common transformations to "no transformations" */
00453   pFontBase->pFontArray[FontID].FontTransform[0]=1.0;
00454   pFontBase->pFontArray[FontID].FontTransform[1]=0.0;
00455   pFontBase->pFontArray[FontID].FontTransform[2]=0.0;
00456   pFontBase->pFontArray[FontID].FontTransform[3]=1.0;
00457 
00458   /* Now, that the font has been loaded into memory, try to find the
00459      FontMatrix in the font info dictionary. If it exists, load it into
00460      our local fontmatrix, otherwise use a default matrix which scales to
00461      1/1000 (since font outlines  are defined in a 1000 point space)
00462      and does no further transformations. */
00463   if (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTMATRIX].value.data.arrayP == NULL){
00464     pFontBase->pFontArray[FontID].FontMatrix[0]=0.001;
00465     pFontBase->pFontArray[FontID].FontMatrix[1]=0.0;
00466     pFontBase->pFontArray[FontID].FontMatrix[2]=0.0;
00467     pFontBase->pFontArray[FontID].FontMatrix[3]=0.001;
00468   }
00469   else{
00470     pFontBase->pFontArray[FontID].FontMatrix[0]= (double)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTMATRIX].value.data.arrayP[0].data.real;
00471     pFontBase->pFontArray[FontID].FontMatrix[1]= (double)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTMATRIX].value.data.arrayP[1].data.real;
00472     pFontBase->pFontArray[FontID].FontMatrix[2]= (double)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTMATRIX].value.data.arrayP[2].data.real;
00473     pFontBase->pFontArray[FontID].FontMatrix[3]= (double)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTMATRIX].value.data.arrayP[3].data.real;
00474   }
00475 
00476   /* Set the default values for transformation: */
00477   pFontBase->pFontArray[FontID].slant=0.0;
00478   pFontBase->pFontArray[FontID].extend=1.0;
00479 
00480   
00481   /* Now try to load afm-structures from corresponding .afm-file (if
00482      not suppressed by the user). */
00483   if ((pFontBase->t1lib_flags & T1_NO_AFM)!=0) {
00484     pFontBase->pFontArray[FontID].pAFMData = NULL;
00485     T1_PrintLog( "T1_LoadFont()",
00486                "Suppressing AFM data handling on user request",
00487                T1LOG_STATISTIC);
00488   }
00489   else {
00490     if ((i=openFontMetricsFile( FontID, 0))){
00491       /* Try a fallback, opening sloppy: */
00492       if ((i=openFontMetricsFile( FontID, 1))) {
00493        sprintf( err_warn_msg_buf,
00494                "Alert: Error (%d) sloppy-processing afm-file for Font %d!",
00495                i ,FontID);
00496        T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_STATISTIC);
00497        if ((pFontBase->pFontArray[FontID].pAFMData=
00498             T1_GenerateAFMFallbackInfo(FontID))==NULL){
00499          sprintf( err_warn_msg_buf,
00500                  "Ultimately failed to generate metrics information Font %d!",
00501                  FontID);
00502          T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_WARNING);
00503        }
00504        else {
00505          pFontBase->pFontArray[FontID].info_flags |=AFM_SELFGEN_SUCCESS;
00506          T1_PrintLog( "T1_LoadFont()",
00507                      "Generating AFM-information from fontfile successful!",
00508                      T1LOG_STATISTIC);
00509        }
00510       }
00511       else {
00512        pFontBase->pFontArray[FontID].info_flags |=AFM_SLOPPY_SUCCESS;
00513        sprintf( err_warn_msg_buf,
00514                "Alert: Limited afm-information for Font %d",FontID);
00515        T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_STATISTIC);
00516       } 
00517     }
00518     else {
00519       pFontBase->pFontArray[FontID].info_flags |=AFM_SUCCESS;
00520     }
00521   }
00522   
00523   
00524   /* Now, set Encodingvector entry to default if the font's
00525      internal encoding is "StandardEncoding".
00526      */
00527   if (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[ENCODING].value.data.arrayP
00528       == StdEncArrayP) {
00529     pFontBase->pFontArray[FontID].info_flags |=USES_STANDARD_ENCODING;
00530     pFontBase->pFontArray[FontID].pFontEnc=pFontBase->default_enc;
00531     sprintf( err_warn_msg_buf,
00532             "Font %d reencoded to default",FontID);
00533     T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
00534   }
00535   else {
00536     sprintf( err_warn_msg_buf,
00537             "Font %d not reencoded to default",FontID);
00538     T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
00539     pFontBase->pFontArray[FontID].pFontEnc = NULL;
00540   }
00541 
00542   
00543   /* If AFM-Info available we try to speed up some things: */
00544   if (pFontBase->pFontArray[FontID].pAFMData != NULL) {
00545     /* We have to fill the array that maps the current encodings' indices to the
00546        indices used in afm file. The interpretation has been changed in
00547        in t1lib-1.2. We now use positive values for indexing into the charmetrics
00548        array and negative values for indexing into the composite character array.
00549        an index of zero indicates that no metrics are defined for this character.
00550        This may happen because (a) not all AFM-files define metrics for the .notdef
00551        character, and (b) because font and AFM-file do not match. */
00552     if ((pFontBase->pFontArray[FontID].pEncMap=
00553         (int *)calloc(256,sizeof(int)))==NULL) {
00554       sprintf( err_warn_msg_buf, "Error allocating memory for encoding map (FontID=%d)",
00555               FontID);
00556       T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf,
00557                T1LOG_WARNING);
00558       T1_errno=T1ERR_ALLOC_MEM;
00559       return(-1);
00560     }
00561     for (i=0; i<256; i++) {
00562       charname=T1_GetCharName( FontID, i);
00563       /* in a first loop check for ordinary characters */
00564       for ( j=0; j<pFontBase->pFontArray[FontID].pAFMData->numOfChars; j++) {
00565        if (strcmp( charname,
00566                   pFontBase->pFontArray[FontID].pAFMData->cmi[j].name)==0) {
00567          pFontBase->pFontArray[FontID].pEncMap[i]=j+1; /* index 0 is reserved! */
00568          continue;
00569        }
00570       }
00571       /* if nothing has been found, check for composite characters */ 
00572       for ( j=0; j<pFontBase->pFontArray[FontID].pAFMData->numOfComps; j++) {
00573        if (strcmp( charname,
00574                   pFontBase->pFontArray[FontID].pAFMData->ccd[j].ccName)==0) {
00575          pFontBase->pFontArray[FontID].pEncMap[i]=-(j+1); /* index 0 is reserved! */
00576          continue;
00577        }
00578       }
00579     }
00580     
00581     /* For composite characters, we still have to compute the width and bbox */
00582     for ( j=0; j<pFontBase->pFontArray[FontID].pAFMData->numOfComps; j++) {
00583       /*and bounding box by ourselves. First, set up an identity charspace
00584        matrix and then generate an edgelist for the composite character at
00585        size 1000bp using no transformation and current encoding. Note: This
00586        action is only required when loading a font at first time, but not
00587        when reencoding a font. */
00588       S=(struct XYspace *)IDENTITY;
00589       S=(struct XYspace *)Permanent
00590        (Transform(S, pFontBase->pFontArray[FontID].FontTransform[0],
00591                  pFontBase->pFontArray[FontID].FontTransform[1],
00592                  pFontBase->pFontArray[FontID].FontTransform[2],
00593                  pFontBase->pFontArray[FontID].FontTransform[3]));
00594       
00595       area=fontfcnB_ByName( FontID, 0, S,
00596                          pFontBase->pFontArray[FontID].pAFMData->ccd[j].ccName,
00597                          &mode, pFontBase->pFontArray[FontID].pType1Data,
00598                          DO_RASTER);
00599       /* Store bounding box ... */
00600       pFontBase->pFontArray[FontID].pAFMData->ccd[j].charBBox.llx=area->xmin;
00601       pFontBase->pFontArray[FontID].pAFMData->ccd[j].charBBox.urx=area->xmax;
00602       pFontBase->pFontArray[FontID].pAFMData->ccd[j].charBBox.lly=area->ymin;
00603       pFontBase->pFontArray[FontID].pAFMData->ccd[j].charBBox.ury=area->ymax;
00604       /* ... and character width. This should be the width of the base character
00605         of the composite! */
00606       pFontBase->pFontArray[FontID].pAFMData->ccd[j].wx=NEARESTPEL(area->ending.x);
00607       /* clean up. */
00608       KillRegion (area);
00609       if (S!=NULL) {
00610        KillSpace (S);
00611        S=NULL;
00612       }
00613     }
00614     /* We now create an encoding-specific kerning table which will speed up
00615        looking for kerning pairs! */
00616     pFontBase->pFontArray[FontID].KernMapSize=0;
00617     /* First, get number of defined kerning pairs: */
00618     k=pFontBase->pFontArray[FontID].pAFMData->numOfPairs;
00619     if (k>0){ /* i.e., there are any pairs */
00620       /* OK, it does not suffice to alloc numOfPairs METRICS_ENTRYs, because
00621         a given character might be encoded at several locations and kerning
00622         should still work. As a worst case estimation, we allocate 256^2
00623         and realloc later. */ 
00624       if ((pFontBase->pFontArray[FontID].pKernMap=
00625           (METRICS_ENTRY *)malloc( (256*256) *sizeof( METRICS_ENTRY)))==NULL){
00626        sprintf( err_warn_msg_buf, "Error allocating memory for metrics map (FontID=%d)",
00627                FontID);
00628        T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf,
00629                    T1LOG_WARNING);
00630        T1_errno=T1ERR_ALLOC_MEM;
00631        return(-1);
00632       }
00633       kern_tbl=pFontBase->pFontArray[FontID].pKernMap;
00634       pkd=pFontBase->pFontArray[FontID].pAFMData->pkd;
00635       j=0;
00636       for ( i=0; i<k; i++) {
00637        /* We do not check T1_GetEncodingIndices() against the return value
00638           NULL because we just loading the font in question: */
00639        l=0;
00640        while ((char1=(T1_GetEncodingIndices( FontID, pkd[i].name1))[l++])!=-1) {
00641          /* pair could be relevant in current encoding */
00642          m=0;
00643          while ((char2=(T1_GetEncodingIndices( FontID, pkd[i].name2))[m++])!=-1) {
00644            /* Since we get here we have a relevant pair -->
00645               Put char1 in higher byte and char2 in LSB: */
00646            kern_tbl[j].chars=(char1 << 8) | char2;
00647            /* We only make use of horizontal kerning */
00648            kern_tbl[j].hkern=pkd[i].xamt;
00649            j++;
00650          } /* while (char2) */
00651        } /* while (char1) */
00652       } /* for */
00653       /* We are done, realloc memory: */
00654       kern_tbl=(METRICS_ENTRY*) realloc( kern_tbl, j*sizeof(METRICS_ENTRY));
00655       /* We now sort the kerning array with respect to char indices */
00656       qsort( kern_tbl, (size_t) j, sizeof(METRICS_ENTRY),
00657             &cmp_METRICS_ENTRY );
00658       /* Finally write back pointer for the case that realloc changed the
00659         pointer */
00660       pFontBase->pFontArray[FontID].pKernMap=kern_tbl;
00661       pFontBase->pFontArray[FontID].KernMapSize=j;
00662     }
00663     else
00664       pFontBase->pFontArray[FontID].pKernMap=NULL;
00665   }
00666   else { /* no AFM data */
00667     pFontBase->pFontArray[FontID].pKernMap=NULL;
00668     pFontBase->pFontArray[FontID].pEncMap=NULL;
00669   }
00670   /* End of "if (AFM-info ..)" */
00671   
00672   
00673   /* We have just loaded a physical font into memory, thus .... */
00674   pFontBase->pFontArray[FontID].physical=1;
00675 
00676   /* Set reference-counter to 1: */
00677   pFontBase->pFontArray[FontID].refcount=1;
00678 
00679   /* Get the index into encoding vector where the space character is
00680      found. If not encoded, set space_position to -1. */
00681   pFontBase->pFontArray[FontID].space_position=-1;
00682   i=0;
00683   if (pFontBase->pFontArray[FontID].pFontEnc) { /* external default encoding */
00684     while (i<256) {
00685       if (strcmp( (char *)pFontBase->pFontArray[FontID].pFontEnc[i],
00686                 "space")==0){
00687        /* space found at position i: */
00688        pFontBase->pFontArray[FontID].space_position=i;
00689        break;
00690       }
00691       i++;
00692     }
00693   }
00694   else { /* internal encoding */
00695     while (i<256) {
00696       if (strcmp( (char *)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[ENCODING].value.data.arrayP[i].data.arrayP,
00697                 "space")==0){
00698        /* space found at position i: */
00699        pFontBase->pFontArray[FontID].space_position=i;
00700        break;
00701       }
00702       i++;
00703     }
00704   }
00705   
00706 
00707   /* Set the lining rule parameters to default values */
00708   pFontBase->pFontArray[FontID].UndrLnPos=
00709     pFontBase->pFontArray[FontID].pType1Data->fontInfoP[UNDERLINEPOSITION].value.data.real;
00710   pFontBase->pFontArray[FontID].UndrLnThick=
00711     pFontBase->pFontArray[FontID].pType1Data->fontInfoP[UNDERLINETHICKNESS].value.data.real;
00712 
00713   /* We have to set the value for the typographic ascender. If possible,
00714      we get it from the afm-File. But be aware this value might be undefined!
00715      This value should in any acse explicitly be set later by the user! */
00716   if (pFontBase->pFontArray[FontID].pAFMData!=NULL &&
00717       pFontBase->pFontArray[FontID].pAFMData->gfi!=NULL) {
00718     ascender=(float) pFontBase->pFontArray[FontID].pAFMData->gfi->ascender;
00719   }
00720   else {
00721     ascender=(float) T1_GetCharBBox( FontID, T1_GetEncodingIndex( FontID, "d")).ury;
00722   }
00723   
00724   pFontBase->pFontArray[FontID].OvrLnPos=ascender
00725     + (float) abs( (double)pFontBase->pFontArray[FontID].UndrLnPos);
00726   pFontBase->pFontArray[FontID].OvrStrkPos=ascender / 2.0;
00727   pFontBase->pFontArray[FontID].OvrLnThick=pFontBase->pFontArray[FontID].UndrLnThick;
00728   pFontBase->pFontArray[FontID].OvrStrkThick=pFontBase->pFontArray[FontID].UndrLnThick;
00729 
00730   
00731   /* Finally, set the font size dependencies pointer to NULL since we can
00732      assume, that at load time of a font, no size specific data of this
00733      font is available.
00734      */
00735   
00736   pFontBase->pFontArray[FontID].pFontSizeDeps=NULL;
00737 
00738   /* If wanted, some debugging information is put into logfile */
00739   sprintf( err_warn_msg_buf, "Pointer vm_base: 0x%lX",
00740           (long)pFontBase->pFontArray[FontID].vm_base);
00741   T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
00742   sprintf( err_warn_msg_buf, "Pointer vm_start: 0x%lX",
00743           (long)pFontBase->pFontArray[FontID].pType1Data->vm_start);
00744   T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
00745   sprintf( err_warn_msg_buf, "Pointer CharStringsP: 0x%lX",
00746           (long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP);
00747   T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
00748   sprintf( err_warn_msg_buf, "Pointer Private: 0x%lX",
00749           (long)pFontBase->pFontArray[FontID].pType1Data->Private);
00750   T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
00751   sprintf( err_warn_msg_buf, "Pointer fontInfoP: 0x%lX",
00752           (long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP);
00753   T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
00754 
00755   return(0);
00756 }
00757   
00758 
00759 /* openFontMetricsFile( FontID, open_sloppy): Gets the fontfilename
00760    corresponding to FontID, opens the corresponding afm-file and fills
00761    the data structures. return-value is the value returned by the
00762    T1lib_parseFile() function. If open_sloppy is set, the minimum
00763    information needed is read from AFM file. This can be considered a
00764    fallback for problematic AFM files. */
00765 static int openFontMetricsFile( int FontID, int open_sloppy)
00766 {
00767   char *FontFileName;
00768   char *AFMFileName;
00769   char *afm_name;
00770   char *AFMFileNamePath;
00771   
00772   int i, j;
00773   FILE *metricsfile;
00774   
00775 
00776   afm_name=T1_GetAfmFileName(FontID);
00777   
00778   if (afm_name!=NULL) { /* We have name explicitly specified */
00779     /* It needs to be freeable */
00780     if ((AFMFileName=
00781         (char *)malloc( (strlen(afm_name)+1)*sizeof( char)))==NULL) {
00782       T1_errno=T1ERR_ALLOC_MEM;
00783       return( -6);
00784     }
00785     strcpy( AFMFileName, afm_name);
00786   }
00787   else {
00788     FontFileName=T1_GetFontFileName( FontID);
00789     i=strlen(FontFileName);
00790     j=i;
00791     AFMFileName=(char *)malloc( i+5);
00792     strcpy( AFMFileName, FontFileName);
00793     while ( AFMFileName[i] != '.'){
00794       if (i==0) break;
00795       else i--;
00796     }
00797     if (i==0){
00798       /* We have a filename without extension -> append extension */
00799       AFMFileName[j]='.';
00800       AFMFileName[j+1]='a';
00801       AFMFileName[j+2]='f';
00802       AFMFileName[j+3]='m';
00803       AFMFileName[j+4]='\0';
00804     }
00805     else{
00806       /* we found a '.' -> replace extension */
00807       AFMFileName[i+1]='a';
00808       AFMFileName[i+2]='f';
00809       AFMFileName[i+3]='m';
00810       AFMFileName[i+4]='\0';
00811     }
00812   }
00813   
00814   /* Get full path of the afm file (The case of a full path name
00815      name specification is valid */
00816   AFMFileNamePath=intT1_Env_GetCompletePath( AFMFileName, T1_AFM_ptr);
00817   free( AFMFileName);
00818   
00819   /* open afm-file: */
00820   if (AFMFileNamePath!=NULL){
00821     if ((metricsfile=fopen(AFMFileNamePath,"rb"))==NULL){
00822       free(AFMFileNamePath);
00823       return(-4);
00824     }
00825     else {
00826       free(AFMFileNamePath);
00827     }
00828   }
00829   else{
00830     return( -5);
00831   }
00832   
00833   /* Call procedure to read afm-file and store the data formatted.
00834      Flags used here: P_M  All Metrics Information
00835                       P_P  Pair Kerning Information
00836                     P_C  Composite Character Data (since t1lib V.1.2)
00837      The P_G flag to get global font information should not be used
00838      if not absolutely needed. When parsing an unknown keyword, which
00839      may be harmless, the T1lib_parseFile function returns the error code
00840      -1 (parseError). On the other hand, all other really relevant
00841      data may habe been parsed and stored correctly. In such a case,
00842      There's no way to make a serious decision whether an error has
00843      occured or not.
00844      */
00845   if (open_sloppy!=0)
00846     i=T1lib_parseFile( (FILE *) metricsfile,
00847                      (FontInfo **) &(FontBase.pFontArray[FontID].pAFMData),
00848                      P_M );
00849   else
00850     i=T1lib_parseFile( (FILE *) metricsfile,
00851                      (FontInfo **) &(FontBase.pFontArray[FontID].pAFMData),
00852                      P_G | P_M | P_P | P_C );
00853   fclose(metricsfile);
00854   return(i);
00855 }
00856 
00857 
00858 
00859 /* T1int_CreateNewFontSize( FontID, size): Create a new size "size" of font
00860    "FontID" and allocate all data necessary for this. The data
00861    structure is connected to the linked list of FontSizeDeps for this
00862    font. Returns a pointer to the newly created FontSizeDeps-struct
00863    if all went correct and NULL otherwise.
00864    Since of version 0.3 a member antialias has been added to the
00865    FONTSIZEDEPS structure! This can be:
00866 
00867    0:     bitmaps are stored in this struct
00868    1:     non-antialiased bytemaps are stored in this struct
00869    2:     low-antialiased bytemaps are stored in this struct
00870    4:     high-antialiased bytemaps are stored in this struct
00871    */
00872 FONTSIZEDEPS *T1int_CreateNewFontSize( int FontID, float size, int aa)
00873 {
00874 
00875   FONTSIZEDEPS *pFontSizeDeps, *pPrev;
00876   
00877 
00878   /* First, get to the last font size in the linked list for this font.
00879      The following routine returns the address of the last struct in the
00880      linked list of FONTSIZEDEPS or NULL if none exists. */
00881   pFontSizeDeps=T1int_GetLastFontSize( FontID);
00882   pPrev=pFontSizeDeps;
00883   
00884   
00885   if (pFontSizeDeps==NULL){
00886     /* Allocate memory for first FontSizeDeps-structure: */
00887     if ((pFontBase->pFontArray[FontID].pFontSizeDeps=(FONTSIZEDEPS *)malloc(sizeof(FONTSIZEDEPS)))==NULL){
00888       T1_errno=T1ERR_ALLOC_MEM;
00889       return(NULL);
00890     }
00891     pFontSizeDeps=pFontBase->pFontArray[FontID].pFontSizeDeps;
00892   }
00893   else{
00894     /* A valid address of an existing structure was found */
00895     if ((pFontSizeDeps->pNextFontSizeDeps=(FONTSIZEDEPS *)malloc(sizeof(FONTSIZEDEPS)))==NULL){
00896       T1_errno=T1ERR_ALLOC_MEM;
00897       return(NULL);
00898     }
00899     pFontSizeDeps=pFontSizeDeps->pNextFontSizeDeps;
00900   }
00901 
00902   /* The pointer to the previous struct */
00903   pFontSizeDeps->pPrevFontSizeDeps=pPrev;
00904   /* Put the size into this structure */
00905   pFontSizeDeps->size=size;
00906   /* Set the antialias mark: */
00907   pFontSizeDeps->antialias=aa;
00908   
00909   /* Just the current becomes now the last item in the linked list: */
00910   pFontSizeDeps->pNextFontSizeDeps=NULL;
00911   /* Setup CharSpaceMatrix for this font: */
00912   pFontSizeDeps->pCharSpaceLocal=(struct XYspace *) IDENTITY;
00913   /* Apply transformation with font matrix: */
00914   pFontSizeDeps->pCharSpaceLocal=(struct XYspace *)
00915     Transform(pFontSizeDeps->pCharSpaceLocal,
00916              pFontBase->pFontArray[FontID].FontMatrix[0],
00917              pFontBase->pFontArray[FontID].FontMatrix[1],
00918              pFontBase->pFontArray[FontID].FontMatrix[2],
00919              pFontBase->pFontArray[FontID].FontMatrix[3]);
00920   /* Apply a further transformation (optionally): */
00921   pFontSizeDeps->pCharSpaceLocal=(struct XYspace *)
00922     Transform(pFontSizeDeps->pCharSpaceLocal,
00923              pFontBase->pFontArray[FontID].FontTransform[0],
00924              pFontBase->pFontArray[FontID].FontTransform[1],
00925              pFontBase->pFontArray[FontID].FontTransform[2],
00926              pFontBase->pFontArray[FontID].FontTransform[3]);
00927   /* Apply desired scaling factor, and make it Permanent */
00928   pFontSizeDeps->pCharSpaceLocal=(struct XYspace *) Permanent
00929     (Scale(pFontSizeDeps->pCharSpaceLocal, size, size));
00930                                                   
00931   /* We should now allocate memory for the glyph area of the font
00932      cache: */
00933   if ((pFontSizeDeps->pFontCache=(GLYPH *)calloc(256,sizeof(GLYPH)))
00934       ==NULL)
00935     return(NULL);
00936 
00937   sprintf( err_warn_msg_buf, "New Size %f created for FontID %d (antialias=%d)",
00938           pFontSizeDeps->size, FontID, pFontSizeDeps->antialias);
00939   T1_PrintLog( "CreateNewFontSize()", err_warn_msg_buf, T1LOG_STATISTIC);
00940   /* We are done */
00941   return(pFontSizeDeps);
00942   
00943 }
00944 
00945   
00946 
00947 
00948 /* T1_QueryFontSize( FontID, size, aa): Search if a requested size of font
00949    FontID is already existing. If so, it returns a pointer to the
00950    respective FontSizeDeps-structure,  otherwise NULL is returned: */
00951 FONTSIZEDEPS *T1int_QueryFontSize( int FontID, float size, int aa)
00952 {
00953   
00954   FONTSIZEDEPS *link_ptr;
00955 
00956 
00957   /* There's not yet one size: */
00958   if (pFontBase->pFontArray[FontID].pFontSizeDeps == NULL)
00959     return(pFontBase->pFontArray[FontID].pFontSizeDeps);
00960   
00961 
00962   /* There's already existing one or more size */
00963   link_ptr=pFontBase->pFontArray[FontID].pFontSizeDeps;
00964   
00965   while (((link_ptr->size != size)||(link_ptr->antialias != aa))
00966         &&(link_ptr->pNextFontSizeDeps != NULL))
00967     link_ptr=link_ptr->pNextFontSizeDeps;
00968   
00969   if ((link_ptr->size != size)||(link_ptr->antialias != aa))
00970     return( NULL);     /* requested size/aa-combination  was not found */
00971   else
00972     return(link_ptr); /* return pointer to requested struct */
00973   
00974 }
00975 
00976 /* FONTSIZEDEPS *T1int_GetLastFontSize( FontID): Get the address of the
00977    last struct in the linked list of FontSizeDeps or NULL if there is
00978    no existing size dependent data. */
00979 FONTSIZEDEPS *T1int_GetLastFontSize( int FontID)
00980 {
00981   FONTSIZEDEPS *link_ptr, *result_ptr;
00982   
00983 
00984   /* There's not yet one size: */
00985   if (pFontBase->pFontArray[FontID].pFontSizeDeps == NULL)
00986     return((FONTSIZEDEPS *) (pFontBase->pFontArray[FontID].pFontSizeDeps));
00987   
00988   
00989   /* There's already existing one or more size */
00990   link_ptr=pFontBase->pFontArray[FontID].pFontSizeDeps;
00991   
00992   while (link_ptr != NULL){
00993     result_ptr=link_ptr;
00994     link_ptr=link_ptr->pNextFontSizeDeps;
00995   }
00996 
00997   return((FONTSIZEDEPS *)(result_ptr));
00998 }
00999 
01000 
01001 /* A function for comparing METRICS_ENTRY structs */
01002 static int cmp_METRICS_ENTRY( const void *entry1, const void *entry2)
01003 {
01004   if (((METRICS_ENTRY *)entry1)->chars <
01005       ((METRICS_ENTRY *)entry2)->chars)
01006     return(-1);
01007   if (((METRICS_ENTRY *)entry1)->chars >
01008       ((METRICS_ENTRY *)entry2)->chars)
01009     return(1);
01010   return(0); /* This should not happen */
01011 }
01012     
01013