~ubuntu-branches/ubuntu/oneiric/evince/oneiric-updates

« back to all changes in this revision

Viewing changes to backend/dvi/mdvi-lib/fontmap.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-01-10 19:35:11 UTC
  • mto: (1.3.1 experimental) (52.1.1 hardy-proposed)
  • mto: This revision was merged to the branch mainline in revision 20.
  • Revision ID: james.westby@ubuntu.com-20070110193511-yjrnndv8e8wv03yy
Tags: upstream-0.7.1
ImportĀ upstreamĀ versionĀ 0.7.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* encoding.c - functions to manipulate encodings and fontmaps */
 
2
/*
 
3
 * Copyright (C) 2000, Matias Atria
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 */
 
19
 
 
20
#include <string.h>
 
21
#include <stdlib.h>
 
22
#include <stdio.h>
 
23
#include <errno.h>
 
24
#include <sys/stat.h>
 
25
 
 
26
#include "mdvi.h"
 
27
#include "private.h"
 
28
 
 
29
#include <kpathsea/expand.h>
 
30
#include <kpathsea/pathsearch.h>
 
31
 
 
32
typedef struct _DviFontMap DviFontMap;
 
33
 
 
34
struct _DviFontMap {
 
35
        ListHead entries;
 
36
        DviHashTable fonts;
 
37
};
 
38
 
 
39
typedef struct _PSFontMap {
 
40
        struct _PSFontMap *next;
 
41
        struct _PSFontMap *prev;
 
42
        char    *psname;
 
43
        char    *mapname;
 
44
        char    *fullname;
 
45
} PSFontMap;
 
46
 
 
47
/* these variables control PS font maps */
 
48
static char *pslibdir = NULL;   /* path where we look for PS font maps */
 
49
static char *psfontdir = NULL;  /* PS font search path */
 
50
static int psinitialized = 0;   /* did we expand the path already? */
 
51
 
 
52
static ListHead psfonts = MDVI_EMPTY_LIST_HEAD;
 
53
static DviHashTable pstable = MDVI_EMPTY_HASH_TABLE;
 
54
 
 
55
static ListHead fontmaps;
 
56
static DviHashTable maptable;
 
57
static int fontmaps_loaded = 0;
 
58
 
 
59
#define MAP_HASH_SIZE   57
 
60
#define ENC_HASH_SIZE   31
 
61
#define PSMAP_HASH_SIZE 57
 
62
 
 
63
/* this hash table should be big enough to 
 
64
 * hold (ideally) one glyph name per bucket */
 
65
#define ENCNAME_HASH_SIZE       131 /* most TeX fonts have 128 glyphs */
 
66
 
 
67
static ListHead encodings = MDVI_EMPTY_LIST_HEAD;
 
68
static DviEncoding *tex_text_encoding = NULL;
 
69
static DviEncoding *default_encoding = NULL;
 
70
 
 
71
/* we keep two hash tables for encodings: one for their base files (e.g.
 
72
 * "8r.enc"), and another one for their names (e.g. "TeXBase1Encoding") */ 
 
73
static DviHashTable enctable = MDVI_EMPTY_HASH_TABLE;
 
74
static DviHashTable enctable_file = MDVI_EMPTY_HASH_TABLE;
 
75
 
 
76
/* the TeX text encoding, from dvips */
 
77
static char *tex_text_vector[256] = {
 
78
        "Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma", "Upsilon",
 
79
        "Phi", "Psi", "Omega", "arrowup", "arrowdown", "quotesingle",
 
80
        "exclamdown", "questiondown", "dotlessi", "dotlessj", "grave",
 
81
        "acute", "caron", "breve", "macron", "ring", "cedilla",
 
82
        "germandbls", "ae", "oe", "oslash", "AE", "OE", "Oslash", "space",
 
83
        "exclam", "quotedbl", "numbersign", "dollar", "percent",
 
84
        "ampersand", "quoteright", "parenleft", "parenright", "asterisk",
 
85
        "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two",
 
86
        "three", "four", "five", "six", "seven", "eight", "nine", "colon",
 
87
        "semicolon", "less", "equal", "greater", "question", "at", "A", "B",
 
88
        "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
 
89
        "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
 
90
        "bracketleft", "backslash", "bracketright", "circumflex",
 
91
        "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h",
 
92
        "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
 
93
        "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "tilde",
 
94
        "dieresis", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
95
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
96
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
97
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
98
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
99
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 
100
};
 
101
 
 
102
static void ps_init_default_paths __PROTO((void));
 
103
static int      mdvi_set_default_encoding __PROTO((const char *name));
 
104
static int      mdvi_init_fontmaps __PROTO((void));
 
105
 
 
106
/* 
 
107
 * What we do here is allocate one block large enough to hold the entire
 
108
 * file (these files are small) minus the leading comments. This is much
 
109
 * better than allocating up to 256 tiny strings per encoding vector. */
 
110
static int read_encoding(DviEncoding *enc)
 
