d0686bbdd47c896e0d4174e346a1c9fadd431bd3
[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: %d\n",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 %d)\n",font, fontnum,points,len,str,len));
370   T1_LoadFont(fontnum);  /* FIXME: Here a return code is ignored - haw haw haw */ 
371
372   if (len == 0) {
373     /* len == 0 has special meaning to T1lib, but it means there's
374        nothing to draw, so return that */
375     bbox.llx = bbox.lly = bbox.urx = bbox.ury = 0;
376     advance = 0;
377   }
378   else {
379     if (utf8) {
380       int worklen;
381       char *work = t1_from_utf8(str, len, &worklen);
382       advance = T1_GetStringWidth(fontnum, work, worklen, 0, mod_flags);
383       bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
384       t1_fix_bbox(&bbox, work, worklen, advance, space_position);
385       myfree(work);
386     }
387     else {
388       advance = T1_GetStringWidth(fontnum, (char *)str, len, 0, mod_flags);
389       bbox = T1_GetStringBBox(fontnum,(char *)str,len,0,mod_flags);
390       t1_fix_bbox(&bbox, str, len, advance, space_position);
391     }
392   }
393   gbbox = T1_GetFontBBox(fontnum);
394   
395   mm_log((1,"bbox: (%d,%d,%d,%d)\n",
396           (int)(bbox.llx*points/1000),
397           (int)(gbbox.lly*points/1000),
398           (int)(bbox.urx*points/1000),
399           (int)(gbbox.ury*points/1000),
400           (int)(bbox.lly*points/1000),
401           (int)(bbox.ury*points/1000) ));
402
403
404   cords[BBOX_NEG_WIDTH]=((double)bbox.llx*points)/1000;
405   cords[BBOX_POS_WIDTH]=((double)bbox.urx*points)/1000;
406
407   cords[BBOX_GLOBAL_DESCENT]=((double)gbbox.lly*points)/1000;
408   cords[BBOX_GLOBAL_ASCENT]=((double)gbbox.ury*points)/1000;
409
410   cords[BBOX_DESCENT]=((double)bbox.lly*points)/1000;
411   cords[BBOX_ASCENT]=((double)bbox.ury*points)/1000;
412
413   cords[BBOX_ADVANCE_WIDTH] = ((double)advance * points)/1000;
414   cords[BBOX_RIGHT_BEARING] = 
415     cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH];
416
417   i_mutex_unlock(mutex);
418
419   return BBOX_RIGHT_BEARING+1;
420 }
421
422
423 /*
424 =item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align, aa)
425
426 Interface to text rendering in a single color onto an image
427
428    im      - pointer to image structure
429    xb      - x coordinate of start of string
430    yb      - y coordinate of start of string ( see align )
431    cl      - color to draw the text in
432    fontnum - t1 library font id
433    points  - number of points in fontheight
434    str     - char pointer to string to render
435    len     - string length
436    align   - (0 - top of font glyph | 1 - baseline )
437    aa      - anti-aliasing level
438
439 =cut
440 */
441
442 undef_int
443 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) {
444   GLYPH *glyph;
445   int xsize,ysize,y;
446   int mod_flags = t1_get_flags(flags);
447   i_render *r;
448   int fontnum = font->font_id;
449
450   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",
451           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));
452
453   i_clear_error();
454
455   if (im == NULL) {
456     i_push_error(0, "null image");
457     mm_log((1,"i_t1_text: Null image in input\n"));
458     return(0);
459   }
460
461   i_mutex_lock(mutex);
462
463   i_t1_set_aa(aa);
464
465   if (utf8) {
466     int worklen;
467     char *work = t1_from_utf8(str, len, &worklen);
468     glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
469     myfree(work);
470   }
471   else {
472     /* T1_AASetString() accepts a char * not a const char */
473     glyph=T1_AASetString( fontnum, (char *)str, len, 0, mod_flags, points, NULL);
474   }
475   if (glyph == NULL) {
476     mm_log((1, "T1_AASetString failed\n"));
477     t1_push_error();
478     i_push_error(0, "i_t1_text(): T1_AASetString failed");
479     i_mutex_unlock(mutex);
480     return 0;
481   }
482
483   mm_log((1,"metrics:  ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
484   mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
485   mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
486   mm_log((1,"bpp: %d\n",glyph->bpp));
487   
488   xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
489   ysize=glyph->metrics.ascent-glyph->metrics.descent;
490   
491   mm_log((1,"width: %d height: %d\n",xsize,ysize));
492
493   if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
494
495   r = i_render_new(im, xsize);
496   for(y=0;y<ysize;y++) {
497     i_render_color(r, xb, yb+y, xsize, (unsigned char *)glyph->bits+y*xsize, cl);
498   }
499   i_render_delete(r);
500
501   i_mutex_unlock(mutex);
502     
503   return 1;
504 }
505
506 /*
507 =item t1_get_flags(flags)
508
509 Processes the characters in I<flags> to create a mod_flags value used
510 by some T1Lib functions.
511
512 =cut
513  */
514 static int
515 t1_get_flags(char const *flags) {
516   int mod_flags = T1_KERNING;
517
518   while (*flags) {
519     switch (*flags++) {
520     case 'u': case 'U': mod_flags |= T1_UNDERLINE; break;
521     case 'o': case 'O': mod_flags |= T1_OVERLINE; break;
522     case 's': case 'S': mod_flags |= T1_OVERSTRIKE; break;
523       /* ignore anything we don't recognize */
524     }
525   }
526
527   return mod_flags;
528 }
529
530 /*
531 =item t1_from_utf8(char const *in, size_t len, int *outlen)
532
533 Produces an unencoded version of I<in> by dropping any Unicode
534 character over 255.
535
536 Returns a newly allocated buffer which should be freed with myfree().
537 Sets *outlen to the number of bytes used in the output string.
538
539 =cut
540 */
541
542 static char *
543 t1_from_utf8(char const *in, size_t len, int *outlen) {
544   /* at this point len is from a STRLEN which should be size_t and can't
545      be too big for mymalloc */
546   char *out = mymalloc(len+1); /* rechecked 29jul11 tonyc */
547   char *p = out;
548   unsigned long c;
549
550   while (len) {
551     c = i_utf8_advance(&in, &len);
552     if (c == ~0UL) {
553       myfree(out);
554       i_push_error(0, "invalid UTF8 character");
555       return 0;
556     }
557     /* yeah, just drop them */
558     if (c < 0x100) {
559       *p++ = (char)c;
560     }
561   }
562   *p = '\0';
563   *outlen = p - out;
564
565   return out;
566 }
567
568 /*
569 =item i_t1_has_chars(font_num, text, len, utf8, out)
570
571 Check if the given characters are defined by the font.  Note that len
572 is the number of bytes, not the number of characters (when utf8 is
573 non-zero).
574
575 out[char index] will be true if the character exists.
576
577 Accepts UTF-8, but since T1 can only have 256 characters, any chars
578 with values over 255 will simply be returned as false.
579
580 Returns the number of characters that were checked.
581
582 =cut
583 */
584
585 int
586 i_t1_has_chars(i_t1_font_t font, const char *text, size_t len, int utf8,
587                char *out) {
588   int count = 0;
589   int font_num = font->font_id;
590   
591   i_mutex_lock(mutex);
592
593   mm_log((1, "i_t1_has_chars(font_num %d, text %p, len %d, utf8 %d)\n", 
594           font_num, text, len, utf8));
595
596   i_clear_error();
597   if (T1_LoadFont(font_num)) {
598     t1_push_error();
599     i_mutex_unlock(mutex);
600     return 0;
601   }
602
603   while (len) {
604     unsigned long c;
605     if (utf8) {
606       c = i_utf8_advance(&text, &len);
607       if (c == ~0UL) {
608         i_push_error(0, "invalid UTF8 character");
609         i_mutex_unlock(mutex);
610         return 0;
611       }
612     }
613     else {
614       c = (unsigned char)*text++;
615       --len;
616     }
617     
618     if (c >= 0x100) {
619       /* limit of 256 characters for T1 */
620       *out++ = 0;
621     }
622     else {
623       char const * name = T1_GetCharName(font_num, (unsigned char)c);
624
625       if (name) {
626         *out++ = strcmp(name, ".notdef") != 0;
627       }
628       else {
629         mm_log((2, "  No name found for character %lx\n", c));
630         *out++ = 0;
631       }
632     }
633     ++count;
634   }
635
636   i_mutex_unlock(mutex);
637
638   return count;
639 }
640
641 /*
642 =item i_t1_face_name(font, name_buf, name_buf_size)
643
644 Copies the face name of the given C<font_num> to C<name_buf>.  Returns
645 the number of characters required to store the name (which can be
646 larger than C<name_buf_size>, including the space required to store
647 the terminating NUL).
648
649 If name_buf is too small (as specified by name_buf_size) then the name
650 will be truncated.  name_buf will always be NUL termintaed.
651
652 =cut
653 */
654
655 int
656 i_t1_face_name(i_t1_font_t font, char *name_buf, size_t name_buf_size) {
657   char *name;
658   int font_num = font->font_id;
659
660   i_mutex_lock(mutex);
661
662   T1_errno = 0;
663   if (T1_LoadFont(font_num)) {
664     t1_push_error();
665     i_mutex_unlock(mutex);
666     return 0;
667   }
668   name = T1_GetFontName(font_num);
669
670   if (name) {
671     size_t len = strlen(name);
672     strncpy(name_buf, name, name_buf_size);
673     name_buf[name_buf_size-1] = '\0';
674     i_mutex_unlock(mutex);
675     return len + 1;
676   }
677   else {
678     t1_push_error();
679     i_mutex_unlock(mutex);
680     return 0;
681   }
682 }
683
684 int
685 i_t1_glyph_name(i_t1_font_t font, unsigned long ch, char *name_buf, 
686                  size_t name_buf_size) {
687   char *name;
688   int font_num = font->font_id;
689
690   i_mutex_lock(mutex);
691   i_clear_error();
692   if (ch > 0xFF) {
693     i_mutex_unlock(mutex);
694     return 0;
695   }
696   if (T1_LoadFont(font_num)) {
697     t1_push_error();
698     i_mutex_unlock(mutex);
699     return 0;
700   }
701   name = T1_GetCharName(font_num, (unsigned char)ch);
702   if (name) {
703     if (strcmp(name, ".notdef")) {
704       size_t len = strlen(name);
705       strncpy(name_buf, name, name_buf_size);
706       name_buf[name_buf_size-1] = '\0';
707       i_mutex_unlock(mutex);
708       return len + 1;
709     }
710     else {
711       i_mutex_unlock(mutex);
712       return 0;
713     }
714   }
715   else {
716     t1_push_error();
717     i_mutex_unlock(mutex);
718     return 0;
719   }
720 }
721
722 static void
723 t1_push_error(void) {
724 #if T1LIB_VERSION > 5 || T1LIB_VERSION == 5 && T1LIB_VERSION >= 1
725   /* I don't know when T1_StrError() was introduced, be conservative */
726   i_push_error(T1_errno, T1_StrError(T1_errno));
727 #else
728   switch (T1_errno) {
729   case 0: 
730     i_push_error(0, "No error"); 
731     break;
732
733 #ifdef T1ERR_SCAN_FONT_FORMAT
734   case T1ERR_SCAN_FONT_FORMAT:
735     i_push_error(T1ERR_SCAN_FONT_FORMAT, "Attempt to Load Multiple Master Font"); 
736     break;
737 #endif
738
739 #ifdef T1ERR_SCAN_FILE_OPEN_ERR
740   case T1ERR_SCAN_FILE_OPEN_ERR:
741     i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "Type 1 Font File Open Error"); 
742     break;
743 #endif
744
745 #ifdef T1ERR_SCAN_OUT_OF_MEMORY
746   case T1ERR_SCAN_OUT_OF_MEMORY:
747     i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "Virtual Memory Exceeded"); 
748     break;
749 #endif
750
751 #ifdef T1ERR_SCAN_ERROR
752   case T1ERR_SCAN_ERROR:
753     i_push_error(T1ERR_SCAN_ERROR, "Syntactical Error Scanning Font File"); 
754     break;
755 #endif
756
757 #ifdef T1ERR_SCAN_FILE_EOF
758   case T1ERR_SCAN_FILE_EOF:
759     i_push_error(T1ERR_SCAN_FILE_EOF, "Premature End of Font File Encountered"); 
760     break;
761 #endif
762
763 #ifdef T1ERR_PATH_ERROR
764   case T1ERR_PATH_ERROR:
765     i_push_error(T1ERR_PATH_ERROR, "Path Construction Error"); 
766     break;
767 #endif
768
769 #ifdef T1ERR_PARSE_ERROR
770   case T1ERR_PARSE_ERROR:
771     i_push_error(T1ERR_PARSE_ERROR, "Font is Corrupt"); 
772     break;
773 #endif
774
775 #ifdef T1ERR_TYPE1_ABORT
776   case T1ERR_TYPE1_ABORT:
777     i_push_error(T1ERR_TYPE1_ABORT, "Rasterization Aborted"); 
778     break;
779 #endif
780
781 #ifdef T1ERR_INVALID_FONTID
782   case T1ERR_INVALID_FONTID:
783     i_push_error(T1ERR_INVALID_FONTID, "Font ID Invalid in this Context"); 
784     break;
785 #endif
786
787 #ifdef T1ERR_INVALID_PARAMETER
788   case T1ERR_INVALID_PARAMETER:
789     i_push_error(T1ERR_INVALID_PARAMETER, "Invalid Argument in Function Call"); 
790     break;
791 #endif
792
793 #ifdef T1ERR_OP_NOT_PERMITTED
794   case T1ERR_OP_NOT_PERMITTED:
795     i_push_error(T1ERR_OP_NOT_PERMITTED, "Operation not Permitted"); 
796     break;
797 #endif
798
799 #ifdef T1ERR_ALLOC_MEM
800   case T1ERR_ALLOC_MEM:
801     i_push_error(T1ERR_ALLOC_MEM, "Memory Allocation Error"); 
802     break;
803 #endif
804
805 #ifdef T1ERR_FILE_OPEN_ERR
806   case T1ERR_FILE_OPEN_ERR:
807     i_push_error(T1ERR_FILE_OPEN_ERR, "Error Opening File"); 
808     break;
809 #endif
810
811 #ifdef T1ERR_UNSPECIFIED
812   case T1ERR_UNSPECIFIED:
813     i_push_error(T1ERR_UNSPECIFIED, "Unspecified T1Lib Error"); 
814     break;
815 #endif
816
817 #ifdef T1ERR_NO_AFM_DATA
818   case T1ERR_NO_AFM_DATA:
819     i_push_error(T1ERR_NO_AFM_DATA, "Missing AFM Data"); 
820     break;
821 #endif
822
823 #ifdef T1ERR_X11
824   case T1ERR_X11:
825     i_push_error(T1ERR_X11, "X11 Interface Error"); 
826     break;
827 #endif
828
829 #ifdef T1ERR_COMPOSITE_CHAR
830   case T1ERR_COMPOSITE_CHAR:
831     i_push_error(T1ERR_COMPOSITE_CHAR, "Missing Component of Composite Character"); 
832     break;
833 #endif
834
835 #ifdef T1ERR_SCAN_ENCODING
836   case T1ERR_SCAN_ENCODING:
837     i_push_error(T1ERR_SCAN_ENCODING, "Error Scanning Encoding File"); 
838     break;
839 #endif
840
841   default:
842     i_push_errorf(T1_errno, "unknown error %d", (int)T1_errno);
843   }
844 #endif
845 }
846