]> git.imager.perl.org - imager.git/blob - T1/imt1.c
mark mm_log() for the API with the right gcc -Wformat magic
[imager.git] / T1 / imt1.c
1 #include "imext.h"
2 #include "imt1.h"
3 #include <t1lib.h>
4 #include <string.h>
5
6 static int t1_get_flags(char const *flags);
7 static char *t1_from_utf8(char const *in, size_t len, int *outlen);
8 static undef_int i_init_t1_low(int t1log);
9 static void t1_push_error(void);
10 static void i_t1_set_aa(int st);
11
12 static int t1_active_fonts = 0;
13 static int t1_initialized = 0;
14 static int t1_aa = 0;
15
16 struct i_t1_font_tag {
17   int font_id;
18 };
19
20 static i_mutex_t mutex;
21
22 /*
23 =item i_t1_start()
24
25 Initialize the font driver.  This does not actually initialize T1Lib,
26 it just allocates the mutex we use to gate access to it.
27
28 =cut
29 */
30
31 void
32 i_t1_start(void) {
33   mutex = i_mutex_new();
34 }
35
36 /* 
37 =item i_init_t1(t1log)
38
39 Initializes the t1lib font rendering engine.
40
41 =cut
42 */
43
44 undef_int
45 i_init_t1(int t1log) {
46   undef_int result;
47   i_mutex_lock(mutex);
48
49   result = i_init_t1_low(t1log);
50
51   i_mutex_unlock(mutex);
52
53   return result;
54 }
55
56 static undef_int
57 i_init_t1_low(int t1log) {
58   int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE;
59
60   mm_log((1,"init_t1(%d)\n", t1log));
61
62   i_clear_error();
63
64   if (t1_active_fonts) {
65     mm_log((1, "Cannot re-initialize T1 - active fonts\n"));
66     i_push_error(0, "Cannot re-initialize T1 - active fonts");
67     return 1;
68   }
69
70   if (t1_initialized) {
71     T1_CloseLib();
72     t1_initialized = 0;
73   }
74   
75   if (t1log)
76     init_flags |= LOGFILE;
77   if ((T1_InitLib(init_flags) == NULL)){
78     mm_log((1,"Initialization of t1lib failed\n"));
79     i_push_error(0, "T1_InitLib failed");
80     return(1);
81   }
82   T1_SetLogLevel(T1LOG_DEBUG);
83
84   ++t1_initialized;
85
86   return(0);
87 }
88
89 /* 
90 =item i_close_t1()
91
92 Shuts the t1lib font rendering engine down.
93
94   This it seems that this function is never used.
95
96 =cut
97 */
98
99 void
100 i_close_t1(void) {
101   i_mutex_lock(mutex);
102   T1_CloseLib();
103   t1_initialized = 0;
104   i_mutex_unlock(mutex);
105 }
106
107
108 /*
109 =item i_t1_new(pfb, afm)
110
111 Loads the fonts with the given filenames, returns its font id
112
113  pfb -  path to pfb file for font
114  afm -  path to afm file for font
115
116 =cut
117 */
118
119 i_t1_font_t
120 i_t1_new(char *pfb,char *afm) {
121   int font_id;
122   i_t1_font_t font;
123
124   i_mutex_lock(mutex);
125
126   i_clear_error();
127
128   if (!t1_initialized && i_init_t1_low(0)) {
129     i_mutex_unlock(mutex);
130     return NULL;
131   }
132
133   mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL")));
134   font_id = T1_AddFont(pfb);
135   if (font_id<0) {
136     mm_log((1,"i_t1_new: Failed to load pfb file '%s' - return code %d.\n",pfb,font_id));
137     t1_push_error();
138     i_mutex_unlock(mutex);
139     return NULL;
140   }
141   
142   if (afm != NULL) {
143     mm_log((1,"i_t1_new: requesting afm file '%s'.\n",afm));
144     if (T1_SetAfmFileName(font_id,afm)<0) mm_log((1,"i_t1_new: afm loading of '%s' failed.\n",afm));
145   }
146
147   if (T1_LoadFont(font_id)) {
148     mm_log((1, "i_t1_new() -> -1 - T1_LoadFont failed (%d)\n", T1_errno));
149     t1_push_error();
150     i_push_error(0, "loading font");
151     T1_DeleteFont(font_id);
152     i_mutex_unlock(mutex);
153     return NULL;
154   }
155
156   ++t1_active_fonts;
157
158   i_mutex_unlock(mutex);
159
160   font = mymalloc(sizeof(*font));
161   font->font_id = font_id;
162
163   mm_log((1, "i_t1_new() -> %p (%d)\n", font, font_id));
164
165   return font;
166 }
167
168 /*
169 =item i_t1_destroy(font)
170
171 Frees resources for a t1 font with given font id.
172
173    font - font to free
174
175 =cut
176 */
177
178 int
179 i_t1_destroy(i_t1_font_t font) {
180   int result;
181
182   i_mutex_lock(mutex);
183
184   mm_log((1,"i_t1_destroy(font %p (%d))\n", font, font->font_id));
185
186   --t1_active_fonts;
187
188   result = T1_DeleteFont(font->font_id);
189   myfree(font);
190
191   i_mutex_unlock(mutex);
192
193   return result;
194 }
195
196
197 /*
198 =item i_t1_set_aa(st)
199
200 Sets the antialiasing level of the t1 library.
201
202    st - 0 =  NONE, 1 = LOW, 2 =  HIGH.
203
204 Must be called with the mutex locked.
205
206 =cut
207 */
208
209 static void
210 i_t1_set_aa(int st) {
211   int i;
212   unsigned long cst[17];
213
214   if (t1_aa == st)
215     return;
216
217   switch(st) {
218   case 0:
219     T1_AASetBitsPerPixel( 8 );
220     T1_AASetLevel( T1_AA_NONE );
221     T1_AANSetGrayValues( 0, 255 );
222     mm_log((1,"setting T1 antialias to none\n"));
223     break;
224   case 1:
225     T1_AASetBitsPerPixel( 8 );
226     T1_AASetLevel( T1_AA_LOW );
227     T1_AASetGrayValues( 0,65,127,191,255 );
228     mm_log((1,"setting T1 antialias to low\n"));
229     break;
230   case 2:
231     T1_AASetBitsPerPixel(8);
232     T1_AASetLevel(T1_AA_HIGH);
233     for(i=0;i<17;i++) cst[i]=(i*255)/16;
234     T1_AAHSetGrayValues( cst );
235     mm_log((1,"setting T1 antialias to high\n"));
236   }
237   
238   t1_aa = st;
239 }
240
241
242 /* 
243 =item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align,aa)
244
245 Interface to text rendering into a single channel in an image
246
247    im        pointer to image structure
248    xb        x coordinate of start of string
249    yb        y coordinate of start of string ( see align )
250    channel - destination channel
251    fontnum - t1 library font id
252    points  - number of points in fontheight
253    str     - string to render
254    len     - string length
255    align   - (0 - top of font glyph | 1 - baseline )
256    aa      - anti-aliasing level
257
258 =cut
259 */
260
261 undef_int
262 i_t1_cp(i_t1_font_t font, i_img *im,i_img_dim xb,i_img_dim yb,int channel,double points,char* str,size_t len,int align, int utf8, char const *flags, int aa) {
263   GLYPH *glyph;
264   int xsize,ysize,x,y;
265   i_color val;
266   int mod_flags = t1_get_flags(flags);
267   int fontnum = font->font_id;
268
269   unsigned int ch_mask_store;
270   
271   i_clear_error();
272
273   mm_log((1, "i_t1_cp(font %p (%d), im %p, (xb,yb)=" i_DFp ", channel %d, points %g, str %p, len %u, align %d, utf8 %d, flags '%s', aa %d)\n",
274           font, fontnum, im, i_DFcp(xb, yb), channel, points, str, (unsigned)len, align, utf8, flags, aa));
275
276   if (im == NULL) {
277     mm_log((1,"i_t1_cp: Null image in input\n"));
278     i_push_error(0, "null image");
279     return(0);
280   }
281
282   i_mutex_lock(mutex);
283
284   i_t1_set_aa(aa);
285
286   if (utf8) {
287     int worklen;
288     char *work = t1_from_utf8(str, len, &worklen);
289     glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
290     myfree(work);
291   }
292   else {
293     glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
294   }
295   if (glyph == NULL) {
296     t1_push_error();
297     i_push_error(0, "i_t1_cp: T1_AASetString failed");
298     i_mutex_unlock(mutex);
299     return 0;
300   }
301
302   mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
303   mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
304   mm_log((1," advanceX: %d  advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
305   mm_log((1,"bpp: %lu\n", (unsigned long)glyph->bpp));
306   
307   xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
308   ysize=glyph->metrics.ascent-glyph->metrics.descent;
309   
310   mm_log((1,"width: %d height: %d\n",xsize,ysize));
311
312   ch_mask_store=im->ch_mask;
313   im->ch_mask=1<<channel;
314
315   if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
316   
317   for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
318     val.channel[channel]=glyph->bits[y*xsize+x];
319     i_ppix(im,x+xb,y+yb,&val);
320   }
321   
322   im->ch_mask=ch_mask_store;
323
324   i_mutex_unlock(mutex);
325
326   return 1;
327 }
328
329 static void
330 t1_fix_bbox(BBox *bbox, const char *str, size_t len, int advance, 
331             int space_position) {
332   /* never called with len == 0 */
333   if (str[0] == space_position && bbox->llx > 0)
334     bbox->llx = 0;
335   if (str[len-1] == space_position && bbox->urx < advance)
336     bbox->urx = advance;
337   if (bbox->lly > bbox->ury)
338     bbox->lly = bbox->ury = 0; 
339 }
340
341 /*
342 =item i_t1_bbox(handle, fontnum, points, str, len, cords)
343
344 function to get a strings bounding box given the font id and sizes
345
346    handle  - pointer to font handle   
347    fontnum - t1 library font id
348    points  - number of points in fontheight
349    str     - string to measure
350    len     - string length
351    cords   - the bounding box (modified in place)
352
353 =cut
354 */
355
356 int
357 i_t1_bbox(i_t1_font_t font, double points,const char *str,size_t len, i_img_dim cords[6], int utf8,char const *flags) {
358   BBox bbox;
359   BBox gbbox;
360   int mod_flags = t1_get_flags(flags);
361   i_img_dim advance;
362   int fontnum = font->font_id;
363   int space_position;
364
365   i_mutex_lock(mutex);
366
367   space_position = T1_GetEncodingIndex(fontnum, "space");
368   
369   mm_log((1,"i_t1_bbox(font %p (%d),points %.2f,str '%.*s', len %u)\n",
370           font, fontnum,points,(int)len,str,(unsigned)len));
371   T1_LoadFont(fontnum);  /* FIXME: Here a return code is ignored - haw haw haw */ 
372
373   if (len == 0) {
374     /* len == 0 has special meaning to T1lib, but it means there's
375        nothing to draw, so return that */
376     bbox.llx = bbox.lly = bbox.urx = bbox.ury = 0;
377     advance = 0;
378   }
379   else {
380     if (utf8) {
381       int worklen;
382       char *work = t1_from_utf8(str, len, &worklen);
383       advance = T1_GetStringWidth(fontnum, work, worklen, 0, mod_flags);
384       bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
385       t1_fix_bbox(&bbox, work, worklen, advance, space_position);
386       myfree(work);
387     }
388     else {
389       advance = T1_GetStringWidth(fontnum, (char *)str, len, 0, mod_flags);
390       bbox = T1_GetStringBBox(fontnum,(char *)str,len,0,mod_flags);
391       t1_fix_bbox(&bbox, str, len, advance, space_position);
392     }
393   }
394   gbbox = T1_GetFontBBox(fontnum);
395   
396   mm_log((1,"bbox: (%d, %d, %d, %d, %d, %d)\n",
397           (int)(bbox.llx*points/1000),
398           (int)(gbbox.lly*points/1000),
399           (int)(bbox.urx*points/1000),
400           (int)(gbbox.ury*points/1000),
401           (int)(bbox.lly*points/1000),
402           (int)(bbox.ury*points/1000) ));
403
404
405   cords[BBOX_NEG_WIDTH]=((double)bbox.llx*points)/1000;
406   cords[BBOX_POS_WIDTH]=((double)bbox.urx*points)/1000;
407
408   cords[BBOX_GLOBAL_DESCENT]=((double)gbbox.lly*points)/1000;
409   cords[BBOX_GLOBAL_ASCENT]=((double)gbbox.ury*points)/1000;
410
411   cords[BBOX_DESCENT]=((double)bbox.lly*points)/1000;
412   cords[BBOX_ASCENT]=((double)bbox.ury*points)/1000;
413
414   cords[BBOX_ADVANCE_WIDTH] = ((double)advance * points)/1000;
415   cords[BBOX_RIGHT_BEARING] = 
416     cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH];
417
418   i_mutex_unlock(mutex);
419
420   return BBOX_RIGHT_BEARING+1;
421 }
422
423
424 /*
425 =item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align, aa)
426
427 Interface to text rendering in a single color onto an image
428
429    im      - pointer to image structure
430    xb      - x coordinate of start of string
431    yb      - y coordinate of start of string ( see align )
432    cl      - color to draw the text in
433    fontnum - t1 library font id
434    points  - number of points in fontheight
435    str     - char pointer to string to render
436    len     - string length
437    align   - (0 - top of font glyph | 1 - baseline )
438    aa      - anti-aliasing level
439
440 =cut
441 */
442
443 undef_int
444 i_t1_text(i_t1_font_t font, i_img *im, i_img_dim xb, i_img_dim yb,const i_color *cl, double points,const char* str,size_t len,int align, int utf8, char const *flags, int aa) {
445   GLYPH *glyph;
446   int xsize,ysize,y;
447   int mod_flags = t1_get_flags(flags);
448   i_render *r;
449   int fontnum = font->font_id;
450
451   mm_log((1, "i_t1_text(font %p (%d), im %p, (xb,yb)=" i_DFp ", cl (%d,%d,%d,%d), points %g, str %p, len %u, align %d, utf8 %d, flags '%s', aa %d)\n",
452           font, fontnum, im, i_DFcp(xb, yb), cl->rgba.r, cl->rgba.g, cl->rgba.b, cl->rgba.a, points, str, (unsigned)len, align, utf8, flags, aa));
453
454   i_clear_error();
455
456   if (im == NULL) {
457     i_push_error(0, "null image");
458     mm_log((1,"i_t1_text: Null image in input\n"));
459     return(0);
460   }
461
462   i_mutex_lock(mutex);
463
464   i_t1_set_aa(aa);
465
466   if (utf8) {
467     int worklen;
468     char *work = t1_from_utf8(str, len, &worklen);
469     glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
470     myfree(work);
471   }
472   else {
473     /* T1_AASetString() accepts a char * not a const char */
474     glyph=T1_AASetString( fontnum, (char *)str, len, 0, mod_flags, points, NULL);
475   }
476   if (glyph == NULL) {
477     mm_log((1, "T1_AASetString failed\n"));
478     t1_push_error();
479     i_push_error(0, "i_t1_text(): T1_AASetString failed");
480     i_mutex_unlock(mutex);
481     return 0;
482   }
483
484   mm_log((1,"metrics:  ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
485   mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
486   mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
487   mm_log((1,"bpp: %lu\n",(unsigned long)glyph->bpp));
488   
489   xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
490   ysize=glyph->metrics.ascent-glyph->metrics.descent;
491   
492   mm_log((1,"width: %d height: %d\n",xsize,ysize));
493
494   if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
495
496   r = i_render_new(im, xsize);
497   for(y=0;y<ysize;y++) {
498     i_render_color(r, xb, yb+y, xsize, (unsigned char *)glyph->bits+y*xsize, cl);
499   }
500   i_render_delete(r);
501
502   i_mutex_unlock(mutex);
503     
504   return 1;
505 }
506
507 /*
508 =item t1_get_flags(flags)
509
510 Processes the characters in I<flags> to create a mod_flags value used
511 by some T1Lib functions.
512
513 =cut
514  */
515 static int
516 t1_get_flags(char const *flags) {
517   int mod_flags = T1_KERNING;
518
519   while (*flags) {
520     switch (*flags++) {
521     case 'u': case 'U': mod_flags |= T1_UNDERLINE; break;
522     case 'o': case 'O': mod_flags |= T1_OVERLINE; break;
523     case 's': case 'S': mod_flags |= T1_OVERSTRIKE; break;
524       /* ignore anything we don't recognize */
525     }
526   }
527
528   return mod_flags;
529 }
530
531 /*
532 =item t1_from_utf8(char const *in, size_t len, int *outlen)
533
534 Produces an unencoded version of I<in> by dropping any Unicode
535 character over 255.
536
537 Returns a newly allocated buffer which should be freed with myfree().
538 Sets *outlen to the number of bytes used in the output string.
539
540 =cut
541 */
542
543 static char *
544 t1_from_utf8(char const *in, size_t len, int *outlen) {
545   /* at this point len is from a STRLEN which should be size_t and can't
546      be too big for mymalloc */
547   char *out = mymalloc(len+1); /* rechecked 29jul11 tonyc */
548   char *p = out;
549   unsigned long c;
550
551   while (len) {
552     c = i_utf8_advance(&in, &len);
553     if (c == ~0UL) {
554       myfree(out);
555       i_push_error(0, "invalid UTF8 character");
556       return 0;
557     }
558     /* yeah, just drop them */
559     if (c < 0x100) {
560       *p++ = (char)c;
561     }
562   }
563   *p = '\0';
564   *outlen = p - out;
565
566   return out;
567 }
568
569 /*
570 =item i_t1_has_chars(font_num, text, len, utf8, out)
571
572 Check if the given characters are defined by the font.  Note that len
573 is the number of bytes, not the number of characters (when utf8 is
574 non-zero).
575
576 out[char index] will be true if the character exists.
577
578 Accepts UTF-8, but since T1 can only have 256 characters, any chars
579 with values over 255 will simply be returned as false.
580
581 Returns the number of characters that were checked.
582
583 =cut
584 */
585
586 int
587 i_t1_has_chars(i_t1_font_t font, const char *text, size_t len, int utf8,
588                char *out) {
589   int count = 0;
590   int font_num = font->font_id;
591   
592   i_mutex_lock(mutex);
593
594   mm_log((1, "i_t1_has_chars(font_num %d, text %p, len %u, utf8 %d)\n", 
595           font_num, text, (unsigned)len, utf8));
596
597   i_clear_error();
598   if (T1_LoadFont(font_num)) {
599     t1_push_error();
600     i_mutex_unlock(mutex);
601     return 0;
602   }
603
604   while (len) {
605     unsigned long c;
606     if (utf8) {
607       c = i_utf8_advance(&text, &len);
608       if (c == ~0UL) {
609         i_push_error(0, "invalid UTF8 character");
610         i_mutex_unlock(mutex);
611         return 0;
612       }
613     }
614     else {
615       c = (unsigned char)*text++;
616       --len;
617     }
618     
619     if (c >= 0x100) {
620       /* limit of 256 characters for T1 */
621       *out++ = 0;
622     }
623     else {
624       char const * name = T1_GetCharName(font_num, (unsigned char)c);
625
626       if (name) {
627         *out++ = strcmp(name, ".notdef") != 0;
628       }
629       else {
630         mm_log((2, "  No name found for character %lx\n", c));
631         *out++ = 0;
632       }
633     }
634     ++count;
635   }
636
637   i_mutex_unlock(mutex);
638
639   return count;
640 }
641
642 /*
643 =item i_t1_face_name(font, name_buf, name_buf_size)
644
645 Copies the face name of the given C<font_num> to C<name_buf>.  Returns
646 the number of characters required to store the name (which can be
647 larger than C<name_buf_size>, including the space required to store
648 the terminating NUL).
649
650 If name_buf is too small (as specified by name_buf_size) then the name
651 will be truncated.  name_buf will always be NUL termintaed.
652
653 =cut
654 */
655
656 int
657 i_t1_face_name(i_t1_font_t font, char *name_buf, size_t name_buf_size) {
658   char *name;
659   int font_num = font->font_id;
660
661   i_mutex_lock(mutex);
662
663   T1_errno = 0;
664   if (T1_LoadFont(font_num)) {
665     t1_push_error();
666     i_mutex_unlock(mutex);
667     return 0;
668   }
669   name = T1_GetFontName(font_num);
670
671   if (name) {
672     size_t len = strlen(name);
673     strncpy(name_buf, name, name_buf_size);
674     name_buf[name_buf_size-1] = '\0';
675     i_mutex_unlock(mutex);
676     return len + 1;
677   }
678   else {
679     t1_push_error();
680     i_mutex_unlock(mutex);
681     return 0;
682   }
683 }
684
685 int
686 i_t1_glyph_name(i_t1_font_t font, unsigned long ch, char *name_buf, 
687                  size_t name_buf_size) {
688   char *name;
689   int font_num = font->font_id;
690
691   i_mutex_lock(mutex);
692   i_clear_error();
693   if (ch > 0xFF) {
694     i_mutex_unlock(mutex);
695     return 0;
696   }
697   if (T1_LoadFont(font_num)) {
698     t1_push_error();
699     i_mutex_unlock(mutex);
700     return 0;
701   }
702   name = T1_GetCharName(font_num, (unsigned char)ch);
703   if (name) {
704     if (strcmp(name, ".notdef")) {
705       size_t len = strlen(name);
706       strncpy(name_buf, name, name_buf_size);
707       name_buf[name_buf_size-1] = '\0';
708       i_mutex_unlock(mutex);
709       return len + 1;
710     }
711     else {
712       i_mutex_unlock(mutex);
713       return 0;
714     }
715   }
716   else {
717     t1_push_error();
718     i_mutex_unlock(mutex);
719     return 0;
720   }
721 }
722
723 static void
724 t1_push_error(void) {
725 #if T1LIB_VERSION > 5 || T1LIB_VERSION == 5 && T1LIB_VERSION >= 1
726   /* I don't know when T1_StrError() was introduced, be conservative */
727   i_push_error(T1_errno, T1_StrError(T1_errno));
728 #else
729   switch (T1_errno) {
730   case 0: 
731     i_push_error(0, "No error"); 
732     break;
733
734 #ifdef T1ERR_SCAN_FONT_FORMAT
735   case T1ERR_SCAN_FONT_FORMAT:
736     i_push_error(T1ERR_SCAN_FONT_FORMAT, "Attempt to Load Multiple Master Font"); 
737     break;
738 #endif
739
740 #ifdef T1ERR_SCAN_FILE_OPEN_ERR
741   case T1ERR_SCAN_FILE_OPEN_ERR:
742     i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "Type 1 Font File Open Error"); 
743     break;
744 #endif
745
746 #ifdef T1ERR_SCAN_OUT_OF_MEMORY
747   case T1ERR_SCAN_OUT_OF_MEMORY:
748     i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "Virtual Memory Exceeded"); 
749     break;
750 #endif
751
752 #ifdef T1ERR_SCAN_ERROR
753   case T1ERR_SCAN_ERROR:
754     i_push_error(T1ERR_SCAN_ERROR, "Syntactical Error Scanning Font File"); 
755     break;
756 #endif
757
758 #ifdef T1ERR_SCAN_FILE_EOF
759   case T1ERR_SCAN_FILE_EOF:
760     i_push_error(T1ERR_SCAN_FILE_EOF, "Premature End of Font File Encountered"); 
761     break;
762 #endif
763
764 #ifdef T1ERR_PATH_ERROR
765   case T1ERR_PATH_ERROR:
766     i_push_error(T1ERR_PATH_ERROR, "Path Construction Error"); 
767     break;
768 #endif
769
770 #ifdef T1ERR_PARSE_ERROR
771   case T1ERR_PARSE_ERROR:
772     i_push_error(T1ERR_PARSE_ERROR, "Font is Corrupt"); 
773     break;
774 #endif
775
776 #ifdef T1ERR_TYPE1_ABORT
777   case T1ERR_TYPE1_ABORT:
778     i_push_error(T1ERR_TYPE1_ABORT, "Rasterization Aborted"); 
779     break;
780 #endif
781
782 #ifdef T1ERR_INVALID_FONTID
783   case T1ERR_INVALID_FONTID:
784     i_push_error(T1ERR_INVALID_FONTID, "Font ID Invalid in this Context"); 
785     break;
786 #endif
787
788 #ifdef T1ERR_INVALID_PARAMETER
789   case T1ERR_INVALID_PARAMETER:
790     i_push_error(T1ERR_INVALID_PARAMETER, "Invalid Argument in Function Call"); 
791     break;
792 #endif
793
794 #ifdef T1ERR_OP_NOT_PERMITTED
795   case T1ERR_OP_NOT_PERMITTED:
796     i_push_error(T1ERR_OP_NOT_PERMITTED, "Operation not Permitted"); 
797     break;
798 #endif
799
800 #ifdef T1ERR_ALLOC_MEM
801   case T1ERR_ALLOC_MEM:
802     i_push_error(T1ERR_ALLOC_MEM, "Memory Allocation Error"); 
803     break;
804 #endif
805
806 #ifdef T1ERR_FILE_OPEN_ERR
807   case T1ERR_FILE_OPEN_ERR:
808     i_push_error(T1ERR_FILE_OPEN_ERR, "Error Opening File"); 
809     break;
810 #endif
811
812 #ifdef T1ERR_UNSPECIFIED
813   case T1ERR_UNSPECIFIED:
814     i_push_error(T1ERR_UNSPECIFIED, "Unspecified T1Lib Error"); 
815     break;
816 #endif
817
818 #ifdef T1ERR_NO_AFM_DATA
819   case T1ERR_NO_AFM_DATA:
820     i_push_error(T1ERR_NO_AFM_DATA, "Missing AFM Data"); 
821     break;
822 #endif
823
824 #ifdef T1ERR_X11
825   case T1ERR_X11:
826     i_push_error(T1ERR_X11, "X11 Interface Error"); 
827     break;
828 #endif
829
830 #ifdef T1ERR_COMPOSITE_CHAR
831   case T1ERR_COMPOSITE_CHAR:
832     i_push_error(T1ERR_COMPOSITE_CHAR, "Missing Component of Composite Character"); 
833     break;
834 #endif
835
836 #ifdef T1ERR_SCAN_ENCODING
837   case T1ERR_SCAN_ENCODING:
838     i_push_error(T1ERR_SCAN_ENCODING, "Error Scanning Encoding File"); 
839     break;
840 #endif
841
842   default:
843     i_push_errorf(T1_errno, "unknown error %d", (int)T1_errno);
844   }
845 #endif
846 }
847