111
{
 
112
        FILE    *in;
 
113
        int     curr;
 
114
        char    *line;
 
115
        char    *name;
 
116
        char    *next;
 
117
        struct stat st;
 
118
        
 
119
        ASSERT(enc->private == NULL);
 
120
 
 
121
        in = fopen(enc->filename, "r");
 
122
        if(in == NULL) {
 
123
                DEBUG((DBG_FMAP, "%s: could not read `%s' (%s)\n",
 
124
                        enc->name, enc->filename, strerror(errno)));
 
125
                return -1;
 
126
        }
 
127
        if(fstat(fileno(in), &st) < 0) {
 
128
                /* should not happen */
 
129
                fclose(in);
 
130
                return -1;
 
131
        }
 
132
        st.st_size -= enc->offset;
 
133
 
 
134
        /* this will be one big string */
 
135
        enc->private = (char *)malloc(st.st_size + 1);
 
136
        /* setup the hash table */
 
137
        mdvi_hash_create(&enc->nametab, ENCNAME_HASH_SIZE);
 
138
        /* setup the encoding vector */
 
139
        enc->vector = (char **)mdvi_malloc(256 * sizeof(char *));
 
140
 
 
141
        /* jump to the beginning of the interesting part */
 
142
        fseek(in, enc->offset, SEEK_SET);
 
143
        /* and read everything */
 
144
        if(fread(enc->private, st.st_size, 1, in) != 1) {
 
145
                fclose(in);
 
146
                mdvi_free(enc->private);
 
147
                enc->private = NULL;
 
148
                return -1;
 
149
        }
 
150
        /* we don't need this anymore */
 
151
        fclose(in);
 
152
        curr = 0;
 
153
 
 
154
        next = name = NULL;
 
155
        DEBUG((DBG_FMAP, "%s: reading encoding vector\n", enc->name));  
 
156
        for(line = enc->private; *line && curr < 256; line = next) {
 
157
                SKIPSP(line);
 
158
                if(*line == ']') {
 
159
                        line++; SKIPSP(line);
 
160
                        if(STRNEQ(line, "def", 3))
 
161
                                break;
 
162
                }
 
163
                name = getword(line, " \t\n", &next);
 
164
                if(name == NULL)
 
165
                        break;
 
166
                /* next > line */
 
167
                if(*name < ' ')
 
168
                        continue;
 
169
                if(*name == '%') {
 
170
                        while(*next && *next != '\n')
 
171
                                next++;
 
172
                        if(*next) next++; /* skip \n */
 
173
                        continue;
 
174
                }
 
175
 
 
176
                /* got a name */
 
177
                if(*next) *next++ = 0;
 
178
                
 
179
                if(*name == '/')
 
180
                        name++;
 
181
                enc->vector[curr] = name;
 
182
                /* add it to the hash table */
 
183
                if(!STREQ(name, ".notdef")) {
 
184
                        mdvi_hash_add(&enc->nametab, MDVI_KEY(name), 
 
185
                                Int2Ptr(curr + 1), MDVI_HASH_REPLACE);
 
186
                }
 
187
                curr++;
 
188
        }
 
189
        if(curr == 0) {
 
190
                mdvi_hash_reset(&enc->nametab, 0);
 
191
                mdvi_free(enc->private);
 
192
                mdvi_free(enc);
 
193
                return -1;
 
194
        }
 
195
        while(curr < 256)
 
196
                enc->vector[curr++] = NULL;
 
197
        return 0;
 
198
}
 
199
 
 
200
static DviEncoding *find_encoding(const char *name)
 
201
{
 
202
        return (DviEncoding *)(encodings.count ? 
 
203
                mdvi_hash_lookup(&enctable, MDVI_KEY(name)) : NULL);
 
204
}
 
205
 
 
206
static void destroy_encoding(DviEncoding *enc)
 
207
{
 
208
        if(enc == default_encoding) {
 
209
                default_encoding = tex_text_encoding;
 
210
                /* now we use reference counts again */
 
211
                mdvi_release_encoding(enc, 1);
 
212
        }
 
213
        if(enc != tex_text_encoding) {
 
214
                mdvi_hash_reset(&enc->nametab, 0);
 
215
                if(enc->private) {
 
216
                        mdvi_free(enc->private);
 
217
                        mdvi_free(enc->vector);
 
218
                }
 
219
                if(enc->name)
 
220
                        mdvi_free(enc->name);
 
221
                if(enc->filename)
 
222
                        mdvi_free(enc->filename);
 
223
                mdvi_free(enc);
 
224
        }
 
225
}
 
226
 
 
227
/* this is used for the `enctable_file' hash table */
 
228
static void file_hash_free(DviHashKey key, void *data)
 
229
{
 
230
        mdvi_free(key);
 
231
}
 
232
 
 
233
static DviEncoding *register_encoding(const char *basefile, int replace)
 
234
{
 
235
        DviEncoding *enc;
 
236
        FILE    *in;
 
237
        char    *filename;
 
238
        char    *name;
 
239
        Dstring input;
 
240
        char    *line;
 
241
        long    offset;
 
242
 
 
243
        DEBUG((DBG_FMAP, "register_encoding(%s)\n", basefile));
 
244
 
 
245
        if(encodings.count) {
 
246
                enc = mdvi_hash_lookup(&enctable_file, MDVI_KEY(basefile));
 
247
                if(enc != NULL) {
 
248
                        DEBUG((DBG_FMAP, "%s: already there\n", basefile));
 
249
                        return enc; /* no error */
 
250
                }
 
251
        } 
 
252
 
 
253
        /* try our own files first */
 
254
        filename = kpse_find_file(basefile, 
 
255
                kpse_program_text_format, 0);
 
256
 
 
257
        /* then try the system-wide ones */
 
258
        if(filename == NULL)
 
259
                filename = kpse_find_file(basefile, 
 
260
                        kpse_tex_ps_header_format, 0);
 
261
        if(filename == NULL)
 
262
                filename = kpse_find_file(basefile,
 
263
                        kpse_dvips_config_format, 0);
 
264
 
 
265
        /* finally try the given name */
 
266
        if(filename == NULL)
 
267
                filename = mdvi_strdup(basefile);
 
268
 
 
269
        in = fopen(filename, "r");
 
270
        if(in == NULL) {
 
271
                mdvi_free(filename);
 
272
                return NULL;
 
273
        }
 
274
        
 
275
        /* just lookup the name of the encoding */
 
276
        name = NULL;
 
277
        dstring_init(&input);
 
278
        while((line = dgets(&input, in)) != NULL) {
 
279
                if(STRNEQ(line, "Encoding=", 9)) {
 
280
                        name = getword(line + 9, " \t", &line);
 
281
                        if(*line) *line++ = 0;
 
282
                        break;
 
283
                } else if(*line == '/') {
 
284
                        char    *label = getword(line + 1, " \t", &line);
 
285
                        if(*line) {
 
286
                                *line++ = 0;
 
287
                                SKIPSP(line);
 
288
                                if(*line == '[') {
 
289
                                        *line = 0;
 
290
                                        name = label;
 
291
                                        break;
 
292
                                }
 
293
                        }
 
294
                }
 
295
        }
 
296
        offset = ftell(in);
 
297
        fclose(in);
 
298
        if(name == NULL || *name == 0) {
 
299
                DEBUG((DBG_FMAP, 
 
300
                        "%s: could not determine name of encoding\n",
 
301
                        basefile));
 
302
                mdvi_free(filename);
 
303
                return NULL;
 
304
        }
 
305
        
 
306
        /* check if the encoding is already there */
 
307
        enc = find_encoding(name);
 
308
        if(enc == tex_text_encoding) {
 
309
                /* A special case: if the vector we found is the static one,
 
310
                 * allow the user to override it with an external file */
 
311
                listh_remove(&encodings, LIST(enc));
 
312
                mdvi_hash_remove(&enctable, MDVI_KEY(enc->name));
 
313
                if(enc == default_encoding)
 
314
                        default_encoding = NULL;
 
315
        } else if(enc) {
 
316
                /* if the encoding is being used, refuse to remove it */
 
317
                if(enc->links) {
 
318
                        mdvi_free(filename);
 
319
                        dstring_reset(&input);
 
320
                        return NULL;
 
321
                }
 
322
                if(replace) {
 
323
                        mdvi_hash_remove(&enctable, MDVI_KEY(name));
 
324
                        mdvi_hash_remove(&enctable_file, MDVI_KEY(basefile));
 
325
                        listh_remove(&encodings, LIST(enc));
 
326
                        if(enc == default_encoding) {
 
327
                                default_encoding = NULL;
 
328
                                mdvi_release_encoding(enc, 1);
 
329
                        }
 
330
                        DEBUG((DBG_FMAP, "%s: overriding encoding\n", name));
 
331
                        destroy_encoding(enc);
 
332
                } else {
 
333
                        mdvi_free(filename);
 
334
                        dstring_reset(&input);
 
335
                        return enc; /* no error */
 
336
                }
 
337
        }
 
338
        enc = xalloc(DviEncoding);
 
339
        enc->name = mdvi_strdup(name);
 
340
        enc->filename = filename;
 
341
        enc->links = 0;
 
342
        enc->offset = offset;
 
343
        enc->private = NULL;
 
344
        enc->vector = NULL;
 
345
        mdvi_hash_init(&enc->nametab);
 
346
        dstring_reset(&input);
 
347
        if(default_encoding == NULL)
 
348
                default_encoding = enc;
 
349
        mdvi_hash_add(&enctable, MDVI_KEY(enc->name), 
 
350
                enc, MDVI_HASH_UNCHECKED);
 
351
        mdvi_hash_add(&enctable_file, MDVI_KEY(mdvi_strdup(basefile)), 
 
352
                enc, MDVI_HASH_REPLACE);
 
353
        listh_prepend(&encodings, LIST(enc));
 
354
        DEBUG((DBG_FMAP, "%s: encoding `%s' registered\n",
 
355
                basefile, enc->name));
 
356
        return enc;
 
357
}
 
