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);
12 static int t1_active_fonts = 0;
13 static int t1_initialized = 0;
16 struct i_t1_font_tag {
20 static i_mutex_t mutex;
25 Initialize the font driver. This does not actually initialize T1Lib,
26 it just allocates the mutex we use to gate access to it.
33 mutex = i_mutex_new();
37 =item i_init_t1(t1log)
39 Initializes the t1lib font rendering engine.
45 i_init_t1(int t1log) {
49 result = i_init_t1_low(t1log);
51 i_mutex_unlock(mutex);
57 i_init_t1_low(int t1log) {
58 int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE;
60 mm_log((1,"init_t1(%d)\n", t1log));
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");
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");
82 T1_SetLogLevel(T1LOG_DEBUG);
92 Shuts the t1lib font rendering engine down.
94 This it seems that this function is never used.
104 i_mutex_unlock(mutex);
109 =item i_t1_new(pfb, afm)
111 Loads the fonts with the given filenames, returns its font id
113 pfb - path to pfb file for font
114 afm - path to afm file for font
120 i_t1_new(char *pfb,char *afm) {
128 if (!t1_initialized && i_init_t1_low(0)) {
129 i_mutex_unlock(mutex);
133 mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL")));
134 font_id = T1_AddFont(pfb);
136 mm_log((1,"i_t1_new: Failed to load pfb file '%s' - return code %d.\n",pfb,font_id));
138 i_mutex_unlock(mutex);
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));
147 if (T1_LoadFont(font_id)) {
148 mm_log((1, "i_t1_new() -> -1 - T1_LoadFont failed (%d)\n", T1_errno));
150 i_push_error(0, "loading font");
151 T1_DeleteFont(font_id);
152 i_mutex_unlock(mutex);
158 i_mutex_unlock(mutex);
160 font = mymalloc(sizeof(*font));
161 font->font_id = font_id;
163 mm_log((1, "i_t1_new() -> %p (%d)\n", font, font_id));
169 =item i_t1_destroy(font)
171 Frees resources for a t1 font with given font id.
179 i_t1_destroy(i_t1_font_t font) {
184 mm_log((1,"i_t1_destroy(font %p (%d))\n", font, font->font_id));
188 result = T1_DeleteFont(font->font_id);
191 i_mutex_unlock(mutex);
198 =item i_t1_set_aa(st)
200 Sets the antialiasing level of the t1 library.
202 st - 0 = NONE, 1 = LOW, 2 = HIGH.
204 Must be called with the mutex locked.
210 i_t1_set_aa(int st) {
212 unsigned long cst[17];
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"));
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"));
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"));
243 =item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align,aa)
245 Interface to text rendering into a single channel in an image
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
255 align - (0 - top of font glyph | 1 - baseline )
256 aa - anti-aliasing level
262 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) {
266 int mod_flags = t1_get_flags(flags);
267 int fontnum = font->font_id;
269 unsigned int ch_mask_store;
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));
277 mm_log((1,"i_t1_cp: Null image in input\n"));
278 i_push_error(0, "null image");
288 char *work = t1_from_utf8(str, len, &worklen);
289 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
293 glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
297 i_push_error(0, "i_t1_cp: T1_AASetString failed");
298 i_mutex_unlock(mutex);
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));
305 mm_log((1,"bpp: %lu\n", (unsigned long)glyph->bpp));
307 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
308 ysize=glyph->metrics.ascent-glyph->metrics.descent;
310 mm_log((1,"width: %d height: %d\n",xsize,ysize));
312 ch_mask_store=im->ch_mask;
313 im->ch_mask=1<<channel;
315 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
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);
322 im->ch_mask=ch_mask_store;
324 i_mutex_unlock(mutex);
330 t1_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)
335 if (str[len-1] == space_position && bbox->urx < advance)
337 if (bbox->lly > bbox->ury)
338 bbox->lly = bbox->ury = 0;
342 =item i_t1_bbox(handle, fontnum, points, str, len, cords)
344 function to get a strings bounding box given the font id and sizes
346 handle - pointer to font handle
347 fontnum - t1 library font id
348 points - number of points in fontheight
349 str - string to measure
351 cords - the bounding box (modified in place)
357 i_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) {
360 int mod_flags = t1_get_flags(flags);
362 int fontnum = font->font_id;
367 space_position = T1_GetEncodingIndex(fontnum, "space");
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));
371 T1_LoadFont(fontnum); /* FIXME: Here a return code is ignored - haw haw haw */
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;
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);
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);
394 gbbox = T1_GetFontBBox(fontnum);
396 mm_log((1,"bbox: (%d, %d, %d, %d, %d, %d)\n",
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) ));
405 cords[BBOX_NEG_WIDTH]=((double)bbox.llx*points)/1000;
406 cords[BBOX_POS_WIDTH]=((double)bbox.urx*points)/1000;
408 cords[BBOX_GLOBAL_DESCENT]=((double)gbbox.lly*points)/1000;
409 cords[BBOX_GLOBAL_ASCENT]=((double)gbbox.ury*points)/1000;
411 cords[BBOX_DESCENT]=((double)bbox.lly*points)/1000;
412 cords[BBOX_ASCENT]=((double)bbox.ury*points)/1000;
414 cords[BBOX_ADVANCE_WIDTH] = ((double)advance * points)/1000;
415 cords[BBOX_RIGHT_BEARING] =
416 cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH];
418 i_mutex_unlock(mutex);
420 return BBOX_RIGHT_BEARING+1;
425 =item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align, aa)
427 Interface to text rendering in a single color onto an image
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
437 align - (0 - top of font glyph | 1 - baseline )
438 aa - anti-aliasing level
444 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) {
447 int mod_flags = t1_get_flags(flags);
449 int fontnum = font->font_id;
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));
457 i_push_error(0, "null image");
458 mm_log((1,"i_t1_text: Null image in input\n"));
468 char *work = t1_from_utf8(str, len, &worklen);
469 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
473 /* T1_AASetString() accepts a char * not a const char */
474 glyph=T1_AASetString( fontnum, (char *)str, len, 0, mod_flags, points, NULL);
477 mm_log((1, "T1_AASetString failed\n"));
479 i_push_error(0, "i_t1_text(): T1_AASetString failed");
480 i_mutex_unlock(mutex);
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));
487 mm_log((1,"bpp: %lu\n",(unsigned long)glyph->bpp));
489 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
490 ysize=glyph->metrics.ascent-glyph->metrics.descent;
492 mm_log((1,"width: %d height: %d\n",xsize,ysize));
494 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
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);
502 i_mutex_unlock(mutex);
508 =item t1_get_flags(flags)
510 Processes the characters in I<flags> to create a mod_flags value used
511 by some T1Lib functions.
516 t1_get_flags(char const *flags) {
517 int mod_flags = T1_KERNING;
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 */
532 =item t1_from_utf8(char const *in, size_t len, int *outlen)
534 Produces an unencoded version of I<in> by dropping any Unicode
537 Returns a newly allocated buffer which should be freed with myfree().
538 Sets *outlen to the number of bytes used in the output string.
544 t1_from_utf8(char const *in, size_t len, int *outlen) {
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 */
552 c = i_utf8_advance(&in, &len);
555 i_push_error(0, "invalid UTF8 character");
558 /* yeah, just drop them */
570 =item i_t1_has_chars(font_num, text, len, utf8, out)
572 Check if the given characters are defined by the font. Note that len
573 is the number of bytes, not the number of characters (when utf8 is
576 out[char index] will be true if the character exists.
578 Accepts UTF-8, but since T1 can only have 256 characters, any chars
579 with values over 255 will simply be returned as false.
581 Returns the number of characters that were checked.
587 i_t1_has_chars(i_t1_font_t font, const char *text, size_t len, int utf8,
590 int font_num = font->font_id;
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));
598 if (T1_LoadFont(font_num)) {
600 i_mutex_unlock(mutex);
607 c = i_utf8_advance(&text, &len);
609 i_push_error(0, "invalid UTF8 character");
610 i_mutex_unlock(mutex);
615 c = (unsigned char)*text++;
620 /* limit of 256 characters for T1 */
624 char const * name = T1_GetCharName(font_num, (unsigned char)c);
627 *out++ = strcmp(name, ".notdef") != 0;
630 mm_log((2, " No name found for character %lx\n", c));
637 i_mutex_unlock(mutex);
643 =item i_t1_face_name(font, name_buf, name_buf_size)
645 Copies the face name of the given C<font_num> to C<name_buf>. Returns
646 the number of characters required to store the name (which can be
647 larger than C<name_buf_size>, including the space required to store
648 the terminating NUL).
650 If name_buf is too small (as specified by name_buf_size) then the name
651 will be truncated. name_buf will always be NUL termintaed.
657 i_t1_face_name(i_t1_font_t font, char *name_buf, size_t name_buf_size) {
659 int font_num = font->font_id;
664 if (T1_LoadFont(font_num)) {
666 i_mutex_unlock(mutex);
669 name = T1_GetFontName(font_num);
672 size_t len = strlen(name);
673 strncpy(name_buf, name, name_buf_size);
674 name_buf[name_buf_size-1] = '\0';
675 i_mutex_unlock(mutex);
680 i_mutex_unlock(mutex);
686 i_t1_glyph_name(i_t1_font_t font, unsigned long ch, char *name_buf,
687 size_t name_buf_size) {
689 int font_num = font->font_id;
694 i_mutex_unlock(mutex);
697 if (T1_LoadFont(font_num)) {
699 i_mutex_unlock(mutex);
702 name = T1_GetCharName(font_num, (unsigned char)ch);
704 if (strcmp(name, ".notdef")) {
705 size_t len = strlen(name);
706 strncpy(name_buf, name, name_buf_size);
707 name_buf[name_buf_size-1] = '\0';
708 i_mutex_unlock(mutex);
712 i_mutex_unlock(mutex);
718 i_mutex_unlock(mutex);
724 t1_push_error(void) {
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));
731 i_push_error(0, "No error");
734 #ifdef T1ERR_SCAN_FONT_FORMAT
735 case T1ERR_SCAN_FONT_FORMAT:
736 i_push_error(T1ERR_SCAN_FONT_FORMAT, "Attempt to Load Multiple Master Font");
740 #ifdef T1ERR_SCAN_FILE_OPEN_ERR
741 case T1ERR_SCAN_FILE_OPEN_ERR:
742 i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "Type 1 Font File Open Error");
746 #ifdef T1ERR_SCAN_OUT_OF_MEMORY
747 case T1ERR_SCAN_OUT_OF_MEMORY:
748 i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "Virtual Memory Exceeded");
752 #ifdef T1ERR_SCAN_ERROR
753 case T1ERR_SCAN_ERROR:
754 i_push_error(T1ERR_SCAN_ERROR, "Syntactical Error Scanning Font File");
758 #ifdef T1ERR_SCAN_FILE_EOF
759 case T1ERR_SCAN_FILE_EOF:
760 i_push_error(T1ERR_SCAN_FILE_EOF, "Premature End of Font File Encountered");
764 #ifdef T1ERR_PATH_ERROR
765 case T1ERR_PATH_ERROR:
766 i_push_error(T1ERR_PATH_ERROR, "Path Construction Error");
770 #ifdef T1ERR_PARSE_ERROR
771 case T1ERR_PARSE_ERROR:
772 i_push_error(T1ERR_PARSE_ERROR, "Font is Corrupt");
776 #ifdef T1ERR_TYPE1_ABORT
777 case T1ERR_TYPE1_ABORT:
778 i_push_error(T1ERR_TYPE1_ABORT, "Rasterization Aborted");
782 #ifdef T1ERR_INVALID_FONTID
783 case T1ERR_INVALID_FONTID:
784 i_push_error(T1ERR_INVALID_FONTID, "Font ID Invalid in this Context");
788 #ifdef T1ERR_INVALID_PARAMETER
789 case T1ERR_INVALID_PARAMETER:
790 i_push_error(T1ERR_INVALID_PARAMETER, "Invalid Argument in Function Call");
794 #ifdef T1ERR_OP_NOT_PERMITTED
795 case T1ERR_OP_NOT_PERMITTED:
796 i_push_error(T1ERR_OP_NOT_PERMITTED, "Operation not Permitted");
800 #ifdef T1ERR_ALLOC_MEM
801 case T1ERR_ALLOC_MEM:
802 i_push_error(T1ERR_ALLOC_MEM, "Memory Allocation Error");
806 #ifdef T1ERR_FILE_OPEN_ERR
807 case T1ERR_FILE_OPEN_ERR:
808 i_push_error(T1ERR_FILE_OPEN_ERR, "Error Opening File");
812 #ifdef T1ERR_UNSPECIFIED
813 case T1ERR_UNSPECIFIED:
814 i_push_error(T1ERR_UNSPECIFIED, "Unspecified T1Lib Error");
818 #ifdef T1ERR_NO_AFM_DATA
819 case T1ERR_NO_AFM_DATA:
820 i_push_error(T1ERR_NO_AFM_DATA, "Missing AFM Data");
826 i_push_error(T1ERR_X11, "X11 Interface Error");
830 #ifdef T1ERR_COMPOSITE_CHAR
831 case T1ERR_COMPOSITE_CHAR:
832 i_push_error(T1ERR_COMPOSITE_CHAR, "Missing Component of Composite Character");
836 #ifdef T1ERR_SCAN_ENCODING
837 case T1ERR_SCAN_ENCODING:
838 i_push_error(T1ERR_SCAN_ENCODING, "Error Scanning Encoding File");
843 i_push_errorf(T1_errno, "unknown error %d", (int)T1_errno);