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