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 **)xmalloc(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) {
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);
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);
222 xfree(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 = xstrdup(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 = xstrdup(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(xstrdup(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 xfree(ent->encoding);
445 ent->encoding = xstrdup(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 = xstrdup(tex_name);
570 ent->psname = ps_name ? xstrdup(ps_name) : NULL;
571 ent->fontfile = font_file ? xstrdup(font_file) : NULL;
572 ent->encfile = vec_name ? xstrdup(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 = xstrdup(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 xfree(ent->fontname);
613 xfree(ent->fontfile);
615 xfree(ent->encoding);
619 xfree(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();
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 xfree(ent->fullfile);
826 ent->fullfile = xstrdup(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)
875 char *kppath = mdvi_getenv("MDVI_PS_LIBPATH");
876 char *kfpath = mdvi_getenv("MDVI_PS_FONTPATH");
878 ASSERT(psinitialized == 0);
880 kppath = getenv("GS_LIB");
882 kfpath = getenv("GS_FONTPATH");
884 pslibdir = kpse_path_expand(kppath);
886 psfontdir = kpse_path_expand(kfpath);
887 listh_init(&psfonts);
888 mdvi_hash_create(&pstable, PSMAP_HASH_SIZE);
892 int mdvi_ps_read_fontmap(const char *name)
901 ps_init_default_paths();
903 fullname = kpse_path_search(pslibdir, name, 1);
905 fullname = (char *)name;
906 in = fopen(fullname, "r");
914 while((line = dgets(&dstr, in)) != NULL) {
921 /* we're looking for lines of the form
922 * /FONT-NAME (fontfile)
923 * /FONT-NAME /FONT-ALIAS
927 name = getword(line + 1, " \t", &line);
928 if(*line) *line++ = 0;
929 mapname = getword(line, " \t", &line);
930 if(*line) *line++ = 0;
932 if(!name || !mapname || !*name)
934 if(*mapname == '(') {
938 for(end = mapname; *end && *end != ')'; end++);
943 /* dont add `.gsf' fonts, which require a full blown
944 * PostScript interpreter */
945 ext = file_extension(mapname);
946 if(ext && STREQ(ext, "gsf")) {
947 DEBUG((DBG_FMAP, "(ps) %s: font `%s' ignored\n",
951 ps = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(name));
953 if(STREQ(ps->mapname, mapname))
956 "(ps) replacing font `%s' (%s) by `%s'\n",
957 name, ps->mapname, mapname));
959 ps->mapname = xstrdup(mapname);
965 DEBUG((DBG_FMAP, "(ps) adding font `%s' as `%s'\n",
967 ps = xalloc(PSFontMap);
968 ps->psname = xstrdup(name);
969 ps->mapname = xstrdup(mapname);
971 listh_append(&psfonts, LIST(ps));
972 mdvi_hash_add(&pstable, MDVI_KEY(ps->psname),
973 ps, MDVI_HASH_UNCHECKED);
978 dstring_reset(&dstr);
980 DEBUG((DBG_FMAP, "(ps) %s: %d PostScript fonts registered\n",
985 void mdvi_ps_flush_fonts(void)
991 DEBUG((DBG_FMAP, "(ps) flushing PS font map (%d) entries\n",
993 mdvi_hash_reset(&pstable, 0);
994 for(; (map = (PSFontMap *)psfonts.head); ) {
995 psfonts.head = LIST(map->next);
999 xfree(map->fullname);
1002 listh_init(&psfonts);
1014 char *mdvi_ps_find_font(const char *psname)
1016 PSFontMap *map, *smap;
1018 int recursion_limit = 32;
1020 DEBUG((DBG_FMAP, "(ps) resolving PS font `%s'\n", psname));
1023 map = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(psname));
1027 return xstrdup(map->fullname);
1029 /* is it an alias? */
1031 while(recursion_limit-- > 0 && smap && *smap->mapname == '/')
1032 smap = (PSFontMap *)mdvi_hash_lookup(&pstable,
1033 MDVI_KEY(smap->mapname + 1));
1035 if(recursion_limit == 0)
1037 "(ps) %s: possible loop in PS font map\n",
1043 filename = kpse_path_search(psfontdir, smap->mapname, 1);
1044 else if(file_exists(map->mapname))
1045 filename = xstrdup(map->mapname);
1049 map->fullname = xstrdup(filename);
1055 * To get metric info for a font, we proceed as follows:
1056 * - We try to find NAME.<tfm,ofm,afm>.
1057 * - We query the fontmap for NAME.
1058 * - We get back a PSNAME, and use to find the file in the PS font map.
1059 * - We get the PSFONT file name, replace its extension by "afm" and
1060 * lookup the file in GS's font search path.
1061 * - We finally read the data, transform it as specified in our font map,
1062 * and return it to the caller. The new data is left in the font metrics
1063 * cache, so the next time it will be found at the first step (when we look
1066 * The name `_ps_' in this function is not meant to imply that it can be
1067 * used for Type1 fonts only. It should be usable for TrueType fonts as well.
1069 * The returned metric info is subjected to the same caching mechanism as
1070 * all the other metric data, as returned by get_font_metrics(). One should
1071 * not modify the returned data at all, and it should be disposed with
1072 * free_font_metrics().
1074 TFMInfo *mdvi_ps_get_metrics(const char *fontname)
1078 char buffer[64]; /* to avoid mallocs */
1089 DEBUG((DBG_FMAP, "(ps) %s: looking for metric data\n", fontname));
1090 info = get_font_metrics(fontname, DviFontAny, NULL);
1094 /* query the fontmap */
1095 if(mdvi_query_fontmap(&map, fontname) < 0 || !map.psname)
1098 /* get the PS font */
1099 psfont = mdvi_ps_find_font(map.psname);
1102 DEBUG((DBG_FMAP, "(ps) %s: found as PS font `%s'\n",
1104 /* replace its extension */
1105 basefile = strrchr(psfont, '/');
1106 if(basefile == NULL)
1108 baselen = strlen(basefile);
1109 ext = strrchr(basefile, '.');
1112 if(baselen + 4 < 64)
1113 afmfile = &buffer[0];
1115 afmfile = xmalloc(baselen + 5);
1116 strcpy(afmfile, basefile);
1117 strcpy(afmfile + baselen, ".afm");
1118 /* we don't need this anymore */
1120 DEBUG((DBG_FMAP, "(ps) %s: looking for `%s'\n",
1121 fontname, afmfile));
1122 /* lookup the file */
1123 psfont = kpse_path_search(psfontdir, afmfile, 1);
1124 /* don't need this anymore */
1125 if(afmfile != &buffer[0])
1127 if(psfont != NULL) {
1128 info = get_font_metrics(fontname, DviFontAFM, psfont);
1132 if(info == NULL || (!map.extend && !map.slant))
1136 * transform the data as prescribed -- keep in mind that `info'
1137 * points to CACHED data, so we're modifying the metric cache
1141 #define DROUND(x) ((x) >= 0 ? floor((x) + 0.5) : ceil((x) - 0.5))
1142 #define TRANSFORM(x,y) DROUND(efactor * (x) + sfactor * (y))
1144 efactor = (double)map.extend / 10000.0;
1145 sfactor = (double)map.slant / 10000.0;
1146 DEBUG((DBG_FMAP, "(ps) %s: applying extend=%f, slant=%f\n",
1149 nc = info->hic - info->loc + 1;
1150 for(ch = info->chars; ch < info->chars + nc; ch++) {
1151 /* the AFM bounding box is:
1157 * what we do here is transform wx, llx, and urx by
1158 * newX = efactor * oldX + sfactor * oldY
1159 * where for `wx' oldY = 0. Also, these numbers are all in
1160 * TFM units (i.e. TFM's fix-words, which is just the actual
1161 * number times 2^20, no need to do anything to it).
1164 ch->advance = TRANSFORM(ch->advance, 0);
1165 ch->left = TRANSFORM(ch->left, -ch->depth);
1166 ch->right = TRANSFORM(ch->right, ch->height);