358
 
 
359
DviEncoding *mdvi_request_encoding(const char *name)
 
360
{
 
361
        DviEncoding *enc = find_encoding(name);
 
362
 
 
363
        if(enc == NULL) {
 
364
                DEBUG((DBG_FMAP, "%s: encoding not found, returning default `%s'\n",
 
365
                        name, default_encoding->name));
 
366
                return default_encoding;
 
367
        }
 
368
        /* we don't keep reference counts for this */
 
369
        if(enc == tex_text_encoding)
 
370
                return enc;
 
371
        if(!enc->private && read_encoding(enc) < 0)
 
372
                return NULL;
 
373
        enc->links++;
 
374
 
 
375
        /* if the hash table is empty, rebuild it */
 
376
        if(enc->nametab.nkeys == 0) {
 
377
                int     i;
 
378
 
 
379
                DEBUG((DBG_FMAP, "%s: rehashing\n", enc->name));                
 
380
                for(i = 0; i < 256; i++) {
 
381
                        if(enc->vector[i] == NULL)
 
382
                                continue;
 
383
                        mdvi_hash_add(&enc->nametab,
 
384
                                MDVI_KEY(enc->vector[i]),
 
385
                                (DviHashKey)Int2Ptr(i),
 
386
                                MDVI_HASH_REPLACE);
 
387
                }
 
388
        }
 
389
        return enc;
 
390
}
 
391
 
 
392
void    mdvi_release_encoding(DviEncoding *enc, int should_free)
 
393
{
 
394
        /* ignore our static encoding */
 
395
        if(enc == tex_text_encoding)
 
396
                return;
 
397
        if(!enc->links || --enc->links > 0 || !should_free)
 
398
                return;
 
399
        DEBUG((DBG_FMAP, "%s: resetting encoding vector\n", enc->name));
 
400
        mdvi_hash_reset(&enc->nametab, 1); /* we'll reuse it */
 
401
}
 
402
 
 
403
int     mdvi_encode_glyph(DviEncoding *enc, const char *name)
 
404
{
 
405
        void    *data;
 
406
        
 
407
        data = mdvi_hash_lookup(&enc->nametab, MDVI_KEY(name));
 
408
        if(data == NULL)
 
409
                return -1;
 
410
        /* we added +1 to the hashed index just to distinguish
 
411
         * a failed lookup from a zero index. Adjust it now. */
 
412
        return (Ptr2Int(data) - 1);
 
413
}
 
414
 
 
415
/****************
 
416
 * Fontmaps     *
 
417
 ****************/
 
418
 
 
419
static void parse_spec(DviFontMapEnt *ent, char *spec)
 
420
{
 
421
        char    *arg, *command;
 
422
        
 
423
        /* this is a ridiculously simple parser, and recognizes only
 
424
         * things of the form <argument> <command>. Of these, only
 
425
         * command=SlantFont, ExtendFont and ReEncodeFont are handled */
 
426
        while(*spec) {
 
427
                arg = getword(spec, " \t", &spec);
 
428
                if(*spec) *spec++ = 0;
 
429
                command = getword(spec, " \t", &spec);
 
430
                if(*spec) *spec++ = 0;
 
431
                if(!arg || !command)    
 
432
                        continue;
 
433
                if(STREQ(command, "SlantFont")) {
 
434
                        double  x = 10000 * strtod(arg, 0);
 
435
                
 
436
                        /* SFROUND evaluates arguments twice */ 
 
437
                        ent->slant = SFROUND(x);
 
438
                } else if(STREQ(command, "ExtendFont")) {
 
439
                        double  x = 10000 * strtod(arg, 0);
 
440
                        
 
441
                        ent->extend = SFROUND(x);
 
442
                } else if(STREQ(command, "ReEncodeFont")) {
 
443
                        if(ent->encoding)
 
444
                                mdvi_free(ent->encoding);
 
445
                        ent->encoding = mdvi_strdup(arg);
 
446
                }
 
447
        }
 
448
}
 
449
 
 
450
#if 0
 
451
static void print_ent(DviFontMapEnt *ent)
 
