2 * Copyright (C) 2000, Matias Atria
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #ifdef WITH_TRUETYPE_FONTS
30 static TT_Engine tt_handle;
31 static int initialized = 0;
33 typedef struct ftinfo {
45 DviFontMapInfo mapinfo;
46 DviEncoding *encoding;
49 static int tt_load_font __PROTO((DviParams *, DviFont *));
50 static int tt_font_get_glyph __PROTO((DviParams *, DviFont *, int));
51 static void tt_free_data __PROTO((DviFont *));
52 static void tt_reset_font __PROTO((DviFont *));
53 static void tt_shrink_glyph
54 __PROTO((DviContext *, DviFont *, DviFontChar *, DviGlyph *));
55 static void tt_font_remove __PROTO((FTInfo *));
57 DviFontInfo tt_font_info = {
63 mdvi_shrink_glyph_grey,
64 tt_free_data, /* free */
65 tt_reset_font, /* reset */
71 #define FT_HASH_SIZE 31
73 static ListHead ttfonts = {NULL, NULL, 0};
75 static int init_freetype(void)
79 ASSERT(initialized == 0);
80 code = TT_Init_FreeType(&tt_handle);
82 DEBUG((DBG_TT, "(tt) Init_Freetype: error %d\n", code));
85 code = TT_Init_Post_Extension(tt_handle);
87 TT_Done_FreeType(tt_handle);
95 static void tt_encode_font(DviFont *font, FTInfo *info)
97 TT_Face_Properties prop;
100 if(TT_Get_Face_Properties(info->face, &prop))
103 for(i = 0; i < prop.num_Glyphs; i++) {
107 if(TT_Get_PS_Name(info->face, i, &string))
109 ndx = mdvi_encode_glyph(info->encoding, string);
110 if(ndx < font->loc || ndx > font->hic)
112 font->chars[ndx - font->loc].code = i;
116 static int tt_really_load_font(DviParams *params, DviFont *font, FTInfo *info)
120 Int32 z, alpha, beta;
125 static int warned = 0;
127 TT_Face_Properties props;
130 DEBUG((DBG_TT, "(tt) really_load_font(%s)\n", info->fontname));
132 /* get the point size */
133 point_size = (double)font->scale / (params->tfm_conv * 0x100000);
134 point_size = 72.0 * point_size / 72.27;
136 /* just reset the size info */
137 TT_Set_Instance_Resolutions(info->instance,
138 params->dpi, params->vdpi);
139 TT_Set_Instance_CharSize(info->instance, FROUND(point_size * 64));
140 /* FIXME: should extend/slant again */
141 info->hasmetrics = 1;
146 DEBUG((DBG_TT, "(tt) loading new face `%s'\n",
148 status = TT_Open_Face(tt_handle, font->filename, &info->face);
150 warning(_("(tt) %s: could not load face: %s\n"),
151 info->fontname, TT_ErrToString18(status));
155 /* create a new instance of this face */
156 status = TT_New_Instance(info->face, &info->instance);
158 warning(_("(tt) %s: could not create face: %s\n"),
159 info->fontname, TT_ErrToString18(status));
160 TT_Close_Face(info->face);
165 status = TT_New_Glyph(info->face, &info->glyph);
167 warning(_("(tt) %s: could not create glyph: %s\n"),
168 info->fontname, TT_ErrToString18(status));
173 * We'll try to find a Unicode charmap. It's not that important that we
174 * actually find one, especially if the fontmap files are installed
175 * properly, but it's good to have some predefined behaviour
177 TT_Get_Face_Properties(info->face, &props);
180 for(i = 0; map_found < 0 && i < props.num_CharMaps; i++) {
183 TT_Get_CharMap_ID(info->face, i, &pid, &eid);
185 case TT_PLATFORM_APPLE_UNICODE:
188 case TT_PLATFORM_ISO:
189 if(eid == TT_ISO_ID_7BIT_ASCII ||
190 eid == TT_ISO_ID_8859_1)
193 case TT_PLATFORM_MICROSOFT:
194 if(eid == TT_MS_ID_UNICODE_CS)
200 warning(_("(tt) %s: no acceptable map found, using #0\n"),
204 DEBUG((DBG_TT, "(tt) %s: using charmap #%d\n",
205 info->fontname, map_found));
206 TT_Get_CharMap(info->face, map_found, &cmap);
208 DEBUG((DBG_TT, "(tt) %s: Set_Char_Size(%.2f, %d, %d)\n",
209 font->fontname, point_size, font->hdpi, font->vdpi));
210 status = TT_Set_Instance_Resolutions(info->instance,
211 params->dpi, params->vdpi);
213 error(_("(tt) %s: could not set resolution: %s\n"),
214 info->fontname, TT_ErrToString18(status));
217 status = TT_Set_Instance_CharSize(info->instance,
218 FROUND(point_size * 64));
220 error(_("(tt) %s: could not set point size: %s\n"),
221 info->fontname, TT_ErrToString18(status));
225 /* after this point we don't fail */
227 /* get information from the fontmap */
228 status = mdvi_query_fontmap(&info->mapinfo, info->fontname);
229 if(!status && info->mapinfo.encoding)
230 info->encoding = mdvi_request_encoding(info->mapinfo.encoding);
232 info->encoding = NULL;
234 if(info->encoding != NULL) {
237 status = TT_Load_PS_Names(info->face, &post);
239 warning(_("(tt) %s: could not load PS name table\n"),
241 mdvi_release_encoding(info->encoding, 0);
242 info->encoding = NULL;
246 /* get the metrics. If this fails, it's not fatal, but certainly bad */
247 info->tfminfo = get_font_metrics(info->fontname,
248 info->fmftype, info->fmfname);
250 if(info->tfminfo == NULL) {
251 warning("(tt) %s: no metrics data, font ignored\n",
256 font->design = info->tfminfo->design;
258 /* get the scaled character metrics */
259 get_tfm_chars(params, font, info->tfminfo, 0);
262 tt_encode_font(font, info);
264 warning(_("%s: no encoding vector found, expect bad output\n"),
266 /* this is better than nothing */
267 for(i = font->loc; i <= font->hic; i++)
268 font->chars[i - font->loc].code = TT_Char_Index(cmap, i);
272 info->hasmetrics = 1;
276 tt_font_remove(info);
277 mdvi_free(font->chars);
279 font->loc = font->hic = 0;
283 static int tt_load_font(DviParams *params, DviFont *font)
288 if(!initialized && init_freetype() < 0)
291 if(font->in != NULL) {
296 info = xalloc(FTInfo);
298 memzero(info, sizeof(FTInfo));
299 info->fmftype = DviFontAny; /* any metrics type will do */
300 info->fmfname = lookup_font_metrics(font->fontname, &info->fmftype);
301 info->fontname = font->fontname;
302 info->hasmetrics = 0;
305 /* these will be obtained from the fontmaps */
306 info->mapinfo.psname = NULL;
307 info->mapinfo.encoding = NULL;
308 info->mapinfo.fontfile = NULL;
309 info->mapinfo.extend = 0;
310 info->mapinfo.slant = 0;
312 /* initialize these */
313 font->chars = xnalloc(DviFontChar, 256);
316 for(i = 0; i < 256; i++) {
317 font->chars[i].offset = 1;
318 font->chars[i].glyph.data = NULL;
319 font->chars[i].shrunk.data = NULL;
320 font->chars[i].grey.data = NULL;
323 if(info->fmfname == NULL)
324 warning(_("(tt) %s: no font metric data\n"), font->fontname);
326 listh_append(&ttfonts, LIST(info));
327 font->private = info;
332 static int tt_get_bitmap(DviParams *params, DviFont *font,
333 int code, double xscale, double yscale, DviGlyph *glyph)
336 TT_Raster_Map raster;
338 TT_Glyph_Metrics metrics;
342 int have_outline = 0;
345 info = (FTInfo *)font->private;
349 error = TT_Load_Glyph(info->instance, info->glyph,
350 code, TTLOAD_DEFAULT);
351 if(error) goto tt_error;
352 error = TT_Get_Glyph_Outline(info->glyph, &outline);
353 if(error) goto tt_error;
355 mat.xx = FROUND(xscale * 65536);
356 mat.yy = FROUND(yscale * 65536);
359 TT_Transform_Outline(&outline, &mat);
360 error = TT_Get_Outline_BBox(&outline, &bbox);
361 if(error) goto tt_error;
364 bbox.xMax = (bbox.xMax + 63) & -64;
365 bbox.yMax = (bbox.yMax + 63) & -64;
366 w = (bbox.xMax - bbox.xMin) / 64;
367 h = (bbox.yMax - bbox.yMin) / 64;
371 glyph->x = -bbox.xMin / 64;
372 glyph->y = bbox.yMax / 64;
377 raster.cols = ROUND(w, 8);
378 raster.size = h * raster.cols;
379 raster.flow = TT_Flow_Down;
380 raster.bitmap = mdvi_calloc(h, raster.cols);
382 TT_Translate_Outline(&outline, -bbox.xMin, -bbox.yMin);
383 TT_Get_Outline_Bitmap(tt_handle, &outline, &raster);
384 glyph->data = bitmap_convert_msb8(raster.bitmap, w, h);
385 TT_Done_Outline(&outline);
386 mdvi_free(raster.bitmap);
391 TT_Done_Outline(&outline);
395 static int tt_font_get_glyph(DviParams *params, DviFont *font, int code)
397 FTInfo *info = (FTInfo *)font->private;
403 ASSERT(info != NULL);
404 if(!info->hasmetrics && tt_really_load_font(params, font, info) < 0)
406 ch = FONTCHAR(font, code);
407 if(!ch || !glyph_present(ch))
410 if(!ch->width || !ch->height)
413 ch->glyph.data = NULL;
417 dpi = Max(font->hdpi, font->vdpi);
418 error = tt_get_bitmap(params, font, ch->code,
419 (double)font->hdpi / dpi,
420 (double)font->vdpi / dpi,
430 ch->glyph.data = MDVI_GLYPH_EMPTY;
433 ch->glyph.w = ch->width;
434 ch->glyph.h = ch->height;
440 static void tt_shrink_glyph(DviContext *dvi, DviFont *font, DviFontChar *ch, DviGlyph *dest)
442 tt_get_bitmap(&dvi->params, font,
444 (double)font->hdpi / (dvi->params.dpi * dvi->params.hshrink),
445 (double)font->vdpi / (dvi->params.vdpi * dvi->params.vshrink),
447 /* transform the glyph for the current orientation */
448 font_transform_glyph(dvi->params.orientation, dest);
451 static void tt_reset_font(DviFont *font)
453 FTInfo *info = (FTInfo *)font->private;
457 info->hasmetrics = 0;
460 static void tt_font_remove(FTInfo *info)
465 /* all fonts in the hash table have called TT_Open_Face */
466 TT_Done_Instance(info->instance);
467 TT_Close_Face(info->face);
469 listh_remove(&ttfonts, LIST(info));
470 /* release our encodings */
472 mdvi_release_encoding(info->encoding, 1);
473 /* and destroy the font */
475 free_font_metrics(info->tfminfo);
477 mdvi_free(info->fmfname);
481 static void tt_free_data(DviFont *font)
483 if(font->private == NULL)
486 tt_font_remove((FTInfo *)font->private);
487 if(initialized && ttfonts.count == 0) {
488 DEBUG((DBG_TT, "(tt) last font removed -- closing FreeType\n"));
489 TT_Done_FreeType(tt_handle);
494 #endif /* WITH_TRUETYPE_FONTS */