1
/* encoding.c - functions to manipulate encodings and fontmaps */
3
* Copyright (C) 2000, Matias Atria
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.
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.
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
29
#include <kpathsea/expand.h>
30
#include <kpathsea/pathsearch.h>
32
typedef struct _DviFontMap DviFontMap;
39
typedef struct _PSFontMap {
40
struct _PSFontMap *next;
41
struct _PSFontMap *prev;
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? */
52
static ListHead psfonts = MDVI_EMPTY_LIST_HEAD;
53
static DviHashTable pstable = MDVI_EMPTY_HASH_TABLE;
55
static ListHead fontmaps;
56
static DviHashTable maptable;
57
static int fontmaps_loaded = 0;
59
#define MAP_HASH_SIZE 57
60
#define ENC_HASH_SIZE 31
61
#define PSMAP_HASH_SIZE 57
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 */
67
static ListHead encodings = MDVI_EMPTY_LIST_HEAD;
68
static DviEncoding *tex_text_encoding = NULL;
69
static DviEncoding *default_encoding = NULL;
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;
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
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));
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)
119
ASSERT(enc->private == NULL);
121
in = fopen(enc->filename, "r");
123
DEBUG((DBG_FMAP, "%s: could not read `%s' (%s)\n",
124
enc->name, enc->filename, strerror(errno)));
127
if(fstat(fileno(in), &st) < 0) {
128
/* should not happen */
132
st.st_size -= enc->offset;
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 *));
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) {
146
mdvi_free(enc->private);
150
/* we don't need this anymore */
155
DEBUG((DBG_FMAP, "%s: reading encoding vector\n", enc->name));
156
for(line = enc->private; *line && curr < 256; line = next) {
159
line++; SKIPSP(line);
160
if(STRNEQ(line, "def", 3))
163
name = getword(line, " \t\n", &next);
170
while(*next && *next != '\n')
172
if(*next) next++; /* skip \n */
177
if(*next) *next++ = 0;
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);
190
mdvi_hash_reset(&enc->nametab, 0);
191
mdvi_free(enc->private);
196
enc->vector[curr++] = NULL;
200
static DviEncoding *find_encoding(const char *name)
202
return (DviEncoding *)(encodings.count ?
203
mdvi_hash_lookup(&enctable, MDVI_KEY(name)) : NULL);
206
static void destroy_encoding(DviEncoding *enc)
208
if(enc == default_encoding) {
209
default_encoding = tex_text_encoding;
210
/* now we use reference counts again */
211
mdvi_release_encoding(enc, 1);
213
if(enc != tex_text_encoding) {
214
mdvi_hash_reset(&enc->nametab, 0);
216
mdvi_free(enc->private);
217
mdvi_free(enc->vector);
220
mdvi_free(enc->name);
222
mdvi_free(enc->filename);
227
/* this is used for the `enctable_file' hash table */
228
static void file_hash_free(DviHashKey key, void *data)
233
static DviEncoding *register_encoding(const char *basefile, int replace)
243
DEBUG((DBG_FMAP, "register_encoding(%s)\n", basefile));
245
if(encodings.count) {
246
enc = mdvi_hash_lookup(&enctable_file, MDVI_KEY(basefile));
248
DEBUG((DBG_FMAP, "%s: already there\n", basefile));
249
return enc; /* no error */
253
/* try our own files first */
254
filename = kpse_find_file(basefile,
255
kpse_program_text_format, 0);
257
/* then try the system-wide ones */
259
filename = kpse_find_file(basefile,
260
kpse_tex_ps_header_format, 0);
262
filename = kpse_find_file(basefile,
263
kpse_dvips_config_format, 0);
265
/* finally try the given name */
267
filename = mdvi_strdup(basefile);
269
in = fopen(filename, "r");
275
/* just lookup the name of the encoding */
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;
283
} else if(*line == '/') {
284
char *label = getword(line + 1, " \t", &line);
298
if(name == NULL || *name == 0) {
300
"%s: could not determine name of encoding\n",
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;
316
/* if the encoding is being used, refuse to remove it */
319
dstring_reset(&input);
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);
330
DEBUG((DBG_FMAP, "%s: overriding encoding\n", name));
331
destroy_encoding(enc);
334
dstring_reset(&input);
335
return enc; /* no error */
338
enc = xalloc(DviEncoding);
339
enc->name = mdvi_strdup(name);
340
enc->filename = filename;
342
enc->offset = offset;
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));
359
DviEncoding *mdvi_request_encoding(const char *name)
361
DviEncoding *enc = find_encoding(name);
364
DEBUG((DBG_FMAP, "%s: encoding not found, returning default `%s'\n",
365
name, default_encoding->name));
366
return default_encoding;
368
/* we don't keep reference counts for this */
369
if(enc == tex_text_encoding)
371
if(!enc->private && read_encoding(enc) < 0)
375
/* if the hash table is empty, rebuild it */
376
if(enc->nametab.nkeys == 0) {
379
DEBUG((DBG_FMAP, "%s: rehashing\n", enc->name));
380
for(i = 0; i < 256; i++) {
381
if(enc->vector[i] == NULL)
383
mdvi_hash_add(&enc->nametab,
384
MDVI_KEY(enc->vector[i]),
385
(DviHashKey)Int2Ptr(i),
392
void mdvi_release_encoding(DviEncoding *enc, int should_free)
394
/* ignore our static encoding */
395
if(enc == tex_text_encoding)
397
if(!enc->links || --enc->links > 0 || !should_free)
399
DEBUG((DBG_FMAP, "%s: resetting encoding vector\n", enc->name));
400
mdvi_hash_reset(&enc->nametab, 1); /* we'll reuse it */
403
int mdvi_encode_glyph(DviEncoding *enc, const char *name)
407
data = mdvi_hash_lookup(&enc->nametab, MDVI_KEY(name));
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);
419
static void parse_spec(DviFontMapEnt *ent, char *spec)
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 */
427
arg = getword(spec, " \t", &spec);
428
if(*spec) *spec++ = 0;
429
command = getword(spec, " \t", &spec);
430
if(*spec) *spec++ = 0;
433
if(STREQ(command, "SlantFont")) {
434
double x = 10000 * strtod(arg, 0);
436
/* SFROUND evaluates arguments twice */
437
ent->slant = SFROUND(x);
438
} else if(STREQ(command, "ExtendFont")) {
439
double x = 10000 * strtod(arg, 0);
441
ent->extend = SFROUND(x);
442
} else if(STREQ(command, "ReEncodeFont")) {
444
mdvi_free(ent->encoding);
445
ent->encoding = mdvi_strdup(arg);
451
static void print_ent(DviFontMapEnt *ent)
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);
463
DviFontMapEnt *mdvi_load_fontmap(const char *file)
471
DviEncoding *last_encoding;
474
ptr = kpse_find_file(file, kpse_program_text_format, 0);
476
ptr = kpse_find_file(file, kpse_tex_ps_header_format, 0);
478
ptr = kpse_find_file(file, kpse_dvips_config_format, 0);
480
in = fopen(file, "r");
482
in = fopen(ptr, "r");
490
dstring_init(&input);
491
last_encoding = NULL;
494
while((ptr = dgets(&input, in)) != NULL) {
505
/* we skip what dvips does */
506
if(*ptr <= ' ' || *ptr == '*' || *ptr == '#' ||
507
*ptr == ';' || *ptr == '%')
517
ent = xalloc(DviFontMapEnt);
518
ent->encoding = NULL;
523
char *hdr_name = NULL;
525
while(*ptr && *ptr <= ' ')
532
str = getstring(ptr, " \t", &ptr);
534
parse_spec(ent, str);
536
} else if(*ptr == '<') {
540
else if(*ptr == '[') {
554
getword(ptr, " \t", &ptr);
558
const char *ext = file_extension(hdr_name);
560
if(is_encoding || (ext && STRCEQ(ext, "enc")))
563
font_file = hdr_name;
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 */
576
/* if we have an encoding file, register it */
578
/* register_encoding is smart enough not to load the
580
if(!last_encfile || !STREQ(last_encfile, ent->encfile)) {
581
last_encfile = ent->encfile;
582
last_encoding = register_encoding(ent->encfile, 1);
586
if(ent->encfile && enc){
587
if(ent->encoding && !STREQ(ent->encoding, enc->name)) {
589
_("%s: %d: [%s] requested encoding `%s' does not match vector `%s'\n"),
591
} else if(!ent->encoding)
592
ent->encoding = mdvi_strdup(enc->name);
595
/* add it to the list */
597
listh_append(&list, LIST(ent));
600
dstring_reset(&input);
603
return (DviFontMapEnt *)list.head;
606
static void free_ent(DviFontMapEnt *ent)
608
ASSERT(ent->fontname != NULL);
609
mdvi_free(ent->fontname);
611
mdvi_free(ent->psname);
613
mdvi_free(ent->fontfile);
615
mdvi_free(ent->encoding);
617
mdvi_free(ent->encfile);
619
mdvi_free(ent->fullfile);
623
void mdvi_install_fontmap(DviFontMapEnt *head)
625
DviFontMapEnt *ent, *next;
627
for(ent = head; ent; ent = next) {
628
/* add all the entries, overriding old ones */
631
old = (DviFontMapEnt *)
632
mdvi_hash_remove(&maptable, MDVI_KEY(ent->fontname));
634
DEBUG((DBG_FMAP, "%s: overriding fontmap entry\n",
636
listh_remove(&fontmaps, LIST(old));
640
mdvi_hash_add(&maptable, MDVI_KEY(ent->fontname),
641
ent, MDVI_HASH_UNCHECKED);
642
listh_append(&fontmaps, LIST(ent));
646
static void init_static_encoding()
648
DviEncoding *encoding;
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;
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);
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;
679
static int mdvi_set_default_encoding(const char *name)
681
DviEncoding *enc, *old;
683
enc = find_encoding(name);
686
if(enc == default_encoding)
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);
693
old = default_encoding;
694
default_encoding = enc;
695
if(old != tex_text_encoding)
696
mdvi_release_encoding(old, 1);
700
static int mdvi_init_fontmaps(void)
711
/* we will only try this once */
714
DEBUG((DBG_FMAP, "reading fontmaps\n"));
716
/* make sure the static encoding is there */
717
init_static_encoding();
719
/* create the fontmap hash table */
720
mdvi_hash_create(&maptable, MAP_HASH_SIZE);
722
/* get the name of our configuration file */
723
config = kpse_cnf_get("mdvi-config");
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);
729
in = fopen(config, "r");
731
in = fopen(file, "r");
736
dstring_init(&input);
737
while((line = dgets(&input, in)) != NULL) {
741
if(*line < ' ' || *line == '#' || *line == '%')
743
if(STRNEQ(line, "fontmap", 7)) {
746
arg = getstring(line + 7, " \t", &line); *line = 0;
747
DEBUG((DBG_FMAP, "%s: loading fontmap\n", arg));
748
ent = mdvi_load_fontmap(arg);
750
warning(_("%s: could not load fontmap\n"), arg);
753
"%s: installing fontmap\n", arg));
754
mdvi_install_fontmap(ent);
757
} else if(STRNEQ(line, "encoding", 8)) {
758
arg = getstring(line + 8, " \t", &line); *line = 0;
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"),
766
} else if(STRNEQ(line, "psfontpath", 10)) {
767
arg = getstring(line + 11, " \t", &line); *line = 0;
769
ps_init_default_paths();
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;
776
ps_init_default_paths();
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",
788
dstring_reset(&input);
790
DEBUG((DBG_FMAP, "%d files installed, %d fontmaps\n",
791
count, fontmaps.count));
795
int mdvi_query_fontmap(DviFontMapInfo *info, const char *fontname)
799
if(!fontmaps_loaded && mdvi_init_fontmaps() < 0)
801
ent = (DviFontMapEnt *)mdvi_hash_lookup(&maptable, MDVI_KEY(fontname));
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;
815
int mdvi_add_fontmap_file(const char *name, const char *fullpath)
819
if(!fontmaps_loaded && mdvi_init_fontmaps() < 0)
821
ent = (DviFontMapEnt *)mdvi_hash_lookup(&maptable, MDVI_KEY(name));
825
mdvi_free(ent->fullfile);
826
ent->fullfile = mdvi_strdup(fullpath);
831
void mdvi_flush_encodings(void)
835
if(enctable.nbucks == 0)
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"),
846
destroy_encoding(enc);
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);
855
void mdvi_flush_fontmaps(void)
862
DEBUG((DBG_FMAP, "flushing %d fontmaps\n", fontmaps.count));
863
for(; (ent = (DviFontMapEnt *)fontmaps.head); ) {
864
fontmaps.head = LIST(ent->next);
867
mdvi_hash_reset(&maptable, 0);
871
/* reading of PS fontmaps */
873
void ps_init_default_paths(void)
878
ASSERT(psinitialized == 0);
880
kppath = getenv("GS_LIB");
881
kfpath = getenv("GS_FONTPATH");
884
pslibdir = kpse_path_expand(kppath);
886
psfontdir = kpse_path_expand(kfpath);
888
listh_init(&psfonts);
889
mdvi_hash_create(&pstable, PSMAP_HASH_SIZE);
893
int mdvi_ps_read_fontmap(const char *name)
902
ps_init_default_paths();
904
fullname = kpse_path_search(pslibdir, name, 1);
906
fullname = (char *)name;
907
in = fopen(fullname, "r");
915
while((line = dgets(&dstr, in)) != NULL) {
922
/* we're looking for lines of the form
923
* /FONT-NAME (fontfile)
924
* /FONT-NAME /FONT-ALIAS
928
name = getword(line + 1, " \t", &line);
929
if(*line) *line++ = 0;
930
mapname = getword(line, " \t", &line);
931
if(*line) *line++ = 0;
933
if(!name || !mapname || !*name)
935
if(*mapname == '(') {
939
for(end = mapname; *end && *end != ')'; end++);
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",
952
ps = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(name));
954
if(STREQ(ps->mapname, mapname))
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);
962
mdvi_free(ps->fullname);
966
DEBUG((DBG_FMAP, "(ps) adding font `%s' as `%s'\n",
968
ps = xalloc(PSFontMap);
969
ps->psname = mdvi_strdup(name);
970
ps->mapname = mdvi_strdup(mapname);
972
listh_append(&psfonts, LIST(ps));
973
mdvi_hash_add(&pstable, MDVI_KEY(ps->psname),
974
ps, MDVI_HASH_UNCHECKED);
979
dstring_reset(&dstr);
981
DEBUG((DBG_FMAP, "(ps) %s: %d PostScript fonts registered\n",
986
void mdvi_ps_flush_fonts(void)
992
DEBUG((DBG_FMAP, "(ps) flushing PS font map (%d) entries\n",
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);
1000
mdvi_free(map->fullname);
1003
listh_init(&psfonts);
1005
mdvi_free(pslibdir);
1009
mdvi_free(psfontdir);
1015
char *mdvi_ps_find_font(const char *psname)
1017
PSFontMap *map, *smap;
1019
int recursion_limit = 32;
1021
DEBUG((DBG_FMAP, "(ps) resolving PS font `%s'\n", psname));
1024
map = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(psname));
1028
return mdvi_strdup(map->fullname);
1030
/* is it an alias? */
1032
while(recursion_limit-- > 0 && smap && *smap->mapname == '/')
1033
smap = (PSFontMap *)mdvi_hash_lookup(&pstable,
1034
MDVI_KEY(smap->mapname + 1));
1036
if(recursion_limit == 0)
1038
"(ps) %s: possible loop in PS font map\n",
1044
filename = kpse_path_search(psfontdir, smap->mapname, 1);
1045
else if(file_exists(map->mapname))
1046
filename = mdvi_strdup(map->mapname);
1050
map->fullname = mdvi_strdup(filename);
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
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.
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().
1075
TFMInfo *mdvi_ps_get_metrics(const char *fontname)
1079
char buffer[64]; /* to avoid mallocs */
1090
DEBUG((DBG_FMAP, "(ps) %s: looking for metric data\n", fontname));
1091
info = get_font_metrics(fontname, DviFontAny, NULL);
1095
/* query the fontmap */
1096
if(mdvi_query_fontmap(&map, fontname) < 0 || !map.psname)
1099
/* get the PS font */
1100
psfont = mdvi_ps_find_font(map.psname);
1103
DEBUG((DBG_FMAP, "(ps) %s: found as PS font `%s'\n",
1105
/* replace its extension */
1106
basefile = strrchr(psfont, '/');
1107
if(basefile == NULL)
1109
baselen = strlen(basefile);
1110
ext = strrchr(basefile, '.');
1113
if(baselen + 4 < 64)
1114
afmfile = &buffer[0];
1116
afmfile = mdvi_malloc(baselen + 5);
1117
strcpy(afmfile, basefile);
1118
strcpy(afmfile + baselen, ".afm");
1119
/* we don't need this anymore */
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])
1128
if(psfont != NULL) {
1129
info = get_font_metrics(fontname, DviFontAFM, psfont);
1133
if(info == NULL || (!map.extend && !map.slant))
1137
* transform the data as prescribed -- keep in mind that `info'
1138
* points to CACHED data, so we're modifying the metric cache
1142
#define DROUND(x) ((x) >= 0 ? floor((x) + 0.5) : ceil((x) - 0.5))
1143
#define TRANSFORM(x,y) DROUND(efactor * (x) + sfactor * (y))
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",
1150
nc = info->hic - info->loc + 1;
1151
for(ch = info->chars; ch < info->chars + nc; ch++) {
1152
/* the AFM bounding box is:
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).
1165
ch->advance = TRANSFORM(ch->advance, 0);
1166
ch->left = TRANSFORM(ch->left, -ch->depth);
1167
ch->right = TRANSFORM(ch->right, ch->height);