452
{
 
453
        printf("Entry for `%s':\n", ent->fontname);
 
454
        printf("  PS name: %s\n", ent->psname ? ent->psname : "(none)");
 
455
        printf("  Encoding: %s\n", ent->encoding ? ent->encoding : "(default)");
 
456
        printf("  EncFile: %s\n", ent->encfile ? ent->encfile : "(none)");
 
457
        printf("  FontFile: %s\n", ent->fontfile ? ent->fontfile : "(same)");
 
458
        printf("  Extend: %ld\n", ent->extend);
 
459
        printf("  Slant: %ld\n", ent->slant);
 
460
}
 
461
#endif
 
462
 
 
463
DviFontMapEnt   *mdvi_load_fontmap(const char *file)
 
464
{
 
465
        char    *ptr;
 
466
        FILE    *in;
 
467
        int     lineno = 1;
 
468
        Dstring input;
 
469
        ListHead list;
 
470
        DviFontMapEnt *ent;
 
471
        DviEncoding     *last_encoding;
 
472
        char    *last_encfile;
 
473
 
 
474
        ptr = kpse_find_file(file, kpse_program_text_format, 0);
 
475
        if(ptr == NULL)
 
476
                ptr = kpse_find_file(file, kpse_tex_ps_header_format, 0);
 
477
        if(ptr == NULL)
 
478
                ptr = kpse_find_file(file, kpse_dvips_config_format, 0);
 
479
        if(ptr == NULL)
 
480
                in = fopen(file, "r");                  
 
481
        else {
 
482
                in = fopen(ptr, "r");
 
483
                mdvi_free(ptr);
 
484
        }
 
485
        if(in == NULL)
 
486
                return NULL;
 
487
                
 
488
        ent = NULL;
 
489
        listh_init(&list);
 
490
        dstring_init(&input);
 
491
        last_encoding = NULL;
 
492
        last_encfile  = NULL;
 
493
                
 
494
        while((ptr = dgets(&input, in)) != NULL) {
 
495
                char    *font_file;
 
496
                char    *tex_name;
 
497
                char    *ps_name;
 
498
                char    *vec_name;
 
499
                int     is_encoding;
 
500
                DviEncoding *enc;
 
501
 
 
502
                lineno++;
 
503
                SKIPSP(ptr);
 
504
                
 
505
                /* we skip what dvips does */
 
506
                if(*ptr <= ' ' || *ptr == '*' || *ptr == '#' || 
 
507
                   *ptr == ';' || *ptr == '%')
 
508
                        continue;
 
509
                        
 
510
                font_file   = NULL;
 
511
                tex_name    = NULL;
 
512
                ps_name     = NULL;
 
513
                vec_name    = NULL;
 
514
                is_encoding = 0;
 
515
 
 
516
                if(ent == NULL) {
 
517
                        ent = xalloc(DviFontMapEnt);
 
518
                        ent->encoding = NULL;
 
519
                        ent->slant = 0;
 
520
                        ent->extend = 0;
 
521
                }
 
522
                while(*ptr) {
 
523
                        char    *hdr_name = NULL;
 
524
                        
 
525
                        while(*ptr && *ptr <= ' ')
 
526
                                ptr++;
 
527
                        if(*ptr == 0)
 
528
                                break;
 
529
                        if(*ptr == '"') {
 
530
                                char    *str;
 
531
                                
 
532
                                str = getstring(ptr, " \t", &ptr);
 
533
                                if(*ptr) *ptr++ = 0;
 
534
                                parse_spec(ent, str);
 
535
                                continue;
 
536
                        } else if(*ptr == '<') {
 
537
                                ptr++;
 
538
                                if(*ptr == '<')
 
539
                                        ptr++;
 
540
                                else if(*ptr == '[') {
 
541
                                        is_encoding = 1;
 
542
                                        ptr++;
 
543
                                }
 
544
                                SKIPSP(ptr);
 
545
                                hdr_name = ptr;
 
546
                        } else if(!tex_name)
 
547
                                tex_name = ptr;
 
548
                        else if(!ps_name)
 
549
                                ps_name = ptr;
 
550
                        else
 
551
                                hdr_name = ptr;
 
552
 
 
553
                        /* get next word */
 
554
                        getword(ptr, " \t", &ptr);
 
555
                        if(*ptr) *ptr++ = 0;
 
556
 
 
557
                        if(hdr_name) {
 
558
                                const char *ext = file_extension(hdr_name);
 
559
                                
 
560
                                if(is_encoding || (ext && STRCEQ(ext, "enc")))
 
561
                                        vec_name = hdr_name;
 
562
                                else
 
563
                                        font_file = hdr_name;
 
564
                        }
 
565
                }
 
566
 
 
567
                if(tex_name == NULL)
 
568
                        continue;
 
569
                ent->fontname = mdvi_strdup(tex_name);
 
570
                ent->psname   = ps_name   ? mdvi_strdup(ps_name)   : NULL;
 
571
                ent->fontfile = font_file ? mdvi_strdup(font_file) : NULL;
 
572
                ent->encfile  = vec_name  ? mdvi_strdup(vec_name)  : NULL;
 
573
                ent->fullfile = NULL;
 
574
                enc = NULL; /* we don't have this yet */
 
575
 
 
576
                /* if we have an encoding file, register it */
 
577
                if(ent->encfile) {
 
578
                        /* register_encoding is smart enough not to load the 
 
579
                         * same file twice */
 
580
                        if(!last_encfile || !STREQ(last_encfile, ent->encfile)) {
 
581
                                last_encfile  = ent->encfile;
 
582
                                last_encoding = register_encoding(ent->encfile, 1);
 
583
                        }
 
584
                        enc = last_encoding;
 
585
                }
 
586
                if(ent->encfile && enc){                
 
587
                        if(ent->encoding && !STREQ(ent->encoding, enc->name)) {
 
588
                                warning(
 
589
        _("%s: %d: [%s] requested encoding `%s' does not match vector `%s'\n"),
 
590
                                        file, lineno);
 
591
                        } else if(!ent->encoding)
 
592
                                ent->encoding = mdvi_strdup(enc->name);
 
593
                }
 
594
                
 
595
                /* add it to the list */
 
596
                /*print_ent(ent);*/
 
597
                listh_append(&list, LIST(ent));
 
598
                ent = NULL;
 
599
        }
 
600
        dstring_reset(&input);  
 
601
        fclose(in);
 
602
        
 
603
        return (DviFontMapEnt *)list.head;
 
604
}
 
