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