1 /* tex-glyph.c: search for GF/PK files.
3 Copyright 1993, 1994, 1995, 1996, 2008 Karl Berry.
4 Copyright 1997, 1998, 1999, 2005 Olaf Weber.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with this library; if not, see <http://www.gnu.org/licenses/>. */
19 #include <kpathsea/config.h>
21 #include <kpathsea/absolute.h>
22 #include <kpathsea/expand.h>
23 #include <kpathsea/fontmap.h>
24 #include <kpathsea/pathsearch.h>
25 #include <kpathsea/tex-glyph.h>
26 #include <kpathsea/tex-make.h>
27 #include <kpathsea/variable.h>
29 /* Routines are in bottom-up order. */
31 /* Support both cmr10.300pk and dpi300/cmr10.pk. (Use the latter
32 instead of dpi300\cmr10.pk since DOS supports /'s, but Unix doesn't
34 #define UNIX_BITMAP_SPEC "$KPATHSEA_NAME.$KPATHSEA_DPI$KPATHSEA_FORMAT"
35 #define DPI_BITMAP_SPEC "dpi$KPATHSEA_DPI/$KPATHSEA_NAME.$KPATHSEA_FORMAT"
37 /* Look up FONTNAME at resolution DPI in PATH, with filename suffix
38 EXTENSION. Return file found or NULL. */
41 try_format P3C(const_string, fontname, unsigned, dpi,
42 kpse_file_format_type, format)
44 static const_string bitmap_specs[]
45 = { UNIX_BITMAP_SPEC, DPI_BITMAP_SPEC, NULL };
49 const_string path = kpse_format_info[format].path;
52 path = kpse_init_format (format);
54 /* Set the suffix on the name we'll be searching for. */
55 sfx = kpse_format_info[format].suffix;
57 xputenv ("KPATHSEA_FORMAT", *sfx);
59 /* OK, the limits on this for loop are a little hokey, but it saves
60 having to repeat the body. We want to do it once with `must_exist'
61 false to avoid looking on the disk for cmr10.600pk if
62 dpi600/cmr10.pk is in ls-R. (The time spent in the extra variable
63 expansions and db searches is negligible.) */
64 for (must_exist = false; !ret && must_exist <= true; must_exist++)
66 for (spec = bitmap_specs; !ret && *spec; spec++)
68 string name = kpse_var_expand (*spec);
69 ret = kpse_path_search (path, name, must_exist);
78 /* Look for FONTNAME at resolution DPI in format FORMAT. Search the
79 (entire) PK path first, then the GF path, if we're looking for both.
80 Return any filename found, and (if we succeeded) fill in GLYPH_FILE. */
83 try_size P4C(const_string, fontname, unsigned, dpi,
84 kpse_file_format_type, format,
85 kpse_glyph_file_type *, glyph_file)
87 kpse_file_format_type format_found;
89 boolean try_gf = format == kpse_gf_format || format == kpse_any_glyph_format;
90 boolean try_pk = format == kpse_pk_format || format == kpse_any_glyph_format;
92 xputenv_int ("KPATHSEA_DPI", dpi);
94 /* Look for PK first (since it's more likely to be found), then GF. */
95 ret = try_pk ? try_format (fontname, dpi, kpse_pk_format) : NULL;
98 format_found = kpse_pk_format;
103 ret = try_format (fontname, dpi, kpse_gf_format);
104 format_found = kpse_gf_format;
108 if (ret != NULL && glyph_file)
109 { /* Success. Fill in the return info. Discard const. */
110 glyph_file->name = (string) fontname;
111 glyph_file->dpi = dpi;
112 glyph_file->format = format_found;
118 /* Look for FONTNAME at resolution DPI, then at the resolutions within
119 KPSE_BITMAP_TOLERANCE of DPI. */
122 try_resolution P4C(const_string, fontname, unsigned, dpi,
123 kpse_file_format_type, format,
124 kpse_glyph_file_type *, glyph_file)
126 string ret = try_size (fontname, dpi, format, glyph_file);
131 unsigned tolerance = KPSE_BITMAP_TOLERANCE (dpi);
132 /* Cast to unsigned to shut up stupid compilers. */
133 unsigned lower_bound = (int) (dpi - tolerance) < 0 ? 0 : (unsigned)(dpi - tolerance);
134 unsigned upper_bound = (unsigned)(dpi + tolerance);
136 /* Prefer scaling up to scaling down, since scaling down can omit
137 character features (Tom did this in dvips). */
138 for (r = lower_bound; !ret && r <= upper_bound; r++)
140 ret = try_size (fontname, r, format, glyph_file);
146 /* Look up *FONTNAME_PTR in format FORMAT at DPI in the texfonts.map files
147 that we can find, returning the filename found and GLYPH_FILE. Also
148 set *FONTNAME_PTR to the real name corresponding to the alias found
149 or the first alias, if that is not an alias itself. (This allows
150 mktexpk to only deal with real names.) */
153 try_fontmap P4C(string *, fontname_ptr, unsigned, dpi,
154 kpse_file_format_type, format,
155 kpse_glyph_file_type *, glyph_file)
157 string *mapped_names;
158 string fontname = *fontname_ptr;
161 mapped_names = kpse_fontmap_lookup (fontname);
164 string first_name = *mapped_names;
165 while (!ret && (mapped_name = *mapped_names++)) {
166 xputenv ("KPATHSEA_NAME", mapped_name);
167 ret = try_resolution (mapped_name, dpi, format, glyph_file);
170 /* If some alias succeeeded, return that alias. */
171 *fontname_ptr = xstrdup (mapped_name);
172 /* Return first alias name, unless that itself is an alias,
173 in which case do nothing. */
174 } else if (!kpse_fontmap_lookup (first_name)) {
175 *fontname_ptr = xstrdup (first_name);
182 /* Look for FONTNAME in `kpse_fallback_resolutions', omitting DPI if we
183 happen across it. Return NULL if nothing found. Pass GLYPH_FILE
184 along as usual. Assume `kpse_fallback_resolutions' is sorted. */
187 try_fallback_resolutions P4C(const_string, fontname, unsigned, dpi,
188 kpse_file_format_type, format,
189 kpse_glyph_file_type *, glyph_file)
193 int lower_loc, upper_loc;
194 unsigned lower_diff, upper_diff;
195 unsigned closest_diff = UINT_MAX;
196 string ret = NULL; /* In case the only fallback resolution is DPI. */
198 /* First find the fallback size closest to DPI, even including DPI. */
199 for (s = 0; kpse_fallback_resolutions[s] != 0; s++)
201 unsigned this_diff = abs (kpse_fallback_resolutions[s] - dpi);
202 if (this_diff < closest_diff)
204 closest_diff = this_diff;
209 return ret; /* If nothing in list, quit now. */
217 unsigned fallback = kpse_fallback_resolutions[loc];
218 /* Don't bother to try DPI itself again. */
221 ret = try_resolution (fontname, fallback, format, glyph_file);
226 /* That didn't work. How far away are the locs above or below? */
227 lower_diff = lower_loc > -1
228 ? dpi - kpse_fallback_resolutions[lower_loc] : INT_MAX;
229 upper_diff = upper_loc < max_loc
230 ? kpse_fallback_resolutions[upper_loc] - dpi : INT_MAX;
232 /* But if we're at the end in both directions, quit. */
233 if (lower_diff == INT_MAX && upper_diff == INT_MAX)
236 /* Go in whichever direction is closest. */
237 if (lower_diff < upper_diff)
252 /* See the .h file for description. This is the entry point. */
255 kpse_find_glyph P4C(const_string, passed_fontname, unsigned, dpi,
256 kpse_file_format_type, format,
257 kpse_glyph_file_type *, glyph_file)
260 kpse_glyph_source_type source;
261 string fontname = (string) passed_fontname; /* discard const */
263 /* Start the search: try the name we're given. */
264 source = kpse_glyph_source_normal;
265 xputenv ("KPATHSEA_NAME", fontname);
266 ret = try_resolution (fontname, dpi, format, glyph_file);
268 /* Try all the various possibilities in order of preference. */
270 /* Maybe FONTNAME was an alias. */
271 source = kpse_glyph_source_alias;
272 ret = try_fontmap (&fontname, dpi, format, glyph_file);
274 /* If not an alias, try creating it on the fly with mktexpk,
275 unless FONTNAME is absolute or explicitly relative. */
276 if (!ret && !kpse_absolute_p (fontname, true)) {
277 source = kpse_glyph_source_maketex;
278 /* `try_resolution' leaves the envvar set randomly. */
279 xputenv_int ("KPATHSEA_DPI", dpi);
280 ret = kpse_make_tex (format, fontname);
283 /* If mktex... succeeded, set return struct. Doesn't make sense for
284 `kpse_make_tex' to set it, since it can only succeed or fail,
285 unlike the other routines. */
286 if (ret && glyph_file) {
287 KPSE_GLYPH_FILE_DPI (*glyph_file) = dpi;
288 KPSE_GLYPH_FILE_NAME (*glyph_file) = fontname;
291 /* If mktex... failed, try any fallback resolutions. */
293 if (kpse_fallback_resolutions)
294 ret = try_fallback_resolutions (fontname, dpi, format, glyph_file);
296 /* We're down to the font of last resort. */
297 if (!ret && kpse_fallback_font) {
298 const_string name = kpse_fallback_font;
299 source = kpse_glyph_source_fallback;
300 xputenv ("KPATHSEA_NAME", name);
302 /* As before, first try it at the given size. */
303 ret = try_resolution (name, dpi, format, glyph_file);
305 /* The fallback font at the fallback resolutions. */
306 if (!ret && kpse_fallback_resolutions)
307 ret = try_fallback_resolutions (name, dpi, format, glyph_file);
312 /* If RET is null, then the caller is not supposed to look at GLYPH_FILE,
313 so it doesn't matter if we assign something incorrect. */
315 KPSE_GLYPH_FILE_SOURCE (*glyph_file) = source;
317 /* FIXME: fontname may have been allocated, but (worse) it may also
318 have been assigned to struct that's passed out of this function.
319 if (fontname != passed_fontname)
326 /* The tolerances change whether we base things on DPI1 or DPI2. */
329 kpse_bitmap_tolerance P2C(double, dpi1, double, dpi2)
331 unsigned tolerance = KPSE_BITMAP_TOLERANCE (dpi2);
332 unsigned lower_bound = (int) (dpi2 - tolerance) < 0 ? 0 : dpi2 - tolerance;
333 unsigned upper_bound = dpi2 + tolerance;
335 return lower_bound <= dpi1 && dpi1 <= upper_bound;
341 test_find_glyph (const_string fontname, unsigned dpi)
344 kpse_glyph_file_type ret;
346 printf ("\nSearch for %s@%u:\n\t", fontname, dpi);
348 answer = kpse_find_glyph_format (fontname, dpi,
349 kpse_any_glyph_format, &ret);
352 string format = ret.format == kpse_pk_format ? "pk" : "gf";
355 printf ("%s\n\t(%s@%u, %s)\n", answer, ret.name, ret.dpi, format);
365 test_find_glyph ("/usr/local/lib/tex/fonts/cm/cmr10", 300); /* absolute */
366 test_find_glyph ("cmr10", 300); /* normal */
367 test_find_glyph ("logo10", 300); /* find gf */
368 test_find_glyph ("cmr10", 299); /* find 300 */
369 test_find_glyph ("circle10", 300); /* in fontmap */
370 test_find_glyph ("none", 300); /* do not find */
371 kpse_fallback_font = "cmr10";
372 test_find_glyph ("fallback", 300); /* find fallback font cmr10 */
373 kpse_init_fallback_resolutions ("KPATHSEA_TEST_SIZES");
374 test_find_glyph ("fallbackdpi", 759); /* find fallback font cmr10@300 */
376 xputenv ("GFFONTS", ".");
377 test_find_glyph ("cmr10", 300); /* different GFFONTS/TEXFONTS */
387 test-compile-command: "gcc -g -I. -I.. -DTEST tex-glyph.c kpathsea.a"