605
 
 
606
static void free_ent(DviFontMapEnt *ent)
 
607
{
 
608
        ASSERT(ent->fontname != NULL);
 
609
        mdvi_free(ent->fontname);
 
610
        if(ent->psname)
 
611
                mdvi_free(ent->psname);
 
612
        if(ent->fontfile)
 
613
                mdvi_free(ent->fontfile);
 
614
        if(ent->encoding)
 
615
                mdvi_free(ent->encoding);
 
616
        if(ent->encfile)
 
617
                mdvi_free(ent->encfile);
 
618
        if(ent->fullfile)
 
619
                mdvi_free(ent->fullfile);
 
620
        mdvi_free(ent);
 
621
}
 
622
 
 
623
void    mdvi_install_fontmap(DviFontMapEnt *head)
 
624
{
 
625
        DviFontMapEnt *ent, *next;
 
626
 
 
627
        for(ent = head; ent; ent = next) {
 
628
                /* add all the entries, overriding old ones */
 
629
                DviFontMapEnt *old;
 
630
                
 
631
                old = (DviFontMapEnt *)
 
632
                        mdvi_hash_remove(&maptable, MDVI_KEY(ent->fontname));
 
633
                if(old != NULL) {
 
634
                        DEBUG((DBG_FMAP, "%s: overriding fontmap entry\n",
 
635
                                old->fontname));
 
636
                        listh_remove(&fontmaps, LIST(old));
 
637
                        free_ent(old);
 
638
                }
 
639
                next = ent->next;
 
640
                mdvi_hash_add(&maptable, MDVI_KEY(ent->fontname), 
 
641
                        ent, MDVI_HASH_UNCHECKED);
 
642
                listh_append(&fontmaps, LIST(ent));
 
643
        }
 
644
}
 
645
 
 
646
static void init_static_encoding()
 
647
{
 
648
        DviEncoding     *encoding;
 
649
        int     i;
 
650
 
 
651
        DEBUG((DBG_FMAP, "installing static TeX text encoding\n"));     
 
652
        encoding = xalloc(DviEncoding);
 
653
        encoding->private  = "";
 
654
        encoding->filename = "";
 
655
        encoding->name     = "TeXTextEncoding";
 
656
        encoding->vector   = tex_text_vector;
 
657
        encoding->links    = 1;
 
658
        encoding->offset   = 0;
 
659
        mdvi_hash_create(&encoding->nametab, ENCNAME_HASH_SIZE);
 
660
        for(i = 0; i < 256; i++) {
 
661
                if(encoding->vector[i]) {
 
662
                        mdvi_hash_add(&encoding->nametab,
 
663
                                MDVI_KEY(encoding->vector[i]),
 
664
                                (DviHashKey)Int2Ptr(i),
 
665
                                MDVI_HASH_UNCHECKED);
 
666
                }
 
667
        }
 
668
        ASSERT_VALUE(encodings.count, 0);
 
669
        mdvi_hash_create(&enctable, ENC_HASH_SIZE);
 
670
        mdvi_hash_create(&enctable_file, ENC_HASH_SIZE);
 
671
        enctable_file.hash_free = file_hash_free;
 
672
        mdvi_hash_add(&enctable, MDVI_KEY(encoding->name), 
 
673
                encoding, MDVI_HASH_UNCHECKED);
 
674
        listh_prepend(&encodings, LIST(encoding));
 
675
        tex_text_encoding = encoding;
 
676
        default_encoding = tex_text_encoding;
 
677
}
 
678
 
 
679
static int      mdvi_set_default_encoding(const char *name)
 
680
{
 
681
        DviEncoding *enc, *old;
 
682
 
 
683
        enc = find_encoding(name);
 
684
        if(enc == NULL)
 
685
                return -1;
 
686
        if(enc == default_encoding)
 
687
                return 0;
 
688
        /* this will read it from file if necessary,
 
689
         * but it can fail if the file is corrupted */
 
690
        enc = mdvi_request_encoding(name);
 
691
        if(enc == NULL)
 
692
                return -1;
 
693
        old = default_encoding;
 
694
        default_encoding = enc;
 
695
        if(old != tex_text_encoding)
 
696
                mdvi_release_encoding(old, 1);
 
697
        return 0;
 
698
}
 
699
 
 
700
static int      mdvi_init_fontmaps(void)
 
