1 /* fontsearch.c -- implements the font lookup mechanism in MDVI */
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * Fonts are divided into MAX_CLASS priority classes. The first
23 * MAX_CLASS-1 ones correspond to `real' fonts (pk, gf, vf, type1, truetype,
24 * etc). The last one corresponds to `metric' fonts that are used as a last
25 * resort (tfm, afm, ofm, ...). When a font is looked up, it is tried in a
26 * `high' priority class (0 being the highest priority). The priority is
27 * lowered until it reaches MAX_CLASS-1. Then the whole thing is repeated
28 * for the fallback font. When the search reaches MAX_CLASS-1, we lookup the
29 * original font, and then the fallback font. The search can be done
30 * incrementally, with several calls to mdvi_lookup_font(). If this function
31 * is called again to continue a search, the function assumes the previous
32 * font it returned was not valid, and it goes on to the next step.
35 * Some font types are quite expensive to load (e.g. Type1), so loading
36 * them is deferred until the last possible moment. This means that a font that
37 * was supposed to exist may have to be discarded. Until now, MDVI had no ability to
38 * "resume" a search, so in this case it would have produced an error, regardless
39 * of whether the offending font existed in other formats.
40 * Also, given the large number of font types supported by MDVI, some mechanism
41 * was necessary to bring some order into the chaos.
43 * This mechanism fixes these two problems. For the first one, a search can
44 * be "resumed" and all the font formats tried for the missing font, and
45 * again for the fallback font (see above). As for the second, the
46 * hierarchical division in classes gives a lot of flexibility in how the
47 * fonts are configured.
53 #define HAVE_PROTOTYPES 1
54 #include <kpathsea/tex-file.h>
55 #include <kpathsea/tex-glyph.h>
57 struct _DviFontClass {
65 char *_mdvi_fallback_font = MDVI_FALLBACK_FONT;
67 /* this leaves classes 0 and 1 for `real' fonts */
69 static ListHead font_classes[MAX_CLASS];
70 static int initialized = 0;
72 static void init_font_classes(void)
76 for(i = 0; i < MAX_CLASS; i++)
77 listh_init(&font_classes[i]);
81 int mdvi_get_font_classes(void)
83 return (MAX_CLASS - 2);
86 char **mdvi_list_font_class(int klass)
94 if(klass < 0 || klass >= MAX_CLASS)
96 n = font_classes[klass].count;
97 list = xnalloc(char *, n + 1);
98 fc = (DviFontClass *)font_classes[klass].head;
99 for(i = 0; i < n; fc = fc->next, i++) {
100 list[i] = mdvi_strdup(fc->info.name);
106 int mdvi_register_font_type(DviFontInfo *info, int klass)
112 if(klass < 0 || klass >= MAX_CLASS)
116 fc = xalloc(struct _DviFontClass);
119 fc->info.name = mdvi_strdup(info->name);
120 fc->info.scalable = info->scalable;
121 fc->info.load = info->load;
122 fc->info.getglyph = info->getglyph;
123 fc->info.shrink0 = info->shrink0;
124 fc->info.shrink1 = info->shrink1;
125 fc->info.freedata = info->freedata;
126 fc->info.reset = info->reset;
127 fc->info.lookup = info->lookup;
128 fc->info.kpse_type = info->kpse_type;
129 listh_append(&font_classes[klass], LIST(fc));
133 int mdvi_unregister_font_type(const char *name, int klass)
139 klass = MAX_CLASS - 1;
141 if(klass >= 0 && klass < MAX_CLASS) {
143 LIST_FOREACH(fc, DviFontClass, &font_classes[k]) {
144 if(STREQ(fc->info.name, name))
147 } else if(klass < 0) {
148 for(k = 0; k < MAX_CLASS; k++) {
149 LIST_FOREACH(fc, DviFontClass, &font_classes[k]) {
150 if(STREQ(fc->info.name, name))
158 if(fc == NULL || fc->links)
161 listh_remove(&font_classes[k], LIST(fc));
164 mdvi_free(fc->info.name);
169 static char *lookup_font(DviFontClass *ptr, const char *name, Ushort *h, Ushort *v)
174 * If the font type registered a function to do the lookup, use that.
175 * Otherwise we use kpathsea.
178 filename = ptr->info.lookup(name, h, v);
179 else if(ptr->info.kpse_type <= kpse_any_glyph_format) {
180 kpse_glyph_file_type type;
182 filename = kpse_find_glyph(name, Max(*h, *v),
183 ptr->info.kpse_type, &type);
184 /* if kpathsea returned a fallback font, reject it */
185 if(filename && type.source == kpse_glyph_source_fallback) {
191 filename = kpse_find_file(name, ptr->info.kpse_type, 1);
196 * Class MAX_CLASS-1 is special: it consists of `metric' fonts that should
197 * be tried as a last resort
199 char *mdvi_lookup_font(DviFontSearch *search)
205 char *filename = NULL;
212 if(search->curr == NULL) {
213 /* this is the initial search */
214 name = search->wanted_name;
220 name = search->actual_name;
221 hdpi = search->actual_hdpi;
222 vdpi = search->actual_vdpi;
229 /* try all classes except MAX_CLASS-1 */
230 for(k = kid; !filename && k < MAX_CLASS-1; k++) {
232 ptr = (DviFontClass *)font_classes[k].head;
236 DEBUG((DBG_FONTS, "%d: trying `%s' at (%d,%d)dpi as `%s'\n",
237 k, name, hdpi, vdpi, ptr->info.name));
238 /* lookup the font in this class */
239 filename = lookup_font(ptr, name, &hdpi, &vdpi);
246 if(filename != NULL) {
249 search->actual_name = name;
250 search->actual_hdpi = hdpi;
251 search->actual_vdpi = vdpi;
252 search->info = &ptr->info;
257 if(kid < MAX_CLASS - 1 && !STREQ(name, _mdvi_fallback_font)) {
258 mdvi_warning("font `%s' at %dx%d not found, trying `%s' instead\n",
259 name, hdpi, vdpi, _mdvi_fallback_font);
260 name = _mdvi_fallback_font;
265 /* we tried the fallback font, and all the `real' classes. Let's
266 * try the `metric' class now */
267 name = search->wanted_name;
270 if(kid == MAX_CLASS-1) {
271 /* we were looking into this class from the beginning */
273 /* no more fonts to try */
278 mdvi_warning("font `%s' not found, trying metric files instead\n",
280 ptr = (DviFontClass *)font_classes[MAX_CLASS-1].head;
285 DEBUG((DBG_FONTS, "metric: trying `%s' at (%d,%d)dpi as `%s'\n",
286 name, hdpi, vdpi, ptr->info.name));
287 filename = lookup_font(ptr, name, &hdpi, &vdpi);
292 if(filename != NULL) {
293 if(STREQ(name, _mdvi_fallback_font))
294 search->id = MAX_CLASS;
296 search->id = MAX_CLASS - 1;
298 search->actual_name = name;
299 search->actual_hdpi = hdpi;
300 search->actual_vdpi = vdpi;
301 search->info = &ptr->info;
305 if(!STREQ(name, _mdvi_fallback_font)) {
306 mdvi_warning("metric file for `%s' not found, trying `%s' instead\n",
307 name, _mdvi_fallback_font);
308 name = _mdvi_fallback_font;
309 ptr = (DviFontClass *)font_classes[MAX_CLASS-1].head;
314 search->actual_name = NULL;
316 /* tough luck, nothing found */
320 /* called by `font_reference' to do the initial lookup */
321 DviFont *mdvi_add_font(const char *name, Int32 sum,
322 int hdpi, int vdpi, Int32 scale)
326 font = xalloc(DviFont);
327 font->fontname = mdvi_strdup(name);
328 SEARCH_INIT(font->search, font->fontname, hdpi, vdpi);
329 font->filename = mdvi_lookup_font(&font->search);
330 if(font->filename == NULL) {
331 /* this answer is final */
332 mdvi_free(font->fontname);
336 font->hdpi = font->search.actual_hdpi;
337 font->vdpi = font->search.actual_vdpi;
340 font->checksum = sum;
347 font->subfonts = NULL;
352 int mdvi_font_retry(DviParams *params, DviFont *font)
354 /* try the search again */
357 ASSERT(font->search.curr != NULL);
358 /* we won't be using this class anymore */
359 font->search.curr->links--;
361 filename = mdvi_lookup_font(&font->search);
364 mdvi_free(font->filename);
365 font->filename = filename;
366 /* copy the new information */
367 font->hdpi = font->search.actual_hdpi;
368 font->vdpi = font->search.actual_vdpi;