mark mm_log() for the API with the right gcc -Wformat magic
[imager.git] / T1 / imt1.c
CommitLineData
a556912d
TC
1#include "imext.h"
2#include "imt1.h"
3#include <t1lib.h>
4#include <string.h>
5
6static int t1_get_flags(char const *flags);
7static char *t1_from_utf8(char const *in, size_t len, int *outlen);
1aaae40f 8static undef_int i_init_t1_low(int t1log);
a556912d 9static void t1_push_error(void);
1aaae40f 10static void i_t1_set_aa(int st);
a556912d
TC
11
12static int t1_active_fonts = 0;
13static int t1_initialized = 0;
1aaae40f
TC
14static int t1_aa = 0;
15
16struct i_t1_font_tag {
17 int font_id;
18};
19
20static i_mutex_t mutex;
21
22/*
23=item i_t1_start()
24
25Initialize the font driver. This does not actually initialize T1Lib,
26it just allocates the mutex we use to gate access to it.
27
28=cut
29*/
30
31void
32i_t1_start(void) {
33 mutex = i_mutex_new();
34}
a556912d
TC
35
36/*
37=item i_init_t1(t1log)
38
39Initializes the t1lib font rendering engine.
40
41=cut
42*/
43
44undef_int
45i_init_t1(int t1log) {
1aaae40f
TC
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
56static undef_int
57i_init_t1_low(int t1log) {
a556912d 58 int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE;
5cb09ff7
TC
59
60 mm_log((1,"init_t1(%d)\n", t1log));
a556912d
TC
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();
a3fd7df7 72 t1_initialized = 0;
a556912d
TC
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);
a556912d
TC
83
84 ++t1_initialized;
85
86 return(0);
87}
88
89/*
90=item i_close_t1()
91
92Shuts the t1lib font rendering engine down.
93
94 This it seems that this function is never used.
95
96=cut
97*/
98
99void
100i_close_t1(void) {
1aaae40f 101 i_mutex_lock(mutex);
a556912d
TC
102 T1_CloseLib();
103 t1_initialized = 0;
1aaae40f 104 i_mutex_unlock(mutex);
a556912d
TC
105}
106
107
108/*
109=item i_t1_new(pfb, afm)
110
111Loads 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
1aaae40f 119i_t1_font_t
a556912d
TC
120i_t1_new(char *pfb,char *afm) {
121 int font_id;
1aaae40f
TC
122 i_t1_font_t font;
123
124 i_mutex_lock(mutex);
a556912d
TC
125
126 i_clear_error();
127
1aaae40f
TC
128 if (!t1_initialized && i_init_t1_low(0)) {
129 i_mutex_unlock(mutex);
130 return NULL;
131 }
a556912d
TC
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));
73e3ff55 137 t1_push_error();
1aaae40f
TC
138 i_mutex_unlock(mutex);
139 return NULL;
a556912d
TC
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
73e3ff55
TC
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);
1aaae40f
TC
152 i_mutex_unlock(mutex);
153 return NULL;
73e3ff55
TC
154 }
155
a556912d
TC
156 ++t1_active_fonts;
157
1aaae40f
TC
158 i_mutex_unlock(mutex);
159
160 font = mymalloc(sizeof(*font));
161 font->font_id = font_id;
162
5cb09ff7
TC
163 mm_log((1, "i_t1_new() -> %p (%d)\n", font, font_id));
164
1aaae40f 165 return font;
a556912d
TC
166}
167
168/*
1aaae40f 169=item i_t1_destroy(font)
a556912d
TC
170
171Frees resources for a t1 font with given font id.
172
1aaae40f 173 font - font to free
a556912d
TC
174
175=cut
176*/
177
178int
1aaae40f
TC
179i_t1_destroy(i_t1_font_t font) {
180 int result;
181
182 i_mutex_lock(mutex);
183
5cb09ff7 184 mm_log((1,"i_t1_destroy(font %p (%d))\n", font, font->font_id));
a556912d
TC
185
186 --t1_active_fonts;
187
1aaae40f
TC
188 result = T1_DeleteFont(font->font_id);
189 myfree(font);
190
191 i_mutex_unlock(mutex);
192
193 return result;
a556912d
TC
194}
195
196
197/*
198=item i_t1_set_aa(st)
199
200Sets the antialiasing level of the t1 library.
201
202 st - 0 = NONE, 1 = LOW, 2 = HIGH.
203
1aaae40f
TC
204Must be called with the mutex locked.
205
a556912d
TC
206=cut
207*/
208
1aaae40f 209static void
a556912d
TC
210i_t1_set_aa(int st) {
211 int i;
212 unsigned long cst[17];
1aaae40f
TC
213
214 if (t1_aa == st)
215 return;
216
a556912d
TC
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 }
1aaae40f
TC
237
238 t1_aa = st;
a556912d
TC
239}
240
241
242/*
1aaae40f 243=item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align,aa)
a556912d
TC
244
245Interface 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 )
5cb09ff7 256 aa - anti-aliasing level
a556912d
TC
257
258=cut
259*/
260
261undef_int
1aaae40f 262i_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) {
a556912d
TC
263 GLYPH *glyph;
264 int xsize,ysize,x,y;
265 i_color val;
266 int mod_flags = t1_get_flags(flags);
1aaae40f 267 int fontnum = font->font_id;
a556912d
TC
268
269 unsigned int ch_mask_store;
270
5cb09ff7
TC
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 }
a2f0c379 281
1aaae40f
TC
282 i_mutex_lock(mutex);
283
284 i_t1_set_aa(aa);
285
a556912d
TC
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 }
1aaae40f 295 if (glyph == NULL) {
5cb09ff7
TC
296 t1_push_error();
297 i_push_error(0, "i_t1_cp: T1_AASetString failed");
1aaae40f 298 i_mutex_unlock(mutex);
a556912d 299 return 0;
1aaae40f 300 }
a556912d
TC
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));
5e84d110 305 mm_log((1,"bpp: %lu\n", (unsigned long)glyph->bpp));
a556912d
TC
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;
1aaae40f
TC
323
324 i_mutex_unlock(mutex);
325
a556912d
TC
326 return 1;
327}
328
329static void
330t1_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
344function 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
356int
1aaae40f 357i_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) {
a556912d
TC
358 BBox bbox;
359 BBox gbbox;
360 int mod_flags = t1_get_flags(flags);
8d14daab 361 i_img_dim advance;
1aaae40f
TC
362 int fontnum = font->font_id;
363 int space_position;
364
365 i_mutex_lock(mutex);
366
367 space_position = T1_GetEncodingIndex(fontnum, "space");
a556912d 368
5e84d110
TC
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));
a556912d
TC
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
5e84d110 396 mm_log((1,"bbox: (%d, %d, %d, %d, %d, %d)\n",
a556912d
TC
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
8d14daab
TC
405 cords[BBOX_NEG_WIDTH]=((double)bbox.llx*points)/1000;
406 cords[BBOX_POS_WIDTH]=((double)bbox.urx*points)/1000;
a556912d 407
8d14daab
TC
408 cords[BBOX_GLOBAL_DESCENT]=((double)gbbox.lly*points)/1000;
409 cords[BBOX_GLOBAL_ASCENT]=((double)gbbox.ury*points)/1000;
a556912d 410
8d14daab
TC
411 cords[BBOX_DESCENT]=((double)bbox.lly*points)/1000;
412 cords[BBOX_ASCENT]=((double)bbox.ury*points)/1000;
a556912d 413
8d14daab 414 cords[BBOX_ADVANCE_WIDTH] = ((double)advance * points)/1000;
a556912d
TC
415 cords[BBOX_RIGHT_BEARING] =
416 cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH];
417
1aaae40f
TC
418 i_mutex_unlock(mutex);
419
a556912d
TC
420 return BBOX_RIGHT_BEARING+1;
421}
422
423
424/*
1aaae40f 425=item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align, aa)
a556912d
TC
426
427Interface 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 )
1aaae40f 438 aa - anti-aliasing level
a556912d
TC
439
440=cut
441*/
442
443undef_int
1aaae40f 444i_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) {
a556912d
TC
445 GLYPH *glyph;
446 int xsize,ysize,y;
447 int mod_flags = t1_get_flags(flags);
448 i_render *r;
1aaae40f 449 int fontnum = font->font_id;
a556912d 450
5cb09ff7
TC
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 }
a2f0c379 461
1aaae40f
TC
462 i_mutex_lock(mutex);
463
464 i_t1_set_aa(aa);
465
a556912d
TC
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 }
1aaae40f 476 if (glyph == NULL) {
5cb09ff7
TC
477 mm_log((1, "T1_AASetString failed\n"));
478 t1_push_error();
479 i_push_error(0, "i_t1_text(): T1_AASetString failed");
1aaae40f 480 i_mutex_unlock(mutex);
a556912d 481 return 0;
1aaae40f 482 }
a556912d
TC
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));
5e84d110 487 mm_log((1,"bpp: %lu\n",(unsigned long)glyph->bpp));
a556912d
TC
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);
1aaae40f
TC
501
502 i_mutex_unlock(mutex);
a556912d
TC
503
504 return 1;
505}
506
507/*
508=item t1_get_flags(flags)
509
510Processes the characters in I<flags> to create a mod_flags value used
511by some T1Lib functions.
512
513=cut
514 */
515static int
516t1_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
534Produces an unencoded version of I<in> by dropping any Unicode
535character over 255.
536
537Returns a newly allocated buffer which should be freed with myfree().
538Sets *outlen to the number of bytes used in the output string.
539
540=cut
541*/
542
543static char *
544t1_from_utf8(char const *in, size_t len, int *outlen) {
8d14daab
TC
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 */
a556912d
TC
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
572Check if the given characters are defined by the font. Note that len
573is the number of bytes, not the number of characters (when utf8 is
574non-zero).
575
576out[char index] will be true if the character exists.
577
578Accepts UTF-8, but since T1 can only have 256 characters, any chars
579with values over 255 will simply be returned as false.
580
581Returns the number of characters that were checked.
582
583=cut
584*/
585
586int
1aaae40f 587i_t1_has_chars(i_t1_font_t font, const char *text, size_t len, int utf8,
a556912d
TC
588 char *out) {
589 int count = 0;
1aaae40f 590 int font_num = font->font_id;
a556912d 591
1aaae40f
TC
592 i_mutex_lock(mutex);
593
5e84d110
TC
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));
a556912d
TC
596
597 i_clear_error();
598 if (T1_LoadFont(font_num)) {
599 t1_push_error();
1aaae40f 600 i_mutex_unlock(mutex);
a556912d
TC
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");
1aaae40f 610 i_mutex_unlock(mutex);
a556912d
TC
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
1aaae40f
TC
637 i_mutex_unlock(mutex);
638
a556912d
TC
639 return count;
640}
641
642/*
1aaae40f 643=item i_t1_face_name(font, name_buf, name_buf_size)
a556912d
TC
644
645Copies the face name of the given C<font_num> to C<name_buf>. Returns
646the number of characters required to store the name (which can be
647larger than C<name_buf_size>, including the space required to store
648the terminating NUL).
649
650If name_buf is too small (as specified by name_buf_size) then the name
651will be truncated. name_buf will always be NUL termintaed.
652
653=cut
654*/
655
656int
1aaae40f 657i_t1_face_name(i_t1_font_t font, char *name_buf, size_t name_buf_size) {
a556912d 658 char *name;
1aaae40f
TC
659 int font_num = font->font_id;
660
661 i_mutex_lock(mutex);
a556912d
TC
662
663 T1_errno = 0;
664 if (T1_LoadFont(font_num)) {
665 t1_push_error();
1aaae40f 666 i_mutex_unlock(mutex);
a556912d
TC
667 return 0;
668 }
669 name = T1_GetFontName(font_num);
670
671 if (name) {
1aaae40f 672 size_t len = strlen(name);
a556912d
TC
673 strncpy(name_buf, name, name_buf_size);
674 name_buf[name_buf_size-1] = '\0';
1aaae40f
TC
675 i_mutex_unlock(mutex);
676 return len + 1;
a556912d
TC
677 }
678 else {
679 t1_push_error();
1aaae40f 680 i_mutex_unlock(mutex);
a556912d
TC
681 return 0;
682 }
683}
684
685int
1aaae40f 686i_t1_glyph_name(i_t1_font_t font, unsigned long ch, char *name_buf,
a556912d
TC
687 size_t name_buf_size) {
688 char *name;
1aaae40f 689 int font_num = font->font_id;
a556912d 690
1aaae40f 691 i_mutex_lock(mutex);
a556912d
TC
692 i_clear_error();
693 if (ch > 0xFF) {
1aaae40f 694 i_mutex_unlock(mutex);
a556912d
TC
695 return 0;
696 }
697 if (T1_LoadFont(font_num)) {
698 t1_push_error();
1aaae40f 699 i_mutex_unlock(mutex);
a556912d
TC
700 return 0;
701 }
702 name = T1_GetCharName(font_num, (unsigned char)ch);
703 if (name) {
704 if (strcmp(name, ".notdef")) {
1aaae40f 705 size_t len = strlen(name);
a556912d
TC
706 strncpy(name_buf, name, name_buf_size);
707 name_buf[name_buf_size-1] = '\0';
1aaae40f
TC
708 i_mutex_unlock(mutex);
709 return len + 1;
a556912d
TC
710 }
711 else {
1aaae40f 712 i_mutex_unlock(mutex);
a556912d
TC
713 return 0;
714 }
715 }
716 else {
717 t1_push_error();
1aaae40f 718 i_mutex_unlock(mutex);
a556912d
TC
719 return 0;
720 }
721}
722
723static void
724t1_push_error(void) {
73e3ff55
TC
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
a556912d
TC
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:
959df113 736 i_push_error(T1ERR_SCAN_FONT_FORMAT, "Attempt to Load Multiple Master Font");
a556912d
TC
737 break;
738#endif
739
740#ifdef T1ERR_SCAN_FILE_OPEN_ERR
741 case T1ERR_SCAN_FILE_OPEN_ERR:
959df113 742 i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "Type 1 Font File Open Error");
a556912d
TC
743 break;
744#endif
745
746#ifdef T1ERR_SCAN_OUT_OF_MEMORY
747 case T1ERR_SCAN_OUT_OF_MEMORY:
959df113 748 i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "Virtual Memory Exceeded");
a556912d
TC
749 break;
750#endif
751
752#ifdef T1ERR_SCAN_ERROR
753 case T1ERR_SCAN_ERROR:
959df113 754 i_push_error(T1ERR_SCAN_ERROR, "Syntactical Error Scanning Font File");
a556912d
TC
755 break;
756#endif
757
758#ifdef T1ERR_SCAN_FILE_EOF
759 case T1ERR_SCAN_FILE_EOF:
959df113 760 i_push_error(T1ERR_SCAN_FILE_EOF, "Premature End of Font File Encountered");
a556912d
TC
761 break;
762#endif
763
764#ifdef T1ERR_PATH_ERROR
765 case T1ERR_PATH_ERROR:
959df113 766 i_push_error(T1ERR_PATH_ERROR, "Path Construction Error");
a556912d
TC
767 break;
768#endif
769
770#ifdef T1ERR_PARSE_ERROR
771 case T1ERR_PARSE_ERROR:
959df113 772 i_push_error(T1ERR_PARSE_ERROR, "Font is Corrupt");
a556912d
TC
773 break;
774#endif
775
776#ifdef T1ERR_TYPE1_ABORT
777 case T1ERR_TYPE1_ABORT:
959df113 778 i_push_error(T1ERR_TYPE1_ABORT, "Rasterization Aborted");
a556912d
TC
779 break;
780#endif
781
782#ifdef T1ERR_INVALID_FONTID
783 case T1ERR_INVALID_FONTID:
959df113 784 i_push_error(T1ERR_INVALID_FONTID, "Font ID Invalid in this Context");
a556912d
TC
785 break;
786#endif
787
788#ifdef T1ERR_INVALID_PARAMETER
789 case T1ERR_INVALID_PARAMETER:
959df113 790 i_push_error(T1ERR_INVALID_PARAMETER, "Invalid Argument in Function Call");
a556912d
TC
791 break;
792#endif
793
794#ifdef T1ERR_OP_NOT_PERMITTED
795 case T1ERR_OP_NOT_PERMITTED:
959df113 796 i_push_error(T1ERR_OP_NOT_PERMITTED, "Operation not Permitted");
a556912d
TC
797 break;
798#endif
799
800#ifdef T1ERR_ALLOC_MEM
801 case T1ERR_ALLOC_MEM:
959df113 802 i_push_error(T1ERR_ALLOC_MEM, "Memory Allocation Error");
a556912d
TC
803 break;
804#endif
805
806#ifdef T1ERR_FILE_OPEN_ERR
807 case T1ERR_FILE_OPEN_ERR:
959df113 808 i_push_error(T1ERR_FILE_OPEN_ERR, "Error Opening File");
a556912d
TC
809 break;
810#endif
811
812#ifdef T1ERR_UNSPECIFIED
813 case T1ERR_UNSPECIFIED:
959df113 814 i_push_error(T1ERR_UNSPECIFIED, "Unspecified T1Lib Error");
a556912d
TC
815 break;
816#endif
817
818#ifdef T1ERR_NO_AFM_DATA
819 case T1ERR_NO_AFM_DATA:
959df113 820 i_push_error(T1ERR_NO_AFM_DATA, "Missing AFM Data");
a556912d
TC
821 break;
822#endif
823
824#ifdef T1ERR_X11
825 case T1ERR_X11:
959df113 826 i_push_error(T1ERR_X11, "X11 Interface Error");
a556912d
TC
827 break;
828#endif
829
830#ifdef T1ERR_COMPOSITE_CHAR
831 case T1ERR_COMPOSITE_CHAR:
959df113
TC
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");
a556912d
TC
839 break;
840#endif
841
842 default:
843 i_push_errorf(T1_errno, "unknown error %d", (int)T1_errno);
844 }
73e3ff55 845#endif
a556912d
TC
846}
847