701
{
 
702
        char    *file;
 
703
        char    *line;
 
704
        FILE    *in;
 
705
        Dstring input;
 
706
        int     count = 0;
 
707
        char    *config;
 
708
 
 
709
        if(fontmaps_loaded)
 
710
                return 0;
 
711
        /* we will only try this once */
 
712
        fontmaps_loaded = 1;
 
713
 
 
714
        DEBUG((DBG_FMAP, "reading fontmaps\n"));
 
715
 
 
716
        /* make sure the static encoding is there */
 
717
        init_static_encoding();
 
718
 
 
719
        /* create the fontmap hash table */
 
720
        mdvi_hash_create(&maptable, MAP_HASH_SIZE);
 
721
                        
 
722
        /* get the name of our configuration file */
 
723
        config = kpse_cnf_get("mdvi-config");
 
724
        if(config == NULL)
 
725
                config = MDVI_DEFAULT_CONFIG;
 
726
        /* let's ask kpathsea for the file first */
 
727
        file = kpse_find_file(config, kpse_program_text_format, 0);
 
728
        if(file == NULL)
 
729
                in = fopen(config, "r");
 
730
        else {
 
731
                in = fopen(file, "r");
 
732
                mdvi_free(file);
 
733
        }
 
734
        if(in == NULL)
 
735
                return -1;
 
736
        dstring_init(&input);
 
737
        while((line = dgets(&input, in)) != NULL) {
 
738
                char    *arg;
 
739
                
 
740
                SKIPSP(line);
 
741
                if(*line < ' ' || *line == '#' || *line == '%')
 
742
                        continue;
 
743
                if(STRNEQ(line, "fontmap", 7)) {
 
744
                        DviFontMapEnt *ent;
 
745
                        
 
746
                        arg = getstring(line + 7, " \t", &line); *line = 0;
 
747
                        DEBUG((DBG_FMAP, "%s: loading fontmap\n", arg));
 
748
                        ent = mdvi_load_fontmap(arg);
 
749
                        if(ent == NULL)
 
750
                                warning(_("%s: could not load fontmap\n"), arg);
 
751
                        else {
 
752
                                DEBUG((DBG_FMAP, 
 
753
                                        "%s: installing fontmap\n", arg));
 
754
                                mdvi_install_fontmap(ent);
 
755
                                count++;
 
756
                        }
 
757
                } else if(STRNEQ(line, "encoding", 8)) {
 
758
                        arg = getstring(line + 8, " \t", &line); *line = 0;
 
759
                        if(arg && *arg)
 
760
                                register_encoding(arg, 1);
 
761
                } else if(STRNEQ(line, "default-encoding", 16)) {
 
762
                        arg = getstring(line + 16, " \t", &line); *line = 0;
 
763
                        if(mdvi_set_default_encoding(arg) < 0)
 
764
                                warning(_("%s: could not set as default encoding\n"),
 
765
                                        arg);
 
766
                } else if(STRNEQ(line, "psfontpath", 10)) {
 
767
                        arg = getstring(line + 11, " \t", &line); *line = 0;
 
768
                        if(!psinitialized)
 
769
                                ps_init_default_paths();
 
770
                        if(psfontdir)
 
771
                                mdvi_free(psfontdir);
 
772
                        psfontdir = kpse_path_expand(arg);
 
773
                } else if(STRNEQ(line, "pslibpath", 9)) {
 
774
                        arg = getstring(line + 10, " \t", &line); *line = 0;
 
775
                        if(!psinitialized)
 
776
                                ps_init_default_paths();
 
777
                        if(pslibdir)
 
778
                                mdvi_free(pslibdir);
 
779
                        pslibdir = kpse_path_expand(arg);
 
780
                } else if(STRNEQ(line, "psfontmap", 9)) {
 
781
                        arg = getstring(line + 9, " \t", &line); *line = 0;
 
782
                        if(mdvi_ps_read_fontmap(arg) < 0)
 
783
                                warning("%s: %s: could not read PS fontmap\n",
 
784
                                        config, arg);
 
785
                }
 
786
        }
 
787
        fclose(in);
 
788
        dstring_reset(&input);
 
789
        fontmaps_loaded = 1;
 
790
        DEBUG((DBG_FMAP, "%d files installed, %d fontmaps\n",
 
791
                count, fontmaps.count));
 
792
        return count;
 
793
}
 
794
 
 
795
int     mdvi_query_fontmap(DviFontMapInfo *info, const char *fontname)
 
796
{
 
797
        DviFontMapEnt *ent;
 
798
 
 
799
        if(!fontmaps_loaded && mdvi_init_fontmaps() < 0)
 
800
                return -1;              
 
801
        ent = (DviFontMapEnt *)mdvi_hash_lookup(&maptable, MDVI_KEY(fontname));
 
802
 
 
803
        if(ent == NULL)
 
804
                return -1;
 
805
        info->psname   = ent->psname;
 
806
        info->encoding = ent->encoding;
 
807
        info->fontfile = ent->fontfile;
 
808
        info->extend   = ent->extend;
 
809
        info->slant    = ent->slant;
 
810
        info->fullfile = ent->fullfile;
 
811
        
 
812
        return 0;       
 
813
}
 
814
 
 
815
int     mdvi_add_fontmap_file(const char *name, const char *fullpath)
 
816
{
 
817
        DviFontMapEnt *ent;
 
818
        
 
819
        if(!fontmaps_loaded && mdvi_init_fontmaps() < 0)
 
820
                return -1;
 
821
        ent = (DviFontMapEnt *)mdvi_hash_lookup(&maptable, MDVI_KEY(name));
 
822
        if(ent == NULL)
 
823
                return -1;
 
824
        if(ent->fullfile)
 
825
                mdvi_free(ent->fullfile);
 
826
        ent->fullfile = mdvi_strdup(fullpath);
 
827
        return 0;
 
828
}
 
829
 
 
830
 
 
831
void    mdvi_flush_encodings(void)
 
832
{
 
833
        DviEncoding *enc;
 
834
 
 
835
        if(enctable.nbucks == 0)
 
836
                return;
 
837
 
 
838
        DEBUG((DBG_FMAP, "flushing %d encodings\n", encodings.count));
 
839
        /* asked to remove all encodings */
 
840
        for(; (enc = (DviEncoding *)encodings.head); ) {
 
841
                encodings.head = LIST(enc->next);
 
842
                if((enc != tex_text_encoding && enc->links) || enc->links > 1) {
 
843
                        warning(_("encoding vector `%s' is in use\n"),
 
844
                                enc->name);
 
845
                }
 
846
                destroy_encoding(enc);
 
847
        }
 
848
        /* destroy the static encoding */
 
849
        if(tex_text_encoding->nametab.buckets)
 
850
                mdvi_hash_reset(&tex_text_encoding->nametab, 0);
 
851
        mdvi_hash_reset(&enctable, 0);
 
852
        mdvi_hash_reset(&enctable_file, 0);     
 
853
}
 
854
 
 
855
void    mdvi_flush_fontmaps(void)
 
856
{
 
857
        DviFontMapEnt *ent;
 
858
        
 
859
        if(!fontmaps_loaded)
 
860
                return;
 
861
 
 
862
        DEBUG((DBG_FMAP, "flushing %d fontmaps\n", fontmaps.count));
 
863
        for(; (ent = (DviFontMapEnt *)fontmaps.head); ) {
 
864
                fontmaps.head = LIST(ent->next);
 
865
                free_ent(ent);
 
866
        }
 
867
        mdvi_hash_reset(&maptable, 0);
 
868
        fontmaps_loaded = 0;
 
869
}
 
870
 
 
871
/* reading of PS fontmaps */
 
872
 
 
873
void    ps_init_default_paths(void)
 
874
{
 
875
        char    *kppath;
 
876
        char    *kfpath;
 
877
 
 
878
        ASSERT(psinitialized == 0);
 
879
 
 
880
        kppath = getenv("GS_LIB");
 
881
        kfpath = getenv("GS_FONTPATH"); 
 
882
 
 
883
        if(kppath != NULL)
 
884
                pslibdir = kpse_path_expand(kppath);
 
885
        if(kfpath != NULL)
 
886
                psfontdir = kpse_path_expand(kfpath);
 
887
 
 
888
        listh_init(&psfonts);
 
889
        mdvi_hash_create(&pstable, PSMAP_HASH_SIZE);
 
890
        psinitialized = 1;
 
891
}
 
