1 /*--------------------------------------------------------------------------
2   ----- File:        t1load.c
3   ----- Author:      Rainer Menzner (Rainer.Menzner@web.de)
4   ----- Date:        2007-12-23
5   ----- Description: This file is part of the t1-library. It contains
6                      functions for loading fonts  and for managing size
7 		     dependent data.
8   ----- Copyright:   t1lib is copyrighted (c) Rainer Menzner, 1996-2007.
9                      As of version 0.5, t1lib is distributed under the
10 		     GNU General Public Library Lincense. The
11 		     conditions can be found in the files LICENSE and
12 		     LGPL, which should reside in the toplevel
13 		     directory of the distribution.  Please note that
14 		     there are parts of t1lib that are subject to
15 		     other licenses:
16 		     The parseAFM-package is copyrighted by Adobe Systems
17 		     Inc.
18 		     The type1 rasterizer is copyrighted by IBM and the
19 		     X11-consortium.
20   ----- Warranties:  Of course, there's NO WARRANTY OF ANY KIND :-)
21   ----- Credits:     I want to thank IBM and the X11-consortium for making
22                      their rasterizer freely available.
23 		     Also thanks to Piet Tutelaers for his ps2pk, from
24 		     which I took the rasterizer sources in a format
25 		     independent from X11.
26                      Thanks to all people who make free software living!
27 --------------------------------------------------------------------------*/
28 
29 #define T1LOAD_C
30 
31 #define ANSI_REALLOC_VM
32 
33 /* Note: On some systems, like e.g. my Linux box, realloc() frequently returns
34          the identical pointer, if the memory chunk is *decreased* in size. As
35 	 a consequence, pointer shifting (as implemented below) would never
36 	 actually appear. The following definition enforces pointer shifting,
37 	 and hence allows to check pointer shifting on every system. Do not
38 	 activate this, it is meant for testing only!
39 */
40 /* #define ANSI_REALLOC_ENFORCE_POINTERSHIFTING */
41 
42 #include <stdio.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #if defined(_MSC_VER)
47 # include <io.h>
48 # include <sys/types.h>
49 # include <sys/stat.h>
50 #else
51 # include <unistd.h>
52 #endif
53 #include <stdlib.h>
54 #include <math.h>
55 #include <string.h>
56 
57 #include "../type1/ffilest.h"
58 #include "../type1/types.h"
59 #include "parseAFM.h"
60 #include "../type1/objects.h"
61 #include "../type1/spaces.h"
62 #include "../type1/util.h"
63 #include "../type1/fontfcn.h"
64 #include "../type1/blues.h"
65 #include "../type1/paths.h"
66 #include "../type1/regions.h"
67 
68 
69 #include "t1types.h"
70 #include "t1extern.h"
71 #include "t1load.h"
72 #include "t1env.h"
73 #include "t1set.h"
74 #include "t1base.h"
75 #include "t1finfo.h"
76 #include "t1afmtool.h"
77 
78 
79 
80 extern psobj *StdEncArrayP;       /* For checking of a fonts encoding */
81 extern char not_def[];            /* for checking the ".notdef"-string */
82 
83 
84 
85 /* T1_LoadFont(FontID): Loads a Type1 font into memory and allocates all
86    memory, necessary for this. */
87 
T1_LoadFont(int FontID)88 int T1_LoadFont( int FontID)
89 {
90   int i, j, k, l, m, n;
91   char *FileName, *FileNamePath;
92   int mode;  /* This is used by the type1-library for error reporting */
93   char *charname;
94 
95   /* The following vars are used for reallocation of VM */
96   long tmp_size;
97   float ascender;
98 #ifdef ANSI_REALLOC_VM
99   unsigned long shift;
100   unsigned long ldummy;
101   char *tmp_ptr;
102 #endif
103 
104   struct region *area;
105   struct XYspace *S;
106 
107   /* These are for constructing the kerning lookup table: */
108   PairKernData *pkd;
109   METRICS_ENTRY *kern_tbl;
110   int char1, char2;
111 
112 
113   if (T1_CheckForInit()){
114     T1_errno=T1ERR_OP_NOT_PERMITTED;
115     return(-1);
116   }
117 
118 
119   i=T1_CheckForFontID(FontID);
120   if (i==1)
121     return(0);      /* Font already loaded */
122   if (i==-1){
123     T1_errno=T1ERR_INVALID_FONTID;
124     return(-1);     /* illegal FontID */
125   }
126 
127   /* Allocate memory for ps_font structure: */
128   if ((pFontBase->pFontArray[FontID].pType1Data=(psfont *)malloc(sizeof(psfont)))==NULL){
129     T1_PrintLog( "T1_LoadFont()", "Failed to allocate memory for psfont-struct (FontID=%d)",
130 		 T1LOG_ERROR, FontID);
131     T1_errno=T1ERR_ALLOC_MEM;
132     return(-1);
133   }
134 
135   /* Check for valid filename */
136   if ((FileName=T1_GetFontFileName(FontID))==NULL){
137     T1_PrintLog( "T1_LoadFont()", "No font file name for font %d", T1LOG_ERROR, FontID);
138     return(-1);
139   }
140 
141   /* Fetch the full path of type1 font file */
142   if ((FileNamePath=intT1_Env_GetCompletePath( FileName,
143 					 T1_PFAB_ptr))==NULL){
144     T1_PrintLog( "T1_LoadFont()", "Couldn't locate font file for font %d in %s",
145 		 T1LOG_ERROR, FontID, T1_GetFileSearchPath(T1_PFAB_PATH));
146     T1_errno=T1ERR_FILE_OPEN_ERR;
147     return(-1);
148   }
149 
150   /* And load all PostScript information into memory */
151   if (fontfcnA( FileNamePath, &mode,
152 		pFontBase->pFontArray[FontID].pType1Data) == FALSE){
153     T1_PrintLog( "T1_LoadFont()", "Loading font with ID = %d failed! (mode = %d)",
154 		 T1LOG_ERROR, FontID, mode);
155     free(FileNamePath);
156     pFontBase->pFontArray[FontID].pType1Data=NULL;
157     T1_errno=mode;
158     return(-1);
159   }
160   free(FileNamePath);
161 
162 
163   /* Set some default for FontBBox and Encoding if the font does not provide
164      correct data. Strictly taken, these fonts do not adhere to the Type1
165      specification. However, it is easy to work around and find reasonable
166      defaults. This solution has been proposed by the Debian community (see
167      http://bugs.debian.org/313236). */
168   /* 1. FontBBox. We set default values of 0 which is recommended by Adobe
169      in cases where the font does not make use of the SEAC primitive. Later on,
170      if AFM fallback info is computed, these settings might be overwritten with
171      meaningful values. */
172   if (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTBBOX].value.data.arrayP == NULL) {
173     if ((pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTBBOX].value.data.arrayP =
174 	 (psobj *)vm_alloc(4 * sizeof(psobj))) == NULL) {
175       T1_PrintLog( "T1_LoadFont()", "Error allocating memory for fontbbox objects (FontID=%d)",
176 		   T1LOG_ERROR, FontID);
177       T1_errno=T1ERR_ALLOC_MEM;
178       return(-1);
179     }
180     for (n = 0; n < 4; n++) {
181       pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTBBOX].value.data.arrayP[n].type = OBJ_INTEGER;
182       pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTBBOX].value.data.arrayP[n].len = 0;
183       pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTBBOX].value.data.arrayP[n].data.integer = 0;
184     }
185     T1_PrintLog( "T1_LoadFont()", "Missing FontBBox, adding a trivial one in order to avoid crashes (FontID=%d)",
186 		 T1LOG_WARNING, FontID);
187   }
188   /* 2. Encoding. In this case, we simply fallback to Standard Encoding. */
189   if (pFontBase->pFontArray[FontID].pFontEnc == NULL &&
190       pFontBase->pFontArray[FontID].pType1Data->fontInfoP[ENCODING].value.data.arrayP == NULL) {
191     pFontBase->pFontArray[FontID].pType1Data->fontInfoP[ENCODING].value.data.valueP = (char *) StdEncArrayP;
192     T1_PrintLog( "T1_LoadFont()", "Missing, invalid  or undefined Encoding, setting up Standard Encoding in order to avoid crashes (FontID=%d)",
193 		 T1LOG_WARNING, FontID);
194   }
195 
196 
197   /* Store the base address of virtual memory and realloc in order not
198      to waste too much memory: */
199   pFontBase->pFontArray[FontID].vm_base=vm_base;
200 #ifdef ANSI_REALLOC_VM
201   /* We first get the size of pointers on the current system */
202   /* Get size of VM, ... */
203   tmp_size=((unsigned long)vm_used - (unsigned long)vm_base);
204   /* ... realloc to that size ... */
205 #ifdef ANSI_REALLOC_ENFORCE_POINTERSHIFTING
206   tmp_ptr=(char *)malloc( tmp_size);
207   memcpy( tmp_ptr, vm_base, tmp_size);
208 #else
209   tmp_ptr=(char *)realloc(vm_base,  tmp_size);
210 #endif
211   /* ... and shift all pointers refering to that area */
212   if (tmp_ptr > vm_base){
213     shift= (unsigned long)tmp_ptr - (unsigned long)vm_base;
214     sprintf( err_warn_msg_buf,
215 	     "Old VM at 0x%lX, new VM at 0x%lX, shifting up by %lu",
216 	     (unsigned long)vm_base, (unsigned long)tmp_ptr, tmp_size);
217     T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
218 
219     /* We start by shifting the topmost pointers: */
220     pFontBase->pFontArray[FontID].vm_base=tmp_ptr;
221 
222     ldummy=(long)(pFontBase->pFontArray[FontID].pType1Data->vm_start);
223     ldummy +=shift;
224     pFontBase->pFontArray[FontID].pType1Data->vm_start=(char *)ldummy;
225 
226     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP;
227     ldummy +=shift;
228     pFontBase->pFontArray[FontID].pType1Data->CharStringsP=(psdict *)ldummy;
229 
230     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Private;
231     ldummy +=shift;
232     pFontBase->pFontArray[FontID].pType1Data->Private=(psdict *)ldummy;
233 
234     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP;
235     ldummy +=shift;
236     pFontBase->pFontArray[FontID].pType1Data->fontInfoP=(psdict *)ldummy;
237 
238     ldummy=(long)(pFontBase->pFontArray[FontID].pType1Data->BluesP);
239     ldummy +=shift;
240     pFontBase->pFontArray[FontID].pType1Data->BluesP=(struct blues_struct *)ldummy;
241 
242     /* We now have to care for correcting all pointers which are in the VM
243        and refer to some place in the VM! Note: Instead of selecting the
244        appropriate pointer-elements of the union we simply shift the
245        unspecified pointer "valueP".
246        Note: The filename entry does not need to be modified since it does not
247        need to be shifted since it points to memory managed by t1lib.
248        */
249     /* FontInfo-dictionary: All name-pointers and the pointers to all array
250        types have to be shifted: */
251     i=pFontBase->pFontArray[FontID].pType1Data->fontInfoP[0].key.len;
252     for (j=1; j<=i; j++){
253       if ((pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_ARRAY) ||
254 	  (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_STRING) ||
255 	  (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_NAME) ||
256 	  (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_FILE)){
257 	ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP;
258 	ldummy +=shift;
259 	pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP=(char *)ldummy;
260       }
261       /* The encoding needs special treatment: */
262       if (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_ENCODING){
263 	/* If builtin StandardEncoding is used, we do nothing here. Standard Encoding
264 	   is now located once for all fonts on the heap. For font-specific encodings
265 	   we have to move all pointers appropriately, because this is entirely located
266 	   in VM */
267 	if (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.arrayP
268 	    == StdEncArrayP){ /* Font uses builtin StandardEncoding */
269 	  ;
270 	}
271 	else{ /* Font-specific encoding */
272 	  ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP;
273 	  ldummy +=shift;
274 	  pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP=(char *)ldummy;
275 	  for (k=0; k<256; k++){
276 	    ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.arrayP[k].data.arrayP;
277 	    /* The ".notdef" is also static and may not be shifted (Thanks, Derek ;) */
278 	    if (ldummy != (unsigned long)not_def) {
279 	      ldummy +=shift;
280 	      pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.arrayP[k].data.arrayP=(struct ps_obj *)ldummy;
281 	    }
282 	  }
283 	}
284       } /* end of encoding-handling */
285       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].key.data.valueP;
286       ldummy +=shift;
287       pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].key.data.valueP=(char *)ldummy;
288     } /* fontinfo-dict done */
289 
290     /* Private-dictionary: All name-pointers and the pointers to all array
291        types have to be shifted: */
292     i=pFontBase->pFontArray[FontID].pType1Data->Private[0].key.len;
293     for (j=1; j<=i; j++){
294       if ((pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_ARRAY) ||
295 	  (pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_STRING) ||
296 	  (pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_NAME) ||
297 	  (pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_FILE)){
298 	ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Private[j].value.data.valueP;
299 	ldummy +=shift;
300 	pFontBase->pFontArray[FontID].pType1Data->Private[j].value.data.valueP=(char *)ldummy;
301       }
302       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Private[j].key.data.valueP;
303       ldummy +=shift;
304       pFontBase->pFontArray[FontID].pType1Data->Private[j].key.data.valueP=(char *)ldummy;
305     }
306 
307     /* BluesP: The entry "next" is the only pointer in blues_struct. Although it is
308        not used anywhere we should shift it for correctness reasons (in case its not
309        NULL)! */
310     if (pFontBase->pFontArray[FontID].pType1Data->BluesP->next != NULL){
311       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->BluesP->next;
312       ldummy +=shift;
313       pFontBase->pFontArray[FontID].pType1Data->BluesP->next=(struct blues_struct *)ldummy;
314     }
315 
316     /* The CharStrings-dictionary: Every namepointer and its corresponding
317        charstring has to be shifted: */
318     i=pFontBase->pFontArray[FontID].pType1Data->CharStringsP[0].key.len;
319     for (j=1; j<=i; j++){
320       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].value.data.valueP;
321       ldummy +=shift;
322       pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].value.data.valueP=(char *)ldummy;
323       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].key.data.valueP;
324       ldummy +=shift;
325       pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].key.data.valueP=(char *)ldummy;
326     }
327 
328     /* The Subroutines have also to be reorganized: */
329     i=pFontBase->pFontArray[FontID].pType1Data->Subrs.len;
330     /* First, shift pointer to array-start and after that the pointers to
331        each command string: */
332     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP;
333     ldummy +=shift;
334     pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP=(struct ps_obj *)ldummy;
335     for (j=0; j<i; j++) {
336       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP[j].data.valueP;
337       ldummy +=shift;
338       pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP[j].data.valueP=(char *)ldummy;
339     }
340   } /* end of if( tmp_ptr > vm_base ) */
341   else if ( vm_base > tmp_ptr){
342     shift= (unsigned long)vm_base - (unsigned long)tmp_ptr;
343     sprintf( err_warn_msg_buf,
344 	     "Old VM at 0x%lX, new VM at 0x%lX, shifting down by %lu",
345 	     (unsigned long)vm_base, (unsigned long)tmp_ptr, tmp_size);
346     T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
347 
348     /* We start by shifting the topmost pointers: */
349     pFontBase->pFontArray[FontID].vm_base=tmp_ptr;
350 
351     ldummy=(long)(pFontBase->pFontArray[FontID].pType1Data->vm_start);
352     ldummy -=shift;
353     pFontBase->pFontArray[FontID].pType1Data->vm_start=(char *)ldummy;
354 
355     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP;
356     ldummy -=shift;
357     pFontBase->pFontArray[FontID].pType1Data->CharStringsP=(psdict *)ldummy;
358 
359     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Private;
360     ldummy -=shift;
361     pFontBase->pFontArray[FontID].pType1Data->Private=(psdict *)ldummy;
362 
363     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP;
364     ldummy -=shift;
365     pFontBase->pFontArray[FontID].pType1Data->fontInfoP=(psdict *)ldummy;
366 
367     ldummy=(long)(pFontBase->pFontArray[FontID].pType1Data->BluesP);
368     ldummy -=shift;
369     pFontBase->pFontArray[FontID].pType1Data->BluesP=(struct blues_struct *)ldummy;
370 
371     /* We now have to care for correcting all pointers which are in the VM
372        and refer to some place in the VM! Note: Instead of selecting the
373        appropriate pointer-elements of the union we simply shift the
374        unspecified pointer "valueP".
375        Note: The filename entry does not need to be modified since it does not
376        need to be shifted since it points to memory managed by t1lib.
377        */
378     /* FontInfo-dictionary: All name-pointers and the pointers to all array
379        types have to be shifted: */
380     i=pFontBase->pFontArray[FontID].pType1Data->fontInfoP[0].key.len;
381     for (j=1; j<=i; j++){
382       if ((pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_ARRAY) ||
383 	  (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_STRING) ||
384 	  (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_NAME) ||
385 	  (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_FILE)){
386 	ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP;
387 	ldummy -=shift;
388 	pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP=(char *)ldummy;
389       }
390       /* The encoding needs special treatment: */
391       if (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.type==OBJ_ENCODING){
392 	/* If builtin StandardEncoding is used, we do nothing here. Standard Encoding
393 	   is now located once for all fonts on the heap. For font-specific encodings
394 	   we have to move all pointers appropriately, because this is entirely located
395 	   in VM */
396 	if (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.arrayP
397 	    == StdEncArrayP){ /* Font uses builtin StandardEncoding */
398 	  ;
399 	}
400 	else{ /* Font-specific encoding */
401 	  ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP;
402 	  ldummy -=shift;
403 	  pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.valueP=(char *)ldummy;
404 	  for (k=0; k<256; k++){
405 	    ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.arrayP[k].data.arrayP;
406 	    /* The ".notdef" is also static and may not be shifted (Thanks, Derek ;) */
407 	    if (ldummy != (unsigned long)not_def) {
408 	      ldummy -=shift;
409 	      pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].value.data.arrayP[k].data.arrayP=(struct ps_obj *)ldummy;
410 	    }
411 	  }
412 	}
413       } /* end of encoding-handling */
414       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].key.data.valueP;
415       ldummy -=shift;
416       pFontBase->pFontArray[FontID].pType1Data->fontInfoP[j].key.data.valueP=(char *)ldummy;
417     } /* fontinfo-dict done */
418 
419     /* Private-dictionary: All name-pointers and the pointers to all array
420        types have to be shifted: */
421     i=pFontBase->pFontArray[FontID].pType1Data->Private[0].key.len;
422     for (j=1; j<=i; j++){
423       if ((pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_ARRAY) ||
424 	  (pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_STRING) ||
425 	  (pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_NAME) ||
426 	  (pFontBase->pFontArray[FontID].pType1Data->Private[j].value.type==OBJ_FILE)){
427 	ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Private[j].value.data.valueP;
428 	ldummy -=shift;
429 	pFontBase->pFontArray[FontID].pType1Data->Private[j].value.data.valueP=(char *)ldummy;
430       }
431       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Private[j].key.data.valueP;
432       ldummy -=shift;
433       pFontBase->pFontArray[FontID].pType1Data->Private[j].key.data.valueP=(char *)ldummy;
434     }
435 
436     /* BluesP: The entry "next" is the only pointer in blues_struct. Although it is
437        not used anywhere we should shift it for correctness reasons (in case its not
438        NULL)! */
439     if (pFontBase->pFontArray[FontID].pType1Data->BluesP->next != NULL){
440       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->BluesP->next;
441       ldummy -=shift;
442       pFontBase->pFontArray[FontID].pType1Data->BluesP->next=(struct blues_struct *)ldummy;
443     }
444 
445     /* The CharStrings-dictionary: Every namepointer and its corresponding
446        charstring has to be shifted: */
447     i=pFontBase->pFontArray[FontID].pType1Data->CharStringsP[0].key.len;
448     for (j=1; j<=i; j++){
449       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].value.data.valueP;
450       ldummy -=shift;
451       pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].value.data.valueP=(char *)ldummy;
452       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].key.data.valueP;
453       ldummy -=shift;
454       pFontBase->pFontArray[FontID].pType1Data->CharStringsP[j].key.data.valueP=(char *)ldummy;
455     }
456 
457     /* The Subroutines have also to be reorganized: */
458     i=pFontBase->pFontArray[FontID].pType1Data->Subrs.len;
459     /* First, shift pointer to array-start and after that the pointers to
460        each command string: */
461     ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP;
462     ldummy -=shift;
463     pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP=(struct ps_obj *)ldummy;
464     for (j=0; j<i; j++) {
465       ldummy=(long)pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP[j].data.valueP;
466       ldummy -=shift;
467       pFontBase->pFontArray[FontID].pType1Data->Subrs.data.arrayP[j].data.valueP=(char *)ldummy;
468     }
469   } /* end of if( vm_base > tmp_ptr ) */
470   else{ /* VM addess has not changed during reallocation */
471     sprintf( err_warn_msg_buf,
472 	     "Old VM and new VM at 0x%lX, no pointer-shifting",
473 	     (unsigned long)vm_base);
474     T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
475   }
476 #ifdef ANSI_REALLOC_ENFORCE_POINTERSHIFTING
477   /* If pointer shifting had been enforced by allocating from
478      scratch using malloc() free the previous vm. */
479   free( vm_base);
480 #endif
481 #endif
482 
483   /* Generate a message how much VM the current font consumes */
484   sprintf( err_warn_msg_buf,
485 	   "VM for Font %d: %d bytes", FontID, (int) tmp_size);
486   T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_STATISTIC);
487 
488 
489   /* Set the matrix for common transformations to "no transformations" */
490   pFontBase->pFontArray[FontID].FontTransform[0]=1.0;
491   pFontBase->pFontArray[FontID].FontTransform[1]=0.0;
492   pFontBase->pFontArray[FontID].FontTransform[2]=0.0;
493   pFontBase->pFontArray[FontID].FontTransform[3]=1.0;
494 
495   /* Now, that the font has been loaded into memory, try to find the
496      FontMatrix in the font info dictionary. If it exists, load it into
497      our local fontmatrix, otherwise use a default matrix which scales to
498      1/1000 (since font outlines  are defined in a 1000 point space)
499      and does no further transformations. */
500   if (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTMATRIX].value.data.arrayP == NULL){
501     pFontBase->pFontArray[FontID].FontMatrix[0]=0.001;
502     pFontBase->pFontArray[FontID].FontMatrix[1]=0.0;
503     pFontBase->pFontArray[FontID].FontMatrix[2]=0.0;
504     pFontBase->pFontArray[FontID].FontMatrix[3]=0.001;
505   }
506   else{
507     pFontBase->pFontArray[FontID].FontMatrix[0]= (double)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTMATRIX].value.data.arrayP[0].data.real;
508     pFontBase->pFontArray[FontID].FontMatrix[1]= (double)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTMATRIX].value.data.arrayP[1].data.real;
509     pFontBase->pFontArray[FontID].FontMatrix[2]= (double)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTMATRIX].value.data.arrayP[2].data.real;
510     pFontBase->pFontArray[FontID].FontMatrix[3]= (double)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[FONTMATRIX].value.data.arrayP[3].data.real;
511   }
512 
513   /* Set the default values for transformation: */
514   pFontBase->pFontArray[FontID].slant=0.0;
515   pFontBase->pFontArray[FontID].extend=1.0;
516 
517 
518   /* Now try to load afm-structures from corresponding .afm-file (if
519      not suppressed by the user). */
520   if ((pFontBase->t1lib_flags & T1_NO_AFM)!=0) {
521     pFontBase->pFontArray[FontID].pAFMData = NULL;
522     T1_PrintLog( "T1_LoadFont()",
523 		 "Suppressing AFM data handling on user request",
524 		 T1LOG_STATISTIC);
525   }
526   else {
527     if ((i=openFontMetricsFile( FontID, 0))){
528       /* Try a fallback, opening sloppy: */
529       if ((i=openFontMetricsFile( FontID, 1))) {
530 	sprintf( err_warn_msg_buf,
531 		 "Alert: Error (%d) sloppy-processing afm-file for Font %d!",
532 		 i ,FontID);
533 	T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_STATISTIC);
534 	if ((pFontBase->pFontArray[FontID].pAFMData=
535 	     T1_GenerateAFMFallbackInfo(FontID))==NULL){
536 	  sprintf( err_warn_msg_buf,
537 		   "Ultimately failed to generate metrics information Font %d!",
538 		   FontID);
539 	  T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_WARNING);
540 	}
541 	else {
542 	  pFontBase->pFontArray[FontID].info_flags |=AFM_SELFGEN_SUCCESS;
543 	  T1_PrintLog( "T1_LoadFont()",
544 		       "Generating AFM-information from fontfile successful!",
545 		       T1LOG_STATISTIC);
546 	}
547       }
548       else {
549 	pFontBase->pFontArray[FontID].info_flags |=AFM_SLOPPY_SUCCESS;
550 	sprintf( err_warn_msg_buf,
551 		 "Alert: Limited afm-information for Font %d",FontID);
552 	T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_STATISTIC);
553       }
554     }
555     else {
556       pFontBase->pFontArray[FontID].info_flags |=AFM_SUCCESS;
557     }
558   }
559 
560 
561   /* Now, set Encodingvector entry to default if the font's
562      internal encoding is "StandardEncoding".
563      */
564   if (pFontBase->pFontArray[FontID].pType1Data->fontInfoP[ENCODING].value.data.arrayP
565       == StdEncArrayP) {
566     pFontBase->pFontArray[FontID].info_flags |=USES_STANDARD_ENCODING;
567     pFontBase->pFontArray[FontID].pFontEnc=pFontBase->default_enc;
568     sprintf( err_warn_msg_buf,
569 	     "Font %d reencoded to default",FontID);
570     T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
571   }
572   else {
573     sprintf( err_warn_msg_buf,
574 	     "Font %d not reencoded to default",FontID);
575     T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
576     pFontBase->pFontArray[FontID].pFontEnc = NULL;
577   }
578 
579 
580   /* If AFM-Info available we try to speed up some things: */
581   if (pFontBase->pFontArray[FontID].pAFMData != NULL) {
582     /* We have to fill the array that maps the current encodings' indices to the
583        indices used in afm file. The interpretation has been changed in
584        in t1lib-1.2. We now use positive values for indexing into the charmetrics
585        array and negative values for indexing into the composite character array.
586        an index of zero indicates that no metrics are defined for this character.
587        This may happen because (a) not all AFM-files define metrics for the .notdef
588        character, and (b) because font and AFM-file do not match. */
589     if ((pFontBase->pFontArray[FontID].pEncMap=
590 	 (int *)calloc(256,sizeof(int)))==NULL) {
591       sprintf( err_warn_msg_buf, "Error allocating memory for encoding map (FontID=%d)",
592 	       FontID);
593       T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf,
594 		 T1LOG_WARNING);
595       T1_errno=T1ERR_ALLOC_MEM;
596       return(-1);
597     }
598     for (i=0; i<256; i++) {
599       charname=T1_GetCharName( FontID, i);
600       /* in a first loop check for ordinary characters */
601       for ( j=0; j<pFontBase->pFontArray[FontID].pAFMData->numOfChars; j++) {
602 	if (strcmp( charname,
603 		    pFontBase->pFontArray[FontID].pAFMData->cmi[j].name)==0) {
604 	  pFontBase->pFontArray[FontID].pEncMap[i]=j+1; /* index 0 is reserved! */
605 	  continue;
606 	}
607       }
608       /* if nothing has been found, check for composite characters */
609       for ( j=0; j<pFontBase->pFontArray[FontID].pAFMData->numOfComps; j++) {
610 	if (strcmp( charname,
611 		    pFontBase->pFontArray[FontID].pAFMData->ccd[j].ccName)==0) {
612 	  pFontBase->pFontArray[FontID].pEncMap[i]=-(j+1); /* index 0 is reserved! */
613 	  continue;
614 	}
615       }
616     }
617 
618     /* For composite characters, we still have to compute the width and bbox */
619     for ( j=0; j<pFontBase->pFontArray[FontID].pAFMData->numOfComps; j++) {
620       /*and bounding box by ourselves. First, set up an identity charspace
621 	matrix and then generate an edgelist for the composite character at
622 	size 1000bp using no transformation and current encoding. Note: This
623 	action is only required when loading a font at first time, but not
624 	when reencoding a font. */
625       S=(struct XYspace *)IDENTITY;
626       S=(struct XYspace *)Permanent
627 	(Transform(S, pFontBase->pFontArray[FontID].FontTransform[0],
628 		   pFontBase->pFontArray[FontID].FontTransform[1],
629 		   pFontBase->pFontArray[FontID].FontTransform[2],
630 		   pFontBase->pFontArray[FontID].FontTransform[3]));
631 
632       area=fontfcnB_ByName( FontID, 0, S,
633 			    pFontBase->pFontArray[FontID].pAFMData->ccd[j].ccName,
634 			    &mode, pFontBase->pFontArray[FontID].pType1Data,
635 			    DO_RASTER);
636       /* Store bounding box ... */
637       pFontBase->pFontArray[FontID].pAFMData->ccd[j].charBBox.llx=area->xmin;
638       pFontBase->pFontArray[FontID].pAFMData->ccd[j].charBBox.urx=area->xmax;
639       pFontBase->pFontArray[FontID].pAFMData->ccd[j].charBBox.lly=area->ymin;
640       pFontBase->pFontArray[FontID].pAFMData->ccd[j].charBBox.ury=area->ymax;
641       /* ... and character width. This should be the width of the base character
642 	 of the composite! */
643       pFontBase->pFontArray[FontID].pAFMData->ccd[j].wx=NEARESTPEL(area->ending.x);
644       /* clean up. */
645       KillRegion (area);
646       if (S!=NULL) {
647 	KillSpace (S);
648 	S=NULL;
649       }
650     }
651     /* We now create an encoding-specific kerning table which will speed up
652        looking for kerning pairs! */
653     pFontBase->pFontArray[FontID].KernMapSize=0;
654     /* First, get number of defined kerning pairs: */
655     k=pFontBase->pFontArray[FontID].pAFMData->numOfPairs;
656     if (k>0){ /* i.e., there are any pairs */
657       /* OK, it does not suffice to alloc numOfPairs METRICS_ENTRYs, because
658 	 a given character might be encoded at several locations and kerning
659 	 should still work. As a worst case estimation, we allocate 256^2
660 	 and realloc later. */
661       if ((pFontBase->pFontArray[FontID].pKernMap=
662 	   (METRICS_ENTRY *)malloc( (256*256) *sizeof( METRICS_ENTRY)))==NULL){
663 	sprintf( err_warn_msg_buf, "Error allocating memory for metrics map (FontID=%d)",
664 		 FontID);
665 	T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf,
666 		     T1LOG_WARNING);
667 	T1_errno=T1ERR_ALLOC_MEM;
668 	return(-1);
669       }
670       kern_tbl=pFontBase->pFontArray[FontID].pKernMap;
671       pkd=pFontBase->pFontArray[FontID].pAFMData->pkd;
672       j=0;
673       for ( i=0; i<k; i++) {
674 	/* We do not check T1_GetEncodingIndices() against the return value
675 	   NULL because we just loading the font in question: */
676 	l=0;
677 	while ((char1=(T1_GetEncodingIndices( FontID, pkd[i].name1))[l++])!=-1) {
678 	  /* pair could be relevant in current encoding */
679 	  m=0;
680 	  while ((char2=(T1_GetEncodingIndices( FontID, pkd[i].name2))[m++])!=-1) {
681 	    /* Since we get here we have a relevant pair -->
682 	       Put char1 in higher byte and char2 in LSB: */
683 	    kern_tbl[j].chars=(char1 << 8) | char2;
684 	    /* We only make use of horizontal kerning */
685 	    kern_tbl[j].hkern=pkd[i].xamt;
686 	    j++;
687 	  } /* while (char2) */
688 	} /* while (char1) */
689       } /* for */
690       /* We are done, realloc memory: */
691       kern_tbl=(METRICS_ENTRY*) realloc( kern_tbl, j*sizeof(METRICS_ENTRY));
692       /* We now sort the kerning array with respect to char indices */
693       qsort( kern_tbl, (size_t) j, sizeof(METRICS_ENTRY),
694 	     &cmp_METRICS_ENTRY );
695       /* Finally write back pointer for the case that realloc changed the
696 	 pointer */
697       pFontBase->pFontArray[FontID].pKernMap=kern_tbl;
698       pFontBase->pFontArray[FontID].KernMapSize=j;
699     }
700     else
701       pFontBase->pFontArray[FontID].pKernMap=NULL;
702   }
703   else { /* no AFM data */
704     pFontBase->pFontArray[FontID].pKernMap=NULL;
705     pFontBase->pFontArray[FontID].pEncMap=NULL;
706   }
707   /* End of "if (AFM-info ..)" */
708 
709 
710   /* We have just loaded a physical font into memory, thus .... */
711   pFontBase->pFontArray[FontID].physical=1;
712 
713   /* Set reference-counter to 1: */
714   pFontBase->pFontArray[FontID].refcount=1;
715 
716   /* Get the index into encoding vector where the space character is
717      found. If not encoded, set space_position to -1. */
718   pFontBase->pFontArray[FontID].space_position=-1;
719   i=0;
720   if (pFontBase->pFontArray[FontID].pFontEnc) { /* external default encoding */
721     while (i<256) {
722       if (strcmp( (char *)pFontBase->pFontArray[FontID].pFontEnc[i],
723 		  "space")==0){
724 	/* space found at position i: */
725 	pFontBase->pFontArray[FontID].space_position=i;
726 	break;
727       }
728       i++;
729     }
730   }
731   else { /* internal encoding */
732     while (i<256) {
733       if (strcmp( (char *)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[ENCODING].value.data.arrayP[i].data.arrayP,
734 		  "space")==0){
735 	/* space found at position i: */
736 	pFontBase->pFontArray[FontID].space_position=i;
737 	break;
738       }
739       i++;
740     }
741   }
742 
743 
744   /* Set the lining rule parameters to default values */
745   pFontBase->pFontArray[FontID].UndrLnPos=
746     pFontBase->pFontArray[FontID].pType1Data->fontInfoP[UNDERLINEPOSITION].value.data.real;
747   pFontBase->pFontArray[FontID].UndrLnThick=
748     pFontBase->pFontArray[FontID].pType1Data->fontInfoP[UNDERLINETHICKNESS].value.data.real;
749 
750   /* We have to set the value for the typographic ascender. If possible,
751      we get it from the afm-File. But be aware this value might be undefined!
752      This value should in any acse explicitly be set later by the user! */
753   if (pFontBase->pFontArray[FontID].pAFMData!=NULL &&
754       pFontBase->pFontArray[FontID].pAFMData->gfi!=NULL) {
755     ascender=(float) pFontBase->pFontArray[FontID].pAFMData->gfi->ascender;
756   }
757   else {
758     ascender=(float) T1_GetCharBBox( FontID, T1_GetEncodingIndex( FontID, "d")).ury;
759   }
760 
761   pFontBase->pFontArray[FontID].OvrLnPos=ascender
762     + (float) abs( (double)pFontBase->pFontArray[FontID].UndrLnPos);
763   pFontBase->pFontArray[FontID].OvrStrkPos=ascender / 2.0;
764   pFontBase->pFontArray[FontID].OvrLnThick=pFontBase->pFontArray[FontID].UndrLnThick;
765   pFontBase->pFontArray[FontID].OvrStrkThick=pFontBase->pFontArray[FontID].UndrLnThick;
766 
767 
768   /* Finally, set the font size dependencies pointer to NULL since we can
769      assume, that at load time of a font, no size specific data of this
770      font is available.
771      */
772 
773   pFontBase->pFontArray[FontID].pFontSizeDeps=NULL;
774 
775   /* If wanted, some debugging information is put into logfile */
776   sprintf( err_warn_msg_buf, "Pointer vm_base: 0x%lX",
777 	   (long)pFontBase->pFontArray[FontID].vm_base);
778   T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
779   sprintf( err_warn_msg_buf, "Pointer vm_start: 0x%lX",
780 	   (long)pFontBase->pFontArray[FontID].pType1Data->vm_start);
781   T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
782   sprintf( err_warn_msg_buf, "Pointer CharStringsP: 0x%lX",
783 	   (long)pFontBase->pFontArray[FontID].pType1Data->CharStringsP);
784   T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
785   sprintf( err_warn_msg_buf, "Pointer Private: 0x%lX",
786 	   (long)pFontBase->pFontArray[FontID].pType1Data->Private);
787   T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
788   sprintf( err_warn_msg_buf, "Pointer fontInfoP: 0x%lX",
789 	   (long)pFontBase->pFontArray[FontID].pType1Data->fontInfoP);
790   T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf, T1LOG_DEBUG);
791 
792   return(0);
793 }
794 
795 
796 /* openFontMetricsFile( FontID, open_sloppy): Gets the fontfilename
797    corresponding to FontID, opens the corresponding afm-file and fills
798    the data structures. return-value is the value returned by the
799    T1lib_parseFile() function. If open_sloppy is set, the minimum
800    information needed is read from AFM file. This can be considered a
801    fallback for problematic AFM files. */
openFontMetricsFile(int FontID,int open_sloppy)802 static int openFontMetricsFile( int FontID, int open_sloppy)
803 {
804   char *FontFileName;
805   char *AFMFileName;
806   char *afm_name;
807   char *AFMFileNamePath;
808 
809   int i, j;
810   FILE *metricsfile;
811 
812 
813   afm_name=T1_GetAfmFileName(FontID);
814 
815   if (afm_name!=NULL) { /* We have name explicitly specified */
816     /* It needs to be freeable */
817     if ((AFMFileName=
818 	 (char *)malloc( (strlen(afm_name)+1)*sizeof( char)))==NULL) {
819       T1_errno=T1ERR_ALLOC_MEM;
820       return( -6);
821     }
822     strcpy( AFMFileName, afm_name);
823   }
824   else {
825     FontFileName=T1_GetFontFileName( FontID);
826     i=strlen(FontFileName);
827     j=i;
828     AFMFileName=(char *)malloc( i+5);
829     strcpy( AFMFileName, FontFileName);
830     while ( AFMFileName[i] != '.'){
831       if (i==0) break;
832       else i--;
833     }
834     if (i==0){
835       /* We have a filename without extension -> append extension */
836       AFMFileName[j]='.';
837       AFMFileName[j+1]='a';
838       AFMFileName[j+2]='f';
839       AFMFileName[j+3]='m';
840       AFMFileName[j+4]='\0';
841     }
842     else{
843       /* we found a '.' -> replace extension */
844       AFMFileName[i+1]='a';
845       AFMFileName[i+2]='f';
846       AFMFileName[i+3]='m';
847       AFMFileName[i+4]='\0';
848     }
849   }
850 
851   /* Get full path of the afm file (The case of a full path name
852      name specification is valid */
853   AFMFileNamePath=intT1_Env_GetCompletePath( AFMFileName, T1_AFM_ptr);
854   free( AFMFileName);
855 
856   /* open afm-file: */
857   if (AFMFileNamePath!=NULL){
858     if ((metricsfile=fopen(AFMFileNamePath,"rb"))==NULL){
859       free(AFMFileNamePath);
860       return(-4);
861     }
862     else {
863       free(AFMFileNamePath);
864     }
865   }
866   else{
867     return( -5);
868   }
869 
870   /* Call procedure to read afm-file and store the data formatted.
871      Flags used here: P_M  All Metrics Information
872                       P_P  Pair Kerning Information
873 		      P_C  Composite Character Data (since t1lib V.1.2)
874      The P_G flag to get global font information should not be used
875      if not absolutely needed. When parsing an unknown keyword, which
876      may be harmless, the T1lib_parseFile function returns the error code
877      -1 (parseError). On the other hand, all other really relevant
878      data may habe been parsed and stored correctly. In such a case,
879      There's no way to make a serious decision whether an error has
880      occured or not.
881      */
882   if (open_sloppy!=0)
883     i=T1lib_parseFile( (FILE *) metricsfile,
884 		       (FontInfo **) &(FontBase.pFontArray[FontID].pAFMData),
885 		       P_M );
886   else
887     i=T1lib_parseFile( (FILE *) metricsfile,
888 		       (FontInfo **) &(FontBase.pFontArray[FontID].pAFMData),
889 		       P_G | P_M | P_P | P_C );
890   fclose(metricsfile);
891   return(i);
892 }
893 
894 
895 
896 /* T1int_CreateNewFontSize( FontID, size): Create a new size "size" of font
897    "FontID" and allocate all data necessary for this. The data
898    structure is connected to the linked list of FontSizeDeps for this
899    font. Returns a pointer to the newly created FontSizeDeps-struct
900    if all went correct and NULL otherwise.
901    Since of version 0.3 a member antialias has been added to the
902    FONTSIZEDEPS structure! This can be:
903 
904    0:     bitmaps are stored in this struct
905    1:     non-antialiased bytemaps are stored in this struct
906    2:     low-antialiased bytemaps are stored in this struct
907    4:     high-antialiased bytemaps are stored in this struct
908    */
T1int_CreateNewFontSize(int FontID,float size,int aa)909 FONTSIZEDEPS *T1int_CreateNewFontSize( int FontID, float size, int aa)
910 {
911 
912   FONTSIZEDEPS *pFontSizeDeps, *pPrev;
913 
914 
915   /* First, get to the last font size in the linked list for this font.
916      The following routine returns the address of the last struct in the
917      linked list of FONTSIZEDEPS or NULL if none exists. */
918   pFontSizeDeps=T1int_GetLastFontSize( FontID);
919   pPrev=pFontSizeDeps;
920 
921 
922   if (pFontSizeDeps==NULL){
923     /* Allocate memory for first FontSizeDeps-structure: */
924     if ((pFontBase->pFontArray[FontID].pFontSizeDeps=(FONTSIZEDEPS *)malloc(sizeof(FONTSIZEDEPS)))==NULL){
925       T1_errno=T1ERR_ALLOC_MEM;
926       return(NULL);
927     }
928     pFontSizeDeps=pFontBase->pFontArray[FontID].pFontSizeDeps;
929   }
930   else{
931     /* A valid address of an existing structure was found */
932     if ((pFontSizeDeps->pNextFontSizeDeps=(FONTSIZEDEPS *)malloc(sizeof(FONTSIZEDEPS)))==NULL){
933       T1_errno=T1ERR_ALLOC_MEM;
934       return(NULL);
935     }
936     pFontSizeDeps=pFontSizeDeps->pNextFontSizeDeps;
937   }
938 
939   /* The pointer to the previous struct */
940   pFontSizeDeps->pPrevFontSizeDeps=pPrev;
941   /* Put the size into this structure */
942   pFontSizeDeps->size=size;
943   /* Set the antialias mark: */
944   pFontSizeDeps->antialias=aa;
945 
946   /* Just the current becomes now the last item in the linked list: */
947   pFontSizeDeps->pNextFontSizeDeps=NULL;
948   /* Setup CharSpaceMatrix for this font: */
949   pFontSizeDeps->pCharSpaceLocal=(struct XYspace *) IDENTITY;
950   /* Apply transformation with font matrix: */
951   pFontSizeDeps->pCharSpaceLocal=(struct XYspace *)
952     Transform(pFontSizeDeps->pCharSpaceLocal,
953 	      pFontBase->pFontArray[FontID].FontMatrix[0],
954 	      pFontBase->pFontArray[FontID].FontMatrix[1],
955 	      pFontBase->pFontArray[FontID].FontMatrix[2],
956 	      pFontBase->pFontArray[FontID].FontMatrix[3]);
957   /* Apply a further transformation (optionally): */
958   pFontSizeDeps->pCharSpaceLocal=(struct XYspace *)
959     Transform(pFontSizeDeps->pCharSpaceLocal,
960 	      pFontBase->pFontArray[FontID].FontTransform[0],
961 	      pFontBase->pFontArray[FontID].FontTransform[1],
962 	      pFontBase->pFontArray[FontID].FontTransform[2],
963 	      pFontBase->pFontArray[FontID].FontTransform[3]);
964   /* Apply desired scaling factor, and make it Permanent */
965   pFontSizeDeps->pCharSpaceLocal=(struct XYspace *) Permanent
966     (Scale(pFontSizeDeps->pCharSpaceLocal, size, size));
967 
968   /* We should now allocate memory for the glyph area of the font
969      cache: */
970   if ((pFontSizeDeps->pFontCache=(GLYPH *)calloc(256,sizeof(GLYPH)))
971       ==NULL)
972     return(NULL);
973 
974   sprintf( err_warn_msg_buf, "New Size %f created for FontID %d (antialias=%d)",
975 	   pFontSizeDeps->size, FontID, pFontSizeDeps->antialias);
976   T1_PrintLog( "CreateNewFontSize()", err_warn_msg_buf, T1LOG_STATISTIC);
977   /* We are done */
978   return(pFontSizeDeps);
979 
980 }
981 
982 
983 
984 
985 /* T1_QueryFontSize( FontID, size, aa): Search if a requested size of font
986    FontID is already existing. If so, it returns a pointer to the
987    respective FontSizeDeps-structure,  otherwise NULL is returned: */
T1int_QueryFontSize(int FontID,float size,int aa)988 FONTSIZEDEPS *T1int_QueryFontSize( int FontID, float size, int aa)
989 {
990 
991   FONTSIZEDEPS *link_ptr;
992 
993 
994   /* There's not yet one size: */
995   if (pFontBase->pFontArray[FontID].pFontSizeDeps == NULL)
996     return(pFontBase->pFontArray[FontID].pFontSizeDeps);
997 
998 
999   /* There's already existing one or more size */
1000   link_ptr=pFontBase->pFontArray[FontID].pFontSizeDeps;
1001 
1002   while (((link_ptr->size != size)||(link_ptr->antialias != aa))
1003 	 &&(link_ptr->pNextFontSizeDeps != NULL))
1004     link_ptr=link_ptr->pNextFontSizeDeps;
1005 
1006   if ((link_ptr->size != size)||(link_ptr->antialias != aa))
1007     return( NULL);     /* requested size/aa-combination  was not found */
1008   else
1009     return(link_ptr); /* return pointer to requested struct */
1010 
1011 }
1012 
1013 /* FONTSIZEDEPS *T1int_GetLastFontSize( FontID): Get the address of the
1014    last struct in the linked list of FontSizeDeps or NULL if there is
1015    no existing size dependent data. */
T1int_GetLastFontSize(int FontID)1016 FONTSIZEDEPS *T1int_GetLastFontSize( int FontID)
1017 {
1018   FONTSIZEDEPS *link_ptr, *result_ptr;
1019 
1020 
1021   /* There's not yet one size: */
1022   if (pFontBase->pFontArray[FontID].pFontSizeDeps == NULL)
1023     return((FONTSIZEDEPS *) (pFontBase->pFontArray[FontID].pFontSizeDeps));
1024 
1025 
1026   /* There's already existing one or more size */
1027   link_ptr=pFontBase->pFontArray[FontID].pFontSizeDeps;
1028 
1029   while (link_ptr != NULL){
1030     result_ptr=link_ptr;
1031     link_ptr=link_ptr->pNextFontSizeDeps;
1032   }
1033 
1034   return((FONTSIZEDEPS *)(result_ptr));
1035 }
1036 
1037 
1038 /* A function for comparing METRICS_ENTRY structs */
cmp_METRICS_ENTRY(const void * entry1,const void * entry2)1039 static int cmp_METRICS_ENTRY( const void *entry1, const void *entry2)
1040 {
1041   if (((METRICS_ENTRY *)entry1)->chars <
1042       ((METRICS_ENTRY *)entry2)->chars)
1043     return(-1);
1044   if (((METRICS_ENTRY *)entry1)->chars >
1045       ((METRICS_ENTRY *)entry2)->chars)
1046     return(1);
1047   return(0); /* This should not happen */
1048 }
1049 
1050 
1051