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