Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
fontsrch.c
Go to the documentation of this file.
1 /* fontsearch.c -- implements the font lookup mechanism in MDVI */
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 /*
21  * How this works:
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.
33  *
34  * Reason for this:
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.
42  *
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.
48  */
49 
50 #include <config.h>
51 #include "mdvi.h"
52 
53 #define HAVE_PROTOTYPES 1
54 #include <kpathsea/tex-file.h>
55 #include <kpathsea/tex-glyph.h>
56 
57 struct _DviFontClass {
61  int links;
62  int id;
63 };
64 
66 
67 /* this leaves classes 0 and 1 for `real' fonts */
68 #define MAX_CLASS 3
70 static int initialized = 0;
71 
72 static void init_font_classes(void)
73 {
74  int i;
75 
76  for(i = 0; i < MAX_CLASS; i++)
77  listh_init(&font_classes[i]);
78  initialized = 1;
79 }
80 
82 {
83  return (MAX_CLASS - 2);
84 }
85 
86 char **mdvi_list_font_class(int klass)
87 {
88  char **list;
89  int i, n;
90  DviFontClass *fc;
91 
92  if(klass == -1)
93  klass = MAX_CLASS-1;
94  if(klass < 0 || klass >= MAX_CLASS)
95  return NULL;
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);
101  }
102  list[i] = NULL;
103  return list;
104 }
105 
107 {
108  DviFontClass *fc;
109 
110  if(klass == -1)
111  klass = MAX_CLASS-1;
112  if(klass < 0 || klass >= MAX_CLASS)
113  return -1;
114  if(!initialized)
116  fc = xalloc(struct _DviFontClass);
117  fc->links = 0;
118  fc->id = klass;
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));
130  return 0;
131 }
132 
133 int mdvi_unregister_font_type(const char *name, int klass)
134 {
135  DviFontClass *fc;
136  int k;
137 
138  if(klass == -1)
139  klass = MAX_CLASS - 1;
140 
141  if(klass >= 0 && klass < MAX_CLASS) {
142  k = klass;
143  LIST_FOREACH(fc, DviFontClass, &font_classes[k]) {
144  if(STREQ(fc->info.name, name))
145  break;
146  }
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))
151  break;
152  }
153  if(fc) break;
154  }
155  } else
156  return -1;
157 
158  if(fc == NULL || fc->links)
159  return -1;
160  /* remove it */
161  listh_remove(&font_classes[k], LIST(fc));
162 
163  /* and destroy it */
164  mdvi_free(fc->info.name);
165  mdvi_free(fc);
166  return 0;
167 }
168 
169 static char *lookup_font(DviFontClass *ptr, const char *name, Ushort *h, Ushort *v)
170 {
171  char *filename;
172 
173  /*
174  * If the font type registered a function to do the lookup, use that.
175  * Otherwise we use kpathsea.
176  */
177  if(ptr->info.lookup)
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;
181 
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) {
186  mdvi_free(filename);
187  filename = NULL;
188  } else if(filename)
189  *h = *v = type.dpi;
190  } else
191  filename = kpse_find_file(name, ptr->info.kpse_type, 1);
192  return filename;
193 }
194 
195 /*
196  * Class MAX_CLASS-1 is special: it consists of `metric' fonts that should
197  * be tried as a last resort
198  */
200 {
201  int kid;
202  int k;
203  DviFontClass *ptr;
204  DviFontClass *last;
205  char *filename = NULL;
206  const char *name;
207  Ushort hdpi, vdpi;
208 
209  if(search->id < 0)
210  return NULL;
211 
212  if(search->curr == NULL) {
213  /* this is the initial search */
214  name = search->wanted_name;
215  hdpi = search->hdpi;
216  vdpi = search->vdpi;
217  kid = 0;
218  last = NULL;
219  } else {
220  name = search->actual_name;
221  hdpi = search->actual_hdpi;
222  vdpi = search->actual_vdpi;
223  kid = search->id;
224  last = search->curr;
225  }
226 
227  ptr = NULL;
228 again:
229  /* try all classes except MAX_CLASS-1 */
230  for(k = kid; !filename && k < MAX_CLASS-1; k++) {
231  if(last == NULL)
232  ptr = (DviFontClass *)font_classes[k].head;
233  else
234  ptr = last->next;
235  while(ptr) {
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);
240  if(filename)
241  break;
242  ptr = ptr->next;
243  }
244  last = NULL;
245  }
246  if(filename != NULL) {
247  search->id = k-1;
248  search->curr = ptr;
249  search->actual_name = name;
250  search->actual_hdpi = hdpi;
251  search->actual_vdpi = vdpi;
252  search->info = &ptr->info;
253  ptr->links++;
254  return filename;
255  }
256 
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;
261  kid = 0;
262  goto again;
263  }
264 
265  /* we tried the fallback font, and all the `real' classes. Let's
266  * try the `metric' class now */
267  name = search->wanted_name;
268  hdpi = search->hdpi;
269  vdpi = search->vdpi;
270  if(kid == MAX_CLASS-1) {
271  /* we were looking into this class from the beginning */
272  if(last == NULL) {
273  /* no more fonts to try */
274  return NULL;
275  }
276  ptr = last->next;
277  } else {
278  mdvi_warning("font `%s' not found, trying metric files instead\n",
279  name);
280  ptr = (DviFontClass *)font_classes[MAX_CLASS-1].head;
281  }
282 
283 metrics:
284  while(ptr) {
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);
288  if(filename)
289  break;
290  ptr = ptr->next;
291  }
292  if(filename != NULL) {
293  if(STREQ(name, _mdvi_fallback_font))
294  search->id = MAX_CLASS;
295  else
296  search->id = MAX_CLASS - 1;
297  search->curr = ptr;
298  search->actual_name = name;
299  search->actual_hdpi = hdpi;
300  search->actual_vdpi = vdpi;
301  search->info = &ptr->info;
302  ptr->links++;
303  return filename;
304  }
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;
310  goto metrics;
311  }
312 
313  search->id = -1;
314  search->actual_name = NULL;
315 
316  /* tough luck, nothing found */
317  return NULL;
318 }
319 
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)
323 {
324  DviFont *font;
325 
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);
333  mdvi_free(font);
334  return NULL;
335  }
336  font->hdpi = font->search.actual_hdpi;
337  font->vdpi = font->search.actual_vdpi;
338  font->scale = scale;
339  font->design = 0;
340  font->checksum = sum;
341  font->type = 0;
342  font->links = 0;
343  font->loc = 0;
344  font->hic = 0;
345  font->in = NULL;
346  font->chars = NULL;
347  font->subfonts = NULL;
348 
349  return font;
350 }
351 
352 int mdvi_font_retry(DviParams *params, DviFont *font)
353 {
354  /* try the search again */
355  char *filename;
356 
357  ASSERT(font->search.curr != NULL);
358  /* we won't be using this class anymore */
359  font->search.curr->links--;
360 
361  filename = mdvi_lookup_font(&font->search);
362  if(filename == NULL)
363  return -1;
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;
369 
370  return 0;
371 }