892
 
 
893
int     mdvi_ps_read_fontmap(const char *name)
 
894
{
 
895
        char    *fullname;
 
896
        FILE    *in;
 
897
        Dstring dstr;
 
898
        char    *line;
 
899
        int     count = 0;
 
900
        
 
901
        if(!psinitialized)
 
902
                ps_init_default_paths();
 
903
        if(pslibdir)
 
904
                fullname = kpse_path_search(pslibdir, name, 1);
 
905
        else
 
906
                fullname = (char *)name;
 
907
        in = fopen(fullname, "r");
 
908
        if(in == NULL) {
 
909
                if(fullname != name)
 
910
                        mdvi_free(fullname);
 
911
                return -1;
 
912
        }
 
913
        dstring_init(&dstr);
 
914
        
 
915
        while((line = dgets(&dstr, in)) != NULL) {
 
916
                char    *name;
 
917
                char    *mapname;
 
918
                const char *ext;
 
919
                PSFontMap *ps;
 
920
                
 
921
                SKIPSP(line);
 
922
                /* we're looking for lines of the form
 
923
                 *  /FONT-NAME    (fontfile)
 
924
                 *  /FONT-NAME    /FONT-ALIAS 
 
925
                 */
 
926
                if(*line != '/')
 
927
                        continue;
 
928
                name = getword(line + 1, " \t", &line);
 
929
                if(*line) *line++ = 0;
 
930
                mapname = getword(line, " \t", &line);
 
931
                if(*line) *line++ = 0;
 
932
                
 
933
                if(!name || !mapname || !*name)
 
934
                        continue;
 
935
                if(*mapname == '(') {
 
936
                        char    *end;
 
937
                        
 
938
                        mapname++;
 
939
                        for(end = mapname; *end && *end != ')'; end++);
 
940
                        *end = 0;
 
941
                }
 
942
                if(!*mapname)
 
943
                        continue;
 
944
                /* dont add `.gsf' fonts, which require a full blown
 
945
                 * PostScript interpreter */
 
946
                ext = file_extension(mapname);
 
947
                if(ext && STREQ(ext, "gsf")) {
 
948
                        DEBUG((DBG_FMAP, "(ps) %s: font `%s' ignored\n",
 
949
                                name, mapname));
 
950
                        continue;
 
951
                }
 
952
                ps = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(name));
 
953
                if(ps != NULL) {
 
954
                        if(STREQ(ps->mapname, mapname))
 
955
                                continue;
 
956
                        DEBUG((DBG_FMAP, 
 
957
                                "(ps) replacing font `%s' (%s) by `%s'\n",
 
958
                                name, ps->mapname, mapname));
 
959
                        mdvi_free(ps->mapname);
 
960
                        ps->mapname = mdvi_strdup(mapname);
 
961
                        if(ps->fullname) {
 
962
                                mdvi_free(ps->fullname);
 
963
                                ps->fullname = NULL;
 
964
                        }
 
965
                } else {
 
966
                        DEBUG((DBG_FMAP, "(ps) adding font `%s' as `%s'\n",
 
967
                                name, mapname));
 
968
                        ps = xalloc(PSFontMap);
 
969
                        ps->psname   = mdvi_strdup(name);
 
970
                        ps->mapname  = mdvi_strdup(mapname);
 
971
                        ps->fullname = NULL;
 
972
                        listh_append(&psfonts, LIST(ps));
 
973
                        mdvi_hash_add(&pstable, MDVI_KEY(ps->psname),
 
974
                                ps, MDVI_HASH_UNCHECKED);
 
975
                        count++;
 
976
                }
 
977
        }
 
978
        fclose(in);
 
979
        dstring_reset(&dstr);
 
980
        
 
981
        DEBUG((DBG_FMAP, "(ps) %s: %d PostScript fonts registered\n",
 
982
                fullname, count));
 
983
        return 0;
 
984
}
 
985
 
 
986
void    mdvi_ps_flush_fonts(void)
 
987
{
 
988
        PSFontMap *map;
 
989
        
 
990
        if(!psinitialized)
 
991
                return;
 
992
        DEBUG((DBG_FMAP, "(ps) flushing PS font map (%d) entries\n",
 
993
                psfonts.count));
 
994
        mdvi_hash_reset(&pstable, 0);
 
995
        for(; (map = (PSFontMap *)psfonts.head); ) {
 
996
                psfonts.head = LIST(map->next);
 
997
                mdvi_free(map->psname);
 
998
                mdvi_free(map->mapname);
 
999
                if(map->fullname)
 
1000
                        mdvi_free(map->fullname);
 
1001
                mdvi_free(map);
 
1002
        }
 
1003
        listh_init(&psfonts);
 
1004
        if(pslibdir) {
 
1005
                mdvi_free(pslibdir);
 
1006
                pslibdir = NULL;
 
1007
        }
 
1008
        if(psfontdir) {
 
1009
                mdvi_free(psfontdir);
 
1010
                psfontdir = NULL;
 
1011
        }
 
1012
        psinitialized = 0;
 
1013
}
 
1014
 
 
1015
char    *mdvi_ps_find_font(const char *psname)
 
1016
{
 
1017
        PSFontMap *map, *smap;
 
1018
        char    *filename;
 
1019
        int     recursion_limit = 32;
 
1020
 
 
1021
        DEBUG((DBG_FMAP, "(ps) resolving PS font `%s'\n", psname));
 
1022
        if(!psinitialized)
 
1023
                return NULL;
 
1024
        map = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(psname));
 
1025
        if(map == NULL)
 
1026
                return NULL;
 
1027
        if(map->fullname)
 
1028
                return mdvi_strdup(map->fullname);
 
1029
 
 
1030
        /* is it an alias? */
 
1031
        smap = map;
 
1032
        while(recursion_limit-- > 0 && smap && *smap->mapname == '/')
 
1033
                smap = (PSFontMap *)mdvi_hash_lookup(&pstable, 
 
1034
                        MDVI_KEY(smap->mapname + 1));
 
1035
        if(smap == NULL) {
 
1036
                if(recursion_limit == 0)
 
1037
                        DEBUG((DBG_FMAP, 
 
1038
                                "(ps) %s: possible loop in PS font map\n",
 
1039
                                psname));
 
1040
                return NULL;
 
1041
        }
 
1042
 
 
1043
        if(psfontdir)
 
