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
30 #include <kpathsea/expand.h>
31 #include <kpathsea/pathsearch.h>
33 typedef struct _DviFontMap DviFontMap;
40 typedef struct _PSFontMap {
41 struct _PSFontMap *next;
42 struct _PSFontMap *prev;
48 /* these variables control PS font maps */
49 static char *pslibdir = NULL; /* path where we look for PS font maps */
50 static char *psfontdir = NULL; /* PS font search path */
51 static int psinitialized = 0; /* did we expand the path already? */
53 static ListHead psfonts = MDVI_EMPTY_LIST_HEAD;
54 static DviHashTable pstable = MDVI_EMPTY_HASH_TABLE;
56 static ListHead fontmaps;
57 static DviHashTable maptable;
58 static int fontmaps_loaded = 0;
60 #define MAP_HASH_SIZE 57
61 #define ENC_HASH_SIZE 31
62 #define PSMAP_HASH_SIZE 57
64 /* this hash table should be big enough to
65 * hold (ideally) one glyph name per bucket */
66 #define ENCNAME_HASH_SIZE 131 /* most TeX fonts have 128 glyphs */
68 static ListHead encodings = MDVI_EMPTY_LIST_HEAD;
69 static DviEncoding *tex_text_encoding = NULL;
70 static DviEncoding *default_encoding = NULL;
72 /* we keep two hash tables for encodings: one for their base files (e.g.
73 * "8r.enc"), and another one for their names (e.g. "TeXBase1Encoding") */
74 static DviHashTable enctable = MDVI_EMPTY_HASH_TABLE;
75 static DviHashTable enctable_file = MDVI_EMPTY_HASH_TABLE;
77 /* the TeX text encoding, from dvips */
78 static char *tex_text_vector[256] = {
79 "Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma", "Upsilon",
80 "Phi", "Psi", "Omega", "arrowup", "arrowdown", "quotesingle",
81 "exclamdown", "questiondown", "dotlessi", "dotlessj", "grave",
82 "acute", "caron", "breve", "macron", "ring", "cedilla",
83 "germandbls", "ae", "oe", "oslash", "AE", "OE", "Oslash", "space",
84 "exclam", "quotedbl", "numbersign", "dollar", "percent",
85 "ampersand", "quoteright", "parenleft", "parenright", "asterisk",
86 "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two",
87 "three", "four", "five", "six", "seven", "eight", "nine", "colon",
88 "semicolon", "less", "equal", "greater", "question", "at", "A", "B",
89 "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
90 "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
91 "bracketleft", "backslash", "bracketright", "circumflex",
92 "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h",
93 "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
94 "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "tilde",
95 "dieresis", 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, 0, 0, 0, 0, 0, 0,
100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
103 static void ps_init_default_paths __PROTO((void));
104 static int mdvi_set_default_encoding __PROTO((const char *name));
105 static int mdvi_init_fontmaps __PROTO((void));
108 * What we do here is allocate one block large enough to hold the entire
109 * file (these files are small) minus the leading comments. This is much
110 * better than allocating up to 256 tiny strings per encoding vector. */
111 static int read_encoding(DviEncoding *enc)
120 ASSERT(enc->private == NULL);
122 in = fopen(enc->filename, "rb");
124 DEBUG((DBG_FMAP, "%s: could not read `%s' (%s)\n",
125 enc->name, enc->filename, strerror(errno)));
128 if(fstat(fileno(in), &st) < 0) {
129 /* should not happen */
133 st.st_size -= enc->offset;
135 /* this will be one big string */
136 enc->private = (char *)malloc(st.st_size + 1);
137 /* setup the hash table */
138 mdvi_hash_create(&enc->nametab, ENCNAME_HASH_SIZE);
139 /* setup the encoding vector */
140 enc->vector = (char **)mdvi_malloc(256 * sizeof(char *));
142 /* jump to the beginning of the interesting part */
143 fseek(in, enc->offset, SEEK_SET);
144 /* and read everything */
145 if(fread(enc->private, st.st_size, 1, in) != 1) {
147 mdvi_free(enc->private);
151 /* we don't need this anymore */
156 DEBUG((DBG_FMAP, "%s: reading encoding vector\n", enc->name));
157 for(line = enc->private; *line && curr < 256; line = next) {
160 line++; SKIPSP(line);
161 if(STRNEQ(line, "def", 3))
164 name = getword(line, " \t\n", &next);
171 while(*next && *next != '\n')
173 if(*next) next++; /* skip \n */
178 if(*next) *next++ = 0;
182 enc->vector[curr] = name;
183 /* add it to the hash table */
184 if(!STREQ(name, ".notdef")) {
185 mdvi_hash_add(&enc->nametab, MDVI_KEY(name),
186 Int2Ptr(curr + 1), MDVI_HASH_REPLACE);
191 mdvi_hash_reset(&enc->nametab, 0);
192 mdvi_free(enc->private);
197 enc->vector[curr++] = NULL;
201 static DviEncoding *find_encoding(const char *name)
203 return (DviEncoding *)(encodings.count ?
204 mdvi_hash_lookup(&enctable, MDVI_KEY(name)) : NULL);
207 static void destroy_encoding(DviEncoding *enc)
209 if(enc == default_encoding) {
210 default_encoding = tex_text_encoding;
211 /* now we use reference counts again */
212 mdvi_release_encoding(enc, 1);
214 if(enc != tex_text_encoding) {
215 mdvi_hash_reset(&enc->nametab, 0);
217 mdvi_free(enc->private);
218 mdvi_free(enc->vector);
221 mdvi_free(enc->name);
223 mdvi_free(enc->filename);
228 /* this is used for the `enctable_file' hash table */
229 static void file_hash_free(DviHashKey key, void *data)
234 static DviEncoding *register_encoding(const char *basefile, int replace)
244 DEBUG((DBG_FMAP, "register_encoding(%s)\n", basefile));
246 if(encodings.count) {
247 enc = mdvi_hash_lookup(&enctable_file, MDVI_KEY(basefile));
249 DEBUG((DBG_FMAP, "%s: already there\n", basefile));
250 return enc; /* no error */
254 /* try our own files first */
255 filename = kpse_find_file(basefile,
256 kpse_program_text_format, 0);
258 /* then try the system-wide ones */
260 filename = kpse_find_file(basefile,
261 kpse_tex_ps_header_format, 0);
263 filename = kpse_find_file(basefile,
264 kpse_dvips_config_format, 0);
266 /* finally try the given name */
268 filename = mdvi_strdup(basefile);
270 in = fopen(filename, "rb");
276 /* just lookup the name of the encoding */
278 dstring_init(&input);
279 while((line = dgets(&input, in)) != NULL) {
280 if(STRNEQ(line, "Encoding=", 9)) {
281 name = getword(line + 9, " \t", &line);
282 if(*line) *line++ = 0;
284 } else if(*line == '/') {
285 char *label = getword(line + 1, " \t", &line);
299 if(name == NULL || *name == 0) {
301 "%s: could not determine name of encoding\n",
307 /* check if the encoding is already there */
308 enc = find_encoding(name);
309 if(enc == tex_text_encoding) {
310 /* A special case: if the vector we found is the static one,
311 * allow the user to override it with an external file */
312 listh_remove(&encodings, LIST(enc));
313 mdvi_hash_remove(&enctable, MDVI_KEY(enc->name));
314 if(enc == default_encoding)
315 default_encoding = NULL;
317 /* if the encoding is being used, refuse to remove it */
320 dstring_reset(&input);
324 mdvi_hash_remove(&enctable, MDVI_KEY(name));
325 mdvi_hash_remove(&enctable_file, MDVI_KEY(basefile));
326 listh_remove(&encodings, LIST(enc));
327 if(enc == default_encoding) {
328 default_encoding = NULL;
329 mdvi_release_encoding(enc, 1);
331 DEBUG((DBG_FMAP, "%s: overriding encoding\n", name));
332 destroy_encoding(enc);
335 dstring_reset(&input);
336 return enc; /* no error */
339 enc = xalloc(DviEncoding);
340 enc->name = mdvi_strdup(name);
341 enc->filename = filename;
343 enc->offset = offset;
346 mdvi_hash_init(&enc->nametab);
347 dstring_reset(&input);
348 if(default_encoding == NULL)
349 default_encoding = enc;
350 mdvi_hash_add(&enctable, MDVI_KEY(enc->name),
351 enc, MDVI_HASH_UNCHECKED);
352 mdvi_hash_add(&enctable_file, MDVI_KEY(mdvi_strdup(basefile)),
353 enc, MDVI_HASH_REPLACE);
354 listh_prepend(&encodings, LIST(enc));
355 DEBUG((DBG_FMAP, "%s: encoding `%s' registered\n",
356 basefile, enc->name));
360 DviEncoding *mdvi_request_encoding(const char *name)
362 DviEncoding *enc = find_encoding(name);
365 DEBUG((DBG_FMAP, "%s: encoding not found, returning default `%s'\n",
366 name, default_encoding->name));
367 return default_encoding;
369 /* we don't keep reference counts for this */
370 if(enc == tex_text_encoding)
372 if(!enc->private && read_encoding(enc) < 0)
376 /* if the hash table is empty, rebuild it */
377 if(enc->nametab.nkeys == 0) {
380 DEBUG((DBG_FMAP, "%s: rehashing\n", enc->name));
381 for(i = 0; i < 256; i++) {
382 if(enc->vector[i] == NULL)
384 mdvi_hash_add(&enc->nametab,
385 MDVI_KEY(enc->vector[i]),
386 (DviHashKey)Int2Ptr(i),
393 void mdvi_release_encoding(DviEncoding *enc, int should_free)
395 /* ignore our static encoding */
396 if(enc == tex_text_encoding)
398 if(!enc->links || --enc->links > 0 || !should_free)
400 DEBUG((DBG_FMAP, "%s: resetting encoding vector\n", enc->name));
401 mdvi_hash_reset(&enc->nametab, 1); /* we'll reuse it */
404 int mdvi_encode_glyph(DviEncoding *enc, const char *name)
408 data = mdvi_hash_lookup(&enc->nametab, MDVI_KEY(name));
411 /* we added +1 to the hashed index just to distinguish
412 * a failed lookup from a zero index. Adjust it now. */
413 return (Ptr2Int(data) - 1);
420 static void parse_spec(DviFontMapEnt *ent, char *spec)
424 /* this is a ridiculously simple parser, and recognizes only
425 * things of the form <argument> <command>. Of these, only
426 * command=SlantFont, ExtendFont and ReEncodeFont are handled */
428 arg = getword(spec, " \t", &spec);
429 if(*spec) *spec++ = 0;
430 command = getword(spec, " \t", &spec);
431 if(*spec) *spec++ = 0;
434 if(STREQ(command, "SlantFont")) {
435 double x = 10000 * strtod(arg, 0);
437 /* SFROUND evaluates arguments twice */
438 ent->slant = SFROUND(x);
439 } else if(STREQ(command, "ExtendFont")) {
440 double x = 10000 * strtod(arg, 0);
442 ent->extend = SFROUND(x);
443 } else if(STREQ(command, "ReEncodeFont")) {
445 mdvi_free(ent->encoding);
446 ent->encoding = mdvi_strdup(arg);
452 static void print_ent(DviFontMapEnt *ent)
454 printf("Entry for `%s':\n", ent->fontname);
455 printf(" PS name: %s\n", ent->psname ? ent->psname : "(none)");
456 printf(" Encoding: %s\n", ent->encoding ? ent->encoding : "(default)");
457 printf(" EncFile: %s\n", ent->encfile ? ent->encfile : "(none)");
458 printf(" FontFile: %s\n", ent->fontfile ? ent->fontfile : "(same)");
459 printf(" Extend: %ld\n", ent->extend);
460 printf(" Slant: %ld\n", ent->slant);
464 DviFontMapEnt *mdvi_load_fontmap(const char *file)
472 DviEncoding *last_encoding;
475 ptr = kpse_find_file(file, kpse_program_text_format, 0);
477 ptr = kpse_find_file(file, kpse_tex_ps_header_format, 0);
479 ptr = kpse_find_file(file, kpse_dvips_config_format, 0);
481 in = fopen(file, "rb");
483 in = fopen(ptr, "rb");
491 dstring_init(&input);
492 last_encoding = NULL;
495 while((ptr = dgets(&input, in)) != NULL) {
506 /* we skip what dvips does */
507 if(*ptr <= ' ' || *ptr == '*' || *ptr == '#' ||
508 *ptr == ';' || *ptr == '%')
518 ent = xalloc(DviFontMapEnt);
519 ent->encoding = NULL;
524 char *hdr_name = NULL;
526 while(*ptr && *ptr <= ' ')
533 str = getstring(ptr, " \t", &ptr);
535 parse_spec(ent, str);
537 } else if(*ptr == '<') {
541 else if(*ptr == '[') {
555 getword(ptr, " \t", &ptr);
559 const char *ext = file_extension(hdr_name);
561 if(is_encoding || (ext && STRCEQ(ext, "enc")))
564 font_file = hdr_name;
570 ent->fontname = mdvi_strdup(tex_name);
571 ent->psname = ps_name ? mdvi_strdup(ps_name) : NULL;
572 ent->fontfile = font_file ? mdvi_strdup(font_file) : NULL;
573 ent->encfile = vec_name ? mdvi_strdup(vec_name) : NULL;
574 ent->fullfile = NULL;
575 enc = NULL; /* we don't have this yet */
577 /* if we have an encoding file, register it */
579 /* register_encoding is smart enough not to load the
581 if(!last_encfile || !STREQ(last_encfile, ent->encfile)) {
582 last_encfile = ent->encfile;
583 last_encoding = register_encoding(ent->encfile, 1);
587 if(ent->encfile && enc){
588 if(ent->encoding && !STREQ(ent->encoding, enc->name)) {
590 _("%s: %d: [%s] requested encoding `%s' does not match vector `%s'\n"),
591 file, lineno, ent->encfile,
592 ent->encoding, enc->name);
593 } else if(!ent->encoding)
594 ent->encoding = mdvi_strdup(enc->name);
597 /* add it to the list */
599 listh_append(&list, LIST(ent));
602 dstring_reset(&input);
605 return (DviFontMapEnt *)list.head;
608 static void free_ent(DviFontMapEnt *ent)
610 ASSERT(ent->fontname != NULL);
611 mdvi_free(ent->fontname);
613 mdvi_free(ent->psname);
615 mdvi_free(ent->fontfile);
617 mdvi_free(ent->encoding);
619 mdvi_free(ent->encfile);
621 mdvi_free(ent->fullfile);
625 void mdvi_install_fontmap(DviFontMapEnt *head)
627 DviFontMapEnt *ent, *next;
629 for(ent = head; ent; ent = next) {
630 /* add all the entries, overriding old ones */
633 old = (DviFontMapEnt *)
634 mdvi_hash_remove(&maptable, MDVI_KEY(ent->fontname));
636 DEBUG((DBG_FMAP, "%s: overriding fontmap entry\n",
638 listh_remove(&fontmaps, LIST(old));
642 mdvi_hash_add(&maptable, MDVI_KEY(ent->fontname),
643 ent, MDVI_HASH_UNCHECKED);
644 listh_append(&fontmaps, LIST(ent));
648 static void init_static_encoding()
650 DviEncoding *encoding;
653 DEBUG((DBG_FMAP, "installing static TeX text encoding\n"));
654 encoding = xalloc(DviEncoding);
655 encoding->private = "";
656 encoding->filename = "";
657 encoding->name = "TeXTextEncoding";
658 encoding->vector = tex_text_vector;
660 encoding->offset = 0;
661 mdvi_hash_create(&encoding->nametab, ENCNAME_HASH_SIZE);
662 for(i = 0; i < 256; i++) {
663 if(encoding->vector[i]) {
664 mdvi_hash_add(&encoding->nametab,
665 MDVI_KEY(encoding->vector[i]),
666 (DviHashKey)Int2Ptr(i),
667 MDVI_HASH_UNCHECKED);
670 ASSERT_VALUE(encodings.count, 0);
671 mdvi_hash_create(&enctable, ENC_HASH_SIZE);
672 mdvi_hash_create(&enctable_file, ENC_HASH_SIZE);
673 enctable_file.hash_free = file_hash_free;
674 mdvi_hash_add(&enctable, MDVI_KEY(encoding->name),
675 encoding, MDVI_HASH_UNCHECKED);
676 listh_prepend(&encodings, LIST(encoding));
677 tex_text_encoding = encoding;
678 default_encoding = tex_text_encoding;
681 static int mdvi_set_default_encoding(const char *name)
683 DviEncoding *enc, *old;
685 enc = find_encoding(name);
688 if(enc == default_encoding)
690 /* this will read it from file if necessary,
691 * but it can fail if the file is corrupted */
692 enc = mdvi_request_encoding(name);
695 old = default_encoding;
696 default_encoding = enc;
697 if(old != tex_text_encoding)
698 mdvi_release_encoding(old, 1);
702 static int mdvi_init_fontmaps(void)
713 /* we will only try this once */
716 DEBUG((DBG_FMAP, "reading fontmaps\n"));
718 /* make sure the static encoding is there */
719 init_static_encoding();
721 /* create the fontmap hash table */
722 mdvi_hash_create(&maptable, MAP_HASH_SIZE);
724 /* get the name of our configuration file */
725 config = kpse_cnf_get("mdvi-config");
727 config = MDVI_DEFAULT_CONFIG;
728 /* let's ask kpathsea for the file first */
729 file = kpse_find_file(config, kpse_program_text_format, 0);
731 in = fopen(config, "rb");
733 in = fopen(file, "rb");
738 dstring_init(&input);
739 while((line = dgets(&input, in)) != NULL) {
743 if(*line < ' ' || *line == '#' || *line == '%')
745 if(STRNEQ(line, "fontmap", 7)) {
748 arg = getstring(line + 7, " \t", &line); *line = 0;
749 DEBUG((DBG_FMAP, "%s: loading fontmap\n", arg));
750 ent = mdvi_load_fontmap(arg);
752 mdvi_warning(_("%s: could not load fontmap\n"), arg);
755 "%s: installing fontmap\n", arg));
756 mdvi_install_fontmap(ent);
759 } else if(STRNEQ(line, "encoding", 8)) {
760 arg = getstring(line + 8, " \t", &line); *line = 0;
762 register_encoding(arg, 1);
763 } else if(STRNEQ(line, "default-encoding", 16)) {
764 arg = getstring(line + 16, " \t", &line); *line = 0;
765 if(mdvi_set_default_encoding(arg) < 0)
766 mdvi_warning(_("%s: could not set as default encoding\n"),
768 } else if(STRNEQ(line, "psfontpath", 10)) {
769 arg = getstring(line + 11, " \t", &line); *line = 0;
771 ps_init_default_paths();
773 mdvi_free(psfontdir);
774 psfontdir = kpse_path_expand(arg);
775 } else if(STRNEQ(line, "pslibpath", 9)) {
776 arg = getstring(line + 10, " \t", &line); *line = 0;
778 ps_init_default_paths();
781 pslibdir = kpse_path_expand(arg);
782 } else if(STRNEQ(line, "psfontmap", 9)) {
783 arg = getstring(line + 9, " \t", &line); *line = 0;
784 if(mdvi_ps_read_fontmap(arg) < 0)
785 mdvi_warning("%s: %s: could not read PS fontmap\n",
790 dstring_reset(&input);
792 DEBUG((DBG_FMAP, "%d files installed, %d fontmaps\n",
793 count, fontmaps.count));
797 int mdvi_query_fontmap(DviFontMapInfo *info, const char *fontname)
801 if(!fontmaps_loaded && mdvi_init_fontmaps() < 0)
803 ent = (DviFontMapEnt *)mdvi_hash_lookup(&maptable, MDVI_KEY(fontname));
807 info->psname = ent->psname;
808 info->encoding = ent->encoding;
809 info->fontfile = ent->fontfile;
810 info->extend = ent->extend;
811 info->slant = ent->slant;
812 info->fullfile = ent->fullfile;
817 int mdvi_add_fontmap_file(const char *name, const char *fullpath)
821 if(!fontmaps_loaded && mdvi_init_fontmaps() < 0)
823 ent = (DviFontMapEnt *)mdvi_hash_lookup(&maptable, MDVI_KEY(name));
827 mdvi_free(ent->fullfile);
828 ent->fullfile = mdvi_strdup(fullpath);
833 void mdvi_flush_encodings(void)
837 if(enctable.nbucks == 0)
840 DEBUG((DBG_FMAP, "flushing %d encodings\n", encodings.count));
841 /* asked to remove all encodings */
842 for(; (enc = (DviEncoding *)encodings.head); ) {
843 encodings.head = LIST(enc->next);
844 if((enc != tex_text_encoding && enc->links) || enc->links > 1) {
845 mdvi_warning(_("encoding vector `%s' is in use\n"),
848 destroy_encoding(enc);
850 /* destroy the static encoding */
851 if(tex_text_encoding->nametab.buckets)
852 mdvi_hash_reset(&tex_text_encoding->nametab, 0);
853 mdvi_hash_reset(&enctable, 0);
854 mdvi_hash_reset(&enctable_file, 0);
857 void mdvi_flush_fontmaps(void)
864 DEBUG((DBG_FMAP, "flushing %d fontmaps\n", fontmaps.count));
865 for(; (ent = (DviFontMapEnt *)fontmaps.head); ) {
866 fontmaps.head = LIST(ent->next);
869 mdvi_hash_reset(&maptable, 0);
873 /* reading of PS fontmaps */
875 void ps_init_default_paths(void)
880 ASSERT(psinitialized == 0);
882 kppath = getenv("GS_LIB");
883 kfpath = getenv("GS_FONTPATH");
886 pslibdir = kpse_path_expand(kppath);
888 psfontdir = kpse_path_expand(kfpath);
890 listh_init(&psfonts);
891 mdvi_hash_create(&pstable, PSMAP_HASH_SIZE);
895 int mdvi_ps_read_fontmap(const char *name)
904 ps_init_default_paths();
906 fullname = kpse_path_search(pslibdir, name, 1);
908 fullname = (char *)name;
909 in = fopen(fullname, "rb");
917 while((line = dgets(&dstr, in)) != NULL) {
924 /* we're looking for lines of the form
925 * /FONT-NAME (fontfile)
926 * /FONT-NAME /FONT-ALIAS
930 name = getword(line + 1, " \t", &line);
931 if(*line) *line++ = 0;
932 mapname = getword(line, " \t", &line);
933 if(*line) *line++ = 0;
935 if(!name || !mapname || !*name)
937 if(*mapname == '(') {
941 for(end = mapname; *end && *end != ')'; end++);
946 /* dont add `.gsf' fonts, which require a full blown
947 * PostScript interpreter */
948 ext = file_extension(mapname);
949 if(ext && STREQ(ext, "gsf")) {
950 DEBUG((DBG_FMAP, "(ps) %s: font `%s' ignored\n",
954 ps = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(name));
956 if(STREQ(ps->mapname, mapname))
959 "(ps) replacing font `%s' (%s) by `%s'\n",
960 name, ps->mapname, mapname));
961 mdvi_free(ps->mapname);
962 ps->mapname = mdvi_strdup(mapname);
964 mdvi_free(ps->fullname);
968 DEBUG((DBG_FMAP, "(ps) adding font `%s' as `%s'\n",
970 ps = xalloc(PSFontMap);
971 ps->psname = mdvi_strdup(name);
972 ps->mapname = mdvi_strdup(mapname);
974 listh_append(&psfonts, LIST(ps));
975 mdvi_hash_add(&pstable, MDVI_KEY(ps->psname),
976 ps, MDVI_HASH_UNCHECKED);
981 dstring_reset(&dstr);
983 DEBUG((DBG_FMAP, "(ps) %s: %d PostScript fonts registered\n",
988 void mdvi_ps_flush_fonts(void)
994 DEBUG((DBG_FMAP, "(ps) flushing PS font map (%d) entries\n",
996 mdvi_hash_reset(&pstable, 0);
997 for(; (map = (PSFontMap *)psfonts.head); ) {
998 psfonts.head = LIST(map->next);
999 mdvi_free(map->psname);
1000 mdvi_free(map->mapname);
1002 mdvi_free(map->fullname);
1005 listh_init(&psfonts);
1007 mdvi_free(pslibdir);
1011 mdvi_free(psfontdir);
1017 char *mdvi_ps_find_font(const char *psname)
1019 PSFontMap *map, *smap;
1021 int recursion_limit = 32;
1023 DEBUG((DBG_FMAP, "(ps) resolving PS font `%s'\n", psname));
1026 map = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(psname));
1030 return mdvi_strdup(map->fullname);
1032 /* is it an alias? */
1034 while(recursion_limit-- > 0 && smap && *smap->mapname == '/')
1035 smap = (PSFontMap *)mdvi_hash_lookup(&pstable,
1036 MDVI_KEY(smap->mapname + 1));
1038 if(recursion_limit == 0)
1040 "(ps) %s: possible loop in PS font map\n",
1046 filename = kpse_path_search(psfontdir, smap->mapname, 1);
1047 else if(file_exists(map->mapname))
1048 filename = mdvi_strdup(map->mapname);
1052 map->fullname = mdvi_strdup(filename);
1058 * To get metric info for a font, we proceed as follows:
1059 * - We try to find NAME.<tfm,ofm,afm>.
1060 * - We query the fontmap for NAME.
1061 * - We get back a PSNAME, and use to find the file in the PS font map.
1062 * - We get the PSFONT file name, replace its extension by "afm" and
1063 * lookup the file in GS's font search path.
1064 * - We finally read the data, transform it as specified in our font map,
1065 * and return it to the caller. The new data is left in the font metrics
1066 * cache, so the next time it will be found at the first step (when we look
1069 * The name `_ps_' in this function is not meant to imply that it can be
1070 * used for Type1 fonts only. It should be usable for TrueType fonts as well.
1072 * The returned metric info is subjected to the same caching mechanism as
1073 * all the other metric data, as returned by get_font_metrics(). One should
1074 * not modify the returned data at all, and it should be disposed with
1075 * free_font_metrics().
1077 TFMInfo *mdvi_ps_get_metrics(const char *fontname)
1081 char buffer[64]; /* to avoid mallocs */
1092 DEBUG((DBG_FMAP, "(ps) %s: looking for metric data\n", fontname));
1093 info = get_font_metrics(fontname, DviFontAny, NULL);
1097 /* query the fontmap */
1098 if(mdvi_query_fontmap(&map, fontname) < 0 || !map.psname)
1101 /* get the PS font */
1102 psfont = mdvi_ps_find_font(map.psname);
1105 DEBUG((DBG_FMAP, "(ps) %s: found as PS font `%s'\n",
1107 /* replace its extension */
1108 basefile = strrchr(psfont, '/');
1109 if(basefile == NULL)
1111 baselen = strlen(basefile);
1112 ext = strrchr(basefile, '.');
1115 if(baselen + 4 < 64)
1116 afmfile = &buffer[0];
1118 afmfile = mdvi_malloc(baselen + 5);
1119 strcpy(afmfile, basefile);
1120 strcpy(afmfile + baselen, ".afm");
1121 /* we don't need this anymore */
1123 DEBUG((DBG_FMAP, "(ps) %s: looking for `%s'\n",
1124 fontname, afmfile));
1125 /* lookup the file */
1126 psfont = kpse_path_search(psfontdir, afmfile, 1);
1127 /* don't need this anymore */
1128 if(afmfile != &buffer[0])
1130 if(psfont != NULL) {
1131 info = get_font_metrics(fontname, DviFontAFM, psfont);
1135 if(info == NULL || (!map.extend && !map.slant))
1139 * transform the data as prescribed -- keep in mind that `info'
1140 * points to CACHED data, so we're modifying the metric cache
1144 #define DROUND(x) ((x) >= 0 ? floor((x) + 0.5) : ceil((x) - 0.5))
1145 #define TRANSFORM(x,y) DROUND(efactor * (x) + sfactor * (y))
1147 efactor = (double)map.extend / 10000.0;
1148 sfactor = (double)map.slant / 10000.0;
1149 DEBUG((DBG_FMAP, "(ps) %s: applying extend=%f, slant=%f\n",
1152 nc = info->hic - info->loc + 1;
1153 for(ch = info->chars; ch < info->chars + nc; ch++) {
1154 /* the AFM bounding box is:
1160 * what we do here is transform wx, llx, and urx by
1161 * newX = efactor * oldX + sfactor * oldY
1162 * where for `wx' oldY = 0. Also, these numbers are all in
1163 * TFM units (i.e. TFM's fix-words, which is just the actual
1164 * number times 2^20, no need to do anything to it).
1167 ch->advance = TRANSFORM(ch->advance, 0);
1168 ch->left = TRANSFORM(ch->left, -ch->depth);
1169 ch->right = TRANSFORM(ch->right, ch->height);