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
20
* Type1 font support for MDVI
22
* We use T1lib only as a rasterizer, not to draw glyphs.
27
#ifdef WITH_TYPE1_FONTS
33
static int t1lib_initialized = 0;
35
typedef struct t1info {
38
char *fontname; /* (short) name of this font */
39
int t1id; /* T1lib's id for this font */
40
int hasmetrics; /* have we processed this font? */
41
TFMInfo *tfminfo; /* TFM data is shared */
42
DviFontMapInfo mapinfo;
43
DviEncoding *encoding;
46
static void t1_font_remove __PROTO((T1Info *));
47
static int t1_load_font __PROTO((DviParams *, DviFont *));
48
static int t1_font_get_glyph __PROTO((DviParams *, DviFont *, int));
49
static void t1_font_shrink_glyph
50
__PROTO((DviContext *, DviFont *, DviFontChar *, DviGlyph *));
51
static void t1_free_data __PROTO((DviFont *));
52
static void t1_reset_font __PROTO((DviFont *));
53
static char *t1_lookup_font __PROTO((const char *, Ushort *, Ushort *));
55
/* only symbol exported by this file */
56
DviFontInfo t1_font_info = {
58
1, /* scaling supported by format */
62
mdvi_shrink_glyph_grey,
65
t1_lookup_font, /* lookup */
70
/* this seems good enough for most DVI files */
71
#define T1_HASH_SIZE 31
73
/* If these parameters change, we must delete all size information
74
* in all fonts, and reset the device resolutions in T1lib */
75
static int t1lib_xdpi = -1;
76
static int t1lib_ydpi = -1;
78
static ListHead t1fonts = {NULL, NULL, 0};
79
static DviHashTable t1hash;
81
/* Type1 fonts need their own `lookup' function. Here is how it works:
82
* First we try to find the font by its given name. If that fails, we
83
* query the font maps. A typical font map entry may contain the line
85
* ptmr8rn Times-Roman ".82 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <ptmr
87
* which means: If you're looking for the font `ptmr8rn' load `Times-Roman'
88
* which is in `ptmr' instead, and extend it by 0.82 points, then reencode
89
* it with the vector TeXBase1Encoding from the file `8r.enc'. This will
90
* fail if the entry looks like this:
92
* ptmr8rn Times-Roman ".82 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc
94
* because to deal with this we would need to be able to locate the font file
95
* for the `Times-Roman' font ourselves, and that's beyond the scope of mdvi.
96
* But hey, we tried hard.
98
char *t1_lookup_font(const char *name, Ushort *hdpi, Ushort *vdpi)
105
DEBUG((DBG_TYPE1, "(t1) looking for `%s'\n", name));
107
/* first let's try the font we were asked for */
108
filename = kpse_find_file(name, kpse_type1_format, 1);
109
if(filename != NULL) {
114
DEBUG((DBG_TYPE1, "(t1) %s: not found, querying font maps\n", name));
115
/* now query the fontmap */
116
if(mdvi_query_fontmap(&info, name) < 0) {
117
/* it's not there either */
121
/* check what we got */
123
DEBUG((DBG_TYPE1, "(t1) %s: found `%s' (cached)\n",
124
name, info.fullfile));
125
/* this is a cached lookup */
126
return mdvi_strdup(info.fullfile);
129
/* no file associated to this font? */
130
if(info.fontfile == NULL)
131
return info.psname ? mdvi_ps_find_font(info.psname) : NULL;
133
/* let's extract the extension */
134
ext = file_extension(info.fontfile);
135
if(ext && !STREQ(ext, "pfa") && !STREQ(ext, "pfb")) {
137
"(t1) %s: associated name `%s' is not Type1\n",
138
name, info.fontfile));
139
/* it's not a Type1 font */
143
/* get the `base' name */
145
newname = mdvi_strdup(name);
146
newname[ext - info.fontfile - 1] = 0;
148
newname = (char *)name; /* we don't modify this */
151
DEBUG((DBG_TYPE1, "(t1) looking for `%s' on behalf of `%s'\n",
153
filename = kpse_find_file(newname, kpse_type1_format, 1);
155
/* we don't need this anymore */
158
if(filename == NULL) {
159
DEBUG((DBG_TYPE1, "(t1) %s: not found\n", name));
163
DEBUG((DBG_TYPE1, "(t1) %s: found as `%s'\n", name, filename));
164
/* got it! let's remember this */
165
mdvi_add_fontmap_file(name, filename);
169
static void t1_reset_resolution(int xdpi, int ydpi)
174
DEBUG((DBG_TYPE1, "(t1) resetting device resolution (current: (%d,%d))\n",
175
t1lib_xdpi, t1lib_ydpi));
176
#if T1LIB_VERSION < 5
177
nfonts = T1_Get_no_fonts();
179
nfonts = T1_GetNoFonts();
182
for(i = 0; i < nfonts; i++)
183
T1_DeleteAllSizes(i);
184
/* reset device resolutions */
185
if(T1_SetDeviceResolutions((float)xdpi, (float)ydpi) < 0)
186
warning(_("(t1) failed to reset device resolution\n"));
189
"(t1) reset successful, new resolution is (%d, %d)\n",
195
static void t1_reset_font(DviFont *font)
197
T1Info *info = (T1Info *)font->private;
201
DEBUG((DBG_FONTS, "(t1) resetting font `%s'\n", font->fontname));
202
/* just mark the font as not having metric info. It will be reset
203
* automatically later */
204
info->hasmetrics = 0;
207
static void t1_transform_font(T1Info *info)
209
if(!info->hasmetrics && info->encoding != NULL) {
210
DEBUG((DBG_TYPE1, "(t1) %s: encoding with vector `%s'\n",
211
info->fontname, info->encoding->name));
212
T1_DeleteAllSizes(info->t1id);
213
if(T1_ReencodeFont(info->t1id, info->encoding->vector) < 0)
214
warning(_("%s: could not encode font\n"), info->fontname);
216
if(info->mapinfo.slant) {
217
DEBUG((DBG_TYPE1, "(t1) %s: slanting by %.3f\n",
219
MDVI_FMAP_SLANT(&info->mapinfo)));
220
T1_SlantFont(info->t1id,
221
MDVI_FMAP_SLANT(&info->mapinfo));
223
if(info->mapinfo.extend) {
224
DEBUG((DBG_TYPE1, "(t1) %s: extending by %.3f\n",
226
MDVI_FMAP_EXTEND(&info->mapinfo)));
227
T1_ExtendFont(info->t1id,
228
MDVI_FMAP_EXTEND(&info->mapinfo));
232
/* if this function is called, we really need this font */
233
static int t1_really_load_font(DviParams *params, DviFont *font, T1Info *info)
241
DEBUG((DBG_TYPE1, "(t1) really_load_font(%s)\n", info->fontname));
243
/* if the parameters changed, reset T1lib */
244
if(t1lib_xdpi != params->dpi || t1lib_ydpi != params->vdpi)
245
t1_reset_resolution(params->dpi, params->vdpi);
247
/* if we already have a T1lib id, do nothing */
248
if(info->t1id != -1) {
249
info->hasmetrics = 1;
250
/* apply slant and extend again */
251
t1_transform_font(info);
255
/* before we even attempt to load the font, make sure we have metric
257
info->tfminfo = mdvi_ps_get_metrics(info->fontname);
258
if(info->tfminfo == NULL) {
260
"(t1) %s: no metric data, font ignored\n",
265
font->design = info->tfminfo->design;
267
/* check if we have a font with this name (maybe at a different size) */
268
old = (T1Info *)mdvi_hash_lookup(&t1hash, (unsigned char *)info->fontname);
270
/* let's avoid confusion */
273
if(old && old->t1id != -1) {
274
/* let's take advantage of T1lib's font sharing */
275
t1id = T1_CopyFont(old->t1id);
276
DEBUG((DBG_TYPE1, "(t1) %s -> %d (CopyFont)\n",
277
info->fontname, t1id));
280
t1id = T1_AddFont(font->filename);
281
DEBUG((DBG_TYPE1, "(t1) %s -> %d (AddFont)\n",
282
info->fontname, t1id));
290
* a minor optimization: If the old font in the hash table has
291
* not been loaded yet, replace it by this one, so we can use
294
if(old && old->t1id == -1) {
295
DEBUG((DBG_TYPE1, "(t1) font `%s' exchanged in hash table\n",
297
mdvi_hash_remove(&t1hash, (unsigned char *)old->fontname);
298
mdvi_hash_add(&t1hash, (unsigned char *)info->fontname,
299
info, MDVI_HASH_UNCHECKED);
302
/* now let T1lib load it */
303
if(!copied && T1_LoadFont(info->t1id) < 0) {
304
DEBUG((DBG_TYPE1, "(t1) T1_LoadFont(%d) failed with error %d\n",
305
info->t1id, T1_errno));
308
DEBUG((DBG_TYPE1, "(t1) T1_LoadFont(%d) -> Ok\n", info->t1id));
310
/* get information from the fontmap */
311
status = mdvi_query_fontmap(&info->mapinfo, info->fontname);
312
if(!status && info->mapinfo.encoding)
313
info->encoding = mdvi_request_encoding(info->mapinfo.encoding);
314
t1_transform_font(info);
316
i = info->tfminfo->hic - info->tfminfo->loc + 1;
317
if(i != font->hic - font->loc + 1) {
318
/* reset to optimal size */
319
font->chars = mdvi_realloc(font->chars, i * sizeof(DviFontChar));
322
/* get the scaled characters metrics */
323
get_tfm_chars(params, font, info->tfminfo, 0);
324
info->hasmetrics = 1;
326
DEBUG((DBG_TYPE1, "(t1) font `%s' really-loaded\n", info->fontname));
330
/* some error does not allows us to use this font. We need to reset
331
* the font structure, so the font system can try to read this
332
* font in a different class */
334
/* first destroy the private data */
335
t1_font_remove(info);
336
/* now reset all chars -- this is the important part */
337
mdvi_free(font->chars);
339
font->loc = font->hic = 0;
343
static int init_t1lib(DviParams *params)
347
#ifdef WORD_LITTLE_ENDIAN
348
/* try making T1lib use bitmaps in our format, but if this
349
* fails we'll convert the bitmap ourselves */
350
T1_SetBitmapPad(BITMAP_BITS);
352
T1_SetDeviceResolutions((float)params->dpi, (float)params->vdpi);
353
t1flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE|T1_NO_AFM;
356
if(T1_InitLib(t1flags) == NULL)
357
return (t1lib_initialized = -1);
358
if(DEBUGGING(TYPE1)) {
359
DEBUG((DBG_TYPE1, "T1lib debugging output saved in t1lib.log\n"));
360
T1_SetLogLevel(T1LOG_DEBUG);
362
/* initialize our hash table, but don't allocate memory for it
364
mdvi_hash_init(&t1hash);
365
DEBUG((DBG_TYPE1, "(t1) t1lib %s initialized -- resolution is (%d, %d), pad is %d bits\n",
366
T1_GetLibIdent(), params->dpi, params->vdpi, T1_GetBitmapPad()));
367
t1lib_initialized = 1;
368
t1lib_xdpi = params->dpi;
369
t1lib_ydpi = params->vdpi;
373
static int t1_load_font(DviParams *params, DviFont *font)
378
if(t1lib_initialized < 0)
380
else if(t1lib_initialized == 0 && init_t1lib(params) < 0)
383
if(font->in != NULL) {
384
/* we don't need this */
389
info = xalloc(T1Info);
392
* mark the font as `unregistered' with T1lib. It will
393
* be added when we actually use it
397
/* add the font to our list */
398
info->fontname = font->fontname;
399
info->hasmetrics = 0;
400
info->encoding = NULL;
401
info->mapinfo.psname = NULL;
402
info->mapinfo.encoding = NULL;
403
info->mapinfo.fontfile = NULL;
404
info->mapinfo.extend = 0;
405
info->mapinfo.slant = 0;
406
info->encoding = NULL;
408
/* create the hash table if we have not done so yet */
409
if(t1hash.nbucks == 0)
410
mdvi_hash_create(&t1hash, T1_HASH_SIZE);
411
mdvi_hash_add(&t1hash, (unsigned char *) info->fontname, info, MDVI_HASH_UNIQUE);
412
listh_append(&t1fonts, LIST(info));
414
font->private = info;
416
/* reset everything */
417
font->chars = xnalloc(DviFontChar, 256);
420
for(i = 0; i < 256; i++) {
421
font->chars[i].code = i;
422
font->chars[i].offset = 1;
423
font->chars[i].loaded = 0;
424
font->chars[i].glyph.data = NULL;
425
font->chars[i].shrunk.data = NULL;
426
font->chars[i].grey.data = NULL;
432
#define GLYPH_WIDTH(g) \
433
((g)->metrics.rightSideBearing - (g)->metrics.leftSideBearing)
434
#define GLYPH_HEIGHT(g) \
435
((g)->metrics.ascent - (g)->metrics.descent)
437
static inline BITMAP *t1_glyph_bitmap(GLYPH *glyph)
442
w = GLYPH_WIDTH(glyph);
443
h = GLYPH_HEIGHT(glyph);
446
return MDVI_GLYPH_EMPTY;
447
switch(glyph->bpp << 3) {
449
bm = bitmap_convert_lsb8((unsigned char *)glyph->bits, w, h);
452
warning(_("(t1) unsupported bitmap pad size %d\n"),
454
bm = MDVI_GLYPH_EMPTY;
460
static void t1_font_shrink_glyph(DviContext *dvi, DviFont *font, DviFontChar *ch, DviGlyph *dest)
467
info = (T1Info *)font->private;
468
ASSERT(info != NULL);
470
DEBUG((DBG_TYPE1, "(t1) shrinking glyph for character %d in `%s' (%d,%d)\n",
471
ch->code, font->fontname, ch->width, ch->height));
472
size = (double)font->scale / (dvi->params.tfm_conv * 0x100000);
473
size = 72.0 * size / 72.27;
474
matrix.cxx = 1.0/(double)dvi->params.hshrink;
475
matrix.cyy = 1.0/(double)dvi->params.vshrink;
478
glyph = T1_SetChar(info->t1id, ch->code, (float)size, &matrix);
480
dest->data = t1_glyph_bitmap(glyph);
481
dest->x = -glyph->metrics.leftSideBearing;
482
dest->y = glyph->metrics.ascent;
483
dest->w = GLYPH_WIDTH(glyph);
484
dest->h = GLYPH_HEIGHT(glyph);
487
if(DEBUGGING(BITMAP_DATA)) {
488
DEBUG((DBG_BITMAP_DATA,
489
"(t1) %s: t1_shrink_glyph(%d): (%dw,%dh,%dx,%dy) -> (%dw,%dh,%dx,%dy)\n",
490
ch->glyph.w, ch->glyph.h, ch->glyph.x, ch->glyph.y,
491
dest->w, dest->h, dest->x, dest->y));
492
bitmap_print(stderr, (BITMAP *)dest->data);
495
/* transform the glyph - we could do this with t1lib, but we do
496
* it ourselves for now */
497
font_transform_glyph(dvi->params.orientation, dest);
500
static int t1_font_get_glyph(DviParams *params, DviFont *font, int code)
502
T1Info *info = (T1Info *)font->private;
509
ASSERT(info != NULL);
510
if(!info->hasmetrics && t1_really_load_font(params, font, info) < 0)
512
ch = FONTCHAR(font, code);
513
if(!ch || !glyph_present(ch))
516
if(!ch->width || !ch->height) {
519
ch->glyph.w = ch->width;
520
ch->glyph.h = ch->height;
521
ch->glyph.data = NULL;
525
/* load the glyph with T1lib (this is done only once for each glyph) */
527
/* get size in TeX points (tfm_conv includes dpi and magnification) */
528
size = (double)font->scale / (params->tfm_conv * 0x100000);
529
/* and transform into PostScript points */
530
size = 72.0 * size / 72.27;
532
dpi = Max(font->hdpi, font->vdpi);
533
/* we don't want the glyph to be cached twice (once by us, another by
534
* T1lib), so we use an identity matrix to tell T1lib not to keep the
536
matrix.cxx = (double)font->hdpi / dpi;
537
matrix.cyy = (double)font->vdpi / dpi;
538
matrix.cxy = matrix.cyx = 0.0;
539
glyph = T1_SetChar(info->t1id, ch->code, (float)size, &matrix);
543
ch->glyph.w = ch->width;
544
ch->glyph.h = ch->height;
545
ch->glyph.data = NULL;
549
/* and make it a bitmap */
550
ch->glyph.data = t1_glyph_bitmap(glyph);
551
ch->glyph.x = -glyph->metrics.leftSideBearing;
552
ch->glyph.y = glyph->metrics.ascent;
553
ch->glyph.w = GLYPH_WIDTH(glyph);
554
ch->glyph.h = GLYPH_HEIGHT(glyph);
556
/* let's also fix the glyph's origin
557
* (which is not contained in the TFM) */
560
/* let's fix these too */
561
ch->width = ch->glyph.w;
562
ch->height = ch->glyph.h;
567
static void t1_font_remove(T1Info *info)
571
/* first remove it from our list */
572
listh_remove(&t1fonts, LIST(info));
574
/* it it's in the hash table, we may need to replace this by another font */
575
old = (T1Info *)mdvi_hash_lookup(&t1hash, (unsigned char *)info->fontname);
577
mdvi_hash_remove(&t1hash, (unsigned char *) info->fontname);
578
/* go through the list and see if there is another
579
* font with this name */
580
for(old = (T1Info *)t1fonts.head; old; old = old->next)
581
if(STREQ(old->fontname, info->fontname))
584
mdvi_hash_add(&t1hash, (unsigned char *) old->fontname, old,
585
MDVI_HASH_UNCHECKED);
587
/* release our encoding vector */
589
DEBUG((DBG_TYPE1, "(t1) %s: releasing vector `%s'\n",
590
info->fontname, info->encoding->name));
591
mdvi_release_encoding(info->encoding, 1);
594
/* now get rid of it */
595
if(info->t1id != -1) {
596
DEBUG((DBG_TYPE1, "(t1) %s: T1_DeleteFont(%d)\n",
597
info->fontname, info->t1id));
598
T1_DeleteFont(info->t1id);
600
DEBUG((DBG_TYPE1, "(t1) %s: not loaded yet, DeleteFont skipped\n",
604
free_font_metrics(info->tfminfo);
605
/*mdvi_free(info->fontname);*/
609
static void t1_free_data(DviFont *font)
611
/* called after all the glyphs are destroyed */
613
if(font->private == NULL) {
614
/* this is perfectly normal, it just means the font has
615
* not been requested by MDVI yet */
619
/* destroy this data */
621
t1_font_remove((T1Info *)font->private);
622
font->private = NULL;
625
* if this is the last T1 font, reset the T1 library
626
* It is important that we do this, because this is will be called
627
* when the resolution or the magnification changes.
629
if(t1fonts.count == 0) {
630
DEBUG((DBG_TYPE1, "(t1) last font removed -- closing T1lib\n"));
632
t1lib_initialized = 0;
638
#endif /* WITH_TYPE1_FONTS */