1044
                filename = kpse_path_search(psfontdir, smap->mapname, 1);
 
1045
        else if(file_exists(map->mapname))
 
1046
                filename = mdvi_strdup(map->mapname);
 
1047
        else
 
1048
                filename = NULL;
 
1049
        if(filename)
 
1050
                map->fullname = mdvi_strdup(filename);
 
1051
                
 
1052
        return filename;
 
1053
}
 
1054
 
 
1055
/*
 
1056
 * To get metric info for a font, we proceed as follows:
 
1057
 *  - We try to find NAME.<tfm,ofm,afm>.
 
1058
 *  - We query the fontmap for NAME.
 
1059
 *  - We get back a PSNAME, and use to find the file in the PS font map.
 
1060
 *  - We get the PSFONT file name, replace its extension by "afm" and
 
1061
 *  lookup the file in GS's font search path.
 
1062
 *  - We finally read the data, transform it as specified in our font map,
 
1063
 *  and return it to the caller. The new data is left in the font metrics
 
1064
 *  cache, so the next time it will be found at the first step (when we look
 
1065
 *  up NAME.afm).
 
1066
 *
 
1067
 * The name `_ps_' in this function is not meant to imply that it can be 
 
1068
 * used for Type1 fonts only. It should be usable for TrueType fonts as well.
 
1069
 *
 
1070
 * The returned metric info is subjected to the same caching mechanism as
 
1071
 * all the other metric data, as returned by get_font_metrics(). One should
 
1072
 * not modify the returned data at all, and it should be disposed with
 
1073
 * free_font_metrics().
 
1074
 */
 
1075
TFMInfo *mdvi_ps_get_metrics(const char *fontname)
 
1076
{
 
1077
        TFMInfo *info;
 
1078
        DviFontMapInfo map;
 
1079
        char    buffer[64]; /* to avoid mallocs */
 
1080
        char    *psfont;
 
1081
        char    *basefile;
 
1082
        char    *afmfile;
 
1083
        char    *ext;
 
1084
        int     baselen;
 
1085
        int     nc;
 
1086
        TFMChar *ch;
 
1087
        double  efactor;
 
1088
        double  sfactor;
 
1089
 
 
1090
        DEBUG((DBG_FMAP, "(ps) %s: looking for metric data\n", fontname));      
 
1091
        info = get_font_metrics(fontname, DviFontAny, NULL);
 
1092
        if(info != NULL)
 
1093
                return info;
 
1094
 
 
1095
        /* query the fontmap */
 
1096
        if(mdvi_query_fontmap(&map, fontname) < 0 || !map.psname)
 
1097
                return NULL;
 
1098
        
 
1099
        /* get the PS font */
 
1100
        psfont = mdvi_ps_find_font(map.psname);
 
1101
        if(psfont == NULL)
 
1102
                return NULL;
 
1103
        DEBUG((DBG_FMAP, "(ps) %s: found as PS font `%s'\n",
 
1104
                fontname, psfont));
 
1105
        /* replace its extension */
 
1106
        basefile = strrchr(psfont, '/');
 
1107
        if(basefile == NULL)
 
1108
                basefile = psfont;
 
1109
        baselen = strlen(basefile);
 
1110
        ext = strrchr(basefile, '.');
 
1111
        if(ext != NULL)
 
1112
                *ext = 0;
 
1113
        if(baselen + 4 < 64)
 
1114
                afmfile = &buffer[0];
 
1115
        else
 
1116
                afmfile = mdvi_malloc(baselen + 5);
 
1117
        strcpy(afmfile, basefile);
 
1118
        strcpy(afmfile + baselen, ".afm");
 
1119
        /* we don't need this anymore */
 
1120
        mdvi_free(psfont);
 
1121
        DEBUG((DBG_FMAP, "(ps) %s: looking for `%s'\n",
 
1122
                fontname, afmfile));
 
1123
        /* lookup the file */
 
1124
        psfont = kpse_path_search(psfontdir, afmfile, 1);
 
1125
        /* don't need this anymore */
 
1126
        if(afmfile != &buffer[0])
 
1127
                mdvi_free(afmfile);
 
1128
        if(psfont != NULL) {
 
1129
                info = get_font_metrics(fontname, DviFontAFM, psfont);
 
1130
                mdvi_free(psfont);
 
1131
        } else
 
1132
                info = NULL;
 
1133
        if(info == NULL || (!map.extend && !map.slant))
 
1134
                return info;
 
1135
 
 
1136
        /* 
 
1137
         * transform the data as prescribed -- keep in mind that `info' 
 
1138
         * points to CACHED data, so we're modifying the metric cache 
 
1139
         * in place.
 
1140
         */
 
1141
 
 
1142
#define DROUND(x)       ((x) >= 0 ? floor((x) + 0.5) : ceil((x) - 0.5))
 
1143
#define TRANSFORM(x,y)  DROUND(efactor * (x) + sfactor * (y))
 
1144
 
 
1145
        efactor = (double)map.extend / 10000.0;
 
1146
        sfactor = (double)map.slant / 10000.0;
 
1147
        DEBUG((DBG_FMAP, "(ps) %s: applying extend=%f, slant=%f\n",
 
1148
                efactor, sfactor));
 
1149
 
 
1150
        nc = info->hic - info->loc + 1;
 
1151
        for(ch = info->chars; ch < info->chars + nc; ch++) {
 
1152
                /* the AFM bounding box is:
 
1153
                 *    wx = ch->advance
 
1154
                 *   llx = ch->left
 
1155
                 *   lly = -ch->depth
 
1156
                 *   urx = ch->right
 
1157
                 *   ury = ch->height
 
1158
                 * what we do here is transform wx, llx, and urx by
 
1159
                 *         newX = efactor * oldX + sfactor * oldY
 
1160
                 * where for `wx' oldY = 0. Also, these numbers are all in
 
1161
                 * TFM units (i.e. TFM's fix-words, which is just the actual
 
1162
                 * number times 2^20, no need to do anything to it).
 
1163
                 */
 
1164
                if(ch->present) {
 
1165
                        ch->advance = TRANSFORM(ch->advance, 0);
 
1166
                        ch->left    = TRANSFORM(ch->left, -ch->depth);
 
1167
                        ch->right   = TRANSFORM(ch->right, ch->height);
 
1168
                }
 
1169
        }
 
1170
        
 
1171
        return info;
 
1172
}