fixed some minor test code hiccups
[imager.git] / font.c
CommitLineData
02d1d628
AMH
1#include "image.h"
2
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <fcntl.h>
6
7#include <stdio.h>
8#include <stdlib.h>
9
02d1d628
AMH
10/*
11=head1 NAME
12
13font.c - implements font handling functions for t1 and truetype fonts
14
15=head1 SYNOPSIS
16
17 i_init_fonts();
18
19 #ifdef HAVE_LIBT1
20 fontnum = i_t1_new(path_to_pfb, path_to_afm);
21 i_t1_bbox(fontnum, points, "foo", 3, int cords[6]);
22 rc = i_t1_destroy(fontnum);
23 #endif
24
25 #ifdef HAVE_LIBTT
26 handle = i_tt_new(path_to_ttf);
eeaa33fd 27 rc = i_tt_bbox(handle, points, "foo", 3, int cords[6], utf8);
02d1d628
AMH
28 i_tt_destroy(handle);
29
30 // and much more
31
32=head1 DESCRIPTION
33
34font.c implements font creation, rendering, bounding box functions and
35more for Imager.
36
37=head1 FUNCTION REFERENCE
38
39Some of these functions are internal.
40
b8c2033e 41=over
02d1d628
AMH
42
43=cut
44
45*/
46
47
48
49
50
51
52
53
54
55/*
56=item i_init_fonts()
57
58Initialize font rendering libraries if they are avaliable.
59
60=cut
61*/
62
63undef_int
4cb58f1b 64i_init_fonts(int t1log) {
02d1d628
AMH
65 mm_log((1,"Initializing fonts\n"));
66
67#ifdef HAVE_LIBT1
b33c08f8 68 i_init_t1(t1log);
02d1d628
AMH
69#endif
70
71#ifdef HAVE_LIBTT
b33c08f8 72 i_init_tt();
02d1d628
AMH
73#endif
74
faa9b3e7
TC
75#ifdef HAVE_FT2
76 if (!i_ft2_init())
77 return 0;
78#endif
79
02d1d628
AMH
80 return(1); /* FIXME: Always true - check the return values of the init_t1 and init_tt functions */
81}
82
83
84
85
86#ifdef HAVE_LIBT1
87
1bd75e4c
TC
88static int t1_get_flags(char const *flags);
89static char *t1_from_utf8(char const *in, int len, int *outlen);
02d1d628
AMH
90
91/*
4cb58f1b 92=item i_init_t1(t1log)
02d1d628
AMH
93
94Initializes the t1lib font rendering engine.
95
96=cut
97*/
98
99undef_int
b33c08f8 100i_init_t1(int t1log) {
4cb58f1b 101 int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE;
02d1d628 102 mm_log((1,"init_t1()\n"));
4cb58f1b
TC
103
104 if (t1log)
105 init_flags |= LOGFILE;
106 if ((T1_InitLib(init_flags) == NULL)){
02d1d628
AMH
107 mm_log((1,"Initialization of t1lib failed\n"));
108 return(1);
109 }
110 T1_SetLogLevel(T1LOG_DEBUG);
111 i_t1_set_aa(1); /* Default Antialias value */
112 return(0);
113}
114
115
116/*
117=item i_close_t1()
118
119Shuts the t1lib font rendering engine down.
120
121 This it seems that this function is never used.
122
123=cut
124*/
125
126void
faa9b3e7 127i_close_t1(void) {
02d1d628
AMH
128 T1_CloseLib();
129}
130
131
132/*
133=item i_t1_new(pfb, afm)
134
135Loads the fonts with the given filenames, returns its font id
136
137 pfb - path to pfb file for font
138 afm - path to afm file for font
139
140=cut
141*/
142
143int
144i_t1_new(char *pfb,char *afm) {
145 int font_id;
1bd75e4c 146
02d1d628
AMH
147 mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL")));
148 font_id = T1_AddFont(pfb);
149 if (font_id<0) {
150 mm_log((1,"i_t1_new: Failed to load pfb file '%s' - return code %d.\n",pfb,font_id));
151 return font_id;
152 }
153
154 if (afm != NULL) {
155 mm_log((1,"i_t1_new: requesting afm file '%s'.\n",afm));
156 if (T1_SetAfmFileName(font_id,afm)<0) mm_log((1,"i_t1_new: afm loading of '%s' failed.\n",afm));
157 }
1bd75e4c 158
02d1d628
AMH
159 return font_id;
160}
161
162/*
163=item i_t1_destroy(font_id)
164
165Frees resources for a t1 font with given font id.
166
167 font_id - number of the font to free
168
169=cut
170*/
171
172int
173i_t1_destroy(int font_id) {
174 mm_log((1,"i_t1_destroy(font_id %d)\n",font_id));
175 return T1_DeleteFont(font_id);
176}
177
178
179/*
180=item i_t1_set_aa(st)
181
182Sets the antialiasing level of the t1 library.
183
184 st - 0 = NONE, 1 = LOW, 2 = HIGH.
185
186=cut
187*/
188
189void
190i_t1_set_aa(int st) {
191 int i;
192 unsigned long cst[17];
193 switch(st) {
194 case 0:
195 T1_AASetBitsPerPixel( 8 );
196 T1_AASetLevel( T1_AA_NONE );
197 T1_AANSetGrayValues( 0, 255 );
198 mm_log((1,"setting T1 antialias to none\n"));
199 break;
200 case 1:
201 T1_AASetBitsPerPixel( 8 );
202 T1_AASetLevel( T1_AA_LOW );
203 T1_AASetGrayValues( 0,65,127,191,255 );
204 mm_log((1,"setting T1 antialias to low\n"));
205 break;
206 case 2:
207 T1_AASetBitsPerPixel(8);
208 T1_AASetLevel(T1_AA_HIGH);
209 for(i=0;i<17;i++) cst[i]=(i*255)/16;
210 T1_AAHSetGrayValues( cst );
211 mm_log((1,"setting T1 antialias to high\n"));
212 }
213}
214
215
216/*
217=item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align)
218
219Interface to text rendering into a single channel in an image
220
221 im pointer to image structure
222 xb x coordinate of start of string
223 yb y coordinate of start of string ( see align )
224 channel - destination channel
225 fontnum - t1 library font id
226 points - number of points in fontheight
227 str - string to render
228 len - string length
229 align - (0 - top of font glyph | 1 - baseline )
230
231=cut
232*/
233
234undef_int
1bd75e4c 235i_t1_cp(i_img *im,int xb,int yb,int channel,int fontnum,float points,char* str,int len,int align, int utf8, char const *flags) {
02d1d628
AMH
236 GLYPH *glyph;
237 int xsize,ysize,x,y;
238 i_color val;
1bd75e4c 239 int mod_flags = t1_get_flags(flags);
02d1d628
AMH
240
241 unsigned int ch_mask_store;
242
243 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
244
1bd75e4c
TC
245 if (utf8) {
246 int worklen;
247 char *work = t1_from_utf8(str, len, &worklen);
248 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
249 myfree(work);
250 }
251 else {
252 glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
253 }
faa9b3e7
TC
254 if (glyph == NULL)
255 return 0;
02d1d628
AMH
256
257 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
258 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
259 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
260 mm_log((1,"bpp: %d\n",glyph->bpp));
261
262 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
263 ysize=glyph->metrics.ascent-glyph->metrics.descent;
264
265 mm_log((1,"width: %d height: %d\n",xsize,ysize));
266
267 ch_mask_store=im->ch_mask;
268 im->ch_mask=1<<channel;
269
270 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
271
272 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
273 val.channel[channel]=glyph->bits[y*xsize+x];
274 i_ppix(im,x+xb,y+yb,&val);
275 }
276
277 im->ch_mask=ch_mask_store;
278 return 1;
279}
280
281
282/*
283=item i_t1_bbox(handle, fontnum, points, str, len, cords)
284
285function to get a strings bounding box given the font id and sizes
286
287 handle - pointer to font handle
288 fontnum - t1 library font id
289 points - number of points in fontheight
290 str - string to measure
291 len - string length
292 cords - the bounding box (modified in place)
293
294=cut
295*/
296
297void
1bd75e4c 298i_t1_bbox(int fontnum,float points,char *str,int len,int cords[6], int utf8,char const *flags) {
02d1d628
AMH
299 BBox bbox;
300 BBox gbbox;
1bd75e4c 301 int mod_flags = t1_get_flags(flags);
02d1d628
AMH
302
303 mm_log((1,"i_t1_bbox(fontnum %d,points %.2f,str '%.*s', len %d)\n",fontnum,points,len,str,len));
304 T1_LoadFont(fontnum); /* FIXME: Here a return code is ignored - haw haw haw */
1bd75e4c
TC
305 if (utf8) {
306 int worklen;
307 char *work = t1_from_utf8(str, len, &worklen);
308 bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
309 myfree(work);
310 }
311 else {
312 bbox = T1_GetStringBBox(fontnum,str,len,0,mod_flags);
313 }
02d1d628
AMH
314 gbbox = T1_GetFontBBox(fontnum);
315
316 mm_log((1,"bbox: (%d,%d,%d,%d)\n",
317 (int)(bbox.llx*points/1000),
318 (int)(gbbox.lly*points/1000),
319 (int)(bbox.urx*points/1000),
320 (int)(gbbox.ury*points/1000),
321 (int)(bbox.lly*points/1000),
322 (int)(bbox.ury*points/1000) ));
323
324
325 cords[0]=((float)bbox.llx*points)/1000;
326 cords[2]=((float)bbox.urx*points)/1000;
327
328 cords[1]=((float)gbbox.lly*points)/1000;
329 cords[3]=((float)gbbox.ury*points)/1000;
330
331 cords[4]=((float)bbox.lly*points)/1000;
332 cords[5]=((float)bbox.ury*points)/1000;
333}
334
335
336/*
337=item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align)
338
339Interface to text rendering in a single color onto an image
340
341 im - pointer to image structure
342 xb - x coordinate of start of string
343 yb - y coordinate of start of string ( see align )
344 cl - color to draw the text in
345 fontnum - t1 library font id
346 points - number of points in fontheight
347 str - char pointer to string to render
348 len - string length
349 align - (0 - top of font glyph | 1 - baseline )
350
351=cut
352*/
353
354undef_int
1bd75e4c 355i_t1_text(i_img *im,int xb,int yb,i_color *cl,int fontnum,float points,char* str,int len,int align, int utf8, char const *flags) {
02d1d628
AMH
356 GLYPH *glyph;
357 int xsize,ysize,x,y,ch;
358 i_color val;
359 unsigned char c,i;
1bd75e4c 360 int mod_flags = t1_get_flags(flags);
02d1d628
AMH
361
362 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
363
1bd75e4c
TC
364 if (utf8) {
365 int worklen;
366 char *work = t1_from_utf8(str, len, &worklen);
367 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
368 myfree(work);
369 }
370 else {
371 glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
372 }
faa9b3e7
TC
373 if (glyph == NULL)
374 return 0;
02d1d628
AMH
375
376 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
377 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
378 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
379 mm_log((1,"bpp: %d\n",glyph->bpp));
380
381 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
382 ysize=glyph->metrics.ascent-glyph->metrics.descent;
383
384 mm_log((1,"width: %d height: %d\n",xsize,ysize));
385
386 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
387
388 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
389 c=glyph->bits[y*xsize+x];
390 i=255-c;
391 i_gpix(im,x+xb,y+yb,&val);
392 for(ch=0;ch<im->channels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255;
393 i_ppix(im,x+xb,y+yb,&val);
394 }
395 return 1;
396}
397
1bd75e4c
TC
398/*
399=item t1_get_flags(flags)
400
401Processes the characters in I<flags> to create a mod_flags value used
402by some T1Lib functions.
403
404=cut
405 */
406static int
407t1_get_flags(char const *flags) {
408 int mod_flags = T1_KERNING;
409
410 while (*flags) {
411 switch (*flags++) {
412 case 'u': case 'U': mod_flags |= T1_UNDERLINE; break;
413 case 'o': case 'O': mod_flags |= T1_OVERLINE; break;
414 case 's': case 'S': mod_flags |= T1_OVERSTRIKE; break;
415 /* ignore anything we don't recognize */
416 }
417 }
418
419 return mod_flags;
420}
421
422/*
423=item t1_from_utf8(char const *in, int len, int *outlen)
424
425Produces an unencoded version of I<in> by dropping any Unicode
426character over 255.
427
428Returns a newly allocated buffer which should be freed with myfree().
429Sets *outlen to the number of bytes used in the output string.
430
431=cut
432*/
433
434static char *
435t1_from_utf8(char const *in, int len, int *outlen) {
436 char *out = mymalloc(len+1);
437 char *p = out;
438 unsigned long c;
439
440 while (len) {
441 c = i_utf8_advance(&in, &len);
442 if (c == ~0UL) {
443 myfree(out);
444 i_push_error(0, "invalid UTF8 character");
445 return 0;
446 }
447 /* yeah, just drop them */
448 if (c < 0x100) {
449 *p++ = (char)c;
450 }
451 }
452 *p = '\0';
453 *outlen = p - out;
454
455 return out;
456}
02d1d628
AMH
457
458#endif /* HAVE_LIBT1 */
459
460
4f68b48f 461/* Truetype font support */
02d1d628 462
4f68b48f 463#ifdef HAVE_LIBTT
02d1d628 464
4f68b48f
TC
465#include <freetype.h>
466#define TT_CHC 5
02d1d628 467
4f68b48f
TC
468/* convert a code point into an index in the glyph cache */
469#define TT_HASH(x) ((x) & 0xFF)
02d1d628 470
4f68b48f
TC
471typedef struct i_glyph_entry_ {
472 TT_Glyph glyph;
473 unsigned long ch;
474} i_tt_glyph_entry;
02d1d628 475
4f68b48f 476#define TT_NOCHAR (~0UL)
02d1d628 477
4f68b48f
TC
478struct TT_Instancehandle_ {
479 TT_Instance instance;
480 TT_Instance_Metrics imetrics;
481 TT_Glyph_Metrics gmetrics[256];
482 i_tt_glyph_entry glyphs[256];
483 int smooth;
484 int ptsize;
485 int order;
486};
02d1d628 487
4f68b48f 488typedef struct TT_Instancehandle_ TT_Instancehandle;
02d1d628 489
4f68b48f
TC
490struct TT_Fonthandle_ {
491 TT_Face face;
492 TT_Face_Properties properties;
493 TT_Instancehandle instanceh[TT_CHC];
494 TT_CharMap char_map;
495};
02d1d628
AMH
496
497/* Defines */
498
499#define USTRCT(x) ((x).z)
500#define TT_VALID( handle ) ( ( handle ).z != NULL )
501
502
503/* Prototypes */
504
505static int i_tt_get_instance( TT_Fonthandle *handle, int points, int smooth );
506static void i_tt_init_raster_map( TT_Raster_Map* bit, int width, int height, int smooth );
507static void i_tt_done_raster_map( TT_Raster_Map *bit );
508static void i_tt_clear_raster_map( TT_Raster_Map* bit );
509static void i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,int x_off, int y_off );
4f68b48f
TC
510static int i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j );
511static void
512i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics,
513 TT_Raster_Map *bit, TT_Raster_Map *small_bit,
514 int x_off, int y_off, int smooth );
515static int
516i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit,
517 TT_Raster_Map *small_bit, int cords[6],
518 char const* txt, int len, int smooth, int utf8 );
02d1d628
AMH
519static void i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, i_color *cl, int smooth );
520static void i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, int xb, int yb, int channel, int smooth );
4f68b48f
TC
521static int
522i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6],
523 float points, char const* txt, int len, int smooth, int utf8 );
524static undef_int i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int cords[6], int utf8 );
02d1d628
AMH
525
526
527/* static globals needed */
528
529static TT_Engine engine;
530static int LTT_dpi = 72; /* FIXME: this ought to be a part of the call interface */
531static int LTT_hinted = 1; /* FIXME: this too */
532
533
534/*
535 * FreeType interface
536 */
537
538
539/*
540=item init_tt()
541
542Initializes the freetype font rendering engine
543
544=cut
545*/
546
547undef_int
b33c08f8 548i_init_tt() {
02d1d628
AMH
549 TT_Error error;
550 mm_log((1,"init_tt()\n"));
551 error = TT_Init_FreeType( &engine );
552 if ( error ){
553 mm_log((1,"Initialization of freetype failed, code = 0x%x\n",error));
554 return(1);
555 }
556 return(0);
557}
558
559
560/*
561=item i_tt_get_instance(handle, points, smooth)
562
563Finds a points+smooth instance or if one doesn't exist in the cache
564allocates room and returns its cache entry
565
566 fontname - path to the font to load
567 handle - handle to the font.
568 points - points of the requested font
569 smooth - boolean (True: antialias on, False: antialias is off)
570
571=cut
572*/
573
574static
575int
576i_tt_get_instance( TT_Fonthandle *handle, int points, int smooth ) {
577 int i,idx;
578 TT_Error error;
579
4f68b48f
TC
580 mm_log((1,"i_tt_get_instance(handle 0x%X, points %d, smooth %d)\n",
581 handle,points,smooth));
02d1d628
AMH
582
583 if (smooth == -1) { /* Smooth doesn't matter for this search */
4f68b48f
TC
584 for(i=0;i<TT_CHC;i++) {
585 if (handle->instanceh[i].ptsize==points) {
586 mm_log((1,"i_tt_get_instance: in cache - (non selective smoothing search) returning %d\n",i));
587 return i;
588 }
02d1d628
AMH
589 }
590 smooth=1; /* We will be adding a font - add it as smooth then */
591 } else { /* Smooth doesn't matter for this search */
4f68b48f
TC
592 for(i=0;i<TT_CHC;i++) {
593 if (handle->instanceh[i].ptsize == points
594 && handle->instanceh[i].smooth == smooth) {
595 mm_log((1,"i_tt_get_instance: in cache returning %d\n",i));
596 return i;
597 }
02d1d628
AMH
598 }
599 }
600
601 /* Found the instance in the cache - return the cache index */
602
4f68b48f
TC
603 for(idx=0;idx<TT_CHC;idx++) {
604 if (!(handle->instanceh[idx].order)) break; /* find the lru item */
605 }
02d1d628
AMH
606
607 mm_log((1,"i_tt_get_instance: lru item is %d\n",idx));
4f68b48f
TC
608 mm_log((1,"i_tt_get_instance: lru pointer 0x%X\n",
609 USTRCT(handle->instanceh[idx].instance) ));
02d1d628
AMH
610
611 if ( USTRCT(handle->instanceh[idx].instance) ) {
612 mm_log((1,"i_tt_get_instance: freeing lru item from cache %d\n",idx));
93d0372f 613
4f68b48f 614 /* Free cached glyphs */
93d0372f 615 for(i=0;i<256;i++)
4f68b48f
TC
616 if ( USTRCT(handle->instanceh[idx].glyphs[i].glyph) )
617 TT_Done_Glyph( handle->instanceh[idx].glyphs[i].glyph );
93d0372f 618
4f68b48f
TC
619 for(i=0;i<256;i++) {
620 handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR;
621 USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL;
622 }
623
624 /* Free instance if needed */
625 TT_Done_Instance( handle->instanceh[idx].instance );
02d1d628
AMH
626 }
627
628 /* create and initialize instance */
629 /* FIXME: probably a memory leak on fail */
630
631 (void) (( error = TT_New_Instance( handle->face, &handle->instanceh[idx].instance ) ) ||
632 ( error = TT_Set_Instance_Resolutions( handle->instanceh[idx].instance, LTT_dpi, LTT_dpi ) ) ||
633 ( error = TT_Set_Instance_CharSize( handle->instanceh[idx].instance, points*64 ) ) );
634
635 if ( error ) {
636 mm_log((1, "Could not create and initialize instance: error 0x%x.\n",error ));
637 return -1;
638 }
639
640 /* Now that the instance should the inplace we need to lower all of the
641 ru counts and put `this' one with the highest entry */
642
643 for(i=0;i<TT_CHC;i++) handle->instanceh[i].order--;
644
645 handle->instanceh[idx].order=TT_CHC-1;
646 handle->instanceh[idx].ptsize=points;
647 handle->instanceh[idx].smooth=smooth;
648 TT_Get_Instance_Metrics( handle->instanceh[idx].instance, &(handle->instanceh[idx].imetrics) );
649
4f68b48f
TC
650 /* Zero the memory for the glyph storage so they are not thought as
651 cached if they haven't been cached since this new font was loaded */
02d1d628 652
4f68b48f
TC
653 for(i=0;i<256;i++) {
654 handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR;
655 USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL;
656 }
02d1d628
AMH
657
658 return idx;
659}
660
661
662/*
663=item i_tt_new(fontname)
664
665Creates a new font handle object, finds a character map and initialise the
666the font handle's cache
667
668 fontname - path to the font to load
669
670=cut
671*/
672
673TT_Fonthandle*
674i_tt_new(char *fontname) {
675 TT_Error error;
676 TT_Fonthandle *handle;
677 unsigned short i,n;
678 unsigned short platform,encoding;
679
680 mm_log((1,"i_tt_new(fontname '%s')\n",fontname));
681
682 /* allocate memory for the structure */
683
4b19f77a 684 handle = mymalloc( sizeof(TT_Fonthandle) );
02d1d628
AMH
685
686 /* load the typeface */
687 error = TT_Open_Face( engine, fontname, &handle->face );
688 if ( error ) {
4f68b48f
TC
689 if ( error == TT_Err_Could_Not_Open_File ) {
690 mm_log((1, "Could not find/open %s.\n", fontname ));
691 }
692 else {
693 mm_log((1, "Error while opening %s, error code = 0x%x.\n",fontname,
694 error ));
695 }
02d1d628
AMH
696 return NULL;
697 }
698
699 TT_Get_Face_Properties( handle->face, &(handle->properties) );
4f68b48f 700
02d1d628 701 /* First, look for a Unicode charmap */
02d1d628
AMH
702 n = handle->properties.num_CharMaps;
703 USTRCT( handle->char_map )=NULL; /* Invalidate character map */
704
705 for ( i = 0; i < n; i++ ) {
706 TT_Get_CharMap_ID( handle->face, i, &platform, &encoding );
4f68b48f
TC
707 if ( (platform == 3 && encoding == 1 )
708 || (platform == 0 && encoding == 0 ) ) {
709 mm_log((2,"i_tt_new - found char map platform %u encoding %u\n",
710 platform, encoding));
02d1d628
AMH
711 TT_Get_CharMap( handle->face, i, &(handle->char_map) );
712 break;
713 }
714 }
27e79497
TC
715 if (!USTRCT(handle->char_map) && n != 0) {
716 /* just use the first one */
717 TT_Get_CharMap( handle->face, 0, &(handle->char_map));
718 }
02d1d628
AMH
719
720 /* Zero the pointsizes - and ordering */
721
722 for(i=0;i<TT_CHC;i++) {
723 USTRCT(handle->instanceh[i].instance)=NULL;
724 handle->instanceh[i].order=i;
725 handle->instanceh[i].ptsize=0;
726 handle->instanceh[i].smooth=-1;
727 }
728
729 mm_log((1,"i_tt_new <- 0x%X\n",handle));
730 return handle;
731}
732
733
734
735/*
736