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