[rt #75560] don't fallback to using DynaLoader when XSLoader fails
[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);
8
9static void t1_push_error(void);
10
11static int t1_active_fonts = 0;
12static int t1_initialized = 0;
13
14/*
15=item i_init_t1(t1log)
16
17Initializes the t1lib font rendering engine.
18
19=cut
20*/
21
22undef_int
23i_init_t1(int t1log) {
24 int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE;
25 mm_log((1,"init_t1()\n"));
26
27 i_clear_error();
28
29 if (t1_active_fonts) {
30 mm_log((1, "Cannot re-initialize T1 - active fonts\n"));
31 i_push_error(0, "Cannot re-initialize T1 - active fonts");
32 return 1;
33 }
34
35 if (t1_initialized) {
36 T1_CloseLib();
a3fd7df7 37 t1_initialized = 0;
a556912d
TC
38 }
39
40 if (t1log)
41 init_flags |= LOGFILE;
42 if ((T1_InitLib(init_flags) == NULL)){
43 mm_log((1,"Initialization of t1lib failed\n"));
44 i_push_error(0, "T1_InitLib failed");
45 return(1);
46 }
47 T1_SetLogLevel(T1LOG_DEBUG);
48 i_t1_set_aa(1); /* Default Antialias value */
49
50 ++t1_initialized;
51
52 return(0);
53}
54
55/*
56=item i_close_t1()
57
58Shuts the t1lib font rendering engine down.
59
60 This it seems that this function is never used.
61
62=cut
63*/
64
65void
66i_close_t1(void) {
67 T1_CloseLib();
68 t1_initialized = 0;
69}
70
71
72/*
73=item i_t1_new(pfb, afm)
74
75Loads the fonts with the given filenames, returns its font id
76
77 pfb - path to pfb file for font
78 afm - path to afm file for font
79
80=cut
81*/
82
83int
84i_t1_new(char *pfb,char *afm) {
85 int font_id;
86
87 i_clear_error();
88
89 if (!t1_initialized && i_init_t1(0))
90 return -1;
91
92 mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL")));
93 font_id = T1_AddFont(pfb);
94 if (font_id<0) {
95 mm_log((1,"i_t1_new: Failed to load pfb file '%s' - return code %d.\n",pfb,font_id));
73e3ff55 96 t1_push_error();
a556912d
TC
97 return font_id;
98 }
99
100 if (afm != NULL) {
101 mm_log((1,"i_t1_new: requesting afm file '%s'.\n",afm));
102 if (T1_SetAfmFileName(font_id,afm)<0) mm_log((1,"i_t1_new: afm loading of '%s' failed.\n",afm));
103 }
104
73e3ff55
TC
105 if (T1_LoadFont(font_id)) {
106 mm_log((1, "i_t1_new() -> -1 - T1_LoadFont failed (%d)\n", T1_errno));
107 t1_push_error();
108 i_push_error(0, "loading font");
109 T1_DeleteFont(font_id);
110 return -1;
111 }
112
a556912d
TC
113 ++t1_active_fonts;
114
73e3ff55
TC
115 mm_log((1, "i_t1_new() -> %d\n", font_id));
116
a556912d
TC
117 return font_id;
118}
119
120/*
121=item i_t1_destroy(font_id)
122
123Frees resources for a t1 font with given font id.
124
125 font_id - number of the font to free
126
127=cut
128*/
129
130int
131i_t1_destroy(int font_id) {
132 mm_log((1,"i_t1_destroy(font_id %d)\n",font_id));
133
134 --t1_active_fonts;
135
136 return T1_DeleteFont(font_id);
137}
138
139
140/*
141=item i_t1_set_aa(st)
142
143Sets the antialiasing level of the t1 library.
144
145 st - 0 = NONE, 1 = LOW, 2 = HIGH.
146
147=cut
148*/
149
150void
151i_t1_set_aa(int st) {
152 int i;
153 unsigned long cst[17];
154 switch(st) {
155 case 0:
156 T1_AASetBitsPerPixel( 8 );
157 T1_AASetLevel( T1_AA_NONE );
158 T1_AANSetGrayValues( 0, 255 );
159 mm_log((1,"setting T1 antialias to none\n"));
160 break;
161 case 1:
162 T1_AASetBitsPerPixel( 8 );
163 T1_AASetLevel( T1_AA_LOW );
164 T1_AASetGrayValues( 0,65,127,191,255 );
165 mm_log((1,"setting T1 antialias to low\n"));
166 break;
167 case 2:
168 T1_AASetBitsPerPixel(8);
169 T1_AASetLevel(T1_AA_HIGH);
170 for(i=0;i<17;i++) cst[i]=(i*255)/16;
171 T1_AAHSetGrayValues( cst );
172 mm_log((1,"setting T1 antialias to high\n"));
173 }
174}
175
176
177/*
178=item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align)
179
180Interface to text rendering into a single channel in an image
181
182 im pointer to image structure
183 xb x coordinate of start of string
184 yb y coordinate of start of string ( see align )
185 channel - destination channel
186 fontnum - t1 library font id
187 points - number of points in fontheight
188 str - string to render
189 len - string length
190 align - (0 - top of font glyph | 1 - baseline )
191
192=cut
193*/
194
195undef_int
8d14daab 196i_t1_cp(i_img *im,i_img_dim xb,i_img_dim yb,int channel,int fontnum,double points,char* str,size_t len,int align, int utf8, char const *flags) {
a556912d
TC
197 GLYPH *glyph;
198 int xsize,ysize,x,y;
199 i_color val;
200 int mod_flags = t1_get_flags(flags);
201
202 unsigned int ch_mask_store;
203
204 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
205
206 if (utf8) {
207 int worklen;
208 char *work = t1_from_utf8(str, len, &worklen);
209 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
210 myfree(work);
211 }
212 else {
213 glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
214 }
215 if (glyph == NULL)
216 return 0;
217
218 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
219 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
220 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
221 mm_log((1,"bpp: %d\n",glyph->bpp));
222
223 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
224 ysize=glyph->metrics.ascent-glyph->metrics.descent;
225
226 mm_log((1,"width: %d height: %d\n",xsize,ysize));
227
228 ch_mask_store=im->ch_mask;
229 im->ch_mask=1<<channel;
230
231 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
232
233 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
234 val.channel[channel]=glyph->bits[y*xsize+x];
235 i_ppix(im,x+xb,y+yb,&val);
236 }
237
238 im->ch_mask=ch_mask_store;
239 return 1;
240}
241
242static void
243t1_fix_bbox(BBox *bbox, const char *str, size_t len, int advance,
244 int space_position) {
245 /* never called with len == 0 */
246 if (str[0] == space_position && bbox->llx > 0)
247 bbox->llx = 0;
248 if (str[len-1] == space_position && bbox->urx < advance)
249 bbox->urx = advance;
250 if (bbox->lly > bbox->ury)
251 bbox->lly = bbox->ury = 0;
252}
253
254/*
255=item i_t1_bbox(handle, fontnum, points, str, len, cords)
256
257function to get a strings bounding box given the font id and sizes
258
259 handle - pointer to font handle
260 fontnum - t1 library font id
261 points - number of points in fontheight
262 str - string to measure
263 len - string length
264 cords - the bounding box (modified in place)
265
266=cut
267*/
268
269int
8d14daab 270i_t1_bbox(int fontnum, double points,const char *str,size_t len, i_img_dim cords[6], int utf8,char const *flags) {
a556912d
TC
271 BBox bbox;
272 BBox gbbox;
273 int mod_flags = t1_get_flags(flags);
8d14daab 274 i_img_dim advance;
a556912d
TC
275 int space_position = T1_GetEncodingIndex(fontnum, "space");
276
277 mm_log((1,"i_t1_bbox(fontnum %d,points %.2f,str '%.*s', len %d)\n",fontnum,points,len,str,len));
278 T1_LoadFont(fontnum); /* FIXME: Here a return code is ignored - haw haw haw */
279
280 if (len == 0) {
281 /* len == 0 has special meaning to T1lib, but it means there's
282 nothing to draw, so return that */
283 bbox.llx = bbox.lly = bbox.urx = bbox.ury = 0;
284 advance = 0;
285 }
286 else {
287 if (utf8) {
288 int worklen;
289 char *work = t1_from_utf8(str, len, &worklen);
290 advance = T1_GetStringWidth(fontnum, work, worklen, 0, mod_flags);
291 bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
292 t1_fix_bbox(&bbox, work, worklen, advance, space_position);
293 myfree(work);
294 }
295 else {
296 advance = T1_GetStringWidth(fontnum, (char *)str, len, 0, mod_flags);
297 bbox = T1_GetStringBBox(fontnum,(char *)str,len,0,mod_flags);
298 t1_fix_bbox(&bbox, str, len, advance, space_position);
299 }
300 }
301 gbbox = T1_GetFontBBox(fontnum);
302
303 mm_log((1,"bbox: (%d,%d,%d,%d)\n",
304 (int)(bbox.llx*points/1000),
305 (int)(gbbox.lly*points/1000),
306 (int)(bbox.urx*points/1000),
307 (int)(gbbox.ury*points/1000),
308 (int)(bbox.lly*points/1000),
309 (int)(bbox.ury*points/1000) ));
310
311
8d14daab
TC
312 cords[BBOX_NEG_WIDTH]=((double)bbox.llx*points)/1000;
313 cords[BBOX_POS_WIDTH]=((double)bbox.urx*points)/1000;
a556912d 314
8d14daab
TC
315 cords[BBOX_GLOBAL_DESCENT]=((double)gbbox.lly*points)/1000;
316 cords[BBOX_GLOBAL_ASCENT]=((double)gbbox.ury*points)/1000;
a556912d 317
8d14daab
TC
318 cords[BBOX_DESCENT]=((double)bbox.lly*points)/1000;
319 cords[BBOX_ASCENT]=((double)bbox.ury*points)/1000;
a556912d 320
8d14daab 321 cords[BBOX_ADVANCE_WIDTH] = ((double)advance * points)/1000;
a556912d
TC
322 cords[BBOX_RIGHT_BEARING] =
323 cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH];
324
325 return BBOX_RIGHT_BEARING+1;
326}
327
328
329/*
330=item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align)
331
332Interface to text rendering in a single color onto an image
333
334 im - pointer to image structure
335 xb - x coordinate of start of string
336 yb - y coordinate of start of string ( see align )
337 cl - color to draw the text in
338 fontnum - t1 library font id
339 points - number of points in fontheight
340 str - char pointer to string to render
341 len - string length
342 align - (0 - top of font glyph | 1 - baseline )
343
344=cut
345*/
346
347undef_int
8d14daab 348i_t1_text(i_img *im, i_img_dim xb, i_img_dim yb,const i_color *cl,int fontnum, double points,const char* str,size_t len,int align, int utf8, char const *flags) {
a556912d
TC
349 GLYPH *glyph;
350 int xsize,ysize,y;
351 int mod_flags = t1_get_flags(flags);
352 i_render *r;
353
354 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
355
356 if (utf8) {
357 int worklen;
358 char *work = t1_from_utf8(str, len, &worklen);
359 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
360 myfree(work);
361 }
362 else {
363 /* T1_AASetString() accepts a char * not a const char */
364 glyph=T1_AASetString( fontnum, (char *)str, len, 0, mod_flags, points, NULL);
365 }
366 if (glyph == NULL)
367 return 0;
368
369 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
370 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
371 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
372 mm_log((1,"bpp: %d\n",glyph->bpp));
373
374 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
375 ysize=glyph->metrics.ascent-glyph->metrics.descent;
376
377 mm_log((1,"width: %d height: %d\n",xsize,ysize));
378
379 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
380
381 r = i_render_new(im, xsize);
382 for(y=0;y<ysize;y++) {
383 i_render_color(r, xb, yb+y, xsize, (unsigned char *)glyph->bits+y*xsize, cl);
384 }
385 i_render_delete(r);
386
387 return 1;
388}
389
390/*
391=item t1_get_flags(flags)
392
393Processes the characters in I<flags> to create a mod_flags value used
394by some T1Lib functions.
395
396=cut
397 */
398static int
399t1_get_flags(char const *flags) {
400 int mod_flags = T1_KERNING;
401
402 while (*flags) {
403 switch (*flags++) {
404 case 'u': case 'U': mod_flags |= T1_UNDERLINE; break;
405 case 'o': case 'O': mod_flags |= T1_OVERLINE; break;
406 case 's': case 'S': mod_flags |= T1_OVERSTRIKE; break;
407 /* ignore anything we don't recognize */
408 }
409 }
410
411 return mod_flags;
412}
413
414/*
415=item t1_from_utf8(char const *in, size_t len, int *outlen)
416
417Produces an unencoded version of I<in> by dropping any Unicode
418character over 255.
419
420Returns a newly allocated buffer which should be freed with myfree().
421Sets *outlen to the number of bytes used in the output string.
422
423=cut
424*/
425
426static char *
427t1_from_utf8(char const *in, size_t len, int *outlen) {
8d14daab
TC
428 /* at this point len is from a STRLEN which should be size_t and can't
429 be too big for mymalloc */
430 char *out = mymalloc(len+1); /* rechecked 29jul11 tonyc */
a556912d
TC
431 char *p = out;
432 unsigned long c;
433
434 while (len) {
435 c = i_utf8_advance(&in, &len);
436 if (c == ~0UL) {
437 myfree(out);
438 i_push_error(0, "invalid UTF8 character");
439 return 0;
440 }
441 /* yeah, just drop them */
442 if (c < 0x100) {
443 *p++ = (char)c;
444 }
445 }
446 *p = '\0';
447 *outlen = p - out;
448
449 return out;
450}
451
452/*
453=item i_t1_has_chars(font_num, text, len, utf8, out)
454
455Check if the given characters are defined by the font. Note that len
456is the number of bytes, not the number of characters (when utf8 is
457non-zero).
458
459out[char index] will be true if the character exists.
460
461Accepts UTF-8, but since T1 can only have 256 characters, any chars
462with values over 255 will simply be returned as false.
463
464Returns the number of characters that were checked.
465
466=cut
467*/
468
469int
470i_t1_has_chars(int font_num, const char *text, size_t len, int utf8,
471 char *out) {
472 int count = 0;
473
474 mm_log((1, "i_t1_has_chars(font_num %d, text %p, len %d, utf8 %d)\n",
475 font_num, text, len, utf8));
476
477 i_clear_error();
478 if (T1_LoadFont(font_num)) {
479 t1_push_error();
480 return 0;
481 }
482
483 while (len) {
484 unsigned long c;
485 if (utf8) {
486 c = i_utf8_advance(&text, &len);
487 if (c == ~0UL) {
488 i_push_error(0, "invalid UTF8 character");
489 return 0;
490 }
491 }
492 else {
493 c = (unsigned char)*text++;
494 --len;
495 }
496
497 if (c >= 0x100) {
498 /* limit of 256 characters for T1 */
499 *out++ = 0;
500 }
501 else {
502 char const * name = T1_GetCharName(font_num, (unsigned char)c);
503
504 if (name) {
505 *out++ = strcmp(name, ".notdef") != 0;
506 }
507 else {
508 mm_log((2, " No name found for character %lx\n", c));
509 *out++ = 0;
510 }
511 }
512 ++count;
513 }
514
515 return count;
516}
517
518/*
519=item i_t1_face_name(font_num, name_buf, name_buf_size)
520
521Copies the face name of the given C<font_num> to C<name_buf>. Returns
522the number of characters required to store the name (which can be
523larger than C<name_buf_size>, including the space required to store
524the terminating NUL).
525
526If name_buf is too small (as specified by name_buf_size) then the name
527will be truncated. name_buf will always be NUL termintaed.
528
529=cut
530*/
531
532int
533i_t1_face_name(int font_num, char *name_buf, size_t name_buf_size) {
534 char *name;
535
536 T1_errno = 0;
537 if (T1_LoadFont(font_num)) {
538 t1_push_error();
539 return 0;
540 }
541 name = T1_GetFontName(font_num);
542
543 if (name) {
544 strncpy(name_buf, name, name_buf_size);
545 name_buf[name_buf_size-1] = '\0';
546 return strlen(name) + 1;
547 }
548 else {
549 t1_push_error();
550 return 0;
551 }
552}
553
554int
555i_t1_glyph_name(int font_num, unsigned long ch, char *name_buf,
556 size_t name_buf_size) {
557 char *name;
558
559 i_clear_error();
560 if (ch > 0xFF) {
561 return 0;
562 }
563 if (T1_LoadFont(font_num)) {
564 t1_push_error();
565 return 0;
566 }
567 name = T1_GetCharName(font_num, (unsigned char)ch);
568 if (name) {
569 if (strcmp(name, ".notdef")) {
570 strncpy(name_buf, name, name_buf_size);
571 name_buf[name_buf_size-1] = '\0';
572 return strlen(name) + 1;
573 }
574 else {
575 return 0;
576 }
577 }
578 else {
579 t1_push_error();
580 return 0;
581 }
582}
583
584static void
585t1_push_error(void) {
73e3ff55
TC
586#if T1LIB_VERSION > 5 || T1LIB_VERSION == 5 && T1LIB_VERSION >= 1
587 /* I don't know when T1_StrError() was introduced, be conservative */
588 i_push_error(T1_errno, T1_StrError(T1_errno));
589#else
a556912d
TC
590 switch (T1_errno) {
591 case 0:
592 i_push_error(0, "No error");
593 break;
594
595#ifdef T1ERR_SCAN_FONT_FORMAT
596 case T1ERR_SCAN_FONT_FORMAT:
597 i_push_error(T1ERR_SCAN_FONT_FORMAT, "SCAN_FONT_FORMAT");
598 break;
599#endif
600
601#ifdef T1ERR_SCAN_FILE_OPEN_ERR
602 case T1ERR_SCAN_FILE_OPEN_ERR:
603 i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "SCAN_FILE_OPEN_ERR");
604 break;
605#endif
606
607#ifdef T1ERR_SCAN_OUT_OF_MEMORY
608 case T1ERR_SCAN_OUT_OF_MEMORY:
609 i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "SCAN_OUT_OF_MEMORY");
610 break;
611#endif
612
613#ifdef T1ERR_SCAN_ERROR
614 case T1ERR_SCAN_ERROR:
615 i_push_error(T1ERR_SCAN_ERROR, "SCAN_ERROR");
616 break;
617#endif
618
619#ifdef T1ERR_SCAN_FILE_EOF
620 case T1ERR_SCAN_FILE_EOF:
621 i_push_error(T1ERR_SCAN_FILE_EOF, "SCAN_FILE_EOF");
622 break;
623#endif
624
625#ifdef T1ERR_PATH_ERROR
626 case T1ERR_PATH_ERROR:
627 i_push_error(T1ERR_PATH_ERROR, "PATH_ERROR");
628 break;
629#endif
630
631#ifdef T1ERR_PARSE_ERROR
632 case T1ERR_PARSE_ERROR:
633 i_push_error(T1ERR_PARSE_ERROR, "PARSE_ERROR");
634 break;
635#endif
636
637#ifdef T1ERR_TYPE1_ABORT
638 case T1ERR_TYPE1_ABORT:
639 i_push_error(T1ERR_TYPE1_ABORT, "TYPE1_ABORT");
640 break;
641#endif
642
643#ifdef T1ERR_INVALID_FONTID
644 case T1ERR_INVALID_FONTID:
645 i_push_error(T1ERR_INVALID_FONTID, "INVALID_FONTID");
646 break;
647#endif
648
649#ifdef T1ERR_INVALID_PARAMETER
650 case T1ERR_INVALID_PARAMETER:
651 i_push_error(T1ERR_INVALID_PARAMETER, "INVALID_PARAMETER");
652 break;
653#endif
654
655#ifdef T1ERR_OP_NOT_PERMITTED
656 case T1ERR_OP_NOT_PERMITTED:
657 i_push_error(T1ERR_OP_NOT_PERMITTED, "OP_NOT_PERMITTED");
658 break;
659#endif
660
661#ifdef T1ERR_ALLOC_MEM
662 case T1ERR_ALLOC_MEM:
663 i_push_error(T1ERR_ALLOC_MEM, "ALLOC_MEM");
664 break;
665#endif
666
667#ifdef T1ERR_FILE_OPEN_ERR
668 case T1ERR_FILE_OPEN_ERR:
669 i_push_error(T1ERR_FILE_OPEN_ERR, "FILE_OPEN_ERR");
670 break;
671#endif
672
673#ifdef T1ERR_UNSPECIFIED
674 case T1ERR_UNSPECIFIED:
675 i_push_error(T1ERR_UNSPECIFIED, "UNSPECIFIED");
676 break;
677#endif
678
679#ifdef T1ERR_NO_AFM_DATA
680 case T1ERR_NO_AFM_DATA:
681 i_push_error(T1ERR_NO_AFM_DATA, "NO_AFM_DATA");
682 break;
683#endif
684
685#ifdef T1ERR_X11
686 case T1ERR_X11:
687 i_push_error(T1ERR_X11, "X11");
688 break;
689#endif
690
691#ifdef T1ERR_COMPOSITE_CHAR
692 case T1ERR_COMPOSITE_CHAR:
693 i_push_error(T1ERR_COMPOSITE_CHAR, "COMPOSITE_CHAR");
694 break;
695#endif
696
697 default:
698 i_push_errorf(T1_errno, "unknown error %d", (int)T1_errno);
699 }
73e3ff55 700#endif
a556912d
TC
701}
702