freetype-config might not be available, allow pkg-config to work
[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;
0d052fd9 14static int t1_aa = -1;
1aaae40f
TC
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 213
0d052fd9
TC
214 mm_log((1, "i_t1_set_aa(%d)\n", st));
215
1aaae40f
TC
216 if (t1_aa == st)
217 return;
218
a556912d
TC
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 }
1aaae40f
TC
239
240 t1_aa = st;
a556912d
TC
241}
242
243
244/*
1aaae40f 245=item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align,aa)
a556912d
TC
246
247Interface 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 )
5cb09ff7 258 aa - anti-aliasing level
a556912d
TC
259
260=cut
261*/
262
263undef_int
1aaae40f 264i_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
265 GLYPH *glyph;
266 int xsize,ysize,x,y;
267 i_color val;
268 int mod_flags = t1_get_flags(flags);
1aaae40f 269 int fontnum = font->font_id;
a556912d
TC
270
271 unsigned int ch_mask_store;
272
5cb09ff7
TC
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 }
a2f0c379 283
1aaae40f
TC
284 i_mutex_lock(mutex);
285
286 i_t1_set_aa(aa);
287
a556912d
TC
288 if (utf8) {
289 int worklen;
290 char *work = t1_from_utf8(str, len, &worklen);
932f9afb
TC
291 if (work == NULL) {
292 i_mutex_unlock(mutex);
293 return 0;
294 }
a556912d
TC
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 }
1aaae40f 301 if (glyph == NULL) {
5cb09ff7
TC
302 t1_push_error();
303 i_push_error(0, "i_t1_cp: T1_AASetString failed");
1aaae40f 304 i_mutex_unlock(mutex);
a556912d 305 return 0;
1aaae40f 306 }
a556912d
TC
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));
5e84d110 311 mm_log((1,"bpp: %lu\n", (unsigned long)glyph->bpp));
a556912d
TC
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;
1aaae40f
TC
329
330 i_mutex_unlock(mutex);
331
a556912d
TC
332 return 1;
333}
334
335static void
336t1_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
350function 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
362int
567c2038 363i_t1_bbox(i_t1_font_t font, double points,const char *str,size_t len, i_img_dim *cords, int utf8,char const *flags) {
a556912d
TC
364 BBox bbox;
365 BBox gbbox;
366 int mod_flags = t1_get_flags(flags);
8d14daab 367 i_img_dim advance;
1aaae40f
TC
368 int fontnum = font->font_id;
369 int space_position;
370
932f9afb
TC
371 i_clear_error();
372
1aaae40f
TC
373 i_mutex_lock(mutex);
374
375 space_position = T1_GetEncodingIndex(fontnum, "space");
a556912d 376
5e84d110
TC
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));
932f9afb
TC
379 if (T1_LoadFont(fontnum) == -1) {
380 t1_push_error();
381 i_mutex_unlock(mutex);
382 return 0;
383 }
a556912d
TC
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);
932f9afb
TC
395 if (!work) {
396 i_mutex_unlock(mutex);
397 return 0;
398 }
a556912d
TC
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
5e84d110 412 mm_log((1,"bbox: (%d, %d, %d, %d, %d, %d)\n",
a556912d
TC
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
8d14daab
TC
421 cords[BBOX_NEG_WIDTH]=((double)bbox.llx*points)/1000;
422 cords[BBOX_POS_WIDTH]=((double)bbox.urx*points)/1000;
a556912d 423
8d14daab
TC
424 cords[BBOX_GLOBAL_DESCENT]=((double)gbbox.lly*points)/1000;
425 cords[BBOX_GLOBAL_ASCENT]=((double)gbbox.ury*points)/1000;
a556912d 426
8d14daab
TC
427 cords[BBOX_DESCENT]=((double)bbox.lly*points)/1000;
428 cords[BBOX_ASCENT]=((double)bbox.ury*points)/1000;
a556912d 429
8d14daab 430 cords[BBOX_ADVANCE_WIDTH] = ((double)advance * points)/1000;
a556912d
TC
431 cords[BBOX_RIGHT_BEARING] =
432 cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH];
433
1aaae40f
TC
434 i_mutex_unlock(mutex);
435
a556912d
TC
436 return BBOX_RIGHT_BEARING+1;
437}
438
439
440/*
932f9afb 441=item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align, utf8, flags, aa)
a556912d
TC
442
443Interface 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 )
932f9afb
TC
454 utf8 - str is utf8
455 flags - formatting flags
1aaae40f 456 aa - anti-aliasing level
a556912d
TC
457
458=cut
459*/
460
461undef_int
1aaae40f 462i_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
463 GLYPH *glyph;
464 int xsize,ysize,y;
465 int mod_flags = t1_get_flags(flags);
466 i_render *r;
1aaae40f 467 int fontnum = font->font_id;
a556912d 468
5cb09ff7
TC
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 }
a2f0c379 479
1aaae40f
TC
480 i_mutex_lock(mutex);
481
482 i_t1_set_aa(aa);
483
a556912d
TC
484 if (utf8) {
485 int worklen;
486 char *work = t1_from_utf8(str, len, &worklen);
932f9afb
TC
487 if (!work) {
488 i_mutex_unlock(mutex);
489 return 0;
490 }
a556912d
TC
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 }
1aaae40f 498 if (glyph == NULL) {
5cb09ff7
TC
499 mm_log((1, "T1_AASetString failed\n"));
500 t1_push_error();
501 i_push_error(0, "i_t1_text(): T1_AASetString failed");
1aaae40f 502 i_mutex_unlock(mutex);
a556912d 503 return 0;
1aaae40f 504 }
a556912d
TC
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));
5e84d110 509 mm_log((1,"bpp: %lu\n",(unsigned long)glyph->bpp));
a556912d
TC
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);
1aaae40f
TC
523
524 i_mutex_unlock(mutex);
a556912d
TC
525
526 return 1;
527}
528
529/*
530=item t1_get_flags(flags)
531
532Processes the characters in I<flags> to create a mod_flags value used
533by some T1Lib functions.
534
535=cut
536 */
537static int
538t1_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
556Produces an unencoded version of I<in> by dropping any Unicode
557character over 255.
558
559Returns a newly allocated buffer which should be freed with myfree().
560Sets *outlen to the number of bytes used in the output string.
561
562=cut
563*/
564
565static char *
566t1_from_utf8(char const *in, size_t len, int *outlen) {
8d14daab
TC
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 */
a556912d
TC
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
594Check if the given characters are defined by the font. Note that len
595is the number of bytes, not the number of characters (when utf8 is
596non-zero).
597
598out[char index] will be true if the character exists.
599
600Accepts UTF-8, but since T1 can only have 256 characters, any chars
601with values over 255 will simply be returned as false.
602
603Returns the number of characters that were checked.
604
605=cut
606*/
607
608int
1aaae40f 609i_t1_has_chars(i_t1_font_t font, const char *text, size_t len, int utf8,
a556912d
TC
610 char *out) {
611 int count = 0;
1aaae40f 612 int font_num = font->font_id;
a556912d 613
1aaae40f
TC
614 i_mutex_lock(mutex);
615
5e84d110
TC
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));
a556912d
TC
618
619 i_clear_error();
620 if (T1_LoadFont(font_num)) {
621 t1_push_error();
1aaae40f 622 i_mutex_unlock(mutex);
a556912d
TC
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");
1aaae40f 632 i_mutex_unlock(mutex);
a556912d
TC
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
1aaae40f
TC
659 i_mutex_unlock(mutex);
660
a556912d
TC
661 return count;
662}
663
664/*
1aaae40f 665=item i_t1_face_name(font, name_buf, name_buf_size)
a556912d
TC
666
667Copies the face name of the given C<font_num> to C<name_buf>. Returns
668the number of characters required to store the name (which can be
669larger than C<name_buf_size>, including the space required to store
670the terminating NUL).
671
672If name_buf is too small (as specified by name_buf_size) then the name
673will be truncated. name_buf will always be NUL termintaed.
674
675=cut
676*/
677
678int
1aaae40f 679i_t1_face_name(i_t1_font_t font, char *name_buf, size_t name_buf_size) {
a556912d 680 char *name;
1aaae40f
TC
681 int font_num = font->font_id;
682
683 i_mutex_lock(mutex);
a556912d
TC
684
685 T1_errno = 0;
686 if (T1_LoadFont(font_num)) {
687 t1_push_error();
1aaae40f 688 i_mutex_unlock(mutex);
a556912d
TC
689 return 0;
690 }
691 name = T1_GetFontName(font_num);
692
693 if (name) {
1aaae40f 694 size_t len = strlen(name);
a556912d
TC
695 strncpy(name_buf, name, name_buf_size);
696 name_buf[name_buf_size-1] = '\0';
1aaae40f
TC
697 i_mutex_unlock(mutex);
698 return len + 1;
a556912d
TC
699 }
700 else {
701 t1_push_error();
1aaae40f 702 i_mutex_unlock(mutex);
a556912d
TC
703 return 0;
704 }
705}
706
707int
1aaae40f 708i_t1_glyph_name(i_t1_font_t font, unsigned long ch, char *name_buf,
a556912d
TC
709 size_t name_buf_size) {
710 char *name;
1aaae40f 711 int font_num = font->font_id;
a556912d
TC
712
713 i_clear_error();
714 if (ch > 0xFF) {
715 return 0;
716 }
932f9afb
TC
717
718 i_mutex_lock(mutex);
719
a556912d
TC
720 if (T1_LoadFont(font_num)) {
721 t1_push_error();
1aaae40f 722 i_mutex_unlock(mutex);
a556912d
TC
723 return 0;
724 }
725 name = T1_GetCharName(font_num, (unsigned char)ch);
726 if (name) {
727 if (strcmp(name, ".notdef")) {
1aaae40f 728 size_t len = strlen(name);
a556912d
TC
729 strncpy(name_buf, name, name_buf_size);
730 name_buf[name_buf_size-1] = '\0';
1aaae40f
TC
731 i_mutex_unlock(mutex);
732 return len + 1;
a556912d
TC
733 }
734 else {
1aaae40f 735 i_mutex_unlock(mutex);
a556912d
TC
736 return 0;
737 }
738 }
739 else {
740 t1_push_error();
1aaae40f 741 i_mutex_unlock(mutex);
a556912d
TC
742 return 0;
743 }
744}
745
746static void
747t1_push_error(void) {
73e3ff55
TC
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
a556912d
TC
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:
959df113 759 i_push_error(T1ERR_SCAN_FONT_FORMAT, "Attempt to Load Multiple Master Font");
a556912d
TC
760 break;
761#endif
762
763#ifdef T1ERR_SCAN_FILE_OPEN_ERR
764 case T1ERR_SCAN_FILE_OPEN_ERR:
959df113 765 i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "Type 1 Font File Open Error");
a556912d
TC
766 break;
767#endif
768
769#ifdef T1ERR_SCAN_OUT_OF_MEMORY
770 case T1ERR_SCAN_OUT_OF_MEMORY:
959df113 771 i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "Virtual Memory Exceeded");
a556912d
TC
772 break;
773#endif
774
775#ifdef T1ERR_SCAN_ERROR
776 case T1ERR_SCAN_ERROR:
959df113 777 i_push_error(T1ERR_SCAN_ERROR, "Syntactical Error Scanning Font File");
a556912d
TC
778 break;
779#endif
780
781#ifdef T1ERR_SCAN_FILE_EOF
782 case T1ERR_SCAN_FILE_EOF:
959df113 783 i_push_error(T1ERR_SCAN_FILE_EOF, "Premature End of Font File Encountered");
a556912d
TC
784 break;
785#endif
786
787#ifdef T1ERR_PATH_ERROR
788 case T1ERR_PATH_ERROR:
959df113 789 i_push_error(T1ERR_PATH_ERROR, "Path Construction Error");
a556912d
TC
790 break;
791#endif
792
793#ifdef T1ERR_PARSE_ERROR
794 case T1ERR_PARSE_ERROR:
959df113 795 i_push_error(T1ERR_PARSE_ERROR, "Font is Corrupt");
a556912d
TC
796 break;
797#endif
798
799#ifdef T1ERR_TYPE1_ABORT
800 case T1ERR_TYPE1_ABORT:
959df113 801 i_push_error(T1ERR_TYPE1_ABORT, "Rasterization Aborted");
a556912d
TC
802 break;
803#endif
804
805#ifdef T1ERR_INVALID_FONTID
806 case T1ERR_INVALID_FONTID:
959df113 807 i_push_error(T1ERR_INVALID_FONTID, "Font ID Invalid in this Context");
a556912d
TC
808 break;
809#endif
810
811#ifdef T1ERR_INVALID_PARAMETER
812 case T1ERR_INVALID_PARAMETER:
959df113 813 i_push_error(T1ERR_INVALID_PARAMETER, "Invalid Argument in Function Call");
a556912d
TC
814 break;
815#endif
816
817#ifdef T1ERR_OP_NOT_PERMITTED
818 case T1ERR_OP_NOT_PERMITTED:
959df113 819 i_push_error(T1ERR_OP_NOT_PERMITTED, "Operation not Permitted");
a556912d
TC
820 break;
821#endif
822
823#ifdef T1ERR_ALLOC_MEM
824 case T1ERR_ALLOC_MEM:
959df113 825 i_push_error(T1ERR_ALLOC_MEM, "Memory Allocation Error");
a556912d
TC
826 break;
827#endif
828
829#ifdef T1ERR_FILE_OPEN_ERR
830 case T1ERR_FILE_OPEN_ERR:
959df113 831 i_push_error(T1ERR_FILE_OPEN_ERR, "Error Opening File");
a556912d
TC
832 break;
833#endif
834
835#ifdef T1ERR_UNSPECIFIED
836 case T1ERR_UNSPECIFIED:
959df113 837 i_push_error(T1ERR_UNSPECIFIED, "Unspecified T1Lib Error");
a556912d
TC
838 break;
839#endif
840
841#ifdef T1ERR_NO_AFM_DATA
842 case T1ERR_NO_AFM_DATA:
959df113 843 i_push_error(T1ERR_NO_AFM_DATA, "Missing AFM Data");
a556912d
TC
844 break;
845#endif
846
847#ifdef T1ERR_X11
848 case T1ERR_X11:
959df113 849 i_push_error(T1ERR_X11, "X11 Interface Error");
a556912d
TC
850 break;
851#endif
852
853#ifdef T1ERR_COMPOSITE_CHAR
854 case T1ERR_COMPOSITE_CHAR:
959df113
TC
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");
a556912d
TC
862 break;
863#endif
864
865 default:
866 i_push_errorf(T1_errno, "unknown error %d", (int)T1_errno);
867 }
73e3ff55 868#endif
a556912d
TC
869}
870