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 | ||
02d1d628 AMH |
10 | /* |
11 | =head1 NAME | |
12 | ||
13 | font.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 | ||
34 | font.c implements font creation, rendering, bounding box functions and | |
35 | more for Imager. | |
36 | ||
37 | =head1 FUNCTION REFERENCE | |
38 | ||
39 | Some 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 | ||
58 | Initialize font rendering libraries if they are avaliable. | |
59 | ||
60 | =cut | |
61 | */ | |
62 | ||
63 | undef_int | |
4cb58f1b | 64 | i_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 |
88 | static int t1_get_flags(char const *flags); |
89 | static 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 | |
94 | Initializes the t1lib font rendering engine. | |
95 | ||
96 | =cut | |
97 | */ | |
98 | ||
99 | undef_int | |
b33c08f8 | 100 | i_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 | ||
119 | Shuts the t1lib font rendering engine down. | |
120 | ||
121 | This it seems that this function is never used. | |
122 | ||
123 | =cut | |
124 | */ | |
125 | ||
126 | void | |
faa9b3e7 | 127 | i_close_t1(void) { |
02d1d628 AMH |
128 | T1_CloseLib(); |
129 | } | |
130 | ||
131 | ||
132 | /* | |
133 | =item i_t1_new(pfb, afm) | |
134 | ||
135 | Loads 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 | ||
143 | int | |
144 | i_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 | ||
165 | Frees resources for a t1 font with given font id. | |
166 | ||
167 | font_id - number of the font to free | |
168 | ||
169 | =cut | |
170 | */ | |
171 | ||
172 | int | |
173 | i_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 | ||
182 | Sets the antialiasing level of the t1 library. | |
183 | ||
184 | st - 0 = NONE, 1 = LOW, 2 = HIGH. | |
185 | ||
186 | =cut | |
187 | */ | |
188 | ||
189 | void | |
190 | i_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 | ||
219 | Interface 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 | ||
234 | undef_int | |
1bd75e4c | 235 | i_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 | ||
285 | function 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 | ||
297 | void | |
1bd75e4c | 298 | i_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 | ||
339 | Interface 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 | ||
354 | undef_int | |
1bd75e4c | 355 | i_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 | ||
401 | Processes the characters in I<flags> to create a mod_flags value used | |
402 | by some T1Lib functions. | |
403 | ||
404 | =cut | |
405 | */ | |
406 | static int | |
407 | t1_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 | ||
425 | Produces an unencoded version of I<in> by dropping any Unicode | |
426 | character over 255. | |
427 | ||
428 | Returns a newly allocated buffer which should be freed with myfree(). | |
429 | Sets *outlen to the number of bytes used in the output string. | |
430 | ||
431 | =cut | |
432 | */ | |
433 | ||
434 | static char * | |
435 | t1_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 |
471 | typedef 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 |
478 | struct 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 | 488 | typedef struct TT_Instancehandle_ TT_Instancehandle; |
02d1d628 | 489 | |
4f68b48f TC |
490 | struct 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 | ||
505 | static int i_tt_get_instance( TT_Fonthandle *handle, int points, int smooth ); | |
506 | static void i_tt_init_raster_map( TT_Raster_Map* bit, int width, int height, int smooth ); | |
507 | static void i_tt_done_raster_map( TT_Raster_Map *bit ); | |
508 | static void i_tt_clear_raster_map( TT_Raster_Map* bit ); | |
509 | static void i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,int x_off, int y_off ); | |
4f68b48f TC |
510 | static int i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j ); |
511 | static void | |
512 | i_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 ); | |
515 | static int | |
516 | i_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 |
519 | static void i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, i_color *cl, int smooth ); |
520 | static void i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, int xb, int yb, int channel, int smooth ); | |
4f68b48f TC |
521 | static int |
522 | i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6], | |
523 | float points, char const* txt, int len, int smooth, int utf8 ); | |
524 | static 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 | ||
529 | static TT_Engine engine; | |
530 | static int LTT_dpi = 72; /* FIXME: this ought to be a part of the call interface */ | |
531 | static int LTT_hinted = 1; /* FIXME: this too */ | |
532 | ||
533 | ||
534 | /* | |
535 | * FreeType interface | |
536 | */ | |
537 | ||
538 | ||
539 | /* | |
540 | =item init_tt() | |
541 | ||
542 | Initializes the freetype font rendering engine | |
543 | ||
544 | =cut | |
545 | */ | |
546 | ||
547 | undef_int | |
b33c08f8 | 548 | i_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 | ||
563 | Finds a points+smooth instance or if one doesn't exist in the cache | |
564 | allocates 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 | ||
574 | static | |
575 | int | |
576 | i_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 | ||
665 | Creates a new font handle object, finds a character map and initialise the | |
666 | the font handle's cache | |
667 | ||
668 | fontname - path to the font to load | |
669 | ||
670 | =cut | |
671 | */ | |
672 | ||
673 | TT_Fonthandle* | |
674 | i_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 |